@arbidocs/client 0.4.167 → 0.4.169

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.js CHANGED
@@ -4,55 +4,67 @@ import sodium from 'libsodium-wrappers-sumo';
4
4
  // src/client.ts
5
5
 
6
6
  // src/session.ts
7
- function createInitialState() {
7
+ function createInitialState(isSsoMode = false) {
8
8
  return {
9
9
  accessToken: null,
10
10
  userEmail: null,
11
11
  userExtId: null,
12
12
  selectedWorkspaceId: null,
13
- isSsoMode: false,
14
- isAuth0Authenticated: false,
15
- auth0AccessToken: null
13
+ isSsoMode,
14
+ user: null,
15
+ signedIn: false,
16
+ serverSessionKey: null
16
17
  };
17
18
  }
18
- function createSessionManager() {
19
- let state = createInitialState();
19
+ var stored = (s) => ({
20
+ accessToken: s.accessToken,
21
+ userEmail: s.userEmail,
22
+ userExtId: s.userExtId,
23
+ isSsoMode: s.isSsoMode,
24
+ user: s.user,
25
+ signedIn: s.signedIn
26
+ });
27
+ function createSessionManager(options = {}) {
28
+ const { storage } = options;
29
+ let state = { ...createInitialState(), ...storage?.load() ?? {} };
20
30
  const listeners = /* @__PURE__ */ new Set();
21
- function notify() {
22
- const snapshot = { ...state };
23
- for (const listener of listeners) {
24
- listener(snapshot);
25
- }
31
+ function update(patch) {
32
+ state = { ...state, ...patch };
33
+ storage?.save(stored(state));
34
+ const snapshot = state;
35
+ for (const listener of [...listeners]) listener(snapshot);
26
36
  }
27
37
  return {
28
- getState() {
29
- return state;
30
- },
31
- setAccessToken(token) {
32
- state = { ...state, accessToken: token };
33
- notify();
34
- },
38
+ getState: () => state,
39
+ setAccessToken: (accessToken) => update({ accessToken }),
35
40
  setUser(email, extId) {
36
- state = { ...state, userEmail: email, userExtId: extId ?? state.userExtId };
37
- notify();
38
- },
39
- setSelectedWorkspace(id) {
40
- state = { ...state, selectedWorkspaceId: id };
41
- notify();
41
+ update({
42
+ userEmail: email,
43
+ userExtId: extId ?? state.userExtId,
44
+ user: state.user ? { ...state.user, email } : null
45
+ });
42
46
  },
43
- setSsoState(opts) {
44
- state = {
45
- ...state,
46
- isSsoMode: opts.isSsoMode ?? state.isSsoMode,
47
- isAuth0Authenticated: opts.isAuth0Authenticated ?? state.isAuth0Authenticated,
48
- auth0AccessToken: opts.auth0AccessToken !== void 0 ? opts.auth0AccessToken : state.auth0AccessToken
49
- };
50
- notify();
47
+ updateUser(patch) {
48
+ if (!state.user) return;
49
+ const user = { ...state.user, ...patch };
50
+ update({ user, userEmail: user.email });
51
51
  },
52
- clear() {
53
- state = createInitialState();
54
- notify();
52
+ setSelectedWorkspace: (selectedWorkspaceId) => update({ selectedWorkspaceId }),
53
+ setSsoMode: (isSsoMode) => update({ isSsoMode }),
54
+ setServerSessionKey: (serverSessionKey) => update({ serverSessionKey }),
55
+ signIn({ accessToken, user, isSsoMode, serverSessionKey }) {
56
+ update({
57
+ accessToken,
58
+ user,
59
+ userEmail: user.email,
60
+ userExtId: user.external_id,
61
+ isSsoMode,
62
+ serverSessionKey,
63
+ signedIn: true
64
+ });
55
65
  },
66
+ // The SSO mode outlives a sign-out: it says how this deployment (or this user) signs in.
67
+ clear: () => update(createInitialState(state.isSsoMode)),
56
68
  subscribe(listener) {
57
69
  listeners.add(listener);
58
70
  return () => {
@@ -61,23 +73,41 @@ function createSessionManager() {
61
73
  }
62
74
  };
63
75
  }
76
+ var ACCESS_TOKEN_STORAGE_KEY = "arbi_access_token";
77
+ var SESSION_STORAGE_KEY = "arbi_session";
78
+ function browserSessionStateStorage() {
79
+ return {
80
+ load() {
81
+ try {
82
+ const rest = JSON.parse(window.localStorage.getItem(SESSION_STORAGE_KEY) ?? "null");
83
+ const accessToken = window.sessionStorage.getItem(ACCESS_TOKEN_STORAGE_KEY);
84
+ return { ...rest ?? {}, accessToken };
85
+ } catch {
86
+ return null;
87
+ }
88
+ },
89
+ save({ accessToken, ...rest }) {
90
+ try {
91
+ if (accessToken) window.sessionStorage.setItem(ACCESS_TOKEN_STORAGE_KEY, accessToken);
92
+ else window.sessionStorage.removeItem(ACCESS_TOKEN_STORAGE_KEY);
93
+ if (rest.signedIn || rest.isSsoMode)
94
+ window.localStorage.setItem(SESSION_STORAGE_KEY, JSON.stringify(rest));
95
+ else window.localStorage.removeItem(SESSION_STORAGE_KEY);
96
+ } catch {
97
+ }
98
+ }
99
+ };
100
+ }
64
101
  function createTokenProvider(session) {
65
102
  return {
66
103
  getAccessToken: () => session.getState().accessToken
67
104
  };
68
105
  }
69
- function createAuthStateProvider(session) {
106
+ function createAuthStateProvider(session, selectedWorkspace = () => session.getState().selectedWorkspaceId) {
70
107
  return {
71
108
  getUserEmail: () => session.getState().userEmail,
72
- getSsoState: () => {
73
- const s = session.getState();
74
- return {
75
- isSsoMode: s.isSsoMode,
76
- isAuth0Authenticated: s.isAuth0Authenticated,
77
- auth0AccessToken: s.auth0AccessToken
78
- };
79
- },
80
- getSelectedWorkspaceId: () => session.getState().selectedWorkspaceId,
109
+ isSsoMode: () => session.getState().isSsoMode,
110
+ getSelectedWorkspaceId: selectedWorkspace,
81
111
  setAccessToken: (token) => session.setAccessToken(token)
82
112
  };
83
113
  }
@@ -356,6 +386,25 @@ function parseCallFragment(hash) {
356
386
  const v = Number(params.get("v"));
357
387
  return { key, linkVersion: Number.isInteger(v) && v > 0 ? v : null };
358
388
  }
389
+ function buildCallLink(origin, callExtId, key, linkVersion) {
390
+ return `${origin}/call/${callExtId}#${buildCallFragment(key, linkVersion)}`;
391
+ }
392
+ async function sealCallKeyForPeers(key, peers, exclude) {
393
+ const out = {};
394
+ for (const peer of peers) {
395
+ if (!peer.encryption_public_key || peer.external_id === exclude) continue;
396
+ out[peer.external_id] = await sealCallKey(key, peer.encryption_public_key);
397
+ }
398
+ return out;
399
+ }
400
+ async function openCallKeyOf(call, encryptionSecretKey) {
401
+ if (!call.my_sealed_key) return null;
402
+ try {
403
+ return await openSealedCallKey(call.my_sealed_key, encryptionSecretKey);
404
+ } catch {
405
+ return null;
406
+ }
407
+ }
359
408
  var CHAT_KEY_BYTES = 32;
360
409
  async function deriveDirectChatKey(peerPublicKeyBase64, mySecretKey) {
361
410
  await initSodium();
@@ -1060,8 +1109,126 @@ function createBearerAuthMiddleware(config) {
1060
1109
  };
1061
1110
  }
1062
1111
 
1112
+ // src/workspace-keys.ts
1113
+ function createWorkspaceKeys(deps) {
1114
+ const wrapped = /* @__PURE__ */ new Map();
1115
+ const keyless = /* @__PURE__ */ new Set();
1116
+ let listing = null;
1117
+ const primed = /* @__PURE__ */ new Map();
1118
+ let primedFor = null;
1119
+ function remember(workspaces) {
1120
+ for (const ws of workspaces) {
1121
+ if (ws.wrapped_key) {
1122
+ wrapped.set(ws.external_id, ws.wrapped_key);
1123
+ keyless.delete(ws.external_id);
1124
+ } else if (ws.is_public || ws.is_member) keyless.add(ws.external_id);
1125
+ }
1126
+ return workspaces;
1127
+ }
1128
+ function readList() {
1129
+ listing ??= (async () => {
1130
+ try {
1131
+ const token = deps.getAccessToken();
1132
+ if (!token) throw new Error("Not signed in");
1133
+ const list = await deps.listWorkspaces(token);
1134
+ if (!list) throw new Error("Failed to fetch workspaces");
1135
+ remember(list);
1136
+ } finally {
1137
+ listing = null;
1138
+ }
1139
+ })();
1140
+ return listing;
1141
+ }
1142
+ async function wrappedKey(workspaceId, { refresh = false } = {}) {
1143
+ if (!refresh) {
1144
+ const cached = wrapped.get(workspaceId);
1145
+ if (cached) return { wrappedKey: cached, fromCache: true };
1146
+ if (keyless.has(workspaceId)) return { wrappedKey: null, fromCache: true };
1147
+ }
1148
+ wrapped.delete(workspaceId);
1149
+ keyless.delete(workspaceId);
1150
+ await readList();
1151
+ const fresh = wrapped.get(workspaceId);
1152
+ if (fresh) return { wrappedKey: fresh, fromCache: false };
1153
+ if (keyless.has(workspaceId)) return { wrappedKey: null, fromCache: false };
1154
+ throw new Error(`Workspace ${workspaceId} not found or has no encryption key`);
1155
+ }
1156
+ async function sealedFor(workspaceId, serverSessionKey2, refresh) {
1157
+ const stored2 = await deps.persistence.getSession();
1158
+ if (!stored2?.signingPrivateKey) throw new Error("No stored identity to unlock the workspace");
1159
+ const { wrappedKey: key, fromCache } = await wrappedKey(workspaceId, { refresh });
1160
+ if (!key) throw new Error(`Workspace ${workspaceId} is public: it has no key to deposit`);
1161
+ try {
1162
+ await deps.crypto.ensureReady();
1163
+ return await deps.crypto.sealKeyForSession(
1164
+ deps.unwrapWorkspaceKey(key, stored2.signingPrivateKey),
1165
+ serverSessionKey2
1166
+ );
1167
+ } catch (error) {
1168
+ if (!fromCache) throw error;
1169
+ return sealedFor(workspaceId, serverSessionKey2, true);
1170
+ }
1171
+ }
1172
+ async function serverSessionKey() {
1173
+ const key = deps.getServerSessionKey() ?? (await deps.persistence.getSession())?.serverSessionKey;
1174
+ if (!key) throw new Error("No server session to unlock the workspace for");
1175
+ return key;
1176
+ }
1177
+ function prime(workspaceId, { force = false } = {}) {
1178
+ const sessionKey = deps.getServerSessionKey();
1179
+ if (sessionKey !== primedFor) {
1180
+ primed.clear();
1181
+ primedFor = sessionKey;
1182
+ }
1183
+ const pending = primed.get(workspaceId);
1184
+ if (pending && !force) return pending;
1185
+ const run = (async () => {
1186
+ const token = deps.getAccessToken();
1187
+ if (!token) throw new Error("Not signed in");
1188
+ const sealed = await sealedFor(workspaceId, await serverSessionKey(), false);
1189
+ await deps.primeKey(token, workspaceId, sealed);
1190
+ })();
1191
+ primed.set(workspaceId, run);
1192
+ run.catch(() => {
1193
+ if (primed.get(workspaceId) === run) primed.delete(workspaceId);
1194
+ });
1195
+ return run;
1196
+ }
1197
+ return {
1198
+ remember,
1199
+ wrappedKey,
1200
+ prime,
1201
+ forget(workspaceIds) {
1202
+ for (const id of workspaceIds) {
1203
+ wrapped.delete(id);
1204
+ keyless.delete(id);
1205
+ primed.delete(id);
1206
+ }
1207
+ },
1208
+ clear() {
1209
+ wrapped.clear();
1210
+ keyless.clear();
1211
+ primed.clear();
1212
+ primedFor = null;
1213
+ }
1214
+ };
1215
+ }
1216
+ function workspaceKeyRequiredOf(body) {
1217
+ const detail = body?.detail;
1218
+ if (!detail || typeof detail !== "object") return null;
1219
+ const d = detail;
1220
+ return d.code === "workspace_key_required" && typeof d.workspace_ext_id === "string" ? d.workspace_ext_id : null;
1221
+ }
1222
+
1063
1223
  // src/middleware/auto-relogin.ts
1064
1224
  var NO_ACTIVE_WORKSPACE = /no active workspace/i;
1225
+ async function keyRequiredWorkspace(response) {
1226
+ try {
1227
+ return workspaceKeyRequiredOf(await response.clone().json());
1228
+ } catch {
1229
+ return null;
1230
+ }
1231
+ }
1065
1232
  async function isNoActiveWorkspace(response) {
1066
1233
  try {
1067
1234
  return NO_ACTIVE_WORKSPACE.test(await response.clone().text());
@@ -1086,6 +1253,16 @@ function createAutoReloginMiddleware(config) {
1086
1253
  }
1087
1254
  },
1088
1255
  async onResponse({ response, request }) {
1256
+ if (response.status === 409 && config.primeWorkspaceHandler) {
1257
+ const workspaceId = await keyRequiredWorkspace(response);
1258
+ if (workspaceId) {
1259
+ if (!await config.primeWorkspaceHandler(workspaceId)) return response;
1260
+ const retry = cloneCache.get(request) ?? safeClone(request);
1261
+ if (retry) return fetch(retry);
1262
+ config.onRetryCloneFailed?.();
1263
+ return response;
1264
+ }
1265
+ }
1089
1266
  if (response.status === 400 && await isNoActiveWorkspace(response)) {
1090
1267
  let token = null;
1091
1268
  let recovered = await config.reopenWorkspaceHandler?.() ?? false;
@@ -1093,10 +1270,7 @@ function createAutoReloginMiddleware(config) {
1093
1270
  token = await config.reloginHandler();
1094
1271
  recovered = token !== null;
1095
1272
  }
1096
- if (!recovered) {
1097
- config.onReloginFailed?.();
1098
- return response;
1099
- }
1273
+ if (!recovered) return response;
1100
1274
  const retry = cloneCache.get(request) ?? safeClone(request);
1101
1275
  if (retry) {
1102
1276
  if (token) retry.headers.set("Authorization", `Bearer ${token}`);
@@ -1135,8 +1309,6 @@ function createAutoReloginMiddleware(config) {
1135
1309
  console.warn("[API] Could not retry request after re-login (body already consumed)");
1136
1310
  config.onRetryCloneFailed?.();
1137
1311
  }
1138
- } else {
1139
- config.onReloginFailed?.();
1140
1312
  }
1141
1313
  }
1142
1314
  }
@@ -1162,15 +1334,20 @@ function createReloginHandler(deps) {
1162
1334
  const userEmail = deps.authState.getUserEmail();
1163
1335
  if (!userEmail) {
1164
1336
  console.warn("[API] Re-login aborted: no user email");
1337
+ deps.onReloginFailed?.("not-ready");
1165
1338
  return Promise.resolve(null);
1166
1339
  }
1340
+ const fail = (reason) => {
1341
+ deps.onReloginFailed?.(reason);
1342
+ return null;
1343
+ };
1167
1344
  reloginPromise = (async () => {
1168
1345
  try {
1169
1346
  await deps.crypto.ensureReady();
1170
- const session = await deps.sessionStorage.getSession();
1347
+ const session = await deps.persistence.getSession();
1171
1348
  if (!session) {
1172
1349
  console.warn("[API] Re-login aborted: no session");
1173
- return null;
1350
+ return fail("not-ready");
1174
1351
  }
1175
1352
  const ed25519PublicKey = session.signingPrivateKey.slice(32, 64);
1176
1353
  const encryptionKeyPair = deps.crypto.deriveEncryptionKeypair({
@@ -1180,22 +1357,17 @@ function createReloginHandler(deps) {
1180
1357
  const timestamp = Math.floor(Date.now() / 1e3);
1181
1358
  const message = `${userEmail}|${timestamp}`;
1182
1359
  const signature = deps.crypto.signMessage(message, session.signingPrivateKey);
1183
- const ssoState = deps.authState.getSsoState();
1184
- const isSsoAccount = ssoState.isSsoMode || ssoState.isAuth0Authenticated || !!ssoState.auth0AccessToken;
1185
1360
  let ssoToken = null;
1186
- if (deps.ssoTokenProvider) {
1361
+ if (deps.authState.isSsoMode()) {
1187
1362
  try {
1188
- ssoToken = await deps.ssoTokenProvider.getToken();
1363
+ ssoToken = await deps.sso?.getToken() ?? null;
1189
1364
  } catch (error) {
1190
- console.error("[API] Failed to get SSO token from provider:", error);
1365
+ console.error("[API] Failed to get SSO token:", error);
1366
+ }
1367
+ if (!ssoToken) {
1368
+ console.warn("[API] Re-login aborted: SSO account but no token available");
1369
+ return fail("refused");
1191
1370
  }
1192
- }
1193
- if (!ssoToken && ssoState.auth0AccessToken) {
1194
- ssoToken = ssoState.auth0AccessToken;
1195
- }
1196
- if (!ssoToken && isSsoAccount) {
1197
- console.warn("[API] Re-login aborted: SSO account but no token available");
1198
- return null;
1199
1371
  }
1200
1372
  const loginResult = await deps.loginProvider.login({
1201
1373
  email: userEmail,
@@ -1203,11 +1375,15 @@ function createReloginHandler(deps) {
1203
1375
  timestamp,
1204
1376
  ssoToken: ssoToken ?? void 0
1205
1377
  });
1378
+ if (loginResult === "unreachable") {
1379
+ console.warn("[API] Re-login failed: server unreachable");
1380
+ return fail("unreachable");
1381
+ }
1206
1382
  if (!loginResult) {
1207
1383
  console.warn("[API] Re-login failed");
1208
- return null;
1384
+ return fail("refused");
1209
1385
  }
1210
- await deps.sessionStorage.saveSession({
1386
+ await deps.persistence.saveSession({
1211
1387
  signingPrivateKey: session.signingPrivateKey,
1212
1388
  serverSessionKey: loginResult.sessionKey,
1213
1389
  userExtId: loginResult.userExtId,
@@ -1257,7 +1433,7 @@ function createReloginHandler(deps) {
1257
1433
  console.error("[API] Re-login error:", error);
1258
1434
  lastSuccessToken = null;
1259
1435
  lastSuccessTime = 0;
1260
- return null;
1436
+ return fail("refused");
1261
1437
  } finally {
1262
1438
  reloginPromise = null;
1263
1439
  }
@@ -1276,7 +1452,7 @@ function createWorkspaceReopener(deps) {
1276
1452
  const workspaceId = deps.authState.getSelectedWorkspaceId();
1277
1453
  const accessToken = deps.getAccessToken();
1278
1454
  if (!workspaceId || !accessToken) return false;
1279
- const session = await deps.sessionStorage.getSession();
1455
+ const session = await deps.persistence.getSession();
1280
1456
  if (!session?.signingPrivateKey || !session.serverSessionKey) return false;
1281
1457
  await deps.crypto.ensureReady();
1282
1458
  const wrappedKey = await deps.workspaceKeyRefreshProvider.getWrappedKey(
@@ -1306,29 +1482,56 @@ function createWorkspaceReopener(deps) {
1306
1482
  return inFlight;
1307
1483
  };
1308
1484
  }
1485
+ function createAllWorkspacesOpener(deps) {
1486
+ return async function openAllWorkspaces() {
1487
+ const accessToken = deps.getAccessToken();
1488
+ if (!accessToken) return;
1489
+ await deps.crypto.ensureReady();
1490
+ const session = await deps.persistence.getSession();
1491
+ if (!session?.signingPrivateKey) return;
1492
+ const sessionKey = deps.getSessionKey(accessToken);
1493
+ if (!sessionKey) return;
1494
+ const sessionKeyBytes = deps.crypto.fromBase64(sessionKey);
1495
+ let workspaces;
1496
+ try {
1497
+ workspaces = await deps.listWorkspaces(accessToken);
1498
+ } catch {
1499
+ return;
1500
+ }
1501
+ for (const ws of workspaces ?? []) {
1502
+ if (!ws.wrapped_key || !ws.external_id) continue;
1503
+ try {
1504
+ const workspaceKey = deps.unwrapWorkspaceKey(ws.wrapped_key, session.signingPrivateKey);
1505
+ const sealed = await deps.crypto.sealKeyForSession(workspaceKey, sessionKeyBytes);
1506
+ await deps.workspaceOpenProvider.openWorkspace(accessToken, ws.external_id, sealed);
1507
+ } catch (error) {
1508
+ console.warn(`[API] Failed to open workspace ${ws.external_id}:`, error);
1509
+ }
1510
+ }
1511
+ };
1512
+ }
1309
1513
 
1310
- // src/auth/register.ts
1311
- async function register(params, deps) {
1312
- const credentials = await generateRegistrationCredentials(
1313
- {
1314
- email: params.email,
1315
- verification_credential: params.verificationCode,
1316
- given_name: params.firstName,
1317
- family_name: params.lastName,
1318
- picture: params.picture
1319
- },
1320
- params.password,
1321
- deps.deploymentDomain
1322
- );
1323
- const response = await deps.fetchClient.POST("/v1/user/register", {
1324
- body: credentials.request
1325
- });
1326
- if (response.error) {
1327
- throw new Error(
1328
- `Registration failed: ${typeof response.error === "object" && response.error !== null && "detail" in response.error ? response.error.detail : "Unknown error"}`
1514
+ // src/auth/session-claims.ts
1515
+ function readSessionClaims(token) {
1516
+ const payload = token?.split(".")[1];
1517
+ if (!payload) return null;
1518
+ let claims;
1519
+ try {
1520
+ const binary = atob(payload.replace(/-/g, "+").replace(/_/g, "/"));
1521
+ claims = JSON.parse(
1522
+ new TextDecoder().decode(Uint8Array.from(binary, (c) => c.charCodeAt(0)))
1329
1523
  );
1524
+ } catch {
1525
+ return null;
1330
1526
  }
1331
- return { signingPrivateKey: credentials.signingPrivateKey };
1527
+ if (typeof claims !== "object" || claims === null) return null;
1528
+ const { sk, exp } = claims;
1529
+ const sessionKey = typeof sk === "string" && sk ? sk : null;
1530
+ return {
1531
+ sessionKey,
1532
+ sessionId: sessionKey ? sessionKey.slice(0, 12) : null,
1533
+ expiresAt: typeof exp === "number" && Number.isFinite(exp) ? exp * 1e3 : null
1534
+ };
1332
1535
  }
1333
1536
 
1334
1537
  // src/auth/identity.ts
@@ -1355,6 +1558,11 @@ async function unlockIdentityWithPassword(email, password, deploymentDomain) {
1355
1558
  }
1356
1559
 
1357
1560
  // src/auth/login.ts
1561
+ function authRequestError(what, error, status) {
1562
+ const detail = typeof error === "object" && error !== null && "detail" in error ? error.detail : void 0;
1563
+ const text = typeof detail === "string" ? detail : "Unknown error";
1564
+ return Object.assign(new Error(`${what} failed: ${text}`), { detail, status });
1565
+ }
1358
1566
  async function login(params, deps) {
1359
1567
  const credentials = await generateLoginCredentials(
1360
1568
  {
@@ -1364,7 +1572,12 @@ async function login(params, deps) {
1364
1572
  params.password,
1365
1573
  deps.deploymentDomain
1366
1574
  );
1367
- return performLogin(credentials.request, { password: credentials.passwordPrivateKey }, deps);
1575
+ return performLogin(
1576
+ credentials.request,
1577
+ { password: credentials.passwordPrivateKey },
1578
+ deps,
1579
+ params.profile
1580
+ );
1368
1581
  }
1369
1582
  async function loginWithKey(params, deps) {
1370
1583
  const credentials = generateLoginCredentialsFromKey(
@@ -1376,27 +1589,42 @@ async function loginWithKey(params, deps) {
1376
1589
  );
1377
1590
  return performLogin(credentials.request, { identity: credentials.signingPrivateKey }, deps);
1378
1591
  }
1379
- async function performLogin(request, signer, deps) {
1592
+ async function performLogin(request, signer, deps, profile) {
1380
1593
  const response = await deps.fetchClient.POST("/v1/user/login", {
1381
1594
  body: request
1382
1595
  });
1383
1596
  if (response.error || !response.data) {
1384
- throw new Error(
1385
- `Login failed: ${typeof response.error === "object" && response.error !== null && "detail" in response.error ? response.error.detail : "Unknown error"}`
1386
- );
1597
+ throw authRequestError("Login", response.error, response.response?.status);
1387
1598
  }
1388
1599
  const data = response.data;
1389
1600
  const serverSessionKey = base64ToBytes(data.session_key);
1390
1601
  const signingPrivateKey = "password" in signer ? identityFromLoginResponse(signer.password, data) : signer.identity;
1391
- await saveSession({
1602
+ await deps.signIn?.before?.({ user: data.user });
1603
+ await (deps.persistence?.saveSession ?? saveSession)({
1392
1604
  signingPrivateKey,
1393
1605
  serverSessionKey,
1394
1606
  userExtId: data.user.external_id ?? void 0,
1395
1607
  wrappedIdentityKey: data.wrapped_identity_key ?? null
1396
1608
  });
1397
- deps.session.setAccessToken(data.access_token);
1398
- deps.session.setUser(request.email, data.user.external_id ?? void 0);
1609
+ const email = request.email;
1610
+ deps.session.signIn({
1611
+ accessToken: data.access_token,
1612
+ isSsoMode: !!request.sso_token,
1613
+ serverSessionKey,
1614
+ user: {
1615
+ ...data.user,
1616
+ email,
1617
+ given_name: profile?.given_name ?? data.user.given_name ?? email.split("@")[0],
1618
+ family_name: profile?.family_name ?? data.user.family_name,
1619
+ picture: profile?.picture ?? data.user.picture ?? null,
1620
+ parent_ext_id: data.user.parent_ext_id ?? null,
1621
+ is_sso: data.user.is_sso ?? false,
1622
+ is_identity_verified: data.user.is_identity_verified ?? false
1623
+ }
1624
+ });
1625
+ deps.signIn?.after?.({ response: data, serverSessionKey });
1399
1626
  return {
1627
+ response: data,
1400
1628
  accessToken: data.access_token,
1401
1629
  userExtId: data.user.external_id ?? void 0,
1402
1630
  parentExtId: data.user.parent_ext_id ?? null,
@@ -1413,10 +1641,26 @@ async function performLogin(request, signer, deps) {
1413
1641
  };
1414
1642
  }
1415
1643
 
1416
- // src/auth/logout.ts
1417
- async function logout(session) {
1418
- session.clear();
1419
- await clearAllData();
1644
+ // src/auth/register.ts
1645
+ async function register(params, deps) {
1646
+ const credentials = await generateRegistrationCredentials(
1647
+ {
1648
+ email: params.email,
1649
+ verification_credential: params.verificationCode,
1650
+ given_name: params.firstName,
1651
+ family_name: params.lastName,
1652
+ picture: params.picture
1653
+ },
1654
+ params.password,
1655
+ deps.deploymentDomain
1656
+ );
1657
+ const response = await deps.fetchClient.POST("/v1/user/register", {
1658
+ body: credentials.request
1659
+ });
1660
+ if (response.error) {
1661
+ throw authRequestError("Registration", response.error, response.response?.status);
1662
+ }
1663
+ return { signingPrivateKey: credentials.signingPrivateKey };
1420
1664
  }
1421
1665
 
1422
1666
  // src/auth/change-password.ts
@@ -1455,29 +1699,6 @@ async function changePassword(params, deps) {
1455
1699
  return { wrappedIdentityKey: request.wrapped_identity_key };
1456
1700
  }
1457
1701
 
1458
- // src/auth/session-claims.ts
1459
- function readSessionClaims(token) {
1460
- const payload = token?.split(".")[1];
1461
- if (!payload) return null;
1462
- let claims;
1463
- try {
1464
- const binary = atob(payload.replace(/-/g, "+").replace(/_/g, "/"));
1465
- claims = JSON.parse(
1466
- new TextDecoder().decode(Uint8Array.from(binary, (c) => c.charCodeAt(0)))
1467
- );
1468
- } catch {
1469
- return null;
1470
- }
1471
- if (typeof claims !== "object" || claims === null) return null;
1472
- const { sk, exp } = claims;
1473
- const sessionKey = typeof sk === "string" && sk ? sk : null;
1474
- return {
1475
- sessionKey,
1476
- sessionId: sessionKey ? sessionKey.slice(0, 12) : null,
1477
- expiresAt: typeof exp === "number" && Number.isFinite(exp) ? exp * 1e3 : null
1478
- };
1479
- }
1480
-
1481
1702
  // src/client.ts
1482
1703
  var API_PREFIX = "/v1";
1483
1704
  var RETRYABLE_CODES = /* @__PURE__ */ new Set([
@@ -1514,24 +1735,42 @@ function createRetryFetch() {
1514
1735
  throw lastError;
1515
1736
  };
1516
1737
  }
1738
+ var HTTP_METHODS = ["GET", "PUT", "POST", "DELETE", "OPTIONS", "HEAD", "PATCH", "TRACE"];
1739
+ function readBaseUrlPerRequest(fetchClient, base) {
1740
+ const methods = fetchClient;
1741
+ for (const method of HTTP_METHODS) {
1742
+ const call = methods[method].bind(fetchClient);
1743
+ methods[method] = (url, init) => call(url, { ...init, baseUrl: base() });
1744
+ }
1745
+ const request = methods.request.bind(fetchClient);
1746
+ methods.request = (method, url, init) => request(method, url, { ...init, baseUrl: base() });
1747
+ }
1748
+ var deploymentDomainOf = ({ deploymentDomain }) => typeof deploymentDomain === "function" ? deploymentDomain() : deploymentDomain;
1517
1749
  function createArbiClient(options) {
1518
- const { fetch: fetch2, session, relogin, reopenWorkspace } = options.transport ?? createTransport(options);
1519
- const authDeps = { fetchClient: fetch2, session, deploymentDomain: options.deploymentDomain };
1750
+ const { fetch: fetch2, session, persistence, workspaceKeys, auth } = createTransport(options);
1751
+ const authDeps = {
1752
+ fetchClient: fetch2,
1753
+ session,
1754
+ get deploymentDomain() {
1755
+ return deploymentDomainOf(options);
1756
+ },
1757
+ persistence,
1758
+ signIn: options.signIn
1759
+ };
1520
1760
  return {
1521
1761
  fetch: fetch2,
1762
+ workspaceKeys,
1522
1763
  session,
1523
1764
  auth: {
1524
1765
  register: (params) => register(params, authDeps),
1525
1766
  login: (params) => login(params, authDeps),
1526
1767
  loginWithKey: (params) => loginWithKey(params, authDeps),
1527
- logout: () => logout(session),
1528
1768
  changePassword: (params) => changePassword(params, authDeps),
1529
- relogin,
1530
- reopenWorkspace
1769
+ ...auth
1531
1770
  },
1532
1771
  crypto: {
1533
1772
  initSodium,
1534
- generateUserKeypairs: (email, password) => generateUserKeypairs(email, password, options.deploymentDomain),
1773
+ generateUserKeypairs: (email, password) => generateUserKeypairs(email, password, deploymentDomainOf(options)),
1535
1774
  signMessage,
1536
1775
  sealedBoxDecrypt,
1537
1776
  sealedBoxEncrypt,
@@ -1557,24 +1796,22 @@ function createArbiClient(options) {
1557
1796
  }
1558
1797
  function createTransport(options) {
1559
1798
  const {
1560
- baseUrl,
1561
- reloginExcludePatterns = [`${API_PREFIX}/user/login`],
1799
+ reloginExcludePatterns = [`${API_PREFIX}/user/login`, `${API_PREFIX}/user/logout`],
1562
1800
  credentials = "include",
1563
- ssoTokenProvider = null,
1801
+ sso = null,
1802
+ middleware = [],
1564
1803
  onReloginSuccess,
1565
- onSessionExpired,
1566
- sessionStorage: sessionStorageOverride,
1804
+ onRetryCloneFailed,
1567
1805
  userEmail
1568
1806
  } = options;
1569
- const sessionStorage = sessionStorageOverride ?? {
1570
- getSession,
1571
- saveSession
1572
- };
1807
+ const persistence = options.persistence ?? { getSession, saveSession };
1808
+ const baseUrlOption = options.baseUrl;
1809
+ const base = typeof baseUrlOption === "function" ? baseUrlOption : () => baseUrlOption;
1573
1810
  const retryFetch = createRetryFetch();
1574
- const session = createSessionManager();
1811
+ const session = options.session ?? createSessionManager();
1575
1812
  if (userEmail) session.setUser(userEmail);
1576
1813
  const tokenProvider = createTokenProvider(session);
1577
- const authState = createAuthStateProvider(session);
1814
+ const authState = createAuthStateProvider(session, options.selectedWorkspace);
1578
1815
  const cryptoProvider = {
1579
1816
  ensureReady: initSodium,
1580
1817
  signMessage,
@@ -1583,11 +1820,10 @@ function createTransport(options) {
1583
1820
  sealKeyForSession,
1584
1821
  fromBase64: base64ToBytes
1585
1822
  };
1586
- let reloginUnreachable = false;
1587
1823
  const loginProvider = {
1588
1824
  async login(payload) {
1589
1825
  const rawFetch = createFetchClient({
1590
- baseUrl,
1826
+ baseUrl: base(),
1591
1827
  credentials,
1592
1828
  fetch: retryFetch
1593
1829
  });
@@ -1603,8 +1839,7 @@ function createTransport(options) {
1603
1839
  });
1604
1840
  } catch (error) {
1605
1841
  console.warn("[API] Login call unreachable:", error);
1606
- reloginUnreachable = true;
1607
- return null;
1842
+ return "unreachable";
1608
1843
  }
1609
1844
  if (response.error || !response.data) {
1610
1845
  console.warn("[API] Login call failed:", response.error);
@@ -1619,81 +1854,219 @@ function createTransport(options) {
1619
1854
  };
1620
1855
  }
1621
1856
  };
1622
- const workspaceKeyRefreshProvider = {
1623
- async getWrappedKey(accessToken, workspaceId) {
1624
- const workspacesResponse = await retryFetch(`${baseUrl}${API_PREFIX}/user/workspaces`, {
1625
- method: "GET",
1626
- headers: {
1627
- Authorization: `Bearer ${accessToken}`,
1628
- "Content-Type": "application/json"
1629
- },
1630
- credentials
1631
- });
1632
- if (!workspacesResponse.ok) return null;
1633
- const workspacesData = await workspacesResponse.json();
1634
- const workspace = workspacesData.find(
1635
- (w) => w.external_id === workspaceId
1857
+ async function listWorkspaces(accessToken) {
1858
+ const response = await retryFetch(`${base()}${API_PREFIX}/user/workspaces`, {
1859
+ method: "GET",
1860
+ headers: {
1861
+ Authorization: `Bearer ${accessToken}`,
1862
+ "Content-Type": "application/json"
1863
+ },
1864
+ credentials
1865
+ });
1866
+ return response.ok ? response.json() : null;
1867
+ }
1868
+ const workspaceKeys = createWorkspaceKeys({
1869
+ crypto: cryptoProvider,
1870
+ unwrapWorkspaceKey,
1871
+ persistence,
1872
+ getAccessToken: () => session.getState().accessToken,
1873
+ getServerSessionKey: () => session.getState().serverSessionKey,
1874
+ listWorkspaces,
1875
+ async primeKey(accessToken, workspaceId, sealedKey) {
1876
+ const response = await retryFetch(
1877
+ `${base()}${API_PREFIX}/workspace/${workspaceId}/prime-key`,
1878
+ {
1879
+ method: "POST",
1880
+ headers: { Authorization: `Bearer ${accessToken}`, "Content-Type": "application/json" },
1881
+ body: JSON.stringify({ workspace_key: sealedKey }),
1882
+ credentials
1883
+ }
1636
1884
  );
1637
- return workspace?.wrapped_key ?? null;
1885
+ if (!response.ok) throw new Error(`Could not unlock the workspace (${response.status})`);
1886
+ }
1887
+ });
1888
+ let keysUser = session.getState().signedIn ? session.getState().userExtId : null;
1889
+ session.subscribe((state) => {
1890
+ const user = state.signedIn ? state.userExtId : null;
1891
+ if (user !== keysUser) workspaceKeys.clear();
1892
+ keysUser = user;
1893
+ });
1894
+ const workspaceKeyRefreshProvider = {
1895
+ async getWrappedKey(_accessToken, workspaceId) {
1896
+ return (await workspaceKeys.wrappedKey(workspaceId).catch(() => null))?.wrappedKey ?? null;
1638
1897
  }
1639
1898
  };
1640
1899
  const workspaceOpenProvider = {
1641
1900
  async openWorkspace(accessToken, workspaceId, encryptedWorkspaceKey) {
1901
+ const query = "?include_documents=false&include_conversations=false&include_tags=false";
1642
1902
  try {
1643
- const response = await retryFetch(`${baseUrl}${API_PREFIX}/workspace/${workspaceId}/open`, {
1644
- method: "POST",
1645
- headers: {
1646
- Authorization: `Bearer ${accessToken}`,
1647
- "Content-Type": "application/json"
1648
- },
1649
- body: JSON.stringify({ workspace_key: encryptedWorkspaceKey }),
1650
- credentials
1651
- });
1903
+ const response = await retryFetch(
1904
+ `${base()}${API_PREFIX}/workspace/${workspaceId}/open${query}`,
1905
+ {
1906
+ method: "POST",
1907
+ headers: {
1908
+ Authorization: `Bearer ${accessToken}`,
1909
+ "Content-Type": "application/json"
1910
+ },
1911
+ body: JSON.stringify({ workspace_key: encryptedWorkspaceKey }),
1912
+ credentials
1913
+ }
1914
+ );
1652
1915
  return response.ok ? true : null;
1653
1916
  } catch {
1654
1917
  return null;
1655
1918
  }
1656
1919
  }
1657
1920
  };
1658
- const rawReloginHandler = createReloginHandler({
1921
+ let lastFailure = null;
1922
+ const expiredListeners = /* @__PURE__ */ new Set();
1923
+ const rawRelogin = createReloginHandler({
1659
1924
  crypto: cryptoProvider,
1660
- sessionStorage,
1925
+ persistence,
1661
1926
  authState,
1662
- ssoTokenProvider,
1927
+ sso,
1663
1928
  loginProvider,
1664
1929
  workspaceKeyRefreshProvider,
1665
1930
  workspaceOpenProvider,
1666
- onReloginSuccess
1931
+ // The new server session key goes into the session before the token: whatever re-renders on
1932
+ // the token reads the key that goes with it.
1933
+ async onReloginSuccess(data) {
1934
+ session.setServerSessionKey(data.serverSessionKey);
1935
+ await onReloginSuccess?.(data);
1936
+ },
1937
+ onReloginFailed: (reason) => {
1938
+ lastFailure = reason;
1939
+ }
1667
1940
  });
1668
- const reloginHandler = () => {
1669
- reloginUnreachable = false;
1670
- return rawReloginHandler();
1671
- };
1941
+ async function relogin() {
1942
+ const tokenBefore = session.getState().accessToken;
1943
+ const token = await rawRelogin();
1944
+ if (token) return token;
1945
+ const tokenNow = session.getState().accessToken;
1946
+ if (tokenNow && tokenNow !== tokenBefore) return tokenNow;
1947
+ if (lastFailure === "refused") {
1948
+ lastFailure = null;
1949
+ session.clear();
1950
+ for (const listener of [...expiredListeners]) listener();
1951
+ }
1952
+ return null;
1953
+ }
1672
1954
  const reopenWorkspace = createWorkspaceReopener({
1673
1955
  crypto: cryptoProvider,
1674
- sessionStorage,
1956
+ persistence,
1675
1957
  authState,
1676
1958
  getAccessToken: () => session.getState().accessToken,
1677
1959
  workspaceKeyRefreshProvider,
1678
1960
  workspaceOpenProvider
1679
1961
  });
1962
+ const openAllWorkspaces = createAllWorkspacesOpener({
1963
+ crypto: cryptoProvider,
1964
+ persistence,
1965
+ getAccessToken: () => session.getState().accessToken,
1966
+ getSessionKey: (accessToken) => readSessionClaims(accessToken)?.sessionKey ?? null,
1967
+ unwrapWorkspaceKey,
1968
+ listWorkspaces: async (accessToken) => {
1969
+ const list = await listWorkspaces(accessToken);
1970
+ return list && workspaceKeys.remember(list);
1971
+ },
1972
+ workspaceOpenProvider
1973
+ });
1680
1974
  const fetchClient = createFetchClient({
1681
- baseUrl,
1975
+ baseUrl: base(),
1682
1976
  credentials,
1683
1977
  fetch: retryFetch
1684
1978
  });
1979
+ if (typeof baseUrlOption === "function") readBaseUrlPerRequest(fetchClient, base);
1685
1980
  fetchClient.use(createBearerAuthMiddleware({ tokenProvider }));
1981
+ for (const m of middleware) fetchClient.use(m);
1686
1982
  fetchClient.use(
1687
1983
  createAutoReloginMiddleware({
1688
- reloginHandler,
1984
+ reloginHandler: relogin,
1689
1985
  reloginExcludePatterns,
1690
1986
  reopenWorkspaceHandler: reopenWorkspace,
1691
- onReloginFailed: () => {
1692
- if (!reloginUnreachable && session.getState().userEmail) onSessionExpired?.();
1693
- }
1987
+ primeWorkspaceHandler: (workspaceId) => workspaceKeys.prime(workspaceId, { force: true }).then(
1988
+ () => true,
1989
+ (error) => {
1990
+ console.warn("[API] Could not unlock workspace", workspaceId, error);
1991
+ return false;
1992
+ }
1993
+ ),
1994
+ onRetryCloneFailed
1694
1995
  })
1695
1996
  );
1696
- return { fetch: fetchClient, session, relogin: reloginHandler, reopenWorkspace };
1997
+ return {
1998
+ fetch: fetchClient,
1999
+ session,
2000
+ persistence,
2001
+ workspaceKeys,
2002
+ auth: {
2003
+ relogin,
2004
+ reopenWorkspace,
2005
+ openAllWorkspaces,
2006
+ async logout({ everywhere = false } = {}) {
2007
+ if (session.getState().accessToken) {
2008
+ try {
2009
+ await fetchClient.POST("/v1/user/logout", {
2010
+ params: { query: { all_sessions: everywhere } }
2011
+ });
2012
+ } catch (error) {
2013
+ console.warn("[API] Server logout failed:", error);
2014
+ }
2015
+ }
2016
+ session.clear();
2017
+ if (everywhere) await clearAllData();
2018
+ },
2019
+ async unlock({ email, password }) {
2020
+ const saved = await persistence.getSession();
2021
+ if (!saved?.signingPrivateKey) throw new Error("no-session");
2022
+ let signingPrivateKey;
2023
+ try {
2024
+ signingPrivateKey = await unlockIdentityWithPassword(
2025
+ email,
2026
+ password,
2027
+ deploymentDomainOf(options)
2028
+ );
2029
+ } catch {
2030
+ throw new Error("bad-password");
2031
+ }
2032
+ const { publicKey } = encryptionKeypairFromSigningKey(signingPrivateKey);
2033
+ session.signIn({
2034
+ accessToken: null,
2035
+ isSsoMode: false,
2036
+ serverSessionKey: saved.serverSessionKey ?? null,
2037
+ user: {
2038
+ email,
2039
+ given_name: email.split("@")[0],
2040
+ family_name: null,
2041
+ picture: null,
2042
+ external_id: saved.userExtId ?? "",
2043
+ parent_ext_id: null,
2044
+ encryption_public_key: bytesToBase64(publicKey),
2045
+ is_sso: false,
2046
+ is_identity_verified: false,
2047
+ temporary_access_only: false
2048
+ }
2049
+ });
2050
+ },
2051
+ async restore() {
2052
+ if (!session.getState().signedIn) return false;
2053
+ const keys = await persistence.getSession().catch(() => null);
2054
+ if (session.getState().serverSessionKey) return true;
2055
+ if (keys?.signingPrivateKey && keys.serverSessionKey) {
2056
+ session.setServerSessionKey(keys.serverSessionKey);
2057
+ return true;
2058
+ }
2059
+ session.clear();
2060
+ return false;
2061
+ },
2062
+ onSessionExpired(listener) {
2063
+ expiredListeners.add(listener);
2064
+ return () => {
2065
+ expiredListeners.delete(listener);
2066
+ };
2067
+ }
2068
+ }
2069
+ };
1697
2070
  }
1698
2071
 
1699
2072
  // src/websocket.ts
@@ -1721,6 +2094,6 @@ function isMessageType(msg, type) {
1721
2094
  return msg.type === type;
1722
2095
  }
1723
2096
 
1724
- export { API_PREFIX, CALL_KEY_BYTES, CHAT_KEY_BYTES, ENCRYPTED_RECOVERY_KEY_SIZE, RECOVERY_KEY_ERRORS, SECURE_MAIL_KEY_BYTES, UNENCRYPTED_RECOVERY_KEY_SIZE, base64Decode, base64Encode, base64ToBytes, base64UrlToBytes, buildCallFragment, buildWebSocketUrl, bytesToBase64, bytesToBase64Url, canPersistSession, changePassword, clearAllData, clearSession, computeSharedSecret, createArbiClient, createAuthMessage, createAutoReloginMiddleware, createBearerAuthMiddleware, createContentHash, createOfflineSealer, createRecoveryFile, createRecoveryUrl, createReloginHandler, createSessionManager, createWorkspaceReopener, decodeCallKey, decodeSecureMailKey, decryptCallTitle, decryptFile, decryptMessage, decryptMessageWithSharedSecret, decryptRecoveryKey, decryptWithChatKey, deriveDirectChatKey, deriveEncryptionKeypairFromSigning, derivePublicKey, encodeCallKey, encryptCallTitle, encryptFile, encryptMessage, encryptMessageWithSharedSecret, encryptRecoveryKey, encryptWithChatKey, encryptionKeypairFromSigningKey, generateCallKey, generateChatKey, generateIdentityKeypair, generateKeyPairs, generateLoginCredentials, generateLoginCredentialsFromKey, generatePasswordChangeCredentials, generateRandomSigningKeypair, generateRegistrationCredentials, generateUserKeypairs, getRecoveryKeyFilename, getSession, getUserEncryptionKeypair, hasSession, identityFromLoginResponse, initSodium, initializeDatabase, isEncryptedRecoveryKey, isMessageType, openSealedCallKey, openSealedChatKey, openSecureMail, parseCallFragment, parseRecoveryUrl, parseServerMessage, passwordChangeErrorMessage, prewarmKeyPairs, readSessionClaims, saveSession, sealCallKey, sealChatKey, sealKeyForSession, sealSecureMail, sealedBoxDecrypt, sealedBoxEncrypt, secureMailClaim, signMessage, unlockIdentityWithPassword, unwrapIdentityKey, unwrapWorkspaceKey, updateWrappedIdentityKey, validateRecoveryKeyFile, wrapIdentityKey };
2097
+ export { ACCESS_TOKEN_STORAGE_KEY, API_PREFIX, CALL_KEY_BYTES, CHAT_KEY_BYTES, ENCRYPTED_RECOVERY_KEY_SIZE, RECOVERY_KEY_ERRORS, SECURE_MAIL_KEY_BYTES, UNENCRYPTED_RECOVERY_KEY_SIZE, authRequestError, base64Decode, base64Encode, base64ToBytes, base64UrlToBytes, browserSessionStateStorage, buildCallFragment, buildCallLink, buildWebSocketUrl, bytesToBase64, bytesToBase64Url, canPersistSession, changePassword, clearAllData, clearSession, computeSharedSecret, createAllWorkspacesOpener, createArbiClient, createAuthMessage, createAutoReloginMiddleware, createBearerAuthMiddleware, createContentHash, createOfflineSealer, createRecoveryFile, createRecoveryUrl, createReloginHandler, createSessionManager, createWorkspaceKeys, createWorkspaceReopener, decodeCallKey, decodeSecureMailKey, decryptCallTitle, decryptFile, decryptMessage, decryptMessageWithSharedSecret, decryptRecoveryKey, decryptWithChatKey, deriveDirectChatKey, deriveEncryptionKeypairFromSigning, derivePublicKey, encodeCallKey, encryptCallTitle, encryptFile, encryptMessage, encryptMessageWithSharedSecret, encryptRecoveryKey, encryptWithChatKey, encryptionKeypairFromSigningKey, generateCallKey, generateChatKey, generateIdentityKeypair, generateKeyPairs, generateLoginCredentials, generateLoginCredentialsFromKey, generatePasswordChangeCredentials, generateRandomSigningKeypair, generateRegistrationCredentials, generateUserKeypairs, getRecoveryKeyFilename, getSession, getUserEncryptionKeypair, hasSession, identityFromLoginResponse, initSodium, initializeDatabase, isEncryptedRecoveryKey, isMessageType, openCallKeyOf, openSealedCallKey, openSealedChatKey, openSecureMail, parseCallFragment, parseRecoveryUrl, parseServerMessage, passwordChangeErrorMessage, prewarmKeyPairs, readSessionClaims, saveSession, sealCallKey, sealCallKeyForPeers, sealChatKey, sealKeyForSession, sealSecureMail, sealedBoxDecrypt, sealedBoxEncrypt, secureMailClaim, signMessage, unlockIdentityWithPassword, unwrapIdentityKey, unwrapWorkspaceKey, updateWrappedIdentityKey, validateRecoveryKeyFile, workspaceKeyRequiredOf, wrapIdentityKey };
1725
2098
  //# sourceMappingURL=index.js.map
1726
2099
  //# sourceMappingURL=index.js.map