@arbidocs/client 0.4.2 → 0.4.4

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
@@ -17199,6 +17199,13 @@ interface AutoReloginMiddlewareConfig {
17199
17199
  reloginHandler: ReloginHandler;
17200
17200
  /** URL substrings that should never trigger re-login (e.g. the login endpoint itself) */
17201
17201
  reloginExcludePatterns?: string[];
17202
+ /**
17203
+ * Re-open the selected workspace on the server session without a new login. Resolves true when
17204
+ * done. Used on 400 "No active workspace" (the server lost the open-workspace state while the
17205
+ * token is still valid); when it is absent or returns false, a full re-login (which also
17206
+ * re-opens the workspace) is tried instead.
17207
+ */
17208
+ reopenWorkspaceHandler?: () => Promise<boolean>;
17202
17209
  onRetryCloneFailed?: () => void;
17203
17210
  /** Called when re-login was attempted but failed (returned null). Use to clear stale auth state. */
17204
17211
  onReloginFailed?: () => void;
@@ -17815,6 +17822,13 @@ interface ArbiClientOptions {
17815
17822
  userExtId?: string;
17816
17823
  serverSessionKey: Uint8Array;
17817
17824
  }) => void;
17825
+ /**
17826
+ * Called when the session cannot be recovered: a request failed with 401 (or 400 "No active
17827
+ * workspace") and neither a workspace re-open nor a silent re-login worked because the server
17828
+ * REFUSED it (not a network failure, which leaves the session alone). The host shows "your
17829
+ * session expired, sign in again". Not called before anyone has logged in.
17830
+ */
17831
+ onSessionExpired?: () => void;
17818
17832
  /**
17819
17833
  * Optional session storage provider for the relogin handler.
17820
17834
  *
@@ -17844,8 +17858,10 @@ interface ArbiClient {
17844
17858
  loginWithKey(params: LoginWithKeyParams): Promise<LoginResult>;
17845
17859
  logout(): Promise<void>;
17846
17860
  changePassword(params: ChangePasswordParams): Promise<ChangePasswordResult>;
17847
- /** Instant re-login using stored private key */
17861
+ /** Instant re-login using stored private key (re-opens the selected workspace too) */
17848
17862
  relogin(): Promise<string | null>;
17863
+ /** Re-open the selected workspace on the server session, without a new login */
17864
+ reopenWorkspace(): Promise<boolean>;
17849
17865
  };
17850
17866
  /** Crypto utilities */
