@agg-build/hooks 2.1.1 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  __async,
3
3
  useAggClient
4
- } from "./chunk-FYEPQHKO.mjs";
4
+ } from "./chunk-7UDYSDKQ.mjs";
5
5
 
6
6
  // src/use-ramp-quotes.ts
7
7
  import { useMutation } from "@tanstack/react-query";
@@ -835,6 +835,7 @@ var enUsLabels = {
835
835
  orderSkip: "Skip",
836
836
  orderRetryRemaining: "Retry remaining",
837
837
  resolvedEarningsTitle: "Your Earnings",
838
+ resolvedResolutionDateLabel: "Resolution date",
838
839
  resolvedSharesLabel: "Shares",
839
840
  resolvedTotalPayoutLabel: "Total payout",
840
841
  claimWinnings: "Claim Winnings",
@@ -2007,6 +2008,98 @@ var applyOrderbookDepth = (data, depth) => {
2007
2008
  });
2008
2009
  };
2009
2010
 
2011
+ // src/market-data/market-resolution-cache.ts
2012
+ var isRecord = (value) => {
2013
+ return typeof value === "object" && value !== null;
2014
+ };
2015
+ var NESTED_COLLECTION_FIELDS = ["pages", "data", "markets", "events", "venueMarkets"];
2016
+ var marketContainsOutcomeId = (market, outcomeId) => {
2017
+ if (!isRecord(market)) return false;
2018
+ const outcomes = market.venueMarketOutcomes;
2019
+ if (!Array.isArray(outcomes)) return false;
2020
+ return outcomes.some((outcome) => isRecord(outcome) && outcome.id === outcomeId);
2021
+ };
2022
+ var cachedDataContainsOutcomeId = (data, outcomeId) => {
2023
+ if (Array.isArray(data)) {
2024
+ return data.some((entry) => cachedDataContainsOutcomeId(entry, outcomeId));
2025
+ }
2026
+ if (!isRecord(data)) return false;
2027
+ if (marketContainsOutcomeId(data, outcomeId)) return true;
2028
+ return NESTED_COLLECTION_FIELDS.some((field) => {
2029
+ const value = data[field];
2030
+ return Array.isArray(value) && value.some((entry) => cachedDataContainsOutcomeId(entry, outcomeId));
2031
+ });
2032
+ };
2033
+ var normalizeLabel = (label) => {
2034
+ return typeof label === "string" ? label.trim().toLowerCase() : "";
2035
+ };
2036
+ var findResolvedOutcome = (resolvedOutcomes, outcome) => {
2037
+ var _a;
2038
+ const externalIdentifier = outcome.externalIdentifier;
2039
+ if (typeof externalIdentifier === "string" && externalIdentifier.length > 0) {
2040
+ const matchedByExternalId = resolvedOutcomes.find(
2041
+ (resolved) => resolved.externalIdentifier === externalIdentifier
2042
+ );
2043
+ if (matchedByExternalId) return matchedByExternalId;
2044
+ }
2045
+ const label = normalizeLabel(outcome.label);
2046
+ if (label) {
2047
+ return (_a = resolvedOutcomes.find((resolved) => normalizeLabel(resolved.label) === label)) != null ? _a : null;
2048
+ }
2049
+ return null;
2050
+ };
2051
+ var applyWinnersToOutcomes = (outcomes, resolution) => {
2052
+ let changed = false;
2053
+ const next = outcomes.map((outcome) => {
2054
+ if (!isRecord(outcome)) return outcome;
2055
+ const resolved = findResolvedOutcome(resolution.outcomes, outcome);
2056
+ if (!resolved) return outcome;
2057
+ const nextWinner = resolved.winner === true;
2058
+ if (outcome.winner === nextWinner) return outcome;
2059
+ changed = true;
2060
+ return __spreadProps(__spreadValues({}, outcome), { winner: nextWinner });
2061
+ });
2062
+ return changed ? next : outcomes;
2063
+ };
2064
+ var applyResolutionToMarket = (market, resolution) => {
2065
+ const outcomes = market.venueMarketOutcomes;
2066
+ if (!Array.isArray(outcomes)) return market;
2067
+ if (!outcomes.some((outcome) => isRecord(outcome) && outcome.id === resolution.outcomeId)) {
2068
+ return market;
2069
+ }
2070
+ const nextOutcomes = applyWinnersToOutcomes(outcomes, resolution);
2071
+ const statusChanged = market.status !== resolution.status;
2072
+ if (!statusChanged && nextOutcomes === outcomes) return market;
2073
+ return __spreadProps(__spreadValues({}, market), { status: resolution.status, venueMarketOutcomes: nextOutcomes });
2074
+ };
2075
+ var applyResolutionToCachedData = (data, resolution) => {
2076
+ if (Array.isArray(data)) {
2077
+ let changed2 = false;
2078
+ const next2 = data.map((entry) => {
2079
+ const updated = applyResolutionToCachedData(entry, resolution);
2080
+ if (updated !== entry) changed2 = true;
2081
+ return updated;
2082
+ });
2083
+ return changed2 ? next2 : data;
2084
+ }
2085
+ if (!isRecord(data)) return data;
2086
+ if (Array.isArray(data.venueMarketOutcomes)) {
2087
+ return applyResolutionToMarket(data, resolution);
2088
+ }
2089
+ let changed = false;
2090
+ const next = __spreadValues({}, data);
2091
+ for (const field of NESTED_COLLECTION_FIELDS) {
2092
+ const value = data[field];
2093
+ if (!Array.isArray(value)) continue;
2094
+ const updated = applyResolutionToCachedData(value, resolution);
2095
+ if (updated !== value) {
2096
+ next[field] = updated;
2097
+ changed = true;
2098
+ }
2099
+ }
2100
+ return changed ? next : data;
2101
+ };
2102
+
2010
2103
  // src/market-data/query-keys.ts
