@agg-build/hooks 4.0.1 → 4.5.0

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.
package/dist/index.mjs CHANGED
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  useRampQuotes,
3
3
  useRampSession
4
- } from "./chunk-BR6NZSXN.mjs";
4
+ } from "./chunk-O4RM4KKO.mjs";
5
5
  import {
6
6
  useWithdrawEstimate,
7
7
  useWithdrawFlow,
8
8
  useWithdrawPreview,
9
9
  useWithdrawalLifecycle
10
- } from "./chunk-AZYAQIZB.mjs";
10
+ } from "./chunk-IHMZHA2W.mjs";
11
11
  import {
12
12
  AggAuthContext,
13
13
  AggBalanceProvider,
@@ -97,7 +97,7 @@ import {
97
97
  useSyncBalances,
98
98
  useWithdrawManaged,
99
99
  userActivityQueryKeys
100
- } from "./chunk-SC6X5TL4.mjs";
100
+ } from "./chunk-LVOL27OZ.mjs";
101
101
 
102
102
  // src/index.ts
103
103
  import { QueryClient as QueryClient4, QueryClientProvider, useQueryClient as useQueryClient3 } from "@tanstack/react-query";
@@ -220,7 +220,7 @@ function useLinkAccount() {
220
220
  [client]
221
221
  );
222
222
  const confirmLink = useCallback2(
223
- (token) => run(() => client.linkAccountConfirm(token)),
223
+ (input) => run(() => client.linkAccountConfirm(input)),
224
224
  [client]
225
225
  );
226
226
  return { startLink, confirmLink, isLoading, error };
