@arbidocs/sdk 0.4.2 → 0.4.3

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.
@@ -9,6 +9,10 @@ import { SessionStorageProvider, ArbiClient, LoginResult, components, WebSocketS
9
9
  declare class ArbiError extends Error {
10
10
  constructor(message: string);
11
11
  }
12
+ /** The session cannot be recovered (token and workspace re-open both refused): sign in again. */
13
+ declare class ArbiSessionExpiredError extends ArbiError {
14
+ constructor(message?: string);
15
+ }
12
16
  declare class ArbiApiError extends ArbiError {
13
17
  readonly apiError?: unknown;
14
18
  constructor(message: string, apiError?: unknown);
@@ -2034,6 +2038,7 @@ declare class Arbi {
2034
2038
  private loginResult;
2035
2039
  private currentWorkspaceId;
2036
2040
  private dmCryptoContext;
2041
+ private readonly sessionExpiredListeners;
2037
2042
  private readonly options;
2038
2043
  constructor(options: ArbiOptions);
2039
2044
  /** Initialize the SDK client and sodium crypto. Called automatically by login(). */
@@ -2068,6 +2073,20 @@ declare class Arbi {
2068
2073
  * workspace, decrypts the wrapped key, and sets up auth headers.
2069
2074
  */
2070
2075
  selectWorkspace(workspaceId: string): Promise<void>;
2076
+ /**
2077
+ * Subscribe to "the session cannot be recovered". Fires when a request failed with 401 or
2078
+ * "No active workspace" and neither a workspace re-open nor a silent re-login was possible
2079
+ * (the server refused; an unreachable server does not fire). The local session is already
2080
+ * cleared when it fires: show "Your session expired, sign in again". Returns an unsubscribe.
2081
+ */
2082
+ onSessionExpired(listener: () => void): () => void;
2083
+ private expireSession;
2084
+ /**
2085
+ * Run a raw-fetch operation (streaming, multipart: no middleware) and, when it fails because
2086
+ * the token expired or the server lost the open workspace, recover once and run it again.
2087
+ * `run` must read the auth headers itself so the retry carries the fresh token.
2088
+ */
2089
+ private recovering;
2071
2090
  /** Log out and clear internal state. */
2072
2091
  logout(): Promise<void>;
2073
2092
  /** Get the underlying ArbiClient (throws if not initialized). */
@@ -5978,4 +5997,4 @@ declare namespace projects {
5978
5997
  export { type projects_ProjectInvoicesResponse as ProjectInvoicesResponse, type projects_ProjectUpdateRequest as ProjectUpdateRequest, type projects_ProjectUsageResponse as ProjectUsageResponse, type projects_UserDailyUsageResponse as UserDailyUsageResponse, projects_createProject as createProject, projects_deleteProject as deleteProject, projects_getProjectInvoices as getProjectInvoices, projects_getProjectUsage as getProjectUsage, projects_getUserUsageToday as getUserUsageToday, projects_listProjects as listProjects, projects_refreshProject as refreshProject, projects_renameProject as renameProject, projects_updateProject as updateProject };
5979
5998
  }
5980
5999
 
5981
- export { type ResponseFailedEvent as $, type AgentControlStateEvent as A, type DocumentWaiterOptions as B, type ChatSession as C, DOC_TERMINAL_STATUSES as D, type FactSearchRequest as E, type FactResponse as F, type FactSearchResponse as G, type FormattedWsMessage as H, type ListFactsOptions as I, type ListPaginatedOptions as J, type MessageMetadataPayload$1 as K, type ListAllOptions as L, type MessageLevel as M, type MessageQueuedEvent as N, type OutputTokensDetails as O, type ParsedSlashCommand as P, type ProbeAnswerEvent as Q, type ProjectInvoicesResponse as R, type ProjectUsageResponse as S, type QueryOptions as T, type ReconnectOptions as U, type ReconnectableWsConnection as V, type ResolvedCitation as W, type ResolvedRecipient as X, type ResponseCompletedEvent as Y, type ResponseContentPartAddedEvent as Z, type ResponseCreatedEvent as _, type AgentStepDeltaEvent as a, parseSlashCommand as a$, type ResponseOutputItemAddedEvent as a0, type ResponseOutputItemDoneEvent as a1, type ResponseOutputTextDeltaEvent as a2, type ResponseOutputTextDoneEvent as a3, type ResponseUsage as a4, type SSEEvent as a5, type SSEStreamCallbacks as a6, type SSEStreamResult as a7, type SSEStreamStartData as a8, SUPPORTED_EXTENSIONS as a9, connectWithReconnect as aA, consumeSSEStream as aB, contacts as aC, conversations as aD, countCitations as aE, createAuthenticatedClient as aF, createDocumentWaiter as aG, dm as aH, doctags as aI, documents as aJ, facts as aK, files as aL, filterSkills as aM, formatAgentStepLabel as aN, formatFileSize as aO, formatItemLabel as aP, formatStreamSummary as aQ, formatUserName as aR, formatWorkspaceChoices as aS, formatWsMessage as aT, generateEncryptedWorkspaceKey as aU, generateNewWorkspaceKey as aV, getErrorCode as aW, getErrorMessage as aX, getRawWorkspaceKey as aY, health as aZ, parseSSEEvents as a_, type SkillSummary as aa, type SkippedFile as ab, type TaskResponse as ac, type TokenBudgetContext as ad, type UpdateFactRequest as ae, type UpdateTaskRequest as af, type UploadBatchResult as ag, type UploadDirectOptions as ah, type UploadDirectResult as ai, type UploadOptions as aj, type UploadResult as ak, type UserDailyUsageResponse as al, type UserInfo as am, type UserInputRequestEvent as an, type UserMessageEvent as ao, WebSocketAuthError as ap, type WorkspaceContext as aq, type WsConnection as ar, agentconfig as as, assistant as at, authenticatedFetch as au, buildDocNameMap as av, buildRetrievalChunkTool as aw, buildRetrievalFullContextTool as ax, buildRetrievalTocTool as ay, connectWebSocket as az, type AgentStepEvent as b, parseSlashTokenInProgress as b0, performPasswordLogin as b1, performSigningKeyLogin as b2, performSsoDeviceFlowLogin as b3, projects as b4, requireData as b5, requireOk as b6, resolveAuth as b7, resolveCitations as b8, resolveWorkspace as b9, responses as ba, selectWorkspace as bb, selectWorkspaceById as bc, settings as bd, streamSSE as be, stripCitationMarkdown as bf, summarizeCitations as bg, tags as bh, tasks as bi, workspaces as bj, Arbi as c, ArbiApiError as d, ArbiError as e, type ArbiErrorEvent as f, type ArbiOptions as g, type ArtifactEvent as h, type AuthContext as i, type AuthHeaders as j, type AuthenticatedClient as k, type CitationSummary as l, type CliConfig as m, type CliCredentials as n, type CommandDescriptor as o, type ConfigStore as p, type ConnectOptions as q, type CreateFactRequest as r, type CreateFactsRequest as s, type CreateTaskRequest as t, type DeferredInterjectionEvent as u, type DmCryptoContext as v, type DocNameMap as w, type DocumentListFields as x, type DocumentListOrder as y, type DocumentWaiter as z };
6000
+ export { type ResponseCreatedEvent as $, type AgentControlStateEvent as A, type DocumentWaiter as B, type ChatSession as C, DOC_TERMINAL_STATUSES as D, type DocumentWaiterOptions as E, type FactResponse as F, type FactSearchRequest as G, type FactSearchResponse as H, type FormattedWsMessage as I, type ListFactsOptions as J, type ListPaginatedOptions as K, type ListAllOptions as L, type MessageLevel as M, type MessageMetadataPayload$1 as N, type MessageQueuedEvent as O, type OutputTokensDetails as P, type ParsedSlashCommand as Q, type ProbeAnswerEvent as R, type ProjectInvoicesResponse as S, type ProjectUsageResponse as T, type QueryOptions as U, type ReconnectOptions as V, type ReconnectableWsConnection as W, type ResolvedCitation as X, type ResolvedRecipient as Y, type ResponseCompletedEvent as Z, type ResponseContentPartAddedEvent as _, type AgentStepDeltaEvent as a, parseSSEEvents as a$, type ResponseFailedEvent as a0, type ResponseOutputItemAddedEvent as a1, type ResponseOutputItemDoneEvent as a2, type ResponseOutputTextDeltaEvent as a3, type ResponseOutputTextDoneEvent as a4, type ResponseUsage as a5, type SSEEvent as a6, type SSEStreamCallbacks as a7, type SSEStreamResult as a8, type SSEStreamStartData as a9, connectWebSocket as aA, connectWithReconnect as aB, consumeSSEStream as aC, contacts as aD, conversations as aE, countCitations as aF, createAuthenticatedClient as aG, createDocumentWaiter as aH, dm as aI, doctags as aJ, documents as aK, facts as aL, files as aM, filterSkills as aN, formatAgentStepLabel as aO, formatFileSize as aP, formatItemLabel as aQ, formatStreamSummary as aR, formatUserName as aS, formatWorkspaceChoices as aT, formatWsMessage as aU, generateEncryptedWorkspaceKey as aV, generateNewWorkspaceKey as aW, getErrorCode as aX, getErrorMessage as aY, getRawWorkspaceKey as aZ, health as a_, SUPPORTED_EXTENSIONS as aa, type SkillSummary as ab, type SkippedFile as ac, type TaskResponse as ad, type TokenBudgetContext as ae, type UpdateFactRequest as af, type UpdateTaskRequest as ag, type UploadBatchResult as ah, type UploadDirectOptions as ai, type UploadDirectResult as aj, type UploadOptions as ak, type UploadResult as al, type UserDailyUsageResponse as am, type UserInfo as an, type UserInputRequestEvent as ao, type UserMessageEvent as ap, WebSocketAuthError as aq, type WorkspaceContext as ar, type WsConnection as as, agentconfig as at, assistant as au, authenticatedFetch as av, buildDocNameMap as aw, buildRetrievalChunkTool as ax, buildRetrievalFullContextTool as ay, buildRetrievalTocTool as az, type AgentStepEvent as b, parseSlashCommand as b0, parseSlashTokenInProgress as b1, performPasswordLogin as b2, performSigningKeyLogin as b3, performSsoDeviceFlowLogin as b4, projects as b5, requireData as b6, requireOk as b7, resolveAuth as b8, resolveCitations as b9, resolveWorkspace as ba, responses as bb, selectWorkspace as bc, selectWorkspaceById as bd, settings as be, streamSSE as bf, stripCitationMarkdown as bg, summarizeCitations as bh, tags as bi, tasks as bj, workspaces as bk, Arbi as c, ArbiApiError as d, ArbiError as e, type ArbiErrorEvent as f, type ArbiOptions as g, ArbiSessionExpiredError as h, type ArtifactEvent as i, type AuthContext as j, type AuthHeaders as k, type AuthenticatedClient as l, type CitationSummary as m, type CliConfig as n, type CliCredentials as o, type CommandDescriptor as p, type ConfigStore as q, type ConnectOptions as r, type CreateFactRequest as s, type CreateFactsRequest as t, type CreateTaskRequest as u, type DeferredInterjectionEvent as v, type DmCryptoContext as w, type DocNameMap as x, type DocumentListFields as y, type DocumentListOrder as z };
@@ -9,6 +9,10 @@ import { SessionStorageProvider, ArbiClient, LoginResult, components, WebSocketS
9
9
  declare class ArbiError extends Error {
10
10
  constructor(message: string);
11
11
  }
12
+ /** The session cannot be recovered (token and workspace re-open both refused): sign in again. */
13
+ declare class ArbiSessionExpiredError extends ArbiError {
14
+ constructor(message?: string);
15
+ }
12
16
  declare class ArbiApiError extends ArbiError {
13
17
  readonly apiError?: unknown;
14
18
  constructor(message: string, apiError?: unknown);
@@ -2034,6 +2038,7 @@ declare class Arbi {
2034
2038
  private loginResult;
2035
2039
  private currentWorkspaceId;
2036
2040
  private dmCryptoContext;
2041
+ private readonly sessionExpiredListeners;
2037
2042
  private readonly options;
2038
2043
  constructor(options: ArbiOptions);
2039
2044
  /** Initialize the SDK client and sodium crypto. Called automatically by login(). */
@@ -2068,6 +2073,20 @@ declare class Arbi {
2068
2073
  * workspace, decrypts the wrapped key, and sets up auth headers.
2069
2074
  */
2070
2075
  selectWorkspace(workspaceId: string): Promise<void>;
2076
+ /**
2077
+ * Subscribe to "the session cannot be recovered". Fires when a request failed with 401 or
2078
+ * "No active workspace" and neither a workspace re-open nor a silent re-login was possible
2079
+ * (the server refused; an unreachable server does not fire). The local session is already
2080
+ * cleared when it fires: show "Your session expired, sign in again". Returns an unsubscribe.
2081
+ */
2082
+ onSessionExpired(listener: () => void): () => void;
2083
+ private expireSession;
2084
+ /**
2085
+ * Run a raw-fetch operation (streaming, multipart: no middleware) and, when it fails because
2086
+ * the token expired or the server lost the open workspace, recover once and run it again.
2087
+ * `run` must read the auth headers itself so the retry carries the fresh token.
2088
+ */
2089
+ private recovering;
2071
2090
  /** Log out and clear internal state. */
2072
2091
  logout(): Promise<void>;
2073
2092
  /** Get the underlying ArbiClient (throws if not initialized). */
@@ -5978,4 +5997,4 @@ declare namespace projects {
5978
5997
  export { type projects_ProjectInvoicesResponse as ProjectInvoicesResponse, type projects_ProjectUpdateRequest as ProjectUpdateRequest, type projects_ProjectUsageResponse as ProjectUsageResponse, type projects_UserDailyUsageResponse as UserDailyUsageResponse, projects_createProject as createProject, projects_deleteProject as deleteProject, projects_getProjectInvoices as getProjectInvoices, projects_getProjectUsage as getProjectUsage, projects_getUserUsageToday as getUserUsageToday, projects_listProjects as listProjects, projects_refreshProject as refreshProject, projects_renameProject as renameProject, projects_updateProject as updateProject };
5979
5998
  }
5980
5999
 
5981
- export { type ResponseFailedEvent as $, type AgentControlStateEvent as A, type DocumentWaiterOptions as B, type ChatSession as C, DOC_TERMINAL_STATUSES as D, type FactSearchRequest as E, type FactResponse as F, type FactSearchResponse as G, type FormattedWsMessage as H, type ListFactsOptions as I, type ListPaginatedOptions as J, type MessageMetadataPayload$1 as K, type ListAllOptions as L, type MessageLevel as M, type MessageQueuedEvent as N, type OutputTokensDetails as O, type ParsedSlashCommand as P, type ProbeAnswerEvent as Q, type ProjectInvoicesResponse as R, type ProjectUsageResponse as S, type QueryOptions as T, type ReconnectOptions as U, type ReconnectableWsConnection as V, type ResolvedCitation as W, type ResolvedRecipient as X, type ResponseCompletedEvent as Y, type ResponseContentPartAddedEvent as Z, type ResponseCreatedEvent as _, type AgentStepDeltaEvent as a, parseSlashCommand as a$, type ResponseOutputItemAddedEvent as a0, type ResponseOutputItemDoneEvent as a1, type ResponseOutputTextDeltaEvent as a2, type ResponseOutputTextDoneEvent as a3, type ResponseUsage as a4, type SSEEvent as a5, type SSEStreamCallbacks as a6, type SSEStreamResult as a7, type SSEStreamStartData as a8, SUPPORTED_EXTENSIONS as a9, connectWithReconnect as aA, consumeSSEStream as aB, contacts as aC, conversations as aD, countCitations as aE, createAuthenticatedClient as aF, createDocumentWaiter as aG, dm as aH, doctags as aI, documents as aJ, facts as aK, files as aL, filterSkills as aM, formatAgentStepLabel as aN, formatFileSize as aO, formatItemLabel as aP, formatStreamSummary as aQ, formatUserName as aR, formatWorkspaceChoices as aS, formatWsMessage as aT, generateEncryptedWorkspaceKey as aU, generateNewWorkspaceKey as aV, getErrorCode as aW, getErrorMessage as aX, getRawWorkspaceKey as aY, health as aZ, parseSSEEvents as a_, type SkillSummary as aa, type SkippedFile as ab, type TaskResponse as ac, type TokenBudgetContext as ad, type UpdateFactRequest as ae, type UpdateTaskRequest as af, type UploadBatchResult as ag, type UploadDirectOptions as ah, type UploadDirectResult as ai, type UploadOptions as aj, type UploadResult as ak, type UserDailyUsageResponse as al, type UserInfo as am, type UserInputRequestEvent as an, type UserMessageEvent as ao, WebSocketAuthError as ap, type WorkspaceContext as aq, type WsConnection as ar, agentconfig as as, assistant as at, authenticatedFetch as au, buildDocNameMap as av, buildRetrievalChunkTool as aw, buildRetrievalFullContextTool as ax, buildRetrievalTocTool as ay, connectWebSocket as az, type AgentStepEvent as b, parseSlashTokenInProgress as b0, performPasswordLogin as b1, performSigningKeyLogin as b2, performSsoDeviceFlowLogin as b3, projects as b4, requireData as b5, requireOk as b6, resolveAuth as b7, resolveCitations as b8, resolveWorkspace as b9, responses as ba, selectWorkspace as bb, selectWorkspaceById as bc, settings as bd, streamSSE as be, stripCitationMarkdown as bf, summarizeCitations as bg, tags as bh, tasks as bi, workspaces as bj, Arbi as c, ArbiApiError as d, ArbiError as e, type ArbiErrorEvent as f, type ArbiOptions as g, type ArtifactEvent as h, type AuthContext as i, type AuthHeaders as j, type AuthenticatedClient as k, type CitationSummary as l, type CliConfig as m, type CliCredentials as n, type CommandDescriptor as o, type ConfigStore as p, type ConnectOptions as q, type CreateFactRequest as r, type CreateFactsRequest as s, type CreateTaskRequest as t, type DeferredInterjectionEvent as u, type DmCryptoContext as v, type DocNameMap as w, type DocumentListFields as x, type DocumentListOrder as y, type DocumentWaiter as z };
6000
+ export { type ResponseCreatedEvent as $, type AgentControlStateEvent as A, type DocumentWaiter as B, type ChatSession as C, DOC_TERMINAL_STATUSES as D, type DocumentWaiterOptions as E, type FactResponse as F, type FactSearchRequest as G, type FactSearchResponse as H, type FormattedWsMessage as I, type ListFactsOptions as J, type ListPaginatedOptions as K, type ListAllOptions as L, type MessageLevel as M, type MessageMetadataPayload$1 as N, type MessageQueuedEvent as O, type OutputTokensDetails as P, type ParsedSlashCommand as Q, type ProbeAnswerEvent as R, type ProjectInvoicesResponse as S, type ProjectUsageResponse as T, type QueryOptions as U, type ReconnectOptions as V, type ReconnectableWsConnection as W, type ResolvedCitation as X, type ResolvedRecipient as Y, type ResponseCompletedEvent as Z, type ResponseContentPartAddedEvent as _, type AgentStepDeltaEvent as a, parseSSEEvents as a$, type ResponseFailedEvent as a0, type ResponseOutputItemAddedEvent as a1, type ResponseOutputItemDoneEvent as a2, type ResponseOutputTextDeltaEvent as a3, type ResponseOutputTextDoneEvent as a4, type ResponseUsage as a5, type SSEEvent as a6, type SSEStreamCallbacks as a7, type SSEStreamResult as a8, type SSEStreamStartData as a9, connectWebSocket as aA, connectWithReconnect as aB, consumeSSEStream as aC, contacts as aD, conversations as aE, countCitations as aF, createAuthenticatedClient as aG, createDocumentWaiter as aH, dm as aI, doctags as aJ, documents as aK, facts as aL, files as aM, filterSkills as aN, formatAgentStepLabel as aO, formatFileSize as aP, formatItemLabel as aQ, formatStreamSummary as aR, formatUserName as aS, formatWorkspaceChoices as aT, formatWsMessage as aU, generateEncryptedWorkspaceKey as aV, generateNewWorkspaceKey as aW, getErrorCode as aX, getErrorMessage as aY, getRawWorkspaceKey as aZ, health as a_, SUPPORTED_EXTENSIONS as aa, type SkillSummary as ab, type SkippedFile as ac, type TaskResponse as ad, type TokenBudgetContext as ae, type UpdateFactRequest as af, type UpdateTaskRequest as ag, type UploadBatchResult as ah, type UploadDirectOptions as ai, type UploadDirectResult as aj, type UploadOptions as ak, type UploadResult as al, type UserDailyUsageResponse as am, type UserInfo as an, type UserInputRequestEvent as ao, type UserMessageEvent as ap, WebSocketAuthError as aq, type WorkspaceContext as ar, type WsConnection as as, agentconfig as at, assistant as au, authenticatedFetch as av, buildDocNameMap as aw, buildRetrievalChunkTool as ax, buildRetrievalFullContextTool as ay, buildRetrievalTocTool as az, type AgentStepEvent as b, parseSlashCommand as b0, parseSlashTokenInProgress as b1, performPasswordLogin as b2, performSigningKeyLogin as b3, performSsoDeviceFlowLogin as b4, projects as b5, requireData as b6, requireOk as b7, resolveAuth as b8, resolveCitations as b9, resolveWorkspace as ba, responses as bb, selectWorkspace as bc, selectWorkspaceById as bd, settings as be, streamSSE as bf, stripCitationMarkdown as bg, summarizeCitations as bh, tags as bi, tasks as bj, workspaces as bk, Arbi as c, ArbiApiError as d, ArbiError as e, type ArbiErrorEvent as f, type ArbiOptions as g, ArbiSessionExpiredError as h, type ArtifactEvent as i, type AuthContext as j, type AuthHeaders as k, type AuthenticatedClient as l, type CitationSummary as m, type CliConfig as n, type CliCredentials as o, type CommandDescriptor as p, type ConfigStore as q, type ConnectOptions as r, type CreateFactRequest as s, type CreateFactsRequest as t, type CreateTaskRequest as u, type DeferredInterjectionEvent as v, type DmCryptoContext as w, type DocNameMap as x, type DocumentListFields as y, type DocumentListOrder as z };
package/dist/browser.cjs CHANGED
@@ -3484,6 +3484,12 @@ var ArbiError = class extends Error {
3484
3484
  this.name = "ArbiError";
3485
3485
  }
3486
3486
  };
3487
+ var ArbiSessionExpiredError = class extends ArbiError {
3488
+ constructor(message = "Your session expired. Sign in again.") {
3489
+ super(message);
3490
+ this.name = "ArbiSessionExpiredError";
3491
+ }
3492
+ };
3487
3493
  var ArbiApiError = class extends ArbiError {
3488
3494
  apiError;
3489
3495
  constructor(message, apiError) {
@@ -5620,11 +5626,23 @@ async function remindFact(arbi, factId, options = {}) {
5620
5626
  }
5621
5627
 
5622
5628
  // src/arbi.ts
5629
+ function tokenExpiresWithin(token, seconds) {
5630
+ const payload = token?.split(".")[1];
5631
+ if (!payload) return false;
5632
+ try {
5633
+ const json = atob(payload.replace(/-/g, "+").replace(/_/g, "/"));
5634
+ const { exp } = JSON.parse(json);
5635
+ return typeof exp === "number" && exp * 1e3 - Date.now() < seconds * 1e3;
5636
+ } catch {
5637
+ return false;
5638
+ }
5639
+ }
5623
5640
  var Arbi = class {
5624
5641
  client = null;
5625
5642
  loginResult = null;
5626
5643
  currentWorkspaceId = null;
5627
5644
  dmCryptoContext = null;
5645
+ sessionExpiredListeners = /* @__PURE__ */ new Set();
5628
5646
  options;
5629
5647
  constructor(options) {
5630
5648
  this.options = options;
@@ -5637,7 +5655,13 @@ var Arbi = class {
5637
5655
  this.client = client.createArbiClient({
5638
5656
  baseUrl: this.options.url,
5639
5657
  deploymentDomain: domain,
5640
- credentials: this.options.credentials ?? "omit"
5658
+ credentials: this.options.credentials ?? "omit",
5659
+ // A silent re-login rotates the server session key: keep ours in step, or the next
5660
+ // workspace open would seal the key for a session the server no longer has.
5661
+ onReloginSuccess: ({ serverSessionKey }) => {
5662
+ if (this.loginResult) this.loginResult = { ...this.loginResult, serverSessionKey };
5663
+ },
5664
+ onSessionExpired: () => this.expireSession()
5641
5665
  });
5642
5666
  await this.client.crypto.initSodium();
5643
5667
  return this.client;
@@ -5700,6 +5724,52 @@ var Arbi = class {
5700
5724
  });
5701
5725
  this.currentWorkspaceId = ws.external_id;
5702
5726
  }
5727
+ /**
5728
+ * Subscribe to "the session cannot be recovered". Fires when a request failed with 401 or
5729
+ * "No active workspace" and neither a workspace re-open nor a silent re-login was possible
5730
+ * (the server refused; an unreachable server does not fire). The local session is already
5731
+ * cleared when it fires: show "Your session expired, sign in again". Returns an unsubscribe.
5732
+ */
5733
+ onSessionExpired(listener) {
5734
+ this.sessionExpiredListeners.add(listener);
5735
+ return () => this.sessionExpiredListeners.delete(listener);
5736
+ }
5737
+ expireSession() {
5738
+ if (this.loginResult) {
5739
+ this.loginResult.signingPrivateKey.fill(0);
5740
+ this.loginResult.serverSessionKey.fill(0);
5741
+ }
5742
+ this.loginResult = null;
5743
+ this.currentWorkspaceId = null;
5744
+ this.dmCryptoContext = null;
5745
+ this.client?.session.clear();
5746
+ for (const listener of [...this.sessionExpiredListeners]) listener();
5747
+ }
5748
+ /**
5749
+ * Run a raw-fetch operation (streaming, multipart: no middleware) and, when it fails because
5750
+ * the token expired or the server lost the open workspace, recover once and run it again.
5751
+ * `run` must read the auth headers itself so the retry carries the fresh token.
5752
+ */
5753
+ async recovering(run) {
5754
+ if (this.client && tokenExpiresWithin(this.client.session.getState().accessToken, 30)) {
5755
+ await this.client.auth.relogin();
5756
+ }
5757
+ try {
5758
+ return await run();
5759
+ } catch (error) {
5760
+ const message = error instanceof Error ? error.message : "";
5761
+ const noWorkspace = /no active workspace/i.test(message);
5762
+ const unauthorised = /\b401\b|token has expired/i.test(message);
5763
+ if (!(error instanceof ArbiApiError) || !(noWorkspace || unauthorised)) throw error;
5764
+ const client = this.requireClient();
5765
+ const recovered = noWorkspace && await client.auth.reopenWorkspace() || await client.auth.relogin() !== null;
5766
+ if (!recovered) {
5767
+ this.expireSession();
5768
+ throw new ArbiSessionExpiredError();
5769
+ }
5770
+ return run();
5771
+ }
5772
+ }
5703
5773
  /** Log out and clear internal state. */
5704
5774
  async logout() {
5705
5775
  if (this.client) {
@@ -5866,16 +5936,18 @@ var Arbi = class {
5866
5936
  },
5867
5937
  uploadFile: (fileData, fileName, options) => {
5868
5938
  this.requireWorkspace();
5869
- return uploadFile(
5870
- this.getAuthHeaders(),
5871
- fileData,
5872
- fileName,
5873
- options?.folder ? { folder: options.folder } : void 0
5939
+ return this.recovering(
5940
+ () => uploadFile(
5941
+ this.getAuthHeaders(),
5942
+ fileData,
5943
+ fileName,
5944
+ options?.folder ? { folder: options.folder } : void 0
5945
+ )
5874
5946
  );
5875
5947
  },
5876
- download: (docId) => downloadDocument(this.getAuthHeaders(), docId),
5877
- getParsedContent: (docId, stage) => getParsedContent(this.getAuthHeaders(), docId, stage),
5878
- getThumbnails: (docIds) => getThumbnails(this.getAuthHeaders(), docIds)
5948
+ download: (docId) => this.recovering(() => downloadDocument(this.getAuthHeaders(), docId)),
5949
+ getParsedContent: (docId, stage) => this.recovering(() => getParsedContent(this.getAuthHeaders(), docId, stage)),
5950
+ getThumbnails: (docIds) => this.recovering(() => getThumbnails(this.getAuthHeaders(), docIds))
5879
5951
  };
5880
5952
  // ── Conversations ─────────────────────────────────────────────────────
5881
5953
  conversations = {
@@ -5894,16 +5966,17 @@ var Arbi = class {
5894
5966
  * Returns the accumulated result after the stream completes.
5895
5967
  */
5896
5968
  query: async (question, options) => {
5897
- const auth = this.getAuthHeaders();
5898
5969
  const workspaceId = this.requireWorkspace();
5899
- const response = await queryAssistant({
5900
- ...auth,
5901
- workspaceId,
5902
- question,
5903
- docIds: options.docIds,
5904
- previousResponseId: options.previousResponseId,
5905
- model: options.model
5906
- });
5970
+ const response = await this.recovering(
5971
+ () => queryAssistant({
5972
+ ...this.getAuthHeaders(),
5973
+ workspaceId,
5974
+ question,
5975
+ docIds: options.docIds,
5976
+ previousResponseId: options.previousResponseId,
5977
+ model: options.model
5978
+ })
5979
+ );
5907
5980
  const callbacks = {
5908
5981
  onToken: options.onToken,
5909
5982
  onStreamStart: options.onStreamStart,
@@ -6067,8 +6140,10 @@ var Arbi = class {
6067
6140
  list: (options) => listFiles(this.requireClient(), options),
6068
6141
  get: (fileId) => getFile(this.requireClient(), fileId),
6069
6142
  delete: (fileId) => deleteFile(this.requireClient(), fileId),
6070
- upload: (fileData, fileName, purpose) => uploadFile2(this.getAuthHeaders(), fileData, fileName, purpose),
6071
- getContent: (fileId) => getFileContent(this.getAuthHeaders(), fileId)
6143
+ upload: (fileData, fileName, purpose) => this.recovering(
6144
+ () => uploadFile2(this.getAuthHeaders(), fileData, fileName, purpose)
6145
+ ),
6146
+ getContent: (fileId) => this.recovering(() => getFileContent(this.getAuthHeaders(), fileId))
6072
6147
  };
6073
6148
  // ── Agents ──────────────────────────────────────────────────────────
6074
6149
  agents = {