@arbidocs/sdk 0.3.64 → 0.3.66

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.
@@ -84,16 +84,40 @@ interface CliConfig {
84
84
  }
85
85
  interface CliCredentials {
86
86
  email: string;
87
+ /** User's external ID (``usr-*`` or ``agt-*``). Needed by features
88
+ * that key on user identity (DM crypto, contact resolution, etc.).
89
+ * Set on every login from the API's response; required by
90
+ * ``buildAuthFromCache`` to restore the session client-side
91
+ * without a server round-trip. */
92
+ userExtId?: string;
87
93
  signingPrivateKeyBase64: string;
88
94
  serverSessionKeyBase64: string;
89
- /** Cached access token from last successful resolveWorkspace() */
95
+ /** Cached access token for the live server session. Valid as long as
96
+ * ``tokenTimestamp`` is within ``TOKEN_MAX_AGE_MS``. */
90
97
  accessToken?: string;
91
- /** Cached session-sealed workspace key from last successful resolveWorkspace() */
92
- sealedWorkspaceKey?: string;
93
- /** Workspace ID the cached token was issued for */
94
- workspaceId?: string;
95
- /** ISO timestamp when the token was cached */
98
+ /** ISO timestamp when ``accessToken`` was issued. Used for client-side
99
+ * TTL — the server enforces JWT exp independently. */
96
100
  tokenTimestamp?: string;
101
+ /**
102
+ * Workspaces whose keys are already deposited on the current server
103
+ * session — i.e. the keys of ``session.workspaces`` in the backend's
104
+ * Redis entry. Client-side mirror so we can skip a redundant `/open`
105
+ * round-trip when we've already deposited a workspace's key during
106
+ * this session's lifetime.
107
+ *
108
+ * Both grant types end up in this set:
109
+ * - **Permanent** — first `/open` for the workspace POSTs the
110
+ * wrapped_key and the server adds it to ``session.workspaces``.
111
+ * - **Session-only** (PA agents, temporary shares) — the backend
112
+ * pre-deposits via ``store_workspace_key_for_session_pubkey``,
113
+ * then the client's `/open` is just a metadata fetch.
114
+ *
115
+ * Cleared on every event that invalidates the session: fresh login,
116
+ * auto-relogin on 401, logout. The new session starts with an empty
117
+ * ``session.workspaces`` server-side, so this client mirror must
118
+ * start empty too.
119
+ */
120
+ openedWorkspaces?: string[];
97
121
  /** Auth0 SSO token — needed for session recovery of SSO users */
98
122
  ssoToken?: string;
99
123
  /** Parent user ext_id — set for persistent agent accounts */
@@ -152,7 +176,6 @@ interface AuthContext {
152
176
  interface WorkspaceContext extends AuthContext {
153
177
  workspaceId: string;
154
178
  accessToken: string;
155
- sealedWorkspaceKey: string;
156
179
  }
157
180
  /** Minimal workspace shape required by formatWorkspaceChoices. */
158
181
  interface WorkspaceForChoice {
@@ -232,23 +255,40 @@ declare function generateNewWorkspaceKey(arbi: ArbiClient, serverSessionKey: Uin
232
255
  * never log, persist, or transmit it over the wire.
233
256
  */
234
257
  declare function getRawWorkspaceKey(arbi: ArbiClient, workspaceId: string, signingPrivateKeyBase64: string): Promise<Uint8Array>;
235
- /**
236
- * Find a workspace by ID in the user's workspace list, select it, and return workspace info.
237
- */
238
258
  declare function selectWorkspaceById(arbi: ArbiClient, workspaceId: string, serverSessionKey: Uint8Array, signingPrivateKeyBase64: string): Promise<{
239
259
  external_id: string;
240
260
  name: string;
241
- wrapped_key: string;
261
+ wrapped_key: string | null;
262
+ /** The session-sealed workspace key — `null` for session-only grants */
263
+ sealed_key: string | null;
242
264
  }>;
243
265
  /**
244
266
  * Authenticate and return the SDK client + config.
245
- * Throws ArbiError instead of calling process.exit.
267
+ *
268
+ * Fast path: reuse the live server session via cached accessToken.
269
+ * Slow path: fresh ``loginWithKey`` (mints a new session, clears
270
+ * ``openedWorkspaces``).
246
271
  */
247
272
  declare function resolveAuth(store: ConfigStore): Promise<AuthContext>;
248
273
  /**
249
- * Authenticate, resolve workspace, and set up headers.
250
- * Uses cached JWT when available for the same workspace and not expired.
251
- * Throws ArbiError instead of calling process.exit.
274
+ * Authenticate, ensure the workspace's key is deposited on the current
275
+ * server session, and return everything callers need.
276
+ *
277
+ * Decisions are independent:
278
+ * 1. **Session aliveness** — reuse the live session if its accessToken
279
+ * is within TTL; otherwise fresh login. (Fresh login = new session
280
+ * = ``openedWorkspaces`` reset to ``[]``.)
281
+ * 2. **Workspace deposit** — if ``workspaceId`` already appears in
282
+ * ``creds.openedWorkspaces``, the server's session already holds
283
+ * its key; no ``/open`` needed. Otherwise call ``/open`` once and
284
+ * append to the set.
285
+ *
286
+ * Splitting these matters: previously the cache was gated on
287
+ * ``creds.workspaceId === workspaceId``, so any switch between
288
+ * workspaces forced a re-login. That orphaned PA-agent session
289
+ * deposits and broke ``arbi docs`` for them. Now switching workspaces
290
+ * within a live session just adds another entry to
291
+ * ``openedWorkspaces`` — no re-login, no orphaned deposits.
252
292
  */
253
293
  declare function resolveWorkspace(store: ConfigStore, workspaceOpt?: string): Promise<WorkspaceContext>;
254
294
 
@@ -2489,7 +2529,6 @@ declare class Arbi {
2489
2529
  muted_users: string[];
2490
2530
  premium_model?: string | null | undefined;
2491
2531
  picture?: string | null | undefined;
2492
- deletion_requested_at?: string | null | undefined;
2493
2532
  }>;
2494
2533
  update: (body: UserSettingsUpdate$1) => Promise<void>;
2495
2534
  };
@@ -3817,7 +3856,6 @@ declare function getSettings(arbi: ArbiClient): Promise<{
3817
3856
  muted_users: string[];
3818
3857
  premium_model?: string | null | undefined;
3819
3858
  picture?: string | null | undefined;
3820
- deletion_requested_at?: string | null | undefined;
3821
3859
  }>;
3822
3860
  declare function updateSettings(arbi: ArbiClient, body: UserSettingsUpdate): Promise<void>;
3823
3861
 
@@ -84,16 +84,40 @@ interface CliConfig {
84
84
  }
85
85
  interface CliCredentials {
86
86
  email: string;
87
+ /** User's external ID (``usr-*`` or ``agt-*``). Needed by features
88
+ * that key on user identity (DM crypto, contact resolution, etc.).
89
+ * Set on every login from the API's response; required by
90
+ * ``buildAuthFromCache`` to restore the session client-side
91
+ * without a server round-trip. */
92
+ userExtId?: string;
87
93
  signingPrivateKeyBase64: string;
88
94
  serverSessionKeyBase64: string;
89
- /** Cached access token from last successful resolveWorkspace() */
95
+ /** Cached access token for the live server session. Valid as long as
96
+ * ``tokenTimestamp`` is within ``TOKEN_MAX_AGE_MS``. */
90
97
  accessToken?: string;
91
- /** Cached session-sealed workspace key from last successful resolveWorkspace() */
92
- sealedWorkspaceKey?: string;
93
- /** Workspace ID the cached token was issued for */
94
- workspaceId?: string;
95
- /** ISO timestamp when the token was cached */
98
+ /** ISO timestamp when ``accessToken`` was issued. Used for client-side
99
+ * TTL — the server enforces JWT exp independently. */
96
100
  tokenTimestamp?: string;
101
+ /**
102
+ * Workspaces whose keys are already deposited on the current server
103
+ * session — i.e. the keys of ``session.workspaces`` in the backend's
104
+ * Redis entry. Client-side mirror so we can skip a redundant `/open`
105
+ * round-trip when we've already deposited a workspace's key during
106
+ * this session's lifetime.
107
+ *
108
+ * Both grant types end up in this set:
109
+ * - **Permanent** — first `/open` for the workspace POSTs the
110
+ * wrapped_key and the server adds it to ``session.workspaces``.
111
+ * - **Session-only** (PA agents, temporary shares) — the backend
112
+ * pre-deposits via ``store_workspace_key_for_session_pubkey``,
113
+ * then the client's `/open` is just a metadata fetch.
114
+ *
115
+ * Cleared on every event that invalidates the session: fresh login,
116
+ * auto-relogin on 401, logout. The new session starts with an empty
117
+ * ``session.workspaces`` server-side, so this client mirror must
118
+ * start empty too.
119
+ */
120
+ openedWorkspaces?: string[];
97
121
  /** Auth0 SSO token — needed for session recovery of SSO users */
98
122
  ssoToken?: string;
99
123
  /** Parent user ext_id — set for persistent agent accounts */
@@ -152,7 +176,6 @@ interface AuthContext {
152
176
  interface WorkspaceContext extends AuthContext {
153
177
  workspaceId: string;
154
178
  accessToken: string;
155
- sealedWorkspaceKey: string;
156
179
  }
157
180
  /** Minimal workspace shape required by formatWorkspaceChoices. */
158
181
  interface WorkspaceForChoice {
@@ -232,23 +255,40 @@ declare function generateNewWorkspaceKey(arbi: ArbiClient, serverSessionKey: Uin
232
255
  * never log, persist, or transmit it over the wire.
233
256
  */
234
257
  declare function getRawWorkspaceKey(arbi: ArbiClient, workspaceId: string, signingPrivateKeyBase64: string): Promise<Uint8Array>;
235
- /**
236
- * Find a workspace by ID in the user's workspace list, select it, and return workspace info.
237
- */
238
258
  declare function selectWorkspaceById(arbi: ArbiClient, workspaceId: string, serverSessionKey: Uint8Array, signingPrivateKeyBase64: string): Promise<{
239
259
  external_id: string;
240
260
  name: string;
241
- wrapped_key: string;
261
+ wrapped_key: string | null;
262
+ /** The session-sealed workspace key — `null` for session-only grants */
263
+ sealed_key: string | null;
242
264
  }>;
243
265
  /**
244
266
  * Authenticate and return the SDK client + config.
245
- * Throws ArbiError instead of calling process.exit.
267
+ *
268
+ * Fast path: reuse the live server session via cached accessToken.
269
+ * Slow path: fresh ``loginWithKey`` (mints a new session, clears
270
+ * ``openedWorkspaces``).
246
271
  */
247
272
  declare function resolveAuth(store: ConfigStore): Promise<AuthContext>;
248
273
  /**
249
- * Authenticate, resolve workspace, and set up headers.
250
- * Uses cached JWT when available for the same workspace and not expired.
251
- * Throws ArbiError instead of calling process.exit.
274
+ * Authenticate, ensure the workspace's key is deposited on the current
275
+ * server session, and return everything callers need.
276
+ *
277
+ * Decisions are independent:
278
+ * 1. **Session aliveness** — reuse the live session if its accessToken
279
+ * is within TTL; otherwise fresh login. (Fresh login = new session
280
+ * = ``openedWorkspaces`` reset to ``[]``.)
281
+ * 2. **Workspace deposit** — if ``workspaceId`` already appears in
282
+ * ``creds.openedWorkspaces``, the server's session already holds
283
+ * its key; no ``/open`` needed. Otherwise call ``/open`` once and
284
+ * append to the set.
285
+ *
286
+ * Splitting these matters: previously the cache was gated on
287
+ * ``creds.workspaceId === workspaceId``, so any switch between
288
+ * workspaces forced a re-login. That orphaned PA-agent session
289
+ * deposits and broke ``arbi docs`` for them. Now switching workspaces
290
+ * within a live session just adds another entry to
291
+ * ``openedWorkspaces`` — no re-login, no orphaned deposits.
252
292
  */
253
293
  declare function resolveWorkspace(store: ConfigStore, workspaceOpt?: string): Promise<WorkspaceContext>;
254
294
 
@@ -2489,7 +2529,6 @@ declare class Arbi {
2489
2529
  muted_users: string[];
2490
2530
  premium_model?: string | null | undefined;
2491
2531
  picture?: string | null | undefined;
2492
- deletion_requested_at?: string | null | undefined;
2493
2532
  }>;
2494
2533
  update: (body: UserSettingsUpdate$1) => Promise<void>;
2495
2534
  };
@@ -3817,7 +3856,6 @@ declare function getSettings(arbi: ArbiClient): Promise<{
3817
3856
  muted_users: string[];
3818
3857
  premium_model?: string | null | undefined;
3819
3858
  picture?: string | null | undefined;
3820
- deletion_requested_at?: string | null | undefined;
3821
3859
  }>;
3822
3860
  declare function updateSettings(arbi: ArbiClient, body: UserSettingsUpdate): Promise<void>;
3823
3861
 
package/dist/browser.cjs CHANGED
@@ -3568,6 +3568,7 @@ async function authenticatedFetch(options) {
3568
3568
  }
3569
3569
 
3570
3570
  // src/auth.ts
3571
+ var TOKEN_MAX_AGE_MS = 50 * 60 * 1e3;
3571
3572
  function formatWorkspaceChoices(wsList) {
3572
3573
  return wsList.map((ws) => {
3573
3574
  const totalDocs = ws.shared_document_count + ws.private_document_count;
@@ -3598,11 +3599,11 @@ async function createAuthenticatedClient(config, creds, store) {
3598
3599
  });
3599
3600
  store.saveCredentials({
3600
3601
  ...creds,
3602
+ userExtId: loginResult.userExtId ?? creds.userExtId,
3601
3603
  serverSessionKeyBase64: arbi.crypto.bytesToBase64(loginResult.serverSessionKey),
3602
3604
  accessToken: void 0,
3603
- sealedWorkspaceKey: void 0,
3604
- workspaceId: void 0,
3605
- tokenTimestamp: void 0
3605
+ tokenTimestamp: void 0,
3606
+ openedWorkspaces: void 0
3606
3607
  });
3607
3608
  return { arbi, loginResult };
3608
3609
  }
@@ -3612,13 +3613,18 @@ async function performPasswordLogin(config, email, password, store) {
3612
3613
  const loginResult = await arbi.auth.login({ email, password });
3613
3614
  store.saveCredentials({
3614
3615
  email,
3616
+ userExtId: loginResult.userExtId,
3615
3617
  signingPrivateKeyBase64: arbi.crypto.bytesToBase64(loginResult.signingPrivateKey),
3616
3618
  serverSessionKeyBase64: arbi.crypto.bytesToBase64(loginResult.serverSessionKey),
3617
- // Clear any cached workspace tokens new session key invalidates them
3619
+ // `parent_ext_id` is set for persistent agent accounts (the user is
3620
+ // an Assistant owned by another user). Persisting it makes the CLI's
3621
+ // `arbi listen` work — it requires this to confirm a real agent
3622
+ // identity. Regular users get `null`, which we store as `undefined`.
3623
+ parentExtId: loginResult.parentExtId ?? void 0,
3624
+ // New session = no workspaces deposited yet.
3618
3625
  accessToken: void 0,
3619
- sealedWorkspaceKey: void 0,
3620
- workspaceId: void 0,
3621
- tokenTimestamp: void 0
3626
+ tokenTimestamp: void 0,
3627
+ openedWorkspaces: void 0
3622
3628
  });
3623
3629
  return { arbi, loginResult, config };
3624
3630
  }
@@ -3634,16 +3640,6 @@ async function selectWorkspace(arbi, workspaceId, wrappedKey, serverSessionKey,
3634
3640
  arbi.session.setSelectedWorkspace(workspaceId);
3635
3641
  return header;
3636
3642
  }
3637
- async function generateEncryptedWorkspaceKey(arbi, wrappedKey, serverSessionKey, signingPrivateKeyBase64) {
3638
- const signingPrivateKey = client.base64ToBytes(signingPrivateKeyBase64);
3639
- const ed25519PublicKey = signingPrivateKey.slice(32, 64);
3640
- const encryptionKeyPair = client.deriveEncryptionKeypairFromSigning({
3641
- publicKey: ed25519PublicKey,
3642
- secretKey: signingPrivateKey
3643
- });
3644
- const workspaceKey = client.sealedBoxDecrypt(wrappedKey, encryptionKeyPair.secretKey);
3645
- return client.sealKeyForSession(workspaceKey, serverSessionKey);
3646
- }
3647
3643
  async function getRawWorkspaceKey(arbi, workspaceId, signingPrivateKeyBase64) {
3648
3644
  const { data: workspaces, error } = await arbi.fetch.GET("/v1/user/workspaces");
3649
3645
  if (error || !workspaces) {
@@ -3661,38 +3657,79 @@ async function getRawWorkspaceKey(arbi, workspaceId, signingPrivateKeyBase64) {
3661
3657
  });
3662
3658
  return client.sealedBoxDecrypt(ws.wrapped_key, encryptionKeyPair.secretKey);
3663
3659
  }
3660
+ async function openWorkspaceEntry(arbi, ws, serverSessionKey, signingPrivateKeyBase64) {
3661
+ if (ws.wrapped_key) {
3662
+ const sealedKey = await selectWorkspace(
3663
+ arbi,
3664
+ ws.external_id,
3665
+ ws.wrapped_key,
3666
+ serverSessionKey,
3667
+ signingPrivateKeyBase64
3668
+ );
3669
+ const { error: error2 } = await arbi.fetch.POST("/v1/workspace/{workspace_ext_id}/open", {
3670
+ params: { path: { workspace_ext_id: ws.external_id } },
3671
+ body: { workspace_key: sealedKey }
3672
+ });
3673
+ if (error2) {
3674
+ throw new ArbiError(`Workspace open failed for ${ws.external_id}: ${JSON.stringify(error2)}`);
3675
+ }
3676
+ return sealedKey;
3677
+ }
3678
+ arbi.session.setSelectedWorkspace(ws.external_id);
3679
+ const { error } = await arbi.fetch.POST("/v1/workspace/{workspace_ext_id}/open", {
3680
+ params: { path: { workspace_ext_id: ws.external_id } },
3681
+ body: {}
3682
+ });
3683
+ if (error) {
3684
+ throw new ArbiError(`Workspace open failed for ${ws.external_id}: ${JSON.stringify(error)}`);
3685
+ }
3686
+ return null;
3687
+ }
3664
3688
  async function selectWorkspaceById(arbi, workspaceId, serverSessionKey, signingPrivateKeyBase64) {
3665
3689
  const { data: workspaces, error } = await arbi.fetch.GET("/v1/user/workspaces");
3666
3690
  if (error || !workspaces) {
3667
3691
  throw new ArbiError("Failed to fetch workspaces");
3668
3692
  }
3669
3693
  const ws = workspaces.find((w2) => w2.external_id === workspaceId);
3670
- if (!ws || !ws.wrapped_key) {
3671
- throw new ArbiError(`Workspace ${workspaceId} not found or has no encryption key`);
3694
+ if (!ws) {
3695
+ throw new ArbiError(`Workspace ${workspaceId} not found`);
3672
3696
  }
3673
- const sealedKey = await selectWorkspace(
3674
- arbi,
3675
- ws.external_id,
3676
- ws.wrapped_key,
3677
- serverSessionKey,
3678
- signingPrivateKeyBase64
3679
- );
3680
- await arbi.fetch.POST("/v1/workspace/{workspace_ext_id}/open", {
3681
- params: { path: { workspace_ext_id: ws.external_id } },
3682
- body: { workspace_key: sealedKey }
3683
- });
3684
- return { external_id: ws.external_id, name: ws.name, wrapped_key: ws.wrapped_key };
3697
+ const sealedKey = await openWorkspaceEntry(arbi, ws, serverSessionKey, signingPrivateKeyBase64);
3698
+ return {
3699
+ external_id: ws.external_id,
3700
+ name: ws.name,
3701
+ wrapped_key: ws.wrapped_key ?? null,
3702
+ sealed_key: sealedKey
3703
+ };
3704
+ }
3705
+ function isSessionAlive(creds) {
3706
+ return !!(creds.accessToken && creds.tokenTimestamp && Date.now() - new Date(creds.tokenTimestamp).getTime() < TOKEN_MAX_AGE_MS);
3707
+ }
3708
+ async function buildAuthFromCache(config, creds, store) {
3709
+ const arbi = client.createArbiClient(buildClientOptions(config, store, creds.email));
3710
+ await arbi.crypto.initSodium();
3711
+ arbi.session.setUser(creds.email, creds.userExtId);
3712
+ arbi.session.setAccessToken(creds.accessToken);
3713
+ const signingPrivateKey = client.base64ToBytes(creds.signingPrivateKeyBase64);
3714
+ const serverSessionKey = client.base64ToBytes(creds.serverSessionKeyBase64);
3715
+ const loginResult = {
3716
+ accessToken: creds.accessToken,
3717
+ userExtId: creds.userExtId,
3718
+ signingPrivateKey,
3719
+ serverSessionKey
3720
+ };
3721
+ return { arbi, loginResult };
3685
3722
  }
3686
3723
  async function resolveAuth(store) {
3687
3724
  const config = store.requireConfig();
3688
3725
  const creds = store.requireCredentials();
3726
+ if (isSessionAlive(creds)) {
3727
+ const { arbi: arbi2, loginResult: loginResult2 } = await buildAuthFromCache(config, creds, store);
3728
+ return { arbi: arbi2, loginResult: loginResult2, config };
3729
+ }
3689
3730
  const { arbi, loginResult } = await createAuthenticatedClient(config, creds, store);
3690
3731
  return { arbi, loginResult, config };
3691
3732
  }
3692
- var TOKEN_MAX_AGE_MS = 50 * 60 * 1e3;
3693
- function isCachedTokenValid(creds, workspaceId) {
3694
- return !!(creds.accessToken && creds.sealedWorkspaceKey && creds.workspaceId === workspaceId && creds.tokenTimestamp && Date.now() - new Date(creds.tokenTimestamp).getTime() < TOKEN_MAX_AGE_MS);
3695
- }
3696
3733
  async function resolveWorkspace(store, workspaceOpt) {
3697
3734
  const config = store.requireConfig();
3698
3735
  const creds = store.requireCredentials();
@@ -3700,53 +3737,52 @@ async function resolveWorkspace(store, workspaceOpt) {
3700
3737
  if (!workspaceId) {
3701
3738
  throw new ArbiError("No workspace selected. Run: arbi workspace select <id>");
3702
3739
  }
3703
- if (isCachedTokenValid(creds, workspaceId)) {
3704
- const arbi2 = client.createArbiClient(buildClientOptions(config, store, creds.email));
3705
- await arbi2.crypto.initSodium();
3706
- arbi2.session.setUser(creds.email);
3740
+ if (isSessionAlive(creds)) {
3741
+ const { arbi: arbi2, loginResult: loginResult2 } = await buildAuthFromCache(config, creds, store);
3707
3742
  arbi2.session.setSelectedWorkspace(workspaceId);
3708
- arbi2.session.setAccessToken(creds.accessToken);
3709
- const signingPrivateKey = client.base64ToBytes(creds.signingPrivateKeyBase64);
3710
- const serverSessionKey = client.base64ToBytes(creds.serverSessionKeyBase64);
3711
- const loginResult2 = {
3712
- accessToken: creds.accessToken,
3713
- signingPrivateKey,
3714
- serverSessionKey
3715
- };
3743
+ await selectWorkspaceById(
3744
+ arbi2,
3745
+ workspaceId,
3746
+ loginResult2.serverSessionKey,
3747
+ creds.signingPrivateKeyBase64
3748
+ );
3749
+ const nextOpened = Array.from(/* @__PURE__ */ new Set([...creds.openedWorkspaces ?? [], workspaceId]));
3750
+ store.saveCredentials({
3751
+ ...store.requireCredentials(),
3752
+ openedWorkspaces: nextOpened
3753
+ });
3716
3754
  return {
3717
3755
  arbi: arbi2,
3718
3756
  loginResult: loginResult2,
3719
3757
  config,
3720
3758
  workspaceId,
3721
- accessToken: creds.accessToken,
3722
- sealedWorkspaceKey: creds.sealedWorkspaceKey
3759
+ accessToken: creds.accessToken
3723
3760
  };
3724
3761
  }
3725
3762
  const { arbi, loginResult } = await createAuthenticatedClient(config, creds, store);
3726
- const wsInfo = await selectWorkspaceById(
3763
+ await selectWorkspaceById(
3727
3764
  arbi,
3728
3765
  workspaceId,
3729
3766
  loginResult.serverSessionKey,
3730
3767
  creds.signingPrivateKeyBase64
3731
3768
  );
3732
3769
  const accessToken = arbi.session.getState().accessToken;
3733
- const sealedWorkspaceKey = await generateEncryptedWorkspaceKey(
3734
- arbi,
3735
- wsInfo.wrapped_key,
3736
- loginResult.serverSessionKey,
3737
- creds.signingPrivateKeyBase64
3738
- );
3739
3770
  if (!accessToken) {
3740
3771
  throw new ArbiError("Authentication error \u2014 missing token");
3741
3772
  }
3742
3773
  store.saveCredentials({
3743
3774
  ...store.requireCredentials(),
3744
3775
  accessToken,
3745
- sealedWorkspaceKey,
3746
- workspaceId,
3747
- tokenTimestamp: (/* @__PURE__ */ new Date()).toISOString()
3776
+ tokenTimestamp: (/* @__PURE__ */ new Date()).toISOString(),
3777
+ openedWorkspaces: [workspaceId]
3748
3778
  });
3749
- return { arbi, loginResult, config, workspaceId, accessToken, sealedWorkspaceKey };
3779
+ return {
3780
+ arbi,
3781
+ loginResult,
3782
+ config,
3783
+ workspaceId,
3784
+ accessToken
3785
+ };
3750
3786
  }
3751
3787
 
3752
3788
  // src/sse.ts