@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.
Files changed (95) hide show
  1. package/README.md +13 -0
  2. package/dist/index.d.ts +35 -100
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +33 -930
  5. package/dist/index.js.map +1 -1
  6. package/dist/plugin.d.ts +110 -0
  7. package/dist/plugin.d.ts.map +1 -0
  8. package/dist/plugin.js +1055 -0
  9. package/dist/plugin.js.map +1 -0
  10. package/dist/runtime/__tests__/helpers/runtime-gateway-harness.d.ts +3 -3
  11. package/dist/runtime/audit-query.types.d.ts +113 -0
  12. package/dist/runtime/audit-query.types.d.ts.map +1 -0
  13. package/dist/runtime/audit-query.types.js +35 -0
  14. package/dist/runtime/audit-query.types.js.map +1 -0
  15. package/dist/runtime/auto-update/coordinator.d.ts +12 -8
  16. package/dist/runtime/auto-update/coordinator.d.ts.map +1 -1
  17. package/dist/runtime/auto-update/coordinator.js +18 -17
  18. package/dist/runtime/auto-update/coordinator.js.map +1 -1
  19. package/dist/runtime/auto-update/gateway-restart.d.ts +9 -2
  20. package/dist/runtime/auto-update/gateway-restart.d.ts.map +1 -1
  21. package/dist/runtime/auto-update/gateway-restart.js +23 -13
  22. package/dist/runtime/auto-update/gateway-restart.js.map +1 -1
  23. package/dist/runtime/create-actions.d.ts.map +1 -1
  24. package/dist/runtime/create-actions.js +13 -2
  25. package/dist/runtime/create-actions.js.map +1 -1
  26. package/dist/runtime/run.d.ts +52 -1
  27. package/dist/runtime/run.d.ts.map +1 -1
  28. package/dist/runtime/run.js +9 -0
  29. package/dist/runtime/run.js.map +1 -1
  30. package/dist/runtime/runtime.d.ts +56 -0
  31. package/dist/runtime/runtime.d.ts.map +1 -1
  32. package/dist/runtime/runtime.js +169 -1
  33. package/dist/runtime/runtime.js.map +1 -1
  34. package/dist/runtime-api/config.d.ts +47 -0
  35. package/dist/runtime-api/config.d.ts.map +1 -0
  36. package/dist/runtime-api/config.js +74 -0
  37. package/dist/runtime-api/config.js.map +1 -0
  38. package/dist/runtime-api/handlers/audit.d.ts +78 -0
  39. package/dist/runtime-api/handlers/audit.d.ts.map +1 -0
  40. package/dist/runtime-api/handlers/audit.js +65 -0
  41. package/dist/runtime-api/handlers/audit.js.map +1 -0
  42. package/dist/runtime-api/handlers/group-by-scanner.d.ts +43 -0
  43. package/dist/runtime-api/handlers/group-by-scanner.d.ts.map +1 -0
  44. package/dist/runtime-api/handlers/group-by-scanner.js +43 -0
  45. package/dist/runtime-api/handlers/group-by-scanner.js.map +1 -0
  46. package/dist/runtime-api/handlers/ingest-signals.d.ts +54 -0
  47. package/dist/runtime-api/handlers/ingest-signals.d.ts.map +1 -0
  48. package/dist/runtime-api/handlers/ingest-signals.js +141 -0
  49. package/dist/runtime-api/handlers/ingest-signals.js.map +1 -0
  50. package/dist/runtime-api/handlers/lookup.d.ts +36 -0
  51. package/dist/runtime-api/handlers/lookup.d.ts.map +1 -0
  52. package/dist/runtime-api/handlers/lookup.js +31 -0
  53. package/dist/runtime-api/handlers/lookup.js.map +1 -0
  54. package/dist/runtime-api/handlers/types.d.ts +85 -0
  55. package/dist/runtime-api/handlers/types.d.ts.map +1 -0
  56. package/dist/runtime-api/handlers/types.js +8 -0
  57. package/dist/runtime-api/handlers/types.js.map +1 -0
  58. package/dist/runtime-api/lifecycle.d.ts +98 -0
  59. package/dist/runtime-api/lifecycle.d.ts.map +1 -0
  60. package/dist/runtime-api/lifecycle.js +137 -0
  61. package/dist/runtime-api/lifecycle.js.map +1 -0
  62. package/dist/runtime-api/readiness.d.ts +37 -0
  63. package/dist/runtime-api/readiness.d.ts.map +1 -0
  64. package/dist/runtime-api/readiness.js +35 -0
  65. package/dist/runtime-api/readiness.js.map +1 -0
  66. package/dist/runtime-api/routes/audit.d.ts +40 -0
  67. package/dist/runtime-api/routes/audit.d.ts.map +1 -0
  68. package/dist/runtime-api/routes/audit.js +90 -0
  69. package/dist/runtime-api/routes/audit.js.map +1 -0
  70. package/dist/runtime-api/routes/audit.schema.d.ts +75 -0
  71. package/dist/runtime-api/routes/audit.schema.d.ts.map +1 -0
  72. package/dist/runtime-api/routes/audit.schema.js +78 -0
  73. package/dist/runtime-api/routes/audit.schema.js.map +1 -0
  74. package/dist/runtime-api/routes/health.d.ts +53 -0
  75. package/dist/runtime-api/routes/health.d.ts.map +1 -0
  76. package/dist/runtime-api/routes/health.js +48 -0
  77. package/dist/runtime-api/routes/health.js.map +1 -0
  78. package/dist/runtime-api/routes/signals.d.ts +50 -0
  79. package/dist/runtime-api/routes/signals.d.ts.map +1 -0
  80. package/dist/runtime-api/routes/signals.js +90 -0
  81. package/dist/runtime-api/routes/signals.js.map +1 -0
  82. package/dist/runtime-api/routes/signals.schema.d.ts +94 -0
  83. package/dist/runtime-api/routes/signals.schema.d.ts.map +1 -0
  84. package/dist/runtime-api/routes/signals.schema.js +58 -0
  85. package/dist/runtime-api/routes/signals.schema.js.map +1 -0
  86. package/dist/runtime-api/server.d.ts +79 -0
  87. package/dist/runtime-api/server.d.ts.map +1 -0
  88. package/dist/runtime-api/server.js +109 -0
  89. package/dist/runtime-api/server.js.map +1 -0
  90. package/dist/senpi/client.d.ts +92 -2
  91. package/dist/senpi/client.d.ts.map +1 -1
  92. package/dist/senpi/client.js +181 -8
  93. package/dist/senpi/client.js.map +1 -1
  94. package/openclaw.plugin.json +24 -0
  95. package/package.json +6 -2
