@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.
Files changed (181) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/README.md +3 -3
  3. package/dist/app-audit-binding.d.ts +15 -0
  4. package/dist/app-audit-binding.d.ts.map +1 -0
  5. package/dist/app-audit-binding.js +136 -0
  6. package/dist/app-audit-binding.js.map +1 -0
  7. package/dist/app-daemons.d.ts +29 -0
  8. package/dist/app-daemons.d.ts.map +1 -0
  9. package/dist/app-daemons.js +27 -0
  10. package/dist/app-daemons.js.map +1 -0
  11. package/dist/app-lifecycle.js +272 -0
  12. package/dist/app-lifecycle.js.map +1 -0
  13. package/dist/app-metrics.js +79 -0
  14. package/dist/app-metrics.js.map +1 -0
  15. package/dist/app-middleware.js +92 -0
  16. package/dist/app-middleware.js.map +1 -0
  17. package/dist/app-routes.js +131 -0
  18. package/dist/app-routes.js.map +1 -0
  19. package/dist/app-ws.js +65 -0
  20. package/dist/app-ws.js.map +1 -0
  21. package/dist/app.d.ts +16 -16
  22. package/dist/app.d.ts.map +1 -1
  23. package/dist/app.js +35 -607
  24. package/dist/app.js.map +1 -1
  25. package/dist/commentary/built-in-patterns.d.ts +1 -1
  26. package/dist/commentary/built-in-patterns.js +1 -1
  27. package/dist/commentary/built-in-patterns.js.map +1 -1
  28. package/dist/config.d.ts +100 -1
  29. package/dist/config.d.ts.map +1 -1
  30. package/dist/config.js +30 -2
  31. package/dist/config.js.map +1 -1
  32. package/dist/health/checks.d.ts +15 -1
  33. package/dist/health/checks.d.ts.map +1 -1
  34. package/dist/health/checks.js +21 -0
  35. package/dist/health/checks.js.map +1 -1
  36. package/dist/health/routes.js +1 -1
  37. package/dist/index.d.ts +8 -2
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +19 -24
  40. package/dist/index.js.map +1 -1
  41. package/dist/internal/context.d.ts +2 -2
  42. package/dist/internal/wire-error.js +20 -0
  43. package/dist/internal/wire-error.js.map +1 -0
  44. package/dist/lifecycle/pre-bind.d.ts +1 -1
  45. package/dist/metrics/catalog.d.ts.map +1 -1
  46. package/dist/metrics/catalog.js.map +1 -1
  47. package/dist/metrics/tools-bridge.d.ts +15 -0
  48. package/dist/metrics/tools-bridge.d.ts.map +1 -0
  49. package/dist/metrics/tools-bridge.js +103 -0
  50. package/dist/metrics/tools-bridge.js.map +1 -0
  51. package/dist/middleware/audit.d.ts +1 -1
  52. package/dist/middleware/auth.js +1 -1
  53. package/dist/middleware/csrf.js +1 -1
  54. package/dist/middleware/index.js +1 -1
  55. package/dist/middleware/scope.d.ts.map +1 -1
  56. package/dist/middleware/scope.js +44 -4
  57. package/dist/middleware/scope.js.map +1 -1
  58. package/dist/package.js +1 -1
  59. package/dist/package.js.map +1 -1
  60. package/dist/registry/index.d.ts +33 -0
  61. package/dist/registry/index.d.ts.map +1 -1
  62. package/dist/registry/index.js.map +1 -1
  63. package/dist/replay/routes.d.ts +1 -1
  64. package/dist/replay/routes.js +2 -2
  65. package/dist/routes/agents.d.ts.map +1 -1
  66. package/dist/routes/agents.js +64 -18
  67. package/dist/routes/agents.js.map +1 -1
  68. package/dist/routes/auth.js +2 -2
  69. package/dist/routes/auth.js.map +1 -1
  70. package/dist/routes/sessions.js +5 -5
  71. package/dist/routes/sessions.js.map +1 -1
  72. package/dist/routes/tokens.d.ts +1 -1
  73. package/dist/routes/tokens.d.ts.map +1 -1
  74. package/dist/routes/tokens.js +21 -1
  75. package/dist/routes/tokens.js.map +1 -1
  76. package/dist/routes/workflows.d.ts.map +1 -1
  77. package/dist/routes/workflows.js +165 -19
  78. package/dist/routes/workflows.js.map +1 -1
  79. package/dist/runtime/retention.d.ts +105 -0
  80. package/dist/runtime/retention.d.ts.map +1 -0
  81. package/dist/runtime/retention.js +154 -0
  82. package/dist/runtime/retention.js.map +1 -0
  83. package/dist/runtime/run-state.d.ts +2 -0
  84. package/dist/runtime/run-state.d.ts.map +1 -1
  85. package/dist/runtime/run-state.js +34 -2
  86. package/dist/runtime/run-state.js.map +1 -1
  87. package/dist/sse/events.js +3 -4
  88. package/dist/sse/events.js.map +1 -1
  89. package/dist/tools-audit-bridge.d.ts +29 -0
  90. package/dist/tools-audit-bridge.d.ts.map +1 -0
  91. package/dist/tools-audit-bridge.js +103 -0
  92. package/dist/tools-audit-bridge.js.map +1 -0
  93. package/dist/workflows/timer-daemon.d.ts +69 -0
  94. package/dist/workflows/timer-daemon.d.ts.map +1 -0
  95. package/dist/workflows/timer-daemon.js +37 -0
  96. package/dist/workflows/timer-daemon.js.map +1 -0
  97. package/dist/ws/dispatcher.d.ts +1 -1
  98. package/dist/ws/dispatcher.js +19 -12
  99. package/dist/ws/dispatcher.js.map +1 -1
  100. package/dist/ws/index.d.ts +2 -2
  101. package/dist/ws/index.js +3 -3
  102. package/dist/ws/replay-buffer.d.ts +35 -1
  103. package/dist/ws/replay-buffer.d.ts.map +1 -1
  104. package/dist/ws/replay-buffer.js +35 -3
  105. package/dist/ws/replay-buffer.js.map +1 -1
  106. package/dist/ws/upgrade.d.ts.map +1 -1
  107. package/dist/ws/upgrade.js +24 -18
  108. package/dist/ws/upgrade.js.map +1 -1
  109. package/package.json +30 -29
  110. package/src/app-audit-binding.ts +227 -0
  111. package/src/app-daemons.ts +73 -0
  112. package/src/app-lifecycle.ts +476 -0
  113. package/src/app-metrics.ts +144 -0
  114. package/src/app-middleware.ts +149 -0
  115. package/src/app-routes.ts +305 -0
  116. package/src/app-ws.ts +111 -0
  117. package/src/app.ts +317 -0
  118. package/src/commentary/audit-bridge.ts +135 -0
  119. package/src/commentary/built-in-patterns.ts +79 -0
  120. package/src/commentary/index.ts +32 -0
  121. package/src/commentary/sanitizer.ts +238 -0
  122. package/src/commentary/types.ts +130 -0
  123. package/src/config.ts +472 -0
  124. package/src/consolidator/daemon.ts +141 -0
  125. package/src/consolidator/index.ts +14 -0
  126. package/src/errors/index.ts +247 -0
  127. package/src/health/checks.ts +322 -0
  128. package/src/health/index.ts +34 -0
  129. package/src/health/routes.ts +154 -0
  130. package/src/index.ts +243 -0
  131. package/src/internal/context.ts +77 -0
  132. package/src/internal/ids.ts +17 -0
  133. package/src/internal/json.ts +47 -0
  134. package/src/internal/wire-error.ts +44 -0
  135. package/src/lifecycle/hooks.ts +66 -0
  136. package/src/lifecycle/index.ts +16 -0
  137. package/src/lifecycle/pre-bind.ts +138 -0
  138. package/src/metrics/catalog.ts +112 -0
  139. package/src/metrics/index.ts +12 -0
  140. package/src/metrics/registry.ts +337 -0
  141. package/src/metrics/tools-bridge.ts +124 -0
  142. package/src/middleware/audit.ts +114 -0
  143. package/src/middleware/auth.ts +195 -0
  144. package/src/middleware/cors.ts +72 -0
  145. package/src/middleware/csrf.ts +98 -0
  146. package/src/middleware/idempotency.ts +336 -0
  147. package/src/middleware/index.ts +38 -0
  148. package/src/middleware/rate-limit.ts +71 -0
  149. package/src/middleware/request-state.ts +79 -0
  150. package/src/middleware/scope.ts +161 -0
  151. package/src/registry/index.ts +278 -0
  152. package/src/replay/index.ts +14 -0
  153. package/src/replay/routes.ts +255 -0
  154. package/src/routes/agents.ts +363 -0
  155. package/src/routes/audit.ts +207 -0
  156. package/src/routes/auth.ts +80 -0
  157. package/src/routes/health.ts +42 -0
  158. package/src/routes/index.ts +16 -0
  159. package/src/routes/mcp.ts +97 -0
  160. package/src/routes/memory.ts +152 -0
  161. package/src/routes/sessions.ts +250 -0
  162. package/src/routes/skills.ts +91 -0
  163. package/src/routes/tokens.ts +166 -0
  164. package/src/routes/workflows.ts +616 -0
  165. package/src/runtime/retention.ts +284 -0
  166. package/src/runtime/run-state.ts +422 -0
  167. package/src/sse/events.ts +303 -0
  168. package/src/sse/index.ts +7 -0
  169. package/src/tools-audit-bridge.ts +120 -0
  170. package/src/triggers/daemon.ts +198 -0
  171. package/src/triggers/index.ts +16 -0
  172. package/src/triggers/routes.ts +139 -0
  173. package/src/workflows/timer-daemon.ts +102 -0
  174. package/src/ws/dispatcher.ts +537 -0
  175. package/src/ws/index.ts +45 -0
  176. package/src/ws/replay-buffer.ts +209 -0
  177. package/src/ws/subjects.ts +162 -0
  178. package/src/ws/ticket.ts +174 -0
  179. package/src/ws/upgrade.ts +507 -0
  180. package/dist/lifecycle/index.js +0 -3
  181. 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
+ }