@arbidocs/sdk 0.3.115 → 0.3.117

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
@@ -4642,6 +4642,7 @@ __export(workspaces_exports, {
4642
4642
  copyDocuments: () => copyDocuments,
4643
4643
  createWorkspace: () => createWorkspace,
4644
4644
  deleteWorkspaces: () => deleteWorkspaces,
4645
+ getWorkspaceChronology: () => getWorkspaceChronology,
4645
4646
  listWorkspaceUsers: () => listWorkspaceUsers,
4646
4647
  listWorkspaces: () => listWorkspaces,
4647
4648
  removeWorkspaceUsers: () => removeWorkspaceUsers,
@@ -4706,6 +4707,14 @@ async function setUserRole(arbi, userIds, role) {
4706
4707
  "Failed to update roles"
4707
4708
  );
4708
4709
  }
4710
+ async function getWorkspaceChronology(arbi, workspaceId) {
4711
+ return requireData(
4712
+ await arbi.fetch.GET("/v1/workspace/{workspace_ext_id}/chronology", {
4713
+ params: { path: { workspace_ext_id: workspaceId } }
4714
+ }),
4715
+ "Failed to fetch workspace chronology"
4716
+ );
4717
+ }
4709
4718
  async function copyDocuments(arbi, targetWorkspaceId, docIds, targetWorkspaceKey) {
4710
4719
  return requireData(
4711
4720
  await arbi.fetch.POST("/v1/workspace/copy", {
@@ -5070,13 +5079,50 @@ __export(dm_exports, {
5070
5079
  decryptDmContent: () => decryptDmContent,
5071
5080
  deleteDMs: () => deleteDMs,
5072
5081
  encryptDmContent: () => encryptDmContent,
5082
+ listActivity: () => listActivity,
5073
5083
  listDMs: () => listDMs,
5074
5084
  listDecryptedDMs: () => listDecryptedDMs,
5075
5085
  markRead: () => markRead,
5076
5086
  requestWorkspaceAccess: () => requestWorkspaceAccess,
5087
+ resolveRecipient: () => resolveRecipient,
5077
5088
  sendDM: () => sendDM,
5078
5089
  sendEncryptedDM: () => sendEncryptedDM
5079
5090
  });
5091
+
5092
+ // src/operations/agents.ts
5093
+ async function listAgents(arbi) {
5094
+ return requireData(await arbi.fetch.GET("/v1/agents"), "Failed to fetch agents");
5095
+ }
5096
+ async function createAgent(arbi, name) {
5097
+ const body = { name };
5098
+ return requireData(await arbi.fetch.POST("/v1/agents", { body }), "Failed to create agent");
5099
+ }
5100
+ async function getAgentConfig(arbi, agentExtId) {
5101
+ return requireData(
5102
+ await arbi.fetch.GET("/v1/agents/{agent_ext_id}/config", {
5103
+ params: { path: { agent_ext_id: agentExtId } }
5104
+ }),
5105
+ "Failed to fetch agent config"
5106
+ );
5107
+ }
5108
+ async function listAgentWorkspaces(arbi, agentExtId) {
5109
+ return requireData(
5110
+ await arbi.fetch.GET("/v1/agents/{agent_ext_id}/workspaces", {
5111
+ params: { path: { agent_ext_id: agentExtId } }
5112
+ }),
5113
+ "Failed to fetch agent workspaces"
5114
+ );
5115
+ }
5116
+ async function deleteAgents(arbi, agentExtIds) {
5117
+ return requireData(
5118
+ await arbi.fetch.DELETE("/v1/agents", {
5119
+ body: { agent_ext_ids: agentExtIds }
5120
+ }),
5121
+ "Failed to delete agents"
5122
+ );
5123
+ }
5124
+
5125
+ // src/operations/dm.ts
5080
5126
  function createDmCryptoContext(arbi, signingPrivateKeyBytes, userExtId) {
5081
5127
  const ed25519PublicKey = signingPrivateKeyBytes.slice(32, 64);
5082
5128
  const encryptionKeypair = arbi.crypto.deriveEncryptionKeypairFromSigning({
@@ -5125,6 +5171,51 @@ async function listDecryptedDMs(arbi, crypto) {
5125
5171
  const raw = await listDMs(arbi);
5126
5172
  return decryptDmBatch(arbi, raw, crypto);
5127
5173
  }
5174
+ async function listActivity(arbi, options) {
5175
+ return requireData(
5176
+ await arbi.fetch.GET("/v1/notifications/", {
5177
+ params: {
5178
+ query: {
5179
+ type: "activity",
5180
+ ...options?.limit != null ? { limit: options.limit } : {},
5181
+ ...options?.offset != null ? { offset: options.offset } : {}
5182
+ }
5183
+ }
5184
+ }),
5185
+ "Failed to fetch activity"
5186
+ );
5187
+ }
5188
+ async function resolveRecipient(arbi, ref) {
5189
+ const isEmail = ref.includes("@");
5190
+ const matchKey = isEmail ? "email" : "external_id";
5191
+ const contacts = await listContacts(arbi);
5192
+ const contactMatch = contacts.find(
5193
+ (c2) => isEmail ? c2.email === ref : c2.user?.external_id === ref || c2.external_id === ref
5194
+ );
5195
+ if (contactMatch?.user?.encryption_public_key) {
5196
+ return {
5197
+ extId: contactMatch.user.external_id,
5198
+ pubKey: contactMatch.user.encryption_public_key
5199
+ };
5200
+ }
5201
+ try {
5202
+ const agents = await listAgents(arbi);
5203
+ const agentMatch = agents.find((a2) => a2[matchKey] === ref);
5204
+ if (agentMatch?.encryption_public_key) {
5205
+ return { extId: agentMatch.external_id, pubKey: agentMatch.encryption_public_key };
5206
+ }
5207
+ } catch {
5208
+ }
5209
+ try {
5210
+ const wsUsers = await listWorkspaceUsers(arbi);
5211
+ const wsMatch = wsUsers.find((wu) => wu.user[matchKey] === ref);
5212
+ if (wsMatch?.user.encryption_public_key) {
5213
+ return { extId: wsMatch.user.external_id, pubKey: wsMatch.user.encryption_public_key };
5214
+ }
5215
+ } catch {
5216
+ }
5217
+ return null;
5218
+ }
5128
5219
  async function sendEncryptedDM(arbi, messages, crypto) {
5129
5220
  const encrypted = await Promise.all(
5130
5221
  messages.map(async (msg) => ({
@@ -5321,45 +5412,21 @@ async function getFileContent(auth, fileId) {
5321
5412
  });
5322
5413
  }
5323
5414
 
5324
- // src/operations/agents.ts
5325
- async function listAgents(arbi) {
5326
- return requireData(await arbi.fetch.GET("/v1/agents"), "Failed to fetch agents");
5327
- }
5328
- async function createAgent(arbi, name) {
5329
- const body = { name };
5330
- return requireData(await arbi.fetch.POST("/v1/agents", { body }), "Failed to create agent");
5331
- }
5332
- async function getAgentConfig(arbi, agentExtId) {
5333
- return requireData(
5334
- await arbi.fetch.GET("/v1/agents/{agent_ext_id}/config", {
5335
- params: { path: { agent_ext_id: agentExtId } }
5336
- }),
5337
- "Failed to fetch agent config"
5338
- );
5339
- }
5340
- async function listAgentWorkspaces(arbi, agentExtId) {
5341
- return requireData(
5342
- await arbi.fetch.GET("/v1/agents/{agent_ext_id}/workspaces", {
5343
- params: { path: { agent_ext_id: agentExtId } }
5344
- }),
5345
- "Failed to fetch agent workspaces"
5346
- );
5347
- }
5348
- async function deleteAgents(arbi, agentExtIds) {
5349
- return requireData(
5350
- await arbi.fetch.DELETE("/v1/agents", {
5351
- body: { agent_ext_ids: agentExtIds }
5352
- }),
5353
- "Failed to delete agents"
5354
- );
5355
- }
5356
-
5357
5415
  // src/operations/sessions.ts
5358
5416
  async function listSessions(arbi) {
5359
5417
  return requireData(await arbi.fetch.GET("/v1/user/sessions"), "Failed to fetch sessions");
5360
5418
  }
5361
5419
 
5362
5420
  // src/operations/projects.ts
5421
+ var projects_exports = {};
5422
+ __export(projects_exports, {
5423
+ createProject: () => createProject,
5424
+ getProjectInvoices: () => getProjectInvoices,
5425
+ getProjectUsage: () => getProjectUsage,
5426
+ getUserUsageToday: () => getUserUsageToday,
5427
+ listProjects: () => listProjects,
5428
+ refreshProject: () => refreshProject
5429
+ });
5363
5430
  async function listProjects(arbi) {
5364
5431
  return requireData(await arbi.fetch.GET("/v1/user/projects/"), "Failed to fetch projects");
5365
5432
  }
@@ -5379,6 +5446,28 @@ async function refreshProject(arbi, projectExtId) {
5379
5446
  "Failed to refresh project"
5380
5447
  );
5381
5448
  }
5449
+ async function getProjectUsage(arbi, projectExtId, monthsBack) {
5450
+ return requireData(
5451
+ await arbi.fetch.GET("/v1/user/projects/{project_ext_id}/usage", {
5452
+ params: {
5453
+ path: { project_ext_id: projectExtId },
5454
+ query: monthsBack === void 0 ? void 0 : { months_back: monthsBack }
5455
+ }
5456
+ }),
5457
+ "Failed to fetch project usage"
5458
+ );
5459
+ }
5460
+ async function getProjectInvoices(arbi, projectExtId) {
5461
+ return requireData(
5462
+ await arbi.fetch.GET("/v1/user/projects/{project_ext_id}/invoices", {
5463
+ params: { path: { project_ext_id: projectExtId } }
5464
+ }),
5465
+ "Failed to fetch project invoices"
5466
+ );
5467
+ }
5468
+ async function getUserUsageToday(arbi) {
5469
+ return requireData(await arbi.fetch.GET("/v1/user/me/usage/today"), "Failed to fetch today usage");
5470
+ }
5382
5471
 
5383
5472
  // src/operations/tasks.ts
5384
5473
  var tasks_exports = {};
@@ -5471,6 +5560,7 @@ var Arbi = class {
5471
5560
  client = null;
5472
5561
  loginResult = null;
5473
5562
  currentWorkspaceId = null;
5563
+ dmCryptoContext = null;
5474
5564
  options;
5475
5565
  constructor(options) {
5476
5566
  this.options = options;
@@ -5557,6 +5647,7 @@ var Arbi = class {
5557
5647
  }
5558
5648
  this.loginResult = null;
5559
5649
  this.currentWorkspaceId = null;
5650
+ this.dmCryptoContext = null;
5560
5651
  }
5561
5652
  // ── Accessors ─────────────────────────────────────────────────────────
5562
5653
  /** Get the underlying ArbiClient (throws if not initialized). */
@@ -5604,7 +5695,26 @@ var Arbi = class {
5604
5695
  projects = {
5605
5696
  list: () => listProjects(this.requireClient()),
5606
5697
  create: (name) => createProject(this.requireClient(), name),
5607
- refresh: (projectExtId) => refreshProject(this.requireClient(), projectExtId)
5698
+ refresh: (projectExtId) => refreshProject(this.requireClient(), projectExtId),
5699
+ /** AI usage + spend breakdown for a project's billing period. */
5700
+ usage: (projectExtId, monthsBack) => getProjectUsage(this.requireClient(), projectExtId, monthsBack),
5701
+ /** Stripe invoices for a project's subscription. */
5702
+ invoices: (projectExtId) => getProjectInvoices(this.requireClient(), projectExtId)
5703
+ };
5704
+ // ── User (account-scoped usage) ───────────────────────────────────────
5705
+ user = {
5706
+ /**
5707
+ * The authenticated user's identity from the current session
5708
+ * (`external_id` + `email`), established at login. Returns `null` when not
5709
+ * logged in. This is the canonical "who am I" accessor — DM direction and
5710
+ * ownership checks read it instead of re-deriving identity per call.
5711
+ */
5712
+ identity: () => {
5713
+ const state = this.requireClient().session.getState();
5714
+ return state.userExtId && state.userEmail ? { externalId: state.userExtId, email: state.userEmail } : null;
5715
+ },
5716
+ /** Today's deployment-wide credit spend for the current user. */
5717
+ usageToday: () => getUserUsageToday(this.requireClient())
5608
5718
  };
5609
5719
  // ── Workspaces ────────────────────────────────────────────────────────
5610
5720
  workspaces = {
@@ -5652,6 +5762,14 @@ var Arbi = class {
5652
5762
  targetWorkspaceId,
5653
5763
  docIds,
5654
5764
  targetWorkspaceKey
5765
+ ),
5766
+ /**
5767
+ * The last-generated document-derived chronology (key case events / dates).
5768
+ * Defaults to the currently open workspace when no id is passed.
5769
+ */
5770
+ chronology: (workspaceId) => getWorkspaceChronology(
5771
+ this.requireClient(),
5772
+ workspaceId ?? this.requireWorkspace()
5655
5773
  )
5656
5774
  };
5657
5775
  // ── Documents ─────────────────────────────────────────────────────────
@@ -5778,11 +5896,80 @@ var Arbi = class {
5778
5896
  groupByStatus: groupContactsByStatus
5779
5897
  };
5780
5898
  // ── Direct Messages ───────────────────────────────────────────────────
5899
+ /**
5900
+ * Build (and cache) the DM crypto context for the current session.
5901
+ *
5902
+ * Derives the user's curve25519 keypair from the stored signing key and pairs
5903
+ * it with their external_id — everything `list()`/`send()` need to encrypt and
5904
+ * decrypt. Cached for the session and cleared on logout. Consumers never touch
5905
+ * this: it's an internal of the `dm` surface.
5906
+ */
5907
+ async requireDmCrypto() {
5908
+ if (this.dmCryptoContext) return this.dmCryptoContext;
5909
+ const client = this.requireClient();
5910
+ const session = await client.storage.getSession();
5911
+ if (!session) {
5912
+ throw new ArbiError("Not authenticated \u2014 no session available for DM encryption");
5913
+ }
5914
+ const userExtId = client.session.getState().userExtId;
5915
+ if (!userExtId) {
5916
+ throw new ArbiError("No user identity in session \u2014 cannot set up DM encryption");
5917
+ }
5918
+ this.dmCryptoContext = createDmCryptoContext(client, session.signingPrivateKey, userExtId);
5919
+ return this.dmCryptoContext;
5920
+ }
5781
5921
  dm = {
5782
- list: () => listDMs(this.requireClient()),
5783
- send: (messages) => sendDM(this.requireClient(), messages),
5922
+ /**
5923
+ * List direct messages, newest first, with content already **decrypted**.
5924
+ * (A message that can't be decrypted comes back as `[Decryption failed]`.)
5925
+ */
5926
+ list: async () => listDecryptedDMs(this.requireClient(), await this.requireDmCrypto()),
5927
+ /**
5928
+ * Send an E2E-encrypted DM to a recipient (email or `usr-`/`agt-` id).
5929
+ * Resolves the recipient's public key and encrypts internally — the caller
5930
+ * passes plaintext and never handles keys or ciphertext.
5931
+ */
5932
+ send: async (recipient, text) => {
5933
+ const client = this.requireClient();
5934
+ const resolved = await resolveRecipient(client, recipient);
5935
+ if (!resolved) {
5936
+ throw new ArbiError(
5937
+ `Could not resolve DM recipient "${recipient}" (not a known contact, agent, or workspace member)`
5938
+ );
5939
+ }
5940
+ return sendEncryptedDM(
5941
+ client,
5942
+ [
5943
+ {
5944
+ recipient_ext_id: resolved.extId,
5945
+ content: text,
5946
+ recipient_encryption_public_key: resolved.pubKey
5947
+ }
5948
+ ],
5949
+ await this.requireDmCrypto()
5950
+ );
5951
+ },
5952
+ /**
5953
+ * Send to a recipient whose external_id + public key are already known
5954
+ * (e.g. from a message's `sender`), skipping directory resolution.
5955
+ */
5956
+ sendTo: async (recipientExtId, recipientPublicKey, text) => sendEncryptedDM(
5957
+ this.requireClient(),
5958
+ [
5959
+ {
5960
+ recipient_ext_id: recipientExtId,
5961
+ content: text,
5962
+ recipient_encryption_public_key: recipientPublicKey
5963
+ }
5964
+ ],
5965
+ await this.requireDmCrypto()
5966
+ ),
5967
+ /** Resolve a recipient reference to `{ extId, pubKey }` (contacts → agents → workspace). */
5968
+ resolveRecipient: (recipient) => resolveRecipient(this.requireClient(), recipient),
5784
5969
  markRead: (messageIds) => markRead(this.requireClient(), messageIds),
5785
- delete: (messageIds) => deleteDMs(this.requireClient(), messageIds)
5970
+ delete: (messageIds) => deleteDMs(this.requireClient(), messageIds),
5971
+ /** List the current user's durable activity feed (never unread; excluded from DMs). */
5972
+ listActivity: (options) => listActivity(this.requireClient(), options)
5786
5973
  };
5787
5974
  // ── Settings ──────────────────────────────────────────────────────────
5788
5975
  settings = {
@@ -5960,6 +6147,7 @@ exports.parseSSEEvents = parseSSEEvents;
5960
6147
  exports.parseSlashCommand = parseSlashCommand;
5961
6148
  exports.parseSlashTokenInProgress = parseSlashTokenInProgress;
5962
6149
  exports.performPasswordLogin = performPasswordLogin;
6150
+ exports.projects = projects_exports;
5963
6151
  exports.requireData = requireData;
5964
6152
  exports.requireOk = requireOk;
5965
6153
  exports.resolveAuth = resolveAuth;