@arbidocs/sdk 0.4.5 → 0.4.6

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/browser.cjs CHANGED
@@ -3557,14 +3557,15 @@ async function extractErrorMessage(res) {
3557
3557
  return `Request failed: ${res.status} ${res.statusText}`;
3558
3558
  }
3559
3559
  async function authenticatedFetch(options) {
3560
- const { baseUrl, accessToken, path, method, body, headers } = options;
3560
+ const { baseUrl, accessToken, path, method, body, headers, signal } = options;
3561
3561
  const res = await fetch(`${baseUrl}${path}`, {
3562
3562
  method: method ?? (body ? "POST" : "GET"),
3563
3563
  headers: {
3564
3564
  Authorization: `Bearer ${accessToken}`,
3565
3565
  ...headers
3566
3566
  },
3567
- body
3567
+ body,
3568
+ signal
3568
3569
  });
3569
3570
  if (!res.ok) {
3570
3571
  const message = await extractErrorMessage(res);
@@ -4927,7 +4928,7 @@ async function retrieve(options) {
4927
4928
  return data;
4928
4929
  }
4929
4930
  async function queryAssistant(options) {
4930
- const { workspaceId, question, docIds, previousResponseId, model, ...auth } = options;
4931
+ const { workspaceId, question, docIds, previousResponseId, model, signal, ...auth } = options;
4931
4932
  const body = {
4932
4933
  input: question,
4933
4934
  workspace_ext_id: workspaceId,
@@ -4946,7 +4947,8 @@ async function queryAssistant(options) {
4946
4947
  path: "/v1/assistant/query",
4947
4948
  method: "POST",
4948
4949
  body: JSON.stringify(body),
4949
- headers: { "Content-Type": "application/json" }
4950
+ headers: { "Content-Type": "application/json" },
4951
+ signal
4950
4952
  });
4951
4953
  }
4952
4954
  async function respondToAgent(arbi, assistantMessageExtId, answer) {
@@ -5482,9 +5484,78 @@ async function getFileContent(auth, fileId) {
5482
5484
  }
5483
5485
 
5484
5486
  // src/operations/sessions.ts
5487
+ var sessions_exports = {};
5488
+ __export(sessions_exports, {
5489
+ currentSessionId: () => currentSessionId,
5490
+ listSessions: () => listSessions,
5491
+ logoutAllSessions: () => logoutAllSessions,
5492
+ terminateSession: () => terminateSession
5493
+ });
5485
5494
  async function listSessions(arbi) {
5486
5495
  return requireData(await arbi.fetch.GET("/v1/user/sessions"), "Failed to fetch sessions");
5487
5496
  }
5497
+ async function terminateSession(arbi, sessionId) {
5498
+ requireOk(
5499
+ await arbi.fetch.PATCH("/v1/user/sessions/{session_id}", {
5500
+ params: { path: { session_id: sessionId } },
5501
+ body: { ttl: 0 }
5502
+ }),
5503
+ "Failed to end session"
5504
+ );
5505
+ }
5506
+ async function logoutAllSessions(arbi) {
5507
+ requireOk(
5508
+ await arbi.fetch.POST("/v1/user/logout", { params: { query: { all_sessions: true } } }),
5509
+ "Failed to sign out of all sessions"
5510
+ );
5511
+ }
5512
+ function currentSessionId(accessToken) {
5513
+ const payload = accessToken?.split(".")[1];
5514
+ if (!payload) return null;
5515
+ try {
5516
+ const claims = JSON.parse(atob(payload.replace(/-/g, "+").replace(/_/g, "/")));
5517
+ return typeof claims.sk === "string" ? claims.sk.slice(0, 12) : null;
5518
+ } catch {
5519
+ return null;
5520
+ }
5521
+ }
5522
+
5523
+ // src/operations/profile.ts
5524
+ var profile_exports = {};
5525
+ __export(profile_exports, {
5526
+ updateProfile: () => updateProfile
5527
+ });
5528
+ async function updateProfile(arbi, body) {
5529
+ return requireData(
5530
+ await arbi.fetch.PATCH("/v1/user/profile", { body }),
5531
+ "Failed to update profile"
5532
+ );
5533
+ }
5534
+
5535
+ // src/operations/account.ts
5536
+ var account_exports = {};
5537
+ __export(account_exports, {
5538
+ confirmEmailChange: () => confirmEmailChange,
5539
+ requestDeletion: () => requestDeletion,
5540
+ requestEmailChange: () => requestEmailChange
5541
+ });
5542
+ async function requestEmailChange(arbi, newEmail) {
5543
+ requireOk(
5544
+ await arbi.fetch.POST("/v1/user/request-email-change", { body: { new_email: newEmail } }),
5545
+ "Failed to send the verification code"
5546
+ );
5547
+ }
5548
+ async function confirmEmailChange(arbi, newEmail, verificationCode) {
5549
+ return requireData(
5550
+ await arbi.fetch.POST("/v1/user/confirm-email-change", {
5551
+ body: { new_email: newEmail, verification_code: verificationCode }
5552
+ }),
5553
+ "Invalid or expired verification code"
5554
+ );
5555
+ }
5556
+ async function requestDeletion(arbi) {
5557
+ return requireData(await arbi.fetch.POST("/v1/user/request-deletion"), "Failed to delete account");
5558
+ }
5488
5559
 
5489
5560
  // src/operations/projects.ts
5490
5561
  var projects_exports = {};
@@ -5694,6 +5765,8 @@ function tokenExpiresWithin(token, seconds) {
5694
5765
  var Arbi = class {
5695
5766
  client = null;
5696
5767
  loginResult = null;
5768
+ userProfile = null;
5769
+ profileListeners = /* @__PURE__ */ new Set();
5697
5770
  currentWorkspaceId = null;
5698
5771
  dmCryptoContext = null;
5699
5772
  sessionExpiredListeners = /* @__PURE__ */ new Set();
@@ -5742,6 +5815,7 @@ var Arbi = class {
5742
5815
  async login(email, password) {
5743
5816
  const client = await this.init();
5744
5817
  this.loginResult = await client.auth.login({ email, password });
5818
+ this.userProfile = this.loginResult.profile ?? null;
5745
5819
  }
5746
5820
  /**
5747
5821
  * Recover a session using a stored signing private key (base64).
@@ -5751,6 +5825,7 @@ var Arbi = class {
5751
5825
  const client = await this.init();
5752
5826
  const signingPrivateKey = client.crypto.base64ToBytes(signingPrivateKeyBase64);
5753
5827
  this.loginResult = await client.auth.loginWithKey({ email, signingPrivateKey });
5828
+ this.userProfile = this.loginResult.profile ?? null;
5754
5829
  }
5755
5830
  /** A workspace's key, sealed to the caller's own session (what `/open` and `POST /workspace/users` take). */
5756
5831
  async sealWorkspaceKey(workspaceId) {
@@ -5810,6 +5885,7 @@ var Arbi = class {
5810
5885
  this.loginResult.serverSessionKey.fill(0);
5811
5886
  }
5812
5887
  this.loginResult = null;
5888
+ this.userProfile = null;
5813
5889
  this.currentWorkspaceId = null;
5814
5890
  this.dmCryptoContext = null;
5815
5891
  this.client?.session.clear();
@@ -5840,6 +5916,10 @@ var Arbi = class {
5840
5916
  return run();
5841
5917
  }
5842
5918
  }
5919
+ setUserProfile(profile) {
5920
+ this.userProfile = profile;
5921
+ for (const listener of [...this.profileListeners]) listener(profile);
5922
+ }
5843
5923
  /** Log out and clear internal state. */
5844
5924
  async logout() {
5845
5925
  if (this.client) {
@@ -5850,6 +5930,7 @@ var Arbi = class {
5850
5930
  this.loginResult.serverSessionKey.fill(0);
5851
5931
  }
5852
5932
  this.loginResult = null;
5933
+ this.userProfile = null;
5853
5934
  this.currentWorkspaceId = null;
5854
5935
  this.dmCryptoContext = null;
5855
5936
  }
@@ -5923,9 +6004,76 @@ var Arbi = class {
5923
6004
  const state = this.requireClient().session.getState();
5924
6005
  return state.userExtId ? { externalId: state.userExtId, email: state.userEmail ?? null } : null;
5925
6006
  },
6007
+ /**
6008
+ * The signed-in user's profile (name, picture, email, SSO flag) as the login response
6009
+ * carried it, kept current by `profile.update` and `account.confirmEmailChange`. `null` when
6010
+ * not logged in or when the session was restored without a login (then read the workspace
6011
+ * roster instead).
6012
+ */
6013
+ profile: () => this.userProfile,
6014
+ /** Be told when the profile changes (name, picture or email saved). Returns the unsubscribe. */
6015
+ onProfileChange: (listener) => {
6016
+ this.profileListeners.add(listener);
6017
+ return () => this.profileListeners.delete(listener);
6018
+ },
5926
6019
  /** Today's deployment-wide credit spend for the current user. */
5927
6020
  usageToday: () => getUserUsageToday(this.requireClient())
5928
6021
  };
6022
+ // ── Profile ───────────────────────────────────────────────────────────
6023
+ profile = {
6024
+ /** Update the display profile; pass only what changes (`''` clears family name or picture). */
6025
+ update: async (body) => {
6026
+ const updated = await updateProfile(this.requireClient(), body);
6027
+ if (this.userProfile) {
6028
+ this.setUserProfile({
6029
+ ...this.userProfile,
6030
+ givenName: updated.given_name ?? this.userProfile.givenName,
6031
+ familyName: updated.family_name ?? null,
6032
+ picture: updated.picture ?? null
6033
+ });
6034
+ }
6035
+ return updated;
6036
+ }
6037
+ };
6038
+ // ── Account ───────────────────────────────────────────────────────────
6039
+ account = {
6040
+ /** Send a verification code to the new address (not for SSO accounts). */
6041
+ requestEmailChange: (newEmail) => requestEmailChange(this.requireClient(), newEmail),
6042
+ /** Confirm the email change with the emailed code; the session and profile follow. */
6043
+ confirmEmailChange: async (newEmail, verificationCode) => {
6044
+ const client = this.requireClient();
6045
+ const result = await confirmEmailChange(client, newEmail, verificationCode);
6046
+ client.session.setUser(result.email, client.session.getState().userExtId ?? void 0);
6047
+ if (this.userProfile) this.setUserProfile({ ...this.userProfile, email: result.email });
6048
+ return result;
6049
+ },
6050
+ /**
6051
+ * Change (or, after recovery, set) the master password: re-keys the workspaces and direct
6052
+ * messages. Omit `currentPassword` in recovery mode. Resolves with the new signing key, whose
6053
+ * recovery file the user should save.
6054
+ */
6055
+ changePassword: async (params) => {
6056
+ const client$1 = this.requireClient();
6057
+ const lr2 = this.requireLogin();
6058
+ const email = client$1.session.getState().userEmail ?? this.userProfile?.email;
6059
+ if (!email) throw new ArbiError("The account email is unknown; sign in again.");
6060
+ const result = await client.changePasswordWithRekey(
6061
+ { ...params, email, userExtId: lr2.userExtId },
6062
+ {
6063
+ fetchClient: client$1.fetch,
6064
+ deploymentDomain: this.options.deploymentDomain ?? new URL(this.options.url).hostname
6065
+ }
6066
+ );
6067
+ this.loginResult = { ...lr2, signingPrivateKey: result.newSigningPrivateKey };
6068
+ return result;
6069
+ },
6070
+ /** Close the account (soft delete) and sign out. Refused while a subscription is active. */
6071
+ requestDeletion: async () => {
6072
+ const result = await requestDeletion(this.requireClient());
6073
+ await this.logout();
6074
+ return result;
6075
+ }
6076
+ };
5929
6077
  // ── Workspaces ────────────────────────────────────────────────────────
5930
6078
  workspaces = {
5931
6079
  list: () => listWorkspaces(this.requireClient()),
@@ -6063,7 +6211,8 @@ var Arbi = class {
6063
6211
  question,
6064
6212
  docIds: options.docIds,
6065
6213
  previousResponseId: options.previousResponseId,
6066
- model: options.model
6214
+ model: options.model,
6215
+ signal: options.signal
6067
6216
  })
6068
6217
  );
6069
6218
  const callbacks = {
@@ -6311,7 +6460,16 @@ var Arbi = class {
6311
6460
  };
6312
6461
  // ── Sessions ────────────────────────────────────────────────────────
6313
6462
  sessions = {
6314
- list: () => listSessions(this.requireClient())
6463
+ list: () => listSessions(this.requireClient()),
6464
+ /** The id this device's session is listed under in `list()`; `null` when unknown. */
6465
+ currentId: () => currentSessionId(this.client?.session.getState().accessToken),
6466
+ /** End one of your own sessions now (not the one this device is on: that is `logout`). */
6467
+ terminate: (sessionId) => terminateSession(this.requireClient(), sessionId),
6468
+ /** Sign out of every device on the server, then clear this instance. */
6469
+ logoutAll: async () => {
6470
+ await logoutAllSessions(this.requireClient());
6471
+ await this.logout();
6472
+ }
6315
6473
  };
6316
6474
  // ── Internal guards ───────────────────────────────────────────────────
6317
6475
  requireClient() {
@@ -6401,6 +6559,7 @@ exports.Arbi = Arbi;
6401
6559
  exports.ArbiApiError = ArbiApiError;
6402
6560
  exports.ArbiError = ArbiError;
6403
6561
  exports.WebSocketAuthError = WebSocketAuthError;
6562
+ exports.account = account_exports;
6404
6563
  exports.agentconfig = agentconfig_exports;
6405
6564
  exports.assistant = assistant_exports;
6406
6565
  exports.authenticatedFetch = authenticatedFetch;
@@ -6432,6 +6591,7 @@ exports.parseSSEEvents = parseSSEEvents;
6432
6591
  exports.parseSlashCommand = parseSlashCommand;
6433
6592
  exports.parseSlashTokenInProgress = parseSlashTokenInProgress;
6434
6593
  exports.performPasswordLogin = performPasswordLogin;
6594
+ exports.profile = profile_exports;
6435
6595
  exports.projects = projects_exports;
6436
6596
  exports.requireData = requireData;
6437
6597
  exports.requireOk = requireOk;
@@ -6441,6 +6601,7 @@ exports.resolveWorkspace = resolveWorkspace;
6441
6601
  exports.responses = responses_exports;
6442
6602
  exports.selectWorkspace = selectWorkspace;
6443
6603
  exports.selectWorkspaceById = selectWorkspaceById;
6604
+ exports.sessions = sessions_exports;
6444
6605
  exports.settings = settings_exports;
6445
6606
  exports.streamSSE = streamSSE;
6446
6607
  exports.stripCitationMarkdown = stripCitationMarkdown;