@calimero-network/mero-js 29.4.0 → 29.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/dist/cloud-v2/client.d.ts +95 -1
- package/dist/cloud-v2/client.js +84 -4
- package/dist/cloud-v2/errors.d.ts +49 -3
- package/dist/cloud-v2/errors.js +67 -3
- package/dist/cloud-v2/index.d.ts +2 -2
- package/dist/cloud-v2/index.js +1 -1
- package/dist/index.browser.mjs +5 -5
- package/dist/index.browser.mjs.map +3 -3
- package/dist/index.cjs +117 -2
- package/dist/index.cjs.map +2 -2
- package/dist/index.mjs +117 -2
- package/dist/index.mjs.map +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -98,7 +98,8 @@ Pinned measurements go through `policy.verifyQuote` (`createQuoteVerifier`).
|
|
|
98
98
|
## The API
|
|
99
99
|
|
|
100
100
|
- **Credentials**: `signUp` (with an `invite`, on a cluster that takes new accounts by invite; `signUpPolicy` reads which), `signIn`, `refresh`, `signOut`, `signOutEverywhere`, `useSession`, `useApiKey`, `me`, `usage`, `addPasskey`, `labelPasskey`, `removePasskey`, `createApiKey`, `listApiKeys`, `revokeApiKey`. Adding or removing a passkey and creating an API key are approved with a passkey the account already has.
|
|
101
|
-
- **
|
|
101
|
+
- **Account recovery** (core #4844): `createRecoveryCode`, `removeRecoveryCode` (passkey-approved; the code is shown once), then signed out `startAccountRecovery(code, passkey)` and, 72 hours later, `finishAccountRecovery(passkey, accountId?)`; a passkey the account still has cancels in between (`cancelAccountRecovery`; `me()` shows `recoveryCode` and `recoveryPending`).
|
|
102
|
+
- **Package origins**: `packageOrigins.list`, `packageOrigins.add`, `packageOrigins.remove`. A package's managers register the web origins of a frontend they host themselves (approved with a passkey); `signUp` and `signIn` on such a page send its origin, sign for that origin's relying-party id, and open a session bound to the package (`me()` answers its `app` and `origin`). An unregistered origin is refused with `OriginNotRegistered`. `packageOrigins.add(pkg, origin, passkey, { served: true })` registers a custom domain: the cluster also serves the package's frontend there from its signed bundle (`https://host`, no port; the passkey's consent names `served: true`); `list` answers `served` on each origin, and the extra refusals are `NotServing` (the cluster serves no frontends), `ClusterNotUpgraded` (a node is on an older release), `QuotaExceeded` (4 served per package, 64 per cluster) and `OriginTaken` (held with the other `served`).
|
|
102
103
|
- **Packages**: `installPackage`, `uploadPackage`, `packages`, `package`, `uninstallPackage`; `uploadBundle` (raw WASM, development clusters only).
|
|
103
104
|
- **Apps**: `createApp`, `listApps`, `getApp`, `deleteApp`, `setAccess`, `setAppMetadata`, `appStorage`, `appAbi`, `upgradeApp`, `transferApp`.
|
|
104
105
|
- **Calls**: `call`, `callConfirmed`, `view`, `events`. A call always carries an idempotency key, and is sent again with it while the node answers `503`, then to the next node.
|
|
@@ -106,7 +107,7 @@ Pinned measurements go through `policy.verifyQuote` (`createQuoteVerifier`).
|
|
|
106
107
|
- **Organizations**: `createOrg`, `getOrg`, `deleteOrg`, `setOrgMetadata`, `setMember`, `removeMember`, `setMemberMetadata`, `setCapabilities` (`ORG_CAPABILITIES`), teams, `invite`, `redeemInvite`, recovery (`setRecoveryKey`, `startRecovery`, `cancelRecovery`, `finishRecovery`; `newRecoverySeed`, `recoveryPublicKey`). Setting or removing a member or team member, capabilities and invites are approved with the caller's passkey; redeeming an invite is not.
|
|
107
108
|
- **Owner decisions** (passkey approval, never from an app's frontend): `upgradeOrg`, `upgradeRun`, `retryUpgradeRun`, `approveRelease`, `approveOutbound`, `bindPublisher`, `upgradePublished`.
|
|
108
109
|
- **Approvals from an app**: `appsReport`, `releaseRules`, `pendingApprovals`, then `requestConsent` / `openConsentPage` to send the user to the node's consent page, and `consentResult`. Show the answer's `code` to the user before sending them to `url` (`openConsentPage`'s `confirm` hook); they should see the same code on the page (`confirmationCode(requestId)` checks it). See [Ask your users to approve node images and app upgrades](https://calimero-network.github.io/mero-js/guides/user-approvals/).
|
|
109
|
-
- **Operator** (ops token): `opsApps`, `opsOrgs`, `setReleaseDeadline`, `liftReleaseDeadline`.
|
|
110
|
+
- **Operator** (ops token): `opsApps`, `opsOrgs`, `opsServedOrigins` (every custom domain the log holds, by package label), `setReleaseDeadline`, `liftReleaseDeadline`.
|
|
110
111
|
- **Any route**: `get`, `post`, `put`, `delete`; `postConfirmed` and `deleteConfirmed` answer a `412 CONFIRM_REQUIRED` with a passkey.
|
|
111
112
|
|
|
112
113
|
Refusals are typed (`LoginRequired`, `WrongNode`, `NotFound`, `ConfirmRequired`, `ConfirmCancelled`,
|
|
@@ -12,7 +12,7 @@
|
|
|
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 OpenConsentOptions, type OpsAppsReport, type OpsOrgsReport, type PageOptions, type PendingApprovals, type PublisherBindingInfo, type PublisherProof, type ReleaseRules } from './approvals.js';
|
|
15
|
-
export { AppError, ArgsTooLarge, BadOrigin, CalimeroError, ConfirmCancelled, ConfirmRequired, IdempotencyMismatch, LoginRequired, ConsentStale, NotFound, OriginNotRegistered, OriginTaken, QuotaExceeded, ReleaseDeadlineError, SignUpRefused, TrapError, UnavailableError, WrongNode, errorFrom, } from './errors.js';
|
|
15
|
+
export { AppError, ArgsTooLarge, BadOrigin, CalimeroError, ConfirmCancelled, ConfirmRequired, IdempotencyMismatch, LoginRequired, ConsentStale, NotFound, OriginNotRegistered, OriginTaken, QuotaExceeded, RecoveryNotReady, ReleaseDeadlineError, SignUpRefused, TrapError, UnavailableError, WrongNode, WrongRecoveryCode, errorFrom, } from './errors.js';
|
|
16
16
|
export type { Committed, SignUpRefusal } from './errors.js';
|
|
17
17
|
export interface CalimeroSession {
|
|
18
18
|
accountId: string;
|
|
@@ -302,6 +302,25 @@ export interface MeInfo extends Record<string, unknown> {
|
|
|
302
302
|
app?: string | null;
|
|
303
303
|
/** The web origin the session was opened on, when the node recorded one. */
|
|
304
304
|
origin?: string | null;
|
|
305
|
+
/** Whether the account holds a recovery code ({@link CalimeroClient.createRecoveryCode}); never the code. */
|
|
306
|
+
recoveryCode?: boolean;
|
|
307
|
+
/**
|
|
308
|
+
* A recovery of this account under way: someone holding its recovery code
|
|
309
|
+
* started it with a new passkey. Warn on every device; a passkey the
|
|
310
|
+
* account has cancels it ({@link CalimeroClient.cancelAccountRecovery})
|
|
311
|
+
* until `readyAt`.
|
|
312
|
+
*/
|
|
313
|
+
recoveryPending?: AccountRecovery | null;
|
|
314
|
+
}
|
|
315
|
+
/** A recovery of an account under way (core #4844, `docs/specs/account-recovery.md`). */
|
|
316
|
+
export interface AccountRecovery {
|
|
317
|
+
accountId: string;
|
|
318
|
+
/** The new passkey the recovery adds when it finishes. */
|
|
319
|
+
credentialId: string;
|
|
320
|
+
/** When it started (Unix seconds). */
|
|
321
|
+
startedAt: number;
|
|
322
|
+
/** The earliest it may finish (Unix seconds): 72 hours after the start. */
|
|
323
|
+
readyAt: number;
|
|
305
324
|
}
|
|
306
325
|
/** One web origin registered for a package (`GET /package-origins/{package}`). */
|
|
307
326
|
export interface PackageOrigin {
|
|
@@ -312,6 +331,12 @@ export interface PackageOrigin {
|
|
|
312
331
|
/** The account that registered it. */
|
|
313
332
|
addedBy: string;
|
|
314
333
|
addedAt: string | number;
|
|
334
|
+
/**
|
|
335
|
+
* The cluster serves the package's frontend on this origin too (a custom
|
|
336
|
+
* domain, from its signed bundle). Absent (`false`) from a node that
|
|
337
|
+
* predates served origins.
|
|
338
|
+
*/
|
|
339
|
+
served?: boolean;
|
|
315
340
|
}
|
|
316
341
|
/** What registering an origin answers. */
|
|
317
342
|
export interface PackageOriginAdded extends PackageOrigin {
|
|
@@ -337,9 +362,21 @@ export interface PackageOrigins {
|
|
|
337
362
|
* caller as {@link ConfirmRequired}). `rpId` defaults to the node's choice
|
|
338
363
|
* for the origin (its host). Refusals: {@link BadOrigin} (`BAD_ORIGIN`,
|
|
339
364
|
* `BAD_RP_ID`), {@link OriginTaken}, {@link QuotaExceeded}.
|
|
365
|
+
*
|
|
366
|
+
* `served: true` makes it a custom domain: the cluster also serves the
|
|
367
|
+
* package's frontend on it (`https://host`, no port; never a name under the
|
|
368
|
+
* apps domain or the cluster's rp-id), and the consent the passkey signs
|
|
369
|
+
* names it (`{ origin, rpId, served: true }`). Further refusals:
|
|
370
|
+
* {@link NotServing} (the cluster serves no frontends),
|
|
371
|
+
* {@link ClusterNotUpgraded} (a node of the cluster is on an older release),
|
|
372
|
+
* {@link QuotaExceeded} for the served limits (4 per package, 64 per
|
|
373
|
+
* cluster), {@link OriginTaken} when the origin is held with the other
|
|
374
|
+
* `served` (remove it first). Serving it to browsers also needs the
|
|
375
|
+
* certificate and route Calimero Cloud sets up for the domain.
|
|
340
376
|
*/
|
|
341
377
|
add(pkg: string, origin: string, passkey?: PasskeyProvider, options?: {
|
|
342
378
|
rpId?: string;
|
|
379
|
+
served?: boolean;
|
|
343
380
|
}): Promise<PackageOriginAdded>;
|
|
344
381
|
/**
|
|
345
382
|
* Remove `origin` from `pkg`, approved with `passkey` (`__remove_origin`).
|
|
@@ -347,6 +384,22 @@ export interface PackageOrigins {
|
|
|
347
384
|
*/
|
|
348
385
|
remove(pkg: string, origin: string, passkey?: PasskeyProvider): Promise<PackageOriginRemoved>;
|
|
349
386
|
}
|
|
387
|
+
/** One served origin (custom domain) of the cluster, as `GET /ops/served-origins` lists it. */
|
|
388
|
+
export interface ServedOrigin {
|
|
389
|
+
/** `https://host`. */
|
|
390
|
+
origin: string;
|
|
391
|
+
/** The origin's host, the name a certificate and a route are for. */
|
|
392
|
+
host: string;
|
|
393
|
+
/** The package's app-host label (`{label}.{apps domain}`); the listing names no package. */
|
|
394
|
+
label: string;
|
|
395
|
+
addedAt: string;
|
|
396
|
+
}
|
|
397
|
+
/** `GET /ops/served-origins`: every served origin the cluster's log holds. Operator token. */
|
|
398
|
+
export interface ServedOrigins {
|
|
399
|
+
/** This node had caught up with the system leader. */
|
|
400
|
+
fresh: boolean;
|
|
401
|
+
origins: ServedOrigin[];
|
|
402
|
+
}
|
|
350
403
|
/**
|
|
351
404
|
* Where a sign-up or sign-in says it runs. By default the page's origin
|
|
352
405
|
* (`window.location.origin`) when it is not the origin of a node the client
|
|
@@ -610,6 +663,41 @@ export declare class CalimeroClient {
|
|
|
610
663
|
removePasskey(credentialId: string, passkey: PasskeyProvider): Promise<void>;
|
|
611
664
|
/** Name one of the account's passkeys (a device label); `''` clears the name. */
|
|
612
665
|
labelPasskey(credentialId: string, label: string): Promise<void>;
|
|
666
|
+
/**
|
|
667
|
+
* Make the account's recovery code (replacing any it had), approved with
|
|
668
|
+
* `passkey` (`412 CONFIRM_REQUIRED`). Answers the code, once: show it to
|
|
669
|
+
* the person to keep offline; the node keeps only its public key. A passkey
|
|
670
|
+
* session on the cluster's own origin only (never an API key or a
|
|
671
|
+
* package-bound session).
|
|
672
|
+
*/
|
|
673
|
+
createRecoveryCode(passkey: PasskeyProvider): Promise<string>;
|
|
674
|
+
/** Remove the account's recovery code, approved with `passkey`. */
|
|
675
|
+
removeRecoveryCode(passkey: PasskeyProvider): Promise<void>;
|
|
676
|
+
/**
|
|
677
|
+
* Signed out: start recovering the account `code` names. `passkey` makes a
|
|
678
|
+
* new passkey for it (the browser's create prompt, user verified); the
|
|
679
|
+
* node spends the code and keeps the passkey as pending. Nothing is added
|
|
680
|
+
* and no session opens: finish with {@link finishAccountRecovery} at
|
|
681
|
+
* `readyAt`. A code the cluster does not hold (mistyped, replaced or
|
|
682
|
+
* spent) is {@link WrongRecoveryCode}; an account with a recovery already
|
|
683
|
+
* under way `409 RECOVERY_PENDING`.
|
|
684
|
+
*/
|
|
685
|
+
startAccountRecovery(code: string, passkey: PasskeyProvider): Promise<AccountRecovery>;
|
|
686
|
+
/**
|
|
687
|
+
* Cancel the recovery of the signed-in account under way, approved with
|
|
688
|
+
* `passkey` (one the account already has). The code stays spent: make a
|
|
689
|
+
* new one.
|
|
690
|
+
*/
|
|
691
|
+
cancelAccountRecovery(passkey: PasskeyProvider): Promise<void>;
|
|
692
|
+
/**
|
|
693
|
+
* Signed out, once the delay passed: finish the recovery with the passkey
|
|
694
|
+
* it registered (`passkey` signs the node's sign-in challenge). The passkey
|
|
695
|
+
* joins the account, every other session of the account ends, and this
|
|
696
|
+
* client is signed in. `accountId` (from the start) lets the node refuse
|
|
697
|
+
* early and offer only that passkey; before `readyAt` it is
|
|
698
|
+
* {@link RecoveryNotReady}, with no recovery under way {@link NotFound}.
|
|
699
|
+
*/
|
|
700
|
+
finishAccountRecovery(passkey: PasskeyProvider, accountId?: string): Promise<CalimeroSession>;
|
|
613
701
|
/** What this account uses (apps, bundle bytes, API keys, owned orgs), with the cluster's quotas. */
|
|
614
702
|
usage(): Promise<Record<string, unknown>>;
|
|
615
703
|
/**
|
|
@@ -981,6 +1069,12 @@ export declare class CalimeroClient {
|
|
|
981
1069
|
opsApps(page?: PageOptions): Promise<OpsAppsReport>;
|
|
982
1070
|
/** `GET /ops/orgs`: each organization's approved releases. Operator token. */
|
|
983
1071
|
opsOrgs(page?: PageOptions): Promise<OpsOrgsReport>;
|
|
1072
|
+
/**
|
|
1073
|
+
* `GET /ops/served-origins`: every served origin (custom domain) the
|
|
1074
|
+
* cluster's log holds, with its package's label and no package name or
|
|
1075
|
+
* account. Operator token.
|
|
1076
|
+
*/
|
|
1077
|
+
opsServedOrigins(): Promise<ServedOrigins>;
|
|
984
1078
|
/**
|
|
985
1079
|
* Announce when work on images older than `version` ends: from `after` on,
|
|
986
1080
|
* a scope that has not approved it (or newer) starts no new work. Operator
|
package/dist/cloud-v2/client.js
CHANGED
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
import { SealedTransportError, createSealedFetch } from '../sealed/sealed.js';
|
|
13
13
|
import { fetchAttestedKey } from './attestation.js';
|
|
14
14
|
import { DEFAULT_DIRECTORY, orderNodes, readDirectory } from './directory.js';
|
|
15
|
-
import { CalimeroError, ConfirmCancelled, ConfirmRequired, LoginRequired, OriginNotRegistered, UnavailableError, WrongNode, errorFrom, } from './errors.js';
|
|
15
|
+
import { CalimeroError, ConfirmCancelled, ConfirmRequired, LoginRequired, OriginNotRegistered, UnavailableError, WrongNode, WrongRecoveryCode, errorFrom, } from './errors.js';
|
|
16
16
|
import { b64url, fromB64url } from './passkey.js';
|
|
17
17
|
import { signRecovery } from './recovery.js';
|
|
18
18
|
import { confirmationCode, pageQuery, pendingApprovalsFrom, } from './approvals.js';
|
|
19
|
-
export { AppError, ArgsTooLarge, BadOrigin, CalimeroError, ConfirmCancelled, ConfirmRequired, IdempotencyMismatch, LoginRequired, ConsentStale, NotFound, OriginNotRegistered, OriginTaken, QuotaExceeded, ReleaseDeadlineError, SignUpRefused, TrapError, UnavailableError, WrongNode, errorFrom, } from './errors.js';
|
|
19
|
+
export { AppError, ArgsTooLarge, BadOrigin, CalimeroError, ConfirmCancelled, ConfirmRequired, IdempotencyMismatch, LoginRequired, ConsentStale, NotFound, OriginNotRegistered, OriginTaken, QuotaExceeded, RecoveryNotReady, ReleaseDeadlineError, SignUpRefused, TrapError, UnavailableError, WrongNode, WrongRecoveryCode, errorFrom, } from './errors.js';
|
|
20
20
|
/** A deployer's key, as `GET /deployers` lists it and `DELETE /deployers/{key}` takes it. */
|
|
21
21
|
export function deployerKey(deployer) {
|
|
22
22
|
return 'account' in deployer ? `account:${deployer.account}` : `org:${deployer.org}`;
|
|
@@ -151,8 +151,10 @@ export function retryDelayMs(retry, options) {
|
|
|
151
151
|
* before it spends the challenge or the refresh token (core #4774).
|
|
152
152
|
*/
|
|
153
153
|
function ceremony(path) {
|
|
154
|
-
return path === 'auth/refresh' || path.startsWith('auth/passkey/');
|
|
154
|
+
return path === 'auth/refresh' || path.startsWith('auth/passkey/') || RECOVERY_CEREMONIES.has(path);
|
|
155
155
|
}
|
|
156
|
+
/** The signed-out halves of an account recovery: a `401` there is the code's, not a session's. */
|
|
157
|
+
const RECOVERY_CEREMONIES = new Set(['auth/recovery/begin', 'auth/recovery/start', 'auth/recovery/finish']);
|
|
156
158
|
export class CalimeroClient {
|
|
157
159
|
/**
|
|
158
160
|
* A client for the Calimero Cloud cluster named `cluster`: its node list read
|
|
@@ -198,7 +200,14 @@ export class CalimeroClient {
|
|
|
198
200
|
const { origins } = await this.get(`package-origins/${seg(pkg)}`);
|
|
199
201
|
return origins ?? [];
|
|
200
202
|
},
|
|
201
|
-
add: (pkg, origin, passkey, options = {}) => this.confirmed('POST', `package-origins/${seg(pkg)}`,
|
|
203
|
+
add: (pkg, origin, passkey, options = {}) => this.confirmed('POST', `package-origins/${seg(pkg)}`,
|
|
204
|
+
// Only the fields set: the node refuses unknown ones, and one that
|
|
205
|
+
// predates served origins takes a plain add unchanged.
|
|
206
|
+
{
|
|
207
|
+
origin,
|
|
208
|
+
...(options.rpId === undefined ? {} : { rpId: options.rpId }),
|
|
209
|
+
...(options.served ? { served: true } : {}),
|
|
210
|
+
}, passkey),
|
|
202
211
|
remove: (pkg, origin, passkey) => this.confirmed('DELETE', `package-origins/${seg(pkg)}`, { origin }, passkey),
|
|
203
212
|
};
|
|
204
213
|
const trim = (url) => url.replace(/\/+$/, '');
|
|
@@ -608,6 +617,69 @@ export class CalimeroClient {
|
|
|
608
617
|
async labelPasskey(credentialId, label) {
|
|
609
618
|
await this.post(`auth/passkeys/${seg(credentialId)}`, { label });
|
|
610
619
|
}
|
|
620
|
+
// ---------------------------------------------------------------- account recovery
|
|
621
|
+
//
|
|
622
|
+
// core #4844 (`docs/specs/account-recovery.md`): a recovery code, made with
|
|
623
|
+
// a passkey and shown once, lets someone who lost every passkey register a
|
|
624
|
+
// new one; it is added, and the account signed in, 72 hours later unless a
|
|
625
|
+
// passkey the account still has cancels it first.
|
|
626
|
+
/**
|
|
627
|
+
* Make the account's recovery code (replacing any it had), approved with
|
|
628
|
+
* `passkey` (`412 CONFIRM_REQUIRED`). Answers the code, once: show it to
|
|
629
|
+
* the person to keep offline; the node keeps only its public key. A passkey
|
|
630
|
+
* session on the cluster's own origin only (never an API key or a
|
|
631
|
+
* package-bound session).
|
|
632
|
+
*/
|
|
633
|
+
async createRecoveryCode(passkey) {
|
|
634
|
+
const { code } = await this.postConfirmed('auth/recovery', {}, passkey);
|
|
635
|
+
return code;
|
|
636
|
+
}
|
|
637
|
+
/** Remove the account's recovery code, approved with `passkey`. */
|
|
638
|
+
async removeRecoveryCode(passkey) {
|
|
639
|
+
await this.deleteConfirmed('auth/recovery', passkey);
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* Signed out: start recovering the account `code` names. `passkey` makes a
|
|
643
|
+
* new passkey for it (the browser's create prompt, user verified); the
|
|
644
|
+
* node spends the code and keeps the passkey as pending. Nothing is added
|
|
645
|
+
* and no session opens: finish with {@link finishAccountRecovery} at
|
|
646
|
+
* `readyAt`. A code the cluster does not hold (mistyped, replaced or
|
|
647
|
+
* spent) is {@link WrongRecoveryCode}; an account with a recovery already
|
|
648
|
+
* under way `409 RECOVERY_PENDING`.
|
|
649
|
+
*/
|
|
650
|
+
async startAccountRecovery(code, passkey) {
|
|
651
|
+
try {
|
|
652
|
+
const begin = await this.post('auth/recovery/begin', { code });
|
|
653
|
+
const registration = await passkey.create(begin.options);
|
|
654
|
+
return await this.post('auth/recovery/start', { challengeId: begin.challengeId, code, registration });
|
|
655
|
+
}
|
|
656
|
+
catch (error) {
|
|
657
|
+
if (error instanceof LoginRequired)
|
|
658
|
+
throw new WrongRecoveryCode(error.message.replace(/^401 UNAUTHENTICATED: /, ''), error.details);
|
|
659
|
+
throw error;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* Cancel the recovery of the signed-in account under way, approved with
|
|
664
|
+
* `passkey` (one the account already has). The code stays spent: make a
|
|
665
|
+
* new one.
|
|
666
|
+
*/
|
|
667
|
+
async cancelAccountRecovery(passkey) {
|
|
668
|
+
await this.postConfirmed('auth/recovery/cancel', {}, passkey);
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* Signed out, once the delay passed: finish the recovery with the passkey
|
|
672
|
+
* it registered (`passkey` signs the node's sign-in challenge). The passkey
|
|
673
|
+
* joins the account, every other session of the account ends, and this
|
|
674
|
+
* client is signed in. `accountId` (from the start) lets the node refuse
|
|
675
|
+
* early and offer only that passkey; before `readyAt` it is
|
|
676
|
+
* {@link RecoveryNotReady}, with no recovery under way {@link NotFound}.
|
|
677
|
+
*/
|
|
678
|
+
async finishAccountRecovery(passkey, accountId) {
|
|
679
|
+
const session = await this.postConfirmed('auth/recovery/finish', accountId ? { accountId } : {}, passkey);
|
|
680
|
+
this.useSession(session);
|
|
681
|
+
return session;
|
|
682
|
+
}
|
|
611
683
|
/** What this account uses (apps, bundle bytes, API keys, owned orgs), with the cluster's quotas. */
|
|
612
684
|
usage() {
|
|
613
685
|
return this.get('auth/usage');
|
|
@@ -1176,6 +1248,14 @@ export class CalimeroClient {
|
|
|
1176
1248
|
opsOrgs(page = {}) {
|
|
1177
1249
|
return this.get(`ops/orgs${pageQuery(page)}`);
|
|
1178
1250
|
}
|
|
1251
|
+
/**
|
|
1252
|
+
* `GET /ops/served-origins`: every served origin (custom domain) the
|
|
1253
|
+
* cluster's log holds, with its package's label and no package name or
|
|
1254
|
+
* account. Operator token.
|
|
1255
|
+
*/
|
|
1256
|
+
opsServedOrigins() {
|
|
1257
|
+
return this.get('ops/served-origins');
|
|
1258
|
+
}
|
|
1179
1259
|
/**
|
|
1180
1260
|
* Announce when work on images older than `version` ends: from `after` on,
|
|
1181
1261
|
* a scope that has not approved it (or newer) starts no new work. Operator
|
|
@@ -117,15 +117,58 @@ export declare class OriginNotRegistered extends CalimeroError {
|
|
|
117
117
|
* `400 BAD_ORIGIN` or `400 BAD_RP_ID`: the node does not accept the origin a
|
|
118
118
|
* package's manager tried to register (it must be a bare web origin,
|
|
119
119
|
* `scheme://host[:port]`), or the relying-party id given for it (which must
|
|
120
|
-
* fit the origin's host). `code` says which.
|
|
120
|
+
* fit the origin's host). `code` says which. A served origin (`served: true`)
|
|
121
|
+
* must also be `https://host` with no port, and not a name under the
|
|
122
|
+
* cluster's apps domain or its rp-id.
|
|
121
123
|
*/
|
|
122
124
|
export declare class BadOrigin extends CalimeroError {
|
|
123
125
|
constructor(code: 'BAD_ORIGIN' | 'BAD_RP_ID', message: string, details?: Record<string, unknown>);
|
|
124
126
|
}
|
|
125
|
-
/**
|
|
127
|
+
/**
|
|
128
|
+
* `409 ORIGIN_TAKEN`: the origin is registered already (for another package,
|
|
129
|
+
* or for this one with the other `served`: remove it first), or it is one of
|
|
130
|
+
* the cluster's own (a node's API host, a cluster origin, a frontend it
|
|
131
|
+
* serves).
|
|
132
|
+
*/
|
|
126
133
|
export declare class OriginTaken extends CalimeroError {
|
|
127
134
|
constructor(message: string, details?: Record<string, unknown>);
|
|
128
135
|
}
|
|
136
|
+
/**
|
|
137
|
+
* `400 NOT_SERVING`: a served origin (a custom domain, `served: true`) was
|
|
138
|
+
* asked of a cluster that serves no frontends (merod without
|
|
139
|
+
* `--apps-domain`). Register the origin unserved, or use a cluster that
|
|
140
|
+
* serves them.
|
|
141
|
+
*/
|
|
142
|
+
export declare class NotServing extends CalimeroError {
|
|
143
|
+
constructor(message: string, details?: Record<string, unknown>);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* `409 CLUSTER_NOT_UPGRADED`: the change needs every node of the cluster
|
|
147
|
+
* (replicas, voters and learners) on the node's release or later, and one
|
|
148
|
+
* is not yet; for instance adding a served origin. Retry once the cluster is
|
|
149
|
+
* upgraded.
|
|
150
|
+
*/
|
|
151
|
+
export declare class ClusterNotUpgraded extends CalimeroError {
|
|
152
|
+
constructor(message: string, details?: Record<string, unknown>);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* `409 RECOVERY_NOT_READY`: a recovery (an account's or an organization's)
|
|
156
|
+
* may finish only once its 72-hour delay has passed. `readyAt` is when it may
|
|
157
|
+
* (Unix seconds), when the node said.
|
|
158
|
+
*/
|
|
159
|
+
export declare class RecoveryNotReady extends CalimeroError {
|
|
160
|
+
readonly readyAt: number | undefined;
|
|
161
|
+
constructor(message: string, details?: Record<string, unknown>);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* The recovery code is not one the cluster holds: mistyped, replaced by a
|
|
165
|
+
* newer one, or spent by a recovery that started (whether it finished or was
|
|
166
|
+
* cancelled). The node answers it `401`; a recovery is signed out, so it is
|
|
167
|
+
* this error, not {@link LoginRequired}.
|
|
168
|
+
*/
|
|
169
|
+
export declare class WrongRecoveryCode extends CalimeroError {
|
|
170
|
+
constructor(message: string, details?: Record<string, unknown>);
|
|
171
|
+
}
|
|
129
172
|
/** Why a sign-up was refused ({@link SignUpRefused.reason}), read from what the node said. */
|
|
130
173
|
export type SignUpRefusal = 'invite-only' | 'closed' | 'unknown-invite' | 'expired-invite' | 'org-gone' | 'other';
|
|
131
174
|
/**
|
|
@@ -146,7 +189,10 @@ export declare class SignUpRefused extends CalimeroError {
|
|
|
146
189
|
readonly reason: SignUpRefusal;
|
|
147
190
|
constructor(message: string, details?: Record<string, unknown>);
|
|
148
191
|
}
|
|
149
|
-
/**
|
|
192
|
+
/**
|
|
193
|
+
* `429 QUOTA_EXCEEDED`: the caller holds as many of something (origins,
|
|
194
|
+
* served origins per package or per cluster, blobs, ...) as it may.
|
|
195
|
+
*/
|
|
150
196
|
export declare class QuotaExceeded extends CalimeroError {
|
|
151
197
|
constructor(message: string, details?: Record<string, unknown>);
|
|
152
198
|
}
|
package/dist/cloud-v2/errors.js
CHANGED
|
@@ -150,7 +150,9 @@ export class OriginNotRegistered extends CalimeroError {
|
|
|
150
150
|
* `400 BAD_ORIGIN` or `400 BAD_RP_ID`: the node does not accept the origin a
|
|
151
151
|
* package's manager tried to register (it must be a bare web origin,
|
|
152
152
|
* `scheme://host[:port]`), or the relying-party id given for it (which must
|
|
153
|
-
* fit the origin's host). `code` says which.
|
|
153
|
+
* fit the origin's host). `code` says which. A served origin (`served: true`)
|
|
154
|
+
* must also be `https://host` with no port, and not a name under the
|
|
155
|
+
* cluster's apps domain or its rp-id.
|
|
154
156
|
*/
|
|
155
157
|
export class BadOrigin extends CalimeroError {
|
|
156
158
|
constructor(code, message, details = {}) {
|
|
@@ -158,13 +160,66 @@ export class BadOrigin extends CalimeroError {
|
|
|
158
160
|
this.name = 'BadOrigin';
|
|
159
161
|
}
|
|
160
162
|
}
|
|
161
|
-
/**
|
|
163
|
+
/**
|
|
164
|
+
* `409 ORIGIN_TAKEN`: the origin is registered already (for another package,
|
|
165
|
+
* or for this one with the other `served`: remove it first), or it is one of
|
|
166
|
+
* the cluster's own (a node's API host, a cluster origin, a frontend it
|
|
167
|
+
* serves).
|
|
168
|
+
*/
|
|
162
169
|
export class OriginTaken extends CalimeroError {
|
|
163
170
|
constructor(message, details = {}) {
|
|
164
171
|
super(409, 'ORIGIN_TAKEN', message, details);
|
|
165
172
|
this.name = 'OriginTaken';
|
|
166
173
|
}
|
|
167
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* `400 NOT_SERVING`: a served origin (a custom domain, `served: true`) was
|
|
177
|
+
* asked of a cluster that serves no frontends (merod without
|
|
178
|
+
* `--apps-domain`). Register the origin unserved, or use a cluster that
|
|
179
|
+
* serves them.
|
|
180
|
+
*/
|
|
181
|
+
export class NotServing extends CalimeroError {
|
|
182
|
+
constructor(message, details = {}) {
|
|
183
|
+
super(400, 'NOT_SERVING', message, details);
|
|
184
|
+
this.name = 'NotServing';
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* `409 CLUSTER_NOT_UPGRADED`: the change needs every node of the cluster
|
|
189
|
+
* (replicas, voters and learners) on the node's release or later, and one
|
|
190
|
+
* is not yet; for instance adding a served origin. Retry once the cluster is
|
|
191
|
+
* upgraded.
|
|
192
|
+
*/
|
|
193
|
+
export class ClusterNotUpgraded extends CalimeroError {
|
|
194
|
+
constructor(message, details = {}) {
|
|
195
|
+
super(409, 'CLUSTER_NOT_UPGRADED', message, details);
|
|
196
|
+
this.name = 'ClusterNotUpgraded';
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* `409 RECOVERY_NOT_READY`: a recovery (an account's or an organization's)
|
|
201
|
+
* may finish only once its 72-hour delay has passed. `readyAt` is when it may
|
|
202
|
+
* (Unix seconds), when the node said.
|
|
203
|
+
*/
|
|
204
|
+
export class RecoveryNotReady extends CalimeroError {
|
|
205
|
+
constructor(message, details = {}) {
|
|
206
|
+
super(409, 'RECOVERY_NOT_READY', message, details);
|
|
207
|
+
this.name = 'RecoveryNotReady';
|
|
208
|
+
this.readyAt = typeof details.readyAt === 'number' ? details.readyAt : undefined;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* The recovery code is not one the cluster holds: mistyped, replaced by a
|
|
213
|
+
* newer one, or spent by a recovery that started (whether it finished or was
|
|
214
|
+
* cancelled). The node answers it `401`; a recovery is signed out, so it is
|
|
215
|
+
* this error, not {@link LoginRequired}.
|
|
216
|
+
*/
|
|
217
|
+
export class WrongRecoveryCode extends CalimeroError {
|
|
218
|
+
constructor(message, details = {}) {
|
|
219
|
+
super(401, 'UNAUTHENTICATED', message || 'unknown or used recovery code', details);
|
|
220
|
+
this.name = 'WrongRecoveryCode';
|
|
221
|
+
}
|
|
222
|
+
}
|
|
168
223
|
/**
|
|
169
224
|
* `403 SIGN_UP_REFUSED`: the cluster's sign-up policy does not take this
|
|
170
225
|
* sign-up (core `SystemState::admits`), answered by `register/begin` before a
|
|
@@ -199,7 +254,10 @@ function signUpRefusal(message) {
|
|
|
199
254
|
return 'org-gone';
|
|
200
255
|
return 'other';
|
|
201
256
|
}
|
|
202
|
-
/**
|
|
257
|
+
/**
|
|
258
|
+
* `429 QUOTA_EXCEEDED`: the caller holds as many of something (origins,
|
|
259
|
+
* served origins per package or per cluster, blobs, ...) as it may.
|
|
260
|
+
*/
|
|
203
261
|
export class QuotaExceeded extends CalimeroError {
|
|
204
262
|
constructor(message, details = {}) {
|
|
205
263
|
super(429, 'QUOTA_EXCEEDED', message, details);
|
|
@@ -297,8 +355,14 @@ export function errorFrom(status, body, retryAfterHeader) {
|
|
|
297
355
|
return new BadOrigin(code, message, details);
|
|
298
356
|
case '409 ORIGIN_TAKEN':
|
|
299
357
|
return new OriginTaken(message, details);
|
|
358
|
+
case '400 NOT_SERVING':
|
|
359
|
+
return new NotServing(message, details);
|
|
360
|
+
case '409 CLUSTER_NOT_UPGRADED':
|
|
361
|
+
return new ClusterNotUpgraded(message, details);
|
|
300
362
|
case '429 QUOTA_EXCEEDED':
|
|
301
363
|
return new QuotaExceeded(message, details);
|
|
364
|
+
case '409 RECOVERY_NOT_READY':
|
|
365
|
+
return new RecoveryNotReady(message, details);
|
|
302
366
|
case '403 SIGN_UP_REFUSED':
|
|
303
367
|
return new SignUpRefused(message, details);
|
|
304
368
|
case '412 CONFIRM_REQUIRED':
|
package/dist/cloud-v2/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export { CalimeroClient, deployerKey, frontendManifest, pageDeployment } from './client.js';
|
|
2
2
|
export { DEFAULT_DIRECTORY, DirectoryError } from './directory.js';
|
|
3
3
|
export type { DirectoryFailure } from './directory.js';
|
|
4
|
-
export { AppError, ArgsTooLarge, BadOrigin, CalimeroError, ConfirmCancelled, ConfirmRequired, IdempotencyMismatch, LoginRequired, ConsentStale, NotFound, OriginNotRegistered, OriginTaken, QuotaExceeded, ReleaseDeadlineError, SignUpRefused, TrapError, UnavailableError, WrongNode, errorFrom, } from './errors.js';
|
|
4
|
+
export { AppError, ArgsTooLarge, BadOrigin, CalimeroError, ClusterNotUpgraded, ConfirmCancelled, ConfirmRequired, IdempotencyMismatch, LoginRequired, ConsentStale, NotFound, NotServing, OriginNotRegistered, OriginTaken, QuotaExceeded, RecoveryNotReady, ReleaseDeadlineError, SignUpRefused, TrapError, UnavailableError, WrongNode, WrongRecoveryCode, errorFrom, } from './errors.js';
|
|
5
5
|
export type { Committed, SignUpRefusal } from './errors.js';
|
|
6
|
-
export type { AppInfo, AppXcalls, BlobContent, BlobInfo, DeadLetter, Deployer, DeployerGrant, DeployersInfo, DeploymentInfo, DeploymentOffer, DeploymentOrgs, FrontendManifest, MeInfo, PackageOrigin, PackageOriginAdded, PackageOriginRemoved, PackageOrigins, SignInOptions, SignUpOptions, SignUpPolicy, PublicDeployment, CallResult, CalimeroClientOptions, CalimeroConnectOptions, CloudEvent, CalimeroSession, PackageInfo, PackageInstalled, CloudRetryOptions, OrgInfo, OrgRecovery, RecoveryTimes, OrgUpgradeTarget, PresenceEntry, UpgradeRun, ViewResult, } from './client.js';
|
|
6
|
+
export type { AppInfo, AppXcalls, BlobContent, BlobInfo, DeadLetter, Deployer, DeployerGrant, DeployersInfo, DeploymentInfo, DeploymentOffer, DeploymentOrgs, FrontendManifest, MeInfo, PackageOrigin, PackageOriginAdded, PackageOriginRemoved, PackageOrigins, ServedOrigin, ServedOrigins, SignInOptions, AccountRecovery, SignUpOptions, SignUpPolicy, PublicDeployment, CallResult, CalimeroClientOptions, CalimeroConnectOptions, CloudEvent, CalimeroSession, PackageInfo, PackageInstalled, CloudRetryOptions, OrgInfo, OrgRecovery, RecoveryTimes, OrgUpgradeTarget, PresenceEntry, UpgradeRun, ViewResult, } from './client.js';
|
|
7
7
|
export { claimedRelease, fetchAttestedKey, freshCollateral, MOCK_QUOTE_HEADER } from './attestation.js';
|
|
8
8
|
export type { AttestationDoc, CloudPolicy, CloudReleasePolicy } from './attestation.js';
|
|
9
9
|
export { browserPasskey, b64url, fromB64url } from './passkey.js';
|
package/dist/cloud-v2/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { CalimeroClient, deployerKey, frontendManifest, pageDeployment } from './client.js';
|
|
2
2
|
export { DEFAULT_DIRECTORY, DirectoryError } from './directory.js';
|
|
3
|
-
export { AppError, ArgsTooLarge, BadOrigin, CalimeroError, ConfirmCancelled, ConfirmRequired, IdempotencyMismatch, LoginRequired, ConsentStale, NotFound, OriginNotRegistered, OriginTaken, QuotaExceeded, ReleaseDeadlineError, SignUpRefused, TrapError, UnavailableError, WrongNode, errorFrom, } from './errors.js';
|
|
3
|
+
export { AppError, ArgsTooLarge, BadOrigin, CalimeroError, ClusterNotUpgraded, ConfirmCancelled, ConfirmRequired, IdempotencyMismatch, LoginRequired, ConsentStale, NotFound, NotServing, OriginNotRegistered, OriginTaken, QuotaExceeded, RecoveryNotReady, ReleaseDeadlineError, SignUpRefused, TrapError, UnavailableError, WrongNode, WrongRecoveryCode, errorFrom, } from './errors.js';
|
|
4
4
|
export { claimedRelease, fetchAttestedKey, freshCollateral, MOCK_QUOTE_HEADER } from './attestation.js';
|
|
5
5
|
export { browserPasskey, b64url, fromB64url } from './passkey.js';
|
|
6
6
|
export { MAX_RECOVERY_NONCE_BYTES, RECOVERY_DOMAIN, newRecoverySeed, parseRecoverySeed, recoveryMessage, recoveryPublicKey, recoverySeedText, signRecovery, } from './recovery.js';
|