@lifi/widget 4.7.1 → 4.8.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.
Files changed (115) hide show
  1. package/dist/esm/components/AmountInput/AmountInput.style.d.ts.map +1 -1
  2. package/dist/esm/components/Card/Card.d.ts.map +1 -1
  3. package/dist/esm/components/Card/CardIconButton.d.ts.map +1 -1
  4. package/dist/esm/components/ContractComponent/ItemPrice.d.ts.map +1 -1
  5. package/dist/esm/components/ListItem/ListItemButton.d.ts.map +1 -1
  6. package/dist/esm/components/ListItemButton.d.ts.map +1 -1
  7. package/dist/esm/components/Token/Token.d.ts.map +1 -1
  8. package/dist/esm/components/TokenList/types.d.ts.map +1 -1
  9. package/dist/esm/config/version.d.ts +1 -1
  10. package/dist/esm/config/version.js +1 -1
  11. package/dist/esm/config/version.js.map +1 -1
  12. package/dist/esm/hooks/useAvailableChains.d.ts.map +1 -1
  13. package/dist/esm/hooks/useAvailableChains.js +21 -38
  14. package/dist/esm/hooks/useAvailableChains.js.map +1 -1
  15. package/dist/esm/hooks/useFromTokenSufficiency.js +3 -3
  16. package/dist/esm/hooks/useFromTokenSufficiency.js.map +1 -1
  17. package/dist/esm/hooks/useGasRecommendation.js +3 -3
  18. package/dist/esm/hooks/useGasRecommendation.js.map +1 -1
  19. package/dist/esm/hooks/useGasSufficiency.js +3 -3
  20. package/dist/esm/hooks/useGasSufficiency.js.map +1 -1
  21. package/dist/esm/hooks/useIsBatchingSupported.js +2 -2
  22. package/dist/esm/hooks/useIsBatchingSupported.js.map +1 -1
  23. package/dist/esm/hooks/useRouteExecution.js +6 -6
  24. package/dist/esm/hooks/useRouteExecution.js.map +1 -1
  25. package/dist/esm/hooks/useRoutes.js +7 -7
  26. package/dist/esm/hooks/useRoutes.js.map +1 -1
  27. package/dist/esm/hooks/useTokenBalance.js +4 -4
  28. package/dist/esm/hooks/useTokenBalance.js.map +1 -1
  29. package/dist/esm/hooks/useTokenBalancesQueries.js +3 -3
  30. package/dist/esm/hooks/useTokenBalancesQueries.js.map +1 -1
  31. package/dist/esm/hooks/useTokenSearch.js +3 -3
  32. package/dist/esm/hooks/useTokenSearch.js.map +1 -1
  33. package/dist/esm/hooks/useTokens.js +14 -14
  34. package/dist/esm/hooks/useTokens.js.map +1 -1
  35. package/dist/esm/hooks/useTools.d.ts.map +1 -1
  36. package/dist/esm/hooks/useTools.js +26 -27
  37. package/dist/esm/hooks/useTools.js.map +1 -1
  38. package/dist/esm/hooks/useTransactionDetails.js +2 -2
  39. package/dist/esm/hooks/useTransactionDetails.js.map +1 -1
  40. package/dist/esm/hooks/useTransactionHistory.js +3 -3
  41. package/dist/esm/hooks/useTransactionHistory.js.map +1 -1
  42. package/dist/esm/index.d.ts +5 -1
  43. package/dist/esm/index.js +3 -1
  44. package/dist/esm/pages/RoutesPage/RoutesPage.style.d.ts.map +1 -1
  45. package/dist/esm/providers/I18nProvider/types.d.ts.map +1 -1
  46. package/dist/esm/providers/WidgetProvider/WidgetProvider.d.ts.map +1 -1
  47. package/dist/esm/providers/WidgetProvider/WidgetProvider.js +9 -1
  48. package/dist/esm/providers/WidgetProvider/WidgetProvider.js.map +1 -1
  49. package/dist/esm/providers/WidgetProvider/types.d.ts +2 -0
  50. package/dist/esm/providers/WidgetProvider/types.d.ts.map +1 -1
  51. package/dist/esm/queries/getChains.d.ts +38 -0
  52. package/dist/esm/queries/getChains.d.ts.map +1 -0
  53. package/dist/esm/queries/getChains.js +51 -0
  54. package/dist/esm/queries/getChains.js.map +1 -0
  55. package/dist/esm/queries/getTools.d.ts +26 -0
  56. package/dist/esm/queries/getTools.d.ts.map +1 -0
  57. package/dist/esm/queries/getTools.js +30 -0
  58. package/dist/esm/queries/getTools.js.map +1 -0
  59. package/dist/esm/queries/index.d.ts +4 -0
  60. package/dist/esm/queries/index.js +3 -0
  61. package/dist/esm/queries/types.d.ts +25 -0
  62. package/dist/esm/queries/types.d.ts.map +1 -0
  63. package/dist/esm/shared.d.ts +2 -1
  64. package/dist/esm/shared.js +2 -1
  65. package/dist/esm/stores/StoreProvider.d.ts.map +1 -1
  66. package/dist/esm/stores/StoreProvider.js +16 -17
  67. package/dist/esm/stores/StoreProvider.js.map +1 -1
  68. package/dist/esm/stores/header/useHeaderStore.d.ts +1 -1
  69. package/dist/esm/stores/header/useHeaderStore.d.ts.map +1 -1
  70. package/dist/esm/stores/header/useHeaderStore.js.map +1 -1
  71. package/dist/esm/themes/createTheme.d.ts.map +1 -1
  72. package/dist/esm/types/events.d.ts.map +1 -1
  73. package/dist/esm/types/token.d.ts.map +1 -1
  74. package/dist/esm/types/widget.d.ts +30 -0
  75. package/dist/esm/types/widget.d.ts.map +1 -1
  76. package/dist/esm/types/widget.js.map +1 -1
  77. package/dist/esm/utils/queries.js.map +1 -1
  78. package/dist/esm/utils/scopeKeys.d.ts +6 -0
  79. package/dist/esm/utils/scopeKeys.d.ts.map +1 -0
  80. package/dist/esm/utils/scopeKeys.js +8 -0
  81. package/dist/esm/utils/scopeKeys.js.map +1 -0
  82. package/package.json +12 -4
  83. package/src/config/version.ts +1 -1
  84. package/src/hooks/useAvailableChains.test.tsx +170 -0
  85. package/src/hooks/useAvailableChains.ts +29 -47
  86. package/src/hooks/useFromTokenSufficiency.ts +2 -2
  87. package/src/hooks/useGasRecommendation.ts +2 -2
  88. package/src/hooks/useGasSufficiency.ts +2 -2
  89. package/src/hooks/useIsBatchingSupported.ts +2 -2
  90. package/src/hooks/useRouteExecution.ts +5 -5
  91. package/src/hooks/useRoutes.ts +6 -6
  92. package/src/hooks/useTokenBalance.ts +4 -4
  93. package/src/hooks/useTokenBalancesQueries.ts +3 -3
  94. package/src/hooks/useTokenSearch.ts +7 -3
  95. package/src/hooks/useTokens.ts +13 -14
  96. package/src/hooks/useTools.sharedEntry.test.tsx +155 -0
  97. package/src/hooks/useTools.ts +42 -37
  98. package/src/hooks/useTransactionDetails.ts +3 -3
  99. package/src/hooks/useTransactionHistory.ts +2 -2
  100. package/src/index.ts +2 -1
  101. package/src/providers/WidgetProvider/WidgetProvider.test.tsx +73 -0
  102. package/src/providers/WidgetProvider/WidgetProvider.tsx +13 -0
  103. package/src/providers/WidgetProvider/types.ts +2 -0
  104. package/src/queries/getChains.ts +93 -0
  105. package/src/queries/getTools.ts +62 -0
  106. package/src/queries/index.ts +30 -0
  107. package/src/queries/sharedCache.test.tsx +223 -0
  108. package/src/queries/types.ts +38 -0
  109. package/src/shared.ts +1 -0
  110. package/src/stores/StoreProvider.test.tsx +107 -0
  111. package/src/stores/StoreProvider.tsx +8 -6
  112. package/src/stores/header/useHeaderStore.tsx +3 -4
  113. package/src/types/widget.ts +30 -0
  114. package/src/utils/queries.ts +1 -0
  115. package/src/utils/scopeKeys.ts +18 -0
