@arbidocs/sdk 0.3.17 → 0.3.18
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-BtAHbiq_.d.cts → browser-DUQ3Eyvd.d.cts} +14 -1
- package/dist/{browser-BtAHbiq_.d.ts → browser-DUQ3Eyvd.d.ts} +14 -1
- package/dist/browser.cjs +4 -1
- 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 +4 -1
- package/dist/browser.js.map +1 -1
- package/dist/index.cjs +139 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +63 -3
- package/dist/index.d.ts +63 -3
- package/dist/index.js +138 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -285,6 +285,107 @@ var FileConfigStore = class {
|
|
|
285
285
|
return null;
|
|
286
286
|
}
|
|
287
287
|
};
|
|
288
|
+
|
|
289
|
+
// src/device-flow.ts
|
|
290
|
+
var device_flow_exports = {};
|
|
291
|
+
__export(device_flow_exports, {
|
|
292
|
+
DeviceFlowAccessDenied: () => DeviceFlowAccessDenied,
|
|
293
|
+
DeviceFlowError: () => DeviceFlowError,
|
|
294
|
+
DeviceFlowExpired: () => DeviceFlowExpired,
|
|
295
|
+
fetchSsoConfig: () => fetchSsoConfig,
|
|
296
|
+
pollForToken: () => pollForToken,
|
|
297
|
+
requestDeviceCode: () => requestDeviceCode
|
|
298
|
+
});
|
|
299
|
+
var DeviceFlowError = class extends Error {
|
|
300
|
+
constructor(message) {
|
|
301
|
+
super(message);
|
|
302
|
+
this.name = "DeviceFlowError";
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
var DeviceFlowExpired = class extends DeviceFlowError {
|
|
306
|
+
constructor() {
|
|
307
|
+
super("Device code expired \u2014 please try again");
|
|
308
|
+
this.name = "DeviceFlowExpired";
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
var DeviceFlowAccessDenied = class extends DeviceFlowError {
|
|
312
|
+
constructor() {
|
|
313
|
+
super("Authorization was denied by the user");
|
|
314
|
+
this.name = "DeviceFlowAccessDenied";
|
|
315
|
+
}
|
|
316
|
+
};
|
|
317
|
+
async function fetchSsoConfig(baseUrl) {
|
|
318
|
+
const arbi = client.createArbiClient({ baseUrl, deploymentDomain: "", credentials: "omit" });
|
|
319
|
+
const { data, error } = await arbi.fetch.GET("/v1/user/sso-config");
|
|
320
|
+
if (error || !data) {
|
|
321
|
+
throw new DeviceFlowError(`Failed to fetch SSO config`);
|
|
322
|
+
}
|
|
323
|
+
return {
|
|
324
|
+
ssoEnabled: data.sso_enabled,
|
|
325
|
+
domain: data.domain,
|
|
326
|
+
clientId: data.cli_client_id || data.client_id,
|
|
327
|
+
audience: data.audience
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
async function requestDeviceCode(domain, clientId, audience, scope = "openid email profile") {
|
|
331
|
+
const body = new URLSearchParams({
|
|
332
|
+
client_id: clientId,
|
|
333
|
+
scope,
|
|
334
|
+
...audience ? { audience } : {}
|
|
335
|
+
});
|
|
336
|
+
const res = await fetch(`https://${domain}/oauth/device/code`, {
|
|
337
|
+
method: "POST",
|
|
338
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
339
|
+
body
|
|
340
|
+
});
|
|
341
|
+
if (!res.ok) {
|
|
342
|
+
const text = await res.text();
|
|
343
|
+
throw new DeviceFlowError(`Device code request failed: ${res.status} ${text}`);
|
|
344
|
+
}
|
|
345
|
+
return await res.json();
|
|
346
|
+
}
|
|
347
|
+
async function pollForToken(domain, clientId, deviceCode, interval, expiresIn, onPoll) {
|
|
348
|
+
const deadline = Date.now() + expiresIn * 1e3;
|
|
349
|
+
let pollInterval = interval * 1e3;
|
|
350
|
+
while (Date.now() < deadline) {
|
|
351
|
+
await sleep(pollInterval);
|
|
352
|
+
onPoll?.(Date.now());
|
|
353
|
+
const res = await fetch(`https://${domain}/oauth/token`, {
|
|
354
|
+
method: "POST",
|
|
355
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
356
|
+
body: new URLSearchParams({
|
|
357
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
358
|
+
client_id: clientId,
|
|
359
|
+
device_code: deviceCode
|
|
360
|
+
})
|
|
361
|
+
});
|
|
362
|
+
if (res.ok) {
|
|
363
|
+
const data = await res.json();
|
|
364
|
+
return data.access_token;
|
|
365
|
+
}
|
|
366
|
+
const errBody = await res.json().catch(() => ({ error: "unknown" }));
|
|
367
|
+
if (errBody.error === "authorization_pending") {
|
|
368
|
+
continue;
|
|
369
|
+
} else if (errBody.error === "slow_down") {
|
|
370
|
+
pollInterval += 5e3;
|
|
371
|
+
continue;
|
|
372
|
+
} else if (errBody.error === "expired_token") {
|
|
373
|
+
throw new DeviceFlowExpired();
|
|
374
|
+
} else if (errBody.error === "access_denied") {
|
|
375
|
+
throw new DeviceFlowAccessDenied();
|
|
376
|
+
} else {
|
|
377
|
+
throw new DeviceFlowError(
|
|
378
|
+
`Token polling error: ${errBody.error} \u2014 ${errBody.error_description ?? ""}`
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
throw new DeviceFlowExpired();
|
|
383
|
+
}
|
|
384
|
+
function sleep(ms) {
|
|
385
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// src/auth.ts
|
|
288
389
|
function formatWorkspaceChoices(wsList) {
|
|
289
390
|
return wsList.map((ws) => {
|
|
290
391
|
const totalDocs = ws.shared_document_count + ws.private_document_count;
|
|
@@ -305,7 +406,8 @@ async function createAuthenticatedClient(config, creds, store) {
|
|
|
305
406
|
const signingPrivateKey = client.base64ToBytes(creds.signingPrivateKeyBase64);
|
|
306
407
|
const loginResult = await arbi.auth.loginWithKey({
|
|
307
408
|
email: creds.email,
|
|
308
|
-
signingPrivateKey
|
|
409
|
+
signingPrivateKey,
|
|
410
|
+
ssoToken: creds.ssoToken
|
|
309
411
|
});
|
|
310
412
|
store.saveCredentials({
|
|
311
413
|
...creds,
|
|
@@ -337,6 +439,40 @@ async function performPasswordLogin(config, email, password, store) {
|
|
|
337
439
|
});
|
|
338
440
|
return { arbi, loginResult, config };
|
|
339
441
|
}
|
|
442
|
+
async function performSsoDeviceFlowLogin(config, email, password, store, callbacks) {
|
|
443
|
+
const ssoConfig = await fetchSsoConfig(config.baseUrl);
|
|
444
|
+
if (!ssoConfig.ssoEnabled) {
|
|
445
|
+
throw new ArbiError("SSO is not enabled on this deployment");
|
|
446
|
+
}
|
|
447
|
+
const dc = await requestDeviceCode(ssoConfig.domain, ssoConfig.clientId, ssoConfig.audience);
|
|
448
|
+
callbacks?.onUserCode?.(dc.user_code, dc.verification_uri_complete);
|
|
449
|
+
const ssoToken = await pollForToken(
|
|
450
|
+
ssoConfig.domain,
|
|
451
|
+
ssoConfig.clientId,
|
|
452
|
+
dc.device_code,
|
|
453
|
+
dc.interval,
|
|
454
|
+
dc.expires_in,
|
|
455
|
+
callbacks?.onPoll
|
|
456
|
+
);
|
|
457
|
+
const arbi = client.createArbiClient({
|
|
458
|
+
baseUrl: config.baseUrl,
|
|
459
|
+
deploymentDomain: config.deploymentDomain,
|
|
460
|
+
credentials: "omit"
|
|
461
|
+
});
|
|
462
|
+
await arbi.crypto.initSodium();
|
|
463
|
+
const loginResult = await arbi.auth.login({ email, password, ssoToken });
|
|
464
|
+
store.saveCredentials({
|
|
465
|
+
email,
|
|
466
|
+
signingPrivateKeyBase64: arbi.crypto.bytesToBase64(loginResult.signingPrivateKey),
|
|
467
|
+
serverSessionKeyBase64: arbi.crypto.bytesToBase64(loginResult.serverSessionKey),
|
|
468
|
+
ssoToken,
|
|
469
|
+
accessToken: void 0,
|
|
470
|
+
workspaceKeyHeader: void 0,
|
|
471
|
+
workspaceId: void 0,
|
|
472
|
+
tokenTimestamp: void 0
|
|
473
|
+
});
|
|
474
|
+
return { arbi, loginResult, config };
|
|
475
|
+
}
|
|
340
476
|
async function selectWorkspace(arbi, workspaceId, wrappedKey, serverSessionKey, signingPrivateKeyBase64) {
|
|
341
477
|
const signingPrivateKey = client.base64ToBytes(signingPrivateKeyBase64);
|
|
342
478
|
const ed25519PublicKey = signingPrivateKey.slice(32, 64);
|
|
@@ -2097,6 +2233,7 @@ exports.conversations = conversations_exports;
|
|
|
2097
2233
|
exports.countCitations = countCitations;
|
|
2098
2234
|
exports.createAuthenticatedClient = createAuthenticatedClient;
|
|
2099
2235
|
exports.createDocumentWaiter = createDocumentWaiter;
|
|
2236
|
+
exports.deviceFlow = device_flow_exports;
|
|
2100
2237
|
exports.dm = dm_exports;
|
|
2101
2238
|
exports.doctags = doctags_exports;
|
|
2102
2239
|
exports.documents = documents_exports;
|
|
@@ -2114,6 +2251,7 @@ exports.getErrorMessage = getErrorMessage;
|
|
|
2114
2251
|
exports.health = health_exports;
|
|
2115
2252
|
exports.parseSSEEvents = parseSSEEvents;
|
|
2116
2253
|
exports.performPasswordLogin = performPasswordLogin;
|
|
2254
|
+
exports.performSsoDeviceFlowLogin = performSsoDeviceFlowLogin;
|
|
2117
2255
|
exports.requireData = requireData;
|
|
2118
2256
|
exports.requireOk = requireOk;
|
|
2119
2257
|
exports.resolveAuth = resolveAuth;
|