@jango-blockchained/hoox-shared 1.0.8 → 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 -2
- 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 -25
- package/dist/colors.d.ts.map +1 -1
- package/dist/colors.js +60 -20
- 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 +34 -0
- package/dist/cron-handler.d.ts.map +1 -0
- package/dist/cron-handler.js +48 -0
- package/dist/d1/index.js +50 -6
- package/dist/d1/repository.d.ts +5 -0
- package/dist/d1/repository.d.ts.map +1 -1
- package/dist/d1/repository.js +297 -0
- package/dist/d1/schemas.js +81 -0
- package/dist/errors.d.ts +1 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +48 -5
- package/dist/exchanges/base-exchange-client.d.ts +68 -0
- package/dist/exchanges/base-exchange-client.d.ts.map +1 -0
- package/dist/exchanges/base-exchange-client.js +120 -0
- package/dist/exchanges/index.d.ts +3 -0
- package/dist/exchanges/index.d.ts.map +1 -0
- package/dist/exchanges/index.js +120 -0
- package/dist/exchanges/types.d.ts +19 -0
- package/dist/exchanges/types.d.ts.map +1 -0
- package/dist/exchanges/types.js +1 -0
- package/dist/health.js +48 -5
- package/dist/index.d.ts +30 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1058 -73
- package/dist/kvUtils.js +48 -5
- package/dist/middleware/auth.d.ts +46 -7
- 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 +361 -101
- package/dist/middleware/logger.d.ts +2 -1
- package/dist/middleware/logger.d.ts.map +1 -1
- package/dist/middleware/logger.js +202 -0
- package/dist/middleware/rate-limit.d.ts +3 -1
- 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 +205 -0
- package/dist/path-utils.d.ts.map +1 -0
- package/dist/path-utils.js +188 -0
- package/dist/queue-handler.d.ts +43 -0
- package/dist/queue-handler.d.ts.map +1 -0
- package/dist/queue-handler.js +46 -0
- package/dist/router.d.ts +2 -2
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +15 -8
- 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 +68 -26
- package/dist/service-bindings.d.ts.map +1 -1
- package/dist/service-bindings.js +219 -2
- package/dist/session.d.ts +9 -5
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +179 -4
- 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 +50 -1
- package/dist/stores/service-store.d.ts.map +1 -1
- package/dist/stores/service-store.js +162 -27
- package/dist/test-utils.d.ts +132 -0
- package/dist/test-utils.d.ts.map +1 -0
- package/dist/test-utils.js +128 -0
- package/dist/types/router.d.ts +18 -8
- package/dist/types/router.d.ts.map +1 -1
- package/dist/types.d.ts +124 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +11 -0
- package/dist/wizard/engine.d.ts.map +1 -1
- 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 +46 -12
|
@@ -1,32 +1,74 @@
|
|
|
1
|
+
import type { InternalAuthKeyName } from "./middleware/auth";
|
|
2
|
+
export interface ServiceBinding {
|
|
3
|
+
fetch(request: Request | string, init?: RequestInit): Promise<Response>;
|
|
4
|
+
}
|
|
5
|
+
/** Env binding names for scoped internal auth keys. */
|
|
6
|
+
export declare const InternalAuthKeyFields: {
|
|
7
|
+
readonly DEFAULT: "INTERNAL_KEY_BINDING";
|
|
8
|
+
readonly D1_READ: "D1_READ_KEY_BINDING";
|
|
9
|
+
readonly D1_WRITE: "D1_WRITE_KEY_BINDING";
|
|
10
|
+
readonly TRADE_EXECUTE: "TRADE_EXECUTE_KEY_BINDING";
|
|
11
|
+
readonly TRADE_READ: "TRADE_READ_KEY_BINDING";
|
|
12
|
+
readonly TELEGRAM_ALERT: "TELEGRAM_INTERNAL_KEY_BINDING";
|
|
13
|
+
readonly WALLET_EXECUTE: "WALLET_EXECUTE_KEY_BINDING";
|
|
14
|
+
readonly AGENT: "AGENT_INTERNAL_KEY";
|
|
15
|
+
/** Dashboard Pages secret aliases (legacy naming). */
|
|
16
|
+
readonly D1_INTERNAL_ALIAS: "D1_INTERNAL_KEY";
|
|
17
|
+
readonly TRADE_INTERNAL_ALIAS: "TRADE_INTERNAL_KEY";
|
|
18
|
+
readonly TELEGRAM_INTERNAL_ALIAS: "TELEGRAM_INTERNAL_KEY";
|
|
19
|
+
};
|
|
20
|
+
/** d1-worker read routes: prefer read-only key, fall back to legacy full key. */
|
|
21
|
+
export declare const D1_READ_AUTH_KEY_FIELDS: readonly ["D1_READ_KEY_BINDING", "INTERNAL_KEY_BINDING"];
|
|
22
|
+
/** d1-worker write/RPC routes: prefer write key, fall back to legacy full key. */
|
|
23
|
+
export declare const D1_WRITE_AUTH_KEY_FIELDS: readonly ["D1_WRITE_KEY_BINDING", "INTERNAL_KEY_BINDING"];
|
|
24
|
+
/** trade-worker execute routes (/webhook, /process, POST /api/signals). */
|
|
25
|
+
export declare const TRADE_EXECUTE_AUTH_KEY_FIELDS: readonly ["TRADE_EXECUTE_KEY_BINDING", "INTERNAL_KEY_BINDING", "AGENT_INTERNAL_KEY"];
|
|
26
|
+
/** trade-worker read routes (GET /api/signals, GET /report). */
|
|
27
|
+
export declare const TRADE_READ_AUTH_KEY_FIELDS: readonly ["TRADE_READ_KEY_BINDING", "INTERNAL_KEY_BINDING"];
|
|
28
|
+
/** telegram-worker /alert notification endpoint. */
|
|
29
|
+
export declare const TELEGRAM_ALERT_AUTH_KEY_FIELDS: readonly ["TELEGRAM_INTERNAL_KEY_BINDING", "INTERNAL_KEY_BINDING"];
|
|
30
|
+
/** web3-wallet-worker privileged routes. */
|
|
31
|
+
export declare const WALLET_EXECUTE_AUTH_KEY_FIELDS: readonly ["WALLET_EXECUTE_KEY_BINDING", "INTERNAL_KEY_BINDING"];
|
|
32
|
+
/** Dashboard → d1-worker read calls (includes Pages secret aliases). */
|
|
33
|
+
export declare const DASHBOARD_D1_READ_AUTH_KEY_FIELDS: readonly ["D1_READ_KEY_BINDING", "D1_INTERNAL_KEY", "INTERNAL_KEY_BINDING"];
|
|
34
|
+
/** Dashboard → trade-worker execute calls. */
|
|
35
|
+
export declare const DASHBOARD_TRADE_EXECUTE_AUTH_KEY_FIELDS: readonly ["TRADE_EXECUTE_KEY_BINDING", "TRADE_INTERNAL_KEY", "INTERNAL_KEY_BINDING"];
|
|
36
|
+
/** Dashboard → telegram-worker /alert calls. */
|
|
37
|
+
export declare const DASHBOARD_TELEGRAM_ALERT_AUTH_KEY_FIELDS: readonly ["TELEGRAM_INTERNAL_KEY_BINDING", "TELEGRAM_INTERNAL_KEY", "INTERNAL_KEY_BINDING"];
|
|
38
|
+
/** First configured key from an ordered fallback list. */
|
|
39
|
+
export declare function resolveInternalAuthKey(env: object, keyFields: InternalAuthKeyName): string | undefined;
|
|
40
|
+
export interface AuthenticatedServiceEnv {
|
|
41
|
+
INTERNAL_KEY_BINDING?: string;
|
|
42
|
+
D1_READ_KEY_BINDING?: string;
|
|
43
|
+
D1_WRITE_KEY_BINDING?: string;
|
|
44
|
+
TRADE_EXECUTE_KEY_BINDING?: string;
|
|
45
|
+
TRADE_READ_KEY_BINDING?: string;
|
|
46
|
+
TELEGRAM_INTERNAL_KEY_BINDING?: string;
|
|
47
|
+
WALLET_EXECUTE_KEY_BINDING?: string;
|
|
48
|
+
AGENT_INTERNAL_KEY?: string;
|
|
49
|
+
D1_INTERNAL_KEY?: string;
|
|
50
|
+
TRADE_INTERNAL_KEY?: string;
|
|
51
|
+
TELEGRAM_INTERNAL_KEY?: string;
|
|
52
|
+
}
|
|
53
|
+
export declare class ServiceAuthError extends Error {
|
|
54
|
+
constructor(message: string);
|
|
55
|
+
}
|
|
1
56
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* Uses `Fetcher.fetch(url, init)` directly — avoids the `as unknown as Request`
|
|
5
|
-
* anti-pattern and inconsistent URL schemes used across workers
|
|
6
|
-
* (http://trade-service/webhook, http://localhost/query, https://internal/webhook, etc.).
|
|
7
|
-
*
|
|
8
|
-
* Convention: URL path matches the route the target worker serves.
|
|
9
|
-
* Defaults to POST with JSON Content-Type body.
|
|
10
|
-
*
|
|
11
|
-
* Note: Uses `any` for the binding parameter to avoid `@cloudflare/workers-types`
|
|
12
|
-
* `Fetcher` type incompatibilities that can arise when different workspace
|
|
13
|
-
* packages resolve distinct instances of the types package. At runtime, service
|
|
14
|
-
* bindings from the Workers runtime always have a compatible `fetch` method.
|
|
15
|
-
*
|
|
16
|
-
* @example
|
|
17
|
-
* // POST with JSON body (default)
|
|
18
|
-
* const response = await serviceFetch(env.TRADE_SERVICE, "/webhook", payload);
|
|
19
|
-
*
|
|
20
|
-
* // POST with extra headers
|
|
21
|
-
* const response = await serviceFetch(env.D1_SERVICE, "/query", { query, params }, {
|
|
22
|
-
* headers: { "X-Request-ID": requestId },
|
|
23
|
-
* });
|
|
24
|
-
*
|
|
25
|
-
* // GET request (no body)
|
|
26
|
-
* const response = await serviceFetch(env.D1_SERVICE, "/health", undefined, { method: "GET" });
|
|
57
|
+
* serviceFetch with fail-closed internal auth.
|
|
58
|
+
* Injects X-Internal-Auth-Key from env.INTERNAL_KEY_BINDING.
|
|
27
59
|
*/
|
|
28
|
-
export declare function
|
|
60
|
+
export declare function authenticatedServiceFetch<E extends AuthenticatedServiceEnv>(binding: ServiceBinding, env: E, path: string, body?: unknown, options?: {
|
|
29
61
|
method?: string;
|
|
30
62
|
headers?: Record<string, string>;
|
|
63
|
+
timeout?: number;
|
|
64
|
+
/** Override env key (e.g. TELEGRAM_INTERNAL_KEY_BINDING, AGENT_INTERNAL_KEY) */
|
|
65
|
+
internalKey?: string;
|
|
66
|
+
/** Ordered env fields to try when internalKey is not set */
|
|
67
|
+
internalKeyFields?: InternalAuthKeyName;
|
|
68
|
+
}): Promise<Response>;
|
|
69
|
+
export declare function serviceFetch(binding: ServiceBinding, path: string, body?: unknown, options?: {
|
|
70
|
+
method?: string;
|
|
71
|
+
headers?: Record<string, string>;
|
|
72
|
+
timeout?: number;
|
|
31
73
|
}): Promise<Response>;
|
|
32
74
|
//# sourceMappingURL=service-bindings.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service-bindings.d.ts","sourceRoot":"","sources":["../src/service-bindings.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"service-bindings.d.ts","sourceRoot":"","sources":["../src/service-bindings.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAmB,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAE9E,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CACzE;AAED,uDAAuD;AACvD,eAAO,MAAM,qBAAqB;;;;;;;;;IAShC,sDAAsD;;;;CAI9C,CAAC;AAEX,iFAAiF;AACjF,eAAO,MAAM,uBAAuB,0DAG1B,CAAC;AAEX,kFAAkF;AAClF,eAAO,MAAM,wBAAwB,2DAG3B,CAAC;AAEX,2EAA2E;AAC3E,eAAO,MAAM,6BAA6B,sFAIhC,CAAC;AAEX,gEAAgE;AAChE,eAAO,MAAM,0BAA0B,6DAG7B,CAAC;AAEX,oDAAoD;AACpD,eAAO,MAAM,8BAA8B,oEAGjC,CAAC;AAEX,4CAA4C;AAC5C,eAAO,MAAM,8BAA8B,iEAGjC,CAAC;AAEX,wEAAwE;AACxE,eAAO,MAAM,iCAAiC,6EAIpC,CAAC;AAEX,8CAA8C;AAC9C,eAAO,MAAM,uCAAuC,sFAI1C,CAAC;AAEX,gDAAgD;AAChD,eAAO,MAAM,wCAAwC,6FAI3C,CAAC;AAEX,0DAA0D;AAC1D,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,mBAAmB,GAC7B,MAAM,GAAG,SAAS,CAEpB;AAED,MAAM,WAAW,uBAAuB;IACtC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,6BAA6B,CAAC,EAAE,MAAM,CAAC;IACvC,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,OAAO,EAAE,MAAM;CAI5B;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,CAAC,SAAS,uBAAuB,EACzE,OAAO,EAAE,cAAc,EACvB,GAAG,EAAE,CAAC,EACN,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,OAAO,EACd,OAAO,CAAC,EAAE;IACR,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gFAAgF;IAChF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,iBAAiB,CAAC,EAAE,mBAAmB,CAAC;CACzC,GACA,OAAO,CAAC,QAAQ,CAAC,CAsBnB;AAED,wBAAgB,YAAY,CAC1B,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,OAAO,EACd,OAAO,CAAC,EAAE;IACR,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GACA,OAAO,CAAC,QAAQ,CAAC,CAWnB"}
|
package/dist/service-bindings.js
CHANGED
|
@@ -15,17 +15,234 @@ var __export = (target, all) => {
|
|
|
15
15
|
};
|
|
16
16
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
17
17
|
|
|
18
|
+
// src/middleware/auth.ts
|
|
19
|
+
function timingSafeEqual(a, b) {
|
|
20
|
+
const encoder = new TextEncoder;
|
|
21
|
+
const aBuf = encoder.encode(a);
|
|
22
|
+
const bBuf = encoder.encode(b);
|
|
23
|
+
const len = Math.max(aBuf.length, bBuf.length);
|
|
24
|
+
let result = aBuf.length === bBuf.length ? 0 : 1;
|
|
25
|
+
for (let i = 0;i < len; i++) {
|
|
26
|
+
const av = i < aBuf.length ? aBuf[i] : 0;
|
|
27
|
+
const bv = i < bBuf.length ? bBuf[i] : 0;
|
|
28
|
+
result |= av ^ bv;
|
|
29
|
+
}
|
|
30
|
+
return result === 0;
|
|
31
|
+
}
|
|
32
|
+
function resolveOperatorApiKey(env) {
|
|
33
|
+
const preferred = env.OPERATOR_API_KEY;
|
|
34
|
+
if (typeof preferred === "string" && preferred.length > 0) {
|
|
35
|
+
return preferred;
|
|
36
|
+
}
|
|
37
|
+
const legacy = env.INTERNAL_API_KEY;
|
|
38
|
+
if (typeof legacy === "string" && legacy.length > 0) {
|
|
39
|
+
return legacy;
|
|
40
|
+
}
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
async function requireAuth(request, env) {
|
|
44
|
+
return requireOperatorAuth(request, env);
|
|
45
|
+
}
|
|
46
|
+
async function requireOperatorAuth(request, env) {
|
|
47
|
+
const apiKey = resolveOperatorApiKey(env);
|
|
48
|
+
if (!apiKey) {
|
|
49
|
+
return new Response(JSON.stringify({
|
|
50
|
+
error: "Operator API key not configured",
|
|
51
|
+
hint: "Set OPERATOR_API_KEY (preferred) or INTERNAL_API_KEY on the Worker"
|
|
52
|
+
}), { status: 401, headers: { "Content-Type": "application/json" } });
|
|
53
|
+
}
|
|
54
|
+
const authHeader = request.headers.get("Authorization");
|
|
55
|
+
const expectedHeader = `Bearer ${apiKey}`;
|
|
56
|
+
if (!authHeader || !timingSafeEqual(authHeader, expectedHeader)) {
|
|
57
|
+
return new Response(JSON.stringify({ error: "Unauthorized" }), {
|
|
58
|
+
status: 401,
|
|
59
|
+
headers: { "Content-Type": "application/json" }
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
function createOperatorAuthMiddleware() {
|
|
65
|
+
return async (request, env, _ctx) => {
|
|
66
|
+
const denied = await requireOperatorAuth(request, env);
|
|
67
|
+
if (denied)
|
|
68
|
+
return denied;
|
|
69
|
+
return;
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function normalizeKeyNames(keyName) {
|
|
73
|
+
if (typeof keyName === "string") {
|
|
74
|
+
return [keyName];
|
|
75
|
+
}
|
|
76
|
+
return [...keyName];
|
|
77
|
+
}
|
|
78
|
+
function collectInternalAuthKeys(env, keyNames) {
|
|
79
|
+
const keys = [];
|
|
80
|
+
for (const name of normalizeKeyNames(keyNames)) {
|
|
81
|
+
const value = env[name];
|
|
82
|
+
if (typeof value === "string" && value.length > 0) {
|
|
83
|
+
keys.push(value);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return keys;
|
|
87
|
+
}
|
|
88
|
+
function matchesAnyInternalAuthKey(providedKey, expectedKeys) {
|
|
89
|
+
for (const expected of expectedKeys) {
|
|
90
|
+
if (timingSafeEqual(providedKey, expected)) {
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
function internalAuthNotConfiguredResponse(keyNames) {
|
|
97
|
+
const label = normalizeKeyNames(keyNames).join(" | ");
|
|
98
|
+
return new Response(JSON.stringify({
|
|
99
|
+
success: false,
|
|
100
|
+
error: `Internal auth key(s) not configured: ${label}`
|
|
101
|
+
}), { status: 401, headers: { "Content-Type": "application/json" } });
|
|
102
|
+
}
|
|
103
|
+
function requireInternalAuth(request, env, keyName = "INTERNAL_KEY_BINDING") {
|
|
104
|
+
const expectedKeys = collectInternalAuthKeys(env, keyName);
|
|
105
|
+
if (expectedKeys.length === 0) {
|
|
106
|
+
return internalAuthNotConfiguredResponse(keyName);
|
|
107
|
+
}
|
|
108
|
+
const providedKey = request.headers.get("X-Internal-Auth-Key");
|
|
109
|
+
if (!providedKey || !matchesAnyInternalAuthKey(providedKey, expectedKeys)) {
|
|
110
|
+
return new Response(JSON.stringify({ success: false, error: "Unauthorized" }), { status: 401, headers: { "Content-Type": "application/json" } });
|
|
111
|
+
}
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
function createInternalAuthMiddleware(keyName = "INTERNAL_KEY_BINDING") {
|
|
115
|
+
return async (request, env, _ctx) => {
|
|
116
|
+
const expectedKeys = collectInternalAuthKeys(env, keyName);
|
|
117
|
+
if (expectedKeys.length === 0) {
|
|
118
|
+
return internalAuthNotConfiguredResponse(keyName);
|
|
119
|
+
}
|
|
120
|
+
const providedKey = request.headers.get("X-Internal-Auth-Key");
|
|
121
|
+
if (!providedKey || !matchesAnyInternalAuthKey(providedKey, expectedKeys)) {
|
|
122
|
+
return new Response(JSON.stringify({ success: false, error: "Unauthorized" }), { status: 401, headers: { "Content-Type": "application/json" } });
|
|
123
|
+
}
|
|
124
|
+
return;
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function checkInternalAuth(request, env, keyName = "INTERNAL_KEY_BINDING") {
|
|
128
|
+
const expectedKeys = collectInternalAuthKeys(env, keyName);
|
|
129
|
+
if (expectedKeys.length === 0) {
|
|
130
|
+
return {
|
|
131
|
+
authorized: false,
|
|
132
|
+
error: `${normalizeKeyNames(keyName).join(" | ")} not configured`
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
const providedKey = request.headers.get("X-Internal-Auth-Key");
|
|
136
|
+
if (!providedKey || !matchesAnyInternalAuthKey(providedKey, expectedKeys)) {
|
|
137
|
+
return { authorized: false, error: "Unauthorized" };
|
|
138
|
+
}
|
|
139
|
+
return { authorized: true };
|
|
140
|
+
}
|
|
141
|
+
|
|
18
142
|
// src/service-bindings.ts
|
|
143
|
+
var InternalAuthKeyFields = {
|
|
144
|
+
DEFAULT: "INTERNAL_KEY_BINDING",
|
|
145
|
+
D1_READ: "D1_READ_KEY_BINDING",
|
|
146
|
+
D1_WRITE: "D1_WRITE_KEY_BINDING",
|
|
147
|
+
TRADE_EXECUTE: "TRADE_EXECUTE_KEY_BINDING",
|
|
148
|
+
TRADE_READ: "TRADE_READ_KEY_BINDING",
|
|
149
|
+
TELEGRAM_ALERT: "TELEGRAM_INTERNAL_KEY_BINDING",
|
|
150
|
+
WALLET_EXECUTE: "WALLET_EXECUTE_KEY_BINDING",
|
|
151
|
+
AGENT: "AGENT_INTERNAL_KEY",
|
|
152
|
+
D1_INTERNAL_ALIAS: "D1_INTERNAL_KEY",
|
|
153
|
+
TRADE_INTERNAL_ALIAS: "TRADE_INTERNAL_KEY",
|
|
154
|
+
TELEGRAM_INTERNAL_ALIAS: "TELEGRAM_INTERNAL_KEY"
|
|
155
|
+
};
|
|
156
|
+
var D1_READ_AUTH_KEY_FIELDS = [
|
|
157
|
+
InternalAuthKeyFields.D1_READ,
|
|
158
|
+
InternalAuthKeyFields.DEFAULT
|
|
159
|
+
];
|
|
160
|
+
var D1_WRITE_AUTH_KEY_FIELDS = [
|
|
161
|
+
InternalAuthKeyFields.D1_WRITE,
|
|
162
|
+
InternalAuthKeyFields.DEFAULT
|
|
163
|
+
];
|
|
164
|
+
var TRADE_EXECUTE_AUTH_KEY_FIELDS = [
|
|
165
|
+
InternalAuthKeyFields.TRADE_EXECUTE,
|
|
166
|
+
InternalAuthKeyFields.DEFAULT,
|
|
167
|
+
InternalAuthKeyFields.AGENT
|
|
168
|
+
];
|
|
169
|
+
var TRADE_READ_AUTH_KEY_FIELDS = [
|
|
170
|
+
InternalAuthKeyFields.TRADE_READ,
|
|
171
|
+
InternalAuthKeyFields.DEFAULT
|
|
172
|
+
];
|
|
173
|
+
var TELEGRAM_ALERT_AUTH_KEY_FIELDS = [
|
|
174
|
+
InternalAuthKeyFields.TELEGRAM_ALERT,
|
|
175
|
+
InternalAuthKeyFields.DEFAULT
|
|
176
|
+
];
|
|
177
|
+
var WALLET_EXECUTE_AUTH_KEY_FIELDS = [
|
|
178
|
+
InternalAuthKeyFields.WALLET_EXECUTE,
|
|
179
|
+
InternalAuthKeyFields.DEFAULT
|
|
180
|
+
];
|
|
181
|
+
var DASHBOARD_D1_READ_AUTH_KEY_FIELDS = [
|
|
182
|
+
InternalAuthKeyFields.D1_READ,
|
|
183
|
+
InternalAuthKeyFields.D1_INTERNAL_ALIAS,
|
|
184
|
+
InternalAuthKeyFields.DEFAULT
|
|
185
|
+
];
|
|
186
|
+
var DASHBOARD_TRADE_EXECUTE_AUTH_KEY_FIELDS = [
|
|
187
|
+
InternalAuthKeyFields.TRADE_EXECUTE,
|
|
188
|
+
InternalAuthKeyFields.TRADE_INTERNAL_ALIAS,
|
|
189
|
+
InternalAuthKeyFields.DEFAULT
|
|
190
|
+
];
|
|
191
|
+
var DASHBOARD_TELEGRAM_ALERT_AUTH_KEY_FIELDS = [
|
|
192
|
+
InternalAuthKeyFields.TELEGRAM_ALERT,
|
|
193
|
+
InternalAuthKeyFields.TELEGRAM_INTERNAL_ALIAS,
|
|
194
|
+
InternalAuthKeyFields.DEFAULT
|
|
195
|
+
];
|
|
196
|
+
function resolveInternalAuthKey(env, keyFields) {
|
|
197
|
+
return collectInternalAuthKeys(env, keyFields)[0];
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
class ServiceAuthError extends Error {
|
|
201
|
+
constructor(message) {
|
|
202
|
+
super(message);
|
|
203
|
+
this.name = "ServiceAuthError";
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
function authenticatedServiceFetch(binding, env, path, body, options) {
|
|
207
|
+
const key = options?.internalKey ?? (options?.internalKeyFields ? resolveInternalAuthKey(env, options.internalKeyFields) : env.INTERNAL_KEY_BINDING);
|
|
208
|
+
if (!key) {
|
|
209
|
+
const label = options?.internalKeyFields ? Array.isArray(options.internalKeyFields) ? options.internalKeyFields.join(" | ") : options.internalKeyFields : "INTERNAL_KEY_BINDING";
|
|
210
|
+
return Promise.reject(new ServiceAuthError(`${label} not configured`));
|
|
211
|
+
}
|
|
212
|
+
return serviceFetch(binding, path, body, {
|
|
213
|
+
method: options?.method,
|
|
214
|
+
timeout: options?.timeout,
|
|
215
|
+
headers: {
|
|
216
|
+
...options?.headers,
|
|
217
|
+
"X-Internal-Auth-Key": key
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
}
|
|
19
221
|
function serviceFetch(binding, path, body, options) {
|
|
222
|
+
const timeout = options?.timeout ?? 30000;
|
|
20
223
|
return binding.fetch(`http://internal${path}`, {
|
|
21
224
|
method: options?.method ?? "POST",
|
|
22
225
|
headers: {
|
|
23
226
|
"Content-Type": "application/json",
|
|
24
227
|
...options?.headers
|
|
25
228
|
},
|
|
26
|
-
body: body != null ? JSON.stringify(body) : undefined
|
|
229
|
+
body: body != null ? JSON.stringify(body) : undefined,
|
|
230
|
+
signal: AbortSignal.timeout(timeout)
|
|
27
231
|
});
|
|
28
232
|
}
|
|
29
233
|
export {
|
|
30
|
-
serviceFetch
|
|
234
|
+
serviceFetch,
|
|
235
|
+
resolveInternalAuthKey,
|
|
236
|
+
authenticatedServiceFetch,
|
|
237
|
+
WALLET_EXECUTE_AUTH_KEY_FIELDS,
|
|
238
|
+
TRADE_READ_AUTH_KEY_FIELDS,
|
|
239
|
+
TRADE_EXECUTE_AUTH_KEY_FIELDS,
|
|
240
|
+
TELEGRAM_ALERT_AUTH_KEY_FIELDS,
|
|
241
|
+
ServiceAuthError,
|
|
242
|
+
InternalAuthKeyFields,
|
|
243
|
+
DASHBOARD_TRADE_EXECUTE_AUTH_KEY_FIELDS,
|
|
244
|
+
DASHBOARD_TELEGRAM_ALERT_AUTH_KEY_FIELDS,
|
|
245
|
+
DASHBOARD_D1_READ_AUTH_KEY_FIELDS,
|
|
246
|
+
D1_WRITE_AUTH_KEY_FIELDS,
|
|
247
|
+
D1_READ_AUTH_KEY_FIELDS
|
|
31
248
|
};
|
package/dist/session.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Session persistence — saves/restores TUI state to
|
|
2
|
+
* Session persistence — saves/restores TUI state to $HOME/.hoox/.tui-state/session.json.
|
|
3
3
|
*
|
|
4
4
|
* On destroy (app exit): serializes { activeView, sidebarExpanded, windowSize,
|
|
5
5
|
* lastData } so the user returns to the same state on next launch.
|
|
@@ -7,6 +7,10 @@
|
|
|
7
7
|
* On startup: restores previous activeView and sidebarExpanded state.
|
|
8
8
|
* Window size and lastData are saved for reference but re-detected/fetched fresh.
|
|
9
9
|
*
|
|
10
|
+
* Uses the shared getHooxHome() utility for cross-OS home directory resolution,
|
|
11
|
+
* and stores session data in the .tui-state subdirectory. Falls back to
|
|
12
|
+
* current working directory if $HOME is not available.
|
|
13
|
+
*
|
|
10
14
|
* Uses Bun's native file API for async read/write.
|
|
11
15
|
*/
|
|
12
16
|
import type { ViewId } from "./types";
|
|
@@ -26,18 +30,18 @@ export interface SessionState {
|
|
|
26
30
|
savedAt: string;
|
|
27
31
|
}
|
|
28
32
|
/**
|
|
29
|
-
* Persist the current UI state to
|
|
33
|
+
* Persist the current UI state to $HOME/.hoox/.tui-state/session.json.
|
|
30
34
|
* Call this on app destroy / clean shutdown.
|
|
31
35
|
*
|
|
32
|
-
* The
|
|
33
|
-
*
|
|
36
|
+
* The $HOME/.hoox/.tui-state directory is created automatically by
|
|
37
|
+
* Bun.write if needed (Bun creates parent directories).
|
|
34
38
|
*/
|
|
35
39
|
export declare function saveSession(activeView: ViewId, sidebarExpanded: boolean, windowSize: {
|
|
36
40
|
cols: number;
|
|
37
41
|
rows: number;
|
|
38
42
|
}, lastData: number): Promise<void>;
|
|
39
43
|
/**
|
|
40
|
-
* Restore the previous session state from
|
|
44
|
+
* Restore the previous session state from $HOME/.hoox/.tui-state/session.json.
|
|
41
45
|
* Returns defaults if the file doesn't exist or can't be parsed.
|
|
42
46
|
*
|
|
43
47
|
* @returns The saved session state, or defaults
|
package/dist/session.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAKtC,MAAM,WAAW,YAAY;IAC3B,wDAAwD;IACxD,UAAU,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,eAAe,EAAE,OAAO,CAAC;IACzB,+CAA+C;IAC/C,UAAU,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,kDAAkD;IAClD,OAAO,EAAE,MAAM,CAAC;CACjB;AA+CD;;;;;;GAMG;AACH,wBAAsB,WAAW,CAC/B,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,OAAO,EACxB,UAAU,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAC1C,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAkBf;AAID;;;;;GAKG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,YAAY,CAAC,CA8B5D"}
|
package/dist/session.js
CHANGED
|
@@ -15,10 +15,184 @@ var __export = (target, all) => {
|
|
|
15
15
|
};
|
|
16
16
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
17
17
|
|
|
18
|
-
// src/
|
|
18
|
+
// src/path-utils.ts
|
|
19
|
+
import { existsSync } from "fs";
|
|
19
20
|
import { homedir } from "os";
|
|
20
|
-
import { join } from "path";
|
|
21
|
-
|
|
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
|
+
var SESSION_FILE = (() => {
|
|
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
|
+
})();
|
|
22
196
|
var DEFAULT_SESSION = {
|
|
23
197
|
activeView: "dashboard",
|
|
24
198
|
sidebarExpanded: true,
|
|
@@ -47,7 +221,8 @@ async function restoreSession() {
|
|
|
47
221
|
if (!exists)
|
|
48
222
|
return { ...DEFAULT_SESSION };
|
|
49
223
|
const raw = await file.text();
|
|
50
|
-
const
|
|
224
|
+
const result = SessionStateFileSchema.safeParse(JSON.parse(raw));
|
|
225
|
+
const parsed = result.success ? result.data : {};
|
|
51
226
|
return {
|
|
52
227
|
activeView: validateViewId(parsed.activeView) ? parsed.activeView : DEFAULT_SESSION.activeView,
|
|
53
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"}
|