@calimero-network/mero-js 23.4.3 → 23.6.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.
@@ -1,5 +1,8 @@
1
1
  import { type Signer } from '../signer/signer.js';
2
- /** The `ownership_proof` body for `POST /api/cloud/me/namespaces/{ns}/enable-ha`. */
2
+ /**
3
+ * The `ownership_proof` body for `POST /api/cloud/me/namespaces/{ns}/enable-ha`
4
+ * and for `POST /api/cloud/accounts/{account}/namespaces/{ns}/enable-ha`.
5
+ */
3
6
  export interface AccountOwnershipProof {
4
7
  kind: 'account';
5
8
  /** hex `AccountProof<DeviceCert>`, the account's credential. */
@@ -9,15 +12,14 @@ export interface AccountOwnershipProof {
9
12
  /** base64 ed25519 by the certified device key. */
10
13
  signature: string;
11
14
  }
12
- export interface AccountOwnershipClaimInput {
15
+ /** What every account claim needs; the audience and `subject` differ per route. */
16
+ interface AccountClaimBase {
13
17
  /** The namespace, hex: the id `foundNamespace` returned. */
14
18
  namespaceId: string;
15
19
  /** The founding account, hex. */
16
20
  accountId: string;
17
21
  /** The salt `foundNamespace` returned, hex (32 bytes). */
18
22
  salt: string;
19
- /** The cloud login's email: the claim is for this login only. */
20
- subject: string;
21
23
  /** The account's credential, hex `AccountProof<DeviceCert>`. */
22
24
  credential: string;
23
25
  deviceSecret?: string;
@@ -27,4 +29,35 @@ export interface AccountOwnershipClaimInput {
27
29
  /** For tests. */
28
30
  now?: () => number;
29
31
  }
32
+ export interface AccountOwnershipClaimInput extends AccountClaimBase {
33
+ /** The cloud login's email: the claim is for this login only. */
34
+ subject: string;
35
+ }
36
+ /**
37
+ * Input for {@link signAccountHaClaim}: the same as the session claim, minus
38
+ * `subject` — there is no login to bind it to.
39
+ */
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
+ }
49
+ /** The audience of the session route's claim (`/api/cloud/me/...`). */
50
+ export declare const ACCOUNT_OWNERSHIP_AUDIENCE = "mdma:enable-ha-namespace";
51
+ /** The audience of the anonymous account route's claim (`/api/cloud/accounts/...`). */
52
+ export declare const ACCOUNT_HA_AUDIENCE = "mdma:enable-ha-namespace-as-account";
53
+ /** The founder's claim for the SESSION route, bound to one cloud login (`subject`). */
30
54
  export declare function signAccountOwnershipClaim(input: AccountOwnershipClaimInput): Promise<AccountOwnershipProof>;
55
+ /**
56
+ * The founder's claim for the ANONYMOUS account route
57
+ * (`POST /api/cloud/accounts/{account}/namespaces/{ns}/enable-ha`): no cloud
58
+ * session, so no `subject`, and its own audience so a claim minted for one
59
+ * route can never be replayed on the other. The cloud finds the user to bill
60
+ * through the account's wallet link instead.
61
+ */
62
+ export declare function signAccountHaClaim(input: AccountHaClaimInput): Promise<AccountOwnershipProof>;
63
+ export {};
@@ -19,6 +19,12 @@ 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;
24
+ /** The audience of the session route's claim (`/api/cloud/me/...`). */
25
+ export const ACCOUNT_OWNERSHIP_AUDIENCE = 'mdma:enable-ha-namespace';
26
+ /** The audience of the anonymous account route's claim (`/api/cloud/accounts/...`). */
27
+ export const ACCOUNT_HA_AUDIENCE = 'mdma:enable-ha-namespace-as-account';
22
28
  function base64(bytes) {
23
29
  let binary = '';
24
30
  for (const b of bytes)
@@ -30,26 +36,52 @@ const hex32 = (value, what) => {
30
36
  throw new Error(`${what} must be 64 hex characters`);
31
37
  return value.toLowerCase();
32
38
  };
33
- export async function signAccountOwnershipClaim(input) {
39
+ /**
40
+ * Sign one claim. `subject` is spliced in after `salt` only when given, so the
41
+ * session claim keeps its exact field order and the account claim has no
42
+ * `subject` key at all (not a null one: the cloud tells the two apart by it).
43
+ */
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
+ }
34
48
  const ttl = input.ttlMs ?? DEFAULT_TTL_MS;
35
49
  if (!(ttl > 0 && ttl <= MAX_TTL_MS))
36
50
  throw new Error(`ttlMs must be in (0, ${MAX_TTL_MS}]`);
37
- if (!input.subject)
38
- throw new Error('subject must be the cloud login email');
51
+ const groupId = hex32(input.namespaceId, 'namespaceId');
52
+ const accountId = hex32(input.accountId, 'accountId');
53
+ const salt = hex32(input.salt, 'salt');
39
54
  const signer = await resolveSigner(input.deviceSecret, input.signer, 'deviceSecret');
40
55
  const issued = (input.now ?? Date.now)();
41
56
  const nonce = Array.from(crypto.getRandomValues(new Uint8Array(16)), (b) => b.toString(16).padStart(2, '0')).join('');
42
57
  const payload = new TextEncoder().encode(JSON.stringify({
43
58
  v: 1,
44
- audience: 'mdma:enable-ha-namespace',
45
- group_id: hex32(input.namespaceId, 'namespaceId'),
46
- account_id: hex32(input.accountId, 'accountId'),
47
- salt: hex32(input.salt, 'salt'),
48
- subject: input.subject,
59
+ audience,
60
+ group_id: groupId,
61
+ account_id: accountId,
62
+ salt,
63
+ ...(subject === undefined ? {} : { subject }),
49
64
  nonce,
50
65
  issued_at_ms: issued,
51
66
  expires_at_ms: issued + ttl,
67
+ ...(relayUrl === undefined ? {} : { relay_url: relayUrl }),
52
68
  }));
53
69
  const signature = await signer.sign(concat(DOMAIN, payload));
54
70
  return { kind: 'account', credential: input.credential, signed_payload: base64(payload), signature: base64(signature) };
55
71
  }
72
+ /** The founder's claim for the SESSION route, bound to one cloud login (`subject`). */
73
+ export async function signAccountOwnershipClaim(input) {
74
+ if (!input.subject)
75
+ throw new Error('subject must be the cloud login email');
76
+ return signClaim(input, ACCOUNT_OWNERSHIP_AUDIENCE, input.subject);
77
+ }
78
+ /**
79
+ * The founder's claim for the ANONYMOUS account route
80
+ * (`POST /api/cloud/accounts/{account}/namespaces/{ns}/enable-ha`): no cloud
81
+ * session, so no `subject`, and its own audience so a claim minted for one
82
+ * route can never be replayed on the other. The cloud finds the user to bill
83
+ * through the account's wallet link instead.
84
+ */
85
+ export async function signAccountHaClaim(input) {
86
+ return signClaim(input, ACCOUNT_HA_AUDIENCE, undefined, input.relayUrl);
87
+ }
@@ -24,8 +24,9 @@
24
24
  * ever sent, and would be a throughput bottleneck on a path that has no reason
25
25
  * to involve it.
26
26
  */
27
- import type { AccountOwnershipProof } from './account-ownership.js';
27
+ import { type AccountOwnershipProof } from './account-ownership.js';
28
28
  import { type RootSource } from '../account/index.js';
29
+ import { HTTPError } from '../http-client/web-client.js';
29
30
  import type { Signer } from '../signer/signer.js';
30
31
  import { type DiscoveryChallenge, type RoutingChallenge, type RoutingCredential } from './routing-proof.js';
31
32
  /**
@@ -365,6 +366,86 @@ export interface DisableHAOptions {
365
366
  contextId: string;
366
367
  redirectUrl?: string;
367
368
  }
369
+ /** Options for {@link CloudClient.enableHaAsAccount}. */
370
+ export interface EnableHaAsAccountOptions {
371
+ /** The namespace, hex: the id `foundNamespace` returned. */
372
+ namespaceId: string;
373
+ /** The salt `foundNamespace` returned, hex (32 bytes). */
374
+ salt: string;
375
+ /** The founding account, hex. */
376
+ accountId: string;
377
+ /** The account's credential, hex `AccountProof<DeviceCert>`. */
378
+ credential: string;
379
+ /** The certified device's secret, hex. Give this or `signer`. */
380
+ deviceSecret?: string;
381
+ signer?: Signer;
382
+ /** The claim's lifetime in ms; default one minute, at most five. */
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;
390
+ }
391
+ /**
392
+ * The cloud's refusals of {@link CloudClient.enableHaAsAccount} that a
393
+ * person can do something about. Both are `409`s with `{"error": code}`.
394
+ *
395
+ * Extends {@link HTTPError}, so `instanceof HTTPError` handling still catches it.
396
+ */
397
+ export declare class AccountHaRefusedError extends HTTPError {
398
+ /** The cloud's `error` code, verbatim. */
399
+ readonly code: string;
400
+ name: string;
401
+ constructor(
402
+ /** The cloud's `error` code, verbatim. */
403
+ code: string, status: number, statusText: string, url: string, headers: Headers, bodyText?: string);
404
+ }
405
+ /**
406
+ * `account_not_linked`: the account was never linked to a cloud user through
407
+ * the wallet, so the cloud has nobody to host the namespace for. Linking it
408
+ * fixes this; retrying does not.
409
+ */
410
+ export declare class AccountNotLinkedError extends AccountHaRefusedError {
411
+ name: string;
412
+ static readonly CODE = "account_not_linked";
413
+ }
414
+ /**
415
+ * `account_linked_to_several_users`: more than one cloud user linked this
416
+ * account, so the cloud cannot tell whose quota hosts the namespace. Unlink it
417
+ * from all but one.
418
+ */
419
+ export declare class AccountLinkedToSeveralUsersError extends AccountHaRefusedError {
420
+ name: string;
421
+ static readonly CODE = "account_linked_to_several_users";
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
+ }
368
449
  export declare class CloudClient {
369
450
  private baseUrl;
370
451
  private session;
@@ -610,6 +691,24 @@ export declare class CloudClient {
610
691
  * The login must be linked to that account.
611
692
  */
612
693
  enableFoundedNamespaceHa(namespaceId: string, ownershipProof: AccountOwnershipProof): Promise<unknown>;
694
+ /**
695
+ * Enable HA for a namespace this account founded, with **no cloud session**.
696
+ *
697
+ * The anonymous sibling of {@link enableFoundedNamespaceHa}: it signs the
698
+ * founder's claim itself ({@link signAccountHaClaim} — no `subject`, its own
699
+ * audience) and posts it to
700
+ * `/api/cloud/accounts/{accountId}/namespaces/{namespaceId}/enable-ha`. The
701
+ * cloud bills the user the account is linked to through the wallet, so the
702
+ * account must be linked to exactly one:
703
+ *
704
+ * - not linked at all → {@link AccountNotLinkedError};
705
+ * - linked to several → {@link AccountLinkedToSeveralUsersError}.
706
+ *
707
+ * A claim that does not verify is a `403` `HTTPError`; quota and the rest
708
+ * answer as the session route does. Returns the cloud's response body, the
709
+ * same shape the session route's enable-ha returns.
710
+ */
711
+ enableHaAsAccount(options: EnableHaAsAccountOptions): Promise<unknown>;
613
712
  /**
614
713
  * Stop hosting a claimed namespace.
615
714
  *
@@ -24,6 +24,7 @@
24
24
  * ever sent, and would be a throughput bottleneck on a path that has no reason
25
25
  * to involve it.
26
26
  */
27
+ import { signAccountHaClaim } from './account-ownership.js';
27
28
  import { resolveRoot, resolveRootPair, signAccountLink, signAccountLogin, } from '../account/index.js';
28
29
  import { HTTPError } from '../http-client/web-client.js';
29
30
  import { routingProofHeaders, } from './routing-proof.js';
@@ -65,6 +66,107 @@ function teeRoleOf(row) {
65
66
  export function pickExecutingRelay(relays) {
66
67
  return (relays.find((r) => r.canExecute && r.relayUrl !== null && r.executorAccount !== null) ?? null);
67
68
  }
69
+ /**
70
+ * The cloud's refusals of {@link CloudClient.enableHaAsAccount} that a
71
+ * person can do something about. Both are `409`s with `{"error": code}`.
72
+ *
73
+ * Extends {@link HTTPError}, so `instanceof HTTPError` handling still catches it.
74
+ */
75
+ export class AccountHaRefusedError extends HTTPError {
76
+ constructor(
77
+ /** The cloud's `error` code, verbatim. */
78
+ code, status, statusText, url, headers, bodyText) {
79
+ super(status, statusText, url, headers, bodyText);
80
+ this.code = code;
81
+ this.name = 'AccountHaRefusedError';
82
+ }
83
+ }
84
+ /**
85
+ * `account_not_linked`: the account was never linked to a cloud user through
86
+ * the wallet, so the cloud has nobody to host the namespace for. Linking it
87
+ * fixes this; retrying does not.
88
+ */
89
+ export class AccountNotLinkedError extends AccountHaRefusedError {
90
+ constructor() {
91
+ super(...arguments);
92
+ this.name = 'AccountNotLinkedError';
93
+ }
94
+ }
95
+ AccountNotLinkedError.CODE = 'account_not_linked';
96
+ /**
97
+ * `account_linked_to_several_users`: more than one cloud user linked this
98
+ * account, so the cloud cannot tell whose quota hosts the namespace. Unlink it
99
+ * from all but one.
100
+ */
101
+ export class AccountLinkedToSeveralUsersError extends AccountHaRefusedError {
102
+ constructor() {
103
+ super(...arguments);
104
+ this.name = 'AccountLinkedToSeveralUsersError';
105
+ }
106
+ }
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
+ };
147
+ /**
148
+ * The `error` code of a 409 body. Accepts `{"error": code}` (the contract) and
149
+ * FastAPI's `{"detail": code}` / `{"detail": {"error": code}}`, so how the
150
+ * route raises it does not change what a caller catches.
151
+ */
152
+ function conflictCode(bodyText) {
153
+ if (!bodyText)
154
+ return undefined;
155
+ try {
156
+ const body = JSON.parse(bodyText);
157
+ if (typeof body?.error === 'string')
158
+ return body.error;
159
+ if (typeof body?.detail === 'string')
160
+ return body.detail;
161
+ const nested = body?.detail?.error;
162
+ if (typeof nested === 'string')
163
+ return nested;
164
+ }
165
+ catch {
166
+ // Not JSON: not one of ours.
167
+ }
168
+ return undefined;
169
+ }
68
170
  /** Response headers MDMA uses to hand back a rolling-refreshed session. */
69
171
  const REFRESH_HEADER = 'x-mdma-session-refresh';
70
172
  const REFRESH_EXPIRES_HEADER = 'x-mdma-session-expires';
@@ -509,6 +611,52 @@ export class CloudClient {
509
611
  async enableFoundedNamespaceHa(namespaceId, ownershipProof) {
510
612
  return this.request('POST', `/api/cloud/me/namespaces/${encodeURIComponent(namespaceId)}/enable-ha`, { body: { groups: [], ownership_proof: ownershipProof } });
511
613
  }
614
+ /**
615
+ * Enable HA for a namespace this account founded, with **no cloud session**.
616
+ *
617
+ * The anonymous sibling of {@link enableFoundedNamespaceHa}: it signs the
618
+ * founder's claim itself ({@link signAccountHaClaim} — no `subject`, its own
619
+ * audience) and posts it to
620
+ * `/api/cloud/accounts/{accountId}/namespaces/{namespaceId}/enable-ha`. The
621
+ * cloud bills the user the account is linked to through the wallet, so the
622
+ * account must be linked to exactly one:
623
+ *
624
+ * - not linked at all → {@link AccountNotLinkedError};
625
+ * - linked to several → {@link AccountLinkedToSeveralUsersError}.
626
+ *
627
+ * A claim that does not verify is a `403` `HTTPError`; quota and the rest
628
+ * answer as the session route does. Returns the cloud's response body, the
629
+ * same shape the session route's enable-ha returns.
630
+ */
631
+ async enableHaAsAccount(options) {
632
+ const proof = await signAccountHaClaim({
633
+ namespaceId: options.namespaceId,
634
+ accountId: options.accountId,
635
+ salt: options.salt,
636
+ credential: options.credential,
637
+ deviceSecret: options.deviceSecret,
638
+ signer: options.signer,
639
+ ttlMs: options.ttlMs,
640
+ relayUrl: options.relayUrl,
641
+ });
642
+ // The path carries the ids as the claim does — lowercase hex — so a caller
643
+ // that kept them uppercase does not address a different resource.
644
+ const account = options.accountId.toLowerCase();
645
+ const namespace = options.namespaceId.toLowerCase();
646
+ try {
647
+ return await this.request('POST', `/api/cloud/accounts/${encodeURIComponent(account)}/namespaces/${encodeURIComponent(namespace)}/enable-ha`, { body: { ownership_proof: proof }, anonymous: true });
648
+ }
649
+ catch (err) {
650
+ if (err instanceof HTTPError && ACCOUNT_HA_REFUSALS[err.status]) {
651
+ const code = conflictCode(err.bodyText);
652
+ const Typed = ACCOUNT_HA_REFUSALS[err.status].find((t) => t.CODE === code);
653
+ if (Typed && code) {
654
+ throw new Typed(code, err.status, err.statusText, err.url, err.headers, err.bodyText);
655
+ }
656
+ }
657
+ throw err;
658
+ }
659
+ }
512
660
  /**
513
661
  * Stop hosting a claimed namespace.
514
662
  *
@@ -1,5 +1,5 @@
1
- export { CloudClient, admitterAddrsFromNetworkStatus } from './cloud-client.js';
2
- export type { CloudClientConfig, CloudSession, CloudNamespace, CloudRelay, CloudAccountRelay, CloudNamespaceNode, CloudNamespaceRouting, CloudMachine, CloudMachineNamespace, CloudLinkedAccount, CloudLinkedAccounts, CloudAccountLink, AccountLinkChallenge, AccountLinkProof, AccountLinkHandoff, AccountLinkCallback, AccountLoginChallenge, AccountLoginProof, EnableHAOptions, DisableHAOptions, } from './cloud-client.js';
1
+ export { CloudClient, admitterAddrsFromNetworkStatus, AccountHaRefusedError, AccountNotLinkedError, AccountLinkedToSeveralUsersError, HaRequestPendingError, UnknownRelayError, RelayNotDialableError, } from './cloud-client.js';
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';
5
5
  export { signRoutingChallenge, routingProofHeaders } from './routing-proof.js';
@@ -8,5 +8,5 @@ export { cloudLinkUrl, beginCloudLink, readCloudLinkCallback, completeCloudLink,
8
8
  export type { BeginCloudLinkOptions, CloudLinkCallback, CompleteCloudLinkOptions, } from './link-redirect.js';
9
9
  export { deviceEnrolmentUrl, beginDeviceEnrolment, readEnrolmentCallback, completeDeviceEnrolment, callbackIsForeign, } from './enrol-redirect.js';
10
10
  export type { DeviceEnrolmentOptions, DeviceEnrolmentCallback, CompleteDeviceEnrolmentOptions, EnrolledDevice, } from './enrol-redirect.js';
11
- export { signAccountOwnershipClaim } from './account-ownership.js';
12
- export type { AccountOwnershipProof, AccountOwnershipClaimInput } from './account-ownership.js';
11
+ export { signAccountOwnershipClaim, signAccountHaClaim, ACCOUNT_OWNERSHIP_AUDIENCE, ACCOUNT_HA_AUDIENCE, } from './account-ownership.js';
12
+ export type { AccountOwnershipProof, AccountOwnershipClaimInput, AccountHaClaimInput, } from './account-ownership.js';
@@ -1,4 +1,4 @@
1
- export { CloudClient, admitterAddrsFromNetworkStatus } 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
@@ -7,4 +7,4 @@ export { cloudLinkUrl, beginCloudLink, readCloudLinkCallback, completeCloudLink,
7
7
  // Getting this app's device key certified by a wallet on another origin — the
8
8
  // redirect that keeps the account root out of the app's reach.
9
9
  export { deviceEnrolmentUrl, beginDeviceEnrolment, readEnrolmentCallback, completeDeviceEnrolment, callbackIsForeign, } from './enrol-redirect.js';
10
- export { signAccountOwnershipClaim } from './account-ownership.js';
10
+ export { signAccountOwnershipClaim, signAccountHaClaim, ACCOUNT_OWNERSHIP_AUDIENCE, ACCOUNT_HA_AUDIENCE, } from './account-ownership.js';