@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.
Files changed (108) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/README.md +22 -7
  3. package/THIRD_PARTY_NOTICES.md +9 -0
  4. package/dist/api.js +14 -45
  5. package/dist/app-state.js +99 -0
  6. package/dist/autostart/command.js +24 -0
  7. package/dist/autostart/context.js +43 -0
  8. package/dist/autostart/files.js +60 -0
  9. package/dist/autostart/installation.js +48 -0
  10. package/dist/autostart/start.js +47 -0
  11. package/dist/autostart/windows-registry.js +88 -0
  12. package/dist/autostart/windows.js +59 -0
  13. package/dist/autostart-contract.js +31 -0
  14. package/dist/autostart-entry.js +10 -0
  15. package/dist/autostart.js +69 -0
  16. package/dist/cli.js +11 -11
  17. package/dist/commands/auto.js +15 -0
  18. package/dist/commands/lifecycle.js +5 -31
  19. package/dist/commands/logs.js +11 -4
  20. package/dist/commands/shared.js +2 -4
  21. package/dist/commands/status.js +6 -7
  22. package/dist/commands/update.js +7 -3
  23. package/dist/commands/web.js +19 -27
  24. package/dist/contracts.js +171 -335
  25. package/dist/core-config-validation.js +22 -38
  26. package/dist/core-update.js +126 -762
  27. package/dist/core.js +20 -46
  28. package/dist/daemon/app.js +132 -113
  29. package/dist/daemon/context.js +13 -7
  30. package/dist/daemon/entry.js +21 -38
  31. package/dist/daemon/errors.js +6 -1
  32. package/dist/daemon/handlers/autostart.js +18 -0
  33. package/dist/daemon/handlers/core.js +32 -9
  34. package/dist/daemon/handlers/daemon.js +32 -6
  35. package/dist/daemon/handlers/profiles.js +12 -2
  36. package/dist/daemon/handlers/settings.js +9 -36
  37. package/dist/daemon/router.js +40 -27
  38. package/dist/daemon/scheduler.js +3 -1
  39. package/dist/daemon/server.js +6 -3
  40. package/dist/daemon/web-auth.js +52 -0
  41. package/dist/daemon-auth.js +2 -2
  42. package/dist/daemon-client.js +18 -2
  43. package/dist/daemon-http.js +7 -0
  44. package/dist/daemon-lifecycle.js +19 -196
  45. package/dist/github.js +7 -2
  46. package/dist/http.js +7 -5
  47. package/dist/log-follow.js +2 -1
  48. package/dist/mihomo-config.js +7 -9
  49. package/dist/paths.js +5 -7
  50. package/dist/profile-model.js +87 -0
  51. package/dist/profile-service.js +250 -587
  52. package/dist/profiles.js +43 -171
  53. package/dist/runtime-lifecycle.js +112 -194
  54. package/dist/runtime-owner.js +37 -76
  55. package/dist/sash-client.js +63 -21
  56. package/dist/settings-service.js +29 -228
  57. package/dist/settings.js +61 -285
  58. package/dist/status.js +24 -40
  59. package/dist/supervisor.js +1 -14
  60. package/dist/sysproxy/common.js +5 -45
  61. package/dist/sysproxy/factory.js +24 -65
  62. package/dist/sysproxy/snapshot.js +24 -257
  63. package/dist/sysproxy.js +1 -4
  64. package/dist/system-proxy-manager.js +37 -35
  65. package/dist/ui/assets/{ConnectionsView-DNGmZBSU.js → ConnectionsView-BgXQM6Z4.js} +1 -1
  66. package/dist/ui/assets/{LogsView-fSiaxQ13.js → LogsView-2f542P8z.js} +1 -1
  67. package/dist/ui/assets/{PaginationFooter-B3kHzRfB.js → PaginationFooter-cj1tcZej.js} +1 -1
  68. package/dist/ui/assets/ProfileEditorDialog-C9M8uKZC.css +1 -0
  69. package/dist/ui/assets/ProfileEditorDialog-DD4y4GBC.js +14 -0
  70. package/dist/ui/assets/ProfilesView-BXU2DOA7.css +1 -0
  71. package/dist/ui/assets/ProfilesView-DNnzYIEY.js +7 -0
  72. package/dist/ui/assets/{RulesView-D9vZBiJ1.js → RulesView-CtKvlckZ.js} +1 -1
  73. package/dist/ui/assets/SettingsView-BaeKFF_N.js +1 -0
  74. package/dist/ui/assets/SettingsView-CWjIe05v.css +1 -0
  75. package/dist/ui/assets/{0be242294f7d791af850c6df38ac78a0-2cL6Ntwf.woff2 → e2a57555d97d0b02b45d9418eb6ee295-D9nhF3rM.woff2} +0 -0
  76. package/dist/ui/assets/index-CBInDvdJ.js +19 -0
  77. package/dist/ui/assets/index-mOLy7fkB.css +1 -0
  78. package/dist/ui/assets/{theme-BNq4FkXS.js → theme-D40MF8cQ.js} +1 -1
  79. package/dist/ui/index.html +2 -2
  80. package/dist/web-bootstrap.js +113 -0
  81. package/docs/architecture-proposal.md +109 -0
  82. package/docs/autostart.md +101 -0
  83. package/docs/backend.md +92 -216
  84. package/docs/frontend.md +61 -97
  85. package/docs/usage.md +88 -186
  86. package/package.json +10 -6
  87. package/dist/commands/upgrade.js +0 -43
  88. package/dist/core-install-transaction.js +0 -114
  89. package/dist/core-update-coordination.js +0 -105
  90. package/dist/core-update-service.js +0 -245
  91. package/dist/managed-state-transaction.js +0 -377
  92. package/dist/offline-mutation.js +0 -58
  93. package/dist/profile-migration.js +0 -101
  94. package/dist/runtime-recovery.js +0 -31
  95. package/dist/sysproxy/darwin.js +0 -287
  96. package/dist/sysproxy/gnome.js +0 -181
  97. package/dist/sysproxy/legacy.js +0 -58
  98. package/dist/tun-guidance.js +0 -11
  99. package/dist/ui/assets/CodeEditorModal-6m0TJWyF.css +0 -1
  100. package/dist/ui/assets/CodeEditorModal-CFEnWsyh.js +0 -14
  101. package/dist/ui/assets/ProfileEditorDialog-BydoZthX.js +0 -1
  102. package/dist/ui/assets/ProfilesView-Btc1DOxE.js +0 -2
  103. package/dist/ui/assets/ProfilesView-ByqdFNHN.css +0 -1
  104. package/dist/ui/assets/SettingsFileDialog-CNFEAVs4.js +0 -1
  105. package/dist/ui/assets/SettingsView-BlDhZkXQ.js +0 -2
  106. package/dist/ui/assets/SettingsView-CngS3vBM.css +0 -1
  107. package/dist/ui/assets/index-B61V60w_.js +0 -19
  108. package/dist/ui/assets/index-bkyxJG8J.css +0 -1
@@ -1,71 +1,30 @@
1
- import { isSystemProxySupported } from "./common.js";
2
- import { applyDarwinSnapshot, captureDarwinSnapshot, createDarwinTarget, darwinState, } from "./darwin.js";
3
- import { applyLinuxSnapshot, captureLinuxSnapshot, createLinuxTarget, linuxState, } from "./gnome.js";
4
- import { parseSystemProxySnapshot, snapshotsCompatible, snapshotsEquivalent } from "./snapshot.js";
1
+ import { snapshotsCompatible, snapshotsEquivalent } from "./snapshot.js";
5
2
  import { applyWindowsSnapshot, captureWindowsSnapshot, createWindowsTarget, windowsState, } from "./windows.js";
