@arbidocs/client 0.4.85 → 0.4.86

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/dist/index.d.cts CHANGED
@@ -31114,6 +31114,8 @@ interface CryptoProvider {
31114
31114
  interface SessionKeys {
31115
31115
  signingPrivateKey: Uint8Array;
31116
31116
  serverSessionKey?: Uint8Array;
31117
+ /** The identity wrapped under the password key (see SessionData.wrappedIdentityKey). */
31118
+ wrappedIdentityKey?: string | null;
31117
31119
  }
31118
31120
  interface SessionStorageProvider {
31119
31121
  getSession(): Promise<SessionKeys | null>;
@@ -31139,6 +31141,8 @@ interface LoginResult$1 {
31139
31141
  accessToken: string;
31140
31142
  sessionKey: Uint8Array;
31141
31143
  userExtId?: string;
31144
+ /** The login response's `wrapped_identity_key`, saved with the session. */
31145
+ wrappedIdentityKey?: string | null;
31142
31146
  }
31143
31147
  /** Performs the login API call. Transport details are the consumer's concern. */
31144
31148
  interface LoginProvider {
@@ -31451,10 +31455,15 @@ declare function generateUserKeypairs(username: string, password: string, deploy
31451
31455
  * Generates registration, login, and password-change credentials.
31452
31456
  * Uses inline type definitions (structurally identical to OpenAPI schema types)
31453
31457
  * to avoid coupling the crypto module to the schema file.
31458
+ *
31459
+ * Two keys are in play (see ./identity.ts): the account identity, a fixed random Ed25519 keypair, and the
31460
+ * password key, derived from email + password, which signs password logins and wraps the identity.
31454
31461
  */
31455
31462
  interface RegisterRequest {
31456
31463
  email: string;
31457
31464
  signing_key: string;
31465
+ login_key?: string | null;
31466
+ wrapped_identity_key?: string | null;
31458
31467
  verification_credential: string;
31459
31468
  given_name?: string | null;
31460
31469
  family_name?: string | null;
@@ -31469,8 +31478,8 @@ interface LoginRequest {
31469
31478
  interface ChangePasswordRequest {
31470
31479
  signature: string;
31471
31480
  timestamp: number;
31472
- new_signing_key: string;
31473
- rewrapped_workspace_keys: Record<string, string>;
31481
+ new_login_key: string;
31482
+ wrapped_identity_key: string;
31474
31483
  }
31475
31484
  /**
31476
31485
  * Credentials returned by generate functions.
@@ -31479,76 +31488,77 @@ interface ChangePasswordRequest {
31479
31488
  */
31480
31489
  interface RegistrationCredentials {
31481
31490
  request: RegisterRequest;
31491
+ /** The new account's identity secret key (what the session keeps, and the recovery key). */
31482
31492
  signingPrivateKey: Uint8Array;
31483
31493
  }
31484
31494
  interface LoginCredentials {
31485
31495
  request: LoginRequest;
31496
+ /**
31497
+ * The password key that signed the request. Not the identity: open it from the response with
31498
+ * `unwrapIdentityKey(response.wrapped_identity_key, passwordPrivateKey)`.
31499
+ */
31500
+ passwordPrivateKey: Uint8Array;
31501
+ }
31502
+ interface KeyLoginCredentials {
31503
+ request: LoginRequest;
31504
+ /** The identity secret key that signed the request (recovery key, session re-login). */
31486
31505
  signingPrivateKey: Uint8Array;
31487
31506
  }
31488
31507
  interface PasswordChangeCredentials {
31489
- request: Omit<ChangePasswordRequest, 'rewrapped_workspace_keys'>;
31490
- newSigningPrivateKey: Uint8Array;
31508
+ request: ChangePasswordRequest;
31491
31509
  }
31492
31510
  /**
31493
- * Generate registration credentials with Ed25519 signing key.
31494
- *
31495
- * Creates Ed25519 keypair deterministically from email + password.
31496
- * Server receives the Ed25519 public key (signing_key) and derives X25519 from it.
31511
+ * Generate registration credentials: a random identity, wrapped under the password key.
31497
31512
  *
31498
- * @param registrationData - Registration fields (signing_key will be generated)
31499
- * @param password - User's password (to generate keypair)
31500
- * @param deploymentDomain - Deployment domain for salt derivation
31501
- * @returns RegistrationCredentials with request body and private key (kept separate)
31513
+ * The server stores the identity public key (signing_key, and the X25519 key it derives from it), the password
31514
+ * key (login_key) and the wrapped identity.
31502
31515
  */
31503
- declare function generateRegistrationCredentials(registrationData: Omit<RegisterRequest, 'signing_key'>, password: string, deploymentDomain: string): Promise<RegistrationCredentials>;
31516
+ declare function generateRegistrationCredentials(registrationData: Omit<RegisterRequest, 'signing_key' | 'login_key' | 'wrapped_identity_key'>, password: string, deploymentDomain: string): Promise<RegistrationCredentials>;
31504
31517
  /**
31505
- * Generate login credentials with Ed25519 signature authentication.
31506
- *
31507
- * Derives Ed25519 keypair from email + password and signs "email|timestamp".
31508
- * Server verifies signature using stored Ed25519 public key.
31509
- *
31510
- * @param loginData - Login fields (signature and timestamp will be generated)
31511
- * @param password - User's password (to regenerate keypair)
31512
- * @param deploymentDomain - Deployment domain for salt derivation
31513
- * @returns LoginCredentials with request body and private key (kept separate)
31518
+ * Generate password-login credentials: derive the password key and sign "email|timestamp" with it.
31514
31519
  */
31515
31520
  declare function generateLoginCredentials(loginData: Omit<LoginRequest, 'signature' | 'timestamp'>, password: string, deploymentDomain: string): Promise<LoginCredentials>;
31516
31521
  /**
31517
- * Generate login credentials using an existing signing key (for password recovery).
31518
- *
31519
- * Bypasses password derivation and uses the provided key directly.
31520
- *
31521
- * @param loginData - Login fields (signature and timestamp will be generated)
31522
- * @param signingPrivateKey - The Ed25519 signing private key (64 bytes)
31523
- * @returns LoginCredentials with request body and private key
31522
+ * Generate login credentials signed by the identity key itself (recovery key, session re-login).
31524
31523
  */
31525
- declare function generateLoginCredentialsFromKey(loginData: Omit<LoginRequest, 'signature' | 'timestamp'>, signingPrivateKey: Uint8Array): LoginCredentials;
31524
+ declare function generateLoginCredentialsFromKey(loginData: Omit<LoginRequest, 'signature' | 'timestamp'>, signingPrivateKey: Uint8Array): KeyLoginCredentials;
31526
31525
  /**
31527
- * Generate change password credentials with Ed25519 signature authentication.
31528
- *
31529
- * Signs "email|timestamp" with current Ed25519 key to prove knowledge of current password.
31530
- * Provides new Ed25519 public key derived from new password.
31526
+ * Generate a password change: the identity is kept, re-wrapped under the new password key.
31531
31527
  *
31532
- * @param email - User's email address
31533
- * @param currentPassword - Current password (to sign with current key)
31534
- * @param newPassword - New password (to generate new key)
31535
- * @param deploymentDomain - Deployment domain for salt derivation
31536
- * @returns PasswordChangeCredentials with request body and new private key (kept separate)
31528
+ * Signed with the current password key when `currentPassword` is given (proves it), else with the identity key
31529
+ * (recovery: the user signed in with the recovery key and no longer knows the password).
31537
31530
  */
31538
- declare function generatePasswordChangeCredentials(email: string, currentPassword: string, newPassword: string, deploymentDomain: string): Promise<PasswordChangeCredentials>;
31531
+ declare function generatePasswordChangeCredentials(params: {
31532
+ email: string;
31533
+ identitySecretKey: Uint8Array;
31534
+ newPassword: string;
31535
+ currentPassword?: string;
31536
+ }, deploymentDomain: string): Promise<PasswordChangeCredentials>;
31537
+
31539
31538
  /**
31540
- * Generate password change credentials for recovery mode.
31539
+ * The account identity and the password key that wraps it.
31541
31540
  *
31542
- * Used when the user is recovering their account with a recovery key.
31543
- * Signs with the existing signing key (from recovery) instead of deriving from password.
31541
+ * The identity is a fixed Ed25519 keypair (its X25519 form is what workspace keys, mailbox keys and direct
31542
+ * messages are encrypted to). The password derives a separate "password key" (Argon2id, `generateUserKeypairs`)
31543
+ * that signs password logins and wraps the identity's secret key. Changing the password re-wraps the identity
31544
+ * and re-encrypts nothing.
31544
31545
  *
31545
- * @param email - User's email address
31546
- * @param currentSigningKey - Current signing key (from recovery)
31547
- * @param newPassword - New password (to generate new key)
31548
- * @param deploymentDomain - Deployment domain for salt derivation
31549
- * @returns PasswordChangeCredentials with request body and new private key
31546
+ * Accounts registered before this existed have no wrap: their password key IS the identity
31547
+ * (`wrapped_identity_key` is null in the login response).
31548
+ *
31549
+ * Same scheme as the Python SDK (`arbi_client.sdk.crypto`): BLAKE2b-256 keyed by the password key's seed over
31550
+ * a fixed context gives a SecretBox key; the wrap is base64 of `nonce(24) ‖ secretbox(identity secret key)`.
31551
+ */
31552
+
31553
+ /** A fresh random identity (Ed25519; secretKey is the 64-byte form). */
31554
+ declare function generateIdentityKeypair(): KeyPair;
31555
+ /** Wrap the identity's 64-byte Ed25519 secret key under a password key. */
31556
+ declare function wrapIdentityKey(identitySecretKey: Uint8Array, passwordSecretKey: Uint8Array): string;
31557
+ /**
31558
+ * The identity's 64-byte Ed25519 secret key a password key opens: unwrapped from `wrapped`, or the password key
31559
+ * itself when nothing is wrapped. Throws when the password key does not open the wrap (a wrong password).
31550
31560
  */
31551
- declare function generateRecoveryPasswordChangeCredentials(email: string, currentSigningKey: Uint8Array, newPassword: string, deploymentDomain: string): Promise<PasswordChangeCredentials>;
31561
+ declare function unwrapIdentityKey(wrapped: string | null | undefined, passwordSecretKey: Uint8Array): Uint8Array;
31552
31562
 
31553
31563
  /**
31554
31564
  * storage.ts - IndexedDB Storage Module
@@ -31585,9 +31595,16 @@ declare function canPersistSession(): boolean;
31585
31595
  * Note: accessToken is stored in Zustand (persisted separately), not here.
31586
31596
  */
31587
31597
  interface SessionData {
31598
+ /** The account identity's Ed25519 secret key (64 bytes) - X25519 derived from this */
31588
31599
  signingPrivateKey: Uint8Array;
31589
31600
  serverSessionKey?: Uint8Array;
31590
31601
  userExtId?: string;
31602
+ /**
31603
+ * The identity wrapped under the password key, as the last login returned it (null: the password key is
31604
+ * the identity). Lets a typed password be checked, and the identity opened, without the server (offline
31605
+ * unlock, step-up confirmations). Ciphertext under the password key, so it is stored as is.
31606
+ */
31607
+ wrappedIdentityKey?: string | null;
31591
31608
  }
31592
31609
  /**
31593
31610
  * Initialize IndexedDB database.
@@ -31617,12 +31634,11 @@ declare function saveSession(sessionData: SessionData): Promise<void>;
31617
31634
  */
31618
31635
  declare function getSession(): Promise<SessionData | null>;
31619
31636
  /**
31620
- * Update the signing private key in IndexedDB (used when changing password).
31621
- * This re-encrypts the new key while preserving other session data.
31637
+ * Replace the stored wrapped identity (after a password change), keeping the rest of the session.
31622
31638
  *
31623
- * @param newSigningPrivateKey - New Ed25519 private key to store
31639
+ * @param wrappedIdentityKey - The identity wrapped under the new password key
31624
31640
  */
31625
- declare function updateSigningPrivateKey(newSigningPrivateKey: Uint8Array): Promise<void>;
31641
+ declare function updateWrappedIdentityKey(wrappedIdentityKey: string): Promise<void>;
31626
31642
  /**
31627
31643
  * Clear session data from IndexedDB.
31628
31644
  */
@@ -31668,7 +31684,8 @@ interface RegisterResult {
31668
31684
  /**
31669
31685
  * Login flow
31670
31686
  *
31671
- * Generates Ed25519 signature → posts to /v1/user/login → saves session
31687
+ * Signs "email|timestamp" (password key, or the identity key itself) → posts to /v1/user/login → opens the
31688
+ * identity → saves session
31672
31689
  */
31673
31690
 
31674
31691
  interface LoginParams {
@@ -31700,6 +31717,7 @@ interface LoginResult {
31700
31717
  parentExtId?: string | null;
31701
31718
  /** The profile from the login response, so hosts need no second request for the name. */
31702
31719
  profile?: LoginProfile;
31720
+ /** The account identity's secret key (the session key material, and the recovery key). */
31703
31721
  signingPrivateKey: Uint8Array;
31704
31722
  serverSessionKey: Uint8Array;
31705
31723
  }
@@ -31707,46 +31725,57 @@ interface LoginResult {
31707
31725
  /**
31708
31726
  * Change password flow
31709
31727
  *
31710
- * Generates old + new credentials → posts to /v1/user/change_password → updates stored key
31728
+ * The password only wraps the account identity (see ../crypto/identity.ts). Changing it derives the new password
31729
+ * key, re-wraps the session's identity under it and posts both to /v1/user/change_password: one request, O(1).
31730
+ * Workspace keys, mailbox keys and direct messages stay encrypted to the unchanged identity, so nothing is
31731
+ * re-encrypted, nothing can be missed and the other party of a conversation is unaffected. The recovery key
31732
+ * (the identity secret key) is unchanged too.
31711
31733
  */
31712
31734
 
31713
31735
  interface ChangePasswordParams {
31714
31736
  email: string;
31715
- currentPassword: string;
31716
31737
  newPassword: string;
31717
- rewrappedWorkspaceKeys?: Record<string, string>;
31718
- }
31719
- interface ChangePasswordResult {
31720
- newSigningPrivateKey: Uint8Array;
31721
- }
31722
- interface RekeyedPasswordChangeParams {
31723
- email: string;
31724
- newPassword: string;
31725
- /** The current password. Omit in recovery mode: the session's own signing key proves identity. */
31738
+ /** The current password. Omit in recovery mode: the session's identity key signs instead. */
31726
31739
  currentPassword?: string;
31727
- /** The caller's `usr-` id; needed to tell sent from received direct messages. */
31728
- userExtId?: string;
31740
+ /**
31741
+ * The account identity's secret key. Omitted: read from the browser session store, which is then
31742
+ * updated with the new wrap (hosts with their own key store pass it and keep `wrappedIdentityKey`).
31743
+ */
31744
+ identitySecretKey?: Uint8Array;
31729
31745
  }
31730
- interface RekeyedPasswordChangeResult {
31731
- newSigningPrivateKey: Uint8Array;
31732
- /** Workspaces the server re-keyed. */
31733
- workspacesUpdated: number;
31734
- /** Direct messages re-encrypted for the new key. */
31735
- messagesReEncrypted: number;
31746
+ interface ChangePasswordResult {
31747
+ /** The identity wrapped under the new password key (what a password login now returns). */
31748
+ wrappedIdentityKey: string;
31736
31749
  }
31737
- type FetchClient = ReturnType<typeof createFetchClient<paths>>;
31738
31750
  /** Pull a readable message out of whatever shape a failed call carried (`{ detail }`, `Error`). */
31739
31751
  declare function passwordChangeErrorMessage(err: unknown): string;
31740
31752
  /**
31741
- * Change (or, in recovery mode, set) the master password: derive the new keys, re-wrap the key of
31742
- * every workspace the user is a member of for them, re-encrypt direct messages, post it all to
31743
- * `/v1/user/change_password`, then store the new signing key. The caller shows the recovery key
31744
- * for `newSigningPrivateKey` afterwards.
31753
+ * Change (or, in recovery mode, set) the master password of the signed-in account.
31745
31754
  */
31746
- declare function changePasswordWithRekey(params: RekeyedPasswordChangeParams, deps: {
31747
- fetchClient: FetchClient;
31755
+ declare function changePassword(params: ChangePasswordParams, deps: {
31756
+ fetchClient: ReturnType<typeof createFetchClient<paths>>;
31748
31757
  deploymentDomain: string;
31749
- }): Promise<RekeyedPasswordChangeResult>;
31758
+ }): Promise<ChangePasswordResult>;
31759
+
31760
+ /**
31761
+ * Opening the account identity with a password (see ../crypto/identity.ts).
31762
+ */
31763
+ /**
31764
+ * The identity a password login opened: unwrapped from the response with the password key that signed it (or
31765
+ * the password key itself for an account whose password key is its identity). Refuses an identity that is not
31766
+ * the account's, so a wrong wrap cannot become the session's key.
31767
+ */
31768
+ declare function identityFromLoginResponse(passwordPrivateKey: Uint8Array, response: {
31769
+ wrapped_identity_key?: string | null;
31770
+ user: {
31771
+ encryption_public_key: string;
31772
+ };
31773
+ }): Uint8Array;
31774
+ /**
31775
+ * Check a typed password against the signed-in session and return the identity it opens (step-up
31776
+ * confirmations, offline unlock). Uses the wrap saved at the last login; throws "Incorrect password".
31777
+ */
31778
+ declare function unlockIdentityWithPassword(email: string, password: string, deploymentDomain: string): Promise<Uint8Array>;
31750
31779
 
31751
31780
  /**
31752
31781
  * createArbiClient() — SDK entry point
@@ -31970,4 +31999,4 @@ interface ReopenDeps {
31970
31999
  */
31971
32000
  declare function createWorkspaceReopener(deps: ReopenDeps): () => Promise<boolean>;
31972
32001
 
31973
- export { type $defs, API_PREFIX, type ArbiClient, type ArbiClientOptions, type AuthStateProvider, type AutoReloginMiddlewareConfig, type BearerAuthMiddlewareConfig, CALL_KEY_BYTES, type ChangePasswordParams, type ChangePasswordRequest, type ChangePasswordResult, type CryptoProvider, type KeyPair, type LoginCredentials, type LoginParams, type LoginProfile, type LoginProvider, type LoginRequest, type LoginResult, type LoginWithKeyParams, type OnReloginSuccess, type PasswordChangeCredentials, type RegisterParams, type RegisterRequest, type RegisterResult, type RegistrationCredentials, type RekeyedPasswordChangeParams, type RekeyedPasswordChangeResult, type ReloginDeps, type ReloginHandler, type ReopenDeps, type SessionData, type SessionKeys, type SessionManager, type SessionState, type SessionStorageProvider, type SsoTokenProvider, type TokenProvider, type UserKeypairs, type WebSocketClientMessage, type WebSocketServerMessage, type WorkspaceKeyRefreshProvider, type WorkspaceOpenProvider, type WsAuthMessage, type WsAuthResultMessage, type WsBatchCompleteMessage, type WsConnectionClosedMessage, type WsConversationMessagePostedMessage, type WsErrorMessage, type WsNotificationResponse, type WsPresenceUpdateMessage, type WsResponseCompleteMessage, type WsTaskUpdateMessage, base64Decode, base64Encode, base64ToBytes, buildCallFragment, buildWebSocketUrl, bytesToBase64, canPersistSession, changePasswordWithRekey, clearAllData, clearSession, type components, computeSharedSecret, createArbiClient, createAuthMessage, createAutoReloginMiddleware, createBearerAuthMiddleware, createContentHash, createReloginHandler, createSessionManager, createWorkspaceReopener, decodeCallKey, decryptCallTitle, decryptFile, decryptMessage, decryptMessageWithSharedSecret, deriveEncryptionKeypairFromSigning, derivePublicKey, encodeCallKey, encryptCallTitle, encryptFile, encryptMessage, encryptMessageWithSharedSecret, generateCallKey, generateKeyPairs, generateLoginCredentials, generateLoginCredentialsFromKey, generatePasswordChangeCredentials, generateRandomSigningKeypair, generateRecoveryPasswordChangeCredentials, generateRegistrationCredentials, generateUserKeypairs, getSession, getUserEncryptionKeypair, hasSession, initSodium, initializeDatabase, isMessageType, openSealedCallKey, type operations, parseCallFragment, parseServerMessage, passwordChangeErrorMessage, type paths, prewarmKeyPairs, saveSession, sealCallKey, sealKeyForSession, sealedBoxDecrypt, sealedBoxEncrypt, signMessage, updateSigningPrivateKey, type webhooks };
32002
+ export { type $defs, API_PREFIX, type ArbiClient, type ArbiClientOptions, type AuthStateProvider, type AutoReloginMiddlewareConfig, type BearerAuthMiddlewareConfig, CALL_KEY_BYTES, type ChangePasswordParams, type ChangePasswordRequest, type ChangePasswordResult, type CryptoProvider, type KeyLoginCredentials, type KeyPair, type LoginCredentials, type LoginParams, type LoginProfile, type LoginProvider, type LoginRequest, type LoginResult, type LoginWithKeyParams, type OnReloginSuccess, type PasswordChangeCredentials, type RegisterParams, type RegisterRequest, type RegisterResult, type RegistrationCredentials, type ReloginDeps, type ReloginHandler, type ReopenDeps, type SessionData, type SessionKeys, type SessionManager, type SessionState, type SessionStorageProvider, type SsoTokenProvider, type TokenProvider, type UserKeypairs, type WebSocketClientMessage, type WebSocketServerMessage, type WorkspaceKeyRefreshProvider, type WorkspaceOpenProvider, type WsAuthMessage, type WsAuthResultMessage, type WsBatchCompleteMessage, type WsConnectionClosedMessage, type WsConversationMessagePostedMessage, type WsErrorMessage, type WsNotificationResponse, type WsPresenceUpdateMessage, type WsResponseCompleteMessage, type WsTaskUpdateMessage, base64Decode, base64Encode, base64ToBytes, buildCallFragment, buildWebSocketUrl, bytesToBase64, canPersistSession, changePassword, clearAllData, clearSession, type components, computeSharedSecret, createArbiClient, createAuthMessage, createAutoReloginMiddleware, createBearerAuthMiddleware, createContentHash, createReloginHandler, createSessionManager, createWorkspaceReopener, decodeCallKey, decryptCallTitle, decryptFile, decryptMessage, decryptMessageWithSharedSecret, deriveEncryptionKeypairFromSigning, derivePublicKey, encodeCallKey, encryptCallTitle, encryptFile, encryptMessage, encryptMessageWithSharedSecret, generateCallKey, generateIdentityKeypair, generateKeyPairs, generateLoginCredentials, generateLoginCredentialsFromKey, generatePasswordChangeCredentials, generateRandomSigningKeypair, generateRegistrationCredentials, generateUserKeypairs, getSession, getUserEncryptionKeypair, hasSession, identityFromLoginResponse, initSodium, initializeDatabase, isMessageType, openSealedCallKey, type operations, parseCallFragment, parseServerMessage, passwordChangeErrorMessage, type paths, prewarmKeyPairs, saveSession, sealCallKey, sealKeyForSession, sealedBoxDecrypt, sealedBoxEncrypt, signMessage, unlockIdentityWithPassword, unwrapIdentityKey, updateWrappedIdentityKey, type webhooks, wrapIdentityKey };
package/dist/index.d.ts CHANGED
@@ -31114,6 +31114,8 @@ interface CryptoProvider {
31114
31114
  interface SessionKeys {
31115
31115
  signingPrivateKey: Uint8Array;
31116
31116
  serverSessionKey?: Uint8Array;
31117
+ /** The identity wrapped under the password key (see SessionData.wrappedIdentityKey). */
31118
+ wrappedIdentityKey?: string | null;
31117
31119
  }
31118
31120
  interface SessionStorageProvider {
31119
31121
  getSession(): Promise<SessionKeys | null>;
@@ -31139,6 +31141,8 @@ interface LoginResult$1 {
31139
31141
  accessToken: string;
31140
31142
  sessionKey: Uint8Array;
31141
31143
  userExtId?: string;
31144
+ /** The login response's `wrapped_identity_key`, saved with the session. */
31145
+ wrappedIdentityKey?: string | null;
31142
31146
  }
31143
31147
  /** Performs the login API call. Transport details are the consumer's concern. */
31144
31148
  interface LoginProvider {
@@ -31451,10 +31455,15 @@ declare function generateUserKeypairs(username: string, password: string, deploy
31451
31455
  * Generates registration, login, and password-change credentials.
31452
31456
  * Uses inline type definitions (structurally identical to OpenAPI schema types)
31453
31457
  * to avoid coupling the crypto module to the schema file.
31458
+ *
31459
+ * Two keys are in play (see ./identity.ts): the account identity, a fixed random Ed25519 keypair, and the
31460
+ * password key, derived from email + password, which signs password logins and wraps the identity.
31454
31461
  */
31455
31462
  interface RegisterRequest {
31456
31463
  email: string;
31457
31464
  signing_key: string;
31465
+ login_key?: string | null;
31466
+ wrapped_identity_key?: string | null;
31458
31467
  verification_credential: string;
31459
31468
  given_name?: string | null;
31460
31469
  family_name?: string | null;
@@ -31469,8 +31478,8 @@ interface LoginRequest {
31469
31478
  interface ChangePasswordRequest {
31470
31479
  signature: string;
31471
31480
  timestamp: number;
31472
- new_signing_key: string;
31473
- rewrapped_workspace_keys: Record<string, string>;
31481
+ new_login_key: string;
31482
+ wrapped_identity_key: string;
31474
31483
  }
31475
31484
  /**
31476
31485
  * Credentials returned by generate functions.
@@ -31479,76 +31488,77 @@ interface ChangePasswordRequest {
31479
31488
  */
31480
31489
  interface RegistrationCredentials {
31481
31490
  request: RegisterRequest;
31491
+ /** The new account's identity secret key (what the session keeps, and the recovery key). */
31482
31492
  signingPrivateKey: Uint8Array;
31483
31493
  }
31484
31494
  interface LoginCredentials {
31485
31495
  request: LoginRequest;
31496
+ /**
31497
+ * The password key that signed the request. Not the identity: open it from the response with
31498
+ * `unwrapIdentityKey(response.wrapped_identity_key, passwordPrivateKey)`.
31499
+ */
31500
+ passwordPrivateKey: Uint8Array;
31501
+ }
31502
+ interface KeyLoginCredentials {
31503
+ request: LoginRequest;
31504
+ /** The identity secret key that signed the request (recovery key, session re-login). */
31486
31505
  signingPrivateKey: Uint8Array;
31487
31506
  }
31488
31507
  interface PasswordChangeCredentials {
31489
- request: Omit<ChangePasswordRequest, 'rewrapped_workspace_keys'>;
31490
- newSigningPrivateKey: Uint8Array;
31508
+ request: ChangePasswordRequest;
31491
31509
  }
31492
31510
  /**
31493
- * Generate registration credentials with Ed25519 signing key.
31494
- *
31495
- * Creates Ed25519 keypair deterministically from email + password.
31496
- * Server receives the Ed25519 public key (signing_key) and derives X25519 from it.
31511
+ * Generate registration credentials: a random identity, wrapped under the password key.
31497
31512
  *
31498
- * @param registrationData - Registration fields (signing_key will be generated)
31499
- * @param password - User's password (to generate keypair)
31500
- * @param deploymentDomain - Deployment domain for salt derivation
31501
- * @returns RegistrationCredentials with request body and private key (kept separate)
31513
+ * The server stores the identity public key (signing_key, and the X25519 key it derives from it), the password
31514
+ * key (login_key) and the wrapped identity.
31502
31515
  */
31503
- declare function generateRegistrationCredentials(registrationData: Omit<RegisterRequest, 'signing_key'>, password: string, deploymentDomain: string): Promise<RegistrationCredentials>;
31516
+ declare function generateRegistrationCredentials(registrationData: Omit<RegisterRequest, 'signing_key' | 'login_key' | 'wrapped_identity_key'>, password: string, deploymentDomain: string): Promise<RegistrationCredentials>;
31504
31517
  /**
31505
- * Generate login credentials with Ed25519 signature authentication.
31506
- *
31507
- * Derives Ed25519 keypair from email + password and signs "email|timestamp".
31508
- * Server verifies signature using stored Ed25519 public key.
31509
- *
31510
- * @param loginData - Login fields (signature and timestamp will be generated)
31511
- * @param password - User's password (to regenerate keypair)
31512
- * @param deploymentDomain - Deployment domain for salt derivation
31513
- * @returns LoginCredentials with request body and private key (kept separate)
31518
+ * Generate password-login credentials: derive the password key and sign "email|timestamp" with it.
31514
31519
  */
31515
31520
  declare function generateLoginCredentials(loginData: Omit<LoginRequest, 'signature' | 'timestamp'>, password: string, deploymentDomain: string): Promise<LoginCredentials>;
31516
31521
  /**
31517
- * Generate login credentials using an existing signing key (for password recovery).
31518
- *
31519
- * Bypasses password derivation and uses the provided key directly.
31520
- *
31521
- * @param loginData - Login fields (signature and timestamp will be generated)
31522
- * @param signingPrivateKey - The Ed25519 signing private key (64 bytes)
31523
- * @returns LoginCredentials with request body and private key
31522
+ * Generate login credentials signed by the identity key itself (recovery key, session re-login).
31524
31523
  */
31525
- declare function generateLoginCredentialsFromKey(loginData: Omit<LoginRequest, 'signature' | 'timestamp'>, signingPrivateKey: Uint8Array): LoginCredentials;
31524
+ declare function generateLoginCredentialsFromKey(loginData: Omit<LoginRequest, 'signature' | 'timestamp'>, signingPrivateKey: Uint8Array): KeyLoginCredentials;
31526
31525
  /**
31527
- * Generate change password credentials with Ed25519 signature authentication.
31528
- *
31529
- * Signs "email|timestamp" with current Ed25519 key to prove knowledge of current password.
31530
- * Provides new Ed25519 public key derived from new password.
31526
+ * Generate a password change: the identity is kept, re-wrapped under the new password key.
31531
31527
  *
31532
- * @param email - User's email address
31533
- * @param currentPassword - Current password (to sign with current key)
31534
- * @param newPassword - New password (to generate new key)
31535
- * @param deploymentDomain - Deployment domain for salt derivation
31536
- * @returns PasswordChangeCredentials with request body and new private key (kept separate)
31528
+ * Signed with the current password key when `currentPassword` is given (proves it), else with the identity key
31529
+ * (recovery: the user signed in with the recovery key and no longer knows the password).
31537
31530
  */
31538
- declare function generatePasswordChangeCredentials(email: string, currentPassword: string, newPassword: string, deploymentDomain: string): Promise<PasswordChangeCredentials>;
31531
+ declare function generatePasswordChangeCredentials(params: {
31532
+ email: string;
31533
+ identitySecretKey: Uint8Array;
31534
+ newPassword: string;
31535
+ currentPassword?: string;
31536
+ }, deploymentDomain: string): Promise<PasswordChangeCredentials>;
31537
+
31539
31538
  /**
31540
- * Generate password change credentials for recovery mode.
31539
+ * The account identity and the password key that wraps it.
31541
31540
  *
31542
- * Used when the user is recovering their account with a recovery key.
31543
- * Signs with the existing signing key (from recovery) instead of deriving from password.
31541
+ * The identity is a fixed Ed25519 keypair (its X25519 form is what workspace keys, mailbox keys and direct
31542
+ * messages are encrypted to). The password derives a separate "password key" (Argon2id, `generateUserKeypairs`)
31543
+ * that signs password logins and wraps the identity's secret key. Changing the password re-wraps the identity
31544
+ * and re-encrypts nothing.
31544
31545
  *
31545
- * @param email - User's email address
31546
- * @param currentSigningKey - Current signing key (from recovery)
31547
- * @param newPassword - New password (to generate new key)
31548
- * @param deploymentDomain - Deployment domain for salt derivation
31549
- * @returns PasswordChangeCredentials with request body and new private key
31546
+ * Accounts registered before this existed have no wrap: their password key IS the identity
31547
+ * (`wrapped_identity_key` is null in the login response).
31548
+ *
31549
+ * Same scheme as the Python SDK (`arbi_client.sdk.crypto`): BLAKE2b-256 keyed by the password key's seed over
31550
+ * a fixed context gives a SecretBox key; the wrap is base64 of `nonce(24) ‖ secretbox(identity secret key)`.
31551
+ */
31552
+
31553
+ /** A fresh random identity (Ed25519; secretKey is the 64-byte form). */
31554
+ declare function generateIdentityKeypair(): KeyPair;
31555
+ /** Wrap the identity's 64-byte Ed25519 secret key under a password key. */
31556
+ declare function wrapIdentityKey(identitySecretKey: Uint8Array, passwordSecretKey: Uint8Array): string;
31557
+ /**
31558
+ * The identity's 64-byte Ed25519 secret key a password key opens: unwrapped from `wrapped`, or the password key
31559
+ * itself when nothing is wrapped. Throws when the password key does not open the wrap (a wrong password).
31550
31560
  */
31551
- declare function generateRecoveryPasswordChangeCredentials(email: string, currentSigningKey: Uint8Array, newPassword: string, deploymentDomain: string): Promise<PasswordChangeCredentials>;
31561
+ declare function unwrapIdentityKey(wrapped: string | null | undefined, passwordSecretKey: Uint8Array): Uint8Array;
31552
31562
 
31553
31563
  /**
31554
31564
  * storage.ts - IndexedDB Storage Module
@@ -31585,9 +31595,16 @@ declare function canPersistSession(): boolean;
31585
31595
  * Note: accessToken is stored in Zustand (persisted separately), not here.
31586
31596
  */
31587
31597
  interface SessionData {
31598
+ /** The account identity's Ed25519 secret key (64 bytes) - X25519 derived from this */
31588
31599
  signingPrivateKey: Uint8Array;
31589
31600
  serverSessionKey?: Uint8Array;
31590
31601
  userExtId?: string;
31602
+ /**
31603
+ * The identity wrapped under the password key, as the last login returned it (null: the password key is
31604
+ * the identity). Lets a typed password be checked, and the identity opened, without the server (offline
31605
+ * unlock, step-up confirmations). Ciphertext under the password key, so it is stored as is.
31606
+ */
31607
+ wrappedIdentityKey?: string | null;
31591
31608
  }
31592
31609
  /**
31593
31610
  * Initialize IndexedDB database.
@@ -31617,12 +31634,11 @@ declare function saveSession(sessionData: SessionData): Promise<void>;
31617
31634
  */
31618
31635
  declare function getSession(): Promise<SessionData | null>;
31619
31636
  /**
31620
- * Update the signing private key in IndexedDB (used when changing password).
31621
- * This re-encrypts the new key while preserving other session data.
31637
+ * Replace the stored wrapped identity (after a password change), keeping the rest of the session.
31622
31638
  *
31623
- * @param newSigningPrivateKey - New Ed25519 private key to store
31639
+ * @param wrappedIdentityKey - The identity wrapped under the new password key
31624
31640
  */
31625
- declare function updateSigningPrivateKey(newSigningPrivateKey: Uint8Array): Promise<void>;
31641
+ declare function updateWrappedIdentityKey(wrappedIdentityKey: string): Promise<void>;
31626
31642
  /**
31627
31643
  * Clear session data from IndexedDB.
31628
31644
  */
@@ -31668,7 +31684,8 @@ interface RegisterResult {
31668
31684
  /**
31669
31685
  * Login flow
31670
31686
  *
31671
- * Generates Ed25519 signature → posts to /v1/user/login → saves session
31687
+ * Signs "email|timestamp" (password key, or the identity key itself) → posts to /v1/user/login → opens the
31688
+ * identity → saves session
31672
31689
  */
31673
31690
 
31674
31691
  interface LoginParams {
@@ -31700,6 +31717,7 @@ interface LoginResult {
31700
31717
  parentExtId?: string | null;
31701
31718
  /** The profile from the login response, so hosts need no second request for the name. */
31702
31719
  profile?: LoginProfile;
31720
+ /** The account identity's secret key (the session key material, and the recovery key). */
31703
31721
  signingPrivateKey: Uint8Array;
31704
31722
  serverSessionKey: Uint8Array;
31705
31723
  }
@@ -31707,46 +31725,57 @@ interface LoginResult {
31707
31725
  /**
31708
31726
  * Change password flow
31709
31727
  *
31710
- * Generates old + new credentials → posts to /v1/user/change_password → updates stored key
31728
+ * The password only wraps the account identity (see ../crypto/identity.ts). Changing it derives the new password
31729
+ * key, re-wraps the session's identity under it and posts both to /v1/user/change_password: one request, O(1).
31730
+ * Workspace keys, mailbox keys and direct messages stay encrypted to the unchanged identity, so nothing is
31731
+ * re-encrypted, nothing can be missed and the other party of a conversation is unaffected. The recovery key
31732
+ * (the identity secret key) is unchanged too.
31711
31733
  */
31712
31734
 
31713
31735
  interface ChangePasswordParams {
31714
31736
  email: string;
31715
- currentPassword: string;
31716
31737
  newPassword: string;
31717
- rewrappedWorkspaceKeys?: Record<string, string>;
31718
- }
31719
- interface ChangePasswordResult {
31720
- newSigningPrivateKey: Uint8Array;
31721
- }
31722
- interface RekeyedPasswordChangeParams {
31723
- email: string;
31724
- newPassword: string;
31725
- /** The current password. Omit in recovery mode: the session's own signing key proves identity. */
31738
+ /** The current password. Omit in recovery mode: the session's identity key signs instead. */
31726
31739
  currentPassword?: string;
31727
- /** The caller's `usr-` id; needed to tell sent from received direct messages. */
31728
- userExtId?: string;
31740
+ /**
31741
+ * The account identity's secret key. Omitted: read from the browser session store, which is then
31742
+ * updated with the new wrap (hosts with their own key store pass it and keep `wrappedIdentityKey`).
31743
+ */
31744
+ identitySecretKey?: Uint8Array;
31729
31745
  }
31730
- interface RekeyedPasswordChangeResult {
31731
- newSigningPrivateKey: Uint8Array;
31732
- /** Workspaces the server re-keyed. */
31733
- workspacesUpdated: number;
31734
- /** Direct messages re-encrypted for the new key. */
31735
- messagesReEncrypted: number;
31746
+ interface ChangePasswordResult {
31747
+ /** The identity wrapped under the new password key (what a password login now returns). */
31748
+ wrappedIdentityKey: string;
31736
31749
  }
31737
- type FetchClient = ReturnType<typeof createFetchClient<paths>>;
31738
31750
  /** Pull a readable message out of whatever shape a failed call carried (`{ detail }`, `Error`). */
31739
31751
  declare function passwordChangeErrorMessage(err: unknown): string;
31740
31752
  /**
31741
- * Change (or, in recovery mode, set) the master password: derive the new keys, re-wrap the key of
31742
- * every workspace the user is a member of for them, re-encrypt direct messages, post it all to
31743
- * `/v1/user/change_password`, then store the new signing key. The caller shows the recovery key
31744
- * for `newSigningPrivateKey` afterwards.
31753
+ * Change (or, in recovery mode, set) the master password of the signed-in account.
31745
31754
  */
31746
- declare function changePasswordWithRekey(params: RekeyedPasswordChangeParams, deps: {
31747
- fetchClient: FetchClient;
31755
+ declare function changePassword(params: ChangePasswordParams, deps: {
31756
+ fetchClient: ReturnType<typeof createFetchClient<paths>>;
31748
31757
  deploymentDomain: string;
31749
- }): Promise<RekeyedPasswordChangeResult>;
31758
+ }): Promise<ChangePasswordResult>;
31759
+
31760
+ /**
31761
+ * Opening the account identity with a password (see ../crypto/identity.ts).
31762
+ */
31763
+ /**
31764
+ * The identity a password login opened: unwrapped from the response with the password key that signed it (or
31765
+ * the password key itself for an account whose password key is its identity). Refuses an identity that is not
31766
+ * the account's, so a wrong wrap cannot become the session's key.
31767
+ */
31768
+ declare function identityFromLoginResponse(passwordPrivateKey: Uint8Array, response: {
31769
+ wrapped_identity_key?: string | null;
31770
+ user: {
31771
+ encryption_public_key: string;
31772
+ };
31773
+ }): Uint8Array;
31774
+ /**
31775
+ * Check a typed password against the signed-in session and return the identity it opens (step-up
31776
+ * confirmations, offline unlock). Uses the wrap saved at the last login; throws "Incorrect password".
31777
+ */
31778
+ declare function unlockIdentityWithPassword(email: string, password: string, deploymentDomain: string): Promise<Uint8Array>;
31750
31779
 
31751
31780
  /**
31752
31781
  * createArbiClient() — SDK entry point
@@ -31970,4 +31999,4 @@ interface ReopenDeps {
31970
31999
  */
31971
32000
  declare function createWorkspaceReopener(deps: ReopenDeps): () => Promise<boolean>;
31972
32001
 
31973
- export { type $defs, API_PREFIX, type ArbiClient, type ArbiClientOptions, type AuthStateProvider, type AutoReloginMiddlewareConfig, type BearerAuthMiddlewareConfig, CALL_KEY_BYTES, type ChangePasswordParams, type ChangePasswordRequest, type ChangePasswordResult, type CryptoProvider, type KeyPair, type LoginCredentials, type LoginParams, type LoginProfile, type LoginProvider, type LoginRequest, type LoginResult, type LoginWithKeyParams, type OnReloginSuccess, type PasswordChangeCredentials, type RegisterParams, type RegisterRequest, type RegisterResult, type RegistrationCredentials, type RekeyedPasswordChangeParams, type RekeyedPasswordChangeResult, type ReloginDeps, type ReloginHandler, type ReopenDeps, type SessionData, type SessionKeys, type SessionManager, type SessionState, type SessionStorageProvider, type SsoTokenProvider, type TokenProvider, type UserKeypairs, type WebSocketClientMessage, type WebSocketServerMessage, type WorkspaceKeyRefreshProvider, type WorkspaceOpenProvider, type WsAuthMessage, type WsAuthResultMessage, type WsBatchCompleteMessage, type WsConnectionClosedMessage, type WsConversationMessagePostedMessage, type WsErrorMessage, type WsNotificationResponse, type WsPresenceUpdateMessage, type WsResponseCompleteMessage, type WsTaskUpdateMessage, base64Decode, base64Encode, base64ToBytes, buildCallFragment, buildWebSocketUrl, bytesToBase64, canPersistSession, changePasswordWithRekey, clearAllData, clearSession, type components, computeSharedSecret, createArbiClient, createAuthMessage, createAutoReloginMiddleware, createBearerAuthMiddleware, createContentHash, createReloginHandler, createSessionManager, createWorkspaceReopener, decodeCallKey, decryptCallTitle, decryptFile, decryptMessage, decryptMessageWithSharedSecret, deriveEncryptionKeypairFromSigning, derivePublicKey, encodeCallKey, encryptCallTitle, encryptFile, encryptMessage, encryptMessageWithSharedSecret, generateCallKey, generateKeyPairs, generateLoginCredentials, generateLoginCredentialsFromKey, generatePasswordChangeCredentials, generateRandomSigningKeypair, generateRecoveryPasswordChangeCredentials, generateRegistrationCredentials, generateUserKeypairs, getSession, getUserEncryptionKeypair, hasSession, initSodium, initializeDatabase, isMessageType, openSealedCallKey, type operations, parseCallFragment, parseServerMessage, passwordChangeErrorMessage, type paths, prewarmKeyPairs, saveSession, sealCallKey, sealKeyForSession, sealedBoxDecrypt, sealedBoxEncrypt, signMessage, updateSigningPrivateKey, type webhooks };
32002
+ export { type $defs, API_PREFIX, type ArbiClient, type ArbiClientOptions, type AuthStateProvider, type AutoReloginMiddlewareConfig, type BearerAuthMiddlewareConfig, CALL_KEY_BYTES, type ChangePasswordParams, type ChangePasswordRequest, type ChangePasswordResult, type CryptoProvider, type KeyLoginCredentials, type KeyPair, type LoginCredentials, type LoginParams, type LoginProfile, type LoginProvider, type LoginRequest, type LoginResult, type LoginWithKeyParams, type OnReloginSuccess, type PasswordChangeCredentials, type RegisterParams, type RegisterRequest, type RegisterResult, type RegistrationCredentials, type ReloginDeps, type ReloginHandler, type ReopenDeps, type SessionData, type SessionKeys, type SessionManager, type SessionState, type SessionStorageProvider, type SsoTokenProvider, type TokenProvider, type UserKeypairs, type WebSocketClientMessage, type WebSocketServerMessage, type WorkspaceKeyRefreshProvider, type WorkspaceOpenProvider, type WsAuthMessage, type WsAuthResultMessage, type WsBatchCompleteMessage, type WsConnectionClosedMessage, type WsConversationMessagePostedMessage, type WsErrorMessage, type WsNotificationResponse, type WsPresenceUpdateMessage, type WsResponseCompleteMessage, type WsTaskUpdateMessage, base64Decode, base64Encode, base64ToBytes, buildCallFragment, buildWebSocketUrl, bytesToBase64, canPersistSession, changePassword, clearAllData, clearSession, type components, computeSharedSecret, createArbiClient, createAuthMessage, createAutoReloginMiddleware, createBearerAuthMiddleware, createContentHash, createReloginHandler, createSessionManager, createWorkspaceReopener, decodeCallKey, decryptCallTitle, decryptFile, decryptMessage, decryptMessageWithSharedSecret, deriveEncryptionKeypairFromSigning, derivePublicKey, encodeCallKey, encryptCallTitle, encryptFile, encryptMessage, encryptMessageWithSharedSecret, generateCallKey, generateIdentityKeypair, generateKeyPairs, generateLoginCredentials, generateLoginCredentialsFromKey, generatePasswordChangeCredentials, generateRandomSigningKeypair, generateRegistrationCredentials, generateUserKeypairs, getSession, getUserEncryptionKeypair, hasSession, identityFromLoginResponse, initSodium, initializeDatabase, isMessageType, openSealedCallKey, type operations, parseCallFragment, parseServerMessage, passwordChangeErrorMessage, type paths, prewarmKeyPairs, saveSession, sealCallKey, sealKeyForSession, sealedBoxDecrypt, sealedBoxEncrypt, signMessage, unlockIdentityWithPassword, unwrapIdentityKey, updateWrappedIdentityKey, type webhooks, wrapIdentityKey };