@@ -1 +1 @@
1
- {"version":3,"file":"widget.d.ts","names":[],"sources":["../../../src/types/widget.ts"],"mappings":"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"}
1
+ {"version":3,"file":"widget.d.ts","names":[],"sources":["../../../src/types/widget.ts"],"mappings":";;;;;;;;;YAoCY;;YAGA;YACA,yDAKR;YACQ;YACA;EACV,YAAY;;YAEF;iBACK;;;;;;EAMf,QAAQ,YAAY;EACpB;IAAW,MAAM;;;;;;;YAOP,wBAAwB;;YAExB;YAOA,mBAAmB,2BAA2B;YAE9C,aAAa;iBACR;;;;;EAKf;;YAEU,wBAAwB,QAClC,KACE,WAAW;YAeH;EACV;IACE;MACE,SAAS;;IAEX;MACE,SAAS;;;EAGb,QAAQ,QAAQ;EAChB,aAAa;EACb,aAAa;EACb,YAAY;EACZ,kBAAkB;EAClB,wBAAwB;EACxB,SAAS;EACT,aAAa;;iBAGE;EACf;EACA;EACA;EACA;;iBAGe;EACf;EACA;EACA;EACA;EACA;;;;;EAKA;EACA;;;;;EAKA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;;;EAMA;EACA;;;;;EAKA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;iBAGe;EACf;EACA;;YAGU;EACV;EACA;;;;;;;;;EASA;;iBAGe;EACf,wBAAwB,eAAe;EACvC,WAAW,OAAO;;;;;;;;;EASlB;;;;;EAKA;;iBAGe,wBACP,KACN;EAQF,eAAe,KACb;EAGF,mBAAmB,KAAK;;iBAGT;EACf;EACA;;iBAGe;EACf,WAAW;EACX,SAAS;EACT,WAAW;EACX,SAAS;EACT;EACA;EACA;EACA;EACA;;iBAGe;EACf;EACA;EACA;;;;;EAKA;;;;;EAKA;;;;EAIA,sBAAsB;;;;;;;;;EAStB,cAAc,QAAQ,qBAAqB;;iBAG5B;EACf;EACA;EACA,WAAW;EACX;;iBAGe,UAAU;EACzB,QAAQ;EACR,OAAO;;YAGG;iBACK;EACf,QAAQ,IAAI;EACZ,OAAO,IAAI;;YAGD;EACV,OAAO;EACP,KAAK;IACH;YAEQ,eAAe;EACzB,OAAO,UAAU;EACjB,KAAK,UAAU;IACb,UAAU;YAEF;EACV,QAAQ,UAAU;IAChB;YAEQ;EACV,WAAW;EACX,UAAU;EACV,UAAU;EACV,WAAW;IACT,eAAe;YAEP;EACV,UAAU;IACR,UAAU;YAEF;iBAEK;EACf;EACA,KAAK,QAAQ;;iBAGE;EACf,OAAO;EAEP,UAAU;EACV,YAAY;EACZ;EACA;EACA;EACA;;;;;;;;EAQA,SAAS,OAAO;;YAGN;EAGN;EACA;EACA;;YAGM,kBACV,OAAO,kBAAkB,yBACtB;iBAEY;EACf;EACA;EACA;EACA;EACA,YAAY;EACZ,cAAc;EACd;EACA;EACA;EACA;EAEA,YAAY;EAEZ,gBAAgB;EAChB,oBAAoB;EACpB,6BAA6B;EAC7B,2BAA2B;EAC3B,eAAe;EACf;EACA;EACA,YAAY;EACZ;EAEA,gBAAgB;EAChB;EAEA,UAAU;EACV,OAAO;EACP,cAAc;;;;;;;EAOd,kBAAkB;EAElB,aAAa;EACb,QAAQ;EAER,aAAa;EACb,WAAW;EACX,aAAa;EACb,YAAY;;;;;;;EAOZ;EACA;EAEA,eAAe;EACf,YAAY;EAEZ;;;;;EAKA;;;;;;;;;;;;EAYA;;;;;;;;;;;;;;EAcA;EAEA,UAAU;EACV,YAAY;EACZ,SAAS;EACT,SAAS;EACT,YAAY;EACZ,oBAAoB;EACpB,eAAe,eAAe,iBAC5B,QAAQ,mBAAmB;EAC7B,YAAY;;;;EAKZ,cAAc;;iBAGC;EACf;;iBAGe,oBACP,KAAK;EACb;EACA;EACA,YAAY;;YAGF,mBAAmB;YAEnB,yBAAyB,UAAU,YAC7C,KAAK,GACL,OAAO,YAAY,IACnB,UAAU;YAGA;EACV,eAAe;;YAGL,UAAU,UAAU;iBAEf;EACf,UAAU;;iBAGK,0BAA0B;EACzC,QAAQ;;iBAGO;EACf,SAAS,QAAQ;;YAGP,cAAc,oBACxB,eACA,2BACA;iBAEe,0BAA0B;EACzC,aAAa,UAAU;EACvB;;;;EAIA;;oBAGU;EACV;EACA;EACA"}
@@ -1 +1 @@
1
- {"version":3,"file":"widget.js","names":[],"sources":["../../../src/types/widget.ts"],"sourcesContent":["import type {\n BaseToken,\n ChainType,\n ContractCall,\n ExecutionOptions,\n ExtendedChain,\n Order,\n Route,\n RouteOptions,\n SDKConfig,\n StaticToken,\n Token,\n} from '@lifi/sdk'\nimport type { WalletMenuOpenArgs } from '@lifi/wallet-management'\nimport type { WidgetProviderProps } from '@lifi/widget-provider'\nimport type {\n Components,\n PaletteMode,\n PaletteOptions,\n Shape,\n SxProps,\n Theme,\n} from '@mui/material'\nimport type { TypographyVariantsOptions } from '@mui/material/styles'\nimport type {\n CSSProperties,\n PropsWithChildren,\n ReactNode,\n RefObject,\n} from 'react'\nimport type {\n LanguageKey,\n LanguageResources,\n} from '../providers/I18nProvider/types.js'\nimport type { DefaultFieldValues } from '../stores/form/types.js'\n\nexport type WidgetVariant = 'compact' | 'wide' | 'drawer'\n\n/** @internal Not part of the public API. */\nexport type InternalWidgetMode = 'limit'\nexport type WidgetMode =\n | 'default'\n | 'split'\n | 'custom'\n | 'refuel'\n | InternalWidgetMode\nexport type SplitMode = 'bridge' | 'swap'\nexport type SplitModeOptions = {\n defaultTab: SplitMode\n}\nexport type CustomMode = 'checkout' | 'deposit'\nexport interface ModeOptions {\n /**\n * Configure split mode behavior:\n * - 'bridge' | 'swap': Single mode without tabs\n * - { defaultTab: 'bridge' | 'swap' }: Tabs mode with configurable default tab\n */\n split?: SplitMode | SplitModeOptions\n custom?: { type: CustomMode }\n}\n\n/**\n * Identity of a header navigation tab. Each key maps to a widget variant, mode and\n * (optionally) mode options; labels are resolved from the key.\n */\nexport type SplitNavigationTabKey = SplitMode\n/** @internal Not part of the public API. */\nexport type InternalNavigationTabKey =\n | 'default'\n | 'private'\n | 'refuel'\n | 'swap-advanced'\n | 'bridge-advanced'\n | 'limit'\nexport type NavigationTabKey = InternalNavigationTabKey | SplitNavigationTabKey\n\nexport type Appearance = PaletteMode | 'system'\nexport interface NavigationProps {\n /**\n * If given, uses a negative margin to counteract the padding on sides for navigation elements like icon buttons.\n * @default true\n */\n edge?: boolean\n}\nexport type WidgetThemeComponents = Partial<\n Pick<\n Components<Theme>,\n | 'MuiAppBar'\n | 'MuiAvatar'\n | 'MuiButton'\n | 'MuiCard'\n | 'MuiDrawer'\n | 'MuiIconButton'\n | 'MuiInputCard'\n | 'MuiNavigationTabs'\n | 'MuiNavigationTab'\n | 'MuiTabs'\n | 'MuiCheckbox'\n >\n>\n\nexport type WidgetTheme = {\n colorSchemes?: {\n light?: {\n palette: PaletteOptions\n }\n dark?: {\n palette: PaletteOptions\n }\n }\n shape?: Partial<Shape>\n typography?: TypographyVariantsOptions\n components?: WidgetThemeComponents\n container?: CSSProperties\n routesContainer?: CSSProperties\n chainSidebarContainer?: CSSProperties\n header?: CSSProperties\n navigation?: NavigationProps\n}\n\nexport interface DisabledUIConfig {\n fromAmount?: boolean\n fromToken?: boolean\n toAddress?: boolean\n toToken?: boolean\n}\n\nexport interface HiddenUIConfig {\n addressBookConnectedWallets?: boolean\n allNetworks?: boolean\n appearance?: boolean\n bridgesSettings?: boolean\n chainSelect?: boolean\n /**\n * Hide the chain sidebar in the `wide` variant. No effect in other variants.\n * @default false\n */\n chainSidebar?: boolean\n contactSupport?: boolean\n /**\n * Hide the drawer close button. Only meaningful when `variant === 'drawer'`.\n * @default false\n */\n drawerCloseButton?: boolean\n fromToken?: boolean\n gasRefuelMessage?: boolean\n hideSmallBalances?: boolean\n history?: boolean\n insufficientGasMessage?: boolean\n integratorStepDetails?: boolean\n language?: boolean\n /**\n * Hide the warning shown when sending to an address with low historical\n * on-chain activity (low transaction count or contract-like behavior).\n * @default false\n */\n lowAddressActivityConfirmation?: boolean\n poweredBy?: boolean\n /**\n * Hide the \"Recent searches\" section in the token select view.\n * @default false\n */\n recentSearches?: boolean\n reverseTokensButton?: boolean\n routeCardPriceImpact?: boolean\n routeTokenDescription?: boolean\n searchTokenInput?: boolean\n toAddress?: boolean\n toToken?: boolean\n walletMenu?: boolean\n}\n\nexport interface RequiredUIConfig {\n accountDeployedMessage?: boolean\n toAddress?: boolean\n}\n\nexport type DefaultUI = {\n transactionDetailsExpanded?: boolean\n navigationHeaderTitleNoWrap?: boolean\n /**\n * Layout for the main form.\n * - `'default'`: the chain/token selectors plus single amount input.\n * - `'cards'`: the redesigned card-based layout — stacked Send/Receive amount\n * cards (`AmountInputCardPair`) with inline token pill selectors and a swap\n * button.\n * @default 'default'\n */\n layout?: 'default' | 'cards'\n}\n\nexport interface WidgetWalletConfig {\n walletEcosystemsOrder?: Record<string, ChainType[]>\n onConnect?(args?: WalletMenuOpenArgs): void\n /**\n * Determines whether the widget should provide partial wallet management functionality.\n *\n * In partial mode, external wallet management will be used for \"opt-out\" providers,\n * while the internal management is applied for any remaining providers that do not opt out.\n * This allows a flexible balance between the integrator's custom wallet menu and the widget's native wallet menu.\n * @default false\n */\n usePartialWalletManagement?: boolean\n /**\n * This option forces the widget to always use internal wallet management ignoring external wallet management contexts\n * @default false\n */\n forceInternalWalletManagement?: boolean\n}\n\nexport interface WidgetSDKConfig\n extends Omit<\n SDKConfig,\n | 'apiKey'\n | 'disableVersionCheck'\n | 'integrator'\n | 'providers'\n | 'routeOptions'\n | 'widgetVersion'\n > {\n routeOptions?: Omit<\n RouteOptions,\n 'bridges' | 'exchanges' | 'fee' | 'referrer' | 'order' | 'slippage'\n >\n executionOptions?: Pick<ExecutionOptions, 'updateTransactionRequestHook'>\n}\n\nexport interface WidgetContractTool {\n name: string\n logoURI: string\n}\n\nexport interface CalculateFeeParams {\n fromChain: ExtendedChain\n toChain: ExtendedChain\n fromToken: Token\n toToken: Token\n fromAddress?: string\n toAddress?: string\n fromAmount?: bigint\n toAmount?: bigint\n slippage?: number\n}\n\nexport interface WidgetFeeConfig {\n name?: string\n logoURI?: string\n fee?: number\n /**\n * Whether to show the fee percentage in the fee details.\n * @default false\n */\n showFeePercentage?: boolean\n /**\n * Whether to show a tooltip with the fee details. Requires `name` or `feeTooltipComponent` to be set.\n * @default false\n */\n showFeeTooltip?: boolean\n /**\n * Custom tooltip component to show with the fee details.\n */\n feeTooltipComponent?: ReactNode\n /**\n * Function to calculate fees before fetching quotes.\n * If provided, this function will be used instead of the `fee` parameter.\n * Only one of `fee` or `calculateFee` should be used.\n *\n * @param params Object containing the fee calculation parameters\n * @returns A promise that resolves to the calculated fee as a number (e.g., 0.03 represents a 3% fee)\n */\n calculateFee?(params: CalculateFeeParams): Promise<number | undefined>\n}\n\nexport interface ToAddress {\n name?: string\n address: string\n chainType: ChainType\n logoURI?: string\n}\n\nexport interface AllowDeny<T> {\n allow?: T[]\n deny?: T[]\n}\n\nexport type AllowDenySetItem = string | number\nexport interface AllowDenySet {\n allow?: Set<AllowDenySetItem>\n deny?: Set<AllowDenySetItem>\n}\n\nexport type AllowDenySets = {\n from?: AllowDenySet\n to?: AllowDenySet\n} & AllowDenySet\n\nexport type AllowDenyItems<T> = {\n from?: AllowDeny<T>\n to?: AllowDeny<T>\n} & AllowDeny<T>\n\nexport type WidgetChains = {\n types?: AllowDeny<ChainType>\n} & AllowDenyItems<number>\n\nexport type WidgetTokens = {\n featured?: StaticToken[]\n include?: Token[]\n popular?: StaticToken[]\n verified?: BaseToken[]\n} & AllowDenyItems<BaseToken>\n\nexport type WidgetLanguages = {\n default?: LanguageKey\n} & AllowDeny<LanguageKey>\n\nexport type PoweredByType = 'default' | 'jumper'\n\nexport interface RouteLabel {\n text: string\n sx?: SxProps<Theme>\n}\n\nexport interface RouteLabelRule {\n label: RouteLabel\n // Matching criteria\n bridges?: AllowDeny<string>\n exchanges?: AllowDeny<string>\n fromChainId?: number[]\n toChainId?: number[]\n fromTokenAddress?: string[]\n toTokenAddress?: string[]\n /**\n * Custom match function evaluated against the route. When provided, its\n * result is AND'd with the other matching criteria — all specified\n * conditions must pass for the label to apply. Use this for matching logic\n * that the built-in fields cannot express (gas costs, step count, route\n * tags, etc.).\n */\n match?: (route: Route) => boolean\n}\n\nexport type ExplorerUrl =\n | string\n | {\n url: string\n txPath?: string\n addressPath?: string\n }\n\nexport type WidgetProvider = (\n props: PropsWithChildren<WidgetProviderProps>\n) => ReactNode\n\nexport interface WidgetConfig {\n fromChain?: number\n toChain?: number\n fromToken?: string\n toToken?: string\n toAddress?: ToAddress\n toAddresses?: ToAddress[]\n fromAmount?: number | string\n minFromAmountUSD?: number\n toAmount?: number | string\n formUpdateKey?: string\n\n providers?: WidgetProvider[]\n\n contractCalls?: ContractCall[]\n contractComponent?: ReactNode\n contractSecondaryComponent?: ReactNode\n contractCompactComponent?: ReactNode\n contractTool?: WidgetContractTool\n integrator: string\n apiKey?: string\n feeConfig?: WidgetFeeConfig\n referrer?: string\n\n routePriority?: Order\n slippage?: number\n\n variant?: WidgetVariant\n mode?: WidgetMode\n modeOptions?: ModeOptions\n /**\n * Header navigation tabs, in order. When set, the widget renders a tab bar\n * and the active tab drives the displayed flow. Each entry is a tab key.\n *\n * @internal Not part of the public API.\n */\n _navigationTabs?: NavigationTabKey[]\n\n appearance?: Appearance\n theme?: WidgetTheme\n\n disabledUI?: DisabledUIConfig\n hiddenUI?: HiddenUIConfig\n requiredUI?: RequiredUIConfig\n defaultUI?: DefaultUI\n /**\n * When true, shows only the recommended route and hides the route\n * selector UI. Distinct from `routePriority`, which sets the SDK\n * ranking order across multiple displayed routes.\n * @default false\n */\n showSingleRoute?: boolean\n useRelayerRoutes?: boolean\n\n walletConfig?: WidgetWalletConfig\n sdkConfig?: WidgetSDKConfig\n\n buildUrl?: boolean\n keyPrefix?: string\n\n bridges?: AllowDeny<string>\n exchanges?: AllowDeny<string>\n chains?: WidgetChains\n tokens?: WidgetTokens\n languages?: WidgetLanguages\n languageResources?: LanguageResources\n explorerUrls?: Record<number, ExplorerUrl[]> &\n Partial<Record<'internal', ExplorerUrl[]>>\n poweredBy?: PoweredByType\n\n /**\n * Custom labels/badges to show on routes based on specified rules\n */\n routeLabels?: RouteLabelRule[]\n}\n\nexport interface FormFieldOptions {\n setUrlSearchParam: boolean\n}\n\nexport interface FieldValues\n extends Omit<DefaultFieldValues, 'fromAmount' | 'toAmount' | 'toAddress'> {\n fromAmount?: number | string\n toAmount?: number | string\n toAddress?: ToAddress | string\n}\n\nexport type FieldNames = keyof FieldValues\n\nexport type SetFieldValueFunction = <K extends FieldNames>(\n key: K,\n value: FieldValues[K],\n options?: FormFieldOptions\n) => void\n\nexport type FormState = {\n setFieldValue: SetFieldValueFunction\n}\n\nexport type FormRef = RefObject<FormState | null>\n\nexport interface FormRefProps {\n formRef?: FormRef\n}\n\nexport interface WidgetConfigProps extends FormRefProps {\n config: WidgetConfig\n}\n\nexport interface WidgetConfigPartialProps {\n config?: Partial<WidgetConfig>\n}\n\nexport type WidgetProps = WidgetDrawerProps &\n WidgetConfig &\n WidgetConfigPartialProps &\n FormRefProps\n\nexport interface WidgetDrawerProps extends WidgetConfigPartialProps {\n elementRef?: RefObject<HTMLDivElement>\n open?: boolean\n /**\n * Make sure to make the onClose callback stable (e.g. using useCallback) to avoid causing re-renders of the entire widget\n */\n onClose?(): void\n}\n\nexport enum ExpansionType {\n Routes = 'routes',\n FromChain = 'fromChain',\n ToChain = 'toChain',\n}\n"],"mappings":";AAieA,IAAY,gBAAL,yBAAA,eAAA;CACL,cAAA,YAAA;CACA,cAAA,eAAA;CACA,cAAA,aAAA;;AACF,EAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"widget.js","names":[],"sources":["../../../src/types/widget.ts"],"sourcesContent":["import type {\n BaseToken,\n ChainType,\n ContractCall,\n ExecutionOptions,\n ExtendedChain,\n Order,\n Route,\n RouteOptions,\n SDKConfig,\n StaticToken,\n Token,\n} from '@lifi/sdk'\nimport type { WalletMenuOpenArgs } from '@lifi/wallet-management'\nimport type { WidgetProviderProps } from '@lifi/widget-provider'\nimport type {\n Components,\n PaletteMode,\n PaletteOptions,\n Shape,\n SxProps,\n Theme,\n} from '@mui/material'\nimport type { TypographyVariantsOptions } from '@mui/material/styles'\nimport type {\n CSSProperties,\n PropsWithChildren,\n ReactNode,\n RefObject,\n} from 'react'\nimport type {\n LanguageKey,\n LanguageResources,\n} from '../providers/I18nProvider/types.js'\nimport type { DefaultFieldValues } from '../stores/form/types.js'\n\nexport type WidgetVariant = 'compact' | 'wide' | 'drawer'\n\n/** @internal Not part of the public API. */\nexport type InternalWidgetMode = 'limit'\nexport type WidgetMode =\n | 'default'\n | 'split'\n | 'custom'\n | 'refuel'\n | InternalWidgetMode\nexport type SplitMode = 'bridge' | 'swap'\nexport type SplitModeOptions = {\n defaultTab: SplitMode\n}\nexport type CustomMode = 'checkout' | 'deposit'\nexport interface ModeOptions {\n /**\n * Configure split mode behavior:\n * - 'bridge' | 'swap': Single mode without tabs\n * - { defaultTab: 'bridge' | 'swap' }: Tabs mode with configurable default tab\n */\n split?: SplitMode | SplitModeOptions\n custom?: { type: CustomMode }\n}\n\n/**\n * Identity of a header navigation tab. Each key maps to a widget variant, mode and\n * (optionally) mode options; labels are resolved from the key.\n */\nexport type SplitNavigationTabKey = SplitMode\n/** @internal Not part of the public API. */\nexport type InternalNavigationTabKey =\n | 'default'\n | 'private'\n | 'refuel'\n | 'swap-advanced'\n | 'bridge-advanced'\n | 'limit'\nexport type NavigationTabKey = InternalNavigationTabKey | SplitNavigationTabKey\n\nexport type Appearance = PaletteMode | 'system'\nexport interface NavigationProps {\n /**\n * If given, uses a negative margin to counteract the padding on sides for navigation elements like icon buttons.\n * @default true\n */\n edge?: boolean\n}\nexport type WidgetThemeComponents = Partial<\n Pick<\n Components<Theme>,\n | 'MuiAppBar'\n | 'MuiAvatar'\n | 'MuiButton'\n | 'MuiCard'\n | 'MuiDrawer'\n | 'MuiIconButton'\n | 'MuiInputCard'\n | 'MuiNavigationTabs'\n | 'MuiNavigationTab'\n | 'MuiTabs'\n | 'MuiCheckbox'\n >\n>\n\nexport type WidgetTheme = {\n colorSchemes?: {\n light?: {\n palette: PaletteOptions\n }\n dark?: {\n palette: PaletteOptions\n }\n }\n shape?: Partial<Shape>\n typography?: TypographyVariantsOptions\n components?: WidgetThemeComponents\n container?: CSSProperties\n routesContainer?: CSSProperties\n chainSidebarContainer?: CSSProperties\n header?: CSSProperties\n navigation?: NavigationProps\n}\n\nexport interface DisabledUIConfig {\n fromAmount?: boolean\n fromToken?: boolean\n toAddress?: boolean\n toToken?: boolean\n}\n\nexport interface HiddenUIConfig {\n addressBookConnectedWallets?: boolean\n allNetworks?: boolean\n appearance?: boolean\n bridgesSettings?: boolean\n chainSelect?: boolean\n /**\n * Hide the chain sidebar in the `wide` variant. No effect in other variants.\n * @default false\n */\n chainSidebar?: boolean\n contactSupport?: boolean\n /**\n * Hide the drawer close button. Only meaningful when `variant === 'drawer'`.\n * @default false\n */\n drawerCloseButton?: boolean\n fromToken?: boolean\n gasRefuelMessage?: boolean\n hideSmallBalances?: boolean\n history?: boolean\n insufficientGasMessage?: boolean\n integratorStepDetails?: boolean\n language?: boolean\n /**\n * Hide the warning shown when sending to an address with low historical\n * on-chain activity (low transaction count or contract-like behavior).\n * @default false\n */\n lowAddressActivityConfirmation?: boolean\n poweredBy?: boolean\n /**\n * Hide the \"Recent searches\" section in the token select view.\n * @default false\n */\n recentSearches?: boolean\n reverseTokensButton?: boolean\n routeCardPriceImpact?: boolean\n routeTokenDescription?: boolean\n searchTokenInput?: boolean\n toAddress?: boolean\n toToken?: boolean\n walletMenu?: boolean\n}\n\nexport interface RequiredUIConfig {\n accountDeployedMessage?: boolean\n toAddress?: boolean\n}\n\nexport type DefaultUI = {\n transactionDetailsExpanded?: boolean\n navigationHeaderTitleNoWrap?: boolean\n /**\n * Layout for the main form.\n * - `'default'`: the chain/token selectors plus single amount input.\n * - `'cards'`: the redesigned card-based layout — stacked Send/Receive amount\n * cards (`AmountInputCardPair`) with inline token pill selectors and a swap\n * button.\n * @default 'default'\n */\n layout?: 'default' | 'cards'\n}\n\nexport interface WidgetWalletConfig {\n walletEcosystemsOrder?: Record<string, ChainType[]>\n onConnect?(args?: WalletMenuOpenArgs): void\n /**\n * Determines whether the widget should provide partial wallet management functionality.\n *\n * In partial mode, external wallet management will be used for \"opt-out\" providers,\n * while the internal management is applied for any remaining providers that do not opt out.\n * This allows a flexible balance between the integrator's custom wallet menu and the widget's native wallet menu.\n * @default false\n */\n usePartialWalletManagement?: boolean\n /**\n * This option forces the widget to always use internal wallet management ignoring external wallet management contexts\n * @default false\n */\n forceInternalWalletManagement?: boolean\n}\n\nexport interface WidgetSDKConfig\n extends Omit<\n SDKConfig,\n | 'apiKey'\n | 'disableVersionCheck'\n | 'integrator'\n | 'providers'\n | 'routeOptions'\n | 'widgetVersion'\n > {\n routeOptions?: Omit<\n RouteOptions,\n 'bridges' | 'exchanges' | 'fee' | 'referrer' | 'order' | 'slippage'\n >\n executionOptions?: Pick<ExecutionOptions, 'updateTransactionRequestHook'>\n}\n\nexport interface WidgetContractTool {\n name: string\n logoURI: string\n}\n\nexport interface CalculateFeeParams {\n fromChain: ExtendedChain\n toChain: ExtendedChain\n fromToken: Token\n toToken: Token\n fromAddress?: string\n toAddress?: string\n fromAmount?: bigint\n toAmount?: bigint\n slippage?: number\n}\n\nexport interface WidgetFeeConfig {\n name?: string\n logoURI?: string\n fee?: number\n /**\n * Whether to show the fee percentage in the fee details.\n * @default false\n */\n showFeePercentage?: boolean\n /**\n * Whether to show a tooltip with the fee details. Requires `name` or `feeTooltipComponent` to be set.\n * @default false\n */\n showFeeTooltip?: boolean\n /**\n * Custom tooltip component to show with the fee details.\n */\n feeTooltipComponent?: ReactNode\n /**\n * Function to calculate fees before fetching quotes.\n * If provided, this function will be used instead of the `fee` parameter.\n * Only one of `fee` or `calculateFee` should be used.\n *\n * @param params Object containing the fee calculation parameters\n * @returns A promise that resolves to the calculated fee as a number (e.g., 0.03 represents a 3% fee)\n */\n calculateFee?(params: CalculateFeeParams): Promise<number | undefined>\n}\n\nexport interface ToAddress {\n name?: string\n address: string\n chainType: ChainType\n logoURI?: string\n}\n\nexport interface AllowDeny<T> {\n allow?: T[]\n deny?: T[]\n}\n\nexport type AllowDenySetItem = string | number\nexport interface AllowDenySet {\n allow?: Set<AllowDenySetItem>\n deny?: Set<AllowDenySetItem>\n}\n\nexport type AllowDenySets = {\n from?: AllowDenySet\n to?: AllowDenySet\n} & AllowDenySet\n\nexport type AllowDenyItems<T> = {\n from?: AllowDeny<T>\n to?: AllowDeny<T>\n} & AllowDeny<T>\n\nexport type WidgetChains = {\n types?: AllowDeny<ChainType>\n} & AllowDenyItems<number>\n\nexport type WidgetTokens = {\n featured?: StaticToken[]\n include?: Token[]\n popular?: StaticToken[]\n verified?: BaseToken[]\n} & AllowDenyItems<BaseToken>\n\nexport type WidgetLanguages = {\n default?: LanguageKey\n} & AllowDeny<LanguageKey>\n\nexport type PoweredByType = 'default' | 'jumper'\n\nexport interface RouteLabel {\n text: string\n sx?: SxProps<Theme>\n}\n\nexport interface RouteLabelRule {\n label: RouteLabel\n // Matching criteria\n bridges?: AllowDeny<string>\n exchanges?: AllowDeny<string>\n fromChainId?: number[]\n toChainId?: number[]\n fromTokenAddress?: string[]\n toTokenAddress?: string[]\n /**\n * Custom match function evaluated against the route. When provided, its\n * result is AND'd with the other matching criteria — all specified\n * conditions must pass for the label to apply. Use this for matching logic\n * that the built-in fields cannot express (gas costs, step count, route\n * tags, etc.).\n */\n match?: (route: Route) => boolean\n}\n\nexport type ExplorerUrl =\n | string\n | {\n url: string\n txPath?: string\n addressPath?: string\n }\n\nexport type WidgetProvider = (\n props: PropsWithChildren<WidgetProviderProps>\n) => ReactNode\n\nexport interface WidgetConfig {\n fromChain?: number\n toChain?: number\n fromToken?: string\n toToken?: string\n toAddress?: ToAddress\n toAddresses?: ToAddress[]\n fromAmount?: number | string\n minFromAmountUSD?: number\n toAmount?: number | string\n formUpdateKey?: string\n\n providers?: WidgetProvider[]\n\n contractCalls?: ContractCall[]\n contractComponent?: ReactNode\n contractSecondaryComponent?: ReactNode\n contractCompactComponent?: ReactNode\n contractTool?: WidgetContractTool\n integrator: string\n apiKey?: string\n feeConfig?: WidgetFeeConfig\n referrer?: string\n\n routePriority?: Order\n slippage?: number\n\n variant?: WidgetVariant\n mode?: WidgetMode\n modeOptions?: ModeOptions\n /**\n * Header navigation tabs, in order. When set, the widget renders a tab bar\n * and the active tab drives the displayed flow. Each entry is a tab key.\n *\n * @internal Not part of the public API.\n */\n _navigationTabs?: NavigationTabKey[]\n\n appearance?: Appearance\n theme?: WidgetTheme\n\n disabledUI?: DisabledUIConfig\n hiddenUI?: HiddenUIConfig\n requiredUI?: RequiredUIConfig\n defaultUI?: DefaultUI\n /**\n * When true, shows only the recommended route and hides the route\n * selector UI. Distinct from `routePriority`, which sets the SDK\n * ranking order across multiple displayed routes.\n * @default false\n */\n showSingleRoute?: boolean\n useRelayerRoutes?: boolean\n\n walletConfig?: WidgetWalletConfig\n sdkConfig?: WidgetSDKConfig\n\n buildUrl?: boolean\n /**\n * @deprecated Use `storageScopeKey` for persisted state and `queryScopeKey`\n * for the query cache. Still honoured as the fallback for both.\n */\n keyPrefix?: string\n /**\n * Namespaces the widget's persisted state in `localStorage`: bookmarks,\n * pinned tokens, recent tokens, chain order and route history, as\n * `keyPrefix` does. Use a different value per widget instance that should\n * keep its own state. Settings keep one shared name.\n *\n * It also scopes the widget's other queries (routes, tokens, balances, …),\n * so instances with different values keep their data apart.\n *\n * Falls back to `keyPrefix`, then to the historical `li.fi-*` names.\n */\n storageScopeKey?: string\n /**\n * Scopes the widget's chains and tools queries inside the host's react-query\n * `QueryClient`. Widget instances - and a host app using the\n * `@lifi/widget/queries` factories - that pass the same value\n * share those entries. The other widget queries are scoped by\n * `storageScopeKey`.\n *\n * The keys start with a plain `'chains'` / `'tools'`, as in wagmi, so a host\n * that matches on those roots (for example `setQueriesData({ queryKey:\n * ['chains'] })`) also reaches the widget's entries.\n *\n * Falls back to `keyPrefix`, then to `'li.fi'`.\n */\n queryScopeKey?: string\n\n bridges?: AllowDeny<string>\n exchanges?: AllowDeny<string>\n chains?: WidgetChains\n tokens?: WidgetTokens\n languages?: WidgetLanguages\n languageResources?: LanguageResources\n explorerUrls?: Record<number, ExplorerUrl[]> &\n Partial<Record<'internal', ExplorerUrl[]>>\n poweredBy?: PoweredByType\n\n /**\n * Custom labels/badges to show on routes based on specified rules\n */\n routeLabels?: RouteLabelRule[]\n}\n\nexport interface FormFieldOptions {\n setUrlSearchParam: boolean\n}\n\nexport interface FieldValues\n extends Omit<DefaultFieldValues, 'fromAmount' | 'toAmount' | 'toAddress'> {\n fromAmount?: number | string\n toAmount?: number | string\n toAddress?: ToAddress | string\n}\n\nexport type FieldNames = keyof FieldValues\n\nexport type SetFieldValueFunction = <K extends FieldNames>(\n key: K,\n value: FieldValues[K],\n options?: FormFieldOptions\n) => void\n\nexport type FormState = {\n setFieldValue: SetFieldValueFunction\n}\n\nexport type FormRef = RefObject<FormState | null>\n\nexport interface FormRefProps {\n formRef?: FormRef\n}\n\nexport interface WidgetConfigProps extends FormRefProps {\n config: WidgetConfig\n}\n\nexport interface WidgetConfigPartialProps {\n config?: Partial<WidgetConfig>\n}\n\nexport type WidgetProps = WidgetDrawerProps &\n WidgetConfig &\n WidgetConfigPartialProps &\n FormRefProps\n\nexport interface WidgetDrawerProps extends WidgetConfigPartialProps {\n elementRef?: RefObject<HTMLDivElement>\n open?: boolean\n /**\n * Make sure to make the onClose callback stable (e.g. using useCallback) to avoid causing re-renders of the entire widget\n */\n onClose?(): void\n}\n\nexport enum ExpansionType {\n Routes = 'routes',\n FromChain = 'fromChain',\n ToChain = 'toChain',\n}\n"],"mappings":";AA+fA,IAAY,gBAAL,yBAAA,eAAA;CACL,cAAA,YAAA;CACA,cAAA,eAAA;CACA,cAAA,aAAA;;AACF,EAAA,CAAA,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"queries.js","names":[],"sources":["../../../src/utils/queries.ts"],"sourcesContent":["export const getQueryKey = (key: string, prefix?: string) =>\n `${prefix || 'li.fi'}-widget-${key}`\n"],"mappings":";AAAA,MAAa,eAAe,KAAa,WACvC,GAAG,UAAU,QAAQ,UAAU"}
1
+ {"version":3,"file":"queries.js","names":[],"sources":["../../../src/utils/queries.ts"],"sourcesContent":["// Legacy keys: callers pass the storage scope, so instances stay apart.\nexport const getQueryKey = (key: string, prefix?: string) =>\n `${prefix || 'li.fi'}-widget-${key}`\n"],"mappings":";AACA,MAAa,eAAe,KAAa,WACvC,GAAG,UAAU,QAAQ,UAAU"}
@@ -0,0 +1,6 @@
1
+ import { WidgetConfig } from "../types/widget.js";
2
+ //#region src/utils/scopeKeys.d.ts
3
+ type ScopeKeyConfig = Pick<WidgetConfig, "storageScopeKey" | "queryScopeKey" | "keyPrefix">;
4
+ export declare const resolveStorageScopeKey: (config: Partial<ScopeKeyConfig> | undefined) => string | undefined;
5
+ //#endregion
6
+ //# sourceMappingURL=scopeKeys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scopeKeys.d.ts","names":[],"sources":["../../../src/utils/scopeKeys.ts"],"mappings":";;KAKK,iBAAiB,KACpB;qBAKW,yBACX,QAAQ,QAAQ"}
@@ -0,0 +1,8 @@
1
+ //#region src/utils/scopeKeys.ts
2
+ const defaultQueryScopeKey = "li.fi";
3
+ const resolveStorageScopeKey = (config) => config?.storageScopeKey ?? config?.keyPrefix;
4
+ const resolveQueryScopeKey = (config) => config?.queryScopeKey ?? config?.keyPrefix ?? "li.fi";
5
+ //#endregion
6
+ export { defaultQueryScopeKey, resolveQueryScopeKey, resolveStorageScopeKey };
7
+
8
+ //# sourceMappingURL=scopeKeys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scopeKeys.js","names":[],"sources":["../../../src/utils/scopeKeys.ts"],"sourcesContent":["import type { WidgetConfig } from '../types/widget.js'\n\n// Non-empty, so an unconfigured widget never shares a host's unscoped entries.\nexport const defaultQueryScopeKey = 'li.fi'\n\ntype ScopeKeyConfig = Pick<\n WidgetConfig,\n 'storageScopeKey' | 'queryScopeKey' | 'keyPrefix'\n>\n\n// `undefined` keeps the historical `li.fi-*` store names.\nexport const resolveStorageScopeKey = (\n config: Partial<ScopeKeyConfig> | undefined\n): string | undefined => config?.storageScopeKey ?? config?.keyPrefix\n\nexport const resolveQueryScopeKey = (\n config: Partial<ScopeKeyConfig> | undefined\n): string => config?.queryScopeKey ?? config?.keyPrefix ?? defaultQueryScopeKey\n"],"mappings":";AAGA,MAAa,uBAAuB;AAQpC,MAAa,0BACX,WACuB,QAAQ,mBAAmB,QAAQ;AAE5D,MAAa,wBACX,WACW,QAAQ,iBAAiB,QAAQ,aAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lifi/widget",
3
- "version": "4.7.1",
3
+ "version": "4.8.0",
4
4
  "description": "LI.FI Widget for cross-chain bridging and swapping. It will drive your multi-chain strategy and attract new users from everywhere.",
5
5
  "type": "module",
6
6
  "main": "./dist/esm/index.js",
@@ -21,6 +21,11 @@
21
21
  "import": "./dist/esm/shared.js",
22
22
  "default": "./dist/esm/shared.js"
23
23
  },
24
+ "./queries": {
25
+ "types": "./dist/esm/queries/index.d.ts",
26
+ "import": "./dist/esm/queries/index.js",
27
+ "default": "./dist/esm/queries/index.js"
28
+ },
24
29
  "./package.json": "./package.json"
25
30
  },
