@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.
Files changed (80) hide show
  1. package/channel/index.ts +49 -1
  2. package/common/index.ts +2 -0
  3. package/common/search/gather.ts +45 -0
  4. package/common/search/index.ts +67 -0
  5. package/common/storage/constants.ts +16 -2
  6. package/common/storage/entity/index.ts +2 -1
  7. package/common/storage/entity/openers.ts +32 -0
  8. package/common/storage/entity/shortcut-settings.ts +22 -0
  9. package/common/storage/shortcut-storage.ts +58 -0
  10. package/common/utils/file.ts +62 -0
  11. package/common/{utils.ts → utils/index.ts} +14 -2
  12. package/common/utils/polling.ts +184 -0
  13. package/common/utils/task-queue.ts +108 -0
  14. package/common/utils/time.ts +374 -0
  15. package/core-box/README.md +8 -8
  16. package/core-box/builder/index.ts +6 -0
  17. package/core-box/builder/tuff-builder.example.ts.bak +258 -0
  18. package/core-box/builder/tuff-builder.ts +1162 -0
  19. package/core-box/index.ts +5 -2
  20. package/core-box/run-tests.sh +7 -0
  21. package/core-box/search.ts +1 -536
  22. package/core-box/tuff/index.ts +6 -0
  23. package/core-box/tuff/tuff-dsl.ts +1412 -0
  24. package/electron/clipboard-helper.ts +199 -0
  25. package/electron/env-tool.ts +36 -2
  26. package/electron/file-parsers/index.ts +8 -0
  27. package/electron/file-parsers/parsers/text-parser.ts +109 -0
  28. package/electron/file-parsers/registry.ts +92 -0
  29. package/electron/file-parsers/types.ts +58 -0
  30. package/electron/index.ts +3 -0
  31. package/eventbus/index.ts +0 -7
  32. package/index.ts +3 -1
  33. package/package.json +4 -29
  34. package/plugin/channel.ts +48 -16
  35. package/plugin/index.ts +194 -30
  36. package/plugin/log/types.ts +11 -0
  37. package/plugin/node/index.ts +4 -0
  38. package/plugin/node/logger-manager.ts +113 -0
  39. package/plugin/{log → node}/logger.ts +41 -7
  40. package/plugin/plugin-source.ts +74 -0
  41. package/plugin/preload.ts +5 -15
  42. package/plugin/providers/index.ts +2 -0
  43. package/plugin/providers/registry.ts +47 -0
  44. package/plugin/providers/types.ts +54 -0
  45. package/plugin/risk/index.ts +1 -0
  46. package/plugin/risk/types.ts +20 -0
  47. package/plugin/sdk/enum/bridge-event.ts +4 -0
  48. package/plugin/sdk/enum/index.ts +1 -0
  49. package/plugin/sdk/hooks/bridge.ts +68 -0
  50. package/plugin/sdk/hooks/index.ts +2 -1
  51. package/plugin/sdk/hooks/life-cycle.ts +2 -4
  52. package/plugin/sdk/index.ts +2 -0
  53. package/plugin/sdk/storage.ts +84 -0
  54. package/plugin/sdk/types.ts +2 -2
  55. package/plugin/sdk/window/index.ts +5 -3
  56. package/preload/index.ts +2 -0
  57. package/preload/loading.ts +15 -0
  58. package/preload/renderer.ts +41 -0
  59. package/renderer/hooks/arg-mapper.ts +79 -0
  60. package/renderer/hooks/index.ts +2 -0
  61. package/renderer/hooks/initialize.ts +198 -0
  62. package/renderer/index.ts +3 -0
  63. package/renderer/storage/app-settings.ts +2 -0
  64. package/renderer/storage/base-storage.ts +1 -0
  65. package/renderer/storage/openers.ts +11 -0
  66. package/renderer/touch-sdk/env.ts +106 -0
  67. package/renderer/touch-sdk/index.ts +108 -0
  68. package/renderer/touch-sdk/terminal.ts +85 -0
  69. package/renderer/touch-sdk/utils.ts +61 -0
  70. package/search/levenshtein-utils.ts +39 -0
  71. package/search/types.ts +16 -16
  72. package/types/index.ts +2 -1
  73. package/types/modules/base.ts +146 -0
  74. package/types/modules/index.ts +4 -0
  75. package/types/modules/module-lifecycle.ts +148 -0
  76. package/types/modules/module-manager.ts +99 -0
  77. package/types/modules/module.ts +112 -0
  78. package/types/touch-app-core.ts +16 -93
  79. package/core-box/types.ts +0 -384
  80. 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 { genChannel } from './channel'
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
- $send: (type: string, data: any) => void
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 init(window: Window) {
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
- initBridge(window)
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,2 @@
1
+ export * from './registry'
2
+ export * from './types'
@@ -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,4 @@
1
+ export enum BridgeEventForCoreBox {
2
+ CORE_BOX_INPUT_CHANGE = 'core-box:input-change',
3
+ CORE_BOX_CLIPBOARD_CHANGE = 'core-box:clipboard-change'
4
+ }
@@ -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
- genChannel().regChannel("@lifecycle:" + type, (obj: any) => {
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)
@@ -16,3 +16,5 @@ export * from './types'
16
16
  export * from './window/index'
17
17
  export * from './hooks/index'
18
18
  export * from './service/index'
19
+
20
+ export * from './storage'
@@ -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
+ }
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @fileoverview Plugin SDK utilities and interfaces for Talex Touch plugin development
3
- * @author Talex Touch Team
2
+ * @fileoverview Plugin SDK utilities and interfaces for Tuff plugin development
3
+ * @author Tuff Team
4
4
  * @version 1.0.0
5
5
  */
6
6
 
@@ -1,7 +1,9 @@
1
1
  import { genChannel } from '../../channel';
2
- import {
3
- BrowserWindowConstructorOptions, BrowserWindow, WebContents
4
- } from "electron";
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)
@@ -0,0 +1,2 @@
1
+ export * from './loading'
2
+ export * from './renderer'
@@ -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
+ }
@@ -0,0 +1,2 @@
1
+ export * from './arg-mapper'
2
+ export * from './initialize'