@senpi/runtime 1.0.95-dev.runtime-phase-2.20260506193916 → 1.0.95-dev.runtime-phase-2-api.20260507133904
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.mts +38 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +38 -0
- package/dist/index.mjs.map +1 -0
- package/dist/{index.d.ts → plugin.d.ts} +8 -1
- package/dist/plugin.d.ts.map +1 -0
- package/dist/{index.js → plugin.js} +152 -32
- package/dist/plugin.js.map +1 -0
- package/dist/runtime/__tests__/helpers/runtime-gateway-harness.d.ts +3 -3
- 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/create-actions.d.ts.map +1 -1
- package/dist/runtime/create-actions.js +13 -2
- package/dist/runtime/create-actions.js.map +1 -1
- package/dist/runtime/run.d.ts +52 -1
- 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 +169 -1
- 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 +78 -0
- package/dist/runtime-api/handlers/audit.d.ts.map +1 -0
- package/dist/runtime-api/handlers/audit.js +65 -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 +141 -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 +85 -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 +90 -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 +90 -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 +109 -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 +181 -8
- package/dist/senpi/client.js.map +1 -1
- package/openclaw.plugin.json +24 -0
- package/package.json +8 -4
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helper that groups a flat `SignalItem[]` by `(address, scanner)` so
|
|
3
|
+
* the route handler can fan-out groups in parallel while keeping items within
|
|
4
|
+
* a group sequential — dodging the per-(address, scanner) ingest lock held by
|
|
5
|
+
* `ScannerEngine` during async ingest
|
|
6
|
+
* (`src/scanners/engine/engine.ts:282-287`).
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Group signal items by `(lowercased address, scanner)`.
|
|
10
|
+
*
|
|
11
|
+
* Items within a group must be processed sequentially — the runtime's scanner
|
|
12
|
+
* engine holds a per-(address, scanner) mutex during the full async ingest
|
|
13
|
+
* chain and throws `UNAVAILABLE` on concurrent calls for the same key.
|
|
14
|
+
*
|
|
15
|
+
* Groups with different keys (different address or different scanner) can be
|
|
16
|
+
* processed in parallel — they do not share the lock.
|
|
17
|
+
*
|
|
18
|
+
* Each item carries its original index so the route handler can sort results
|
|
19
|
+
* back to input order after `Promise.all` resolves.
|
|
20
|
+
*
|
|
21
|
+
* @param items Flat array of signal items as received in the request body.
|
|
22
|
+
* @returns Array of groups; order of groups is not guaranteed, but item
|
|
23
|
+
* order within each group is preserved.
|
|
24
|
+
*/
|
|
25
|
+
export function groupByAddressScanner(items) {
|
|
26
|
+
const grouped = new Map();
|
|
27
|
+
for (let index = 0; index < items.length; index++) {
|
|
28
|
+
const item = items[index];
|
|
29
|
+
// item is always defined inside bounds; the cast avoids a superfluous
|
|
30
|
+
// non-null assertion in strict mode.
|
|
31
|
+
const safeItem = item;
|
|
32
|
+
const key = `${safeItem.address.toLowerCase()}::${safeItem.scanner}`;
|
|
33
|
+
const existing = grouped.get(key);
|
|
34
|
+
if (existing !== undefined) {
|
|
35
|
+
existing.push({ index, item: safeItem });
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
grouped.set(key, [{ index, item: safeItem }]);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return Array.from(grouped.values());
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=group-by-scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"group-by-scanner.js","sourceRoot":"","sources":["../../../src/runtime-api/handlers/group-by-scanner.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAsBH;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAmB;IACvD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAuB,CAAC;IAE/C,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;QAClD,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;QAC1B,sEAAsE;QACtE,qCAAqC;QACrC,MAAM,QAAQ,GAAG,IAAkB,CAAC;QACpC,MAAM,GAAG,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,QAAQ,CAAC,OAAO,EAAE,CAAC;QACrE,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC3C,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;AACtC,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared ingest handler for `POST /signals`.
|
|
3
|
+
*
|
|
4
|
+
* Called by the HTTP route (S4) and the gateway-method shim (S6). Contains
|
|
5
|
+
* all business logic for one ingest item — lookup, validation, execution, and
|
|
6
|
+
* error translation — so neither transport duplicates logic.
|
|
7
|
+
*/
|
|
8
|
+
import type { SignalItem, SignalResult } from "./types.js";
|
|
9
|
+
import type { RuntimeHandle } from "../../runtime/run.js";
|
|
10
|
+
import type { Logger } from "../../utils/logger.js";
|
|
11
|
+
/**
|
|
12
|
+
* Dependencies injected into {@link ingestSignalsHandler}.
|
|
13
|
+
*
|
|
14
|
+
* Keeping deps explicit (rather than closing over module-level state) makes
|
|
15
|
+
* unit-testing straightforward and keeps the function pure with respect to
|
|
16
|
+
* side effects outside the deps object.
|
|
17
|
+
*/
|
|
18
|
+
export interface IngestSignalsDeps {
|
|
19
|
+
/** Live runtime handles maintained by the plugin. */
|
|
20
|
+
runtimeHandles: Map<string, RuntimeHandle>;
|
|
21
|
+
/** Logger instance — errors logged at `error`, unexpected throws at `error`. */
|
|
22
|
+
logger: Logger;
|
|
23
|
+
/**
|
|
24
|
+
* Transport tag forwarded to future tracking events so the telemetry
|
|
25
|
+
* pipeline can distinguish HTTP-originated ingests from gateway-shim
|
|
26
|
+
* ingests on the migration dashboard.
|
|
27
|
+
*/
|
|
28
|
+
transport: "http" | "gateway";
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Ingest one signal item.
|
|
32
|
+
*
|
|
33
|
+
* Looks up the runtime by address, validates handler-level constraints, calls
|
|
34
|
+
* `RuntimeHandle.ingestExternalScannerData`, and translates all error shapes
|
|
35
|
+
* into the uniform `{ success: false, code, message }` discriminant. Never
|
|
36
|
+
* throws — all error paths return a `SignalResult`.
|
|
37
|
+
*
|
|
38
|
+
* Validation rules (beyond TypeBox):
|
|
39
|
+
* - At least one of `asset`, `data`, or `signals` must be present; an item
|
|
40
|
+
* with none of those fields has nothing to ingest → `INVALID_REQUEST`.
|
|
41
|
+
* - `data` and `signals` are mutually exclusive → `INVALID_REQUEST`.
|
|
42
|
+
* (The runtime also enforces this, but we check early to surface a clear
|
|
43
|
+
* message before the engine lock is acquired.)
|
|
44
|
+
*
|
|
45
|
+
* Per-(address, scanner) ingest lock is the engine's concern; callers should
|
|
46
|
+
* use {@link groupByAddressScanner} or nest multiple signals in `signals[]`
|
|
47
|
+
* rather than submitting concurrent top-level items for the same key.
|
|
48
|
+
*
|
|
49
|
+
* @param item A single element from the `POST /signals` request body.
|
|
50
|
+
* @param deps Injected dependencies.
|
|
51
|
+
* @returns A resolved `SignalResult` — never rejects.
|
|
52
|
+
*/
|
|
53
|
+
export declare function ingestSignalsHandler(item: SignalItem, deps: IngestSignalsDeps): Promise<SignalResult>;
|
|
54
|
+
//# sourceMappingURL=ingest-signals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ingest-signals.d.ts","sourceRoot":"","sources":["../../../src/runtime-api/handlers/ingest-signals.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAChC,qDAAqD;IACrD,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC3C,gFAAgF;IAChF,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,YAAY,CAAC,CAuIvB"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared ingest handler for `POST /signals`.
|
|
3
|
+
*
|
|
4
|
+
* Called by the HTTP route (S4) and the gateway-method shim (S6). Contains
|
|
5
|
+
* all business logic for one ingest item — lookup, validation, execution, and
|
|
6
|
+
* error translation — so neither transport duplicates logic.
|
|
7
|
+
*/
|
|
8
|
+
import { ExternalScannerIngestError, } from "../../scanners/external-scanner-receiver.js";
|
|
9
|
+
import { findRuntimeHandleByAddress } from "./lookup.js";
|
|
10
|
+
/**
|
|
11
|
+
* Ingest one signal item.
|
|
12
|
+
*
|
|
13
|
+
* Looks up the runtime by address, validates handler-level constraints, calls
|
|
14
|
+
* `RuntimeHandle.ingestExternalScannerData`, and translates all error shapes
|
|
15
|
+
* into the uniform `{ success: false, code, message }` discriminant. Never
|
|
16
|
+
* throws — all error paths return a `SignalResult`.
|
|
17
|
+
*
|
|
18
|
+
* Validation rules (beyond TypeBox):
|
|
19
|
+
* - At least one of `asset`, `data`, or `signals` must be present; an item
|
|
20
|
+
* with none of those fields has nothing to ingest → `INVALID_REQUEST`.
|
|
21
|
+
* - `data` and `signals` are mutually exclusive → `INVALID_REQUEST`.
|
|
22
|
+
* (The runtime also enforces this, but we check early to surface a clear
|
|
23
|
+
* message before the engine lock is acquired.)
|
|
24
|
+
*
|
|
25
|
+
* Per-(address, scanner) ingest lock is the engine's concern; callers should
|
|
26
|
+
* use {@link groupByAddressScanner} or nest multiple signals in `signals[]`
|
|
27
|
+
* rather than submitting concurrent top-level items for the same key.
|
|
28
|
+
*
|
|
29
|
+
* @param item A single element from the `POST /signals` request body.
|
|
30
|
+
* @param deps Injected dependencies.
|
|
31
|
+
* @returns A resolved `SignalResult` — never rejects.
|
|
32
|
+
*/
|
|
33
|
+
export async function ingestSignalsHandler(item, deps) {
|
|
34
|
+
const address = item.address.toLowerCase();
|
|
35
|
+
const { scanner } = item;
|
|
36
|
+
// --- Handler-level validation ---
|
|
37
|
+
const hasAsset = item.asset !== undefined;
|
|
38
|
+
const hasData = item.data !== undefined;
|
|
39
|
+
// `signals: []` is treated as no signals — the caller intended a batch but
|
|
40
|
+
// sent nothing to ingest. Falls through to the at-least-one rule below.
|
|
41
|
+
const hasSignals = item.signals !== undefined && item.signals.length > 0;
|
|
42
|
+
if (!hasAsset && !hasData && !hasSignals) {
|
|
43
|
+
return {
|
|
44
|
+
success: false,
|
|
45
|
+
address,
|
|
46
|
+
scanner,
|
|
47
|
+
code: "INVALID_REQUEST",
|
|
48
|
+
message: "Signal item must include at least one of: asset, data, or signals.",
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
if (hasData && hasSignals) {
|
|
52
|
+
return {
|
|
53
|
+
success: false,
|
|
54
|
+
address,
|
|
55
|
+
scanner,
|
|
56
|
+
code: "INVALID_REQUEST",
|
|
57
|
+
message: "Signal item must not include both data and signals — they are mutually exclusive.",
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
// --- Runtime lookup ---
|
|
61
|
+
const lookup = findRuntimeHandleByAddress(deps.runtimeHandles, address);
|
|
62
|
+
if (!lookup.found) {
|
|
63
|
+
return {
|
|
64
|
+
success: false,
|
|
65
|
+
address,
|
|
66
|
+
scanner,
|
|
67
|
+
code: "NOT_FOUND",
|
|
68
|
+
message: lookup.message,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
const { handle } = lookup;
|
|
72
|
+
// --- Build the ingest request (address stays at the routing layer) ---
|
|
73
|
+
//
|
|
74
|
+
// `signals` only forwarded when non-empty — mirrors the validation rule
|
|
75
|
+
// above. An empty array would have failed the at-least-one check (unless
|
|
76
|
+
// accompanied by asset/data), so we strip it here for symmetry: don't
|
|
77
|
+
// forward what the validator just rejected as meaningful payload.
|
|
78
|
+
const request = {
|
|
79
|
+
scanner: item.scanner,
|
|
80
|
+
...(item.asset !== undefined && { asset: item.asset }),
|
|
81
|
+
...(item.direction !== undefined && { direction: item.direction }),
|
|
82
|
+
...(item.score !== undefined && { score: item.score }),
|
|
83
|
+
...(item.signal_type !== undefined && { signal_type: item.signal_type }),
|
|
84
|
+
...(item.data !== undefined && { data: item.data }),
|
|
85
|
+
...(hasSignals && { signals: item.signals }),
|
|
86
|
+
};
|
|
87
|
+
// --- Dispatch ---
|
|
88
|
+
console.info("[senpi-runtime] [ingest-trace] /signals handler dispatching", JSON.stringify({
|
|
89
|
+
address,
|
|
90
|
+
scanner,
|
|
91
|
+
transport: deps.transport,
|
|
92
|
+
hasAsset,
|
|
93
|
+
hasData,
|
|
94
|
+
hasSignals,
|
|
95
|
+
dataKeys: hasData ? Object.keys(item.data) : [],
|
|
96
|
+
}));
|
|
97
|
+
try {
|
|
98
|
+
const result = await handle.ingestExternalScannerData(request);
|
|
99
|
+
// TODO(s11): emit runtime.signals_ingested with transport=deps.transport
|
|
100
|
+
console.info("[senpi-runtime] [ingest-trace] /signals handler dispatch ok", JSON.stringify({ address, scanner, signalCount: result.signalCount, contextUpdated: result.contextUpdated }));
|
|
101
|
+
return {
|
|
102
|
+
success: true,
|
|
103
|
+
address,
|
|
104
|
+
scanner,
|
|
105
|
+
timestamp: result.timestamp,
|
|
106
|
+
signalCount: result.signalCount,
|
|
107
|
+
contextUpdated: result.contextUpdated,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
console.info("[senpi-runtime] [ingest-trace] /signals handler dispatch THREW", JSON.stringify({
|
|
112
|
+
address,
|
|
113
|
+
scanner,
|
|
114
|
+
errType: err instanceof Error ? err.constructor.name : typeof err,
|
|
115
|
+
message: err instanceof Error ? err.message : String(err),
|
|
116
|
+
}));
|
|
117
|
+
if (err instanceof ExternalScannerIngestError) {
|
|
118
|
+
return {
|
|
119
|
+
success: false,
|
|
120
|
+
address,
|
|
121
|
+
scanner,
|
|
122
|
+
code: err.code,
|
|
123
|
+
message: err.message,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
// Unexpected throw — do not add a new INTERNAL code; map to UNAVAILABLE
|
|
127
|
+
// per Section 5 plan: "reuse INVALID_REQUEST | NOT_FOUND | UNAVAILABLE".
|
|
128
|
+
const message = err instanceof Error
|
|
129
|
+
? err.message
|
|
130
|
+
: `Unexpected ingest error: ${String(err)}`;
|
|
131
|
+
deps.logger.error("[senpi-core][runtime-api][ingest-signals] Unexpected error during ingest", { address, scanner, transport: deps.transport, err });
|
|
132
|
+
return {
|
|
133
|
+
success: false,
|
|
134
|
+
address,
|
|
135
|
+
scanner,
|
|
136
|
+
code: "UNAVAILABLE",
|
|
137
|
+
message,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=ingest-signals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ingest-signals.js","sourceRoot":"","sources":["../../../src/runtime-api/handlers/ingest-signals.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helper for resolving a running runtime handle by wallet address.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from `getRuntimeHandleByAddressOrRespond` in `src/index.ts` so
|
|
5
|
+
* both the HTTP route layer (S4) and the gateway shim (S6) can share the
|
|
6
|
+
* lookup logic without the respond-on-error side-effect.
|
|
7
|
+
*/
|
|
8
|
+
import type { RuntimeHandle } from "../../runtime/run.js";
|
|
9
|
+
/**
|
|
10
|
+
* Discriminated result of a handle lookup.
|
|
11
|
+
*
|
|
12
|
+
* Use `found` to narrow:
|
|
13
|
+
* - `true` → `runtimeId` and `handle` are available.
|
|
14
|
+
* - `false` → `code` is always `"NOT_FOUND"` and `message` describes the miss.
|
|
15
|
+
*/
|
|
16
|
+
export type LookupResult = {
|
|
17
|
+
found: true;
|
|
18
|
+
runtimeId: string;
|
|
19
|
+
handle: RuntimeHandle;
|
|
20
|
+
} | {
|
|
21
|
+
found: false;
|
|
22
|
+
code: "NOT_FOUND";
|
|
23
|
+
message: string;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Find a running runtime by lowercased wallet address.
|
|
27
|
+
*
|
|
28
|
+
* Matches case-insensitively — wallet addresses from the runtime's strategy
|
|
29
|
+
* config may differ in capitalisation from caller-supplied values.
|
|
30
|
+
*
|
|
31
|
+
* @param handles The live map maintained by the plugin (`runtimeHandles`).
|
|
32
|
+
* @param address Wallet address to search for. Case is normalised internally.
|
|
33
|
+
* @returns A discriminated union; never throws.
|
|
34
|
+
*/
|
|
35
|
+
export declare function findRuntimeHandleByAddress(handles: Map<string, RuntimeHandle>, address: string): LookupResult;
|
|
36
|
+
//# sourceMappingURL=lookup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lookup.d.ts","sourceRoot":"","sources":["../../../src/runtime-api/handlers/lookup.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GACpB;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,GACzD;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzD;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,EACnC,OAAO,EAAE,MAAM,GACd,YAAY,CAYd"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helper for resolving a running runtime handle by wallet address.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from `getRuntimeHandleByAddressOrRespond` in `src/index.ts` so
|
|
5
|
+
* both the HTTP route layer (S4) and the gateway shim (S6) can share the
|
|
6
|
+
* lookup logic without the respond-on-error side-effect.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Find a running runtime by lowercased wallet address.
|
|
10
|
+
*
|
|
11
|
+
* Matches case-insensitively — wallet addresses from the runtime's strategy
|
|
12
|
+
* config may differ in capitalisation from caller-supplied values.
|
|
13
|
+
*
|
|
14
|
+
* @param handles The live map maintained by the plugin (`runtimeHandles`).
|
|
15
|
+
* @param address Wallet address to search for. Case is normalised internally.
|
|
16
|
+
* @returns A discriminated union; never throws.
|
|
17
|
+
*/
|
|
18
|
+
export function findRuntimeHandleByAddress(handles, address) {
|
|
19
|
+
const normalizedAddress = address.toLowerCase();
|
|
20
|
+
for (const [runtimeId, handle] of handles) {
|
|
21
|
+
if (handle.wallet.toLowerCase() === normalizedAddress) {
|
|
22
|
+
return { found: true, runtimeId, handle };
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
found: false,
|
|
27
|
+
code: "NOT_FOUND",
|
|
28
|
+
message: `No running runtime found for wallet address "${address}".`,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=lookup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lookup.js","sourceRoot":"","sources":["../../../src/runtime-api/handlers/lookup.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAeH;;;;;;;;;GASG;AACH,MAAM,UAAU,0BAA0B,CACxC,OAAmC,EACnC,OAAe;IAEf,MAAM,iBAAiB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAChD,KAAK,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QAC1C,IAAI,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,iBAAiB,EAAE,CAAC;YACtD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;QAC5C,CAAC;IACH,CAAC;IACD,OAAO;QACL,KAAK,EAAE,KAAK;QACZ,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,gDAAgD,OAAO,IAAI;KACrE,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transport-agnostic type definitions shared by all `src/runtime-api/handlers/`
|
|
3
|
+
* modules and the route layer that consumes them.
|
|
4
|
+
*
|
|
5
|
+
* No Fastify imports. No side-effects.
|
|
6
|
+
*/
|
|
7
|
+
import type { ExternalScannerIngestSignalItem, ExternalScannerIngestErrorCode } from "../../scanners/external-scanner-receiver.js";
|
|
8
|
+
import type { Signal } from "../../scanners/types.js";
|
|
9
|
+
/**
|
|
10
|
+
* Per-item shape accepted by `POST /signals`.
|
|
11
|
+
*
|
|
12
|
+
* Mirrors {@link ExternalScannerIngestRequest} with `address` lifted to the
|
|
13
|
+
* item level so a single request body can target multiple wallets.
|
|
14
|
+
*
|
|
15
|
+
* Only one of `data` (single-signal shortcut) or `signals[]` (batch within
|
|
16
|
+
* one address+scanner) may be present — the handler enforces mutual exclusion
|
|
17
|
+
* at runtime in addition to the TypeBox schema check.
|
|
18
|
+
*/
|
|
19
|
+
export interface SignalItem {
|
|
20
|
+
/** Wallet address of the target runtime. Lowercased server-side. */
|
|
21
|
+
address: string;
|
|
22
|
+
/** Configured scanner id. */
|
|
23
|
+
scanner: string;
|
|
24
|
+
/** Asset for a single ingested signal. */
|
|
25
|
+
asset?: string;
|
|
26
|
+
/** Direction for a single ingested signal. */
|
|
27
|
+
direction?: Signal["direction"];
|
|
28
|
+
/** Confidence score for a single ingested signal (0–1). */
|
|
29
|
+
score?: number;
|
|
30
|
+
/** Signal classification override for a single ingested signal. */
|
|
31
|
+
signal_type?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Single ingest payload for signal-producing or context-producing scanners.
|
|
34
|
+
* Mutually exclusive with `signals[]`.
|
|
35
|
+
*/
|
|
36
|
+
data?: Record<string, unknown>;
|
|
37
|
+
/**
|
|
38
|
+
* Batch signal payloads for signal-producing external scanners.
|
|
39
|
+
* Mutually exclusive with `data`.
|
|
40
|
+
* Prefer this over multiple top-level items for the same address+scanner
|
|
41
|
+
* to avoid the per-(address, scanner) ingest lock.
|
|
42
|
+
*/
|
|
43
|
+
signals?: ExternalScannerIngestSignalItem[];
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Per-item result returned by {@link ingestSignalsHandler}.
|
|
47
|
+
*
|
|
48
|
+
* INTERNAL handler shape — kept flat so the gateway shim
|
|
49
|
+
* (`senpi.ingestExternalScannerData` in `src/plugin.ts`) can read fields
|
|
50
|
+
* directly without a transform. The HTTP route layer
|
|
51
|
+
* (`routes/signals.ts`) reshapes this into the senpi-stack wire format
|
|
52
|
+
* `{ success, address, scanner, data | error }` before sending on the wire.
|
|
53
|
+
*
|
|
54
|
+
* Discriminator is `success` (matching MCP and the rest of the runtime-api
|
|
55
|
+
* surface).
|
|
56
|
+
*
|
|
57
|
+
* Error codes reuse the existing
|
|
58
|
+
* {@link ExternalScannerIngestErrorCode} taxonomy:
|
|
59
|
+
* `INVALID_REQUEST | NOT_FOUND | UNAVAILABLE`. No `INTERNAL` code is added —
|
|
60
|
+
* unexpected throws map to `UNAVAILABLE`.
|
|
61
|
+
*/
|
|
62
|
+
export type SignalResult = {
|
|
63
|
+
success: true;
|
|
64
|
+
/** Lowercased wallet address. */
|
|
65
|
+
address: string;
|
|
66
|
+
/** Configured scanner id. */
|
|
67
|
+
scanner: string;
|
|
68
|
+
/** Unix epoch ms timestamp from the ingest result. */
|
|
69
|
+
timestamp: number;
|
|
70
|
+
/** Number of committed signals; `0` for context-only ingests. */
|
|
71
|
+
signalCount: number;
|
|
72
|
+
/** Whether retained context was updated. */
|
|
73
|
+
contextUpdated: boolean;
|
|
74
|
+
} | {
|
|
75
|
+
success: false;
|
|
76
|
+
/** Lowercased wallet address. */
|
|
77
|
+
address: string;
|
|
78
|
+
/** Configured scanner id. */
|
|
79
|
+
scanner: string;
|
|
80
|
+
/** Machine-readable failure code. */
|
|
81
|
+
code: ExternalScannerIngestErrorCode;
|
|
82
|
+
/** Human-readable failure detail. */
|
|
83
|
+
message: string;
|
|
84
|
+
};
|
|
85
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/runtime-api/handlers/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,+BAA+B,EAC/B,8BAA8B,EAC/B,MAAM,6CAA6C,CAAC;AACrD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEtD;;;;;;;;;GASG;AACH,MAAM,WAAW,UAAU;IACzB,oEAAoE;IACpE,OAAO,EAAE,MAAM,CAAC;IAChB,6BAA6B;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC;IAChC,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,+BAA+B,EAAE,CAAC;CAC7C;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,YAAY,GACpB;IACE,OAAO,EAAE,IAAI,CAAC;IACd,iCAAiC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,6BAA6B;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,WAAW,EAAE,MAAM,CAAC;IACpB,4CAA4C;IAC5C,cAAc,EAAE,OAAO,CAAC;CACzB,GACD;IACE,OAAO,EAAE,KAAK,CAAC;IACf,iCAAiC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,6BAA6B;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,qCAAqC;IACrC,IAAI,EAAE,8BAA8B,CAAC;IACrC,qCAAqC;IACrC,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/runtime-api/handlers/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Start/stop helpers for the runtime HTTP API.
|
|
3
|
+
*
|
|
4
|
+
* This module owns the Fastify server lifecycle: binding the port,
|
|
5
|
+
* flipping readiness states, and draining in-flight requests on shutdown
|
|
6
|
+
* with a hard 15s timeout so teardown always proceeds.
|
|
7
|
+
*
|
|
8
|
+
* The plugin glue layer (S6 in `src/index.ts`) calls {@link startApi} during
|
|
9
|
+
* `api.lifecycle.start` and {@link ApiHandle.close} during `api.lifecycle.stop`.
|
|
10
|
+
* This module does NOT modify `src/index.ts`.
|
|
11
|
+
*/
|
|
12
|
+
import type { FastifyInstance } from "fastify";
|
|
13
|
+
import { type CreateApiDeps, type ApiArtifacts } from "./server.js";
|
|
14
|
+
import type { Logger } from "../utils/logger.js";
|
|
15
|
+
/**
|
|
16
|
+
* Hard timeout for Fastify drain.
|
|
17
|
+
*
|
|
18
|
+
* After this many milliseconds, {@link stopApi} logs a warning and proceeds
|
|
19
|
+
* to runtime teardown regardless of in-flight requests. 15s is enough
|
|
20
|
+
* headroom for any Telegram notification or close-resolver tick that may
|
|
21
|
+
* be mid-flight on the underlying runtime.
|
|
22
|
+
*/
|
|
23
|
+
export declare const DRAIN_HARD_TIMEOUT_MS = 15000;
|
|
24
|
+
/**
|
|
25
|
+
* Handle returned by {@link startApi}.
|
|
26
|
+
*
|
|
27
|
+
* The plugin lifecycle layer holds this and calls `ready()` once runtimes
|
|
28
|
+
* are confirmed healthy, then `close()` at shutdown.
|
|
29
|
+
*/
|
|
30
|
+
export interface ApiHandle {
|
|
31
|
+
/** The bound Fastify instance (exposed for tests that need `fastify.inject`). */
|
|
32
|
+
fastify: FastifyInstance;
|
|
33
|
+
/**
|
|
34
|
+
* Flip readiness from `"starting"` to `"ok"`.
|
|
35
|
+
*
|
|
36
|
+
* Call immediately after {@link startApi} resolves unless you need a
|
|
37
|
+
* deliberate warm-up window before accepting traffic.
|
|
38
|
+
*/
|
|
39
|
+
ready: () => void;
|
|
40
|
+
/**
|
|
41
|
+
* Drain in-flight requests and close the HTTP server.
|
|
42
|
+
*
|
|
43
|
+
* Sets readiness to `"draining"` (so `/health` starts returning 503),
|
|
44
|
+
* then awaits `fastify.close()` with a hard {@link DRAIN_HARD_TIMEOUT_MS}
|
|
45
|
+
* timeout. If the timeout fires, a warning is logged and teardown proceeds
|
|
46
|
+
* without waiting further.
|
|
47
|
+
*
|
|
48
|
+
* Never throws — all errors are logged and swallowed so the caller's
|
|
49
|
+
* teardown sequence is not interrupted.
|
|
50
|
+
*/
|
|
51
|
+
close: () => Promise<void>;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Start the HTTP API server.
|
|
55
|
+
*
|
|
56
|
+
* Calls {@link createApi} to build the Fastify instance, binds it to
|
|
57
|
+
* `deps.apiConfig.host:deps.apiConfig.port`, and returns an {@link ApiHandle}.
|
|
58
|
+
*
|
|
59
|
+
* The server is NOT yet marked ready after this call — `/health` will return
|
|
60
|
+
* 503 until the caller invokes `handle.ready()`. Call `ready()` immediately
|
|
61
|
+
* after the runtimes are confirmed up, which in the plugin lifecycle is right
|
|
62
|
+
* after `startApi` returns.
|
|
63
|
+
*
|
|
64
|
+
* A boot-time warning is logged when `deps.apiConfig.host !== "127.0.0.1"` so
|
|
65
|
+
* any operator who opts into Docker port mapping sees it in the logs.
|
|
66
|
+
*
|
|
67
|
+
* @param deps Same dependencies passed to {@link createApi}: runtime handles,
|
|
68
|
+
* validated API config, logger, and plugin version string.
|
|
69
|
+
* @returns An {@link ApiHandle} whose `ready()` and `close()` methods drive
|
|
70
|
+
* the lifecycle.
|
|
71
|
+
* @throws Re-throws any `fastify.listen()` error (e.g. `EADDRINUSE`) so
|
|
72
|
+
* the plugin lifecycle layer can perform its rollback and fail the
|
|
73
|
+
* openclaw start cleanly.
|
|
74
|
+
*/
|
|
75
|
+
export declare function startApi(deps: CreateApiDeps): Promise<ApiHandle>;
|
|
76
|
+
/**
|
|
77
|
+
* Drain in-flight requests and close the HTTP server.
|
|
78
|
+
*
|
|
79
|
+
* Sets readiness to `"draining"` immediately so `/health` stops returning 200,
|
|
80
|
+
* then races `fastify.close()` against {@link DRAIN_HARD_TIMEOUT_MS}. If the
|
|
81
|
+
* hard timeout fires first, a warning is logged and a best-effort force-close
|
|
82
|
+
* is issued (fire-and-forget). The function always resolves — it never rejects.
|
|
83
|
+
*
|
|
84
|
+
* @param artifacts The {@link ApiArtifacts} returned by `createApi`.
|
|
85
|
+
* @param logger Logger for the startup/drain messages.
|
|
86
|
+
*/
|
|
87
|
+
declare function stopApi(artifacts: ApiArtifacts, logger: Logger): Promise<void>;
|
|
88
|
+
/**
|
|
89
|
+
* Exported for tests (S8) so they can assert drain timeout behavior without
|
|
90
|
+
* going through the full `startApi` path.
|
|
91
|
+
*
|
|
92
|
+
* @internal Not part of the public API surface — import only in `__tests__/`.
|
|
93
|
+
*/
|
|
94
|
+
export declare const __test_only: {
|
|
95
|
+
stopApi: typeof stopApi;
|
|
96
|
+
};
|
|
97
|
+
export {};
|
|
98
|
+
//# sourceMappingURL=lifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../src/runtime-api/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAa,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAC/E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAEjD;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,QAAS,CAAC;AAE5C;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACxB,iFAAiF;IACjF,OAAO,EAAE,eAAe,CAAC;IACzB;;;;;OAKG;IACH,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB;;;;;;;;;;OAUG;IACH,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,SAAS,CAAC,CA+BtE;AAED;;;;;;;;;;GAUG;AACH,iBAAe,OAAO,CAAC,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAuD7E;AAED;;;;;GAKG;AACH,eAAO,MAAM,WAAW;;CAAc,CAAC"}
|