@talex-touch/utils 1.0.34 → 1.0.35
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/package.json +1 -1
- package/plugin/channel.ts +66 -7
- package/plugin/sdk/README.md +5 -1
- package/plugin/sdk/box-sdk.ts +148 -41
- package/plugin/sdk/channel.ts +34 -0
- package/plugin/sdk/division-box.ts +2 -7
- package/plugin/sdk/feature-sdk.ts +3 -7
- package/plugin/sdk/hooks/bridge.ts +3 -1
- package/plugin/sdk/hooks/life-cycle.ts +4 -1
- package/plugin/sdk/storage.ts +2 -1
package/package.json
CHANGED
package/plugin/channel.ts
CHANGED
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
DataCode,
|
|
11
11
|
} from '../channel'
|
|
12
12
|
|
|
13
|
+
const CHANNEL_DEFAULT_TIMEOUT = 10_000
|
|
14
|
+
|
|
13
15
|
let cachedIpcRenderer: IpcRenderer | null = null
|
|
14
16
|
|
|
15
17
|
// 使用惰性解析避免在打包阶段静态引入 electron
|
|
@@ -197,6 +199,19 @@ class TouchChannel implements ITouchClientChannel {
|
|
|
197
199
|
return true
|
|
198
200
|
}
|
|
199
201
|
|
|
202
|
+
private formatPayloadPreview(payload: unknown): string {
|
|
203
|
+
if (payload === null || payload === undefined)
|
|
204
|
+
return String(payload)
|
|
205
|
+
if (typeof payload === 'string')
|
|
206
|
+
return payload.length > 200 ? `${payload.slice(0, 200)}…` : payload
|
|
207
|
+
try {
|
|
208
|
+
return JSON.stringify(payload)
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
return '[unserializable]'
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
200
215
|
send(eventName: string, arg: any): Promise<any> {
|
|
201
216
|
const uniqueId = `${new Date().getTime()}#${eventName}@${Math.random().toString(
|
|
202
217
|
12,
|
|
@@ -207,7 +222,7 @@ class TouchChannel implements ITouchClientChannel {
|
|
|
207
222
|
data: arg,
|
|
208
223
|
sync: {
|
|
209
224
|
timeStamp: new Date().getTime(),
|
|
210
|
-
timeout:
|
|
225
|
+
timeout: CHANNEL_DEFAULT_TIMEOUT,
|
|
211
226
|
id: uniqueId,
|
|
212
227
|
},
|
|
213
228
|
name: eventName,
|
|
@@ -218,10 +233,40 @@ class TouchChannel implements ITouchClientChannel {
|
|
|
218
233
|
},
|
|
219
234
|
} as RawStandardChannelData
|
|
220
235
|
|
|
221
|
-
return new Promise((resolve) => {
|
|
222
|
-
|
|
236
|
+
return new Promise((resolve, reject) => {
|
|
237
|
+
try {
|
|
238
|
+
this.ipcRenderer.send('@plugin-process-message', data)
|
|
239
|
+
}
|
|
240
|
+
catch (error) {
|
|
241
|
+
const errorMessage = error instanceof Error ? error.message : String(error)
|
|
242
|
+
console.error(
|
|
243
|
+
`[PluginChannel] Failed to send "${eventName}": ${errorMessage}`,
|
|
244
|
+
{ payloadPreview: this.formatPayloadPreview(arg) },
|
|
245
|
+
)
|
|
246
|
+
reject(
|
|
247
|
+
Object.assign(
|
|
248
|
+
new Error(`Failed to send plugin channel message "${eventName}": ${errorMessage}`),
|
|
249
|
+
{ code: 'plugin_channel_send_failed' },
|
|
250
|
+
),
|
|
251
|
+
)
|
|
252
|
+
return
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const timeoutMs = data.sync?.timeout ?? CHANNEL_DEFAULT_TIMEOUT
|
|
256
|
+
const timeoutHandle = setTimeout(() => {
|
|
257
|
+
if (!this.pendingMap.has(uniqueId))
|
|
258
|
+
return
|
|
259
|
+
this.pendingMap.delete(uniqueId)
|
|
260
|
+
const timeoutError = Object.assign(
|
|
261
|
+
new Error(`Plugin channel request "${eventName}" timed out after ${timeoutMs}ms`),
|
|
262
|
+
{ code: 'plugin_channel_timeout' },
|
|
263
|
+
)
|
|
264
|
+
console.warn(timeoutError.message)
|
|
265
|
+
reject(timeoutError)
|
|
266
|
+
}, timeoutMs)
|
|
223
267
|
|
|
224
268
|
this.pendingMap.set(uniqueId, (res: any) => {
|
|
269
|
+
clearTimeout(timeoutHandle)
|
|
225
270
|
this.pendingMap.delete(uniqueId)
|
|
226
271
|
|
|
227
272
|
resolve(res.data)
|
|
@@ -241,12 +286,26 @@ class TouchChannel implements ITouchClientChannel {
|
|
|
241
286
|
},
|
|
242
287
|
} as RawStandardChannelData
|
|
243
288
|
|
|
244
|
-
|
|
289
|
+
try {
|
|
290
|
+
const res = this.__parse_raw_data(
|
|
291
|
+
void 0,
|
|
292
|
+
this.ipcRenderer.sendSync('@plugin-process-message', data),
|
|
293
|
+
)!
|
|
245
294
|
|
|
246
|
-
|
|
247
|
-
|
|
295
|
+
if (res.header.status === 'reply')
|
|
296
|
+
return res.data
|
|
248
297
|
|
|
249
|
-
|
|
298
|
+
return res
|
|
299
|
+
}
|
|
300
|
+
catch (error) {
|
|
301
|
+
const errorMessage = error instanceof Error ? error.message : String(error)
|
|
302
|
+
console.error('[PluginChannel] Failed to sendSync message', {
|
|
303
|
+
eventName,
|
|
304
|
+
error: errorMessage,
|
|
305
|
+
payloadPreview: this.formatPayloadPreview(arg),
|
|
306
|
+
})
|
|
307
|
+
throw new Error(`Failed to sendSync plugin channel message "${eventName}": ${errorMessage}`)
|
|
308
|
+
}
|
|
250
309
|
}
|
|
251
310
|
}
|
|
252
311
|
|
package/plugin/sdk/README.md
CHANGED
|
@@ -26,8 +26,10 @@ plugin.box.shrink()
|
|
|
26
26
|
plugin.box.hideInput()
|
|
27
27
|
plugin.box.showInput()
|
|
28
28
|
|
|
29
|
-
//
|
|
29
|
+
// 获取与设置输入
|
|
30
30
|
const input = await plugin.box.getInput()
|
|
31
|
+
await plugin.box.setInput('Hello Touch!')
|
|
32
|
+
await plugin.box.clearInput()
|
|
31
33
|
```
|
|
32
34
|
|
|
33
35
|
### 2. FeatureSDK - 搜索结果管理
|
|
@@ -203,6 +205,8 @@ export default {
|
|
|
203
205
|
- `core-box:hide-input` - 隐藏输入框
|
|
204
206
|
- `core-box:show-input` - 显示输入框
|
|
205
207
|
- `core-box:get-input` - 获取当前输入值
|
|
208
|
+
- `core-box:set-input` - 设置输入框内容
|
|
209
|
+
- `core-box:clear-input` - 清空输入框
|
|
206
210
|
- `core-box:input-changed` - 输入变化广播(主进程 → 插件)
|
|
207
211
|
- `core-box:set-input-visibility` - 设置输入框可见性(主进程 → 渲染进程)
|
|
208
212
|
- `core-box:request-input-value` - 请求输入值(主进程 → 渲染进程)
|
package/plugin/sdk/box-sdk.ts
CHANGED
|
@@ -1,9 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Box SDK for Plugin Development
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Provides a unified API for plugins to control the CoreBox window behavior,
|
|
5
5
|
* including visibility, size, input field control, and input value access.
|
|
6
6
|
*/
|
|
7
|
+
import { ensureRendererChannel } from './channel'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Clipboard content type flags for binary combination
|
|
11
|
+
*/
|
|
12
|
+
export enum ClipboardType {
|
|
13
|
+
TEXT = 0b0001,
|
|
14
|
+
IMAGE = 0b0010,
|
|
15
|
+
FILE = 0b0100,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Preset clipboard type combinations
|
|
20
|
+
*/
|
|
21
|
+
export const ClipboardTypePresets = {
|
|
22
|
+
TEXT_ONLY: ClipboardType.TEXT,
|
|
23
|
+
TEXT_AND_IMAGE: ClipboardType.TEXT | ClipboardType.IMAGE,
|
|
24
|
+
ALL: ClipboardType.TEXT | ClipboardType.IMAGE | ClipboardType.FILE,
|
|
25
|
+
} as const
|
|
7
26
|
|
|
8
27
|
/**
|
|
9
28
|
* Expand options for CoreBox window
|
|
@@ -17,18 +36,18 @@ export interface BoxExpandOptions {
|
|
|
17
36
|
|
|
18
37
|
/**
|
|
19
38
|
* Box SDK interface for plugins
|
|
20
|
-
*
|
|
39
|
+
*
|
|
21
40
|
* @example
|
|
22
41
|
* ```typescript
|
|
23
42
|
* // Hide CoreBox
|
|
24
43
|
* plugin.box.hide()
|
|
25
|
-
*
|
|
44
|
+
*
|
|
26
45
|
* // Show CoreBox
|
|
27
46
|
* plugin.box.show()
|
|
28
|
-
*
|
|
47
|
+
*
|
|
29
48
|
* // Expand to show 10 items
|
|
30
49
|
* plugin.box.expand({ length: 10 })
|
|
31
|
-
*
|
|
50
|
+
*
|
|
32
51
|
* // Get current input
|
|
33
52
|
* const input = plugin.box.getInput()
|
|
34
53
|
* ```
|
|
@@ -36,93 +55,142 @@ export interface BoxExpandOptions {
|
|
|
36
55
|
export interface BoxSDK {
|
|
37
56
|
/**
|
|
38
57
|
* Hides the CoreBox window
|
|
39
|
-
*
|
|
58
|
+
*
|
|
40
59
|
* @example
|
|
41
60
|
* ```typescript
|
|
42
61
|
* plugin.box.hide()
|
|
43
62
|
* ```
|
|
44
63
|
*/
|
|
45
|
-
hide()
|
|
64
|
+
hide: () => void
|
|
46
65
|
|
|
47
66
|
/**
|
|
48
67
|
* Shows the CoreBox window
|
|
49
|
-
*
|
|
68
|
+
*
|
|
50
69
|
* @example
|
|
51
70
|
* ```typescript
|
|
52
71
|
* plugin.box.show()
|
|
53
72
|
* ```
|
|
54
73
|
*/
|
|
55
|
-
show()
|
|
74
|
+
show: () => void
|
|
56
75
|
|
|
57
76
|
/**
|
|
58
77
|
* Expands the CoreBox window
|
|
59
|
-
*
|
|
78
|
+
*
|
|
60
79
|
* @param options - Optional expansion configuration
|
|
61
|
-
*
|
|
80
|
+
*
|
|
62
81
|
* @example
|
|
63
82
|
* ```typescript
|
|
64
83
|
* // Expand to show 10 items
|
|
65
84
|
* plugin.box.expand({ length: 10 })
|
|
66
|
-
*
|
|
85
|
+
*
|
|
67
86
|
* // Force maximum expansion
|
|
68
87
|
* plugin.box.expand({ forceMax: true })
|
|
69
|
-
*
|
|
88
|
+
*
|
|
70
89
|
* // Default expansion
|
|
71
90
|
* plugin.box.expand()
|
|
72
91
|
* ```
|
|
73
92
|
*/
|
|
74
|
-
expand(options?: BoxExpandOptions)
|
|
93
|
+
expand: (options?: BoxExpandOptions) => Promise<void>
|
|
75
94
|
|
|
76
95
|
/**
|
|
77
96
|
* Shrinks the CoreBox window to compact size
|
|
78
|
-
*
|
|
97
|
+
*
|
|
79
98
|
* @example
|
|
80
99
|
* ```typescript
|
|
81
100
|
* plugin.box.shrink()
|
|
82
101
|
* ```
|
|
83
102
|
*/
|
|
84
|
-
shrink()
|
|
103
|
+
shrink: () => Promise<void>
|
|
85
104
|
|
|
86
105
|
/**
|
|
87
106
|
* Hides the input field in CoreBox
|
|
88
|
-
*
|
|
107
|
+
*
|
|
89
108
|
* @example
|
|
90
109
|
* ```typescript
|
|
91
110
|
* plugin.box.hideInput()
|
|
92
111
|
* ```
|
|
93
112
|
*/
|
|
94
|
-
hideInput()
|
|
113
|
+
hideInput: () => Promise<void>
|
|
95
114
|
|
|
96
115
|
/**
|
|
97
116
|
* Shows the input field in CoreBox
|
|
98
|
-
*
|
|
117
|
+
*
|
|
99
118
|
* @example
|
|
100
119
|
* ```typescript
|
|
101
120
|
* plugin.box.showInput()
|
|
102
121
|
* ```
|
|
103
122
|
*/
|
|
104
|
-
showInput()
|
|
123
|
+
showInput: () => Promise<void>
|
|
105
124
|
|
|
106
125
|
/**
|
|
107
126
|
* Gets the current input value from CoreBox search field
|
|
108
|
-
*
|
|
127
|
+
*
|
|
109
128
|
* @returns Promise resolving to the current input string
|
|
110
|
-
*
|
|
129
|
+
*
|
|
111
130
|
* @example
|
|
112
131
|
* ```typescript
|
|
113
132
|
* const input = await plugin.box.getInput()
|
|
114
133
|
* console.log('Current input:', input)
|
|
115
134
|
* ```
|
|
116
135
|
*/
|
|
117
|
-
getInput()
|
|
136
|
+
getInput: () => Promise<string>
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Sets the CoreBox search input to the specified value
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```typescript
|
|
143
|
+
* await plugin.box.setInput('hello world')
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
setInput: (value: string) => Promise<void>
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Clears the CoreBox search input
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ```typescript
|
|
153
|
+
* await plugin.box.clearInput()
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
clearInput: () => Promise<void>
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Enable input monitoring for attached UI view
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* ```typescript
|
|
163
|
+
* await plugin.box.allowInput()
|
|
164
|
+
* plugin.channel.regChannel('core-box:input-change', ({ data }) => {
|
|
165
|
+
* console.log('Input changed:', data.input)
|
|
166
|
+
* })
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
169
|
+
allowInput: () => Promise<void>
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Enable clipboard monitoring for specified type combination
|
|
173
|
+
*
|
|
174
|
+
* @param types - Binary combination of ClipboardType flags
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```typescript
|
|
178
|
+
* // Allow text and images
|
|
179
|
+
* await plugin.box.allowClipboard(ClipboardType.TEXT | ClipboardType.IMAGE)
|
|
180
|
+
*
|
|
181
|
+
* // Or use presets
|
|
182
|
+
* await plugin.box.allowClipboard(ClipboardTypePresets.TEXT_AND_IMAGE)
|
|
183
|
+
* ```
|
|
184
|
+
*/
|
|
185
|
+
allowClipboard: (types: number) => Promise<void>
|
|
118
186
|
}
|
|
119
187
|
|
|
120
188
|
/**
|
|
121
189
|
* Creates a Box SDK instance for plugin use
|
|
122
|
-
*
|
|
190
|
+
*
|
|
123
191
|
* @param channel - The plugin channel bridge for IPC communication
|
|
124
192
|
* @returns Configured Box SDK instance
|
|
125
|
-
*
|
|
193
|
+
*
|
|
126
194
|
* @internal
|
|
127
195
|
*/
|
|
128
196
|
export function createBoxSDK(channel: any): BoxSDK {
|
|
@@ -148,7 +216,8 @@ export function createBoxSDK(channel: any): BoxSDK {
|
|
|
148
216
|
async expand(options?: BoxExpandOptions): Promise<void> {
|
|
149
217
|
try {
|
|
150
218
|
await sendFn('core-box:expand', options || {})
|
|
151
|
-
}
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
152
221
|
console.error('[Box SDK] Failed to expand CoreBox:', error)
|
|
153
222
|
throw error
|
|
154
223
|
}
|
|
@@ -157,7 +226,8 @@ export function createBoxSDK(channel: any): BoxSDK {
|
|
|
157
226
|
async shrink(): Promise<void> {
|
|
158
227
|
try {
|
|
159
228
|
await sendFn('core-box:expand', { mode: 'collapse' })
|
|
160
|
-
}
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
161
231
|
console.error('[Box SDK] Failed to shrink CoreBox:', error)
|
|
162
232
|
throw error
|
|
163
233
|
}
|
|
@@ -166,7 +236,8 @@ export function createBoxSDK(channel: any): BoxSDK {
|
|
|
166
236
|
async hideInput(): Promise<void> {
|
|
167
237
|
try {
|
|
168
238
|
await sendFn('core-box:hide-input')
|
|
169
|
-
}
|
|
239
|
+
}
|
|
240
|
+
catch (error) {
|
|
170
241
|
console.error('[Box SDK] Failed to hide input:', error)
|
|
171
242
|
throw error
|
|
172
243
|
}
|
|
@@ -175,7 +246,8 @@ export function createBoxSDK(channel: any): BoxSDK {
|
|
|
175
246
|
async showInput(): Promise<void> {
|
|
176
247
|
try {
|
|
177
248
|
await sendFn('core-box:show-input')
|
|
178
|
-
}
|
|
249
|
+
}
|
|
250
|
+
catch (error) {
|
|
179
251
|
console.error('[Box SDK] Failed to show input:', error)
|
|
180
252
|
throw error
|
|
181
253
|
}
|
|
@@ -185,35 +257,70 @@ export function createBoxSDK(channel: any): BoxSDK {
|
|
|
185
257
|
try {
|
|
186
258
|
const result = await sendFn('core-box:get-input')
|
|
187
259
|
return result?.data?.input || result?.input || ''
|
|
188
|
-
}
|
|
260
|
+
}
|
|
261
|
+
catch (error) {
|
|
189
262
|
console.error('[Box SDK] Failed to get input:', error)
|
|
190
263
|
throw error
|
|
191
264
|
}
|
|
192
|
-
}
|
|
265
|
+
},
|
|
266
|
+
|
|
267
|
+
async setInput(value: string): Promise<void> {
|
|
268
|
+
try {
|
|
269
|
+
await sendFn('core-box:set-input', { value })
|
|
270
|
+
}
|
|
271
|
+
catch (error) {
|
|
272
|
+
console.error('[Box SDK] Failed to set input:', error)
|
|
273
|
+
throw error
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
|
|
277
|
+
async clearInput(): Promise<void> {
|
|
278
|
+
try {
|
|
279
|
+
await sendFn('core-box:clear-input')
|
|
280
|
+
}
|
|
281
|
+
catch (error) {
|
|
282
|
+
console.error('[Box SDK] Failed to clear input:', error)
|
|
283
|
+
throw error
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
|
|
287
|
+
async allowInput(): Promise<void> {
|
|
288
|
+
try {
|
|
289
|
+
await sendFn('core-box:allow-input')
|
|
290
|
+
}
|
|
291
|
+
catch (error) {
|
|
292
|
+
console.error('[Box SDK] Failed to enable input monitoring:', error)
|
|
293
|
+
throw error
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
|
|
297
|
+
async allowClipboard(types: number): Promise<void> {
|
|
298
|
+
try {
|
|
299
|
+
await sendFn('core-box:allow-clipboard', types)
|
|
300
|
+
}
|
|
301
|
+
catch (error) {
|
|
302
|
+
console.error('[Box SDK] Failed to enable clipboard monitoring:', error)
|
|
303
|
+
throw error
|
|
304
|
+
}
|
|
305
|
+
},
|
|
193
306
|
}
|
|
194
307
|
}
|
|
195
308
|
|
|
196
309
|
/**
|
|
197
310
|
* Hook for using Box SDK in plugin context
|
|
198
|
-
*
|
|
311
|
+
*
|
|
199
312
|
* @returns Box SDK instance
|
|
200
|
-
*
|
|
313
|
+
*
|
|
201
314
|
* @example
|
|
202
315
|
* ```typescript
|
|
203
316
|
* const box = useBox()
|
|
204
|
-
*
|
|
317
|
+
*
|
|
205
318
|
* box.hide()
|
|
206
319
|
* box.expand({ length: 10 })
|
|
207
320
|
* const input = await box.getInput()
|
|
208
321
|
* ```
|
|
209
322
|
*/
|
|
210
323
|
export function useBox(): BoxSDK {
|
|
211
|
-
|
|
212
|
-
const channel = window.$channel
|
|
213
|
-
|
|
214
|
-
if (!channel) {
|
|
215
|
-
throw new Error('[Box SDK] Channel not available. Make sure this is called in a plugin context.')
|
|
216
|
-
}
|
|
217
|
-
|
|
324
|
+
const channel = ensureRendererChannel('[Box SDK] Channel not available. Make sure this is called in a plugin context.')
|
|
218
325
|
return createBoxSDK(channel)
|
|
219
326
|
}
|
package/plugin/sdk/channel.ts
CHANGED
|
@@ -4,6 +4,34 @@ import { genChannel } from '../channel'
|
|
|
4
4
|
|
|
5
5
|
const ensureClientChannel = (): ITouchClientChannel => genChannel()
|
|
6
6
|
|
|
7
|
+
const DEFAULT_CHANNEL_ERROR = '[Plugin SDK] Channel not available. Make sure this code runs inside a plugin renderer context.'
|
|
8
|
+
|
|
9
|
+
let cachedWindowChannel: ITouchClientChannel | null = null
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Ensures that the renderer-side plugin channel (window.$channel) exists and returns it.
|
|
13
|
+
*
|
|
14
|
+
* @param errorMessage - Optional custom error message when the channel is unavailable
|
|
15
|
+
*/
|
|
16
|
+
export function ensureRendererChannel(errorMessage = DEFAULT_CHANNEL_ERROR): ITouchClientChannel {
|
|
17
|
+
const globalWindow = typeof window === 'undefined' ? undefined : window
|
|
18
|
+
const channel = globalWindow?.$channel ?? cachedWindowChannel
|
|
19
|
+
|
|
20
|
+
if (!channel) {
|
|
21
|
+
throw new Error(errorMessage)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
cachedWindowChannel = channel
|
|
25
|
+
return channel
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Convenience hook for accessing window.$channel in plugin renderers.
|
|
30
|
+
*/
|
|
31
|
+
export function useChannel(errorMessage?: string): ITouchClientChannel {
|
|
32
|
+
return ensureRendererChannel(errorMessage)
|
|
33
|
+
}
|
|
34
|
+
|
|
7
35
|
export function createPluginRendererChannel(): IPluginRendererChannel {
|
|
8
36
|
const client = ensureClientChannel()
|
|
9
37
|
|
|
@@ -46,3 +74,9 @@ export function usePluginRendererChannel(): IPluginRendererChannel {
|
|
|
46
74
|
|
|
47
75
|
return cachedRendererChannel
|
|
48
76
|
}
|
|
77
|
+
|
|
78
|
+
declare global {
|
|
79
|
+
interface Window {
|
|
80
|
+
$channel: ITouchClientChannel
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -11,6 +11,7 @@ import type {
|
|
|
11
11
|
DivisionBoxState,
|
|
12
12
|
SessionInfo,
|
|
13
13
|
} from '../../types/division-box'
|
|
14
|
+
import { ensureRendererChannel } from './channel'
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* State change event handler
|
|
@@ -255,12 +256,6 @@ export function createDivisionBoxSDK(channel: any): DivisionBoxSDK {
|
|
|
255
256
|
* ```
|
|
256
257
|
*/
|
|
257
258
|
export function useDivisionBox(): DivisionBoxSDK {
|
|
258
|
-
|
|
259
|
-
const channel = window.$channel
|
|
260
|
-
|
|
261
|
-
if (!channel) {
|
|
262
|
-
throw new Error('[DivisionBox SDK] Channel not available. Make sure this is called in a plugin context.')
|
|
263
|
-
}
|
|
264
|
-
|
|
259
|
+
const channel = ensureRendererChannel('[DivisionBox SDK] Channel not available. Make sure this is called in a plugin context.')
|
|
265
260
|
return createDivisionBoxSDK(channel)
|
|
266
261
|
}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { TuffItem } from '../../core-box/tuff'
|
|
10
|
+
import { ensureRendererChannel } from './channel'
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Input change event handler
|
|
@@ -218,18 +219,13 @@ export function createFeatureSDK(boxItemsAPI: any, channel: any): FeatureSDK {
|
|
|
218
219
|
* ```
|
|
219
220
|
*/
|
|
220
221
|
export function useFeature(): FeatureSDK {
|
|
221
|
-
// @ts-ignore - window.$boxItems
|
|
222
|
+
// @ts-ignore - window.$boxItems is injected by the plugin system
|
|
222
223
|
const boxItemsAPI = window.$boxItems
|
|
223
|
-
|
|
224
|
-
const channel = window.$channel
|
|
224
|
+
const channel = ensureRendererChannel('[Feature SDK] Channel not available. Make sure this is called in a plugin context.')
|
|
225
225
|
|
|
226
226
|
if (!boxItemsAPI) {
|
|
227
227
|
throw new Error('[Feature SDK] boxItems API not available. Make sure this is called in a plugin context.')
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
-
if (!channel) {
|
|
231
|
-
throw new Error('[Feature SDK] Channel not available. Make sure this is called in a plugin context.')
|
|
232
|
-
}
|
|
233
|
-
|
|
234
230
|
return createFeatureSDK(boxItemsAPI, channel)
|
|
235
231
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BridgeEventForCoreBox } from '../enum/bridge-event'
|
|
2
|
+
import { ensureRendererChannel } from '../channel'
|
|
2
3
|
|
|
3
4
|
export type BridgeEvent = BridgeEventForCoreBox
|
|
4
5
|
|
|
@@ -26,7 +27,8 @@ export function injectBridgeEvent<T>(type: BridgeEvent, hook: BridgeHook<T>) {
|
|
|
26
27
|
|
|
27
28
|
// Only register the channel listener once per event type
|
|
28
29
|
if (hooks.length === 0) {
|
|
29
|
-
|
|
30
|
+
const channel = ensureRendererChannel('[TouchSDK] Bridge channel not available. Make sure hooks run in plugin renderer context.')
|
|
31
|
+
channel.regChannel(type, ({ data }) => {
|
|
30
32
|
console.debug(`[TouchSDK] ${type} event received: `, data)
|
|
31
33
|
// When the event is received, call all registered hooks for this type
|
|
32
34
|
const registeredHooks = __hooks[type]
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { ensureRendererChannel } from '../channel'
|
|
2
|
+
|
|
1
3
|
export enum LifecycleHooks {
|
|
2
4
|
ENABLE = 'en',
|
|
3
5
|
DISABLE = 'di',
|
|
@@ -22,7 +24,8 @@ export function injectHook(type: LifecycleHooks, hook: Function, processFunc = (
|
|
|
22
24
|
const hooks: Array<Function> = __hooks[type] || (__hooks[type] = [])
|
|
23
25
|
|
|
24
26
|
if (hooks.length === 0) {
|
|
25
|
-
|
|
27
|
+
const channel = ensureRendererChannel('[Lifecycle Hook] Channel not available. Make sure hooks run in plugin renderer context.')
|
|
28
|
+
channel.regChannel(`@lifecycle:${type}`, (obj: any) => {
|
|
26
29
|
processFunc(obj)
|
|
27
30
|
|
|
28
31
|
// @ts-ignore
|
package/plugin/sdk/storage.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { FileDetails, StorageStats, StorageTreeNode } from '../../types/storage'
|
|
2
|
+
import { ensureRendererChannel } from './channel'
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Get the storage for the current plugin.
|
|
@@ -15,7 +16,7 @@ export function usePluginStorage() {
|
|
|
15
16
|
throw new Error('[Plugin SDK] Cannot determine plugin name. Make sure this is called in a plugin context.')
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
const channel =
|
|
19
|
+
const channel = ensureRendererChannel('[Plugin Storage] Channel not available. Make sure this is called in a plugin context.')
|
|
19
20
|
|
|
20
21
|
return {
|
|
21
22
|
/**
|