@calimero-network/mero-js 27.0.2 → 27.2.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 +10 -4
- package/dist/cloud-v2/approvals.d.ts +344 -0
- package/dist/cloud-v2/approvals.js +170 -0
- package/dist/cloud-v2/capabilities.d.ts +8 -1
- package/dist/cloud-v2/capabilities.js +8 -1
- package/dist/cloud-v2/client.d.ts +180 -11
- package/dist/cloud-v2/client.js +299 -33
- package/dist/cloud-v2/errors.d.ts +49 -1
- package/dist/cloud-v2/errors.js +62 -1
- package/dist/cloud-v2/index.d.ts +4 -2
- package/dist/cloud-v2/index.js +2 -1
- package/dist/index.browser.mjs +7 -3
- package/dist/index.browser.mjs.map +4 -4
- package/dist/index.cjs +431 -30
- package/dist/index.cjs.map +4 -4
- package/dist/index.mjs +431 -30
- package/dist/index.mjs.map +4 -4
- package/package.json +1 -1
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { type AttestationDoc, type CloudPolicy } from './attestation.js';
|
|
13
13
|
import { type PasskeyProvider } from './passkey.js';
|
|
14
|
-
|
|
14
|
+
import { type AppsReport, type ConsentRequest, type ConsentResult, type ConsentStarted, type OpsAppsReport, type OpsOrgsReport, type PageOptions, type PendingApprovals, type PublisherBindingInfo, type PublisherProof, type ReleaseRules } from './approvals.js';
|
|
15
|
+
export { AppError, ArgsTooLarge, CalimeroError, ConfirmCancelled, ConfirmRequired, IdempotencyMismatch, LoginRequired, ConsentStale, NotFound, ReleaseDeadlineError, TrapError, UnavailableError, WrongNode, errorFrom, } from './errors.js';
|
|
15
16
|
export type { Committed } from './errors.js';
|
|
16
17
|
export interface CalimeroSession {
|
|
17
18
|
accountId: string;
|
|
@@ -112,6 +113,23 @@ export interface OrgUpgradeTarget {
|
|
|
112
113
|
cascade?: boolean;
|
|
113
114
|
migrate?: string;
|
|
114
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* `GET /orgs/{org}`: the organization as the caller sees it. Besides its
|
|
118
|
+
* members, teams and metadata, who may approve its releases, the package
|
|
119
|
+
* signing keys it publishes, and whether a passed release deadline has
|
|
120
|
+
* stopped new work on its own set.
|
|
121
|
+
*/
|
|
122
|
+
export interface OrgInfo extends Record<string, unknown> {
|
|
123
|
+
/** Accounts holding `APPROVE_RELEASES` there (owner and admins included). */
|
|
124
|
+
releaseApprovers: string[];
|
|
125
|
+
/** The signer ids (`did:key`) bound to it as publisher. */
|
|
126
|
+
publishes: string[];
|
|
127
|
+
/** `null` unless a deadline stopped new work: approve `release` (or newer) to lift it. */
|
|
128
|
+
newWorkStopped: {
|
|
129
|
+
release: string;
|
|
130
|
+
after: string;
|
|
131
|
+
} | null;
|
|
132
|
+
}
|
|
115
133
|
/**
|
|
116
134
|
* How a call or a view is sent again while the node is unavailable (D70): with
|
|
117
135
|
* the same key, after a backoff that starts at `baseDelayMs` and doubles up to
|
|
@@ -138,8 +156,15 @@ export declare function retryDelayMs(retry: number, options: {
|
|
|
138
156
|
maxDelayMs: number;
|
|
139
157
|
}): number;
|
|
140
158
|
export interface CalimeroClientOptions {
|
|
141
|
-
/** One node of the cluster. */
|
|
159
|
+
/** One node of the cluster: the one the client talks to first. */
|
|
142
160
|
baseUrl: string;
|
|
161
|
+
/**
|
|
162
|
+
* Other nodes of the same cluster, in the order to move to them when a node
|
|
163
|
+
* answers `421 WRONG_NODE` (its release may not serve this account). Each is
|
|
164
|
+
* attested under the same `policy` before anything is sent to it. Without
|
|
165
|
+
* them a `421` reaches the caller as {@link WrongNode}.
|
|
166
|
+
*/
|
|
167
|
+
nodes?: string[];
|
|
143
168
|
policy: CloudPolicy;
|
|
144
169
|
/** Fetch that carries attestation and envelopes. Defaults to global `fetch`. */
|
|
145
170
|
fetch?: typeof fetch;
|
|
@@ -147,21 +172,70 @@ export interface CalimeroClientOptions {
|
|
|
147
172
|
retry?: CloudRetryOptions;
|
|
148
173
|
}
|
|
149
174
|
export declare class CalimeroClient {
|
|
150
|
-
|
|
151
|
-
private readonly
|
|
175
|
+
/** Every node this client may use, `baseUrl` first. */
|
|
176
|
+
private readonly nodeUrls;
|
|
177
|
+
/** The one in use: an index into {@link nodeUrls}. */
|
|
178
|
+
private at;
|
|
179
|
+
/** A sealed fetch per node, each attesting its own node on first use. */
|
|
180
|
+
private readonly channels;
|
|
181
|
+
private readonly policy;
|
|
152
182
|
/** The unsealed fetch, for the one route served in the clear (`/attestation`). */
|
|
153
183
|
private readonly raw;
|
|
154
184
|
private auth;
|
|
155
185
|
private current;
|
|
186
|
+
/** The refresh under way, which every request that needs one shares. */
|
|
187
|
+
private refreshing;
|
|
156
188
|
private readonly retry;
|
|
157
189
|
/** Rejections of the underlying `fetch` itself: the node could not be reached or dropped the connection. */
|
|
158
190
|
private readonly networkFailures;
|
|
159
191
|
constructor(options: CalimeroClientOptions);
|
|
192
|
+
/** The node requests go to now: `baseUrl`, until a `421 WRONG_NODE` moved the client on. */
|
|
193
|
+
get nodeUrl(): string;
|
|
194
|
+
/** The sealed channel to `url`, attested under the client's policy before its first request. */
|
|
195
|
+
private channel;
|
|
196
|
+
/**
|
|
197
|
+
* Move on from node `from` (the one that answered `421 WRONG_NODE`) to the
|
|
198
|
+
* next one. False when there is no other. A request that saw the same node
|
|
199
|
+
* refuse after another request moved on already does not move again.
|
|
200
|
+
*/
|
|
201
|
+
private moveOn;
|
|
160
202
|
/** Authenticate every request with an API key. */
|
|
161
203
|
useApiKey(key: string): void;
|
|
162
204
|
useSession(session: CalimeroSession): void;
|
|
163
205
|
get session(): CalimeroSession | undefined;
|
|
206
|
+
/**
|
|
207
|
+
* Send one request to the node in use, with the credential held now, and
|
|
208
|
+
* answer the response, whatever its status. {@link send} judges it.
|
|
209
|
+
*/
|
|
164
210
|
private request;
|
|
211
|
+
/**
|
|
212
|
+
* {@link request}, answering what a lost issuing node or a node on the
|
|
213
|
+
* wrong release does to a session: a successful response, or the refusal as a
|
|
214
|
+
* typed error ({@link errorFrom}).
|
|
215
|
+
*
|
|
216
|
+
* - `401 UNAUTHENTICATED` to a request that carried a session: the node that
|
|
217
|
+
* signed the session may be gone, replaced, or out of reach of the node
|
|
218
|
+
* asked, which any node of the cluster answers with a refresh. The client
|
|
219
|
+
* refreshes once, shared by every request that needs it at the same time
|
|
220
|
+
* ({@link refresh}), and repeats the request once. A refresh that is
|
|
221
|
+
* refused surfaces as {@link LoginRequired}.
|
|
222
|
+
* - `421 WRONG_NODE`: this node's release may not serve the account. The
|
|
223
|
+
* client moves to the next node it knows and repeats the request once; with
|
|
224
|
+
* none, the {@link WrongNode} reaches the caller.
|
|
225
|
+
*
|
|
226
|
+
* Repeating is safe even for a request that is not idempotent: the node
|
|
227
|
+
* answers `401` and `421` when it judges the credential, before it reads what
|
|
228
|
+
* the request asks, so the first attempt ran nothing. The exceptions are the
|
|
229
|
+
* ceremonies that mint a session ({@link ceremony}), never repeated here.
|
|
230
|
+
*/
|
|
231
|
+
private send;
|
|
232
|
+
/** Whether a `401` to a request sent with `token` is one a refresh may answer. */
|
|
233
|
+
private mayRefresh;
|
|
234
|
+
/**
|
|
235
|
+
* A fresh session in place of the one `token` belonged to: by the refresh
|
|
236
|
+
* another request already made, or by one this request starts.
|
|
237
|
+
*/
|
|
238
|
+
private renew;
|
|
165
239
|
private json;
|
|
166
240
|
/**
|
|
167
241
|
* {@link json} for a call or a view (D70): while the node answers 503 or
|
|
@@ -181,8 +255,14 @@ export declare class CalimeroClient {
|
|
|
181
255
|
signUp(passkey: PasskeyProvider, name: string): Promise<CalimeroSession>;
|
|
182
256
|
/** Sign in with an existing passkey. */
|
|
183
257
|
signIn(passkey: PasskeyProvider): Promise<CalimeroSession>;
|
|
184
|
-
/**
|
|
258
|
+
/**
|
|
259
|
+
* Swap the refresh token for a new session, on whichever node the client
|
|
260
|
+
* uses: any node of the cluster takes it. A refresh token is used once, so
|
|
261
|
+
* calls made while one refresh is under way share it rather than sending the
|
|
262
|
+
* same token again (which would revoke the session).
|
|
263
|
+
*/
|
|
185
264
|
refresh(): Promise<CalimeroSession>;
|
|
265
|
+
private exchangeRefresh;
|
|
186
266
|
signOut(): Promise<void>;
|
|
187
267
|
/** End every session of the signed-in account, on every device, this one too. */
|
|
188
268
|
signOutEverywhere(): Promise<void>;
|
|
@@ -266,8 +346,11 @@ export declare class CalimeroClient {
|
|
|
266
346
|
* Move an app to another release of its package (`{ version }`), another
|
|
267
347
|
* package, or a bundle hash, running its migration. Answers the upgrade's
|
|
268
348
|
* entry; a failed migration rejects with code `UPGRADE_FAILED` (422).
|
|
269
|
-
* Where
|
|
270
|
-
* (`412 CONFIRM_REQUIRED`), which
|
|
349
|
+
* Where owners hold app upgrades, the node asks for the approval of
|
|
350
|
+
* whoever the package's manifest names (`412 CONFIRM_REQUIRED`), which
|
|
351
|
+
* `passkey` gives. Refused (`403`) to a session opened on an app's
|
|
352
|
+
* frontend: an app asks its user with {@link requestConsent} instead. Past
|
|
353
|
+
* a release deadline its approver has not met: {@link ReleaseDeadlineError}.
|
|
271
354
|
*/
|
|
272
355
|
upgradeApp(app: string, target: {
|
|
273
356
|
version?: string;
|
|
@@ -346,7 +429,7 @@ export declare class CalimeroClient {
|
|
|
346
429
|
deleteAlias(alias: string): Promise<void>;
|
|
347
430
|
createOrg(name: string): Promise<string>;
|
|
348
431
|
/** The organization, with the teams this caller reaches or manages. */
|
|
349
|
-
getOrg(org: string): Promise<
|
|
432
|
+
getOrg(org: string): Promise<OrgInfo>;
|
|
350
433
|
/**
|
|
351
434
|
* Delete an organization with its teams, invites and apps (its owner only).
|
|
352
435
|
* The node asks for the owner's passkey (`412 CONFIRM_REQUIRED`), which `passkey` gives.
|
|
@@ -370,8 +453,11 @@ export declare class CalimeroClient {
|
|
|
370
453
|
/**
|
|
371
454
|
* Approve a mero-tee release to hold the apps of `org`, or of this account
|
|
372
455
|
* outside any organization (`org` `null`); `approved: false` withdraws it.
|
|
373
|
-
* Until then, nodes on that release get none of those apps' data.
|
|
374
|
-
* approves with `passkey
|
|
456
|
+
* Until then, nodes on that release get none of those apps' data. For an
|
|
457
|
+
* organization, a member holding `APPROVE_RELEASES` approves with `passkey`;
|
|
458
|
+
* the node binds the release's measurements itself. Refused (`403`) to a
|
|
459
|
+
* session opened on an app's frontend: an app asks its user with
|
|
460
|
+
* {@link requestConsent} instead.
|
|
375
461
|
*/
|
|
376
462
|
approveRelease(org: string | null, version: string, passkey: PasskeyProvider, approved?: boolean): Promise<Record<string, unknown>>;
|
|
377
463
|
/**
|
|
@@ -379,12 +465,95 @@ export declare class CalimeroClient {
|
|
|
379
465
|
* `org`'s apps or this account's own (`org` `null`). `prefixes` `'manifest'`
|
|
380
466
|
* (the default) approves every prefix the package's latest release declares;
|
|
381
467
|
* `replace` sets exactly `prefixes`, which is how one is revoked. Approved
|
|
382
|
-
* with `passkey`.
|
|
468
|
+
* with `passkey`. Refused (`403`) to a session opened on an app's frontend:
|
|
469
|
+
* an app asks with {@link requestConsent} (`kind: 'outbound'`) instead.
|
|
383
470
|
*/
|
|
384
471
|
approveOutbound(org: string | null, pkg: string, passkey: PasskeyProvider, options?: {
|
|
385
472
|
prefixes?: string[] | 'manifest';
|
|
386
473
|
replace?: boolean;
|
|
387
474
|
}): Promise<Record<string, unknown>>;
|
|
475
|
+
/**
|
|
476
|
+
* One page of the report of a scope's apps: an organization's (any member;
|
|
477
|
+
* `404` to anyone else) or, with `org` `null`, the account's own outside any
|
|
478
|
+
* organization (a session bound to an app's frontend: that package's apps).
|
|
479
|
+
* The governance, the scope's approved releases, the releases the cluster's
|
|
480
|
+
* nodes run and whether each is approved, and per app its release, newer
|
|
481
|
+
* releases it may move to, last upgrade and replicas.
|
|
482
|
+
*/
|
|
483
|
+
appsReport(org: string | null, page?: PageOptions): Promise<AppsReport>;
|
|
484
|
+
/** {@link appsReport}, every page, with the apps of all of them in `apps`. */
|
|
485
|
+
appsReportAll(org: string | null): Promise<AppsReport>;
|
|
486
|
+
/** `GET /releases`: the cluster's governance and every release deadline. Public. */
|
|
487
|
+
releaseRules(): Promise<ReleaseRules>;
|
|
488
|
+
/**
|
|
489
|
+
* What waits for a decision in a scope (`org`, or the account's own apps
|
|
490
|
+
* with `null`): mero-tee releases the cluster's nodes run that the scope has
|
|
491
|
+
* not approved, apps with newer releases of their package, and whether a
|
|
492
|
+
* passed deadline stops new work. Read over the sealed channel; act on an
|
|
493
|
+
* item by sending the user to the consent page ({@link requestConsent},
|
|
494
|
+
* `releaseConsent`, `upgradeConsent`).
|
|
495
|
+
*/
|
|
496
|
+
pendingApprovals(org?: string | null): Promise<PendingApprovals>;
|
|
497
|
+
/**
|
|
498
|
+
* Ask the node to ask the user: a release, upgrade or outbound approval
|
|
499
|
+
* that only the account holder may make, decided on the node's own consent
|
|
500
|
+
* page, never in the app. Needs a passkey session (a session bound to the
|
|
501
|
+
* app's frontend is fine). Send the person to the answer's `url`; the page
|
|
502
|
+
* sends them back to `returnTo?request_id=…&result=approved|declined`
|
|
503
|
+
* (`consentReturn`), and {@link consentResult} confirms the decision.
|
|
504
|
+
*/
|
|
505
|
+
requestConsent(request: ConsentRequest): Promise<ConsentStarted>;
|
|
506
|
+
/**
|
|
507
|
+
* {@link requestConsent}, then send the browser to the consent page
|
|
508
|
+
* (`navigate`, by default `window.location.assign`). Answers the request
|
|
509
|
+
* once `navigate` returns: with a popup (`url => window.open(url)`), poll it
|
|
510
|
+
* with {@link waitForConsent}.
|
|
511
|
+
*/
|
|
512
|
+
openConsentPage(request: ConsentRequest, navigate?: (url: string) => void): Promise<ConsentStarted>;
|
|
513
|
+
/** The decision on a consent request (any node answers, for the account that asked). */
|
|
514
|
+
consentResult(requestId: string): Promise<ConsentResult>;
|
|
515
|
+
/**
|
|
516
|
+
* Poll {@link consentResult} until the request is decided, every
|
|
517
|
+
* `intervalMs` (2 s), until `signal` aborts or `expiresAt` (Unix seconds)
|
|
518
|
+
* passes, when it answers the last `pending` result.
|
|
519
|
+
*/
|
|
520
|
+
waitForConsent(requestId: string, options?: {
|
|
521
|
+
intervalMs?: number;
|
|
522
|
+
signal?: AbortSignal;
|
|
523
|
+
expiresAt?: number;
|
|
524
|
+
}): Promise<ConsentResult>;
|
|
525
|
+
/** `GET /publishers/{signerId}`: the cluster name and binding generation a key signs to bind it next. */
|
|
526
|
+
publisherBinding(signerId: string): Promise<PublisherBindingInfo>;
|
|
527
|
+
/**
|
|
528
|
+
* Bind a package signing key to `org`, which then approves the node images
|
|
529
|
+
* every instance of the key's packages runs on, and upgrades those whose
|
|
530
|
+
* package declares `upgrades: publisher`. `proof` is the key's signature
|
|
531
|
+
* over `publisherBindingMessage(cluster, org, signerId, generation)`; a
|
|
532
|
+
* member holding `APPROVE_RELEASES` sends it with `passkey`.
|
|
533
|
+
*/
|
|
534
|
+
bindPublisher(org: string, proof: PublisherProof, passkey: PasskeyProvider): Promise<Record<string, unknown>>;
|
|
535
|
+
/**
|
|
536
|
+
* Upgrade every instance of `pkg` whose release declares `upgrades:
|
|
537
|
+
* publisher`, whoever owns it, as its publisher `org` (a
|
|
538
|
+
* `MANAGE_APPLICATION` holder there), with one passkey approval. Answers
|
|
539
|
+
* the run, kept on the publisher.
|
|
540
|
+
*/
|
|
541
|
+
upgradePublished(org: string, pkg: string, target: {
|
|
542
|
+
version: string;
|
|
543
|
+
migrate?: string;
|
|
544
|
+
}, passkey: PasskeyProvider): Promise<UpgradeRun>;
|
|
545
|
+
/** `GET /ops/apps`: what every app runs, without names or accounts. Operator token (`useApiKey`). */
|
|
546
|
+
opsApps(page?: PageOptions): Promise<OpsAppsReport>;
|
|
547
|
+
/** `GET /ops/orgs`: each organization's approved releases. Operator token. */
|
|
548
|
+
opsOrgs(page?: PageOptions): Promise<OpsOrgsReport>;
|
|
549
|
+
/**
|
|
550
|
+
* Announce when work on images older than `version` ends: from `after` on,
|
|
551
|
+
* a scope that has not approved it (or newer) starts no new work. Operator
|
|
552
|
+
* token.
|
|
553
|
+
*/
|
|
554
|
+
setReleaseDeadline(version: string, after: Date | string): Promise<void>;
|
|
555
|
+
/** Lift a release's deadline. Operator token. */
|
|
556
|
+
liftReleaseDeadline(version: string): Promise<void>;
|
|
388
557
|
/** Add a member, or change their role. */
|
|
389
558
|
setMember(org: string, account: string, role: 'guest' | 'member' | 'admin' | 'owner'): Promise<void>;
|
|
390
559
|
removeMember(org: string, account: string): Promise<Record<string, unknown>>;
|