@meistrari/vault-sdk 1.4.3 → 1.5.0

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
@@ -200,6 +200,69 @@ async function detectFileMimeType(blob) {
200
200
  return void 0;
201
201
  }
202
202
 
203
+ const name = "@meistrari/vault-sdk";
204
+ const version = "1.5.0";
205
+ const license = "UNLICENSED";
206
+ const repository = {
207
+ type: "git",
208
+ url: "https://github.com/meistrari/vault.git"
209
+ };
210
+ const exports$1 = {
211
+ ".": {
212
+ types: "./dist/index.d.ts",
213
+ "import": "./dist/index.mjs",
214
+ require: "./dist/index.cjs"
215
+ }
216
+ };
217
+ const main = "dist/index.mjs";
218
+ const types = "dist/index.d.ts";
219
+ const files = [
220
+ "dist"
221
+ ];
222
+ const scripts = {
223
+ test: "vitest --no-watch",
224
+ "test:watch": "vitest",
225
+ build: "unbuild",
226
+ lint: "eslint .",
227
+ "lint:fix": "eslint . --fix",
228
+ check: "bun run lint && bun tsc --noEmit"
229
+ };
230
+ const dependencies = {
231
+ "@meistrari/vault-shared": "workspace:*",
232
+ "file-type": "21.0.0",
233
+ "mime-types": "3.0.1",
234
+ ofetch: "1.4.1",
235
+ zod: "3.23.8"
236
+ };
237
+ const devDependencies = {
238
+ "@types/bun": "latest",
239
+ "@types/mime-types": "3.0.1",
240
+ msw: "2.6.8",
241
+ unbuild: "2.0.0",
242
+ vitest: "2.1.9"
243
+ };
244
+ const peerDependencies = {
245
+ typescript: "^5.0.0"
246
+ };
247
+ const publishConfig = {
248
+ access: "public"
249
+ };
250
+ const packageJson = {
251
+ name: name,
252
+ version: version,
253
+ license: license,
254
+ repository: repository,
255
+ exports: exports$1,
256
+ main: main,
257
+ types: types,
258
+ files: files,
259
+ scripts: scripts,
260
+ dependencies: dependencies,
261
+ devDependencies: devDependencies,
262
+ peerDependencies: peerDependencies,
263
+ publishConfig: publishConfig
264
+ };
265
+
203
266
  var __defProp = Object.defineProperty;