26
31
  "sideEffects": false,
@@ -52,9 +57,9 @@
52
57
  "dependencies": {
53
58
  "@emotion/react": "^11.14.0",
54
59
  "@emotion/styled": "^11.14.1",
55
- "@lifi/sdk": "^4.8.0",
56
- "@lifi/wallet-management": "4.3.0",
57
- "@lifi/widget-provider": "4.5.0",
60
+ "@lifi/sdk": "^4.10.0",
61
+ "@lifi/wallet-management": "4.3.1",
62
+ "@lifi/widget-provider": "4.5.1",
58
63
  "@mui/icons-material": "^9.4.0",
59
64
  "@mui/material": "^9.4.0",
60
65
  "@mui/system": "^9.4.0",
@@ -82,6 +87,9 @@
82
87
  ],
83
88
  "shared": [
84
89
  "./dist/esm/shared.d.ts"
90
+ ],
91
+ "queries": [
92
+ "./dist/esm/queries/index.d.ts"
85
93
  ]
86
94
  }
87
95
  },
@@ -1,2 +1,2 @@
1
1
  export const name = '@lifi/widget'
2
- export const version = '4.7.1'
2
+ export const version = '4.8.0'
@@ -0,0 +1,170 @@
1
+ /** @vitest-environment happy-dom */
2
+
3
+ import type * as LifiSdk from '@lifi/sdk'
4
+ import { ChainType, type ExtendedChain, type SDKClient } from '@lifi/sdk'
5
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
6
+ import { act } from 'react'
7
+ import { createRoot, type Root } from 'react-dom/client'
8
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
9
+ import type { WidgetConfig } from '../types/widget.js'
10
+
11
+ /**
12
+ * The chains entry is shared with the host app through
13
+ * `getChainsQueryOptions`, keyed by the client's API base, the requested chain
14
+ * types and the widget's `queryScopeKey`. The widget's own SDK client still
15
+ * gets the chains, whoever filled the entry.
16
+ */
17
+
18
+ const API_URL = 'https://api.example/v1'
19
+
20
+ const mocks = vi.hoisted(() => ({
21
+ getChains: vi.fn(),
22
+ setChains: vi.fn(),
23
+ }))
24
+
25
+ vi.mock('@lifi/sdk', async (importOriginal) => ({
26
+ ...(await importOriginal<typeof LifiSdk>()),
27
+ getChains: mocks.getChains,
28
+ }))
29
+
30
+ let widgetConfig: Partial<WidgetConfig> = {}
31
+
32
+ vi.mock('../providers/WidgetProvider/WidgetProvider.js', () => ({
33
+ useWidgetConfig: () => widgetConfig,
34
+ }))
35
+
36
+ const client = {
37
+ config: { apiUrl: API_URL },
38
+ setChains: mocks.setChains,
39
+ } as unknown as SDKClient
40
+ vi.mock('../providers/SDKClientProvider.js', () => ({
41
+ useSDKClient: () => client,
42
+ }))
43
+
44
+ import { getChainsQueryKey } from '../queries/getChains.js'
45
+ import { useAvailableChains } from './useAvailableChains.js'
46
+
47
+ const CHAINS = [{ id: 1, name: 'Ethereum' }] as ExtendedChain[]
48
+
49
+ let root: Root
50
+ let queryClient: QueryClient
51
+ let externalConfig: WidgetConfig | undefined
52
+
53
+ const Probe = () => {
54
+ useAvailableChains(undefined, externalConfig)
55
+ return null
56
+ }
57
+
58
+ const render = async () => {
59
+ await act(async () => {
60
+ root.render(
61
+ <QueryClientProvider client={queryClient}>
62
+ <Probe />
63
+ </QueryClientProvider>
64
+ )
65
+ })
66
+ }
67
+
68
+ const evmKey = getChainsQueryKey({
69
+ apiUrl: API_URL,
70
+ chainTypes: [ChainType.EVM],
71
+ scopeKey: 'host',
72
+ })
73
+
74
+ describe('useAvailableChains', () => {
75
+ beforeEach(() => {
76
+ vi.clearAllMocks()
77
+ mocks.getChains.mockResolvedValue(CHAINS)
78
+ widgetConfig = {
79
+ queryScopeKey: 'host',
80
+ chains: { types: { allow: [ChainType.EVM] } },
81
+ }
82
+ externalConfig = undefined
83
+ queryClient = new QueryClient({
84
+ defaultOptions: { queries: { retry: false } },
85
+ })
86
+ const container = document.createElement('div')
87
+ document.body.appendChild(container)
88
+ root = createRoot(container)
89
+ })
90
+
91
+ afterEach(async () => {
92
+ await act(async () => root.unmount())
93
+ queryClient.clear()
94
+ })
95
+
96
+ it('fetches the allowed chain types under the widget scope and hands them to the client', async () => {
97
+ await render()
98
+
99
+ await vi.waitFor(() => {
100
+ expect(mocks.setChains).toHaveBeenCalledWith(CHAINS)
101
+ })
102
+ expect(mocks.getChains).toHaveBeenCalledWith(client, {
103
+ chainTypes: [ChainType.EVM],
104
+ })
105
+ expect(queryClient.getQueryData(evmKey)).toBe(CHAINS)
106
+ })
107
+
108
+ it('reads an entry the host filled, and still hands the chains to the client', async () => {
109
+ queryClient.setQueryData(evmKey, CHAINS)
110
+
111
+ await render()
112
+
113
+ await vi.waitFor(() => {
114
+ expect(mocks.setChains).toHaveBeenCalledWith(CHAINS)
115
+ })
116
+ expect(mocks.getChains).not.toHaveBeenCalled()
117
+ })
118
+
119
+ it('hands the chains to the client again after a refetch with equal data', async () => {
120
+ // Structural sharing keeps the data reference on an equal refetch. The
121
+ // client's own chain storage expires, so every fetch must refresh it.
122
+ await render()
123
+ await vi.waitFor(() => {
124
+ expect(mocks.setChains).toHaveBeenCalledTimes(1)
125
+ })
126
+
127
+ await act(async () => {
128
+ await queryClient.refetchQueries({ queryKey: evmKey })
129
+ })
130
+
131
+ await vi.waitFor(() => {
132
+ expect(mocks.setChains).toHaveBeenCalledTimes(2)
133
+ })
134
+ })
135
+
136
+ it('refreshes the chains every five minutes', async () => {
137
+ await render()
138
+ await vi.waitFor(() => {
139
+ expect(queryClient.getQueryData(evmKey)).toBe(CHAINS)
140
+ })
141
+
142
+ const [observer] = queryClient
143
+ .getQueryCache()
144
+ .find({ queryKey: evmKey })!.observers
145
+ expect(observer.options.refetchInterval).toBe(300_000)
146
+ expect(observer.options.staleTime).toBe(300_000)
147
+ })
148
+
149
+ it('uses the API base and scope of an external widget config', async () => {
150
+ externalConfig = {
151
+ integrator: 'partner',
152
+ keyPrefix: 'partner',
153
+ sdkConfig: { apiUrl: 'https://partner.example/v1' },
154
+ chains: { types: { allow: [ChainType.SVM] } },
155
+ }
156
+
157
+ await render()
158
+
159
+ const partnerKey = getChainsQueryKey({
160
+ apiUrl: 'https://partner.example/v1',
161
+ chainTypes: [ChainType.SVM],
162
+ scopeKey: 'partner',
163
+ })
164
+ await vi.waitFor(() => {
165
+ expect(queryClient.getQueryData(partnerKey)).toBe(CHAINS)
166
+ })
167
+ // The external config's own client, not the widget's.
168
+ expect(mocks.getChains.mock.calls[0][0]).not.toBe(client)
169
+ })
170
+ })
@@ -1,26 +1,23 @@
1
- import type { ExtendedChain } from '@lifi/sdk'
2
- import { ChainType, createClient, getChains } from '@lifi/sdk'
1
+ import type { ChainType, ExtendedChain } from '@lifi/sdk'
2
+ import { createClient } from '@lifi/sdk'
3
3
  import { useQuery } from '@tanstack/react-query'
