@calimero-network/mero-js 13.3.0 → 14.0.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/dist/account/index.d.ts +15 -15
- package/dist/account/index.js +15 -15
- package/dist/admin-api/admin-client.d.ts +12 -6
- package/dist/admin-api/admin-client.js +12 -6
- package/dist/admin-api/admin-types.d.ts +17 -11
- package/dist/events/group.d.ts +1 -1
- package/dist/index.browser.mjs +2 -2
- package/dist/index.browser.mjs.map +4 -4
- package/dist/index.cjs +151 -9
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -1
- package/dist/index.mjs +151 -9
- package/dist/index.mjs.map +4 -4
- package/dist/warrant/index.d.ts +2 -0
- package/dist/warrant/index.js +2 -0
- package/dist/warrant/warrant.d.ts +76 -0
- package/dist/warrant/warrant.js +143 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -16,6 +16,8 @@ export type { SseEventData, WsEventData, AppVersionChangedEvent, GroupMembership
|
|
|
16
16
|
export { EphemeralClient, jsonCodec } from './ephemeral/index.js';
|
|
17
17
|
export type { Codec, EphemeralEntry } from './ephemeral/index.js';
|
|
18
18
|
export * from './cloud/index.js';
|
|
19
|
+
export { signWarrant, intentHash } from './warrant/index.js';
|
|
20
|
+
export type { WarrantInput } from './warrant/index.js';
|
|
19
21
|
export * from './capabilities.js';
|
|
20
22
|
export { DEFAULT_LOCAL_NODE_PORTS, localNodeUrl, nodeEndpoint, probeNodeHealth, discoverLocalNodes, } from './nodeDiscovery.js';
|
|
21
23
|
export type { DiscoverLocalNodesOptions } from './nodeDiscovery.js';
|
package/dist/index.js
CHANGED
|
@@ -10,7 +10,7 @@ export * from './auth-api/index.js';
|
|
|
10
10
|
export * from './admin-api/index.js';
|
|
11
11
|
// Auth utilities
|
|
12
12
|
export { parseAuthCallback, buildAuthLoginUrl } from './auth/index.js';
|
|
13
|
-
// Account id encoding (hex
|
|
13
|
+
// Account id encoding (hex everywhere core spells one; an app may re-encode)
|
|
14
14
|
export { toAccountHex, toAccountBase58, sameAccount, } from './account/index.js';
|
|
15
15
|
// Token store
|
|
16
16
|
export { MemoryTokenStore, LocalStorageTokenStore } from './token-store/index.js';
|
|
@@ -22,6 +22,8 @@ export { SseClient, WsClient } from './events/index.js';
|
|
|
22
22
|
export { EphemeralClient, jsonCodec } from './ephemeral/index.js';
|
|
23
23
|
// Cloud client (enable-HA, disable-HA)
|
|
24
24
|
export * from './cloud/index.js';
|
|
25
|
+
// Warrant signing — mint the author's consent for a relay to run one intent
|
|
26
|
+
export { signWarrant, intentHash } from './warrant/index.js';
|
|
25
27
|
// Member capability bitmask constants & helpers
|
|
26
28
|
export * from './capabilities.js';
|
|
27
29
|
// Utilities
|
package/dist/index.mjs
CHANGED
|
@@ -1119,7 +1119,8 @@ var AdminApiClient = class {
|
|
|
1119
1119
|
* CAN_AUTHOR_ON_BEHALF to …", or that the nonce is already spent — so a caller
|
|
1120
1120
|
* can tell which precondition failed rather than only that one did.
|
|
1121
1121
|
*
|
|
1122
|
-
*
|
|
1122
|
+
* Mint the warrant with {@link signWarrant}; see
|
|
1123
|
+
* {@link PerformIntentRequest.warrant}.
|
|
1123
1124
|
*/
|
|
1124
1125
|
async performIntent(contextId, request) {
|
|
1125
1126
|
return unwrap(
|
|
@@ -1225,14 +1226,16 @@ var AdminApiClient = class {
|
|
|
1225
1226
|
}
|
|
1226
1227
|
/**
|
|
1227
1228
|
* `identity` is the member's ACCOUNT (64 hex), as returned by
|
|
1228
|
-
* {@link listGroupMembers} — not the
|
|
1229
|
+
* {@link listGroupMembers} — not the signing key that added them. Both are
|
|
1230
|
+
* 64 hex, so nothing but the source tells them apart.
|
|
1229
1231
|
*/
|
|
1230
1232
|
async updateMemberRole(groupId, identity, request) {
|
|
1231
1233
|
await this.httpClient.put(`/admin-api/groups/${groupId}/members/${identity}/role`, request);
|
|
1232
1234
|
}
|
|
1233
1235
|
/**
|
|
1234
1236
|
* `identity` is the member's ACCOUNT (64 hex), as returned by
|
|
1235
|
-
* {@link listGroupMembers} — not the
|
|
1237
|
+
* {@link listGroupMembers} — not the signing key that added them. Both are
|
|
1238
|
+
* 64 hex, so nothing but the source tells them apart.
|
|
1236
1239
|
*/
|
|
1237
1240
|
async getMemberCapabilities(groupId, identity) {
|
|
1238
1241
|
return unwrap(
|
|
@@ -1243,7 +1246,8 @@ var AdminApiClient = class {
|
|
|
1243
1246
|
}
|
|
1244
1247
|
/**
|
|
1245
1248
|
* `identity` is the member's ACCOUNT (64 hex), as returned by
|
|
1246
|
-
* {@link listGroupMembers} — not the
|
|
1249
|
+
* {@link listGroupMembers} — not the signing key that added them. Both are
|
|
1250
|
+
* 64 hex, so nothing but the source tells them apart.
|
|
1247
1251
|
*/
|
|
1248
1252
|
async setMemberCapabilities(groupId, identity, request) {
|
|
1249
1253
|
await this.httpClient.put(`/admin-api/groups/${groupId}/members/${identity}/capabilities`, request);
|
|
@@ -1276,7 +1280,8 @@ var AdminApiClient = class {
|
|
|
1276
1280
|
}
|
|
1277
1281
|
/**
|
|
1278
1282
|
* `identity` is the member's ACCOUNT (64 hex), as returned by
|
|
1279
|
-
* {@link listGroupMembers} — not the
|
|
1283
|
+
* {@link listGroupMembers} — not the signing key that added them. Both are
|
|
1284
|
+
* 64 hex, so nothing but the source tells them apart.
|
|
1280
1285
|
*/
|
|
1281
1286
|
async getMemberMetadata(groupId, identity) {
|
|
1282
1287
|
const response = await this.httpClient.get(
|
|
@@ -1430,7 +1435,8 @@ var AdminApiClient = class {
|
|
|
1430
1435
|
* /admin-api/groups/:group_id/members/:identity/auto-follow).
|
|
1431
1436
|
*
|
|
1432
1437
|
* `identity` is the member's ACCOUNT (64 hex), as returned by
|
|
1433
|
-
* {@link listGroupMembers} — not the
|
|
1438
|
+
* {@link listGroupMembers} — not the signing key that added them. Both are
|
|
1439
|
+
* 64 hex, so nothing but the source tells them apart.
|
|
1434
1440
|
*/
|
|
1435
1441
|
async setMemberAutoFollow(groupId, identity, request) {
|
|
1436
1442
|
await this.httpClient.put(`/admin-api/groups/${groupId}/members/${identity}/auto-follow`, request);
|
|
@@ -2495,10 +2501,10 @@ function toHex(bytes) {
|
|
|
2495
2501
|
for (const byte of bytes) out += byte.toString(16).padStart(2, "0");
|
|
2496
2502
|
return out;
|
|
2497
2503
|
}
|
|
2498
|
-
function fromHex(
|
|
2499
|
-
const bytes = new Uint8Array(
|
|
2504
|
+
function fromHex(hex2) {
|
|
2505
|
+
const bytes = new Uint8Array(hex2.length / 2);
|
|
2500
2506
|
for (let i = 0; i < bytes.length; i++) {
|
|
2501
|
-
bytes[i] = parseInt(
|
|
2507
|
+
bytes[i] = parseInt(hex2.slice(i * 2, i * 2 + 2), 16);
|
|
2502
2508
|
}
|
|
2503
2509
|
return bytes;
|
|
2504
2510
|
}
|
|
@@ -2603,6 +2609,140 @@ var CloudClient = class {
|
|
|
2603
2609
|
}
|
|
2604
2610
|
};
|
|
2605
2611
|
|
|
2612
|
+
// src/warrant/warrant.ts
|
|
2613
|
+
var SIGN_DOMAIN = new TextEncoder().encode("calimero.warrant.v1");
|
|
2614
|
+
var INTENT_DOMAIN = new TextEncoder().encode("calimero.warrant.intent.v1");
|
|
2615
|
+
var PKCS8_ED25519_PREFIX = new Uint8Array([
|
|
2616
|
+
48,
|
|
2617
|
+
46,
|
|
2618
|
+
2,
|
|
2619
|
+
1,
|
|
2620
|
+
0,
|
|
2621
|
+
48,
|
|
2622
|
+
5,
|
|
2623
|
+
6,
|
|
2624
|
+
3,
|
|
2625
|
+
43,
|
|
2626
|
+
101,
|
|
2627
|
+
112,
|
|
2628
|
+
4,
|
|
2629
|
+
34,
|
|
2630
|
+
4,
|
|
2631
|
+
32
|
|
2632
|
+
]);
|
|
2633
|
+
function hex(bytes) {
|
|
2634
|
+
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
2635
|
+
}
|
|
2636
|
+
function fromHex2(value, label, expectedBytes) {
|
|
2637
|
+
const clean = value.trim();
|
|
2638
|
+
if (!/^[0-9a-fA-F]*$/.test(clean) || clean.length !== expectedBytes * 2) {
|
|
2639
|
+
throw new Error(
|
|
2640
|
+
`${label} must be ${expectedBytes * 2} hex characters, got ${clean.length}`
|
|
2641
|
+
);
|
|
2642
|
+
}
|
|
2643
|
+
const bytes = new Uint8Array(expectedBytes);
|
|
2644
|
+
for (let i = 0; i < expectedBytes; i += 1) {
|
|
2645
|
+
bytes[i] = Number.parseInt(clean.slice(i * 2, i * 2 + 2), 16);
|
|
2646
|
+
}
|
|
2647
|
+
return bytes;
|
|
2648
|
+
}
|
|
2649
|
+
function u64le(value) {
|
|
2650
|
+
const out = new Uint8Array(8);
|
|
2651
|
+
new DataView(out.buffer).setBigUint64(0, BigInt(value), true);
|
|
2652
|
+
return out;
|
|
2653
|
+
}
|
|
2654
|
+
function concat(...parts) {
|
|
2655
|
+
const out = new Uint8Array(parts.reduce((total, p) => total + p.length, 0));
|
|
2656
|
+
let offset = 0;
|
|
2657
|
+
for (const part of parts) {
|
|
2658
|
+
out.set(part, offset);
|
|
2659
|
+
offset += part.length;
|
|
2660
|
+
}
|
|
2661
|
+
return out;
|
|
2662
|
+
}
|
|
2663
|
+
async function domainHash(domain, parts) {
|
|
2664
|
+
const chunks = [u64le(domain.length), domain];
|
|
2665
|
+
for (const part of parts) {
|
|
2666
|
+
chunks.push(u64le(part.length), part);
|
|
2667
|
+
}
|
|
2668
|
+
return new Uint8Array(
|
|
2669
|
+
await crypto.subtle.digest("SHA-256", concat(...chunks))
|
|
2670
|
+
);
|
|
2671
|
+
}
|
|
2672
|
+
async function intentHash(method, argsJson) {
|
|
2673
|
+
const args = new TextEncoder().encode(JSON.stringify(argsJson));
|
|
2674
|
+
return domainHash(INTENT_DOMAIN, [new TextEncoder().encode(method), args]);
|
|
2675
|
+
}
|
|
2676
|
+
async function importSigningKey(secretHex) {
|
|
2677
|
+
const seed = fromHex2(secretHex, "deviceSecret", 32);
|
|
2678
|
+
const pkcs8 = concat(PKCS8_ED25519_PREFIX, seed);
|
|
2679
|
+
try {
|
|
2680
|
+
return await crypto.subtle.importKey(
|
|
2681
|
+
"pkcs8",
|
|
2682
|
+
pkcs8,
|
|
2683
|
+
{ name: "Ed25519" },
|
|
2684
|
+
false,
|
|
2685
|
+
["sign"]
|
|
2686
|
+
);
|
|
2687
|
+
} catch (cause) {
|
|
2688
|
+
const detail = cause instanceof Error ? `: ${cause.message}` : "";
|
|
2689
|
+
throw new Error(
|
|
2690
|
+
"this runtime has no WebCrypto Ed25519, so a warrant cannot be signed here. Node 18.4+, Safari 17+, Firefox 129+ and Chrome 137+ have it; otherwise mint the warrant with `merod account warrant`" + detail
|
|
2691
|
+
);
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2694
|
+
async function signWarrant(input) {
|
|
2695
|
+
const context = fromHex2(input.context, "context", 32);
|
|
2696
|
+
const authorAccount = fromHex2(input.authorAccount, "authorAccount", 32);
|
|
2697
|
+
const executor = fromHex2(input.executor, "executor", 32);
|
|
2698
|
+
const key = await importSigningKey(input.deviceSecret);
|
|
2699
|
+
const publicKey = await derivePublicKey(input.deviceSecret);
|
|
2700
|
+
const commitment = await intentHash(input.method, input.argsJson);
|
|
2701
|
+
const nonce = u64le(input.nonce);
|
|
2702
|
+
const notAfter = u64le(input.notAfter);
|
|
2703
|
+
const preimage = await domainHash(SIGN_DOMAIN, [
|
|
2704
|
+
context,
|
|
2705
|
+
authorAccount,
|
|
2706
|
+
publicKey,
|
|
2707
|
+
executor,
|
|
2708
|
+
commitment,
|
|
2709
|
+
nonce,
|
|
2710
|
+
notAfter
|
|
2711
|
+
]);
|
|
2712
|
+
const signature = new Uint8Array(
|
|
2713
|
+
await crypto.subtle.sign({ name: "Ed25519" }, key, preimage)
|
|
2714
|
+
);
|
|
2715
|
+
return hex(
|
|
2716
|
+
concat(
|
|
2717
|
+
context,
|
|
2718
|
+
authorAccount,
|
|
2719
|
+
publicKey,
|
|
2720
|
+
executor,
|
|
2721
|
+
commitment,
|
|
2722
|
+
nonce,
|
|
2723
|
+
notAfter,
|
|
2724
|
+
signature
|
|
2725
|
+
)
|
|
2726
|
+
);
|
|
2727
|
+
}
|
|
2728
|
+
async function derivePublicKey(secretHex) {
|
|
2729
|
+
const seed = fromHex2(secretHex, "deviceSecret", 32);
|
|
2730
|
+
const pkcs8 = concat(PKCS8_ED25519_PREFIX, seed);
|
|
2731
|
+
const key = await crypto.subtle.importKey(
|
|
2732
|
+
"pkcs8",
|
|
2733
|
+
pkcs8,
|
|
2734
|
+
{ name: "Ed25519" },
|
|
2735
|
+
true,
|
|
2736
|
+
["sign"]
|
|
2737
|
+
);
|
|
2738
|
+
const jwk = await crypto.subtle.exportKey("jwk", key);
|
|
2739
|
+
const raw = jwk.x;
|
|
2740
|
+
return Uint8Array.from(
|
|
2741
|
+
atob(raw.replace(/-/g, "+").replace(/_/g, "/")),
|
|
2742
|
+
(c) => c.charCodeAt(0)
|
|
2743
|
+
);
|
|
2744
|
+
}
|
|
2745
|
+
|
|
2606
2746
|
// src/capabilities.ts
|
|
2607
2747
|
var CAPABILITIES = {
|
|
2608
2748
|
CAN_CREATE_CONTEXT: 1 << 0,
|
|
@@ -2715,12 +2855,14 @@ export {
|
|
|
2715
2855
|
createUniversalHttpClient,
|
|
2716
2856
|
discoverLocalNodes,
|
|
2717
2857
|
hasCap,
|
|
2858
|
+
intentHash,
|
|
2718
2859
|
jsonCodec,
|
|
2719
2860
|
localNodeUrl,
|
|
2720
2861
|
nodeEndpoint,
|
|
2721
2862
|
parseAuthCallback,
|
|
2722
2863
|
probeNodeHealth,
|
|
2723
2864
|
sameAccount,
|
|
2865
|
+
signWarrant,
|
|
2724
2866
|
toAccountBase58,
|
|
2725
2867
|
toAccountHex,
|
|
2726
2868
|
withCap,
|