@huyooo/file-explorer-core 0.4.27 → 0.4.30
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.d.ts +128 -30
- package/dist/index.js +1 -1
- package/package.json +4 -15
package/dist/index.d.ts
CHANGED
|
@@ -36,6 +36,11 @@ interface FileItem {
|
|
|
36
36
|
thumbnailUrl?: string;
|
|
37
37
|
/** 子项(仅文件夹) */
|
|
38
38
|
children?: FileItem[];
|
|
39
|
+
/**
|
|
40
|
+
* 标记 iOS-on-Mac (Designed for iPad/iPhone) 应用
|
|
41
|
+
* 仅在 macOS「应用程序」合并视图中对 APPLICATION 类型项有效
|
|
42
|
+
*/
|
|
43
|
+
isIosOnMac?: boolean;
|
|
39
44
|
}
|
|
40
45
|
/**
|
|
41
46
|
* 文件信息
|
|
@@ -141,7 +146,7 @@ declare function isMediaFile(type: FileType): boolean;
|
|
|
141
146
|
declare function isPreviewable(type: FileType): boolean;
|
|
142
147
|
|
|
143
148
|
/**
|
|
144
|
-
*
|
|
149
|
+
* 格式化文件大小(最小单位 KB)
|
|
145
150
|
*/
|
|
146
151
|
declare function formatFileSize(bytes: number): string;
|
|
147
152
|
/**
|
|
@@ -170,6 +175,10 @@ interface ReadDirectoryOptions {
|
|
|
170
175
|
}
|
|
171
176
|
/**
|
|
172
177
|
* 读取目录内容
|
|
178
|
+
*
|
|
179
|
+
* 特殊处理: macOS 上访问 `/Applications` 时,会透明合并 `/Applications`、
|
|
180
|
+
* `~/Applications`、`/System/Applications`、`/System/Applications/Utilities`
|
|
181
|
+
* 四个目录的应用,并把应用名替换为本地化显示名(对齐 Finder 「应用程序」视图)。
|
|
173
182
|
*/
|
|
174
183
|
declare function readDirectory(dirPath: string, options?: ReadDirectoryOptions): Promise<FileItem[]>;
|
|
175
184
|
/**
|
|
@@ -386,9 +395,48 @@ declare function getHomeDirectory(): string;
|
|
|
386
395
|
*/
|
|
387
396
|
declare function getPlatform(): NodeJS.Platform;
|
|
388
397
|
|
|
398
|
+
interface ListFilesOptions {
|
|
399
|
+
/** 最大递归深度,0 或不传表示不限 */
|
|
400
|
+
maxDepth?: number;
|
|
401
|
+
/** 是否在结果中包含目录路径,默认 false */
|
|
402
|
+
includeDirs?: boolean;
|
|
403
|
+
/** 最大结果数量(提前截断) */
|
|
404
|
+
maxFiles?: number;
|
|
405
|
+
/** 额外排除的目录名列表(叠加在 .gitignore 之上),默认 [] */
|
|
406
|
+
excludeDirs?: string[];
|
|
407
|
+
/** 额外排除规则(gitignore 语法),叠加在 .gitignore/.ignore 之上 */
|
|
408
|
+
extraIgnoreRules?: string[];
|
|
409
|
+
/** 是否遵守 .gitignore / .ignore 文件,默认 true */
|
|
410
|
+
useIgnoreFiles?: boolean;
|
|
411
|
+
/** 是否包含隐藏文件/目录(以 . 开头),默认 true */
|
|
412
|
+
includeHidden?: boolean;
|
|
413
|
+
/** 可选取消信号 */
|
|
414
|
+
signal?: AbortSignal;
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* 列出目录下所有非忽略文件
|
|
418
|
+
*
|
|
419
|
+
* 使用 fdir 快速扫描 + ignore 解析根目录 .gitignore/.ignore。
|
|
420
|
+
*/
|
|
421
|
+
declare function listFiles(rootPath: string, options?: ListFilesOptions): Promise<string[]>;
|
|
422
|
+
/**
|
|
423
|
+
* 同步版本
|
|
424
|
+
*/
|
|
425
|
+
declare function listFilesSync(rootPath: string, options?: ListFilesOptions): string[];
|
|
426
|
+
/**
|
|
427
|
+
* 流式遍历目录(逐层搜索,边走边回调)
|
|
428
|
+
*
|
|
429
|
+
* 与 listFiles 的区别:
|
|
430
|
+
* - 逐层读取嵌套 .gitignore/.ignore(子目录各自独立生效)
|
|
431
|
+
* - 按目录层级逐批回调,适合需要实时展示结果的 UI 场景
|
|
432
|
+
*
|
|
433
|
+
* @param onBatch 回调返回 true 可提前终止遍历
|
|
434
|
+
*/
|
|
435
|
+
declare function walkFiles(rootPath: string, onBatch: (paths: string[], done: boolean) => boolean | void | Promise<boolean | void>, options?: ListFilesOptions): Promise<void>;
|
|
436
|
+
|
|
389
437
|
/**
|
|
390
438
|
* 使用 fdir 快速搜索文件和文件夹
|
|
391
|
-
*
|
|
439
|
+
* 自动遵守 .gitignore / .ignore
|
|
392
440
|
*
|
|
393
441
|
* @param searchPath 搜索路径
|
|
394
442
|
* @param pattern 搜索模式(支持 * 通配符,忽略大小写)
|
|
@@ -397,15 +445,19 @@ declare function getPlatform(): NodeJS.Platform;
|
|
|
397
445
|
declare function searchFiles(searchPath: string, pattern?: string, maxDepth?: number): Promise<string[]>;
|
|
398
446
|
/**
|
|
399
447
|
* 流式搜索文件(逐层搜索,边搜边返回)
|
|
448
|
+
* 逐层读取 .gitignore / .ignore,嵌套目录各自独立生效
|
|
400
449
|
*
|
|
401
450
|
* @param searchPath 搜索路径
|
|
402
451
|
* @param pattern 搜索模式
|
|
403
452
|
* @param onResults 找到结果时的回调
|
|
404
453
|
* @param maxResults 最大结果数
|
|
405
454
|
*/
|
|
406
|
-
declare function searchFilesStream(searchPath: string, pattern: string, onResults: (paths: string[], done: boolean) => void, maxResults?: number
|
|
455
|
+
declare function searchFilesStream(searchPath: string, pattern: string, onResults: (paths: string[], done: boolean) => void, maxResults?: number, options?: {
|
|
456
|
+
signal?: AbortSignal;
|
|
457
|
+
}): Promise<void>;
|
|
407
458
|
/**
|
|
408
459
|
* 同步搜索(用于小目录)
|
|
460
|
+
* 自动遵守 .gitignore / .ignore
|
|
409
461
|
*/
|
|
410
462
|
declare function searchFilesSync(searchPath: string, pattern?: string, maxDepth?: number): string[];
|
|
411
463
|
|
|
@@ -447,15 +499,64 @@ declare function pasteFiles(targetDir: string, sourcePaths: string[]): Promise<O
|
|
|
447
499
|
/**
|
|
448
500
|
* 应用程序图标获取(macOS)
|
|
449
501
|
*
|
|
450
|
-
* 纯 Node.js
|
|
502
|
+
* 纯 Node.js 实现,覆盖三类 .app 结构:
|
|
503
|
+
* 1. 传统 macOS 应用:`Contents/Resources/*.icns`,使用 `sips` 转 PNG。
|
|
504
|
+
* 2. Electron / 现代 macOS 应用:`Assets.xcassets/AppIcon.appiconset/*.png`,直接读取。
|
|
505
|
+
* 3. iOS-on-Mac(Designed for iPad/iPhone,从 Mac App Store 安装):
|
|
506
|
+
* `WrappedBundle -> Wrapper/{Name}.app/AppIconNxN@2x.png`,直接读取 PNG。
|
|
451
507
|
*/
|
|
452
508
|
/**
|
|
453
|
-
* 获取应用程序图标(仅 macOS
|
|
509
|
+
* 获取应用程序图标(仅 macOS),返回 base64 PNG 的 data URL。
|
|
454
510
|
*
|
|
455
|
-
*
|
|
511
|
+
* 解析顺序:
|
|
512
|
+
* 1. iOS-on-Mac WrappedBundle 结构(直接读 PNG,无需 sips)
|
|
513
|
+
* 2. 传统 / 现代 macOS 应用(找到 .icns 后用 sips 转 PNG;找到 .png 直接读取)
|
|
456
514
|
*/
|
|
457
515
|
declare function getApplicationIcon(appPath: string): Promise<string | null>;
|
|
458
516
|
|
|
517
|
+
/**
|
|
518
|
+
* 应用程序元信息(macOS)
|
|
519
|
+
*
|
|
520
|
+
* - 本地化显示名(如 Calculator.app -> 计算器):基于 macOS Spotlight 元数据 `mdls`
|
|
521
|
+
* - 标准应用目录扫描:合并 `/Applications`、`~/Applications`、`/System/Applications`、
|
|
522
|
+
* `/System/Applications/Utilities` 四个 macOS 官方应用目录
|
|
523
|
+
*
|
|
524
|
+
* 仅在 macOS 上有效,其它平台返回回退值或空数组。
|
|
525
|
+
*/
|
|
526
|
+
/**
|
|
527
|
+
* 批量获取多个 .app 的本地化显示名,内置 mtime 失效缓存。
|
|
528
|
+
*
|
|
529
|
+
* 实现细节:
|
|
530
|
+
* - 一次 `mdls` 调用支持多个路径,结果用 NUL (\0) 分隔
|
|
531
|
+
* - 命中缓存的不会重复查询
|
|
532
|
+
* - 任一路径失败时自动回退到文件名
|
|
533
|
+
*/
|
|
534
|
+
declare function getApplicationDisplayNames(appPaths: readonly string[]): Promise<Map<string, string>>;
|
|
535
|
+
/** 单个查询,内部走批量接口以共享缓存 */
|
|
536
|
+
declare function getApplicationDisplayName(appPath: string): Promise<string>;
|
|
537
|
+
/**
|
|
538
|
+
* 列出 macOS 标准目录中的所有 `.app` 路径。
|
|
539
|
+
*
|
|
540
|
+
* - 同名应用按目录优先级去重: `/Applications` > `~/Applications`
|
|
541
|
+
* > `/System/Applications/Utilities` > `/System/Applications`
|
|
542
|
+
* - 返回结果已按本地化显示名排序
|
|
543
|
+
*/
|
|
544
|
+
declare function listMacApplications(): Promise<string[]>;
|
|
545
|
+
/**
|
|
546
|
+
* 判断一个目录是否是 macOS Finder 「应用程序」视图的目标根目录。
|
|
547
|
+
* SuperX / file-explorer 用此来决定是否启用合并视图。
|
|
548
|
+
*/
|
|
549
|
+
declare function isMacApplicationsRoot(dirPath: string): boolean;
|
|
550
|
+
/**
|
|
551
|
+
* 判断一个 .app 是否为 iOS-on-Mac (Designed for iPad/iPhone) 应用。
|
|
552
|
+
*
|
|
553
|
+
* 这类应用从 Mac App Store 的 iOS 应用安装,bundle 内层套了一个 `Wrapper/{Name}.app`
|
|
554
|
+
* 子 bundle,根目录有一个 `WrappedBundle` 软链指向它。检测软链存在性即可,
|
|
555
|
+
* 比读取 Info.plist 更轻量。
|
|
556
|
+
*/
|
|
557
|
+
declare function isIosOnMacApp(appPath: string): Promise<boolean>;
|
|
558
|
+
declare function detectIosOnMacApps(appPaths: readonly string[]): Promise<Set<string>>;
|
|
559
|
+
|
|
459
560
|
/**
|
|
460
561
|
* 文件系统监听服务
|
|
461
562
|
*
|
|
@@ -609,10 +710,25 @@ declare function getThumbnailService(): ThumbnailService | null;
|
|
|
609
710
|
/**
|
|
610
711
|
* SQLite 缩略图数据库实现
|
|
611
712
|
*
|
|
612
|
-
*
|
|
713
|
+
* 不直接依赖 better-sqlite3,由消费方通过工厂函数注入 Database 实例,
|
|
714
|
+
* 避免 Electron / Node.js 原生模块版本冲突。
|
|
613
715
|
*/
|
|
614
716
|
|
|
717
|
+
/** 与 better-sqlite3 Database 实例兼容的最小接口 */
|
|
718
|
+
interface SqliteDatabase {
|
|
719
|
+
pragma(source: string): unknown;
|
|
720
|
+
exec(source: string): void;
|
|
721
|
+
prepare(source: string): {
|
|
722
|
+
get(...params: unknown[]): unknown;
|
|
723
|
+
run(...params: unknown[]): unknown;
|
|
724
|
+
};
|
|
725
|
+
close(): void;
|
|
726
|
+
}
|
|
727
|
+
/** 消费方提供的数据库工厂:接收 dbPath,返回已打开的 Database 实例 */
|
|
728
|
+
type SqliteDatabaseFactory = (dbPath: string) => SqliteDatabase;
|
|
615
729
|
interface SqliteThumbnailDatabaseOptions {
|
|
730
|
+
/** 数据库工厂函数,由消费方注入 */
|
|
731
|
+
sqliteFactory: SqliteDatabaseFactory;
|
|
616
732
|
/**
|
|
617
733
|
* 缩略图存储目录(绝对路径)。如果提供,则优先使用该目录。
|
|
618
734
|
* 适用于将本库嵌入到其他应用时,自定义缩略图缓存位置。
|
|
@@ -634,23 +750,14 @@ interface SqliteThumbnailDatabaseOptions {
|
|
|
634
750
|
*/
|
|
635
751
|
dbPath?: string;
|
|
636
752
|
}
|
|
637
|
-
/**
|
|
638
|
-
* SQLite 缩略图数据库实现
|
|
639
|
-
*/
|
|
640
753
|
declare class SqliteThumbnailDatabase implements ThumbnailDatabase {
|
|
641
754
|
private db;
|
|
642
755
|
private cacheDir;
|
|
643
756
|
private dbPath;
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
* 初始化数据库
|
|
647
|
-
*/
|
|
757
|
+
private sqliteFactory;
|
|
758
|
+
constructor(userDataPath: string, options: SqliteThumbnailDatabaseOptions);
|
|
648
759
|
init(): void;
|
|
649
760
|
getCacheDir(): string;
|
|
650
|
-
/**
|
|
651
|
-
* 快速查询缩略图(用路径和修改时间,不需要哈希)
|
|
652
|
-
* 比计算文件哈希快很多
|
|
653
|
-
*/
|
|
654
761
|
getThumbnailPathFast(filePath: string, mtime: number): string | null;
|
|
655
762
|
getThumbnailPath(filePath: string, fileHash: string, mtime: number): string | null;
|
|
656
763
|
saveThumbnail(filePath: string, fileHash: string, mtime: number, thumbnailPath: string): void;
|
|
@@ -659,22 +766,13 @@ declare class SqliteThumbnailDatabase implements ThumbnailDatabase {
|
|
|
659
766
|
close(): void;
|
|
660
767
|
}
|
|
661
768
|
/**
|
|
662
|
-
* 创建 SQLite
|
|
663
|
-
|
|
664
|
-
/**
|
|
665
|
-
* 创建 SQLite 缩略图数据库(统一入口:仅支持 options 对象)
|
|
666
|
-
* 说明:不再支持“传 dbPath 当作参数”的用法;宿主需要显式传入 userDataPath(以及可选的目录/文件覆盖)。
|
|
769
|
+
* 创建 SQLite 缩略图数据库(统一入口)
|
|
770
|
+
* 宿主需传入 userDataPath 和 sqliteFactory。
|
|
667
771
|
*/
|
|
668
772
|
declare function createSqliteThumbnailDatabase(options: {
|
|
669
773
|
userDataPath: string;
|
|
670
774
|
} & SqliteThumbnailDatabaseOptions): SqliteThumbnailDatabase;
|
|
671
|
-
/**
|
|
672
|
-
* 获取缩略图数据库实例
|
|
673
|
-
*/
|
|
674
775
|
declare function getSqliteThumbnailDatabase(): SqliteThumbnailDatabase | null;
|
|
675
|
-
/**
|
|
676
|
-
* 关闭缩略图数据库(应在应用退出时调用)
|
|
677
|
-
*/
|
|
678
776
|
declare function closeThumbnailDatabase(): void;
|
|
679
777
|
|
|
680
778
|
/**
|
|
@@ -946,4 +1044,4 @@ declare function getMediaService(): MediaService | null;
|
|
|
946
1044
|
*/
|
|
947
1045
|
declare function createMediaService(options: MediaServiceOptions): MediaService;
|
|
948
1046
|
|
|
949
|
-
export { APP_PROTOCOL_HOST, APP_PROTOCOL_PREFIX, APP_PROTOCOL_SCHEME, type ClipboardAdapter, type CompressFormat, type CompressLevel, type CompressOptions, type CompressProgress, type CompressResult, type DeleteOptions, type ExtractOptions, type FileInfo, type FileItem, type FileOperationOptions, FileType, type ImageProcessor, type MediaFormatInfo, type MediaMetadata, type ProgressCallback as MediaProgressCallback, MediaService, type MediaServiceOptions, type MediaType, type OperationResult, type PlatformAdapter, type ProgressCallback$1 as ProgressCallback, type ReadDirectoryOptions, type RenameOptions, SqliteThumbnailDatabase, type SystemPathId, type ThumbnailDatabase, ThumbnailService, type ThumbnailServiceOptions, type TranscodeInfo, type TranscodeMethod, type TranscodeProgress, type TranscodeResult, type TranscodeStatus, type UrlEncoder, type VideoProcessor, type WatchCallback, type WatchEvent, type WatchEventType, WatchManager, type Watcher, cleanupAllTranscodedFiles, cleanupTranscodedFile, closeThumbnailDatabase, compressFiles, copyFiles, copyFilesToClipboard, createFfmpegVideoProcessor, createFile, createFolder, createMediaService, createSharpImageProcessor, createSqliteThumbnailDatabase, decodeFileUrl, deleteFiles, detectArchiveFormat, detectTranscodeNeeds, encodeFileUrl, exists, extractArchive, formatDate, formatDateTime, formatFileSize, getAllSystemPaths, getApplicationIcon, getClipboardFiles, getFileHash, getFileInfo, getFileType, getHomeDirectory, getMediaFormat, getMediaService, getMediaTypeByExtension, getPlatform, getSqliteThumbnailDatabase, getSystemPath, getThumbnailService, getWatchManager, initMediaService, initThumbnailService, isAppProtocolUrl, isArchiveFile, isDirectory, isMediaFile, isPreviewable, moveFiles, openInEditor, openInTerminal, pasteFiles, readDirectory, readFileContent, readImageAsBase64, renameFile, revealInFileManager, searchFiles, searchFilesStream, searchFilesSync, showFileInfo, transcodeMedia, watchDirectory, writeFileContent };
|
|
1047
|
+
export { APP_PROTOCOL_HOST, APP_PROTOCOL_PREFIX, APP_PROTOCOL_SCHEME, type ClipboardAdapter, type CompressFormat, type CompressLevel, type CompressOptions, type CompressProgress, type CompressResult, type DeleteOptions, type ExtractOptions, type FileInfo, type FileItem, type FileOperationOptions, FileType, type ImageProcessor, type ListFilesOptions, type MediaFormatInfo, type MediaMetadata, type ProgressCallback as MediaProgressCallback, MediaService, type MediaServiceOptions, type MediaType, type OperationResult, type PlatformAdapter, type ProgressCallback$1 as ProgressCallback, type ReadDirectoryOptions, type RenameOptions, type SqliteDatabase, type SqliteDatabaseFactory, SqliteThumbnailDatabase, type SqliteThumbnailDatabaseOptions, type SystemPathId, type ThumbnailDatabase, ThumbnailService, type ThumbnailServiceOptions, type TranscodeInfo, type TranscodeMethod, type TranscodeProgress, type TranscodeResult, type TranscodeStatus, type UrlEncoder, type VideoProcessor, type WatchCallback, type WatchEvent, type WatchEventType, WatchManager, type Watcher, cleanupAllTranscodedFiles, cleanupTranscodedFile, closeThumbnailDatabase, compressFiles, copyFiles, copyFilesToClipboard, createFfmpegVideoProcessor, createFile, createFolder, createMediaService, createSharpImageProcessor, createSqliteThumbnailDatabase, decodeFileUrl, deleteFiles, detectArchiveFormat, detectIosOnMacApps, detectTranscodeNeeds, encodeFileUrl, exists, extractArchive, formatDate, formatDateTime, formatFileSize, getAllSystemPaths, getApplicationDisplayName, getApplicationDisplayNames, getApplicationIcon, getClipboardFiles, getFileHash, getFileInfo, getFileType, getHomeDirectory, getMediaFormat, getMediaService, getMediaTypeByExtension, getPlatform, getSqliteThumbnailDatabase, getSystemPath, getThumbnailService, getWatchManager, initMediaService, initThumbnailService, isAppProtocolUrl, isArchiveFile, isDirectory, isIosOnMacApp, isMacApplicationsRoot, isMediaFile, isPreviewable, listFiles, listFilesSync, listMacApplications, moveFiles, openInEditor, openInTerminal, pasteFiles, readDirectory, readFileContent, readImageAsBase64, renameFile, revealInFileManager, searchFiles, searchFilesStream, searchFilesSync, showFileInfo, transcodeMedia, walkFiles, watchDirectory, writeFileContent };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var t=(t=>(t.FOLDER="folder",t.FILE="file",t.IMAGE="image",t.VIDEO="video",t.MUSIC="music",t.DOCUMENT="document",t.CODE="code",t.TEXT="text",t.ARCHIVE="archive",t.APPLICATION="application",t.UNKNOWN="unknown",t))(t||{}),e="app",r="file",a=`app://${r}`;function n(t){if(!t)return"";const e=t.split("/").map(t=>encodeURIComponent(t)).join("/");return`${a}${e}`}function i(t){if(!t)return"";let e=t;e.startsWith(a)&&(e=e.slice(a.length));const r=e.indexOf("#");-1!==r&&(e=e.substring(0,r));const n=e.indexOf("?");-1!==n&&(e=e.substring(0,n));try{return decodeURIComponent(e)}catch{return e}}function s(t){return t?.startsWith(a)??!1}import o from"path";var c=new Set([".jpg",".jpeg",".png",".gif",".bmp",".webp",".svg",".ico",".tiff",".tif",".heic",".heif"]),u=new Set([".mp4",".mov",".avi",".mkv",".wmv",".flv",".webm",".m4v",".3gp",".mpeg",".mpg"]),l=new Set([".mp3",".wav",".flac",".aac",".ogg",".wma",".m4a",".aiff",".alac"]),m=new Set([".pdf",".doc",".docx",".xls",".xlsx",".ppt",".pptx",".odt",".ods",".odp",".rtf",".pages",".numbers",".key"]),h=new Set([".js",".ts",".jsx",".tsx",".vue",".svelte",".py",".rb",".go",".rs",".java",".kt",".swift",".c",".cpp",".h",".hpp",".html",".css",".scss",".sass",".less",".json",".yaml",".yml",".toml",".xml",".sh",".bash",".zsh",".fish",".ps1",".sql",".graphql",".prisma"]),d=new Set([".txt",".md",".markdown",".log",".ini",".conf",".cfg",".env"]),p=new Set([".zip",".rar",".7z",".tar",".gz",".bz2",".xz",".dmg",".iso"]),f=new Set([".app",".exe",".msi",".deb",".rpm",".pkg",".apk",".ipa"]);function w(t,e){if(e.isDirectory())return t.endsWith(".app")?"application":"folder";const r=o.extname(t).toLowerCase();return c.has(r)?"image":u.has(r)?"video":l.has(r)?"music":m.has(r)?"document":h.has(r)?"code":d.has(r)?"text":p.has(r)?"archive":f.has(r)?"application":"file"}function g(t){return"image"===t||"video"===t||"music"===t}function y(t){return"image"===t||"video"===t||"music"===t||"text"===t||"code"===t}function b(t){if(0===t)return"0 B";const e=Math.floor(Math.log(t)/Math.log(1024));return`${parseFloat((t/Math.pow(1024,e)).toFixed(1))} ${["B","KB","MB","GB","TB"][e]}`}function v(t){const e=(new Date).getTime()-t.getTime(),r=Math.floor(e/864e5);return 0===r?t.toLocaleTimeString("zh-CN",{hour:"2-digit",minute:"2-digit"}):1===r?"昨天":r<7?`${r} 天前`:t.toLocaleDateString("zh-CN",{year:"numeric",month:"2-digit",day:"2-digit"})}function E(t){return t.toLocaleString("zh-CN",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"})}import{promises as T}from"fs";import C from"path";var $=t=>`file://${encodeURIComponent(t)}`;async function P(t,e={}){const{urlEncoder:r=$,includeHidden:a=!1,getThumbnailUrl:n}=e;try{const e=await T.readdir(t,{withFileTypes:!0}),i=[];for(const s of e){if(!a&&s.name.startsWith("."))continue;const e=C.join(t,s.name);try{let t;try{t=await T.lstat(e)}catch{try{t=await T.stat(e)}catch(t){t.code;continue}}const a=w(e,t),o=r(e),c={id:e,name:s.name,type:a,dateModified:v(t.mtime),url:o};if(t.isDirectory())c.children=[];else if(c.size=b(t.size),n&&("image"===a||"video"===a)){const t=await n(e);t&&(c.thumbnailUrl=t)}i.push(c)}catch(t){t.code;continue}}return i.sort((t,e)=>"folder"===t.type&&"folder"!==e.type?-1:"folder"!==t.type&&"folder"===e.type?1:t.name.localeCompare(e.name,"zh-CN")),i}catch(t){return[]}}async function S(t){return await T.readFile(t,"utf-8")}async function x(t){try{let e=t;if(t.startsWith("app://file")){const r=t.slice(10);e=decodeURIComponent(r)}else t.startsWith("file://")&&(e=decodeURIComponent(t.replace("file://","")));if(!(await T.stat(e)).isFile())return{success:!1,error:`路径不是文件: ${e}`};const r=(await T.readFile(e)).toString("base64"),a=C.extname(e).toLowerCase().slice(1);return{success:!0,base64:r,mimeType:{jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",gif:"image/gif",webp:"image/webp",bmp:"image/bmp",svg:"image/svg+xml"}[a]||"image/jpeg"}}catch(t){return{success:!1,error:String(t)}}}import{promises as F}from"fs";import k from"path";async function D(t,e){try{return await F.writeFile(t,e,"utf-8"),{success:!0}}catch(t){return{success:!1,error:String(t)}}}async function j(t){try{try{await F.access(t)}catch{return await F.mkdir(t,{recursive:!0}),{success:!0,data:{finalPath:t}}}const e=k.dirname(t),r=k.basename(t);let a=2,n=k.join(e,`${r} ${a}`);for(;;)try{await F.access(n),a++,n=k.join(e,`${r} ${a}`)}catch{break}return await F.mkdir(n,{recursive:!0}),{success:!0,data:{finalPath:n}}}catch(t){return{success:!1,error:String(t)}}}async function I(t,e=""){try{const r=k.dirname(t);await F.mkdir(r,{recursive:!0});try{await F.access(t)}catch{return await F.writeFile(t,e,"utf-8"),{success:!0,data:{finalPath:t}}}const a=k.dirname(t),n=k.extname(t),i=k.basename(t,n);let s=2,o=k.join(a,`${i} ${s}${n}`);for(;;)try{await F.access(o),s++,o=k.join(a,`${i} ${s}${n}`)}catch{break}return await F.writeFile(o,e,"utf-8"),{success:!0,data:{finalPath:o}}}catch(t){return{success:!1,error:String(t)}}}import{promises as _}from"fs";async function z(t,e={}){const{adapter:r,useTrash:a=!0,onDeleted:n}=e;try{for(const e of t){if(a&&r?.trashItem)await r.trashItem(e);else{(await _.stat(e)).isDirectory()?await _.rm(e,{recursive:!0,force:!0}):await _.unlink(e)}n?.(e)}return{success:!0,message:a?"文件已移动到回收站":"文件已删除"}}catch(t){return{success:!1,error:String(t)}}}import{promises as N}from"fs";async function M(t,e,r={}){const{onRenamed:a}=r;try{return await N.rename(t,e),a?.(t,e),{success:!0}}catch(t){return{success:!1,error:String(t)}}}import{promises as A}from"fs";import L from"path";async function R(t,e){try{const r=[];for(const a of t){const t=L.basename(a);let n=L.join(e,t),i=1;for(;;)try{await A.access(n);const r=L.extname(t),a=L.basename(t,r);n=L.join(e,`${a} ${++i}${r}`)}catch{break}(await A.stat(a)).isDirectory()?await W(a,n):await A.copyFile(a,n),r.push(n)}return{success:!0,data:{copiedPaths:r}}}catch(t){return{success:!1,error:String(t)}}}async function O(t,e){try{const r=[];for(const a of t){const t=L.basename(a);let n=L.join(e,t),i=1;for(;;)try{await A.access(n);const r=L.extname(t),a=L.basename(t,r);n=L.join(e,`${a} ${++i}${r}`)}catch{break}try{await A.rename(a,n)}catch{(await A.stat(a)).isDirectory()?await W(a,n):await A.copyFile(a,n),await A.rm(a,{recursive:!0,force:!0})}r.push(n)}return{success:!0,data:{movedPaths:r}}}catch(t){return{success:!1,error:String(t)}}}async function W(t,e){await A.mkdir(e,{recursive:!0});const r=await A.readdir(t,{withFileTypes:!0});for(const a of r){const r=L.join(t,a.name),n=L.join(e,a.name);a.isDirectory()?await W(r,n):await A.copyFile(r,n)}}import{promises as U}from"fs";import B from"path";async function X(t){try{const e=await U.stat(t),r=B.basename(t),a=B.extname(r);return{success:!0,data:{path:t,name:r,size:e.size,isFile:e.isFile(),isDirectory:e.isDirectory(),createdAt:e.birthtime,updatedAt:e.mtime,extension:a||void 0}}}catch(t){return{success:!1,error:String(t)}}}async function q(t){try{return await U.access(t),!0}catch{return!1}}async function H(t){try{return(await U.stat(t)).isDirectory()}catch{return!1}}import{exec as V}from"child_process";import{promisify as K}from"util";import*as G from"path";var Y=K(V);function J(){switch(process.platform){case"darwin":return"mac";case"win32":return"windows";default:return"linux"}}async function Q(t){const e=J();try{switch(e){case"mac":{const e=`tell application "Finder"\n activate\n set theFile to POSIX file "${t}" as alias\n open information window of theFile\n end tell`;await Y(`osascript -e '${e}'`);break}case"windows":{const e=t.replace(/'/g,"''"),r=`\n $shell = New-Object -ComObject Shell.Application\n $folder = $shell.Namespace((Split-Path '${e}'))\n $item = $folder.ParseName((Split-Path '${e}' -Leaf))\n $item.InvokeVerb('properties')\n `;await Y(`powershell -Command "${r.replace(/\n/g," ")}"`);break}case"linux":{const e=[`nautilus --select "${t}" && nautilus -q`,`dolphin --select "${t}"`,`thunar --quit && thunar "${G.dirname(t)}"`,`xdg-open "${G.dirname(t)}"`];let r=null;for(const t of e)try{return await Y(t),{success:!0}}catch(t){r=t}throw r||new Error("No file manager found")}}return{success:!0}}catch(t){return{success:!1,error:t instanceof Error?t.message:String(t)}}}async function Z(t){const e=J();try{switch(e){case"mac":await Y(`open -R "${t}"`);break;case"windows":await Y(`explorer.exe /select,"${t}"`);break;case"linux":await Y(`xdg-open "${G.dirname(t)}"`)}return{success:!0}}catch(t){return{success:!1,error:t instanceof Error?t.message:String(t)}}}async function tt(t){const e=J();try{switch(e){case"mac":try{const e=`tell application "iTerm"\n activate\n try\n set newWindow to (create window with default profile)\n tell current session of newWindow\n write text "cd '${t}'"\n end tell\n on error\n tell current window\n create tab with default profile\n tell current session\n write text "cd '${t}'"\n end tell\n end tell\n end try\n end tell`;await Y(`osascript -e '${e}'`)}catch{const e=`tell application "Terminal"\n activate\n do script "cd '${t}'"\n end tell`;await Y(`osascript -e '${e}'`)}break;case"windows":try{await Y(`wt -d "${t}"`)}catch{await Y(`start cmd /K "cd /d ${t}"`)}break;case"linux":{const e=[`gnome-terminal --working-directory="${t}"`,`konsole --workdir "${t}"`,`xfce4-terminal --working-directory="${t}"`,`xterm -e "cd '${t}' && $SHELL"`];let r=null;for(const t of e)try{return await Y(t),{success:!0}}catch(t){r=t}throw r||new Error("No terminal found")}}return{success:!0}}catch(t){return{success:!1,error:t instanceof Error?t.message:String(t)}}}async function et(t){const e=J();try{const r="mac"===e?[`open -a "Cursor" "${t}"`,`open -a "Visual Studio Code" "${t}"`,`code "${t}"`]:[`cursor "${t}"`,`code "${t}"`];let a=null;for(const t of r)try{return await Y(t),{success:!0}}catch(t){a=t}throw a||new Error("No editor found")}catch(t){return{success:!1,error:t instanceof Error?t.message:String(t)}}}import*as rt from"compressing";import*as at from"path";import*as nt from"fs";import{promises as it}from"fs";import{pipeline as st}from"stream/promises";function ot(t){const e=t.toLowerCase();return e.endsWith(".zip")?"zip":e.endsWith(".tar.gz")||e.endsWith(".tgz")?"tgz":e.endsWith(".tar.bz2")||e.endsWith(".tbz2")?"tarbz2":e.endsWith(".tar")?"tar":null}function ct(t){return null!==ot(t)}async function ut(t){const e=[],r=await it.readdir(t,{withFileTypes:!0});for(const a of r){const r=at.join(t,a.name);a.isDirectory()?e.push(...await ut(r)):e.push(r)}return e}async function lt(t,e,r){try{const{format:a,level:n="normal",outputName:i,outputDir:s,deleteSource:o}=e,c=function(t){switch(t){case"zip":default:return".zip";case"tar":return".tar";case"tgz":return".tar.gz";case"tarbz2":return".tar.bz2"}}(a),u=i.endsWith(c)?i:i+c,l=at.join(s,u);await it.mkdir(s,{recursive:!0});const m=await async function(t){let e=0;for(const r of t)(await it.stat(r)).isDirectory()?e+=(await ut(r)).length:e+=1;return e}(t);let h=0;switch(a){case"zip":{const e=new rt.zip.Stream;for(const a of t){const t=await it.stat(a),n=at.basename(a);if(t.isDirectory()){const t=await ut(a);for(const n of t){const t=at.relative(at.dirname(a),n);e.addEntry(n,{relativePath:t}),h++,r?.({currentFile:at.basename(n),processedCount:h,totalCount:m,percent:Math.round(h/m*100)})}}else e.addEntry(a,{relativePath:n}),h++,r?.({currentFile:n,processedCount:h,totalCount:m,percent:Math.round(h/m*100)})}const a=nt.createWriteStream(l);await st(e,a);break}case"tar":{const e=new rt.tar.Stream;for(const a of t){const t=await it.stat(a),n=at.basename(a);if(t.isDirectory()){const t=await ut(a);for(const n of t){const t=at.relative(at.dirname(a),n);e.addEntry(n,{relativePath:t}),h++,r?.({currentFile:at.basename(n),processedCount:h,totalCount:m,percent:Math.round(h/m*100)})}}else e.addEntry(a,{relativePath:n}),h++,r?.({currentFile:n,processedCount:h,totalCount:m,percent:Math.round(h/m*100)})}const a=nt.createWriteStream(l);await st(e,a);break}case"tgz":{const e=new rt.tgz.Stream;for(const a of t){const t=await it.stat(a),n=at.basename(a);if(t.isDirectory()){const t=await ut(a);for(const n of t){const t=at.relative(at.dirname(a),n);e.addEntry(n,{relativePath:t}),h++,r?.({currentFile:at.basename(n),processedCount:h,totalCount:m,percent:Math.round(h/m*100)})}}else e.addEntry(a,{relativePath:n}),h++,r?.({currentFile:n,processedCount:h,totalCount:m,percent:Math.round(h/m*100)})}const a=nt.createWriteStream(l);await st(e,a);break}case"tarbz2":{const e=new rt.tgz.Stream;for(const a of t){const t=await it.stat(a),n=at.basename(a);if(t.isDirectory()){const t=await ut(a);for(const n of t){const t=at.relative(at.dirname(a),n);e.addEntry(n,{relativePath:t}),h++,r?.({currentFile:at.basename(n),processedCount:h,totalCount:m,percent:Math.round(h/m*100)})}}else e.addEntry(a,{relativePath:n}),h++,r?.({currentFile:n,processedCount:h,totalCount:m,percent:Math.round(h/m*100)})}const a=nt.createWriteStream(l.replace(".tar.bz2",".tar.gz"));await st(e,a);break}}if(o)for(const e of t){(await it.stat(e)).isDirectory()?await it.rm(e,{recursive:!0}):await it.unlink(e)}return{success:!0,outputPath:l}}catch(t){return{success:!1,error:t instanceof Error?t.message:String(t)}}}async function mt(t,e,r){try{const{targetDir:a,deleteArchive:n}=e,i=ot(t);if(!i)return{success:!1,error:"不支持的压缩格式"};switch(await it.mkdir(a,{recursive:!0}),r?.({currentFile:at.basename(t),processedCount:0,totalCount:1,percent:0}),i){case"zip":await rt.zip.uncompress(t,a);break;case"tar":await rt.tar.uncompress(t,a);break;case"tgz":await rt.tgz.uncompress(t,a);break;case"tarbz2":return{success:!1,error:"tar.bz2 格式暂不支持"}}return r?.({currentFile:at.basename(t),processedCount:1,totalCount:1,percent:100}),n&&await it.unlink(t),{success:!0,outputPath:a}}catch(t){return{success:!1,error:t instanceof Error?t.message:String(t)}}}import ht from"path";import dt from"os";var pt=process.platform;function ft(t){const e=dt.homedir();switch(t){case"desktop":return ht.join(e,"Desktop");case"documents":return ht.join(e,"Documents");case"downloads":return ht.join(e,"Downloads");case"pictures":return ht.join(e,"Pictures");case"music":return ht.join(e,"Music");case"videos":return"darwin"===pt?ht.join(e,"Movies"):ht.join(e,"Videos");case"applications":return"darwin"===pt?"/Applications":"win32"===pt?process.env.ProgramFiles||"C:\\Program Files":"/usr/share/applications";case"home":return e;case"root":return"darwin"===pt?"/":"win32"===pt?"C:\\":"/";default:return null}}function wt(){const t=["desktop","documents","downloads","pictures","music","videos","applications","home","root"],e={};for(const r of t)e[r]=ft(r);return e}function gt(){return dt.homedir()}function yt(){return process.platform}import{fdir as bt}from"fdir";import vt from"path";import{promises as Et}from"fs";function Tt(t){return new RegExp(t.replace(/\*/g,".*"),"i")}async function Ct(t,e,r){const a=(new bt).withFullPaths().withDirs();r&&r>0&&a.withMaxDepth(r);const n=a.crawl(t),i=await n.withPromise();if(e){const t=Tt(e);return i.filter(e=>t.test(vt.basename(e)))}return i}async function $t(t,e,r,a=100){const n=Tt(e),i=[];let s=!1;await async function t(e){if(!s)try{const o=await Et.readdir(e,{withFileTypes:!0}),c=[],u=[];for(const t of o){if(s)return;const o=vt.join(e,t.name);if(n.test(t.name)&&(c.push(o),i.push(o),i.length>=a))return s=!0,void r(c,!0);t.isDirectory()&&u.push(o)}c.length>0&&r(c,!1);for(const e of u)await t(e)}catch{}}(t),s||r([],!0)}function Pt(t,e,r){const a=(new bt).withFullPaths().withDirs();r&&r>0&&a.withMaxDepth(r);const n=a.crawl(t).sync();if(e){const t=new RegExp(e.replace(/\*/g,".*"),"i");return n.filter(e=>t.test(vt.basename(e)))}return n}import{xxhash64 as St}from"hash-wasm";import{stat as xt}from"fs/promises";async function Ft(t,e){const r=e||await xt(t),a=`${t}:${r.size}:${r.mtime.getTime()}`;return await St(a)}import{promises as kt}from"fs";import Dt from"path";async function jt(t,e){try{const r=[];for(const e of t)try{await kt.access(e),r.push(e)}catch{}return 0===r.length?{success:!1,error:"没有找到有效的文件"}:(e.writeFiles(r),{success:!0})}catch(t){return{success:!1,error:String(t)}}}function It(t){try{const e=t.readFiles();return e&&Array.isArray(e)&&e.length>0?{success:!0,data:{files:e}}:{success:!1,error:"剪贴板中没有文件"}}catch(t){return{success:!1,error:String(t)}}}async function _t(t,e){try{if(!t||"string"!=typeof t)return{success:!1,error:"目标目录路径无效"};if(!e||!Array.isArray(e)||0===e.length)return{success:!1,error:"源文件路径列表无效"};const r=[];for(const a of e){const e=Dt.basename(a);let n=Dt.join(t,e),i=1;for(;;)try{await kt.access(n);const r=Dt.extname(e),a=Dt.basename(e,r);n=Dt.join(t,`${a} ${++i}${r}`)}catch{break}(await kt.stat(a)).isDirectory()?await zt(a,n):await kt.copyFile(a,n),r.push(n)}return{success:!0,data:{pastedPaths:r}}}catch(t){return{success:!1,error:String(t)}}}async function zt(t,e){await kt.mkdir(e,{recursive:!0});const r=await kt.readdir(t,{withFileTypes:!0});for(const a of r){const r=Dt.join(t,a.name),n=Dt.join(e,a.name);a.isDirectory()?await zt(r,n):await kt.copyFile(r,n)}}import{promises as Nt}from"fs";import Mt from"path";import At from"os";import{exec as Lt}from"child_process";import{promisify as Rt}from"util";var Ot=Rt(Lt);async function Wt(t){if("darwin"!==process.platform)return null;try{if(!(await Nt.stat(t)).isDirectory()||!t.endsWith(".app"))return null}catch{return null}const e=await async function(t){const e=Mt.join(t,"Contents","Resources");try{const r=["AppIcon.icns","app.icns","application.icns","icon.icns"],a=Mt.join(t,"Contents","Info.plist");try{const t=(await Nt.readFile(a,"utf-8")).match(/<key>CFBundleIconFile<\/key>\s*<string>([^<]+)<\/string>/);if(t&&t[1]){let r=t[1].trim();r.endsWith(".icns")||(r+=".icns");const a=Mt.join(e,r);try{return await Nt.access(a),a}catch{}}}catch{}for(const t of r){const r=Mt.join(e,t);try{return await Nt.access(r),r}catch{continue}}try{const t=(await Nt.readdir(e)).find(t=>t.toLowerCase().endsWith(".icns"));if(t)return Mt.join(e,t)}catch{}return null}catch{return null}}(t);if(!e)return null;try{const t=Mt.join(At.tmpdir(),`app-icon-${Date.now()}.png`);await Ot(`sips -s format png "${e}" --out "${t}" --resampleHeightWidthMax 128`);const r=await Nt.readFile(t);try{await Nt.unlink(t)}catch{}return`data:image/png;base64,${r.toString("base64")}`}catch{return null}}import*as Ut from"fs";import*as Bt from"path";var Xt=new Map;function qt(t,e){let r=null;try{r=Ut.watch(t,{persistent:!0},(r,a)=>{if(!a)return;const n=Bt.join(t,a),i=`${t}:${a}`,s=Xt.get(i);s&&clearTimeout(s);const o=setTimeout(()=>{Xt.delete(i),Ut.access(n,Ut.constants.F_OK,t=>{let i;i=t?"remove":"rename"===r?"add":"change",e({type:i,path:n,filename:a})})},100);Xt.set(i,o)}),r.on("error",t=>{})}catch(t){}return{close:()=>{r&&(r.close(),r=null);for(const[e,r]of Xt.entries())e.startsWith(`${t}:`)&&(clearTimeout(r),Xt.delete(e))},path:t}}var Ht=class{watchers=new Map;callbacks=new Map;watch(t,e){const r=Bt.normalize(t);let a=this.callbacks.get(r);a||(a=new Set,this.callbacks.set(r,a)),a.add(e);let n=this.watchers.get(r);if(n)n.refCount++;else{n={watcher:qt(r,t=>{const e=this.callbacks.get(r);if(e)for(const r of e)try{r(t)}catch(t){}}),refCount:1},this.watchers.set(r,n)}return()=>{this.unwatch(r,e)}}unwatch(t,e){const r=Bt.normalize(t),a=this.callbacks.get(r);a&&(a.delete(e),0===a.size&&this.callbacks.delete(r));const n=this.watchers.get(r);n&&(n.refCount--,n.refCount<=0&&(n.watcher.close(),this.watchers.delete(r)))}closeAll(){for(const[,t]of this.watchers)t.watcher.close();this.watchers.clear(),this.callbacks.clear()}},Vt=null;function Kt(){return Vt||(Vt=new Ht),Vt}import{promises as Gt}from"fs";import Yt from"path";var Jt=class{database;imageProcessor;videoProcessor;urlEncoder;getApplicationIcon;constructor(t){this.database=t.database,this.imageProcessor=t.imageProcessor||null,this.videoProcessor=t.videoProcessor||null,this.urlEncoder=t.urlEncoder||(t=>`file://${encodeURIComponent(t)}`),this.getApplicationIcon=t.getApplicationIcon||null}async getCachedThumbnailUrl(t){try{const e=await Gt.stat(t),r=w(t,e);if("application"===r&&this.getApplicationIcon)return await this.getApplicationIcon(t);if("image"!==r&&"video"!==r)return null;const a=e.mtime.getTime(),n=this.database.getThumbnailPathFast(t,a);return n?this.urlEncoder(n):(Ft(t,e).then(e=>{this.generateThumbnail(t,e,a).catch(()=>{})}).catch(()=>{}),null)}catch(t){return null}}async getThumbnailUrl(t){try{const e=await Gt.stat(t),r=w(t,e);if("application"===r&&this.getApplicationIcon)return await this.getApplicationIcon(t);if("image"!==r&&"video"!==r)return null;const a=e.mtime.getTime(),n=this.database.getThumbnailPathFast(t,a);if(n)return this.urlEncoder(n);const i=await Ft(t,e),s=await this.generateThumbnail(t,i,a);return s?this.urlEncoder(s):null}catch(t){return null}}async generateThumbnail(t,e,r){const a=this.database.getThumbnailPath(t,e,r);if(a)return a;try{const a=w(t,await Gt.stat(t)),n=`${e.substring(0,16)}.jpg`,i=Yt.join(this.database.getCacheDir(),n);if(function(t,e){return"image"===e}(0,a)&&this.imageProcessor)await this.imageProcessor.resize(t,i,256);else{if(!function(t,e){return"video"===e}(0,a)||!this.videoProcessor)return null;await this.videoProcessor.screenshot(t,i,"00:00:01","256x256")}return this.database.saveThumbnail(t,e,r,i),i}catch(t){return null}}async generateThumbnailsBatch(t,e=3){const r=async t=>{try{await this.generateThumbnail(t.path,t.hash,t.mtime)}catch(t){}};for(let a=0;a<t.length;a+=e){const n=t.slice(a,a+e);await Promise.allSettled(n.map(r))}}deleteThumbnail(t){this.database.deleteThumbnail(t)}cleanupOldThumbnails(){this.database.cleanupOldThumbnails()}},Qt=null;function Zt(t){return Qt=new Jt(t)}function te(){return Qt}import ee from"better-sqlite3";import re from"path";import{existsSync as ae,mkdirSync as ne}from"fs";var ie=class{db=null;cacheDir;dbPath;constructor(t,e={}){const r=e.dirName||"thumbnails",a=e.dbFileName||"thumbnails.db",n=e.dbPath?re.dirname(e.dbPath):null;this.cacheDir=e.thumbnailDir?e.thumbnailDir:n||re.join(t,r),this.dbPath=e.dbPath?e.dbPath:re.join(this.cacheDir,a),ae(this.cacheDir)||ne(this.cacheDir,{recursive:!0})}init(){this.db||(this.db=new ee(this.dbPath,{fileMustExist:!1}),this.db.pragma("journal_mode = WAL"),this.db.exec("\n CREATE TABLE IF NOT EXISTS thumbnails (\n file_path TEXT PRIMARY KEY,\n file_hash TEXT NOT NULL,\n mtime INTEGER NOT NULL,\n thumbnail_path TEXT NOT NULL,\n created_at INTEGER NOT NULL\n );\n \n CREATE INDEX IF NOT EXISTS idx_file_hash ON thumbnails(file_hash);\n CREATE INDEX IF NOT EXISTS idx_mtime ON thumbnails(mtime);\n "))}getCacheDir(){return this.cacheDir}getThumbnailPathFast(t,e){this.db||this.init();const r=this.db.prepare("\n SELECT thumbnail_path \n FROM thumbnails \n WHERE file_path = ? AND mtime = ?\n ").get(t,e);return r&&ae(r.thumbnail_path)?r.thumbnail_path:null}getThumbnailPath(t,e,r){this.db||this.init();const a=this.db.prepare("\n SELECT thumbnail_path, mtime \n FROM thumbnails \n WHERE file_path = ? AND file_hash = ?\n ").get(t,e);return a&&a.mtime===r&&ae(a.thumbnail_path)?a.thumbnail_path:null}saveThumbnail(t,e,r,a){this.db||this.init();this.db.prepare("\n INSERT OR REPLACE INTO thumbnails \n (file_path, file_hash, mtime, thumbnail_path, created_at)\n VALUES (?, ?, ?, ?, ?)\n ").run(t,e,r,a,Date.now())}deleteThumbnail(t){this.db||this.init();this.db.prepare("DELETE FROM thumbnails WHERE file_path = ?").run(t)}cleanupOldThumbnails(){this.db||this.init();const t=Date.now()-2592e6;this.db.prepare("DELETE FROM thumbnails WHERE created_at < ?").run(t)}close(){if(this.db){try{this.db.pragma("wal_checkpoint(TRUNCATE)")}catch(t){}this.db.close(),this.db=null}}},se=null;function oe(t){return se||(se=new ie(t.userDataPath,t)).init(),se}function ce(){return se}function ue(){se&&(se.close(),se=null)}import{spawn as le}from"child_process";function me(t){return{async resize(e,r,a){await t(e).resize({width:a,withoutEnlargement:!0}).jpeg({quality:80,optimiseCoding:!0}).toFile(r)}}}function he(t){return{async screenshot(e,r,a,n){const i=n.split("x")[0];return new Promise((n,s)=>{const o=le(t,["-y","-ss",a,"-i",e,"-vframes","1","-vf",`thumbnail,scale=${i}:-1:force_original_aspect_ratio=decrease`,"-c:v","mjpeg","-q:v","6",r]),c=setTimeout(()=>{o.kill(),s(new Error("Video thumbnail generation timeout"))},3e4);o.stderr.on("data",t=>{t.toString().includes("Unsupported pixel format")}),o.on("close",t=>{clearTimeout(c),0===t?n():s(new Error(`ffmpeg exited with code ${t}`))}),o.on("error",t=>{clearTimeout(c),s(t)})})}}}import{execFile as de}from"child_process";import{promisify as pe}from"util";import fe from"path";var we=pe(de),ge=new Set(["mp4","webm","ogg","ogv"]),ye=new Set(["h264","avc1","vp8","vp9","theora","av1"]),be=new Set(["aac","mp3","opus","vorbis","flac"]),ve=new Set(["mp3","wav","ogg","oga","webm","m4a","aac","flac"]),Ee=new Set(["mp3","aac","opus","vorbis","flac","pcm_s16le","pcm_s24le"]),Te=new Set(["h264","avc1","hevc","h265"]),Ce=new Set(["aac","alac"]),$e=new Set(["mp4","mkv","avi","mov","wmv","flv","webm","ogv","ogg","m4v","mpeg","mpg","3gp","ts","mts","m2ts","vob","rmvb","rm"]),Pe=new Set(["mp3","wav","flac","aac","m4a","ogg","oga","wma","ape","alac","aiff","aif","opus","mid","midi","wv","mka"]);function Se(t){const e=fe.extname(t).toLowerCase().slice(1);return $e.has(e)?"video":Pe.has(e)?"audio":null}async function xe(t,e){try{const{stdout:r}=await we(e,["-v","quiet","-print_format","json","-show_format","-show_streams",t]),a=JSON.parse(r),n=a.format||{},i=a.streams||[],s=i.find(t=>"video"===t.codec_type),o=i.find(t=>"audio"===t.codec_type),c=s?"video":"audio",u=n.format_name||"";return{type:c,container:u.split(",")[0].toLowerCase(),videoCodec:s?.codec_name?.toLowerCase(),audioCodec:o?.codec_name?.toLowerCase(),duration:parseFloat(n.duration)||void 0,width:s?.width,height:s?.height,bitrate:parseInt(n.bit_rate)||void 0}}catch{const e=Se(t);if(!e)return null;return{type:e,container:fe.extname(t).toLowerCase().slice(1)}}}function Fe(t,e){if(t&&"direct"!==e)return"remux"===e?Math.ceil(t/50):Math.ceil(t/3)}async function ke(t,e){const r=await xe(t,e);if(!r){return{type:Se(t)||"video",needsTranscode:!1,method:"direct"}}const{type:a}=r;return"video"===a?(n=r,!ge.has(n.container)||n.videoCodec&&!ye.has(n.videoCodec)||n.audioCodec&&!be.has(n.audioCodec)?function(t){if(!t.videoCodec||!Te.has(t.videoCodec))return!1;if(t.audioCodec&&!be.has(t.audioCodec)&&!Ce.has(t.audioCodec))return!1;return!0}(r)?{type:a,needsTranscode:!0,method:"remux",formatInfo:r,targetFormat:"mp4",estimatedTime:Fe(r.duration,"remux")}:{type:a,needsTranscode:!0,method:"transcode",formatInfo:r,targetFormat:"mp4",estimatedTime:Fe(r.duration,"transcode")}:{type:a,needsTranscode:!1,method:"direct",formatInfo:r}):function(t){return!(!ve.has(t.container)||t.audioCodec&&!Ee.has(t.audioCodec))}(r)?{type:a,needsTranscode:!1,method:"direct",formatInfo:r}:function(t){return!!t.audioCodec&&Ce.has(t.audioCodec)}(r)?{type:a,needsTranscode:!0,method:"remux",formatInfo:r,targetFormat:"m4a",estimatedTime:Fe(r.duration,"remux")}:{type:a,needsTranscode:!0,method:"transcode",formatInfo:r,targetFormat:"mp3",estimatedTime:Fe(r.duration,"transcode")};var n}import{spawn as De}from"child_process";import je from"fs/promises";import Ie from"path";import _e from"os";function ze(t,e){const r=t.match(/time=(\d+):(\d+):(\d+)\.(\d+)/);if(!r)return null;const a=3600*parseInt(r[1])+60*parseInt(r[2])+parseInt(r[3])+parseInt(r[4])/100,n=t.match(/speed=\s*([\d.]+)x/),i=n?`${n[1]}x`:void 0;let s=0;return e&&e>0&&(s=Math.min(100,Math.round(a/e*100))),{percent:s,time:a,duration:e,speed:i}}async function Ne(t,e,r,a,n){try{if(!r.needsTranscode)return{success:!0,outputPath:e};const i=r.targetFormat||("video"===r.type?"mp4":"mp3"),s=await async function(t,e,r){const a=r||Ie.join(_e.tmpdir(),"file-explorer-media");await je.mkdir(a,{recursive:!0});const n=`${Ie.basename(t,Ie.extname(t))}_${Date.now()}.${e}`;return Ie.join(a,n)}(e,i,a),o=r.formatInfo?.duration;return"video"===r.type?"remux"===r.method?await async function(t,e,r,a,n){return new Promise((i,s)=>{const o=De(t,["-i",e,"-c","copy","-movflags","+faststart","-y",r]);let c="";o.stderr.on("data",t=>{if(c+=t.toString(),n){const t=ze(c,a);t&&n(t)}}),o.on("close",t=>{0===t?i():s(new Error(`ffmpeg exited with code ${t}`))}),o.on("error",s)})}(t,e,s,o,n):await async function(t,e,r,a,n){return new Promise((i,s)=>{const o=De(t,["-i",e,"-c:v","libx264","-preset","fast","-crf","23","-c:a","aac","-b:a","192k","-movflags","+faststart","-y",r]);let c="";o.stderr.on("data",t=>{if(c+=t.toString(),n){const t=ze(c,a);t&&n(t)}}),o.on("close",t=>{0===t?i():s(new Error(`ffmpeg exited with code ${t}`))}),o.on("error",s)})}(t,e,s,o,n):"remux"===r.method?await async function(t,e,r,a,n){return new Promise((i,s)=>{const o=De(t,["-i",e,"-c","copy","-y",r]);let c="";o.stderr.on("data",t=>{if(c+=t.toString(),n){const t=ze(c,a);t&&n(t)}}),o.on("close",t=>{0===t?i():s(new Error(`ffmpeg exited with code ${t}`))}),o.on("error",s)})}(t,e,s,o,n):await async function(t,e,r,a,n){return new Promise((i,s)=>{const o=Ie.extname(r).toLowerCase(),c=De(t,["-i",e,"-c:a",".m4a"===o?"aac":"libmp3lame","-b:a","192k","-y",r]);let u="";c.stderr.on("data",t=>{if(u+=t.toString(),n){const t=ze(u,a);t&&n(t)}}),c.on("close",t=>{0===t?i():s(new Error(`ffmpeg exited with code ${t}`))}),c.on("error",s)})}(t,e,s,o,n),n&&n({percent:100,duration:o}),{success:!0,outputPath:s}}catch(t){return{success:!1,error:t instanceof Error?t.message:"Unknown error"}}}async function Me(t){try{t.includes("file-explorer-media")&&await je.unlink(t)}catch{}}async function Ae(t){const e=t||Ie.join(_e.tmpdir(),"file-explorer-media");try{const t=await je.readdir(e);await Promise.all(t.map(t=>je.unlink(Ie.join(e,t)).catch(()=>{})))}catch{}}import Le from"path";import{execFile as Re}from"child_process";import{promisify as Oe}from"util";var We=Oe(Re),Ue=null,Be=class{ffmpegPath;ffprobePath;tempDir;urlEncoder;transcodeInfoCache=new Map;transcodedFiles=new Map;constructor(t){this.ffmpegPath=t.ffmpegPath,this.ffprobePath=t.ffprobePath||Le.join(Le.dirname(t.ffmpegPath),"ffprobe"),this.tempDir=t.tempDir,this.urlEncoder=t.urlEncoder}async needsTranscode(t){const e=this.transcodeInfoCache.get(t);if(e)return e;const r=await ke(t,this.ffprobePath);return this.transcodeInfoCache.set(t,r),r}async transcode(t,e){const r=this.transcodedFiles.get(t);if(r)return{success:!0,outputPath:r,url:this.urlEncoder?this.urlEncoder(r):`file://${r}`};const a=await this.needsTranscode(t);if(!a.needsTranscode){return{success:!0,outputPath:t,url:this.urlEncoder?this.urlEncoder(t):`file://${t}`}}const n=await Ne(this.ffmpegPath,t,a,this.tempDir,e);return n.success&&n.outputPath&&(this.transcodedFiles.set(t,n.outputPath),n.url=this.urlEncoder?this.urlEncoder(n.outputPath):`file://${n.outputPath}`),n}async getMetadata(t){try{const{stdout:e}=await We(this.ffprobePath,["-v","quiet","-print_format","json","-show_format","-show_streams",t]),r=JSON.parse(e).format||{},a=r.tags||{},n=await xe(t,this.ffprobePath);return n?{filePath:t,type:n.type,duration:parseFloat(r.duration)||0,format:n,title:a.title||a.TITLE,artist:a.artist||a.ARTIST,album:a.album||a.ALBUM,year:a.date||a.DATE||a.year||a.YEAR}:null}catch{return null}}async getPlayableUrl(t,e){const r=await this.transcode(t,e);return r.success&&r.url||null}async cleanupFile(t){const e=this.transcodedFiles.get(t);e&&(await Me(e),this.transcodedFiles.delete(t)),this.transcodeInfoCache.delete(t)}async cleanup(){await Ae(this.tempDir),this.transcodedFiles.clear(),this.transcodeInfoCache.clear()}clearCache(){this.transcodeInfoCache.clear()}};function Xe(t){return Ue=new Be(t)}function qe(){return Ue}function He(t){return new Be(t)}export{r as APP_PROTOCOL_HOST,a as APP_PROTOCOL_PREFIX,e as APP_PROTOCOL_SCHEME,t as FileType,Be as MediaService,ie as SqliteThumbnailDatabase,Jt as ThumbnailService,Ht as WatchManager,Ae as cleanupAllTranscodedFiles,Me as cleanupTranscodedFile,ue as closeThumbnailDatabase,lt as compressFiles,R as copyFiles,jt as copyFilesToClipboard,he as createFfmpegVideoProcessor,I as createFile,j as createFolder,He as createMediaService,me as createSharpImageProcessor,oe as createSqliteThumbnailDatabase,i as decodeFileUrl,z as deleteFiles,ot as detectArchiveFormat,ke as detectTranscodeNeeds,n as encodeFileUrl,q as exists,mt as extractArchive,v as formatDate,E as formatDateTime,b as formatFileSize,wt as getAllSystemPaths,Wt as getApplicationIcon,It as getClipboardFiles,Ft as getFileHash,X as getFileInfo,w as getFileType,gt as getHomeDirectory,xe as getMediaFormat,qe as getMediaService,Se as getMediaTypeByExtension,yt as getPlatform,ce as getSqliteThumbnailDatabase,ft as getSystemPath,te as getThumbnailService,Kt as getWatchManager,Xe as initMediaService,Zt as initThumbnailService,s as isAppProtocolUrl,ct as isArchiveFile,H as isDirectory,g as isMediaFile,y as isPreviewable,O as moveFiles,et as openInEditor,tt as openInTerminal,_t as pasteFiles,P as readDirectory,S as readFileContent,x as readImageAsBase64,M as renameFile,Z as revealInFileManager,Ct as searchFiles,$t as searchFilesStream,Pt as searchFilesSync,Q as showFileInfo,Ne as transcodeMedia,qt as watchDirectory,D as writeFileContent};
|
|
1
|
+
var t=(t=>(t.FOLDER="folder",t.FILE="file",t.IMAGE="image",t.VIDEO="video",t.MUSIC="music",t.DOCUMENT="document",t.CODE="code",t.TEXT="text",t.ARCHIVE="archive",t.APPLICATION="application",t.UNKNOWN="unknown",t))(t||{}),e="app",r="file",n=`app://${r}`;function a(t){if(!t)return"";const e=t.split("/").map(t=>encodeURIComponent(t)).join("/");return`${n}${e}`}function i(t){if(!t)return"";let e=t;e.startsWith(n)&&(e=e.slice(n.length));const r=e.indexOf("#");-1!==r&&(e=e.substring(0,r));const a=e.indexOf("?");-1!==a&&(e=e.substring(0,a));try{return decodeURIComponent(e)}catch{return e}}function s(t){return t?.startsWith(n)??!1}import o from"path";var c=new Set([".jpg",".jpeg",".png",".gif",".bmp",".webp",".svg",".ico",".tiff",".tif",".heic",".heif"]),u=new Set([".mp4",".mov",".avi",".mkv",".wmv",".flv",".webm",".m4v",".3gp",".mpeg",".mpg"]),l=new Set([".mp3",".wav",".flac",".aac",".ogg",".wma",".m4a",".aiff",".alac"]),m=new Set([".pdf",".doc",".docx",".xls",".xlsx",".ppt",".pptx",".odt",".ods",".odp",".rtf",".pages",".numbers",".key"]),f=new Set([".js",".ts",".jsx",".tsx",".vue",".svelte",".py",".rb",".go",".rs",".java",".kt",".swift",".c",".cpp",".h",".hpp",".html",".css",".scss",".sass",".less",".json",".yaml",".yml",".toml",".xml",".sh",".bash",".zsh",".fish",".ps1",".sql",".graphql",".prisma"]),d=new Set([".txt",".md",".markdown",".log",".ini",".conf",".cfg",".env"]),h=new Set([".zip",".rar",".7z",".tar",".gz",".bz2",".xz",".dmg",".iso"]),p=new Set([".app",".exe",".msi",".deb",".rpm",".pkg",".apk",".ipa"]);function w(t,e){if(e.isDirectory())return t.endsWith(".app")?"application":"folder";const r=o.extname(t).toLowerCase();return c.has(r)?"image":u.has(r)?"video":l.has(r)?"music":m.has(r)?"document":f.has(r)?"code":d.has(r)?"text":h.has(r)?"archive":p.has(r)?"application":"file"}function g(t){return"image"===t||"video"===t||"music"===t}function y(t){return"image"===t||"video"===t||"music"===t||"text"===t||"code"===t}function b(t){if(t<=0)return"0 KB";const e=1024;if(t<e)return"< 1 KB";const r=["KB","MB","GB","TB"],n=Math.min(Math.floor(Math.log(t/e)/Math.log(e)),r.length-1);return`${parseFloat((t/Math.pow(e,n+1)).toFixed(1))} ${r[n]}`}function v(t){const e=(new Date).getTime()-t.getTime(),r=Math.floor(e/864e5);return 0===r?t.toLocaleTimeString("zh-CN",{hour:"2-digit",minute:"2-digit"}):1===r?"昨天":r<7?`${r} 天前`:t.toLocaleDateString("zh-CN",{year:"numeric",month:"2-digit",day:"2-digit"})}function F(t){return t.toLocaleString("zh-CN",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"})}import{promises as x}from"fs";import C from"path";import{promises as E}from"fs";import S from"path";import I from"os";import{execFile as $}from"child_process";import{promisify as T}from"util";var D=T($),P=["/Applications",S.join(I.homedir(),"Applications"),"/System/Applications/Utilities","/System/Applications"],j=new Map;function k(t){return S.basename(t,".app")}async function M(t){const e=new Map;if(0===t.length)return e;if("darwin"!==process.platform){for(const r of t)e.set(r,k(r));return e}const r=[],n=new Map;if(await Promise.all(t.map(async t=>{try{const a=await E.stat(t);n.set(t,a.mtimeMs);const i=j.get(t);i&&i.mtimeMs===a.mtimeMs?e.set(t,i.name):r.push(t)}catch{e.set(t,k(t))}})),0===r.length)return e;try{const{stdout:t}=await D("mdls",["-name","kMDItemDisplayName","-raw",...r],{maxBuffer:4194304}),a=t.split("\0");r.forEach((t,r)=>{const i=(a[r]??"").trim(),s=k(t),o=i&&"(null)"!==i?i.replace(/\.app$/i,""):s,c=n.get(t)??0;j.set(t,{mtimeMs:c,name:o}),e.set(t,o)})}catch{for(const t of r)e.set(t,k(t))}return e}async function N(t){return(await M([t])).get(t)??k(t)}async function z(t){try{const e=await E.readdir(t,{withFileTypes:!0});return(await Promise.all(e.filter(t=>t.name.endsWith(".app")).map(async e=>{const r=S.join(t,e.name);if(e.isDirectory())return r;if(e.isSymbolicLink())try{return(await E.stat(r)).isDirectory()?r:null}catch{return null}return null}))).filter(t=>null!==t)}catch{return[]}}async function A(){if("darwin"!==process.platform)return[];const t=await Promise.all(P.map(z)),e=new Map;for(const r of t)for(const t of r){const r=S.basename(t);e.has(r)||e.set(r,t)}const r=[...e.values()],n=await M(r);return r.sort((t,e)=>{const r=n.get(t)??S.basename(t,".app"),a=n.get(e)??S.basename(e,".app");return r.localeCompare(a,"zh-CN")})}function _(t){return"darwin"===process.platform&&"/Applications"===t}async function W(t){if("darwin"!==process.platform)return!1;try{return(await E.lstat(S.join(t,"WrappedBundle"))).isSymbolicLink()}catch{return!1}}var L=new Map;async function R(t){const e=new Set;return"darwin"!==process.platform||0===t.length||await Promise.all(t.map(async t=>{let r=0;try{r=(await E.stat(t)).mtimeMs}catch{return}const n=L.get(t);let a;n&&n.mtimeMs===r?a=n.isIos:(a=await W(t),L.set(t,{mtimeMs:r,isIos:a})),a&&e.add(t)})),e}var O=t=>`file://${encodeURIComponent(t)}`;async function B(t,e={}){const{urlEncoder:r=O,includeHidden:n=!1,getThumbnailUrl:a}=e;try{if(_(t))return await async function(t,e,r){const n=[],a=new Set;let i=[];try{i=await x.readdir(t,{withFileTypes:!0})}catch{i=[]}for(const s of i){if(!r&&s.name.startsWith("."))continue;const i=C.join(t,s.name),o=await U(i,s.name,e);o&&(n.push(o),"application"===o.type&&a.add(s.name))}const s=(await A()).filter(e=>!e.startsWith(`${t}/`)&&!a.has(C.basename(e)));for(const t of s){const r=await U(t,C.basename(t),e);r&&n.push(r)}const o=n.filter(t=>"application"===t.type).map(t=>t.id),[c,u]=await Promise.all([M(o),R(o)]);for(const t of n)if("application"===t.type){const e=c.get(t.id);e&&(t.name=e),u.has(t.id)&&(t.isIosOnMac=!0)}return n.sort((t,e)=>"folder"===t.type&&"folder"!==e.type?-1:"folder"!==t.type&&"folder"===e.type?1:t.name.localeCompare(e.name,"zh-CN")),n}(t,r,n);const e=await x.readdir(t,{withFileTypes:!0}),i=[];for(const s of e){if(!n&&s.name.startsWith("."))continue;const e=C.join(t,s.name);try{let t;try{t=await x.lstat(e)}catch{try{t=await x.stat(e)}catch(t){t.code;continue}}const n=w(e,t),o=r(e),c={id:e,name:s.name,type:n,dateModified:v(t.mtime),url:o};if(t.isDirectory())c.children=[];else if(c.size=b(t.size),a&&("image"===n||"video"===n)){const t=await a(e);t&&(c.thumbnailUrl=t)}i.push(c)}catch(t){t.code;continue}}return i.sort((t,e)=>"folder"===t.type&&"folder"!==e.type?-1:"folder"!==t.type&&"folder"===e.type?1:t.name.localeCompare(e.name,"zh-CN")),i}catch(t){return[]}}async function U(t,e,r){try{let n;try{if(n=await x.lstat(t),n.isSymbolicLink())try{n=await x.stat(t)}catch{return null}}catch{return null}const a={id:t,name:e,type:w(t,n),dateModified:v(n.mtime),url:r(t)};return n.isDirectory()?a.children=[]:a.size=b(n.size),a}catch{return null}}async function H(t){return await x.readFile(t,"utf-8")}async function q(t){try{let e=t;if(t.startsWith("app://file")){const r=t.slice(10);e=decodeURIComponent(r)}else t.startsWith("file://")&&(e=decodeURIComponent(t.replace("file://","")));if(!(await x.stat(e)).isFile())return{success:!1,error:`路径不是文件: ${e}`};const r=(await x.readFile(e)).toString("base64"),n=C.extname(e).toLowerCase().slice(1);return{success:!0,base64:r,mimeType:{jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",gif:"image/gif",webp:"image/webp",bmp:"image/bmp",svg:"image/svg+xml"}[n]||"image/jpeg"}}catch(t){return{success:!1,error:String(t)}}}import{promises as X}from"fs";import K from"path";async function V(t,e){try{return await X.writeFile(t,e,"utf-8"),{success:!0}}catch(t){return{success:!1,error:String(t)}}}async function G(t){try{try{await X.access(t)}catch{return await X.mkdir(t,{recursive:!0}),{success:!0,data:{finalPath:t}}}const e=K.dirname(t),r=K.basename(t);let n=2,a=K.join(e,`${r} ${n}`);for(;;)try{await X.access(a),n++,a=K.join(e,`${r} ${n}`)}catch{break}return await X.mkdir(a,{recursive:!0}),{success:!0,data:{finalPath:a}}}catch(t){return{success:!1,error:String(t)}}}async function J(t,e=""){try{const r=K.dirname(t);await X.mkdir(r,{recursive:!0});try{await X.access(t)}catch{return await X.writeFile(t,e,"utf-8"),{success:!0,data:{finalPath:t}}}const n=K.dirname(t),a=K.extname(t),i=K.basename(t,a);let s=2,o=K.join(n,`${i} ${s}${a}`);for(;;)try{await X.access(o),s++,o=K.join(n,`${i} ${s}${a}`)}catch{break}return await X.writeFile(o,e,"utf-8"),{success:!0,data:{finalPath:o}}}catch(t){return{success:!1,error:String(t)}}}import{promises as Y}from"fs";async function Q(t,e={}){const{adapter:r,useTrash:n=!0,onDeleted:a}=e;try{for(const e of t){if(n&&r?.trashItem)await r.trashItem(e);else{(await Y.stat(e)).isDirectory()?await Y.rm(e,{recursive:!0,force:!0}):await Y.unlink(e)}a?.(e)}return{success:!0,message:n?"文件已移动到回收站":"文件已删除"}}catch(t){return{success:!1,error:String(t)}}}import{promises as Z}from"fs";async function tt(t,e,r={}){const{onRenamed:n}=r;try{return await Z.rename(t,e),n?.(t,e),{success:!0}}catch(t){return{success:!1,error:String(t)}}}import{promises as et}from"fs";import rt from"path";async function nt(t,e){try{const r=[];for(const n of t){const t=rt.basename(n);let a=rt.join(e,t),i=1;for(;;)try{await et.access(a);const r=rt.extname(t),n=rt.basename(t,r);a=rt.join(e,`${n} ${++i}${r}`)}catch{break}(await et.stat(n)).isDirectory()?await it(n,a):await et.copyFile(n,a),r.push(a)}return{success:!0,data:{copiedPaths:r}}}catch(t){return{success:!1,error:String(t)}}}async function at(t,e){try{const r=[];for(const n of t){const t=rt.basename(n);let a=rt.join(e,t),i=1;for(;;)try{await et.access(a);const r=rt.extname(t),n=rt.basename(t,r);a=rt.join(e,`${n} ${++i}${r}`)}catch{break}try{await et.rename(n,a)}catch{(await et.stat(n)).isDirectory()?await it(n,a):await et.copyFile(n,a),await et.rm(n,{recursive:!0,force:!0})}r.push(a)}return{success:!0,data:{movedPaths:r}}}catch(t){return{success:!1,error:String(t)}}}async function it(t,e){await et.mkdir(e,{recursive:!0});const r=await et.readdir(t,{withFileTypes:!0});for(const n of r){const r=rt.join(t,n.name),a=rt.join(e,n.name);n.isDirectory()?await it(r,a):await et.copyFile(r,a)}}import{promises as st}from"fs";import ot from"path";async function ct(t){try{const e=await st.stat(t),r=ot.basename(t),n=ot.extname(r);return{success:!0,data:{path:t,name:r,size:e.size,isFile:e.isFile(),isDirectory:e.isDirectory(),createdAt:e.birthtime,updatedAt:e.mtime,extension:n||void 0}}}catch(t){return{success:!1,error:String(t)}}}async function ut(t){try{return await st.access(t),!0}catch{return!1}}async function lt(t){try{return(await st.stat(t)).isDirectory()}catch{return!1}}import{exec as mt}from"child_process";import{promisify as ft}from"util";import*as dt from"path";var ht=ft(mt);function pt(){switch(process.platform){case"darwin":return"mac";case"win32":return"windows";default:return"linux"}}async function wt(t){const e=pt();try{switch(e){case"mac":{const e=`tell application "Finder"\n activate\n set theFile to POSIX file "${t}" as alias\n open information window of theFile\n end tell`;await ht(`osascript -e '${e}'`);break}case"windows":{const e=t.replace(/'/g,"''"),r=`\n $shell = New-Object -ComObject Shell.Application\n $folder = $shell.Namespace((Split-Path '${e}'))\n $item = $folder.ParseName((Split-Path '${e}' -Leaf))\n $item.InvokeVerb('properties')\n `;await ht(`powershell -Command "${r.replace(/\n/g," ")}"`);break}case"linux":{const e=[`nautilus --select "${t}" && nautilus -q`,`dolphin --select "${t}"`,`thunar --quit && thunar "${dt.dirname(t)}"`,`xdg-open "${dt.dirname(t)}"`];let r=null;for(const t of e)try{return await ht(t),{success:!0}}catch(t){r=t}throw r||new Error("No file manager found")}}return{success:!0}}catch(t){return{success:!1,error:t instanceof Error?t.message:String(t)}}}async function gt(t){const e=pt();try{switch(e){case"mac":await ht(`open -R "${t}"`);break;case"windows":await ht(`explorer.exe /select,"${t}"`);break;case"linux":await ht(`xdg-open "${dt.dirname(t)}"`)}return{success:!0}}catch(t){return{success:!1,error:t instanceof Error?t.message:String(t)}}}async function yt(t){const e=pt();try{switch(e){case"mac":try{const e=`tell application "iTerm"\n activate\n try\n set newWindow to (create window with default profile)\n tell current session of newWindow\n write text "cd '${t}'"\n end tell\n on error\n tell current window\n create tab with default profile\n tell current session\n write text "cd '${t}'"\n end tell\n end tell\n end try\n end tell`;await ht(`osascript -e '${e}'`)}catch{const e=`tell application "Terminal"\n activate\n do script "cd '${t}'"\n end tell`;await ht(`osascript -e '${e}'`)}break;case"windows":try{await ht(`wt -d "${t}"`)}catch{await ht(`start cmd /K "cd /d ${t}"`)}break;case"linux":{const e=[`gnome-terminal --working-directory="${t}"`,`konsole --workdir "${t}"`,`xfce4-terminal --working-directory="${t}"`,`xterm -e "cd '${t}' && $SHELL"`];let r=null;for(const t of e)try{return await ht(t),{success:!0}}catch(t){r=t}throw r||new Error("No terminal found")}}return{success:!0}}catch(t){return{success:!1,error:t instanceof Error?t.message:String(t)}}}async function bt(t){const e=pt();try{const r="mac"===e?[`open -a "Cursor" "${t}"`,`open -a "Visual Studio Code" "${t}"`,`code "${t}"`]:[`cursor "${t}"`,`code "${t}"`];let n=null;for(const t of r)try{return await ht(t),{success:!0}}catch(t){n=t}throw n||new Error("No editor found")}catch(t){return{success:!1,error:t instanceof Error?t.message:String(t)}}}import*as vt from"compressing";import*as Ft from"path";import*as xt from"fs";import{promises as Ct}from"fs";import{pipeline as Et}from"stream/promises";function St(t){const e=t.toLowerCase();return e.endsWith(".zip")?"zip":e.endsWith(".tar.gz")||e.endsWith(".tgz")?"tgz":e.endsWith(".tar.bz2")||e.endsWith(".tbz2")?"tarbz2":e.endsWith(".tar")?"tar":null}function It(t){return null!==St(t)}async function $t(t){const e=[],r=await Ct.readdir(t,{withFileTypes:!0});for(const n of r){const r=Ft.join(t,n.name);n.isDirectory()?e.push(...await $t(r)):e.push(r)}return e}async function Tt(t,e,r){try{const{format:n,level:a="normal",outputName:i,outputDir:s,deleteSource:o}=e,c=function(t){switch(t){case"zip":default:return".zip";case"tar":return".tar";case"tgz":return".tar.gz";case"tarbz2":return".tar.bz2"}}(n),u=i.endsWith(c)?i:i+c,l=Ft.join(s,u);await Ct.mkdir(s,{recursive:!0});const m=await async function(t){let e=0;for(const r of t)(await Ct.stat(r)).isDirectory()?e+=(await $t(r)).length:e+=1;return e}(t);let f=0;switch(n){case"zip":{const e=new vt.zip.Stream;for(const n of t){const t=await Ct.stat(n),a=Ft.basename(n);if(t.isDirectory()){const t=await $t(n);for(const a of t){const t=Ft.relative(Ft.dirname(n),a);e.addEntry(a,{relativePath:t}),f++,r?.({currentFile:Ft.basename(a),processedCount:f,totalCount:m,percent:Math.round(f/m*100)})}}else e.addEntry(n,{relativePath:a}),f++,r?.({currentFile:a,processedCount:f,totalCount:m,percent:Math.round(f/m*100)})}const n=xt.createWriteStream(l);await Et(e,n);break}case"tar":{const e=new vt.tar.Stream;for(const n of t){const t=await Ct.stat(n),a=Ft.basename(n);if(t.isDirectory()){const t=await $t(n);for(const a of t){const t=Ft.relative(Ft.dirname(n),a);e.addEntry(a,{relativePath:t}),f++,r?.({currentFile:Ft.basename(a),processedCount:f,totalCount:m,percent:Math.round(f/m*100)})}}else e.addEntry(n,{relativePath:a}),f++,r?.({currentFile:a,processedCount:f,totalCount:m,percent:Math.round(f/m*100)})}const n=xt.createWriteStream(l);await Et(e,n);break}case"tgz":{const e=new vt.tgz.Stream;for(const n of t){const t=await Ct.stat(n),a=Ft.basename(n);if(t.isDirectory()){const t=await $t(n);for(const a of t){const t=Ft.relative(Ft.dirname(n),a);e.addEntry(a,{relativePath:t}),f++,r?.({currentFile:Ft.basename(a),processedCount:f,totalCount:m,percent:Math.round(f/m*100)})}}else e.addEntry(n,{relativePath:a}),f++,r?.({currentFile:a,processedCount:f,totalCount:m,percent:Math.round(f/m*100)})}const n=xt.createWriteStream(l);await Et(e,n);break}case"tarbz2":{const e=new vt.tgz.Stream;for(const n of t){const t=await Ct.stat(n),a=Ft.basename(n);if(t.isDirectory()){const t=await $t(n);for(const a of t){const t=Ft.relative(Ft.dirname(n),a);e.addEntry(a,{relativePath:t}),f++,r?.({currentFile:Ft.basename(a),processedCount:f,totalCount:m,percent:Math.round(f/m*100)})}}else e.addEntry(n,{relativePath:a}),f++,r?.({currentFile:a,processedCount:f,totalCount:m,percent:Math.round(f/m*100)})}const n=xt.createWriteStream(l.replace(".tar.bz2",".tar.gz"));await Et(e,n);break}}if(o)for(const e of t){(await Ct.stat(e)).isDirectory()?await Ct.rm(e,{recursive:!0}):await Ct.unlink(e)}return{success:!0,outputPath:l}}catch(t){return{success:!1,error:t instanceof Error?t.message:String(t)}}}async function Dt(t,e,r){try{const{targetDir:n,deleteArchive:a}=e,i=St(t);if(!i)return{success:!1,error:"不支持的压缩格式"};switch(await Ct.mkdir(n,{recursive:!0}),r?.({currentFile:Ft.basename(t),processedCount:0,totalCount:1,percent:0}),i){case"zip":await vt.zip.uncompress(t,n);break;case"tar":await vt.tar.uncompress(t,n);break;case"tgz":await vt.tgz.uncompress(t,n);break;case"tarbz2":return{success:!1,error:"tar.bz2 格式暂不支持"}}return r?.({currentFile:Ft.basename(t),processedCount:1,totalCount:1,percent:100}),a&&await Ct.unlink(t),{success:!0,outputPath:n}}catch(t){return{success:!1,error:t instanceof Error?t.message:String(t)}}}import Pt from"path";import jt from"os";var kt=process.platform;function Mt(t){const e=jt.homedir();switch(t){case"desktop":return Pt.join(e,"Desktop");case"documents":return Pt.join(e,"Documents");case"downloads":return Pt.join(e,"Downloads");case"pictures":return Pt.join(e,"Pictures");case"music":return Pt.join(e,"Music");case"videos":return"darwin"===kt?Pt.join(e,"Movies"):Pt.join(e,"Videos");case"applications":return"darwin"===kt?"/Applications":"win32"===kt?process.env.ProgramFiles||"C:\\Program Files":"/usr/share/applications";case"home":return e;case"root":return"darwin"===kt?"/":"win32"===kt?"C:\\":"/";default:return null}}function Nt(){const t=["desktop","documents","downloads","pictures","music","videos","applications","home","root"],e={};for(const r of t)e[r]=Mt(r);return e}function zt(){return jt.homedir()}function At(){return process.platform}import{fdir as _t}from"fdir";import Wt from"path";import{promises as Lt,readFileSync as Rt}from"fs";import Ot from"ignore";function Bt(){return Ot().add(".git")}async function Ut(t,e){const r=Bt();if(!e)return r;for(const e of[".gitignore",".ignore"])try{r.add(await Lt.readFile(Wt.join(t,e),"utf-8"))}catch{}return r}function Ht(t,e,r){for(const n of r){const r=Wt.relative(n.basePath,t);if(r&&!r.startsWith("..")&&n.ig.ignores(e?r+"/":r))return!0}return!1}function qt(t){return t.startsWith(".")&&"."!==t}function Xt(t,e){const r=new Map;function n(t){if(r.has(t))return r.get(t);const n=e?function(t){const e=Ot();let r=!1;for(const n of[".gitignore",".ignore"])try{e.add(Rt(Wt.join(t,n),"utf-8")),r=!0}catch{}return r?e:null}(t):null;return r.set(t,n),n}return{isNestedIgnored:function(r,a){if(!e)return!1;let i=Wt.dirname(r);for(;i.length>t.length&&i.startsWith(t);){const t=n(i);if(t){const e=Wt.relative(i,r);if(t.ignores(a?e+"/":e))return!0}i=Wt.dirname(i)}return!1}}}function Kt(t){return{maxDepth:t?.maxDepth??0,includeDirs:t?.includeDirs??!1,maxFiles:t?.maxFiles??0,excludeDirs:t?.excludeDirs??[],extraIgnoreRules:t?.extraIgnoreRules??[],useIgnoreFiles:t?.useIgnoreFiles??!0,includeHidden:t?.includeHidden??!0,signal:t?.signal}}async function Vt(t,e){const r=Kt(e),n=await Ut(t,r.useIgnoreFiles);r.extraIgnoreRules.length>0&&n.add(r.extraIgnoreRules);const a=r.excludeDirs.length>0?new Set(r.excludeDirs):null,i=Xt(t,r.useIgnoreFiles),s=(new _t).withFullPaths().exclude((e,s)=>{if(!r.includeHidden&&qt(e))return!0;if(a?.has(e))return!0;const o=Wt.relative(t,s);return!!o&&(!!n.ignores(o+"/")||i.isNestedIgnored(s,!0))}).filter((e,a)=>{if(!r.includeHidden&&qt(Wt.basename(e)))return!1;const s=Wt.relative(t,e);return!s||!n.ignores(a?s+"/":s)&&!i.isNestedIgnored(e,a)});r.signal&&s.withAbortSignal(r.signal),r.includeDirs&&s.withDirs(),r.maxDepth>0&&s.withMaxDepth(r.maxDepth);const o=await s.crawl(t).withPromise();return r.maxFiles>0?o.slice(0,r.maxFiles):o}function Gt(t,e){const r=Kt(e),n=function(t,e){const r=Bt();if(!e)return r;for(const e of[".gitignore",".ignore"])try{r.add(Rt(Wt.join(t,e),"utf-8"))}catch{}return r}(t,r.useIgnoreFiles);r.extraIgnoreRules.length>0&&n.add(r.extraIgnoreRules);const a=r.excludeDirs.length>0?new Set(r.excludeDirs):null,i=Xt(t,r.useIgnoreFiles),s=(new _t).withFullPaths().exclude((e,s)=>{if(!r.includeHidden&&qt(e))return!0;if(a?.has(e))return!0;const o=Wt.relative(t,s);return!!o&&(!!n.ignores(o+"/")||i.isNestedIgnored(s,!0))}).filter((e,a)=>{if(!r.includeHidden&&qt(Wt.basename(e)))return!1;const s=Wt.relative(t,e);return!s||!n.ignores(a?s+"/":s)&&!i.isNestedIgnored(e,a)});r.signal&&s.withAbortSignal(r.signal),r.includeDirs&&s.withDirs(),r.maxDepth>0&&s.withMaxDepth(r.maxDepth);const o=s.crawl(t).sync();return r.maxFiles>0?o.slice(0,r.maxFiles):o}async function Jt(t,e,r){const n=Kt(r),a=await Ut(t,n.useIgnoreFiles);n.extraIgnoreRules.length>0&&a.add(n.extraIgnoreRules);const i={ig:a,basePath:t},s=n.excludeDirs.length>0?new Set(n.excludeDirs):null;let o=0,c=!1;const u=n.maxFiles>0?n.maxFiles:1/0;await async function r(a,i,l){if(c||n.signal?.aborted)return;if(n.maxDepth>0&&l>n.maxDepth)return;let m=i;if(a!==t&&n.useIgnoreFiles){const t=await async function(t){const e=[];for(const r of[".gitignore",".ignore"])try{e.push(await Lt.readFile(Wt.join(t,r),"utf-8"))}catch{}return e}(a);if(t.length>0){const e=Ot();for(const r of t)e.add(r);m=[...i,{ig:e,basePath:a}]}}try{const t=await Lt.readdir(a,{withFileTypes:!0}),i=[],f=[];for(const r of t){if(c||n.signal?.aborted)return;const t=Wt.join(a,r.name),l=r.isDirectory();if((n.includeHidden||!qt(r.name))&&(!s?.has(r.name)&&!Ht(t,l,m))){if((!l||n.includeDirs)&&(i.push(t),o++,o>=u))return c=!0,void await e(i,!0);l&&f.push(t)}}if(i.length>0){if(!0===await e(i,!1))return void(c=!0)}for(const t of f){if(n.signal?.aborted)return;await r(t,m,l+1)}}catch{}}(t,[i],0),c||n.signal?.aborted||await e([],!0)}import Yt from"path";function Qt(t){return new RegExp(t.replace(/\*/g,".*"),"i")}async function Zt(t,e,r){const n=await Vt(t,{maxDepth:r,includeDirs:!0});if(e){const t=Qt(e);return n.filter(e=>t.test(Yt.basename(e)))}return n}async function te(t,e,r,n=100,a){const i=Qt(e);let s=0;await Jt(t,(t,e)=>{const a=t.filter(t=>i.test(Yt.basename(t)));if(a.length>0){const t=n-s,i=a.length>t?a.slice(0,t):a;s+=i.length,r(i,e||s>=n)}else e&&r([],!0);return s>=n},{includeDirs:!0,signal:a?.signal})}function ee(t,e,r){const n=Gt(t,{maxDepth:r,includeDirs:!0});if(e){const t=new RegExp(e.replace(/\*/g,".*"),"i");return n.filter(e=>t.test(Yt.basename(e)))}return n}import{xxhash64 as re}from"hash-wasm";import{stat as ne}from"fs/promises";async function ae(t,e){const r=e||await ne(t),n=`${t}:${r.size}:${r.mtime.getTime()}`;return await re(n)}import{promises as ie}from"fs";import se from"path";async function oe(t,e){try{const r=[];for(const e of t)try{await ie.access(e),r.push(e)}catch{}return 0===r.length?{success:!1,error:"没有找到有效的文件"}:(e.writeFiles(r),{success:!0})}catch(t){return{success:!1,error:String(t)}}}function ce(t){try{const e=t.readFiles();return e&&Array.isArray(e)&&e.length>0?{success:!0,data:{files:e}}:{success:!1,error:"剪贴板中没有文件"}}catch(t){return{success:!1,error:String(t)}}}async function ue(t,e){try{if(!t||"string"!=typeof t)return{success:!1,error:"目标目录路径无效"};if(!e||!Array.isArray(e)||0===e.length)return{success:!1,error:"源文件路径列表无效"};const r=[];for(const n of e){const e=se.basename(n);let a=se.join(t,e),i=1;for(;;)try{await ie.access(a);const r=se.extname(e),n=se.basename(e,r);a=se.join(t,`${n} ${++i}${r}`)}catch{break}(await ie.stat(n)).isDirectory()?await le(n,a):await ie.copyFile(n,a),r.push(a)}return{success:!0,data:{pastedPaths:r}}}catch(t){return{success:!1,error:String(t)}}}async function le(t,e){await ie.mkdir(e,{recursive:!0});const r=await ie.readdir(t,{withFileTypes:!0});for(const n of r){const r=se.join(t,n.name),a=se.join(e,n.name);n.isDirectory()?await le(r,a):await ie.copyFile(r,a)}}import{promises as me}from"fs";import fe from"path";import de from"os";import{createHash as he}from"crypto";import{execFile as pe}from"child_process";import{promisify as we}from"util";import{inflateSync as ge}from"zlib";var ye=we(pe),be=fe.join(de.tmpdir(),"file-explorer-app-icons"),ve=!1;async function Fe(t,e){if(await async function(){if(!ve)try{await me.mkdir(be,{recursive:!0}),ve=!0}catch{}}(),!ve)return;const r=e.split(",")[1];if(r)try{await me.writeFile(fe.join(be,`${t}.png`),Buffer.from(r,"base64"))}catch{}}async function xe(t){try{return await me.access(t),!0}catch{return!1}}function Ce(t,e,r,n){const a=Buffer.from(e);for(let e=0;e<a.length;e++){const i=e>=n?a[e-n]:0,s=r[e]??0,o=e>=n?r[e-n]??0:0;if(1===t)a[e]=a[e]+i&255;else if(2===t)a[e]=a[e]+s&255;else if(3===t)a[e]=a[e]+Math.floor((i+s)/2)&255;else if(4===t){const t=i+s-o,r=Math.abs(t-i),n=Math.abs(t-s),c=Math.abs(t-o),u=r<=n&&r<=c?i:n<=c?s:o;a[e]=a[e]+u&255}}return a}async function Ee(t){const e=fe.join(de.tmpdir(),`app-icon-${Date.now()}-${Math.random().toString(36).slice(2)}.png`);try{await ye("sips",["-s","format","png",t,"--out",e,"--resampleHeightWidthMax",String(128)]);const r=await me.readFile(e);return function(t){if(!function(t){return t.length>=8&&137===t[0]&&80===t[1]&&78===t[2]&&71===t[3]&&13===t[4]&&10===t[5]&&26===t[6]&&10===t[7]}(t))return!1;if(t.length>4096)return!1;try{let e=8,r=0,n=0,a=0,i=0;const s=[];for(;e+12<=t.length;){const o=t.readUInt32BE(e),c=t.toString("ascii",e+4,e+8),u=e+8,l=u+o;if(l>t.length)return!1;const m=t.subarray(u,l);if("IHDR"===c)r=m.readUInt32BE(0),n=m.readUInt32BE(4),a=m[8]??0,i=m[9]??0;else if("IDAT"===c)s.push(m);else if("IEND"===c)break;e=l+4}const o=6===i?4:2===i?3:0;if(!r||!n||8!==a||!o||0===s.length)return!1;const c=ge(Buffer.concat(s)),u=r*o,l=new Set;let m=Buffer.alloc(u);for(let t=0;t<n;t++){const e=t*(u+1),n=Ce(c[e]??0,c.subarray(e+1,e+1+u),m,o);m=n;for(let t=0;t<r;t++){const e=t*o;if(l.add(n.subarray(e,e+o).toString("hex")),l.size>2)return!1}}return!0}catch{return!1}}(r)?null:`data:image/png;base64,${r.toString("base64")}`}catch{return null}finally{me.unlink(e).catch(()=>{})}}async function Se(t){const e=fe.join(de.tmpdir(),`app-icon-native-${Date.now()}-${Math.random().toString(36).slice(2)}.png`);try{return await ye("osascript",["-l","JavaScript","-e","\nObjC.import('AppKit');\nObjC.import('Foundation');\n\nfunction run(argv) {\n const image = $.NSWorkspace.sharedWorkspace.iconForFile(argv[0]);\n if (!image) return false;\n image.setSize($.NSMakeSize(128, 128));\n const tiff = image.TIFFRepresentation;\n if (!tiff) return false;\n const rep = $.NSBitmapImageRep.imageRepWithData(tiff);\n if (!rep) return false;\n const data = rep.representationUsingTypeProperties($.NSBitmapImageFileTypePNG, $());\n if (!data) return false;\n return data.writeToFileAtomically(argv[1], true);\n}\n",t,e],{timeout:5e3,maxBuffer:65536}),await Ee(e)}catch{return null}finally{me.unlink(e).catch(()=>{})}}async function Ie(t){try{const e=await me.readFile(t);return function(t){return!(t.length<16)&&137===t[0]&&80===t[1]&&78===t[2]&&71===t[3]&&t.subarray(8,32).includes(Buffer.from("CgBI"))}(e)?Ee(t):`data:image/png;base64,${e.toString("base64")}`}catch{return null}}async function $e(t){try{const{stdout:e}=await ye("plutil",["-convert","json","-o","-",t]),r=JSON.parse(e);return r&&"object"==typeof r?r:null}catch{return null}}async function Te(t){const e=await async function(t){const e=fe.join(t,"WrappedBundle");try{return(await me.lstat(e)).isSymbolicLink()?await me.realpath(e):null}catch{const e=fe.join(t,"Wrapper");try{const t=(await me.readdir(e)).find(t=>t.endsWith(".app"));return t?fe.join(e,t):null}catch{return null}}}(t);if(!e)return null;const r=await $e(fe.join(e,"Info.plist"));if(!r)return null;const n=function(t){const e=t=>"string"==typeof t?[t]:Array.isArray(t)?t.filter(t=>"string"==typeof t):[],r=new Set,n=t=>{if(!t||"object"!=typeof t)return;const n=t,a=n.CFBundlePrimaryIcon;if(a&&"object"==typeof a){const t=a;e(t.CFBundleIconFiles).forEach(t=>r.add(t)),e(t.CFBundleIconName).forEach(t=>r.add(t))}e(n.CFBundleIconFiles).forEach(t=>r.add(t)),e(n.CFBundleIconName).forEach(t=>r.add(t))};return n(t.CFBundleIcons),n(t["CFBundleIcons~ipad"]),e(t.CFBundleIconFiles).forEach(t=>r.add(t)),e(t.CFBundleIconName).forEach(t=>r.add(t)),[...r]}(r);return async function(t,e){if(0===e.length)return null;let r;try{r=await me.readdir(t)}catch{return null}const n=[];for(const t of e)for(const e of r)e.toLowerCase().endsWith(".png")&&(e===`${t}.png`||e.startsWith(`${t}@`)||e.startsWith(`${t}-`))&&n.push(e);if(0===n.length)return null;const a=t=>{let e=0;return t.includes("@3x")?e+=30:t.includes("@2x")?e+=20:e+=10,t.includes("~ipad")&&(e+=5),e};return n.sort((t,e)=>a(e)-a(t)),fe.join(t,n[0])}(e,n)}async function De(t){if("darwin"!==process.platform)return null;let e=0;try{const r=await me.stat(t);if(!r.isDirectory()||!t.endsWith(".app"))return null;e=r.mtimeMs}catch{return null}const r=function(t,e){return he("sha1").update(`v2|${t}|${Math.floor(e)}`).digest("hex")}(t,e),n=await async function(t){try{return`data:image/png;base64,${(await me.readFile(fe.join(be,`${t}.png`))).toString("base64")}`}catch{return null}}(r);if(n)return n;const a=await async function(t){const e=await Te(t);if(e){const t=await Ie(e);if(t)return t}const r=await async function(t){const e=fe.join(t,"Contents","Resources"),r=fe.join(t,"Contents","Info.plist"),n=await $e(r),a=n?.CFBundleIconFile;if("string"==typeof a&&a.trim().length>0){const t=a.endsWith(".icns")?a:`${a}.icns`,r=fe.join(e,t);if(await xe(r))return r}const i=["AppIcon.icns","app.icns","application.icns","icon.icns"];for(const t of i){const r=fe.join(e,t);if(await xe(r))return r}try{const t=(await me.readdir(e)).find(t=>t.toLowerCase().endsWith(".icns"));if(t)return fe.join(e,t)}catch{}const s=fe.join(e,"Assets.xcassets","AppIcon.appiconset"),o=fe.join(s,"Contents.json");try{const t=await me.readFile(o,"utf-8"),e=(JSON.parse(t).images??[]).filter(t=>t.filename?.toLowerCase().endsWith(".png")).map(t=>({path:fe.join(s,t.filename),scale:parseFloat(t.scale??"1")||1})).sort((t,e)=>e.scale-t.scale);if(e[0]&&await xe(e[0].path))return e[0].path}catch{}try{const t=(await me.readdir(s)).find(t=>t.toLowerCase().endsWith(".png"));if(t)return fe.join(s,t)}catch{}try{const e=(await me.readdir(t)).find(t=>t.toLowerCase().endsWith(".icns"));if(e)return fe.join(t,e)}catch{}return null}(t);if(!r)return Se(t);if(r.toLowerCase().endsWith(".png"))return Ie(r);return await Ee(r)??Se(t)}(t);return a&&Fe(r,a),a}import*as Pe from"fs";import*as je from"path";var ke=new Map;function Me(t,e){let r=null;try{r=Pe.watch(t,{persistent:!0,recursive:!0},(r,n)=>{if(!n)return;const a=je.join(t,n),i=`${t}:${n}`,s=ke.get(i);s&&clearTimeout(s);const o=setTimeout(()=>{ke.delete(i),Pe.access(a,Pe.constants.F_OK,t=>{let i;i=t?"remove":"rename"===r?"add":"change",e({type:i,path:a,filename:n})})},100);ke.set(i,o)}),r.on("error",t=>{})}catch(t){}return{close:()=>{r&&(r.close(),r=null);for(const[e,r]of ke.entries())e.startsWith(`${t}:`)&&(clearTimeout(r),ke.delete(e))},path:t}}var Ne=class{watchers=new Map;callbacks=new Map;watch(t,e){const r=je.normalize(t);let n=this.callbacks.get(r);n||(n=new Set,this.callbacks.set(r,n)),n.add(e);let a=this.watchers.get(r);if(a)a.refCount++;else{a={watcher:Me(r,t=>{const e=this.callbacks.get(r);if(e)for(const r of e)try{r(t)}catch(t){}}),refCount:1},this.watchers.set(r,a)}return()=>{this.unwatch(r,e)}}unwatch(t,e){const r=je.normalize(t),n=this.callbacks.get(r);n&&(n.delete(e),0===n.size&&this.callbacks.delete(r));const a=this.watchers.get(r);a&&(a.refCount--,a.refCount<=0&&(a.watcher.close(),this.watchers.delete(r)))}closeAll(){for(const[,t]of this.watchers)t.watcher.close();this.watchers.clear(),this.callbacks.clear()}},ze=null;function Ae(){return ze||(ze=new Ne),ze}import{promises as _e}from"fs";import We from"path";var Le=class{database;imageProcessor;videoProcessor;urlEncoder;getApplicationIcon;constructor(t){this.database=t.database,this.imageProcessor=t.imageProcessor||null,this.videoProcessor=t.videoProcessor||null,this.urlEncoder=t.urlEncoder||(t=>`file://${encodeURIComponent(t)}`),this.getApplicationIcon=t.getApplicationIcon||null}async getCachedThumbnailUrl(t){try{const e=await _e.stat(t),r=w(t,e);if("application"===r&&this.getApplicationIcon)return await this.getApplicationIcon(t);if("image"!==r&&"video"!==r)return null;const n=e.mtime.getTime(),a=this.database.getThumbnailPathFast(t,n);return a?this.urlEncoder(a):(ae(t,e).then(e=>{this.generateThumbnail(t,e,n).catch(()=>{})}).catch(()=>{}),null)}catch(t){return null}}async getThumbnailUrl(t){try{const e=await _e.stat(t),r=w(t,e);if("application"===r&&this.getApplicationIcon)return await this.getApplicationIcon(t);if("image"!==r&&"video"!==r)return null;const n=e.mtime.getTime(),a=this.database.getThumbnailPathFast(t,n);if(a)return this.urlEncoder(a);const i=await ae(t,e),s=await this.generateThumbnail(t,i,n);return s?this.urlEncoder(s):null}catch(t){return null}}async generateThumbnail(t,e,r){const n=this.database.getThumbnailPath(t,e,r);if(n)return n;try{const n=w(t,await _e.stat(t)),a=`${e.substring(0,16)}.jpg`,i=We.join(this.database.getCacheDir(),a);if(function(t,e){return"image"===e}(0,n)&&this.imageProcessor)await this.imageProcessor.resize(t,i,256);else{if(!function(t,e){return"video"===e}(0,n)||!this.videoProcessor)return null;await this.videoProcessor.screenshot(t,i,"00:00:01","256x256")}return this.database.saveThumbnail(t,e,r,i),i}catch(t){return null}}async generateThumbnailsBatch(t,e=3){const r=async t=>{try{await this.generateThumbnail(t.path,t.hash,t.mtime)}catch(t){}};for(let n=0;n<t.length;n+=e){const a=t.slice(n,n+e);await Promise.allSettled(a.map(r))}}deleteThumbnail(t){this.database.deleteThumbnail(t)}cleanupOldThumbnails(){this.database.cleanupOldThumbnails()}},Re=null;function Oe(t){return Re=new Le(t)}function Be(){return Re}import Ue from"path";import{existsSync as He,mkdirSync as qe}from"fs";var Xe=class{db=null;cacheDir;dbPath;sqliteFactory;constructor(t,e){this.sqliteFactory=e.sqliteFactory;const r=e.dirName||"thumbnails",n=e.dbFileName||"thumbnails.db",a=e.dbPath?Ue.dirname(e.dbPath):null;this.cacheDir=e.thumbnailDir?e.thumbnailDir:a||Ue.join(t,r),this.dbPath=e.dbPath?e.dbPath:Ue.join(this.cacheDir,n),He(this.cacheDir)||qe(this.cacheDir,{recursive:!0})}init(){this.db||(this.db=this.sqliteFactory(this.dbPath),this.db.pragma("journal_mode = WAL"),this.db.exec("\n CREATE TABLE IF NOT EXISTS thumbnails (\n file_path TEXT PRIMARY KEY,\n file_hash TEXT NOT NULL,\n mtime INTEGER NOT NULL,\n thumbnail_path TEXT NOT NULL,\n created_at INTEGER NOT NULL\n );\n\n CREATE INDEX IF NOT EXISTS idx_file_hash ON thumbnails(file_hash);\n CREATE INDEX IF NOT EXISTS idx_mtime ON thumbnails(mtime);\n "))}getCacheDir(){return this.cacheDir}getThumbnailPathFast(t,e){this.db||this.init();const r=this.db.prepare("\n SELECT thumbnail_path\n FROM thumbnails\n WHERE file_path = ? AND mtime = ?\n ").get(t,e);return r&&He(r.thumbnail_path)?r.thumbnail_path:null}getThumbnailPath(t,e,r){this.db||this.init();const n=this.db.prepare("\n SELECT thumbnail_path, mtime\n FROM thumbnails\n WHERE file_path = ? AND file_hash = ?\n ").get(t,e);return n&&n.mtime===r&&He(n.thumbnail_path)?n.thumbnail_path:null}saveThumbnail(t,e,r,n){this.db||this.init(),this.db.prepare("\n INSERT OR REPLACE INTO thumbnails\n (file_path, file_hash, mtime, thumbnail_path, created_at)\n VALUES (?, ?, ?, ?, ?)\n ").run(t,e,r,n,Date.now())}deleteThumbnail(t){this.db||this.init(),this.db.prepare("DELETE FROM thumbnails WHERE file_path = ?").run(t)}cleanupOldThumbnails(){this.db||this.init();const t=Date.now()-2592e6;this.db.prepare("DELETE FROM thumbnails WHERE created_at < ?").run(t)}close(){if(this.db){try{this.db.pragma("wal_checkpoint(TRUNCATE)")}catch{}this.db.close(),this.db=null}}},Ke=null;function Ve(t){return Ke||(Ke=new Xe(t.userDataPath,t)).init(),Ke}function Ge(){return Ke}function Je(){Ke&&(Ke.close(),Ke=null)}import{spawn as Ye}from"child_process";function Qe(t){return{async resize(e,r,n){await t(e).resize({width:n,withoutEnlargement:!0}).jpeg({quality:80,optimiseCoding:!0}).toFile(r)}}}function Ze(t){return{async screenshot(e,r,n,a){const i=a.split("x")[0];return new Promise((a,s)=>{const o=Ye(t,["-y","-ss",n,"-i",e,"-vframes","1","-vf",`thumbnail,scale=${i}:-1:force_original_aspect_ratio=decrease`,"-c:v","mjpeg","-q:v","6",r]),c=setTimeout(()=>{o.kill(),s(new Error("Video thumbnail generation timeout"))},3e4);o.stderr.on("data",t=>{t.toString().includes("Unsupported pixel format")}),o.on("close",t=>{clearTimeout(c),0===t?a():s(new Error(`ffmpeg exited with code ${t}`))}),o.on("error",t=>{clearTimeout(c),s(t)})})}}}import{execFile as tr}from"child_process";import{promisify as er}from"util";import rr from"path";var nr=er(tr),ar=new Set(["mp4","webm","ogg","ogv"]),ir=new Set(["h264","avc1","vp8","vp9","theora","av1"]),sr=new Set(["aac","mp3","opus","vorbis","flac"]),or=new Set(["mp3","wav","ogg","oga","webm","m4a","aac","flac"]),cr=new Set(["mp3","aac","opus","vorbis","flac","pcm_s16le","pcm_s24le"]),ur=new Set(["h264","avc1","hevc","h265"]),lr=new Set(["aac","alac"]),mr=new Set(["mp4","mkv","avi","mov","wmv","flv","webm","ogv","ogg","m4v","mpeg","mpg","3gp","ts","mts","m2ts","vob","rmvb","rm"]),fr=new Set(["mp3","wav","flac","aac","m4a","ogg","oga","wma","ape","alac","aiff","aif","opus","mid","midi","wv","mka"]);function dr(t){const e=rr.extname(t).toLowerCase().slice(1);return mr.has(e)?"video":fr.has(e)?"audio":null}async function hr(t,e){try{const{stdout:r}=await nr(e,["-v","quiet","-print_format","json","-show_format","-show_streams",t]),n=JSON.parse(r),a=n.format||{},i=n.streams||[],s=i.find(t=>"video"===t.codec_type),o=i.find(t=>"audio"===t.codec_type),c=s?"video":"audio",u=a.format_name||"";return{type:c,container:u.split(",")[0].toLowerCase(),videoCodec:s?.codec_name?.toLowerCase(),audioCodec:o?.codec_name?.toLowerCase(),duration:parseFloat(a.duration)||void 0,width:s?.width,height:s?.height,bitrate:parseInt(a.bit_rate)||void 0}}catch{const e=dr(t);if(!e)return null;return{type:e,container:rr.extname(t).toLowerCase().slice(1)}}}function pr(t,e){if(t&&"direct"!==e)return"remux"===e?Math.ceil(t/50):Math.ceil(t/3)}async function wr(t,e){const r=await hr(t,e);if(!r){return{type:dr(t)||"video",needsTranscode:!1,method:"direct"}}const{type:n}=r;return"video"===n?(a=r,!ar.has(a.container)||a.videoCodec&&!ir.has(a.videoCodec)||a.audioCodec&&!sr.has(a.audioCodec)?function(t){if(!t.videoCodec||!ur.has(t.videoCodec))return!1;if(t.audioCodec&&!sr.has(t.audioCodec)&&!lr.has(t.audioCodec))return!1;return!0}(r)?{type:n,needsTranscode:!0,method:"remux",formatInfo:r,targetFormat:"mp4",estimatedTime:pr(r.duration,"remux")}:{type:n,needsTranscode:!0,method:"transcode",formatInfo:r,targetFormat:"mp4",estimatedTime:pr(r.duration,"transcode")}:{type:n,needsTranscode:!1,method:"direct",formatInfo:r}):function(t){return!(!or.has(t.container)||t.audioCodec&&!cr.has(t.audioCodec))}(r)?{type:n,needsTranscode:!1,method:"direct",formatInfo:r}:function(t){return!!t.audioCodec&&lr.has(t.audioCodec)}(r)?{type:n,needsTranscode:!0,method:"remux",formatInfo:r,targetFormat:"m4a",estimatedTime:pr(r.duration,"remux")}:{type:n,needsTranscode:!0,method:"transcode",formatInfo:r,targetFormat:"mp3",estimatedTime:pr(r.duration,"transcode")};var a}import{spawn as gr}from"child_process";import yr from"fs/promises";import br from"path";import vr from"os";function Fr(t,e){const r=t.match(/time=(\d+):(\d+):(\d+)\.(\d+)/);if(!r)return null;const n=3600*parseInt(r[1])+60*parseInt(r[2])+parseInt(r[3])+parseInt(r[4])/100,a=t.match(/speed=\s*([\d.]+)x/),i=a?`${a[1]}x`:void 0;let s=0;return e&&e>0&&(s=Math.min(100,Math.round(n/e*100))),{percent:s,time:n,duration:e,speed:i}}async function xr(t,e,r,n,a){try{if(!r.needsTranscode)return{success:!0,outputPath:e};const i=r.targetFormat||("video"===r.type?"mp4":"mp3"),s=await async function(t,e,r){const n=r||br.join(vr.tmpdir(),"file-explorer-media");await yr.mkdir(n,{recursive:!0});const a=`${br.basename(t,br.extname(t))}_${Date.now()}.${e}`;return br.join(n,a)}(e,i,n),o=r.formatInfo?.duration;return"video"===r.type?"remux"===r.method?await async function(t,e,r,n,a){return new Promise((i,s)=>{const o=gr(t,["-i",e,"-c","copy","-movflags","+faststart","-y",r]);let c="";o.stderr.on("data",t=>{if(c+=t.toString(),a){const t=Fr(c,n);t&&a(t)}}),o.on("close",t=>{0===t?i():s(new Error(`ffmpeg exited with code ${t}`))}),o.on("error",s)})}(t,e,s,o,a):await async function(t,e,r,n,a){return new Promise((i,s)=>{const o=gr(t,["-i",e,"-c:v","libx264","-preset","fast","-crf","23","-c:a","aac","-b:a","192k","-movflags","+faststart","-y",r]);let c="";o.stderr.on("data",t=>{if(c+=t.toString(),a){const t=Fr(c,n);t&&a(t)}}),o.on("close",t=>{0===t?i():s(new Error(`ffmpeg exited with code ${t}`))}),o.on("error",s)})}(t,e,s,o,a):"remux"===r.method?await async function(t,e,r,n,a){return new Promise((i,s)=>{const o=gr(t,["-i",e,"-c","copy","-y",r]);let c="";o.stderr.on("data",t=>{if(c+=t.toString(),a){const t=Fr(c,n);t&&a(t)}}),o.on("close",t=>{0===t?i():s(new Error(`ffmpeg exited with code ${t}`))}),o.on("error",s)})}(t,e,s,o,a):await async function(t,e,r,n,a){return new Promise((i,s)=>{const o=br.extname(r).toLowerCase(),c=gr(t,["-i",e,"-c:a",".m4a"===o?"aac":"libmp3lame","-b:a","192k","-y",r]);let u="";c.stderr.on("data",t=>{if(u+=t.toString(),a){const t=Fr(u,n);t&&a(t)}}),c.on("close",t=>{0===t?i():s(new Error(`ffmpeg exited with code ${t}`))}),c.on("error",s)})}(t,e,s,o,a),a&&a({percent:100,duration:o}),{success:!0,outputPath:s}}catch(t){return{success:!1,error:t instanceof Error?t.message:"Unknown error"}}}async function Cr(t){try{t.includes("file-explorer-media")&&await yr.unlink(t)}catch{}}async function Er(t){const e=t||br.join(vr.tmpdir(),"file-explorer-media");try{const t=await yr.readdir(e);await Promise.all(t.map(t=>yr.unlink(br.join(e,t)).catch(()=>{})))}catch{}}import Sr from"path";import{execFile as Ir}from"child_process";import{promisify as $r}from"util";var Tr=$r(Ir),Dr=null,Pr=class{ffmpegPath;ffprobePath;tempDir;urlEncoder;transcodeInfoCache=new Map;transcodedFiles=new Map;constructor(t){this.ffmpegPath=t.ffmpegPath,this.ffprobePath=t.ffprobePath||Sr.join(Sr.dirname(t.ffmpegPath),"ffprobe"),this.tempDir=t.tempDir,this.urlEncoder=t.urlEncoder}async needsTranscode(t){const e=this.transcodeInfoCache.get(t);if(e)return e;const r=await wr(t,this.ffprobePath);return this.transcodeInfoCache.set(t,r),r}async transcode(t,e){const r=this.transcodedFiles.get(t);if(r)return{success:!0,outputPath:r,url:this.urlEncoder?this.urlEncoder(r):`file://${r}`};const n=await this.needsTranscode(t);if(!n.needsTranscode){return{success:!0,outputPath:t,url:this.urlEncoder?this.urlEncoder(t):`file://${t}`}}const a=await xr(this.ffmpegPath,t,n,this.tempDir,e);return a.success&&a.outputPath&&(this.transcodedFiles.set(t,a.outputPath),a.url=this.urlEncoder?this.urlEncoder(a.outputPath):`file://${a.outputPath}`),a}async getMetadata(t){try{const{stdout:e}=await Tr(this.ffprobePath,["-v","quiet","-print_format","json","-show_format","-show_streams",t]),r=JSON.parse(e).format||{},n=r.tags||{},a=await hr(t,this.ffprobePath);return a?{filePath:t,type:a.type,duration:parseFloat(r.duration)||0,format:a,title:n.title||n.TITLE,artist:n.artist||n.ARTIST,album:n.album||n.ALBUM,year:n.date||n.DATE||n.year||n.YEAR}:null}catch{return null}}async getPlayableUrl(t,e){const r=await this.transcode(t,e);return r.success&&r.url||null}async cleanupFile(t){const e=this.transcodedFiles.get(t);e&&(await Cr(e),this.transcodedFiles.delete(t)),this.transcodeInfoCache.delete(t)}async cleanup(){await Er(this.tempDir),this.transcodedFiles.clear(),this.transcodeInfoCache.clear()}clearCache(){this.transcodeInfoCache.clear()}};function jr(t){return Dr=new Pr(t)}function kr(){return Dr}function Mr(t){return new Pr(t)}export{r as APP_PROTOCOL_HOST,n as APP_PROTOCOL_PREFIX,e as APP_PROTOCOL_SCHEME,t as FileType,Pr as MediaService,Xe as SqliteThumbnailDatabase,Le as ThumbnailService,Ne as WatchManager,Er as cleanupAllTranscodedFiles,Cr as cleanupTranscodedFile,Je as closeThumbnailDatabase,Tt as compressFiles,nt as copyFiles,oe as copyFilesToClipboard,Ze as createFfmpegVideoProcessor,J as createFile,G as createFolder,Mr as createMediaService,Qe as createSharpImageProcessor,Ve as createSqliteThumbnailDatabase,i as decodeFileUrl,Q as deleteFiles,St as detectArchiveFormat,R as detectIosOnMacApps,wr as detectTranscodeNeeds,a as encodeFileUrl,ut as exists,Dt as extractArchive,v as formatDate,F as formatDateTime,b as formatFileSize,Nt as getAllSystemPaths,N as getApplicationDisplayName,M as getApplicationDisplayNames,De as getApplicationIcon,ce as getClipboardFiles,ae as getFileHash,ct as getFileInfo,w as getFileType,zt as getHomeDirectory,hr as getMediaFormat,kr as getMediaService,dr as getMediaTypeByExtension,At as getPlatform,Ge as getSqliteThumbnailDatabase,Mt as getSystemPath,Be as getThumbnailService,Ae as getWatchManager,jr as initMediaService,Oe as initThumbnailService,s as isAppProtocolUrl,It as isArchiveFile,lt as isDirectory,W as isIosOnMacApp,_ as isMacApplicationsRoot,g as isMediaFile,y as isPreviewable,Vt as listFiles,Gt as listFilesSync,A as listMacApplications,at as moveFiles,bt as openInEditor,yt as openInTerminal,ue as pasteFiles,B as readDirectory,H as readFileContent,q as readImageAsBase64,tt as renameFile,gt as revealInFileManager,Zt as searchFiles,te as searchFilesStream,ee as searchFilesSync,wt as showFileInfo,xr as transcodeMedia,Jt as walkFiles,Me as watchDirectory,V as writeFileContent};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@huyooo/file-explorer-core",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.30",
|
|
4
4
|
"description": "File Explorer Core - File system operations for Node.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
11
|
"types": "./dist/index.d.ts",
|
|
12
|
-
"development": "./src/index.ts",
|
|
13
12
|
"import": "./dist/index.js"
|
|
14
13
|
}
|
|
15
14
|
},
|
|
@@ -25,17 +24,14 @@
|
|
|
25
24
|
"dependencies": {
|
|
26
25
|
"compressing": "^2.0.0",
|
|
27
26
|
"fdir": "^6.5.0",
|
|
28
|
-
"hash-wasm": "^4.12.0"
|
|
27
|
+
"hash-wasm": "^4.12.0",
|
|
28
|
+
"ignore": "^7.0.5"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
31
|
-
"better-sqlite3": ">=9.0.0",
|
|
32
31
|
"ffmpeg-static": ">=5.0.0",
|
|
33
32
|
"sharp": ">=0.33.0"
|
|
34
33
|
},
|
|
35
34
|
"peerDependenciesMeta": {
|
|
36
|
-
"better-sqlite3": {
|
|
37
|
-
"optional": true
|
|
38
|
-
},
|
|
39
35
|
"sharp": {
|
|
40
36
|
"optional": true
|
|
41
37
|
},
|
|
@@ -44,7 +40,6 @@
|
|
|
44
40
|
}
|
|
45
41
|
},
|
|
46
42
|
"devDependencies": {
|
|
47
|
-
"@types/better-sqlite3": "^7.6.0",
|
|
48
43
|
"@types/node": "^22.0.0",
|
|
49
44
|
"terser": "^5.44.1",
|
|
50
45
|
"tsup": "^8.0.0",
|
|
@@ -60,12 +55,6 @@
|
|
|
60
55
|
"author": "huyooo",
|
|
61
56
|
"license": "SEE LICENSE IN LICENSE",
|
|
62
57
|
"publishConfig": {
|
|
63
|
-
"access": "public"
|
|
64
|
-
"exports": {
|
|
65
|
-
".": {
|
|
66
|
-
"types": "./dist/index.d.ts",
|
|
67
|
-
"import": "./dist/index.js"
|
|
68
|
-
}
|
|
69
|
-
}
|
|
58
|
+
"access": "public"
|
|
70
59
|
}
|
|
71
60
|
}
|