@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.
- package/dist/{browser-U90kdb7T.d.cts → browser-4VHbRx1J.d.cts} +20 -1
- package/dist/{browser-U90kdb7T.d.ts → browser-4VHbRx1J.d.ts} +20 -1
- package/dist/browser.cjs +95 -20
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.cts +1 -1
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +95 -20
- package/dist/browser.js.map +1 -1
- package/dist/index.cjs +96 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +96 -21
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -3496,6 +3496,12 @@ var ArbiError = class extends Error {
|
|
|
3496
3496
|
this.name = "ArbiError";
|
|
3497
3497
|
}
|
|
3498
3498
|
};
|
|
3499
|
+
var ArbiSessionExpiredError = class extends ArbiError {
|
|
3500
|
+
constructor(message = "Your session expired. Sign in again.") {
|
|
3501
|
+
super(message);
|
|
3502
|
+
this.name = "ArbiSessionExpiredError";
|
|
3503
|
+
}
|
|
3504
|
+
};
|
|
3499
3505
|
var ArbiApiError = class extends ArbiError {
|
|
3500
3506
|
apiError;
|
|
3501
3507
|
constructor(message, apiError) {
|
|
@@ -6191,11 +6197,23 @@ async function remindFact(arbi, factId, options = {}) {
|
|
|
6191
6197
|
}
|
|
6192
6198
|
|
|
6193
6199
|
// src/arbi.ts
|
|
6200
|
+
function tokenExpiresWithin(token, seconds) {
|
|
6201
|
+
const payload = token?.split(".")[1];
|
|
6202
|
+
if (!payload) return false;
|
|
6203
|
+
try {
|
|
6204
|
+
const json = atob(payload.replace(/-/g, "+").replace(/_/g, "/"));
|
|
6205
|
+
const { exp } = JSON.parse(json);
|
|
6206
|
+
return typeof exp === "number" && exp * 1e3 - Date.now() < seconds * 1e3;
|
|
6207
|
+
} catch {
|
|
6208
|
+
return false;
|
|
6209
|
+
}
|
|
6210
|
+
}
|
|
6194
6211
|
var Arbi = class {
|
|
6195
6212
|
client = null;
|
|
6196
6213
|
loginResult = null;
|
|
6197
6214
|
currentWorkspaceId = null;
|
|
6198
6215
|
dmCryptoContext = null;
|
|
6216
|
+
sessionExpiredListeners = /* @__PURE__ */ new Set();
|
|
6199
6217
|
options;
|
|
6200
6218
|
constructor(options) {
|
|
6201
6219
|
this.options = options;
|
|
@@ -6208,7 +6226,13 @@ var Arbi = class {
|
|
|
6208
6226
|
this.client = client.createArbiClient({
|
|
6209
6227
|
baseUrl: this.options.url,
|
|
6210
6228
|
deploymentDomain: domain,
|
|
6211
|
-
credentials: this.options.credentials ?? "omit"
|
|
6229
|
+
credentials: this.options.credentials ?? "omit",
|
|
6230
|
+
// A silent re-login rotates the server session key: keep ours in step, or the next
|
|
6231
|
+
// workspace open would seal the key for a session the server no longer has.
|
|
6232
|
+
onReloginSuccess: ({ serverSessionKey }) => {
|
|
6233
|
+
if (this.loginResult) this.loginResult = { ...this.loginResult, serverSessionKey };
|
|
6234
|
+
},
|
|
6235
|
+
onSessionExpired: () => this.expireSession()
|
|
6212
6236
|
});
|
|
6213
6237
|
await this.client.crypto.initSodium();
|
|
6214
6238
|
return this.client;
|
|
@@ -6271,6 +6295,52 @@ var Arbi = class {
|
|
|
6271
6295
|
});
|
|
6272
6296
|
this.currentWorkspaceId = ws.external_id;
|
|
6273
6297
|
}
|
|
6298
|
+
/**
|
|
6299
|
+
* Subscribe to "the session cannot be recovered". Fires when a request failed with 401 or
|
|
6300
|
+
* "No active workspace" and neither a workspace re-open nor a silent re-login was possible
|
|
6301
|
+
* (the server refused; an unreachable server does not fire). The local session is already
|
|
6302
|
+
* cleared when it fires: show "Your session expired, sign in again". Returns an unsubscribe.
|
|
6303
|
+
*/
|
|
6304
|
+
onSessionExpired(listener) {
|
|
6305
|
+
this.sessionExpiredListeners.add(listener);
|
|
6306
|
+
return () => this.sessionExpiredListeners.delete(listener);
|
|
6307
|
+
}
|
|
6308
|
+
expireSession() {
|
|
6309
|
+
if (this.loginResult) {
|
|
6310
|
+
this.loginResult.signingPrivateKey.fill(0);
|
|
6311
|
+
this.loginResult.serverSessionKey.fill(0);
|
|
6312
|
+
}
|
|
6313
|
+
this.loginResult = null;
|
|
6314
|
+
this.currentWorkspaceId = null;
|
|
6315
|
+
this.dmCryptoContext = null;
|
|
6316
|
+
this.client?.session.clear();
|
|
6317
|
+
for (const listener of [...this.sessionExpiredListeners]) listener();
|
|
6318
|
+
}
|
|
6319
|
+
/**
|
|
6320
|
+
* Run a raw-fetch operation (streaming, multipart: no middleware) and, when it fails because
|
|
6321
|
+
* the token expired or the server lost the open workspace, recover once and run it again.
|
|
6322
|
+
* `run` must read the auth headers itself so the retry carries the fresh token.
|
|
6323
|
+
*/
|
|
6324
|
+
async recovering(run) {
|
|
6325
|
+
if (this.client && tokenExpiresWithin(this.client.session.getState().accessToken, 30)) {
|
|
6326
|
+
await this.client.auth.relogin();
|
|
6327
|
+
}
|
|
6328
|
+
try {
|
|
6329
|
+
return await run();
|
|
6330
|
+
} catch (error) {
|
|
6331
|
+
const message = error instanceof Error ? error.message : "";
|
|
6332
|
+
const noWorkspace = /no active workspace/i.test(message);
|
|
6333
|
+
const unauthorised = /\b401\b|token has expired/i.test(message);
|
|
6334
|
+
if (!(error instanceof ArbiApiError) || !(noWorkspace || unauthorised)) throw error;
|
|
6335
|
+
const client = this.requireClient();
|
|
6336
|
+
const recovered = noWorkspace && await client.auth.reopenWorkspace() || await client.auth.relogin() !== null;
|
|
6337
|
+
if (!recovered) {
|
|
6338
|
+
this.expireSession();
|
|
6339
|
+
throw new ArbiSessionExpiredError();
|
|
6340
|
+
}
|
|
6341
|
+
return run();
|
|
6342
|
+
}
|
|
6343
|
+
}
|
|
6274
6344
|
/** Log out and clear internal state. */
|
|
6275
6345
|
async logout() {
|
|
6276
6346
|
if (this.client) {
|
|
@@ -6437,16 +6507,18 @@ var Arbi = class {
|
|
|
6437
6507
|
},
|
|
6438
6508
|
uploadFile: (fileData, fileName, options) => {
|
|
6439
6509
|
this.requireWorkspace();
|
|
6440
|
-
return
|
|
6441
|
-
|
|
6442
|
-
|
|
6443
|
-
|
|
6444
|
-
|
|
6510
|
+
return this.recovering(
|
|
6511
|
+
() => uploadFile(
|
|
6512
|
+
this.getAuthHeaders(),
|
|
6513
|
+
fileData,
|
|
6514
|
+
fileName,
|
|
6515
|
+
options?.folder ? { folder: options.folder } : void 0
|
|
6516
|
+
)
|
|
6445
6517
|
);
|
|
6446
6518
|
},
|
|
6447
|
-
download: (docId) => downloadDocument(this.getAuthHeaders(), docId),
|
|
6448
|
-
getParsedContent: (docId, stage) => getParsedContent(this.getAuthHeaders(), docId, stage),
|
|
6449
|
-
getThumbnails: (docIds) => getThumbnails(this.getAuthHeaders(), docIds)
|
|
6519
|
+
download: (docId) => this.recovering(() => downloadDocument(this.getAuthHeaders(), docId)),
|
|
6520
|
+
getParsedContent: (docId, stage) => this.recovering(() => getParsedContent(this.getAuthHeaders(), docId, stage)),
|
|
6521
|
+
getThumbnails: (docIds) => this.recovering(() => getThumbnails(this.getAuthHeaders(), docIds))
|
|
6450
6522
|
};
|
|
6451
6523
|
// ── Conversations ─────────────────────────────────────────────────────
|
|
6452
6524
|
conversations = {
|
|
@@ -6465,16 +6537,17 @@ var Arbi = class {
|
|
|
6465
6537
|
* Returns the accumulated result after the stream completes.
|
|
6466
6538
|
*/
|
|
6467
6539
|
query: async (question, options) => {
|
|
6468
|
-
const auth = this.getAuthHeaders();
|
|
6469
6540
|
const workspaceId = this.requireWorkspace();
|
|
6470
|
-
const response = await
|
|
6471
|
-
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
|
|
6541
|
+
const response = await this.recovering(
|
|
6542
|
+
() => queryAssistant({
|
|
6543
|
+
...this.getAuthHeaders(),
|
|
6544
|
+
workspaceId,
|
|
6545
|
+
question,
|
|
6546
|
+
docIds: options.docIds,
|
|
6547
|
+
previousResponseId: options.previousResponseId,
|
|
6548
|
+
model: options.model
|
|
6549
|
+
})
|
|
6550
|
+
);
|
|
6478
6551
|
const callbacks = {
|
|
6479
6552
|
onToken: options.onToken,
|
|
6480
6553
|
onStreamStart: options.onStreamStart,
|
|
@@ -6638,8 +6711,10 @@ var Arbi = class {
|
|
|
6638
6711
|
list: (options) => listFiles(this.requireClient(), options),
|
|
6639
6712
|
get: (fileId) => getFile(this.requireClient(), fileId),
|
|
6640
6713
|
delete: (fileId) => deleteFile(this.requireClient(), fileId),
|
|
6641
|
-
upload: (fileData, fileName, purpose) =>
|
|
6642
|
-
|
|
6714
|
+
upload: (fileData, fileName, purpose) => this.recovering(
|
|
6715
|
+
() => uploadFile2(this.getAuthHeaders(), fileData, fileName, purpose)
|
|
6716
|
+
),
|
|
6717
|
+
getContent: (fileId) => this.recovering(() => getFileContent(this.getAuthHeaders(), fileId))
|
|
6643
6718
|
};
|
|
6644
6719
|
// ── Agents ──────────────────────────────────────────────────────────
|
|
6645
6720
|
agents = {
|
|
@@ -7824,6 +7899,7 @@ async function startDmListener(options) {
|
|
|
7824
7899
|
exports.Arbi = Arbi;
|
|
7825
7900
|
exports.ArbiApiError = ArbiApiError;
|
|
7826
7901
|
exports.ArbiError = ArbiError;
|
|
7902
|
+
exports.ArbiSessionExpiredError = ArbiSessionExpiredError;
|
|
7827
7903
|
exports.ClaudeOrchestrator = ClaudeOrchestrator;
|
|
7828
7904
|
exports.DOC_TERMINAL_STATUSES = DOC_TERMINAL_STATUSES;
|
|
7829
7905
|
exports.FileConfigStore = FileConfigStore;
|