@astralyn/sash 0.1.0 → 0.1.2
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 +48 -0
- package/README.md +22 -7
- package/THIRD_PARTY_NOTICES.md +9 -0
- package/dist/api.js +14 -45
- package/dist/app-state.js +99 -0
- package/dist/autostart/command.js +24 -0
- package/dist/autostart/context.js +43 -0
- package/dist/autostart/files.js +60 -0
- package/dist/autostart/installation.js +48 -0
- package/dist/autostart/start.js +47 -0
- package/dist/autostart/windows-registry.js +88 -0
- package/dist/autostart/windows.js +59 -0
- package/dist/autostart-contract.js +31 -0
- package/dist/autostart-entry.js +10 -0
- package/dist/autostart.js +69 -0
- package/dist/cli.js +11 -11
- package/dist/commands/auto.js +15 -0
- package/dist/commands/lifecycle.js +5 -31
- package/dist/commands/logs.js +11 -4
- package/dist/commands/shared.js +2 -4
- package/dist/commands/status.js +6 -7
- package/dist/commands/update.js +7 -3
- package/dist/commands/web.js +19 -27
- package/dist/contracts.js +171 -335
- package/dist/core-config-validation.js +22 -38
- package/dist/core-update.js +126 -762
- package/dist/core.js +20 -46
- package/dist/daemon/app.js +132 -113
- package/dist/daemon/context.js +13 -7
- package/dist/daemon/entry.js +21 -38
- package/dist/daemon/errors.js +6 -1
- package/dist/daemon/handlers/autostart.js +18 -0
- package/dist/daemon/handlers/core.js +32 -9
- package/dist/daemon/handlers/daemon.js +32 -6
- package/dist/daemon/handlers/profiles.js +12 -2
- package/dist/daemon/handlers/settings.js +9 -36
- package/dist/daemon/router.js +40 -27
- package/dist/daemon/scheduler.js +3 -1
- package/dist/daemon/server.js +6 -3
- package/dist/daemon/web-auth.js +52 -0
- package/dist/daemon-auth.js +2 -2
- package/dist/daemon-client.js +18 -2
- package/dist/daemon-http.js +7 -0
- package/dist/daemon-lifecycle.js +19 -196
- package/dist/github.js +7 -2
- package/dist/http.js +7 -5
- package/dist/log-follow.js +2 -1
- package/dist/mihomo-config.js +7 -9
- package/dist/paths.js +5 -7
- package/dist/profile-model.js +87 -0
- package/dist/profile-service.js +250 -587
- package/dist/profiles.js +43 -171
- package/dist/runtime-lifecycle.js +112 -194
- package/dist/runtime-owner.js +37 -76
- package/dist/sash-client.js +63 -21
- package/dist/settings-service.js +29 -228
- package/dist/settings.js +61 -285
- package/dist/status.js +24 -40
- package/dist/supervisor.js +1 -14
- package/dist/sysproxy/common.js +5 -45
- package/dist/sysproxy/factory.js +24 -65
- package/dist/sysproxy/snapshot.js +24 -257
- package/dist/sysproxy.js +1 -4
- package/dist/system-proxy-manager.js +37 -35
- package/dist/ui/assets/{ConnectionsView-DNGmZBSU.js → ConnectionsView-BgXQM6Z4.js} +1 -1
- package/dist/ui/assets/{LogsView-fSiaxQ13.js → LogsView-2f542P8z.js} +1 -1
- package/dist/ui/assets/{PaginationFooter-B3kHzRfB.js → PaginationFooter-cj1tcZej.js} +1 -1
- package/dist/ui/assets/ProfileEditorDialog-C9M8uKZC.css +1 -0
- package/dist/ui/assets/ProfileEditorDialog-DD4y4GBC.js +14 -0
- package/dist/ui/assets/ProfilesView-BXU2DOA7.css +1 -0
- package/dist/ui/assets/ProfilesView-DNnzYIEY.js +7 -0
- package/dist/ui/assets/{RulesView-D9vZBiJ1.js → RulesView-CtKvlckZ.js} +1 -1
- package/dist/ui/assets/SettingsView-BaeKFF_N.js +1 -0
- package/dist/ui/assets/SettingsView-CWjIe05v.css +1 -0
- package/dist/ui/assets/{0be242294f7d791af850c6df38ac78a0-2cL6Ntwf.woff2 → e2a57555d97d0b02b45d9418eb6ee295-D9nhF3rM.woff2} +0 -0
- package/dist/ui/assets/index-CBInDvdJ.js +19 -0
- package/dist/ui/assets/index-mOLy7fkB.css +1 -0
- package/dist/ui/assets/{theme-BNq4FkXS.js → theme-D40MF8cQ.js} +1 -1
- package/dist/ui/index.html +2 -2
- package/dist/web-bootstrap.js +113 -0
- package/docs/architecture-proposal.md +109 -0
- package/docs/autostart.md +101 -0
- package/docs/backend.md +92 -216
- package/docs/frontend.md +61 -97
- package/docs/usage.md +88 -186
- package/package.json +10 -6
- package/dist/commands/upgrade.js +0 -43
- package/dist/core-install-transaction.js +0 -114
- package/dist/core-update-coordination.js +0 -105
- package/dist/core-update-service.js +0 -245
- package/dist/managed-state-transaction.js +0 -377
- package/dist/offline-mutation.js +0 -58
- package/dist/profile-migration.js +0 -101
- package/dist/runtime-recovery.js +0 -31
- package/dist/sysproxy/darwin.js +0 -287
- package/dist/sysproxy/gnome.js +0 -181
- package/dist/sysproxy/legacy.js +0 -58
- package/dist/tun-guidance.js +0 -11
- package/dist/ui/assets/CodeEditorModal-6m0TJWyF.css +0 -1
- package/dist/ui/assets/CodeEditorModal-CFEnWsyh.js +0 -14
- package/dist/ui/assets/ProfileEditorDialog-BydoZthX.js +0 -1
- package/dist/ui/assets/ProfilesView-Btc1DOxE.js +0 -2
- package/dist/ui/assets/ProfilesView-ByqdFNHN.css +0 -1
- package/dist/ui/assets/SettingsFileDialog-CNFEAVs4.js +0 -1
- package/dist/ui/assets/SettingsView-BlDhZkXQ.js +0 -2
- package/dist/ui/assets/SettingsView-CngS3vBM.css +0 -1
- package/dist/ui/assets/index-B61V60w_.js +0 -19
- package/dist/ui/assets/index-bkyxJG8J.css +0 -1
package/dist/contracts.js
CHANGED
|
@@ -1,412 +1,248 @@
|
|
|
1
1
|
import { isCanonicalIsoTimestamp, isPlainObject } from "./json-shape.js";
|
|
2
|
+
import { parseProfileMeta } from "./profile-model.js";
|
|
3
|
+
export { parseProfilesIndex } from "./profile-model.js";
|
|
2
4
|
export const WEB_SOCKET_AUTH_PROTOCOL = "sash";
|
|
3
5
|
export const WEB_SOCKET_TOKEN_PROTOCOL_PREFIX = "sash-token.";
|
|
4
|
-
|
|
5
|
-
return { error: { code, message } };
|
|
6
|
-
}
|
|
7
|
-
export function parseApiErrorBody(value) {
|
|
8
|
-
if (!isPlainObject(value) || !isPlainObject(value.error))
|
|
9
|
-
return undefined;
|
|
10
|
-
const { code, message } = value.error;
|
|
11
|
-
if (typeof code !== "string" || typeof message !== "string")
|
|
12
|
-
return undefined;
|
|
13
|
-
return { code, message };
|
|
14
|
-
}
|
|
15
|
-
function invalid(contract, path, expected) {
|
|
16
|
-
throw new TypeError(`${contract} response is invalid: ${path} must be ${expected}`);
|
|
17
|
-
}
|
|
18
|
-
function objectValue(value, contract, path) {
|
|
6
|
+
function object(value, name) {
|
|
19
7
|
if (!isPlainObject(value))
|
|
20
|
-
|
|
21
|
-
return value;
|
|
22
|
-
}
|
|
23
|
-
function required(source, key, contract, path) {
|
|
24
|
-
if (!Object.hasOwn(source, key))
|
|
25
|
-
invalid(contract, path, "present");
|
|
26
|
-
return source[key];
|
|
27
|
-
}
|
|
28
|
-
function booleanValue(value, contract, path) {
|
|
29
|
-
if (typeof value !== "boolean")
|
|
30
|
-
invalid(contract, path, "a boolean");
|
|
31
|
-
return value;
|
|
32
|
-
}
|
|
33
|
-
function stringValue(value, contract, path, nonEmpty = false) {
|
|
34
|
-
if (typeof value !== "string" || (nonEmpty && !value.trim())) {
|
|
35
|
-
invalid(contract, path, nonEmpty ? "a non-empty string" : "a string");
|
|
36
|
-
}
|
|
8
|
+
throw new TypeError(`${name} must be a plain object`);
|
|
37
9
|
return value;
|
|
38
10
|
}
|
|
39
|
-
function
|
|
40
|
-
if (typeof value !== "
|
|
41
|
-
|
|
42
|
-
}
|
|
11
|
+
function string(value, name, allowEmpty = false) {
|
|
12
|
+
if (typeof value !== "string" || (!allowEmpty && !value.trim()))
|
|
13
|
+
throw new TypeError(`${name} must be a string${allowEmpty ? "" : " with content"}`);
|
|
43
14
|
return value;
|
|
44
15
|
}
|
|
45
|
-
function
|
|
46
|
-
if (typeof value !== "
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
return value;
|
|
50
|
-
}
|
|
51
|
-
function nonNegativeSafeInteger(value, contract, path) {
|
|
52
|
-
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
|
|
53
|
-
invalid(contract, path, "a non-negative safe integer");
|
|
54
|
-
}
|
|
16
|
+
function boolean(value, name) {
|
|
17
|
+
if (typeof value !== "boolean")
|
|
18
|
+
throw new TypeError(`${name} must be a boolean`);
|
|
55
19
|
return value;
|
|
56
20
|
}
|
|
57
|
-
function
|
|
58
|
-
if (typeof value !== "number" || !Number.
|
|
59
|
-
|
|
60
|
-
}
|
|
21
|
+
function integer(value, name, min = 0, max = Number.MAX_SAFE_INTEGER) {
|
|
22
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < min || value > max)
|
|
23
|
+
throw new TypeError(`${name} must be an integer from ${min} to ${max}`);
|
|
61
24
|
return value;
|
|
62
25
|
}
|
|
63
|
-
function
|
|
26
|
+
function timestamp(value, name) {
|
|
64
27
|
if (!isCanonicalIsoTimestamp(value))
|
|
65
|
-
|
|
28
|
+
throw new TypeError(`${name} must be a canonical timestamp`);
|
|
66
29
|
return value;
|
|
67
30
|
}
|
|
68
|
-
function optionalString(source, key
|
|
69
|
-
return Object.hasOwn(source, key) ?
|
|
31
|
+
function optionalString(source, key) {
|
|
32
|
+
return Object.hasOwn(source, key) ? string(source[key], key, true) : undefined;
|
|
70
33
|
}
|
|
71
|
-
function
|
|
72
|
-
return
|
|
73
|
-
}
|
|
74
|
-
function parseSystemProxyState(value, contract, path) {
|
|
75
|
-
const source = objectValue(value, contract, path);
|
|
76
|
-
const server = optionalString(source, "server", contract, `${path}.server`);
|
|
77
|
-
const details = optionalString(source, "details", contract, `${path}.details`);
|
|
78
|
-
return {
|
|
79
|
-
supported: booleanValue(required(source, "supported", contract, `${path}.supported`), contract, `${path}.supported`),
|
|
80
|
-
enabled: booleanValue(required(source, "enabled", contract, `${path}.enabled`), contract, `${path}.enabled`),
|
|
81
|
-
...(server !== undefined ? { server } : {}),
|
|
82
|
-
...(details !== undefined ? { details } : {}),
|
|
83
|
-
};
|
|
34
|
+
export function apiErrorBody(code, message) {
|
|
35
|
+
return { error: { code, message } };
|
|
84
36
|
}
|
|
85
|
-
function
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
: undefined;
|
|
93
|
-
const healthy = Object.hasOwn(source, "healthy")
|
|
94
|
-
? booleanValue(source.healthy, contract, "core.healthy")
|
|
95
|
-
: undefined;
|
|
96
|
-
const version = optionalString(source, "version", contract, "core.version");
|
|
97
|
-
const tunActive = Object.hasOwn(source, "tunActive")
|
|
98
|
-
? booleanValue(source.tunActive, contract, "core.tunActive")
|
|
99
|
-
: undefined;
|
|
100
|
-
return {
|
|
101
|
-
running: booleanValue(required(source, "running", contract, "core.running"), contract, "core.running"),
|
|
102
|
-
...(pid !== undefined ? { pid } : {}),
|
|
103
|
-
...(startedAt !== undefined ? { startedAt } : {}),
|
|
104
|
-
...(healthy !== undefined ? { healthy } : {}),
|
|
105
|
-
...(version !== undefined ? { version } : {}),
|
|
106
|
-
...(tunActive !== undefined ? { tunActive } : {}),
|
|
107
|
-
};
|
|
37
|
+
export function parseApiErrorBody(value) {
|
|
38
|
+
if (!isPlainObject(value) ||
|
|
39
|
+
!isPlainObject(value.error) ||
|
|
40
|
+
typeof value.error.code !== "string" ||
|
|
41
|
+
typeof value.error.message !== "string")
|
|
42
|
+
return undefined;
|
|
43
|
+
return { code: value.error.code, message: value.error.message };
|
|
108
44
|
}
|
|
109
|
-
export function
|
|
110
|
-
const
|
|
111
|
-
const source = objectValue(value, contract, "settings");
|
|
45
|
+
export function parseHealthInfo(value) {
|
|
46
|
+
const source = object(value, "health");
|
|
112
47
|
return {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
allowLan: booleanValue(required(source, "allowLan", contract, "settings.allowLan"), contract, "settings.allowLan"),
|
|
117
|
-
daemonPort: portValue(required(source, "daemonPort", contract, "settings.daemonPort"), contract, "settings.daemonPort"),
|
|
118
|
-
systemProxy: booleanValue(required(source, "systemProxy", contract, "settings.systemProxy"), contract, "settings.systemProxy"),
|
|
48
|
+
token: string(source.token, "token"),
|
|
49
|
+
pid: integer(source.pid, "pid", 1),
|
|
50
|
+
startedAt: timestamp(source.startedAt, "startedAt"),
|
|
119
51
|
};
|
|
120
52
|
}
|
|
121
|
-
function
|
|
122
|
-
const source =
|
|
123
|
-
const subInfoValue = Object.hasOwn(source, "subInfo")
|
|
124
|
-
? objectValue(source.subInfo, contract, `${path}.subInfo`)
|
|
125
|
-
: undefined;
|
|
126
|
-
const subInfo = subInfoValue
|
|
127
|
-
? {
|
|
128
|
-
upload: finiteNumber(required(subInfoValue, "upload", contract, `${path}.subInfo.upload`), contract, `${path}.subInfo.upload`),
|
|
129
|
-
download: finiteNumber(required(subInfoValue, "download", contract, `${path}.subInfo.download`), contract, `${path}.subInfo.download`),
|
|
130
|
-
total: finiteNumber(required(subInfoValue, "total", contract, `${path}.subInfo.total`), contract, `${path}.subInfo.total`),
|
|
131
|
-
...(Object.hasOwn(subInfoValue, "expire")
|
|
132
|
-
? {
|
|
133
|
-
expire: finiteNumber(subInfoValue.expire, contract, `${path}.subInfo.expire`),
|
|
134
|
-
}
|
|
135
|
-
: {}),
|
|
136
|
-
}
|
|
137
|
-
: undefined;
|
|
138
|
-
const homePage = optionalString(source, "homePage", contract, `${path}.homePage`);
|
|
139
|
-
const lastError = optionalString(source, "lastError", contract, `${path}.lastError`);
|
|
53
|
+
export function parseWebBootstrapInfo(value) {
|
|
54
|
+
const source = object(value, "bootstrap");
|
|
140
55
|
return {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
url: stringValue(required(source, "url", contract, `${path}.url`), contract, `${path}.url`),
|
|
144
|
-
intervalHours: nonNegativeSafeInteger(required(source, "intervalHours", contract, `${path}.intervalHours`), contract, `${path}.intervalHours`),
|
|
145
|
-
createdAt: timestampValue(required(source, "createdAt", contract, `${path}.createdAt`), contract, `${path}.createdAt`),
|
|
146
|
-
updatedAt: timestampValue(required(source, "updatedAt", contract, `${path}.updatedAt`), contract, `${path}.updatedAt`),
|
|
147
|
-
...(subInfo !== undefined ? { subInfo } : {}),
|
|
148
|
-
...(homePage !== undefined ? { homePage } : {}),
|
|
149
|
-
...(lastError !== undefined ? { lastError } : {}),
|
|
56
|
+
token: string(source.token, "token"),
|
|
57
|
+
expiresAt: timestamp(source.expiresAt, "expiresAt"),
|
|
150
58
|
};
|
|
151
59
|
}
|
|
152
|
-
function
|
|
153
|
-
|
|
154
|
-
? { proxyCount: nonNegativeSafeInteger(source.proxyCount, contract, `${path}.proxyCount`) }
|
|
155
|
-
: {};
|
|
156
|
-
}
|
|
157
|
-
export function parseHealthInfo(value) {
|
|
158
|
-
const contract = "sashd health";
|
|
159
|
-
const source = objectValue(value, contract, "response");
|
|
60
|
+
export function parseWebSessionInfo(value) {
|
|
61
|
+
const source = object(value, "session");
|
|
160
62
|
return {
|
|
161
|
-
token:
|
|
162
|
-
|
|
163
|
-
startedAt: timestampValue(required(source, "startedAt", contract, "startedAt"), contract, "startedAt"),
|
|
63
|
+
token: string(source.token, "token"),
|
|
64
|
+
daemonToken: string(source.daemonToken, "daemonToken"),
|
|
164
65
|
};
|
|
165
66
|
}
|
|
166
67
|
export function parseCoreStartResult(value) {
|
|
167
|
-
const
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
const tunActive = Object.hasOwn(source, "tunActive")
|
|
171
|
-
? booleanValue(source.tunActive, contract, "tunActive")
|
|
172
|
-
: undefined;
|
|
173
|
-
return {
|
|
174
|
-
pid: positiveSafeInteger(required(source, "pid", contract, "pid"), contract, "pid"),
|
|
175
|
-
...(version !== undefined ? { version } : {}),
|
|
176
|
-
...(tunActive !== undefined ? { tunActive } : {}),
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
export function parseCoreReloadResult(value) {
|
|
180
|
-
const contract = "sashd core reload";
|
|
181
|
-
const source = objectValue(value, contract, "response");
|
|
182
|
-
const sourceKind = stringValue(required(source, "source", contract, "source"), contract, "source");
|
|
183
|
-
if (sourceKind !== "subscription" && sourceKind !== "default") {
|
|
184
|
-
invalid(contract, "source", `"subscription" or "default"`);
|
|
185
|
-
}
|
|
186
|
-
return {
|
|
187
|
-
proxyCount: nonNegativeSafeInteger(required(source, "proxyCount", contract, "proxyCount"), contract, "proxyCount"),
|
|
188
|
-
source: sourceKind,
|
|
189
|
-
};
|
|
68
|
+
const source = object(value, "Core start");
|
|
69
|
+
const version = optionalString(source, "version");
|
|
70
|
+
return { pid: integer(source.pid, "pid", 1), ...(version !== undefined ? { version } : {}) };
|
|
190
71
|
}
|
|
191
|
-
export function
|
|
192
|
-
|
|
193
|
-
const source = objectValue(value, contract, "response");
|
|
194
|
-
return {
|
|
195
|
-
coreWasRunning: booleanValue(required(source, "coreWasRunning", contract, "coreWasRunning"), contract, "coreWasRunning"),
|
|
196
|
-
};
|
|
72
|
+
export function parseCoreUpdateResponse(value) {
|
|
73
|
+
return { version: string(object(value, "Core update").version, "version") };
|
|
197
74
|
}
|
|
198
|
-
export function
|
|
199
|
-
const
|
|
200
|
-
const source = objectValue(value, contract, "response");
|
|
201
|
-
const state = parseSystemProxyState(source, contract, "response");
|
|
202
|
-
const queryError = optionalString(source, "queryError", contract, "queryError");
|
|
75
|
+
export function parsePublicSettings(value) {
|
|
76
|
+
const source = object(value, "settings");
|
|
203
77
|
return {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
...(queryError !== undefined ? { queryError } : {}),
|
|
78
|
+
mixedPort: integer(source.mixedPort, "mixedPort", 1, 65535),
|
|
79
|
+
controller: string(source.controller, "controller"),
|
|
80
|
+
allowLan: boolean(source.allowLan, "allowLan"),
|
|
81
|
+
daemonPort: integer(source.daemonPort, "daemonPort", 1, 65535),
|
|
82
|
+
systemProxy: boolean(source.systemProxy, "systemProxy"),
|
|
210
83
|
};
|
|
211
84
|
}
|
|
212
|
-
export function parseSettingsPatch(value
|
|
213
|
-
const
|
|
214
|
-
const fail = (path, expected) => {
|
|
215
|
-
throw new TypeError(`${subject} is invalid: ${path} must be ${expected}`);
|
|
216
|
-
};
|
|
217
|
-
if (!isPlainObject(value))
|
|
218
|
-
fail("body", "a plain object");
|
|
219
|
-
const source = value;
|
|
220
|
-
const allowed = new Set([
|
|
221
|
-
"mixedPort",
|
|
222
|
-
"allowLan",
|
|
223
|
-
"tun",
|
|
224
|
-
"systemProxy",
|
|
225
|
-
"daemonPort",
|
|
226
|
-
"daemonSecret",
|
|
227
|
-
]);
|
|
85
|
+
export function parseSettingsPatch(value) {
|
|
86
|
+
const source = object(value, "settings patch");
|
|
228
87
|
for (const key of Object.keys(source)) {
|
|
229
|
-
if (!
|
|
230
|
-
|
|
88
|
+
if (!["mixedPort", "allowLan", "systemProxy"].includes(key))
|
|
89
|
+
throw new TypeError(`Unknown settings field: ${key}`);
|
|
231
90
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
if (!Object.hasOwn(source, key))
|
|
243
|
-
return undefined;
|
|
244
|
-
const field = source[key];
|
|
245
|
-
if (typeof field !== "boolean")
|
|
246
|
-
return fail(key, "a boolean");
|
|
247
|
-
return field;
|
|
91
|
+
return {
|
|
92
|
+
...(Object.hasOwn(source, "mixedPort")
|
|
93
|
+
? { mixedPort: integer(source.mixedPort, "mixedPort", 1, 65535) }
|
|
94
|
+
: {}),
|
|
95
|
+
...(Object.hasOwn(source, "allowLan")
|
|
96
|
+
? { allowLan: boolean(source.allowLan, "allowLan") }
|
|
97
|
+
: {}),
|
|
98
|
+
...(Object.hasOwn(source, "systemProxy")
|
|
99
|
+
? { systemProxy: boolean(source.systemProxy, "systemProxy") }
|
|
100
|
+
: {}),
|
|
248
101
|
};
|
|
249
|
-
const patch = {};
|
|
250
|
-
const mixedPort = portField("mixedPort");
|
|
251
|
-
if (mixedPort !== undefined)
|
|
252
|
-
patch.mixedPort = mixedPort;
|
|
253
|
-
const daemonPort = portField("daemonPort");
|
|
254
|
-
if (daemonPort !== undefined)
|
|
255
|
-
patch.daemonPort = daemonPort;
|
|
256
|
-
const allowLan = boolField("allowLan");
|
|
257
|
-
if (allowLan !== undefined)
|
|
258
|
-
patch.allowLan = allowLan;
|
|
259
|
-
const tun = boolField("tun");
|
|
260
|
-
if (tun !== undefined)
|
|
261
|
-
patch.tun = tun;
|
|
262
|
-
const systemProxy = boolField("systemProxy");
|
|
263
|
-
if (systemProxy !== undefined)
|
|
264
|
-
patch.systemProxy = systemProxy;
|
|
265
|
-
if (Object.hasOwn(source, "daemonSecret")) {
|
|
266
|
-
const secret = source.daemonSecret;
|
|
267
|
-
if (typeof secret !== "string" || !secret.trim()) {
|
|
268
|
-
fail("daemonSecret", "a non-empty string");
|
|
269
|
-
}
|
|
270
|
-
patch.daemonSecret = secret;
|
|
271
|
-
}
|
|
272
|
-
return patch;
|
|
273
102
|
}
|
|
274
103
|
export function parseSettingsWriteResult(value) {
|
|
275
|
-
const
|
|
276
|
-
const source = objectValue(value, contract, "response");
|
|
104
|
+
const source = object(value, "settings write");
|
|
277
105
|
return {
|
|
278
|
-
restartRequired:
|
|
279
|
-
settings: parsePublicSettings(
|
|
106
|
+
restartRequired: boolean(source.restartRequired, "restartRequired"),
|
|
107
|
+
settings: parsePublicSettings(source.settings),
|
|
280
108
|
};
|
|
281
109
|
}
|
|
282
|
-
|
|
283
|
-
const
|
|
284
|
-
const
|
|
110
|
+
function parseSystemProxyState(value) {
|
|
111
|
+
const source = object(value, "system proxy");
|
|
112
|
+
const server = optionalString(source, "server");
|
|
113
|
+
const details = optionalString(source, "details");
|
|
285
114
|
return {
|
|
286
|
-
|
|
115
|
+
supported: boolean(source.supported, "supported"),
|
|
116
|
+
enabled: boolean(source.enabled, "enabled"),
|
|
117
|
+
...(server !== undefined ? { server } : {}),
|
|
118
|
+
...(details !== undefined ? { details } : {}),
|
|
287
119
|
};
|
|
288
120
|
}
|
|
289
|
-
export function
|
|
290
|
-
const
|
|
291
|
-
const
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
121
|
+
export function parseSystemProxyStatusResponse(value) {
|
|
122
|
+
const source = object(value, "system proxy status");
|
|
123
|
+
const queryError = optionalString(source, "queryError");
|
|
124
|
+
return {
|
|
125
|
+
...parseSystemProxyState(source),
|
|
126
|
+
desired: boolean(source.desired, "desired"),
|
|
127
|
+
applied: boolean(source.applied, "applied"),
|
|
128
|
+
appliedKnown: boolean(source.appliedKnown, "appliedKnown"),
|
|
129
|
+
stateKnown: boolean(source.stateKnown, "stateKnown"),
|
|
130
|
+
...(queryError !== undefined ? { queryError } : {}),
|
|
299
131
|
};
|
|
300
132
|
}
|
|
301
133
|
export function parseProfileActionResponse(value) {
|
|
302
|
-
const
|
|
303
|
-
const source = objectValue(value, contract, "response");
|
|
134
|
+
const source = object(value, "profile action");
|
|
304
135
|
return {
|
|
305
|
-
profile: parseProfileMeta(
|
|
306
|
-
activated:
|
|
307
|
-
...optionalProxyCount(source, contract, "response"),
|
|
136
|
+
profile: parseProfileMeta(source.profile),
|
|
137
|
+
activated: boolean(source.activated, "activated"),
|
|
308
138
|
};
|
|
309
139
|
}
|
|
310
140
|
export function parseProfileUpdateResponse(value) {
|
|
311
|
-
|
|
312
|
-
const source = objectValue(value, contract, "response");
|
|
313
|
-
return {
|
|
314
|
-
profile: parseProfileMeta(required(source, "profile", contract, "profile"), contract, "profile"),
|
|
315
|
-
...optionalProxyCount(source, contract, "response"),
|
|
316
|
-
};
|
|
317
|
-
}
|
|
318
|
-
export function parseProfilesUpdateAllResponse(value) {
|
|
319
|
-
const contract = "sashd profiles update-all";
|
|
320
|
-
const source = objectValue(value, contract, "response");
|
|
321
|
-
const failedValue = required(source, "failed", contract, "failed");
|
|
322
|
-
if (!Array.isArray(failedValue))
|
|
323
|
-
invalid(contract, "failed", "an array");
|
|
324
|
-
return {
|
|
325
|
-
updated: nonNegativeSafeInteger(required(source, "updated", contract, "updated"), contract, "updated"),
|
|
326
|
-
failed: failedValue.map((entry, index) => {
|
|
327
|
-
const path = `failed[${index}]`;
|
|
328
|
-
const failure = objectValue(entry, contract, path);
|
|
329
|
-
return {
|
|
330
|
-
id: stringValue(required(failure, "id", contract, `${path}.id`), contract, `${path}.id`),
|
|
331
|
-
name: stringValue(required(failure, "name", contract, `${path}.name`), contract, `${path}.name`),
|
|
332
|
-
error: stringValue(required(failure, "error", contract, `${path}.error`), contract, `${path}.error`),
|
|
333
|
-
};
|
|
334
|
-
}),
|
|
335
|
-
...optionalProxyCount(source, contract, "response"),
|
|
336
|
-
};
|
|
141
|
+
return { profile: parseProfileMeta(object(value, "profile").profile) };
|
|
337
142
|
}
|
|
143
|
+
export { parseProfileUpdateResponse as parseProfileRenameResponse };
|
|
338
144
|
export function parseProfileContentResponse(value) {
|
|
339
|
-
const
|
|
340
|
-
const source = objectValue(value, contract, "response");
|
|
145
|
+
const source = object(value, "profile content");
|
|
341
146
|
return {
|
|
342
|
-
name:
|
|
343
|
-
content:
|
|
147
|
+
name: string(source.name, "name"),
|
|
148
|
+
content: string(source.content, "content", true),
|
|
149
|
+
revision: integer(source.revision, "revision", 1),
|
|
344
150
|
};
|
|
345
151
|
}
|
|
346
152
|
export function parseProfileActivateResponse(value) {
|
|
347
|
-
const
|
|
348
|
-
const source = objectValue(value, contract, "response");
|
|
349
|
-
const activeValue = required(source, "activeId", contract, "activeId");
|
|
153
|
+
const source = object(value, "profile selection");
|
|
350
154
|
return {
|
|
351
|
-
activeId:
|
|
352
|
-
proxyCount:
|
|
155
|
+
activeId: source.activeId === null ? null : string(source.activeId, "activeId"),
|
|
156
|
+
proxyCount: integer(source.proxyCount, "proxyCount"),
|
|
353
157
|
};
|
|
354
158
|
}
|
|
355
159
|
export function parseProfileRemoveResponse(value) {
|
|
356
|
-
|
|
357
|
-
const source = objectValue(value, contract, "response");
|
|
358
|
-
return {
|
|
359
|
-
wasActive: booleanValue(required(source, "wasActive", contract, "wasActive"), contract, "wasActive"),
|
|
360
|
-
...optionalProxyCount(source, contract, "response"),
|
|
361
|
-
};
|
|
160
|
+
return { wasActive: boolean(object(value, "profile removal").wasActive, "wasActive") };
|
|
362
161
|
}
|
|
363
|
-
export function
|
|
364
|
-
const
|
|
365
|
-
|
|
162
|
+
export function parseProfilesUpdateAllResponse(value) {
|
|
163
|
+
const source = object(value, "profiles update");
|
|
164
|
+
if (!Array.isArray(source.failed))
|
|
165
|
+
throw new TypeError("failed must be an array");
|
|
366
166
|
return {
|
|
367
|
-
|
|
167
|
+
updated: integer(source.updated, "updated"),
|
|
168
|
+
failed: source.failed.map((item) => {
|
|
169
|
+
const failure = object(item, "profile error");
|
|
170
|
+
return {
|
|
171
|
+
id: string(failure.id, "id"),
|
|
172
|
+
name: string(failure.name, "name"),
|
|
173
|
+
error: string(failure.error, "error"),
|
|
174
|
+
};
|
|
175
|
+
}),
|
|
368
176
|
};
|
|
369
177
|
}
|
|
370
178
|
export function parseDaemonStatus(value) {
|
|
371
|
-
const
|
|
372
|
-
const
|
|
373
|
-
const
|
|
374
|
-
const
|
|
375
|
-
const
|
|
376
|
-
const
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
const queryError = optionalString(proxySource, "queryError", contract, "systemProxy.queryError");
|
|
380
|
-
const activeValue = required(source, "activeProfile", contract, "activeProfile");
|
|
381
|
-
const activeProfile = activeValue === null
|
|
179
|
+
const source = object(value, "status");
|
|
180
|
+
const daemon = object(source.daemon, "daemon");
|
|
181
|
+
const revisions = object(source.revisions, "revisions");
|
|
182
|
+
const core = object(source.core, "core");
|
|
183
|
+
const proxy = object(source.systemProxy, "systemProxy");
|
|
184
|
+
const configuration = object(source.configuration, "configuration");
|
|
185
|
+
const selected = source.activeProfile === null ? null : object(source.activeProfile, "activeProfile");
|
|
186
|
+
const applied = configuration.appliedProfile === null
|
|
382
187
|
? null
|
|
383
|
-
: (
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
};
|
|
390
|
-
})();
|
|
188
|
+
: object(configuration.appliedProfile, "appliedProfile");
|
|
189
|
+
const appliedSettings = configuration.appliedSettings === null
|
|
190
|
+
? null
|
|
191
|
+
: object(configuration.appliedSettings, "appliedSettings");
|
|
192
|
+
const version = optionalString(core, "version");
|
|
193
|
+
const queryError = optionalString(proxy, "queryError");
|
|
391
194
|
return {
|
|
392
195
|
daemon: {
|
|
393
|
-
pid:
|
|
394
|
-
|
|
395
|
-
|
|
196
|
+
pid: integer(daemon.pid, "daemon.pid", 1),
|
|
197
|
+
bootId: string(daemon.bootId, "daemon.bootId"),
|
|
198
|
+
startedAt: timestamp(daemon.startedAt, "daemon.startedAt"),
|
|
199
|
+
port: integer(daemon.port, "daemon.port", 1, 65535),
|
|
396
200
|
},
|
|
397
201
|
revisions: {
|
|
398
|
-
profiles:
|
|
202
|
+
profiles: integer(revisions.profiles, "revisions.profiles"),
|
|
203
|
+
runtime: integer(revisions.runtime, "revisions.runtime"),
|
|
204
|
+
},
|
|
205
|
+
core: {
|
|
206
|
+
running: boolean(core.running, "core.running"),
|
|
207
|
+
...(Object.hasOwn(core, "pid") ? { pid: integer(core.pid, "core.pid", 1) } : {}),
|
|
208
|
+
...(Object.hasOwn(core, "startedAt")
|
|
209
|
+
? { startedAt: timestamp(core.startedAt, "core.startedAt") }
|
|
210
|
+
: {}),
|
|
211
|
+
...(Object.hasOwn(core, "healthy") ? { healthy: boolean(core.healthy, "core.healthy") } : {}),
|
|
212
|
+
...(version !== undefined ? { version } : {}),
|
|
213
|
+
},
|
|
214
|
+
configuration: {
|
|
215
|
+
pending: boolean(configuration.pending, "configuration.pending"),
|
|
216
|
+
appliedProfile: applied
|
|
217
|
+
? {
|
|
218
|
+
id: string(applied.id, "appliedProfile.id"),
|
|
219
|
+
revision: integer(applied.revision, "appliedProfile.revision", 1),
|
|
220
|
+
name: string(applied.name, "appliedProfile.name"),
|
|
221
|
+
url: string(applied.url, "appliedProfile.url", true),
|
|
222
|
+
}
|
|
223
|
+
: null,
|
|
224
|
+
appliedSettings: appliedSettings
|
|
225
|
+
? {
|
|
226
|
+
mixedPort: integer(appliedSettings.mixedPort, "appliedSettings.mixedPort", 1, 65535),
|
|
227
|
+
allowLan: boolean(appliedSettings.allowLan, "appliedSettings.allowLan"),
|
|
228
|
+
}
|
|
229
|
+
: null,
|
|
399
230
|
},
|
|
400
|
-
core: parseCoreState(required(source, "core", contract, "core"), contract),
|
|
401
231
|
systemProxy: {
|
|
402
|
-
desired:
|
|
403
|
-
applied:
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
232
|
+
desired: boolean(proxy.desired, "systemProxy.desired"),
|
|
233
|
+
applied: boolean(proxy.applied, "systemProxy.applied"),
|
|
234
|
+
appliedKnown: boolean(proxy.appliedKnown, "systemProxy.appliedKnown"),
|
|
235
|
+
stateKnown: boolean(proxy.stateKnown, "systemProxy.stateKnown"),
|
|
236
|
+
...(Object.hasOwn(proxy, "actual") ? { actual: parseSystemProxyState(proxy.actual) } : {}),
|
|
407
237
|
...(queryError !== undefined ? { queryError } : {}),
|
|
408
238
|
},
|
|
409
|
-
settings: parsePublicSettings(
|
|
410
|
-
activeProfile
|
|
239
|
+
settings: parsePublicSettings(source.settings),
|
|
240
|
+
activeProfile: selected
|
|
241
|
+
? {
|
|
242
|
+
id: string(selected.id, "activeProfile.id"),
|
|
243
|
+
name: string(selected.name, "activeProfile.name"),
|
|
244
|
+
url: string(selected.url, "activeProfile.url", true),
|
|
245
|
+
}
|
|
246
|
+
: null,
|
|
411
247
|
};
|
|
412
248
|
}
|