17851
17867
  crypto: {
@@ -17967,4 +17983,29 @@ declare function isMessageType<T extends WebSocketServerMessage>(msg: WebSocketS
17967
17983
  */
17968
17984
  declare function createReloginHandler(deps: ReloginDeps): () => Promise<string | null>;
17969
17985
 
17970
- export { type $defs, API_PREFIX, type ArbiClient, type ArbiClientOptions, type AuthStateProvider, type AutoReloginMiddlewareConfig, type BearerAuthMiddlewareConfig, type ChangePasswordParams, type ChangePasswordRequest, type ChangePasswordResult, type CryptoProvider, type KeyPair, type LoginCredentials, type LoginParams, 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 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 WsErrorMessage, type WsNotificationResponse, type WsPresenceUpdateMessage, type WsResponseCompleteMessage, type WsTaskUpdateMessage, base64Decode, base64Encode, base64ToBytes, buildWebSocketUrl, bytesToBase64, clearAllData, clearSession, type components, computeSharedSecret, createArbiClient, createAuthMessage, createAutoReloginMiddleware, createBearerAuthMiddleware, createContentHash, createReloginHandler, createSessionManager, decryptFile, decryptMessage, decryptMessageWithSharedSecret, deriveEncryptionKeypairFromSigning, derivePublicKey, encryptFile, encryptMessage, encryptMessageWithSharedSecret, generateKeyPairs, generateLoginCredentials, generateLoginCredentialsFromKey, generatePasswordChangeCredentials, generateRandomSigningKeypair, generateRecoveryPasswordChangeCredentials, generateRegistrationCredentials, generateUserKeypairs, getSession, getUserEncryptionKeypair, hasSession, initSodium, initializeDatabase, isMessageType, type operations, parseServerMessage, type paths, prewarmKeyPairs, saveSession, sealKeyForSession, sealedBoxDecrypt, sealedBoxEncrypt, signMessage, updateSigningPrivateKey, type webhooks };
17986
+ /**
17987
+ * Workspace re-open (no re-login)
17988
+ *
17989
+ * The server keeps "which workspace is open, and its key sealed for this session" on the session.
17990
+ * When that state is gone while the access token is still valid (a server restart, a rotated
17991
+ * session, an expired workspace session), requests fail with 400 "No active workspace - call
17992
+ * /open first". Re-opening needs no new login: unwrap the workspace key with the stored signing
17993
+ * key, seal it for the stored server session key, POST /open.
17994
+ */
17995
+
17996
+ interface ReopenDeps {
17997
+ crypto: Pick<CryptoProvider, 'ensureReady' | 'deriveEncryptionKeypair' | 'sealedBoxDecrypt' | 'sealKeyForSession'>;
17998
+ sessionStorage: SessionStorageProvider;
17999
+ authState: Pick<AuthStateProvider, 'getSelectedWorkspaceId'>;
18000
+ getAccessToken(): string | null;
18001
+ workspaceKeyRefreshProvider: WorkspaceKeyRefreshProvider;
18002
+ workspaceOpenProvider: WorkspaceOpenProvider;
18003
+ }
18004
+ /**
18005
+ * Returns `reopenWorkspace()`: resolves true when the selected workspace is open again on the
18006
+ * server session, false when it cannot be (nothing selected, no stored keys, server refused).
18007
+ * Concurrent calls share one in-flight attempt.
18008
+ */
18009
+ declare function createWorkspaceReopener(deps: ReopenDeps): () => Promise<boolean>;
18010
+
18011
+ export { type $defs, API_PREFIX, type ArbiClient, type ArbiClientOptions, type AuthStateProvider, type AutoReloginMiddlewareConfig, type BearerAuthMiddlewareConfig, type ChangePasswordParams, type ChangePasswordRequest, type ChangePasswordResult, type CryptoProvider, type KeyPair, type LoginCredentials, type LoginParams, 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 WsErrorMessage, type WsNotificationResponse, type WsPresenceUpdateMessage, type WsResponseCompleteMessage, type WsTaskUpdateMessage, base64Decode, base64Encode, base64ToBytes, buildWebSocketUrl, bytesToBase64, clearAllData, clearSession, type components, computeSharedSecret, createArbiClient, createAuthMessage, createAutoReloginMiddleware, createBearerAuthMiddleware, createContentHash, createReloginHandler, createSessionManager, createWorkspaceReopener, decryptFile, decryptMessage, decryptMessageWithSharedSecret, deriveEncryptionKeypairFromSigning, derivePublicKey, encryptFile, encryptMessage, encryptMessageWithSharedSecret, generateKeyPairs, generateLoginCredentials, generateLoginCredentialsFromKey, generatePasswordChangeCredentials, generateRandomSigningKeypair, generateRecoveryPasswordChangeCredentials, generateRegistrationCredentials, generateUserKeypairs, getSession, getUserEncryptionKeypair, hasSession, initSodium, initializeDatabase, isMessageType, type operations, parseServerMessage, type paths, prewarmKeyPairs, saveSession, sealKeyForSession, sealedBoxDecrypt, sealedBoxEncrypt, signMessage, updateSigningPrivateKey, type webhooks };
package/dist/index.d.ts CHANGED
@@ -17199,6 +17199,13 @@ interface AutoReloginMiddlewareConfig {
17199
17199
  reloginHandler: ReloginHandler;
17200
17200
  /** URL substrings that should never trigger re-login (e.g. the login endpoint itself) */
17201
17201
  reloginExcludePatterns?: string[];
17202
+ /**
17203
+ * Re-open the selected workspace on the server session without a new login. Resolves true when
17204
+ * done. Used on 400 "No active workspace" (the server lost the open-workspace state while the
17205
+ * token is still valid); when it is absent or returns false, a full re-login (which also
17206
+ * re-opens the workspace) is tried instead.
17207
+ */
17208
+ reopenWorkspaceHandler?: () => Promise<boolean>;
17202
17209
  onRetryCloneFailed?: () => void;
17203
17210
  /** Called when re-login was attempted but failed (returned null). Use to clear stale auth state. */
17204
17211
  onReloginFailed?: () => void;
@@ -17815,6 +17822,13 @@ interface ArbiClientOptions {
17815
17822
  userExtId?: string;
17816
17823
  serverSessionKey: Uint8Array;
17817
17824
  }) => void;
17825
+ /**
17826
+ * Called when the session cannot be recovered: a request failed with 401 (or 400 "No active
17827
+ * workspace") and neither a workspace re-open nor a silent re-login worked because the server
17828
+ * REFUSED it (not a network failure, which leaves the session alone). The host shows "your
17829
+ * session expired, sign in again". Not called before anyone has logged in.
17830
+ */
17831
+ onSessionExpired?: () => void;
17818
17832
  /**
17819
17833
  * Optional session storage provider for the relogin handler.
17820
17834
  *
@@ -17844,8 +17858,10 @@ interface ArbiClient {
17844
17858
  loginWithKey(params: LoginWithKeyParams): Promise<LoginResult>;
17845
17859
  logout(): Promise<void>;
17846
17860
  changePassword(params: ChangePasswordParams): Promise<ChangePasswordResult>;
17847
- /** Instant re-login using stored private key */
17861
+ /** Instant re-login using stored private key (re-opens the selected workspace too) */
17848
17862
  relogin(): Promise<string | null>;
17863
+ /** Re-open the selected workspace on the server session, without a new login */
17864
+ reopenWorkspace(): Promise<boolean>;
17849
17865
  };
17850
17866
  /** Crypto utilities */
17851
17867
  crypto: {
@@ -17967,4 +17983,29 @@ declare function isMessageType<T extends WebSocketServerMessage>(msg: WebSocketS
17967
17983
  */
17968
17984
  declare function createReloginHandler(deps: ReloginDeps): () => Promise<string | null>;
17969
17985
 
17970
- export { type $defs, API_PREFIX, type ArbiClient, type ArbiClientOptions, type AuthStateProvider, type AutoReloginMiddlewareConfig, type BearerAuthMiddlewareConfig, type ChangePasswordParams, type ChangePasswordRequest, type ChangePasswordResult, type CryptoProvider, type KeyPair, type LoginCredentials, type LoginParams, 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 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 WsErrorMessage, type WsNotificationResponse, type WsPresenceUpdateMessage, type WsResponseCompleteMessage, type WsTaskUpdateMessage, base64Decode, base64Encode, base64ToBytes, buildWebSocketUrl, bytesToBase64, clearAllData, clearSession, type components, computeSharedSecret, createArbiClient, createAuthMessage, createAutoReloginMiddleware, createBearerAuthMiddleware, createContentHash, createReloginHandler, createSessionManager, decryptFile, decryptMessage, decryptMessageWithSharedSecret, deriveEncryptionKeypairFromSigning, derivePublicKey, encryptFile, encryptMessage, encryptMessageWithSharedSecret, generateKeyPairs, generateLoginCredentials, generateLoginCredentialsFromKey, generatePasswordChangeCredentials, generateRandomSigningKeypair, generateRecoveryPasswordChangeCredentials, generateRegistrationCredentials, generateUserKeypairs, getSession, getUserEncryptionKeypair, hasSession, initSodium, initializeDatabase, isMessageType, type operations, parseServerMessage, type paths, prewarmKeyPairs, saveSession, sealKeyForSession, sealedBoxDecrypt, sealedBoxEncrypt, signMessage, updateSigningPrivateKey, type webhooks };
17986
+ /**
17987
+ * Workspace re-open (no re-login)
17988
+ *
17989
+ * The server keeps "which workspace is open, and its key sealed for this session" on the session.
17990
+ * When that state is gone while the access token is still valid (a server restart, a rotated
17991
+ * session, an expired workspace session), requests fail with 400 "No active workspace - call
17992
+ * /open first". Re-opening needs no new login: unwrap the workspace key with the stored signing
17993
+ * key, seal it for the stored server session key, POST /open.
17994
+ */
17995
+
17996
+ interface ReopenDeps {
17997
+ crypto: Pick<CryptoProvider, 'ensureReady' | 'deriveEncryptionKeypair' | 'sealedBoxDecrypt' | 'sealKeyForSession'>;
17998
+ sessionStorage: SessionStorageProvider;
17999
+ authState: Pick<AuthStateProvider, 'getSelectedWorkspaceId'>;
18000
+ getAccessToken(): string | null;
18001
+ workspaceKeyRefreshProvider: WorkspaceKeyRefreshProvider;
18002
+ workspaceOpenProvider: WorkspaceOpenProvider;
18003
+ }
18004
+ /**
18005
+ * Returns `reopenWorkspace()`: resolves true when the selected workspace is open again on the
18006
+ * server session, false when it cannot be (nothing selected, no stored keys, server refused).
18007
+ * Concurrent calls share one in-flight attempt.
18008
+ */
18009
+ declare function createWorkspaceReopener(deps: ReopenDeps): () => Promise<boolean>;
18010
+
18011
+ export { type $defs, API_PREFIX, type ArbiClient, type ArbiClientOptions, type AuthStateProvider, type AutoReloginMiddlewareConfig, type BearerAuthMiddlewareConfig, type ChangePasswordParams, type ChangePasswordRequest, type ChangePasswordResult, type CryptoProvider, type KeyPair, type LoginCredentials, type LoginParams, 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 WsErrorMessage, type WsNotificationResponse, type WsPresenceUpdateMessage, type WsResponseCompleteMessage, type WsTaskUpdateMessage, base64Decode, base64Encode, base64ToBytes, buildWebSocketUrl, bytesToBase64, clearAllData, clearSession, type components, computeSharedSecret, createArbiClient, createAuthMessage, createAutoReloginMiddleware, createBearerAuthMiddleware, createContentHash, createReloginHandler, createSessionManager, createWorkspaceReopener, decryptFile, decryptMessage, decryptMessageWithSharedSecret, deriveEncryptionKeypairFromSigning, derivePublicKey, encryptFile, encryptMessage, encryptMessageWithSharedSecret, generateKeyPairs, generateLoginCredentials, generateLoginCredentialsFromKey, generatePasswordChangeCredentials, generateRandomSigningKeypair, generateRecoveryPasswordChangeCredentials, generateRegistrationCredentials, generateUserKeypairs, getSession, getUserEncryptionKeypair, hasSession, initSodium, initializeDatabase, isMessageType, type operations, parseServerMessage, type paths, prewarmKeyPairs, saveSession, sealKeyForSession, sealedBoxDecrypt, sealedBoxEncrypt, signMessage, updateSigningPrivateKey, type webhooks };
package/dist/index.js CHANGED
@@ -385,6 +385,21 @@ function createBearerAuthMiddleware(config) {
385
385
  }
386
386
 
387
387
  // src/middleware/auto-relogin.ts
388
+ var NO_ACTIVE_WORKSPACE = /no active workspace/i;
389
+ async function isNoActiveWorkspace(response) {
390
+ try {
391
+ return NO_ACTIVE_WORKSPACE.test(await response.clone().text());
392
+ } catch {
393
+ return false;
394
+ }
395
+ }
396
+ function safeClone(request) {
397
+ try {
398
+ return request.clone();
399
+ } catch {
400
+ return null;
401
+ }
402
+ }
388
403
  function createAutoReloginMiddleware(config) {
389
404
  const cloneCache = /* @__PURE__ */ new WeakMap();
390
405
  return {
@@ -395,6 +410,25 @@ function createAutoReloginMiddleware(config) {
395
410
  }
396
411
  },
397
412
  async onResponse({ response, request }) {
413
+ if (response.status === 400 && await isNoActiveWorkspace(response)) {
414
+ let token = null;
415
+ let recovered = await config.reopenWorkspaceHandler?.() ?? false;
416
+ if (!recovered) {
417
+ token = await config.reloginHandler();
418
+ recovered = token !== null;
419
+ }
420
+ if (!recovered) {
421
+ config.onReloginFailed?.();
422
+ return response;
423
+ }
424
+ const retry = cloneCache.get(request) ?? safeClone(request);
425
+ if (retry) {
426
+ if (token) retry.headers.set("Authorization", `Bearer ${token}`);
427
+ return fetch(retry);
428
+ }
429
+ config.onRetryCloneFailed?.();
430
+ return response;
431
+ }
398
432
  if (response.status === 400) {
399
433
  const isSafeMethod = ["GET", "HEAD", "DELETE"].includes(request.method);
400
434
  if (isSafeMethod) {
@@ -555,6 +589,47 @@ function createReloginHandler(deps) {
555
589
  };
556
590
  }
557
591
 
592
+ // src/relogin/reopen.ts
593
+ function createWorkspaceReopener(deps) {
594
+ let inFlight = null;
595
+ return function reopenWorkspace() {
596
+ if (inFlight) return inFlight;
597
+ inFlight = (async () => {
598
+ try {
599
+ const workspaceId = deps.authState.getSelectedWorkspaceId();
600
+ const accessToken = deps.getAccessToken();
601
+ if (!workspaceId || !accessToken) return false;
602
+ const session = await deps.sessionStorage.getSession();
603
+ if (!session?.signingPrivateKey || !session.serverSessionKey) return false;
604
+ await deps.crypto.ensureReady();
605
+ const wrappedKey = await deps.workspaceKeyRefreshProvider.getWrappedKey(
606
+ accessToken,
607
+ workspaceId
608
+ );
609
+ if (!wrappedKey) return false;
610
+ const encryptionKeyPair = deps.crypto.deriveEncryptionKeypair({
611
+ publicKey: session.signingPrivateKey.slice(32, 64),
612
+ secretKey: session.signingPrivateKey
613
+ });
614
+ const workspaceKey = deps.crypto.sealedBoxDecrypt(wrappedKey, encryptionKeyPair.secretKey);
615
+ const sealed = await deps.crypto.sealKeyForSession(workspaceKey, session.serverSessionKey);
616
+ const opened = await deps.workspaceOpenProvider.openWorkspace(
617
+ accessToken,
618
+ workspaceId,
619
+ sealed
620
+ );
621
+ return opened === true;
622
+ } catch (error) {
623
+ console.error("[API] Failed to re-open workspace:", error);
624
+ return false;
625
+ } finally {
626
+ inFlight = null;
627
+ }
628
+ })();
629
+ return inFlight;
630
+ };
631
+ }
632
+
558
633
  // src/storage/indexed-db.ts
559
634
  var DB_NAME = "arbi-crypto";
560
635
  var DB_VERSION = 2;
@@ -1002,6 +1077,7 @@ function createArbiClient(options) {
1002
1077
  credentials = "include",
1003
1078
  ssoTokenProvider = null,
1004
1079
  onReloginSuccess,
1080
+ onSessionExpired,
1005
1081
  sessionStorage: sessionStorageOverride,
1006
1082
  userEmail
1007
1083
  } = options;
@@ -1022,6 +1098,7 @@ function createArbiClient(options) {
1022
1098
  sealKeyForSession,
1023
1099
  fromBase64: base64ToBytes
1024
1100
  };
1101
+ let reloginUnreachable = false;
1025
1102
  const loginProvider = {
1026
1103
  async login(payload) {
1027
1104
  const rawFetch = createFetchClient({
@@ -1029,14 +1106,21 @@ function createArbiClient(options) {
1029
1106
  credentials,
1030
1107
  fetch: retryFetch
1031
1108
  });
1032
- const response = await rawFetch.POST("/v1/user/login", {
1033
- body: {
1034
- email: payload.email,
1035
- signature: payload.signature,
1036
- timestamp: payload.timestamp,
1037
- sso_token: payload.ssoToken
1038
- }
1039
- });
1109
+ let response;
1110
+ try {
1111
+ response = await rawFetch.POST("/v1/user/login", {
1112
+ body: {
1113
+ email: payload.email,
1114
+ signature: payload.signature,
1115
+ timestamp: payload.timestamp,
1116
+ sso_token: payload.ssoToken
1117
+ }
1118
+ });
1119
+ } catch (error) {
1120
+ console.warn("[API] Login call unreachable:", error);
1121
+ reloginUnreachable = true;
1122
+ return null;
1123
+ }
1040
1124
  if (response.error || !response.data) {
1041
1125
  console.warn("[API] Login call failed:", response.error);
1042
1126
  return null;
@@ -1067,15 +1151,46 @@ function createArbiClient(options) {
1067
1151
  return workspace?.wrapped_key ?? null;
1068
1152
  }
1069
1153
  };
1070
- const reloginHandler = createReloginHandler({
1154
+ const workspaceOpenProvider = {
1155
+ async openWorkspace(accessToken, workspaceId, encryptedWorkspaceKey) {
1156
+ try {
1157
+ const response = await retryFetch(`${baseUrl}${API_PREFIX}/workspace/${workspaceId}/open`, {
1158
+ method: "POST",
1159
+ headers: {
1160
+ Authorization: `Bearer ${accessToken}`,
1161
+ "Content-Type": "application/json"
1162
+ },
1163
+ body: JSON.stringify({ workspace_key: encryptedWorkspaceKey }),
1164
+ credentials
1165
+ });
1166
+ return response.ok ? true : null;
1167
+ } catch {
1168
+ return null;
1169
+ }
1170
+ }
1171
+ };
1172
+ const rawReloginHandler = createReloginHandler({
1071
1173
  crypto: cryptoProvider,
1072
1174
  sessionStorage,
1073
1175
  authState,
1074
1176
  ssoTokenProvider,
1075
1177
  loginProvider,
1076
1178
  workspaceKeyRefreshProvider,
1179
+ workspaceOpenProvider,
1077
1180
  onReloginSuccess
1078
1181
  });
1182
+ const reloginHandler = () => {
1183
+ reloginUnreachable = false;
1184
+ return rawReloginHandler();
1185
+ };
1186
+ const reopenWorkspace = createWorkspaceReopener({
1187
+ crypto: cryptoProvider,
1188
+ sessionStorage,
1189
+ authState,
1190
+ getAccessToken: () => session.getState().accessToken,
1191
+ workspaceKeyRefreshProvider,
1192
+ workspaceOpenProvider
1193
+ });
1079
1194
  const fetchClient = createFetchClient({
1080
1195
  baseUrl,
1081
1196
  credentials,
@@ -1085,7 +1200,11 @@ function createArbiClient(options) {
1085
1200
  fetchClient.use(
1086
1201
  createAutoReloginMiddleware({
1087
1202
  reloginHandler,
1088
- reloginExcludePatterns
1203
+ reloginExcludePatterns,
1204
+ reopenWorkspaceHandler: reopenWorkspace,
1205
+ onReloginFailed: () => {
1206
+ if (!reloginUnreachable && session.getState().userEmail) onSessionExpired?.();
1207
+ }
1089
1208
  })
1090
1209
  );
1091
1210
  const authDeps = {
@@ -1102,7 +1221,8 @@ function createArbiClient(options) {
1102
1221
  loginWithKey: (params) => loginWithKey(params, authDeps),
1103
1222
  logout: () => logout(session),
1104
1223
  changePassword: (params) => changePassword(params, authDeps),
1105
- relogin: reloginHandler
1224
+ relogin: reloginHandler,
1225
+ reopenWorkspace
1106
1226
  },
1107
1227
  crypto: {
1108
1228
  initSodium,
@@ -1156,6 +1276,6 @@ function isMessageType(msg, type) {
1156
1276
  return msg.type === type;
1157
1277
  }
1158
1278
 
1159
- export { API_PREFIX, base64Decode, base64Encode, base64ToBytes, buildWebSocketUrl, bytesToBase64, clearAllData, clearSession, computeSharedSecret, createArbiClient, createAuthMessage, createAutoReloginMiddleware, createBearerAuthMiddleware, createContentHash, createReloginHandler, createSessionManager, decryptFile, decryptMessage, decryptMessageWithSharedSecret, deriveEncryptionKeypairFromSigning, derivePublicKey, encryptFile, encryptMessage, encryptMessageWithSharedSecret, generateKeyPairs, generateLoginCredentials, generateLoginCredentialsFromKey, generatePasswordChangeCredentials, generateRandomSigningKeypair, generateRecoveryPasswordChangeCredentials, generateRegistrationCredentials, generateUserKeypairs, getSession, getUserEncryptionKeypair, hasSession, initSodium, initializeDatabase, isMessageType, parseServerMessage, prewarmKeyPairs, saveSession, sealKeyForSession, sealedBoxDecrypt, sealedBoxEncrypt, signMessage, updateSigningPrivateKey };
1279
+ export { API_PREFIX, base64Decode, base64Encode, base64ToBytes, buildWebSocketUrl, bytesToBase64, clearAllData, clearSession, computeSharedSecret, createArbiClient, createAuthMessage, createAutoReloginMiddleware, createBearerAuthMiddleware, createContentHash, createReloginHandler, createSessionManager, createWorkspaceReopener, decryptFile, decryptMessage, decryptMessageWithSharedSecret, deriveEncryptionKeypairFromSigning, derivePublicKey, encryptFile, encryptMessage, encryptMessageWithSharedSecret, generateKeyPairs, generateLoginCredentials, generateLoginCredentialsFromKey, generatePasswordChangeCredentials, generateRandomSigningKeypair, generateRecoveryPasswordChangeCredentials, generateRegistrationCredentials, generateUserKeypairs, getSession, getUserEncryptionKeypair, hasSession, initSodium, initializeDatabase, isMessageType, parseServerMessage, prewarmKeyPairs, saveSession, sealKeyForSession, sealedBoxDecrypt, sealedBoxEncrypt, signMessage, updateSigningPrivateKey };
1160
1280
  //# sourceMappingURL=index.js.map
1161
1281
  //# sourceMappingURL=index.js.map