@arbidocs/sdk 0.3.46 → 0.3.48

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/index.cjs CHANGED
@@ -4655,6 +4655,7 @@ __export(documents_exports, {
4655
4655
  listAll: () => listAll,
4656
4656
  listDocuments: () => listDocuments,
4657
4657
  listPaginated: () => listPaginated,
4658
+ mimeFromName: () => mimeFromName,
4658
4659
  sanitizeFolderPath: () => sanitizeFolderPath,
4659
4660
  updateDocuments: () => updateDocuments,
4660
4661
  uploadDocumentsDirect: () => uploadDocumentsDirect,
@@ -4709,10 +4710,17 @@ async function listDocuments(arbi) {
4709
4710
  return requireData(await arbi.fetch.GET("/v1/document/list"), "Failed to fetch documents");
4710
4711
  }
4711
4712
  async function* listPaginated(arbi, options = {}) {
4712
- const { pageSize = 5e3, order = "id_asc", fields, signal, lookahead = 3 } = options;
4713
- const fetchPage = async (pageOffset) => {
4713
+ const {
4714
+ pageSize = 5e3,
4715
+ firstPageSize,
4716
+ order = "id_asc",
4717
+ fields,
4718
+ signal,
4719
+ lookahead = 1
4720
+ } = options;
4721
+ const fetchPage = async (pageOffset, limit) => {
4714
4722
  const query = {
4715
- limit: pageSize,
4723
+ limit,
4716
4724
  offset: pageOffset,
4717
4725
  order
4718
4726
  };
@@ -4735,19 +4743,21 @@ async function* listPaginated(arbi, options = {}) {
4735
4743
  const queue = [];
4736
4744
  const tryEnqueue = () => {
4737
4745
  while (!done && queue.length < depth && issued < MAX_PAGES) {
4738
- const p2 = fetchPage(nextOffsetToIssue);
4739
- p2.catch(() => {
4746
+ const limit = issued === 0 && firstPageSize !== void 0 ? firstPageSize : pageSize;
4747
+ const promise = fetchPage(nextOffsetToIssue, limit);
4748
+ promise.catch(() => {
4740
4749
  });
4741
- queue.push(p2);
4742
- nextOffsetToIssue += pageSize;
4750
+ queue.push({ limit, promise });
4751
+ nextOffsetToIssue += limit;
4743
4752
  issued++;
4744
4753
  }
4745
4754
  };
4746
4755
  tryEnqueue();
4747
4756
  while (queue.length > 0 && !signal?.aborted) {
4748
- const page = await queue.shift();
4757
+ const { limit, promise } = queue.shift();
4758
+ const page = await promise;
4749
4759
  if (signal?.aborted) return;
4750
- const isShort = page.length < pageSize;
4760
+ const isShort = page.length < limit;
4751
4761
  if (isShort) done = true;
4752
4762
  tryEnqueue();
4753
4763
  if (page.length > 0) {
@@ -4795,11 +4805,11 @@ async function updateDocuments(arbi, documents) {
4795
4805
  "Failed to update documents"
4796
4806
  );
4797
4807
  }
4798
- async function uploadUrl(arbi, urls, workspaceId, shared = false) {
4808
+ async function uploadUrl(arbi, urls, shared = false) {
4799
4809
  return requireData(
4800
4810
  await arbi.fetch.POST("/v1/document/upload-url", {
4801
4811
  params: {
4802
- query: { urls, workspace_ext_id: workspaceId, shared }
4812
+ query: { urls, shared }
4803
4813
  }
4804
4814
  }),
4805
4815
  "Failed to upload from URLs"
@@ -4812,29 +4822,31 @@ async function getParsedContent(auth, docId, stage) {
4812
4822
  });
4813
4823
  return res.json();
4814
4824
  }
4815
- async function uploadFile(auth, workspaceId, fileData, fileName, options) {
4825
+ async function uploadFile(auth, fileData, fileName, options) {
4816
4826
  const formData = new FormData();
4817
4827
  formData.append("files", fileData, fileName);
4818
- const params = new URLSearchParams({ workspace_ext_id: workspaceId });
4828
+ const params = new URLSearchParams();
4819
4829
  if (options?.folder) params.set("folder", sanitizeFolderPath(options.folder));
4820
4830
  if (options?.configExtId) params.set("config_ext_id", options.configExtId);
4831
+ const qs = params.toString();
4821
4832
  const res = await authenticatedFetch({
4822
4833
  ...auth,
4823
- path: `/v1/document/upload?${params.toString()}`,
4834
+ path: qs ? `/v1/document/upload?${qs}` : `/v1/document/upload`,
4824
4835
  method: "POST",
4825
4836
  body: formData
4826
4837
  });
4827
4838
  return res.json();
4828
4839
  }
4829
- async function uploadFiles(auth, workspaceId, files, options) {
4840
+ async function uploadFiles(auth, files, options) {
4830
4841
  const formData = new FormData();
4831
4842
  for (const f2 of files) formData.append("files", f2.data, f2.name);
4832
- const params = new URLSearchParams({ workspace_ext_id: workspaceId });
4843
+ const params = new URLSearchParams();
4833
4844
  if (options?.folder) params.set("folder", sanitizeFolderPath(options.folder));
4834
4845
  if (options?.configExtId) params.set("config_ext_id", options.configExtId);
4846
+ const qs = params.toString();
4835
4847
  const res = await authenticatedFetch({
4836
4848
  ...auth,
4837
- path: `/v1/document/upload?${params.toString()}`,
4849
+ path: qs ? `/v1/document/upload?${qs}` : `/v1/document/upload`,
4838
4850
  method: "POST",
4839
4851
  body: formData
4840
4852
  });
@@ -4846,6 +4858,68 @@ async function downloadDocument(auth, docId) {
4846
4858
  path: `/v1/document/${docId}/download`
4847
4859
  });
4848
4860
  }
4861
+ function mimeFromName(name) {
4862
+ const dot = name.lastIndexOf(".");
4863
+ const ext = dot === -1 ? "" : name.slice(dot).toLowerCase();
4864
+ switch (ext) {
4865
+ case ".pdf":
4866
+ return "application/pdf";
4867
+ case ".txt":
4868
+ return "text/plain";
4869
+ case ".md":
4870
+ return "text/markdown";
4871
+ case ".html":
4872
+ case ".htm":
4873
+ return "text/html";
4874
+ case ".doc":
4875
+ return "application/msword";
4876
+ case ".docx":
4877
+ return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
4878
+ case ".xls":
4879
+ return "application/vnd.ms-excel";
4880
+ case ".xlsx":
4881
+ return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
4882
+ case ".ppt":
4883
+ return "application/vnd.ms-powerpoint";
4884
+ case ".pptx":
4885
+ return "application/vnd.openxmlformats-officedocument.presentationml.presentation";
4886
+ case ".eml":
4887
+ return "message/rfc822";
4888
+ default:
4889
+ return void 0;
4890
+ }
4891
+ }
4892
+ async function presignedPut(url, body, onProgress) {
4893
+ const XhrGlobal = globalThis.XMLHttpRequest;
4894
+ if (XhrGlobal) {
4895
+ await new Promise((resolve2, reject) => {
4896
+ const xhr = new XhrGlobal();
4897
+ xhr.open("PUT", url);
4898
+ if (onProgress) {
4899
+ xhr.upload.addEventListener("progress", (e) => {
4900
+ if (e.lengthComputable) onProgress(e.loaded, e.total);
4901
+ });
4902
+ }
4903
+ xhr.addEventListener("load", () => {
4904
+ if (xhr.status >= 200 && xhr.status < 300) {
4905
+ resolve2();
4906
+ } else {
4907
+ const snippet = (xhr.responseText || "").slice(0, 200);
4908
+ reject(new Error(`Presigned PUT failed: ${xhr.status} ${snippet}`));
4909
+ }
4910
+ });
4911
+ xhr.addEventListener("error", () => reject(new Error("Presigned PUT network error")));
4912
+ xhr.addEventListener("abort", () => reject(new Error("Presigned PUT aborted")));
4913
+ xhr.send(body);
4914
+ });
4915
+ return;
4916
+ }
4917
+ const putRes = await fetch(url, { method: "PUT", body });
4918
+ if (!putRes.ok) {
4919
+ const snippet = await putRes.text().catch(() => "");
4920
+ throw new Error(`Presigned PUT failed: ${putRes.status} ${snippet.slice(0, 200)}`);
4921
+ }
4922
+ }
4849
4923
  async function uploadDocumentsDirect(arbi, workspaceKey, files, options) {
4850
4924
  if (files.length === 0) return { doc_ext_ids: [], skipped: [] };
4851
4925
  const SECRETBOX_ENVELOPE_OVERHEAD = 40;
@@ -4878,6 +4952,11 @@ async function uploadDocumentsDirect(arbi, workspaceKey, files, options) {
4878
4952
  }
4879
4953
  const skipped = [];
4880
4954
  const toCommit = [];
4955
+ const indexByName = /* @__PURE__ */ new Map();
4956
+ files.forEach((f2, i2) => {
4957
+ if (!indexByName.has(f2.name)) indexByName.set(f2.name, []);
4958
+ indexByName.get(f2.name).push(i2);
4959
+ });
4881
4960
  for (const item of items) {
4882
4961
  if (item.status !== "uploading" || !item.upload_url || !item.doc_ext_id) {
4883
4962
  skipped.push({
@@ -4887,21 +4966,34 @@ async function uploadDocumentsDirect(arbi, workspaceKey, files, options) {
4887
4966
  continue;
4888
4967
  }
4889
4968
  const queue = bytesByName.get(item.file_name);
4890
- if (!queue || queue.length === 0) {
4969
+ const idxQueue = indexByName.get(item.file_name);
4970
+ if (!queue || queue.length === 0 || !idxQueue || idxQueue.length === 0) {
4891
4971
  throw new Error(`upload-init returned slot for unknown file: ${item.file_name}`);
4892
4972
  }
4893
4973
  const raw = queue.shift();
4974
+ const fileIndex = idxQueue.shift();
4894
4975
  const ciphertext = client.encryptFile(raw, workspaceKey);
4895
- const putRes = await fetch(item.upload_url, {
4896
- method: "PUT",
4897
- body: ciphertext
4898
- });
4899
- if (!putRes.ok) {
4900
- const body = await putRes.text().catch(() => "");
4976
+ const total = ciphertext.length;
4977
+ try {
4978
+ await presignedPut(item.upload_url, ciphertext, (loaded, putTotal) => {
4979
+ options?.onBytesProgress?.({
4980
+ fileIndex,
4981
+ fileName: item.file_name,
4982
+ loaded,
4983
+ total: putTotal
4984
+ });
4985
+ });
4986
+ } catch (err) {
4901
4987
  throw new Error(
4902
- `Presigned PUT for ${item.doc_ext_id} failed: ${putRes.status} ${body.slice(0, 200)}`
4988
+ `Presigned PUT for ${item.doc_ext_id} failed: ${err instanceof Error ? err.message : String(err)}`
4903
4989
  );
4904
4990
  }
4991
+ options?.onBytesProgress?.({
4992
+ fileIndex,
4993
+ fileName: item.file_name,
4994
+ loaded: total,
4995
+ total
4996
+ });
4905
4997
  toCommit.push(item.doc_ext_id);
4906
4998
  }
4907
4999
  if (toCommit.length === 0) {
@@ -5757,19 +5849,19 @@ var Arbi = class {
5757
5849
  get: (externalIds) => getDocuments(this.requireClient(), externalIds),
5758
5850
  delete: (externalIds) => deleteDocuments(this.requireClient(), externalIds),
5759
5851
  update: (documents) => updateDocuments(this.requireClient(), documents),
5760
- uploadUrl: (urls, shared, workspaceId) => uploadUrl(
5761
- this.requireClient(),
5762
- urls,
5763
- workspaceId ?? this.requireWorkspace(),
5764
- shared
5765
- ),
5766
- uploadFile: (fileData, fileName, options) => uploadFile(
5767
- this.getAuthHeaders(),
5768
- options?.workspaceId ?? this.requireWorkspace(),
5769
- fileData,
5770
- fileName,
5771
- options?.folder ? { folder: options.folder } : void 0
5772
- ),
5852
+ uploadUrl: (urls, shared) => {
5853
+ this.requireWorkspace();
5854
+ return uploadUrl(this.requireClient(), urls, shared);
5855
+ },
5856
+ uploadFile: (fileData, fileName, options) => {
5857
+ this.requireWorkspace();
5858
+ return uploadFile(
5859
+ this.getAuthHeaders(),
5860
+ fileData,
5861
+ fileName,
5862
+ options?.folder ? { folder: options.folder } : void 0
5863
+ );
5864
+ },
5773
5865
  download: (docId) => downloadDocument(this.getAuthHeaders(), docId),
5774
5866
  getParsedContent: (docId, stage) => getParsedContent(this.getAuthHeaders(), docId, stage)
5775
5867
  };
@@ -5967,7 +6059,8 @@ function chunk(arr, size) {
5967
6059
  }
5968
6060
  return chunks;
5969
6061
  }
5970
- function readFileAsBlob(filePath, fileSize) {
6062
+ function readFileAsBlob(filePath, fileSize, fileName) {
6063
+ const type = fileName ? mimeFromName(fileName) ?? "" : "";
5971
6064
  if (fileSize > NODE_BUFFER_LIMIT) {
5972
6065
  const chunks = [];
5973
6066
  const CHUNK = 256 * 1024 * 1024;
@@ -5981,15 +6074,15 @@ function readFileAsBlob(filePath, fileSize) {
5981
6074
  pos += len;
5982
6075
  }
5983
6076
  fs2__default.default.closeSync(fd);
5984
- return new Blob(chunks);
6077
+ return new Blob(chunks, { type });
5985
6078
  }
5986
- return new Blob([fs2__default.default.readFileSync(filePath)]);
6079
+ return new Blob([fs2__default.default.readFileSync(filePath)], { type });
5987
6080
  }
5988
- async function uploadLocalFile(auth, workspaceId, filePath, options) {
6081
+ async function uploadLocalFile(auth, filePath, options) {
5989
6082
  const stat = fs2__default.default.statSync(filePath);
5990
6083
  const fileName = path2__default.default.basename(filePath);
5991
- const blob = readFileAsBlob(filePath, stat.size);
5992
- const result = await uploadFile(auth, workspaceId, blob, fileName, options);
6084
+ const blob = readFileAsBlob(filePath, stat.size, fileName);
6085
+ const result = await uploadFile(auth, blob, fileName, options);
5993
6086
  return { ...result, fileName };
5994
6087
  }
5995
6088
  async function uploadLocalFilesDirect(arbi, workspaceKey, filePaths, options) {
@@ -6148,37 +6241,7 @@ async function uploadLocalArchiveDirect(arbi, workspaceKey, archivePath, options
6148
6241
  }
6149
6242
  }
6150
6243
  }
6151
- function mimeFromName(name) {
6152
- const ext = path2__default.default.extname(name).toLowerCase();
6153
- switch (ext) {
6154
- case ".pdf":
6155
- return "application/pdf";
6156
- case ".txt":
6157
- return "text/plain";
6158
- case ".md":
6159
- return "text/markdown";
6160
- case ".html":
6161
- case ".htm":
6162
- return "text/html";
6163
- case ".doc":
6164
- return "application/msword";
6165
- case ".docx":
6166
- return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
6167
- case ".xls":
6168
- return "application/vnd.ms-excel";
6169
- case ".xlsx":
6170
- return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
6171
- case ".ppt":
6172
- return "application/vnd.ms-powerpoint";
6173
- case ".pptx":
6174
- return "application/vnd.openxmlformats-officedocument.presentationml.presentation";
6175
- case ".eml":
6176
- return "message/rfc822";
6177
- default:
6178
- return void 0;
6179
- }
6180
- }
6181
- async function uploadDirectory(auth, workspaceId, dirPath, options) {
6244
+ async function uploadDirectory(auth, dirPath, options) {
6182
6245
  const resolvedDir = path2__default.default.resolve(dirPath);
6183
6246
  const dirName = path2__default.default.basename(resolvedDir);
6184
6247
  const entries = collectFiles(resolvedDir);
@@ -6234,7 +6297,7 @@ async function uploadDirectory(auth, workspaceId, dirPath, options) {
6234
6297
  });
6235
6298
  } else {
6236
6299
  try {
6237
- uploadable.push({ data: readFileAsBlob(f2.absolutePath, f2.size), name: f2.name });
6300
+ uploadable.push({ data: readFileAsBlob(f2.absolutePath, f2.size, f2.name), name: f2.name });
6238
6301
  } catch (err) {
6239
6302
  batchSkipped.push({
6240
6303
  file_name: f2.name,
@@ -6245,7 +6308,7 @@ async function uploadDirectory(auth, workspaceId, dirPath, options) {
6245
6308
  }
6246
6309
  let result = { doc_ext_ids: [], skipped: [] };
6247
6310
  if (uploadable.length > 0) {
6248
- result = await uploadFiles(auth, workspaceId, uploadable, {
6311
+ result = await uploadFiles(auth, uploadable, {
6249
6312
  folder,
6250
6313
  configExtId: options?.configExtId
6251
6314
  });
@@ -6270,7 +6333,7 @@ async function uploadDirectory(auth, workspaceId, dirPath, options) {
6270
6333
  }
6271
6334
  return { doc_ext_ids: allDocIds, skipped: allSkipped, folders };
6272
6335
  }
6273
- async function uploadZip(auth, workspaceId, zipPath, options) {
6336
+ async function uploadZip(auth, zipPath, options) {
6274
6337
  const JSZip = (await import('jszip')).default;
6275
6338
  const zipBuffer = fs2__default.default.readFileSync(zipPath);
6276
6339
  const zip = await JSZip.loadAsync(zipBuffer);
@@ -6334,7 +6397,7 @@ async function uploadZip(auth, workspaceId, zipPath, options) {
6334
6397
  data: new Blob([f2.data]),
6335
6398
  name: f2.name
6336
6399
  }));
6337
- const result = await uploadFiles(auth, workspaceId, blobs, {
6400
+ const result = await uploadFiles(auth, blobs, {
6338
6401
  folder,
6339
6402
  configExtId: options?.configExtId
6340
6403
  });
@@ -6405,7 +6468,7 @@ function isTransientError(err) {
6405
6468
  function sleep2(ms) {
6406
6469
  return new Promise((r2) => setTimeout(r2, ms));
6407
6470
  }
6408
- async function uploadManifest(auth, workspaceId, paths, options) {
6471
+ async function uploadManifest(auth, paths, options) {
6409
6472
  const maxRetries = Math.max(1, options?.maxRetries ?? 3);
6410
6473
  const outcomes = [];
6411
6474
  const summary = {
@@ -6526,7 +6589,7 @@ async function uploadManifest(auth, workspaceId, paths, options) {
6526
6589
  const readable = [];
6527
6590
  for (const f2 of batch) {
6528
6591
  try {
6529
- const blob = readFileAsBlob(f2.absolutePath, f2.size);
6592
+ const blob = readFileAsBlob(f2.absolutePath, f2.size, f2.basename);
6530
6593
  readable.push({ f: f2, blob });
6531
6594
  } catch (err) {
6532
6595
  const msg = err instanceof Error ? err.message : String(err);
@@ -6554,7 +6617,6 @@ async function uploadManifest(auth, workspaceId, paths, options) {
6554
6617
  try {
6555
6618
  result = await uploadFiles(
6556
6619
  auth,
6557
- workspaceId,
6558
6620
  readable.map((r2) => ({ data: r2.blob, name: r2.f.basename })),
6559
6621
  { folder, configExtId: options?.configExtId }
6560
6622
  );
@@ -6668,7 +6730,7 @@ function walkSupportedFiles(dirPath) {
6668
6730
  }
6669
6731
  return out.sort();
6670
6732
  }
6671
- async function uploadArchive(auth, workspaceId, archivePath, options) {
6733
+ async function uploadArchive(auth, archivePath, options) {
6672
6734
  try {
6673
6735
  child_process.execSync("7z --help", { stdio: "ignore" });
6674
6736
  } catch {
@@ -6687,7 +6749,7 @@ async function uploadArchive(auth, workspaceId, archivePath, options) {
6687
6749
  fs2__default.default.renameSync(tmpDir, namedDir);
6688
6750
  uploadDir = namedDir;
6689
6751
  }
6690
- return await uploadDirectory(auth, workspaceId, uploadDir, options);
6752
+ return await uploadDirectory(auth, uploadDir, options);
6691
6753
  } finally {
6692
6754
  fs2__default.default.rmSync(tmpDir, { recursive: true, force: true });
6693
6755
  }