express-storage 1.0.0 → 1.1.2

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.
Files changed (48) hide show
  1. package/README.md +519 -348
  2. package/dist/drivers/azure.driver.d.ts +88 -0
  3. package/dist/drivers/azure.driver.d.ts.map +1 -0
  4. package/dist/drivers/azure.driver.js +367 -0
  5. package/dist/drivers/azure.driver.js.map +1 -0
  6. package/dist/drivers/base.driver.d.ts +125 -24
  7. package/dist/drivers/base.driver.d.ts.map +1 -1
  8. package/dist/drivers/base.driver.js +248 -62
  9. package/dist/drivers/base.driver.js.map +1 -1
  10. package/dist/drivers/gcs.driver.d.ts +60 -13
  11. package/dist/drivers/gcs.driver.d.ts.map +1 -1
  12. package/dist/drivers/gcs.driver.js +242 -41
  13. package/dist/drivers/gcs.driver.js.map +1 -1
  14. package/dist/drivers/local.driver.d.ts +89 -12
  15. package/dist/drivers/local.driver.d.ts.map +1 -1
  16. package/dist/drivers/local.driver.js +533 -45
  17. package/dist/drivers/local.driver.js.map +1 -1
  18. package/dist/drivers/s3.driver.d.ts +64 -13
  19. package/dist/drivers/s3.driver.d.ts.map +1 -1
  20. package/dist/drivers/s3.driver.js +269 -41
  21. package/dist/drivers/s3.driver.js.map +1 -1
  22. package/dist/factory/driver.factory.d.ts +35 -29
  23. package/dist/factory/driver.factory.d.ts.map +1 -1
  24. package/dist/factory/driver.factory.js +119 -59
  25. package/dist/factory/driver.factory.js.map +1 -1
  26. package/dist/index.d.ts +23 -22
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +26 -46
  29. package/dist/index.js.map +1 -1
  30. package/dist/storage-manager.d.ts +205 -52
  31. package/dist/storage-manager.d.ts.map +1 -1
  32. package/dist/storage-manager.js +644 -73
  33. package/dist/storage-manager.js.map +1 -1
  34. package/dist/types/storage.types.d.ts +243 -18
  35. package/dist/types/storage.types.d.ts.map +1 -1
  36. package/dist/utils/config.utils.d.ts +28 -4
  37. package/dist/utils/config.utils.d.ts.map +1 -1
  38. package/dist/utils/config.utils.js +121 -47
  39. package/dist/utils/config.utils.js.map +1 -1
  40. package/dist/utils/file.utils.d.ts +111 -14
  41. package/dist/utils/file.utils.d.ts.map +1 -1
  42. package/dist/utils/file.utils.js +215 -32
  43. package/dist/utils/file.utils.js.map +1 -1
  44. package/package.json +51 -27
  45. package/dist/drivers/oci.driver.d.ts +0 -37
  46. package/dist/drivers/oci.driver.d.ts.map +0 -1
  47. package/dist/drivers/oci.driver.js +0 -84
  48. package/dist/drivers/oci.driver.js.map +0 -1
@@ -1,115 +1,176 @@
1
1
  import dotenv from 'dotenv';
2
- // Load environment variables
3
- dotenv.config();
4
- // Environment variable keys
2
+ let dotenvInitialized = false;
3
+ /**
4
+ * Loads your .env file if it hasn't been loaded already.
5
+ * Safe to call multiple times — it only runs once.
6
+ */
7
+ export function initializeDotenv() {
8
+ if (!dotenvInitialized) {
9
+ dotenv.config();
10
+ dotenvInitialized = true;
11
+ }
12
+ }
5
13
  const ENV_KEYS = {
6
14
  FILE_DRIVER: 'FILE_DRIVER',
7
15
  BUCKET_NAME: 'BUCKET_NAME',
16
+ BUCKET_PATH: 'BUCKET_PATH',
8
17
  LOCAL_PATH: 'LOCAL_PATH',
9
18
  PRESIGNED_URL_EXPIRY: 'PRESIGNED_URL_EXPIRY',
10
- // AWS S3
19
+ MAX_FILE_SIZE: 'MAX_FILE_SIZE',
11
20
  AWS_REGION: 'AWS_REGION',
12
21
  AWS_ACCESS_KEY: 'AWS_ACCESS_KEY',
13
22
  AWS_SECRET_KEY: 'AWS_SECRET_KEY',
14
- // Google Cloud Storage
15
23
  GCS_PROJECT_ID: 'GCS_PROJECT_ID',
16
24
  GCS_CREDENTIALS: 'GCS_CREDENTIALS',
17
- // Oracle Cloud Infrastructure
18
- OCI_REGION: 'OCI_REGION',
19
- OCI_CREDENTIALS: 'OCI_CREDENTIALS',
25
+ AZURE_CONNECTION_STRING: 'AZURE_CONNECTION_STRING',
26
+ AZURE_ACCOUNT_NAME: 'AZURE_ACCOUNT_NAME',
27
+ AZURE_ACCOUNT_KEY: 'AZURE_ACCOUNT_KEY',
20
28
  };
