@meistrari/vault-sdk 3.0.0 → 3.1.1

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
@@ -48,7 +48,7 @@ class FetchError extends Error {
48
48
  this.name = "FetchError";
49
49
  }
50
50
  static async from(url, method, response) {
51
- const text = await response.clone().json().then((json) => JSON.stringify(json, null, 2)).catch(() => response.clone().text());
51
+ const text = await response.clone().json().then((json) => JSON.stringify(json, null, 2)).catch(async () => await response.clone().text());
52
52
  const error = new FetchError(`Failed to ${method} ${url}: ${response.status} ${response.statusText}:
53
53
  ${text}`, url, method, response);
54
54
  return error;
@@ -237,7 +237,7 @@ function getFileName(content) {
237
237
  }
238
238
 
239
239
  const name = "@meistrari/vault-sdk";
240
- const version = "3.0.0";
240
+ const version = "3.1.1";
241
241
  const license = "UNLICENSED";
242
242
  const repository = {
243
243
  type: "git",
@@ -264,8 +264,8 @@ const scripts = {
264
264
  check: "bun run lint && bun tsc --noEmit"
265
265
  };
266
266
  const dependencies = {
267
- "@meistrari/file-type": "^22.0.0",
268
- "@meistrari/vault-shared": "0.0.7",
267
+ "@meistrari/file-type": "22.0.0",
268
+ "@meistrari/vault-shared": "0.1.0",
269
269
  "mime-types": "3.0.1",
270
270
  ofetch: "1.4.1",
271
271
  zod: "3.23.8"
@@ -309,6 +309,7 @@ var __publicField = (obj, key, value) => {
309
309
  return value;
310
310
  };
311
311
  const compatibilityDate = "2025-05-19";
312
+ const bunStreamingUploadFixVersion = "1.3.10";
312
313
  function detectMimeTypeFromFilename(filename) {
313
314
  const extension = filename.split(".").pop()?.toLowerCase();
314
315
  if (extension) {
@@ -319,6 +320,30 @@ function detectMimeTypeFromFilename(filename) {
319
320
  }
320
321
  return void 0;
321
322
  }
323
+ function compareDottedVersions(left, right) {
324
+ const leftParts = left.split(".");
325
+ const rightParts = right.split(".");
326
+ const length = Math.max(leftParts.length, rightParts.length);
327
+ for (let index = 0; index < length; index++) {
328
+ const leftPart = Number.parseInt(leftParts[index] ?? "0", 10);
329
+ const rightPart = Number.parseInt(rightParts[index] ?? "0", 10);
330
+ const normalizedLeft = Number.isNaN(leftPart) ? 0 : leftPart;
331
+ const normalizedRight = Number.isNaN(rightPart) ? 0 : rightPart;
332
+ if (normalizedLeft !== normalizedRight) {
333
+ return normalizedLeft - normalizedRight;
334
+ }
335
+ }
336
+ return 0;
337
+ }
338
+ function shouldBufferStreamingUploadForBunVersion(bunVersion) {
339
+ return compareDottedVersions(bunVersion, bunStreamingUploadFixVersion) < 0;
340
+ }
341
+ function shouldBufferStreamingUploadOnBun() {
342
+ if (typeof Bun === "undefined") {
343
+ return false;
344
+ }
345
+ return shouldBufferStreamingUploadForBunVersion(Bun.version);
346
+ }
322
347
  async function wrappedFetch(url, requestInit) {
323
348
  const options = {
324
349
  ...requestInit,
@@ -426,7 +451,7 @@ class VaultFile {
426
451
  async _createFile(metadata = {}, options) {
427
452
  const response = await this._fetch({
428
453
  method: "POST",
429
- path: `files`,
454
+ path: "files",
430
455
  body: JSON.stringify({
431
456
  size: metadata.size,
432
457
  mimeType: metadata.mimeType,
@@ -495,7 +520,7 @@ class VaultFile {
495
520
  method: "GET",
496
521
  headers: authStrategy.getHeaders(),
497
522
  signal: options?.signal
498
- }).then((response2) => response2.json()).then((data) => schemas.GetDownloadUrlResponse.safeParse(data));
523
+ }).then(async (response2) => await response2.json()).then((data) => schemas.GetDownloadUrlResponse.safeParse(data));
499
524
  if (!response.success) {
500
525
  throw new Error("Invalid response from vault service");
501
526
  }
@@ -509,7 +534,7 @@ class VaultFile {
509
534
  name: response.data.metadata?.originalFileName ?? void 0
510
535
  };
511
536
  if (download) {
512
- await wrappedFetch(response.data.url, { method: "GET", signal: options?.signal }).then((response2) => response2.blob()).then((blob) => fileParams.content = blob);
537
+ await wrappedFetch(response.data.url, { method: "GET", signal: options?.signal }).then(async (response2) => await response2.blob()).then((blob) => fileParams.content = blob);
513
538
  }
514
539
  return new VaultFile(fileParams);
515
540
  }
@@ -732,8 +757,8 @@ class VaultFile {
732
757
  const file = new VaultFile({
733
758
  config,
734
759
  id: item.id,
735
- name: item.metadata?.originalFileName ?? preparedFiles[index].name,
736
- content: preparedFiles[index].content,
760
+ name: item.metadata.originalFileName ?? preparedFiles[index]?.name,
761
+ content: preparedFiles[index]?.content,
737
762
  metadata: item.metadata
738
763
  });
739
764
  file.lastUploadUrl = {
@@ -745,7 +770,7 @@ class VaultFile {
745
770
  if (upload) {
746
771
  await Promise.all(
747
772
  vaultFiles.map(
748
- (file) => file.upload(void 0, void 0, { signal: options?.signal })
773
+ async (file) => await file.upload(void 0, void 0, { signal: options?.signal })
749
774
  )
750
775
  );
751
776
  }
@@ -812,7 +837,7 @@ class VaultFile {
812
837
  const file = new VaultFile({
813
838
  config,
814
839
  id: item.id,
815
- name: item.metadata?.originalFileName ?? preparedFiles[index].name,
840
+ name: item.metadata?.originalFileName ?? preparedFiles[index]?.name,
816
841
  metadata: item.metadata
817
842
  });
818
843
  file.lastUploadUrl = {
@@ -867,6 +892,7 @@ class VaultFile {
867
892
  } catch (error) {
868
893
  console.error("Error fetching file metadata", error);
869
894
  }
895
+ return void 0;
870
896
  }
871
897
  /**
872
898
  * Returns the vault URI reference for this file.
@@ -1006,7 +1032,7 @@ class VaultFile {
1006
1032
  path: `files/${this.id}`,
1007
1033
  signal: options?.signal,
1008
1034
  ...options?.expiresIn ? { query: { expiresIn: options.expiresIn.toString() } } : {}
1009
- }).then(schemas.GetUploadUrlResponseV2.safeParse);
1035
+ }).then((result) => schemas.GetUploadUrlResponseV2.safeParse(result));
1010
1036
  if (!response.success) {
1011
1037
  throw new Error(`Invalid response from vault service. ${JSON.stringify(response.error)}`);
1012
1038
  }
@@ -1211,7 +1237,8 @@ class VaultFile {
1211
1237
  *
1212
1238
  * This method is ideal for uploading large files without loading the entire content into memory.
1213
1239
  * The stream is sent directly to cloud storage, making it perfect for files larger than a few
1214
- * megabytes. Note: When using Bun, the stream is buffered due to implementation limitations.
1240
+ * megabytes. Note: On Bun versions older than 1.3.10, the stream is buffered due to
1241
+ * implementation limitations.
1215
1242
  *
1216
1243
  * @param stream - A ReadableStream of Uint8Array chunks containing the file data
1217
1244
  * @param options - Required options for the upload
@@ -1278,10 +1305,10 @@ class VaultFile {
1278
1305
  headers.set("Content-Type", mimeType);
1279
1306
  headers.set("Content-Length", contentLength.toString());
1280
1307
  let content = stream;
1281
- if (stream instanceof ReadableStream && typeof Bun !== "undefined") {
1308
+ if (stream instanceof ReadableStream && shouldBufferStreamingUploadOnBun()) {
1282
1309
  console.warn(
1283
- "[Vault SDK - WARNING] Buffering file upload due to Bun fetch implementation. Large files may cause memory issues. Consider using Node.js for streaming uploads.",
1284
- { fileName: this.name, fileSize: contentLength }
1310
+ `[Vault SDK - WARNING] Buffering file upload on Bun ${Bun.version}. Streaming uploads are only buffered on Bun versions older than ${bunStreamingUploadFixVersion}. Large files may cause memory issues. Upgrade Bun or use Node.js for streaming uploads.`,
1311
+ { fileName: this.name, fileSize: contentLength, bunVersion: Bun.version }
1285
1312
  );
1286
1313
  const chunks = [];
1287
1314
  const reader = stream.getReader();
@@ -1412,7 +1439,7 @@ class VaultFile {
1412
1439
  if (!this.metadata?.workspaceId) {
1413
1440
  throw new Error("Workspace ID is not set. Call populateMetadata() to populate the metadata fields.");
1414
1441
  }
1415
- return Permalink.create(this.config, {
1442
+ return await Permalink.create(this.config, {
1416
1443
  fileId: this.id,
1417
1444
  workspaceId: this.metadata.workspaceId,
1418
1445
  expiresIn: params.expiresIn
@@ -1685,7 +1712,7 @@ class VaultFile {
1685
1712
  if (!this.id) {
1686
1713
  throw new Error("Parent file ID is not set");
1687
1714
  }
1688
- return VaultFile.fromContent(
1715
+ return await VaultFile.fromContent(
1689
1716
  {
1690
1717
  ...params,
1691
1718
  config: this.config,
@@ -1734,7 +1761,7 @@ class VaultFile {
1734
1761
  if (!this.id) {
1735
1762
  throw new Error("Parent file ID is not set");
1736
1763
  }
1737
- return VaultFile.fromStream(
1764
+ return await VaultFile.fromStream(
1738
1765
  {
1739
1766
  ...params,
1740
1767
  config: this.config,
@@ -1809,8 +1836,8 @@ class VaultFile {
1809
1836
  }
1810
1837
  }
1811
1838
 
1812
- const VAULT_REFERENCE_UUID_REGEX = /^vault:\/\/[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
1813
- const VAULT_REFERENCE_SHA256_REGEX = /^vault:\/\/[a-f0-9]{64}$/i;
1839
+ const VAULT_REFERENCE_UUID_REGEX = /vault:\/\/[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/i;
1840
+ const VAULT_REFERENCE_SHA256_REGEX = /vault:\/\/[a-f0-9]{64}/i;
1814
1841
  function isValidUuidV4(uuid) {
1815
1842
  return /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(uuid);
1816
1843
  }
@@ -1840,7 +1867,14 @@ function isS3UrlExpired(url) {
1840
1867
  }
1841
1868
  }
1842
1869
  function isVaultReference(url) {
1843
- return VAULT_REFERENCE_UUID_REGEX.test(url) || VAULT_REFERENCE_SHA256_REGEX.test(url);
1870
+ return new RegExp(`^${VAULT_REFERENCE_UUID_REGEX.source}$`, "i").test(url) || new RegExp(`^${VAULT_REFERENCE_SHA256_REGEX.source}$`, "i").test(url);
1871
+ }
1872
+ function extractVaultReferences(text) {
1873
+ const uuidRegex = new RegExp(VAULT_REFERENCE_UUID_REGEX.source, "gi");
1874
+ const sha256Regex = new RegExp(VAULT_REFERENCE_SHA256_REGEX.source, "gi");
1875
+ const uuidMatches = text.match(uuidRegex) || [];
1876
+ const sha256Matches = text.match(sha256Regex) || [];
1877
+ return [...uuidMatches, ...sha256Matches];
1844
1878
  }
1845
1879
  function isPresignedS3Url(url) {
1846
1880
  try {
@@ -1985,6 +2019,7 @@ exports.FetchError = FetchError;
1985
2019
  exports.VaultFile = VaultFile;
1986
2020
  exports.convertS3UrlToVaultReference = convertS3UrlToVaultReference;
1987
2021
  exports.extractVaultFileIdFromS3Url = extractVaultFileIdFromS3Url;
2022
+ exports.extractVaultReferences = extractVaultReferences;
1988
2023
  exports.getVaultParamsFromS3Url = getVaultParamsFromS3Url;
1989
2024
  exports.isS3UrlExpired = isS3UrlExpired;
1990
2025
  exports.isTaggedVaultPresignedUrl = isTaggedVaultPresignedUrl;
package/dist/index.d.cts CHANGED
@@ -786,7 +786,8 @@ declare class VaultFile {
786
786
  *
787
787
  * This method is ideal for uploading large files without loading the entire content into memory.
788
788
  * The stream is sent directly to cloud storage, making it perfect for files larger than a few
789
- * megabytes. Note: When using Bun, the stream is buffered due to implementation limitations.
789
+ * megabytes. Note: On Bun versions older than 1.3.10, the stream is buffered due to
790
+ * implementation limitations.
790
791
  *
791
792
  * @param stream - A ReadableStream of Uint8Array chunks containing the file data
792
793
  * @param options - Required options for the upload
@@ -1271,6 +1272,18 @@ declare function isS3UrlExpired(url: string): boolean;
1271
1272
  * @returns true if the URL is a valid vault reference, false otherwise
1272
1273
  */
1273
1274
  declare function isVaultReference(url: string): boolean;
1275
+ /**
1276
+ * Extracts all vault references from a given text string.
1277
+ * Finds both UUID v4 and SHA-256 hash format vault references.
1278
+ *
1279
+ * @param text - The text to search for vault references
1280
+ * @returns An array of vault reference strings found in the text
1281
+ * @example
1282
+ * const text = 'Files: vault://2fce5740-83da-49fe-3f10-b32205893ec0 and vault://abc123...def'
1283
+ * const refs = extractVaultReferences(text)
1284
+ * // Returns: ['vault://2fce5740-83da-49fe-3f10-b32205893ec0', 'vault://abc123...def']
1285
+ */
1286
+ declare function extractVaultReferences(text: string): string[];
1274
1287
  /**
1275
1288
  * Checks if a URL seems like a valid presigned S3 URL, with no additional checks.
1276
1289
  *
@@ -1388,5 +1401,5 @@ declare function vaultClient(vaultConfig: VaultConfig): {
1388
1401
  }) => Promise<VaultFile[]>;
1389
1402
  };
1390
1403
 
1391
- export { APIKeyAuthStrategy, DataTokenAuthStrategy, FetchError, VaultFile, convertS3UrlToVaultReference, extractVaultFileIdFromS3Url, getVaultParamsFromS3Url, isS3UrlExpired, isTaggedVaultPresignedUrl, isPresignedS3Url as isVaultFileS3Url, isVaultReference, vaultClient };
1404
+ export { APIKeyAuthStrategy, DataTokenAuthStrategy, FetchError, VaultFile, convertS3UrlToVaultReference, extractVaultFileIdFromS3Url, extractVaultReferences, getVaultParamsFromS3Url, isS3UrlExpired, isTaggedVaultPresignedUrl, isPresignedS3Url as isVaultFileS3Url, isVaultReference, vaultClient };
1392
1405
  export type { AuthStrategy, VaultConfig };
package/dist/index.d.mts CHANGED
@@ -786,7 +786,8 @@ declare class VaultFile {
786
786
  *
787
787
  * This method is ideal for uploading large files without loading the entire content into memory.
788
788
  * The stream is sent directly to cloud storage, making it perfect for files larger than a few
789
- * megabytes. Note: When using Bun, the stream is buffered due to implementation limitations.
789
+ * megabytes. Note: On Bun versions older than 1.3.10, the stream is buffered due to
790
+ * implementation limitations.
790
791
  *
791
792
  * @param stream - A ReadableStream of Uint8Array chunks containing the file data
792
793
  * @param options - Required options for the upload
@@ -1271,6 +1272,18 @@ declare function isS3UrlExpired(url: string): boolean;
1271
1272
  * @returns true if the URL is a valid vault reference, false otherwise
1272
1273
  */
1273
1274
  declare function isVaultReference(url: string): boolean;
1275
+ /**
1276
+ * Extracts all vault references from a given text string.
1277
+ * Finds both UUID v4 and SHA-256 hash format vault references.
1278
+ *
1279
+ * @param text - The text to search for vault references
1280
+ * @returns An array of vault reference strings found in the text
1281
+ * @example
1282
+ * const text = 'Files: vault://2fce5740-83da-49fe-3f10-b32205893ec0 and vault://abc123...def'
1283
+ * const refs = extractVaultReferences(text)
1284
+ * // Returns: ['vault://2fce5740-83da-49fe-3f10-b32205893ec0', 'vault://abc123...def']
1285
+ */
1286
+ declare function extractVaultReferences(text: string): string[];
1274
1287
  /**
1275
1288
  * Checks if a URL seems like a valid presigned S3 URL, with no additional checks.
1276
1289
  *
@@ -1388,5 +1401,5 @@ declare function vaultClient(vaultConfig: VaultConfig): {
1388
1401
  }) => Promise<VaultFile[]>;
1389
1402
  };
1390
1403
 
1391
- export { APIKeyAuthStrategy, DataTokenAuthStrategy, FetchError, VaultFile, convertS3UrlToVaultReference, extractVaultFileIdFromS3Url, getVaultParamsFromS3Url, isS3UrlExpired, isTaggedVaultPresignedUrl, isPresignedS3Url as isVaultFileS3Url, isVaultReference, vaultClient };
1404
+ export { APIKeyAuthStrategy, DataTokenAuthStrategy, FetchError, VaultFile, convertS3UrlToVaultReference, extractVaultFileIdFromS3Url, extractVaultReferences, getVaultParamsFromS3Url, isS3UrlExpired, isTaggedVaultPresignedUrl, isPresignedS3Url as isVaultFileS3Url, isVaultReference, vaultClient };
1392
1405
  export type { AuthStrategy, VaultConfig };
package/dist/index.d.ts CHANGED
@@ -786,7 +786,8 @@ declare class VaultFile {
786
786
  *
787
787
  * This method is ideal for uploading large files without loading the entire content into memory.
788
788
  * The stream is sent directly to cloud storage, making it perfect for files larger than a few
789
- * megabytes. Note: When using Bun, the stream is buffered due to implementation limitations.
789
+ * megabytes. Note: On Bun versions older than 1.3.10, the stream is buffered due to
790
+ * implementation limitations.
790
791
  *
791
792
  * @param stream - A ReadableStream of Uint8Array chunks containing the file data
792
793
  * @param options - Required options for the upload
@@ -1271,6 +1272,18 @@ declare function isS3UrlExpired(url: string): boolean;
1271
1272
  * @returns true if the URL is a valid vault reference, false otherwise
1272
1273
  */
1273
1274
  declare function isVaultReference(url: string): boolean;
1275
+ /**
1276
+ * Extracts all vault references from a given text string.
1277
+ * Finds both UUID v4 and SHA-256 hash format vault references.
1278
+ *
1279
+ * @param text - The text to search for vault references
1280
+ * @returns An array of vault reference strings found in the text
1281
+ * @example
1282
+ * const text = 'Files: vault://2fce5740-83da-49fe-3f10-b32205893ec0 and vault://abc123...def'
1283
+ * const refs = extractVaultReferences(text)
1284
+ * // Returns: ['vault://2fce5740-83da-49fe-3f10-b32205893ec0', 'vault://abc123...def']
1285
+ */
1286
+ declare function extractVaultReferences(text: string): string[];
1274
1287
  /**
1275
1288
  * Checks if a URL seems like a valid presigned S3 URL, with no additional checks.
1276
1289
  *
@@ -1388,5 +1401,5 @@ declare function vaultClient(vaultConfig: VaultConfig): {
1388
1401
  }) => Promise<VaultFile[]>;
1389
1402
  };
1390
1403
 
1391
- export { APIKeyAuthStrategy, DataTokenAuthStrategy, FetchError, VaultFile, convertS3UrlToVaultReference, extractVaultFileIdFromS3Url, getVaultParamsFromS3Url, isS3UrlExpired, isTaggedVaultPresignedUrl, isPresignedS3Url as isVaultFileS3Url, isVaultReference, vaultClient };
1404
+ export { APIKeyAuthStrategy, DataTokenAuthStrategy, FetchError, VaultFile, convertS3UrlToVaultReference, extractVaultFileIdFromS3Url, extractVaultReferences, getVaultParamsFromS3Url, isS3UrlExpired, isTaggedVaultPresignedUrl, isPresignedS3Url as isVaultFileS3Url, isVaultReference, vaultClient };
1392
1405
  export type { AuthStrategy, VaultConfig };
package/dist/index.mjs CHANGED
@@ -42,7 +42,7 @@ class FetchError extends Error {
42
42
  this.name = "FetchError";
43
43
  }
44
44
  static async from(url, method, response) {
45
- const text = await response.clone().json().then((json) => JSON.stringify(json, null, 2)).catch(() => response.clone().text());
45
+ const text = await response.clone().json().then((json) => JSON.stringify(json, null, 2)).catch(async () => await response.clone().text());
46
46
  const error = new FetchError(`Failed to ${method} ${url}: ${response.status} ${response.statusText}:
47
47
  ${text}`, url, method, response);
48
48
  return error;
@@ -231,7 +231,7 @@ function getFileName(content) {
231
231
  }
232
232
 
233
233
  const name = "@meistrari/vault-sdk";
234
- const version = "3.0.0";
234
+ const version = "3.1.1";
235
235
  const license = "UNLICENSED";
236
236
  const repository = {
237
237
  type: "git",
@@ -258,8 +258,8 @@ const scripts = {
258
258
  check: "bun run lint && bun tsc --noEmit"
259
259
  };
260
260
  const dependencies = {
261
- "@meistrari/file-type": "^22.0.0",
262
- "@meistrari/vault-shared": "0.0.7",
261
+ "@meistrari/file-type": "22.0.0",
262
+ "@meistrari/vault-shared": "0.1.0",
263
263
  "mime-types": "3.0.1",
264
264
  ofetch: "1.4.1",
265
265
  zod: "3.23.8"
@@ -303,6 +303,7 @@ var __publicField = (obj, key, value) => {
303
303
  return value;
304
304
  };
305
305
  const compatibilityDate = "2025-05-19";
306
+ const bunStreamingUploadFixVersion = "1.3.10";
306
307
  function detectMimeTypeFromFilename(filename) {
307
308
  const extension = filename.split(".").pop()?.toLowerCase();
308
309
  if (extension) {
@@ -313,6 +314,30 @@ function detectMimeTypeFromFilename(filename) {
313
314
  }
314
315
  return void 0;
315
316
  }
317
+ function compareDottedVersions(left, right) {
318
+ const leftParts = left.split(".");
319
+ const rightParts = right.split(".");
320
+ const length = Math.max(leftParts.length, rightParts.length);
321
+ for (let index = 0; index < length; index++) {
322
+ const leftPart = Number.parseInt(leftParts[index] ?? "0", 10);
323
+ const rightPart = Number.parseInt(rightParts[index] ?? "0", 10);
324
+ const normalizedLeft = Number.isNaN(leftPart) ? 0 : leftPart;
325
+ const normalizedRight = Number.isNaN(rightPart) ? 0 : rightPart;
326
+ if (normalizedLeft !== normalizedRight) {
327
+ return normalizedLeft - normalizedRight;
328
+ }
329
+ }
330
+ return 0;
331
+ }
332
+ function shouldBufferStreamingUploadForBunVersion(bunVersion) {
333
+ return compareDottedVersions(bunVersion, bunStreamingUploadFixVersion) < 0;
334
+ }
335
+ function shouldBufferStreamingUploadOnBun() {
336
+ if (typeof Bun === "undefined") {
337
+ return false;
338
+ }
339
+ return shouldBufferStreamingUploadForBunVersion(Bun.version);
340
+ }
316
341
  async function wrappedFetch(url, requestInit) {
317
342
  const options = {
318
343
  ...requestInit,
@@ -420,7 +445,7 @@ class VaultFile {
420
445
  async _createFile(metadata = {}, options) {
421
446
  const response = await this._fetch({
422
447
  method: "POST",
423
- path: `files`,
448
+ path: "files",
424
449
  body: JSON.stringify({
425
450
  size: metadata.size,
426
451
  mimeType: metadata.mimeType,
@@ -489,7 +514,7 @@ class VaultFile {
489
514
  method: "GET",
490
515
  headers: authStrategy.getHeaders(),
491
516
  signal: options?.signal
492
- }).then((response2) => response2.json()).then((data) => GetDownloadUrlResponse.safeParse(data));
517
+ }).then(async (response2) => await response2.json()).then((data) => GetDownloadUrlResponse.safeParse(data));
493
518
  if (!response.success) {
494
519
  throw new Error("Invalid response from vault service");
495
520
  }
@@ -503,7 +528,7 @@ class VaultFile {
503
528
  name: response.data.metadata?.originalFileName ?? void 0
504
529
  };
505
530
  if (download) {
506
- await wrappedFetch(response.data.url, { method: "GET", signal: options?.signal }).then((response2) => response2.blob()).then((blob) => fileParams.content = blob);
531
+ await wrappedFetch(response.data.url, { method: "GET", signal: options?.signal }).then(async (response2) => await response2.blob()).then((blob) => fileParams.content = blob);
507
532
  }
508
533
  return new VaultFile(fileParams);
509
534
  }
@@ -726,8 +751,8 @@ class VaultFile {
726
751
  const file = new VaultFile({
727
752
  config,
728
753
  id: item.id,
729
- name: item.metadata?.originalFileName ?? preparedFiles[index].name,
730
- content: preparedFiles[index].content,
754
+ name: item.metadata.originalFileName ?? preparedFiles[index]?.name,
755
+ content: preparedFiles[index]?.content,
731
756
  metadata: item.metadata
732
757
  });
733
758
  file.lastUploadUrl = {
@@ -739,7 +764,7 @@ class VaultFile {
739
764
  if (upload) {
740
765
  await Promise.all(
741
766
  vaultFiles.map(
742
- (file) => file.upload(void 0, void 0, { signal: options?.signal })
767
+ async (file) => await file.upload(void 0, void 0, { signal: options?.signal })
743
768
  )
744
769
  );
745
770
  }
@@ -806,7 +831,7 @@ class VaultFile {
806
831
  const file = new VaultFile({
807
832
  config,
808
833
  id: item.id,
809
- name: item.metadata?.originalFileName ?? preparedFiles[index].name,
834
+ name: item.metadata?.originalFileName ?? preparedFiles[index]?.name,
810
835
  metadata: item.metadata
811
836
  });
812
837
  file.lastUploadUrl = {
@@ -861,6 +886,7 @@ class VaultFile {
861
886
  } catch (error) {
862
887
  console.error("Error fetching file metadata", error);
863
888
  }
889
+ return void 0;
864
890
  }
865
891
  /**
866
892
  * Returns the vault URI reference for this file.
@@ -1000,7 +1026,7 @@ class VaultFile {
1000
1026
  path: `files/${this.id}`,
1001
1027
  signal: options?.signal,
1002
1028
  ...options?.expiresIn ? { query: { expiresIn: options.expiresIn.toString() } } : {}
1003
- }).then(GetUploadUrlResponseV2.safeParse);
1029
+ }).then((result) => GetUploadUrlResponseV2.safeParse(result));
1004
1030
  if (!response.success) {
1005
1031
  throw new Error(`Invalid response from vault service. ${JSON.stringify(response.error)}`);
1006
1032
  }
@@ -1205,7 +1231,8 @@ class VaultFile {
1205
1231
  *
1206
1232
  * This method is ideal for uploading large files without loading the entire content into memory.
1207
1233
  * The stream is sent directly to cloud storage, making it perfect for files larger than a few
1208
- * megabytes. Note: When using Bun, the stream is buffered due to implementation limitations.
1234
+ * megabytes. Note: On Bun versions older than 1.3.10, the stream is buffered due to
1235
+ * implementation limitations.
1209
1236
  *
1210
1237
  * @param stream - A ReadableStream of Uint8Array chunks containing the file data
1211
1238
  * @param options - Required options for the upload
@@ -1272,10 +1299,10 @@ class VaultFile {
1272
1299
  headers.set("Content-Type", mimeType);
1273
1300
  headers.set("Content-Length", contentLength.toString());
1274
1301
  let content = stream;
1275
- if (stream instanceof ReadableStream && typeof Bun !== "undefined") {
1302
+ if (stream instanceof ReadableStream && shouldBufferStreamingUploadOnBun()) {
1276
1303
  console.warn(
1277
- "[Vault SDK - WARNING] Buffering file upload due to Bun fetch implementation. Large files may cause memory issues. Consider using Node.js for streaming uploads.",
1278
- { fileName: this.name, fileSize: contentLength }
1304
+ `[Vault SDK - WARNING] Buffering file upload on Bun ${Bun.version}. Streaming uploads are only buffered on Bun versions older than ${bunStreamingUploadFixVersion}. Large files may cause memory issues. Upgrade Bun or use Node.js for streaming uploads.`,
1305
+ { fileName: this.name, fileSize: contentLength, bunVersion: Bun.version }
1279
1306
  );
1280
1307
  const chunks = [];
1281
1308
  const reader = stream.getReader();
@@ -1406,7 +1433,7 @@ class VaultFile {
1406
1433
  if (!this.metadata?.workspaceId) {
1407
1434
  throw new Error("Workspace ID is not set. Call populateMetadata() to populate the metadata fields.");
1408
1435
  }
1409
- return Permalink.create(this.config, {
1436
+ return await Permalink.create(this.config, {
1410
1437
  fileId: this.id,
1411
1438
  workspaceId: this.metadata.workspaceId,
1412
1439
  expiresIn: params.expiresIn
@@ -1679,7 +1706,7 @@ class VaultFile {
1679
1706
  if (!this.id) {
1680
1707
  throw new Error("Parent file ID is not set");
1681
1708
  }
1682
- return VaultFile.fromContent(
1709
+ return await VaultFile.fromContent(
1683
1710
  {
1684
1711
  ...params,
1685
1712
  config: this.config,
@@ -1728,7 +1755,7 @@ class VaultFile {
1728
1755
  if (!this.id) {
1729
1756
  throw new Error("Parent file ID is not set");
1730
1757
  }
1731
- return VaultFile.fromStream(
1758
+ return await VaultFile.fromStream(
1732
1759
  {
1733
1760
  ...params,
1734
1761
  config: this.config,
@@ -1803,8 +1830,8 @@ class VaultFile {
1803
1830
  }
1804
1831
  }
1805
1832
 
1806
- const VAULT_REFERENCE_UUID_REGEX = /^vault:\/\/[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
1807
- const VAULT_REFERENCE_SHA256_REGEX = /^vault:\/\/[a-f0-9]{64}$/i;
1833
+ const VAULT_REFERENCE_UUID_REGEX = /vault:\/\/[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/i;
1834
+ const VAULT_REFERENCE_SHA256_REGEX = /vault:\/\/[a-f0-9]{64}/i;
1808
1835
  function isValidUuidV4(uuid) {
1809
1836
  return /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(uuid);
1810
1837
  }
@@ -1834,7 +1861,14 @@ function isS3UrlExpired(url) {
1834
1861
  }
1835
1862
  }
1836
1863
  function isVaultReference(url) {
1837
- return VAULT_REFERENCE_UUID_REGEX.test(url) || VAULT_REFERENCE_SHA256_REGEX.test(url);
1864
+ return new RegExp(`^${VAULT_REFERENCE_UUID_REGEX.source}$`, "i").test(url) || new RegExp(`^${VAULT_REFERENCE_SHA256_REGEX.source}$`, "i").test(url);
1865
+ }
1866
+ function extractVaultReferences(text) {
1867
+ const uuidRegex = new RegExp(VAULT_REFERENCE_UUID_REGEX.source, "gi");
1868
+ const sha256Regex = new RegExp(VAULT_REFERENCE_SHA256_REGEX.source, "gi");
1869
+ const uuidMatches = text.match(uuidRegex) || [];
1870
+ const sha256Matches = text.match(sha256Regex) || [];
1871
+ return [...uuidMatches, ...sha256Matches];
1838
1872
  }
1839
1873
  function isPresignedS3Url(url) {
1840
1874
  try {
@@ -1973,4 +2007,4 @@ function vaultClient(vaultConfig) {
1973
2007
  return { createFromContent, createFromReference, createFromStream, createFromContentBulk, createFromStreamBulk };
1974
2008
  }
1975
2009
 
1976
- export { APIKeyAuthStrategy, DataTokenAuthStrategy, FetchError, VaultFile, convertS3UrlToVaultReference, extractVaultFileIdFromS3Url, getVaultParamsFromS3Url, isS3UrlExpired, isTaggedVaultPresignedUrl, isPresignedS3Url as isVaultFileS3Url, isVaultReference, vaultClient };
2010
+ export { APIKeyAuthStrategy, DataTokenAuthStrategy, FetchError, VaultFile, convertS3UrlToVaultReference, extractVaultFileIdFromS3Url, extractVaultReferences, getVaultParamsFromS3Url, isS3UrlExpired, isTaggedVaultPresignedUrl, isPresignedS3Url as isVaultFileS3Url, isVaultReference, vaultClient };
package/package.json CHANGED
@@ -1,49 +1,49 @@
1
1
  {
2
- "name": "@meistrari/vault-sdk",
3
- "version": "3.0.0",
4
- "license": "UNLICENSED",
5
- "repository": {
6
- "type": "git",
7
- "url": "https://github.com/meistrari/vault.git"
8
- },
9
- "exports": {
10
- ".": {
11
- "types": "./dist/index.d.ts",
12
- "import": "./dist/index.mjs",
13
- "require": "./dist/index.cjs"
14
- }
15
- },
16
- "main": "dist/index.mjs",
17
- "types": "dist/index.d.ts",
18
- "files": [
19
- "dist"
20
- ],
21
- "scripts": {
22
- "test": "vitest --no-watch",
23
- "test:watch": "vitest",
24
- "build": "unbuild",
25
- "lint": "eslint .",
26
- "lint:fix": "eslint . --fix",
27
- "check": "bun run lint && bun tsc --noEmit"
28
- },
29
- "dependencies": {
30
- "@meistrari/file-type": "^22.0.0",
31
- "@meistrari/vault-shared": "0.0.7",
32
- "mime-types": "3.0.1",
33
- "ofetch": "1.4.1",
34
- "zod": "3.23.8"
35
- },
36
- "devDependencies": {
37
- "@types/bun": "latest",
38
- "@types/mime-types": "3.0.1",
39
- "msw": "2.6.8",
40
- "unbuild": "2.0.0",
41
- "vitest": "2.1.9"
42
- },
43
- "peerDependencies": {
44
- "typescript": "^5.0.0"
45
- },
46
- "publishConfig": {
47
- "access": "public"
2
+ "name": "@meistrari/vault-sdk",
3
+ "version": "3.1.1",
4
+ "license": "UNLICENSED",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/meistrari/vault.git"
8
+ },
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.mjs",
13
+ "require": "./dist/index.cjs"
48
14
  }
15
+ },
16
+ "main": "dist/index.mjs",
17
+ "types": "dist/index.d.ts",
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "scripts": {
22
+ "test": "vitest --no-watch",
23
+ "test:watch": "vitest",
24
+ "build": "unbuild",
25
+ "lint": "eslint .",
26
+ "lint:fix": "eslint . --fix",
27
+ "check": "bun run lint && bun tsc --noEmit"
28
+ },
29
+ "dependencies": {
30
+ "@meistrari/file-type": "22.0.0",
31
+ "@meistrari/vault-shared": "0.1.0",
32
+ "mime-types": "3.0.1",
33
+ "ofetch": "1.4.1",
34
+ "zod": "3.23.8"
35
+ },
36
+ "devDependencies": {
37
+ "@types/bun": "latest",
38
+ "@types/mime-types": "3.0.1",
39
+ "msw": "2.6.8",
40
+ "unbuild": "2.0.0",
41
+ "vitest": "2.1.9"
42
+ },
43
+ "peerDependencies": {
44
+ "typescript": "^5.0.0"
45
+ },
46
+ "publishConfig": {
47
+ "access": "public"
48
+ }
49
49
  }