UNPKG

@telefonica/confluence-sync

Version:

Creates/updates/deletes Confluence pages based on a list of objects containing the page contents. Supports nested pages and attachments upload

304 lines (303 loc) 11.9 kB
"use strict"; // SPDX-FileCopyrightText: 2025 Telefónica Innovación Digital // SPDX-License-Identifier: Apache-2.0 Object.defineProperty(exports, "__esModule", { value: true }); exports.CustomConfluenceClient = void 0; const confluence_js_1 = require("confluence.js"); const AttachmentsNotFoundError_1 = require("./errors/AttachmentsNotFoundError"); const AxiosErrors_1 = require("./errors/AxiosErrors"); const CreateAttachmentsError_1 = require("./errors/CreateAttachmentsError"); const CreatePageError_1 = require("./errors/CreatePageError"); const DeletePageError_1 = require("./errors/DeletePageError"); const PageNotFoundError_1 = require("./errors/PageNotFoundError"); const UpdatePageError_1 = require("./errors/UpdatePageError"); const CustomError_1 = require("./errors/CustomError"); const GET_CHILDREN_LIMIT = 100; /** * Type guard to check if the authentication is basic * @param auth - Object to check * @returns True if the authentication is basic, false otherwise */ function isBasicAuthentication(auth) { return (auth.basic !== undefined); } /** * Type guard to check if the authentication is OAuth2 * @param auth - Object to check * @returns True if the authentication is OAuth2, false otherwise */ function isOAuth2Authentication(auth) { return auth.oauth2 !== undefined; } /** * Type guard to check if the authentication is JWT * @param auth - Object to check * @returns True if the authentication is JWT, false otherwise */ function isJWTAuthentication(auth) { return (auth.jwt !== undefined); } /** * Type guard to check if the authentication is valid * @param auth The authentication object to check * @returns True if the authentication is valid, false otherwise */ function isAuthentication(auth) { if (typeof auth !== "object" || auth === null) { return false; } return (isBasicAuthentication(auth) || isOAuth2Authentication(auth) || isJWTAuthentication(auth)); } const CustomConfluenceClient = class CustomConfluenceClient { _config; _client; _logger; constructor(config) { this._config = config; if (!isAuthentication(config.authentication) && !config.personalAccessToken) { throw new Error("Either authentication or personalAccessToken must be provided"); } // Backward compatibility with personalAccessToken const authentication = isAuthentication(config.authentication) ? config.authentication : { oauth2: { accessToken: config.personalAccessToken, }, }; const apiPrefix = config.apiPrefix ?? "/rest/"; this._client = new confluence_js_1.ConfluenceClient({ host: config.url, authentication, apiPrefix, }); this._logger = config.logger; } // Exposed mainly for testing purposes get logger() { return this._logger; } async _getChildPages(parentId, start = 0, otherChildren = []) { try { this._logger.silly(`Getting child pages of parent with id ${parentId}`); const response = await this._client.contentChildrenAndDescendants.getContentChildren({ id: parentId, start, limit: GET_CHILDREN_LIMIT, expand: ["page"], }); this._logger.silly(`Get child pages response of page ${parentId}, starting at ${start}: ${JSON.stringify(response.page, null, 2)}`); const childrenResults = response.page?.results || []; const size = response.page?.size || 0; const allChildren = [ ...otherChildren, ...childrenResults, ]; if (start + childrenResults.length < size) { const newStart = start + GET_CHILDREN_LIMIT; this._logger.silly(`There are more child pages of page with id ${parentId}, fetching next page starting from ${newStart}`); return this._getChildPages(parentId, newStart, allChildren); } return allChildren; } catch (e) { const error = (0, AxiosErrors_1.toConfluenceClientError)(e); throw new PageNotFoundError_1.PageNotFoundError(parentId, { cause: error }); } } async getPage(id) { try { this._logger.silly(`Getting page with id ${id}`); const childrenRequest = this._getChildPages(id); const pageRequest = this._client.content.getContentById({ id, expand: ["ancestors", "version.number"], }); const [response, childrenResponse] = await Promise.all([ pageRequest, childrenRequest, ]); this._logger.silly(`Get page response: ${JSON.stringify(response, null, 2)}`); this._logger.silly(`Get children response: ${JSON.stringify(childrenResponse, null, 2)}`); return { title: response.title, id: response.id, version: response.version?.number, ancestors: response.ancestors?.map((ancestor) => this._convertToConfluencePageBasicInfo(ancestor)), children: childrenResponse.map((child) => this._convertToConfluencePageBasicInfo(child)), }; } catch (e) { if (!(e instanceof CustomError_1.CustomError)) { const error = (0, AxiosErrors_1.toConfluenceClientError)(e); throw new PageNotFoundError_1.PageNotFoundError(id, { cause: error }); } throw e; } } async createPage({ title, content, ancestors, }) { if (!this._config.dryRun) { const createContentBody = { type: "page", title, space: { key: this._config.spaceId, }, ancestors: this.handleAncestors(ancestors), body: { storage: { value: content || "", representation: "storage", }, }, }; try { this._logger.silly(`Creating page with title ${title}`); const response = await this._client.content.createContent(createContentBody); this._logger.silly(`Create page response: ${JSON.stringify(response, null, 2)}`); return { title: response.title, id: response.id, version: response.version?.number, ancestors: response.ancestors?.map((ancestor) => this._convertToConfluencePageBasicInfo(ancestor)), }; } catch (e) { const error = (0, AxiosErrors_1.toConfluenceClientError)(e); throw new CreatePageError_1.CreatePageError(title, { cause: error }); } } else { this._logger.info(`Dry run: creating page with title ${title}`); return { title, id: "1234", version: 1, ancestors, }; } } async updatePage({ id, title, content, version, ancestors, }) { if (!this._config.dryRun) { const updateContentBody = { id, type: "page", title, ancestors: this.handleAncestors(ancestors), version: { number: version, }, body: { storage: { value: content || "", representation: "storage", }, }, }; try { this._logger.silly(`Updating page with title ${title}`); const response = await this._client.content.updateContent(updateContentBody); this._logger.silly(`Update page response: ${JSON.stringify(response, null, 2)}`); return { title: response.title, id: response.id, version: response.version?.number, ancestors: response.ancestors?.map((ancestor) => this._convertToConfluencePageBasicInfo(ancestor)), }; } catch (e) { const error = (0, AxiosErrors_1.toConfluenceClientError)(e); throw new UpdatePageError_1.UpdatePageError(id, title, { cause: error }); } } else { this._logger.info(`Dry run: updating page with title ${title}`); return { title, id, version, ancestors, }; } } async deleteContent(id) { if (!this._config.dryRun) { try { this._logger.silly(`Deleting content with id ${id}`); await this._client.content.deleteContent({ id }); } catch (e) { const error = (0, AxiosErrors_1.toConfluenceClientError)(e); throw new DeletePageError_1.DeletePageError(id, { cause: error }); } } else { this._logger.info(`Dry run: deleting content with id ${id}`); } } async getAttachments(id) { try { this._logger.silly(`Getting attachments of page with id ${id}`); const response = await this._client.contentAttachments.getAttachments({ id, }); this._logger.silly(`Get attachments response: ${JSON.stringify(response, null, 2)}`); return (response.results?.map((attachment) => ({ id: attachment.id, title: attachment.title, })) || []); } catch (e) { const error = (0, AxiosErrors_1.toConfluenceClientError)(e); throw new AttachmentsNotFoundError_1.AttachmentsNotFoundError(id, { cause: error }); } } async createAttachments(id, attachments) { if (!this._config.dryRun) { try { const bodyRequest = attachments.map((attachment) => ({ minorEdit: true, ...attachment, })); this._logger.silly(`Creating attachments of page with id ${id}, attachments: ${attachments .map((attachment) => attachment.filename) .join(", ")}`); const response = await this._client.contentAttachments.createAttachments({ id, attachments: bodyRequest, }); this._logger.silly(`Create attachments response: ${JSON.stringify(response, null, 2)}`); } catch (e) { const error = (0, AxiosErrors_1.toConfluenceClientError)(e); throw new CreateAttachmentsError_1.CreateAttachmentsError(id, { cause: error }); } } else { this._logger .info(`Dry run: creating attachments of page with id ${id}, attachments: ${attachments .map((attachment) => attachment.filename) .join(", ")} `); } } handleAncestors(ancestors) { if (ancestors && ancestors.length) { const id = ancestors.at(-1)?.id; return [{ id }]; } else { return undefined; } } _convertToConfluencePageBasicInfo(rawInfo) { return { id: rawInfo.id, title: rawInfo.title, }; } }; exports.CustomConfluenceClient = CustomConfluenceClient;