@jango-blockchained/hoox-shared 1.0.9 → 1.1.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 +17 -0
- package/dist/analytics.d.ts +23 -1
- package/dist/analytics.d.ts.map +1 -1
- package/dist/analytics.js +14 -3
- package/dist/api-client.d.ts +12 -2
- package/dist/api-client.d.ts.map +1 -1
- package/dist/api-client.js +74 -7
- package/dist/colors.d.ts +63 -24
- package/dist/colors.d.ts.map +1 -1
- package/dist/colors.js +60 -19
- package/dist/config.d.ts +34 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +61 -6
- package/dist/cron-handler.d.ts +2 -2
- package/dist/cron-handler.d.ts.map +1 -1
- package/dist/d1/index.js +1 -0
- package/dist/d1/repository.js +297 -0
- package/dist/d1/schemas.js +81 -0
- package/dist/exchanges/base-exchange-client.js +120 -0
- package/dist/exchanges/types.js +1 -0
- package/dist/index.d.ts +21 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +580 -60
- package/dist/middleware/auth.d.ts +42 -6
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +151 -0
- package/dist/middleware/cors.d.ts +28 -2
- package/dist/middleware/cors.d.ts.map +1 -1
- package/dist/middleware/cors.js +77 -0
- package/dist/middleware/index.d.ts +2 -2
- package/dist/middleware/index.d.ts.map +1 -1
- package/dist/middleware/index.js +192 -107
- package/dist/middleware/logger.js +202 -0
- package/dist/middleware/rate-limit.d.ts.map +1 -1
- package/dist/middleware/rate-limit.js +181 -0
- package/dist/middleware/security-headers.js +58 -0
- package/dist/middleware/validate.js +56 -0
- package/dist/operator-transport.d.ts +61 -0
- package/dist/operator-transport.d.ts.map +1 -0
- package/dist/operator-transport.js +87 -0
- package/dist/path-utils.d.ts +59 -1
- package/dist/path-utils.d.ts.map +1 -1
- package/dist/path-utils.js +89 -2
- package/dist/queue-handler.d.ts +3 -3
- package/dist/queue-handler.d.ts.map +1 -1
- package/dist/router.d.ts +2 -2
- package/dist/router.d.ts.map +1 -1
- package/dist/schemas/index.js +7 -4
- package/dist/schemas/registry.js +387 -0
- package/dist/schemas/types.js +1 -0
- package/dist/schemas/validators.d.ts.map +1 -1
- package/dist/schemas/validators.js +290 -0
- package/dist/service-bindings.d.ts +65 -0
- package/dist/service-bindings.d.ts.map +1 -1
- package/dist/service-bindings.js +216 -1
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +97 -2
- package/dist/sse.d.ts +12 -3
- package/dist/sse.d.ts.map +1 -1
- package/dist/sse.js +70 -7
- package/dist/stores/config-store.d.ts.map +1 -1
- package/dist/stores/config-store.js +129 -6
- package/dist/stores/service-store.d.ts.map +1 -1
- package/dist/stores/service-store.js +96 -25
- package/dist/types.d.ts +66 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +11 -0
- package/dist/wizard/engine.js +501 -0
- package/dist/wizard/index.js +2 -1
- package/dist/wizard/persistence.js +31 -0
- package/dist/wizard/presets.js +199 -0
- package/dist/wizard/provisioner.js +1 -0
- package/dist/wizard/types.js +1 -0
- package/package.json +38 -12
package/dist/session.js
CHANGED
|
@@ -16,13 +16,18 @@ var __export = (target, all) => {
|
|
|
16
16
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
17
17
|
|
|
18
18
|
// src/path-utils.ts
|
|
19
|
+
import { existsSync } from "fs";
|
|
19
20
|
import { homedir } from "os";
|
|
20
|
-
import { join, resolve } from "path";
|
|
21
|
+
import { dirname, join, resolve } from "path";
|
|
21
22
|
function createHooxPath(path) {
|
|
22
23
|
return path;
|
|
23
24
|
}
|
|
24
25
|
function getHooxHome() {
|
|
25
26
|
try {
|
|
27
|
+
const override = process.env.HOOX_HOME?.trim();
|
|
28
|
+
if (override) {
|
|
29
|
+
return createHooxPath(resolve(override));
|
|
30
|
+
}
|
|
26
31
|
const home = homedir();
|
|
27
32
|
if (!home || home.length === 0) {
|
|
28
33
|
return createHooxPath(resolve(process.cwd(), ".hoox"));
|
|
@@ -32,6 +37,84 @@ function getHooxHome() {
|
|
|
32
37
|
return createHooxPath(resolve(process.cwd(), ".hoox"));
|
|
33
38
|
}
|
|
34
39
|
}
|
|
40
|
+
function isHooxSetupRoot(dir) {
|
|
41
|
+
if (!dir)
|
|
42
|
+
return false;
|
|
43
|
+
try {
|
|
44
|
+
const root = resolve(dir);
|
|
45
|
+
return existsSync(join(root, "wrangler.jsonc")) && existsSync(join(root, "packages", "cli", "package.json"));
|
|
46
|
+
} catch {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function findHooxSetupRoot(startDir = process.cwd()) {
|
|
51
|
+
let dir = resolve(startDir);
|
|
52
|
+
for (;; ) {
|
|
53
|
+
if (isHooxSetupRoot(dir))
|
|
54
|
+
return dir;
|
|
55
|
+
const parent = dirname(dir);
|
|
56
|
+
if (parent === dir)
|
|
57
|
+
return null;
|
|
58
|
+
dir = parent;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function resolveHooxRuntimeRoot(options) {
|
|
62
|
+
const env = options?.env ?? process.env;
|
|
63
|
+
const cwd = resolve(options?.cwd ?? process.cwd());
|
|
64
|
+
const globalRepo = getHooxRepoPath();
|
|
65
|
+
const envRepo = env.HOOX_REPO?.trim();
|
|
66
|
+
if (envRepo) {
|
|
67
|
+
const resolved = resolve(envRepo);
|
|
68
|
+
if (isHooxSetupRoot(resolved)) {
|
|
69
|
+
return {
|
|
70
|
+
root: resolved,
|
|
71
|
+
source: "env",
|
|
72
|
+
checked: {
|
|
73
|
+
env: resolved,
|
|
74
|
+
cwd: findHooxSetupRoot(cwd),
|
|
75
|
+
global: globalRepo
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
root: null,
|
|
81
|
+
source: "env",
|
|
82
|
+
checked: {
|
|
83
|
+
env: resolved,
|
|
84
|
+
cwd: findHooxSetupRoot(cwd),
|
|
85
|
+
global: globalRepo
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
const local = findHooxSetupRoot(cwd);
|
|
90
|
+
if (local) {
|
|
91
|
+
return {
|
|
92
|
+
root: local,
|
|
93
|
+
source: "cwd",
|
|
94
|
+
checked: { cwd: local, global: globalRepo }
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
if (isHooxSetupRoot(globalRepo)) {
|
|
98
|
+
return {
|
|
99
|
+
root: globalRepo,
|
|
100
|
+
source: "global",
|
|
101
|
+
checked: { cwd: null, global: globalRepo }
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
root: null,
|
|
106
|
+
source: "none",
|
|
107
|
+
checked: { cwd: null, global: globalRepo }
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function getTuiEntryCandidates(runtimeRoot) {
|
|
111
|
+
const root = resolve(runtimeRoot);
|
|
112
|
+
return [
|
|
113
|
+
join(root, "packages", "tui", "src", "main.tsx"),
|
|
114
|
+
join(root, "packages", "tui", "dist", "main.js"),
|
|
115
|
+
join(root, "packages", "tui", "src", "main.ts")
|
|
116
|
+
];
|
|
117
|
+
}
|
|
35
118
|
function resolveHooxPath(relativePath) {
|
|
36
119
|
if (!relativePath || typeof relativePath !== "string") {
|
|
37
120
|
throw new Error("relativePath must be a non-empty string");
|
|
@@ -90,6 +173,17 @@ function getHooxStatePath() {
|
|
|
90
173
|
}
|
|
91
174
|
|
|
92
175
|
// src/session.ts
|
|
176
|
+
import { z } from "zod";
|
|
177
|
+
var SessionStateFileSchema = z.object({
|
|
178
|
+
activeView: z.string().optional(),
|
|
179
|
+
sidebarExpanded: z.boolean().optional(),
|
|
180
|
+
windowSize: z.object({
|
|
181
|
+
cols: z.number().int().positive(),
|
|
182
|
+
rows: z.number().int().positive()
|
|
183
|
+
}).optional(),
|
|
184
|
+
lastData: z.number().nonnegative().optional(),
|
|
185
|
+
savedAt: z.string().optional()
|
|
186
|
+
}).strict();
|
|
93
187
|
var TUI_STATE_DIR = ".tui-state";
|
|
94
188
|
var SESSION_FILE = (() => {
|
|
95
189
|
try {
|
|
@@ -127,7 +221,8 @@ async function restoreSession() {
|
|
|
127
221
|
if (!exists)
|
|
128
222
|
return { ...DEFAULT_SESSION };
|
|
129
223
|
const raw = await file.text();
|
|
130
|
-
const
|
|
224
|
+
const result = SessionStateFileSchema.safeParse(JSON.parse(raw));
|
|
225
|
+
const parsed = result.success ? result.data : {};
|
|
131
226
|
return {
|
|
132
227
|
activeView: validateViewId(parsed.activeView) ? parsed.activeView : DEFAULT_SESSION.activeView,
|
|
133
228
|
sidebarExpanded: typeof parsed.sidebarExpanded === "boolean" ? parsed.sidebarExpanded : DEFAULT_SESSION.sidebarExpanded,
|
package/dist/sse.d.ts
CHANGED
|
@@ -1,26 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* SSE Streaming Client — subscribes to Server-Sent Events from
|
|
2
|
+
* SSE Streaming Client — subscribes to Server-Sent Events from the Hoox
|
|
3
|
+
* operator management API.
|
|
3
4
|
*
|
|
4
5
|
* Uses Bun's native fetch with ReadableStream reader for SSE parsing.
|
|
5
6
|
* Supports reconnection with exponential backoff.
|
|
6
7
|
* Events must be JSON-encoded in the "data:" field.
|
|
8
|
+
*
|
|
9
|
+
* Auth: operator transport profile (Bearer + optional Access service token).
|
|
7
10
|
*/
|
|
11
|
+
import { type OperatorTransportEnv, type OperatorTransportProfile } from "./operator-transport";
|
|
8
12
|
export type SSECallback<T> = (event: T) => void;
|
|
9
13
|
export type SSEStatusCallback = (status: "connected" | "reconnecting" | "disconnected") => void;
|
|
10
14
|
interface SSESubscription {
|
|
11
15
|
abort: () => void;
|
|
12
16
|
}
|
|
17
|
+
export interface SubscribeSSEOptions {
|
|
18
|
+
transport?: OperatorTransportProfile;
|
|
19
|
+
transportEnv?: OperatorTransportEnv;
|
|
20
|
+
}
|
|
13
21
|
/**
|
|
14
22
|
* Subscribe to an SSE endpoint and invoke the callback for each parsed event.
|
|
15
23
|
*
|
|
16
24
|
* Automatically reconnects on connection loss with exponential backoff.
|
|
17
25
|
* Returns an object with an `abort()` method to cancel the subscription.
|
|
18
26
|
*
|
|
19
|
-
* @param path API path (e.g. "/trades/stream")
|
|
27
|
+
* @param path API path (e.g. "/v1/trades/stream")
|
|
20
28
|
* @param callback Called with each parsed event of type T
|
|
21
29
|
* @param onStatus Optional callback for connection status updates
|
|
30
|
+
* @param options Optional transport profile override
|
|
22
31
|
* @returns Subscription controller with abort method
|
|
23
32
|
*/
|
|
24
|
-
export declare function subscribeSSE<T>(path: string, callback: SSECallback<T>, onStatus?: SSEStatusCallback): SSESubscription;
|
|
33
|
+
export declare function subscribeSSE<T>(path: string, callback: SSECallback<T>, onStatus?: SSEStatusCallback, options?: SubscribeSSEOptions): SSESubscription;
|
|
25
34
|
export {};
|
|
26
35
|
//# sourceMappingURL=sse.d.ts.map
|
package/dist/sse.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../src/sse.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../src/sse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAIL,KAAK,oBAAoB,EACzB,KAAK,wBAAwB,EAC9B,MAAM,sBAAsB,CAAC;AAS9B,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;AAChD,MAAM,MAAM,iBAAiB,GAAG,CAC9B,MAAM,EAAE,WAAW,GAAG,cAAc,GAAG,cAAc,KAClD,IAAI,CAAC;AAEV,UAAU,eAAe;IACvB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,wBAAwB,CAAC;IACrC,YAAY,CAAC,EAAE,oBAAoB,CAAC;CACrC;AAID;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAC5B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,EACxB,QAAQ,CAAC,EAAE,iBAAiB,EAC5B,OAAO,CAAC,EAAE,mBAAmB,GAC5B,eAAe,CAsFjB"}
|
package/dist/sse.js
CHANGED
|
@@ -15,22 +15,86 @@ var __export = (target, all) => {
|
|
|
15
15
|
};
|
|
16
16
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
17
17
|
|
|
18
|
+
// src/operator-transport.ts
|
|
19
|
+
function stripTrailingSlashes(url) {
|
|
20
|
+
return url.replace(/\/+$/, "");
|
|
21
|
+
}
|
|
22
|
+
function parseTransport(raw) {
|
|
23
|
+
if (!raw)
|
|
24
|
+
return null;
|
|
25
|
+
const v = raw.trim().toLowerCase();
|
|
26
|
+
if (VALID_TRANSPORTS.has(v)) {
|
|
27
|
+
return v;
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
function resolveOperatorTransportProfile(env = process.env, options = {}) {
|
|
32
|
+
const accessClientId = env.CF_ACCESS_CLIENT_ID?.trim() ?? "";
|
|
33
|
+
const accessClientSecret = env.CF_ACCESS_CLIENT_SECRET?.trim() ?? "";
|
|
34
|
+
const hasAccess = Boolean(accessClientId && accessClientSecret);
|
|
35
|
+
const explicit = parseTransport(env.HOOX_TRANSPORT) ?? parseTransport(options.configTransport);
|
|
36
|
+
const transport = explicit ?? (hasAccess ? "access" : "public");
|
|
37
|
+
const apiFromEnv = env.HOOX_API_URL?.trim();
|
|
38
|
+
const apiFromConfig = options.configApiUrl?.trim();
|
|
39
|
+
const tokenFromEnv = env.HOOX_API_TOKEN?.trim();
|
|
40
|
+
const tokenFromConfig = options.configApiToken?.trim();
|
|
41
|
+
return {
|
|
42
|
+
transport,
|
|
43
|
+
apiBase: stripTrailingSlashes(apiFromEnv || apiFromConfig || DEFAULT_API_BASE),
|
|
44
|
+
bearerToken: tokenFromEnv || tokenFromConfig || "",
|
|
45
|
+
accessClientId,
|
|
46
|
+
accessClientSecret
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function buildOperatorAuthHeaders(profile) {
|
|
50
|
+
const headers = {};
|
|
51
|
+
if (profile.bearerToken) {
|
|
52
|
+
headers.Authorization = `Bearer ${profile.bearerToken}`;
|
|
53
|
+
}
|
|
54
|
+
const useAccessHeaders = profile.transport === "access" || Boolean(profile.accessClientId) && Boolean(profile.accessClientSecret);
|
|
55
|
+
if (useAccessHeaders && profile.accessClientId && profile.accessClientSecret) {
|
|
56
|
+
headers["CF-Access-Client-Id"] = profile.accessClientId;
|
|
57
|
+
headers["CF-Access-Client-Secret"] = profile.accessClientSecret;
|
|
58
|
+
}
|
|
59
|
+
return headers;
|
|
60
|
+
}
|
|
61
|
+
function hasOperatorClientCredentials(profile) {
|
|
62
|
+
if (profile.bearerToken)
|
|
63
|
+
return true;
|
|
64
|
+
return Boolean(profile.accessClientId && profile.accessClientSecret);
|
|
65
|
+
}
|
|
66
|
+
function operatorUrl(profile, path) {
|
|
67
|
+
const base = profile.apiBase.replace(/\/+$/, "");
|
|
68
|
+
const p = path.startsWith("/") ? path : `/${path}`;
|
|
69
|
+
return `${base}${p}`;
|
|
70
|
+
}
|
|
71
|
+
var DEFAULT_API_BASE = "http://localhost:8787", VALID_TRANSPORTS;
|
|
72
|
+
var init_operator_transport = __esm(() => {
|
|
73
|
+
VALID_TRANSPORTS = new Set([
|
|
74
|
+
"public",
|
|
75
|
+
"access",
|
|
76
|
+
"mtls",
|
|
77
|
+
"tunnel"
|
|
78
|
+
]);
|
|
79
|
+
});
|
|
80
|
+
|
|
18
81
|
// src/sse.ts
|
|
19
82
|
var exports_sse = {};
|
|
20
83
|
__export(exports_sse, {
|
|
21
84
|
subscribeSSE: () => subscribeSSE
|
|
22
85
|
});
|
|
23
|
-
function subscribeSSE(path, callback, onStatus) {
|
|
86
|
+
function subscribeSSE(path, callback, onStatus, options) {
|
|
24
87
|
let aborted = false;
|
|
88
|
+
const profile = options?.transport ?? (options?.transportEnv ? resolveOperatorTransportProfile(options.transportEnv) : resolveOperatorTransportProfile());
|
|
25
89
|
const run = async () => {
|
|
26
90
|
let attempt = 0;
|
|
27
91
|
while (!aborted && attempt < MAX_RECONNECT_ATTEMPTS) {
|
|
28
92
|
try {
|
|
29
|
-
const url =
|
|
93
|
+
const url = operatorUrl(profile, path);
|
|
30
94
|
const response = await fetch(url, {
|
|
31
95
|
headers: {
|
|
32
96
|
Accept: "text/event-stream",
|
|
33
|
-
...
|
|
97
|
+
...buildOperatorAuthHeaders(profile)
|
|
34
98
|
}
|
|
35
99
|
});
|
|
36
100
|
if (!response.ok || !response.body) {
|
|
@@ -59,7 +123,7 @@ function subscribeSSE(path, callback, onStatus) {
|
|
|
59
123
|
}
|
|
60
124
|
}
|
|
61
125
|
}
|
|
62
|
-
} catch
|
|
126
|
+
} catch {
|
|
63
127
|
if (aborted)
|
|
64
128
|
break;
|
|
65
129
|
onStatus?.("reconnecting");
|
|
@@ -79,10 +143,9 @@ function subscribeSSE(path, callback, onStatus) {
|
|
|
79
143
|
}
|
|
80
144
|
};
|
|
81
145
|
}
|
|
82
|
-
var
|
|
146
|
+
var RECONNECT_BASE_MS = 1000, RECONNECT_MAX_MS = 16000, MAX_RECONNECT_ATTEMPTS = 10;
|
|
83
147
|
var init_sse = __esm(() => {
|
|
84
|
-
|
|
85
|
-
API_TOKEN = process.env.HOOX_API_TOKEN || "";
|
|
148
|
+
init_operator_transport();
|
|
86
149
|
});
|
|
87
150
|
init_sse();
|
|
88
151
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-store.d.ts","sourceRoot":"","sources":["../../src/stores/config-store.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config-store.d.ts","sourceRoot":"","sources":["../../src/stores/config-store.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAoF3E,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,UAAU,EAAE,SAAS,CAAC;IACtB,aAAa,EAAE,uBAAuB,CAAC;IACvC,YAAY,EAAE,OAAO,CAAC;CACvB;AAID,UAAU,aAAa;IACrB,+DAA+D;IAC/D,YAAY,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IACtD,8CAA8C;IAC9C,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,yCAAyC;IACzC,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,8CAA8C;IAC9C,kBAAkB,EAAE,CAAC,OAAO,EAAE,MAAM,uBAAuB,KAAK,IAAI,CAAC;CACtE;AAiBD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;eAtClB,MAAM,GAAG,OAAO;2BACJ,MAAM;qBACZ,MAAM;;;;;;;;;;;;;;;;sBAKL,OAAO;sBAOP,CAAC,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI;uBAEtC,MAAM,IAAI;qBAEZ,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI;4BAE9B,CAAC,OAAO,EAAE,MAAM,uBAAuB,KAAK,IAAI;;;eApB7D,MAAM,GAAG,OAAO;2BACJ,MAAM;qBACZ,MAAM;;;;;;;;;;;;;;;;sBAKL,OAAO;sBAOP,CAAC,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI;uBAEtC,MAAM,IAAI;qBAEZ,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI;4BAE9B,CAAC,OAAO,EAAE,MAAM,uBAAuB,KAAK,IAAI;;EA+ErE,CAAC"}
|
|
@@ -15,16 +15,133 @@ var __export = (target, all) => {
|
|
|
15
15
|
};
|
|
16
16
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
17
17
|
|
|
18
|
+
// src/config.ts
|
|
19
|
+
import {
|
|
20
|
+
readFileSync,
|
|
21
|
+
writeFileSync,
|
|
22
|
+
existsSync,
|
|
23
|
+
mkdirSync,
|
|
24
|
+
chmodSync,
|
|
25
|
+
statSync
|
|
26
|
+
} 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
|
+
}
|
|
133
|
+
|
|
18
134
|
// src/stores/config-store.ts
|
|
19
135
|
import { create } from "zustand";
|
|
20
136
|
import { immer } from "zustand/middleware/immer";
|
|
21
137
|
import { persist, createJSONStorage } from "zustand/middleware";
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
138
|
+
import { chmodSync as chmodSync2, mkdirSync as mkdirSync2, existsSync as existsSync2 } from "fs";
|
|
139
|
+
import { homedir as homedir2 } from "os";
|
|
140
|
+
import { join as join2 } from "path";
|
|
24
141
|
var bunConfigStorage = {
|
|
25
142
|
getItem: async (_name) => {
|
|
26
143
|
try {
|
|
27
|
-
const file = Bun.file(
|
|
144
|
+
const file = Bun.file(join2(homedir2(), ".hoox", "config.json"));
|
|
28
145
|
const exists = await file.exists();
|
|
29
146
|
if (!exists)
|
|
30
147
|
return null;
|
|
@@ -34,12 +151,18 @@ var bunConfigStorage = {
|
|
|
34
151
|
}
|
|
35
152
|
},
|
|
36
153
|
setItem: async (_name, value) => {
|
|
37
|
-
const dir =
|
|
154
|
+
const dir = join2(homedir2(), ".hoox");
|
|
155
|
+
if (!existsSync2(dir)) {
|
|
156
|
+
mkdirSync2(dir, { recursive: true, mode: HOOX_DIR_MODE });
|
|
157
|
+
}
|
|
38
158
|
try {
|
|
39
|
-
|
|
159
|
+
chmodSync2(dir, HOOX_DIR_MODE);
|
|
40
160
|
} catch {}
|
|
41
|
-
const filePath =
|
|
161
|
+
const filePath = join2(dir, "config.json");
|
|
42
162
|
await Bun.write(filePath, value);
|
|
163
|
+
try {
|
|
164
|
+
chmodSync2(filePath, HOOX_CONFIG_FILE_MODE);
|
|
165
|
+
} catch {}
|
|
43
166
|
},
|
|
44
167
|
removeItem: async (_name) => {}
|
|
45
168
|
};
|
|
@@ -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":"AA6BA,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,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,SAAS,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,IAAI,CAAC;IACrC,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;AA0CD,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0BA5GR,gBAAgB;qBACrB,MAAM;0BACD,MAAM,GAAG,IAAI;oBAInB,MAAM;mBAEP,MAAM,GAAG,IAAI;;;;;;;;;;6BASH,MAAM;wBAEX,MAAM;wBAEN,MAAM,GAAG,IAAI;sBAMf,MAAM,OAAO,CAAC,IAAI,CAAC;sBACnB,MAAM,OAAO,CAAC,IAAI,CAAC;oBACrB,MAAM,OAAO,CAAC,IAAI,CAAC;kBACrB,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI;mBACrB,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,IAAI;6BACf,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI;sBACzC,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI;oBAC7B,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,IAAI;mBAChC,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI;iBACxB,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI;oBACpB,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI;iCAInB,MAAM,IAAI;iCAEV,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI;sBAEzC,MAAM,IAAI;oBAEZ,MAAM,IAAI;6BAMD,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,KAAK,IAAI;oBAMlD,MAAM,IAAI;0BAMJ,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0BAjElC,gBAAgB;qBACrB,MAAM;0BACD,MAAM,GAAG,IAAI;oBAInB,MAAM;mBAEP,MAAM,GAAG,IAAI;;;;;;;;;;6BASH,MAAM;wBAEX,MAAM;wBAEN,MAAM,GAAG,IAAI;sBAMf,MAAM,OAAO,CAAC,IAAI,CAAC;sBACnB,MAAM,OAAO,CAAC,IAAI,CAAC;oBACrB,MAAM,OAAO,CAAC,IAAI,CAAC;kBACrB,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI;mBACrB,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,IAAI;6BACf,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI;sBACzC,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI;oBAC7B,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,IAAI;mBAChC,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI;iBACxB,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI;oBACpB,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI;iCAInB,MAAM,IAAI;iCAEV,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI;sBAEzC,MAAM,IAAI;oBAEZ,MAAM,IAAI;6BAMD,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,KAAK,IAAI;oBAMlD,MAAM,IAAI;0BAMJ,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI;;EA4UrD,CAAC"}
|