diff --git a/frontend/src/component/admin/billing/BillingDashboard/BillingPlan/BillingDetailsPAYG.tsx b/frontend/src/component/admin/billing/BillingDashboard/BillingPlan/BillingDetailsPAYG.tsx index 69c854ffb2..15687e8bc5 100644 --- a/frontend/src/component/admin/billing/BillingDashboard/BillingPlan/BillingDetailsPAYG.tsx +++ b/frontend/src/component/admin/billing/BillingDashboard/BillingPlan/BillingDetailsPAYG.tsx @@ -8,8 +8,8 @@ import { useUsers } from 'hooks/api/getters/useUsers/useUsers'; import { BILLING_INCLUDED_REQUESTS, BILLING_PAYG_DEFAULT_MINIMUM_SEATS, - BILLING_PAYG_USER_PRICE, - BILLING_TRAFFIC_BUNDLE_PRICE, + BILLING_PAYG_SEAT_PRICE, + BILLING_TRAFFIC_PRICE, } from './BillingPlan'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { useOverageCost } from './useOverageCost'; @@ -34,11 +34,16 @@ export const BillingDetailsPAYG = ({ const eligibleUsers = users.filter((user) => user.email); + const seatPrice = + instanceStatus.prices?.payg?.seat ?? BILLING_PAYG_SEAT_PRICE; + const trafficPrice = + instanceStatus.prices?.payg?.traffic ?? BILLING_TRAFFIC_PRICE; + const minSeats = instanceStatus.minSeats ?? BILLING_PAYG_DEFAULT_MINIMUM_SEATS; const billableUsers = Math.max(eligibleUsers.length, minSeats); - const usersCost = BILLING_PAYG_USER_PRICE * billableUsers; + const usersCost = seatPrice * billableUsers; const includedTraffic = BILLING_INCLUDED_REQUESTS; const overageCost = useOverageCost(includedTraffic); @@ -66,7 +71,7 @@ export const BillingDetailsPAYG = ({ - ${BILLING_PAYG_USER_PRICE}/month per paid member + ${seatPrice}/month per paid member @@ -93,8 +98,8 @@ export const BillingDetailsPAYG = ({ - ${BILLING_TRAFFIC_BUNDLE_PRICE} per 1 - million started above included data + ${trafficPrice} per 1 million started above + included data diff --git a/frontend/src/component/admin/billing/BillingDashboard/BillingPlan/BillingDetailsPro.tsx b/frontend/src/component/admin/billing/BillingDashboard/BillingPlan/BillingDetailsPro.tsx index 84ac700dcd..9e5280d87f 100644 --- a/frontend/src/component/admin/billing/BillingDashboard/BillingPlan/BillingDetailsPro.tsx +++ b/frontend/src/component/admin/billing/BillingDashboard/BillingPlan/BillingDetailsPro.tsx @@ -9,10 +9,10 @@ import { ConditionallyRender } from 'component/common/ConditionallyRender/Condit import { useUsers } from 'hooks/api/getters/useUsers/useUsers'; import { BILLING_INCLUDED_REQUESTS, - BILLING_PLAN_PRICES, BILLING_PRO_DEFAULT_INCLUDED_SEATS, - BILLING_PRO_USER_PRICE, - BILLING_TRAFFIC_BUNDLE_PRICE, + BILLING_PRO_BASE_PRICE, + BILLING_PRO_SEAT_PRICE, + BILLING_TRAFFIC_PRICE, } from './BillingPlan'; import { useOverageCost } from './useOverageCost'; @@ -41,12 +41,17 @@ export const BillingDetailsPro = ({ const eligibleUsers = users.filter((user) => user.email); - const planPrice = BILLING_PLAN_PRICES[instanceStatus.plan]; + const planPrice = + instanceStatus.prices?.pro?.base ?? BILLING_PRO_BASE_PRICE; + const seatPrice = + instanceStatus.prices?.pro?.seat ?? BILLING_PRO_SEAT_PRICE; + const trafficPrice = + instanceStatus.prices?.pro?.traffic ?? BILLING_TRAFFIC_PRICE; const seats = BILLING_PRO_DEFAULT_INCLUDED_SEATS; const freeAssigned = Math.min(eligibleUsers.length, seats); const paidAssigned = eligibleUsers.length - freeAssigned; - const paidAssignedPrice = BILLING_PRO_USER_PRICE * paidAssigned; + const paidAssignedPrice = seatPrice * paidAssigned; const includedTraffic = BILLING_INCLUDED_REQUESTS; const overageCost = useOverageCost(includedTraffic); @@ -96,7 +101,7 @@ export const BillingDetailsPro = ({ - ${BILLING_PRO_USER_PRICE}/month per paid member + ${seatPrice}/month per paid member @@ -123,8 +128,8 @@ export const BillingDetailsPro = ({ - ${BILLING_TRAFFIC_BUNDLE_PRICE} per 1 - million started above included data + ${trafficPrice} per 1 million started above + included data diff --git a/frontend/src/component/admin/billing/BillingDashboard/BillingPlan/BillingPlan.tsx b/frontend/src/component/admin/billing/BillingDashboard/BillingPlan/BillingPlan.tsx index 24e5796a3f..0c7690bbbb 100644 --- a/frontend/src/component/admin/billing/BillingDashboard/BillingPlan/BillingPlan.tsx +++ b/frontend/src/component/admin/billing/BillingDashboard/BillingPlan/BillingPlan.tsx @@ -1,6 +1,6 @@ import { Alert, Grid, styled } from '@mui/material'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; -import { InstanceState, InstancePlan } from 'interfaces/instance'; +import { InstanceState } from 'interfaces/instance'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import { trialHasExpired, isTrialInstance } from 'utils/instanceTrial'; import { GridRow } from 'component/common/GridRow/GridRow'; @@ -9,16 +9,14 @@ import { Badge } from 'component/common/Badge/Badge'; import { BillingDetails } from './BillingDetails'; import { useInstanceStatus } from 'hooks/api/getters/useInstanceStatus/useInstanceStatus'; -export const BILLING_PLAN_PRICES: Record = { - [InstancePlan.PRO]: 80, -}; +export const BILLING_PRO_BASE_PRICE = 80; +export const BILLING_PRO_SEAT_PRICE = 15; +export const BILLING_PAYG_SEAT_PRICE = 75; +export const BILLING_TRAFFIC_PRICE = 5; -export const BILLING_PAYG_USER_PRICE = 75; export const BILLING_PAYG_DEFAULT_MINIMUM_SEATS = 5; -export const BILLING_PRO_USER_PRICE = 15; export const BILLING_PRO_DEFAULT_INCLUDED_SEATS = 5; export const BILLING_INCLUDED_REQUESTS = 53_000_000; -export const BILLING_TRAFFIC_BUNDLE_PRICE = 5; const StyledPlanBox = styled('aside')(({ theme }) => ({ padding: theme.spacing(2.5), @@ -77,7 +75,8 @@ export const BillingPlan = () => { ); const expired = trialHasExpired(instanceStatus); - const planPrice = BILLING_PLAN_PRICES[instanceStatus.plan] ?? 0; + const baseProPrice = + instanceStatus.prices?.pro?.base ?? BILLING_PRO_BASE_PRICE; const plan = `${instanceStatus.plan}${isPAYG ? ' Pay-as-You-Go' : ''}`; const inactive = instanceStatus.state !== InstanceState.ACTIVE; @@ -131,10 +130,10 @@ export const BillingPlan = () => { 0} + condition={!isPAYG} show={ - ${planPrice.toFixed(2)} + ${baseProPrice.toFixed(2)} } /> diff --git a/frontend/src/component/admin/billing/BillingDashboard/BillingPlan/useOverageCost.ts b/frontend/src/component/admin/billing/BillingDashboard/BillingPlan/useOverageCost.ts index 80ae41455c..1f29f95158 100644 --- a/frontend/src/component/admin/billing/BillingDashboard/BillingPlan/useOverageCost.ts +++ b/frontend/src/component/admin/billing/BillingDashboard/BillingPlan/useOverageCost.ts @@ -5,7 +5,8 @@ import { calculateOverageCost, calculateTotalUsage, } from 'utils/traffic-calculations'; -import { BILLING_TRAFFIC_BUNDLE_PRICE } from './BillingPlan'; +import { BILLING_TRAFFIC_PRICE } from './BillingPlan'; +import { useInstanceStatus } from 'hooks/api/getters/useInstanceStatus/useInstanceStatus'; export const useOverageCost = (includedTraffic: number) => { if (!includedTraffic) { @@ -17,6 +18,12 @@ export const useOverageCost = (includedTraffic: number) => { const from = formatDate(startOfMonth(now)); const to = formatDate(endOfMonth(now)); + const { instanceStatus } = useInstanceStatus(); + const trafficPrice = + instanceStatus?.prices?.[ + instanceStatus?.billing === 'pay-as-you-go' ? 'payg' : 'pro' + ]?.traffic ?? BILLING_TRAFFIC_PRICE; + const { result } = useTrafficSearch('daily', { from, to }); const overageCost = useMemo(() => { if (result.state !== 'success') { @@ -24,12 +31,8 @@ export const useOverageCost = (includedTraffic: number) => { } const totalUsage = calculateTotalUsage(result.data); - return calculateOverageCost( - totalUsage, - includedTraffic, - BILLING_TRAFFIC_BUNDLE_PRICE, - ); - }, [includedTraffic, JSON.stringify(result)]); + return calculateOverageCost(totalUsage, includedTraffic, trafficPrice); + }, [includedTraffic, JSON.stringify(result), trafficPrice]); return overageCost; }; diff --git a/frontend/src/component/admin/network/NetworkTrafficUsage/hooks/useStats.ts b/frontend/src/component/admin/network/NetworkTrafficUsage/hooks/useStats.ts index c34f4ab910..eec6922988 100644 --- a/frontend/src/component/admin/network/NetworkTrafficUsage/hooks/useStats.ts +++ b/frontend/src/component/admin/network/NetworkTrafficUsage/hooks/useStats.ts @@ -12,10 +12,11 @@ import { calculateOverageCost, calculateTotalUsage, } from 'utils/traffic-calculations'; -import { BILLING_TRAFFIC_BUNDLE_PRICE } from '../../../billing/BillingDashboard/BillingPlan/BillingPlan'; +import { BILLING_TRAFFIC_PRICE } from '../../../billing/BillingDashboard/BillingPlan/BillingPlan'; import { averageTrafficPreviousMonths } from '../average-traffic-previous-months'; import { useConnectionsConsumption } from 'hooks/api/getters/useConnectionsConsumption/useConnectionsConsumption'; import { useRequestsConsumption } from 'hooks/api/getters/useRequestsConsumption/useRequestsConsumption'; +import { useInstanceStatus } from 'hooks/api/getters/useInstanceStatus/useInstanceStatus'; export const useTrafficStats = ( includedTraffic: number, @@ -26,6 +27,12 @@ export const useTrafficStats = ( chartDataSelection.grouping, toDateRange(chartDataSelection, currentDate), ); + const { instanceStatus } = useInstanceStatus(); + const trafficPrice = + instanceStatus?.prices?.[ + instanceStatus?.billing === 'pay-as-you-go' ? 'payg' : 'pro' + ]?.traffic ?? BILLING_TRAFFIC_PRICE; + const results = useMemo(() => { if (result.state !== 'success') { return { @@ -43,14 +50,14 @@ export const useTrafficStats = ( const overageCost = calculateOverageCost( usageTotal, includedTraffic, - BILLING_TRAFFIC_BUNDLE_PRICE, + trafficPrice, ); const estimatedMonthlyCost = calculateEstimatedMonthlyCost( traffic.apiData, includedTraffic, currentDate, - BILLING_TRAFFIC_BUNDLE_PRICE, + trafficPrice, ); const requestSummaryUsage = @@ -69,6 +76,7 @@ export const useTrafficStats = ( JSON.stringify(result), includedTraffic, JSON.stringify(chartDataSelection), + trafficPrice, ]); return results; diff --git a/frontend/src/component/admin/users/CreateUser/SeatCostWarning/SeatCostWarning.tsx b/frontend/src/component/admin/users/CreateUser/SeatCostWarning/SeatCostWarning.tsx index 0ef6df601a..62d20034c8 100644 --- a/frontend/src/component/admin/users/CreateUser/SeatCostWarning/SeatCostWarning.tsx +++ b/frontend/src/component/admin/users/CreateUser/SeatCostWarning/SeatCostWarning.tsx @@ -2,11 +2,15 @@ import type { VFC } from 'react'; import { Alert } from '@mui/material'; import { useUsersPlan } from 'hooks/useUsersPlan'; import { useUsers } from 'hooks/api/getters/useUsers/useUsers'; -import { BILLING_PRO_USER_PRICE } from 'component/admin/billing/BillingDashboard/BillingPlan/BillingPlan'; +import { BILLING_PRO_SEAT_PRICE } from 'component/admin/billing/BillingDashboard/BillingPlan/BillingPlan'; +import { useInstanceStatus } from 'hooks/api/getters/useInstanceStatus/useInstanceStatus'; export const SeatCostWarning: VFC = () => { const { users } = useUsers(); const { isBillingUsers, seats, planUsers } = useUsersPlan(users); + const { instanceStatus } = useInstanceStatus(); + const seatPrice = + instanceStatus?.prices?.pro?.seat ?? BILLING_PRO_SEAT_PRICE; if (!isBillingUsers || planUsers.length < seats) { return null; @@ -20,9 +24,8 @@ export const SeatCostWarning: VFC = () => {

Heads up! You are exceeding your allocated free members included in your plan ({planUsers.length} of {seats}). - Creating this user will add{' '} - ${BILLING_PRO_USER_PRICE}/month to your - invoice, starting with your next payment. + Creating this user will add ${seatPrice}/month{' '} + to your invoice, starting with your next payment.

); diff --git a/frontend/src/component/demo/DemoDialog/DemoDialogPlans/DemoDialogPlans.tsx b/frontend/src/component/demo/DemoDialog/DemoDialogPlans/DemoDialogPlans.tsx index 6728914ea5..c038ef3e27 100644 --- a/frontend/src/component/demo/DemoDialog/DemoDialogPlans/DemoDialogPlans.tsx +++ b/frontend/src/component/demo/DemoDialog/DemoDialogPlans/DemoDialogPlans.tsx @@ -6,11 +6,11 @@ import { usePlausibleTracker } from 'hooks/usePlausibleTracker'; import { useUiFlag } from 'hooks/useUiFlag'; import { BILLING_PAYG_DEFAULT_MINIMUM_SEATS, - BILLING_PAYG_USER_PRICE, - BILLING_PLAN_PRICES, + BILLING_PAYG_SEAT_PRICE, + BILLING_PRO_BASE_PRICE, BILLING_PRO_DEFAULT_INCLUDED_SEATS, } from 'component/admin/billing/BillingDashboard/BillingPlan/BillingPlan'; -import { InstancePlan } from 'interfaces/instance'; +import { useInstanceStatus } from 'hooks/api/getters/useInstanceStatus/useInstanceStatus'; const StyledDemoDialog = styled(DemoDialog)(({ theme }) => ({ '& .MuiDialog-paper': { @@ -91,6 +91,12 @@ interface IDemoDialogPlansProps { export const DemoDialogPlans = ({ open, onClose }: IDemoDialogPlansProps) => { const { trackEvent } = usePlausibleTracker(); const isEnterprisePaygEnabled = useUiFlag('enterprise-payg'); + const { instanceStatus } = useInstanceStatus(); + + const paygSeatPrice = + instanceStatus?.prices?.payg?.seat ?? BILLING_PAYG_SEAT_PRICE; + const proBasePrice = + instanceStatus?.prices?.pro?.base ?? BILLING_PRO_BASE_PRICE; return ( @@ -139,7 +145,7 @@ export const DemoDialogPlans = ({ open, onClose }: IDemoDialogPlansProps) => {
- ${BILLING_PAYG_USER_PRICE} per user/month + ${paygSeatPrice} per user/month {BILLING_PAYG_DEFAULT_MINIMUM_SEATS} users @@ -174,7 +180,7 @@ export const DemoDialogPlans = ({ open, onClose }: IDemoDialogPlansProps) => {
- ${BILLING_PLAN_PRICES[InstancePlan.PRO]}/month + ${proBasePrice}/month includes {BILLING_PRO_DEFAULT_INCLUDED_SEATS}{' '} diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/ProjectEnvironmentStrategyDraggableItem.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/ProjectEnvironmentStrategyDraggableItem.tsx index 19de8335cf..cd0a413dee 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/ProjectEnvironmentStrategyDraggableItem.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/ProjectEnvironmentStrategyDraggableItem.tsx @@ -1,5 +1,5 @@ import { type DragEventHandler, type RefObject, useRef } from 'react'; -import { Box, useMediaQuery, useTheme } from '@mui/material'; +import { useMediaQuery, useTheme } from '@mui/material'; import type { IFeatureEnvironment } from 'interfaces/featureToggle'; import type { IFeatureStrategy } from 'interfaces/strategy'; import { useRequiredPathParam } from 'hooks/useRequiredPathParam'; @@ -34,8 +34,6 @@ type ProjectEnvironmentStrategyDraggableItemProps = { onDragEnd?: () => void; }; -const onDragNoOp = () => () => {}; - export const ProjectEnvironmentStrategyDraggableItem = ({ className, strategy, @@ -43,9 +41,9 @@ export const ProjectEnvironmentStrategyDraggableItem = ({ environmentName, otherEnvironments, isDragging, - onDragStartRef = onDragNoOp, - onDragOver = onDragNoOp, - onDragEnd = onDragNoOp, + onDragStartRef, + onDragOver, + onDragEnd, }: ProjectEnvironmentStrategyDraggableItemProps) => { const projectId = useRequiredPathParam('projectId'); const featureId = useRequiredPathParam('featureId'); @@ -75,67 +73,59 @@ export const ProjectEnvironmentStrategyDraggableItem = ({ const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm')); return ( - - - {draftChange && !isSmallScreen ? ( - - ) : null} + + {draftChange && !isSmallScreen ? ( + + ) : null} - {scheduledChanges && - scheduledChanges.length > 0 && - !isSmallScreen ? ( - scheduledChange.id)} - /> - ) : null} - {otherEnvironments && otherEnvironments?.length > 0 ? ( - - ) : null} - - - - 0 && + !isSmallScreen ? ( + scheduledChange.id)} + /> + ) : null} + {otherEnvironments && otherEnvironments?.length > 0 ? ( + - - } - /> - + ) : null} + + + + + + } + /> ); }; diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyDraggableItem.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyDraggableItem.tsx index 0ca7ca554a..6e2d857c6f 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyDraggableItem.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyDraggableItem.tsx @@ -8,8 +8,6 @@ import { Box } from '@mui/material'; import type { IFeatureStrategy } from 'interfaces/strategy'; import { StrategyItem } from './StrategyItem/StrategyItem'; -const onDragNoOp = () => () => {}; - type StrategyDraggableItemProps = { headerItemsRight: ReactNode; strategy: IFeatureStrategy; @@ -30,9 +28,9 @@ export const StrategyDraggableItem = ({ strategy, index, isDragging, - onDragStartRef = onDragNoOp, - onDragOver = onDragNoOp, - onDragEnd = onDragNoOp, + onDragStartRef, + onDragOver, + onDragEnd, headerItemsRight, }: StrategyDraggableItemProps) => { const ref = useRef(null); @@ -41,13 +39,13 @@ export const StrategyDraggableItem = ({ diff --git a/frontend/src/interfaces/instance.ts b/frontend/src/interfaces/instance.ts index 5a03e1e91b..c06eef0e63 100644 --- a/frontend/src/interfaces/instance.ts +++ b/frontend/src/interfaces/instance.ts @@ -1,3 +1,17 @@ +type InstancePrices = { + pro?: { + base?: number; + seat?: number; + traffic?: number; + }; + payg?: { + seat?: number; + traffic?: number; + }; +}; + +type InstanceBilling = 'pay-as-you-go' | 'subscription'; + export interface IInstanceStatus { plan: InstancePlan; trialExpiry?: string; @@ -8,6 +22,8 @@ export interface IInstanceStatus { seats?: number; minSeats?: number; isCustomBilling?: boolean; + prices?: InstancePrices; + billing?: InstanceBilling; } export enum InstanceState { diff --git a/src/lib/services/access-service.ts b/src/lib/services/access-service.ts index 4cd15f3b11..388fc35cfb 100644 --- a/src/lib/services/access-service.ts +++ b/src/lib/services/access-service.ts @@ -457,8 +457,9 @@ export class AccessService { async getRootRoleForUser(userId: number): Promise { const rootRole = await this.store.getRootRoleForUser(userId); if (!rootRole) { - const defaultRole = await this.getPredefinedRole(RoleName.VIEWER); - return defaultRole; + // this should never happen, but before breaking we want to know if it does. + this.logger.warn(`Could not find root role for user=${userId}.`); + return this.getPredefinedRole(RoleName.VIEWER); } return rootRole; } diff --git a/src/migrations/20250320121200-all-users-have-a-root-role.js b/src/migrations/20250320121200-all-users-have-a-root-role.js new file mode 100644 index 0000000000..8f1ab0ad27 --- /dev/null +++ b/src/migrations/20250320121200-all-users-have-a-root-role.js @@ -0,0 +1,20 @@ +exports.up = function (db, cb) { + // add root role Viewer (id 3) to all users who don't have a root role + db.runSql( + `INSERT INTO role_user(role_id, user_id, project) SELECT 3, u.id, 'default' +FROM users u +WHERE u.id > 0 AND u.deleted_at IS NULL AND NOT EXISTS ( + SELECT 1 + FROM role_user ru + JOIN roles r ON ru.role_id = r.id + WHERE ru.user_id = u.id + AND r.type IN ('root', 'root-custom') +);`, + cb, + ); +}; + +exports.down = function (db, callback) { + // No rollback + callback(); +}; \ No newline at end of file diff --git a/website/yarn.lock b/website/yarn.lock index 36a5ec6a41..5c9b6237c8 100644 --- a/website/yarn.lock +++ b/website/yarn.lock @@ -235,7 +235,7 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.16.0, @babel/code-frame@npm:^7.25.9, @babel/code-frame@npm:^7.26.0, @babel/code-frame@npm:^7.8.3": +"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.16.0, @babel/code-frame@npm:^7.25.9, @babel/code-frame@npm:^7.26.0, @babel/code-frame@npm:^7.26.2, @babel/code-frame@npm:^7.8.3": version: 7.26.2 resolution: "@babel/code-frame@npm:7.26.2" dependencies: @@ -494,12 +494,12 @@ __metadata: linkType: hard "@babel/helpers@npm:^7.26.0": - version: 7.26.0 - resolution: "@babel/helpers@npm:7.26.0" + version: 7.26.10 + resolution: "@babel/helpers@npm:7.26.10" dependencies: - "@babel/template": "npm:^7.25.9" - "@babel/types": "npm:^7.26.0" - checksum: 10c0/343333cced6946fe46617690a1d0789346960910225ce359021a88a60a65bc0d791f0c5d240c0ed46cf8cc63b5fd7df52734ff14e43b9c32feae2b61b1647097 + "@babel/template": "npm:^7.26.9" + "@babel/types": "npm:^7.26.10" + checksum: 10c0/f99e1836bcffce96db43158518bb4a24cf266820021f6461092a776cba2dc01d9fc8b1b90979d7643c5c2ab7facc438149064463a52dd528b21c6ab32509784f languageName: node linkType: hard @@ -514,6 +514,17 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.26.9": + version: 7.26.10 + resolution: "@babel/parser@npm:7.26.10" + dependencies: + "@babel/types": "npm:^7.26.10" + bin: + parser: ./bin/babel-parser.js + checksum: 10c0/c47f5c0f63cd12a663e9dc94a635f9efbb5059d98086a92286d7764357c66bceba18ccbe79333e01e9be3bfb8caba34b3aaebfd8e62c3d5921c8cf907267be75 + languageName: node + linkType: hard + "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.25.9": version: 7.25.9 resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.25.9" @@ -1482,6 +1493,17 @@ __metadata: languageName: node linkType: hard +"@babel/template@npm:^7.26.9": + version: 7.26.9 + resolution: "@babel/template@npm:7.26.9" + dependencies: + "@babel/code-frame": "npm:^7.26.2" + "@babel/parser": "npm:^7.26.9" + "@babel/types": "npm:^7.26.9" + checksum: 10c0/019b1c4129cc01ad63e17529089c2c559c74709d225f595eee017af227fee11ae8a97a6ab19ae6768b8aa22d8d75dcb60a00b28f52e9fa78140672d928bc1ae9 + languageName: node + linkType: hard + "@babel/traverse@npm:^7.25.9": version: 7.25.9 resolution: "@babel/traverse@npm:7.25.9" @@ -1507,6 +1529,16 @@ __metadata: languageName: node linkType: hard +"@babel/types@npm:^7.26.10, @babel/types@npm:^7.26.9": + version: 7.26.10 + resolution: "@babel/types@npm:7.26.10" + dependencies: + "@babel/helper-string-parser": "npm:^7.25.9" + "@babel/helper-validator-identifier": "npm:^7.25.9" + checksum: 10c0/7a7f83f568bfc3dfabfaf9ae3a97ab5c061726c0afa7dcd94226d4f84a81559da368ed79671e3a8039d16f12476cf110381a377ebdea07587925f69628200dac + languageName: node + linkType: hard + "@braintree/sanitize-url@npm:^7.0.1": version: 7.1.1 resolution: "@braintree/sanitize-url@npm:7.1.1"