@calimero-network/mero-js 22.0.0 → 22.2.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/README.md +7 -5
- package/dist/admin-api/admin-types.d.ts +32 -1
- package/dist/cloud/cloud-client.d.ts +44 -14
- package/dist/cloud/cloud-client.js +82 -37
- package/dist/cloud/connect.d.ts +2 -1
- package/dist/cloud/connect.js +23 -12
- package/dist/events/group.d.ts +2 -1
- package/dist/index.browser.mjs +2 -2
- package/dist/index.browser.mjs.map +3 -3
- package/dist/index.cjs +85 -42
- package/dist/index.cjs.map +2 -2
- package/dist/index.mjs +85 -42
- package/dist/index.mjs.map +2 -2
- package/dist/namespace-op/namespace-op.d.ts +8 -2
- package/dist/namespace-op/namespace-op.js +8 -2
- package/dist/relay/relay-client.d.ts +7 -4
- package/dist/relay/relay-client.js +7 -4
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -5379,6 +5379,15 @@ function base642(bytes) {
|
|
|
5379
5379
|
|
|
5380
5380
|
// src/cloud/cloud-client.ts
|
|
5381
5381
|
var DEFAULT_CLOUD_BASE_URL = "https://cloud.calimero.network";
|
|
5382
|
+
function canExecuteOf(row, legacy) {
|
|
5383
|
+
return typeof row.can_execute === "boolean" ? row.can_execute : legacy;
|
|
5384
|
+
}
|
|
5385
|
+
function teeRoleOf(row) {
|
|
5386
|
+
return typeof row.tee_role === "string" && row.tee_role !== "" ? row.tee_role : null;
|
|
5387
|
+
}
|
|
5388
|
+
function pickExecutingRelay(relays) {
|
|
5389
|
+
return relays.find((r) => r.canExecute && r.relayUrl !== null && r.executorAccount !== null) ?? null;
|
|
5390
|
+
}
|
|
5382
5391
|
var REFRESH_HEADER = "x-mdma-session-refresh";
|
|
5383
5392
|
var REFRESH_EXPIRES_HEADER = "x-mdma-session-expires";
|
|
5384
5393
|
var CloudClient = class {
|
|
@@ -5527,37 +5536,48 @@ var CloudClient = class {
|
|
|
5527
5536
|
* The relays serving one namespace: where to present an intent, and as whom.
|
|
5528
5537
|
*
|
|
5529
5538
|
* Everything a client needs in order to mint a warrant it can actually
|
|
5530
|
-
* spend. Filter on `
|
|
5531
|
-
*
|
|
5532
|
-
*
|
|
5539
|
+
* spend. Filter on `canExecute` before signing — a warrant presented to a
|
|
5540
|
+
* relay that does not relay (a `ReadOnlyTee` replica, or a node with no role
|
|
5541
|
+
* and no grant) is refused *after* the author has burned a nonce from its
|
|
5542
|
+
* monotonic sequence on it.
|
|
5533
5543
|
*/
|
|
5534
5544
|
async getNamespaceRelays(namespaceId) {
|
|
5535
5545
|
const body = await this.request(
|
|
5536
5546
|
"GET",
|
|
5537
5547
|
`/api/cloud/me/namespaces/${encodeURIComponent(namespaceId)}/relays`
|
|
5538
5548
|
);
|
|
5539
|
-
return (body.relays ?? []).map((row) =>
|
|
5540
|
-
|
|
5541
|
-
|
|
5542
|
-
|
|
5543
|
-
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
|
|
5547
|
-
|
|
5549
|
+
return (body.relays ?? []).map((row) => {
|
|
5550
|
+
const relayUrl = row.relay_url ?? null;
|
|
5551
|
+
const executorAccount = row.executor_account ?? null;
|
|
5552
|
+
const authorshipReady = row.authorship_ready === true;
|
|
5553
|
+
return {
|
|
5554
|
+
peerId: String(row.peer_id ?? ""),
|
|
5555
|
+
relayUrl,
|
|
5556
|
+
executorAccount,
|
|
5557
|
+
status: String(row.status ?? ""),
|
|
5558
|
+
authorshipReady,
|
|
5559
|
+
teeRole: teeRoleOf(row),
|
|
5560
|
+
canExecute: canExecuteOf(
|
|
5561
|
+
row,
|
|
5562
|
+
authorshipReady && relayUrl !== null && executorAccount !== null
|
|
5563
|
+
),
|
|
5564
|
+
lastSeenAt: row.last_seen_at ?? null,
|
|
5565
|
+
confirmedAt: row.confirmed_at ?? null
|
|
5566
|
+
};
|
|
5567
|
+
});
|
|
5548
5568
|
}
|
|
5549
5569
|
/**
|
|
5550
5570
|
* The first relay for `namespaceId` that can actually run an intent, or
|
|
5551
5571
|
* `null`.
|
|
5552
5572
|
*
|
|
5553
|
-
* "Can actually run one" is
|
|
5554
|
-
* gets a refusal it cannot explain: the cloud must know a URL, the
|
|
5555
|
-
* have reported the executor account a warrant has to name, and
|
|
5556
|
-
* must
|
|
5573
|
+
* "Can actually run one" is several conditions, and a client that checks
|
|
5574
|
+
* fewer gets a refusal it cannot explain: the cloud must know a URL, the
|
|
5575
|
+
* relay must have reported the executor account a warrant has to name, and
|
|
5576
|
+
* the node must relay — which the cloud folds into `canExecute`.
|
|
5557
5577
|
*/
|
|
5558
5578
|
async findExecutingRelay(namespaceId) {
|
|
5559
5579
|
const relays = await this.getNamespaceRelays(namespaceId);
|
|
5560
|
-
return relays
|
|
5580
|
+
return pickExecutingRelay(relays);
|
|
5561
5581
|
}
|
|
5562
5582
|
/**
|
|
5563
5583
|
* Where to reach a namespace without owning it: one read, both verbs.
|
|
@@ -5585,17 +5605,27 @@ var CloudClient = class {
|
|
|
5585
5605
|
});
|
|
5586
5606
|
return {
|
|
5587
5607
|
namespaceId: String(body.namespace_id ?? namespaceId),
|
|
5588
|
-
nodes: (body.admitters ?? []).map((row) =>
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5608
|
+
nodes: (body.admitters ?? []).map((row) => {
|
|
5609
|
+
const account = row.account ?? null;
|
|
5610
|
+
const relayUrl = row.relay_url ?? null;
|
|
5611
|
+
const fresh = row.fresh === true;
|
|
5612
|
+
const authorshipReady = row.authorship_ready === true;
|
|
5613
|
+
return {
|
|
5614
|
+
peerId: String(row.peer_id ?? ""),
|
|
5615
|
+
account,
|
|
5616
|
+
relayUrl,
|
|
5617
|
+
admitUrl: row.admit_url ?? null,
|
|
5618
|
+
status: String(row.status ?? ""),
|
|
5619
|
+
fresh,
|
|
5620
|
+
canAdmit: row.can_admit === true,
|
|
5621
|
+
authorshipReady,
|
|
5622
|
+
teeRole: teeRoleOf(row),
|
|
5623
|
+
canExecute: canExecuteOf(
|
|
5624
|
+
row,
|
|
5625
|
+
authorshipReady && relayUrl !== null && account !== null && fresh
|
|
5626
|
+
)
|
|
5627
|
+
};
|
|
5628
|
+
}),
|
|
5599
5629
|
servable: body.servable === true,
|
|
5600
5630
|
writable: body.writable === true
|
|
5601
5631
|
};
|
|
@@ -5726,23 +5756,32 @@ var CloudClient = class {
|
|
|
5726
5756
|
"GET",
|
|
5727
5757
|
"/api/cloud/me/machines"
|
|
5728
5758
|
);
|
|
5729
|
-
return (body.machines ?? []).map((row) =>
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
canExecute: row.can_execute === true,
|
|
5734
|
-
namespaces: (Array.isArray(row.namespaces) ? row.namespaces : []).map((n) => {
|
|
5759
|
+
return (body.machines ?? []).map((row) => {
|
|
5760
|
+
const relayUrl = row.relay_url ?? null;
|
|
5761
|
+
const executorAccount = row.executor_account ?? null;
|
|
5762
|
+
const namespaces = (Array.isArray(row.namespaces) ? row.namespaces : []).map((n) => {
|
|
5735
5763
|
const ns = n;
|
|
5736
5764
|
return {
|
|
5737
5765
|
namespaceId: String(ns.namespace_id ?? ""),
|
|
5738
5766
|
status: String(ns.status ?? ""),
|
|
5739
5767
|
authorshipReady: ns.authorship_ready === true,
|
|
5768
|
+
teeRole: teeRoleOf(ns),
|
|
5740
5769
|
fresh: ns.fresh === true,
|
|
5741
5770
|
confirmedAt: ns.confirmed_at ?? null,
|
|
5742
5771
|
lastSeenAt: ns.last_seen_at ?? null
|
|
5743
5772
|
};
|
|
5744
|
-
})
|
|
5745
|
-
|
|
5773
|
+
});
|
|
5774
|
+
return {
|
|
5775
|
+
peerId: String(row.peer_id ?? ""),
|
|
5776
|
+
relayUrl,
|
|
5777
|
+
executorAccount,
|
|
5778
|
+
canExecute: canExecuteOf(
|
|
5779
|
+
row,
|
|
5780
|
+
relayUrl !== null && executorAccount !== null && namespaces.some((n) => n.authorshipReady)
|
|
5781
|
+
),
|
|
5782
|
+
namespaces
|
|
5783
|
+
};
|
|
5784
|
+
});
|
|
5746
5785
|
}
|
|
5747
5786
|
/**
|
|
5748
5787
|
* Claim a namespace under this account, proving ownership.
|
|
@@ -7282,12 +7321,12 @@ async function connectCloud(options) {
|
|
|
7282
7321
|
const namespaces = await cloud.getMyNamespaces();
|
|
7283
7322
|
const namespace = pickNamespace(namespaces, options.namespaceId);
|
|
7284
7323
|
const relays = await cloud.getNamespaceRelays(namespace.namespaceId);
|
|
7285
|
-
const relayInfo = relays
|
|
7324
|
+
const relayInfo = pickExecutingRelay(relays);
|
|
7286
7325
|
if (!relayInfo) {
|
|
7287
7326
|
throw new Error(explainNoRelay(namespace, relays));
|
|
7288
7327
|
}
|
|
7289
7328
|
const relay = new RelayClient({
|
|
7290
|
-
// Checked by `
|
|
7329
|
+
// Checked by `pickExecutingRelay`, which is the only thing that returns a
|
|
7291
7330
|
// relay — narrowed here rather than re-validated, so the invariant lives in
|
|
7292
7331
|
// one place.
|
|
7293
7332
|
relayUrl: relayInfo.relayUrl,
|
|
@@ -7341,11 +7380,15 @@ function explainNoRelay(namespace, relays) {
|
|
|
7341
7380
|
if (relays.length === 0) {
|
|
7342
7381
|
return namespace.haStatus === "enabled" ? `namespace ${namespace.namespaceId} has HA enabled but no relay has been assigned to it yet \u2014 retry shortly` : `namespace ${namespace.namespaceId} has no relays: enable HA on it in the cloud to have an attested node assigned`;
|
|
7343
7382
|
}
|
|
7344
|
-
const
|
|
7345
|
-
if (
|
|
7383
|
+
const replicas = relays.filter((r) => r.teeRole !== null && r.teeRole !== "RelayTee");
|
|
7384
|
+
if (replicas.length === relays.length) {
|
|
7385
|
+
return `every node on namespace ${namespace.namespaceId} is a read-only TEE replica (ReadOnlyTee), which never relays delegated writes: an admin of the namespace must set its TEE admission policy with mode: 'relay' \u2014 AdminClient.setTeeAdmissionPolicy(namespaceId, { ..., mode: 'relay' }) \u2014 so fleet nodes are admitted as RelayTee`;
|
|
7386
|
+
}
|
|
7387
|
+
const waitingOnGrant = relays.filter((r) => r.teeRole === null && !r.authorshipReady);
|
|
7388
|
+
if (waitingOnGrant.length > 0 && waitingOnGrant.length + replicas.length === relays.length) {
|
|
7346
7389
|
return `every relay on namespace ${namespace.namespaceId} is waiting for the authorship grant: an admin of the namespace must grant CAN_AUTHOR_ON_BEHALF to ${waitingOnGrant.map((r) => r.executorAccount ?? r.peerId).join(", ") || "the relay account"} \u2014 with AdminClient.grantAuthorship(namespaceId, account) for these relays, and AdminClient.openToDelegatedExecution(namespaceId) so relays assigned later need no further op`;
|
|
7347
7390
|
}
|
|
7348
|
-
return `namespace ${namespace.namespaceId} has ${relays.length} relay(s), but none
|
|
7391
|
+
return `namespace ${namespace.namespaceId} has ${relays.length} relay(s), but none is ready to relay yet (a URL, an executor account and a recent heartbeat) \u2014 retry shortly`;
|
|
7349
7392
|
}
|
|
7350
7393
|
async function defaultNonceSource(deviceSecret) {
|
|
7351
7394
|
const key = `mero-js:warrant-nonce:${hex(await derivePublicKey(deviceSecret))}`;
|
|
@@ -8017,7 +8060,7 @@ function splitVersion2(version) {
|
|
|
8017
8060
|
}
|
|
8018
8061
|
|
|
8019
8062
|
// src/namespace-op/namespace-op.ts
|
|
8020
|
-
var SIGNED_NAMESPACE_OP_SCHEMA_VERSION =
|
|
8063
|
+
var SIGNED_NAMESPACE_OP_SCHEMA_VERSION = 12;
|
|
8021
8064
|
var NAMESPACE_SIGN_DOMAIN = new TextEncoder().encode("calimero.namespace.v1");
|
|
8022
8065
|
var NAMESPACE_OP_ROOT = 0;
|
|
8023
8066
|
var ROOT_OP = {
|