@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.
- 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 +32 -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 +9 -5
- package/market/index.ts +1 -1
- package/market/types.ts +19 -4
- 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 +80 -7
- 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 -4
- package/plugin/providers/market-client.ts +6 -3
- package/plugin/providers/npm-provider.ts +22 -7
- package/plugin/providers/tpex-provider.ts +22 -8
- 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 +13 -6
- 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/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 +16 -2
- 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 +55 -214
- 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 +31 -40
- 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 +31 -31
- 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 +166 -173
- 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
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Feature SDK for Plugin Development
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Provides a unified API for plugins to manage search result items (TuffItems)
|
|
5
5
|
* in the CoreBox interface. This SDK handles item lifecycle, updates, and
|
|
6
6
|
* input change notifications.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { TuffItem } from '../../core-box/tuff'
|
|
10
|
+
import { createPluginTuffTransport } from '../../transport'
|
|
11
|
+
import { defineRawEvent } from '../../transport/event/builder'
|
|
12
|
+
import { createDisposableBag } from '../../transport/sdk'
|
|
13
|
+
import { useBoxItems } from './box-items'
|
|
10
14
|
import { ensureRendererChannel } from './channel'
|
|
11
15
|
|
|
12
16
|
/**
|
|
@@ -32,9 +36,12 @@ export interface ForwardedKeyEvent {
|
|
|
32
36
|
*/
|
|
33
37
|
export type KeyEventHandler = (event: ForwardedKeyEvent) => void
|
|
34
38
|
|
|
39
|
+
const featureInputChangeEvent = defineRawEvent<unknown, unknown>('core-box:input-change')
|
|
40
|
+
const featureKeyEvent = defineRawEvent<unknown, unknown>('core-box:key-event')
|
|
41
|
+
|
|
35
42
|
/**
|
|
36
43
|
* Feature SDK interface for plugins
|
|
37
|
-
*
|
|
44
|
+
*
|
|
38
45
|
* @example
|
|
39
46
|
* ```typescript
|
|
40
47
|
* // Push items to CoreBox
|
|
@@ -42,10 +49,10 @@ export type KeyEventHandler = (event: ForwardedKeyEvent) => void
|
|
|
42
49
|
* { id: 'item-1', title: 'Result 1', ... },
|
|
43
50
|
* { id: 'item-2', title: 'Result 2', ... }
|
|
44
51
|
* ])
|
|
45
|
-
*
|
|
52
|
+
*
|
|
46
53
|
* // Update a specific item
|
|
47
54
|
* plugin.feature.updateItem('item-1', { title: 'Updated Title' })
|
|
48
|
-
*
|
|
55
|
+
*
|
|
49
56
|
* // Listen for input changes
|
|
50
57
|
* plugin.feature.onInputChange((input) => {
|
|
51
58
|
* console.log('User typed:', input)
|
|
@@ -55,9 +62,9 @@ export type KeyEventHandler = (event: ForwardedKeyEvent) => void
|
|
|
55
62
|
export interface FeatureSDK {
|
|
56
63
|
/**
|
|
57
64
|
* Pushes multiple items to the CoreBox search results
|
|
58
|
-
*
|
|
65
|
+
*
|
|
59
66
|
* @param items - Array of TuffItem objects to display
|
|
60
|
-
*
|
|
67
|
+
*
|
|
61
68
|
* @example
|
|
62
69
|
* ```typescript
|
|
63
70
|
* plugin.feature.pushItems([
|
|
@@ -70,14 +77,14 @@ export interface FeatureSDK {
|
|
|
70
77
|
* ])
|
|
71
78
|
* ```
|
|
72
79
|
*/
|
|
73
|
-
pushItems(items: TuffItem[])
|
|
80
|
+
pushItems: (items: TuffItem[]) => void
|
|
74
81
|
|
|
75
82
|
/**
|
|
76
83
|
* Updates a specific item by ID
|
|
77
|
-
*
|
|
84
|
+
*
|
|
78
85
|
* @param id - The unique ID of the item to update
|
|
79
86
|
* @param updates - Partial TuffItem with fields to update
|
|
80
|
-
*
|
|
87
|
+
*
|
|
81
88
|
* @example
|
|
82
89
|
* ```typescript
|
|
83
90
|
* // Update title and subtitle
|
|
@@ -87,49 +94,49 @@ export interface FeatureSDK {
|
|
|
87
94
|
* })
|
|
88
95
|
* ```
|
|
89
96
|
*/
|
|
90
|
-
updateItem(id: string, updates: Partial<TuffItem>)
|
|
97
|
+
updateItem: (id: string, updates: Partial<TuffItem>) => void
|
|
91
98
|
|
|
92
99
|
/**
|
|
93
100
|
* Removes a specific item by ID
|
|
94
|
-
*
|
|
101
|
+
*
|
|
95
102
|
* @param id - The unique ID of the item to remove
|
|
96
|
-
*
|
|
103
|
+
*
|
|
97
104
|
* @example
|
|
98
105
|
* ```typescript
|
|
99
106
|
* plugin.feature.removeItem('item-1')
|
|
100
107
|
* ```
|
|
101
108
|
*/
|
|
102
|
-
removeItem(id: string)
|
|
109
|
+
removeItem: (id: string) => void
|
|
103
110
|
|
|
104
111
|
/**
|
|
105
112
|
* Clears all items pushed by this plugin
|
|
106
|
-
*
|
|
113
|
+
*
|
|
107
114
|
* @example
|
|
108
115
|
* ```typescript
|
|
109
116
|
* plugin.feature.clearItems()
|
|
110
117
|
* ```
|
|
111
118
|
*/
|
|
112
|
-
clearItems()
|
|
119
|
+
clearItems: () => void
|
|
113
120
|
|
|
114
121
|
/**
|
|
115
122
|
* Gets all items currently pushed by this plugin
|
|
116
|
-
*
|
|
123
|
+
*
|
|
117
124
|
* @returns Array of TuffItem objects
|
|
118
|
-
*
|
|
125
|
+
*
|
|
119
126
|
* @example
|
|
120
127
|
* ```typescript
|
|
121
128
|
* const items = plugin.feature.getItems()
|
|
122
129
|
* console.log(`Currently showing ${items.length} items`)
|
|
123
130
|
* ```
|
|
124
131
|
*/
|
|
125
|
-
getItems()
|
|
132
|
+
getItems: () => TuffItem[]
|
|
126
133
|
|
|
127
134
|
/**
|
|
128
135
|
* Registers a listener for input changes in the CoreBox search field
|
|
129
|
-
*
|
|
136
|
+
*
|
|
130
137
|
* @param handler - Callback function invoked when input changes
|
|
131
138
|
* @returns Unsubscribe function
|
|
132
|
-
*
|
|
139
|
+
*
|
|
133
140
|
* @example
|
|
134
141
|
* ```typescript
|
|
135
142
|
* const unsubscribe = plugin.feature.onInputChange((input) => {
|
|
@@ -137,22 +144,22 @@ export interface FeatureSDK {
|
|
|
137
144
|
* // Perform real-time search
|
|
138
145
|
* performSearch(input)
|
|
139
146
|
* })
|
|
140
|
-
*
|
|
147
|
+
*
|
|
141
148
|
* // Later, unsubscribe
|
|
142
149
|
* unsubscribe()
|
|
143
150
|
* ```
|
|
144
151
|
*/
|
|
145
|
-
onInputChange(handler: InputChangeHandler)
|
|
152
|
+
onInputChange: (handler: InputChangeHandler) => () => void
|
|
146
153
|
|
|
147
154
|
/**
|
|
148
155
|
* Registers a listener for keyboard events forwarded from CoreBox
|
|
149
|
-
*
|
|
156
|
+
*
|
|
150
157
|
* When a plugin's UI view is attached to CoreBox, certain key events
|
|
151
158
|
* (Enter, Arrow keys, Meta+key combinations) are forwarded to the plugin.
|
|
152
|
-
*
|
|
159
|
+
*
|
|
153
160
|
* @param handler - Callback function invoked when a key event is forwarded
|
|
154
161
|
* @returns Unsubscribe function
|
|
155
|
-
*
|
|
162
|
+
*
|
|
156
163
|
* @example
|
|
157
164
|
* ```typescript
|
|
158
165
|
* const unsubscribe = plugin.feature.onKeyEvent((event) => {
|
|
@@ -167,70 +174,95 @@ export interface FeatureSDK {
|
|
|
167
174
|
* openSearch()
|
|
168
175
|
* }
|
|
169
176
|
* })
|
|
170
|
-
*
|
|
177
|
+
*
|
|
171
178
|
* // Later, unsubscribe
|
|
172
179
|
* unsubscribe()
|
|
173
180
|
* ```
|
|
174
181
|
*/
|
|
175
|
-
onKeyEvent(handler: KeyEventHandler)
|
|
182
|
+
onKeyEvent: (handler: KeyEventHandler) => () => void
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* 释放内部监听器,避免重复注册导致的内存泄漏
|
|
186
|
+
*/
|
|
187
|
+
dispose: () => void
|
|
176
188
|
}
|
|
177
189
|
|
|
178
190
|
/**
|
|
179
191
|
* Creates a Feature SDK instance for plugin use
|
|
180
|
-
*
|
|
192
|
+
*
|
|
181
193
|
* @param boxItemsAPI - The boxItems API object from plugin context
|
|
182
194
|
* @param channel - The plugin channel bridge for IPC communication
|
|
183
195
|
* @returns Configured Feature SDK instance
|
|
184
|
-
*
|
|
196
|
+
*
|
|
185
197
|
* @internal
|
|
186
198
|
*/
|
|
187
199
|
export function createFeatureSDK(boxItemsAPI: any, channel: any): FeatureSDK {
|
|
188
200
|
const inputChangeHandlers: Set<InputChangeHandler> = new Set()
|
|
189
201
|
const keyEventHandlers: Set<KeyEventHandler> = new Set()
|
|
202
|
+
const disposables = createDisposableBag()
|
|
203
|
+
const transport = createPluginTuffTransport(channel)
|
|
204
|
+
let disposed = false
|
|
205
|
+
|
|
206
|
+
const emitInput = (payload: any) => {
|
|
207
|
+
const input = payload?.input || payload?.query?.text || payload || ''
|
|
208
|
+
for (const handler of inputChangeHandlers) {
|
|
209
|
+
try {
|
|
210
|
+
handler(input)
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
console.error('[Feature SDK] onInputChange handler error:', error)
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const emitKeyEvent = (payload: any) => {
|
|
219
|
+
const keyEvent = payload as ForwardedKeyEvent
|
|
220
|
+
if (!keyEvent) {
|
|
221
|
+
return
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
for (const handler of keyEventHandlers) {
|
|
225
|
+
try {
|
|
226
|
+
handler(keyEvent)
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
console.error('[Feature SDK] onKeyEvent handler error:', error)
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
190
233
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
// Main process plugin context
|
|
195
|
-
channel.onMain('core-box:input-change', (event: any) => {
|
|
196
|
-
const input = event.data?.input || event.data?.query?.text || event.input || ''
|
|
197
|
-
inputChangeHandlers.forEach(handler => handler(input))
|
|
198
|
-
})
|
|
199
|
-
} else if (channel.on) {
|
|
200
|
-
// Renderer process context
|
|
201
|
-
channel.on('core-box:input-change', (data: any) => {
|
|
202
|
-
const input = data?.input || data?.query?.text || data || ''
|
|
203
|
-
inputChangeHandlers.forEach(handler => handler(input))
|
|
204
|
-
})
|
|
234
|
+
const ensureActive = (method: string) => {
|
|
235
|
+
if (disposed) {
|
|
236
|
+
throw new Error(`[Feature SDK] Cannot call ${method} after dispose`)
|
|
205
237
|
}
|
|
206
238
|
}
|
|
207
239
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
// Main process plugin context
|
|
212
|
-
channel.onMain('core-box:key-event', (event: any) => {
|
|
213
|
-
const keyEvent = event.data as ForwardedKeyEvent
|
|
214
|
-
if (keyEvent) {
|
|
215
|
-
keyEventHandlers.forEach(handler => handler(keyEvent))
|
|
216
|
-
}
|
|
217
|
-
})
|
|
218
|
-
} else if (channel.on) {
|
|
219
|
-
// Renderer process context
|
|
220
|
-
channel.on('core-box:key-event', (data: any) => {
|
|
221
|
-
const keyEvent = data as ForwardedKeyEvent
|
|
222
|
-
if (keyEvent) {
|
|
223
|
-
keyEventHandlers.forEach(handler => handler(keyEvent))
|
|
224
|
-
}
|
|
225
|
-
})
|
|
240
|
+
const dispose = () => {
|
|
241
|
+
if (disposed) {
|
|
242
|
+
return
|
|
226
243
|
}
|
|
244
|
+
|
|
245
|
+
disposed = true
|
|
246
|
+
inputChangeHandlers.clear()
|
|
247
|
+
keyEventHandlers.clear()
|
|
248
|
+
disposables.dispose()
|
|
249
|
+
transport.destroy()
|
|
227
250
|
}
|
|
228
251
|
|
|
229
|
-
|
|
230
|
-
|
|
252
|
+
disposables.add(
|
|
253
|
+
transport.on(featureInputChangeEvent, emitInput),
|
|
254
|
+
transport.on(featureKeyEvent, emitKeyEvent),
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
if (typeof window !== 'undefined' && typeof window.addEventListener === 'function') {
|
|
258
|
+
const onBeforeUnload = () => dispose()
|
|
259
|
+
window.addEventListener('beforeunload', onBeforeUnload, { once: true })
|
|
260
|
+
disposables.add(() => window.removeEventListener('beforeunload', onBeforeUnload))
|
|
261
|
+
}
|
|
231
262
|
|
|
232
263
|
return {
|
|
233
264
|
pushItems(items: TuffItem[]): void {
|
|
265
|
+
ensureActive('pushItems')
|
|
234
266
|
if (!boxItemsAPI || !boxItemsAPI.pushItems) {
|
|
235
267
|
throw new Error('[Feature SDK] boxItems API not available')
|
|
236
268
|
}
|
|
@@ -238,6 +270,7 @@ export function createFeatureSDK(boxItemsAPI: any, channel: any): FeatureSDK {
|
|
|
238
270
|
},
|
|
239
271
|
|
|
240
272
|
updateItem(id: string, updates: Partial<TuffItem>): void {
|
|
273
|
+
ensureActive('updateItem')
|
|
241
274
|
if (!boxItemsAPI || !boxItemsAPI.update) {
|
|
242
275
|
throw new Error('[Feature SDK] boxItems API not available')
|
|
243
276
|
}
|
|
@@ -245,6 +278,7 @@ export function createFeatureSDK(boxItemsAPI: any, channel: any): FeatureSDK {
|
|
|
245
278
|
},
|
|
246
279
|
|
|
247
280
|
removeItem(id: string): void {
|
|
281
|
+
ensureActive('removeItem')
|
|
248
282
|
if (!boxItemsAPI || !boxItemsAPI.remove) {
|
|
249
283
|
throw new Error('[Feature SDK] boxItems API not available')
|
|
250
284
|
}
|
|
@@ -252,6 +286,7 @@ export function createFeatureSDK(boxItemsAPI: any, channel: any): FeatureSDK {
|
|
|
252
286
|
},
|
|
253
287
|
|
|
254
288
|
clearItems(): void {
|
|
289
|
+
ensureActive('clearItems')
|
|
255
290
|
if (!boxItemsAPI || !boxItemsAPI.clear) {
|
|
256
291
|
throw new Error('[Feature SDK] boxItems API not available')
|
|
257
292
|
}
|
|
@@ -259,6 +294,7 @@ export function createFeatureSDK(boxItemsAPI: any, channel: any): FeatureSDK {
|
|
|
259
294
|
},
|
|
260
295
|
|
|
261
296
|
getItems(): TuffItem[] {
|
|
297
|
+
ensureActive('getItems')
|
|
262
298
|
if (!boxItemsAPI || !boxItemsAPI.getItems) {
|
|
263
299
|
throw new Error('[Feature SDK] boxItems API not available')
|
|
264
300
|
}
|
|
@@ -266,45 +302,44 @@ export function createFeatureSDK(boxItemsAPI: any, channel: any): FeatureSDK {
|
|
|
266
302
|
},
|
|
267
303
|
|
|
268
304
|
onInputChange(handler: InputChangeHandler): () => void {
|
|
305
|
+
ensureActive('onInputChange')
|
|
269
306
|
inputChangeHandlers.add(handler)
|
|
270
|
-
|
|
307
|
+
|
|
271
308
|
return () => {
|
|
272
309
|
inputChangeHandlers.delete(handler)
|
|
273
310
|
}
|
|
274
311
|
},
|
|
275
312
|
|
|
276
313
|
onKeyEvent(handler: KeyEventHandler): () => void {
|
|
314
|
+
ensureActive('onKeyEvent')
|
|
277
315
|
keyEventHandlers.add(handler)
|
|
278
|
-
|
|
316
|
+
|
|
279
317
|
return () => {
|
|
280
318
|
keyEventHandlers.delete(handler)
|
|
281
319
|
}
|
|
282
|
-
}
|
|
320
|
+
},
|
|
321
|
+
|
|
322
|
+
dispose,
|
|
283
323
|
}
|
|
284
324
|
}
|
|
285
325
|
|
|
286
326
|
/**
|
|
287
327
|
* Hook for using Feature SDK in plugin context
|
|
288
|
-
*
|
|
328
|
+
*
|
|
289
329
|
* @returns Feature SDK instance
|
|
290
|
-
*
|
|
330
|
+
*
|
|
291
331
|
* @example
|
|
292
332
|
* ```typescript
|
|
293
333
|
* const feature = useFeature()
|
|
294
|
-
*
|
|
334
|
+
*
|
|
295
335
|
* feature.pushItems([
|
|
296
336
|
* { id: '1', title: { text: 'Item 1' }, ... }
|
|
297
337
|
* ])
|
|
298
338
|
* ```
|
|
299
339
|
*/
|
|
300
340
|
export function useFeature(): FeatureSDK {
|
|
301
|
-
|
|
302
|
-
const boxItemsAPI = window.$boxItems
|
|
341
|
+
const boxItemsAPI = useBoxItems()
|
|
303
342
|
const channel = ensureRendererChannel('[Feature SDK] Channel not available. Make sure this is called in a plugin context.')
|
|
304
|
-
|
|
305
|
-
if (!boxItemsAPI) {
|
|
306
|
-
throw new Error('[Feature SDK] boxItems API not available. Make sure this is called in a plugin context.')
|
|
307
|
-
}
|
|
308
|
-
|
|
343
|
+
|
|
309
344
|
return createFeatureSDK(boxItemsAPI, channel)
|
|
310
345
|
}
|
package/plugin/sdk/flow.ts
CHANGED
|
@@ -6,14 +6,29 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type {
|
|
9
|
-
FlowPayload,
|
|
10
9
|
FlowDispatchOptions,
|
|
11
10
|
FlowDispatchResult,
|
|
12
|
-
|
|
11
|
+
FlowPayload,
|
|
12
|
+
FlowPayloadType,
|
|
13
13
|
FlowSessionUpdate,
|
|
14
|
-
|
|
14
|
+
FlowTargetInfo,
|
|
15
15
|
} from '../../types/flow'
|
|
16
|
-
import {
|
|
16
|
+
import { createPluginTuffTransport } from '../../transport'
|
|
17
|
+
import { FlowEvents } from '../../transport/events'
|
|
18
|
+
import { tryGetPluginSdkApi } from './plugin-info'
|
|
19
|
+
|
|
20
|
+
function resolveSdkApi(): number | undefined {
|
|
21
|
+
return tryGetPluginSdkApi()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Flow transfer handler function type
|
|
26
|
+
*/
|
|
27
|
+
export type FlowTransferHandler = (
|
|
28
|
+
payload: FlowPayload,
|
|
29
|
+
sessionId: string,
|
|
30
|
+
senderInfo: { senderId: string, senderName?: string },
|
|
31
|
+
) => Promise<void> | void
|
|
17
32
|
|
|
18
33
|
/**
|
|
19
34
|
* Flow SDK interface
|
|
@@ -41,7 +56,7 @@ export interface IFlowSDK {
|
|
|
41
56
|
* )
|
|
42
57
|
* ```
|
|
43
58
|
*/
|
|
44
|
-
dispatch(payload: FlowPayload, options?: FlowDispatchOptions)
|
|
59
|
+
dispatch: (payload: FlowPayload, options?: FlowDispatchOptions) => Promise<FlowDispatchResult>
|
|
45
60
|
|
|
46
61
|
/**
|
|
47
62
|
* Gets available flow targets
|
|
@@ -49,7 +64,25 @@ export interface IFlowSDK {
|
|
|
49
64
|
* @param payloadType - Filter by payload type (optional)
|
|
50
65
|
* @returns List of available targets
|
|
51
66
|
*/
|
|
52
|
-
getAvailableTargets(payloadType?: FlowPayloadType)
|
|
67
|
+
getAvailableTargets: (payloadType?: FlowPayloadType) => Promise<FlowTargetInfo[]>
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Registers a handler for incoming flow transfers
|
|
71
|
+
* This tells the system that your plugin can handle flow data
|
|
72
|
+
*
|
|
73
|
+
* @param handler - Handler function for incoming flows
|
|
74
|
+
* @returns Unsubscribe function
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```typescript
|
|
78
|
+
* const unsubscribe = flow.onFlowTransfer(async (payload, sessionId, sender) => {
|
|
79
|
+
* console.log(`Received ${payload.type} from ${sender.senderName}`)
|
|
80
|
+
* // Process the payload...
|
|
81
|
+
* await flow.acknowledge(sessionId, { processed: true })
|
|
82
|
+
* })
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
onFlowTransfer: (handler: FlowTransferHandler) => () => void
|
|
53
86
|
|
|
54
87
|
/**
|
|
55
88
|
* Listens for session updates
|
|
@@ -58,17 +91,17 @@ export interface IFlowSDK {
|
|
|
58
91
|
* @param handler - Update handler
|
|
59
92
|
* @returns Unsubscribe function
|
|
60
93
|
*/
|
|
61
|
-
onSessionUpdate(
|
|
94
|
+
onSessionUpdate: (
|
|
62
95
|
sessionId: string,
|
|
63
|
-
handler: (update: FlowSessionUpdate) => void
|
|
64
|
-
)
|
|
96
|
+
handler: (update: FlowSessionUpdate) => void,
|
|
97
|
+
) => () => void
|
|
65
98
|
|
|
66
99
|
/**
|
|
67
100
|
* Cancels a flow session
|
|
68
101
|
*
|
|
69
102
|
* @param sessionId - Session to cancel
|
|
70
103
|
*/
|
|
71
|
-
cancel(sessionId: string)
|
|
104
|
+
cancel: (sessionId: string) => Promise<void>
|
|
72
105
|
|
|
73
106
|
/**
|
|
74
107
|
* Acknowledges a received flow (for target plugins)
|
|
@@ -76,7 +109,7 @@ export interface IFlowSDK {
|
|
|
76
109
|
* @param sessionId - Session to acknowledge
|
|
77
110
|
* @param ackPayload - Optional acknowledgment data
|
|
78
111
|
*/
|
|
79
|
-
acknowledge(sessionId: string, ackPayload?: any)
|
|
112
|
+
acknowledge: (sessionId: string, ackPayload?: any) => Promise<void>
|
|
80
113
|
|
|
81
114
|
/**
|
|
82
115
|
* Reports an error for a received flow (for target plugins)
|
|
@@ -84,40 +117,61 @@ export interface IFlowSDK {
|
|
|
84
117
|
* @param sessionId - Session to report error for
|
|
85
118
|
* @param message - Error message
|
|
86
119
|
*/
|
|
87
|
-
reportError(sessionId: string, message: string)
|
|
120
|
+
reportError: (sessionId: string, message: string) => Promise<void>
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Uses native system share functionality
|
|
124
|
+
*
|
|
125
|
+
* @param payload - Data to share
|
|
126
|
+
* @param target - Optional preferred native target (system, airdrop, mail, messages)
|
|
127
|
+
*/
|
|
128
|
+
nativeShare: (payload: FlowPayload, target?: string) => Promise<{ success: boolean, target?: string, error?: string }>
|
|
88
129
|
}
|
|
89
130
|
|
|
90
131
|
/**
|
|
91
132
|
* Creates a Flow SDK instance
|
|
92
133
|
*
|
|
93
134
|
* @param channel - Channel for IPC communication
|
|
135
|
+
* @param channel.send - Send function for IPC communication
|
|
94
136
|
* @param pluginId - Current plugin ID
|
|
95
137
|
* @returns Flow SDK instance
|
|
96
138
|
*/
|
|
97
139
|
export function createFlowSDK(
|
|
98
140
|
channel: { send: (event: string, data?: any) => Promise<any> },
|
|
99
|
-
pluginId: string
|
|
141
|
+
pluginId: string,
|
|
100
142
|
): IFlowSDK {
|
|
101
143
|
const sessionListeners = new Map<string, Set<(update: FlowSessionUpdate) => void>>()
|
|
144
|
+
const flowTransferHandlers = new Set<FlowTransferHandler>()
|
|
145
|
+
let hasRegisteredHandler = false
|
|
102
146
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
} catch (error) {
|
|
114
|
-
console.error('[FlowSDK] Error in session listener:', error)
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
147
|
+
const transport = createPluginTuffTransport(channel as any)
|
|
148
|
+
|
|
149
|
+
transport.on(FlowEvents.sessionUpdate, (update) => {
|
|
150
|
+
const listeners = sessionListeners.get((update as any)?.sessionId)
|
|
151
|
+
if (!listeners) {
|
|
152
|
+
return
|
|
153
|
+
}
|
|
154
|
+
for (const listener of listeners) {
|
|
155
|
+
try {
|
|
156
|
+
listener(update as any)
|
|
118
157
|
}
|
|
119
|
-
|
|
120
|
-
|
|
158
|
+
catch (error) {
|
|
159
|
+
console.error('[FlowSDK] Error in session listener:', error)
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
transport.on(FlowEvents.deliver, (payload) => {
|
|
165
|
+
const { sessionId, payload: flowPayload, senderId, senderName } = payload as any
|
|
166
|
+
for (const h of flowTransferHandlers) {
|
|
167
|
+
try {
|
|
168
|
+
h(flowPayload, sessionId, { senderId, senderName })
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
console.error('[FlowSDK] Error in flow transfer handler:', error)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
})
|
|
121
175
|
|
|
122
176
|
return {
|
|
123
177
|
async dispatch(payload: FlowPayload, options?: FlowDispatchOptions): Promise<FlowDispatchResult> {
|
|
@@ -126,26 +180,32 @@ export function createFlowSDK(
|
|
|
126
180
|
...payload,
|
|
127
181
|
context: {
|
|
128
182
|
...payload.context,
|
|
129
|
-
sourcePluginId: payload.context?.sourcePluginId || pluginId
|
|
130
|
-
}
|
|
183
|
+
sourcePluginId: payload.context?.sourcePluginId || pluginId,
|
|
184
|
+
},
|
|
131
185
|
}
|
|
132
186
|
|
|
133
|
-
const response = await
|
|
187
|
+
const response = await transport.send(FlowEvents.dispatch, {
|
|
134
188
|
senderId: pluginId,
|
|
135
189
|
payload: enrichedPayload,
|
|
136
|
-
options
|
|
190
|
+
options,
|
|
191
|
+
_sdkapi: resolveSdkApi(),
|
|
137
192
|
})
|
|
138
193
|
|
|
139
194
|
if (!response?.success) {
|
|
140
195
|
throw new Error(response?.error?.message || 'Flow dispatch failed')
|
|
141
196
|
}
|
|
142
197
|
|
|
198
|
+
if (!response.data) {
|
|
199
|
+
throw new Error('Flow dispatch failed')
|
|
200
|
+
}
|
|
201
|
+
|
|
143
202
|
return response.data
|
|
144
203
|
},
|
|
145
204
|
|
|
146
205
|
async getAvailableTargets(payloadType?: FlowPayloadType): Promise<FlowTargetInfo[]> {
|
|
147
|
-
const response = await
|
|
148
|
-
payloadType
|
|
206
|
+
const response = await transport.send(FlowEvents.getTargets, {
|
|
207
|
+
payloadType,
|
|
208
|
+
_sdkapi: resolveSdkApi(),
|
|
149
209
|
})
|
|
150
210
|
|
|
151
211
|
if (!response?.success) {
|
|
@@ -157,7 +217,7 @@ export function createFlowSDK(
|
|
|
157
217
|
|
|
158
218
|
onSessionUpdate(
|
|
159
219
|
sessionId: string,
|
|
160
|
-
handler: (update: FlowSessionUpdate) => void
|
|
220
|
+
handler: (update: FlowSessionUpdate) => void,
|
|
161
221
|
): () => void {
|
|
162
222
|
if (!sessionListeners.has(sessionId)) {
|
|
163
223
|
sessionListeners.set(sessionId, new Set())
|
|
@@ -176,8 +236,9 @@ export function createFlowSDK(
|
|
|
176
236
|
},
|
|
177
237
|
|
|
178
238
|
async cancel(sessionId: string): Promise<void> {
|
|
179
|
-
const response = await
|
|
180
|
-
sessionId
|
|
239
|
+
const response = await transport.send(FlowEvents.cancel, {
|
|
240
|
+
sessionId,
|
|
241
|
+
_sdkapi: resolveSdkApi(),
|
|
181
242
|
})
|
|
182
243
|
|
|
183
244
|
if (!response?.success) {
|
|
@@ -186,9 +247,10 @@ export function createFlowSDK(
|
|
|
186
247
|
},
|
|
187
248
|
|
|
188
249
|
async acknowledge(sessionId: string, ackPayload?: any): Promise<void> {
|
|
189
|
-
const response = await
|
|
250
|
+
const response = await transport.send(FlowEvents.acknowledge, {
|
|
190
251
|
sessionId,
|
|
191
|
-
ackPayload
|
|
252
|
+
ackPayload,
|
|
253
|
+
_sdkapi: resolveSdkApi(),
|
|
192
254
|
})
|
|
193
255
|
|
|
194
256
|
if (!response?.success) {
|
|
@@ -197,15 +259,54 @@ export function createFlowSDK(
|
|
|
197
259
|
},
|
|
198
260
|
|
|
199
261
|
async reportError(sessionId: string, message: string): Promise<void> {
|
|
200
|
-
const response = await
|
|
262
|
+
const response = await transport.send(FlowEvents.reportError, {
|
|
201
263
|
sessionId,
|
|
202
|
-
message
|
|
264
|
+
message,
|
|
265
|
+
_sdkapi: resolveSdkApi(),
|
|
203
266
|
})
|
|
204
267
|
|
|
205
268
|
if (!response?.success) {
|
|
206
269
|
throw new Error(response?.error?.message || 'Failed to report error')
|
|
207
270
|
}
|
|
208
|
-
}
|
|
271
|
+
},
|
|
272
|
+
|
|
273
|
+
onFlowTransfer(handler: FlowTransferHandler): () => void {
|
|
274
|
+
flowTransferHandlers.add(handler)
|
|
275
|
+
|
|
276
|
+
// Notify the system that this plugin has a flow handler
|
|
277
|
+
if (!hasRegisteredHandler) {
|
|
278
|
+
hasRegisteredHandler = true
|
|
279
|
+
void transport.send(FlowEvents.setPluginHandler, {
|
|
280
|
+
pluginId,
|
|
281
|
+
hasHandler: true,
|
|
282
|
+
_sdkapi: resolveSdkApi(),
|
|
283
|
+
}).catch((err: unknown) => {
|
|
284
|
+
console.warn('[FlowSDK] Failed to register flow handler:', err)
|
|
285
|
+
})
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return () => {
|
|
289
|
+
flowTransferHandlers.delete(handler)
|
|
290
|
+
if (flowTransferHandlers.size === 0) {
|
|
291
|
+
hasRegisteredHandler = false
|
|
292
|
+
void transport.send(FlowEvents.setPluginHandler, {
|
|
293
|
+
pluginId,
|
|
294
|
+
hasHandler: false,
|
|
295
|
+
_sdkapi: resolveSdkApi(),
|
|
296
|
+
}).catch(() => {})
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
|
|
301
|
+
async nativeShare(payload: FlowPayload, target?: string): Promise<{ success: boolean, target?: string, error?: string }> {
|
|
302
|
+
const response = await transport.send(FlowEvents.nativeShare, {
|
|
303
|
+
payload,
|
|
304
|
+
target,
|
|
305
|
+
_sdkapi: resolveSdkApi(),
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
return response || { success: false, error: 'Native share failed' }
|
|
309
|
+
},
|
|
209
310
|
}
|
|
210
311
|
}
|
|
211
312
|
|
|
@@ -231,7 +332,7 @@ export function extractFlowData(query: any): {
|
|
|
231
332
|
sessionId: query.flow.sessionId,
|
|
232
333
|
payload: query.flow.payload,
|
|
233
334
|
senderId: query.flow.senderId,
|
|
234
|
-
senderName: query.flow.senderName
|
|
335
|
+
senderName: query.flow.senderName,
|
|
235
336
|
}
|
|
236
337
|
}
|
|
237
338
|
|