21
- // Default configuration
22
29
  const DEFAULT_CONFIG = {
23
- presignedUrlExpiry: 600, // 10 minutes
30
+ presignedUrlExpiry: 600,
24
31
  localPath: 'public/express-storage',
25
32
  };
26
33
  /**
27
- * Load environment configuration
34
+ * Reads storage configuration from environment variables.
35
+ * Automatically loads .env on first call.
28
36
  */
29
37
  export function loadEnvironmentConfig() {
38
+ initializeDotenv();
30
39
  return {
31
40
  FILE_DRIVER: process.env[ENV_KEYS.FILE_DRIVER] || '',
32
41
  BUCKET_NAME: process.env[ENV_KEYS.BUCKET_NAME] || undefined,
42
+ BUCKET_PATH: process.env[ENV_KEYS.BUCKET_PATH] || undefined,
33
43
  LOCAL_PATH: process.env[ENV_KEYS.LOCAL_PATH] || undefined,
34
44
  PRESIGNED_URL_EXPIRY: process.env[ENV_KEYS.PRESIGNED_URL_EXPIRY] || undefined,
35
- // AWS S3
45
+ MAX_FILE_SIZE: process.env[ENV_KEYS.MAX_FILE_SIZE] || undefined,
36
46
  AWS_REGION: process.env[ENV_KEYS.AWS_REGION] || undefined,
37
47
  AWS_ACCESS_KEY: process.env[ENV_KEYS.AWS_ACCESS_KEY] || undefined,
38
48
  AWS_SECRET_KEY: process.env[ENV_KEYS.AWS_SECRET_KEY] || undefined,
39
- // Google Cloud Storage
40
49
  GCS_PROJECT_ID: process.env[ENV_KEYS.GCS_PROJECT_ID] || undefined,
41
50
  GCS_CREDENTIALS: process.env[ENV_KEYS.GCS_CREDENTIALS] || undefined,
42
- // Oracle Cloud Infrastructure
43
- OCI_REGION: process.env[ENV_KEYS.OCI_REGION] || undefined,
44
- OCI_CREDENTIALS: process.env[ENV_KEYS.OCI_CREDENTIALS] || undefined,
51
+ AZURE_CONNECTION_STRING: process.env[ENV_KEYS.AZURE_CONNECTION_STRING] || undefined,
52
+ AZURE_ACCOUNT_NAME: process.env[ENV_KEYS.AZURE_ACCOUNT_NAME] || undefined,
53
+ AZURE_ACCOUNT_KEY: process.env[ENV_KEYS.AZURE_ACCOUNT_KEY] || undefined,
45
54
  };
46
55
  }
47
56
  /**
48
- * Convert environment config to storage config
57
+ * Safely parses a string to an integer, returning a default for invalid values.
58
+ *
59
+ * Unlike parseInt(), this function rejects strings with trailing non-numeric characters.
60
+ * For example, "100abc" returns the default value, not 100.
61
+ */
62
+ function parseIntSafe(value, defaultValue) {
63
+ if (!value)
64
+ return defaultValue;
65
+ // Trim whitespace and check if the entire string is a valid integer
66
+ const trimmed = value.trim();
67
+ // Check if the string matches a valid integer pattern (optional sign followed by digits)
68
+ if (!/^-?\d+$/.test(trimmed)) {
69
+ return defaultValue;
70
+ }
71
+ const parsed = parseInt(trimmed, 10);
72
+ return Number.isNaN(parsed) ? defaultValue : parsed;
73
+ }
74
+ /**
75
+ * Converts environment variables into a StorageConfig object.
49
76
  */
