import { _ } from '@sveltia/i18n'; import { fetchAPI, fetchGraphQL, graphqlVars } from '$lib/services/backends/git/shared/api'; import { REPOSITORY_INFO_PLACEHOLDER } from '$lib/services/backends/git/shared/repository'; import { user } from '$lib/services/user/account.svelte'; /** * @import { RepositoryBaseURLs, RepositoryInfo } from '$lib/types/private'; */ /** * Placeholder for repository information. * @type {RepositoryInfo} */ export const repository = { ...REPOSITORY_INFO_PLACEHOLDER }; /** * Generate base URLs for accessing the repository’s resources. * @param {string} repoURL The base URL of the repository. * @param {string} [branch] The branch name. Could be `undefined` if the branch is not specified in * the CMS configuration. * @returns {RepositoryBaseURLs} An object containing the tree base URL for browsing files, and the * blob base URL for accessing file contents. */ export const getBaseURLs = (repoURL, branch) => ({ treeBaseURL: branch ? `${repoURL}/tree/${branch}` : repoURL, blobBaseURL: branch ? `${repoURL}/blob/${branch}` : '', commitBaseURL: `${repoURL}/commit`, }); /** * Check if the user has access to the current repository. * @throws {Error} If the user is not a collaborator of the repository. * @see https://docs.github.com/en/rest/collaborators/collaborators#check-if-a-user-is-a-repository-collaborator */ export const checkRepositoryAccess = async () => { const { owner, repo } = repository; const userName = /** @type {string} */ (user.account?.login); const { ok } = /** @type {Response} */ ( await fetchAPI(`/repos/${owner}/${repo}/collaborators/${encodeURIComponent(userName)}`, { headers: { Accept: 'application/json' }, responseType: 'raw', }) ); if (!ok) { throw new Error('Not a collaborator of the repository', { cause: new Error(_('repository_no_access', { values: { repo } })), }); } }; const FETCH_DEFAULT_BRANCH_NAME_QUERY = ` query($owner: String!, $repo: String!) { repository(owner: $owner, name: $repo) { defaultBranchRef { name } } } `; /** * Fetch the repository’s default branch name, which is typically `master` or `main`. * @returns {Promise} Branch name. * @throws {Error} When the repository could not be found, or when the repository is empty. */ export const fetchDefaultBranchName = async () => { const { repo, repoURL = '' } = repository; const result = /** @type {{ repository: { defaultBranchRef?: { name: string } } }} */ ( await fetchGraphQL(FETCH_DEFAULT_BRANCH_NAME_QUERY) ); if (!result.repository) { throw new Error('Failed to retrieve the default branch name.', { cause: new Error(_('repository_not_found', { values: { repo } })), }); } const { name: branch } = result.repository.defaultBranchRef ?? {}; if (!branch) { throw new Error('Failed to retrieve the default branch name.', { cause: new Error(_('repository_empty', { values: { repo } })), }); } Object.assign(repository, { branch }, getBaseURLs(repoURL, branch)); Object.assign(graphqlVars, { branch }); return branch; };