@talex-touch/utils 1.0.42 → 1.0.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintcache +1 -0
- package/__tests__/cloud-sync-sdk.test.ts +442 -0
- package/__tests__/icons/icons.test.ts +84 -0
- package/__tests__/plugin-sdk-lifecycle.test.ts +130 -0
- package/__tests__/power-sdk.test.ts +143 -0
- package/__tests__/preset-export-types.test.ts +108 -0
- package/__tests__/search/fuzzy-match.test.ts +137 -0
- package/__tests__/transport/port-policy.test.ts +44 -0
- package/__tests__/transport-domain-sdks.test.ts +152 -0
- package/__tests__/types/update.test.ts +67 -0
- package/account/account-sdk.ts +915 -0
- package/account/index.ts +2 -0
- package/account/types.ts +321 -0
- package/analytics/client.ts +136 -0
- package/analytics/index.ts +2 -0
- package/analytics/types.ts +156 -0
- package/animation/auto-resize.ts +322 -0
- package/animation/window-node.ts +26 -19
- package/auth/clerk-types.ts +12 -30
- package/auth/index.ts +0 -2
- package/auth/useAuthState.ts +6 -14
- package/base/index.ts +2 -0
- package/base/log-level.ts +105 -0
- package/channel/index.ts +170 -69
- package/cloud-sync/cloud-sync-sdk.ts +450 -0
- package/cloud-sync/index.ts +1 -0
- package/common/file-scan-utils.ts +17 -9
- package/common/index.ts +4 -0
- package/common/logger/index.ts +46 -0
- package/common/logger/logger-manager.ts +303 -0
- package/common/logger/module-logger.ts +270 -0
- package/common/logger/transport-logger.ts +234 -0
- package/common/logger/types.ts +93 -0
- package/common/search/gather.ts +48 -6
- package/common/search/index.ts +8 -0
- package/common/storage/constants.ts +13 -0
- package/common/storage/entity/app-settings.ts +245 -0
- package/common/storage/entity/index.ts +3 -0
- package/common/storage/entity/layout-atom-types.ts +147 -0
- package/common/storage/entity/openers.ts +1 -0
- package/common/storage/entity/preset-cloud-api.ts +132 -0
- package/common/storage/entity/preset-export-types.ts +256 -0
- package/common/storage/entity/shortcut-settings.ts +1 -0
- package/common/storage/shortcut-storage.ts +11 -0
- package/common/utils/clone-diagnostics.ts +105 -0
- package/common/utils/file.ts +16 -8
- package/common/utils/index.ts +6 -2
- package/common/utils/payload-preview.ts +173 -0
- package/common/utils/polling.ts +167 -13
- package/common/utils/safe-path.ts +103 -0
- package/common/utils/safe-shell.ts +115 -0
- package/common/utils/task-queue.ts +4 -1
- package/core-box/builder/tuff-builder.ts +0 -1
- package/core-box/index.ts +1 -1
- package/core-box/recommendation.ts +38 -1
- package/core-box/tuff/tuff-dsl.ts +32 -0
- package/electron/download-manager.ts +10 -7
- package/electron/env-tool.ts +42 -40
- package/electron/index.ts +0 -1
- package/env/index.ts +156 -0
- package/eslint.config.js +55 -0
- package/i18n/index.ts +62 -0
- package/i18n/locales/en.json +226 -0
- package/i18n/locales/zh.json +226 -0
- package/i18n/message-keys.ts +236 -0
- package/i18n/resolver.ts +181 -0
- package/icons/index.ts +257 -0
- package/icons/svg.ts +69 -0
- package/index.ts +9 -1
- package/intelligence/client.ts +72 -42
- package/market/constants.ts +9 -5
- package/market/index.ts +1 -1
- package/market/types.ts +19 -4
- package/package.json +15 -5
- package/permission/index.ts +143 -46
- package/permission/legacy.ts +26 -0
- package/permission/registry.ts +304 -0
- package/permission/types.ts +164 -0
- package/plugin/channel.ts +68 -39
- package/plugin/index.ts +80 -7
- package/plugin/install.ts +3 -0
- package/plugin/log/types.ts +22 -5
- package/plugin/node/logger-manager.ts +11 -3
- package/plugin/node/logger.ts +24 -17
- package/plugin/preload.ts +25 -2
- package/plugin/providers/index.ts +4 -4
- package/plugin/providers/market-client.ts +6 -3
- package/plugin/providers/npm-provider.ts +22 -7
- package/plugin/providers/tpex-provider.ts +22 -8
- package/plugin/sdk/box-items.ts +14 -0
- package/plugin/sdk/box-sdk.ts +64 -0
- package/plugin/sdk/channel.ts +119 -4
- package/plugin/sdk/clipboard.ts +26 -12
- package/plugin/sdk/cloud-sync.ts +113 -0
- package/plugin/sdk/common.ts +19 -11
- package/plugin/sdk/core-box.ts +6 -15
- package/plugin/sdk/division-box.ts +160 -65
- package/plugin/sdk/examples/storage-onDidChange-example.js +5 -2
- package/plugin/sdk/feature-sdk.ts +111 -76
- package/plugin/sdk/flow.ts +146 -45
- package/plugin/sdk/hooks/bridge.ts +13 -6
- package/plugin/sdk/hooks/life-cycle.ts +35 -16
- package/plugin/sdk/index.ts +14 -3
- package/plugin/sdk/intelligence.ts +87 -0
- package/plugin/sdk/meta/README.md +179 -0
- package/plugin/sdk/meta-sdk.ts +244 -0
- package/plugin/sdk/notification.ts +9 -0
- package/plugin/sdk/plugin-info.ts +64 -0
- package/plugin/sdk/power.ts +155 -0
- package/plugin/sdk/recommend.ts +21 -0
- package/plugin/sdk/service/index.ts +12 -8
- package/plugin/sdk/sqlite.ts +141 -0
- package/plugin/sdk/storage.ts +2 -6
- package/plugin/sdk/system.ts +2 -9
- package/plugin/sdk/temp-files.ts +41 -0
- package/plugin/sdk/touch-sdk.ts +18 -0
- package/plugin/sdk/types.ts +44 -4
- package/plugin/sdk/window/index.ts +12 -9
- package/plugin/sdk-version.ts +231 -0
- package/preload/renderer.ts +3 -2
- package/renderer/hooks/arg-mapper.ts +16 -2
- package/renderer/hooks/index.ts +13 -0
- package/renderer/hooks/initialize.ts +2 -1
- package/renderer/hooks/use-agent-market-sdk.ts +7 -0
- package/renderer/hooks/use-agent-market.ts +106 -0
- package/renderer/hooks/use-agents-sdk.ts +7 -0
- package/renderer/hooks/use-app-sdk.ts +7 -0
- package/renderer/hooks/use-channel.ts +33 -4
- package/renderer/hooks/use-download-sdk.ts +21 -0
- package/renderer/hooks/use-intelligence-sdk.ts +7 -0
- package/renderer/hooks/use-intelligence-stats.ts +290 -0
- package/renderer/hooks/use-intelligence.ts +55 -214
- package/renderer/hooks/use-market-sdk.ts +16 -0
- package/renderer/hooks/use-notification-sdk.ts +7 -0
- package/renderer/hooks/use-permission-sdk.ts +7 -0
- package/renderer/hooks/use-permission.ts +325 -0
- package/renderer/hooks/use-platform-sdk.ts +7 -0
- package/renderer/hooks/use-plugin-sdk.ts +16 -0
- package/renderer/hooks/use-settings-sdk.ts +7 -0
- package/renderer/hooks/use-update-sdk.ts +21 -0
- package/renderer/index.ts +1 -0
- package/renderer/ref.ts +19 -10
- package/renderer/shared/components/SharedPluginDetailContent.vue +84 -0
- package/renderer/shared/components/SharedPluginDetailHeader.vue +116 -0
- package/renderer/shared/components/SharedPluginDetailMetaList.vue +39 -0
- package/renderer/shared/components/SharedPluginDetailReadme.vue +45 -0
- package/renderer/shared/components/SharedPluginDetailVersions.vue +98 -0
- package/renderer/shared/components/index.ts +5 -0
- package/renderer/shared/components/shims-vue.d.ts +5 -0
- package/renderer/shared/index.ts +2 -0
- package/renderer/shared/plugin-detail.ts +62 -0
- package/renderer/storage/app-settings.ts +3 -1
- package/renderer/storage/base-storage.ts +508 -82
- package/renderer/storage/intelligence-storage.ts +31 -40
- package/renderer/storage/openers.ts +3 -1
- package/renderer/storage/storage-subscription.ts +126 -42
- package/renderer/touch-sdk/env.ts +10 -10
- package/renderer/touch-sdk/index.ts +114 -18
- package/renderer/touch-sdk/terminal.ts +24 -13
- package/search/feature-matcher.ts +279 -0
- package/search/fuzzy-match.ts +64 -34
- package/search/index.ts +10 -0
- package/search/levenshtein-utils.ts +17 -11
- package/transport/errors.ts +310 -0
- package/transport/event/builder.ts +378 -0
- package/transport/event/index.ts +7 -0
- package/transport/event/types.ts +292 -0
- package/transport/events/index.ts +2670 -0
- package/transport/events/meta-overlay.ts +79 -0
- package/transport/events/types/agents.ts +177 -0
- package/transport/events/types/app-index.ts +9 -0
- package/transport/events/types/app.ts +475 -0
- package/transport/events/types/box-item.ts +222 -0
- package/transport/events/types/clipboard.ts +80 -0
- package/transport/events/types/core-box.ts +534 -0
- package/transport/events/types/device-idle.ts +7 -0
- package/transport/events/types/division-box.ts +99 -0
- package/transport/events/types/download.ts +115 -0
- package/transport/events/types/file-index.ts +73 -0
- package/transport/events/types/flow.ts +149 -0
- package/transport/events/types/index.ts +70 -0
- package/transport/events/types/market.ts +39 -0
- package/transport/events/types/meta-overlay.ts +184 -0
- package/transport/events/types/notification.ts +140 -0
- package/transport/events/types/permission.ts +90 -0
- package/transport/events/types/platform.ts +8 -0
- package/transport/events/types/plugin.ts +620 -0
- package/transport/events/types/sentry.ts +20 -0
- package/transport/events/types/storage.ts +208 -0
- package/transport/events/types/transport.ts +60 -0
- package/transport/events/types/tray.ts +16 -0
- package/transport/events/types/update.ts +78 -0
- package/transport/index.ts +139 -0
- package/transport/main.ts +2 -0
- package/transport/sdk/constants.ts +29 -0
- package/transport/sdk/domains/agents-market.ts +47 -0
- package/transport/sdk/domains/agents.ts +62 -0
- package/transport/sdk/domains/app.ts +48 -0
- package/transport/sdk/domains/disposable.ts +35 -0
- package/transport/sdk/domains/download.ts +139 -0
- package/transport/sdk/domains/index.ts +13 -0
- package/transport/sdk/domains/intelligence.ts +616 -0
- package/transport/sdk/domains/market.ts +35 -0
- package/transport/sdk/domains/notification.ts +62 -0
- package/transport/sdk/domains/permission.ts +85 -0
- package/transport/sdk/domains/platform.ts +19 -0
- package/transport/sdk/domains/plugin.ts +144 -0
- package/transport/sdk/domains/settings.ts +92 -0
- package/transport/sdk/domains/update.ts +64 -0
- package/transport/sdk/index.ts +60 -0
- package/transport/sdk/main-transport.ts +710 -0
- package/transport/sdk/main.ts +9 -0
- package/transport/sdk/plugin-transport.ts +654 -0
- package/transport/sdk/port-policy.ts +38 -0
- package/transport/sdk/renderer-transport.ts +1165 -0
- package/transport/types.ts +605 -0
- package/types/agent.ts +399 -0
- package/types/cloud-sync.ts +157 -0
- package/types/division-box.ts +31 -31
- package/types/download.ts +1 -0
- package/types/flow.ts +63 -12
- package/types/icon.ts +2 -1
- package/types/index.ts +5 -0
- package/types/intelligence.ts +166 -173
- package/types/modules/base.ts +2 -0
- package/types/path-browserify.d.ts +5 -0
- package/types/platform.ts +12 -0
- package/types/startup-info.ts +32 -0
- package/types/touch-app-core.ts +8 -8
- package/types/update.ts +94 -1
- package/vitest.config.ts +25 -0
- package/auth/useClerkConfig.ts +0 -40
- package/auth/useClerkProvider.ts +0 -52
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
CoreBoxCanvasConfig,
|
|
3
|
+
CoreBoxThemeConfig,
|
|
4
|
+
LayoutAtomConfig,
|
|
5
|
+
LayoutCanvasConfig,
|
|
6
|
+
ThemePresetConfig,
|
|
7
|
+
} from './layout-atom-types'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Version of the preset export format
|
|
11
|
+
* Increment when breaking changes occur
|
|
12
|
+
*/
|
|
13
|
+
export const PRESET_EXPORT_VERSION = 2
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Preset export data structure
|
|
17
|
+
* Supports both local file export and future cloud publishing
|
|
18
|
+
*/
|
|
19
|
+
export interface PresetExportData {
|
|
20
|
+
/** Export format version */
|
|
21
|
+
version: number
|
|
22
|
+
/** Export timestamp (ISO 8601) */
|
|
23
|
+
exportedAt: string
|
|
24
|
+
/** Optional preset metadata */
|
|
25
|
+
meta: PresetMeta
|
|
26
|
+
/** Layout atom configuration */
|
|
27
|
+
layout?: LayoutAtomConfig
|
|
28
|
+
/** CoreBox theme configuration */
|
|
29
|
+
coreBox?: CoreBoxThemeConfig
|
|
30
|
+
/** Theme-level configuration */
|
|
31
|
+
theme?: ThemePresetConfig
|
|
32
|
+
/** Main layout canvas configuration */
|
|
33
|
+
mainCanvas?: LayoutCanvasConfig
|
|
34
|
+
/** CoreBox canvas configuration */
|
|
35
|
+
coreBoxCanvas?: CoreBoxCanvasConfig
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface PresetCompat {
|
|
39
|
+
minAppVersion?: string
|
|
40
|
+
maxAppVersion?: string
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Preset metadata for identification and discovery
|
|
45
|
+
*/
|
|
46
|
+
export interface PresetMeta {
|
|
47
|
+
/** Unique preset ID (uuid for local, assigned for cloud) */
|
|
48
|
+
id?: string
|
|
49
|
+
/** Human-readable name */
|
|
50
|
+
name: string
|
|
51
|
+
/** Optional description */
|
|
52
|
+
description?: string
|
|
53
|
+
/** Author information */
|
|
54
|
+
author?: PresetAuthor
|
|
55
|
+
/** Tags for categorization */
|
|
56
|
+
tags?: string[]
|
|
57
|
+
/** Preview image URL or data URI */
|
|
58
|
+
preview?: string
|
|
59
|
+
/** Creation timestamp */
|
|
60
|
+
createdAt?: string
|
|
61
|
+
/** Last update timestamp */
|
|
62
|
+
updatedAt?: string
|
|
63
|
+
/** Release channel */
|
|
64
|
+
channel?: 'stable' | 'beta'
|
|
65
|
+
/** Compatibility window */
|
|
66
|
+
compat?: PresetCompat
|
|
67
|
+
/** Preset source */
|
|
68
|
+
source?: 'local' | 'nexus'
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Author information for cloud-published presets
|
|
73
|
+
*/
|
|
74
|
+
export interface PresetAuthor {
|
|
75
|
+
/** Author display name */
|
|
76
|
+
name: string
|
|
77
|
+
/** Author ID (for cloud) */
|
|
78
|
+
id?: string
|
|
79
|
+
/** Author avatar URL */
|
|
80
|
+
avatar?: string
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Cloud preset listing item (for marketplace)
|
|
85
|
+
*/
|
|
86
|
+
export interface CloudPresetItem {
|
|
87
|
+
/** Unique cloud ID */
|
|
88
|
+
id: string
|
|
89
|
+
/** Preset metadata */
|
|
90
|
+
meta: PresetMeta
|
|
91
|
+
/** Download count */
|
|
92
|
+
downloads: number
|
|
93
|
+
/** Like count */
|
|
94
|
+
likes: number
|
|
95
|
+
/** Whether current user liked */
|
|
96
|
+
liked?: boolean
|
|
97
|
+
/** Publish status */
|
|
98
|
+
status: 'published' | 'pending' | 'rejected'
|
|
99
|
+
/** Publish timestamp */
|
|
100
|
+
publishedAt: string
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Cloud preset API response
|
|
105
|
+
*/
|
|
106
|
+
export interface CloudPresetListResponse {
|
|
107
|
+
items: CloudPresetItem[]
|
|
108
|
+
total: number
|
|
109
|
+
page: number
|
|
110
|
+
pageSize: number
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Cloud preset publish request
|
|
115
|
+
*/
|
|
116
|
+
export interface CloudPresetPublishRequest {
|
|
117
|
+
preset: PresetExportData
|
|
118
|
+
visibility: 'public' | 'unlisted' | 'private'
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Validation result for preset import
|
|
123
|
+
*/
|
|
124
|
+
export interface PresetValidationResult {
|
|
125
|
+
valid: boolean
|
|
126
|
+
errors: string[]
|
|
127
|
+
warnings: string[]
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Validates a preset export data structure
|
|
132
|
+
*/
|
|
133
|
+
export function validatePresetData(data: unknown): PresetValidationResult {
|
|
134
|
+
const errors: string[] = []
|
|
135
|
+
const warnings: string[] = []
|
|
136
|
+
|
|
137
|
+
if (!data || typeof data !== 'object') {
|
|
138
|
+
return { valid: false, errors: ['Invalid data format'], warnings: [] }
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const preset = data as Record<string, unknown>
|
|
142
|
+
|
|
143
|
+
// Check version
|
|
144
|
+
if (typeof preset.version !== 'number') {
|
|
145
|
+
errors.push('Missing or invalid version field')
|
|
146
|
+
} else if (preset.version > PRESET_EXPORT_VERSION) {
|
|
147
|
+
warnings.push(`Preset version (${preset.version}) is newer than supported (${PRESET_EXPORT_VERSION})`)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Check meta
|
|
151
|
+
if (!preset.meta || typeof preset.meta !== 'object') {
|
|
152
|
+
errors.push('Missing or invalid meta field')
|
|
153
|
+
} else {
|
|
154
|
+
const meta = preset.meta as Record<string, unknown>
|
|
155
|
+
if (typeof meta.name !== 'string' || !meta.name.trim()) {
|
|
156
|
+
errors.push('Missing or invalid preset name')
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Check that at least one config is present
|
|
161
|
+
if (!preset.layout && !preset.coreBox && !preset.theme && !preset.mainCanvas && !preset.coreBoxCanvas) {
|
|
162
|
+
warnings.push('Preset contains no configurable fields')
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Validate layout structure if present
|
|
166
|
+
if (preset.layout) {
|
|
167
|
+
const layout = preset.layout as Record<string, unknown>
|
|
168
|
+
if (!layout.preset || !layout.header || !layout.aside || !layout.view || !layout.nav) {
|
|
169
|
+
errors.push('Invalid layout configuration structure')
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Validate coreBox structure if present
|
|
174
|
+
if (preset.coreBox) {
|
|
175
|
+
const coreBox = preset.coreBox as Record<string, unknown>
|
|
176
|
+
if (!coreBox.preset || !coreBox.logo || !coreBox.input || !coreBox.results) {
|
|
177
|
+
errors.push('Invalid CoreBox configuration structure')
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (preset.theme) {
|
|
182
|
+
const theme = preset.theme as Record<string, unknown>
|
|
183
|
+
if (!theme.style && !theme.addon && !theme.transition && !theme.palette && !theme.window) {
|
|
184
|
+
warnings.push('Theme preset is empty')
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (preset.mainCanvas) {
|
|
189
|
+
const mainCanvas = preset.mainCanvas as Record<string, unknown>
|
|
190
|
+
if (
|
|
191
|
+
typeof mainCanvas.columns !== 'number'
|
|
192
|
+
|| typeof mainCanvas.rowHeight !== 'number'
|
|
193
|
+
|| !Array.isArray(mainCanvas.items)
|
|
194
|
+
) {
|
|
195
|
+
errors.push('Invalid mainCanvas configuration structure')
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (preset.coreBoxCanvas) {
|
|
200
|
+
const coreBoxCanvas = preset.coreBoxCanvas as Record<string, unknown>
|
|
201
|
+
if (
|
|
202
|
+
typeof coreBoxCanvas.columns !== 'number'
|
|
203
|
+
|| typeof coreBoxCanvas.rowHeight !== 'number'
|
|
204
|
+
|| !Array.isArray(coreBoxCanvas.items)
|
|
205
|
+
) {
|
|
206
|
+
errors.push('Invalid coreBoxCanvas configuration structure')
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return {
|
|
211
|
+
valid: errors.length === 0,
|
|
212
|
+
errors,
|
|
213
|
+
warnings
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Creates a new preset export data structure
|
|
219
|
+
*/
|
|
220
|
+
export function createPresetExport(options: {
|
|
221
|
+
name: string
|
|
222
|
+
description?: string
|
|
223
|
+
layout?: LayoutAtomConfig
|
|
224
|
+
coreBox?: CoreBoxThemeConfig
|
|
225
|
+
theme?: ThemePresetConfig
|
|
226
|
+
mainCanvas?: LayoutCanvasConfig
|
|
227
|
+
coreBoxCanvas?: CoreBoxCanvasConfig
|
|
228
|
+
author?: PresetAuthor
|
|
229
|
+
tags?: string[]
|
|
230
|
+
channel?: 'stable' | 'beta'
|
|
231
|
+
source?: 'local' | 'nexus'
|
|
232
|
+
compat?: PresetCompat
|
|
233
|
+
}): PresetExportData {
|
|
234
|
+
const now = new Date().toISOString()
|
|
235
|
+
return {
|
|
236
|
+
version: PRESET_EXPORT_VERSION,
|
|
237
|
+
exportedAt: now,
|
|
238
|
+
meta: {
|
|
239
|
+
id: crypto.randomUUID(),
|
|
240
|
+
name: options.name,
|
|
241
|
+
description: options.description,
|
|
242
|
+
author: options.author,
|
|
243
|
+
tags: options.tags,
|
|
244
|
+
createdAt: now,
|
|
245
|
+
updatedAt: now,
|
|
246
|
+
channel: options.channel ?? 'beta',
|
|
247
|
+
source: options.source ?? 'local',
|
|
248
|
+
compat: options.compat,
|
|
249
|
+
},
|
|
250
|
+
layout: options.layout,
|
|
251
|
+
coreBox: options.coreBox,
|
|
252
|
+
theme: options.theme,
|
|
253
|
+
mainCanvas: options.mainCanvas,
|
|
254
|
+
coreBoxCanvas: options.coreBoxCanvas,
|
|
255
|
+
}
|
|
256
|
+
}
|
|
@@ -55,6 +55,17 @@ class ShortcutStorage {
|
|
|
55
55
|
this._save()
|
|
56
56
|
return true
|
|
57
57
|
}
|
|
58
|
+
|
|
59
|
+
updateShortcutEnabled(id: string, enabled: boolean): boolean {
|
|
60
|
+
const shortcut = this.getShortcutById(id)
|
|
61
|
+
if (!shortcut) {
|
|
62
|
+
return false
|
|
63
|
+
}
|
|
64
|
+
shortcut.meta.enabled = enabled
|
|
65
|
+
shortcut.meta.modificationTime = Date.now()
|
|
66
|
+
this._save()
|
|
67
|
+
return true
|
|
68
|
+
}
|
|
58
69
|
}
|
|
59
70
|
|
|
60
71
|
export default ShortcutStorage
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
export interface CloneIssue {
|
|
2
|
+
path: string
|
|
3
|
+
reason: string
|
|
4
|
+
type: string
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const DEFAULT_MAX_DEPTH = 4
|
|
8
|
+
const MAX_INSPECT_ITEMS = 50
|
|
9
|
+
|
|
10
|
+
function getValueType(value: unknown): string {
|
|
11
|
+
return Object.prototype.toString.call(value)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function isCloneError(error: unknown): boolean {
|
|
15
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
16
|
+
return message.includes('could not be cloned')
|
|
17
|
+
|| message.includes('DataCloneError')
|
|
18
|
+
|| message.includes('Cannot clone')
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function summarizeClonePayload(payload: unknown): Record<string, unknown> {
|
|
22
|
+
const summary: Record<string, unknown> = { valueType: typeof payload }
|
|
23
|
+
if (payload === null) {
|
|
24
|
+
summary.value = null
|
|
25
|
+
return summary
|
|
26
|
+
}
|
|
27
|
+
if (typeof payload !== 'object') {
|
|
28
|
+
summary.value = payload
|
|
29
|
+
return summary
|
|
30
|
+
}
|
|
31
|
+
summary.objectType = getValueType(payload)
|
|
32
|
+
if (Array.isArray(payload)) {
|
|
33
|
+
summary.length = payload.length
|
|
34
|
+
return summary
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
const keys = Object.keys(payload as Record<string, unknown>)
|
|
38
|
+
summary.keys = keys.slice(0, 20)
|
|
39
|
+
summary.keysCount = keys.length
|
|
40
|
+
} catch (error) {
|
|
41
|
+
summary.keysError = error instanceof Error ? error.message : String(error)
|
|
42
|
+
}
|
|
43
|
+
return summary
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function findCloneIssue(
|
|
47
|
+
payload: unknown,
|
|
48
|
+
options?: { maxDepth?: number }
|
|
49
|
+
): CloneIssue | null {
|
|
50
|
+
if (typeof structuredClone !== 'function') return null
|
|
51
|
+
|
|
52
|
+
const maxDepth = options?.maxDepth ?? DEFAULT_MAX_DEPTH
|
|
53
|
+
const seen = new WeakSet<object>()
|
|
54
|
+
|
|
55
|
+
const inspect = (value: unknown, path: string, depth: number): CloneIssue | null => {
|
|
56
|
+
try {
|
|
57
|
+
structuredClone(value)
|
|
58
|
+
return null
|
|
59
|
+
} catch (error) {
|
|
60
|
+
const reason = error instanceof Error ? error.message : String(error)
|
|
61
|
+
if (depth >= maxDepth) {
|
|
62
|
+
return { path, reason: 'max_depth', type: getValueType(value) }
|
|
63
|
+
}
|
|
64
|
+
if (value && typeof value === 'object') {
|
|
65
|
+
if (seen.has(value)) {
|
|
66
|
+
return { path, reason: 'circular_ref', type: getValueType(value) }
|
|
67
|
+
}
|
|
68
|
+
seen.add(value)
|
|
69
|
+
if (Array.isArray(value)) {
|
|
70
|
+
const limit = Math.min(value.length, MAX_INSPECT_ITEMS)
|
|
71
|
+
for (let i = 0; i < limit; i += 1) {
|
|
72
|
+
const result = inspect(value[i], `${path}[${i}]`, depth + 1)
|
|
73
|
+
if (result) return result
|
|
74
|
+
}
|
|
75
|
+
if (value.length > limit) {
|
|
76
|
+
return { path, reason: 'array_truncated', type: getValueType(value) }
|
|
77
|
+
}
|
|
78
|
+
} else {
|
|
79
|
+
let entries: [string, unknown][]
|
|
80
|
+
try {
|
|
81
|
+
entries = Object.entries(value as Record<string, unknown>)
|
|
82
|
+
} catch (entryError) {
|
|
83
|
+
const entryReason = entryError instanceof Error ? entryError.message : String(entryError)
|
|
84
|
+
return { path, reason: entryReason, type: getValueType(value) }
|
|
85
|
+
}
|
|
86
|
+
const limit = Math.min(entries.length, MAX_INSPECT_ITEMS)
|
|
87
|
+
for (let i = 0; i < limit; i += 1) {
|
|
88
|
+
const entry = entries[i]
|
|
89
|
+
if (!entry)
|
|
90
|
+
continue
|
|
91
|
+
const [key, entryValue] = entry
|
|
92
|
+
const result = inspect(entryValue, `${path}.${key}`, depth + 1)
|
|
93
|
+
if (result) return result
|
|
94
|
+
}
|
|
95
|
+
if (entries.length > limit) {
|
|
96
|
+
return { path, reason: 'keys_truncated', type: getValueType(value) }
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return { path, reason, type: getValueType(value) }
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return inspect(payload, 'payload', 0)
|
|
105
|
+
}
|
package/common/utils/file.ts
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
|
-
|
|
1
|
+
import pathBrowserify from 'path-browserify'
|
|
2
|
+
import { hasWindow } from '../../env'
|
|
3
|
+
|
|
2
4
|
const path = (() => {
|
|
3
|
-
if (
|
|
4
|
-
return
|
|
5
|
-
}
|
|
6
|
-
try {
|
|
7
|
-
return require('path-browserify')
|
|
5
|
+
if (hasWindow()) {
|
|
6
|
+
return pathBrowserify
|
|
8
7
|
}
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
|
|
9
|
+
const nodeRequire = typeof require === 'function' ? require : null
|
|
10
|
+
if (nodeRequire) {
|
|
11
|
+
try {
|
|
12
|
+
return nodeRequire('node:path')
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return pathBrowserify
|
|
16
|
+
}
|
|
11
17
|
}
|
|
18
|
+
|
|
19
|
+
return pathBrowserify
|
|
12
20
|
})()
|
|
13
21
|
|
|
14
22
|
/**
|
package/common/utils/index.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { hasDocument } from '../../env'
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Delays execution for a given amount of milliseconds.
|
|
3
5
|
*
|
|
@@ -51,7 +53,7 @@ export function anyStr2Num(str: string): bigint {
|
|
|
51
53
|
* ```
|
|
52
54
|
*/
|
|
53
55
|
export function num2anyStr(num: bigint): string {
|
|
54
|
-
const [baseStr, encoded] = num.toString().split('000')
|
|
56
|
+
const [baseStr, encoded = ''] = num.toString().split('000')
|
|
55
57
|
const base = Number(baseStr)
|
|
56
58
|
|
|
57
59
|
let result = ''
|
|
@@ -100,7 +102,7 @@ export function structuredStrictStringify(value: unknown): string {
|
|
|
100
102
|
return 'null'
|
|
101
103
|
if (Array.isArray(val))
|
|
102
104
|
return 'Array'
|
|
103
|
-
if (
|
|
105
|
+
if (hasDocument()) {
|
|
104
106
|
if (val instanceof Node)
|
|
105
107
|
return 'DOMNode'
|
|
106
108
|
}
|
|
@@ -177,6 +179,8 @@ export function structuredStrictStringify(value: unknown): string {
|
|
|
177
179
|
}
|
|
178
180
|
|
|
179
181
|
export * from './file'
|
|
182
|
+
export * from './safe-path'
|
|
183
|
+
export * from './safe-shell'
|
|
180
184
|
|
|
181
185
|
export { type AdaptiveTaskQueueOptions, runAdaptiveTaskQueue } from './task-queue'
|
|
182
186
|
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
export interface PayloadPreviewOptions {
|
|
2
|
+
maxOutputChars?: number
|
|
3
|
+
maxStringChars?: number
|
|
4
|
+
maxDepth?: number
|
|
5
|
+
maxKeys?: number
|
|
6
|
+
maxArrayLength?: number
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const DEFAULT_OPTIONS: Required<PayloadPreviewOptions> = {
|
|
10
|
+
maxOutputChars: 800,
|
|
11
|
+
maxStringChars: 200,
|
|
12
|
+
maxDepth: 4,
|
|
13
|
+
maxKeys: 30,
|
|
14
|
+
maxArrayLength: 20,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function truncate(value: string, maxChars: number): string {
|
|
18
|
+
if (maxChars <= 0)
|
|
19
|
+
return ''
|
|
20
|
+
return value.length > maxChars ? `${value.slice(0, maxChars)}…` : value
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function redactDataUrl(value: string, maxPrefixChars: number): string {
|
|
24
|
+
if (!value.startsWith('data:'))
|
|
25
|
+
return value
|
|
26
|
+
const base64Index = value.indexOf(';base64,')
|
|
27
|
+
if (base64Index === -1)
|
|
28
|
+
return value
|
|
29
|
+
|
|
30
|
+
const prefixEnd = base64Index + ';base64,'.length
|
|
31
|
+
const prefix = value.slice(0, prefixEnd)
|
|
32
|
+
const omittedChars = Math.max(0, value.length - prefixEnd)
|
|
33
|
+
const safePrefix = truncate(prefix, Math.max(10, maxPrefixChars))
|
|
34
|
+
return `${safePrefix}[base64 omitted ${omittedChars} chars]`
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function isTypedArray(value: unknown): value is ArrayBufferView {
|
|
38
|
+
return (
|
|
39
|
+
typeof ArrayBuffer !== 'undefined'
|
|
40
|
+
&& typeof ArrayBuffer.isView === 'function'
|
|
41
|
+
&& ArrayBuffer.isView(value)
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function bufferLength(value: unknown): number | null {
|
|
46
|
+
try {
|
|
47
|
+
if (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) {
|
|
48
|
+
return value.length
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// ignore
|
|
53
|
+
}
|
|
54
|
+
return null
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function formatPayloadPreview(payload: unknown, options?: PayloadPreviewOptions): string {
|
|
58
|
+
const opts = { ...DEFAULT_OPTIONS, ...(options ?? {}) }
|
|
59
|
+
|
|
60
|
+
if (payload === null || payload === undefined)
|
|
61
|
+
return String(payload)
|
|
62
|
+
if (typeof payload === 'string') {
|
|
63
|
+
const redacted = redactDataUrl(payload, opts.maxStringChars)
|
|
64
|
+
return truncate(redacted, opts.maxOutputChars)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const seen = typeof WeakSet !== 'undefined' ? new WeakSet<object>() : null
|
|
68
|
+
|
|
69
|
+
const simplify = (value: unknown, depth: number): unknown => {
|
|
70
|
+
if (value === null || value === undefined)
|
|
71
|
+
return value
|
|
72
|
+
if (depth >= opts.maxDepth)
|
|
73
|
+
return '[max-depth]'
|
|
74
|
+
|
|
75
|
+
const valueType = typeof value
|
|
76
|
+
if (valueType === 'string') {
|
|
77
|
+
const redacted = redactDataUrl(value as string, opts.maxStringChars)
|
|
78
|
+
return truncate(redacted, opts.maxStringChars)
|
|
79
|
+
}
|
|
80
|
+
if (valueType === 'number' || valueType === 'boolean')
|
|
81
|
+
return value
|
|
82
|
+
if (valueType === 'bigint')
|
|
83
|
+
return `${value.toString()}n`
|
|
84
|
+
if (valueType === 'symbol')
|
|
85
|
+
return String(value)
|
|
86
|
+
if (valueType === 'function')
|
|
87
|
+
return '[function]'
|
|
88
|
+
|
|
89
|
+
if (value instanceof Error) {
|
|
90
|
+
return {
|
|
91
|
+
name: value.name,
|
|
92
|
+
message: truncate(value.message ?? '', opts.maxStringChars),
|
|
93
|
+
stack: typeof value.stack === 'string' ? truncate(value.stack, opts.maxOutputChars) : undefined,
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const bufLen = bufferLength(value)
|
|
98
|
+
if (typeof bufLen === 'number')
|
|
99
|
+
return `[buffer ${bufLen} bytes]`
|
|
100
|
+
if (isTypedArray(value))
|
|
101
|
+
return `[typed-array ${value.byteLength} bytes]`
|
|
102
|
+
if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {
|
|
103
|
+
return `[array-buffer ${value.byteLength} bytes]`
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (Array.isArray(value)) {
|
|
107
|
+
const items = value.slice(0, opts.maxArrayLength).map(item => simplify(item, depth + 1))
|
|
108
|
+
if (value.length > opts.maxArrayLength) {
|
|
109
|
+
items.push(`[+${value.length - opts.maxArrayLength} more]`)
|
|
110
|
+
}
|
|
111
|
+
return items
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (valueType === 'object') {
|
|
115
|
+
const obj = value as Record<string, unknown>
|
|
116
|
+
if (seen) {
|
|
117
|
+
if (seen.has(obj))
|
|
118
|
+
return '[circular]'
|
|
119
|
+
seen.add(obj)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (obj instanceof Map) {
|
|
123
|
+
return {
|
|
124
|
+
_type: 'Map',
|
|
125
|
+
size: obj.size,
|
|
126
|
+
entries: Array.from(obj.entries())
|
|
127
|
+
.slice(0, opts.maxArrayLength)
|
|
128
|
+
.map(([k, v]) => [simplify(k, depth + 1), simplify(v, depth + 1)]),
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (obj instanceof Set) {
|
|
133
|
+
return {
|
|
134
|
+
_type: 'Set',
|
|
135
|
+
size: obj.size,
|
|
136
|
+
values: Array.from(obj.values())
|
|
137
|
+
.slice(0, opts.maxArrayLength)
|
|
138
|
+
.map(v => simplify(v, depth + 1)),
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const keys = Object.keys(obj)
|
|
143
|
+
const out: Record<string, unknown> = {}
|
|
144
|
+
for (const key of keys.slice(0, opts.maxKeys)) {
|
|
145
|
+
try {
|
|
146
|
+
out[key] = simplify(obj[key], depth + 1)
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
out[key] = '[throws]'
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (keys.length > opts.maxKeys) {
|
|
153
|
+
out._moreKeys = keys.length - opts.maxKeys
|
|
154
|
+
}
|
|
155
|
+
return out
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
try {
|
|
159
|
+
return truncate(String(value), opts.maxStringChars)
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
return '[unserializable]'
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
try {
|
|
167
|
+
const text = JSON.stringify(simplify(payload, 0))
|
|
168
|
+
return truncate(text, opts.maxOutputChars)
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
return '[unserializable]'
|
|
172
|
+
}
|
|
173
|
+
}
|