@senpi/runtime 1.0.95-dev.runtime-phase-2.20260506193916 → 1.0.95-dev.runtime-phase-2-api.20260507130312
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 +35 -100
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +33 -930
- package/dist/index.js.map +1 -1
- package/dist/plugin.d.ts +110 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +1055 -0
- 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 +6 -2
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeBox schema and loader for the `api` block in the openclaw plugin config.
|
|
3
|
+
*
|
|
4
|
+
* The `api` block is an optional top-level property inside `openclaw.json`
|
|
5
|
+
* `plugins[*].config`. If the operator omits it entirely — or omits individual
|
|
6
|
+
* fields — this module fills in the documented defaults so the rest of the
|
|
7
|
+
* runtime-api code can rely on a fully-typed, always-present value.
|
|
8
|
+
*/
|
|
9
|
+
import { Type } from "@sinclair/typebox";
|
|
10
|
+
import { Value } from "@sinclair/typebox/value";
|
|
11
|
+
/** TypeBox schema for the `api` config block. Mirrors openclaw.plugin.json. */
|
|
12
|
+
export const ApiConfigSchema = Type.Object({
|
|
13
|
+
/**
|
|
14
|
+
* Bind interface for the HTTP server inside the openclaw container.
|
|
15
|
+
* Default `127.0.0.1` — container loopback only (most secure).
|
|
16
|
+
* Set to `0.0.0.0` to enable Docker port mapping for Postman testing.
|
|
17
|
+
* A boot-time warning is logged when this is not `127.0.0.1`.
|
|
18
|
+
*/
|
|
19
|
+
host: Type.String({ default: "127.0.0.1" }),
|
|
20
|
+
/**
|
|
21
|
+
* TCP port the HTTP server listens on.
|
|
22
|
+
* Default `8787`. Must be in [1, 65535].
|
|
23
|
+
*/
|
|
24
|
+
port: Type.Integer({ minimum: 1, maximum: 65535, default: 8787 }),
|
|
25
|
+
/**
|
|
26
|
+
* Maximum number of items allowed in a single `POST /signals` request body.
|
|
27
|
+
* Conservative default of `10` — operators raise it deliberately when
|
|
28
|
+
* broadcasting to many wallets at once.
|
|
29
|
+
*/
|
|
30
|
+
maxItemsPerSignalsRequest: Type.Integer({
|
|
31
|
+
minimum: 1,
|
|
32
|
+
maximum: 1000,
|
|
33
|
+
default: 10,
|
|
34
|
+
}),
|
|
35
|
+
}, { additionalProperties: false });
|
|
36
|
+
/** Default values applied when the operator omits the `api` block or individual fields. */
|
|
37
|
+
const API_CONFIG_DEFAULTS = {
|
|
38
|
+
host: "127.0.0.1",
|
|
39
|
+
port: 8787,
|
|
40
|
+
maxItemsPerSignalsRequest: 10,
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Load and validate the `api` config block from the full plugin config object.
|
|
44
|
+
*
|
|
45
|
+
* Merges operator-supplied values over the defaults, then validates the result
|
|
46
|
+
* against {@link ApiConfigSchema}. Throws if any field is out of range or the
|
|
47
|
+
* wrong type (e.g. a port value of 99999).
|
|
48
|
+
*
|
|
49
|
+
* @param pluginConfig - The entire plugin config object as passed by openclaw to
|
|
50
|
+
* `register(api)`. May be `undefined`, `null`, or a plain object. The function
|
|
51
|
+
* reads only the `api` sub-key; all other keys are ignored.
|
|
52
|
+
* @returns A fully-typed {@link ApiConfig} with all defaults applied.
|
|
53
|
+
* @throws {Error} If the merged config fails TypeBox validation (e.g. port out of range).
|
|
54
|
+
*/
|
|
55
|
+
export function loadApiConfig(pluginConfig) {
|
|
56
|
+
const raw = pluginConfig !== null &&
|
|
57
|
+
typeof pluginConfig === "object" &&
|
|
58
|
+
"api" in pluginConfig
|
|
59
|
+
? pluginConfig["api"]
|
|
60
|
+
: undefined;
|
|
61
|
+
const merged = {
|
|
62
|
+
...API_CONFIG_DEFAULTS,
|
|
63
|
+
...(raw !== null && typeof raw === "object" ? raw : {}),
|
|
64
|
+
};
|
|
65
|
+
if (!Value.Check(ApiConfigSchema, merged)) {
|
|
66
|
+
const firstError = Value.Errors(ApiConfigSchema, merged).First();
|
|
67
|
+
const detail = firstError
|
|
68
|
+
? `${firstError.path}: ${firstError.message}`
|
|
69
|
+
: "unknown validation error";
|
|
70
|
+
throw new Error(`Invalid runtime api config — ${detail}`);
|
|
71
|
+
}
|
|
72
|
+
return merged;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/runtime-api/config.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,IAAI,EAAe,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAEhD,+EAA+E;AAC/E,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC,MAAM,CACxC;IACE;;;;;OAKG;IACH,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;IAE3C;;;OAGG;IACH,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAEjE;;;;OAIG;IACH,yBAAyB,EAAE,IAAI,CAAC,OAAO,CAAC;QACtC,OAAO,EAAE,CAAC;QACV,OAAO,EAAE,IAAI;QACb,OAAO,EAAE,EAAE;KACZ,CAAC;CACH,EACD,EAAE,oBAAoB,EAAE,KAAK,EAAE,CAChC,CAAC;AAKF,2FAA2F;AAC3F,MAAM,mBAAmB,GAAc;IACrC,IAAI,EAAE,WAAW;IACjB,IAAI,EAAE,IAAI;IACV,yBAAyB,EAAE,EAAE;CAC9B,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,aAAa,CAAC,YAAqB;IACjD,MAAM,GAAG,GACP,YAAY,KAAK,IAAI;QACrB,OAAO,YAAY,KAAK,QAAQ;QAChC,KAAK,IAAK,YAAwC;QAChD,CAAC,CAAE,YAAwC,CAAC,KAAK,CAAC;QAClD,CAAC,CAAC,SAAS,CAAC;IAEhB,MAAM,MAAM,GAAc;QACxB,GAAG,mBAAmB;QACtB,GAAG,CAAC,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAE,GAA0B,CAAC,CAAC,CAAC,EAAE,CAAC;KAChF,CAAC;IAEF,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,eAAe,EAAE,MAAM,CAAC,EAAE,CAAC;QAC1C,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,KAAK,EAAE,CAAC;QACjE,MAAM,MAAM,GAAG,UAAU;YACvB,CAAC,CAAC,GAAG,UAAU,CAAC,IAAI,KAAK,UAAU,CAAC,OAAO,EAAE;YAC7C,CAAC,CAAC,0BAA0B,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,gCAAgC,MAAM,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared audit handler for `GET /audit`.
|
|
3
|
+
*
|
|
4
|
+
* Delegates to `RuntimeHandle.auditQuery` and translates `AuditQueryError`
|
|
5
|
+
* codes into the HTTP-layer result shape. Called by the Fastify route (S4).
|
|
6
|
+
*
|
|
7
|
+
* The discriminator field is `success` (matching MCP and the rest of the
|
|
8
|
+
* runtime-api surface). The route layer translates a successful result
|
|
9
|
+
* into the wire shape `{ success: true, data: {...} }` and a failure into
|
|
10
|
+
* `{ success: false, error: { code, message } }` per the senpi-stack
|
|
11
|
+
* convention.
|
|
12
|
+
*/
|
|
13
|
+
import type { AuditQueryArgs, AuditQueryResult } from "../../runtime/audit-query.types.js";
|
|
14
|
+
import type { RuntimeHandle } from "../../runtime/run.js";
|
|
15
|
+
import type { Logger } from "../../utils/logger.js";
|
|
16
|
+
/**
|
|
17
|
+
* Dependencies injected into {@link auditHandler}.
|
|
18
|
+
*/
|
|
19
|
+
export interface AuditDeps {
|
|
20
|
+
/** Live runtime handles maintained by the plugin. */
|
|
21
|
+
runtimeHandles: Map<string, RuntimeHandle>;
|
|
22
|
+
/** Logger instance — unexpected errors logged at `error` level. */
|
|
23
|
+
logger: Logger;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Result returned by {@link auditHandler}.
|
|
27
|
+
*
|
|
28
|
+
* Discriminated on `success`:
|
|
29
|
+
* - `true` → audit query succeeded; `address`, `strategyId`, and `result` are present.
|
|
30
|
+
* - `false` → failure; `code` is one of `NOT_FOUND | UPSTREAM | ABORTED`.
|
|
31
|
+
*
|
|
32
|
+
* `NOT_FOUND` — no running runtime for the given address, or `listStrategies`
|
|
33
|
+
* returned 0 matches (wallet not owned by the API-key user).
|
|
34
|
+
* `UPSTREAM` — MCP returned an error (network, auth, schema mismatch, runtime
|
|
35
|
+
* not started).
|
|
36
|
+
* `ABORTED` — caller cancelled via `AbortSignal` before MCP responded.
|
|
37
|
+
*/
|
|
38
|
+
export type AuditHandlerResult = {
|
|
39
|
+
success: true;
|
|
40
|
+
/** Lowercased wallet address. */
|
|
41
|
+
address: string;
|
|
42
|
+
/**
|
|
43
|
+
* Strategy UUID resolved from the wallet by `listStrategies`.
|
|
44
|
+
* May be `null` on the first successful call in the unlikely window
|
|
45
|
+
* between `auditQuery` resolving and `getStrategyId()` being read —
|
|
46
|
+
* in practice the cache is populated synchronously before the
|
|
47
|
+
* Promise resolves.
|
|
48
|
+
*/
|
|
49
|
+
strategyId: string | null;
|
|
50
|
+
/** Pass-through `audit_query` response payload. */
|
|
51
|
+
result: AuditQueryResult;
|
|
52
|
+
} | {
|
|
53
|
+
success: false;
|
|
54
|
+
code: "NOT_FOUND" | "UPSTREAM" | "ABORTED";
|
|
55
|
+
message: string;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Execute an audit query for one wallet via its runtime handle.
|
|
59
|
+
*
|
|
60
|
+
* Steps:
|
|
61
|
+
* 1. Resolve the runtime handle by `address` (case-insensitive lookup).
|
|
62
|
+
* Returns `NOT_FOUND` on miss.
|
|
63
|
+
* 2. Call `handle.auditQuery(args, { signal })`.
|
|
64
|
+
* 3. Read `handle.getStrategyId()` after a successful call — the id is cached
|
|
65
|
+
* on the runtime instance from step 2's `listStrategies` resolution.
|
|
66
|
+
* 4. On `AuditQueryError`: map `code` straight through to the result.
|
|
67
|
+
* 5. On any other throw: log + return `UPSTREAM`.
|
|
68
|
+
*
|
|
69
|
+
* @param address Wallet address to audit (normalised to lowercase internally).
|
|
70
|
+
* @param args Audit query filters forwarded to `RuntimeHandle.auditQuery`.
|
|
71
|
+
* @param deps Injected dependencies.
|
|
72
|
+
* @param signal Optional `AbortSignal` tied to the Fastify request lifetime.
|
|
73
|
+
* Threads through to the underlying MCP call so the runtime
|
|
74
|
+
* can cancel in-flight work when the HTTP client disconnects.
|
|
75
|
+
* @returns A resolved `AuditHandlerResult` — never rejects.
|
|
76
|
+
*/
|
|
77
|
+
export declare function auditHandler(address: string, args: AuditQueryArgs, deps: AuditDeps, signal?: AbortSignal): Promise<AuditHandlerResult>;
|
|
78
|
+
//# sourceMappingURL=audit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../../src/runtime-api/handlers/audit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,EACjB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAEpD;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,qDAAqD;IACrD,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC3C,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,kBAAkB,GAC1B;IACE,OAAO,EAAE,IAAI,CAAC;IACd,iCAAiC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,mDAAmD;IACnD,MAAM,EAAE,gBAAgB,CAAC;CAC1B,GACD;IACE,OAAO,EAAE,KAAK,CAAC;IACf,IAAI,EAAE,WAAW,GAAG,UAAU,GAAG,SAAS,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEN;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,cAAc,EACpB,IAAI,EAAE,SAAS,EACf,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,kBAAkB,CAAC,CAsC7B"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared audit handler for `GET /audit`.
|
|
3
|
+
*
|
|
4
|
+
* Delegates to `RuntimeHandle.auditQuery` and translates `AuditQueryError`
|
|
5
|
+
* codes into the HTTP-layer result shape. Called by the Fastify route (S4).
|
|
6
|
+
*
|
|
7
|
+
* The discriminator field is `success` (matching MCP and the rest of the
|
|
8
|
+
* runtime-api surface). The route layer translates a successful result
|
|
9
|
+
* into the wire shape `{ success: true, data: {...} }` and a failure into
|
|
10
|
+
* `{ success: false, error: { code, message } }` per the senpi-stack
|
|
11
|
+
* convention.
|
|
12
|
+
*/
|
|
13
|
+
import { findRuntimeHandleByAddress } from "./lookup.js";
|
|
14
|
+
import { AuditQueryError } from "../../runtime/audit-query.types.js";
|
|
15
|
+
/**
|
|
16
|
+
* Execute an audit query for one wallet via its runtime handle.
|
|
17
|
+
*
|
|
18
|
+
* Steps:
|
|
19
|
+
* 1. Resolve the runtime handle by `address` (case-insensitive lookup).
|
|
20
|
+
* Returns `NOT_FOUND` on miss.
|
|
21
|
+
* 2. Call `handle.auditQuery(args, { signal })`.
|
|
22
|
+
* 3. Read `handle.getStrategyId()` after a successful call — the id is cached
|
|
23
|
+
* on the runtime instance from step 2's `listStrategies` resolution.
|
|
24
|
+
* 4. On `AuditQueryError`: map `code` straight through to the result.
|
|
25
|
+
* 5. On any other throw: log + return `UPSTREAM`.
|
|
26
|
+
*
|
|
27
|
+
* @param address Wallet address to audit (normalised to lowercase internally).
|
|
28
|
+
* @param args Audit query filters forwarded to `RuntimeHandle.auditQuery`.
|
|
29
|
+
* @param deps Injected dependencies.
|
|
30
|
+
* @param signal Optional `AbortSignal` tied to the Fastify request lifetime.
|
|
31
|
+
* Threads through to the underlying MCP call so the runtime
|
|
32
|
+
* can cancel in-flight work when the HTTP client disconnects.
|
|
33
|
+
* @returns A resolved `AuditHandlerResult` — never rejects.
|
|
34
|
+
*/
|
|
35
|
+
export async function auditHandler(address, args, deps, signal) {
|
|
36
|
+
const normalizedAddress = address.toLowerCase();
|
|
37
|
+
const lookup = findRuntimeHandleByAddress(deps.runtimeHandles, normalizedAddress);
|
|
38
|
+
if (!lookup.found) {
|
|
39
|
+
return { success: false, code: "NOT_FOUND", message: lookup.message };
|
|
40
|
+
}
|
|
41
|
+
const { handle } = lookup;
|
|
42
|
+
try {
|
|
43
|
+
const result = await handle.auditQuery(args, { signal });
|
|
44
|
+
// getStrategyId() is synchronous — the cache is populated by auditQuery
|
|
45
|
+
// before the awaited Promise resolves, so this is always set on success.
|
|
46
|
+
const strategyId = handle.getStrategyId();
|
|
47
|
+
return {
|
|
48
|
+
success: true,
|
|
49
|
+
address: normalizedAddress,
|
|
50
|
+
strategyId,
|
|
51
|
+
result,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
if (err instanceof AuditQueryError) {
|
|
56
|
+
return { success: false, code: err.code, message: err.message };
|
|
57
|
+
}
|
|
58
|
+
const message = err instanceof Error
|
|
59
|
+
? err.message
|
|
60
|
+
: `Unexpected audit error: ${String(err)}`;
|
|
61
|
+
deps.logger.error("[senpi-core][runtime-api][audit] Unexpected error during audit query", { address: normalizedAddress, err });
|
|
62
|
+
return { success: false, code: "UPSTREAM", message };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../../../src/runtime-api/handlers/audit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAqDrE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAAe,EACf,IAAoB,EACpB,IAAe,EACf,MAAoB;IAEpB,MAAM,iBAAiB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAEhD,MAAM,MAAM,GAAG,0BAA0B,CAAC,IAAI,CAAC,cAAc,EAAE,iBAAiB,CAAC,CAAC;IAClF,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAClB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;IACxE,CAAC;IAED,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IAE1B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;QAEzD,wEAAwE;QACxE,yEAAyE;QACzE,MAAM,UAAU,GAAG,MAAM,CAAC,aAAa,EAAE,CAAC;QAE1C,OAAO;YACL,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,iBAAiB;YAC1B,UAAU;YACV,MAAM;SACP,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,eAAe,EAAE,CAAC;YACnC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC;QAClE,CAAC;QAED,MAAM,OAAO,GACX,GAAG,YAAY,KAAK;YAClB,CAAC,CAAC,GAAG,CAAC,OAAO;YACb,CAAC,CAAC,2BAA2B,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/C,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,sEAAsE,EACtE,EAAE,OAAO,EAAE,iBAAiB,EAAE,GAAG,EAAE,CACpC,CAAC;QACF,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;IACvD,CAAC;AACH,CAAC"}
|
|
@@ -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
|
+
import type { SignalItem } from "./types.js";
|
|
9
|
+
/**
|
|
10
|
+
* A `SignalItem` paired with its original zero-based index in the input array.
|
|
11
|
+
* The index is used to re-flatten grouped results back into the caller's
|
|
12
|
+
* requested order after `Promise.all` group settlement.
|
|
13
|
+
*/
|
|
14
|
+
export interface IndexedSignalItem {
|
|
15
|
+
/** Zero-based position in the original input array. */
|
|
16
|
+
index: number;
|
|
17
|
+
/** The original signal item. */
|
|
18
|
+
item: SignalItem;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* A sequence of items that share the same `(lowercased address, scanner)` key
|
|
22
|
+
* and must be processed sequentially to avoid the per-(address, scanner) lock.
|
|
23
|
+
*/
|
|
24
|
+
export type SignalGroup = IndexedSignalItem[];
|
|
25
|
+
/**
|
|
26
|
+
* Group signal items by `(lowercased address, scanner)`.
|
|
27
|
+
*
|
|
28
|
+
* Items within a group must be processed sequentially — the runtime's scanner
|
|
29
|
+
* engine holds a per-(address, scanner) mutex during the full async ingest
|
|
30
|
+
* chain and throws `UNAVAILABLE` on concurrent calls for the same key.
|
|
31
|
+
*
|
|
32
|
+
* Groups with different keys (different address or different scanner) can be
|
|
33
|
+
* processed in parallel — they do not share the lock.
|
|
34
|
+
*
|
|
35
|
+
* Each item carries its original index so the route handler can sort results
|
|
36
|
+
* back to input order after `Promise.all` resolves.
|
|
37
|
+
*
|
|
38
|
+
* @param items Flat array of signal items as received in the request body.
|
|
39
|
+
* @returns Array of groups; order of groups is not guaranteed, but item
|
|
40
|
+
* order within each group is preserved.
|
|
41
|
+
*/
|
|
42
|
+
export declare function groupByAddressScanner(items: SignalItem[]): SignalGroup[];
|
|
43
|
+
//# sourceMappingURL=group-by-scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"group-by-scanner.d.ts","sourceRoot":"","sources":["../../../src/runtime-api/handlers/group-by-scanner.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAC;IACd,gCAAgC;IAChC,IAAI,EAAE,UAAU,CAAC;CAClB;AAED;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,iBAAiB,EAAE,CAAC;AAE9C;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,WAAW,EAAE,CAkBxE"}
|
|
@@ -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"}
|