@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
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Health-family REST routes.
|
|
3
|
+
*
|
|
4
|
+
* GET /health (unauthenticated; liveness)
|
|
5
|
+
* GET /health/secrets (admin scope)
|
|
6
|
+
* GET /metrics (Prometheus exposition)
|
|
7
|
+
*
|
|
8
|
+
* `/health` returns 200 even when the rollup is `'degraded'`; only
|
|
9
|
+
* `'failing'` short-circuits with 503 so liveness probes do not flap
|
|
10
|
+
* on minor degradations (e.g. WAL above the warn threshold).
|
|
11
|
+
*
|
|
12
|
+
* @packageDocumentation
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { getSecretsStoreStatus } from '@graphorin/security/secrets';
|
|
16
|
+
import type { Context } from 'hono';
|
|
17
|
+
import { Hono } from 'hono';
|
|
18
|
+
|
|
19
|
+
import type { ServerVariables } from '../internal/context.js';
|
|
20
|
+
import type { MetricRegistry } from '../metrics/registry.js';
|
|
21
|
+
import { createScopeMiddleware } from '../middleware/scope.js';
|
|
22
|
+
import { collectHealth, type HealthCheckOptions } from './checks.js';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @stable
|
|
26
|
+
*/
|
|
27
|
+
export interface HealthRouteOptions {
|
|
28
|
+
readonly version: string;
|
|
29
|
+
readonly startedAt: number;
|
|
30
|
+
readonly now?: () => number;
|
|
31
|
+
readonly probes: () => HealthCheckOptions | Promise<HealthCheckOptions>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Public health route (anonymous; mounted before auth middleware).
|
|
36
|
+
* Returns the rollup + per-check breakdown; HTTP 200 even when the
|
|
37
|
+
* rollup is `'degraded'` so liveness probes do not flap on minor
|
|
38
|
+
* degradations. Only `'failing'` short-circuits with 503.
|
|
39
|
+
*
|
|
40
|
+
* @stable
|
|
41
|
+
*/
|
|
42
|
+
export function createExtendedHealthRoutes(
|
|
43
|
+
options: HealthRouteOptions,
|
|
44
|
+
): Hono<{ Variables: ServerVariables }> {
|
|
45
|
+
const app = new Hono<{ Variables: ServerVariables }>();
|
|
46
|
+
const now = options.now ?? Date.now;
|
|
47
|
+
|
|
48
|
+
app.get('/', async (c) => {
|
|
49
|
+
const probes = await options.probes();
|
|
50
|
+
const summary = await collectHealth(probes);
|
|
51
|
+
const body = {
|
|
52
|
+
status: summary.status,
|
|
53
|
+
version: options.version,
|
|
54
|
+
uptimeSeconds: Math.max(0, Math.floor((now() - options.startedAt) / 1000)),
|
|
55
|
+
checks: summary.checks,
|
|
56
|
+
};
|
|
57
|
+
if (summary.status === 'failing') {
|
|
58
|
+
return c.json(body, 503);
|
|
59
|
+
}
|
|
60
|
+
return c.json(body, 200);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
return app;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Authed health route. Mounted at `${base}/health/secrets` AFTER the
|
|
68
|
+
* auth middleware so the scope check has a verified token to inspect.
|
|
69
|
+
* Returns the active secrets store + fallback chain + downgrade
|
|
70
|
+
* reason per the secrets capability matrix.
|
|
71
|
+
*
|
|
72
|
+
* @stable
|
|
73
|
+
*/
|
|
74
|
+
export function createSecretsHealthRoutes(): Hono<{ Variables: ServerVariables }> {
|
|
75
|
+
const app = new Hono<{ Variables: ServerVariables }>();
|
|
76
|
+
|
|
77
|
+
app.get('/', createScopeMiddleware('secrets:read'), (c) => {
|
|
78
|
+
const status = getSecretsStoreStatus();
|
|
79
|
+
if (status === undefined) {
|
|
80
|
+
return c.json(
|
|
81
|
+
{
|
|
82
|
+
active: 'unknown',
|
|
83
|
+
fallbackChain: [] as ReadonlyArray<string>,
|
|
84
|
+
strictMode: false,
|
|
85
|
+
headlessReasons: [] as ReadonlyArray<string>,
|
|
86
|
+
message: 'Secrets store has not been activated yet.',
|
|
87
|
+
},
|
|
88
|
+
200,
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
return c.json(
|
|
92
|
+
{
|
|
93
|
+
active: status.active,
|
|
94
|
+
fallbackChain: [...status.fallbackChain],
|
|
95
|
+
...(status.downgradedFrom !== undefined ? { downgradedFrom: status.downgradedFrom } : {}),
|
|
96
|
+
...(status.downgradeReason !== undefined
|
|
97
|
+
? { downgradeReason: status.downgradeReason }
|
|
98
|
+
: {}),
|
|
99
|
+
strictMode: status.strictMode,
|
|
100
|
+
headlessReasons: [...status.headlessReasons],
|
|
101
|
+
},
|
|
102
|
+
200,
|
|
103
|
+
);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
return app;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* @stable
|
|
111
|
+
*/
|
|
112
|
+
export interface MetricsRoutesOptions {
|
|
113
|
+
readonly registry: MetricRegistry;
|
|
114
|
+
readonly requireAuth?: boolean;
|
|
115
|
+
/**
|
|
116
|
+
* Optional refresh callback invoked before every scrape. Use it to
|
|
117
|
+
* sample live signals (WAL size, in-flight runs, daemon status,
|
|
118
|
+
* replay buffer occupancy) into the registry so the scraped output
|
|
119
|
+
* reflects the moment of the request.
|
|
120
|
+
*
|
|
121
|
+
* Refresh failures are swallowed - a broken probe never blocks a
|
|
122
|
+
* Prometheus scrape - and surfaced through the optional `onError`
|
|
123
|
+
* sink.
|
|
124
|
+
*/
|
|
125
|
+
readonly refresh?: () => void | Promise<void>;
|
|
126
|
+
readonly onError?: (err: unknown) => void;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* @stable
|
|
131
|
+
*/
|
|
132
|
+
export function createMetricsRoutes(
|
|
133
|
+
options: MetricsRoutesOptions,
|
|
134
|
+
): Hono<{ Variables: ServerVariables }> {
|
|
135
|
+
const app = new Hono<{ Variables: ServerVariables }>();
|
|
136
|
+
const handler = async (c: Context<{ Variables: ServerVariables }>) => {
|
|
137
|
+
if (options.refresh !== undefined) {
|
|
138
|
+
try {
|
|
139
|
+
await options.refresh();
|
|
140
|
+
} catch (err) {
|
|
141
|
+
options.onError?.(err);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const body = options.registry.render();
|
|
145
|
+
c.header('Content-Type', options.registry.contentType());
|
|
146
|
+
return c.body(body, 200);
|
|
147
|
+
};
|
|
148
|
+
if (options.requireAuth === true) {
|
|
149
|
+
app.get('/', createScopeMiddleware('admin:metrics:read'), handler);
|
|
150
|
+
} else {
|
|
151
|
+
app.get('/', handler);
|
|
152
|
+
}
|
|
153
|
+
return app;
|
|
154
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@graphorin/server` - standalone server runtime for the Graphorin
|
|
3
|
+
* framework.
|
|
4
|
+
*
|
|
5
|
+
* Phase 14a entry point. Ships:
|
|
6
|
+
*
|
|
7
|
+
* - {@link createServer} - the single programmatic entry that wires
|
|
8
|
+
* the Hono app, the auth + scope + idempotency + audit middleware
|
|
9
|
+
* stack, REST endpoints (agents / workflows / sessions / memory /
|
|
10
|
+
* skills / mcp / tokens / audit / health), the lifecycle hooks
|
|
11
|
+
* (`beforeStart` / `onReady` / `beforeShutdown` / `onError`), the
|
|
12
|
+
* pre-bind secrets-resolution + storage-migration runner, and the
|
|
13
|
+
* graceful SIGTERM drain.
|
|
14
|
+
* - {@link defineConfig} + {@link parseServerConfig} - typed
|
|
15
|
+
* configuration loader with a Zod-validated schema; missing fields
|
|
16
|
+
* fall back to documented production-ready defaults.
|
|
17
|
+
* - {@link AgentRegistry} + {@link WorkflowRegistry} - read/write
|
|
18
|
+
* registries the route handlers consult to look up user-defined
|
|
19
|
+
* agents / workflows.
|
|
20
|
+
* - {@link RunStateTracker} - in-memory bookkeeping for in-flight
|
|
21
|
+
* runs (run id, status, AbortController). Phase 14b/c promote the
|
|
22
|
+
* tracker to a SQLite-backed durable variant.
|
|
23
|
+
* - The full middleware factory suite - re-exported from
|
|
24
|
+
* `@graphorin/server/middleware` so operators can compose a custom
|
|
25
|
+
* Hono app on top of the same primitives.
|
|
26
|
+
*
|
|
27
|
+
* @packageDocumentation
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/** Canonical version constant, derived from `package.json` at build time. */
|
|
31
|
+
import pkg from '../package.json' with { type: 'json' };
|
|
32
|
+
|
|
33
|
+
export const VERSION: string = pkg.version;
|
|
34
|
+
|
|
35
|
+
export {
|
|
36
|
+
type CreateServerOptions,
|
|
37
|
+
createServer,
|
|
38
|
+
ensureStoreAuditBinding,
|
|
39
|
+
type GraphorinServer,
|
|
40
|
+
type TriggersDaemonInput,
|
|
41
|
+
type WorkflowTimersInput,
|
|
42
|
+
} from './app.js';
|
|
43
|
+
export {
|
|
44
|
+
createDeliveryCommentarySanitizer,
|
|
45
|
+
DEFAULT_APPLY_TO_EVENTS,
|
|
46
|
+
DEFAULT_DELIVERY_COMMENTARY_PATTERNS,
|
|
47
|
+
type DeliveryCommentaryConfig,
|
|
48
|
+
type DeliveryCommentaryDecision,
|
|
49
|
+
type DeliveryCommentaryPattern,
|
|
50
|
+
type DeliveryCommentaryPolicy,
|
|
51
|
+
type DeliveryCommentaryReason,
|
|
52
|
+
type DeliveryCommentarySanitizer,
|
|
53
|
+
type DeliveryCommentarySink,
|
|
54
|
+
type DeliveryCommentaryTransport,
|
|
55
|
+
} from './commentary/index.js';
|
|
56
|
+
export {
|
|
57
|
+
type DeliveryCommentaryPolicyConfig,
|
|
58
|
+
defineConfig,
|
|
59
|
+
type IdempotencyRequireKeyMode,
|
|
60
|
+
parseServerConfig,
|
|
61
|
+
type SecretRefString,
|
|
62
|
+
type SecretsSource,
|
|
63
|
+
type ServerConfigInput,
|
|
64
|
+
ServerConfigSchema,
|
|
65
|
+
type ServerConfigSpec,
|
|
66
|
+
} from './config.js';
|
|
67
|
+
export {
|
|
68
|
+
type ConsolidatorDaemon,
|
|
69
|
+
type ConsolidatorLike,
|
|
70
|
+
type ConsolidatorStatusLike,
|
|
71
|
+
type CreateConsolidatorDaemonOptions,
|
|
72
|
+
createConsolidatorDaemon,
|
|
73
|
+
} from './consolidator/index.js';
|
|
74
|
+
export * from './errors/index.js';
|
|
75
|
+
export {
|
|
76
|
+
type BaseHealthCheck,
|
|
77
|
+
type ConsolidatorCheck,
|
|
78
|
+
collectHealth,
|
|
79
|
+
createExtendedHealthRoutes,
|
|
80
|
+
createMetricsRoutes,
|
|
81
|
+
createSecretsHealthRoutes,
|
|
82
|
+
type EmbedderCheck,
|
|
83
|
+
type EncryptionCheck,
|
|
84
|
+
type HealthCheck,
|
|
85
|
+
type HealthCheckOptions,
|
|
86
|
+
type HealthChecks,
|
|
87
|
+
type HealthRollup,
|
|
88
|
+
type HealthRouteOptions,
|
|
89
|
+
type HealthStatus,
|
|
90
|
+
type HealthSummary,
|
|
91
|
+
type MetricsRoutesOptions,
|
|
92
|
+
type ReplayBufferCheck,
|
|
93
|
+
type ReplayBufferProbe,
|
|
94
|
+
rollup,
|
|
95
|
+
type SecretsCheck,
|
|
96
|
+
type StorageCheck,
|
|
97
|
+
type TriggersCheck,
|
|
98
|
+
} from './health/index.js';
|
|
99
|
+
export type { RequestToken, ServerRequestState, ServerVariables } from './internal/context.js';
|
|
100
|
+
export {
|
|
101
|
+
type BeforeShutdownContext,
|
|
102
|
+
type BeforeStartContext,
|
|
103
|
+
type LifecycleHooks,
|
|
104
|
+
type OnErrorContext,
|
|
105
|
+
type OnReadyContext,
|
|
106
|
+
type PreBindResult,
|
|
107
|
+
type RunPreBindOptions,
|
|
108
|
+
runPreBind,
|
|
109
|
+
} from './lifecycle/index.js';
|
|
110
|
+
export {
|
|
111
|
+
createServerMetricRegistry,
|
|
112
|
+
type LabelSet,
|
|
113
|
+
type MetricKind,
|
|
114
|
+
MetricRegistry,
|
|
115
|
+
SERVER_METRIC_NAMES,
|
|
116
|
+
} from './metrics/index.js';
|
|
117
|
+
export { syncToolCounters } from './metrics/tools-bridge.js';
|
|
118
|
+
export {
|
|
119
|
+
type AuditErrorSink,
|
|
120
|
+
type AuditMiddlewareOptions,
|
|
121
|
+
type AuthMiddlewareOptions,
|
|
122
|
+
createAuditMiddleware,
|
|
123
|
+
createAuthMiddleware,
|
|
124
|
+
createCorsMiddleware,
|
|
125
|
+
createCsrfMiddleware,
|
|
126
|
+
createIdempotencyMiddleware,
|
|
127
|
+
createRateLimitMiddleware,
|
|
128
|
+
createRequestStateMiddleware,
|
|
129
|
+
createScopeMiddleware,
|
|
130
|
+
HTTP_REQUEST_AUDIT_ACTION,
|
|
131
|
+
type IdempotencyMiddlewareOptions,
|
|
132
|
+
type RequestStateMiddlewareOptions,
|
|
133
|
+
type ScopeRequirement,
|
|
134
|
+
} from './middleware/index.js';
|
|
135
|
+
export {
|
|
136
|
+
type AgentRegistration,
|
|
137
|
+
AgentRegistry,
|
|
138
|
+
type AgentSummary,
|
|
139
|
+
type ServerAgentLike,
|
|
140
|
+
type ServerWorkflowLike,
|
|
141
|
+
type WorkflowRegistration,
|
|
142
|
+
WorkflowRegistry,
|
|
143
|
+
type WorkflowSummary,
|
|
144
|
+
} from './registry/index.js';
|
|
145
|
+
export {
|
|
146
|
+
createReplayRoutes,
|
|
147
|
+
type ReplayApi,
|
|
148
|
+
type ReplayMode,
|
|
149
|
+
type ReplayResponse,
|
|
150
|
+
type ReplayRoutesDeps,
|
|
151
|
+
} from './replay/index.js';
|
|
152
|
+
export {
|
|
153
|
+
type AgentRoutesDeps,
|
|
154
|
+
type AuditApi,
|
|
155
|
+
type AuditRoutesDeps,
|
|
156
|
+
type AuthRoutesDeps,
|
|
157
|
+
createAgentRoutes,
|
|
158
|
+
createAuditRoutes,
|
|
159
|
+
createAuthRoutes,
|
|
160
|
+
createHealthRoutes,
|
|
161
|
+
createMcpRoutes,
|
|
162
|
+
createMemoryRoutes,
|
|
163
|
+
createRunRoutes,
|
|
164
|
+
createSessionRoutes,
|
|
165
|
+
createSkillsRoutes,
|
|
166
|
+
createTokensRoutes,
|
|
167
|
+
createWorkflowRoutes,
|
|
168
|
+
type HealthRoutesDeps,
|
|
169
|
+
type McpApi,
|
|
170
|
+
type McpRoutesDeps,
|
|
171
|
+
type MemoryApi,
|
|
172
|
+
type MemoryRoutesDeps,
|
|
173
|
+
type SessionApi,
|
|
174
|
+
type SessionRoutesDeps,
|
|
175
|
+
type SkillsApi,
|
|
176
|
+
type SkillsRoutesDeps,
|
|
177
|
+
type TokensRoutesDeps,
|
|
178
|
+
type WorkflowRoutesDeps,
|
|
179
|
+
} from './routes/index.js';
|
|
180
|
+
export {
|
|
181
|
+
createConsoleRetentionLog,
|
|
182
|
+
type RetentionConfig,
|
|
183
|
+
type RetentionLog,
|
|
184
|
+
type RetentionLogLevel,
|
|
185
|
+
type RetentionStoreLike,
|
|
186
|
+
type ScheduleRetentionOptions,
|
|
187
|
+
scheduleRetentionSweeps,
|
|
188
|
+
} from './runtime/retention.js';
|
|
189
|
+
export {
|
|
190
|
+
type RunDescriptor,
|
|
191
|
+
type RunHandle,
|
|
192
|
+
type RunStateSnapshot,
|
|
193
|
+
RunStateTracker,
|
|
194
|
+
type RunStatus,
|
|
195
|
+
} from './runtime/run-state.js';
|
|
196
|
+
export { createSseRoutes, type SseRoutesDeps } from './sse/index.js';
|
|
197
|
+
export {
|
|
198
|
+
bridgeToolAuditToAudit,
|
|
199
|
+
type ToolAuditBridge,
|
|
200
|
+
type ToolEventsAuditPolicy,
|
|
201
|
+
toolAuditEventToAuditInput,
|
|
202
|
+
} from './tools-audit-bridge.js';
|
|
203
|
+
export {
|
|
204
|
+
type CreateTriggersDaemonOptions,
|
|
205
|
+
createTriggersDaemon,
|
|
206
|
+
createTriggersRoutes,
|
|
207
|
+
defaultCatchupPolicy,
|
|
208
|
+
type TriggersDaemon,
|
|
209
|
+
type TriggersDaemonMetrics,
|
|
210
|
+
type TriggersDaemonStatus,
|
|
211
|
+
type TriggersRoutesDeps,
|
|
212
|
+
} from './triggers/index.js';
|
|
213
|
+
export {
|
|
214
|
+
type CreateWorkflowTimerDaemonOptions,
|
|
215
|
+
createWorkflowTimerDaemon,
|
|
216
|
+
type WorkflowTimerDaemon,
|
|
217
|
+
type WorkflowTimerDaemonStatus,
|
|
218
|
+
type WorkflowTimerDriverLike,
|
|
219
|
+
} from './workflows/timer-daemon.js';
|
|
220
|
+
export {
|
|
221
|
+
type BareEventFrame,
|
|
222
|
+
createReplayBuffer,
|
|
223
|
+
createWsDispatcher,
|
|
224
|
+
createWsTicketStore,
|
|
225
|
+
createWsUpgradeEvents,
|
|
226
|
+
type ParsedSubject,
|
|
227
|
+
type ReplayBuffer,
|
|
228
|
+
type ReplayBufferOptions,
|
|
229
|
+
type ReplayBufferSlice,
|
|
230
|
+
requiredScopeFor,
|
|
231
|
+
type SubscribeResult,
|
|
232
|
+
tryParseSubject,
|
|
233
|
+
type WsDispatcher,
|
|
234
|
+
type WsDispatcherOptions,
|
|
235
|
+
type WsDispatcherWarning,
|
|
236
|
+
type WsSubscriberHandle,
|
|
237
|
+
type WsSubscriptionSnapshot,
|
|
238
|
+
type WsTicket,
|
|
239
|
+
type WsTicketConsumeResult,
|
|
240
|
+
type WsTicketStore,
|
|
241
|
+
type WsTicketStoreOptions,
|
|
242
|
+
type WsUpgradeOptions,
|
|
243
|
+
} from './ws/index.js';
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-request context shape stored on the Hono `c.var` slot. Consumers
|
|
3
|
+
* (route handlers, audit middleware, idempotency middleware) read these
|
|
4
|
+
* fields through type-safe accessors defined in this module.
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { ParsedScope, VerifiedToken } from '@graphorin/security/auth';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Discriminator for the request authentication state.
|
|
13
|
+
*
|
|
14
|
+
* @stable
|
|
15
|
+
*/
|
|
16
|
+
export type AuthState =
|
|
17
|
+
| { readonly kind: 'unauthenticated' }
|
|
18
|
+
| {
|
|
19
|
+
readonly kind: 'token';
|
|
20
|
+
readonly token: VerifiedToken;
|
|
21
|
+
readonly grantedScopes: ReadonlyArray<ParsedScope>;
|
|
22
|
+
}
|
|
23
|
+
// IP-13: authentication is disabled server-wide (`auth.kind = 'none'`,
|
|
24
|
+
// the documented trusted-loopback / single-operator mode). There is no
|
|
25
|
+
// token, but the request is fully authorized - `grantedScopes` carries
|
|
26
|
+
// `admin:*` so every scope check passes uniformly.
|
|
27
|
+
| {
|
|
28
|
+
readonly kind: 'anonymous';
|
|
29
|
+
readonly grantedScopes: ReadonlyArray<ParsedScope>;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Request-scoped variables surfaced through `c.var` in Hono. The
|
|
34
|
+
* server's middleware populates these fields incrementally; route
|
|
35
|
+
* handlers consume them through `getRequestState`.
|
|
36
|
+
*
|
|
37
|
+
* @stable
|
|
38
|
+
*/
|
|
39
|
+
export interface ServerRequestState {
|
|
40
|
+
readonly requestId: string;
|
|
41
|
+
readonly receivedAt: number;
|
|
42
|
+
readonly clientIp: string | undefined;
|
|
43
|
+
readonly auth: AuthState;
|
|
44
|
+
readonly idempotencyKey?: string;
|
|
45
|
+
readonly idempotencyReplay?: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Convenience snapshot of the verified token surfaced on `c.var.token`
|
|
50
|
+
* once the auth middleware has resolved the bearer credential. Mirrors
|
|
51
|
+
* the contract documented in the runtime architecture (Phase 14a §
|
|
52
|
+
* Authentication / authorization middleware: "populates `c.var.token:
|
|
53
|
+
* { id, label, scopes, env }`").
|
|
54
|
+
*
|
|
55
|
+
* Read this through `getRequestToken` so consumers do not have
|
|
56
|
+
* to remember the variable key.
|
|
57
|
+
*
|
|
58
|
+
* @stable
|
|
59
|
+
*/
|
|
60
|
+
export interface RequestToken {
|
|
61
|
+
readonly id: string;
|
|
62
|
+
readonly label: string | undefined;
|
|
63
|
+
readonly scopes: ReadonlyArray<ParsedScope>;
|
|
64
|
+
readonly env: string;
|
|
65
|
+
readonly expiresAt: number | undefined;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Hono variable map. Exported so consumers can type their own
|
|
70
|
+
* middleware against the same surface.
|
|
71
|
+
*
|
|
72
|
+
* @stable
|
|
73
|
+
*/
|
|
74
|
+
export interface ServerVariables extends Record<string, unknown> {
|
|
75
|
+
readonly state: ServerRequestState;
|
|
76
|
+
readonly token?: RequestToken;
|
|
77
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tiny id helpers shared across middleware + routes.
|
|
3
|
+
*
|
|
4
|
+
* @internal
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { randomUUID } from 'node:crypto';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Generate an opaque per-request id. UUID v4 keeps the surface area
|
|
11
|
+
* minimal - operators that already pin a different scheme (Datadog
|
|
12
|
+
* trace ids, AWS request ids, …) can override the generator on
|
|
13
|
+
* `createServer({ requestIdGenerator })`.
|
|
14
|
+
*/
|
|
15
|
+
export function newRequestId(): string {
|
|
16
|
+
return randomUUID();
|
|
17
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers for the strict JSON contract every REST endpoint speaks.
|
|
3
|
+
*
|
|
4
|
+
* @internal
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { createHash } from 'node:crypto';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Stable, recursive JSON canonicalisation: object keys sorted
|
|
11
|
+
* lexicographically, arrays preserved as-is. Used by the idempotency
|
|
12
|
+
* middleware so two semantically-identical bodies produce the same
|
|
13
|
+
* fingerprint.
|
|
14
|
+
*/
|
|
15
|
+
export function canonicalJson(value: unknown): string {
|
|
16
|
+
return JSON.stringify(canonicalize(value));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function canonicalize(value: unknown): unknown {
|
|
20
|
+
if (value === null) return null;
|
|
21
|
+
if (typeof value !== 'object') return value;
|
|
22
|
+
if (Array.isArray(value)) return value.map(canonicalize);
|
|
23
|
+
const entries = Object.entries(value as Record<string, unknown>).sort(([a], [b]) =>
|
|
24
|
+
a < b ? -1 : a > b ? 1 : 0,
|
|
25
|
+
);
|
|
26
|
+
const out: Record<string, unknown> = {};
|
|
27
|
+
for (const [key, val] of entries) out[key] = canonicalize(val);
|
|
28
|
+
return out;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* SHA-256 hex digest of the supplied bytes. Returns the lowercase
|
|
33
|
+
* hex string so it can be compared against the persisted fingerprint
|
|
34
|
+
* without further normalisation.
|
|
35
|
+
*/
|
|
36
|
+
export function sha256Hex(input: string | Uint8Array): string {
|
|
37
|
+
return createHash('sha256').update(input).digest('hex');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* SHA-256 fingerprint of a (method, path, body) tuple. The body is
|
|
42
|
+
* canonicalised before hashing so trivial whitespace differences do
|
|
43
|
+
* not register as a payload mismatch.
|
|
44
|
+
*/
|
|
45
|
+
export function fingerprintRequest(method: string, path: string, body: unknown): string {
|
|
46
|
+
return sha256Hex(`${method.toUpperCase()} ${path}\n${canonicalJson(body)}`);
|
|
47
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* W-052: machine-readable error envelope for the server boundary.
|
|
3
|
+
*
|
|
4
|
+
* The packages disagree on the error discriminator by history:
|
|
5
|
+
* `@graphorin/agent` / `@graphorin/workflow` use `code`,
|
|
6
|
+
* `@graphorin/tools` / `@graphorin/memory` / `@graphorin/provider` /
|
|
7
|
+
* the server's own errors use `kind`. Renaming either family is a
|
|
8
|
+
* breaking change to no benefit - NORMALIZATION IS THE SERVER
|
|
9
|
+
* BOUNDARY'S JOB. Every wire payload that reports a failure funnels
|
|
10
|
+
* through {@link toWireError}, so clients branch on one stable `code`
|
|
11
|
+
* field (e.g. retry `checkpoint-version-conflict`, abandon
|
|
12
|
+
* `node-execution-failed`) instead of parsing English prose.
|
|
13
|
+
*
|
|
14
|
+
* @packageDocumentation
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/** Normalized error envelope for wire payloads. */
|
|
18
|
+
export interface WireError {
|
|
19
|
+
/** `err.code` if a string, else `err.kind` if a string, else `'unknown'`. */
|
|
20
|
+
readonly code: string;
|
|
21
|
+
readonly message: string;
|
|
22
|
+
/** Operator hint when the source error carries one (`WorkflowError.hint`). */
|
|
23
|
+
readonly hint?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Normalize any thrown value into the wire envelope (W-052). */
|
|
27
|
+
export function toWireError(err: unknown): WireError {
|
|
28
|
+
if (err !== null && typeof err === 'object') {
|
|
29
|
+
const rec = err as { code?: unknown; kind?: unknown; message?: unknown; hint?: unknown };
|
|
30
|
+
const code =
|
|
31
|
+
typeof rec.code === 'string' && rec.code.length > 0
|
|
32
|
+
? rec.code
|
|
33
|
+
: typeof rec.kind === 'string' && rec.kind.length > 0
|
|
34
|
+
? rec.kind
|
|
35
|
+
: 'unknown';
|
|
36
|
+
const message = typeof rec.message === 'string' ? rec.message : String(err);
|
|
37
|
+
return {
|
|
38
|
+
code,
|
|
39
|
+
message,
|
|
40
|
+
...(typeof rec.hint === 'string' && rec.hint.length > 0 ? { hint: rec.hint } : {}),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return { code: 'unknown', message: String(err) };
|
|
44
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lifecycle hook contract used by `createServer({...})`. Hooks fire
|
|
3
|
+
* in the documented order:
|
|
4
|
+
*
|
|
5
|
+
* beforeStart -> pre-bind -> migrations -> bind -> onReady
|
|
6
|
+
*
|
|
7
|
+
* On shutdown:
|
|
8
|
+
*
|
|
9
|
+
* SIGTERM -> beforeShutdown -> drain -> onError? -> exit
|
|
10
|
+
*
|
|
11
|
+
* @packageDocumentation
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { ServerConfigSpec } from '../config.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Snapshot passed to {@link LifecycleHooks.beforeStart}.
|
|
18
|
+
*
|
|
19
|
+
* @stable
|
|
20
|
+
*/
|
|
21
|
+
export interface BeforeStartContext {
|
|
22
|
+
readonly config: ServerConfigSpec;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Snapshot passed to {@link LifecycleHooks.onReady}.
|
|
27
|
+
*
|
|
28
|
+
* @stable
|
|
29
|
+
*/
|
|
30
|
+
export interface OnReadyContext {
|
|
31
|
+
readonly config: ServerConfigSpec;
|
|
32
|
+
readonly listeningOn: { readonly host: string; readonly port: number };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Snapshot passed to {@link LifecycleHooks.beforeShutdown}.
|
|
37
|
+
*
|
|
38
|
+
* @stable
|
|
39
|
+
*/
|
|
40
|
+
export interface BeforeShutdownContext {
|
|
41
|
+
readonly config: ServerConfigSpec;
|
|
42
|
+
readonly inflight: number;
|
|
43
|
+
readonly drainTimeoutMs: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Snapshot passed to {@link LifecycleHooks.onError}. Errors raised
|
|
48
|
+
* outside the request hot path (lifecycle, audit append, etc.) flow
|
|
49
|
+
* here so operators can fan them into Sentry / Datadog / etc.
|
|
50
|
+
*
|
|
51
|
+
* @stable
|
|
52
|
+
*/
|
|
53
|
+
export interface OnErrorContext {
|
|
54
|
+
readonly error: unknown;
|
|
55
|
+
readonly phase: 'beforeStart' | 'onReady' | 'beforeShutdown' | 'request' | 'background';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @stable
|
|
60
|
+
*/
|
|
61
|
+
export interface LifecycleHooks {
|
|
62
|
+
readonly beforeStart?: (ctx: BeforeStartContext) => void | Promise<void>;
|
|
63
|
+
readonly onReady?: (ctx: OnReadyContext) => void | Promise<void>;
|
|
64
|
+
readonly beforeShutdown?: (ctx: BeforeShutdownContext) => void | Promise<void>;
|
|
65
|
+
readonly onError?: (ctx: OnErrorContext) => void | Promise<void>;
|
|
66
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public lifecycle surface for `@graphorin/server`. Re-exports the
|
|
3
|
+
* hook contract + the pre-bind helper so consumers can wire bespoke
|
|
4
|
+
* lifecycles around the standard server.
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export type {
|
|
10
|
+
BeforeShutdownContext,
|
|
11
|
+
BeforeStartContext,
|
|
12
|
+
LifecycleHooks,
|
|
13
|
+
OnErrorContext,
|
|
14
|
+
OnReadyContext,
|
|
15
|
+
} from './hooks.js';
|
|
16
|
+
export { type PreBindResult, type RunPreBindOptions, runPreBind } from './pre-bind.js';
|