@@ -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;AAM/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAwDpD;;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,CA+CN"}
@@ -0,0 +1,90 @@
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
+ function toWire(r) {
19
+ if (r.success) {
20
+ return {
21
+ success: true,
22
+ address: r.address,
23
+ scanner: r.scanner,
24
+ data: {
25
+ timestamp: r.timestamp,
26
+ signalCount: r.signalCount,
27
+ contextUpdated: r.contextUpdated,
28
+ },
29
+ };
30
+ }
31
+ return {
32
+ success: false,
33
+ address: r.address,
34
+ scanner: r.scanner,
35
+ error: {
36
+ code: r.code,
37
+ message: r.message,
38
+ },
39
+ };
40
+ }
41
+ /**
42
+ * Register `POST /signals` on the given Fastify instance.
43
+ *
44
+ * The route validates the body against the `SignalsBody` TypeBox schema, then:
45
+ * 1. Rejects oversized batches (handler-level cap, configurable).
46
+ * 2. Groups items by `(address, scanner)` via `groupByAddressScanner`.
47
+ * 3. Runs groups in parallel; items within each group run sequentially.
48
+ * 4. Re-flattens results back to input order before responding.
49
+ *
50
+ * @param fastify Fastify instance to register the route on.
51
+ * @param deps Route dependencies injected at plugin start.
52
+ */
53
+ export function registerSignalsRoute(fastify, deps) {
54
+ fastify.post("/signals", { schema: { body: SignalsBody } }, async (req, reply) => {
55
+ const items = req.body;
56
+ // Handler-level cap — operator-tunable, not encoded in the TypeBox schema.
57
+ if (items.length > deps.maxItems) {
58
+ return reply.status(400).send({
59
+ success: false,
60
+ error: {
61
+ code: "INVALID_REQUEST",
62
+ message: `Exceeded api.maxItemsPerSignalsRequest=${deps.maxItems}; got ${items.length}.`,
63
+ },
64
+ });
65
+ }
66
+ // Group by (address, scanner) — each group is a SignalGroup (IndexedSignalItem[]).
67
+ const groups = groupByAddressScanner(items);
68
+ // Fan out across groups in parallel; process items within each group sequentially.
69
+ const grouped = await Promise.all(groups.map(async (group) => {
70
+ const out = [];
71
+ for (const { index, item } of group) {
72
+ out.push({
73
+ index,
74
+ result: await ingestSignalsHandler(item, {
75
+ runtimeHandles: deps.runtimeHandles,
76
+ logger: deps.logger,
77
+ transport: deps.transport,
78
+ }),
79
+ });
80
+ }
81
+ return out;
82
+ }));
83
+ // Re-flatten in input order.
84
+ const flat = grouped.flat();
85
+ flat.sort((a, b) => a.index - b.index);
86
+ const results = flat.map((entry) => toWire(entry.result));
87
+ return reply.send({ success: true, data: { results } });
88
+ });
89
+ }
90
+ //# sourceMappingURL=signals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signals.js","sourceRoot":"","sources":["../../../src/runtime-api/routes/signals.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * TypeBox schema for the `POST /signals` request body.
3
+ *
4
+ * `SignalItemT` is derived from TypeBox `Static<>` and is structurally
5
+ * compatible with the hand-written {@link SignalItem} interface in
6
+ * `handlers/types.ts`. The interface in `handlers/types.ts` is kept as the
7
+ * canonical description (referenced by JSDoc across the codebase); this module
8
+ * derives the runtime-validatable form from TypeBox so both shapes stay in
9
+ * sync at compile-time.
10
+ *
11
+ * Note on `direction`: the TypeBox schema accepts any string so
12
+ * `SignalItemT["direction"]` is `string | undefined`, matching
13
+ * `Signal["direction"]` in `scanners/types.ts`. The tighter
14
+ * `"long" | "short" | null` constraint lives in the MCP layer; the runtime
15
+ * applies it implicitly during scanner-engine ingest.
16
+ *
17
+ * Note on `maxItems`: enforced at handler level using the configured
18
+ * `api.maxItemsPerSignalsRequest` value (default 10). Schema-level cap is
19
+ * kept open-ended so the shape works in tests without recompiling.
20
+ */
21
+ import { type Static } from "@sinclair/typebox";
22
+ /** TypeBox schema for one item in the `POST /signals` body. */
23
+ export declare const SignalItem: import("@sinclair/typebox").TObject<{
24
+ /** Wallet address of the target runtime. Lowercased server-side. */
25
+ address: import("@sinclair/typebox").TString;
26
+ /** Configured scanner id. */
27
+ scanner: import("@sinclair/typebox").TString;
28
+ /** Asset for a single ingested signal. */
29
+ asset: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
30
+ /**
31
+ * Direction for a single ingested signal.
32
+ * Accepts any string — `"long"` / `"short"` are the conventional values.
33
+ */
34
+ direction: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
35
+ /** Confidence score for a single ingested signal (0–1). */
36
+ score: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
37
+ /** Signal classification override for a single ingested signal. */
38
+ signal_type: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
39
+ /**
40
+ * Single ingest payload for signal-producing or context-producing scanners.
41
+ * Mutually exclusive with `signals[]`.
42
+ */
43
+ data: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TUnknown>>;
44
+ /**
45
+ * Batch signal payloads for signal-producing external scanners.
46
+ * Mutually exclusive with `data`.
47
+ */
48
+ signals: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
49
+ asset: import("@sinclair/typebox").TString;
50
+ direction: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
51
+ score: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
52
+ signal_type: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
53
+ data: import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TUnknown>;
54
+ }>>>;
55
+ }>;
56
+ /** TypeBox schema for the full `POST /signals` request body array. */
57
+ export declare const SignalsBody: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
58
+ /** Wallet address of the target runtime. Lowercased server-side. */
59
+ address: import("@sinclair/typebox").TString;
60
+ /** Configured scanner id. */
61
+ scanner: import("@sinclair/typebox").TString;
62
+ /** Asset for a single ingested signal. */
63
+ asset: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
64
+ /**
65
+ * Direction for a single ingested signal.
66
+ * Accepts any string — `"long"` / `"short"` are the conventional values.
67
+ */
68
+ direction: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
69
+ /** Confidence score for a single ingested signal (0–1). */
70
+ score: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
71
+ /** Signal classification override for a single ingested signal. */
72
+ signal_type: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
73
+ /**
74
+ * Single ingest payload for signal-producing or context-producing scanners.
75
+ * Mutually exclusive with `signals[]`.
76
+ */
77
+ data: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TUnknown>>;
78
+ /**
79
+ * Batch signal payloads for signal-producing external scanners.
80
+ * Mutually exclusive with `data`.
81
+ */
82
+ signals: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
83
+ asset: import("@sinclair/typebox").TString;
84
+ direction: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
85
+ score: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
86
+ signal_type: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
87
+ data: import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TUnknown>;
88
+ }>>>;
89
+ }>>;
90
+ /** TypeScript type for one signal item — derived from TypeBox, single source of truth. */
91
+ export type SignalItemT = Static<typeof SignalItem>;
92
+ /** TypeScript type for the `POST /signals` request body. */
93
+ export type SignalsBodyT = Static<typeof SignalsBody>;
94
+ //# sourceMappingURL=signals.schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signals.schema.d.ts","sourceRoot":"","sources":["../../../src/runtime-api/routes/signals.schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAQ,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEtD,+DAA+D;AAC/D,eAAO,MAAM,UAAU;IAEnB,oEAAoE;;IAEpE,6BAA6B;;IAE7B,0CAA0C;;IAE1C;;;OAGG;;IAEH,2DAA2D;;IAE3D,mEAAmE;;IAEnE;;;OAGG;;IAEH;;;OAGG;;;;;;;;EAcN,CAAC;AAEF,sEAAsE;AACtE,eAAO,MAAM,WAAW;IAxCpB,oEAAoE;;IAEpE,6BAA6B;;IAE7B,0CAA0C;;IAE1C;;;OAGG;;IAEH,2DAA2D;;IAE3D,mEAAmE;;IAEnE;;;OAGG;;IAEH;;;OAGG;;;;;;;;GAiB2D,CAAC;AAEnE,0FAA0F;AAC1F,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAEpD,4DAA4D;AAC5D,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,WAAW,CAAC,CAAC"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * TypeBox schema for the `POST /signals` request body.
3
+ *
4
+ * `SignalItemT` is derived from TypeBox `Static<>` and is structurally
5
+ * compatible with the hand-written {@link SignalItem} interface in
6
+ * `handlers/types.ts`. The interface in `handlers/types.ts` is kept as the
7
+ * canonical description (referenced by JSDoc across the codebase); this module
8
+ * derives the runtime-validatable form from TypeBox so both shapes stay in
9
+ * sync at compile-time.
10
+ *
11
+ * Note on `direction`: the TypeBox schema accepts any string so
12
+ * `SignalItemT["direction"]` is `string | undefined`, matching
13
+ * `Signal["direction"]` in `scanners/types.ts`. The tighter
14
+ * `"long" | "short" | null` constraint lives in the MCP layer; the runtime
15
+ * applies it implicitly during scanner-engine ingest.
16
+ *
17
+ * Note on `maxItems`: enforced at handler level using the configured
18
+ * `api.maxItemsPerSignalsRequest` value (default 10). Schema-level cap is
19
+ * kept open-ended so the shape works in tests without recompiling.
20
+ */
21
+ import { Type } from "@sinclair/typebox";
22
+ /** TypeBox schema for one item in the `POST /signals` body. */
23
+ export const SignalItem = Type.Object({
24
+ /** Wallet address of the target runtime. Lowercased server-side. */
25
+ address: Type.String({ minLength: 1 }),
26
+ /** Configured scanner id. */
27
+ scanner: Type.String({ minLength: 1 }),
28
+ /** Asset for a single ingested signal. */
29
+ asset: Type.Optional(Type.String()),
30
+ /**
31
+ * Direction for a single ingested signal.
32
+ * Accepts any string — `"long"` / `"short"` are the conventional values.
33
+ */
34
+ direction: Type.Optional(Type.String()),
35
+ /** Confidence score for a single ingested signal (0–1). */
36
+ score: Type.Optional(Type.Number({ minimum: 0, maximum: 1 })),
37
+ /** Signal classification override for a single ingested signal. */
38
+ signal_type: Type.Optional(Type.String()),
39
+ /**
40
+ * Single ingest payload for signal-producing or context-producing scanners.
41
+ * Mutually exclusive with `signals[]`.
42
+ */
43
+ data: Type.Optional(Type.Record(Type.String(), Type.Unknown())),
44
+ /**
45
+ * Batch signal payloads for signal-producing external scanners.
46
+ * Mutually exclusive with `data`.
47
+ */
48
+ signals: Type.Optional(Type.Array(Type.Object({
49
+ asset: Type.String(),
50
+ direction: Type.Optional(Type.String()),
51
+ score: Type.Optional(Type.Number({ minimum: 0, maximum: 1 })),
52
+ signal_type: Type.Optional(Type.String()),
53
+ data: Type.Record(Type.String(), Type.Unknown()),
54
+ }))),
55
+ }, { additionalProperties: false });
56
+ /** TypeBox schema for the full `POST /signals` request body array. */
57
+ export const SignalsBody = Type.Array(SignalItem, { minItems: 1 });
58
+ //# sourceMappingURL=signals.schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signals.schema.js","sourceRoot":"","sources":["../../../src/runtime-api/routes/signals.schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,IAAI,EAAe,MAAM,mBAAmB,CAAC;AAEtD,+DAA+D;AAC/D,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CACnC;IACE,oEAAoE;IACpE,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;IACtC,6BAA6B;IAC7B,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;IACtC,0CAA0C;IAC1C,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;IACnC;;;OAGG;IACH,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;IACvC,2DAA2D;IAC3D,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAC7D,mEAAmE;IACnE,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;IACzC;;;OAGG;IACH,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/D;;;OAGG;IACH,OAAO,EAAE,IAAI,CAAC,QAAQ,CACpB,IAAI,CAAC,KAAK,CACR,IAAI,CAAC,MAAM,CAAC;QACV,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE;QACpB,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;QACvC,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;QAC7D,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;QACzC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC;KACjD,CAAC,CACH,CACF;CACF,EACD,EAAE,oBAAoB,EAAE,KAAK,EAAE,CAChC,CAAC;AAEF,sEAAsE;AACtE,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * `createApi()` — Fastify server factory for the runtime HTTP API.
3
+ *
4
+ * Wires the Fastify instance with:
5
+ * - `POST /signals` — ingest signals for one or more wallets.
6
+ * - `GET /audit` — MCP audit-query proxy scoped to one wallet.
7
+ * - `GET /health` — three-state readiness + per-runtime queue depth.
8
+ *
9
+ * Returns the Fastify instance, the mutable readiness flag, and the boot
10
+ * timestamp. The lifecycle layer (S5) calls `fastify.listen()` and flips
11
+ * `readiness.setOk()` / `readiness.setDraining()` around start/stop.
12
+ *
13
+ * This module owns only wiring — no business logic. All route logic
14
+ * delegates to the shared handlers in `handlers/`.
15
+ */
16
+ import { type FastifyInstance } from "fastify";
17
+ import { createReadiness } from "./readiness.js";
18
+ import type { RuntimeHandle } from "../runtime/run.js";
19
+ import type { Logger } from "../utils/logger.js";
20
+ import type { ApiConfig } from "./config.js";
21
+ /**
22
+ * Dependencies passed to {@link createApi}.
23
+ */
24
+ export interface CreateApiDeps {
25
+ /** Live runtime handles maintained by the plugin, keyed by lowercased address. */
26
+ runtimeHandles: Map<string, RuntimeHandle>;
27
+ /** Validated `api` config block (host, port, maxItemsPerSignalsRequest). */
28
+ apiConfig: ApiConfig;
29
+ /** Logger instance — forwarded to shared handlers for structured error logging. */
30
+ logger: Logger;
31
+ /**
32
+ * Plugin version string read from `openclaw.plugin.json` at boot.
33
+ * Exposed in `GET /health` so callers can correlate requests with deployments.
34
+ */
35
+ version: string;
36
+ }
37
+ /**
38
+ * Artifacts returned by {@link createApi}.
39
+ *
40
+ * Ownership:
41
+ * - `fastify` — call `.listen()` and `.close()` in the lifecycle layer (S5).
42
+ * - `readiness` — call `setOk()` after `.listen()` resolves; `setDraining()`
43
+ * before `.close()` during graceful shutdown.
44
+ * - `bootedAt` — Unix epoch ms recorded when `createApi()` was called;
45
+ * used by `GET /health` to compute `uptime_ms`.
46
+ */
47
+ export interface ApiArtifacts {
48
+ fastify: FastifyInstance;
49
+ readiness: ReturnType<typeof createReadiness>;
50
+ bootedAt: number;
51
+ }
52
+ /**
53
+ * Create and configure the Fastify HTTP server.
54
+ *
55
+ * Does NOT start listening. Call `artifacts.fastify.listen(...)` from the
56
+ * lifecycle layer (S5) after `createApi()` returns.
57
+ *
58
+ * Error handler behaviour:
59
+ * - `400` (schema validation), `413` (body too large), `415` (wrong
60
+ * content-type) are passed through as `INVALID_REQUEST` with the original
61
+ * Fastify message so callers can read the validation detail.
62
+ * - All other errors are logged and returned as `500 / UNAVAILABLE`.
63
+ *
64
+ * Request timeout strategy (resolved in S5):
65
+ * A single server-wide `requestTimeout: 30_000` covers all routes.
66
+ * The plan called for per-route values (10s for `/signals` + `/health`,
67
+ * 30s for `/audit`), but Fastify v5 does not expose a declarative per-route
68
+ * `requestTimeout` and wiring an `onRequest` hook with manual `setTimeout`
69
+ * calls adds meaningful complexity for a localhost-only server where requests
70
+ * that genuinely hang are almost always MCP-side. The 30s ceiling is driven
71
+ * entirely by `/audit` (MCP round-trip); `/signals` and `/health` both
72
+ * complete in well under 1s in practice. If per-route enforcement becomes
73
+ * necessary, add an `onRequest` hook in this file.
74
+ *
75
+ * @param deps Dependencies injected by the plugin entry point.
76
+ * @returns `{ fastify, readiness, bootedAt }`.
77
+ */
78
+ export declare function createApi(deps: CreateApiDeps): ApiArtifacts;
79
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/runtime-api/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,SAAS,CAAC;AAIxD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,kFAAkF;IAClF,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC3C,4EAA4E;IAC5E,SAAS,EAAE,SAAS,CAAC;IACrB,mFAAmF;IACnF,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,eAAe,CAAC;IACzB,SAAS,EAAE,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;IAC9C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,YAAY,CAqE3D"}