@arbidocs/sdk 0.4.3 → 0.4.5

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
@@ -3644,6 +3644,16 @@ async function selectWorkspace(arbi, workspaceId, wrappedKey, serverSessionKey,
3644
3644
  arbi.session.setSelectedWorkspace(workspaceId);
3645
3645
  return header;
3646
3646
  }
3647
+ async function generateEncryptedWorkspaceKey(arbi, wrappedKey, serverSessionKey, signingPrivateKeyBase64) {
3648
+ const signingPrivateKey = client.base64ToBytes(signingPrivateKeyBase64);
3649
+ const ed25519PublicKey = signingPrivateKey.slice(32, 64);
3650
+ const encryptionKeyPair = client.deriveEncryptionKeypairFromSigning({
3651
+ publicKey: ed25519PublicKey,
3652
+ secretKey: signingPrivateKey
3653
+ });
3654
+ const workspaceKey = client.sealedBoxDecrypt(wrappedKey, encryptionKeyPair.secretKey);
3655
+ return client.sealKeyForSession(workspaceKey, serverSessionKey);
3656
+ }
3647
3657
  async function getRawWorkspaceKey(arbi, workspaceId, signingPrivateKeyBase64) {
3648
3658
  const { data: workspaces, error } = await arbi.fetch.GET("/v1/user/workspaces");
3649
3659
  if (error || !workspaces) {
@@ -4469,6 +4479,7 @@ async function uploadFile(auth, fileData, fileName, options) {
4469
4479
  if (options?.folder) params.set("folder", sanitizeFolderPath(options.folder));
4470
4480
  if (options?.configExtId) params.set("config_ext_id", options.configExtId);
4471
4481
  if (options?.wpType) params.set("wp_type", options.wpType);
4482
+ if (options?.parentExtId) params.set("parent_ext_id", options.parentExtId);
4472
4483
  const qs = params.toString();
4473
4484
  const res = await authenticatedFetch({
4474
4485
  ...auth,
@@ -4485,6 +4496,7 @@ async function uploadFiles(auth, files, options) {
4485
4496
  if (options?.folder) params.set("folder", sanitizeFolderPath(options.folder));
4486
4497
  if (options?.configExtId) params.set("config_ext_id", options.configExtId);
4487
4498
  if (options?.wpType) params.set("wp_type", options.wpType);
4499
+ if (options?.parentExtId) params.set("parent_ext_id", options.parentExtId);
4488
4500
  const qs = params.toString();
4489
4501
  const res = await authenticatedFetch({
4490
4502
  ...auth,
@@ -4666,6 +4678,7 @@ __export(workspaces_exports, {
4666
4678
  copyDocuments: () => copyDocuments,
4667
4679
  createWorkspace: () => createWorkspace,
4668
4680
  deleteWorkspaces: () => deleteWorkspaces,
4681
+ grantTemporaryWorkspaceAccess: () => grantTemporaryWorkspaceAccess,
4669
4682
  listWorkspaceUsers: () => listWorkspaceUsers,
4670
4683
  listWorkspaces: () => listWorkspaces,
4671
4684
  removeWorkspaceUsers: () => removeWorkspaceUsers,
@@ -4706,14 +4719,33 @@ async function updateWorkspace(arbi, body) {
4706
4719
  async function listWorkspaceUsers(arbi) {
4707
4720
  return requireData(await arbi.fetch.GET("/v1/workspace/users"), "Failed to fetch workspace users");
4708
4721
  }
4709
- async function addWorkspaceUsers(arbi, emails, role = "collaborator") {
4722
+ async function addWorkspaceUsers(arbi, emails, role = "collaborator", target) {
4710
4723
  return requireData(
4711
4724
  await arbi.fetch.POST("/v1/workspace/users", {
4712
- body: { emails, role }
4725
+ body: target ? {
4726
+ emails,
4727
+ role,
4728
+ workspace_ext_id: target.workspaceExtId,
4729
+ workspace_key: target.workspaceKey
4730
+ } : { emails, role }
4713
4731
  }),
4714
4732
  "Failed to add users"
4715
4733
  );
4716
4734
  }
4735
+ async function grantTemporaryWorkspaceAccess(arbi, params) {
4736
+ return requireData(
4737
+ await arbi.fetch.POST("/v1/workspace/users", {
4738
+ body: {
4739
+ emails: params.emails,
4740
+ role: params.role ?? "collaborator",
4741
+ workspace_ext_id: params.workspaceExtId,
4742
+ workspace_key: params.workspaceKey,
4743
+ session_pubkey_b64: params.sessionPubkeyB64
4744
+ }
4745
+ }),
4746
+ "Failed to grant temporary access"
4747
+ );
4748
+ }
4717
4749
  async function removeWorkspaceUsers(arbi, userIds) {
4718
4750
  requireOk(
4719
4751
  await arbi.fetch.DELETE("/v1/workspace/users", {
@@ -5138,6 +5170,21 @@ async function deleteAgents(arbi, agentExtIds) {
5138
5170
  "Failed to delete agents"
5139
5171
  );
5140
5172
  }
5173
+ async function authorizeAgent(arbi, agentExtId, workspaceExtId, ttlSeconds) {
5174
+ return requireData(
5175
+ await arbi.fetch.POST("/v1/agents/{agent_ext_id}/authorize", {
5176
+ params: { path: { agent_ext_id: agentExtId } },
5177
+ body: { workspace_ext_id: workspaceExtId, ttl_seconds: ttlSeconds ?? null }
5178
+ }),
5179
+ "Failed to authorize agent"
5180
+ );
5181
+ }
5182
+ async function getAuthorizeLimits(arbi) {
5183
+ return requireData(
5184
+ await arbi.fetch.GET("/v1/agents/authorize-limits"),
5185
+ "Failed to fetch authorize limits"
5186
+ );
5187
+ }
5141
5188
 
5142
5189
  // src/operations/dm.ts
5143
5190
  function createDmCryptoContext(arbi, signingPrivateKeyBytes, userExtId) {
@@ -5520,6 +5567,7 @@ __export(tasks_exports, {
5520
5567
  createTask: () => createTask,
5521
5568
  deleteTask: () => deleteTask,
5522
5569
  getTask: () => getTask,
5570
+ listTaskRuns: () => listTaskRuns,
5523
5571
  listTasks: () => listTasks,
5524
5572
  runTask: () => runTask,
5525
5573
  updateTask: () => updateTask
@@ -5557,6 +5605,12 @@ async function runTask(arbi, taskId) {
5557
5605
  "Failed to run task"
5558
5606
  );
5559
5607
  }
5608
+ async function listTaskRuns(arbi, taskId) {
5609
+ return requireData(
5610
+ await arbi.fetch.GET("/v1/tasks/{task_id}/runs", { params: { path: { task_id: taskId } } }),
5611
+ "Failed to list task runs"
5612
+ );
5613
+ }
5560
5614
 
5561
5615
  // src/operations/facts.ts
5562
5616
  var facts_exports = {};
@@ -5698,6 +5752,22 @@ var Arbi = class {
5698
5752
  const signingPrivateKey = client.crypto.base64ToBytes(signingPrivateKeyBase64);
5699
5753
  this.loginResult = await client.auth.loginWithKey({ email, signingPrivateKey });
5700
5754
  }
5755
+ /** A workspace's key, sealed to the caller's own session (what `/open` and `POST /workspace/users` take). */
5756
+ async sealWorkspaceKey(workspaceId) {
5757
+ const client = this.requireClient();
5758
+ const lr2 = this.requireLogin();
5759
+ const all = await listWorkspaces(client);
5760
+ const ws = all.find((w2) => w2.external_id === workspaceId);
5761
+ if (!ws || !ws.wrapped_key) {
5762
+ throw new ArbiError(`Workspace ${workspaceId} not found or has no encryption key`);
5763
+ }
5764
+ return generateEncryptedWorkspaceKey(
5765
+ client,
5766
+ ws.wrapped_key,
5767
+ lr2.serverSessionKey,
5768
+ client.crypto.bytesToBase64(lr2.signingPrivateKey)
5769
+ );
5770
+ }
5701
5771
  /**
5702
5772
  * Select a workspace by ID. Fetches the workspace list, finds the matching
5703
5773
  * workspace, decrypts the wrapped key, and sets up auth headers.
@@ -5880,6 +5950,30 @@ var Arbi = class {
5880
5950
  update: (body) => updateWorkspace(this.requireClient(), body),
5881
5951
  listUsers: () => listWorkspaceUsers(this.requireClient()),
5882
5952
  addUsers: (emails, role) => addWorkspaceUsers(this.requireClient(), emails, role),
5953
+ /**
5954
+ * Grant users a temporary key scoped to ONE session (identified by its public key), for
5955
+ * example an agent's run session minted by `agents.authorize()`. Nothing standing is created:
5956
+ * the grant expires with that session. Works for any workspace the caller holds a key for;
5957
+ * it does not need to be the open one.
5958
+ */
5959
+ grantTemporaryAccess: async (params) => {
5960
+ const client = this.requireClient();
5961
+ return grantTemporaryWorkspaceAccess(client, {
5962
+ emails: params.emails,
5963
+ workspaceExtId: params.workspaceId,
5964
+ workspaceKey: await this.sealWorkspaceKey(params.workspaceId),
5965
+ sessionPubkeyB64: params.sessionPubkeyB64,
5966
+ role: params.role
5967
+ });
5968
+ },
5969
+ /**
5970
+ * Add users (standing, permanent membership) to ANY workspace the caller holds a key for,
5971
+ * without opening it. `addUsers` does the same for the currently open workspace.
5972
+ */
5973
+ grantAccess: async (params) => addWorkspaceUsers(this.requireClient(), params.emails, params.role, {
5974
+ workspaceExtId: params.workspaceId,
5975
+ workspaceKey: await this.sealWorkspaceKey(params.workspaceId)
5976
+ }),
5883
5977
  removeUsers: (userIds) => removeWorkspaceUsers(this.requireClient(), userIds),
5884
5978
  setUserRole: (userIds, role) => setUserRole(this.requireClient(), userIds, role),
5885
5979
  /**
@@ -5937,12 +6031,7 @@ var Arbi = class {
5937
6031
  uploadFile: (fileData, fileName, options) => {
5938
6032
  this.requireWorkspace();
5939
6033
  return this.recovering(
5940
- () => uploadFile(
5941
- this.getAuthHeaders(),
5942
- fileData,
5943
- fileName,
5944
- options?.folder ? { folder: options.folder } : void 0
5945
- )
6034
+ () => uploadFile(this.getAuthHeaders(), fileData, fileName, options)
5946
6035
  );
5947
6036
  },
5948
6037
  download: (docId) => this.recovering(() => downloadDocument(this.getAuthHeaders(), docId)),
@@ -5995,6 +6084,8 @@ var Arbi = class {
5995
6084
  * Respond to an agent's question during a human-in-the-loop workflow.
5996
6085
  */
5997
6086
  respond: (assistantMessageExtId, answer) => respondToAgent(this.requireClient(), assistantMessageExtId, answer),
6087
+ /** The skills the caller can run (own + shared marketplace), metadata only. */
6088
+ listSkills: (options) => listSkills(this.requireClient(), options),
5998
6089
  /**
5999
6090
  * Search documents without LLM generation (retrieval only).
6000
6091
  */
@@ -6151,7 +6242,28 @@ var Arbi = class {
6151
6242
  create: (name) => createAgent(this.requireClient(), name),
6152
6243
  getConfig: (agentExtId) => getAgentConfig(this.requireClient(), agentExtId),
6153
6244
  listWorkspaces: (agentExtId) => listAgentWorkspaces(this.requireClient(), agentExtId),
6154
- delete: (agentExtIds) => deleteAgents(this.requireClient(), agentExtIds)
6245
+ delete: (agentExtIds) => deleteAgents(this.requireClient(), agentExtIds),
6246
+ /** Mint a TTL'd run session for an agent; see `grantTemporaryAccess` to also deposit a key. */
6247
+ authorize: (agentExtId, workspaceId, ttlSeconds) => authorizeAgent(this.requireClient(), agentExtId, workspaceId, ttlSeconds),
6248
+ authorizeLimits: () => getAuthorizeLimits(this.requireClient()),
6249
+ /**
6250
+ * Give an agent temporary, session-scoped access to a workspace: mint its run session, then
6251
+ * deposit the workspace key on it. Returns the session details (`ttl` in seconds).
6252
+ */
6253
+ grantTemporaryAccess: async (agentExtId, workspaceId, ttlSeconds) => {
6254
+ const session = await authorizeAgent(
6255
+ this.requireClient(),
6256
+ agentExtId,
6257
+ workspaceId,
6258
+ ttlSeconds
6259
+ );
6260
+ await this.workspaces.grantTemporaryAccess({
6261
+ workspaceId,
6262
+ emails: [session.agent_email],
6263
+ sessionPubkeyB64: session.session_pubkey_b64
6264
+ });
6265
+ return session;
6266
+ }
6155
6267
  };
6156
6268
  // ── Scheduled tasks ───────────────────────────────────────────────────
6157
6269
  tasks = {
@@ -6160,7 +6272,26 @@ var Arbi = class {
6160
6272
  get: (taskId) => getTask(this.requireClient(), taskId),
6161
6273
  update: (taskId, body) => updateTask(this.requireClient(), taskId, body),
6162
6274
  delete: (taskId) => deleteTask(this.requireClient(), taskId),
6163
- run: (taskId) => runTask(this.requireClient(), taskId)
6275
+ run: (taskId) => runTask(this.requireClient(), taskId),
6276
+ listRuns: (taskId) => listTaskRuns(this.requireClient(), taskId),
6277
+ /**
6278
+ * Run a task and, when the run is parked waiting for workspace access (a temporary
6279
+ * authorization tier), grant the agent's run session a temporary key and run it again.
6280
+ * A task that needs no approval returns from the first call already running.
6281
+ */
6282
+ runWithAuth: async (taskId) => {
6283
+ const client = this.requireClient();
6284
+ const first = await runTask(client, taskId);
6285
+ if (!first.pending_auth_request_id || !first.pending_auth_session_pubkey || !first.pending_auth_agent_email || !first.workspace_ext_id) {
6286
+ return first;
6287
+ }
6288
+ await this.workspaces.grantTemporaryAccess({
6289
+ workspaceId: first.workspace_ext_id,
6290
+ emails: [first.pending_auth_agent_email],
6291
+ sessionPubkeyB64: first.pending_auth_session_pubkey
6292
+ });
6293
+ return runTask(client, taskId);
6294
+ }
6164
6295
  };
6165
6296
  // ── Workspace facts ─────────────────────────────────────────────────
6166
6297
  facts = {