alinea
Version:
Headless git-based CMS
89 lines (87 loc) • 3.07 kB
JavaScript
import {
pLimit
} from "../../chunks/chunk-C53YJRET.js";
import "../../chunks/chunk-NZLE2WMY.js";
// src/core/source/GithubSource.ts
import * as paths from "alinea/core/util/Paths";
import { HttpError } from "../HttpError.js";
import { assert } from "../util/Assert.js";
import { ReadonlyTree } from "./Tree.js";
var GithubSource = class {
#current = ReadonlyTree.EMPTY;
#options;
#limit = pLimit(8);
constructor(options) {
this.#options = options;
}
get contentLocation() {
const { contentDir, rootDir } = this.#options;
return paths.join(rootDir, contentDir);
}
async getTree() {
const current = this.#current;
const newTree = await this.getTreeIfDifferent(current.sha);
if (newTree) return this.#current = newTree;
return current;
}
async shaAt(ref) {
const { owner, repo, authToken } = this.#options;
const parentDir = this.contentLocation.split("/").slice(0, -1).join("/");
const parentInfo = await fetch(
`https://api.github.com/repos/${owner}/${repo}/contents/${parentDir}?ref=${ref}`,
{ headers: { Authorization: `Bearer ${authToken}` } }
);
assert(parentInfo.ok, `Failed to get parent: ${parentInfo.statusText}`);
const parents = await parentInfo.json();
assert(Array.isArray(parents));
const parent = parents.find((entry) => entry.path === this.contentLocation);
if (!parent) return ReadonlyTree.EMPTY.sha;
assert(typeof parent.sha === "string");
return parent.sha;
}
async getTreeIfDifferent(sha) {
const { branch, owner, repo, authToken } = this.#options;
const remoteSha = await this.shaAt(branch);
if (remoteSha === sha) return void 0;
const treeInfo = await fetch(
`https://api.github.com/repos/${owner}/${repo}/git/trees/${remoteSha}?recursive=true`,
{ headers: { Authorization: `Bearer ${authToken}` } }
);
assert(treeInfo.ok, `Failed to get tree: ${treeInfo.statusText}`);
const treeData = await treeInfo.json();
assert(treeData.truncated === false);
const tree = ReadonlyTree.fromFlat(treeData);
return tree;
}
async *getBlobs(shas) {
const { owner, repo, authToken } = this.#options;
const responses = shas.map((sha) => {
const promise = this.#limit(
() => fetch(
`https://api.github.com/repos/${owner}/${repo}/git/blobs/${sha}`,
{ headers: { Authorization: `Bearer ${authToken}` } }
)
);
return [sha, promise];
});
for (const [sha, promise] of responses) {
const response = await promise;
if (!response.ok)
throw new HttpError(
response.status,
`Failed to get blob: ${response.statusText}`
);
const blobData = await response.json();
assert(blobData.encoding === "base64");
assert(typeof blobData.content === "string");
assert(blobData.size > 0);
yield [sha, Uint8Array.from(atob(blobData.content), (c) => c.charCodeAt(0))];
}
}
async applyChanges(batch) {
throw new Error("Not implemented");
}
};
export {
GithubSource
};