diff --git a/biome.json b/biome.json index f2beea6a03c..9c06a077aff 100644 --- a/biome.json +++ b/biome.json @@ -1,9 +1,9 @@ { - "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", + "$schema": "https://biomejs.dev/schemas/2.3.5/schema.json", "vcs": { "enabled": false, "clientKind": "git", "useIgnoreFile": false }, "files": { "ignoreUnknown": false, - "ignore": ["src/__generated__/**/*", ".cache/**/*", "dist/**/*"] + "includes": ["**", "!**/src/__generated__/**/*", "!**/.cache/**/*", "!**/dist/**/*"] }, "formatter": { "enabled": true, @@ -15,9 +15,9 @@ "lineWidth": 80, "attributePosition": "auto", "bracketSpacing": true, - "ignore": ["**/__generated__", "hokusai/*.yml", ".cache/**/*", "dist/**/*"] + "includes": ["**", "!**/__generated__", "!**/hokusai/**/*.yml", "!**/.cache/**/*", "!**/dist/**/*"] }, - "organizeImports": { "enabled": true }, + "assist": { "actions": { "source": { "organizeImports": "on" } } }, "linter": { "enabled": true, "rules": { @@ -32,7 +32,8 @@ "noForEach": "off", "noUselessFragments": "off", "useLiteralKeys": "off", - "useOptionalChain": "off" + "useOptionalChain": "off", + "noArguments": "off" }, "performance": { "noAccumulatingSpread": "off", @@ -42,10 +43,28 @@ "noDangerouslySetInnerHtml": "off" }, "style": { - "noArguments": "off", "noNonNullAssertion": "off", "noUselessElse": "off", - "useNodejsImportProtocol": "off" + "useNodejsImportProtocol": "off", + "noRestrictedImports": { + "level": "error", + "options": { + "paths": { + "superagent": "Please use native fetch instead.", + "sharify": "Please use getENV instead.", + "unstated": "Please just use React state.", + "react-waypoint": "Please use `useIntersectionObserver`", + "relay-runtime": { + "importNames": ["graphql"], + "message": "Please import `graphql` from `react-relay`." + }, + "@unleash/proxy-client-react": { + "importNames": ["useFlag", "useVariant"], + "message": "Please import useFlag from `System/FeatureFlags/useFlag.ts` and useVariant from `System/FeatureFlags/useVariant.ts` instead." + } + } + } + } }, "suspicious": { "noArrayIndexKey": "off", @@ -54,7 +73,7 @@ "noImplicitAnyLet": "off" } }, - "ignore": ["src/__generated__/**/*", ".cache/**/*", "dist/**/*"] + "includes": ["**", "!**/src/__generated__/**/*", "!**/.cache/**/*", "!**/dist/**/*"] }, "javascript": { "formatter": { @@ -70,14 +89,32 @@ } }, "overrides": [ - { "include": ["*.cy.js", "*.cy.ts"], "linter": { "rules": {} } }, + { "includes": ["**/*.cy.js", "**/*.cy.ts"], "linter": { "rules": {} } }, { - "include": ["webpack/**/*"], + "includes": ["**/webpack/**/*"], "linter": { "rules": { "suspicious": { "noConsole": "off" } } } }, { - "include": ["*.test.ts", "*.test.tsx", "*.jest.ts", "**/*.jest.tsx"], + "includes": [ + "**/*.test.ts", + "**/*.test.tsx", + "**/*.jest.ts", + "**/*.jest.tsx" + ], "linter": { "rules": { "style": { "noNonNullAssertion": "off" } } } + }, + { + "includes": [ + "**/System/FeatureFlags/useFlag.ts", + "**/System/FeatureFlags/useVariant.ts" + ], + "linter": { + "rules": { + "style": { + "noRestrictedImports": "off" + } + } + } } ] } diff --git a/docs/using_unleash.md b/docs/using_unleash.md index 59463ff53b8..c77216f8db4 100644 --- a/docs/using_unleash.md +++ b/docs/using_unleash.md @@ -49,14 +49,14 @@ By following these steps, you can safely manage feature rollouts and experiments 3. **Use the flag in your code**: Refer to the examples in this guide to implement the feature flag in your application. -## Using Feature Flags in React (Client-side) +## Using Feature Flags in React (Isomorphic) -IMPORTANT: `useFlag` is not isomorphic. Meaning you will not have access to the flag on the server side render. Design your UI accordingly. +Our feature flag hooks are **isomorphic** - they work on both server-side render (SSR) and client-side. This prevents hydration mismatches and enables consistent behavior. ### Basic Feature Flag Usage ```tsx -import { useFlag } from "@unleash/proxy-client-react" +import { useFlag } from "System/FeatureFlags/useFlag" const MyComponent = () => { const enabled = useFlag("demo-feature") @@ -71,10 +71,8 @@ const MyComponent = () => { ### A/B Testing with Variants -IMPORTANT: `useVariant` is not isomorphic. Meaning you will not have access to the variant on the server side render. `variant` will be `"disabled"` until Unleash mounts and fetches. - ```tsx -import { useVariant } from "@unleash/proxy-client-react" +import { useVariant } from "System/FeatureFlags/useVariant" import { useTrackFeatureVariantOnMount } from "System/Hooks/useTrackFeatureVariant" const MyExperiment = () => { diff --git a/package.json b/package.json index f733d072201..9a23b9004ae 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "hokusai": "yarn hokusai dev start --no-build", "jest": "node_modules/.bin/jest --config jest.config.js", "jest:debug": "node --inspect node_modules/.bin/jest --runInBand", - "lint": "yarn biome lint --no-errors-on-unmatched", + "lint": "yarn biome lint --no-errors-on-unmatched --fix", "local-palette-dev": "./scripts/yalc-link-local-palette", "local-palette-dev:stop": "./scripts/yalc-unlink-local-palette", "open-consent-modal": "open http://localhost:5000?otreset=false&otpreview=true&otgeo=gb", @@ -191,7 +191,7 @@ }, "devDependencies": { "@artaio/arta-browser": "^2.16.1", - "@biomejs/biome": "1.9.4", + "@biomejs/biome": "^2.3.5", "@graphql-inspector/core": "1.14.0", "@graphql-tools/jest-transform": "^2.0.0", "@loadable/webpack-plugin": "5.15.2", @@ -223,6 +223,7 @@ "@types/jest": "27.0.2", "@types/jwt-decode": "2.2.0", "@types/loadable__component": "5.13.1", + "@types/loadable__webpack-plugin": "^5.15.1", "@types/lodash": "4.14.111", "@types/luxon": "^3.2.0", "@types/memoize-one": "3.1.1", @@ -247,6 +248,7 @@ "@types/testing-library__jest-dom": "^6.0.0", "@types/testing-library__react": "^10.2.0", "@types/underscore.string": "0.0.32", + "@types/webpack-node-externals": "^3.0.4", "@types/yup": "^0.29.13", "chai": "4.0.0", "chai-passport-strategy": "^3.0.0", diff --git a/playwright/e2e/collection.spec.ts b/playwright/e2e/collection.spec.ts index 52ecf318344..27968192912 100644 --- a/playwright/e2e/collection.spec.ts +++ b/playwright/e2e/collection.spec.ts @@ -1,6 +1,8 @@ import { test, expect } from "@playwright/test" const artworkGridRenders = async (page: any) => { + // Wait for network to be idle to ensure artwork data has loaded + await page.waitForLoadState("networkidle") await expect(page.locator("div[data-test='artworkGrid']")).toHaveCount(1) const gridItems = page.locator("div[data-test='artworkGridItem']") expect(await gridItems.count()).toBeGreaterThanOrEqual(1) diff --git a/src/Apps/Artwork/Components/ArtworkLightbox.tsx b/src/Apps/Artwork/Components/ArtworkLightbox.tsx index f86eed9fe52..b4d577c9a65 100644 --- a/src/Apps/Artwork/Components/ArtworkLightbox.tsx +++ b/src/Apps/Artwork/Components/ArtworkLightbox.tsx @@ -4,7 +4,7 @@ import { Image, ResponsiveBox, } from "@artsy/palette" -import { useFlag } from "@unleash/proxy-client-react" +import { useFlag } from "System/FeatureFlags/useFlag" import { useSystemContext } from "System/Hooks/useSystemContext" import { useLocalImage } from "Utils/localImageHelpers" import { userIsTeam } from "Utils/user" diff --git a/src/Apps/Home/HomeApp.tsx b/src/Apps/Home/HomeApp.tsx index 1da3b3d5cfb..636182d42e7 100644 --- a/src/Apps/Home/HomeApp.tsx +++ b/src/Apps/Home/HomeApp.tsx @@ -1,7 +1,9 @@ import { Join, Spacer } from "@artsy/palette" import { MyBidsQueryRenderer } from "Apps/Auctions/Components/MyBids/MyBids" +import { HomeArtworkRecommendationsRailQueryRenderer } from "Apps/Home/Components/HomeArtworkRecommendationsRail" import { HomeAuctionLotsTabBar } from "Apps/Home/Components/HomeAuctionLotsTabBar" import { HomeNewWorksFromGalleriesYouFollowRailQueryRenderer } from "Apps/Home/Components/HomeNewWorksFromGalleriesYouFollowRail" +import { HomeRecommendedArtistsRailQueryRenderer } from "Apps/Home/Components/HomeRecommendedArtistsRail" import { ArtworkGridContextProvider } from "Components/ArtworkGrid/ArtworkGridContext" import { FlashBannerQueryRenderer } from "Components/FlashBanner" import type { HomeApp_featuredEventsOrderedSet$data } from "__generated__/HomeApp_featuredEventsOrderedSet.graphql" @@ -19,8 +21,6 @@ import { HomeMeta } from "./Components/HomeMeta" import { HomeStructuredData } from "./Components/HomeStructuredData" import { HomeTrendingArtistsRailQueryRenderer } from "./Components/HomeTrendingArtistsRail" import { HomeWorksForYouTabBar } from "./Components/HomeWorksForYouTabBar" -import { HomeRecommendedArtistsRailQueryRenderer } from "Apps/Home/Components/HomeRecommendedArtistsRail" -import { HomeArtworkRecommendationsRailQueryRenderer } from "Apps/Home/Components/HomeArtworkRecommendationsRail" interface HomeAppProps { featuredEventsOrderedSet: HomeApp_featuredEventsOrderedSet$data | null diff --git a/src/Apps/Order/Routes/Payment/index.tsx b/src/Apps/Order/Routes/Payment/index.tsx index 3201746522e..4d2101e42b8 100644 --- a/src/Apps/Order/Routes/Payment/index.tsx +++ b/src/Apps/Order/Routes/Payment/index.tsx @@ -12,7 +12,6 @@ import type { PaymentRouteSetOrderPaymentMutation } from "__generated__/PaymentR import type { Payment_me$data } from "__generated__/Payment_me.graphql" import type { Payment_order$data } from "__generated__/Payment_order.graphql" -import { useFlag } from "@unleash/proxy-client-react" import { useStripePaymentBySetupIntentId } from "Apps/Order/Hooks/useStripePaymentBySetupIntentId" import { useSetPayment } from "Apps/Order/Mutations/useSetPayment" import { @@ -20,6 +19,7 @@ import { injectCommitMutation, } from "Apps/Order/Utils/commitMutation" import { getInitialPaymentMethodValue } from "Apps/Order/Utils/orderUtils" +import { useFlag } from "System/FeatureFlags/useFlag" import { useRouter } from "System/Hooks/useRouter" // utils, hooks, mutations and system tools import { extractNodes } from "Utils/extractNodes" @@ -386,7 +386,7 @@ export const PaymentRoute: FC< let title = "An error occurred" let message = "Something went wrong. Please try again or contact orders@artsy.net" - let width: undefined | number = undefined + let width: undefined | number const errorCode = (paymentSetupError as any).code diff --git a/src/Apps/Order/Routes/Shipping/Components/FulfillmentDetails.tsx b/src/Apps/Order/Routes/Shipping/Components/FulfillmentDetails.tsx index 6ae64f29cca..bbea42da919 100644 --- a/src/Apps/Order/Routes/Shipping/Components/FulfillmentDetails.tsx +++ b/src/Apps/Order/Routes/Shipping/Components/FulfillmentDetails.tsx @@ -11,7 +11,7 @@ import { addressWithFallbackValues, getInitialShippingValues, } from "Apps/Order/Routes/Shipping/Utils/shippingUtils" -import { useFlag } from "@unleash/proxy-client-react" +import { useFlag } from "System/FeatureFlags/useFlag" import { useRouter } from "System/Hooks/useRouter" import { extractNodes } from "Utils/extractNodes" import createLogger from "Utils/logger" diff --git a/src/Apps/Settings/Routes/Insights/Components/InsightsMedianSalePrice.tsx b/src/Apps/Settings/Routes/Insights/Components/InsightsMedianSalePrice.tsx index 55e9893cb4b..0e7142c55db 100644 --- a/src/Apps/Settings/Routes/Insights/Components/InsightsMedianSalePrice.tsx +++ b/src/Apps/Settings/Routes/Insights/Components/InsightsMedianSalePrice.tsx @@ -1,7 +1,7 @@ import { Box, Clickable, Flex, Join, Spacer, Text } from "@artsy/palette" import { themeGet } from "@styled-system/theme-get" -import { useFlag } from "@unleash/proxy-client-react" import { EntityHeaderArtistFragmentContainer } from "Components/EntityHeaders/EntityHeaderArtist" +import { useFlag } from "System/FeatureFlags/useFlag" import { useRouter } from "System/Hooks/useRouter" import { extractNodes } from "Utils/extractNodes" import type { InsightsMedianSalePrice_me$data } from "__generated__/InsightsMedianSalePrice_me.graphql" diff --git a/src/Apps/Settings/Routes/Insights/InsightsRoute.tsx b/src/Apps/Settings/Routes/Insights/InsightsRoute.tsx index 01214c4604e..9ffc5524f11 100644 --- a/src/Apps/Settings/Routes/Insights/InsightsRoute.tsx +++ b/src/Apps/Settings/Routes/Insights/InsightsRoute.tsx @@ -2,7 +2,7 @@ import { Join, Spacer } from "@artsy/palette" import { InsightsCareerHighlightRailFragmentContainer } from "Apps/Settings/Routes/Insights/Components/CareerHighlights/InsightsCareerHighlightRail" import { InsightsMedianSalePriceFragmentContainer } from "Apps/Settings/Routes/Insights/Components/InsightsMedianSalePrice" import { MetaTags } from "Components/MetaTags" -import { useFlag } from "@unleash/proxy-client-react" +import { useFlag } from "System/FeatureFlags/useFlag" import { Media } from "Utils/Responsive" import type { InsightsRoute_me$data } from "__generated__/InsightsRoute_me.graphql" import { createFragmentContainer, graphql } from "react-relay" diff --git a/src/Apps/Settings/Routes/MyCollection/MyCollectionRoute.tsx b/src/Apps/Settings/Routes/MyCollection/MyCollectionRoute.tsx index 05dffc5c867..0f6363cce04 100644 --- a/src/Apps/Settings/Routes/MyCollection/MyCollectionRoute.tsx +++ b/src/Apps/Settings/Routes/MyCollection/MyCollectionRoute.tsx @@ -1,12 +1,12 @@ import { ActionType, ContextModule, OwnerType } from "@artsy/cohesion" import ShareIcon from "@artsy/icons/ShareIcon" import { Box, Button, Flex, Stack } from "@artsy/palette" -import { useFlag } from "@unleash/proxy-client-react" import { useMyCollectionTracking } from "Apps/CollectorProfile/Routes/MyCollection/Hooks/useMyCollectionTracking" import { MyCollectionArtworkGrid } from "Apps/Settings/Routes/MyCollection/Components/MyCollectionArtworkGrid" import { MetaTags } from "Components/MetaTags" import { ShareCollectionDialog } from "Components/ShareCollectionDialog" import { RouterLink } from "System/Components/RouterLink" +import { useFlag } from "System/FeatureFlags/useFlag" import { cleanLocalImages } from "Utils/localImageHelpers" import type { MyCollectionRoute_me$data } from "__generated__/MyCollectionRoute_me.graphql" import { type FC, useEffect, useState } from "react" diff --git a/src/Components/Address/AddressAutocompleteInput.tsx b/src/Components/Address/AddressAutocompleteInput.tsx index f2aa5270a0b..c06b9c50e4e 100644 --- a/src/Components/Address/AddressAutocompleteInput.tsx +++ b/src/Components/Address/AddressAutocompleteInput.tsx @@ -13,7 +13,7 @@ import { usePrevious, } from "@artsy/palette" import type { Address } from "Components/Address/utils" -import { useFlag } from "@unleash/proxy-client-react" +import { useFlag } from "System/FeatureFlags/useFlag" import { getENV } from "Utils/getENV" import { throttle, uniqBy } from "lodash" import { useCallback, useEffect, useReducer } from "react" diff --git a/src/Components/Address/useAddressAutocomplete.ts b/src/Components/Address/useAddressAutocomplete.ts index 8500dcd6950..297bbcbf102 100644 --- a/src/Components/Address/useAddressAutocomplete.ts +++ b/src/Components/Address/useAddressAutocomplete.ts @@ -6,8 +6,8 @@ import { } from "@artsy/cohesion" import type { AutocompleteInputOptionType } from "@artsy/palette" import type { Address } from "Components/Address/utils" +import { useFlag } from "System/FeatureFlags/useFlag" import { useAnalyticsContext } from "System/Hooks/useAnalyticsContext" -import { useFlag } from "@unleash/proxy-client-react" import { getENV } from "Utils/getENV" import { throttle, uniqBy } from "lodash" import { useCallback, useEffect, useMemo, useState } from "react" @@ -101,9 +101,7 @@ export const useAddressAutocomplete = ( } if (!apiKey) return null - const url = - "https://us-autocomplete-pro.api.smarty.com/lookup?" + - new URLSearchParams(params).toString() + const url = `https://us-autocomplete-pro.api.smarty.com/lookup?${new URLSearchParams(params).toString()}` const response = await fetch(url) const json = await response.json() diff --git a/src/Components/ArtworkFilter/ArtworkFilterPlaceholder.tsx b/src/Components/ArtworkFilter/ArtworkFilterPlaceholder.tsx index 11dfe21246e..8588dd12c1b 100644 --- a/src/Components/ArtworkFilter/ArtworkFilterPlaceholder.tsx +++ b/src/Components/ArtworkFilter/ArtworkFilterPlaceholder.tsx @@ -19,7 +19,6 @@ import { SkeletonText, Spacer, } from "@artsy/palette" -import { useFlag } from "@unleash/proxy-client-react" import { AppContainer } from "Apps/Components/AppContainer" import { HorizontalPadding } from "Apps/Components/HorizontalPadding" import { ArtworkFilterActiveFilters } from "Components/ArtworkFilter/ArtworkFilterActiveFilters" @@ -30,6 +29,7 @@ import { import { Sticky } from "Components/Sticky" import { useStickyBackdrop } from "Components/Sticky/useStickyBackdrop" import { useAnalyticsContext } from "System/Hooks/useAnalyticsContext" +import { useFlag } from "System/FeatureFlags/useFlag" import { Media } from "Utils/Responsive" interface ArtworkFilterPlaceholderProps extends BoxProps { diff --git a/src/Components/ArtworkFilter/ArtworkFilters/ArtworkLocationFilter.tsx b/src/Components/ArtworkFilter/ArtworkFilters/ArtworkLocationFilter.tsx index 48e6453f6fa..0c7f4b36dda 100644 --- a/src/Components/ArtworkFilter/ArtworkFilters/ArtworkLocationFilter.tsx +++ b/src/Components/ArtworkFilter/ArtworkFilters/ArtworkLocationFilter.tsx @@ -1,15 +1,15 @@ -import { SelectedFiltersCountsLabels } from "Components/ArtworkFilter/ArtworkFilterContext" -import { ResultsFilter } from "./ResultsFilter" -import { useFlag } from "@unleash/proxy-client-react" -import { getArtworkLocationSearchableText } from "Components/ArtworkFilter/Utils/getArtworkLocationSearchableText" -import { useTracking } from "react-tracking" -import { useAnalyticsContext } from "System/Hooks/useAnalyticsContext" -import type { FilterSelectChangeState } from "@artsy/palette" import { ActionType, + type CommercialFilterSelectedAll, ContextModule, - CommercialFilterSelectedAll, } from "@artsy/cohesion" +import type { FilterSelectChangeState } from "@artsy/palette" +import { SelectedFiltersCountsLabels } from "Components/ArtworkFilter/ArtworkFilterContext" +import { getArtworkLocationSearchableText } from "Components/ArtworkFilter/Utils/getArtworkLocationSearchableText" +import { useFlag } from "System/FeatureFlags/useFlag" +import { useAnalyticsContext } from "System/Hooks/useAnalyticsContext" +import { useTracking } from "react-tracking" +import { ResultsFilter } from "./ResultsFilter" export interface ArtworkLocationFilterProps { expanded?: boolean diff --git a/src/Components/ArtworkFilter/index.tsx b/src/Components/ArtworkFilter/index.tsx index e7c6d095803..c3b1ac42cca 100644 --- a/src/Components/ArtworkFilter/index.tsx +++ b/src/Components/ArtworkFilter/index.tsx @@ -22,7 +22,6 @@ import { Spacer, Text, } from "@artsy/palette" -import { useFlag, useVariant } from "@unleash/proxy-client-react" import { AppContainer } from "Apps/Components/AppContainer" import { HorizontalPadding } from "Apps/Components/HorizontalPadding" import { ArtworkFilterActiveFilters } from "Components/ArtworkFilter/ArtworkFilterActiveFilters" @@ -44,6 +43,8 @@ import { } from "Components/ProgressiveOnboarding/ProgressiveOnboardingImmersiveView" import { Sticky } from "Components/Sticky" import { useStickyBackdrop } from "Components/Sticky/useStickyBackdrop" +import { useFlag } from "System/FeatureFlags/useFlag" +import { useVariant } from "System/FeatureFlags/useVariant" import { useAnalyticsContext } from "System/Hooks/useAnalyticsContext" import { useSystemContext } from "System/Hooks/useSystemContext" import { Jump, useJump } from "Utils/Hooks/useJump" diff --git a/src/System/Contexts/SystemContext.tsx b/src/System/Contexts/SystemContext.tsx index 56bef7643cb..f2a7f052df9 100644 --- a/src/System/Contexts/SystemContext.tsx +++ b/src/System/Contexts/SystemContext.tsx @@ -5,6 +5,7 @@ import { getUser } from "Utils/user" import type { Router } from "found" import { createContext, useState } from "react" import type { Environment } from "react-relay" +import type { IToggle } from "unleash-proxy-client" export type UserPreferences = { metric: Metric @@ -20,6 +21,7 @@ export interface SystemContextState { interface FeatureFlags { isEnabled: (flag: string) => boolean getVariant: (flag: string) => any + toggles: IToggle[] } export interface SystemContextProps extends SystemContextState { diff --git a/src/System/FeatureFlags/FeatureFlagContext.tsx b/src/System/FeatureFlags/FeatureFlagContext.tsx index b338884508e..84d45c56cd8 100644 --- a/src/System/FeatureFlags/FeatureFlagContext.tsx +++ b/src/System/FeatureFlags/FeatureFlagContext.tsx @@ -9,7 +9,7 @@ import { getENV } from "Utils/getENV" export const FeatureFlagProvider: React.FC< React.PropsWithChildren > = ({ children }) => { - const { user } = useSystemContext() + const { user, featureFlags } = useSystemContext() const unleashConfig: IConfig = { url: `${getENV("UNLEASH_API_URL")}/frontend`, @@ -21,6 +21,7 @@ export const FeatureFlagProvider: React.FC< userId: user?.id, sessionId: getENV("SESSION_ID"), }, + bootstrap: featureFlags?.toggles || [], } return {children} diff --git a/src/System/FeatureFlags/unleashClient.ts b/src/System/FeatureFlags/unleashClient.ts index 7a121672a06..9d3c644ffc2 100644 --- a/src/System/FeatureFlags/unleashClient.ts +++ b/src/System/FeatureFlags/unleashClient.ts @@ -3,7 +3,7 @@ import { UnleashClient } from "unleash-proxy-client" let unleashClient: UnleashClient | null = null -export function getOrInitUnleashClient(): UnleashClient { +export async function getOrInitUnleashClient(): Promise { if (unleashClient) { return unleashClient } @@ -24,5 +24,34 @@ export function getOrInitUnleashClient(): UnleashClient { unleashClient = new UnleashClient(config) unleashClient.start() + await new Promise(resolve => { + if (unleashClient) { + const fallbackTimeout = setTimeout(() => { + console.warn( + "[unleashClient] Unleash initialization timeout. Continuing...", + ) + resolve() + }, 5000) + + unleashClient.on("ready", () => { + clearInterval(fallbackTimeout) + resolve() + }) + + unleashClient.on("error", error => { + console.warn( + "[unleashClient] Failed to initialize Unleash, continuing without feature flags:", + error, + ) + + clearInterval(fallbackTimeout) + resolve() + }) + } else { + console.error("[unleashClient] Failed to initialize Unleash client") + resolve() + } + }) + return unleashClient } diff --git a/src/System/FeatureFlags/unleashServer.ts b/src/System/FeatureFlags/unleashServer.ts index 7691d91dc08..30d2bfcbf64 100644 --- a/src/System/FeatureFlags/unleashServer.ts +++ b/src/System/FeatureFlags/unleashServer.ts @@ -9,7 +9,7 @@ import { Unleash } from "unleash-client" let unleashServer: Unleash | null = null -export function getOrInitUnleashServer(): Unleash { +export async function getOrInitUnleashServer(): Promise { if (unleashServer) { return unleashServer } @@ -26,6 +26,35 @@ export function getOrInitUnleashServer(): Unleash { unleashServer = new Unleash(config) + await new Promise(resolve => { + if (unleashServer) { + const fallbackTimeout = setTimeout(() => { + console.warn( + "[unleashServer] Unleash initialization timeout. Continuing...", + ) + resolve() + }, 5000) + + unleashServer.on("ready", () => { + clearInterval(fallbackTimeout) + resolve() + }) + + unleashServer.on("error", error => { + console.warn( + "[unleashServer] Failed to initialize Unleash, continuing without feature flags:", + error, + ) + + clearInterval(fallbackTimeout) + resolve() + }) + } else { + console.error("[unleashServer] Failed to initialize Unleash server") + resolve() + } + }) + return unleashServer } diff --git a/src/System/FeatureFlags/useFlag.ts b/src/System/FeatureFlags/useFlag.ts new file mode 100644 index 00000000000..ed6f799edf3 --- /dev/null +++ b/src/System/FeatureFlags/useFlag.ts @@ -0,0 +1,14 @@ +/** biome-ignore-all lint/correctness/useHookAtTopLevel: This is our wrapper */ + +import { useSystemContext } from "System/Hooks/useSystemContext" +import { useFlag as useUnleashFlag } from "@unleash/proxy-client-react" + +export function useFlag(flagName: string): boolean { + const systemContext = useSystemContext() + + if (typeof window === "undefined") { + return systemContext.featureFlags?.isEnabled(flagName) ?? false + } + + return useUnleashFlag(flagName) +} diff --git a/src/System/FeatureFlags/useVariant.ts b/src/System/FeatureFlags/useVariant.ts new file mode 100644 index 00000000000..1094bf3cc10 --- /dev/null +++ b/src/System/FeatureFlags/useVariant.ts @@ -0,0 +1,19 @@ +/** biome-ignore-all lint/correctness/useHookAtTopLevel: This is our wrapper */ + +import { useSystemContext } from "System/Hooks/useSystemContext" +import { useVariant as useUnleashVariant } from "@unleash/proxy-client-react" + +export function useVariant(flagName: string) { + const systemContext = useSystemContext() + + if (typeof window === "undefined") { + return ( + systemContext.featureFlags?.getVariant(flagName) ?? { + name: "disabled", + enabled: false, + } + ) + } + + return useUnleashVariant(flagName) +} diff --git a/src/System/Router/__tests__/clientRouter.jest.tsx b/src/System/Router/__tests__/clientRouter.jest.tsx index 28bc3e66164..54f7cc1f639 100644 --- a/src/System/Router/__tests__/clientRouter.jest.tsx +++ b/src/System/Router/__tests__/clientRouter.jest.tsx @@ -174,6 +174,7 @@ describe("clientRouter", () => { featureFlags: { isEnabled: jest.fn().mockReturnValue(true), getVariant: jest.fn(), + toggles: [], }, }, }) diff --git a/src/client.tsx b/src/client.tsx index 5dfbfd3d9e7..24261dc2552 100644 --- a/src/client.tsx +++ b/src/client.tsx @@ -15,7 +15,7 @@ setupWebVitals() // Rehydrate app ;(async () => { - const unleashClient = getOrInitUnleashClient() + const unleashClient = await getOrInitUnleashClient() const { ClientRouter } = await setupClientRouter({ routes: getAppRoutes(), @@ -23,6 +23,7 @@ setupWebVitals() featureFlags: { isEnabled: unleashClient.isEnabled.bind(unleashClient), getVariant: unleashClient.getVariant.bind(unleashClient), + toggles: unleashClient.getAllToggles(), }, }, }) diff --git a/src/server.ts b/src/server.ts index 14237ba0f03..a740a5bcc3d 100644 --- a/src/server.ts +++ b/src/server.ts @@ -19,11 +19,28 @@ import { setupServerRouter } from "System/Router/serverRouter" import express from "express" import type { NextFunction } from "express" import { initializeMiddleware } from "middleware" +import type { Unleash } from "unleash-client" +import type { IToggle } from "unleash-proxy-client" const app = express() -// Initialize unleash server client -const unleashClient = getOrInitUnleashServer() +// Initialize unleash server client and wait for it to be ready +let unleashClient: Unleash | null = null + +app.use(async (req, res, next) => { + if (!unleashClient) { + try { + unleashClient = await getOrInitUnleashServer() + } catch (error) { + console.warn( + "[force] Failed to initialize Unleash, continuing without feature flags:", + error, + ) + } + } + + next() +}) // Mount middleware initializeMiddleware(app) @@ -54,9 +71,10 @@ app.get( context: { featureFlags: { isEnabled: (flag: string) => - unleashClient.isEnabled(flag, unleashContext), + !!unleashClient?.isEnabled(flag, unleashContext), getVariant: (flag: string) => - unleashClient.getVariant(flag, unleashContext), + unleashClient?.getVariant(flag, unleashContext), + toggles: unleashClient?.getFeatureToggleDefinitions() as IToggle[], }, }, }) @@ -84,7 +102,7 @@ app // Should be second to last .use(redirectsServerRoutes) // Final middleware. Errors and anything else should be last - .use("*", (req, res, next) => { + .use("*", (_req, _res, next) => { const err = new Error() // @ts-ignore -- FIXME: status does not exist on err err.status = 404 diff --git a/yarn.lock b/yarn.lock index e40ff2b88cd..43b2b82a896 100644 --- a/yarn.lock +++ b/yarn.lock @@ -554,18 +554,18 @@ __metadata: languageName: node linkType: hard -"@biomejs/biome@npm:1.9.4": - version: 1.9.4 - resolution: "@biomejs/biome@npm:1.9.4" - dependencies: - "@biomejs/cli-darwin-arm64": "npm:1.9.4" - "@biomejs/cli-darwin-x64": "npm:1.9.4" - "@biomejs/cli-linux-arm64": "npm:1.9.4" - "@biomejs/cli-linux-arm64-musl": "npm:1.9.4" - "@biomejs/cli-linux-x64": "npm:1.9.4" - "@biomejs/cli-linux-x64-musl": "npm:1.9.4" - "@biomejs/cli-win32-arm64": "npm:1.9.4" - "@biomejs/cli-win32-x64": "npm:1.9.4" +"@biomejs/biome@npm:^2.3.5": + version: 2.3.5 + resolution: "@biomejs/biome@npm:2.3.5" + dependencies: + "@biomejs/cli-darwin-arm64": "npm:2.3.5" + "@biomejs/cli-darwin-x64": "npm:2.3.5" + "@biomejs/cli-linux-arm64": "npm:2.3.5" + "@biomejs/cli-linux-arm64-musl": "npm:2.3.5" + "@biomejs/cli-linux-x64": "npm:2.3.5" + "@biomejs/cli-linux-x64-musl": "npm:2.3.5" + "@biomejs/cli-win32-arm64": "npm:2.3.5" + "@biomejs/cli-win32-x64": "npm:2.3.5" dependenciesMeta: "@biomejs/cli-darwin-arm64": optional: true @@ -585,62 +585,62 @@ __metadata: optional: true bin: biome: bin/biome - checksum: 10c0/b5655c5aed9a6fffe24f7d04f15ba4444389d0e891c9ed9106fab7388ac9b4be63185852cc2a937b22940dac3e550b71032a4afd306925cfea436c33e5646b3e + checksum: 10c0/c29264d9e3427b665a169af01aadea5584def961397ff6e1d1be4f16c5d37aca1b1b6ea1e6190c63330d0d8022009261ddc4c42a39727f77d5668b91e427b4f3 languageName: node linkType: hard -"@biomejs/cli-darwin-arm64@npm:1.9.4": - version: 1.9.4 - resolution: "@biomejs/cli-darwin-arm64@npm:1.9.4" +"@biomejs/cli-darwin-arm64@npm:2.3.5": + version: 2.3.5 + resolution: "@biomejs/cli-darwin-arm64@npm:2.3.5" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@biomejs/cli-darwin-x64@npm:1.9.4": - version: 1.9.4 - resolution: "@biomejs/cli-darwin-x64@npm:1.9.4" +"@biomejs/cli-darwin-x64@npm:2.3.5": + version: 2.3.5 + resolution: "@biomejs/cli-darwin-x64@npm:2.3.5" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@biomejs/cli-linux-arm64-musl@npm:1.9.4": - version: 1.9.4 - resolution: "@biomejs/cli-linux-arm64-musl@npm:1.9.4" +"@biomejs/cli-linux-arm64-musl@npm:2.3.5": + version: 2.3.5 + resolution: "@biomejs/cli-linux-arm64-musl@npm:2.3.5" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@biomejs/cli-linux-arm64@npm:1.9.4": - version: 1.9.4 - resolution: "@biomejs/cli-linux-arm64@npm:1.9.4" +"@biomejs/cli-linux-arm64@npm:2.3.5": + version: 2.3.5 + resolution: "@biomejs/cli-linux-arm64@npm:2.3.5" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@biomejs/cli-linux-x64-musl@npm:1.9.4": - version: 1.9.4 - resolution: "@biomejs/cli-linux-x64-musl@npm:1.9.4" +"@biomejs/cli-linux-x64-musl@npm:2.3.5": + version: 2.3.5 + resolution: "@biomejs/cli-linux-x64-musl@npm:2.3.5" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@biomejs/cli-linux-x64@npm:1.9.4": - version: 1.9.4 - resolution: "@biomejs/cli-linux-x64@npm:1.9.4" +"@biomejs/cli-linux-x64@npm:2.3.5": + version: 2.3.5 + resolution: "@biomejs/cli-linux-x64@npm:2.3.5" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@biomejs/cli-win32-arm64@npm:1.9.4": - version: 1.9.4 - resolution: "@biomejs/cli-win32-arm64@npm:1.9.4" +"@biomejs/cli-win32-arm64@npm:2.3.5": + version: 2.3.5 + resolution: "@biomejs/cli-win32-arm64@npm:2.3.5" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@biomejs/cli-win32-x64@npm:1.9.4": - version: 1.9.4 - resolution: "@biomejs/cli-win32-x64@npm:1.9.4" +"@biomejs/cli-win32-x64@npm:2.3.5": + version: 2.3.5 + resolution: "@biomejs/cli-win32-x64@npm:2.3.5" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -4136,6 +4136,33 @@ __metadata: languageName: node linkType: hard +"@types/eslint-scope@npm:^3.7.7": + version: 3.7.7 + resolution: "@types/eslint-scope@npm:3.7.7" + dependencies: + "@types/eslint": "npm:*" + "@types/estree": "npm:*" + checksum: 10c0/a0ecbdf2f03912679440550817ff77ef39a30fa8bfdacaf6372b88b1f931828aec392f52283240f0d648cf3055c5ddc564544a626bcf245f3d09fcb099ebe3cc + languageName: node + linkType: hard + +"@types/eslint@npm:*": + version: 9.6.1 + resolution: "@types/eslint@npm:9.6.1" + dependencies: + "@types/estree": "npm:*" + "@types/json-schema": "npm:*" + checksum: 10c0/69ba24fee600d1e4c5abe0df086c1a4d798abf13792d8cfab912d76817fe1a894359a1518557d21237fbaf6eda93c5ab9309143dee4c59ef54336d1b3570420e + languageName: node + linkType: hard + +"@types/estree@npm:*, @types/estree@npm:^1.0.8": + version: 1.0.8 + resolution: "@types/estree@npm:1.0.8" + checksum: 10c0/39d34d1afaa338ab9763f37ad6066e3f349444f9052b9676a7cc0252ef9485a41c6d81c9c4e0d26e9077993354edf25efc853f3224dd4b447175ef62bdcc86a5 + languageName: node + linkType: hard + "@types/estree@npm:^1.0.0": version: 1.0.1 resolution: "@types/estree@npm:1.0.1" @@ -4272,6 +4299,13 @@ __metadata: languageName: node linkType: hard +"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.15, @types/json-schema@npm:^7.0.9": + version: 7.0.15 + resolution: "@types/json-schema@npm:7.0.15" + checksum: 10c0/a996a745e6c5d60292f36731dd41341339d4eeed8180bb09226e5c8d23759067692b1d88e5d91d72ee83dfc00d3aca8e7bd43ea120516c17922cbcb7c3e252db + languageName: node + linkType: hard + "@types/jwt-decode@npm:2.2.0": version: 2.2.0 resolution: "@types/jwt-decode@npm:2.2.0" @@ -4297,6 +4331,15 @@ __metadata: languageName: node linkType: hard +"@types/loadable__webpack-plugin@npm:^5.15.1": + version: 5.15.1 + resolution: "@types/loadable__webpack-plugin@npm:5.15.1" + dependencies: + "@types/webpack": "npm:^4" + checksum: 10c0/c6b8ce3c9f0caa538fc9fe93b3b99bd5d1d9e3a1adc2dc7bebe9816aa16333d2e96e0121129fdf01957910ce9db05246ba67ca9cc7b9acda822be74a658cc89d + languageName: node + linkType: hard + "@types/lodash@npm:4.14.111": version: 4.14.111 resolution: "@types/lodash@npm:4.14.111" @@ -4636,6 +4679,13 @@ __metadata: languageName: node linkType: hard +"@types/source-list-map@npm:*": + version: 0.1.6 + resolution: "@types/source-list-map@npm:0.1.6" + checksum: 10c0/1e6d8d4a48535c51368c65bb2c44a1c9fd9afe2eeefefa32cbf06f9c191f7b20f638b3aa755100de0a750b0ba6a76140e912f1bee75705bc2b9a58b5a5185539 + languageName: node + linkType: hard + "@types/stack-utils@npm:^2.0.0": version: 2.0.1 resolution: "@types/stack-utils@npm:2.0.1" @@ -4676,6 +4726,13 @@ __metadata: languageName: node linkType: hard +"@types/tapable@npm:^1": + version: 1.0.12 + resolution: "@types/tapable@npm:1.0.12" + checksum: 10c0/d6a080f5839b323eb96dd5b65a6c3161c1297d8c2433eb52437912d1c3df54e38fce12ce7a57650f6453d96942298bd0935436e2501d09e407b7f41634483131 + languageName: node + linkType: hard + "@types/testing-library__jest-dom@npm:^6.0.0": version: 6.0.0 resolution: "@types/testing-library__jest-dom@npm:6.0.0" @@ -4701,6 +4758,15 @@ __metadata: languageName: node linkType: hard +"@types/uglify-js@npm:*": + version: 3.17.5 + resolution: "@types/uglify-js@npm:3.17.5" + dependencies: + source-map: "npm:^0.6.1" + checksum: 10c0/e225d7da26a7a8b71e71f584ab2b4e14f9bd61e2ae4c72fa14d3d862ebfb8f3c1c24414048f23ea485e93618d3370e6c9d5e5af51b6a836d48ec453a26e419f4 + languageName: node + linkType: hard + "@types/underscore.string@npm:0.0.32": version: 0.0.32 resolution: "@types/underscore.string@npm:0.0.32" @@ -4731,6 +4797,41 @@ __metadata: languageName: node linkType: hard +"@types/webpack-node-externals@npm:^3.0.4": + version: 3.0.4 + resolution: "@types/webpack-node-externals@npm:3.0.4" + dependencies: + "@types/node": "npm:*" + webpack: "npm:^5" + checksum: 10c0/07a324c0130fb5b49ae31010ecee2690330e9f397b13dd7e826f8b9adeb2be415c57261f5b39c20350aeb53c972d36cea38c6feed9414487c2bbdc3ae41429f4 + languageName: node + linkType: hard + +"@types/webpack-sources@npm:*": + version: 3.2.3 + resolution: "@types/webpack-sources@npm:3.2.3" + dependencies: + "@types/node": "npm:*" + "@types/source-list-map": "npm:*" + source-map: "npm:^0.7.3" + checksum: 10c0/74e9dfdd38bc345ce99442f3be5b5ad1efc7af5890304175c141717a7c0b38c152e6f7fe1d2875fc19aaa68964019ff4661678eba7fdeee8c3ad42dc6dbf6b62 + languageName: node + linkType: hard + +"@types/webpack@npm:^4": + version: 4.41.40 + resolution: "@types/webpack@npm:4.41.40" + dependencies: + "@types/node": "npm:*" + "@types/tapable": "npm:^1" + "@types/uglify-js": "npm:*" + "@types/webpack-sources": "npm:*" + anymatch: "npm:^3.0.0" + source-map: "npm:^0.6.0" + checksum: 10c0/ecd530e5db4c21ec61795eec538026f96c126323836249a83e72805afd1d0b1141fc781f14d4a59d77f877523384b4c5d79dc391cfb901e7a781a9aa085f8198 + languageName: node + linkType: hard + "@types/yargs-parser@npm:*": version: 20.2.0 resolution: "@types/yargs-parser@npm:20.2.0" @@ -4825,6 +4926,171 @@ __metadata: languageName: node linkType: hard +"@webassemblyjs/ast@npm:1.14.1, @webassemblyjs/ast@npm:^1.14.1": + version: 1.14.1 + resolution: "@webassemblyjs/ast@npm:1.14.1" + dependencies: + "@webassemblyjs/helper-numbers": "npm:1.13.2" + "@webassemblyjs/helper-wasm-bytecode": "npm:1.13.2" + checksum: 10c0/67a59be8ed50ddd33fbb2e09daa5193ac215bf7f40a9371be9a0d9797a114d0d1196316d2f3943efdb923a3d809175e1563a3cb80c814fb8edccd1e77494972b + languageName: node + linkType: hard + +"@webassemblyjs/floating-point-hex-parser@npm:1.13.2": + version: 1.13.2 + resolution: "@webassemblyjs/floating-point-hex-parser@npm:1.13.2" + checksum: 10c0/0e88bdb8b50507d9938be64df0867f00396b55eba9df7d3546eb5dc0ca64d62e06f8d881ec4a6153f2127d0f4c11d102b6e7d17aec2f26bb5ff95a5e60652412 + languageName: node + linkType: hard + +"@webassemblyjs/helper-api-error@npm:1.13.2": + version: 1.13.2 + resolution: "@webassemblyjs/helper-api-error@npm:1.13.2" + checksum: 10c0/31be497f996ed30aae4c08cac3cce50c8dcd5b29660383c0155fce1753804fc55d47fcba74e10141c7dd2899033164e117b3bcfcda23a6b043e4ded4f1003dfb + languageName: node + linkType: hard + +"@webassemblyjs/helper-buffer@npm:1.14.1": + version: 1.14.1 + resolution: "@webassemblyjs/helper-buffer@npm:1.14.1" + checksum: 10c0/0d54105dc373c0fe6287f1091e41e3a02e36cdc05e8cf8533cdc16c59ff05a646355415893449d3768cda588af451c274f13263300a251dc11a575bc4c9bd210 + languageName: node + linkType: hard + +"@webassemblyjs/helper-numbers@npm:1.13.2": + version: 1.13.2 + resolution: "@webassemblyjs/helper-numbers@npm:1.13.2" + dependencies: + "@webassemblyjs/floating-point-hex-parser": "npm:1.13.2" + "@webassemblyjs/helper-api-error": "npm:1.13.2" + "@xtuc/long": "npm:4.2.2" + checksum: 10c0/9c46852f31b234a8fb5a5a9d3f027bc542392a0d4de32f1a9c0075d5e8684aa073cb5929b56df565500b3f9cc0a2ab983b650314295b9bf208d1a1651bfc825a + languageName: node + linkType: hard + +"@webassemblyjs/helper-wasm-bytecode@npm:1.13.2": + version: 1.13.2 + resolution: "@webassemblyjs/helper-wasm-bytecode@npm:1.13.2" + checksum: 10c0/c4355d14f369b30cf3cbdd3acfafc7d0488e086be6d578e3c9780bd1b512932352246be96e034e2a7fcfba4f540ec813352f312bfcbbfe5bcfbf694f82ccc682 + languageName: node + linkType: hard + +"@webassemblyjs/helper-wasm-section@npm:1.14.1": + version: 1.14.1 + resolution: "@webassemblyjs/helper-wasm-section@npm:1.14.1" + dependencies: + "@webassemblyjs/ast": "npm:1.14.1" + "@webassemblyjs/helper-buffer": "npm:1.14.1" + "@webassemblyjs/helper-wasm-bytecode": "npm:1.13.2" + "@webassemblyjs/wasm-gen": "npm:1.14.1" + checksum: 10c0/1f9b33731c3c6dbac3a9c483269562fa00d1b6a4e7133217f40e83e975e636fd0f8736e53abd9a47b06b66082ecc976c7384391ab0a68e12d509ea4e4b948d64 + languageName: node + linkType: hard + +"@webassemblyjs/ieee754@npm:1.13.2": + version: 1.13.2 + resolution: "@webassemblyjs/ieee754@npm:1.13.2" + dependencies: + "@xtuc/ieee754": "npm:^1.2.0" + checksum: 10c0/2e732ca78c6fbae3c9b112f4915d85caecdab285c0b337954b180460290ccd0fb00d2b1dc4bb69df3504abead5191e0d28d0d17dfd6c9d2f30acac8c4961c8a7 + languageName: node + linkType: hard + +"@webassemblyjs/leb128@npm:1.13.2": + version: 1.13.2 + resolution: "@webassemblyjs/leb128@npm:1.13.2" + dependencies: + "@xtuc/long": "npm:4.2.2" + checksum: 10c0/dad5ef9e383c8ab523ce432dfd80098384bf01c45f70eb179d594f85ce5db2f80fa8c9cba03adafd85684e6d6310f0d3969a882538975989919329ac4c984659 + languageName: node + linkType: hard + +"@webassemblyjs/utf8@npm:1.13.2": + version: 1.13.2 + resolution: "@webassemblyjs/utf8@npm:1.13.2" + checksum: 10c0/d3fac9130b0e3e5a1a7f2886124a278e9323827c87a2b971e6d0da22a2ba1278ac9f66a4f2e363ecd9fac8da42e6941b22df061a119e5c0335f81006de9ee799 + languageName: node + linkType: hard + +"@webassemblyjs/wasm-edit@npm:^1.14.1": + version: 1.14.1 + resolution: "@webassemblyjs/wasm-edit@npm:1.14.1" + dependencies: + "@webassemblyjs/ast": "npm:1.14.1" + "@webassemblyjs/helper-buffer": "npm:1.14.1" + "@webassemblyjs/helper-wasm-bytecode": "npm:1.13.2" + "@webassemblyjs/helper-wasm-section": "npm:1.14.1" + "@webassemblyjs/wasm-gen": "npm:1.14.1" + "@webassemblyjs/wasm-opt": "npm:1.14.1" + "@webassemblyjs/wasm-parser": "npm:1.14.1" + "@webassemblyjs/wast-printer": "npm:1.14.1" + checksum: 10c0/5ac4781086a2ca4b320bdbfd965a209655fe8a208ca38d89197148f8597e587c9a2c94fb6bd6f1a7dbd4527c49c6844fcdc2af981f8d793a97bf63a016aa86d2 + languageName: node + linkType: hard + +"@webassemblyjs/wasm-gen@npm:1.14.1": + version: 1.14.1 + resolution: "@webassemblyjs/wasm-gen@npm:1.14.1" + dependencies: + "@webassemblyjs/ast": "npm:1.14.1" + "@webassemblyjs/helper-wasm-bytecode": "npm:1.13.2" + "@webassemblyjs/ieee754": "npm:1.13.2" + "@webassemblyjs/leb128": "npm:1.13.2" + "@webassemblyjs/utf8": "npm:1.13.2" + checksum: 10c0/d678810d7f3f8fecb2e2bdadfb9afad2ec1d2bc79f59e4711ab49c81cec578371e22732d4966f59067abe5fba8e9c54923b57060a729d28d408e608beef67b10 + languageName: node + linkType: hard + +"@webassemblyjs/wasm-opt@npm:1.14.1": + version: 1.14.1 + resolution: "@webassemblyjs/wasm-opt@npm:1.14.1" + dependencies: + "@webassemblyjs/ast": "npm:1.14.1" + "@webassemblyjs/helper-buffer": "npm:1.14.1" + "@webassemblyjs/wasm-gen": "npm:1.14.1" + "@webassemblyjs/wasm-parser": "npm:1.14.1" + checksum: 10c0/515bfb15277ee99ba6b11d2232ddbf22aed32aad6d0956fe8a0a0a004a1b5a3a277a71d9a3a38365d0538ac40d1b7b7243b1a244ad6cd6dece1c1bb2eb5de7ee + languageName: node + linkType: hard + +"@webassemblyjs/wasm-parser@npm:1.14.1, @webassemblyjs/wasm-parser@npm:^1.14.1": + version: 1.14.1 + resolution: "@webassemblyjs/wasm-parser@npm:1.14.1" + dependencies: + "@webassemblyjs/ast": "npm:1.14.1" + "@webassemblyjs/helper-api-error": "npm:1.13.2" + "@webassemblyjs/helper-wasm-bytecode": "npm:1.13.2" + "@webassemblyjs/ieee754": "npm:1.13.2" + "@webassemblyjs/leb128": "npm:1.13.2" + "@webassemblyjs/utf8": "npm:1.13.2" + checksum: 10c0/95427b9e5addbd0f647939bd28e3e06b8deefdbdadcf892385b5edc70091bf9b92fa5faac3fce8333554437c5d85835afef8c8a7d9d27ab6ba01ffab954db8c6 + languageName: node + linkType: hard + +"@webassemblyjs/wast-printer@npm:1.14.1": + version: 1.14.1 + resolution: "@webassemblyjs/wast-printer@npm:1.14.1" + dependencies: + "@webassemblyjs/ast": "npm:1.14.1" + "@xtuc/long": "npm:4.2.2" + checksum: 10c0/8d7768608996a052545251e896eac079c98e0401842af8dd4de78fba8d90bd505efb6c537e909cd6dae96e09db3fa2e765a6f26492553a675da56e2db51f9d24 + languageName: node + linkType: hard + +"@xtuc/ieee754@npm:^1.2.0": + version: 1.2.0 + resolution: "@xtuc/ieee754@npm:1.2.0" + checksum: 10c0/a8565d29d135039bd99ae4b2220d3e167d22cf53f867e491ed479b3f84f895742d0097f935b19aab90265a23d5d46711e4204f14c479ae3637fbf06c4666882f + languageName: node + linkType: hard + +"@xtuc/long@npm:4.2.2": + version: 4.2.2 + resolution: "@xtuc/long@npm:4.2.2" + checksum: 10c0/8582cbc69c79ad2d31568c412129bf23d2b1210a1dfb60c82d5a1df93334da4ee51f3057051658569e2c196d8dc33bc05ae6b974a711d0d16e801e1d0647ccd1 + languageName: node + linkType: hard + "@yarnpkg/lockfile@npm:^1.1.0": version: 1.1.0 resolution: "@yarnpkg/lockfile@npm:1.1.0" @@ -4891,6 +5157,15 @@ __metadata: languageName: node linkType: hard +"acorn-import-phases@npm:^1.0.3": + version: 1.0.4 + resolution: "acorn-import-phases@npm:1.0.4" + peerDependencies: + acorn: ^8.14.0 + checksum: 10c0/338eb46fc1aed5544f628344cb9af189450b401d152ceadbf1f5746901a5d923016cd0e7740d5606062d374fdf6941c29bb515d2bd133c4f4242d5d4cd73a3c7 + languageName: node + linkType: hard + "acorn-walk@npm:^8.0.2": version: 8.2.0 resolution: "acorn-walk@npm:8.2.0" @@ -4907,6 +5182,15 @@ __metadata: languageName: node linkType: hard +"acorn@npm:^8.15.0": + version: 8.15.0 + resolution: "acorn@npm:8.15.0" + bin: + acorn: bin/acorn + checksum: 10c0/dec73ff59b7d6628a01eebaece7f2bdb8bb62b9b5926dcad0f8931f2b8b79c2be21f6c68ac095592adb5adb15831a3635d9343e6a91d028bbe85d564875ec3ec + languageName: node + linkType: hard + "actioncable@npm:^5.2.7-1": version: 5.2.7-1 resolution: "actioncable@npm:5.2.7-1" @@ -4949,6 +5233,43 @@ __metadata: languageName: node linkType: hard +"ajv-formats@npm:^2.1.1": + version: 2.1.1 + resolution: "ajv-formats@npm:2.1.1" + dependencies: + ajv: "npm:^8.0.0" + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + checksum: 10c0/e43ba22e91b6a48d96224b83d260d3a3a561b42d391f8d3c6d2c1559f9aa5b253bfb306bc94bbeca1d967c014e15a6efe9a207309e95b3eaae07fcbcdc2af662 + languageName: node + linkType: hard + +"ajv-keywords@npm:^5.1.0": + version: 5.1.0 + resolution: "ajv-keywords@npm:5.1.0" + dependencies: + fast-deep-equal: "npm:^3.1.3" + peerDependencies: + ajv: ^8.8.2 + checksum: 10c0/18bec51f0171b83123ba1d8883c126e60c6f420cef885250898bf77a8d3e65e3bfb9e8564f497e30bdbe762a83e0d144a36931328616a973ee669dc74d4a9590 + languageName: node + linkType: hard + +"ajv@npm:^8.0.0, ajv@npm:^8.9.0": + version: 8.17.1 + resolution: "ajv@npm:8.17.1" + dependencies: + fast-deep-equal: "npm:^3.1.3" + fast-uri: "npm:^3.0.1" + json-schema-traverse: "npm:^1.0.0" + require-from-string: "npm:^2.0.2" + checksum: 10c0/ec3ba10a573c6b60f94639ffc53526275917a2df6810e4ab5a6b959d87459f9ef3f00d5e7865b82677cb7d21590355b34da14d1d0b9c32d75f95a187e76fff35 + languageName: node + linkType: hard + "analytics-node@npm:2.4.1": version: 2.4.1 resolution: "analytics-node@npm:2.4.1" @@ -5049,7 +5370,7 @@ __metadata: languageName: node linkType: hard -"anymatch@npm:^3.0.3, anymatch@npm:~3.1.2": +"anymatch@npm:^3.0.0, anymatch@npm:^3.0.3, anymatch@npm:~3.1.2": version: 3.1.3 resolution: "anymatch@npm:3.1.3" dependencies: @@ -5486,6 +5807,15 @@ __metadata: languageName: node linkType: hard +"baseline-browser-mapping@npm:^2.8.25": + version: 2.8.28 + resolution: "baseline-browser-mapping@npm:2.8.28" + bin: + baseline-browser-mapping: dist/cli.js + checksum: 10c0/d157d73de33bff69cf3413983dc1b2421063cd1c895e9edabc22dcb6667f7e17762b46ebeee5eee7496271351754c12750867c6ea5cb432f1bbe33dc5c62d1e6 + languageName: node + linkType: hard + "basic-auth@npm:~2.0.1": version: 2.0.1 resolution: "basic-auth@npm:2.0.1" @@ -5748,6 +6078,21 @@ __metadata: languageName: node linkType: hard +"browserslist@npm:^4.26.3": + version: 4.28.0 + resolution: "browserslist@npm:4.28.0" + dependencies: + baseline-browser-mapping: "npm:^2.8.25" + caniuse-lite: "npm:^1.0.30001754" + electron-to-chromium: "npm:^1.5.249" + node-releases: "npm:^2.0.27" + update-browserslist-db: "npm:^1.1.4" + bin: + browserslist: cli.js + checksum: 10c0/4284fd568f7d40a496963083860d488cb2a89fb055b6affd316bebc59441fec938e090b3e62c0ee065eb0bc88cd1bc145f4300a16c75f3f565621c5823715ae1 + languageName: node + linkType: hard + "bser@npm:2.1.1": version: 2.1.1 resolution: "bser@npm:2.1.1" @@ -6012,6 +6357,13 @@ __metadata: languageName: node linkType: hard +"caniuse-lite@npm:^1.0.30001754": + version: 1.0.30001754 + resolution: "caniuse-lite@npm:1.0.30001754" + checksum: 10c0/d38709ab11abc36eea28068d241434eba925c4d3462916ccaa17a34a6227dfdeb58ab0e1eb614bab12fb393c7d527db392a0f477b48c33d70d8e466954f381ba + languageName: node + linkType: hard + "capture-stack-trace@npm:^1.0.0": version: 1.0.0 resolution: "capture-stack-trace@npm:1.0.0" @@ -6200,6 +6552,13 @@ __metadata: languageName: node linkType: hard +"chrome-trace-event@npm:^1.0.2": + version: 1.0.4 + resolution: "chrome-trace-event@npm:1.0.4" + checksum: 10c0/3058da7a5f4934b87cf6a90ef5fb68ebc5f7d06f143ed5a4650208e5d7acae47bc03ec844b29fbf5ba7e46e8daa6acecc878f7983a4f4bb7271593da91e61ff5 + languageName: node + linkType: hard + "ci-info@npm:^1.0.0": version: 1.1.3 resolution: "ci-info@npm:1.1.3" @@ -7842,6 +8201,13 @@ __metadata: languageName: node linkType: hard +"electron-to-chromium@npm:^1.5.249": + version: 1.5.250 + resolution: "electron-to-chromium@npm:1.5.250" + checksum: 10c0/ccd12850fb5fd1c6539cdd7936c28cb6fbae421568e9b8b9fa0eb754e6cc36408c83cf0440d7b776c8bd325b5b760a378719415a629a75eedaad12943c936061 + languageName: node + linkType: hard + "electron-to-chromium@npm:^1.5.41": version: 1.5.71 resolution: "electron-to-chromium@npm:1.5.71" @@ -7938,6 +8304,16 @@ __metadata: languageName: node linkType: hard +"enhanced-resolve@npm:^5.17.3": + version: 5.18.3 + resolution: "enhanced-resolve@npm:5.18.3" + dependencies: + graceful-fs: "npm:^4.2.4" + tapable: "npm:^2.2.0" + checksum: 10c0/d413c23c2d494e4c1c9c9ac7d60b812083dc6d446699ed495e69c920988af0a3c66bf3f8d0e7a45cb1686c2d4c1df9f4e7352d973f5b56fe63d8d711dd0ccc54 + languageName: node + linkType: hard + "enquirer@npm:^2.3.5": version: 2.3.6 resolution: "enquirer@npm:2.3.6" @@ -8027,6 +8403,13 @@ __metadata: languageName: node linkType: hard +"es-module-lexer@npm:^1.2.1": + version: 1.7.0 + resolution: "es-module-lexer@npm:1.7.0" + checksum: 10c0/4c935affcbfeba7fb4533e1da10fa8568043df1e3574b869385980de9e2d475ddc36769891936dbb07036edb3c3786a8b78ccf44964cd130dedc1f2c984b6c7b + languageName: node + linkType: hard + "es-module-lexer@npm:^1.5.4": version: 1.5.4 resolution: "es-module-lexer@npm:1.5.4" @@ -8246,6 +8629,16 @@ __metadata: languageName: node linkType: hard +"eslint-scope@npm:5.1.1": + version: 5.1.1 + resolution: "eslint-scope@npm:5.1.1" + dependencies: + esrecurse: "npm:^4.3.0" + estraverse: "npm:^4.1.1" + checksum: 10c0/d30ef9dc1c1cbdece34db1539a4933fe3f9b14e1ffb27ecc85987902ee663ad7c9473bbd49a9a03195a373741e62e2f807c4938992e019b511993d163450e70a + languageName: node + linkType: hard + "esprima@npm:^4.0.0, esprima@npm:^4.0.1, esprima@npm:~4.0.0": version: 4.0.1 resolution: "esprima@npm:4.0.1" @@ -8256,6 +8649,22 @@ __metadata: languageName: node linkType: hard +"esrecurse@npm:^4.3.0": + version: 4.3.0 + resolution: "esrecurse@npm:4.3.0" + dependencies: + estraverse: "npm:^5.2.0" + checksum: 10c0/81a37116d1408ded88ada45b9fb16dbd26fba3aadc369ce50fcaf82a0bac12772ebd7b24cd7b91fc66786bf2c1ac7b5f196bc990a473efff972f5cb338877cf5 + languageName: node + linkType: hard + +"estraverse@npm:^4.1.1": + version: 4.3.0 + resolution: "estraverse@npm:4.3.0" + checksum: 10c0/9cb46463ef8a8a4905d3708a652d60122a0c20bb58dec7e0e12ab0e7235123d74214fc0141d743c381813e1b992767e2708194f6f6e0f9fd00c1b4e0887b8b6d + languageName: node + linkType: hard + "estraverse@npm:^5.2.0": version: 5.3.0 resolution: "estraverse@npm:5.3.0" @@ -8314,7 +8723,7 @@ __metadata: languageName: node linkType: hard -"events@npm:^3.3.0": +"events@npm:^3.2.0, events@npm:^3.3.0": version: 3.3.0 resolution: "events@npm:3.3.0" checksum: 10c0/d6b6f2adbccbcda74ddbab52ed07db727ef52e31a61ed26db9feb7dc62af7fc8e060defa65e5f8af9449b86b52cc1a1f6a79f2eafcf4e62add2b7a1fa4a432f6 @@ -8618,6 +9027,13 @@ __metadata: languageName: node linkType: hard +"fast-uri@npm:^3.0.1": + version: 3.0.6 + resolution: "fast-uri@npm:3.0.6" + checksum: 10c0/74a513c2af0584448aee71ce56005185f81239eab7a2343110e5bad50c39ad4fb19c5a6f99783ead1cac7ccaf3461a6034fda89fffa2b30b6d99b9f21c2f9d29 + languageName: node + linkType: hard + "fb-watchman@npm:^2.0.0": version: 2.0.1 resolution: "fb-watchman@npm:2.0.1" @@ -8914,7 +9330,7 @@ __metadata: "@artsy/palette-tokens": "npm:7.3.0" "@artsy/react-html-parser": "npm:^3.0.2" "@artsy/xapp": "npm:2.0.0" - "@biomejs/biome": "npm:1.9.4" + "@biomejs/biome": "npm:^2.3.5" "@graphql-inspector/core": "npm:1.14.0" "@graphql-tools/jest-transform": "npm:^2.0.0" "@loadable/component": "npm:5.15.2" @@ -8957,6 +9373,7 @@ __metadata: "@types/jest": "npm:27.0.2" "@types/jwt-decode": "npm:2.2.0" "@types/loadable__component": "npm:5.13.1" + "@types/loadable__webpack-plugin": "npm:^5.15.1" "@types/lodash": "npm:4.14.111" "@types/luxon": "npm:^3.2.0" "@types/memoize-one": "npm:3.1.1" @@ -8981,6 +9398,7 @@ __metadata: "@types/testing-library__jest-dom": "npm:^6.0.0" "@types/testing-library__react": "npm:^10.2.0" "@types/underscore.string": "npm:0.0.32" + "@types/webpack-node-externals": "npm:^3.0.4" "@types/yup": "npm:^0.29.13" "@unleash/proxy-client-react": "npm:^4.5.2" actioncable: "npm:^5.2.7-1" @@ -9568,6 +9986,13 @@ __metadata: languageName: node linkType: hard +"glob-to-regexp@npm:^0.4.1": + version: 0.4.1 + resolution: "glob-to-regexp@npm:0.4.1" + checksum: 10c0/0486925072d7a916f052842772b61c3e86247f0a80cc0deb9b5a3e8a1a9faad5b04fb6f58986a09f34d3e96cd2a22a24b7e9882fb1cf904c31e9a310de96c429 + languageName: node + linkType: hard + "glob@npm:7.1.3": version: 7.1.3 resolution: "glob@npm:7.1.3" @@ -11456,6 +11881,17 @@ __metadata: languageName: node linkType: hard +"jest-worker@npm:^27.4.5": + version: 27.5.1 + resolution: "jest-worker@npm:27.5.1" + dependencies: + "@types/node": "npm:*" + merge-stream: "npm:^2.0.0" + supports-color: "npm:^8.0.0" + checksum: 10c0/8c4737ffd03887b3c6768e4cc3ca0269c0336c1e4b1b120943958ddb035ed2a0fc6acab6dc99631720a3720af4e708ff84fb45382ad1e83c27946adf3623969b + languageName: node + linkType: hard + "jest-worker@npm:^29.5.0, jest-worker@npm:^29.7.0": version: 29.7.0 resolution: "jest-worker@npm:29.7.0" @@ -11600,13 +12036,20 @@ __metadata: languageName: node linkType: hard -"json-parse-even-better-errors@npm:^2.3.0": +"json-parse-even-better-errors@npm:^2.3.0, json-parse-even-better-errors@npm:^2.3.1": version: 2.3.1 resolution: "json-parse-even-better-errors@npm:2.3.1" checksum: 10c0/140932564c8f0b88455432e0f33c4cb4086b8868e37524e07e723f4eaedb9425bdc2bafd71bd1d9765bd15fd1e2d126972bc83990f55c467168c228c24d665f3 languageName: node linkType: hard +"json-schema-traverse@npm:^1.0.0": + version: 1.0.0 + resolution: "json-schema-traverse@npm:1.0.0" + checksum: 10c0/71e30015d7f3d6dc1c316d6298047c8ef98a06d31ad064919976583eb61e1018a60a0067338f0f79cabc00d84af3fcc489bd48ce8a46ea165d9541ba17fb30c6 + languageName: node + linkType: hard + "json5@npm:^2.1.0, json5@npm:^2.2.2, json5@npm:^2.2.3": version: 2.2.3 resolution: "json5@npm:2.2.3" @@ -11914,6 +12357,13 @@ __metadata: languageName: node linkType: hard +"loader-runner@npm:^4.2.0": + version: 4.3.0 + resolution: "loader-runner@npm:4.3.0" + checksum: 10c0/a44d78aae0907a72f73966fe8b82d1439c8c485238bd5a864b1b9a2a3257832effa858790241e6b37876b5446a78889adf2fcc8dd897ce54c089ecc0a0ce0bf0 + languageName: node + linkType: hard + "localforage@npm:^1.10.0": version: 1.10.0 resolution: "localforage@npm:1.10.0" @@ -12548,7 +12998,7 @@ __metadata: languageName: node linkType: hard -"mime-types@npm:^2.1.12, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34": +"mime-types@npm:^2.1.12, mime-types@npm:^2.1.27, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34": version: 2.1.35 resolution: "mime-types@npm:2.1.35" dependencies: @@ -12921,6 +13371,13 @@ __metadata: languageName: node linkType: hard +"neo-async@npm:^2.6.2": + version: 2.6.2 + resolution: "neo-async@npm:2.6.2" + checksum: 10c0/c2f5a604a54a8ec5438a342e1f356dff4bc33ccccdb6dc668d94fe8e5eccfc9d2c2eea6064b0967a767ba63b33763f51ccf2cd2441b461a7322656c1f06b3f5d + languageName: node + linkType: hard + "nice-try@npm:^1.0.4": version: 1.0.5 resolution: "nice-try@npm:1.0.5" @@ -13098,6 +13555,13 @@ __metadata: languageName: node linkType: hard +"node-releases@npm:^2.0.27": + version: 2.0.27 + resolution: "node-releases@npm:2.0.27" + checksum: 10c0/f1e6583b7833ea81880627748d28a3a7ff5703d5409328c216ae57befbced10ce2c991bea86434e8ec39003bd017f70481e2e5f8c1f7e0a7663241f81d6e00e2 + languageName: node + linkType: hard + "node-uuid@npm:1.4.8": version: 1.4.8 resolution: "node-uuid@npm:1.4.8" @@ -15726,6 +16190,30 @@ __metadata: languageName: node linkType: hard +"schema-utils@npm:^4.3.0": + version: 4.3.2 + resolution: "schema-utils@npm:4.3.2" + dependencies: + "@types/json-schema": "npm:^7.0.9" + ajv: "npm:^8.9.0" + ajv-formats: "npm:^2.1.1" + ajv-keywords: "npm:^5.1.0" + checksum: 10c0/981632f9bf59f35b15a9bcdac671dd183f4946fe4b055ae71a301e66a9797b95e5dd450de581eb6cca56fb6583ce8f24d67b2d9f8e1b2936612209697f6c277e + languageName: node + linkType: hard + +"schema-utils@npm:^4.3.3": + version: 4.3.3 + resolution: "schema-utils@npm:4.3.3" + dependencies: + "@types/json-schema": "npm:^7.0.9" + ajv: "npm:^8.9.0" + ajv-formats: "npm:^2.1.1" + ajv-keywords: "npm:^5.1.0" + checksum: 10c0/1c8d2c480a026d7c02ab2ecbe5919133a096d6a721a3f201fa50663e4f30f6d6ba020dfddd93cb828b66b922e76b342e103edd19a62c95c8f60e9079cc403202 + languageName: node + linkType: hard + "scroll-behavior@npm:^0.11.0": version: 0.11.0 resolution: "scroll-behavior@npm:0.11.0" @@ -15810,6 +16298,15 @@ __metadata: languageName: node linkType: hard +"serialize-javascript@npm:^6.0.2": + version: 6.0.2 + resolution: "serialize-javascript@npm:6.0.2" + dependencies: + randombytes: "npm:^2.1.0" + checksum: 10c0/2dd09ef4b65a1289ba24a788b1423a035581bef60817bea1f01eda8e3bda623f86357665fe7ac1b50f6d4f583f97db9615b3f07b2a2e8cbcb75033965f771dd2 + languageName: node + linkType: hard + "serve-favicon@npm:2.5.0": version: 2.5.0 resolution: "serve-favicon@npm:2.5.0" @@ -16828,6 +17325,20 @@ __metadata: languageName: node linkType: hard +"tapable@npm:^2.2.0": + version: 2.2.2 + resolution: "tapable@npm:2.2.2" + checksum: 10c0/8ad130aa705cab6486ad89e42233569a1fb1ff21af115f59cebe9f2b45e9e7995efceaa9cc5062510cdb4ec673b527924b2ab812e3579c55ad659ae92117011e + languageName: node + linkType: hard + +"tapable@npm:^2.3.0": + version: 2.3.0 + resolution: "tapable@npm:2.3.0" + checksum: 10c0/cb9d67cc2c6a74dedc812ef3085d9d681edd2c1fa18e4aef57a3c0605fdbe44e6b8ea00bd9ef21bc74dd45314e39d31227aa031ebf2f5e38164df514136f2681 + languageName: node + linkType: hard + "tar@npm:^6.1.11": version: 6.2.1 resolution: "tar@npm:6.2.1" @@ -16865,6 +17376,28 @@ __metadata: languageName: node linkType: hard +"terser-webpack-plugin@npm:^5.3.11": + version: 5.3.14 + resolution: "terser-webpack-plugin@npm:5.3.14" + dependencies: + "@jridgewell/trace-mapping": "npm:^0.3.25" + jest-worker: "npm:^27.4.5" + schema-utils: "npm:^4.3.0" + serialize-javascript: "npm:^6.0.2" + terser: "npm:^5.31.1" + peerDependencies: + webpack: ^5.1.0 + peerDependenciesMeta: + "@swc/core": + optional: true + esbuild: + optional: true + uglify-js: + optional: true + checksum: 10c0/9b060947241af43bd6fd728456f60e646186aef492163672a35ad49be6fbc7f63b54a7356c3f6ff40a8f83f00a977edc26f044b8e106cc611c053c8c0eaf8569 + languageName: node + linkType: hard + "terser@npm:^5.15.1": version: 5.37.0 resolution: "terser@npm:5.37.0" @@ -16879,6 +17412,20 @@ __metadata: languageName: node linkType: hard +"terser@npm:^5.31.1": + version: 5.43.1 + resolution: "terser@npm:5.43.1" + dependencies: + "@jridgewell/source-map": "npm:^0.3.3" + acorn: "npm:^8.14.0" + commander: "npm:^2.20.0" + source-map-support: "npm:~0.5.20" + bin: + terser: bin/terser + checksum: 10c0/9cd3fa09ea6bcb79eb71995216b8bef0651b18c5c3877535fc699a77e1ab43b140a4da5811ac9baeb654fa9ec939b17324092f0f0bdb19c402e101e3db946986 + languageName: node + linkType: hard + "test-exclude@npm:^6.0.0": version: 6.0.0 resolution: "test-exclude@npm:6.0.0" @@ -17599,6 +18146,20 @@ __metadata: languageName: node linkType: hard +"update-browserslist-db@npm:^1.1.4": + version: 1.1.4 + resolution: "update-browserslist-db@npm:1.1.4" + dependencies: + escalade: "npm:^3.2.0" + picocolors: "npm:^1.1.1" + peerDependencies: + browserslist: ">= 4.21.0" + bin: + update-browserslist-db: cli.js + checksum: 10c0/db0c9aaecf1258a6acda5e937fc27a7996ccca7a7580a1b4aa8bba6a9b0e283e5e65c49ebbd74ec29288ef083f1b88d4da13e3d4d326c1e5fc55bf72d7390702 + languageName: node + linkType: hard + "update-notifier@npm:^2.5.0": version: 2.5.0 resolution: "update-notifier@npm:2.5.0" @@ -17953,6 +18514,16 @@ __metadata: languageName: node linkType: hard +"watchpack@npm:^2.4.4": + version: 2.4.4 + resolution: "watchpack@npm:2.4.4" + dependencies: + glob-to-regexp: "npm:^0.4.1" + graceful-fs: "npm:^4.1.2" + checksum: 10c0/6c0901f75ce245d33991225af915eea1c5ae4ba087f3aee2b70dd377d4cacb34bef02a48daf109da9d59b2d31ec6463d924a0d72f8618ae1643dd07b95de5275 + languageName: node + linkType: hard + "wcwidth@npm:^1.0.1": version: 1.0.1 resolution: "wcwidth@npm:1.0.1" @@ -18008,6 +18579,13 @@ __metadata: languageName: node linkType: hard +"webpack-sources@npm:^3.3.3": + version: 3.3.3 + resolution: "webpack-sources@npm:3.3.3" + checksum: 10c0/ab732f6933b513ba4d505130418995ddef6df988421fccf3289e53583c6a39e205c4a0739cee98950964552d3006604912679c736031337fb4a9d78d8576ed40 + languageName: node + linkType: hard + "webpack-virtual-modules@npm:^0.6.2": version: 0.6.2 resolution: "webpack-virtual-modules@npm:0.6.2" @@ -18015,6 +18593,44 @@ __metadata: languageName: node linkType: hard +"webpack@npm:^5": + version: 5.102.1 + resolution: "webpack@npm:5.102.1" + dependencies: + "@types/eslint-scope": "npm:^3.7.7" + "@types/estree": "npm:^1.0.8" + "@types/json-schema": "npm:^7.0.15" + "@webassemblyjs/ast": "npm:^1.14.1" + "@webassemblyjs/wasm-edit": "npm:^1.14.1" + "@webassemblyjs/wasm-parser": "npm:^1.14.1" + acorn: "npm:^8.15.0" + acorn-import-phases: "npm:^1.0.3" + browserslist: "npm:^4.26.3" + chrome-trace-event: "npm:^1.0.2" + enhanced-resolve: "npm:^5.17.3" + es-module-lexer: "npm:^1.2.1" + eslint-scope: "npm:5.1.1" + events: "npm:^3.2.0" + glob-to-regexp: "npm:^0.4.1" + graceful-fs: "npm:^4.2.11" + json-parse-even-better-errors: "npm:^2.3.1" + loader-runner: "npm:^4.2.0" + mime-types: "npm:^2.1.27" + neo-async: "npm:^2.6.2" + schema-utils: "npm:^4.3.3" + tapable: "npm:^2.3.0" + terser-webpack-plugin: "npm:^5.3.11" + watchpack: "npm:^2.4.4" + webpack-sources: "npm:^3.3.3" + peerDependenciesMeta: + webpack-cli: + optional: true + bin: + webpack: bin/webpack.js + checksum: 10c0/74c3afeef50a5414e58399f1c0123fe5cdb3d8d081c206fae74b8334097d5ff6b729147154dbb4af48e662ba756a89e06d550b3390917153fa1d7ce285f96777 + languageName: node + linkType: hard + "whatwg-encoding@npm:^2.0.0": version: 2.0.0 resolution: "whatwg-encoding@npm:2.0.0"