@calimero-network/mero-js 29.8.1 → 29.10.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
@@ -97,7 +97,7 @@ Pinned measurements go through `policy.verifyQuote` (`createQuoteVerifier`).
97
97
 
98
98
  ## The API
99
99
 
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.
100
+ - **Credentials**: `signUp` (with an `invite`, on a cluster that takes new accounts by invite; `signUpPolicy` reads which), `signIn`, `refresh`, `signOut`, `signOutEverywhere`, `listSessions`, `revokeSession`, `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
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).
@@ -175,6 +175,20 @@ export interface ScopeApp {
175
175
  * instance of the package here; `[]`: none, for a fresh install).
176
176
  */
177
177
  instances?: string[];
178
+ /**
179
+ * Open (`everyone`) or close (`invite`) this package's app team in this
180
+ * step, and no other (absent: as `shared` says). Naming it on any package
181
+ * leaves an absent `shared` meaning "no other team"; `shared: true` with an
182
+ * `everyone` is refused.
183
+ */
184
+ join?: 'everyone' | 'invite';
185
+ /**
186
+ * Closing (`join: 'invite'`) only: who keeps the app besides the team's
187
+ * leads, members of the organization (at most 1024). Absent: everyone who
188
+ * reaches it now keeps it. Everyone else loses it, with their rows in the
189
+ * teams below it (its private channels); opening the team again lets them back.
190
+ */
191
+ keep?: string[];
178
192
  }
179
193
  /** What {@link CalimeroClient.scopeApps} asks for; every field absent takes the node's default. */
180
194
  export interface ScopeAppsOptions {
@@ -191,8 +205,12 @@ export interface ScopedAppTeam {
191
205
  created: boolean;
192
206
  /** The instances moved onto it. */
193
207
  apps: string[];
194
- /** How many rows were added for people who reached those instances. */
208
+ /** How many rows were added for people who reached those instances (or kept on a close). */
195
209
  added: number;
210
+ /** The team's `join` after the step (absent from nodes before per-app close). */
211
+ join?: 'everyone' | 'invite';
212
+ /** How many people lost the app in this step (a close with `keep`; absent from nodes before per-app close). */
213
+ dropped?: number;
196
214
  }
197
215
  /** `POST /orgs/{org}/app-teams`: the organization's mode after, and each package's team. */
198
216
  export interface ScopeAppsResult {
@@ -402,11 +420,46 @@ export declare function frontendManifest(origin?: string, fetcher?: typeof fetch
402
420
  * not opened through a deployment. `href` defaults to `window.location.href`.
403
421
  */
404
422
  export declare function pageDeployment(href?: string): string | null;
423
+ /** One of the account's passkeys (devices), as `GET /auth/me` lists it. */
424
+ export interface MePasskey {
425
+ /** The credential id, which {@link CalimeroClient.labelPasskey} and {@link CalimeroClient.removePasskey} take. */
426
+ id: string;
427
+ /** The account's name for it; `null` when unnamed. */
428
+ label?: string | null;
429
+ signCount: number;
430
+ /**
431
+ * When it was added (Unix seconds). `null` when it was added on a release
432
+ * that kept no times (1.0.0-rc.14 and earlier); absent from such a node.
433
+ */
434
+ addedAt?: number | null;
435
+ /**
436
+ * When it last signed in (Unix seconds): a sign-up, a sign-in or an account
437
+ * recovery's finish; a refresh does not move it. `null` when it has not
438
+ * signed in since the node kept times; absent from a node that keeps none.
439
+ */
440
+ lastSignInAt?: number | null;
441
+ }
442
+ /** An organization the account is in, as `GET /auth/me` lists it. */
443
+ export interface MeOrg {
444
+ orgId: string;
445
+ name: string;
446
+ role: 'guest' | 'member' | 'admin' | 'owner';
447
+ }
405
448
  /** `GET /auth/me`: who the credential is. */
406
449
  export interface MeInfo extends Record<string, unknown> {
407
450
  accountId?: string;
408
- /** `session` or `apikey`. */
451
+ name?: string;
452
+ /** The account's passkeys. */
453
+ passkeys?: MePasskey[];
454
+ /** The organizations the account is in, with its role in each. */
455
+ orgs?: MeOrg[];
456
+ /** `session` or `apiKey`. */
409
457
  via?: string;
458
+ /**
459
+ * The passkey (credential id) this session was opened with; `null` for an
460
+ * API key.
461
+ */
462
+ passkeyId?: string | null;
410
463
  /**
411
464
  * The package the session is bound to: opened on an app's frontend or on
412
465
  * an origin its manager registered ({@link CalimeroClient.packageOrigins}).
@@ -425,6 +478,30 @@ export interface MeInfo extends Record<string, unknown> {
425
478
  */
426
479
  recoveryPending?: AccountRecovery | null;
427
480
  }
481
+ /**
482
+ * One of the account's live sessions, as {@link CalimeroClient.listSessions}
483
+ * lists it (core #4894).
484
+ */
485
+ export interface AccountSession {
486
+ /** The session's id, which {@link CalimeroClient.revokeSession} takes. */
487
+ session: string;
488
+ /** The passkey (credential id) it was opened with. */
489
+ passkey: string | null;
490
+ /** The package it is bound to; `null` on the cluster's own origin. */
491
+ app: string | null;
492
+ /** The registered origin it was opened on; `null` on the cluster's own origin. */
493
+ origin: string | null;
494
+ /** When it opened (Unix seconds); `null` when opened before the node kept it. */
495
+ openedAt: number | null;
496
+ /**
497
+ * When its refresh token was last exchanged (Unix seconds). A token younger
498
+ * than an hour refreshes without a write and a session token lives 15
499
+ * minutes, so the session may have been used up to about 1 h 15 min later.
500
+ */
501
+ lastActiveAt: number;
502
+ /** Whether it is the caller's own session. */
503
+ current: boolean;
504
+ }
428
505
  /** A recovery of an account under way (core #4844, `docs/specs/account-recovery.md`). */
429
506
  export interface AccountRecovery {
430
507
  accountId: string;
@@ -782,6 +859,24 @@ export declare class CalimeroClient {
782
859
  * request fails, and the failure is thrown.
783
860
  */
784
861
  signOutEverywhere(): Promise<void>;
862
+ /**
863
+ * The signed-in account's live sessions, latest active first (at most 256,
864
+ * `GET /auth/sessions`); `current` marks this one. The account holder's own
865
+ * session on the cluster's origin only: an API key or a package-bound
866
+ * session is refused (`403`). A node before core #4894 has no such route
867
+ * ({@link NotFound}).
868
+ */
869
+ listSessions(): Promise<AccountSession[]>;
870
+ /**
871
+ * End one of the signed-in account's sessions (`DELETE
872
+ * /auth/sessions/{session}`), say a lost phone's, from another; no passkey
873
+ * is asked. A session the account does not hold live (ended already, or
874
+ * another account's) is {@link NotFound}; gated as {@link listSessions}.
875
+ * To end this client's own session ({@link AccountSession.current}) use
876
+ * {@link signOut}, which also drops its tokens: ended here, they stay
877
+ * held and the next request or refresh is {@link LoginRequired}.
878
+ */
879
+ revokeSession(session: string): Promise<void>;
785
880
  private signingOut;
786
881
  /** Who the credential is: the account, how it signed in, and the package (`app`) and `origin` a session is bound to. */
787
882
  me(): Promise<MeInfo>;
@@ -941,7 +1036,10 @@ export declare class CalimeroClient {
941
1036
  appAbi(app: string): Promise<Record<string, unknown>>;
942
1037
  /**
943
1038
  * Hand the app to another account (an organization's app only to one of its
944
- * members). The owner approves with `passkey`.
1039
+ * members), approved with `passkey`. The app's owner may; for an
1040
+ * organization's app, its owner only while a member of the organization
1041
+ * (`member` or above), and the organization's admins (`admin`, `owner`)
1042
+ * too, so an organization can hand on an app whose owner left (core #4893).
945
1043
  */
946
1044
  transferApp(app: string, to: string, passkey: PasskeyProvider): Promise<void>;
947
1045
  /**
@@ -1312,6 +1410,8 @@ export declare class CalimeroClient {
1312
1410
  * Give apps their own access lists in one step (owner or admin): find or
1313
1411
  * make each package's app team, add everyone who reaches its instances now,
1314
1412
  * and move those instances onto it; with `shared`, close every app team.
1413
+ * A package's own `join` opens or closes its team alone, a close keeping
1414
+ * everyone who reaches it or only the leads and `keep`.
1315
1415
  * Idempotent per package. Approved with the caller's `passkey`
1316
1416
  * (`__scope_apps { apps, shared }`); a refusal is `400 REJECTED` with the
1317
1417
  * node's reason. For a fresh standalone install pass
@@ -639,6 +639,29 @@ export class CalimeroClient {
639
639
  async signOutEverywhere() {
640
640
  await this.signingOut('auth/logout-all');
641
641
  }
642
+ /**
643
+ * The signed-in account's live sessions, latest active first (at most 256,
644
+ * `GET /auth/sessions`); `current` marks this one. The account holder's own
645
+ * session on the cluster's origin only: an API key or a package-bound
646
+ * session is refused (`403`). A node before core #4894 has no such route
647
+ * ({@link NotFound}).
648
+ */
649
+ async listSessions() {
650
+ const { sessions } = await this.get('auth/sessions');
651
+ return sessions;
652
+ }
653
+ /**
654
+ * End one of the signed-in account's sessions (`DELETE
655
+ * /auth/sessions/{session}`), say a lost phone's, from another; no passkey
656
+ * is asked. A session the account does not hold live (ended already, or
657
+ * another account's) is {@link NotFound}; gated as {@link listSessions}.
658
+ * To end this client's own session ({@link AccountSession.current}) use
659
+ * {@link signOut}, which also drops its tokens: ended here, they stay
660
+ * held and the next request or refresh is {@link LoginRequired}.
661
+ */
662
+ async revokeSession(session) {
663
+ await this.delete(`auth/sessions/${seg(session)}`);
664
+ }
642
665
  async signingOut(path) {
643
666
  try {
644
667
  await this.post(path);
@@ -896,7 +919,10 @@ export class CalimeroClient {
896
919
  }
897
920
  /**
898
921
  * Hand the app to another account (an organization's app only to one of its
899
- * members). The owner approves with `passkey`.
922
+ * members), approved with `passkey`. The app's owner may; for an
923
+ * organization's app, its owner only while a member of the organization
924
+ * (`member` or above), and the organization's admins (`admin`, `owner`)
925
+ * too, so an organization can hand on an app whose owner left (core #4893).
900
926
  */
901
927
  async transferApp(app, to, passkey) {
902
928
  await this.postConfirmed(`apps/${seg(app)}/transfer`, { to }, passkey);
@@ -1442,6 +1468,8 @@ export class CalimeroClient {
1442
1468
  * Give apps their own access lists in one step (owner or admin): find or
1443
1469
  * make each package's app team, add everyone who reaches its instances now,
1444
1470
  * and move those instances onto it; with `shared`, close every app team.
1471
+ * A package's own `join` opens or closes its team alone, a close keeping
1472
+ * everyone who reaches it or only the leads and `keep`.
1445
1473
  * Idempotent per package. Approved with the caller's `passkey`
1446
1474
  * (`__scope_apps { apps, shared }`); a refusal is `400 REJECTED` with the
1447
1475
  * node's reason. For a fresh standalone install pass
@@ -3,7 +3,7 @@ export { DEFAULT_DIRECTORY, DirectoryError } from './directory.js';
3
3
  export type { DirectoryFailure } from './directory.js';
4
4
  export { AppError, ArgsTooLarge, BadOrigin, CalimeroError, ClusterNotUpgraded, ConfirmCancelled, ConfirmPromptBlocked, 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, AppTeam, AppTeams, 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, OrgInvite, OrgMode, OrgRecovery, RecoveryTimes, OrgUpgradeTarget, PresenceEntry, ScopeApp, ScopeAppsOptions, ScopeAppsResult, ScopedAppTeam, TeamInfo, TeamMemberInfo, UpgradeRun, ViewResult, } from './client.js';
6
+ export type { AppInfo, AppTeam, AppTeams, AppXcalls, BlobContent, BlobInfo, DeadLetter, Deployer, DeployerGrant, DeployersInfo, DeploymentInfo, DeploymentOffer, DeploymentOrgs, FrontendManifest, MeInfo, MeOrg, MePasskey, AccountSession, PackageOrigin, PackageOriginAdded, PackageOriginRemoved, PackageOrigins, ServedOrigin, ServedOrigins, SignInOptions, AccountRecovery, SignUpOptions, SignUpPolicy, PublicDeployment, CallResult, CalimeroClientOptions, CalimeroConnectOptions, CloudEvent, CalimeroSession, PackageInfo, PackageInstalled, CloudRetryOptions, OrgInfo, OrgInvite, OrgMode, OrgRecovery, RecoveryTimes, OrgUpgradeTarget, PresenceEntry, ScopeApp, ScopeAppsOptions, ScopeAppsResult, ScopedAppTeam, TeamInfo, TeamMemberInfo, 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';