@talex-touch/utils 1.0.42 → 1.0.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (233) hide show
  1. package/.eslintcache +1 -0
  2. package/__tests__/cloud-sync-sdk.test.ts +442 -0
  3. package/__tests__/icons/icons.test.ts +84 -0
  4. package/__tests__/plugin-sdk-lifecycle.test.ts +130 -0
  5. package/__tests__/power-sdk.test.ts +143 -0
  6. package/__tests__/preset-export-types.test.ts +108 -0
  7. package/__tests__/search/fuzzy-match.test.ts +137 -0
  8. package/__tests__/transport/port-policy.test.ts +44 -0
  9. package/__tests__/transport-domain-sdks.test.ts +152 -0
  10. package/__tests__/types/update.test.ts +67 -0
  11. package/account/account-sdk.ts +915 -0
  12. package/account/index.ts +2 -0
  13. package/account/types.ts +321 -0
  14. package/analytics/client.ts +136 -0
  15. package/analytics/index.ts +2 -0
  16. package/analytics/types.ts +156 -0
  17. package/animation/auto-resize.ts +322 -0
  18. package/animation/window-node.ts +26 -19
  19. package/auth/clerk-types.ts +12 -30
  20. package/auth/index.ts +0 -2
  21. package/auth/useAuthState.ts +6 -14
  22. package/base/index.ts +2 -0
  23. package/base/log-level.ts +105 -0
  24. package/channel/index.ts +170 -69
  25. package/cloud-sync/cloud-sync-sdk.ts +450 -0
  26. package/cloud-sync/index.ts +1 -0
  27. package/common/file-scan-utils.ts +17 -9
  28. package/common/index.ts +4 -0
  29. package/common/logger/index.ts +46 -0
  30. package/common/logger/logger-manager.ts +303 -0
  31. package/common/logger/module-logger.ts +270 -0
  32. package/common/logger/transport-logger.ts +234 -0
  33. package/common/logger/types.ts +93 -0
  34. package/common/search/gather.ts +48 -6
  35. package/common/search/index.ts +8 -0
  36. package/common/storage/constants.ts +13 -0
  37. package/common/storage/entity/app-settings.ts +245 -0
  38. package/common/storage/entity/index.ts +3 -0
  39. package/common/storage/entity/layout-atom-types.ts +147 -0
  40. package/common/storage/entity/openers.ts +1 -0
  41. package/common/storage/entity/preset-cloud-api.ts +132 -0
  42. package/common/storage/entity/preset-export-types.ts +256 -0
  43. package/common/storage/entity/shortcut-settings.ts +1 -0
  44. package/common/storage/shortcut-storage.ts +11 -0
  45. package/common/utils/clone-diagnostics.ts +105 -0
  46. package/common/utils/file.ts +16 -8
  47. package/common/utils/index.ts +6 -2
  48. package/common/utils/payload-preview.ts +173 -0
  49. package/common/utils/polling.ts +167 -13
  50. package/common/utils/safe-path.ts +103 -0
  51. package/common/utils/safe-shell.ts +115 -0
  52. package/common/utils/task-queue.ts +4 -1
  53. package/core-box/builder/tuff-builder.ts +0 -1
  54. package/core-box/index.ts +1 -1
  55. package/core-box/recommendation.ts +38 -1
  56. package/core-box/tuff/tuff-dsl.ts +32 -0
  57. package/electron/download-manager.ts +10 -7
  58. package/electron/env-tool.ts +42 -40
  59. package/electron/index.ts +0 -1
  60. package/env/index.ts +156 -0
  61. package/eslint.config.js +55 -0
  62. package/i18n/index.ts +62 -0
  63. package/i18n/locales/en.json +226 -0
  64. package/i18n/locales/zh.json +226 -0
  65. package/i18n/message-keys.ts +236 -0
  66. package/i18n/resolver.ts +181 -0
  67. package/icons/index.ts +257 -0
  68. package/icons/svg.ts +69 -0
  69. package/index.ts +9 -1
  70. package/intelligence/client.ts +72 -42
  71. package/market/constants.ts +9 -5
  72. package/market/index.ts +1 -1
  73. package/market/types.ts +19 -4
  74. package/package.json +15 -5
  75. package/permission/index.ts +143 -46
  76. package/permission/legacy.ts +26 -0
  77. package/permission/registry.ts +304 -0
  78. package/permission/types.ts +164 -0
  79. package/plugin/channel.ts +68 -39
  80. package/plugin/index.ts +80 -7
  81. package/plugin/install.ts +3 -0
  82. package/plugin/log/types.ts +22 -5
  83. package/plugin/node/logger-manager.ts +11 -3
  84. package/plugin/node/logger.ts +24 -17
  85. package/plugin/preload.ts +25 -2
  86. package/plugin/providers/index.ts +4 -4
  87. package/plugin/providers/market-client.ts +6 -3
  88. package/plugin/providers/npm-provider.ts +22 -7
  89. package/plugin/providers/tpex-provider.ts +22 -8
  90. package/plugin/sdk/box-items.ts +14 -0
  91. package/plugin/sdk/box-sdk.ts +64 -0
  92. package/plugin/sdk/channel.ts +119 -4
  93. package/plugin/sdk/clipboard.ts +26 -12
  94. package/plugin/sdk/cloud-sync.ts +113 -0
  95. package/plugin/sdk/common.ts +19 -11
  96. package/plugin/sdk/core-box.ts +6 -15
  97. package/plugin/sdk/division-box.ts +160 -65
  98. package/plugin/sdk/examples/storage-onDidChange-example.js +5 -2
  99. package/plugin/sdk/feature-sdk.ts +111 -76
  100. package/plugin/sdk/flow.ts +146 -45
  101. package/plugin/sdk/hooks/bridge.ts +13 -6
  102. package/plugin/sdk/hooks/life-cycle.ts +35 -16
  103. package/plugin/sdk/index.ts +14 -3
  104. package/plugin/sdk/intelligence.ts +87 -0
  105. package/plugin/sdk/meta/README.md +179 -0
  106. package/plugin/sdk/meta-sdk.ts +244 -0
  107. package/plugin/sdk/notification.ts +9 -0
  108. package/plugin/sdk/plugin-info.ts +64 -0
  109. package/plugin/sdk/power.ts +155 -0
  110. package/plugin/sdk/recommend.ts +21 -0
  111. package/plugin/sdk/service/index.ts +12 -8
  112. package/plugin/sdk/sqlite.ts +141 -0
  113. package/plugin/sdk/storage.ts +2 -6
  114. package/plugin/sdk/system.ts +2 -9
  115. package/plugin/sdk/temp-files.ts +41 -0
  116. package/plugin/sdk/touch-sdk.ts +18 -0
  117. package/plugin/sdk/types.ts +44 -4
  118. package/plugin/sdk/window/index.ts +12 -9
  119. package/plugin/sdk-version.ts +231 -0
  120. package/preload/renderer.ts +3 -2
  121. package/renderer/hooks/arg-mapper.ts +16 -2
  122. package/renderer/hooks/index.ts +13 -0
  123. package/renderer/hooks/initialize.ts +2 -1
  124. package/renderer/hooks/use-agent-market-sdk.ts +7 -0
  125. package/renderer/hooks/use-agent-market.ts +106 -0
  126. package/renderer/hooks/use-agents-sdk.ts +7 -0
  127. package/renderer/hooks/use-app-sdk.ts +7 -0
  128. package/renderer/hooks/use-channel.ts +33 -4
  129. package/renderer/hooks/use-download-sdk.ts +21 -0
  130. package/renderer/hooks/use-intelligence-sdk.ts +7 -0
  131. package/renderer/hooks/use-intelligence-stats.ts +290 -0
  132. package/renderer/hooks/use-intelligence.ts +55 -214
  133. package/renderer/hooks/use-market-sdk.ts +16 -0
  134. package/renderer/hooks/use-notification-sdk.ts +7 -0
  135. package/renderer/hooks/use-permission-sdk.ts +7 -0
  136. package/renderer/hooks/use-permission.ts +325 -0
  137. package/renderer/hooks/use-platform-sdk.ts +7 -0
  138. package/renderer/hooks/use-plugin-sdk.ts +16 -0
  139. package/renderer/hooks/use-settings-sdk.ts +7 -0
  140. package/renderer/hooks/use-update-sdk.ts +21 -0
  141. package/renderer/index.ts +1 -0
  142. package/renderer/ref.ts +19 -10
  143. package/renderer/shared/components/SharedPluginDetailContent.vue +84 -0
  144. package/renderer/shared/components/SharedPluginDetailHeader.vue +116 -0
  145. package/renderer/shared/components/SharedPluginDetailMetaList.vue +39 -0
  146. package/renderer/shared/components/SharedPluginDetailReadme.vue +45 -0
  147. package/renderer/shared/components/SharedPluginDetailVersions.vue +98 -0
  148. package/renderer/shared/components/index.ts +5 -0
  149. package/renderer/shared/components/shims-vue.d.ts +5 -0
  150. package/renderer/shared/index.ts +2 -0
  151. package/renderer/shared/plugin-detail.ts +62 -0
  152. package/renderer/storage/app-settings.ts +3 -1
  153. package/renderer/storage/base-storage.ts +508 -82
  154. package/renderer/storage/intelligence-storage.ts +31 -40
  155. package/renderer/storage/openers.ts +3 -1
  156. package/renderer/storage/storage-subscription.ts +126 -42
  157. package/renderer/touch-sdk/env.ts +10 -10
  158. package/renderer/touch-sdk/index.ts +114 -18
  159. package/renderer/touch-sdk/terminal.ts +24 -13
  160. package/search/feature-matcher.ts +279 -0
  161. package/search/fuzzy-match.ts +64 -34
  162. package/search/index.ts +10 -0
  163. package/search/levenshtein-utils.ts +17 -11
  164. package/transport/errors.ts +310 -0
  165. package/transport/event/builder.ts +378 -0
  166. package/transport/event/index.ts +7 -0
  167. package/transport/event/types.ts +292 -0
  168. package/transport/events/index.ts +2670 -0
  169. package/transport/events/meta-overlay.ts +79 -0
  170. package/transport/events/types/agents.ts +177 -0
  171. package/transport/events/types/app-index.ts +9 -0
  172. package/transport/events/types/app.ts +475 -0
  173. package/transport/events/types/box-item.ts +222 -0
  174. package/transport/events/types/clipboard.ts +80 -0
  175. package/transport/events/types/core-box.ts +534 -0
  176. package/transport/events/types/device-idle.ts +7 -0
  177. package/transport/events/types/division-box.ts +99 -0
  178. package/transport/events/types/download.ts +115 -0
  179. package/transport/events/types/file-index.ts +73 -0
  180. package/transport/events/types/flow.ts +149 -0
  181. package/transport/events/types/index.ts +70 -0
  182. package/transport/events/types/market.ts +39 -0
  183. package/transport/events/types/meta-overlay.ts +184 -0
  184. package/transport/events/types/notification.ts +140 -0
  185. package/transport/events/types/permission.ts +90 -0
  186. package/transport/events/types/platform.ts +8 -0
  187. package/transport/events/types/plugin.ts +620 -0
  188. package/transport/events/types/sentry.ts +20 -0
  189. package/transport/events/types/storage.ts +208 -0
  190. package/transport/events/types/transport.ts +60 -0
  191. package/transport/events/types/tray.ts +16 -0
  192. package/transport/events/types/update.ts +78 -0
  193. package/transport/index.ts +139 -0
  194. package/transport/main.ts +2 -0
  195. package/transport/sdk/constants.ts +29 -0
  196. package/transport/sdk/domains/agents-market.ts +47 -0
  197. package/transport/sdk/domains/agents.ts +62 -0
  198. package/transport/sdk/domains/app.ts +48 -0
  199. package/transport/sdk/domains/disposable.ts +35 -0
  200. package/transport/sdk/domains/download.ts +139 -0
  201. package/transport/sdk/domains/index.ts +13 -0
  202. package/transport/sdk/domains/intelligence.ts +616 -0
  203. package/transport/sdk/domains/market.ts +35 -0
  204. package/transport/sdk/domains/notification.ts +62 -0
  205. package/transport/sdk/domains/permission.ts +85 -0
  206. package/transport/sdk/domains/platform.ts +19 -0
  207. package/transport/sdk/domains/plugin.ts +144 -0
  208. package/transport/sdk/domains/settings.ts +92 -0
  209. package/transport/sdk/domains/update.ts +64 -0
  210. package/transport/sdk/index.ts +60 -0
  211. package/transport/sdk/main-transport.ts +710 -0
  212. package/transport/sdk/main.ts +9 -0
  213. package/transport/sdk/plugin-transport.ts +654 -0
  214. package/transport/sdk/port-policy.ts +38 -0
  215. package/transport/sdk/renderer-transport.ts +1165 -0
  216. package/transport/types.ts +605 -0
  217. package/types/agent.ts +399 -0
  218. package/types/cloud-sync.ts +157 -0
  219. package/types/division-box.ts +31 -31
  220. package/types/download.ts +1 -0
  221. package/types/flow.ts +63 -12
  222. package/types/icon.ts +2 -1
  223. package/types/index.ts +5 -0
  224. package/types/intelligence.ts +166 -173
  225. package/types/modules/base.ts +2 -0
  226. package/types/path-browserify.d.ts +5 -0
  227. package/types/platform.ts +12 -0
  228. package/types/startup-info.ts +32 -0
  229. package/types/touch-app-core.ts +8 -8
  230. package/types/update.ts +94 -1
  231. package/vitest.config.ts +25 -0
  232. package/auth/useClerkConfig.ts +0 -40
  233. package/auth/useClerkProvider.ts +0 -52
