@meistrari/vault-sdk 0.0.13 → 1.0.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/README.md CHANGED
@@ -11,28 +11,91 @@ ni @meistrari/vault-sdk-sdk
11
11
  ## Usage
12
12
 
13
13
  The main component of the SDK is the `VaultFile` class.
14
- It accepts the vault url and an auth strategy, and provides methods to upload and download that file.
14
+ It provides methods to upload, download, and reference files in the vault.
15
+
16
+ ### Creating Files
17
+
18
+ To create a new file in the vault, use `VaultFile.fromContent`:
15
19
 
16
20
  ```ts
17
- import { VaultFile } from '@meistrari/vault-sdk'
21
+ const vaultFile = await VaultFile.fromContent({
22
+ name: 'document.txt', // Original filename
23
+ content: new File(['content'], 'document.txt'), // File content
24
+ config: {
25
+ vaultUrl,
26
+ authStrategy: new DataTokenAuthStrategy(dataToken)
27
+ },
28
+ upload: true // Optional: upload immediately
29
+ })
30
+ ```
18
31
 
19
- const dataToken = '[some-data-token]'
20
- const vaultUrl = Bun.env.VAULT_URL ?? 'https://vault.tela.com'
32
+ ### Retrieving Files
33
+
34
+ To retrieve a file using a vault reference, use `VaultFile.fromVaultReference`:
35
+
36
+ ```ts
37
+ const vaultFile = await VaultFile.fromVaultReference({
38
+ reference: 'vault://1234567890', // The vault reference
39
+ config: {
40
+ vaultUrl,
41
+ authStrategy: new DataTokenAuthStrategy(dataToken)
42
+ },
43
+ download: false // Optional: download immediately if true
44
+ })
45
+ ```
46
+
47
+ ## Basic Usage Flow
48
+
49
+ The typical workflow with the SDK involves:
50
+
51
+ 1. Creating a file in the vault using `VaultFile.fromContent`
52
+ 2. Getting a reference to that file with `getVaultReference()`
53
+ 3. Later, retrieving the file using `VaultFile.fromVaultReference`
21
54
 
22
- const vaultFile = new VaultFile('file.txt', vaultUrl, new DataTokenAuthStrategy(dataToken))
23
- const localFile = Bun.file('path/to/local/file.txt')
55
+ Here's an example showing the complete flow:
24
56
 
25
- await vaultFile.upload(localFile)
57
+ ```ts
58
+ import { VaultFile, DataTokenAuthStrategy } from '@meistrari/vault-sdk'
26
59
 
27
- const downloadedFile = await vaultFile.download()
60
+ const dataToken = '[some-data-token]'
61
+ const vaultUrl = Bun.env.VAULT_URL ?? 'https://vault.tela.com'
28
62
 
29
- console.log(downloadedFile)
63
+ // Step 1: Create and upload a new file
64
+ const fileContent = Bun.file('path/to/local/file.txt')
65
+ const vaultFile = await VaultFile.fromContent({
66
+ name: 'file.txt',
67
+ content: fileContent,
68
+ config: {
69
+ vaultUrl,
70
+ authStrategy: new DataTokenAuthStrategy(dataToken)
71
+ },
72
+ upload: true // Upload immediately
73
+ })
74
+
75
+ // Step 2: Get a reference to store in your database or application
76
+ const vaultReference = vaultFile.getVaultReference() // e.g. 'vault://1234567890'
77
+ console.log(`Store this reference: ${vaultReference}`)
78
+
79
+ // ... Later, in another part of your application ...
80
+
81
+ // Step 3: Retrieve the file using the reference
82
+ const retrievedFile = await VaultFile.fromVaultReference({
83
+ reference: vaultReference,
84
+ config: {
85
+ vaultUrl,
86
+ authStrategy: new DataTokenAuthStrategy(dataToken)
87
+ },
88
+ download: false // Set to true to download immediately
89
+ })
90
+
91
+ // Step 4: Download the content when needed
92
+ const fileContent = await retrievedFile.download()
93
+ console.log(fileContent)
30
94
  ```
