@graphorin/server 0.6.0 → 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 +85 -0
- package/README.md +6 -6
- 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 +40 -611
- 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 +9 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -26
- 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 +6 -0
- package/dist/package.js.map +1 -0
- 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.d.ts.map +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 +26 -19
- package/dist/ws/upgrade.js.map +1 -1
- package/package.json +31 -30
- 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,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token-management REST routes. The handlers wrap the
|
|
3
|
+
* `@graphorin/security/auth` CRUD library functions so the operator
|
|
4
|
+
* can mint / list / revoke tokens through the same API surface as
|
|
5
|
+
* `graphorin token` (Phase 15).
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { AuthTokenStore } from '@graphorin/core/contracts';
|
|
11
|
+
import { createToken, listTokens, revokeToken, type SecretValue } from '@graphorin/security';
|
|
12
|
+
import { scopeSetMatches, tryParseScope, validateScopeSet } from '@graphorin/security/auth';
|
|
13
|
+
import type { Context } from 'hono';
|
|
14
|
+
import { Hono } from 'hono';
|
|
15
|
+
import { z } from 'zod';
|
|
16
|
+
|
|
17
|
+
import type { ServerVariables } from '../internal/context.js';
|
|
18
|
+
import { createScopeMiddleware } from '../middleware/scope.js';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @stable
|
|
22
|
+
*/
|
|
23
|
+
export interface TokensRoutesDeps {
|
|
24
|
+
readonly tokenStore: AuthTokenStore;
|
|
25
|
+
readonly pepper: SecretValue;
|
|
26
|
+
readonly defaultEnv: string;
|
|
27
|
+
readonly allowedEnvs: ReadonlyArray<string>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const CreateBodySchema = z
|
|
31
|
+
.object({
|
|
32
|
+
label: z.string().min(1).optional(),
|
|
33
|
+
scopes: z.array(z.string().min(3)).min(1),
|
|
34
|
+
env: z.string().min(1).optional(),
|
|
35
|
+
expiresInMs: z.number().int().positive().optional(),
|
|
36
|
+
})
|
|
37
|
+
.strict();
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @stable
|
|
41
|
+
*/
|
|
42
|
+
export function createTokensRoutes(deps: TokensRoutesDeps): Hono<{ Variables: ServerVariables }> {
|
|
43
|
+
const app = new Hono<{ Variables: ServerVariables }>();
|
|
44
|
+
|
|
45
|
+
app.get('/', createScopeMiddleware('tokens:list'), async (c) => {
|
|
46
|
+
const records = await listTokens(deps.tokenStore);
|
|
47
|
+
// Never reveal hashes or pepper-derived material.
|
|
48
|
+
const sanitized = records.map((r) => ({
|
|
49
|
+
id: r.id,
|
|
50
|
+
label: r.label,
|
|
51
|
+
scopes: r.scopes,
|
|
52
|
+
createdAt: r.createdAt,
|
|
53
|
+
lastUsedAt: r.lastUsedAt,
|
|
54
|
+
expiresAt: r.expiresAt,
|
|
55
|
+
revokedAt: r.revokedAt,
|
|
56
|
+
}));
|
|
57
|
+
return c.json({ tokens: sanitized });
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
app.post('/', createScopeMiddleware('tokens:create'), async (c) => {
|
|
61
|
+
const parsed = CreateBodySchema.safeParse(await safelyParseJson(c));
|
|
62
|
+
if (!parsed.success) {
|
|
63
|
+
return c.json(
|
|
64
|
+
{
|
|
65
|
+
error: 'config-invalid',
|
|
66
|
+
message: 'Invalid create-token body.',
|
|
67
|
+
issues: parsed.error.issues.map((i) => ({ path: i.path, message: i.message })),
|
|
68
|
+
},
|
|
69
|
+
400,
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
const env = parsed.data.env ?? deps.defaultEnv;
|
|
73
|
+
if (!deps.allowedEnvs.includes(env)) {
|
|
74
|
+
return c.json(
|
|
75
|
+
{
|
|
76
|
+
error: 'config-invalid',
|
|
77
|
+
message: `Environment '${env}' is not in the allowed set.`,
|
|
78
|
+
allowed: deps.allowedEnvs,
|
|
79
|
+
},
|
|
80
|
+
400,
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
// W-106: reject syntactically-invalid scopes up front - the old
|
|
84
|
+
// z.string().min(3) accepted garbage that would grant nothing.
|
|
85
|
+
const syntaxErrors = validateScopeSet(parsed.data.scopes);
|
|
86
|
+
if (syntaxErrors.length > 0) {
|
|
87
|
+
return c.json(
|
|
88
|
+
{
|
|
89
|
+
error: 'config-invalid',
|
|
90
|
+
message: 'One or more requested scopes are syntactically invalid.',
|
|
91
|
+
issues: syntaxErrors.map((e) => ({ message: e.message })),
|
|
92
|
+
},
|
|
93
|
+
400,
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
// W-106: attenuation-only minting. A token principal can only mint
|
|
97
|
+
// scopes its OWN grant already covers - `tokens:create` alone must
|
|
98
|
+
// not transitively zero-out the least-privilege catalogue by minting
|
|
99
|
+
// `admin:*`. Delegation chains therefore narrow monotonically (the
|
|
100
|
+
// child's `tokens:create` must itself be covered). The anonymous
|
|
101
|
+
// principal (IP-13 trusted loopback operator, auth disabled) is
|
|
102
|
+
// exempt: it already holds `admin:*`.
|
|
103
|
+
const auth = c.get('state').auth;
|
|
104
|
+
if (auth.kind === 'token') {
|
|
105
|
+
const denied = parsed.data.scopes.filter((requested) => {
|
|
106
|
+
const requestedParsed = tryParseScope(requested);
|
|
107
|
+
if (requestedParsed === undefined) return true;
|
|
108
|
+
return !scopeSetMatches(auth.grantedScopes, requestedParsed);
|
|
109
|
+
});
|
|
110
|
+
if (denied.length > 0) {
|
|
111
|
+
return c.json(
|
|
112
|
+
{
|
|
113
|
+
error: 'scope-escalation-denied',
|
|
114
|
+
message:
|
|
115
|
+
'Attenuation-only minting: a token may only mint scopes covered by its own grant.',
|
|
116
|
+
denied,
|
|
117
|
+
},
|
|
118
|
+
403,
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const created = await createToken({
|
|
123
|
+
tokenStore: deps.tokenStore,
|
|
124
|
+
pepper: deps.pepper,
|
|
125
|
+
env,
|
|
126
|
+
scopes: parsed.data.scopes,
|
|
127
|
+
...(parsed.data.label !== undefined ? { label: parsed.data.label } : {}),
|
|
128
|
+
...(parsed.data.expiresInMs !== undefined ? { expiresInMs: parsed.data.expiresInMs } : {}),
|
|
129
|
+
});
|
|
130
|
+
// Reveal the raw token exactly once - at creation.
|
|
131
|
+
const raw = await created.raw.use((value) => value);
|
|
132
|
+
return c.json(
|
|
133
|
+
{
|
|
134
|
+
token: {
|
|
135
|
+
id: created.record.id,
|
|
136
|
+
label: created.record.label,
|
|
137
|
+
scopes: created.record.scopes,
|
|
138
|
+
createdAt: created.record.createdAt,
|
|
139
|
+
expiresAt: created.record.expiresAt,
|
|
140
|
+
},
|
|
141
|
+
raw,
|
|
142
|
+
warning: 'Store this raw value securely; it is shown exactly once.',
|
|
143
|
+
},
|
|
144
|
+
201,
|
|
145
|
+
);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
app.delete('/:id', createScopeMiddleware('tokens:revoke'), async (c) => {
|
|
149
|
+
const id = c.req.param('id');
|
|
150
|
+
const updated = await revokeToken(deps.tokenStore, id);
|
|
151
|
+
if (updated === undefined) {
|
|
152
|
+
return c.json({ error: 'token-not-found', message: `Token '${id}' not found.` }, 404);
|
|
153
|
+
}
|
|
154
|
+
return c.body(null, 204);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
return app;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async function safelyParseJson(c: Context<{ Variables: ServerVariables }>): Promise<unknown> {
|
|
161
|
+
try {
|
|
162
|
+
return await c.req.json();
|
|
163
|
+
} catch {
|
|
164
|
+
return {};
|
|
165
|
+
}
|
|
166
|
+
}
|