@graphorin/server 0.6.1 → 0.7.0
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/CHANGELOG.md +71 -0
- package/README.md +3 -3
- package/dist/app-audit-binding.d.ts +15 -0
- package/dist/app-audit-binding.d.ts.map +1 -0
- package/dist/app-audit-binding.js +136 -0
- package/dist/app-audit-binding.js.map +1 -0
- package/dist/app-daemons.d.ts +29 -0
- package/dist/app-daemons.d.ts.map +1 -0
- package/dist/app-daemons.js +27 -0
- package/dist/app-daemons.js.map +1 -0
- package/dist/app-lifecycle.js +272 -0
- package/dist/app-lifecycle.js.map +1 -0
- package/dist/app-metrics.js +79 -0
- package/dist/app-metrics.js.map +1 -0
- package/dist/app-middleware.js +92 -0
- package/dist/app-middleware.js.map +1 -0
- package/dist/app-routes.js +131 -0
- package/dist/app-routes.js.map +1 -0
- package/dist/app-ws.js +65 -0
- package/dist/app-ws.js.map +1 -0
- package/dist/app.d.ts +16 -16
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +35 -607
- package/dist/app.js.map +1 -1
- package/dist/commentary/built-in-patterns.d.ts +1 -1
- package/dist/commentary/built-in-patterns.js +1 -1
- package/dist/commentary/built-in-patterns.js.map +1 -1
- package/dist/config.d.ts +100 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +30 -2
- package/dist/config.js.map +1 -1
- package/dist/health/checks.d.ts +15 -1
- package/dist/health/checks.d.ts.map +1 -1
- package/dist/health/checks.js +21 -0
- package/dist/health/checks.js.map +1 -1
- package/dist/health/routes.js +1 -1
- package/dist/index.d.ts +8 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -24
- package/dist/index.js.map +1 -1
- package/dist/internal/context.d.ts +2 -2
- package/dist/internal/wire-error.js +20 -0
- package/dist/internal/wire-error.js.map +1 -0
- package/dist/lifecycle/pre-bind.d.ts +1 -1
- package/dist/metrics/catalog.d.ts.map +1 -1
- package/dist/metrics/catalog.js.map +1 -1
- package/dist/metrics/tools-bridge.d.ts +15 -0
- package/dist/metrics/tools-bridge.d.ts.map +1 -0
- package/dist/metrics/tools-bridge.js +103 -0
- package/dist/metrics/tools-bridge.js.map +1 -0
- package/dist/middleware/audit.d.ts +1 -1
- package/dist/middleware/auth.js +1 -1
- package/dist/middleware/csrf.js +1 -1
- package/dist/middleware/index.js +1 -1
- package/dist/middleware/scope.d.ts.map +1 -1
- package/dist/middleware/scope.js +44 -4
- package/dist/middleware/scope.js.map +1 -1
- package/dist/package.js +1 -1
- package/dist/package.js.map +1 -1
- package/dist/registry/index.d.ts +33 -0
- package/dist/registry/index.d.ts.map +1 -1
- package/dist/registry/index.js.map +1 -1
- package/dist/replay/routes.d.ts +1 -1
- package/dist/replay/routes.js +2 -2
- package/dist/routes/agents.d.ts.map +1 -1
- package/dist/routes/agents.js +64 -18
- package/dist/routes/agents.js.map +1 -1
- package/dist/routes/auth.js +2 -2
- package/dist/routes/auth.js.map +1 -1
- package/dist/routes/sessions.js +5 -5
- package/dist/routes/sessions.js.map +1 -1
- package/dist/routes/tokens.d.ts +1 -1
- package/dist/routes/tokens.d.ts.map +1 -1
- package/dist/routes/tokens.js +21 -1
- package/dist/routes/tokens.js.map +1 -1
- package/dist/routes/workflows.d.ts.map +1 -1
- package/dist/routes/workflows.js +165 -19
- package/dist/routes/workflows.js.map +1 -1
- package/dist/runtime/retention.d.ts +105 -0
- package/dist/runtime/retention.d.ts.map +1 -0
- package/dist/runtime/retention.js +154 -0
- package/dist/runtime/retention.js.map +1 -0
- package/dist/runtime/run-state.d.ts +2 -0
- package/dist/runtime/run-state.d.ts.map +1 -1
- package/dist/runtime/run-state.js +34 -2
- package/dist/runtime/run-state.js.map +1 -1
- package/dist/sse/events.js +3 -4
- package/dist/sse/events.js.map +1 -1
- package/dist/tools-audit-bridge.d.ts +29 -0
- package/dist/tools-audit-bridge.d.ts.map +1 -0
- package/dist/tools-audit-bridge.js +103 -0
- package/dist/tools-audit-bridge.js.map +1 -0
- package/dist/workflows/timer-daemon.d.ts +69 -0
- package/dist/workflows/timer-daemon.d.ts.map +1 -0
- package/dist/workflows/timer-daemon.js +37 -0
- package/dist/workflows/timer-daemon.js.map +1 -0
- package/dist/ws/dispatcher.d.ts +1 -1
- package/dist/ws/dispatcher.js +19 -12
- package/dist/ws/dispatcher.js.map +1 -1
- package/dist/ws/index.d.ts +2 -2
- package/dist/ws/index.js +3 -3
- package/dist/ws/replay-buffer.d.ts +35 -1
- package/dist/ws/replay-buffer.d.ts.map +1 -1
- package/dist/ws/replay-buffer.js +35 -3
- package/dist/ws/replay-buffer.js.map +1 -1
- package/dist/ws/upgrade.d.ts.map +1 -1
- package/dist/ws/upgrade.js +24 -18
- package/dist/ws/upgrade.js.map +1 -1
- package/package.json +30 -29
- package/src/app-audit-binding.ts +227 -0
- package/src/app-daemons.ts +73 -0
- package/src/app-lifecycle.ts +476 -0
- package/src/app-metrics.ts +144 -0
- package/src/app-middleware.ts +149 -0
- package/src/app-routes.ts +305 -0
- package/src/app-ws.ts +111 -0
- package/src/app.ts +317 -0
- package/src/commentary/audit-bridge.ts +135 -0
- package/src/commentary/built-in-patterns.ts +79 -0
- package/src/commentary/index.ts +32 -0
- package/src/commentary/sanitizer.ts +238 -0
- package/src/commentary/types.ts +130 -0
- package/src/config.ts +472 -0
- package/src/consolidator/daemon.ts +141 -0
- package/src/consolidator/index.ts +14 -0
- package/src/errors/index.ts +247 -0
- package/src/health/checks.ts +322 -0
- package/src/health/index.ts +34 -0
- package/src/health/routes.ts +154 -0
- package/src/index.ts +243 -0
- package/src/internal/context.ts +77 -0
- package/src/internal/ids.ts +17 -0
- package/src/internal/json.ts +47 -0
- package/src/internal/wire-error.ts +44 -0
- package/src/lifecycle/hooks.ts +66 -0
- package/src/lifecycle/index.ts +16 -0
- package/src/lifecycle/pre-bind.ts +138 -0
- package/src/metrics/catalog.ts +112 -0
- package/src/metrics/index.ts +12 -0
- package/src/metrics/registry.ts +337 -0
- package/src/metrics/tools-bridge.ts +124 -0
- package/src/middleware/audit.ts +114 -0
- package/src/middleware/auth.ts +195 -0
- package/src/middleware/cors.ts +72 -0
- package/src/middleware/csrf.ts +98 -0
- package/src/middleware/idempotency.ts +336 -0
- package/src/middleware/index.ts +38 -0
- package/src/middleware/rate-limit.ts +71 -0
- package/src/middleware/request-state.ts +79 -0
- package/src/middleware/scope.ts +161 -0
- package/src/registry/index.ts +278 -0
- package/src/replay/index.ts +14 -0
- package/src/replay/routes.ts +255 -0
- package/src/routes/agents.ts +363 -0
- package/src/routes/audit.ts +207 -0
- package/src/routes/auth.ts +80 -0
- package/src/routes/health.ts +42 -0
- package/src/routes/index.ts +16 -0
- package/src/routes/mcp.ts +97 -0
- package/src/routes/memory.ts +152 -0
- package/src/routes/sessions.ts +250 -0
- package/src/routes/skills.ts +91 -0
- package/src/routes/tokens.ts +166 -0
- package/src/routes/workflows.ts +616 -0
- package/src/runtime/retention.ts +284 -0
- package/src/runtime/run-state.ts +422 -0
- package/src/sse/events.ts +303 -0
- package/src/sse/index.ts +7 -0
- package/src/tools-audit-bridge.ts +120 -0
- package/src/triggers/daemon.ts +198 -0
- package/src/triggers/index.ts +16 -0
- package/src/triggers/routes.ts +139 -0
- package/src/workflows/timer-daemon.ts +102 -0
- package/src/ws/dispatcher.ts +537 -0
- package/src/ws/index.ts +45 -0
- package/src/ws/replay-buffer.ts +209 -0
- package/src/ws/subjects.ts +162 -0
- package/src/ws/ticket.ts +174 -0
- package/src/ws/upgrade.ts +507 -0
- package/dist/lifecycle/index.js +0 -3
- package/dist/routes/index.js +0 -12
package/dist/app.js
CHANGED
|
@@ -1,148 +1,20 @@
|
|
|
1
1
|
import { version } from "./package.js";
|
|
2
|
-
import {
|
|
3
|
-
import "./
|
|
4
|
-
import { LifecycleDoubleStartError, LifecycleNotStartedError, ShutdownTimeoutError } from "./errors/index.js";
|
|
5
|
-
import { parseServerConfig } from "./config.js";
|
|
6
|
-
import { createConsolidatorDaemon } from "./consolidator/daemon.js";
|
|
7
|
-
import { createExtendedHealthRoutes, createMetricsRoutes, createSecretsHealthRoutes } from "./health/routes.js";
|
|
8
|
-
import "./health/index.js";
|
|
9
|
-
import { runPreBind } from "./lifecycle/pre-bind.js";
|
|
10
|
-
import "./lifecycle/index.js";
|
|
2
|
+
import { buildDaemons } from "./app-daemons.js";
|
|
3
|
+
import { ensureStoreAuditBinding } from "./app-audit-binding.js";
|
|
11
4
|
import { SERVER_METRIC_NAMES, createServerMetricRegistry } from "./metrics/catalog.js";
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import { createRateLimitMiddleware } from "./middleware/rate-limit.js";
|
|
18
|
-
import { createRequestStateMiddleware } from "./middleware/request-state.js";
|
|
19
|
-
import "./middleware/index.js";
|
|
5
|
+
import { attachGlobalMiddleware } from "./app-middleware.js";
|
|
6
|
+
import { RunStateTracker } from "./runtime/run-state.js";
|
|
7
|
+
import { createLifecycle } from "./app-lifecycle.js";
|
|
8
|
+
import { buildWsLayer } from "./app-ws.js";
|
|
9
|
+
import { parseServerConfig } from "./config.js";
|
|
20
10
|
import { AgentRegistry, WorkflowRegistry } from "./registry/index.js";
|
|
21
|
-
import {
|
|
22
|
-
import "./replay/index.js";
|
|
23
|
-
import { createAgentRoutes, createRunRoutes } from "./routes/agents.js";
|
|
24
|
-
import { createAuditRoutes } from "./routes/audit.js";
|
|
25
|
-
import { createAuthRoutes } from "./routes/auth.js";
|
|
26
|
-
import { createMcpRoutes } from "./routes/mcp.js";
|
|
27
|
-
import { createMemoryRoutes } from "./routes/memory.js";
|
|
28
|
-
import { createSessionRoutes } from "./routes/sessions.js";
|
|
29
|
-
import { createSkillsRoutes } from "./routes/skills.js";
|
|
30
|
-
import { createTokensRoutes } from "./routes/tokens.js";
|
|
31
|
-
import { createWorkflowRoutes } from "./routes/workflows.js";
|
|
32
|
-
import "./routes/index.js";
|
|
33
|
-
import { RunStateTracker, scheduleRunPruning } from "./runtime/run-state.js";
|
|
34
|
-
import { createSseRoutes } from "./sse/events.js";
|
|
35
|
-
import "./sse/index.js";
|
|
36
|
-
import { createTriggersDaemon } from "./triggers/daemon.js";
|
|
37
|
-
import { createTriggersRoutes } from "./triggers/routes.js";
|
|
38
|
-
import { createWsDispatcher } from "./ws/dispatcher.js";
|
|
39
|
-
import { createWsTicketStore } from "./ws/ticket.js";
|
|
40
|
-
import { createWsUpgradeEvents } from "./ws/upgrade.js";
|
|
41
|
-
import "./ws/index.js";
|
|
42
|
-
import { SUBPROTOCOL_NAME, negotiateSubprotocol } from "@graphorin/protocol";
|
|
43
|
-
import { TokenVerifier, applyProcessHardening, generatePepper } from "@graphorin/security";
|
|
44
|
-
import { openAuditDb, registerAuditDbBinding } from "@graphorin/security/audit";
|
|
45
|
-
import { createSqliteStore, loadCipherDriver, readWalSize } from "@graphorin/store-sqlite";
|
|
46
|
-
import { serve } from "@hono/node-server";
|
|
47
|
-
import { createNodeWebSocket } from "@hono/node-ws";
|
|
11
|
+
import { createSqliteStore } from "@graphorin/store-sqlite";
|
|
48
12
|
import { Hono } from "hono";
|
|
49
13
|
|
|
50
14
|
//#region src/app.ts
|
|
51
15
|
/**
|
|
52
16
|
* @stable
|
|
53
17
|
*/
|
|
54
|
-
/**
|
|
55
|
-
* Pre-built audit-db binding shipped from `@graphorin/store-sqlite`.
|
|
56
|
-
* Registered exactly once per process so {@link openAuditDb} can find
|
|
57
|
-
* a default binding without forcing operators to wire it manually.
|
|
58
|
-
*
|
|
59
|
-
* Exported as {@link ensureStoreAuditBinding} so the CLI (Phase 15
|
|
60
|
-
* `graphorin audit verify | prune | export`) can reach into the same
|
|
61
|
-
* binding without booting the HTTP listener.
|
|
62
|
-
*
|
|
63
|
-
* @stable
|
|
64
|
-
*/
|
|
65
|
-
let storeAuditBindingRegistered = false;
|
|
66
|
-
function ensureStoreAuditBinding() {
|
|
67
|
-
if (storeAuditBindingRegistered) return;
|
|
68
|
-
registerAuditDbBinding({
|
|
69
|
-
id: "better-sqlite3-multiple-ciphers",
|
|
70
|
-
description: "Default audit-db binding shipped by @graphorin/store-sqlite.",
|
|
71
|
-
open: async (opts) => {
|
|
72
|
-
const driver = await loadCipherDriver();
|
|
73
|
-
const passphrase = await opts.passphrase.use((value) => value);
|
|
74
|
-
const db = new driver(opts.path);
|
|
75
|
-
db.pragma(`key = '${passphrase.replace(/'/g, "''")}'`);
|
|
76
|
-
db.pragma("journal_mode = WAL");
|
|
77
|
-
db.pragma("synchronous = NORMAL");
|
|
78
|
-
db.pragma("busy_timeout = 5000");
|
|
79
|
-
db.pragma("foreign_keys = ON");
|
|
80
|
-
db.exec(`CREATE TABLE IF NOT EXISTS audit_log (
|
|
81
|
-
seq INTEGER PRIMARY KEY,
|
|
82
|
-
ts INTEGER NOT NULL,
|
|
83
|
-
actor_json TEXT NOT NULL,
|
|
84
|
-
action TEXT NOT NULL,
|
|
85
|
-
target TEXT NOT NULL,
|
|
86
|
-
decision TEXT NOT NULL,
|
|
87
|
-
context_json TEXT,
|
|
88
|
-
metadata_json TEXT,
|
|
89
|
-
prev_hash TEXT NOT NULL,
|
|
90
|
-
hash TEXT NOT NULL UNIQUE
|
|
91
|
-
) WITHOUT ROWID;`);
|
|
92
|
-
return {
|
|
93
|
-
binding: "better-sqlite3-multiple-ciphers",
|
|
94
|
-
path: opts.path,
|
|
95
|
-
async insert(entry) {
|
|
96
|
-
db.prepare(`INSERT INTO audit_log (
|
|
97
|
-
seq, ts, actor_json, action, target, decision,
|
|
98
|
-
context_json, metadata_json, prev_hash, hash
|
|
99
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(entry.seq, entry.ts, JSON.stringify(entry.actor), entry.action, entry.target, entry.decision, entry.context !== void 0 ? JSON.stringify(entry.context) : null, entry.metadata !== void 0 ? JSON.stringify(entry.metadata) : null, entry.prevHash, entry.hash);
|
|
100
|
-
return entry;
|
|
101
|
-
},
|
|
102
|
-
async latest() {
|
|
103
|
-
const row = db.prepare("SELECT * FROM audit_log ORDER BY seq DESC LIMIT 1").get();
|
|
104
|
-
if (row === void 0) return void 0;
|
|
105
|
-
return rowToEntry(row);
|
|
106
|
-
},
|
|
107
|
-
async *iterate(bounds) {
|
|
108
|
-
const lo = bounds?.fromSeq ?? 1;
|
|
109
|
-
const hi = bounds?.toSeq ?? Number.MAX_SAFE_INTEGER;
|
|
110
|
-
const iter = db.prepare("SELECT * FROM audit_log WHERE seq BETWEEN ? AND ? ORDER BY seq ASC").iterate(lo, hi);
|
|
111
|
-
for (const row of iter) yield rowToEntry(row);
|
|
112
|
-
},
|
|
113
|
-
async count() {
|
|
114
|
-
return db.prepare("SELECT COUNT(*) AS n FROM audit_log").get().n;
|
|
115
|
-
},
|
|
116
|
-
async deleteUpTo(threshold) {
|
|
117
|
-
const before = db.prepare("SELECT COUNT(*) AS n FROM audit_log WHERE seq <= ?").get(threshold);
|
|
118
|
-
db.prepare("DELETE FROM audit_log WHERE seq <= ?").run(threshold);
|
|
119
|
-
return before.n;
|
|
120
|
-
},
|
|
121
|
-
async replaceEntry(entry) {
|
|
122
|
-
db.prepare(`UPDATE audit_log SET prev_hash = ?, hash = ? WHERE seq = ?`).run(entry.prevHash, entry.hash, entry.seq);
|
|
123
|
-
},
|
|
124
|
-
async close() {
|
|
125
|
-
if (db.open) db.close();
|
|
126
|
-
}
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
}, { setAsDefault: true });
|
|
130
|
-
storeAuditBindingRegistered = true;
|
|
131
|
-
}
|
|
132
|
-
function rowToEntry(row) {
|
|
133
|
-
return {
|
|
134
|
-
seq: row.seq,
|
|
135
|
-
ts: row.ts,
|
|
136
|
-
actor: JSON.parse(row.actor_json),
|
|
137
|
-
action: row.action,
|
|
138
|
-
target: row.target,
|
|
139
|
-
decision: row.decision,
|
|
140
|
-
...row.context_json !== null ? { context: JSON.parse(row.context_json) } : {},
|
|
141
|
-
...row.metadata_json !== null ? { metadata: JSON.parse(row.metadata_json) } : {},
|
|
142
|
-
prevHash: row.prev_hash,
|
|
143
|
-
hash: row.hash
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
18
|
const VERSION = version;
|
|
147
19
|
/**
|
|
148
20
|
* Build a fully-wired Graphorin server. The returned handle is
|
|
@@ -186,59 +58,25 @@ async function createServer(options = {}) {
|
|
|
186
58
|
const agents = options.agents ?? new AgentRegistry();
|
|
187
59
|
const workflows = options.workflows ?? new WorkflowRegistry();
|
|
188
60
|
const app = new Hono();
|
|
189
|
-
app
|
|
61
|
+
attachGlobalMiddleware(app, config, now);
|
|
62
|
+
const { triggersDaemon, consolidatorDaemon, workflowTimerDaemon } = buildDaemons(options);
|
|
63
|
+
const lifecycle = createLifecycle({
|
|
64
|
+
options,
|
|
65
|
+
config,
|
|
66
|
+
store,
|
|
67
|
+
app,
|
|
68
|
+
metricRegistry,
|
|
69
|
+
runs,
|
|
70
|
+
agents,
|
|
71
|
+
workflows,
|
|
72
|
+
version: version$1,
|
|
73
|
+
startedAt,
|
|
190
74
|
now,
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
let serverInstance;
|
|
197
|
-
let listening;
|
|
198
|
-
let started = false;
|
|
199
|
-
let stopped = false;
|
|
200
|
-
let stopRunPruning;
|
|
201
|
-
let auditDb;
|
|
202
|
-
let preBind;
|
|
203
|
-
let verifier;
|
|
204
|
-
let pepperHandle;
|
|
205
|
-
let triggersDaemon;
|
|
206
|
-
if (options.triggers !== void 0) if ("daemon" in options.triggers) triggersDaemon = options.triggers.daemon;
|
|
207
|
-
else triggersDaemon = createTriggersDaemon({ scheduler: options.triggers.scheduler });
|
|
208
|
-
let consolidatorDaemon;
|
|
209
|
-
if (options.consolidator !== void 0) consolidatorDaemon = createConsolidatorDaemon({ consolidator: options.consolidator });
|
|
210
|
-
let dispatcher;
|
|
211
|
-
let tickets;
|
|
212
|
-
let wsAdapter;
|
|
213
|
-
let commentaryAuditSink;
|
|
214
|
-
if (config.server.ws.enabled) {
|
|
215
|
-
commentaryAuditSink = createLateBoundCommentarySink();
|
|
216
|
-
dispatcher = createWsDispatcher({
|
|
217
|
-
commentary: {
|
|
218
|
-
policy: config.server.ws.commentarySanitization.policy,
|
|
219
|
-
applyToEvents: config.server.ws.commentarySanitization.applyToEvents,
|
|
220
|
-
sink: commentaryAuditSink
|
|
221
|
-
},
|
|
222
|
-
replayBuffer: {
|
|
223
|
-
maxEvents: config.server.stream.replayBuffer.maxEvents,
|
|
224
|
-
ttlMs: config.server.stream.replayBuffer.ttlSeconds * 1e3
|
|
225
|
-
},
|
|
226
|
-
perConnectionQueueLimit: config.server.stream.perConnectionQueueLimit,
|
|
227
|
-
now
|
|
228
|
-
});
|
|
229
|
-
tickets = createWsTicketStore({
|
|
230
|
-
ttlMs: config.server.ws.ticketTtlMs,
|
|
231
|
-
now
|
|
232
|
-
});
|
|
233
|
-
wsAdapter = createNodeWebSocket({ app });
|
|
234
|
-
const wssOptions = wsAdapter.wss.options;
|
|
235
|
-
wssOptions.handleProtocols = (protocols) => {
|
|
236
|
-
const negotiated = negotiateSubprotocol(Array.from(protocols));
|
|
237
|
-
if (negotiated !== null) return negotiated;
|
|
238
|
-
for (const candidate of protocols) if (candidate === SUBPROTOCOL_NAME) return SUBPROTOCOL_NAME;
|
|
239
|
-
return false;
|
|
240
|
-
};
|
|
241
|
-
}
|
|
75
|
+
ws: buildWsLayer(app, config, now),
|
|
76
|
+
triggersDaemon,
|
|
77
|
+
consolidatorDaemon,
|
|
78
|
+
workflowTimerDaemon
|
|
79
|
+
});
|
|
242
80
|
return {
|
|
243
81
|
version: version$1,
|
|
244
82
|
config,
|
|
@@ -248,10 +86,10 @@ async function createServer(options = {}) {
|
|
|
248
86
|
runs,
|
|
249
87
|
metrics: metricRegistry,
|
|
250
88
|
get wsDispatcher() {
|
|
251
|
-
return
|
|
89
|
+
return lifecycle.wsDispatcher;
|
|
252
90
|
},
|
|
253
91
|
get wsTickets() {
|
|
254
|
-
return
|
|
92
|
+
return lifecycle.wsTickets;
|
|
255
93
|
},
|
|
256
94
|
get triggers() {
|
|
257
95
|
return triggersDaemon;
|
|
@@ -259,427 +97,17 @@ async function createServer(options = {}) {
|
|
|
259
97
|
get consolidator() {
|
|
260
98
|
return consolidatorDaemon;
|
|
261
99
|
},
|
|
262
|
-
get
|
|
263
|
-
return
|
|
100
|
+
get workflowTimers() {
|
|
101
|
+
return workflowTimerDaemon;
|
|
264
102
|
},
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
started = true;
|
|
268
|
-
try {
|
|
269
|
-
if (options.hooks?.beforeStart !== void 0) await options.hooks.beforeStart({ config });
|
|
270
|
-
if (options.skipHardening !== true && config.hardening.applyOnStart) applyProcessHardening({
|
|
271
|
-
refuseRoot: config.hardening.refuseRoot,
|
|
272
|
-
umask: config.hardening.umask
|
|
273
|
-
});
|
|
274
|
-
preBind = await runPreBind({
|
|
275
|
-
config,
|
|
276
|
-
store,
|
|
277
|
-
...options.probeCipherPeer !== void 0 ? { probeCipherPeer: options.probeCipherPeer } : {}
|
|
278
|
-
});
|
|
279
|
-
if (config.audit.enabled && preBind.auditPassphrase !== void 0 && preBind.auditPath !== void 0) {
|
|
280
|
-
ensureStoreAuditBinding();
|
|
281
|
-
auditDb = await openAuditDb({
|
|
282
|
-
path: preBind.auditPath,
|
|
283
|
-
passphrase: preBind.auditPassphrase,
|
|
284
|
-
...config.audit.cipher !== void 0 ? { cipher: config.audit.cipher } : {}
|
|
285
|
-
});
|
|
286
|
-
commentaryAuditSink?.bind(bridgeCommentaryToAudit(auditDb));
|
|
287
|
-
}
|
|
288
|
-
if (config.auth.kind === "token") {
|
|
289
|
-
const pepper = preBind.pepper ?? await fallbackPepper(options.skipHardening === true);
|
|
290
|
-
pepperHandle = pepper;
|
|
291
|
-
verifier = new TokenVerifier({
|
|
292
|
-
tokenStore: store.authTokens,
|
|
293
|
-
pepper,
|
|
294
|
-
acceptPrefix: config.auth.tokenPrefix,
|
|
295
|
-
acceptEnvironments: config.auth.tokenEnvironments,
|
|
296
|
-
...config.auth.perIpFailureThreshold !== void 0 ? { perIpFailureThreshold: config.auth.perIpFailureThreshold } : {},
|
|
297
|
-
...config.auth.perIpLockoutMs !== void 0 ? { perIpLockoutMs: config.auth.perIpLockoutMs } : {},
|
|
298
|
-
now
|
|
299
|
-
});
|
|
300
|
-
}
|
|
301
|
-
mountRoutes(app, config, {
|
|
302
|
-
version: version$1,
|
|
303
|
-
startedAt,
|
|
304
|
-
now,
|
|
305
|
-
agents,
|
|
306
|
-
workflows,
|
|
307
|
-
runs,
|
|
308
|
-
store,
|
|
309
|
-
metricRegistry,
|
|
310
|
-
...options.sessions !== void 0 ? { sessions: options.sessions } : {},
|
|
311
|
-
...options.memory !== void 0 ? { memory: options.memory } : {},
|
|
312
|
-
...options.skills !== void 0 ? { skills: options.skills } : {},
|
|
313
|
-
...options.mcp !== void 0 ? { mcp: options.mcp } : {},
|
|
314
|
-
...options.audit !== void 0 ? { audit: options.audit } : {},
|
|
315
|
-
...options.replay !== void 0 ? { replay: options.replay } : {},
|
|
316
|
-
...options.healthProbes !== void 0 ? { healthProbes: options.healthProbes } : {},
|
|
317
|
-
...verifier !== void 0 ? { verifier } : {},
|
|
318
|
-
...auditDb !== void 0 ? { auditDb } : {},
|
|
319
|
-
...pepperHandle !== void 0 ? { pepper: pepperHandle } : {},
|
|
320
|
-
...dispatcher !== void 0 ? { wsDispatcher: dispatcher } : {},
|
|
321
|
-
...tickets !== void 0 ? { wsTickets: tickets } : {},
|
|
322
|
-
...wsAdapter !== void 0 ? { wsAdapter } : {},
|
|
323
|
-
...triggersDaemon !== void 0 ? { triggersDaemon } : {},
|
|
324
|
-
...consolidatorDaemon !== void 0 ? { consolidatorDaemon } : {}
|
|
325
|
-
});
|
|
326
|
-
if (consolidatorDaemon !== void 0) {
|
|
327
|
-
await consolidatorDaemon.start();
|
|
328
|
-
if (triggersDaemon !== void 0 && consolidatorDaemon.consolidator.registerWithScheduler !== void 0) await consolidatorDaemon.consolidator.registerWithScheduler(triggersDaemon.scheduler);
|
|
329
|
-
}
|
|
330
|
-
if (triggersDaemon !== void 0) await triggersDaemon.start();
|
|
331
|
-
try {
|
|
332
|
-
const wal = readWalSize(store.connection);
|
|
333
|
-
metricRegistry.set(SERVER_METRIC_NAMES.storageWalSize, wal);
|
|
334
|
-
} catch {}
|
|
335
|
-
metricRegistry.set(SERVER_METRIC_NAMES.serverUptime, Math.max(0, Math.floor((now() - startedAt) / 1e3)));
|
|
336
|
-
metricRegistry.set(SERVER_METRIC_NAMES.inflightRuns, runs.runningCount());
|
|
337
|
-
metricRegistry.set(SERVER_METRIC_NAMES.replayBufferEvents, 0);
|
|
338
|
-
stopRunPruning = scheduleRunPruning(runs, now);
|
|
339
|
-
if (options.skipListen !== true) {
|
|
340
|
-
serverInstance = serve({
|
|
341
|
-
fetch: app.fetch.bind(app),
|
|
342
|
-
hostname: config.server.host,
|
|
343
|
-
port: config.server.port
|
|
344
|
-
});
|
|
345
|
-
if (wsAdapter !== void 0 && serverInstance !== void 0) wsAdapter.injectWebSocket(serverInstance);
|
|
346
|
-
await new Promise((resolve) => {
|
|
347
|
-
const server = serverInstance;
|
|
348
|
-
if ("once" in server && typeof server.once === "function") server.once("listening", () => resolve());
|
|
349
|
-
else setImmediate(() => resolve());
|
|
350
|
-
});
|
|
351
|
-
const address = serverInstance.address();
|
|
352
|
-
if (address !== null && typeof address === "object") listening = {
|
|
353
|
-
host: address.address,
|
|
354
|
-
port: address.port
|
|
355
|
-
};
|
|
356
|
-
else listening = {
|
|
357
|
-
host: config.server.host,
|
|
358
|
-
port: config.server.port
|
|
359
|
-
};
|
|
360
|
-
} else listening = {
|
|
361
|
-
host: config.server.host,
|
|
362
|
-
port: config.server.port
|
|
363
|
-
};
|
|
364
|
-
if (options.hooks?.onReady !== void 0) await options.hooks.onReady({
|
|
365
|
-
config,
|
|
366
|
-
listeningOn: listening
|
|
367
|
-
});
|
|
368
|
-
return listening;
|
|
369
|
-
} catch (err) {
|
|
370
|
-
started = false;
|
|
371
|
-
await emitError(options.hooks, {
|
|
372
|
-
error: err,
|
|
373
|
-
phase: "beforeStart"
|
|
374
|
-
});
|
|
375
|
-
throw err;
|
|
376
|
-
}
|
|
103
|
+
get listeningOn() {
|
|
104
|
+
return lifecycle.listeningOn;
|
|
377
105
|
},
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
if (stopped) return;
|
|
381
|
-
stopped = true;
|
|
382
|
-
stopRunPruning?.();
|
|
383
|
-
stopRunPruning = void 0;
|
|
384
|
-
const drainTimeoutMs = force === true ? 0 : config.server.shutdown.drainTimeoutMs;
|
|
385
|
-
try {
|
|
386
|
-
if (options.hooks?.beforeShutdown !== void 0) await options.hooks.beforeShutdown({
|
|
387
|
-
config,
|
|
388
|
-
inflight: runs.inflightCount(),
|
|
389
|
-
drainTimeoutMs
|
|
390
|
-
});
|
|
391
|
-
} catch (err) {
|
|
392
|
-
await emitError(options.hooks, {
|
|
393
|
-
error: err,
|
|
394
|
-
phase: "beforeShutdown"
|
|
395
|
-
});
|
|
396
|
-
}
|
|
397
|
-
if (triggersDaemon !== void 0) try {
|
|
398
|
-
await triggersDaemon.stop();
|
|
399
|
-
} catch (err) {
|
|
400
|
-
await emitError(options.hooks, {
|
|
401
|
-
error: err,
|
|
402
|
-
phase: "beforeShutdown"
|
|
403
|
-
});
|
|
404
|
-
}
|
|
405
|
-
if (consolidatorDaemon !== void 0) try {
|
|
406
|
-
await consolidatorDaemon.stop();
|
|
407
|
-
} catch (err) {
|
|
408
|
-
await emitError(options.hooks, {
|
|
409
|
-
error: err,
|
|
410
|
-
phase: "beforeShutdown"
|
|
411
|
-
});
|
|
412
|
-
}
|
|
413
|
-
runs.abortPending("server-shutdown");
|
|
414
|
-
if (!await drainInFlight(runs, drainTimeoutMs, now) && drainTimeoutMs > 0) runs.abortAll(new ShutdownTimeoutError(drainTimeoutMs, runs.runningCount()));
|
|
415
|
-
if (dispatcher !== void 0) try {
|
|
416
|
-
dispatcher.shutdown();
|
|
417
|
-
} catch {}
|
|
418
|
-
if (serverInstance !== void 0) {
|
|
419
|
-
await new Promise((resolve) => {
|
|
420
|
-
serverInstance.close(() => resolve());
|
|
421
|
-
});
|
|
422
|
-
serverInstance = void 0;
|
|
423
|
-
}
|
|
424
|
-
if (auditDb !== void 0) {
|
|
425
|
-
await auditDb.close();
|
|
426
|
-
auditDb = void 0;
|
|
427
|
-
}
|
|
428
|
-
await store.close();
|
|
429
|
-
listening = void 0;
|
|
430
|
-
verifier = void 0;
|
|
431
|
-
started = false;
|
|
432
|
-
preBind = void 0;
|
|
433
|
-
dispatcher = void 0;
|
|
434
|
-
tickets = void 0;
|
|
435
|
-
wsAdapter = void 0;
|
|
436
|
-
}
|
|
437
|
-
};
|
|
438
|
-
}
|
|
439
|
-
/** IP-23: is `host` a loopback interface (so an open /metrics is not exposed)? */
|
|
440
|
-
function isLoopbackHost(host) {
|
|
441
|
-
const h = host.trim().toLowerCase();
|
|
442
|
-
return h === "127.0.0.1" || h === "::1" || h === "[::1]" || h === "localhost";
|
|
443
|
-
}
|
|
444
|
-
function mountRoutes(app, config, ctx) {
|
|
445
|
-
const base = config.server.basePath;
|
|
446
|
-
const probes = ctx.healthProbes ?? (() => buildDefaultHealthProbes(ctx.store, ctx.triggersDaemon, ctx.consolidatorDaemon, ctx.wsDispatcher, config));
|
|
447
|
-
const health = createExtendedHealthRoutes({
|
|
448
|
-
version: ctx.version,
|
|
449
|
-
startedAt: ctx.startedAt,
|
|
450
|
-
now: ctx.now,
|
|
451
|
-
probes
|
|
452
|
-
});
|
|
453
|
-
app.route(`${base}/health`, health);
|
|
454
|
-
if (config.auth.kind === "none" && !isLoopbackHost(config.server.host)) console.warn(`[graphorin/server] WARN: auth.kind='none' disables authentication on every endpoint, but the server binds the non-loopback host '${config.server.host}'. Anyone who can reach it has full admin access - use auth.kind='token' for non-loopback deployments or bind a loopback host.`);
|
|
455
|
-
if (config.metrics.enabled) {
|
|
456
|
-
if (!config.metrics.requireAuth && !isLoopbackHost(config.server.host)) console.warn(`[graphorin/server] WARN: /metrics is unauthenticated (metrics.requireAuth=false) and the server binds the non-loopback host '${config.server.host}'. The exposition leaks operational detail to anyone who can reach it - set metrics.requireAuth=true or bind a loopback host.`);
|
|
457
|
-
const metricsRoute = createMetricsRoutes({
|
|
458
|
-
registry: ctx.metricRegistry,
|
|
459
|
-
requireAuth: config.metrics.requireAuth,
|
|
460
|
-
refresh: () => refreshLiveMetrics({
|
|
461
|
-
registry: ctx.metricRegistry,
|
|
462
|
-
store: ctx.store,
|
|
463
|
-
runs: ctx.runs,
|
|
464
|
-
startedAt: ctx.startedAt,
|
|
465
|
-
now: ctx.now,
|
|
466
|
-
...ctx.triggersDaemon !== void 0 ? { triggersDaemon: ctx.triggersDaemon } : {},
|
|
467
|
-
...ctx.consolidatorDaemon !== void 0 ? { consolidatorDaemon: ctx.consolidatorDaemon } : {},
|
|
468
|
-
...ctx.wsDispatcher !== void 0 ? { wsDispatcher: ctx.wsDispatcher } : {}
|
|
469
|
-
})
|
|
470
|
-
});
|
|
471
|
-
app.route(`${base}${config.metrics.path}`, metricsRoute);
|
|
472
|
-
}
|
|
473
|
-
const wsUpgradePath = config.server.ws.enabled ? `${base}${config.server.ws.path}` : void 0;
|
|
474
|
-
const metricsPath = config.metrics.enabled && !config.metrics.requireAuth ? `${base}${config.metrics.path}` : void 0;
|
|
475
|
-
function shouldSkipAuth(path) {
|
|
476
|
-
if (path === `${base}/health` || path === `${base}/health/`) return true;
|
|
477
|
-
if (wsUpgradePath !== void 0) {
|
|
478
|
-
if (path === wsUpgradePath || path === `${wsUpgradePath}/`) return true;
|
|
479
|
-
}
|
|
480
|
-
if (metricsPath !== void 0) {
|
|
481
|
-
if (path === metricsPath || path === `${metricsPath}/`) return true;
|
|
482
|
-
}
|
|
483
|
-
return false;
|
|
484
|
-
}
|
|
485
|
-
const anonymousAuth = ctx.verifier === void 0 && config.auth.kind === "none";
|
|
486
|
-
if (ctx.verifier !== void 0 || anonymousAuth) {
|
|
487
|
-
const authMw = ctx.verifier !== void 0 ? createAuthMiddleware({ verifier: ctx.verifier }) : createAnonymousAuthMiddleware();
|
|
488
|
-
app.use(`${base}/*`, async (c, next) => {
|
|
489
|
-
if (shouldSkipAuth(c.req.path)) {
|
|
490
|
-
await next();
|
|
491
|
-
return;
|
|
492
|
-
}
|
|
493
|
-
return authMw(c, next);
|
|
494
|
-
});
|
|
495
|
-
if (ctx.auditDb !== void 0) {
|
|
496
|
-
const auditMw = createAuditMiddleware({
|
|
497
|
-
auditDb: ctx.auditDb,
|
|
498
|
-
now: ctx.now
|
|
499
|
-
});
|
|
500
|
-
app.use(`${base}/*`, async (c, next) => {
|
|
501
|
-
if (shouldSkipAuth(c.req.path)) {
|
|
502
|
-
await next();
|
|
503
|
-
return;
|
|
504
|
-
}
|
|
505
|
-
return auditMw(c, next);
|
|
506
|
-
});
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
if (config.server.idempotency.enabled) {
|
|
510
|
-
const idempotencyMw = createIdempotencyMiddleware({
|
|
511
|
-
store: ctx.store.idempotency,
|
|
512
|
-
config: config.server.idempotency,
|
|
513
|
-
now: ctx.now,
|
|
514
|
-
excludeResponseCachePaths: [`${base}/tokens`],
|
|
515
|
-
metricRegistry: ctx.metricRegistry
|
|
516
|
-
});
|
|
517
|
-
app.use(`${base}/*`, async (c, next) => {
|
|
518
|
-
if (shouldSkipAuth(c.req.path)) {
|
|
519
|
-
await next();
|
|
520
|
-
return;
|
|
521
|
-
}
|
|
522
|
-
return idempotencyMw(c, next);
|
|
523
|
-
});
|
|
524
|
-
}
|
|
525
|
-
app.route(`${base}/health/secrets`, createSecretsHealthRoutes());
|
|
526
|
-
app.route(`${base}/agents`, createAgentRoutes({
|
|
527
|
-
agents: ctx.agents,
|
|
528
|
-
runs: ctx.runs,
|
|
529
|
-
...ctx.wsDispatcher !== void 0 ? { dispatcher: ctx.wsDispatcher } : {}
|
|
530
|
-
}));
|
|
531
|
-
app.route(`${base}/runs`, createRunRoutes({
|
|
532
|
-
agents: ctx.agents,
|
|
533
|
-
runs: ctx.runs
|
|
534
|
-
}));
|
|
535
|
-
app.route(`${base}/workflows`, createWorkflowRoutes({
|
|
536
|
-
workflows: ctx.workflows,
|
|
537
|
-
runs: ctx.runs,
|
|
538
|
-
...ctx.wsDispatcher !== void 0 ? { dispatcher: ctx.wsDispatcher } : {}
|
|
539
|
-
}));
|
|
540
|
-
if (ctx.sessions !== void 0) app.route(`${base}/sessions`, createSessionRoutes({ sessions: ctx.sessions }));
|
|
541
|
-
if (ctx.memory !== void 0) app.route(`${base}/memory`, createMemoryRoutes({ memory: ctx.memory }));
|
|
542
|
-
if (ctx.skills !== void 0) app.route(`${base}/skills`, createSkillsRoutes({ skills: ctx.skills }));
|
|
543
|
-
if (ctx.mcp !== void 0) app.route(`${base}/mcp`, createMcpRoutes({ mcp: ctx.mcp }));
|
|
544
|
-
if (ctx.audit !== void 0) app.route(`${base}/audit`, createAuditRoutes({ audit: ctx.audit }));
|
|
545
|
-
if (ctx.triggersDaemon !== void 0) app.route(`${base}/triggers`, createTriggersRoutes({ daemon: ctx.triggersDaemon }));
|
|
546
|
-
if (ctx.replay !== void 0) app.route(`${base}`, createReplayRoutes({
|
|
547
|
-
replay: ctx.replay,
|
|
548
|
-
...ctx.auditDb !== void 0 ? { auditDb: ctx.auditDb } : {},
|
|
549
|
-
now: ctx.now
|
|
550
|
-
}));
|
|
551
|
-
if (config.auth.kind === "token" && ctx.pepper !== void 0) app.route(`${base}/tokens`, createTokensRoutes({
|
|
552
|
-
tokenStore: ctx.store.authTokens,
|
|
553
|
-
pepper: ctx.pepper,
|
|
554
|
-
defaultEnv: "live",
|
|
555
|
-
allowedEnvs: config.auth.tokenEnvironments
|
|
556
|
-
}));
|
|
557
|
-
if (ctx.wsTickets !== void 0) app.route(`${base}`, createAuthRoutes({ tickets: ctx.wsTickets }));
|
|
558
|
-
if (ctx.wsDispatcher !== void 0 && ctx.wsTickets !== void 0 && ctx.wsAdapter !== void 0 && (ctx.verifier !== void 0 || anonymousAuth) && config.server.ws.enabled) {
|
|
559
|
-
const dispatcher = ctx.wsDispatcher;
|
|
560
|
-
const tickets = ctx.wsTickets;
|
|
561
|
-
const verifier = ctx.verifier;
|
|
562
|
-
const runs = ctx.runs;
|
|
563
|
-
app.get(`${base}${config.server.ws.path}`, ctx.wsAdapter.upgradeWebSocket((c) => createWsUpgradeEvents(c, {
|
|
564
|
-
dispatcher,
|
|
565
|
-
tickets,
|
|
566
|
-
...verifier !== void 0 ? { verifier } : {},
|
|
567
|
-
anonymous: anonymousAuth,
|
|
568
|
-
runs,
|
|
569
|
-
now: ctx.now
|
|
570
|
-
})));
|
|
571
|
-
}
|
|
572
|
-
if (ctx.wsDispatcher !== void 0 && config.server.sse.enabled) app.route(`${base}${config.server.sse.path}`, createSseRoutes({
|
|
573
|
-
dispatcher: ctx.wsDispatcher,
|
|
574
|
-
keepAliveMs: config.server.sse.keepAliveMs,
|
|
575
|
-
perConnectionQueueLimit: config.server.stream.perConnectionQueueLimit,
|
|
576
|
-
now: ctx.now
|
|
577
|
-
}));
|
|
578
|
-
}
|
|
579
|
-
async function drainInFlight(runs, drainTimeoutMs, now) {
|
|
580
|
-
if (runs.runningCount() === 0) return true;
|
|
581
|
-
if (drainTimeoutMs <= 0) return runs.runningCount() === 0;
|
|
582
|
-
const deadline = now() + drainTimeoutMs;
|
|
583
|
-
while (now() < deadline) {
|
|
584
|
-
if (runs.runningCount() === 0) return true;
|
|
585
|
-
await new Promise((resolve) => setTimeout(resolve, Math.min(50, deadline - now())));
|
|
586
|
-
}
|
|
587
|
-
return runs.runningCount() === 0;
|
|
588
|
-
}
|
|
589
|
-
async function emitError(hooks, ctx) {
|
|
590
|
-
if (hooks?.onError === void 0) return;
|
|
591
|
-
try {
|
|
592
|
-
await hooks.onError(ctx);
|
|
593
|
-
} catch {}
|
|
594
|
-
}
|
|
595
|
-
async function refreshLiveMetrics(options) {
|
|
596
|
-
const { registry, store, runs, startedAt, now } = options;
|
|
597
|
-
try {
|
|
598
|
-
const wal = readWalSize(store.connection);
|
|
599
|
-
registry.set(SERVER_METRIC_NAMES.storageWalSize, wal);
|
|
600
|
-
} catch {}
|
|
601
|
-
registry.set(SERVER_METRIC_NAMES.serverUptime, Math.max(0, Math.floor((now() - startedAt) / 1e3)));
|
|
602
|
-
registry.set(SERVER_METRIC_NAMES.inflightRuns, runs.runningCount());
|
|
603
|
-
if (options.wsDispatcher !== void 0) {
|
|
604
|
-
const sizes = options.wsDispatcher.size();
|
|
605
|
-
registry.set(SERVER_METRIC_NAMES.replayBufferEvents, sizes.subscriptions);
|
|
606
|
-
}
|
|
607
|
-
if (options.triggersDaemon !== void 0) {
|
|
608
|
-
const metrics = options.triggersDaemon.metrics();
|
|
609
|
-
for (const [triggerId, counts] of metrics.fires) {
|
|
610
|
-
const sanitized = sanitizeMetricLabelValue(triggerId);
|
|
611
|
-
const successCurrent = readCounter(registry, SERVER_METRIC_NAMES.triggersFiresTotal, {
|
|
612
|
-
trigger_id: sanitized,
|
|
613
|
-
status: "success"
|
|
614
|
-
});
|
|
615
|
-
const errorCurrent = readCounter(registry, SERVER_METRIC_NAMES.triggersFiresTotal, {
|
|
616
|
-
trigger_id: sanitized,
|
|
617
|
-
status: "error"
|
|
618
|
-
});
|
|
619
|
-
const successDelta = counts.success - successCurrent;
|
|
620
|
-
const errorDelta = counts.error - errorCurrent;
|
|
621
|
-
if (successDelta > 0) registry.inc(SERVER_METRIC_NAMES.triggersFiresTotal, {
|
|
622
|
-
trigger_id: sanitized,
|
|
623
|
-
status: "success"
|
|
624
|
-
}, successDelta);
|
|
625
|
-
if (errorDelta > 0) registry.inc(SERVER_METRIC_NAMES.triggersFiresTotal, {
|
|
626
|
-
trigger_id: sanitized,
|
|
627
|
-
status: "error"
|
|
628
|
-
}, errorDelta);
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
if (options.consolidatorDaemon !== void 0) try {
|
|
632
|
-
const status = await options.consolidatorDaemon.status();
|
|
633
|
-
registry.set(SERVER_METRIC_NAMES.consolidatorQueueDepth, status.queueDepth, { phase: "aggregate" });
|
|
634
|
-
registry.set(SERVER_METRIC_NAMES.consolidatorDlqSize, status.dlqSize);
|
|
635
|
-
registry.set(SERVER_METRIC_NAMES.consolidatorBudgetRemainingUsd, status.budget.costRemaining);
|
|
636
|
-
registry.set(SERVER_METRIC_NAMES.consolidatorBudgetRemainingTokens, status.budget.tokensRemaining);
|
|
637
|
-
} catch {}
|
|
638
|
-
}
|
|
639
|
-
/**
|
|
640
|
-
* Convert an arbitrary user-supplied identifier (trigger id) into a
|
|
641
|
-
* Prometheus-safe label value. Replaces every character outside the
|
|
642
|
-
* `[A-Za-z0-9_:]` range with `_`. This guarantees the cardinality
|
|
643
|
-
* never explodes on UTF-8 sequences while keeping the value
|
|
644
|
-
* recognizable.
|
|
645
|
-
*/
|
|
646
|
-
function sanitizeMetricLabelValue(value) {
|
|
647
|
-
return value.replace(/[^A-Za-z0-9_:.-]/g, "_").slice(0, 200);
|
|
648
|
-
}
|
|
649
|
-
function readCounter(registry, name, labels) {
|
|
650
|
-
const snap = registry.snapshot().counters[name] ?? [];
|
|
651
|
-
for (const entry of snap) if (matchesLabels(entry.labels, labels)) return entry.value;
|
|
652
|
-
return 0;
|
|
653
|
-
}
|
|
654
|
-
function matchesLabels(a, b) {
|
|
655
|
-
for (const k of Object.keys(b)) if (String(a[k]) !== b[k]) return false;
|
|
656
|
-
for (const k of Object.keys(a)) if (!(k in b)) return false;
|
|
657
|
-
return true;
|
|
658
|
-
}
|
|
659
|
-
function buildDefaultHealthProbes(store, triggersDaemon, consolidatorDaemon, dispatcher, config) {
|
|
660
|
-
const out = {
|
|
661
|
-
store,
|
|
662
|
-
walWarnThresholdBytes: config.health.walWarnThresholdBytes,
|
|
663
|
-
encryptionEnabled: config.storage.encryption.enabled,
|
|
664
|
-
...config.storage.encryption.enabled ? { cipherPeerInstalled: true } : {}
|
|
106
|
+
start: lifecycle.start,
|
|
107
|
+
stop: lifecycle.stop
|
|
665
108
|
};
|
|
666
|
-
if (triggersDaemon !== void 0) out.triggers = triggersDaemon;
|
|
667
|
-
if (consolidatorDaemon !== void 0) out.consolidator = consolidatorDaemon;
|
|
668
|
-
if (dispatcher !== void 0) {
|
|
669
|
-
const sizes = dispatcher.size();
|
|
670
|
-
out.replayBuffer = {
|
|
671
|
-
eventsBuffered: sizes.subscriptions,
|
|
672
|
-
subscribers: sizes.subscribers,
|
|
673
|
-
subscriptions: sizes.subscriptions
|
|
674
|
-
};
|
|
675
|
-
}
|
|
676
|
-
return Object.freeze(out);
|
|
677
|
-
}
|
|
678
|
-
async function fallbackPepper(skipHardening) {
|
|
679
|
-
if (!skipHardening) throw new Error("[graphorin/server] missing resolved pepper after pre-bind; auth.pepperRef is required when auth.kind = token.");
|
|
680
|
-
return generatePepper();
|
|
681
109
|
}
|
|
682
110
|
|
|
683
111
|
//#endregion
|
|
684
|
-
export { createServer
|
|
112
|
+
export { createServer };
|
|
685
113
|
//# sourceMappingURL=app.js.map
|