@calimero-network/mero-js 19.24.0 → 19.25.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/admin-api/admin-client.d.ts +29 -1
- package/dist/admin-api/admin-client.js +43 -0
- package/dist/admin-api/admin-types.d.ts +78 -0
- package/dist/index.browser.mjs +2 -2
- package/dist/index.browser.mjs.map +3 -3
- package/dist/index.cjs +86 -3
- package/dist/index.cjs.map +2 -2
- package/dist/index.mjs +86 -3
- package/dist/index.mjs.map +2 -2
- package/dist/sealed/sealed.d.ts +5 -1
- package/dist/sealed/sealed.js +50 -3
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -823,6 +823,14 @@ var AdminApiClient = class {
|
|
|
823
823
|
async healthCheck() {
|
|
824
824
|
return unwrap(await this.httpClient.get("/admin-api/health"));
|
|
825
825
|
}
|
|
826
|
+
/**
|
|
827
|
+
* Whether the node has finished starting and its store answers. Public, like
|
|
828
|
+
* {@link healthCheck}; unlike it, a node that is up but not ready answers
|
|
829
|
+
* `503`, which this surfaces as an `HTTPError` whose body names the stage.
|
|
830
|
+
*/
|
|
831
|
+
async readinessCheck() {
|
|
832
|
+
return unwrap(await this.httpClient.get("/admin-api/ready"));
|
|
833
|
+
}
|
|
826
834
|
async isAuthed() {
|
|
827
835
|
return this.httpClient.get("/admin-api/is-authed");
|
|
828
836
|
}
|
|
@@ -1217,6 +1225,23 @@ var AdminApiClient = class {
|
|
|
1217
1225
|
)
|
|
1218
1226
|
);
|
|
1219
1227
|
}
|
|
1228
|
+
/**
|
|
1229
|
+
* Read a context as the session's ACCOUNT, without minting a warrant.
|
|
1230
|
+
*
|
|
1231
|
+
* Needs an account-authenticated session — one from {@link login}, not the
|
|
1232
|
+
* admin password login — and refuses otherwise with a `401`. The account must
|
|
1233
|
+
* be a member of the group owning the context (`403` if not), and the method
|
|
1234
|
+
* must be declared read-only in the app's ABI (`409` if not; a write needs
|
|
1235
|
+
* {@link performIntent}).
|
|
1236
|
+
*/
|
|
1237
|
+
async queryContext(contextId, request) {
|
|
1238
|
+
return unwrap(
|
|
1239
|
+
await this.httpClient.post(
|
|
1240
|
+
`/admin-api/contexts/${contextId}/query`,
|
|
1241
|
+
request
|
|
1242
|
+
)
|
|
1243
|
+
);
|
|
1244
|
+
}
|
|
1220
1245
|
/**
|
|
1221
1246
|
* Ask what this node can do for a member in `contextId`, before they sign
|
|
1222
1247
|
* anything.
|
|
@@ -1539,6 +1564,32 @@ var AdminApiClient = class {
|
|
|
1539
1564
|
}
|
|
1540
1565
|
return response;
|
|
1541
1566
|
}
|
|
1567
|
+
/**
|
|
1568
|
+
* Member accounts in the group and the devices bound to each. An admin node
|
|
1569
|
+
* sees every account; a plain member only its own. `403` if this node is not a
|
|
1570
|
+
* member of the group.
|
|
1571
|
+
*/
|
|
1572
|
+
async listMemberDevices(groupId, options = {}) {
|
|
1573
|
+
const params = new URLSearchParams();
|
|
1574
|
+
if (options.offset !== void 0) params.set("offset", String(options.offset));
|
|
1575
|
+
if (options.limit !== void 0) params.set("limit", String(options.limit));
|
|
1576
|
+
const query = params.toString();
|
|
1577
|
+
const path = `/admin-api/groups/${groupId}/member-devices${query ? `?${query}` : ""}`;
|
|
1578
|
+
return this.httpClient.get(path);
|
|
1579
|
+
}
|
|
1580
|
+
/**
|
|
1581
|
+
* Seal a small payload to a member account's root key. This node must be a
|
|
1582
|
+
* member of the group, and `account` must be an account the group knows, so
|
|
1583
|
+
* the route reaches no further than the caller already does.
|
|
1584
|
+
*/
|
|
1585
|
+
async sealToAccount(groupId, account, request) {
|
|
1586
|
+
return unwrap(
|
|
1587
|
+
await this.httpClient.post(
|
|
1588
|
+
`/admin-api/groups/${groupId}/accounts/${account}/seal`,
|
|
1589
|
+
request
|
|
1590
|
+
)
|
|
1591
|
+
);
|
|
1592
|
+
}
|
|
1542
1593
|
async listGroupContexts(groupId) {
|
|
1543
1594
|
return unwrap(await this.httpClient.get(`/admin-api/groups/${groupId}/contexts`));
|
|
1544
1595
|
}
|
|
@@ -6654,6 +6705,8 @@ var HEADER_LEN = 1 + SESSION_ID_LEN + 8;
|
|
|
6654
6705
|
var FRAME_HEAD = 0;
|
|
6655
6706
|
var FRAME_DATA = 1;
|
|
6656
6707
|
var FRAME_END = 2;
|
|
6708
|
+
var MAX_FRAME_LEN = 1 + 64 * 1024 + 16;
|
|
6709
|
+
var MAX_HANDSHAKE_REPLY = 1024;
|
|
6657
6710
|
var RENEW_BEFORE_MS = 6e4;
|
|
6658
6711
|
var TRANSPORT_BINDING_DOMAIN = "calimero.tee-attest.transport-key.v1";
|
|
6659
6712
|
var NULL_BODY_STATUSES = [101, 204, 205, 304];
|
|
@@ -6665,10 +6718,11 @@ var StaleTransportKeyError = class extends Error {
|
|
|
6665
6718
|
}
|
|
6666
6719
|
};
|
|
6667
6720
|
var SealedTransportError = class extends Error {
|
|
6668
|
-
constructor(status, code, message) {
|
|
6721
|
+
constructor(status, code, message, retryAfterMs) {
|
|
6669
6722
|
super(message);
|
|
6670
6723
|
this.status = status;
|
|
6671
6724
|
this.code = code;
|
|
6725
|
+
this.retryAfterMs = retryAfterMs;
|
|
6672
6726
|
this.name = "SealedTransportError";
|
|
6673
6727
|
}
|
|
6674
6728
|
};
|
|
@@ -6772,6 +6826,15 @@ async function checkedKey(key) {
|
|
|
6772
6826
|
return bytes;
|
|
6773
6827
|
}
|
|
6774
6828
|
async function handshake(baseFetch, nodeUrl, transportKey) {
|
|
6829
|
+
try {
|
|
6830
|
+
return await handshakeOnce(baseFetch, nodeUrl, transportKey);
|
|
6831
|
+
} catch (error) {
|
|
6832
|
+
if (!(error instanceof SealedTransportError) || error.code !== "busy") throw error;
|
|
6833
|
+
await new Promise((resolve) => setTimeout(resolve, error.retryAfterMs ?? 1e3));
|
|
6834
|
+
return handshakeOnce(baseFetch, nodeUrl, transportKey);
|
|
6835
|
+
}
|
|
6836
|
+
}
|
|
6837
|
+
async function handshakeOnce(baseFetch, nodeUrl, transportKey) {
|
|
6775
6838
|
const noise = await initiate(transportKey, PROLOGUE);
|
|
6776
6839
|
const response = await baseFetch(`${nodeUrl}${HANDSHAKE_PATH}`, {
|
|
6777
6840
|
method: "POST",
|
|
@@ -6781,7 +6844,7 @@ async function handshake(baseFetch, nodeUrl, transportKey) {
|
|
|
6781
6844
|
if (response.headers.get("content-type") !== SEALED_CONTENT_TYPE) {
|
|
6782
6845
|
throw await envelopeRefusal(response);
|
|
6783
6846
|
}
|
|
6784
|
-
const reply =
|
|
6847
|
+
const reply = await readAtMost(response, MAX_HANDSHAKE_REPLY);
|
|
6785
6848
|
return sessionFrom(noise, reply);
|
|
6786
6849
|
}
|
|
6787
6850
|
async function sessionFrom(noise, reply) {
|
|
@@ -6907,6 +6970,10 @@ function frameReader(reader) {
|
|
|
6907
6970
|
async next() {
|
|
6908
6971
|
if (!await fill(4)) return null;
|
|
6909
6972
|
const length = new DataView(buffer.buffer, buffer.byteOffset).getUint32(0, false);
|
|
6973
|
+
if (length > MAX_FRAME_LEN) {
|
|
6974
|
+
await reader.cancel();
|
|
6975
|
+
throw new Error("The sealed response is malformed: a frame is larger than the node sends");
|
|
6976
|
+
}
|
|
6910
6977
|
if (!await fill(4 + length)) return null;
|
|
6911
6978
|
const frame = buffer.slice(4, 4 + length);
|
|
6912
6979
|
buffer = buffer.slice(4 + length);
|
|
@@ -6915,6 +6982,20 @@ function frameReader(reader) {
|
|
|
6915
6982
|
cancel: () => reader.cancel()
|
|
6916
6983
|
};
|
|
6917
6984
|
}
|
|
6985
|
+
async function readAtMost(response, limit) {
|
|
6986
|
+
if (!response.body) return new Uint8Array();
|
|
6987
|
+
const reader = response.body.getReader();
|
|
6988
|
+
let bytes = new Uint8Array();
|
|
6989
|
+
for (; ; ) {
|
|
6990
|
+
const { done, value } = await reader.read();
|
|
6991
|
+
if (done) return bytes;
|
|
6992
|
+
bytes = concat(bytes, value);
|
|
6993
|
+
if (bytes.length > limit) {
|
|
6994
|
+
await reader.cancel();
|
|
6995
|
+
throw new Error("The handshake reply is malformed: it is too long");
|
|
6996
|
+
}
|
|
6997
|
+
}
|
|
6998
|
+
}
|
|
6918
6999
|
async function envelopeRefusal(response) {
|
|
6919
7000
|
let code;
|
|
6920
7001
|
let message = `Sealed request refused: HTTP ${response.status}`;
|
|
@@ -6925,7 +7006,9 @@ async function envelopeRefusal(response) {
|
|
|
6925
7006
|
} catch {
|
|
6926
7007
|
}
|
|
6927
7008
|
if (code === "stale_transport_key") return new StaleTransportKeyError();
|
|
6928
|
-
|
|
7009
|
+
const retryAfter = Number(response.headers.get("retry-after"));
|
|
7010
|
+
const retryAfterMs = Number.isFinite(retryAfter) && retryAfter > 0 ? Math.min(retryAfter, 5) * 1e3 : void 0;
|
|
7011
|
+
return new SealedTransportError(response.status, code, message, retryAfterMs);
|
|
6929
7012
|
}
|
|
6930
7013
|
|
|
6931
7014
|
// src/namespace-op/namespace-op.ts
|