@hoox-sh/hoox-shared 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/agent-config-fields.d.ts +5 -0
  2. package/dist/agent-config-fields.d.ts.map +1 -1
  3. package/dist/analytics.d.ts.map +1 -1
  4. package/dist/analytics.js +8 -3
  5. package/dist/config.d.ts +10 -2
  6. package/dist/config.d.ts.map +1 -1
  7. package/dist/config.js +256 -24
  8. package/dist/errors.d.ts +1 -0
  9. package/dist/errors.d.ts.map +1 -1
  10. package/dist/exchange-client.d.ts +0 -19
  11. package/dist/exchange-client.d.ts.map +1 -1
  12. package/dist/exchange-client.js +0 -66
  13. package/dist/exchanges/base-exchange-client.d.ts.map +1 -1
  14. package/dist/exchanges/base-exchange-client.js +4 -3
  15. package/dist/exchanges/index.js +4 -3
  16. package/dist/index.d.ts +2 -3
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +293 -604
  19. package/dist/middleware/auth.d.ts +9 -0
  20. package/dist/middleware/auth.d.ts.map +1 -1
  21. package/dist/middleware/index.js +3 -2
  22. package/dist/middleware/logger.d.ts +2 -0
  23. package/dist/middleware/logger.d.ts.map +1 -1
  24. package/dist/middleware/rate-limit.d.ts +7 -0
  25. package/dist/middleware/rate-limit.d.ts.map +1 -1
  26. package/dist/middleware/rate-limit.js +3 -2
  27. package/dist/middleware/validate.d.ts +2 -0
  28. package/dist/middleware/validate.d.ts.map +1 -1
  29. package/dist/path-utils.d.ts.map +1 -1
  30. package/dist/path-utils.js +13 -3
  31. package/dist/queue-handler.d.ts.map +1 -1
  32. package/dist/queue-handler.js +19 -8
  33. package/dist/router.d.ts +5 -0
  34. package/dist/router.d.ts.map +1 -1
  35. package/dist/schemas/index.js +40 -23
  36. package/dist/schemas/registry.d.ts.map +1 -1
  37. package/dist/schemas/registry.js +4 -1
  38. package/dist/schemas/validators.d.ts.map +1 -1
  39. package/dist/schemas/validators.js +36 -22
  40. package/dist/service-bindings.d.ts +4 -0
  41. package/dist/service-bindings.d.ts.map +1 -1
  42. package/dist/session.d.ts +10 -3
  43. package/dist/session.d.ts.map +1 -1
  44. package/dist/session.js +109 -33
  45. package/dist/sse.d.ts.map +1 -1
  46. package/dist/sse.js +24 -6
  47. package/dist/stores/config-store.d.ts +2 -50
  48. package/dist/stores/config-store.d.ts.map +1 -1
  49. package/dist/stores/config-store.js +145 -134
  50. package/dist/stores/service-store.d.ts +2 -192
  51. package/dist/stores/service-store.d.ts.map +1 -1
  52. package/dist/stores/service-store.js +24 -6
  53. package/dist/stores/ui-store.d.ts +2 -48
  54. package/dist/stores/ui-store.d.ts.map +1 -1
  55. package/dist/tenant.d.ts +1 -0
  56. package/dist/tenant.d.ts.map +1 -1
  57. package/dist/types.d.ts +6 -1
  58. package/dist/types.d.ts.map +1 -1
  59. package/dist/types.js +19 -0
  60. package/dist/wizard/engine.d.ts.map +1 -1
  61. package/dist/wizard/engine.js +13 -7
  62. package/dist/wizard/index.js +13 -7
  63. package/dist/wizard/presets.js +3 -3
  64. package/package.json +1 -1
@@ -8,144 +8,49 @@ import { join as join3 } from "path";
8
8
 
9
9
  // src/config.ts
10
10
  import {
11
- readFileSync,
12
- writeFileSync,
13
- existsSync,
14
- mkdirSync,
15
- chmodSync,
11
+ readFileSync as readFileSync2,
12
+ writeFileSync as writeFileSync2,
13
+ existsSync as existsSync2,
14
+ mkdirSync as mkdirSync2,
15
+ chmodSync as chmodSync2,
16
16
  statSync
17
17
  } from "fs";
