@agg-build/ui 4.4.0 → 4.7.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.
Files changed (31) hide show
  1. package/README.md +4 -0
  2. package/dist/{chunk-WW5QKNIM.mjs → chunk-3UBMK2YH.mjs} +302 -26
  3. package/dist/{chunk-V5CRUO6S.mjs → chunk-C4GFVJ62.mjs} +98 -30
  4. package/dist/{chunk-64BBTXFE.mjs → chunk-KDBKKJ7W.mjs} +68 -35
  5. package/dist/{chunk-UCU2XCV5.mjs → chunk-LXQ3U4X2.mjs} +2 -2
  6. package/dist/{chunk-N7UPPT5J.mjs → chunk-RDBMHBR2.mjs} +14 -0
  7. package/dist/{chunk-6STRIKUA.mjs → chunk-WYCSTAN7.mjs} +1 -1
  8. package/dist/{chunk-734VTGCV.mjs → chunk-XN2NB2NP.mjs} +1 -1
  9. package/dist/events.js +97 -25
  10. package/dist/events.mjs +3 -3
  11. package/dist/index.js +464 -79
  12. package/dist/index.mjs +7 -7
  13. package/dist/modals.mjs +3 -3
  14. package/dist/pages.js +464 -79
  15. package/dist/pages.mjs +6 -6
  16. package/dist/primitives.mjs +1 -1
  17. package/dist/trading.js +65 -32
  18. package/dist/trading.mjs +4 -4
  19. package/dist/types/events/list/event-list.constants.d.mts +3 -1
  20. package/dist/types/events/list/event-list.constants.d.ts +3 -1
  21. package/dist/types/events/list/event-list.types.d.mts +17 -0
  22. package/dist/types/events/list/event-list.types.d.ts +17 -0
  23. package/dist/types/events/list/event-list.utils.d.mts +4 -0
  24. package/dist/types/events/list/event-list.utils.d.ts +4 -0
  25. package/dist/types/events/list/index.d.mts +2 -2
  26. package/dist/types/events/list/index.d.ts +2 -2
  27. package/dist/types/pages/home/event-discovery-url-state.d.mts +35 -0
  28. package/dist/types/pages/home/event-discovery-url-state.d.ts +35 -0
  29. package/dist/types/trading/place-order/index.place-order.utils.d.mts +26 -0
  30. package/dist/types/trading/place-order/index.place-order.utils.d.ts +26 -0
  31. package/package.json +3 -3
@@ -24,7 +24,7 @@ import {
24
24
  resolveUnifiedOrderBookEntries,
25
25
  sortOutcomeSelectorOutcomes,
26
26
  useEventTradingContext
27
- } from "./chunk-6STRIKUA.mjs";
27
+ } from "./chunk-WYCSTAN7.mjs";
28
28
  import {
29
29
  AutocompleteSelect,
30
30
  Badge,
@@ -76,8 +76,9 @@ import {
76
76
  resolveYesOutcome,
77
77
  sortCategoriesForNavigation,
78
78
  sortOutcomes,
79
- splitEventsByLifecycle
80
- } from "./chunk-N7UPPT5J.mjs";
79
+ splitEventsByLifecycle,
80
+ validateSubcategoryPath
81
+ } from "./chunk-RDBMHBR2.mjs";
81
82
 
82
83
  // src/events/item/index.tsx
