@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.
- package/dist/agent-config-fields.d.ts +5 -0
- package/dist/agent-config-fields.d.ts.map +1 -1
- package/dist/analytics.d.ts.map +1 -1
- package/dist/analytics.js +8 -3
- package/dist/config.d.ts +10 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +256 -24
- package/dist/errors.d.ts +1 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/exchange-client.d.ts +0 -19
- package/dist/exchange-client.d.ts.map +1 -1
- package/dist/exchange-client.js +0 -66
- package/dist/exchanges/base-exchange-client.d.ts.map +1 -1
- package/dist/exchanges/base-exchange-client.js +4 -3
- package/dist/exchanges/index.js +4 -3
- package/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +293 -604
- package/dist/middleware/auth.d.ts +9 -0
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/index.js +3 -2
- package/dist/middleware/logger.d.ts +2 -0
- package/dist/middleware/logger.d.ts.map +1 -1
- package/dist/middleware/rate-limit.d.ts +7 -0
- package/dist/middleware/rate-limit.d.ts.map +1 -1
- package/dist/middleware/rate-limit.js +3 -2
- package/dist/middleware/validate.d.ts +2 -0
- package/dist/middleware/validate.d.ts.map +1 -1
- package/dist/path-utils.d.ts.map +1 -1
- package/dist/path-utils.js +13 -3
- package/dist/queue-handler.d.ts.map +1 -1
- package/dist/queue-handler.js +19 -8
- package/dist/router.d.ts +5 -0
- package/dist/router.d.ts.map +1 -1
- package/dist/schemas/index.js +40 -23
- package/dist/schemas/registry.d.ts.map +1 -1
- package/dist/schemas/registry.js +4 -1
- package/dist/schemas/validators.d.ts.map +1 -1
- package/dist/schemas/validators.js +36 -22
- package/dist/service-bindings.d.ts +4 -0
- package/dist/service-bindings.d.ts.map +1 -1
- package/dist/session.d.ts +10 -3
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +109 -33
- package/dist/sse.d.ts.map +1 -1
- package/dist/sse.js +24 -6
- package/dist/stores/config-store.d.ts +2 -50
- package/dist/stores/config-store.d.ts.map +1 -1
- package/dist/stores/config-store.js +145 -134
- package/dist/stores/service-store.d.ts +2 -192
- package/dist/stores/service-store.d.ts.map +1 -1
- package/dist/stores/service-store.js +24 -6
- package/dist/stores/ui-store.d.ts +2 -48
- package/dist/stores/ui-store.d.ts.map +1 -1
- package/dist/tenant.d.ts +1 -0
- package/dist/tenant.d.ts.map +1 -1
- package/dist/types.d.ts +6 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +19 -0
- package/dist/wizard/engine.d.ts.map +1 -1
- package/dist/wizard/engine.js +13 -7
- package/dist/wizard/index.js +13 -7
- package/dist/wizard/presets.js +3 -3
- 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
|
|
128
|
-
mkdirSync
|
|
129
|
-
readFileSync
|
|
130
|
-
writeFileSync
|
|
131
|
-
chmodSync
|
|
22
|
+
existsSync,
|
|
23
|
+
mkdirSync,
|
|
24
|
+
readFileSync,
|
|
25
|
+
writeFileSync,
|
|
26
|
+
chmodSync
|
|
132
27
|
} from "fs";
|
|
133
|
-
import { homedir
|
|
134
|
-
import { dirname, join
|
|
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 =
|
|
49
|
+
const home = homedir();
|
|
145
50
|
if (!home || home.length === 0) {
|
|
146
51
|
return createHooxPath(resolve(process.cwd(), ".hoox"));
|
|
147
52
|
}
|
|
148
|
-
return createHooxPath(
|
|
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 (!
|
|
63
|
+
if (!existsSync(join(root, "packages", "cli", "package.json"))) {
|
|
159
64
|
return false;
|
|
160
65
|
}
|
|
161
|
-
return
|
|
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 (!
|
|
77
|
+
if (!existsSync(path))
|
|
173
78
|
return null;
|
|
174
|
-
const raw =
|
|
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
|
-
|
|
95
|
+
mkdirSync(configDir, { recursive: true, mode: 448 });
|
|
191
96
|
try {
|
|
192
|
-
|
|
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
|
-
|
|
104
|
+
writeFileSync(path, JSON.stringify(payload, null, 2) + `
|
|
200
105
|
`, {
|
|
201
106
|
mode: 384
|
|
202
107
|
});
|
|
203
108
|
try {
|
|
204
|
-
|
|
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
|
-
|
|
285
|
-
|
|
286
|
-
|
|
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 =
|
|
203
|
+
const fullPath = join(hooxHome, normalizedPath);
|
|
299
204
|
const resolvedPath = resolve(fullPath);
|
|
300
205
|
const resolvedHome = resolve(hooxHome);
|
|
301
|
-
if (!resolvedPath
|
|
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
|
|
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
|
-
|
|
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":"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
|
|
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
|
-
|
|
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(
|
|
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) =>
|
|
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
|
}
|