dsh-home-hosted 0.7.2 → 0.7.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/docs/BOOT.md +45 -0
- package/lib/index.js +126 -21
- package/lib/index.js.map +3 -3
- package/lib/types/boot/escape.d.ts +51 -6
- package/lib/types/home-hosted/config-file.d.ts +23 -1
- package/lib/types/home-hosted/panel.d.ts +13 -0
- package/package.json +1 -1
|
@@ -36,14 +36,31 @@ export declare function shellCommand(program: string, args: string[]): string;
|
|
|
36
36
|
*/
|
|
37
37
|
export declare function systemdExecWord(value: string): string;
|
|
38
38
|
/**
|
|
39
|
-
* A single-line free-text setting such as `Description
|
|
39
|
+
* A single-line free-text setting such as `Description=`.
|
|
40
|
+
*
|
|
41
|
+
* systemd reads these **verbatim** — unlike `ExecStart=`, it does not unescape
|
|
42
|
+
* `\\` or `$` there — so doubling a backslash puts a backslash *into* the value.
|
|
43
|
+
* Only two things need care: `%` starts a specifier, and a value that *ends* in a
|
|
44
|
+
* backslash splices the following line onto this directive, because the
|
|
45
|
+
* continuation rule applies to the raw line whatever the setting. A trailing
|
|
46
|
+
* space is the one encoding that leaves both the value and the next directive
|
|
47
|
+
* intact.
|
|
40
48
|
*/
|
|
41
49
|
export declare function systemdText(value: string): string;
|
|
42
50
|
/**
|
|
43
|
-
* A path setting (`WorkingDirectory=`).
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
51
|
+
* A path setting (`WorkingDirectory=`).
|
|
52
|
+
*
|
|
53
|
+
* Measured against real systemd (`systemctl show -p WorkingDirectory --value`):
|
|
54
|
+
* the value is taken **verbatim**, so a backslash is a backslash and must not be
|
|
55
|
+
* doubled — doubling turned a directory named `a\b` into a path that does not
|
|
56
|
+
* exist, and the unit failed with `status=200/CHDIR`. `%` still expands as a
|
|
57
|
+
* specifier, and an unknown one (`%i` in a system unit) is fatal, so it is
|
|
58
|
+
* escaped. The remaining hazard is a *trailing* backslash, which continues the
|
|
59
|
+
* directive onto the next line and swallows it; a trailing space absorbs that
|
|
60
|
+
* without changing the path.
|
|
61
|
+
*
|
|
62
|
+
* A double quote is refused rather than quoted: systemd does not unquote these
|
|
63
|
+
* settings, so a quoted form is simply a path with a quote in it.
|
|
47
64
|
*/
|
|
48
65
|
export declare function systemdPath(value: string, what?: string): string;
|
|
49
66
|
/** `Environment=KEY=value`, quoted as one assignment when the value needs it. */
|
|
@@ -52,9 +69,37 @@ export declare function xmlEscape(value: string): string;
|
|
|
52
69
|
export declare function xmlUnescape(value: string): string;
|
|
53
70
|
/** A marker inside an XML comment may not contain `--`. */
|
|
54
71
|
export declare function assertXmlCommentSafe(value: string): string;
|
|
72
|
+
/**
|
|
73
|
+
* Escape one value for the **key-file** layer of a `.desktop` file.
|
|
74
|
+
*
|
|
75
|
+
* This is a separate layer from `Exec=`'s own quoting, and it runs *first*:
|
|
76
|
+
* GLib reads the line with `GKeyFile`, which consumes `\n`, `\t`, `\r`, `\s`
|
|
77
|
+
* and `\\` before anything else sees the value. A `\` that is not one of those
|
|
78
|
+
* escapes makes `g_key_file_get_string` fail outright — "Key file contains key
|
|
79
|
+
* … which has a value that cannot be interpreted" — so the whole entry becomes
|
|
80
|
+
* unloadable, and `desktop-file-validate` happily accepts the file.
|
|
81
|
+
*
|
|
82
|
+
* That is why every backslash is doubled here: after the key-file layer the
|
|
83
|
+
* value is byte-identical to what the next layer was handed. Only `\\` may
|
|
84
|
+
* appear in the file — a bare `\` is always invalid.
|
|
85
|
+
*/
|
|
86
|
+
export declare function desktopValueEscape(value: string): string;
|
|
87
|
+
/**
|
|
88
|
+
* Quote one `Exec=` word for the desktop-entry parser.
|
|
89
|
+
*
|
|
90
|
+
* Two layers, in order: `desktopValueEscape` for the key file, then the shell
|
|
91
|
+
* quoting below for `g_shell_parse_argv`, which is what actually splits the
|
|
92
|
+
* value into words and unquotes each one.
|
|
93
|
+
*/
|
|
55
94
|
export declare function desktopWord(value: string): string;
|
|
56
95
|
export declare function desktopExec(program: string, args: string[]): string;
|
|
57
|
-
/**
|
|
96
|
+
/**
|
|
97
|
+
* A `Key=value` line in a `.desktop` file.
|
|
98
|
+
*
|
|
99
|
+
* The value is key-file escaped, because a `.desktop` line has no shell to
|
|
100
|
+
* quote for: `Path=`/`Name=`/`Comment=` are read as plain strings, and a
|
|
101
|
+
* backslash in any of them is a key-file escape rather than data.
|
|
102
|
+
*/
|
|
58
103
|
export declare function desktopValue(key: string, value: string): string;
|
|
59
104
|
/** Quote one argv word the way `CreateProcess`/`cmd` parse a command line. */
|
|
60
105
|
export declare function windowsArg(value: string): string;
|
|
@@ -23,6 +23,10 @@ export interface SettingsReadResult {
|
|
|
23
23
|
export declare class ConfigLayoutError extends Error {
|
|
24
24
|
name: string;
|
|
25
25
|
}
|
|
26
|
+
/** A patch the panel's own schema would reject, refused rather than written. */
|
|
27
|
+
export declare class ConfigPatchError extends Error {
|
|
28
|
+
name: string;
|
|
29
|
+
}
|
|
26
30
|
/** One workspace's entries. A not-yet-migrated root is reported, never parsed. */
|
|
27
31
|
export declare function readConfig(home: string, workspace?: string): ConfigReadResult;
|
|
28
32
|
/**
|
|
@@ -47,7 +51,25 @@ export declare function setControl(home: string, patch: Record<string, unknown>,
|
|
|
47
51
|
export declare function findEntry(raw: RawConfig, id: string): ServerEntry | null;
|
|
48
52
|
/** Insert or replace one entry, preserving every other key in the file. */
|
|
49
53
|
export declare function upsertEntry(raw: RawConfig, entry: ServerEntry): RawConfig;
|
|
54
|
+
/**
|
|
55
|
+
* Apply one entry patch, merging the nested groups the panel merges.
|
|
56
|
+
*
|
|
57
|
+
* Only the keys `patch` names are touched; everything else in the entry — and
|
|
58
|
+
* every other entry in the file — is preserved.
|
|
59
|
+
*
|
|
60
|
+
* An explicit `null` for one of the three groups is **refused**, not written.
|
|
61
|
+
* The panel's patch schema declares them `.optional()` but not nullable, so the
|
|
62
|
+
* API answers 400; writing it here instead produced a config the panel then
|
|
63
|
+
* refused to boot from (`servers[0] ("a"): restart must be an object (was null)`)
|
|
64
|
+
* — a file this plugin wrote, that this plugin's own panel cannot start on. A
|
|
65
|
+
* `null` nested *inside* a group is fine: that is how an optional key is cleared.
|
|
66
|
+
*/
|
|
50
67
|
export declare function patchEntry(raw: RawConfig, id: string, patch: ServerEntryPatch): RawConfig;
|
|
51
|
-
/**
|
|
68
|
+
/**
|
|
69
|
+
* Patch a settings file's `control` block, as a pure value.
|
|
70
|
+
*
|
|
71
|
+
* `auth` and `tls` merge the way the panel's `CONTROL_MERGE_KEYS` says, so a
|
|
72
|
+
* patch naming one of them does not reset its siblings.
|
|
73
|
+
*/
|
|
52
74
|
export declare function patchControl(raw: GlobalSettings, patch: Record<string, unknown>): GlobalSettings;
|
|
53
75
|
export declare function removeEntry(raw: RawConfig, id: string): RawConfig;
|
|
@@ -39,6 +39,19 @@ export declare class PanelClient {
|
|
|
39
39
|
* `workspace`. One mapping, so a caller never has to know both spellings.
|
|
40
40
|
*/
|
|
41
41
|
private view;
|
|
42
|
+
/**
|
|
43
|
+
* A `POST`/`PATCH` answer.
|
|
44
|
+
*
|
|
45
|
+
* The real panel answers the stored entry *flat* here — no `config` wrapper, no
|
|
46
|
+
* `workspaceId`, no live status — while `GET` answers a view. Both are accepted:
|
|
47
|
+
* a body that already carries a `config` object is a view, and anything else is
|
|
48
|
+
* the entry itself. Reading a flat entry as a view is what made `created.config`
|
|
49
|
+
* `undefined`, so the shape is decided here rather than assumed.
|
|
50
|
+
*
|
|
51
|
+
* A flat entry carries no live status, so it is reported as `unknown`: the panel
|
|
52
|
+
* has not said. Callers that need one re-read the list.
|
|
53
|
+
*/
|
|
54
|
+
private written;
|
|
42
55
|
private ws;
|
|
43
56
|
private request;
|
|
44
57
|
listServers(workspace?: string): Promise<ServerEntryView[]>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-home-hosted",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.4",
|
|
4
4
|
"description": "DeepSeek Harness (dsh) plugin: prompt your home servers into existence through home-hosted — Gitea, Jellyfin, anything — and manage the panel, the entries and boot autostart from dsh.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|