SQLite database file header encoding and decoding.

Every SQLite database file opens with a fixed 100-byte, big-endian header at offset 0 of page 1:

 0      7 8     15 16    23 24    31
+--------+--------+--------+--------+
|        Magic ("SQLite format 3")  |
|             ... + NUL             |
+--------+--------+--------+--------+
|     Page Size   |WrVer   |RdVer   |
+--------+--------+--------+--------+
|Reserved|MaxEPF  |MinEPF  |LeafPF  |
+--------+--------+--------+--------+
|          File Change Counter      |
+--------+--------+--------+--------+
|         Database Size (pages)     |
+--------+--------+--------+--------+
|       First Freelist Trunk Page   |
+--------+--------+--------+--------+
|          Freelist Page Count      |
+--------+--------+--------+--------+
|             Schema Cookie         |
+--------+--------+--------+--------+
|          Schema Format Number     |
+--------+--------+--------+--------+
|        Default Page Cache Size    |
+--------+--------+--------+--------+
|        Largest Root B-tree Page   |
+--------+--------+--------+--------+
|            Text Encoding          |
+--------+--------+--------+--------+
|             User Version          |
+--------+--------+--------+--------+
|        Incremental Vacuum Mode    |
+--------+--------+--------+--------+
|            Application ID         |
+--------+--------+--------+--------+
|     Reserved for Expansion (20)   |
|                ...                |
+--------+--------+--------+--------+
|       Version-Valid-For Number    |
+--------+--------+--------+--------+
|         SQLite Version Number     |
+--------+--------+--------+--------+

Every field is big-endian. This module covers the 100-byte header only — no page layout, B-tree, or record parsing. Those live at deeper offsets governed by pageSize and are out of scope for v0.0.1.

See the SQLite file format specification for the authoritative field-by-field description.

Examples

Round-trip a freshly-created database header

import { assertEquals } from "@std/assert";
import {
  sqliteHeader,
  SQLITE_HEADER_SIZE,
  SQLITE_MAGIC,
  SQLITE_TEXT_ENCODING,
} from "@binstruct/sqlite";

const coder = sqliteHeader();
const header = {
  magic: SQLITE_MAGIC,
  pageSize: 4096,
  fileFormatWriteVersion: 1,
  fileFormatReadVersion: 1,
  reservedSpacePerPage: 0,
  maxEmbeddedPayloadFraction: 64,
  minEmbeddedPayloadFraction: 32,
  leafPayloadFraction: 32,
  fileChangeCounter: 1,
  databaseSizeInPages: 2,
  firstFreelistTrunkPage: 0,
  freelistPageCount: 0,
  schemaCookie: 1,
  schemaFormatNumber: 4,
  defaultPageCacheSize: 0,
  largestRootBtreePage: 0,
  textEncoding: SQLITE_TEXT_ENCODING.UTF8,
  userVersion: 0,
  incrementalVacuumMode: 0,
  applicationId: 0,
  reservedForExpansion: new Uint8Array(20),
  versionValidForNumber: 3045000,
  sqliteVersionNumber: 3045000,
};

const buffer = new Uint8Array(SQLITE_HEADER_SIZE);
const written = coder.encode(header, buffer);
const [decoded, read] = coder.decode(buffer);

assertEquals(written, SQLITE_HEADER_SIZE);
assertEquals(read, SQLITE_HEADER_SIZE);
assertEquals(decoded, header);