@od-oneapp/storage 2026.1.1301
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 +854 -0
- package/dist/client-next.d.mts +61 -0
- package/dist/client-next.d.mts.map +1 -0
- package/dist/client-next.mjs +111 -0
- package/dist/client-next.mjs.map +1 -0
- package/dist/client-utils-Dx6W25iz.d.mts +43 -0
- package/dist/client-utils-Dx6W25iz.d.mts.map +1 -0
- package/dist/client.d.mts +28 -0
- package/dist/client.d.mts.map +1 -0
- package/dist/client.mjs +183 -0
- package/dist/client.mjs.map +1 -0
- package/dist/env-BVHLmQdh.mjs +128 -0
- package/dist/env-BVHLmQdh.mjs.map +1 -0
- package/dist/env.mjs +3 -0
- package/dist/health-check-D7LnnDec.mjs +746 -0
- package/dist/health-check-D7LnnDec.mjs.map +1 -0
- package/dist/health-check-im_huJ59.d.mts +116 -0
- package/dist/health-check-im_huJ59.d.mts.map +1 -0
- package/dist/index.d.mts +60 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +3 -0
- package/dist/keys.d.mts +37 -0
- package/dist/keys.d.mts.map +1 -0
- package/dist/keys.mjs +253 -0
- package/dist/keys.mjs.map +1 -0
- package/dist/server-edge.d.mts +28 -0
- package/dist/server-edge.d.mts.map +1 -0
- package/dist/server-edge.mjs +88 -0
- package/dist/server-edge.mjs.map +1 -0
- package/dist/server-next.d.mts +183 -0
- package/dist/server-next.d.mts.map +1 -0
- package/dist/server-next.mjs +1353 -0
- package/dist/server-next.mjs.map +1 -0
- package/dist/server.d.mts +70 -0
- package/dist/server.d.mts.map +1 -0
- package/dist/server.mjs +384 -0
- package/dist/server.mjs.map +1 -0
- package/dist/types.d.mts +321 -0
- package/dist/types.d.mts.map +1 -0
- package/dist/types.mjs +3 -0
- package/dist/validation.d.mts +101 -0
- package/dist/validation.d.mts.map +1 -0
- package/dist/validation.mjs +590 -0
- package/dist/validation.mjs.map +1 -0
- package/dist/vercel-blob-07Sx0Akn.d.mts +31 -0
- package/dist/vercel-blob-07Sx0Akn.d.mts.map +1 -0
- package/dist/vercel-blob-DA8HaYuw.mjs +158 -0
- package/dist/vercel-blob-DA8HaYuw.mjs.map +1 -0
- package/package.json +111 -0
- package/src/actions/blob-upload.ts +171 -0
- package/src/actions/index.ts +23 -0
- package/src/actions/mediaActions.ts +1071 -0
- package/src/actions/productMediaActions.ts +538 -0
- package/src/auth-helpers.ts +386 -0
- package/src/capabilities.ts +225 -0
- package/src/client-next.ts +184 -0
- package/src/client-utils.ts +292 -0
- package/src/client.ts +102 -0
- package/src/constants.ts +88 -0
- package/src/health-check.ts +81 -0
- package/src/multi-storage.ts +230 -0
- package/src/multipart.ts +497 -0
- package/src/retry-utils.test.ts +118 -0
- package/src/retry-utils.ts +59 -0
- package/src/server-edge.ts +129 -0
- package/src/server-next.ts +14 -0
- package/src/server.ts +666 -0
- package/src/validation.test.ts +312 -0
- package/src/validation.ts +827 -0
package/dist/server.mjs
ADDED
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
import { r as safeEnv, t as env } from "./env-BVHLmQdh.mjs";
|
|
2
|
+
import { validateStorageKey } from "./keys.mjs";
|
|
3
|
+
import { ConfigError, DownloadError, NetworkError, ProviderError, StorageError, StorageErrorCode, UploadError, ValidationError, createStorageError, formatFileSize, getErrorCode, getQuotaInfo, isQuotaExceeded, isRetryableError, parseFileSize, validateFileSize, validateMimeType, validateUploadOptions } from "./validation.mjs";
|
|
4
|
+
import { _ as DEFAULT_STORAGE_CAPABILITIES, a as getBestProvider, b as CloudflareImagesProvider, c as hasAllCapabilities, d as validateProviderCapabilities, f as MultipartUploadManager, g as MultiStorageManager, h as hasMultipartSupport, i as describeProviderCapabilities, l as hasAnyCapability, m as getOptimalPartSize, n as storageHealthCheck, o as getCapabilityMatrix, p as createMultipartUploadManager, r as checkProviderSuitability, s as getProviderCapabilities, t as checkProviderHealth, u as hasCapability, y as CloudflareR2Provider } from "./health-check-D7LnnDec.mjs";
|
|
5
|
+
import { t as VercelBlobProvider } from "./vercel-blob-DA8HaYuw.mjs";
|
|
6
|
+
import { logWarn } from "@od-oneapp/shared/logs/server/next";
|
|
7
|
+
|
|
8
|
+
//#region src/server.ts
|
|
9
|
+
/**
|
|
10
|
+
* @fileoverview Server-side storage exports (non-Next.js)
|
|
11
|
+
*
|
|
12
|
+
* This file provides server-side storage functionality for non-Next.js environments.
|
|
13
|
+
* For Next.js applications, use '@od-oneapp/storage/server/next' instead.
|
|
14
|
+
*
|
|
15
|
+
* Features:
|
|
16
|
+
* - Multi-provider storage support (Vercel Blob, Cloudflare R2, Cloudflare Images)
|
|
17
|
+
* - Storage provider abstraction
|
|
18
|
+
* - Upload, download, list, and delete operations
|
|
19
|
+
* - Presigned URL generation
|
|
20
|
+
* - Multipart upload support
|
|
21
|
+
*
|
|
22
|
+
* @module @od-oneapp/storage/server
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Configuration validation helpers
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* Validates storage configuration and returns helpful error messages
|
|
29
|
+
* @param config - Storage configuration to validate
|
|
30
|
+
* @returns Validation result with errors if any
|
|
31
|
+
*/
|
|
32
|
+
function validateStorageConfig(config) {
|
|
33
|
+
const errors = [];
|
|
34
|
+
const warnings = [];
|
|
35
|
+
if (!config.provider) errors.push("Storage provider is required");
|
|
36
|
+
switch (config.provider) {
|
|
37
|
+
case "multi":
|
|
38
|
+
errors.push("Multi provider configuration should not be validated here");
|
|
39
|
+
break;
|
|
40
|
+
case "vercel-blob":
|
|
41
|
+
if (!config.vercelBlob?.token) errors.push("VERCEL_BLOB_READ_WRITE_TOKEN is required for Vercel Blob provider");
|
|
42
|
+
break;
|
|
43
|
+
case "cloudflare-r2":
|
|
44
|
+
if (!config.cloudflareR2) errors.push("Cloudflare R2 configuration is required");
|
|
45
|
+
else {
|
|
46
|
+
const r2Config = Array.isArray(config.cloudflareR2) ? config.cloudflareR2[0] : config.cloudflareR2;
|
|
47
|
+
if (!r2Config) errors.push("Cloudflare R2 configuration is required");
|
|
48
|
+
else {
|
|
49
|
+
if (!r2Config.accessKeyId) errors.push("R2_ACCESS_KEY_ID is required for Cloudflare R2 provider");
|
|
50
|
+
if (!r2Config.secretAccessKey) errors.push("R2_SECRET_ACCESS_KEY is required for Cloudflare R2 provider");
|
|
51
|
+
if (!r2Config.bucket) errors.push("R2_BUCKET is required for Cloudflare R2 provider");
|
|
52
|
+
if (!r2Config.accountId) errors.push("R2_ACCOUNT_ID is required for Cloudflare R2 provider");
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
break;
|
|
56
|
+
case "cloudflare-images":
|
|
57
|
+
if (!config.cloudflareImages) errors.push("Cloudflare Images configuration is required");
|
|
58
|
+
else {
|
|
59
|
+
if (!config.cloudflareImages.accountId) errors.push("CLOUDFLARE_IMAGES_ACCOUNT_ID is required for Cloudflare Images provider");
|
|
60
|
+
if (!config.cloudflareImages.apiToken) errors.push("CLOUDFLARE_IMAGES_API_TOKEN is required for Cloudflare Images provider");
|
|
61
|
+
}
|
|
62
|
+
break;
|
|
63
|
+
default: errors.push(`Unknown storage provider: ${config.provider}`);
|
|
64
|
+
}
|
|
65
|
+
if (config.cloudflareR2 && config.cloudflareImages) warnings.push("Multiple providers configured - consider using multi-provider setup");
|
|
66
|
+
return {
|
|
67
|
+
valid: errors.length === 0,
|
|
68
|
+
errors,
|
|
69
|
+
warnings
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Determine storage provider capabilities based on the provided storage configuration.
|
|
74
|
+
*
|
|
75
|
+
* @param config - The storage configuration used to infer provider capabilities
|
|
76
|
+
* @returns A `StorageCapabilities` object describing which features the configured provider supports
|
|
77
|
+
*/
|
|
78
|
+
function getProviderCapabilitiesFromConfig(config) {
|
|
79
|
+
switch (config.provider) {
|
|
80
|
+
case "multi": return { ...DEFAULT_STORAGE_CAPABILITIES };
|
|
81
|
+
case "vercel-blob": return {
|
|
82
|
+
multipart: true,
|
|
83
|
+
presignedUrls: false,
|
|
84
|
+
progressTracking: true,
|
|
85
|
+
abortSignal: true,
|
|
86
|
+
metadata: true,
|
|
87
|
+
customDomains: true,
|
|
88
|
+
edgeCompatible: true,
|
|
89
|
+
versioning: false,
|
|
90
|
+
encryption: false,
|
|
91
|
+
directoryListing: false
|
|
92
|
+
};
|
|
93
|
+
case "cloudflare-r2": return {
|
|
94
|
+
multipart: true,
|
|
95
|
+
presignedUrls: true,
|
|
96
|
+
progressTracking: false,
|
|
97
|
+
abortSignal: false,
|
|
98
|
+
metadata: true,
|
|
99
|
+
customDomains: true,
|
|
100
|
+
edgeCompatible: false,
|
|
101
|
+
versioning: false,
|
|
102
|
+
encryption: false,
|
|
103
|
+
directoryListing: false
|
|
104
|
+
};
|
|
105
|
+
case "cloudflare-images": return {
|
|
106
|
+
multipart: false,
|
|
107
|
+
presignedUrls: false,
|
|
108
|
+
progressTracking: false,
|
|
109
|
+
abortSignal: false,
|
|
110
|
+
metadata: true,
|
|
111
|
+
customDomains: true,
|
|
112
|
+
edgeCompatible: false,
|
|
113
|
+
versioning: false,
|
|
114
|
+
encryption: false,
|
|
115
|
+
directoryListing: false
|
|
116
|
+
};
|
|
117
|
+
default: return {
|
|
118
|
+
multipart: false,
|
|
119
|
+
presignedUrls: false,
|
|
120
|
+
progressTracking: false,
|
|
121
|
+
abortSignal: false,
|
|
122
|
+
metadata: false,
|
|
123
|
+
customDomains: false,
|
|
124
|
+
edgeCompatible: false,
|
|
125
|
+
versioning: false,
|
|
126
|
+
encryption: false,
|
|
127
|
+
directoryListing: false
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Create a StorageProvider instance based on the provided StorageConfig.
|
|
133
|
+
*
|
|
134
|
+
* @param config - Storage configuration specifying `provider` and the provider-specific settings required to instantiate that provider
|
|
135
|
+
* @returns The instantiated StorageProvider corresponding to `config.provider`
|
|
136
|
+
* @throws Error if the chosen provider's configuration is missing or incomplete, if a `cloudflare-r2` array is empty, or if `provider` is unrecognized
|
|
137
|
+
*/
|
|
138
|
+
function createStorageProvider(config) {
|
|
139
|
+
switch (config.provider) {
|
|
140
|
+
case "multi": throw new Error("Multi provider should be created via MultiStorageManager");
|
|
141
|
+
case "cloudflare-r2":
|
|
142
|
+
if (!config.cloudflareR2) throw new Error("Storage provider configuration is incomplete");
|
|
143
|
+
if (!Array.isArray(config.cloudflareR2)) return new CloudflareR2Provider(config.cloudflareR2);
|
|
144
|
+
if (config.cloudflareR2.length === 0) throw new Error("No R2 configurations provided");
|
|
145
|
+
const firstR2Config = config.cloudflareR2[0];
|
|
146
|
+
if (!firstR2Config) throw new Error("First R2 configuration is undefined");
|
|
147
|
+
return new CloudflareR2Provider(firstR2Config);
|
|
148
|
+
case "cloudflare-images":
|
|
149
|
+
if (!config.cloudflareImages) throw new Error("Storage provider configuration is incomplete");
|
|
150
|
+
return new CloudflareImagesProvider(config.cloudflareImages);
|
|
151
|
+
case "vercel-blob":
|
|
152
|
+
if (!config.vercelBlob?.token) throw new Error("Storage provider configuration is incomplete");
|
|
153
|
+
return new VercelBlobProvider(config.vercelBlob.token);
|
|
154
|
+
default: throw new Error(`Unknown storage provider: ${config.provider}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
let storageInstance = null;
|
|
158
|
+
let hasLoggedWarning = false;
|
|
159
|
+
let multiStorageInstance = null;
|
|
160
|
+
/**
|
|
161
|
+
* Test helper to reset singleton state
|
|
162
|
+
* @internal
|
|
163
|
+
*/
|
|
164
|
+
function resetStorageState() {
|
|
165
|
+
storageInstance = null;
|
|
166
|
+
multiStorageInstance = null;
|
|
167
|
+
hasLoggedWarning = false;
|
|
168
|
+
}
|
|
169
|
+
var MockStorageProvider = class {
|
|
170
|
+
storage = /* @__PURE__ */ new Map();
|
|
171
|
+
async delete(key) {
|
|
172
|
+
this.storage.delete(key);
|
|
173
|
+
}
|
|
174
|
+
async download(_key) {
|
|
175
|
+
return new Blob(["mock data"], { type: "text/plain" });
|
|
176
|
+
}
|
|
177
|
+
async exists(key) {
|
|
178
|
+
return this.storage.has(key);
|
|
179
|
+
}
|
|
180
|
+
async getMetadata(key) {
|
|
181
|
+
const item = this.storage.get(key);
|
|
182
|
+
if (!item) throw new Error(`Object with key ${key} not found`);
|
|
183
|
+
return item.metadata;
|
|
184
|
+
}
|
|
185
|
+
async getUrl(key, _options) {
|
|
186
|
+
return `https://mock-storage.example.com/${key}`;
|
|
187
|
+
}
|
|
188
|
+
async list(_options) {
|
|
189
|
+
return Array.from(this.storage.values()).map((item) => item.metadata);
|
|
190
|
+
}
|
|
191
|
+
async upload(key, data, options) {
|
|
192
|
+
const mockObject = {
|
|
193
|
+
contentType: options?.contentType ?? "application/octet-stream",
|
|
194
|
+
key,
|
|
195
|
+
lastModified: /* @__PURE__ */ new Date(),
|
|
196
|
+
size: data instanceof Buffer ? data.length : 1024,
|
|
197
|
+
url: `https://mock-storage.example.com/${key}`
|
|
198
|
+
};
|
|
199
|
+
this.storage.set(key, {
|
|
200
|
+
data,
|
|
201
|
+
metadata: mockObject
|
|
202
|
+
});
|
|
203
|
+
return mockObject;
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
/**
|
|
207
|
+
* Return the configured StorageProvider, initializing it on first access if needed.
|
|
208
|
+
*
|
|
209
|
+
* @returns The configured StorageProvider; a mock provider when no real provider is configured
|
|
210
|
+
*/
|
|
211
|
+
function getStorage() {
|
|
212
|
+
if (!storageInstance) return initializeStorage();
|
|
213
|
+
return storageInstance;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Initialize and return the application's storage provider from environment configuration.
|
|
217
|
+
*
|
|
218
|
+
* Builds a StorageConfig from environment variables, validates it, and instantiates the corresponding StorageProvider. If no provider is configured, a MockStorageProvider is returned.
|
|
219
|
+
*
|
|
220
|
+
* @returns The instantiated StorageProvider (a MockStorageProvider when no provider is configured).
|
|
221
|
+
* @throws Error when required provider environment variables are missing (message: "Storage provider configuration is incomplete").
|
|
222
|
+
* @throws Error when configuration validation fails (message: "Storage configuration validation failed: <errors>").
|
|
223
|
+
*/
|
|
224
|
+
function initializeStorage() {
|
|
225
|
+
if (storageInstance) return storageInstance;
|
|
226
|
+
const env = safeEnv();
|
|
227
|
+
const provider = env.STORAGE_PROVIDER;
|
|
228
|
+
if (!provider) {
|
|
229
|
+
if (!hasLoggedWarning) hasLoggedWarning = true;
|
|
230
|
+
storageInstance = new MockStorageProvider();
|
|
231
|
+
return storageInstance;
|
|
232
|
+
}
|
|
233
|
+
const config = { provider };
|
|
234
|
+
switch (provider) {
|
|
235
|
+
case "multi": throw new Error("Multi provider configuration not supported in getStorage()");
|
|
236
|
+
case "cloudflare-images": throw new Error("Cloudflare Images provider not supported as primary storage provider");
|
|
237
|
+
case "cloudflare-r2":
|
|
238
|
+
if (!env.R2_ACCOUNT_ID || !env.R2_ACCESS_KEY_ID || !env.R2_SECRET_ACCESS_KEY || !env.R2_BUCKET) throw new Error("Storage provider configuration is incomplete");
|
|
239
|
+
config.cloudflareR2 = {
|
|
240
|
+
accessKeyId: env.R2_ACCESS_KEY_ID,
|
|
241
|
+
accountId: env.R2_ACCOUNT_ID,
|
|
242
|
+
bucket: env.R2_BUCKET,
|
|
243
|
+
secretAccessKey: env.R2_SECRET_ACCESS_KEY
|
|
244
|
+
};
|
|
245
|
+
break;
|
|
246
|
+
case "vercel-blob":
|
|
247
|
+
if (!env.VERCEL_BLOB_READ_WRITE_TOKEN) throw new Error("Storage provider configuration is incomplete");
|
|
248
|
+
config.vercelBlob = { token: env.VERCEL_BLOB_READ_WRITE_TOKEN };
|
|
249
|
+
break;
|
|
250
|
+
}
|
|
251
|
+
const validation = validateStorageConfig(config);
|
|
252
|
+
if (!validation.valid) throw new Error(`Storage configuration validation failed: ${validation.errors.join(", ")}`);
|
|
253
|
+
if (validation.warnings.length > 0) logWarn("Storage configuration warnings:", {
|
|
254
|
+
warnings: validation.warnings,
|
|
255
|
+
provider: config.provider
|
|
256
|
+
});
|
|
257
|
+
storageInstance = createStorageProvider(config);
|
|
258
|
+
return storageInstance;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Initialize multi-storage manager with environment variables
|
|
262
|
+
* @returns Configured multi-storage manager instance
|
|
263
|
+
*/
|
|
264
|
+
function initializeMultiStorage() {
|
|
265
|
+
if (multiStorageInstance) return multiStorageInstance;
|
|
266
|
+
const env = safeEnv();
|
|
267
|
+
if (env.STORAGE_CONFIG) {
|
|
268
|
+
multiStorageInstance = new MultiStorageManager(typeof env.STORAGE_CONFIG === "string" ? JSON.parse(env.STORAGE_CONFIG) : env.STORAGE_CONFIG);
|
|
269
|
+
return multiStorageInstance;
|
|
270
|
+
}
|
|
271
|
+
const config = { providers: {} };
|
|
272
|
+
if (env.R2_CREDENTIALS && Array.isArray(env.R2_CREDENTIALS)) env.R2_CREDENTIALS.forEach((r2Config, index) => {
|
|
273
|
+
const name = r2Config.name ?? `r2-${index}`;
|
|
274
|
+
config.providers[name] = {
|
|
275
|
+
provider: "cloudflare-r2",
|
|
276
|
+
cloudflareR2: r2Config
|
|
277
|
+
};
|
|
278
|
+
});
|
|
279
|
+
if (env.R2_ACCESS_KEY_ID && env.R2_SECRET_ACCESS_KEY && env.R2_BUCKET && env.R2_ACCOUNT_ID) config.providers["r2-legacy"] = {
|
|
280
|
+
provider: "cloudflare-r2",
|
|
281
|
+
cloudflareR2: {
|
|
282
|
+
accessKeyId: env.R2_ACCESS_KEY_ID,
|
|
283
|
+
accountId: env.R2_ACCOUNT_ID,
|
|
284
|
+
bucket: env.R2_BUCKET,
|
|
285
|
+
secretAccessKey: env.R2_SECRET_ACCESS_KEY
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
if (env.CLOUDFLARE_IMAGES_API_TOKEN && env.CLOUDFLARE_IMAGES_ACCOUNT_ID) config.providers["images"] = {
|
|
289
|
+
provider: "cloudflare-images",
|
|
290
|
+
cloudflareImages: {
|
|
291
|
+
accountId: env.CLOUDFLARE_IMAGES_ACCOUNT_ID,
|
|
292
|
+
apiToken: env.CLOUDFLARE_IMAGES_API_TOKEN,
|
|
293
|
+
deliveryUrl: env.CLOUDFLARE_IMAGES_DELIVERY_URL,
|
|
294
|
+
signingKey: env.CLOUDFLARE_IMAGES_SIGNING_KEY
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
if (env.VERCEL_BLOB_READ_WRITE_TOKEN) config.providers["blob"] = {
|
|
298
|
+
provider: "vercel-blob",
|
|
299
|
+
vercelBlob: { token: env.VERCEL_BLOB_READ_WRITE_TOKEN }
|
|
300
|
+
};
|
|
301
|
+
config.routing = {
|
|
302
|
+
images: "images",
|
|
303
|
+
documents: config.providers["r2-0"] ? "r2-0" : "r2-legacy"
|
|
304
|
+
};
|
|
305
|
+
if (Object.keys(config.providers).length === 0) {
|
|
306
|
+
config.providers["mock"] = {
|
|
307
|
+
provider: "vercel-blob",
|
|
308
|
+
vercelBlob: { token: "mock" }
|
|
309
|
+
};
|
|
310
|
+
multiStorageInstance = new MultiStorageManager(config);
|
|
311
|
+
if (!hasLoggedWarning) hasLoggedWarning = true;
|
|
312
|
+
return multiStorageInstance;
|
|
313
|
+
}
|
|
314
|
+
multiStorageInstance = new MultiStorageManager(config);
|
|
315
|
+
return multiStorageInstance;
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Get multi-storage manager instance with lazy initialization
|
|
319
|
+
* @returns Multi-storage manager instance
|
|
320
|
+
*/
|
|
321
|
+
function getMultiStorage() {
|
|
322
|
+
if (!multiStorageInstance) return initializeMultiStorage();
|
|
323
|
+
return multiStorageInstance;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Helper functions for common storage operations
|
|
327
|
+
* Provides direct access to the primary storage provider methods
|
|
328
|
+
*/
|
|
329
|
+
const storage = {
|
|
330
|
+
delete: (key) => getStorage().delete(key),
|
|
331
|
+
download: (key) => getStorage().download(key),
|
|
332
|
+
exists: (key) => getStorage().exists(key),
|
|
333
|
+
getMetadata: (key) => getStorage().getMetadata(key),
|
|
334
|
+
getUrl: (key, options) => getStorage().getUrl(key, options),
|
|
335
|
+
list: (options) => getStorage().list(options),
|
|
336
|
+
upload: (key, data, options) => getStorage().upload(key, data, options),
|
|
337
|
+
createMultipartUpload: (key, options) => {
|
|
338
|
+
const provider = getStorage();
|
|
339
|
+
if (!provider.createMultipartUpload) throw new Error("Provider does not support multipart uploads");
|
|
340
|
+
return provider.createMultipartUpload(key, options);
|
|
341
|
+
},
|
|
342
|
+
uploadPart: (uploadId, partNumber, data, options) => {
|
|
343
|
+
const provider = getStorage();
|
|
344
|
+
if (!provider.uploadPart) throw new Error("Provider does not support multipart uploads");
|
|
345
|
+
return provider.uploadPart(uploadId, partNumber, data, options);
|
|
346
|
+
},
|
|
347
|
+
completeMultipartUpload: (uploadId, parts) => {
|
|
348
|
+
const provider = getStorage();
|
|
349
|
+
if (!provider.completeMultipartUpload) throw new Error("Provider does not support multipart uploads");
|
|
350
|
+
return provider.completeMultipartUpload(uploadId, parts);
|
|
351
|
+
},
|
|
352
|
+
abortMultipartUpload: (uploadId) => {
|
|
353
|
+
const provider = getStorage();
|
|
354
|
+
if (!provider.abortMultipartUpload) throw new Error("Provider does not support multipart uploads");
|
|
355
|
+
return provider.abortMultipartUpload(uploadId);
|
|
356
|
+
},
|
|
357
|
+
getPresignedUploadUrl: (key, options) => {
|
|
358
|
+
const provider = getStorage();
|
|
359
|
+
if (!provider.getPresignedUploadUrl) throw new Error("Provider does not support presigned URLs");
|
|
360
|
+
return provider.getPresignedUploadUrl(key, options);
|
|
361
|
+
},
|
|
362
|
+
getCapabilities: () => {
|
|
363
|
+
return getStorage().getCapabilities?.() ?? { ...DEFAULT_STORAGE_CAPABILITIES };
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
/**
|
|
367
|
+
* Multi-storage helper functions
|
|
368
|
+
* Provides access to multi-storage manager methods with automatic routing
|
|
369
|
+
*/
|
|
370
|
+
const multiStorage = {
|
|
371
|
+
delete: (key) => getMultiStorage().delete(key),
|
|
372
|
+
download: (key) => getMultiStorage().download(key),
|
|
373
|
+
exists: (key) => getMultiStorage().exists(key),
|
|
374
|
+
getMetadata: (key) => getMultiStorage().getMetadata(key),
|
|
375
|
+
getProvider: (name) => getMultiStorage().getProvider(name),
|
|
376
|
+
getProviderNames: () => getMultiStorage().getProviderNames(),
|
|
377
|
+
getUrl: (key, options) => getMultiStorage().getUrl(key, options),
|
|
378
|
+
list: (options) => getMultiStorage().list(options),
|
|
379
|
+
upload: (key, data, options) => getMultiStorage().upload(key, data, options)
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
//#endregion
|
|
383
|
+
export { CloudflareImagesProvider, CloudflareR2Provider, ConfigError, DownloadError, MultiStorageManager, MultipartUploadManager, NetworkError, ProviderError, StorageError, StorageErrorCode, UploadError, ValidationError, VercelBlobProvider, checkProviderHealth, checkProviderSuitability, createMultipartUploadManager, createStorageError, createStorageProvider, describeProviderCapabilities, env, formatFileSize, getBestProvider, getCapabilityMatrix, getErrorCode, getMultiStorage, getOptimalPartSize, getProviderCapabilities, getProviderCapabilitiesFromConfig, getQuotaInfo, getStorage, hasAllCapabilities, hasAnyCapability, hasCapability, hasMultipartSupport, initializeMultiStorage, initializeStorage, isQuotaExceeded, isRetryableError, multiStorage, parseFileSize, resetStorageState, safeEnv, storage, storageHealthCheck, validateFileSize, validateMimeType, validateProviderCapabilities, validateStorageConfig, validateStorageKey, validateUploadOptions };
|
|
384
|
+
//# sourceMappingURL=server.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.mjs","names":[],"sources":["../src/server.ts"],"sourcesContent":["/**\n * @fileoverview Server-side storage exports (non-Next.js)\n *\n * This file provides server-side storage functionality for non-Next.js environments.\n * For Next.js applications, use '@repo/storage/server/next' instead.\n *\n * Features:\n * - Multi-provider storage support (Vercel Blob, Cloudflare R2, Cloudflare Images)\n * - Storage provider abstraction\n * - Upload, download, list, and delete operations\n * - Presigned URL generation\n * - Multipart upload support\n *\n * @module @repo/storage/server\n */\n\nimport { logWarn } from '@repo/shared/logs/server/next';\n\nimport { safeEnv } from '../env';\nimport { CloudflareImagesProvider } from '../providers/cloudflare-images';\nimport { CloudflareR2Provider } from '../providers/cloudflare-r2';\nimport { VercelBlobProvider } from '../providers/vercel-blob';\nimport {\n type ListOptions,\n type MultiStorageConfig,\n type StorageCapabilities,\n type StorageConfig,\n type StorageObject,\n type StorageProvider,\n type StorageProviderType,\n type UploadOptions,\n} from '../types';\n\nimport { DEFAULT_STORAGE_CAPABILITIES } from './constants';\nimport { MultiStorageManager } from './multi-storage';\n\n\nexport { env, safeEnv } from '../env';\nexport { CloudflareImagesProvider } from '../providers/cloudflare-images';\nexport { CloudflareR2Provider } from '../providers/cloudflare-r2';\nexport { VercelBlobProvider } from '../providers/vercel-blob';\nexport * from '../types';\nexport { MultiStorageManager } from './multi-storage';\n\n// Export multipart utilities\nexport {\n createMultipartUploadManager,\n getOptimalPartSize,\n hasMultipartSupport,\n MultipartUploadManager,\n type MultipartUploadResult,\n type MultipartUploadState,\n} from './multipart';\n\n// Export validation utilities\nexport {\n ConfigError,\n createStorageError,\n DownloadError,\n formatFileSize,\n getErrorCode,\n getQuotaInfo,\n isQuotaExceeded,\n isRetryableError,\n NetworkError,\n parseFileSize,\n ProviderError,\n StorageError,\n StorageErrorCode,\n UploadError,\n validateFileSize,\n validateMimeType,\n validateStorageKey,\n validateUploadOptions,\n ValidationError,\n type QuotaInfo,\n type ValidationOptions,\n} from './validation';\n\n// Export capabilities utilities\nexport {\n checkProviderSuitability,\n describeProviderCapabilities,\n getBestProvider,\n getCapabilityMatrix,\n getProviderCapabilities,\n hasAllCapabilities,\n hasAnyCapability,\n hasCapability,\n validateProviderCapabilities,\n} from './capabilities';\n\n// Export health check utilities\nexport { checkProviderHealth, storageHealthCheck } from './health-check';\nexport type { HealthCheckResult } from './health-check';\n\n/**\n * Configuration validation helpers\n */\n\n/**\n * Validates storage configuration and returns helpful error messages\n * @param config - Storage configuration to validate\n * @returns Validation result with errors if any\n */\nexport function validateStorageConfig(config: StorageConfig): {\n valid: boolean;\n errors: string[];\n warnings: string[];\n} {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n // Check provider type\n if (!config.provider) {\n errors.push('Storage provider is required');\n }\n\n // Validate provider-specific configuration\n switch (config.provider) {\n case 'multi':\n errors.push('Multi provider configuration should not be validated here');\n break;\n\n case 'vercel-blob':\n if (!config.vercelBlob?.token) {\n errors.push('VERCEL_BLOB_READ_WRITE_TOKEN is required for Vercel Blob provider');\n }\n break;\n\n case 'cloudflare-r2':\n if (!config.cloudflareR2) {\n errors.push('Cloudflare R2 configuration is required');\n } else {\n const r2Config = Array.isArray(config.cloudflareR2)\n ? config.cloudflareR2[0]\n : config.cloudflareR2;\n if (!r2Config) {\n errors.push('Cloudflare R2 configuration is required');\n } else {\n if (!r2Config.accessKeyId) {\n errors.push('R2_ACCESS_KEY_ID is required for Cloudflare R2 provider');\n }\n if (!r2Config.secretAccessKey) {\n errors.push('R2_SECRET_ACCESS_KEY is required for Cloudflare R2 provider');\n }\n if (!r2Config.bucket) {\n errors.push('R2_BUCKET is required for Cloudflare R2 provider');\n }\n if (!r2Config.accountId) {\n errors.push('R2_ACCOUNT_ID is required for Cloudflare R2 provider');\n }\n }\n }\n break;\n\n case 'cloudflare-images':\n if (!config.cloudflareImages) {\n errors.push('Cloudflare Images configuration is required');\n } else {\n if (!config.cloudflareImages.accountId) {\n errors.push('CLOUDFLARE_IMAGES_ACCOUNT_ID is required for Cloudflare Images provider');\n }\n if (!config.cloudflareImages.apiToken) {\n errors.push('CLOUDFLARE_IMAGES_API_TOKEN is required for Cloudflare Images provider');\n }\n }\n break;\n\n default:\n errors.push(`Unknown storage provider: ${config.provider}`);\n }\n\n // Check for common configuration issues\n if (config.cloudflareR2 && config.cloudflareImages) {\n warnings.push('Multiple providers configured - consider using multi-provider setup');\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\n/**\n * Determine storage provider capabilities based on the provided storage configuration.\n *\n * @param config - The storage configuration used to infer provider capabilities\n * @returns A `StorageCapabilities` object describing which features the configured provider supports\n */\nexport function getProviderCapabilitiesFromConfig(config: StorageConfig): StorageCapabilities {\n switch (config.provider) {\n case 'multi':\n return { ...DEFAULT_STORAGE_CAPABILITIES };\n\n case 'vercel-blob':\n return {\n multipart: true,\n presignedUrls: false,\n progressTracking: true,\n abortSignal: true,\n metadata: true,\n customDomains: true,\n edgeCompatible: true,\n versioning: false,\n encryption: false,\n directoryListing: false,\n };\n\n case 'cloudflare-r2':\n return {\n multipart: true,\n presignedUrls: true,\n progressTracking: false,\n abortSignal: false,\n metadata: true,\n customDomains: true,\n edgeCompatible: false,\n versioning: false,\n encryption: false,\n directoryListing: false,\n };\n\n case 'cloudflare-images':\n return {\n multipart: false,\n presignedUrls: false,\n progressTracking: false,\n abortSignal: false,\n metadata: true,\n customDomains: true,\n edgeCompatible: false,\n versioning: false,\n encryption: false,\n directoryListing: false,\n };\n\n default:\n return {\n multipart: false,\n presignedUrls: false,\n progressTracking: false,\n abortSignal: false,\n metadata: false,\n customDomains: false,\n edgeCompatible: false,\n versioning: false,\n encryption: false,\n directoryListing: false,\n };\n }\n}\n\n/**\n * Create a StorageProvider instance based on the provided StorageConfig.\n *\n * @param config - Storage configuration specifying `provider` and the provider-specific settings required to instantiate that provider\n * @returns The instantiated StorageProvider corresponding to `config.provider`\n * @throws Error if the chosen provider's configuration is missing or incomplete, if a `cloudflare-r2` array is empty, or if `provider` is unrecognized\n */\nexport function createStorageProvider(config: StorageConfig): StorageProvider {\n switch (config.provider) {\n case 'multi':\n throw new Error('Multi provider should be created via MultiStorageManager');\n\n case 'cloudflare-r2':\n if (!config.cloudflareR2) {\n throw new Error('Storage provider configuration is incomplete');\n }\n // Support single R2 config\n if (!Array.isArray(config.cloudflareR2)) {\n return new CloudflareR2Provider(config.cloudflareR2);\n }\n // For array, use first one (backward compatibility)\n if (config.cloudflareR2.length === 0) {\n throw new Error('No R2 configurations provided');\n }\n const firstR2Config = config.cloudflareR2[0];\n if (!firstR2Config) {\n throw new Error('First R2 configuration is undefined');\n }\n return new CloudflareR2Provider(firstR2Config);\n\n case 'cloudflare-images':\n if (!config.cloudflareImages) {\n throw new Error('Storage provider configuration is incomplete');\n }\n return new CloudflareImagesProvider(config.cloudflareImages);\n\n case 'vercel-blob':\n if (!config.vercelBlob?.token) {\n throw new Error('Storage provider configuration is incomplete');\n }\n return new VercelBlobProvider(config.vercelBlob.token);\n\n default:\n throw new Error(`Unknown storage provider: ${config.provider}`);\n }\n}\n\n// Singleton storage instance\nlet storageInstance: MultiStorageManager | null | StorageProvider = null;\nlet hasLoggedWarning = false;\nlet multiStorageInstance: MultiStorageManager | null = null;\n\n/**\n * Test helper to reset singleton state\n * @internal\n */\nexport function resetStorageState(): void {\n storageInstance = null;\n multiStorageInstance = null;\n hasLoggedWarning = false;\n}\n\n// Mock storage provider for development\nclass MockStorageProvider implements StorageProvider {\n private storage = new Map<\n string,\n { data: ArrayBuffer | Blob | Buffer | File | ReadableStream; metadata: StorageObject }\n >();\n\n async delete(key: string): Promise<void> {\n this.storage.delete(key);\n }\n\n async download(_key: string): Promise<Blob> {\n return new Blob(['mock data'], { type: 'text/plain' });\n }\n\n async exists(key: string): Promise<boolean> {\n return this.storage.has(key);\n }\n\n async getMetadata(key: string): Promise<StorageObject> {\n const item = this.storage.get(key);\n if (!item) {\n throw new Error(`Object with key ${key} not found`);\n }\n return item.metadata;\n }\n\n async getUrl(key: string, _options?: { expiresIn?: number }): Promise<string> {\n return `https://mock-storage.example.com/${key}`;\n }\n\n async list(_options?: ListOptions): Promise<StorageObject[]> {\n return Array.from(this.storage.values()).map(item => item.metadata);\n }\n\n async upload(\n key: string,\n data: ArrayBuffer | Blob | Buffer | File | ReadableStream,\n options?: UploadOptions,\n ): Promise<StorageObject> {\n const mockObject: StorageObject = {\n contentType: options?.contentType ?? 'application/octet-stream',\n key,\n lastModified: new Date(),\n size: data instanceof Buffer ? data.length : 1024,\n url: `https://mock-storage.example.com/${key}`,\n };\n this.storage.set(key, { data, metadata: mockObject });\n return mockObject;\n }\n}\n\n/**\n * Return the configured StorageProvider, initializing it on first access if needed.\n *\n * @returns The configured StorageProvider; a mock provider when no real provider is configured\n */\nexport function getStorage(): StorageProvider {\n if (!storageInstance) {\n return initializeStorage();\n }\n return storageInstance;\n}\n\n/**\n * Initialize and return the application's storage provider from environment configuration.\n *\n * Builds a StorageConfig from environment variables, validates it, and instantiates the corresponding StorageProvider. If no provider is configured, a MockStorageProvider is returned.\n *\n * @returns The instantiated StorageProvider (a MockStorageProvider when no provider is configured).\n * @throws Error when required provider environment variables are missing (message: \"Storage provider configuration is incomplete\").\n * @throws Error when configuration validation fails (message: \"Storage configuration validation failed: <errors>\").\n */\nexport function initializeStorage(): StorageProvider {\n if (storageInstance) {\n return storageInstance;\n }\n\n const env = safeEnv();\n const provider = env.STORAGE_PROVIDER;\n\n // Return mock provider if no provider is configured\n if (!provider) {\n if (!hasLoggedWarning) {\n // Storage service runs in mock mode when not configured\n hasLoggedWarning = true;\n }\n storageInstance = new MockStorageProvider();\n return storageInstance;\n }\n\n const config: StorageConfig = {\n provider: provider as StorageProviderType,\n };\n\n // Configure based on provider\n switch (provider) {\n case 'multi':\n throw new Error('Multi provider configuration not supported in getStorage()');\n\n case 'cloudflare-images':\n throw new Error('Cloudflare Images provider not supported as primary storage provider');\n\n case 'cloudflare-r2': {\n if (\n !env.R2_ACCOUNT_ID ||\n !env.R2_ACCESS_KEY_ID ||\n !env.R2_SECRET_ACCESS_KEY ||\n !env.R2_BUCKET\n ) {\n throw new Error('Storage provider configuration is incomplete');\n }\n config.cloudflareR2 = {\n accessKeyId: env.R2_ACCESS_KEY_ID,\n accountId: env.R2_ACCOUNT_ID,\n bucket: env.R2_BUCKET,\n secretAccessKey: env.R2_SECRET_ACCESS_KEY,\n };\n break;\n }\n case 'vercel-blob': {\n if (!env.VERCEL_BLOB_READ_WRITE_TOKEN) {\n throw new Error('Storage provider configuration is incomplete');\n }\n config.vercelBlob = {\n token: env.VERCEL_BLOB_READ_WRITE_TOKEN,\n };\n break;\n }\n }\n\n // Validate configuration before creating provider\n const validation = validateStorageConfig(config);\n if (!validation.valid) {\n throw new Error(`Storage configuration validation failed: ${validation.errors.join(', ')}`);\n }\n\n // Log warnings if any\n if (validation.warnings.length > 0) {\n logWarn('Storage configuration warnings:', {\n warnings: validation.warnings,\n provider: config.provider,\n });\n }\n\n storageInstance = createStorageProvider(config);\n return storageInstance;\n}\n\n/**\n * Initialize multi-storage manager with environment variables\n * @returns Configured multi-storage manager instance\n */\nexport function initializeMultiStorage(): MultiStorageManager {\n if (multiStorageInstance) {\n return multiStorageInstance;\n }\n\n const env = safeEnv();\n\n // Check if we have a full storage config JSON\n if (env.STORAGE_CONFIG) {\n const config =\n typeof env.STORAGE_CONFIG === 'string' ? JSON.parse(env.STORAGE_CONFIG) : env.STORAGE_CONFIG;\n multiStorageInstance = new MultiStorageManager(config);\n return multiStorageInstance;\n }\n\n // Build config from individual env vars\n const config: MultiStorageConfig = {\n providers: {},\n };\n\n // Add R2 providers from JSON array\n if (env.R2_CREDENTIALS && Array.isArray(env.R2_CREDENTIALS)) {\n const r2Configs = env.R2_CREDENTIALS;\n r2Configs.forEach((r2Config, index: number) => {\n const name = r2Config.name ?? `r2-${index}`;\n config.providers[name] = {\n provider: 'cloudflare-r2',\n cloudflareR2: r2Config,\n };\n });\n }\n\n // Add legacy R2 config if present\n if (env.R2_ACCESS_KEY_ID && env.R2_SECRET_ACCESS_KEY && env.R2_BUCKET && env.R2_ACCOUNT_ID) {\n config.providers['r2-legacy'] = {\n provider: 'cloudflare-r2',\n cloudflareR2: {\n accessKeyId: env.R2_ACCESS_KEY_ID,\n accountId: env.R2_ACCOUNT_ID,\n bucket: env.R2_BUCKET,\n secretAccessKey: env.R2_SECRET_ACCESS_KEY,\n },\n };\n }\n\n // Add Cloudflare Images if configured\n if (env.CLOUDFLARE_IMAGES_API_TOKEN && env.CLOUDFLARE_IMAGES_ACCOUNT_ID) {\n config.providers['images'] = {\n provider: 'cloudflare-images',\n cloudflareImages: {\n accountId: env.CLOUDFLARE_IMAGES_ACCOUNT_ID,\n apiToken: env.CLOUDFLARE_IMAGES_API_TOKEN,\n deliveryUrl: env.CLOUDFLARE_IMAGES_DELIVERY_URL,\n signingKey: env.CLOUDFLARE_IMAGES_SIGNING_KEY,\n },\n };\n }\n\n // Add Vercel Blob if configured\n if (env.VERCEL_BLOB_READ_WRITE_TOKEN) {\n config.providers['blob'] = {\n provider: 'vercel-blob',\n vercelBlob: {\n token: env.VERCEL_BLOB_READ_WRITE_TOKEN,\n },\n };\n }\n\n // Set up routing\n config.routing = {\n images: 'images', // Route image files to Cloudflare Images if available\n documents: config.providers['r2-0'] ? 'r2-0' : 'r2-legacy', // Route documents to first R2\n };\n\n if (Object.keys(config.providers).length === 0) {\n // Return mock multi-storage\n config.providers['mock'] = {\n provider: 'vercel-blob', // Using mock provider\n vercelBlob: { token: 'mock' },\n };\n multiStorageInstance = new MultiStorageManager(config);\n\n if (!hasLoggedWarning) {\n // Multi-storage service runs in mock mode when not configured\n hasLoggedWarning = true;\n }\n return multiStorageInstance;\n }\n\n multiStorageInstance = new MultiStorageManager(config);\n return multiStorageInstance;\n}\n\n/**\n * Get multi-storage manager instance with lazy initialization\n * @returns Multi-storage manager instance\n */\nexport function getMultiStorage(): MultiStorageManager {\n if (!multiStorageInstance) {\n return initializeMultiStorage();\n }\n return multiStorageInstance;\n}\n\n/**\n * Helper functions for common storage operations\n * Provides direct access to the primary storage provider methods\n */\nexport const storage = {\n delete: (key: string) => getStorage().delete(key),\n download: (key: string) => getStorage().download(key),\n exists: (key: string) => getStorage().exists(key),\n getMetadata: (key: string) => getStorage().getMetadata(key),\n getUrl: (key: string, options?: { expiresIn?: number }) => getStorage().getUrl(key, options),\n list: (options?: ListOptions) => getStorage().list(options),\n upload: (\n key: string,\n data: ArrayBuffer | Blob | Buffer | File | ReadableStream,\n options?: UploadOptions,\n ) => getStorage().upload(key, data, options),\n\n // Multipart upload helpers\n createMultipartUpload: (key: string, options?: UploadOptions) => {\n const provider = getStorage();\n if (!provider.createMultipartUpload) {\n throw new Error('Provider does not support multipart uploads');\n }\n return provider.createMultipartUpload(key, options);\n },\n\n uploadPart: (\n uploadId: string,\n partNumber: number,\n data: ArrayBuffer | Blob | Buffer,\n options?: UploadOptions,\n ) => {\n const provider = getStorage();\n if (!provider.uploadPart) {\n throw new Error('Provider does not support multipart uploads');\n }\n return provider.uploadPart(uploadId, partNumber, data, options);\n },\n\n completeMultipartUpload: (\n uploadId: string,\n parts: Array<{ etag: string; partNumber: number }>,\n ) => {\n const provider = getStorage();\n if (!provider.completeMultipartUpload) {\n throw new Error('Provider does not support multipart uploads');\n }\n return provider.completeMultipartUpload(uploadId, parts);\n },\n\n abortMultipartUpload: (uploadId: string) => {\n const provider = getStorage();\n if (!provider.abortMultipartUpload) {\n throw new Error('Provider does not support multipart uploads');\n }\n return provider.abortMultipartUpload(uploadId);\n },\n\n // Presigned URL helper\n getPresignedUploadUrl: (key: string, options?: { expiresIn?: number; contentType?: string }) => {\n const provider = getStorage();\n if (!provider.getPresignedUploadUrl) {\n throw new Error('Provider does not support presigned URLs');\n }\n return provider.getPresignedUploadUrl(key, options);\n },\n\n // Capabilities helper\n getCapabilities: () => {\n const provider = getStorage();\n return provider.getCapabilities?.() ?? { ...DEFAULT_STORAGE_CAPABILITIES };\n },\n};\n\n/**\n * Multi-storage helper functions\n * Provides access to multi-storage manager methods with automatic routing\n */\nexport const multiStorage = {\n delete: (key: string) => getMultiStorage().delete(key),\n download: (key: string) => getMultiStorage().download(key),\n exists: (key: string) => getMultiStorage().exists(key),\n getMetadata: (key: string) => getMultiStorage().getMetadata(key),\n getProvider: (name: string) => getMultiStorage().getProvider(name),\n getProviderNames: () => getMultiStorage().getProviderNames(),\n getUrl: (key: string, options?: { expiresIn?: number }) => getMultiStorage().getUrl(key, options),\n list: (options?: ListOptions & { provider?: string }) => getMultiStorage().list(options),\n upload: (\n key: string,\n data: ArrayBuffer | Blob | Buffer | File | ReadableStream,\n options?: UploadOptions & { provider?: string },\n ) => getMultiStorage().upload(key, data, options),\n};\n"],"mappings":"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"}
|