genesis-mesh-sdk 0.53.0
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/CHANGELOG.md +29 -0
- package/LICENSE +21 -0
- package/README.md +276 -0
- package/dist/cjs/agreement.js +26 -0
- package/dist/cjs/attestation.js +22 -0
- package/dist/cjs/auth.js +54 -0
- package/dist/cjs/boundary.js +18 -0
- package/dist/cjs/client.js +78 -0
- package/dist/cjs/consensus.js +22 -0
- package/dist/cjs/data_usage.js +26 -0
- package/dist/cjs/disclosure.js +26 -0
- package/dist/cjs/errors.js +87 -0
- package/dist/cjs/evidence.js +18 -0
- package/dist/cjs/index.js +63 -0
- package/dist/cjs/types.js +7 -0
- package/dist/esm/agreement.js +23 -0
- package/dist/esm/agreement.js.map +1 -0
- package/dist/esm/attestation.js +19 -0
- package/dist/esm/attestation.js.map +1 -0
- package/dist/esm/auth.js +50 -0
- package/dist/esm/auth.js.map +1 -0
- package/dist/esm/boundary.js +15 -0
- package/dist/esm/boundary.js.map +1 -0
- package/dist/esm/client.js +75 -0
- package/dist/esm/client.js.map +1 -0
- package/dist/esm/consensus.js +19 -0
- package/dist/esm/consensus.js.map +1 -0
- package/dist/esm/data_usage.js +23 -0
- package/dist/esm/data_usage.js.map +1 -0
- package/dist/esm/disclosure.js +23 -0
- package/dist/esm/disclosure.js.map +1 -0
- package/dist/esm/errors.js +77 -0
- package/dist/esm/errors.js.map +1 -0
- package/dist/esm/evidence.js +15 -0
- package/dist/esm/evidence.js.map +1 -0
- package/dist/esm/index.js +42 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/types.js +7 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/types/agreement.d.ts +42 -0
- package/dist/types/agreement.d.ts.map +1 -0
- package/dist/types/attestation.d.ts +28 -0
- package/dist/types/attestation.d.ts.map +1 -0
- package/dist/types/auth.d.ts +25 -0
- package/dist/types/auth.d.ts.map +1 -0
- package/dist/types/boundary.d.ts +20 -0
- package/dist/types/boundary.d.ts.map +1 -0
- package/dist/types/client.d.ts +31 -0
- package/dist/types/client.d.ts.map +1 -0
- package/dist/types/consensus.d.ts +29 -0
- package/dist/types/consensus.d.ts.map +1 -0
- package/dist/types/data_usage.d.ts +35 -0
- package/dist/types/data_usage.d.ts.map +1 -0
- package/dist/types/disclosure.d.ts +33 -0
- package/dist/types/disclosure.d.ts.map +1 -0
- package/dist/types/errors.d.ts +32 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/evidence.d.ts +20 -0
- package/dist/types/evidence.d.ts.map +1 -0
- package/dist/types/index.d.ts +39 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/types.d.ts +228 -0
- package/dist/types/types.d.ts.map +1 -0
- package/package.json +52 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `genesis-mesh-sdk` are documented here.
|
|
4
|
+
|
|
5
|
+
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
|
+
Versions align with the [Genesis Mesh release sequence](https://github.com/GenesisMeshLabs/genesismesh/blob/main/CHANGELOG.md).
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## [0.53.0] — 2026-06-29
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `GenesisMeshClient` — unified entry point with 7 domain sub-clients
|
|
15
|
+
- `AgreementClient` — capability offer, counter, accept, verify
|
|
16
|
+
- `BoundaryClient` — boundary decision and verification
|
|
17
|
+
- `EvidenceClient` — trust evidence build and verify
|
|
18
|
+
- `AttestationClient` — membership attestation issue, revoke, recognition policy
|
|
19
|
+
- `DisclosureClient` — selective Merkle capability disclosure, nullifier
|
|
20
|
+
- `ConsensusClient` — validator vote, consensus proof assembly and verify
|
|
21
|
+
- `DataUsageClient` — data license policy, access intent, verify
|
|
22
|
+
- `src/auth.ts` — `canonicalJson`, `signBytes`, `buildAdminHeaders` (Ed25519 / PKCS8-DER)
|
|
23
|
+
- `src/client.ts` — `HttpTransport` with fetch, timeout, and typed error mapping
|
|
24
|
+
- `src/errors.ts` — `GenesisMeshError` and typed subclasses for all NA error codes
|
|
25
|
+
- `src/types.ts` — 30+ protocol interfaces matching the NA JSON wire format
|
|
26
|
+
- ESM and CJS dual build (`dist/esm/`, `dist/cjs/`, `dist/types/`)
|
|
27
|
+
- 74 Jest unit tests covering all sub-clients
|
|
28
|
+
|
|
29
|
+
[0.53.0]: https://github.com/GenesisMeshLabs/sdk-typescript/releases/tag/v0.53.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Genesis Mesh Labs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
# genesis-mesh-sdk
|
|
2
|
+
|
|
3
|
+
TypeScript SDK for the Genesis Mesh Network Authority HTTP API.
|
|
4
|
+
|
|
5
|
+
**Node.js ≥ 20 required. Zero runtime dependencies.**
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install genesis-mesh-sdk
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick start
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { GenesisMeshClient } from 'genesis-mesh-sdk';
|
|
17
|
+
import { readFileSync } from 'node:fs';
|
|
18
|
+
|
|
19
|
+
// Load operator key seed (32 bytes, base64-encoded, from operator.key file)
|
|
20
|
+
const signingKeyBase64 = readFileSync('/path/to/keys/operator.key', 'utf-8')
|
|
21
|
+
.split('\n')
|
|
22
|
+
.find(l => !l.startsWith('#'))!
|
|
23
|
+
.trim();
|
|
24
|
+
|
|
25
|
+
const client = new GenesisMeshClient({
|
|
26
|
+
baseUrl: 'http://127.0.0.1:9443',
|
|
27
|
+
signingKeyBase64,
|
|
28
|
+
keyId: 'operator-local', // must match the NA's registered operator key
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Sub-clients
|
|
33
|
+
|
|
34
|
+
### agreement
|
|
35
|
+
|
|
36
|
+
> **Note:** `accept` requires the NA to have a recognition treaty for the
|
|
37
|
+
> responder sovereign. Issue one first via `/admin/recognition-treaties` (see
|
|
38
|
+
> [Raw admin calls](#raw-admin-calls) below).
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
// Create a capability offer (admin — requires signing key)
|
|
42
|
+
const offer = await client.agreement.offer({
|
|
43
|
+
responder_sovereign_id: 'BETA-NA',
|
|
44
|
+
capabilities: ['read:data', 'write:log'],
|
|
45
|
+
valid_from: '2026-01-01T00:00:00Z',
|
|
46
|
+
valid_until: '2026-12-31T00:00:00Z',
|
|
47
|
+
expires_at: '2026-01-15T00:00:00Z',
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Counter an offer
|
|
51
|
+
const counter = await client.agreement.counter({
|
|
52
|
+
offer,
|
|
53
|
+
capabilities: ['read:data'], // narrowed scope
|
|
54
|
+
valid_from: '2026-01-01T00:00:00Z',
|
|
55
|
+
valid_until: '2026-06-30T00:00:00Z',
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Accept an offer or counter
|
|
59
|
+
const agreement = await client.agreement.accept({ offer });
|
|
60
|
+
// or: await client.agreement.accept({ counter, original_offer: offer });
|
|
61
|
+
|
|
62
|
+
// Verify agreement signatures (no auth required)
|
|
63
|
+
const check = await client.agreement.verify({ agreement });
|
|
64
|
+
console.log(check.accepted); // true | false
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### boundary
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
// Issue a boundary decision (admin)
|
|
71
|
+
const decision = await client.boundary.decide({
|
|
72
|
+
agreement,
|
|
73
|
+
requested_capability: 'read:data',
|
|
74
|
+
context: { session_id: 'sess-123' },
|
|
75
|
+
});
|
|
76
|
+
console.log(decision.authorized); // true | false
|
|
77
|
+
|
|
78
|
+
// Verify a boundary decision (no auth required)
|
|
79
|
+
const v = await client.boundary.verify({ decision });
|
|
80
|
+
console.log(v.accepted, v.authorized);
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### evidence
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
// Build signed trust evidence (admin)
|
|
87
|
+
// verdict must be one of: "allow" | "block" | "escalate" | "warn"
|
|
88
|
+
const evidence = await client.evidence.build({
|
|
89
|
+
decision: {
|
|
90
|
+
source_sovereign_id: 'ALPHA',
|
|
91
|
+
target_sovereign_id: 'BETA',
|
|
92
|
+
verdict: 'allow',
|
|
93
|
+
reason: 'long-standing member',
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Verify trust evidence (no auth required)
|
|
98
|
+
const ev = await client.evidence.verify({ evidence });
|
|
99
|
+
console.log(ev.accepted, ev.verdict);
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### attestation
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
// Issue a membership attestation (admin)
|
|
106
|
+
// roles must use a recognized prefix:
|
|
107
|
+
// role:anchor | role:bridge | role:client | role:operator | role:service:<name>
|
|
108
|
+
const att = await client.attestation.issue({
|
|
109
|
+
subject_id: 'node-xyz',
|
|
110
|
+
roles: ['role:client', 'role:anchor'],
|
|
111
|
+
validity_hours: 8760,
|
|
112
|
+
claims: { department: 'engineering' },
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Revoke an attestation (admin)
|
|
116
|
+
await client.attestation.revoke(att.attestation_id, { reason: 'key compromised' });
|
|
117
|
+
|
|
118
|
+
// Set recognition policy (admin)
|
|
119
|
+
await client.attestation.savePolicy({
|
|
120
|
+
recognition_policy: {
|
|
121
|
+
local_sovereign_id: 'MY-NA',
|
|
122
|
+
recognized_issuers: [], // add RecognizedIssuer entries as needed
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### disclosure
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
// Commit to a set of capabilities (admin)
|
|
131
|
+
const commitment = await client.disclosure.commit({
|
|
132
|
+
capabilities: ['read:data', 'write:log'],
|
|
133
|
+
agreement,
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// Generate a Merkle membership proof (no auth required)
|
|
137
|
+
const proof = await client.disclosure.prove({
|
|
138
|
+
capability: 'read:data',
|
|
139
|
+
capabilities: ['read:data', 'write:log'],
|
|
140
|
+
commitment,
|
|
141
|
+
prover_sovereign_id: 'BETA',
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// Issue a one-time nullifier (admin)
|
|
145
|
+
const nullifier = await client.disclosure.nullifier({ proof });
|
|
146
|
+
|
|
147
|
+
// Verify the proof (no auth required)
|
|
148
|
+
const dv = await client.disclosure.verify({ proof, commitment });
|
|
149
|
+
console.log(dv.valid);
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### consensus
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
// Cast a validator vote (admin)
|
|
156
|
+
const vote = await client.consensus.vote({
|
|
157
|
+
justification_proof: { proof_id: 'jp-001', decision_id: 'dec-001' },
|
|
158
|
+
vote: true,
|
|
159
|
+
reason: 'evidence satisfactory',
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// Assemble a consensus proof (admin)
|
|
163
|
+
const cp = await client.consensus.proof({
|
|
164
|
+
justification_proof: { proof_id: 'jp-001', decision_id: 'dec-001' },
|
|
165
|
+
votes: [vote],
|
|
166
|
+
required_threshold: 1,
|
|
167
|
+
validator_sovereign_ids: ['ALPHA'],
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Verify the consensus proof (no auth required)
|
|
171
|
+
const cv = await client.consensus.verify({ proof: cp });
|
|
172
|
+
console.log(cv.valid);
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### dataUsage
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
// Create a data license policy (admin)
|
|
179
|
+
const pol = await client.dataUsage.createPolicy({
|
|
180
|
+
licensee_sovereign_id: 'BETA',
|
|
181
|
+
allowed_source_ids: ['src-a'],
|
|
182
|
+
allowed_access_types: ['read', 'aggregate'],
|
|
183
|
+
valid_from: '2026-01-01T00:00:00Z',
|
|
184
|
+
valid_until: '2026-12-31T00:00:00Z',
|
|
185
|
+
max_volume_bytes_per_session: 104857600,
|
|
186
|
+
prohibited_classification_tags: ['pii'],
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
// Create a data access intent (admin)
|
|
190
|
+
// source_type: "personal" | "proprietary" | "public" | "synthetic"
|
|
191
|
+
const intent = await client.dataUsage.createIntent({
|
|
192
|
+
sources: [{
|
|
193
|
+
source_id: 'src-a',
|
|
194
|
+
source_type: 'public',
|
|
195
|
+
owner_sovereign_id: 'MY-NA',
|
|
196
|
+
classification_tags: ['public'],
|
|
197
|
+
}],
|
|
198
|
+
access_types: ['read'],
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// Get the active policy (no auth required)
|
|
202
|
+
const activePol = await client.dataUsage.getPolicy();
|
|
203
|
+
|
|
204
|
+
// Verify intent against policy (no auth required)
|
|
205
|
+
const dv = await client.dataUsage.verify({ intent, policy: pol });
|
|
206
|
+
console.log(dv.valid, dv.violations);
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Raw admin calls
|
|
210
|
+
|
|
211
|
+
For NA routes not yet covered by a sub-client (e.g. `/admin/recognition-treaties`),
|
|
212
|
+
use `buildAdminHeaders` directly:
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
import { buildAdminHeaders } from 'genesis-mesh-sdk';
|
|
216
|
+
|
|
217
|
+
const body = {
|
|
218
|
+
subject_sovereign_id: 'BETA-NA',
|
|
219
|
+
subject_public_keys: ['<base64-ed25519-pubkey>'],
|
|
220
|
+
scope: { allowed_roles: ['role:client'] },
|
|
221
|
+
validity_hours: 24,
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
const headers = buildAdminHeaders(body, keyId, signingKeyBase64);
|
|
225
|
+
const res = await fetch(`${baseUrl}/admin/recognition-treaties`, {
|
|
226
|
+
method: 'POST',
|
|
227
|
+
headers: { 'Content-Type': 'application/json', ...headers },
|
|
228
|
+
body: JSON.stringify(body),
|
|
229
|
+
});
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## Error handling
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
import {
|
|
236
|
+
UnauthorizedError,
|
|
237
|
+
RateLimitError,
|
|
238
|
+
ValidationError,
|
|
239
|
+
NotFoundError,
|
|
240
|
+
NetworkError,
|
|
241
|
+
} from 'genesis-mesh-sdk';
|
|
242
|
+
|
|
243
|
+
try {
|
|
244
|
+
await client.agreement.offer({ ... });
|
|
245
|
+
} catch (err) {
|
|
246
|
+
if (err instanceof UnauthorizedError) { /* bad signing key or stale timestamp */ }
|
|
247
|
+
if (err instanceof RateLimitError) { /* back off and retry */ }
|
|
248
|
+
if (err instanceof ValidationError) { /* inspect err.message and err.code */ }
|
|
249
|
+
if (err instanceof NetworkError) { /* connection refused or timeout */ }
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## Admin authentication
|
|
254
|
+
|
|
255
|
+
Admin routes are authenticated with four HTTP headers generated from an Ed25519 operator key:
|
|
256
|
+
|
|
257
|
+
| Header | Description |
|
|
258
|
+
|---|---|
|
|
259
|
+
| `X-Admin-Key-Id` | Key identifier registered with the NA |
|
|
260
|
+
| `X-Admin-Signature` | Ed25519 signature over `canonicalJson({body, key_id, nonce, timestamp})` |
|
|
261
|
+
| `X-Admin-Timestamp` | ISO 8601 UTC timestamp (must be within NA's nonce window) |
|
|
262
|
+
| `X-Admin-Nonce` | UUID v4 replay-protection token (single use) |
|
|
263
|
+
|
|
264
|
+
The SDK handles all of this automatically when `signingKeyBase64` is provided.
|
|
265
|
+
|
|
266
|
+
## Build
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
npm run build # ESM → dist/esm/ and CJS → dist/cjs/
|
|
270
|
+
npm run typecheck # type-check without emitting
|
|
271
|
+
npm test # run 74 Jest tests
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## License
|
|
275
|
+
|
|
276
|
+
MIT
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AgreementClient = void 0;
|
|
4
|
+
class AgreementClient {
|
|
5
|
+
http;
|
|
6
|
+
constructor(http) {
|
|
7
|
+
this.http = http;
|
|
8
|
+
}
|
|
9
|
+
/** Create and sign a capability offer (admin). */
|
|
10
|
+
offer(params) {
|
|
11
|
+
return this.http.adminPost('/admin/agreements/offer', params);
|
|
12
|
+
}
|
|
13
|
+
/** Create and sign a counter-offer (admin). */
|
|
14
|
+
counter(params) {
|
|
15
|
+
return this.http.adminPost('/admin/agreements/counter', params);
|
|
16
|
+
}
|
|
17
|
+
/** Accept an offer or counter (admin). */
|
|
18
|
+
accept(params) {
|
|
19
|
+
return this.http.adminPost('/admin/agreements/accept', params);
|
|
20
|
+
}
|
|
21
|
+
/** Verify agreement signatures (unauthenticated). */
|
|
22
|
+
verify(params) {
|
|
23
|
+
return this.http.publicPost('/agreements/verify', params);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.AgreementClient = AgreementClient;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AttestationClient = void 0;
|
|
4
|
+
class AttestationClient {
|
|
5
|
+
http;
|
|
6
|
+
constructor(http) {
|
|
7
|
+
this.http = http;
|
|
8
|
+
}
|
|
9
|
+
/** Issue a signed membership attestation (admin). */
|
|
10
|
+
issue(params) {
|
|
11
|
+
return this.http.adminPost('/admin/attestations', params);
|
|
12
|
+
}
|
|
13
|
+
/** Revoke a membership attestation by ID (admin). */
|
|
14
|
+
revoke(attestationId, params = {}) {
|
|
15
|
+
return this.http.adminPost(`/admin/attestations/${attestationId}/revoke`, params);
|
|
16
|
+
}
|
|
17
|
+
/** Set the active recognition policy for this sovereign (admin). */
|
|
18
|
+
savePolicy(params) {
|
|
19
|
+
return this.http.adminPost('/admin/recognition-policy', params);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.AttestationClient = AttestationClient;
|
package/dist/cjs/auth.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Admin authentication for Genesis Mesh NA endpoints.
|
|
4
|
+
*
|
|
5
|
+
* The NA verifies requests via four HTTP headers:
|
|
6
|
+
* X-Admin-Key-Id — which operator key was used
|
|
7
|
+
* X-Admin-Signature — Ed25519(canonicalJson({body,key_id,nonce,timestamp}))
|
|
8
|
+
* X-Admin-Timestamp — ISO 8601 UTC timestamp
|
|
9
|
+
* X-Admin-Nonce — UUID v4 replay-protection token
|
|
10
|
+
*
|
|
11
|
+
* Canonical JSON matches Python json.dumps(..., sort_keys=True, separators=(",",":")):
|
|
12
|
+
* keys are recursively sorted, output is compact with no whitespace.
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.canonicalJson = canonicalJson;
|
|
16
|
+
exports.signBytes = signBytes;
|
|
17
|
+
exports.buildAdminHeaders = buildAdminHeaders;
|
|
18
|
+
const node_crypto_1 = require("node:crypto");
|
|
19
|
+
/** Recursively produce compact sorted JSON — stable across Python and Node.js. */
|
|
20
|
+
function canonicalJson(value) {
|
|
21
|
+
if (value === null || typeof value !== 'object')
|
|
22
|
+
return JSON.stringify(value);
|
|
23
|
+
if (Array.isArray(value))
|
|
24
|
+
return '[' + value.map(canonicalJson).join(',') + ']';
|
|
25
|
+
const keys = Object.keys(value).sort();
|
|
26
|
+
const pairs = keys.map(k => `${JSON.stringify(k)}:${canonicalJson(value[k])}`);
|
|
27
|
+
return '{' + pairs.join(',') + '}';
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* PKCS8 DER prefix for an Ed25519 private key.
|
|
31
|
+
* Layout: SEQUENCE { INTEGER 0, SEQUENCE { OID 1.3.101.112 }, OCTET STRING { OCTET STRING <seed> } }
|
|
32
|
+
* Concatenate with the 32-byte seed to form a valid PKCS8 DER buffer.
|
|
33
|
+
*/
|
|
34
|
+
const ED25519_PKCS8_PREFIX = Buffer.from('302e020100300506032b657004220420', 'hex');
|
|
35
|
+
/** Sign raw bytes with an Ed25519 seed (32-byte base64-encoded private key seed). */
|
|
36
|
+
function signBytes(message, seedBase64) {
|
|
37
|
+
const seed = Buffer.from(seedBase64, 'base64');
|
|
38
|
+
const pkcs8 = Buffer.concat([ED25519_PKCS8_PREFIX, seed]);
|
|
39
|
+
const privateKey = (0, node_crypto_1.createPrivateKey)({ key: pkcs8, format: 'der', type: 'pkcs8' });
|
|
40
|
+
return (0, node_crypto_1.sign)(null, message, privateKey);
|
|
41
|
+
}
|
|
42
|
+
/** Build the four admin auth headers for a given request body. */
|
|
43
|
+
function buildAdminHeaders(body, keyId, signingKeyBase64) {
|
|
44
|
+
const timestamp = new Date().toISOString();
|
|
45
|
+
const nonce = (0, node_crypto_1.randomUUID)();
|
|
46
|
+
const canonical = canonicalJson({ body, key_id: keyId, nonce, timestamp });
|
|
47
|
+
const sig = signBytes(Buffer.from(canonical, 'utf-8'), signingKeyBase64);
|
|
48
|
+
return {
|
|
49
|
+
'X-Admin-Key-Id': keyId,
|
|
50
|
+
'X-Admin-Signature': sig.toString('base64'),
|
|
51
|
+
'X-Admin-Timestamp': timestamp,
|
|
52
|
+
'X-Admin-Nonce': nonce,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BoundaryClient = void 0;
|
|
4
|
+
class BoundaryClient {
|
|
5
|
+
http;
|
|
6
|
+
constructor(http) {
|
|
7
|
+
this.http = http;
|
|
8
|
+
}
|
|
9
|
+
/** Issue a signed boundary decision for a capability request (admin). */
|
|
10
|
+
decide(params) {
|
|
11
|
+
return this.http.adminPost('/admin/boundary/decide', params);
|
|
12
|
+
}
|
|
13
|
+
/** Verify a boundary decision signature (unauthenticated). */
|
|
14
|
+
verify(params) {
|
|
15
|
+
return this.http.publicPost('/boundary/verify', params);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.BoundaryClient = BoundaryClient;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* HTTP transport layer for the Genesis Mesh SDK.
|
|
4
|
+
* Handles request dispatch, response parsing, and error mapping.
|
|
5
|
+
* Admin-route authentication is delegated to auth.ts.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.HttpTransport = void 0;
|
|
9
|
+
const auth_js_1 = require("./auth.js");
|
|
10
|
+
const errors_js_1 = require("./errors.js");
|
|
11
|
+
class HttpTransport {
|
|
12
|
+
baseUrl;
|
|
13
|
+
signingKeyBase64;
|
|
14
|
+
keyId;
|
|
15
|
+
timeout;
|
|
16
|
+
_fetch;
|
|
17
|
+
constructor(options) {
|
|
18
|
+
this.baseUrl = options.baseUrl.replace(/\/$/, '');
|
|
19
|
+
this.signingKeyBase64 = options.signingKeyBase64;
|
|
20
|
+
this.keyId = options.keyId ?? 'operator-local';
|
|
21
|
+
this.timeout = options.timeout ?? 10_000;
|
|
22
|
+
this._fetch = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
23
|
+
}
|
|
24
|
+
async adminPost(path, body) {
|
|
25
|
+
if (!this.signingKeyBase64) {
|
|
26
|
+
throw new Error('signingKeyBase64 is required for admin routes');
|
|
27
|
+
}
|
|
28
|
+
const adminHeaders = (0, auth_js_1.buildAdminHeaders)(body, this.keyId, this.signingKeyBase64);
|
|
29
|
+
return this._post(path, body, adminHeaders);
|
|
30
|
+
}
|
|
31
|
+
async publicPost(path, body) {
|
|
32
|
+
return this._post(path, body, {});
|
|
33
|
+
}
|
|
34
|
+
async publicGet(path) {
|
|
35
|
+
const url = this.baseUrl + path;
|
|
36
|
+
let response;
|
|
37
|
+
try {
|
|
38
|
+
response = await this._fetch(url, {
|
|
39
|
+
method: 'GET',
|
|
40
|
+
signal: AbortSignal.timeout(this.timeout),
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
throw new errors_js_1.NetworkError(`GET ${path} failed: ${err.message}`);
|
|
45
|
+
}
|
|
46
|
+
return this._parse(response);
|
|
47
|
+
}
|
|
48
|
+
async _post(path, body, extraHeaders) {
|
|
49
|
+
const url = this.baseUrl + path;
|
|
50
|
+
let response;
|
|
51
|
+
try {
|
|
52
|
+
response = await this._fetch(url, {
|
|
53
|
+
method: 'POST',
|
|
54
|
+
headers: { 'Content-Type': 'application/json', ...extraHeaders },
|
|
55
|
+
body: JSON.stringify(body),
|
|
56
|
+
signal: AbortSignal.timeout(this.timeout),
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
throw new errors_js_1.NetworkError(`POST ${path} failed: ${err.message}`);
|
|
61
|
+
}
|
|
62
|
+
return this._parse(response);
|
|
63
|
+
}
|
|
64
|
+
async _parse(response) {
|
|
65
|
+
let data;
|
|
66
|
+
try {
|
|
67
|
+
data = await response.json();
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
throw new errors_js_1.NetworkError(`Failed to parse response body (HTTP ${response.status})`);
|
|
71
|
+
}
|
|
72
|
+
if (!response.ok) {
|
|
73
|
+
throw (0, errors_js_1.fromHttpError)(response.status, data);
|
|
74
|
+
}
|
|
75
|
+
return data;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
exports.HttpTransport = HttpTransport;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConsensusClient = void 0;
|
|
4
|
+
class ConsensusClient {
|
|
5
|
+
http;
|
|
6
|
+
constructor(http) {
|
|
7
|
+
this.http = http;
|
|
8
|
+
}
|
|
9
|
+
/** Cast a validator vote signed by the NA (admin). */
|
|
10
|
+
vote(params) {
|
|
11
|
+
return this.http.adminPost('/admin/consensus/vote', params);
|
|
12
|
+
}
|
|
13
|
+
/** Assemble a consensus proof from votes (admin). */
|
|
14
|
+
proof(params) {
|
|
15
|
+
return this.http.adminPost('/admin/consensus/proof', params);
|
|
16
|
+
}
|
|
17
|
+
/** Verify consensus proof signature and threshold (unauthenticated). */
|
|
18
|
+
verify(params) {
|
|
19
|
+
return this.http.publicPost('/consensus/verify', params);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.ConsensusClient = ConsensusClient;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DataUsageClient = void 0;
|
|
4
|
+
class DataUsageClient {
|
|
5
|
+
http;
|
|
6
|
+
constructor(http) {
|
|
7
|
+
this.http = http;
|
|
8
|
+
}
|
|
9
|
+
/** Create and sign a data license policy (admin). */
|
|
10
|
+
createPolicy(params) {
|
|
11
|
+
return this.http.adminPost('/admin/data-usage/policy', params);
|
|
12
|
+
}
|
|
13
|
+
/** Create and sign a data access intent (admin). */
|
|
14
|
+
createIntent(params) {
|
|
15
|
+
return this.http.adminPost('/admin/data-usage/intent', params);
|
|
16
|
+
}
|
|
17
|
+
/** Get the currently active data license policy (unauthenticated). */
|
|
18
|
+
getPolicy() {
|
|
19
|
+
return this.http.publicGet('/data-usage/policy');
|
|
20
|
+
}
|
|
21
|
+
/** Verify a data access intent against a policy (unauthenticated). */
|
|
22
|
+
verify(params) {
|
|
23
|
+
return this.http.publicPost('/data-usage/verify', params);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.DataUsageClient = DataUsageClient;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DisclosureClient = void 0;
|
|
4
|
+
class DisclosureClient {
|
|
5
|
+
http;
|
|
6
|
+
constructor(http) {
|
|
7
|
+
this.http = http;
|
|
8
|
+
}
|
|
9
|
+
/** Commit to a set of capabilities under an agreement (admin). */
|
|
10
|
+
commit(params) {
|
|
11
|
+
return this.http.adminPost('/admin/disclosure/commit', params);
|
|
12
|
+
}
|
|
13
|
+
/** Issue a one-time nullifier for a proof (admin). */
|
|
14
|
+
nullifier(params) {
|
|
15
|
+
return this.http.adminPost('/admin/disclosure/nullifier', params);
|
|
16
|
+
}
|
|
17
|
+
/** Generate a Merkle membership proof (unauthenticated). */
|
|
18
|
+
prove(params) {
|
|
19
|
+
return this.http.publicPost('/disclosure/prove', params);
|
|
20
|
+
}
|
|
21
|
+
/** Verify a capability membership proof (unauthenticated). */
|
|
22
|
+
verify(params) {
|
|
23
|
+
return this.http.publicPost('/disclosure/verify', params);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.DisclosureClient = DisclosureClient;
|