@meistrari/vault-sdk 3.2.0 → 3.3.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.mjs CHANGED
@@ -1,17 +1,18 @@
1
- import { GetUploadUrlResponseV2, GetDownloadUrlResponse } from '@meistrari/vault-shared/schemas';
1
+ import { z } from 'zod';
2
2
  import { fileTypeFromBlob } from '@meistrari/file-type';
3
3
  import { lookup } from 'mime-types';
4
+ import { GetUploadUrlResponseV2, GetDownloadUrlResponse } from '@meistrari/vault-shared/schemas';
4
5
  import vaultUtils from '@meistrari/vault-shared/utils';
5
6
 
6
- var __defProp$2 = Object.defineProperty;
7
- var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
- var __publicField$2 = (obj, key, value) => {
9
- __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
7
+ var __defProp$3 = Object.defineProperty;
8
+ var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
+ var __publicField$3 = (obj, key, value) => {
10
+ __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
10
11
  return value;
11
12
  };
12
13
  class DataTokenAuthStrategy {
13
14
  constructor(dataToken) {
14
- __publicField$2(this, "dataToken");
15
+ __publicField$3(this, "dataToken");
15
16
  this.dataToken = dataToken;
16
17
  }
17
18
  getHeaders() {
@@ -22,7 +23,7 @@ class DataTokenAuthStrategy {
22
23
  }
23
24
  class APIKeyAuthStrategy {
24
25
  constructor(apiKey) {
25
- __publicField$2(this, "apiKey");
26
+ __publicField$3(this, "apiKey");
26
27
  this.apiKey = apiKey;
27
28
  }
28
29
  getHeaders() {
@@ -62,116 +63,6 @@ function resolveConfig(config) {
62
63
  };
63
64
  }
64
65
 
65
- var __defProp$1 = Object.defineProperty;
66
- var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
67
- var __publicField$1 = (obj, key, value) => {
68
- __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
69
- return value;
70
- };
71
- class Permalink {
72
- constructor(vaultConfig, params) {
73
- __publicField$1(this, "config");
74
- __publicField$1(this, "id");
75
- __publicField$1(this, "workspaceId");
76
- __publicField$1(this, "createdAt");
77
- __publicField$1(this, "createdBy");
78
- __publicField$1(this, "expiresAt");
79
- __publicField$1(this, "fileId");
80
- __publicField$1(this, "baseUrl");
81
- const config = resolveConfig(vaultConfig);
82
- this.config = config;
83
- this.id = params.id;
84
- this.workspaceId = params.workspaceId;
85
- this.createdAt = new Date(params.createdAt);
86
- this.createdBy = params.createdBy;
87
- this.expiresAt = params.expiresAt ? new Date(params.expiresAt) : null;
88
- this.fileId = params.fileId;
89
- this.baseUrl = config.vaultUrl;
90
- }
91
- /**
92
- * The URL for the permalink.
93
- */
94
- get url() {
95
- return new URL(`permalinks/${this.id}`, this.baseUrl);
96
- }
97
- /**
98
- * Get a new permalink instance from its ID.
99
- *
100
- * @param vaultConfig - The vault config.
101
- * @param id - The permalink ID.
102
- * @returns The permalink.
103
- */
104
- static async fromId(vaultConfig, id) {
105
- const config = resolveConfig(vaultConfig);
106
- const response = await fetch(new URL(`permalinks/${id}/metadata`, config.vaultUrl), {
107
- headers: config.authStrategy.getHeaders()
108
- });
109
- if (!response.ok) {
110
- throw await FetchError.from(response.url, "GET", response);
111
- }
112
- const data = await response.json();
113
- return new Permalink(config, data);
114
- }
115
- /**
116
- * Create a new permalink.
117
- *
118
- * @param vaultConfig - The vault config.
119
- * @param params - The parameters for the permalink.
120
- * @param params.expiresIn - Time, in seconds, the permalink will be valid for.
121
- * @param params.fileId - The ID of the file to create a permalink for.
122
- * @param params.workspaceId - The ID of the workspace to create a permalink for.
123
- *
124
- * @param options - Additional options for the request.
125
- * @param options.signal - The signal to abort the request.
126
- *
127
- * @returns The permalink.
128
- */
129
- static async create(vaultConfig, params, options) {
130
- const config = resolveConfig(vaultConfig);
131
- const { expiresIn } = params;
132
- const expiresAt = expiresIn ? new Date(Date.now() + expiresIn * 1e3) : void 0;
133
- const headers = config.authStrategy.getHeaders();
134
- headers.append("x-compatibility-date", "2025-07-29");
135
- headers.append("content-type", "application/json");
136
- const body = expiresAt ? JSON.stringify({ expiresAt: expiresAt.toISOString() }) : "{}";
137
- const response = await fetch(new URL(`files/${params.fileId}/permalinks`, config.vaultUrl), {
138
- method: "POST",
139
- signal: options?.signal,
140
- headers,
141
- body
142
- });
143
- if (!response.ok) {
144
- throw await FetchError.from(response.url, "POST", response);
145
- }
146
- const data = await response.json();
147
- return new Permalink(config, data);
148
- }
149
- /**
150
- * Delete the permalink.
151
- *
152
- * @param options - Additional options for the request.
153
- * @param options.signal - The signal to abort the request.
154
- */
155
- async delete(options) {
156
- const response = await fetch(new URL(`permalinks/${this.id}`, this.baseUrl), {
157
- method: "DELETE",
158
- signal: options?.signal,
159
- headers: this.config.authStrategy.getHeaders()
160
- });
161
- if (!response.ok) {
162
- throw await FetchError.from(response.url, "DELETE", response);
163
- }
164
- }
165
- }
166
-
167
- async function blobToBase64(blob) {
168
- const fileContent = new Uint8Array(await blob.arrayBuffer());
169
- let content = "";
170
- for (const part of fileContent)
171
- content += String.fromCharCode(part);
172
- return btoa(content);
173
- }
174
-
175
66
  async function getFileHash(blob) {
176
67
  const arrayBuffer = await blob.arrayBuffer();
177
68
  const hashBuffer = await crypto.subtle.digest("SHA-256", arrayBuffer);
@@ -218,6 +109,16 @@ async function detectFileMimeType(blob) {
218
109
  }
219
110
  return void 0;
220
111
  }
112
+ function sanitizeFileName(name) {
113
+ if (!name.includes("\0"))
114
+ return name;
115
+ const sanitized = name.replace(/\0/g, "");
116
+ console.warn(
117
+ "[Vault SDK - WARNING] Null bytes found in file name and were removed.",
118
+ { original: name, sanitized }
119
+ );
120
+ return sanitized;
121
+ }
221
122
  function basename(name, separator = "/") {
222
123
  if (!name)
223
124
  return void 0;
@@ -231,7 +132,7 @@ function getFileName(content) {
231
132
  }
232
133
 
233
134
  const name = "@meistrari/vault-sdk";
234
- const version = "3.2.0";
135
+ const version = "3.3.0";
235
136
  const license = "UNLICENSED";
236
137
  const repository = {
237
138
  type: "git",
@@ -259,13 +160,13 @@ const scripts = {
259
160
  };
260
161
  const dependencies = {
261
162
  "@meistrari/file-type": "22.0.0",
262
- "@meistrari/vault-shared": "0.1.1",
163
+ "@meistrari/vault-shared": "0.1.2",
263
164
  "mime-types": "3.0.1",
264
165
  ofetch: "1.4.1",
265
166
  zod: "4.3.6"
266
167
  };
267
168
  const devDependencies = {
268
- "@types/bun": "latest",
169
+ "@types/bun": "1.3.14",
269
170
  "@types/mime-types": "3.0.1",
270
171
  msw: "2.6.8",
271
172
  unbuild: "2.0.0",
@@ -296,6 +197,194 @@ const packageJson = {
296
197
  const serviceName = typeof process !== "undefined" ? process?.env?.SERVICE_NAME : "";
297
198
  const userAgent = `vault-js-sdk:${packageJson.version}${serviceName ? `@${serviceName}` : ""}`.trim();
298
199
 
200
+ var __defProp$2 = Object.defineProperty;
201
+ var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
202
+ var __publicField$2 = (obj, key, value) => {
203
+ __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
204
+ return value;
205
+ };
206
+ const compatibilityDate$1 = "2025-05-19";
207
+ const PublicAssetUploadResponse = z.object({
208
+ assetId: z.string(),
209
+ assetUrl: z.string().url(),
210
+ uploadUrl: z.string().url(),
211
+ expiresAt: z.string().datetime(),
212
+ uploadHeaders: z.record(z.string(), z.string())
213
+ });
214
+ async function wrappedFetch$1(url, requestInit) {
215
+ const request = new Request(url, requestInit);
216
+ request.headers.set("User-Agent", userAgent);
217
+ request.headers.set("x-compatibility-date", compatibilityDate$1);
218
+ const response = await fetch(request);
219
+ if (!response.ok) {
220
+ throw await FetchError.from(request.url, request.method, response);
221
+ }
222
+ return response;
223
+ }
224
+ class VaultAsset {
225
+ constructor({ assetId, assetUrl, uploadUrl, expiresAt, uploadHeaders }) {
226
+ __publicField$2(this, "assetId");
227
+ __publicField$2(this, "assetUrl");
228
+ __publicField$2(this, "uploadUrl");
229
+ __publicField$2(this, "expiresAt");
230
+ __publicField$2(this, "uploadHeaders");
231
+ this.assetId = assetId;
232
+ this.assetUrl = new URL(assetUrl);
233
+ this.uploadUrl = new URL(uploadUrl);
234
+ this.expiresAt = new Date(expiresAt);
235
+ this.uploadHeaders = uploadHeaders;
236
+ }
237
+ static async create(vaultConfig, params, options) {
238
+ const config = resolveConfig(vaultConfig);
239
+ const headers = config.authStrategy.getHeaders();
240
+ headers.set("content-type", "application/json");
241
+ const response = await wrappedFetch$1(new URL("assets", config.vaultUrl), {
242
+ method: "POST",
243
+ signal: options?.signal,
244
+ headers,
245
+ body: JSON.stringify({
246
+ assetClass: params.assetClass,
247
+ mimeType: params.mimeType,
248
+ size: params.size
249
+ })
250
+ }).then(async (response2) => await response2.json()).then((data) => PublicAssetUploadResponse.safeParse(data));
251
+ if (!response.success) {
252
+ throw new Error(`Invalid response from vault service. ${JSON.stringify(response.error)}`);
253
+ }
254
+ return new VaultAsset(response.data);
255
+ }
256
+ static async fromContent(vaultConfig, content, params, options) {
257
+ const mimeType = params.mimeType ?? await detectFileMimeType(content) ?? "application/octet-stream";
258
+ const asset = await VaultAsset.create(vaultConfig, {
259
+ assetClass: params.assetClass,
260
+ mimeType,
261
+ size: content.size
262
+ }, options);
263
+ if (params.upload) {
264
+ await asset.upload(content, options);
265
+ }
266
+ return asset;
267
+ }
268
+ async upload(content, options) {
269
+ await wrappedFetch$1(this.uploadUrl, {
270
+ method: "PUT",
271
+ signal: options?.signal,
272
+ headers: new Headers(this.uploadHeaders),
273
+ body: content
274
+ });
275
+ }
276
+ }
277
+
278
+ var __defProp$1 = Object.defineProperty;
279
+ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
280
+ var __publicField$1 = (obj, key, value) => {
281
+ __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
282
+ return value;
283
+ };
284
+ class Permalink {
285
+ constructor(vaultConfig, params) {
286
+ __publicField$1(this, "config");
287
+ __publicField$1(this, "id");
288
+ __publicField$1(this, "workspaceId");
289
+ __publicField$1(this, "createdAt");
290
+ __publicField$1(this, "createdBy");
291
+ __publicField$1(this, "expiresAt");
292
+ __publicField$1(this, "fileId");
293
+ __publicField$1(this, "baseUrl");
294
+ const config = resolveConfig(vaultConfig);
295
+ this.config = config;
296
+ this.id = params.id;
297
+ this.workspaceId = params.workspaceId;
298
+ this.createdAt = new Date(params.createdAt);
299
+ this.createdBy = params.createdBy;
300
+ this.expiresAt = params.expiresAt ? new Date(params.expiresAt) : null;
301
+ this.fileId = params.fileId;
302
+ this.baseUrl = config.vaultUrl;
303
+ }
304
+ /**
305
+ * The URL for the permalink.
306
+ */
307
+ get url() {
308
+ return new URL(`permalinks/${this.id}`, this.baseUrl);
309
+ }
310
+ /**
311
+ * Get a new permalink instance from its ID.
312
+ *
313
+ * @param vaultConfig - The vault config.
314
+ * @param id - The permalink ID.
315
+ * @returns The permalink.
316
+ */
317
+ static async fromId(vaultConfig, id) {
318
+ const config = resolveConfig(vaultConfig);
319
+ const response = await fetch(new URL(`permalinks/${id}/metadata`, config.vaultUrl), {
320
+ headers: config.authStrategy.getHeaders()
321
+ });
322
+ if (!response.ok) {
323
+ throw await FetchError.from(response.url, "GET", response);
324
+ }
325
+ const data = await response.json();
326
+ return new Permalink(config, data);
327
+ }
328
+ /**
329
+ * Create a new permalink.
330
+ *
331
+ * @param vaultConfig - The vault config.
332
+ * @param params - The parameters for the permalink.
333
+ * @param params.expiresIn - Time, in seconds, the permalink will be valid for.
334
+ * @param params.fileId - The ID of the file to create a permalink for.
335
+ * @param params.workspaceId - The ID of the workspace to create a permalink for.
336
+ *
337
+ * @param options - Additional options for the request.
338
+ * @param options.signal - The signal to abort the request.
339
+ *
340
+ * @returns The permalink.
341
+ */
342
+ static async create(vaultConfig, params, options) {
343
+ const config = resolveConfig(vaultConfig);
344
+ const { expiresIn } = params;
345
+ const expiresAt = expiresIn ? new Date(Date.now() + expiresIn * 1e3) : void 0;
346
+ const headers = config.authStrategy.getHeaders();
347
+ headers.append("x-compatibility-date", "2025-07-29");
348
+ headers.append("content-type", "application/json");
349
+ const body = expiresAt ? JSON.stringify({ expiresAt: expiresAt.toISOString() }) : "{}";
350
+ const response = await fetch(new URL(`files/${params.fileId}/permalinks`, config.vaultUrl), {
351
+ method: "POST",
352
+ signal: options?.signal,
353
+ headers,
354
+ body
355
+ });
356
+ if (!response.ok) {
357
+ throw await FetchError.from(response.url, "POST", response);
358
+ }
359
+ const data = await response.json();
360
+ return new Permalink(config, data);
361
+ }
362
+ /**
363
+ * Delete the permalink.
364
+ *
365
+ * @param options - Additional options for the request.
366
+ * @param options.signal - The signal to abort the request.
367
+ */
368
+ async delete(options) {
369
+ const response = await fetch(new URL(`permalinks/${this.id}`, this.baseUrl), {
370
+ method: "DELETE",
371
+ signal: options?.signal,
372
+ headers: this.config.authStrategy.getHeaders()
373
+ });
374
+ if (!response.ok) {
375
+ throw await FetchError.from(response.url, "DELETE", response);
376
+ }
377
+ }
378
+ }
379
+
380
+ async function blobToBase64(blob) {
381
+ const fileContent = new Uint8Array(await blob.arrayBuffer());
382
+ let content = "";
383
+ for (const part of fileContent)
384
+ content += String.fromCharCode(part);
385
+ return btoa(content);
386
+ }
387
+
299
388
  var __defProp = Object.defineProperty;
300
389
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
301
390
  var __publicField = (obj, key, value) => {
@@ -597,7 +686,8 @@ class VaultFile {
597
686
  */
598
687
  static async fromContent(params, options) {
599
688
  const { content, config: vaultConfig, upload = false, parentId, onMissingParent, onParentConflict } = params;
600
- const name = basename(params.name) ?? getFileName(content);
689
+ const rawName = basename(params.name) ?? getFileName(content);
690
+ const name = rawName ? sanitizeFileName(rawName) : rawName;
601
691
  const config = resolveConfig(vaultConfig);
602
692
  const { vaultUrl, authStrategy } = config;
603
693
  const sha256sum = await getFileHash(content);
@@ -680,7 +770,8 @@ class VaultFile {
680
770
  onMissingParent,
681
771
  onParentConflict
682
772
  } = params;
683
- const name = basename(params.name);
773
+ const rawName = basename(params.name);
774
+ const name = rawName ? sanitizeFileName(rawName) : rawName;
684
775
  const config = resolveConfig(vaultConfig);
685
776
  const file = new VaultFile({ config, name });
686
777
  await file._createFile({
@@ -721,7 +812,8 @@ class VaultFile {
721
812
  const config = resolveConfig(vaultConfig);
722
813
  const preparedFiles = await Promise.all(
723
814
  fileInputs.map(async (input) => {
724
- const name = basename(input.name) ?? getFileName(input.content);
815
+ const rawName = basename(input.name) ?? getFileName(input.content);
816
+ const name = rawName ? sanitizeFileName(rawName) : rawName;
725
817
  const sha256sum = await getFileHash(input.content);
726
818
  const mimeType = input.mimeType ?? await detectFileMimeType(input.content);
727
819
  const size = input.content.size;
@@ -804,7 +896,8 @@ class VaultFile {
804
896
  const { files: fileInputs, config: vaultConfig } = params;
805
897
  const config = resolveConfig(vaultConfig);
806
898
  const preparedFiles = fileInputs.map((input) => {
807
- const name = basename(input.name);
899
+ const rawName = basename(input.name);
900
+ const name = rawName ? sanitizeFileName(rawName) : rawName;
808
901
  const mimeType = input.contentType || "application/octet-stream";
809
902
  const size = input.contentLength;
810
903
  return { ...input, name, mimeType, size };
@@ -2004,7 +2097,15 @@ function vaultClient(vaultConfig) {
2004
2097
  config
2005
2098
  }, { signal: options?.signal });
2006
2099
  }
2007
- return { createFromContent, createFromReference, createFromStream, createFromContentBulk, createFromStreamBulk };
2100
+ const assets = {
2101
+ async create(params, options) {
2102
+ return await VaultAsset.create(config, params, { signal: options?.signal });
2103
+ },
2104
+ async createFromContent(content, params, options) {
2105
+ return await VaultAsset.fromContent(config, content, params, { signal: options?.signal });
2106
+ }
2107
+ };
2108
+ return { createFromContent, createFromReference, createFromStream, createFromContentBulk, createFromStreamBulk, assets };
2008
2109
  }
2009
2110
 
2010
- export { APIKeyAuthStrategy, DataTokenAuthStrategy, FetchError, VaultFile, convertS3UrlToVaultReference, extractVaultFileIdFromS3Url, extractVaultReferences, getVaultParamsFromS3Url, isS3UrlExpired, isTaggedVaultPresignedUrl, isPresignedS3Url as isVaultFileS3Url, isVaultReference, vaultClient };
2111
+ export { APIKeyAuthStrategy, DataTokenAuthStrategy, FetchError, Permalink, VaultAsset, VaultFile, convertS3UrlToVaultReference, extractVaultFileIdFromS3Url, extractVaultReferences, getVaultParamsFromS3Url, isS3UrlExpired, isTaggedVaultPresignedUrl, isPresignedS3Url as isVaultFileS3Url, isVaultReference, vaultClient };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meistrari/vault-sdk",
3
- "version": "3.2.0",
3
+ "version": "3.3.0",
4
4
  "license": "UNLICENSED",
5
5
  "repository": {
6
6
  "type": "git",
@@ -28,13 +28,13 @@
28
28
  },
29
29
  "dependencies": {
30
30
  "@meistrari/file-type": "22.0.0",
31
- "@meistrari/vault-shared": "0.1.1",
31
+ "@meistrari/vault-shared": "0.1.2",
32
32
  "mime-types": "3.0.1",
33
33
  "ofetch": "1.4.1",
34
34
  "zod": "4.3.6"
35
35
  },
36
36
  "devDependencies": {
37
- "@types/bun": "latest",
37
+ "@types/bun": "1.3.14",
38
38
  "@types/mime-types": "3.0.1",
39
39
  "msw": "2.6.8",
40
40
  "unbuild": "2.0.0",