@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,139 @@
1
+ /**
2
+ * REST routes for the `/v1/triggers` family. Mounted by the server
3
+ * factory when a {@link TriggersDaemon} is wired in.
4
+ *
5
+ * GET /triggers (scope `triggers:read`)
6
+ * GET /triggers/:id (scope `triggers:read`)
7
+ * POST /triggers/:id/fire (scope `triggers:fire`)
8
+ * POST /triggers/:id/disable (scope `triggers:disable`) - flag flip
9
+ * POST /triggers/:id/enable (scope `triggers:disable`) - flag flip
10
+ * DELETE /triggers/:id (scope `triggers:disable`) - unregister
11
+ * POST /triggers/prune (scope `triggers:disable`)
12
+ *
13
+ * Response shapes mirror the persisted `TriggerState` rows so CLI +
14
+ * dashboard consumers can render them without re-mapping.
15
+ *
16
+ * @packageDocumentation
17
+ */
18
+
19
+ import type { TriggerState } from '@graphorin/core/contracts';
20
+ import type { Scheduler } from '@graphorin/triggers';
21
+ import { Hono } from 'hono';
22
+
23
+ import type { ServerVariables } from '../internal/context.js';
24
+ import { createScopeMiddleware } from '../middleware/scope.js';
25
+ import type { TriggersDaemon } from './daemon.js';
26
+
27
+ /**
28
+ * @stable
29
+ */
30
+ export interface TriggersRoutesDeps {
31
+ readonly daemon: TriggersDaemon;
32
+ }
33
+
34
+ /**
35
+ * @stable
36
+ */
37
+ export function createTriggersRoutes(
38
+ deps: TriggersRoutesDeps,
39
+ ): Hono<{ Variables: ServerVariables }> {
40
+ const app = new Hono<{ Variables: ServerVariables }>();
41
+ const scheduler: Scheduler = deps.daemon.scheduler;
42
+
43
+ app.get('/', createScopeMiddleware('triggers:read'), async (c) => {
44
+ const all = await scheduler.list();
45
+ return c.json({ triggers: all.map(serializeTrigger) });
46
+ });
47
+
48
+ app.get('/:id', createScopeMiddleware('triggers:read'), async (c) => {
49
+ const id = c.req.param('id');
50
+ const all = await scheduler.list();
51
+ const found = all.find((t) => t.id === id);
52
+ if (found === undefined) {
53
+ return c.json({ error: 'not-found', message: `Trigger '${id}' not found.` }, 404);
54
+ }
55
+ return c.json({ trigger: serializeTrigger(found) });
56
+ });
57
+
58
+ app.post('/:id/fire', createScopeMiddleware('triggers:fire'), async (c) => {
59
+ const id = c.req.param('id');
60
+ try {
61
+ await scheduler.fire(id);
62
+ } catch (err) {
63
+ return c.json(
64
+ {
65
+ error: 'not-found',
66
+ message: err instanceof Error ? err.message : `Trigger '${id}' not found.`,
67
+ },
68
+ 404,
69
+ );
70
+ }
71
+ return c.json({ ok: true, fired: id });
72
+ });
73
+
74
+ // IP-17: disable/enable are non-destructive flag flips on the
75
+ // persistent TriggerState (in agreement with the CLI); the
76
+ // destructive removal is DELETE /:id.
77
+ app.post('/:id/disable', createScopeMiddleware('triggers:disable'), async (c) => {
78
+ const id = c.req.param('id');
79
+ try {
80
+ const updated = await scheduler.setDisabled(id, true);
81
+ return c.json({ ok: true, trigger: serializeTrigger(updated) });
82
+ } catch {
83
+ return c.json({ error: 'not-found', message: `Trigger '${id}' not found.` }, 404);
84
+ }
85
+ });
86
+
87
+ app.post('/:id/enable', createScopeMiddleware('triggers:disable'), async (c) => {
88
+ const id = c.req.param('id');
89
+ try {
90
+ const updated = await scheduler.setDisabled(id, false);
91
+ return c.json({ ok: true, trigger: serializeTrigger(updated) });
92
+ } catch {
93
+ return c.json({ error: 'not-found', message: `Trigger '${id}' not found.` }, 404);
94
+ }
95
+ });
96
+
97
+ app.delete('/:id', createScopeMiddleware('triggers:disable'), async (c) => {
98
+ const id = c.req.param('id');
99
+ const all = await scheduler.list();
100
+ if (!all.some((t) => t.id === id)) {
101
+ return c.json({ error: 'not-found', message: `Trigger '${id}' not found.` }, 404);
102
+ }
103
+ await scheduler.unregister(id);
104
+ return c.json({ ok: true, removed: id });
105
+ });
106
+
107
+ app.post('/prune', createScopeMiddleware('triggers:disable'), async (c) => {
108
+ const all = await scheduler.list();
109
+ const removedIds: string[] = [];
110
+ for (const trigger of all) {
111
+ if (trigger.disabled) {
112
+ await scheduler.unregister(trigger.id);
113
+ removedIds.push(trigger.id);
114
+ }
115
+ }
116
+ return c.json({ ok: true, removed: removedIds, count: removedIds.length });
117
+ });
118
+
119
+ return app;
120
+ }
121
+
122
+ function serializeTrigger(state: TriggerState): Record<string, unknown> {
123
+ return {
124
+ id: state.id,
125
+ kind: state.kind,
126
+ spec: state.spec,
127
+ callbackRef: state.callbackRef,
128
+ ...(state.nextFireAt !== undefined ? { nextFireAt: state.nextFireAt } : {}),
129
+ ...(state.lastFiredAt !== undefined ? { lastFiredAt: state.lastFiredAt } : {}),
130
+ missedFires: state.missedFires,
131
+ disabled: state.disabled,
132
+ catchupPolicy: state.catchupPolicy,
133
+ maxCatchupRuns: state.maxCatchupRuns,
134
+ catchupWindowMs: state.catchupWindowMs,
135
+ ...(state.tags !== undefined ? { tags: [...state.tags] } : {}),
136
+ createdAt: state.createdAt,
137
+ ...(state.updatedAt !== undefined ? { updatedAt: state.updatedAt } : {}),
138
+ };
139
+ }
@@ -0,0 +1,102 @@
1
+ /**
2
+ * W-032: durable-timer driver integration with the server lifecycle.
3
+ *
4
+ * Mirrors the triggers daemon: the operator builds a
5
+ * `createTimerDriver(...)` (from `@graphorin/workflow`) over their
6
+ * workflows + checkpoint stores and hands it to `createServer({
7
+ * workflowTimers: { driver } })`; the daemon binds `start()`/`stop()`
8
+ * to the lifecycle hooks and surfaces `status()` through `/v1/health`.
9
+ * The driver is typed STRUCTURALLY so `@graphorin/server` takes no
10
+ * dependency on `@graphorin/workflow`.
11
+ *
12
+ * @packageDocumentation
13
+ */
14
+
15
+ /**
16
+ * Structural slice of `@graphorin/workflow`'s `TimerDriver` the daemon
17
+ * consumes.
18
+ *
19
+ * @stable
20
+ */
21
+ export interface WorkflowTimerDriverLike {
22
+ start(): void;
23
+ stop(): void;
24
+ status(): {
25
+ readonly running: boolean;
26
+ readonly sweeps: number;
27
+ readonly fired: number;
28
+ readonly errors: number;
29
+ readonly lastSweepAt?: number;
30
+ readonly nextWakeAt?: number;
31
+ };
32
+ sweep(): Promise<number>;
33
+ }
34
+
35
+ /**
36
+ * Snapshot exposed via {@link WorkflowTimerDaemon.status} + the
37
+ * `/v1/health` aggregator.
38
+ *
39
+ * @stable
40
+ */
41
+ export interface WorkflowTimerDaemonStatus {
42
+ readonly running: boolean;
43
+ readonly sweeps: number;
44
+ readonly fired: number;
45
+ readonly errors: number;
46
+ readonly lastSweepAt?: string;
47
+ readonly nextWakeAt?: string;
48
+ }
49
+
50
+ /** @stable */
51
+ export interface CreateWorkflowTimerDaemonOptions {
52
+ readonly driver: WorkflowTimerDriverLike;
53
+ }
54
+
55
+ /**
56
+ * Stateful handle returned by {@link createWorkflowTimerDaemon}.
57
+ *
58
+ * @stable
59
+ */
60
+ export interface WorkflowTimerDaemon {
61
+ start(): Promise<void>;
62
+ stop(): Promise<void>;
63
+ status(): Promise<WorkflowTimerDaemonStatus>;
64
+ readonly driver: WorkflowTimerDriverLike;
65
+ }
66
+
67
+ /**
68
+ * @stable
69
+ */
70
+ export function createWorkflowTimerDaemon(
71
+ options: CreateWorkflowTimerDaemonOptions,
72
+ ): WorkflowTimerDaemon {
73
+ let running = false;
74
+ return {
75
+ get driver() {
76
+ return options.driver;
77
+ },
78
+ async start() {
79
+ if (running) return;
80
+ running = true;
81
+ options.driver.start();
82
+ },
83
+ async stop() {
84
+ if (!running) return;
85
+ running = false;
86
+ options.driver.stop();
87
+ },
88
+ async status() {
89
+ const s = options.driver.status();
90
+ return Object.freeze({
91
+ running: s.running,
92
+ sweeps: s.sweeps,
93
+ fired: s.fired,
94
+ errors: s.errors,
95
+ ...(s.lastSweepAt !== undefined
96
+ ? { lastSweepAt: new Date(s.lastSweepAt).toISOString() }
97
+ : {}),
98
+ ...(s.nextWakeAt !== undefined ? { nextWakeAt: new Date(s.nextWakeAt).toISOString() } : {}),
99
+ });
100
+ },
101
+ };
102
+ }