31
95
 
32
- ### The `useVault` function
96
+ ### Using the useVault helper
33
97
 
34
- In order to simplify the creation of multiple `VaultFile` instances, the `useVault` function is exported.
35
- It takes the vault url and an auth strategy, and returns a function that creates a `VaultFile` instance using those parameters.
98
+ The SDK provides a convenient `useVault` helper function that simplifies creating vault files:
36
99
 
37
100
  ```ts
38
101
  import { useVault, DataTokenAuthStrategy } from '@meistrari/vault-sdk'
@@ -40,17 +103,28 @@ import { useVault, DataTokenAuthStrategy } from '@meistrari/vault-sdk'
40
103
  const dataToken = '[some-data-token]'
41
104
  const vaultUrl = Bun.env.VAULT_URL ?? 'https://vault.tela.com'
42
105
 
43
- const { createVaultFile } = useVault(vaultUrl, new DataTokenAuthStrategy(dataToken))
44
- const vaultFile = createVaultFile('test.txt')
106
+ // Create a vault instance
107
+ const vault = useVault({
108
+ vaultUrl,
109
+ authStrategy: new DataTokenAuthStrategy(dataToken)
110
+ })
45
111
 
46
- const localFile = Bun.file('./package.json')
112
+ // Create a file from content
113
+ const fileFromContent = vault.createFromContent(
114
+ 'document.txt',
115
+ new File(['content'], 'document.txt')
116
+ )
47
117
 
48
- await vaultFile.upload(localFile)
118
+ // Create a file from a vault reference
119
+ const fileFromReference = vault.createFromReference('vault://1234567890')
120
+ ```
49
121
 
50
- const downloadedFile = await vaultFile.download()
122
+ The `useVault` helper provides two methods:
51
123
 
52
- console.log(downloadedFile)
53
- ```
124
+ - `createFromContent(name, content)`: Creates a new `VaultFile` instance from a name and content (Blob or File)
125
+ - `createFromReference(reference)`: Creates a new `VaultFile` instance from a vault reference string
126
+
127
+ This helper makes it more convenient to work with multiple vault files using the same configuration.
54
128
 
55
129
  ### Auth strategies
56
130
 
@@ -72,9 +146,16 @@ const authStrategy = new DataTokenAuthStrategy(dataToken)
72
146
  #### APIKeyAuthStrategy
73
147
 
74
148
  It takes an API key, and passes it as the `Authorization` header in requests to the vault.
75
- Use this when performing external calls to the vault, such as from the frontend.
149
+ Use this when performing external calls **through the API Gateway**, such as from the frontend.
76
150
  Since the clerk token is also passed as the `Authorization` header, this strategy can also be used with the value of the `__session` cookie instead of an API key.
77
- For vault, there's no real difference between using an API key and the clerk token, since it only needs the workspace ID, and that's provided by both types of credentials.
151
+
152
+ > [!WARNING]
153
+ > The vault service itself does not support API Keys, it only understands data tokens.
154
+ > To use this strategy, the request **must** go through the API Gateway.
155
+ > For that, the gateway URL should be used instead of the vault service URL.
156
+ >
157
+ > Use this: `https://staging.api.tela.com/_services/vault`.<br>
158
+ > Instead of this: `https://vault.tela.com`
78
159
 
79
160
  ```ts
80
161
  import { APIKeyAuthStrategy } from '@meistrari/vault-sdk'
@@ -83,23 +164,3 @@ const apiKey = '[some-api-key]'
83
164
 
84
165
  const authStrategy = new APIKeyAuthStrategy(apiKey)
85
166
  ```
