@termix-ssh/plugin-sdk 1.0.0
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/README.md +52 -0
- package/cli/commands/build.mjs +246 -0
- package/cli/commands/migrations.mjs +248 -0
- package/cli/commands/pack.mjs +42 -0
- package/cli/commands/sign.mjs +83 -0
- package/cli/commands/test.mjs +33 -0
- package/cli/commands/validate.mjs +215 -0
- package/cli/index.mjs +65 -0
- package/cli/lib/changelog.mjs +126 -0
- package/cli/lib/externals.mjs +46 -0
- package/cli/lib/plugin-dir.mjs +29 -0
- package/cli/lib/signing.mjs +86 -0
- package/cli/lib/static-url-imports.mjs +54 -0
- package/cli/lib/tmxplug.mjs +106 -0
- package/cli/patches/guacamole-common-js-flush.cjs +76 -0
- package/cli/patches/xterm-android-ime.cjs +130 -0
- package/client.d.ts +13 -0
- package/dist/backend.d.ts +1777 -0
- package/dist/backend.js +84 -0
- package/dist/capabilities.d.ts +38 -0
- package/dist/capabilities.js +71 -0
- package/dist/db.d.ts +112 -0
- package/dist/db.js +189 -0
- package/dist/ddl.d.ts +76 -0
- package/dist/ddl.js +678 -0
- package/dist/desktop.d.ts +346 -0
- package/dist/desktop.js +5 -0
- package/dist/frontend.d.ts +1206 -0
- package/dist/frontend.js +388 -0
- package/dist/host/chunk-F3SDZDDG.js +6017 -0
- package/dist/host/chunk-XGWE7BTJ.js +90 -0
- package/dist/host/chunk-XH5NXL6Y.js +56314 -0
- package/dist/host/chunk-YC2MAKSP.js +14 -0
- package/dist/host/linked-server-FZGWQW32.js +12 -0
- package/dist/host/rbac-api-6KDMBVDZ.js +52 -0
- package/dist/host/testing-host.js +414 -0
- package/dist/host/theme.css +91 -0
- package/dist/host/types/src/types/auth-protocols.d.ts +10 -0
- package/dist/host/types/src/types/connection-log.d.ts +13 -0
- package/dist/host/types/src/types/credential-sidebar-preferences.d.ts +38 -0
- package/dist/host/types/src/types/host-defaults.d.ts +60 -0
- package/dist/host/types/src/types/host-sidebar-preferences.d.ts +55 -0
- package/dist/host/types/src/types/index.d.ts +298 -0
- package/dist/host/types/src/types/keybindings.d.ts +27 -0
- package/dist/host/types/src/types/ui-preferences.d.ts +102 -0
- package/dist/host/types/src/types/ui-types.d.ts +260 -0
- package/dist/host/types/src/ui/api/admin-user-data-api.d.ts +11 -0
- package/dist/host/types/src/ui/api/auth-methods-api.d.ts +63 -0
- package/dist/host/types/src/ui/api/credential-sidebar-preferences-api.d.ts +3 -0
- package/dist/host/types/src/ui/api/credentials-api.d.ts +56 -0
- package/dist/host/types/src/ui/api/dashboard-api.d.ts +23 -0
- package/dist/host/types/src/ui/api/external-account-api.d.ts +8 -0
- package/dist/host/types/src/ui/api/host-sidebar-preferences-api.d.ts +3 -0
- package/dist/host/types/src/ui/api/host-status-api.d.ts +11 -0
- package/dist/host/types/src/ui/api/open-tabs-api.d.ts +74 -0
- package/dist/host/types/src/ui/api/plugins-api.d.ts +128 -0
- package/dist/host/types/src/ui/api/rbac-api.d.ts +167 -0
- package/dist/host/types/src/ui/api/settings-api.d.ts +22 -0
- package/dist/host/types/src/ui/api/ssh-host-management-api.d.ts +65 -0
- package/dist/host/types/src/ui/api/sync-api.d.ts +93 -0
- package/dist/host/types/src/ui/api/system-status-api.d.ts +49 -0
- package/dist/host/types/src/ui/api/ui-preferences-api.d.ts +8 -0
- package/dist/host/types/src/ui/api/user-management-api.d.ts +80 -0
- package/dist/host/types/src/ui/auth/Auth.d.ts +12 -0
- package/dist/host/types/src/ui/auth/auth-bits.d.ts +11 -0
- package/dist/host/types/src/ui/auth/silent-signin.d.ts +2 -0
- package/dist/host/types/src/ui/components/FullScreenAppWrapper.d.ts +9 -0
- package/dist/host/types/src/ui/components/alert-dialog.d.ts +14 -0
- package/dist/host/types/src/ui/components/alert.d.ts +9 -0
- package/dist/host/types/src/ui/components/badge.d.ts +9 -0
- package/dist/host/types/src/ui/components/button.d.ts +13 -0
- package/dist/host/types/src/ui/components/card-grid/CardGridCanvas.d.ts +22 -0
- package/dist/host/types/src/ui/components/card-grid/layout-utils.d.ts +26 -0
- package/dist/host/types/src/ui/components/card-grid/types.d.ts +29 -0
- package/dist/host/types/src/ui/components/card-masonry.d.ts +16 -0
- package/dist/host/types/src/ui/components/card.d.ts +11 -0
- package/dist/host/types/src/ui/components/charts/BarSeries.d.ts +16 -0
- package/dist/host/types/src/ui/components/charts/LineChart.d.ts +17 -0
- package/dist/host/types/src/ui/components/charts/RadialGauge.d.ts +18 -0
- package/dist/host/types/src/ui/components/charts/Sparkline.d.ts +22 -0
- package/dist/host/types/src/ui/components/charts/StatRow.d.ts +15 -0
- package/dist/host/types/src/ui/components/charts/geometry.d.ts +20 -0
- package/dist/host/types/src/ui/components/charts/index.d.ts +4 -0
- package/dist/host/types/src/ui/components/checkbox.d.ts +4 -0
- package/dist/host/types/src/ui/components/connection/ConnectionGate.d.ts +56 -0
- package/dist/host/types/src/ui/components/connection/ConnectionLogPanel.d.ts +9 -0
- package/dist/host/types/src/ui/components/connection/ConnectionScreen.d.ts +34 -0
- package/dist/host/types/src/ui/components/connection/connection-status.d.ts +1 -0
- package/dist/host/types/src/ui/components/data-view.d.ts +32 -0
- package/dist/host/types/src/ui/components/dialog.d.ts +17 -0
- package/dist/host/types/src/ui/components/dropdown-menu.d.ts +29 -0
- package/dist/host/types/src/ui/components/empty-state.d.ts +19 -0
- package/dist/host/types/src/ui/components/form-fields.d.ts +115 -0
- package/dist/host/types/src/ui/components/input.d.ts +3 -0
- package/dist/host/types/src/ui/components/kbd.d.ts +12 -0
- package/dist/host/types/src/ui/components/label.d.ts +4 -0
- package/dist/host/types/src/ui/components/manager-card.d.ts +25 -0
- package/dist/host/types/src/ui/components/meter.d.ts +14 -0
- package/dist/host/types/src/ui/components/metric-card.d.ts +18 -0
- package/dist/host/types/src/ui/components/panel-layout.d.ts +83 -0
- package/dist/host/types/src/ui/components/password-input.d.ts +4 -0
- package/dist/host/types/src/ui/components/popover.d.ts +7 -0
- package/dist/host/types/src/ui/components/scroll-area.d.ts +5 -0
- package/dist/host/types/src/ui/components/section-card.d.ts +29 -0
- package/dist/host/types/src/ui/components/select.d.ts +15 -0
- package/dist/host/types/src/ui/components/select2.d.ts +8 -0
- package/dist/host/types/src/ui/components/separator.d.ts +4 -0
- package/dist/host/types/src/ui/components/sheet.d.ts +14 -0
- package/dist/host/types/src/ui/components/sidebar.d.ts +69 -0
- package/dist/host/types/src/ui/components/skeleton.d.ts +2 -0
- package/dist/host/types/src/ui/components/slider.d.ts +4 -0
- package/dist/host/types/src/ui/components/sonner.d.ts +4 -0
- package/dist/host/types/src/ui/components/surface/prompt-styles.d.ts +4 -0
- package/dist/host/types/src/ui/components/surface/surface-scope.d.ts +79 -0
- package/dist/host/types/src/ui/components/switch.d.ts +4 -0
- package/dist/host/types/src/ui/components/tab-strip.d.ts +19 -0
- package/dist/host/types/src/ui/components/tabs.d.ts +7 -0
- package/dist/host/types/src/ui/components/textarea.d.ts +4 -0
- package/dist/host/types/src/ui/components/theme-provider.d.ts +14 -0
- package/dist/host/types/src/ui/components/tooltip.d.ts +7 -0
- package/dist/host/types/src/ui/contexts/BrandingContext.d.ts +15 -0
- package/dist/host/types/src/ui/contexts/UiPreferencesContext.d.ts +38 -0
- package/dist/host/types/src/ui/contexts/branding-document.d.ts +10 -0
- package/dist/host/types/src/ui/dashboard/dashboard-cards-registry.d.ts +30 -0
- package/dist/host/types/src/ui/hooks/use-action-slot.d.ts +10 -0
- package/dist/host/types/src/ui/hooks/use-adaptive-polling.d.ts +5 -0
- package/dist/host/types/src/ui/hooks/use-mobile.d.ts +1 -0
- package/dist/host/types/src/ui/hooks/use-permissions.d.ts +29 -0
- package/dist/host/types/src/ui/hooks/use-status-color-scheme.d.ts +12 -0
- package/dist/host/types/src/ui/hooks/use-sync-status.d.ts +4 -0
- package/dist/host/types/src/ui/hooks/useSshAuthProviders.d.ts +17 -0
- package/dist/host/types/src/ui/i18n/i18n.d.ts +52 -0
- package/dist/host/types/src/ui/lib/ServerStatusContext.d.ts +33 -0
- package/dist/host/types/src/ui/lib/adaptive-polling.d.ts +29 -0
- package/dist/host/types/src/ui/lib/adaptive-resource-budget.d.ts +39 -0
- package/dist/host/types/src/ui/lib/app-keyboard-shortcuts.d.ts +8 -0
- package/dist/host/types/src/ui/lib/base-path.d.ts +1 -0
- package/dist/host/types/src/ui/lib/clipboard-provider.d.ts +9 -0
- package/dist/host/types/src/ui/lib/clipboard.d.ts +20 -0
- package/dist/host/types/src/ui/lib/connection-origin.d.ts +47 -0
- package/dist/host/types/src/ui/lib/db-health-monitor.d.ts +34 -0
- package/dist/host/types/src/ui/lib/device-id.d.ts +1 -0
- package/dist/host/types/src/ui/lib/electron.d.ts +1 -0
- package/dist/host/types/src/ui/lib/embedded-server-status.d.ts +15 -0
- package/dist/host/types/src/ui/lib/error-message.d.ts +9 -0
- package/dist/host/types/src/ui/lib/frontend-logger.d.ts +67 -0
- package/dist/host/types/src/ui/lib/global-shortcut-handler.d.ts +3 -0
- package/dist/host/types/src/ui/lib/host-defaults-context.d.ts +48 -0
- package/dist/host/types/src/ui/lib/hosts-request-cache.d.ts +9 -0
- package/dist/host/types/src/ui/lib/keybinding-match.d.ts +3 -0
- package/dist/host/types/src/ui/lib/linked-server.d.ts +10 -0
- package/dist/host/types/src/ui/lib/local-adaptive-engine.d.ts +40 -0
- package/dist/host/types/src/ui/lib/permissions.d.ts +16 -0
- package/dist/host/types/src/ui/lib/plugin-i18n.d.ts +11 -0
- package/dist/host/types/src/ui/lib/plugin-icon.d.ts +11 -0
- package/dist/host/types/src/ui/lib/plugin-transport.d.ts +50 -0
- package/dist/host/types/src/ui/lib/registry.d.ts +29 -0
- package/dist/host/types/src/ui/lib/rem.d.ts +7 -0
- package/dist/host/types/src/ui/lib/remote-server-api.d.ts +11 -0
- package/dist/host/types/src/ui/lib/server-status-store.d.ts +37 -0
- package/dist/host/types/src/ui/lib/sync-events.d.ts +2 -0
- package/dist/host/types/src/ui/lib/sync-status.d.ts +6 -0
- package/dist/host/types/src/ui/lib/tab-jump-hotkey.d.ts +4 -0
- package/dist/host/types/src/ui/lib/theme.d.ts +21 -0
- package/dist/host/types/src/ui/lib/ttl-request-cache.d.ts +10 -0
- package/dist/host/types/src/ui/lib/usage-color.d.ts +5 -0
- package/dist/host/types/src/ui/lib/utils.d.ts +2 -0
- package/dist/host/types/src/ui/lib/visible-interval.d.ts +5 -0
- package/dist/host/types/src/ui/lib/widget-title.d.ts +8 -0
- package/dist/host/types/src/ui/lib/ws-auth.d.ts +1 -0
- package/dist/host/types/src/ui/main-axios.d.ts +170 -0
- package/dist/host/types/src/ui/plugin-host/PluginViewPlaceholder.d.ts +13 -0
- package/dist/host/types/src/ui/plugin-host/app.d.ts +18 -0
- package/dist/host/types/src/ui/plugin-host/auth-registry.d.ts +50 -0
- package/dist/host/types/src/ui/plugin-host/bridge.d.ts +26 -0
- package/dist/host/types/src/ui/plugin-host/component-registry.d.ts +24 -0
- package/dist/host/types/src/ui/plugin-host/desktop.d.ts +7 -0
- package/dist/host/types/src/ui/plugin-host/extension-registry.d.ts +16 -0
- package/dist/host/types/src/ui/plugin-host/host-scope.d.ts +26 -0
- package/dist/host/types/src/ui/plugin-host/loader.d.ts +52 -0
- package/dist/host/types/src/ui/plugin-host/plugin-store.d.ts +40 -0
- package/dist/host/types/src/ui/plugin-host/scope.d.ts +20 -0
- package/dist/host/types/src/ui/plugin-host/sdk-ui.d.ts +99 -0
- package/dist/host/types/src/ui/plugin-host/shell-bridge.d.ts +67 -0
- package/dist/host/types/src/ui/plugin-host/view-ownership.d.ts +31 -0
- package/dist/host/types/src/ui/settings/HostPluginSections.d.ts +31 -0
- package/dist/host/types/src/ui/settings/SettingsFields.d.ts +22 -0
- package/dist/host/types/src/ui/settings/host-feature-tabs.d.ts +11 -0
- package/dist/host/types/src/ui/settings/settings-components.d.ts +32 -0
- package/dist/host/types/src/ui/settings/settings-fields-util.d.ts +11 -0
- package/dist/host/types/src/ui/shell/ActionSlot.d.ts +41 -0
- package/dist/host/types/src/ui/shell/TabContext.d.ts +30 -0
- package/dist/host/types/src/ui/shell/action-registry.d.ts +99 -0
- package/dist/host/types/src/ui/shell/keybinding-registry.d.ts +62 -0
- package/dist/host/types/src/ui/shell/palette-registry.d.ts +55 -0
- package/dist/host/types/src/ui/shell/panel-registry.d.ts +24 -0
- package/dist/host/types/src/ui/shell/tab-registry.d.ts +92 -0
- package/dist/host/types/src/ui/sidebar/HostManagerTabs.d.ts +65 -0
- package/dist/host/types/src/ui/sidebar/host-contributions.d.ts +72 -0
- package/dist/host/types/src/ui/sidebar/host-defaults/catalog.d.ts +17 -0
- package/dist/host/types/src/ui/sidebar/host-protocols.d.ts +49 -0
- package/dist/host/types/src/ui/sidebar/quick-connect-host.d.ts +21 -0
- package/dist/host/types/src/ui/sidebar/rail-items.d.ts +103 -0
- package/dist/host/types/src/ui/ssh/connection-log/ConnectionLogContext.d.ts +17 -0
- package/dist/host/types/src/ui/ssh/dialogs/BrowserSignInDialog.d.ts +18 -0
- package/dist/host/types/src/ui/ssh/dialogs/HostKeyVerificationDialog.d.ts +17 -0
- package/dist/host/types/src/ui/ssh/dialogs/PassphraseDialog.d.ts +15 -0
- package/dist/host/types/src/ui/ssh/dialogs/SSHAuthDialog.d.ts +20 -0
- package/dist/host/types/src/ui/ssh/dialogs/TOTPDialog.d.ts +13 -0
- package/dist/host/ui.d.ts +1 -0
- package/dist/host/ui.js +31754 -0
- package/dist/host/use-permissions-NULZL43J.js +18 -0
- package/dist/host-commands.d.ts +89 -0
- package/dist/host-commands.js +387 -0
- package/dist/manifest.d.ts +461 -0
- package/dist/manifest.js +1499 -0
- package/dist/settings.d.ts +43 -0
- package/dist/settings.js +168 -0
- package/dist/ssh-certs.d.ts +25 -0
- package/dist/ssh-certs.js +234 -0
- package/dist/ssh-options.d.ts +23 -0
- package/dist/ssh-options.js +1 -0
- package/dist/table-builder.d.ts +26 -0
- package/dist/table-builder.js +87 -0
- package/dist/testing/safe-ports.d.ts +10 -0
- package/dist/testing/safe-ports.js +59 -0
- package/dist/testing/setup.d.ts +7 -0
- package/dist/testing/setup.js +146 -0
- package/dist/testing.d.ts +537 -0
- package/dist/testing.js +1451 -0
- package/dist/vitest-preset.d.ts +54 -0
- package/dist/vitest-preset.js +96 -0
- package/package.json +143 -0
- package/schema/changelog.schema.json +67 -0
- package/schema/manifest.schema.json +1160 -0
- package/tsconfig.plugin.json +31 -0
package/dist/frontend.js
ADDED
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The frontend contract: what a plugin's frontend entry receives, and the
|
|
3
|
+
* hooks its components use.
|
|
4
|
+
*
|
|
5
|
+
* A plugin frontend is `src/frontend/index.tsx` exporting `activate(app)` and
|
|
6
|
+
* optionally `deactivate()`. Everything it contributes goes through `app`, and
|
|
7
|
+
* everything registered there is removed when the plugin is disabled, without
|
|
8
|
+
* a page reload.
|
|
9
|
+
*
|
|
10
|
+
* This module has no runtime dependencies. The hooks delegate to a host that
|
|
11
|
+
* core installs at startup (`__setPluginHost`), because React, i18next and the
|
|
12
|
+
* shell's state all live in core and must be one instance across the shell
|
|
13
|
+
* and every plugin bundle.
|
|
14
|
+
*/
|
|
15
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
16
|
+
/** Stands in for a saved protocol secret the editor has not changed. */
|
|
17
|
+
export const HOST_PROTOCOL_SECRET_KEPT = "existing_protocol_secret";
|
|
18
|
+
export function definePluginFrontend(plugin) {
|
|
19
|
+
return plugin;
|
|
20
|
+
}
|
|
21
|
+
let host = null;
|
|
22
|
+
/**
|
|
23
|
+
* Called once by core, before any plugin loads. Not part of the plugin API:
|
|
24
|
+
* once set it cannot be swapped, so a plugin cannot replace the bridge every
|
|
25
|
+
* other plugin talks through.
|
|
26
|
+
*/
|
|
27
|
+
export function __setPluginHost(bridge) {
|
|
28
|
+
if (host && bridge !== host) {
|
|
29
|
+
throw new Error("@termix-ssh/plugin-sdk/frontend: the plugin host is already set");
|
|
30
|
+
}
|
|
31
|
+
host = bridge;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Set by the shared test setup, so a plugin component rendered on its own in a
|
|
35
|
+
* unit test still has hooks. A global rather than an import, because the test
|
|
36
|
+
* setup and the component can load different copies of this module.
|
|
37
|
+
*/
|
|
38
|
+
const TEST_HOST_KEY = "__termixTestPluginHost";
|
|
39
|
+
function requireHost() {
|
|
40
|
+
const fallback = globalThis[TEST_HOST_KEY];
|
|
41
|
+
if (!host && fallback)
|
|
42
|
+
return fallback;
|
|
43
|
+
if (!host) {
|
|
44
|
+
throw new Error("@termix-ssh/plugin-sdk/frontend: no plugin host. Hooks only work inside Termix or renderWithApp().");
|
|
45
|
+
}
|
|
46
|
+
return host;
|
|
47
|
+
}
|
|
48
|
+
/** The id of the plugin that registered the component being rendered. */
|
|
49
|
+
export function usePluginId() {
|
|
50
|
+
return requireHost().usePluginId();
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Translation bound to this plugin's namespace. Keys the plugin does not
|
|
54
|
+
* define fall back to core's shared strings (common.*, hosts.*).
|
|
55
|
+
*/
|
|
56
|
+
export function useTranslation() {
|
|
57
|
+
const bridge = requireHost();
|
|
58
|
+
return bridge.useTranslation(bridge.usePluginId());
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Whether the current user holds a permission. A short name resolves to this
|
|
62
|
+
* plugin's own namespace, a dotted id is taken as given. UI only: the backend
|
|
63
|
+
* route checks again.
|
|
64
|
+
*/
|
|
65
|
+
export function usePermission(permission) {
|
|
66
|
+
const bridge = requireHost();
|
|
67
|
+
return bridge.usePermission(bridge.usePluginId(), permission);
|
|
68
|
+
}
|
|
69
|
+
export function useSettings(scope, hostId) {
|
|
70
|
+
const bridge = requireHost();
|
|
71
|
+
return bridge.useSettings(bridge.usePluginId(), scope, hostId);
|
|
72
|
+
}
|
|
73
|
+
export function useHost(hostId) {
|
|
74
|
+
return requireHost().useHost(hostId);
|
|
75
|
+
}
|
|
76
|
+
export function useHosts() {
|
|
77
|
+
return requireHost().useHosts();
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Core's status for one host, kept current by the shell's own polling. Null
|
|
81
|
+
* outside the app shell (a standalone window) and for hosts with status
|
|
82
|
+
* checks off.
|
|
83
|
+
*/
|
|
84
|
+
export function useHostStatus(hostId) {
|
|
85
|
+
return requireHost().useHostStatus(hostId);
|
|
86
|
+
}
|
|
87
|
+
export function useCurrentUser() {
|
|
88
|
+
return requireHost().useCurrentUser();
|
|
89
|
+
}
|
|
90
|
+
export function useTheme() {
|
|
91
|
+
return requireHost().useTheme();
|
|
92
|
+
}
|
|
93
|
+
export function useToast() {
|
|
94
|
+
return requireHost().toast;
|
|
95
|
+
}
|
|
96
|
+
export function logActivity(type, hostId, hostName) {
|
|
97
|
+
return requireHost().core.logActivity(type, hostId, hostName);
|
|
98
|
+
}
|
|
99
|
+
/** Tells the shell hosts were added or changed, so its lists reload. */
|
|
100
|
+
export function notifyHostsChanged() {
|
|
101
|
+
requireHost().core.notifyHostsChanged();
|
|
102
|
+
}
|
|
103
|
+
/** How the user wants host status shown: the brand accent, or green/red. */
|
|
104
|
+
export function getHostStatusColorScheme() {
|
|
105
|
+
return requireHost().core.getHostStatusColorScheme();
|
|
106
|
+
}
|
|
107
|
+
/** The desktop app's local backend token, or null in a browser. */
|
|
108
|
+
export function getLocalAuthToken() {
|
|
109
|
+
return requireHost().core.getLocalAuthToken();
|
|
110
|
+
}
|
|
111
|
+
export function getHostPassword(hostId, field) {
|
|
112
|
+
return requireHost().core.getHostPassword(hostId, field);
|
|
113
|
+
}
|
|
114
|
+
export function patchOpenTab(instanceId, updates) {
|
|
115
|
+
return requireHost().core.patchOpenTab(instanceId, updates);
|
|
116
|
+
}
|
|
117
|
+
export function getCustomKeybindings() {
|
|
118
|
+
return requireHost().core.getCustomKeybindings();
|
|
119
|
+
}
|
|
120
|
+
export function runKeybindingAction(action, context) {
|
|
121
|
+
return requireHost().core.runKeybindingAction(action, context);
|
|
122
|
+
}
|
|
123
|
+
export function getClientPreference(name) {
|
|
124
|
+
return requireHost().core.getClientPreference(name);
|
|
125
|
+
}
|
|
126
|
+
export function setClientPreference(name, value) {
|
|
127
|
+
requireHost().core.setClientPreference(name, value);
|
|
128
|
+
}
|
|
129
|
+
export function listCredentials() {
|
|
130
|
+
return requireHost().core.listCredentials();
|
|
131
|
+
}
|
|
132
|
+
export function usePluginApi() {
|
|
133
|
+
const bridge = requireHost();
|
|
134
|
+
return bridge.getApi(bridge.usePluginId());
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* This plugin's client for a resolved connection origin: "remote" reaches the
|
|
138
|
+
* desktop app's connected remote server, anything else is usePluginApi's.
|
|
139
|
+
*/
|
|
140
|
+
export function usePluginApiFor(origin) {
|
|
141
|
+
const bridge = requireHost();
|
|
142
|
+
return bridge.getApiFor(bridge.usePluginId(), origin);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* This plugin's Appearance area: the preset it declared in
|
|
146
|
+
* contributes.uiPresets for the user's level, with the user's changes on top.
|
|
147
|
+
* `set` saves one change; null clears it back to the preset.
|
|
148
|
+
*/
|
|
149
|
+
export function usePluginUiPreferences() {
|
|
150
|
+
const bridge = requireHost();
|
|
151
|
+
return bridge.usePluginUiPreferences(bridge.usePluginId());
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Grid or list and row density for one of this plugin's views, kept in its
|
|
155
|
+
* Appearance area as `<prefix>viewMode` and `<prefix>density`. Declare those
|
|
156
|
+
* keys in contributes.uiPresets so each preset level can pick a default.
|
|
157
|
+
*/
|
|
158
|
+
export function usePluginPanelView(prefix = "") {
|
|
159
|
+
const { values, set } = usePluginUiPreferences();
|
|
160
|
+
const view = values[`${prefix}viewMode`] === "list" ? "list" : "grid";
|
|
161
|
+
const density = values[`${prefix}density`] === "compact" ? "compact" : "comfortable";
|
|
162
|
+
return {
|
|
163
|
+
view,
|
|
164
|
+
density,
|
|
165
|
+
compact: density === "compact",
|
|
166
|
+
setView: (next) => set(`${prefix}viewMode`, next),
|
|
167
|
+
setDensity: (next) => set(`${prefix}density`, next),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
export function useTabs() {
|
|
171
|
+
return requireHost().useTabs();
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* The SSH auth types this server can connect with, core's and every enabled
|
|
175
|
+
* plugin's, for pickers such as a default auth type.
|
|
176
|
+
*/
|
|
177
|
+
export function useSshAuthTypes() {
|
|
178
|
+
return requireHost().useSshAuthTypes();
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* The visible contributions to a slot another plugin owns, with their
|
|
182
|
+
* metadata (id, titleKey, component). For an owner that needs to build a
|
|
183
|
+
* catalog from what was contributed rather than just render it in place, e.g.
|
|
184
|
+
* host-metrics listing manager cards plugins added to "host-metrics.managers"
|
|
185
|
+
* next to its own. Same permission and `when` filtering as ComponentSlot;
|
|
186
|
+
* `context` is what each contribution's `when` sees.
|
|
187
|
+
*/
|
|
188
|
+
/**
|
|
189
|
+
* The connection protocols a host has switched on: "ssh" plus every protocol
|
|
190
|
+
* a running plugin registered with registerHostProtocol. Lets a
|
|
191
|
+
* plugin offer a protocol without knowing which plugin owns its settings.
|
|
192
|
+
*/
|
|
193
|
+
export function hostProtocols(record) {
|
|
194
|
+
return requireHost().hostProtocols(record);
|
|
195
|
+
}
|
|
196
|
+
export function useSlotContributions(slotId, context) {
|
|
197
|
+
return requireHost().useSlotContributions(slotId, context);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Every host action any running plugin (and core) registered with
|
|
201
|
+
* registerHostAction, for a plugin that offers a picker over "what can I do
|
|
202
|
+
* with this host" without knowing which plugin provides each one - a quick
|
|
203
|
+
* connect widget, say. Reactive: it re-renders as plugins enable and disable.
|
|
204
|
+
*/
|
|
205
|
+
export function useHostActions() {
|
|
206
|
+
return requireHost().useHostActions();
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Recent-activity types every registered tab claims (registerTab's
|
|
210
|
+
* activityTypes), core's and plugins'. For a filter that lists what a user
|
|
211
|
+
* can pick, without knowing which plugin owns each activity type.
|
|
212
|
+
*/
|
|
213
|
+
export function useActivityTypes() {
|
|
214
|
+
return requireHost().useActivityTypes();
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* What a recent-activity entry of this type opens and how it is labelled -
|
|
218
|
+
* the tab type claiming it through registerTab's activityTypes, core's or a
|
|
219
|
+
* plugin's. undefined for a type nothing claims (its plugin is gone).
|
|
220
|
+
*/
|
|
221
|
+
export function activityTarget(type) {
|
|
222
|
+
return requireHost().activityTarget(type);
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Every item any running plugin added to `pointId` with registerExtension.
|
|
226
|
+
* Reactive: it re-renders as plugins enable and disable.
|
|
227
|
+
*/
|
|
228
|
+
export function useExtensions(pointId) {
|
|
229
|
+
return requireHost().useExtensions(pointId);
|
|
230
|
+
}
|
|
231
|
+
/** A single item added to `pointId`, by id, or undefined if none. */
|
|
232
|
+
export function getExtension(pointId, id) {
|
|
233
|
+
return requireHost().getExtension(pointId, id);
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* The component another plugin registered under `id` with
|
|
237
|
+
* app.registerComponent, or undefined while that plugin is off.
|
|
238
|
+
*/
|
|
239
|
+
export function usePluginComponent(id) {
|
|
240
|
+
return requireHost().usePluginComponent(id);
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Runs an action another plugin registered, from anywhere in a plugin's code.
|
|
244
|
+
* Resolves undefined when nobody registered it, so an optional dependency
|
|
245
|
+
* that is switched off reads as "nothing there".
|
|
246
|
+
*/
|
|
247
|
+
export function invokeAction(id, ...args) {
|
|
248
|
+
return requireHost().invokeAction(id, ...args);
|
|
249
|
+
}
|
|
250
|
+
const COUNTDOWN_TICK_MS = 250;
|
|
251
|
+
const RETRY_JITTER_RATIO = 0.1;
|
|
252
|
+
export function computeReconnectDelay(attempt, baseDelayMs, maxDelayMs, random = Math.random) {
|
|
253
|
+
const base = Math.min(baseDelayMs * Math.pow(2, Math.max(0, attempt - 1)), maxDelayMs);
|
|
254
|
+
const jitter = base * RETRY_JITTER_RATIO * (random() * 2 - 1);
|
|
255
|
+
return Math.max(baseDelayMs, Math.min(maxDelayMs, Math.round(base + jitter)));
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Exponential-backoff reconnect with jitter, for a plugin's own connect flow
|
|
259
|
+
* (docker's console, host-metrics polling, remote desktop tokens, the file
|
|
260
|
+
* manager). Promoted here once a fourth plugin needed its own copy of the
|
|
261
|
+
* same hook.
|
|
262
|
+
*/
|
|
263
|
+
export function useConnectionRetry({ connect, maxAttempts = 8, baseDelayMs = 2000, maxDelayMs = 8000, enabled = true, autoStart = true, }) {
|
|
264
|
+
const [status, setStatus] = useState("connecting");
|
|
265
|
+
const [attempt, setAttempt] = useState(0);
|
|
266
|
+
const [nextRetryInMs, setNextRetryInMs] = useState(null);
|
|
267
|
+
const connectRef = useRef(connect);
|
|
268
|
+
connectRef.current = connect;
|
|
269
|
+
const enabledRef = useRef(enabled);
|
|
270
|
+
enabledRef.current = enabled;
|
|
271
|
+
const attemptRef = useRef(0);
|
|
272
|
+
const retryTimeoutRef = useRef(null);
|
|
273
|
+
const countdownIntervalRef = useRef(null);
|
|
274
|
+
const isMountedRef = useRef(true);
|
|
275
|
+
const markFailedRef = useRef(() => { });
|
|
276
|
+
const clearTimers = useCallback(() => {
|
|
277
|
+
if (retryTimeoutRef.current) {
|
|
278
|
+
clearTimeout(retryTimeoutRef.current);
|
|
279
|
+
retryTimeoutRef.current = null;
|
|
280
|
+
}
|
|
281
|
+
if (countdownIntervalRef.current) {
|
|
282
|
+
clearInterval(countdownIntervalRef.current);
|
|
283
|
+
countdownIntervalRef.current = null;
|
|
284
|
+
}
|
|
285
|
+
}, []);
|
|
286
|
+
const runConnect = useCallback(() => {
|
|
287
|
+
if (!isMountedRef.current)
|
|
288
|
+
return;
|
|
289
|
+
setStatus("connecting");
|
|
290
|
+
try {
|
|
291
|
+
void Promise.resolve(connectRef.current()).catch(() => {
|
|
292
|
+
markFailedRef.current();
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
catch {
|
|
296
|
+
markFailedRef.current();
|
|
297
|
+
}
|
|
298
|
+
}, []);
|
|
299
|
+
const scheduleRetry = useCallback(() => {
|
|
300
|
+
if (attemptRef.current >= maxAttempts) {
|
|
301
|
+
setStatus("disconnected");
|
|
302
|
+
setNextRetryInMs(null);
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
attemptRef.current += 1;
|
|
306
|
+
setAttempt(attemptRef.current);
|
|
307
|
+
const delay = computeReconnectDelay(attemptRef.current, baseDelayMs, maxDelayMs);
|
|
308
|
+
let remaining = delay;
|
|
309
|
+
setNextRetryInMs(remaining);
|
|
310
|
+
countdownIntervalRef.current = setInterval(() => {
|
|
311
|
+
remaining = Math.max(0, remaining - COUNTDOWN_TICK_MS);
|
|
312
|
+
setNextRetryInMs(remaining);
|
|
313
|
+
}, COUNTDOWN_TICK_MS);
|
|
314
|
+
retryTimeoutRef.current = setTimeout(() => {
|
|
315
|
+
clearTimers();
|
|
316
|
+
if (!isMountedRef.current || !enabledRef.current)
|
|
317
|
+
return;
|
|
318
|
+
runConnect();
|
|
319
|
+
}, delay);
|
|
320
|
+
}, [baseDelayMs, maxDelayMs, maxAttempts, clearTimers, runConnect]);
|
|
321
|
+
const markConnected = useCallback(() => {
|
|
322
|
+
clearTimers();
|
|
323
|
+
attemptRef.current = 0;
|
|
324
|
+
setAttempt(0);
|
|
325
|
+
setNextRetryInMs(null);
|
|
326
|
+
if (isMountedRef.current)
|
|
327
|
+
setStatus("connected");
|
|
328
|
+
}, [clearTimers]);
|
|
329
|
+
const markFailed = useCallback(() => {
|
|
330
|
+
clearTimers();
|
|
331
|
+
if (!isMountedRef.current)
|
|
332
|
+
return;
|
|
333
|
+
setStatus("error");
|
|
334
|
+
if (enabledRef.current) {
|
|
335
|
+
scheduleRetry();
|
|
336
|
+
}
|
|
337
|
+
else {
|
|
338
|
+
setNextRetryInMs(null);
|
|
339
|
+
}
|
|
340
|
+
}, [clearTimers, scheduleRetry]);
|
|
341
|
+
markFailedRef.current = markFailed;
|
|
342
|
+
const retryNow = useCallback(() => {
|
|
343
|
+
clearTimers();
|
|
344
|
+
attemptRef.current = 0;
|
|
345
|
+
setAttempt(0);
|
|
346
|
+
setNextRetryInMs(null);
|
|
347
|
+
runConnect();
|
|
348
|
+
}, [clearTimers, runConnect]);
|
|
349
|
+
const reset = useCallback(() => {
|
|
350
|
+
clearTimers();
|
|
351
|
+
attemptRef.current = 0;
|
|
352
|
+
setAttempt(0);
|
|
353
|
+
setNextRetryInMs(null);
|
|
354
|
+
if (isMountedRef.current)
|
|
355
|
+
setStatus("connecting");
|
|
356
|
+
}, [clearTimers]);
|
|
357
|
+
useEffect(() => {
|
|
358
|
+
isMountedRef.current = true;
|
|
359
|
+
if (autoStart) {
|
|
360
|
+
runConnect();
|
|
361
|
+
}
|
|
362
|
+
return () => {
|
|
363
|
+
isMountedRef.current = false;
|
|
364
|
+
clearTimers();
|
|
365
|
+
};
|
|
366
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
367
|
+
}, []);
|
|
368
|
+
useEffect(() => {
|
|
369
|
+
if (enabled && status === "error" && !retryTimeoutRef.current) {
|
|
370
|
+
scheduleRetry();
|
|
371
|
+
}
|
|
372
|
+
if (!enabled) {
|
|
373
|
+
clearTimers();
|
|
374
|
+
setNextRetryInMs(null);
|
|
375
|
+
}
|
|
376
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
377
|
+
}, [enabled]);
|
|
378
|
+
return {
|
|
379
|
+
status,
|
|
380
|
+
attempt,
|
|
381
|
+
maxAttempts,
|
|
382
|
+
nextRetryInMs,
|
|
383
|
+
markConnected,
|
|
384
|
+
markFailed,
|
|
385
|
+
retryNow,
|
|
386
|
+
reset,
|
|
387
|
+
};
|
|
388
|
+
}
|