157 lines · 7.5 KB
import { env } from "cloudflare:workers";
import { z } from "zod";
import { peekAuthToken, storeAuthToken } from "../auth-tokens";
import { randomToken } from "../crypto";
import { badRequest, forbidden, HttpError, unauthorized } from "../errors";
import { publicUrl } from "../events/emit";
import { authenticatedRemote, mintRepoToken } from "../git/artifacts";
import { limitWrite } from "../limits";
import { hasPermission, loadRepoById, repoPermission } from "../repos";
import { loadUserById, toViewer } from "../auth";
import { containerLimits, containersEnabled } from "./container-config";
import type { EditorContainer } from "./container-do";
import { containerMinutesThisMonth } from "./container-meter";
import { json } from "./http";
import { editorOriginFor } from "./origin";
import { editorRoomStub } from "./room-client";
import { canWrite, EDITOR_TOKEN_PREFIX, resolveEditorToken } from "./session";
import type { EditorSession } from "./session";
import { EDITOR_WS_PROTOCOL } from "~/lib/editor-protocol";

const PREVIEW_PREFIX = "gitfor_pvw";
const PREVIEW_TTL_SECONDS = 60 * 60;
const UNLIMITED_ATTEMPTS = Number.MAX_SAFE_INTEGER;
const HTTP_PAYMENT_REQUIRED = 402;
const MAX_PORT = 65535;

/** Containers are per (account, repo, branch): co-editors each get their own, billed to themselves. */
function containerStub(accountId: string, repoId: string, branch: string): DurableObjectStub<EditorContainer> {
  return env.EDITOR_CONTAINER.getByName(`${accountId}:${repoId}:${branch}`);
}

function requireContainerAccess(session: EditorSession): void {
  if (!containersEnabled()) throw forbidden("Containers aren't enabled on this forge");
  if (!canWrite(session)) throw forbidden("Containers need write access to a branch");
}

function stubFor(session: EditorSession) {
  return containerStub(session.viewer.id, session.repo.id, session.revision.name);
}