@netnodeag/kraftwerk 0.61.0 → 0.63.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/dist/cli/routines.js +2 -3
- package/dist/client/index.d.ts +59 -0
- package/dist/client/index.js +63 -0
- package/dist/client/live.d.ts +34 -0
- package/dist/client/live.js +169 -0
- package/dist/client/routes.d.ts +125 -0
- package/dist/client/routes.js +126 -0
- package/dist/inspector/api/agents.d.ts +31 -0
- package/dist/inspector/api/agents.js +50 -0
- package/dist/inspector/api/attention.d.ts +10 -0
- package/dist/inspector/api/attention.js +23 -0
- package/dist/inspector/api/channels.d.ts +67 -0
- package/dist/inspector/api/channels.js +58 -0
- package/dist/inspector/api/chats.d.ts +55 -0
- package/dist/inspector/api/chats.js +154 -0
- package/dist/inspector/api/files.d.ts +15 -0
- package/dist/inspector/api/files.js +43 -0
- package/dist/inspector/api/git.d.ts +25 -0
- package/dist/inspector/api/git.js +56 -0
- package/dist/inspector/api/index.d.ts +334 -0
- package/dist/inspector/api/index.js +43 -0
- package/dist/inspector/api/knowledge.d.ts +13 -0
- package/dist/inspector/api/knowledge.js +56 -0
- package/dist/inspector/api/mime.d.ts +2 -0
- package/dist/inspector/api/mime.js +18 -0
- package/dist/inspector/api/projects.d.ts +11 -0
- package/dist/inspector/api/projects.js +32 -0
- package/dist/inspector/api/router.d.ts +75 -0
- package/dist/inspector/api/router.js +186 -0
- package/dist/inspector/api/runs.d.ts +33 -0
- package/dist/inspector/api/runs.js +105 -0
- package/dist/inspector/api/socket.d.ts +3 -0
- package/dist/inspector/api/socket.js +115 -0
- package/dist/inspector/api/vibeables.d.ts +4 -0
- package/dist/inspector/api/vibeables.js +31 -0
- package/dist/inspector/api/workspace.d.ts +55 -0
- package/dist/inspector/api/workspace.js +117 -0
- package/dist/inspector/chat/sessions.js +31 -19
- package/dist/inspector/context.d.ts +5 -7
- package/dist/inspector/context.js +6 -20
- package/dist/inspector/git.js +52 -43
- package/dist/inspector/live.d.ts +42 -0
- package/dist/inspector/live.js +91 -0
- package/dist/inspector/notifications.js +19 -13
- package/dist/inspector/routines.d.ts +22 -1
- package/dist/inspector/routines.js +32 -5
- package/dist/inspector/runner.js +5 -4
- package/dist/inspector/server.d.ts +2 -2
- package/dist/inspector/server.js +59 -1389
- package/dist/inspector/version.d.ts +9 -0
- package/dist/inspector/version.js +27 -0
- package/dist/inspector/vibeables.js +25 -23
- package/dist/inspector/workspace.d.ts +42 -0
- package/dist/inspector/workspace.js +63 -0
- package/dist/inspector/ws.d.ts +11 -0
- package/dist/inspector/ws.js +143 -0
- package/inspector/dist/assets/{dist-B3L4wDm3.js → dist-9RESajfo.js} +1 -1
- package/inspector/dist/assets/{dist-Cwukoo61.js → dist-Bm5S1BoZ.js} +1 -1
- package/inspector/dist/assets/dist-C8BofvHx.js +1 -0
- package/inspector/dist/assets/{dist-wYE0FpHk.js → dist-CIs4wnTu.js} +1 -1
- package/inspector/dist/assets/{dist-De7-pK5i.js → dist-CjuETd-_.js} +1 -1
- package/inspector/dist/assets/{dist-B58fOC3R.js → dist-CmVK6rgN.js} +1 -1
- package/inspector/dist/assets/{dist-zk56dqRQ.js → dist-CryXvMV_.js} +1 -1
- package/inspector/dist/assets/{dist-BiWJ3XY1.js → dist-D1hk0iC5.js} +1 -1
- package/inspector/dist/assets/{dist-CH9pz3rR.js → dist-DvW9QE1d.js} +1 -1
- package/inspector/dist/assets/{dist-Dno2CmWo.js → dist-VD9jMxBv.js} +1 -1
- package/inspector/dist/assets/{dist-BKBuUSVQ.js → dist-VlAqWD8T.js} +1 -1
- package/inspector/dist/assets/{editor-CMQMyCOv.js → editor-DkWqwl89.js} +3 -3
- package/inspector/dist/assets/index-Bra74Nxe.css +2 -0
- package/inspector/dist/assets/index-DRJS2pGj.js +229 -0
- package/inspector/dist/index.html +2 -2
- package/package.json +7 -2
- package/inspector/dist/assets/dist-Bj93ipvc.js +0 -1
- package/inspector/dist/assets/index-1wfYRgHE.css +0 -2
- package/inspector/dist/assets/index-CtygNkZJ.js +0 -229
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
import { type PathOf, type ResultOf, type Route } from "./router.js";
|
|
2
|
+
/**
|
|
3
|
+
* The control plane's contract. Every route has a stable name; clients
|
|
4
|
+
* (the web UI today, a native app or the CLI later) address it by that name
|
|
5
|
+
* and get the handler's return type as its result — inferred, so the
|
|
6
|
+
* contract cannot drift from the implementation. Bump PROTOCOL_VERSION when
|
|
7
|
+
* a route is removed or its result changes incompatibly; adding routes or
|
|
8
|
+
* fields is not a bump.
|
|
9
|
+
*/
|
|
10
|
+
export declare const PROTOCOL_VERSION = 1;
|
|
11
|
+
/** One line per route, for clients and people: what exists and how to reach it. */
|
|
12
|
+
export interface RouteInfo {
|
|
13
|
+
name: string;
|
|
14
|
+
method: string;
|
|
15
|
+
path: string;
|
|
16
|
+
summary: string;
|
|
17
|
+
/** A stream or a file, not a JSON result. */
|
|
18
|
+
raw?: boolean;
|
|
19
|
+
/** The body is a file's bytes. */
|
|
20
|
+
upload?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare const routes: (Route<"agents.addJournal", {
|
|
23
|
+
journal: string;
|
|
24
|
+
}, "/api/agents/:slug/journal"> | Route<"agents.archive", import("../agents.js").AgentDetail, "/api/agents/:slug/archive"> | Route<"agents.create", import("../agents.js").AgentDetail, "/api/agents"> | Route<"agents.delete", {
|
|
25
|
+
ok: boolean;
|
|
26
|
+
}, "/api/agents/:slug"> | Route<"agents.deleteRoutine", {
|
|
27
|
+
ok: boolean;
|
|
28
|
+
}, "/api/agents/:slug/routines/:id"> | Route<"agents.deleteSkill", {
|
|
29
|
+
ok: boolean;
|
|
30
|
+
}, "/api/agents/:slug/skills/:name"> | Route<"agents.get", import("../agents.js").AgentDetail, "/api/agents/:slug"> | Route<"agents.journal", {
|
|
31
|
+
journal: string;
|
|
32
|
+
}, "/api/agents/:slug/journal"> | Route<"agents.list", {
|
|
33
|
+
root: string;
|
|
34
|
+
agents: import("../agents.js").Agent[];
|
|
35
|
+
}, "/api/agents"> | Route<"agents.routines", {
|
|
36
|
+
routines: import("../routines.js").RoutineStatus[];
|
|
37
|
+
}, "/api/agents/:slug/routines"> | Route<"agents.runRoutine", {
|
|
38
|
+
chatId: string;
|
|
39
|
+
}, "/api/agents/:slug/routines/:id/run"> | Route<"agents.save", import("../agents.js").AgentDetail, "/api/agents/:slug"> | Route<"agents.saveRoutine", import("../routines.js").Routine, "/api/agents/:slug/routines"> | Route<"agents.saveSkill", import("../skills.js").SkillInfo & {
|
|
40
|
+
content: string;
|
|
41
|
+
}, "/api/agents/:slug/skills"> | Route<"agents.sessions", {
|
|
42
|
+
sessions: {
|
|
43
|
+
sessionId: string;
|
|
44
|
+
title?: string;
|
|
45
|
+
updatedAt?: string;
|
|
46
|
+
cwd: string;
|
|
47
|
+
}[];
|
|
48
|
+
}, "/api/agent-sessions"> | Route<"agents.skill", {
|
|
49
|
+
name: string;
|
|
50
|
+
description: string;
|
|
51
|
+
path: string;
|
|
52
|
+
dir: string;
|
|
53
|
+
source: "workspace" | "project" | "user" | "agent";
|
|
54
|
+
agent?: string;
|
|
55
|
+
content: string;
|
|
56
|
+
}, "/api/agents/:slug/skills/:name"> | Route<"agents.skills", {
|
|
57
|
+
skills: import("../skills.js").SkillInfo[];
|
|
58
|
+
}, "/api/agents/:slug/skills"> | Route<"agents.status", Record<string, import("../agent-status.js").AgentStatus>, "/api/agent-status"> | Route<"attention.list", import("../attention.js").AttentionView, "/api/attention"> | Route<"channels.create", {
|
|
59
|
+
slug: string;
|
|
60
|
+
name: string;
|
|
61
|
+
purpose?: string;
|
|
62
|
+
members: string[];
|
|
63
|
+
responder?: string;
|
|
64
|
+
maxHops: number;
|
|
65
|
+
project?: string;
|
|
66
|
+
chatId: string;
|
|
67
|
+
busy: boolean;
|
|
68
|
+
awaitingApproval: boolean;
|
|
69
|
+
updatedAt: string;
|
|
70
|
+
}, "/api/channels"> | Route<"channels.delete", {
|
|
71
|
+
ok: boolean;
|
|
72
|
+
}, "/api/channels/:slug"> | Route<"channels.fromChat", {
|
|
73
|
+
slug: string;
|
|
74
|
+
name: string;
|
|
75
|
+
purpose?: string;
|
|
76
|
+
members: string[];
|
|
77
|
+
responder?: string;
|
|
78
|
+
maxHops: number;
|
|
79
|
+
project?: string;
|
|
80
|
+
chatId: string;
|
|
81
|
+
busy: boolean;
|
|
82
|
+
awaitingApproval: boolean;
|
|
83
|
+
updatedAt: string;
|
|
84
|
+
}, "/api/channels/from-chat"> | Route<"channels.get", {
|
|
85
|
+
slug: string;
|
|
86
|
+
name: string;
|
|
87
|
+
purpose?: string;
|
|
88
|
+
members: string[];
|
|
89
|
+
responder?: string;
|
|
90
|
+
maxHops: number;
|
|
91
|
+
project?: string;
|
|
92
|
+
chatId: string;
|
|
93
|
+
busy: boolean;
|
|
94
|
+
awaitingApproval: boolean;
|
|
95
|
+
updatedAt: string;
|
|
96
|
+
}, "/api/channels/:slug"> | Route<"channels.list", {
|
|
97
|
+
root: string;
|
|
98
|
+
channels: {
|
|
99
|
+
slug: string;
|
|
100
|
+
name: string;
|
|
101
|
+
purpose?: string;
|
|
102
|
+
members: string[];
|
|
103
|
+
responder?: string;
|
|
104
|
+
maxHops: number;
|
|
105
|
+
project?: string;
|
|
106
|
+
chatId: string;
|
|
107
|
+
busy: boolean;
|
|
108
|
+
awaitingApproval: boolean;
|
|
109
|
+
updatedAt: string;
|
|
110
|
+
}[];
|
|
111
|
+
}, "/api/channels"> | Route<"channels.save", {
|
|
112
|
+
slug: string;
|
|
113
|
+
name: string;
|
|
114
|
+
purpose?: string;
|
|
115
|
+
members: string[];
|
|
116
|
+
responder?: string;
|
|
117
|
+
maxHops: number;
|
|
118
|
+
project?: string;
|
|
119
|
+
chatId: string;
|
|
120
|
+
busy: boolean;
|
|
121
|
+
awaitingApproval: boolean;
|
|
122
|
+
updatedAt: string;
|
|
123
|
+
}, "/api/channels/:slug"> | Route<"chats.attach", {
|
|
124
|
+
name: string;
|
|
125
|
+
mimeType: string;
|
|
126
|
+
size: number;
|
|
127
|
+
}, "/api/chats/:id/attachments"> | Route<"chats.attachment", undefined, "/api/chats/:id/attachments/:name"> | Route<"chats.cancel", import("./router.js").Reply<{
|
|
128
|
+
error: string;
|
|
129
|
+
}> | {
|
|
130
|
+
ok: true;
|
|
131
|
+
}, "/api/chats/:id/cancel"> | Route<"chats.config", import("./router.js").Reply<{
|
|
132
|
+
error: string;
|
|
133
|
+
}> | {
|
|
134
|
+
ok: true;
|
|
135
|
+
}, "/api/chats/:id/config"> | Route<"chats.create", import("../chat/types.js").ChatMeta, "/api/chats"> | Route<"chats.delete", import("./router.js").Reply<{
|
|
136
|
+
error?: string;
|
|
137
|
+
}>, "/api/chats/:id"> | Route<"chats.elicitation", import("./router.js").Reply<{
|
|
138
|
+
error: string;
|
|
139
|
+
}> | {
|
|
140
|
+
ok: true;
|
|
141
|
+
}, "/api/chats/:id/elicitation"> | Route<"chats.events", undefined, "/api/chats/:id/events"> | Route<"chats.fork", import("../chat/types.js").ChatMeta, "/api/chats/:id/fork"> | Route<"chats.get", {
|
|
142
|
+
meta: import("../chat/types.js").ChatMeta;
|
|
143
|
+
events: import("../chat/types.js").StoredChatEvent[];
|
|
144
|
+
busy: boolean;
|
|
145
|
+
}, "/api/chats/:id"> | Route<"chats.list", {
|
|
146
|
+
chats: (import("../chat/types.js").ChatMeta & {
|
|
147
|
+
busy: boolean;
|
|
148
|
+
awaitingApproval: boolean;
|
|
149
|
+
})[];
|
|
150
|
+
}, "/api/chats"> | Route<"chats.message", import("./router.js").Reply<{
|
|
151
|
+
error: string;
|
|
152
|
+
}> | {
|
|
153
|
+
ok: true;
|
|
154
|
+
}, "/api/chats/:id/message"> | Route<"chats.permission", import("./router.js").Reply<{
|
|
155
|
+
error: string;
|
|
156
|
+
}> | {
|
|
157
|
+
ok: true;
|
|
158
|
+
}, "/api/chats/:id/permission"> | Route<"chats.rename", import("./router.js").Reply<{
|
|
159
|
+
meta?: import("../chat/types.js").ChatMeta;
|
|
160
|
+
error?: string;
|
|
161
|
+
}>, "/api/chats/:id"> | Route<"chats.resetSession", import("../chat/types.js").ChatMeta, "/api/chats/:id/reset-session"> | Route<"chats.setVibeable", import("../chat/types.js").ChatMeta, "/api/chats/:id/vibeable"> | Route<"chats.steer", import("./router.js").Reply<{
|
|
162
|
+
error: string;
|
|
163
|
+
}> | {
|
|
164
|
+
ok: true;
|
|
165
|
+
}, "/api/chats/:id/steer"> | Route<"chats.stopTask", import("./router.js").Reply<{
|
|
166
|
+
error: string;
|
|
167
|
+
}> | {
|
|
168
|
+
ok: true;
|
|
169
|
+
}, "/api/chats/:id/task-stop"> | Route<"files.delete", {
|
|
170
|
+
ok: boolean;
|
|
171
|
+
}, "/api/files"> | Route<"files.list", import("../files.js").FilesListing, "/api/files/list"> | Route<"files.mkdir", import("./router.js").Reply<import("../files.js").FileEntry>, "/api/files/folder"> | Route<"files.move", {
|
|
172
|
+
ok: boolean;
|
|
173
|
+
}, "/api/files/move"> | Route<"files.raw", void, "/api/files/raw"> | Route<"files.recent", {
|
|
174
|
+
root: string;
|
|
175
|
+
count: number;
|
|
176
|
+
recent: {
|
|
177
|
+
path: string;
|
|
178
|
+
at: string;
|
|
179
|
+
}[];
|
|
180
|
+
}, "/api/files/recent"> | Route<"files.scopes", {
|
|
181
|
+
scopes: import("../files.js").FilesScopeInfo[];
|
|
182
|
+
}, "/api/files"> | Route<"files.upload", import("./router.js").Reply<import("../files.js").FileEntry>, "/api/files/upload"> | Route<"git.commit", import("./router.js").Reply<{
|
|
183
|
+
ok: boolean;
|
|
184
|
+
error?: string;
|
|
185
|
+
committed?: number;
|
|
186
|
+
}>, "/api/git/commit"> | Route<"git.diff", import("../git.js").GitDiff, "/api/git/diff"> | Route<"git.fetch", import("./router.js").Reply<{
|
|
187
|
+
ok: boolean;
|
|
188
|
+
error?: string;
|
|
189
|
+
}>, "/api/git/fetch"> | Route<"git.pull", import("./router.js").Reply<{
|
|
190
|
+
ok: boolean;
|
|
191
|
+
error?: string;
|
|
192
|
+
}>, "/api/git/pull"> | Route<"git.push", import("./router.js").Reply<{
|
|
193
|
+
ok: boolean;
|
|
194
|
+
error?: string;
|
|
195
|
+
}>, "/api/git/push"> | Route<"git.status", import("../git.js").GitStatus, "/api/git"> | Route<"knowledge.concept", import("../../okf.js").ConceptDetail, "/api/knowledge/:bundle/concept"> | Route<"knowledge.create", import("../../okf.js").BundleInfo, "/api/knowledge"> | Route<"knowledge.delete", {
|
|
196
|
+
ok: boolean;
|
|
197
|
+
}, "/api/knowledge/:bundle"> | Route<"knowledge.get", import("../knowledge.js").BundleDetail, "/api/knowledge/:bundle"> | Route<"knowledge.list", import("../knowledge.js").KnowledgeIndex, "/api/knowledge"> | Route<"knowledge.putConcept", import("../../okf.js").ConceptDetail, "/api/knowledge/:bundle/concept"> | Route<"knowledge.verify", import("../../okf.js").ConceptDetail, "/api/knowledge/:bundle/verify"> | Route<"meta.get", {
|
|
198
|
+
version: string;
|
|
199
|
+
diskVersion: string;
|
|
200
|
+
restartable: boolean;
|
|
201
|
+
projectName: string;
|
|
202
|
+
projectIcon: string;
|
|
203
|
+
projectColor: string;
|
|
204
|
+
projectNamed: boolean;
|
|
205
|
+
projectRoot: string;
|
|
206
|
+
projectRootLabel: string;
|
|
207
|
+
git: boolean;
|
|
208
|
+
repos: boolean;
|
|
209
|
+
vibeables: boolean;
|
|
210
|
+
projects: boolean;
|
|
211
|
+
publicUrl: string;
|
|
212
|
+
cloud: import("../cloud.js").CloudStatus;
|
|
213
|
+
switcher: import("../../config.js").SwitcherEntry[];
|
|
214
|
+
}, "/api/meta"> | Route<"notifications.clear", {
|
|
215
|
+
ok: boolean;
|
|
216
|
+
}, "/api/notifications"> | Route<"notifications.diagnose", import("./router.js").Reply<{
|
|
217
|
+
error: string;
|
|
218
|
+
status: number;
|
|
219
|
+
}> | {
|
|
220
|
+
chatId: string;
|
|
221
|
+
href: string;
|
|
222
|
+
}, "/api/notifications/:id/diagnose"> | Route<"notifications.list", import("../notifications.js").NotificationsView, "/api/notifications"> | Route<"notifications.read", import("../notifications.js").NotificationsView, "/api/notifications/read"> | Route<"projects.create", import("./router.js").Reply<import("../projects.js").ProjectDetail>, "/api/projects"> | Route<"projects.delete", {
|
|
223
|
+
ok: boolean;
|
|
224
|
+
}, "/api/projects/:slug"> | Route<"projects.get", import("../projects.js").ProjectDetail, "/api/projects/:slug"> | Route<"projects.link", import("../projects.js").ProjectDetail, "/api/projects/:slug/links"> | Route<"projects.list", import("../projects.js").ProjectsView, "/api/projects"> | Route<"projects.log", {
|
|
225
|
+
ok: boolean;
|
|
226
|
+
log: string;
|
|
227
|
+
}, "/api/projects/:slug/log"> | Route<"projects.save", import("../projects.js").ProjectDetail, "/api/projects/:slug"> | Route<"projects.saveLayout", {
|
|
228
|
+
ok: boolean;
|
|
229
|
+
layout: import("../projects.js").ProjectLayout;
|
|
230
|
+
}, "/api/projects"> | Route<"protocol.get", {
|
|
231
|
+
version: number;
|
|
232
|
+
routes: RouteInfo[];
|
|
233
|
+
}, "/api/protocol"> | Route<"repos.add", import("./router.js").Reply<import("../repos.js").RepoInfo>, "/api/repos"> | Route<"repos.commit", import("./router.js").Reply<import("../git.js").GitDiff>, "/api/repos/:slug/commits/:hash"> | Route<"repos.diff", import("./router.js").Reply<import("../git.js").GitDiff>, "/api/repos/:slug/diff"> | Route<"repos.get", import("../repos.js").RepoDetail, "/api/repos/:slug"> | Route<"repos.list", import("../repos.js").ReposView, "/api/repos"> | Route<"repos.remove", import("./router.js").Reply<{
|
|
234
|
+
ok: boolean;
|
|
235
|
+
error?: string;
|
|
236
|
+
off?: boolean;
|
|
237
|
+
conflict?: boolean;
|
|
238
|
+
}>, "/api/repos/:slug"> | Route<"repos.update", import("./router.js").Reply<{
|
|
239
|
+
ok: boolean;
|
|
240
|
+
error?: string;
|
|
241
|
+
off?: boolean;
|
|
242
|
+
repo?: import("../repos.js").RepoInfo;
|
|
243
|
+
}>, "/api/repos/:slug/update"> | Route<"routines.list", {
|
|
244
|
+
routines: (import("../routines.js").RoutineStatus & {
|
|
245
|
+
agent: {
|
|
246
|
+
slug: string;
|
|
247
|
+
name: string;
|
|
248
|
+
emoji: string;
|
|
249
|
+
};
|
|
250
|
+
workflows: string[];
|
|
251
|
+
})[];
|
|
252
|
+
}, "/api/routines"> | Route<"runs.decide", import("../decisions.js").DecisionAnswer, "/api/runs/:id/decision"> | Route<"runs.delete", {
|
|
253
|
+
deleted: boolean;
|
|
254
|
+
}, "/api/runs/:id"> | Route<"runs.file", undefined, "/api/runs/:id/file"> | Route<"runs.fileText", {
|
|
255
|
+
name: string;
|
|
256
|
+
size: number;
|
|
257
|
+
truncated: boolean;
|
|
258
|
+
content: string;
|
|
259
|
+
}, "/api/runs/:id/text"> | Route<"runs.get", import("../runs.js").RunDetail, "/api/runs/:id"> | Route<"runs.list", {
|
|
260
|
+
outputDir: string;
|
|
261
|
+
runs: import("../runs.js").RunListItem[];
|
|
262
|
+
}, "/api/runs"> | Route<"runs.stop", {
|
|
263
|
+
stopped: boolean;
|
|
264
|
+
}, "/api/runs/:id/stop"> | Route<"search.agents", import("../search.js").AgentSearch, "/api/search/agents"> | Route<"server.restart", {
|
|
265
|
+
ok: boolean;
|
|
266
|
+
}, "/api/restart"> | Route<"settings.get", import("../settings.js").SettingsView, "/api/settings"> | Route<"settings.save", import("../settings.js").SettingsView, "/api/settings"> | Route<"skills.get", import("../skills.js").SkillDetail, "/api/skills/:name"> | Route<"skills.list", {
|
|
267
|
+
root: string;
|
|
268
|
+
skills: import("../skills.js").SkillInfo[];
|
|
269
|
+
}, "/api/skills"> | Route<"trash.empty", {
|
|
270
|
+
ok: boolean;
|
|
271
|
+
purged: number;
|
|
272
|
+
}, "/api/trash"> | Route<"trash.list", {
|
|
273
|
+
root: string;
|
|
274
|
+
entries: import("../trash.js").TrashEntry[];
|
|
275
|
+
}, "/api/trash"> | Route<"trash.purge", import("../trash.js").TrashEntry, "/api/trash/purge"> | Route<"trash.restore", import("../trash.js").TrashEntry, "/api/trash/restore"> | Route<"update.check", import("./router.js").Reply<{
|
|
276
|
+
name: string;
|
|
277
|
+
current: string;
|
|
278
|
+
latest: string;
|
|
279
|
+
error: string;
|
|
280
|
+
}> | {
|
|
281
|
+
name: string;
|
|
282
|
+
current: string;
|
|
283
|
+
latest: string;
|
|
284
|
+
error?: string;
|
|
285
|
+
}, "/api/update-check"> | Route<"update.start", import("./router.js").Reply<{
|
|
286
|
+
state: "idle" | "running" | "done" | "failed";
|
|
287
|
+
version?: string;
|
|
288
|
+
log: string[];
|
|
289
|
+
startedAt?: string;
|
|
290
|
+
finishedAt?: string;
|
|
291
|
+
exitCode?: number | null;
|
|
292
|
+
name: string;
|
|
293
|
+
}>, "/api/update"> | Route<"update.status", {
|
|
294
|
+
state: "idle" | "running" | "done" | "failed";
|
|
295
|
+
version?: string;
|
|
296
|
+
log: string[];
|
|
297
|
+
startedAt?: string;
|
|
298
|
+
finishedAt?: string;
|
|
299
|
+
exitCode?: number | null;
|
|
300
|
+
name: string;
|
|
301
|
+
available: boolean;
|
|
302
|
+
reason: string | undefined;
|
|
303
|
+
restartable: boolean;
|
|
304
|
+
}, "/api/update"> | Route<"vibeables.create", import("./router.js").Reply<import("../vibeables.js").VibeableInfo>, "/api/vibeables"> | Route<"vibeables.delete", {
|
|
305
|
+
ok: boolean;
|
|
306
|
+
}, "/api/vibeables/:slug"> | Route<"vibeables.devStart", import("../vibeables.js").VibeableStatus, "/api/vibeables/:slug/dev/start"> | Route<"vibeables.devStop", import("../vibeables.js").VibeableStatus, "/api/vibeables/:slug/dev/stop"> | Route<"vibeables.events", void, "/api/vibeables/:slug/events"> | Route<"vibeables.get", import("../vibeables.js").VibeableStatus, "/api/vibeables/:slug"> | Route<"vibeables.list", import("../vibeables.js").VibeablesView, "/api/vibeables"> | Route<"workflows.delete", {
|
|
307
|
+
ok: boolean;
|
|
308
|
+
}, "/api/workflows/:slug"> | Route<"workflows.get", import("../workflows.js").WorkflowDetail, "/api/workflows/:slug"> | Route<"workflows.list", {
|
|
309
|
+
root?: string;
|
|
310
|
+
workflows: import("../workflows.js").WorkflowSummary[];
|
|
311
|
+
}, "/api/workflows"> | Route<"workflows.run", {
|
|
312
|
+
runId: string;
|
|
313
|
+
}, "/api/workflows/:slug/run"> | Route<"workflows.runner", {
|
|
314
|
+
available: boolean;
|
|
315
|
+
image: boolean;
|
|
316
|
+
}, "/api/workflows/:slug/run"> | Route<"workspaces.forget", {
|
|
317
|
+
ok: boolean;
|
|
318
|
+
}, "/api/workspaces/forget"> | Route<"workspaces.list", import("../instances.js").WorkspaceDetail[], "/api/workspaces"> | Route<"workspaces.start", import("./router.js").Reply<import("../instances.js").StartResult>, "/api/workspaces/start"> | Route<"workspaces.stop", import("./router.js").Reply<{
|
|
319
|
+
ok: boolean;
|
|
320
|
+
error?: string;
|
|
321
|
+
}>, "/api/workspaces/stop">)[];
|
|
322
|
+
export declare const apiRouter: import("./router.js").Router;
|
|
323
|
+
type AnyRoute = (typeof routes)[number];
|
|
324
|
+
/** Every route name. */
|
|
325
|
+
export type ApiName = AnyRoute["name"];
|
|
326
|
+
/** The result of route `N` (its 200 body). */
|
|
327
|
+
export type ApiResult<N extends ApiName> = ResultOf<Extract<AnyRoute, {
|
|
328
|
+
name: N;
|
|
329
|
+
}>>;
|
|
330
|
+
/** The path pattern of route `N` (`/api/projects/:slug`). */
|
|
331
|
+
export type ApiPath<N extends ApiName> = PathOf<Extract<AnyRoute, {
|
|
332
|
+
name: N;
|
|
333
|
+
}>>;
|
|
334
|
+
export {};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { agentRoutes } from "./agents.js";
|
|
2
|
+
import { attentionRoutes } from "./attention.js";
|
|
3
|
+
import { channelRoutes } from "./channels.js";
|
|
4
|
+
import { chatRoutes } from "./chats.js";
|
|
5
|
+
import { fileRoutes } from "./files.js";
|
|
6
|
+
import { gitRoutes } from "./git.js";
|
|
7
|
+
import { knowledgeRoutes } from "./knowledge.js";
|
|
8
|
+
import { projectRoutes } from "./projects.js";
|
|
9
|
+
import { createRouter, route } from "./router.js";
|
|
10
|
+
import { runRoutes } from "./runs.js";
|
|
11
|
+
import { vibeableRoutes } from "./vibeables.js";
|
|
12
|
+
import { workspaceRoutes } from "./workspace.js";
|
|
13
|
+
/**
|
|
14
|
+
* The control plane's contract. Every route has a stable name; clients
|
|
15
|
+
* (the web UI today, a native app or the CLI later) address it by that name
|
|
16
|
+
* and get the handler's return type as its result — inferred, so the
|
|
17
|
+
* contract cannot drift from the implementation. Bump PROTOCOL_VERSION when
|
|
18
|
+
* a route is removed or its result changes incompatibly; adding routes or
|
|
19
|
+
* fields is not a bump.
|
|
20
|
+
*/
|
|
21
|
+
export const PROTOCOL_VERSION = 1;
|
|
22
|
+
const domainRoutes = [
|
|
23
|
+
...workspaceRoutes,
|
|
24
|
+
...attentionRoutes,
|
|
25
|
+
...agentRoutes,
|
|
26
|
+
...chatRoutes,
|
|
27
|
+
...channelRoutes,
|
|
28
|
+
...projectRoutes,
|
|
29
|
+
...runRoutes,
|
|
30
|
+
...knowledgeRoutes,
|
|
31
|
+
...fileRoutes,
|
|
32
|
+
...gitRoutes,
|
|
33
|
+
...vibeableRoutes,
|
|
34
|
+
];
|
|
35
|
+
const protocolRoute = route({ name: "protocol.get", method: "GET", path: "/api/protocol", summary: "the protocol version and every route" }, async () => ({
|
|
36
|
+
version: PROTOCOL_VERSION,
|
|
37
|
+
routes: describe(),
|
|
38
|
+
}));
|
|
39
|
+
function describe() {
|
|
40
|
+
return routes.map(({ name, method, path, summary, raw, upload }) => ({ name, method, path, summary, ...(raw ? { raw } : {}), ...(upload ? { upload } : {}) }));
|
|
41
|
+
}
|
|
42
|
+
export const routes = [protocolRoute, ...domainRoutes];
|
|
43
|
+
export const apiRouter = createRouter(routes);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Knowledge bundles and their concepts, the workspace's skills, and the trash. */
|
|
2
|
+
export declare const knowledgeRoutes: (import("./router.js").Route<"knowledge.concept", import("../../okf.js").ConceptDetail, "/api/knowledge/:bundle/concept"> | import("./router.js").Route<"knowledge.create", import("../../okf.js").BundleInfo, "/api/knowledge"> | import("./router.js").Route<"knowledge.delete", {
|
|
3
|
+
ok: boolean;
|
|
4
|
+
}, "/api/knowledge/:bundle"> | import("./router.js").Route<"knowledge.get", import("../knowledge.js").BundleDetail, "/api/knowledge/:bundle"> | import("./router.js").Route<"knowledge.list", import("../knowledge.js").KnowledgeIndex, "/api/knowledge"> | import("./router.js").Route<"knowledge.putConcept", import("../../okf.js").ConceptDetail, "/api/knowledge/:bundle/concept"> | import("./router.js").Route<"knowledge.verify", import("../../okf.js").ConceptDetail, "/api/knowledge/:bundle/verify"> | import("./router.js").Route<"skills.get", import("../skills.js").SkillDetail, "/api/skills/:name"> | import("./router.js").Route<"skills.list", {
|
|
5
|
+
root: string;
|
|
6
|
+
skills: import("../skills.js").SkillInfo[];
|
|
7
|
+
}, "/api/skills"> | import("./router.js").Route<"trash.empty", {
|
|
8
|
+
ok: boolean;
|
|
9
|
+
purged: number;
|
|
10
|
+
}, "/api/trash"> | import("./router.js").Route<"trash.list", {
|
|
11
|
+
root: string;
|
|
12
|
+
entries: import("../trash.js").TrashEntry[];
|
|
13
|
+
}, "/api/trash"> | import("./router.js").Route<"trash.purge", import("../trash.js").TrashEntry, "/api/trash/purge"> | import("./router.js").Route<"trash.restore", import("../trash.js").TrashEntry, "/api/trash/restore">)[];
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { tildify } from "../instances.js";
|
|
2
|
+
import { bundleDetail, conceptDetail, createBundle, deleteBundle, knowledgeIndex, putConcept, verifyFromUi } from "../knowledge.js";
|
|
3
|
+
import { getSkill, listSkills, skillsRoot } from "../skills.js";
|
|
4
|
+
import { emptyTrash, listTrash, purgeFromTrash, restoreFromTrash, trashRoot } from "../trash.js";
|
|
5
|
+
import { ApiError, fail, route } from "./router.js";
|
|
6
|
+
/** Knowledge bundles and their concepts, the workspace's skills, and the trash. */
|
|
7
|
+
export const knowledgeRoutes = [
|
|
8
|
+
route({ name: "knowledge.list", method: "GET", path: "/api/knowledge", summary: "the bundle index" }, async () => knowledgeIndex()),
|
|
9
|
+
route({ name: "knowledge.create", method: "POST", path: "/api/knowledge", summary: "create a bundle {name}", errors: 400 }, async (c) => createBundle(String((await c.body()).name ?? "").trim())),
|
|
10
|
+
route({ name: "knowledge.get", method: "GET", path: "/api/knowledge/:bundle", summary: "a bundle's concepts and log" }, async (c) => {
|
|
11
|
+
const detail = await bundleDetail(c.params.bundle).catch(() => {
|
|
12
|
+
throw new ApiError(400, "invalid bundle name");
|
|
13
|
+
});
|
|
14
|
+
return detail ?? fail(404, "not found");
|
|
15
|
+
}),
|
|
16
|
+
route({ name: "knowledge.delete", method: "DELETE", path: "/api/knowledge/:bundle", summary: "move the bundle to the trash", errors: 400 }, async (c) => {
|
|
17
|
+
await deleteBundle(c.params.bundle);
|
|
18
|
+
return { ok: true };
|
|
19
|
+
}),
|
|
20
|
+
route({ name: "knowledge.concept", method: "GET", path: "/api/knowledge/:bundle/concept", summary: "one concept ?id=", errors: 400 }, async (c) => (await conceptDetail(c.params.bundle, c.query.get("id") ?? "")) ?? fail(404, "not found")),
|
|
21
|
+
route({ name: "knowledge.putConcept", method: "POST", path: "/api/knowledge/:bundle/concept", summary: "write one concept {id, content}", errors: 400 }, async (c) => {
|
|
22
|
+
const body = await c.body();
|
|
23
|
+
if (!body.id || !body.content?.trim())
|
|
24
|
+
fail(400, "id and content are required");
|
|
25
|
+
return putConcept(c.params.bundle, body.id, body.content);
|
|
26
|
+
}),
|
|
27
|
+
route({ name: "knowledge.verify", method: "POST", path: "/api/knowledge/:bundle/verify", summary: "a person verifies a concept {id}", errors: 400 }, async (c) => {
|
|
28
|
+
const { id } = await c.body();
|
|
29
|
+
if (!id)
|
|
30
|
+
fail(400, "id is required");
|
|
31
|
+
return verifyFromUi(c.params.bundle, id);
|
|
32
|
+
}),
|
|
33
|
+
// Discovered from the workspace root, .claude/skills and ~/.claude/skills.
|
|
34
|
+
route({ name: "skills.list", method: "GET", path: "/api/skills", summary: "every discovered skill" }, async () => {
|
|
35
|
+
const [root, skills] = await Promise.all([skillsRoot(), listSkills()]);
|
|
36
|
+
return { root, skills };
|
|
37
|
+
}),
|
|
38
|
+
route({ name: "skills.get", method: "GET", path: "/api/skills/:name", summary: "one skill with SKILL.md and its bundled files" }, async (c) => (await getSkill(c.params.name)) ?? fail(404, "not found")),
|
|
39
|
+
route({ name: "trash.list", method: "GET", path: "/api/trash", summary: "what was deleted, newest first", errors: 400 }, async () => ({
|
|
40
|
+
root: tildify(await trashRoot()),
|
|
41
|
+
entries: await listTrash(),
|
|
42
|
+
})),
|
|
43
|
+
route({ name: "trash.empty", method: "DELETE", path: "/api/trash", summary: "empty the trash for good", errors: 400 }, async () => ({ ok: true, purged: await emptyTrash() })),
|
|
44
|
+
route({ name: "trash.restore", method: "POST", path: "/api/trash/restore", summary: "put one {id} back", errors: 400 }, async (c) => {
|
|
45
|
+
const { id } = await c.body();
|
|
46
|
+
if (!id)
|
|
47
|
+
fail(400, "id is required");
|
|
48
|
+
return restoreFromTrash(id);
|
|
49
|
+
}),
|
|
50
|
+
route({ name: "trash.purge", method: "POST", path: "/api/trash/purge", summary: "delete one {id} for good", errors: 400 }, async (c) => {
|
|
51
|
+
const { id } = await c.body();
|
|
52
|
+
if (!id)
|
|
53
|
+
fail(400, "id is required");
|
|
54
|
+
return purgeFromTrash(id);
|
|
55
|
+
}),
|
|
56
|
+
];
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Content types by extension, for files served as themselves. */
|
|
2
|
+
export const MIME = {
|
|
3
|
+
".html": "text/html; charset=utf-8",
|
|
4
|
+
".js": "text/javascript; charset=utf-8",
|
|
5
|
+
".css": "text/css; charset=utf-8",
|
|
6
|
+
".svg": "image/svg+xml",
|
|
7
|
+
".png": "image/png",
|
|
8
|
+
".jpg": "image/jpeg",
|
|
9
|
+
".jpeg": "image/jpeg",
|
|
10
|
+
".gif": "image/gif",
|
|
11
|
+
".webp": "image/webp",
|
|
12
|
+
".ico": "image/x-icon",
|
|
13
|
+
".pdf": "application/pdf",
|
|
14
|
+
".json": "application/json; charset=utf-8",
|
|
15
|
+
".woff": "font/woff",
|
|
16
|
+
".woff2": "font/woff2",
|
|
17
|
+
".txt": "text/plain; charset=utf-8",
|
|
18
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const projectErrors: (message: string) => number;
|
|
2
|
+
/** Projects: folders with a goal, a brief, a log and links, plus the rail's order. */
|
|
3
|
+
export declare const projectRoutes: (import("./router.js").Route<"projects.create", import("./router.js").Reply<import("../projects.js").ProjectDetail>, "/api/projects"> | import("./router.js").Route<"projects.delete", {
|
|
4
|
+
ok: boolean;
|
|
5
|
+
}, "/api/projects/:slug"> | import("./router.js").Route<"projects.get", import("../projects.js").ProjectDetail, "/api/projects/:slug"> | import("./router.js").Route<"projects.link", import("../projects.js").ProjectDetail, "/api/projects/:slug/links"> | import("./router.js").Route<"projects.list", import("../projects.js").ProjectsView, "/api/projects"> | import("./router.js").Route<"projects.log", {
|
|
6
|
+
ok: boolean;
|
|
7
|
+
log: string;
|
|
8
|
+
}, "/api/projects/:slug/log"> | import("./router.js").Route<"projects.save", import("../projects.js").ProjectDetail, "/api/projects/:slug"> | import("./router.js").Route<"projects.saveLayout", {
|
|
9
|
+
ok: boolean;
|
|
10
|
+
layout: import("../projects.js").ProjectLayout;
|
|
11
|
+
}, "/api/projects">)[];
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { appendProjectLog, createProject, deleteProject, getProject, linkProject, listProjects, openProjects, saveLayout, saveProject } from "../projects.js";
|
|
2
|
+
import { fail, reply, route, statusByMessage } from "./router.js";
|
|
3
|
+
export const projectErrors = statusByMessage(/^no project/);
|
|
4
|
+
const str = (v) => (typeof v === "string" ? v : undefined);
|
|
5
|
+
/** Projects: folders with a goal, a brief, a log and links, plus the rail's order. */
|
|
6
|
+
export const projectRoutes = [
|
|
7
|
+
route({ name: "projects.list", method: "GET", path: "/api/projects", summary: "every project folder, with the rail's layout" }, async () => listProjects()),
|
|
8
|
+
route({ name: "projects.create", method: "POST", path: "/api/projects", summary: "create one {title, goal?, slug?} from the starter", errors: 400 }, async (c) => {
|
|
9
|
+
if ((await openProjects()).off)
|
|
10
|
+
fail(409, "projects are off");
|
|
11
|
+
const body = await c.body();
|
|
12
|
+
return reply(201, await createProject({ title: str(body.title) ?? "", goal: str(body.goal), slug: str(body.slug) }));
|
|
13
|
+
}),
|
|
14
|
+
route({ name: "projects.saveLayout", method: "PUT", path: "/api/projects", summary: "save the rail's order and sections {top, sections}", errors: projectErrors }, async (c) => ({
|
|
15
|
+
ok: true,
|
|
16
|
+
layout: await saveLayout(await c.body()),
|
|
17
|
+
})),
|
|
18
|
+
route({ name: "projects.get", method: "GET", path: "/api/projects/:slug", summary: "definition, brief, state, log and link states", errors: projectErrors }, async (c) => (await getProject(c.params.slug)) ?? fail(404, `no project "${c.params.slug}"`)),
|
|
19
|
+
route({ name: "projects.save", method: "PUT", path: "/api/projects/:slug", summary: "save fields", errors: projectErrors }, async (c) => saveProject(c.params.slug, await c.body())),
|
|
20
|
+
route({ name: "projects.delete", method: "DELETE", path: "/api/projects/:slug", summary: "move the folder to the trash", errors: projectErrors }, async (c) => {
|
|
21
|
+
await deleteProject(c.params.slug);
|
|
22
|
+
return { ok: true };
|
|
23
|
+
}),
|
|
24
|
+
route({ name: "projects.log", method: "POST", path: "/api/projects/:slug/log", summary: "append a stamped line {entry, actor?} to log.md", errors: projectErrors }, async (c) => {
|
|
25
|
+
const body = await c.body();
|
|
26
|
+
return { ok: true, log: await appendProjectLog(c.params.slug, str(body.entry) ?? "", str(body.actor) ?? "human:user") };
|
|
27
|
+
}),
|
|
28
|
+
route({ name: "projects.link", method: "POST", path: "/api/projects/:slug/links", summary: "add or drop one linked slug {kind, target, remove?}", errors: projectErrors }, async (c) => {
|
|
29
|
+
const body = await c.body();
|
|
30
|
+
return linkProject(c.params.slug, str(body.kind) ?? "", str(body.target) ?? "", body.remove === true);
|
|
31
|
+
}),
|
|
32
|
+
];
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type http from "node:http";
|
|
2
|
+
/**
|
|
3
|
+
* The API's routing: every endpoint is one named route — an RPC-style name
|
|
4
|
+
* (`projects.get`), an HTTP method + path pattern, and a handler that
|
|
5
|
+
* returns its result instead of writing the response. The name and the
|
|
6
|
+
* result type are the contract other clients build on (see api/index.ts);
|
|
7
|
+
* HTTP is one transport for it. Handlers that must own the response — SSE
|
|
8
|
+
* streams, file downloads, raw uploads — are marked `raw` and write to
|
|
9
|
+
* `c.res` themselves.
|
|
10
|
+
*/
|
|
11
|
+
export type Method = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
12
|
+
export interface Ctx {
|
|
13
|
+
req: http.IncomingMessage;
|
|
14
|
+
res: http.ServerResponse;
|
|
15
|
+
url: URL;
|
|
16
|
+
/** Path parameters, already URI-decoded (`:slug` → params.slug). */
|
|
17
|
+
params: Record<string, string>;
|
|
18
|
+
query: URLSearchParams;
|
|
19
|
+
/** The JSON body; an empty body is `{}`, malformed JSON a 400. Read once. */
|
|
20
|
+
body<T = Record<string, unknown>>(): Promise<T>;
|
|
21
|
+
}
|
|
22
|
+
/** A result with a status other than 200 (201 created, 409 with a body, …). */
|
|
23
|
+
export declare class Reply<B> {
|
|
24
|
+
readonly status: number;
|
|
25
|
+
readonly body: B;
|
|
26
|
+
constructor(status: number, body: B);
|
|
27
|
+
}
|
|
28
|
+
export declare const reply: <B>(status: number, body: B) => Reply<B>;
|
|
29
|
+
/** A refusal with a status; the body is `{error}` unless given. */
|
|
30
|
+
export declare class ApiError extends Error {
|
|
31
|
+
readonly status: number;
|
|
32
|
+
readonly body: unknown;
|
|
33
|
+
constructor(status: number, message: string, body?: unknown);
|
|
34
|
+
}
|
|
35
|
+
export declare function fail(status: number, message: string): never;
|
|
36
|
+
export interface RouteDef<N extends string, P extends string = string> {
|
|
37
|
+
name: N;
|
|
38
|
+
method: Method;
|
|
39
|
+
/** `/api/projects/:slug/log` — literal segments win over parameters. */
|
|
40
|
+
path: P;
|
|
41
|
+
summary: string;
|
|
42
|
+
/** Status for an Error the handler throws (not an ApiError); default 500. */
|
|
43
|
+
errors?: number | ((message: string) => number);
|
|
44
|
+
/** The handler writes the response itself (streams, files). HTTP only. */
|
|
45
|
+
raw?: boolean;
|
|
46
|
+
/** The request body is the bytes of a file (`c.req`), not JSON. HTTP only. */
|
|
47
|
+
upload?: boolean;
|
|
48
|
+
}
|
|
49
|
+
export interface Route<N extends string = string, R = unknown, P extends string = string> extends RouteDef<N, P> {
|
|
50
|
+
handle(c: Ctx): Promise<R>;
|
|
51
|
+
}
|
|
52
|
+
export declare function route<const N extends string, R, const P extends string>(def: RouteDef<N, P>, handle: (c: Ctx) => Promise<R>): Route<N, R, P>;
|
|
53
|
+
/** The 200 body of a route's result. */
|
|
54
|
+
export type ResultOf<R> = R extends Route<string, infer T, string> ? (T extends Reply<infer B> ? B : T) : never;
|
|
55
|
+
/** A route's path pattern, as a literal type. */
|
|
56
|
+
export type PathOf<R> = R extends Route<string, unknown, infer P> ? P : never;
|
|
57
|
+
/** Maps an error message to a status by the usual wording: "no <thing>" is 404, "… are off" 409, else 400. */
|
|
58
|
+
export declare const statusByMessage: (missing: RegExp) => (message: string) => number;
|
|
59
|
+
export interface Router {
|
|
60
|
+
routes: readonly Route[];
|
|
61
|
+
handle(req: http.IncomingMessage, res: http.ServerResponse, url: URL): Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* Run a route by name without HTTP (the socket): path parameters by name,
|
|
64
|
+
* `query` and `body` beside them. Raw and upload routes are refused.
|
|
65
|
+
*/
|
|
66
|
+
invoke(name: string, input: Record<string, unknown>): Promise<{
|
|
67
|
+
status: number;
|
|
68
|
+
data: unknown;
|
|
69
|
+
}>;
|
|
70
|
+
}
|
|
71
|
+
export declare function json(res: http.ServerResponse, body: unknown, status?: number): void;
|
|
72
|
+
export declare function readBody(req: http.IncomingMessage): Promise<string>;
|
|
73
|
+
/** A raw upload body (attachments), capped at `max` bytes. */
|
|
74
|
+
export declare function readRawBody(req: http.IncomingMessage, max: number): Promise<Buffer>;
|
|
75
|
+
export declare function createRouter(routes: readonly Route[]): Router;
|