18
- import { join } from "path";
19
- import { homedir } from "os";
20
- var HOX_DIR = join(homedir(), ".hoox");
21
- var CONFIG_PATH = join(HOX_DIR, "config.json");
22
- var HOOX_DIR_MODE = 448;
23
- var HOOX_CONFIG_FILE_MODE = 384;
24
- var DEFAULT_CONFIG = {
25
- apiUrl: "http://localhost:8787",
26
- apiToken: "",
27
- transport: "public",
28
- refreshIntervalMs: 500,
29
- theme: "dark",
30
- activeExchanges: ["binance", "bybit", "mexc"],
31
- notifications: {
32
- alerts: true,
33
- trades: true,
34
- debug: false,
35
- system: true
36
- },
37
- soundEnabled: true,
38
- defaultView: "dashboard"
39
- };
40
- function readConfigSync() {
41
- const envConfig = {
42
- apiUrl: process.env.HOOX_API_URL,
43
- apiToken: process.env.HOOX_API_TOKEN
44
- };
45
- let fileConfig = {};
46
- try {
47
- if (existsSync(CONFIG_PATH)) {
48
- fileConfig = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
49
- }
50
- } catch {}
51
- return {
52
- ...DEFAULT_CONFIG,
53
- ...fileConfig,
54
- ...Object.fromEntries(Object.entries(envConfig).filter(([_, v]) => v !== undefined))
55
- };
56
- }
57
- async function readConfig() {
58
- return readConfigSync();
59
- }
60
- function ensureHooxDirSecure(dir = HOX_DIR) {
61
- if (!existsSync(dir)) {
62
- mkdirSync(dir, { recursive: true, mode: HOOX_DIR_MODE });
63
- }
64
- try {
65
- chmodSync(dir, HOOX_DIR_MODE);
66
- } catch {}
67
- }
68
- function writeSecureFileSync(filePath, contents, mode = HOOX_CONFIG_FILE_MODE) {
69
- writeFileSync(filePath, contents, { encoding: "utf-8", mode });
70
- try {
71
- chmodSync(filePath, mode);
72
- } catch {}
73
- }
74
- function isUnixModeGroupOrWorldAccessible(mode) {
75
- return (mode & 63) !== 0;
76
- }
77
- function isConfigWorldOrGroupReadable(filePath = CONFIG_PATH) {
78
- try {
79
- if (!existsSync(filePath))
80
- return false;
81
- return isUnixModeGroupOrWorldAccessible(statSync(filePath).mode & 511);
82
- } catch {
83
- return false;
84
- }
85
- }
86
- function formatConfigPermissionWarning(filePath = CONFIG_PATH) {
87
- if (!isConfigWorldOrGroupReadable(filePath))
88
- return null;
89
- return `Warning: ${filePath} is group/world-accessible. ` + `Run: chmod 600 ${filePath} (and chmod 700 on the parent dir). ` + `This file may contain apiToken / operator secrets.`;
90
- }
91
- function writeConfigSync(config) {
92
- try {
93
- ensureHooxDirSecure(HOX_DIR);
94
- writeSecureFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), HOOX_CONFIG_FILE_MODE);
95
- } catch (err) {
96
- console.error("Failed to write config:", err);
97
- }
98
- }
99
- async function writeConfig(config) {
100
- writeConfigSync(config);
101
- }
102
- var VALID_TRANSPORTS = new Set([
103
- "public",
104
- "access",
105
- "mtls",
106
- "tunnel"
107
- ]);
108
- function validateConfig(config) {
109
- const errors = [];
110
- if (config.apiUrl && !config.apiUrl.startsWith("http")) {
111
- errors.push("apiUrl must start with http:// or https://");
112
- }
113
- if (config.refreshIntervalMs !== undefined && config.refreshIntervalMs < 100) {
114
- errors.push("refreshIntervalMs must be >= 100ms");
115
- }
116
- if (config.theme && !["dark", "light"].includes(config.theme)) {
117
- errors.push('theme must be "dark" or "light"');
118
- }
119
- if (config.transport !== undefined && !VALID_TRANSPORTS.has(config.transport)) {
120
- errors.push('transport must be "public" | "access" | "mtls" | "tunnel"');
121
- }
122
- return errors;
123
- }
18
+ import { join as join2 } from "path";
124
19
 
