@calimero-network/mero-js 26.10.0 → 27.0.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.
Files changed (220) hide show
  1. package/README.md +73 -288
  2. package/dist/cloud-v2/attestation.d.ts +91 -0
  3. package/dist/cloud-v2/attestation.js +135 -0
  4. package/dist/cloud-v2/capabilities.d.ts +30 -0
  5. package/dist/cloud-v2/capabilities.js +31 -0
  6. package/dist/cloud-v2/client.d.ts +426 -0
  7. package/dist/cloud-v2/client.js +646 -0
  8. package/dist/cloud-v2/errors.d.ts +98 -0
  9. package/dist/cloud-v2/errors.js +165 -0
  10. package/dist/cloud-v2/index.d.ts +10 -0
  11. package/dist/cloud-v2/index.js +5 -0
  12. package/dist/cloud-v2/passkey.d.ts +27 -0
  13. package/dist/cloud-v2/passkey.js +73 -0
  14. package/dist/crypto/internal.d.ts +3 -37
  15. package/dist/crypto/internal.js +3 -72
  16. package/dist/index.browser.mjs +4 -2
  17. package/dist/index.browser.mjs.map +4 -4
  18. package/dist/index.cjs +1750 -12767
  19. package/dist/index.cjs.map +4 -4
  20. package/dist/index.d.ts +3 -56
  21. package/dist/index.js +14 -75
  22. package/dist/index.mjs +1750 -12767
  23. package/dist/index.mjs.map +4 -4
  24. package/dist/sealed/index.d.ts +4 -4
  25. package/dist/sealed/index.js +2 -2
  26. package/dist/sealed/release.d.ts +21 -76
  27. package/dist/sealed/release.js +24 -108
  28. package/dist/sealed/sealed.d.ts +8 -56
  29. package/dist/sealed/sealed.js +11 -89
  30. package/dist/sealed/verify.d.ts +7 -13
  31. package/dist/sealed/verify.js +3 -7
  32. package/package.json +8 -13
  33. package/dist/account/account-admin.d.ts +0 -80
  34. package/dist/account/account-admin.js +0 -346
  35. package/dist/account/account.d.ts +0 -196
  36. package/dist/account/account.js +0 -269
  37. package/dist/account/application-id.d.ts +0 -50
  38. package/dist/account/application-id.js +0 -83
  39. package/dist/account/bootstrap-from-invitation.d.ts +0 -110
  40. package/dist/account/bootstrap-from-invitation.js +0 -80
  41. package/dist/account/create-context.d.ts +0 -103
  42. package/dist/account/create-context.js +0 -267
  43. package/dist/account/govern.d.ts +0 -24
  44. package/dist/account/govern.js +0 -50
  45. package/dist/account/index.d.ts +0 -26
  46. package/dist/account/index.js +0 -15
  47. package/dist/account/join-as-account.d.ts +0 -23
  48. package/dist/account/join-as-account.js +0 -34
  49. package/dist/account/join-with-node.d.ts +0 -115
  50. package/dist/account/join-with-node.js +0 -161
  51. package/dist/account/node-admin.d.ts +0 -20
  52. package/dist/account/node-admin.js +0 -33
  53. package/dist/account/relay-from-invitation.d.ts +0 -137
  54. package/dist/account/relay-from-invitation.js +0 -180
  55. package/dist/account/relay-login-error.d.ts +0 -32
  56. package/dist/account/relay-login-error.js +0 -34
  57. package/dist/account/session.d.ts +0 -266
  58. package/dist/account/session.js +0 -915
  59. package/dist/account/wordlist.d.ts +0 -16
  60. package/dist/account/wordlist.js +0 -273
  61. package/dist/admin-api/admin-client.d.ts +0 -686
  62. package/dist/admin-api/admin-client.js +0 -1225
  63. package/dist/admin-api/admin-factory.d.ts +0 -14
  64. package/dist/admin-api/admin-factory.js +0 -22
  65. package/dist/admin-api/admin-types.d.ts +0 -2041
  66. package/dist/admin-api/admin-types.js +0 -12
  67. package/dist/admin-api/index.d.ts +0 -4
  68. package/dist/admin-api/index.js +0 -5
  69. package/dist/admin-api/redeem-invitation.d.ts +0 -101
  70. package/dist/admin-api/redeem-invitation.js +0 -200
  71. package/dist/auth/index.d.ts +0 -34
  72. package/dist/auth/index.js +0 -67
  73. package/dist/auth-api/auth-client.d.ts +0 -31
  74. package/dist/auth-api/auth-client.js +0 -117
  75. package/dist/auth-api/auth-factory.d.ts +0 -7
  76. package/dist/auth-api/auth-factory.js +0 -41
  77. package/dist/auth-api/auth-types.d.ts +0 -130
  78. package/dist/auth-api/auth-types.js +0 -2
  79. package/dist/auth-api/index.d.ts +0 -3
  80. package/dist/auth-api/index.js +0 -4
  81. package/dist/capabilities.d.ts +0 -84
  82. package/dist/capabilities.js +0 -117
  83. package/dist/cloud/account-ownership.d.ts +0 -63
  84. package/dist/cloud/account-ownership.js +0 -87
  85. package/dist/cloud/cloud-client.d.ts +0 -949
  86. package/dist/cloud/cloud-client.js +0 -1068
  87. package/dist/cloud/connect.d.ts +0 -213
  88. package/dist/cloud/connect.js +0 -260
  89. package/dist/cloud/enrol-redirect.d.ts +0 -181
  90. package/dist/cloud/enrol-redirect.js +0 -244
  91. package/dist/cloud/index.d.ts +0 -12
  92. package/dist/cloud/index.js +0 -10
  93. package/dist/cloud/link-redirect.d.ts +0 -95
  94. package/dist/cloud/link-redirect.js +0 -121
  95. package/dist/cloud/link-state.d.ts +0 -36
  96. package/dist/cloud/link-state.js +0 -104
  97. package/dist/cloud/routing-proof.d.ts +0 -113
  98. package/dist/cloud/routing-proof.js +0 -96
  99. package/dist/device-cert/device-cert.d.ts +0 -189
  100. package/dist/device-cert/device-cert.js +0 -239
  101. package/dist/device-cert/device-scope.d.ts +0 -58
  102. package/dist/device-cert/device-scope.js +0 -76
  103. package/dist/device-cert/index.d.ts +0 -4
  104. package/dist/device-cert/index.js +0 -3
  105. package/dist/ephemeral/codec.d.ts +0 -4
  106. package/dist/ephemeral/codec.js +0 -12
  107. package/dist/ephemeral/index.d.ts +0 -57
  108. package/dist/ephemeral/index.js +0 -101
  109. package/dist/ephemeral/types.d.ts +0 -27
  110. package/dist/ephemeral/types.js +0 -1
  111. package/dist/errors/classify.d.ts +0 -65
  112. package/dist/errors/classify.js +0 -117
  113. package/dist/errors/index.d.ts +0 -2
  114. package/dist/errors/index.js +0 -1
  115. package/dist/events/group.d.ts +0 -95
  116. package/dist/events/group.js +0 -10
  117. package/dist/events/index.d.ts +0 -5
  118. package/dist/events/index.js +0 -2
  119. package/dist/events/sse.d.ts +0 -127
  120. package/dist/events/sse.js +0 -469
  121. package/dist/events/ws.d.ts +0 -57
  122. package/dist/events/ws.js +0 -212
  123. package/dist/http-client/api-response.d.ts +0 -15
  124. package/dist/http-client/api-response.js +0 -1
  125. package/dist/http-client/http-factory.d.ts +0 -71
  126. package/dist/http-client/http-factory.js +0 -68
  127. package/dist/http-client/http-types.d.ts +0 -87
  128. package/dist/http-client/http-types.js +0 -1
  129. package/dist/http-client/index.d.ts +0 -7
  130. package/dist/http-client/index.js +0 -11
  131. package/dist/http-client/path-segment.d.ts +0 -1
  132. package/dist/http-client/path-segment.js +0 -8
  133. package/dist/http-client/retry.d.ts +0 -5
  134. package/dist/http-client/retry.js +0 -82
  135. package/dist/http-client/signal-utils.d.ts +0 -2
  136. package/dist/http-client/signal-utils.js +0 -41
  137. package/dist/http-client/web-client.d.ts +0 -80
  138. package/dist/http-client/web-client.js +0 -557
  139. package/dist/invitation/index.d.ts +0 -2
  140. package/dist/invitation/index.js +0 -2
  141. package/dist/invitation/invitation.d.ts +0 -106
  142. package/dist/invitation/invitation.js +0 -104
  143. package/dist/login/index.d.ts +0 -4
  144. package/dist/login/index.js +0 -3
  145. package/dist/login/login.d.ts +0 -111
  146. package/dist/login/login.js +0 -110
  147. package/dist/login/session.d.ts +0 -124
  148. package/dist/login/session.js +0 -141
  149. package/dist/mero-js.d.ts +0 -231
  150. package/dist/mero-js.js +0 -469
  151. package/dist/namespace-op/index.d.ts +0 -2
  152. package/dist/namespace-op/index.js +0 -3
  153. package/dist/namespace-op/namespace-op.d.ts +0 -150
  154. package/dist/namespace-op/namespace-op.js +0 -191
  155. package/dist/nodeDiscovery.d.ts +0 -47
  156. package/dist/nodeDiscovery.js +0 -101
  157. package/dist/owner-op/index.d.ts +0 -2
  158. package/dist/owner-op/index.js +0 -3
  159. package/dist/owner-op/owner-op.d.ts +0 -119
  160. package/dist/owner-op/owner-op.js +0 -214
  161. package/dist/presence/relay-presence.d.ts +0 -56
  162. package/dist/presence/relay-presence.js +0 -107
  163. package/dist/presence/statement.d.ts +0 -12
  164. package/dist/presence/statement.js +0 -17
  165. package/dist/relay/index.d.ts +0 -4
  166. package/dist/relay/index.js +0 -2
  167. package/dist/relay/nonce-source.d.ts +0 -72
  168. package/dist/relay/nonce-source.js +0 -111
  169. package/dist/relay/relay-client.d.ts +0 -472
  170. package/dist/relay/relay-client.js +0 -518
  171. package/dist/relay-attestation/attest-node-key.d.ts +0 -66
  172. package/dist/relay-attestation/attest-node-key.js +0 -110
  173. package/dist/relay-attestation/index.d.ts +0 -1
  174. package/dist/relay-attestation/index.js +0 -1
  175. package/dist/request/caller-proof.d.ts +0 -43
  176. package/dist/request/caller-proof.js +0 -36
  177. package/dist/request/index.d.ts +0 -3
  178. package/dist/request/index.js +0 -3
  179. package/dist/request/proof-signer.d.ts +0 -49
  180. package/dist/request/proof-signer.js +0 -59
  181. package/dist/request/request-sig.d.ts +0 -99
  182. package/dist/request/request-sig.js +0 -95
  183. package/dist/request-proof/authorizer.d.ts +0 -41
  184. package/dist/request-proof/authorizer.js +0 -60
  185. package/dist/request-proof/index.d.ts +0 -4
  186. package/dist/request-proof/index.js +0 -2
  187. package/dist/request-proof/request-proof.d.ts +0 -53
  188. package/dist/request-proof/request-proof.js +0 -95
  189. package/dist/rpc/index.d.ts +0 -64
  190. package/dist/rpc/index.js +0 -78
  191. package/dist/signer/index.d.ts +0 -2
  192. package/dist/signer/index.js +0 -3
  193. package/dist/signer/signer.d.ts +0 -92
  194. package/dist/signer/signer.js +0 -147
  195. package/dist/token-store/index.d.ts +0 -27
  196. package/dist/token-store/index.js +0 -62
  197. package/dist/transport/index.d.ts +0 -6
  198. package/dist/transport/index.js +0 -3
  199. package/dist/transport/mero-client.d.ts +0 -294
  200. package/dist/transport/mero-client.js +0 -386
  201. package/dist/transport/relay-observer.d.ts +0 -152
  202. package/dist/transport/relay-observer.js +0 -173
  203. package/dist/transport/relay-transport.d.ts +0 -73
  204. package/dist/transport/relay-transport.js +0 -94
  205. package/dist/transport/types.d.ts +0 -100
  206. package/dist/transport/types.js +0 -32
  207. package/dist/types/api-response.d.ts +0 -15
  208. package/dist/types/api-response.js +0 -1
  209. package/dist/types/index.d.ts +0 -1
  210. package/dist/types/index.js +0 -1
  211. package/dist/warrant/creation-warrant.d.ts +0 -163
  212. package/dist/warrant/creation-warrant.js +0 -194
  213. package/dist/warrant/governance-op.d.ts +0 -202
  214. package/dist/warrant/governance-op.js +0 -355
  215. package/dist/warrant/governance-warrant.d.ts +0 -124
  216. package/dist/warrant/governance-warrant.js +0 -164
  217. package/dist/warrant/index.d.ts +0 -8
  218. package/dist/warrant/index.js +0 -5
  219. package/dist/warrant/warrant.d.ts +0 -188
  220. package/dist/warrant/warrant.js +0 -202
