import type { CollectionBoxSnapshot } from "./listingBook.js"; /** One live timed auction in an {@link AuctionBook}: an item stack under open bidding until it closes. */ export interface Auction { readonly id: string; readonly sellerId: string; readonly itemId: string; readonly count: number; readonly currency: string; readonly startPrice: number; readonly minIncrement: number; readonly buyoutPrice: number | null; readonly listedAt: number; readonly endsAt: number; readonly highBid: HighBid | null; } /** The current leading bid on an {@link Auction}. */ export interface HighBid { readonly bidderId: string; readonly amount: number; readonly at: number; } /** * Tunables for {@link createAuctionBook} — per-seller auction cap, run length, house cut, and the * anti-snipe window: a bid landing within `antiSnipeWindowSeconds` of the close pushes the close * out so it ends at least `antiSnipeExtensionSeconds` after that bid. */ export interface AuctionBookConfig { maxAuctionsPerSeller: number; durationSeconds: number; cutRate: number; antiSnipeWindowSeconds?: number; antiSnipeExtensionSeconds?: number; } /** Input to {@link AuctionBook.post} — the goods, opening terms, and current game-time. */ export interface PostAuctionInput { id?: string; sellerId: string; itemId: string; count: number; currency: string; startPrice: number; minIncrement: number; buyoutPrice?: number; now: number; } /** Why {@link AuctionBook.post} refused an auction. */ export type PostAuctionReason = "invalid-count" | "invalid-price" | "invalid-increment" | "invalid-buyout" | "auction-cap-reached" | "duplicate-id"; /** Result of {@link AuctionBook.post}. */ export type PostAuctionResult = { status: "ok"; auction: Auction; } | { status: "rejected"; reason: PostAuctionReason; }; /** Why {@link AuctionBook.bid} refused a bid. */ export type BidReason = "not-found" | "ended" | "own-auction" | "already-leading" | "bid-too-low" | "invalid-amount" | "no-buyout"; /** * Result of {@link AuctionBook.bid}. On `ok` the caller must escrow `escrowed` from the bidder's * wallet; any previously escrowed leading bid has already been refunded to that bidder's * collection box. `won` is true when the bid met the buyout price and settled the auction * immediately. */ export type BidResult = { status: "ok"; auction: Auction; escrowed: number; won: boolean; } | { status: "rejected"; reason: BidReason; }; /** Result of {@link AuctionBook.cancel}: a bid-on auction can no longer be withdrawn. */ export type CancelAuctionResult = { status: "ok"; auction: Auction; } | { status: "rejected"; reason: "not-found" | "not-owner" | "has-bids"; }; /** How one closed auction resolved during {@link AuctionBook.settleExpired}. */ export type AuctionSettlement = { status: "sold"; auction: Auction; winnerId: string; price: number; houseCut: number; sellerProceeds: number; } | { status: "returned"; auction: Auction; }; /** * A timed-bid auction marketplace plus the per-player collection boxes behind it. See * {@link createAuctionBook}. */ export interface AuctionBook { post(input: PostAuctionInput): PostAuctionResult; bid(auctionId: string, bidderId: string, amount: number, now: number): BidResult; buyout(auctionId: string, buyerId: string, now: number): BidResult; cancel(auctionId: string, sellerId: string): CancelAuctionResult; settleExpired(now: number): readonly AuctionSettlement[]; get(auctionId: string): Auction | null; active(): readonly Auction[]; auctionsOf(sellerId: string): readonly Auction[]; countOf(sellerId: string): number; collectionOf(playerId: string): CollectionBoxSnapshot; claimCurrency(playerId: string): Readonly>; claimItem(playerId: string, itemId: string, count: number): boolean; } /** * Timed-bid auctions in the WoW/BDO auction-house mold: post an item with a start price, minimum * increment, and optional buyout; bids escrow currency, outbid players are refunded into their * collection box, bids near the close extend it (anti-snipe), and settlement pays the seller minus * the house cut while the item lands in the winner's collection box. Unsold auctions return the * goods to the seller's box. Wallet and inventory movement is the caller's job (mirrors * `economy/listingBook`) — this primitive owns the auction lifecycle and the escrowed * collection-box bookkeeping behind it. * * @capability auction-book timed bid auctions with escrowed bids, buyout, anti-snipe close extension, and collection-box settlement */ export declare function createAuctionBook(config: AuctionBookConfig): AuctionBook;