@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
|
@@ -5,6 +5,8 @@ import type {
|
|
|
5
5
|
PluginProvider,
|
|
6
6
|
PluginProviderContext,
|
|
7
7
|
} from './types'
|
|
8
|
+
import { Buffer } from 'node:buffer'
|
|
9
|
+
import process from 'node:process'
|
|
8
10
|
import { PluginProviderType } from './types'
|
|
9
11
|
|
|
10
12
|
const NPM_REGISTRY = 'https://registry.npmjs.org'
|
|
@@ -30,12 +32,12 @@ export interface NpmPackageInfo {
|
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
export interface NpmPackageVersions {
|
|
33
|
-
name: string
|
|
35
|
+
'name': string
|
|
34
36
|
'dist-tags': {
|
|
35
37
|
latest: string
|
|
36
38
|
[tag: string]: string
|
|
37
39
|
}
|
|
38
|
-
versions: Record<string, NpmPackageInfo>
|
|
40
|
+
'versions': Record<string, NpmPackageInfo>
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
/**
|
|
@@ -51,17 +53,29 @@ export interface NpmPackageVersions {
|
|
|
51
53
|
function parseNpmSource(source: string): { packageName: string, version?: string } | null {
|
|
52
54
|
const npmMatch = source.match(/^npm:(@?[a-z0-9][\w\-.]*(?:\/[a-z0-9][\w\-.]*)?)(?:@(.+))?$/i)
|
|
53
55
|
if (npmMatch) {
|
|
54
|
-
|
|
56
|
+
const packageName = npmMatch[1]
|
|
57
|
+
if (!packageName)
|
|
58
|
+
return null
|
|
59
|
+
const version = npmMatch[2]
|
|
60
|
+
return version ? { packageName, version } : { packageName }
|
|
55
61
|
}
|
|
56
62
|
|
|
57
63
|
const scopedMatch = source.match(/^(@tuff\/[a-z0-9][\w\-.]*)(?:@(.+))?$/i)
|
|
58
64
|
if (scopedMatch) {
|
|
59
|
-
|
|
65
|
+
const packageName = scopedMatch[1]
|
|
66
|
+
if (!packageName)
|
|
67
|
+
return null
|
|
68
|
+
const version = scopedMatch[2]
|
|
69
|
+
return version ? { packageName, version } : { packageName }
|
|
60
70
|
}
|
|
61
71
|
|
|
62
72
|
const prefixMatch = source.match(/^(tuff-plugin-[a-z0-9][\w\-.]*)(?:@(.+))?$/i)
|
|
63
73
|
if (prefixMatch) {
|
|
64
|
-
|
|
74
|
+
const packageName = prefixMatch[1]
|
|
75
|
+
if (!packageName)
|
|
76
|
+
return null
|
|
77
|
+
const version = prefixMatch[2]
|
|
78
|
+
return version ? { packageName, version } : { packageName }
|
|
65
79
|
}
|
|
66
80
|
|
|
67
81
|
return null
|
|
@@ -123,7 +137,7 @@ export class NpmProvider implements PluginProvider {
|
|
|
123
137
|
const fileName = `${safePackageName}-${packageInfo.version}.tgz`
|
|
124
138
|
const filePath = `${tempDir}/${fileName}`
|
|
125
139
|
|
|
126
|
-
if (typeof
|
|
140
|
+
if (typeof process !== 'undefined') {
|
|
127
141
|
const fs = await import('node:fs/promises')
|
|
128
142
|
await fs.writeFile(filePath, Buffer.from(arrayBuffer))
|
|
129
143
|
}
|
|
@@ -166,7 +180,8 @@ export class NpmProvider implements PluginProvider {
|
|
|
166
180
|
const res = await fetch(`${this.registry}/${encodedName}`)
|
|
167
181
|
|
|
168
182
|
if (!res.ok) {
|
|
169
|
-
if (res.status === 404)
|
|
183
|
+
if (res.status === 404)
|
|
184
|
+
return null
|
|
170
185
|
throw new Error(`Failed to fetch package info: ${res.statusText}`)
|
|
171
186
|
}
|
|
172
187
|
|
|
@@ -5,9 +5,12 @@ import type {
|
|
|
5
5
|
PluginProvider,
|
|
6
6
|
PluginProviderContext,
|
|
7
7
|
} from './types'
|
|
8
|
+
import { Buffer } from 'node:buffer'
|
|
9
|
+
import process from 'node:process'
|
|
10
|
+
import { NEXUS_BASE_URL } from '../../env'
|
|
8
11
|
import { PluginProviderType } from './types'
|
|
9
12
|
|
|
10
|
-
const DEFAULT_TPEX_API =
|
|
13
|
+
const DEFAULT_TPEX_API = NEXUS_BASE_URL
|
|
11
14
|
|
|
12
15
|
/**
|
|
13
16
|
* Check if source is a .tpex file path or URL
|
|
@@ -41,6 +44,7 @@ export interface TpexPluginInfo {
|
|
|
41
44
|
channel: string
|
|
42
45
|
packageUrl: string
|
|
43
46
|
packageSize: number
|
|
47
|
+
signature?: string
|
|
44
48
|
manifest?: Record<string, unknown> | null
|
|
45
49
|
changelog?: string | null
|
|
46
50
|
}
|
|
@@ -59,6 +63,7 @@ export interface TpexDetailResponse {
|
|
|
59
63
|
channel: string
|
|
60
64
|
packageUrl: string
|
|
61
65
|
packageSize: number
|
|
66
|
+
signature?: string
|
|
62
67
|
manifest?: Record<string, unknown> | null
|
|
63
68
|
changelog?: string | null
|
|
64
69
|
}>
|
|
@@ -70,14 +75,22 @@ export interface TpexDetailResponse {
|
|
|
70
75
|
* Formats: "tpex:slug", "tpex:slug@version", "slug" (when hintType is TPEX)
|
|
71
76
|
*/
|
|
72
77
|
function parseTpexSource(source: string): { slug: string, version?: string } | null {
|
|
73
|
-
const tpexMatch = source.match(/^tpex:([a-z0-9][
|
|
78
|
+
const tpexMatch = source.match(/^tpex:([a-z0-9][\w\-.]{1,62}[a-z0-9])(?:@(.+))?$/i)
|
|
74
79
|
if (tpexMatch) {
|
|
75
|
-
|
|
80
|
+
const slug = tpexMatch[1]
|
|
81
|
+
if (!slug)
|
|
82
|
+
return null
|
|
83
|
+
const version = tpexMatch[2]
|
|
84
|
+
return version ? { slug, version } : { slug }
|
|
76
85
|
}
|
|
77
86
|
|
|
78
|
-
const slugMatch = source.match(/^([a-z0-9][
|
|
87
|
+
const slugMatch = source.match(/^([a-z0-9][\w\-.]{1,62}[a-z0-9])(?:@(.+))?$/i)
|
|
79
88
|
if (slugMatch) {
|
|
80
|
-
|
|
89
|
+
const slug = slugMatch[1]
|
|
90
|
+
if (!slug)
|
|
91
|
+
return null
|
|
92
|
+
const version = slugMatch[2]
|
|
93
|
+
return version ? { slug, version } : { slug }
|
|
81
94
|
}
|
|
82
95
|
|
|
83
96
|
return null
|
|
@@ -138,7 +151,7 @@ export class TpexProvider implements PluginProvider {
|
|
|
138
151
|
const fileName = `tpex-${Date.now()}.tpex`
|
|
139
152
|
filePath = `${tempDir}/${fileName}`
|
|
140
153
|
|
|
141
|
-
if (typeof
|
|
154
|
+
if (typeof process !== 'undefined') {
|
|
142
155
|
const fs = await import('node:fs/promises')
|
|
143
156
|
await fs.writeFile(filePath, Buffer.from(arrayBuffer))
|
|
144
157
|
}
|
|
@@ -204,7 +217,7 @@ export class TpexProvider implements PluginProvider {
|
|
|
204
217
|
const fileName = `${slug}-${targetVersion.version}.tpex`
|
|
205
218
|
const filePath = `${tempDir}/${fileName}`
|
|
206
219
|
|
|
207
|
-
if (typeof
|
|
220
|
+
if (typeof process !== 'undefined') {
|
|
208
221
|
const fs = await import('node:fs/promises')
|
|
209
222
|
await fs.writeFile(filePath, Buffer.from(arrayBuffer))
|
|
210
223
|
}
|
|
@@ -257,7 +270,8 @@ export class TpexProvider implements PluginProvider {
|
|
|
257
270
|
async getPlugin(slug: string): Promise<TpexDetailResponse['plugin'] | null> {
|
|
258
271
|
const res = await fetch(`${this.apiBase}/api/market/plugins/${slug}`)
|
|
259
272
|
if (!res.ok) {
|
|
260
|
-
if (res.status === 404)
|
|
273
|
+
if (res.status === 404)
|
|
274
|
+
return null
|
|
261
275
|
throw new Error(`Failed to fetch plugin: ${res.statusText}`)
|
|
262
276
|
}
|
|
263
277
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { hasWindow } from '../../env'
|
|
2
|
+
|
|
3
|
+
export type BoxItemsAPI = Record<string, any>
|
|
4
|
+
|
|
5
|
+
const DEFAULT_BOX_ITEMS_ERROR
|
|
6
|
+
= '[Feature SDK] boxItems API not available. Make sure this is called in a plugin context.'
|
|
7
|
+
|
|
8
|
+
export function useBoxItems(errorMessage = DEFAULT_BOX_ITEMS_ERROR): BoxItemsAPI {
|
|
9
|
+
const boxItemsApi = hasWindow() ? (window as any)?.$boxItems as BoxItemsAPI | undefined : undefined
|
|
10
|
+
if (!boxItemsApi) {
|
|
11
|
+
throw new Error(errorMessage)
|
|
12
|
+
}
|
|
13
|
+
return boxItemsApi
|
|
14
|
+
}
|
package/plugin/sdk/box-sdk.ts
CHANGED
|
@@ -184,6 +184,39 @@ export interface BoxSDK {
|
|
|
184
184
|
* ```
|
|
185
185
|
*/
|
|
186
186
|
allowClipboard: (types: number) => Promise<void>
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Set CoreBox window to a specific height (60-800px)
|
|
190
|
+
*
|
|
191
|
+
* @param height - Target height in pixels (will be clamped to 60-800)
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```typescript
|
|
195
|
+
* // Set to custom height
|
|
196
|
+
* await plugin.box.setHeight(400)
|
|
197
|
+
* ```
|
|
198
|
+
*/
|
|
199
|
+
setHeight: (height: number) => Promise<void>
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Set CoreBox vertical position as percentage from top (0.1-0.9)
|
|
203
|
+
*
|
|
204
|
+
* @param topPercent - Position from top (0.1 = 10%, 0.5 = 50%, etc.)
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* ```typescript
|
|
208
|
+
* // Position at 40% from top
|
|
209
|
+
* await plugin.box.setPositionOffset(0.4)
|
|
210
|
+
* ```
|
|
211
|
+
*/
|
|
212
|
+
setPositionOffset: (topPercent: number) => Promise<void>
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Get current CoreBox window bounds
|
|
216
|
+
*
|
|
217
|
+
* @returns Window bounds { x, y, width, height }
|
|
218
|
+
*/
|
|
219
|
+
getBounds: () => Promise<{ x: number, y: number, width: number, height: number }>
|
|
187
220
|
}
|
|
188
221
|
|
|
189
222
|
/**
|
|
@@ -298,6 +331,37 @@ export function createBoxSDK(channel: ITouchClientChannel): BoxSDK {
|
|
|
298
331
|
throw error
|
|
299
332
|
}
|
|
300
333
|
},
|
|
334
|
+
|
|
335
|
+
async setHeight(height: number): Promise<void> {
|
|
336
|
+
try {
|
|
337
|
+
await channel.send('core-box:set-height', { height })
|
|
338
|
+
}
|
|
339
|
+
catch (error) {
|
|
340
|
+
console.error('[Box SDK] Failed to set height:', error)
|
|
341
|
+
throw error
|
|
342
|
+
}
|
|
343
|
+
},
|
|
344
|
+
|
|
345
|
+
async setPositionOffset(topPercent: number): Promise<void> {
|
|
346
|
+
try {
|
|
347
|
+
await channel.send('core-box:set-position-offset', { topPercent })
|
|
348
|
+
}
|
|
349
|
+
catch (error) {
|
|
350
|
+
console.error('[Box SDK] Failed to set position offset:', error)
|
|
351
|
+
throw error
|
|
352
|
+
}
|
|
353
|
+
},
|
|
354
|
+
|
|
355
|
+
async getBounds(): Promise<{ x: number, y: number, width: number, height: number }> {
|
|
356
|
+
try {
|
|
357
|
+
const result = await channel.send('core-box:get-bounds')
|
|
358
|
+
return result.bounds
|
|
359
|
+
}
|
|
360
|
+
catch (error) {
|
|
361
|
+
console.error('[Box SDK] Failed to get bounds:', error)
|
|
362
|
+
throw error
|
|
363
|
+
}
|
|
364
|
+
},
|
|
301
365
|
}
|
|
302
366
|
}
|
|
303
367
|
|
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'
|