@@ -1,20 +1,23 @@
1
- import type { IntelligenceProviderConfig, AISDKGlobalConfig, AISDKStorageData } from '../../types/intelligence'
1
+ import type {
2
+ IntelligenceGlobalConfig,
3
+ IntelligenceProviderConfig,
4
+ IntelligenceStorageData,
5
+ } from '../../types/intelligence'
6
+ import { getLogger } from '../../common/logger'
2
7
  import { StorageList } from '../../common/storage/constants'
3
8
  import {
4
-
5
- IntelligenceProviderType,
6
-
7
9
  DEFAULT_CAPABILITIES,
8
10
  DEFAULT_GLOBAL_CONFIG,
9
11
  DEFAULT_PROVIDERS,
12
+ IntelligenceProviderType,
10
13
  } from '../../types/intelligence'
11
- import { createStorageProxy, TouchStorage } from './base-storage'
14
+ import { createStorageDataProxy, createStorageProxy, TouchStorage } from './base-storage'
12
15
 
13
16
  // Re-export types for convenience
14
17
  export { IntelligenceProviderType }
15
- export type { IntelligenceProviderConfig, AISDKGlobalConfig }
18
+ export type { IntelligenceGlobalConfig, IntelligenceProviderConfig }
16
19
 
17
- const defaultIntelligenceData: AISDKStorageData = {
20
+ const defaultIntelligenceData: IntelligenceStorageData = {
18
21
  providers: [...DEFAULT_PROVIDERS],
19
22
  globalConfig: { ...DEFAULT_GLOBAL_CONFIG },
20
23
  capabilities: { ...DEFAULT_CAPABILITIES },
@@ -22,8 +25,9 @@ const defaultIntelligenceData: AISDKStorageData = {
22
25
  }
23
26
 
24
27
  const INTELLIGENCE_STORAGE_KEY = `storage:${StorageList.IntelligenceConfig}`
28
+ const intelligenceStorageLog = getLogger('intelligence-storage')
25
29
 
26
- class IntelligenceStorage extends TouchStorage<AISDKStorageData> {
30
+ class IntelligenceStorage extends TouchStorage<IntelligenceStorageData> {
27
31
  constructor() {
28
32
  super(StorageList.IntelligenceConfig, defaultIntelligenceData)
29
33
  this.setAutoSave(true)
@@ -50,8 +54,11 @@ class IntelligenceStorage extends TouchStorage<AISDKStorageData> {
50
54
 
51
55
  if (providerIndex !== -1) {
52
56
  const updatedProviders = [...currentData.providers]
57
+ const currentProvider = updatedProviders[providerIndex]
58
+ if (!currentProvider)
59
+ return
53
60
  updatedProviders[providerIndex] = {
54
- ...updatedProviders[providerIndex],
61
+ ...currentProvider,
55
62
  ...updatedProvider,
56
63
  }
57
64
 
@@ -78,7 +85,7 @@ class IntelligenceStorage extends TouchStorage<AISDKStorageData> {
78
85
  /**
79
86
  * 更新全局配置
80
87
  */
81
- updateGlobalConfig(config: Partial<AISDKGlobalConfig>): void {
88
+ updateGlobalConfig(config: Partial<IntelligenceGlobalConfig>): void {
82
89
  const currentData = this.get()
83
90
 
84
91
  this.set({
@@ -129,25 +136,19 @@ export const intelligenceStorage = createStorageProxy<IntelligenceStorage>(
129
136
  () => new IntelligenceStorage(),
130
137
  )
131
138
 
132
- /**
133
- * Alias for backward compatibility
134
- * @deprecated Use intelligenceStorage instead
135
- */
136
- export const aisdkStorage = intelligenceStorage
139
+ export const intelligenceData = createStorageDataProxy(intelligenceStorage)
137
140
 
138
- /**
139
- * Alias for backward compatibility
140
- * @deprecated Use intelligenceStorage instead
141
- */
142
141
  export const intelligenceSettings = intelligenceStorage
143
142
 
143
+ export const intelligenceSettingsData = intelligenceData
144
+
144
145
  export async function migrateIntelligenceSettings(): Promise<void> {
145
- console.log('[Intelligence Storage] Starting migration check...')
146
+ intelligenceStorageLog.info('Starting migration check...')
146
147
  const currentData = intelligenceStorage.data
147
148
 
148
149
  // Version 2: Force update capabilities to include all new ones
149
150
  if (!currentData.version || currentData.version < 2) {
150
- console.log('[Intelligence Storage] Migrating settings to version 2')
151
+ intelligenceStorageLog.info('Migrating settings to version 2')
151
152
 
152
153
  const migratedProviders = currentData.providers.map(provider => ({
153
154
  ...provider,
@@ -163,7 +164,7 @@ export async function migrateIntelligenceSettings(): Promise<void> {
163
164
  const normalizedStrategy
164
165
  = storedStrategy === 'priority' ? 'rule-based-default' : storedStrategy ?? 'adaptive-default'
165
166
 
166
- const migratedGlobalConfig: AISDKGlobalConfig = {
167
+ const migratedGlobalConfig: IntelligenceGlobalConfig = {
167
168
  defaultStrategy: normalizedStrategy,
168
169
  enableAudit: currentData.globalConfig?.enableAudit ?? false,
169
170
  enableCache: currentData.globalConfig?.enableCache ?? true,
@@ -171,8 +172,8 @@ export async function migrateIntelligenceSettings(): Promise<void> {
171
172
  }
172
173
 
173
174
  // Force update to latest DEFAULT_CAPABILITIES (version 2)
174
- console.log('[Intelligence Storage] Updating capabilities to latest defaults')
175
-
175
+ intelligenceStorageLog.info('Updating capabilities to latest defaults')
176
+
176
177
  intelligenceStorage.applyData({
177
178
  providers: migratedProviders,
178
179
  globalConfig: migratedGlobalConfig,
@@ -182,23 +183,18 @@ export async function migrateIntelligenceSettings(): Promise<void> {
182
183
 
183
184
  await intelligenceStorage.saveToRemote({ force: true })
184
185
 
185
- console.log('[Intelligence Storage] Migration to v2 complete, capabilities count:', Object.keys(DEFAULT_CAPABILITIES).length)
186
+ intelligenceStorageLog.info(`Migration to v2 complete, capabilities count: ${Object.keys(DEFAULT_CAPABILITIES).length}`)
186
187
  }
187
188
  else {
188
- console.log('[Intelligence Storage] No migration needed, current version:', currentData.version)
189
+ intelligenceStorageLog.info(`No migration needed, current version: ${currentData.version}`)
189
190
  }
190
191
 
191
- console.log('[Intelligence Storage] Final providers count:', intelligenceStorage.data.providers.length)
192
- console.log('[Intelligence Storage] Final capabilities count:', Object.keys(intelligenceStorage.data.capabilities).length)
192
+ intelligenceStorageLog.info(`Final providers count: ${intelligenceStorage.data.providers.length}`)
193
+ intelligenceStorageLog.info(`Final capabilities count: ${Object.keys(intelligenceStorage.data.capabilities).length}`)
193
194
  }
194
195
 
195
- /**
196
- * @deprecated Use migrateIntelligenceSettings instead
197
- */
198
- export const migrateAISDKSettings = migrateIntelligenceSettings
199
-
200
196
  export async function resetIntelligenceConfig(): Promise<void> {
201
- console.log('[Intelligence Storage] Resetting to default configuration')
197
+ intelligenceStorageLog.info('Resetting to default configuration')
202
198
 
203
199
  intelligenceStorage.applyData({
204
200
  providers: [...DEFAULT_PROVIDERS],
@@ -209,10 +205,5 @@ export async function resetIntelligenceConfig(): Promise<void> {
209
205
 
210
206
  await intelligenceStorage.saveToRemote({ force: true })
211
207
 
212
- console.log('[Intelligence Storage] Reset complete')
208
+ intelligenceStorageLog.info('Reset complete')
213
209
  }
214
-
215
- /**
216
- * @deprecated Use resetIntelligenceConfig instead
217
- */
218
- export const resetAISDKConfig = resetIntelligenceConfig
@@ -1,6 +1,6 @@
1
1
  import type { OpenersMap } from '../..'
2
2
  import { openersOriginData, StorageList } from '../..'
3
- import { createStorageProxy, TouchStorage } from './base-storage'
3
+ import { createStorageDataProxy, createStorageProxy, TouchStorage } from './base-storage'
4
4
 
5
5
  class OpenersStorage extends TouchStorage<OpenersMap> {
6
6
  constructor() {
@@ -19,3 +19,5 @@ export const openersStorage = createStorageProxy<OpenersStorage>(
19
19
  OPENERS_STORAGE_KEY,
20
20
  () => new OpenersStorage(),
21
21
  )
22
+
23
+ export const openersData = createStorageDataProxy(openersStorage)
@@ -1,4 +1,8 @@
1
+ import type { ITuffTransport } from '../../transport'
2
+ import type { StorageUpdateNotification } from '../../transport/events/types'
1
3
  import type { IStorageChannel } from './base-storage'
4
+ import { defineRawEvent } from '../../transport/event/builder'
5
+ import { StorageEvents } from '../../transport/events'
2
6
 
3
7
  /**
4
8
  * Storage subscription callback type
@@ -11,34 +15,68 @@ export type StorageSubscriptionCallback = (data: any) => void
11
15
  */
12
16
  class StorageSubscriptionManager {
13
17
  private channel: IStorageChannel | null = null
18
+ private transport: ITuffTransport | null = null
14
19
  private subscribers = new Map<string, Set<StorageSubscriptionCallback>>()
15
20
  private channelListenerRegistered = false
16
21
  private pendingUpdates = new Map<string, NodeJS.Timeout>()
17
22
  private configVersions = new Map<string, number>()
23
+ private cachedData = new Map<string, unknown>()
18
24
 
19
25
  /**
20
26
  * Initialize the subscription manager with a channel
21
27
  */
22
- init(channel: IStorageChannel): void {
23
- this.channel = channel
28
+ init(channel?: IStorageChannel, transport?: ITuffTransport): void {
29
+ if (channel) {
30
+ this.channel = channel
31
+ }
32
+ if (transport) {
33
+ this.transport = transport
34
+ }
24
35
 
25
36
  if (!this.channelListenerRegistered) {
26
- // Listen to storage:update events from main process
27
- this.channel.regChannel('storage:update', ({ data }) => {
28
- const { name, version } = data as { name: string, version?: number }
29
- // Only handle update if version is newer or unknown
30
- const currentVersion = this.configVersions.get(name) ?? 0
31
- if (version === undefined || version > currentVersion) {
32
- if (version !== undefined) {
33
- this.configVersions.set(name, version)
34
- }
35
- this.handleStorageUpdate(name)
36
- }
37
- })
37
+ if (this.transport) {
38
+ this.transport
39
+ .stream(StorageEvents.app.updated, undefined, {
40
+ onData: (payload: StorageUpdateNotification) => {
41
+ this.handleVersionedUpdate(payload.key, payload.version)
42
+ },
43
+ })
44
+ .catch((error) => {
45
+ console.error('[StorageSubscription] Failed to subscribe to storage updates:', error)
46
+ })
47
+
48
+ const legacyStorageUpdateEvent = defineRawEvent<{ name: string; version?: number }, void>(
49
+ StorageEvents.legacy.update.toEventName()
50
+ )
51
+ this.transport.on(legacyStorageUpdateEvent, (payload) => {
52
+ if (!payload || typeof payload !== 'object') return
53
+ const { name, version } = payload as { name?: string; version?: number }
54
+ if (!name) return
55
+ this.handleVersionedUpdate(name, version)
56
+ })
57
+ }
58
+
59
+ if (this.channel) {
60
+ // Listen to storage:update events from main process
61
+ this.channel.regChannel(StorageEvents.legacy.update.toEventName(), ({ data }) => {
62
+ const { name, version } = data as { name: string, version?: number }
63
+ this.handleVersionedUpdate(name, version)
64
+ })
65
+ }
38
66
  this.channelListenerRegistered = true
39
67
  }
40
68
  }
41
69
 
70
+ private handleVersionedUpdate(name: string, version?: number): void {
71
+ const currentVersion = this.configVersions.get(name) ?? 0
72
+ if (version === undefined || version > currentVersion) {
73
+ if (version !== undefined) {
74
+ this.configVersions.set(name, version)
75
+ }
76
+ void this.handleStorageUpdate(name)
77
+ }
78
+ }
79
+
42
80
  /**
43
81
  * Subscribe to storage changes for a specific config
44
82
  * @param configName - The configuration file name (e.g., 'app-setting.ini')
@@ -62,18 +100,51 @@ class StorageSubscriptionManager {
62
100
 
63
101
  this.subscribers.get(configName)!.add(callback)
64
102
 
65
- // Immediately load and call with current data
66
- if (this.channel) {
67
- const currentData = this.channel.sendSync('storage:get', configName)
68
- if (currentData) {
69
- try {
70
- callback(currentData)
71
- }
72
- catch (error) {
73
- console.error(`[StorageSubscription] Callback error for "${configName}":`, error)
74
- }
103
+ const cached = this.cachedData.get(configName)
104
+ if (cached !== undefined) {
105
+ try {
106
+ callback(cached)
107
+ }
108
+ catch (error) {
109
+ console.error(`[StorageSubscription] Callback error for "${configName}":`, error)
75
110
  }
76
111
  }
112
+ else if (this.channel) {
113
+ this.channel
114
+ .send('storage:get', configName)
115
+ .then((data) => {
116
+ if (data === undefined || data === null)
117
+ return
118
+ this.cachedData.set(configName, data)
119
+ try {
120
+ callback(data)
121
+ }
122
+ catch (error) {
123
+ console.error(`[StorageSubscription] Callback error for "${configName}":`, error)
124
+ }
125
+ })
126
+ .catch((error) => {
127
+ console.error(`[StorageSubscription] Failed to load "${configName}":`, error)
128
+ })
129
+ }
130
+ else if (this.transport) {
131
+ this.transport
132
+ .send(StorageEvents.app.get, { key: configName })
133
+ .then((data) => {
134
+ if (data === undefined || data === null)
135
+ return
136
+ this.cachedData.set(configName, data)
137
+ try {
138
+ callback(data)
139
+ }
140
+ catch (error) {
141
+ console.error(`[StorageSubscription] Callback error for "${configName}":`, error)
142
+ }
143
+ })
144
+ .catch((error) => {
145
+ console.error(`[StorageSubscription] Failed to load "${configName}":`, error)
146
+ })
147
+ }
77
148
 
78
149
  // Return unsubscribe function
79
150
  return () => {
@@ -92,6 +163,7 @@ class StorageSubscriptionManager {
92
163
  callbacks.delete(callback)
93
164
  if (callbacks.size === 0) {
94
165
  this.subscribers.delete(configName)
166
+ this.cachedData.delete(configName)
95
167
  }
96
168
  }
97
169
  }
@@ -106,7 +178,7 @@ class StorageSubscriptionManager {
106
178
  return
107
179
  }
108
180
 
109
- if (!this.channel) {
181
+ if (!this.channel && !this.transport) {
110
182
  return
111
183
  }
112
184
 
@@ -117,24 +189,35 @@ class StorageSubscriptionManager {
117
189
  }
118
190
 
119
191
  const timer = setTimeout(async () => {
120
- // Fetch latest data
121
- const data = await this.channel!.send('storage:get', configName)
122
- if (!data) {
123
- this.pendingUpdates.delete(configName)
124
- return
125
- }
192
+ try {
193
+ // Fetch latest data
194
+ const data = this.channel
195
+ ? await this.channel.send('storage:get', configName)
196
+ : await this.transport!.send(StorageEvents.app.get, { key: configName })
126
197
 
127
- // Notify all subscribers
128
- callbacks.forEach((callback) => {
129
- try {
130
- callback(data)
131
- }
132
- catch (error) {
133
- console.error(`[StorageSubscription] Callback error for "${configName}":`, error)
198
+ if (data === undefined || data === null) {
199
+ this.pendingUpdates.delete(configName)
200
+ return
134
201
  }
135
- })
136
202
 
137
- this.pendingUpdates.delete(configName)
203
+ this.cachedData.set(configName, data)
204
+
205
+ // Notify all subscribers
206
+ callbacks.forEach((callback) => {
207
+ try {
208
+ callback(data)
209
+ }
210
+ catch (error) {
211
+ console.error(`[StorageSubscription] Callback error for "${configName}":`, error)
212
+ }
213
+ })
214
+ }
215
+ catch (error) {
216
+ console.error(`[StorageSubscription] Failed to reload "${configName}":`, error)
217
+ }
218
+ finally {
219
+ this.pendingUpdates.delete(configName)
220
+ }
138
221
  }, 50) // 50ms debounce window
139
222
 
140
223
  this.pendingUpdates.set(configName, timer)
@@ -154,6 +237,7 @@ class StorageSubscriptionManager {
154
237
  */
155
238
  clear(): void {
156
239
  this.subscribers.clear()
240
+ this.cachedData.clear()
157
241
  }
158
242
  }
159
243
 
@@ -166,8 +250,8 @@ const subscriptionManager = new StorageSubscriptionManager()
166
250
  *
167
251
  * @param channel - The storage channel
168
252
  */
169
- export function initStorageSubscription(channel: IStorageChannel): void {
170
- subscriptionManager.init(channel)
253
+ export function initStorageSubscription(channel?: IStorageChannel, transport?: ITuffTransport): void {
254
+ subscriptionManager.init(channel, transport)
171
255
  }
172
256
 
173
257
  /**
@@ -1,11 +1,11 @@
1
- import type { ITouchClientChannel } from '@talex-touch/utils/channel'
1
+ import type { ITuffTransport } from '@talex-touch/utils/transport'
2
2
  import { Terminal } from './terminal'
3
3
 
4
4
  export class EnvDetector {
5
- private static channel: ITouchClientChannel
5
+ private static transport: ITuffTransport
6
6
 
7
- public static init(channel: ITouchClientChannel) {
8
- this.channel = channel
7
+ public static init(transport: ITuffTransport) {
8
+ this.transport = transport
9
9
  }
10
10
 
11
11
  private static async checkCommand(
@@ -13,11 +13,11 @@ export class EnvDetector {
13
13
  versionArgs: string = '--version',
14
14
  versionRegex: RegExp = /(\d+\.\d+\.\d+)/,
15
15
  ): Promise<string | false> {
16
- if (!this.channel) {
17
- throw new Error('EnvDetector not initialized. Call EnvDetector.init(channel) first.')
16
+ if (!this.transport) {
17
+ throw new Error('EnvDetector not initialized. Call EnvDetector.init(transport) first.')
18
18
  }
19
19
  return new Promise((resolve) => {
20
- const terminal = new Terminal(this.channel)
20
+ const terminal = new Terminal(this.transport)
21
21
  let output = ''
22
22
  let resolved = false
23
23
 
@@ -68,11 +68,11 @@ export class EnvDetector {
68
68
  }
69
69
 
70
70
  static async getDegit(): Promise<boolean> {
71
- if (!this.channel) {
72
- throw new Error('EnvDetector not initialized. Call EnvDetector.init(channel) first.')
71
+ if (!this.transport) {
72
+ throw new Error('EnvDetector not initialized. Call EnvDetector.init(transport) first.')
73
73
  }
74
74
  return new Promise((resolve) => {
75
- const terminal = new Terminal(this.channel)
75
+ const terminal = new Terminal(this.transport)
76
76
  let receivedOutput = false
77
77
  let resolved = false
78
78
 
@@ -1,7 +1,32 @@
1
1
  import type { ITouchClientChannel } from '@talex-touch/utils/channel'
2
+ import type { ITuffTransport, TuffEvent } from '@talex-touch/utils/transport'
3
+ import { defineRawEvent } from '@talex-touch/utils/transport/event/builder'
4
+
5
+ const legacyCloseEvent = defineRawEvent<void, void>('close')
6
+ const legacyHideEvent = defineRawEvent<void, void>('hide')
7
+ const legacyMinimizeEvent = defineRawEvent<void, void>('minimize')
8
+ const legacyDevToolsEvent = defineRawEvent<void, void>('dev-tools')
9
+ const legacyCwdEvent = defineRawEvent<void, string>('common:cwd')
10
+ const legacyPackageEvent = defineRawEvent<void, any>('get-package')
11
+ const legacyOsEvent = defineRawEvent<void, any>('get-os')
12
+ const legacyFolderOpenEvent = defineRawEvent<FolderOpenOptions, void>('folder:open')
13
+ const legacyExecuteCmdEvent = defineRawEvent<ExecuteCommandOptions, void>('execute:cmd')
14
+ const legacyAppOpenEvent = defineRawEvent<AppOpenOptions, void>('app:open')
15
+ const legacyOpenExternalEvent = defineRawEvent<ExternalUrlOptions, void>('open-external')
16
+ const legacyTempFileCreateEvent = defineRawEvent<TempFileCreateOptions, TempFileCreateResult>(
17
+ 'temp-file:create',
18
+ )
19
+ const legacyTempFileDeleteEvent = defineRawEvent<TempFileDeleteOptions, TempFileDeleteResult>(
20
+ 'temp-file:delete',
21
+ )
22
+ const legacyPluginFolderEvent = defineRawEvent<string, void>('plugin:explorer')
23
+ const legacyPluginDevToolsEvent = defineRawEvent<string, void>('plugin:open-devtools')
24
+ const legacyPluginReloadEvent = defineRawEvent<{ name: string }, void>('reload-plugin')
25
+ const legacyModuleFolderEvent = defineRawEvent<{ name?: string }, void>('module:folder')
2
26
 
3
27
  export interface TouchSDKOptions {
4
- channel: ITouchClientChannel
28
+ transport?: ITuffTransport
29
+ channel?: ITouchClientChannel
5
30
  }
6
31
 
7
32
  export interface FolderOpenOptions {
@@ -21,68 +46,130 @@ export interface ExternalUrlOptions {
21
46
  url: string
22
47
  }
23
48
 
49
+ export interface TempFileCreateOptions {
50
+ namespace: string
51
+ ext?: string
52
+ text?: string
53
+ base64?: string
54
+ prefix?: string
55
+ retentionMs?: number
56
+ }
57
+
58
+ export interface TempFileCreateResult {
59
+ url: string
60
+ sizeBytes: number
61
+ createdAt: number
62
+ }
63
+
64
+ export interface TempFileDeleteOptions {
65
+ url?: string
66
+ path?: string
67
+ }
68
+
69
+ export interface TempFileDeleteResult {
70
+ success: boolean
71
+ }
72
+
24
73
  export class TouchSDK {
25
- private channel: ITouchClientChannel
74
+ private transport: ITuffTransport | null
75
+ private channel: ITouchClientChannel | null
26
76
 
27
77
  constructor(options: TouchSDKOptions) {
28
- this.channel = options.channel
78
+ this.transport = options.transport ?? null
79
+ this.channel = options.channel ?? null
80
+ }
81
+
82
+ private async sendEvent<TReq, TRes>(event: TuffEvent<TReq, TRes>, payload?: TReq): Promise<TRes> {
83
+ if (this.transport) {
84
+ const shouldPassPayload = payload !== undefined
85
+ if (shouldPassPayload) {
86
+ return this.transport.send(event, payload)
87
+ }
88
+ return this.transport.send(event as TuffEvent<void, TRes>)
89
+ }
90
+
91
+ if (this.channel) {
92
+ return this.channel.send(event.toEventName(), payload as any) as Promise<TRes>
93
+ }
94
+
95
+ throw new Error('[TouchSDK] Transport or channel not initialized.')
29
96
  }
30
97
 
31
98
  /**
32
99
  * System Operations
33
100
  */
34
101
  async closeApp(): Promise<void> {
35
- return this.channel.send('close')
102
+ return this.sendEvent(legacyCloseEvent)
36
103
  }
37
104
 
38
105
  async hideApp(): Promise<void> {
39
- return this.channel.send('hide')
106
+ return this.sendEvent(legacyHideEvent)
40
107
  }
41
108
 
42
109
  async minimizeApp(): Promise<void> {
43
- return this.channel.send('minimize')
110
+ return this.sendEvent(legacyMinimizeEvent)
44
111
  }
45
112
 
46
113
  async openDevTools(): Promise<void> {
47
- return this.channel.send('dev-tools')
114
+ return this.sendEvent(legacyDevToolsEvent)
48
115
  }
49
116
 
50
117
  async getCurrentWorkingDirectory(): Promise<string> {
51
- return this.channel.send('common:cwd')
118
+ return this.sendEvent(legacyCwdEvent)
52
119
  }
53
120
 
54
121
  async getPackageInfo(): Promise<any> {
55
- return this.channel.send('get-package')
122
+ return this.sendEvent(legacyPackageEvent)
56
123
  }
57
124
 
58
125
  async getOSInfo(): Promise<any> {
59
- return this.channel.send('get-os')
126
+ return this.sendEvent(legacyOsEvent)
60
127
  }
61
128
 
62
129
  /**
63
130
  * File & Folder Operations
64
131
  */
65
132
  async openFolder(options: FolderOpenOptions): Promise<void> {
66
- return this.channel.send('folder:open', options)
133
+ return this.sendEvent(legacyFolderOpenEvent, options)
67
134
  }
68
135
 
69
136
  async executeCommand(options: ExecuteCommandOptions): Promise<void> {
70
- return this.channel.send('execute:cmd', options)
137
+ return this.sendEvent(legacyExecuteCmdEvent, options)
71
138
  }
72
139
 
73
140
  async openApp(options: AppOpenOptions): Promise<void> {
74
- return this.channel.send('app:open', options)
141
+ return this.sendEvent(legacyAppOpenEvent, options)
75
142
  }
76
143
 
77
144
  async openExternalUrl(options: ExternalUrlOptions): Promise<void> {
78
- return this.channel.send('open-external', options)
145
+ return this.sendEvent(legacyOpenExternalEvent, options)
146
+ }
147
+
148
+ /**
149
+ * Temp file operations
150
+ */
151
+ async createTempFile(options: TempFileCreateOptions): Promise<TempFileCreateResult> {
152
+ return this.sendEvent(legacyTempFileCreateEvent, options)
153
+ }
154
+
155
+ async deleteTempFile(options: TempFileDeleteOptions): Promise<TempFileDeleteResult> {
156
+ return this.sendEvent(legacyTempFileDeleteEvent, options)
79
157
  }
80
158
 
81
159
  /**
82
160
  * Plugin Operations
83
161
  */
84
162
  async openPluginFolder(pluginName: string): Promise<void> {
85
- return this.channel.send('plugin:explorer', pluginName)
163
+ return this.sendEvent(legacyPluginFolderEvent, pluginName)
164
+ }
165
+
166
+ /**
167
+ * Opens the DevTools for a plugin's Surface WebContents
168
+ * @param pluginName - The name of the plugin to open DevTools for
169
+ * @returns Promise that resolves when DevTools is opened
170
+ */
171
+ async openPluginDevTools(pluginName: string): Promise<void> {
172
+ return this.sendEvent(legacyPluginDevToolsEvent, pluginName)
86
173
  }
87
174
 
88
175
  /**
@@ -91,27 +178,36 @@ export class TouchSDK {
91
178
  * @returns Promise that resolves when the reload operation completes
92
179
  */
93
180
  async reloadPlugin(pluginName: string): Promise<void> {
94
- return this.channel.send('reload-plugin', { name: pluginName })
181
+ return this.sendEvent(legacyPluginReloadEvent, { name: pluginName })
95
182
  }
96
183
 
97
184
  /**
98
185
  * Module Operations
99
186
  */
100
187
  async openModuleFolder(moduleName?: string): Promise<void> {
101
- return this.channel.send('module:folder', { name: moduleName })
188
+ return this.sendEvent(legacyModuleFolderEvent, { name: moduleName })
102
189
  }
103
190
 
104
191
  /**
105
192
  * Event Registration
106
193
  */
107
194
  onChannelEvent(eventName: string, callback: (data: any) => void): () => void {
108
- return this.channel.regChannel(eventName, callback)
195
+ if (this.transport) {
196
+ return this.transport.on(defineRawEvent<any, any>(eventName), callback)
197
+ }
198
+ if (this.channel) {
199
+ return this.channel.regChannel(eventName, callback)
200
+ }
201
+ throw new Error('[TouchSDK] Transport or channel not initialized.')
109
202
  }
110
203
 
111
204
  /**
112
205
  * Raw channel access for advanced usage
113
206
  */
114
207
  get rawChannel(): ITouchClientChannel {
208
+ if (!this.channel) {
209
+ throw new Error('[TouchSDK] Channel not initialized.')
210
+ }
115
211
  return this.channel
116
212
  }
117
213
  }