From 307e6d5d3419aa7b11800628d379f65d162eec6e Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Sat, 16 May 2026 18:11:52 +0200 Subject: [PATCH] fix: warn + block install when app version is below plugin's minAppVersion --- app/admin/_tabs/marketplace.tsx | 24 ++++++++++++-- app/admin/marketplace/[slug]/page.tsx | 23 ++++++++++++-- lib/__tests__/version-compare.test.ts | 46 +++++++++++++++++++++++++++ lib/version-compare.ts | 39 +++++++++++++++++++++++ 4 files changed, 128 insertions(+), 4 deletions(-) create mode 100644 lib/__tests__/version-compare.test.ts create mode 100644 lib/version-compare.ts diff --git a/app/admin/_tabs/marketplace.tsx b/app/admin/_tabs/marketplace.tsx index 7aefa46d..af2af802 100644 --- a/app/admin/_tabs/marketplace.tsx +++ b/app/admin/_tabs/marketplace.tsx @@ -2,8 +2,11 @@ import { useEffect, useState, useCallback } from 'react'; import Link from 'next/link'; -import { Search, Download, Check, Loader2, Store, Puzzle, SwatchBook, Star, Eye } from 'lucide-react'; +import { Search, Download, Check, Loader2, Store, Puzzle, SwatchBook, Star, Eye, AlertTriangle } from 'lucide-react'; import { apiFetch } from '@/lib/browser-navigation'; +import { isVersionSatisfied } from '@/lib/version-compare'; + +const CURRENT_APP_VERSION = process.env.NEXT_PUBLIC_APP_VERSION || '0.0.0'; interface Extension { slug: string; @@ -94,6 +97,13 @@ export function MarketplaceTab() { }, [searchInput]); async function handleInstall(ext: Extension) { + if (ext.minAppVersion && !isVersionSatisfied(CURRENT_APP_VERSION, ext.minAppVersion)) { + setMessage({ + type: 'error', + text: `"${ext.name}" requires app v${ext.minAppVersion}+. You are running v${CURRENT_APP_VERSION}.`, + }); + return; + } setInstalling(ext.slug); setMessage(null); @@ -258,6 +268,8 @@ function ExtensionCard({ }) { const isPlugin = extension.type === 'plugin'; const previewHref = `/admin/marketplace/${encodeURIComponent(extension.slug)}`; + const versionMismatch = !!extension.minAppVersion + && !isVersionSatisfied(CURRENT_APP_VERSION, extension.minAppVersion); return (