Skip to content
File

Blob: src/worker/git/receive/response.ts

typescript58 lines
1import { asBodyInit } from "@/worker/common";
2import { concatChunks, flushPkt } from "@/worker/git/core/pktline";
3import {
4 createSidebandPacketChunks,
5 enqueueSidebandPayload,
6} from "@/worker/git/operations/fetch/sideband";
7 
8export type ReceiveResponseMode = "plain" | "side-band-64k";
9 
10export function buildSidebandReceiveBody(reportStatusBody: Uint8Array): Uint8Array {
11 return concatChunks([...createSidebandPacketChunks(1, reportStatusBody), flushPkt()]);
12}
13 
14export function buildReceiveResultResponse(args: {
15 mode: ReceiveResponseMode;
16 reportStatusBody: Uint8Array;
17 changed: boolean;
18 empty: boolean;
19}): Response {
20 const body =
21 args.mode === "side-band-64k"
22 ? buildSidebandReceiveBody(args.reportStatusBody)
23 : args.reportStatusBody;
24 
25 return new Response(asBodyInit(body), {
26 status: 200,
27 headers: {
28 "Content-Type": "application/x-git-receive-pack-result",
29 // Receive-pack is credentialed and mutating; never sit in shared
30 // caches regardless of repo visibility.
31 "Cache-Control": "no-store",
32 "X-Repo-Changed": args.changed ? "1" : "0",
33 "X-Repo-Empty": args.empty ? "1" : "0",
34 },
35 });
36}
37 
38export class ReceiveSidebandWriter {
39 private readonly controller: ReadableStreamDefaultController<Uint8Array>;
40 
41 constructor(controller: ReadableStreamDefaultController<Uint8Array>) {
42 this.controller = controller;
43 }
44 
45 progress(message: string): void {
46 enqueueSidebandPayload(this.controller, 2, new TextEncoder().encode(message));
47 }
48 
49 fatal(message: string): void {
50 enqueueSidebandPayload(this.controller, 3, new TextEncoder().encode(`fatal: ${message}\n`));
51 }
52 
53 reportStatus(reportStatusBody: Uint8Array): void {
54 enqueueSidebandPayload(this.controller, 1, reportStatusBody);
55 this.controller.enqueue(flushPkt());
56 }
57}