/** * shipping.ts, the tier preference, and the ladder that steps down one rung. * * The preference is ORDINAL against what the checkout actually offers, not * against delivery-day promises. Merchants describe delivery in incomparable * ways, "2-day", "express", "by Tuesday", and a rule written against those * words breaks on the next merchant. Ranking the offered options cheapest-first * and indexing into that ranking works everywhere and is honest about what it * is doing. * * A merchant offering three options gets all three tiers; two options collapse * `fast` and `fastest` onto the same one; one option leaves nothing to choose. * * ── The ladder ──────────────────────────────────────────────────────────── * * The preferred tier draws on the overage pool. When the pool cannot cover it, * step down ONE tier at a time until it fits, stopping at the cheapest. Not * straight to the cheapest: with tiers at $15 / $9 / $5 and $9 available, the * one-rung rule gets the owner $9 delivery and the shortcut gets them $5 * delivery they did not ask for. * * A step-down needs no approval, it is within budget by construction, but it * IS recorded and surfaced, because the owner must not learn about it from a * late package. * * ── Filler items ────────────────────────────────────────────────────────── * * There is no free-shipping-threshold logic in this file, and there must never * be. Adding an item the owner did not ask for in order to save on delivery is * buying something on their behalf to make a number look better. `assertCartMatchesRequest` * in cart.ts is the enforcement; its absence here is the design. */ import type { MinorUnits, ShippingOption, ShippingStepDown, ShippingTier } from './types.js'; export interface RankedShipping { /** Cheapest first. The ranking the tier preference indexes into. */ readonly ranked: readonly ShippingOption[]; readonly tierToOption: ReadonlyMap; } /** * Rank the checkout's delivery options and map each tier onto one. * * Ties are broken by the order the checkout listed them, so a merchant offering * two options at the same price does not get a coin flip between them. */ export declare function rankShippingOptions(options: readonly ShippingOption[]): RankedShipping; export interface ShippingLadderResult { readonly tier: ShippingTier; readonly option: ShippingOption; readonly costMinorUnits: MinorUnits; readonly stepDown: ShippingStepDown | null; /** How many rungs were tried, so a test can prove it stepped rather than jumped. */ readonly rungsTried: number; } /** * Walk down from the preferred tier until the total unavoidable draw fits. * * `budgetForOverage` is what the overage pool can still cover; `fixedUnavoidable` * is tax plus mandatory fees, which no amount of stepping down can reduce. * Returns null when nothing fits even at the cheastest rung, the caller then * either draws on the tolerance pool or refuses, per the decision order. */ export declare function walkShippingLadder(input: { readonly preferred: ShippingTier; readonly options: readonly ShippingOption[]; readonly fixedUnavoidableMinorUnits: MinorUnits; readonly budgetForOverageMinorUnits: MinorUnits; }): ShippingLadderResult | null; /** The cheapest rung, for the shortfall arithmetic when even it does not fit. */ export declare function cheapestOption(options: readonly ShippingOption[]): ShippingOption | null; //# sourceMappingURL=shipping.d.ts.map