@aashari/mcp-server-atlassian-bitbucket
Version:
Node.js/TypeScript MCP server for Atlassian Bitbucket. Enables AI systems (LLMs) to interact with workspaces, repositories, and pull requests via tools (list, get, comment, search). Connects AI directly to version control workflows through the standard MC
107 lines (106 loc) • 4.1 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 methodLogger = 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) {
methodLogger.warn(`Failed to parse next URL: ${pageData.next}`, { error });
}
}
break;
}
default:
methodLogger.warn(`Unknown pagination type: ${paginationType}`);
}
if (nextCursor) {
methodLogger.debug(`Next cursor: ${nextCursor}`);
}
if (count !== undefined) {
methodLogger.debug(`Count: ${count}`);
}
return {
nextCursor,
hasMore: !!nextCursor,
count,
};
}
catch (error) {
methodLogger.warn(`Error extracting pagination information: ${error instanceof Error ? error.message : String(error)}`);
return { hasMore: false };
}
}