@@ -323,6 +323,7 @@ function useExecutionOrders(options = {}) {
323
323
  const client = useAggClient();
324
324
  const {
325
325
  status,
326
+ orderType,
326
327
  orderId,
327
328
  quoteId,
328
329
  mode,
@@ -338,11 +339,13 @@ function useExecutionOrders(options = {}) {
338
339
  status != null ? status : "all",
339
340
  quoteId != null ? quoteId : null,
340
341
  orderId != null ? orderId : null,
342
+ ...orderType ? [orderType] : [],
341
343
  ...mode ? [mode] : [],
342
344
  limit
343
345
  ],
344
346
  queryFn: ({ pageParam }) => client.getExecutionOrders(__spreadProps(__spreadValues({
345
347
  status,
348
+ orderType,
346
349
  orderId,
347
350
  quoteId
348
351
  }, mode ? { mode } : {}), {
@@ -2294,7 +2297,7 @@ var getIsDocumentVisible = () => {
2294
2297
  return document.visibilityState !== "hidden";
2295
2298
  };
2296
2299
  function useSmartRoute(options) {
2297
- var _a, _b, _c, _d;
2300
+ var _a, _b, _c, _d, _e, _f;
2298
2301
  const client = useAggClient();
2299
2302
  const {
2300
2303
  venueMarketOutcomeId,
@@ -2309,6 +2312,7 @@ function useSmartRoute(options) {
2309
2312
  slipCapBps,
2310
2313
  compareVenues,
2311
2314
  sellCacheScope,
2315
+ balanceCacheScope,
2312
2316
  deepEstimate,
2313
2317
  enabled = true,
2314
2318
  staleTimeMs = SMART_ROUTE_STALE_TIME_MS,
@@ -2330,7 +2334,8 @@ function useSmartRoute(options) {
2330
2334
  slipCapBps != null ? slipCapBps : null,
2331
2335
  compareVenues != null ? compareVenues : false,
2332
2336
  deepEstimate != null ? deepEstimate : false,
2333
- ...tradeSide === "sell" ? [(_b = sellCacheScope == null ? void 0 : sellCacheScope.accountId) != null ? _b : null, (_c = sellCacheScope == null ? void 0 : sellCacheScope.positionVersion) != null ? _c : null] : []
2337
+ ...balanceCacheScope ? [(_b = balanceCacheScope.accountId) != null ? _b : null, (_c = balanceCacheScope.balanceVersion) != null ? _c : null] : [],
2338
+ ...tradeSide === "sell" ? [(_d = sellCacheScope == null ? void 0 : sellCacheScope.accountId) != null ? _d : null, (_e = sellCacheScope == null ? void 0 : sellCacheScope.positionVersion) != null ? _e : null] : []
2334
2339
  ],
2335
2340
  queryFn: (_0) => __async(null, [_0], function* ({ signal }) {
2336
2341
  return client.getSmartRoute(
@@ -2387,7 +2392,7 @@ function useSmartRoute(options) {
2387
2392
  }
2388
2393
  }
2389
2394
  return {
2390
- data: (_d = query.data) != null ? _d : null,
2395
+ data: (_f = query.data) != null ? _f : null,
2391
2396
  isLoading: query.isLoading,
2392
2397
  isFetching: query.isFetching,
2393
2398
  error: error instanceof Error ? error : error ? new Error(String(error)) : null,
@@ -2397,7 +2402,7 @@ function useSmartRoute(options) {
2397
2402
  }
2398
2403
 
2399
2404
  // src/use-limit-order-venue-quotes.ts
2400
- import { keepPreviousData as keepPreviousData7, useQueries as useQueries6 } from "@tanstack/react-query";
2405
+ import { keepPreviousData as keepPreviousData7, useQueries as useQueries6, useQuery as useQuery8 } from "@tanstack/react-query";
2401
2406
  var getIsDocumentVisible2 = () => {
2402
2407
  if (typeof document === "undefined") return true;
2403
2408
  return document.visibilityState !== "hidden";
@@ -2410,6 +2415,27 @@ var getUniqueVenueRequests = (requests) => {
2410
2415
  }
2411
2416
  return [...requestsByVenue.values()].sort((left, right) => left.venue.localeCompare(right.venue));
2412
2417
  };
2418
+ var resolveLimitOrderTickSizesByVenue = (response) => {
2419
+ var _a, _b;
2420
+ const tickSizes = /* @__PURE__ */ new Map();
2421
+ const setTickSize = (venue, tickSize) => {
2422
+ if (tickSizes.has(venue)) return;
2423
+ if (typeof tickSize !== "number" || !Number.isFinite(tickSize) || tickSize <= 0) return;
2424
+ tickSizes.set(venue, tickSize);
2425
+ };
2426
+ for (const item of (_a = response == null ? void 0 : response.data) != null ? _a : []) {
2427
+ for (const [venue, entry] of Object.entries(item.venueOrderbooks)) {
2428
+ setTickSize(venue, (_b = entry.tick) != null ? _b : entry.tickSize);
2429
+ }
2430
+ for (const market of item.matchedMarkets) {
2431
+ setTickSize(market.venue, market.tickSize);
2432
+ }
2433
+ if (item.requestedMarket) {
2434
+ setTickSize(item.requestedMarket.venue, item.requestedMarket.tickSize);
2435
+ }
2436
+ }
2437
+ return tickSizes;
2438
+ };
2413
2439
  var useLimitOrderVenueQuotes = (options) => {
2414
2440
  var _a, _b;
2415
2441
  const client = useAggClient();
@@ -2431,6 +2457,15 @@ var useLimitOrderVenueQuotes = (options) => {
2431
2457
  const hasRequiredAccount = tradeSide === "buy" || Boolean(accountId);
2432
2458
  const queryEnabled = enabled && hasValidInput && hasRequiredAccount;
2433
2459
  const serializedChainBalances = chainBalances ? JSON.stringify(chainBalances) : null;
2460
+ const tickMetadataQuery = useQuery8({
2461
+ queryKey: ["orderbooks", marketId != null ? marketId : "__disabled__", "limit-order-ticks"],
2462
+ queryFn: ({ signal }) => client.getOrderbooks({ venueMarketIds: [marketId] }, { signal }),
2463
+ enabled: enabled && Boolean(marketId),
2464
+ staleTime: 6e4,
2465
+ gcTime: 5 * 6e4,
2466
+ refetchOnWindowFocus: false,
2467
+ retry: 1
2468
+ });
2434
2469
  const queries = useQueries6({
2435
2470
  queries: uniqueRequests.map((request) => ({
2436
2471
  queryKey: [
@@ -2485,12 +2520,15 @@ var useLimitOrderVenueQuotes = (options) => {
2485
2520
  retry: 1
2486
2521
  }))
2487
2522
  });
2523
+ const tickSizesByVenue = resolveLimitOrderTickSizesByVenue(tickMetadataQuery.data);
2488
2524
  const quotes = queries.map((query, index) => {
2489
- var _a2;
2525
+ var _a2, _b2;
2490
2526
  const queryError = query.error;
2527
+ const request = uniqueRequests[index];
2491
2528
  return {
2492
- request: uniqueRequests[index],
2529
+ request,
2493
2530
  data: (_a2 = query.data) != null ? _a2 : null,
2531
+ tickSize: (_b2 = tickSizesByVenue.get(request.venue)) != null ? _b2 : null,
2494
2532
  isLoading: query.isLoading,
2495
2533
  isFetching: query.isFetching,
2496
2534
  error: queryError instanceof Error ? queryError : queryError ? new Error(String(queryError)) : null,
@@ -2502,7 +2540,10 @@ var useLimitOrderVenueQuotes = (options) => {
2502
2540
  isLoading: quotes.some((quote) => quote.isLoading),
2503
2541
  isFetching: quotes.some((quote) => quote.isFetching),
2504
2542
  error: (_b = (_a = quotes.find((quote) => quote.error)) == null ? void 0 : _a.error) != null ? _b : null,
2505
- refetch: () => Promise.all(quotes.map((quote) => quote.refetch()))
2543
+ refetch: () => Promise.all([
2544
+ ...marketId ? [tickMetadataQuery.refetch()] : [],
2545
+ ...quotes.map((quote) => quote.refetch())
2546
+ ])
2506
2547
  };
2507
2548
  };
2508
2549
 
@@ -2655,25 +2696,566 @@ function useUserHoldings(options) {
2655
2696
  import { useMemo as useMemo10 } from "react";
2656
2697
 
2657
2698
  // src/use-venue-event.ts
2658
- import { useQuery as useQuery8 } from "@tanstack/react-query";
2699
+ import { useQuery as useQuery10 } from "@tanstack/react-query";
2700
+
2701
+ // src/use-recurring-crypto-markets.ts
2702
+ import { useQuery as useQuery9 } from "@tanstack/react-query";
2703
+ var RESOLVING_POLL_INTERVAL_MS = 15e3;
2704
+ var FALLBACK_VENUE_EVENT_PAGE_LIMIT = 100;
2705
+ var FALLBACK_VENUE_EVENT_MAX_PAGES = 5;
2706
+ var FALLBACK_TARGET_WINDOW_COUNT = 5;
2707
+ var RECURRING_MARKET_STATUSES = [
2708
+ "open" /* open */,
2709
+ "closed" /* closed */,
2710
+ "resolved" /* resolved */,
2711
+ "unopened" /* unopened */,
2712
+ "paused" /* paused */
2713
+ ];
2714
+ var RECURRING_DURATION_MS = {
2715
+ PT5M: 5 * 6e4,
2716
+ PT15M: 15 * 6e4,
2717
+ PT1H: 60 * 6e4,
2718
+ P1D: 24 * 60 * 6e4
2719
+ };
2720
+ var RECURRING_SLUG_DURATION = {
2721
+ "5m": "PT5M",
2722
+ "15m": "PT15M",
2723
+ "1h": "PT1H",
2724
+ "1d": "P1D"
2725
+ };
2726
+ var RECURRING_DURATION_AGG_KEY_SEGMENT = {
2727
+ PT5M: "5m",
2728
+ PT15M: "15m",
2729
+ PT1H: "1h"
2730
+ };
2731
+ var RECURRING_CRYPTO_SLUG_PATTERN = /^([a-z0-9]+)-updown-(5m|15m|1h|1d)-(\d+)$/i;
2732
+ var RECURRING_CRYPTO_AGG_KEY_PATTERN = /^agg_ud_([a-z0-9]+)_(5m|15m|1h)_(\d{2})(\d{2})(\d{2})T(\d{2})(\d{2})$/i;
2733
+ var RECURRING_CRYPTO_DAILY_AGG_KEY_PATTERN = /^agg_ud_([a-z0-9]+)_1d_(\d{2})(\d{2})(\d{2})$/i;
2734
+ var isRecurringCryptoDuration = (value) => value != null && Object.prototype.hasOwnProperty.call(RECURRING_DURATION_MS, value);
2735
+ var parseTimestamp = (value) => {
2736
+ if (!value) return null;
2737
+ const timestamp = Date.parse(value);
2738
+ return Number.isFinite(timestamp) ? timestamp : null;
2739
+ };
2740
+ var hasCryptoCategory = (event) => event.categories.some(
2741
+ ({ category }) => [category.name, category.displayName].some((value) => (value == null ? void 0 : value.trim().toLowerCase()) === "crypto")
2742
+ );
2743
+ var resolveWindowStartFromEnd = (event, duration) => {
2744
+ var _a, _b;
2745
+ const end = (_b = (_a = parseTimestamp(event.endDate)) != null ? _a : event.venueMarkets.map((market) => parseTimestamp(market.endDate)).find((value) => value != null)) != null ? _b : null;
2746
+ if (end != null) return end - RECURRING_DURATION_MS[duration];
2747
+ return parseTimestamp(event.startDate);
2748
+ };
2749
+ var parseAggKeyWindowStart = (match) => {
2750
+ const year = 2e3 + Number(match[3]);
2751
+ const monthIndex = Number(match[4]) - 1;
2752
+ const day = Number(match[5]);
2753
+ const hour = Number(match[6]);
2754
+ const minute = Number(match[7]);
2755
+ const timestamp = Date.UTC(year, monthIndex, day, hour, minute);
2756
+ const parsed = new Date(timestamp);
2757
+ if (parsed.getUTCFullYear() !== year || parsed.getUTCMonth() !== monthIndex || parsed.getUTCDate() !== day || parsed.getUTCHours() !== hour || parsed.getUTCMinutes() !== minute) {
2758
+ return null;
2759
+ }
2760
+ return timestamp;
2761
+ };
2762
+ var resolveRecurringCryptoIdentity = (event) => {
2763
+ var _a, _b, _c, _d, _e, _f, _g;
2764
+ const slugMatch = (_a = event.slug) == null ? void 0 : _a.match(RECURRING_CRYPTO_SLUG_PATTERN);
2765
+ if (slugMatch && hasCryptoCategory(event)) {
2766
+ const [, asset, durationSegment, epochSeconds] = slugMatch;
2767
+ const duration = RECURRING_SLUG_DURATION[durationSegment.toLowerCase()];
2768
+ const parsedEpochSeconds = Number(epochSeconds);
2769
+ const windowStart = parsedEpochSeconds * 1e3;
2770
+ if (duration && Number.isSafeInteger(parsedEpochSeconds) && Number.isFinite(windowStart)) {
2771
+ return { asset: asset.toUpperCase(), duration, windowStart };
2772
+ }
2773
+ }
2774
+ const aggKeyMatch = (_b = event.aggKey) == null ? void 0 : _b.match(RECURRING_CRYPTO_AGG_KEY_PATTERN);
2775
+ if (aggKeyMatch) {
2776
+ const [, asset, durationSegment] = aggKeyMatch;
2777
+ const duration = RECURRING_SLUG_DURATION[durationSegment.toLowerCase()];
2778
+ const windowStart = parseAggKeyWindowStart(aggKeyMatch);
2779
+ if (duration && windowStart != null) {
2780
+ return { asset: asset.toUpperCase(), duration, windowStart };
2781
+ }
2782
+ }
2783
+ const dailyAggKeyMatch = (_c = event.aggKey) == null ? void 0 : _c.match(RECURRING_CRYPTO_DAILY_AGG_KEY_PATTERN);
2784
+ if (dailyAggKeyMatch) {
2785
+ return {
2786
+ asset: dailyAggKeyMatch[1].toUpperCase(),
2787
+ duration: "P1D",
2788
+ windowStart: resolveWindowStartFromEnd(event, "P1D")
2789
+ };
2790
+ }
2791
+ if (!isRecurringCryptoDuration(event.recurrence)) return null;
2792
+ return {
2793
+ asset: (_g = (_f = (_d = slugMatch == null ? void 0 : slugMatch[1]) == null ? void 0 : _d.toUpperCase()) != null ? _f : (_e = aggKeyMatch == null ? void 0 : aggKeyMatch[1]) == null ? void 0 : _e.toUpperCase()) != null ? _g : null,
2794
+ duration: event.recurrence,
2795
+ windowStart: resolveWindowStartFromEnd(event, event.recurrence)
2796
+ };
2797
+ };
2798
+ var mergeWindowMarkets = (current, incoming) => {
2799
+ const marketsById = new Map(
2800
+ current.map((market) => [
2801
+ `${market.venue}:${market.venueEventId}:${market.venueMarketId}`,
2802
+ market
2803
+ ])
2804
+ );
2805
+ incoming.forEach((market) => {
2806
+ marketsById.set(`${market.venue}:${market.venueEventId}:${market.venueMarketId}`, market);
2807
+ });
2808
+ return [...marketsById.values()];
2809
+ };
2810
+ var mergeRecurringCryptoWindows = (windows) => {
2811
+ const windowsById = /* @__PURE__ */ new Map();
2812
+ windows.forEach((windowMarket) => {
2813
+ const existing = windowsById.get(windowMarket.id);
2814
+ if (!existing) {
2815
+ windowsById.set(windowMarket.id, windowMarket);
2816
+ return;
2817
+ }
2818
+ windowsById.set(windowMarket.id, __spreadProps(__spreadValues(__spreadValues({}, existing), windowMarket), {
2819
+ markets: mergeWindowMarkets(existing.markets, windowMarket.markets)
2820
+ }));
2821
+ });
2822
+ return [...windowsById.values()].sort(
2823
+ (left, right) => {
2824
+ var _a, _b;
2825
+ return ((_a = parseTimestamp(left.windowStart)) != null ? _a : 0) - ((_b = parseTimestamp(right.windowStart)) != null ? _b : 0);
2826
+ }
2827
+ );
2828
+ };
2829
+ var selectNavigableMarket = (markets, event) => {
2830
+ var _a, _b, _c;
2831
+ const navigableMarkets = markets.filter((market) => market.priceSource === "snag");
2832
+ return (_c = (_b = (_a = navigableMarkets.find((market) => market.venueEventId === event.id)) != null ? _a : navigableMarkets.find((market) => market.venue === event.venue)) != null ? _b : navigableMarkets[0]) != null ? _c : null;
2833
+ };
2834
+ var resolveRecurringCryptoTimeline = (windows, event, now) => {
2835
+ var _a, _b, _c;
2836
+ const all = mergeRecurringCryptoWindows(windows).flatMap((windowMarket) => {
2837
+ const windowStart = parseTimestamp(windowMarket.windowStart);
2838
+ const windowEnd = parseTimestamp(windowMarket.windowEnd);
2839
+ const market = selectNavigableMarket(windowMarket.markets, event);
2840
+ if (windowStart == null || windowEnd == null || windowEnd <= windowStart || !market) return [];
2841
+ return [
2842
+ {
2843
+ id: windowMarket.id,
2844
+ asset: windowMarket.asset,
2845
+ duration: windowMarket.duration,
2846
+ windowStart: windowMarket.windowStart,
2847
+ windowEnd: windowMarket.windowEnd,
2848
+ status: market.status,
2849
+ venueEventId: market.venueEventId,
2850
+ venueMarketId: market.venueMarketId,
2851
+ venue: market.venue
2852
+ }
2853
+ ];
2854
+ });
2855
+ const viewed = (_a = all.find((market) => market.venueEventId === event.id)) != null ? _a : null;
2856
+ const live = (_b = all.find((market) => {
2857
+ const startsAt = parseTimestamp(market.windowStart);
2858
+ const endsAt = parseTimestamp(market.windowEnd);
2859
+ return market.status === "open" /* open */ && startsAt != null && endsAt != null && startsAt <= now && now < endsAt;
2860
+ })) != null ? _b : null;
2861
+ const endedMarkets = all.filter(
2862
+ (market) => {
2863
+ var _a2;
2864
+ return ((_a2 = parseTimestamp(market.windowEnd)) != null ? _a2 : Infinity) <= now;
2865
+ }
2866
+ );
2867
+ const ended = (_c = endedMarkets[endedMarkets.length - 1]) != null ? _c : null;
2868
+ const upcoming = all.filter((market) => {
2869
+ var _a2;
2870
+ return ((_a2 = parseTimestamp(market.windowStart)) != null ? _a2 : -Infinity) > now;
2871
+ }).slice(0, 3);
2872
+ const defaultVisible = [ended, live, ...upcoming].filter(
2873
+ (market, index, values) => market != null && values.findIndex((candidate) => (candidate == null ? void 0 : candidate.id) === market.id) === index
2874
+ );
2875
+ let visible = defaultVisible;
2876
+ if (viewed && !defaultVisible.some((market) => market.id === viewed.id)) {
2877
+ const viewedStart = Date.parse(viewed.windowStart);
2878
+ const viewedEnd = Date.parse(viewed.windowEnd);
2879
+ const marketToReplace = viewedEnd <= now ? ended : viewedStart > now ? upcoming[upcoming.length - 1] : ended != null ? ended : upcoming[upcoming.length - 1];
2880
+ visible = [
2881
+ ...defaultVisible.filter((market) => market.id !== (marketToReplace == null ? void 0 : marketToReplace.id)),
2882
+ viewed
2883
+ ].sort(
2884
+ (left, right) => {
2885
+ var _a2, _b2;
2886
+ return ((_a2 = parseTimestamp(left.windowStart)) != null ? _a2 : 0) - ((_b2 = parseTimestamp(right.windowStart)) != null ? _b2 : 0);
2887
+ }
2888
+ );
2889
+ }
2890
+ return { all, visible, ended, live, upcoming, viewed };
2891
+ };
2892
+ var fetchRecurringCryptoPage = (client, options, signal) => __async(null, null, function* () {
2893
+ var _a;
2894
+ return client.listRecurringCryptoMarkets(__spreadProps(__spreadValues({}, options), {
2895
+ status: (_a = options.status) != null ? _a : RECURRING_MARKET_STATUSES,
2896
+ includeOrderbookPrices: false,
2897
+ includeReferencePrices: false,
2898
+ includeDirectVenueMarkets: options.includeDirectVenueMarkets,
2899
+ limit: 100,
2900
+ signal
2901
+ }));
2902
+ });
2903
+ var createEmptyPriceComparison = () => ({
2904
+ count: 0,
2905
+ min: null,
2906
+ max: null,
2907
+ spread: null,
2908
+ spreadBps: null,
2909
+ byVenue: []
2910
+ });
2911
+ var normalizeFallbackVenueEvent = (candidate, identity) => {
2912
+ var _a, _b, _c, _d;
2913
+ const candidateIdentity = resolveRecurringCryptoIdentity(candidate);
2914
+ const venueMarket = candidate.venueMarkets[0];
2915
+ if (!(candidateIdentity == null ? void 0 : candidateIdentity.asset) || !identity.asset || candidateIdentity.asset !== identity.asset || candidateIdentity.duration !== identity.duration || candidateIdentity.windowStart == null || !venueMarket) {
2916
+ return null;
2917
+ }
2918
+ const status = (_b = (_a = candidate.status) != null ? _a : venueMarket.status) != null ? _b : "unopened" /* unopened */;
2919
+ const windowStart = candidateIdentity.windowStart;
2920
+ return {
2921
+ id: `${candidateIdentity.asset}:${candidateIdentity.duration}:${new Date(windowStart).toISOString()}`,
2922
+ asset: candidateIdentity.asset,
2923
+ quoteAsset: "USD",
2924
+ duration: candidateIdentity.duration,
2925
+ windowStart: new Date(windowStart).toISOString(),
2926
+ windowEnd: new Date(windowStart + RECURRING_DURATION_MS[identity.duration]).toISOString(),
2927
+ status,
2928
+ markets: [
2929
+ {
2930
+ venue: candidate.venue,
2931
+ venueEventId: candidate.id,
2932
+ venueMarketId: venueMarket.id,
2933
+ externalEventId: candidate.externalIdentifier,
2934
+ externalMarketId: venueMarket.externalIdentifier,
2935
+ question: venueMarket.question,
2936
+ status,
2937
+ priceSource: "snag",
2938
+ routeable: false,
2939
+ splitOrdersAllowed: false,
2940
+ outcomes: ((_c = venueMarket.venueMarketOutcomes) != null ? _c : []).map((outcome) => {
2941
+ var _a2, _b2;
2942
+ return {
2943
+ venueMarketOutcomeId: outcome.id,
2944
+ externalOutcomeId: (_a2 = outcome.externalIdentifier) != null ? _a2 : null,
2945
+ routeable: false,
2946
+ splitOrdersAllowed: false,
2947
+ label: outcome.label,
2948
+ title: (_b2 = outcome.title) != null ? _b2 : null,
2949
+ midpoint: null,
2950
+ bestBid: null,
2951
+ bestAsk: null,
2952
+ markSource: null,
2953
+ lastKnownPrice: null,
2954
+ orderbookDepth: null
2955
+ };
2956
+ }),
2957
+ metrics: {
2958
+ volume: (_d = venueMarket.volume) != null ? _d : null,
2959
+ volume24h: null,
2960
+ openInterest: null,
2961
+ liquidity: null,
2962
+ spread: null
2963
+ },
2964
+ resolution: {
2965
+ sourceName: null,
2966
+ sourceUrl: null,
2967
+ sourceDomain: null,
2968
+ rawCriteria: null,
2969
+ confidence: "missing"
2970
+ },
2971
+ referencePrice: {
2972
+ asset: candidateIdentity.asset,
2973
+ quoteAsset: "USD",
2974
+ raw: null,
2975
+ decimals: null,
2976
+ normalized: null,
2977
+ timestamp: null,
2978
+ provider: null,
2979
+ providerMarketId: null,
2980
+ confidence: "missing"
2981
+ }
2982
+ }
2983
+ ],
2984
+ comparisons: {
2985
+ referencePrice: createEmptyPriceComparison(),
2986
+ outcomePrices: {
2987
+ up: createEmptyPriceComparison(),
2988
+ down: createEmptyPriceComparison()
2989
+ }
2990
+ }
2991
+ };
2992
+ };
2993
+ var formatCanonicalRecurringAggKey = (asset, duration, windowStart) => {
2994
+ const durationSegment = RECURRING_DURATION_AGG_KEY_SEGMENT[duration];
2995
+ if (!durationSegment) return null;
2996
+ const date = new Date(windowStart);
2997
+ if (Number.isNaN(date.getTime())) return null;
2998
+ const twoDigits = (value) => String(value).padStart(2, "0");
2999
+ const timestamp = [
3000
+ twoDigits(date.getUTCFullYear() % 100),
3001
+ twoDigits(date.getUTCMonth() + 1),
3002
+ twoDigits(date.getUTCDate()),
3003
+ "T",
3004
+ twoDigits(date.getUTCHours()),
3005
+ twoDigits(date.getUTCMinutes())
3006
+ ].join("");
3007
+ return `agg_ud_${asset.toLowerCase()}_${durationSegment}_${timestamp}`;
3008
+ };
3009
+ var fetchCanonicalAggKeyWindows = (client, event, identity, signal, now) => __async(null, null, function* () {
3010
+ var _a;
3011
+ const aggKeyMatch = (_a = event.aggKey) == null ? void 0 : _a.match(RECURRING_CRYPTO_AGG_KEY_PATTERN);
3012
+ const asset = identity.asset;
3013
+ if (!aggKeyMatch || !asset) return [];
3014
+ const durationMs = RECURRING_DURATION_MS[identity.duration];
3015
+ const currentWindowStart = Math.floor(now / durationMs) * durationMs;
3016
+ const windowStarts = /* @__PURE__ */ new Set([
3017
+ currentWindowStart - durationMs,
3018
+ currentWindowStart,
3019
+ currentWindowStart + durationMs,
3020
+ currentWindowStart + durationMs * 2,
3021
+ currentWindowStart + durationMs * 3,
3022
+ identity.windowStart
3023
+ ]);
3024
+ const aggKeys = [...windowStarts].flatMap((windowStart) => {
3025
+ if (windowStart == null) return [];
3026
+ const aggKey = formatCanonicalRecurringAggKey(asset, identity.duration, windowStart);
3027
+ return aggKey ? [aggKey] : [];
3028
+ });
3029
+ if (!aggKeys.length) return [];
3030
+ const response = yield client.getVenueEvents({
3031
+ venues: [event.venue],
3032
+ aggKey: aggKeys,
3033
+ limit: 100,
3034
+ signal
3035
+ });
3036
+ return mergeRecurringCryptoWindows(
3037
+ response.data.flatMap((candidate) => {
3038
+ const normalized = normalizeFallbackVenueEvent(candidate, identity);
3039
+ return normalized ? [normalized] : [];
3040
+ })
3041
+ );
3042
+ });
3043
+ var fetchFallbackVenueEventWindows = (client, event, identity, signal, now) => __async(null, null, function* () {
3044
+ var _a;
3045
+ const durationMs = RECURRING_DURATION_MS[identity.duration];
3046
+ const categoryIds = event.categories.filter(
3047
+ ({ category }) => [category.name, category.displayName].some(
3048
+ (value) => (value == null ? void 0 : value.trim().toLowerCase()) === "crypto"
3049
+ )
3050
+ ).map(({ category }) => category.id);
3051
+ const windowStarts = /* @__PURE__ */ new Set([((_a = identity.windowStart) != null ? _a : now) - durationMs, now - durationMs * 2]);
3052
+ const responses = yield Promise.all(
3053
+ [...windowStarts].map((windowStart) => __async(null, null, function* () {
3054
+ var _a2;
3055
+ const windows = [];
3056
+ const seenCursors = /* @__PURE__ */ new Set();
3057
+ let cursor;
3058
+ for (let page = 0; page < FALLBACK_VENUE_EVENT_MAX_PAGES; page += 1) {
3059
+ const response = yield client.getVenueEvents({
3060
+ venues: [event.venue],
3061
+ categoryIds,
3062
+ status: RECURRING_MARKET_STATUSES,
3063
+ sortBy: "endDate",
3064
+ sortDir: "asc",
3065
+ endDateFrom: new Date(windowStart).toISOString(),
3066
+ limit: FALLBACK_VENUE_EVENT_PAGE_LIMIT,
3067
+ cursor,
3068
+ signal
3069
+ });
3070
+ response.data.forEach((candidate) => {
3071
+ const normalized = normalizeFallbackVenueEvent(
3072
+ candidate,
3073
+ identity
3074
+ );
3075
+ if (normalized) windows.push(normalized);
3076
+ });
3077
+ if (mergeRecurringCryptoWindows(windows).length >= FALLBACK_TARGET_WINDOW_COUNT) break;
3078
+ const nextCursor = response.hasMore ? (_a2 = response.nextCursor) != null ? _a2 : void 0 : void 0;
3079
+ if (!nextCursor || seenCursors.has(nextCursor)) break;
3080
+ seenCursors.add(nextCursor);
3081
+ cursor = nextCursor;
3082
+ }
3083
+ return windows;
3084
+ }))
3085
+ );
3086
+ return mergeRecurringCryptoWindows(responses.flat());
3087
+ });
3088
+ var fetchRecurringCryptoMarkets = (_0, _1, _2, ..._3) => __async(null, [_0, _1, _2, ..._3], function* (client, event, signal, now = Date.now()) {
3089
+ var _a, _b;
3090
+ const identity = resolveRecurringCryptoIdentity(event);
3091
+ if (!identity) return [];
3092
+ const { asset, duration, windowStart: anchorStart } = identity;
3093
+ const queryAssets = ((_a = event.aggKey) == null ? void 0 : _a.match(RECURRING_CRYPTO_DAILY_AGG_KEY_PATTERN)) ? void 0 : asset ? [asset] : void 0;
3094
+ const canonicalAggKeyWindowsPromise = fetchCanonicalAggKeyWindows(
3095
+ client,
3096
+ event,
3097
+ identity,
3098
+ signal,
3099
+ now
3100
+ ).catch(() => []);
3101
+ const anchorOptions = anchorStart == null ? {
3102
+ assets: queryAssets,
3103
+ durations: [duration],
3104
+ venues: [event.venue],
3105
+ window: "current",
3106
+ includeDirectVenueMarkets: duration === "P1D"
3107
+ } : {
3108
+ assets: queryAssets,
3109
+ durations: [duration],
3110
+ venues: [event.venue],
3111
+ windowStartFrom: new Date(anchorStart - 1e3).toISOString(),
3112
+ windowStartTo: new Date(anchorStart + 1e3).toISOString(),
3113
+ includeDirectVenueMarkets: duration === "P1D"
3114
+ };
3115
+ let anchorResponse = yield fetchRecurringCryptoPage(client, anchorOptions, signal);
3116
+ let anchor = anchorResponse.data.find(
3117
+ (windowMarket) => windowMarket.markets.some((market) => market.venueEventId === event.id)
3118
+ );
3119
+ let timelineVenues = [event.venue];
3120
+ let canonicalAggKeyWindows = null;
3121
+ if (!anchor) {
3122
+ canonicalAggKeyWindows = yield canonicalAggKeyWindowsPromise;
3123
+ if (canonicalAggKeyWindows.some(
3124
+ (windowMarket) => windowMarket.markets.some((market) => market.venueEventId === event.id)
3125
+ )) {
3126
+ return canonicalAggKeyWindows;
3127
+ }
3128
+ }
3129
+ if (!anchor && asset && anchorStart != null) {
3130
+ const unscopedAnchorResponse = yield fetchRecurringCryptoPage(
3131
+ client,
3132
+ __spreadProps(__spreadValues({}, anchorOptions), { venues: void 0 }),
3133
+ signal
3134
+ );
3135
+ const matchingWindow = unscopedAnchorResponse.data.find(
3136
+ (windowMarket) => windowMarket.asset === asset && windowMarket.duration === duration && parseTimestamp(windowMarket.windowStart) === anchorStart
3137
+ );
3138
+ const viewedWindow = normalizeFallbackVenueEvent(event, identity);
3139
+ if (matchingWindow && viewedWindow) {
3140
+ anchorResponse = unscopedAnchorResponse;
3141
+ anchor = __spreadProps(__spreadValues({}, matchingWindow), {
3142
+ markets: mergeWindowMarkets(matchingWindow.markets, viewedWindow.markets)
3143
+ });
3144
+ timelineVenues = void 0;
3145
+ }
3146
+ }
3147
+ if (!anchor) {
3148
+ return fetchFallbackVenueEventWindows(client, event, identity, signal, now);
3149
+ }
3150
+ const timelineStart = now - RECURRING_DURATION_MS[duration] * 2;
3151
+ const windows = [
3152
+ anchor,
3153
+ ...anchorResponse.data.filter(
3154
+ (windowMarket) => windowMarket.asset === anchor.asset && windowMarket.duration === duration
3155
+ )
3156
+ ];
3157
+ const seenCursors = /* @__PURE__ */ new Set();
3158
+ let cursor;
3159
+ do {
3160
+ const response = yield fetchRecurringCryptoPage(
3161
+ client,
3162
+ {
3163
+ assets: [anchor.asset],
3164
+ durations: [duration],
3165
+ venues: timelineVenues,
3166
+ windowStartFrom: new Date(timelineStart).toISOString(),
3167
+ includeDirectVenueMarkets: duration === "P1D",
3168
+ cursor
3169
+ },
3170
+ signal
3171
+ );
3172
+ windows.push(...response.data);
3173
+ const nextCursor = response.hasMore ? (_b = response.nextCursor) != null ? _b : void 0 : void 0;
3174
+ if (!nextCursor || seenCursors.has(nextCursor)) break;
3175
+ seenCursors.add(nextCursor);
3176
+ cursor = nextCursor;
3177
+ } while (cursor);
3178
+ windows.push(...canonicalAggKeyWindows != null ? canonicalAggKeyWindows : yield canonicalAggKeyWindowsPromise);
3179
+ return mergeRecurringCryptoWindows(windows);
3180
+ });
3181
+ var recurringCryptoTransitionPollInterval = (windows, event, now = Date.now()) => {
3182
+ var _a, _b;
3183
+ if (!windows) return false;
3184
+ const timeline = resolveRecurringCryptoTimeline(windows, event, now);
3185
+ const viewedEnd = parseTimestamp((_b = (_a = timeline.viewed) == null ? void 0 : _a.windowEnd) != null ? _b : event.endDate);
3186
+ return viewedEnd != null && viewedEnd <= now && !timeline.live ? RESOLVING_POLL_INTERVAL_MS : false;
3187
+ };
3188
+ var useRecurringCryptoMarkets = ({
3189
+ event,
3190
+ enabled = true
3191
+ }) => {
3192
+ var _a;
3193
+ const client = useAggClient();
3194
+ const identity = event ? resolveRecurringCryptoIdentity(event) : null;
3195
+ const isEnabled = enabled && event != null && identity != null;
3196
+ const query = useQuery9({
3197
+ queryKey: [
3198
+ "recurring-crypto-markets",
3199
+ event == null ? void 0 : event.id,
3200
+ identity == null ? void 0 : identity.asset,
3201
+ identity == null ? void 0 : identity.duration,
3202
+ identity == null ? void 0 : identity.windowStart,
3203
+ event == null ? void 0 : event.venue
3204
+ ],
3205
+ queryFn: ({ signal }) => fetchRecurringCryptoMarkets(client, event, signal),
3206
+ enabled: isEnabled,
3207
+ staleTime: 1e4,
3208
+ gcTime: 5 * 6e4,
3209
+ refetchOnWindowFocus: true,
3210
+ refetchOnReconnect: true,
3211
+ refetchOnMount: true,
3212
+ refetchInterval: (queryState) => event ? recurringCryptoTransitionPollInterval(
3213
+ queryState.state.data,
3214
+ event
3215
+ ) : false,
3216
+ retry: 1
3217
+ });
3218
+ return __spreadProps(__spreadValues({}, query), {
3219
+ windows: (_a = query.data) != null ? _a : [],
3220
+ isRecurringCryptoMarket: isEnabled
3221
+ });
3222
+ };
3223
+
3224
+ // src/use-venue-event.ts
2659
3225
  var RESOLUTION_POLL_MS = 15e3;
2660
3226
  var RESOLUTION_POLL_MAX_PAST_END_MS = 60 * 6e4;
2661
3227
  function resolutionPollInterval(event) {
2662
- var _a;
2663
- if (!((_a = event == null ? void 0 : event.venueMarkets) == null ? void 0 : _a.length)) return false;
3228
+ if (!event) return false;
2664
3229
  const now = Date.now();
3230
+ const isRecurringCryptoMarket = resolveRecurringCryptoIdentity(event) != null;
3231
+ if (isRecurringCryptoMarket && event.status === "resolved" /* resolved */) return false;
3232
+ if (isRecurringCryptoMarket && event.status === "closed" /* closed */) {
3233
+ return RESOLUTION_POLL_MS;
3234
+ }
3235
+ const eventEndsAt = event.endDate ? Date.parse(event.endDate) : Number.NaN;
3236
+ if (isRecurringCryptoMarket && event.status === "paused" /* paused */ && Number.isFinite(eventEndsAt) && eventEndsAt <= now) {
3237
+ return RESOLUTION_POLL_MS;
3238
+ }
2665
3239
  const shouldPoll = event.venueMarkets.some((market) => {
2666
- if (market.status !== "open" /* open */ || !market.endDate) return false;
3240
+ if (!market.endDate) return false;
2667
3241
  const endsAt = new Date(market.endDate).getTime();
3242
+ if (isRecurringCryptoMarket && (market.status === "closed" /* closed */ || market.status === "paused" /* paused */) && Number.isFinite(endsAt) && endsAt <= now) {
3243
+ return true;
3244
+ }
3245
+ if (market.status !== "open" /* open */) return false;
2668
3246
  return Number.isFinite(endsAt) && now > endsAt && now < endsAt + RESOLUTION_POLL_MAX_PAST_END_MS;
2669
3247
  });
2670
- return shouldPoll ? RESOLUTION_POLL_MS : false;
3248
+ if (shouldPoll) return RESOLUTION_POLL_MS;
3249
+ if (!isRecurringCryptoMarket || event.status !== "open" /* open */) return false;
3250
+ if (!Number.isFinite(eventEndsAt)) return false;
3251
+ if (now <= eventEndsAt || now >= eventEndsAt + RESOLUTION_POLL_MAX_PAST_END_MS) return false;
3252
+ return RESOLUTION_POLL_MS;
2671
3253
  }
2672
3254
  function useVenueEvent(options) {
2673
3255
  var _a;
2674
3256
  const client = useAggClient();
2675
3257
  const { eventId, enabled = true } = options;
2676
- const query = useQuery8({
3258
+ const query = useQuery10({
2677
3259
  queryKey: ["venue-event", eventId],
2678
3260
  queryFn: (_0) => __async(null, [_0], function* ({ signal }) {
2679
3261
  return client.getVenueEventById(eventId, { signal });
@@ -2973,8 +3555,48 @@ function useVenueEvents(options) {
2973
3555
  });
2974
3556
  }
2975
3557
 
3558
+ // src/use-sports-live.ts
3559
+ import { useQuery as useQuery11 } from "@tanstack/react-query";
3560
+ var SPORTS_LIVE_POLL_INTERVAL_MS = 5e3;
3561
+ var SPORTS_SCHEDULED_POLL_INTERVAL_MS = 3e4;
3562
+ var sportsLiveQueryKey = (sortedEventIds) => ["sports-live", ...sortedEventIds];
3563
+ var sportsLiveRefetchInterval = (response) => {
3564
+ if (!response) return false;
3565
+ if (response.data.some((state) => state.status === "live" || state.status === "paused")) {
3566
+ return SPORTS_LIVE_POLL_INTERVAL_MS;
3567
+ }
3568
+ if (response.data.some((state) => state.status === "scheduled")) {
3569
+ return SPORTS_SCHEDULED_POLL_INTERVAL_MS;
3570
+ }
3571
+ return false;
3572
+ };
3573
+ var useSportsLive = (eventIds, enabled = true) => {
3574
+ var _a, _b, _c, _d;
3575
+ const client = useAggClient();
3576
+ const sortedEventIds = [
3577
+ ...new Set(eventIds.map((eventId) => eventId.trim()).filter(Boolean))
3578
+ ].sort();
3579
+ const query = useQuery11({
3580
+ queryKey: sportsLiveQueryKey(sortedEventIds),
3581
+ queryFn: ({ signal }) => client.getSportsLive(sortedEventIds, { signal }),
3582
+ enabled: enabled && sortedEventIds.length > 0,
3583
+ refetchInterval: (queryState) => sportsLiveRefetchInterval(queryState.state.data),
3584
+ refetchIntervalInBackground: false,
3585
+ refetchOnWindowFocus: true
3586
+ });
3587
+ const states = (_b = (_a = query.data) == null ? void 0 : _a.data) != null ? _b : [];
3588
+ const stateByEventId = new Map(
3589
+ states.map((state) => [state.eventId, state])
3590
+ );
3591
+ return __spreadProps(__spreadValues({}, query), {
3592
+ states,
3593
+ stateByEventId,
3594
+ missingEventIds: (_d = (_c = query.data) == null ? void 0 : _c.missingEventIds) != null ? _d : []
3595
+ });
3596
+ };
3597
+
2976
3598
  // src/use-venue-market-midpoints.ts
2977
- import { keepPreviousData as keepPreviousData9, useQuery as useQuery9 } from "@tanstack/react-query";
3599
+ import { keepPreviousData as keepPreviousData9, useQuery as useQuery12 } from "@tanstack/react-query";
2978
3600
  var normalizeVenueMarketIds2 = (venueMarketIds) => {
2979
3601
  return [
2980
3602
  ...new Set(venueMarketIds.map((venueMarketId) => venueMarketId.trim()).filter(Boolean))
@@ -3013,7 +3635,7 @@ function useVenueMarketMidpoints(options) {
3013
3635
  const enabled = (_a = options.enabled) != null ? _a : true;
3014
3636
  const requestedVenueMarketIds = normalizeVenueMarketIds2(options.venueMarketIds);
3015
3637
  const maxMidpointIdsPerRequest = (_b = options.maxMidpointIdsPerRequest) != null ? _b : configuredMaxMidpointIdsPerRequest;
3016
- const query = useQuery9({
3638
+ const query = useQuery12({
3017
3639
  queryKey: requestedVenueMarketIds.length ? ["venue-market-midpoints", requestedVenueMarketIds, maxMidpointIdsPerRequest] : ["venue-market-midpoints", "__disabled__"],
3018
3640
  queryFn: (_0) => __async(null, [_0], function* ({ signal }) {
3019
3641
  if (requestedVenueMarketIds.length === 0) {
@@ -3280,12 +3902,12 @@ function useVisibleIds(options = {}) {
3280
3902
  }
3281
3903
 
3282
3904
  // src/use-app-config.ts
3283
- import { useQuery as useQuery10, useQueryClient as useQueryClient2 } from "@tanstack/react-query";
3905
+ import { useQuery as useQuery13, useQueryClient as useQueryClient2 } from "@tanstack/react-query";
3284
3906
  var FIVE_MINUTES = 5 * 60 * 1e3;
3285
3907
  var APP_CONFIG_QUERY_KEY = ["agg", "app-config"];
3286
3908
  function useAppConfig() {
3287
3909
  const client = useAggClient();
3288
- const query = useQuery10({
3910
+ const query = useQuery13({
3289
3911
  queryKey: APP_CONFIG_QUERY_KEY,
3290
3912
  queryFn: () => client.getAppConfig(),
3291
3913
  staleTime: FIVE_MINUTES
@@ -3298,7 +3920,7 @@ function useAppConfig() {
3298
3920
  }
3299
3921
  function useCachedAppConfig() {
3300
3922
  const queryClient = useQueryClient2();
3301
- const query = useQuery10({
3923
+ const query = useQuery13({
3302
3924
  queryKey: APP_CONFIG_QUERY_KEY,
3303
3925
  enabled: false,
3304
3926
  initialData: () => queryClient.getQueryData(APP_CONFIG_QUERY_KEY),
@@ -3339,6 +3961,8 @@ export {
3339
3961
  QueryClient4 as QueryClient,
3340
3962
  QueryClientProvider,
3341
3963
  RedeemRejectedError,
3964
+ SPORTS_LIVE_POLL_INTERVAL_MS,
3965
+ SPORTS_SCHEDULED_POLL_INTERVAL_MS,
3342
3966
  TradeSide,
3343
3967
  TurnstileChallengeError,
3344
3968
  Venue,
@@ -3349,6 +3973,7 @@ export {
3349
3973
  defaultAggUiConfig as defaultSdkUiConfig,
3350
3974
  executionKeys,
3351
3975
  extractOutcomeBestCandidate,
3976
+ fetchRecurringCryptoMarkets,
3352
3977
  findLivePriceById,
3353
3978
  getBuilder,
3354
3979
  getDepositAddress,
@@ -3364,11 +3989,13 @@ export {
3364
3989
  invalidateUserMoneyState,
3365
3990
  isVenueDisabledByConfig,
3366
3991
  mergeBestPricesPreferringLive,
3992
+ mergeRecurringCryptoWindows,
3367
3993
  normalizeVenueId,
3368
3994
  optimizedImageUrl,
3369
3995
  parseEmail,
3370
3996
  parseEmailStrict,
3371
3997
  rangeToSeconds,
3998
+ recurringCryptoTransitionPollInterval,
3372
3999
  requestAggAuthChooserOpen,
3373
4000
  resolveAggUiLabels,
3374
4001
  resolveDefaultMarket as resolveDefaultTradingMarket,
@@ -3376,9 +4003,13 @@ export {
3376
4003
  resolveMarketTradingState,
3377
4004
  resolveMarketWinningOutcome,
3378
4005
  resolveOrderEligibility,
4006
+ resolveRecurringCryptoIdentity,
4007
+ resolveRecurringCryptoTimeline,
3379
4008
  resolveRollingWindow,
3380
4009
  resolveTradingStateKind,
3381
4010
  sortVenues,
4011
+ sportsLiveQueryKey,
4012
+ sportsLiveRefetchInterval,
3382
4013
  timeRangeToInterval,
3383
4014
  tradingReducer,
3384
4015
  useAggAuth,
@@ -3441,6 +4072,7 @@ export {
3441
4072
  useQueryClient3 as useQueryClient,
3442
4073
  useRampQuotes,
3443
4074
  useRampSession,
4075
+ useRecurringCryptoMarkets,
3444
4076
  useRedeem,
3445
4077
  useRedeemEligibleCount,
3446
4078
  useRedeemLifecycle,
@@ -3450,6 +4082,7 @@ export {
3450
4082
  useSdkUiConfig,
3451
4083
  useSearch,
3452
4084
  useSmartRoute,
4085
+ useSportsLive,
3453
4086
  useSyncBalances,
3454
4087
  useUserActivity,
3455
4088
  useUserHoldings,