CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
Blame · Line-by-line history
api-docs.tsx
Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.
| 45e31d0 | 1 | /** |
| 2 | * API Documentation — interactive docs page. | |
| 3 | */ | |
| 4 | ||
| 5 | import { Hono } from "hono"; | |
| 6 | import { Layout } from "../views/layout"; | |
| 7 | import { softAuth } from "../middleware/auth"; | |
| 8 | import type { AuthEnv } from "../middleware/auth"; | |
| 9 | ||
| 10 | const apiDocs = new Hono<AuthEnv>(); | |
| 11 | ||
| 12 | apiDocs.get("/api/docs", softAuth, (c) => { | |
| 13 | const user = c.get("user"); | |
| 14 | ||
| 15 | return c.html( | |
| 16 | <Layout title="API Documentation" user={user}> | |
| 17 | <div style="max-width:900px"> | |
| 18 | <h1 style="margin-bottom:8px">gluecron API</h1> | |
| 19 | <p style="color:var(--text-muted);margin-bottom:32px"> | |
| 20 | Complete REST API for programmatic access to repositories, issues, pull requests, and more. | |
| 21 | </p> | |
| 22 | ||
| 23 | <ApiSection | |
| 24 | title="Authentication" | |
| 25 | description="All API requests require authentication via a personal access token." | |
| 26 | > | |
| 27 | <CodeExample | |
| 28 | title="Using a Bearer token" | |
| 29 | code={`curl -H "Authorization: Bearer glue_your_token_here" \\ | |
| 30 | https://gluecron.com/api/v2/user`} | |
| 31 | /> | |
| 32 | <p style="font-size:14px;color:var(--text-muted);margin-top:12px"> | |
| 33 | Create a token at <a href="/settings/tokens">/settings/tokens</a>. Tokens support scopes: <code>repo</code>, <code>user</code>, <code>admin</code>. | |
| 34 | </p> | |
| 35 | </ApiSection> | |
| 36 | ||
| 37 | <ApiSection title="Rate Limits" description="Rate limits are applied per IP address."> | |
| 38 | <EndpointTable | |
| 39 | rows={[ | |
| 40 | ["API routes", "100 req/min"], | |
| 41 | ["Search", "30 req/min"], | |
| 42 | ["Authentication", "10 req/min"], | |
| 43 | ["Git operations", "60 req/min"], | |
| 44 | ]} | |
| 45 | headers={["Scope", "Limit"]} | |
| 46 | /> | |
| 47 | <p style="font-size:13px;color:var(--text-muted);margin-top:8px"> | |
| 48 | Rate limit info is included in response headers: <code>X-RateLimit-Limit</code>, <code>X-RateLimit-Remaining</code>, <code>X-RateLimit-Reset</code>. | |
| 49 | </p> | |
| 50 | </ApiSection> | |
| 51 | ||
| 52 | <ApiSection title="Users"> | |
| 53 | <Endpoint method="GET" path="/api/v2/user" description="Get authenticated user" auth /> | |
| 54 | <Endpoint method="GET" path="/api/v2/users/:username" description="Get user by username" /> | |
| 55 | <Endpoint method="PATCH" path="/api/v2/user" description="Update profile (displayName, bio, avatarUrl)" auth scope="user" /> | |
| 56 | </ApiSection> | |
| 57 | ||
| 58 | <ApiSection title="Repositories"> | |
| 59 | <Endpoint method="GET" path="/api/v2/users/:username/repos" description="List user repositories" params="sort=updated|stars|name" /> | |
| 60 | <Endpoint method="POST" path="/api/v2/repos" description="Create repository" auth scope="repo" /> | |
| 61 | <Endpoint method="GET" path="/api/v2/repos/:owner/:repo" description="Get repository details" /> | |
| 62 | <Endpoint method="PATCH" path="/api/v2/repos/:owner/:repo" description="Update repository (description, visibility)" auth scope="repo" /> | |
| 63 | <Endpoint method="DELETE" path="/api/v2/repos/:owner/:repo" description="Delete repository" auth scope="admin" /> | |
| 64 | </ApiSection> | |
| 65 | ||
| 66 | <ApiSection title="Branches"> | |
| 67 | <Endpoint method="GET" path="/api/v2/repos/:owner/:repo/branches" description="List all branches" /> | |
| 68 | </ApiSection> | |
| 69 | ||
| 70 | <ApiSection title="Commits"> | |
| 71 | <Endpoint method="GET" path="/api/v2/repos/:owner/:repo/commits" description="List commits" params="ref, limit, offset" /> | |
| 72 | <Endpoint method="GET" path="/api/v2/repos/:owner/:repo/commits/:sha" description="Get commit with diff" /> | |
| 73 | </ApiSection> | |
| 74 | ||
| 75 | <ApiSection title="File Contents"> | |
| 76 | <Endpoint method="GET" path="/api/v2/repos/:owner/:repo/tree/:ref" description="Get file tree at ref" params="path" /> | |
| 77 | <Endpoint method="GET" path="/api/v2/repos/:owner/:repo/contents/:path" description="Get file contents" params="ref" /> | |
| 78 | </ApiSection> | |
| 79 | ||
| 80 | <ApiSection title="Issues"> | |
| 81 | <Endpoint method="GET" path="/api/v2/repos/:owner/:repo/issues" description="List issues" params="state=open|closed, limit" /> | |
| 82 | <Endpoint method="POST" path="/api/v2/repos/:owner/:repo/issues" description="Create issue" auth scope="repo" /> | |
| 83 | <Endpoint method="GET" path="/api/v2/repos/:owner/:repo/issues/:number" description="Get issue with comments" /> | |
| 84 | <Endpoint method="PATCH" path="/api/v2/repos/:owner/:repo/issues/:number" description="Update issue (title, body, state)" auth scope="repo" /> | |
| 85 | <Endpoint method="POST" path="/api/v2/repos/:owner/:repo/issues/:number/comments" description="Add comment to issue" auth scope="repo" /> | |
| 86 | </ApiSection> | |
| 87 | ||
| 88 | <ApiSection title="Pull Requests"> | |
| 89 | <Endpoint method="GET" path="/api/v2/repos/:owner/:repo/pulls" description="List pull requests" params="state=open|closed|merged" /> | |
| 90 | <Endpoint method="POST" path="/api/v2/repos/:owner/:repo/pulls" description="Create pull request" auth scope="repo" /> | |
| 91 | <Endpoint method="GET" path="/api/v2/repos/:owner/:repo/pulls/:number" description="Get PR with comments" /> | |
| 92 | </ApiSection> | |
| 93 | ||
| 94 | <ApiSection title="Stars"> | |
| 95 | <Endpoint method="PUT" path="/api/v2/repos/:owner/:repo/star" description="Star a repository" auth /> | |
| 96 | <Endpoint method="DELETE" path="/api/v2/repos/:owner/:repo/star" description="Unstar a repository" auth /> | |
| 97 | </ApiSection> | |
| 98 | ||
| 99 | <ApiSection title="Labels"> | |
| 100 | <Endpoint method="GET" path="/api/v2/repos/:owner/:repo/labels" description="List labels" /> | |
| 101 | <Endpoint method="POST" path="/api/v2/repos/:owner/:repo/labels" description="Create label" auth scope="repo" /> | |
| 102 | </ApiSection> | |
| 103 | ||
| 104 | <ApiSection title="Search"> | |
| 105 | <Endpoint method="GET" path="/api/v2/search/repos" description="Search repositories" params="q (required), sort, limit" /> | |
| 106 | <Endpoint method="GET" path="/api/v2/repos/:owner/:repo/search/code" description="Search code in repository" params="q (required)" /> | |
| 107 | </ApiSection> | |
| 108 | ||
| 109 | <ApiSection title="Topics"> | |
| 110 | <Endpoint method="GET" path="/api/v2/repos/:owner/:repo/topics" description="Get repository topics" /> | |
| 111 | <Endpoint method="PUT" path="/api/v2/repos/:owner/:repo/topics" description="Set repository topics" auth scope="repo" /> | |
| 112 | </ApiSection> | |
| 113 | ||
| 114 | <ApiSection title="Webhooks"> | |
| 115 | <Endpoint method="GET" path="/api/v2/repos/:owner/:repo/webhooks" description="List webhooks" auth scope="repo" /> | |
| 116 | <Endpoint method="POST" path="/api/v2/repos/:owner/:repo/webhooks" description="Create webhook" auth scope="admin" /> | |
| 117 | </ApiSection> | |
| 118 | ||
| 119 | <ApiSection title="Activity Feed"> | |
| 120 | <Endpoint method="GET" path="/api/v2/repos/:owner/:repo/activity" description="Get activity feed" params="limit" /> | |
| 121 | </ApiSection> | |
| 122 | ||
| 123 | <ApiSection title="Status Checks (CI Integration)"> | |
| 124 | <Endpoint method="POST" path="/api/v2/repos/:owner/:repo/statuses/:sha" description="Create status check" auth scope="repo" /> | |
| 125 | <Endpoint method="GET" path="/api/v2/repos/:owner/:repo/statuses/:sha" description="Get status checks for commit" /> | |
| 126 | <CodeExample | |
| 127 | title="Report CI status" | |
| 128 | code={`curl -X POST -H "Authorization: Bearer glue_xxx" \\ | |
| 129 | -H "Content-Type: application/json" \\ | |
| 130 | -d '{"context":"ci/build","state":"success","targetUrl":"https://ci.example.com/build/123"}' \\ | |
| 131 | https://gluecron.com/api/v2/repos/user/repo/statuses/abc123`} | |
| 132 | /> | |
| 133 | </ApiSection> | |
| 134 | ||
| 135 | <div style="text-align:center;padding:40px 0;color:var(--text-muted)"> | |
| 136 | <p>API index: <code>GET /api/v2</code> returns machine-readable endpoint listing</p> | |
| 137 | <p style="margin-top:8px;font-size:13px">Press <kbd class="kbd">?</kbd> for keyboard shortcuts</p> | |
| 138 | </div> | |
| 139 | </div> | |
| 140 | </Layout> | |
| 141 | ); | |
| 142 | }); | |
| 143 | ||
| 144 | // ─── Documentation Components ──────────────────────────────────────────── | |
| 145 | ||
| 146 | const ApiSection = ({ | |
| 147 | title, | |
| 148 | description, | |
| 149 | children, | |
| 150 | }: { | |
| 151 | title: string; | |
| 152 | description?: string; | |
| 153 | children: any; | |
| 154 | }) => ( | |
| 155 | <div style="margin-bottom:32px"> | |
| 156 | <h2 style="font-size:20px;margin-bottom:8px;padding-bottom:8px;border-bottom:1px solid var(--border)"> | |
| 157 | {title} | |
| 158 | </h2> | |
| 159 | {description && ( | |
| 160 | <p style="color:var(--text-muted);font-size:14px;margin-bottom:16px">{description}</p> | |
| 161 | )} | |
| 162 | {children} | |
| 163 | </div> | |
| 164 | ); | |
| 165 | ||
| 166 | const Endpoint = ({ | |
| 167 | method, | |
| 168 | path, | |
| 169 | description, | |
| 170 | params, | |
| 171 | auth, | |
| 172 | scope, | |
| 173 | }: { | |
| 174 | method: string; | |
| 175 | path: string; | |
| 176 | description: string; | |
| 177 | params?: string; | |
| 178 | auth?: boolean; | |
| 179 | scope?: string; | |
| 180 | }) => { | |
| 181 | const methodColor = | |
| 182 | method === "GET" ? "var(--green)" : | |
| 183 | method === "POST" ? "var(--accent)" : | |
| 184 | method === "PUT" || method === "PATCH" ? "var(--yellow)" : | |
| 185 | method === "DELETE" ? "var(--red)" : "var(--text)"; | |
| 186 | ||
| 187 | return ( | |
| 188 | <div style="padding:10px 0;border-bottom:1px solid var(--border);display:flex;align-items:flex-start;gap:12px;flex-wrap:wrap"> | |
| 189 | <span style={`font-family:var(--font-mono);font-size:12px;font-weight:700;color:${methodColor};min-width:60px`}> | |
| 190 | {method} | |
| 191 | </span> | |
| 192 | <code style="font-size:13px;color:var(--text-link);flex:1;min-width:200px">{path}</code> | |
| 193 | <span style="font-size:13px;color:var(--text-muted);flex:2;min-width:200px"> | |
| 194 | {description} | |
| 195 | {params && ( | |
| 196 | <span style="display:block;font-size:12px;margin-top:2px"> | |
| 197 | Params: <code>{params}</code> | |
| 198 | </span> | |
| 199 | )} | |
| 200 | </span> | |
| 201 | <span style="display:flex;gap:4px;flex-shrink:0"> | |
| 202 | {auth && ( | |
| 203 | <span style="font-size:11px;padding:2px 6px;border-radius:3px;background:rgba(31,111,235,0.15);color:var(--accent)"> | |
| 204 | AUTH | |
| 205 | </span> | |
| 206 | )} | |
| 207 | {scope && ( | |
| 208 | <span style="font-size:11px;padding:2px 6px;border-radius:3px;background:rgba(63,185,80,0.15);color:var(--green)"> | |
| 209 | {scope} | |
| 210 | </span> | |
| 211 | )} | |
| 212 | </span> | |
| 213 | </div> | |
| 214 | ); | |
| 215 | }; | |
| 216 | ||
| 217 | const CodeExample = ({ title, code }: { title: string; code: string }) => ( | |
| 218 | <div style="margin:12px 0"> | |
| 219 | {title && ( | |
| 220 | <div style="font-size:13px;color:var(--text-muted);margin-bottom:4px">{title}</div> | |
| 221 | )} | |
| 222 | <div style="position:relative"> | |
| 223 | <pre style="background:var(--bg-secondary);border:1px solid var(--border);border-radius:var(--radius);padding:12px 16px;font-family:var(--font-mono);font-size:13px;overflow-x:auto;line-height:1.6"> | |
| 224 | {code} | |
| 225 | </pre> | |
| 226 | <button | |
| 227 | type="button" | |
| 228 | class="btn btn-sm" | |
| 229 | data-clipboard={code} | |
| 230 | style="position:absolute;top:8px;right:8px;font-size:11px" | |
| 231 | > | |
| 232 | Copy | |
| 233 | </button> | |
| 234 | </div> | |
| 235 | </div> | |
| 236 | ); | |
| 237 | ||
| 238 | const EndpointTable = ({ | |
| 239 | headers, | |
| 240 | rows, | |
| 241 | }: { | |
| 242 | headers: string[]; | |
| 243 | rows: string[][]; | |
| 244 | }) => ( | |
| 245 | <table class="file-table" style="margin:8px 0"> | |
| 246 | <thead> | |
| 247 | <tr> | |
| 248 | {headers.map((h) => ( | |
| 249 | <th style="padding:8px 16px;text-align:left;font-size:13px;color:var(--text-muted);border-bottom:1px solid var(--border)"> | |
| 250 | {h} | |
| 251 | </th> | |
| 252 | ))} | |
| 253 | </tr> | |
| 254 | </thead> | |
| 255 | <tbody> | |
| 256 | {rows.map((row) => ( | |
| 257 | <tr> | |
| 258 | {row.map((cell) => ( | |
| 259 | <td style="padding:8px 16px;font-size:14px">{cell}</td> | |
| 260 | ))} | |
| 261 | </tr> | |
| 262 | ))} | |
| 263 | </tbody> | |
| 264 | </table> | |
| 265 | ); | |
| 266 | ||
| 267 | export default apiDocs; |