feat(atlassian): implement milestone M3 - confluence and safety controls

This commit is contained in:
Stefano Fiorini
2026-03-06 00:53:13 -06:00
parent 73c4bff901
commit 972789c240
8 changed files with 1058 additions and 38 deletions

View File

@@ -1,5 +1,5 @@
import { markdownToAdf } from "./adf.js";
import { createBasicAuthHeader } from "./config.js";
import { sendJsonRequest } from "./http.js";
import type { AtlassianConfig, CommandOutput, FetchLike, JiraIssueSummary } from "./types.js";
const ISSUE_FIELDS = ["summary", "issuetype", "status", "assignee", "created", "updated"] as const;
@@ -60,33 +60,6 @@ function normalizeIssue(config: AtlassianConfig, issue: Record<string, unknown>)
};
}
function createHeaders(config: AtlassianConfig, includeJsonBody: boolean) {
const headers: Array<[string, string]> = [
["Accept", "application/json"],
["Authorization", createBasicAuthHeader(config)],
];
if (includeJsonBody) {
headers.push(["Content-Type", "application/json"]);
}
return headers;
}
async function parseResponse(response: Response) {
if (response.status === 204) {
return null;
}
const contentType = response.headers.get("content-type") ?? "";
if (contentType.includes("application/json")) {
return response.json();
}
return response.text();
}
function createRequest(config: AtlassianConfig, method: "GET" | "POST" | "PUT", path: string, body?: unknown) {
const url = new URL(path, `${config.jiraBaseUrl}/`);
@@ -106,17 +79,14 @@ export function createJiraClient(options: JiraClientOptions) {
async function send(method: "GET" | "POST" | "PUT", path: string, body?: unknown) {
const request = createRequest(options.config, method, path, body);
const response = await fetchImpl(request.url, {
return sendJsonRequest({
config: options.config,
fetchImpl,
url: request.url,
method,
headers: createHeaders(options.config, body !== undefined),
...(body === undefined ? {} : { body: JSON.stringify(body) }),
body,
errorPrefix: "Jira request failed",
});
if (!response.ok) {
throw new Error(`Jira request failed: ${response.status} ${response.statusText}`);
}
return parseResponse(response);
}
return {