import axios, { AxiosError } from "axios";
import { PCO_API_BASE_URL } from "../constants.js";
let apiClient = null;
/**
* Initialize the PCO API client using Personal Access Token credentials.
* Credentials are read from PCO_APP_ID and PCO_SECRET environment variables.
*/
export function getApiClient() {
if (apiClient)
return apiClient;
const appId = process.env.PCO_APP_ID;
const secret = process.env.PCO_SECRET;
if (!appId || !secret) {
throw new Error("Missing PCO credentials. Set PCO_APP_ID and PCO_SECRET environment variables. " +
"Get your credentials at https://api.planningcenteronline.com/oauth/applications");
}
apiClient = axios.create({
baseURL: PCO_API_BASE_URL,
auth: { username: appId, password: secret },
timeout: 30000,
headers: {
"Content-Type": "application/json",
"Accept": "application/vnd.api+json",
},
});
return apiClient;
}
/**
* Make a GET request to the PCO API.
*/
export async function apiGet(path, params) {
const client = getApiClient();
const response = await client.get(path, { params });
return response.data;
}
/**
* Make a POST request to the PCO API.
*/
export async function apiPost(path, body) {
const client = getApiClient();
const response = await client.post(path, body);
return response.data;
}
/**
* Make a PATCH request to the PCO API.
*/
export async function apiPatch(path, body) {
const client = getApiClient();
const response = await client.patch(path, body);
return response.data;
}
/**
* Make a DELETE request to the PCO API.
*/
export async function apiDelete(path) {
const client = getApiClient();
await client.delete(path);
}
/**
* Convert an API error to a human-readable message.
*/
export function handleApiError(error) {
if (error instanceof AxiosError) {
if (error.response) {
const status = error.response.status;
const detail = (() => {
try {
const data = error.response.data;
if (data?.errors && Array.isArray(data.errors)) {
return data.errors
.map((e) => e.detail)
.filter(Boolean)
.join("; ");
}
}
catch {
// ignore parse errors
}
return null;
})();
switch (status) {
case 400:
return `Error: Bad request${detail ? ` — ${detail}` : ""}. Check your input parameters.`;
case 401:
return "Error: Authentication failed. Check your PCO_APP_ID and PCO_SECRET.";
case 403:
return "Error: Permission denied. You don't have access to this resource.";
case 404:
return "Error: Resource not found. Check that the ID is correct.";
case 422:
return `Error: Validation failed${detail ? ` — ${detail}` : ""}. Check your input.`;
case 429:
return "Error: Rate limit exceeded. Please wait before making more requests.";
case 500:
return "Error: PCO server error. Try again later.";
default:
return `Error: API request failed with status ${status}${detail ? ` — ${detail}` : ""}.`;
}
}
else if (error.code === "ECONNABORTED") {
return "Error: Request timed out. Please try again.";
}
else if (error.code === "ECONNREFUSED") {
return "Error: Could not connect to Planning Center. Check your internet connection.";
}
}
return `Error: ${error instanceof Error ? error.message : String(error)}`;
}
/**
* Build PCO pagination query parameters (offset-based, JSON API style).
*/
export function buildPaginationParams(limit, offset) {
return {
"per_page": limit,
"offset": offset,
};
}
/**
* Extract total count from a JSON API response.
*/
export function getTotalCount(response) {
return response.meta?.total_count ?? 0;
}
/**
* Ensure response data is always an array.
*/
export function ensureArray(data) {
return Array.isArray(data) ? data : [data];
}
//# sourceMappingURL=api.js.map