@calimero-network/mero-js 26.11.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.
- package/README.md +73 -288
- package/dist/cloud-v2/attestation.d.ts +91 -0
- package/dist/cloud-v2/attestation.js +135 -0
- package/dist/cloud-v2/capabilities.d.ts +30 -0
- package/dist/cloud-v2/capabilities.js +31 -0
- package/dist/cloud-v2/client.d.ts +426 -0
- package/dist/cloud-v2/client.js +646 -0
- package/dist/cloud-v2/errors.d.ts +98 -0
- package/dist/cloud-v2/errors.js +165 -0
- package/dist/cloud-v2/index.d.ts +10 -0
- package/dist/cloud-v2/index.js +5 -0
- package/dist/cloud-v2/passkey.d.ts +27 -0
- package/dist/cloud-v2/passkey.js +73 -0
- package/dist/crypto/internal.d.ts +3 -37
- package/dist/crypto/internal.js +3 -72
- package/dist/index.browser.mjs +4 -2
- package/dist/index.browser.mjs.map +4 -4
- package/dist/index.cjs +1750 -12772
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +3 -56
- package/dist/index.js +14 -75
- package/dist/index.mjs +1750 -12772
- package/dist/index.mjs.map +4 -4
- package/dist/sealed/index.d.ts +4 -4
- package/dist/sealed/index.js +2 -2
- package/dist/sealed/release.d.ts +21 -76
- package/dist/sealed/release.js +24 -108
- package/dist/sealed/sealed.d.ts +8 -56
- package/dist/sealed/sealed.js +11 -89
- package/dist/sealed/verify.d.ts +7 -13
- package/dist/sealed/verify.js +3 -7
- package/package.json +8 -13
- package/dist/account/account-admin.d.ts +0 -80
- package/dist/account/account-admin.js +0 -346
- package/dist/account/account.d.ts +0 -196
- package/dist/account/account.js +0 -269
- package/dist/account/application-id.d.ts +0 -50
- package/dist/account/application-id.js +0 -83
- package/dist/account/bootstrap-from-invitation.d.ts +0 -110
- package/dist/account/bootstrap-from-invitation.js +0 -80
- package/dist/account/create-context.d.ts +0 -103
- package/dist/account/create-context.js +0 -267
- package/dist/account/govern.d.ts +0 -24
- package/dist/account/govern.js +0 -50
- package/dist/account/index.d.ts +0 -26
- package/dist/account/index.js +0 -15
- package/dist/account/join-as-account.d.ts +0 -23
- package/dist/account/join-as-account.js +0 -34
- package/dist/account/join-with-node.d.ts +0 -115
- package/dist/account/join-with-node.js +0 -161
- package/dist/account/node-admin.d.ts +0 -20
- package/dist/account/node-admin.js +0 -33
- package/dist/account/relay-from-invitation.d.ts +0 -137
- package/dist/account/relay-from-invitation.js +0 -180
- package/dist/account/relay-login-error.d.ts +0 -32
- package/dist/account/relay-login-error.js +0 -34
- package/dist/account/session.d.ts +0 -266
- package/dist/account/session.js +0 -915
- package/dist/account/wordlist.d.ts +0 -16
- package/dist/account/wordlist.js +0 -273
- package/dist/admin-api/admin-client.d.ts +0 -688
- package/dist/admin-api/admin-client.js +0 -1230
- package/dist/admin-api/admin-factory.d.ts +0 -14
- package/dist/admin-api/admin-factory.js +0 -22
- package/dist/admin-api/admin-types.d.ts +0 -2046
- package/dist/admin-api/admin-types.js +0 -12
- package/dist/admin-api/index.d.ts +0 -4
- package/dist/admin-api/index.js +0 -5
- package/dist/admin-api/redeem-invitation.d.ts +0 -101
- package/dist/admin-api/redeem-invitation.js +0 -200
- package/dist/auth/index.d.ts +0 -34
- package/dist/auth/index.js +0 -67
- package/dist/auth-api/auth-client.d.ts +0 -31
- package/dist/auth-api/auth-client.js +0 -117
- package/dist/auth-api/auth-factory.d.ts +0 -7
- package/dist/auth-api/auth-factory.js +0 -41
- package/dist/auth-api/auth-types.d.ts +0 -130
- package/dist/auth-api/auth-types.js +0 -2
- package/dist/auth-api/index.d.ts +0 -3
- package/dist/auth-api/index.js +0 -4
- package/dist/capabilities.d.ts +0 -84
- package/dist/capabilities.js +0 -117
- package/dist/cloud/account-ownership.d.ts +0 -63
- package/dist/cloud/account-ownership.js +0 -87
- package/dist/cloud/cloud-client.d.ts +0 -949
- package/dist/cloud/cloud-client.js +0 -1068
- package/dist/cloud/connect.d.ts +0 -213
- package/dist/cloud/connect.js +0 -260
- package/dist/cloud/enrol-redirect.d.ts +0 -181
- package/dist/cloud/enrol-redirect.js +0 -244
- package/dist/cloud/index.d.ts +0 -12
- package/dist/cloud/index.js +0 -10
- package/dist/cloud/link-redirect.d.ts +0 -95
- package/dist/cloud/link-redirect.js +0 -121
- package/dist/cloud/link-state.d.ts +0 -36
- package/dist/cloud/link-state.js +0 -104
- package/dist/cloud/routing-proof.d.ts +0 -113
- package/dist/cloud/routing-proof.js +0 -96
- package/dist/device-cert/device-cert.d.ts +0 -189
- package/dist/device-cert/device-cert.js +0 -239
- package/dist/device-cert/device-scope.d.ts +0 -58
- package/dist/device-cert/device-scope.js +0 -76
- package/dist/device-cert/index.d.ts +0 -4
- package/dist/device-cert/index.js +0 -3
- package/dist/ephemeral/codec.d.ts +0 -4
- package/dist/ephemeral/codec.js +0 -12
- package/dist/ephemeral/index.d.ts +0 -57
- package/dist/ephemeral/index.js +0 -101
- package/dist/ephemeral/types.d.ts +0 -27
- package/dist/ephemeral/types.js +0 -1
- package/dist/errors/classify.d.ts +0 -65
- package/dist/errors/classify.js +0 -117
- package/dist/errors/index.d.ts +0 -2
- package/dist/errors/index.js +0 -1
- package/dist/events/group.d.ts +0 -95
- package/dist/events/group.js +0 -10
- package/dist/events/index.d.ts +0 -5
- package/dist/events/index.js +0 -2
- package/dist/events/sse.d.ts +0 -127
- package/dist/events/sse.js +0 -469
- package/dist/events/ws.d.ts +0 -57
- package/dist/events/ws.js +0 -212
- package/dist/http-client/api-response.d.ts +0 -15
- package/dist/http-client/api-response.js +0 -1
- package/dist/http-client/http-factory.d.ts +0 -71
- package/dist/http-client/http-factory.js +0 -68
- package/dist/http-client/http-types.d.ts +0 -87
- package/dist/http-client/http-types.js +0 -1
- package/dist/http-client/index.d.ts +0 -7
- package/dist/http-client/index.js +0 -11
- package/dist/http-client/path-segment.d.ts +0 -1
- package/dist/http-client/path-segment.js +0 -8
- package/dist/http-client/retry.d.ts +0 -5
- package/dist/http-client/retry.js +0 -82
- package/dist/http-client/signal-utils.d.ts +0 -2
- package/dist/http-client/signal-utils.js +0 -41
- package/dist/http-client/web-client.d.ts +0 -80
- package/dist/http-client/web-client.js +0 -557
- package/dist/invitation/index.d.ts +0 -2
- package/dist/invitation/index.js +0 -2
- package/dist/invitation/invitation.d.ts +0 -106
- package/dist/invitation/invitation.js +0 -104
- package/dist/login/index.d.ts +0 -4
- package/dist/login/index.js +0 -3
- package/dist/login/login.d.ts +0 -111
- package/dist/login/login.js +0 -110
- package/dist/login/session.d.ts +0 -124
- package/dist/login/session.js +0 -141
- package/dist/mero-js.d.ts +0 -231
- package/dist/mero-js.js +0 -469
- package/dist/namespace-op/index.d.ts +0 -2
- package/dist/namespace-op/index.js +0 -3
- package/dist/namespace-op/namespace-op.d.ts +0 -150
- package/dist/namespace-op/namespace-op.js +0 -191
- package/dist/nodeDiscovery.d.ts +0 -47
- package/dist/nodeDiscovery.js +0 -101
- package/dist/owner-op/index.d.ts +0 -2
- package/dist/owner-op/index.js +0 -3
- package/dist/owner-op/owner-op.d.ts +0 -119
- package/dist/owner-op/owner-op.js +0 -214
- package/dist/presence/relay-presence.d.ts +0 -56
- package/dist/presence/relay-presence.js +0 -107
- package/dist/presence/statement.d.ts +0 -12
- package/dist/presence/statement.js +0 -17
- package/dist/relay/index.d.ts +0 -4
- package/dist/relay/index.js +0 -2
- package/dist/relay/nonce-source.d.ts +0 -72
- package/dist/relay/nonce-source.js +0 -111
- package/dist/relay/relay-client.d.ts +0 -472
- package/dist/relay/relay-client.js +0 -518
- package/dist/relay-attestation/attest-node-key.d.ts +0 -66
- package/dist/relay-attestation/attest-node-key.js +0 -110
- package/dist/relay-attestation/index.d.ts +0 -1
- package/dist/relay-attestation/index.js +0 -1
- package/dist/request/caller-proof.d.ts +0 -43
- package/dist/request/caller-proof.js +0 -36
- package/dist/request/index.d.ts +0 -3
- package/dist/request/index.js +0 -3
- package/dist/request/proof-signer.d.ts +0 -49
- package/dist/request/proof-signer.js +0 -59
- package/dist/request/request-sig.d.ts +0 -99
- package/dist/request/request-sig.js +0 -95
- package/dist/request-proof/authorizer.d.ts +0 -41
- package/dist/request-proof/authorizer.js +0 -60
- package/dist/request-proof/index.d.ts +0 -4
- package/dist/request-proof/index.js +0 -2
- package/dist/request-proof/request-proof.d.ts +0 -53
- package/dist/request-proof/request-proof.js +0 -95
- package/dist/rpc/index.d.ts +0 -64
- package/dist/rpc/index.js +0 -78
- package/dist/signer/index.d.ts +0 -2
- package/dist/signer/index.js +0 -3
- package/dist/signer/signer.d.ts +0 -92
- package/dist/signer/signer.js +0 -147
- package/dist/token-store/index.d.ts +0 -27
- package/dist/token-store/index.js +0 -62
- package/dist/transport/index.d.ts +0 -6
- package/dist/transport/index.js +0 -3
- package/dist/transport/mero-client.d.ts +0 -294
- package/dist/transport/mero-client.js +0 -386
- package/dist/transport/relay-observer.d.ts +0 -152
- package/dist/transport/relay-observer.js +0 -173
- package/dist/transport/relay-transport.d.ts +0 -73
- package/dist/transport/relay-transport.js +0 -94
- package/dist/transport/types.d.ts +0 -100
- package/dist/transport/types.js +0 -32
- package/dist/types/api-response.d.ts +0 -15
- package/dist/types/api-response.js +0 -1
- package/dist/types/index.d.ts +0 -1
- package/dist/types/index.js +0 -1
- package/dist/warrant/creation-warrant.d.ts +0 -163
- package/dist/warrant/creation-warrant.js +0 -194
- package/dist/warrant/governance-op.d.ts +0 -202
- package/dist/warrant/governance-op.js +0 -355
- package/dist/warrant/governance-warrant.d.ts +0 -124
- package/dist/warrant/governance-warrant.js +0 -164
- package/dist/warrant/index.d.ts +0 -8
- package/dist/warrant/index.js +0 -5
- package/dist/warrant/warrant.d.ts +0 -188
- 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[];
|