Add proof-measure client + bump to 1.4.0
Some checks failed
Build and Test / build (16.x) (push) Failing after 45s
Build and Test / build (18.x) (push) Failing after 40s
Publish to NPM Registry / publish (release) Successful in 54s
Build and Test / build (20.x) (push) Failing after 38s

proof-measure is a separate, public, unauthenticated Dragonchain service. Adds:
- UnauthHttpClient: HMAC-free transport mirroring DragonchainClient (timeout,
  agent, redirect refusal).
- ProofMeasureClient: getSecurity / report / health; default base URL
  https://proof-measure.dragonchain.com. Standalone (new ProofMeasureClient())
  and via DragonchainSDK.proofMeasure.
- Proof-measure types (decimals as strings, timestamps as numbers).
- jest tests.
This commit is contained in:
2026-06-04 13:45:09 -04:00
parent a35dc508b0
commit 5a943f45a6
7 changed files with 394 additions and 1 deletions

View File

@@ -0,0 +1,79 @@
import { ProofMeasureClient, PROOF_MEASURE_DEFAULT_BASE_URL } from '../src/proofMeasure';
import { UnauthHttpClient } from '../src/unauthHttpClient';
import { ProofMeasureSecurityResult, ProofMeasureTransactionReport } from '../src/types';
// Build a fake transport that is an instanceof UnauthHttpClient (so the
// ProofMeasureClient constructor uses it directly) with mocked get/post.
function fakeClient(get?: jest.Mock, post?: jest.Mock): UnauthHttpClient {
const c = Object.create(UnauthHttpClient.prototype) as UnauthHttpClient;
(c as unknown as { get: jest.Mock }).get = get ?? jest.fn(async () => ({}));
(c as unknown as { post: jest.Mock }).post = post ?? jest.fn(async () => ({}));
return c;
}
describe('ProofMeasureClient', () => {
it('getSecurity builds the path with since and returns the parsed result', async () => {
const sec: ProofMeasureSecurityResult = {
network: 'BTC',
consensus: 'pow',
raw: { value: '71.63', unit: 'Yottahashes', base: '7.16e25' },
valueUsd: '13928170.26',
valueUsdFormatted: '$13,928,170.26',
label: '$13,928,170.26 energy consumed',
normalizedScore: '0.9234',
since: 1780504894,
asOf: 1780591253,
};
const get = jest.fn(async () => sec);
const client = fakeClient(get);
const res = await new ProofMeasureClient(client).getSecurity('BTC', 1780504894);
expect(get).toHaveBeenCalledWith('/api/v1/security/BTC?since=1780504894');
expect(res.network).toBe('BTC');
expect(res.raw.unit).toBe('Yottahashes');
expect(res.valueUsdFormatted).toBe('$13,928,170.26');
});
it('getSecurity omits the since param when not provided', async () => {
const get = jest.fn(async () => ({}));
await new ProofMeasureClient(fakeClient(get)).getSecurity('ETH');
expect(get).toHaveBeenCalledWith('/api/v1/security/ETH');
});
it('report POSTs the request to /api/v1/report and parses the report', async () => {
const report: ProofMeasureTransactionReport = {
transactionId: 't',
primeId: 'p',
blockId: '42',
anchors: [],
totalValueUsd: '100.00',
totalValueUsdFormatted: '$100.00',
hashPower: { value: '40.06', units: 'Yottahashes' },
totalNormalizedScore: '0.9',
};
const post = jest.fn(async () => report);
const client = fakeClient(undefined, post);
const req = {
transactionId: 't',
primeId: 'p',
blockId: '42',
anchors: [{ network: 'BTC', txHash: '0xabc', timestamp: 1712345678 }],
};
const rep = await new ProofMeasureClient(client).report(req);
expect(post).toHaveBeenCalledWith('/api/v1/report', 'application/json', req);
expect(rep.totalValueUsdFormatted).toBe('$100.00');
expect(rep.hashPower?.units).toBe('Yottahashes');
});
it('health calls /api/v1/health', async () => {
const get = jest.fn(async () => ({ status: 'ok' }));
const res = await new ProofMeasureClient(fakeClient(get)).health();
expect(get).toHaveBeenCalledWith('/api/v1/health');
expect(res.status).toBe('ok');
});
it('defaults to the public endpoint with no config', () => {
const pm = new ProofMeasureClient();
expect(pm).toBeInstanceOf(ProofMeasureClient);
expect(PROOF_MEASURE_DEFAULT_BASE_URL).toBe('https://proof-measure.dragonchain.com');
});
});