@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 +102 -41
- package/dist/index.cjs +330 -79
- package/dist/index.d.cts +219 -42
- package/dist/index.d.mts +219 -42
- package/dist/index.d.ts +219 -42
- package/dist/index.mjs +330 -79
- package/package.json +14 -12
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
|
|
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
|
-
|
|
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
|
-
|
|
20
|
-
|
|
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
|
-
|
|
23
|
-
const localFile = Bun.file('path/to/local/file.txt')
|
|
55
|
+
Here's an example showing the complete flow:
|
|
24
56
|
|
|
25
|
-
|
|
57
|
+
```ts
|
|
58
|
+
import { VaultFile, DataTokenAuthStrategy } from '@meistrari/vault-sdk'
|
|
26
59
|
|
|
27
|
-
const
|
|
60
|
+
const dataToken = '[some-data-token]'
|
|
61
|
+
const vaultUrl = Bun.env.VAULT_URL ?? 'https://vault.tela.com'
|
|
28
62
|
|
|
29
|
-
|
|
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
|
-
###
|
|
96
|
+
### Using the useVault helper
|
|
33
97
|
|
|
34
|
-
|
|
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
|
-
|
|
44
|
-
const
|
|
106
|
+
// Create a vault instance
|
|
107
|
+
const vault = useVault({
|
|
108
|
+
vaultUrl,
|
|
109
|
+
authStrategy: new DataTokenAuthStrategy(dataToken)
|
|
110
|
+
})
|
|
45
111
|
|
|
46
|
-
|
|
112
|
+
// Create a file from content
|
|
113
|
+
const fileFromContent = vault.createFromContent(
|
|
114
|
+
'document.txt',
|
|
115
|
+
new File(['content'], 'document.txt')
|
|
116
|
+
)
|
|
47
117
|
|
|
48
|
-
|
|
118
|
+
// Create a file from a vault reference
|
|
119
|
+
const fileFromReference = vault.createFromReference('vault://1234567890')
|
|
120
|
+
```
|
|
49
121
|
|
|
50
|
-
|
|
122
|
+
The `useVault` helper provides two methods:
|
|
51
123
|
|
|
52
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
35
|
-
|
|
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, "
|
|
38
|
-
this
|
|
39
|
-
this
|
|
40
|
-
this
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
|
70
|
-
const url = new URL(this.vaultUrl + path).toString();
|
|
71
|
-
const
|
|
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
|
|
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
|
-
*
|
|
84
|
-
*
|
|
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
|
|
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
|
-
*
|
|
89
|
-
*
|
|
90
|
-
* the file
|
|
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
|
|
95
|
-
*
|
|
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
|
-
* @
|
|
98
|
-
* @
|
|
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
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
this.name =
|
|
104
|
-
|
|
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
|
-
*
|
|
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
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
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
|
|
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
|
-
|
|
125
|
-
|
|
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
|
|
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
|
|
178
|
-
function
|
|
179
|
-
return
|
|
422
|
+
function vaultClient(config) {
|
|
423
|
+
function createFromContent(name, content) {
|
|
424
|
+
return VaultFile.fromContent({
|
|
180
425
|
name,
|
|
181
|
-
|
|
182
|
-
|
|
426
|
+
content,
|
|
427
|
+
config
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
function createFromReference(reference) {
|
|
431
|
+
return VaultFile.fromVaultReference({
|
|
432
|
+
reference,
|
|
433
|
+
config
|
|
183
434
|
});
|
|
184
435
|
}
|
|
185
|
-
return {
|
|
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.
|
|
443
|
+
exports.vaultClient = vaultClient;
|