import type { ItemStack } from "../inventory/storageTier.js"; /** One active post in a {@link ListingBook}: an item stack a seller offered at a fixed price until it expires. */ export interface Listing { readonly id: string; readonly sellerId: string; readonly itemId: string; readonly count: number; readonly price: number; readonly currency: string; readonly listedAt: number; readonly expiresAt: number; } /** Tunables for {@link createListingBook} — per-seller listing cap, expiry window, house cut, and optional price bounds. */ export interface ListingBookConfig { maxListingsPerSeller: number; expirySeconds: number; cutRate: number; minPrice?: number; maxPrice?: number; } /** Input to {@link ListingBook.post} — the goods, asking price, and current game-time to stamp the listing with. */ export interface PostListingInput { id?: string; sellerId: string; itemId: string; count: number; price: number; currency: string; now: number; } /** Why {@link ListingBook.post} refused a listing. */ export type PostListingReason = "invalid-count" | "invalid-price" | "price-too-low" | "price-too-high" | "listing-cap-reached" | "duplicate-id"; /** Result of {@link ListingBook.post}. */ export type PostListingResult = { status: "ok"; listing: Listing; } | { status: "rejected"; reason: PostListingReason; }; /** Result of {@link ListingBook.cancel}. */ export type CancelListingResult = { status: "ok"; listing: Listing; } | { status: "rejected"; reason: "not-found" | "not-owner"; }; /** The financial split of a completed sale: total price, the house's cut, and what the seller's collection box was credited. */ export interface BuyListingOutcome { listing: Listing; houseCut: number; sellerProceeds: number; } /** Result of {@link ListingBook.buy}. */ export type BuyListingResult = { status: "ok"; outcome: BuyListingOutcome; } | { status: "rejected"; reason: "not-found" | "expired" | "own-listing"; }; /** A read-only view of a seller's collection box — currency and item stacks waiting to be claimed. */ export interface CollectionBoxSnapshot { currency: Readonly>; items: readonly ItemStack[]; } /** A player-driven marketplace of {@link Listing}s plus the per-seller collection boxes behind it. See {@link createListingBook}. */ export interface ListingBook { post(input: PostListingInput): PostListingResult; cancel(listingId: string, sellerId: string): CancelListingResult; buy(listingId: string, buyerId: string, now: number): BuyListingResult; sweepExpired(now: number): readonly Listing[]; get(listingId: string): Listing | null; active(): readonly Listing[]; listingsOf(sellerId: string): readonly Listing[]; countOf(sellerId: string): number; collectionOf(sellerId: string): CollectionBoxSnapshot; claimCurrency(sellerId: string): Readonly>; claimItem(sellerId: string, itemId: string, count: number): boolean; } /** * A player-driven listing marketplace: post/cancel/buy against a shared book with a house cut on * every sale, an expiry sweep that pulls unsold goods out of circulation, and a per-seller * collection box holding sale proceeds and returned items until claimed. Buyer/seller wallet and * inventory movement is the caller's job (mirrors `game/trade`'s split) — this primitive owns only * the listing lifecycle and the escrowed collection-box bookkeeping behind it. * * @capability listing-book player-driven marketplace listings with a house cut, expiry sweep, and seller collection box */ export declare function createListingBook(config: ListingBookConfig): ListingBook;