@@ -1,949 +0,0 @@
1
- /**
2
- * Calimero Cloud (MDMA) client.
3
- *
4
- * # Why the SDK knows about the cloud at all
5
- *
6
- * Delegated execution lets an account that holds one signing key write into a
7
- * context without running a node — but only through a *relay*, and a relay is
8
- * something the client has to be told about. A warrant names an executor
9
- * account, so a client that cannot discover which relay serves its namespace,
10
- * and which account that relay writes as, cannot mint a usable warrant at all.
11
- *
12
- * For a self-hosted namespace the operator hands those two facts over out of
13
- * band. For the hosted tier the cloud is the directory: the user signs in, the
14
- * cloud knows which namespaces they own and which attested TEE nodes are
15
- * assigned to each, and it answers with the relay's URL and executor account.
16
- * That is what this client is for — it is the discovery half of
17
- * {@link RelayClient}, not a second way to talk to a node.
18
- *
19
- * # What it deliberately is not
20
- *
21
- * It never sees a warrant, a device secret, or an intent. Discovery goes
22
- * through the cloud; the write goes straight from the client to the relay. A
23
- * cloud that proxied intents would read every method and argument its users
24
- * ever sent, and would be a throughput bottleneck on a path that has no reason
25
- * to involve it.
26
- */
27
- import { type AccountOwnershipProof } from './account-ownership.js';
28
- import { type RootSource } from '../account/index.js';
29
- import { HTTPError } from '../http-client/web-client.js';
30
- import type { Signer } from '../signer/signer.js';
31
- import { type DiscoveryChallenge, type RoutingChallenge, type RoutingCredential } from './routing-proof.js';
32
- /**
33
- * The first relay a warrant can be spent at, or `null`.
34
- *
35
- * Shared by {@link CloudClient.findExecutingRelay} and `connectCloud`, which
36
- * already holds the list and must not fetch it twice.
37
- */
38
- export declare function pickExecutingRelay(relays: readonly CloudRelay[]): CloudRelay | null;
39
- export interface CloudClientConfig {
40
- cloudBaseUrl?: string;
41
- /**
42
- * An MDMA session token to start out authenticated with — from a previous
43
- * {@link CloudClient.signInWithGoogle}, persisted by the app.
44
- *
45
- * Sessions are 7-day JWTs with a rolling refresh, so a stored one is usually
46
- * still live and re-running the Google flow on every launch is avoidable.
47
- */
48
- sessionToken?: string;
49
- /**
50
- * Called whenever the session token changes — a sign-in, an explicit
51
- * refresh, or a rolling refresh the server performed mid-request. Persist it
52
- * here; errors thrown are swallowed so a storage failure cannot mask the
53
- * response the caller is waiting for.
54
- */
55
- onSession?: (session: CloudSession | null) => void | Promise<void>;
56
- /** Injected for tests and non-browser runtimes. Defaults to global `fetch`. */
57
- fetch?: typeof fetch;
58
- /** Per-request timeout. Defaults to 10s, as the node clients do. */
59
- timeoutMs?: number;
60
- /**
61
- * The device credential to prove an account with on the routing read.
62
- *
63
- * Nothing to do with {@link sessionToken}: a cloud session says who is signed
64
- * in, this says which account holds the key. A joiner has the second and
65
- * cannot have the first — see `routing-proof.ts` for why that is not an
66
- * oversight.
67
- *
68
- * Omitting it leaves {@link CloudClient.getNamespaceRouting} anonymous, which
69
- * the cloud still answers while `require_routing_proof` is off. Supply it and
70
- * the read is attributed; the cloud verifies a supplied proof either way, so
71
- * a wrong one surfaces immediately rather than on the day the flag flips.
72
- */
73
- routingCredential?: RoutingCredential;
74
- }
75
- /** Who is signed in, and until when. */
76
- export interface CloudSession {
77
- sessionToken: string;
78
- /** Epoch **seconds**, as MDMA reports it — not milliseconds. */
79
- expiresAt: number;
80
- user: {
81
- email: string;
82
- name?: string;
83
- picture?: string;
84
- };
85
- }
86
- /** One namespace the signed-in user owns. */
87
- export interface CloudNamespace {
88
- namespaceId: string;
89
- /** Always equal to `namespaceId`; MDMA keeps it for wire compatibility. */
90
- groupId: string;
91
- /** `'enabled' | 'disabled' | 'none'` — `'none'` means HA was never enabled. */
92
- haStatus: string;
93
- haEnabledAt?: string | null;
94
- contexts: string[];
95
- fleetReplicas?: {
96
- current?: number;
97
- limit?: number;
98
- } | unknown;
99
- }
100
- /**
101
- * One attested node the cloud has assigned to a namespace, described as a
102
- * relay.
103
- *
104
- * `canExecute` is the field that decides whether a write can happen, and it is
105
- * the cloud's own verdict rather than something to re-derive: a node that
106
- * reports a role relays only as a `RelayTee` (the namespace's TEE admission
107
- * policy set with `mode: 'relay'`), whatever its grant; a `ReadOnlyTee` is a
108
- * replica and never relays. Only a node too old to report a role is decided by
109
- * `authorshipReady` — the `CAN_AUTHOR_ON_BEHALF` grant, which is reported
110
- * rather than assumed because it is not the cloud's to give.
111
- */
112
- export interface CloudRelay {
113
- peerId: string;
114
- /** Base URL to present intents to, or `null` when the cloud knows none yet. */
115
- relayUrl: string | null;
116
- /** The account a warrant for this relay must name as its `executor`, hex. */
117
- executorAccount: string | null;
118
- /**
119
- * The relay node's ed25519 **device signing key**, hex — or `null`, which is
120
- * what it is today.
121
- *
122
- * A relay is an ordinary node, so it can be logged in to and subscribed to;
123
- * the login statement has to be signed against this key, supplied separately
124
- * rather than read from the node being authenticated. The cloud does not
125
- * publish it yet (mdma #312), so this is `null` on every row and the hosted
126
- * path reports `canSubscribe === false`.
127
- *
128
- * It is parsed rather than omitted so the hosted path needs no API change
129
- * when the field lands: `connectCloud` already passes it through, and the
130
- * same call site starts observing. `peerId` is **not** a fallback — it is a
131
- * libp2p identity, a different key, and signing a statement about it would
132
- * authenticate nothing.
133
- *
134
- * Both plausible spellings are accepted because mdma #312 has not fixed one;
135
- * if it lands under a third name, this mapping is the single line to change.
136
- */
137
- nodeKey: string | null;
138
- /** `'assigned'` (admitted pending confirm) or `'active'`. */
139
- status: string;
140
- /** Whether this relay holds `CAN_AUTHOR_ON_BEHALF` on the namespace. */
141
- authorshipReady: boolean;
142
- /**
143
- * The core role the node reported for itself here — `'RelayTee'` or
144
- * `'ReadOnlyTee'` — or `null` for a sidecar too old to report one.
145
- */
146
- teeRole: string | null;
147
- /**
148
- * Whether an intent can be presented here now: a URL, an executor account, a
149
- * fresh heartbeat, and a node that relays by role (or, for one reporting no
150
- * role, holds the grant).
151
- *
152
- * The cloud's `can_execute`. Against an older cloud that does not send it,
153
- * derived from `authorshipReady` plus the URL and account, as before.
154
- */
155
- canExecute: boolean;
156
- lastSeenAt?: string | null;
157
- confirmedAt?: string | null;
158
- /**
159
- * How far along this relay's admission is, as the cloud judges it:
160
- * `'confirmed'` (in), `'pending'` (trying), `'refused'` (alive and turned
161
- * away), `'absent'` (stopped talking before getting in). `null` from a cloud
162
- * that predates the field. A string, not a closed union, so a verdict the
163
- * cloud adds later is passed through rather than dropped.
164
- */
165
- admission: string | null;
166
- /** The cloud's one-line explanation of `admission`, for a person; `null` when none. */
167
- admissionHint: string | null;
168
- /**
169
- * What the relay itself reported about its latest attempt to join, reasons
170
- * included — or `null` when it has reported nothing (an older fleet node or
171
- * cloud, or a relay assigned since its last report).
172
- */
173
- join: CloudRelayJoin | null;
174
- }
175
- /**
176
- * A fleet node's own account of its latest attempt to join a namespace.
177
- *
178
- * A refusal happens peer to peer, between the node and the namespace's
179
- * admitters, so this is the only place a client learns WHY a relay is stuck:
180
- * the node forwards what each admitter it asked directly answered.
181
- */
182
- export interface CloudRelayJoin {
183
- /**
184
- * `'admitted'` (in, or an admitter said yes and the key is on its way),
185
- * `'refused'` (every admitter asked declined; see `refusals`), `'waiting'`
186
- * (nobody answered directly yet), or `'error'` (the attempt itself failed;
187
- * see `error`). Passed through as sent.
188
- */
189
- state: string;
190
- /** Consecutive attempts without admission, as the node counts them. */
191
- attempts: number;
192
- /**
193
- * Each directly-asked admitter that declined: its libp2p peer id and its
194
- * reason, verbatim. Text to show a person, never to parse — the most useful
195
- * one is "was removed from group … and cannot rejoin; an admin must re-add
196
- * them", which the namespace owner can fix by re-adding the node.
197
- */
198
- refusals: Array<{
199
- peer: string;
200
- reason: string;
201
- }>;
202
- /** Why the attempt itself failed, when `state` is `'error'`. */
203
- error: string | null;
204
- /** When the node reported this, ISO 8601 (UTC, no offset), or `null`. */
205
- reportedAt: string | null;
206
- }
207
- /**
208
- * One node serving a namespace, as a caller with no cloud account sees it.
209
- *
210
- * The public counterpart to {@link CloudRelay}: same fleet rows, but keyed on a
211
- * namespace id anyone holding an invitation already has, and answering both
212
- * things a keyholder needs from a node rather than one of them.
213
- */
214
- /**
215
- * One relay that serves an account, as the bootstrap read reports it.
216
- *
217
- * `fresh` and a null `relayUrl` are reported rather than filtered, because
218
- * "your relay is down", "we have no address for it" and "you have no relay"
219
- * need different actions from a caller and an empty list erases the
220
- * distinction. A caller looking for somewhere to talk to wants
221
- * `fresh && relayUrl`; one diagnosing wants the rest.
222
- */
223
- export interface CloudAccountRelay {
224
- peerId: string;
225
- relayUrl: string | null;
226
- fresh: boolean;
227
- /**
228
- * The relay's own account id: 64 lowercase hex, the executor a delegated
229
- * write through this relay names.
230
- *
231
- * Null when the server did not say (older servers omit it) or sent anything
232
- * that is not 64 lowercase hex — an executor that cannot be named is the
233
- * same as none, and a malformed one would only fail later, at the node.
234
- */
235
- executorAccount: string | null;
236
- /**
237
- * True when the cloud has just assigned this relay to an account that had
238
- * none (the assignment is sticky); false for relays the account already
239
- * used, and on older servers that omit the field.
240
- */
241
- assigned: boolean;
242
- }
243
- export interface CloudNamespaceNode {
244
- peerId: string;
245
- /**
246
- * The node's own account id, hex.
247
- *
248
- * Intersect this against the invitation's signed `admitters` list before
249
- * using the node. That list is a MINT-TIME SNAPSHOT, so a node assigned after
250
- * an invitation was created is live, healthy, listed here, and still refused
251
- * with 403 — the cloud cannot know which invitation you hold.
252
- */
253
- account: string | null;
254
- /** Base URL, or `null` when the cloud knows none yet. */
255
- relayUrl: string | null;
256
- /** Ready-made admission URL, so a caller never rebuilds the path. */
257
- admitUrl: string | null;
258
- /** `'assigned'` (admitted pending confirm) or `'active'`. */
259
- status: string;
260
- /** Whether the node's heartbeat for this namespace is recent. */
261
- fresh: boolean;
262
- /**
263
- * Whether a signed join can be presented here now.
264
- *
265
- * Deliberately independent of {@link CloudNamespaceNode.authorshipReady}:
266
- * relaying a join the joiner already signed is not authoring on anyone's
267
- * behalf, so a node with no grant admits perfectly well.
268
- */
269
- canAdmit: boolean;
270
- /** Whether the node holds `CAN_AUTHOR_ON_BEHALF` on the namespace root group. */
271
- authorshipReady: boolean;
272
- /** `'RelayTee'`, `'ReadOnlyTee'`, or `null` for a node too old to report one. */
273
- teeRole: string | null;
274
- /**
275
- * Whether a delegated write can be posted here now — a URL, an account, a
276
- * fresh heartbeat, and a `RelayTee` (or, for a node reporting no role, the
277
- * grant). A `ReadOnlyTee` is a replica and never relays.
278
- *
279
- * Namespace-level. A context in a RESTRICTED SUBGROUP is governed by that
280
- * subgroup, so per-context routing remains the exact answer if a write is
281
- * refused despite this being true.
282
- */
283
- canExecute: boolean;
284
- }
285
- /** What {@link CloudClient.getNamespaceRouting} reports. */
286
- export interface CloudNamespaceRouting {
287
- namespaceId: string;
288
- /** Usable nodes first, then a stable order, so a polling caller sees no shuffle. */
289
- nodes: CloudNamespaceNode[];
290
- /** Whether any listed node can take a join now. */
291
- servable: boolean;
292
- /** Whether any listed node can take a delegated write now. */
293
- writable: boolean;
294
- }
295
- /** One namespace of the caller's that a machine is serving. */
296
- export interface CloudMachineNamespace {
297
- namespaceId: string;
298
- /** `'assigned'` (admitted pending confirm) or `'active'`. */
299
- status: string;
300
- /** Whether the machine holds `CAN_AUTHOR_ON_BEHALF` on this namespace. */
301
- authorshipReady: boolean;
302
- /** `'RelayTee'`, `'ReadOnlyTee'`, or `null` for a machine too old to report one. */
303
- teeRole: string | null;
304
- /**
305
- * Whether the machine's heartbeat for this namespace is recent.
306
- *
307
- * The same freshness rule the per-plan fleet cap uses, so a replica that
308
- * stopped polling reads as stale here rather than continuing to look
309
- * healthy — otherwise "my writes stopped working" has no visible cause.
310
- */
311
- fresh: boolean;
312
- confirmedAt?: string | null;
313
- lastSeenAt?: string | null;
314
- }
315
- /**
316
- * One attested machine serving this account.
317
- *
318
- * A narrow view on purpose: the zone, machine type, instance name, public IP
319
- * and KMS ids are operator data with no client use, and a cloud user is not an
320
- * operator.
321
- */
322
- export interface CloudMachine {
323
- peerId: string;
324
- relayUrl: string | null;
325
- executorAccount: string | null;
326
- /**
327
- * Whether this machine can write for the caller *somewhere* — a URL, an
328
- * executor account, and at least one namespace it relays in: as a
329
- * `RelayTee`, or, reporting no role, holding the grant.
330
- *
331
- * Folded here so a client does not re-derive the three-way precondition and
332
- * get a refusal it cannot explain.
333
- */
334
- canExecute: boolean;
335
- /** Only the caller's own namespaces, even on a machine shared with others. */
336
- namespaces: CloudMachineNamespace[];
337
- }
338
- /** A Calimero account linked to this cloud login. */
339
- export interface CloudLinkedAccount {
340
- /** The account id, 64 hex. */
341
- accountId: string;
342
- linkedAt?: string | null;
343
- /**
344
- * Whether a recovery envelope has been stored for this account, so a UI can
345
- * say "recoverable" without fetching the blob.
346
- */
347
- hasRecoveryEnvelope: boolean;
348
- }
349
- /** What {@link CloudClient.getMyAccounts} reports. */
350
- export interface CloudLinkedAccounts {
351
- accounts: CloudLinkedAccount[];
352
- /** How many the caller's plan allows. `null` means no limit. */
353
- limit: number | null;
354
- }
355
- /** A single-use challenge to sign with an account root. */
356
- export interface AccountLinkChallenge {
357
- /** Sign this verbatim — it is an opaque sealed string, not a decodable id. */
358
- nonce: string;
359
- /** When it stops being accepted, epoch milliseconds. */
360
- expiresAtMs: number | null;
361
- }
362
- /** A proof assembled by whoever holds the root, for {@link CloudClient.submitAccountLink}. */
363
- export interface AccountLinkProof {
364
- /** The account being claimed, 64 hex. */
365
- accountId: string;
366
- /** The root that names it, 64 hex. */
367
- rootPublicKey: string;
368
- /** The challenge that was signed. */
369
- nonce: string;
370
- /** `signAccountLink`'s output — standard base64. */
371
- signature: string;
372
- }
373
- /** Where to send someone so a cloud login can consent to linking an account. */
374
- export interface AccountLinkHandoff {
375
- /** The cloud portal URL to open — a new tab, a popup, or the system browser. */
376
- url: string;
377
- /** The account the consent will be for, echoed so a caller can show it. */
378
- accountId: string;
379
- }
380
- /** What comes back on the callback: a grant, a refusal, or neither. */
381
- export interface AccountLinkCallback {
382
- /** The grant to spend with {@link CloudClient.linkAccountWithGrant}. */
383
- grant?: string;
384
- /** The account the grant is for, as the portal echoed it. */
385
- accountId?: string;
386
- /** The cloud login that consented. Show it before spending: anyone holding the handoff URL could have answered it. */
387
- login?: string;
388
- /** This browser's secret for the grant. Pass it to {@link CloudClient.linkAccountWithGrant}. */
389
- verifier?: string;
390
- /** `'denied'` when the person cancelled, `'unexpected_callback'` for a grant this browser never asked for. */
391
- error?: string;
392
- }
393
- /** A single-use challenge for an account root to sign itself in with. */
394
- export interface AccountLoginChallenge {
395
- /** Sign this verbatim. Opaque and sealed by the cloud; nonces live ~2 minutes. */
396
- nonce: string;
397
- /** When it stops being accepted, epoch milliseconds. */
398
- expiresAtMs: number;
399
- }
400
- /** A proof assembled by whoever holds the root, for {@link CloudClient.submitAccountLogin}. */
401
- export interface AccountLoginProof {
402
- /**
403
- * The root that names the account, 64 hex.
404
- *
405
- * No `accountId` field, unlike {@link AccountLinkProof}: the cloud derives
406
- * the account from this key rather than accepting one alongside it, so there
407
- * is nothing a caller could state that the signature would then contradict.
408
- */
409
- rootPublicKey: string;
410
- /** The challenge that was signed. */
411
- nonce: string;
412
- /** `signAccountLogin`'s output — standard base64. */
413
- signature: string;
414
- }
415
- /** The outcome of {@link CloudClient.linkAccount}. */
416
- export interface CloudAccountLink {
417
- accountId: string;
418
- linkedAt?: string | null;
419
- /**
420
- * True when this account was already linked to this same login, which the
421
- * cloud treats as a 200 no-op rather than an error. A caller re-running
422
- * onboarding gets success, not a confusing failure.
423
- */
424
- alreadyLinked: boolean;
425
- }
426
- export interface EnableHAOptions {
427
- groupId: string;
428
- contextId: string;
429
- redirectUrl?: string;
430
- }
431
- export interface DisableHAOptions {
432
- groupId: string;
433
- contextId: string;
434
- redirectUrl?: string;
435
- }
436
- /** Options for {@link CloudClient.enableHaAsAccount}. */
437
- export interface EnableHaAsAccountOptions {
438
- /** The namespace, hex: the id `foundNamespace` returned. */
439
- namespaceId: string;
440
- /** The salt `foundNamespace` returned, hex (32 bytes). */
441
- salt: string;
442
- /** The founding account, hex. */
443
- accountId: string;
444
- /** The account's credential, hex `AccountProof<DeviceCert>`. */
445
- credential: string;
446
- /** The certified device's secret, hex. Give this or `signer`. */
447
- deviceSecret?: string;
448
- signer?: Signer;
449
- /** The claim's lifetime in ms; default one minute, at most five. */
450
- ttlMs?: number;
451
- /**
452
- * The relay that founded the namespace (the delegated session's `relayUrl`).
453
- * The cloud gives that relay to the fleet node as its admitter; without it
454
- * the node has to find the relay by discovery.
455
- */
456
- relayUrl?: string;
457
- }
458
- /**
459
- * The cloud's refusals of {@link CloudClient.enableHaAsAccount} that a
460
- * person can do something about. Both are `409`s with `{"error": code}`.
461
- *
462
- * Extends {@link HTTPError}, so `instanceof HTTPError` handling still catches it.
463
- */
464
- export declare class AccountHaRefusedError extends HTTPError {
465
- /** The cloud's `error` code, verbatim. */
466
- readonly code: string;
467
- name: string;
468
- constructor(
469
- /** The cloud's `error` code, verbatim. */
470
- code: string, status: number, statusText: string, url: string, headers: Headers, bodyText?: string);
471
- }
472
- /**
473
- * `account_not_linked`: the account was never linked to a cloud user through
474
- * the wallet, so the cloud has nobody to host the namespace for. Linking it
475
- * fixes this; retrying does not.
476
- */
477
- export declare class AccountNotLinkedError extends AccountHaRefusedError {
478
- name: string;
479
- static readonly CODE = "account_not_linked";
480
- }
481
- /**
482
- * `account_linked_to_several_users`: more than one cloud user linked this
483
- * account, so the cloud cannot tell whose quota hosts the namespace. Unlink it
484
- * from all but one.
485
- */
486
- export declare class AccountLinkedToSeveralUsersError extends AccountHaRefusedError {
487
- name: string;
488
- static readonly CODE = "account_linked_to_several_users";
489
- }
490
- /**
491
- * `ha_request_pending` (409): another namespace of this account is waiting for
492
- * its first fleet node to be admitted. The route allows one at a time; it
493
- * clears once that node is admitted, or by disabling HA on it from a cloud
494
- * session. The claim was not spent.
495
- */
496
- export declare class HaRequestPendingError extends AccountHaRefusedError {
497
- name: string;
498
- static readonly CODE = "ha_request_pending";
499
- }
500
- /**
501
- * `unknown_relay` (422): the cloud runs no relay at `relayUrl`. The claim was
502
- * not spent.
503
- */
504
- export declare class UnknownRelayError extends AccountHaRefusedError {
505
- name: string;
506
- static readonly CODE = "unknown_relay";
507
- }
508
- /**
509
- * `relay_not_dialable` (422): the relay is the cloud's but has not reported
510
- * its addresses yet. The claim was not spent; retrying later can succeed.
511
- */
512
- export declare class RelayNotDialableError extends AccountHaRefusedError {
513
- name: string;
514
- static readonly CODE = "relay_not_dialable";
515
- }
516
- export declare class CloudClient {
517
- private baseUrl;
518
- private session;
519
- private readonly onSession?;
520
- private readonly fetchImpl;
521
- private readonly timeoutMs;
522
- private readonly routingCredential?;
523
- constructor(config?: CloudClientConfig);
524
- /** The current session, or `null` when nobody is signed in. */
525
- getSession(): CloudSession | null;
526
- /** Whether a session token is held. Says nothing about the server agreeing. */
527
- isSignedIn(): boolean;
528
- /**
529
- * Exchange a Google OAuth2 ID token for an MDMA session.
530
- *
531
- * The app owns the Google flow (One Tap, an auth-code popup, a native
532
- * browser) and hands the resulting ID token here once. Everything after this
533
- * uses the returned session token, so the Google credential does not have to
534
- * be kept or re-minted per call.
535
- */
536
- signInWithGoogle(idToken: string): Promise<CloudSession>;
537
- /**
538
- * Sign in as a Calimero account, proving it with its root key.
539
- *
540
- * The password-free counterpart to {@link signInWithGoogle}: no Google, no
541
- * password, no server-held secret — the cloud mints a challenge, the account
542
- * root signs it, and the session that comes back is the same MDMA session
543
- * token every other cloud route already accepts.
544
- *
545
- * Doing this **once** is what makes an account's later device proofs mean
546
- * something. A routing read shows that the caller holds a device the root
547
- * certified, but certificates are public, so it can never show that anyone
548
- * held the root; the cloud records this claim and from then on knows the
549
- * account behind those reads was claimed by its owner. The claim is recorded
550
- * even when the session is refused.
551
- *
552
- * @param root the account root: its 64-hex secret, or a `Signer` over a root
553
- * this process may use and cannot read — the form a phrase-held root in a
554
- * browser takes. Either way nothing but a signature over the cloud's nonce
555
- * travels.
556
- *
557
- * A `403` means either the signature did not verify, or the account is not
558
- * linked to a cloud login: ownership alone says who you are, and the link
559
- * says what you are entitled to. Anyone can mint a root offline, so a session
560
- * on the proof alone would authenticate perfectly and authorize nothing. The
561
- * ownership claim is recorded either way, so linking later needs no re-proof.
562
- */
563
- signInWithAccount(root: RootSource): Promise<CloudSession>;
564
- /**
565
- * Mint a challenge for an account root to sign.
566
- *
567
- * Public, and deliberately so: the caller has no session — obtaining one is
568
- * what this exchange does. The nonce is not a capability, it is the thing a
569
- * capability gets demonstrated against, and demonstrating it needs the root.
570
- *
571
- * Split out of {@link signInWithAccount} for the case that call cannot serve:
572
- * a root held by a hardware key, a desktop app or an air-gapped machine,
573
- * which signs without the secret ever reaching this process.
574
- */
575
- getAccountLoginChallenge(): Promise<AccountLoginChallenge>;
576
- /** Post a proof assembled elsewhere. The other half of {@link getAccountLoginChallenge}. */
577
- submitAccountLogin(proof: AccountLoginProof): Promise<CloudSession>;
578
- /**
579
- * Refresh the session token explicitly.
580
- *
581
- * Rarely needed: MDMA rolling-refreshes on ordinary authenticated calls and
582
- * this client adopts the replacement automatically. Use it when an app wants
583
- * a fresh token before going idle rather than on the next request.
584
- */
585
- refreshSession(): Promise<CloudSession>;
586
- /**
587
- * Revoke this session server-side and forget it locally.
588
- *
589
- * Local state is cleared even if the server call fails: the caller asked to
590
- * be signed out, and keeping a token they believe is gone is the worse of the
591
- * two failures.
592
- */
593
- signOut(): Promise<void>;
594
- /** Namespaces the signed-in user owns. */
595
- getMyNamespaces(): Promise<CloudNamespace[]>;
596
- /**
597
- * The relays serving one namespace: where to present an intent, and as whom.
598
- *
599
- * Everything a client needs in order to mint a warrant it can actually
600
- * spend. Filter on `canExecute` before signing — a warrant presented to a
601
- * relay that does not relay (a `ReadOnlyTee` replica, or a node with no role
602
- * and no grant) is refused *after* the author has burned a nonce from its
603
- * monotonic sequence on it.
604
- */
605
- getNamespaceRelays(namespaceId: string): Promise<CloudRelay[]>;
606
- /**
607
- * The first relay for `namespaceId` that can actually run an intent, or
608
- * `null`.
609
- *
610
- * "Can actually run one" is several conditions, and a client that checks
611
- * fewer gets a refusal it cannot explain: the cloud must know a URL, the
612
- * relay must have reported the executor account a warrant has to name, and
613
- * the node must relay — which the cloud folds into `canExecute`.
614
- */
615
- findExecutingRelay(namespaceId: string): Promise<CloudRelay | null>;
616
- /**
617
- * Where to reach a namespace without owning it: one read, both verbs.
618
- *
619
- * **Anonymous.** A joiner is by construction not the namespace owner and holds
620
- * no cloud session — needing one is exactly what this path exists to avoid.
621
- * Discovery is not authorization: merod refuses an `/admit` call unless the
622
- * relaying node's account is on the invitation's signed `admitters` list, and
623
- * refuses an intent unless the warrant is genuinely the member's, so naming a
624
- * node grants the caller nothing it did not already have.
625
- *
626
- * A keyholder resolves a namespace to a node ONCE and then admits, reads and
627
- * posts intents against that same node, which is why admission and writability
628
- * are answered together rather than across two endpoints — the per-context
629
- * read needs a context id a joiner does not yet have.
630
- *
631
- * An empty `nodes` list is a state, not an error: the cloud has no record of
632
- * a node holding the namespace, so there is no hosted admitter.
633
- */
634
- getNamespaceRouting(namespaceId: string): Promise<CloudNamespaceRouting>;
635
- /**
636
- * Ask the cloud for a challenge to prove an account against.
637
- *
638
- * Public and unauthenticated on purpose, and safe to be: the nonce is sealed
639
- * and bound to this one namespace, so it is not a capability — it is the
640
- * thing a capability gets demonstrated against. A caller with no credential
641
- * gains nothing by holding one.
642
- *
643
- * {@link getNamespaceRouting} calls this for you when the client was
644
- * constructed with a `routingCredential`. Call it directly only to sign a
645
- * challenge somewhere this client cannot reach the key.
646
- */
647
- getRoutingChallenge(namespaceId: string): Promise<RoutingChallenge>;
648
- /**
649
- * The proof headers for one routing read, or nothing when no credential was
650
- * configured.
651
- *
652
- * A challenge per read rather than a cached one: they expire in about two
653
- * minutes and are single-namespace, so caching would trade one cheap request
654
- * for a class of expiry bug that only shows up on a slow client.
655
- */
656
- private routingProof;
657
- /**
658
- * Ask the cloud for a challenge bound to one ACCOUNT.
659
- *
660
- * Public and unauthenticated like {@link getRoutingChallenge}: an account id
661
- * is `H(genesis(root_pk))` and travels in the clear in every device-link op,
662
- * so naming one here reveals nothing and authorises nothing. MDMA re-derives
663
- * the account from the certificate and refuses a mismatch.
664
- */
665
- getAccountRelaysChallenge(accountId: string): Promise<DiscoveryChallenge>;
666
- /**
667
- * Which relays serve this account — the bootstrap, and nothing more.
668
- *
669
- * A device holding a certificate can resolve a namespace it can *name*
670
- * ({@link getNamespaceRouting}) and can ask a node it can *reach* what its
671
- * account belongs to. It starts with neither. This closes that one gap.
672
- *
673
- * **It does not return namespaces, deliberately.** The node answers that from
674
- * the governance DAG, scoped to the calling account: log in at one of these
675
- * relays with an account proof and read its namespace listing. A cloud-side
676
- * copy would be a second source of truth built from rows that linger for an
677
- * account which left a namespace.
678
- *
679
- * So the sequence is: this → log in at a relay → ask it what you are in.
680
- *
681
- * Proven with the **device certificate**, not a cloud session, so it needs a
682
- * `routingCredential` and throws without one rather than returning an empty
683
- * list — "you configured no credential" and "you have no relays" are
684
- * different answers and must not look alike.
685
- */
686
- getAccountRelays(accountId: string): Promise<CloudAccountRelay[]>;
687
- /**
688
- * The node to send a signed join to, chosen from those an invitation names.
689
- *
690
- * Pass the invitation's `admitters` and the intersection is done here, because
691
- * skipping it is the failure this method exists to prevent: the cloud lists
692
- * every node assigned to the namespace, while `admitters` is a snapshot signed
693
- * when the invitation was minted. A node added afterwards looks perfect in
694
- * every field here and answers 403.
695
- *
696
- * Omit `admitters` only for an invitation that names none — an empty list on
697
- * the wire authorises any node to admit.
698
- */
699
- findAdmitter(namespaceId: string, admitters?: readonly string[]): Promise<CloudNamespaceNode | null>;
700
- /**
701
- * Every attested machine currently serving something this account owns.
702
- *
703
- * The account-wide view of the same rows {@link getNamespaceRelays} returns
704
- * per namespace, keyed by machine — so a UI can answer "what is running for
705
- * me?" in one call. `canExecute` folds the three-way precondition, so a
706
- * caller does not re-derive it.
707
- *
708
- * Only the caller's own namespaces appear on each machine. A plan's
709
- * `usersPerMachine` is greater than one, so a fleet node routinely serves
710
- * several accounts at once.
711
- */
712
- getMyMachines(): Promise<CloudMachine[]>;
713
- /**
714
- * Claim a namespace under this account, proving ownership.
715
- *
716
- * The cloud has no other way to learn a namespace exists — namespaces are
717
- * created on a node, and there is deliberately no "create namespace" in the
718
- * cloud. `ownershipProof` comes from
719
- * `admin.issueNamespaceOwnershipProof(namespaceId, …)` on a node that is a
720
- * **direct admin** of that namespace; merod refuses to issue one otherwise.
721
- *
722
- * Pass merod's response object straight through. The cloud accepts core's
723
- * `signerPublicKey`/`signedPayload` casing as well as snake_case, so there is
724
- * no re-keying step — and getting that wrong used to surface as a `422`
725
- * naming three missing fields. Passing it whole also carries the `founding`
726
- * and `credential` merod attaches: the cloud accepts a namespace proof only
727
- * from a node of the account that founded the namespace, checked with those
728
- * two, and only when that account is linked to this login. A node that
729
- * predates them, or an admin that did not found the namespace, gets a `422`.
730
- *
731
- * Idempotent for the same account. A namespace already claimed by someone
732
- * else is a `409`; a replayed proof nonce is a `403`.
733
- */
734
- claimNamespace(namespaceId: string, ownershipProof: unknown): Promise<void>;
735
- /**
736
- * Ask the fleet to host a claimed namespace — the step that gets a relay
737
- * assigned.
738
- *
739
- * Carries no proof: {@link claimNamespace} already established ownership,
740
- * and this is the separate "now host it" half. Idempotent.
741
- *
742
- * `admitterAddrs` is where the owner's own node can be dialed — take it from
743
- * that node's network status with {@link admitterAddrsFromNetworkStatus}.
744
- * The first fleet node placed on a namespace has nobody but the owner to ask
745
- * for admission, and without these it can only broadcast and hope the
746
- * owner's node — often a laptop behind a relay — hears it. They are a dial
747
- * hint, not a grant: the owner's node admits by its own policy. Omit them to
748
- * leave whatever the cloud already holds; pass them again when the node's
749
- * relay address changes, and they replace the stored ones.
750
- *
751
- * Not to be confused with {@link enableHA}, which opens the cloud's web flow
752
- * in a browser tab for a user to complete by hand. This is the API call.
753
- */
754
- enableNamespaceHa(namespaceId: string, options?: {
755
- admitterAddrs?: readonly string[];
756
- }): Promise<unknown>;
757
- /**
758
- * Enable HA for a namespace this ACCOUNT founded through a relay, with the
759
- * founder's claim (`signAccountOwnershipClaim`) instead of a node's
760
- * ownership proof: a nodeless account holds no node that could issue one.
761
- * The login must be linked to that account.
762
- */
763
- enableFoundedNamespaceHa(namespaceId: string, ownershipProof: AccountOwnershipProof): Promise<unknown>;
764
- /**
765
- * Enable HA for a namespace this account founded, with **no cloud session**.
766
- *
767
- * The anonymous sibling of {@link enableFoundedNamespaceHa}: it signs the
768
- * founder's claim itself ({@link signAccountHaClaim} — no `subject`, its own
769
- * audience) and posts it to
770
- * `/api/cloud/accounts/{accountId}/namespaces/{namespaceId}/enable-ha`. The
771
- * cloud bills the user the account is linked to through the wallet, so the
772
- * account must be linked to exactly one:
773
- *
774
- * - not linked at all → {@link AccountNotLinkedError};
775
- * - linked to several → {@link AccountLinkedToSeveralUsersError}.
776
- *
777
- * A claim that does not verify is a `403` `HTTPError`; quota and the rest
778
- * answer as the session route does. Returns the cloud's response body, the
779
- * same shape the session route's enable-ha returns.
780
- */
781
- enableHaAsAccount(options: EnableHaAsAccountOptions): Promise<unknown>;
782
- /**
783
- * Stop hosting a claimed namespace.
784
- *
785
- * The fleet's own reconcile loop does the rest: each assigned node notices
786
- * the namespace is no longer assigned to it and **self-leaves**, which makes
787
- * core evict it and purge its local data and keys. So this is not just a
788
- * billing flip.
789
- */
790
- disableNamespaceHa(namespaceId: string): Promise<unknown>;
791
- /**
792
- * The node assigned to the signed-in user, or `null`.
793
- *
794
- * @deprecated Use {@link getMyMachines}. This reads the cloud's retired
795
- * `NodeAssignment` ledger, which nothing has written since the v1
796
- * retirement, so it answers `null` for every namespace-native account —
797
- * which reads as "you have no machine" when the truth is "that is no longer
798
- * how a machine is assigned".
799
- */
800
- getMyNode(): Promise<Record<string, unknown> | null>;
801
- enableHA(options: EnableHAOptions): void;
802
- disableHA(options: DisableHAOptions): void;
803
- /** Record a freshly-issued session and tell the app to persist it. */
804
- /**
805
- * Link a Calimero account to this cloud login, proving possession of its root.
806
- *
807
- * Two hops, folded into one call because they are useless apart: fetch a
808
- * single-use challenge, then sign it with the account root and post the proof.
809
- * The secret never leaves this process — only a signature over a nonce the
810
- * cloud minted does.
811
- *
812
- * This is the binding the cloud bills against. A relay does not need it to run
813
- * an intent; the cloud needs it to know whose plan a hosted node is spending,
814
- * and to sign that account back in later.
815
- *
816
- * @param root the account root: its 64-hex secret — from
817
- * {@link generateAccountRoot}, a restored recovery phrase, or a desktop app
818
- * or hardware key that already holds one — or a `Signer` over a root this
819
- * process cannot read, which is what a phrase-held browser root is.
820
- *
821
- * Idempotent for the same login. An account already linked to a *different*
822
- * cloud login is a `409`; a replayed or expired challenge is a `403`; and
823
- * exceeding the plan's account limit is a `402`.
824
- */
825
- linkAccount(root: RootSource): Promise<CloudAccountLink>;
826
- /**
827
- * Mint a single-use challenge for an account root to sign.
828
- *
829
- * The split half of {@link linkAccount}, for the case that call cannot serve:
830
- * a root held by a desktop app, a hardware key or an air-gapped machine, which
831
- * signs without the secret ever reaching this process. Fetch the challenge
832
- * here, have the holder sign it, then hand the proof to
833
- * {@link submitAccountLink}.
834
- *
835
- * Bound to the signed-in login and short-lived, so it is not a standing
836
- * capability if it leaks — but it IS single-use, so a challenge fetched and
837
- * abandoned is spent.
838
- */
839
- getAccountLinkChallenge(): Promise<AccountLinkChallenge>;
840
- /**
841
- * Post a proof assembled elsewhere. The other half of
842
- * {@link getAccountLinkChallenge}.
843
- *
844
- * `accountId` must be the account `rootPublicKey` names — the cloud refuses a
845
- * valid signature by a key that names a different account, or a caller could
846
- * prove one root and link somebody else's account. Derive both from the same
847
- * key rather than letting a user type either.
848
- */
849
- submitAccountLink(proof: AccountLinkProof): Promise<CloudAccountLink>;
850
- /**
851
- * Where to send someone to authorise linking this account, and what to expect
852
- * back. Pairs with {@link readAccountLinkCallback} and
853
- * {@link linkAccountWithGrant}.
854
- *
855
- * This exists because a browser app is in a bind: it holds an account root and
856
- * can never hold a *first* cloud session, since only Google issues one. So the
857
- * person goes to the cloud, where they are signed in, and consents there. What
858
- * comes back is a grant — consent to link this one account, spendable only by
859
- * whoever can sign with its root.
860
- *
861
- * @param callbackUrl where the portal sends the person back. Must be an origin
862
- * the cloud allows; unlisted ones are refused when the grant is minted, not
863
- * here. The grant arrives in the URL **fragment**, which browsers do not
864
- * send to servers.
865
- *
866
- * Static, so it needs no client and no session: there is nothing to
867
- * authenticate as yet.
868
- */
869
- static accountLinkHandoff(options: {
870
- /** The cloud portal's origin, e.g. `https://cloud.calimero.network`. */
871
- portalUrl: string;
872
- /** The account to be linked, 64 hex — derive it, never let a user type it. */
873
- accountId: string;
874
- /** Where to come back to. */
875
- callbackUrl: string;
876
- }): Promise<AccountLinkHandoff>;
877
- /**
878
- * Read the portal's answer out of a callback URL's fragment.
879
- *
880
- * Returns `{}` when there is nothing to read, so it is safe to call on every
881
- * load — which is how a redirected app finds out it has been sent back.
882
- *
883
- * A grant is only returned when it answers a handoff this browser began, for the
884
- * account that handoff named; anything else comes back as
885
- * `error: 'unexpected_callback'`, because the redirect URL can be forwarded.
886
- *
887
- * @param href defaults to the current location, when there is one.
888
- */
889
- static readAccountLinkCallback(href?: string): AccountLinkCallback;
890
- /**
891
- * Spend a link grant: sign it with the account root and post the pair.
892
- *
893
- * Anonymous, and it has to be — the app doing this holds no cloud session,
894
- * which is the whole reason the grant exists. The grant carries the consenting
895
- * login sealed inside it, so nothing here names one; a caller-supplied email
896
- * would be a field to lie in.
897
- *
898
- * The signature is an ordinary account-link signature with the grant as the
899
- * nonce, so the same {@link signAccountLink} every other link path uses signs
900
- * this one. The grant is bound to the verifier of the browser that asked for
901
- * it, and is refused here, before the root signs, unless it carries that
902
- * verifier's challenge and names this root's account.
903
- *
904
- * A `403` means the grant was bad, expired, already spent, or signed by a key
905
- * that names a different account; `409` that the account belongs to another
906
- * login; `402` that the plan is full.
907
- */
908
- linkAccountWithGrant(options: {
909
- grant: string;
910
- /** The verifier {@link readAccountLinkCallback} returned with the grant. */
911
- verifier: string;
912
- /** The root of the account the grant names, 64 hex. */
913
- rootSecret?: string;
914
- /**
915
- * The root's signer — use instead of `rootSecret` when the root is a key
916
- * this process may use and cannot read.
917
- */
918
- signer?: Signer;
919
- }): Promise<CloudAccountLink>;
920
- /** The accounts linked to this login, and how many the plan allows. */
921
- getMyAccounts(): Promise<CloudLinkedAccounts>;
922
- private adoptSession;
923
- private notifySession;
924
- private request;
925
- /**
926
- * Adopt a session token the server refreshed mid-request.
927
- *
928
- * MDMA rotates the token on activity and returns the replacement in a
929
- * response header rather than making the client ask. Ignoring it costs
930
- * nothing immediately and then logs the user out a week later, which is the
931
- * kind of bug that is impossible to reproduce in a short session.
932
- *
933
- * The user identity is carried over: the header holds only a token, and the
934
- * refresh is the same logical session as the sign-in that named the user.
935
- */
936
- private adoptRollingRefresh;
937
- }
938
- /**
939
- * The addresses a fleet node can dial to ask this node for admission, from the
940
- * node's `GET /admin-api/network/status` (see `AdminApiClient`).
941
- *
942
- * Its `externalAddrs`, each made to end in `/p2p/<localPeerId>`: that is the
943
- * shape core dials, and an external address is usually reported without it. A
944
- * relay-circuit address already contains `/p2p/` — the relay's — so the test is
945
- * whether it ends in this node's own id, not whether it names a peer at all.
946
- * Anything that is not a multiaddr is dropped. Empty when the status names no
947
- * peer id or no external address, which is an honest "not dialable yet".
948
- */
949
- export declare function admitterAddrsFromNetworkStatus(status: unknown): string[];