# build ## Purpose Constructs a server-signed `Manifest` for an ingested file: bundles the file metadata (`fileId`, `fileSize`, `chunkSize`, `totalChunks`), encryption envelope (`algo`, `fileKeyWrapped`, `baseNonce`), and per-chunk integrity hashes into a single record, then signs the canonical encoding under the server private key. The manifest is the consensus artefact: peers that trust the server public key can verify it without holding any chunk bytes. ## Features - `buildManifest(options): Manifest` — pure function, no I/O, no global state. - `canonicalSerialize(manifest): Uint8Array` — deterministic big-endian length-prefixed encoding suitable for cross-platform Ed25519 signing. - `algo` is encoded as a length-prefixed UTF-8 string so future encryption algorithms can be added without breaking the wire format. - Per-chunk entries pack `(chunkId: u32, hash: 32 bytes, payloadLen: u32)` into 40 bytes — bounded growth, predictable memory. ## Usage: Basic Example ```ts import { buildManifest } from "@suaveplan/drive-plugin-chunks"; const manifest = buildManifest({ fileId: sha256Bytes, fileSize: 12n, chunkSize: 1024, totalChunks: 1, encryption: { algo: "xchacha20poly1305", fileKeyWrapped: fileKey, baseNonce }, chunks: [{ chunkId: 0, hash: chunkHash, payloadLen: 12 }], serverPrivKey, }); ``` ## Usage: Advanced Example ```ts import { buildManifest, canonicalSerialize } from "@suaveplan/drive-plugin-chunks"; import { verify } from "@suaveplan/crypto-curve/ed25519"; const manifest = buildManifest({ /* ... */ }); const { sig, ...base } = manifest; const ok = verify(sig, canonicalSerialize(base), serverPubKey); ``` ## API Reference - `buildManifest(options): Manifest` — returns `{ version, fileId, fileSize, chunkSize, totalChunks, encryption, chunks, sig }`. - `canonicalSerialize(manifest: Omit): Uint8Array` — used both for signing and for verification. ## Implementation Notes Field order in `canonicalSerialize` is fixed and big-endian; changing it would break every previously-stored manifest. The `algo` length prefix makes the encoded form self-delimiting so receivers don't need an explicit version bump to add new algorithms — they only need to add a parsing branch keyed on the algo string. The final `buf.slice(0, off)` trims any over-allocated tail, but `totalLen` is computed exactly so this is normally a no-op.