jira.ts•1.71 kB
import { AppError } from '../lib/errors.js';
import { requestJson } from '../lib/http.js';
type JiraCfg = { url: string; token: string };
export class JiraAdapter {
constructor(private cfg: JiraCfg) {}
private headers() {
// Jira Cloud typically uses basic auth with API token. Expect token to be in form 'email:token' base64'd.
const token = Buffer.from(this.cfg.token).toString('base64');
return { Authorization: `Basic ${token}` };
}
async searchIssues(jql: string, maxResults = 50) {
const limit = Math.max(1, Math.min(100, maxResults));
let startAt = 0;
const issues: unknown[] = [];
while (issues.length < limit) {
const pageSize = Math.min(50, limit - issues.length);
const u = new URL('/rest/api/3/search', this.cfg.url);
u.searchParams.set('jql', jql);
u.searchParams.set('maxResults', String(pageSize));
u.searchParams.set('startAt', String(startAt));
const { status, data } = await requestJson(u.toString(), { headers: this.headers() });
if (status >= 400)
throw new AppError('UPSTREAM_HTTP_ERROR', 'Jira search failed', { status });
const arr = Array.isArray((data as any).issues) ? (data as any).issues : [];
issues.push(...arr);
if (arr.length === 0) break; // no more pages
startAt += arr.length;
}
return { issues };
}
async getIssue(key: string) {
const u = new URL(`/rest/api/3/issue/${encodeURIComponent(key)}`, this.cfg.url);
const { status, data } = await requestJson(u.toString(), { headers: this.headers() });
if (status >= 400)
throw new AppError('UPSTREAM_HTTP_ERROR', 'Jira get issue failed', { status });
return data as unknown;
}
}