@calimero-network/mero-js 23.5.0 → 23.7.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-types.d.ts +14 -0
- package/dist/cloud/account-ownership.d.ts +9 -1
- package/dist/cloud/account-ownership.js +8 -2
- package/dist/cloud/cloud-client.d.ts +38 -2
- package/dist/cloud/cloud-client.js +48 -8
- package/dist/cloud/index.d.ts +1 -1
- package/dist/cloud/index.js +1 -1
- package/dist/index.browser.mjs +2 -2
- package/dist/index.browser.mjs.map +3 -3
- package/dist/index.cjs +45 -7
- package/dist/index.cjs.map +2 -2
- package/dist/index.mjs +45 -7
- package/dist/index.mjs.map +2 -2
- package/package.json +1 -1
|
@@ -1714,6 +1714,20 @@ export interface IssueOwnershipProofResponseData {
|
|
|
1714
1714
|
signedPayload: string;
|
|
1715
1715
|
/** Base64 64-byte ed25519 signature. */
|
|
1716
1716
|
signature: string;
|
|
1717
|
+
/**
|
|
1718
|
+
* Namespace proofs only: what the namespace id was derived from. Not signed;
|
|
1719
|
+
* the id commits to it. With {@link credential}, it is what lets the cloud
|
|
1720
|
+
* check that the signer is a node of the account that FOUNDED the namespace
|
|
1721
|
+
* (mdma refuses a namespace proof without both). Absent on nodes that predate
|
|
1722
|
+
* it, and on context proofs.
|
|
1723
|
+
*/
|
|
1724
|
+
founding?: NamespaceFounding;
|
|
1725
|
+
/**
|
|
1726
|
+
* Namespace proofs only: hex borsh `AccountProof<DeviceCert>` — the node's join
|
|
1727
|
+
* credential, whose account root certifies `signerPublicKey`. See
|
|
1728
|
+
* {@link founding}.
|
|
1729
|
+
*/
|
|
1730
|
+
credential?: string;
|
|
1717
1731
|
}
|
|
1718
1732
|
export interface CreateGroupInvitationRequest {
|
|
1719
1733
|
expirationTimestamp?: number;
|
|
@@ -37,7 +37,15 @@ export interface AccountOwnershipClaimInput extends AccountClaimBase {
|
|
|
37
37
|
* Input for {@link signAccountHaClaim}: the same as the session claim, minus
|
|
38
38
|
* `subject` — there is no login to bind it to.
|
|
39
39
|
*/
|
|
40
|
-
export
|
|
40
|
+
export interface AccountHaClaimInput extends AccountClaimBase {
|
|
41
|
+
/**
|
|
42
|
+
* The relay that founded the namespace (the delegated session's `relayUrl`).
|
|
43
|
+
* Signed into the claim so nobody forwarding it can swap it: the cloud
|
|
44
|
+
* resolves it to one of its own fleet relays and hands that relay's
|
|
45
|
+
* addresses to the fleet node as its admitter. Leave it out when unknown.
|
|
46
|
+
*/
|
|
47
|
+
relayUrl?: string;
|
|
48
|
+
}
|
|
41
49
|
/** The audience of the session route's claim (`/api/cloud/me/...`). */
|
|
42
50
|
export declare const ACCOUNT_OWNERSHIP_AUDIENCE = "mdma:enable-ha-namespace";
|
|
43
51
|
/** The audience of the anonymous account route's claim (`/api/cloud/accounts/...`). */
|
|
@@ -19,6 +19,8 @@ const DOMAIN = new TextEncoder().encode('calimero.mdma.account-ownership-claim.v
|
|
|
19
19
|
/** What the cloud accepts; it caps a claim's lifetime at five minutes. */
|
|
20
20
|
const DEFAULT_TTL_MS = 60000;
|
|
21
21
|
const MAX_TTL_MS = 5 * 60000;
|
|
22
|
+
/** The cloud's limit on `relay_url`. */
|
|
23
|
+
const MAX_RELAY_URL = 1024;
|
|
22
24
|
/** The audience of the session route's claim (`/api/cloud/me/...`). */
|
|
23
25
|
export const ACCOUNT_OWNERSHIP_AUDIENCE = 'mdma:enable-ha-namespace';
|
|
24
26
|
/** The audience of the anonymous account route's claim (`/api/cloud/accounts/...`). */
|
|
@@ -39,7 +41,10 @@ const hex32 = (value, what) => {
|
|
|
39
41
|
* session claim keeps its exact field order and the account claim has no
|
|
40
42
|
* `subject` key at all (not a null one: the cloud tells the two apart by it).
|
|
41
43
|
*/
|
|
42
|
-
async function signClaim(input, audience, subject) {
|
|
44
|
+
async function signClaim(input, audience, subject, relayUrl) {
|
|
45
|
+
if (relayUrl !== undefined && !(relayUrl.length > 0 && relayUrl.length <= MAX_RELAY_URL)) {
|
|
46
|
+
throw new Error(`relayUrl must be a non-empty string of at most ${MAX_RELAY_URL} characters`);
|
|
47
|
+
}
|
|
43
48
|
const ttl = input.ttlMs ?? DEFAULT_TTL_MS;
|
|
44
49
|
if (!(ttl > 0 && ttl <= MAX_TTL_MS))
|
|
45
50
|
throw new Error(`ttlMs must be in (0, ${MAX_TTL_MS}]`);
|
|
@@ -59,6 +64,7 @@ async function signClaim(input, audience, subject) {
|
|
|
59
64
|
nonce,
|
|
60
65
|
issued_at_ms: issued,
|
|
61
66
|
expires_at_ms: issued + ttl,
|
|
67
|
+
...(relayUrl === undefined ? {} : { relay_url: relayUrl }),
|
|
62
68
|
}));
|
|
63
69
|
const signature = await signer.sign(concat(DOMAIN, payload));
|
|
64
70
|
return { kind: 'account', credential: input.credential, signed_payload: base64(payload), signature: base64(signature) };
|
|
@@ -77,5 +83,5 @@ export async function signAccountOwnershipClaim(input) {
|
|
|
77
83
|
* through the account's wallet link instead.
|
|
78
84
|
*/
|
|
79
85
|
export async function signAccountHaClaim(input) {
|
|
80
|
-
return signClaim(input, ACCOUNT_HA_AUDIENCE, undefined);
|
|
86
|
+
return signClaim(input, ACCOUNT_HA_AUDIENCE, undefined, input.relayUrl);
|
|
81
87
|
}
|
|
@@ -381,9 +381,15 @@ export interface EnableHaAsAccountOptions {
|
|
|
381
381
|
signer?: Signer;
|
|
382
382
|
/** The claim's lifetime in ms; default one minute, at most five. */
|
|
383
383
|
ttlMs?: number;
|
|
384
|
+
/**
|
|
385
|
+
* The relay that founded the namespace (the delegated session's `relayUrl`).
|
|
386
|
+
* The cloud gives that relay to the fleet node as its admitter; without it
|
|
387
|
+
* the node has to find the relay by discovery.
|
|
388
|
+
*/
|
|
389
|
+
relayUrl?: string;
|
|
384
390
|
}
|
|
385
391
|
/**
|
|
386
|
-
* The cloud's
|
|
392
|
+
* The cloud's refusals of {@link CloudClient.enableHaAsAccount} that a
|
|
387
393
|
* person can do something about. Both are `409`s with `{"error": code}`.
|
|
388
394
|
*
|
|
389
395
|
* Extends {@link HTTPError}, so `instanceof HTTPError` handling still catches it.
|
|
@@ -414,6 +420,32 @@ export declare class AccountLinkedToSeveralUsersError extends AccountHaRefusedEr
|
|
|
414
420
|
name: string;
|
|
415
421
|
static readonly CODE = "account_linked_to_several_users";
|
|
416
422
|
}
|
|
423
|
+
/**
|
|
424
|
+
* `ha_request_pending` (409): another namespace of this account is waiting for
|
|
425
|
+
* its first fleet node to be admitted. The route allows one at a time; it
|
|
426
|
+
* clears once that node is admitted, or by disabling HA on it from a cloud
|
|
427
|
+
* session. The claim was not spent.
|
|
428
|
+
*/
|
|
429
|
+
export declare class HaRequestPendingError extends AccountHaRefusedError {
|
|
430
|
+
name: string;
|
|
431
|
+
static readonly CODE = "ha_request_pending";
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* `unknown_relay` (422): the cloud runs no relay at `relayUrl`. The claim was
|
|
435
|
+
* not spent.
|
|
436
|
+
*/
|
|
437
|
+
export declare class UnknownRelayError extends AccountHaRefusedError {
|
|
438
|
+
name: string;
|
|
439
|
+
static readonly CODE = "unknown_relay";
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* `relay_not_dialable` (422): the relay is the cloud's but has not reported
|
|
443
|
+
* its addresses yet. The claim was not spent; retrying later can succeed.
|
|
444
|
+
*/
|
|
445
|
+
export declare class RelayNotDialableError extends AccountHaRefusedError {
|
|
446
|
+
name: string;
|
|
447
|
+
static readonly CODE = "relay_not_dialable";
|
|
448
|
+
}
|
|
417
449
|
export declare class CloudClient {
|
|
418
450
|
private baseUrl;
|
|
419
451
|
private session;
|
|
@@ -624,7 +656,11 @@ export declare class CloudClient {
|
|
|
624
656
|
* Pass merod's response object straight through. The cloud accepts core's
|
|
625
657
|
* `signerPublicKey`/`signedPayload` casing as well as snake_case, so there is
|
|
626
658
|
* no re-keying step — and getting that wrong used to surface as a `422`
|
|
627
|
-
* naming three missing fields.
|
|
659
|
+
* naming three missing fields. Passing it whole also carries the `founding`
|
|
660
|
+
* and `credential` merod attaches: the cloud accepts a namespace proof only
|
|
661
|
+
* from a node of the account that founded the namespace, checked with those
|
|
662
|
+
* two, and only when that account is linked to this login. A node that
|
|
663
|
+
* predates them, or an admin that did not found the namespace, gets a `422`.
|
|
628
664
|
*
|
|
629
665
|
* Idempotent for the same account. A namespace already claimed by someone
|
|
630
666
|
* else is a `409`; a replayed proof nonce is a `403`.
|
|
@@ -67,7 +67,7 @@ export function pickExecutingRelay(relays) {
|
|
|
67
67
|
return (relays.find((r) => r.canExecute && r.relayUrl !== null && r.executorAccount !== null) ?? null);
|
|
68
68
|
}
|
|
69
69
|
/**
|
|
70
|
-
* The cloud's
|
|
70
|
+
* The cloud's refusals of {@link CloudClient.enableHaAsAccount} that a
|
|
71
71
|
* person can do something about. Both are `409`s with `{"error": code}`.
|
|
72
72
|
*
|
|
73
73
|
* Extends {@link HTTPError}, so `instanceof HTTPError` handling still catches it.
|
|
@@ -105,6 +105,45 @@ export class AccountLinkedToSeveralUsersError extends AccountHaRefusedError {
|
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
AccountLinkedToSeveralUsersError.CODE = 'account_linked_to_several_users';
|
|
108
|
+
/**
|
|
109
|
+
* `ha_request_pending` (409): another namespace of this account is waiting for
|
|
110
|
+
* its first fleet node to be admitted. The route allows one at a time; it
|
|
111
|
+
* clears once that node is admitted, or by disabling HA on it from a cloud
|
|
112
|
+
* session. The claim was not spent.
|
|
113
|
+
*/
|
|
114
|
+
export class HaRequestPendingError extends AccountHaRefusedError {
|
|
115
|
+
constructor() {
|
|
116
|
+
super(...arguments);
|
|
117
|
+
this.name = 'HaRequestPendingError';
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
HaRequestPendingError.CODE = 'ha_request_pending';
|
|
121
|
+
/**
|
|
122
|
+
* `unknown_relay` (422): the cloud runs no relay at `relayUrl`. The claim was
|
|
123
|
+
* not spent.
|
|
124
|
+
*/
|
|
125
|
+
export class UnknownRelayError extends AccountHaRefusedError {
|
|
126
|
+
constructor() {
|
|
127
|
+
super(...arguments);
|
|
128
|
+
this.name = 'UnknownRelayError';
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
UnknownRelayError.CODE = 'unknown_relay';
|
|
132
|
+
/**
|
|
133
|
+
* `relay_not_dialable` (422): the relay is the cloud's but has not reported
|
|
134
|
+
* its addresses yet. The claim was not spent; retrying later can succeed.
|
|
135
|
+
*/
|
|
136
|
+
export class RelayNotDialableError extends AccountHaRefusedError {
|
|
137
|
+
constructor() {
|
|
138
|
+
super(...arguments);
|
|
139
|
+
this.name = 'RelayNotDialableError';
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
RelayNotDialableError.CODE = 'relay_not_dialable';
|
|
143
|
+
const ACCOUNT_HA_REFUSALS = {
|
|
144
|
+
409: [AccountNotLinkedError, AccountLinkedToSeveralUsersError, HaRequestPendingError],
|
|
145
|
+
422: [UnknownRelayError, RelayNotDialableError],
|
|
146
|
+
};
|
|
108
147
|
/**
|
|
109
148
|
* The `error` code of a 409 body. Accepts `{"error": code}` (the contract) and
|
|
110
149
|
* FastAPI's `{"detail": code}` / `{"detail": {"error": code}}`, so how the
|
|
@@ -528,7 +567,11 @@ export class CloudClient {
|
|
|
528
567
|
* Pass merod's response object straight through. The cloud accepts core's
|
|
529
568
|
* `signerPublicKey`/`signedPayload` casing as well as snake_case, so there is
|
|
530
569
|
* no re-keying step — and getting that wrong used to surface as a `422`
|
|
531
|
-
* naming three missing fields.
|
|
570
|
+
* naming three missing fields. Passing it whole also carries the `founding`
|
|
571
|
+
* and `credential` merod attaches: the cloud accepts a namespace proof only
|
|
572
|
+
* from a node of the account that founded the namespace, checked with those
|
|
573
|
+
* two, and only when that account is linked to this login. A node that
|
|
574
|
+
* predates them, or an admin that did not found the namespace, gets a `422`.
|
|
532
575
|
*
|
|
533
576
|
* Idempotent for the same account. A namespace already claimed by someone
|
|
534
577
|
* else is a `409`; a replayed proof nonce is a `403`.
|
|
@@ -598,6 +641,7 @@ export class CloudClient {
|
|
|
598
641
|
deviceSecret: options.deviceSecret,
|
|
599
642
|
signer: options.signer,
|
|
600
643
|
ttlMs: options.ttlMs,
|
|
644
|
+
relayUrl: options.relayUrl,
|
|
601
645
|
});
|
|
602
646
|
// The path carries the ids as the claim does — lowercase hex — so a caller
|
|
603
647
|
// that kept them uppercase does not address a different resource.
|
|
@@ -607,13 +651,9 @@ export class CloudClient {
|
|
|
607
651
|
return await this.request('POST', `/api/cloud/accounts/${encodeURIComponent(account)}/namespaces/${encodeURIComponent(namespace)}/enable-ha`, { body: { ownership_proof: proof }, anonymous: true });
|
|
608
652
|
}
|
|
609
653
|
catch (err) {
|
|
610
|
-
if (err instanceof HTTPError && err.status
|
|
654
|
+
if (err instanceof HTTPError && ACCOUNT_HA_REFUSALS[err.status]) {
|
|
611
655
|
const code = conflictCode(err.bodyText);
|
|
612
|
-
const Typed =
|
|
613
|
-
? AccountNotLinkedError
|
|
614
|
-
: code === AccountLinkedToSeveralUsersError.CODE
|
|
615
|
-
? AccountLinkedToSeveralUsersError
|
|
616
|
-
: undefined;
|
|
656
|
+
const Typed = ACCOUNT_HA_REFUSALS[err.status].find((t) => t.CODE === code);
|
|
617
657
|
if (Typed && code) {
|
|
618
658
|
throw new Typed(code, err.status, err.statusText, err.url, err.headers, err.bodyText);
|
|
619
659
|
}
|
package/dist/cloud/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { CloudClient, admitterAddrsFromNetworkStatus, AccountHaRefusedError, AccountNotLinkedError, AccountLinkedToSeveralUsersError, } from './cloud-client.js';
|
|
1
|
+
export { CloudClient, admitterAddrsFromNetworkStatus, AccountHaRefusedError, AccountNotLinkedError, AccountLinkedToSeveralUsersError, HaRequestPendingError, UnknownRelayError, RelayNotDialableError, } from './cloud-client.js';
|
|
2
2
|
export type { CloudClientConfig, CloudSession, CloudNamespace, CloudRelay, CloudAccountRelay, CloudNamespaceNode, CloudNamespaceRouting, CloudMachine, CloudMachineNamespace, CloudLinkedAccount, CloudLinkedAccounts, CloudAccountLink, AccountLinkChallenge, AccountLinkProof, AccountLinkHandoff, AccountLinkCallback, AccountLoginChallenge, AccountLoginProof, EnableHAOptions, DisableHAOptions, EnableHaAsAccountOptions, } from './cloud-client.js';
|
|
3
3
|
export { connectCloud, connectCloudWithAccount } from './connect.js';
|
|
4
4
|
export type { ConnectCloudOptions, ConnectCloudWithAccountOptions, CloudConnection, } from './connect.js';
|
package/dist/cloud/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { CloudClient, admitterAddrsFromNetworkStatus, AccountHaRefusedError, AccountNotLinkedError, AccountLinkedToSeveralUsersError, } from './cloud-client.js';
|
|
1
|
+
export { CloudClient, admitterAddrsFromNetworkStatus, AccountHaRefusedError, AccountNotLinkedError, AccountLinkedToSeveralUsersError, HaRequestPendingError, UnknownRelayError, RelayNotDialableError, } from './cloud-client.js';
|
|
2
2
|
export { connectCloud, connectCloudWithAccount } from './connect.js';
|
|
3
3
|
export { signRoutingChallenge, routingProofHeaders } from './routing-proof.js';
|
|
4
4
|
// Linking an account to a cloud login from a browser — the redirect half the
|