Repository Public MIT
1import { createHash } from "node:crypto";2import semver from "semver";3import {4 ArchiveError, LIMITS, SCANNER_VERSION, normalizeCompatibility, parseName, readArchive, securityStatus, validatePackage, versionSchema, type Finding,5} from "@skills/registry-core";6import { audit } from "./audit";7import { isPlatformAdmin, requireScope } from "./auth";8import { userOf, type Ctx } from "./context";9import { verifier } from "./crypto";10import { ApiError, badRequest, conflict, forbidden, notFound, unprocessable } from "./errors";11import { env } from "./env";12import { getArtifactRow, getRelease, recomputeLatest, releaseDto, writableArtifact, type ArtifactRow, type ReleaseRow } from "./registry";13import { discardStaging, openBlob, promoteStaging, readStaging, receiveToStaging } from "./storage";1415const UPLOAD_TTL_MIN = 60;16/** Findings that send a release to human review instead of publishing it directly. */17const REVIEW_CODES = new Set(["exec-pipe-to-shell", "exec-encoded-payload", "exec-destructive", "exec-eval-remote", "cred-access", "prompt-exfiltration", "prompt-concealment", "prompt-override", "text-bidi-control"]);1819interface UploadRow {20 id: string;21 artifact_id: string;22 version: string;23 declared_sha256: string;24 declared_size: string;25 release_notes: string | null;26 source_commit: string | null;27 state: "pending" | "uploaded" | "validating" | "security_review" | "published" | "rejected" | "quarantined" | "expired";28 received_sha256: string | null;29 release_id: string | null;30 rejection: { findings: Finding[] } | null;31 created_by: string;32 created_by_token: string | null;33 expires_at: Date;34}3536export function uploadDto(u: UploadRow) {37 return {38 uploadId: u.id, state: u.state, version: u.version, sha256: u.declared_sha256, sizeBytes: Number(u.declared_size), expiresAt: u.expires_at,39 uploadUrl: `${env.publicUrl}/api/v1/uploads/${u.id}`, uploadMethod: "PUT", uploadContentType: "application/gzip",40 finalizeUrl: `${env.publicUrl}/api/v1/uploads/${u.id}/finalize`, releaseId: u.release_id, findings: u.rejection?.findings ?? undefined,41 };42}4344export interface BeginUploadInput {45 version: string;46 sha256: string;47 sizeBytes: number;48 releaseNotes?: string;49 sourceCommit?: string;50}5152export async function beginUpload(ctx: Ctx, artifactId: string, input: BeginUploadInput) {53 const { a } = await writableArtifact(ctx, artifactId, "uploads:create");54 const v = versionSchema.safeParse(input.version);55 if (!v.success) throw badRequest("version must be a strict semantic version such as 1.2.0 (no build metadata).");56 if (typeof input.sha256 !== "string" || !/^[0-9a-f]{64}$/.test(input.sha256)) throw badRequest("sha256 must be the lowercase hex SHA-256 of the archive.");57 if (!Number.isInteger(input.sizeBytes) || input.sizeBytes < 64) throw badRequest("sizeBytes must be the archive size in bytes.");58 if (input.sizeBytes > LIMITS.maxArchiveBytes) throw new ApiError(413, "payload_too_large", `Archives are limited to ${LIMITS.maxArchiveBytes} bytes.`);59 if (input.sourceCommit !== undefined && !/^[0-9a-f]{7,64}$/.test(input.sourceCommit)) throw badRequest("sourceCommit must be a hexadecimal commit id.");60 if (a.state === "archived" || a.state === "taken_down") throw forbidden(`@${a.namespace}/${a.slug} is ${a.state.replace("_", " ")}; new releases are not accepted.`, "artifact_closed");61 const [exists] = await ctx.sql`SELECT 1 FROM releases WHERE artifact_id = ${a.id} AND version = ${input.version}`;62 if (exists) throw conflict(`Version ${input.version} of @${a.namespace}/${a.slug} already exists. Releases are immutable; publish a new version.`, "version_exists");63 const p = ctx.principal;64 const user = userOf(p)!;65 const [u] = await ctx.sql<UploadRow[]>`66 INSERT INTO uploads (artifact_id, version, declared_sha256, declared_size, release_notes, source_commit, created_by, created_by_token, expires_at)67 VALUES (${a.id}, ${input.version}, ${input.sha256}, ${input.sizeBytes}, ${input.releaseNotes?.slice(0, 20000) ?? null}, ${input.sourceCommit ?? null},68 ${user.id}, ${p.kind === "token" ? p.token.id : null}, ${new Date(Date.now() + UPLOAD_TTL_MIN * 60_000)}) RETURNING *`;69 await audit(ctx, { action: "upload.begin", targetType: "artifact", targetId: a.id, targetLabel: `@${a.namespace}/${a.slug}@${input.version}`, detail: { uploadId: u!.id, sha256: input.sha256, sizeBytes: input.sizeBytes } });70 return uploadDto(u!);71}7273/** Uploads belong to the credential that began them; another token of the same user cannot hijack one. */74async function ownUpload(ctx: Ctx, uploadId: string, scope: "uploads:create" | "releases:publish"): Promise<{ u: UploadRow; a: ArtifactRow }> {75 requireScope(ctx.principal, scope);76 if (!/^[0-9a-f-]{36}$/.test(uploadId)) throw notFound("Upload");77 const [u] = await ctx.sql<UploadRow[]>`SELECT * FROM uploads WHERE id = ${uploadId}`;78 const user = userOf(ctx.principal)!;79 if (!u || u.created_by !== user.id) throw notFound("Upload");80 const { a } = await writableArtifact(ctx, u.artifact_id, scope);81 if (u.state === "pending" && u.expires_at.getTime() < Date.now()) {82 await ctx.sql`UPDATE uploads SET state = 'expired', updated_at = now() WHERE id = ${u.id}`;83 discardStaging(u.id);84 throw new ApiError(410, "upload_expired", "This upload session expired. Begin a new one.");85 }86 return { u, a };87}8889export async function receiveUpload(ctx: Ctx, uploadId: string, body: ReadableStream<Uint8Array> | null, contentLength: number | null) {90 const { u, a } = await ownUpload(ctx, uploadId, "uploads:create");91 if (u.state !== "pending") throw conflict(`This upload is already ${u.state}.`, "upload_state");92 const declared = Number(u.declared_size);93 if (contentLength !== null && contentLength !== declared) throw badRequest(`Content-Length ${contentLength} does not match the declared size ${declared}.`);94 const got = await receiveToStaging(u.id, body, declared);95 if (got.size !== declared || got.sha256 !== u.declared_sha256) {96 discardStaging(u.id);97 await audit(ctx, { action: "upload.receive", result: "denied", targetType: "artifact", targetId: a.id, detail: { uploadId: u.id, reason: "checksum_or_size_mismatch", receivedSize: got.size } });98 throw unprocessable("The received bytes do not match the declared size and SHA-256. Nothing was stored.", "checksum_mismatch", { expectedSha256: u.declared_sha256, receivedSha256: got.sha256, expectedSize: declared, receivedSize: got.size });99 }100 const [n] = await ctx.sql<UploadRow[]>`UPDATE uploads SET state = 'uploaded', staging_key = ${u.id}, received_sha256 = ${got.sha256}, received_size = ${got.size}, updated_at = now() WHERE id = ${u.id} AND state = 'pending' RETURNING *`;101 if (!n) throw conflict("This upload changed state concurrently.", "upload_state");102 await audit(ctx, { action: "upload.receive", targetType: "artifact", targetId: a.id, targetLabel: `@${a.namespace}/${a.slug}@${u.version}`, detail: { uploadId: u.id, sha256: got.sha256 } });103 return uploadDto(n);104}105106/**107 * uploaded → validating → (rejected | security_review → published | quarantined).108 * The archive is parsed in memory and statically inspected. It is never extracted to disk and never executed.109 */110export async function finalizeUpload(ctx: Ctx, uploadId: string, input: { sha256: string }) {111 const { u, a } = await ownUpload(ctx, uploadId, "releases:publish");112 if (u.state === "published" || u.state === "quarantined") {113 // Idempotent replay.114 const r = await getRelease({ ...ctx }, await getArtifactRow(ctx, a.namespace, a.slug), u.version);115 return { upload: uploadDto(u), release: releaseDto(a, r), findings: [] as Finding[], replayed: true };116 }117 if (u.state !== "uploaded") throw conflict(u.state === "pending" ? "Send the archive bytes (PUT uploadUrl) before finalizing." : `This upload is ${u.state}.`, "upload_state", u.rejection ?? undefined);118 if (input.sha256 !== u.declared_sha256) throw unprocessable("sha256 does not match the uploaded archive.", "checksum_mismatch");119 const [claimed] = await ctx.sql<UploadRow[]>`UPDATE uploads SET state = 'validating', updated_at = now() WHERE id = ${u.id} AND state = 'uploaded' RETURNING *`;120 if (!claimed) throw conflict("This upload is already being finalized.", "upload_state");121 const label = `@${a.namespace}/${a.slug}@${u.version}`;122123 const reject = async (findings: Finding[]): Promise<never> => {124 discardStaging(u.id);125 await ctx.sql`UPDATE uploads SET state = 'rejected', rejection = ${ctx.sql.json({ findings } as never)}, updated_at = now() WHERE id = ${u.id}`;126 await ctx.sql`INSERT INTO scan_results (upload_id, scanner_version, findings, max_severity, blocking_count)127 VALUES (${u.id}, ${SCANNER_VERSION}, ${ctx.sql.json(findings as never)}, ${findings[0]?.severity ?? null}, ${findings.filter((f) => f.blocking).length})`;128 await audit(ctx, { action: "release.reject", result: "denied", targetType: "artifact", targetId: a.id, targetLabel: label, detail: { uploadId: u.id, codes: [...new Set(findings.filter((f) => f.blocking).map((f) => f.code))] } });129 throw unprocessable(`Release rejected: ${findings.filter((f) => f.blocking).length} blocking finding(s). Nothing was published.`, "release_rejected", { findings });130 };131132 let bytes: Buffer;133 try {134 bytes = readStaging(u.id);135 } catch {136 await ctx.sql`UPDATE uploads SET state = 'expired', updated_at = now() WHERE id = ${u.id}`;137 throw new ApiError(410, "upload_expired", "The staged archive is no longer available. Begin a new upload.");138 }139 if (createHash("sha256").update(bytes).digest("hex") !== u.declared_sha256) return reject([{ code: "archive-checksum", severity: "critical", message: "staged archive does not match its checksum", blocking: true }]);140141 let files;142 try {143 files = readArchive(bytes);144 } catch (e) {145 if (e instanceof ArchiveError) return reject([{ code: e.code, severity: "critical", message: e.message, blocking: true }]);146 throw e;147 }148 const result = validatePackage(files, { expectedName: `@${a.namespace}/${a.slug}`, expectedVersion: u.version });149 const findings = [...result.findings];150 const m = result.manifest;151 if (m && m.type !== a.type) findings.unshift({ code: "manifest-type-mismatch", severity: "high", message: `manifest type ${m.type} does not match the artifact type ${a.type}; the type of an artifact is immutable`, path: "agent-registry.json", blocking: true });152153 // Dependency references must resolve to visible artifacts (and, for bundles, to existing versions).154 const deps = m?.dependencies ?? [];155 for (const d of deps) {156 const id = parseName(d.name)!;157 const rows = await ctx.sql<{ version: string; visibility: string }[]>`158 SELECT r.version, x.visibility FROM artifacts x LEFT JOIN releases r ON r.artifact_id = x.id AND r.state = 'published'159 WHERE x.namespace = ${id.namespace} AND x.slug = ${id.slug} AND x.state IN ('active','deprecated') AND (x.visibility <> 'private' OR x.namespace = ${a.namespace})`;160 const versions = rows.map((r) => r.version).filter(Boolean);161 if (rows.length === 0) {162 findings.push({ code: "dependency-unknown", severity: d.optional ? "low" : "high", message: `dependency ${d.name} does not exist in this registry`, path: "agent-registry.json", blocking: !d.optional });163 } else if (!versions.some((ver) => semver.satisfies(ver, d.version, { includePrerelease: true }))) {164 findings.push({ code: "dependency-unsatisfied", severity: d.optional ? "low" : "high", message: `no published version of ${d.name} satisfies "${d.version}"`, path: "agent-registry.json", blocking: !d.optional });165 }166 }167 if (!m || findings.some((f) => f.blocking)) return reject(findings);168169 await ctx.sql`UPDATE uploads SET state = 'security_review', updated_at = now() WHERE id = ${u.id}`;170 const needsReview = findings.some((f) => REVIEW_CODES.has(f.code));171 const state = needsReview ? "quarantined" : "published";172 const status = securityStatus(findings);173 const sv = semver.parse(u.version)!;174 const user = userOf(ctx.principal)!;175 const key = promoteStaging(u.id, u.declared_sha256);176177 const release = await ctx.sql.begin(async (tx) => {178 const [r] = await tx<ReleaseRow[]>`179 INSERT INTO releases (artifact_id, version, v_major, v_minor, v_patch, v_prerelease, manifest_json, archive_object_key, sha256, size_bytes, unpacked_bytes, file_count,180 source_commit, release_notes, readme, published_by, published_by_token, state, security_status)181 VALUES (${a.id}, ${u.version}, ${sv.major}, ${sv.minor}, ${sv.patch}, ${sv.prerelease.length ? sv.prerelease.join(".") : null}, ${tx.json(m as never)}, ${key},182 ${u.declared_sha256}, ${bytes.length}, ${result.totalBytes}, ${result.files.length}, ${u.source_commit ?? m.sourceCommit ?? null}, ${u.release_notes},183 ${result.readme}, ${user.id}, ${u.created_by_token}, ${state}, ${status})184 RETURNING *`;185 const byPath = new Map(files.map((f) => [f.path, f]));186 const fileRows = result.files.map((f) => ({187 release_id: r!.id, path: f.path, size_bytes: f.size, sha256: f.sha256, mime: f.mime, mode: f.mode, is_text: f.isText,188 content_text: f.isText && f.size <= LIMITS.maxPreviewBytes ? byPath.get(f.path)!.data.toString("utf8").replace(/\u0000/g, "") : null,189 }));190 for (let i = 0; i < fileRows.length; i += 200) await tx`INSERT INTO release_files ${tx(fileRows.slice(i, i + 200))}`;191 for (const d of deps) {192 const id = parseName(d.name)!;193 await tx`INSERT INTO release_dependencies (release_id, dep_namespace, dep_slug, version_range, optional) VALUES (${r!.id}, ${id.namespace}, ${id.slug}, ${d.version}, ${d.optional ?? false})`;194 }195 for (const c of normalizeCompatibility(m)) {196 await tx`INSERT INTO release_compatibility (release_id, client, platform, min_version, install_strategy) VALUES (${r!.id}, ${c.client}, ${c.platform}, ${c.minVersion}, ${c.installStrategy})197 ON CONFLICT DO NOTHING`;198 }199 await tx`INSERT INTO scan_results (upload_id, release_id, scanner_version, findings, max_severity, blocking_count)200 VALUES (${u.id}, ${r!.id}, ${SCANNER_VERSION}, ${tx.json(findings as never)}, ${result.maxSeverity}, 0)`;201 await tx`UPDATE uploads SET state = ${state}, release_id = ${r!.id}, updated_at = now() WHERE id = ${u.id}`;202 if (state === "published") {203 await recomputeLatest(tx as never, a.id);204 const [art] = await tx<{ latest_release_id: string | null }[]>`SELECT latest_release_id FROM artifacts WHERE id = ${a.id}`;205 if (art!.latest_release_id === r!.id) {206 // Listing metadata follows the newest release's manifest; history stays in each release row.207 await tx`UPDATE artifacts SET summary = ${m.description}, license = ${m.license}, keywords = ${m.keywords ?? []}, capabilities = ${result.capabilities},208 description = ${result.readme}, repository_url = coalesce(${m.repository ?? null}, repository_url), homepage_url = coalesce(${m.homepage ?? null}, homepage_url),209 issues_url = coalesce(${m.issues ?? null}, issues_url),210 source_verified = CASE WHEN repository_url IS DISTINCT FROM coalesce(${m.repository ?? null}, repository_url) THEN false ELSE source_verified END,211 updated_at = now() WHERE id = ${a.id}`;212 }213 }214 await audit({ ...ctx, sql: tx as never }, {215 action: state === "published" ? "release.publish" : "release.quarantine", targetType: "release", targetId: r!.id, targetLabel: label,216 detail: { uploadId: u.id, sha256: r!.sha256, sizeBytes: bytes.length, files: result.files.length, securityStatus: status, advisoryCodes: [...new Set(findings.map((f) => f.code))] },217 });218 return r!;219 });220 const [uNow] = await ctx.sql<UploadRow[]>`SELECT * FROM uploads WHERE id = ${u.id}`;221 return { upload: uploadDto(uNow!), release: releaseDto(a, release), findings, replayed: false };222}223224export async function getUpload(ctx: Ctx, uploadId: string) {225 const { u } = await ownUpload(ctx, uploadId, "uploads:create");226 return uploadDto(u);227}228229async function releaseById(ctx: Ctx, id: string): Promise<ReleaseRow> {230 if (!/^[0-9a-f-]{36}$/.test(id)) throw notFound("Release");231 const [r] = await ctx.sql<ReleaseRow[]>`SELECT * FROM releases WHERE id = ${id}`;232 if (!r) throw notFound("Release");233 return r;234}235236/** Revocation is the takedown state for a compromised version. The record and its audit trail remain. */237export async function revokeRelease(ctx: Ctx, releaseId: string, input: { reason?: string; confirm?: boolean }) {238 requireScope(ctx.principal, "releases:revoke");239 const r0 = await releaseById(ctx, releaseId);240 const p = ctx.principal;241 const user = userOf(p)!;242 const moderator = isPlatformAdmin(user) && (p.kind !== "token" || (p.token.elevated && p.token.scopes.includes("admin:moderate")));243 const a = moderator ? await getArtifactRow({ ...ctx, principal: { kind: "local", user } }, ...(await nameOf(ctx, r0.artifact_id))) : (await writableArtifact(ctx, r0.artifact_id, "releases:revoke")).a;244 const reason = (input.reason ?? "").trim().slice(0, 1000);245 if (reason.length < 5) throw badRequest("A revocation reason (5+ characters) is required; it is shown publicly.");246 if (input.confirm !== true) throw new ApiError(428, "confirmation_required", `Revoking @${a.namespace}/${a.slug}@${r0.version} blocks downloads permanently. Resend with confirm: true.`);247 if (r0.state === "revoked") return releaseDto(a, r0);248 const r = await ctx.sql.begin(async (tx) => {249 const [x] = await tx<ReleaseRow[]>`UPDATE releases SET state = 'revoked', revoked_at = now(), revoked_by = ${user.id}, revocation_reason = ${reason} WHERE id = ${r0.id} RETURNING *`;250 await recomputeLatest(tx as never, a.id);251 await audit({ ...ctx, sql: tx as never }, { action: "release.revoke", targetType: "release", targetId: r0.id, targetLabel: `@${a.namespace}/${a.slug}@${r0.version}`, detail: { reason, asModerator: moderator } });252 return x!;253 });254 return releaseDto(a, r);255}256257async function nameOf(ctx: Ctx, artifactId: string): Promise<[string, string]> {258 const [x] = await ctx.sql<{ namespace: string; slug: string }[]>`SELECT namespace, slug FROM artifacts WHERE id = ${artifactId}`;259 if (!x) throw notFound("Artifact");260 return [x.namespace, x.slug];261}262263/** releases:update — release notes only. Content, manifest, version and checksum are frozen by a database trigger. */264export async function updateReleaseNotes(ctx: Ctx, releaseId: string, patch: Record<string, unknown>) {265 requireScope(ctx.principal, "releases:update");266 const r0 = await releaseById(ctx, releaseId);267 const { a } = await writableArtifact(ctx, r0.artifact_id, "releases:update");268 const keys = Object.keys(patch);269 if (keys.length !== 1 || keys[0] !== "releaseNotes") throw new ApiError(409, "release_immutable", "Published releases are immutable. Only `releaseNotes` can be edited; publish a new version to change content.");270 const notes = patch.releaseNotes === null ? null : String(patch.releaseNotes).slice(0, 20000);271 const [r] = await ctx.sql<ReleaseRow[]>`UPDATE releases SET release_notes = ${notes} WHERE id = ${r0.id} RETURNING *`;272 await audit(ctx, { action: "release.update_notes", targetType: "release", targetId: r0.id, targetLabel: `@${a.namespace}/${a.slug}@${r0.version}`, detail: { previousLength: r0.release_notes?.length ?? 0, newLength: notes?.length ?? 0 } });273 return releaseDto(a, r!);274}275276/** Moderator decision on a quarantined release. */277export async function reviewRelease(ctx: Ctx, releaseId: string, input: { decision: string; reason?: string }) {278 requireScope(ctx.principal, "admin:moderate");279 const p = ctx.principal;280 if (p.kind === "token" && !p.token.elevated) throw forbidden("Moderation requires an elevated token.", "admin_required");281 const r0 = await releaseById(ctx, releaseId);282 const user = userOf(p)!;283 const [ns, slug] = await nameOf(ctx, r0.artifact_id);284 if (r0.state !== "quarantined") throw conflict(`This release is ${r0.state}, not quarantined.`, "release_state");285 if (input.decision !== "approve" && input.decision !== "reject") throw badRequest("decision must be approve or reject.");286 const reason = (input.reason ?? "").trim().slice(0, 1000);287 if (reason.length < 5) throw badRequest("A review note (5+ characters) is required.");288 await ctx.sql.begin(async (tx) => {289 if (input.decision === "approve") await tx`UPDATE releases SET state = 'published' WHERE id = ${r0.id}`;290 else await tx`UPDATE releases SET state = 'revoked', revoked_at = now(), revoked_by = ${user.id}, revocation_reason = ${`Rejected in security review: ${reason}`} WHERE id = ${r0.id}`;291 await tx`UPDATE uploads SET state = ${input.decision === "approve" ? "published" : "rejected"}, updated_at = now() WHERE release_id = ${r0.id}`;292 await recomputeLatest(tx as never, r0.artifact_id);293 await tx`INSERT INTO moderation_actions (actor_user_id, action, target_type, target_id, reason) VALUES (${user.id}, ${`release.review.${input.decision}`}, 'release', ${r0.id}, ${reason})`;294 await audit({ ...ctx, sql: tx as never }, { action: `release.review.${input.decision}`, targetType: "release", targetId: r0.id, targetLabel: `@${ns}/${slug}@${r0.version}`, detail: { reason } });295 });296 const a = await getArtifactRow({ ...ctx, principal: { kind: "local", user } }, ns, slug);297 return releaseDto(a, await releaseById(ctx, r0.id));298}299300/* ───────────────────────── downloads ───────────────────────── */301302const BOT_UA = /bot|crawl|spider|slurp|preview|monitor|uptime|headless|scan|python-urllib|go-http-client\/1|facebookexternalhit|curl\/0/i;303304/** Daily aggregate, one count per (release, visitor-hash, day). The hash is salted per day and purged after two days. */305export async function countDownload(ctx: Ctx, releaseId: string) {306 if (!ctx.userAgent || BOT_UA.test(ctx.userAgent)) return;307 const day = new Date().toISOString().slice(0, 10);308 const hash = verifier("download", `${day}\0${releaseId}\0${ctx.ip}\0${ctx.userAgent}`).slice(0, 32);309 const ins = await ctx.sql`INSERT INTO download_dedupe (day, hash) VALUES (${day}, ${hash}) ON CONFLICT DO NOTHING`;310 if (ins.count === 0) return;311 await ctx.sql`INSERT INTO download_daily (release_id, day, count) VALUES (${releaseId}, ${day}, 1) ON CONFLICT (release_id, day) DO UPDATE SET count = download_daily.count + 1`;312 if (Math.random() < 0.01) await ctx.sql`DELETE FROM download_dedupe WHERE day < current_date - 2`;313}314315export async function downloadRelease(ctx: Ctx, a: ArtifactRow, r: ReleaseRow, ifNoneMatch: string | null): Promise<Response> {316 if (r.state === "revoked") throw new ApiError(410, "release_revoked", `@${a.namespace}/${a.slug}@${r.version} was revoked: ${r.revocation_reason ?? "no reason recorded"}.`);317 const etag = `"sha256-${r.sha256}"`;318 const isPublic = a.visibility !== "private" && r.state === "published";319 const headers: Record<string, string> = {320 ETag: etag,321 "Cache-Control": isPublic ? "public, max-age=31536000, immutable" : "private, no-store",322 "X-Checksum-Sha256": r.sha256,323 "Repr-Digest": `sha-256=:${Buffer.from(r.sha256, "hex").toString("base64")}:`,324 "X-Content-Type-Options": "nosniff",325 };326 if (ifNoneMatch && ifNoneMatch.split(",").map((s) => s.trim()).includes(etag)) return new Response(null, { status: 304, headers });327 const { stream, size } = openBlob(r.archive_object_key);328 await countDownload(ctx, r.id);329 return new Response(stream, {330 status: 200,331 headers: { ...headers, "Content-Type": "application/gzip", "Content-Length": String(size), "Content-Disposition": `attachment; filename="${a.slug}-${r.version}.tar.gz"` },332 });333}334