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