@senpi/runtime 1.0.95-dev.runtime-phase-2.20260427204640 → 1.0.95-dev.runtime-phase-2-api.20260505093328
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 +13 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +156 -31
- package/dist/index.js.map +1 -1
- package/dist/runtime/audit-query.types.d.ts +113 -0
- package/dist/runtime/audit-query.types.d.ts.map +1 -0
- package/dist/runtime/audit-query.types.js +35 -0
- package/dist/runtime/audit-query.types.js.map +1 -0
- package/dist/runtime/auto-update/coordinator.d.ts +12 -8
- package/dist/runtime/auto-update/coordinator.d.ts.map +1 -1
- package/dist/runtime/auto-update/coordinator.js +18 -17
- package/dist/runtime/auto-update/coordinator.js.map +1 -1
- package/dist/runtime/auto-update/gateway-restart.d.ts +9 -2
- package/dist/runtime/auto-update/gateway-restart.d.ts.map +1 -1
- package/dist/runtime/auto-update/gateway-restart.js +23 -13
- package/dist/runtime/auto-update/gateway-restart.js.map +1 -1
- package/dist/runtime/run.d.ts +46 -0
- package/dist/runtime/run.d.ts.map +1 -1
- package/dist/runtime/run.js +9 -0
- package/dist/runtime/run.js.map +1 -1
- package/dist/runtime/runtime.d.ts +56 -0
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +140 -0
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/runtime-api/config.d.ts +47 -0
- package/dist/runtime-api/config.d.ts.map +1 -0
- package/dist/runtime-api/config.js +74 -0
- package/dist/runtime-api/config.js.map +1 -0
- package/dist/runtime-api/handlers/audit.d.ts +76 -0
- package/dist/runtime-api/handlers/audit.d.ts.map +1 -0
- package/dist/runtime-api/handlers/audit.js +63 -0
- package/dist/runtime-api/handlers/audit.js.map +1 -0
- package/dist/runtime-api/handlers/group-by-scanner.d.ts +43 -0
- package/dist/runtime-api/handlers/group-by-scanner.d.ts.map +1 -0
- package/dist/runtime-api/handlers/group-by-scanner.js +43 -0
- package/dist/runtime-api/handlers/group-by-scanner.js.map +1 -0
- package/dist/runtime-api/handlers/ingest-signals.d.ts +54 -0
- package/dist/runtime-api/handlers/ingest-signals.d.ts.map +1 -0
- package/dist/runtime-api/handlers/ingest-signals.js +118 -0
- package/dist/runtime-api/handlers/ingest-signals.js.map +1 -0
- package/dist/runtime-api/handlers/lookup.d.ts +36 -0
- package/dist/runtime-api/handlers/lookup.d.ts.map +1 -0
- package/dist/runtime-api/handlers/lookup.js +31 -0
- package/dist/runtime-api/handlers/lookup.js.map +1 -0
- package/dist/runtime-api/handlers/types.d.ts +80 -0
- package/dist/runtime-api/handlers/types.d.ts.map +1 -0
- package/dist/runtime-api/handlers/types.js +8 -0
- package/dist/runtime-api/handlers/types.js.map +1 -0
- package/dist/runtime-api/lifecycle.d.ts +98 -0
- package/dist/runtime-api/lifecycle.d.ts.map +1 -0
- package/dist/runtime-api/lifecycle.js +137 -0
- package/dist/runtime-api/lifecycle.js.map +1 -0
- package/dist/runtime-api/readiness.d.ts +37 -0
- package/dist/runtime-api/readiness.d.ts.map +1 -0
- package/dist/runtime-api/readiness.js +35 -0
- package/dist/runtime-api/readiness.js.map +1 -0
- package/dist/runtime-api/routes/audit.d.ts +40 -0
- package/dist/runtime-api/routes/audit.d.ts.map +1 -0
- package/dist/runtime-api/routes/audit.js +82 -0
- package/dist/runtime-api/routes/audit.js.map +1 -0
- package/dist/runtime-api/routes/audit.schema.d.ts +75 -0
- package/dist/runtime-api/routes/audit.schema.d.ts.map +1 -0
- package/dist/runtime-api/routes/audit.schema.js +78 -0
- package/dist/runtime-api/routes/audit.schema.js.map +1 -0
- package/dist/runtime-api/routes/health.d.ts +53 -0
- package/dist/runtime-api/routes/health.d.ts.map +1 -0
- package/dist/runtime-api/routes/health.js +48 -0
- package/dist/runtime-api/routes/health.js.map +1 -0
- package/dist/runtime-api/routes/signals.d.ts +50 -0
- package/dist/runtime-api/routes/signals.d.ts.map +1 -0
- package/dist/runtime-api/routes/signals.js +65 -0
- package/dist/runtime-api/routes/signals.js.map +1 -0
- package/dist/runtime-api/routes/signals.schema.d.ts +94 -0
- package/dist/runtime-api/routes/signals.schema.d.ts.map +1 -0
- package/dist/runtime-api/routes/signals.schema.js +58 -0
- package/dist/runtime-api/routes/signals.schema.js.map +1 -0
- package/dist/runtime-api/server.d.ts +79 -0
- package/dist/runtime-api/server.d.ts.map +1 -0
- package/dist/runtime-api/server.js +105 -0
- package/dist/runtime-api/server.js.map +1 -0
- package/dist/senpi/client.d.ts +92 -2
- package/dist/senpi/client.d.ts.map +1 -1
- package/dist/senpi/client.js +216 -9
- package/dist/senpi/client.js.map +1 -1
- package/openclaw.plugin.json +24 -0
- package/package.json +6 -2
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Three-state readiness contract for `GET /health`.
|
|
3
|
+
*
|
|
4
|
+
* S5 (lifecycle layer) wires the lifecycle to flip these states:
|
|
5
|
+
* - `"starting"` — initial state; server is binding or warming up.
|
|
6
|
+
* - `"ok"` — server is bound and ready to handle traffic.
|
|
7
|
+
* - `"draining"` — graceful-shutdown in progress; stop routing new requests.
|
|
8
|
+
*
|
|
9
|
+
* `GET /health` returns `200` for `"ok"` and `503` for the other two states
|
|
10
|
+
* so load balancers stop routing before the process exits.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Create a mutable readiness object.
|
|
14
|
+
*
|
|
15
|
+
* The returned object satisfies both the read-only {@link Readiness} interface
|
|
16
|
+
* and exposes `setOk()` / `setDraining()` mutators for the lifecycle layer
|
|
17
|
+
* (S5) to call at the appropriate moments.
|
|
18
|
+
*
|
|
19
|
+
* Initial state is `"starting"`.
|
|
20
|
+
*
|
|
21
|
+
* @returns A combined readiness + mutator object.
|
|
22
|
+
*/
|
|
23
|
+
export function createReadiness() {
|
|
24
|
+
let s = "starting";
|
|
25
|
+
return {
|
|
26
|
+
state: () => s,
|
|
27
|
+
setOk: () => {
|
|
28
|
+
s = "ok";
|
|
29
|
+
},
|
|
30
|
+
setDraining: () => {
|
|
31
|
+
s = "draining";
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=readiness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"readiness.js","sourceRoot":"","sources":["../../src/runtime-api/readiness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAcH;;;;;;;;;;GAUG;AACH,MAAM,UAAU,eAAe;IAI7B,IAAI,CAAC,GAAmB,UAAU,CAAC;IACnC,OAAO;QACL,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QACd,KAAK,EAAE,GAAG,EAAE;YACV,CAAC,GAAG,IAAI,CAAC;QACX,CAAC;QACD,WAAW,EAAE,GAAG,EAAE;YAChB,CAAC,GAAG,UAAU,CAAC;QACjB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fastify route: `GET /audit`.
|
|
3
|
+
*
|
|
4
|
+
* Proxies a `audit_query` MCP call through the runtime handle matching the
|
|
5
|
+
* requested wallet address. AbortSignal is wired to the HTTP request lifetime
|
|
6
|
+
* so MCP cancels in-flight work when the client disconnects.
|
|
7
|
+
*
|
|
8
|
+
* Business logic lives entirely in `handlers/audit.ts`. This file contains
|
|
9
|
+
* only Fastify wiring and query-string coercion.
|
|
10
|
+
*/
|
|
11
|
+
import type { FastifyInstance } from "fastify";
|
|
12
|
+
import type { RuntimeHandle } from "../../runtime/run.js";
|
|
13
|
+
import type { Logger } from "../../utils/logger.js";
|
|
14
|
+
/**
|
|
15
|
+
* Dependencies injected into the `/audit` route at registration time.
|
|
16
|
+
*/
|
|
17
|
+
export interface AuditRouteDeps {
|
|
18
|
+
/** Live runtime handles maintained by the plugin, keyed by lowercased address. */
|
|
19
|
+
runtimeHandles: Map<string, RuntimeHandle>;
|
|
20
|
+
/** Logger instance for unexpected errors. */
|
|
21
|
+
logger: Logger;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Register `GET /audit` on the given Fastify instance.
|
|
25
|
+
*
|
|
26
|
+
* Coerces string query-string values to their typed counterparts before
|
|
27
|
+
* forwarding to `auditHandler`. The `success` field is `"true" | "false"` from
|
|
28
|
+
* the schema; converted to `boolean`. Integer fields are parsed with
|
|
29
|
+
* `parseInt`. Missing optional fields are left as `undefined`.
|
|
30
|
+
*
|
|
31
|
+
* HTTP status mapping from `AuditQueryError.code`:
|
|
32
|
+
* - `NOT_FOUND` → 404
|
|
33
|
+
* - `ABORTED` → 504 (gateway timeout — client disconnected)
|
|
34
|
+
* - `UPSTREAM` → 502 (bad gateway — MCP error)
|
|
35
|
+
*
|
|
36
|
+
* @param fastify Fastify instance to register the route on.
|
|
37
|
+
* @param deps Route dependencies injected at plugin start.
|
|
38
|
+
*/
|
|
39
|
+
export declare function registerAuditRoute(fastify: FastifyInstance, deps: AuditRouteDeps): void;
|
|
40
|
+
//# sourceMappingURL=audit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../../src/runtime-api/routes/audit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAK/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAEpD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,kFAAkF;IAClF,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC3C,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,cAAc,GACnB,IAAI,CA4DN"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fastify route: `GET /audit`.
|
|
3
|
+
*
|
|
4
|
+
* Proxies a `audit_query` MCP call through the runtime handle matching the
|
|
5
|
+
* requested wallet address. AbortSignal is wired to the HTTP request lifetime
|
|
6
|
+
* so MCP cancels in-flight work when the client disconnects.
|
|
7
|
+
*
|
|
8
|
+
* Business logic lives entirely in `handlers/audit.ts`. This file contains
|
|
9
|
+
* only Fastify wiring and query-string coercion.
|
|
10
|
+
*/
|
|
11
|
+
import { AuditQuery } from "./audit.schema.js";
|
|
12
|
+
import { auditHandler } from "../handlers/audit.js";
|
|
13
|
+
/**
|
|
14
|
+
* Register `GET /audit` on the given Fastify instance.
|
|
15
|
+
*
|
|
16
|
+
* Coerces string query-string values to their typed counterparts before
|
|
17
|
+
* forwarding to `auditHandler`. The `success` field is `"true" | "false"` from
|
|
18
|
+
* the schema; converted to `boolean`. Integer fields are parsed with
|
|
19
|
+
* `parseInt`. Missing optional fields are left as `undefined`.
|
|
20
|
+
*
|
|
21
|
+
* HTTP status mapping from `AuditQueryError.code`:
|
|
22
|
+
* - `NOT_FOUND` → 404
|
|
23
|
+
* - `ABORTED` → 504 (gateway timeout — client disconnected)
|
|
24
|
+
* - `UPSTREAM` → 502 (bad gateway — MCP error)
|
|
25
|
+
*
|
|
26
|
+
* @param fastify Fastify instance to register the route on.
|
|
27
|
+
* @param deps Route dependencies injected at plugin start.
|
|
28
|
+
*/
|
|
29
|
+
export function registerAuditRoute(fastify, deps) {
|
|
30
|
+
fastify.get("/audit", { schema: { querystring: AuditQuery } }, async (req, reply) => {
|
|
31
|
+
const q = req.query;
|
|
32
|
+
// Coerce string query-string values to typed handler args.
|
|
33
|
+
const args = {
|
|
34
|
+
...(q.tool_name !== undefined && { tool_name: q.tool_name }),
|
|
35
|
+
...(q.action_type !== undefined && { action_type: q.action_type }),
|
|
36
|
+
...(q.success !== undefined && { success: q.success === "true" }),
|
|
37
|
+
...(q.start_time !== undefined && { start_time: q.start_time }),
|
|
38
|
+
...(q.end_time !== undefined && { end_time: q.end_time }),
|
|
39
|
+
...(q.min_duration_ms !== undefined && {
|
|
40
|
+
min_duration_ms: parseInt(q.min_duration_ms, 10),
|
|
41
|
+
}),
|
|
42
|
+
...(q.max_duration_ms !== undefined && {
|
|
43
|
+
max_duration_ms: parseInt(q.max_duration_ms, 10),
|
|
44
|
+
}),
|
|
45
|
+
...(q.limit !== undefined
|
|
46
|
+
? { limit: parseInt(q.limit, 10) }
|
|
47
|
+
: { limit: 100 }),
|
|
48
|
+
...(q.offset !== undefined
|
|
49
|
+
? { offset: parseInt(q.offset, 10) }
|
|
50
|
+
: { offset: 0 }),
|
|
51
|
+
...(q.cursor_requested_at !== undefined && {
|
|
52
|
+
cursor_requested_at: q.cursor_requested_at,
|
|
53
|
+
}),
|
|
54
|
+
...(q.cursor_id !== undefined && { cursor_id: q.cursor_id }),
|
|
55
|
+
};
|
|
56
|
+
// Wire AbortSignal to the request close event so MCP cancellation works
|
|
57
|
+
// when the HTTP client disconnects before the MCP response arrives.
|
|
58
|
+
const ac = new AbortController();
|
|
59
|
+
req.raw.on("close", () => {
|
|
60
|
+
if (req.raw.destroyed)
|
|
61
|
+
ac.abort();
|
|
62
|
+
});
|
|
63
|
+
const result = await auditHandler(q.address, args, deps, ac.signal);
|
|
64
|
+
if (result.ok) {
|
|
65
|
+
return reply.send({
|
|
66
|
+
address: result.address,
|
|
67
|
+
strategyId: result.strategyId,
|
|
68
|
+
...result.result,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
const statusMap = {
|
|
72
|
+
NOT_FOUND: 404,
|
|
73
|
+
ABORTED: 504,
|
|
74
|
+
UPSTREAM: 502,
|
|
75
|
+
};
|
|
76
|
+
const status = statusMap[result.code] ?? 502;
|
|
77
|
+
return reply
|
|
78
|
+
.status(status)
|
|
79
|
+
.send({ ok: false, code: result.code, message: result.message });
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../../../src/runtime-api/routes/audit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeBox schema for the `GET /audit` query string.
|
|
3
|
+
*
|
|
4
|
+
* All Fastify query-string values arrive as strings. Integer fields
|
|
5
|
+
* (`min_duration_ms`, `max_duration_ms`, `limit`, `offset`) and the `success`
|
|
6
|
+
* boolean are declared as strings here so TypeBox validation passes on the raw
|
|
7
|
+
* HTTP input. The route handler coerces them to the appropriate types before
|
|
8
|
+
* forwarding to `auditHandler`.
|
|
9
|
+
*
|
|
10
|
+
* Fields excluded from the caller-visible surface (per plan Section 6):
|
|
11
|
+
* - `resource_type` — always `"strategy"`, set by `RuntimeHandle.auditQuery`.
|
|
12
|
+
* - `resource_id` — resolved wallet → strategyId, set by the handle.
|
|
13
|
+
* - `user_ids` — server-controlled (the MCP API-key user).
|
|
14
|
+
* - `usernames` — server-controlled (the MCP API-key user).
|
|
15
|
+
*
|
|
16
|
+
* @see senpi-hyperliquid-mcp/src/tools/audit.tools.ts `auditQueryInputSchema`
|
|
17
|
+
* for the upstream MCP Zod schema this mirrors.
|
|
18
|
+
*/
|
|
19
|
+
import { type Static } from "@sinclair/typebox";
|
|
20
|
+
/** TypeBox schema for `GET /audit` query-string parameters. */
|
|
21
|
+
export declare const AuditQuery: import("@sinclair/typebox").TObject<{
|
|
22
|
+
/**
|
|
23
|
+
* Wallet address to scope the audit query.
|
|
24
|
+
* Required — used to look up the matching runtime handle.
|
|
25
|
+
*/
|
|
26
|
+
address: import("@sinclair/typebox").TString;
|
|
27
|
+
/** Filter by exact tool name (e.g. `create_position`). */
|
|
28
|
+
tool_name: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
29
|
+
/**
|
|
30
|
+
* Filter by action classification.
|
|
31
|
+
* One of: `read`, `create`, `update`, `delete`.
|
|
32
|
+
*/
|
|
33
|
+
action_type: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"read">, import("@sinclair/typebox").TLiteral<"create">, import("@sinclair/typebox").TLiteral<"update">, import("@sinclair/typebox").TLiteral<"delete">]>>;
|
|
34
|
+
/**
|
|
35
|
+
* Filter by success/failure.
|
|
36
|
+
* Query strings arrive as text — coerce `"true"` / `"false"` in the route.
|
|
37
|
+
*/
|
|
38
|
+
success: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"true">, import("@sinclair/typebox").TLiteral<"false">]>>;
|
|
39
|
+
/** ISO 8601 inclusive lower bound on `requested_at`. */
|
|
40
|
+
start_time: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
41
|
+
/** ISO 8601 inclusive upper bound on `requested_at`. */
|
|
42
|
+
end_time: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
43
|
+
/**
|
|
44
|
+
* Minimum end-to-end duration in ms.
|
|
45
|
+
* Arrives as a string; pattern restricts to non-negative integers so
|
|
46
|
+
* `parseInt` never produces NaN. Coerced to integer in the route handler.
|
|
47
|
+
*/
|
|
48
|
+
min_duration_ms: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
49
|
+
/**
|
|
50
|
+
* Maximum end-to-end duration in ms.
|
|
51
|
+
* Arrives as a string; pattern restricts to non-negative integers so
|
|
52
|
+
* `parseInt` never produces NaN. Coerced to integer in the route handler.
|
|
53
|
+
*/
|
|
54
|
+
max_duration_ms: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
55
|
+
/**
|
|
56
|
+
* Page size (1–1000, MCP default 100).
|
|
57
|
+
* Arrives as a string; pattern restricts to non-negative integers.
|
|
58
|
+
* Coerced to integer in the route handler. Default `100` applied on
|
|
59
|
+
* missing value. MCP enforces the 1–1000 range.
|
|
60
|
+
*/
|
|
61
|
+
limit: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
62
|
+
/**
|
|
63
|
+
* Offset-based pagination skip count (≥0, MCP default 0).
|
|
64
|
+
* Arrives as a string; pattern restricts to non-negative integers.
|
|
65
|
+
* Coerced to integer in the route handler.
|
|
66
|
+
*/
|
|
67
|
+
offset: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
68
|
+
/** Cursor timestamp for keyset pagination (ISO 8601). Must pair with `cursor_id`. */
|
|
69
|
+
cursor_requested_at: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
70
|
+
/** Cursor UUID for keyset pagination. Must pair with `cursor_requested_at`. */
|
|
71
|
+
cursor_id: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
72
|
+
}>;
|
|
73
|
+
/** TypeScript type for the `GET /audit` query string. */
|
|
74
|
+
export type AuditQueryT = Static<typeof AuditQuery>;
|
|
75
|
+
//# sourceMappingURL=audit.schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.schema.d.ts","sourceRoot":"","sources":["../../../src/runtime-api/routes/audit.schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAQ,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEtD,+DAA+D;AAC/D,eAAO,MAAM,UAAU;IAEnB;;;OAGG;;IAGH,0DAA0D;;IAG1D;;;OAGG;;IAUH;;;OAGG;;IAKH,wDAAwD;;IAGxD,wDAAwD;;IAGxD;;;;OAIG;;IAGH;;;;OAIG;;IAGH;;;;;OAKG;;IAGH;;;;OAIG;;IAGH,qFAAqF;;IAGrF,+EAA+E;;EAIlF,CAAC;AAEF,yDAAyD;AACzD,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeBox schema for the `GET /audit` query string.
|
|
3
|
+
*
|
|
4
|
+
* All Fastify query-string values arrive as strings. Integer fields
|
|
5
|
+
* (`min_duration_ms`, `max_duration_ms`, `limit`, `offset`) and the `success`
|
|
6
|
+
* boolean are declared as strings here so TypeBox validation passes on the raw
|
|
7
|
+
* HTTP input. The route handler coerces them to the appropriate types before
|
|
8
|
+
* forwarding to `auditHandler`.
|
|
9
|
+
*
|
|
10
|
+
* Fields excluded from the caller-visible surface (per plan Section 6):
|
|
11
|
+
* - `resource_type` — always `"strategy"`, set by `RuntimeHandle.auditQuery`.
|
|
12
|
+
* - `resource_id` — resolved wallet → strategyId, set by the handle.
|
|
13
|
+
* - `user_ids` — server-controlled (the MCP API-key user).
|
|
14
|
+
* - `usernames` — server-controlled (the MCP API-key user).
|
|
15
|
+
*
|
|
16
|
+
* @see senpi-hyperliquid-mcp/src/tools/audit.tools.ts `auditQueryInputSchema`
|
|
17
|
+
* for the upstream MCP Zod schema this mirrors.
|
|
18
|
+
*/
|
|
19
|
+
import { Type } from "@sinclair/typebox";
|
|
20
|
+
/** TypeBox schema for `GET /audit` query-string parameters. */
|
|
21
|
+
export const AuditQuery = Type.Object({
|
|
22
|
+
/**
|
|
23
|
+
* Wallet address to scope the audit query.
|
|
24
|
+
* Required — used to look up the matching runtime handle.
|
|
25
|
+
*/
|
|
26
|
+
address: Type.String({ minLength: 1 }),
|
|
27
|
+
/** Filter by exact tool name (e.g. `create_position`). */
|
|
28
|
+
tool_name: Type.Optional(Type.String()),
|
|
29
|
+
/**
|
|
30
|
+
* Filter by action classification.
|
|
31
|
+
* One of: `read`, `create`, `update`, `delete`.
|
|
32
|
+
*/
|
|
33
|
+
action_type: Type.Optional(Type.Union([
|
|
34
|
+
Type.Literal("read"),
|
|
35
|
+
Type.Literal("create"),
|
|
36
|
+
Type.Literal("update"),
|
|
37
|
+
Type.Literal("delete"),
|
|
38
|
+
])),
|
|
39
|
+
/**
|
|
40
|
+
* Filter by success/failure.
|
|
41
|
+
* Query strings arrive as text — coerce `"true"` / `"false"` in the route.
|
|
42
|
+
*/
|
|
43
|
+
success: Type.Optional(Type.Union([Type.Literal("true"), Type.Literal("false")])),
|
|
44
|
+
/** ISO 8601 inclusive lower bound on `requested_at`. */
|
|
45
|
+
start_time: Type.Optional(Type.String()),
|
|
46
|
+
/** ISO 8601 inclusive upper bound on `requested_at`. */
|
|
47
|
+
end_time: Type.Optional(Type.String()),
|
|
48
|
+
/**
|
|
49
|
+
* Minimum end-to-end duration in ms.
|
|
50
|
+
* Arrives as a string; pattern restricts to non-negative integers so
|
|
51
|
+
* `parseInt` never produces NaN. Coerced to integer in the route handler.
|
|
52
|
+
*/
|
|
53
|
+
min_duration_ms: Type.Optional(Type.String({ pattern: "^\\d+$" })),
|
|
54
|
+
/**
|
|
55
|
+
* Maximum end-to-end duration in ms.
|
|
56
|
+
* Arrives as a string; pattern restricts to non-negative integers so
|
|
57
|
+
* `parseInt` never produces NaN. Coerced to integer in the route handler.
|
|
58
|
+
*/
|
|
59
|
+
max_duration_ms: Type.Optional(Type.String({ pattern: "^\\d+$" })),
|
|
60
|
+
/**
|
|
61
|
+
* Page size (1–1000, MCP default 100).
|
|
62
|
+
* Arrives as a string; pattern restricts to non-negative integers.
|
|
63
|
+
* Coerced to integer in the route handler. Default `100` applied on
|
|
64
|
+
* missing value. MCP enforces the 1–1000 range.
|
|
65
|
+
*/
|
|
66
|
+
limit: Type.Optional(Type.String({ pattern: "^\\d+$" })),
|
|
67
|
+
/**
|
|
68
|
+
* Offset-based pagination skip count (≥0, MCP default 0).
|
|
69
|
+
* Arrives as a string; pattern restricts to non-negative integers.
|
|
70
|
+
* Coerced to integer in the route handler.
|
|
71
|
+
*/
|
|
72
|
+
offset: Type.Optional(Type.String({ pattern: "^\\d+$" })),
|
|
73
|
+
/** Cursor timestamp for keyset pagination (ISO 8601). Must pair with `cursor_id`. */
|
|
74
|
+
cursor_requested_at: Type.Optional(Type.String()),
|
|
75
|
+
/** Cursor UUID for keyset pagination. Must pair with `cursor_requested_at`. */
|
|
76
|
+
cursor_id: Type.Optional(Type.String()),
|
|
77
|
+
}, { additionalProperties: false });
|
|
78
|
+
//# sourceMappingURL=audit.schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.schema.js","sourceRoot":"","sources":["../../../src/runtime-api/routes/audit.schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,IAAI,EAAe,MAAM,mBAAmB,CAAC;AAEtD,+DAA+D;AAC/D,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CACnC;IACE;;;OAGG;IACH,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;IAEtC,0DAA0D;IAC1D,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;IAEvC;;;OAGG;IACH,WAAW,EAAE,IAAI,CAAC,QAAQ,CACxB,IAAI,CAAC,KAAK,CAAC;QACT,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;QACpB,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;QACtB,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;QACtB,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;KACvB,CAAC,CACH;IAED;;;OAGG;IACH,OAAO,EAAE,IAAI,CAAC,QAAQ,CACpB,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAC1D;IAED,wDAAwD;IACxD,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;IAExC,wDAAwD;IACxD,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;IAEtC;;;;OAIG;IACH,eAAe,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;IAElE;;;;OAIG;IACH,eAAe,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;IAElE;;;;;OAKG;IACH,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;IAExD;;;;OAIG;IACH,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;IAEzD,qFAAqF;IACrF,mBAAmB,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;IAEjD,+EAA+E;IAC/E,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;CACxC,EACD,EAAE,oBAAoB,EAAE,KAAK,EAAE,CAChC,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fastify route: `GET /health`.
|
|
3
|
+
*
|
|
4
|
+
* Returns a three-state readiness signal (`starting` | `ok` | `draining`)
|
|
5
|
+
* suitable for load-balancer / Kubernetes liveness and readiness probes.
|
|
6
|
+
* Also exposes per-runtime signal-queue depth for capacity planning.
|
|
7
|
+
*
|
|
8
|
+
* HTTP status:
|
|
9
|
+
* - `200` when `status === "ok"`.
|
|
10
|
+
* - `503` when `status === "starting"` or `"draining"` — load balancer
|
|
11
|
+
* should stop routing new requests but the process is still alive.
|
|
12
|
+
*/
|
|
13
|
+
import type { FastifyInstance } from "fastify";
|
|
14
|
+
import type { Readiness } from "../readiness.js";
|
|
15
|
+
import type { RuntimeHandle } from "../../runtime/run.js";
|
|
16
|
+
/**
|
|
17
|
+
* Dependencies injected into the `/health` route at registration time.
|
|
18
|
+
*/
|
|
19
|
+
export interface HealthRouteDeps {
|
|
20
|
+
/** Live runtime handles maintained by the plugin, keyed by lowercased address. */
|
|
21
|
+
runtimeHandles: Map<string, RuntimeHandle>;
|
|
22
|
+
/** Subset of `ApiConfig` needed for the response body. */
|
|
23
|
+
apiConfig: {
|
|
24
|
+
host: string;
|
|
25
|
+
port: number;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Three-state readiness flag.
|
|
29
|
+
* S5 (lifecycle) flips it to `"ok"` after the server binds and to
|
|
30
|
+
* `"draining"` during graceful shutdown.
|
|
31
|
+
*/
|
|
32
|
+
readiness: Readiness;
|
|
33
|
+
/**
|
|
34
|
+
* Plugin version string (read from `openclaw.plugin.json` at boot).
|
|
35
|
+
* Included in the response so callers can correlate logs with deployments.
|
|
36
|
+
*/
|
|
37
|
+
version: string;
|
|
38
|
+
/** Unix epoch ms timestamp recorded when `createApi()` was called. */
|
|
39
|
+
bootedAt: number;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Register `GET /health` on the given Fastify instance.
|
|
43
|
+
*
|
|
44
|
+
* Response is never cached (`Cache-Control: no-store`). The shape is stable
|
|
45
|
+
* across minor versions — callers may rely on `status`, `runtimes.count`, and
|
|
46
|
+
* `runtimes.items[].signalQueueDepth` being present whenever the server is
|
|
47
|
+
* reachable.
|
|
48
|
+
*
|
|
49
|
+
* @param fastify Fastify instance to register the route on.
|
|
50
|
+
* @param deps Route dependencies injected at plugin start.
|
|
51
|
+
*/
|
|
52
|
+
export declare function registerHealthRoute(fastify: FastifyInstance, deps: HealthRouteDeps): void;
|
|
53
|
+
//# sourceMappingURL=health.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../../src/runtime-api/routes/health.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,kFAAkF;IAClF,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC3C,0DAA0D;IAC1D,SAAS,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1C;;;;OAIG;IACH,SAAS,EAAE,SAAS,CAAC;IACrB;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,eAAe,GACpB,IAAI,CAyBN"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fastify route: `GET /health`.
|
|
3
|
+
*
|
|
4
|
+
* Returns a three-state readiness signal (`starting` | `ok` | `draining`)
|
|
5
|
+
* suitable for load-balancer / Kubernetes liveness and readiness probes.
|
|
6
|
+
* Also exposes per-runtime signal-queue depth for capacity planning.
|
|
7
|
+
*
|
|
8
|
+
* HTTP status:
|
|
9
|
+
* - `200` when `status === "ok"`.
|
|
10
|
+
* - `503` when `status === "starting"` or `"draining"` — load balancer
|
|
11
|
+
* should stop routing new requests but the process is still alive.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Register `GET /health` on the given Fastify instance.
|
|
15
|
+
*
|
|
16
|
+
* Response is never cached (`Cache-Control: no-store`). The shape is stable
|
|
17
|
+
* across minor versions — callers may rely on `status`, `runtimes.count`, and
|
|
18
|
+
* `runtimes.items[].signalQueueDepth` being present whenever the server is
|
|
19
|
+
* reachable.
|
|
20
|
+
*
|
|
21
|
+
* @param fastify Fastify instance to register the route on.
|
|
22
|
+
* @param deps Route dependencies injected at plugin start.
|
|
23
|
+
*/
|
|
24
|
+
export function registerHealthRoute(fastify, deps) {
|
|
25
|
+
fastify.get("/health", async (_req, reply) => {
|
|
26
|
+
const status = deps.readiness.state();
|
|
27
|
+
const httpStatus = status === "ok" ? 200 : 503;
|
|
28
|
+
const items = Array.from(deps.runtimeHandles, ([_id, handle]) => ({
|
|
29
|
+
address: handle.wallet.toLowerCase(),
|
|
30
|
+
signalQueueDepth: handle.getSignalQueueDepth(),
|
|
31
|
+
}));
|
|
32
|
+
return reply
|
|
33
|
+
.status(httpStatus)
|
|
34
|
+
.header("Cache-Control", "no-store")
|
|
35
|
+
.send({
|
|
36
|
+
status,
|
|
37
|
+
version: deps.version,
|
|
38
|
+
uptime_ms: Date.now() - deps.bootedAt,
|
|
39
|
+
runtimes: { count: items.length, items },
|
|
40
|
+
api: { host: deps.apiConfig.host, port: deps.apiConfig.port },
|
|
41
|
+
build: {
|
|
42
|
+
commit: process.env.SENPI_GIT_COMMIT ?? null,
|
|
43
|
+
node: process.version,
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.js","sourceRoot":"","sources":["../../../src/runtime-api/routes/health.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA6BH;;;;;;;;;;GAUG;AACH,MAAM,UAAU,mBAAmB,CACjC,OAAwB,EACxB,IAAqB;IAErB,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE;QAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;QACtC,MAAM,UAAU,GAAG,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;QAE/C,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;YAChE,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE;YACpC,gBAAgB,EAAE,MAAM,CAAC,mBAAmB,EAAE;SAC/C,CAAC,CAAC,CAAC;QAEJ,OAAO,KAAK;aACT,MAAM,CAAC,UAAU,CAAC;aAClB,MAAM,CAAC,eAAe,EAAE,UAAU,CAAC;aACnC,IAAI,CAAC;YACJ,MAAM;YACN,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ;YACrC,QAAQ,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE;YACxC,GAAG,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE;YAC7D,KAAK,EAAE;gBACL,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,IAAI;gBAC5C,IAAI,EAAE,OAAO,CAAC,OAAO;aACtB;SACF,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fastify route: `POST /signals`.
|
|
3
|
+
*
|
|
4
|
+
* Accepts a batch of signal items targeting one or more runtime wallets,
|
|
5
|
+
* groups them by `(address, scanner)` to avoid the per-key ingest lock, fans
|
|
6
|
+
* out groups in parallel, processes items within each group sequentially, and
|
|
7
|
+
* returns per-item results in input order.
|
|
8
|
+
*
|
|
9
|
+
* Business logic lives entirely in:
|
|
10
|
+
* - `handlers/ingest-signals.ts` — per-item dispatch + error translation.
|
|
11
|
+
* - `handlers/group-by-scanner.ts` — lock-aware grouping helper.
|
|
12
|
+
*
|
|
13
|
+
* This file contains only Fastify wiring and the handler-level cap check.
|
|
14
|
+
*/
|
|
15
|
+
import type { FastifyInstance } from "fastify";
|
|
16
|
+
import type { RuntimeHandle } from "../../runtime/run.js";
|
|
17
|
+
import type { Logger } from "../../utils/logger.js";
|
|
18
|
+
/**
|
|
19
|
+
* Dependencies injected into the `/signals` route at registration time.
|
|
20
|
+
*/
|
|
21
|
+
export interface SignalsRouteDeps {
|
|
22
|
+
/** Live runtime handles maintained by the plugin, keyed by lowercased address. */
|
|
23
|
+
runtimeHandles: Map<string, RuntimeHandle>;
|
|
24
|
+
/** Logger instance for unexpected errors. */
|
|
25
|
+
logger: Logger;
|
|
26
|
+
/**
|
|
27
|
+
* Maximum number of items allowed in a single request.
|
|
28
|
+
* Sourced from `config.api.maxItemsPerSignalsRequest` (default 10).
|
|
29
|
+
*/
|
|
30
|
+
maxItems: number;
|
|
31
|
+
/**
|
|
32
|
+
* Transport tag forwarded to the ingest handler for telemetry.
|
|
33
|
+
* Fixed as `"http"` for this route; the gateway shim passes `"gateway"`.
|
|
34
|
+
*/
|
|
35
|
+
transport: "http" | "gateway";
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Register `POST /signals` on the given Fastify instance.
|
|
39
|
+
*
|
|
40
|
+
* The route validates the body against the `SignalsBody` TypeBox schema, then:
|
|
41
|
+
* 1. Rejects oversized batches (handler-level cap, configurable).
|
|
42
|
+
* 2. Groups items by `(address, scanner)` via `groupByAddressScanner`.
|
|
43
|
+
* 3. Runs groups in parallel; items within each group run sequentially.
|
|
44
|
+
* 4. Re-flattens results back to input order before responding.
|
|
45
|
+
*
|
|
46
|
+
* @param fastify Fastify instance to register the route on.
|
|
47
|
+
* @param deps Route dependencies injected at plugin start.
|
|
48
|
+
*/
|
|
49
|
+
export declare function registerSignalsRoute(fastify: FastifyInstance, deps: SignalsRouteDeps): void;
|
|
50
|
+
//# sourceMappingURL=signals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signals.d.ts","sourceRoot":"","sources":["../../../src/runtime-api/routes/signals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAK/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAEpD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,kFAAkF;IAClF,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC3C,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,gBAAgB,GACrB,IAAI,CA6CN"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fastify route: `POST /signals`.
|
|
3
|
+
*
|
|
4
|
+
* Accepts a batch of signal items targeting one or more runtime wallets,
|
|
5
|
+
* groups them by `(address, scanner)` to avoid the per-key ingest lock, fans
|
|
6
|
+
* out groups in parallel, processes items within each group sequentially, and
|
|
7
|
+
* returns per-item results in input order.
|
|
8
|
+
*
|
|
9
|
+
* Business logic lives entirely in:
|
|
10
|
+
* - `handlers/ingest-signals.ts` — per-item dispatch + error translation.
|
|
11
|
+
* - `handlers/group-by-scanner.ts` — lock-aware grouping helper.
|
|
12
|
+
*
|
|
13
|
+
* This file contains only Fastify wiring and the handler-level cap check.
|
|
14
|
+
*/
|
|
15
|
+
import { SignalsBody } from "./signals.schema.js";
|
|
16
|
+
import { ingestSignalsHandler } from "../handlers/ingest-signals.js";
|
|
17
|
+
import { groupByAddressScanner } from "../handlers/group-by-scanner.js";
|
|
18
|
+
/**
|
|
19
|
+
* Register `POST /signals` on the given Fastify instance.
|
|
20
|
+
*
|
|
21
|
+
* The route validates the body against the `SignalsBody` TypeBox schema, then:
|
|
22
|
+
* 1. Rejects oversized batches (handler-level cap, configurable).
|
|
23
|
+
* 2. Groups items by `(address, scanner)` via `groupByAddressScanner`.
|
|
24
|
+
* 3. Runs groups in parallel; items within each group run sequentially.
|
|
25
|
+
* 4. Re-flattens results back to input order before responding.
|
|
26
|
+
*
|
|
27
|
+
* @param fastify Fastify instance to register the route on.
|
|
28
|
+
* @param deps Route dependencies injected at plugin start.
|
|
29
|
+
*/
|
|
30
|
+
export function registerSignalsRoute(fastify, deps) {
|
|
31
|
+
fastify.post("/signals", { schema: { body: SignalsBody } }, async (req, reply) => {
|
|
32
|
+
const items = req.body;
|
|
33
|
+
// Handler-level cap — operator-tunable, not encoded in the TypeBox schema.
|
|
34
|
+
if (items.length > deps.maxItems) {
|
|
35
|
+
return reply.status(400).send({
|
|
36
|
+
success: false,
|
|
37
|
+
code: "INVALID_REQUEST",
|
|
38
|
+
message: `Exceeded api.maxItemsPerSignalsRequest=${deps.maxItems}; got ${items.length}.`,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
// Group by (address, scanner) — each group is a SignalGroup (IndexedSignalItem[]).
|
|
42
|
+
const groups = groupByAddressScanner(items);
|
|
43
|
+
// Fan out across groups in parallel; process items within each group sequentially.
|
|
44
|
+
const grouped = await Promise.all(groups.map(async (group) => {
|
|
45
|
+
const out = [];
|
|
46
|
+
for (const { index, item } of group) {
|
|
47
|
+
out.push({
|
|
48
|
+
index,
|
|
49
|
+
result: await ingestSignalsHandler(item, {
|
|
50
|
+
runtimeHandles: deps.runtimeHandles,
|
|
51
|
+
logger: deps.logger,
|
|
52
|
+
transport: deps.transport,
|
|
53
|
+
}),
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return out;
|
|
57
|
+
}));
|
|
58
|
+
// Re-flatten in input order.
|
|
59
|
+
const flat = grouped.flat();
|
|
60
|
+
flat.sort((a, b) => a.index - b.index);
|
|
61
|
+
const results = flat.map((entry) => entry.result);
|
|
62
|
+
return reply.send({ results });
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=signals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signals.js","sourceRoot":"","sources":["../../../src/runtime-api/routes/signals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAyBxE;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,oBAAoB,CAClC,OAAwB,EACxB,IAAsB;IAEtB,OAAO,CAAC,IAAI,CACV,UAAU,EACV,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,EACjC,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;QACnB,MAAM,KAAK,GAAG,GAAG,CAAC,IAAoB,CAAC;QAEvC,2EAA2E;QAC3E,IAAI,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YACjC,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBAC5B,OAAO,EAAE,KAAK;gBACd,IAAI,EAAE,iBAAiB;gBACvB,OAAO,EAAE,0CAA0C,IAAI,CAAC,QAAQ,SAAS,KAAK,CAAC,MAAM,GAAG;aACzF,CAAC,CAAC;QACL,CAAC;QAED,mFAAmF;QACnF,MAAM,MAAM,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;QAE5C,mFAAmF;QACnF,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YACzB,MAAM,GAAG,GAAmD,EAAE,CAAC;YAC/D,KAAK,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,KAAK,EAAE,CAAC;gBACpC,GAAG,CAAC,IAAI,CAAC;oBACP,KAAK;oBACL,MAAM,EAAE,MAAM,oBAAoB,CAAC,IAAI,EAAE;wBACvC,cAAc,EAAE,IAAI,CAAC,cAAc;wBACnC,MAAM,EAAE,IAAI,CAAC,MAAM;wBACnB,SAAS,EAAE,IAAI,CAAC,SAAS;qBAC1B,CAAC;iBACH,CAAC,CAAC;YACL,CAAC;YACD,OAAO,GAAG,CAAC;QACb,CAAC,CAAC,CACH,CAAC;QAEF,6BAA6B;QAC7B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;QACvC,MAAM,OAAO,GAAmB,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAElE,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;IACjC,CAAC,CACF,CAAC;AACJ,CAAC"}
|