@calimero-network/mero-js 29.5.0 → 29.7.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 CHANGED
@@ -99,7 +99,7 @@ Pinned measurements go through `policy.verifyQuote` (`createQuoteVerifier`).
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`.
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`).
103
103
  - **Packages**: `installPackage`, `uploadPackage`, `packages`, `package`, `uninstallPackage`; `uploadBundle` (raw WASM, development clusters only).
104
104
  - **Apps**: `createApp`, `listApps`, `getApp`, `deleteApp`, `setAccess`, `setAppMetadata`, `appStorage`, `appAbi`, `upgradeApp`, `transferApp`.
105
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.
@@ -107,10 +107,10 @@ Pinned measurements go through `policy.verifyQuote` (`createQuoteVerifier`).
107
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.
108
108
  - **Owner decisions** (passkey approval, never from an app's frontend): `upgradeOrg`, `upgradeRun`, `retryUpgradeRun`, `approveRelease`, `approveOutbound`, `bindPublisher`, `upgradePublished`.
109
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/).
110
- - **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`.
111
111
  - **Any route**: `get`, `post`, `put`, `delete`; `postConfirmed` and `deleteConfirmed` answer a `412 CONFIRM_REQUIRED` with a passkey.
112
112
 
113
- Refusals are typed (`LoginRequired`, `WrongNode`, `NotFound`, `ConfirmRequired`, `ConfirmCancelled`,
113
+ Refusals are typed (`LoginRequired`, `PasskeyUnknownHere`, `WrongNode`, `NotFound`, `ConfirmRequired`, `ConfirmCancelled`,
114
114
  `ArgsTooLarge`, `IdempotencyMismatch`, `ReleaseDeadlineError`, `ConsentStale`, `AppError`, `TrapError`,
115
115
  `UnavailableError`, `OriginNotRegistered`, `BadOrigin`, `OriginTaken`, `QuotaExceeded`),
116
116
  all extending `CalimeroError` with the node's `status` and `code`. A `401` once
@@ -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, RecoveryNotReady, ReleaseDeadlineError, SignUpRefused, TrapError, UnavailableError, WrongNode, WrongRecoveryCode, errorFrom, } from './errors.js';
15
+ export { AppError, ArgsTooLarge, BadOrigin, CalimeroError, ConfirmCancelled, ConfirmRequired, IdempotencyMismatch, LoginRequired, ConsentStale, NotFound, OriginNotRegistered, OriginTaken, PasskeyUnknownHere, 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;
@@ -331,6 +331,12 @@ export interface PackageOrigin {
331
331
  /** The account that registered it. */
332
332
  addedBy: string;
333
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;
334
340
  }
335
341
  /** What registering an origin answers. */
336
342
  export interface PackageOriginAdded extends PackageOrigin {
@@ -356,9 +362,21 @@ export interface PackageOrigins {
356
362
  * caller as {@link ConfirmRequired}). `rpId` defaults to the node's choice
357
363
  * for the origin (its host). Refusals: {@link BadOrigin} (`BAD_ORIGIN`,
358
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.
359
376
  */
360
377
  add(pkg: string, origin: string, passkey?: PasskeyProvider, options?: {
361
378
  rpId?: string;
379
+ served?: boolean;
362
380
  }): Promise<PackageOriginAdded>;
363
381
  /**
364
382
  * Remove `origin` from `pkg`, approved with `passkey` (`__remove_origin`).
@@ -366,6 +384,22 @@ export interface PackageOrigins {
366
384
  */
367
385
  remove(pkg: string, origin: string, passkey?: PasskeyProvider): Promise<PackageOriginRemoved>;
368
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
+ }
369
403
  /**
370
404
  * Where a sign-up or sign-in says it runs. By default the page's origin
371
405
  * (`window.location.origin`) when it is not the origin of a node the client
@@ -595,7 +629,8 @@ export declare class CalimeroClient {
595
629
  * cluster's ({@link SignInOptions}), the assertion is made for that
596
630
  * origin's relying-party id, as the node answers it, and the session is
597
631
  * bound to the origin's package; an unregistered origin is refused with
598
- * {@link OriginNotRegistered}.
632
+ * {@link OriginNotRegistered}. A passkey this cluster does not know (made
633
+ * on another cluster, or removed) is refused with {@link PasskeyUnknownHere}.
599
634
  */
600
635
  signIn(passkey: PasskeyProvider, options?: SignInOptions): Promise<CalimeroSession>;
601
636
  /**
@@ -1035,6 +1070,12 @@ export declare class CalimeroClient {
1035
1070
  opsApps(page?: PageOptions): Promise<OpsAppsReport>;
1036
1071
  /** `GET /ops/orgs`: each organization's approved releases. Operator token. */
1037
1072
  opsOrgs(page?: PageOptions): Promise<OpsOrgsReport>;
1073
+ /**
1074
+ * `GET /ops/served-origins`: every served origin (custom domain) the
1075
+ * cluster's log holds, with its package's label and no package name or
1076
+ * account. Operator token.
1077
+ */
1078
+ opsServedOrigins(): Promise<ServedOrigins>;
1038
1079
  /**
1039
1080
  * Announce when work on images older than `version` ends: from `after` on,
1040
1081
  * a scope that has not approved it (or newer) starts no new work. Operator
@@ -16,7 +16,7 @@ import { CalimeroError, ConfirmCancelled, ConfirmRequired, LoginRequired, Origin
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, RecoveryNotReady, ReleaseDeadlineError, SignUpRefused, TrapError, UnavailableError, WrongNode, WrongRecoveryCode, errorFrom, } from './errors.js';
19
+ export { AppError, ArgsTooLarge, BadOrigin, CalimeroError, ConfirmCancelled, ConfirmRequired, IdempotencyMismatch, LoginRequired, ConsentStale, NotFound, OriginNotRegistered, OriginTaken, PasskeyUnknownHere, 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}`;
@@ -200,7 +200,14 @@ export class CalimeroClient {
200
200
  const { origins } = await this.get(`package-origins/${seg(pkg)}`);
201
201
  return origins ?? [];
202
202
  },
