@hoox-sh/hoox-shared 1.4.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/README.md +6 -0
- package/dist/agent-config-fields.d.ts +5 -0
- package/dist/agent-config-fields.d.ts.map +1 -1
- package/dist/agent-config-fields.js +21 -29
- package/dist/analytics.d.ts +3 -4
- package/dist/analytics.d.ts.map +1 -1
- package/dist/analytics.js +64 -19
- package/dist/api-client.js +12 -21
- package/dist/colors.js +5 -21
- package/dist/config.d.ts +10 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +267 -51
- package/dist/cron-handler.js +0 -16
- package/dist/d1/index.js +8 -25
- package/dist/d1/repository.js +3 -19
- package/dist/d1/schemas.js +4 -20
- package/dist/dashboard-manifest.d.ts +2 -1
- package/dist/dashboard-manifest.d.ts.map +1 -1
- package/dist/dashboard-manifest.js +37 -33
- package/dist/entitlements.d.ts +46 -0
- package/dist/entitlements.d.ts.map +1 -0
- package/dist/entitlements.js +15 -0
- package/dist/errors.d.ts +1 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +7 -23
- package/dist/exchange-client.d.ts +0 -19
- package/dist/exchange-client.d.ts.map +1 -1
- package/dist/exchange-client.js +1 -83
- package/dist/exchanges/base-exchange-client.d.ts.map +1 -1
- package/dist/exchanges/base-exchange-client.js +4 -19
- package/dist/exchanges/index.js +4 -19
- package/dist/format-time.js +2 -18
- package/dist/formatters.js +12 -28
- package/dist/health.js +3 -19
- package/dist/index.d.ts +7 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3568 -3766
- package/dist/kill-switch.js +12 -20
- package/dist/kvKeys.d.ts +8 -0
- package/dist/kvKeys.d.ts.map +1 -1
- package/dist/kvKeys.js +42 -46
- package/dist/kvUtils.js +8 -24
- package/dist/legal.js +5 -21
- package/dist/middleware/auth.d.ts +9 -0
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +9 -25
- package/dist/middleware/cors.js +4 -20
- package/dist/middleware/index.js +144 -165
- package/dist/middleware/logger.d.ts +2 -0
- package/dist/middleware/logger.d.ts.map +1 -1
- package/dist/middleware/logger.js +9 -25
- 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 +5 -20
- package/dist/middleware/security-headers.js +2 -18
- package/dist/middleware/validate.d.ts +2 -0
- package/dist/middleware/validate.d.ts.map +1 -1
- package/dist/middleware/validate.js +5 -21
- package/dist/middleware/wait-until.js +2 -18
- package/dist/operator-transport.js +13 -17
- package/dist/path-utils.d.ts.map +1 -1
- package/dist/path-utils.js +28 -34
- package/dist/queue-handler.d.ts.map +1 -1
- package/dist/queue-handler.js +19 -24
- package/dist/router.d.ts +5 -0
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +0 -16
- package/dist/schemas/index.js +75 -50
- package/dist/schemas/registry.d.ts.map +1 -1
- package/dist/schemas/registry.js +33 -21
- package/dist/schemas/validators.d.ts.map +1 -1
- package/dist/schemas/validators.js +41 -43
- package/dist/service-bindings.d.ts +4 -0
- package/dist/service-bindings.d.ts.map +1 -1
- package/dist/service-bindings.js +13 -29
- package/dist/session.d.ts +10 -3
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +111 -51
- package/dist/sse.d.ts.map +1 -1
- package/dist/sse.js +34 -24
- 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 +153 -156
- 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 +40 -35
- package/dist/stores/ui-store.d.ts +2 -48
- package/dist/stores/ui-store.d.ts.map +1 -1
- package/dist/stores/ui-store.js +0 -16
- package/dist/tenant.d.ts +62 -0
- package/dist/tenant.d.ts.map +1 -0
- package/dist/tenant.js +56 -0
- package/dist/test-utils.js +11 -27
- package/dist/types.d.ts +10 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +29 -24
- package/dist/wizard/engine.d.ts.map +1 -1
- package/dist/wizard/engine.js +33 -27
- package/dist/wizard/index.d.ts +1 -0
- package/dist/wizard/index.d.ts.map +1 -1
- package/dist/wizard/index.js +48 -39
- package/dist/wizard/persistence.d.ts +4 -0
- package/dist/wizard/persistence.d.ts.map +1 -1
- package/dist/wizard/persistence.js +7 -19
- package/dist/wizard/presets.d.ts.map +1 -1
- package/dist/wizard/presets.js +13 -25
- package/dist/wizard/types.d.ts +6 -0
- package/dist/wizard/types.d.ts.map +1 -1
- package/dist/wizard/types.js +5 -0
- package/package.json +7 -2
|
@@ -1,160 +1,56 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
for (var name in all)
|
|
9
|
-
__defProp(target, name, {
|
|
10
|
-
get: all[name],
|
|
11
|
-
enumerable: true,
|
|
12
|
-
configurable: true,
|
|
13
|
-
set: __exportSetter.bind(all, name)
|
|
14
|
-
});
|
|
15
|
-
};
|
|
16
|
-
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
2
|
+
// src/stores/config-store.ts
|
|
3
|
+
import { create } from "zustand";
|
|
4
|
+
import { immer } from "zustand/middleware/immer";
|
|
5
|
+
import { persist, createJSONStorage } from "zustand/middleware";
|
|
6
|
+
import { chmodSync as chmodSync3, mkdirSync as mkdirSync3, existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
|
|
7
|
+
import { join as join3 } from "path";
|
|
17
8
|
|
|
18
9
|
// src/config.ts
|
|
19
10
|
import {
|
|
20
|
-
readFileSync,
|
|
21
|
-
writeFileSync,
|
|
22
|
-
existsSync,
|
|
23
|
-
mkdirSync,
|
|
24
|
-
chmodSync,
|
|
11
|
+
readFileSync as readFileSync2,
|
|
12
|
+
writeFileSync as writeFileSync2,
|
|
13
|
+
existsSync as existsSync2,
|
|
14
|
+
mkdirSync as mkdirSync2,
|
|
15
|
+
chmodSync as chmodSync2,
|
|
25
16
|
statSync
|
|
26
17
|
} from "fs";
|
|
27
|
-
import { join } from "path";
|
|
28
|
-
import { homedir } from "os";
|
|
29
|
-
var HOX_DIR = join(homedir(), ".hoox");
|
|
30
|
-
var CONFIG_PATH = join(HOX_DIR, "config.json");
|
|
31
|
-
var HOOX_DIR_MODE = 448;
|
|
32
|
-
var HOOX_CONFIG_FILE_MODE = 384;
|
|
33
|
-
var DEFAULT_CONFIG = {
|
|
34
|
-
apiUrl: "http://localhost:8787",
|
|
35
|
-
apiToken: "",
|
|
36
|
-
transport: "public",
|
|
37
|
-
refreshIntervalMs: 500,
|
|
38
|
-
theme: "dark",
|
|
39
|
-
activeExchanges: ["binance", "bybit", "mexc"],
|
|
40
|
-
notifications: {
|
|
41
|
-
alerts: true,
|
|
42
|
-
trades: true,
|
|
43
|
-
debug: false,
|
|
44
|
-
system: true
|
|
45
|
-
},
|
|
46
|
-
soundEnabled: true,
|
|
47
|
-
defaultView: "dashboard"
|
|
48
|
-
};
|
|
49
|
-
function readConfigSync() {
|
|
50
|
-
const envConfig = {
|
|
51
|
-
apiUrl: process.env.HOOX_API_URL,
|
|
52
|
-
apiToken: process.env.HOOX_API_TOKEN
|
|
53
|
-
};
|
|
54
|
-
let fileConfig = {};
|
|
55
|
-
try {
|
|
56
|
-
if (existsSync(CONFIG_PATH)) {
|
|
57
|
-
fileConfig = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
|
|
58
|
-
}
|
|
59
|
-
} catch {}
|
|
60
|
-
return {
|
|
61
|
-
...DEFAULT_CONFIG,
|
|
62
|
-
...fileConfig,
|
|
63
|
-
...Object.fromEntries(Object.entries(envConfig).filter(([_, v]) => v !== undefined))
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
async function readConfig() {
|
|
67
|
-
return readConfigSync();
|
|
68
|
-
}
|
|
69
|
-
function ensureHooxDirSecure(dir = HOX_DIR) {
|
|
70
|
-
if (!existsSync(dir)) {
|
|
71
|
-
mkdirSync(dir, { recursive: true, mode: HOOX_DIR_MODE });
|
|
72
|
-
}
|
|
73
|
-
try {
|
|
74
|
-
chmodSync(dir, HOOX_DIR_MODE);
|
|
75
|
-
} catch {}
|
|
76
|
-
}
|
|
77
|
-
function writeSecureFileSync(filePath, contents, mode = HOOX_CONFIG_FILE_MODE) {
|
|
78
|
-
writeFileSync(filePath, contents, { encoding: "utf-8", mode });
|
|
79
|
-
try {
|
|
80
|
-
chmodSync(filePath, mode);
|
|
81
|
-
} catch {}
|
|
82
|
-
}
|
|
83
|
-
function isUnixModeGroupOrWorldAccessible(mode) {
|
|
84
|
-
return (mode & 63) !== 0;
|
|
85
|
-
}
|
|
86
|
-
function isConfigWorldOrGroupReadable(filePath = CONFIG_PATH) {
|
|
87
|
-
try {
|
|
88
|
-
if (!existsSync(filePath))
|
|
89
|
-
return false;
|
|
90
|
-
return isUnixModeGroupOrWorldAccessible(statSync(filePath).mode & 511);
|
|
91
|
-
} catch {
|
|
92
|
-
return false;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
function formatConfigPermissionWarning(filePath = CONFIG_PATH) {
|
|
96
|
-
if (!isConfigWorldOrGroupReadable(filePath))
|
|
97
|
-
return null;
|
|
98
|
-
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.`;
|
|
99
|
-
}
|
|
100
|
-
function writeConfigSync(config) {
|
|
101
|
-
try {
|
|
102
|
-
ensureHooxDirSecure(HOX_DIR);
|
|
103
|
-
writeSecureFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), HOOX_CONFIG_FILE_MODE);
|
|
104
|
-
} catch (err) {
|
|
105
|
-
console.error("Failed to write config:", err);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
async function writeConfig(config) {
|
|
109
|
-
writeConfigSync(config);
|
|
110
|
-
}
|
|
111
|
-
var VALID_TRANSPORTS = new Set([
|
|
112
|
-
"public",
|
|
113
|
-
"access",
|
|
114
|
-
"mtls",
|
|
115
|
-
"tunnel"
|
|
116
|
-
]);
|
|
117
|
-
function validateConfig(config) {
|
|
118
|
-
const errors = [];
|
|
119
|
-
if (config.apiUrl && !config.apiUrl.startsWith("http")) {
|
|
120
|
-
errors.push("apiUrl must start with http:// or https://");
|
|
121
|
-
}
|
|
122
|
-
if (config.refreshIntervalMs !== undefined && config.refreshIntervalMs < 100) {
|
|
123
|
-
errors.push("refreshIntervalMs must be >= 100ms");
|
|
124
|
-
}
|
|
125
|
-
if (config.theme && !["dark", "light"].includes(config.theme)) {
|
|
126
|
-
errors.push('theme must be "dark" or "light"');
|
|
127
|
-
}
|
|
128
|
-
if (config.transport !== undefined && !VALID_TRANSPORTS.has(config.transport)) {
|
|
129
|
-
errors.push('transport must be "public" | "access" | "mtls" | "tunnel"');
|
|
130
|
-
}
|
|
131
|
-
return errors;
|
|
132
|
-
}
|
|
18
|
+
import { join as join2 } from "path";
|
|
133
19
|
|
|
134
20
|
// src/path-utils.ts
|
|
135
21
|
import {
|
|
136
|
-
existsSync
|
|
137
|
-
mkdirSync
|
|
138
|
-
readFileSync
|
|
139
|
-
writeFileSync
|
|
140
|
-
chmodSync
|
|
22
|
+
existsSync,
|
|
23
|
+
mkdirSync,
|
|
24
|
+
readFileSync,
|
|
25
|
+
writeFileSync,
|
|
26
|
+
chmodSync
|
|
141
27
|
} from "fs";
|
|
142
|
-
import { homedir
|
|
143
|
-
import { dirname, join
|
|
28
|
+
import { homedir } from "os";
|
|
29
|
+
import { dirname, join, resolve, sep } from "path";
|
|
144
30
|
function createHooxPath(path) {
|
|
145
31
|
return path;
|
|
146
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
|
+
}
|
|
147
43
|
function getHooxHome() {
|
|
148
44
|
try {
|
|
149
45
|
const override = process.env.HOOX_HOME?.trim();
|
|
150
46
|
if (override) {
|
|
151
47
|
return createHooxPath(resolve(override));
|
|
152
48
|
}
|
|
153
|
-
const home =
|
|
49
|
+
const home = homedir();
|
|
154
50
|
if (!home || home.length === 0) {
|
|
155
51
|
return createHooxPath(resolve(process.cwd(), ".hoox"));
|
|
156
52
|
}
|
|
157
|
-
return createHooxPath(
|
|
53
|
+
return createHooxPath(join(home, ".hoox"));
|
|
158
54
|
} catch {
|
|
159
55
|
return createHooxPath(resolve(process.cwd(), ".hoox"));
|
|
160
56
|
}
|
|
@@ -164,10 +60,10 @@ function isHooxSetupRoot(dir) {
|
|
|
164
60
|
return false;
|
|
165
61
|
try {
|
|
166
62
|
const root = resolve(dir);
|
|
167
|
-
if (!
|
|
63
|
+
if (!existsSync(join(root, "packages", "cli", "package.json"))) {
|
|
168
64
|
return false;
|
|
169
65
|
}
|
|
170
|
-
return
|
|
66
|
+
return existsSync(join(root, "wrangler.jsonc")) || existsSync(join(root, "wrangler.jsonc.example")) || existsSync(join(root, "workers")) || existsSync(join(root, ".gitmodules"));
|
|
171
67
|
} catch {
|
|
172
68
|
return false;
|
|
173
69
|
}
|
|
@@ -178,9 +74,9 @@ function getRememberedMonorepoPath() {
|
|
|
178
74
|
function getRememberedMonorepoRoot() {
|
|
179
75
|
try {
|
|
180
76
|
const path = getRememberedMonorepoPath();
|
|
181
|
-
if (!
|
|
77
|
+
if (!existsSync(path))
|
|
182
78
|
return null;
|
|
183
|
-
const raw =
|
|
79
|
+
const raw = readFileSync(path, "utf-8");
|
|
184
80
|
const data = JSON.parse(raw);
|
|
185
81
|
if (!data.root || typeof data.root !== "string")
|
|
186
82
|
return null;
|
|
@@ -196,21 +92,21 @@ function rememberMonorepoRoot(root) {
|
|
|
196
92
|
if (!isHooxSetupRoot(resolved))
|
|
197
93
|
return false;
|
|
198
94
|
const configDir = getHooxConfigDir();
|
|
199
|
-
|
|
95
|
+
mkdirSync(configDir, { recursive: true, mode: 448 });
|
|
200
96
|
try {
|
|
201
|
-
|
|
97
|
+
chmodSync(configDir, 448);
|
|
202
98
|
} catch {}
|
|
203
99
|
const payload = {
|
|
204
100
|
root: resolved,
|
|
205
101
|
updatedAt: new Date().toISOString()
|
|
206
102
|
};
|
|
207
103
|
const path = getRememberedMonorepoPath();
|
|
208
|
-
|
|
104
|
+
writeFileSync(path, JSON.stringify(payload, null, 2) + `
|
|
209
105
|
`, {
|
|
210
106
|
mode: 384
|
|
211
107
|
});
|
|
212
108
|
try {
|
|
213
|
-
|
|
109
|
+
chmodSync(path, 384);
|
|
214
110
|
} catch {}
|
|
215
111
|
return true;
|
|
216
112
|
} catch {
|
|
@@ -290,9 +186,9 @@ function resolveHooxRuntimeRoot(options) {
|
|
|
290
186
|
function getTuiEntryCandidates(runtimeRoot) {
|
|
291
187
|
const root = resolve(runtimeRoot);
|
|
292
188
|
return [
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
189
|
+
join(root, "packages", "tui", "src", "main.tsx"),
|
|
190
|
+
join(root, "packages", "tui", "dist", "main.js"),
|
|
191
|
+
join(root, "packages", "tui", "src", "main.ts")
|
|
296
192
|
];
|
|
297
193
|
}
|
|
298
194
|
function resolveHooxPath(relativePath) {
|
|
@@ -304,10 +200,10 @@ function resolveHooxPath(relativePath) {
|
|
|
304
200
|
}
|
|
305
201
|
const normalizedPath = relativePath.replace(/\\/g, "/");
|
|
306
202
|
const hooxHome = getHooxHome();
|
|
307
|
-
const fullPath =
|
|
203
|
+
const fullPath = join(hooxHome, normalizedPath);
|
|
308
204
|
const resolvedPath = resolve(fullPath);
|
|
309
205
|
const resolvedHome = resolve(hooxHome);
|
|
310
|
-
if (!resolvedPath
|
|
206
|
+
if (!isInsideDir(resolvedPath, resolvedHome)) {
|
|
311
207
|
throw new Error(`Resolved path "${resolvedPath}" is outside Hoox home directory`);
|
|
312
208
|
}
|
|
313
209
|
return createHooxPath(resolvedPath);
|
|
@@ -317,7 +213,7 @@ function isWithinHooxHome(path) {
|
|
|
317
213
|
const hooxHome = getHooxHome();
|
|
318
214
|
const resolvedPath = resolve(path);
|
|
319
215
|
const resolvedHome = resolve(hooxHome);
|
|
320
|
-
return resolvedPath
|
|
216
|
+
return isInsideDir(resolvedPath, resolvedHome);
|
|
321
217
|
} catch {
|
|
322
218
|
return false;
|
|
323
219
|
}
|
|
@@ -352,12 +248,113 @@ function getHooxStatePath() {
|
|
|
352
248
|
return resolveHooxPath("data/state.json");
|
|
353
249
|
}
|
|
354
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
|
+
|
|
355
357
|
// src/stores/config-store.ts
|
|
356
|
-
import { create } from "zustand";
|
|
357
|
-
import { immer } from "zustand/middleware/immer";
|
|
358
|
-
import { persist, createJSONStorage } from "zustand/middleware";
|
|
359
|
-
import { chmodSync as chmodSync3, mkdirSync as mkdirSync3, existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
|
|
360
|
-
import { join as join3 } from "path";
|
|
361
358
|
function getTuiPreferencesPath() {
|
|
362
359
|
return join3(getHooxHome(), ".tui-state", "preferences.json");
|
|
363
360
|
}
|
|
@@ -501,6 +498,6 @@ var useConfigStore = create()(persist(immer((set) => ({
|
|
|
501
498
|
})
|
|
502
499
|
}));
|
|
503
500
|
export {
|
|
504
|
-
|
|
505
|
-
|
|
501
|
+
getTuiPreferencesPath,
|
|
502
|
+
useConfigStore
|
|
506
503
|
};
|
|
@@ -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"}
|