204
267
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
205
268
  var __publicField = (obj, key, value) => {
@@ -212,6 +275,7 @@ function removeVaultPrefix(url) {
212
275
  }
213
276
  async function wrappedFetch(...params) {
214
277
  const request = new Request(...params);
278
+ request.headers.set("User-Agent", `vault-js-sdk:${packageJson.version}`);
215
279
  const response = await fetch(request);
216
280
  if (!response.ok) {
217
281
  throw await FetchError.from(request.url, request.method, response);
@@ -253,7 +317,9 @@ class VaultFile {
253
317
  * @returns The headers for the request
254
318
  */
255
319
  get headers() {
256
- return this.config.authStrategy.getHeaders();
320
+ const headers = this.config.authStrategy.getHeaders();
321
+ headers.set("User-Agent", `vault-js-sdk:${packageJson.version}`);
322
+ return headers;
257
323
  }
258
324
  /**
259
325
  * Performs a request to the vault service and handles the response or errors.
@@ -679,6 +745,79 @@ class VaultFile {
679
745
  }
680
746
  }
681
747
 
748
+ function isS3UrlExpired(url) {
749
+ try {
750
+ const urlObj = new URL(url);
751
+ const amzDate = urlObj.searchParams.get("X-Amz-Date");
752
+ const amzExpires = urlObj.searchParams.get("X-Amz-Expires");
753
+ if (!amzDate || !amzExpires)
754
+ return false;
755
+ const year = Number.parseInt(amzDate.substring(0, 4));
756
+ const month = Number.parseInt(amzDate.substring(4, 6)) - 1;
757
+ const day = Number.parseInt(amzDate.substring(6, 8));
758
+ const hours = Number.parseInt(amzDate.substring(9, 11));
759
+ const minutes = Number.parseInt(amzDate.substring(11, 13));
760
+ const seconds = Number.parseInt(amzDate.substring(13, 15));
761
+ const signedDate = new Date(Date.UTC(year, month, day, hours, minutes, seconds));
762
+ const expiresInSeconds = Number.parseInt(amzExpires);
763
+ const expirationTime = signedDate.getTime() + expiresInSeconds * 1e3;
764
+ const currentTime = Date.now();
765
+ return currentTime > expirationTime;
766
+ } catch {
767
+ return false;
768
+ }
769
+ }
770
+ function isVaultReference(url) {
771
+ return url.startsWith("vault://") && url.length === 10;
772
+ }
773
+ function isVaultFileS3Url(url) {
774
+ const urlObj = new URL(url);
775
+ const amzDate = urlObj.searchParams.get("X-Amz-Date");
776
+ const amzExpires = urlObj.searchParams.get("X-Amz-Expires");
777
+ return urlObj.hostname.includes("amazonaws.com") && Boolean(amzDate) && Boolean(amzExpires);
778
+ }
779
+ const URL_STRATEGIES = [
780
+ {
781
+ separator: "/",
782
+ extractSegments: ([workspaceId, vaultFileId]) => ({
783
+ workspaceId,
784
+ vaultFileId
785
+ })
786
+ },
787
+ {
788
+ separator: "_",
789
+ extractSegments: ([vaultFileId, workspaceId]) => ({
790
+ vaultFileId,
791
+ workspaceId
792
+ })
793
+ }
794
+ ];
795
+ function extractVaultFileIdFromS3Url(url) {
796
+ if (isVaultReference(url))
797
+ return url.replace("vault://", "");
798
+ try {
799
+ if (!isVaultFileS3Url(url))
800
+ return null;
801
+ const urlObj = new URL(url);
802
+ const strategy = URL_STRATEGIES.find((strategy2) => urlObj.pathname.includes(strategy2.separator));
803
+ if (!strategy)
804
+ return null;
805
+ const segments = urlObj.pathname.split(strategy.separator).filter((segment) => segment.length > 0);
806
+ if (segments.length < 2)
807
+ return null;
808
+ const extractedIds = strategy.extractSegments(segments);
809
+ if (!extractedIds || !extractedIds.vaultFileId || !extractedIds.workspaceId || extractedIds.vaultFileId.length < 32)
810
+ return null;
811
+ return extractedIds.vaultFileId;
812
+ } catch {
813
+ return null;
814
+ }
815
+ }
816
+ function convertS3UrlToVaultReference(url) {
817
+ const vaultFileId = extractVaultFileIdFromS3Url(url);
818
+ return vaultFileId ? `vault://${vaultFileId}` : null;
819
+ }
820
+
682
821
  function vaultClient(vaultConfig) {
683
822
  const config = resolveConfig(vaultConfig);
684
823
  function createFromContent(name, content, options) {
@@ -701,4 +840,8 @@ exports.APIKeyAuthStrategy = APIKeyAuthStrategy;
701
840
  exports.DataTokenAuthStrategy = DataTokenAuthStrategy;
702
841
  exports.FetchError = FetchError;
703
842
  exports.VaultFile = VaultFile;
843
+ exports.convertS3UrlToVaultReference = convertS3UrlToVaultReference;
844
+ exports.extractVaultFileIdFromS3Url = extractVaultFileIdFromS3Url;
845
+ exports.isS3UrlExpired = isS3UrlExpired;
846
+ exports.isVaultFileS3Url = isVaultFileS3Url;
704
847
  exports.vaultClient = vaultClient;
package/dist/index.d.cts CHANGED
@@ -399,6 +399,36 @@ declare class VaultFile {
399
399
  }): Promise<Permalink[]>;
400
400
  }
401
401
 
402
+ /**
403
+ * Checks if an Amazon S3 signed URL has expired
404
+ * @param url - The S3 URL to check for expiration
405
+ * @returns true if the URL is expired, false if it's still valid or not an S3 signed URL
406
+ * @example
407
+ * const expired = isS3UrlExpired('https://vault-prod.s3.amazonaws.com/file?X-Amz-Date=20240101T000000Z&X-Amz-Expires=3600')
408
+ */
409
+ declare function isS3UrlExpired(url: string): boolean;
410
+ /**
411
+ * Checks if a URL is a valid S3 vault URL
412
+ * @param url - The S3 URL to check
413
+ * @returns true if the URL is a valid S3 vault URL, false otherwise
414
+ */
415
+ declare function isVaultFileS3Url(url: string): boolean;
416
+ /**
417
+ * Detects if a URL is an expired S3 vault URL and extracts the vault file ID
418
+ * Returns null if not a vault S3 URL, not expired, or extraction fails
419
+ */
420
+ declare function extractVaultFileIdFromS3Url(url: string): string | null;
421
+ /**
422
+ * Converts an S3 vault URL to a vault reference format
423
+ * Extracts the vault file ID from the S3 URL path and formats it as vault://[fileId]
424
+ * @param url - The S3 vault URL to convert
425
+ * @returns A vault reference string (vault://[fileId]) if successful, null if the URL is not a valid vault S3 URL
426
+ * @example
427
+ * const ref = convertS3UrlToVaultReference('https://vault-prod.s3.amazonaws.com/workspace123/2fce574083da49fe3f10b32205893ec0bb024fe1c7673fa54927fdfe1d0db9d6?...')
428
+ * // Returns: 'vault://2fce574083da49fe3f10b32205893ec0bb024fe1c7673fa54927fdfe1d0db9d6'
429
+ */
430
+ declare function convertS3UrlToVaultReference(url: string): string | null;
431
+
402
432
  declare function vaultClient(vaultConfig: VaultConfig): {
403
433
  createFromContent: (name: string, content: Blob | File, options?: {
404
434
  signal?: AbortSignal;
@@ -408,5 +438,5 @@ declare function vaultClient(vaultConfig: VaultConfig): {
408
438
  }) => Promise<VaultFile>;
409
439
  };
410
440
 
411
- export { APIKeyAuthStrategy, DataTokenAuthStrategy, FetchError, VaultFile, vaultClient };
441
+ export { APIKeyAuthStrategy, DataTokenAuthStrategy, FetchError, VaultFile, convertS3UrlToVaultReference, extractVaultFileIdFromS3Url, isS3UrlExpired, isVaultFileS3Url, vaultClient };
412
442
  export type { AuthStrategy, VaultConfig };
package/dist/index.d.mts CHANGED
@@ -399,6 +399,36 @@ declare class VaultFile {
399
399
  }): Promise<Permalink[]>;
400
400
  }
401
401
 
402
+ /**
403
+ * Checks if an Amazon S3 signed URL has expired
404
+ * @param url - The S3 URL to check for expiration
405
+ * @returns true if the URL is expired, false if it's still valid or not an S3 signed URL
406
+ * @example
407
+ * const expired = isS3UrlExpired('https://vault-prod.s3.amazonaws.com/file?X-Amz-Date=20240101T000000Z&X-Amz-Expires=3600')
408
+ */
409
+ declare function isS3UrlExpired(url: string): boolean;
410
+ /**
411
+ * Checks if a URL is a valid S3 vault URL
412
+ * @param url - The S3 URL to check
413
+ * @returns true if the URL is a valid S3 vault URL, false otherwise
414
+ */
415
+ declare function isVaultFileS3Url(url: string): boolean;
416
+ /**
417
+ * Detects if a URL is an expired S3 vault URL and extracts the vault file ID
418
+ * Returns null if not a vault S3 URL, not expired, or extraction fails
419
+ */
420
+ declare function extractVaultFileIdFromS3Url(url: string): string | null;
421
+ /**
422
+ * Converts an S3 vault URL to a vault reference format
423
+ * Extracts the vault file ID from the S3 URL path and formats it as vault://[fileId]
424
+ * @param url - The S3 vault URL to convert
425
+ * @returns A vault reference string (vault://[fileId]) if successful, null if the URL is not a valid vault S3 URL
426
+ * @example
427
+ * const ref = convertS3UrlToVaultReference('https://vault-prod.s3.amazonaws.com/workspace123/2fce574083da49fe3f10b32205893ec0bb024fe1c7673fa54927fdfe1d0db9d6?...')
428
+ * // Returns: 'vault://2fce574083da49fe3f10b32205893ec0bb024fe1c7673fa54927fdfe1d0db9d6'
429
+ */
430
+ declare function convertS3UrlToVaultReference(url: string): string | null;
431
+
402
432
  declare function vaultClient(vaultConfig: VaultConfig): {
403
433
  createFromContent: (name: string, content: Blob | File, options?: {
404
434
  signal?: AbortSignal;
@@ -408,5 +438,5 @@ declare function vaultClient(vaultConfig: VaultConfig): {
408
438
  }) => Promise<VaultFile>;
409
439
  };
410
440
 
411
- export { APIKeyAuthStrategy, DataTokenAuthStrategy, FetchError, VaultFile, vaultClient };
441
+ export { APIKeyAuthStrategy, DataTokenAuthStrategy, FetchError, VaultFile, convertS3UrlToVaultReference, extractVaultFileIdFromS3Url, isS3UrlExpired, isVaultFileS3Url, vaultClient };
412
442
  export type { AuthStrategy, VaultConfig };
package/dist/index.d.ts CHANGED
@@ -399,6 +399,36 @@ declare class VaultFile {
399
399
  }): Promise<Permalink[]>;
400
400
  }
401
401
 
402
+ /**
403
+ * Checks if an Amazon S3 signed URL has expired
404
+ * @param url - The S3 URL to check for expiration
405
+ * @returns true if the URL is expired, false if it's still valid or not an S3 signed URL
406
+ * @example
407
+ * const expired = isS3UrlExpired('https://vault-prod.s3.amazonaws.com/file?X-Amz-Date=20240101T000000Z&X-Amz-Expires=3600')
408
+ */
409
+ declare function isS3UrlExpired(url: string): boolean;
410
+ /**
411
+ * Checks if a URL is a valid S3 vault URL
412
+ * @param url - The S3 URL to check
413
+ * @returns true if the URL is a valid S3 vault URL, false otherwise
414
+ */
415
+ declare function isVaultFileS3Url(url: string): boolean;
416
+ /**
417
+ * Detects if a URL is an expired S3 vault URL and extracts the vault file ID
418
+ * Returns null if not a vault S3 URL, not expired, or extraction fails
419
+ */
420
+ declare function extractVaultFileIdFromS3Url(url: string): string | null;
421
+ /**
422
+ * Converts an S3 vault URL to a vault reference format
423
+ * Extracts the vault file ID from the S3 URL path and formats it as vault://[fileId]
424
+ * @param url - The S3 vault URL to convert
425
+ * @returns A vault reference string (vault://[fileId]) if successful, null if the URL is not a valid vault S3 URL
426
+ * @example
427
+ * const ref = convertS3UrlToVaultReference('https://vault-prod.s3.amazonaws.com/workspace123/2fce574083da49fe3f10b32205893ec0bb024fe1c7673fa54927fdfe1d0db9d6?...')
428
+ * // Returns: 'vault://2fce574083da49fe3f10b32205893ec0bb024fe1c7673fa54927fdfe1d0db9d6'
429
+ */
430
+ declare function convertS3UrlToVaultReference(url: string): string | null;
431
+
402
432
  declare function vaultClient(vaultConfig: VaultConfig): {
403
433
  createFromContent: (name: string, content: Blob | File, options?: {
404
434
  signal?: AbortSignal;
@@ -408,5 +438,5 @@ declare function vaultClient(vaultConfig: VaultConfig): {
408
438
  }) => Promise<VaultFile>;
409
439
  };
410
440
 
411
- export { APIKeyAuthStrategy, DataTokenAuthStrategy, FetchError, VaultFile, vaultClient };
441
+ export { APIKeyAuthStrategy, DataTokenAuthStrategy, FetchError, VaultFile, convertS3UrlToVaultReference, extractVaultFileIdFromS3Url, isS3UrlExpired, isVaultFileS3Url, vaultClient };
412
442
  export type { AuthStrategy, VaultConfig };
package/dist/index.mjs CHANGED
@@ -198,6 +198,69 @@ async function detectFileMimeType(blob) {
198
198
  return void 0;
199
199
  }
200
200
 
201
+ const name = "@meistrari/vault-sdk";
202
+ const version = "1.5.0";
203
+ const license = "UNLICENSED";
204
+ const repository = {
205
+ type: "git",
206
+ url: "https://github.com/meistrari/vault.git"
207
+ };
208
+ const exports = {
209
+ ".": {
210
+ types: "./dist/index.d.ts",
211
+ "import": "./dist/index.mjs",
212
+ require: "./dist/index.cjs"
213
+ }
214
+ };
215
+ const main = "dist/index.mjs";
216
+ const types = "dist/index.d.ts";
217
+ const files = [
218
+ "dist"
219
+ ];
220
+ const scripts = {
221
+ test: "vitest --no-watch",
222
+ "test:watch": "vitest",
223
+ build: "unbuild",
224
+ lint: "eslint .",
225
+ "lint:fix": "eslint . --fix",
226
+ check: "bun run lint && bun tsc --noEmit"
227
+ };
228
+ const dependencies = {
229
+ "@meistrari/vault-shared": "workspace:*",
230
+ "file-type": "21.0.0",
231
+ "mime-types": "3.0.1",
232
+ ofetch: "1.4.1",
233
+ zod: "3.23.8"
234
+ };
235
+ const devDependencies = {
236
+ "@types/bun": "latest",
237
+ "@types/mime-types": "3.0.1",
238
+ msw: "2.6.8",
239
+ unbuild: "2.0.0",
240
+ vitest: "2.1.9"
241
+ };
242
+ const peerDependencies = {
243
+ typescript: "^5.0.0"
244
+ };
245
+ const publishConfig = {
246
+ access: "public"
247
+ };
248
+ const packageJson = {
249
+ name: name,
250
+ version: version,
251
+ license: license,
252
+ repository: repository,
253
+ exports: exports,
254
+ main: main,
255
+ types: types,
256
+ files: files,
257
+ scripts: scripts,
258
+ dependencies: dependencies,
259
+ devDependencies: devDependencies,
260
+ peerDependencies: peerDependencies,
261
+ publishConfig: publishConfig
262
+ };
263
+
201
264
  var __defProp = Object.defineProperty;
202
265
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
203
266
  var __publicField = (obj, key, value) => {
@@ -210,6 +273,7 @@ function removeVaultPrefix(url) {
210
273
  }
211
274
  async function wrappedFetch(...params) {
212
275
  const request = new Request(...params);
276
+ request.headers.set("User-Agent", `vault-js-sdk:${packageJson.version}`);
213
277
  const response = await fetch(request);
214
278
  if (!response.ok) {
215
279
  throw await FetchError.from(request.url, request.method, response);
@@ -251,7 +315,9 @@ class VaultFile {
251
315
  * @returns The headers for the request
252
316
  */
253
317
  get headers() {
254
- return this.config.authStrategy.getHeaders();
318
+ const headers = this.config.authStrategy.getHeaders();
319
+ headers.set("User-Agent", `vault-js-sdk:${packageJson.version}`);
320
+ return headers;
255
321
  }
256
322
  /**
257
323
  * Performs a request to the vault service and handles the response or errors.
@@ -677,6 +743,79 @@ class VaultFile {
677
743
  }
678
744
  }
679
745
 
746
+ function isS3UrlExpired(url) {
747
+ try {
748
+ const urlObj = new URL(url);
749
+ const amzDate = urlObj.searchParams.get("X-Amz-Date");
750
+ const amzExpires = urlObj.searchParams.get("X-Amz-Expires");
751
+ if (!amzDate || !amzExpires)
752
+ return false;
753
+ const year = Number.parseInt(amzDate.substring(0, 4));
754
+ const month = Number.parseInt(amzDate.substring(4, 6)) - 1;
755
+ const day = Number.parseInt(amzDate.substring(6, 8));
756
+ const hours = Number.parseInt(amzDate.substring(9, 11));
757
+ const minutes = Number.parseInt(amzDate.substring(11, 13));
758
+ const seconds = Number.parseInt(amzDate.substring(13, 15));
759
+ const signedDate = new Date(Date.UTC(year, month, day, hours, minutes, seconds));
760
+ const expiresInSeconds = Number.parseInt(amzExpires);
761
+ const expirationTime = signedDate.getTime() + expiresInSeconds * 1e3;
762
+ const currentTime = Date.now();
763
+ return currentTime > expirationTime;
764
+ } catch {
765
+ return false;
766
+ }
767
+ }
768
+ function isVaultReference(url) {
769
+ return url.startsWith("vault://") && url.length === 10;
770
+ }
771
+ function isVaultFileS3Url(url) {
772
+ const urlObj = new URL(url);
773
+ const amzDate = urlObj.searchParams.get("X-Amz-Date");
774
+ const amzExpires = urlObj.searchParams.get("X-Amz-Expires");
775
+ return urlObj.hostname.includes("amazonaws.com") && Boolean(amzDate) && Boolean(amzExpires);
776
+ }
777
+ const URL_STRATEGIES = [
778
+ {
779
+ separator: "/",
780
+ extractSegments: ([workspaceId, vaultFileId]) => ({
781
+ workspaceId,
782
+ vaultFileId
783
+ })
784
+ },
785
+ {
786
+ separator: "_",
787
+ extractSegments: ([vaultFileId, workspaceId]) => ({
788
+ vaultFileId,
789
+ workspaceId
790
+ })
791
+ }
792
+ ];
793
+ function extractVaultFileIdFromS3Url(url) {
794
+ if (isVaultReference(url))
795
+ return url.replace("vault://", "");
796
+ try {
797
+ if (!isVaultFileS3Url(url))
798
+ return null;
799
+ const urlObj = new URL(url);
800
+ const strategy = URL_STRATEGIES.find((strategy2) => urlObj.pathname.includes(strategy2.separator));
801
+ if (!strategy)
802
+ return null;
803
+ const segments = urlObj.pathname.split(strategy.separator).filter((segment) => segment.length > 0);
804
+ if (segments.length < 2)
805
+ return null;
806
+ const extractedIds = strategy.extractSegments(segments);
807
+ if (!extractedIds || !extractedIds.vaultFileId || !extractedIds.workspaceId || extractedIds.vaultFileId.length < 32)
808
+ return null;
809
+ return extractedIds.vaultFileId;
810
+ } catch {
811
+ return null;
812
+ }
813
+ }
814
+ function convertS3UrlToVaultReference(url) {
815
+ const vaultFileId = extractVaultFileIdFromS3Url(url);
816
+ return vaultFileId ? `vault://${vaultFileId}` : null;
817
+ }
818
+
680
819
  function vaultClient(vaultConfig) {
681
820
  const config = resolveConfig(vaultConfig);
682
821
  function createFromContent(name, content, options) {
@@ -695,4 +834,4 @@ function vaultClient(vaultConfig) {
695
834
  return { createFromContent, createFromReference };
696
835
  }
697
836
 
698
- export { APIKeyAuthStrategy, DataTokenAuthStrategy, FetchError, VaultFile, vaultClient };
837
+ export { APIKeyAuthStrategy, DataTokenAuthStrategy, FetchError, VaultFile, convertS3UrlToVaultReference, extractVaultFileIdFromS3Url, isS3UrlExpired, isVaultFileS3Url, vaultClient };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meistrari/vault-sdk",
3
- "version": "1.4.3",
3
+ "version": "1.5.0",
4
4
  "license": "UNLICENSED",
5
5
  "repository": {
6
6
  "type": "git",