50
77
  export function environmentToStorageConfig(envConfig) {
51
78
  const config = {
52
79
  driver: envConfig.FILE_DRIVER,
53
80
  bucketName: envConfig.BUCKET_NAME,
81
+ bucketPath: envConfig.BUCKET_PATH || '',
54
82
  localPath: envConfig.LOCAL_PATH || DEFAULT_CONFIG.localPath,
55
- presignedUrlExpiry: envConfig.PRESIGNED_URL_EXPIRY
56
- ? parseInt(envConfig.PRESIGNED_URL_EXPIRY, 10)
57
- : DEFAULT_CONFIG.presignedUrlExpiry,
58
- // AWS S3
83
+ presignedUrlExpiry: parseIntSafe(envConfig.PRESIGNED_URL_EXPIRY, DEFAULT_CONFIG.presignedUrlExpiry),
84
+ maxFileSize: parseIntSafe(envConfig.MAX_FILE_SIZE, undefined),
59
85
  awsRegion: envConfig.AWS_REGION,
60
86
  awsAccessKey: envConfig.AWS_ACCESS_KEY,
61
87
  awsSecretKey: envConfig.AWS_SECRET_KEY,
62
- // Google Cloud Storage
63
88
  gcsProjectId: envConfig.GCS_PROJECT_ID,
64
89
  gcsCredentials: envConfig.GCS_CREDENTIALS,
65
- // Oracle Cloud Infrastructure
66
- ociRegion: envConfig.OCI_REGION,
67
- ociCredentials: envConfig.OCI_CREDENTIALS,
90
+ azureConnectionString: envConfig.AZURE_CONNECTION_STRING,
91
+ azureAccountName: envConfig.AZURE_ACCOUNT_NAME,
92
+ azureAccountKey: envConfig.AZURE_ACCOUNT_KEY,
93
+ azureContainerName: envConfig.BUCKET_NAME, // Use BUCKET_NAME for Azure container
68
94
  };
69
95
  return config;
70
96
  }
71
97
  /**
72
- * Validate storage configuration
98
+ * Validates a storage configuration.
99
+ *
100
+ * Checks that:
101
+ * - A valid driver is specified
102
+ * - Required credentials are present for the chosen driver
103
+ * - Numeric values are within acceptable ranges
104
+ *
105
+ * Returns an object with isValid and an array of error messages.
73
106
  */
