git-fs-s3 0.15.0 → 0.15.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/ops/tree.ts","../src/ops/types.ts","../src/ops/history.ts","../src/ops/branch.ts","../src/pack-write.ts","../src/semaphore.ts"],"sourcesContent":["import git from \"isomorphic-git\";\nimport { GitInvalidRequestError, GitPathNotFoundError } from \"../git-errors.js\";\nimport type { Repo } from \"./types.js\";\n\nexport interface TreeEntry {\n\tpath: string;\n\tmode: string;\n\ttype: \"blob\" | \"tree\" | \"commit\";\n\toid: string;\n\tsize?: number;\n}\n\nconst joinPath = (prefix: string, name: string) =>\n\tprefix ? `${prefix.replace(/\\/+$/, \"\")}/${name}` : name;\n\n/** File modes a blob entry can carry; anything else isn't a regular file. */\nconst BLOB_MODES = new Set([\"100644\", \"100755\", \"120000\"]);\n\n/**\n * Build/update a git tree by overlaying new blobs onto an existing tree,\n * returning the new root tree oid. `entries` maps relative paths to blob oids.\n *\n * An updated file keeps its existing mode (executable bit, symlink); a path\n * that names an existing directory, or runs through an existing file, is\n * rejected rather than silently replacing what's there.\n */\nexport async function upsertTree(\n\trepo: Repo,\n\ttreeOid: string | undefined,\n\tentries: Map<string, string>,\n): Promise<string> {\n\tconst existing = treeOid\n\t\t? (await git.readTree({ ...repo, oid: treeOid })).tree\n\t\t: [];\n\tconst byName = new Map(existing.map((e) => [e.path, e]));\n\tconst direct = new Map<string, string>();\n\tconst nested = new Map<string, Map<string, string>>();\n\tfor (const [filePath, blobOid] of entries) {\n\t\tconst slash = filePath.indexOf(\"/\");\n\t\tif (slash === -1) {\n\t\t\tdirect.set(filePath, blobOid);\n\t\t} else {\n\t\t\tconst dir = filePath.slice(0, slash);\n\t\t\tconst rest = filePath.slice(slash + 1);\n\t\t\tif (!nested.has(dir)) nested.set(dir, new Map());\n\t\t\tnested.get(dir)?.set(rest, blobOid);\n\t\t}\n\t}\n\tfor (const [name, blobOid] of direct) {\n\t\tconst current = byName.get(name);\n\t\tif (current && current.type !== \"blob\") {\n\t\t\tthrow new GitInvalidRequestError(`\"${name}\" is a directory, not a file`);\n\t\t}\n\t\tbyName.set(name, {\n\t\t\tmode: current && BLOB_MODES.has(current.mode) ? current.mode : \"100644\",\n\t\t\tpath: name,\n\t\t\toid: blobOid,\n\t\t\ttype: \"blob\",\n\t\t});\n\t}\n\t// Sibling subdirectories are independent subtree writes — no reason to\n\t// serialize them for multi-file commits touching several directories.\n\tconst nestedResults = await Promise.all(\n\t\tArray.from(nested, async ([dir, subEntries]) => {\n\t\t\tconst entry = byName.get(dir);\n\t\t\tif (entry && entry.type !== \"tree\") {\n\t\t\t\tthrow new GitInvalidRequestError(`\"${dir}\" is a file, not a directory`);\n\t\t\t}\n\t\t\tconst subtreeOid = entry?.oid;\n\t\t\tconst newOid = await upsertTree(repo, subtreeOid, subEntries);\n\t\t\treturn [dir, newOid] as const;\n\t\t}),\n\t);\n\tfor (const [dir, newOid] of nestedResults) {\n\t\tbyName.set(dir, { mode: \"040000\", path: dir, oid: newOid, type: \"tree\" });\n\t}\n\treturn git.writeTree({ ...repo, tree: Array.from(byName.values()) });\n}\n\n/**\n * Remove a file path from a tree, returning the new root tree oid. Throws\n * GitPathNotFoundError when there's no such file; directories left empty\n * are dropped, as git never stores an empty subtree.\n */\nexport async function deleteFromTree(\n\trepo: Repo,\n\ttreeOid: string,\n\tfilePath: string,\n): Promise<string> {\n\tconst result = await deleteFromSubtree(repo, treeOid, filePath, filePath);\n\treturn result ?? git.writeTree({ ...repo, tree: [] });\n}\n\n/** The new subtree oid, or null when removing the file left it empty. */\nasync function deleteFromSubtree(\n\trepo: Repo,\n\ttreeOid: string,\n\tfilePath: string,\n\tfullPath: string,\n): Promise<string | null> {\n\tconst existing = (await git.readTree({ ...repo, oid: treeOid })).tree;\n\tconst byName = new Map(existing.map((e) => [e.path, e]));\n\tconst slash = filePath.indexOf(\"/\");\n\tconst name = slash === -1 ? filePath : filePath.slice(0, slash);\n\tconst entry = byName.get(name);\n\tif (slash === -1) {\n\t\tif (entry?.type !== \"blob\") {\n\t\t\tthrow new GitPathNotFoundError(`No such file: ${fullPath}`);\n\t\t}\n\t\tbyName.delete(name);\n\t} else {\n\t\tif (entry?.type !== \"tree\") {\n\t\t\tthrow new GitPathNotFoundError(`No such file: ${fullPath}`);\n\t\t}\n\t\tconst newOid = await deleteFromSubtree(\n\t\t\trepo,\n\t\t\tentry.oid,\n\t\t\tfilePath.slice(slash + 1),\n\t\t\tfullPath,\n\t\t);\n\t\tif (newOid === null) byName.delete(name);\n\t\telse byName.set(name, { ...entry, oid: newOid });\n\t}\n\tif (byName.size === 0) return null;\n\treturn git.writeTree({ ...repo, tree: Array.from(byName.values()) });\n}\n\n/** Resolve a path inside a tree to its entry, or null when absent. */\nexport async function findTreeEntry(\n\trepo: Repo,\n\trootTreeOid: string,\n\ttreePath: string,\n): Promise<TreeEntry | null> {\n\tif (!treePath) {\n\t\treturn { path: \"\", mode: \"040000\", type: \"tree\", oid: rootTreeOid };\n\t}\n\n\tconst parts = treePath.split(\"/\").filter(Boolean);\n\tlet currentTreeOid = rootTreeOid;\n\tlet currentPath = \"\";\n\n\tfor (const [index, part] of parts.entries()) {\n\t\tconst tree = await git.readTree({ ...repo, oid: currentTreeOid });\n\t\tconst entry = tree.tree.find((candidate) => candidate.path === part);\n\n\t\tif (!entry) return null;\n\n\t\tcurrentPath = currentPath ? joinPath(currentPath, entry.path) : entry.path;\n\n\t\tif (index === parts.length - 1) {\n\t\t\treturn {\n\t\t\t\tpath: currentPath,\n\t\t\t\tmode: entry.mode,\n\t\t\t\ttype: entry.type,\n\t\t\t\toid: entry.oid,\n\t\t\t};\n\t\t}\n\n\t\tif (entry.type !== \"tree\") return null;\n\n\t\tcurrentTreeOid = entry.oid;\n\t}\n\n\treturn null;\n}\n\n/** List a tree's direct entries, with paths prefixed by `prefix`. */\nexport async function listTreeEntries(\n\trepo: Repo,\n\ttreeOid: string,\n\tprefix = \"\",\n): Promise<TreeEntry[]> {\n\tconst tree = await git.readTree({ ...repo, oid: treeOid });\n\n\treturn tree.tree.map((entry) => ({\n\t\tpath: prefix ? joinPath(prefix, entry.path) : entry.path,\n\t\tmode: entry.mode,\n\t\ttype: entry.type,\n\t\toid: entry.oid,\n\t}));\n}\n","import type git from \"isomorphic-git\";\n\n/** The fs shape isomorphic-git accepts, derived from its own signatures. */\nexport type IsoGitFs = Parameters<typeof git.readTree>[0][\"fs\"];\n\n/**\n * A repository handle: everything isomorphic-git needs to address one bare\n * repo. Create it once per request (sharing `cache` across calls is what lets\n * isomorphic-git reuse parsed pack indexes) and pass it to every op.\n */\nexport interface Repo {\n\tfs: IsoGitFs;\n\tgitdir: string;\n\t/** isomorphic-git's shared parse cache — strongly recommended per repo. */\n\tcache?: object;\n}\n\n/**\n * Key/value store for memoizing expensive walk results (commit logs, tree\n * listings, per-path history). Keys are namespaced `kind:gitdir:headSha:…`,\n * so entries self-invalidate on push (new head, new key); evict\n * {@link resultKeyPrefixes} to drop a repo's superseded entries early.\n * Values are always objects (arrays or records).\n */\nexport interface ResultCache {\n\tget<T extends object>(key: string): T | null | undefined;\n\tset(key: string, value: object): void;\n}\n\n/** Optional instrumentation hooks accepted by every op. */\nexport interface OpsHooks {\n\tresultCache?: ResultCache;\n\t/** Wrap a timed sub-step (network walk, tree listing). Default: run directly. */\n\tstep?: <T>(label: string, fn: () => Promise<T>) => Promise<T>;\n\t/** Diagnostic sink for cache hit/miss and walk summaries. */\n\tonNote?: (message: string) => void;\n\t/**\n\t * Warm every pack (e.g. `GitFs.prefetchPacks`) before a cache-miss read,\n\t * so a sequential walk doesn't discover packs one round trip at a time.\n\t */\n\tprefetch?: () => Promise<void>;\n}\n\nexport const runStep = <T>(\n\thooks: OpsHooks | undefined,\n\tlabel: string,\n\tfn: () => Promise<T>,\n): Promise<T> => (hooks?.step ? hooks.step(label, fn) : fn());\n\n/**\n * The result-cache key prefixes holding entries for `gitdir` — evict these\n * from your {@link ResultCache} when the repo's storage was rewritten outside\n * a normal push (rename, repack).\n */\nexport function resultKeyPrefixes(gitdir: string): string[] {\n\treturn [\n\t\t`commitlog:${gitdir}:`,\n\t\t`tree:${gitdir}:`,\n\t\t`last-commits:${gitdir}:`,\n\t\t`file-history:${gitdir}:`,\n\t];\n}\n","import git from \"isomorphic-git\";\nimport {\n\tGitObjectNotFoundError,\n\tGitPathNotFoundError,\n\tGitRefNotFoundError,\n} from \"../git-errors.js\";\nimport { qualifyBranchRef } from \"../refs.js\";\nimport { findTreeEntry, listTreeEntries, type TreeEntry } from \"./tree.js\";\nimport { type OpsHooks, type Repo, runStep } from \"./types.js\";\n\n/** How far back history walks look by default (commit count). */\nexport const HISTORY_WALK_DEPTH = 400;\n\nexport interface GitIdentity {\n\tname: string;\n\temail: string;\n\ttimestamp: number;\n\ttimezoneOffset: number;\n}\n\nexport interface CommitInfo {\n\toid: string;\n\tcommit: {\n\t\tmessage: string;\n\t\ttree: string;\n\t\tparent: string[];\n\t\tauthor: GitIdentity;\n\t\tcommitter: GitIdentity;\n\t};\n\tpayload: string;\n}\n\n/** The display summary of a commit (history lists, \"last commit\" columns). */\nexport interface CommitSummary {\n\tsha: string;\n\tmessage: string;\n\tauthorName: string;\n\tauthorEmail: string;\n\t/** ISO 8601 author date. */\n\tcreatedAt: string;\n}\n\nexport function summarizeCommit(commit: CommitInfo): CommitSummary {\n\treturn {\n\t\tsha: commit.oid,\n\t\tmessage: commit.commit.message.trim(),\n\t\tauthorName: commit.commit.author.name,\n\t\tauthorEmail: commit.commit.author.email,\n\t\tcreatedAt: new Date(commit.commit.author.timestamp * 1000).toISOString(),\n\t};\n}\n\nconst isNotFound = (err: unknown) =>\n\t(err as { code?: string } | null)?.code === \"NotFoundError\";\n\n/**\n * A ref that doesn't resolve is an expected condition (empty repo, unborn\n * branch) each caller handles. An object missing *underneath* a resolved ref\n * means storage is inconsistent — raised as GitObjectNotFoundError so it is\n * never mistaken for \"empty\".\n */\nfunction wrapMissingObject<T>(\n\tpromise: Promise<T>,\n\tcontext: string,\n): Promise<T> {\n\treturn promise.catch((err: unknown) => {\n\t\tif (isNotFound(err)) {\n\t\t\tthrow new GitObjectNotFoundError(\n\t\t\t\t`Git data for ${context} is missing from storage`,\n\t\t\t);\n\t\t}\n\t\tthrow err;\n\t});\n}\n\n/** The commit a branch name, full ref or sha points at; GitRefNotFoundError if none. */\n/**\n * A short name tries `refs/heads/<name>` first and then `refs/tags/<name>`,\n * so a branch wins over a same-named tag. Annotated tags are peeled to the\n * commit they point at, so every read accepts a tag wherever it accepts a\n * branch.\n */\nasync function resolveRefOid(repo: Repo, ref: string): Promise<string> {\n\tconst qualified = qualifyBranchRef(ref);\n\tconst candidates =\n\t\tqualified === `refs/heads/${ref}`\n\t\t\t? [qualified, `refs/tags/${ref}`]\n\t\t\t: [qualified];\n\tfor (const candidate of candidates) {\n\t\ttry {\n\t\t\treturn await peelToCommit(\n\t\t\t\trepo,\n\t\t\t\tawait git.resolveRef({ ...repo, ref: candidate }),\n\t\t\t);\n\t\t} catch (err) {\n\t\t\tif (!isNotFound(err)) throw err;\n\t\t}\n\t}\n\tthrow new GitRefNotFoundError(`Ref ${ref} does not exist`);\n}\n\n/** Follow annotated tags (possibly nested) down to the object they name. */\nexport async function peelToCommit(repo: Repo, oid: string): Promise<string> {\n\tlet current = oid;\n\tfor (let depth = 0; depth < 10; depth++) {\n\t\tconst { type, object } = await git.readObject({\n\t\t\t...repo,\n\t\t\toid: current,\n\t\t\tformat: \"parsed\",\n\t\t});\n\t\tif (type !== \"tag\") return current;\n\t\tcurrent = (object as { object: string }).object;\n\t}\n\tthrow new GitRefNotFoundError(`Tag chain at ${oid} is too deep`);\n}\n\n/** Resolve a branch name / full ref / sha to its commit. */\nexport async function resolveCommit(repo: Repo, ref: string) {\n\tconst oid = await resolveRefOid(repo, ref);\n\tconst { commit } = await wrapMissingObject(\n\t\tgit.readCommit({ ...repo, oid }),\n\t\t`${repo.gitdir} commit ${oid}`,\n\t);\n\treturn { oid, commit };\n}\n\n/** Read a blob's bytes by oid. */\nexport async function getBlob(repo: Repo, sha: string): Promise<Uint8Array> {\n\tconst { blob } = await wrapMissingObject(\n\t\tgit.readBlob({ ...repo, oid: sha }),\n\t\t`${repo.gitdir} blob ${sha}`,\n\t);\n\treturn blob;\n}\n\n/** Read a file's bytes at a ref. Throws GitPathNotFoundError when absent. */\nexport async function getFileContent(\n\trepo: Repo,\n\tfilePath: string,\n\tref: string,\n\thooks?: OpsHooks,\n): Promise<Uint8Array> {\n\t// A commit, a tree per path segment, then the blob: warm every pack first\n\t// rather than discovering them one round trip at a time.\n\tif (hooks?.prefetch) await runStep(hooks, \"prefetch\", hooks.prefetch);\n\tconst { commit } = await resolveCommit(repo, ref);\n\tconst context = `${repo.gitdir}@${ref}:${filePath}`;\n\tconst entry = await wrapMissingObject(\n\t\tfindTreeEntry(repo, commit.tree, filePath),\n\t\tcontext,\n\t);\n\tif (entry?.type !== \"blob\") {\n\t\tthrow new GitPathNotFoundError(`File not found: ${filePath}`);\n\t}\n\tconst { blob } = await wrapMissingObject(\n\t\tgit.readBlob({ ...repo, oid: entry.oid }),\n\t\tcontext,\n\t);\n\treturn blob;\n}\n\n/** Read one commit by sha. */\nexport async function getCommit(repo: Repo, sha: string): Promise<CommitInfo> {\n\tconst result = await wrapMissingObject(\n\t\tgit.readCommit({ ...repo, oid: sha }),\n\t\t`${repo.gitdir} commit ${sha}`,\n\t);\n\treturn { oid: result.oid, commit: result.commit, payload: result.payload };\n}\n\nexport interface CommitLogOptions {\n\tref: string;\n\tdepth?: number;\n\t/** The ref's commit, when the caller already resolved it (saves a lookup). */\n\tknownHeadSha?: string;\n}\n\n/**\n * The commit chain from a ref, newest first; [] when the ref doesn't exist.\n * Walking is sequential and round-trip-bound on object storage, so the\n * deepest walk seen per head is memoized in `hooks.resultCache` and sliced\n * for shallower requests.\n */\nexport async function getCommitLog(\n\trepo: Repo,\n\toptions: CommitLogOptions,\n\thooks?: OpsHooks,\n): Promise<CommitInfo[]> {\n\tconst { ref } = options;\n\tconst depth = options.depth ?? 50;\n\tlet headSha = options.knownHeadSha;\n\tif (headSha === undefined) {\n\t\ttry {\n\t\t\theadSha = await resolveRefOid(repo, ref);\n\t\t} catch (err) {\n\t\t\tif (err instanceof GitRefNotFoundError) return [];\n\t\t\tthrow err;\n\t\t}\n\t}\n\n\tconst cacheKey = `commitlog:${repo.gitdir}:${headSha}`;\n\tconst cached = hooks?.resultCache?.get<CommitInfo[]>(cacheKey);\n\tconst fullyWalked = cached?.at(-1)?.commit.parent.length === 0;\n\tif (cached && (cached.length >= depth || fullyWalked)) {\n\t\thooks?.onNote?.(`getCommitLog: cache hit ${cacheKey} (depth=${depth})`);\n\t\treturn cached.slice(0, depth);\n\t}\n\thooks?.onNote?.(`getCommitLog: cache miss ${cacheKey} (depth=${depth})`);\n\tif (hooks?.prefetch) await runStep(hooks, \"prefetch\", hooks.prefetch);\n\n\tconst log = await wrapMissingObject(\n\t\trunStep(hooks, `git.log ${ref} depth=${depth}`, () =>\n\t\t\tgit.log({ ...repo, ref: headSha, depth }),\n\t\t),\n\t\t`${repo.gitdir}@${ref} history`,\n\t);\n\tconst result = log.map(({ oid, commit, payload }) => ({\n\t\toid,\n\t\tcommit,\n\t\tpayload: payload ?? \"\",\n\t}));\n\tif (!cached || result.length > cached.length) {\n\t\thooks?.resultCache?.set(cacheKey, result);\n\t}\n\treturn result;\n}\n\n/**\n * List a directory at the tip of a ref. Throws GitRefNotFoundError when the\n * ref doesn't resolve and GitPathNotFoundError when `treePath` doesn't exist.\n * Memoized per head sha.\n */\nexport async function getTreeFromRef(\n\trepo: Repo,\n\toptions: { ref: string; treePath?: string },\n\thooks?: OpsHooks,\n): Promise<TreeEntry[]> {\n\tconst { ref } = options;\n\tconst treePath = options.treePath ?? \"\";\n\tconst { commit, oid: headSha } = await resolveCommit(repo, ref);\n\n\tconst cacheKey = `tree:${repo.gitdir}:${headSha}:${treePath}`;\n\tconst cached = hooks?.resultCache?.get<TreeEntry[]>(cacheKey);\n\tif (cached) {\n\t\thooks?.onNote?.(`getTreeFromRef: cache hit ${cacheKey}`);\n\t\treturn cached;\n\t}\n\thooks?.onNote?.(`getTreeFromRef: cache miss ${cacheKey}`);\n\tif (hooks?.prefetch) await runStep(hooks, \"prefetch\", hooks.prefetch);\n\n\tconst context = `${repo.gitdir}@${ref}:${treePath || \"/\"}`;\n\tconst dir = treePath\n\t\t? await wrapMissingObject(\n\t\t\t\trunStep(hooks, `findTreeEntry ${treePath}`, () =>\n\t\t\t\t\tfindTreeEntry(repo, commit.tree, treePath),\n\t\t\t\t),\n\t\t\t\tcontext,\n\t\t\t)\n\t\t: { path: \"\", type: \"tree\" as const, oid: commit.tree };\n\tif (!dir) {\n\t\tthrow new GitPathNotFoundError(\n\t\t\t`Path \"${treePath}\" does not exist at ${ref}`,\n\t\t);\n\t}\n\tconst result =\n\t\tdir.type === \"tree\"\n\t\t\t? await wrapMissingObject(\n\t\t\t\t\trunStep(hooks, `listTreeEntries ${treePath || \"/\"}`, () =>\n\t\t\t\t\t\tlistTreeEntries(repo, dir.oid, dir.path),\n\t\t\t\t\t),\n\t\t\t\t\tcontext,\n\t\t\t\t)\n\t\t\t: [];\n\thooks?.resultCache?.set(cacheKey, result);\n\treturn result;\n}\n\n/**\n * A page of commit history from a ref tip; [] when the ref doesn't exist.\n * Pages are slices of {@link getCommitLog}'s memoized walk.\n */\nexport async function getCommitHistory(\n\trepo: Repo,\n\toptions: { ref: string; limit?: number; skip?: number },\n\thooks?: OpsHooks,\n): Promise<CommitInfo[]> {\n\tconst limit = options.limit ?? 50;\n\tconst skip = options.skip ?? 0;\n\tconst log = await getCommitLog(\n\t\trepo,\n\t\t{ ref: options.ref, depth: limit + skip },\n\t\thooks,\n\t);\n\treturn log.slice(skip, skip + limit);\n}\n","import git from \"isomorphic-git\";\nimport { GitConflictError, GitInvalidRequestError } from \"../git-errors.js\";\nimport { isSafeBranchName } from \"../refs.js\";\nimport { peelToCommit } from \"./history.js\";\nimport type { Repo } from \"./types.js\";\n\nexport interface Branch {\n\tname: string;\n\tcommit: string;\n\tisDefault: boolean;\n}\n\nexport interface Tag {\n\tname: string;\n\t/** The commit the tag names (annotated tags peeled). */\n\tcommit: string;\n\t/** The tag object's own oid, for annotated tags; absent for lightweight ones. */\n\ttagObject?: string;\n}\n\n/**\n * Defense in depth for every branch-name argument below: `git.deleteBranch`\n * and raw resolveRef/writeRef reads don't validate ref names internally the\n * way `git.branch` does (see refs.ts) — guard at the point the primitives are\n * actually called, not just at an API boundary far above.\n */\nexport function assertSafeBranchName(name: string): void {\n\tif (!isSafeBranchName(name)) {\n\t\tthrow new GitInvalidRequestError(`Invalid branch name: ${name}`);\n\t}\n}\n\nconst FULL_SHA_RE = /^[0-9a-f]{40}$/i;\n\ntype RecursiveFileLister = {\n\tlistFilesRecursively(dirpath: string): Promise<string[]>;\n};\n\nfunction hasRecursiveFileLister(\n\tfs: Repo[\"fs\"],\n): fs is Repo[\"fs\"] & RecursiveFileLister {\n\treturn (\n\t\ttypeof fs === \"object\" &&\n\t\tfs !== null &&\n\t\t\"listFilesRecursively\" in fs &&\n\t\ttypeof (fs as Partial<RecursiveFileLister>).listFilesRecursively ===\n\t\t\t\"function\"\n\t);\n}\n\ntype PromisesFs = {\n\treadFile(path: string, encoding: \"utf8\"): Promise<string | Uint8Array>;\n};\n\n// Repo.fs is typed as isomorphic-git's own fs union (promise- or\n// callback-based) since that's what git.readTree's signature allows, but\n// every fs this package actually constructs (git-fs.ts) is promise-based —\n// this just keeps the callback-style branch honest instead of crashing on\n// it. Shared by every loose-ref fast path below instead of each repeating\n// the same cast + presence check.\nfunction getPromisesFs(fs: Repo[\"fs\"]): PromisesFs | null {\n\tconst promises = (fs as { promises?: PromisesFs }).promises;\n\treturn promises ?? null;\n}\n\nfunction decodeFileContent(content: string | Uint8Array): string {\n\treturn typeof content === \"string\"\n\t\t? content\n\t\t: new TextDecoder().decode(content);\n}\n\n/**\n * Lists loose branch names without isomorphic-git's recursive readdir/stat\n * traversal. Object stores already return only leaf keys in a recursive LIST,\n * so this is one request regardless of branch-name nesting. Ordinary\n * filesystems retain isomorphic-git's implementation and packed refs remain\n * supported there.\n */\nasync function listLooseBranches(repo: Repo): Promise<string[] | null> {\n\treturn listLooseRefNames(repo, \"refs/heads\");\n}\n\n/**\n * Loose ref names under `dir` (e.g. `refs/tags`) in one recursive listing,\n * or `null` when the fs can't list recursively (use isomorphic-git's walk).\n */\nexport async function listLooseRefNames(\n\trepo: Repo,\n\tdir: \"refs/heads\" | \"refs/tags\",\n): Promise<string[] | null> {\n\tif (!hasRecursiveFileLister(repo.fs)) return null;\n\tconst names = await repo.fs.listFilesRecursively(`${repo.gitdir}/${dir}`);\n\treturn names.filter(isSafeBranchName);\n}\n\n/** Read packed branch refs so the object-store fast path preserves Git semantics. */\nasync function readPackedBranches(repo: Repo): Promise<Map<string, string>> {\n\tif (!hasRecursiveFileLister(repo.fs)) return new Map();\n\tconst promisesFs = getPromisesFs(repo.fs);\n\tif (!promisesFs) return new Map();\n\ttry {\n\t\tconst content = await promisesFs.readFile(\n\t\t\t`${repo.gitdir}/packed-refs`,\n\t\t\t\"utf8\",\n\t\t);\n\t\tconst refs = new Map<string, string>();\n\t\tfor (const line of decodeFileContent(content).split(\"\\n\")) {\n\t\t\tconst match = /^([0-9a-f]{40}) refs\\/heads\\/(.+)$/i.exec(line);\n\t\t\tif (match?.[1] && match[2] && isSafeBranchName(match[2])) {\n\t\t\t\trefs.set(match[2], match[1]);\n\t\t\t}\n\t\t}\n\t\treturn refs;\n\t} catch {\n\t\treturn new Map();\n\t}\n}\n\n/** Read the symbolic HEAD directly when the object-store fs is available. */\nasync function getCurrentLooseBranch(repo: Repo): Promise<string | null> {\n\tif (!hasRecursiveFileLister(repo.fs)) return null;\n\tconst promisesFs = getPromisesFs(repo.fs);\n\tif (!promisesFs) return null;\n\ttry {\n\t\tconst content = await promisesFs.readFile(`${repo.gitdir}/HEAD`, \"utf8\");\n\t\tconst head = decodeFileContent(content).trim();\n\t\tconst match = /^ref: refs\\/heads\\/(.+)$/.exec(head);\n\t\treturn match?.[1] && isSafeBranchName(match[1]) ? match[1] : null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Resolve a fully-qualified ref's oid with one read instead of isomorphic-\n * git's own `resolveRef`, which does a stat *then* a read for a loose ref\n * (two round trips against object storage) — wasteful specifically here,\n * where the caller already knows the ref exists (it came from a directory\n * listing moments earlier). Reads the loose file directly and falls back to\n * `git.resolveRef` only when that doesn't pan out (packed-refs, or anything\n * else the plain-loose-file assumption doesn't cover), so correctness for\n * those cases is unchanged — this only removes the redundant round trip on\n * the common path.\n */\nexport async function resolveLooseRefFast(\n\trepo: Repo,\n\tref: string,\n): Promise<string> {\n\tconst promisesFs = getPromisesFs(repo.fs);\n\tif (promisesFs) {\n\t\ttry {\n\t\t\tconst content = await promisesFs.readFile(\n\t\t\t\t`${repo.gitdir}/${ref}`,\n\t\t\t\t\"utf8\",\n\t\t\t);\n\t\t\tconst oid = decodeFileContent(content).trim();\n\t\t\tif (FULL_SHA_RE.test(oid)) return oid;\n\t\t} catch {\n\t\t\t// Not a loose file (packed-refs, or genuinely absent) — fall through.\n\t\t}\n\t}\n\treturn git.resolveRef({ ...repo, ref });\n}\n\n/** All branches with their tip commits; [] for an empty repository. */\nexport async function listBranches(repo: Repo): Promise<Branch[]> {\n\ttry {\n\t\tconst [looseBranches, looseCurrentBranch, packedBranches] =\n\t\t\tawait Promise.all([\n\t\t\t\tlistLooseBranches(repo),\n\t\t\t\tgetCurrentLooseBranch(repo),\n\t\t\t\treadPackedBranches(repo),\n\t\t\t]);\n\t\tconst branches =\n\t\t\tlooseBranches === null\n\t\t\t\t? await git.listBranches(repo)\n\t\t\t\t: [...new Set([...looseBranches, ...packedBranches.keys()])].sort();\n\t\tconst currentBranch =\n\t\t\tlooseBranches === null\n\t\t\t\t? await git\n\t\t\t\t\t\t.currentBranch({ ...repo, fullname: false })\n\t\t\t\t\t\t.catch(() => null)\n\t\t\t\t: looseCurrentBranch;\n\n\t\treturn Promise.all(\n\t\t\tbranches.map(async (branch) => {\n\t\t\t\tconst packedCommit = packedBranches.get(branch);\n\t\t\t\treturn {\n\t\t\t\t\tname: branch,\n\t\t\t\t\tcommit:\n\t\t\t\t\t\tpackedCommit && !looseBranches?.includes(branch)\n\t\t\t\t\t\t\t? packedCommit\n\t\t\t\t\t\t\t: await resolveLooseRefFast(repo, `refs/heads/${branch}`),\n\t\t\t\t\tisDefault: branch === currentBranch,\n\t\t\t\t};\n\t\t\t}),\n\t\t);\n\t} catch (err: unknown) {\n\t\tif ((err as { code?: string }).code === \"NotFoundError\") return [];\n\t\tthrow err;\n\t}\n}\n\n/** Create `name` pointing at the tip of `startPoint` (no checkout). */\nexport async function createBranchFrom(\n\trepo: Repo,\n\tname: string,\n\tstartPoint: string,\n): Promise<void> {\n\tassertSafeBranchName(name);\n\tassertSafeBranchName(startPoint);\n\tconst object = await resolveLooseRefFast(repo, `refs/heads/${startPoint}`);\n\ttry {\n\t\tawait git.branch({ ...repo, ref: name, checkout: false, object });\n\t} catch (err) {\n\t\tif ((err as { code?: string }).code === \"AlreadyExistsError\") {\n\t\t\tthrow new GitConflictError(`Branch ${name} already exists`);\n\t\t}\n\t\tthrow err;\n\t}\n}\n\n/** Delete a branch ref (validated — deleteBranch has no internal ref check). */\nexport async function deleteBranchByName(\n\trepo: Repo,\n\tname: string,\n): Promise<void> {\n\tassertSafeBranchName(name);\n\t// Same rule as receive-pack: deleting the branch HEAD names leaves every\n\t// clone without a default branch.\n\tconst current =\n\t\t(await getCurrentLooseBranch(repo)) ??\n\t\t(await git.currentBranch({ ...repo, fullname: false }).catch(() => null));\n\tif (current === name) {\n\t\tthrow new GitInvalidRequestError(\n\t\t\t`Cannot delete ${name}: it is the default branch`,\n\t\t);\n\t}\n\tawait git.deleteBranch({ ...repo, ref: name });\n}\n\n/** Throws (NotFoundError) unless the branch resolves. */\nexport async function assertBranchExists(\n\trepo: Repo,\n\tname: string,\n): Promise<void> {\n\tassertSafeBranchName(name);\n\tawait resolveLooseRefFast(repo, `refs/heads/${name}`);\n}\n\n/** All tags with the commits they name, sorted by name; [] when there are none. */\nexport async function listTags(repo: Repo): Promise<Tag[]> {\n\tconst names = (await listLooseRefNames(repo, \"refs/tags\")) ?? [];\n\tconst all = new Set([\n\t\t...names,\n\t\t...(await git.listTags(repo).catch(() => [] as string[])),\n\t]);\n\tconst tags = await Promise.all(\n\t\t[...all].filter(isSafeBranchName).map(async (name): Promise<Tag | null> => {\n\t\t\ttry {\n\t\t\t\tconst oid = await resolveLooseRefFast(repo, `refs/tags/${name}`);\n\t\t\t\tconst commit = await peelToCommit(repo, oid);\n\t\t\t\treturn commit === oid\n\t\t\t\t\t? { name, commit }\n\t\t\t\t\t: { name, commit, tagObject: oid };\n\t\t\t} catch {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}),\n\t);\n\treturn tags\n\t\t.filter((tag): tag is Tag => tag !== null)\n\t\t.sort((a, b) => a.name.localeCompare(b.name, undefined, { numeric: true }));\n}\n","/**\n * Writing packfiles: serialize whole (never deltified) objects into a pack,\n * and store a pack plus its index in a repository. Shared by repack (the\n * loose-object fallback) and packed writes (ops/packed-writes.ts).\n *\n * Edge-compatible: Web Crypto SHA-1, CompressionStream, Uint8Array only.\n */\nimport git from \"isomorphic-git\";\nimport {\n\tconcat,\n\tdeflate,\n\tencodeUtf8,\n\tfromHex,\n\tsha1,\n\ttoHex,\n} from \"./edge-utils.js\";\nimport { rawFs } from \"./http/types.js\";\nimport type { Repo } from \"./ops/types.js\";\nimport { packFileName } from \"./pack-files.js\";\n\nexport type PackObjectType = \"commit\" | \"tree\" | \"blob\" | \"tag\";\n\n// Git pack object type bits (bits 6-4 of the header's first byte).\nconst PACK_OBJECT_TYPE_BITS: Record<PackObjectType, number> = {\n\tcommit: 0b0010000,\n\ttree: 0b0100000,\n\tblob: 0b0110000,\n\ttag: 0b1000000,\n};\n\n// First byte: continuation bit | 3-bit type | low 4 bits of length; the rest\n// of the length follows 7 bits at a time, little-endian.\nfunction encodePackObjectHeader(\n\ttype: PackObjectType,\n\tlength: number,\n): Uint8Array {\n\tconst bytes: number[] = [];\n\tlet more = length > 0b1111;\n\tbytes.push(\n\t\t(more ? 0b10000000 : 0) | PACK_OBJECT_TYPE_BITS[type] | (length & 0b1111),\n\t);\n\tlet rest = Math.floor(length / 16);\n\twhile (more) {\n\t\tmore = rest > 0b01111111;\n\t\tbytes.push((more ? 0b10000000 : 0) | (rest & 0b01111111));\n\t\trest = Math.floor(rest / 128);\n\t}\n\treturn new Uint8Array(bytes);\n}\n\n/** Git's object id: sha1(\"<type> <byte length>\\0<content>\"). */\nexport function hashGitObject(\n\ttype: string,\n\tcontent: Uint8Array,\n): Promise<string> {\n\treturn sha1(concat(encodeUtf8(`${type} ${content.length}\\0`), content));\n}\n\nexport interface PackObject {\n\ttype: PackObjectType;\n\tcontent: Uint8Array<ArrayBuffer>;\n}\n\n/** A version-2 pack holding `objects` as full entries, in order. */\nexport async function encodePack(\n\tobjects: readonly PackObject[],\n): Promise<Uint8Array<ArrayBuffer>> {\n\tconst header = new Uint8Array(12);\n\tconst view = new DataView(header.buffer);\n\theader.set(encodeUtf8(\"PACK\"), 0);\n\tview.setUint32(4, 2, false);\n\tview.setUint32(8, objects.length, false);\n\n\tconst chunks: Uint8Array[] = [header];\n\tconst BATCH_SIZE = 100;\n\tfor (let i = 0; i < objects.length; i += BATCH_SIZE) {\n\t\tconst encoded = await Promise.all(\n\t\t\tobjects\n\t\t\t\t.slice(i, i + BATCH_SIZE)\n\t\t\t\t.map(async (object) =>\n\t\t\t\t\tconcat(\n\t\t\t\t\t\tencodePackObjectHeader(object.type, object.content.length),\n\t\t\t\t\t\tawait deflate(object.content),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t);\n\t\tchunks.push(...encoded);\n\t}\n\t// The trailer is the SHA-1 of every preceding byte.\n\tconst body = concat(...chunks);\n\treturn concat(body, fromHex(await sha1(body)));\n}\n\n/**\n * A pack's conventional base name, `pack-<checksum>`: the trailer SHA-1 is a\n * function of the content, so two writers can never pick the same name for\n * different packs, and rewriting the same pack is idempotent.\n */\nexport function packBaseName(pack: Uint8Array): string {\n\treturn `pack-${toHex(pack.subarray(pack.length - 20))}`;\n}\n\n/**\n * Store `pack` in `repo` and index it (isomorphic-git's `indexPack`, which\n * re-hashes every object). The `.idx` is written last: a pack only becomes\n * visible to readers once its index exists. Returns the base name and the\n * oids the index lists.\n */\nexport async function storePack(\n\trepo: Repo,\n\tpack: Uint8Array,\n): Promise<{ base: string; oids: string[] }> {\n\tconst fsp = rawFs(repo);\n\tconst packDir = `${repo.gitdir}/objects/pack`;\n\tconst base = packBaseName(pack);\n\tawait fsp.mkdir(packDir, { recursive: true });\n\tawait fsp.writeFile(`${packDir}/${packFileName(base, \"pack\")}`, pack);\n\tconst { oids } = await git.indexPack({\n\t\t...repo,\n\t\tdir: packDir,\n\t\tfilepath: packFileName(base, \"pack\"),\n\t});\n\treturn { base, oids };\n}\n","/**\n * A FIFO semaphore for bounding in-flight I/O.\n *\n * An unbounded `Promise.all` over a list whose size the caller (or an\n * attacker) controls — a git tree with tens of thousands of blob entries, say,\n * each costing one object-store read — issues that many concurrent requests\n * from a single push or clone. Sockets and memory then scale with the input,\n * and S3-compatible providers rate-limit per account, so one hostile push\n * degrades every other tenant. Bounding the *in-flight* count caps resource\n * use at `limit` no matter how wide the input is, while still letting reads\n * overlap up to that limit instead of running strictly sequentially.\n */\nexport interface Semaphore {\n\trun<T>(fn: () => Promise<T>): Promise<T>;\n}\n\n/**\n * Create a FIFO semaphore admitting at most `limit` concurrent `run`\n * executions. Waiters are queued as promises and released in call order — no\n * polling or timers — so a caller blocked on a full semaphore is woken the\n * instant a permit frees, not on the next tick of a poll loop.\n */\nexport function createSemaphore(limit: number): Semaphore {\n\tif (!Number.isInteger(limit) || limit < 1) {\n\t\tthrow new Error(\n\t\t\t`createSemaphore: limit must be an integer >= 1, got ${limit}`,\n\t\t);\n\t}\n\n\tlet active = 0;\n\tconst waiting: Array<() => void> = [];\n\n\t/**\n\t * Hand the permit to the next waiter instead of dropping it, so `active`\n\t * only decreases when nothing is queued and never exceeds `limit`.\n\t */\n\tfunction release(): void {\n\t\tconst next = waiting.shift();\n\t\tif (next) next();\n\t\telse active--;\n\t}\n\n\tfunction acquire(): Promise<void> {\n\t\tif (active < limit) {\n\t\t\tactive++;\n\t\t\treturn Promise.resolve();\n\t\t}\n\t\treturn new Promise<void>((resolve) => {\n\t\t\twaiting.push(resolve);\n\t\t});\n\t}\n\n\treturn {\n\t\trun<T>(fn: () => Promise<T>): Promise<T> {\n\t\t\treturn acquire().then(async () => {\n\t\t\t\ttry {\n\t\t\t\t\treturn await fn();\n\t\t\t\t} finally {\n\t\t\t\t\trelease();\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t};\n}\n"],"mappings":"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","names":["git","git","git","git","git","git"]}
@@ -1,442 +0,0 @@
1
- // src/edge-utils.ts
2
- var textEncoder = new TextEncoder();
3
- var textDecoder = new TextDecoder();
4
- function encodeUtf8(data) {
5
- return textEncoder.encode(data);
6
- }
7
- function decodeUtf8(data) {
8
- return textDecoder.decode(data);
9
- }
10
- function decodeAscii(data) {
11
- let s = "";
12
- for (let i = 0; i < data.length; i++)
13
- s += String.fromCharCode(data[i]);
14
- return s;
15
- }
16
- function concat(...parts) {
17
- let total = 0;
18
- for (const p of parts) total += p.length;
19
- const out = new Uint8Array(total);
20
- let offset = 0;
21
- for (const p of parts) {
22
- out.set(p, offset);
23
- offset += p.length;
24
- }
25
- return out;
26
- }
27
- function toHex(data) {
28
- let hex = "";
29
- for (let i = 0; i < data.length; i++)
30
- hex += data[i].toString(16).padStart(2, "0");
31
- return hex;
32
- }
33
- function toBase64(data) {
34
- let binary = "";
35
- for (let i = 0; i < data.length; i++)
36
- binary += String.fromCharCode(data[i]);
37
- return btoa(binary);
38
- }
39
- function fromHex(hex) {
40
- const bytes = new Uint8Array(hex.length / 2);
41
- for (let i = 0; i < bytes.length; i++) {
42
- bytes[i] = Number.parseInt(hex.slice(i * 2, i * 2 + 2), 16);
43
- }
44
- return bytes;
45
- }
46
- async function sha1(data) {
47
- const bytes = typeof data === "string" ? encodeUtf8(data) : data;
48
- const hash = await globalThis.crypto.subtle.digest("SHA-1", bytes);
49
- return toHex(new Uint8Array(hash));
50
- }
51
- async function deflate(data) {
52
- const stream = new Response(data).body.pipeThrough(
53
- new CompressionStream("deflate")
54
- );
55
- return new Uint8Array(await new Response(stream).arrayBuffer());
56
- }
57
- async function inflatePrefix(compressed, enough) {
58
- const stream = new Response(compressed).body.pipeThrough(
59
- new DecompressionStream("deflate")
60
- );
61
- const reader = stream.getReader();
62
- const chunks = [];
63
- let total = 0;
64
- try {
65
- while (total < enough) {
66
- const { done, value } = await reader.read();
67
- if (done) break;
68
- chunks.push(value);
69
- total += value.byteLength;
70
- }
71
- } catch {
72
- } finally {
73
- await reader.cancel().catch(() => {
74
- });
75
- }
76
- if (total === 0) return null;
77
- return concat(...chunks.map((chunk) => new Uint8Array(chunk)));
78
- }
79
- async function inflate(data) {
80
- const stream = new Response(data).body.pipeThrough(
81
- new DecompressionStream("deflate")
82
- );
83
- return new Uint8Array(await new Response(stream).arrayBuffer());
84
- }
85
- function hasNullByte(data) {
86
- return data.includes(0);
87
- }
88
- function readBlobContent(blob) {
89
- const isBinary = hasNullByte(blob);
90
- return {
91
- isBinary,
92
- text: isBinary ? "" : decodeUtf8(blob),
93
- bytes: blob
94
- };
95
- }
96
-
97
- // src/git-errors.ts
98
- var GitError = class extends Error {
99
- statusCode;
100
- retryable;
101
- constructor(message, statusCode = 500, retryable = false) {
102
- super(message);
103
- this.name = this.constructor.name;
104
- this.statusCode = statusCode;
105
- this.retryable = retryable;
106
- Error.captureStackTrace?.(this, this.constructor);
107
- }
108
- toJSON() {
109
- return {
110
- error: this.name,
111
- message: this.message,
112
- statusCode: this.statusCode,
113
- retryable: this.retryable
114
- };
115
- }
116
- };
117
- var GitPathNotFoundError = class extends GitError {
118
- constructor(message) {
119
- super(message, 404, false);
120
- }
121
- };
122
- var GitObjectNotFoundError = class extends GitError {
123
- constructor(message) {
124
- super(message, 404, false);
125
- }
126
- };
127
- var GitRefNotFoundError = class extends GitError {
128
- constructor(message) {
129
- super(message, 404, false);
130
- }
131
- };
132
- var GitRepositoryNotFoundError = class extends GitError {
133
- constructor(message) {
134
- super(message, 404, false);
135
- }
136
- };
137
- var GitConflictError = class extends GitError {
138
- conflicts;
139
- constructor(message, conflicts = []) {
140
- super(message, 409, false);
141
- this.conflicts = conflicts;
142
- }
143
- toJSON() {
144
- return { ...super.toJSON(), conflicts: this.conflicts };
145
- }
146
- };
147
- var GitAuthenticationError = class extends GitError {
148
- constructor(message) {
149
- super(message, 401, false);
150
- }
151
- };
152
- var GitAuthorizationError = class extends GitError {
153
- constructor(message) {
154
- super(message, 403, false);
155
- }
156
- };
157
- var GitRateLimitError = class extends GitError {
158
- constructor(message) {
159
- super(message, 429, false);
160
- }
161
- };
162
- var GitInvalidRequestError = class extends GitError {
163
- constructor(message) {
164
- super(message, 400, false);
165
- }
166
- };
167
- var GitProtocolError = class extends GitError {
168
- constructor(message) {
169
- super(message, 400, false);
170
- }
171
- };
172
- function formatErrorResponse(error) {
173
- if (error instanceof GitError) {
174
- return {
175
- status: error.statusCode,
176
- body: error.toJSON(),
177
- headers: error.statusCode === 401 ? { "WWW-Authenticate": 'Basic realm="Git Repository"' } : void 0
178
- };
179
- }
180
- if (error?.code === "EUNAVAILABLE") {
181
- return {
182
- status: 503,
183
- body: {
184
- error: "ServiceUnavailable",
185
- message: "Storage is temporarily unavailable",
186
- retryable: true
187
- },
188
- headers: { "Retry-After": "30" }
189
- };
190
- }
191
- if (error instanceof Error) {
192
- return {
193
- status: 500,
194
- body: {
195
- error: "InternalServerError",
196
- message: "An internal error occurred",
197
- retryable: true
198
- }
199
- };
200
- }
201
- return {
202
- status: 500,
203
- body: {
204
- error: "UnknownError",
205
- message: "An unknown error occurred",
206
- retryable: true
207
- }
208
- };
209
- }
210
- function isNotFoundError(error) {
211
- return error instanceof GitPathNotFoundError || error instanceof GitObjectNotFoundError || error instanceof GitRefNotFoundError || error instanceof GitRepositoryNotFoundError;
212
- }
213
-
214
- // src/pack-files.ts
215
- var PACK_FILE_KINDS = [
216
- "pack",
217
- "idx",
218
- "keep",
219
- "bitmap",
220
- "rev"
221
- ];
222
- var READABLE_PACK_FILE_KINDS = /* @__PURE__ */ new Set([
223
- "pack",
224
- "idx"
225
- ]);
226
- var KNOWN_KINDS = new Set(PACK_FILE_KINDS);
227
- function isPackFileKind(value) {
228
- return KNOWN_KINDS.has(value);
229
- }
230
- function parsePackFileName(name) {
231
- const dot = name.lastIndexOf(".");
232
- if (dot <= 0) return null;
233
- const kind = name.slice(dot + 1);
234
- if (!isPackFileKind(kind)) return null;
235
- return { base: name.slice(0, dot), kind, name };
236
- }
237
- function packFileName(base, kind) {
238
- return `${base}.${kind}`;
239
- }
240
- function parsePackDirectory(entries) {
241
- return entries.map(parsePackFileName).filter((file) => file !== null);
242
- }
243
-
244
- // src/http/types.ts
245
- var runStep = (hooks, label, fn) => hooks?.step ? hooks.step(label, fn) : fn();
246
- function rawFs(repo) {
247
- const fs = repo.fs;
248
- if (!fs?.promises) {
249
- throw new TypeError(
250
- "This operation needs a promise fs (`fs.promises`) \u2014 node:fs and createGitFs both provide one"
251
- );
252
- }
253
- return fs.promises;
254
- }
255
-
256
- // src/refs.ts
257
- var BAD_REF_COMPONENT = (
258
- // biome-ignore lint/suspicious/noControlCharactersInRegex: control chars are exactly what git's own ref-name rules reject — this needs to match the same range.
259
- /(^|[/.])([/.]|$)|^@$|@\{|[\x00-\x20\x7f~^:?*[\\]|\.lock(\/|$)/
260
- );
261
- var FULL_SHA_RE = /^[0-9a-f]{40}$/i;
262
- function isSafeFullRefName(ref) {
263
- if (!ref.startsWith("refs/heads/") && !ref.startsWith("refs/tags/")) {
264
- return false;
265
- }
266
- return !BAD_REF_COMPONENT.test(ref);
267
- }
268
- function isSafeBranchName(name) {
269
- if (!name || name.startsWith("refs/") || name === "HEAD") return false;
270
- if (FULL_SHA_RE.test(name)) return false;
271
- return !BAD_REF_COMPONENT.test(name);
272
- }
273
- function isFullSha(value) {
274
- return FULL_SHA_RE.test(value);
275
- }
276
- function isSafeRefName(value) {
277
- return isSafeBranchName(value) || isFullSha(value);
278
- }
279
- function isSafeRepoPath(p) {
280
- if (p.startsWith("/")) return false;
281
- if (p.split("/").some((segment) => segment === "..")) return false;
282
- if (/^\.git(\/|$)/i.test(p)) return false;
283
- if (p.includes("\0")) return false;
284
- return true;
285
- }
286
- function isSafeTreePath(p) {
287
- if (!isSafeRepoPath(p) || p.length === 0) return false;
288
- return p.split("/").every(
289
- (segment) => segment.length > 0 && segment !== "." && segment !== ".." && segment.toLowerCase() !== ".git"
290
- );
291
- }
292
- function qualifyBranchRef(ref) {
293
- if (ref.startsWith("refs/") || ref === "HEAD" || FULL_SHA_RE.test(ref)) {
294
- return ref;
295
- }
296
- return `refs/heads/${ref}`;
297
- }
298
-
299
- // src/pack-entry.ts
300
- var OBJ_OFS_DELTA = 6;
301
- var OBJ_REF_DELTA = 7;
302
- var OID_BYTES = 20;
303
- function readEntryHeader(bytes, start) {
304
- let byte = bytes[start];
305
- const type = byte >> 4 & 7;
306
- let size = byte & 15;
307
- let shift = 4;
308
- let at = start + 1;
309
- while (byte & 128) {
310
- byte = bytes[at++];
311
- size += (byte & 127) * 2 ** shift;
312
- shift += 7;
313
- }
314
- return { type, size, length: at - start };
315
- }
316
- function encodeEntryHeader(type, size) {
317
- const bytes = [];
318
- let rest = Math.floor(size / 16);
319
- bytes.push((rest > 0 ? 128 : 0) | type << 4 | size % 16);
320
- while (rest > 0) {
321
- const low = rest % 128;
322
- rest = Math.floor(rest / 128);
323
- bytes.push((rest > 0 ? 128 : 0) | low);
324
- }
325
- return new Uint8Array(bytes);
326
- }
327
- function readOfsDeltaOffset(bytes, start) {
328
- let at = start;
329
- let byte = bytes[at++];
330
- let distance = byte & 127;
331
- while (byte & 128) {
332
- byte = bytes[at++];
333
- distance = (distance + 1) * 128 + (byte & 127);
334
- }
335
- return { distance, length: at - start };
336
- }
337
- function readVarint(bytes, start) {
338
- let at = start;
339
- let byte = bytes[at++];
340
- let value = byte & 127;
341
- let shift = 7;
342
- while (byte & 128) {
343
- byte = bytes[at++];
344
- value += (byte & 127) * 2 ** shift;
345
- shift += 7;
346
- }
347
- return { value, length: at - start };
348
- }
349
- function readDeltaHeader(bytes, start) {
350
- const base = readVarint(bytes, start);
351
- const result = readVarint(bytes, start + base.length);
352
- return {
353
- baseSize: base.value,
354
- resultSize: result.value,
355
- length: base.length + result.length
356
- };
357
- }
358
-
359
- // src/pack-index.ts
360
- var IDX_V2 = {
361
- magic: 4285812579,
362
- version: 2,
363
- headerBytes: 8,
364
- fanoutEntries: 256,
365
- /** Offsets with this bit set index the 64-bit large-offset table. */
366
- largeOffsetFlag: 2147483648
367
- };
368
- function readPackIndex(idx) {
369
- const view = new DataView(idx.buffer, idx.byteOffset, idx.byteLength);
370
- const namesStart = IDX_V2.headerBytes + IDX_V2.fanoutEntries * 4;
371
- if (idx.byteLength < namesStart || view.getUint32(0) !== IDX_V2.magic || view.getUint32(4) !== IDX_V2.version) {
372
- return null;
373
- }
374
- const count = view.getUint32(namesStart - 4);
375
- const crcStart = namesStart + count * OID_BYTES;
376
- const offsetsStart = crcStart + count * 4;
377
- if (idx.byteLength < offsetsStart + count * 4) return null;
378
- const entries = [];
379
- for (let i = 0; i < count; i++) {
380
- const offset = view.getUint32(offsetsStart + i * 4);
381
- if (offset & IDX_V2.largeOffsetFlag) return null;
382
- const at = namesStart + i * OID_BYTES;
383
- entries.push({ oid: toHex(idx.subarray(at, at + OID_BYTES)), offset });
384
- }
385
- return entries;
386
- }
387
- function findPackIndexOffset(idx, oid) {
388
- return readPackIndex(idx)?.find((entry) => entry.oid === oid)?.offset ?? null;
389
- }
390
-
391
- export {
392
- encodeUtf8,
393
- decodeUtf8,
394
- decodeAscii,
395
- concat,
396
- toHex,
397
- toBase64,
398
- fromHex,
399
- sha1,
400
- deflate,
401
- inflatePrefix,
402
- inflate,
403
- hasNullByte,
404
- readBlobContent,
405
- GitError,
406
- GitPathNotFoundError,
407
- GitObjectNotFoundError,
408
- GitRefNotFoundError,
409
- GitRepositoryNotFoundError,
410
- GitConflictError,
411
- GitAuthenticationError,
412
- GitAuthorizationError,
413
- GitRateLimitError,
414
- GitInvalidRequestError,
415
- GitProtocolError,
416
- formatErrorResponse,
417
- isNotFoundError,
418
- PACK_FILE_KINDS,
419
- READABLE_PACK_FILE_KINDS,
420
- parsePackFileName,
421
- packFileName,
422
- parsePackDirectory,
423
- runStep,
424
- rawFs,
425
- OBJ_OFS_DELTA,
426
- OBJ_REF_DELTA,
427
- OID_BYTES,
428
- readEntryHeader,
429
- encodeEntryHeader,
430
- readOfsDeltaOffset,
431
- readDeltaHeader,
432
- readPackIndex,
433
- findPackIndexOffset,
434
- isSafeFullRefName,
435
- isSafeBranchName,
436
- isFullSha,
437
- isSafeRefName,
438
- isSafeRepoPath,
439
- isSafeTreePath,
440
- qualifyBranchRef
441
- };
442
- //# sourceMappingURL=chunk-OKBQISUC.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/edge-utils.ts","../src/git-errors.ts","../src/pack-files.ts","../src/http/types.ts","../src/refs.ts","../src/pack-entry.ts","../src/pack-index.ts"],"sourcesContent":["/**\n * Edge-compatible utilities replacing node:crypto, node:zlib, and Buffer.\n *\n * Every function here uses only Web APIs (SubtleCrypto, CompressionStream,\n * TextEncoder/TextDecoder) — no Node built-ins. They work on Cloudflare\n * Workers, Vercel Edge, Deno Deploy, and Node >= 18.\n */\n\nconst textEncoder = new TextEncoder();\nconst textDecoder = new TextDecoder();\n\n// ---------------------------------------------------------------------------\n// Text\n// ---------------------------------------------------------------------------\n\n/**\n * Encode a UTF-8 string to bytes.\n *\n * Return type pinned to `Uint8Array<ArrayBuffer>` (not the bare `Uint8Array`,\n * whose default type argument differs across TypeScript versions) so it's\n * always assignable to Fetch API `BodyInit` regardless of a consumer's own\n * TypeScript/lib version.\n */\nexport function encodeUtf8(data: string): Uint8Array<ArrayBuffer> {\n\treturn textEncoder.encode(data);\n}\n\n/** Decode bytes as UTF-8. */\nexport function decodeUtf8(data: Uint8Array): string {\n\treturn textDecoder.decode(data);\n}\n\n/** Decode bytes as ASCII. */\nexport function decodeAscii(data: Uint8Array): string {\n\tlet s = \"\";\n\tfor (let i = 0; i < data.length; i++)\n\t\ts += String.fromCharCode(data[i] as number);\n\treturn s;\n}\n\n// ---------------------------------------------------------------------------\n// Array manipulation\n// ---------------------------------------------------------------------------\n\n/** Concatenate any number of Uint8Arrays into one. */\nexport function concat(...parts: Uint8Array[]): Uint8Array<ArrayBuffer> {\n\tlet total = 0;\n\tfor (const p of parts) total += p.length;\n\tconst out = new Uint8Array(total);\n\tlet offset = 0;\n\tfor (const p of parts) {\n\t\tout.set(p, offset);\n\t\toffset += p.length;\n\t}\n\treturn out;\n}\n\n// ---------------------------------------------------------------------------\n// Encoding\n// ---------------------------------------------------------------------------\n\n/** Uint8Array → lowercase hex string. */\nexport function toHex(data: Uint8Array): string {\n\tlet hex = \"\";\n\tfor (let i = 0; i < data.length; i++)\n\t\thex += (data[i] as number).toString(16).padStart(2, \"0\");\n\treturn hex;\n}\n\n/** Uint8Array → base64 string. */\nexport function toBase64(data: Uint8Array): string {\n\tlet binary = \"\";\n\tfor (let i = 0; i < data.length; i++)\n\t\tbinary += String.fromCharCode(data[i] as number);\n\treturn btoa(binary);\n}\n\n/** Hex string → Uint8Array. */\nexport function fromHex(hex: string): Uint8Array<ArrayBuffer> {\n\tconst bytes = new Uint8Array(hex.length / 2);\n\tfor (let i = 0; i < bytes.length; i++) {\n\t\tbytes[i] = Number.parseInt(hex.slice(i * 2, i * 2 + 2), 16);\n\t}\n\treturn bytes;\n}\n\n// ---------------------------------------------------------------------------\n// Crypto\n// ---------------------------------------------------------------------------\n\n/** SHA-1 hash via Web Crypto API. Returns a hex string. */\nexport async function sha1(\n\tdata: Uint8Array<ArrayBuffer> | string,\n): Promise<string> {\n\tconst bytes = typeof data === \"string\" ? encodeUtf8(data) : data;\n\tconst hash = await globalThis.crypto.subtle.digest(\"SHA-1\", bytes);\n\treturn toHex(new Uint8Array(hash));\n}\n\n// ---------------------------------------------------------------------------\n// Compression\n// ---------------------------------------------------------------------------\n\n/** Deflate (zlib) via the CompressionStream Web API. */\nexport async function deflate(\n\tdata: Uint8Array<ArrayBuffer>,\n): Promise<Uint8Array<ArrayBuffer>> {\n\t// Response, not Blob.stream(): some Blob implementations (jsdom's) have\n\t// no stream().\n\tconst stream = (new Response(data).body as ReadableStream).pipeThrough(\n\t\tnew CompressionStream(\"deflate\"),\n\t);\n\treturn new Uint8Array(await new Response(stream).arrayBuffer());\n}\n\n/**\n * The first `enough` bytes of a deflate stream, given a prefix of that stream.\n *\n * Deflate emits output as it consumes input, so a bounded compressed prefix\n * yields a bounded uncompressed prefix — which is how a delta entry's header\n * (the only place its reconstructed size is recorded) can be read without\n * inflating the whole object. The prefix ends mid-symbol by construction, so\n * the stream errors after the bytes we wanted have already arrived; that error\n * carries no information and is not propagated.\n *\n * Returns `null` when fewer than `enough` bytes could be recovered, so a caller\n * distinguishes \"not readable from this prefix\" from a zero-length answer.\n */\nexport async function inflatePrefix(\n\tcompressed: Uint8Array<ArrayBuffer>,\n\tenough: number,\n): Promise<Uint8Array<ArrayBuffer> | null> {\n\tconst stream = (new Response(compressed).body as ReadableStream).pipeThrough(\n\t\tnew DecompressionStream(\"deflate\"),\n\t);\n\tconst reader = stream.getReader();\n\tconst chunks: Uint8Array[] = [];\n\tlet total = 0;\n\ttry {\n\t\twhile (total < enough) {\n\t\t\tconst { done, value } = await reader.read();\n\t\t\tif (done) break;\n\t\t\tchunks.push(value);\n\t\t\ttotal += value.byteLength;\n\t\t}\n\t} catch {\n\t\t// Expected: the compressed prefix is truncated. Whatever was emitted\n\t\t// before that is what this returns.\n\t} finally {\n\t\tawait reader.cancel().catch(() => {});\n\t}\n\tif (total === 0) return null;\n\treturn concat(...chunks.map((chunk) => new Uint8Array(chunk)));\n}\n\n/** Inflate (zlib) via the DecompressionStream Web API. */\nexport async function inflate(\n\tdata: Uint8Array<ArrayBuffer>,\n): Promise<Uint8Array<ArrayBuffer>> {\n\tconst stream = (new Response(data).body as ReadableStream).pipeThrough(\n\t\tnew DecompressionStream(\"deflate\"),\n\t);\n\treturn new Uint8Array(await new Response(stream).arrayBuffer());\n}\n\n// ---------------------------------------------------------------------------\n// Binary detection (replaces Buffer.includes(0) pattern)\n// ---------------------------------------------------------------------------\n\n/** Check if a Uint8Array contains a null byte. */\nexport function hasNullByte(data: Uint8Array): boolean {\n\treturn data.includes(0);\n}\n\n/**\n * Read a blob as text or binary metadata — the edge-compatible replacement\n * for the `Buffer.from(blob)` pattern used throughout diff.ts and history.ts.\n */\nexport function readBlobContent(blob: Uint8Array): {\n\tisBinary: boolean;\n\ttext: string;\n\tbytes: Uint8Array;\n} {\n\tconst isBinary = hasNullByte(blob);\n\treturn {\n\t\tisBinary,\n\t\ttext: isBinary ? \"\" : decodeUtf8(blob),\n\t\tbytes: blob,\n\t};\n}\n","/**\n * Git-server error types carrying an HTTP status and a retryability flag, so\n * transport layers can map internal failures to responses without inspecting\n * messages. Extend {@link GitError} for app-specific cases (storage backends,\n * quota, …) and {@link formatErrorResponse} keeps working for them.\n */\nexport class GitError extends Error {\n\tstatusCode: number;\n\tretryable: boolean;\n\n\tconstructor(message: string, statusCode = 500, retryable = false) {\n\t\tsuper(message);\n\t\tthis.name = this.constructor.name;\n\t\tthis.statusCode = statusCode;\n\t\tthis.retryable = retryable;\n\t\tError.captureStackTrace?.(this, this.constructor);\n\t}\n\n\ttoJSON(): Record<string, unknown> {\n\t\treturn {\n\t\t\terror: this.name,\n\t\t\tmessage: this.message,\n\t\t\tstatusCode: this.statusCode,\n\t\t\tretryable: this.retryable,\n\t\t};\n\t}\n}\n\n/** A file/directory path not found within a tree (404). */\nexport class GitPathNotFoundError extends GitError {\n\tconstructor(message: string) {\n\t\tsuper(message, 404, false);\n\t}\n}\n\n/** A git object not found (404). */\nexport class GitObjectNotFoundError extends GitError {\n\tconstructor(message: string) {\n\t\tsuper(message, 404, false);\n\t}\n}\n\n/** A ref (branch/tag) not found (404). */\nexport class GitRefNotFoundError extends GitError {\n\tconstructor(message: string) {\n\t\tsuper(message, 404, false);\n\t}\n}\n\n/** The repository itself not found (404). */\nexport class GitRepositoryNotFoundError extends GitError {\n\tconstructor(message: string) {\n\t\tsuper(message, 404, false);\n\t}\n}\n\nexport interface MergeConflictDetail {\n\tfile: string;\n\tbaseLines?: string[];\n\tsourceLines?: string[];\n\ttargetLines?: string[];\n}\n\n/** A merge conflict (409), carrying per-file conflict detail. */\nexport class GitConflictError extends GitError {\n\tconflicts: MergeConflictDetail[];\n\n\tconstructor(message: string, conflicts: MergeConflictDetail[] = []) {\n\t\tsuper(message, 409, false);\n\t\tthis.conflicts = conflicts;\n\t}\n\n\toverride toJSON(): Record<string, unknown> {\n\t\treturn { ...super.toJSON(), conflicts: this.conflicts };\n\t}\n}\n\n/** Authentication failed (401). */\nexport class GitAuthenticationError extends GitError {\n\tconstructor(message: string) {\n\t\tsuper(message, 401, false);\n\t}\n}\n\n/** Authorization failed (403). */\nexport class GitAuthorizationError extends GitError {\n\tconstructor(message: string) {\n\t\tsuper(message, 403, false);\n\t}\n}\n\n/** Too many failed attempts (429). */\nexport class GitRateLimitError extends GitError {\n\tconstructor(message: string) {\n\t\tsuper(message, 429, false);\n\t}\n}\n\n/** Malformed request (400). */\nexport class GitInvalidRequestError extends GitError {\n\tconstructor(message: string) {\n\t\tsuper(message, 400, false);\n\t}\n}\n\n/** Git wire-protocol violation (400). */\nexport class GitProtocolError extends GitError {\n\tconstructor(message: string) {\n\t\tsuper(message, 400, false);\n\t}\n}\n\n/**\n * Map any error to an HTTP response shape. 401s carry the WWW-Authenticate\n * header git clients need before they will prompt for credentials. Non-GitError\n * failures are masked as opaque 500s — internal messages don't leak.\n */\nexport function formatErrorResponse(error: unknown): {\n\tstatus: number;\n\tbody: Record<string, unknown>;\n\theaders?: Record<string, string>;\n} {\n\tif (error instanceof GitError) {\n\t\treturn {\n\t\t\tstatus: error.statusCode,\n\t\t\tbody: error.toJSON(),\n\t\t\theaders:\n\t\t\t\terror.statusCode === 401\n\t\t\t\t\t? { \"WWW-Authenticate\": 'Basic realm=\"Git Repository\"' }\n\t\t\t\t\t: undefined,\n\t\t};\n\t}\n\n\t// The object store's circuit breaker is open (retry.ts's CircuitOpenError):\n\t// the backend is down, not this request — tell clients when to retry.\n\tif ((error as { code?: unknown } | null)?.code === \"EUNAVAILABLE\") {\n\t\treturn {\n\t\t\tstatus: 503,\n\t\t\tbody: {\n\t\t\t\terror: \"ServiceUnavailable\",\n\t\t\t\tmessage: \"Storage is temporarily unavailable\",\n\t\t\t\tretryable: true,\n\t\t\t},\n\t\t\theaders: { \"Retry-After\": \"30\" },\n\t\t};\n\t}\n\n\tif (error instanceof Error) {\n\t\treturn {\n\t\t\tstatus: 500,\n\t\t\tbody: {\n\t\t\t\terror: \"InternalServerError\",\n\t\t\t\tmessage: \"An internal error occurred\",\n\t\t\t\tretryable: true,\n\t\t\t},\n\t\t};\n\t}\n\n\treturn {\n\t\tstatus: 500,\n\t\tbody: {\n\t\t\terror: \"UnknownError\",\n\t\t\tmessage: \"An unknown error occurred\",\n\t\t\tretryable: true,\n\t\t},\n\t};\n}\n\n/** A missing repository, ref, path or object: on a read path that's a 404. */\nexport function isNotFoundError(error: unknown): boolean {\n\treturn (\n\t\terror instanceof GitPathNotFoundError ||\n\t\terror instanceof GitObjectNotFoundError ||\n\t\terror instanceof GitRefNotFoundError ||\n\t\terror instanceof GitRepositoryNotFoundError\n\t);\n}\n","/**\n * Typed view of a git `objects/pack` directory listing.\n *\n * Every pack is a set of sibling files sharing one base name\n * (`pack-<hash>.pack`, `.idx`, and optionally `.keep`/`.bitmap`/`.rev`).\n * Parsing names once into {@link PackFileName} lets callers group, filter and\n * rename by kind instead of re-matching filename strings at each call site.\n *\n * Edge-compatible: no node: imports.\n */\n\n/** Every file kind git writes into `objects/pack`. */\nexport const PACK_FILE_KINDS = [\n\t\"pack\",\n\t\"idx\",\n\t\"keep\",\n\t\"bitmap\",\n\t\"rev\",\n] as const;\nexport type PackFileKind = (typeof PACK_FILE_KINDS)[number];\n\n/** Kinds isomorphic-git actually reads; the rest are git-CLI accelerators. */\nexport const READABLE_PACK_FILE_KINDS: ReadonlySet<PackFileKind> = new Set([\n\t\"pack\",\n\t\"idx\",\n]);\n\nexport interface PackFileName {\n\t/** Shared base of a pack's sibling files, e.g. `pack-1a2b…`. */\n\treadonly base: string;\n\treadonly kind: PackFileKind;\n\t/** The file name as listed, e.g. `pack-1a2b….idx`. */\n\treadonly name: string;\n}\n\nconst KNOWN_KINDS: ReadonlySet<string> = new Set(PACK_FILE_KINDS);\n\nfunction isPackFileKind(value: string): value is PackFileKind {\n\treturn KNOWN_KINDS.has(value);\n}\n\n/** Parse a pack-directory entry; `null` for anything git didn't put there. */\nexport function parsePackFileName(name: string): PackFileName | null {\n\tconst dot = name.lastIndexOf(\".\");\n\tif (dot <= 0) return null;\n\tconst kind = name.slice(dot + 1);\n\tif (!isPackFileKind(kind)) return null;\n\treturn { base: name.slice(0, dot), kind, name };\n}\n\n/** File name of the `kind` sibling of the pack with this base name. */\nexport function packFileName(base: string, kind: PackFileKind): string {\n\treturn `${base}.${kind}`;\n}\n\n/** Parse a directory listing, dropping entries that aren't pack files. */\nexport function parsePackDirectory(entries: readonly string[]): PackFileName[] {\n\treturn entries\n\t\t.map(parsePackFileName)\n\t\t.filter((file): file is PackFileName => file !== null);\n}\n","import type { Repo } from \"../ops/types.js\";\n\n/**\n * Transport-agnostic HTTP response the handlers produce.\n *\n * `body` is pinned to `Uint8Array<ArrayBuffer>` (not the bare `Uint8Array`,\n * whose default type argument isn't consistent across TypeScript versions)\n * so it's always assignable to Fetch API `BodyInit` regardless of which\n * TypeScript/lib version a consumer compiles against — every producer here\n * (`concat`, `pktLine`, `TextEncoder.encode`) is ArrayBuffer-backed already.\n */\nexport interface GitHttpResult {\n\tstatus: number;\n\theaders: Record<string, string>;\n\tbody: Uint8Array<ArrayBuffer>;\n}\n\n/** Optional instrumentation hooks shared by the /http handlers. */\nexport interface HttpHooks {\n\t/** Wrap a timed sub-step. Default: run directly. */\n\tstep?: <T>(label: string, fn: () => Promise<T>) => Promise<T>;\n\t/** Non-fatal problem sink (missing objects, failed repacks). */\n\tonWarn?: (message: string, error?: unknown) => void;\n}\n\nexport const runStep = <T>(\n\thooks: HttpHooks | undefined,\n\tlabel: string,\n\tfn: () => Promise<T>,\n): Promise<T> => (hooks?.step ? hooks.step(label, fn) : fn());\n\n/**\n * The raw promise-fs surface some /http paths need beyond isomorphic-git's\n * plumbing (writing an incoming pack file, listing/deleting pack files).\n * Both `node:fs` and this package's `GitFs` satisfy it via `.promises`.\n */\nexport interface RawFsPromises {\n\treadFile(path: string): Promise<Uint8Array | string>;\n\twriteFile(path: string, data: Uint8Array | string): Promise<void>;\n\tunlink(path: string): Promise<void>;\n\treaddir(path: string): Promise<string[]>;\n\tmkdir(path: string, options?: { recursive?: boolean }): Promise<unknown>;\n\tstat(path: string): Promise<unknown>;\n}\n\n/** Duck-type the `.promises` surface off a repo's fs. */\nexport function rawFs(repo: Repo): RawFsPromises {\n\tconst fs = repo.fs as { promises?: RawFsPromises };\n\tif (!fs?.promises) {\n\t\tthrow new TypeError(\n\t\t\t\"This operation needs a promise fs (`fs.promises`) — node:fs and createGitFs both provide one\",\n\t\t);\n\t}\n\treturn fs.promises;\n}\n","/**\n * Git ref-name validation, mirroring isomorphic-git's own internal `isValidRef`\n * character-class rules (the check `git.branch` and top-level `git.writeRef`\n * run before touching disk).\n *\n * Several of isomorphic-git's OTHER ref-touching primitives — `git.commit`,\n * `git.merge`, `git.deleteBranch`, and top-level `git.resolveRef`/\n * `git.deleteRef` — do NOT run this check internally: they resolve straight\n * through `fs.write`/`fs.rm(join(gitdir, ref))` with no jail to the gitdir.\n * On a shared-storage server (many repos under one prefix or base directory),\n * every branch/ref name that originates from request input must be validated\n * against these predicates before it reaches any of those primitives —\n * otherwise a `\"../\"`-laden name lets a caller with write access to any single\n * repo read, corrupt, or delete another repo's ref/object files.\n */\n\nconst BAD_REF_COMPONENT =\n\t// biome-ignore lint/suspicious/noControlCharactersInRegex: control chars are exactly what git's own ref-name rules reject — this needs to match the same range.\n\t/(^|[/.])([/.]|$)|^@$|@\\{|[\\x00-\\x20\\x7f~^:?*[\\\\]|\\.lock(\\/|$)/;\n\nconst FULL_SHA_RE = /^[0-9a-f]{40}$/i;\n\n/** Validates a fully-qualified ref (must start with refs/heads/ or refs/tags/). */\nexport function isSafeFullRefName(ref: string): boolean {\n\tif (!ref.startsWith(\"refs/heads/\") && !ref.startsWith(\"refs/tags/\")) {\n\t\treturn false;\n\t}\n\treturn !BAD_REF_COMPONENT.test(ref);\n}\n\n/**\n * Validates a bare branch name (no refs/ prefix). Rejects anything that looks\n * like a full ref path — a name of `\"refs/heads/x\"` would otherwise sail\n * through unprefixed at call sites that build `refs/heads/${name}` themselves\n * (doubling the prefix into something that still resolves), or be used as-is\n * at call sites that pass a name already containing `\"refs/\"` straight\n * through. Also rejects 40-hex SHA-shaped values so a stored branch name can\n * never be ambiguous with a commit SHA at write time; use\n * {@link isSafeRefName} on read paths that accept both shapes.\n */\nexport function isSafeBranchName(name: string): boolean {\n\tif (!name || name.startsWith(\"refs/\") || name === \"HEAD\") return false;\n\tif (FULL_SHA_RE.test(name)) return false;\n\treturn !BAD_REF_COMPONENT.test(name);\n}\n\n/** True for a full 40-hex-char commit SHA — the shape {@link isSafeBranchName} deliberately rejects. */\nexport function isFullSha(value: string): boolean {\n\treturn FULL_SHA_RE.test(value);\n}\n\n/**\n * Validates a \"ref\" field that may name either a branch or a commit SHA it's\n * pinned to — the shape read-path route params take (permalinks, raw links).\n * Both shapes still go through the traversal check.\n */\nexport function isSafeRefName(value: string): boolean {\n\treturn isSafeBranchName(value) || isFullSha(value);\n}\n\n/**\n * Validates a repo-relative file path from request input: relative, no `..`\n * segments, no `.git/` prefix, no null bytes. Use this anywhere a path\n * segment comes straight off a URL or form field rather than re-deriving the\n * checks ad hoc.\n */\nexport function isSafeRepoPath(p: string): boolean {\n\tif (p.startsWith(\"/\")) return false;\n\tif (p.split(\"/\").some((segment) => segment === \"..\")) return false;\n\tif (/^\\.git(\\/|$)/i.test(p)) return false;\n\tif (p.includes(\"\\0\")) return false;\n\treturn true;\n}\n\n/**\n * Whether `p` can name a file written into a tree: what {@link isSafeRepoPath}\n * checks, plus every segment non-empty and neither `.` nor `..`, and no\n * `.git` segment anywhere (any case) — git itself refuses to check those out,\n * since a tracked `.git/config` in a subdirectory is a code-execution vector\n * on clone. Use it for paths that become tree entries; reads keep the looser\n * {@link isSafeRepoPath} (which also accepts `\"\"`, the root).\n */\nexport function isSafeTreePath(p: string): boolean {\n\tif (!isSafeRepoPath(p) || p.length === 0) return false;\n\treturn p\n\t\t.split(\"/\")\n\t\t.every(\n\t\t\t(segment) =>\n\t\t\t\tsegment.length > 0 &&\n\t\t\t\tsegment !== \".\" &&\n\t\t\t\tsegment !== \"..\" &&\n\t\t\t\tsegment.toLowerCase() !== \".git\",\n\t\t);\n}\n\n/**\n * Qualify a bare branch name to `refs/heads/<name>` before handing it to\n * isomorphic-git. `resolveRef`/`expand` try several candidate paths in\n * sequence for a bare name — `ref`, `refs/ref`, `refs/tags/ref`,\n * `refs/heads/ref`, … — missing (and, against object storage, paying a real\n * round trip for) the first three every time. For a branch-only ref model,\n * skip straight to the winner. Left untouched: already-qualified refs,\n * `\"HEAD\"` (its own first candidate, already optimal), and 40-hex oids\n * (resolved locally by isomorphic-git with no I/O at all).\n */\nexport function qualifyBranchRef(ref: string): string {\n\tif (ref.startsWith(\"refs/\") || ref === \"HEAD\" || FULL_SHA_RE.test(ref)) {\n\t\treturn ref;\n\t}\n\treturn `refs/heads/${ref}`;\n}\n","/**\n * Parsing the entry headers inside a git packfile (`gitformat-pack(5)`).\n *\n * Shared by the two places that read a pack's structure rather than its\n * objects: `http/pack-reuse.ts` (copying stored entries into a new pack) and\n * `object-size.ts` (answering an object's size without inflating it).\n *\n * Edge-compatible: `Uint8Array` only.\n */\n\n/** Git pack object type bits (bits 6-4 of an entry's first byte). */\nexport const OBJ_COMMIT = 1;\nexport const OBJ_TREE = 2;\nexport const OBJ_BLOB = 3;\nexport const OBJ_TAG = 4;\nexport const OBJ_OFS_DELTA = 6;\nexport const OBJ_REF_DELTA = 7;\n\n/** Bytes in a pack object's id, and in a `REF_DELTA`'s base reference. */\nexport const OID_BYTES = 20;\n\n/** The variable-length type/size header that starts every pack entry. */\nexport interface EntryHeader {\n\treadonly type: number;\n\t/**\n\t * For a whole object, its size in bytes. For a delta entry, the size of the\n\t * **delta stream**, not of the object it reconstructs — that is in the delta\n\t * header (see {@link readDeltaHeader}).\n\t */\n\treadonly size: number;\n\t/** Bytes the header occupies. */\n\treadonly length: number;\n}\n\n/**\n * Read the entry header at `start`.\n *\n * A header that runs off the end of `bytes` yields whatever digits were\n * available: this reads from a bounded slice of a pack, and every caller\n * decides for itself whether the result is plausible (`length` beyond what it\n * read means \"unknown\", not \"zero\").\n */\nexport function readEntryHeader(bytes: Uint8Array, start: number): EntryHeader {\n\tlet byte = bytes[start] as number;\n\tconst type = (byte >> 4) & 0b111;\n\tlet size = byte & 0b1111;\n\tlet shift = 4;\n\tlet at = start + 1;\n\twhile (byte & 0x80) {\n\t\tbyte = bytes[at++] as number;\n\t\tsize += (byte & 0x7f) * 2 ** shift;\n\t\tshift += 7;\n\t}\n\treturn { type, size, length: at - start };\n}\n\n/** Serialize an entry header (the inverse of {@link readEntryHeader}). */\nexport function encodeEntryHeader(type: number, size: number): Uint8Array {\n\tconst bytes: number[] = [];\n\tlet rest = Math.floor(size / 16);\n\tbytes.push((rest > 0 ? 0x80 : 0) | (type << 4) | (size % 16));\n\twhile (rest > 0) {\n\t\tconst low = rest % 128;\n\t\trest = Math.floor(rest / 128);\n\t\tbytes.push((rest > 0 ? 0x80 : 0) | low);\n\t}\n\treturn new Uint8Array(bytes);\n}\n\n/** `OFS_DELTA`'s negative base offset: big-endian base-128 with +1 carries. */\nexport function readOfsDeltaOffset(\n\tbytes: Uint8Array,\n\tstart: number,\n): { distance: number; length: number } {\n\tlet at = start;\n\tlet byte = bytes[at++] as number;\n\tlet distance = byte & 0x7f;\n\twhile (byte & 0x80) {\n\t\tbyte = bytes[at++] as number;\n\t\tdistance = (distance + 1) * 128 + (byte & 0x7f);\n\t}\n\treturn { distance, length: at - start };\n}\n\n/** The two varints a delta stream opens with: base size, then result size. */\nexport interface DeltaHeader {\n\t/** Size of the object the delta is written against. */\n\treadonly baseSize: number;\n\t/** Size of the object the delta reconstructs. */\n\treadonly resultSize: number;\n\t/** Bytes the two varints occupy. */\n\treadonly length: number;\n}\n\n/** Read the base-128 little-endian varint at `start`, 7 bits per byte. */\nfunction readVarint(\n\tbytes: Uint8Array,\n\tstart: number,\n): { value: number; length: number } {\n\tlet at = start;\n\tlet byte = bytes[at++] as number;\n\tlet value = byte & 0x7f;\n\tlet shift = 7;\n\twhile (byte & 0x80) {\n\t\tbyte = bytes[at++] as number;\n\t\tvalue += (byte & 0x7f) * 2 ** shift;\n\t\tshift += 7;\n\t}\n\treturn { value, length: at - start };\n}\n\n/**\n * Read the delta header that follows an `OFS_DELTA` / `REF_DELTA` entry's own\n * header (and, for `REF_DELTA`, its 20-byte base id): the size of the object\n * being modified, then the size of the result. The result size is the answer\n * {@link ObjectSize} exists to get — it is the only place a deltified object's\n * real length is recorded.\n */\nexport function readDeltaHeader(bytes: Uint8Array, start: number): DeltaHeader {\n\tconst base = readVarint(bytes, start);\n\tconst result = readVarint(bytes, start + base.length);\n\treturn {\n\t\tbaseSize: base.value,\n\t\tresultSize: result.value,\n\t\tlength: base.length + result.length,\n\t};\n}\n","/**\n * Reading a pack's version-2 `.idx` (`gitformat-pack(5)`) — the oid → offset\n * table git writes beside every packfile.\n *\n * Kept separate from the code that reads pack *entries*: an index lookup is how\n * you find out which bytes to look at, and it is the cheap half of any question\n * about a packed object's contents (`http/pack-reuse.ts` copies entries into a\n * new pack; `object-size.ts` reads one entry's header).\n *\n * Edge-compatible: `Uint8Array` and `DataView` only.\n */\n\nimport { toHex } from \"./edge-utils.js\";\nimport { OID_BYTES } from \"./pack-entry.js\";\n\nconst IDX_V2 = {\n\tmagic: 0xff744f63,\n\tversion: 2,\n\theaderBytes: 8,\n\tfanoutEntries: 256,\n\t/** Offsets with this bit set index the 64-bit large-offset table. */\n\tlargeOffsetFlag: 0x80000000,\n} as const;\n\n/** An object's position in a pack, as listed by its `.idx`. */\nexport interface PackIndexEntry {\n\treadonly oid: string;\n\treadonly offset: number;\n}\n\n/**\n * Entries of a version-2 `.idx`, in the index's own (oid) order; `null` for any\n * other format, or for one whose declared object count doesn't fit the bytes\n * present — an index that fails either check is not something to guess about.\n */\nexport function readPackIndex(idx: Uint8Array): PackIndexEntry[] | null {\n\tconst view = new DataView(idx.buffer, idx.byteOffset, idx.byteLength);\n\tconst namesStart = IDX_V2.headerBytes + IDX_V2.fanoutEntries * 4;\n\tif (\n\t\tidx.byteLength < namesStart ||\n\t\tview.getUint32(0) !== IDX_V2.magic ||\n\t\tview.getUint32(4) !== IDX_V2.version\n\t) {\n\t\treturn null;\n\t}\n\t// The last fanout slot counts every object in the pack.\n\tconst count = view.getUint32(namesStart - 4);\n\tconst crcStart = namesStart + count * OID_BYTES;\n\tconst offsetsStart = crcStart + count * 4;\n\tif (idx.byteLength < offsetsStart + count * 4) return null;\n\n\tconst entries: PackIndexEntry[] = [];\n\tfor (let i = 0; i < count; i++) {\n\t\tconst offset = view.getUint32(offsetsStart + i * 4);\n\t\t// Packs over 2 GiB use the 64-bit offset table instead; callers that\n\t\t// can't handle it treat this as \"not readable\" rather than guessing.\n\t\tif (offset & IDX_V2.largeOffsetFlag) return null;\n\t\tconst at = namesStart + i * OID_BYTES;\n\t\tentries.push({ oid: toHex(idx.subarray(at, at + OID_BYTES)), offset });\n\t}\n\treturn entries;\n}\n\n/** Offset of `oid` in `idx`, or `null` when the index doesn't list it. */\nexport function findPackIndexOffset(\n\tidx: Uint8Array,\n\toid: string,\n): number | null {\n\treturn readPackIndex(idx)?.find((entry) => entry.oid === oid)?.offset ?? null;\n}\n"],"mappings":"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","names":[]}