feat: lodge server, client and admin
This commit is contained in:
commit
95fc50e2c2
84 files changed
+7625
No files matched your search
@@ -0,0 +1,136 @@
|
||||
import { api } from "$lib/api/client";
|
||||
|
||||
export interface Change {
|
||||
base: string;
|
||||
hash: string;
|
||||
path: string;
|
||||
space: string;
|
||||
}
|
||||
|
||||
export interface Revision {
|
||||
changes: Change[];
|
||||
machine: string;
|
||||
main_branch: string;
|
||||
main_sha: string;
|
||||
seq: number;
|
||||
time: number;
|
||||
}
|
||||
|
||||
export interface Repo {
|
||||
key: string;
|
||||
name: string;
|
||||
seq: number;
|
||||
time: number;
|
||||
}
|
||||
|
||||
export interface Machine {
|
||||
created_at: number;
|
||||
id: number;
|
||||
last_push: number;
|
||||
name: string;
|
||||
revisions: number;
|
||||
}
|
||||
|
||||
export interface FileEntry {
|
||||
hash: string;
|
||||
time: number;
|
||||
}
|
||||
|
||||
export interface RepoState {
|
||||
seq: number;
|
||||
spaces: Record<string, Record<string, FileEntry>>;
|
||||
}
|
||||
|
||||
export interface Code {
|
||||
code: string;
|
||||
command: string;
|
||||
expires_at: number;
|
||||
}
|
||||
|
||||
export const SHARED = "shared";
|
||||
const PATTERNS = 7;
|
||||
const WEB = "web";
|
||||
const REVOKED = "revoked";
|
||||
const SHORT_SHA = 7;
|
||||
const BRANCH_PREFIX = "branch:";
|
||||
|
||||
export const lithology = (machine: string, machines: string[]): string => {
|
||||
if (machine === WEB) {
|
||||
return "lith lith-web";
|
||||
}
|
||||
const index = machines.indexOf(machine);
|
||||
if (machine === REVOKED || index < 0) {
|
||||
return "lith lith-gone";
|
||||
}
|
||||
return `lith lith-${index % PATTERNS}`;
|
||||
};
|
||||
|
||||
export const shortSha = (sha: string): string =>
|
||||
sha ? sha.slice(0, SHORT_SHA) : "no commit";
|
||||
|
||||
export const spaceName = (space: string): string =>
|
||||
space.startsWith(BRANCH_PREFIX) ? space.slice(BRANCH_PREFIX.length) : space;
|
||||
|
||||
export const fileId = (space: string, path: string): string =>
|
||||
`${space}\n${path}`;
|
||||
|
||||
export const changeKind = (
|
||||
change: Change
|
||||
): "added" | "deleted" | "modified" => {
|
||||
if (!change.base) {
|
||||
return "added";
|
||||
}
|
||||
return change.hash ? "modified" : "deleted";
|
||||
};
|
||||
|
||||
const UNITS: [Intl.RelativeTimeFormatUnit, number][] = [
|
||||
["year", 31_536_000_000],
|
||||
["month", 2_592_000_000],
|
||||
["day", 86_400_000],
|
||||
["hour", 3_600_000],
|
||||
["minute", 60_000],
|
||||
];
|
||||
const relative = new Intl.RelativeTimeFormat("en", { numeric: "auto" });
|
||||
const absolute = new Intl.DateTimeFormat("en-GB", {
|
||||
dateStyle: "medium",
|
||||
timeStyle: "short",
|
||||
});
|
||||
|
||||
export const ago = (time: number): string => {
|
||||
if (!time) {
|
||||
return "never";
|
||||
}
|
||||
const delta = time - Date.now();
|
||||
for (const [unit, size] of UNITS) {
|
||||
if (Math.abs(delta) >= size) {
|
||||
return relative.format(Math.round(delta / size), unit);
|
||||
}
|
||||
}
|
||||
return "just now";
|
||||
};
|
||||
|
||||
export const exact = (time: number): string => absolute.format(time);
|
||||
|
||||
const blobs = new Map<string, Promise<Uint8Array>>();
|
||||
|
||||
export const blob = (hash: string): Promise<Uint8Array> => {
|
||||
let pending = blobs.get(hash);
|
||||
if (!pending) {
|
||||
pending = api.bytes(`/blobs/${hash}`);
|
||||
blobs.set(hash, pending);
|
||||
}
|
||||
return pending;
|
||||
};
|
||||
|
||||
const decoder = new TextDecoder("utf-8", { fatal: true });
|
||||
|
||||
export const text = (bytes: Uint8Array): string | null => {
|
||||
if (bytes.includes(0)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return decoder.decode(bytes);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
Reference in new issue
Block a user