@talex-touch/utils 1.0.29 → 1.0.31

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/renderer/index.ts CHANGED
@@ -3,3 +3,4 @@ export * from './storage'
3
3
  export * from './touch-sdk'
4
4
  export * from './touch-sdk/utils'
5
5
  export * from './hooks'
6
+ export * from '../auth' // Re-export auth for renderer
@@ -32,5 +32,3 @@ class AppSettingsStorage extends TouchStorage<AppSetting> {
32
32
  * Global instance of the application settings
33
33
  */
34
34
  export const appSettings = new AppSettingsStorage();
35
-
36
- console.log(appSettings)
@@ -29,8 +29,14 @@ export interface IStorageChannel extends ITouchClientChannel {
29
29
 
30
30
  let channel: IStorageChannel | null = null;
31
31
 
32
+ /**
33
+ * Queue of initialization callbacks waiting for channel initialization
34
+ */
35
+ const pendingInitializations: Array<() => void> = [];
36
+
32
37
  /**
33
38
  * Initializes the global channel for communication.
39
+ * Processes all pending storage initializations after initialization.
34
40
  *
35
41
  * @example
36
42
  * ```ts
@@ -45,6 +51,14 @@ let channel: IStorageChannel | null = null;
45
51
  */
46
52
  export function initStorageChannel(c: IStorageChannel): void {
47
53
  channel = c;
54
+
55
+ // Process all pending storage initializations
56
+ for (const initFn of pendingInitializations) {
57
+ initFn();
58
+ }
59
+
60
+ // Clear the queue
61
+ pendingInitializations.length = 0;
48
62
  }
49
63
 
50
64
  /**
@@ -64,6 +78,7 @@ export class TouchStorage<T extends object> {
64
78
  #assigning = false;
65
79
  readonly originalData: T;
66
80
  private readonly _onUpdate: Array<() => void> = [];
81
+ #channelInitialized = false;
67
82
 
68
83
  /**
69
84
  * The reactive data exposed to users.
@@ -72,6 +87,7 @@ export class TouchStorage<T extends object> {
72
87
 
73
88
  /**
74
89
  * Creates a new reactive storage instance.
90
+ * If channel is not initialized, the instance will be queued for initialization.
75
91
  *
76
92
  * @param qName Globally unique name for the instance
77
93
  * @param initData Initial data to populate the storage
@@ -86,30 +102,52 @@ export class TouchStorage<T extends object> {
86
102
  if (storages.has(qName)) {
87
103
  throw new Error(`Storage "${qName}" already exists`);
88
104
  }
105
+
106
+ this.#qualifiedName = qName;
107
+ this.originalData = initData;
108
+ this.data = reactive({ ...initData }) as UnwrapNestedRefs<T>;
109
+
110
+ if (onUpdate) this._onUpdate.push(onUpdate);
111
+
112
+ // Register to storages map immediately
113
+ storages.set(qName, this);
114
+
115
+ // Initialize channel-dependent operations
116
+ if (channel) {
117
+ this.#initializeChannel();
118
+ } else {
119
+ // Queue initialization callback for later
120
+ pendingInitializations.push(() => this.#initializeChannel());
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Initialize channel-dependent operations
126
+ */
127
+ #initializeChannel(): void {
128
+ if (this.#channelInitialized) {
129
+ return;
130
+ }
131
+
89
132
  if (!channel) {
90
133
  throw new Error(
91
134
  'TouchStorage: channel is not initialized. Please call initStorageChannel(...) before using.'
92
135
  );
93
136
  }
94
137
 
95
- this.#qualifiedName = qName;
96
- this.originalData = initData;
97
-
98
- // const stored = (channel.sendSync('storage:get', qName) as Partial<T>) || {};
99
- this.data = reactive({ ...initData }) as UnwrapNestedRefs<T>;
100
- this.loadFromRemote()
138
+ this.#channelInitialized = true;
101
139
 
102
- if (onUpdate) this._onUpdate.push(onUpdate);
140
+ // Load data from remote
141
+ this.loadFromRemote();
103
142
 
143
+ // Register update listener
104
144
  channel.regChannel('storage:update', ({ data }) => {
105
145
  const { name } = data!
106
146
 
107
- if (name === qName) {
147
+ if (name === this.#qualifiedName) {
108
148
  this.loadFromRemote()
109
149
  }
110
- })
111
-
112
- storages.set(qName, this);
150
+ });
113
151
  }
