@calimero-network/mero-js 18.3.0 → 19.1.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 +23 -3
- package/dist/admin-api/admin-client.js +33 -4
- package/dist/admin-api/admin-types.d.ts +19 -0
- package/dist/index.browser.mjs +2 -2
- package/dist/index.browser.mjs.map +3 -3
- package/dist/index.cjs +66 -6
- package/dist/index.cjs.map +2 -2
- package/dist/index.mjs +66 -6
- package/dist/index.mjs.map +2 -2
- package/dist/warrant/warrant.d.ts +89 -10
- package/dist/warrant/warrant.js +109 -12
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1031,13 +1031,30 @@ var AdminApiClient = class {
|
|
|
1031
1031
|
);
|
|
1032
1032
|
return { blobs: res.blobs.map((b) => ({ blobId: b.blob_id, size: b.size })) };
|
|
1033
1033
|
}
|
|
1034
|
+
/**
|
|
1035
|
+
* Blob-read query params. `context_id` is the same snake_case param
|
|
1036
|
+
* {@link uploadBlob} announces with; building it in one place keeps the read
|
|
1037
|
+
* side from drifting from the write side.
|
|
1038
|
+
*/
|
|
1039
|
+
blobPath(blobId, options) {
|
|
1040
|
+
if (!options?.contextId) return `/admin-api/blobs/${blobId}`;
|
|
1041
|
+
const params = new URLSearchParams({ context_id: options.contextId });
|
|
1042
|
+
return `/admin-api/blobs/${blobId}?${params.toString()}`;
|
|
1043
|
+
}
|
|
1034
1044
|
/**
|
|
1035
1045
|
* Download a blob's raw bytes. `GET /admin-api/blobs/:id` streams the blob
|
|
1036
1046
|
* content (e.g. `application/gzip`), NOT JSON — so fetch it as an ArrayBuffer.
|
|
1037
1047
|
* Use {@link listBlobs} for `{ blobId, size }` metadata.
|
|
1048
|
+
*
|
|
1049
|
+
* Without `contextId` the read is local-only: the node answers from its own
|
|
1050
|
+
* blob store and returns immediately, or 404s. Passing `contextId` opts into
|
|
1051
|
+
* network discovery — the node probes that context's peers (availability
|
|
1052
|
+
* nodes first) for a holder, then transfers the bytes. Budget for it: core
|
|
1053
|
+
* bounds discovery by a ~30s deadline, and the transfer is on top of that, so
|
|
1054
|
+
* the worst case is well past what a UI should block on unhinted.
|
|
1038
1055
|
*/
|
|
1039
|
-
async getBlob(blobId) {
|
|
1040
|
-
return this.httpClient.get(
|
|
1056
|
+
async getBlob(blobId, options) {
|
|
1057
|
+
return this.httpClient.get(this.blobPath(blobId, options), {
|
|
1041
1058
|
parse: "arrayBuffer"
|
|
1042
1059
|
});
|
|
1043
1060
|
}
|
|
@@ -1045,15 +1062,26 @@ var AdminApiClient = class {
|
|
|
1045
1062
|
* Fetch a blob's metadata without downloading it. `HEAD /admin-api/blobs/:id`
|
|
1046
1063
|
* returns the info in response headers (size via `content-length`, plus
|
|
1047
1064
|
* `x-blob-id`/`x-blob-hash`/`x-blob-mime-type`).
|
|
1065
|
+
*
|
|
1066
|
+
* Without `contextId` this is a local-only presence check that returns
|
|
1067
|
+
* immediately. Passing `contextId` opts into the same network discovery
|
|
1068
|
+
* {@link getBlob} uses — presence and size answered by probing the context's
|
|
1069
|
+
* peers, with no transfer — so it inherits core's ~30s discovery deadline as
|
|
1070
|
+
* its worst case. A probe only carries `found` and `size`, so a peer-sourced
|
|
1071
|
+
* answer has no `hash`/`mimeType`; read `source` to tell the two apart.
|
|
1048
1072
|
*/
|
|
1049
|
-
async getBlobInfo(blobId) {
|
|
1050
|
-
const { headers } = await this.httpClient.head(
|
|
1073
|
+
async getBlobInfo(blobId, options) {
|
|
1074
|
+
const { headers } = await this.httpClient.head(this.blobPath(blobId, options));
|
|
1051
1075
|
const size = Number(headers["content-length"]);
|
|
1052
1076
|
return {
|
|
1053
1077
|
blobId: headers["x-blob-id"] ?? blobId,
|
|
1054
1078
|
size: Number.isFinite(size) ? size : 0,
|
|
1055
1079
|
hash: headers["x-blob-hash"],
|
|
1056
|
-
mimeType: headers["x-blob-mime-type"]
|
|
1080
|
+
mimeType: headers["x-blob-mime-type"],
|
|
1081
|
+
// Nodes that predate the context-aware HEAD omit this header entirely, so
|
|
1082
|
+
// it stays undefined rather than being defaulted to 'local' — absent means
|
|
1083
|
+
// "the node didn't say", which is not the same claim as "served locally".
|
|
1084
|
+
source: headers["x-blob-source"]
|
|
1057
1085
|
};
|
|
1058
1086
|
}
|
|
1059
1087
|
// ---- Alias Management ----
|
|
@@ -3164,8 +3192,10 @@ async function derivePublicKey(secretHex) {
|
|
|
3164
3192
|
}
|
|
3165
3193
|
|
|
3166
3194
|
// src/warrant/warrant.ts
|
|
3167
|
-
var SIGN_DOMAIN = new TextEncoder().encode("calimero.warrant.
|
|
3195
|
+
var SIGN_DOMAIN = new TextEncoder().encode("calimero.warrant.v2");
|
|
3168
3196
|
var INTENT_DOMAIN = new TextEncoder().encode("calimero.warrant.intent.v1");
|
|
3197
|
+
var MAX_CITED_HEADS = 64;
|
|
3198
|
+
var UNPINNED_APP = "00".repeat(32);
|
|
3169
3199
|
async function intentHash(method, argsJson) {
|
|
3170
3200
|
const args = new TextEncoder().encode(JSON.stringify(argsJson));
|
|
3171
3201
|
return domainHash(INTENT_DOMAIN, [new TextEncoder().encode(method), args]);
|
|
@@ -3174,8 +3204,16 @@ async function signWarrant(input) {
|
|
|
3174
3204
|
const context = fromHex(input.context, "context", 32);
|
|
3175
3205
|
const authorAccount = fromHex(input.authorAccount, "authorAccount", 32);
|
|
3176
3206
|
const executor = fromHex(input.executor, "executor", 32);
|
|
3207
|
+
const appVersion = fromHex(
|
|
3208
|
+
input.appVersion ?? UNPINNED_APP,
|
|
3209
|
+
"appVersion",
|
|
3210
|
+
32
|
|
3211
|
+
);
|
|
3212
|
+
const accountHeads = citedHeads(input.accountHeads, "accountHeads");
|
|
3213
|
+
const governanceFloor = citedHeads(input.governanceFloor, "governanceFloor");
|
|
3177
3214
|
const key = await importSigningKey(input.deviceSecret);
|
|
3178
3215
|
const publicKey = await derivePublicKey(input.deviceSecret);
|
|
3216
|
+
const method = new TextEncoder().encode(input.method);
|
|
3179
3217
|
const commitment = await intentHash(input.method, input.argsJson);
|
|
3180
3218
|
const nonce = u64le(input.nonce);
|
|
3181
3219
|
const notAfter = u64le(input.notAfter);
|
|
@@ -3184,7 +3222,13 @@ async function signWarrant(input) {
|
|
|
3184
3222
|
authorAccount,
|
|
3185
3223
|
publicKey,
|
|
3186
3224
|
executor,
|
|
3225
|
+
appVersion,
|
|
3226
|
+
method,
|
|
3187
3227
|
commitment,
|
|
3228
|
+
u64le(accountHeads.length),
|
|
3229
|
+
...accountHeads,
|
|
3230
|
+
u64le(governanceFloor.length),
|
|
3231
|
+
...governanceFloor,
|
|
3188
3232
|
nonce,
|
|
3189
3233
|
notAfter
|
|
3190
3234
|
]);
|
|
@@ -3197,13 +3241,29 @@ async function signWarrant(input) {
|
|
|
3197
3241
|
authorAccount,
|
|
3198
3242
|
publicKey,
|
|
3199
3243
|
executor,
|
|
3244
|
+
appVersion,
|
|
3245
|
+
u32le(method.length),
|
|
3246
|
+
method,
|
|
3200
3247
|
commitment,
|
|
3248
|
+
u32le(accountHeads.length),
|
|
3249
|
+
...accountHeads,
|
|
3250
|
+
u32le(governanceFloor.length),
|
|
3251
|
+
...governanceFloor,
|
|
3201
3252
|
nonce,
|
|
3202
3253
|
notAfter,
|
|
3203
3254
|
signature
|
|
3204
3255
|
)
|
|
3205
3256
|
);
|
|
3206
3257
|
}
|
|
3258
|
+
function citedHeads(heads, label) {
|
|
3259
|
+
const list = heads ?? [];
|
|
3260
|
+
if (list.length > MAX_CITED_HEADS) {
|
|
3261
|
+
throw new Error(
|
|
3262
|
+
`${label} cites ${list.length} heads, over the ${MAX_CITED_HEADS} a node accepts`
|
|
3263
|
+
);
|
|
3264
|
+
}
|
|
3265
|
+
return list.map((head, i) => fromHex(head, `${label}[${i}]`, 32));
|
|
3266
|
+
}
|
|
3207
3267
|
|
|
3208
3268
|
// src/relay/relay-client.ts
|
|
3209
3269
|
var DEFAULT_TTL_SECONDS = 300;
|