@kumix/storage 0.1.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.
@@ -0,0 +1,410 @@
1
+ //#region src/config.ts
2
+ function getDefaultEnv() {
3
+ if (typeof process !== "undefined" && process?.env) return process.env;
4
+ }
5
+ function resolveEnv(env) {
6
+ return env ?? getDefaultEnv();
7
+ }
8
+ /**
9
+ * Environment variable names for storage configuration
10
+ * @public
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * import { ENV_VARS } from '@kumix/storage';
15
+ *
16
+ * // Check if specific env vars are set
17
+ * console.log(process.env[ENV_VARS.KUMIX_S3_BUCKET]);
18
+ * console.log(process.env[ENV_VARS.KUMIX_CLOUDINARY_CLOUD_NAME]);
19
+ * ```
20
+ */
21
+ const ENV_VARS = {
22
+ KUMIX_S3_PROVIDER: "KUMIX_S3_PROVIDER",
23
+ KUMIX_S3_REGION: "KUMIX_S3_REGION",
24
+ KUMIX_S3_BUCKET: "KUMIX_S3_BUCKET",
25
+ KUMIX_S3_ACCESS_KEY_ID: "KUMIX_S3_ACCESS_KEY_ID",
26
+ KUMIX_S3_SECRET_ACCESS_KEY: "KUMIX_S3_SECRET_ACCESS_KEY",
27
+ KUMIX_S3_ENDPOINT: "KUMIX_S3_ENDPOINT",
28
+ KUMIX_S3_FORCE_PATH_STYLE: "KUMIX_S3_FORCE_PATH_STYLE",
29
+ KUMIX_S3_PUBLIC_URL: "KUMIX_S3_PUBLIC_URL",
30
+ KUMIX_CLOUDINARY_CLOUD_NAME: "KUMIX_CLOUDINARY_CLOUD_NAME",
31
+ KUMIX_CLOUDINARY_API_KEY: "KUMIX_CLOUDINARY_API_KEY",
32
+ KUMIX_CLOUDINARY_API_SECRET: "KUMIX_CLOUDINARY_API_SECRET",
33
+ KUMIX_CLOUDINARY_SECURE: "KUMIX_CLOUDINARY_SECURE",
34
+ KUMIX_CLOUDINARY_FOLDER: "KUMIX_CLOUDINARY_FOLDER"
35
+ };
36
+ /**
37
+ * Get environment variable value
38
+ * @param key - Environment variable name
39
+ * @param env - Optional environment record
40
+ * @internal
41
+ */
42
+ function getEnvVar(key, env) {
43
+ const e = resolveEnv(env);
44
+ if (!e) return void 0;
45
+ return e[key];
46
+ }
47
+ /**
48
+ * Get required environment variable value
49
+ * @param key - Environment variable name
50
+ * @param env - Optional environment record
51
+ * @internal
52
+ */
53
+ function getRequiredEnvVar(key, env) {
54
+ const value = getEnvVar(key, env);
55
+ if (!value) throw new Error(`Missing required environment variable: ${key}`);
56
+ return value;
57
+ }
58
+ /**
59
+ * Get boolean environment variable value
60
+ * @param key - Environment variable name
61
+ * @param defaultValue - Default boolean value if not set
62
+ * @param env - Optional environment record
63
+ * @internal
64
+ */
65
+ function getBooleanEnvVar(key, defaultValue = false, env) {
66
+ const value = getEnvVar(key, env);
67
+ if (!value) return defaultValue;
68
+ return value.toLowerCase() === "true" || value === "1";
69
+ }
70
+ /**
71
+ * Load S3 configuration from environment variables
72
+ * @param env - Optional environment record
73
+ * @returns S3 configuration object
74
+ * @throws Error if required environment variables are missing
75
+ * @public
76
+ *
77
+ * @example
78
+ * ```typescript
79
+ * import { loadS3Config } from '@kumix/storage';
80
+ *
81
+ * // Set environment variables first:
82
+ * // KUMIX_S3_PROVIDER=aws
83
+ * // KUMIX_S3_REGION=us-east-1
84
+ * // KUMIX_S3_BUCKET=my-bucket
85
+ * // KUMIX_S3_ACCESS_KEY_ID=AKIA...
86
+ * // KUMIX_S3_SECRET_ACCESS_KEY=secret...
87
+ *
88
+ * try {
89
+ * const config = loadS3Config();
90
+ * console.log(config);
91
+ * // Returns: {
92
+ * // provider: 'aws',
93
+ * // region: 'us-east-1',
94
+ * // bucket: 'my-bucket',
95
+ * // accessKeyId: 'AKIA...',
96
+ * // secretAccessKey: 'secret...'
97
+ * // }
98
+ * } catch (error) {
99
+ * console.error('Missing S3 configuration:', error.message);
100
+ * }
101
+ * ```
102
+ */
103
+ function loadS3Config(env) {
104
+ const provider = getRequiredEnvVar(ENV_VARS.KUMIX_S3_PROVIDER, env);
105
+ const validProviders = [
106
+ "aws",
107
+ "cloudflare-r2",
108
+ "minio",
109
+ "digitalocean",
110
+ "supabase",
111
+ "custom"
112
+ ];
113
+ if (!validProviders.includes(provider)) throw new Error(`Invalid S3 provider: ${provider}. Must be one of: ${validProviders.join(", ")}`);
114
+ return {
115
+ provider,
116
+ region: getRequiredEnvVar(ENV_VARS.KUMIX_S3_REGION, env),
117
+ bucket: getRequiredEnvVar(ENV_VARS.KUMIX_S3_BUCKET, env),
118
+ accessKeyId: getRequiredEnvVar(ENV_VARS.KUMIX_S3_ACCESS_KEY_ID, env),
119
+ secretAccessKey: getRequiredEnvVar(ENV_VARS.KUMIX_S3_SECRET_ACCESS_KEY, env),
120
+ endpoint: getEnvVar(ENV_VARS.KUMIX_S3_ENDPOINT, env),
121
+ forcePathStyle: getBooleanEnvVar(ENV_VARS.KUMIX_S3_FORCE_PATH_STYLE, false, env),
122
+ publicUrl: getEnvVar(ENV_VARS.KUMIX_S3_PUBLIC_URL, env)
123
+ };
124
+ }
125
+ /**
126
+ * Load Cloudinary configuration from environment variables
127
+ * @param env - Optional environment record
128
+ * @returns Cloudinary configuration object
129
+ * @throws Error if required environment variables are missing
130
+ * @public
131
+ *
132
+ * @example
133
+ * ```typescript
134
+ * import { loadCloudinaryConfig } from '@kumix/storage';
135
+ *
136
+ * // Set environment variables first:
137
+ * // KUMIX_CLOUDINARY_CLOUD_NAME=my-cloud
138
+ * // KUMIX_CLOUDINARY_API_KEY=123456789
139
+ * // KUMIX_CLOUDINARY_API_SECRET=secret...
140
+ * // KUMIX_CLOUDINARY_SECURE=true (optional)
141
+ * // KUMIX_CLOUDINARY_FOLDER=uploads (optional)
142
+ *
143
+ * try {
144
+ * const config = loadCloudinaryConfig();
145
+ * console.log(config);
146
+ * // Returns: {
147
+ * // provider: 'cloudinary',
148
+ * // cloudName: 'my-cloud',
149
+ * // apiKey: '123456789',
150
+ * // apiSecret: 'secret...',
151
+ * // secure: true,
152
+ * // folder: 'uploads'
153
+ * // }
154
+ * } catch (error) {
155
+ * console.error('Missing Cloudinary configuration:', error.message);
156
+ * }
157
+ * ```
158
+ */
159
+ function loadCloudinaryConfig(env) {
160
+ return {
161
+ provider: "cloudinary",
162
+ cloudName: getRequiredEnvVar(ENV_VARS.KUMIX_CLOUDINARY_CLOUD_NAME, env),
163
+ apiKey: getRequiredEnvVar(ENV_VARS.KUMIX_CLOUDINARY_API_KEY, env),
164
+ apiSecret: getRequiredEnvVar(ENV_VARS.KUMIX_CLOUDINARY_API_SECRET, env),
165
+ secure: getBooleanEnvVar(ENV_VARS.KUMIX_CLOUDINARY_SECURE, true, env),
166
+ folder: getEnvVar(ENV_VARS.KUMIX_CLOUDINARY_FOLDER, env)
167
+ };
168
+ }
169
+ /**
170
+ * Auto-detect and load storage configuration from environment variables
171
+ * Determines the provider based on available environment variables
172
+ * @param env - Optional environment record
173
+ * @returns Storage configuration object (S3 or Cloudinary)
174
+ * @throws Error if no valid configuration is found
175
+ * @public
176
+ *
177
+ * @example
178
+ * ```typescript
179
+ * import { loadStorageConfig } from '@kumix/storage';
180
+ *
181
+ * // Auto-detection based on available env vars
182
+ * try {
183
+ * const config = loadStorageConfig();
184
+ *
185
+ * if (config.provider === 'cloudinary') {
186
+ * console.log('Using Cloudinary:', config.cloudName);
187
+ * } else {
188
+ * console.log('Using S3:', config.provider, config.bucket);
189
+ * }
190
+ * } catch (error) {
191
+ * console.error('No storage configuration found:', error.message);
192
+ * }
193
+ *
194
+ * // Explicit provider (set KUMIX_S3_PROVIDER=cloudinary)
195
+ * // Will load Cloudinary config even if S3 vars are also present
196
+ * ```
197
+ */
198
+ function loadStorageConfig(env) {
199
+ const provider = getEnvVar(ENV_VARS.KUMIX_S3_PROVIDER, env);
200
+ if (provider) {
201
+ if (provider === "cloudinary") return loadCloudinaryConfig(env);
202
+ return loadS3Config(env);
203
+ }
204
+ const hasCloudinaryVars = getEnvVar(ENV_VARS.KUMIX_CLOUDINARY_CLOUD_NAME, env) && getEnvVar(ENV_VARS.KUMIX_CLOUDINARY_API_KEY, env) && getEnvVar(ENV_VARS.KUMIX_CLOUDINARY_API_SECRET, env);
205
+ const hasS3Vars = getEnvVar(ENV_VARS.KUMIX_S3_BUCKET, env) && getEnvVar(ENV_VARS.KUMIX_S3_ACCESS_KEY_ID, env) && getEnvVar(ENV_VARS.KUMIX_S3_SECRET_ACCESS_KEY, env);
206
+ if (hasCloudinaryVars) return loadCloudinaryConfig(env);
207
+ if (hasS3Vars) {
208
+ const config = loadS3Config(env);
209
+ if (!config.provider) config.provider = "aws";
210
+ return config;
211
+ }
212
+ throw new Error("No storage configuration found. Please set either:\n- S3: KUMIX_S3_PROVIDER, KUMIX_S3_REGION, KUMIX_S3_BUCKET, KUMIX_S3_ACCESS_KEY_ID, KUMIX_S3_SECRET_ACCESS_KEY\n- Cloudinary: KUMIX_CLOUDINARY_CLOUD_NAME, KUMIX_CLOUDINARY_API_KEY, KUMIX_CLOUDINARY_API_SECRET");
213
+ }
214
+ /**
215
+ * Check if storage configuration is available in environment variables
216
+ * @param env - Optional environment record
217
+ * @returns True if valid storage configuration is found
218
+ * @public
219
+ *
220
+ * @example
221
+ * ```typescript
222
+ * import { hasStorageConfig, loadStorageConfig } from '@kumix/storage';
223
+ *
224
+ * if (hasStorageConfig()) {
225
+ * const config = loadStorageConfig();
226
+ * console.log('Storage configured:', config.provider);
227
+ * } else {
228
+ * console.log('Please set storage environment variables');
229
+ * }
230
+ *
231
+ * // Use in conditional initialization
232
+ * const storage = hasStorageConfig() ? createStorage() : null;
233
+ * ```
234
+ */
235
+ function hasStorageConfig(env) {
236
+ try {
237
+ loadStorageConfig(env);
238
+ return true;
239
+ } catch {
240
+ return false;
241
+ }
242
+ }
243
+ /**
244
+ * Check if storage configuration is available in environment variables
245
+ * @param env - Optional environment record
246
+ * @returns True if either S3 or Cloudinary configuration is available
247
+ * @public
248
+ *
249
+ * @example
250
+ * ```typescript
251
+ * import { isStorageConfigured, createS3, createCloudinary } from '@kumix/storage';
252
+ *
253
+ * if (isStorageConfigured()) {
254
+ * // Choose your preferred provider
255
+ * const s3 = createS3();
256
+ * // OR
257
+ * const cloudinary = createCloudinary();
258
+ *
259
+ * await s3.uploadFile('test.txt', 'Hello World');
260
+ * } else {
261
+ * console.log('Storage not configured. Please set environment variables.');
262
+ * }
263
+ *
264
+ * // Use in conditional initialization
265
+ * const storage = isStorageConfigured() ? createS3() : null;
266
+ * if (storage) {
267
+ * await storage.uploadFile('file.txt', content);
268
+ * }
269
+ * ```
270
+ */
271
+ function isStorageConfigured(env) {
272
+ return hasStorageConfig(env);
273
+ }
274
+ /**
275
+ * Get storage provider name from environment variables without loading full config
276
+ * @param env - Optional environment record
277
+ * @returns Provider name or undefined if not configured
278
+ * @public
279
+ *
280
+ * @example
281
+ * ```typescript
282
+ * import { getStorageProvider } from '@kumix/storage';
283
+ *
284
+ * const provider = getStorageProvider();
285
+ *
286
+ * switch (provider) {
287
+ * case 'aws':
288
+ * console.log('Using AWS S3');
289
+ * break;
290
+ * case 'cloudinary':
291
+ * console.log('Using Cloudinary');
292
+ * break;
293
+ * case 'cloudflare-r2':
294
+ * console.log('Using Cloudflare R2');
295
+ * break;
296
+ * default:
297
+ * console.log('No storage provider configured');
298
+ * }
299
+ *
300
+ * // Quick check without throwing errors
301
+ * if (getStorageProvider()) {
302
+ * // Storage is configured
303
+ * }
304
+ * ```
305
+ */
306
+ function getStorageProvider(env) {
307
+ const provider = getEnvVar(ENV_VARS.KUMIX_S3_PROVIDER, env);
308
+ if (provider) return provider;
309
+ const hasCloudinaryVars = getEnvVar(ENV_VARS.KUMIX_CLOUDINARY_CLOUD_NAME, env);
310
+ const hasS3Vars = getEnvVar(ENV_VARS.KUMIX_S3_BUCKET, env);
311
+ if (hasCloudinaryVars) return "cloudinary";
312
+ if (hasS3Vars) return "aws";
313
+ }
314
+ /**
315
+ * Validate if all required environment variables are set for S3
316
+ * @param env - Optional environment record
317
+ * @returns Validation result with missing variables
318
+ * @public
319
+ *
320
+ * @example
321
+ * ```typescript
322
+ * import { validateS3EnvVars } from '@kumix/storage';
323
+ *
324
+ * const validation = validateS3EnvVars();
325
+ *
326
+ * if (validation.valid) {
327
+ * console.log('S3 configuration is complete');
328
+ * } else {
329
+ * console.log('Missing S3 variables:', validation.missing);
330
+ * // Returns: ["KUMIX_S3_REGION", "KUMIX_S3_BUCKET"]
331
+ * }
332
+ * ```
333
+ */
334
+ function validateS3EnvVars(env) {
335
+ const missing = [
336
+ ENV_VARS.KUMIX_S3_PROVIDER,
337
+ ENV_VARS.KUMIX_S3_REGION,
338
+ ENV_VARS.KUMIX_S3_BUCKET,
339
+ ENV_VARS.KUMIX_S3_ACCESS_KEY_ID,
340
+ ENV_VARS.KUMIX_S3_SECRET_ACCESS_KEY
341
+ ].filter((key) => !getEnvVar(key, env));
342
+ return {
343
+ valid: missing.length === 0,
344
+ missing
345
+ };
346
+ }
347
+ /**
348
+ * Validate if all required environment variables are set for Cloudinary
349
+ * @param env - Optional environment record
350
+ * @returns Validation result with missing variables
351
+ * @public
352
+ *
353
+ * @example
354
+ * ```typescript
355
+ * import { validateCloudinaryEnvVars } from '@kumix/storage';
356
+ *
357
+ * const validation = validateCloudinaryEnvVars();
358
+ *
359
+ * if (validation.valid) {
360
+ * console.log('Cloudinary configuration is complete');
361
+ * } else {
362
+ * console.log('Missing Cloudinary variables:', validation.missing);
363
+ * // Returns: ["KUMIX_CLOUDINARY_API_KEY"]
364
+ * }
365
+ * ```
366
+ */
367
+ function validateCloudinaryEnvVars(env) {
368
+ const missing = [
369
+ ENV_VARS.KUMIX_CLOUDINARY_CLOUD_NAME,
370
+ ENV_VARS.KUMIX_CLOUDINARY_API_KEY,
371
+ ENV_VARS.KUMIX_CLOUDINARY_API_SECRET
372
+ ].filter((key) => !getEnvVar(key, env));
373
+ return {
374
+ valid: missing.length === 0,
375
+ missing
376
+ };
377
+ }
378
+ /**
379
+ * Get all available environment variables for debugging
380
+ * @param env - Optional environment record
381
+ * @returns Object containing all storage-related env vars
382
+ * @public
383
+ *
384
+ * @example
385
+ * ```typescript
386
+ * import { getStorageEnvVars } from '@kumix/storage';
387
+ *
388
+ * const envVars = getStorageEnvVars();
389
+ * console.log('Storage environment variables:', envVars);
390
+ * // Returns: {
391
+ * // KUMIX_S3_PROVIDER: 'aws',
392
+ * // KUMIX_S3_REGION: 'us-east-1',
393
+ * // KUMIX_S3_BUCKET: 'my-bucket',
394
+ * // // ... other set variables (secrets are masked)
395
+ * // }
396
+ * ```
397
+ */
398
+ function getStorageEnvVars(env) {
399
+ const result = {};
400
+ Object.values(ENV_VARS).forEach((key) => {
401
+ const value = getEnvVar(key, env);
402
+ if (value) if (key.includes("SECRET") || key.includes("API_SECRET")) result[key] = `${value.substring(0, 4)}***`;
403
+ else result[key] = value;
404
+ });
405
+ return result;
406
+ }
407
+ //#endregion
408
+ export { isStorageConfigured as a, loadStorageConfig as c, hasStorageConfig as i, validateCloudinaryEnvVars as l, getStorageEnvVars as n, loadCloudinaryConfig as o, getStorageProvider as r, loadS3Config as s, ENV_VARS as t, validateS3EnvVars as u };
409
+
410
+ //# sourceMappingURL=config-t-NVJICl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-t-NVJICl.js","names":[],"sources":["../src/config.ts"],"sourcesContent":["/**\n * Storage configuration from environment variables\n * Provides automatic configuration loading from environment variables\n */\n\nimport type { CloudinaryConfig, S3Config, StorageConfig } from \"./types\";\n\n/**\n * Cross-runtime environment record.\n * Pass `process.env` on Node.js, `ctx.env` on Cloudflare Workers,\n * `Deno.env.toObject()` on Deno, or a plain object in the browser.\n */\nexport type EnvRecord = Record<string, string | undefined>;\n\nfunction getDefaultEnv(): EnvRecord | undefined {\n if (typeof process !== \"undefined\" && process?.env) {\n return process.env as EnvRecord;\n }\n return undefined;\n}\n\nfunction resolveEnv(env?: EnvRecord): EnvRecord | undefined {\n return env ?? getDefaultEnv();\n}\n\n/**\n * Environment variable names for storage configuration\n * @public\n *\n * @example\n * ```typescript\n * import { ENV_VARS } from '@kumix/storage';\n *\n * // Check if specific env vars are set\n * console.log(process.env[ENV_VARS.KUMIX_S3_BUCKET]);\n * console.log(process.env[ENV_VARS.KUMIX_CLOUDINARY_CLOUD_NAME]);\n * ```\n */\nexport const ENV_VARS = {\n // S3 Configuration\n KUMIX_S3_PROVIDER: \"KUMIX_S3_PROVIDER\",\n KUMIX_S3_REGION: \"KUMIX_S3_REGION\",\n KUMIX_S3_BUCKET: \"KUMIX_S3_BUCKET\",\n KUMIX_S3_ACCESS_KEY_ID: \"KUMIX_S3_ACCESS_KEY_ID\",\n KUMIX_S3_SECRET_ACCESS_KEY: \"KUMIX_S3_SECRET_ACCESS_KEY\",\n KUMIX_S3_ENDPOINT: \"KUMIX_S3_ENDPOINT\",\n KUMIX_S3_FORCE_PATH_STYLE: \"KUMIX_S3_FORCE_PATH_STYLE\",\n KUMIX_S3_PUBLIC_URL: \"KUMIX_S3_PUBLIC_URL\",\n\n // Cloudinary Configuration\n KUMIX_CLOUDINARY_CLOUD_NAME: \"KUMIX_CLOUDINARY_CLOUD_NAME\",\n KUMIX_CLOUDINARY_API_KEY: \"KUMIX_CLOUDINARY_API_KEY\",\n KUMIX_CLOUDINARY_API_SECRET: \"KUMIX_CLOUDINARY_API_SECRET\",\n KUMIX_CLOUDINARY_SECURE: \"KUMIX_CLOUDINARY_SECURE\",\n KUMIX_CLOUDINARY_FOLDER: \"KUMIX_CLOUDINARY_FOLDER\",\n} as const;\n\n/**\n * Get environment variable value\n * @param key - Environment variable name\n * @param env - Optional environment record\n * @internal\n */\nfunction getEnvVar(key: string, env?: EnvRecord): string | undefined {\n const e = resolveEnv(env);\n if (!e) return undefined;\n return e[key];\n}\n\n/**\n * Get required environment variable value\n * @param key - Environment variable name\n * @param env - Optional environment record\n * @internal\n */\nfunction getRequiredEnvVar(key: string, env?: EnvRecord): string {\n const value = getEnvVar(key, env);\n if (!value) {\n throw new Error(`Missing required environment variable: ${key}`);\n }\n return value;\n}\n\n/**\n * Get boolean environment variable value\n * @param key - Environment variable name\n * @param defaultValue - Default boolean value if not set\n * @param env - Optional environment record\n * @internal\n */\nfunction getBooleanEnvVar(key: string, defaultValue = false, env?: EnvRecord): boolean {\n const value = getEnvVar(key, env);\n if (!value) return defaultValue;\n return value.toLowerCase() === \"true\" || value === \"1\";\n}\n\n/**\n * Load S3 configuration from environment variables\n * @param env - Optional environment record\n * @returns S3 configuration object\n * @throws Error if required environment variables are missing\n * @public\n *\n * @example\n * ```typescript\n * import { loadS3Config } from '@kumix/storage';\n *\n * // Set environment variables first:\n * // KUMIX_S3_PROVIDER=aws\n * // KUMIX_S3_REGION=us-east-1\n * // KUMIX_S3_BUCKET=my-bucket\n * // KUMIX_S3_ACCESS_KEY_ID=AKIA...\n * // KUMIX_S3_SECRET_ACCESS_KEY=secret...\n *\n * try {\n * const config = loadS3Config();\n * console.log(config);\n * // Returns: {\n * // provider: 'aws',\n * // region: 'us-east-1',\n * // bucket: 'my-bucket',\n * // accessKeyId: 'AKIA...',\n * // secretAccessKey: 'secret...'\n * // }\n * } catch (error) {\n * console.error('Missing S3 configuration:', error.message);\n * }\n * ```\n */\nexport function loadS3Config(env?: EnvRecord): S3Config {\n const provider = getRequiredEnvVar(ENV_VARS.KUMIX_S3_PROVIDER, env) as S3Config[\"provider\"];\n\n // Validate provider\n const validProviders: S3Config[\"provider\"][] = [\n \"aws\",\n \"cloudflare-r2\",\n \"minio\",\n \"digitalocean\",\n \"supabase\",\n \"custom\",\n ];\n if (!validProviders.includes(provider)) {\n throw new Error(\n `Invalid S3 provider: ${provider}. Must be one of: ${validProviders.join(\", \")}`,\n );\n }\n\n return {\n provider,\n region: getRequiredEnvVar(ENV_VARS.KUMIX_S3_REGION, env),\n bucket: getRequiredEnvVar(ENV_VARS.KUMIX_S3_BUCKET, env),\n accessKeyId: getRequiredEnvVar(ENV_VARS.KUMIX_S3_ACCESS_KEY_ID, env),\n secretAccessKey: getRequiredEnvVar(ENV_VARS.KUMIX_S3_SECRET_ACCESS_KEY, env),\n endpoint: getEnvVar(ENV_VARS.KUMIX_S3_ENDPOINT, env),\n forcePathStyle: getBooleanEnvVar(ENV_VARS.KUMIX_S3_FORCE_PATH_STYLE, false, env),\n publicUrl: getEnvVar(ENV_VARS.KUMIX_S3_PUBLIC_URL, env),\n };\n}\n\n/**\n * Load Cloudinary configuration from environment variables\n * @param env - Optional environment record\n * @returns Cloudinary configuration object\n * @throws Error if required environment variables are missing\n * @public\n *\n * @example\n * ```typescript\n * import { loadCloudinaryConfig } from '@kumix/storage';\n *\n * // Set environment variables first:\n * // KUMIX_CLOUDINARY_CLOUD_NAME=my-cloud\n * // KUMIX_CLOUDINARY_API_KEY=123456789\n * // KUMIX_CLOUDINARY_API_SECRET=secret...\n * // KUMIX_CLOUDINARY_SECURE=true (optional)\n * // KUMIX_CLOUDINARY_FOLDER=uploads (optional)\n *\n * try {\n * const config = loadCloudinaryConfig();\n * console.log(config);\n * // Returns: {\n * // provider: 'cloudinary',\n * // cloudName: 'my-cloud',\n * // apiKey: '123456789',\n * // apiSecret: 'secret...',\n * // secure: true,\n * // folder: 'uploads'\n * // }\n * } catch (error) {\n * console.error('Missing Cloudinary configuration:', error.message);\n * }\n * ```\n */\nexport function loadCloudinaryConfig(env?: EnvRecord): CloudinaryConfig {\n return {\n provider: \"cloudinary\",\n cloudName: getRequiredEnvVar(ENV_VARS.KUMIX_CLOUDINARY_CLOUD_NAME, env),\n apiKey: getRequiredEnvVar(ENV_VARS.KUMIX_CLOUDINARY_API_KEY, env),\n apiSecret: getRequiredEnvVar(ENV_VARS.KUMIX_CLOUDINARY_API_SECRET, env),\n secure: getBooleanEnvVar(ENV_VARS.KUMIX_CLOUDINARY_SECURE, true, env),\n folder: getEnvVar(ENV_VARS.KUMIX_CLOUDINARY_FOLDER, env),\n };\n}\n\n/**\n * Auto-detect and load storage configuration from environment variables\n * Determines the provider based on available environment variables\n * @param env - Optional environment record\n * @returns Storage configuration object (S3 or Cloudinary)\n * @throws Error if no valid configuration is found\n * @public\n *\n * @example\n * ```typescript\n * import { loadStorageConfig } from '@kumix/storage';\n *\n * // Auto-detection based on available env vars\n * try {\n * const config = loadStorageConfig();\n *\n * if (config.provider === 'cloudinary') {\n * console.log('Using Cloudinary:', config.cloudName);\n * } else {\n * console.log('Using S3:', config.provider, config.bucket);\n * }\n * } catch (error) {\n * console.error('No storage configuration found:', error.message);\n * }\n *\n * // Explicit provider (set KUMIX_S3_PROVIDER=cloudinary)\n * // Will load Cloudinary config even if S3 vars are also present\n * ```\n */\nexport function loadStorageConfig(env?: EnvRecord): StorageConfig {\n const provider = getEnvVar(ENV_VARS.KUMIX_S3_PROVIDER, env);\n\n // If provider is explicitly set, use it\n if (provider) {\n if (provider === \"cloudinary\") {\n return loadCloudinaryConfig(env);\n }\n return loadS3Config(env);\n }\n\n // Auto-detect based on available environment variables\n const hasCloudinaryVars =\n getEnvVar(ENV_VARS.KUMIX_CLOUDINARY_CLOUD_NAME, env) &&\n getEnvVar(ENV_VARS.KUMIX_CLOUDINARY_API_KEY, env) &&\n getEnvVar(ENV_VARS.KUMIX_CLOUDINARY_API_SECRET, env);\n\n const hasS3Vars =\n getEnvVar(ENV_VARS.KUMIX_S3_BUCKET, env) &&\n getEnvVar(ENV_VARS.KUMIX_S3_ACCESS_KEY_ID, env) &&\n getEnvVar(ENV_VARS.KUMIX_S3_SECRET_ACCESS_KEY, env);\n\n if (hasCloudinaryVars) {\n return loadCloudinaryConfig(env);\n }\n if (hasS3Vars) {\n // Default to AWS if no provider specified\n const config = loadS3Config(env);\n if (!config.provider) {\n config.provider = \"aws\";\n }\n return config;\n }\n\n throw new Error(\n \"No storage configuration found. Please set either:\\n\" +\n \"- S3: KUMIX_S3_PROVIDER, KUMIX_S3_REGION, KUMIX_S3_BUCKET, KUMIX_S3_ACCESS_KEY_ID, KUMIX_S3_SECRET_ACCESS_KEY\\n\" +\n \"- Cloudinary: KUMIX_CLOUDINARY_CLOUD_NAME, KUMIX_CLOUDINARY_API_KEY, KUMIX_CLOUDINARY_API_SECRET\",\n );\n}\n\n/**\n * Check if storage configuration is available in environment variables\n * @param env - Optional environment record\n * @returns True if valid storage configuration is found\n * @public\n *\n * @example\n * ```typescript\n * import { hasStorageConfig, loadStorageConfig } from '@kumix/storage';\n *\n * if (hasStorageConfig()) {\n * const config = loadStorageConfig();\n * console.log('Storage configured:', config.provider);\n * } else {\n * console.log('Please set storage environment variables');\n * }\n *\n * // Use in conditional initialization\n * const storage = hasStorageConfig() ? createStorage() : null;\n * ```\n */\nexport function hasStorageConfig(env?: EnvRecord): boolean {\n try {\n loadStorageConfig(env);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Check if storage configuration is available in environment variables\n * @param env - Optional environment record\n * @returns True if either S3 or Cloudinary configuration is available\n * @public\n *\n * @example\n * ```typescript\n * import { isStorageConfigured, createS3, createCloudinary } from '@kumix/storage';\n *\n * if (isStorageConfigured()) {\n * // Choose your preferred provider\n * const s3 = createS3();\n * // OR\n * const cloudinary = createCloudinary();\n *\n * await s3.uploadFile('test.txt', 'Hello World');\n * } else {\n * console.log('Storage not configured. Please set environment variables.');\n * }\n *\n * // Use in conditional initialization\n * const storage = isStorageConfigured() ? createS3() : null;\n * if (storage) {\n * await storage.uploadFile('file.txt', content);\n * }\n * ```\n */\nexport function isStorageConfigured(env?: EnvRecord): boolean {\n return hasStorageConfig(env);\n}\n\n/**\n * Get storage provider name from environment variables without loading full config\n * @param env - Optional environment record\n * @returns Provider name or undefined if not configured\n * @public\n *\n * @example\n * ```typescript\n * import { getStorageProvider } from '@kumix/storage';\n *\n * const provider = getStorageProvider();\n *\n * switch (provider) {\n * case 'aws':\n * console.log('Using AWS S3');\n * break;\n * case 'cloudinary':\n * console.log('Using Cloudinary');\n * break;\n * case 'cloudflare-r2':\n * console.log('Using Cloudflare R2');\n * break;\n * default:\n * console.log('No storage provider configured');\n * }\n *\n * // Quick check without throwing errors\n * if (getStorageProvider()) {\n * // Storage is configured\n * }\n * ```\n */\nexport function getStorageProvider(env?: EnvRecord): string | undefined {\n const provider = getEnvVar(ENV_VARS.KUMIX_S3_PROVIDER, env);\n if (provider) return provider;\n\n // Auto-detect\n const hasCloudinaryVars = getEnvVar(ENV_VARS.KUMIX_CLOUDINARY_CLOUD_NAME, env);\n const hasS3Vars = getEnvVar(ENV_VARS.KUMIX_S3_BUCKET, env);\n\n if (hasCloudinaryVars) return \"cloudinary\";\n if (hasS3Vars) return \"aws\"; // Default S3 provider\n\n return undefined;\n}\n\n/**\n * Validate if all required environment variables are set for S3\n * @param env - Optional environment record\n * @returns Validation result with missing variables\n * @public\n *\n * @example\n * ```typescript\n * import { validateS3EnvVars } from '@kumix/storage';\n *\n * const validation = validateS3EnvVars();\n *\n * if (validation.valid) {\n * console.log('S3 configuration is complete');\n * } else {\n * console.log('Missing S3 variables:', validation.missing);\n * // Returns: [\"KUMIX_S3_REGION\", \"KUMIX_S3_BUCKET\"]\n * }\n * ```\n */\nexport function validateS3EnvVars(env?: EnvRecord): {\n valid: boolean;\n missing: string[];\n} {\n const required = [\n ENV_VARS.KUMIX_S3_PROVIDER,\n ENV_VARS.KUMIX_S3_REGION,\n ENV_VARS.KUMIX_S3_BUCKET,\n ENV_VARS.KUMIX_S3_ACCESS_KEY_ID,\n ENV_VARS.KUMIX_S3_SECRET_ACCESS_KEY,\n ];\n\n const missing = required.filter((key) => !getEnvVar(key, env));\n\n return {\n valid: missing.length === 0,\n missing,\n };\n}\n\n/**\n * Validate if all required environment variables are set for Cloudinary\n * @param env - Optional environment record\n * @returns Validation result with missing variables\n * @public\n *\n * @example\n * ```typescript\n * import { validateCloudinaryEnvVars } from '@kumix/storage';\n *\n * const validation = validateCloudinaryEnvVars();\n *\n * if (validation.valid) {\n * console.log('Cloudinary configuration is complete');\n * } else {\n * console.log('Missing Cloudinary variables:', validation.missing);\n * // Returns: [\"KUMIX_CLOUDINARY_API_KEY\"]\n * }\n * ```\n */\nexport function validateCloudinaryEnvVars(env?: EnvRecord): {\n valid: boolean;\n missing: string[];\n} {\n const required = [\n ENV_VARS.KUMIX_CLOUDINARY_CLOUD_NAME,\n ENV_VARS.KUMIX_CLOUDINARY_API_KEY,\n ENV_VARS.KUMIX_CLOUDINARY_API_SECRET,\n ];\n\n const missing = required.filter((key) => !getEnvVar(key, env));\n\n return {\n valid: missing.length === 0,\n missing,\n };\n}\n\n/**\n * Get all available environment variables for debugging\n * @param env - Optional environment record\n * @returns Object containing all storage-related env vars\n * @public\n *\n * @example\n * ```typescript\n * import { getStorageEnvVars } from '@kumix/storage';\n *\n * const envVars = getStorageEnvVars();\n * console.log('Storage environment variables:', envVars);\n * // Returns: {\n * // KUMIX_S3_PROVIDER: 'aws',\n * // KUMIX_S3_REGION: 'us-east-1',\n * // KUMIX_S3_BUCKET: 'my-bucket',\n * // // ... other set variables (secrets are masked)\n * // }\n * ```\n */\nexport function getStorageEnvVars(env?: EnvRecord): Record<string, string | undefined> {\n const result: Record<string, string | undefined> = {};\n\n Object.values(ENV_VARS).forEach((key) => {\n const value = getEnvVar(key, env);\n if (value) {\n // Mask sensitive values\n if (key.includes(\"SECRET\") || key.includes(\"API_SECRET\")) {\n result[key] = `${value.substring(0, 4)}***`;\n } else {\n result[key] = value;\n }\n }\n });\n\n return result;\n}\n"],"mappings":"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"}