@termix-ssh/plugin-sdk 1.0.1 → 1.0.4
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/CHANGELOG.md +74 -0
- package/LICENSE +202 -0
- package/README.md +4 -3
- package/cli/commands/build.mjs +37 -12
- package/cli/commands/dev.mjs +1 -1
- package/cli/commands/openapi.mjs +39 -0
- package/cli/commands/validate.mjs +67 -0
- package/cli/index.mjs +3 -0
- package/cli/lib/css-classes.mjs +37 -0
- package/dist/changelog.d.ts +3 -8
- package/dist/changelog.js +6 -14
- package/dist/docs.d.ts +28 -0
- package/dist/docs.js +39 -0
- package/dist/frontend.d.ts +17 -0
- package/dist/frontend.js +8 -0
- package/dist/host/{chunk-COGRSHKO.js → chunk-F5RZH6HE.js} +13 -2
- package/dist/host/{chunk-3KG44G55.js → chunk-O2OHNVFX.js} +1 -1
- package/dist/host/{chunk-7GL25GFS.js → chunk-RU4E5XLY.js} +531 -300
- package/dist/host/core-classes.json +1 -0
- package/dist/host/{linked-server-BD573BEG.js → linked-server-4VWYYABP.js} +1 -1
- package/dist/host/{rbac-api-7GHDJLU4.js → rbac-api-WIJVZH3M.js} +1 -1
- package/dist/host/testing-host.js +3 -3
- package/dist/host/types/src/ui/api/plugins-api.d.ts +23 -0
- package/dist/host/types/src/ui/api/system-status-api.d.ts +24 -0
- package/dist/host/types/src/ui/components/docs-link.d.ts +25 -0
- package/dist/host/types/src/ui/components/panel-layout.d.ts +3 -1
- package/dist/host/types/src/ui/hooks/use-installed-plugins.d.ts +6 -0
- package/dist/host/types/src/ui/lib/docs.d.ts +10 -0
- package/dist/host/types/src/ui/main-axios.d.ts +1 -0
- package/dist/host/types/src/ui/plugin-host/sdk-ui.d.ts +1 -0
- package/dist/host/types/src/ui/settings/settings-fields-util.d.ts +10 -0
- package/dist/host/ui.js +139 -110
- package/dist/host/{use-permissions-SKWXHWDJ.js → use-permissions-KIQCJ35M.js} +1 -1
- package/dist/manifest.d.ts +16 -1
- package/dist/manifest.js +84 -1
- package/dist/openapi.d.ts +43 -0
- package/dist/openapi.js +60 -0
- package/dist/testing/setup.js +1 -0
- package/package.json +12 -2
- package/schema/manifest.schema.json +27 -0
package/dist/changelog.js
CHANGED
|
@@ -3,12 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* # Changelog
|
|
5
5
|
*
|
|
6
|
-
* ##
|
|
7
|
-
*
|
|
8
|
-
* ### Added
|
|
9
|
-
* - Something merged but not shipped yet
|
|
10
|
-
*
|
|
11
|
-
* ## 1.1.0 - 2026-10-06
|
|
6
|
+
* ## 1.1.0
|
|
12
7
|
*
|
|
13
8
|
* An optional summary paragraph.
|
|
14
9
|
*
|
|
@@ -19,7 +14,8 @@
|
|
|
19
14
|
* - Something broken
|
|
20
15
|
*
|
|
21
16
|
* Releases are listed newest first, and the newest one has to be the
|
|
22
|
-
* manifest version.
|
|
17
|
+
* manifest version. Notes go straight under the version they ship in, there
|
|
18
|
+
* is no Unreleased section.
|
|
23
19
|
*/
|
|
24
20
|
import semver from "semver";
|
|
25
21
|
export const CHANGE_TYPES = [
|
|
@@ -94,7 +90,7 @@ export function parseReleaseNotes(body, where = "release") {
|
|
|
94
90
|
/** Parses a whole CHANGELOG.md. Problems are reported, never thrown. */
|
|
95
91
|
export function parseChangelog(markdown) {
|
|
96
92
|
const problems = [];
|
|
97
|
-
const changelog = {
|
|
93
|
+
const changelog = { releases: [] };
|
|
98
94
|
const lines = markdown.replace(/\r/g, "").split("\n");
|
|
99
95
|
const blocks = [];
|
|
100
96
|
let fence = false;
|
|
@@ -109,13 +105,9 @@ export function parseChangelog(markdown) {
|
|
|
109
105
|
}
|
|
110
106
|
});
|
|
111
107
|
const seen = new Set();
|
|
112
|
-
blocks.forEach((block
|
|
108
|
+
blocks.forEach((block) => {
|
|
113
109
|
if (UNRELEASED_HEADING.test(block.heading)) {
|
|
114
|
-
|
|
115
|
-
problems.push(`"## Unreleased" has to come first`);
|
|
116
|
-
const notes = parseReleaseNotes(block.body.join("\n"), "Unreleased");
|
|
117
|
-
problems.push(...notes.problems);
|
|
118
|
-
changelog.unreleased = notes.changes;
|
|
110
|
+
problems.push(`line ${block.line}: drop "## Unreleased", notes go under the version they ship in`);
|
|
119
111
|
return;
|
|
120
112
|
}
|
|
121
113
|
const match = RELEASE_HEADING.exec(block.heading);
|
package/dist/docs.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Docs links and env var entries from a manifest. Kept apart from manifest.ts
|
|
3
|
+
* so the browser can use them without pulling in semver.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* A docs link, or null for anything that is not an https URL. Core only ever
|
|
7
|
+
* opens it in a new tab, but a javascript: or file: link should never get there.
|
|
8
|
+
*/
|
|
9
|
+
export declare function pluginDocsUrl(value: unknown): string | null;
|
|
10
|
+
/** Joins a page and anchor onto a plugin's docs URL. */
|
|
11
|
+
export declare function pluginDocsPage(base: string, page?: string, anchor?: string): string;
|
|
12
|
+
export declare const ENV_NAME_PATTERN: RegExp;
|
|
13
|
+
export declare const MAX_ENV_DESCRIPTION_LENGTH = 300;
|
|
14
|
+
/**
|
|
15
|
+
* An environment variable a plugin reads. Only shown in docs and on the
|
|
16
|
+
* plugin's page, so people know what they can set.
|
|
17
|
+
*/
|
|
18
|
+
export interface PluginEnvVar {
|
|
19
|
+
name: string;
|
|
20
|
+
description: string;
|
|
21
|
+
/** The value used when it is not set, as written in a compose file. */
|
|
22
|
+
default?: string;
|
|
23
|
+
required?: boolean;
|
|
24
|
+
/** Holds a password or key. */
|
|
25
|
+
secret?: boolean;
|
|
26
|
+
}
|
|
27
|
+
/** The usable env entries of a manifest. Bad ones are dropped. */
|
|
28
|
+
export declare function pluginEnvVars(value: unknown): PluginEnvVar[];
|
package/dist/docs.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Docs links and env var entries from a manifest. Kept apart from manifest.ts
|
|
3
|
+
* so the browser can use them without pulling in semver.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* A docs link, or null for anything that is not an https URL. Core only ever
|
|
7
|
+
* opens it in a new tab, but a javascript: or file: link should never get there.
|
|
8
|
+
*/
|
|
9
|
+
export function pluginDocsUrl(value) {
|
|
10
|
+
if (typeof value !== "string")
|
|
11
|
+
return null;
|
|
12
|
+
try {
|
|
13
|
+
const url = new URL(value.trim());
|
|
14
|
+
if (url.protocol !== "https:")
|
|
15
|
+
return null;
|
|
16
|
+
return url.toString().replace(/\/$/, "");
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** Joins a page and anchor onto a plugin's docs URL. */
|
|
23
|
+
export function pluginDocsPage(base, page, anchor) {
|
|
24
|
+
const clean = (page ?? "").replace(/^\/+|\/+$/g, "");
|
|
25
|
+
const url = clean ? `${base}/${clean}` : base;
|
|
26
|
+
return anchor ? `${url}#${anchor.replace(/^#/, "")}` : url;
|
|
27
|
+
}
|
|
28
|
+
export const ENV_NAME_PATTERN = /^[A-Z][A-Z0-9_]{0,63}$/;
|
|
29
|
+
export const MAX_ENV_DESCRIPTION_LENGTH = 300;
|
|
30
|
+
/** The usable env entries of a manifest. Bad ones are dropped. */
|
|
31
|
+
export function pluginEnvVars(value) {
|
|
32
|
+
if (!Array.isArray(value))
|
|
33
|
+
return [];
|
|
34
|
+
return value.filter((v) => typeof v === "object" &&
|
|
35
|
+
v !== null &&
|
|
36
|
+
typeof v.name === "string" &&
|
|
37
|
+
ENV_NAME_PATTERN.test(v.name) &&
|
|
38
|
+
typeof v.description === "string");
|
|
39
|
+
}
|
package/dist/frontend.d.ts
CHANGED
|
@@ -816,6 +816,15 @@ export interface DesktopApi {
|
|
|
816
816
|
/** Called when the desktop app connects to or leaves a remote server. */
|
|
817
817
|
onRemoteServerChange: (listener: () => void) => Disposer;
|
|
818
818
|
}
|
|
819
|
+
/** Links into this plugin's docs, from the manifest's docs field. */
|
|
820
|
+
export interface DocsApi {
|
|
821
|
+
/** The docs link, or null when the manifest has none. */
|
|
822
|
+
readonly url: string | null;
|
|
823
|
+
/** A page of the docs ("setup"), with an optional anchor. */
|
|
824
|
+
page: (page?: string, anchor?: string) => string | null;
|
|
825
|
+
/** Opens a page in a new tab. Does nothing without a docs link. */
|
|
826
|
+
open: (page?: string, anchor?: string) => void;
|
|
827
|
+
}
|
|
819
828
|
export interface TermixAppInfo {
|
|
820
829
|
readonly pluginId: string;
|
|
821
830
|
readonly manifest: PluginManifest;
|
|
@@ -913,6 +922,8 @@ export interface TermixApp extends TermixAppInfo {
|
|
|
913
922
|
confirm: (options: ConfirmRequest) => Promise<boolean>;
|
|
914
923
|
/** The desktop app, when the frontend runs in it. */
|
|
915
924
|
desktop: DesktopApi;
|
|
925
|
+
/** This plugin's docs. Needs plugin API 1.2. */
|
|
926
|
+
docs: DocsApi;
|
|
916
927
|
/**
|
|
917
928
|
* Fires after this plugin's settings are saved from the settings screen or
|
|
918
929
|
* the host editor. Disposed automatically.
|
|
@@ -966,6 +977,7 @@ export interface SshAuthTypeInfo {
|
|
|
966
977
|
*/
|
|
967
978
|
export interface PluginHostBridge {
|
|
968
979
|
usePluginId: () => string;
|
|
980
|
+
useDocsUrl: (pluginId: string, page?: string, anchor?: string) => string | null;
|
|
969
981
|
useTranslation: (pluginId: string) => {
|
|
970
982
|
t: TranslateFn;
|
|
971
983
|
language: string;
|
|
@@ -1107,6 +1119,11 @@ export interface HostStatusInfo {
|
|
|
1107
1119
|
export declare function __setPluginHost(bridge: PluginHostBridge | null): void;
|
|
1108
1120
|
/** The id of the plugin that registered the component being rendered. */
|
|
1109
1121
|
export declare function usePluginId(): string;
|
|
1122
|
+
/**
|
|
1123
|
+
* A page of this plugin's docs, or null when the manifest has no docs link.
|
|
1124
|
+
* Pass it to PanelShell's docs prop or use DocsLink. Needs plugin API 1.2.
|
|
1125
|
+
*/
|
|
1126
|
+
export declare function useDocsUrl(page?: string, anchor?: string): string | null;
|
|
1110
1127
|
/**
|
|
1111
1128
|
* Translation bound to this plugin's namespace. Keys the plugin does not
|
|
1112
1129
|
* define fall back to core's shared strings (common.*, hosts.*).
|
package/dist/frontend.js
CHANGED
|
@@ -49,6 +49,14 @@ function requireHost() {
|
|
|
49
49
|
export function usePluginId() {
|
|
50
50
|
return requireHost().usePluginId();
|
|
51
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* A page of this plugin's docs, or null when the manifest has no docs link.
|
|
54
|
+
* Pass it to PanelShell's docs prop or use DocsLink. Needs plugin API 1.2.
|
|
55
|
+
*/
|
|
56
|
+
export function useDocsUrl(page, anchor) {
|
|
57
|
+
const bridge = requireHost();
|
|
58
|
+
return bridge.useDocsUrl(bridge.usePluginId(), page, anchor);
|
|
59
|
+
}
|
|
52
60
|
/**
|
|
53
61
|
* Translation bound to this plugin's namespace. Keys the plugin does not
|
|
54
62
|
* define fall back to core's shared strings (common.*, hosts.*).
|
|
@@ -5037,7 +5037,7 @@ async function updateRole(roleId, roleData) {
|
|
|
5037
5037
|
try {
|
|
5038
5038
|
const response = await rbacApi.put(`/rbac/roles/${roleId}`, roleData);
|
|
5039
5039
|
if (roleData.permissions) {
|
|
5040
|
-
const { notifyPermissionsChanged } = await import("./use-permissions-
|
|
5040
|
+
const { notifyPermissionsChanged } = await import("./use-permissions-KIQCJ35M.js");
|
|
5041
5041
|
notifyPermissionsChanged();
|
|
5042
5042
|
}
|
|
5043
5043
|
return response.data;
|
|
@@ -5266,6 +5266,7 @@ async function getUserPreferences() {
|
|
|
5266
5266
|
}
|
|
5267
5267
|
|
|
5268
5268
|
// src/ui/main-axios.ts
|
|
5269
|
+
var TRUST_TOKEN_KEY = "termixTrustToken";
|
|
5269
5270
|
function getLoggerForService(serviceName) {
|
|
5270
5271
|
if (serviceName.includes("SSH") || serviceName.includes("ssh")) {
|
|
5271
5272
|
return sshLogger;
|
|
@@ -5427,6 +5428,15 @@ function createApiInstance(baseURL, serviceName = "API") {
|
|
|
5427
5428
|
config.headers["Authorization"] = `Bearer ${jwt}`;
|
|
5428
5429
|
}
|
|
5429
5430
|
}
|
|
5431
|
+
const trustToken = localStorage.getItem(TRUST_TOKEN_KEY);
|
|
5432
|
+
const isLogin = config.url?.includes("/users/login") || /\/users\/auth\/[^/]+\/verify$/.test(config.url ?? "");
|
|
5433
|
+
if (trustToken && isLogin) {
|
|
5434
|
+
if (config.headers.set) {
|
|
5435
|
+
config.headers.set("X-Termix-Trust-Token", trustToken);
|
|
5436
|
+
} else {
|
|
5437
|
+
config.headers["X-Termix-Trust-Token"] = trustToken;
|
|
5438
|
+
}
|
|
5439
|
+
}
|
|
5430
5440
|
}
|
|
5431
5441
|
if (typeof window !== "undefined" && window.ReactNativeWebView) {
|
|
5432
5442
|
let platform = "Unknown";
|
|
@@ -5587,7 +5597,7 @@ function createRemoteOriginApiInstance(path) {
|
|
|
5587
5597
|
});
|
|
5588
5598
|
instance.interceptors.request.use(
|
|
5589
5599
|
async (config) => {
|
|
5590
|
-
const { getLinkedSession: getLinkedSession2 } = await import("./linked-server-
|
|
5600
|
+
const { getLinkedSession: getLinkedSession2 } = await import("./linked-server-4VWYYABP.js");
|
|
5591
5601
|
const linked = await getLinkedSession2();
|
|
5592
5602
|
config.baseURL = linked ? `${linked.serverUrl}${path}` : "http://no-server-configured";
|
|
5593
5603
|
if (config.headers.set) {
|
|
@@ -6009,6 +6019,7 @@ export {
|
|
|
6009
6019
|
patchOpenTab,
|
|
6010
6020
|
parseCustomKeybindings,
|
|
6011
6021
|
getUserPreferences,
|
|
6022
|
+
TRUST_TOKEN_KEY,
|
|
6012
6023
|
setCookie,
|
|
6013
6024
|
getCookie,
|
|
6014
6025
|
markUserAuthenticated,
|
|
@@ -21,7 +21,7 @@ var inFlight = null;
|
|
|
21
21
|
function load() {
|
|
22
22
|
if (cache) return Promise.resolve(cache);
|
|
23
23
|
if (inFlight) return inFlight;
|
|
24
|
-
inFlight = import("./rbac-api-
|
|
24
|
+
inFlight = import("./rbac-api-WIJVZH3M.js").then(({ getMyPermissions }) => getMyPermissions()).then((result) => {
|
|
25
25
|
cache = {
|
|
26
26
|
permissions: result.permissions ?? [],
|
|
27
27
|
isAdmin: !!result.isAdmin
|