203
- add: (pkg, origin, passkey, options = {}) => this.confirmed('POST', `package-origins/${seg(pkg)}`, options.rpId === undefined ? { origin } : { origin, rpId: options.rpId }, passkey),
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),
204
211
  remove: (pkg, origin, passkey) => this.confirmed('DELETE', `package-origins/${seg(pkg)}`, { origin }, passkey),
205
212
  };
206
213
  const trim = (url) => url.replace(/\/+$/, '');
@@ -489,7 +496,8 @@ export class CalimeroClient {
489
496
  * cluster's ({@link SignInOptions}), the assertion is made for that
490
497
  * origin's relying-party id, as the node answers it, and the session is
491
498
  * bound to the origin's package; an unregistered origin is refused with
492
- * {@link OriginNotRegistered}.
499
+ * {@link OriginNotRegistered}. A passkey this cluster does not know (made
500
+ * on another cluster, or removed) is refused with {@link PasskeyUnknownHere}.
493
501
  */
494
502
  async signIn(passkey, options = {}) {
495
503
  const origin = this.pageOrigin(options);
@@ -1241,6 +1249,14 @@ export class CalimeroClient {
1241
1249
  opsOrgs(page = {}) {
1242
1250
  return this.get(`ops/orgs${pageQuery(page)}`);
1243
1251
  }
1252
+ /**
1253
+ * `GET /ops/served-origins`: every served origin (custom domain) the
1254
+ * cluster's log holds, with its package's label and no package name or
1255
+ * account. Operator token.
1256
+ */
1257
+ opsServedOrigins() {
1258
+ return this.get('ops/served-origins');
1259
+ }
1244
1260
  /**
1245
1261
  * Announce when work on images older than `version` ends: from `after` on,
1246
1262
  * a scope that has not approved it (or newer) starts no new work. Operator
@@ -34,6 +34,23 @@ export declare class CalimeroError extends Error {
34
34
  export declare class LoginRequired extends CalimeroError {
35
35
  constructor(message: string, details?: Record<string, unknown>);
36
36
  }
37
+ /**
38
+ * `401 PASSKEY_UNKNOWN_HERE`: a sign-in (or a confirmation) with a passkey no
39
+ * account of this cluster has. Accounts and passkeys are each cluster's own,
40
+ * while clusters may share one WebAuthn rp-id (every Calimero Cloud cluster
41
+ * uses `calimero.network`), so the browser offers a passkey made on another
42
+ * cluster here too; a passkey removed from its account answers the same.
43
+ *
44
+ * It is not a {@link LoginRequired}: the client does not refresh for it, and
45
+ * signing in again with the same passkey fails the same way. Offer to sign up
46
+ * on this cluster, or point the person to the app link for the cluster their
47
+ * account is on; the passkey's name in their password manager names that
48
+ * cluster (`alice · eu-shared-1`). The node does not say which cluster or
49
+ * account the passkey belongs to: it only knows its own.
50
+ */
51
+ export declare class PasskeyUnknownHere extends CalimeroError {
52
+ constructor(message: string, details?: Record<string, unknown>);
53
+ }
37
54
  /**
38
55
  * `421 WRONG_NODE`: this node runs a mero-tee release the account's owners have
39
56
  * not approved, so it neither issues nor takes the account's sessions. Use
@@ -117,15 +134,40 @@ export declare class OriginNotRegistered extends CalimeroError {
117
134
  * `400 BAD_ORIGIN` or `400 BAD_RP_ID`: the node does not accept the origin a
118
135
  * package's manager tried to register (it must be a bare web origin,
119
136
  * `scheme://host[:port]`), or the relying-party id given for it (which must
120
- * fit the origin's host). `code` says which.
137
+ * fit the origin's host). `code` says which. A served origin (`served: true`)
138
+ * must also be `https://host` with no port, and not a name under the
139
+ * cluster's apps domain or its rp-id.
121
140
  */
122
141
  export declare class BadOrigin extends CalimeroError {
123
142
  constructor(code: 'BAD_ORIGIN' | 'BAD_RP_ID', message: string, details?: Record<string, unknown>);
124
143
  }
125
- /** `409 ORIGIN_TAKEN`: the origin is registered already (for this package or another). */
144
+ /**
145
+ * `409 ORIGIN_TAKEN`: the origin is registered already (for another package,
146
+ * or for this one with the other `served`: remove it first), or it is one of
147
+ * the cluster's own (a node's API host, a cluster origin, a frontend it
148
+ * serves).
149
+ */
126
150
  export declare class OriginTaken extends CalimeroError {
127
151
  constructor(message: string, details?: Record<string, unknown>);
128
152
  }
153
+ /**
154
+ * `400 NOT_SERVING`: a served origin (a custom domain, `served: true`) was
155
+ * asked of a cluster that serves no frontends (merod without
156
+ * `--apps-domain`). Register the origin unserved, or use a cluster that
157
+ * serves them.
158
+ */
159
+ export declare class NotServing extends CalimeroError {
160
+ constructor(message: string, details?: Record<string, unknown>);
161
+ }
162
+ /**
163
+ * `409 CLUSTER_NOT_UPGRADED`: the change needs every node of the cluster
164
+ * (replicas, voters and learners) on the node's release or later, and one
165
+ * is not yet; for instance adding a served origin. Retry once the cluster is
166
+ * upgraded.
167
+ */
168
+ export declare class ClusterNotUpgraded extends CalimeroError {
169
+ constructor(message: string, details?: Record<string, unknown>);
170
+ }
129
171
  /**
130
172
  * `409 RECOVERY_NOT_READY`: a recovery (an account's or an organization's)
131
173
  * may finish only once its 72-hour delay has passed. `readyAt` is when it may
@@ -164,7 +206,10 @@ export declare class SignUpRefused extends CalimeroError {
164
206
  readonly reason: SignUpRefusal;
165
207
  constructor(message: string, details?: Record<string, unknown>);
166
208
  }
167
- /** `429 QUOTA_EXCEEDED`: the caller holds as many of something (origins, blobs, ...) as it may. */
209
+ /**
210
+ * `429 QUOTA_EXCEEDED`: the caller holds as many of something (origins,
211
+ * served origins per package or per cluster, blobs, ...) as it may.
212
+ */
168
213
  export declare class QuotaExceeded extends CalimeroError {
169
214
  constructor(message: string, details?: Record<string, unknown>);
170
215
  }
@@ -40,6 +40,26 @@ export class LoginRequired extends CalimeroError {
40
40
  this.name = 'LoginRequired';
41
41
  }
42
42
  }
43
+ /**
44
+ * `401 PASSKEY_UNKNOWN_HERE`: a sign-in (or a confirmation) with a passkey no
45
+ * account of this cluster has. Accounts and passkeys are each cluster's own,
46
+ * while clusters may share one WebAuthn rp-id (every Calimero Cloud cluster
47
+ * uses `calimero.network`), so the browser offers a passkey made on another
48
+ * cluster here too; a passkey removed from its account answers the same.
49
+ *
50
+ * It is not a {@link LoginRequired}: the client does not refresh for it, and
51
+ * signing in again with the same passkey fails the same way. Offer to sign up
52
+ * on this cluster, or point the person to the app link for the cluster their
53
+ * account is on; the passkey's name in their password manager names that
54
+ * cluster (`alice · eu-shared-1`). The node does not say which cluster or
55
+ * account the passkey belongs to: it only knows its own.
56
+ */
57
+ export class PasskeyUnknownHere extends CalimeroError {
58
+ constructor(message, details = {}) {
59
+ super(401, 'PASSKEY_UNKNOWN_HERE', message || 'this passkey belongs to another Calimero cluster or was removed from this one', details);
60
+ this.name = 'PasskeyUnknownHere';
61
+ }
62
+ }
43
63
  /**
44
64
  * `421 WRONG_NODE`: this node runs a mero-tee release the account's owners have
45
65
  * not approved, so it neither issues nor takes the account's sessions. Use
@@ -150,7 +170,9 @@ export class OriginNotRegistered extends CalimeroError {
150
170
  * `400 BAD_ORIGIN` or `400 BAD_RP_ID`: the node does not accept the origin a
151
171
  * package's manager tried to register (it must be a bare web origin,
152
172
  * `scheme://host[:port]`), or the relying-party id given for it (which must
153
- * fit the origin's host). `code` says which.
173
+ * fit the origin's host). `code` says which. A served origin (`served: true`)
174
+ * must also be `https://host` with no port, and not a name under the
175
+ * cluster's apps domain or its rp-id.
154
176
  */
155
177
  export class BadOrigin extends CalimeroError {
156
178
  constructor(code, message, details = {}) {
@@ -158,13 +180,42 @@ export class BadOrigin extends CalimeroError {
158
180
  this.name = 'BadOrigin';
159
181
  }
160
182
  }
161
- /** `409 ORIGIN_TAKEN`: the origin is registered already (for this package or another). */
183
+ /**
184
+ * `409 ORIGIN_TAKEN`: the origin is registered already (for another package,
185
+ * or for this one with the other `served`: remove it first), or it is one of
186
+ * the cluster's own (a node's API host, a cluster origin, a frontend it
187
+ * serves).
188
+ */
162
189
  export class OriginTaken extends CalimeroError {
163
190
  constructor(message, details = {}) {
164
191
  super(409, 'ORIGIN_TAKEN', message, details);
165
192
  this.name = 'OriginTaken';
166
193
  }
167
194
  }
195
+ /**
196
+ * `400 NOT_SERVING`: a served origin (a custom domain, `served: true`) was
197
+ * asked of a cluster that serves no frontends (merod without
198
+ * `--apps-domain`). Register the origin unserved, or use a cluster that
199
+ * serves them.
200
+ */
201
+ export class NotServing extends CalimeroError {
202
+ constructor(message, details = {}) {
203
+ super(400, 'NOT_SERVING', message, details);
204
+ this.name = 'NotServing';
205
+ }
206
+ }
207
+ /**
208
+ * `409 CLUSTER_NOT_UPGRADED`: the change needs every node of the cluster
209
+ * (replicas, voters and learners) on the node's release or later, and one
210
+ * is not yet; for instance adding a served origin. Retry once the cluster is
211
+ * upgraded.
212
+ */
213
+ export class ClusterNotUpgraded extends CalimeroError {
214
+ constructor(message, details = {}) {
215
+ super(409, 'CLUSTER_NOT_UPGRADED', message, details);
216
+ this.name = 'ClusterNotUpgraded';
217
+ }
218
+ }
168
219
  /**
169
220
  * `409 RECOVERY_NOT_READY`: a recovery (an account's or an organization's)
170
221
  * may finish only once its 72-hour delay has passed. `readyAt` is when it may
@@ -223,7 +274,10 @@ function signUpRefusal(message) {
223
274
  return 'org-gone';
224
275
  return 'other';
225
276
  }
226
- /** `429 QUOTA_EXCEEDED`: the caller holds as many of something (origins, blobs, ...) as it may. */
277
+ /**
278
+ * `429 QUOTA_EXCEEDED`: the caller holds as many of something (origins,
279
+ * served origins per package or per cluster, blobs, ...) as it may.
280
+ */
227
281
  export class QuotaExceeded extends CalimeroError {
228
282
  constructor(message, details = {}) {
229
283
  super(429, 'QUOTA_EXCEEDED', message, details);
@@ -304,6 +358,8 @@ export function errorFrom(status, body, retryAfterHeader) {
304
358
  switch (`${status} ${code}`) {
305
359
  case '401 UNAUTHENTICATED':
306
360
  return new LoginRequired(message, details);
361
+ case '401 PASSKEY_UNKNOWN_HERE':
362
+ return new PasskeyUnknownHere(message, details);
307
363
  case '421 WRONG_NODE':
308
364
  return new WrongNode(message, details);
309
365
  case '404 NOT_FOUND':
@@ -321,6 +377,10 @@ export function errorFrom(status, body, retryAfterHeader) {
321
377
  return new BadOrigin(code, message, details);
322
378
  case '409 ORIGIN_TAKEN':
323
379
  return new OriginTaken(message, details);
380
+ case '400 NOT_SERVING':
381
+ return new NotServing(message, details);
382
+ case '409 CLUSTER_NOT_UPGRADED':
383
+ return new ClusterNotUpgraded(message, details);
324
384
  case '429 QUOTA_EXCEEDED':
325
385
  return new QuotaExceeded(message, details);
326
386
  case '409 RECOVERY_NOT_READY':
@@ -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, RecoveryNotReady, ReleaseDeadlineError, SignUpRefused, TrapError, UnavailableError, WrongNode, WrongRecoveryCode, errorFrom, } from './errors.js';
4
+ export { AppError, ArgsTooLarge, BadOrigin, CalimeroError, ClusterNotUpgraded, ConfirmCancelled, ConfirmRequired, IdempotencyMismatch, LoginRequired, ConsentStale, NotFound, NotServing, OriginNotRegistered, OriginTaken, PasskeyUnknownHere, 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, AccountRecovery, 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';
@@ -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, RecoveryNotReady, ReleaseDeadlineError, SignUpRefused, TrapError, UnavailableError, WrongNode, WrongRecoveryCode, errorFrom, } from './errors.js';
3
+ export { AppError, ArgsTooLarge, BadOrigin, CalimeroError, ClusterNotUpgraded, ConfirmCancelled, ConfirmRequired, IdempotencyMismatch, LoginRequired, ConsentStale, NotFound, NotServing, OriginNotRegistered, OriginTaken, PasskeyUnknownHere, 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';