@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,16 @@
|
|
|
1
|
+
import { onUnmounted } from 'vue'
|
|
2
|
+
import { useTuffTransport } from '../../transport'
|
|
3
|
+
import { createDisposableBag } from '../../transport/sdk'
|
|
4
|
+
import { createMarketSdk } from '../../transport/sdk/domains/market'
|
|
5
|
+
|
|
6
|
+
export function useMarketSdk() {
|
|
7
|
+
const transport = useTuffTransport()
|
|
8
|
+
return createMarketSdk(transport)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function useMarketSdkScope() {
|
|
12
|
+
const sdk = useMarketSdk()
|
|
13
|
+
const disposables = createDisposableBag()
|
|
14
|
+
onUnmounted(() => disposables.dispose())
|
|
15
|
+
return { sdk, disposables }
|
|
16
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { createNotificationSdk } from '../../transport/sdk/domains/notification'
|
|
2
|
+
import { useTuffTransport } from '../../transport/sdk/index'
|
|
3
|
+
|
|
4
|
+
export function useNotificationSdk() {
|
|
5
|
+
const transport = useTuffTransport()
|
|
6
|
+
return createNotificationSdk(transport)
|
|
7
|
+
}
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* usePermission - Permission management hooks for renderer process
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
PermissionDefinition,
|
|
7
|
+
PermissionGrant,
|
|
8
|
+
PluginPermissionStatus,
|
|
9
|
+
} from '../../permission/types'
|
|
10
|
+
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
|
11
|
+
import { usePermissionSdk } from './use-permission-sdk'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Hook for managing plugin permissions
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* @deprecated 请优先使用 usePermissionSdk(),该 hook 仅保留兼容壳。
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
export function usePermission(pluginId: string) {
|
|
21
|
+
const permissionSdk = usePermissionSdk()
|
|
22
|
+
const permissions = ref<PermissionGrant[]>([])
|
|
23
|
+
const loading = ref(true)
|
|
24
|
+
const error = ref<string | null>(null)
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Refresh permissions from main process
|
|
28
|
+
*/
|
|
29
|
+
async function refresh(): Promise<void> {
|
|
30
|
+
loading.value = true
|
|
31
|
+
error.value = null
|
|
32
|
+
try {
|
|
33
|
+
const result = await permissionSdk.getPlugin({ pluginId })
|
|
34
|
+
permissions.value = result || []
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
error.value = (e as Error).message
|
|
38
|
+
}
|
|
39
|
+
finally {
|
|
40
|
+
loading.value = false
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Grant a permission
|
|
46
|
+
*/
|
|
47
|
+
async function grant(permissionId: string): Promise<boolean> {
|
|
48
|
+
try {
|
|
49
|
+
const result = await permissionSdk.grant({
|
|
50
|
+
pluginId,
|
|
51
|
+
permissionId,
|
|
52
|
+
grantedBy: 'user',
|
|
53
|
+
})
|
|
54
|
+
if (result?.success) {
|
|
55
|
+
await refresh()
|
|
56
|
+
}
|
|
57
|
+
return result?.success || false
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return false
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Revoke a permission
|
|
66
|
+
*/
|
|
67
|
+
async function revoke(permissionId: string): Promise<boolean> {
|
|
68
|
+
try {
|
|
69
|
+
const result = await permissionSdk.revoke({
|
|
70
|
+
pluginId,
|
|
71
|
+
permissionId,
|
|
72
|
+
})
|
|
73
|
+
if (result?.success) {
|
|
74
|
+
await refresh()
|
|
75
|
+
}
|
|
76
|
+
return result?.success || false
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return false
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Grant multiple permissions
|
|
85
|
+
*/
|
|
86
|
+
async function grantMultiple(permissionIds: string[]): Promise<boolean> {
|
|
87
|
+
try {
|
|
88
|
+
const result = await permissionSdk.grantMultiple({
|
|
89
|
+
pluginId,
|
|
90
|
+
permissionIds,
|
|
91
|
+
grantedBy: 'user',
|
|
92
|
+
})
|
|
93
|
+
if (result?.success) {
|
|
94
|
+
await refresh()
|
|
95
|
+
}
|
|
96
|
+
return result?.success || false
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return false
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Revoke all permissions
|
|
105
|
+
*/
|
|
106
|
+
async function revokeAll(): Promise<boolean> {
|
|
107
|
+
try {
|
|
108
|
+
const result = await permissionSdk.revokeAll({
|
|
109
|
+
pluginId,
|
|
110
|
+
})
|
|
111
|
+
if (result?.success) {
|
|
112
|
+
await refresh()
|
|
113
|
+
}
|
|
114
|
+
return result?.success || false
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
return false
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Check if a permission is granted
|
|
123
|
+
*/
|
|
124
|
+
function isGranted(permissionId: string): boolean {
|
|
125
|
+
return permissions.value.some(p => p.permissionId === permissionId)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Get granted permission IDs
|
|
130
|
+
*/
|
|
131
|
+
const grantedIds = computed(() => permissions.value.map(p => p.permissionId))
|
|
132
|
+
|
|
133
|
+
// Listen for permission updates
|
|
134
|
+
let unsubscribe: (() => void) | null = null
|
|
135
|
+
|
|
136
|
+
onMounted(() => {
|
|
137
|
+
refresh()
|
|
138
|
+
unsubscribe = permissionSdk.onUpdated((payload) => {
|
|
139
|
+
if (payload?.pluginId === pluginId) {
|
|
140
|
+
refresh()
|
|
141
|
+
}
|
|
142
|
+
})
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
onUnmounted(() => {
|
|
146
|
+
unsubscribe?.()
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
return {
|
|
150
|
+
permissions,
|
|
151
|
+
loading,
|
|
152
|
+
error,
|
|
153
|
+
refresh,
|
|
154
|
+
grant,
|
|
155
|
+
revoke,
|
|
156
|
+
grantMultiple,
|
|
157
|
+
revokeAll,
|
|
158
|
+
isGranted,
|
|
159
|
+
grantedIds,
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Hook for getting plugin permission status
|
|
165
|
+
*/
|
|
166
|
+
/**
|
|
167
|
+
* @deprecated 请优先使用 usePermissionSdk().getStatus(),该 hook 仅保留兼容壳。
|
|
168
|
+
*/
|
|
169
|
+
|
|
170
|
+
export function usePermissionStatus(
|
|
171
|
+
pluginId: string,
|
|
172
|
+
sdkapi: number | undefined,
|
|
173
|
+
declared: { required: string[], optional: string[] },
|
|
174
|
+
) {
|
|
175
|
+
const permissionSdk = usePermissionSdk()
|
|
176
|
+
const status = ref<PluginPermissionStatus | null>(null)
|
|
177
|
+
const loading = ref(true)
|
|
178
|
+
|
|
179
|
+
async function refresh(): Promise<void> {
|
|
180
|
+
loading.value = true
|
|
181
|
+
try {
|
|
182
|
+
const result = await permissionSdk.getStatus({
|
|
183
|
+
pluginId,
|
|
184
|
+
sdkapi,
|
|
185
|
+
required: declared.required,
|
|
186
|
+
optional: declared.optional,
|
|
187
|
+
})
|
|
188
|
+
status.value = result
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
status.value = null
|
|
192
|
+
}
|
|
193
|
+
finally {
|
|
194
|
+
loading.value = false
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Computed helpers
|
|
199
|
+
const enforcePermissions = computed(() => status.value?.enforcePermissions ?? false)
|
|
200
|
+
const missingRequired = computed(() => status.value?.missingRequired ?? [])
|
|
201
|
+
const hasWarning = computed(() => !!status.value?.warning)
|
|
202
|
+
const warning = computed(() => status.value?.warning)
|
|
203
|
+
|
|
204
|
+
onMounted(() => {
|
|
205
|
+
refresh()
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
status,
|
|
210
|
+
loading,
|
|
211
|
+
refresh,
|
|
212
|
+
enforcePermissions,
|
|
213
|
+
missingRequired,
|
|
214
|
+
hasWarning,
|
|
215
|
+
warning,
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Hook for getting permission registry (all available permissions)
|
|
221
|
+
*/
|
|
222
|
+
/**
|
|
223
|
+
* @deprecated 请优先使用 usePermissionSdk().getRegistry(),该 hook 仅保留兼容壳。
|
|
224
|
+
*/
|
|
225
|
+
|
|
226
|
+
export function usePermissionRegistry() {
|
|
227
|
+
const permissionSdk = usePermissionSdk()
|
|
228
|
+
const registry = ref<PermissionDefinition[]>([])
|
|
229
|
+
const loading = ref(true)
|
|
230
|
+
|
|
231
|
+
async function refresh(): Promise<void> {
|
|
232
|
+
loading.value = true
|
|
233
|
+
try {
|
|
234
|
+
const result = await permissionSdk.getRegistry()
|
|
235
|
+
registry.value = result || []
|
|
236
|
+
}
|
|
237
|
+
catch {
|
|
238
|
+
registry.value = []
|
|
239
|
+
}
|
|
240
|
+
finally {
|
|
241
|
+
loading.value = false
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Get permission by ID
|
|
247
|
+
*/
|
|
248
|
+
function getPermission(id: string): PermissionDefinition | undefined {
|
|
249
|
+
return registry.value.find(p => p.id === id)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Get permissions by category
|
|
254
|
+
*/
|
|
255
|
+
function byCategory(category: string): PermissionDefinition[] {
|
|
256
|
+
return registry.value.filter(p => p.category === category)
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Get permissions by risk level
|
|
261
|
+
*/
|
|
262
|
+
function byRisk(risk: string): PermissionDefinition[] {
|
|
263
|
+
return registry.value.filter(p => p.risk === risk)
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
onMounted(() => {
|
|
267
|
+
refresh()
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
return {
|
|
271
|
+
registry,
|
|
272
|
+
loading,
|
|
273
|
+
refresh,
|
|
274
|
+
getPermission,
|
|
275
|
+
byCategory,
|
|
276
|
+
byRisk,
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Hook for getting all plugin permissions
|
|
282
|
+
*/
|
|
283
|
+
/**
|
|
284
|
+
* @deprecated 请优先使用 usePermissionSdk().getAll(),该 hook 仅保留兼容壳。
|
|
285
|
+
*/
|
|
286
|
+
|
|
287
|
+
export function useAllPluginPermissions() {
|
|
288
|
+
const permissionSdk = usePermissionSdk()
|
|
289
|
+
const permissions = ref<Record<string, PermissionGrant[]>>({})
|
|
290
|
+
const loading = ref(true)
|
|
291
|
+
|
|
292
|
+
async function refresh(): Promise<void> {
|
|
293
|
+
loading.value = true
|
|
294
|
+
try {
|
|
295
|
+
const result = await permissionSdk.getAll()
|
|
296
|
+
permissions.value = result || {}
|
|
297
|
+
}
|
|
298
|
+
catch {
|
|
299
|
+
permissions.value = {}
|
|
300
|
+
}
|
|
301
|
+
finally {
|
|
302
|
+
loading.value = false
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Listen for permission updates
|
|
307
|
+
let unsubscribe: (() => void) | null = null
|
|
308
|
+
|
|
309
|
+
onMounted(() => {
|
|
310
|
+
refresh()
|
|
311
|
+
unsubscribe = permissionSdk.onUpdated(() => {
|
|
312
|
+
refresh()
|
|
313
|
+
})
|
|
314
|
+
})
|
|
315
|
+
|
|
316
|
+
onUnmounted(() => {
|
|
317
|
+
unsubscribe?.()
|
|
318
|
+
})
|
|
319
|
+
|
|
320
|
+
return {
|
|
321
|
+
permissions,
|
|
322
|
+
loading,
|
|
323
|
+
refresh,
|
|
324
|
+
}
|
|
325
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { onUnmounted } from 'vue'
|
|
2
|
+
import { useTuffTransport } from '../../transport'
|
|
3
|
+
import { createDisposableBag } from '../../transport/sdk'
|
|
4
|
+
import { createPluginSdk } from '../../transport/sdk/domains/plugin'
|
|
5
|
+
|
|
6
|
+
export function usePluginSdk() {
|
|
7
|
+
const transport = useTuffTransport()
|
|
8
|
+
return createPluginSdk(transport)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function usePluginSdkScope() {
|
|
12
|
+
const sdk = usePluginSdk()
|
|
13
|
+
const disposables = createDisposableBag()
|
|
14
|
+
onUnmounted(() => disposables.dispose())
|
|
15
|
+
return { sdk, disposables }
|
|
16
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { onUnmounted } from 'vue'
|
|
2
|
+
import { useTuffTransport } from '../../transport'
|
|
3
|
+
import { createDisposableBag } from '../../transport/sdk'
|
|
4
|
+
import { createUpdateSdk } from '../../transport/sdk/domains/update'
|
|
5
|
+
|
|
6
|
+
export function useUpdateSdk() {
|
|
7
|
+
const transport = useTuffTransport()
|
|
8
|
+
return createUpdateSdk(transport)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function useUpdateSdkScope() {
|
|
12
|
+
const sdk = useUpdateSdk()
|
|
13
|
+
const disposables = createDisposableBag()
|
|
14
|
+
const register = (dispose: () => void) => {
|
|
15
|
+
disposables.add(dispose)
|
|
16
|
+
return dispose
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
onUnmounted(() => disposables.dispose())
|
|
20
|
+
return { sdk, disposables, register }
|
|
21
|
+
}
|
package/renderer/index.ts
CHANGED
package/renderer/ref.ts
CHANGED
|
@@ -1,38 +1,47 @@
|
|
|
1
|
+
import type { WritableComputedRef } from 'vue'
|
|
1
2
|
import { computed, customRef } from 'vue'
|
|
2
3
|
|
|
3
|
-
export function useModelWrapper
|
|
4
|
+
export function useModelWrapper<
|
|
5
|
+
P extends Record<string, unknown>,
|
|
6
|
+
K extends string = 'modelValue'
|
|
7
|
+
>(
|
|
8
|
+
props: P,
|
|
9
|
+
emit: (event: `update:${K}`, value: P[K]) => void,
|
|
10
|
+
name?: K
|
|
11
|
+
): WritableComputedRef<P[K]> {
|
|
12
|
+
const key = (name ?? 'modelValue') as K
|
|
4
13
|
return computed({
|
|
5
|
-
get: () => props[
|
|
6
|
-
set: value => emit(`update:${
|
|
14
|
+
get: () => props[key] as P[K],
|
|
15
|
+
set: value => emit(`update:${key}` as `update:${K}`, value),
|
|
7
16
|
})
|
|
8
17
|
}
|
|
9
18
|
|
|
10
|
-
export function throttleRef(value:
|
|
19
|
+
export function throttleRef<T>(value: T, time: number) {
|
|
11
20
|
let ts = 0
|
|
12
21
|
|
|
13
|
-
return customRef((track, trigger) => {
|
|
22
|
+
return customRef<T>((track, trigger) => {
|
|
14
23
|
return {
|
|
15
24
|
get() {
|
|
16
25
|
track()
|
|
17
26
|
return value
|
|
18
27
|
},
|
|
19
28
|
set(newValue) {
|
|
20
|
-
if (
|
|
29
|
+
if (Date.now() - ts < time)
|
|
21
30
|
return
|
|
22
31
|
|
|
23
32
|
value = newValue
|
|
24
33
|
track()
|
|
25
34
|
trigger()
|
|
26
|
-
ts =
|
|
35
|
+
ts = Date.now()
|
|
27
36
|
},
|
|
28
37
|
}
|
|
29
38
|
})
|
|
30
39
|
}
|
|
31
40
|
|
|
32
|
-
export function debounceRef(value:
|
|
33
|
-
let timer:
|
|
41
|
+
export function debounceRef<T>(value: T, delay: number) {
|
|
42
|
+
let timer: ReturnType<typeof setTimeout> | undefined
|
|
34
43
|
|
|
35
|
-
return customRef((track, trigger) => {
|
|
44
|
+
return customRef<T>((track, trigger) => {
|
|
36
45
|
return {
|
|
37
46
|
get() {
|
|
38
47
|
track()
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { SharedPluginDetail } from '../plugin-detail'
|
|
3
|
+
import { computed } from 'vue'
|
|
4
|
+
import SharedPluginDetailHeader from './SharedPluginDetailHeader.vue'
|
|
5
|
+
import SharedPluginDetailMetaList from './SharedPluginDetailMetaList.vue'
|
|
6
|
+
import SharedPluginDetailReadme from './SharedPluginDetailReadme.vue'
|
|
7
|
+
import SharedPluginDetailVersions from './SharedPluginDetailVersions.vue'
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
detail: SharedPluginDetail
|
|
11
|
+
showMeta?: boolean
|
|
12
|
+
showReadme?: boolean
|
|
13
|
+
showVersions?: boolean
|
|
14
|
+
readmeTitle?: string
|
|
15
|
+
versionsTitle?: string
|
|
16
|
+
metaTitle?: string
|
|
17
|
+
emptyReadmeText?: string
|
|
18
|
+
emptyVersionsText?: string
|
|
19
|
+
renderMarkdown?: (markdown: string) => string
|
|
20
|
+
formatDate?: (value: string | number | Date) => string
|
|
21
|
+
formatNumber?: (value: number) => string
|
|
22
|
+
formatSize?: (value: number) => string
|
|
23
|
+
installsText?: string
|
|
24
|
+
versionText?: string
|
|
25
|
+
updatedText?: string
|
|
26
|
+
officialLabel?: string
|
|
27
|
+
installsLabel?: string
|
|
28
|
+
versionLabel?: string
|
|
29
|
+
updatedLabel?: string
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
33
|
+
showMeta: true,
|
|
34
|
+
showReadme: true,
|
|
35
|
+
showVersions: true,
|
|
36
|
+
readmeTitle: 'README',
|
|
37
|
+
versionsTitle: 'Versions',
|
|
38
|
+
metaTitle: '',
|
|
39
|
+
emptyReadmeText: 'No README',
|
|
40
|
+
emptyVersionsText: 'No versions'
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
const hasMeta = computed(() => (props.detail.metaItems?.length ?? 0) > 0)
|
|
44
|
+
</script>
|
|
45
|
+
|
|
46
|
+
<template>
|
|
47
|
+
<div class="space-y-6">
|
|
48
|
+
<SharedPluginDetailHeader
|
|
49
|
+
:detail="detail"
|
|
50
|
+
:format-date="formatDate"
|
|
51
|
+
:format-number="formatNumber"
|
|
52
|
+
:installs-text="installsText"
|
|
53
|
+
:version-text="versionText"
|
|
54
|
+
:updated-text="updatedText"
|
|
55
|
+
:official-label="officialLabel"
|
|
56
|
+
:installs-label="installsLabel"
|
|
57
|
+
:version-label="versionLabel"
|
|
58
|
+
:updated-label="updatedLabel"
|
|
59
|
+
/>
|
|
60
|
+
|
|
61
|
+
<div class="flex flex-col gap-6 lg:flex-row">
|
|
62
|
+
<div class="min-w-0 flex-1 space-y-6">
|
|
63
|
+
<SharedPluginDetailReadme
|
|
64
|
+
v-if="showReadme"
|
|
65
|
+
:readme="detail.readme"
|
|
66
|
+
:title="readmeTitle"
|
|
67
|
+
:empty-text="emptyReadmeText"
|
|
68
|
+
:render-markdown="renderMarkdown"
|
|
69
|
+
/>
|
|
70
|
+
<SharedPluginDetailVersions
|
|
71
|
+
v-if="showVersions"
|
|
72
|
+
:versions="detail.versions"
|
|
73
|
+
:title="versionsTitle"
|
|
74
|
+
:empty-text="emptyVersionsText"
|
|
75
|
+
:format-date="formatDate"
|
|
76
|
+
:format-size="formatSize"
|
|
77
|
+
/>
|
|
78
|
+
</div>
|
|
79
|
+
<aside v-if="showMeta && hasMeta" class="w-full lg:w-64">
|
|
80
|
+
<SharedPluginDetailMetaList :items="detail.metaItems" :title="metaTitle" />
|
|
81
|
+
</aside>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
</template>
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { SharedPluginDetail } from '../plugin-detail'
|
|
3
|
+
import { computed } from 'vue'
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
detail: SharedPluginDetail
|
|
7
|
+
formatDate?: (value: string | number | Date) => string
|
|
8
|
+
formatNumber?: (value: number) => string
|
|
9
|
+
installsText?: string
|
|
10
|
+
versionText?: string
|
|
11
|
+
updatedText?: string
|
|
12
|
+
officialLabel?: string
|
|
13
|
+
installsLabel?: string
|
|
14
|
+
versionLabel?: string
|
|
15
|
+
updatedLabel?: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
19
|
+
officialLabel: 'Official',
|
|
20
|
+
installsLabel: 'Installs',
|
|
21
|
+
versionLabel: 'Version',
|
|
22
|
+
updatedLabel: 'Updated'
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
const displayInstalls = computed(() => {
|
|
26
|
+
if (props.detail.installs === undefined || props.detail.installs === null) {
|
|
27
|
+
return ''
|
|
28
|
+
}
|
|
29
|
+
return props.formatNumber ? props.formatNumber(props.detail.installs) : `${props.detail.installs}`
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
const installsPillText = computed(() => {
|
|
33
|
+
if (props.installsText) return props.installsText
|
|
34
|
+
if (!displayInstalls.value) return ''
|
|
35
|
+
return `${props.installsLabel} · ${displayInstalls.value}`
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
const updatedAtValue = computed(() => {
|
|
39
|
+
return props.detail.updatedAt ?? props.detail.latestVersion?.createdAt
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
const displayUpdatedAt = computed(() => {
|
|
43
|
+
if (!updatedAtValue.value) return ''
|
|
44
|
+
if (props.formatDate) return props.formatDate(updatedAtValue.value)
|
|
45
|
+
const date = new Date(updatedAtValue.value as any)
|
|
46
|
+
return Number.isNaN(date.valueOf()) ? `${updatedAtValue.value}` : date.toLocaleDateString()
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
const displayVersion = computed(() => props.detail.latestVersion?.version ?? '')
|
|
50
|
+
|
|
51
|
+
const isOfficial = computed(() => props.detail.official || props.detail.trustLevel === 'official')
|
|
52
|
+
|
|
53
|
+
const versionPillText = computed(() => {
|
|
54
|
+
if (props.versionText) return props.versionText
|
|
55
|
+
if (!displayVersion.value) return ''
|
|
56
|
+
return `${props.versionLabel} · v${displayVersion.value}`
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
const updatedPillText = computed(() => {
|
|
60
|
+
if (props.updatedText) return props.updatedText
|
|
61
|
+
if (!displayUpdatedAt.value) return ''
|
|
62
|
+
return `${props.updatedLabel} · ${displayUpdatedAt.value}`
|
|
63
|
+
})
|
|
64
|
+
</script>
|
|
65
|
+
|
|
66
|
+
<template>
|
|
67
|
+
<header class="space-y-3">
|
|
68
|
+
<div class="flex flex-wrap items-center gap-2">
|
|
69
|
+
<h2 class="text-2xl font-semibold">
|
|
70
|
+
{{ detail.name }}
|
|
71
|
+
</h2>
|
|
72
|
+
<span
|
|
73
|
+
v-if="isOfficial"
|
|
74
|
+
class="inline-flex items-center rounded-full bg-emerald-100 px-2 py-0.5 text-xs text-emerald-700"
|
|
75
|
+
>
|
|
76
|
+
{{ officialLabel }}
|
|
77
|
+
</span>
|
|
78
|
+
<span
|
|
79
|
+
v-if="detail.category?.label"
|
|
80
|
+
class="inline-flex items-center rounded-full bg-black/5 px-2 py-0.5 text-xs text-black/70"
|
|
81
|
+
>
|
|
82
|
+
{{ detail.category.label }}
|
|
83
|
+
</span>
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
<p v-if="detail.summary" class="text-sm text-black/70">
|
|
87
|
+
{{ detail.summary }}
|
|
88
|
+
</p>
|
|
89
|
+
|
|
90
|
+
<p v-if="detail.author?.name" class="text-xs text-black/50">
|
|
91
|
+
{{ detail.author.name }}
|
|
92
|
+
</p>
|
|
93
|
+
|
|
94
|
+
<div class="flex flex-wrap gap-2 text-xs text-black/60">
|
|
95
|
+
<span v-if="installsPillText" class="inline-flex items-center rounded-full bg-black/5 px-2 py-0.5">
|
|
96
|
+
{{ installsPillText }}
|
|
97
|
+
</span>
|
|
98
|
+
<span v-if="versionPillText" class="inline-flex items-center rounded-full bg-black/5 px-2 py-0.5">
|
|
99
|
+
{{ versionPillText }}
|
|
100
|
+
</span>
|
|
101
|
+
<span v-if="updatedPillText" class="inline-flex items-center rounded-full bg-black/5 px-2 py-0.5">
|
|
102
|
+
{{ updatedPillText }}
|
|
103
|
+
</span>
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
<div v-if="detail.badges?.length" class="flex flex-wrap gap-2">
|
|
107
|
+
<span
|
|
108
|
+
v-for="badge in detail.badges"
|
|
109
|
+
:key="badge"
|
|
110
|
+
class="inline-flex items-center rounded-full bg-black/5 px-2 py-0.5 text-xs text-black/70"
|
|
111
|
+
>
|
|
112
|
+
{{ badge }}
|
|
113
|
+
</span>
|
|
114
|
+
</div>
|
|
115
|
+
</header>
|
|
116
|
+
</template>
|