@talex-touch/utils 1.0.23 → 1.0.25
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/common/file-scan-constants.ts +543 -0
- package/common/file-scan-utils.ts +432 -0
- package/common/index.ts +2 -0
- package/common/storage/entity/app-settings.ts +7 -1
- package/common/utils/polling.ts +4 -4
- package/common/utils/timing.ts +257 -13
- package/core-box/tuff/tuff-dsl.ts +17 -0
- package/package.json +1 -1
- package/plugin/index.ts +78 -3
- package/plugin/sdk/common.ts +63 -14
- package/plugin/sdk/core-box.ts +27 -0
- package/plugin/sdk/examples/storage-onDidChange-example.js +201 -0
- package/plugin/sdk/features.ts +324 -0
- package/plugin/sdk/index.ts +2 -0
- package/plugin/sdk/types.ts +142 -0
- package/renderer/touch-sdk/index.ts +9 -0
package/common/utils/timing.ts
CHANGED
|
@@ -8,8 +8,44 @@ export interface TimingRecord {
|
|
|
8
8
|
iteration?: number
|
|
9
9
|
meta?: TimingMeta
|
|
10
10
|
error?: unknown
|
|
11
|
+
logLevel?: TimingLogLevel
|
|
11
12
|
}
|
|
12
13
|
|
|
14
|
+
export type TimingLogLevel = 'none' | 'info' | 'warn' | 'error'
|
|
15
|
+
|
|
16
|
+
export type TimingLogThresholdOverrides = Partial<Record<Exclude<TimingLogLevel, 'error'>, number>>
|
|
17
|
+
|
|
18
|
+
type ResolvedTimingLogThresholds = Record<Exclude<TimingLogLevel, 'error'>, number>
|
|
19
|
+
|
|
20
|
+
const DEFAULT_AUTO_LOG = true
|
|
21
|
+
const DEFAULT_STORE_HISTORY = true
|
|
22
|
+
const DEFAULT_HISTORY_LIMIT = 50
|
|
23
|
+
|
|
24
|
+
export const DEFAULT_TIMING_LOG_THRESHOLDS: Readonly<ResolvedTimingLogThresholds> = Object.freeze({
|
|
25
|
+
none: 16.7,
|
|
26
|
+
info: 200,
|
|
27
|
+
warn: 500
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
export const DEFAULT_TIMING_OPTIONS: Readonly<Required<Pick<TimingOptions, 'autoLog' | 'storeHistory'>> & {
|
|
31
|
+
logThresholds: Readonly<ResolvedTimingLogThresholds>
|
|
32
|
+
}> = Object.freeze({
|
|
33
|
+
autoLog: DEFAULT_AUTO_LOG,
|
|
34
|
+
storeHistory: DEFAULT_STORE_HISTORY,
|
|
35
|
+
logThresholds: DEFAULT_TIMING_LOG_THRESHOLDS
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
export const DEFAULT_TIMING_MANAGER_CONFIG: Readonly<
|
|
39
|
+
Required<Pick<TimingManagerConfig, 'autoLog' | 'storeHistory' | 'historyLimit'>> & {
|
|
40
|
+
logThresholds: Readonly<ResolvedTimingLogThresholds>
|
|
41
|
+
}
|
|
42
|
+
> = Object.freeze({
|
|
43
|
+
autoLog: DEFAULT_AUTO_LOG,
|
|
44
|
+
storeHistory: DEFAULT_STORE_HISTORY,
|
|
45
|
+
historyLimit: DEFAULT_HISTORY_LIMIT,
|
|
46
|
+
logThresholds: DEFAULT_TIMING_LOG_THRESHOLDS
|
|
47
|
+
})
|
|
48
|
+
|
|
13
49
|
export interface TimingStats {
|
|
14
50
|
label: string
|
|
15
51
|
count: number
|
|
@@ -22,6 +58,7 @@ export interface TimingStats {
|
|
|
22
58
|
lastEndedAt?: number
|
|
23
59
|
errorCount: number
|
|
24
60
|
lastError?: unknown
|
|
61
|
+
lastLogLevel?: TimingLogLevel
|
|
25
62
|
}
|
|
26
63
|
|
|
27
64
|
export interface TimingSummary extends TimingStats {
|
|
@@ -30,9 +67,11 @@ export interface TimingSummary extends TimingStats {
|
|
|
30
67
|
|
|
31
68
|
export interface TimingManagerConfig {
|
|
32
69
|
autoLog?: boolean
|
|
70
|
+
storeHistory?: boolean
|
|
33
71
|
historyLimit?: number
|
|
34
72
|
logger?: (message: string, entry: TimingRecord, stats: TimingStats) => void
|
|
35
73
|
formatter?: (entry: TimingRecord, stats: TimingStats) => string
|
|
74
|
+
logThresholds?: TimingLogThresholdOverrides
|
|
36
75
|
}
|
|
37
76
|
|
|
38
77
|
export interface TimingOptions {
|
|
@@ -41,39 +80,63 @@ export interface TimingOptions {
|
|
|
41
80
|
logger?: (message: string, entry: TimingRecord, stats: TimingStats) => void
|
|
42
81
|
formatter?: (entry: TimingRecord, stats: TimingStats) => string
|
|
43
82
|
historyLimit?: number
|
|
83
|
+
logThresholds?: TimingLogThresholdOverrides
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
type ResolvedTimingOptions = {
|
|
87
|
+
autoLog: boolean
|
|
88
|
+
storeHistory: boolean
|
|
89
|
+
historyLimit: number
|
|
90
|
+
logThresholds: ResolvedTimingLogThresholds
|
|
91
|
+
formatter: (entry: TimingRecord, stats: TimingStats) => string
|
|
92
|
+
logger: (message: string, entry: TimingRecord, stats: TimingStats) => void
|
|
44
93
|
}
|
|
45
94
|
|
|
46
95
|
export class TimingManager {
|
|
47
96
|
private readonly stats = new Map<string, TimingStats>()
|
|
48
97
|
private readonly history = new Map<string, TimingRecord[]>()
|
|
49
98
|
private readonly moduleStats = new Map<string, TimingStats>()
|
|
99
|
+
private readonly config: TimingManagerConfig
|
|
100
|
+
|
|
101
|
+
constructor(config: TimingManagerConfig = {}) {
|
|
102
|
+
const mergedThresholds: ResolvedTimingLogThresholds = {
|
|
103
|
+
...DEFAULT_TIMING_LOG_THRESHOLDS,
|
|
104
|
+
...(config.logThresholds ?? {})
|
|
105
|
+
}
|
|
50
106
|
|
|
51
|
-
|
|
107
|
+
this.config = {
|
|
108
|
+
...DEFAULT_TIMING_MANAGER_CONFIG,
|
|
109
|
+
...config,
|
|
110
|
+
logThresholds: mergedThresholds
|
|
111
|
+
}
|
|
112
|
+
}
|
|
52
113
|
|
|
53
114
|
createTiming(label: string, options: TimingOptions = {}): TimingScope {
|
|
54
115
|
return new TimingScope(this, label, options)
|
|
55
116
|
}
|
|
56
117
|
|
|
57
118
|
record(label: string, record: TimingRecord, options: TimingOptions = {}): void {
|
|
58
|
-
const
|
|
119
|
+
const resolved = this.resolveOptions(options)
|
|
120
|
+
const logLevel = determineLogLevel(record.durationMs, resolved.logThresholds)
|
|
121
|
+
const recordWithLevel: TimingRecord = { ...record, logLevel }
|
|
122
|
+
|
|
123
|
+
const stats = this.updateStats(this.stats, label, recordWithLevel)
|
|
59
124
|
const moduleKey = this.extractModuleKey(label)
|
|
60
|
-
this.updateStats(this.moduleStats, moduleKey, { ...
|
|
125
|
+
this.updateStats(this.moduleStats, moduleKey, { ...recordWithLevel, label: moduleKey })
|
|
61
126
|
|
|
62
|
-
if (
|
|
63
|
-
const limit =
|
|
127
|
+
if (resolved.storeHistory) {
|
|
128
|
+
const limit = resolved.historyLimit
|
|
64
129
|
const list = this.history.get(label) ?? []
|
|
65
|
-
list.push(
|
|
130
|
+
list.push(recordWithLevel)
|
|
66
131
|
if (list.length > limit) {
|
|
67
132
|
list.splice(0, list.length - limit)
|
|
68
133
|
}
|
|
69
134
|
this.history.set(label, list)
|
|
70
135
|
}
|
|
71
136
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const logger = options.logger ?? this.config.logger ?? defaultLogger
|
|
76
|
-
logger(formatter(record, stats), record, stats)
|
|
137
|
+
if (resolved.autoLog && logLevel !== 'none') {
|
|
138
|
+
const message = resolved.formatter(recordWithLevel, stats)
|
|
139
|
+
resolved.logger(message, recordWithLevel, stats)
|
|
77
140
|
}
|
|
78
141
|
}
|
|
79
142
|
|
|
@@ -131,6 +194,7 @@ export class TimingManager {
|
|
|
131
194
|
next.lastMs = durationMs
|
|
132
195
|
next.lastStartedAt = record.startedAt
|
|
133
196
|
next.lastEndedAt = record.endedAt
|
|
197
|
+
next.lastLogLevel = record.logLevel
|
|
134
198
|
|
|
135
199
|
if (error) {
|
|
136
200
|
next.errorCount += 1
|
|
@@ -145,6 +209,23 @@ export class TimingManager {
|
|
|
145
209
|
const [moduleKey] = label.split(':')
|
|
146
210
|
return moduleKey || label
|
|
147
211
|
}
|
|
212
|
+
|
|
213
|
+
private resolveOptions(options: TimingOptions = {}): ResolvedTimingOptions {
|
|
214
|
+
const logThresholds: ResolvedTimingLogThresholds = {
|
|
215
|
+
...DEFAULT_TIMING_LOG_THRESHOLDS,
|
|
216
|
+
...(this.config.logThresholds ?? {}),
|
|
217
|
+
...(options.logThresholds ?? {})
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return {
|
|
221
|
+
autoLog: options.autoLog ?? this.config.autoLog ?? DEFAULT_AUTO_LOG,
|
|
222
|
+
storeHistory: options.storeHistory ?? this.config.storeHistory ?? DEFAULT_STORE_HISTORY,
|
|
223
|
+
historyLimit: options.historyLimit ?? this.config.historyLimit ?? DEFAULT_HISTORY_LIMIT,
|
|
224
|
+
logThresholds,
|
|
225
|
+
formatter: options.formatter ?? this.config.formatter ?? defaultFormatter,
|
|
226
|
+
logger: options.logger ?? this.config.logger ?? defaultLogger
|
|
227
|
+
}
|
|
228
|
+
}
|
|
148
229
|
}
|
|
149
230
|
|
|
150
231
|
export class TimingScope {
|
|
@@ -224,13 +305,49 @@ export class TimingScope {
|
|
|
224
305
|
|
|
225
306
|
function defaultFormatter(record: TimingRecord, stats: TimingStats): string {
|
|
226
307
|
const duration = record.durationMs.toFixed(2)
|
|
227
|
-
|
|
308
|
+
const levelTag =
|
|
309
|
+
record.logLevel && record.logLevel !== 'info' ? ` [${record.logLevel.toUpperCase()}]` : ''
|
|
310
|
+
return `⏱ [${record.label}] ${duration} ms${levelTag} (avg: ${stats.avgMs.toFixed(
|
|
311
|
+
2
|
|
312
|
+
)} ms, max: ${stats.maxMs.toFixed(2)} ms, count: ${stats.count})`
|
|
228
313
|
}
|
|
229
314
|
|
|
230
|
-
function defaultLogger(message: string): void {
|
|
315
|
+
function defaultLogger(message: string, entry: TimingRecord, _stats: TimingStats): void {
|
|
316
|
+
if (entry.logLevel === 'none') {
|
|
317
|
+
return
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (entry.logLevel === 'warn') {
|
|
321
|
+
console.warn(message)
|
|
322
|
+
return
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (entry.logLevel === 'error') {
|
|
326
|
+
console.error(message)
|
|
327
|
+
return
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if (typeof console.info === 'function') {
|
|
331
|
+
console.info(message)
|
|
332
|
+
return
|
|
333
|
+
}
|
|
334
|
+
|
|
231
335
|
console.log(message)
|
|
232
336
|
}
|
|
233
337
|
|
|
338
|
+
function determineLogLevel(durationMs: number, thresholds: ResolvedTimingLogThresholds): TimingLogLevel {
|
|
339
|
+
if (durationMs <= thresholds.none) {
|
|
340
|
+
return 'none'
|
|
341
|
+
}
|
|
342
|
+
if (durationMs <= thresholds.info) {
|
|
343
|
+
return 'info'
|
|
344
|
+
}
|
|
345
|
+
if (durationMs <= thresholds.warn) {
|
|
346
|
+
return 'warn'
|
|
347
|
+
}
|
|
348
|
+
return 'error'
|
|
349
|
+
}
|
|
350
|
+
|
|
234
351
|
const now = (() => {
|
|
235
352
|
if (typeof globalThis !== 'undefined') {
|
|
236
353
|
const perf = (globalThis as typeof globalThis & { performance?: { now?: () => number } }).performance
|
|
@@ -245,6 +362,133 @@ const timingManagerInstance = new TimingManager()
|
|
|
245
362
|
|
|
246
363
|
export const timingManager = timingManagerInstance
|
|
247
364
|
|
|
365
|
+
export function startTiming(): number {
|
|
366
|
+
return now()
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
export function completeTiming(
|
|
370
|
+
label: string,
|
|
371
|
+
startedAt: number,
|
|
372
|
+
meta: TimingMeta = {},
|
|
373
|
+
options: TimingOptions = {}
|
|
374
|
+
): number {
|
|
375
|
+
const endedAt = now()
|
|
376
|
+
const durationMs = endedAt - startedAt
|
|
377
|
+
timingManagerInstance.record(
|
|
378
|
+
label,
|
|
379
|
+
{
|
|
380
|
+
label,
|
|
381
|
+
durationMs,
|
|
382
|
+
startedAt,
|
|
383
|
+
endedAt,
|
|
384
|
+
meta
|
|
385
|
+
},
|
|
386
|
+
options
|
|
387
|
+
)
|
|
388
|
+
return durationMs
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
export function logTiming(
|
|
392
|
+
label: string,
|
|
393
|
+
durationMs: number,
|
|
394
|
+
meta: TimingMeta = {},
|
|
395
|
+
options: TimingOptions = {}
|
|
396
|
+
): void {
|
|
397
|
+
const endedAt = now()
|
|
398
|
+
const startedAt = endedAt - durationMs
|
|
399
|
+
timingManagerInstance.record(
|
|
400
|
+
label,
|
|
401
|
+
{
|
|
402
|
+
label,
|
|
403
|
+
durationMs,
|
|
404
|
+
startedAt,
|
|
405
|
+
endedAt,
|
|
406
|
+
meta
|
|
407
|
+
},
|
|
408
|
+
options
|
|
409
|
+
)
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
export interface TimingLoggerToken {
|
|
413
|
+
label: string
|
|
414
|
+
startedAt: number
|
|
415
|
+
meta: TimingMeta
|
|
416
|
+
options: TimingOptions
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
export const timingLogger = {
|
|
420
|
+
start(label: string, meta: TimingMeta = {}, options: TimingOptions = {}): TimingLoggerToken {
|
|
421
|
+
return {
|
|
422
|
+
label,
|
|
423
|
+
startedAt: startTiming(),
|
|
424
|
+
meta,
|
|
425
|
+
options
|
|
426
|
+
}
|
|
427
|
+
},
|
|
428
|
+
|
|
429
|
+
finish(
|
|
430
|
+
token: TimingLoggerToken,
|
|
431
|
+
meta: TimingMeta = {},
|
|
432
|
+
overrides: TimingOptions = {}
|
|
433
|
+
): number {
|
|
434
|
+
const mergedMeta = { ...token.meta, ...meta }
|
|
435
|
+
const mergedOptions = mergeTimingOptions(token.options, overrides)
|
|
436
|
+
return completeTiming(token.label, token.startedAt, mergedMeta, mergedOptions)
|
|
437
|
+
},
|
|
438
|
+
|
|
439
|
+
print(
|
|
440
|
+
label: string,
|
|
441
|
+
durationMs: number,
|
|
442
|
+
meta: TimingMeta = {},
|
|
443
|
+
options: TimingOptions = {}
|
|
444
|
+
): number {
|
|
445
|
+
logTiming(label, durationMs, meta, options)
|
|
446
|
+
return durationMs
|
|
447
|
+
},
|
|
448
|
+
|
|
449
|
+
async cost<T>(
|
|
450
|
+
label: string,
|
|
451
|
+
fn: () => Promise<T> | T,
|
|
452
|
+
meta: TimingMeta = {},
|
|
453
|
+
options: TimingOptions = {}
|
|
454
|
+
): Promise<T> {
|
|
455
|
+
const scope = createTiming(label, options)
|
|
456
|
+
return scope.cost(fn, meta)
|
|
457
|
+
},
|
|
458
|
+
|
|
459
|
+
mark(
|
|
460
|
+
label: string,
|
|
461
|
+
durationMs: number,
|
|
462
|
+
meta: TimingMeta = {},
|
|
463
|
+
options: TimingOptions = {}
|
|
464
|
+
): number {
|
|
465
|
+
logTiming(label, durationMs, meta, options)
|
|
466
|
+
return durationMs
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
248
470
|
export function createTiming(label: string, options: TimingOptions = {}): TimingScope {
|
|
249
471
|
return timingManagerInstance.createTiming(label, options)
|
|
250
472
|
}
|
|
473
|
+
|
|
474
|
+
function mergeTimingOptions(
|
|
475
|
+
base: TimingOptions = {},
|
|
476
|
+
override: TimingOptions = {}
|
|
477
|
+
): TimingOptions {
|
|
478
|
+
if (!base && !override) return {}
|
|
479
|
+
if (!override || Object.keys(override).length === 0) {
|
|
480
|
+
return { ...base }
|
|
481
|
+
}
|
|
482
|
+
if (!base || Object.keys(base).length === 0) {
|
|
483
|
+
return { ...override }
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
return {
|
|
487
|
+
...base,
|
|
488
|
+
...override,
|
|
489
|
+
logThresholds: {
|
|
490
|
+
...(base.logThresholds ?? {}),
|
|
491
|
+
...(override.logThresholds ?? {})
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
}
|
|
@@ -863,12 +863,29 @@ export interface TuffMeta {
|
|
|
863
863
|
* @description The ID of the feature.
|
|
864
864
|
*/
|
|
865
865
|
featureId?: string
|
|
866
|
+
|
|
867
|
+
/**
|
|
868
|
+
* For plugin feature items, this holds the interaction configuration.
|
|
869
|
+
* @description Defines how the feature should be rendered (widget, webcontent, or index).
|
|
870
|
+
*/
|
|
871
|
+
interaction?: {
|
|
872
|
+
type: 'webcontent' | 'widget' | 'index'
|
|
873
|
+
path?: string
|
|
874
|
+
}
|
|
875
|
+
|
|
866
876
|
/**
|
|
867
877
|
* Defines the default action to be taken when the item is executed (e.g., by pressing Enter).
|
|
868
878
|
* This is used to distinguish simple actions (like 'copy') from feature activations.
|
|
869
879
|
* @description The default action type.
|
|
870
880
|
*/
|
|
871
881
|
defaultAction?: string;
|
|
882
|
+
|
|
883
|
+
/**
|
|
884
|
+
* Priority of the item for sorting in search results
|
|
885
|
+
* Higher numbers have higher priority (displayed first)
|
|
886
|
+
* @description Priority value for search result ordering
|
|
887
|
+
*/
|
|
888
|
+
priority?: number;
|
|
872
889
|
/**
|
|
873
890
|
* 原始数据
|
|
874
891
|
* @description 项目的原始数据对象,用于特殊处理
|
package/package.json
CHANGED
package/plugin/index.ts
CHANGED
|
@@ -59,7 +59,7 @@ export interface IPluginBaseInfo {
|
|
|
59
59
|
export interface IPluginDev {
|
|
60
60
|
enable: boolean
|
|
61
61
|
address: string
|
|
62
|
-
source?:
|
|
62
|
+
source?: boolean
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
export interface ITouchPlugin extends IPluginBaseInfo {
|
|
@@ -81,6 +81,47 @@ export interface ITouchPlugin extends IPluginBaseInfo {
|
|
|
81
81
|
|
|
82
82
|
enable(): Promise<boolean>
|
|
83
83
|
disable(): Promise<boolean>
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Get the plugin file.
|
|
87
|
+
* @param fileName The name of the file.
|
|
88
|
+
* @returns The content of the file.
|
|
89
|
+
*/
|
|
90
|
+
getPluginFile(fileName: string): object
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Save the plugin file.
|
|
94
|
+
* @param fileName The name of the file.
|
|
95
|
+
* @param content The content of the file.
|
|
96
|
+
* @returns The result of the save operation.
|
|
97
|
+
*/
|
|
98
|
+
savePluginFile(fileName: string, content: object): { success: boolean; error?: string }
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Delete the plugin file.
|
|
102
|
+
* @param fileName The name of the file.
|
|
103
|
+
* @returns The result of the delete operation.
|
|
104
|
+
*/
|
|
105
|
+
deletePluginFile(fileName: string): { success: boolean; error?: string }
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* List all files in the plugin.
|
|
109
|
+
* @returns The list of files.
|
|
110
|
+
*/
|
|
111
|
+
listPluginFiles(): string[]
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Get the plugin configuration.
|
|
115
|
+
* @returns The configuration content.
|
|
116
|
+
*/
|
|
117
|
+
getPluginConfig(): object
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Save the plugin configuration.
|
|
121
|
+
* @param content The configuration content.
|
|
122
|
+
* @returns The result of the save operation.
|
|
123
|
+
*/
|
|
124
|
+
savePluginConfig(content: object): { success: boolean; error?: string }
|
|
84
125
|
}
|
|
85
126
|
|
|
86
127
|
export interface IFeatureCommand {
|
|
@@ -98,6 +139,12 @@ export interface IPluginFeature {
|
|
|
98
139
|
platform: IPlatform
|
|
99
140
|
commands: IFeatureCommand[]
|
|
100
141
|
interaction?: IFeatureInteraction
|
|
142
|
+
/**
|
|
143
|
+
* Priority of the feature for sorting in search results
|
|
144
|
+
* Higher numbers have higher priority (displayed first)
|
|
145
|
+
* Default is 0
|
|
146
|
+
*/
|
|
147
|
+
priority?: number
|
|
101
148
|
}
|
|
102
149
|
|
|
103
150
|
export type IFeatureInteraction = {
|
|
@@ -113,6 +160,18 @@ export type IFeatureInteraction = {
|
|
|
113
160
|
* These hooks are triggered based on real user interaction and system events.
|
|
114
161
|
*/
|
|
115
162
|
export interface IFeatureLifeCycle {
|
|
163
|
+
/**
|
|
164
|
+
* onInit is called when the feature is initialized.
|
|
165
|
+
* Can be used to prepare data or UI specific to this session.
|
|
166
|
+
*/
|
|
167
|
+
onInit?(): void
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Called when a message is received from the main application.
|
|
171
|
+
* @param key - The key of the message
|
|
172
|
+
* @param info - The information of the message
|
|
173
|
+
*/
|
|
174
|
+
onMessage?(key: string, info: any): void
|
|
116
175
|
/**
|
|
117
176
|
* Called when a feature is actively launched from the launcher.
|
|
118
177
|
* Can be used to prepare data or UI specific to this session.
|
|
@@ -156,8 +215,16 @@ export interface IFeatureLifeCycle {
|
|
|
156
215
|
* This is used for handling actions on the items themselves,
|
|
157
216
|
* rather than triggering a new feature.
|
|
158
217
|
* @param item The TuffItem that was executed.
|
|
218
|
+
* @returns Object indicating whether to activate the feature and any activation data
|
|
159
219
|
*/
|
|
160
|
-
onItemAction?(item: any): Promise<
|
|
220
|
+
onItemAction?(item: any): Promise<{
|
|
221
|
+
/** Whether the action executed an external operation (e.g., opened browser) */
|
|
222
|
+
externalAction?: boolean
|
|
223
|
+
/** Whether the feature should be activated after this action */
|
|
224
|
+
shouldActivate?: boolean
|
|
225
|
+
/** Activation data if shouldActivate is true */
|
|
226
|
+
activation?: any
|
|
227
|
+
} | void>
|
|
161
228
|
}
|
|
162
229
|
|
|
163
230
|
/**
|
|
@@ -206,8 +273,16 @@ export interface ITargetFeatureLifeCycle {
|
|
|
206
273
|
* This is used for handling actions on the items themselves,
|
|
207
274
|
* rather than triggering a new feature.
|
|
208
275
|
* @param item The TuffItem that was executed.
|
|
276
|
+
* @returns Object indicating whether to activate the feature and any activation data
|
|
209
277
|
*/
|
|
210
|
-
onItemAction?(item: any): Promise<
|
|
278
|
+
onItemAction?(item: any): Promise<{
|
|
279
|
+
/** Whether the action executed an external operation (e.g., opened browser) */
|
|
280
|
+
externalAction?: boolean
|
|
281
|
+
/** Whether the feature should be activated after this action */
|
|
282
|
+
shouldActivate?: boolean
|
|
283
|
+
/** Activation data if shouldActivate is true */
|
|
284
|
+
activation?: any
|
|
285
|
+
} | void>
|
|
211
286
|
}
|
|
212
287
|
|
|
213
288
|
/**
|
package/plugin/sdk/common.ts
CHANGED
|
@@ -1,28 +1,77 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Plugin SDK Common Utilities
|
|
3
|
+
*
|
|
4
|
+
* @description
|
|
5
|
+
* 提供插件SDK的通用功能,包括通信、快捷键等
|
|
6
|
+
*/
|
|
3
7
|
|
|
4
|
-
|
|
5
|
-
const channel = genChannel()
|
|
8
|
+
import { genChannel } from '../channel'
|
|
6
9
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Register a shortcut
|
|
12
|
+
* @param key - The shortcut combination
|
|
13
|
+
* @param func - The trigger function
|
|
14
|
+
* @returns Whether the shortcut is registered successfully
|
|
15
|
+
*/
|
|
16
|
+
export function regShortcut(key: string, func: Function): boolean {
|
|
17
|
+
const channel = genChannel()
|
|
18
|
+
|
|
19
|
+
const res = channel.sendSync('shortcon:reg', { key })
|
|
20
|
+
if (res instanceof String) throw new Error(String(res))
|
|
21
|
+
if (res === false) return false
|
|
10
22
|
|
|
11
|
-
|
|
23
|
+
channel.regChannel('shortcon:trigger', ({ data }) => key === data.key && func())
|
|
12
24
|
|
|
13
|
-
|
|
25
|
+
return true
|
|
14
26
|
}
|
|
15
27
|
|
|
16
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Communicate with other plugins via the index:communicate channel
|
|
30
|
+
* @param key - The message key
|
|
31
|
+
* @param info - The message data
|
|
32
|
+
* @returns Promise<any> The communication result
|
|
33
|
+
*/
|
|
34
|
+
export async function communicateWithPlugin(
|
|
35
|
+
key: string,
|
|
36
|
+
info: any = {}
|
|
37
|
+
): Promise<any> {
|
|
17
38
|
const channel = genChannel()
|
|
18
39
|
|
|
19
|
-
|
|
40
|
+
try {
|
|
41
|
+
return await channel.send('index:communicate', {
|
|
42
|
+
key,
|
|
43
|
+
info
|
|
44
|
+
})
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.error(`[Plugin SDK] Failed to communicate`, error)
|
|
47
|
+
throw error
|
|
48
|
+
}
|
|
20
49
|
}
|
|
21
50
|
|
|
22
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Send a message to the main application
|
|
53
|
+
* @param message - The message type
|
|
54
|
+
* @param data - The message data
|
|
55
|
+
* @returns Promise<any> The message result
|
|
56
|
+
*/
|
|
57
|
+
export async function sendMessage(message: string, data: any = {}): Promise<any> {
|
|
23
58
|
const channel = genChannel()
|
|
24
59
|
|
|
25
|
-
|
|
60
|
+
try {
|
|
61
|
+
return await channel.send(`plugin:${message}`, data)
|
|
62
|
+
} catch (error) {
|
|
63
|
+
console.error(`[Plugin SDK] Failed to send message: ${message}`, error)
|
|
64
|
+
throw error
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Get the channel object for the plugin
|
|
70
|
+
* Attention: Using this function make sure you know what you are doing.
|
|
71
|
+
* @returns The channel object for the plugin
|
|
72
|
+
*/
|
|
73
|
+
export function getChannel() {
|
|
74
|
+
return genChannel()
|
|
26
75
|
}
|
|
27
76
|
|
|
28
|
-
export * from './window'
|
|
77
|
+
export * from './window'
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { IPluginRendererChannel } from './types'
|
|
2
|
+
|
|
3
|
+
const ensurePluginContext = (): { channel: IPluginRendererChannel; pluginName: string } => {
|
|
4
|
+
const plugin = (window as any)?.$plugin
|
|
5
|
+
if (!plugin?.name) {
|
|
6
|
+
throw new Error('[TouchSDK] Unable to resolve plugin name inside renderer context.')
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const channel = (window as any)?.$channel as IPluginRendererChannel | undefined
|
|
10
|
+
if (!channel) {
|
|
11
|
+
throw new Error('[TouchSDK] Channel bridge is not available for the current plugin renderer.')
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
channel,
|
|
16
|
+
pluginName: plugin.name as string
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Clears all CoreBox items associated with the current plugin.
|
|
22
|
+
*/
|
|
23
|
+
export async function clearCoreBoxItems(): Promise<void> {
|
|
24
|
+
const { channel, pluginName } = ensurePluginContext()
|
|
25
|
+
await channel.send('core-box:clear-items', { pluginName })
|
|
26
|
+
}
|
|
27
|
+
|