4
4
  import { useCallback, useEffect, useMemo } from 'react'
5
5
  import { useSDKClient } from '../providers/SDKClientProvider.js'
6
6
  import { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'
7
+ import {
8
+ getChainsQueryOptions,
9
+ supportedChainTypes,
10
+ } from '../queries/getChains.js'
7
11
  import type { WidgetConfig } from '../types/widget.js'
8
12
  import { getConfigItemSets, isItemAllowedForSets } from '../utils/item.js'
9
- import { getQueryKey } from '../utils/queries.js'
13
+ import { resolveQueryScopeKey } from '../utils/scopeKeys.js'
10
14
 
11
15
  type GetChainById = (
12
16
  chainId?: number,
13
17
  chains?: ExtendedChain[]
14
18
  ) => ExtendedChain | undefined
15
19
 
16
- const supportedChainTypes = [
17
- ChainType.EVM,
18
- ChainType.SVM,
19
- ChainType.UTXO,
20
- ChainType.MVM,
21
- ChainType.TVM,
22
- ChainType.STL,
23
- ]
20
+ const refetchInterval = 300_000
24
21
 
25
22
  export const useAvailableChains = (
26
23
  chainTypes?: ChainType[],
@@ -30,7 +27,7 @@ export const useAvailableChains = (
30
27
  getChainById: GetChainById
31
28
  isLoading: boolean
32
29
  } => {
33
- const { chains: internalChains, keyPrefix: internalKeyPrefix } =
30
+ const { chains: internalChains, queryScopeKey: internalQueryScopeKey } =
34
31
  useWidgetConfig()
35
32
  const internalClient = useSDKClient()
36
33
 
@@ -46,46 +43,31 @@ export const useAvailableChains = (
46
43
  }, [widgetConfig])
47
44
 
48
45
  // Overwrite widget config if passed as param
49
- const keyPrefix = widgetConfig?.keyPrefix ?? internalKeyPrefix
46
+ const client = externalClient ?? internalClient
50
47
  const chains = widgetConfig?.chains ?? internalChains
48
+ const queryScopeKey = widgetConfig
49
+ ? resolveQueryScopeKey(widgetConfig)
50
+ : internalQueryScopeKey
51
51
 
52
- const { data, isLoading } = useQuery({
53
- queryKey: [
54
- getQueryKey('chains', keyPrefix),
55
- chains?.types,
56
- chains?.allow,
57
- chains?.deny,
58
- chains?.from,
59
- chains?.to,
60
- !!externalClient,
61
- ] as const,
62
- queryFn: async ({ queryKey: [, chainTypesConfig] }) => {
63
- const chainsConfigSets = getConfigItemSets(
64
- chainTypesConfig,
65
- (chains) => new Set(chains)
66
- )
67
- const chainTypesRequest = supportedChainTypes.filter((chainType) =>
68
- isItemAllowedForSets(chainType, chainsConfigSets)
69
- )
70
- const client = externalClient ?? internalClient
71
- const availableChains = await getChains(client, {
72
- chainTypes: chainTypes || chainTypesRequest,
73
- })
74
- client.setChains(availableChains)
75
- return availableChains
76
- },
77
- refetchInterval: 300_000,
78
- staleTime: 300_000,
79
- })
52
+ const typeSets = getConfigItemSets(chains?.types, (types) => new Set(types))
53
+ const requestedTypes =
54
+ chainTypes ??
55
+ supportedChainTypes.filter((type) => isItemAllowedForSets(type, typeSets))
56
+
57
+ const { data, dataUpdatedAt, isLoading } = useQuery(
58
+ getChainsQueryOptions(client, {
59
+ chainTypes: requestedTypes,
60
+ scopeKey: queryScopeKey,
61
+ query: { refetchInterval, staleTime: refetchInterval },
62
+ })
63
+ )
80
64
 
81
- // Ensure the current internal client always has chains, even when:
82
- // - the query result came from cache (external call populated it first)
83
- // - the client was recreated due to config changes (stale closure in queryFn)
65
+ // A host may fill the entry; key on dataUpdatedAt, as a refetch keeps data.
84
66
  useEffect(() => {
85
- if (data && !externalClient) {
86
- internalClient.setChains(data)
67
+ if (data && dataUpdatedAt) {
68
+ client.setChains(data)
87
69
  }
88
- }, [data, externalClient, internalClient])
70
+ }, [data, dataUpdatedAt, client])
89
71
 
90
72
  const getChainById: GetChainById = useCallback(
91
73
  (chainId?: number, chains: ExtendedChain[] | undefined = data) => {
@@ -22,7 +22,7 @@ export const useFromTokenSufficiency = (
22
22
  'fromToken',
23
23
  'fromAmount'
24
24
  )
25
- const { keyPrefix } = useWidgetConfig()
25
+ const { storageScopeKey } = useWidgetConfig()
26
26
  const sdkClient = useSDKClient()
27
27
 
28
28
  let chainId = fromChainId
@@ -42,7 +42,7 @@ export const useFromTokenSufficiency = (
42
42
 
43
43
  const { data: insufficientFromToken, isLoading } = useQuery({
44
44
  queryKey: [
45
- getQueryKey('from-token-sufficiency-check', keyPrefix),
45
+ getQueryKey('from-token-sufficiency-check', storageScopeKey),
46
46
  account.address,
47
47
  chainId,
48
48
  tokenAddress,
@@ -14,7 +14,7 @@ export const useGasRecommendation = (
14
14
  fromToken?: string
15
15
  ): UseQueryResult<Awaited<ReturnType<typeof getGasRecommendation>> | null> => {
16
16
  const { chains } = useAvailableChains()
17
- const { keyPrefix, hiddenUI } = useWidgetConfig()
17
+ const { storageScopeKey, hiddenUI } = useWidgetConfig()
18
18
  const sdkClient = useSDKClient()
19
19
 
20
20
  const checkRecommendationLiFuel =
@@ -28,7 +28,7 @@ export const useGasRecommendation = (
28
28
 
29
29
  return useQuery({
30
30
  queryKey: [
31
- getQueryKey('gas-recommendation', keyPrefix),
31
+ getQueryKey('gas-recommendation', storageScopeKey),
32
32
  toChainId,
33
33
  fromChain,
34
34
  fromToken,
@@ -32,7 +32,7 @@ export const useGasSufficiency = (
32
32
  const { account: EVMAccount, accounts } = useAccount({
33
33
  chainType: ChainType.EVM,
34
34
  })
35
- const { keyPrefix, hiddenUI } = useWidgetConfig()
35
+ const { storageScopeKey, hiddenUI } = useWidgetConfig()
36
36
  const sdkClient = useSDKClient()
37
37
 
38
38
  const { relevantAccounts, relevantAccountsQueryKey } = useMemo(() => {
@@ -67,7 +67,7 @@ export const useGasSufficiency = (
67
67
 
68
68
  const { data: insufficientGas, isLoading } = useQuery<GasSufficiency[]>({
69
69
  queryKey: [
70
- getQueryKey('gas-sufficiency-check', keyPrefix),
70
+ getQueryKey('gas-sufficiency-check', storageScopeKey),
71
71
  relevantAccountsQueryKey,
72
72
  route?.id,
73
73
  isContractAddress,
@@ -13,7 +13,7 @@ export function useIsBatchingSupported(
13
13
  isBatchingSupported: boolean | undefined
14
14
  isBatchingSupportedLoading: boolean
15
15
  } {
16
- const { keyPrefix } = useWidgetConfig()
16
+ const { storageScopeKey } = useWidgetConfig()
17
17
  const sdkClient = useSDKClient()
18
18
  const { isBatchingSupported } = useEthereumContext()
19
19
 
@@ -22,7 +22,7 @@ export function useIsBatchingSupported(
22
22
  )
23
23
  const { data, isLoading } = useQuery({
24
24
  queryKey: [
25
- getQueryKey('isBatchingSupported', keyPrefix),
25
+ getQueryKey('isBatchingSupported', storageScopeKey),
26
26
  chain?.id,
27
27
  address,
28
28
  ],
@@ -43,7 +43,7 @@ export const useRouteExecution = ({
43
43
  const queryClient = useQueryClient()
44
44
  const { account } = useAccount()
45
45
  const resumedAfterMount = useRef(false)
46
- const { keyPrefix } = useWidgetConfig()
46
+ const { storageScopeKey } = useWidgetConfig()
47
47
  const sdkClient = useSDKClient()
48
48
  const emitter = useWidgetEvents()
49
49
  const routeExecutionStoreContext = useRouteExecutionStoreContext()
@@ -84,16 +84,16 @@ export const useRouteExecution = ({
84
84
  if (executionCompleted || executionFailed) {
85
85
  const invalidateKeys = [
86
86
  [
87
- getQueryKey('token-balances', keyPrefix),
87
+ getQueryKey('token-balances', storageScopeKey),
88
88
  clonedUpdatedRoute.fromAddress,
89
89
  clonedUpdatedRoute.fromChainId,
90
90
  ],
91
91
  [
92
- getQueryKey('token-balances', keyPrefix),
92
+ getQueryKey('token-balances', storageScopeKey),
93
93
  clonedUpdatedRoute.toAddress,
94
94
  clonedUpdatedRoute.toChainId,
95
95
  ],
96
- [getQueryKey('transaction-history', keyPrefix)],
96
+ [getQueryKey('transaction-history', storageScopeKey)],
97
97
  ]
98
98
  for (const key of invalidateKeys) {
99
99
  queryClient.invalidateQueries(
@@ -133,7 +133,7 @@ export const useRouteExecution = ({
133
133
  throw new Error('Execution route not found.')
134
134
  }
135
135
  queryClient.removeQueries({
136
- queryKey: [getQueryKey('routes', keyPrefix)],
136
+ queryKey: [getQueryKey('routes', storageScopeKey)],
137
137
  exact: false,
138
138
  })
139
139
  return executeRoute(sdkClient, routeExecution.route, {
@@ -82,7 +82,7 @@ export const useRoutes = ({
82
82
  exchanges,
83
83
  feeConfig,
84
84
  useRelayerRoutes,
85
- keyPrefix,
85
+ storageScopeKey,
86
86
  } = useWidgetConfig()
87
87
  const sdkClient = useSDKClient()
88
88
  const setExecutableRoute = useSetExecutableRoute()
@@ -214,7 +214,7 @@ export const useRoutes = ({
214
214
  const queryKey = useMemo(
215
215
  () =>
216
216
  [
217
- getQueryKey('routes', keyPrefix),
217
+ getQueryKey('routes', storageScopeKey),
218
218
  effectiveFromAddress,
219
219
  fromChain?.id as number,
220
220
  fromToken?.address as string,
@@ -244,7 +244,7 @@ export const useRoutes = ({
244
244
  observableRoute?.id,
245
245
  ] as const,
246
246
  [
247
- keyPrefix,
247
+ storageScopeKey,
248
248
  effectiveFromAddress,
249
249
  fromChain?.id,
250
250
  fromToken?.address,
@@ -550,14 +550,14 @@ export const useRoutes = ({
550
550
  ;[fromToken, toToken].forEach((token) => {
551
551
  // Update main tokens cache (verified)
552
552
  queryClient.setQueriesData<TokensByChain>(
553
- { queryKey: [getQueryKey('tokens', keyPrefix)] },
553
+ { queryKey: [getQueryKey('tokens', storageScopeKey)] },
554
554
  (data) => updateTokenInCache(data, token)
555
555
  )
556
556
 
557
557
  // Update search tokens cache (unverified) - matches any search query
558
558
  queryClient.setQueriesData<TokensByChain>(
559
559
  {
560
- queryKey: [getQueryKey('tokens-search', keyPrefix)],
560
+ queryKey: [getQueryKey('tokens-search', storageScopeKey)],
561
561
  exact: false,
562
562
  },
563
563
  (data) => updateTokenInCache(data, token)
@@ -566,7 +566,7 @@ export const useRoutes = ({
566
566
  queryClient.setQueriesData<Token[]>(
567
567
  {
568
568
  queryKey: [
569
- getQueryKey('token-balances', keyPrefix),
569
+ getQueryKey('token-balances', storageScopeKey),
570
570
  fromAddress,
571
571
  token.chainId,
572
572
  ],
@@ -23,18 +23,18 @@ export const useTokenBalance = (
23
23
  getTokenBalancesWithRetry: typeof getTokenBalancesWithRetry
24
24
  } => {
25
25
  const queryClient = useQueryClient()
26
- const { keyPrefix } = useWidgetConfig()
26
+ const { storageScopeKey } = useWidgetConfig()
27
27
  const sdkClient = useSDKClient()
28
28
 
29
29
  const tokenBalanceQueryKey = useMemo(
30
30
  () =>
31
31
  [
32
- getQueryKey('token-balance', keyPrefix),
32
+ getQueryKey('token-balance', storageScopeKey),
33
33
  accountAddress,
34
34
  token?.chainId,
35
35
  token?.address,
36
36
  ] as const,
37
- [token?.address, token?.chainId, accountAddress, keyPrefix]
37
+ [token?.address, token?.chainId, accountAddress, storageScopeKey]
38
38
  )
39
39
 
40
40
  const { data, isLoading, refetch } = useQuery({
@@ -67,7 +67,7 @@ export const useTokenBalance = (
67
67
  queryClient.setQueriesData<TokenAmount[]>(
68
68
  {
69
69
  queryKey: [
70
- getQueryKey('token-balances', keyPrefix),
70
+ getQueryKey('token-balances', storageScopeKey),
71
71
  accountAddress,
72
72
  tokenChainId,
73
73
  ],