@talex-touch/utils 1.0.18 → 1.0.21
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/channel/index.ts +49 -1
- package/common/index.ts +2 -0
- package/common/search/gather.ts +45 -0
- package/common/search/index.ts +67 -0
- package/common/storage/constants.ts +16 -2
- package/common/storage/entity/index.ts +2 -1
- package/common/storage/entity/openers.ts +32 -0
- package/common/storage/entity/shortcut-settings.ts +22 -0
- package/common/storage/shortcut-storage.ts +58 -0
- package/common/utils/file.ts +62 -0
- package/common/{utils.ts → utils/index.ts} +14 -2
- package/common/utils/polling.ts +184 -0
- package/common/utils/task-queue.ts +108 -0
- package/common/utils/time.ts +374 -0
- package/core-box/README.md +8 -8
- package/core-box/builder/index.ts +6 -0
- package/core-box/builder/tuff-builder.example.ts.bak +258 -0
- package/core-box/builder/tuff-builder.ts +1162 -0
- package/core-box/index.ts +5 -2
- package/core-box/run-tests.sh +7 -0
- package/core-box/search.ts +1 -536
- package/core-box/tuff/index.ts +6 -0
- package/core-box/tuff/tuff-dsl.ts +1412 -0
- package/electron/clipboard-helper.ts +199 -0
- package/electron/env-tool.ts +36 -2
- package/electron/file-parsers/index.ts +8 -0
- package/electron/file-parsers/parsers/text-parser.ts +109 -0
- package/electron/file-parsers/registry.ts +92 -0
- package/electron/file-parsers/types.ts +58 -0
- package/electron/index.ts +3 -0
- package/eventbus/index.ts +0 -7
- package/index.ts +3 -1
- package/package.json +4 -29
- package/plugin/channel.ts +48 -16
- package/plugin/index.ts +194 -30
- package/plugin/log/types.ts +11 -0
- package/plugin/node/index.ts +4 -0
- package/plugin/node/logger-manager.ts +113 -0
- package/plugin/{log → node}/logger.ts +41 -7
- package/plugin/plugin-source.ts +74 -0
- package/plugin/preload.ts +5 -15
- package/plugin/providers/index.ts +2 -0
- package/plugin/providers/registry.ts +47 -0
- package/plugin/providers/types.ts +54 -0
- package/plugin/risk/index.ts +1 -0
- package/plugin/risk/types.ts +20 -0
- package/plugin/sdk/enum/bridge-event.ts +4 -0
- package/plugin/sdk/enum/index.ts +1 -0
- package/plugin/sdk/hooks/bridge.ts +68 -0
- package/plugin/sdk/hooks/index.ts +2 -1
- package/plugin/sdk/hooks/life-cycle.ts +2 -4
- package/plugin/sdk/index.ts +2 -0
- package/plugin/sdk/storage.ts +84 -0
- package/plugin/sdk/types.ts +2 -2
- package/plugin/sdk/window/index.ts +5 -3
- package/preload/index.ts +2 -0
- package/preload/loading.ts +15 -0
- package/preload/renderer.ts +41 -0
- package/renderer/hooks/arg-mapper.ts +79 -0
- package/renderer/hooks/index.ts +2 -0
- package/renderer/hooks/initialize.ts +198 -0
- package/renderer/index.ts +3 -0
- package/renderer/storage/app-settings.ts +2 -0
- package/renderer/storage/base-storage.ts +1 -0
- package/renderer/storage/openers.ts +11 -0
- package/renderer/touch-sdk/env.ts +106 -0
- package/renderer/touch-sdk/index.ts +108 -0
- package/renderer/touch-sdk/terminal.ts +85 -0
- package/renderer/touch-sdk/utils.ts +61 -0
- package/search/levenshtein-utils.ts +39 -0
- package/search/types.ts +16 -16
- package/types/index.ts +2 -1
- package/types/modules/base.ts +146 -0
- package/types/modules/index.ts +4 -0
- package/types/modules/module-lifecycle.ts +148 -0
- package/types/modules/module-manager.ts +99 -0
- package/types/modules/module.ts +112 -0
- package/types/touch-app-core.ts +16 -93
- package/core-box/types.ts +0 -384
- package/plugin/log/logger-manager.ts +0 -60
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { IManifest } from '@talex-touch/utils/plugin'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Interface for plugin download options.
|
|
5
|
+
*/
|
|
6
|
+
export interface IDownloadOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Timeout configuration for download in milliseconds.
|
|
9
|
+
*/
|
|
10
|
+
timeout?: number;
|
|
11
|
+
/**
|
|
12
|
+
* List of fallback download URLs.
|
|
13
|
+
*/
|
|
14
|
+
fallbackUrls?: string[];
|
|
15
|
+
/**
|
|
16
|
+
* Callback function for download progress, with progress value (0-100).
|
|
17
|
+
*/
|
|
18
|
+
onProgress?: (progress: number) => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Interface for plugin download results.
|
|
23
|
+
*/
|
|
24
|
+
export interface IDownloadResult {
|
|
25
|
+
/**
|
|
26
|
+
* Local file path after download, which can be the plugin's compressed package or the unzipped folder path.
|
|
27
|
+
*/
|
|
28
|
+
filePath?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Interface for options when resolving a plugin manifest.
|
|
33
|
+
*/
|
|
34
|
+
export interface IResolveManifestOptions {
|
|
35
|
+
// Add any future resolution options here, e.g., caching strategy, network request configuration.
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Abstract interface for a plugin source. Defines how to resolve and download plugins.
|
|
40
|
+
*/
|
|
41
|
+
export interface IPluginSource {
|
|
42
|
+
/**
|
|
43
|
+
* Get the name of the plugin source.
|
|
44
|
+
* @returns The name of the plugin source.
|
|
45
|
+
*/
|
|
46
|
+
getSourceName(): string;
|
|
47
|
+
/**
|
|
48
|
+
* Get the description of the plugin source.
|
|
49
|
+
* @returns The description of the plugin source.
|
|
50
|
+
*/
|
|
51
|
+
getSourceDesc(): string;
|
|
52
|
+
/**
|
|
53
|
+
* Timestamp of the last update for this plugin source.
|
|
54
|
+
*/
|
|
55
|
+
lastUpdateTime?: number;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Attempts to resolve a plugin manifest from the specified path or URL.
|
|
59
|
+
* If resolution is successful, returns an IManifest; otherwise, returns undefined.
|
|
60
|
+
* The returned result must be a plugin manifest object conforming to the IManifest format.
|
|
61
|
+
* @param sourcePath The root directory path or URL of the plugin.
|
|
62
|
+
* @param options Resolution options.
|
|
63
|
+
* @returns A Promise containing the plugin manifest, or undefined if resolution fails.
|
|
64
|
+
*/
|
|
65
|
+
resolveManifest(sourcePath: string, options?: IResolveManifestOptions): Promise<IManifest | undefined>
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Downloads the plugin source.
|
|
69
|
+
* @param sourceUrl The URL of the plugin source.
|
|
70
|
+
* @param options Download options.
|
|
71
|
+
* @returns A Promise containing the download result. The filePath must be the path to the plugin's compressed package or unzipped folder.
|
|
72
|
+
*/
|
|
73
|
+
downloadPlugin(sourceUrl: string, options?: IDownloadOptions): Promise<IDownloadResult>
|
|
74
|
+
}
|
package/plugin/preload.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ITouchClientChannel } from '../channel'
|
|
2
2
|
import './sdk/index'
|
|
3
3
|
|
|
4
4
|
// window type
|
|
@@ -8,9 +8,7 @@ declare global {
|
|
|
8
8
|
name: string
|
|
9
9
|
path: Object
|
|
10
10
|
}
|
|
11
|
-
$
|
|
12
|
-
$sendSync: (type: string, data: any) => Promise<any>
|
|
13
|
-
$regChannel: (type: string, callback: Function) => void
|
|
11
|
+
$channel: ITouchClientChannel
|
|
14
12
|
$crash: (message: string, extraData: any) => void
|
|
15
13
|
$config: {
|
|
16
14
|
themeStyle: any
|
|
@@ -18,22 +16,14 @@ declare global {
|
|
|
18
16
|
}
|
|
19
17
|
}
|
|
20
18
|
|
|
21
|
-
export function
|
|
19
|
+
export function initTuff(window: Window) {
|
|
22
20
|
const plugin = window.$plugin
|
|
23
21
|
if (!plugin)
|
|
24
22
|
throw new Error('Plugin has a fatal error! Please check your plugin!')
|
|
25
23
|
|
|
26
24
|
window.$crash = function (message, extraData) {
|
|
27
|
-
window.$send('crash', { message, ...extraData })
|
|
25
|
+
window.$channel.send('crash', { message, ...extraData })
|
|
28
26
|
}
|
|
29
27
|
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function initBridge(window: Window) {
|
|
34
|
-
const touchChannel = genChannel()
|
|
35
|
-
|
|
36
|
-
window.$send = touchChannel.send.bind(touchChannel)
|
|
37
|
-
window.$sendSync = touchChannel.sendSync.bind(touchChannel)
|
|
38
|
-
window.$regChannel = touchChannel.regChannel.bind(touchChannel)
|
|
28
|
+
console.log(`%c[Plugin] ${plugin.name} loaded`, 'color: #42b983')
|
|
39
29
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { defaultRiskPromptHandler } from '../risk'
|
|
2
|
+
import type { PluginInstallRequest, PluginInstallResult, PluginProvider, PluginProviderContext } from './types'
|
|
3
|
+
|
|
4
|
+
class ProviderRegistry {
|
|
5
|
+
private providers: PluginProvider[] = []
|
|
6
|
+
|
|
7
|
+
register(provider: PluginProvider): void {
|
|
8
|
+
if (this.providers.some((item) => item.type === provider.type)) {
|
|
9
|
+
throw new Error(`Plugin provider '${provider.type}' already registered`)
|
|
10
|
+
}
|
|
11
|
+
this.providers.push(provider)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
unregister(type: PluginProvider['type']): void {
|
|
15
|
+
this.providers = this.providers.filter((item) => item.type !== type)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
clear(): void {
|
|
19
|
+
this.providers = []
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
resolve(request: PluginInstallRequest): PluginProvider | undefined {
|
|
23
|
+
return this.providers.find((provider) => provider.canHandle(request))
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async install(
|
|
27
|
+
request: PluginInstallRequest,
|
|
28
|
+
context: PluginProviderContext = {}
|
|
29
|
+
): Promise<PluginInstallResult | undefined> {
|
|
30
|
+
const provider = this.resolve(request)
|
|
31
|
+
if (!provider) return undefined
|
|
32
|
+
|
|
33
|
+
const composedContext: PluginProviderContext = {
|
|
34
|
+
riskPrompt: defaultRiskPromptHandler,
|
|
35
|
+
...context
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!composedContext.riskPrompt) {
|
|
39
|
+
composedContext.riskPrompt = defaultRiskPromptHandler
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return provider.install(request, composedContext)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const pluginProviderRegistry = new ProviderRegistry()
|
|
47
|
+
export type { PluginProvider } from './types'
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { IDownloadOptions, IDownloadResult } from '../plugin-source'
|
|
2
|
+
import type { IManifest } from '..'
|
|
3
|
+
import type { RiskPromptHandler } from '../risk'
|
|
4
|
+
|
|
5
|
+
export enum PluginProviderType {
|
|
6
|
+
GITHUB = 'github',
|
|
7
|
+
NPM = 'npm',
|
|
8
|
+
TPEX = 'tpex',
|
|
9
|
+
FILE = 'file',
|
|
10
|
+
DEV = 'dev'
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface PluginInstallRequest {
|
|
14
|
+
/** 用户输入或配置的原始地址,例如 repo URL、npm 包名、文件路径等。 */
|
|
15
|
+
source: string
|
|
16
|
+
/** 额外提示信息,例如指定 provider 类型或版本。 */
|
|
17
|
+
hintType?: PluginProviderType
|
|
18
|
+
/** 可选元数据,在调用链中透传。 */
|
|
19
|
+
metadata?: Record<string, unknown>
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface PluginProviderContext {
|
|
23
|
+
/** 下载配置,例如进度回调、超时时间等。 */
|
|
24
|
+
downloadOptions?: IDownloadOptions
|
|
25
|
+
/** 风险提示处理器,未提供时默认为自动通过。 */
|
|
26
|
+
riskPrompt?: RiskPromptHandler
|
|
27
|
+
/** 提供缓存或临时目录位置。 */
|
|
28
|
+
tempDir?: string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface PluginInstallResult extends IDownloadResult {
|
|
32
|
+
/** provider 类型,便于后续逻辑分支。 */
|
|
33
|
+
provider: PluginProviderType
|
|
34
|
+
/** 是否经过官方认证或白名单。 */
|
|
35
|
+
official?: boolean
|
|
36
|
+
/** 解析得到的 manifest;某些 provider 可能只提供压缩包路径。 */
|
|
37
|
+
manifest?: IManifest
|
|
38
|
+
/** 附加信息,例如使用的 tag、branch 等。 */
|
|
39
|
+
metadata?: Record<string, unknown>
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface PluginProvider {
|
|
43
|
+
readonly type: PluginProviderType
|
|
44
|
+
canHandle(request: PluginInstallRequest): boolean
|
|
45
|
+
install(
|
|
46
|
+
request: PluginInstallRequest,
|
|
47
|
+
context?: PluginProviderContext
|
|
48
|
+
): Promise<PluginInstallResult>
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface PluginInstallSummary {
|
|
52
|
+
manifest?: IManifest
|
|
53
|
+
providerResult: PluginInstallResult
|
|
54
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './types'
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type RiskLevel = 'trusted' | 'needs_confirmation' | 'blocked'
|
|
2
|
+
|
|
3
|
+
export interface RiskPromptInput {
|
|
4
|
+
/** 资源来源标识,例如 provider 类型。 */
|
|
5
|
+
sourceType: string
|
|
6
|
+
/** 用户可识别的资源名称或路径。 */
|
|
7
|
+
sourceId: string
|
|
8
|
+
/** 风险等级,用于决定是否需要拦截或弹窗确认。 */
|
|
9
|
+
level: RiskLevel
|
|
10
|
+
/** 供 UI 展示的标题。 */
|
|
11
|
+
title?: string
|
|
12
|
+
/** 供 UI 展示的详细描述。 */
|
|
13
|
+
description?: string
|
|
14
|
+
/** 附加元数据,方便调用方扩展。 */
|
|
15
|
+
metadata?: Record<string, unknown>
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type RiskPromptHandler = (input: RiskPromptInput) => Promise<boolean>
|
|
19
|
+
|
|
20
|
+
export const defaultRiskPromptHandler: RiskPromptHandler = async () => true
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './bridge-event'
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { BridgeEventForCoreBox } from '../enum/bridge-event'
|
|
2
|
+
|
|
3
|
+
export type BridgeEvent = BridgeEventForCoreBox
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Defines the shape of a bridge hook function.
|
|
7
|
+
* @template T The type of data the hook will receive.
|
|
8
|
+
*/
|
|
9
|
+
export type BridgeHook<T = any> = (data: T) => void
|
|
10
|
+
|
|
11
|
+
const __hooks: Record<BridgeEvent, Array<BridgeHook>> = {
|
|
12
|
+
[BridgeEventForCoreBox.CORE_BOX_INPUT_CHANGE]: [],
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Injects a hook for a given bridge event.
|
|
17
|
+
* @param type The bridge event type.
|
|
18
|
+
* @param hook The hook function to inject.
|
|
19
|
+
* @returns The wrapped hook function.
|
|
20
|
+
* @internal
|
|
21
|
+
* @template T The type of data the hook will receive.
|
|
22
|
+
*/
|
|
23
|
+
export function injectBridgeEvent<T>(type: BridgeEvent, hook: BridgeHook<T>) {
|
|
24
|
+
const hooks: Array<BridgeHook<T>> = __hooks[type] || (__hooks[type] = [])
|
|
25
|
+
|
|
26
|
+
// Only register the channel listener once per event type
|
|
27
|
+
if (hooks.length === 0) {
|
|
28
|
+
window.$channel.regChannel(type, ({ data }) => {
|
|
29
|
+
console.debug(`[TouchSDK] ${type} event received: `, data)
|
|
30
|
+
// When the event is received, call all registered hooks for this type
|
|
31
|
+
const registeredHooks = __hooks[type]
|
|
32
|
+
if (registeredHooks) {
|
|
33
|
+
registeredHooks.forEach(h => h(data))
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const wrappedHook = (data: T) => {
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
|
|
42
|
+
hook(data)
|
|
43
|
+
|
|
44
|
+
} catch (e) {
|
|
45
|
+
console.error(`[TouchSDK] ${type} hook error: `, e)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
hooks.push(wrappedHook)
|
|
51
|
+
|
|
52
|
+
return wrappedHook
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Creates a hook for a given bridge event.
|
|
57
|
+
* @param type The bridge event type.
|
|
58
|
+
* @returns A function that takes a hook function and injects it.
|
|
59
|
+
* @template T The type of data the hook will receive.
|
|
60
|
+
*/
|
|
61
|
+
export const createBridgeHook = <T>(type: BridgeEvent) => (hook: BridgeHook<T>) => injectBridgeEvent<T>(type, hook)
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Hook for when the core box input changes.
|
|
65
|
+
* The hook receives the new input value as a string.
|
|
66
|
+
* @param data The input change data (string).
|
|
67
|
+
*/
|
|
68
|
+
export const onCoreBoxInputChange = createBridgeHook<{ query: string }>(BridgeEventForCoreBox.CORE_BOX_INPUT_CHANGE)
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export * as LifeCycle from './life-cycle'
|
|
1
|
+
export * as LifeCycle from './life-cycle'
|
|
2
|
+
export * from './bridge'
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { genChannel } from './../../channel';
|
|
2
|
-
|
|
3
1
|
export enum LifecycleHooks {
|
|
4
2
|
ENABLE = 'en',
|
|
5
3
|
DISABLE = 'di',
|
|
@@ -25,7 +23,7 @@ export function injectHook(type: LifecycleHooks, hook: Function, processFunc = (
|
|
|
25
23
|
|
|
26
24
|
if (hooks.length === 0) {
|
|
27
25
|
|
|
28
|
-
|
|
26
|
+
window.$channel.regChannel("@lifecycle:" + type, (obj: any) => {
|
|
29
27
|
|
|
30
28
|
processFunc(obj)
|
|
31
29
|
|
|
@@ -93,4 +91,4 @@ export const onPluginInactive = createHook(LifecycleHooks.INACTIVE)
|
|
|
93
91
|
* data.extraData Crash data
|
|
94
92
|
* @returns void
|
|
95
93
|
*/
|
|
96
|
-
export const onCrash = createHook(LifecycleHooks.CRASH)
|
|
94
|
+
export const onCrash = createHook(LifecycleHooks.CRASH)
|
package/plugin/sdk/index.ts
CHANGED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get the storage for the current plugin.
|
|
3
|
+
* It provides a simple key-value store that is persisted across application launches.
|
|
4
|
+
* The data is stored in a JSON file in the application's support directory.
|
|
5
|
+
* Each plugin has its own separate storage file.
|
|
6
|
+
*
|
|
7
|
+
* @returns An object with methods to interact with the storage.
|
|
8
|
+
*/
|
|
9
|
+
export function usePluginStorage() {
|
|
10
|
+
// @ts-ignore
|
|
11
|
+
const pluginName = window.$plugin.name as string
|
|
12
|
+
|
|
13
|
+
if (!pluginName) {
|
|
14
|
+
throw new Error('[Plugin SDK] Cannot determine plugin name. Make sure this is called in a plugin context.')
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const channel = window.$channel
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
/**
|
|
21
|
+
* Retrieves an item from the storage.
|
|
22
|
+
* @param key The key of the item to retrieve.
|
|
23
|
+
* @returns A promise that resolves with the value of the item, or null if the item does not exist.
|
|
24
|
+
*/
|
|
25
|
+
getItem: async (key: string): Promise<any> => {
|
|
26
|
+
return channel.send('plugin:storage:get-item', { pluginName, key })
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Stores an item in the storage.
|
|
31
|
+
* @param key The key of the item to store.
|
|
32
|
+
* @param value The value of the item to store.
|
|
33
|
+
* @returns A promise that resolves when the item has been stored.
|
|
34
|
+
*/
|
|
35
|
+
setItem: async (key: string, value: any): Promise<{ success: boolean, error?: string }> => {
|
|
36
|
+
return channel.send('plugin:storage:set-item', { pluginName, key, value: JSON.parse(JSON.stringify(value)) })
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Removes an item from the storage.
|
|
41
|
+
* @param key The key of the item to remove.
|
|
42
|
+
* @returns A promise that resolves when the item has been removed.
|
|
43
|
+
*/
|
|
44
|
+
removeItem: async (key: string): Promise<{ success: boolean, error?: string }> => {
|
|
45
|
+
return channel.send('plugin:storage:remove-item', { pluginName, key })
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Clears all items from the storage for the current plugin.
|
|
50
|
+
* @returns A promise that resolves when the storage has been cleared.
|
|
51
|
+
*/
|
|
52
|
+
clear: async (): Promise<{ success: boolean, error?: string }> => {
|
|
53
|
+
return channel.send('plugin:storage:clear', { pluginName })
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Retrieves all items from the storage for the current plugin.
|
|
58
|
+
* @returns A promise that resolves with an object containing all items.
|
|
59
|
+
*/
|
|
60
|
+
getAllItems: async (): Promise<Record<string, any>> => {
|
|
61
|
+
return channel.send('plugin:storage:get-all', { pluginName })
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Listens for changes to the storage.
|
|
66
|
+
* When `clear()` is called, the key will be `__clear__`.
|
|
67
|
+
* @param callback The function to call when the storage changes for the current plugin.
|
|
68
|
+
* @returns A function to unsubscribe from the listener.
|
|
69
|
+
*/
|
|
70
|
+
onDidChange: (callback: (data: { name: string, key?: string }) => void) => {
|
|
71
|
+
const listener = (data: { name: string, key?: string }) => {
|
|
72
|
+
if (data.name === pluginName) {
|
|
73
|
+
callback(data)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
channel.on('plugin:storage:update', listener)
|
|
78
|
+
|
|
79
|
+
return () => {
|
|
80
|
+
channel.off('plugin:storage:update', listener)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
package/plugin/sdk/types.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { genChannel } from '../../channel';
|
|
2
|
-
import {
|
|
3
|
-
BrowserWindowConstructorOptions,
|
|
4
|
-
|
|
2
|
+
import type {
|
|
3
|
+
BrowserWindowConstructorOptions,
|
|
4
|
+
BrowserWindow,
|
|
5
|
+
WebContents,
|
|
6
|
+
} from 'electron'
|
|
5
7
|
|
|
6
8
|
export function createWindow(options: BrowserWindowConstructorOptions & { file?: string } & { url?: string }): number {
|
|
7
9
|
const res = genChannel().sendSync('window:new', options)
|
package/preload/index.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const PRELOAD_LOADING_CHANNEL = '@talex-touch/preload'
|
|
2
|
+
|
|
3
|
+
export type LoadingMode = 'classic' | 'progress' | 'debug'
|
|
4
|
+
|
|
5
|
+
export type LoadingState = 'start' | 'finish'
|
|
6
|
+
|
|
7
|
+
export type LoadingEvent =
|
|
8
|
+
| { type: 'mode'; mode: LoadingMode }
|
|
9
|
+
| { type: 'message'; message: string }
|
|
10
|
+
| { type: 'progress'; delta?: number; reset?: boolean }
|
|
11
|
+
| { type: 'state'; state: LoadingState }
|
|
12
|
+
|
|
13
|
+
export interface PreloadAPI {
|
|
14
|
+
sendPreloadEvent(event: LoadingEvent): void
|
|
15
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { LoadingEvent, LoadingMode, LoadingState, PreloadAPI } from './loading'
|
|
2
|
+
|
|
3
|
+
function getPreloadApi(): PreloadAPI | null {
|
|
4
|
+
if (typeof window === 'undefined') return null
|
|
5
|
+
return window.api ?? null
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function sendPreloadEvent(event: LoadingEvent): void {
|
|
9
|
+
const api = getPreloadApi()
|
|
10
|
+
api?.sendPreloadEvent(event)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function preloadLog(message: string): void {
|
|
14
|
+
sendPreloadEvent({ type: 'message', message })
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function preloadProgress(delta = 0.05): void {
|
|
18
|
+
sendPreloadEvent({ type: 'progress', delta })
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function preloadResetProgress(): void {
|
|
22
|
+
sendPreloadEvent({ type: 'progress', reset: true })
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function preloadSetMode(mode: LoadingMode): void {
|
|
26
|
+
sendPreloadEvent({ type: 'mode', mode })
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function preloadState(state: LoadingState): void {
|
|
30
|
+
sendPreloadEvent({ type: 'state', state })
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function preloadDebugStep(message: string, delta = 0.08): void {
|
|
34
|
+
preloadLog(message)
|
|
35
|
+
preloadProgress(delta)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function preloadRemoveOverlay(): void {
|
|
39
|
+
if (typeof window === 'undefined') return
|
|
40
|
+
window.postMessage({ payload: 'removeLoading' }, '*')
|
|
41
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* Interface for command line argument mapper options
|
|
4
|
+
* @interface IArgMapperOptions
|
|
5
|
+
*/
|
|
6
|
+
export interface IArgMapperOptions {
|
|
7
|
+
/** The type of touch window - either main window or core-box popup */
|
|
8
|
+
touchType?: 'main' | 'core-box'
|
|
9
|
+
/** User data directory path */
|
|
10
|
+
userDataDir?: string
|
|
11
|
+
/** Application path */
|
|
12
|
+
appPath?: string
|
|
13
|
+
/** Renderer client identifier */
|
|
14
|
+
rendererClientId?: string
|
|
15
|
+
/** Launch time ticks value */
|
|
16
|
+
launchTimeTicks?: string
|
|
17
|
+
/** Time ticks value */
|
|
18
|
+
timeTicks?: string
|
|
19
|
+
/** Additional dynamic string properties */
|
|
20
|
+
[key: string]: string | undefined
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
declare global {
|
|
24
|
+
export interface Window {
|
|
25
|
+
/** Global argument mapper cache */
|
|
26
|
+
$argMapper: IArgMapperOptions
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Converts environment arguments into a structured mapper object
|
|
32
|
+
* @param args - Array of command line arguments (defaults to process.argv)
|
|
33
|
+
* @returns Mapped command line arguments as key-value pairs
|
|
34
|
+
*/
|
|
35
|
+
export function useArgMapper(args: string[] = process.argv): IArgMapperOptions {
|
|
36
|
+
if ( window.$argMapper ) {
|
|
37
|
+
return window.$argMapper
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const mapper: IArgMapperOptions = {}
|
|
41
|
+
|
|
42
|
+
for (const arg of args) {
|
|
43
|
+
if (arg.startsWith('--') && arg.includes('=')) {
|
|
44
|
+
const [key, ...valueParts] = arg.slice(2).split('=')
|
|
45
|
+
const value = valueParts.join('=')
|
|
46
|
+
|
|
47
|
+
const camelCaseKey = key.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase())
|
|
48
|
+
mapper[camelCaseKey] = value
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return window.$argMapper = mapper
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Gets the current touch type from command line arguments
|
|
57
|
+
* @returns The touch type ('main' | 'core-box') or undefined
|
|
58
|
+
*/
|
|
59
|
+
export function useTouchType() {
|
|
60
|
+
const argMapper = useArgMapper()
|
|
61
|
+
|
|
62
|
+
return argMapper.touchType
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Checks if the current window is the main window
|
|
67
|
+
* @returns True if the current window is the main window
|
|
68
|
+
*/
|
|
69
|
+
export function isMainWindow() {
|
|
70
|
+
return useTouchType() === 'main'
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Checks if the current window is a core-box popup
|
|
75
|
+
* @returns True if the current window is a core-box popup
|
|
76
|
+
*/
|
|
77
|
+
export function isCoreBox() {
|
|
78
|
+
return useTouchType() === 'core-box'
|
|
79
|
+
}
|