2011
2104
  var marketDataKeys = {
2012
2105
  all: () => ["market-data"],
@@ -2235,6 +2328,62 @@ function AggWebSocketProvider({ children }) {
2235
2328
  const invalidateActivityCaches = useCallback3(() => {
2236
2329
  invalidateUserActivityQueries(queryClient);
2237
2330
  }, [queryClient]);
2331
+ const invalidateResolutionCaches = useCallback3(
2332
+ (resolution) => {
2333
+ const { outcomeId } = resolution;
2334
+ syncLiveQuery(outcomeId, (previous) => {
2335
+ if (!previous) return previous;
2336
+ if (previous.orderbook == null && previous.orderbookError == null) return previous;
2337
+ return __spreadProps(__spreadValues({}, previous), {
2338
+ orderbook: null,
2339
+ orderbookError: null,
2340
+ integrity: "ok"
2341
+ });
2342
+ });
2343
+ const affectedQueries = queryClient.getQueryCache().findAll({
2344
+ predicate: (query) => cachedDataContainsOutcomeId(query.state.data, outcomeId)
2345
+ });
2346
+ for (const query of affectedQueries) {
2347
+ queryClient.setQueryData(
2348
+ query.queryKey,
2349
+ (previous) => applyResolutionToCachedData(previous, resolution)
2350
+ );
2351
+ }
2352
+ queryClient.invalidateQueries({
2353
+ queryKey: ["midpoints"],
2354
+ refetchType: "all"
2355
+ });
2356
+ queryClient.invalidateQueries({
2357
+ queryKey: ["venue-market-midpoints"],
2358
+ refetchType: "all"
2359
+ });
2360
+ queryClient.invalidateQueries({
2361
+ queryKey: ["venue-event"],
2362
+ refetchType: "all"
2363
+ });
2364
+ queryClient.invalidateQueries({
2365
+ queryKey: ["venue-markets"],
2366
+ refetchType: "all"
2367
+ });
2368
+ queryClient.invalidateQueries({
2369
+ queryKey: ["events"],
2370
+ refetchType: "all"
2371
+ });
2372
+ queryClient.invalidateQueries({
2373
+ queryKey: ["event-list"],
2374
+ refetchType: "all"
2375
+ });
2376
+ queryClient.invalidateQueries({
2377
+ queryKey: ["search"],
2378
+ refetchType: "all"
2379
+ });
2380
+ queryClient.invalidateQueries({
2381
+ predicate: (query) => cachedDataContainsOutcomeId(query.state.data, outcomeId),
2382
+ refetchType: "all"
2383
+ });
2384
+ },
2385
+ [queryClient, syncLiveQuery]
2386
+ );
2238
2387
  const callbacks = useMemo2(
2239
2388
  () => ({
2240
2389
  onSnapshot: (marketId, book) => {
@@ -2383,6 +2532,14 @@ function AggWebSocketProvider({ children }) {
2383
2532
  listener(msg);
2384
2533
  }
2385
2534
  },
2535
+ onMarketResolved: (msg) => {
2536
+ invalidateResolutionCaches(msg);
2537
+ if (isClientAuthenticated) {
2538
+ invalidateBalanceCaches();
2539
+ invalidatePositionCaches();
2540
+ invalidateActivityCaches();
2541
+ }
2542
+ },
2386
2543
  onError: (msg) => {
2387
2544
  const outcomeId = resolveSnapshotUnavailableOutcomeId(msg.message);
2388
2545
  if (!outcomeId) return;
@@ -2420,6 +2577,7 @@ function AggWebSocketProvider({ children }) {
2420
2577
  invalidateActivityCaches,
2421
2578
  invalidateBalanceCaches,
2422
2579
  invalidatePositionCaches,
2580
+ invalidateResolutionCaches,
2423
2581
  isClientAuthenticated,
2424
2582
  queryClient,
2425
2583
  syncChartQueries,
@@ -11,7 +11,7 @@ import {
11
11
  useOnWithdrawalLifecycle,
12
12
  useSyncBalances,
13
13
  useWithdrawManaged
14
- } from "./chunk-FYEPQHKO.mjs";
14
+ } from "./chunk-7UDYSDKQ.mjs";
15
15
 
16
16
  // src/withdraw/use-withdraw-flow.ts
17
17
  import { useCallback, useEffect, useMemo, useState } from "react";
package/dist/deposit.js CHANGED
@@ -98,8 +98,9 @@ var import_wagmi = require("wagmi");
98
98
 
99
99
  // src/deposit/constants.ts
100
100
  var DEFAULT_SOLANA_RPC_ENDPOINTS = [
101
+ "https://solana-rpc.publicnode.com",
101
102
  "https://api.mainnet.solana.com",
102
- "https://solana-rpc.publicnode.com"
103
+ "https://rpc.ankr.com/solana"
103
104
  ];
104
105
  var DEFAULT_SOLANA_RPC_ENDPOINT = DEFAULT_SOLANA_RPC_ENDPOINTS[0];
105
106
  var SVM_CHAIN_IDS = /* @__PURE__ */ new Set([792703809]);
@@ -769,6 +770,7 @@ var enUsLabels = {
769
770
  orderSkip: "Skip",
770
771
  orderRetryRemaining: "Retry remaining",
771
772
  resolvedEarningsTitle: "Your Earnings",
773
+ resolvedResolutionDateLabel: "Resolution date",
772
774
  resolvedSharesLabel: "Shares",
773
775
  resolvedTotalPayoutLabel: "Total payout",
774
776
  claimWinnings: "Claim Winnings",
package/dist/deposit.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  useRampQuotes,
3
3
  useRampSession
4
- } from "./chunk-AFZD3GIQ.mjs";
4
+ } from "./chunk-5VDUIUJB.mjs";
5
5
  import {
6
6
  __async,
7
7
  useAggAuthState,
@@ -10,7 +10,7 @@ import {
10
10
  useAggUiConfig,
11
11
  useDepositAddresses,
12
12
  useSyncBalances
13
- } from "./chunk-FYEPQHKO.mjs";
13
+ } from "./chunk-7UDYSDKQ.mjs";
14
14
 
15
15
  // src/deposit/normalize-wallet-error.ts
16
16
  function normalizeWalletError(error, supportedChains) {
@@ -41,8 +41,9 @@ import { useAccount, useReadContract } from "wagmi";
41
41
 
42
42
  // src/deposit/constants.ts
43
43
  var DEFAULT_SOLANA_RPC_ENDPOINTS = [
44
+ "https://solana-rpc.publicnode.com",
44
45
  "https://api.mainnet.solana.com",
45
- "https://solana-rpc.publicnode.com"
46
+ "https://rpc.ankr.com/solana"
46
47
  ];
47
48
  var DEFAULT_SOLANA_RPC_ENDPOINT = DEFAULT_SOLANA_RPC_ENDPOINTS[0];
48
49
  var SVM_CHAIN_IDS = /* @__PURE__ */ new Set([792703809]);
package/dist/index.d.mts CHANGED
@@ -271,6 +271,12 @@ type VenueMarket = {
271
271
  sportsMarketType?: string | null | undefined;
272
272
  /** Sort rank within a sports section (0=moneyline, 1=spread, 2=total, 3+=other). */
273
273
  sectionRank?: number | null | undefined;
274
+ /** Period identifier for sports markets (e.g., "1H", "2H", "Q1", etc.). */
275
+ period?: string | null | undefined;
276
+ /** Normalized subject category for prop-tab grouping (e.g., game_lines, exact_score, etc.). */
277
+ marketCategory?: string | null | undefined;
278
+ /** Line value for spread/total markets (e.g., 2.5 for totals, 3 for spreads). */
279
+ lineValue?: number | null | undefined;
274
280
  matchedVenueMarkets?: {
275
281
  id: string;
276
282
  venue: Venue;
@@ -324,10 +330,18 @@ type VenueEvent = {
324
330
  startDate?: string | null | undefined;
325
331
  endDate?: string | null | undefined;
326
332
  creationDate?: string | null | undefined;
333
+ /**
334
+ * Scheduled kickoff/start of the underlying game (sports events only).
335
+ * Distinct from `endDate` (market close/expiration), which can sit well
336
+ * after the game. The FE prefers this over `endDate` for the game-date
337
+ * title suffix. Null for non-sports events.
338
+ */
339
+ gameStartTime?: string | null | undefined;
327
340
  slug?: string | null | undefined;
328
341
  subtitle?: string | null | undefined;
329
342
  venues?: Venue[];
330
343
  venueCount?: number | undefined;
344
+ groupMarketCount?: number | undefined;
331
345
  marketCount?: number | undefined;
332
346
  /**
333
347
  * ISO-8601 duration denormalized from Series.recurrence. `null` means
@@ -1087,6 +1101,7 @@ interface AggUiLabels {
1087
1101
  orderSkip: string;
1088
1102
  orderRetryRemaining: string;
1089
1103
  resolvedEarningsTitle: string;
1104
+ resolvedResolutionDateLabel: string;
1090
1105
  resolvedSharesLabel: string;
1091
1106
  resolvedTotalPayoutLabel: string;
1092
1107
  claimWinnings: string;
@@ -3350,10 +3365,42 @@ declare function useLiveOutcomePrices(venueMarkets: VenueMarket[] | null | undef
3350
3365
  */
3351
3366
  declare function findLivePriceById(livePrices: Map<string, number>, id: string): number | undefined;
3352
3367
 
3368
+ interface MarketLiveState {
3369
+ marketId: string;
3370
+ orderbook: OrderbookState | null;
3371
+ orderbookSnapshotVersion: number;
3372
+ orderbookError: string | null;
3373
+ trades: WsTrade[];
3374
+ isConnected: boolean;
3375
+ integrity: "ok" | "resyncing";
3376
+ }
3377
+
3353
3378
  type LiveBestPrices = ReadonlyMap<string, {
3354
3379
  bestBid?: number;
3355
3380
  bestAsk?: number;
3356
3381
  }>;
3382
+ /**
3383
+ * A WS-derived best-price candidate for one outcome, carrying the venue that
3384
+ * produced each side *and* a freshness stamp. This is the richer companion to
3385
+ * {@link LiveBestPrices}: it keeps the venue attribution that the bare
3386
+ * `{ bestBid, bestAsk }` map throws away, so display surfaces can switch the
3387
+ * venue logo to whichever venue currently owns the best live price — keeping
3388
+ * the logo paired with the price instead of pinned to the REST snapshot.
3389
+ */
3390
+ interface LiveBestPriceCandidate {
3391
+ bestBid?: number;
3392
+ bestAsk?: number;
3393
+ /** Venue that owns the cross-venue best bid (best place to sell). */
3394
+ bestBidVenue?: string;
3395
+ /** Venue that owns the cross-venue best ask (cheapest place to buy). */
3396
+ bestAskVenue?: string;
3397
+ midpoint?: number;
3398
+ /** Venue the midpoint is attributed to (cheapest-ask side, then best-bid). */
3399
+ midpointVenue?: string;
3400
+ /** Orderbook timestamp (seconds) of the freshest book backing this candidate. */
3401
+ updatedAt?: number;
3402
+ }
3403
+ type LiveBestPriceCandidates = ReadonlyMap<string, LiveBestPriceCandidate>;
3357
3404
  /**
3358
3405
  * WS-derived cross-venue + cross-outcome best bid/ask per outcome.
3359
3406
  *
@@ -3381,6 +3428,35 @@ declare function mergeBestPricesPreferringLive(rest: ReadonlyMap<string, {
3381
3428
  bestBid?: number;
3382
3429
  bestAsk?: number;
3383
3430
  }>;
3431
+ /**
3432
+ * Pull the per-outcome best bid/ask, attributed venues, midpoint and freshness
3433
+ * out of a single live orderbook state. Pure — exported for unit tests.
3434
+ */
3435
+ declare const extractOutcomeBestCandidate: (state: MarketLiveState | undefined) => LiveBestPriceCandidate;
3436
+ /**
3437
+ * Cross-venue + cross-outcome venue-attributed best-price candidates.
3438
+ *
3439
+ * Pure (no React) so the cross-venue fold can be unit-tested directly:
3440
+ * - Pass 1: per-outcome candidate from each outcome's own aggregated book.
3441
+ * - Pass 2: fold across MVMO groups. Lowest ask wins (cheapest to buy),
3442
+ * highest bid wins (best to sell), and the *winning venue* + freshest
3443
+ * timestamp travel with the chosen price to every member of the group.
3444
+ * This is what lets a different venue's live book switch both the price
3445
+ * and the venue logo on every WS update.
3446
+ *
3447
+ * Mirrors the price fold in {@link useLiveBestPrices} and the REST fold in
3448
+ * `useMidpoints.extractBestPrices`, but additionally tracks venue + freshness.
3449
+ */
3450
+ declare function buildLiveBestPriceCandidates(outcomeIds: string[], states: Array<MarketLiveState | undefined>, venueMarkets: VenueMarket[] | null | undefined): Map<string, LiveBestPriceCandidate>;
3451
+ /**
3452
+ * React hook companion to {@link useLiveBestPrices} that additionally carries
3453
+ * venue attribution + freshness per outcome. Recomputes on every WS update
3454
+ * (snapshot/delta) that moves price, venue ownership, or timestamp.
3455
+ *
3456
+ * Empty until WS books land for the subscribed outcomes. Designed to feed a
3457
+ * unified price+venue selector so the venue logo always follows the live price.
3458
+ */
3459
+ declare function useLiveBestPriceCandidates(venueMarkets: VenueMarket[] | null | undefined): LiveBestPriceCandidates;
3384
3460
 
3385
3461
  /**
3386
3462
  * Subscribe to real-time trade feed for a canonical market.
@@ -5504,4 +5580,4 @@ declare function useAppConfig(): UseAppConfigResult;
5504
5580
  */
5505
5581
  declare function useCachedAppConfig(): UseAppConfigResult;
5506
5582
 
5507
- export { AUTH_CHOOSER_OPEN_EVENT, type AggAuthContextValue, type AggAuthSignInOptions, type AggBalanceContextValue, AggBalanceProvider, AggProvider, type AggProviderProps, AggProvider as AggSdkProvider, type AggProviderProps as AggSdkProviderProps, type AggUiConfig, type AggUiConfigInput, type AggUiLabels, type AggUiLabelsInput, AggUiProvider, type AggUiTradingExecutionMode, CHART_TIME_RANGES, CONFIRMED_MATCH_STATUSES, type ChartTimeRange, type ClosedPositionTotals, type ComputePriceGapsOptions, DEFAULT_AGG_ROOT_CLASS_NAME, type DagStepProgress, type EventListStateContextValue, EventListStateProvider, type EventListStateSnapshot, type EventTradingContextValue, type EventTradingState, type ExecutionProgressPhase, type ExecutionTerminalOrderEvent, type GeoBlockState, type GetOrdersQuery, type GetPositionsQuery, type InvalidateUserActivityOptions, type InvalidateUserMoneyStateOptions, type LiveBestPrices, type LiveCandle, MAX_PRICE_GAP_PCT, MIN_PRICE_GAP_PCT, type MarketChartCandle, type MarketChartData, type MarketChartVenueData, type MarketOrderbookData, type MarketOrderbookIntegrity, MarketStatus, type MarketTradingState, MatchStatus, MatchType, type OrderEligibility, type OrderEligibilityReason, type OrderListItem, type OrderbookResult, type PositionGroup, type PriceGapValue, type RedeemEvent, type RedeemLegLifecycle, type RedeemLifecycleState, RedeemRejectedError, type RollingChartWindow, type ScaledCandlePoint, type SdkUiConfig, type SdkUiConfigInput, type SdkUiProviderProps, type SmartRouteLoadingReason, type ThemeMode, TradeSide, type TradingAction, type TradingState, type TradingStateBase, type TradingStateKind, type UseAggAuthOptions, type UseAggAuthReturn, type UseAppConfigResult, type UseArbFeedResult, type UseCategoriesOptions, type UseCategoryChildrenOptions, type UseEnrichedVenueEventOptions, type UseExecuteManagedOptions, type UseExecutionOrdersOptions, type UseExecutionPositionsOptions, type UseExecutionProgressOptions, type UseExecutionProgressResult, type UseExternalIdOptions, type UseExternalIdReturn, type UseLinkAccountReturn, type UseLiveCandleOverlayOptions, type UseLiveCandleOverlayResult, type UseLiveCandlesOptions, type UseLiveCandlesResult, type UseLiveMarketResult, type UseMarketArbResult, type UseMarketChartOptions, type UseMarketChartResult, type UseMarketOrderbookOptions, type UseMarketOrderbookResult, type UseMarketOrderbookVenueOutcome, type UseMarketSearchOptions, type UseMidpointsOptions, type UseMidpointsResult, type UseOrderBookOptions, type UseOrderbookQuoteOptions, type UseOrderbookQuoteResult, type UseOrdersOptions, type UsePositionsOptions, type UseQuoteManagedOptions, type UseRedeemLifecycleInput, type UseRollingChartWindowOptions, type UseSearchOptions, type UseSmartRouteOptions, type UseSmartRouteResult, type UseTradableVenuesResult, type UseUserActivityOptions, type UseUserHoldingsOptions, type UseVenueEventOptions, type UseVenueEventsOptions, type UseVenueMarketMidpointsOptions, type UseVenueMarketsOptions, type UseViewportMidpointsOptions, type UseVisibleIdsOptions, type UseVisibleIdsResult, type UserActivityInvalidationStrategy, Venue, type VenueAvailabilityState, type VenueEvent, type VenueEventWithMarkets, type VenueMarket, type VenueMarketOutcome, type WalletActionSendTokenParams, type WalletActions, computeClosedPositionTotals, computePriceGaps, defaultAggUiConfig, defaultAggUiConfig as defaultSdkUiConfig, executionKeys, findLivePriceById, getBuilder, getOrCreateBuilder, getVenueAvailabilityState, getVisibleVenueIdsByConfig, getVisibleVenuesByConfig, getWalletAddressFromUserProfile, invalidateBalanceQueries, invalidatePositionQueries, invalidateUserActivityQueries, invalidateUserClaimState, invalidateUserMoneyState, isVenueDisabledByConfig, mergeBestPricesPreferringLive, normalizeVenueId, optimizedImageUrl, parseEmail, parseEmailStrict, rangeToSeconds, requestAggAuthChooserOpen, resolveAggUiLabels, resolveDefaultMarket as resolveDefaultTradingMarket, resolveEventTradingState, resolveMarketTradingState, resolveMarketWinningOutcome, resolveOrderEligibility, resolveRollingWindow, resolveTradingStateKind, sortVenues, timeRangeToInterval, tradingReducer, useAggAuth, useAggAuthContext, useAggAuthState, useAggBalance, useAggBalanceContext, useAggBalanceState, useAggClient, useAggLabels, useAggUiConfig, useAggWebSocket, useAppConfig, useArbFeed, useCachedAppConfig, useCategories, useCategoryChildren, useDebouncedValue, useEnrichedVenueEvent, useEventListState, useEventOrderbookData, useEventTradingContext, useExecuteManaged, useExecutionOrders, useExecutionPositions, useExecutionProgress, useExternalId, useGeoBlock, useLabels, useLinkAccount, useLiveBestPrices, useLiveCandleOverlay, useLiveCandles, useLiveMarket, useLiveMarketStores, useLiveOutcomePrices, useLiveTrades, useMarketArb, useMarketChart, useMarketOrderbook, useMarketSearch, useMidpoints, useOnBalanceUpdate, useOnOrderEvent, useOnOrderSubmitted, useOnRedeemEvent, useOnWithdrawalLifecycle, useOptionalAggClient, useOrderBook, useOrderbookQuote, useOrders, usePositions, useQuoteManaged, useRampQuotes, useRampSession, useRedeem, useRedeemEligibleCount, useRedeemLifecycle, useRedeemLifecycles, useRollingChartWindow, useSdkLabels, useSdkUiConfig, useSearch, useSmartRoute, useTradableVenues, useUserActivity, useUserHoldings, useVenueEvent, useVenueEvents, useVenueMarketMidpoints, useVenueMarkets, useViewportMidpoints, useVisibleIds, userActivityQueryKeys };
5583
+ export { AUTH_CHOOSER_OPEN_EVENT, type AggAuthContextValue, type AggAuthSignInOptions, type AggBalanceContextValue, AggBalanceProvider, AggProvider, type AggProviderProps, AggProvider as AggSdkProvider, type AggProviderProps as AggSdkProviderProps, type AggUiConfig, type AggUiConfigInput, type AggUiLabels, type AggUiLabelsInput, AggUiProvider, type AggUiTradingExecutionMode, CHART_TIME_RANGES, CONFIRMED_MATCH_STATUSES, type ChartTimeRange, type ClosedPositionTotals, type ComputePriceGapsOptions, DEFAULT_AGG_ROOT_CLASS_NAME, type DagStepProgress, type EventListStateContextValue, EventListStateProvider, type EventListStateSnapshot, type EventTradingContextValue, type EventTradingState, type ExecutionProgressPhase, type ExecutionTerminalOrderEvent, type GeoBlockState, type GetOrdersQuery, type GetPositionsQuery, type InvalidateUserActivityOptions, type InvalidateUserMoneyStateOptions, type LiveBestPriceCandidate, type LiveBestPriceCandidates, type LiveBestPrices, type LiveCandle, MAX_PRICE_GAP_PCT, MIN_PRICE_GAP_PCT, type MarketChartCandle, type MarketChartData, type MarketChartVenueData, type MarketOrderbookData, type MarketOrderbookIntegrity, MarketStatus, type MarketTradingState, MatchStatus, MatchType, type OrderEligibility, type OrderEligibilityReason, type OrderListItem, type OrderbookResult, type PositionGroup, type PriceGapValue, type RedeemEvent, type RedeemLegLifecycle, type RedeemLifecycleState, RedeemRejectedError, type RollingChartWindow, type ScaledCandlePoint, type SdkUiConfig, type SdkUiConfigInput, type SdkUiProviderProps, type SmartRouteLoadingReason, type ThemeMode, TradeSide, type TradingAction, type TradingState, type TradingStateBase, type TradingStateKind, type UseAggAuthOptions, type UseAggAuthReturn, type UseAppConfigResult, type UseArbFeedResult, type UseCategoriesOptions, type UseCategoryChildrenOptions, type UseEnrichedVenueEventOptions, type UseExecuteManagedOptions, type UseExecutionOrdersOptions, type UseExecutionPositionsOptions, type UseExecutionProgressOptions, type UseExecutionProgressResult, type UseExternalIdOptions, type UseExternalIdReturn, type UseLinkAccountReturn, type UseLiveCandleOverlayOptions, type UseLiveCandleOverlayResult, type UseLiveCandlesOptions, type UseLiveCandlesResult, type UseLiveMarketResult, type UseMarketArbResult, type UseMarketChartOptions, type UseMarketChartResult, type UseMarketOrderbookOptions, type UseMarketOrderbookResult, type UseMarketOrderbookVenueOutcome, type UseMarketSearchOptions, type UseMidpointsOptions, type UseMidpointsResult, type UseOrderBookOptions, type UseOrderbookQuoteOptions, type UseOrderbookQuoteResult, type UseOrdersOptions, type UsePositionsOptions, type UseQuoteManagedOptions, type UseRedeemLifecycleInput, type UseRollingChartWindowOptions, type UseSearchOptions, type UseSmartRouteOptions, type UseSmartRouteResult, type UseTradableVenuesResult, type UseUserActivityOptions, type UseUserHoldingsOptions, type UseVenueEventOptions, type UseVenueEventsOptions, type UseVenueMarketMidpointsOptions, type UseVenueMarketsOptions, type UseViewportMidpointsOptions, type UseVisibleIdsOptions, type UseVisibleIdsResult, type UserActivityInvalidationStrategy, Venue, type VenueAvailabilityState, type VenueEvent, type VenueEventWithMarkets, type VenueMarket, type VenueMarketOutcome, type WalletActionSendTokenParams, type WalletActions, buildLiveBestPriceCandidates, computeClosedPositionTotals, computePriceGaps, defaultAggUiConfig, defaultAggUiConfig as defaultSdkUiConfig, executionKeys, extractOutcomeBestCandidate, findLivePriceById, getBuilder, getOrCreateBuilder, getVenueAvailabilityState, getVisibleVenueIdsByConfig, getVisibleVenuesByConfig, getWalletAddressFromUserProfile, invalidateBalanceQueries, invalidatePositionQueries, invalidateUserActivityQueries, invalidateUserClaimState, invalidateUserMoneyState, isVenueDisabledByConfig, mergeBestPricesPreferringLive, normalizeVenueId, optimizedImageUrl, parseEmail, parseEmailStrict, rangeToSeconds, requestAggAuthChooserOpen, resolveAggUiLabels, resolveDefaultMarket as resolveDefaultTradingMarket, resolveEventTradingState, resolveMarketTradingState, resolveMarketWinningOutcome, resolveOrderEligibility, resolveRollingWindow, resolveTradingStateKind, sortVenues, timeRangeToInterval, tradingReducer, useAggAuth, useAggAuthContext, useAggAuthState, useAggBalance, useAggBalanceContext, useAggBalanceState, useAggClient, useAggLabels, useAggUiConfig, useAggWebSocket, useAppConfig, useArbFeed, useCachedAppConfig, useCategories, useCategoryChildren, useDebouncedValue, useEnrichedVenueEvent, useEventListState, useEventOrderbookData, useEventTradingContext, useExecuteManaged, useExecutionOrders, useExecutionPositions, useExecutionProgress, useExternalId, useGeoBlock, useLabels, useLinkAccount, useLiveBestPriceCandidates, useLiveBestPrices, useLiveCandleOverlay, useLiveCandles, useLiveMarket, useLiveMarketStores, useLiveOutcomePrices, useLiveTrades, useMarketArb, useMarketChart, useMarketOrderbook, useMarketSearch, useMidpoints, useOnBalanceUpdate, useOnOrderEvent, useOnOrderSubmitted, useOnRedeemEvent, useOnWithdrawalLifecycle, useOptionalAggClient, useOrderBook, useOrderbookQuote, useOrders, usePositions, useQuoteManaged, useRampQuotes, useRampSession, useRedeem, useRedeemEligibleCount, useRedeemLifecycle, useRedeemLifecycles, useRollingChartWindow, useSdkLabels, useSdkUiConfig, useSearch, useSmartRoute, useTradableVenues, useUserActivity, useUserHoldings, useVenueEvent, useVenueEvents, useVenueMarketMidpoints, useVenueMarkets, useViewportMidpoints, useVisibleIds, userActivityQueryKeys };
package/dist/index.d.ts CHANGED
@@ -271,6 +271,12 @@ type VenueMarket = {
271
271
  sportsMarketType?: string | null | undefined;
272
272
  /** Sort rank within a sports section (0=moneyline, 1=spread, 2=total, 3+=other). */
273
273
  sectionRank?: number | null | undefined;
274
+ /** Period identifier for sports markets (e.g., "1H", "2H", "Q1", etc.). */
275
+ period?: string | null | undefined;
276
+ /** Normalized subject category for prop-tab grouping (e.g., game_lines, exact_score, etc.). */
277
+ marketCategory?: string | null | undefined;
278
+ /** Line value for spread/total markets (e.g., 2.5 for totals, 3 for spreads). */
279
+ lineValue?: number | null | undefined;
274
280
  matchedVenueMarkets?: {
275
281
  id: string;
276
282
  venue: Venue;
@@ -324,10 +330,18 @@ type VenueEvent = {
324
330
  startDate?: string | null | undefined;
325
331
  endDate?: string | null | undefined;
326
332
  creationDate?: string | null | undefined;
333
+ /**
334
+ * Scheduled kickoff/start of the underlying game (sports events only).
335
+ * Distinct from `endDate` (market close/expiration), which can sit well
336
+ * after the game. The FE prefers this over `endDate` for the game-date
337
+ * title suffix. Null for non-sports events.
338
+ */
339
+ gameStartTime?: string | null | undefined;
327
340
  slug?: string | null | undefined;
328
341
  subtitle?: string | null | undefined;
329
342
  venues?: Venue[];
330
343
  venueCount?: number | undefined;
344
+ groupMarketCount?: number | undefined;
331
345
  marketCount?: number | undefined;
332
346
  /**
333
347
  * ISO-8601 duration denormalized from Series.recurrence. `null` means
@@ -1087,6 +1101,7 @@ interface AggUiLabels {
1087
1101
  orderSkip: string;
1088
1102
  orderRetryRemaining: string;
1089
1103
  resolvedEarningsTitle: string;
1104
+ resolvedResolutionDateLabel: string;
1090
1105
  resolvedSharesLabel: string;
1091
1106
  resolvedTotalPayoutLabel: string;
1092
1107
  claimWinnings: string;
@@ -3350,10 +3365,42 @@ declare function useLiveOutcomePrices(venueMarkets: VenueMarket[] | null | undef
3350
3365
  */
3351
3366
  declare function findLivePriceById(livePrices: Map<string, number>, id: string): number | undefined;
3352
3367
 
3368
+ interface MarketLiveState {
3369
+ marketId: string;
3370
+ orderbook: OrderbookState | null;
3371
+ orderbookSnapshotVersion: number;
3372
+ orderbookError: string | null;
3373
+ trades: WsTrade[];
3374
+ isConnected: boolean;
3375
+ integrity: "ok" | "resyncing";
3376
+ }
3377
+
3353
3378
  type LiveBestPrices = ReadonlyMap<string, {
3354
3379
  bestBid?: number;
3355
3380
  bestAsk?: number;
3356
3381
  }>;
3382
+ /**
3383
+ * A WS-derived best-price candidate for one outcome, carrying the venue that
3384
+ * produced each side *and* a freshness stamp. This is the richer companion to
3385
+ * {@link LiveBestPrices}: it keeps the venue attribution that the bare
3386
+ * `{ bestBid, bestAsk }` map throws away, so display surfaces can switch the
3387
+ * venue logo to whichever venue currently owns the best live price — keeping
3388
+ * the logo paired with the price instead of pinned to the REST snapshot.
3389
+ */
3390
+ interface LiveBestPriceCandidate {
3391
+ bestBid?: number;
3392
+ bestAsk?: number;
3393
+ /** Venue that owns the cross-venue best bid (best place to sell). */
3394
+ bestBidVenue?: string;
3395
+ /** Venue that owns the cross-venue best ask (cheapest place to buy). */
3396
+ bestAskVenue?: string;
3397
+ midpoint?: number;
3398
+ /** Venue the midpoint is attributed to (cheapest-ask side, then best-bid). */
3399
+ midpointVenue?: string;
3400
+ /** Orderbook timestamp (seconds) of the freshest book backing this candidate. */
3401
+ updatedAt?: number;
3402
+ }
3403
+ type LiveBestPriceCandidates = ReadonlyMap<string, LiveBestPriceCandidate>;
3357
3404
  /**
3358
3405
  * WS-derived cross-venue + cross-outcome best bid/ask per outcome.
3359
3406
  *
@@ -3381,6 +3428,35 @@ declare function mergeBestPricesPreferringLive(rest: ReadonlyMap<string, {
3381
3428
  bestBid?: number;
3382
3429
  bestAsk?: number;
3383
3430
  }>;
3431
+ /**
3432
+ * Pull the per-outcome best bid/ask, attributed venues, midpoint and freshness
3433
+ * out of a single live orderbook state. Pure — exported for unit tests.
3434
+ */
3435
+ declare const extractOutcomeBestCandidate: (state: MarketLiveState | undefined) => LiveBestPriceCandidate;
3436
+ /**
3437
+ * Cross-venue + cross-outcome venue-attributed best-price candidates.
3438
+ *
3439
+ * Pure (no React) so the cross-venue fold can be unit-tested directly:
3440
+ * - Pass 1: per-outcome candidate from each outcome's own aggregated book.
3441
+ * - Pass 2: fold across MVMO groups. Lowest ask wins (cheapest to buy),
3442
+ * highest bid wins (best to sell), and the *winning venue* + freshest
3443
+ * timestamp travel with the chosen price to every member of the group.
3444
+ * This is what lets a different venue's live book switch both the price
3445
+ * and the venue logo on every WS update.
3446
+ *
3447
+ * Mirrors the price fold in {@link useLiveBestPrices} and the REST fold in
3448
+ * `useMidpoints.extractBestPrices`, but additionally tracks venue + freshness.
3449
+ */
3450
+ declare function buildLiveBestPriceCandidates(outcomeIds: string[], states: Array<MarketLiveState | undefined>, venueMarkets: VenueMarket[] | null | undefined): Map<string, LiveBestPriceCandidate>;
3451
+ /**
3452
+ * React hook companion to {@link useLiveBestPrices} that additionally carries
3453
+ * venue attribution + freshness per outcome. Recomputes on every WS update
3454
+ * (snapshot/delta) that moves price, venue ownership, or timestamp.
3455
+ *
3456
+ * Empty until WS books land for the subscribed outcomes. Designed to feed a
3457
+ * unified price+venue selector so the venue logo always follows the live price.
3458
+ */
3459
+ declare function useLiveBestPriceCandidates(venueMarkets: VenueMarket[] | null | undefined): LiveBestPriceCandidates;
3384
3460
 
3385
3461
  /**
3386
3462
  * Subscribe to real-time trade feed for a canonical market.
@@ -5504,4 +5580,4 @@ declare function useAppConfig(): UseAppConfigResult;
5504
5580
  */
5505
5581
  declare function useCachedAppConfig(): UseAppConfigResult;
5506
5582
 
5507
- export { AUTH_CHOOSER_OPEN_EVENT, type AggAuthContextValue, type AggAuthSignInOptions, type AggBalanceContextValue, AggBalanceProvider, AggProvider, type AggProviderProps, AggProvider as AggSdkProvider, type AggProviderProps as AggSdkProviderProps, type AggUiConfig, type AggUiConfigInput, type AggUiLabels, type AggUiLabelsInput, AggUiProvider, type AggUiTradingExecutionMode, CHART_TIME_RANGES, CONFIRMED_MATCH_STATUSES, type ChartTimeRange, type ClosedPositionTotals, type ComputePriceGapsOptions, DEFAULT_AGG_ROOT_CLASS_NAME, type DagStepProgress, type EventListStateContextValue, EventListStateProvider, type EventListStateSnapshot, type EventTradingContextValue, type EventTradingState, type ExecutionProgressPhase, type ExecutionTerminalOrderEvent, type GeoBlockState, type GetOrdersQuery, type GetPositionsQuery, type InvalidateUserActivityOptions, type InvalidateUserMoneyStateOptions, type LiveBestPrices, type LiveCandle, MAX_PRICE_GAP_PCT, MIN_PRICE_GAP_PCT, type MarketChartCandle, type MarketChartData, type MarketChartVenueData, type MarketOrderbookData, type MarketOrderbookIntegrity, MarketStatus, type MarketTradingState, MatchStatus, MatchType, type OrderEligibility, type OrderEligibilityReason, type OrderListItem, type OrderbookResult, type PositionGroup, type PriceGapValue, type RedeemEvent, type RedeemLegLifecycle, type RedeemLifecycleState, RedeemRejectedError, type RollingChartWindow, type ScaledCandlePoint, type SdkUiConfig, type SdkUiConfigInput, type SdkUiProviderProps, type SmartRouteLoadingReason, type ThemeMode, TradeSide, type TradingAction, type TradingState, type TradingStateBase, type TradingStateKind, type UseAggAuthOptions, type UseAggAuthReturn, type UseAppConfigResult, type UseArbFeedResult, type UseCategoriesOptions, type UseCategoryChildrenOptions, type UseEnrichedVenueEventOptions, type UseExecuteManagedOptions, type UseExecutionOrdersOptions, type UseExecutionPositionsOptions, type UseExecutionProgressOptions, type UseExecutionProgressResult, type UseExternalIdOptions, type UseExternalIdReturn, type UseLinkAccountReturn, type UseLiveCandleOverlayOptions, type UseLiveCandleOverlayResult, type UseLiveCandlesOptions, type UseLiveCandlesResult, type UseLiveMarketResult, type UseMarketArbResult, type UseMarketChartOptions, type UseMarketChartResult, type UseMarketOrderbookOptions, type UseMarketOrderbookResult, type UseMarketOrderbookVenueOutcome, type UseMarketSearchOptions, type UseMidpointsOptions, type UseMidpointsResult, type UseOrderBookOptions, type UseOrderbookQuoteOptions, type UseOrderbookQuoteResult, type UseOrdersOptions, type UsePositionsOptions, type UseQuoteManagedOptions, type UseRedeemLifecycleInput, type UseRollingChartWindowOptions, type UseSearchOptions, type UseSmartRouteOptions, type UseSmartRouteResult, type UseTradableVenuesResult, type UseUserActivityOptions, type UseUserHoldingsOptions, type UseVenueEventOptions, type UseVenueEventsOptions, type UseVenueMarketMidpointsOptions, type UseVenueMarketsOptions, type UseViewportMidpointsOptions, type UseVisibleIdsOptions, type UseVisibleIdsResult, type UserActivityInvalidationStrategy, Venue, type VenueAvailabilityState, type VenueEvent, type VenueEventWithMarkets, type VenueMarket, type VenueMarketOutcome, type WalletActionSendTokenParams, type WalletActions, computeClosedPositionTotals, computePriceGaps, defaultAggUiConfig, defaultAggUiConfig as defaultSdkUiConfig, executionKeys, findLivePriceById, getBuilder, getOrCreateBuilder, getVenueAvailabilityState, getVisibleVenueIdsByConfig, getVisibleVenuesByConfig, getWalletAddressFromUserProfile, invalidateBalanceQueries, invalidatePositionQueries, invalidateUserActivityQueries, invalidateUserClaimState, invalidateUserMoneyState, isVenueDisabledByConfig, mergeBestPricesPreferringLive, normalizeVenueId, optimizedImageUrl, parseEmail, parseEmailStrict, rangeToSeconds, requestAggAuthChooserOpen, resolveAggUiLabels, resolveDefaultMarket as resolveDefaultTradingMarket, resolveEventTradingState, resolveMarketTradingState, resolveMarketWinningOutcome, resolveOrderEligibility, resolveRollingWindow, resolveTradingStateKind, sortVenues, timeRangeToInterval, tradingReducer, useAggAuth, useAggAuthContext, useAggAuthState, useAggBalance, useAggBalanceContext, useAggBalanceState, useAggClient, useAggLabels, useAggUiConfig, useAggWebSocket, useAppConfig, useArbFeed, useCachedAppConfig, useCategories, useCategoryChildren, useDebouncedValue, useEnrichedVenueEvent, useEventListState, useEventOrderbookData, useEventTradingContext, useExecuteManaged, useExecutionOrders, useExecutionPositions, useExecutionProgress, useExternalId, useGeoBlock, useLabels, useLinkAccount, useLiveBestPrices, useLiveCandleOverlay, useLiveCandles, useLiveMarket, useLiveMarketStores, useLiveOutcomePrices, useLiveTrades, useMarketArb, useMarketChart, useMarketOrderbook, useMarketSearch, useMidpoints, useOnBalanceUpdate, useOnOrderEvent, useOnOrderSubmitted, useOnRedeemEvent, useOnWithdrawalLifecycle, useOptionalAggClient, useOrderBook, useOrderbookQuote, useOrders, usePositions, useQuoteManaged, useRampQuotes, useRampSession, useRedeem, useRedeemEligibleCount, useRedeemLifecycle, useRedeemLifecycles, useRollingChartWindow, useSdkLabels, useSdkUiConfig, useSearch, useSmartRoute, useTradableVenues, useUserActivity, useUserHoldings, useVenueEvent, useVenueEvents, useVenueMarketMidpoints, useVenueMarkets, useViewportMidpoints, useVisibleIds, userActivityQueryKeys };
5583
+ export { AUTH_CHOOSER_OPEN_EVENT, type AggAuthContextValue, type AggAuthSignInOptions, type AggBalanceContextValue, AggBalanceProvider, AggProvider, type AggProviderProps, AggProvider as AggSdkProvider, type AggProviderProps as AggSdkProviderProps, type AggUiConfig, type AggUiConfigInput, type AggUiLabels, type AggUiLabelsInput, AggUiProvider, type AggUiTradingExecutionMode, CHART_TIME_RANGES, CONFIRMED_MATCH_STATUSES, type ChartTimeRange, type ClosedPositionTotals, type ComputePriceGapsOptions, DEFAULT_AGG_ROOT_CLASS_NAME, type DagStepProgress, type EventListStateContextValue, EventListStateProvider, type EventListStateSnapshot, type EventTradingContextValue, type EventTradingState, type ExecutionProgressPhase, type ExecutionTerminalOrderEvent, type GeoBlockState, type GetOrdersQuery, type GetPositionsQuery, type InvalidateUserActivityOptions, type InvalidateUserMoneyStateOptions, type LiveBestPriceCandidate, type LiveBestPriceCandidates, type LiveBestPrices, type LiveCandle, MAX_PRICE_GAP_PCT, MIN_PRICE_GAP_PCT, type MarketChartCandle, type MarketChartData, type MarketChartVenueData, type MarketOrderbookData, type MarketOrderbookIntegrity, MarketStatus, type MarketTradingState, MatchStatus, MatchType, type OrderEligibility, type OrderEligibilityReason, type OrderListItem, type OrderbookResult, type PositionGroup, type PriceGapValue, type RedeemEvent, type RedeemLegLifecycle, type RedeemLifecycleState, RedeemRejectedError, type RollingChartWindow, type ScaledCandlePoint, type SdkUiConfig, type SdkUiConfigInput, type SdkUiProviderProps, type SmartRouteLoadingReason, type ThemeMode, TradeSide, type TradingAction, type TradingState, type TradingStateBase, type TradingStateKind, type UseAggAuthOptions, type UseAggAuthReturn, type UseAppConfigResult, type UseArbFeedResult, type UseCategoriesOptions, type UseCategoryChildrenOptions, type UseEnrichedVenueEventOptions, type UseExecuteManagedOptions, type UseExecutionOrdersOptions, type UseExecutionPositionsOptions, type UseExecutionProgressOptions, type UseExecutionProgressResult, type UseExternalIdOptions, type UseExternalIdReturn, type UseLinkAccountReturn, type UseLiveCandleOverlayOptions, type UseLiveCandleOverlayResult, type UseLiveCandlesOptions, type UseLiveCandlesResult, type UseLiveMarketResult, type UseMarketArbResult, type UseMarketChartOptions, type UseMarketChartResult, type UseMarketOrderbookOptions, type UseMarketOrderbookResult, type UseMarketOrderbookVenueOutcome, type UseMarketSearchOptions, type UseMidpointsOptions, type UseMidpointsResult, type UseOrderBookOptions, type UseOrderbookQuoteOptions, type UseOrderbookQuoteResult, type UseOrdersOptions, type UsePositionsOptions, type UseQuoteManagedOptions, type UseRedeemLifecycleInput, type UseRollingChartWindowOptions, type UseSearchOptions, type UseSmartRouteOptions, type UseSmartRouteResult, type UseTradableVenuesResult, type UseUserActivityOptions, type UseUserHoldingsOptions, type UseVenueEventOptions, type UseVenueEventsOptions, type UseVenueMarketMidpointsOptions, type UseVenueMarketsOptions, type UseViewportMidpointsOptions, type UseVisibleIdsOptions, type UseVisibleIdsResult, type UserActivityInvalidationStrategy, Venue, type VenueAvailabilityState, type VenueEvent, type VenueEventWithMarkets, type VenueMarket, type VenueMarketOutcome, type WalletActionSendTokenParams, type WalletActions, buildLiveBestPriceCandidates, computeClosedPositionTotals, computePriceGaps, defaultAggUiConfig, defaultAggUiConfig as defaultSdkUiConfig, executionKeys, extractOutcomeBestCandidate, findLivePriceById, getBuilder, getOrCreateBuilder, getVenueAvailabilityState, getVisibleVenueIdsByConfig, getVisibleVenuesByConfig, getWalletAddressFromUserProfile, invalidateBalanceQueries, invalidatePositionQueries, invalidateUserActivityQueries, invalidateUserClaimState, invalidateUserMoneyState, isVenueDisabledByConfig, mergeBestPricesPreferringLive, normalizeVenueId, optimizedImageUrl, parseEmail, parseEmailStrict, rangeToSeconds, requestAggAuthChooserOpen, resolveAggUiLabels, resolveDefaultMarket as resolveDefaultTradingMarket, resolveEventTradingState, resolveMarketTradingState, resolveMarketWinningOutcome, resolveOrderEligibility, resolveRollingWindow, resolveTradingStateKind, sortVenues, timeRangeToInterval, tradingReducer, useAggAuth, useAggAuthContext, useAggAuthState, useAggBalance, useAggBalanceContext, useAggBalanceState, useAggClient, useAggLabels, useAggUiConfig, useAggWebSocket, useAppConfig, useArbFeed, useCachedAppConfig, useCategories, useCategoryChildren, useDebouncedValue, useEnrichedVenueEvent, useEventListState, useEventOrderbookData, useEventTradingContext, useExecuteManaged, useExecutionOrders, useExecutionPositions, useExecutionProgress, useExternalId, useGeoBlock, useLabels, useLinkAccount, useLiveBestPriceCandidates, useLiveBestPrices, useLiveCandleOverlay, useLiveCandles, useLiveMarket, useLiveMarketStores, useLiveOutcomePrices, useLiveTrades, useMarketArb, useMarketChart, useMarketOrderbook, useMarketSearch, useMidpoints, useOnBalanceUpdate, useOnOrderEvent, useOnOrderSubmitted, useOnRedeemEvent, useOnWithdrawalLifecycle, useOptionalAggClient, useOrderBook, useOrderbookQuote, useOrders, usePositions, useQuoteManaged, useRampQuotes, useRampSession, useRedeem, useRedeemEligibleCount, useRedeemLifecycle, useRedeemLifecycles, useRollingChartWindow, useSdkLabels, useSdkUiConfig, useSearch, useSmartRoute, useTradableVenues, useUserActivity, useUserHoldings, useVenueEvent, useVenueEvents, useVenueMarketMidpoints, useVenueMarkets, useViewportMidpoints, useVisibleIds, userActivityQueryKeys };
package/dist/index.js CHANGED
@@ -90,11 +90,13 @@ __export(src_exports, {
90
90
  TradeSide: () => TradeSide,
91
91
  TurnstileChallengeError: () => import_sdk4.TurnstileChallengeError,
92
92
  Venue: () => Venue,
93
+ buildLiveBestPriceCandidates: () => buildLiveBestPriceCandidates,
93
94
  computeClosedPositionTotals: () => computeClosedPositionTotals,
94
95
  computePriceGaps: () => computePriceGaps,
95
96
  defaultAggUiConfig: () => defaultAggUiConfig,
96
97
  defaultSdkUiConfig: () => defaultAggUiConfig,
97
98
  executionKeys: () => executionKeys,
99
+ extractOutcomeBestCandidate: () => extractOutcomeBestCandidate,
98
100
  findLivePriceById: () => findLivePriceById,
99
101
  getBuilder: () => getBuilder,
100
102
  getDepositAddress: () => getDepositAddress,
@@ -156,6 +158,7 @@ __export(src_exports, {
156
158
  useGeoBlock: () => useGeoBlock,
157
159
  useLabels: () => useLabels,
158
160
  useLinkAccount: () => useLinkAccount,
161
+ useLiveBestPriceCandidates: () => useLiveBestPriceCandidates,
159
162
  useLiveBestPrices: () => useLiveBestPrices,
160
163
  useLiveCandleOverlay: () => useLiveCandleOverlay,
161
164
  useLiveCandles: () => useLiveCandles,
@@ -1155,6 +1158,7 @@ var enUsLabels = {
1155
1158
  orderSkip: "Skip",
1156
1159
  orderRetryRemaining: "Retry remaining",
1157
1160
  resolvedEarningsTitle: "Your Earnings",
1161
+ resolvedResolutionDateLabel: "Resolution date",
1158
1162
  resolvedSharesLabel: "Shares",
1159
1163
  resolvedTotalPayoutLabel: "Total payout",
1160
1164
  claimWinnings: "Claim Winnings",
@@ -2519,6 +2523,98 @@ var applyOrderbookDepth = (data, depth) => {
2519
2523
  });
2520
2524
  };
2521
2525
 
2526
+ // src/market-data/market-resolution-cache.ts
2527
+ var isRecord = (value) => {
2528
+ return typeof value === "object" && value !== null;
2529
+ };
2530
+ var NESTED_COLLECTION_FIELDS = ["pages", "data", "markets", "events", "venueMarkets"];
2531
+ var marketContainsOutcomeId = (market, outcomeId) => {
2532
+ if (!isRecord(market)) return false;
2533
+ const outcomes = market.venueMarketOutcomes;
2534
+ if (!Array.isArray(outcomes)) return false;
2535
+ return outcomes.some((outcome) => isRecord(outcome) && outcome.id === outcomeId);
2536
+ };
2537
+ var cachedDataContainsOutcomeId = (data, outcomeId) => {
2538
+ if (Array.isArray(data)) {
2539
+ return data.some((entry) => cachedDataContainsOutcomeId(entry, outcomeId));
2540
+ }
2541
+ if (!isRecord(data)) return false;
2542
+ if (marketContainsOutcomeId(data, outcomeId)) return true;
2543
+ return NESTED_COLLECTION_FIELDS.some((field) => {
2544
+ const value = data[field];
2545
+ return Array.isArray(value) && value.some((entry) => cachedDataContainsOutcomeId(entry, outcomeId));
2546
+ });
2547
+ };
2548
+ var normalizeLabel = (label) => {
2549
+ return typeof label === "string" ? label.trim().toLowerCase() : "";
2550
+ };
2551
+ var findResolvedOutcome = (resolvedOutcomes, outcome) => {
2552
+ var _a;
2553
+ const externalIdentifier = outcome.externalIdentifier;
2554
+ if (typeof externalIdentifier === "string" && externalIdentifier.length > 0) {
2555
+ const matchedByExternalId = resolvedOutcomes.find(
2556
+ (resolved) => resolved.externalIdentifier === externalIdentifier
2557
+ );
2558
+ if (matchedByExternalId) return matchedByExternalId;
2559
+ }
2560
+ const label = normalizeLabel(outcome.label);
2561
+ if (label) {
2562
+ return (_a = resolvedOutcomes.find((resolved) => normalizeLabel(resolved.label) === label)) != null ? _a : null;
2563
+ }
2564
+ return null;
2565
+ };
2566
+ var applyWinnersToOutcomes = (outcomes, resolution) => {
2567
+ let changed = false;
2568
+ const next = outcomes.map((outcome) => {
2569
+ if (!isRecord(outcome)) return outcome;
2570
+ const resolved = findResolvedOutcome(resolution.outcomes, outcome);
2571
+ if (!resolved) return outcome;
2572
+ const nextWinner = resolved.winner === true;
2573
+ if (outcome.winner === nextWinner) return outcome;
2574
+ changed = true;
2575
+ return __spreadProps(__spreadValues({}, outcome), { winner: nextWinner });
2576
+ });
2577
+ return changed ? next : outcomes;
2578
+ };
2579
+ var applyResolutionToMarket = (market, resolution) => {
2580
+ const outcomes = market.venueMarketOutcomes;
2581
+ if (!Array.isArray(outcomes)) return market;
2582
+ if (!outcomes.some((outcome) => isRecord(outcome) && outcome.id === resolution.outcomeId)) {
2583
+ return market;
2584
+ }
2585
+ const nextOutcomes = applyWinnersToOutcomes(outcomes, resolution);
2586
+ const statusChanged = market.status !== resolution.status;
2587
+ if (!statusChanged && nextOutcomes === outcomes) return market;
2588
+ return __spreadProps(__spreadValues({}, market), { status: resolution.status, venueMarketOutcomes: nextOutcomes });
2589
+ };
2590
+ var applyResolutionToCachedData = (data, resolution) => {
2591
+ if (Array.isArray(data)) {
2592
+ let changed2 = false;
2593
+ const next2 = data.map((entry) => {
2594
+ const updated = applyResolutionToCachedData(entry, resolution);
2595
+ if (updated !== entry) changed2 = true;
2596
+ return updated;
2597
+ });
2598
+ return changed2 ? next2 : data;
2599
+ }
2600
+ if (!isRecord(data)) return data;
2601
+ if (Array.isArray(data.venueMarketOutcomes)) {
2602
+ return applyResolutionToMarket(data, resolution);
2603
+ }
2604
+ let changed = false;
2605
+ const next = __spreadValues({}, data);
2606
+ for (const field of NESTED_COLLECTION_FIELDS) {
2607
+ const value = data[field];
2608
+ if (!Array.isArray(value)) continue;
2609
+ const updated = applyResolutionToCachedData(value, resolution);
2610
+ if (updated !== value) {
2611
+ next[field] = updated;
2612
+ changed = true;
2613
+ }
2614
+ }
2615
+ return changed ? next : data;
2616
+ };
2617
+
2522
2618
  // src/market-data/query-keys.ts
2523
2619
  var marketDataKeys = {
2524
2620
  all: () => ["market-data"],
@@ -2786,6 +2882,62 @@ function AggWebSocketProvider({ children }) {
2786
2882
  const invalidateActivityCaches = (0, import_react6.useCallback)(() => {
2787
2883
  invalidateUserActivityQueries(queryClient);
2788
2884
  }, [queryClient]);
2885
+ const invalidateResolutionCaches = (0, import_react6.useCallback)(
2886
+ (resolution) => {
2887
+ const { outcomeId } = resolution;
2888
+ syncLiveQuery(outcomeId, (previous) => {
2889
+ if (!previous) return previous;
2890
+ if (previous.orderbook == null && previous.orderbookError == null) return previous;
2891
+ return __spreadProps(__spreadValues({}, previous), {
2892
+ orderbook: null,
2893
+ orderbookError: null,
2894
+ integrity: "ok"
2895
+ });
2896
+ });
2897
+ const affectedQueries = queryClient.getQueryCache().findAll({
2898
+ predicate: (query) => cachedDataContainsOutcomeId(query.state.data, outcomeId)
2899
+ });
2900
+ for (const query of affectedQueries) {
2901
+ queryClient.setQueryData(
2902
+ query.queryKey,
2903
+ (previous) => applyResolutionToCachedData(previous, resolution)
2904
+ );
2905
+ }
2906
+ queryClient.invalidateQueries({
2907
+ queryKey: ["midpoints"],
2908
+ refetchType: "all"
2909
+ });
2910
+ queryClient.invalidateQueries({
2911
+ queryKey: ["venue-market-midpoints"],
2912
+ refetchType: "all"
2913
+ });
2914
+ queryClient.invalidateQueries({
2915
+ queryKey: ["venue-event"],
2916
+ refetchType: "all"
2917
+ });
2918
+ queryClient.invalidateQueries({
2919
+ queryKey: ["venue-markets"],
2920
+ refetchType: "all"
2921
+ });
2922
+ queryClient.invalidateQueries({
2923
+ queryKey: ["events"],
2924
+ refetchType: "all"
2925
+ });
2926
+ queryClient.invalidateQueries({
2927
+ queryKey: ["event-list"],
2928
+ refetchType: "all"
2929
+ });
2930
+ queryClient.invalidateQueries({
2931
+ queryKey: ["search"],
2932
+ refetchType: "all"
2933
+ });
2934
+ queryClient.invalidateQueries({
2935
+ predicate: (query) => cachedDataContainsOutcomeId(query.state.data, outcomeId),
2936
+ refetchType: "all"
2937
+ });
2938
+ },
2939
+ [queryClient, syncLiveQuery]
2940
+ );
2789
2941
  const callbacks = (0, import_react6.useMemo)(
2790
2942
  () => ({
2791
2943
  onSnapshot: (marketId, book) => {
@@ -2934,6 +3086,14 @@ function AggWebSocketProvider({ children }) {
2934
3086
  listener(msg);
2935
3087
  }
2936
3088
  },
3089
+ onMarketResolved: (msg) => {
3090
+ invalidateResolutionCaches(msg);
3091
+ if (isClientAuthenticated) {
3092
+ invalidateBalanceCaches();
3093
+ invalidatePositionCaches();
3094
+ invalidateActivityCaches();
3095
+ }
3096
+ },
2937
3097
  onError: (msg) => {
2938
3098
  const outcomeId = resolveSnapshotUnavailableOutcomeId(msg.message);
2939
3099
  if (!outcomeId) return;
@@ -2971,6 +3131,7 @@ function AggWebSocketProvider({ children }) {
2971
3131
  invalidateActivityCaches,
2972
3132
  invalidateBalanceCaches,
2973
3133
  invalidatePositionCaches,
3134
+ invalidateResolutionCaches,
2974
3135
  isClientAuthenticated,
2975
3136
  queryClient,
2976
3137
  syncChartQueries,
@@ -5806,6 +5967,7 @@ function findLivePriceById(livePrices, id) {
5806
5967
  var import_react27 = require("react");
5807
5968
  var import_react_query25 = require("@tanstack/react-query");
5808
5969
  var EMPTY = /* @__PURE__ */ new Map();
5970
+ var EMPTY_CANDIDATES = /* @__PURE__ */ new Map();
5809
5971
  var extractOutcomeBestPrices = (state) => {
5810
5972
  var _a, _b;
5811
5973
  const ob = state == null ? void 0 : state.orderbook;
@@ -5923,6 +6085,175 @@ function mergeBestPricesPreferringLive(rest, live) {
5923
6085
  }
5924
6086
  return merged;
5925
6087
  }
6088
+ var pickSideVenue = (venues, level, side) => {
6089
+ if (venues) {
6090
+ let bestVenue;
6091
+ let bestValue;
6092
+ for (const [venue, info] of Object.entries(venues)) {
6093
+ const value = side === "bid" ? info.bestBid : info.bestAsk;
6094
+ if (value == null) continue;
6095
+ const wins = bestValue == null || (side === "bid" ? value > bestValue : value < bestValue);
6096
+ if (wins) {
6097
+ bestValue = value;
6098
+ bestVenue = venue;
6099
+ }
6100
+ }
6101
+ if (bestVenue != null) return bestVenue;
6102
+ }
6103
+ if (level == null ? void 0 : level.venues) {
6104
+ let bestVenue;
6105
+ let bestSize = -Infinity;
6106
+ for (const [venue, size] of Object.entries(level.venues)) {
6107
+ if (size > bestSize) {
6108
+ bestSize = size;
6109
+ bestVenue = venue;
6110
+ }
6111
+ }
6112
+ if (bestVenue != null) return bestVenue;
6113
+ }
6114
+ return void 0;
6115
+ };
6116
+ var extractOutcomeBestCandidate = (state) => {
6117
+ var _a;
6118
+ const ob = state == null ? void 0 : state.orderbook;
6119
+ if (!ob) return {};
6120
+ const candidate = {};
6121
+ const bidLevel = ob.bids[0];
6122
+ const askLevel = ob.asks[0];
6123
+ if ((bidLevel == null ? void 0 : bidLevel.price) != null) {
6124
+ candidate.bestBid = bidLevel.price;
6125
+ const venue = pickSideVenue(ob.venues, bidLevel, "bid");
6126
+ if (venue) candidate.bestBidVenue = venue;
6127
+ }
6128
+ if ((askLevel == null ? void 0 : askLevel.price) != null) {
6129
+ candidate.bestAsk = askLevel.price;
6130
+ const venue = pickSideVenue(ob.venues, askLevel, "ask");
6131
+ if (venue) candidate.bestAskVenue = venue;
6132
+ }
6133
+ if (ob.midpoint != null) {
6134
+ candidate.midpoint = ob.midpoint;
6135
+ const midVenue = (_a = candidate.bestAskVenue) != null ? _a : candidate.bestBidVenue;
6136
+ if (midVenue) candidate.midpointVenue = midVenue;
6137
+ }
6138
+ if (ob.timestamp != null) candidate.updatedAt = ob.timestamp;
6139
+ return candidate;
6140
+ };
6141
+ function buildLiveBestPriceCandidates(outcomeIds, states, venueMarkets) {
6142
+ var _a, _b, _c;
6143
+ const perOutcome = /* @__PURE__ */ new Map();
6144
+ for (let i = 0; i < outcomeIds.length; i++) {
6145
+ const candidate = extractOutcomeBestCandidate(states[i]);
6146
+ if (candidate.bestBid != null || candidate.bestAsk != null || candidate.midpoint != null) {
6147
+ perOutcome.set(outcomeIds[i], candidate);
6148
+ }
6149
+ }
6150
+ if (perOutcome.size === 0 || !(venueMarkets == null ? void 0 : venueMarkets.length)) {
6151
+ return perOutcome;
6152
+ }
6153
+ const result = new Map(perOutcome);
6154
+ for (const vm of venueMarkets) {
6155
+ for (const outcome of (_a = vm.venueMarketOutcomes) != null ? _a : []) {
6156
+ const refs = (_b = outcome.matchedVenueMarketOutcomes) != null ? _b : [];
6157
+ if (!refs.length) continue;
6158
+ const group = [outcome.id, ...refs.map((ref) => ref.venueMarketOutcomeId)];
6159
+ let groupBestAsk;
6160
+ let groupBestAskVenue;
6161
+ let groupBestBid;
6162
+ let groupBestBidVenue;
6163
+ let groupUpdatedAt;
6164
+ for (const id of group) {
6165
+ const entry = perOutcome.get(id);
6166
+ if (!entry) continue;
6167
+ if (entry.bestAsk != null && (groupBestAsk == null || entry.bestAsk < groupBestAsk)) {
6168
+ groupBestAsk = entry.bestAsk;
6169
+ groupBestAskVenue = entry.bestAskVenue;
6170
+ }
6171
+ if (entry.bestBid != null && (groupBestBid == null || entry.bestBid > groupBestBid)) {
6172
+ groupBestBid = entry.bestBid;
6173
+ groupBestBidVenue = entry.bestBidVenue;
6174
+ }
6175
+ if (entry.updatedAt != null && (groupUpdatedAt == null || entry.updatedAt > groupUpdatedAt)) {
6176
+ groupUpdatedAt = entry.updatedAt;
6177
+ }
6178
+ }
6179
+ if (groupBestAsk == null && groupBestBid == null) continue;
6180
+ for (const id of group) {
6181
+ const prev = (_c = result.get(id)) != null ? _c : {};
6182
+ const next = __spreadValues({}, prev);
6183
+ if (groupBestBid != null) {
6184
+ next.bestBid = groupBestBid;
6185
+ if (groupBestBidVenue) next.bestBidVenue = groupBestBidVenue;
6186
+ }
6187
+ if (groupBestAsk != null) {
6188
+ next.bestAsk = groupBestAsk;
6189
+ if (groupBestAskVenue) next.bestAskVenue = groupBestAskVenue;
6190
+ }
6191
+ if (groupUpdatedAt != null) next.updatedAt = groupUpdatedAt;
6192
+ result.set(id, next);
6193
+ }
6194
+ }
6195
+ }
6196
+ return result;
6197
+ }
6198
+ var buildCandidateFingerprint = (outcomeIds, queries) => {
6199
+ var _a, _b, _c, _d;
6200
+ const parts = [];
6201
+ for (let i = 0; i < outcomeIds.length; i++) {
6202
+ const ob = (_b = (_a = queries[i]) == null ? void 0 : _a.data) == null ? void 0 : _b.orderbook;
6203
+ const bid = (_c = ob == null ? void 0 : ob.bids[0]) == null ? void 0 : _c.price;
6204
+ const ask = (_d = ob == null ? void 0 : ob.asks[0]) == null ? void 0 : _d.price;
6205
+ const mid = ob == null ? void 0 : ob.midpoint;
6206
+ const ts = ob == null ? void 0 : ob.timestamp;
6207
+ const venues = (ob == null ? void 0 : ob.venues) ? Object.keys(ob.venues).sort().join(",") : "";
6208
+ parts.push(`${outcomeIds[i]}:${bid != null ? bid : "_"}:${ask != null ? ask : "_"}:${mid != null ? mid : "_"}:${ts != null ? ts : "_"}:${venues}`);
6209
+ }
6210
+ return parts.join("|");
6211
+ };
6212
+ function useLiveBestPriceCandidates(venueMarkets) {
6213
+ const {
6214
+ features: { enableLiveUpdates }
6215
+ } = useAggUiConfig();
6216
+ const outcomeIds = (0, import_react27.useMemo)(() => {
6217
+ var _a, _b;
6218
+ if (!(venueMarkets == null ? void 0 : venueMarkets.length)) return [];
6219
+ const ids = /* @__PURE__ */ new Set();
6220
+ for (const vm of venueMarkets) {
6221
+ for (const outcome of (_a = vm.venueMarketOutcomes) != null ? _a : []) {
6222
+ if (outcome.id) ids.add(outcome.id);
6223
+ for (const ref of (_b = outcome.matchedVenueMarketOutcomes) != null ? _b : []) {
6224
+ if (ref.venueMarketOutcomeId) ids.add(ref.venueMarketOutcomeId);
6225
+ }
6226
+ }
6227
+ }
6228
+ return [...ids].sort();
6229
+ }, [venueMarkets]);
6230
+ const queries = (0, import_react_query25.useQueries)({
6231
+ queries: outcomeIds.map((id) => ({
6232
+ queryKey: marketDataKeys.live(id),
6233
+ queryFn: () => createMarketLiveState(id),
6234
+ enabled: false,
6235
+ staleTime: Infinity,
6236
+ gcTime: 5 * 6e4,
6237
+ initialData: () => createMarketLiveState(id)
6238
+ }))
6239
+ });
6240
+ const fingerprint = buildCandidateFingerprint(outcomeIds, queries);
6241
+ const prevRef = (0, import_react27.useRef)({
6242
+ fingerprint: "",
6243
+ result: EMPTY_CANDIDATES
6244
+ });
6245
+ return (0, import_react27.useMemo)(() => {
6246
+ if (!(venueMarkets == null ? void 0 : venueMarkets.length) || !enableLiveUpdates) return EMPTY_CANDIDATES;
6247
+ if (fingerprint === prevRef.current.fingerprint) return prevRef.current.result;
6248
+ const states = outcomeIds.map((_, i) => {
6249
+ var _a;
6250
+ return (_a = queries[i]) == null ? void 0 : _a.data;
6251
+ });
6252
+ const result = buildLiveBestPriceCandidates(outcomeIds, states, venueMarkets);
6253
+ prevRef.current = { fingerprint, result };
6254
+ return result;
6255
+ }, [venueMarkets, enableLiveUpdates, fingerprint, outcomeIds, queries]);
6256
+ }
5926
6257
 
5927
6258
  // src/use-live-trades.ts
5928
6259
  function useLiveTrades(canonicalMarketId) {
@@ -7461,11 +7792,13 @@ var toAppConfigResult = (query) => {
7461
7792
  TradeSide,
7462
7793
  TurnstileChallengeError,
7463
7794
  Venue,
7795
+ buildLiveBestPriceCandidates,
7464
7796
  computeClosedPositionTotals,
7465
7797
  computePriceGaps,
7466
7798
  defaultAggUiConfig,
7467
7799
  defaultSdkUiConfig,
7468
7800
  executionKeys,
7801
+ extractOutcomeBestCandidate,
7469
7802
  findLivePriceById,
7470
7803
  getBuilder,
7471
7804
  getDepositAddress,
@@ -7527,6 +7860,7 @@ var toAppConfigResult = (query) => {
7527
7860
  useGeoBlock,
7528
7861
  useLabels,
7529
7862
  useLinkAccount,
7863
+ useLiveBestPriceCandidates,
7530
7864
  useLiveBestPrices,
7531
7865
  useLiveCandleOverlay,
7532
7866
  useLiveCandles,
package/dist/index.mjs CHANGED
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  useRampQuotes,
3
3
  useRampSession
4
- } from "./chunk-AFZD3GIQ.mjs";
4
+ } from "./chunk-5VDUIUJB.mjs";
5
5
  import {
6
6
  useWithdrawEstimate,
7
7
  useWithdrawFlow,
8
8
  useWithdrawPreview,
9
9
  useWithdrawalLifecycle
10
- } from "./chunk-5P53A3NQ.mjs";
10
+ } from "./chunk-FBYQBFFR.mjs";
11
11
  import {
12
12
  AggAuthContext,
13
13
  AggBalanceProvider,
@@ -95,7 +95,7 @@ import {
95
95
  useSyncBalances,
96
96
  useWithdrawManaged,
97
97
  userActivityQueryKeys
98
- } from "./chunk-FYEPQHKO.mjs";
98
+ } from "./chunk-7UDYSDKQ.mjs";
99
99
 
100
100
  // src/index.ts
101
101
  import { QueryClient as QueryClient4, QueryClientProvider, useQueryClient as useQueryClient3 } from "@tanstack/react-query";
@@ -1003,6 +1003,7 @@ function findLivePriceById(livePrices, id) {
1003
1003
  import { useMemo as useMemo7, useRef as useRef3 } from "react";
1004
1004
  import { useQueries as useQueries4 } from "@tanstack/react-query";
1005
1005
  var EMPTY = /* @__PURE__ */ new Map();
1006
+ var EMPTY_CANDIDATES = /* @__PURE__ */ new Map();
1006
1007
  var extractOutcomeBestPrices = (state) => {
1007
1008
  var _a, _b;
1008
1009
  const ob = state == null ? void 0 : state.orderbook;
@@ -1120,6 +1121,175 @@ function mergeBestPricesPreferringLive(rest, live) {
1120
1121
  }
1121
1122
  return merged;
1122
1123
  }
1124
+ var pickSideVenue = (venues, level, side) => {
1125
+ if (venues) {
1126
+ let bestVenue;
1127
+ let bestValue;
1128
+ for (const [venue, info] of Object.entries(venues)) {
1129
+ const value = side === "bid" ? info.bestBid : info.bestAsk;
1130
+ if (value == null) continue;
1131
+ const wins = bestValue == null || (side === "bid" ? value > bestValue : value < bestValue);
1132
+ if (wins) {
1133
+ bestValue = value;
1134
+ bestVenue = venue;
1135
+ }
1136
+ }
1137
+ if (bestVenue != null) return bestVenue;
1138
+ }
1139
+ if (level == null ? void 0 : level.venues) {
1140
+ let bestVenue;
1141
+ let bestSize = -Infinity;
1142
+ for (const [venue, size] of Object.entries(level.venues)) {
1143
+ if (size > bestSize) {
1144
+ bestSize = size;
1145
+ bestVenue = venue;
1146
+ }
1147
+ }
1148
+ if (bestVenue != null) return bestVenue;
1149
+ }
1150
+ return void 0;
1151
+ };
1152
+ var extractOutcomeBestCandidate = (state) => {
1153
+ var _a;
1154
+ const ob = state == null ? void 0 : state.orderbook;
1155
+ if (!ob) return {};
1156
+ const candidate = {};
1157
+ const bidLevel = ob.bids[0];
1158
+ const askLevel = ob.asks[0];
1159
+ if ((bidLevel == null ? void 0 : bidLevel.price) != null) {
1160
+ candidate.bestBid = bidLevel.price;
1161
+ const venue = pickSideVenue(ob.venues, bidLevel, "bid");
1162
+ if (venue) candidate.bestBidVenue = venue;
1163
+ }
1164
+ if ((askLevel == null ? void 0 : askLevel.price) != null) {
1165
+ candidate.bestAsk = askLevel.price;
1166
+ const venue = pickSideVenue(ob.venues, askLevel, "ask");
1167
+ if (venue) candidate.bestAskVenue = venue;
1168
+ }
1169
+ if (ob.midpoint != null) {
1170
+ candidate.midpoint = ob.midpoint;
1171
+ const midVenue = (_a = candidate.bestAskVenue) != null ? _a : candidate.bestBidVenue;
1172
+ if (midVenue) candidate.midpointVenue = midVenue;
1173
+ }
1174
+ if (ob.timestamp != null) candidate.updatedAt = ob.timestamp;
1175
+ return candidate;
1176
+ };
1177
+ function buildLiveBestPriceCandidates(outcomeIds, states, venueMarkets) {
1178
+ var _a, _b, _c;
1179
+ const perOutcome = /* @__PURE__ */ new Map();
1180
+ for (let i = 0; i < outcomeIds.length; i++) {
1181
+ const candidate = extractOutcomeBestCandidate(states[i]);
1182
+ if (candidate.bestBid != null || candidate.bestAsk != null || candidate.midpoint != null) {
1183
+ perOutcome.set(outcomeIds[i], candidate);
1184
+ }
1185
+ }
1186
+ if (perOutcome.size === 0 || !(venueMarkets == null ? void 0 : venueMarkets.length)) {
1187
+ return perOutcome;
1188
+ }
1189
+ const result = new Map(perOutcome);
1190
+ for (const vm of venueMarkets) {
1191
+ for (const outcome of (_a = vm.venueMarketOutcomes) != null ? _a : []) {
1192
+ const refs = (_b = outcome.matchedVenueMarketOutcomes) != null ? _b : [];
1193
+ if (!refs.length) continue;
1194
+ const group = [outcome.id, ...refs.map((ref) => ref.venueMarketOutcomeId)];
1195
+ let groupBestAsk;
1196
+ let groupBestAskVenue;
1197
+ let groupBestBid;
1198
+ let groupBestBidVenue;
1199
+ let groupUpdatedAt;
1200
+ for (const id of group) {
1201
+ const entry = perOutcome.get(id);
1202
+ if (!entry) continue;
1203
+ if (entry.bestAsk != null && (groupBestAsk == null || entry.bestAsk < groupBestAsk)) {
1204
+ groupBestAsk = entry.bestAsk;
1205
+ groupBestAskVenue = entry.bestAskVenue;
1206
+ }
1207
+ if (entry.bestBid != null && (groupBestBid == null || entry.bestBid > groupBestBid)) {
1208
+ groupBestBid = entry.bestBid;
1209
+ groupBestBidVenue = entry.bestBidVenue;
1210
+ }
1211
+ if (entry.updatedAt != null && (groupUpdatedAt == null || entry.updatedAt > groupUpdatedAt)) {
1212
+ groupUpdatedAt = entry.updatedAt;
1213
+ }
1214
+ }
1215
+ if (groupBestAsk == null && groupBestBid == null) continue;
1216
+ for (const id of group) {
1217
+ const prev = (_c = result.get(id)) != null ? _c : {};
1218
+ const next = __spreadValues({}, prev);
1219
+ if (groupBestBid != null) {
1220
+ next.bestBid = groupBestBid;
1221
+ if (groupBestBidVenue) next.bestBidVenue = groupBestBidVenue;
1222
+ }
1223
+ if (groupBestAsk != null) {
1224
+ next.bestAsk = groupBestAsk;
1225
+ if (groupBestAskVenue) next.bestAskVenue = groupBestAskVenue;
1226
+ }
1227
+ if (groupUpdatedAt != null) next.updatedAt = groupUpdatedAt;
1228
+ result.set(id, next);
1229
+ }
1230
+ }
1231
+ }
1232
+ return result;
1233
+ }
1234
+ var buildCandidateFingerprint = (outcomeIds, queries) => {
1235
+ var _a, _b, _c, _d;
1236
+ const parts = [];
1237
+ for (let i = 0; i < outcomeIds.length; i++) {
1238
+ const ob = (_b = (_a = queries[i]) == null ? void 0 : _a.data) == null ? void 0 : _b.orderbook;
1239
+ const bid = (_c = ob == null ? void 0 : ob.bids[0]) == null ? void 0 : _c.price;
1240
+ const ask = (_d = ob == null ? void 0 : ob.asks[0]) == null ? void 0 : _d.price;
1241
+ const mid = ob == null ? void 0 : ob.midpoint;
1242
+ const ts = ob == null ? void 0 : ob.timestamp;
1243
+ const venues = (ob == null ? void 0 : ob.venues) ? Object.keys(ob.venues).sort().join(",") : "";
1244
+ parts.push(`${outcomeIds[i]}:${bid != null ? bid : "_"}:${ask != null ? ask : "_"}:${mid != null ? mid : "_"}:${ts != null ? ts : "_"}:${venues}`);
1245
+ }
1246
+ return parts.join("|");
1247
+ };
1248
+ function useLiveBestPriceCandidates(venueMarkets) {
1249
+ const {
1250
+ features: { enableLiveUpdates }
1251
+ } = useAggUiConfig();
1252
+ const outcomeIds = useMemo7(() => {
1253
+ var _a, _b;
1254
+ if (!(venueMarkets == null ? void 0 : venueMarkets.length)) return [];
1255
+ const ids = /* @__PURE__ */ new Set();
1256
+ for (const vm of venueMarkets) {
1257
+ for (const outcome of (_a = vm.venueMarketOutcomes) != null ? _a : []) {
1258
+ if (outcome.id) ids.add(outcome.id);
1259
+ for (const ref of (_b = outcome.matchedVenueMarketOutcomes) != null ? _b : []) {
1260
+ if (ref.venueMarketOutcomeId) ids.add(ref.venueMarketOutcomeId);
1261
+ }
1262
+ }
1263
+ }
1264
+ return [...ids].sort();
1265
+ }, [venueMarkets]);
1266
+ const queries = useQueries4({
1267
+ queries: outcomeIds.map((id) => ({
1268
+ queryKey: marketDataKeys.live(id),
1269
+ queryFn: () => createMarketLiveState(id),
1270
+ enabled: false,
1271
+ staleTime: Infinity,
1272
+ gcTime: 5 * 6e4,
1273
+ initialData: () => createMarketLiveState(id)
1274
+ }))
1275
+ });
1276
+ const fingerprint = buildCandidateFingerprint(outcomeIds, queries);
1277
+ const prevRef = useRef3({
1278
+ fingerprint: "",
1279
+ result: EMPTY_CANDIDATES
1280
+ });
1281
+ return useMemo7(() => {
1282
+ if (!(venueMarkets == null ? void 0 : venueMarkets.length) || !enableLiveUpdates) return EMPTY_CANDIDATES;
1283
+ if (fingerprint === prevRef.current.fingerprint) return prevRef.current.result;
1284
+ const states = outcomeIds.map((_, i) => {
1285
+ var _a;
1286
+ return (_a = queries[i]) == null ? void 0 : _a.data;
1287
+ });
1288
+ const result = buildLiveBestPriceCandidates(outcomeIds, states, venueMarkets);
1289
+ prevRef.current = { fingerprint, result };
1290
+ return result;
1291
+ }, [venueMarkets, enableLiveUpdates, fingerprint, outcomeIds, queries]);
1292
+ }
1123
1293
 
1124
1294
  // src/use-live-trades.ts
1125
1295
  function useLiveTrades(canonicalMarketId) {
@@ -2667,11 +2837,13 @@ export {
2667
2837
  TradeSide,
2668
2838
  TurnstileChallengeError,
2669
2839
  Venue,
2840
+ buildLiveBestPriceCandidates,
2670
2841
  computeClosedPositionTotals,
2671
2842
  computePriceGaps,
2672
2843
  defaultAggUiConfig,
2673
2844
  defaultAggUiConfig as defaultSdkUiConfig,
2674
2845
  executionKeys,
2846
+ extractOutcomeBestCandidate,
2675
2847
  findLivePriceById,
2676
2848
  getBuilder,
2677
2849
  getDepositAddress,
@@ -2733,6 +2905,7 @@ export {
2733
2905
  useGeoBlock,
2734
2906
  useLabels,
2735
2907
  useLinkAccount,
2908
+ useLiveBestPriceCandidates,
2736
2909
  useLiveBestPrices,
2737
2910
  useLiveCandleOverlay,
2738
2911
  useLiveCandles,
package/dist/withdraw.js CHANGED
@@ -702,6 +702,7 @@ var enUsLabels = {
702
702
  orderSkip: "Skip",
703
703
  orderRetryRemaining: "Retry remaining",
704
704
  resolvedEarningsTitle: "Your Earnings",
705
+ resolvedResolutionDateLabel: "Resolution date",
705
706
  resolvedSharesLabel: "Shares",
706
707
  resolvedTotalPayoutLabel: "Total payout",
707
708
  claimWinnings: "Claim Winnings",
package/dist/withdraw.mjs CHANGED
@@ -3,12 +3,12 @@ import {
3
3
  useWithdrawFlow,
4
4
  useWithdrawPreview,
5
5
  useWithdrawalLifecycle
6
- } from "./chunk-5P53A3NQ.mjs";
6
+ } from "./chunk-FBYQBFFR.mjs";
7
7
  import {
8
8
  useDepositAddresses,
9
9
  useManagedBalances,
10
10
  useWithdrawManaged
11
- } from "./chunk-FYEPQHKO.mjs";
11
+ } from "./chunk-7UDYSDKQ.mjs";
12
12
  export {
13
13
  useDepositAddresses,
14
14
  useManagedBalances,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agg-build/hooks",
3
- "version": "2.1.1",
3
+ "version": "2.1.2",
4
4
  "description": "React hooks and providers for the AGG prediction market aggregator. Wraps @agg-build/sdk with TanStack Query, shared session state, and live WebSocket data.",
5
5
  "sideEffects": false,
6
6
  "license": "MIT",
@@ -83,7 +83,7 @@
83
83
  "react": "^18.0.0 || ^19.0.0",
84
84
  "viem": "^2.0.0",
85
85
  "wagmi": "^3.0.0 || ^2.0.0",
86
- "@agg-build/sdk": "^2.1.0"
86
+ "@agg-build/sdk": "^2.1.2"
87
87
  },
88
88
  "peerDependenciesMeta": {
89
89
  "@solana/wallet-adapter-react": {