@stacknet/stacks 0.2.0 → 0.2.2
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/README.md +136 -0
- package/dist/{billing-eQZIWeNW.d.cts → billing-cj0eSVrp.d.cts} +59 -1
- package/dist/{billing-eQZIWeNW.d.ts → billing-cj0eSVrp.d.ts} +59 -1
- package/dist/clients/index.cjs +4 -4
- package/dist/clients/index.d.cts +24 -1
- package/dist/clients/index.d.ts +24 -1
- package/dist/clients/index.js +4 -4
- package/dist/index.cjs +7 -7
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +7 -7
- package/dist/proxy/index.cjs +2 -2
- package/dist/proxy/index.js +2 -2
- package/dist/streaming/index.cjs +5 -5
- package/dist/streaming/index.js +5 -5
- package/dist/types/index.d.cts +1 -1
- package/dist/types/index.d.ts +1 -1
- package/package.json +15 -13
- package/src/clients/agents.ts +0 -250
- package/src/clients/billing.ts +0 -197
- package/src/clients/coder.ts +0 -655
- package/src/clients/files.ts +0 -86
- package/src/clients/index.ts +0 -93
- package/src/clients/magma.ts +0 -299
- package/src/clients/mcp.ts +0 -208
- package/src/clients/network.ts +0 -118
- package/src/clients/points.ts +0 -403
- package/src/clients/skills.ts +0 -236
- package/src/clients/social.ts +0 -286
- package/src/clients/stack-management.ts +0 -279
- package/src/clients/task-network.ts +0 -303
- package/src/clients/user.ts +0 -84
- package/src/clients/widgets.ts +0 -171
- package/src/index.ts +0 -387
- package/src/managers/index.ts +0 -10
- package/src/managers/task-manager.ts +0 -332
- package/src/proxy/forwarder.ts +0 -235
- package/src/proxy/index.ts +0 -32
- package/src/proxy/route-handlers.ts +0 -1107
- package/src/streaming/component-stream.ts +0 -319
- package/src/streaming/index.ts +0 -21
- package/src/streaming/sse.ts +0 -266
- package/src/types/agent.ts +0 -108
- package/src/types/billing.ts +0 -121
- package/src/types/chat.ts +0 -58
- package/src/types/coder.ts +0 -345
- package/src/types/credential.ts +0 -111
- package/src/types/file.ts +0 -15
- package/src/types/imagination.ts +0 -50
- package/src/types/index.ts +0 -20
- package/src/types/mcp.ts +0 -35
- package/src/types/network.ts +0 -97
- package/src/types/points.ts +0 -250
- package/src/types/skill.ts +0 -107
- package/src/types/social.ts +0 -109
- package/src/types/stack.ts +0 -269
- package/src/types/task.ts +0 -41
- package/src/types/user.ts +0 -29
- package/src/types/widget.ts +0 -57
- package/src/utils/constants.ts +0 -26
- package/src/utils/errors.ts +0 -169
- package/src/utils/helpers.ts +0 -85
- package/src/utils/index.ts +0 -7
|
@@ -1,1107 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Next.js API Route Handler Factories
|
|
3
|
-
*
|
|
4
|
-
* Create pre-configured route handlers for common patterns.
|
|
5
|
-
*
|
|
6
|
-
* SECURITY NOTES
|
|
7
|
-
* - Every path-position parameter is run through `validateId` before being
|
|
8
|
-
* interpolated into the upstream path. Without this, characters like `?`,
|
|
9
|
-
* `&`, `#`, or `/` in an id would smuggle extra query params or escape
|
|
10
|
-
* the intended namespace.
|
|
11
|
-
* - Every factory supports `extractAuth`; the forwarder receives an
|
|
12
|
-
* `Authorization` header so the upstream can attribute the request to
|
|
13
|
-
* the real caller instead of treating it as anonymous.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import { forwardRequest, forwardJSON, type ForwarderConfig } from './forwarder';
|
|
17
|
-
|
|
18
|
-
export interface RouteHandlerConfig extends ForwarderConfig {
|
|
19
|
-
requireAuth?: boolean;
|
|
20
|
-
enrichResponse?: (data: unknown) => Promise<unknown>;
|
|
21
|
-
/** Extract the caller's bearer token from the incoming Request and
|
|
22
|
-
* forward it upstream as `Authorization: Bearer <token>`. If unset,
|
|
23
|
-
* the handler passes through any inbound `Authorization` header
|
|
24
|
-
* verbatim. Without one of these the upstream sees no auth at all. */
|
|
25
|
-
extractAuth?: (request: Request) => string | null;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export type RouteHandler = (request: Request, context?: { params?: Record<string, string> }) => Promise<Response>;
|
|
29
|
-
|
|
30
|
-
export interface CRUDRouteHandlers {
|
|
31
|
-
GET: RouteHandler;
|
|
32
|
-
POST: RouteHandler;
|
|
33
|
-
PUT?: RouteHandler;
|
|
34
|
-
DELETE?: RouteHandler;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/** Back-compat: `StackRouteHandlerConfig` used to be distinct; now every
|
|
38
|
-
* factory accepts `extractAuth`, so the two configs are identical. */
|
|
39
|
-
export type StackRouteHandlerConfig = RouteHandlerConfig;
|
|
40
|
-
|
|
41
|
-
// ----------------------------------------------------------------------------
|
|
42
|
-
// Shared helpers
|
|
43
|
-
// ----------------------------------------------------------------------------
|
|
44
|
-
|
|
45
|
-
/** Validate that an id/param is a safe alphanumeric/dash/underscore/dot string.
|
|
46
|
-
* Blocks path traversal (`..`, `/`), query smuggling (`?`, `&`, `#`), and
|
|
47
|
-
* header injection (`\r`, `\n`) in one shot. */
|
|
48
|
-
function validateId(id: string | null | undefined, name: string): string {
|
|
49
|
-
if (!id || typeof id !== 'string') {
|
|
50
|
-
throw new Error(`Missing required parameter: ${name}`);
|
|
51
|
-
}
|
|
52
|
-
if (!/^[\w.\-]+$/.test(id)) {
|
|
53
|
-
throw new Error(`Invalid ${name}: contains disallowed characters`);
|
|
54
|
-
}
|
|
55
|
-
return id;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/** Convert a thrown validation error into a 400 response so handlers don't
|
|
59
|
-
* have to pepper try/catch everywhere. */
|
|
60
|
-
function badRequest(err: unknown): Response {
|
|
61
|
-
const message = err instanceof Error ? err.message : 'Bad request';
|
|
62
|
-
return Response.json({ error: message }, { status: 400 });
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function authHeaders(config: RouteHandlerConfig, request: Request): Record<string, string> {
|
|
66
|
-
const headers: Record<string, string> = {};
|
|
67
|
-
if (config.extractAuth) {
|
|
68
|
-
const token = config.extractAuth(request);
|
|
69
|
-
if (token) headers['Authorization'] = `Bearer ${token}`;
|
|
70
|
-
} else {
|
|
71
|
-
const auth = request.headers.get('Authorization');
|
|
72
|
-
if (auth) headers['Authorization'] = auth;
|
|
73
|
-
}
|
|
74
|
-
return headers;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/** Pull an id from the Next-style context first, then fall back to the
|
|
78
|
-
* last path segment. Runs through validateId either way. */
|
|
79
|
-
function idFromContext(
|
|
80
|
-
request: Request,
|
|
81
|
-
context: { params?: Record<string, string | undefined> } | undefined,
|
|
82
|
-
key: string,
|
|
83
|
-
segmentFromEnd = 1,
|
|
84
|
-
): string {
|
|
85
|
-
const fromCtx = context?.params?.[key];
|
|
86
|
-
if (fromCtx) return validateId(fromCtx, key);
|
|
87
|
-
const segs = new URL(request.url).pathname.split('/').filter(Boolean);
|
|
88
|
-
const candidate = segs[segs.length - segmentFromEnd];
|
|
89
|
-
return validateId(candidate, key);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// ============================================================================
|
|
93
|
-
// Agent Route Handlers
|
|
94
|
-
// ============================================================================
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Create agent route handlers
|
|
98
|
-
*/
|
|
99
|
-
export function createAgentRoutes(config: RouteHandlerConfig = {}): CRUDRouteHandlers {
|
|
100
|
-
const baseUrl = config.baseUrl;
|
|
101
|
-
|
|
102
|
-
return {
|
|
103
|
-
GET: async (request: Request) => {
|
|
104
|
-
const url = new URL(request.url);
|
|
105
|
-
const userMid = url.searchParams.get('userMid');
|
|
106
|
-
const visibility = url.searchParams.get('visibility');
|
|
107
|
-
|
|
108
|
-
const path = userMid
|
|
109
|
-
? `/agents?creator_mid=${encodeURIComponent(userMid)}`
|
|
110
|
-
: visibility
|
|
111
|
-
? `/agents?visibility=${encodeURIComponent(visibility)}`
|
|
112
|
-
: '/agents';
|
|
113
|
-
|
|
114
|
-
const { data, status } = await forwardJSON(
|
|
115
|
-
path,
|
|
116
|
-
{ headers: authHeaders(config, request) },
|
|
117
|
-
{ baseUrl },
|
|
118
|
-
);
|
|
119
|
-
|
|
120
|
-
let responseData = data;
|
|
121
|
-
if (config.enrichResponse) {
|
|
122
|
-
responseData = await config.enrichResponse(data);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return Response.json(responseData, { status });
|
|
126
|
-
},
|
|
127
|
-
|
|
128
|
-
POST: async (request: Request) => {
|
|
129
|
-
const body = await request.json();
|
|
130
|
-
const { data, status } = await forwardJSON(
|
|
131
|
-
'/agents',
|
|
132
|
-
{ method: 'POST', body, headers: authHeaders(config, request) },
|
|
133
|
-
{ baseUrl }
|
|
134
|
-
);
|
|
135
|
-
return Response.json(data, { status });
|
|
136
|
-
},
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Create agent detail route handlers (for [id] routes)
|
|
142
|
-
*/
|
|
143
|
-
export function createAgentDetailRoutes(config: RouteHandlerConfig = {}): CRUDRouteHandlers {
|
|
144
|
-
const baseUrl = config.baseUrl;
|
|
145
|
-
|
|
146
|
-
return {
|
|
147
|
-
GET: async (request: Request, context?: { params?: { id?: string } }) => {
|
|
148
|
-
let id: string;
|
|
149
|
-
try { id = idFromContext(request, context, 'id'); } catch (e) { return badRequest(e); }
|
|
150
|
-
const { data, status } = await forwardJSON(
|
|
151
|
-
`/agents/${id}`,
|
|
152
|
-
{ headers: authHeaders(config, request) },
|
|
153
|
-
{ baseUrl },
|
|
154
|
-
);
|
|
155
|
-
|
|
156
|
-
let responseData = data;
|
|
157
|
-
if (config.enrichResponse) {
|
|
158
|
-
responseData = await config.enrichResponse(data);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
return Response.json(responseData, { status });
|
|
162
|
-
},
|
|
163
|
-
|
|
164
|
-
POST: async (request: Request, context?: { params?: { id?: string } }) => {
|
|
165
|
-
let id: string;
|
|
166
|
-
try { id = idFromContext(request, context, 'id'); } catch (e) { return badRequest(e); }
|
|
167
|
-
const body = await request.json();
|
|
168
|
-
const { data, status } = await forwardJSON(
|
|
169
|
-
`/agents/${id}`,
|
|
170
|
-
{ method: 'POST', body, headers: authHeaders(config, request) },
|
|
171
|
-
{ baseUrl }
|
|
172
|
-
);
|
|
173
|
-
return Response.json(data, { status });
|
|
174
|
-
},
|
|
175
|
-
|
|
176
|
-
PUT: async (request: Request, context?: { params?: { id?: string } }) => {
|
|
177
|
-
let id: string;
|
|
178
|
-
try { id = idFromContext(request, context, 'id'); } catch (e) { return badRequest(e); }
|
|
179
|
-
const body = await request.json();
|
|
180
|
-
const { data, status } = await forwardJSON(
|
|
181
|
-
`/agents/${id}`,
|
|
182
|
-
{ method: 'PUT', body, headers: authHeaders(config, request) },
|
|
183
|
-
{ baseUrl }
|
|
184
|
-
);
|
|
185
|
-
return Response.json(data, { status });
|
|
186
|
-
},
|
|
187
|
-
|
|
188
|
-
DELETE: async (request: Request, context?: { params?: { id?: string } }) => {
|
|
189
|
-
let id: string;
|
|
190
|
-
try { id = idFromContext(request, context, 'id'); } catch (e) { return badRequest(e); }
|
|
191
|
-
const { data, status } = await forwardJSON(
|
|
192
|
-
`/agents/${id}`,
|
|
193
|
-
{ method: 'DELETE', headers: authHeaders(config, request) },
|
|
194
|
-
{ baseUrl }
|
|
195
|
-
);
|
|
196
|
-
return Response.json(data, { status });
|
|
197
|
-
},
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* Create agent execute route handler
|
|
203
|
-
*/
|
|
204
|
-
export function createAgentExecuteRoute(config: RouteHandlerConfig = {}): { POST: RouteHandler } {
|
|
205
|
-
const baseUrl = config.baseUrl;
|
|
206
|
-
|
|
207
|
-
return {
|
|
208
|
-
POST: async (request: Request, context?: { params?: { id?: string } }) => {
|
|
209
|
-
let id: string;
|
|
210
|
-
try { id = idFromContext(request, context, 'id', 2); } catch (e) { return badRequest(e); }
|
|
211
|
-
const body = await request.json();
|
|
212
|
-
|
|
213
|
-
const response = await forwardRequest(
|
|
214
|
-
`/agents/${id}/execute`,
|
|
215
|
-
{ method: 'POST', body, stream: true, headers: authHeaders(config, request) },
|
|
216
|
-
{ baseUrl }
|
|
217
|
-
);
|
|
218
|
-
|
|
219
|
-
// Check if streaming
|
|
220
|
-
const contentType = response.headers.get('content-type') || '';
|
|
221
|
-
if (contentType.includes('text/event-stream') && response.body) {
|
|
222
|
-
return new Response(response.body, {
|
|
223
|
-
status: response.status,
|
|
224
|
-
headers: {
|
|
225
|
-
'Content-Type': 'text/event-stream',
|
|
226
|
-
'Cache-Control': 'no-cache',
|
|
227
|
-
'Connection': 'keep-alive',
|
|
228
|
-
},
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
const data = await response.json();
|
|
233
|
-
return Response.json(data, { status: response.status });
|
|
234
|
-
},
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* Create agent enable/disable route handlers
|
|
240
|
-
*/
|
|
241
|
-
export function createAgentToggleRoutes(config: RouteHandlerConfig = {}): {
|
|
242
|
-
enable: { POST: RouteHandler };
|
|
243
|
-
disable: { POST: RouteHandler };
|
|
244
|
-
} {
|
|
245
|
-
const baseUrl = config.baseUrl;
|
|
246
|
-
|
|
247
|
-
return {
|
|
248
|
-
enable: {
|
|
249
|
-
POST: async (request: Request, context?: { params?: { id?: string } }) => {
|
|
250
|
-
let id: string;
|
|
251
|
-
try { id = idFromContext(request, context, 'id', 2); } catch (e) { return badRequest(e); }
|
|
252
|
-
const { data, status } = await forwardJSON(
|
|
253
|
-
`/agents/${id}/enable`,
|
|
254
|
-
{ method: 'POST', headers: authHeaders(config, request) },
|
|
255
|
-
{ baseUrl }
|
|
256
|
-
);
|
|
257
|
-
return Response.json(data, { status });
|
|
258
|
-
},
|
|
259
|
-
},
|
|
260
|
-
disable: {
|
|
261
|
-
POST: async (request: Request, context?: { params?: { id?: string } }) => {
|
|
262
|
-
let id: string;
|
|
263
|
-
try { id = idFromContext(request, context, 'id', 2); } catch (e) { return badRequest(e); }
|
|
264
|
-
const { data, status } = await forwardJSON(
|
|
265
|
-
`/agents/${id}/disable`,
|
|
266
|
-
{ method: 'POST', headers: authHeaders(config, request) },
|
|
267
|
-
{ baseUrl }
|
|
268
|
-
);
|
|
269
|
-
return Response.json(data, { status });
|
|
270
|
-
},
|
|
271
|
-
},
|
|
272
|
-
};
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
// ============================================================================
|
|
276
|
-
// Skill Route Handlers
|
|
277
|
-
// ============================================================================
|
|
278
|
-
|
|
279
|
-
/**
|
|
280
|
-
* Create skill route handlers
|
|
281
|
-
*/
|
|
282
|
-
export function createSkillRoutes(config: RouteHandlerConfig = {}): CRUDRouteHandlers {
|
|
283
|
-
const baseUrl = config.baseUrl;
|
|
284
|
-
|
|
285
|
-
return {
|
|
286
|
-
GET: async (request: Request) => {
|
|
287
|
-
const url = new URL(request.url);
|
|
288
|
-
const scope = url.searchParams.get('scope');
|
|
289
|
-
const creatorMid = url.searchParams.get('creator_mid');
|
|
290
|
-
|
|
291
|
-
let path = '/skills';
|
|
292
|
-
if (scope) path += `?scope=${encodeURIComponent(scope)}`;
|
|
293
|
-
else if (creatorMid) path += `?creator_mid=${encodeURIComponent(creatorMid)}`;
|
|
294
|
-
|
|
295
|
-
const { data, status } = await forwardJSON(
|
|
296
|
-
path,
|
|
297
|
-
{ headers: authHeaders(config, request) },
|
|
298
|
-
{ baseUrl },
|
|
299
|
-
);
|
|
300
|
-
return Response.json(data, { status });
|
|
301
|
-
},
|
|
302
|
-
|
|
303
|
-
POST: async (request: Request) => {
|
|
304
|
-
const body = await request.json();
|
|
305
|
-
const { data, status } = await forwardJSON(
|
|
306
|
-
'/skills',
|
|
307
|
-
{ method: 'POST', body, headers: authHeaders(config, request) },
|
|
308
|
-
{ baseUrl }
|
|
309
|
-
);
|
|
310
|
-
return Response.json(data, { status });
|
|
311
|
-
},
|
|
312
|
-
};
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* Create skill detail route handlers
|
|
317
|
-
*/
|
|
318
|
-
export function createSkillDetailRoutes(config: RouteHandlerConfig = {}): CRUDRouteHandlers {
|
|
319
|
-
const baseUrl = config.baseUrl;
|
|
320
|
-
|
|
321
|
-
return {
|
|
322
|
-
GET: async (request: Request, context?: { params?: { id?: string } }) => {
|
|
323
|
-
let id: string;
|
|
324
|
-
try { id = idFromContext(request, context, 'id'); } catch (e) { return badRequest(e); }
|
|
325
|
-
const { data, status } = await forwardJSON(
|
|
326
|
-
`/skills/${id}`,
|
|
327
|
-
{ headers: authHeaders(config, request) },
|
|
328
|
-
{ baseUrl },
|
|
329
|
-
);
|
|
330
|
-
return Response.json(data, { status });
|
|
331
|
-
},
|
|
332
|
-
|
|
333
|
-
POST: async (request: Request, context?: { params?: { id?: string } }) => {
|
|
334
|
-
let id: string;
|
|
335
|
-
try { id = idFromContext(request, context, 'id'); } catch (e) { return badRequest(e); }
|
|
336
|
-
const body = await request.json();
|
|
337
|
-
const { data, status } = await forwardJSON(
|
|
338
|
-
`/skills/${id}`,
|
|
339
|
-
{ method: 'POST', body, headers: authHeaders(config, request) },
|
|
340
|
-
{ baseUrl }
|
|
341
|
-
);
|
|
342
|
-
return Response.json(data, { status });
|
|
343
|
-
},
|
|
344
|
-
|
|
345
|
-
PUT: async (request: Request, context?: { params?: { id?: string } }) => {
|
|
346
|
-
let id: string;
|
|
347
|
-
try { id = idFromContext(request, context, 'id'); } catch (e) { return badRequest(e); }
|
|
348
|
-
const body = await request.json();
|
|
349
|
-
const { data, status } = await forwardJSON(
|
|
350
|
-
`/skills/${id}`,
|
|
351
|
-
{ method: 'PUT', body, headers: authHeaders(config, request) },
|
|
352
|
-
{ baseUrl }
|
|
353
|
-
);
|
|
354
|
-
return Response.json(data, { status });
|
|
355
|
-
},
|
|
356
|
-
|
|
357
|
-
DELETE: async (request: Request, context?: { params?: { id?: string } }) => {
|
|
358
|
-
let id: string;
|
|
359
|
-
try { id = idFromContext(request, context, 'id'); } catch (e) { return badRequest(e); }
|
|
360
|
-
const { data, status } = await forwardJSON(
|
|
361
|
-
`/skills/${id}`,
|
|
362
|
-
{ method: 'DELETE', headers: authHeaders(config, request) },
|
|
363
|
-
{ baseUrl }
|
|
364
|
-
);
|
|
365
|
-
return Response.json(data, { status });
|
|
366
|
-
},
|
|
367
|
-
};
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
// ============================================================================
|
|
371
|
-
// Widget Route Handlers
|
|
372
|
-
// ============================================================================
|
|
373
|
-
|
|
374
|
-
/**
|
|
375
|
-
* Create widget route handlers (same pattern as skills)
|
|
376
|
-
*/
|
|
377
|
-
export function createWidgetRoutes(config: RouteHandlerConfig = {}): CRUDRouteHandlers {
|
|
378
|
-
const baseUrl = config.baseUrl;
|
|
379
|
-
|
|
380
|
-
return {
|
|
381
|
-
GET: async (request: Request) => {
|
|
382
|
-
const url = new URL(request.url);
|
|
383
|
-
const scope = url.searchParams.get('scope');
|
|
384
|
-
const creatorMid = url.searchParams.get('creator_mid');
|
|
385
|
-
|
|
386
|
-
let path = '/widgets';
|
|
387
|
-
if (scope) path += `?scope=${encodeURIComponent(scope)}`;
|
|
388
|
-
else if (creatorMid) path += `?creator_mid=${encodeURIComponent(creatorMid)}`;
|
|
389
|
-
|
|
390
|
-
const { data, status } = await forwardJSON(
|
|
391
|
-
path,
|
|
392
|
-
{ headers: authHeaders(config, request) },
|
|
393
|
-
{ baseUrl },
|
|
394
|
-
);
|
|
395
|
-
return Response.json(data, { status });
|
|
396
|
-
},
|
|
397
|
-
|
|
398
|
-
POST: async (request: Request) => {
|
|
399
|
-
const body = await request.json();
|
|
400
|
-
const { data, status } = await forwardJSON(
|
|
401
|
-
'/widgets',
|
|
402
|
-
{ method: 'POST', body, headers: authHeaders(config, request) },
|
|
403
|
-
{ baseUrl }
|
|
404
|
-
);
|
|
405
|
-
return Response.json(data, { status });
|
|
406
|
-
},
|
|
407
|
-
};
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
/**
|
|
411
|
-
* Create widget detail route handlers
|
|
412
|
-
*/
|
|
413
|
-
export function createWidgetDetailRoutes(config: RouteHandlerConfig = {}): CRUDRouteHandlers {
|
|
414
|
-
const baseUrl = config.baseUrl;
|
|
415
|
-
|
|
416
|
-
return {
|
|
417
|
-
GET: async (request: Request, context?: { params?: { id?: string } }) => {
|
|
418
|
-
let id: string;
|
|
419
|
-
try { id = idFromContext(request, context, 'id'); } catch (e) { return badRequest(e); }
|
|
420
|
-
const { data, status } = await forwardJSON(
|
|
421
|
-
`/widgets/${id}`,
|
|
422
|
-
{ headers: authHeaders(config, request) },
|
|
423
|
-
{ baseUrl },
|
|
424
|
-
);
|
|
425
|
-
return Response.json(data, { status });
|
|
426
|
-
},
|
|
427
|
-
|
|
428
|
-
POST: async (request: Request, context?: { params?: { id?: string } }) => {
|
|
429
|
-
let id: string;
|
|
430
|
-
try { id = idFromContext(request, context, 'id'); } catch (e) { return badRequest(e); }
|
|
431
|
-
const body = await request.json();
|
|
432
|
-
const { data, status } = await forwardJSON(
|
|
433
|
-
`/widgets/${id}`,
|
|
434
|
-
{ method: 'POST', body, headers: authHeaders(config, request) },
|
|
435
|
-
{ baseUrl }
|
|
436
|
-
);
|
|
437
|
-
return Response.json(data, { status });
|
|
438
|
-
},
|
|
439
|
-
|
|
440
|
-
PUT: async (request: Request, context?: { params?: { id?: string } }) => {
|
|
441
|
-
let id: string;
|
|
442
|
-
try { id = idFromContext(request, context, 'id'); } catch (e) { return badRequest(e); }
|
|
443
|
-
const body = await request.json();
|
|
444
|
-
const { data, status } = await forwardJSON(
|
|
445
|
-
`/widgets/${id}`,
|
|
446
|
-
{ method: 'PUT', body, headers: authHeaders(config, request) },
|
|
447
|
-
{ baseUrl }
|
|
448
|
-
);
|
|
449
|
-
return Response.json(data, { status });
|
|
450
|
-
},
|
|
451
|
-
|
|
452
|
-
DELETE: async (request: Request, context?: { params?: { id?: string } }) => {
|
|
453
|
-
let id: string;
|
|
454
|
-
try { id = idFromContext(request, context, 'id'); } catch (e) { return badRequest(e); }
|
|
455
|
-
const { data, status } = await forwardJSON(
|
|
456
|
-
`/widgets/${id}`,
|
|
457
|
-
{ method: 'DELETE', headers: authHeaders(config, request) },
|
|
458
|
-
{ baseUrl }
|
|
459
|
-
);
|
|
460
|
-
return Response.json(data, { status });
|
|
461
|
-
},
|
|
462
|
-
};
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
// ============================================================================
|
|
466
|
-
// Imagination Route Handlers
|
|
467
|
-
// ============================================================================
|
|
468
|
-
|
|
469
|
-
/**
|
|
470
|
-
* Create imagination route handlers
|
|
471
|
-
*/
|
|
472
|
-
export function createImaginationRoutes(config: RouteHandlerConfig = {}): CRUDRouteHandlers {
|
|
473
|
-
const baseUrl = config.baseUrl;
|
|
474
|
-
|
|
475
|
-
return {
|
|
476
|
-
GET: async (request: Request) => {
|
|
477
|
-
const url = new URL(request.url);
|
|
478
|
-
const idParam = url.searchParams.get('id');
|
|
479
|
-
const creatorMid = url.searchParams.get('creator_mid');
|
|
480
|
-
|
|
481
|
-
let path = '/imaginations';
|
|
482
|
-
if (idParam) {
|
|
483
|
-
try {
|
|
484
|
-
const id = validateId(idParam, 'id');
|
|
485
|
-
path = `/imaginations/${id}`;
|
|
486
|
-
} catch (e) {
|
|
487
|
-
return badRequest(e);
|
|
488
|
-
}
|
|
489
|
-
} else if (creatorMid) {
|
|
490
|
-
path += `?creator_mid=${encodeURIComponent(creatorMid)}`;
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
const { data, status } = await forwardJSON(
|
|
494
|
-
path,
|
|
495
|
-
{ headers: authHeaders(config, request) },
|
|
496
|
-
{ baseUrl },
|
|
497
|
-
);
|
|
498
|
-
return Response.json(data, { status });
|
|
499
|
-
},
|
|
500
|
-
|
|
501
|
-
POST: async (request: Request) => {
|
|
502
|
-
const body = await request.json();
|
|
503
|
-
const { data, status } = await forwardJSON(
|
|
504
|
-
'/imaginations',
|
|
505
|
-
{ method: 'POST', body, headers: authHeaders(config, request) },
|
|
506
|
-
{ baseUrl }
|
|
507
|
-
);
|
|
508
|
-
return Response.json(data, { status });
|
|
509
|
-
},
|
|
510
|
-
};
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
// ============================================================================
|
|
514
|
-
// Coder Route Handlers
|
|
515
|
-
// ============================================================================
|
|
516
|
-
|
|
517
|
-
/**
|
|
518
|
-
* Create coder session route handlers
|
|
519
|
-
*/
|
|
520
|
-
export function createCoderSessionRoutes(config: RouteHandlerConfig = {}): CRUDRouteHandlers {
|
|
521
|
-
const baseUrl = config.baseUrl;
|
|
522
|
-
|
|
523
|
-
return {
|
|
524
|
-
GET: async (request: Request) => {
|
|
525
|
-
const url = new URL(request.url);
|
|
526
|
-
const status = url.searchParams.get('status');
|
|
527
|
-
const limit = url.searchParams.get('limit');
|
|
528
|
-
|
|
529
|
-
let path = '/coder/sessions';
|
|
530
|
-
const params: string[] = [];
|
|
531
|
-
if (status) params.push(`status=${encodeURIComponent(status)}`);
|
|
532
|
-
if (limit) params.push(`limit=${encodeURIComponent(limit)}`);
|
|
533
|
-
if (params.length) path += `?${params.join('&')}`;
|
|
534
|
-
|
|
535
|
-
const { data, status: resStatus } = await forwardJSON(
|
|
536
|
-
path,
|
|
537
|
-
{ headers: authHeaders(config, request) },
|
|
538
|
-
{ baseUrl },
|
|
539
|
-
);
|
|
540
|
-
return Response.json(data, { status: resStatus });
|
|
541
|
-
},
|
|
542
|
-
|
|
543
|
-
POST: async (request: Request) => {
|
|
544
|
-
const body = await request.json();
|
|
545
|
-
const { data, status } = await forwardJSON(
|
|
546
|
-
'/coder/sessions',
|
|
547
|
-
{ method: 'POST', body, headers: authHeaders(config, request) },
|
|
548
|
-
{ baseUrl }
|
|
549
|
-
);
|
|
550
|
-
return Response.json(data, { status });
|
|
551
|
-
},
|
|
552
|
-
};
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
/**
|
|
556
|
-
* Create coder session detail route handlers
|
|
557
|
-
*/
|
|
558
|
-
export function createCoderSessionDetailRoutes(config: RouteHandlerConfig = {}): CRUDRouteHandlers & {
|
|
559
|
-
abort: { POST: RouteHandler };
|
|
560
|
-
} {
|
|
561
|
-
const baseUrl = config.baseUrl;
|
|
562
|
-
|
|
563
|
-
return {
|
|
564
|
-
GET: async (request: Request, context?: { params?: { id?: string } }) => {
|
|
565
|
-
let id: string;
|
|
566
|
-
try { id = idFromContext(request, context, 'id'); } catch (e) { return badRequest(e); }
|
|
567
|
-
const { data, status } = await forwardJSON(
|
|
568
|
-
`/coder/sessions/${id}`,
|
|
569
|
-
{ headers: authHeaders(config, request) },
|
|
570
|
-
{ baseUrl },
|
|
571
|
-
);
|
|
572
|
-
return Response.json(data, { status });
|
|
573
|
-
},
|
|
574
|
-
|
|
575
|
-
POST: async (request: Request, context?: { params?: { id?: string } }) => {
|
|
576
|
-
let id: string;
|
|
577
|
-
try { id = idFromContext(request, context, 'id'); } catch (e) { return badRequest(e); }
|
|
578
|
-
const body = await request.json();
|
|
579
|
-
const { data, status } = await forwardJSON(
|
|
580
|
-
`/coder/sessions/${id}`,
|
|
581
|
-
{ method: 'POST', body, headers: authHeaders(config, request) },
|
|
582
|
-
{ baseUrl }
|
|
583
|
-
);
|
|
584
|
-
return Response.json(data, { status });
|
|
585
|
-
},
|
|
586
|
-
|
|
587
|
-
DELETE: async (request: Request, context?: { params?: { id?: string } }) => {
|
|
588
|
-
let id: string;
|
|
589
|
-
try { id = idFromContext(request, context, 'id'); } catch (e) { return badRequest(e); }
|
|
590
|
-
const { data, status } = await forwardJSON(
|
|
591
|
-
`/coder/sessions/${id}`,
|
|
592
|
-
{ method: 'DELETE', headers: authHeaders(config, request) },
|
|
593
|
-
{ baseUrl }
|
|
594
|
-
);
|
|
595
|
-
return Response.json(data, { status });
|
|
596
|
-
},
|
|
597
|
-
|
|
598
|
-
abort: {
|
|
599
|
-
POST: async (request: Request, context?: { params?: { id?: string } }) => {
|
|
600
|
-
let id: string;
|
|
601
|
-
try { id = idFromContext(request, context, 'id', 2); } catch (e) { return badRequest(e); }
|
|
602
|
-
const { data, status } = await forwardJSON(
|
|
603
|
-
`/coder/sessions/${id}/abort`,
|
|
604
|
-
{ method: 'POST', headers: authHeaders(config, request) },
|
|
605
|
-
{ baseUrl }
|
|
606
|
-
);
|
|
607
|
-
return Response.json(data, { status });
|
|
608
|
-
},
|
|
609
|
-
},
|
|
610
|
-
};
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
/**
|
|
614
|
-
* Create coder execute route handler (with streaming support)
|
|
615
|
-
*/
|
|
616
|
-
export function createCoderExecuteRoute(config: RouteHandlerConfig = {}): { POST: RouteHandler } {
|
|
617
|
-
const baseUrl = config.baseUrl;
|
|
618
|
-
|
|
619
|
-
return {
|
|
620
|
-
POST: async (request: Request) => {
|
|
621
|
-
const body = await request.json();
|
|
622
|
-
|
|
623
|
-
const response = await forwardRequest(
|
|
624
|
-
'/coder/execute',
|
|
625
|
-
{ method: 'POST', body, stream: body.stream, headers: authHeaders(config, request) },
|
|
626
|
-
{ baseUrl }
|
|
627
|
-
);
|
|
628
|
-
|
|
629
|
-
// Check if streaming
|
|
630
|
-
const contentType = response.headers.get('content-type') || '';
|
|
631
|
-
if (contentType.includes('text/event-stream') && response.body) {
|
|
632
|
-
return new Response(response.body, {
|
|
633
|
-
status: response.status,
|
|
634
|
-
headers: {
|
|
635
|
-
'Content-Type': 'text/event-stream',
|
|
636
|
-
'Cache-Control': 'no-cache',
|
|
637
|
-
'Connection': 'keep-alive',
|
|
638
|
-
},
|
|
639
|
-
});
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
const data = await response.json();
|
|
643
|
-
return Response.json(data, { status: response.status });
|
|
644
|
-
},
|
|
645
|
-
};
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
/**
|
|
649
|
-
* Create coder tools route handlers
|
|
650
|
-
*/
|
|
651
|
-
export function createCoderToolsRoutes(config: RouteHandlerConfig = {}): {
|
|
652
|
-
GET: RouteHandler;
|
|
653
|
-
call: { POST: RouteHandler };
|
|
654
|
-
} {
|
|
655
|
-
const baseUrl = config.baseUrl;
|
|
656
|
-
|
|
657
|
-
return {
|
|
658
|
-
GET: async (request: Request) => {
|
|
659
|
-
const { data, status } = await forwardJSON(
|
|
660
|
-
'/coder/tools',
|
|
661
|
-
{ headers: authHeaders(config, request) },
|
|
662
|
-
{ baseUrl },
|
|
663
|
-
);
|
|
664
|
-
return Response.json(data, { status });
|
|
665
|
-
},
|
|
666
|
-
|
|
667
|
-
call: {
|
|
668
|
-
POST: async (request: Request, context?: { params?: { tool?: string } }) => {
|
|
669
|
-
let tool: string;
|
|
670
|
-
try { tool = idFromContext(request, context, 'tool'); } catch (e) { return badRequest(e); }
|
|
671
|
-
const body = await request.json();
|
|
672
|
-
const { data, status } = await forwardJSON(
|
|
673
|
-
`/coder/tools/${tool}`,
|
|
674
|
-
{ method: 'POST', body, headers: authHeaders(config, request) },
|
|
675
|
-
{ baseUrl }
|
|
676
|
-
);
|
|
677
|
-
return Response.json(data, { status });
|
|
678
|
-
},
|
|
679
|
-
},
|
|
680
|
-
};
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
/**
|
|
684
|
-
* Create coder file operation route handlers
|
|
685
|
-
*/
|
|
686
|
-
export function createCoderFilesRoutes(config: RouteHandlerConfig = {}): {
|
|
687
|
-
read: { GET: RouteHandler };
|
|
688
|
-
write: { POST: RouteHandler };
|
|
689
|
-
list: { GET: RouteHandler };
|
|
690
|
-
search: { GET: RouteHandler };
|
|
691
|
-
diff: { POST: RouteHandler };
|
|
692
|
-
} {
|
|
693
|
-
const baseUrl = config.baseUrl;
|
|
694
|
-
|
|
695
|
-
return {
|
|
696
|
-
read: {
|
|
697
|
-
GET: async (request: Request) => {
|
|
698
|
-
const url = new URL(request.url);
|
|
699
|
-
const path = url.searchParams.get('path') || '';
|
|
700
|
-
const sessionId = url.searchParams.get('sessionId');
|
|
701
|
-
const sandboxId = url.searchParams.get('sandboxId');
|
|
702
|
-
|
|
703
|
-
let apiPath = `/coder/files/read?path=${encodeURIComponent(path)}`;
|
|
704
|
-
if (sessionId) apiPath += `&sessionId=${encodeURIComponent(sessionId)}`;
|
|
705
|
-
if (sandboxId) apiPath += `&sandboxId=${encodeURIComponent(sandboxId)}`;
|
|
706
|
-
|
|
707
|
-
const { data, status } = await forwardJSON(
|
|
708
|
-
apiPath,
|
|
709
|
-
{ headers: authHeaders(config, request) },
|
|
710
|
-
{ baseUrl },
|
|
711
|
-
);
|
|
712
|
-
return Response.json(data, { status });
|
|
713
|
-
},
|
|
714
|
-
},
|
|
715
|
-
|
|
716
|
-
write: {
|
|
717
|
-
POST: async (request: Request) => {
|
|
718
|
-
const body = await request.json();
|
|
719
|
-
const { data, status } = await forwardJSON(
|
|
720
|
-
'/coder/files/write',
|
|
721
|
-
{ method: 'POST', body, headers: authHeaders(config, request) },
|
|
722
|
-
{ baseUrl }
|
|
723
|
-
);
|
|
724
|
-
return Response.json(data, { status });
|
|
725
|
-
},
|
|
726
|
-
},
|
|
727
|
-
|
|
728
|
-
list: {
|
|
729
|
-
GET: async (request: Request) => {
|
|
730
|
-
const url = new URL(request.url);
|
|
731
|
-
const path = url.searchParams.get('path') || '.';
|
|
732
|
-
const recursive = url.searchParams.get('recursive');
|
|
733
|
-
const maxDepth = url.searchParams.get('maxDepth');
|
|
734
|
-
const sessionId = url.searchParams.get('sessionId');
|
|
735
|
-
const sandboxId = url.searchParams.get('sandboxId');
|
|
736
|
-
|
|
737
|
-
let apiPath = `/coder/files/list?path=${encodeURIComponent(path)}`;
|
|
738
|
-
if (recursive) apiPath += `&recursive=${encodeURIComponent(recursive)}`;
|
|
739
|
-
if (maxDepth) apiPath += `&maxDepth=${encodeURIComponent(maxDepth)}`;
|
|
740
|
-
if (sessionId) apiPath += `&sessionId=${encodeURIComponent(sessionId)}`;
|
|
741
|
-
if (sandboxId) apiPath += `&sandboxId=${encodeURIComponent(sandboxId)}`;
|
|
742
|
-
|
|
743
|
-
const { data, status } = await forwardJSON(
|
|
744
|
-
apiPath,
|
|
745
|
-
{ headers: authHeaders(config, request) },
|
|
746
|
-
{ baseUrl },
|
|
747
|
-
);
|
|
748
|
-
return Response.json(data, { status });
|
|
749
|
-
},
|
|
750
|
-
},
|
|
751
|
-
|
|
752
|
-
search: {
|
|
753
|
-
GET: async (request: Request) => {
|
|
754
|
-
const url = new URL(request.url);
|
|
755
|
-
const pattern = url.searchParams.get('pattern') || '';
|
|
756
|
-
const path = url.searchParams.get('path');
|
|
757
|
-
const filePattern = url.searchParams.get('filePattern');
|
|
758
|
-
const sessionId = url.searchParams.get('sessionId');
|
|
759
|
-
const sandboxId = url.searchParams.get('sandboxId');
|
|
760
|
-
|
|
761
|
-
let apiPath = `/coder/files/search?pattern=${encodeURIComponent(pattern)}`;
|
|
762
|
-
if (path) apiPath += `&path=${encodeURIComponent(path)}`;
|
|
763
|
-
if (filePattern) apiPath += `&filePattern=${encodeURIComponent(filePattern)}`;
|
|
764
|
-
if (sessionId) apiPath += `&sessionId=${encodeURIComponent(sessionId)}`;
|
|
765
|
-
if (sandboxId) apiPath += `&sandboxId=${encodeURIComponent(sandboxId)}`;
|
|
766
|
-
|
|
767
|
-
const { data, status } = await forwardJSON(
|
|
768
|
-
apiPath,
|
|
769
|
-
{ headers: authHeaders(config, request) },
|
|
770
|
-
{ baseUrl },
|
|
771
|
-
);
|
|
772
|
-
return Response.json(data, { status });
|
|
773
|
-
},
|
|
774
|
-
},
|
|
775
|
-
|
|
776
|
-
diff: {
|
|
777
|
-
POST: async (request: Request) => {
|
|
778
|
-
const body = await request.json();
|
|
779
|
-
const { data, status } = await forwardJSON(
|
|
780
|
-
'/coder/files/diff',
|
|
781
|
-
{ method: 'POST', body, headers: authHeaders(config, request) },
|
|
782
|
-
{ baseUrl }
|
|
783
|
-
);
|
|
784
|
-
return Response.json(data, { status });
|
|
785
|
-
},
|
|
786
|
-
},
|
|
787
|
-
};
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
/**
|
|
791
|
-
* Create coder sandbox route handlers
|
|
792
|
-
*/
|
|
793
|
-
export function createCoderSandboxRoutes(config: RouteHandlerConfig = {}): {
|
|
794
|
-
create: { POST: RouteHandler };
|
|
795
|
-
get: { GET: RouteHandler };
|
|
796
|
-
exec: { POST: RouteHandler };
|
|
797
|
-
destroy: { DELETE: RouteHandler };
|
|
798
|
-
} {
|
|
799
|
-
const baseUrl = config.baseUrl;
|
|
800
|
-
|
|
801
|
-
return {
|
|
802
|
-
create: {
|
|
803
|
-
POST: async (request: Request) => {
|
|
804
|
-
const body = await request.json();
|
|
805
|
-
const { data, status } = await forwardJSON(
|
|
806
|
-
'/coder/sandbox',
|
|
807
|
-
{ method: 'POST', body, headers: authHeaders(config, request) },
|
|
808
|
-
{ baseUrl }
|
|
809
|
-
);
|
|
810
|
-
return Response.json(data, { status });
|
|
811
|
-
},
|
|
812
|
-
},
|
|
813
|
-
|
|
814
|
-
get: {
|
|
815
|
-
GET: async (request: Request, context?: { params?: { id?: string } }) => {
|
|
816
|
-
let id: string;
|
|
817
|
-
try { id = idFromContext(request, context, 'id'); } catch (e) { return badRequest(e); }
|
|
818
|
-
const { data, status } = await forwardJSON(
|
|
819
|
-
`/coder/sandbox/${id}`,
|
|
820
|
-
{ headers: authHeaders(config, request) },
|
|
821
|
-
{ baseUrl },
|
|
822
|
-
);
|
|
823
|
-
return Response.json(data, { status });
|
|
824
|
-
},
|
|
825
|
-
},
|
|
826
|
-
|
|
827
|
-
exec: {
|
|
828
|
-
POST: async (request: Request, context?: { params?: { id?: string } }) => {
|
|
829
|
-
let id: string;
|
|
830
|
-
try { id = idFromContext(request, context, 'id', 2); } catch (e) { return badRequest(e); }
|
|
831
|
-
const body = await request.json();
|
|
832
|
-
|
|
833
|
-
const response = await forwardRequest(
|
|
834
|
-
`/coder/sandbox/${id}/exec`,
|
|
835
|
-
{ method: 'POST', body, stream: body.stream, headers: authHeaders(config, request) },
|
|
836
|
-
{ baseUrl }
|
|
837
|
-
);
|
|
838
|
-
|
|
839
|
-
// Check if streaming
|
|
840
|
-
const contentType = response.headers.get('content-type') || '';
|
|
841
|
-
if (contentType.includes('text/event-stream') && response.body) {
|
|
842
|
-
return new Response(response.body, {
|
|
843
|
-
status: response.status,
|
|
844
|
-
headers: {
|
|
845
|
-
'Content-Type': 'text/event-stream',
|
|
846
|
-
'Cache-Control': 'no-cache',
|
|
847
|
-
'Connection': 'keep-alive',
|
|
848
|
-
},
|
|
849
|
-
});
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
const data = await response.json();
|
|
853
|
-
return Response.json(data, { status: response.status });
|
|
854
|
-
},
|
|
855
|
-
},
|
|
856
|
-
|
|
857
|
-
destroy: {
|
|
858
|
-
DELETE: async (request: Request, context?: { params?: { id?: string } }) => {
|
|
859
|
-
let id: string;
|
|
860
|
-
try { id = idFromContext(request, context, 'id'); } catch (e) { return badRequest(e); }
|
|
861
|
-
const { data, status } = await forwardJSON(
|
|
862
|
-
`/coder/sandbox/${id}`,
|
|
863
|
-
{ method: 'DELETE', headers: authHeaders(config, request) },
|
|
864
|
-
{ baseUrl }
|
|
865
|
-
);
|
|
866
|
-
return Response.json(data, { status });
|
|
867
|
-
},
|
|
868
|
-
},
|
|
869
|
-
};
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
/**
|
|
873
|
-
* Create coder command execution route handlers
|
|
874
|
-
*/
|
|
875
|
-
export function createCoderExecRoutes(config: RouteHandlerConfig = {}): {
|
|
876
|
-
POST: RouteHandler;
|
|
877
|
-
stream: { POST: RouteHandler };
|
|
878
|
-
} {
|
|
879
|
-
const baseUrl = config.baseUrl;
|
|
880
|
-
|
|
881
|
-
return {
|
|
882
|
-
POST: async (request: Request) => {
|
|
883
|
-
const body = await request.json();
|
|
884
|
-
const { data, status } = await forwardJSON(
|
|
885
|
-
'/coder/exec',
|
|
886
|
-
{ method: 'POST', body, headers: authHeaders(config, request) },
|
|
887
|
-
{ baseUrl }
|
|
888
|
-
);
|
|
889
|
-
return Response.json(data, { status });
|
|
890
|
-
},
|
|
891
|
-
|
|
892
|
-
stream: {
|
|
893
|
-
POST: async (request: Request) => {
|
|
894
|
-
const body = await request.json();
|
|
895
|
-
|
|
896
|
-
const response = await forwardRequest(
|
|
897
|
-
'/coder/exec/stream',
|
|
898
|
-
{ method: 'POST', body, stream: true, headers: authHeaders(config, request) },
|
|
899
|
-
{ baseUrl }
|
|
900
|
-
);
|
|
901
|
-
|
|
902
|
-
if (response.body) {
|
|
903
|
-
return new Response(response.body, {
|
|
904
|
-
status: response.status,
|
|
905
|
-
headers: {
|
|
906
|
-
'Content-Type': 'text/event-stream',
|
|
907
|
-
'Cache-Control': 'no-cache',
|
|
908
|
-
'Connection': 'keep-alive',
|
|
909
|
-
},
|
|
910
|
-
});
|
|
911
|
-
}
|
|
912
|
-
|
|
913
|
-
const data = await response.json();
|
|
914
|
-
return Response.json(data, { status: response.status });
|
|
915
|
-
},
|
|
916
|
-
},
|
|
917
|
-
};
|
|
918
|
-
}
|
|
919
|
-
|
|
920
|
-
// ============================================================================
|
|
921
|
-
// Stack Management Route Handlers
|
|
922
|
-
// ============================================================================
|
|
923
|
-
|
|
924
|
-
/**
|
|
925
|
-
* Create stack CRUD route handlers (list + create)
|
|
926
|
-
*/
|
|
927
|
-
export function createStackRoutes(config: StackRouteHandlerConfig = {}): CRUDRouteHandlers {
|
|
928
|
-
const baseUrl = config.baseUrl;
|
|
929
|
-
|
|
930
|
-
return {
|
|
931
|
-
GET: async (request: Request) => {
|
|
932
|
-
const { data, status } = await forwardJSON(
|
|
933
|
-
'/api/v2/stacks',
|
|
934
|
-
{ headers: authHeaders(config, request) },
|
|
935
|
-
{ baseUrl }
|
|
936
|
-
);
|
|
937
|
-
return Response.json(data, { status });
|
|
938
|
-
},
|
|
939
|
-
|
|
940
|
-
POST: async (request: Request) => {
|
|
941
|
-
const body = await request.json();
|
|
942
|
-
const { data, status } = await forwardJSON(
|
|
943
|
-
'/api/v2/stacks',
|
|
944
|
-
{ method: 'POST', body, headers: authHeaders(config, request) },
|
|
945
|
-
{ baseUrl }
|
|
946
|
-
);
|
|
947
|
-
return Response.json(data, { status });
|
|
948
|
-
},
|
|
949
|
-
};
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
/**
|
|
953
|
-
* Create stack detail route handlers (get, update, delete by [stackId])
|
|
954
|
-
*/
|
|
955
|
-
export function createStackDetailRoutes(config: StackRouteHandlerConfig = {}): CRUDRouteHandlers {
|
|
956
|
-
const baseUrl = config.baseUrl;
|
|
957
|
-
|
|
958
|
-
return {
|
|
959
|
-
GET: async (request: Request, context?: { params?: { stackId?: string } }) => {
|
|
960
|
-
let stackId: string;
|
|
961
|
-
try { stackId = validateId(context?.params?.stackId, 'stackId'); } catch (e) { return badRequest(e); }
|
|
962
|
-
const { data, status } = await forwardJSON(
|
|
963
|
-
`/api/v2/stacks/${stackId}`,
|
|
964
|
-
{ headers: authHeaders(config, request) },
|
|
965
|
-
{ baseUrl }
|
|
966
|
-
);
|
|
967
|
-
return Response.json(data, { status });
|
|
968
|
-
},
|
|
969
|
-
|
|
970
|
-
POST: async () => Response.json({ error: 'Method not allowed' }, { status: 405 }),
|
|
971
|
-
|
|
972
|
-
PUT: async (request: Request, context?: { params?: { stackId?: string } }) => {
|
|
973
|
-
let stackId: string;
|
|
974
|
-
try { stackId = validateId(context?.params?.stackId, 'stackId'); } catch (e) { return badRequest(e); }
|
|
975
|
-
const body = await request.json();
|
|
976
|
-
const { data, status } = await forwardJSON(
|
|
977
|
-
`/api/v2/stacks/${stackId}`,
|
|
978
|
-
{ method: 'PATCH', body, headers: authHeaders(config, request) },
|
|
979
|
-
{ baseUrl }
|
|
980
|
-
);
|
|
981
|
-
return Response.json(data, { status });
|
|
982
|
-
},
|
|
983
|
-
|
|
984
|
-
DELETE: async (request: Request, context?: { params?: { stackId?: string } }) => {
|
|
985
|
-
let stackId: string;
|
|
986
|
-
try { stackId = validateId(context?.params?.stackId, 'stackId'); } catch (e) { return badRequest(e); }
|
|
987
|
-
const { data, status } = await forwardJSON(
|
|
988
|
-
`/api/v2/stacks/${stackId}`,
|
|
989
|
-
{ method: 'DELETE', headers: authHeaders(config, request) },
|
|
990
|
-
{ baseUrl }
|
|
991
|
-
);
|
|
992
|
-
return Response.json(data, { status });
|
|
993
|
-
},
|
|
994
|
-
};
|
|
995
|
-
}
|
|
996
|
-
|
|
997
|
-
/**
|
|
998
|
-
* Create stack keys route handlers (list + create + revoke)
|
|
999
|
-
*/
|
|
1000
|
-
export function createStackKeysRoutes(config: StackRouteHandlerConfig = {}): CRUDRouteHandlers {
|
|
1001
|
-
const baseUrl = config.baseUrl;
|
|
1002
|
-
|
|
1003
|
-
return {
|
|
1004
|
-
GET: async (request: Request, context?: { params?: { stackId?: string } }) => {
|
|
1005
|
-
let stackId: string;
|
|
1006
|
-
try { stackId = validateId(context?.params?.stackId, 'stackId'); } catch (e) { return badRequest(e); }
|
|
1007
|
-
const { data, status } = await forwardJSON(
|
|
1008
|
-
`/api/v2/stacks/${stackId}/keys`,
|
|
1009
|
-
{ headers: authHeaders(config, request) },
|
|
1010
|
-
{ baseUrl }
|
|
1011
|
-
);
|
|
1012
|
-
return Response.json(data, { status });
|
|
1013
|
-
},
|
|
1014
|
-
|
|
1015
|
-
POST: async (request: Request, context?: { params?: { stackId?: string } }) => {
|
|
1016
|
-
let stackId: string;
|
|
1017
|
-
try { stackId = validateId(context?.params?.stackId, 'stackId'); } catch (e) { return badRequest(e); }
|
|
1018
|
-
const body = await request.json();
|
|
1019
|
-
const { data, status } = await forwardJSON(
|
|
1020
|
-
`/api/v2/stacks/${stackId}/keys`,
|
|
1021
|
-
{ method: 'POST', body, headers: authHeaders(config, request) },
|
|
1022
|
-
{ baseUrl }
|
|
1023
|
-
);
|
|
1024
|
-
return Response.json(data, { status });
|
|
1025
|
-
},
|
|
1026
|
-
|
|
1027
|
-
DELETE: async (request: Request, context?: { params?: { stackId?: string; keyId?: string } }) => {
|
|
1028
|
-
let stackId: string;
|
|
1029
|
-
let keyId: string;
|
|
1030
|
-
try {
|
|
1031
|
-
stackId = validateId(context?.params?.stackId, 'stackId');
|
|
1032
|
-
keyId = validateId(context?.params?.keyId, 'keyId');
|
|
1033
|
-
} catch (e) { return badRequest(e); }
|
|
1034
|
-
const { data, status } = await forwardJSON(
|
|
1035
|
-
`/api/v2/stacks/${stackId}/keys/${keyId}`,
|
|
1036
|
-
{ method: 'DELETE', headers: authHeaders(config, request) },
|
|
1037
|
-
{ baseUrl }
|
|
1038
|
-
);
|
|
1039
|
-
return Response.json(data, { status });
|
|
1040
|
-
},
|
|
1041
|
-
};
|
|
1042
|
-
}
|
|
1043
|
-
|
|
1044
|
-
/**
|
|
1045
|
-
* Create stack members route handlers
|
|
1046
|
-
*/
|
|
1047
|
-
export function createStackMembersRoutes(config: StackRouteHandlerConfig = {}): {
|
|
1048
|
-
GET: RouteHandler;
|
|
1049
|
-
stats: { GET: RouteHandler };
|
|
1050
|
-
updateRole: { PATCH: RouteHandler };
|
|
1051
|
-
} {
|
|
1052
|
-
const baseUrl = config.baseUrl;
|
|
1053
|
-
|
|
1054
|
-
return {
|
|
1055
|
-
GET: async (request: Request, context?: { params?: { stackId?: string } }) => {
|
|
1056
|
-
let stackId: string;
|
|
1057
|
-
try { stackId = validateId(context?.params?.stackId, 'stackId'); } catch (e) { return badRequest(e); }
|
|
1058
|
-
const url = new URL(request.url);
|
|
1059
|
-
const params = new URLSearchParams();
|
|
1060
|
-
const limit = url.searchParams.get('limit');
|
|
1061
|
-
const offset = url.searchParams.get('offset');
|
|
1062
|
-
const role = url.searchParams.get('role');
|
|
1063
|
-
if (limit) params.set('limit', limit);
|
|
1064
|
-
if (offset) params.set('offset', offset);
|
|
1065
|
-
if (role) params.set('role', role);
|
|
1066
|
-
const qs = params.toString() ? `?${params}` : '';
|
|
1067
|
-
|
|
1068
|
-
const { data, status } = await forwardJSON(
|
|
1069
|
-
`/api/v2/stacks/${stackId}/members${qs}`,
|
|
1070
|
-
{ headers: authHeaders(config, request) },
|
|
1071
|
-
{ baseUrl }
|
|
1072
|
-
);
|
|
1073
|
-
return Response.json(data, { status });
|
|
1074
|
-
},
|
|
1075
|
-
|
|
1076
|
-
stats: {
|
|
1077
|
-
GET: async (request: Request, context?: { params?: { stackId?: string } }) => {
|
|
1078
|
-
let stackId: string;
|
|
1079
|
-
try { stackId = validateId(context?.params?.stackId, 'stackId'); } catch (e) { return badRequest(e); }
|
|
1080
|
-
const { data, status } = await forwardJSON(
|
|
1081
|
-
`/api/v2/stacks/${stackId}/members/stats`,
|
|
1082
|
-
{ headers: authHeaders(config, request) },
|
|
1083
|
-
{ baseUrl }
|
|
1084
|
-
);
|
|
1085
|
-
return Response.json(data, { status });
|
|
1086
|
-
},
|
|
1087
|
-
},
|
|
1088
|
-
|
|
1089
|
-
updateRole: {
|
|
1090
|
-
PATCH: async (request: Request, context?: { params?: { stackId?: string; userId?: string } }) => {
|
|
1091
|
-
let stackId: string;
|
|
1092
|
-
let userId: string;
|
|
1093
|
-
try {
|
|
1094
|
-
stackId = validateId(context?.params?.stackId, 'stackId');
|
|
1095
|
-
userId = validateId(context?.params?.userId, 'userId');
|
|
1096
|
-
} catch (e) { return badRequest(e); }
|
|
1097
|
-
const body = await request.json();
|
|
1098
|
-
const { data, status } = await forwardJSON(
|
|
1099
|
-
`/api/v2/stacks/${stackId}/members/${userId}/role`,
|
|
1100
|
-
{ method: 'PATCH', body, headers: authHeaders(config, request) },
|
|
1101
|
-
{ baseUrl }
|
|
1102
|
-
);
|
|
1103
|
-
return Response.json(data, { status });
|
|
1104
|
-
},
|
|
1105
|
-
},
|
|
1106
|
-
};
|
|
1107
|
-
}
|