86
-
87
- ### Retrieving files with a vault ref
88
-
89
- Both the `VaultFile` class and the `createVaultFile` function accept a vault ref as the name of the file.
90
- The vault ref is a string with the form `vault://file-name.ext`.
91
- The workspace ID is obtained from the authentication data, and doesn't need to be explicitly passed.
92
-
93
- ```ts
94
- import { useVault, DataTokenAuthStrategy } from '@meistrari/vault-sdk'
95
-
96
- const dataToken = '[some-data-token]'
97
- const vaultUrl = Bun.env.VAULT_URL ?? 'https://vault.tela.com'
98
-
99
- const { createVaultFile } = useVault(vaultUrl, new DataTokenAuthStrategy(dataToken))
100
- const vaultFile = createVaultFile('vault://file-name.ext')
101
-
102
- const downloadedFile = await vaultFile.download()
103
-
104
- console.log(downloadedFile)
105
- ```
package/dist/index.cjs CHANGED
@@ -1,11 +1,22 @@
1
1
  'use strict';
2
2
 
3
+ const schemas = require('@meistrari/vault-shared/schemas');
4
+
3
5
  class FetchError extends Error {
4
- constructor(message, response) {
6
+ constructor(message, url, method, response) {
5
7
  super(message);
8
+ this.message = message;
9
+ this.url = url;
10
+ this.method = method;
6
11
  this.response = response;
7
12
  this.name = "FetchError";
8
13
  }
14
+ static async from(url, method, response) {
15
+ const text = await response.clone().json().then((json) => JSON.stringify(json, null, 2)).catch(() => response.clone().text());
16
+ const error = new FetchError(`Failed to ${method} ${url}: ${response.status} ${response.statusText}:
17
+ ${text}`, url, method, response);
18
+ return error;
19
+ }
9
20
  }
10
21
 
11
22
  async function blobToBase64(blob) {
@@ -30,114 +41,348 @@ var __publicField$1 = (obj, key, value) => {
30
41
  __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
31
42
  return value;
32
43
  };
44
+ const compatibilityDate = "2025-05-19";
45
+ function removeVaultPrefix(url) {
46
+ return url.replace("vault://", "");
47
+ }
48
+ async function wrappedFetch(...params) {
49
+ const request = new Request(...params);
50
+ const response = await fetch(request);
51
+ if (!response.ok) {
52
+ throw await FetchError.from(request.url, request.method, response);
53
+ }
54
+ return response;
55
+ }
33
56
  class VaultFile {
34
- constructor(params) {
35
- __publicField$1(this, "vaultUrl");
57
+ /**
58
+ * Constructs a new VaultFile instance. Direct usage of the constructor is not recommended,
59
+ * instead use the static methods {@link VaultFile.fromVaultReference} when dealing with an existing file in the vault,
60
+ * or {@link VaultFile.fromContent} when preparing a new file for upload.
61
+ *
62
+ * @param params - The parameters for the VaultFile constructor
63
+ * @param params.config - The configuration for the VaultFile
64
+ * @param params.content - The content of the file
65
+ * @param params.id - The ID of the file
66
+ * @param params.name - The name of the file
67
+ * @param params.metadata - The metadata of the file
68
+ */
69
+ constructor({ config, content, id, name, metadata }) {
70
+ __publicField$1(this, "id");
36
71
  __publicField$1(this, "name");
37
- __publicField$1(this, "headers");
38
- this.name = params.name;
39
- this.vaultUrl = params.vaultUrl;
40
- this.headers = params.authStrategy.getHeaders();
41
- }
42
- getVaultUrl() {
43
- if (this.name.includes("vault://")) {
44
- return this.name;
45
- }
46
- return `vault://${this.name}`;
72
+ __publicField$1(this, "metadata");
73
+ __publicField$1(this, "config");
74
+ __publicField$1(this, "content");
75
+ __publicField$1(this, "lastDownloadUrl");
76
+ __publicField$1(this, "lastUploadUrl");
77
+ this.config = config;
78
+ this.content = content;
79
+ this.id = id;
80
+ this.name = name;
81
+ this.metadata = metadata;
47
82
  }
48
- removeVaultPrefix(url) {
49
- return url.replace("vault://", "");
50
- }
51
- async getUploadUrl() {
52
- const response = await this._fetch({
53
- method: "POST",
54
- path: `/v2/files/${this.removeVaultPrefix(this.name)}`
55
- });
56
- return new URL(response.url);
57
- }
58
- async getDownloadUrl() {
59
- const response = await this._fetch({
60
- method: "GET",
61
- path: `/v2/files/${this.removeVaultPrefix(this.name)}`
62
- });
63
- return new URL(response.url);
64
- }
65
- refreshAuth(authStrategy) {
66
- this.headers = authStrategy.getHeaders();
83
+ /**
84
+ * Gets the headers for the request based on the auth strategy.
85
+ *
86
+ * @returns The headers for the request
87
+ */
88
+ get headers() {
89
+ return this.config.authStrategy.getHeaders();
67
90
  }
91
+ /**
92
+ * Performs a request to the vault service and handles the response or errors.
93
+ *
94
+ * @param params - The parameters for the fetch
95
+ * @param params.method - The method to use for the fetch
96
+ * @param params.path - The path to fetch
97
+ * @param params.body - The body of the request
98
+ * @returns The response from the vault
99
+ * @throws {FetchError} If the fetch fails
100
+ */
68
101
  async _fetch(params) {
69
- const { method, path, body, ignoreHeaders } = params;
70
- const url = new URL(this.vaultUrl + path).toString();
71
- const response = await fetch(url, {
102
+ const { method, path, body } = params;
103
+ const url = new URL(this.config.vaultUrl + path).toString();
104
+ const headers = new Headers(this.headers);
105
+ headers.set("x-compatibility-date", compatibilityDate);
106
+ const response = await wrappedFetch(url, {
72
107
  method,
73
108
  body,
74
- headers: ignoreHeaders ? void 0 : this.headers
109
+ headers
75
110
  });
76
- if (!response.ok) {
77
- throw new FetchError(`Failed to ${method} ${url}: ${response.status} ${response.statusText}`, response);
78
- }
79
111
  const content = await response.json();
80
112
  return content;
81
113
  }
82
114
  /**
83
- * Adds a SHA-256 hash of the file content as a prefix to the filename. This ensures uniqueness and prevents
84
- * files with identical names but different content from overwriting each other in the vault.
115
+ * Creates a new file in the vault.
116
+ *
117
+ * @returns The metadata of the file
118
+ * @throws {Error} If the file ID is not set
119
+ * @throws {FetchError} If the metadata fetch fails
120
+ */
121
+ async _createFile() {
122
+ const response = await this._fetch({
123
+ method: "POST",
124
+ path: `/v2/files`,
125
+ body: JSON.stringify({
126
+ fileName: this.name,
127
+ sha256sum: this.id ?? this.metadata?.id ?? (this.content ? await getFileHash(this.content) : void 0)
128
+ })
129
+ }).then((data) => schemas.GetUploadUrlResponseV2.safeParse(data));
130
+ if (!response.success) {
131
+ throw new Error(`Invalid response from vault service. ${JSON.stringify(response.error)}`);
132
+ }
133
+ this.id = response.data.id;
134
+ this.metadata = response.data.metadata;
135
+ this.name = response.data.metadata?.originalFileName;
136
+ return response.data;
137
+ }
138
+ /**
139
+ * Creates a new VaultFile instance from a vault reference.
85
140
  *
86
- * The resulting filename format is: "{hash}-{originalName}"
141
+ * @param params - The parameters for creating a VaultFile from a vault reference
142
+ * @param params.reference - The reference to the file in the vault
143
+ * @param params.config - The configuration for the VaultFile
144
+ * @param params.download - Whether to download the file content (default: false)
145
+ * @returns A new VaultFile instance
87
146
  *
88
- * IMPORTANT: The modified filename must be stored and used for all future operations with this file in the vault,
89
- * as it becomes the file's unique identifier. The original filename alone will not be sufficient to retrieve
90
- * the file later.
147
+ * @example
148
+ * ```ts
149
+ * // Lazily download the file content
150
+ * const vaultFile = await VaultFile.fromVaultReference({
151
+ * reference: 'vault://1234567890',
152
+ * config: {
153
+ * vaultUrl,
154
+ * authStrategy,
155
+ * }
156
+ * })
157
+ * const content = await vaultFile.download()
158
+ * ```
159
+ *
160
+ * @example
161
+ * ```ts
162
+ * // Download the file content while creating the instance
163
+ * const vaultFile = await VaultFile.fromVaultReference({
164
+ * reference: 'vault://1234567890',
165
+ * config: {
166
+ * vaultUrl,
167
+ * authStrategy,
168
+ * },
169
+ * download: true
170
+ * })
171
+ * const content = vaultFile.content
172
+ * ```
173
+ */
174
+ static async fromVaultReference(params) {
175
+ const { reference, config, download = false } = params;
176
+ const { vaultUrl, authStrategy } = config;
177
+ const id = removeVaultPrefix(reference);
178
+ const response = await wrappedFetch(`${vaultUrl}/v2/files/${id}`, {
179
+ method: "GET",
180
+ headers: authStrategy.getHeaders()
181
+ }).then((response2) => response2.json()).then((data) => schemas.GetDownloadUrlResponse.safeParse(data));
182
+ if (!response.success) {
183
+ throw new Error("Invalid response from vault service");
184
+ }
185
+ const fileParams = {
186
+ id,
187
+ metadata: response.data.metadata,
188
+ config: {
189
+ vaultUrl,
190
+ authStrategy
191
+ },
192
+ name: response.data.metadata?.originalFileName
193
+ };
194
+ if (download) {
195
+ await wrappedFetch(response.data.url, { method: "GET" }).then((response2) => response2.blob()).then((blob) => fileParams.content = blob);
196
+ }
197
+ return new VaultFile(fileParams);
198
+ }
199
+ /**
200
+ * Creates a new VaultFile instance from given content.
201
+ *
202
+ * @param params - The parameters for creating a VaultFile from content
203
+ * @param params.name - The name of the file
204
+ * @param params.content - The content of the file
205
+ * @param params.config - The configuration for the VaultFile
206
+ * @param params.upload - Whether to upload the file (default: false)
207
+ * @returns A new VaultFile instance
208
+ *
209
+ * @example
210
+ * ```ts
211
+ * // Lazily upload the file content
212
+ * const file = new File(['content'], 'document.txt')
213
+ * const vaultFile = await VaultFile.fromContent({
214
+ * name: 'document.txt',
215
+ * content: file,
216
+ * config: {
217
+ * vaultUrl,
218
+ * authStrategy,
219
+ * }
220
+ * })
221
+ * await vaultFile.upload()
222
+ * ```
91
223
  *
92
224
  * @example
225
+ * ```ts
226
+ * // Upload the file content while creating the instance
93
227
  * const file = new File(['content'], 'document.txt')
94
- * await vaultFile.addHashToName(file)
95
- * // vaultFile.name becomes: "a1b2c3...xyz-document.txt"
228
+ * const vaultFile = await VaultFile.fromContent({
229
+ * name: 'document.txt',
230
+ * content: file,
231
+ * config: {
232
+ * vaultUrl,
233
+ * authStrategy,
234
+ * },
235
+ * upload: true
236
+ * })
237
+ * ```
238
+ */
239
+ static async fromContent(params) {
240
+ const { name, content, config, upload = false } = params;
241
+ const { vaultUrl, authStrategy } = config;
242
+ const sha256sum = await getFileHash(content);
243
+ const file = new VaultFile({
244
+ content,
245
+ config: {
246
+ vaultUrl,
247
+ authStrategy
248
+ },
249
+ id: sha256sum,
250
+ name
251
+ });
252
+ const createdFile = await file._createFile();
253
+ if (upload) {
254
+ await file.upload(file.content, createdFile.uploadUrl);
255
+ }
256
+ return file;
257
+ }
258
+ /**
259
+ * Populates the metadata of the file instance.
96
260
  *
97
- * @param file - The file to generate a hash for
98
- * @returns The new filename with the hash prefix
261
+ * @returns The file instance
262
+ * @throws {Error} If the file ID is not set
263
+ * @throws {FetchError} If the metadata fetch fails
99
264
  */
100
- async addHashToName(file) {
101
- const fileHash = await getFileHash(file);
102
- if (!this.name.includes(fileHash))
103
- this.name = `${fileHash}-${this.name}`;
104
- return this.name;
265
+ async populateMetadata() {
266
+ try {
267
+ this.metadata = await this.getFileMetadata();
268
+ this.name = this.metadata.originalFileName;
269
+ this.id = this.metadata.id;
270
+ return this;
271
+ } catch (error) {
272
+ console.error("Error fetching file metadata", error);
273
+ }
105
274
  }
106
275
  /**
107
- * Uploads a file to the vault.
276
+ * Gets the vault reference for this file.
277
+ *
278
+ * @returns The vault reference in the format `vault://{fileId}`
279
+ * @throws {Error} If the file ID is not set
280
+ */
281
+ getVaultReference() {
282
+ if (!this.id) {
283
+ throw new Error("File ID is not set");
284
+ }
285
+ return `vault://${this.id}`;
286
+ }
287
+ /**
288
+ * Fetches the metadata of the file.
289
+ *
290
+ * @returns The metadata of the file
291
+ * @throws {Error} If the file ID is not set
292
+ * @throws {FetchError} If the metadata fetch fails
293
+ */
294
+ async getFileMetadata() {
295
+ if (!this.id) {
296
+ throw new Error("File ID is not set");
297
+ }
298
+ const response = await this._fetch({
299
+ method: "GET",
300
+ path: `/v2/files/${this.id}/metadata`
301
+ });
302
+ return response;
303
+ }
304
+ /**
305
+ * Fetches a upload URL for the file.
306
+ *
307
+ * @returns The upload URL for the file
308
+ * @throws {Error} If the vault service returns an invalid response
309
+ * @throws {FetchError} If the upload URL fetch fails
310
+ */
311
+ async getUploadUrl() {
312
+ if (this.lastUploadUrl && this.lastUploadUrl.expiresAt > /* @__PURE__ */ new Date()) {
313
+ return this.lastUploadUrl.url;
314
+ }
315
+ if (!this.id) {
316
+ const createdFile = await this._createFile();
317
+ this.id = createdFile.id;
318
+ this.metadata = createdFile.metadata;
319
+ this.name = createdFile.metadata?.originalFileName;
320
+ this.lastUploadUrl = { url: new URL(createdFile.uploadUrl), expiresAt: new Date(createdFile.expiresAt) };
321
+ return this.lastUploadUrl.url;
322
+ }
323
+ const response = await this._fetch({
324
+ method: "PUT",
325
+ path: `/v2/files/${this.id}`
326
+ }).then(schemas.GetUploadUrlResponseV2.safeParse);
327
+ if (!response.success) {
328
+ throw new Error(`Invalid response from vault service. ${JSON.stringify(response.error)}`);
329
+ }
330
+ this.lastUploadUrl = { url: new URL(response.data.uploadUrl), expiresAt: new Date(response.data.expiresAt) };
331
+ return this.lastUploadUrl.url;
332
+ }
333
+ /**
334
+ * Fetches a download URL for the file.
108
335
  *
109
- * Files are saved with the given file names, so files with the same name within the same workspace
110
- * will overwrite each other. To prevent accidental overwrites and support multiple files with the
111
- * same original name, you should call addHashToName() before uploading to add a unique content-based
112
- * hash to the filename.
336
+ * @returns The download URL for the file
337
+ * @throws {Error} If the vault service returns an invalid response
338
+ * @throws {Error} If not file ID, name or content is set
339
+ * @throws {FetchError} If the download URL fetch fails
340
+ */
341
+ async getDownloadUrl() {
342
+ if (this.lastDownloadUrl && this.lastDownloadUrl.expiresAt > /* @__PURE__ */ new Date()) {
343
+ return this.lastDownloadUrl.url;
344
+ }
345
+ if (!this.id && !this.name && !this.content) {
346
+ throw new Error("File was not created yet");
347
+ }
348
+ const id = this.id ?? this.metadata?.id ?? (this.content ? await getFileHash(this.content) : this.name);
349
+ const response = await this._fetch({
350
+ method: "GET",
351
+ path: `/v2/files/${id}`
352
+ });
353
+ this.lastDownloadUrl = { url: new URL(response.url), expiresAt: new Date(response.expiresAt) };
354
+ return this.lastDownloadUrl.url;
355
+ }
356
+ /**
357
+ * Uploads a file to the vault.
113
358
  *
114
359
  * @example
360
+ * ```ts
115
361
  * const file = new File(['content'], 'document.txt')
116
- * await vaultFile.addHashToName(file) // Adds hash prefix to filename
362
+ * const vaultFile = await VaultFile.fromBlob('document.txt', file, { vaultUrl, authStrategy })
117
363
  * await vaultFile.upload(file)
364
+ * ```
118
365
  *
119
- * @param file - The file to upload to the vault
366
+ * @param file - The file to upload to the vault. If not provided, the file content will be taken from the `content` property.
120
367
  * @throws {FetchError} If the upload fails
368
+ * @throws {Error} If the file content is not set and no file is provided
121
369
  * @returns Promise that resolves when upload is complete
122
370
  */
123
- async upload(file) {
124
- const uploadUrl = await this.getUploadUrl();
125
- const response = await fetch(uploadUrl, {
371
+ async upload(file, url) {
372
+ if (!file && !this.content) {
373
+ throw new Error("Missing file content. Use fromBlob() to create a file with content, or provide a file to upload.");
374
+ }
375
+ const uploadUrl = url ?? await this.getUploadUrl();
376
+ await wrappedFetch(uploadUrl, {
126
377
  method: "PUT",
127
- body: file
378
+ body: file ?? this.content
128
379
  });
129
- if (!response.ok) {
130
- throw new FetchError(`Error uploading file ${this.name}: ${response.status} ${response.statusText}`, response);
131
- }
132
380
  }
133
381
  async download(responseType = "blob") {
134
382
  const downloadUrl = await this.getDownloadUrl();
135
- const response = await fetch(downloadUrl, {
383
+ const response = await wrappedFetch(downloadUrl, {
136
384
  method: "GET"
137
385
  });
138
- if (!response.ok) {
139
- throw new FetchError(`Error downloading file ${this.name}: ${response.status} ${response.statusText}`, response);
140
- }
141
386
  const blob = await response.blob();
142
387
  if (responseType === "blob")
143
388
  return blob;
@@ -174,19 +419,25 @@ class APIKeyAuthStrategy {
174
419
  }
175
420
  }
176
421
 
177
- function useVault(vaultUrl, authStrategy) {
178
- function createVaultFile(name) {
179
- return new VaultFile({
422
+ function vaultClient(config) {
423
+ function createFromContent(name, content) {
424
+ return VaultFile.fromContent({
180
425
  name,
181
- authStrategy,
182
- vaultUrl
426
+ content,
427
+ config
428
+ });
429
+ }
430
+ function createFromReference(reference) {
431
+ return VaultFile.fromVaultReference({
432
+ reference,
433
+ config
183
434
  });
184
435
  }
185
- return { createVaultFile };
436
+ return { createFromContent, createFromReference };
186
437
  }
187
438
 
188
439
  exports.APIKeyAuthStrategy = APIKeyAuthStrategy;
189
440
  exports.DataTokenAuthStrategy = DataTokenAuthStrategy;
190
441
  exports.FetchError = FetchError;
191
442
  exports.VaultFile = VaultFile;
192
- exports.useVault = useVault;
443
+ exports.vaultClient = vaultClient;