83
84
  import {
@@ -5427,7 +5428,7 @@ import {
5427
5428
  } from "@agg-build/hooks";
5428
5429
  import { VENUES } from "@agg-build/sdk";
5429
5430
  import * as Dialog from "@radix-ui/react-dialog";
5430
- import { useEffect as useEffect8, useMemo as useMemo10, useRef as useRef8, useState as useState7 } from "react";
5431
+ import { useCallback as useCallback4, useEffect as useEffect8, useMemo as useMemo10, useRef as useRef8, useState as useState7 } from "react";
5431
5432
 
5432
5433
  // src/events/list/category-sidebar.tsx
5433
5434
  import { useMemo as useMemo8 } from "react";
@@ -5548,12 +5549,19 @@ CategorySidebar.displayName = "CategorySidebar";
5548
5549
 
5549
5550
  // src/events/list/event-list-tabs.tsx
5550
5551
  import { getVenueAvailabilityState, useAppConfig, useGeoBlock, useLabels as useLabels9 } from "@agg-build/hooks";
5551
- import { isVenueInactive } from "@agg-build/sdk";
5552
+ import { getEffectiveDisabledVenues, isVenueInactive } from "@agg-build/sdk";
5552
5553
  import { useCallback as useCallback3, useEffect as useEffect7, useMemo as useMemo9, useRef as useRef7, useState as useState6 } from "react";
5553
5554
 
5554
5555
  // src/events/list/event-list.constants.ts
5555
5556
  import { MatchStatus, Venue as Venue2 } from "@agg-build/sdk";
5556
5557
  var DEFAULT_EVENTS_LIMIT = 50;
5558
+ var DEFAULT_EVENT_LIST_SORT = "volume24hr";
5559
+ var EVENT_LIST_SORT_VALUES = [
5560
+ "volume24hr",
5561
+ "topArbitrage",
5562
+ "volume",
5563
+ "endDate"
5564
+ ];
5557
5565
  var getDefaultEventListTabs = (labels) => {
5558
5566
  return [
5559
5567
  {
@@ -5623,6 +5631,7 @@ var getDefaultEventListTabs = (labels) => {
5623
5631
 
5624
5632
  // src/events/list/event-list-tabs.tsx
5625
5633
  import { jsx as jsx13 } from "react/jsx-runtime";
5634
+ var DEFAULT_HIDDEN_VENUES = new Set(getEffectiveDisabledVenues(void 0));
5626
5635
  var renderTabIcon = (tab, isActive) => {
5627
5636
  if (tab.iconName === "warning-filled") {
5628
5637
  return /* @__PURE__ */ jsx13(Icon, { name: "warning-filled", size: "small", color: "currentColor" });
@@ -5651,15 +5660,11 @@ var useEventListTabs = (tabs) => {
5651
5660
  const availabilityState = getVenueAvailabilityState({
5652
5661
  venueId: tab.venueLogo,
5653
5662
  disabledVenues,
5654
- // A compile-time-inactive venue (novig today) is hidden by default and
5655
- // un-hidden per-environment by NOVIG_DATA_VISIBLE, so its
5656
- // disabled-ness is only known once `/app/config` resolves — treating
5657
- // it as hidden while that request is in flight stops its tab flashing
5658
- // in and out where the flag is unset. Active venues must NOT be
5659
- // withheld, or they pop in late. Keyed off the shared inactive-venue
5660
- // helper rather than a venue name, so launching or retiring one needs
5661
- // no change here.
5662
- isConfigLoading: isAppConfigLoading && isVenueInactive(tab.venueLogo),
5663
+ // A globally inactive or default-disabled venue is hidden until
5664
+ // `/app/config` resolves. That prevents partner-opt-in venues such as
5665
+ // Novig from flashing briefly for apps that still disable them, while
5666
+ // ordinary active venues continue rendering immediately.
5667
+ isConfigLoading: isAppConfigLoading && (isVenueInactive(tab.venueLogo) || DEFAULT_HIDDEN_VENUES.has(tab.venueLogo)),
5663
5668
  isLocationBlocked
5664
5669
  });
5665
5670
  if (availabilityState === "hidden") return [];
@@ -5837,10 +5842,16 @@ var EventList = ({
5837
5842
  getMarketHref,
5838
5843
  getEventHref,
5839
5844
  initialVenueTab,
5845
+ activeVenueTab: controlledActiveVenueTab,
5846
+ onActiveVenueTabChange,
5847
+ selectedSort: controlledSelectedSort,
5848
+ onSelectedSortChange,
5849
+ categoryPath: controlledCategoryPath,
5850
+ onCategoryPathChange,
5840
5851
  initialLoadedPageCount,
5841
5852
  stateRef
5842
5853
  }) => {
5843
- var _a, _b, _c, _d, _e;
5854
+ var _a, _b, _c, _d, _e, _f;
5844
5855
  const labels = useLabels10();
5845
5856
  const { disabledVenues } = useAppConfig2();
5846
5857
  const {
@@ -5852,13 +5863,37 @@ var EventList = ({
5852
5863
  () => disabledVenues.length === 0 ? void 0 : getVisibleVenueIdsByConfig(VENUES, disabledVenues),
5853
5864
  [disabledVenues]
5854
5865
  );
5855
- const [activeTabValue, setActiveTabValue] = useState7(
5866
+ const [internalActiveTabValue, setInternalActiveTabValue] = useState7(
5856
5867
  (_b = initialVenueTab != null ? initialVenueTab : (_a = resolvedTabs[0]) == null ? void 0 : _a.value) != null ? _b : "matched"
5857
5868
  );
5858
- const [selectedSort, setSelectedSort] = useState7("volume24hr");
5869
+ const activeTabValue = controlledActiveVenueTab != null ? controlledActiveVenueTab : internalActiveTabValue;
5870
+ const [internalSelectedSort, setInternalSelectedSort] = useState7(DEFAULT_EVENT_LIST_SORT);
5871
+ const selectedSort = controlledSelectedSort != null ? controlledSelectedSort : internalSelectedSort;
5859
5872
  const [isSubcategoriesModalOpen, setIsSubcategoriesModalOpen] = useState7(false);
5860
- const [categoryPath, setCategoryPath] = useState7([]);
5873
+ const [internalCategoryPath, setInternalCategoryPath] = useState7([]);
5874
+ const categoryPath = controlledCategoryPath != null ? controlledCategoryPath : internalCategoryPath;
5861
5875
  const [collapsedCategoryIds, setCollapsedCategoryIds] = useState7(() => /* @__PURE__ */ new Set());
5876
+ const handleActiveTabChange = useCallback4(
5877
+ (value) => {
5878
+ if (controlledActiveVenueTab == null) setInternalActiveTabValue(value);
5879
+ onActiveVenueTabChange == null ? void 0 : onActiveVenueTabChange(value, { history: "push" });
5880
+ },
5881
+ [controlledActiveVenueTab, onActiveVenueTabChange]
5882
+ );
5883
+ const handleSelectedSortChange = useCallback4(
5884
+ (value) => {
5885
+ if (controlledSelectedSort == null) setInternalSelectedSort(value);
5886
+ onSelectedSortChange == null ? void 0 : onSelectedSortChange(value, { history: "push" });
5887
+ },
5888
+ [controlledSelectedSort, onSelectedSortChange]
5889
+ );
5890
+ const handleCategoryPathChange = useCallback4(
5891
+ (value, options) => {
5892
+ if (controlledCategoryPath == null) setInternalCategoryPath(value);
5893
+ onCategoryPathChange == null ? void 0 : onCategoryPathChange(value, options);
5894
+ },
5895
+ [controlledCategoryPath, onCategoryPathChange]
5896
+ );
5862
5897
  const sortItems = useMemo10(() => {
5863
5898
  return [
5864
5899
  {
@@ -5891,9 +5926,9 @@ var EventList = ({
5891
5926
  const baseCategoryId = (_c = categoryIds == null ? void 0 : categoryIds[0]) != null ? _c : null;
5892
5927
  useEffect8(() => {
5893
5928
  if (!isDiscoveryFiltersEnabled) return;
5894
- setCategoryPath([]);
5929
+ if (controlledCategoryPath == null) setInternalCategoryPath([]);
5895
5930
  setCollapsedCategoryIds(/* @__PURE__ */ new Set());
5896
- }, [baseCategoryId, isDiscoveryFiltersEnabled]);
5931
+ }, [baseCategoryId, controlledCategoryPath, isDiscoveryFiltersEnabled]);
5897
5932
  const { categories: topLevelCategories } = useCategories({
5898
5933
  queryKeyScope: "event-list-top-categories",
5899
5934
  enabled: isDiscoveryFiltersEnabled,
@@ -5905,12 +5940,13 @@ var EventList = ({
5905
5940
  const baseCategoryChildPrefetchIds = useMemo10(() => {
5906
5941
  return Array.from(
5907
5942
  /* @__PURE__ */ new Set([
5943
+ ...baseCategoryId ? [baseCategoryId] : [],
5908
5944
  ...sortedTopLevelCategories.map((category) => category.id),
5909
5945
  ...categoryPath.map((category) => category.id)
5910
5946
  ])
5911
5947
  );
5912
- }, [categoryPath, sortedTopLevelCategories]);
5913
- const { childrenByParentId: baseChildrenByParentId } = useCategoryChildren({
5948
+ }, [baseCategoryId, categoryPath, sortedTopLevelCategories]);
5949
+ const { childrenByParentId: baseChildrenByParentId, isLoading: isBaseCategoryChildrenLoading } = useCategoryChildren({
5914
5950
  queryKeyScope: "event-list-category-children",
5915
5951
  enabled: isDiscoveryFiltersEnabled,
5916
5952
  parentIds: baseCategoryChildPrefetchIds,
@@ -5960,7 +5996,36 @@ var EventList = ({
5960
5996
  ...visibleGrandchildrenByParentId
5961
5997
  ]);
5962
5998
  }, [baseChildrenByParentId, visibleChildrenByParentId, visibleGrandchildrenByParentId]);
5963
- const shouldRenderSubcategoryFilters = isDiscoveryFiltersEnabled && baseCategoryId !== null && (((_e = (_d = childrenByParentId.get(baseCategoryId)) == null ? void 0 : _d.length) != null ? _e : 0) > 0 || categoryPath.length > 0);
5999
+ const controlledCategoryPathKey = (_d = controlledCategoryPath == null ? void 0 : controlledCategoryPath.map((entry) => entry.id).join(",")) != null ? _d : "";
6000
+ const controlledCategoryPathValidationKey = `${baseCategoryId != null ? baseCategoryId : ""}|${controlledCategoryPathKey}`;
6001
+ const [validatedCategoryPathKey, setValidatedCategoryPathKey] = useState7(
6002
+ () => controlledCategoryPath == null || controlledCategoryPath.length === 0 ? controlledCategoryPathValidationKey : ""
6003
+ );
6004
+ useEffect8(() => {
6005
+ if (controlledCategoryPath == null || controlledCategoryPath.length === 0) {
6006
+ setValidatedCategoryPathKey(controlledCategoryPathValidationKey);
6007
+ return;
6008
+ }
6009
+ if (isBaseCategoryChildrenLoading) return;
6010
+ const requestedIds = controlledCategoryPath.map((entry) => entry.id);
6011
+ const validIds = validateSubcategoryPath(requestedIds, baseCategoryId, baseChildrenByParentId);
6012
+ if (validIds.length !== requestedIds.length) {
6013
+ handleCategoryPathChange(controlledCategoryPath.slice(0, validIds.length), {
6014
+ history: "replace"
6015
+ });
6016
+ return;
6017
+ }
6018
+ setValidatedCategoryPathKey(controlledCategoryPathValidationKey);
6019
+ }, [
6020
+ baseCategoryId,
6021
+ baseChildrenByParentId,
6022
+ controlledCategoryPath,
6023
+ controlledCategoryPathKey,
6024
+ controlledCategoryPathValidationKey,
6025
+ handleCategoryPathChange,
6026
+ isBaseCategoryChildrenLoading
6027
+ ]);
6028
+ const shouldRenderSubcategoryFilters = isDiscoveryFiltersEnabled && baseCategoryId !== null && (((_f = (_e = childrenByParentId.get(baseCategoryId)) == null ? void 0 : _e.length) != null ? _f : 0) > 0 || categoryPath.length > 0);
5964
6029
  const baseCategoryEventCount = useMemo10(() => {
5965
6030
  var _a2, _b2;
5966
6031
  return (_b2 = (_a2 = sortedTopLevelCategories.find((c) => c.id === baseCategoryId)) == null ? void 0 : _a2.eventCount) != null ? _b2 : 0;
@@ -6018,7 +6083,8 @@ var EventList = ({
6018
6083
  // markets experience is enabled (the sports event-detail view loads the
6019
6084
  // folded companions via aggKey). Gated on the same flag as that view.
6020
6085
  grouped: showSportsMarkets,
6021
- initialPages: initialLoadedPageCount
6086
+ initialPages: initialLoadedPageCount,
6087
+ enabled: controlledCategoryPath == null || validatedCategoryPathKey === controlledCategoryPathValidationKey
6022
6088
  });
6023
6089
  useEffect8(() => {
6024
6090
  if (stateRef) {
@@ -6079,7 +6145,7 @@ var EventList = ({
6079
6145
  "grid grid-cols-[repeat(auto-fill,minmax(240px,1fr))] md:grid-cols-[repeat(auto-fill,minmax(360px,1fr))] gap-4"
6080
6146
  );
6081
6147
  const handleSelectAllCategories = () => {
6082
- setCategoryPath([]);
6148
+ handleCategoryPathChange([], { history: "push" });
6083
6149
  setCollapsedCategoryIds(/* @__PURE__ */ new Set());
6084
6150
  onCategoryRootChange == null ? void 0 : onCategoryRootChange(baseCategoryId != null ? baseCategoryId : void 0);
6085
6151
  setIsSubcategoriesModalOpen(false);
@@ -6091,7 +6157,7 @@ var EventList = ({
6091
6157
  isExpanded,
6092
6158
  isSelected
6093
6159
  }) => {
6094
- setCategoryPath((prev) => [...prev.slice(0, depth), entry]);
6160
+ handleCategoryPathChange([...categoryPath.slice(0, depth), entry], { history: "push" });
6095
6161
  setCollapsedCategoryIds((prev) => {
6096
6162
  const next = new Set(prev);
6097
6163
  if (hasKnownChildren && isExpanded && isSelected) {
@@ -6131,7 +6197,7 @@ var EventList = ({
6131
6197
  ariaLabel: labels.eventList.tabsAria(title),
6132
6198
  className: "agg-event-list-tabs min-w-0 flex-1 max-w-[600px]!",
6133
6199
  activeTab: activeTabValue,
6134
- onTabChange: setActiveTabValue,
6200
+ onTabChange: handleActiveTabChange,
6135
6201
  overflowBehavior: "scroll"
6136
6202
  }
6137
6203
  ),
@@ -6141,7 +6207,7 @@ var EventList = ({
6141
6207
  ariaLabel: labels.eventList.sortByLabel,
6142
6208
  className: "min-w-[200px] w-auto! shrink-0 min-h-10.5",
6143
6209
  value: selectedSort,
6144
- onChange: setSelectedSort,
6210
+ onChange: handleSelectedSortChange,
6145
6211
  items: sortItems,
6146
6212
  contentClassName: "py-2",
6147
6213
  triggerClassName: "rounded-agg-lg!"
@@ -6158,7 +6224,7 @@ var EventList = ({
6158
6224
  ariaLabel: labels.eventList.tabsAria(title),
6159
6225
  className: "agg-event-list-tabs min-w-0 flex-1",
6160
6226
  activeTab: activeTabValue,
6161
- onTabChange: setActiveTabValue,
6227
+ onTabChange: handleActiveTabChange,
6162
6228
  overflowBehavior: "select"
6163
6229
  }
6164
6230
  ),
@@ -6168,7 +6234,7 @@ var EventList = ({
6168
6234
  ariaLabel: labels.eventList.sortByLabel,
6169
6235
  className: "min-w-0 flex-1 md:min-w-[144px]",
6170
6236
  value: selectedSort,
6171
- onChange: setSelectedSort,
6237
+ onChange: handleSelectedSortChange,
6172
6238
  items: sortItems,
6173
6239
  contentClassName: "rounded-[12px] py-2 shadow-[0_8px_16px_rgba(0,0,0,0.1)]"
6174
6240
  }
@@ -6323,6 +6389,8 @@ export {
6323
6389
  MarketDetails,
6324
6390
  MarketDetailsList,
6325
6391
  DEFAULT_EVENTS_LIMIT,
6392
+ DEFAULT_EVENT_LIST_SORT,
6393
+ EVENT_LIST_SORT_VALUES,
6326
6394
  useEventListTabs,
6327
6395
  EventListTabs,
6328
6396
  useEventListTabsHeaderOverflow,
@@ -9,12 +9,12 @@ import {
9
9
  getTradingVenueLabel,
10
10
  prepareSettlementDifferences,
11
11
  resolveOrderEligibilityMessage
12
- } from "./chunk-6STRIKUA.mjs";
12
+ } from "./chunk-WYCSTAN7.mjs";
13
13
  import {
14
14
  ConnectKalshiModal,
15
15
  GeoBlockBanner,
16
16
  subscribeAggDepositNotification
17
- } from "./chunk-734VTGCV.mjs";
17
+ } from "./chunk-XN2NB2NP.mjs";
18
18
  import {
19
19
  AGG_TERMS_OF_SERVICE_URL,
20
20
  Button,
@@ -47,7 +47,7 @@ import {
47
47
  resolveResolvedOutcomeLabel,
48
48
  skeletonViews,
49
49
  useOptionalToast
50
- } from "./chunk-N7UPPT5J.mjs";
50
+ } from "./chunk-RDBMHBR2.mjs";
51
51
 
52
52
  // src/trading/types.ts
53
53
  import { Venue, enumGuard, isFiniteNonNeg, safeParse } from "@agg-build/sdk";
@@ -993,6 +993,37 @@ var findMatchingVenueOutcome = (market, selectedOutcome) => {
993
993
  return normalizedLabel !== "" && selectedNames.has(normalizedLabel);
994
994
  })) != null ? _b : null;
995
995
  };
996
+ var resolveSellableSharesByVenue = ({
997
+ positions,
998
+ market,
999
+ selectedOutcome
1000
+ }) => {
1001
+ var _a, _b, _c, _d, _e, _f, _g;
1002
+ const sharesByVenue = /* @__PURE__ */ new Map();
1003
+ if (!market || !selectedOutcome) return sharesByVenue;
1004
+ const normalizedSelectedOutcomeLabel = normalizeOutcomeName(selectedOutcome.label);
1005
+ const selectedMarketIdSet = new Set(
1006
+ [
1007
+ market.id,
1008
+ (_a = market.marketId) != null ? _a : void 0,
1009
+ (_b = market.externalIdentifier) != null ? _b : void 0,
1010
+ ...((_c = market.matchedVenueMarkets) != null ? _c : []).map((matched) => matched.id)
1011
+ ].filter((value) => Boolean(value))
1012
+ );
1013
+ for (const group of positions) {
1014
+ for (const outcome of (_e = (_d = group.venueMarket) == null ? void 0 : _d.venueMarketOutcomes) != null ? _e : []) {
1015
+ if (normalizeOutcomeName(outcome.label) !== normalizedSelectedOutcomeLabel) continue;
1016
+ for (const breakdown of (_f = outcome.venueBreakdown) != null ? _f : []) {
1017
+ const matchesMarketId = selectedMarketIdSet.size === 0 || selectedMarketIdSet.has(group.targetMarketId) || selectedMarketIdSet.has(breakdown.venueMarketId);
1018
+ if (!matchesMarketId) continue;
1019
+ const size = Number.isFinite(breakdown.size) ? breakdown.size : 0;
1020
+ if (size <= 0) continue;
1021
+ sharesByVenue.set(breakdown.venue, ((_g = sharesByVenue.get(breakdown.venue)) != null ? _g : 0) + size);
1022
+ }
1023
+ }
1024
+ }
1025
+ return sharesByVenue;
1026
+ };
996
1027
  var buildLimitOrderVenueOptions = ({
997
1028
  currentPrices,
998
1029
  livePrices,
@@ -1077,7 +1108,7 @@ var getSmartRouteTotalFees = (feeBreakdown) => {
1077
1108
  if (!feeBreakdown) return null;
1078
1109
  const feeParts = [feeBreakdown.venueFees, feeBreakdown.bridgeFees, feeBreakdown.executionGas];
1079
1110
  if (!feeParts.every(Number.isFinite)) return null;
1080
- return feeParts.reduce((total, fee) => total + fee, 0);
1111
+ return feeParts.reduce((total, fee) => total + Math.round(fee * 100) / 100, 0);
1081
1112
  };
1082
1113
  var getPlaceOrderContainerClassName = () => {
1083
1114
  return PLACE_ORDER_CONTAINER_CLASS_NAME;
@@ -1339,7 +1370,7 @@ var buildLiveRouteCards = ({
1339
1370
  // balance condition, and `handleExecuteQuote` rejects an empty quoteId.
1340
1371
  sq.venue !== primaryWinnerVenue
1341
1372
  ).map((sq) => {
1342
- var _a2;
1373
+ var _a2, _b2;
1343
1374
  const parsedVenue = parseVenue(sq.venue);
1344
1375
  const venue = parsedVenue.success ? parsedVenue.data : void 0;
1345
1376
  if (geoBlockedVenues.has(sq.venue)) {
@@ -1372,7 +1403,12 @@ var buildLiveRouteCards = ({
1372
1403
  estimatedProfit: sq.estimatedProfit,
1373
1404
  returnPct: sq.returnPct,
1374
1405
  // venueSoloQuotes stripped on solo card's quoteData (only the primary needs them)
1375
- venueSoloQuotes: void 0
1406
+ venueSoloQuotes: void 0,
1407
+ // This solo's OWN fee breakdown. Without it the spread above leaves the
1408
+ // primary route's breakdown in place, so selecting a bridge-free venue
1409
+ // still showed the primary's bridging charge. Falls back to the
1410
+ // primary only when the router omitted one (non-"ok" solos).
1411
+ feeBreakdown: (_b2 = sq.feeBreakdown) != null ? _b2 : quoteData.feeBreakdown
1376
1412
  }), sq.quoteId ? { status: "ok", error: void 0 } : null);
1377
1413
  return {
1378
1414
  id: `live-solo-${sq.venue}`,
@@ -4250,6 +4286,14 @@ var PlaceOrder = ({
4250
4286
  enabled: Boolean(isAuthenticated && isSell),
4251
4287
  mode: isPaperMode ? "paper" : void 0
4252
4288
  });
4289
+ const sellableSharesByVenue = useMemo(
4290
+ () => isSell ? resolveSellableSharesByVenue({
4291
+ positions: executionPositions,
4292
+ market: scopedSelectedMarket,
4293
+ selectedOutcome: scopedSelectedOutcome
4294
+ }) : /* @__PURE__ */ new Map(),
4295
+ [executionPositions, isSell, scopedSelectedMarket, scopedSelectedOutcome]
4296
+ );
4253
4297
  const isSmartRouteEnabled = !isLimitOrder && isQuotePanelActive && !isEndedWithoutKnownWinner && !submissionProgressState && !isBeforeActionPending && !executeManaged.isPending && debouncedAmount > 0 && orderEligibility.canPlaceOrder && // On the sell tab, hold the quote until the amount has been initialized
4254
4298
  // from the user's position for THIS outcome AND the debounced value has
4255
4299
  // caught up to it. The amount input is shared with the buy tab, so right
@@ -4300,13 +4344,26 @@ var PlaceOrder = ({
4300
4344
  }, [limitVenueQuotes.quotes]);
4301
4345
  const availableLimitVenueOptions = useMemo(() => {
4302
4346
  return visibleLimitVenueOptions.filter((option) => {
4303
- return !geoBlockedLimitVenues.has(option.venue) && getVenueAvailabilityState({
4347
+ var _a2;
4348
+ return !geoBlockedLimitVenues.has(option.venue) && // A limit SELL rests against shares held at that specific venue, so a
4349
+ // venue the user has no position on is a guaranteed 409 from the
4350
+ // server's reservation check — and the automatic pick, which sorts on
4351
+ // price alone, would happily choose one. Only narrow once we know
4352
+ // where the shares are; an empty map means positions haven't resolved.
4353
+ (!isSell || sellableSharesByVenue.size === 0 || ((_a2 = sellableSharesByVenue.get(option.venue)) != null ? _a2 : 0) > 0) && getVenueAvailabilityState({
4304
4354
  venueId: option.venue,
4305
4355
  disabledVenues,
4306
4356
  isConfigLoading: isAppConfigLoading
4307
4357
  }) === "available";
4308
4358
  });
4309
- }, [disabledVenues, geoBlockedLimitVenues, isAppConfigLoading, visibleLimitVenueOptions]);
4359
+ }, [
4360
+ disabledVenues,
4361
+ geoBlockedLimitVenues,
4362
+ isAppConfigLoading,
4363
+ isSell,
4364
+ sellableSharesByVenue,
4365
+ visibleLimitVenueOptions
4366
+ ]);
4310
4367
  const automaticLimitVenueOption = useMemo(
4311
4368
  () => resolveAutomaticLimitOrderVenueOption(availableLimitVenueOptions, internalTab),
4312
4369
  [availableLimitVenueOptions, internalTab]
@@ -4408,39 +4465,15 @@ var PlaceOrder = ({
4408
4465
  refreshContext: smartRouteRefreshContext
4409
4466
  });
4410
4467
  const currentSellableShares = useMemo(() => {
4411
- var _a2, _b2, _c2, _d2, _e2, _f2, _g2;
4468
+ var _a2, _b2;
4412
4469
  const sharesFromQuote = (_b2 = (_a2 = smartRoute.data) == null ? void 0 : _a2.positionAvailability) == null ? void 0 : _b2.totalSellableShares;
4413
4470
  if (typeof sharesFromQuote === "number" && Number.isFinite(sharesFromQuote)) {
4414
4471
  return Math.max(0, sharesFromQuote);
4415
4472
  }
4416
- if (!isSell || !scopedSelectedOutcome || !scopedSelectedMarket) return 0;
4417
- const normalizedSelectedOutcomeLabel = scopedSelectedOutcome.label.trim().toLowerCase();
4418
- const selectedMarketIds = [
4419
- scopedSelectedMarket.id,
4420
- (_c2 = scopedSelectedMarket.marketId) != null ? _c2 : void 0,
4421
- (_d2 = scopedSelectedMarket.externalIdentifier) != null ? _d2 : void 0
4422
- ].filter((value) => Boolean(value));
4423
- const selectedMarketIdSet = new Set(selectedMarketIds);
4424
4473
  let resolvedShares = 0;
4425
- for (const group of executionPositions) {
4426
- const groupOutcomes = (_f2 = (_e2 = group.venueMarket) == null ? void 0 : _e2.venueMarketOutcomes) != null ? _f2 : [];
4427
- for (const outcome of groupOutcomes) {
4428
- if (outcome.label.trim().toLowerCase() !== normalizedSelectedOutcomeLabel) continue;
4429
- for (const breakdown of (_g2 = outcome.venueBreakdown) != null ? _g2 : []) {
4430
- const matchesMarketId = selectedMarketIdSet.size === 0 || selectedMarketIdSet.has(group.targetMarketId) || selectedMarketIdSet.has(breakdown.venueMarketId);
4431
- if (!matchesMarketId) continue;
4432
- resolvedShares += Number.isFinite(breakdown.size) ? breakdown.size : 0;
4433
- }
4434
- }
4435
- }
4474
+ for (const size of sellableSharesByVenue.values()) resolvedShares += size;
4436
4475
  return Math.max(0, resolvedShares);
4437
- }, [
4438
- executionPositions,
4439
- isSell,
4440
- scopedSelectedMarket,
4441
- scopedSelectedOutcome,
4442
- (_q = (_p = smartRoute.data) == null ? void 0 : _p.positionAvailability) == null ? void 0 : _q.totalSellableShares
4443
- ]);
4476
+ }, [sellableSharesByVenue, (_q = (_p = smartRoute.data) == null ? void 0 : _p.positionAvailability) == null ? void 0 : _q.totalSellableShares]);
4444
4477
  const maxSellableShares = useMemo(
4445
4478
  () => floorToDecimals(currentSellableShares, SELL_SHARE_INPUT_DECIMALS),
4446
4479
  [currentSellableShares]
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  ConnectKalshiModal,
4
4
  dispatchAggDepositNotification
5
- } from "./chunk-734VTGCV.mjs";
5
+ } from "./chunk-XN2NB2NP.mjs";
6
6
  import {
7
7
  BoltIcon,
8
8
  Button,
@@ -35,7 +35,7 @@ import {
35
35
  shortenAddress,
36
36
  useOptionalToast,
37
37
  venueLogoLabels
38
- } from "./chunk-N7UPPT5J.mjs";
38
+ } from "./chunk-RDBMHBR2.mjs";
39
39
 
40
40
  // src/deposit/index.tsx
41
41
  import { useAggAuthState, useAggUiConfig, useDepositAddresses, useLabels as useLabels11 } from "@agg-build/hooks";
@@ -5435,6 +5435,19 @@ var resolveCategoryIdsFromPath = (path, fallbackCategoryIds) => {
5435
5435
  if (deepest) return [deepest];
5436
5436
  return fallbackCategoryIds;
5437
5437
  };
5438
+ var validateSubcategoryPath = (requestedPath, rootCategoryId, childrenByParentId) => {
5439
+ var _a;
5440
+ if (!rootCategoryId) return [];
5441
+ const validPath = [];
5442
+ let parentId = rootCategoryId;
5443
+ for (const categoryId of requestedPath) {
5444
+ const category = (_a = childrenByParentId.get(parentId)) == null ? void 0 : _a.find((child) => child.id === categoryId);
5445
+ if (!category) break;
5446
+ validPath.push(category.id);
5447
+ parentId = category.id;
5448
+ }
5449
+ return validPath;
5450
+ };
5438
5451
  var resolveTabVenus = (tab, visibleVenues) => {
5439
5452
  const applyAllowList = (venues) => {
5440
5453
  if (!venues) {
@@ -10197,6 +10210,7 @@ export {
10197
10210
  filterEventsByTabValue,
10198
10211
  sortCategoriesForNavigation,
10199
10212
  resolveCategoryIdsFromPath,
10213
+ validateSubcategoryPath,
10200
10214
  resolveTabVenus,
10201
10215
  SkeletonBlock,
10202
10216
  RemoteImage,
@@ -19,7 +19,7 @@ import {
19
19
  selectPrimaryVenueMarket,
20
20
  skeletonViews,
21
21
  sortOutcomes
22
- } from "./chunk-N7UPPT5J.mjs";
22
+ } from "./chunk-RDBMHBR2.mjs";
23
23
 
24
24
  // src/trading/trading-context/index.tsx
25
25
  import { useEventTradingContext } from "@agg-build/hooks";
@@ -18,7 +18,7 @@ import {
18
18
  __spreadProps,
19
19
  __spreadValues,
20
20
  cn
21
- } from "./chunk-N7UPPT5J.mjs";
21
+ } from "./chunk-RDBMHBR2.mjs";
22
22
 
23
23
  // src/geo-block-banner/index.tsx
24
24
  import { useLabels } from "@agg-build/hooks";