114
152
 
115
153
  /**
@@ -313,6 +351,7 @@ export class TouchStorage<T extends object> {
313
351
  }
314
352
  /**
315
353
  * Loads data from remote storage and applies it.
354
+ * If channel is not initialized yet, this method will do nothing.
316
355
  *
317
356
  * @returns The current instance
318
357
  *
@@ -323,11 +362,11 @@ export class TouchStorage<T extends object> {
323
362
  */
324
363
  loadFromRemote(): this {
325
364
  if (!channel) {
326
- throw new Error("TouchStorage: channel not initialized");
365
+ // Channel not initialized yet, data will be loaded when channel is ready
366
+ return this;
327
367
  }
328
368
 
329
369
  const result = channel.sendSync('storage:get', this.#qualifiedName)
330
- console.log("result", result)
331
370
  const parsed = result ? (result as Partial<T>) : {};
332
371
  this.assignData(parsed, true);
333
372
 
package/search/types.ts CHANGED
@@ -16,7 +16,8 @@
16
16
  * @version 1.0.0
17
17
  */
18
18
 
19
- import type { IPluginIcon, IFeatureCommand } from '../plugin';
19
+ import type { IFeatureCommand } from '../plugin';
20
+ import type { ITuffIcon, TuffIconType } from '../types/icon';
20
21
 
21
22
  /**
22
23
  * Search Result Item Interface
@@ -59,9 +60,9 @@ export interface ISearchItem {
59
60
  * Defines how the item's icon should be displayed in the UI.
60
61
  * Supports various icon types including files, remix icons, and data URLs.
61
62
  *
62
- * @see {@link IPluginIcon} for icon configuration options
63
+ * @see {@link ITuffIcon} for icon configuration options
63
64
  */
64
- icon: IPluginIcon;
65
+ icon: ITuffIcon;
65
66
 
66
67
  /**
67
68
  * Whether this item supports push mode functionality
@@ -590,9 +591,8 @@ export function createDataItem(options: {
590
591
  name,
591
592
  desc,
592
593
  icon: {
593
- type: iconType,
594
- value: iconValue,
595
- init: async () => {} // Required by IPluginIcon interface
594
+ type: (iconType === 'remix' || iconType === 'base64' ? 'url' : (iconType === 'file' || iconType === 'emoji' ? iconType : 'emoji')) as TuffIconType,
595
+ value: iconValue
596
596
  },
597
597
  push: false, // Data items don't support push mode
598
598
  names: [name], // Include name in searchable names
@@ -675,7 +675,7 @@ export function createSearchItem(options: {
675
675
  /** Description or subtitle text */
676
676
  desc: string;
677
677
  /** Icon configuration object */
678
- icon: IPluginIcon;
678
+ icon: ITuffIcon;
679
679
  /** Name of the plugin creating this item */
680
680
  pluginName: string;
681
681
  /** Plugin type (defaults to "feature") */
@@ -0,0 +1,162 @@
1
+ // 下载优先级枚举
2
+ export enum DownloadPriority {
3
+ CRITICAL = 100, // 用户手动触发
4
+ HIGH = 80, // 插件安装
5
+ NORMAL = 50, // 应用更新
6
+ LOW = 20, // 资源文件
7
+ BACKGROUND = 10 // 后台预加载
8
+ }
9
+
10
+ // 下载模块枚举
11
+ export enum DownloadModule {
12
+ APP_UPDATE = 'app_update',
13
+ PLUGIN_INSTALL = 'plugin_install',
14
+ RESOURCE_DOWNLOAD = 'resource_download',
15
+ USER_MANUAL = 'user_manual'
16
+ }
17
+
18
+ // 下载状态枚举
19
+ export enum DownloadStatus {
20
+ PENDING = 'pending', // 等待中
21
+ DOWNLOADING = 'downloading', // 下载中
22
+ PAUSED = 'paused', // 已暂停
23
+ COMPLETED = 'completed', // 已完成
24
+ FAILED = 'failed', // 失败
25
+ CANCELLED = 'cancelled' // 已取消
26
+ }
27
+
28
+ // 切片状态枚举
29
+ export enum ChunkStatus {
30
+ PENDING = 'pending',
31
+ DOWNLOADING = 'downloading',
32
+ COMPLETED = 'completed',
33
+ FAILED = 'failed'
34
+ }
35
+
36
+ // 下载任务请求接口
37
+ export interface DownloadRequest {
38
+ id?: string
39
+ url: string
40
+ destination: string
41
+ filename?: string
42
+ priority: DownloadPriority
43
+ module: DownloadModule
44
+ metadata?: Record<string, any>
45
+ checksum?: string
46
+ headers?: Record<string, string>
47
+ }
48
+
49
+ // 下载任务实体
50
+ export interface DownloadTask {
51
+ id: string
52
+ url: string
53
+ destination: string
54
+ filename: string
55
+ priority: DownloadPriority
56
+ module: DownloadModule
57
+ status: DownloadStatus
58
+ progress: DownloadProgress
59
+ chunks: ChunkInfo[]
60
+ metadata: Record<string, any>
61
+ createdAt: Date
62
+ updatedAt: Date
63
+ error?: string
64
+ }
65
+
66
+ // 下载进度接口
67
+ export interface DownloadProgress {
68
+ totalSize?: number
69
+ downloadedSize: number
70
+ speed: number // bytes/s
71
+ remainingTime?: number // seconds
72
+ percentage: number // 0-100
73
+ }
74
+
75
+ // 切片信息接口
76
+ export interface ChunkInfo {
77
+ index: number
78
+ start: number
79
+ end: number
80
+ size: number
81
+ downloaded: number
82
+ status: ChunkStatus
83
+ filePath: string
84
+ }
85
+
86
+ // 下载配置接口
87
+ export interface DownloadConfig {
88
+ concurrency: {
89
+ maxConcurrent: number // 最大并发数 (1-10)
90
+ autoAdjust: boolean // 自动调整
91
+ networkAware: boolean // 网络感知
92
+ priorityBased: boolean // 基于优先级
93
+ }
94
+ chunk: {
95
+ size: number // 切片大小
96
+ resume: boolean // 断点续传
97
+ autoRetry: boolean // 自动重试
98
+ maxRetries: number // 最大重试次数
99
+ }
100
+ storage: {
101
+ tempDir: string // 临时目录
102
+ historyRetention: number // 历史保留天数
103
+ autoCleanup: boolean // 自动清理
104
+ }
105
+ network: {
106
+ timeout: number // 超时时间
107
+ retryDelay: number // 重试延迟
108
+ maxRetries: number // 最大重试次数
109
+ }
110
+ }
111
+
112
+ // 网络状态接口
113
+ export interface NetworkStatus {
114
+ speed: number // bytes/s
115
+ latency: number // ms
116
+ stability: number // 0-1
117
+ recommendedConcurrency: number
118
+ }
119
+
120
+ // 队列状态接口
121
+ export interface QueueStatus {
122
+ totalTasks: number
123
+ pendingTasks: number
124
+ activeTasks: number
125
+ completedTasks: number
126
+ failedTasks: number
127
+ }
128
+
129
+ // 下载统计接口
130
+ export interface DownloadStats {
131
+ totalTasks: number
132
+ completedTasks: number
133
+ failedTasks: number
134
+ totalDownloaded: number
135
+ averageSpeed: number
136
+ }
137
+
138
+ // 默认下载配置
139
+ export const defaultDownloadConfig: DownloadConfig = {
140
+ concurrency: {
141
+ maxConcurrent: 3,
142
+ autoAdjust: true,
143
+ networkAware: true,
144
+ priorityBased: true
145
+ },
146
+ chunk: {
147
+ size: 1024 * 1024, // 1MB
148
+ resume: true,
149
+ autoRetry: true,
150
+ maxRetries: 3
151
+ },
152
+ storage: {
153
+ tempDir: '', // 将在运行时设置
154
+ historyRetention: 30,
155
+ autoCleanup: true
156
+ },
157
+ network: {
158
+ timeout: 30000,
159
+ retryDelay: 5000,
160
+ maxRetries: 3
161
+ }
162
+ }
package/types/icon.ts ADDED
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Icon type definitions
3
+ *
4
+ * @description
5
+ * Defines common icon interfaces and types, supporting emoji, url, and file types
6
+ */
7
+
8
+ /**
9
+ * Icon type enumeration
10
+ * @description
11
+ * - emoji: Emoji characters (e.g., "🚀")
12
+ * - url: Remote URL (http/https) or Data URL (data:image/...)
13
+ * - file: Local file path (relative to plugin root directory)
14
+ * - class: Class name (e.g., "i-ri-rocket-line")
15
+ */
16
+ export type TuffIconType = 'emoji' | 'url' | 'file' | 'class'
17
+
18
+ /**
19
+ * Icon status enumeration
20
+ * @description
21
+ * - normal: Normal state
22
+ * - loading: Loading state
23
+ * - error: Error state
24
+ */
25
+ export type TuffIconStatus = 'normal' | 'loading' | 'error'
26
+
27
+ /**
28
+ * Common icon interface
29
+ *
30
+ * @description
31
+ * Unified icon data structure supporting three icon types and status management
32
+ */
33
+ export interface ITuffIcon {
34
+ /** Icon type */
35
+ type: TuffIconType
36
+
37
+ /** Icon value */
38
+ value: string
39
+
40
+ /** Icon status (optional) */
41
+ status?: TuffIconStatus
42
+
43
+ /** Error message (when status is error) */
44
+ error?: string
45
+ }
package/types/index.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from './touch-app-core'
2
2
  export * from './modules'
3
+ export * from './storage'
@@ -1,4 +1,4 @@
1
- import { ITouchEventBus } from "packages/utils/eventbus";
1
+ import { ITouchEventBus } from "../../eventbus";
2
2
  import { ModuleKey } from ".";
3
3
  import { TalexTouch } from "../touch-app-core";
4
4
  import { ModuleDirectory, ResolvedModuleFileConfig } from "./base";
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Plugin storage statistics
3
+ */
4
+ export interface StorageStats {
5
+ /** Total size in bytes */
6
+ totalSize: number
7
+ /** Number of files (excluding directories) */
8
+ fileCount: number
9
+ /** Number of directories */
10
+ dirCount: number
11
+ /** Maximum size limit in bytes (10MB) */
12
+ maxSize: number
13
+ /** Usage percentage (0-100) */
14
+ usagePercent: number
15
+ }
16
+
17
+ /**
18
+ * Storage tree node representing a file or directory
19
+ */
20
+ export interface StorageTreeNode {
21
+ /** File or directory name */
22
+ name: string
23
+ /** Relative path from storage root */
24
+ path: string
25
+ /** Node type */
26
+ type: 'file' | 'directory'
27
+ /** Size in bytes (for directories, this is the total size of all contained files) */
28
+ size: number
29
+ /** Last modified timestamp */
30
+ modified: number
31
+ /** Child nodes (only for directories) */
32
+ children?: StorageTreeNode[]
33
+ }
34
+
35
+ /**
36
+ * Detailed information about a specific file
37
+ */
38
+ export interface FileDetails {
39
+ /** File name */
40
+ name: string
41
+ /** Relative path from storage root */
42
+ path: string
43
+ /** File size in bytes */
44
+ size: number
45
+ /** Creation timestamp */
46
+ created: number
47
+ /** Last modified timestamp */
48
+ modified: number
49
+ /** File type (extension or detected type) */
50
+ type: string
51
+ /** File content (if available and size permits) */
52
+ content?: any
53
+ /** Whether content was truncated due to size */
54
+ truncated?: boolean
55
+ }
56
+
@@ -0,0 +1,99 @@
1
+ // 更新源类型枚举
2
+ export enum UpdateProviderType {
3
+ GITHUB = 'github',
4
+ OFFICIAL = 'official',
5
+ CUSTOM = 'custom'
6
+ }
7
+
8
+ // 更新源配置接口
9
+ export interface UpdateSourceConfig {
10
+ type: UpdateProviderType
11
+ name: string
12
+ url?: string
13
+ enabled: boolean
14
+ priority: number
15
+ }
16
+
17
+ // 下载资源接口
18
+ export interface DownloadAsset {
19
+ name: string
20
+ url: string
21
+ size: number
22
+ platform: 'win32' | 'darwin' | 'linux'
23
+ arch: 'x64' | 'arm64'
24
+ checksum?: string
25
+ }
26
+
27
+ // GitHub Release接口(兼容GitHub API格式)
28
+ export interface GitHubRelease {
29
+ tag_name: string
30
+ name: string
31
+ published_at: string
32
+ body: string
33
+ assets: DownloadAsset[]
34
+ }
35
+
36
+ // 更新检查结果接口
37
+ export interface UpdateCheckResult {
38
+ hasUpdate: boolean
39
+ release?: GitHubRelease
40
+ error?: string
41
+ source: string
42
+ }
43
+
44
+ // 自定义更新源配置
45
+ export interface CustomUpdateConfig {
46
+ name: string
47
+ url: string
48
+ apiFormat: 'github' | 'custom'
49
+ headers?: Record<string, string>
50
+ }
51
+
52
+ // 应用预览渠道枚举
53
+ export enum AppPreviewChannel {
54
+ MASTER = 'master',
55
+ SNAPSHOT = 'snapshot'
56
+ }
57
+
58
+ // 更新设置配置
59
+ export interface UpdateSettings {
60
+ enabled: boolean
61
+ frequency: 'startup' | 'daily' | 'weekly' | 'manual'
62
+ source: UpdateSourceConfig
63
+ crossChannel: boolean
64
+ ignoredVersions: string[]
65
+ customSources: CustomUpdateConfig[]
66
+ }
67
+
68
+ // 默认更新设置
69
+ export const defaultUpdateSettings: UpdateSettings = {
70
+ enabled: true,
71
+ frequency: 'startup',
72
+ source: {
73
+ type: UpdateProviderType.GITHUB,
74
+ name: 'GitHub Releases',
75
+ url: 'https://api.github.com/repos/talex-touch/tuff/releases',
76
+ enabled: true,
77
+ priority: 1
78
+ },
79
+ crossChannel: false,
80
+ ignoredVersions: [],
81
+ customSources: []
82
+ }
83
+
84
+ // 更新错误类型
85
+ export enum UpdateErrorType {
86
+ NETWORK_ERROR = 'network_error',
87
+ TIMEOUT_ERROR = 'timeout_error',
88
+ API_ERROR = 'api_error',
89
+ PARSE_ERROR = 'parse_error',
90
+ VERSION_ERROR = 'version_error',
91
+ UNKNOWN_ERROR = 'unknown_error'
92
+ }
93
+
94
+ // 更新错误接口
95
+ export interface UpdateError extends Error {
96
+ type: UpdateErrorType
97
+ code?: string
98
+ statusCode?: number
99
+ }