# advertise ## Purpose Encodes and decodes `cd:advertise` envelope payloads — the gossip messages a peer emits to announce which chunks it currently holds for a given file. Enforces DMP-08 (presence bitset's `bitLength` MUST equal `totalChunks`; padding bits MUST be zero), DMP-09 (generation field is unsigned 32-bit), and DMP-21 (presence MUST be framed via `@suaveplan/bitpacker-compressed`). ## Features - `encodeAdvertisePayload(payload)` — Zod-validates, cross-checks the presence bitset's embedded `bitLength` against `totalChunks`, base64-wraps the bitset, and emits UTF-8 JSON bytes. - `decodeAdvertisePayload(bytes)` — inverse, with the same DMP-08 cross-check on the receive side so receivers never trust a malformed advertisement. - Both functions throw `DmpError` with `DMP.BITSET_LENGTH_MISMATCH`, `DMP.BITSET_PADDING_NONZERO`, `DMP.CODEC_MISMATCH`, or `DMP.ENVELOPE_MALFORMED` depending on the failure class. ## Usage: Basic Example ```ts import { chunkIdsToRawBitset, decodeAdvertisePayload, encodeAdvertisePayload, encodeFramedBitset, } from "@suaveplan/drive-mesh-protocol"; const totalChunks = 64; const raw = chunkIdsToRawBitset([0, 5, 17, 63], totalChunks); const presence = encodeFramedBitset(raw, totalChunks); const wire = encodeAdvertisePayload({ fileId: "f".repeat(64), presence, totalChunks, generation: 7, timestamp: Date.now(), }); const back = decodeAdvertisePayload(wire); ``` ## Usage: Advanced Example ```ts import { chunkIdsToRawBitset, decodeAdvertisePayload, encodeAdvertisePayload, encodeFramedBitset, GenerationTracker, } from "@suaveplan/drive-mesh-protocol"; const tracker = new GenerationTracker(); function handleIncomingAdvertise(bytes: Uint8Array, peerId: string): void { const adv = decodeAdvertisePayload(bytes); const r = tracker.observe(peerId, adv.fileId, adv.generation); if (!r.accept) return; // DMP-09 stale-drop // Update peer-index for (peerId, adv.fileId) using adv.presence. } ``` ## API Reference - `encodeAdvertisePayload(payload: ChunkAdvertisePayload): Uint8Array`. - `decodeAdvertisePayload(bytes: Uint8Array): ChunkAdvertisePayload`. - Errors: `DMP.BITSET_LENGTH_MISMATCH`, `DMP.BITSET_PADDING_NONZERO`, `DMP.CODEC_MISMATCH`, `DMP.ENVELOPE_MALFORMED`. ## Implementation Notes The encode-side cross-check between `bitLength` (recovered from the framed presence bitset) and `totalChunks` is intentional defence-in-depth: it stops a bug in the issuer from emitting an advertisement whose receivers would later reject. Generations are validated up to `0xFFFF_FFFF` at the schema layer; wrap-detection logic lives in `generation/monotonic.ts`. The `unwrapWire` helper passes through bare nulls / non-objects so the schema is the single source of "this isn't a valid envelope" rejection — every malformed input ends up at the schema gate, not at a JS-level type error.