@talex-touch/utils 1.0.40 → 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.
- package/.eslintcache +1 -0
- package/__tests__/cloud-sync-sdk.test.ts +442 -0
- package/__tests__/icons/icons.test.ts +84 -0
- package/__tests__/plugin-sdk-lifecycle.test.ts +130 -0
- package/__tests__/power-sdk.test.ts +143 -0
- package/__tests__/preset-export-types.test.ts +108 -0
- package/__tests__/search/fuzzy-match.test.ts +137 -0
- package/__tests__/transport/port-policy.test.ts +44 -0
- package/__tests__/transport-domain-sdks.test.ts +152 -0
- package/__tests__/types/update.test.ts +67 -0
- package/account/account-sdk.ts +915 -0
- package/account/index.ts +2 -0
- package/account/types.ts +321 -0
- package/analytics/client.ts +136 -0
- package/analytics/index.ts +2 -0
- package/analytics/types.ts +156 -0
- package/animation/auto-resize.ts +322 -0
- package/animation/window-node.ts +26 -19
- package/auth/clerk-types.ts +12 -30
- package/auth/index.ts +0 -2
- package/auth/useAuthState.ts +6 -14
- package/base/index.ts +2 -0
- package/base/log-level.ts +105 -0
- package/channel/index.ts +170 -69
- package/cloud-sync/cloud-sync-sdk.ts +450 -0
- package/cloud-sync/index.ts +1 -0
- package/common/file-scan-utils.ts +17 -9
- package/common/index.ts +4 -0
- package/common/logger/index.ts +46 -0
- package/common/logger/logger-manager.ts +303 -0
- package/common/logger/module-logger.ts +270 -0
- package/common/logger/transport-logger.ts +234 -0
- package/common/logger/types.ts +93 -0
- package/common/search/gather.ts +48 -6
- package/common/search/index.ts +8 -0
- package/common/storage/constants.ts +13 -0
- package/common/storage/entity/app-settings.ts +245 -0
- package/common/storage/entity/index.ts +3 -0
- package/common/storage/entity/layout-atom-types.ts +147 -0
- package/common/storage/entity/openers.ts +1 -0
- package/common/storage/entity/preset-cloud-api.ts +132 -0
- package/common/storage/entity/preset-export-types.ts +256 -0
- package/common/storage/entity/shortcut-settings.ts +1 -0
- package/common/storage/shortcut-storage.ts +11 -0
- package/common/utils/clone-diagnostics.ts +105 -0
- package/common/utils/file.ts +16 -8
- package/common/utils/index.ts +6 -2
- package/common/utils/payload-preview.ts +173 -0
- package/common/utils/polling.ts +167 -13
- package/common/utils/safe-path.ts +103 -0
- package/common/utils/safe-shell.ts +115 -0
- package/common/utils/task-queue.ts +4 -1
- package/core-box/builder/tuff-builder.ts +0 -1
- package/core-box/index.ts +1 -1
- package/core-box/recommendation.ts +38 -1
- package/core-box/tuff/tuff-dsl.ts +97 -0
- package/electron/download-manager.ts +10 -7
- package/electron/env-tool.ts +42 -40
- package/electron/index.ts +0 -1
- package/env/index.ts +156 -0
- package/eslint.config.js +55 -0
- package/i18n/index.ts +62 -0
- package/i18n/locales/en.json +226 -0
- package/i18n/locales/zh.json +226 -0
- package/i18n/message-keys.ts +236 -0
- package/i18n/resolver.ts +181 -0
- package/icons/index.ts +257 -0
- package/icons/svg.ts +69 -0
- package/index.ts +9 -1
- package/intelligence/client.ts +72 -42
- package/market/constants.ts +21 -3
- package/market/index.ts +1 -1
- package/market/types.ts +20 -5
- package/package.json +15 -5
- package/permission/index.ts +143 -46
- package/permission/legacy.ts +26 -0
- package/permission/registry.ts +304 -0
- package/permission/types.ts +164 -0
- package/plugin/channel.ts +68 -39
- package/plugin/index.ts +82 -8
- package/plugin/install.ts +3 -0
- package/plugin/log/types.ts +22 -5
- package/plugin/node/logger-manager.ts +11 -3
- package/plugin/node/logger.ts +24 -17
- package/plugin/preload.ts +25 -2
- package/plugin/providers/index.ts +4 -0
- package/plugin/providers/market-client.ts +218 -0
- package/plugin/providers/npm-provider.ts +228 -0
- package/plugin/providers/tpex-provider.ts +297 -0
- package/plugin/providers/tpex-types.ts +34 -0
- package/plugin/sdk/box-items.ts +14 -0
- package/plugin/sdk/box-sdk.ts +64 -0
- package/plugin/sdk/channel.ts +119 -4
- package/plugin/sdk/clipboard.ts +26 -12
- package/plugin/sdk/cloud-sync.ts +113 -0
- package/plugin/sdk/common.ts +19 -11
- package/plugin/sdk/core-box.ts +6 -15
- package/plugin/sdk/division-box.ts +160 -65
- package/plugin/sdk/examples/storage-onDidChange-example.js +5 -2
- package/plugin/sdk/feature-sdk.ts +111 -76
- package/plugin/sdk/flow.ts +146 -45
- package/plugin/sdk/hooks/bridge.ts +113 -49
- package/plugin/sdk/hooks/life-cycle.ts +35 -16
- package/plugin/sdk/index.ts +14 -3
- package/plugin/sdk/intelligence.ts +87 -0
- package/plugin/sdk/meta/README.md +179 -0
- package/plugin/sdk/meta-sdk.ts +244 -0
- package/plugin/sdk/notification.ts +9 -0
- package/plugin/sdk/performance.ts +1 -16
- package/plugin/sdk/plugin-info.ts +64 -0
- package/plugin/sdk/power.ts +155 -0
- package/plugin/sdk/recommend.ts +21 -0
- package/plugin/sdk/service/index.ts +12 -8
- package/plugin/sdk/sqlite.ts +141 -0
- package/plugin/sdk/storage.ts +2 -6
- package/plugin/sdk/system.ts +2 -9
- package/plugin/sdk/temp-files.ts +41 -0
- package/plugin/sdk/touch-sdk.ts +18 -0
- package/plugin/sdk/types.ts +44 -4
- package/plugin/sdk/window/index.ts +12 -9
- package/plugin/sdk-version.ts +231 -0
- package/preload/renderer.ts +3 -2
- package/renderer/hooks/arg-mapper.ts +34 -6
- package/renderer/hooks/index.ts +13 -0
- package/renderer/hooks/initialize.ts +2 -1
- package/renderer/hooks/use-agent-market-sdk.ts +7 -0
- package/renderer/hooks/use-agent-market.ts +106 -0
- package/renderer/hooks/use-agents-sdk.ts +7 -0
- package/renderer/hooks/use-app-sdk.ts +7 -0
- package/renderer/hooks/use-channel.ts +33 -4
- package/renderer/hooks/use-download-sdk.ts +21 -0
- package/renderer/hooks/use-intelligence-sdk.ts +7 -0
- package/renderer/hooks/use-intelligence-stats.ts +290 -0
- package/renderer/hooks/use-intelligence.ts +202 -104
- package/renderer/hooks/use-market-sdk.ts +16 -0
- package/renderer/hooks/use-notification-sdk.ts +7 -0
- package/renderer/hooks/use-permission-sdk.ts +7 -0
- package/renderer/hooks/use-permission.ts +325 -0
- package/renderer/hooks/use-platform-sdk.ts +7 -0
- package/renderer/hooks/use-plugin-sdk.ts +16 -0
- package/renderer/hooks/use-settings-sdk.ts +7 -0
- package/renderer/hooks/use-update-sdk.ts +21 -0
- package/renderer/index.ts +1 -0
- package/renderer/ref.ts +19 -10
- package/renderer/shared/components/SharedPluginDetailContent.vue +84 -0
- package/renderer/shared/components/SharedPluginDetailHeader.vue +116 -0
- package/renderer/shared/components/SharedPluginDetailMetaList.vue +39 -0
- package/renderer/shared/components/SharedPluginDetailReadme.vue +45 -0
- package/renderer/shared/components/SharedPluginDetailVersions.vue +98 -0
- package/renderer/shared/components/index.ts +5 -0
- package/renderer/shared/components/shims-vue.d.ts +5 -0
- package/renderer/shared/index.ts +2 -0
- package/renderer/shared/plugin-detail.ts +62 -0
- package/renderer/storage/app-settings.ts +3 -1
- package/renderer/storage/base-storage.ts +508 -82
- package/renderer/storage/intelligence-storage.ts +37 -46
- package/renderer/storage/openers.ts +3 -1
- package/renderer/storage/storage-subscription.ts +126 -42
- package/renderer/touch-sdk/env.ts +10 -10
- package/renderer/touch-sdk/index.ts +114 -18
- package/renderer/touch-sdk/terminal.ts +24 -13
- package/search/feature-matcher.ts +279 -0
- package/search/fuzzy-match.ts +64 -34
- package/search/index.ts +10 -0
- package/search/levenshtein-utils.ts +17 -11
- package/transport/errors.ts +310 -0
- package/transport/event/builder.ts +378 -0
- package/transport/event/index.ts +7 -0
- package/transport/event/types.ts +292 -0
- package/transport/events/index.ts +2670 -0
- package/transport/events/meta-overlay.ts +79 -0
- package/transport/events/types/agents.ts +177 -0
- package/transport/events/types/app-index.ts +9 -0
- package/transport/events/types/app.ts +475 -0
- package/transport/events/types/box-item.ts +222 -0
- package/transport/events/types/clipboard.ts +80 -0
- package/transport/events/types/core-box.ts +534 -0
- package/transport/events/types/device-idle.ts +7 -0
- package/transport/events/types/division-box.ts +99 -0
- package/transport/events/types/download.ts +115 -0
- package/transport/events/types/file-index.ts +73 -0
- package/transport/events/types/flow.ts +149 -0
- package/transport/events/types/index.ts +70 -0
- package/transport/events/types/market.ts +39 -0
- package/transport/events/types/meta-overlay.ts +184 -0
- package/transport/events/types/notification.ts +140 -0
- package/transport/events/types/permission.ts +90 -0
- package/transport/events/types/platform.ts +8 -0
- package/transport/events/types/plugin.ts +620 -0
- package/transport/events/types/sentry.ts +20 -0
- package/transport/events/types/storage.ts +208 -0
- package/transport/events/types/transport.ts +60 -0
- package/transport/events/types/tray.ts +16 -0
- package/transport/events/types/update.ts +78 -0
- package/transport/index.ts +139 -0
- package/transport/main.ts +2 -0
- package/transport/sdk/constants.ts +29 -0
- package/transport/sdk/domains/agents-market.ts +47 -0
- package/transport/sdk/domains/agents.ts +62 -0
- package/transport/sdk/domains/app.ts +48 -0
- package/transport/sdk/domains/disposable.ts +35 -0
- package/transport/sdk/domains/download.ts +139 -0
- package/transport/sdk/domains/index.ts +13 -0
- package/transport/sdk/domains/intelligence.ts +616 -0
- package/transport/sdk/domains/market.ts +35 -0
- package/transport/sdk/domains/notification.ts +62 -0
- package/transport/sdk/domains/permission.ts +85 -0
- package/transport/sdk/domains/platform.ts +19 -0
- package/transport/sdk/domains/plugin.ts +144 -0
- package/transport/sdk/domains/settings.ts +92 -0
- package/transport/sdk/domains/update.ts +64 -0
- package/transport/sdk/index.ts +60 -0
- package/transport/sdk/main-transport.ts +710 -0
- package/transport/sdk/main.ts +9 -0
- package/transport/sdk/plugin-transport.ts +654 -0
- package/transport/sdk/port-policy.ts +38 -0
- package/transport/sdk/renderer-transport.ts +1165 -0
- package/transport/types.ts +605 -0
- package/types/agent.ts +399 -0
- package/types/cloud-sync.ts +157 -0
- package/types/division-box.ts +47 -27
- package/types/download.ts +1 -0
- package/types/flow.ts +63 -12
- package/types/icon.ts +2 -1
- package/types/index.ts +5 -0
- package/types/intelligence.ts +1492 -81
- package/types/modules/base.ts +2 -0
- package/types/path-browserify.d.ts +5 -0
- package/types/platform.ts +12 -0
- package/types/startup-info.ts +32 -0
- package/types/touch-app-core.ts +8 -8
- package/types/update.ts +94 -1
- package/vitest.config.ts +25 -0
- package/auth/useClerkConfig.ts +0 -40
- package/auth/useClerkProvider.ts +0 -52
package/plugin/sdk/channel.ts
CHANGED
|
@@ -1,12 +1,94 @@
|
|
|
1
|
-
import type { ITouchClientChannel } from '@talex-touch/utils/channel'
|
|
1
|
+
import type { ITouchClientChannel, StandardChannelData } from '@talex-touch/utils/channel'
|
|
2
|
+
import type { ITuffTransport } from '@talex-touch/utils/transport'
|
|
2
3
|
import type { IPluginRendererChannel, PluginChannelHandler } from './types'
|
|
4
|
+
import { ChannelType, DataCode } from '@talex-touch/utils/channel'
|
|
5
|
+
import { hasWindow } from '@talex-touch/utils/env'
|
|
6
|
+
import { defineRawEvent } from '@talex-touch/utils/transport/event/builder'
|
|
3
7
|
import { genChannel } from '../channel'
|
|
4
8
|
|
|
5
9
|
const ensureClientChannel = (): ITouchClientChannel => genChannel()
|
|
10
|
+
function resolvePluginName(): string | undefined {
|
|
11
|
+
if (!hasWindow()) {
|
|
12
|
+
return undefined
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return (window as { $plugin?: { name?: string } } | undefined)?.$plugin?.name
|
|
16
|
+
}
|
|
17
|
+
function buildStandardChannelEvent(eventName: string, payload: unknown, pluginName: string | undefined, reply: (code: DataCode, data: unknown) => void): StandardChannelData {
|
|
18
|
+
return {
|
|
19
|
+
name: eventName,
|
|
20
|
+
header: {
|
|
21
|
+
status: 'request',
|
|
22
|
+
type: ChannelType.PLUGIN,
|
|
23
|
+
plugin: pluginName,
|
|
24
|
+
},
|
|
25
|
+
code: DataCode.SUCCESS,
|
|
26
|
+
data: payload,
|
|
27
|
+
plugin: pluginName,
|
|
28
|
+
reply,
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function createTransportClientChannel(transport: ITuffTransport, fallback: ITouchClientChannel | null): ITouchClientChannel {
|
|
32
|
+
const handlerMap = new Map<string, Map<(data: StandardChannelData) => any, () => void>>()
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
regChannel: (eventName, callback) => {
|
|
36
|
+
const disposer = transport.on(defineRawEvent(eventName), async (payload) => {
|
|
37
|
+
let replied = false
|
|
38
|
+
let replyData: unknown
|
|
39
|
+
const event = buildStandardChannelEvent(
|
|
40
|
+
eventName,
|
|
41
|
+
payload,
|
|
42
|
+
resolvePluginName(),
|
|
43
|
+
(_code, data) => {
|
|
44
|
+
replied = true
|
|
45
|
+
replyData = data
|
|
46
|
+
},
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
const result = await callback(event)
|
|
50
|
+
return replied ? replyData : result
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
let handlers = handlerMap.get(eventName)
|
|
54
|
+
if (!handlers) {
|
|
55
|
+
handlers = new Map()
|
|
56
|
+
handlerMap.set(eventName, handlers)
|
|
57
|
+
}
|
|
58
|
+
handlers.set(callback, disposer)
|
|
59
|
+
|
|
60
|
+
return () => {
|
|
61
|
+
disposer()
|
|
62
|
+
handlers?.delete(callback)
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
unRegChannel: (eventName, callback) => {
|
|
66
|
+
const disposer = handlerMap.get(eventName)?.get(callback)
|
|
67
|
+
if (!disposer) {
|
|
68
|
+
return false
|
|
69
|
+
}
|
|
70
|
+
disposer()
|
|
71
|
+
handlerMap.get(eventName)?.delete(callback)
|
|
72
|
+
return true
|
|
73
|
+
},
|
|
74
|
+
send: (eventName, arg) => transport.send(defineRawEvent(eventName), arg),
|
|
75
|
+
sendSync: (eventName, arg) => {
|
|
76
|
+
if (fallback?.sendSync) {
|
|
77
|
+
return fallback.sendSync(eventName, arg)
|
|
78
|
+
}
|
|
79
|
+
throw new Error(`[Plugin SDK] sendSync is not supported without legacy channel: ${eventName}`)
|
|
80
|
+
},
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function resolveRendererTransport(): ITuffTransport | null {
|
|
84
|
+
const globalWindow = hasWindow() ? window : undefined
|
|
85
|
+
return globalWindow?.$transport ?? null
|
|
86
|
+
}
|
|
6
87
|
|
|
7
88
|
const DEFAULT_CHANNEL_ERROR = '[Plugin SDK] Channel not available. Make sure this code runs inside a plugin renderer context.'
|
|
8
89
|
|
|
9
90
|
let cachedWindowChannel: ITouchClientChannel | null = null
|
|
91
|
+
let cachedTransportChannel: ITouchClientChannel | null = null
|
|
10
92
|
|
|
11
93
|
/**
|
|
12
94
|
* Ensures that the renderer-side plugin channel (window.$channel) exists and returns it.
|
|
@@ -14,7 +96,16 @@ let cachedWindowChannel: ITouchClientChannel | null = null
|
|
|
14
96
|
* @param errorMessage - Optional custom error message when the channel is unavailable
|
|
15
97
|
*/
|
|
16
98
|
export function ensureRendererChannel(errorMessage = DEFAULT_CHANNEL_ERROR): ITouchClientChannel {
|
|
17
|
-
const globalWindow =
|
|
99
|
+
const globalWindow = hasWindow() ? window : undefined
|
|
100
|
+
const transport = globalWindow?.$transport ?? null
|
|
101
|
+
if (transport) {
|
|
102
|
+
if (!cachedTransportChannel) {
|
|
103
|
+
const fallback = globalWindow?.$channel ?? cachedWindowChannel ?? null
|
|
104
|
+
cachedTransportChannel = createTransportClientChannel(transport, fallback)
|
|
105
|
+
}
|
|
106
|
+
return cachedTransportChannel
|
|
107
|
+
}
|
|
108
|
+
|
|
18
109
|
const channel = globalWindow?.$channel ?? cachedWindowChannel
|
|
19
110
|
|
|
20
111
|
if (!channel) {
|
|
@@ -34,9 +125,13 @@ export function useChannel(errorMessage?: string): ITouchClientChannel {
|
|
|
34
125
|
|
|
35
126
|
export function createPluginRendererChannel(): IPluginRendererChannel {
|
|
36
127
|
const client = ensureClientChannel()
|
|
128
|
+
const transport = resolveRendererTransport()
|
|
37
129
|
|
|
38
130
|
return {
|
|
39
131
|
send(eventName, payload) {
|
|
132
|
+
if (transport) {
|
|
133
|
+
return transport.send(defineRawEvent(eventName), payload)
|
|
134
|
+
}
|
|
40
135
|
return client.send(eventName, payload)
|
|
41
136
|
},
|
|
42
137
|
|
|
@@ -45,7 +140,26 @@ export function createPluginRendererChannel(): IPluginRendererChannel {
|
|
|
45
140
|
},
|
|
46
141
|
|
|
47
142
|
on(eventName, handler) {
|
|
48
|
-
|
|
143
|
+
if (!transport) {
|
|
144
|
+
return client.regChannel(eventName, handler)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return transport.on(defineRawEvent(eventName), async (payload) => {
|
|
148
|
+
let replied = false
|
|
149
|
+
let replyData: unknown
|
|
150
|
+
const event = buildStandardChannelEvent(
|
|
151
|
+
eventName,
|
|
152
|
+
payload,
|
|
153
|
+
resolvePluginName(),
|
|
154
|
+
(_code, data) => {
|
|
155
|
+
replied = true
|
|
156
|
+
replyData = data
|
|
157
|
+
},
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
const result = await handler(event)
|
|
161
|
+
return replied ? replyData : result
|
|
162
|
+
})
|
|
49
163
|
},
|
|
50
164
|
|
|
51
165
|
once(eventName, handler) {
|
|
@@ -55,7 +169,7 @@ export function createPluginRendererChannel(): IPluginRendererChannel {
|
|
|
55
169
|
handler(event)
|
|
56
170
|
}
|
|
57
171
|
|
|
58
|
-
dispose =
|
|
172
|
+
dispose = this.on(eventName, wrapped)
|
|
59
173
|
return dispose
|
|
60
174
|
},
|
|
61
175
|
|
|
@@ -78,5 +192,6 @@ export function usePluginRendererChannel(): IPluginRendererChannel {
|
|
|
78
192
|
declare global {
|
|
79
193
|
interface Window {
|
|
80
194
|
$channel: ITouchClientChannel
|
|
195
|
+
$transport?: ITuffTransport
|
|
81
196
|
}
|
|
82
197
|
}
|
package/plugin/sdk/clipboard.ts
CHANGED
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
import type { PluginClipboardHistoryResponse, PluginClipboardItem, PluginClipboardSearchOptions, PluginClipboardSearchResponse } from './types'
|
|
2
|
-
|
|
3
|
-
function ensurePluginChannel() {
|
|
4
|
-
const channel = (window as any)?.$channel
|
|
5
|
-
if (!channel) {
|
|
6
|
-
throw new Error('[Plugin SDK] Clipboard channel requires plugin renderer context with $channel available.')
|
|
7
|
-
}
|
|
8
|
-
return channel
|
|
9
|
-
}
|
|
2
|
+
import { useChannel } from './channel'
|
|
10
3
|
|
|
11
4
|
function normalizeItem(item: PluginClipboardItem | null): PluginClipboardItem | null {
|
|
12
5
|
if (!item)
|
|
@@ -63,6 +56,11 @@ export interface ClipboardImageResult {
|
|
|
63
56
|
dataUrl: string
|
|
64
57
|
width: number
|
|
65
58
|
height: number
|
|
59
|
+
/**
|
|
60
|
+
* Original image as a local streamable URL (Electron only).
|
|
61
|
+
* Returned when calling `readImage({ preview: false })`.
|
|
62
|
+
*/
|
|
63
|
+
tfileUrl?: string
|
|
66
64
|
}
|
|
67
65
|
|
|
68
66
|
export interface ClipboardCopyAndPasteOptions {
|
|
@@ -117,7 +115,7 @@ export function useClipboardHistory() {
|
|
|
117
115
|
* ```
|
|
118
116
|
*/
|
|
119
117
|
export function useClipboard() {
|
|
120
|
-
const channel =
|
|
118
|
+
const channel = useChannel('[Plugin SDK] Clipboard channel requires plugin renderer context with $channel available.')
|
|
121
119
|
|
|
122
120
|
const history = {
|
|
123
121
|
/**
|
|
@@ -214,7 +212,8 @@ export function useClipboard() {
|
|
|
214
212
|
* ```
|
|
215
213
|
*/
|
|
216
214
|
onDidChange(callback: (item: PluginClipboardItem) => void): () => void {
|
|
217
|
-
return channel.regChannel('core-box:clipboard-change', (
|
|
215
|
+
return channel.regChannel('core-box:clipboard-change', (event) => {
|
|
216
|
+
const data = event?.data
|
|
218
217
|
const item = (data && typeof data === 'object' && 'item' in data ? (data as { item: PluginClipboardItem }).item : data) as PluginClipboardItem
|
|
219
218
|
callback(normalizeItem(item) ?? item)
|
|
220
219
|
})
|
|
@@ -264,8 +263,23 @@ export function useClipboard() {
|
|
|
264
263
|
/**
|
|
265
264
|
* Reads image from clipboard as data URL
|
|
266
265
|
*/
|
|
267
|
-
async readImage(): Promise<ClipboardImageResult | null> {
|
|
268
|
-
return await channel.send('clipboard:read-image')
|
|
266
|
+
async readImage(options?: { preview?: boolean }): Promise<ClipboardImageResult | null> {
|
|
267
|
+
return await channel.send('clipboard:read-image', { preview: options?.preview ?? true })
|
|
268
|
+
},
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Resolves the original image URL for a clipboard history item (streamable via tfile://).
|
|
272
|
+
*
|
|
273
|
+
* @remarks
|
|
274
|
+
* - This avoids transferring large base64 payloads over IPC.
|
|
275
|
+
* - Returns null if the item is not an image or original asset is not available.
|
|
276
|
+
*/
|
|
277
|
+
async getHistoryImageUrl(id: number): Promise<string | null> {
|
|
278
|
+
const res = await channel.send('clipboard:get-image-url', { id })
|
|
279
|
+
if (res && typeof res === 'object' && 'url' in res && typeof (res as any).url === 'string') {
|
|
280
|
+
return (res as any).url as string
|
|
281
|
+
}
|
|
282
|
+
return null
|
|
269
283
|
},
|
|
270
284
|
|
|
271
285
|
/**
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type { CloudSyncSDKOptions as ClientOptions } from '../../cloud-sync/cloud-sync-sdk'
|
|
2
|
+
import { CloudSyncSDK as CloudSyncClientSDK, CloudSyncError } from '../../cloud-sync/cloud-sync-sdk'
|
|
3
|
+
import type { HandshakeResponse, PullResponse, PushResponse, SyncItemInput } from '../../types/cloud-sync'
|
|
4
|
+
import { accountSDK } from '../../account'
|
|
5
|
+
import { ensureRendererChannel } from './channel'
|
|
6
|
+
|
|
7
|
+
export interface CloudSyncSDKOptions {
|
|
8
|
+
baseUrl?: string
|
|
9
|
+
serviceBaseUrl?: string
|
|
10
|
+
fetch?: typeof fetch
|
|
11
|
+
now?: () => number
|
|
12
|
+
syncTokenCache?: { token?: string, expiresAt?: string }
|
|
13
|
+
onSyncTokenUpdate?: (token: string, expiresAt: string) => void
|
|
14
|
+
onHandshake?: (response: HandshakeResponse) => void
|
|
15
|
+
onStepUpRequired?: () => string | null | Promise<string | null>
|
|
16
|
+
formDataFactory?: () => FormData
|
|
17
|
+
channelSend?: (event: string, data?: any) => Promise<any>
|
|
18
|
+
ignoreSyncPreferenceCheck?: boolean
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let accountChannelBound = false
|
|
22
|
+
|
|
23
|
+
function bindAccountChannel(options?: CloudSyncSDKOptions) {
|
|
24
|
+
if (accountChannelBound)
|
|
25
|
+
return
|
|
26
|
+
|
|
27
|
+
if (options?.channelSend) {
|
|
28
|
+
accountSDK.setChannelSend(options.channelSend)
|
|
29
|
+
accountChannelBound = true
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const channel = ensureRendererChannel('[CloudSyncSDK] Channel not available. Make sure this runs in plugin renderer context.')
|
|
34
|
+
accountSDK.setChannelSend(channel.send)
|
|
35
|
+
accountChannelBound = true
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function resolveAuthToken(options?: CloudSyncSDKOptions): Promise<string> {
|
|
39
|
+
bindAccountChannel(options)
|
|
40
|
+
if (!options?.ignoreSyncPreferenceCheck) {
|
|
41
|
+
const syncEnabled = await accountSDK.getSyncEnabled()
|
|
42
|
+
if (!syncEnabled) {
|
|
43
|
+
throw new CloudSyncError(
|
|
44
|
+
'[CloudSyncSDK] Sync is disabled by user preference.',
|
|
45
|
+
403,
|
|
46
|
+
'SYNC_DISABLED'
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const token = await accountSDK.getAuthToken()
|
|
51
|
+
if (!token) {
|
|
52
|
+
throw new Error('[CloudSyncSDK] Auth token is not available. Ensure user is signed in and AccountSDK channel is configured.')
|
|
53
|
+
}
|
|
54
|
+
return token
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function resolveDeviceId(options?: CloudSyncSDKOptions): Promise<string> {
|
|
58
|
+
bindAccountChannel(options)
|
|
59
|
+
const deviceId = await accountSDK.getDeviceId()
|
|
60
|
+
if (!deviceId) {
|
|
61
|
+
throw new Error('[CloudSyncSDK] Device ID is not available. Ensure AccountSDK channel is configured.')
|
|
62
|
+
}
|
|
63
|
+
return deviceId
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export class CloudSyncSDK extends CloudSyncClientSDK {
|
|
67
|
+
constructor(options: CloudSyncSDKOptions = {}) {
|
|
68
|
+
bindAccountChannel(options)
|
|
69
|
+
const clientOptions: ClientOptions = {
|
|
70
|
+
baseUrl: options.baseUrl ?? options.serviceBaseUrl,
|
|
71
|
+
fetch: options.fetch,
|
|
72
|
+
now: options.now,
|
|
73
|
+
syncTokenCache: options.syncTokenCache,
|
|
74
|
+
onSyncTokenUpdate: options.onSyncTokenUpdate,
|
|
75
|
+
onHandshake: options.onHandshake,
|
|
76
|
+
onStepUpRequired: options.onStepUpRequired,
|
|
77
|
+
formDataFactory: options.formDataFactory,
|
|
78
|
+
getAuthToken: () => resolveAuthToken(options),
|
|
79
|
+
getDeviceId: () => resolveDeviceId(options),
|
|
80
|
+
}
|
|
81
|
+
super(clientOptions)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async push(items: SyncItemInput[]): Promise<PushResponse> {
|
|
85
|
+
const response = await super.push(items)
|
|
86
|
+
await accountSDK.recordSyncActivity('push')
|
|
87
|
+
return response
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async pull(params?: { cursor?: number, limit?: number }): Promise<PullResponse> {
|
|
91
|
+
const response = await super.pull(params)
|
|
92
|
+
await accountSDK.recordSyncActivity('pull')
|
|
93
|
+
return response
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
let cachedSDK: CloudSyncSDK | null = null
|
|
98
|
+
|
|
99
|
+
export function createCloudSyncSDK(options?: CloudSyncSDKOptions): CloudSyncSDK {
|
|
100
|
+
return new CloudSyncSDK(options)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function useCloudSyncSDK(options?: CloudSyncSDKOptions): CloudSyncSDK {
|
|
104
|
+
if (!cachedSDK)
|
|
105
|
+
cachedSDK = new CloudSyncSDK(options)
|
|
106
|
+
return cachedSDK
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function resetCloudSyncSDK(): void {
|
|
110
|
+
cachedSDK = null
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export { CloudSyncError }
|
package/plugin/sdk/common.ts
CHANGED
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
* 提供插件SDK的通用功能,包括通信、快捷键等
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { getLogger } from '../../common/logger'
|
|
9
|
+
import { useChannel } from './channel'
|
|
10
|
+
|
|
11
|
+
const sdkLog = getLogger('plugin-sdk')
|
|
9
12
|
|
|
10
13
|
/**
|
|
11
14
|
* Register a shortcut
|
|
@@ -13,16 +16,21 @@ import { genChannel } from '../channel'
|
|
|
13
16
|
* @param func - The trigger function
|
|
14
17
|
* @returns Whether the shortcut is registered successfully
|
|
15
18
|
*/
|
|
16
|
-
export function regShortcut(key: string, func:
|
|
17
|
-
const channel =
|
|
19
|
+
export async function regShortcut(key: string, func: () => void): Promise<boolean> {
|
|
20
|
+
const channel = useChannel('[Plugin SDK] Shortcut registration requires renderer channel.')
|
|
18
21
|
|
|
19
|
-
const res = channel.
|
|
20
|
-
if (res
|
|
22
|
+
const res = await channel.send('shortcon:reg', { key })
|
|
23
|
+
if (typeof res === 'string' || Object.prototype.toString.call(res) === '[object String]')
|
|
21
24
|
throw new Error(String(res))
|
|
22
25
|
if (res === false)
|
|
23
26
|
return false
|
|
24
27
|
|
|
25
|
-
channel.regChannel('shortcon:trigger', ({ data }) =>
|
|
28
|
+
channel.regChannel('shortcon:trigger', ({ data }) => {
|
|
29
|
+
const payload = data as { key?: string, id?: string } | undefined
|
|
30
|
+
const triggerKey = payload?.key ?? payload?.id
|
|
31
|
+
if (triggerKey === key)
|
|
32
|
+
func()
|
|
33
|
+
})
|
|
26
34
|
|
|
27
35
|
return true
|
|
28
36
|
}
|
|
@@ -37,7 +45,7 @@ export async function communicateWithPlugin(
|
|
|
37
45
|
key: string,
|
|
38
46
|
info: any = {},
|
|
39
47
|
): Promise<any> {
|
|
40
|
-
const channel =
|
|
48
|
+
const channel = useChannel('[Plugin SDK] Communication requires renderer channel.')
|
|
41
49
|
|
|
42
50
|
try {
|
|
43
51
|
return await channel.send('index:communicate', {
|
|
@@ -46,7 +54,7 @@ export async function communicateWithPlugin(
|
|
|
46
54
|
})
|
|
47
55
|
}
|
|
48
56
|
catch (error) {
|
|
49
|
-
|
|
57
|
+
sdkLog.error('Failed to communicate', { error })
|
|
50
58
|
throw error
|
|
51
59
|
}
|
|
52
60
|
}
|
|
@@ -58,13 +66,13 @@ export async function communicateWithPlugin(
|
|
|
58
66
|
* @returns Promise<any> The message result
|
|
59
67
|
*/
|
|
60
68
|
export async function sendMessage(message: string, data: any = {}): Promise<any> {
|
|
61
|
-
const channel =
|
|
69
|
+
const channel = useChannel('[Plugin SDK] Messaging requires renderer channel.')
|
|
62
70
|
|
|
63
71
|
try {
|
|
64
72
|
return await channel.send(`plugin:${message}`, data)
|
|
65
73
|
}
|
|
66
74
|
catch (error) {
|
|
67
|
-
|
|
75
|
+
sdkLog.error(`Failed to send message: ${message}`, { error })
|
|
68
76
|
throw error
|
|
69
77
|
}
|
|
70
78
|
}
|
|
@@ -75,7 +83,7 @@ export async function sendMessage(message: string, data: any = {}): Promise<any>
|
|
|
75
83
|
* @returns The channel object for the plugin
|
|
76
84
|
*/
|
|
77
85
|
export function getChannel() {
|
|
78
|
-
return
|
|
86
|
+
return useChannel('[Plugin SDK] Channel requires renderer context.')
|
|
79
87
|
}
|
|
80
88
|
|
|
81
89
|
export * from './window'
|
package/plugin/sdk/core-box.ts
CHANGED
|
@@ -1,20 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useChannel } from './channel'
|
|
2
|
+
import { usePluginName } from './plugin-info'
|
|
2
3
|
|
|
3
|
-
function ensurePluginContext(): { channel:
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
throw new Error('[TouchSDK] Unable to resolve plugin name inside renderer context.')
|
|
7
|
-
}
|
|
4
|
+
function ensurePluginContext(): { channel: ReturnType<typeof useChannel>, pluginName: string } {
|
|
5
|
+
const pluginName = usePluginName('[TouchSDK] Unable to resolve plugin name inside renderer context.')
|
|
6
|
+
const channel = useChannel('[TouchSDK] Channel bridge is not available for the current plugin renderer.')
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
if (!channel) {
|
|
11
|
-
throw new Error('[TouchSDK] Channel bridge is not available for the current plugin renderer.')
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
return {
|
|
15
|
-
channel,
|
|
16
|
-
pluginName: plugin.name as string,
|
|
17
|
-
}
|
|
8
|
+
return { channel, pluginName }
|
|
18
9
|
}
|
|
19
10
|
|
|
20
11
|
/**
|