/**
 * Frontier — tracks the last-seen patch SHA per writer.
 *
 * A Frontier is the convergence boundary: it tells you which
 * patches from each writer have been incorporated into the
 * materialized state.
 *
 * @module domain/services/Frontier
 */
import defaultCodec from "../utils/defaultCodec.js";
class Frontier {
    _entries;
    constructor(entries) {
        this._entries = entries ? new Map(entries) : new Map();
    }
    /** Updates the frontier with a new writer→patchSha mapping. */
    set(writerId, patchSha) {
        this._entries.set(writerId, patchSha);
    }
    /** Gets the last-seen patch SHA for a writer. */
    get(writerId) {
        return this._entries.get(writerId);
    }
    /** Whether the frontier contains an entry for this writer. */
    has(writerId) {
        return this._entries.has(writerId);
    }
    /** Number of writers in the frontier. */
    get size() {
        return this._entries.size;
    }
    /** Sorted list of writer IDs. */
    writers() {
        return Array.from(this._entries.keys()).sort();
    }
    /** Iterate over [writerId, patchSha] entries. */
    entries() {
        return this._entries.entries();
    }
    /** Iterate over writer IDs. */
    keys() {
        return this._entries.keys();
    }
    /** Creates a shallow copy. */
    clone() {
        return new Frontier(this._entries);
    }
    /**
     * Deterministic fingerprint for snapshot isolation checks.
     * Two frontiers produce the same fingerprint iff they have
     * identical writer→SHA mappings.
     */
    fingerprint() {
        const sorted = [...this._entries.entries()].sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
        return JSON.stringify(sorted); // nosemgrep: ts-no-json-stringify-in-core -- 0025B
    }
    /**
     * Merges another frontier into this one.
     * Entries from `other` overwrite entries in `this`.
     * Returns a new Frontier (does not mutate).
     */
    merge(other) {
        const merged = this.clone();
        for (const [writerId, patchSha] of other.entries()) {
            merged.set(writerId, patchSha);
        }
        return merged;
    }
    /**
     * Serializes to canonical CBOR bytes.
     * Keys are sorted for determinism.
     *
     * NOTE: CBOR encoding in domain code is a known boundary violation.
     * Kept here because frontier serialization is tightly coupled to
     * CheckpointService. Will move to adapter when CheckpointService
     * converts (Wave 4).
     */
    serialize(codec) {
        const c = codec ?? defaultCodec;
        const obj = {};
        for (const key of this.writers()) {
            const val = this._entries.get(key);
            if (val !== undefined) {
                obj[key] = val;
            }
        }
        return c.encode(obj);
    }
    /**
     * Deserializes from CBOR bytes.
     * Same boundary violation note as serialize().
     */
    static deserialize(buffer, codec) {
        const c = codec ?? defaultCodec;
        const obj = c.decode(buffer);
        const frontier = new Frontier();
        for (const [writerId, patchSha] of Object.entries(obj)) {
            frontier.set(writerId, patchSha);
        }
        return frontier;
    }
}
// -- Backward-compatible free function exports --------------------------------
// These wrap the class for existing callers. Remove when callers migrate.
function createFrontier() {
    return new Map();
}
function updateFrontier(frontier, writerId, patchSha) {
    frontier.set(writerId, patchSha);
}
function getFrontierEntry(frontier, writerId) {
    return frontier.get(writerId);
}
function getWriters(frontier) {
    return Array.from(frontier.keys()).sort();
}
function serializeFrontier(frontier, opts = {}) {
    return new Frontier(frontier).serialize(opts.codec);
}
function deserializeFrontier(buffer, opts = {}) {
    const f = Frontier.deserialize(buffer, opts.codec);
    const map = new Map();
    for (const [k, v] of f.entries()) {
        map.set(k, v);
    }
    return map;
}
function cloneFrontier(frontier) {
    return new Map(frontier);
}
function frontierFingerprint(frontier) {
    return new Frontier(frontier).fingerprint();
}
function mergeFrontiers(a, b) {
    const merged = new Map(a);
    for (const [writerId, patchSha] of b) {
        merged.set(writerId, patchSha);
    }
    return merged;
}
export { Frontier, createFrontier, updateFrontier, getFrontierEntry, getWriters, serializeFrontier, deserializeFrontier, cloneFrontier, frontierFingerprint, mergeFrontiers, };
