@rubric-protocol/sdk 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -187
- package/dist/cli.d.ts +30 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +165 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +351 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +426 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +2 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -25
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +283 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +12 -43
- package/dist/background-queue.d.ts +0 -57
- package/dist/background-queue.d.ts.map +0 -1
- package/dist/background-queue.js +0 -164
- package/dist/background-queue.js.map +0 -1
- package/dist/ml-dsa-local.d.ts +0 -35
- package/dist/ml-dsa-local.d.ts.map +0 -1
- package/dist/ml-dsa-local.js +0 -151
- package/dist/ml-dsa-local.js.map +0 -1
- package/dist/plugins/langchain.d.ts +0 -30
- package/dist/plugins/langchain.d.ts.map +0 -1
- package/dist/plugins/langchain.js +0 -85
- package/dist/plugins/langchain.js.map +0 -1
- package/dist/plugins/openai-plugin.d.ts +0 -23
- package/dist/plugins/openai-plugin.d.ts.map +0 -1
- package/dist/plugins/openai-plugin.js +0 -72
- package/dist/plugins/openai-plugin.js.map +0 -1
- package/dist/proof-types.d.ts +0 -48
- package/dist/proof-types.d.ts.map +0 -1
- package/dist/proof-types.js +0 -105
- package/dist/proof-types.js.map +0 -1
- package/dist/proof-upgrade-manager.d.ts +0 -24
- package/dist/proof-upgrade-manager.d.ts.map +0 -1
- package/dist/proof-upgrade-manager.js +0 -103
- package/dist/proof-upgrade-manager.js.map +0 -1
- package/dist/rubric-client.d.ts +0 -46
- package/dist/rubric-client.d.ts.map +0 -1
- package/dist/rubric-client.js +0 -217
- package/dist/rubric-client.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,218 +1,109 @@
|
|
|
1
1
|
# @rubric-protocol/sdk
|
|
2
2
|
|
|
3
|
-
Post-quantum AI attestation
|
|
3
|
+
Post-quantum AI attestation with ZK inclusion proofs.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Rubric Protocol is the independent witness layer for the AI economy - providing tamper-evident, independently verifiable audit trails for AI decisions, anchored to Hedera Consensus Service.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Installation
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
npm install @rubric-protocol/sdk
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
## Quick Start
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
import { RubricClient } from "@rubric-protocol/sdk";
|
|
14
|
+
const client = new RubricClient({
|
|
15
|
+
baseUrl: "https://rubric-protocol.com/verify",
|
|
16
|
+
apiKey: "your-api-key",
|
|
17
|
+
});
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
Get an API key at https://rubric-protocol.com
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
## Core Concepts
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
Every AI decision submitted to Rubric receives:
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
1. An attestation record - signed with ML-DSA-65 (NIST FIPS 204 post-quantum signature)
|
|
26
|
+
2. A Merkle inclusion - aggregated into a cryptographic tree and anchored to Hedera Consensus Service
|
|
27
|
+
3. A ZK inclusion proof - independently verifiable proof your record was included in the anchored tree
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
The ZK proof means you hold cryptographic evidence of your record that does not require Rubric to verify.
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
npm install openai # for OpenAI plugin
|
|
33
|
-
npm install @langchain/core # for LangChain plugin
|
|
34
|
-
```
|
|
31
|
+
## Submitting Attestations
|
|
35
32
|
|
|
36
|
-
|
|
33
|
+
const result = await client.attestations.tieredAttest({
|
|
34
|
+
data: { model: "gpt-4o", decision: "approved", confidence: 0.94 },
|
|
35
|
+
sourceId: "your-system-id",
|
|
36
|
+
pipelineId: "my-pipeline",
|
|
37
|
+
});
|
|
38
|
+
console.log(result.attestationId); // retain this
|
|
39
|
+
console.log(result.status); // buffered
|
|
37
40
|
|
|
38
|
-
##
|
|
41
|
+
## Retrieving ZK Inclusion Proofs
|
|
39
42
|
|
|
40
|
-
|
|
41
|
-
import { createRubricClient } from '@rubric-protocol/sdk';
|
|
43
|
+
The proof generates asynchronously after the ~30s Merkle flush. Use the built-in polling helper:
|
|
42
44
|
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
const proof = await client.attestations.getZkProof(result.attestationId, {
|
|
46
|
+
timeoutMs: 120_000, // default 120s
|
|
47
|
+
intervalMs: 10_000, // default 10s
|
|
48
|
+
});
|
|
49
|
+
console.log(proof.status); // ready
|
|
50
|
+
console.log(proof.proof.zkRoot); // Poseidon2 Merkle root
|
|
51
|
+
console.log(proof.proof.zkPath); // 20-level inclusion path
|
|
52
|
+
console.log(proof.proof.zkLeaf); // your record leaf hash
|
|
53
|
+
console.log(proof.hcsSeqNum); // HCS sequence number
|
|
54
|
+
console.log(proof.verifyEndpoint); // endpoint to verify this proof
|
|
49
55
|
|
|
50
|
-
|
|
51
|
-
agentId: 'my-agent-v1',
|
|
52
|
-
output: 'Loan application approved. Score: 742, DTI: 28%.',
|
|
53
|
-
leafType: 'AGENT_OUTPUT',
|
|
54
|
-
metadata: { model: 'gpt-4o', pipeline: 'credit-decisioning' },
|
|
55
|
-
});
|
|
56
|
+
HTTP status codes: 202 = pending (retry), 200 = ready, 404 = not found
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
console.log(proof.stage); // 'local'
|
|
58
|
+
## ZK Proof Response Fields
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
60
|
+
status ready or pending
|
|
61
|
+
attestationId your record ID
|
|
62
|
+
flushId Merkle batch ID
|
|
63
|
+
hcsSeqNum HCS sequence number (populated ~60s after submission)
|
|
64
|
+
hcsExplorerUrl Hashscan link for on-chain verification
|
|
65
|
+
proof.zkLeaf BN254 field element - your record leaf hash
|
|
66
|
+
proof.zkRoot Poseidon2 Merkle root - matches HCS anchor
|
|
67
|
+
proof.zkPath 20-element sibling path
|
|
68
|
+
proof.zkIndices left/right indices per level
|
|
69
|
+
proof.leafIndex your position in the Merkle tree
|
|
70
|
+
circuitVersion noir-beta19-poseidon2-depth20
|
|
65
71
|
|
|
66
|
-
|
|
72
|
+
## Full Example
|
|
67
73
|
|
|
68
|
-
|
|
74
|
+
import { RubricClient } from "@rubric-protocol/sdk";
|
|
75
|
+
const client = new RubricClient({
|
|
76
|
+
baseUrl: "https://rubric-protocol.com/verify",
|
|
77
|
+
apiKey: process.env.RUBRIC_API_KEY,
|
|
78
|
+
});
|
|
79
|
+
const attest = await client.attestations.tieredAttest({
|
|
80
|
+
data: { model: "claude-3-5-sonnet", action: "content_moderation", result: "approved" },
|
|
81
|
+
sourceId: "my-ai-system",
|
|
82
|
+
});
|
|
83
|
+
const proof = await client.attestations.getZkProof(attest.attestationId);
|
|
84
|
+
console.log("zkRoot: ", proof.proof.zkRoot);
|
|
85
|
+
console.log("leafIndex:", proof.proof.leafIndex);
|
|
86
|
+
console.log("hcsSeqNum:", proof.hcsSeqNum ?? "pending");
|
|
69
87
|
|
|
70
|
-
|
|
88
|
+
## EU AI Act Article 12 Compliance
|
|
71
89
|
|
|
72
|
-
|
|
73
|
-
import { ChatOpenAI } from '@langchain/openai';
|
|
74
|
-
import { AgentExecutor } from 'langchain/agents';
|
|
75
|
-
import { RubricLangChainHandler } from '@rubric-protocol/sdk';
|
|
90
|
+
Rubric satisfies the tamper-evident logging requirements of EU AI Act Article 12 for high-risk AI systems.
|
|
76
91
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
pipelineId: 'my-pipeline',
|
|
83
|
-
});
|
|
92
|
+
- Timestamp independence: consensus timestamps generated by Hedera network, not Rubric
|
|
93
|
+
- Structural immutability: HCS has no DELETE or UPDATE operation by design
|
|
94
|
+
- Third-party verifiability: records verifiable against Hedera public mirror nodes without Rubric
|
|
95
|
+
- Post-quantum integrity: ML-DSA-65 signatures valid against quantum adversaries
|
|
96
|
+
- ZK inclusion proofs: customers hold independent cryptographic evidence of inclusion
|
|
84
97
|
|
|
85
|
-
|
|
86
|
-
agent,
|
|
87
|
-
tools,
|
|
88
|
-
callbacks: [rubric], // that's it
|
|
89
|
-
});
|
|
98
|
+
## Framework Integrations
|
|
90
99
|
|
|
91
|
-
|
|
92
|
-
await rubric.shutdown(); // flush remaining queue on exit
|
|
93
|
-
```
|
|
100
|
+
pip install autogen-rubric
|
|
94
101
|
|
|
95
|
-
|
|
102
|
+
Supports AutoGen, LlamaIndex, CrewAI, LangGraph, OpenAI Agents SDK, Google ADK, and more.
|
|
96
103
|
|
|
97
|
-
##
|
|
104
|
+
## Support
|
|
98
105
|
|
|
99
|
-
|
|
106
|
+
Website: https://rubric-protocol.com
|
|
107
|
+
Email: scott@rubric-protocol.com
|
|
100
108
|
|
|
101
|
-
|
|
102
|
-
import OpenAI from 'openai';
|
|
103
|
-
import { withRubric } from '@rubric-protocol/sdk';
|
|
104
|
-
|
|
105
|
-
const openai = withRubric(new OpenAI(), {
|
|
106
|
-
apiKey: process.env.RUBRIC_API_KEY!,
|
|
107
|
-
agentId: 'my-openai-agent',
|
|
108
|
-
localSigning: true,
|
|
109
|
-
backgroundQueue: true,
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
// Use exactly as before — attestation happens automatically
|
|
113
|
-
const completion = await openai.chat.completions.create({
|
|
114
|
-
model: 'gpt-4o',
|
|
115
|
-
messages: [{ role: 'user', content: 'Should we approve this claim?' }],
|
|
116
|
-
});
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
---
|
|
120
|
-
|
|
121
|
-
## High-stakes decisions
|
|
122
|
-
|
|
123
|
-
For decisions requiring immediate confirmation (medical triage, credit denial, hiring rejection), await full HCS anchoring:
|
|
124
|
-
|
|
125
|
-
```typescript
|
|
126
|
-
const confirmed = await rubric.attestAndConfirm({
|
|
127
|
-
agentId: 'triage-agent',
|
|
128
|
-
output: 'Patient flagged for immediate review.',
|
|
129
|
-
leafType: 'AGENT_OUTPUT',
|
|
130
|
-
risk: 'high',
|
|
131
|
-
}, 90_000); // timeout ms
|
|
132
|
-
|
|
133
|
-
console.log(confirmed.hcsSequenceNumber);
|
|
134
|
-
console.log(confirmed.hashScanUrl); // immutable public record
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
---
|
|
138
|
-
|
|
139
|
-
## Proof lifecycle
|
|
140
|
-
|
|
141
|
-
Every attestation returns a `LiveProof` that upgrades automatically:
|
|
142
|
-
|
|
143
|
-
| Stage | When | What you have |
|
|
144
|
-
|---|---|---|
|
|
145
|
-
| `local` | <1ms | ML-DSA-65 signature + timestamp |
|
|
146
|
-
| `anchored` | 5–10s | Merkle root committed to Rubric |
|
|
147
|
-
| `confirmed` | ~30s | HCS sequence number, HashScan URL |
|
|
148
|
-
|
|
149
|
-
```typescript
|
|
150
|
-
proof.onUpgrade('anchored', (p) => console.log(p.merkleRoot));
|
|
151
|
-
proof.onUpgrade('confirmed', (p) => console.log(p.hashScanUrl));
|
|
152
|
-
proof.onUpgrade('any', (p) => console.log(p.stage)); // fires on each upgrade
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
---
|
|
156
|
-
|
|
157
|
-
## Configuration
|
|
158
|
-
|
|
159
|
-
```typescript
|
|
160
|
-
createRubricClient({
|
|
161
|
-
apiKey: string, // required — get one at rubric-protocol.com
|
|
162
|
-
node?: 'us'|'sg'|'jp'|'ca'|'eu'|'auto', // default: 'us'
|
|
163
|
-
localSigning?: boolean, // default: false
|
|
164
|
-
keystorePath?: string, // default: ~/.rubric/sdk-keypair.json
|
|
165
|
-
keystorePassphrase?: string, // AES-256-GCM encrypts the keystore
|
|
166
|
-
backgroundQueue?: boolean, // default: false
|
|
167
|
-
enterprise?: boolean, // uses /v1/tiered-attest (Merkle batching)
|
|
168
|
-
proofUpgrade?: boolean, // auto-poll for stage upgrades
|
|
169
|
-
timeout?: number, // HTTP timeout ms, default: 15000
|
|
170
|
-
})
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
---
|
|
174
|
-
|
|
175
|
-
## Nodes
|
|
176
|
-
|
|
177
|
-
The SDK routes to Rubric's global federation automatically when `node: 'auto'`.
|
|
178
|
-
|
|
179
|
-
| Region | Endpoint |
|
|
180
|
-
|---|---|
|
|
181
|
-
| US East | `https://rubric-protocol.com/verify` |
|
|
182
|
-
| Singapore | `https://sg.rubric-protocol.com/verify` |
|
|
183
|
-
| Japan | `https://jp.rubric-protocol.com/verify` |
|
|
184
|
-
| Canada | `https://ca.rubric-protocol.com/verify` |
|
|
185
|
-
| EU Central | `https://eu.rubric-protocol.com/verify` |
|
|
186
|
-
|
|
187
|
-
---
|
|
188
|
-
|
|
189
|
-
## Security
|
|
190
|
-
|
|
191
|
-
- **ML-DSA-65** (NIST FIPS 204) — post-quantum signature scheme, same algorithm used server-side
|
|
192
|
-
- Keypairs stored at `~/.rubric/sdk-keypair.json` with optional AES-256-GCM encryption via passphrase
|
|
193
|
-
- Canonical JSON serialization ensures deterministic, tamper-evident signing
|
|
194
|
-
- All attestations anchored to [Hedera Consensus Service](https://hedera.com) — public, immutable, independently verifiable
|
|
195
|
-
|
|
196
|
-
---
|
|
197
|
-
|
|
198
|
-
## Requirements
|
|
199
|
-
|
|
200
|
-
- Node.js >= 18.0.0
|
|
201
|
-
- TypeScript >= 5.0 (if using TypeScript)
|
|
202
|
-
|
|
203
|
-
---
|
|
204
|
-
|
|
205
|
-
## Links
|
|
206
|
-
|
|
207
|
-
- [Documentation](https://rubric-protocol.com)
|
|
208
|
-
- [API Reference](https://rubric-protocol.com/docs)
|
|
209
|
-
- [HashScan](https://hashscan.io/testnet/topic/0.0.8207826) — live attestation stream
|
|
210
|
-
- [EU AI Act Article 12](https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32024R1689)
|
|
211
|
-
|
|
212
|
-
---
|
|
213
|
-
|
|
214
|
-
## License
|
|
215
|
-
|
|
216
|
-
MIT — Echelon Intelligence Systems LLC
|
|
217
|
-
|
|
218
|
-
*Patent Pending*
|
|
109
|
+
Built by Echelon Intelligence Group.
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env npx ts-node --transpile-only
|
|
2
|
+
/**
|
|
3
|
+
* TEMPUS CLI
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* tempus verify <seq> - Verify attestation by sequence number
|
|
7
|
+
* tempus recent [n] - Show last N attestations (default 10)
|
|
8
|
+
* tempus status - Federation status
|
|
9
|
+
* tempus topic - Topic info
|
|
10
|
+
*/
|
|
11
|
+
declare const MIRROR = "https://testnet.mirrornode.hedera.com";
|
|
12
|
+
declare const TOPIC = "0.0.8207826";
|
|
13
|
+
declare const cmd: string, args: string[];
|
|
14
|
+
declare const COLORS: {
|
|
15
|
+
reset: string;
|
|
16
|
+
cyan: string;
|
|
17
|
+
green: string;
|
|
18
|
+
yellow: string;
|
|
19
|
+
red: string;
|
|
20
|
+
purple: string;
|
|
21
|
+
dim: string;
|
|
22
|
+
bold: string;
|
|
23
|
+
};
|
|
24
|
+
declare function c(color: string, text: string): string;
|
|
25
|
+
declare function fetchJSON(url: string): Promise<any>;
|
|
26
|
+
declare function verifyAttestation(seq: string): Promise<void>;
|
|
27
|
+
declare function showRecent(n: number): Promise<void>;
|
|
28
|
+
declare function showStatus(): Promise<void>;
|
|
29
|
+
declare function main(): Promise<void>;
|
|
30
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG;AAEH,QAAA,MAAM,MAAM,0CAA0C,CAAC;AACvD,QAAA,MAAM,KAAK,gBAAgB,CAAC;AAE5B,QAAA,MAAU,GAAG,UAAK,IAAI,UAAgB,CAAC;AAEvC,QAAA,MAAM,MAAM;;;;;;;;;CASX,CAAC;AAEF,iBAAS,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,iBAAe,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAIlD;AAED,iBAAe,iBAAiB,CAAC,GAAG,EAAE,MAAM,iBAwC3C;AAED,iBAAe,UAAU,CAAC,CAAC,EAAE,MAAM,iBAqBlC;AAED,iBAAe,UAAU,kBAkCxB;AAED,iBAAe,IAAI,kBAmClB"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
#!/usr/bin/env npx ts-node --transpile-only
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* TEMPUS CLI
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* tempus verify <seq> - Verify attestation by sequence number
|
|
8
|
+
* tempus recent [n] - Show last N attestations (default 10)
|
|
9
|
+
* tempus status - Federation status
|
|
10
|
+
* tempus topic - Topic info
|
|
11
|
+
*/
|
|
12
|
+
const MIRROR = 'https://testnet.mirrornode.hedera.com';
|
|
13
|
+
const TOPIC = '0.0.8207826';
|
|
14
|
+
const [, , cmd, ...args] = process.argv;
|
|
15
|
+
const COLORS = {
|
|
16
|
+
reset: '\x1b[0m',
|
|
17
|
+
cyan: '\x1b[36m',
|
|
18
|
+
green: '\x1b[32m',
|
|
19
|
+
yellow: '\x1b[33m',
|
|
20
|
+
red: '\x1b[31m',
|
|
21
|
+
purple: '\x1b[35m',
|
|
22
|
+
dim: '\x1b[2m',
|
|
23
|
+
bold: '\x1b[1m',
|
|
24
|
+
};
|
|
25
|
+
function c(color, text) {
|
|
26
|
+
return `${COLORS[color] || ''}${text}${COLORS.reset}`;
|
|
27
|
+
}
|
|
28
|
+
async function fetchJSON(url) {
|
|
29
|
+
const res = await fetch(url);
|
|
30
|
+
if (!res.ok)
|
|
31
|
+
throw new Error(`HTTP ${res.status}`);
|
|
32
|
+
return res.json();
|
|
33
|
+
}
|
|
34
|
+
async function verifyAttestation(seq) {
|
|
35
|
+
console.log(c('dim', `\nFetching sequence ${seq} from topic ${TOPIC}...\n`));
|
|
36
|
+
const data = await fetchJSON(`${MIRROR}/api/v1/topics/${TOPIC}/messages/${seq}`);
|
|
37
|
+
const payload = JSON.parse(Buffer.from(data.message, 'base64').toString());
|
|
38
|
+
const isFed = payload.type === 'federation_attestation';
|
|
39
|
+
const conf = payload.confidence || 'UNKNOWN';
|
|
40
|
+
const confColor = conf === 'FULL' ? 'green' : conf === 'HIGH' ? 'cyan' : conf === 'QUORUM' ? 'yellow' : 'red';
|
|
41
|
+
console.log(c('bold', ' ╔══════════════════════════════════════════╗'));
|
|
42
|
+
console.log(c('bold', ' ║') + c('green', ' ✓ VERIFIED ATTESTATION ') + c('bold', '║'));
|
|
43
|
+
console.log(c('bold', ' ╚══════════════════════════════════════════╝'));
|
|
44
|
+
console.log('');
|
|
45
|
+
console.log(` ${c('dim', 'Sequence:')} ${c('cyan', '#' + data.sequence_number)}`);
|
|
46
|
+
console.log(` ${c('dim', 'Type:')} ${payload.type || 'unknown'}`);
|
|
47
|
+
console.log(` ${c('dim', 'Epoch:')} ${payload.epoch ?? '-'}`);
|
|
48
|
+
console.log(` ${c('dim', 'View:')} ${payload.view ?? '-'}`);
|
|
49
|
+
console.log(` ${c('dim', 'Confidence:')} ${c(confColor, conf)}`);
|
|
50
|
+
console.log(` ${c('dim', 'Signers:')} ${payload.signer_count ?? '-'}`);
|
|
51
|
+
console.log(` ${c('dim', 'Leader:')} ${payload.leader_id || '-'}`);
|
|
52
|
+
console.log(` ${c('dim', 'Timestamp:')} ${payload.timestamp || '-'}`);
|
|
53
|
+
console.log(` ${c('dim', 'Data Type:')} ${payload.data_type || '-'}`);
|
|
54
|
+
if (payload.signers) {
|
|
55
|
+
console.log(` ${c('dim', 'Signer IDs:')} ${payload.signers.map((s) => c('purple', s)).join(', ')}`);
|
|
56
|
+
}
|
|
57
|
+
if (payload.federation_nodes) {
|
|
58
|
+
console.log(` ${c('dim', 'Fed Nodes:')} ${payload.federation_nodes.join(', ')}`);
|
|
59
|
+
}
|
|
60
|
+
if (payload.sources) {
|
|
61
|
+
console.log(` ${c('dim', 'Sources:')}`);
|
|
62
|
+
payload.sources.forEach((s) => {
|
|
63
|
+
console.log(` ${c('dim', '•')} ${s.provider} (weight: ${s.weight})`);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
console.log('');
|
|
67
|
+
console.log(` ${c('dim', 'Explorer:')} ${c('cyan', `https://hashscan.io/testnet/topic/${TOPIC}/${data.sequence_number}`)}`);
|
|
68
|
+
console.log('');
|
|
69
|
+
}
|
|
70
|
+
async function showRecent(n) {
|
|
71
|
+
console.log(c('dim', `\nFetching last ${n} attestations from topic ${TOPIC}...\n`));
|
|
72
|
+
const data = await fetchJSON(`${MIRROR}/api/v1/topics/${TOPIC}/messages?order=desc&limit=${n}`);
|
|
73
|
+
console.log(c('bold', ' Seq Type Epoch Signers Confidence'));
|
|
74
|
+
console.log(c('dim', ' ───── ───────────────────────── ───── ─────── ──────────'));
|
|
75
|
+
for (const m of (data.messages || [])) {
|
|
76
|
+
try {
|
|
77
|
+
const p = JSON.parse(Buffer.from(m.message, 'base64').toString());
|
|
78
|
+
const conf = p.confidence || '-';
|
|
79
|
+
const confColor = conf === 'FULL' ? 'green' : conf === 'HIGH' ? 'cyan' : conf === 'QUORUM' ? 'yellow' : 'red';
|
|
80
|
+
const type = (p.type || 'unknown').padEnd(25);
|
|
81
|
+
const epoch = String(p.epoch ?? '-').padEnd(5);
|
|
82
|
+
const signers = String(p.signer_count ?? '-').padEnd(7);
|
|
83
|
+
console.log(` ${c('cyan', '#' + String(m.sequence_number).padEnd(4))} ${type} ${epoch} ${signers} ${c(confColor, conf)}`);
|
|
84
|
+
}
|
|
85
|
+
catch { }
|
|
86
|
+
}
|
|
87
|
+
console.log('');
|
|
88
|
+
}
|
|
89
|
+
async function showStatus() {
|
|
90
|
+
const data = await fetchJSON(`${MIRROR}/api/v1/topics/${TOPIC}/messages?order=desc&limit=50`);
|
|
91
|
+
let fedCount = 0;
|
|
92
|
+
let maxEpoch = 0;
|
|
93
|
+
let latestConf = '';
|
|
94
|
+
const signerSets = new Set();
|
|
95
|
+
const confs = {};
|
|
96
|
+
for (const m of (data.messages || [])) {
|
|
97
|
+
try {
|
|
98
|
+
const p = JSON.parse(Buffer.from(m.message, 'base64').toString());
|
|
99
|
+
if (p.type === 'federation_attestation') {
|
|
100
|
+
fedCount++;
|
|
101
|
+
maxEpoch = Math.max(maxEpoch, p.epoch || 0);
|
|
102
|
+
if (!latestConf)
|
|
103
|
+
latestConf = p.confidence || '';
|
|
104
|
+
(p.signers || []).forEach((s) => signerSets.add(s));
|
|
105
|
+
const c = p.confidence || 'UNKNOWN';
|
|
106
|
+
confs[c] = (confs[c] || 0) + 1;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch { }
|
|
110
|
+
}
|
|
111
|
+
console.log('');
|
|
112
|
+
console.log(c('bold', ' TEMPUS Federation Status'));
|
|
113
|
+
console.log(c('dim', ' ───────────────────────────'));
|
|
114
|
+
console.log(` ${c('dim', 'Topic:')} ${c('cyan', TOPIC)}`);
|
|
115
|
+
console.log(` ${c('dim', 'Network:')} Testnet`);
|
|
116
|
+
console.log(` ${c('dim', 'Total Messages:')} ${data.messages?.length || 0} (last 50)`);
|
|
117
|
+
console.log(` ${c('dim', 'Federation Atts:')} ${c('green', String(fedCount))}`);
|
|
118
|
+
console.log(` ${c('dim', 'Latest Epoch:')} ${c('purple', String(maxEpoch))}`);
|
|
119
|
+
console.log(` ${c('dim', 'Latest Confidence:')} ${latestConf}`);
|
|
120
|
+
console.log(` ${c('dim', 'Known Signers:')} ${Array.from(signerSets).map(s => c('purple', s)).join(', ')}`);
|
|
121
|
+
console.log(` ${c('dim', 'Confidence Dist:')} ${Object.entries(confs).map(([k, v]) => `${k}: ${v}`).join(', ')}`);
|
|
122
|
+
console.log('');
|
|
123
|
+
}
|
|
124
|
+
async function main() {
|
|
125
|
+
try {
|
|
126
|
+
switch (cmd) {
|
|
127
|
+
case 'verify':
|
|
128
|
+
case 'v':
|
|
129
|
+
if (!args[0]) {
|
|
130
|
+
console.log('Usage: tempus verify <seq>');
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
133
|
+
await verifyAttestation(args[0]);
|
|
134
|
+
break;
|
|
135
|
+
case 'recent':
|
|
136
|
+
case 'r':
|
|
137
|
+
await showRecent(parseInt(args[0]) || 10);
|
|
138
|
+
break;
|
|
139
|
+
case 'status':
|
|
140
|
+
case 's':
|
|
141
|
+
await showStatus();
|
|
142
|
+
break;
|
|
143
|
+
case 'topic':
|
|
144
|
+
case 't':
|
|
145
|
+
console.log(`\n Topic: ${c('cyan', TOPIC)}`);
|
|
146
|
+
console.log(` Explorer: ${c('cyan', `https://hashscan.io/testnet/topic/${TOPIC}`)}\n`);
|
|
147
|
+
break;
|
|
148
|
+
default:
|
|
149
|
+
console.log('');
|
|
150
|
+
console.log(c('bold', ' TEMPUS CLI'));
|
|
151
|
+
console.log(c('dim', ' ─────────────────'));
|
|
152
|
+
console.log(` ${c('cyan', 'tempus verify <seq>')} Verify attestation`);
|
|
153
|
+
console.log(` ${c('cyan', 'tempus recent [n]')} Last N attestations`);
|
|
154
|
+
console.log(` ${c('cyan', 'tempus status')} Federation status`);
|
|
155
|
+
console.log(` ${c('cyan', 'tempus topic')} Topic info`);
|
|
156
|
+
console.log('');
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
console.error(c('red', `\n Error: ${err.message}\n`));
|
|
161
|
+
process.exit(1);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
main();
|
|
165
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|