~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/pds.js

An atproto PDS in JavaScript, for Cloudflare Workers and Node

0
0
main
73 lines · 2.0 KB Raw History
/**
 * Git bundle file parsing: a text header (format marker, optional
 * capabilities, prerequisites, refs) terminated by a blank line, followed by
 * a complete packfile.
 */

const decoder = new TextDecoder();

/**
 * @typedef {Object} ParsedBundle
 * @property {2|3} version
 * @property {Array<{sha: string, name: string}>} refs
 * @property {string[]} prerequisites
 * @property {Record<string, string>} capabilities
 * @property {Uint8Array} pack - the complete packfile region
 */

/**
 * @param {Uint8Array} bytes
 * @returns {ParsedBundle}
 */
export function parseBundle(bytes) {
  /** @type {Array<{sha: string, name: string}>} */
  const refs = [];
  /** @type {string[]} */
  const prerequisites = [];
  /** @type {Record<string, string>} */
  const capabilities = {};
  /** @type {2|3|null} */
  let version = null;

  let offset = 0;
  let lineStart = 0;
  let sawSignature = false;
  while (offset < bytes.length) {
    if (bytes[offset] !== 0x0a) {
      offset++;
      continue;
    }
    const line = decoder.decode(bytes.subarray(lineStart, offset));
    offset++;
    lineStart = offset;
    if (!sawSignature) {
      if (line === '# v2 git bundle') version = 2;
      else if (line === '# v3 git bundle') version = 3;
      else throw new Error('not a git bundle');
      sawSignature = true;
      continue;
    }
    if (line === '') break;
    if (line.startsWith('@')) {
      const eq = line.indexOf('=');
      if (eq === -1) capabilities[line.slice(1)] = '';
      else capabilities[line.slice(1, eq)] = line.slice(eq + 1);
      continue;
    }
    if (line.startsWith('-')) {
      prerequisites.push(line.slice(1).split(' ')[0]);
      continue;
    }
    const space = line.indexOf(' ');
    if (space === -1) throw new Error('malformed bundle ref line');
    refs.push({ sha: line.slice(0, space), name: line.slice(space + 1) });
  }
  if (version === null) throw new Error('not a git bundle');
  return {
    version,
    refs,
    prerequisites,
    capabilities,
    pack: bytes.subarray(lineStart),
  };
}