6
- function createSupportedBackend(operations) {
3
+ export function createSystemProxyBackend(platform = process.platform) {
4
+ if (platform === "win32")
5
+ return {
6
+ supported: true,
7
+ capture: captureWindowsSnapshot,
8
+ createTarget: createWindowsTarget,
9
+ apply: applyWindowsSnapshot,
10
+ equivalent: snapshotsEquivalent,
11
+ compatible: snapshotsCompatible,
12
+ state: windowsState,
13
+ };
14
+ const unavailable = () => {
15
+ throw new Error("System proxy integration is available on Windows only");
16
+ };
7
17
  return {
8
- supported: true,
9
- capture: () => operations.capture(),
10
- createTarget: (original, opts) => operations.createTarget(original, opts),
11
- apply: (snapshot) => operations.apply(snapshot),
18
+ supported: false,
19
+ capture: async () => unavailable(),
20
+ createTarget: unavailable,
21
+ apply: async () => unavailable(),
12
22
  equivalent: snapshotsEquivalent,
13
23
  compatible: snapshotsCompatible,
14
- state: (snapshot) => operations.state(snapshot),
24
+ state: () => ({
25
+ supported: false,
26
+ enabled: false,
27
+ details: "System proxy integration is available on Windows only",
28
+ }),
15
29
  };
16
30
  }
17
- class UnsupportedSystemProxyBackend {
18
- details;
19
- supported = false;
20
- constructor(details) {
21
- this.details = details;
22
- }
23
- async capture() {
24
- throw new Error(this.details);
25
- }
26
- createTarget(_original, _opts) {
27
- throw new Error(this.details);
28
- }
29
- async apply(_snapshot) {
30
- throw new Error(this.details);
31
- }
32
- equivalent(a, b) {
33
- return snapshotsEquivalent(a, b);
34
- }
35
- compatible(_current, _original, _target) {
36
- return false;
37
- }
38
- state(snapshot) {
39
- parseSystemProxySnapshot(snapshot);
40
- return { supported: false, enabled: false, details: this.details };
41
- }
42
- }
43
- export function createSystemProxyBackend(platform = process.platform) {
44
- switch (platform) {
45
- case "win32":
46
- return createSupportedBackend({
47
- capture: captureWindowsSnapshot,
48
- createTarget: createWindowsTarget,
49
- apply: applyWindowsSnapshot,
50
- state: windowsState,
51
- });
52
- case "darwin":
53
- return createSupportedBackend({
54
- capture: captureDarwinSnapshot,
55
- createTarget: createDarwinTarget,
56
- apply: applyDarwinSnapshot,
57
- state: darwinState,
58
- });
59
- case "linux":
60
- return isSystemProxySupported("linux")
61
- ? createSupportedBackend({
62
- capture: captureLinuxSnapshot,
63
- createTarget: createLinuxTarget,
64
- apply: applyLinuxSnapshot,
65
- state: linuxState,
66
- })
67
- : new UnsupportedSystemProxyBackend("gsettings not available; desktop proxy configuration unsupported");
68
- default:
69
- return new UnsupportedSystemProxyBackend(`unsupported platform: ${platform}`);
70
- }
71
- }
@@ -1,163 +1,24 @@
1
- import { hasExactOwnKeys } from "../json-shape.js";
2
- import { compareStrings, isPlainObject, parseProxyEnable, parseProxyString, parseServiceName, parseSnapshotPort, } from "./common.js";
3
- import { SYSTEM_PROXY_SNAPSHOT_VERSION } from "./types.js";
4
- const MAX_NETWORK_SERVICES = 256;
5
- function hasExactKeys(value, keys, label) {
6
- if (!isPlainObject(value)) {
7
- throw new Error(`Invalid system proxy snapshot: ${label} must be a plain object`);
8
- }
9
- if (!hasExactOwnKeys(value, keys)) {
10
- throw new Error(`Invalid system proxy snapshot: ${label} has unexpected fields`);
11
- }
12
- return value;
13
- }
14
- function parseDarwinSnapshotSetting(value, label) {
15
- const record = hasExactKeys(value, ["enabled", "server", "port", "authenticated"], label);
16
- if (typeof record.enabled !== "boolean") {
17
- throw new Error(`Invalid system proxy snapshot: ${label}.enabled must be a boolean`);
18
- }
19
- if (typeof record.authenticated !== "boolean") {
20
- throw new Error(`Invalid system proxy snapshot: ${label}.authenticated must be a boolean`);
21
- }
22
- return {
23
- enabled: record.enabled,
24
- server: parseProxyString(record.server, `${label}.server`),
25
- port: parseSnapshotPort(record.port, `${label}.port`),
26
- authenticated: record.authenticated,
27
- };
28
- }
29
- function parseDarwinAutoSetting(value, label) {
30
- const record = hasExactKeys(value, ["enabled", "url"], label);
31
- if (typeof record.enabled !== "boolean") {
32
- throw new Error(`Invalid system proxy snapshot: ${label}.enabled must be a boolean`);
33
- }
34
- return {
35
- enabled: record.enabled,
36
- url: parseProxyString(record.url, `${label}.url`),
37
- };
38
- }
39
- function parseLinuxEndpoint(value, label) {
40
- const record = hasExactKeys(value, ["host", "port"], label);
41
- return {
42
- host: parseProxyString(record.host, `${label}.host`),
43
- port: parseSnapshotPort(record.port, `${label}.port`),
44
- };
45
- }
46
- function parseWindowsSnapshot(value) {
47
- const record = hasExactKeys(value, [
48
- "version",
49
- "platform",
50
- "proxyEnable",
51
- "proxyServer",
52
- "proxyOverride",
53
- "autoConfigUrl",
54
- "autoDetect",
55
- ], "Windows snapshot");
56
- if (record.version !== SYSTEM_PROXY_SNAPSHOT_VERSION || record.platform !== "win32") {
57
- throw new Error("Invalid system proxy snapshot: expected version 1 Windows snapshot");
58
- }
59
- if (record.proxyServer !== null && typeof record.proxyServer !== "string") {
60
- throw new Error("Invalid system proxy snapshot: proxyServer must be a string or null");
61
- }
62
- if (record.proxyOverride !== null && typeof record.proxyOverride !== "string") {
63
- throw new Error("Invalid system proxy snapshot: proxyOverride must be a string or null");
64
- }
65
- if (record.autoConfigUrl !== null && typeof record.autoConfigUrl !== "string") {
66
- throw new Error("Invalid system proxy snapshot: autoConfigUrl must be a string or null");
1
+ import { hasExactOwnKeys, isPlainObject } from "../json-shape.js";
2
+ import { parseProxyEnable, parseProxyString } from "./common.js";
3
+ const MANAGED_KEYS = ["proxyEnable", "proxyServer", "proxyOverride", "autoConfigUrl"];
4
+ export function parseSystemProxySnapshot(value) {
5
+ if (!isPlainObject(value) ||
6
+ !hasExactOwnKeys(value, ["version", "platform", ...MANAGED_KEYS, "autoDetect"]) ||
7
+ value.version !== 1 ||
8
+ value.platform !== "win32") {
9
+ throw new Error("Invalid system proxy snapshot: expected a version 1 Windows snapshot");
67
10
  }
68
11
  return {
69
- version: SYSTEM_PROXY_SNAPSHOT_VERSION,
12
+ version: 1,
70
13
  platform: "win32",
71
- proxyEnable: parseProxyEnable(record.proxyEnable),
72
- proxyServer: record.proxyServer === null ? null : parseProxyString(record.proxyServer, "proxyServer"),
73
- proxyOverride: record.proxyOverride === null
74
- ? null
75
- : parseProxyString(record.proxyOverride, "proxyOverride"),
76
- autoConfigUrl: record.autoConfigUrl === null
77
- ? null
78
- : parseProxyString(record.autoConfigUrl, "autoConfigUrl"),
79
- autoDetect: parseProxyEnable(record.autoDetect),
80
- };
81
- }
82
- function parseDarwinSnapshot(value) {
83
- const record = hasExactKeys(value, ["version", "platform", "services"], "macOS snapshot");
84
- if (record.version !== SYSTEM_PROXY_SNAPSHOT_VERSION || record.platform !== "darwin") {
85
- throw new Error("Invalid system proxy snapshot: expected version 1 macOS snapshot");
86
- }
87
- if (!Array.isArray(record.services)) {
88
- throw new Error("Invalid system proxy snapshot: services must be an array");
89
- }
90
- if (record.services.length > MAX_NETWORK_SERVICES) {
91
- throw new Error("Invalid system proxy snapshot: services has too many entries");
92
- }
93
- const services = record.services.map((value, index) => {
94
- const service = hasExactKeys(value, ["service", "web", "secureWeb", "socks", "auto"], `services[${index}]`);
95
- return {
96
- service: parseServiceName(service.service, `services[${index}].service`),
97
- web: parseDarwinSnapshotSetting(service.web, `services[${index}].web`),
98
- secureWeb: parseDarwinSnapshotSetting(service.secureWeb, `services[${index}].secureWeb`),
99
- socks: parseDarwinSnapshotSetting(service.socks, `services[${index}].socks`),
100
- auto: parseDarwinAutoSetting(service.auto, `services[${index}].auto`),
101
- };
102
- });
103
- services.sort((a, b) => compareStrings(a.service, b.service));
104
- for (let index = 1; index < services.length; index++) {
105
- if (services[index - 1]?.service === services[index]?.service) {
106
- throw new Error("Invalid system proxy snapshot: services must not contain duplicate names");
107
- }
108
- }
109
- return {
110
- version: SYSTEM_PROXY_SNAPSHOT_VERSION,
111
- platform: "darwin",
112
- services,
113
- };
114
- }
115
- function parseLinuxSnapshot(value) {
116
- const record = hasExactKeys(value, [
117
- "version",
118
- "platform",
119
- "mode",
120
- "autoConfigUrl",
121
- "httpUseAuthentication",
122
- "http",
123
- "https",
124
- "socks",
125
- ], "Linux snapshot");
126
- if (record.version !== SYSTEM_PROXY_SNAPSHOT_VERSION || record.platform !== "linux") {
127
- throw new Error("Invalid system proxy snapshot: expected version 1 Linux snapshot");
128
- }
129
- if (record.mode !== "none" && record.mode !== "manual" && record.mode !== "auto") {
130
- throw new Error("Invalid system proxy snapshot: mode must be none, manual, or auto");
131
- }
132
- if (typeof record.httpUseAuthentication !== "boolean") {
133
- throw new Error("Invalid system proxy snapshot: httpUseAuthentication must be a boolean");
134
- }
135
- return {
136
- version: SYSTEM_PROXY_SNAPSHOT_VERSION,
137
- platform: "linux",
138
- mode: record.mode,
139
- autoConfigUrl: parseProxyString(record.autoConfigUrl, "autoConfigUrl"),
140
- httpUseAuthentication: record.httpUseAuthentication,
141
- http: parseLinuxEndpoint(record.http, "http"),
142
- https: parseLinuxEndpoint(record.https, "https"),
143
- socks: parseLinuxEndpoint(record.socks, "socks"),
14
+ proxyEnable: parseProxyEnable(value.proxyEnable),
15
+ proxyServer: value.proxyServer === null ? null : parseProxyString(value.proxyServer, "proxyServer"),
16
+ proxyOverride: value.proxyOverride === null ? null : parseProxyString(value.proxyOverride, "proxyOverride"),
17
+ autoConfigUrl: value.autoConfigUrl === null ? null : parseProxyString(value.autoConfigUrl, "autoConfigUrl"),
18
+ autoDetect: parseProxyEnable(value.autoDetect),
144
19
  };
145
20
  }
146
- export function parseSystemProxySnapshot(value) {
147
- if (!isPlainObject(value)) {
148
- throw new Error("Invalid system proxy snapshot: root must be a plain object");
149
- }
150
- switch (value.platform) {
151
- case "win32":
152
- return parseWindowsSnapshot(value);
153
- case "darwin":
154
- return parseDarwinSnapshot(value);
155
- case "linux":
156
- return parseLinuxSnapshot(value);
157
- default:
158
- throw new Error("Invalid system proxy snapshot: platform must be win32, darwin, or linux");
159
- }
160
- }
21
+ export { parseSystemProxySnapshot as windowsSnapshot };
161
22
  export function isSystemProxySnapshot(value) {
162
23
  try {
163
24
  parseSystemProxySnapshot(value);
@@ -167,116 +28,22 @@ export function isSystemProxySnapshot(value) {
167
28
  return false;
168
29
  }
169
30
  }
170
- export function windowsSnapshot(value) {
171
- const snapshot = parseSystemProxySnapshot(value);
172
- if (snapshot.platform !== "win32") {
173
- throw new Error("Invalid system proxy snapshot: expected Windows snapshot");
174
- }
175
- return snapshot;
176
- }
177
- export function darwinSnapshot(value) {
178
- const snapshot = parseSystemProxySnapshot(value);
179
- if (snapshot.platform !== "darwin") {
180
- throw new Error("Invalid system proxy snapshot: expected macOS snapshot");
181
- }
182
- return snapshot;
183
- }
184
- export function linuxSnapshot(value) {
185
- const snapshot = parseSystemProxySnapshot(value);
186
- if (snapshot.platform !== "linux") {
187
- throw new Error("Invalid system proxy snapshot: expected Linux snapshot");
188
- }
189
- return snapshot;
190
- }
191
- function normalizeForEquivalence(snapshot) {
192
- return snapshot.platform === "win32" ? { ...snapshot, autoDetect: null } : snapshot;
193
- }
194
- export function snapshotsEquivalent(a, b) {
31
+ export function snapshotsEquivalent(left, right) {
195
32
  try {
196
- return (JSON.stringify(normalizeForEquivalence(parseSystemProxySnapshot(a))) ===
197
- JSON.stringify(normalizeForEquivalence(parseSystemProxySnapshot(b))));
33
+ const a = parseSystemProxySnapshot(left);
34
+ const b = parseSystemProxySnapshot(right);
35
+ return MANAGED_KEYS.every((key) => a[key] === b[key]);
198
36
  }
199
37
  catch {
200
38
  return false;
201
39
  }
202
40
  }
203
- function leafIsCompatible(current, original, target) {
204
- return current === original || current === target;
205
- }
206
- function sameDarwinServices(a, b) {
207
- if (a.services.length !== b.services.length)
208
- return false;
209
- for (let index = 0; index < a.services.length; index++) {
210
- if (a.services[index]?.service !== b.services[index]?.service)
211
- return false;
212
- }
213
- return true;
214
- }
215
- function darwinSettingIsCompatible(current, original, target) {
216
- return (leafIsCompatible(current.enabled, original.enabled, target.enabled) &&
217
- leafIsCompatible(current.server, original.server, target.server) &&
218
- leafIsCompatible(current.port, original.port, target.port) &&
219
- leafIsCompatible(current.authenticated, original.authenticated, target.authenticated));
220
- }
221
- function darwinAutoSettingIsCompatible(current, original, target) {
222
- return (leafIsCompatible(current.enabled, original.enabled, target.enabled) &&
223
- leafIsCompatible(current.url, original.url, target.url));
224
- }
225
- function linuxEndpointIsCompatible(current, original, target) {
226
- return (leafIsCompatible(current.host, original.host, target.host) &&
227
- leafIsCompatible(current.port, original.port, target.port));
228
- }
229
41
  export function snapshotsCompatible(current, original, target) {
230
42
  try {
231
- const parsedCurrent = parseSystemProxySnapshot(current);
232
- const parsedOriginal = parseSystemProxySnapshot(original);
233
- const parsedTarget = parseSystemProxySnapshot(target);
234
- if (parsedCurrent.platform !== parsedOriginal.platform ||
235
- parsedCurrent.platform !== parsedTarget.platform) {
236
- return false;
237
- }
238
- switch (parsedCurrent.platform) {
239
- case "win32":
240
- if (parsedOriginal.platform !== "win32" || parsedTarget.platform !== "win32") {
241
- return false;
242
- }
243
- return (leafIsCompatible(parsedCurrent.proxyEnable, parsedOriginal.proxyEnable, parsedTarget.proxyEnable) &&
244
- leafIsCompatible(parsedCurrent.proxyServer, parsedOriginal.proxyServer, parsedTarget.proxyServer) &&
245
- leafIsCompatible(parsedCurrent.proxyOverride, parsedOriginal.proxyOverride, parsedTarget.proxyOverride) &&
246
- leafIsCompatible(parsedCurrent.autoConfigUrl, parsedOriginal.autoConfigUrl, parsedTarget.autoConfigUrl));
247
- case "darwin":
248
- if (parsedOriginal.platform !== "darwin" || parsedTarget.platform !== "darwin") {
249
- return false;
250
- }
251
- if (!sameDarwinServices(parsedCurrent, parsedOriginal) ||
252
- !sameDarwinServices(parsedCurrent, parsedTarget)) {
253
- return false;
254
- }
255
- for (let index = 0; index < parsedCurrent.services.length; index++) {
256
- const currentService = parsedCurrent.services[index];
257
- const originalService = parsedOriginal.services[index];
258
- const targetService = parsedTarget.services[index];
259
- if (!currentService || !originalService || !targetService)
260
- return false;
261
- if (!darwinSettingIsCompatible(currentService.web, originalService.web, targetService.web) ||
262
- !darwinSettingIsCompatible(currentService.secureWeb, originalService.secureWeb, targetService.secureWeb) ||
263
- !darwinSettingIsCompatible(currentService.socks, originalService.socks, targetService.socks) ||
264
- !darwinAutoSettingIsCompatible(currentService.auto, originalService.auto, targetService.auto)) {
265
- return false;
266
- }
267
- }
268
- return true;
269
- case "linux":
270
- if (parsedOriginal.platform !== "linux" || parsedTarget.platform !== "linux") {
271
- return false;
272
- }
273
- return (leafIsCompatible(parsedCurrent.mode, parsedOriginal.mode, parsedTarget.mode) &&
274
- leafIsCompatible(parsedCurrent.autoConfigUrl, parsedOriginal.autoConfigUrl, parsedTarget.autoConfigUrl) &&
275
- leafIsCompatible(parsedCurrent.httpUseAuthentication, parsedOriginal.httpUseAuthentication, parsedTarget.httpUseAuthentication) &&
276
- linuxEndpointIsCompatible(parsedCurrent.http, parsedOriginal.http, parsedTarget.http) &&
277
- linuxEndpointIsCompatible(parsedCurrent.https, parsedOriginal.https, parsedTarget.https) &&
278
- linuxEndpointIsCompatible(parsedCurrent.socks, parsedOriginal.socks, parsedTarget.socks));
279
- }
43
+ const now = parseSystemProxySnapshot(current);
44
+ const before = parseSystemProxySnapshot(original);
45
+ const after = parseSystemProxySnapshot(target);
46
+ return MANAGED_KEYS.every((key) => now[key] === before[key] || now[key] === after[key]);
280
47
  }
281
48
  catch {
282
49
  return false;
package/dist/sysproxy.js CHANGED
@@ -1,8 +1,5 @@
1
1
  export { isSystemProxySupported } from "./sysproxy/common.js";
2
- export { parseDarwinAutoProxySetting, parseDarwinProxySetting, parseDarwinServices, } from "./sysproxy/darwin.js";
3
2
  export { createSystemProxyBackend } from "./sysproxy/factory.js";
4
- export { parseGSettingsPort, parseGSettingsString } from "./sysproxy/gnome.js";
5
- export { createLegacyProxyCleanup, disableLegacySystemProxyIfOwned, } from "./sysproxy/legacy.js";
6
3
  export { isSystemProxySnapshot, parseSystemProxySnapshot } from "./sysproxy/snapshot.js";
7
4
  export { DEFAULT_BYPASS_LIST, SYSTEM_PROXY_SNAPSHOT_VERSION } from "./sysproxy/types.js";
8
- export { formatWindowsBypass, parseWindowsRegistryProxyValues, } from "./sysproxy/windows.js";
5
+ export { formatWindowsBypass, parseWindowsRegistryProxyValues } from "./sysproxy/windows.js";
@@ -16,21 +16,6 @@ function hasExactKeys(value, keys) {
16
16
  throw journalError("root has unexpected fields");
17
17
  return value;
18
18
  }
19
- function sameDarwinServiceCollection(a, b) {
20
- if (a.platform !== "darwin" || b.platform !== "darwin")
21
- return false;
22
- if (a.services.length !== b.services.length)
23
- return false;
24
- return a.services.every((service, index) => service.service === b.services[index]?.service);
25
- }
26
- function journalSnapshotsHaveSameStructure(original, target) {
27
- if (original.platform !== target.platform)
28
- return false;
29
- if (original.platform === "darwin" && target.platform === "darwin") {
30
- return sameDarwinServiceCollection(original, target);
31
- }
32
- return true;
33
- }
34
19
  function parseCreatedAt(value) {
35
20
  if (typeof value !== "string" || value.length === 0 || value.length > 128) {
36
21
  throw journalError("createdAt must be a non-empty ISO timestamp");
@@ -49,12 +34,10 @@ export function parseSystemProxyJournal(value) {
49
34
  "original",
50
35
  "target",
51
36
  ]);
52
- if (record.schemaVersion !== 1 && record.schemaVersion !== 2) {
53
- throw journalError("schemaVersion must be 1 or 2");
37
+ if (record.schemaVersion !== 2) {
38
+ throw journalError("schemaVersion must be 2");
54
39
  }
55
- if (record.phase !== "prepared" &&
56
- record.phase !== "applied" &&
57
- !(record.schemaVersion === 2 && record.phase === "restoring")) {
40
+ if (record.phase !== "prepared" && record.phase !== "applied" && record.phase !== "restoring") {
58
41
  throw journalError("phase must be prepared, applied, or restoring");
59
42
  }
60
43
  if (typeof record.ownerPid !== "number" ||
@@ -71,9 +54,6 @@ export function parseSystemProxyJournal(value) {
71
54
  catch (err) {
72
55
  throw journalError(errorMessage(err));
73
56
  }
74
- if (!journalSnapshotsHaveSameStructure(original, target)) {
75
- throw journalError("original and target have different platform structures");
76
- }
77
57
  return {
78
58
  schemaVersion: 2,
79
59
  phase: record.phase,
@@ -101,47 +81,57 @@ export class SystemProxyManager {
101
81
  backend;
102
82
  operationLockFile;
103
83
  operationQueue = Promise.resolve();
84
+ pendingWrites = 0;
104
85
  inspectionGeneration = 0;
105
86
  inspectionCache;
106
87
  inspectionInFlight;
107
- constructor(options = {}, ...unexpected) {
108
- if (typeof options !== "object" ||
109
- options === null ||
110
- Array.isArray(options) ||
111
- unexpected.length > 0 ||
112
- "systemProxyStateFile" in options) {
113
- throw new Error("SystemProxyManager requires an options object with layout and backend fields");
114
- }
88
+ constructor(options = {}) {
115
89
  this.layout = options.layout ?? sashLayout();
116
90
  this.backend = options.backend ?? createSystemProxyBackend();
117
91
  if (!this.layout.systemProxyStateFile) {
118
92
  throw new Error("System proxy journal requires a systemProxyStateFile path");
119
93
  }
120
- this.operationLockFile = `${this.layout.systemProxyStateFile}.lock`;
94
+ this.operationLockFile = this.layout.systemProxyLockFile;
121
95
  }
122
96
  apply(opts) {
97
+ this.pendingWrites += 1;
123
98
  this.invalidateInspection();
124
99
  return this.enqueue(async () => {
125
100
  try {
126
101
  await withStateLock(this.operationLockFile, { purpose: "apply system proxy", timeoutMs: 30_000 }, () => this.applyUnlocked(opts));
127
102
  }
128
103
  finally {
104
+ this.pendingWrites -= 1;
129
105
  this.invalidateInspection();
130
106
  }
131
107
  });
132
108
  }
133
109
  release() {
110
+ this.pendingWrites += 1;
134
111
  this.invalidateInspection();
135
112
  return this.enqueue(async () => {
136
113
  try {
137
114
  await withStateLock(this.operationLockFile, { purpose: "restore system proxy", timeoutMs: 30_000 }, () => this.recoverUnlocked());
138
115
  }
139
116
  finally {
117
+ this.pendingWrites -= 1;
140
118
  this.invalidateInspection();
141
119
  }
142
120
  });
143
121
  }
144
122
  inspect(fresh = false) {
123
+ if (this.pendingWrites > 0) {
124
+ return Promise.resolve({
125
+ applied: false,
126
+ appliedKnown: false,
127
+ stateKnown: false,
128
+ state: this.inspectionCache?.inspection.state ?? {
129
+ supported: this.backend.supported ?? isSystemProxySupported(),
130
+ enabled: false,
131
+ },
132
+ queryError: "System proxy change is in progress",
133
+ });
134
+ }
145
135
  const generation = this.inspectionGeneration;
146
136
  if (!fresh &&
147
137
  this.inspectionCache?.generation === generation &&
@@ -268,6 +258,21 @@ export class SystemProxyManager {
268
258
  };
269
259
  }
270
260
  async inspectUncached() {
261
+ if (this.backend.supported === false) {
262
+ return {
263
+ journalStable: true,
264
+ inspection: {
265
+ applied: false,
266
+ appliedKnown: true,
267
+ stateKnown: true,
268
+ state: {
269
+ supported: false,
270
+ enabled: false,
271
+ details: "System proxy integration is available on Windows only",
272
+ },
273
+ },
274
+ };
275
+ }
271
276
  const first = await this.inspectAttempt();
272
277
  return first.journalStable ? first : this.inspectAttempt();
273
278
  }
@@ -371,9 +376,6 @@ export class SystemProxyManager {
371
376
  }
372
377
  const original = await this.captureCurrent();
373
378
  const target = parseSystemProxySnapshot(this.backend.createTarget(original, opts));
374
- if (!journalSnapshotsHaveSameStructure(original, target)) {
375
- throw new Error("System proxy backend produced a target with a different platform structure");
376
- }
377
379
  const prepared = {
378
380
  schemaVersion: 2,
379
381
  phase: "prepared",
@@ -1 +1 @@
1
- import{d as Q,w as M,o as u,c as p,a as c,b as Z,e as o,I as m,f as J,u as a,t as s,v as R,g as i,h as x,s as T,P as W,n as y,F as B,r as N,i as D,j as F,k as X,l as Y,m as tt,E as et,p as h,q as _,x as at,y as A,z as H,A as st,B as ot,_ as nt}from"./index-B61V60w_.js";import{P as lt}from"./PaginationFooter-B3kHzRfB.js";const it={class:"connections-view"},ct={class:"search-box connection-search"},rt=["aria-label","placeholder"],ut={class:"connection-totals mono"},dt={class:"connections-control"},pt=["aria-label"],mt=["title"],vt=["title"],ht=["title"],_t=["title"],ft={class:"control-actions"},gt=["disabled"],bt={class:"connection-list"},yt={class:"connection-main"},wt=["title"],Ct={class:"connection-tags"},kt={class:"connection-tag tag-network"},Pt=["title"],xt=["title"],Tt={class:"connection-tag tag-time"},At={class:"connection-tag tag-traffic mono"},zt=["aria-label","title","onClick"],I=80,Bt=Q({__name:"ConnectionsView",setup(Dt){const w=h(""),v=h(1),d=h("time"),f=h(!0),r=h(!1),g=h([]);function L(){r.value||(g.value=[...T.connections]),r.value=!r.value}function C(e){d.value===e?f.value=!f.value:(d.value=e,f.value=!0)}function k(e){return{active:d.value===e,reverse:d.value===e&&!f.value}}const b=_(()=>r.value?g.value:T.connections);function O(e,n){const t=l=>!!l?.toLowerCase().includes(n);return t(e.metadata.host)||t(e.metadata.destinationIP)||t(e.metadata.sourceIP)||t(e.metadata.processPath)||t(e.metadata.network)||t(e.rule)||t(e.rulePayload)||e.chains.some(l=>t(l))}const P=_(()=>{const e=w.value.trim().toLowerCase(),n=e?b.value.filter(l=>O(l,e)):[...b.value],t=l=>d.value==="upload"?l.upload:d.value==="download"?l.download:d.value==="host"?z(l):l.start;return n.map(l=>({connection:l,key:t(l)})).sort((l,E)=>{const U=l.key<E.key?-1:l.key>E.key?1:0;return f.value?-U:U}).map(l=>l.connection)}),S=_(()=>Math.max(1,Math.ceil(P.value.length/I))),V=_(()=>(v.value-1)*I),q=_(()=>Math.min(V.value+I,P.value.length)),j=_(()=>P.value.slice(V.value,q.value));M(w,()=>{v.value=1}),M(S,e=>{v.value=Math.min(v.value,e)},{immediate:!0});function z(e){return e.metadata.host?e.metadata.host:`${e.metadata.destinationIP}:${e.metadata.destinationPort}`}function $(e){const n=e.metadata.processPath;return n?n.split(/[\\/]/).pop()??n:"-"}async function G(e){try{await at(e),r.value&&(g.value=g.value.filter(n=>n.id!==e)),A.success(s("toast.connClosed"))}catch(n){A.error(s("toast.failed",{msg:H(n)}))}}async function K(){const e=b.value.length;if(await st({title:s("connections.closeAll"),message:s("connections.closeAllConfirm",{n:e}),confirmText:s("common.confirm"),cancelText:s("common.cancel"),danger:!0}))try{await ot(),g.value=[],A.success(s("toast.connAllClosed"))}catch(t){A.error(s("toast.failed",{msg:H(t)}))}}return(e,n)=>(u(),p("div",it,[c(W,{title:a(s)("page.connections.title")},{default:Z(()=>[o("div",ct,[c(m,{name:"search",size:13}),J(o("input",{"onUpdate:modelValue":n[0]||(n[0]=t=>w.value=t),type:"search","aria-label":a(s)("connections.searchPlaceholder"),placeholder:a(s)("connections.searchPlaceholder")},null,8,rt),[[R,w.value]])]),o("div",ut,i(a(s)("connections.totalShort",{up:a(x)(a(T).connectionsUploadTotal),down:a(x)(a(T).connectionsDownloadTotal)})),1)]),_:1},8,["title"]),o("div",dt,[o("div",{class:"sort-labels",role:"toolbar","aria-label":a(s)("connections.colAction")},[o("button",{type:"button",class:y(["sort-label-btn",k("time")]),title:a(s)("connections.sortTime"),onClick:n[1]||(n[1]=t=>C("time"))},[c(m,{name:"timer",size:13}),o("span",null,i(a(s)("connections.sortTime")),1)],10,mt),o("button",{type:"button",class:y(["sort-label-btn",k("upload")]),title:a(s)("connections.sortUpload"),onClick:n[2]||(n[2]=t=>C("upload"))},[c(m,{name:"upload",size:13}),o("span",null,i(a(s)("connections.sortUpload")),1)],10,vt),o("button",{type:"button",class:y(["sort-label-btn",k("download")]),title:a(s)("connections.sortDownload"),onClick:n[3]||(n[3]=t=>C("download"))},[c(m,{name:"download",size:13}),o("span",null,i(a(s)("connections.sortDownload")),1)],10,ht),o("button",{type:"button",class:y(["sort-label-btn",k("host")]),title:a(s)("connections.sortHost"),onClick:n[4]||(n[4]=t=>C("host"))},[c(m,{name:"monitor",size:13}),o("span",null,i(a(s)("connections.sortHost")),1)],10,_t)],8,pt),o("div",ft,[o("button",{type:"button",class:y(["btn btn-sm btn-pause",{"btn-paused":r.value}]),onClick:L},[c(m,{name:r.value?"play":"pause",size:13},null,8,["name"]),o("span",null,i(r.value?a(s)("connections.resume"):a(s)("connections.pause")),1)],2),o("button",{type:"button",class:"btn btn-sm btn-danger",disabled:b.value.length===0,onClick:K},i(a(s)("connections.closeAll"))+" ("+i(b.value.length)+") ",9,gt)])]),o("div",bt,[(u(!0),p(B,null,N(j.value,t=>(u(),p("article",{key:t.id,class:"connection-row"},[o("div",yt,[o("div",{class:"connection-host mono",title:z(t)},i(z(t)),9,wt),o("div",Ct,[o("span",kt,i(t.metadata.network.toUpperCase()),1),$(t)!=="-"?(u(),p("span",{key:0,class:"connection-tag tag-process",title:t.metadata.processPath},i($(t)),9,Pt)):D("",!0),(u(!0),p(B,null,N(t.chains,l=>(u(),p("span",{key:l,class:"connection-tag tag-chain"},i(l),1))),128)),o("span",{class:"connection-tag tag-rule",title:t.rulePayload},[F(i(t.rule||"-"),1),t.rulePayload?(u(),p(B,{key:0},[F(","+i(t.rulePayload),1)],64)):D("",!0)],8,xt),o("span",Tt,i(a(X)(t.start,a(Y))),1),o("span",At," ↑"+i(a(x)(t.upload))+" ↓"+i(a(x)(t.download)),1)])]),o("button",{type:"button",class:"connection-close","aria-label":a(s)("connections.closeTitle"),title:a(s)("connections.closeTitle"),onClick:l=>G(t.id)},[c(m,{name:"x",size:18})],8,zt)]))),128)),P.value.length===0?(u(),tt(et,{key:0,icon:"swap",title:a(s)("connections.empty")},null,8,["title"])):D("",!0)]),c(lt,{page:v.value,"onUpdate:page":n[5]||(n[5]=t=>v.value=t),pages:S.value},null,8,["page","pages"])]))}}),Vt=nt(Bt,[["__scopeId","data-v-12653872"]]);export{Vt as default};
1
+ import{d as Q,w as M,o as u,c as p,a as c,b as Z,e as o,I as m,f as J,u as a,t as s,v as R,g as i,h as x,s as T,P as W,n as y,F as B,r as N,i as D,j as F,k as X,l as Y,m as tt,E as et,p as h,q as _,x as at,y as A,z as H,A as st,B as ot,_ as nt}from"./index-CBInDvdJ.js";import{P as lt}from"./PaginationFooter-cj1tcZej.js";const it={class:"connections-view"},ct={class:"search-box connection-search"},rt=["aria-label","placeholder"],ut={class:"connection-totals mono"},dt={class:"connections-control"},pt=["aria-label"],mt=["title"],vt=["title"],ht=["title"],_t=["title"],ft={class:"control-actions"},gt=["disabled"],bt={class:"connection-list"},yt={class:"connection-main"},wt=["title"],Ct={class:"connection-tags"},kt={class:"connection-tag tag-network"},Pt=["title"],xt=["title"],Tt={class:"connection-tag tag-time"},At={class:"connection-tag tag-traffic mono"},zt=["aria-label","title","onClick"],I=80,Bt=Q({__name:"ConnectionsView",setup(Dt){const w=h(""),v=h(1),d=h("time"),f=h(!0),r=h(!1),g=h([]);function L(){r.value||(g.value=[...T.connections]),r.value=!r.value}function C(e){d.value===e?f.value=!f.value:(d.value=e,f.value=!0)}function k(e){return{active:d.value===e,reverse:d.value===e&&!f.value}}const b=_(()=>r.value?g.value:T.connections);function O(e,n){const t=l=>!!l?.toLowerCase().includes(n);return t(e.metadata.host)||t(e.metadata.destinationIP)||t(e.metadata.sourceIP)||t(e.metadata.processPath)||t(e.metadata.network)||t(e.rule)||t(e.rulePayload)||e.chains.some(l=>t(l))}const P=_(()=>{const e=w.value.trim().toLowerCase(),n=e?b.value.filter(l=>O(l,e)):[...b.value],t=l=>d.value==="upload"?l.upload:d.value==="download"?l.download:d.value==="host"?z(l):l.start;return n.map(l=>({connection:l,key:t(l)})).sort((l,E)=>{const U=l.key<E.key?-1:l.key>E.key?1:0;return f.value?-U:U}).map(l=>l.connection)}),S=_(()=>Math.max(1,Math.ceil(P.value.length/I))),V=_(()=>(v.value-1)*I),q=_(()=>Math.min(V.value+I,P.value.length)),j=_(()=>P.value.slice(V.value,q.value));M(w,()=>{v.value=1}),M(S,e=>{v.value=Math.min(v.value,e)},{immediate:!0});function z(e){return e.metadata.host?e.metadata.host:`${e.metadata.destinationIP}:${e.metadata.destinationPort}`}function $(e){const n=e.metadata.processPath;return n?n.split(/[\\/]/).pop()??n:"-"}async function G(e){try{await at(e),r.value&&(g.value=g.value.filter(n=>n.id!==e)),A.success(s("toast.connClosed"))}catch(n){A.error(s("toast.failed",{msg:H(n)}))}}async function K(){const e=b.value.length;if(await st({title:s("connections.closeAll"),message:s("connections.closeAllConfirm",{n:e}),confirmText:s("common.confirm"),cancelText:s("common.cancel"),danger:!0}))try{await ot(),g.value=[],A.success(s("toast.connAllClosed"))}catch(t){A.error(s("toast.failed",{msg:H(t)}))}}return(e,n)=>(u(),p("div",it,[c(W,{title:a(s)("page.connections.title")},{default:Z(()=>[o("div",ct,[c(m,{name:"search",size:13}),J(o("input",{"onUpdate:modelValue":n[0]||(n[0]=t=>w.value=t),type:"search","aria-label":a(s)("connections.searchPlaceholder"),placeholder:a(s)("connections.searchPlaceholder")},null,8,rt),[[R,w.value]])]),o("div",ut,i(a(s)("connections.totalShort",{up:a(x)(a(T).connectionsUploadTotal),down:a(x)(a(T).connectionsDownloadTotal)})),1)]),_:1},8,["title"]),o("div",dt,[o("div",{class:"sort-labels",role:"toolbar","aria-label":a(s)("connections.colAction")},[o("button",{type:"button",class:y(["sort-label-btn",k("time")]),title:a(s)("connections.sortTime"),onClick:n[1]||(n[1]=t=>C("time"))},[c(m,{name:"timer",size:13}),o("span",null,i(a(s)("connections.sortTime")),1)],10,mt),o("button",{type:"button",class:y(["sort-label-btn",k("upload")]),title:a(s)("connections.sortUpload"),onClick:n[2]||(n[2]=t=>C("upload"))},[c(m,{name:"upload",size:13}),o("span",null,i(a(s)("connections.sortUpload")),1)],10,vt),o("button",{type:"button",class:y(["sort-label-btn",k("download")]),title:a(s)("connections.sortDownload"),onClick:n[3]||(n[3]=t=>C("download"))},[c(m,{name:"download",size:13}),o("span",null,i(a(s)("connections.sortDownload")),1)],10,ht),o("button",{type:"button",class:y(["sort-label-btn",k("host")]),title:a(s)("connections.sortHost"),onClick:n[4]||(n[4]=t=>C("host"))},[c(m,{name:"monitor",size:13}),o("span",null,i(a(s)("connections.sortHost")),1)],10,_t)],8,pt),o("div",ft,[o("button",{type:"button",class:y(["btn btn-sm btn-pause",{"btn-paused":r.value}]),onClick:L},[c(m,{name:r.value?"play":"pause",size:13},null,8,["name"]),o("span",null,i(r.value?a(s)("connections.resume"):a(s)("connections.pause")),1)],2),o("button",{type:"button",class:"btn btn-sm btn-danger",disabled:b.value.length===0,onClick:K},i(a(s)("connections.closeAll"))+" ("+i(b.value.length)+") ",9,gt)])]),o("div",bt,[(u(!0),p(B,null,N(j.value,t=>(u(),p("article",{key:t.id,class:"connection-row"},[o("div",yt,[o("div",{class:"connection-host mono",title:z(t)},i(z(t)),9,wt),o("div",Ct,[o("span",kt,i(t.metadata.network.toUpperCase()),1),$(t)!=="-"?(u(),p("span",{key:0,class:"connection-tag tag-process",title:t.metadata.processPath},i($(t)),9,Pt)):D("",!0),(u(!0),p(B,null,N(t.chains,l=>(u(),p("span",{key:l,class:"connection-tag tag-chain"},i(l),1))),128)),o("span",{class:"connection-tag tag-rule",title:t.rulePayload},[F(i(t.rule||"-"),1),t.rulePayload?(u(),p(B,{key:0},[F(","+i(t.rulePayload),1)],64)):D("",!0)],8,xt),o("span",Tt,i(a(X)(t.start,a(Y))),1),o("span",At," ↑"+i(a(x)(t.upload))+" ↓"+i(a(x)(t.download)),1)])]),o("button",{type:"button",class:"connection-close","aria-label":a(s)("connections.closeTitle"),title:a(s)("connections.closeTitle"),onClick:l=>G(t.id)},[c(m,{name:"x",size:18})],8,zt)]))),128)),P.value.length===0?(u(),tt(et,{key:0,icon:"swap",title:a(s)("connections.empty")},null,8,["title"])):D("",!0)]),c(lt,{page:v.value,"onUpdate:page":n[5]||(n[5]=t=>v.value=t),pages:S.value},null,8,["page","pages"])]))}}),Vt=nt(Bt,[["__scopeId","data-v-12653872"]]);export{Vt as default};
@@ -1 +1 @@
1
- import{d as A,w as D,s as i,C as I,D as N,o as c,c as u,a as b,b as U,e as n,I as w,f as L,u as a,t as s,v as q,F as C,r as k,g as d,G as z,H as x,P as R,i as V,n as S,q as B,p as v,J as G,_ as E}from"./index-B61V60w_.js";const J={class:"logs-view"},Q={class:"search-box logs-search"},$=["aria-label","placeholder"],j=["aria-label"],K=["value"],O=["disabled"],W=["aria-pressed"],X=["aria-label"],Y={key:0,class:"log-empty text-muted"},Z={class:"log-payload"},ee={key:0,class:"log-time mono"},le=A({__name:"LogsView",setup(ae){const F=["all","info","warning","error","debug"],T=B(()=>{const l={rule:s("overview.modeRule"),global:s("overview.modeGlobal"),direct:s("overview.modeDirect")};return s("logs.modeLabel",{mode:l[i.mode]??i.mode})}),m=v("all"),g=v(""),t=v(!1),f=v(null),p=v(!0);let r=null,_=!1;const y=B(()=>{const l=g.value.trim().toLowerCase();return i.logs.filter(o=>(m.value==="all"||o.type.toLowerCase()===m.value)&&(!l||o.payload.toLowerCase().includes(l)))});function H(l){const o=l.toLowerCase();return o==="error"?"alert":o==="warning"?"info":o==="debug"?"terminal":"check-circle"}function M(){const l=f.value;l&&(p.value=l.scrollHeight-l.scrollTop-l.clientHeight<40)}async function h(){await G(),!(_||t.value||!p.value)&&(r!==null&&cancelAnimationFrame(r),r=requestAnimationFrame(()=>{r=null;const l=f.value;l&&!_&&!t.value&&p.value&&(l.scrollTop=l.scrollHeight)}))}function P(){t.value=!t.value,t.value||h()}return D(()=>i.logs.at(-1)?.id,()=>{!t.value&&p.value&&h()}),I(()=>{h()}),N(()=>{_=!0,r!==null&&cancelAnimationFrame(r)}),(l,o)=>(c(),u("div",J,[b(R,{title:a(s)("page.logs.title"),desc:T.value},{default:U(()=>[n("div",Q,[b(w,{name:"search",size:13}),L(n("input",{"onUpdate:modelValue":o[0]||(o[0]=e=>g.value=e),type:"search","aria-label":a(s)("logs.searchPlaceholder"),placeholder:a(s)("logs.searchPlaceholder")},null,8,$),[[q,g.value]])]),L(n("select",{"onUpdate:modelValue":o[1]||(o[1]=e=>m.value=e),class:"input input-sm level-select","aria-label":a(s)("logs.levelLabel")},[(c(),u(C,null,k(F,e=>n("option",{key:e,value:e},d(e==="all"?a(s)("logs.levelAll"):e.toUpperCase()),9,K)),64))],8,j),[[z,m.value]]),n("button",{type:"button",class:"btn btn-sm log-clear",disabled:a(i).logs.length===0,onClick:o[2]||(o[2]=(...e)=>a(x)&&a(x)(...e))},d(a(s)("common.clear")),9,O),n("button",{type:"button",class:"btn btn-sm log-pause","aria-pressed":t.value,onClick:P},d(t.value?a(s)("logs.resume"):a(s)("logs.pause")),9,W)]),_:1},8,["title","desc"]),n("div",{ref_key:"paneRef",ref:f,class:"log-pane",role:"log",tabindex:"0","aria-live":"off","aria-atomic":"false","aria-label":a(s)("page.logs.title"),onScroll:M},[y.value.length===0?(c(),u("div",Y,d(a(i).logs.length===0?a(s)("logs.listening"):a(s)("logs.empty")),1)):V("",!0),(c(!0),u(C,null,k(y.value,e=>(c(),u("div",{key:e.id,class:S(["log-line",`lv-${e.type.toLowerCase()}`])},[b(w,{name:H(e.type),size:13,class:"log-icon"},null,8,["name"]),n("span",Z,d(e.payload),1),e.time?(c(),u("span",ee,d(e.time),1)):V("",!0)],2))),128))],40,X)]))}}),oe=E(le,[["__scopeId","data-v-a97e5fe8"]]);export{oe as default};
1
+ import{d as A,w as D,s as i,C as I,D as N,o as c,c as u,a as b,b as U,e as n,I as w,f as L,u as a,t as s,v as q,F as C,r as k,g as d,G as z,H as x,P as R,i as V,n as S,q as B,p as v,J as G,_ as E}from"./index-CBInDvdJ.js";const J={class:"logs-view"},Q={class:"search-box logs-search"},$=["aria-label","placeholder"],j=["aria-label"],K=["value"],O=["disabled"],W=["aria-pressed"],X=["aria-label"],Y={key:0,class:"log-empty text-muted"},Z={class:"log-payload"},ee={key:0,class:"log-time mono"},le=A({__name:"LogsView",setup(ae){const F=["all","info","warning","error","debug"],T=B(()=>{const l={rule:s("overview.modeRule"),global:s("overview.modeGlobal"),direct:s("overview.modeDirect")};return s("logs.modeLabel",{mode:l[i.mode]??i.mode})}),m=v("all"),g=v(""),t=v(!1),f=v(null),p=v(!0);let r=null,_=!1;const y=B(()=>{const l=g.value.trim().toLowerCase();return i.logs.filter(o=>(m.value==="all"||o.type.toLowerCase()===m.value)&&(!l||o.payload.toLowerCase().includes(l)))});function H(l){const o=l.toLowerCase();return o==="error"?"alert":o==="warning"?"info":o==="debug"?"terminal":"check-circle"}function M(){const l=f.value;l&&(p.value=l.scrollHeight-l.scrollTop-l.clientHeight<40)}async function h(){await G(),!(_||t.value||!p.value)&&(r!==null&&cancelAnimationFrame(r),r=requestAnimationFrame(()=>{r=null;const l=f.value;l&&!_&&!t.value&&p.value&&(l.scrollTop=l.scrollHeight)}))}function P(){t.value=!t.value,t.value||h()}return D(()=>i.logs.at(-1)?.id,()=>{!t.value&&p.value&&h()}),I(()=>{h()}),N(()=>{_=!0,r!==null&&cancelAnimationFrame(r)}),(l,o)=>(c(),u("div",J,[b(R,{title:a(s)("page.logs.title"),desc:T.value},{default:U(()=>[n("div",Q,[b(w,{name:"search",size:13}),L(n("input",{"onUpdate:modelValue":o[0]||(o[0]=e=>g.value=e),type:"search","aria-label":a(s)("logs.searchPlaceholder"),placeholder:a(s)("logs.searchPlaceholder")},null,8,$),[[q,g.value]])]),L(n("select",{"onUpdate:modelValue":o[1]||(o[1]=e=>m.value=e),class:"input input-sm level-select","aria-label":a(s)("logs.levelLabel")},[(c(),u(C,null,k(F,e=>n("option",{key:e,value:e},d(e==="all"?a(s)("logs.levelAll"):e.toUpperCase()),9,K)),64))],8,j),[[z,m.value]]),n("button",{type:"button",class:"btn btn-sm log-clear",disabled:a(i).logs.length===0,onClick:o[2]||(o[2]=(...e)=>a(x)&&a(x)(...e))},d(a(s)("common.clear")),9,O),n("button",{type:"button",class:"btn btn-sm log-pause","aria-pressed":t.value,onClick:P},d(t.value?a(s)("logs.resume"):a(s)("logs.pause")),9,W)]),_:1},8,["title","desc"]),n("div",{ref_key:"paneRef",ref:f,class:"log-pane",role:"log",tabindex:"0","aria-live":"off","aria-atomic":"false","aria-label":a(s)("page.logs.title"),onScroll:M},[y.value.length===0?(c(),u("div",Y,d(a(i).logs.length===0?a(s)("logs.listening"):a(s)("logs.empty")),1)):V("",!0),(c(!0),u(C,null,k(y.value,e=>(c(),u("div",{key:e.id,class:S(["log-line",`lv-${e.type.toLowerCase()}`])},[b(w,{name:H(e.type),size:13,class:"log-icon"},null,8,["name"]),n("span",Z,d(e.payload),1),e.time?(c(),u("span",ee,d(e.time),1)):V("",!0)],2))),128))],40,X)]))}}),oe=E(le,[["__scopeId","data-v-a97e5fe8"]]);export{oe as default};
@@ -1 +1 @@
1
- import{d as c,a5 as r,o as l,c as p,e as o,g as s,u as n,t as i,i as m,a6 as u,_ as g}from"./index-B61V60w_.js";const b={key:0,class:"pagination-footer"},_={class:"pagination-summary"},v={class:"pagination-actions"},f=["disabled"],y=["disabled"],k=c({__name:"PaginationFooter",props:u({pages:{}},{page:{required:!0},pageModifiers:{}}),emits:["update:page"],setup(t){const e=r(t,"page");return(x,a)=>t.pages>1?(l(),p("footer",b,[o("span",_,s(n(i)("common.pageSummary",{page:e.value,total:t.pages})),1),o("div",v,[o("button",{type:"button",class:"btn btn-secondary btn-sm",disabled:e.value===1,onClick:a[0]||(a[0]=d=>e.value-=1)},s(n(i)("common.previous")),9,f),o("button",{type:"button",class:"btn btn-secondary btn-sm",disabled:e.value===t.pages,onClick:a[1]||(a[1]=d=>e.value+=1)},s(n(i)("common.next")),9,y)])])):m("",!0)}}),B=g(k,[["__scopeId","data-v-c2140dca"]]);export{B as P};
1
+ import{d as c,a6 as r,o as l,c as p,e as o,g as s,u as n,t as i,i as m,a7 as u,_ as g}from"./index-CBInDvdJ.js";const b={key:0,class:"pagination-footer"},_={class:"pagination-summary"},v={class:"pagination-actions"},f=["disabled"],y=["disabled"],k=c({__name:"PaginationFooter",props:u({pages:{}},{page:{required:!0},pageModifiers:{}}),emits:["update:page"],setup(t){const e=r(t,"page");return(x,a)=>t.pages>1?(l(),p("footer",b,[o("span",_,s(n(i)("common.pageSummary",{page:e.value,total:t.pages})),1),o("div",v,[o("button",{type:"button",class:"btn btn-secondary btn-sm",disabled:e.value===1,onClick:a[0]||(a[0]=d=>e.value-=1)},s(n(i)("common.previous")),9,f),o("button",{type:"button",class:"btn btn-secondary btn-sm",disabled:e.value===t.pages,onClick:a[1]||(a[1]=d=>e.value+=1)},s(n(i)("common.next")),9,y)])])):m("",!0)}}),B=g(k,[["__scopeId","data-v-c2140dca"]]);export{B as P};
@@ -0,0 +1 @@
1
+ .editor-overlay[data-v-be7c4f1f]{position:fixed;inset:0;z-index:var(--z-dialog);display:flex;padding:26px;background:var(--bg-scrim)}.editor-dialog[data-v-be7c4f1f]{display:flex;width:100%;min-height:0;flex:1;flex-direction:column;overflow:hidden;background:var(--bg-elevated);border-radius:var(--radius-md);box-shadow:var(--shadow-pop)}.editor-dialog-constrained[data-v-be7c4f1f]{max-width:720px;max-height:100%;margin:auto;flex:0 1 auto}.editor-head[data-v-be7c4f1f]{display:flex;min-height:46px;align-items:center;gap:12px;padding:6px 10px 6px 16px;border-bottom:1px solid var(--border)}.editor-name[data-v-be7c4f1f]{min-width:0;overflow:hidden;color:var(--text-primary);font-size:16px;font-weight:600;text-overflow:ellipsis;white-space:nowrap}.editor-hint[data-v-be7c4f1f]{min-width:0;flex:1;overflow:hidden;color:var(--warning);font-size:14px;text-overflow:ellipsis;white-space:nowrap}.editor-actions[data-v-be7c4f1f]{display:flex;flex-shrink:0;gap:8px;margin-left:auto}.editor-error[data-v-be7c4f1f]{padding:18px 20px;color:var(--danger);font-size:16px}.editor-host[data-v-be7c4f1f]{position:relative;min-height:0;flex:1;overflow:hidden}.editor-host-constrained[data-v-be7c4f1f]{min-height:320px}.editor-loading[data-v-be7c4f1f]{position:absolute;top:12px;left:16px;color:var(--text-muted);font-size:16px}.editor-host[data-v-be7c4f1f] .cm-editor{height:100%;font-size:16px}.editor-host[data-v-be7c4f1f] .cm-editor .cm-scroller{font-family:var(--font-mono)}.editor-host[data-v-be7c4f1f] .cm-editor.cm-focused{outline:none}@media(max-width:640px){.editor-overlay[data-v-be7c4f1f]{padding:0}.editor-dialog[data-v-be7c4f1f]{border-radius:0}.editor-dialog-constrained[data-v-be7c4f1f]{max-width:none}.editor-hint[data-v-be7c4f1f]{display:none}}