88 lines
2.5 KiB
TypeScript
88 lines
2.5 KiB
TypeScript
// ⚠️ GENERATED FILE – do not edit directly. Edit the canonical source in skills/atlassian/shared/scripts/ and run `pnpm run sync:pi`.
|
||
import { createBasicAuthHeader } from "./config.js";
|
||
import type { AtlassianConfig, FetchLike } from "./types.js";
|
||
|
||
export type HttpMethod = "GET" | "POST" | "PUT";
|
||
|
||
export function createJsonHeaders(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;
|
||
}
|
||
|
||
export async function parseResponse(response: Response) {
|
||
if (response.status === 204) {
|
||
return null;
|
||
}
|
||
|
||
const contentType = response.headers.get("content-type") ?? "";
|
||
|
||
if (contentType.includes("application/json")) {
|
||
try {
|
||
return await response.json();
|
||
} catch {
|
||
throw new Error("Malformed JSON response from Atlassian API");
|
||
}
|
||
}
|
||
|
||
return response.text();
|
||
}
|
||
|
||
export function createStatusError(errorPrefix: string, response: Response) {
|
||
const base = `${errorPrefix}: ${response.status} ${response.statusText}`;
|
||
|
||
switch (response.status) {
|
||
case 401:
|
||
return new Error(`${base} - check ATLASSIAN_EMAIL and ATLASSIAN_API_TOKEN`);
|
||
case 403:
|
||
return new Error(`${base} - verify product permissions for this account`);
|
||
case 404:
|
||
return new Error(`${base} - verify the resource identifier or API path`);
|
||
case 429:
|
||
return new Error(`${base} - retry later or reduce request rate`);
|
||
default:
|
||
return new Error(base);
|
||
}
|
||
}
|
||
|
||
export async function sendJsonRequest(options: {
|
||
config: AtlassianConfig;
|
||
fetchImpl?: FetchLike;
|
||
url: string;
|
||
method: HttpMethod;
|
||
body?: unknown;
|
||
errorPrefix: string;
|
||
handleResponseError?: (response: Response) => Error | undefined;
|
||
}) {
|
||
const fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
||
|
||
if (!fetchImpl) {
|
||
throw new Error("Fetch API is not available in this runtime");
|
||
}
|
||
|
||
const response = await fetchImpl(options.url, {
|
||
method: options.method,
|
||
headers: createJsonHeaders(options.config, options.body !== undefined),
|
||
...(options.body === undefined ? {} : { body: JSON.stringify(options.body) }),
|
||
});
|
||
|
||
if (!response.ok) {
|
||
const customError = options.handleResponseError?.(response);
|
||
|
||
if (customError) {
|
||
throw customError;
|
||
}
|
||
|
||
throw createStatusError(options.errorPrefix, response);
|
||
}
|
||
|
||
return parseResponse(response);
|
||
}
|