@jini-ai/http-kit 0.2.1
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/LICENSE +201 -0
- package/README.md +107 -0
- package/dist/active-context.d.ts +99 -0
- package/dist/active-context.d.ts.map +1 -0
- package/dist/active-context.js +77 -0
- package/dist/active-context.js.map +1 -0
- package/dist/adapter.d.ts +36 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.js +92 -0
- package/dist/adapter.js.map +1 -0
- package/dist/agents.d.ts +55 -0
- package/dist/agents.d.ts.map +1 -0
- package/dist/agents.js +23 -0
- package/dist/agents.js.map +1 -0
- package/dist/api-security-middleware.d.ts +146 -0
- package/dist/api-security-middleware.d.ts.map +1 -0
- package/dist/api-security-middleware.js +276 -0
- package/dist/api-security-middleware.js.map +1 -0
- package/dist/attachments.d.ts +317 -0
- package/dist/attachments.d.ts.map +1 -0
- package/dist/attachments.js +664 -0
- package/dist/attachments.js.map +1 -0
- package/dist/cancel-owned-runs.d.ts +44 -0
- package/dist/cancel-owned-runs.d.ts.map +1 -0
- package/dist/cancel-owned-runs.js +35 -0
- package/dist/cancel-owned-runs.js.map +1 -0
- package/dist/compat.d.ts +22 -0
- package/dist/compat.d.ts.map +1 -0
- package/dist/compat.js +17 -0
- package/dist/compat.js.map +1 -0
- package/dist/component-catalog.d.ts +74 -0
- package/dist/component-catalog.d.ts.map +1 -0
- package/dist/component-catalog.js +74 -0
- package/dist/component-catalog.js.map +1 -0
- package/dist/connectors.d.ts +165 -0
- package/dist/connectors.d.ts.map +1 -0
- package/dist/connectors.js +474 -0
- package/dist/connectors.js.map +1 -0
- package/dist/daemon-status.d.ts +72 -0
- package/dist/daemon-status.d.ts.map +1 -0
- package/dist/daemon-status.js +60 -0
- package/dist/daemon-status.js.map +1 -0
- package/dist/db-ops.d.ts +116 -0
- package/dist/db-ops.d.ts.map +1 -0
- package/dist/db-ops.js +191 -0
- package/dist/db-ops.js.map +1 -0
- package/dist/delegated-tools.d.ts +46 -0
- package/dist/delegated-tools.d.ts.map +1 -0
- package/dist/delegated-tools.js +155 -0
- package/dist/delegated-tools.js.map +1 -0
- package/dist/express/run-stream.d.ts +15 -0
- package/dist/express/run-stream.d.ts.map +1 -0
- package/dist/express/run-stream.js +11 -0
- package/dist/express/run-stream.js.map +1 -0
- package/dist/express-index.d.ts +32 -0
- package/dist/express-index.d.ts.map +1 -0
- package/dist/express-index.js +14 -0
- package/dist/express-index.js.map +1 -0
- package/dist/fastify/adapter.d.ts +31 -0
- package/dist/fastify/adapter.d.ts.map +1 -0
- package/dist/fastify/adapter.js +64 -0
- package/dist/fastify/adapter.js.map +1 -0
- package/dist/fastify/agents.d.ts +13 -0
- package/dist/fastify/agents.d.ts.map +1 -0
- package/dist/fastify/agents.js +7 -0
- package/dist/fastify/agents.js.map +1 -0
- package/dist/fastify/api-security-middleware.d.ts +64 -0
- package/dist/fastify/api-security-middleware.d.ts.map +1 -0
- package/dist/fastify/api-security-middleware.js +139 -0
- package/dist/fastify/api-security-middleware.js.map +1 -0
- package/dist/fastify/compat.d.ts +22 -0
- package/dist/fastify/compat.d.ts.map +1 -0
- package/dist/fastify/compat.js +16 -0
- package/dist/fastify/compat.js.map +1 -0
- package/dist/fastify/daemon-status.d.ts +22 -0
- package/dist/fastify/daemon-status.d.ts.map +1 -0
- package/dist/fastify/daemon-status.js +9 -0
- package/dist/fastify/daemon-status.js.map +1 -0
- package/dist/fastify/host-tools.d.ts +13 -0
- package/dist/fastify/host-tools.d.ts.map +1 -0
- package/dist/fastify/host-tools.js +8 -0
- package/dist/fastify/host-tools.js.map +1 -0
- package/dist/fastify/index.d.ts +36 -0
- package/dist/fastify/index.d.ts.map +1 -0
- package/dist/fastify/index.js +18 -0
- package/dist/fastify/index.js.map +1 -0
- package/dist/fastify/local-daemon-request.d.ts +43 -0
- package/dist/fastify/local-daemon-request.d.ts.map +1 -0
- package/dist/fastify/local-daemon-request.js +155 -0
- package/dist/fastify/local-daemon-request.js.map +1 -0
- package/dist/fastify/origin.d.ts +21 -0
- package/dist/fastify/origin.d.ts.map +1 -0
- package/dist/fastify/origin.js +14 -0
- package/dist/fastify/origin.js.map +1 -0
- package/dist/fastify/request.d.ts +20 -0
- package/dist/fastify/request.d.ts.map +1 -0
- package/dist/fastify/request.js +25 -0
- package/dist/fastify/request.js.map +1 -0
- package/dist/fastify/response.d.ts +20 -0
- package/dist/fastify/response.d.ts.map +1 -0
- package/dist/fastify/response.js +41 -0
- package/dist/fastify/response.js.map +1 -0
- package/dist/fastify/route-registration-guard.d.ts +70 -0
- package/dist/fastify/route-registration-guard.d.ts.map +1 -0
- package/dist/fastify/route-registration-guard.js +69 -0
- package/dist/fastify/route-registration-guard.js.map +1 -0
- package/dist/fastify/run-stream.d.ts +18 -0
- package/dist/fastify/run-stream.d.ts.map +1 -0
- package/dist/fastify/run-stream.js +10 -0
- package/dist/fastify/run-stream.js.map +1 -0
- package/dist/fastify/runs.d.ts +17 -0
- package/dist/fastify/runs.d.ts.map +1 -0
- package/dist/fastify/runs.js +33 -0
- package/dist/fastify/runs.js.map +1 -0
- package/dist/frontend-control.d.ts +131 -0
- package/dist/frontend-control.d.ts.map +1 -0
- package/dist/frontend-control.js +77 -0
- package/dist/frontend-control.js.map +1 -0
- package/dist/frontend-sessions.d.ts +100 -0
- package/dist/frontend-sessions.d.ts.map +1 -0
- package/dist/frontend-sessions.js +180 -0
- package/dist/frontend-sessions.js.map +1 -0
- package/dist/health.d.ts +91 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +53 -0
- package/dist/health.js.map +1 -0
- package/dist/host-tools.d.ts +174 -0
- package/dist/host-tools.d.ts.map +1 -0
- package/dist/host-tools.js +338 -0
- package/dist/host-tools.js.map +1 -0
- package/dist/index.d.ts +86 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/local-daemon-request.d.ts +44 -0
- package/dist/local-daemon-request.d.ts.map +1 -0
- package/dist/local-daemon-request.js +145 -0
- package/dist/local-daemon-request.js.map +1 -0
- package/dist/media.d.ts +131 -0
- package/dist/media.d.ts.map +1 -0
- package/dist/media.js +352 -0
- package/dist/media.js.map +1 -0
- package/dist/memory.d.ts +230 -0
- package/dist/memory.d.ts.map +1 -0
- package/dist/memory.js +331 -0
- package/dist/memory.js.map +1 -0
- package/dist/model-proxy.d.ts +45 -0
- package/dist/model-proxy.d.ts.map +1 -0
- package/dist/model-proxy.js +619 -0
- package/dist/model-proxy.js.map +1 -0
- package/dist/origin-validation.d.ts +64 -0
- package/dist/origin-validation.d.ts.map +1 -0
- package/dist/origin-validation.js +226 -0
- package/dist/origin-validation.js.map +1 -0
- package/dist/origin.d.ts +32 -0
- package/dist/origin.d.ts.map +1 -0
- package/dist/origin.js +14 -0
- package/dist/origin.js.map +1 -0
- package/dist/pack-http.d.ts +30 -0
- package/dist/pack-http.d.ts.map +1 -0
- package/dist/pack-http.js +12 -0
- package/dist/pack-http.js.map +1 -0
- package/dist/raw-sse.d.ts +44 -0
- package/dist/raw-sse.d.ts.map +1 -0
- package/dist/raw-sse.js +93 -0
- package/dist/raw-sse.js.map +1 -0
- package/dist/remote-run-events.d.ts +66 -0
- package/dist/remote-run-events.d.ts.map +1 -0
- package/dist/remote-run-events.js +230 -0
- package/dist/remote-run-events.js.map +1 -0
- package/dist/request.d.ts +19 -0
- package/dist/request.d.ts.map +1 -0
- package/dist/request.js +25 -0
- package/dist/request.js.map +1 -0
- package/dist/research.d.ts +42 -0
- package/dist/research.d.ts.map +1 -0
- package/dist/research.js +316 -0
- package/dist/research.js.map +1 -0
- package/dist/response.d.ts +14 -0
- package/dist/response.d.ts.map +1 -0
- package/dist/response.js +45 -0
- package/dist/response.js.map +1 -0
- package/dist/route-manifest.d.ts +31 -0
- package/dist/route-manifest.d.ts.map +1 -0
- package/dist/route-manifest.js +103 -0
- package/dist/route-manifest.js.map +1 -0
- package/dist/route-registration-guard.d.ts +65 -0
- package/dist/route-registration-guard.d.ts.map +1 -0
- package/dist/route-registration-guard.js +71 -0
- package/dist/route-registration-guard.js.map +1 -0
- package/dist/routines.d.ts +114 -0
- package/dist/routines.d.ts.map +1 -0
- package/dist/routines.js +320 -0
- package/dist/routines.js.map +1 -0
- package/dist/run-stream.d.ts +60 -0
- package/dist/run-stream.d.ts.map +1 -0
- package/dist/run-stream.js +108 -0
- package/dist/run-stream.js.map +1 -0
- package/dist/runs.d.ts +79 -0
- package/dist/runs.d.ts.map +1 -0
- package/dist/runs.js +232 -0
- package/dist/runs.js.map +1 -0
- package/dist/sse.d.ts +139 -0
- package/dist/sse.d.ts.map +1 -0
- package/dist/sse.js +157 -0
- package/dist/sse.js.map +1 -0
- package/dist/terminals.d.ts +125 -0
- package/dist/terminals.d.ts.map +1 -0
- package/dist/terminals.js +349 -0
- package/dist/terminals.js.map +1 -0
- package/dist/tool-catalog.d.ts +68 -0
- package/dist/tool-catalog.d.ts.map +1 -0
- package/dist/tool-catalog.js +68 -0
- package/dist/tool-catalog.js.map +1 -0
- package/dist/types.d.ts +58 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/workspace-root.d.ts +69 -0
- package/dist/workspace-root.d.ts.map +1 -0
- package/dist/workspace-root.js +63 -0
- package/dist/workspace-root.js.map +1 -0
- package/dist/xai.d.ts +86 -0
- package/dist/xai.d.ts.map +1 -0
- package/dist/xai.js +668 -0
- package/dist/xai.js.map +1 -0
- package/package.json +58 -0
package/dist/db-ops.d.ts
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { Express } from 'express';
|
|
2
|
+
import type { Principal, ToolPolicy, ToolRegistration } from '@jini-ai/core';
|
|
3
|
+
import type { ToolExecutor } from '@jini-ai/daemon';
|
|
4
|
+
import { type AdapterContext } from './adapter.js';
|
|
5
|
+
/** The `ToolRegistry` id `GET /api/daemon/db` executes through. */
|
|
6
|
+
export declare const DB_INSPECT_TOOL_ID = "daemon.db.inspect";
|
|
7
|
+
/** The `ToolRegistry` id `POST /api/daemon/db/verify` executes through. */
|
|
8
|
+
export declare const DB_VERIFY_TOOL_ID = "daemon.db.verify";
|
|
9
|
+
/** The `ToolRegistry` id `POST /api/daemon/db/vacuum` executes through. */
|
|
10
|
+
export declare const DB_VACUUM_TOOL_ID = "daemon.db.vacuum";
|
|
11
|
+
export interface DaemonDbTableInfo {
|
|
12
|
+
readonly name: string;
|
|
13
|
+
readonly rowCount: number;
|
|
14
|
+
}
|
|
15
|
+
/** Structurally identical to `@jini-ai/sqlite`'s `DaemonDbStatusReport` — defined locally so this package incurs no `better-sqlite3` dependency. */
|
|
16
|
+
export interface DaemonDbStatusReport {
|
|
17
|
+
readonly kind: 'sqlite' | 'postgres';
|
|
18
|
+
readonly location: string;
|
|
19
|
+
readonly sizeBytes: number;
|
|
20
|
+
readonly schemaVersion: number | null;
|
|
21
|
+
readonly tables: readonly DaemonDbTableInfo[];
|
|
22
|
+
readonly generatedAt: number;
|
|
23
|
+
}
|
|
24
|
+
export type DbIntegrityIssueKind = 'integrity' | 'foreign_key';
|
|
25
|
+
export interface DbIntegrityIssue {
|
|
26
|
+
readonly kind: DbIntegrityIssueKind;
|
|
27
|
+
readonly message: string;
|
|
28
|
+
}
|
|
29
|
+
/** Structurally identical to `@jini-ai/sqlite`'s `DbIntegrityReport`. */
|
|
30
|
+
export interface DbIntegrityReport {
|
|
31
|
+
readonly ok: boolean;
|
|
32
|
+
readonly mode: 'integrity_check' | 'quick_check';
|
|
33
|
+
readonly issues: readonly DbIntegrityIssue[];
|
|
34
|
+
readonly elapsedMs: number;
|
|
35
|
+
readonly generatedAt: number;
|
|
36
|
+
}
|
|
37
|
+
export interface DaemonDbVacuumResult {
|
|
38
|
+
readonly ok: true;
|
|
39
|
+
readonly beforeBytes: number;
|
|
40
|
+
readonly afterBytes: number;
|
|
41
|
+
readonly reclaimedBytes: number;
|
|
42
|
+
readonly elapsedMs: number;
|
|
43
|
+
}
|
|
44
|
+
/** The real collaborator a host injects — typically backed by `@jini-ai/sqlite`'s `inspectSqliteDatabase`/`verifySqliteIntegrity` plus a small `vacuum` wrapper around `db.exec('VACUUM')`. */
|
|
45
|
+
export interface DaemonDbOperations {
|
|
46
|
+
inspect(): Promise<DaemonDbStatusReport> | DaemonDbStatusReport;
|
|
47
|
+
verify(quick: boolean): Promise<DbIntegrityReport> | DbIntegrityReport;
|
|
48
|
+
vacuum(): Promise<DaemonDbVacuumResult> | DaemonDbVacuumResult;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Deny-by-default `ToolPolicy` shared by all three DB tools — every call is
|
|
52
|
+
* denied, unconditionally, regardless of principal. Matching
|
|
53
|
+
* `@jini-ai/deploy`'s `denyAllDeployPublishPolicy` precedent: a host must
|
|
54
|
+
* explicitly opt in with its own policy (e.g. role-gated, or "same principal
|
|
55
|
+
* that owns the daemon process") rather than getting a working DB inspector
|
|
56
|
+
* for free merely by registering the tools. `inspect`/`verify` disclose
|
|
57
|
+
* internal schema and row-count information; `vacuum` rewrites the database
|
|
58
|
+
* file in place — none of the three has a safe "mostly harmless" default the
|
|
59
|
+
* way a pure read-only, non-sensitive tool might.
|
|
60
|
+
*/
|
|
61
|
+
export declare const denyAllDaemonDbPolicy: ToolPolicy;
|
|
62
|
+
export interface CreateDaemonDbToolRegistrationsOptions {
|
|
63
|
+
readonly operations: DaemonDbOperations;
|
|
64
|
+
/** Defaults to {@link denyAllDaemonDbPolicy} — see its doc for why a permissive default was rejected. Applies to all three tools; pass distinct `ToolRegistration.policy` values by registering them individually if a host wants per-operation rules. */
|
|
65
|
+
readonly policy?: ToolPolicy;
|
|
66
|
+
readonly requiresConfirmation?: boolean;
|
|
67
|
+
readonly timeoutMs?: number;
|
|
68
|
+
}
|
|
69
|
+
export interface DaemonDbToolRegistrations {
|
|
70
|
+
readonly inspect: ToolRegistration;
|
|
71
|
+
readonly verify: ToolRegistration;
|
|
72
|
+
readonly vacuum: ToolRegistration;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Builds the three `{descriptor, handler, policy}` triples a host registers
|
|
76
|
+
* against `@jini-ai/core`'s `ToolRegistry` so the DB operations become
|
|
77
|
+
* reachable only via `ToolExecutor.execute(principal, run, toolId, input)` —
|
|
78
|
+
* never by a route calling `operations.inspect()`/`verify()`/`vacuum()`
|
|
79
|
+
* directly, which would bypass authorization and the audit trail entirely.
|
|
80
|
+
*
|
|
81
|
+
* @complexity O(1) to build the three registrations; each handler's own cost is `operations`'s.
|
|
82
|
+
* @overallScore 100/100
|
|
83
|
+
*/
|
|
84
|
+
export declare function createDaemonDbToolRegistrations(options: CreateDaemonDbToolRegistrationsOptions): DaemonDbToolRegistrations;
|
|
85
|
+
/** Diagnostic detail for an internal-error response the public API deliberately does not disclose (SEC-005, matching `runs.ts`'s `RunInternalErrorContext`): a `failed`/`timed-out`/`cancelled` tool execution can embed schema names, file paths, or a raw SQLite error message. */
|
|
86
|
+
export interface DaemonDbInternalErrorContext {
|
|
87
|
+
readonly source: 'db-inspect' | 'db-verify' | 'db-vacuum';
|
|
88
|
+
readonly correlationId: string;
|
|
89
|
+
readonly error: unknown;
|
|
90
|
+
}
|
|
91
|
+
export interface DaemonDbHttpDeps {
|
|
92
|
+
readonly toolExecutor: ToolExecutor;
|
|
93
|
+
/**
|
|
94
|
+
* The identity these routes execute tool calls as. A fixed, host-supplied
|
|
95
|
+
* value rather than derived per-request — this transport has no session/
|
|
96
|
+
* identity subsystem of its own (see `packages/http/source-map.md`'s
|
|
97
|
+
* `ExecutionDelegate` design-decision note); a host that needs per-request
|
|
98
|
+
* principals should resolve one from its own auth layer and construct
|
|
99
|
+
* `DaemonDbHttpDeps` per request, or supply a `ToolPolicy` that inspects
|
|
100
|
+
* something other than `Principal` to make its decision.
|
|
101
|
+
*/
|
|
102
|
+
readonly principal: Principal;
|
|
103
|
+
/** Host-owned sink for the real exception behind a generic `INTERNAL_ERROR` response (SEC-005). Defaults to `console.error`. */
|
|
104
|
+
readonly onInternalError?: (context: DaemonDbInternalErrorContext) => void;
|
|
105
|
+
}
|
|
106
|
+
/** `GET /api/daemon/db` — the database inventory (schema version, tables, row counts, size). */
|
|
107
|
+
export declare const daemonDbInspectRoute: import("./types.js").JsonRouteSpec<void, DaemonDbStatusReport, DaemonDbHttpDeps>;
|
|
108
|
+
/** `POST /api/daemon/db/verify?quick=` — `PRAGMA integrity_check`/`quick_check` plus `foreign_key_check`. */
|
|
109
|
+
export declare const daemonDbVerifyRoute: import("./types.js").JsonRouteSpec<{
|
|
110
|
+
quick: boolean;
|
|
111
|
+
}, DbIntegrityReport, DaemonDbHttpDeps>;
|
|
112
|
+
/** `POST /api/daemon/db/vacuum` — runs `VACUUM` and reports bytes reclaimed. */
|
|
113
|
+
export declare const daemonDbVacuumRoute: import("./types.js").JsonRouteSpec<void, DaemonDbVacuumResult, DaemonDbHttpDeps>;
|
|
114
|
+
/** Mounts all three DB-ops routes on `app`. A pack's `http(app, services)` calls this directly. */
|
|
115
|
+
export declare function registerDaemonDbRoutes(app: Express, deps: DaemonDbHttpDeps, adapter: AdapterContext): void;
|
|
116
|
+
//# sourceMappingURL=db-ops.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db-ops.d.ts","sourceRoot":"","sources":["../src/db-ops.ts"],"names":[],"mappings":"AAuCA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,KAAK,EAAE,SAAS,EAAU,UAAU,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACrF,OAAO,KAAK,EAAuB,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEzE,OAAO,EAAmC,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAIpF,mEAAmE;AACnE,eAAO,MAAM,kBAAkB,sBAAsB,CAAC;AACtD,2EAA2E;AAC3E,eAAO,MAAM,iBAAiB,qBAAqB,CAAC;AACpD,2EAA2E;AAC3E,eAAO,MAAM,iBAAiB,qBAAqB,CAAC;AAEpD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,oJAAoJ;AACpJ,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,UAAU,CAAC;IACrC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC9C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,MAAM,oBAAoB,GAAG,WAAW,GAAG,aAAa,CAAC;AAE/D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,yEAAyE;AACzE,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,iBAAiB,GAAG,aAAa,CAAC;IACjD,QAAQ,CAAC,MAAM,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC7C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAClB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,+LAA+L;AAC/L,MAAM,WAAW,kBAAkB;IACjC,OAAO,IAAI,OAAO,CAAC,oBAAoB,CAAC,GAAG,oBAAoB,CAAC;IAChE,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,iBAAiB,CAAC,GAAG,iBAAiB,CAAC;IACvE,MAAM,IAAI,OAAO,CAAC,oBAAoB,CAAC,GAAG,oBAAoB,CAAC;CAChE;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qBAAqB,EAAE,UAEnC,CAAC;AAEF,MAAM,WAAW,sCAAsC;IACrD,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC;IACxC,0PAA0P;IAC1P,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IACxC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;CACnC;AAMD;;;;;;;;;GASG;AACH,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,sCAAsC,GAC9C,yBAAyB,CAuC3B;AAED,qRAAqR;AACrR,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,MAAM,EAAE,YAAY,GAAG,WAAW,GAAG,WAAW,CAAC;IAC1D,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAOD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC;;;;;;;;OAQG;IACH,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,gIAAgI;IAChI,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,4BAA4B,KAAK,IAAI,CAAC;CAC5E;AA8BD,gGAAgG;AAChG,eAAO,MAAM,oBAAoB,kFAS/B,CAAC;AAYH,6GAA6G;AAC7G,eAAO,MAAM,mBAAmB;WAA4B,OAAO;uCASjE,CAAC;AAEH,gFAAgF;AAChF,eAAO,MAAM,mBAAmB,kFAS9B,CAAC;AAEH,mGAAmG;AACnG,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,cAAc,GAAG,IAAI,CAI1G"}
|
package/dist/db-ops.js
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module db-ops
|
|
3
|
+
*
|
|
4
|
+
* Daemon DB inspect/verify/vacuum operations, wired through the
|
|
5
|
+
* tool-execution boundary (`@jini-ai/core`'s `tool-registry.ts` + `@jini-ai/daemon`'s
|
|
6
|
+
* `tool-executor.ts`) rather than called directly from a route handler.
|
|
7
|
+
* Ported from OD's `apps/daemon/src/routes/daemon.ts` `GET /api/daemon/db`,
|
|
8
|
+
* `POST /api/daemon/db/verify`, `POST /api/daemon/db/vacuum` (see
|
|
9
|
+
* `source-map.md`'s routes-classification table, row `#12 daemon.ts`: "generic
|
|
10
|
+
* in shape but depend on a separate `storage/db-inspect.ts` port not built
|
|
11
|
+
* this round" — that port now exists as `@jini-ai/sqlite`'s `db-inspect.ts`).
|
|
12
|
+
*
|
|
13
|
+
* This module does **not** depend on `@jini-ai/sqlite` or `better-sqlite3` at
|
|
14
|
+
* all: `DaemonDbOperations` is a plain injected interface (structurally
|
|
15
|
+
* compatible with `@jini-ai/sqlite`'s `inspectSqliteDatabase`/
|
|
16
|
+
* `verifySqliteIntegrity` return shapes, so a caller can wire those in with
|
|
17
|
+
* zero adapter code) — the same "caller supplies the real collaborator"
|
|
18
|
+
* convention `daemon-status.ts`/`host-tools.ts` already established in this
|
|
19
|
+
* package.
|
|
20
|
+
*
|
|
21
|
+
* **Why the tool-execution boundary, not a plain route handler calling
|
|
22
|
+
* `DaemonDbOperations` directly:** these three operations reveal internal
|
|
23
|
+
* schema/row-count/file-size information (`inspect`/`verify`) and rewrite the
|
|
24
|
+
* database file in place (`vacuum`) — real security stakes the task brief
|
|
25
|
+
* that added this module named explicitly. OD's own origin gated only
|
|
26
|
+
* `verify`/`vacuum` behind `requireLocalDaemonRequest` and left `GET
|
|
27
|
+
* /api/daemon/db` completely ungated — a real pre-existing gap, not carried
|
|
28
|
+
* forward here. Per this repo's binding tool-execution-boundary precedent
|
|
29
|
+
* (`packages/deploy/src/tool.ts`'s `deploy.publish`, `packages/daemon/src/
|
|
30
|
+
* delegated-tool-bridge.ts`), the actual work happens only inside a
|
|
31
|
+
* `ToolHandler` `ToolExecutor.execute` invokes after `ToolPolicy.authorize`
|
|
32
|
+
* allows it — never directly from `registerDaemonDbRoutes`' handlers. All
|
|
33
|
+
* three routes also keep `requireSameOrigin: true` as a first line of
|
|
34
|
+
* defense (matching `daemon-status.ts`'s shutdown route), but that transport
|
|
35
|
+
* gate is defense in depth, not a substitute for the tool-execution
|
|
36
|
+
* boundary — see {@link denyAllDaemonDbPolicy}'s doc for why the default
|
|
37
|
+
* policy denies every call rather than allowing one.
|
|
38
|
+
*/
|
|
39
|
+
import { randomUUID } from 'node:crypto';
|
|
40
|
+
import { createApiError } from '@jini-ai/protocol';
|
|
41
|
+
import { defineJsonRoute, mountJsonRoute } from './adapter.js';
|
|
42
|
+
import { validationError } from './request.js';
|
|
43
|
+
import { err, ok } from './types.js';
|
|
44
|
+
/** The `ToolRegistry` id `GET /api/daemon/db` executes through. */
|
|
45
|
+
export const DB_INSPECT_TOOL_ID = 'daemon.db.inspect';
|
|
46
|
+
/** The `ToolRegistry` id `POST /api/daemon/db/verify` executes through. */
|
|
47
|
+
export const DB_VERIFY_TOOL_ID = 'daemon.db.verify';
|
|
48
|
+
/** The `ToolRegistry` id `POST /api/daemon/db/vacuum` executes through. */
|
|
49
|
+
export const DB_VACUUM_TOOL_ID = 'daemon.db.vacuum';
|
|
50
|
+
/**
|
|
51
|
+
* Deny-by-default `ToolPolicy` shared by all three DB tools — every call is
|
|
52
|
+
* denied, unconditionally, regardless of principal. Matching
|
|
53
|
+
* `@jini-ai/deploy`'s `denyAllDeployPublishPolicy` precedent: a host must
|
|
54
|
+
* explicitly opt in with its own policy (e.g. role-gated, or "same principal
|
|
55
|
+
* that owns the daemon process") rather than getting a working DB inspector
|
|
56
|
+
* for free merely by registering the tools. `inspect`/`verify` disclose
|
|
57
|
+
* internal schema and row-count information; `vacuum` rewrites the database
|
|
58
|
+
* file in place — none of the three has a safe "mostly harmless" default the
|
|
59
|
+
* way a pure read-only, non-sensitive tool might.
|
|
60
|
+
*/
|
|
61
|
+
export const denyAllDaemonDbPolicy = {
|
|
62
|
+
authorize: () => 'deny',
|
|
63
|
+
};
|
|
64
|
+
function isRecord(value) {
|
|
65
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Builds the three `{descriptor, handler, policy}` triples a host registers
|
|
69
|
+
* against `@jini-ai/core`'s `ToolRegistry` so the DB operations become
|
|
70
|
+
* reachable only via `ToolExecutor.execute(principal, run, toolId, input)` —
|
|
71
|
+
* never by a route calling `operations.inspect()`/`verify()`/`vacuum()`
|
|
72
|
+
* directly, which would bypass authorization and the audit trail entirely.
|
|
73
|
+
*
|
|
74
|
+
* @complexity O(1) to build the three registrations; each handler's own cost is `operations`'s.
|
|
75
|
+
* @overallScore 100/100
|
|
76
|
+
*/
|
|
77
|
+
export function createDaemonDbToolRegistrations(options) {
|
|
78
|
+
const { operations, policy = denyAllDaemonDbPolicy, requiresConfirmation, timeoutMs } = options;
|
|
79
|
+
const descriptorExtras = {
|
|
80
|
+
...(requiresConfirmation !== undefined ? { requiresConfirmation } : {}),
|
|
81
|
+
...(timeoutMs !== undefined ? { timeoutMs } : {}),
|
|
82
|
+
};
|
|
83
|
+
return {
|
|
84
|
+
inspect: {
|
|
85
|
+
descriptor: {
|
|
86
|
+
id: DB_INSPECT_TOOL_ID,
|
|
87
|
+
description: 'Inspects the daemon SQLite database: schema version, table list, row counts, on-disk size.',
|
|
88
|
+
...descriptorExtras,
|
|
89
|
+
},
|
|
90
|
+
policy,
|
|
91
|
+
handler: async () => operations.inspect(),
|
|
92
|
+
},
|
|
93
|
+
verify: {
|
|
94
|
+
descriptor: {
|
|
95
|
+
id: DB_VERIFY_TOOL_ID,
|
|
96
|
+
description: 'Runs a SQLite integrity/foreign-key check against the daemon database.',
|
|
97
|
+
...descriptorExtras,
|
|
98
|
+
},
|
|
99
|
+
policy,
|
|
100
|
+
handler: async (ctx) => {
|
|
101
|
+
const input = isRecord(ctx.input) ? ctx.input : {};
|
|
102
|
+
return operations.verify(input.quick === true);
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
vacuum: {
|
|
106
|
+
descriptor: {
|
|
107
|
+
id: DB_VACUUM_TOOL_ID,
|
|
108
|
+
description: 'Runs SQLite VACUUM against the daemon database and reports reclaimed bytes.',
|
|
109
|
+
...descriptorExtras,
|
|
110
|
+
},
|
|
111
|
+
policy,
|
|
112
|
+
handler: async () => operations.vacuum(),
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function defaultDaemonDbInternalErrorSink(context) {
|
|
117
|
+
// eslint-disable-next-line no-console
|
|
118
|
+
console.error(`[@jini-ai/http-kit] internal error (${context.source}, correlationId=${context.correlationId})`, context.error);
|
|
119
|
+
}
|
|
120
|
+
/** Every DB-ops call gets its own opaque, single-use `RunRef` — these are one-off operations requests, not steps of a longer-lived agent run, so there is no real run to attach the audit trail to. */
|
|
121
|
+
function freshRun() {
|
|
122
|
+
return { id: randomUUID() };
|
|
123
|
+
}
|
|
124
|
+
function toolResultToApiResult(deps, source, result) {
|
|
125
|
+
switch (result.status) {
|
|
126
|
+
case 'completed':
|
|
127
|
+
return ok(result.output);
|
|
128
|
+
case 'denied':
|
|
129
|
+
return err(createApiError('TOOL_OPERATION_DENIED', 'this operation was denied by policy'));
|
|
130
|
+
case 'confirmation-denied':
|
|
131
|
+
return err(createApiError('TOOL_OPERATION_DENIED', 'this operation was denied during confirmation'));
|
|
132
|
+
case 'timed-out':
|
|
133
|
+
case 'cancelled':
|
|
134
|
+
case 'failed': {
|
|
135
|
+
const correlationId = randomUUID();
|
|
136
|
+
const sink = deps.onInternalError ?? defaultDaemonDbInternalErrorSink;
|
|
137
|
+
sink({ source, correlationId, error: result.status === 'failed' ? result.error : result.status });
|
|
138
|
+
return err(createApiError('INTERNAL_ERROR', 'an internal error occurred', { requestId: correlationId }));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/** `GET /api/daemon/db` — the database inventory (schema version, tables, row counts, size). */
|
|
143
|
+
export const daemonDbInspectRoute = defineJsonRoute({
|
|
144
|
+
method: 'get',
|
|
145
|
+
path: '/api/daemon/db',
|
|
146
|
+
requireSameOrigin: true,
|
|
147
|
+
parse: () => ok(undefined),
|
|
148
|
+
handle: async (_input, deps) => {
|
|
149
|
+
const result = await deps.toolExecutor.execute(deps.principal, freshRun(), DB_INSPECT_TOOL_ID, undefined);
|
|
150
|
+
return toolResultToApiResult(deps, 'db-inspect', result);
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
function parseDbVerifyInput(input) {
|
|
154
|
+
const raw = input.query.quick;
|
|
155
|
+
if (raw === undefined)
|
|
156
|
+
return ok({ quick: false });
|
|
157
|
+
if (typeof raw !== 'string') {
|
|
158
|
+
return err(validationError('quick must be a single query-string value when provided'));
|
|
159
|
+
}
|
|
160
|
+
const normalized = raw.toLowerCase();
|
|
161
|
+
return ok({ quick: normalized === '1' || normalized === 'true' });
|
|
162
|
+
}
|
|
163
|
+
/** `POST /api/daemon/db/verify?quick=` — `PRAGMA integrity_check`/`quick_check` plus `foreign_key_check`. */
|
|
164
|
+
export const daemonDbVerifyRoute = defineJsonRoute({
|
|
165
|
+
method: 'post',
|
|
166
|
+
path: '/api/daemon/db/verify',
|
|
167
|
+
requireSameOrigin: true,
|
|
168
|
+
parse: parseDbVerifyInput,
|
|
169
|
+
handle: async (input, deps) => {
|
|
170
|
+
const result = await deps.toolExecutor.execute(deps.principal, freshRun(), DB_VERIFY_TOOL_ID, input);
|
|
171
|
+
return toolResultToApiResult(deps, 'db-verify', result);
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
/** `POST /api/daemon/db/vacuum` — runs `VACUUM` and reports bytes reclaimed. */
|
|
175
|
+
export const daemonDbVacuumRoute = defineJsonRoute({
|
|
176
|
+
method: 'post',
|
|
177
|
+
path: '/api/daemon/db/vacuum',
|
|
178
|
+
requireSameOrigin: true,
|
|
179
|
+
parse: () => ok(undefined),
|
|
180
|
+
handle: async (_input, deps) => {
|
|
181
|
+
const result = await deps.toolExecutor.execute(deps.principal, freshRun(), DB_VACUUM_TOOL_ID, undefined);
|
|
182
|
+
return toolResultToApiResult(deps, 'db-vacuum', result);
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
/** Mounts all three DB-ops routes on `app`. A pack's `http(app, services)` calls this directly. */
|
|
186
|
+
export function registerDaemonDbRoutes(app, deps, adapter) {
|
|
187
|
+
mountJsonRoute(app, daemonDbInspectRoute, deps, adapter);
|
|
188
|
+
mountJsonRoute(app, daemonDbVerifyRoute, deps, adapter);
|
|
189
|
+
mountJsonRoute(app, daemonDbVacuumRoute, deps, adapter);
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=db-ops.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db-ops.js","sourceRoot":"","sources":["../src/db-ops.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { Express } from 'express';
|
|
2
|
+
import type { Principal } from '@jini-ai/core';
|
|
3
|
+
import { type RunLifecycle, type ToolExecutionResult, type ToolExecutor } from '@jini-ai/daemon';
|
|
4
|
+
import { type AdapterContext } from './adapter.js';
|
|
5
|
+
export interface DelegatedToolExecuteRequest {
|
|
6
|
+
readonly runId: string;
|
|
7
|
+
readonly toolUseId: string;
|
|
8
|
+
readonly toolId: string;
|
|
9
|
+
readonly input?: unknown;
|
|
10
|
+
}
|
|
11
|
+
export interface DelegatedToolExecuteResponse {
|
|
12
|
+
readonly result: ToolExecutionResult;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Diagnostic detail for an internal-error response the public API deliberately does not
|
|
16
|
+
* disclose (SEC-005), matching `runs.ts`'s `RunInternalErrorContext` precedent: a thrown
|
|
17
|
+
* `ToolExecutor`/registry failure can embed tool-handler internals no HTTP caller should see.
|
|
18
|
+
*/
|
|
19
|
+
export interface DelegatedToolsInternalErrorContext {
|
|
20
|
+
readonly source: 'delegated-tool-execute' | 'resolve-principal';
|
|
21
|
+
readonly runId: string;
|
|
22
|
+
readonly toolId: string;
|
|
23
|
+
readonly correlationId: string;
|
|
24
|
+
readonly error: unknown;
|
|
25
|
+
}
|
|
26
|
+
export interface DelegatedToolsHttpDeps {
|
|
27
|
+
readonly lifecycle: RunLifecycle;
|
|
28
|
+
readonly toolExecutor: ToolExecutor;
|
|
29
|
+
/** Host-owned: resolves the `Principal` a given delegated-tool-call request executes as. Mandatory — see module doc; there is no safe default identity this package could assume on a host's behalf. */
|
|
30
|
+
readonly resolvePrincipal: (request: DelegatedToolExecuteRequest) => Principal | Promise<Principal>;
|
|
31
|
+
/** Host-owned sink for the real exception behind a generic `INTERNAL_ERROR` response (SEC-005). Defaults to `console.error`. */
|
|
32
|
+
readonly onInternalError?: (context: DelegatedToolsInternalErrorContext) => void;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* `POST /api/delegated-tool-calls` — executes one delegated tool call against an already-started
|
|
36
|
+
* run. Maps `ToolExecutionResult.status` to the HTTP response via `toolExecutionResultToApiResult`
|
|
37
|
+
* above — mirroring `db-ops.ts`'s precedent for the identical status union rather than treating
|
|
38
|
+
* every business outcome as a `200`. A genuinely unexpected throw (an unregistered `toolId` — a
|
|
39
|
+
* routing/programming error per `ToolExecutor.execute`'s own contract — or a race where the run
|
|
40
|
+
* became terminal between this route's existence check and the bridge's first emitted event)
|
|
41
|
+
* reaches the same SEC-005 redaction path.
|
|
42
|
+
*/
|
|
43
|
+
export declare const delegatedToolExecuteRoute: import("./types.js").JsonRouteSpec<DelegatedToolExecuteRequest, DelegatedToolExecuteResponse, DelegatedToolsHttpDeps>;
|
|
44
|
+
/** Mounts `POST /api/delegated-tool-calls` on `app`. A pack's `http(app, services)` calls this directly. */
|
|
45
|
+
export declare function registerDelegatedToolRoutes(app: Express, deps: DelegatedToolsHttpDeps, adapter: AdapterContext): void;
|
|
46
|
+
//# sourceMappingURL=delegated-tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delegated-tools.d.ts","sourceRoot":"","sources":["../src/delegated-tools.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAA6B,KAAK,YAAY,EAAE,KAAK,mBAAmB,EAAE,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC5H,OAAO,EAAmC,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAIpF,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;CACtC;AAED;;;;GAIG;AACH,MAAM,WAAW,kCAAkC;IACjD,QAAQ,CAAC,MAAM,EAAE,wBAAwB,GAAG,mBAAmB,CAAC;IAChE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC;IACjC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,wMAAwM;IACxM,QAAQ,CAAC,gBAAgB,EAAE,CAAC,OAAO,EAAE,2BAA2B,KAAK,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IACpG,gIAAgI;IAChI,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,kCAAkC,KAAK,IAAI,CAAC;CAClF;AAyFD;;;;;;;;GAQG;AACH,eAAO,MAAM,yBAAyB,uHAyCpC,CAAC;AAEH,4GAA4G;AAC5G,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,sBAAsB,EAAE,OAAO,EAAE,cAAc,GAAG,IAAI,CAErH"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module delegated-tools
|
|
3
|
+
*
|
|
4
|
+
* `POST /api/delegated-tool-calls` — the daemon-side half of gap 3's MCP-callback continuation
|
|
5
|
+
* transport spike (see `packages/daemon/source-map.md`'s "run/chat orchestration gap 3, part 1"
|
|
6
|
+
* addition and this package's own dated section in `source-map.md`). The swarm-consensus Final
|
|
7
|
+
* Recommendation asked for exactly this round trip: "inject the already-shipped MCP host into
|
|
8
|
+
* one MCP-capable CLI's launch config, prove a tool round-trip through the existing
|
|
9
|
+
* `delegated-tool-bridge.ts`." This route is that round trip's daemon-side half — an MCP server
|
|
10
|
+
* subprocess spawned alongside a `claude` run (`packages/mcp/src/bin/serve.ts`, injected via
|
|
11
|
+
* `packages/daemon/src/agent-executor.ts`'s optional `mcpJsonInjection` config) calls back into
|
|
12
|
+
* the daemon over loopback HTTP (`packages/mcp/src/server/daemon-client.ts`) with
|
|
13
|
+
* `{runId, toolUseId, toolId, input}`; this route decodes that request and calls the
|
|
14
|
+
* already-shipped, already-tested `createDelegatedToolBridge`
|
|
15
|
+
* (`packages/daemon/src/delegated-tool-bridge.ts`), which is the ONLY execution path from here:
|
|
16
|
+
* every injected byte still routes through `ToolExecutor`'s deny-by-default gate — no parallel
|
|
17
|
+
* authorization mechanism is introduced by this route.
|
|
18
|
+
*
|
|
19
|
+
* `resolvePrincipal` is host-owned and has no default (mirrors gap 3's own resolved
|
|
20
|
+
* human-in-the-loop answer — an explicit host-supplied allowlist/policy, never an invented
|
|
21
|
+
* mechanism): whatever `Principal` a host resolves for a given delegated-tool-call request is
|
|
22
|
+
* exactly what flows into `ToolExecutor.execute`'s own `ToolPolicy.authorize`/
|
|
23
|
+
* `ExecutionDelegate` gates. This route does not itself decide who is allowed to do what — it
|
|
24
|
+
* only decides *which run* a request may act against (an unknown or not-yet-started `runId` is
|
|
25
|
+
* rejected with `404` before the bridge is ever invoked, same precedent as `runs.ts`'s
|
|
26
|
+
* `runCancelRoute`).
|
|
27
|
+
*/
|
|
28
|
+
import { randomUUID } from 'node:crypto';
|
|
29
|
+
import { createApiError } from '@jini-ai/protocol';
|
|
30
|
+
import { createDelegatedToolBridge } from '@jini-ai/daemon';
|
|
31
|
+
import { defineJsonRoute, mountJsonRoute } from './adapter.js';
|
|
32
|
+
import { validationError } from './request.js';
|
|
33
|
+
import { err, ok } from './types.js';
|
|
34
|
+
/** Logs the real failure server-side and returns the generic, correlation-id-bearing public error (SEC-005: never the raw exception). */
|
|
35
|
+
function defaultInternalErrorSink(context) {
|
|
36
|
+
// eslint-disable-next-line no-console
|
|
37
|
+
console.error(`[@jini-ai/http-kit] internal error (${context.source}, correlationId=${context.correlationId})`, context.error);
|
|
38
|
+
}
|
|
39
|
+
function reportInternalError(deps, source, error, runId, toolId) {
|
|
40
|
+
const correlationId = randomUUID();
|
|
41
|
+
const sink = deps.onInternalError ?? defaultInternalErrorSink;
|
|
42
|
+
sink({ source, runId, toolId, correlationId, error });
|
|
43
|
+
return createApiError('INTERNAL_ERROR', 'an internal error occurred', { requestId: correlationId });
|
|
44
|
+
}
|
|
45
|
+
function isRecord(value) {
|
|
46
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
47
|
+
}
|
|
48
|
+
function requireNonEmptyString(body, key) {
|
|
49
|
+
const value = body[key];
|
|
50
|
+
return typeof value === 'string' && value.trim().length > 0 ? value : undefined;
|
|
51
|
+
}
|
|
52
|
+
function parseDelegatedToolExecute(input) {
|
|
53
|
+
if (!isRecord(input.body))
|
|
54
|
+
return err(validationError('body must be a JSON object'));
|
|
55
|
+
const runId = requireNonEmptyString(input.body, 'runId');
|
|
56
|
+
if (runId === undefined) {
|
|
57
|
+
return err(validationError('runId must be a non-empty string', [{ path: 'runId', message: 'required non-empty string' }]));
|
|
58
|
+
}
|
|
59
|
+
const toolUseId = requireNonEmptyString(input.body, 'toolUseId');
|
|
60
|
+
if (toolUseId === undefined) {
|
|
61
|
+
return err(validationError('toolUseId must be a non-empty string', [{ path: 'toolUseId', message: 'required non-empty string' }]));
|
|
62
|
+
}
|
|
63
|
+
const toolId = requireNonEmptyString(input.body, 'toolId');
|
|
64
|
+
if (toolId === undefined) {
|
|
65
|
+
return err(validationError('toolId must be a non-empty string', [{ path: 'toolId', message: 'required non-empty string' }]));
|
|
66
|
+
}
|
|
67
|
+
return ok({ runId, toolUseId, toolId, input: input.body.input });
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Maps a settled `ToolExecutionResult` to the wire `Result` — the same status mapping
|
|
71
|
+
* `db-ops.ts`'s `toolResultToApiResult` establishes for this identical `ToolExecutionResult`
|
|
72
|
+
* union, kept consistent here rather than reinvented: `completed` → `200 {result}`,
|
|
73
|
+
* `denied`/`confirmation-denied` → `403 TOOL_OPERATION_DENIED`, `timed-out`/`cancelled` → a
|
|
74
|
+
* SEC-005-redacted `500 INTERNAL_ERROR` (the real status/error goes to `onInternalError`, never the
|
|
75
|
+
* wire).
|
|
76
|
+
*
|
|
77
|
+
* `failed` splits in two, on `result.errorKind` (`@jini-ai/daemon`'s `ToolExecutor` sets it from
|
|
78
|
+
* whether the handler threw `@jini-ai/core`'s `ToolInputError`): `'validation'` means the CALLER's
|
|
79
|
+
* input was the problem — a wrong/missing/malformed field name, a `themeId` that doesn't exist, a
|
|
80
|
+
* path escaping its theme — so it is reported as a real `400 BAD_REQUEST` carrying the handler's own
|
|
81
|
+
* actionable message (the same one a model reads to retry correctly), not redacted. Everything else
|
|
82
|
+
* (`'internal'`, or no `errorKind` at all — e.g. an older `ToolExecutor` build) stays the SEC-005
|
|
83
|
+
* redacted 500 path, because a handler that threw for a reason OTHER than "your input was bad" can
|
|
84
|
+
* embed exactly the kind of internal detail that path exists to keep off the wire.
|
|
85
|
+
*/
|
|
86
|
+
function toolExecutionResultToApiResult(deps, runId, toolId, result) {
|
|
87
|
+
switch (result.status) {
|
|
88
|
+
case 'completed':
|
|
89
|
+
return ok({ result });
|
|
90
|
+
case 'denied':
|
|
91
|
+
return err(createApiError('TOOL_OPERATION_DENIED', 'this operation was denied by policy'));
|
|
92
|
+
case 'confirmation-denied':
|
|
93
|
+
return err(createApiError('TOOL_OPERATION_DENIED', 'this operation was denied during confirmation'));
|
|
94
|
+
case 'timed-out':
|
|
95
|
+
case 'cancelled':
|
|
96
|
+
return err(reportInternalError(deps, 'delegated-tool-execute', result.status, runId, toolId));
|
|
97
|
+
case 'failed':
|
|
98
|
+
if (result.errorKind === 'validation') {
|
|
99
|
+
return err(createApiError('BAD_REQUEST', result.error ?? 'invalid tool input'));
|
|
100
|
+
}
|
|
101
|
+
return err(reportInternalError(deps, 'delegated-tool-execute', result.error ?? result.status, runId, toolId));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* `POST /api/delegated-tool-calls` — executes one delegated tool call against an already-started
|
|
106
|
+
* run. Maps `ToolExecutionResult.status` to the HTTP response via `toolExecutionResultToApiResult`
|
|
107
|
+
* above — mirroring `db-ops.ts`'s precedent for the identical status union rather than treating
|
|
108
|
+
* every business outcome as a `200`. A genuinely unexpected throw (an unregistered `toolId` — a
|
|
109
|
+
* routing/programming error per `ToolExecutor.execute`'s own contract — or a race where the run
|
|
110
|
+
* became terminal between this route's existence check and the bridge's first emitted event)
|
|
111
|
+
* reaches the same SEC-005 redaction path.
|
|
112
|
+
*/
|
|
113
|
+
export const delegatedToolExecuteRoute = defineJsonRoute({
|
|
114
|
+
method: 'post',
|
|
115
|
+
path: '/api/delegated-tool-calls',
|
|
116
|
+
requireSameOrigin: true,
|
|
117
|
+
parse: parseDelegatedToolExecute,
|
|
118
|
+
handle: async (input, deps, signal) => {
|
|
119
|
+
const run = await deps.lifecycle.get(input.runId);
|
|
120
|
+
if (run === undefined) {
|
|
121
|
+
return err(createApiError('NOT_FOUND', `run "${input.runId}" was not found`));
|
|
122
|
+
}
|
|
123
|
+
let principal;
|
|
124
|
+
try {
|
|
125
|
+
principal = await deps.resolvePrincipal(input);
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
return err(reportInternalError(deps, 'resolve-principal', error, input.runId, input.toolId));
|
|
129
|
+
}
|
|
130
|
+
const bridge = createDelegatedToolBridge({ lifecycle: deps.lifecycle, toolExecutor: deps.toolExecutor });
|
|
131
|
+
try {
|
|
132
|
+
// `signal` carries the caller's HTTP connection dropping — see `mountJsonRoute`
|
|
133
|
+
// (`adapter.ts`). The bridge already combines it with the run's own cancellation
|
|
134
|
+
// (`DelegatedToolInvocation.signal`'s doc); this is the wire that was missing, not new
|
|
135
|
+
// behaviour in the bridge or `ToolExecutor`.
|
|
136
|
+
const result = await bridge.execute({
|
|
137
|
+
runId: input.runId,
|
|
138
|
+
toolUseId: input.toolUseId,
|
|
139
|
+
toolId: input.toolId,
|
|
140
|
+
principal,
|
|
141
|
+
input: input.input,
|
|
142
|
+
...(signal !== undefined ? { signal } : {}),
|
|
143
|
+
});
|
|
144
|
+
return toolExecutionResultToApiResult(deps, input.runId, input.toolId, result);
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
return err(reportInternalError(deps, 'delegated-tool-execute', error, input.runId, input.toolId));
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
/** Mounts `POST /api/delegated-tool-calls` on `app`. A pack's `http(app, services)` calls this directly. */
|
|
152
|
+
export function registerDelegatedToolRoutes(app, deps, adapter) {
|
|
153
|
+
mountJsonRoute(app, delegatedToolExecuteRoute, deps, adapter);
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=delegated-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delegated-tools.js","sourceRoot":"","sources":["../src/delegated-tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module express/run-stream
|
|
3
|
+
*
|
|
4
|
+
* Express-specific mounting glue for the shared AG-UI SSE run-stream handler (`../run-stream.js`).
|
|
5
|
+
* Express's `Request`/`Response` already *are* Node's raw `http.IncomingMessage`/
|
|
6
|
+
* `http.ServerResponse` (Express's `Response` extends `http.ServerResponse` directly), so this
|
|
7
|
+
* file's only job is resolving `req.params.runId` and handing the request/response straight
|
|
8
|
+
* through — a few lines, not a reimplementation, per the design decision that motivated building
|
|
9
|
+
* the SSE primitive once instead of duplicating it per transport.
|
|
10
|
+
*/
|
|
11
|
+
import type { Express } from 'express';
|
|
12
|
+
import { type RunStreamDeps } from '../run-stream.js';
|
|
13
|
+
/** Mounts the AG-UI SSE run-stream route on `app`. A pack's `http(app, services)` calls this directly. */
|
|
14
|
+
export declare function registerRunStreamRoute(app: Express, deps: RunStreamDeps): void;
|
|
15
|
+
//# sourceMappingURL=run-stream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-stream.d.ts","sourceRoot":"","sources":["../../src/express/run-stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,OAAO,EAAqB,MAAM,SAAS,CAAC;AAC1D,OAAO,EAAiD,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAErG,0GAA0G;AAC1G,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,GAAG,IAAI,CAO9E"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { handleRunStreamRequest, RUN_STREAM_ROUTE_PATH } from '../run-stream.js';
|
|
2
|
+
/** Mounts the AG-UI SSE run-stream route on `app`. A pack's `http(app, services)` calls this directly. */
|
|
3
|
+
export function registerRunStreamRoute(app, deps) {
|
|
4
|
+
app.get(RUN_STREAM_ROUTE_PATH, async (req, res) => {
|
|
5
|
+
// `:runId` is a required path segment of RUN_STREAM_ROUTE_PATH — this handler is only ever
|
|
6
|
+
// reached via a URL that already matched it, so the param is always present at runtime even
|
|
7
|
+
// though @types/express types every param as possibly `undefined` in general.
|
|
8
|
+
await handleRunStreamRequest(req, res, req.params.runId, deps);
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=run-stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-stream.js","sourceRoot":"","sources":["../../src/express/run-stream.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAsB,MAAM,kBAAkB,CAAC;AAErG,0GAA0G;AAC1G,MAAM,UAAU,sBAAsB,CAAC,GAAY,EAAE,IAAmB;IACtE,GAAG,CAAC,GAAG,CAAC,qBAAqB,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;QACnE,2FAA2F;QAC3F,4FAA4F;QAC5F,8EAA8E;QAC9E,MAAM,sBAAsB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,KAAM,EAAE,IAAI,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @jini/http/express
|
|
3
|
+
*
|
|
4
|
+
* The Express-native transport namespace: re-exports this package's existing flat Express
|
|
5
|
+
* implementation (request parsing, response serialization, the mounting Adapter, the `/api`
|
|
6
|
+
* security middleware, the route-registration guard, compat error helpers, the daemon-status
|
|
7
|
+
* routes, and the runs/agents/host-tools route packs) under one namespace, mirroring
|
|
8
|
+
* `./fastify/index.js`'s shape so a transport-switchable caller (`@jini/node-host`'s
|
|
9
|
+
* `createLocalNodeDaemon`) can import either namespace symmetrically. Nothing here is a new
|
|
10
|
+
* implementation — every export is the same flat file every other consumer of this package
|
|
11
|
+
* already imports directly from the root barrel; this module exists only so `httpExpress.*` and
|
|
12
|
+
* `httpFastify.*` read the same at call sites that need to pick a transport explicitly.
|
|
13
|
+
*/
|
|
14
|
+
export type { AdapterContext } from './adapter.js';
|
|
15
|
+
export { defineJsonRoute, mountJsonRoute } from './adapter.js';
|
|
16
|
+
export type { ApiBearerAuthMiddlewareDeps, ApiOriginGuardMiddlewareDeps } from './api-security-middleware.js';
|
|
17
|
+
export { registerApiBearerAuthMiddleware, registerApiOriginGuardMiddleware } from './api-security-middleware.js';
|
|
18
|
+
export { createCompatApiError, createCompatApiErrorResponse, sendApiError as sendCompatApiError, } from './compat.js';
|
|
19
|
+
export type { DaemonShutdownResponse, DaemonStatusDeps, DaemonStatusResponse, } from './daemon-status.js';
|
|
20
|
+
export { daemonShutdownRoute, daemonStatusRoute, registerDaemonStatusRoutes } from './daemon-status.js';
|
|
21
|
+
export { isLoopbackHostname, isLoopbackPeerAddress, localOriginFromHeader, normalizeLocalAuthority, requireLocalDaemonRequest, validateLocalDaemonRequest, } from './local-daemon-request.js';
|
|
22
|
+
export type { OriginContext } from './origin.js';
|
|
23
|
+
export { guardSameOrigin } from './origin.js';
|
|
24
|
+
export { rawInput, validationError } from './request.js';
|
|
25
|
+
export { registerRunStreamRoute } from './express/run-stream.js';
|
|
26
|
+
export { sendApiError, sendJson, statusForError } from './response.js';
|
|
27
|
+
export type { InstallRouteRegistrationGuardOptions, RouteRegistration } from './route-registration-guard.js';
|
|
28
|
+
export { getRouteRegistrationInventory, guardedRouteKey, installRouteRegistrationGuard, } from './route-registration-guard.js';
|
|
29
|
+
export { registerRunRoutes } from './runs.js';
|
|
30
|
+
export { registerAgentRoutes } from './agents.js';
|
|
31
|
+
export { registerHostToolsRoutes } from './host-tools.js';
|
|
32
|
+
//# sourceMappingURL=express-index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"express-index.d.ts","sourceRoot":"","sources":["../src/express-index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE/D,YAAY,EAAE,2BAA2B,EAAE,4BAA4B,EAAE,MAAM,8BAA8B,CAAC;AAC9G,OAAO,EAAE,+BAA+B,EAAE,gCAAgC,EAAE,MAAM,8BAA8B,CAAC;AAEjH,OAAO,EACL,oBAAoB,EACpB,4BAA4B,EAC5B,YAAY,IAAI,kBAAkB,GACnC,MAAM,aAAa,CAAC;AAErB,YAAY,EACV,sBAAsB,EACtB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAExG,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,qBAAqB,EACrB,uBAAuB,EACvB,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,2BAA2B,CAAC;AAEnC,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAEjE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEvE,YAAY,EAAE,oCAAoC,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAC7G,OAAO,EACL,6BAA6B,EAC7B,eAAe,EACf,6BAA6B,GAC9B,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { defineJsonRoute, mountJsonRoute } from './adapter.js';
|
|
2
|
+
export { registerApiBearerAuthMiddleware, registerApiOriginGuardMiddleware } from './api-security-middleware.js';
|
|
3
|
+
export { createCompatApiError, createCompatApiErrorResponse, sendApiError as sendCompatApiError, } from './compat.js';
|
|
4
|
+
export { daemonShutdownRoute, daemonStatusRoute, registerDaemonStatusRoutes } from './daemon-status.js';
|
|
5
|
+
export { isLoopbackHostname, isLoopbackPeerAddress, localOriginFromHeader, normalizeLocalAuthority, requireLocalDaemonRequest, validateLocalDaemonRequest, } from './local-daemon-request.js';
|
|
6
|
+
export { guardSameOrigin } from './origin.js';
|
|
7
|
+
export { rawInput, validationError } from './request.js';
|
|
8
|
+
export { registerRunStreamRoute } from './express/run-stream.js';
|
|
9
|
+
export { sendApiError, sendJson, statusForError } from './response.js';
|
|
10
|
+
export { getRouteRegistrationInventory, guardedRouteKey, installRouteRegistrationGuard, } from './route-registration-guard.js';
|
|
11
|
+
export { registerRunRoutes } from './runs.js';
|
|
12
|
+
export { registerAgentRoutes } from './agents.js';
|
|
13
|
+
export { registerHostToolsRoutes } from './host-tools.js';
|
|
14
|
+
//# sourceMappingURL=express-index.js.map
|