@data-club/ai-hub-server 0.0.1
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/dist/auth/argon2.d.ts +72 -0
- package/dist/auth/argon2.d.ts.map +1 -0
- package/dist/auth/argon2.js +145 -0
- package/dist/auth/argon2.js.map +1 -0
- package/dist/auth/encryption.d.ts +52 -0
- package/dist/auth/encryption.d.ts.map +1 -0
- package/dist/auth/encryption.js +98 -0
- package/dist/auth/encryption.js.map +1 -0
- package/dist/auth/jwt.d.ts +133 -0
- package/dist/auth/jwt.d.ts.map +1 -0
- package/dist/auth/jwt.js +147 -0
- package/dist/auth/jwt.js.map +1 -0
- package/dist/auth/middleware.d.ts +101 -0
- package/dist/auth/middleware.d.ts.map +1 -0
- package/dist/auth/middleware.js +161 -0
- package/dist/auth/middleware.js.map +1 -0
- package/dist/auth/passwordPolicy.d.ts +72 -0
- package/dist/auth/passwordPolicy.d.ts.map +1 -0
- package/dist/auth/passwordPolicy.js +88 -0
- package/dist/auth/passwordPolicy.js.map +1 -0
- package/dist/auth/roleRules.d.ts +200 -0
- package/dist/auth/roleRules.d.ts.map +1 -0
- package/dist/auth/roleRules.js +365 -0
- package/dist/auth/roleRules.js.map +1 -0
- package/dist/auth/userView.d.ts +55 -0
- package/dist/auth/userView.d.ts.map +1 -0
- package/dist/auth/userView.js +77 -0
- package/dist/auth/userView.js.map +1 -0
- package/dist/bootstrap.d.ts +104 -0
- package/dist/bootstrap.d.ts.map +1 -0
- package/dist/bootstrap.js +160 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/db/connection.d.ts +39 -0
- package/dist/db/connection.d.ts.map +1 -0
- package/dist/db/connection.js +62 -0
- package/dist/db/connection.js.map +1 -0
- package/dist/db/migrate.d.ts +31 -0
- package/dist/db/migrate.d.ts.map +1 -0
- package/dist/db/migrate.js +197 -0
- package/dist/db/migrate.js.map +1 -0
- package/dist/db/schema.d.ts +1902 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +662 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/db/seed.d.ts +92 -0
- package/dist/db/seed.d.ts.map +1 -0
- package/dist/db/seed.js +160 -0
- package/dist/db/seed.js.map +1 -0
- package/dist/handlers/fetch.d.ts +89 -0
- package/dist/handlers/fetch.d.ts.map +1 -0
- package/dist/handlers/fetch.js +173 -0
- package/dist/handlers/fetch.js.map +1 -0
- package/dist/handlers/nextjs.d.ts +40 -0
- package/dist/handlers/nextjs.d.ts.map +1 -0
- package/dist/handlers/nextjs.js +42 -0
- package/dist/handlers/nextjs.js.map +1 -0
- package/dist/handlers/responses.d.ts +46 -0
- package/dist/handlers/responses.d.ts.map +1 -0
- package/dist/handlers/responses.js +74 -0
- package/dist/handlers/responses.js.map +1 -0
- package/dist/handlers/routeTable.d.ts +21 -0
- package/dist/handlers/routeTable.d.ts.map +1 -0
- package/dist/handlers/routeTable.js +133 -0
- package/dist/handlers/routeTable.js.map +1 -0
- package/dist/handlers/router.d.ts +37 -0
- package/dist/handlers/router.d.ts.map +1 -0
- package/dist/handlers/router.js +82 -0
- package/dist/handlers/router.js.map +1 -0
- package/dist/handlers/sse.d.ts +38 -0
- package/dist/handlers/sse.d.ts.map +1 -0
- package/dist/handlers/sse.js +52 -0
- package/dist/handlers/sse.js.map +1 -0
- package/dist/handlers/types.d.ts +96 -0
- package/dist/handlers/types.d.ts.map +1 -0
- package/dist/handlers/types.js +14 -0
- package/dist/handlers/types.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/letta/client.d.ts +355 -0
- package/dist/letta/client.d.ts.map +1 -0
- package/dist/letta/client.js +529 -0
- package/dist/letta/client.js.map +1 -0
- package/dist/letta/eventTranslator.d.ts +166 -0
- package/dist/letta/eventTranslator.d.ts.map +1 -0
- package/dist/letta/eventTranslator.js +532 -0
- package/dist/letta/eventTranslator.js.map +1 -0
- package/dist/letta/index.d.ts +13 -0
- package/dist/letta/index.d.ts.map +1 -0
- package/dist/letta/index.js +12 -0
- package/dist/letta/index.js.map +1 -0
- package/dist/letta/modelSettings.d.ts +176 -0
- package/dist/letta/modelSettings.d.ts.map +1 -0
- package/dist/letta/modelSettings.js +314 -0
- package/dist/letta/modelSettings.js.map +1 -0
- package/dist/letta/promptWrapping.d.ts +141 -0
- package/dist/letta/promptWrapping.d.ts.map +1 -0
- package/dist/letta/promptWrapping.js +213 -0
- package/dist/letta/promptWrapping.js.map +1 -0
- package/dist/letta/sandbox.d.ts +100 -0
- package/dist/letta/sandbox.d.ts.map +1 -0
- package/dist/letta/sandbox.js +151 -0
- package/dist/letta/sandbox.js.map +1 -0
- package/dist/letta/settingsFileSeed.d.ts +146 -0
- package/dist/letta/settingsFileSeed.d.ts.map +1 -0
- package/dist/letta/settingsFileSeed.js +177 -0
- package/dist/letta/settingsFileSeed.js.map +1 -0
- package/dist/letta/subprocessThrottle.d.ts +151 -0
- package/dist/letta/subprocessThrottle.d.ts.map +1 -0
- package/dist/letta/subprocessThrottle.js +195 -0
- package/dist/letta/subprocessThrottle.js.map +1 -0
- package/dist/letta/tpmRecovery.d.ts +202 -0
- package/dist/letta/tpmRecovery.d.ts.map +1 -0
- package/dist/letta/tpmRecovery.js +314 -0
- package/dist/letta/tpmRecovery.js.map +1 -0
- package/dist/letta/types.d.ts +54 -0
- package/dist/letta/types.d.ts.map +1 -0
- package/dist/letta/types.js +16 -0
- package/dist/letta/types.js.map +1 -0
- package/dist/observability/logger.d.ts +48 -0
- package/dist/observability/logger.d.ts.map +1 -0
- package/dist/observability/logger.js +81 -0
- package/dist/observability/logger.js.map +1 -0
- package/dist/observability/metrics.d.ts +53 -0
- package/dist/observability/metrics.d.ts.map +1 -0
- package/dist/observability/metrics.js +92 -0
- package/dist/observability/metrics.js.map +1 -0
- package/dist/routes/admin/agents.d.ts +63 -0
- package/dist/routes/admin/agents.d.ts.map +1 -0
- package/dist/routes/admin/agents.js +461 -0
- package/dist/routes/admin/agents.js.map +1 -0
- package/dist/routes/admin/rotatingMessages.d.ts +51 -0
- package/dist/routes/admin/rotatingMessages.d.ts.map +1 -0
- package/dist/routes/admin/rotatingMessages.js +292 -0
- package/dist/routes/admin/rotatingMessages.js.map +1 -0
- package/dist/routes/admin/sessions.d.ts +61 -0
- package/dist/routes/admin/sessions.d.ts.map +1 -0
- package/dist/routes/admin/sessions.js +232 -0
- package/dist/routes/admin/sessions.js.map +1 -0
- package/dist/routes/admin/settings.d.ts +110 -0
- package/dist/routes/admin/settings.d.ts.map +1 -0
- package/dist/routes/admin/settings.js +401 -0
- package/dist/routes/admin/settings.js.map +1 -0
- package/dist/routes/admin/users.d.ts +115 -0
- package/dist/routes/admin/users.d.ts.map +1 -0
- package/dist/routes/admin/users.js +374 -0
- package/dist/routes/admin/users.js.map +1 -0
- package/dist/routes/agents.d.ts +30 -0
- package/dist/routes/agents.d.ts.map +1 -0
- package/dist/routes/agents.js +55 -0
- package/dist/routes/agents.js.map +1 -0
- package/dist/routes/auth.d.ts +121 -0
- package/dist/routes/auth.d.ts.map +1 -0
- package/dist/routes/auth.js +422 -0
- package/dist/routes/auth.js.map +1 -0
- package/dist/routes/chat.d.ts +97 -0
- package/dist/routes/chat.d.ts.map +1 -0
- package/dist/routes/chat.js +484 -0
- package/dist/routes/chat.js.map +1 -0
- package/dist/routes/featureToggles.d.ts +34 -0
- package/dist/routes/featureToggles.d.ts.map +1 -0
- package/dist/routes/featureToggles.js +47 -0
- package/dist/routes/featureToggles.js.map +1 -0
- package/dist/routes/health.d.ts +24 -0
- package/dist/routes/health.d.ts.map +1 -0
- package/dist/routes/health.js +37 -0
- package/dist/routes/health.js.map +1 -0
- package/dist/routes/metrics.d.ts +35 -0
- package/dist/routes/metrics.d.ts.map +1 -0
- package/dist/routes/metrics.js +106 -0
- package/dist/routes/metrics.js.map +1 -0
- package/dist/routes/sessions.d.ts +161 -0
- package/dist/routes/sessions.d.ts.map +1 -0
- package/dist/routes/sessions.js +1501 -0
- package/dist/routes/sessions.js.map +1 -0
- package/dist/routes/stubs.d.ts +25 -0
- package/dist/routes/stubs.d.ts.map +1 -0
- package/dist/routes/stubs.js +25 -0
- package/dist/routes/stubs.js.map +1 -0
- package/dist/state/cron.d.ts +58 -0
- package/dist/state/cron.d.ts.map +1 -0
- package/dist/state/cron.js +160 -0
- package/dist/state/cron.js.map +1 -0
- package/dist/state/rotationRunner.d.ts +96 -0
- package/dist/state/rotationRunner.d.ts.map +1 -0
- package/dist/state/rotationRunner.js +246 -0
- package/dist/state/rotationRunner.js.map +1 -0
- package/dist/state/rotationScheduler.d.ts +76 -0
- package/dist/state/rotationScheduler.d.ts.map +1 -0
- package/dist/state/rotationScheduler.js +124 -0
- package/dist/state/rotationScheduler.js.map +1 -0
- package/dist/state/turnRegistry.d.ts +95 -0
- package/dist/state/turnRegistry.d.ts.map +1 -0
- package/dist/state/turnRegistry.js +149 -0
- package/dist/state/turnRegistry.js.map +1 -0
- package/dist/state/turnRunner.d.ts +134 -0
- package/dist/state/turnRunner.d.ts.map +1 -0
- package/dist/state/turnRunner.js +476 -0
- package/dist/state/turnRunner.js.map +1 -0
- package/package.json +47 -0
- package/src/auth/argon2.ts +152 -0
- package/src/auth/encryption.ts +110 -0
- package/src/auth/jwt.ts +217 -0
- package/src/auth/middleware.ts +250 -0
- package/src/auth/passwordPolicy.ts +99 -0
- package/src/auth/roleRules.ts +497 -0
- package/src/auth/userView.ts +88 -0
- package/src/bootstrap.ts +254 -0
- package/src/db/connection.ts +75 -0
- package/src/db/migrate.ts +212 -0
- package/src/db/schema.ts +750 -0
- package/src/db/seed.ts +236 -0
- package/src/handlers/fetch.ts +251 -0
- package/src/handlers/nextjs.ts +49 -0
- package/src/handlers/responses.ts +95 -0
- package/src/handlers/routeTable.ts +188 -0
- package/src/handlers/router.ts +96 -0
- package/src/handlers/sse.ts +55 -0
- package/src/handlers/types.ts +104 -0
- package/src/index.ts +60 -0
- package/src/letta/client.ts +860 -0
- package/src/letta/eventTranslator.ts +667 -0
- package/src/letta/index.ts +46 -0
- package/src/letta/lettaCliShim.mjs +40 -0
- package/src/letta/sandbox.ts +167 -0
- package/src/letta/settingsFileSeed.ts +254 -0
- package/src/letta/subprocessThrottle.ts +251 -0
- package/src/letta/types.ts +65 -0
- package/src/observability/logger.ts +103 -0
- package/src/observability/metrics.ts +114 -0
- package/src/routes/admin/agents.ts +574 -0
- package/src/routes/admin/rotatingMessages.ts +351 -0
- package/src/routes/admin/sessions.ts +283 -0
- package/src/routes/admin/settings.ts +463 -0
- package/src/routes/admin/users.ts +455 -0
- package/src/routes/agents.ts +66 -0
- package/src/routes/auth.ts +513 -0
- package/src/routes/chat.ts +534 -0
- package/src/routes/featureToggles.ts +52 -0
- package/src/routes/health.ts +44 -0
- package/src/routes/metrics.ts +111 -0
- package/src/routes/sessions.ts +1878 -0
- package/src/state/cron.ts +179 -0
- package/src/state/rotationRunner.ts +326 -0
- package/src/state/rotationScheduler.ts +164 -0
- package/src/state/turnRegistry.ts +210 -0
- package/src/state/turnRunner.ts +588 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical route table.
|
|
3
|
+
*
|
|
4
|
+
* Order matters — the matcher walks top-to-bottom and returns the first
|
|
5
|
+
* pattern that matches. Concrete paths come before any future wildcards.
|
|
6
|
+
*
|
|
7
|
+
* Entries are paired with the step that wires the real handler. After Step 5
|
|
8
|
+
* every endpoint is real; no stubs remain.
|
|
9
|
+
*
|
|
10
|
+
* @see SPECIFICATIONS.md §6.3 — API surface
|
|
11
|
+
* @see docs/IMPLEMENTATION_PLAN.md — per-endpoint step assignment
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { handleListAgents as handleListAgentsUser } from "../routes/agents.js";
|
|
15
|
+
import { handleGetPublicFeatureToggles } from "../routes/featureToggles.js";
|
|
16
|
+
import {
|
|
17
|
+
handleCreateAgent,
|
|
18
|
+
handleListAgents as handleListAgentsAdmin,
|
|
19
|
+
handlePatchAgent,
|
|
20
|
+
} from "../routes/admin/agents.js";
|
|
21
|
+
import {
|
|
22
|
+
handleListSessionsOverview,
|
|
23
|
+
handlePurgeAdminSessionSandbox,
|
|
24
|
+
} from "../routes/admin/sessions.js";
|
|
25
|
+
import {
|
|
26
|
+
handleCreateRotatingMessage,
|
|
27
|
+
handleListRotatingMessages,
|
|
28
|
+
handlePatchRotatingMessage,
|
|
29
|
+
handleRotateRotatingMessageNow,
|
|
30
|
+
} from "../routes/admin/rotatingMessages.js";
|
|
31
|
+
import {
|
|
32
|
+
handleGetFeatureToggles,
|
|
33
|
+
handleGetSettings,
|
|
34
|
+
handlePatchFeatureToggles,
|
|
35
|
+
handlePatchSettings,
|
|
36
|
+
handleRotateMetricsToken,
|
|
37
|
+
handleRotateSigningKey,
|
|
38
|
+
} from "../routes/admin/settings.js";
|
|
39
|
+
import {
|
|
40
|
+
handleCreateUser,
|
|
41
|
+
handleDeleteUser,
|
|
42
|
+
handleListUsers,
|
|
43
|
+
handlePatchUserRole,
|
|
44
|
+
handleResetUserPassword,
|
|
45
|
+
} from "../routes/admin/users.js";
|
|
46
|
+
import {
|
|
47
|
+
handleChangePassword,
|
|
48
|
+
handleLogin,
|
|
49
|
+
handleLogout,
|
|
50
|
+
handleMe,
|
|
51
|
+
handleMePreferences,
|
|
52
|
+
} from "../routes/auth.js";
|
|
53
|
+
import { handleHealth, handleHealthReady } from "../routes/health.js";
|
|
54
|
+
import { handleMetrics } from "../routes/metrics.js";
|
|
55
|
+
import {
|
|
56
|
+
handleGetChatEvents,
|
|
57
|
+
handlePostChat,
|
|
58
|
+
handlePostChatCancel,
|
|
59
|
+
} from "../routes/chat.js";
|
|
60
|
+
import {
|
|
61
|
+
handleAdminGetSessionMessages,
|
|
62
|
+
handleCreateSession,
|
|
63
|
+
handleDeleteMessageOverride,
|
|
64
|
+
handleGetSession,
|
|
65
|
+
handleGetSessionMessages,
|
|
66
|
+
handleListMessageOverrides,
|
|
67
|
+
handleListSessions,
|
|
68
|
+
handlePatchSession,
|
|
69
|
+
handlePatchSessionReasoning,
|
|
70
|
+
handlePutMessageOverride,
|
|
71
|
+
} from "../routes/sessions.js";
|
|
72
|
+
|
|
73
|
+
import type { RouteEntry } from "./types.js";
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Reads as the canonical Step-5 surface in one place. Step 6 adds no new
|
|
77
|
+
* routes — it extends the chat path with TPM-recovery internals.
|
|
78
|
+
*
|
|
79
|
+
* @returns the immutable route table.
|
|
80
|
+
*/
|
|
81
|
+
export function buildRouteTable(): ReadonlyArray<RouteEntry> {
|
|
82
|
+
return [
|
|
83
|
+
// Health probes — public.
|
|
84
|
+
{ method: "GET", path: "/health", handler: handleHealth },
|
|
85
|
+
{ method: "GET", path: "/health/ready", handler: handleHealthReady },
|
|
86
|
+
|
|
87
|
+
// Auth — full surface after Step 3.
|
|
88
|
+
{ method: "POST", path: "/auth/login", handler: handleLogin },
|
|
89
|
+
{ method: "POST", path: "/auth/change-password", handler: handleChangePassword },
|
|
90
|
+
{ method: "POST", path: "/auth/logout", handler: handleLogout },
|
|
91
|
+
{ method: "GET", path: "/auth/me", handler: handleMe },
|
|
92
|
+
{ method: "PATCH", path: "/auth/me/preferences", handler: handleMePreferences },
|
|
93
|
+
|
|
94
|
+
// Public — Step 10 (deployment-wide UI feature toggles per §8.4).
|
|
95
|
+
{ method: "GET", path: "/feature-toggles", handler: handleGetPublicFeatureToggles },
|
|
96
|
+
|
|
97
|
+
// User-facing — Step 4.
|
|
98
|
+
{ method: "GET", path: "/agents", handler: handleListAgentsUser },
|
|
99
|
+
{ method: "GET", path: "/sessions", handler: handleListSessions },
|
|
100
|
+
{ method: "POST", path: "/sessions", handler: handleCreateSession },
|
|
101
|
+
{ method: "GET", path: "/sessions/:id", handler: handleGetSession },
|
|
102
|
+
{ method: "PATCH", path: "/sessions/:id", handler: handlePatchSession },
|
|
103
|
+
{
|
|
104
|
+
method: "PATCH",
|
|
105
|
+
path: "/sessions/:id/reasoning",
|
|
106
|
+
handler: handlePatchSessionReasoning,
|
|
107
|
+
},
|
|
108
|
+
{ method: "GET", path: "/sessions/:id/messages", handler: handleGetSessionMessages },
|
|
109
|
+
{
|
|
110
|
+
method: "GET",
|
|
111
|
+
path: "/sessions/:id/message-overrides",
|
|
112
|
+
handler: handleListMessageOverrides,
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
method: "PUT",
|
|
116
|
+
path: "/sessions/:id/message-overrides/:position",
|
|
117
|
+
handler: handlePutMessageOverride,
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
method: "DELETE",
|
|
121
|
+
path: "/sessions/:id/message-overrides/:position",
|
|
122
|
+
handler: handleDeleteMessageOverride,
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
// Chat — Step 5 (SSE wire protocol per §9).
|
|
126
|
+
{ method: "POST", path: "/chat", handler: handlePostChat },
|
|
127
|
+
{ method: "GET", path: "/chat/:turn_id/events", handler: handleGetChatEvents },
|
|
128
|
+
{ method: "POST", path: "/chat/:turn_id/cancel", handler: handlePostChatCancel },
|
|
129
|
+
|
|
130
|
+
// Admin — Step 4.
|
|
131
|
+
{ method: "GET", path: "/admin/users", handler: handleListUsers },
|
|
132
|
+
{ method: "POST", path: "/admin/users", handler: handleCreateUser },
|
|
133
|
+
{ method: "PATCH", path: "/admin/users/:id/role", handler: handlePatchUserRole },
|
|
134
|
+
{ method: "POST", path: "/admin/users/:id/reset-password", handler: handleResetUserPassword },
|
|
135
|
+
{ method: "DELETE", path: "/admin/users/:id", handler: handleDeleteUser },
|
|
136
|
+
{ method: "GET", path: "/admin/agents", handler: handleListAgentsAdmin },
|
|
137
|
+
{ method: "POST", path: "/admin/agents", handler: handleCreateAgent },
|
|
138
|
+
{ method: "PATCH", path: "/admin/agents/:id", handler: handlePatchAgent },
|
|
139
|
+
{
|
|
140
|
+
method: "GET",
|
|
141
|
+
path: "/admin/rotating-messages",
|
|
142
|
+
handler: handleListRotatingMessages,
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
method: "POST",
|
|
146
|
+
path: "/admin/rotating-messages",
|
|
147
|
+
handler: handleCreateRotatingMessage,
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
method: "PATCH",
|
|
151
|
+
path: "/admin/rotating-messages/:id",
|
|
152
|
+
handler: handlePatchRotatingMessage,
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
method: "POST",
|
|
156
|
+
path: "/admin/rotating-messages/:id/rotate-now",
|
|
157
|
+
handler: handleRotateRotatingMessageNow,
|
|
158
|
+
},
|
|
159
|
+
{ method: "GET", path: "/admin/sessions", handler: handleListSessionsOverview },
|
|
160
|
+
{
|
|
161
|
+
method: "GET",
|
|
162
|
+
path: "/admin/sessions/:id/messages",
|
|
163
|
+
handler: handleAdminGetSessionMessages,
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
method: "POST",
|
|
167
|
+
path: "/admin/sessions/:id/purge-sandbox",
|
|
168
|
+
handler: handlePurgeAdminSessionSandbox,
|
|
169
|
+
},
|
|
170
|
+
{ method: "GET", path: "/admin/settings", handler: handleGetSettings },
|
|
171
|
+
{ method: "PATCH", path: "/admin/settings", handler: handlePatchSettings },
|
|
172
|
+
{ method: "GET", path: "/admin/settings/feature-toggles", handler: handleGetFeatureToggles },
|
|
173
|
+
{ method: "PATCH", path: "/admin/settings/feature-toggles", handler: handlePatchFeatureToggles },
|
|
174
|
+
{
|
|
175
|
+
method: "POST",
|
|
176
|
+
path: "/admin/settings/rotate-signing-key",
|
|
177
|
+
handler: handleRotateSigningKey,
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
method: "POST",
|
|
181
|
+
path: "/admin/settings/rotate-metrics-token",
|
|
182
|
+
handler: handleRotateMetricsToken,
|
|
183
|
+
},
|
|
184
|
+
|
|
185
|
+
// Metrics — Step 4 (bearer-token-gated, no JWT).
|
|
186
|
+
{ method: "GET", path: "/metrics", handler: handleMetrics },
|
|
187
|
+
];
|
|
188
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tiny path + method matcher.
|
|
3
|
+
*
|
|
4
|
+
* Lives in-package — we explicitly do NOT depend on Hono / Express /
|
|
5
|
+
* Fastify (§6.2). The route table is flat, the patterns are simple, and a
|
|
6
|
+
* 50-line matcher beats a 500 KB framework runtime that brings its own
|
|
7
|
+
* plugin ecosystem we wouldn't use.
|
|
8
|
+
*
|
|
9
|
+
* Pattern syntax: `/sessions/:id` matches `/sessions/abc` and exposes
|
|
10
|
+
* `{ id: "abc" }` as the parameter map. The matcher does not support globs
|
|
11
|
+
* or regex — every spec'd route is a plain segment-by-segment match.
|
|
12
|
+
*
|
|
13
|
+
* The `*` method is the wildcard used by `OPTIONS` preflight handlers and
|
|
14
|
+
* the catch-all 404. First-registered-first-matched, so wildcards always go
|
|
15
|
+
* at the bottom of the table.
|
|
16
|
+
*
|
|
17
|
+
* @see SPECIFICATIONS.md §6.2 — stack (no framework runtime)
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import type { RouteEntry } from "./types.js";
|
|
21
|
+
|
|
22
|
+
/** A successful match's output. */
|
|
23
|
+
export interface MatchResult {
|
|
24
|
+
/** The handler to invoke. */
|
|
25
|
+
entry: RouteEntry;
|
|
26
|
+
/** Path-parameter map (e.g. `{ id: "abc" }`). */
|
|
27
|
+
params: Record<string, string>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Walks `entries` in order and returns the first one whose method + path
|
|
32
|
+
* pattern match `method` and `pathname`. Returns `null` if nothing matches.
|
|
33
|
+
*
|
|
34
|
+
* @param entries - the route table.
|
|
35
|
+
* @param method - request method (uppercased).
|
|
36
|
+
* @param pathname - request path with the basePath already stripped.
|
|
37
|
+
* @returns the matched entry + params, or `null`.
|
|
38
|
+
*/
|
|
39
|
+
export function matchRoute(
|
|
40
|
+
entries: ReadonlyArray<RouteEntry>,
|
|
41
|
+
method: string,
|
|
42
|
+
pathname: string,
|
|
43
|
+
): MatchResult | null {
|
|
44
|
+
for (const entry of entries) {
|
|
45
|
+
if (entry.method !== "*" && entry.method !== method) continue;
|
|
46
|
+
const params = matchPath(entry.path, pathname);
|
|
47
|
+
if (params) return { entry, params };
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Compares a path template (with `:param` placeholders) against an actual
|
|
54
|
+
* pathname. Returns the parameter map on a match, `null` otherwise.
|
|
55
|
+
*
|
|
56
|
+
* Trailing slashes are tolerated — `/foo/` matches `/foo`.
|
|
57
|
+
*
|
|
58
|
+
* @param template - the route template (e.g. `/sessions/:id`).
|
|
59
|
+
* @param pathname - the actual path being matched.
|
|
60
|
+
* @returns parameter map on a match, else `null`.
|
|
61
|
+
*/
|
|
62
|
+
function matchPath(
|
|
63
|
+
template: string,
|
|
64
|
+
pathname: string,
|
|
65
|
+
): Record<string, string> | null {
|
|
66
|
+
const tplParts = trimSlashes(template).split("/");
|
|
67
|
+
const pathParts = trimSlashes(pathname).split("/");
|
|
68
|
+
if (tplParts.length !== pathParts.length) return null;
|
|
69
|
+
|
|
70
|
+
const params: Record<string, string> = {};
|
|
71
|
+
for (let i = 0; i < tplParts.length; i++) {
|
|
72
|
+
const tp = tplParts[i] as string;
|
|
73
|
+
const pp = pathParts[i] as string;
|
|
74
|
+
if (tp.startsWith(":")) {
|
|
75
|
+
const name = tp.slice(1);
|
|
76
|
+
params[name] = decodeURIComponent(pp);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (tp !== pp) return null;
|
|
80
|
+
}
|
|
81
|
+
return params;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Trims a single leading and trailing `/` so `split("/")` yields the same
|
|
86
|
+
* segment count regardless of slash style.
|
|
87
|
+
*
|
|
88
|
+
* @param s - the path or template string.
|
|
89
|
+
* @returns the input with one leading/trailing slash removed.
|
|
90
|
+
*/
|
|
91
|
+
function trimSlashes(s: string): string {
|
|
92
|
+
let out = s;
|
|
93
|
+
if (out.startsWith("/")) out = out.slice(1);
|
|
94
|
+
if (out.endsWith("/")) out = out.slice(0, -1);
|
|
95
|
+
return out;
|
|
96
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Small SSE writer helpers.
|
|
3
|
+
*
|
|
4
|
+
* The chat handler builds a `ReadableStream` of bytes and pipes named
|
|
5
|
+
* events into it. This file holds the encoding (utf-8 + `event:`/`data:`
|
|
6
|
+
* lines) and a `formatSseEvent` helper so the writer stays in one place.
|
|
7
|
+
*
|
|
8
|
+
* @see SPECIFICATIONS.md §9.5 — why SSE (not EventSource)
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { AIHubEvent } from "@data-club/ai-hub";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Formats one ai-hub event into the byte payload an SSE client expects.
|
|
15
|
+
*
|
|
16
|
+
* Format per the W3C EventSource spec:
|
|
17
|
+
*
|
|
18
|
+
* ```
|
|
19
|
+
* event: <event-name>
|
|
20
|
+
* data: <json-payload>
|
|
21
|
+
*
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* The blank line separator is required. Multi-line payloads get one
|
|
25
|
+
* `data:` line per newline; we shouldn't see any in practice (the events
|
|
26
|
+
* we emit are flat JSON), but the helper handles it defensively.
|
|
27
|
+
*
|
|
28
|
+
* @param event - the ai-hub event.
|
|
29
|
+
* @returns the SSE-formatted bytes.
|
|
30
|
+
*/
|
|
31
|
+
export function formatSseEvent(event: AIHubEvent): Uint8Array {
|
|
32
|
+
// `heartbeat` events carry no `data` per the wire-protocol union — for
|
|
33
|
+
// every other variant `data` is present. We pull it out with a narrowing
|
|
34
|
+
// `in` check so we don't include `data: undefined` in the wire payload
|
|
35
|
+
// when there's nothing to send.
|
|
36
|
+
const payload = JSON.stringify({
|
|
37
|
+
seq: event.seq,
|
|
38
|
+
...("data" in event ? { data: event.data } : {}),
|
|
39
|
+
state: event.state,
|
|
40
|
+
});
|
|
41
|
+
const dataLines = payload.split("\n").map((l) => `data: ${l}`).join("\n");
|
|
42
|
+
const text = `event: ${event.event}\n${dataLines}\n\n`;
|
|
43
|
+
return new TextEncoder().encode(text);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Formats a plain SSE comment-line (used for heartbeats). Browsers and
|
|
48
|
+
* proxies treat any line starting with `:` as a comment — keeps the
|
|
49
|
+
* connection alive without delivering an event to the consumer.
|
|
50
|
+
*
|
|
51
|
+
* @returns the bytes of a `:hb\n\n` heartbeat.
|
|
52
|
+
*/
|
|
53
|
+
export function formatSseHeartbeat(): Uint8Array {
|
|
54
|
+
return new TextEncoder().encode(":hb\n\n");
|
|
55
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for the Fetch routing core.
|
|
3
|
+
*
|
|
4
|
+
* `AIHubServerContext` is the per-server-instance bundle: DB, logger, parsed
|
|
5
|
+
* encryption key, route prefix. Subsequent steps extend it (Letta client,
|
|
6
|
+
* mock-Letta toggle, etc.) — additions are additive.
|
|
7
|
+
*
|
|
8
|
+
* Handlers are Web-Standard `(Request, ctx) => Promise<Response>` per §6.2.
|
|
9
|
+
* No framework runtime, no plugin ecosystem.
|
|
10
|
+
*
|
|
11
|
+
* @see SPECIFICATIONS.md §6.2 — stack
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type Database from "better-sqlite3";
|
|
15
|
+
|
|
16
|
+
import type { DrizzleDB } from "../db/connection.js";
|
|
17
|
+
import type { LettaClient } from "../letta/client.js";
|
|
18
|
+
import type { SubprocessThrottle } from "../letta/subprocessThrottle.js";
|
|
19
|
+
import type { Logger } from "../observability/logger.js";
|
|
20
|
+
|
|
21
|
+
/** Per-server-instance context wired by `createFetchHandler`. */
|
|
22
|
+
export interface AIHubServerContext {
|
|
23
|
+
/** Drizzle client typed against the schema — call this for typed queries. */
|
|
24
|
+
db: DrizzleDB;
|
|
25
|
+
/** Raw better-sqlite3 handle — used only for `transaction()` + low-level ops. */
|
|
26
|
+
sqlite: Database.Database;
|
|
27
|
+
/** Pino logger with redaction applied. */
|
|
28
|
+
logger: Logger;
|
|
29
|
+
/** Parsed `AI_HUB_ENCRYPTION_KEY` (32 bytes). */
|
|
30
|
+
encryptionKey: Buffer;
|
|
31
|
+
/**
|
|
32
|
+
* The route prefix (default `/api/ai-hub`). The matcher peels this off
|
|
33
|
+
* before pattern-matching. Set via `createFetchHandler({ basePath })`.
|
|
34
|
+
*/
|
|
35
|
+
basePath: string;
|
|
36
|
+
/**
|
|
37
|
+
* Project-shaped Letta client (§6.4). The handler imports types from
|
|
38
|
+
* `letta/client.ts` and calls this for every Letta interaction —
|
|
39
|
+
* **never raw HTTP**. Tests inject a mock via
|
|
40
|
+
* `createFetchHandler({ lettaClient })`.
|
|
41
|
+
*/
|
|
42
|
+
lettaClient: LettaClient;
|
|
43
|
+
/**
|
|
44
|
+
* Per-process throttle that gates Letta Code subprocess spawning. The chat
|
|
45
|
+
* route's `streamUserMessage` path calls `acquire()` before spawning and
|
|
46
|
+
* `release()` in the finally; if acquire throws `ServerOverloadedError`
|
|
47
|
+
* the route returns HTTP 503 with an `error {server_overloaded}` SSE
|
|
48
|
+
* event. The throttle is per-server-instance (the live-count counter is
|
|
49
|
+
* in-memory) and is constructed once in `createFetchHandler` from env-
|
|
50
|
+
* derived config. Tests can inject a configured-for-the-test instance.
|
|
51
|
+
*
|
|
52
|
+
* @see ../letta/subprocessThrottle.ts
|
|
53
|
+
*/
|
|
54
|
+
subprocessThrottle: SubprocessThrottle;
|
|
55
|
+
/**
|
|
56
|
+
* Env-var record used as the fallback source for the Letta API key when
|
|
57
|
+
* the `admin_setting.letta_api_key_encrypted` column is empty (see
|
|
58
|
+
* `letta/client.ts:resolveApiKey` for the precedence). Production passes
|
|
59
|
+
* `process.env`; tests pass the synthesized record they boot with so
|
|
60
|
+
* the fallback behavior is exercisable without touching the real
|
|
61
|
+
* environment.
|
|
62
|
+
*/
|
|
63
|
+
envSource: Record<string, string | undefined>;
|
|
64
|
+
/**
|
|
65
|
+
* Step-12.5 — absolute base directory holding `seeds/` and `sandboxes/`.
|
|
66
|
+
* Resolved once by `resolveFilesDir(env)` at boot from
|
|
67
|
+
* `AI_HUB_FILES_DIR` (or the `${AI_HUB_DATA_DIR}/files` fallback) and
|
|
68
|
+
* threaded through every route that touches sandbox dirs: the admin
|
|
69
|
+
* agents validator (seed existence check), `POST /sessions`
|
|
70
|
+
* (seed → sandbox copy), and `POST /admin/sessions/:id/purge-sandbox`.
|
|
71
|
+
*
|
|
72
|
+
* @see ../letta/sandbox.ts
|
|
73
|
+
* @see docs/server/session-sandboxes.md
|
|
74
|
+
*/
|
|
75
|
+
filesDir: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* The shape every route handler implements. Mirrors the Web-Standard fetch
|
|
80
|
+
* function signature plus the per-instance context bundle and the matched
|
|
81
|
+
* path parameters.
|
|
82
|
+
*
|
|
83
|
+
* `params` is keyed by the `:name` placeholders in the route template — e.g.
|
|
84
|
+
* `/admin/users/:id/role` yields `{ id: "abc" }`. Handlers that don't use
|
|
85
|
+
* params can simply omit the third argument (TypeScript bivariance allows it).
|
|
86
|
+
*/
|
|
87
|
+
export type RouteHandler = (
|
|
88
|
+
req: Request,
|
|
89
|
+
ctx: AIHubServerContext,
|
|
90
|
+
params: Readonly<Record<string, string>>,
|
|
91
|
+
) => Promise<Response>;
|
|
92
|
+
|
|
93
|
+
/** A path-aware handler entry consumed by the matcher. */
|
|
94
|
+
export interface RouteEntry {
|
|
95
|
+
/** Uppercase HTTP method, or `"*"` to match any. */
|
|
96
|
+
method: string;
|
|
97
|
+
/**
|
|
98
|
+
* Path template with `:param` placeholders (e.g. `/sessions/:id`). Matched
|
|
99
|
+
* against the request path *after* the `basePath` prefix has been peeled.
|
|
100
|
+
*/
|
|
101
|
+
path: string;
|
|
102
|
+
/** The handler. */
|
|
103
|
+
handler: RouteHandler;
|
|
104
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public entry point for `@data-club/ai-hub-server`.
|
|
3
|
+
*
|
|
4
|
+
* Step 2 ships:
|
|
5
|
+
*
|
|
6
|
+
* - `createFetchHandler({...})` — the canonical Web-Standard Fetch entry point.
|
|
7
|
+
* - `createNextRouteHandler({...})` — first-class Next.js App Router adapter.
|
|
8
|
+
* - `bootServer({...})` — convenience: env → DB → migrate → seed → handler.
|
|
9
|
+
* - The shared types re-exported from `@data-club/ai-hub`.
|
|
10
|
+
*
|
|
11
|
+
* Subsequent steps add: full `/auth/*` + role middleware (Step 3), `/admin/*`
|
|
12
|
+
* + `/sessions` + `/agents` + `/metrics` (Step 4), Letta integration + `/chat`
|
|
13
|
+
* SSE (Step 5), TPM recovery (Step 6).
|
|
14
|
+
*
|
|
15
|
+
* @see SPECIFICATIONS.md §6 — server responsibilities
|
|
16
|
+
* @see SPECIFICATIONS.md §6.2 — stack
|
|
17
|
+
* @see docs/IMPLEMENTATION_PLAN.md — step-by-step delivery schedule
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
export type {
|
|
21
|
+
AIHubRole,
|
|
22
|
+
AIHubUser,
|
|
23
|
+
Session,
|
|
24
|
+
AIHubMessage,
|
|
25
|
+
TurnStatus,
|
|
26
|
+
RunningPhase,
|
|
27
|
+
AIHubState,
|
|
28
|
+
AIHubEventState,
|
|
29
|
+
AIHubEvent,
|
|
30
|
+
AIHubError,
|
|
31
|
+
} from "@data-club/ai-hub";
|
|
32
|
+
|
|
33
|
+
export {
|
|
34
|
+
createFetchHandler,
|
|
35
|
+
type CreateFetchHandlerOptions,
|
|
36
|
+
type FetchHandler,
|
|
37
|
+
} from "./handlers/fetch.js";
|
|
38
|
+
|
|
39
|
+
export { createNextRouteHandler } from "./handlers/nextjs.js";
|
|
40
|
+
|
|
41
|
+
export {
|
|
42
|
+
bootServer,
|
|
43
|
+
parseEnvConfig,
|
|
44
|
+
type BootServerOptions,
|
|
45
|
+
type BootedServer,
|
|
46
|
+
type EnvConfig,
|
|
47
|
+
type EnvLike,
|
|
48
|
+
} from "./bootstrap.js";
|
|
49
|
+
|
|
50
|
+
export {
|
|
51
|
+
SUPER_ADMIN_SEED_PASSWORD,
|
|
52
|
+
SUPER_ADMIN_SEED_USERNAME,
|
|
53
|
+
} from "./db/seed.js";
|
|
54
|
+
|
|
55
|
+
export {
|
|
56
|
+
createDefaultLettaClient,
|
|
57
|
+
type CreateLettaClientDeps,
|
|
58
|
+
type LettaClient,
|
|
59
|
+
type StreamUserMessageOpts,
|
|
60
|
+
} from "./letta/client.js";
|