/**
 * EffectPipeline — host-domain infrastructure for managed outbound
 * delivery.
 *
 * Orchestrates emission through sinks and collects delivery
 * observations. This is NOT substrate — it operates entirely
 * outside the graph. The graph provides effect entities (written by
 * participants); the pipeline externalizes them.
 *
 * @module EffectPipeline
 * @see docs/design/layer-boundary.md
 */
import { createEffectEmission } from "../types/EffectEmission.js";
import { requireDeliveryObservationBatch } from "../types/DeliveryObservationBatch.js";
const NULL_COORDINATE = {
    frontier: null,
    ceiling: null,
};
/**
 * Extracts the writer from emit options, defaulting to null.
 */
function resolveWriter(options) {
    return options?.writer ?? null;
}
/**
 * Normalizes a raw coordinate object, defaulting undefined fields to null.
 */
function normalizeCoordinate(coord) {
    return {
        frontier: coord.frontier ?? null,
        ceiling: coord.ceiling ?? null,
    };
}
/**
 * Extracts the coordinate from emit options, defaulting to null frontier and ceiling.
 */
function resolveCoordinate(options) {
    const coord = options?.coordinate ?? null;
    if (coord === null) {
        return NULL_COORDINATE;
    }
    return normalizeCoordinate(coord);
}
export class EffectPipeline {
    _sink;
    _lens;
    _emissions;
    _observations;
    /**
     * Constructs a pipeline bound to a delivery sink and an externalization lens.
     */
    constructor(options) {
        this._sink = options.sink;
        this._lens = options.lens;
        this._emissions = [];
        this._observations = [];
    }
    /**
     * Returns the current externalization policy governing delivery behavior.
     */
    get lens() {
        return this._lens;
    }
    /**
     * Replaces the externalization policy for subsequent deliveries.
     */
    set lens(newLens) {
        this._lens = newLens;
    }
    /**
     * Returns a copy of the emission log.
     */
    get emissions() {
        return [...this._emissions];
    }
    /**
     * Returns a copy of the observation log.
     */
    get observations() {
        return [...this._observations];
    }
    /**
     * Emits an effect and delivers it through the configured sink.
     */
    async emit(kind, payload, // nosemgrep: ts-no-unknown-outside-adapters -- 0025B
    options) {
        const emission = createEffectEmission({
            id: options?.id ?? '',
            kind,
            payload,
            timestamp: options?.timestamp ?? 0,
            writer: resolveWriter(options),
            coordinate: resolveCoordinate(options),
        });
        this._emissions.push(emission);
        const observations = requireDeliveryObservationBatch(await this._sink.deliver(emission, this._lens), this._sink.id);
        this._recordObservations(observations);
        return { emission, observations };
    }
    /**
     * Appends one or more delivery observations to the internal observation log.
     */
    _recordObservations(observations) {
        for (const obs of observations) {
            this._observations.push(obs);
        }
    }
}