74
107
  export function validateStorageConfig(config) {
75
108
  const errors = [];
76
- // Validate driver
109
+ // Check driver
77
110
  if (!config.driver) {
78
111
  errors.push('FILE_DRIVER is required');
79
112
  }
80
- else if (!['s3', 's3-presigned', 'gcs', 'gcs-presigned', 'oci', 'oci-presigned', 'local'].includes(config.driver)) {
81
- errors.push(`Invalid FILE_DRIVER: ${config.driver}. Must be one of: s3, s3-presigned, gcs, gcs-presigned, oci, oci-presigned, local`);
113
+ else if (!['s3', 's3-presigned', 'gcs', 'gcs-presigned', 'azure', 'azure-presigned', 'local'].includes(config.driver)) {
114
+ errors.push(`Invalid FILE_DRIVER: ${config.driver}. Must be one of: s3, s3-presigned, gcs, gcs-presigned, azure, azure-presigned, local`);
82
115
  }
83
- // Validate cloud storage requirements
116
+ // S3 requirements
84
117
  if (config.driver?.includes('s3')) {
85
118
  if (!config.bucketName)
86
119
  errors.push('BUCKET_NAME is required for S3');
87
120
  if (!config.awsRegion)
88
121
  errors.push('AWS_REGION is required for S3');
89
- if (!config.awsAccessKey)
90
- errors.push('AWS_ACCESS_KEY is required for S3');
91
- if (!config.awsSecretKey)
92
- errors.push('AWS_SECRET_KEY is required for S3');
122
+ // Access keys are optional — IAM roles work when running on AWS
93
123
  }
124
+ // GCS requirements
94
125
  if (config.driver?.includes('gcs')) {
95
126
  if (!config.bucketName)
96
127
  errors.push('BUCKET_NAME is required for GCS');
97
128
  if (!config.gcsProjectId)
98
129
  errors.push('GCS_PROJECT_ID is required for GCS');
99
- if (!config.gcsCredentials)
100
- errors.push('GCS_CREDENTIALS is required for GCS');
130
+ // Credentials are optional — ADC works when running on GCP
101
131
  }
102
- if (config.driver?.includes('oci')) {
103
- if (!config.bucketName)
104
- errors.push('BUCKET_NAME is required for OCI');
105
- if (!config.ociRegion)
106
- errors.push('OCI_REGION is required for OCI');
107
- if (!config.ociCredentials)
108
- errors.push('OCI_CREDENTIALS is required for OCI');
132
+ // Azure requirements
133
+ if (config.driver?.includes('azure')) {
134
+ const hasConnectionString = !!config.azureConnectionString;
135
+ const hasAccountKey = config.azureAccountName && config.azureAccountKey;
136
+ const hasManagedIdentity = config.azureAccountName && !config.azureAccountKey;
137
+ if (config.driver === 'azure-presigned') {
138
+ // Presigned mode needs account key for SAS URL generation
139
+ if (!hasConnectionString && !hasAccountKey) {
140
+ errors.push('Azure presigned driver requires either AZURE_CONNECTION_STRING or both AZURE_ACCOUNT_NAME and AZURE_ACCOUNT_KEY (Managed Identity cannot generate SAS URLs)');
141
+ }
142
+ }
143
+ else {
144
+ // Direct mode supports any authentication method
145
+ if (!hasConnectionString && !hasAccountKey && !hasManagedIdentity) {
146
+ errors.push('Azure requires AZURE_CONNECTION_STRING, AZURE_ACCOUNT_NAME + AZURE_ACCOUNT_KEY, or AZURE_ACCOUNT_NAME only (for Managed Identity)');
147
+ }
148
+ }
149
+ if (!config.azureContainerName) {
150
+ errors.push('BUCKET_NAME is required for Azure');
151
+ }
152
+ }
153
+ // Validate URL expiry time
154
+ if (config.presignedUrlExpiry !== undefined) {
155
+ if (Number.isNaN(config.presignedUrlExpiry) || config.presignedUrlExpiry <= 0) {
156
+ errors.push('PRESIGNED_URL_EXPIRY must be a positive number greater than 0');
157
+ }
158
+ // Max 7 days — that's the cloud provider limit
159
+ const MAX_EXPIRY = 604800;
160
+ if (!Number.isNaN(config.presignedUrlExpiry) && config.presignedUrlExpiry > MAX_EXPIRY) {
161
+ errors.push(`PRESIGNED_URL_EXPIRY cannot exceed ${MAX_EXPIRY} seconds (7 days). Cloud providers enforce this limit.`);
162
+ }
109
163
  }
110
- // Validate presigned URL expiry
111
- if (config.presignedUrlExpiry && config.presignedUrlExpiry <= 0) {
112
- errors.push('PRESIGNED_URL_EXPIRY must be greater than 0');
164
+ // Validate max file size
165
+ if (config.maxFileSize !== undefined) {
166
+ if (Number.isNaN(config.maxFileSize) || config.maxFileSize <= 0) {
167
+ errors.push('MAX_FILE_SIZE must be a positive number greater than 0');
168
+ }
169
+ // Max 5TB — reasonable limit for single uploads
170
+ const MAX_FILE_SIZE_LIMIT = 5 * 1024 * 1024 * 1024 * 1024;
171
+ if (!Number.isNaN(config.maxFileSize) && config.maxFileSize > MAX_FILE_SIZE_LIMIT) {
172
+ errors.push(`MAX_FILE_SIZE cannot exceed ${MAX_FILE_SIZE_LIMIT} bytes (5TB). Consider using multipart uploads for larger files.`);
173
+ }
113
174
  }
114
175
  return {
115
176
  isValid: errors.length === 0,
@@ -117,7 +178,8 @@ export function validateStorageConfig(config) {
117
178
  };
118
179
  }
119
180
  /**
120
- * Load and validate configuration from environment
181
+ * Convenience function that loads and validates config in one call.
182
+ * Returns both the config and validation result.
121
183
  */
122
184
  export function loadAndValidateConfig() {
123
185
  const envConfig = loadEnvironmentConfig();
@@ -125,4 +187,16 @@ export function loadAndValidateConfig() {
125
187
  const validation = validateStorageConfig(config);
126
188
  return { config, validation };
127
189
  }
190
+ /**
191
+ * Resets the dotenv initialization flag.
192
+ *
193
+ * This is primarily useful for testing scenarios where you need to
194
+ * reinitialize dotenv with different environment variables.
195
+ *
196
+ * WARNING: This does not clear previously loaded environment variables.
197
+ * It only allows initializeDotenv() to run again.
198
+ */
199
+ export function resetDotenvInitialization() {
200
+ dotenvInitialized = false;
201
+ }
128
202
  //# sourceMappingURL=config.utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.utils.js","sourceRoot":"","sources":["../../src/utils/config.utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.utils.js","sourceRoot":"","sources":["../../src/utils/config.utils.ts"],"names":[],"mappings":"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"}
@@ -1,45 +1,142 @@
1
1
  /**
2
- * Generate unique filename with unix timestamp
2
+ * Creates a unique filename that won't collide with existing files.
3
+ *
4
+ * Format: {timestamp}_{random}_{sanitized_name}.{extension}
5
+ * Example: 1769104576000_a1b2c3d4e5_my_image.jpeg
6
+ *
7
+ * The random part uses crypto.randomBytes() for extra collision resistance
8
+ * in high-throughput scenarios.
3
9
  */
4
10
  export declare function generateUniqueFileName(originalName: string): string;
5
11
  /**
6
- * Sanitize filename to prevent security issues
12
+ * Makes a filename safe for storage by removing problematic characters.
13
+ *
14
+ * Replaces anything that isn't alphanumeric, a dot, or a hyphen with underscores.
15
+ * This ensures compatibility with all filesystems and cloud storage providers.
16
+ *
17
+ * Note: Unicode characters like Chinese or emojis become underscores.
18
+ * If you need to preserve these, consider using your own sanitization function.
7
19
  */
8
20
  export declare function sanitizeFileName(fileName: string): string;
9
21
  /**
10
- * Create month-based directory path
22
+ * Checks if a filename is safe to use.
23
+ *
24
+ * Rejects:
25
+ * - Empty filenames
26
+ * - Filenames over 255 characters
27
+ * - Path traversal attempts (../, /, \)
28
+ * - Null bytes
29
+ *
30
+ * Returns an error message if invalid, null if OK.
31
+ */
32
+ export declare function validateFileName(fileName: string): string | null;
33
+ /**
34
+ * Creates a date-based folder path: YYYY/MM
35
+ *
36
+ * Uses UTC to keep things consistent across timezones.
37
+ * Example: For January 2026 -> 'uploads/2026/01'
11
38
  */
12
39
  export declare function createMonthBasedPath(basePath: string): string;
13
40
  /**
14
- * Ensure directory exists, create if it doesn't
41
+ * Creates a directory if it doesn't exist.
42
+ * Also creates any parent directories needed (recursive).
15
43
  */
16
44
  export declare function ensureDirectoryExists(dirPath: string): void;
17
45
  /**
18
- * Get file size in human readable format
46
+ * Converts bytes to a human-readable string.
47
+ *
48
+ * Examples:
49
+ * - 1024 -> "1 KB"
50
+ * - 1048576 -> "1 MB"
51
+ * - 0 -> "0 Bytes"
19
52
  */
20
53
  export declare function formatFileSize(bytes: number): string;
21
54
  /**
22
- * Validate file size
55
+ * Checks if a file size is within the allowed limit.
23
56
  */
24
57
  export declare function validateFileSize(fileSize: number, maxSize: number): boolean;
25
58
  /**
26
- * Validate file type
59
+ * Checks if a MIME type is in the allowed list.
27
60
  */
28
61
  export declare function validateFileType(mimeType: string, allowedTypes: string[]): boolean;
29
62
  /**
30
- * Create relative URL for local files
31
- */
32
- export declare function createLocalFileUrl(filePath: string, baseUrl?: string): string;
33
- /**
34
- * Get file extension from filename
63
+ * Extracts the file extension (lowercase, includes the dot).
64
+ *
65
+ * Examples:
66
+ * - 'photo.jpg' -> '.jpg'
67
+ * - '.gitignore' -> '' (dotfiles have no extension)
68
+ * - 'archive.tar.gz' -> '.gz' (only the last extension)
35
69
  */
36
70
  export declare function getFileExtension(fileName: string): string;
37
71
  /**
38
- * Check if file is an image
72
+ * Checks if a MIME type indicates an image.
39
73
  */
40
74
  export declare function isImageFile(mimeType: string): boolean;
41
75
  /**
42
- * Check if file is a document
76
+ * Checks if a MIME type indicates a document (PDF, Word, Excel, etc.).
43
77
  */
44
78
  export declare function isDocumentFile(mimeType: string): boolean;
79
+ /**
80
+ * Configuration for retry behavior.
81
+ */
82
+ export interface RetryOptions {
83
+ /** Total attempts including the first one. Default: 3 */
84
+ maxAttempts?: number;
85
+ /** Starting delay between retries in ms. Default: 1000 */
86
+ baseDelay?: number;
87
+ /** Maximum delay between retries in ms. Default: 10000 */
88
+ maxDelay?: number;
89
+ /** Use exponential backoff. Default: true */
90
+ exponentialBackoff?: boolean;
91
+ }
92
+ /**
93
+ * Retries an async operation with exponential backoff.
94
+ *
95
+ * Great for cloud operations that might fail due to network blips
96
+ * or rate limiting.
97
+ *
98
+ * @example
99
+ * // Retry up to 3 times with increasing delays
100
+ * const result = await withRetry(() => storage.uploadFile(file));
101
+ *
102
+ * // More aggressive retry strategy
103
+ * const result = await withRetry(() => fetchData(), {
104
+ * maxAttempts: 5,
105
+ * baseDelay: 500
106
+ * });
107
+ */
108
+ export declare function withRetry<T>(operation: () => Promise<T>, options?: RetryOptions): Promise<T>;
109
+ /**
110
+ * Pauses execution for the specified number of milliseconds.
111
+ */
112
+ export declare function sleep(ms: number): Promise<void>;
113
+ /**
114
+ * Configuration for concurrent execution.
115
+ */
116
+ export interface ConcurrencyOptions {
117
+ /** Maximum parallel operations. Default: 10 */
118
+ maxConcurrent?: number;
119
+ }
120
+ /**
121
+ * Processes an array with a concurrency limit.
122
+ *
123
+ * Prevents overwhelming APIs or running out of resources by limiting
124
+ * how many operations run at once.
125
+ *
126
+ * Implementation uses pre-assigned chunk-based processing to avoid any
127
+ * potential race conditions with shared index counters. Each worker gets
128
+ * its own set of indices to process.
129
+ *
130
+ * Note: The input array is snapshotted at the start to prevent issues
131
+ * if the caller modifies it during processing.
132
+ *
133
+ * @example
134
+ * // Upload 100 files, but only 10 at a time
135
+ * const results = await withConcurrencyLimit(
136
+ * files,
137
+ * (file) => uploadFile(file),
138
+ * { maxConcurrent: 10 }
139
+ * );
140
+ */
141
+ export declare function withConcurrencyLimit<T, R>(items: T[], operation: (item: T, index: number) => Promise<R>, options?: ConcurrencyOptions): Promise<R[]>;
45
142
  //# sourceMappingURL=file.utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"file.utils.d.ts","sourceRoot":"","sources":["../../src/utils/file.utils.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAOnE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAKzD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAM7D;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAI3D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMpD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAE3E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,OAAO,CAElF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,MAAW,GAAG,MAAM,CAGjF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAWxD"}
1
+ {"version":3,"file":"file.utils.d.ts","sourceRoot":"","sources":["../../src/utils/file.utils.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAsBnE;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQzD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAuBhE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAM7D;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAI3D;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAwBpD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAE3E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,OAAO,CAElF;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CASzD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAWxD;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6CAA6C;IAC7C,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAC/B,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAC3B,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,CAAC,CAAC,CA2BZ;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,+CAA+C;IAC/C,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,oBAAoB,CAAC,CAAC,EAAE,CAAC,EAC7C,KAAK,EAAE,CAAC,EAAE,EACV,SAAS,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,EACjD,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,CAAC,EAAE,CAAC,CAyCd"}