125
20
  // src/path-utils.ts
126
21
  import {
127
- existsSync as existsSync2,
128
- mkdirSync as mkdirSync2,
129
- readFileSync as readFileSync2,
130
- writeFileSync as writeFileSync2,
131
- chmodSync as chmodSync2
22
+ existsSync,
23
+ mkdirSync,
24
+ readFileSync,
25
+ writeFileSync,
26
+ chmodSync
132
27
  } from "fs";
133
- import { homedir as homedir2 } from "os";
134
- import { dirname, join as join2, resolve } from "path";
28
+ import { homedir } from "os";
29
+ import { dirname, join, resolve, sep } from "path";
135
30
  function createHooxPath(path) {
136
31
  return path;
137
32
  }
33
+ function isInsideDir(child, parent) {
34
+ const resolvedChild = resolve(child);
35
+ const resolvedParent = resolve(parent);
36
+ const cmpChild = process.platform === "win32" ? resolvedChild.toLowerCase() : resolvedChild;
37
+ const cmpParent = process.platform === "win32" ? resolvedParent.toLowerCase() : resolvedParent;
38
+ if (cmpChild === cmpParent)
39
+ return true;
40
+ const prefix = cmpParent.endsWith(sep) ? cmpParent : cmpParent + sep;
41
+ return cmpChild.startsWith(prefix);
42
+ }
138
43
  function getHooxHome() {
139
44
  try {
140
45
  const override = process.env.HOOX_HOME?.trim();
141
46
  if (override) {
142
47
  return createHooxPath(resolve(override));
143
48
  }
144
- const home = homedir2();
49
+ const home = homedir();
145
50
  if (!home || home.length === 0) {
146
51
  return createHooxPath(resolve(process.cwd(), ".hoox"));
147
52
  }
148
- return createHooxPath(join2(home, ".hoox"));
53
+ return createHooxPath(join(home, ".hoox"));
149
54
  } catch {
150
55
  return createHooxPath(resolve(process.cwd(), ".hoox"));
151
56
  }
@@ -155,10 +60,10 @@ function isHooxSetupRoot(dir) {
155
60
  return false;
156
61
  try {
157
62
  const root = resolve(dir);
158
- if (!existsSync2(join2(root, "packages", "cli", "package.json"))) {
63
+ if (!existsSync(join(root, "packages", "cli", "package.json"))) {
159
64
  return false;
160
65
  }
161
- return existsSync2(join2(root, "wrangler.jsonc")) || existsSync2(join2(root, "wrangler.jsonc.example")) || existsSync2(join2(root, "workers")) || existsSync2(join2(root, ".gitmodules"));
66
+ return existsSync(join(root, "wrangler.jsonc")) || existsSync(join(root, "wrangler.jsonc.example")) || existsSync(join(root, "workers")) || existsSync(join(root, ".gitmodules"));
162
67
  } catch {
163
68
  return false;
164
69
  }
@@ -169,9 +74,9 @@ function getRememberedMonorepoPath() {
169
74
  function getRememberedMonorepoRoot() {
170
75
  try {
171
76
  const path = getRememberedMonorepoPath();
172
- if (!existsSync2(path))
77
+ if (!existsSync(path))
173
78
  return null;
174
- const raw = readFileSync2(path, "utf-8");
79
+ const raw = readFileSync(path, "utf-8");
175
80
  const data = JSON.parse(raw);
176
81
  if (!data.root || typeof data.root !== "string")
177
82
  return null;
@@ -187,21 +92,21 @@ function rememberMonorepoRoot(root) {
187
92
  if (!isHooxSetupRoot(resolved))
188
93
  return false;
189
94
  const configDir = getHooxConfigDir();
190
- mkdirSync2(configDir, { recursive: true, mode: 448 });
95
+ mkdirSync(configDir, { recursive: true, mode: 448 });
191
96
  try {
192
- chmodSync2(configDir, 448);
97
+ chmodSync(configDir, 448);
193
98
  } catch {}
194
99
  const payload = {
195
100
  root: resolved,
196
101
  updatedAt: new Date().toISOString()
197
102
  };
198
103
  const path = getRememberedMonorepoPath();
199
- writeFileSync2(path, JSON.stringify(payload, null, 2) + `
104
+ writeFileSync(path, JSON.stringify(payload, null, 2) + `
200
105
  `, {
201
106
  mode: 384
202
107
  });
203
108
  try {
204
- chmodSync2(path, 384);
109
+ chmodSync(path, 384);
205
110
  } catch {}
206
111
  return true;
207
112
  } catch {
@@ -281,9 +186,9 @@ function resolveHooxRuntimeRoot(options) {
281
186
  function getTuiEntryCandidates(runtimeRoot) {
282
187
  const root = resolve(runtimeRoot);
283
188
  return [
284
- join2(root, "packages", "tui", "src", "main.tsx"),
285
- join2(root, "packages", "tui", "dist", "main.js"),
286
- join2(root, "packages", "tui", "src", "main.ts")
189
+ join(root, "packages", "tui", "src", "main.tsx"),
190
+ join(root, "packages", "tui", "dist", "main.js"),
191
+ join(root, "packages", "tui", "src", "main.ts")
287
192
  ];
288
193
  }
289
194
  function resolveHooxPath(relativePath) {
@@ -295,10 +200,10 @@ function resolveHooxPath(relativePath) {
295
200
  }
296
201
  const normalizedPath = relativePath.replace(/\\/g, "/");
297
202
  const hooxHome = getHooxHome();
298
- const fullPath = join2(hooxHome, normalizedPath);
203
+ const fullPath = join(hooxHome, normalizedPath);
299
204
  const resolvedPath = resolve(fullPath);
300
205
  const resolvedHome = resolve(hooxHome);
301
- if (!resolvedPath.startsWith(resolvedHome)) {
206
+ if (!isInsideDir(resolvedPath, resolvedHome)) {
302
207
  throw new Error(`Resolved path "${resolvedPath}" is outside Hoox home directory`);
303
208
  }
304
209
  return createHooxPath(resolvedPath);
@@ -308,7 +213,7 @@ function isWithinHooxHome(path) {
308
213
  const hooxHome = getHooxHome();
309
214
  const resolvedPath = resolve(path);
310
215
  const resolvedHome = resolve(hooxHome);
311
- return resolvedPath.startsWith(resolvedHome);
216
+ return isInsideDir(resolvedPath, resolvedHome);
312
217
  } catch {
313
218
  return false;
314
219
  }
@@ -343,6 +248,112 @@ function getHooxStatePath() {
343
248
  return resolveHooxPath("data/state.json");
344
249
  }
345
250
 
251
+ // src/config.ts
252
+ function hooxDir() {
253
+ return getHooxHome();
254
+ }
255
+ function configPath() {
256
+ return join2(hooxDir(), "config.json");
257
+ }
258
+ var HOOX_DIR_MODE = 448;
259
+ var HOOX_CONFIG_FILE_MODE = 384;
260
+ var DEFAULT_CONFIG = {
261
+ apiUrl: "http://localhost:8787",
262
+ apiToken: "",
263
+ transport: "public",
264
+ refreshIntervalMs: 500,
265
+ theme: "dark",
266
+ activeExchanges: ["binance", "bybit", "mexc"],
267
+ notifications: {
268
+ alerts: true,
269
+ trades: true,
270
+ debug: false,
271
+ system: true
272
+ },
273
+ soundEnabled: true,
274
+ defaultView: "dashboard"
275
+ };
276
+ function readConfigSync() {
277
+ const envConfig = {
278
+ apiUrl: process.env.HOOX_API_URL,
279
+ apiToken: process.env.HOOX_API_TOKEN
280
+ };
281
+ let fileConfig = {};
282
+ try {
283
+ if (existsSync2(configPath())) {
284
+ fileConfig = JSON.parse(readFileSync2(configPath(), "utf-8"));
285
+ }
286
+ } catch {}
287
+ return {
288
+ ...DEFAULT_CONFIG,
289
+ ...fileConfig,
290
+ ...Object.fromEntries(Object.entries(envConfig).filter(([_, v]) => v !== undefined))
291
+ };
292
+ }
293
+ async function readConfig() {
294
+ return readConfigSync();
295
+ }
296
+ function ensureHooxDirSecure(dir = hooxDir()) {
297
+ if (!existsSync2(dir)) {
298
+ mkdirSync2(dir, { recursive: true, mode: HOOX_DIR_MODE });
299
+ }
300
+ try {
301
+ chmodSync2(dir, HOOX_DIR_MODE);
302
+ } catch {}
303
+ }
304
+ function writeSecureFileSync(filePath, contents, mode = HOOX_CONFIG_FILE_MODE) {
305
+ writeFileSync2(filePath, contents, { encoding: "utf-8", mode });
306
+ try {
307
+ chmodSync2(filePath, mode);
308
+ } catch {}
309
+ }
310
+ function isUnixModeGroupOrWorldAccessible(mode) {
311
+ return (mode & 63) !== 0;
312
+ }
313
+ function isConfigWorldOrGroupReadable(filePath = configPath()) {
314
+ try {
315
+ if (!existsSync2(filePath))
316
+ return false;
317
+ return isUnixModeGroupOrWorldAccessible(statSync(filePath).mode & 511);
318
+ } catch {
319
+ return false;
320
+ }
321
+ }
322
+ function formatConfigPermissionWarning(filePath = configPath()) {
323
+ if (!isConfigWorldOrGroupReadable(filePath))
324
+ return null;
325
+ return `Warning: ${filePath} is group/world-accessible. ` + `Run: chmod 600 ${filePath} (and chmod 700 on the parent dir). ` + `This file may contain apiToken / operator secrets.`;
326
+ }
327
+ function writeConfigSync(config) {
328
+ ensureHooxDirSecure(hooxDir());
329
+ writeSecureFileSync(configPath(), JSON.stringify(config, null, 2), HOOX_CONFIG_FILE_MODE);
330
+ }
331
+ async function writeConfig(config) {
332
+ writeConfigSync(config);
333
+ }
334
+ var VALID_TRANSPORTS = new Set([
335
+ "public",
336
+ "access",
337
+ "mtls",
338
+ "tunnel"
339
+ ]);
340
+ function validateConfig(config) {
341
+ const errors = [];
342
+ if (config.apiUrl && !config.apiUrl.startsWith("http")) {
343
+ errors.push("apiUrl must start with http:// or https://");
344
+ }
345
+ if (config.refreshIntervalMs !== undefined && config.refreshIntervalMs < 100) {
346
+ errors.push("refreshIntervalMs must be >= 100ms");
347
+ }
348
+ if (config.theme && !["dark", "light"].includes(config.theme)) {
349
+ errors.push('theme must be "dark" or "light"');
350
+ }
351
+ if (config.transport !== undefined && !VALID_TRANSPORTS.has(config.transport)) {
352
+ errors.push('transport must be "public" | "access" | "mtls" | "tunnel"');
353
+ }
354
+ return errors;
355
+ }
356
+
346
357
  // src/stores/config-store.ts
347
358
  function getTuiPreferencesPath() {
348
359
  return join3(getHooxHome(), ".tui-state", "preferences.json");
@@ -81,198 +81,8 @@ interface ServiceActions {
81
81
  addCliErrorAlert: (details: CliErrorDetails) => void;
82
82
  }
83
83
  export declare const useServiceStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<ServiceState & ServiceActions>, "setState"> & {
84
- setState(nextStateOrUpdater: (ServiceState & ServiceActions) | Partial<ServiceState & ServiceActions> | ((state: {
85
- workers: {
86
- id: string;
87
- name: string;
88
- status: import("..").WorkerStatus;
89
- uptime: number;
90
- cpu: number;
91
- memory: number;
92
- requests: number;
93
- durableObjectCount: number;
94
- edgeCount: number;
95
- version?: string | undefined;
96
- lastDeployed?: number | undefined;
97
- }[];
98
- tradeStream: {
99
- id: string;
100
- symbol: string;
101
- side: import("..").TradeSide;
102
- price: number;
103
- quantity: number;
104
- timestamp: number;
105
- exchange: string;
106
- strategy?: string | undefined;
107
- pnl?: number | undefined;
108
- }[];
109
- alerts: {
110
- id: string;
111
- type: string;
112
- severity: import("..").AlertSeverity;
113
- message: string;
114
- timestamp: number;
115
- workerId?: string | undefined;
116
- acknowledged: boolean;
117
- source?: string | undefined;
118
- }[];
119
- logs: {
120
- id: string;
121
- level: import("..").LogLevel;
122
- message: string;
123
- timestamp: number;
124
- workerId?: string | undefined;
125
- source?: string | undefined;
126
- metadata?: {
127
- [x: string]: unknown;
128
- } | undefined;
129
- }[];
130
- metrics: {
131
- totalWorkers: number;
132
- onlineWorkers: number;
133
- totalPnl: number;
134
- activeStrategies: number;
135
- dailyTrades: number;
136
- aiCalls: number;
137
- uptime: number;
138
- lastUpdated: number;
139
- } | null;
140
- connectionStatus: ConnectionStatus;
141
- lastUpdated: number;
142
- selectedWorkerId: string | null;
143
- retryCount: number;
144
- lastError: string | null;
145
- lastErrorDetails: {
146
- command: string;
147
- exitCode: number;
148
- stderr: string;
149
- stdout: string;
150
- errorType: import("..").CliErrorType;
151
- timestamp: number;
152
- duration: number;
153
- } | null;
154
- lastSuccessfulFetch: number;
155
- reconnectDelay: number;
156
- disconnectedAt: number | null;
157
- fetchWorkers: () => Promise<void>;
158
- streamTrades: () => Promise<void>;
159
- streamLogs: () => Promise<void>;
160
- stopStreams: () => void;
161
- addAlert: (alert: Alert) => void;
162
- addAlerts: (alerts: Alert[]) => void;
163
- acknowledgeAlert: (id: string) => void;
164
- dismissAlert: (id: string) => void;
165
- clearLogs: () => void;
166
- setConnectionStatus: (status: ConnectionStatus) => void;
167
- selectWorker: (id: string | null) => void;
168
- setWorkers: (workers: WorkerInfo[]) => void;
169
- pushTrade: (trade: Trade) => void;
170
- pushLog: (log: LogEntry) => void;
171
- setMetrics: (metrics: SystemMetrics) => void;
172
- handleConnectionSuccess: () => void;
173
- handleConnectionFailure: (errorMessage: string) => void;
174
- resetRetries: () => void;
175
- forceRetry: () => void;
176
- setLastErrorDetails: (details: CliErrorDetails | null) => void;
177
- clearError: () => void;
178
- addCliErrorAlert: (details: CliErrorDetails) => void;
179
- }) => void), shouldReplace?: false): void;
180
- setState(nextStateOrUpdater: (ServiceState & ServiceActions) | ((state: {
181
- workers: {
182
- id: string;
183
- name: string;
184
- status: import("..").WorkerStatus;
185
- uptime: number;
186
- cpu: number;
187
- memory: number;
188
- requests: number;
189
- durableObjectCount: number;
190
- edgeCount: number;
191
- version?: string | undefined;
192
- lastDeployed?: number | undefined;
193
- }[];
194
- tradeStream: {
195
- id: string;
196
- symbol: string;
197
- side: import("..").TradeSide;
198
- price: number;
199
- quantity: number;
200
- timestamp: number;
201
- exchange: string;
202
- strategy?: string | undefined;
203
- pnl?: number | undefined;
204
- }[];
205
- alerts: {
206
- id: string;
207
- type: string;
208
- severity: import("..").AlertSeverity;
209
- message: string;
210
- timestamp: number;
211
- workerId?: string | undefined;
212
- acknowledged: boolean;
213
- source?: string | undefined;
214
- }[];
215
- logs: {
216
- id: string;
217
- level: import("..").LogLevel;
218
- message: string;
219
- timestamp: number;
220
- workerId?: string | undefined;
221
- source?: string | undefined;
222
- metadata?: {
223
- [x: string]: unknown;
224
- } | undefined;
225
- }[];
226
- metrics: {
227
- totalWorkers: number;
228
- onlineWorkers: number;
229
- totalPnl: number;
230
- activeStrategies: number;
231
- dailyTrades: number;
232
- aiCalls: number;
233
- uptime: number;
234
- lastUpdated: number;
235
- } | null;
236
- connectionStatus: ConnectionStatus;
237
- lastUpdated: number;
238
- selectedWorkerId: string | null;
239
- retryCount: number;
240
- lastError: string | null;
241
- lastErrorDetails: {
242
- command: string;
243
- exitCode: number;
244
- stderr: string;
245
- stdout: string;
246
- errorType: import("..").CliErrorType;
247
- timestamp: number;
248
- duration: number;
249
- } | null;
250
- lastSuccessfulFetch: number;
251
- reconnectDelay: number;
252
- disconnectedAt: number | null;
253
- fetchWorkers: () => Promise<void>;
254
- streamTrades: () => Promise<void>;
255
- streamLogs: () => Promise<void>;
256
- stopStreams: () => void;
257
- addAlert: (alert: Alert) => void;
258
- addAlerts: (alerts: Alert[]) => void;
259
- acknowledgeAlert: (id: string) => void;
260
- dismissAlert: (id: string) => void;
261
- clearLogs: () => void;
262
- setConnectionStatus: (status: ConnectionStatus) => void;
263
- selectWorker: (id: string | null) => void;
264
- setWorkers: (workers: WorkerInfo[]) => void;
265
- pushTrade: (trade: Trade) => void;
266
- pushLog: (log: LogEntry) => void;
267
- setMetrics: (metrics: SystemMetrics) => void;
268
- handleConnectionSuccess: () => void;
269
- handleConnectionFailure: (errorMessage: string) => void;
270
- resetRetries: () => void;
271
- forceRetry: () => void;
272
- setLastErrorDetails: (details: CliErrorDetails | null) => void;
273
- clearError: () => void;
274
- addCliErrorAlert: (details: CliErrorDetails) => void;
275
- }) => void), shouldReplace: true): void;
84
+ setState(nextStateOrUpdater: (ServiceState & ServiceActions) | Partial<ServiceState & ServiceActions> | ((state: import("immer").WritableNonArrayDraft<ServiceState & ServiceActions>) => void), shouldReplace?: false): void;
85
+ setState(nextStateOrUpdater: (ServiceState & ServiceActions) | ((state: import("immer").WritableNonArrayDraft<ServiceState & ServiceActions>) => void), shouldReplace: true): void;
276
86
  }>;
277
87
  export {};
278
88
  //# sourceMappingURL=service-store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"service-store.d.ts","sourceRoot":"","sources":["../../src/stores/service-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service-store.d.ts","sourceRoot":"","sources":["../../src/stores/service-store.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA+BH,OAAO,KAAK,EACV,UAAU,EACV,KAAK,EACL,KAAK,EACL,QAAQ,EACR,aAAa,EACb,gBAAgB,EAChB,eAAe,EAChB,MAAM,UAAU,CAAC;AAwClB,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,WAAW,EAAE,KAAK,EAAE,CAAC;IACrB,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,OAAO,EAAE,aAAa,GAAG,IAAI,CAAC;IAC9B,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAGhC,yDAAyD;IACzD,UAAU,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB;;;;;OAKG;IACH,gBAAgB,EAAE,eAAe,GAAG,IAAI,CAAC;IACzC,sDAAsD;IACtD,mBAAmB,EAAE,MAAM,CAAC;IAC5B,4DAA4D;IAC5D,cAAc,EAAE,MAAM,CAAC;IACvB,wEAAwE;IACxE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAID,UAAU,cAAc;IACtB,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC;;;OAGG;IACH,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,SAAS,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,IAAI,CAAC;IACrC,uDAAuD;IACvD,gBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,kDAAkD;IAClD,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,0DAA0D;IAC1D,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,mBAAmB,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACxD,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC1C,UAAU,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,IAAI,CAAC;IAC5C,SAAS,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAClC,OAAO,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI,CAAC;IACjC,UAAU,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAC;IAG7C,6DAA6D;IAC7D,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,gEAAgE;IAChE,uBAAuB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACxD,0DAA0D;IAC1D,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,kDAAkD;IAClD,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB;;;;OAIG;IACH,mBAAmB,EAAE,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,KAAK,IAAI,CAAC;IAC/D;;;;OAIG;IACH,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB;;;;OAIG;IACH,gBAAgB,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;CACtD;AA8ED,eAAO,MAAM,eAAe;;;EAmW3B,CAAC"}
@@ -182,6 +182,7 @@ var init_api_client = __esm(() => {
182
182
  // src/sse.ts
183
183
  function subscribeSSE(path, callback, onStatus, options) {
184
184
  let aborted = false;
185
+ const ac = new AbortController;
185
186
  const profile = options?.transport ?? (options?.transportEnv ? resolveOperatorTransportProfile(options.transportEnv) : resolveOperatorTransportProfile());
186
187
  const run = async () => {
187
188
  let attempt = 0;
@@ -192,7 +193,8 @@ function subscribeSSE(path, callback, onStatus, options) {
192
193
  headers: {
193
194
  Accept: "text/event-stream",
194
195
  ...buildOperatorAuthHeaders(profile)
195
- }
196
+ },
197
+ signal: ac.signal
196
198
  });
197
199
  if (!response.ok || !response.body) {
198
200
  throw new Error(`SSE connection failed: HTTP ${response.status}`);
@@ -204,17 +206,21 @@ function subscribeSSE(path, callback, onStatus, options) {
204
206
  let buffer = "";
205
207
  while (!aborted) {
206
208
  const { done, value } = await reader.read();
207
- if (done)
208
- break;
209
+ if (done) {
210
+ throw new Error("SSE stream ended");
211
+ }
209
212
  buffer += decoder.decode(value, { stream: true });
210
213
  const lines = buffer.split(`
211
214
  `);
212
215
  buffer = lines.pop() || "";
213
216
  for (const line of lines) {
214
217
  const trimmed = line.trim();
215
- if (trimmed.startsWith("data: ")) {
218
+ if (trimmed.startsWith("data:")) {
219
+ const jsonText = trimmed.slice(5).replace(/^\s/, "");
220
+ if (!jsonText)
221
+ continue;
216
222
  try {
217
- const parsed = JSON.parse(trimmed.slice(6));
223
+ const parsed = JSON.parse(jsonText);
218
224
  callback(parsed);
219
225
  } catch {}
220
226
  }
@@ -226,7 +232,18 @@ function subscribeSSE(path, callback, onStatus, options) {
226
232
  onStatus?.("reconnecting");
227
233
  const delay = Math.min(RECONNECT_BASE_MS * Math.pow(2, attempt), RECONNECT_MAX_MS);
228
234
  attempt++;
229
- await new Promise((resolve) => setTimeout(resolve, delay));
235
+ await new Promise((resolve) => {
236
+ const timer = setTimeout(resolve, delay);
237
+ const onAbort = () => {
238
+ clearTimeout(timer);
239
+ resolve();
240
+ };
241
+ if (ac.signal.aborted) {
242
+ onAbort();
243
+ return;
244
+ }
245
+ ac.signal.addEventListener("abort", onAbort, { once: true });
246
+ });
230
247
  }
231
248
  }
232
249
  if (!aborted) {
@@ -237,6 +254,7 @@ function subscribeSSE(path, callback, onStatus, options) {
237
254
  return {
238
255
  abort: () => {
239
256
  aborted = true;
257
+ ac.abort();
240
258
  }
241
259
  };
242
260
  }