Files
relicario/extension/src/service-worker/git-host.ts
2026-04-27 17:48:24 -04:00

80 lines
3.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/// Abstract interface for reading/writing vault files on a git host.
///
/// Both Gitea and GitHub expose a "repo contents" REST API that lets us
/// read, write, and delete individual files without cloning the repo.
/// This interface captures just the operations the vault needs.
export interface GitHost {
/// Read a single file from the repo, returning its raw bytes.
readFile(path: string): Promise<Uint8Array>;
/// Create or update a file in the repo with a commit message.
writeFile(path: string, content: Uint8Array, message: string): Promise<void>;
/// Delete a file from the repo with a commit message.
deleteFile(path: string, message: string): Promise<void>;
/// List file names in a directory (non-recursive).
listDir(path: string): Promise<string[]>;
/// Best-effort: returns metadata for the most recent commit touching `path`.
/// Returns null if the path has no commits, the API fails, or the host
/// doesn't support the lookup. Callers must tolerate null.
lastCommit(path: string): Promise<{ sha: string; author: string; date: string } | null>;
/// Write an opaque binary blob to the repo. Optimized for large
/// attachments — implementations switch from Contents API to Git
/// Data API when content exceeds BLOB_THRESHOLD_BYTES.
/// Returns the path that was written (same as input, for chaining).
putBlob(path: string, content: Uint8Array, message: string): Promise<string>;
/// Read an opaque binary blob from the repo. Same semantics as
/// readFile for current sizes. Distinct method so we can later add
/// streaming/chunked reads for very large blobs.
getBlob(path: string): Promise<Uint8Array>;
/// Delete a blob from the repo. Currently identical to deleteFile;
/// kept distinct for symmetry with putBlob.
deleteBlob(path: string, message: string): Promise<void>;
}
/// Pre-base64 byte size at which putBlob switches from Contents API to
/// Git Data API. 900 KB leaves headroom for base64 inflation (1.33×) and
/// JSON wrapping under both GitHub's and Gitea's Contents API soft-limits.
export const BLOB_THRESHOLD_BYTES = 900 * 1024;
/// Convert a Uint8Array to a base64 string (works in service worker context).
export function uint8ArrayToBase64(bytes: Uint8Array): string {
let binary = '';
for (let i = 0; i < bytes.length; i++) {
binary += String.fromCharCode(bytes[i]);
}
return btoa(binary);
}
/// Convert a base64 string to a Uint8Array.
export function base64ToUint8Array(base64: string): Uint8Array {
const binary = atob(base64);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) {
bytes[i] = binary.charCodeAt(i);
}
return bytes;
}
/// Factory function that returns the appropriate GitHost implementation.
import { GiteaHost } from './gitea';
import { GitHubHost } from './github';
export function createGitHost(
hostType: 'gitea' | 'github',
hostUrl: string,
repoPath: string,
apiToken: string,
): GitHost {
if (hostType === 'gitea') {
return new GiteaHost(hostUrl, repoPath, apiToken);
}
return new GitHubHost(repoPath, apiToken);
}