Public: anyone can read this; the crew can change it.

A repository's prompt routes leave api.ts for src/http/api/prompts.ts #7045

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

mason/forge:mason/6334-a-repository-s-prompt-routes-leave-api-t → main 1 commit fork

  • Merged. mason/6334-a-repository-s-prompt-routes-leave-api-t was merged into main as b0b4487.

Review

Sign in to review this change.
2 files changed +84 −68
src/http/api.ts +2 −68
@@ -269,12 +269,6 @@ import {
269269 listAppDomains,
270270 removeAppDomain,
271271 } from "../actions/domains.ts";
272 import {
273 addPromptSource,
274 listPromptSources,
275 removePromptSource,
276 runPromptSource,
277 } from "../actions/prompts.ts";
278272 import { listDomains } from "../core/domains.ts";
279273 import {
280274 migrateMessage,
@@ -419,6 +413,7 @@ import { agentRoutes } from "./api/agents.ts";
419413 import { boardRoutes } from "./api/boards.ts";
420414 import { labelsRoutes } from "./api/labels.ts";
421415 import { orgRoutes } from "./api/orgs.ts";
416 import { promptRoutes } from "./api/prompts.ts";
422417 import { secretRoutes } from "./api/secrets.ts";
423418 import { upstreamRoutes } from "./api/upstream.ts";
424419 import type { Router } from "./router.ts";
@@ -5426,68 +5421,7 @@ export function apiRoutes(router: Router<Handler>): void {
54265421
54275422 egressGrantRoutes(router);
54285423
5429 // Where the crew's next tell comes from when nobody is typing
5430 // (docs/APPS.md, "Prompts from Instagram"). Admin scope and admin over
5431 // the repository; the token goes in once and never comes back out.
5432 router.add("GET", "/api/v1/repos/:owner/:name/prompts", (ctx) => {
5433 notePhase(ctx.request, "session", takeSessionTime(ctx.request));
5434 const denied = requireScope(ctx, "admin");
5435 if (denied) return denied;
5436 const repo = loadRepo(ctx);
5437 if (!repo) return notFound();
5438 const listed = timePhase(ctx.request, "prompts", () => listPromptSources(ctx.app, ctx.auth.user, repo));
5439 if (!listed.ok) return respondAccess(listed.error, 422);
5440 return timePhase(ctx.request, "render", () => json({ items: listed.value, next_cursor: null }));
5441 });
5442
5443 router.add("POST", "/api/v1/repos/:owner/:name/prompts", async (ctx) => {
5444 const denied = requireScope(ctx, "admin");
5445 if (denied) return denied;
5446 const repo = loadRepo(ctx);
5447 if (!repo) return notFound();
5448 const input = await body(ctx.request);
5449 const added = addPromptSource(ctx.app, ctx.auth.user, repo, {
5450 kind: str(input.kind),
5451 token: str(input.token),
5452 at: str(input.at),
5453 });
5454 if (!added.ok) return respondAccess(added.error, 422);
5455 return json(added.value, 201);
5456 });
5457
5458 router.add(
5459 "POST",
5460 "/api/v1/repos/:owner/:name/prompts/:id/run",
5461 async (ctx) => {
5462 const denied = requireScope(ctx, "admin");
5463 if (denied) return denied;
5464 const repo = loadRepo(ctx);
5465 if (!repo) return notFound();
5466 const ran = await runPromptSource(
5467 ctx.app,
5468 ctx.auth.user,
5469 repo,
5470 ctx.params.id ?? "",
5471 );
5472 if (!ran.ok) return respondAccess(ran.error, 422);
5473 return json(ran.value);
5474 },
5475 );
5476
5477 router.add("DELETE", "/api/v1/repos/:owner/:name/prompts/:id", (ctx) => {
5478 const denied = requireScope(ctx, "admin");
5479 if (denied) return denied;
5480 const repo = loadRepo(ctx);
5481 if (!repo) return notFound();
5482 const removed = removePromptSource(
5483 ctx.app,
5484 ctx.auth.user,
5485 repo,
5486 ctx.params.id ?? "",
5487 );
5488 if (!removed.ok) return respondAccess(removed.error, 422);
5489 return json({}, 200);
5490 });
5424 promptRoutes(router);
54915425
54925426 secretRoutes(router);
54935427
src/http/api/prompts.ts added +82
@@ -0,0 +1,82 @@
1 /**
2 * A repository's prompt sources over the API:
3 * `/api/v1/repos/:owner/:name/prompts` — list, add, run one now, remove.
4 * Moved out of `api.ts` (#6334); the rules live in `actions/prompts.ts`.
5 */
6
7 import {
8 addPromptSource,
9 listPromptSources,
10 removePromptSource,
11 runPromptSource,
12 } from "../../actions/prompts.ts";
13 import { notePhase, takeSessionTime, timePhase } from "../../core/route_timing.ts";
14 import { loadRepo } from "../api.ts";
15 import type { Handler } from "../context.ts";
16 import { body, json, notFound, requireScope, respondAccess, str } from "../respond.ts";
17 import type { Router } from "../router.ts";
18
19 export function promptRoutes(router: Router<Handler>): void {
20 // Where the crew's next tell comes from when nobody is typing
21 // (docs/APPS.md, "Prompts from Instagram"). Admin scope and admin over
22 // the repository; the token goes in once and never comes back out.
23 router.add("GET", "/api/v1/repos/:owner/:name/prompts", (ctx) => {
24 notePhase(ctx.request, "session", takeSessionTime(ctx.request));
25 const denied = requireScope(ctx, "admin");
26 if (denied) return denied;
27 const repo = loadRepo(ctx);
28 if (!repo) return notFound();
29 const listed = timePhase(ctx.request, "prompts", () => listPromptSources(ctx.app, ctx.auth.user, repo));
30 if (!listed.ok) return respondAccess(listed.error, 422);
31 return timePhase(ctx.request, "render", () => json({ items: listed.value, next_cursor: null }));
32 });
33
34 router.add("POST", "/api/v1/repos/:owner/:name/prompts", async (ctx) => {
35 const denied = requireScope(ctx, "admin");
36 if (denied) return denied;
37 const repo = loadRepo(ctx);
38 if (!repo) return notFound();
39 const input = await body(ctx.request);
40 const added = addPromptSource(ctx.app, ctx.auth.user, repo, {
41 kind: str(input.kind),
42 token: str(input.token),
43 at: str(input.at),
44 });
45 if (!added.ok) return respondAccess(added.error, 422);
46 return json(added.value, 201);
47 });
48
49 router.add(
50 "POST",
51 "/api/v1/repos/:owner/:name/prompts/:id/run",
52 async (ctx) => {
53 const denied = requireScope(ctx, "admin");
54 if (denied) return denied;
55 const repo = loadRepo(ctx);
56 if (!repo) return notFound();
57 const ran = await runPromptSource(
58 ctx.app,
59 ctx.auth.user,
60 repo,
61 ctx.params.id ?? "",
62 );
63 if (!ran.ok) return respondAccess(ran.error, 422);
64 return json(ran.value);
65 },
66 );
67
68 router.add("DELETE", "/api/v1/repos/:owner/:name/prompts/:id", (ctx) => {
69 const denied = requireScope(ctx, "admin");
70 if (denied) return denied;
71 const repo = loadRepo(ctx);
72 if (!repo) return notFound();
73 const removed = removePromptSource(
74 ctx.app,
75 ctx.auth.user,
76 repo,
77 ctx.params.id ?? "",
78 );
79 if (!removed.ok) return respondAccess(removed.error, 422);
80 return json({}, 200);
81 });
82 }

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs