@aashari/mcp-server-atlassian-confluence
Version:
Node.js/TypeScript MCP server for Atlassian Confluence. Provides tools enabling AI systems (LLMs) to list/get spaces & pages (content formatted as Markdown) and search via CQL. Connects AI seamlessly to Confluence knowledge bases using the standard MCP in
107 lines (106 loc) • 4.12 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.PaginationType = void 0;
exports.extractPaginationInfo = extractPaginationInfo;
const logger_util_js_1 = require("./logger.util.js");
/**
* Types of pagination mechanisms used by different Atlassian APIs
*/
var PaginationType;
(function (PaginationType) {
/**
* Offset-based pagination (startAt, maxResults, total)
* Used by Jira APIs
*/
PaginationType["OFFSET"] = "offset";
/**
* Cursor-based pagination (cursor in URL)
* Used by Confluence APIs
*/
PaginationType["CURSOR"] = "cursor";
/**
* Page-based pagination (page parameter in URL)
* Used by Bitbucket APIs
*/
PaginationType["PAGE"] = "page";
})(PaginationType || (exports.PaginationType = PaginationType = {}));
/**
* Extract pagination information from API response
* @param data The API response containing pagination information
* @param paginationType The type of pagination mechanism used
* @returns Object with nextCursor, hasMore, and count properties
*/
function extractPaginationInfo(data, paginationType) {
const paginationLogger = logger_util_js_1.Logger.forContext('utils/pagination.util.ts', 'extractPaginationInfo');
let nextCursor;
let count;
try {
// Extract count from the appropriate data field based on pagination type
switch (paginationType) {
case PaginationType.OFFSET: {
const offsetData = data;
count = offsetData.values?.length;
// Handle Jira's offset-based pagination
if (offsetData.startAt !== undefined &&
offsetData.maxResults !== undefined &&
offsetData.total !== undefined &&
offsetData.startAt + offsetData.maxResults <
offsetData.total) {
nextCursor = String(offsetData.startAt + offsetData.maxResults);
}
else if (offsetData.nextPage) {
nextCursor = offsetData.nextPage;
}
break;
}
case PaginationType.CURSOR: {
const cursorData = data;
count = cursorData.results?.length;
// Handle Confluence's cursor-based pagination
if (cursorData._links && cursorData._links.next) {
const nextUrl = cursorData._links.next;
const cursorMatch = nextUrl.match(/cursor=([^&]+)/);
if (cursorMatch && cursorMatch[1]) {
nextCursor = decodeURIComponent(cursorMatch[1]);
}
}
break;
}
case PaginationType.PAGE: {
const pageData = data;
count = pageData.values?.length;
// Handle Bitbucket's page-based pagination
if (pageData.next) {
try {
const nextUrl = new URL(pageData.next);
const nextPage = nextUrl.searchParams.get('page');
if (nextPage) {
nextCursor = nextPage;
}
}
catch (error) {
paginationLogger.warn(`Failed to parse next URL: ${pageData.next}`, { error });
}
}
break;
}
default:
paginationLogger.warn(`Unknown pagination type: ${paginationType}`);
}
if (nextCursor) {
paginationLogger.debug(`Next cursor: ${nextCursor}`);
}
if (count !== undefined) {
paginationLogger.debug(`Count: ${count}`);
}
return {
nextCursor,
hasMore: !!nextCursor,
count,
};
}
catch (error) {
paginationLogger.warn(`Error extracting pagination information: ${error instanceof Error ? error.message : String(error)}`);
return { hasMore: false };
}
}