hazo_files 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,2457 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ ALL_SYSTEM_VARIABLES: () => ALL_SYSTEM_VARIABLES,
34
+ AuthenticationError: () => AuthenticationError,
35
+ ConfigurationError: () => ConfigurationError,
36
+ DEFAULT_DATE_FORMATS: () => DEFAULT_DATE_FORMATS,
37
+ DirectoryExistsError: () => DirectoryExistsError,
38
+ DirectoryNotEmptyError: () => DirectoryNotEmptyError,
39
+ DirectoryNotFoundError: () => DirectoryNotFoundError,
40
+ FileExistsError: () => FileExistsError,
41
+ FileManager: () => FileManager,
42
+ FileNotFoundError: () => FileNotFoundError,
43
+ FileTooLargeError: () => FileTooLargeError,
44
+ GoogleDriveAuth: () => GoogleDriveAuth,
45
+ GoogleDriveModule: () => GoogleDriveModule,
46
+ HazoFilesError: () => HazoFilesError,
47
+ InvalidExtensionError: () => InvalidExtensionError,
48
+ InvalidPathError: () => InvalidPathError,
49
+ LocalStorageModule: () => LocalStorageModule,
50
+ OperationError: () => OperationError,
51
+ PermissionDeniedError: () => PermissionDeniedError,
52
+ SYSTEM_COUNTER_VARIABLES: () => SYSTEM_COUNTER_VARIABLES,
53
+ SYSTEM_DATE_VARIABLES: () => SYSTEM_DATE_VARIABLES,
54
+ SYSTEM_FILE_VARIABLES: () => SYSTEM_FILE_VARIABLES,
55
+ clonePattern: () => clonePattern,
56
+ createAndInitializeModule: () => createAndInitializeModule,
57
+ createEmptyNamingRuleSchema: () => createEmptyNamingRuleSchema,
58
+ createFileItem: () => createFileItem,
59
+ createFileManager: () => createFileManager,
60
+ createFolderItem: () => createFolderItem,
61
+ createGoogleDriveAuth: () => createGoogleDriveAuth,
62
+ createGoogleDriveModule: () => createGoogleDriveModule,
63
+ createInitializedFileManager: () => createInitializedFileManager,
64
+ createLiteralSegment: () => createLiteralSegment,
65
+ createLocalModule: () => createLocalModule,
66
+ createModule: () => createModule,
67
+ createVariableSegment: () => createVariableSegment,
68
+ errorResult: () => errorResult,
69
+ filterItems: () => filterItems,
70
+ formatBytes: () => formatBytes,
71
+ formatCounter: () => formatCounter,
72
+ formatDateToken: () => formatDateToken,
73
+ generateId: () => generateId,
74
+ generatePreviewName: () => generatePreviewName,
75
+ generateSampleConfig: () => generateSampleConfig,
76
+ generateSegmentId: () => generateSegmentId,
77
+ getBaseName: () => getBaseName,
78
+ getBreadcrumbs: () => getBreadcrumbs,
79
+ getDirName: () => getDirName,
80
+ getExtension: () => getExtension,
81
+ getExtensionFromMime: () => getExtensionFromMime,
82
+ getFileCategory: () => getFileCategory,
83
+ getFileMetadataValues: () => getFileMetadataValues,
84
+ getMimeType: () => getMimeType,
85
+ getNameWithoutExtension: () => getNameWithoutExtension,
86
+ getParentPath: () => getParentPath,
87
+ getPathSegments: () => getPathSegments,
88
+ getRegisteredProviders: () => getRegisteredProviders,
89
+ getRelativePath: () => getRelativePath,
90
+ getSystemVariablePreviewValues: () => getSystemVariablePreviewValues,
91
+ hasExtension: () => hasExtension,
92
+ hazo_files_generate_file_name: () => hazo_files_generate_file_name,
93
+ hazo_files_generate_folder_name: () => hazo_files_generate_folder_name,
94
+ isAudio: () => isAudio,
95
+ isChildPath: () => isChildPath,
96
+ isCounterVariable: () => isCounterVariable,
97
+ isDateVariable: () => isDateVariable,
98
+ isDocument: () => isDocument,
99
+ isFile: () => isFile,
100
+ isFileMetadataVariable: () => isFileMetadataVariable,
101
+ isFolder: () => isFolder,
102
+ isImage: () => isImage,
103
+ isPreviewable: () => isPreviewable,
104
+ isProviderRegistered: () => isProviderRegistered,
105
+ isText: () => isText,
106
+ isVideo: () => isVideo,
107
+ joinPath: () => joinPath,
108
+ loadConfig: () => loadConfig,
109
+ loadConfigAsync: () => loadConfigAsync,
110
+ normalizePath: () => normalizePath,
111
+ parseConfig: () => parseConfig,
112
+ parsePatternString: () => parsePatternString,
113
+ patternToString: () => patternToString,
114
+ registerModule: () => registerModule,
115
+ sanitizeFilename: () => sanitizeFilename,
116
+ saveConfig: () => saveConfig,
117
+ sortItems: () => sortItems,
118
+ successResult: () => successResult,
119
+ validateNamingRuleSchema: () => validateNamingRuleSchema,
120
+ validatePath: () => validatePath
121
+ });
122
+ module.exports = __toCommonJS(index_exports);
123
+
124
+ // src/config/index.ts
125
+ var ini = __toESM(require("ini"));
126
+ var fs = __toESM(require("fs"));
127
+ var path = __toESM(require("path"));
128
+ var DEFAULT_CONFIG_FILENAME = "hazo_files_config.ini";
129
+ function parseConfig(configContent) {
130
+ const parsed = ini.parse(configContent);
131
+ const provider = parsed.general?.provider || "local";
132
+ const config = {
133
+ provider
134
+ };
135
+ if (parsed.local) {
136
+ config.local = {
137
+ basePath: parsed.local.base_path || "./files",
138
+ allowedExtensions: parsed.local.allowed_extensions ? parsed.local.allowed_extensions.split(",").map((ext) => ext.trim()) : void 0,
139
+ maxFileSize: parsed.local.max_file_size ? parseInt(parsed.local.max_file_size, 10) : void 0
140
+ };
141
+ }
142
+ if (parsed.google_drive) {
143
+ config.google_drive = {
144
+ clientId: parsed.google_drive.client_id || process.env.GOOGLE_DRIVE_CLIENT_ID || "",
145
+ clientSecret: parsed.google_drive.client_secret || process.env.GOOGLE_DRIVE_CLIENT_SECRET || "",
146
+ redirectUri: parsed.google_drive.redirect_uri || process.env.GOOGLE_DRIVE_REDIRECT_URI || "",
147
+ refreshToken: parsed.google_drive.refresh_token || process.env.GOOGLE_DRIVE_REFRESH_TOKEN,
148
+ accessToken: parsed.google_drive.access_token || process.env.GOOGLE_DRIVE_ACCESS_TOKEN,
149
+ rootFolderId: parsed.google_drive.root_folder_id || process.env.GOOGLE_DRIVE_ROOT_FOLDER_ID
150
+ };
151
+ }
152
+ return config;
153
+ }
154
+ function loadConfig(configPath) {
155
+ const resolvedPath = configPath || path.join(process.cwd(), DEFAULT_CONFIG_FILENAME);
156
+ if (!fs.existsSync(resolvedPath)) {
157
+ console.warn(`Config file not found at ${resolvedPath}, using defaults`);
158
+ return {
159
+ provider: "local",
160
+ local: {
161
+ basePath: "./files"
162
+ }
163
+ };
164
+ }
165
+ const content = fs.readFileSync(resolvedPath, "utf-8");
166
+ return parseConfig(content);
167
+ }
168
+ async function loadConfigAsync(configPath) {
169
+ const resolvedPath = configPath || path.join(process.cwd(), DEFAULT_CONFIG_FILENAME);
170
+ try {
171
+ const content = await fs.promises.readFile(resolvedPath, "utf-8");
172
+ return parseConfig(content);
173
+ } catch (error) {
174
+ if (error.code === "ENOENT") {
175
+ console.warn(`Config file not found at ${resolvedPath}, using defaults`);
176
+ return {
177
+ provider: "local",
178
+ local: {
179
+ basePath: "./files"
180
+ }
181
+ };
182
+ }
183
+ throw error;
184
+ }
185
+ }
186
+ function generateSampleConfig() {
187
+ return `; Hazo Files Configuration
188
+ ; This file configures the file management system
189
+
190
+ [general]
191
+ ; Available providers: local, google_drive
192
+ provider = local
193
+
194
+ [local]
195
+ ; Base path for local file storage (relative or absolute)
196
+ base_path = ./files
197
+ ; Comma-separated list of allowed extensions (optional, empty = all allowed)
198
+ allowed_extensions =
199
+ ; Maximum file size in bytes (optional, 0 = unlimited)
200
+ max_file_size = 0
201
+
202
+ [google_drive]
203
+ ; Google Drive OAuth credentials
204
+ ; These can also be set via environment variables:
205
+ ; GOOGLE_DRIVE_CLIENT_ID, GOOGLE_DRIVE_CLIENT_SECRET, etc.
206
+ client_id =
207
+ client_secret =
208
+ redirect_uri = http://localhost:3000/api/auth/callback/google
209
+ refresh_token =
210
+ access_token =
211
+ ; Optional: Root folder ID to use as base (empty = root of Drive)
212
+ root_folder_id =
213
+ `;
214
+ }
215
+ async function saveConfig(config, configPath) {
216
+ const resolvedPath = configPath || path.join(process.cwd(), DEFAULT_CONFIG_FILENAME);
217
+ const iniConfig = {
218
+ general: {
219
+ provider: config.provider
220
+ }
221
+ };
222
+ if (config.local) {
223
+ iniConfig.local = {
224
+ base_path: config.local.basePath,
225
+ allowed_extensions: config.local.allowedExtensions?.join(", ") || "",
226
+ max_file_size: config.local.maxFileSize?.toString() || "0"
227
+ };
228
+ }
229
+ if (config.google_drive) {
230
+ iniConfig.google_drive = {
231
+ client_id: config.google_drive.clientId || "",
232
+ client_secret: config.google_drive.clientSecret || "",
233
+ redirect_uri: config.google_drive.redirectUri || "",
234
+ refresh_token: config.google_drive.refreshToken || "",
235
+ access_token: config.google_drive.accessToken || "",
236
+ root_folder_id: config.google_drive.rootFolderId || ""
237
+ };
238
+ }
239
+ const content = ini.stringify(iniConfig);
240
+ await fs.promises.writeFile(resolvedPath, content, "utf-8");
241
+ }
242
+
243
+ // src/modules/local/index.ts
244
+ var fs2 = __toESM(require("fs"));
245
+ var path2 = __toESM(require("path"));
246
+ var import_stream = require("stream");
247
+ var import_promises = require("stream/promises");
248
+
249
+ // src/common/errors.ts
250
+ var HazoFilesError = class extends Error {
251
+ constructor(message, code, details) {
252
+ super(message);
253
+ this.code = code;
254
+ this.details = details;
255
+ this.name = "HazoFilesError";
256
+ }
257
+ };
258
+ var FileNotFoundError = class extends HazoFilesError {
259
+ constructor(path3) {
260
+ super(`File not found: ${path3}`, "FILE_NOT_FOUND", { path: path3 });
261
+ this.name = "FileNotFoundError";
262
+ }
263
+ };
264
+ var DirectoryNotFoundError = class extends HazoFilesError {
265
+ constructor(path3) {
266
+ super(`Directory not found: ${path3}`, "DIRECTORY_NOT_FOUND", { path: path3 });
267
+ this.name = "DirectoryNotFoundError";
268
+ }
269
+ };
270
+ var FileExistsError = class extends HazoFilesError {
271
+ constructor(path3) {
272
+ super(`File already exists: ${path3}`, "FILE_EXISTS", { path: path3 });
273
+ this.name = "FileExistsError";
274
+ }
275
+ };
276
+ var DirectoryExistsError = class extends HazoFilesError {
277
+ constructor(path3) {
278
+ super(`Directory already exists: ${path3}`, "DIRECTORY_EXISTS", { path: path3 });
279
+ this.name = "DirectoryExistsError";
280
+ }
281
+ };
282
+ var DirectoryNotEmptyError = class extends HazoFilesError {
283
+ constructor(path3) {
284
+ super(`Directory is not empty: ${path3}`, "DIRECTORY_NOT_EMPTY", { path: path3 });
285
+ this.name = "DirectoryNotEmptyError";
286
+ }
287
+ };
288
+ var PermissionDeniedError = class extends HazoFilesError {
289
+ constructor(path3, operation) {
290
+ super(`Permission denied for ${operation} on: ${path3}`, "PERMISSION_DENIED", { path: path3, operation });
291
+ this.name = "PermissionDeniedError";
292
+ }
293
+ };
294
+ var InvalidPathError = class extends HazoFilesError {
295
+ constructor(path3, reason) {
296
+ super(`Invalid path "${path3}": ${reason}`, "INVALID_PATH", { path: path3, reason });
297
+ this.name = "InvalidPathError";
298
+ }
299
+ };
300
+ var FileTooLargeError = class extends HazoFilesError {
301
+ constructor(path3, size, maxSize) {
302
+ super(
303
+ `File "${path3}" is too large (${size} bytes). Maximum allowed: ${maxSize} bytes`,
304
+ "FILE_TOO_LARGE",
305
+ { path: path3, size, maxSize }
306
+ );
307
+ this.name = "FileTooLargeError";
308
+ }
309
+ };
310
+ var InvalidExtensionError = class extends HazoFilesError {
311
+ constructor(path3, extension, allowedExtensions) {
312
+ super(
313
+ `File extension "${extension}" is not allowed. Allowed: ${allowedExtensions.join(", ")}`,
314
+ "INVALID_EXTENSION",
315
+ { path: path3, extension, allowedExtensions }
316
+ );
317
+ this.name = "InvalidExtensionError";
318
+ }
319
+ };
320
+ var AuthenticationError = class extends HazoFilesError {
321
+ constructor(provider, message) {
322
+ super(`Authentication failed for ${provider}: ${message}`, "AUTHENTICATION_ERROR", { provider });
323
+ this.name = "AuthenticationError";
324
+ }
325
+ };
326
+ var ConfigurationError = class extends HazoFilesError {
327
+ constructor(message) {
328
+ super(`Configuration error: ${message}`, "CONFIGURATION_ERROR");
329
+ this.name = "ConfigurationError";
330
+ }
331
+ };
332
+ var OperationError = class extends HazoFilesError {
333
+ constructor(operation, message, details) {
334
+ super(`${operation} failed: ${message}`, "OPERATION_ERROR", details);
335
+ this.name = "OperationError";
336
+ }
337
+ };
338
+
339
+ // src/common/utils.ts
340
+ function successResult(data) {
341
+ return {
342
+ success: true,
343
+ data
344
+ };
345
+ }
346
+ function errorResult(error) {
347
+ return {
348
+ success: false,
349
+ error
350
+ };
351
+ }
352
+ function generateId() {
353
+ return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
354
+ }
355
+ function formatBytes(bytes, decimals = 2) {
356
+ if (bytes === 0) return "0 Bytes";
357
+ const k = 1024;
358
+ const dm = decimals < 0 ? 0 : decimals;
359
+ const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB"];
360
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
361
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
362
+ }
363
+ function isFile(item) {
364
+ return !item.isDirectory;
365
+ }
366
+ function isFolder(item) {
367
+ return item.isDirectory;
368
+ }
369
+ function sortItems(items) {
370
+ return [...items].sort((a, b) => {
371
+ if (a.isDirectory && !b.isDirectory) return -1;
372
+ if (!a.isDirectory && b.isDirectory) return 1;
373
+ return a.name.localeCompare(b.name);
374
+ });
375
+ }
376
+ function filterItems(items, searchTerm) {
377
+ const term = searchTerm.toLowerCase();
378
+ return items.filter((item) => item.name.toLowerCase().includes(term));
379
+ }
380
+ function createFileItem(params) {
381
+ return {
382
+ id: params.id,
383
+ name: params.name,
384
+ path: params.path,
385
+ size: params.size,
386
+ mimeType: params.mimeType,
387
+ createdAt: params.createdAt || /* @__PURE__ */ new Date(),
388
+ modifiedAt: params.modifiedAt || /* @__PURE__ */ new Date(),
389
+ isDirectory: false,
390
+ parentId: params.parentId,
391
+ metadata: params.metadata
392
+ };
393
+ }
394
+ function createFolderItem(params) {
395
+ return {
396
+ id: params.id,
397
+ name: params.name,
398
+ path: params.path,
399
+ createdAt: params.createdAt || /* @__PURE__ */ new Date(),
400
+ modifiedAt: params.modifiedAt || /* @__PURE__ */ new Date(),
401
+ isDirectory: true,
402
+ parentId: params.parentId,
403
+ children: params.children,
404
+ metadata: params.metadata
405
+ };
406
+ }
407
+
408
+ // src/common/path-utils.ts
409
+ function normalizePath(inputPath) {
410
+ if (!inputPath) return "/";
411
+ let normalized = inputPath.replace(/\\/g, "/");
412
+ normalized = normalized.replace(/\/+/g, "/");
413
+ const parts = normalized.split("/");
414
+ const result = [];
415
+ for (const part of parts) {
416
+ if (part === "." || part === "") continue;
417
+ if (part === "..") {
418
+ result.pop();
419
+ } else {
420
+ result.push(part);
421
+ }
422
+ }
423
+ normalized = "/" + result.join("/");
424
+ return normalized;
425
+ }
426
+ function joinPath(...segments) {
427
+ const joined = segments.map((s) => s.replace(/^\/+|\/+$/g, "")).filter(Boolean).join("/");
428
+ return normalizePath("/" + joined);
429
+ }
430
+ function getParentPath(inputPath) {
431
+ const normalized = normalizePath(inputPath);
432
+ if (normalized === "/") return "/";
433
+ const lastSlash = normalized.lastIndexOf("/");
434
+ if (lastSlash === 0) return "/";
435
+ return normalized.slice(0, lastSlash) || "/";
436
+ }
437
+ function getBaseName(inputPath) {
438
+ const normalized = normalizePath(inputPath);
439
+ if (normalized === "/") return "";
440
+ const lastSlash = normalized.lastIndexOf("/");
441
+ return normalized.slice(lastSlash + 1);
442
+ }
443
+ function getDirName(inputPath) {
444
+ return getParentPath(inputPath);
445
+ }
446
+ function getPathSegments(inputPath) {
447
+ const normalized = normalizePath(inputPath);
448
+ if (normalized === "/") return [];
449
+ return normalized.slice(1).split("/");
450
+ }
451
+ function isChildPath(parentPath, childPath) {
452
+ const normalizedParent = normalizePath(parentPath);
453
+ const normalizedChild = normalizePath(childPath);
454
+ if (normalizedParent === "/") {
455
+ return normalizedChild !== "/";
456
+ }
457
+ return normalizedChild.startsWith(normalizedParent + "/");
458
+ }
459
+ function getRelativePath(basePath, targetPath) {
460
+ const baseSegments = getPathSegments(basePath);
461
+ const targetSegments = getPathSegments(targetPath);
462
+ let commonLength = 0;
463
+ while (commonLength < baseSegments.length && commonLength < targetSegments.length && baseSegments[commonLength] === targetSegments[commonLength]) {
464
+ commonLength++;
465
+ }
466
+ const upCount = baseSegments.length - commonLength;
467
+ const remaining = targetSegments.slice(commonLength);
468
+ const parts = [];
469
+ for (let i = 0; i < upCount; i++) {
470
+ parts.push("..");
471
+ }
472
+ parts.push(...remaining);
473
+ return parts.join("/") || ".";
474
+ }
475
+ function validatePath(inputPath, basePath) {
476
+ normalizePath(inputPath);
477
+ if (inputPath.includes("\0")) {
478
+ throw new InvalidPathError(inputPath, "Path contains null bytes");
479
+ }
480
+ if (basePath) {
481
+ const normalizedBase = normalizePath(basePath);
482
+ const fullPath = joinPath(normalizedBase, inputPath);
483
+ if (!fullPath.startsWith(normalizedBase)) {
484
+ throw new InvalidPathError(inputPath, "Path traversal detected");
485
+ }
486
+ }
487
+ }
488
+ function sanitizeFilename(filename) {
489
+ let sanitized = filename.replace(/[<>:"/\\|?*\x00-\x1F]/g, "_").replace(/^\.+/, "").trim();
490
+ if (!sanitized) {
491
+ sanitized = "unnamed";
492
+ }
493
+ if (sanitized.length > 255) {
494
+ const ext = getExtension(sanitized);
495
+ const name = sanitized.slice(0, 255 - ext.length);
496
+ sanitized = name + ext;
497
+ }
498
+ return sanitized;
499
+ }
500
+ function getExtension(filename) {
501
+ const lastDot = filename.lastIndexOf(".");
502
+ if (lastDot === -1 || lastDot === 0) return "";
503
+ return filename.slice(lastDot);
504
+ }
505
+ function getNameWithoutExtension(filename) {
506
+ const lastDot = filename.lastIndexOf(".");
507
+ if (lastDot === -1 || lastDot === 0) return filename;
508
+ return filename.slice(0, lastDot);
509
+ }
510
+ function hasExtension(filename, extension) {
511
+ const ext = getExtension(filename).toLowerCase();
512
+ const targetExt = extension.startsWith(".") ? extension.toLowerCase() : "." + extension.toLowerCase();
513
+ return ext === targetExt;
514
+ }
515
+ function getBreadcrumbs(inputPath) {
516
+ const segments = getPathSegments(inputPath);
517
+ const breadcrumbs = [
518
+ { name: "Root", path: "/" }
519
+ ];
520
+ let currentPath = "";
521
+ for (const segment of segments) {
522
+ currentPath += "/" + segment;
523
+ breadcrumbs.push({
524
+ name: segment,
525
+ path: currentPath
526
+ });
527
+ }
528
+ return breadcrumbs;
529
+ }
530
+
531
+ // src/common/base-module.ts
532
+ var BaseStorageModule = class {
533
+ constructor() {
534
+ this.config = null;
535
+ this._initialized = false;
536
+ // Utility methods available to subclasses
537
+ this.normalizePath = normalizePath;
538
+ this.joinPath = joinPath;
539
+ this.getBaseName = getBaseName;
540
+ this.getParentPath = getParentPath;
541
+ this.successResult = successResult;
542
+ this.errorResult = errorResult;
543
+ }
544
+ /**
545
+ * Check if the module is initialized
546
+ */
547
+ get isInitialized() {
548
+ return this._initialized;
549
+ }
550
+ /**
551
+ * Initialize the module with configuration.
552
+ * Subclasses should call super.initialize(config) first.
553
+ */
554
+ async initialize(config) {
555
+ this.config = config;
556
+ this._initialized = true;
557
+ }
558
+ /**
559
+ * Ensure the module is initialized before operations
560
+ */
561
+ ensureInitialized() {
562
+ if (!this._initialized || !this.config) {
563
+ throw new ConfigurationError("Module not initialized. Call initialize() first.");
564
+ }
565
+ }
566
+ /**
567
+ * Get the provider-specific configuration
568
+ */
569
+ getProviderConfig() {
570
+ this.ensureInitialized();
571
+ const providerConfig = this.config[this.provider];
572
+ if (!providerConfig) {
573
+ throw new ConfigurationError(`No configuration found for provider: ${this.provider}`);
574
+ }
575
+ return providerConfig;
576
+ }
577
+ /**
578
+ * Get folder tree structure.
579
+ * Default implementation that can be overridden by subclasses for optimization.
580
+ */
581
+ async getFolderTree(path3 = "/", depth = 3) {
582
+ this.ensureInitialized();
583
+ try {
584
+ const result = await this.buildTree(path3, depth, 0);
585
+ return successResult(result);
586
+ } catch (error) {
587
+ return errorResult(`Failed to get folder tree: ${error.message}`);
588
+ }
589
+ }
590
+ /**
591
+ * Recursively build folder tree
592
+ */
593
+ async buildTree(path3, maxDepth, currentDepth) {
594
+ if (currentDepth >= maxDepth) {
595
+ return [];
596
+ }
597
+ const listResult = await this.listDirectory(path3, { recursive: false });
598
+ if (!listResult.success || !listResult.data) {
599
+ return [];
600
+ }
601
+ const folders = listResult.data.filter((item) => item.isDirectory);
602
+ const nodes = [];
603
+ for (const folder of folders) {
604
+ const children = await this.buildTree(folder.path, maxDepth, currentDepth + 1);
605
+ nodes.push({
606
+ id: folder.id,
607
+ name: folder.name,
608
+ path: folder.path,
609
+ children
610
+ });
611
+ }
612
+ return nodes;
613
+ }
614
+ };
615
+
616
+ // src/common/mime-types.ts
617
+ var MIME_TYPES = {
618
+ // Text
619
+ ".txt": "text/plain",
620
+ ".html": "text/html",
621
+ ".htm": "text/html",
622
+ ".css": "text/css",
623
+ ".csv": "text/csv",
624
+ ".xml": "text/xml",
625
+ ".json": "application/json",
626
+ ".js": "application/javascript",
627
+ ".ts": "application/typescript",
628
+ ".jsx": "text/jsx",
629
+ ".tsx": "text/tsx",
630
+ ".md": "text/markdown",
631
+ ".yaml": "text/yaml",
632
+ ".yml": "text/yaml",
633
+ // Images
634
+ ".png": "image/png",
635
+ ".jpg": "image/jpeg",
636
+ ".jpeg": "image/jpeg",
637
+ ".gif": "image/gif",
638
+ ".bmp": "image/bmp",
639
+ ".webp": "image/webp",
640
+ ".svg": "image/svg+xml",
641
+ ".ico": "image/x-icon",
642
+ // Documents
643
+ ".pdf": "application/pdf",
644
+ ".doc": "application/msword",
645
+ ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
646
+ ".xls": "application/vnd.ms-excel",
647
+ ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
648
+ ".ppt": "application/vnd.ms-powerpoint",
649
+ ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
650
+ // Archives
651
+ ".zip": "application/zip",
652
+ ".rar": "application/x-rar-compressed",
653
+ ".7z": "application/x-7z-compressed",
654
+ ".tar": "application/x-tar",
655
+ ".gz": "application/gzip",
656
+ // Audio
657
+ ".mp3": "audio/mpeg",
658
+ ".wav": "audio/wav",
659
+ ".ogg": "audio/ogg",
660
+ ".m4a": "audio/mp4",
661
+ ".flac": "audio/flac",
662
+ // Video
663
+ ".mp4": "video/mp4",
664
+ ".webm": "video/webm",
665
+ ".avi": "video/x-msvideo",
666
+ ".mov": "video/quicktime",
667
+ ".wmv": "video/x-ms-wmv",
668
+ ".mkv": "video/x-matroska",
669
+ // Fonts
670
+ ".ttf": "font/ttf",
671
+ ".otf": "font/otf",
672
+ ".woff": "font/woff",
673
+ ".woff2": "font/woff2",
674
+ // Other
675
+ ".exe": "application/x-msdownload",
676
+ ".dmg": "application/x-apple-diskimage",
677
+ ".bin": "application/octet-stream"
678
+ };
679
+ var EXTENSION_BY_MIME = Object.entries(MIME_TYPES).reduce(
680
+ (acc, [ext, mime]) => {
681
+ if (!acc[mime]) {
682
+ acc[mime] = ext;
683
+ }
684
+ return acc;
685
+ },
686
+ {}
687
+ );
688
+ function getMimeType(filename) {
689
+ const ext = getExtension(filename).toLowerCase();
690
+ return MIME_TYPES[ext] || "application/octet-stream";
691
+ }
692
+ function getExtensionFromMime(mimeType) {
693
+ return EXTENSION_BY_MIME[mimeType] || "";
694
+ }
695
+ function isImage(filenameOrMime) {
696
+ const mime = filenameOrMime.includes("/") ? filenameOrMime : getMimeType(filenameOrMime);
697
+ return mime.startsWith("image/");
698
+ }
699
+ function isVideo(filenameOrMime) {
700
+ const mime = filenameOrMime.includes("/") ? filenameOrMime : getMimeType(filenameOrMime);
701
+ return mime.startsWith("video/");
702
+ }
703
+ function isAudio(filenameOrMime) {
704
+ const mime = filenameOrMime.includes("/") ? filenameOrMime : getMimeType(filenameOrMime);
705
+ return mime.startsWith("audio/");
706
+ }
707
+ function isText(filenameOrMime) {
708
+ const mime = filenameOrMime.includes("/") ? filenameOrMime : getMimeType(filenameOrMime);
709
+ return mime.startsWith("text/") || mime === "application/json" || mime === "application/javascript";
710
+ }
711
+ function isDocument(filenameOrMime) {
712
+ const mime = filenameOrMime.includes("/") ? filenameOrMime : getMimeType(filenameOrMime);
713
+ return mime === "application/pdf" || mime.includes("document") || mime.includes("spreadsheet") || mime.includes("presentation");
714
+ }
715
+ function isPreviewable(filenameOrMime) {
716
+ return isImage(filenameOrMime) || isText(filenameOrMime) || isVideo(filenameOrMime) || isAudio(filenameOrMime);
717
+ }
718
+ function getFileCategory(filenameOrMime) {
719
+ if (isImage(filenameOrMime)) return "image";
720
+ if (isVideo(filenameOrMime)) return "video";
721
+ if (isAudio(filenameOrMime)) return "audio";
722
+ if (isDocument(filenameOrMime)) return "document";
723
+ if (isText(filenameOrMime)) return "text";
724
+ return "other";
725
+ }
726
+
727
+ // src/modules/local/index.ts
728
+ var LocalStorageModule = class extends BaseStorageModule {
729
+ constructor() {
730
+ super(...arguments);
731
+ this.provider = "local";
732
+ this.basePath = "";
733
+ this.allowedExtensions = [];
734
+ this.maxFileSize = 0;
735
+ }
736
+ async initialize(config) {
737
+ await super.initialize(config);
738
+ const localConfig = this.getProviderConfig();
739
+ this.basePath = path2.resolve(localConfig.basePath);
740
+ this.allowedExtensions = localConfig.allowedExtensions || [];
741
+ this.maxFileSize = localConfig.maxFileSize || 0;
742
+ await fs2.promises.mkdir(this.basePath, { recursive: true });
743
+ }
744
+ /**
745
+ * Resolve a virtual path to an absolute file system path
746
+ */
747
+ resolveFullPath(virtualPath) {
748
+ const normalized = this.normalizePath(virtualPath);
749
+ const relativePath = normalized.startsWith("/") ? normalized.slice(1) : normalized;
750
+ return path2.join(this.basePath, relativePath);
751
+ }
752
+ /**
753
+ * Convert absolute path back to virtual path
754
+ */
755
+ toVirtualPath(absolutePath) {
756
+ const relative2 = path2.relative(this.basePath, absolutePath);
757
+ return this.normalizePath("/" + relative2.replace(/\\/g, "/"));
758
+ }
759
+ /**
760
+ * Validate file extension against allowed list
761
+ */
762
+ validateExtension(filename) {
763
+ if (this.allowedExtensions.length === 0) return;
764
+ const ext = getExtension(filename).toLowerCase().slice(1);
765
+ if (!this.allowedExtensions.includes(ext)) {
766
+ throw new InvalidExtensionError(filename, ext, this.allowedExtensions);
767
+ }
768
+ }
769
+ /**
770
+ * Validate file size against maximum
771
+ */
772
+ validateFileSize(size, filename) {
773
+ if (this.maxFileSize > 0 && size > this.maxFileSize) {
774
+ throw new FileTooLargeError(filename, size, this.maxFileSize);
775
+ }
776
+ }
777
+ /**
778
+ * Create file/folder stats to FileSystemItem
779
+ */
780
+ async statToItem(fullPath, stats) {
781
+ const virtualPath = this.toVirtualPath(fullPath);
782
+ const name = path2.basename(fullPath);
783
+ const id = generateId();
784
+ if (stats.isDirectory()) {
785
+ return createFolderItem({
786
+ id,
787
+ name,
788
+ path: virtualPath,
789
+ createdAt: stats.birthtime,
790
+ modifiedAt: stats.mtime
791
+ });
792
+ }
793
+ return createFileItem({
794
+ id,
795
+ name,
796
+ path: virtualPath,
797
+ size: stats.size,
798
+ mimeType: getMimeType(name),
799
+ createdAt: stats.birthtime,
800
+ modifiedAt: stats.mtime
801
+ });
802
+ }
803
+ async createDirectory(virtualPath) {
804
+ this.ensureInitialized();
805
+ try {
806
+ const fullPath = this.resolveFullPath(virtualPath);
807
+ try {
808
+ const stats2 = await fs2.promises.stat(fullPath);
809
+ if (stats2.isDirectory()) {
810
+ throw new DirectoryExistsError(virtualPath);
811
+ }
812
+ throw new FileExistsError(virtualPath);
813
+ } catch (error) {
814
+ if (error.code !== "ENOENT") {
815
+ throw error;
816
+ }
817
+ }
818
+ await fs2.promises.mkdir(fullPath, { recursive: true });
819
+ const stats = await fs2.promises.stat(fullPath);
820
+ const item = await this.statToItem(fullPath, stats);
821
+ return this.successResult(item);
822
+ } catch (error) {
823
+ if (error instanceof DirectoryExistsError || error instanceof FileExistsError) {
824
+ return this.errorResult(error.message);
825
+ }
826
+ return this.errorResult(`Failed to create directory: ${error.message}`);
827
+ }
828
+ }
829
+ async removeDirectory(virtualPath, recursive = false) {
830
+ this.ensureInitialized();
831
+ try {
832
+ const fullPath = this.resolveFullPath(virtualPath);
833
+ const stats = await fs2.promises.stat(fullPath).catch(() => null);
834
+ if (!stats) {
835
+ throw new DirectoryNotFoundError(virtualPath);
836
+ }
837
+ if (!stats.isDirectory()) {
838
+ throw new DirectoryNotFoundError(virtualPath);
839
+ }
840
+ if (!recursive) {
841
+ const contents = await fs2.promises.readdir(fullPath);
842
+ if (contents.length > 0) {
843
+ throw new DirectoryNotEmptyError(virtualPath);
844
+ }
845
+ }
846
+ await fs2.promises.rm(fullPath, { recursive, force: true });
847
+ return this.successResult();
848
+ } catch (error) {
849
+ if (error instanceof DirectoryNotFoundError || error instanceof DirectoryNotEmptyError) {
850
+ return this.errorResult(error.message);
851
+ }
852
+ return this.errorResult(`Failed to remove directory: ${error.message}`);
853
+ }
854
+ }
855
+ async uploadFile(source, remotePath, options = {}) {
856
+ this.ensureInitialized();
857
+ try {
858
+ const fullPath = this.resolveFullPath(remotePath);
859
+ const filename = path2.basename(fullPath);
860
+ this.validateExtension(filename);
861
+ if (!options.overwrite) {
862
+ try {
863
+ await fs2.promises.stat(fullPath);
864
+ throw new FileExistsError(remotePath);
865
+ } catch (error) {
866
+ if (error.code !== "ENOENT") {
867
+ if (error instanceof FileExistsError) throw error;
868
+ }
869
+ }
870
+ }
871
+ const parentDir = path2.dirname(fullPath);
872
+ await fs2.promises.mkdir(parentDir, { recursive: true });
873
+ if (typeof source === "string") {
874
+ const stats2 = await fs2.promises.stat(source);
875
+ this.validateFileSize(stats2.size, filename);
876
+ if (options.onProgress) {
877
+ const totalBytes = stats2.size;
878
+ let bytesTransferred = 0;
879
+ const readStream = fs2.createReadStream(source);
880
+ const writeStream = fs2.createWriteStream(fullPath);
881
+ readStream.on("data", (chunk) => {
882
+ bytesTransferred += chunk.length;
883
+ const progress = bytesTransferred / totalBytes * 100;
884
+ options.onProgress(progress, bytesTransferred, totalBytes);
885
+ });
886
+ await (0, import_promises.pipeline)(readStream, writeStream);
887
+ } else {
888
+ await fs2.promises.copyFile(source, fullPath);
889
+ }
890
+ } else if (Buffer.isBuffer(source)) {
891
+ this.validateFileSize(source.length, filename);
892
+ await fs2.promises.writeFile(fullPath, source);
893
+ if (options.onProgress) {
894
+ options.onProgress(100, source.length, source.length);
895
+ }
896
+ } else {
897
+ const writeStream = fs2.createWriteStream(fullPath);
898
+ const readable = import_stream.Readable.fromWeb(source);
899
+ await (0, import_promises.pipeline)(readable, writeStream);
900
+ }
901
+ const stats = await fs2.promises.stat(fullPath);
902
+ const item = await this.statToItem(fullPath, stats);
903
+ return this.successResult(item);
904
+ } catch (error) {
905
+ if (error instanceof FileExistsError || error instanceof FileTooLargeError || error instanceof InvalidExtensionError) {
906
+ return this.errorResult(error.message);
907
+ }
908
+ return this.errorResult(`Failed to upload file: ${error.message}`);
909
+ }
910
+ }
911
+ async downloadFile(remotePath, localPath, options = {}) {
912
+ this.ensureInitialized();
913
+ try {
914
+ const fullPath = this.resolveFullPath(remotePath);
915
+ const stats = await fs2.promises.stat(fullPath).catch(() => null);
916
+ if (!stats || stats.isDirectory()) {
917
+ throw new FileNotFoundError(remotePath);
918
+ }
919
+ if (localPath) {
920
+ const destDir = path2.dirname(localPath);
921
+ await fs2.promises.mkdir(destDir, { recursive: true });
922
+ if (options.onProgress) {
923
+ const totalBytes = stats.size;
924
+ let bytesTransferred = 0;
925
+ const readStream = fs2.createReadStream(fullPath);
926
+ const writeStream = fs2.createWriteStream(localPath);
927
+ readStream.on("data", (chunk) => {
928
+ bytesTransferred += chunk.length;
929
+ const progress = bytesTransferred / totalBytes * 100;
930
+ options.onProgress(progress, bytesTransferred, totalBytes);
931
+ });
932
+ await (0, import_promises.pipeline)(readStream, writeStream);
933
+ } else {
934
+ await fs2.promises.copyFile(fullPath, localPath);
935
+ }
936
+ return this.successResult(localPath);
937
+ } else {
938
+ const buffer = await fs2.promises.readFile(fullPath);
939
+ if (options.onProgress) {
940
+ options.onProgress(100, buffer.length, buffer.length);
941
+ }
942
+ return this.successResult(buffer);
943
+ }
944
+ } catch (error) {
945
+ if (error instanceof FileNotFoundError) {
946
+ return this.errorResult(error.message);
947
+ }
948
+ return this.errorResult(`Failed to download file: ${error.message}`);
949
+ }
950
+ }
951
+ async moveItem(sourcePath, destinationPath, options = {}) {
952
+ this.ensureInitialized();
953
+ try {
954
+ const sourceFullPath = this.resolveFullPath(sourcePath);
955
+ const destFullPath = this.resolveFullPath(destinationPath);
956
+ const sourceStats = await fs2.promises.stat(sourceFullPath).catch(() => null);
957
+ if (!sourceStats) {
958
+ throw new FileNotFoundError(sourcePath);
959
+ }
960
+ if (!options.overwrite) {
961
+ const destStats = await fs2.promises.stat(destFullPath).catch(() => null);
962
+ if (destStats) {
963
+ throw new FileExistsError(destinationPath);
964
+ }
965
+ }
966
+ const destParent = path2.dirname(destFullPath);
967
+ await fs2.promises.mkdir(destParent, { recursive: true });
968
+ await fs2.promises.rename(sourceFullPath, destFullPath);
969
+ const newStats = await fs2.promises.stat(destFullPath);
970
+ const item = await this.statToItem(destFullPath, newStats);
971
+ return this.successResult(item);
972
+ } catch (error) {
973
+ if (error instanceof FileNotFoundError || error instanceof FileExistsError) {
974
+ return this.errorResult(error.message);
975
+ }
976
+ return this.errorResult(`Failed to move item: ${error.message}`);
977
+ }
978
+ }
979
+ async deleteFile(virtualPath) {
980
+ this.ensureInitialized();
981
+ try {
982
+ const fullPath = this.resolveFullPath(virtualPath);
983
+ const stats = await fs2.promises.stat(fullPath).catch(() => null);
984
+ if (!stats) {
985
+ throw new FileNotFoundError(virtualPath);
986
+ }
987
+ if (stats.isDirectory()) {
988
+ throw new FileNotFoundError(virtualPath);
989
+ }
990
+ await fs2.promises.unlink(fullPath);
991
+ return this.successResult();
992
+ } catch (error) {
993
+ if (error instanceof FileNotFoundError) {
994
+ return this.errorResult(error.message);
995
+ }
996
+ return this.errorResult(`Failed to delete file: ${error.message}`);
997
+ }
998
+ }
999
+ async renameFile(virtualPath, newName, options = {}) {
1000
+ this.ensureInitialized();
1001
+ try {
1002
+ const fullPath = this.resolveFullPath(virtualPath);
1003
+ const stats = await fs2.promises.stat(fullPath).catch(() => null);
1004
+ if (!stats || stats.isDirectory()) {
1005
+ throw new FileNotFoundError(virtualPath);
1006
+ }
1007
+ this.validateExtension(newName);
1008
+ const parentDir = path2.dirname(fullPath);
1009
+ const newFullPath = path2.join(parentDir, newName);
1010
+ if (!options.overwrite) {
1011
+ const destStats = await fs2.promises.stat(newFullPath).catch(() => null);
1012
+ if (destStats) {
1013
+ throw new FileExistsError(newName);
1014
+ }
1015
+ }
1016
+ await fs2.promises.rename(fullPath, newFullPath);
1017
+ const newStats = await fs2.promises.stat(newFullPath);
1018
+ const item = await this.statToItem(newFullPath, newStats);
1019
+ return this.successResult(item);
1020
+ } catch (error) {
1021
+ if (error instanceof FileNotFoundError || error instanceof FileExistsError || error instanceof InvalidExtensionError) {
1022
+ return this.errorResult(error.message);
1023
+ }
1024
+ return this.errorResult(`Failed to rename file: ${error.message}`);
1025
+ }
1026
+ }
1027
+ async renameFolder(virtualPath, newName, options = {}) {
1028
+ this.ensureInitialized();
1029
+ try {
1030
+ const fullPath = this.resolveFullPath(virtualPath);
1031
+ const stats = await fs2.promises.stat(fullPath).catch(() => null);
1032
+ if (!stats || !stats.isDirectory()) {
1033
+ throw new DirectoryNotFoundError(virtualPath);
1034
+ }
1035
+ const parentDir = path2.dirname(fullPath);
1036
+ const newFullPath = path2.join(parentDir, newName);
1037
+ if (!options.overwrite) {
1038
+ const destStats = await fs2.promises.stat(newFullPath).catch(() => null);
1039
+ if (destStats) {
1040
+ throw new DirectoryExistsError(newName);
1041
+ }
1042
+ }
1043
+ await fs2.promises.rename(fullPath, newFullPath);
1044
+ const newStats = await fs2.promises.stat(newFullPath);
1045
+ const item = await this.statToItem(newFullPath, newStats);
1046
+ return this.successResult(item);
1047
+ } catch (error) {
1048
+ if (error instanceof DirectoryNotFoundError || error instanceof DirectoryExistsError) {
1049
+ return this.errorResult(error.message);
1050
+ }
1051
+ return this.errorResult(`Failed to rename folder: ${error.message}`);
1052
+ }
1053
+ }
1054
+ async listDirectory(virtualPath, options = {}) {
1055
+ this.ensureInitialized();
1056
+ try {
1057
+ const fullPath = this.resolveFullPath(virtualPath);
1058
+ const stats = await fs2.promises.stat(fullPath).catch(() => null);
1059
+ if (!stats || !stats.isDirectory()) {
1060
+ throw new DirectoryNotFoundError(virtualPath);
1061
+ }
1062
+ const entries = await fs2.promises.readdir(fullPath, { withFileTypes: true });
1063
+ const items = [];
1064
+ for (const entry of entries) {
1065
+ if (!options.includeHidden && entry.name.startsWith(".")) {
1066
+ continue;
1067
+ }
1068
+ const entryPath = path2.join(fullPath, entry.name);
1069
+ const entryStats = await fs2.promises.stat(entryPath);
1070
+ const item = await this.statToItem(entryPath, entryStats);
1071
+ if (options.filter && !options.filter(item)) {
1072
+ continue;
1073
+ }
1074
+ items.push(item);
1075
+ if (options.recursive && entry.isDirectory()) {
1076
+ const subResult = await this.listDirectory(
1077
+ this.toVirtualPath(entryPath),
1078
+ options
1079
+ );
1080
+ if (subResult.success && subResult.data) {
1081
+ items.push(...subResult.data);
1082
+ }
1083
+ }
1084
+ }
1085
+ items.sort((a, b) => {
1086
+ if (a.isDirectory && !b.isDirectory) return -1;
1087
+ if (!a.isDirectory && b.isDirectory) return 1;
1088
+ return a.name.localeCompare(b.name);
1089
+ });
1090
+ return this.successResult(items);
1091
+ } catch (error) {
1092
+ if (error instanceof DirectoryNotFoundError) {
1093
+ return this.errorResult(error.message);
1094
+ }
1095
+ return this.errorResult(`Failed to list directory: ${error.message}`);
1096
+ }
1097
+ }
1098
+ async getItem(virtualPath) {
1099
+ this.ensureInitialized();
1100
+ try {
1101
+ const fullPath = this.resolveFullPath(virtualPath);
1102
+ const stats = await fs2.promises.stat(fullPath).catch(() => null);
1103
+ if (!stats) {
1104
+ throw new FileNotFoundError(virtualPath);
1105
+ }
1106
+ const item = await this.statToItem(fullPath, stats);
1107
+ return this.successResult(item);
1108
+ } catch (error) {
1109
+ if (error instanceof FileNotFoundError) {
1110
+ return this.errorResult(error.message);
1111
+ }
1112
+ return this.errorResult(`Failed to get item: ${error.message}`);
1113
+ }
1114
+ }
1115
+ async exists(virtualPath) {
1116
+ this.ensureInitialized();
1117
+ try {
1118
+ const fullPath = this.resolveFullPath(virtualPath);
1119
+ await fs2.promises.stat(fullPath);
1120
+ return true;
1121
+ } catch {
1122
+ return false;
1123
+ }
1124
+ }
1125
+ };
1126
+ function createLocalModule() {
1127
+ return new LocalStorageModule();
1128
+ }
1129
+
1130
+ // src/modules/google-drive/index.ts
1131
+ var import_googleapis2 = require("googleapis");
1132
+ var import_stream2 = require("stream");
1133
+
1134
+ // src/modules/google-drive/auth.ts
1135
+ var import_googleapis = require("googleapis");
1136
+ var GOOGLE_DRIVE_SCOPES = [
1137
+ "https://www.googleapis.com/auth/drive.file",
1138
+ "https://www.googleapis.com/auth/drive.metadata.readonly",
1139
+ "https://www.googleapis.com/auth/userinfo.email",
1140
+ "https://www.googleapis.com/auth/userinfo.profile"
1141
+ ];
1142
+ var GoogleDriveAuth = class {
1143
+ constructor(config, callbacks = {}) {
1144
+ this.tokens = null;
1145
+ this.oauth2Client = new import_googleapis.google.auth.OAuth2(
1146
+ config.clientId,
1147
+ config.clientSecret,
1148
+ config.redirectUri
1149
+ );
1150
+ this.callbacks = callbacks;
1151
+ this.oauth2Client.on("tokens", async (tokens) => {
1152
+ if (this.tokens) {
1153
+ const updatedTokens = {
1154
+ ...this.tokens,
1155
+ accessToken: tokens.access_token || this.tokens.accessToken,
1156
+ expiryDate: tokens.expiry_date ?? this.tokens.expiryDate
1157
+ };
1158
+ if (tokens.refresh_token) {
1159
+ updatedTokens.refreshToken = tokens.refresh_token;
1160
+ }
1161
+ this.tokens = updatedTokens;
1162
+ if (this.callbacks.onTokensUpdated) {
1163
+ await this.callbacks.onTokensUpdated(updatedTokens);
1164
+ }
1165
+ }
1166
+ });
1167
+ }
1168
+ /**
1169
+ * Get the OAuth2 client instance
1170
+ */
1171
+ getClient() {
1172
+ return this.oauth2Client;
1173
+ }
1174
+ /**
1175
+ * Generate the authorization URL for OAuth consent
1176
+ */
1177
+ getAuthUrl(state) {
1178
+ return this.oauth2Client.generateAuthUrl({
1179
+ access_type: "offline",
1180
+ scope: GOOGLE_DRIVE_SCOPES,
1181
+ prompt: "consent",
1182
+ state
1183
+ });
1184
+ }
1185
+ /**
1186
+ * Exchange authorization code for tokens
1187
+ */
1188
+ async exchangeCodeForTokens(code) {
1189
+ const { tokens } = await this.oauth2Client.getToken(code);
1190
+ this.tokens = {
1191
+ accessToken: tokens.access_token,
1192
+ refreshToken: tokens.refresh_token,
1193
+ expiryDate: tokens.expiry_date || void 0,
1194
+ scope: tokens.scope || void 0
1195
+ };
1196
+ this.oauth2Client.setCredentials(tokens);
1197
+ if (this.callbacks.onTokensUpdated) {
1198
+ await this.callbacks.onTokensUpdated(this.tokens);
1199
+ }
1200
+ return this.tokens;
1201
+ }
1202
+ /**
1203
+ * Set tokens directly (e.g., from stored tokens)
1204
+ */
1205
+ async setTokens(tokens) {
1206
+ this.tokens = tokens;
1207
+ const credentials = {
1208
+ access_token: tokens.accessToken,
1209
+ refresh_token: tokens.refreshToken,
1210
+ expiry_date: tokens.expiryDate
1211
+ };
1212
+ this.oauth2Client.setCredentials(credentials);
1213
+ }
1214
+ /**
1215
+ * Load tokens from storage using callback
1216
+ */
1217
+ async loadStoredTokens() {
1218
+ if (!this.callbacks.getStoredTokens) {
1219
+ return false;
1220
+ }
1221
+ const tokens = await this.callbacks.getStoredTokens();
1222
+ if (tokens) {
1223
+ await this.setTokens(tokens);
1224
+ return true;
1225
+ }
1226
+ return false;
1227
+ }
1228
+ /**
1229
+ * Check if authenticated
1230
+ */
1231
+ isAuthenticated() {
1232
+ return this.tokens !== null && !!this.tokens.accessToken;
1233
+ }
1234
+ /**
1235
+ * Get current tokens
1236
+ */
1237
+ getTokens() {
1238
+ return this.tokens;
1239
+ }
1240
+ /**
1241
+ * Refresh the access token
1242
+ */
1243
+ async refreshAccessToken() {
1244
+ if (!this.tokens?.refreshToken) {
1245
+ throw new Error("No refresh token available");
1246
+ }
1247
+ const { credentials } = await this.oauth2Client.refreshAccessToken();
1248
+ this.tokens = {
1249
+ ...this.tokens,
1250
+ accessToken: credentials.access_token,
1251
+ expiryDate: credentials.expiry_date || void 0
1252
+ };
1253
+ if (this.callbacks.onTokensUpdated) {
1254
+ await this.callbacks.onTokensUpdated(this.tokens);
1255
+ }
1256
+ return this.tokens;
1257
+ }
1258
+ /**
1259
+ * Revoke access (disconnect)
1260
+ */
1261
+ async revokeAccess() {
1262
+ if (this.tokens?.accessToken) {
1263
+ await this.oauth2Client.revokeToken(this.tokens.accessToken);
1264
+ }
1265
+ this.tokens = null;
1266
+ this.oauth2Client.setCredentials({});
1267
+ }
1268
+ /**
1269
+ * Check if token is expired or will expire soon
1270
+ */
1271
+ isTokenExpired(bufferSeconds = 300) {
1272
+ if (!this.tokens?.expiryDate) {
1273
+ return false;
1274
+ }
1275
+ const now = Date.now();
1276
+ const expiry = this.tokens.expiryDate;
1277
+ return now >= expiry - bufferSeconds * 1e3;
1278
+ }
1279
+ /**
1280
+ * Ensure valid access token (refresh if needed)
1281
+ */
1282
+ async ensureValidToken() {
1283
+ if (this.isTokenExpired()) {
1284
+ await this.refreshAccessToken();
1285
+ }
1286
+ }
1287
+ };
1288
+ function createGoogleDriveAuth(config, callbacks) {
1289
+ return new GoogleDriveAuth(config, callbacks);
1290
+ }
1291
+
1292
+ // src/modules/google-drive/index.ts
1293
+ var FOLDER_MIME_TYPE = "application/vnd.google-apps.folder";
1294
+ var GoogleDriveModule = class extends BaseStorageModule {
1295
+ constructor() {
1296
+ super(...arguments);
1297
+ this.provider = "google_drive";
1298
+ this.auth = null;
1299
+ this.drive = null;
1300
+ this.rootFolderId = "root";
1301
+ this.authCallbacks = {};
1302
+ }
1303
+ /**
1304
+ * Set authentication callbacks for token persistence
1305
+ */
1306
+ setAuthCallbacks(callbacks) {
1307
+ this.authCallbacks = callbacks;
1308
+ }
1309
+ async initialize(config) {
1310
+ await super.initialize(config);
1311
+ const driveConfig = this.getProviderConfig();
1312
+ if (!driveConfig.clientId || !driveConfig.clientSecret) {
1313
+ throw new AuthenticationError("google_drive", "Missing client ID or client secret");
1314
+ }
1315
+ this.auth = createGoogleDriveAuth(
1316
+ {
1317
+ clientId: driveConfig.clientId,
1318
+ clientSecret: driveConfig.clientSecret,
1319
+ redirectUri: driveConfig.redirectUri
1320
+ },
1321
+ this.authCallbacks
1322
+ );
1323
+ if (driveConfig.refreshToken) {
1324
+ await this.auth.setTokens({
1325
+ accessToken: driveConfig.accessToken || "",
1326
+ refreshToken: driveConfig.refreshToken
1327
+ });
1328
+ }
1329
+ this.drive = import_googleapis2.google.drive({ version: "v3", auth: this.auth.getClient() });
1330
+ this.rootFolderId = driveConfig.rootFolderId || "root";
1331
+ }
1332
+ /**
1333
+ * Get the auth instance for OAuth flow
1334
+ */
1335
+ getAuth() {
1336
+ if (!this.auth) {
1337
+ throw new AuthenticationError("google_drive", "Module not initialized");
1338
+ }
1339
+ return this.auth;
1340
+ }
1341
+ /**
1342
+ * Check if user is authenticated
1343
+ */
1344
+ isAuthenticated() {
1345
+ return this.auth?.isAuthenticated() ?? false;
1346
+ }
1347
+ /**
1348
+ * Authenticate with provided tokens
1349
+ */
1350
+ async authenticate(tokens) {
1351
+ if (!this.auth) {
1352
+ throw new AuthenticationError("google_drive", "Module not initialized");
1353
+ }
1354
+ await this.auth.setTokens(tokens);
1355
+ }
1356
+ /**
1357
+ * Ensure authenticated before operations
1358
+ */
1359
+ async ensureAuthenticated() {
1360
+ this.ensureInitialized();
1361
+ if (!this.isAuthenticated()) {
1362
+ throw new AuthenticationError("google_drive", "Not authenticated. Please connect your Google Drive.");
1363
+ }
1364
+ await this.auth.ensureValidToken();
1365
+ }
1366
+ /**
1367
+ * Get folder ID from path (creates folders if needed for certain operations)
1368
+ */
1369
+ async getIdFromPath(virtualPath, createIfMissing = false) {
1370
+ const normalized = this.normalizePath(virtualPath);
1371
+ if (normalized === "/") {
1372
+ return this.rootFolderId;
1373
+ }
1374
+ const segments = normalized.split("/").filter(Boolean);
1375
+ let currentParentId = this.rootFolderId;
1376
+ for (const segment of segments) {
1377
+ const query = `name='${segment}' and '${currentParentId}' in parents and trashed=false`;
1378
+ const response = await this.drive.files.list({
1379
+ q: query,
1380
+ fields: "files(id, name, mimeType)",
1381
+ pageSize: 1
1382
+ });
1383
+ if (response.data.files && response.data.files.length > 0) {
1384
+ currentParentId = response.data.files[0].id;
1385
+ } else if (createIfMissing) {
1386
+ const createResponse = await this.drive.files.create({
1387
+ requestBody: {
1388
+ name: segment,
1389
+ mimeType: FOLDER_MIME_TYPE,
1390
+ parents: [currentParentId]
1391
+ },
1392
+ fields: "id"
1393
+ });
1394
+ currentParentId = createResponse.data.id;
1395
+ } else {
1396
+ return null;
1397
+ }
1398
+ }
1399
+ return currentParentId;
1400
+ }
1401
+ /**
1402
+ * Convert Drive file to FileSystemItem
1403
+ */
1404
+ driveFileToItem(file, virtualPath) {
1405
+ const isFolder2 = file.mimeType === FOLDER_MIME_TYPE;
1406
+ const path3 = virtualPath || "";
1407
+ if (isFolder2) {
1408
+ return createFolderItem({
1409
+ id: file.id,
1410
+ name: file.name,
1411
+ path: path3,
1412
+ createdAt: file.createdTime ? new Date(file.createdTime) : /* @__PURE__ */ new Date(),
1413
+ modifiedAt: file.modifiedTime ? new Date(file.modifiedTime) : /* @__PURE__ */ new Date(),
1414
+ metadata: {
1415
+ driveId: file.id,
1416
+ webViewLink: file.webViewLink
1417
+ }
1418
+ });
1419
+ }
1420
+ return createFileItem({
1421
+ id: file.id,
1422
+ name: file.name,
1423
+ path: path3,
1424
+ size: parseInt(file.size || "0", 10),
1425
+ mimeType: file.mimeType || "application/octet-stream",
1426
+ createdAt: file.createdTime ? new Date(file.createdTime) : /* @__PURE__ */ new Date(),
1427
+ modifiedAt: file.modifiedTime ? new Date(file.modifiedTime) : /* @__PURE__ */ new Date(),
1428
+ metadata: {
1429
+ driveId: file.id,
1430
+ webViewLink: file.webViewLink,
1431
+ thumbnailLink: file.thumbnailLink
1432
+ }
1433
+ });
1434
+ }
1435
+ async createDirectory(virtualPath) {
1436
+ try {
1437
+ await this.ensureAuthenticated();
1438
+ const normalized = this.normalizePath(virtualPath);
1439
+ const parentPath = this.getParentPath(normalized);
1440
+ const folderName = this.getBaseName(normalized);
1441
+ const parentId = await this.getIdFromPath(parentPath, true);
1442
+ if (!parentId) {
1443
+ throw new DirectoryNotFoundError(parentPath);
1444
+ }
1445
+ const existingQuery = `name='${folderName}' and '${parentId}' in parents and mimeType='${FOLDER_MIME_TYPE}' and trashed=false`;
1446
+ const existingResponse = await this.drive.files.list({
1447
+ q: existingQuery,
1448
+ fields: "files(id)",
1449
+ pageSize: 1
1450
+ });
1451
+ if (existingResponse.data.files && existingResponse.data.files.length > 0) {
1452
+ return this.errorResult(`Directory already exists: ${virtualPath}`);
1453
+ }
1454
+ const response = await this.drive.files.create({
1455
+ requestBody: {
1456
+ name: folderName,
1457
+ mimeType: FOLDER_MIME_TYPE,
1458
+ parents: [parentId]
1459
+ },
1460
+ fields: "id, name, mimeType, createdTime, modifiedTime, webViewLink"
1461
+ });
1462
+ const item = this.driveFileToItem(response.data, normalized);
1463
+ return this.successResult(item);
1464
+ } catch (error) {
1465
+ if (error instanceof AuthenticationError || error instanceof DirectoryNotFoundError) {
1466
+ return this.errorResult(error.message);
1467
+ }
1468
+ return this.errorResult(`Failed to create directory: ${error.message}`);
1469
+ }
1470
+ }
1471
+ async removeDirectory(virtualPath, recursive = false) {
1472
+ try {
1473
+ await this.ensureAuthenticated();
1474
+ const folderId = await this.getIdFromPath(virtualPath);
1475
+ if (!folderId) {
1476
+ throw new DirectoryNotFoundError(virtualPath);
1477
+ }
1478
+ if (!recursive) {
1479
+ const childrenResponse = await this.drive.files.list({
1480
+ q: `'${folderId}' in parents and trashed=false`,
1481
+ fields: "files(id)",
1482
+ pageSize: 1
1483
+ });
1484
+ if (childrenResponse.data.files && childrenResponse.data.files.length > 0) {
1485
+ return this.errorResult(`Directory is not empty: ${virtualPath}`);
1486
+ }
1487
+ }
1488
+ await this.drive.files.delete({ fileId: folderId });
1489
+ return this.successResult();
1490
+ } catch (error) {
1491
+ if (error instanceof DirectoryNotFoundError) {
1492
+ return this.errorResult(error.message);
1493
+ }
1494
+ return this.errorResult(`Failed to remove directory: ${error.message}`);
1495
+ }
1496
+ }
1497
+ async uploadFile(source, remotePath, options = {}) {
1498
+ try {
1499
+ await this.ensureAuthenticated();
1500
+ const normalized = this.normalizePath(remotePath);
1501
+ const parentPath = this.getParentPath(normalized);
1502
+ const fileName = this.getBaseName(normalized);
1503
+ const parentId = await this.getIdFromPath(parentPath, true);
1504
+ if (!parentId) {
1505
+ throw new DirectoryNotFoundError(parentPath);
1506
+ }
1507
+ if (!options.overwrite) {
1508
+ const existingQuery = `name='${fileName}' and '${parentId}' in parents and trashed=false`;
1509
+ const existingResponse = await this.drive.files.list({
1510
+ q: existingQuery,
1511
+ fields: "files(id)",
1512
+ pageSize: 1
1513
+ });
1514
+ if (existingResponse.data.files && existingResponse.data.files.length > 0) {
1515
+ throw new FileExistsError(remotePath);
1516
+ }
1517
+ }
1518
+ let media;
1519
+ if (typeof source === "string") {
1520
+ const fs3 = await import("fs");
1521
+ media = {
1522
+ mimeType: "application/octet-stream",
1523
+ body: fs3.createReadStream(source)
1524
+ };
1525
+ } else if (Buffer.isBuffer(source)) {
1526
+ media = {
1527
+ mimeType: "application/octet-stream",
1528
+ body: source
1529
+ };
1530
+ } else {
1531
+ media = {
1532
+ mimeType: "application/octet-stream",
1533
+ body: import_stream2.Readable.fromWeb(source)
1534
+ };
1535
+ }
1536
+ const response = await this.drive.files.create({
1537
+ requestBody: {
1538
+ name: fileName,
1539
+ parents: [parentId]
1540
+ },
1541
+ media,
1542
+ fields: "id, name, mimeType, size, createdTime, modifiedTime, webViewLink, thumbnailLink"
1543
+ });
1544
+ if (options.onProgress) {
1545
+ options.onProgress(100, parseInt(response.data.size || "0", 10), parseInt(response.data.size || "0", 10));
1546
+ }
1547
+ const item = this.driveFileToItem(response.data, normalized);
1548
+ return this.successResult(item);
1549
+ } catch (error) {
1550
+ if (error instanceof AuthenticationError || error instanceof DirectoryNotFoundError || error instanceof FileExistsError) {
1551
+ return this.errorResult(error.message);
1552
+ }
1553
+ return this.errorResult(`Failed to upload file: ${error.message}`);
1554
+ }
1555
+ }
1556
+ async downloadFile(remotePath, localPath, options = {}) {
1557
+ try {
1558
+ await this.ensureAuthenticated();
1559
+ const fileId = await this.getIdFromPath(remotePath);
1560
+ if (!fileId) {
1561
+ throw new FileNotFoundError(remotePath);
1562
+ }
1563
+ const response = await this.drive.files.get(
1564
+ { fileId, alt: "media" },
1565
+ { responseType: "arraybuffer" }
1566
+ );
1567
+ const buffer = Buffer.from(response.data);
1568
+ if (options.onProgress) {
1569
+ options.onProgress(100, buffer.length, buffer.length);
1570
+ }
1571
+ if (localPath) {
1572
+ const fs3 = await import("fs");
1573
+ const path3 = await import("path");
1574
+ await fs3.promises.mkdir(path3.dirname(localPath), { recursive: true });
1575
+ await fs3.promises.writeFile(localPath, buffer);
1576
+ return this.successResult(localPath);
1577
+ }
1578
+ return this.successResult(buffer);
1579
+ } catch (error) {
1580
+ if (error instanceof FileNotFoundError) {
1581
+ return this.errorResult(error.message);
1582
+ }
1583
+ return this.errorResult(`Failed to download file: ${error.message}`);
1584
+ }
1585
+ }
1586
+ async moveItem(sourcePath, destinationPath, _options = {}) {
1587
+ try {
1588
+ await this.ensureAuthenticated();
1589
+ const fileId = await this.getIdFromPath(sourcePath);
1590
+ if (!fileId) {
1591
+ throw new FileNotFoundError(sourcePath);
1592
+ }
1593
+ const file = await this.drive.files.get({
1594
+ fileId,
1595
+ fields: "parents"
1596
+ });
1597
+ const previousParents = file.data.parents?.join(",") || "";
1598
+ const destParentPath = this.getParentPath(destinationPath);
1599
+ const newName = this.getBaseName(destinationPath);
1600
+ const newParentId = await this.getIdFromPath(destParentPath, true);
1601
+ if (!newParentId) {
1602
+ throw new DirectoryNotFoundError(destParentPath);
1603
+ }
1604
+ const response = await this.drive.files.update({
1605
+ fileId,
1606
+ addParents: newParentId,
1607
+ removeParents: previousParents,
1608
+ requestBody: {
1609
+ name: newName
1610
+ },
1611
+ fields: "id, name, mimeType, size, createdTime, modifiedTime, webViewLink, thumbnailLink"
1612
+ });
1613
+ const item = this.driveFileToItem(response.data, destinationPath);
1614
+ return this.successResult(item);
1615
+ } catch (error) {
1616
+ if (error instanceof FileNotFoundError || error instanceof DirectoryNotFoundError) {
1617
+ return this.errorResult(error.message);
1618
+ }
1619
+ return this.errorResult(`Failed to move item: ${error.message}`);
1620
+ }
1621
+ }
1622
+ async deleteFile(virtualPath) {
1623
+ try {
1624
+ await this.ensureAuthenticated();
1625
+ const fileId = await this.getIdFromPath(virtualPath);
1626
+ if (!fileId) {
1627
+ throw new FileNotFoundError(virtualPath);
1628
+ }
1629
+ await this.drive.files.delete({ fileId });
1630
+ return this.successResult();
1631
+ } catch (error) {
1632
+ if (error instanceof FileNotFoundError) {
1633
+ return this.errorResult(error.message);
1634
+ }
1635
+ return this.errorResult(`Failed to delete file: ${error.message}`);
1636
+ }
1637
+ }
1638
+ async renameFile(virtualPath, newName, _options = {}) {
1639
+ try {
1640
+ await this.ensureAuthenticated();
1641
+ const fileId = await this.getIdFromPath(virtualPath);
1642
+ if (!fileId) {
1643
+ throw new FileNotFoundError(virtualPath);
1644
+ }
1645
+ const response = await this.drive.files.update({
1646
+ fileId,
1647
+ requestBody: {
1648
+ name: newName
1649
+ },
1650
+ fields: "id, name, mimeType, size, createdTime, modifiedTime, webViewLink, thumbnailLink"
1651
+ });
1652
+ const parentPath = this.getParentPath(virtualPath);
1653
+ const newPath = this.joinPath(parentPath, newName);
1654
+ const item = this.driveFileToItem(response.data, newPath);
1655
+ return this.successResult(item);
1656
+ } catch (error) {
1657
+ if (error instanceof FileNotFoundError) {
1658
+ return this.errorResult(error.message);
1659
+ }
1660
+ return this.errorResult(`Failed to rename file: ${error.message}`);
1661
+ }
1662
+ }
1663
+ async renameFolder(virtualPath, newName, _options = {}) {
1664
+ try {
1665
+ await this.ensureAuthenticated();
1666
+ const folderId = await this.getIdFromPath(virtualPath);
1667
+ if (!folderId) {
1668
+ throw new DirectoryNotFoundError(virtualPath);
1669
+ }
1670
+ const response = await this.drive.files.update({
1671
+ fileId: folderId,
1672
+ requestBody: {
1673
+ name: newName
1674
+ },
1675
+ fields: "id, name, mimeType, createdTime, modifiedTime, webViewLink"
1676
+ });
1677
+ const parentPath = this.getParentPath(virtualPath);
1678
+ const newPath = this.joinPath(parentPath, newName);
1679
+ const item = this.driveFileToItem(response.data, newPath);
1680
+ return this.successResult(item);
1681
+ } catch (error) {
1682
+ if (error instanceof DirectoryNotFoundError) {
1683
+ return this.errorResult(error.message);
1684
+ }
1685
+ return this.errorResult(`Failed to rename folder: ${error.message}`);
1686
+ }
1687
+ }
1688
+ async listDirectory(virtualPath, options = {}) {
1689
+ try {
1690
+ await this.ensureAuthenticated();
1691
+ const folderId = await this.getIdFromPath(virtualPath);
1692
+ if (!folderId) {
1693
+ throw new DirectoryNotFoundError(virtualPath);
1694
+ }
1695
+ const items = [];
1696
+ let pageToken;
1697
+ do {
1698
+ const response = await this.drive.files.list({
1699
+ q: `'${folderId}' in parents and trashed=false`,
1700
+ fields: "nextPageToken, files(id, name, mimeType, size, createdTime, modifiedTime, webViewLink, thumbnailLink)",
1701
+ pageSize: 100,
1702
+ pageToken,
1703
+ orderBy: "folder,name"
1704
+ });
1705
+ if (response.data.files) {
1706
+ for (const file of response.data.files) {
1707
+ if (!options.includeHidden && file.name?.startsWith(".")) {
1708
+ continue;
1709
+ }
1710
+ const itemPath = this.joinPath(virtualPath, file.name);
1711
+ const item = this.driveFileToItem(file, itemPath);
1712
+ if (options.filter && !options.filter(item)) {
1713
+ continue;
1714
+ }
1715
+ items.push(item);
1716
+ if (options.recursive && file.mimeType === FOLDER_MIME_TYPE) {
1717
+ const subResult = await this.listDirectory(itemPath, options);
1718
+ if (subResult.success && subResult.data) {
1719
+ items.push(...subResult.data);
1720
+ }
1721
+ }
1722
+ }
1723
+ }
1724
+ pageToken = response.data.nextPageToken || void 0;
1725
+ } while (pageToken);
1726
+ return this.successResult(items);
1727
+ } catch (error) {
1728
+ if (error instanceof DirectoryNotFoundError) {
1729
+ return this.errorResult(error.message);
1730
+ }
1731
+ return this.errorResult(`Failed to list directory: ${error.message}`);
1732
+ }
1733
+ }
1734
+ async getItem(virtualPath) {
1735
+ try {
1736
+ await this.ensureAuthenticated();
1737
+ const fileId = await this.getIdFromPath(virtualPath);
1738
+ if (!fileId) {
1739
+ throw new FileNotFoundError(virtualPath);
1740
+ }
1741
+ const response = await this.drive.files.get({
1742
+ fileId,
1743
+ fields: "id, name, mimeType, size, createdTime, modifiedTime, webViewLink, thumbnailLink"
1744
+ });
1745
+ const item = this.driveFileToItem(response.data, virtualPath);
1746
+ return this.successResult(item);
1747
+ } catch (error) {
1748
+ if (error instanceof FileNotFoundError) {
1749
+ return this.errorResult(error.message);
1750
+ }
1751
+ return this.errorResult(`Failed to get item: ${error.message}`);
1752
+ }
1753
+ }
1754
+ async exists(virtualPath) {
1755
+ try {
1756
+ await this.ensureAuthenticated();
1757
+ const fileId = await this.getIdFromPath(virtualPath);
1758
+ return fileId !== null;
1759
+ } catch {
1760
+ return false;
1761
+ }
1762
+ }
1763
+ async getFolderTree(path3 = "/", depth = 3) {
1764
+ try {
1765
+ await this.ensureAuthenticated();
1766
+ return super.getFolderTree(path3, depth);
1767
+ } catch (error) {
1768
+ return this.errorResult(`Failed to get folder tree: ${error.message}`);
1769
+ }
1770
+ }
1771
+ };
1772
+ function createGoogleDriveModule() {
1773
+ return new GoogleDriveModule();
1774
+ }
1775
+
1776
+ // src/modules/index.ts
1777
+ var moduleRegistry = {
1778
+ local: createLocalModule,
1779
+ google_drive: createGoogleDriveModule
1780
+ };
1781
+ function getRegisteredProviders() {
1782
+ return Object.keys(moduleRegistry);
1783
+ }
1784
+ function isProviderRegistered(provider) {
1785
+ return provider in moduleRegistry;
1786
+ }
1787
+ function createModule(provider) {
1788
+ const factory = moduleRegistry[provider];
1789
+ if (!factory) {
1790
+ throw new ConfigurationError(`Unknown storage provider: ${provider}`);
1791
+ }
1792
+ return factory();
1793
+ }
1794
+ async function createAndInitializeModule(config) {
1795
+ const module2 = createModule(config.provider);
1796
+ await module2.initialize(config);
1797
+ return module2;
1798
+ }
1799
+ function registerModule(provider, factory) {
1800
+ moduleRegistry[provider] = factory;
1801
+ }
1802
+
1803
+ // src/services/file-manager.ts
1804
+ var FileManager = class {
1805
+ constructor(options = {}) {
1806
+ this.module = null;
1807
+ this.config = null;
1808
+ this.initialized = false;
1809
+ this.options = {
1810
+ autoInit: true,
1811
+ ...options
1812
+ };
1813
+ }
1814
+ /**
1815
+ * Initialize the file manager with configuration
1816
+ */
1817
+ async initialize(config) {
1818
+ if (this.initialized) {
1819
+ return;
1820
+ }
1821
+ if (config) {
1822
+ this.config = config;
1823
+ } else if (this.options.config) {
1824
+ this.config = this.options.config;
1825
+ } else {
1826
+ this.config = await loadConfigAsync(this.options.configPath);
1827
+ }
1828
+ this.module = await createAndInitializeModule(this.config);
1829
+ this.initialized = true;
1830
+ }
1831
+ /**
1832
+ * Initialize synchronously (uses sync config loading)
1833
+ */
1834
+ initializeSync(config) {
1835
+ if (this.initialized) {
1836
+ return;
1837
+ }
1838
+ if (config) {
1839
+ this.config = config;
1840
+ } else if (this.options.config) {
1841
+ this.config = this.options.config;
1842
+ } else {
1843
+ this.config = loadConfig(this.options.configPath);
1844
+ }
1845
+ this.module = createModule(this.config.provider);
1846
+ }
1847
+ /**
1848
+ * Check if manager is initialized
1849
+ */
1850
+ isInitialized() {
1851
+ return this.initialized;
1852
+ }
1853
+ /**
1854
+ * Get the current configuration
1855
+ */
1856
+ getConfig() {
1857
+ return this.config;
1858
+ }
1859
+ /**
1860
+ * Get the current provider
1861
+ */
1862
+ getProvider() {
1863
+ return this.config?.provider ?? null;
1864
+ }
1865
+ /**
1866
+ * Get the underlying storage module
1867
+ */
1868
+ getModule() {
1869
+ this.ensureInitialized();
1870
+ return this.module;
1871
+ }
1872
+ /**
1873
+ * Ensure manager is initialized
1874
+ */
1875
+ ensureInitialized() {
1876
+ if (!this.initialized || !this.module) {
1877
+ throw new Error("FileManager not initialized. Call initialize() first.");
1878
+ }
1879
+ }
1880
+ // ============ Directory Operations ============
1881
+ /**
1882
+ * Create a directory at the specified path
1883
+ */
1884
+ async createDirectory(path3) {
1885
+ this.ensureInitialized();
1886
+ return this.module.createDirectory(path3);
1887
+ }
1888
+ /**
1889
+ * Remove a directory
1890
+ * @param path - Directory path
1891
+ * @param recursive - If true, remove directory and all contents
1892
+ */
1893
+ async removeDirectory(path3, recursive = false) {
1894
+ this.ensureInitialized();
1895
+ return this.module.removeDirectory(path3, recursive);
1896
+ }
1897
+ // ============ File Operations ============
1898
+ /**
1899
+ * Upload/save a file
1900
+ * @param source - File path, Buffer, or ReadableStream
1901
+ * @param remotePath - Destination path in storage
1902
+ * @param options - Upload options
1903
+ */
1904
+ async uploadFile(source, remotePath, options) {
1905
+ this.ensureInitialized();
1906
+ return this.module.uploadFile(source, remotePath, options);
1907
+ }
1908
+ /**
1909
+ * Download a file
1910
+ * @param remotePath - Path in storage
1911
+ * @param localPath - Optional local destination path
1912
+ * @param options - Download options
1913
+ */
1914
+ async downloadFile(remotePath, localPath, options) {
1915
+ this.ensureInitialized();
1916
+ return this.module.downloadFile(remotePath, localPath, options);
1917
+ }
1918
+ /**
1919
+ * Move a file or folder
1920
+ * @param sourcePath - Current path
1921
+ * @param destinationPath - New path
1922
+ * @param options - Move options
1923
+ */
1924
+ async moveItem(sourcePath, destinationPath, options) {
1925
+ this.ensureInitialized();
1926
+ return this.module.moveItem(sourcePath, destinationPath, options);
1927
+ }
1928
+ /**
1929
+ * Delete a file
1930
+ */
1931
+ async deleteFile(path3) {
1932
+ this.ensureInitialized();
1933
+ return this.module.deleteFile(path3);
1934
+ }
1935
+ /**
1936
+ * Rename a file
1937
+ * @param path - Current file path
1938
+ * @param newName - New filename (not full path)
1939
+ * @param options - Rename options
1940
+ */
1941
+ async renameFile(path3, newName, options) {
1942
+ this.ensureInitialized();
1943
+ return this.module.renameFile(path3, newName, options);
1944
+ }
1945
+ /**
1946
+ * Rename a folder
1947
+ * @param path - Current folder path
1948
+ * @param newName - New folder name (not full path)
1949
+ * @param options - Rename options
1950
+ */
1951
+ async renameFolder(path3, newName, options) {
1952
+ this.ensureInitialized();
1953
+ return this.module.renameFolder(path3, newName, options);
1954
+ }
1955
+ // ============ Query Operations ============
1956
+ /**
1957
+ * List contents of a directory
1958
+ * @param path - Directory path
1959
+ * @param options - List options
1960
+ */
1961
+ async listDirectory(path3, options) {
1962
+ this.ensureInitialized();
1963
+ return this.module.listDirectory(path3, options);
1964
+ }
1965
+ /**
1966
+ * Get information about a file or folder
1967
+ */
1968
+ async getItem(path3) {
1969
+ this.ensureInitialized();
1970
+ return this.module.getItem(path3);
1971
+ }
1972
+ /**
1973
+ * Check if a file or folder exists
1974
+ */
1975
+ async exists(path3) {
1976
+ this.ensureInitialized();
1977
+ return this.module.exists(path3);
1978
+ }
1979
+ /**
1980
+ * Get folder tree structure
1981
+ * @param path - Starting path (default: root)
1982
+ * @param depth - Maximum depth to traverse
1983
+ */
1984
+ async getFolderTree(path3 = "/", depth = 3) {
1985
+ this.ensureInitialized();
1986
+ return this.module.getFolderTree(path3, depth);
1987
+ }
1988
+ // ============ Convenience Methods ============
1989
+ /**
1990
+ * Create a file with string content
1991
+ */
1992
+ async writeFile(path3, content, options) {
1993
+ const buffer = Buffer.from(content, "utf-8");
1994
+ return this.uploadFile(buffer, path3, options);
1995
+ }
1996
+ /**
1997
+ * Read a file as string
1998
+ */
1999
+ async readFile(path3) {
2000
+ const result = await this.downloadFile(path3);
2001
+ if (!result.success) {
2002
+ return { success: false, error: result.error };
2003
+ }
2004
+ if (Buffer.isBuffer(result.data)) {
2005
+ return { success: true, data: result.data.toString("utf-8") };
2006
+ }
2007
+ const fs3 = await import("fs");
2008
+ const content = await fs3.promises.readFile(result.data, "utf-8");
2009
+ return { success: true, data: content };
2010
+ }
2011
+ /**
2012
+ * Copy a file to a new location
2013
+ */
2014
+ async copyFile(sourcePath, destinationPath, options) {
2015
+ const downloadResult = await this.downloadFile(sourcePath);
2016
+ if (!downloadResult.success) {
2017
+ return { success: false, error: downloadResult.error };
2018
+ }
2019
+ const buffer = Buffer.isBuffer(downloadResult.data) ? downloadResult.data : await import("fs").then((fs3) => fs3.promises.readFile(downloadResult.data));
2020
+ return this.uploadFile(buffer, destinationPath, options);
2021
+ }
2022
+ /**
2023
+ * Ensure a directory exists (creates if needed)
2024
+ */
2025
+ async ensureDirectory(path3) {
2026
+ const exists = await this.exists(path3);
2027
+ if (exists) {
2028
+ const item = await this.getItem(path3);
2029
+ if (item.success && item.data?.isDirectory) {
2030
+ return { success: true, data: item.data };
2031
+ }
2032
+ return { success: false, error: "Path exists but is not a directory" };
2033
+ }
2034
+ return this.createDirectory(path3);
2035
+ }
2036
+ };
2037
+ function createFileManager(options) {
2038
+ return new FileManager(options);
2039
+ }
2040
+ async function createInitializedFileManager(options) {
2041
+ const manager = new FileManager(options);
2042
+ await manager.initialize();
2043
+ return manager;
2044
+ }
2045
+
2046
+ // src/common/naming-utils.ts
2047
+ var DEFAULT_DATE_FORMATS = [
2048
+ "YYYY",
2049
+ "YY",
2050
+ "MM",
2051
+ "M",
2052
+ "DD",
2053
+ "D",
2054
+ "MMM",
2055
+ "MMMM",
2056
+ "YYYY-MM-DD",
2057
+ "YYYY-MMM-DD",
2058
+ "DD-MM-YYYY",
2059
+ "MM-DD-YYYY"
2060
+ ];
2061
+ var MONTH_NAMES_SHORT = [
2062
+ "Jan",
2063
+ "Feb",
2064
+ "Mar",
2065
+ "Apr",
2066
+ "May",
2067
+ "Jun",
2068
+ "Jul",
2069
+ "Aug",
2070
+ "Sep",
2071
+ "Oct",
2072
+ "Nov",
2073
+ "Dec"
2074
+ ];
2075
+ var MONTH_NAMES_FULL = [
2076
+ "January",
2077
+ "February",
2078
+ "March",
2079
+ "April",
2080
+ "May",
2081
+ "June",
2082
+ "July",
2083
+ "August",
2084
+ "September",
2085
+ "October",
2086
+ "November",
2087
+ "December"
2088
+ ];
2089
+ var SYSTEM_DATE_VARIABLES = [
2090
+ { variable_name: "YYYY", description: "Full year (4 digits)", example_value: "2024", category: "date" },
2091
+ { variable_name: "YY", description: "Year (2 digits)", example_value: "24", category: "date" },
2092
+ { variable_name: "MM", description: "Month (2 digits, 01-12)", example_value: "01", category: "date" },
2093
+ { variable_name: "M", description: "Month (1-12)", example_value: "1", category: "date" },
2094
+ { variable_name: "DD", description: "Day (2 digits, 01-31)", example_value: "15", category: "date" },
2095
+ { variable_name: "D", description: "Day (1-31)", example_value: "15", category: "date" },
2096
+ { variable_name: "MMM", description: "Short month name", example_value: "Jan", category: "date" },
2097
+ { variable_name: "MMMM", description: "Full month name", example_value: "January", category: "date" },
2098
+ { variable_name: "YYYY-MM-DD", description: "ISO date format", example_value: "2024-01-15", category: "date" },
2099
+ { variable_name: "YYYY-MMM-DD", description: "Date with month name", example_value: "2024-Jan-15", category: "date" },
2100
+ { variable_name: "DD-MM-YYYY", description: "Day-Month-Year", example_value: "15-01-2024", category: "date" },
2101
+ { variable_name: "MM-DD-YYYY", description: "Month-Day-Year", example_value: "01-15-2024", category: "date" }
2102
+ ];
2103
+ var SYSTEM_FILE_VARIABLES = [
2104
+ { variable_name: "original_name", description: "Original filename without extension", example_value: "document", category: "file" },
2105
+ { variable_name: "extension", description: "Original file extension with dot", example_value: ".pdf", category: "file" },
2106
+ { variable_name: "ext", description: "Extension without dot", example_value: "pdf", category: "file" }
2107
+ ];
2108
+ var SYSTEM_COUNTER_VARIABLES = [
2109
+ { variable_name: "counter", description: "Auto-incrementing number (3 digits)", example_value: "001", category: "counter" }
2110
+ ];
2111
+ var ALL_SYSTEM_VARIABLES = [
2112
+ ...SYSTEM_DATE_VARIABLES,
2113
+ ...SYSTEM_FILE_VARIABLES,
2114
+ ...SYSTEM_COUNTER_VARIABLES
2115
+ ];
2116
+ function formatDateToken(date, format) {
2117
+ const year = date.getFullYear();
2118
+ const month = date.getMonth();
2119
+ const day = date.getDate();
2120
+ switch (format) {
2121
+ case "YYYY":
2122
+ return String(year);
2123
+ case "YY":
2124
+ return String(year).slice(-2);
2125
+ case "MM":
2126
+ return String(month + 1).padStart(2, "0");
2127
+ case "M":
2128
+ return String(month + 1);
2129
+ case "DD":
2130
+ return String(day).padStart(2, "0");
2131
+ case "D":
2132
+ return String(day);
2133
+ case "MMM":
2134
+ return MONTH_NAMES_SHORT[month];
2135
+ case "MMMM":
2136
+ return MONTH_NAMES_FULL[month];
2137
+ case "YYYY-MM-DD":
2138
+ return `${year}-${String(month + 1).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
2139
+ case "YYYY-MMM-DD":
2140
+ return `${year}-${MONTH_NAMES_SHORT[month]}-${String(day).padStart(2, "0")}`;
2141
+ case "DD-MM-YYYY":
2142
+ return `${String(day).padStart(2, "0")}-${String(month + 1).padStart(2, "0")}-${year}`;
2143
+ case "MM-DD-YYYY":
2144
+ return `${String(month + 1).padStart(2, "0")}-${String(day).padStart(2, "0")}-${year}`;
2145
+ default:
2146
+ return format;
2147
+ }
2148
+ }
2149
+ function isDateVariable(variableName, dateFormats = DEFAULT_DATE_FORMATS) {
2150
+ return dateFormats.includes(variableName);
2151
+ }
2152
+ function isFileMetadataVariable(variableName) {
2153
+ return ["original_name", "extension", "ext"].includes(variableName);
2154
+ }
2155
+ function isCounterVariable(variableName) {
2156
+ return variableName === "counter" || variableName.startsWith("counter:");
2157
+ }
2158
+ function formatCounter(value, digits = 3) {
2159
+ return String(value).padStart(digits, "0");
2160
+ }
2161
+ function getFileMetadataValues(filename) {
2162
+ if (!filename) {
2163
+ return {
2164
+ original_name: "",
2165
+ extension: "",
2166
+ ext: ""
2167
+ };
2168
+ }
2169
+ const extension = getExtension(filename);
2170
+ const originalName = getNameWithoutExtension(filename);
2171
+ return {
2172
+ original_name: originalName,
2173
+ extension,
2174
+ ext: extension.startsWith(".") ? extension.slice(1) : extension
2175
+ };
2176
+ }
2177
+ function generateNameFromPattern(pattern, variables, options = {}, originalFileName) {
2178
+ if (pattern.length === 0) {
2179
+ return { success: false, error: "Pattern is empty" };
2180
+ }
2181
+ const {
2182
+ dateFormats = DEFAULT_DATE_FORMATS,
2183
+ date = /* @__PURE__ */ new Date(),
2184
+ counterValue = 1,
2185
+ counterDigits = 3
2186
+ } = options;
2187
+ const fileMetadata = getFileMetadataValues(originalFileName);
2188
+ const parts = [];
2189
+ for (const segment of pattern) {
2190
+ if (segment.type === "literal") {
2191
+ parts.push(segment.value);
2192
+ } else if (segment.type === "variable") {
2193
+ const varName = segment.value;
2194
+ if (isDateVariable(varName, dateFormats)) {
2195
+ parts.push(formatDateToken(date, varName));
2196
+ } else if (isFileMetadataVariable(varName)) {
2197
+ parts.push(fileMetadata[varName] || "");
2198
+ } else if (isCounterVariable(varName)) {
2199
+ if (varName.startsWith("counter:")) {
2200
+ const customDigits = parseInt(varName.split(":")[1], 10);
2201
+ parts.push(formatCounter(counterValue, isNaN(customDigits) ? counterDigits : customDigits));
2202
+ } else {
2203
+ parts.push(formatCounter(counterValue, counterDigits));
2204
+ }
2205
+ } else if (varName in variables) {
2206
+ parts.push(variables[varName]);
2207
+ } else {
2208
+ return {
2209
+ success: false,
2210
+ error: `Missing value for variable: ${varName}`
2211
+ };
2212
+ }
2213
+ }
2214
+ }
2215
+ const name = parts.join("");
2216
+ if (!name.trim()) {
2217
+ return { success: false, error: "Generated name is empty" };
2218
+ }
2219
+ return { success: true, name };
2220
+ }
2221
+ function hazo_files_generate_folder_name(schema, variables, options) {
2222
+ const result = generateNameFromPattern(
2223
+ schema.folderPattern,
2224
+ variables,
2225
+ options
2226
+ );
2227
+ if (!result.success || !result.name) {
2228
+ return result;
2229
+ }
2230
+ const segments = result.name.split("/");
2231
+ const sanitizedSegments = segments.map((seg) => seg.trim()).filter((seg) => seg.length > 0).map((seg) => sanitizeFilename(seg));
2232
+ if (sanitizedSegments.length === 0) {
2233
+ return { success: false, error: "Generated folder name is empty" };
2234
+ }
2235
+ return {
2236
+ success: true,
2237
+ name: sanitizedSegments.join("/")
2238
+ };
2239
+ }
2240
+ function hazo_files_generate_file_name(schema, variables, originalFileName, options) {
2241
+ const { preserveExtension = true, ...restOptions } = options || {};
2242
+ const result = generateNameFromPattern(
2243
+ schema.filePattern,
2244
+ variables,
2245
+ restOptions,
2246
+ originalFileName
2247
+ );
2248
+ if (!result.success || !result.name) {
2249
+ return result;
2250
+ }
2251
+ let finalName = result.name;
2252
+ if (originalFileName && preserveExtension) {
2253
+ const originalExtension = getExtension(originalFileName);
2254
+ if (originalExtension) {
2255
+ const nameWithoutExt = getNameWithoutExtension(finalName);
2256
+ finalName = nameWithoutExt + originalExtension;
2257
+ }
2258
+ }
2259
+ return {
2260
+ success: true,
2261
+ name: sanitizeFilename(finalName)
2262
+ };
2263
+ }
2264
+ function validateNamingRuleSchema(schema) {
2265
+ if (!schema || typeof schema !== "object") return false;
2266
+ const s = schema;
2267
+ if (typeof s.version !== "number") return false;
2268
+ if (!Array.isArray(s.filePattern) || !Array.isArray(s.folderPattern)) return false;
2269
+ const isValidSegment = (seg) => {
2270
+ if (!seg || typeof seg !== "object") return false;
2271
+ const segment = seg;
2272
+ return typeof segment.id === "string" && (segment.type === "variable" || segment.type === "literal") && typeof segment.value === "string";
2273
+ };
2274
+ return s.filePattern.every(isValidSegment) && s.folderPattern.every(isValidSegment);
2275
+ }
2276
+ function createEmptyNamingRuleSchema() {
2277
+ return {
2278
+ version: 1,
2279
+ filePattern: [],
2280
+ folderPattern: [],
2281
+ metadata: {
2282
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
2283
+ }
2284
+ };
2285
+ }
2286
+ function generateSegmentId() {
2287
+ return `seg_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
2288
+ }
2289
+ function createVariableSegment(variableName) {
2290
+ return {
2291
+ id: generateSegmentId(),
2292
+ type: "variable",
2293
+ value: variableName
2294
+ };
2295
+ }
2296
+ function createLiteralSegment(text) {
2297
+ return {
2298
+ id: generateSegmentId(),
2299
+ type: "literal",
2300
+ value: text
2301
+ };
2302
+ }
2303
+ function patternToString(pattern) {
2304
+ return pattern.map((seg) => seg.type === "variable" ? `{${seg.value}}` : seg.value).join("");
2305
+ }
2306
+ function parsePatternString(patternStr) {
2307
+ const segments = [];
2308
+ const regex = /\{([^}]+)\}|([^{]+)/g;
2309
+ let match;
2310
+ while ((match = regex.exec(patternStr)) !== null) {
2311
+ if (match[1]) {
2312
+ segments.push(createVariableSegment(match[1]));
2313
+ } else if (match[2]) {
2314
+ segments.push(createLiteralSegment(match[2]));
2315
+ }
2316
+ }
2317
+ return segments;
2318
+ }
2319
+ function clonePattern(pattern) {
2320
+ return pattern.map((seg) => ({
2321
+ ...seg,
2322
+ id: generateSegmentId()
2323
+ }));
2324
+ }
2325
+ function getSystemVariablePreviewValues(date = /* @__PURE__ */ new Date(), options = {}) {
2326
+ const { counterValue = 1, counterDigits = 3, originalFileName } = options;
2327
+ const fileMetadata = getFileMetadataValues(originalFileName);
2328
+ const values = {};
2329
+ for (const format of DEFAULT_DATE_FORMATS) {
2330
+ values[format] = formatDateToken(date, format);
2331
+ }
2332
+ values.original_name = fileMetadata.original_name || "document";
2333
+ values.extension = fileMetadata.extension || ".pdf";
2334
+ values.ext = fileMetadata.ext || "pdf";
2335
+ values.counter = formatCounter(counterValue, counterDigits);
2336
+ return values;
2337
+ }
2338
+ function generatePreviewName(pattern, userVariables, options = {}) {
2339
+ if (pattern.length === 0) {
2340
+ return "(empty pattern)";
2341
+ }
2342
+ const systemValues = getSystemVariablePreviewValues(
2343
+ options.date,
2344
+ options
2345
+ );
2346
+ const userValues = {};
2347
+ for (const variable of userVariables) {
2348
+ userValues[variable.variable_name] = variable.example_value;
2349
+ }
2350
+ const allValues = { ...userValues, ...systemValues };
2351
+ const parts = [];
2352
+ for (const segment of pattern) {
2353
+ if (segment.type === "literal") {
2354
+ parts.push(segment.value);
2355
+ } else if (segment.type === "variable") {
2356
+ const value = allValues[segment.value];
2357
+ if (value !== void 0) {
2358
+ parts.push(value);
2359
+ } else {
2360
+ parts.push(`{${segment.value}}`);
2361
+ }
2362
+ }
2363
+ }
2364
+ return parts.join("") || "(empty)";
2365
+ }
2366
+ // Annotate the CommonJS export names for ESM import in node:
2367
+ 0 && (module.exports = {
2368
+ ALL_SYSTEM_VARIABLES,
2369
+ AuthenticationError,
2370
+ ConfigurationError,
2371
+ DEFAULT_DATE_FORMATS,
2372
+ DirectoryExistsError,
2373
+ DirectoryNotEmptyError,
2374
+ DirectoryNotFoundError,
2375
+ FileExistsError,
2376
+ FileManager,
2377
+ FileNotFoundError,
2378
+ FileTooLargeError,
2379
+ GoogleDriveAuth,
2380
+ GoogleDriveModule,
2381
+ HazoFilesError,
2382
+ InvalidExtensionError,
2383
+ InvalidPathError,
2384
+ LocalStorageModule,
2385
+ OperationError,
2386
+ PermissionDeniedError,
2387
+ SYSTEM_COUNTER_VARIABLES,
2388
+ SYSTEM_DATE_VARIABLES,
2389
+ SYSTEM_FILE_VARIABLES,
2390
+ clonePattern,
2391
+ createAndInitializeModule,
2392
+ createEmptyNamingRuleSchema,
2393
+ createFileItem,
2394
+ createFileManager,
2395
+ createFolderItem,
2396
+ createGoogleDriveAuth,
2397
+ createGoogleDriveModule,
2398
+ createInitializedFileManager,
2399
+ createLiteralSegment,
2400
+ createLocalModule,
2401
+ createModule,
2402
+ createVariableSegment,
2403
+ errorResult,
2404
+ filterItems,
2405
+ formatBytes,
2406
+ formatCounter,
2407
+ formatDateToken,
2408
+ generateId,
2409
+ generatePreviewName,
2410
+ generateSampleConfig,
2411
+ generateSegmentId,
2412
+ getBaseName,
2413
+ getBreadcrumbs,
2414
+ getDirName,
2415
+ getExtension,
2416
+ getExtensionFromMime,
2417
+ getFileCategory,
2418
+ getFileMetadataValues,
2419
+ getMimeType,
2420
+ getNameWithoutExtension,
2421
+ getParentPath,
2422
+ getPathSegments,
2423
+ getRegisteredProviders,
2424
+ getRelativePath,
2425
+ getSystemVariablePreviewValues,
2426
+ hasExtension,
2427
+ hazo_files_generate_file_name,
2428
+ hazo_files_generate_folder_name,
2429
+ isAudio,
2430
+ isChildPath,
2431
+ isCounterVariable,
2432
+ isDateVariable,
2433
+ isDocument,
2434
+ isFile,
2435
+ isFileMetadataVariable,
2436
+ isFolder,
2437
+ isImage,
2438
+ isPreviewable,
2439
+ isProviderRegistered,
2440
+ isText,
2441
+ isVideo,
2442
+ joinPath,
2443
+ loadConfig,
2444
+ loadConfigAsync,
2445
+ normalizePath,
2446
+ parseConfig,
2447
+ parsePatternString,
2448
+ patternToString,
2449
+ registerModule,
2450
+ sanitizeFilename,
2451
+ saveConfig,
2452
+ sortItems,
2453
+ successResult,
2454
+ validateNamingRuleSchema,
2455
+ validatePath
2456
+ });
2457
+ //# sourceMappingURL=index.js.map