@talex-touch/utils 1.0.40 → 1.0.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintcache +1 -0
- package/__tests__/cloud-sync-sdk.test.ts +442 -0
- package/__tests__/icons/icons.test.ts +84 -0
- package/__tests__/plugin-sdk-lifecycle.test.ts +130 -0
- package/__tests__/power-sdk.test.ts +143 -0
- package/__tests__/preset-export-types.test.ts +108 -0
- package/__tests__/search/fuzzy-match.test.ts +137 -0
- package/__tests__/transport/port-policy.test.ts +44 -0
- package/__tests__/transport-domain-sdks.test.ts +152 -0
- package/__tests__/types/update.test.ts +67 -0
- package/account/account-sdk.ts +915 -0
- package/account/index.ts +2 -0
- package/account/types.ts +321 -0
- package/analytics/client.ts +136 -0
- package/analytics/index.ts +2 -0
- package/analytics/types.ts +156 -0
- package/animation/auto-resize.ts +322 -0
- package/animation/window-node.ts +26 -19
- package/auth/clerk-types.ts +12 -30
- package/auth/index.ts +0 -2
- package/auth/useAuthState.ts +6 -14
- package/base/index.ts +2 -0
- package/base/log-level.ts +105 -0
- package/channel/index.ts +170 -69
- package/cloud-sync/cloud-sync-sdk.ts +450 -0
- package/cloud-sync/index.ts +1 -0
- package/common/file-scan-utils.ts +17 -9
- package/common/index.ts +4 -0
- package/common/logger/index.ts +46 -0
- package/common/logger/logger-manager.ts +303 -0
- package/common/logger/module-logger.ts +270 -0
- package/common/logger/transport-logger.ts +234 -0
- package/common/logger/types.ts +93 -0
- package/common/search/gather.ts +48 -6
- package/common/search/index.ts +8 -0
- package/common/storage/constants.ts +13 -0
- package/common/storage/entity/app-settings.ts +245 -0
- package/common/storage/entity/index.ts +3 -0
- package/common/storage/entity/layout-atom-types.ts +147 -0
- package/common/storage/entity/openers.ts +1 -0
- package/common/storage/entity/preset-cloud-api.ts +132 -0
- package/common/storage/entity/preset-export-types.ts +256 -0
- package/common/storage/entity/shortcut-settings.ts +1 -0
- package/common/storage/shortcut-storage.ts +11 -0
- package/common/utils/clone-diagnostics.ts +105 -0
- package/common/utils/file.ts +16 -8
- package/common/utils/index.ts +6 -2
- package/common/utils/payload-preview.ts +173 -0
- package/common/utils/polling.ts +167 -13
- package/common/utils/safe-path.ts +103 -0
- package/common/utils/safe-shell.ts +115 -0
- package/common/utils/task-queue.ts +4 -1
- package/core-box/builder/tuff-builder.ts +0 -1
- package/core-box/index.ts +1 -1
- package/core-box/recommendation.ts +38 -1
- package/core-box/tuff/tuff-dsl.ts +97 -0
- package/electron/download-manager.ts +10 -7
- package/electron/env-tool.ts +42 -40
- package/electron/index.ts +0 -1
- package/env/index.ts +156 -0
- package/eslint.config.js +55 -0
- package/i18n/index.ts +62 -0
- package/i18n/locales/en.json +226 -0
- package/i18n/locales/zh.json +226 -0
- package/i18n/message-keys.ts +236 -0
- package/i18n/resolver.ts +181 -0
- package/icons/index.ts +257 -0
- package/icons/svg.ts +69 -0
- package/index.ts +9 -1
- package/intelligence/client.ts +72 -42
- package/market/constants.ts +21 -3
- package/market/index.ts +1 -1
- package/market/types.ts +20 -5
- package/package.json +15 -5
- package/permission/index.ts +143 -46
- package/permission/legacy.ts +26 -0
- package/permission/registry.ts +304 -0
- package/permission/types.ts +164 -0
- package/plugin/channel.ts +68 -39
- package/plugin/index.ts +82 -8
- package/plugin/install.ts +3 -0
- package/plugin/log/types.ts +22 -5
- package/plugin/node/logger-manager.ts +11 -3
- package/plugin/node/logger.ts +24 -17
- package/plugin/preload.ts +25 -2
- package/plugin/providers/index.ts +4 -0
- package/plugin/providers/market-client.ts +218 -0
- package/plugin/providers/npm-provider.ts +228 -0
- package/plugin/providers/tpex-provider.ts +297 -0
- package/plugin/providers/tpex-types.ts +34 -0
- package/plugin/sdk/box-items.ts +14 -0
- package/plugin/sdk/box-sdk.ts +64 -0
- package/plugin/sdk/channel.ts +119 -4
- package/plugin/sdk/clipboard.ts +26 -12
- package/plugin/sdk/cloud-sync.ts +113 -0
- package/plugin/sdk/common.ts +19 -11
- package/plugin/sdk/core-box.ts +6 -15
- package/plugin/sdk/division-box.ts +160 -65
- package/plugin/sdk/examples/storage-onDidChange-example.js +5 -2
- package/plugin/sdk/feature-sdk.ts +111 -76
- package/plugin/sdk/flow.ts +146 -45
- package/plugin/sdk/hooks/bridge.ts +113 -49
- package/plugin/sdk/hooks/life-cycle.ts +35 -16
- package/plugin/sdk/index.ts +14 -3
- package/plugin/sdk/intelligence.ts +87 -0
- package/plugin/sdk/meta/README.md +179 -0
- package/plugin/sdk/meta-sdk.ts +244 -0
- package/plugin/sdk/notification.ts +9 -0
- package/plugin/sdk/performance.ts +1 -16
- package/plugin/sdk/plugin-info.ts +64 -0
- package/plugin/sdk/power.ts +155 -0
- package/plugin/sdk/recommend.ts +21 -0
- package/plugin/sdk/service/index.ts +12 -8
- package/plugin/sdk/sqlite.ts +141 -0
- package/plugin/sdk/storage.ts +2 -6
- package/plugin/sdk/system.ts +2 -9
- package/plugin/sdk/temp-files.ts +41 -0
- package/plugin/sdk/touch-sdk.ts +18 -0
- package/plugin/sdk/types.ts +44 -4
- package/plugin/sdk/window/index.ts +12 -9
- package/plugin/sdk-version.ts +231 -0
- package/preload/renderer.ts +3 -2
- package/renderer/hooks/arg-mapper.ts +34 -6
- package/renderer/hooks/index.ts +13 -0
- package/renderer/hooks/initialize.ts +2 -1
- package/renderer/hooks/use-agent-market-sdk.ts +7 -0
- package/renderer/hooks/use-agent-market.ts +106 -0
- package/renderer/hooks/use-agents-sdk.ts +7 -0
- package/renderer/hooks/use-app-sdk.ts +7 -0
- package/renderer/hooks/use-channel.ts +33 -4
- package/renderer/hooks/use-download-sdk.ts +21 -0
- package/renderer/hooks/use-intelligence-sdk.ts +7 -0
- package/renderer/hooks/use-intelligence-stats.ts +290 -0
- package/renderer/hooks/use-intelligence.ts +202 -104
- package/renderer/hooks/use-market-sdk.ts +16 -0
- package/renderer/hooks/use-notification-sdk.ts +7 -0
- package/renderer/hooks/use-permission-sdk.ts +7 -0
- package/renderer/hooks/use-permission.ts +325 -0
- package/renderer/hooks/use-platform-sdk.ts +7 -0
- package/renderer/hooks/use-plugin-sdk.ts +16 -0
- package/renderer/hooks/use-settings-sdk.ts +7 -0
- package/renderer/hooks/use-update-sdk.ts +21 -0
- package/renderer/index.ts +1 -0
- package/renderer/ref.ts +19 -10
- package/renderer/shared/components/SharedPluginDetailContent.vue +84 -0
- package/renderer/shared/components/SharedPluginDetailHeader.vue +116 -0
- package/renderer/shared/components/SharedPluginDetailMetaList.vue +39 -0
- package/renderer/shared/components/SharedPluginDetailReadme.vue +45 -0
- package/renderer/shared/components/SharedPluginDetailVersions.vue +98 -0
- package/renderer/shared/components/index.ts +5 -0
- package/renderer/shared/components/shims-vue.d.ts +5 -0
- package/renderer/shared/index.ts +2 -0
- package/renderer/shared/plugin-detail.ts +62 -0
- package/renderer/storage/app-settings.ts +3 -1
- package/renderer/storage/base-storage.ts +508 -82
- package/renderer/storage/intelligence-storage.ts +37 -46
- package/renderer/storage/openers.ts +3 -1
- package/renderer/storage/storage-subscription.ts +126 -42
- package/renderer/touch-sdk/env.ts +10 -10
- package/renderer/touch-sdk/index.ts +114 -18
- package/renderer/touch-sdk/terminal.ts +24 -13
- package/search/feature-matcher.ts +279 -0
- package/search/fuzzy-match.ts +64 -34
- package/search/index.ts +10 -0
- package/search/levenshtein-utils.ts +17 -11
- package/transport/errors.ts +310 -0
- package/transport/event/builder.ts +378 -0
- package/transport/event/index.ts +7 -0
- package/transport/event/types.ts +292 -0
- package/transport/events/index.ts +2670 -0
- package/transport/events/meta-overlay.ts +79 -0
- package/transport/events/types/agents.ts +177 -0
- package/transport/events/types/app-index.ts +9 -0
- package/transport/events/types/app.ts +475 -0
- package/transport/events/types/box-item.ts +222 -0
- package/transport/events/types/clipboard.ts +80 -0
- package/transport/events/types/core-box.ts +534 -0
- package/transport/events/types/device-idle.ts +7 -0
- package/transport/events/types/division-box.ts +99 -0
- package/transport/events/types/download.ts +115 -0
- package/transport/events/types/file-index.ts +73 -0
- package/transport/events/types/flow.ts +149 -0
- package/transport/events/types/index.ts +70 -0
- package/transport/events/types/market.ts +39 -0
- package/transport/events/types/meta-overlay.ts +184 -0
- package/transport/events/types/notification.ts +140 -0
- package/transport/events/types/permission.ts +90 -0
- package/transport/events/types/platform.ts +8 -0
- package/transport/events/types/plugin.ts +620 -0
- package/transport/events/types/sentry.ts +20 -0
- package/transport/events/types/storage.ts +208 -0
- package/transport/events/types/transport.ts +60 -0
- package/transport/events/types/tray.ts +16 -0
- package/transport/events/types/update.ts +78 -0
- package/transport/index.ts +139 -0
- package/transport/main.ts +2 -0
- package/transport/sdk/constants.ts +29 -0
- package/transport/sdk/domains/agents-market.ts +47 -0
- package/transport/sdk/domains/agents.ts +62 -0
- package/transport/sdk/domains/app.ts +48 -0
- package/transport/sdk/domains/disposable.ts +35 -0
- package/transport/sdk/domains/download.ts +139 -0
- package/transport/sdk/domains/index.ts +13 -0
- package/transport/sdk/domains/intelligence.ts +616 -0
- package/transport/sdk/domains/market.ts +35 -0
- package/transport/sdk/domains/notification.ts +62 -0
- package/transport/sdk/domains/permission.ts +85 -0
- package/transport/sdk/domains/platform.ts +19 -0
- package/transport/sdk/domains/plugin.ts +144 -0
- package/transport/sdk/domains/settings.ts +92 -0
- package/transport/sdk/domains/update.ts +64 -0
- package/transport/sdk/index.ts +60 -0
- package/transport/sdk/main-transport.ts +710 -0
- package/transport/sdk/main.ts +9 -0
- package/transport/sdk/plugin-transport.ts +654 -0
- package/transport/sdk/port-policy.ts +38 -0
- package/transport/sdk/renderer-transport.ts +1165 -0
- package/transport/types.ts +605 -0
- package/types/agent.ts +399 -0
- package/types/cloud-sync.ts +157 -0
- package/types/division-box.ts +47 -27
- package/types/download.ts +1 -0
- package/types/flow.ts +63 -12
- package/types/icon.ts +2 -1
- package/types/index.ts +5 -0
- package/types/intelligence.ts +1492 -81
- package/types/modules/base.ts +2 -0
- package/types/path-browserify.d.ts +5 -0
- package/types/platform.ts +12 -0
- package/types/startup-info.ts +32 -0
- package/types/touch-app-core.ts +8 -8
- package/types/update.ts +94 -1
- package/vitest.config.ts +25 -0
- package/auth/useClerkConfig.ts +0 -40
- package/auth/useClerkProvider.ts +0 -52
package/plugin/index.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type { Arch, SupportOS } from './../base/index'
|
|
|
4
4
|
|
|
5
5
|
import type { IPluginLogger } from './log/types'
|
|
6
6
|
|
|
7
|
-
import type { PluginInstallRequest, PluginInstallSummary } from './providers'
|
|
7
|
+
import type { PluginInstallRequest, PluginInstallSummary } from './providers/types'
|
|
8
8
|
|
|
9
9
|
export enum PluginStatus {
|
|
10
10
|
DISABLED,
|
|
@@ -33,6 +33,14 @@ export interface PluginIssue {
|
|
|
33
33
|
timestamp?: number
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
export interface PluginMeta {
|
|
37
|
+
/**
|
|
38
|
+
* Internal plugins are created in code (no manifest / scanning).
|
|
39
|
+
* They should be hidden in UI unless developer mode is enabled.
|
|
40
|
+
*/
|
|
41
|
+
internal?: boolean
|
|
42
|
+
}
|
|
43
|
+
|
|
36
44
|
export interface DevServerHealthCheckResult {
|
|
37
45
|
healthy: boolean
|
|
38
46
|
version?: string
|
|
@@ -68,13 +76,44 @@ export interface IPluginDev {
|
|
|
68
76
|
source?: boolean
|
|
69
77
|
}
|
|
70
78
|
|
|
79
|
+
/**
|
|
80
|
+
* SDK API version for plugin compatibility checking.
|
|
81
|
+
* Format: YYMMDD (e.g., 251212 = 2025-12-12)
|
|
82
|
+
*
|
|
83
|
+
* Rules:
|
|
84
|
+
* - Not declared or < PERMISSION_ENFORCEMENT_MIN_VERSION: legacy mode (permissions bypassed)
|
|
85
|
+
* - >= PERMISSION_ENFORCEMENT_MIN_VERSION: permissions enforced
|
|
86
|
+
*/
|
|
87
|
+
export type SdkApiVersion = number
|
|
88
|
+
|
|
71
89
|
export interface ITouchPlugin extends IPluginBaseInfo {
|
|
72
90
|
dev: IPluginDev
|
|
73
91
|
pluginPath: string
|
|
74
92
|
logger: IPluginLogger<any>
|
|
93
|
+
/**
|
|
94
|
+
* Category id synced with Nexus (e.g., 'utilities', 'productivity').
|
|
95
|
+
* Used for UI grouping and marketplace filtering.
|
|
96
|
+
*/
|
|
97
|
+
category?: string
|
|
98
|
+
meta?: PluginMeta
|
|
75
99
|
features: IPluginFeature[]
|
|
76
100
|
issues: PluginIssue[]
|
|
77
101
|
divisionBoxConfig?: import('../types/division-box').ManifestDivisionBoxConfig
|
|
102
|
+
/**
|
|
103
|
+
* SDK API version declared by the plugin.
|
|
104
|
+
* Used for compatibility checking and permission enforcement.
|
|
105
|
+
* Format: YYMMDD (e.g., 251212)
|
|
106
|
+
*/
|
|
107
|
+
sdkapi?: SdkApiVersion
|
|
108
|
+
/**
|
|
109
|
+
* Declared permissions from manifest.
|
|
110
|
+
* Used for permission checking and UI display.
|
|
111
|
+
*/
|
|
112
|
+
declaredPermissions?: {
|
|
113
|
+
required: string[]
|
|
114
|
+
optional: string[]
|
|
115
|
+
reasons: Record<string, string>
|
|
116
|
+
}
|
|
78
117
|
|
|
79
118
|
addFeature: (feature: IPluginFeature) => boolean
|
|
80
119
|
delFeature: (featureId: string) => boolean
|
|
@@ -102,14 +141,21 @@ export interface ITouchPlugin extends IPluginBaseInfo {
|
|
|
102
141
|
* @param content The content of the file.
|
|
103
142
|
* @returns The result of the save operation.
|
|
104
143
|
*/
|
|
105
|
-
savePluginFile: (
|
|
144
|
+
savePluginFile: (
|
|
145
|
+
fileName: string,
|
|
146
|
+
content: object,
|
|
147
|
+
options?: { broadcast?: boolean }
|
|
148
|
+
) => { success: boolean, error?: string }
|
|
106
149
|
|
|
107
150
|
/**
|
|
108
151
|
* Delete the plugin file.
|
|
109
152
|
* @param fileName The name of the file.
|
|
110
153
|
* @returns The result of the delete operation.
|
|
111
154
|
*/
|
|
112
|
-
deletePluginFile: (
|
|
155
|
+
deletePluginFile: (
|
|
156
|
+
fileName: string,
|
|
157
|
+
options?: { broadcast?: boolean }
|
|
158
|
+
) => { success: boolean, error?: string }
|
|
113
159
|
|
|
114
160
|
/**
|
|
115
161
|
* List all files in the plugin.
|
|
@@ -133,10 +179,13 @@ export interface ITouchPlugin extends IPluginBaseInfo {
|
|
|
133
179
|
|
|
134
180
|
export interface IFeatureCommand {
|
|
135
181
|
type: 'match' | 'contain' | 'regex' | 'function' | 'over' | 'image' | 'files' | 'directory' | 'window'
|
|
136
|
-
value: string | string[] | RegExp |
|
|
137
|
-
|
|
182
|
+
value: string | string[] | RegExp | FeatureCommandMatcher
|
|
183
|
+
/** Optional trigger callback - not serialized over IPC */
|
|
184
|
+
onTrigger?: () => void
|
|
138
185
|
}
|
|
139
186
|
|
|
187
|
+
export type FeatureCommandMatcher = (queryText: string) => boolean
|
|
188
|
+
|
|
140
189
|
export interface IPluginFeature {
|
|
141
190
|
id: string
|
|
142
191
|
name: string
|
|
@@ -147,6 +196,10 @@ export interface IPluginFeature {
|
|
|
147
196
|
platform: IPlatform
|
|
148
197
|
commands: IFeatureCommand[]
|
|
149
198
|
interaction?: IFeatureInteraction
|
|
199
|
+
/**
|
|
200
|
+
* Experimental features are hidden unless the plugin runs in dev mode.
|
|
201
|
+
*/
|
|
202
|
+
experimental?: boolean
|
|
150
203
|
/**
|
|
151
204
|
* Internal search tokens generated at runtime for better matching
|
|
152
205
|
*/
|
|
@@ -174,6 +227,17 @@ export interface IFeatureInteraction {
|
|
|
174
227
|
* The relative path to the html file from the plugin root.
|
|
175
228
|
*/
|
|
176
229
|
path?: string
|
|
230
|
+
/**
|
|
231
|
+
* Whether to show the input field in CoreBox when this feature is active.
|
|
232
|
+
* Defaults to true for webcontent type.
|
|
233
|
+
*/
|
|
234
|
+
showInput?: boolean
|
|
235
|
+
/**
|
|
236
|
+
* Whether to automatically enable input monitoring for this feature.
|
|
237
|
+
* If true, plugin will receive input change events without calling allowInput().
|
|
238
|
+
* Defaults to true for webcontent features.
|
|
239
|
+
*/
|
|
240
|
+
allowInput?: boolean
|
|
177
241
|
}
|
|
178
242
|
|
|
179
243
|
/**
|
|
@@ -390,6 +454,16 @@ export interface IManifest {
|
|
|
390
454
|
* Version of the plugin, following semantic versioning (e.g., "1.0.0").
|
|
391
455
|
*/
|
|
392
456
|
version: string
|
|
457
|
+
/**
|
|
458
|
+
* SDK API version for compatibility checking.
|
|
459
|
+
* Format: YYMMDD (e.g., 251212 = 2025-12-12)
|
|
460
|
+
* Plugins without this field or with version < 251212 will bypass permission enforcement.
|
|
461
|
+
*/
|
|
462
|
+
sdkapi?: SdkApiVersion
|
|
463
|
+
/**
|
|
464
|
+
* Category id synced with Nexus (e.g., 'utilities', 'productivity').
|
|
465
|
+
*/
|
|
466
|
+
category?: string
|
|
393
467
|
/**
|
|
394
468
|
* Short description of the plugin's functionality.
|
|
395
469
|
*/
|
|
@@ -499,8 +573,8 @@ export interface IManifest {
|
|
|
499
573
|
}
|
|
500
574
|
|
|
501
575
|
export * from './install'
|
|
502
|
-
export type { IPluginLogger, LogDataType, LogItem
|
|
503
|
-
export * from './providers'
|
|
576
|
+
export type { IPluginLogger, LogDataType, LogItem } from './log/types'
|
|
504
577
|
export * from './risk'
|
|
505
|
-
export * from './sdk
|
|
578
|
+
export * from './sdk-version'
|
|
579
|
+
// Plugin runtime SDK should be imported from `@talex-touch/utils/plugin/sdk` to avoid root export collisions.
|
|
506
580
|
export * from './widget'
|
package/plugin/install.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export type PluginInstallTaskStage
|
|
2
2
|
= | 'queued'
|
|
3
3
|
| 'downloading'
|
|
4
|
+
| 'verifying'
|
|
4
5
|
| 'awaiting-confirmation'
|
|
5
6
|
| 'installing'
|
|
6
7
|
| 'completed'
|
|
@@ -20,6 +21,8 @@ export interface PluginInstallProgressEvent {
|
|
|
20
21
|
/** 插件唯一标识或名称(由客户端提供)。 */
|
|
21
22
|
pluginId?: string
|
|
22
23
|
pluginName?: string
|
|
24
|
+
/** 来源提供者 ID,用于区分不同市场源的同名插件。 */
|
|
25
|
+
providerId?: string
|
|
23
26
|
/** 队列中的剩余任务数量(包含当前任务)。 */
|
|
24
27
|
remaining?: number
|
|
25
28
|
/** 当前任务在队列中的位置(0 表示正在处理)。 */
|
package/plugin/log/types.ts
CHANGED
|
@@ -1,7 +1,24 @@
|
|
|
1
|
+
import type { LogLevelString as BaseLogLevelString } from '../../base/log-level'
|
|
1
2
|
/**
|
|
2
|
-
*
|
|
3
|
+
* Re-export unified LogLevel from base
|
|
3
4
|
*/
|
|
4
|
-
|
|
5
|
+
import {
|
|
6
|
+
LogLevel as BaseLogLevel,
|
|
7
|
+
|
|
8
|
+
logLevelToString as baseLogLevelToString,
|
|
9
|
+
stringToLogLevel as baseStringToLogLevel,
|
|
10
|
+
} from '../../base/log-level'
|
|
11
|
+
|
|
12
|
+
export const LogLevel = BaseLogLevel
|
|
13
|
+
export type LogLevelString = BaseLogLevelString
|
|
14
|
+
export const logLevelToString = baseLogLevelToString
|
|
15
|
+
export const stringToLogLevel = baseStringToLogLevel
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Legacy string-based log level type (for backward compatibility)
|
|
19
|
+
* @deprecated Use LogLevel enum instead
|
|
20
|
+
*/
|
|
21
|
+
export type LogLevelLegacy = 'INFO' | 'WARN' | 'ERROR' | 'DEBUG'
|
|
5
22
|
|
|
6
23
|
/**
|
|
7
24
|
* Supported data types for logging arguments.
|
|
@@ -14,8 +31,8 @@ export type LogDataType = string | number | boolean | object
|
|
|
14
31
|
export interface LogItem {
|
|
15
32
|
/** ISO timestamp when the log was created */
|
|
16
33
|
timestamp: string
|
|
17
|
-
/** Logging severity level */
|
|
18
|
-
level:
|
|
34
|
+
/** Logging severity level (uppercase string for storage compatibility) */
|
|
35
|
+
level: LogLevelString
|
|
19
36
|
/** Plugin name */
|
|
20
37
|
plugin: string
|
|
21
38
|
/** Main log message */
|
|
@@ -27,7 +44,7 @@ export interface LogItem {
|
|
|
27
44
|
}
|
|
28
45
|
|
|
29
46
|
/**
|
|
30
|
-
* Minimal contract for plugin loggers
|
|
47
|
+
* Minimal contract for plugin loggers
|
|
31
48
|
*/
|
|
32
49
|
export interface IPluginLogger<TManager = unknown> {
|
|
33
50
|
info: (...args: LogDataType[]) => void
|
|
@@ -3,6 +3,7 @@ import type { LogItem } from '../log/types'
|
|
|
3
3
|
import fs from 'node:fs'
|
|
4
4
|
import path from 'node:path'
|
|
5
5
|
import { structuredStrictStringify } from '@talex-touch/utils'
|
|
6
|
+
import { PollingService } from '../../common/utils/polling'
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* PluginLoggerManager is responsible for managing and writing logs for a specific plugin.
|
|
@@ -14,7 +15,8 @@ export class PluginLoggerManager {
|
|
|
14
15
|
private readonly pluginInfoPath: string
|
|
15
16
|
private readonly sessionStart: string
|
|
16
17
|
private buffer: LogItem[] = []
|
|
17
|
-
private
|
|
18
|
+
private readonly pollingService = PollingService.getInstance()
|
|
19
|
+
private readonly flushTaskId: string
|
|
18
20
|
private onLogAppend?: (log: LogItem) => void
|
|
19
21
|
|
|
20
22
|
/**
|
|
@@ -33,9 +35,15 @@ export class PluginLoggerManager {
|
|
|
33
35
|
this.pluginLogDir = path.resolve(baseDir, 'logs', sessionFolder)
|
|
34
36
|
this.sessionLogPath = path.resolve(this.pluginLogDir, 'session.log')
|
|
35
37
|
this.pluginInfoPath = path.resolve(this.pluginLogDir, 'touch-plugin.info')
|
|
38
|
+
this.flushTaskId = `plugin-logger.flush.${pluginInfo.name}.${Date.now()}`
|
|
36
39
|
|
|
37
40
|
this.ensureLogEnvironment(true)
|
|
38
|
-
this.
|
|
41
|
+
this.pollingService.register(
|
|
42
|
+
this.flushTaskId,
|
|
43
|
+
() => this.flush(),
|
|
44
|
+
{ interval: 5, unit: 'seconds' },
|
|
45
|
+
)
|
|
46
|
+
this.pollingService.start()
|
|
39
47
|
}
|
|
40
48
|
|
|
41
49
|
/**
|
|
@@ -89,7 +97,7 @@ export class PluginLoggerManager {
|
|
|
89
97
|
* Stops the flush interval and ensures remaining logs are written.
|
|
90
98
|
*/
|
|
91
99
|
destroy(): void {
|
|
92
|
-
|
|
100
|
+
this.pollingService.unregister(this.flushTaskId)
|
|
93
101
|
this.flush()
|
|
94
102
|
}
|
|
95
103
|
|
package/plugin/node/logger.ts
CHANGED
|
@@ -1,7 +1,18 @@
|
|
|
1
|
-
import type { IPluginLogger, LogDataType, LogItem,
|
|
1
|
+
import type { IPluginLogger, LogDataType, LogItem, LogLevelString } from '../log/types'
|
|
2
2
|
import type { PluginLoggerManager } from './logger-manager'
|
|
3
|
+
import process from 'node:process'
|
|
4
|
+
import { inspect } from 'node:util'
|
|
3
5
|
import chalk from 'chalk'
|
|
4
6
|
|
|
7
|
+
const pluginLogStdout =
|
|
8
|
+
process.env.TALEX_PLUGIN_LOG_STDOUT === '1' || process.env.TALEX_PLUGIN_LOG_STDOUT === 'true'
|
|
9
|
+
const defaultStdoutLevels = new Set<LogLevelString>(['WARN', 'ERROR'])
|
|
10
|
+
|
|
11
|
+
function shouldWriteToStdout(level: LogLevelString): boolean {
|
|
12
|
+
if (pluginLogStdout) return true
|
|
13
|
+
return defaultStdoutLevels.has(level)
|
|
14
|
+
}
|
|
15
|
+
|
|
5
16
|
/**
|
|
6
17
|
* PluginLogger provides structured logging capabilities for individual plugins.
|
|
7
18
|
*/
|
|
@@ -61,13 +72,13 @@ export class PluginLogger implements IPluginLogger<PluginLoggerManager> {
|
|
|
61
72
|
* @param level - The severity level of the log.
|
|
62
73
|
* @param args - The log message and optional data payload.
|
|
63
74
|
*/
|
|
64
|
-
private log(level:
|
|
75
|
+
private log(level: LogLevelString, ...args: LogDataType[]): void {
|
|
65
76
|
const [message, ...data] = args
|
|
66
77
|
|
|
67
78
|
const normalizedLevel = (typeof level === 'string' ? level.toUpperCase() : level) as string
|
|
68
|
-
const allowedLevels:
|
|
69
|
-
const resolvedLevel = (allowedLevels.includes(normalizedLevel as
|
|
70
|
-
? (normalizedLevel as
|
|
79
|
+
const allowedLevels: LogLevelString[] = ['INFO', 'WARN', 'ERROR', 'DEBUG']
|
|
80
|
+
const resolvedLevel = (allowedLevels.includes(normalizedLevel as LogLevelString)
|
|
81
|
+
? (normalizedLevel as LogLevelString)
|
|
71
82
|
: 'INFO')
|
|
72
83
|
if (resolvedLevel === 'INFO' && normalizedLevel !== 'INFO') {
|
|
73
84
|
console.warn(
|
|
@@ -75,11 +86,12 @@ export class PluginLogger implements IPluginLogger<PluginLoggerManager> {
|
|
|
75
86
|
)
|
|
76
87
|
}
|
|
77
88
|
|
|
78
|
-
const levelColorMap: Record<
|
|
89
|
+
const levelColorMap: Record<LogLevelString, (input: string) => string> = {
|
|
79
90
|
INFO: chalk.bgBlue,
|
|
80
91
|
WARN: chalk.bgYellow,
|
|
81
92
|
ERROR: chalk.bgRed,
|
|
82
93
|
DEBUG: chalk.bgGray,
|
|
94
|
+
NONE: chalk.bgBlack,
|
|
83
95
|
}
|
|
84
96
|
const colorize = levelColorMap[resolvedLevel] ?? ((input: string) => input)
|
|
85
97
|
|
|
@@ -93,17 +105,12 @@ export class PluginLogger implements IPluginLogger<PluginLoggerManager> {
|
|
|
93
105
|
}
|
|
94
106
|
this.manager.append(log)
|
|
95
107
|
|
|
96
|
-
if (resolvedLevel
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
else {
|
|
103
|
-
console.log(
|
|
104
|
-
`${chalk.bgMagenta('[PluginLog]')} ${colorize(resolvedLevel)} ${this.pluginName} - ${message}`,
|
|
105
|
-
...data,
|
|
106
|
-
)
|
|
108
|
+
if (shouldWriteToStdout(resolvedLevel)) {
|
|
109
|
+
const baseMessage = `${chalk.bgMagenta('[PluginLog]')} ${colorize(resolvedLevel)} ${this.pluginName} - ${message}`
|
|
110
|
+
const extra = data.length
|
|
111
|
+
? ` ${data.map(item => (typeof item === 'string' ? item : inspect(item))).join(' ')}`
|
|
112
|
+
: ''
|
|
113
|
+
process.stdout.write(`${baseMessage}${extra}\n`)
|
|
107
114
|
}
|
|
108
115
|
}
|
|
109
116
|
}
|
package/plugin/preload.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { ITouchClientChannel } from '../channel'
|
|
2
|
+
import type { ITuffTransport } from '../transport'
|
|
2
3
|
import type { ITouchSDK } from './sdk/index'
|
|
4
|
+
import { getLogger } from '../common/logger'
|
|
5
|
+
import { createPluginTuffTransport } from '../transport'
|
|
6
|
+
import { defineRawEvent } from '../transport/event/builder'
|
|
3
7
|
// Import SDK for side effects (initializes hooks)
|
|
4
8
|
import './sdk/index'
|
|
5
9
|
|
|
@@ -9,8 +13,11 @@ declare global {
|
|
|
9
13
|
$plugin: {
|
|
10
14
|
name: string
|
|
11
15
|
path: object
|
|
16
|
+
version?: string
|
|
17
|
+
sdkapi?: number
|
|
12
18
|
}
|
|
13
19
|
$channel: ITouchClientChannel
|
|
20
|
+
$transport?: ITuffTransport
|
|
14
21
|
$crash: (message: string, extraData: any) => void
|
|
15
22
|
$config: {
|
|
16
23
|
themeStyle: any
|
|
@@ -19,14 +26,30 @@ declare global {
|
|
|
19
26
|
}
|
|
20
27
|
}
|
|
21
28
|
|
|
29
|
+
const preloadLog = getLogger('plugin-preload')
|
|
30
|
+
const crashEvent = defineRawEvent<Record<string, string | number | boolean | undefined>, void>('crash')
|
|
31
|
+
|
|
22
32
|
export function initTuff(window: Window) {
|
|
23
33
|
const plugin = window.$plugin
|
|
24
34
|
if (!plugin)
|
|
25
35
|
throw new Error('Plugin has a fatal error! Please check your plugin!')
|
|
26
36
|
|
|
37
|
+
if (!window.$transport && window.$channel) {
|
|
38
|
+
window.$transport = createPluginTuffTransport(window.$channel)
|
|
39
|
+
}
|
|
40
|
+
if (window.$transport) {
|
|
41
|
+
window.addEventListener?.('beforeunload', () => {
|
|
42
|
+
window.$transport?.destroy()
|
|
43
|
+
}, { once: true })
|
|
44
|
+
}
|
|
45
|
+
|
|
27
46
|
window.$crash = function (message, extraData) {
|
|
28
|
-
window.$
|
|
47
|
+
if (window.$transport) {
|
|
48
|
+
void window.$transport.send(crashEvent, { message, ...extraData })
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
window.$channel?.send?.('crash', { message, ...extraData })
|
|
29
52
|
}
|
|
30
53
|
|
|
31
|
-
|
|
54
|
+
preloadLog.info(`[Plugin] ${plugin.name} loaded`)
|
|
32
55
|
}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import type { NpmPackageInfo } from './npm-provider'
|
|
2
|
+
import type { TpexPluginInfo } from './tpex-provider'
|
|
3
|
+
import { NpmProvider } from './npm-provider'
|
|
4
|
+
import { TpexProvider } from './tpex-provider'
|
|
5
|
+
import { PluginProviderType } from './types'
|
|
6
|
+
|
|
7
|
+
export type PluginSourceType = 'tpex' | 'npm' | 'all'
|
|
8
|
+
|
|
9
|
+
export interface MarketPluginInfo {
|
|
10
|
+
id: string
|
|
11
|
+
name: string
|
|
12
|
+
slug: string
|
|
13
|
+
version: string
|
|
14
|
+
description: string
|
|
15
|
+
author: string
|
|
16
|
+
icon?: string
|
|
17
|
+
source: PluginSourceType
|
|
18
|
+
isOfficial: boolean
|
|
19
|
+
downloads?: number
|
|
20
|
+
category?: string
|
|
21
|
+
keywords?: string[]
|
|
22
|
+
homepage?: string
|
|
23
|
+
packageUrl?: string
|
|
24
|
+
raw: TpexPluginInfo | NpmPackageInfo
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface MarketSearchOptions {
|
|
28
|
+
keyword?: string
|
|
29
|
+
source?: PluginSourceType
|
|
30
|
+
category?: string
|
|
31
|
+
limit?: number
|
|
32
|
+
offset?: number
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface MarketSearchResult {
|
|
36
|
+
plugins: MarketPluginInfo[]
|
|
37
|
+
total: number
|
|
38
|
+
sources: {
|
|
39
|
+
tpex: number
|
|
40
|
+
npm: number
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function normalizeTpexPlugin(plugin: TpexPluginInfo): MarketPluginInfo {
|
|
45
|
+
return {
|
|
46
|
+
id: plugin.id,
|
|
47
|
+
name: plugin.name,
|
|
48
|
+
slug: plugin.slug,
|
|
49
|
+
version: plugin.latestVersion?.version ?? '0.0.0',
|
|
50
|
+
description: plugin.summary,
|
|
51
|
+
author: plugin.author?.name ?? 'Unknown',
|
|
52
|
+
icon: plugin.iconUrl ?? undefined,
|
|
53
|
+
source: 'tpex',
|
|
54
|
+
isOfficial: plugin.isOfficial,
|
|
55
|
+
downloads: plugin.installs,
|
|
56
|
+
category: plugin.category,
|
|
57
|
+
homepage: plugin.homepage ?? undefined,
|
|
58
|
+
packageUrl: plugin.latestVersion?.packageUrl,
|
|
59
|
+
raw: plugin,
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function normalizeNpmPlugin(pkg: NpmPackageInfo): MarketPluginInfo {
|
|
64
|
+
const authorName = typeof pkg.author === 'string'
|
|
65
|
+
? pkg.author
|
|
66
|
+
: pkg.author?.name ?? 'Unknown'
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
id: pkg.name,
|
|
70
|
+
name: pkg.name.replace(/^tuff-plugin-/, '').replace(/^@tuff\//, ''),
|
|
71
|
+
slug: pkg.name,
|
|
72
|
+
version: pkg.version,
|
|
73
|
+
description: pkg.description ?? '',
|
|
74
|
+
author: authorName,
|
|
75
|
+
icon: pkg.tuff?.icon,
|
|
76
|
+
source: 'npm',
|
|
77
|
+
isOfficial: pkg.name.startsWith('@tuff/'),
|
|
78
|
+
keywords: pkg.keywords,
|
|
79
|
+
packageUrl: pkg.dist.tarball,
|
|
80
|
+
raw: pkg,
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Unified plugin market client supporting multiple sources
|
|
86
|
+
*/
|
|
87
|
+
export class PluginMarketClient {
|
|
88
|
+
private tpexProvider: TpexProvider
|
|
89
|
+
private npmProvider: NpmProvider
|
|
90
|
+
|
|
91
|
+
constructor(options?: {
|
|
92
|
+
tpexApiBase?: string
|
|
93
|
+
npmRegistry?: string
|
|
94
|
+
}) {
|
|
95
|
+
this.tpexProvider = new TpexProvider(options?.tpexApiBase)
|
|
96
|
+
this.npmProvider = new NpmProvider(options?.npmRegistry)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Search plugins from all sources
|
|
101
|
+
*/
|
|
102
|
+
async search(options: MarketSearchOptions = {}): Promise<MarketSearchResult> {
|
|
103
|
+
const { keyword, source = 'all', limit = 50, offset = 0 } = options
|
|
104
|
+
const results: MarketPluginInfo[] = []
|
|
105
|
+
let tpexCount = 0
|
|
106
|
+
let npmCount = 0
|
|
107
|
+
|
|
108
|
+
if (source === 'all' || source === 'tpex') {
|
|
109
|
+
try {
|
|
110
|
+
const tpexPlugins = keyword
|
|
111
|
+
? await this.tpexProvider.searchPlugins(keyword)
|
|
112
|
+
: await this.tpexProvider.listPlugins()
|
|
113
|
+
|
|
114
|
+
const normalized = tpexPlugins.map(normalizeTpexPlugin)
|
|
115
|
+
results.push(...normalized)
|
|
116
|
+
tpexCount = normalized.length
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
console.warn('[MarketClient] TPEX search failed:', error)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (source === 'all' || source === 'npm') {
|
|
124
|
+
try {
|
|
125
|
+
const npmPlugins = await this.npmProvider.searchPlugins(keyword)
|
|
126
|
+
const normalized = npmPlugins.map(normalizeNpmPlugin)
|
|
127
|
+
results.push(...normalized)
|
|
128
|
+
npmCount = normalized.length
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
console.warn('[MarketClient] NPM search failed:', error)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const sorted = results.sort((a, b) => {
|
|
136
|
+
if (a.isOfficial !== b.isOfficial)
|
|
137
|
+
return a.isOfficial ? -1 : 1
|
|
138
|
+
return (b.downloads ?? 0) - (a.downloads ?? 0)
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
const paginated = sorted.slice(offset, offset + limit)
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
plugins: paginated,
|
|
145
|
+
total: results.length,
|
|
146
|
+
sources: {
|
|
147
|
+
tpex: tpexCount,
|
|
148
|
+
npm: npmCount,
|
|
149
|
+
},
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Get plugin details by identifier
|
|
155
|
+
*/
|
|
156
|
+
async getPlugin(identifier: string, source?: PluginSourceType): Promise<MarketPluginInfo | null> {
|
|
157
|
+
if (source === 'tpex' || (!source && !identifier.includes('/'))) {
|
|
158
|
+
try {
|
|
159
|
+
const plugin = await this.tpexProvider.getPlugin(identifier)
|
|
160
|
+
if (plugin)
|
|
161
|
+
return normalizeTpexPlugin(plugin)
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
// Fall through to npm
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (source === 'npm' || !source) {
|
|
169
|
+
try {
|
|
170
|
+
const pkg = await this.npmProvider.getPackageInfo(identifier)
|
|
171
|
+
if (pkg)
|
|
172
|
+
return normalizeNpmPlugin(pkg)
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
// Not found
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return null
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Get install source string for a plugin
|
|
184
|
+
*/
|
|
185
|
+
getInstallSource(plugin: MarketPluginInfo): string {
|
|
186
|
+
if (plugin.source === 'tpex') {
|
|
187
|
+
return `tpex:${plugin.slug}`
|
|
188
|
+
}
|
|
189
|
+
return `npm:${plugin.id}`
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Get provider type for a plugin
|
|
194
|
+
*/
|
|
195
|
+
getProviderType(plugin: MarketPluginInfo): PluginProviderType {
|
|
196
|
+
return plugin.source === 'tpex'
|
|
197
|
+
? PluginProviderType.TPEX
|
|
198
|
+
: PluginProviderType.NPM
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* List all plugins from official source (TPEX)
|
|
203
|
+
*/
|
|
204
|
+
async listOfficialPlugins(): Promise<MarketPluginInfo[]> {
|
|
205
|
+
const plugins = await this.tpexProvider.listPlugins()
|
|
206
|
+
return plugins.map(normalizeTpexPlugin)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* List all plugins from npm
|
|
211
|
+
*/
|
|
212
|
+
async listNpmPlugins(): Promise<MarketPluginInfo[]> {
|
|
213
|
+
const plugins = await this.npmProvider.listPlugins()
|
|
214
|
+
return plugins.map(normalizeNpmPlugin)
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export const defaultMarketClient = new PluginMarketClient()
|