@hoox-sh/hoox-shared 1.2.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 +44 -0
- package/dist/agent-config-fields.d.ts +32 -0
- package/dist/agent-config-fields.d.ts.map +1 -0
- package/dist/agent-config-fields.js +220 -0
- package/dist/analytics.d.ts +47 -0
- package/dist/analytics.d.ts.map +1 -0
- package/dist/analytics.js +45 -0
- package/dist/api-client.d.ts +48 -0
- package/dist/api-client.d.ts.map +1 -0
- package/dist/api-client.js +191 -0
- package/dist/colors.d.ts +76 -0
- package/dist/colors.d.ts.map +1 -0
- package/dist/colors.js +82 -0
- package/dist/config.d.ts +61 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +146 -0
- package/dist/cron-handler.d.ts +38 -0
- package/dist/cron-handler.d.ts.map +1 -0
- package/dist/cron-handler.js +48 -0
- package/dist/d1/index.d.ts +9 -0
- package/dist/d1/index.d.ts.map +1 -0
- package/dist/d1/index.js +360 -0
- package/dist/d1/repository.d.ts +86 -0
- package/dist/d1/repository.d.ts.map +1 -0
- package/dist/d1/repository.js +297 -0
- package/dist/d1/schemas.d.ts +89 -0
- package/dist/d1/schemas.d.ts.map +1 -0
- package/dist/d1/schemas.js +81 -0
- package/dist/dashboard-manifest.d.ts +135 -0
- package/dist/dashboard-manifest.d.ts.map +1 -0
- package/dist/dashboard-manifest.js +401 -0
- package/dist/errors.d.ts +44 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +149 -0
- package/dist/exchange-client.d.ts +98 -0
- package/dist/exchange-client.d.ts.map +1 -0
- package/dist/exchange-client.js +107 -0
- package/dist/exchanges/base-exchange-client.d.ts +81 -0
- package/dist/exchanges/base-exchange-client.d.ts.map +1 -0
- package/dist/exchanges/base-exchange-client.js +123 -0
- package/dist/exchanges/index.d.ts +7 -0
- package/dist/exchanges/index.d.ts.map +1 -0
- package/dist/exchanges/index.js +123 -0
- package/dist/exchanges/types.d.ts +23 -0
- package/dist/exchanges/types.d.ts.map +1 -0
- package/dist/exchanges/types.js +1 -0
- package/dist/format-time.d.ts +28 -0
- package/dist/format-time.d.ts.map +1 -0
- package/dist/format-time.js +57 -0
- package/dist/formatters.d.ts +36 -0
- package/dist/formatters.d.ts.map +1 -0
- package/dist/formatters.js +155 -0
- package/dist/health.d.ts +19 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +160 -0
- package/dist/index.d.ts +72 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4198 -0
- package/dist/kvKeys.d.ts +76 -0
- package/dist/kvKeys.d.ts.map +1 -0
- package/dist/kvKeys.js +107 -0
- package/dist/kvUtils.d.ts +30 -0
- package/dist/kvUtils.d.ts.map +1 -0
- package/dist/kvUtils.js +170 -0
- package/dist/legal.d.ts +15 -0
- package/dist/legal.d.ts.map +1 -0
- package/dist/legal.js +40 -0
- package/dist/middleware/auth.d.ts +102 -0
- package/dist/middleware/auth.d.ts.map +1 -0
- package/dist/middleware/auth.js +151 -0
- package/dist/middleware/cors.d.ts +58 -0
- package/dist/middleware/cors.d.ts.map +1 -0
- package/dist/middleware/cors.js +77 -0
- package/dist/middleware/index.d.ts +14 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +635 -0
- package/dist/middleware/logger.d.ts +17 -0
- package/dist/middleware/logger.d.ts.map +1 -0
- package/dist/middleware/logger.js +202 -0
- package/dist/middleware/rate-limit.d.ts +30 -0
- package/dist/middleware/rate-limit.d.ts.map +1 -0
- package/dist/middleware/rate-limit.js +181 -0
- package/dist/middleware/security-headers.d.ts +43 -0
- package/dist/middleware/security-headers.d.ts.map +1 -0
- package/dist/middleware/security-headers.js +58 -0
- package/dist/middleware/validate.d.ts +25 -0
- package/dist/middleware/validate.d.ts.map +1 -0
- package/dist/middleware/validate.js +56 -0
- package/dist/operator-transport.d.ts +65 -0
- package/dist/operator-transport.d.ts.map +1 -0
- package/dist/operator-transport.js +87 -0
- package/dist/path-utils.d.ts +190 -0
- package/dist/path-utils.d.ts.map +1 -0
- package/dist/path-utils.js +188 -0
- package/dist/queue-handler.d.ts +47 -0
- package/dist/queue-handler.d.ts.map +1 -0
- package/dist/queue-handler.js +46 -0
- package/dist/router.d.ts +15 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +130 -0
- package/dist/schemas/index.d.ts +8 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +705 -0
- package/dist/schemas/registry.d.ts +12 -0
- package/dist/schemas/registry.d.ts.map +1 -0
- package/dist/schemas/registry.js +433 -0
- package/dist/schemas/types.d.ts +83 -0
- package/dist/schemas/types.d.ts.map +1 -0
- package/dist/schemas/types.js +1 -0
- package/dist/schemas/validators.d.ts +39 -0
- package/dist/schemas/validators.d.ts.map +1 -0
- package/dist/schemas/validators.js +290 -0
- package/dist/service-bindings.d.ts +78 -0
- package/dist/service-bindings.d.ts.map +1 -0
- package/dist/service-bindings.js +248 -0
- package/dist/session.d.ts +39 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +261 -0
- package/dist/sse.d.ts +39 -0
- package/dist/sse.d.ts.map +1 -0
- package/dist/sse.js +154 -0
- package/dist/stores/config-store.d.ts +91 -0
- package/dist/stores/config-store.d.ts.map +1 -0
- package/dist/stores/config-store.js +255 -0
- package/dist/stores/service-store.d.ts +266 -0
- package/dist/stores/service-store.d.ts.map +1 -0
- package/dist/stores/service-store.js +516 -0
- package/dist/stores/ui-store.d.ts +67 -0
- package/dist/stores/ui-store.d.ts.map +1 -0
- package/dist/stores/ui-store.js +62 -0
- package/dist/test-utils.d.ts +136 -0
- package/dist/test-utils.d.ts.map +1 -0
- package/dist/test-utils.js +128 -0
- package/dist/types/errors.d.ts +20 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/errors.js +1 -0
- package/dist/types/router.d.ts +36 -0
- package/dist/types/router.d.ts.map +1 -0
- package/dist/types/router.js +1 -0
- package/dist/types.d.ts +442 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +83 -0
- package/dist/wizard/engine.d.ts +46 -0
- package/dist/wizard/engine.d.ts.map +1 -0
- package/dist/wizard/engine.js +525 -0
- package/dist/wizard/index.d.ts +11 -0
- package/dist/wizard/index.d.ts.map +1 -0
- package/dist/wizard/index.js +544 -0
- package/dist/wizard/persistence.d.ts +18 -0
- package/dist/wizard/persistence.d.ts.map +1 -0
- package/dist/wizard/persistence.js +31 -0
- package/dist/wizard/presets.d.ts +38 -0
- package/dist/wizard/presets.d.ts.map +1 -0
- package/dist/wizard/presets.js +223 -0
- package/dist/wizard/provisioner.d.ts +15 -0
- package/dist/wizard/provisioner.d.ts.map +1 -0
- package/dist/wizard/provisioner.js +1 -0
- package/dist/wizard/types.d.ts +76 -0
- package/dist/wizard/types.d.ts.map +1 -0
- package/dist/wizard/types.js +1 -0
- package/package.json +117 -0
package/dist/session.js
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __returnValue = (v) => v;
|
|
4
|
+
function __exportSetter(name, newValue) {
|
|
5
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
6
|
+
}
|
|
7
|
+
var __export = (target, all) => {
|
|
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);
|
|
17
|
+
|
|
18
|
+
// src/path-utils.ts
|
|
19
|
+
import { existsSync } from "fs";
|
|
20
|
+
import { homedir } from "os";
|
|
21
|
+
import { dirname, join, resolve } from "path";
|
|
22
|
+
function createHooxPath(path) {
|
|
23
|
+
return path;
|
|
24
|
+
}
|
|
25
|
+
function getHooxHome() {
|
|
26
|
+
try {
|
|
27
|
+
const override = process.env.HOOX_HOME?.trim();
|
|
28
|
+
if (override) {
|
|
29
|
+
return createHooxPath(resolve(override));
|
|
30
|
+
}
|
|
31
|
+
const home = homedir();
|
|
32
|
+
if (!home || home.length === 0) {
|
|
33
|
+
return createHooxPath(resolve(process.cwd(), ".hoox"));
|
|
34
|
+
}
|
|
35
|
+
return createHooxPath(join(home, ".hoox"));
|
|
36
|
+
} catch {
|
|
37
|
+
return createHooxPath(resolve(process.cwd(), ".hoox"));
|
|
38
|
+
}
|
|
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
|
+
}
|
|
118
|
+
function resolveHooxPath(relativePath) {
|
|
119
|
+
if (!relativePath || typeof relativePath !== "string") {
|
|
120
|
+
throw new Error("relativePath must be a non-empty string");
|
|
121
|
+
}
|
|
122
|
+
if (relativePath.includes("..")) {
|
|
123
|
+
throw new Error(`Path traversal detected in relativePath: "${relativePath}"`);
|
|
124
|
+
}
|
|
125
|
+
const normalizedPath = relativePath.replace(/\\/g, "/");
|
|
126
|
+
const hooxHome = getHooxHome();
|
|
127
|
+
const fullPath = join(hooxHome, normalizedPath);
|
|
128
|
+
const resolvedPath = resolve(fullPath);
|
|
129
|
+
const resolvedHome = resolve(hooxHome);
|
|
130
|
+
if (!resolvedPath.startsWith(resolvedHome)) {
|
|
131
|
+
throw new Error(`Resolved path "${resolvedPath}" is outside Hoox home directory`);
|
|
132
|
+
}
|
|
133
|
+
return createHooxPath(resolvedPath);
|
|
134
|
+
}
|
|
135
|
+
function isWithinHooxHome(path) {
|
|
136
|
+
try {
|
|
137
|
+
const hooxHome = getHooxHome();
|
|
138
|
+
const resolvedPath = resolve(path);
|
|
139
|
+
const resolvedHome = resolve(hooxHome);
|
|
140
|
+
return resolvedPath.startsWith(resolvedHome);
|
|
141
|
+
} catch {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function getRelativeHooxPath(absolutePath) {
|
|
146
|
+
try {
|
|
147
|
+
if (!isWithinHooxHome(absolutePath)) {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
const hooxHome = getHooxHome();
|
|
151
|
+
const resolvedPath = resolve(absolutePath);
|
|
152
|
+
const resolvedHome = resolve(hooxHome);
|
|
153
|
+
const relativePath = resolvedPath.slice(resolvedHome.length);
|
|
154
|
+
return relativePath.startsWith("/") || relativePath.startsWith("\\") ? relativePath.slice(1) : relativePath;
|
|
155
|
+
} catch {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function getHooxRepoPath() {
|
|
160
|
+
return resolveHooxPath("repo");
|
|
161
|
+
}
|
|
162
|
+
function getHooxConfigDir() {
|
|
163
|
+
return resolveHooxPath("config");
|
|
164
|
+
}
|
|
165
|
+
function getHooxDataDir() {
|
|
166
|
+
return resolveHooxPath("data");
|
|
167
|
+
}
|
|
168
|
+
function getHooxWranglerPath() {
|
|
169
|
+
return resolveHooxPath("config/wrangler.jsonc");
|
|
170
|
+
}
|
|
171
|
+
function getHooxStatePath() {
|
|
172
|
+
return resolveHooxPath("data/state.json");
|
|
173
|
+
}
|
|
174
|
+
|
|
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();
|
|
187
|
+
var TUI_STATE_DIR = ".tui-state";
|
|
188
|
+
function getSessionFilePath() {
|
|
189
|
+
try {
|
|
190
|
+
const hooxHome = getHooxHome();
|
|
191
|
+
return `${hooxHome}/${TUI_STATE_DIR}/session.json`;
|
|
192
|
+
} catch {
|
|
193
|
+
return `${process.cwd()}/${TUI_STATE_DIR}/session.json`;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
var DEFAULT_SESSION = {
|
|
197
|
+
activeView: "dashboard",
|
|
198
|
+
sidebarExpanded: true,
|
|
199
|
+
windowSize: { cols: 80, rows: 24 },
|
|
200
|
+
lastData: 0,
|
|
201
|
+
savedAt: new Date().toISOString()
|
|
202
|
+
};
|
|
203
|
+
async function saveSession(activeView, sidebarExpanded, windowSize, lastData) {
|
|
204
|
+
try {
|
|
205
|
+
const session = {
|
|
206
|
+
activeView,
|
|
207
|
+
sidebarExpanded,
|
|
208
|
+
windowSize,
|
|
209
|
+
lastData,
|
|
210
|
+
savedAt: new Date().toISOString()
|
|
211
|
+
};
|
|
212
|
+
await Bun.write(getSessionFilePath(), JSON.stringify(session, null, 2));
|
|
213
|
+
} catch (error) {
|
|
214
|
+
console.error("[session] Failed to save session:", error.message);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
async function restoreSession() {
|
|
218
|
+
try {
|
|
219
|
+
const file = Bun.file(getSessionFilePath());
|
|
220
|
+
const exists = await file.exists();
|
|
221
|
+
if (!exists)
|
|
222
|
+
return { ...DEFAULT_SESSION };
|
|
223
|
+
const raw = await file.text();
|
|
224
|
+
const result = SessionStateFileSchema.safeParse(JSON.parse(raw));
|
|
225
|
+
const parsed = result.success ? result.data : {};
|
|
226
|
+
return {
|
|
227
|
+
activeView: validateViewId(parsed.activeView) ? parsed.activeView : DEFAULT_SESSION.activeView,
|
|
228
|
+
sidebarExpanded: typeof parsed.sidebarExpanded === "boolean" ? parsed.sidebarExpanded : DEFAULT_SESSION.sidebarExpanded,
|
|
229
|
+
windowSize: parsed.windowSize ?? DEFAULT_SESSION.windowSize,
|
|
230
|
+
lastData: typeof parsed.lastData === "number" ? parsed.lastData : DEFAULT_SESSION.lastData,
|
|
231
|
+
savedAt: parsed.savedAt ?? DEFAULT_SESSION.savedAt
|
|
232
|
+
};
|
|
233
|
+
} catch {
|
|
234
|
+
return { ...DEFAULT_SESSION };
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
var VALID_VIEW_IDS = new Set([
|
|
238
|
+
"dashboard",
|
|
239
|
+
"workers",
|
|
240
|
+
"worker-detail",
|
|
241
|
+
"trade-monitor",
|
|
242
|
+
"logs-viewer",
|
|
243
|
+
"service-manager",
|
|
244
|
+
"config-editor",
|
|
245
|
+
"setup-wizard",
|
|
246
|
+
"settings",
|
|
247
|
+
"queue-depth",
|
|
248
|
+
"kv-viewer",
|
|
249
|
+
"secrets-viewer",
|
|
250
|
+
"db-query",
|
|
251
|
+
"ai-chat",
|
|
252
|
+
"edge-topology",
|
|
253
|
+
"worker-settings"
|
|
254
|
+
]);
|
|
255
|
+
function validateViewId(id) {
|
|
256
|
+
return typeof id === "string" && VALID_VIEW_IDS.has(id);
|
|
257
|
+
}
|
|
258
|
+
export {
|
|
259
|
+
saveSession,
|
|
260
|
+
restoreSession
|
|
261
|
+
};
|
package/dist/sse.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 HOOX · HOOX · jango-blockchained (hoox-sh)
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* SSE Streaming Client — subscribes to Server-Sent Events from the Hoox
|
|
7
|
+
* operator management API.
|
|
8
|
+
*
|
|
9
|
+
* Uses Bun's native fetch with ReadableStream reader for SSE parsing.
|
|
10
|
+
* Supports reconnection with exponential backoff.
|
|
11
|
+
* Events must be JSON-encoded in the "data:" field.
|
|
12
|
+
*
|
|
13
|
+
* Auth: operator transport profile (Bearer + optional Access service token).
|
|
14
|
+
*/
|
|
15
|
+
import { type OperatorTransportEnv, type OperatorTransportProfile } from "./operator-transport";
|
|
16
|
+
export type SSECallback<T> = (event: T) => void;
|
|
17
|
+
export type SSEStatusCallback = (status: "connected" | "reconnecting" | "disconnected") => void;
|
|
18
|
+
interface SSESubscription {
|
|
19
|
+
abort: () => void;
|
|
20
|
+
}
|
|
21
|
+
export interface SubscribeSSEOptions {
|
|
22
|
+
transport?: OperatorTransportProfile;
|
|
23
|
+
transportEnv?: OperatorTransportEnv;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Subscribe to an SSE endpoint and invoke the callback for each parsed event.
|
|
27
|
+
*
|
|
28
|
+
* Automatically reconnects on connection loss with exponential backoff.
|
|
29
|
+
* Returns an object with an `abort()` method to cancel the subscription.
|
|
30
|
+
*
|
|
31
|
+
* @param path API path (e.g. "/v1/trades/stream")
|
|
32
|
+
* @param callback Called with each parsed event of type T
|
|
33
|
+
* @param onStatus Optional callback for connection status updates
|
|
34
|
+
* @param options Optional transport profile override
|
|
35
|
+
* @returns Subscription controller with abort method
|
|
36
|
+
*/
|
|
37
|
+
export declare function subscribeSSE<T>(path: string, callback: SSECallback<T>, onStatus?: SSEStatusCallback, options?: SubscribeSSEOptions): SSESubscription;
|
|
38
|
+
export {};
|
|
39
|
+
//# sourceMappingURL=sse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../src/sse.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;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
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __returnValue = (v) => v;
|
|
4
|
+
function __exportSetter(name, newValue) {
|
|
5
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
6
|
+
}
|
|
7
|
+
var __export = (target, all) => {
|
|
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);
|
|
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
|
+
|
|
81
|
+
// src/sse.ts
|
|
82
|
+
var exports_sse = {};
|
|
83
|
+
__export(exports_sse, {
|
|
84
|
+
subscribeSSE: () => subscribeSSE
|
|
85
|
+
});
|
|
86
|
+
function subscribeSSE(path, callback, onStatus, options) {
|
|
87
|
+
let aborted = false;
|
|
88
|
+
const profile = options?.transport ?? (options?.transportEnv ? resolveOperatorTransportProfile(options.transportEnv) : resolveOperatorTransportProfile());
|
|
89
|
+
const run = async () => {
|
|
90
|
+
let attempt = 0;
|
|
91
|
+
while (!aborted && attempt < MAX_RECONNECT_ATTEMPTS) {
|
|
92
|
+
try {
|
|
93
|
+
const url = operatorUrl(profile, path);
|
|
94
|
+
const response = await fetch(url, {
|
|
95
|
+
headers: {
|
|
96
|
+
Accept: "text/event-stream",
|
|
97
|
+
...buildOperatorAuthHeaders(profile)
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
if (!response.ok || !response.body) {
|
|
101
|
+
throw new Error(`SSE connection failed: HTTP ${response.status}`);
|
|
102
|
+
}
|
|
103
|
+
attempt = 0;
|
|
104
|
+
onStatus?.("connected");
|
|
105
|
+
const reader = response.body.getReader();
|
|
106
|
+
const decoder = new TextDecoder;
|
|
107
|
+
let buffer = "";
|
|
108
|
+
while (!aborted) {
|
|
109
|
+
const { done, value } = await reader.read();
|
|
110
|
+
if (done)
|
|
111
|
+
break;
|
|
112
|
+
buffer += decoder.decode(value, { stream: true });
|
|
113
|
+
const lines = buffer.split(`
|
|
114
|
+
`);
|
|
115
|
+
buffer = lines.pop() || "";
|
|
116
|
+
for (const line of lines) {
|
|
117
|
+
const trimmed = line.trim();
|
|
118
|
+
if (trimmed.startsWith("data: ")) {
|
|
119
|
+
try {
|
|
120
|
+
const parsed = JSON.parse(trimmed.slice(6));
|
|
121
|
+
callback(parsed);
|
|
122
|
+
} catch {}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
} catch {
|
|
127
|
+
if (aborted)
|
|
128
|
+
break;
|
|
129
|
+
onStatus?.("reconnecting");
|
|
130
|
+
const delay = Math.min(RECONNECT_BASE_MS * Math.pow(2, attempt), RECONNECT_MAX_MS);
|
|
131
|
+
attempt++;
|
|
132
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (!aborted) {
|
|
136
|
+
onStatus?.("disconnected");
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
run();
|
|
140
|
+
return {
|
|
141
|
+
abort: () => {
|
|
142
|
+
aborted = true;
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
var RECONNECT_BASE_MS = 1000, RECONNECT_MAX_MS = 16000, MAX_RECONNECT_ATTEMPTS = 10;
|
|
147
|
+
var init_sse = __esm(() => {
|
|
148
|
+
init_operator_transport();
|
|
149
|
+
});
|
|
150
|
+
init_sse();
|
|
151
|
+
|
|
152
|
+
export {
|
|
153
|
+
subscribeSSE
|
|
154
|
+
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 HOOX · HOOX · jango-blockchained (hoox-sh)
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import type { ViewId, LogFilter, NotificationPreferences } from "../types";
|
|
6
|
+
export interface ConfigState {
|
|
7
|
+
theme: "dark" | "light";
|
|
8
|
+
refreshIntervalMs: number;
|
|
9
|
+
defaultView: ViewId;
|
|
10
|
+
activeExchanges: string[];
|
|
11
|
+
keyboardShortcuts: Record<string, string>;
|
|
12
|
+
logFilters: LogFilter;
|
|
13
|
+
notifications: NotificationPreferences;
|
|
14
|
+
soundEnabled: boolean;
|
|
15
|
+
}
|
|
16
|
+
interface ConfigActions {
|
|
17
|
+
/** Merge partial config — only provided fields are updated. */
|
|
18
|
+
updateConfig: (partial: Partial<ConfigState>) => void;
|
|
19
|
+
/** Reset all settings to factory defaults. */
|
|
20
|
+
resetDefaults: () => void;
|
|
21
|
+
/** Update a single keyboard shortcut. */
|
|
22
|
+
setShortcut: (action: string, key: string) => void;
|
|
23
|
+
/** Toggle a specific notification channel. */
|
|
24
|
+
toggleNotification: (channel: keyof NotificationPreferences) => void;
|
|
25
|
+
}
|
|
26
|
+
export declare const useConfigStore: import("zustand").UseBoundStore<Omit<Omit<import("zustand").StoreApi<ConfigState & ConfigActions>, "setState" | "persist"> & {
|
|
27
|
+
setState(partial: (ConfigState & ConfigActions) | Partial<ConfigState & ConfigActions> | ((state: ConfigState & ConfigActions) => (ConfigState & ConfigActions) | Partial<ConfigState & ConfigActions>), replace?: false | undefined): unknown;
|
|
28
|
+
setState(state: (ConfigState & ConfigActions) | ((state: ConfigState & ConfigActions) => ConfigState & ConfigActions), replace: true): unknown;
|
|
29
|
+
persist: {
|
|
30
|
+
setOptions: (options: Partial<import("zustand/middleware").PersistOptions<ConfigState & ConfigActions, unknown, unknown>>) => void;
|
|
31
|
+
clearStorage: () => void;
|
|
32
|
+
rehydrate: () => Promise<void> | void;
|
|
33
|
+
hasHydrated: () => boolean;
|
|
34
|
+
onHydrate: (fn: (state: ConfigState & ConfigActions) => void) => () => void;
|
|
35
|
+
onFinishHydration: (fn: (state: ConfigState & ConfigActions) => void) => () => void;
|
|
36
|
+
getOptions: () => Partial<import("zustand/middleware").PersistOptions<ConfigState & ConfigActions, unknown, unknown>>;
|
|
37
|
+
};
|
|
38
|
+
}, "setState"> & {
|
|
39
|
+
setState(nextStateOrUpdater: (ConfigState & ConfigActions) | Partial<ConfigState & ConfigActions> | ((state: {
|
|
40
|
+
theme: "dark" | "light";
|
|
41
|
+
refreshIntervalMs: number;
|
|
42
|
+
defaultView: ViewId;
|
|
43
|
+
activeExchanges: string[];
|
|
44
|
+
keyboardShortcuts: {
|
|
45
|
+
[x: string]: string;
|
|
46
|
+
};
|
|
47
|
+
logFilters: {
|
|
48
|
+
levels: import("..").LogLevel[];
|
|
49
|
+
workers: string[];
|
|
50
|
+
searchText: string;
|
|
51
|
+
};
|
|
52
|
+
notifications: {
|
|
53
|
+
alerts: boolean;
|
|
54
|
+
trades: boolean;
|
|
55
|
+
debug: boolean;
|
|
56
|
+
system: boolean;
|
|
57
|
+
};
|
|
58
|
+
soundEnabled: boolean;
|
|
59
|
+
updateConfig: (partial: Partial<ConfigState>) => void;
|
|
60
|
+
resetDefaults: () => void;
|
|
61
|
+
setShortcut: (action: string, key: string) => void;
|
|
62
|
+
toggleNotification: (channel: keyof NotificationPreferences) => void;
|
|
63
|
+
}) => void), shouldReplace?: false): unknown;
|
|
64
|
+
setState(nextStateOrUpdater: (ConfigState & ConfigActions) | ((state: {
|
|
65
|
+
theme: "dark" | "light";
|
|
66
|
+
refreshIntervalMs: number;
|
|
67
|
+
defaultView: ViewId;
|
|
68
|
+
activeExchanges: string[];
|
|
69
|
+
keyboardShortcuts: {
|
|
70
|
+
[x: string]: string;
|
|
71
|
+
};
|
|
72
|
+
logFilters: {
|
|
73
|
+
levels: import("..").LogLevel[];
|
|
74
|
+
workers: string[];
|
|
75
|
+
searchText: string;
|
|
76
|
+
};
|
|
77
|
+
notifications: {
|
|
78
|
+
alerts: boolean;
|
|
79
|
+
trades: boolean;
|
|
80
|
+
debug: boolean;
|
|
81
|
+
system: boolean;
|
|
82
|
+
};
|
|
83
|
+
soundEnabled: boolean;
|
|
84
|
+
updateConfig: (partial: Partial<ConfigState>) => void;
|
|
85
|
+
resetDefaults: () => void;
|
|
86
|
+
setShortcut: (action: string, key: string) => void;
|
|
87
|
+
toggleNotification: (channel: keyof NotificationPreferences) => void;
|
|
88
|
+
}) => void), shouldReplace: true): unknown;
|
|
89
|
+
}>;
|
|
90
|
+
export {};
|
|
91
|
+
//# sourceMappingURL=config-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-store.d.ts","sourceRoot":"","sources":["../../src/stores/config-store.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAiBH,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"}
|