{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "rate-limiting-config",
  "title": "Rate Limiting Config",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/rate-limiting-config/RateLimitingConfig.vue",
      "content": "<script setup lang=\"ts\">\nimport { ref, computed, type HTMLAttributes } from 'vue'\nimport {\n  Activity,\n  AlertTriangle,\n  CheckCircle2,\n  Copy,\n  Database,\n  Edit3,\n  MoreHorizontal,\n  Plus,\n  RefreshCw,\n  Search,\n  Shield,\n  ShieldAlert,\n  ShieldCheck,\n  Sliders,\n  Timer,\n  Trash2,\n  TrendingUp,\n  Zap,\n  ZapOff,\n} from 'lucide-vue-next'\nimport { cn } from '@/lib/utils'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuLabel,\n  DropdownMenuSeparator,\n  DropdownMenuTrigger,\n} from '@/components/ui/dropdown-menu'\nimport { Progress } from '@/components/ui/progress'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'\nimport { Slider } from '@/components/ui/slider'\nimport { Switch } from '@/components/ui/switch'\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'\n\ninterface Props {\n  class?: HTMLAttributes['class']\n}\n\nconst props = defineProps<Props>()\n\ninterface RateLimitRule {\n  id: string\n  name: string\n  scope: string\n  path: string\n  method: string\n  limitThreshold: string\n  mitigationAction: 'HTTP 429 Too Many Requests' | 'CAPTCHA Challenge' | 'Block IP'\n  actionVariant: 'warning' | 'secondary' | 'destructive'\n  enabled: boolean\n  lastTriggered: string\n  blocked24h: string\n}\n\nconst globalProtection = ref(true)\nconst algorithm = ref<'token-bucket' | 'sliding-window'>('token-bucket')\nconst simVolume = ref(120)\nconst searchQuery = ref('')\n\nconst rules = ref<RateLimitRule[]>([\n  {\n    id: 'rule-auth-bruteforce',\n    name: 'auth-endpoint-bruteforce',\n    scope: 'Login & SSO token issuance',\n    path: '/api/v1/auth/*',\n    method: 'POST',\n    limitThreshold: '100 req / 60s per IP',\n    mitigationAction: 'HTTP 429 Too Many Requests',\n    actionVariant: 'warning',\n    enabled: true,\n    lastTriggered: '2 mins ago',\n    blocked24h: '842 blocks',\n  },\n  {\n    id: 'rule-public-unauth',\n    name: 'public-api-v1-unauthenticated',\n    scope: 'Anonymous REST endpoints',\n    path: '/api/v1/public/*',\n    method: 'GET, POST',\n    limitThreshold: '300 req / 60s per IP',\n    mitigationAction: 'CAPTCHA Challenge',\n    actionVariant: 'secondary',\n    enabled: true,\n    lastTriggered: '14 mins ago',\n    blocked24h: '412 challenges',\n  },\n  {\n    id: 'rule-ai-inference',\n    name: 'ai-inference-tier-standard',\n    scope: 'LLM completions & embeddings',\n    path: '/api/v1/models/generate',\n    method: 'POST',\n    limitThreshold: '20 req / 60s per API Key',\n    mitigationAction: 'HTTP 429 Too Many Requests',\n    actionVariant: 'warning',\n    enabled: true,\n    lastTriggered: '1 hour ago',\n    blocked24h: '148 throttled',\n  },\n  {\n    id: 'rule-search-cluster',\n    name: 'search-endpoints',\n    scope: 'Vector & fuzzy full-text query',\n    path: '/api/v1/search/*',\n    method: 'GET',\n    limitThreshold: '60 req / 60s per IP',\n    mitigationAction: 'Block IP',\n    actionVariant: 'destructive',\n    enabled: false,\n    lastTriggered: '3 days ago',\n    blocked24h: '18 blocks',\n  },\n])\n\nfunction toggleRule(id: string) {\n  const target = rules.value.find((r) => r.id === id)\n  if (target) {\n    target.enabled = !target.enabled\n  }\n}\n\nconst activeRulesCount = computed(() => rules.value.filter((r) => r.enabled).length)\n\nconst filteredRules = computed(() => {\n  if (!searchQuery.value.trim()) return rules.value\n  const q = searchQuery.value.toLowerCase()\n  return rules.value.filter(\n    (r) =>\n      r.name.toLowerCase().includes(q) ||\n      r.path.toLowerCase().includes(q) ||\n      r.scope.toLowerCase().includes(q) ||\n      r.mitigationAction.toLowerCase().includes(q),\n  )\n})\n\nconst simStats = computed(() => {\n  const vol = simVolume.value\n  if (algorithm.value === 'token-bucket') {\n    const refillRate = 50\n    const burstCapacity = 100\n    if (vol <= refillRate) {\n      return {\n        allowed: vol,\n        dropped: 0,\n        allowedPct: 100,\n        droppedPct: 0,\n        bucketFill: Math.round(100 - (vol / refillRate) * 20),\n        status: 'optimal' as const,\n        statusLabel: 'Optimal Throughput · No Throttling',\n        latency: '0.35ms',\n        description: `Traffic volume (${vol} req/s) is well within the 50 req/s continuous refill capacity. 100% of requests pass with zero drop rate.`,\n      }\n    } else if (vol <= burstCapacity) {\n      const drop = 0\n      return {\n        allowed: vol,\n        dropped: drop,\n        allowedPct: 100,\n        droppedPct: 0,\n        bucketFill: Math.max(10, Math.round(100 - ((vol - refillRate) / (burstCapacity - refillRate)) * 80)),\n        status: 'burst' as const,\n        statusLabel: 'Consuming Burst Pool · 0% Dropped',\n        latency: '0.42ms',\n        description: `Traffic exceeds the 50 req/s replenishment rate. Tokens are being drawn from the 100-token burst reservoir. Zero requests dropped so far.`,\n      }\n    } else {\n      const allowed = burstCapacity\n      const dropped = vol - allowed\n      const allowedPct = Math.round((allowed / vol) * 100)\n      const droppedPct = 100 - allowedPct\n      return {\n        allowed,\n        dropped,\n        allowedPct,\n        droppedPct,\n        bucketFill: 0,\n        status: 'throttling' as const,\n        statusLabel: `Rate Limiting Active · ${droppedPct}% Dropped`,\n        latency: '0.51ms',\n        description: `Burst reservoir exhausted. Token bucket limiter is actively enforcing HTTP 429 throttling on ${dropped} req/s excess traffic.`,\n      }\n    }\n  } else {\n    // Sliding window mode\n    const windowLimit = 120\n    if (vol <= windowLimit) {\n      const allowedPct = 100\n      return {\n        allowed: vol,\n        dropped: 0,\n        allowedPct,\n        droppedPct: 0,\n        bucketFill: Math.round((vol / windowLimit) * 100),\n        status: 'optimal' as const,\n        statusLabel: 'Within Sliding Window Quota',\n        latency: '0.38ms',\n        description: `Current 60-second rolling window is ${Math.round((vol / windowLimit) * 100)}% utilized. No mitigation actions triggered.`,\n      }\n    } else {\n      const allowed = windowLimit\n      const dropped = vol - allowed\n      const allowedPct = Math.round((allowed / vol) * 100)\n      const droppedPct = 100 - allowedPct\n      return {\n        allowed,\n        dropped,\n        allowedPct,\n        droppedPct,\n        bucketFill: 100,\n        status: 'throttling' as const,\n        statusLabel: `Window Saturated · ${droppedPct}% Shed`,\n        latency: '0.48ms',\n        description: `Rolling time-window threshold exceeded (${vol} req/s > ${windowLimit} limit). Excess requests are rejected at edge proxy.`,\n      }\n    }\n  }\n})\n</script>\n\n<template>\n  <div data-slot=\"rate-limiting-config\" :class=\"cn('mx-auto w-full max-w-6xl space-y-6', props.class)\">\n    <!-- Header Section -->\n    <div class=\"flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between\">\n      <div class=\"space-y-1.5\">\n        <div class=\"flex flex-wrap items-center gap-2\">\n          <Badge variant=\"outline\" class=\"text-xs font-medium tracking-wide uppercase\">\n            <ShieldCheck class=\"text-primary size-3.5\" />\n            Edge Protection\n          </Badge>\n          <span class=\"text-muted-foreground text-xs\">Cloudflare & Upstash compatible</span>\n        </div>\n        <h1 class=\"text-foreground text-2xl font-bold tracking-tight sm:text-3xl\">\n          Rate Limiting & Traffic Protection\n        </h1>\n        <p class=\"text-muted-foreground text-sm\">\n          Configure DDoS mitigation, IP throttling, and per-tier request quotas.\n        </p>\n      </div>\n\n      <!-- Header Controls -->\n      <div class=\"flex flex-wrap items-center gap-3\">\n        <div class=\"bg-card border-border flex items-center gap-3 rounded-lg border px-3 py-2 shadow-xs\">\n          <div class=\"flex flex-col\">\n            <span class=\"text-foreground text-xs font-semibold\">Global Protection</span>\n            <span class=\"text-muted-foreground text-xs tabular-nums\">\n              {{ globalProtection ? `${activeRulesCount} Active Rules` : 'Disabled (Bypassed)' }}\n            </span>\n          </div>\n          <Switch v-model=\"globalProtection\" />\n        </div>\n\n        <Button class=\"gap-1.5 shadow-xs\">\n          <Plus class=\"size-4\" />\n          <span>Add Rate Limit Rule</span>\n        </Button>\n      </div>\n    </div>\n\n    <!-- 4 Health Cards -->\n    <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n      <!-- Card 1: Total Requests -->\n      <Card class=\"shadow-xs\">\n        <CardHeader class=\"flex flex-row items-center justify-between pb-2\">\n          <CardTitle class=\"text-muted-foreground text-xs font-medium\">Total Requests / min</CardTitle>\n          <div class=\"bg-primary/10 text-primary flex size-8 items-center justify-center rounded-md\">\n            <Activity class=\"size-4\" />\n          </div>\n        </CardHeader>\n        <CardContent class=\"space-y-1\">\n          <div class=\"text-foreground text-2xl font-bold tracking-tight tabular-nums\">4,250 req/s</div>\n          <div class=\"flex items-center gap-1.5 text-xs\">\n            <Badge variant=\"success\" class=\"h-4.5 px-1 py-0 text-xs\">\n              <TrendingUp class=\"size-3\" />\n              +12.4%\n            </Badge>\n            <span class=\"text-muted-foreground tabular-nums\">255.0k / min · 99.98% ok</span>\n          </div>\n        </CardContent>\n      </Card>\n\n      <!-- Card 2: Blocked Attacks -->\n      <Card class=\"shadow-xs\">\n        <CardHeader class=\"flex flex-row items-center justify-between pb-2\">\n          <CardTitle class=\"text-muted-foreground text-xs font-medium\">Blocked Attacks</CardTitle>\n          <div class=\"bg-destructive/10 text-destructive flex size-8 items-center justify-center rounded-md\">\n            <ShieldAlert class=\"size-4\" />\n          </div>\n        </CardHeader>\n        <CardContent class=\"space-y-1\">\n          <div class=\"text-foreground text-2xl font-bold tracking-tight tabular-nums\">1,420 in 24h</div>\n          <div class=\"flex items-center gap-1.5 text-xs\">\n            <Badge variant=\"outline\" class=\"h-4.5 px-1.5 py-0 text-xs font-normal\">Tier-1 Edge</Badge>\n            <span class=\"text-muted-foreground truncate tabular-nums\">18 brute-force bursts</span>\n          </div>\n        </CardContent>\n      </Card>\n\n      <!-- Card 3: Active Throttles -->\n      <Card class=\"shadow-xs\">\n        <CardHeader class=\"flex flex-row items-center justify-between pb-2\">\n          <CardTitle class=\"text-muted-foreground text-xs font-medium\">Active Throttles</CardTitle>\n          <div class=\"bg-warning/10 text-warning flex size-8 items-center justify-center rounded-md\">\n            <ZapOff class=\"size-4\" />\n          </div>\n        </CardHeader>\n        <CardContent class=\"space-y-1\">\n          <div class=\"text-foreground text-2xl font-bold tracking-tight tabular-nums\">18 IPs</div>\n          <div class=\"flex items-center gap-1.5 text-xs\">\n            <span class=\"bg-warning inline-block size-1.5 rounded-full\"></span>\n            <span class=\"text-muted-foreground truncate tabular-nums\">4 edge clusters · Exp 15m</span>\n          </div>\n        </CardContent>\n      </Card>\n\n      <!-- Card 4: Median Latency Overhead -->\n      <Card class=\"shadow-xs\">\n        <CardHeader class=\"flex flex-row items-center justify-between pb-2\">\n          <CardTitle class=\"text-muted-foreground text-xs font-medium\">Median Latency Overhead</CardTitle>\n          <div class=\"bg-info/10 text-info flex size-8 items-center justify-center rounded-md\">\n            <Timer class=\"size-4\" />\n          </div>\n        </CardHeader>\n        <CardContent class=\"space-y-1\">\n          <div class=\"text-foreground text-2xl font-bold tracking-tight tabular-nums\">0.4ms</div>\n          <div class=\"flex items-center gap-1.5 text-xs\">\n            <span class=\"text-muted-foreground tabular-nums\">p99 &lt; 1.2ms · Multi-Region Redis</span>\n          </div>\n        </CardContent>\n      </Card>\n    </div>\n\n    <!-- Interactive Token Bucket Visualizer -->\n    <Card class=\"shadow-xs\">\n      <CardHeader class=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n        <div class=\"space-y-1\">\n          <div class=\"flex flex-wrap items-center gap-2\">\n            <CardTitle class=\"text-lg font-semibold\">Algorithm Simulation & Token Dynamics</CardTitle>\n            <Badge variant=\"outline\" class=\"text-xs font-normal\">Interactive Sandbox</Badge>\n          </div>\n          <CardDescription class=\"text-xs\">\n            Test traffic volume against token reservoir dynamics and rolling time windows.\n          </CardDescription>\n        </div>\n\n        <!-- Algorithm Selector -->\n        <div class=\"flex flex-wrap items-center gap-2\">\n          <span class=\"text-muted-foreground text-xs font-medium\">Algorithm:</span>\n          <Select v-model=\"algorithm\">\n            <SelectTrigger class=\"w-52 text-xs\">\n              <SelectValue placeholder=\"Select algorithm\" />\n            </SelectTrigger>\n            <SelectContent>\n              <SelectItem value=\"token-bucket\">Token Bucket (Burst Tolerant)</SelectItem>\n              <SelectItem value=\"sliding-window\">Sliding Window Counter</SelectItem>\n            </SelectContent>\n          </Select>\n        </div>\n      </CardHeader>\n\n      <CardContent class=\"space-y-6\">\n        <!-- Visual Algorithm Diagram / Pipeline -->\n        <div class=\"grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4\">\n          <!-- Step 1 -->\n          <div class=\"bg-muted/30 border-border relative flex flex-col justify-between rounded-lg border p-3.5\">\n            <div class=\"space-y-1.5\">\n              <div class=\"flex items-center justify-between\">\n                <span class=\"text-muted-foreground text-xs font-medium tracking-wider uppercase\">\n                  {{ algorithm === 'token-bucket' ? '1. Refill Velocity' : '1. Time Window' }}\n                </span>\n                <RefreshCw class=\"text-muted-foreground size-3.5\" />\n              </div>\n              <div class=\"text-foreground text-lg font-semibold tabular-nums\">\n                {{ algorithm === 'token-bucket' ? '50 tokens / s' : '60s Window' }}\n              </div>\n              <p class=\"text-muted-foreground text-xs\">\n                {{\n                  algorithm === 'token-bucket'\n                    ? 'Deterministic continuous refill into pool'\n                    : 'Rolling granular sub-window slices'\n                }}\n              </p>\n            </div>\n            <div class=\"mt-3\">\n              <Progress :model-value=\"100\" class=\"h-1.5\" />\n            </div>\n          </div>\n\n          <!-- Step 2 -->\n          <div class=\"bg-muted/30 border-border relative flex flex-col justify-between rounded-lg border p-3.5\">\n            <div class=\"space-y-1.5\">\n              <div class=\"flex items-center justify-between\">\n                <span class=\"text-muted-foreground text-xs font-medium tracking-wider uppercase\">\n                  {{ algorithm === 'token-bucket' ? '2. Reservoir Capacity' : '2. Window Ceiling' }}\n                </span>\n                <Database class=\"text-muted-foreground size-3.5\" />\n              </div>\n              <div class=\"text-foreground text-lg font-semibold tabular-nums\">\n                {{ algorithm === 'token-bucket' ? '100 tokens max' : '120 req / window' }}\n              </div>\n              <p class=\"text-muted-foreground text-xs\">\n                {{\n                  algorithm === 'token-bucket'\n                    ? `Pool status: ${simStats.bucketFill}% available`\n                    : `Window utilized: ${simStats.bucketFill}%`\n                }}\n              </p>\n            </div>\n            <div class=\"mt-3\">\n              <Progress :model-value=\"simStats.bucketFill\" class=\"h-1.5\" />\n            </div>\n          </div>\n\n          <!-- Step 3 -->\n          <div class=\"bg-muted/30 border-border relative flex flex-col justify-between rounded-lg border p-3.5\">\n            <div class=\"space-y-1.5\">\n              <div class=\"flex items-center justify-between\">\n                <span class=\"text-muted-foreground text-xs font-medium tracking-wider uppercase\"\n                  >3. Test Traffic Load</span\n                >\n                <Zap class=\"text-primary size-3.5\" />\n              </div>\n              <div class=\"text-foreground text-lg font-semibold tabular-nums\">{{ simVolume }} req/s</div>\n              <p class=\"text-muted-foreground text-xs\">Simulated rate generated from slider</p>\n            </div>\n            <div class=\"mt-3\">\n              <Progress :model-value=\"Math.min(100, Math.round((simVolume / 500) * 100))\" class=\"h-1.5\" />\n            </div>\n          </div>\n\n          <!-- Step 4 -->\n          <div class=\"bg-muted/30 border-border relative flex flex-col justify-between rounded-lg border p-3.5\">\n            <div class=\"space-y-1.5\">\n              <div class=\"flex items-center justify-between\">\n                <span class=\"text-muted-foreground text-xs font-medium tracking-wider uppercase\"\n                  >4. Edge Gate Verdict</span\n                >\n                <component\n                  :is=\"\n                    simStats.status === 'optimal'\n                      ? CheckCircle2\n                      : simStats.status === 'burst'\n                        ? AlertTriangle\n                        : ShieldAlert\n                  \"\n                  :class=\"[\n                    'size-3.5',\n                    simStats.status === 'optimal'\n                      ? 'text-success'\n                      : simStats.status === 'burst'\n                        ? 'text-warning'\n                        : 'text-destructive',\n                  ]\"\n                />\n              </div>\n              <div class=\"text-foreground text-lg font-semibold tabular-nums\">\n                {{ simStats.allowed }} Pass · {{ simStats.dropped }} Drop\n              </div>\n              <p class=\"text-muted-foreground text-xs\">Overhead: {{ simStats.latency }}</p>\n            </div>\n            <div class=\"mt-3\">\n              <div class=\"bg-secondary relative h-1.5 w-full overflow-hidden rounded-full\">\n                <div\n                  class=\"bg-success absolute top-0 bottom-0 left-0 transition-colors duration-150\"\n                  :style=\"{ width: `${simStats.allowedPct}%` }\"\n                ></div>\n                <div\n                  class=\"bg-destructive absolute top-0 right-0 bottom-0 transition-colors duration-150\"\n                  :style=\"{ width: `${simStats.droppedPct}%` }\"\n                ></div>\n              </div>\n            </div>\n          </div>\n        </div>\n\n        <!-- Interactive Simulator Slider Box -->\n        <div class=\"bg-muted/20 border-border space-y-4 rounded-lg border p-4\">\n          <div class=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n            <div class=\"space-y-0.5\">\n              <div class=\"flex flex-wrap items-center gap-2\">\n                <Sliders class=\"text-primary size-4\" />\n                <span class=\"text-foreground text-sm font-semibold\">Simulate Incoming Request Volume</span>\n              </div>\n              <p class=\"text-muted-foreground text-xs\">\n                Drag the slider to stress-test the algorithm against burst spikes and DDoS loads.\n              </p>\n            </div>\n\n            <!-- Current Rate Pill -->\n            <div class=\"flex flex-wrap items-center gap-2\">\n              <Badge\n                :variant=\"\n                  simStats.status === 'optimal' ? 'success' : simStats.status === 'burst' ? 'warning' : 'destructive'\n                \"\n                class=\"text-xs font-medium\"\n              >\n                {{ simStats.statusLabel }}\n              </Badge>\n              <div class=\"bg-card border-border rounded border px-2.5 py-1 font-mono text-sm font-bold tabular-nums\">\n                {{ simVolume }} req/s\n              </div>\n            </div>\n          </div>\n\n          <!-- Slider -->\n          <div class=\"space-y-2 pt-2\">\n            <Slider v-model=\"simVolume\" :min=\"10\" :max=\"500\" :step=\"10\" class=\"w-full\" />\n            <div class=\"text-muted-foreground flex justify-between text-xs tabular-nums\">\n              <span>10 req/s (Low)</span>\n              <span>50 req/s (Refill Rate)</span>\n              <span>100 req/s (Burst Limit)</span>\n              <span>250 req/s (Heavy Spike)</span>\n              <span>500 req/s (DDoS Attack)</span>\n            </div>\n          </div>\n\n          <!-- Simulation Visual Metrics & Split Bar -->\n          <div class=\"space-y-3 pt-2\">\n            <!-- Split Bar -->\n            <div class=\"space-y-1.5\">\n              <div class=\"flex justify-between text-xs font-medium\">\n                <span class=\"text-success flex items-center gap-1\">\n                  <span class=\"bg-success size-2 rounded-full\"></span>\n                  Allowed: {{ simStats.allowed }} req/s ({{ simStats.allowedPct }}%)\n                </span>\n                <span class=\"text-destructive flex items-center gap-1\">\n                  <span class=\"bg-destructive size-2 rounded-full\"></span>\n                  Rate Limited / 429: {{ simStats.dropped }} req/s ({{ simStats.droppedPct }}%)\n                </span>\n              </div>\n\n              <div class=\"bg-muted border-border/50 relative h-2.5 w-full overflow-hidden rounded-full border\">\n                <div\n                  class=\"bg-success absolute top-0 bottom-0 left-0 transition-colors duration-150\"\n                  :style=\"{ width: `${simStats.allowedPct}%` }\"\n                ></div>\n                <div\n                  class=\"bg-destructive absolute top-0 right-0 bottom-0 transition-colors duration-150\"\n                  :style=\"{ width: `${simStats.droppedPct}%` }\"\n                ></div>\n              </div>\n            </div>\n\n            <!-- Simulation Summary Description -->\n            <div class=\"bg-card border-border/80 flex items-start gap-2.5 rounded-md border p-3 text-xs\">\n              <Shield class=\"text-primary mt-0.5 size-4 shrink-0\" />\n              <p class=\"text-muted-foreground leading-relaxed\">\n                {{ simStats.description }}\n              </p>\n            </div>\n          </div>\n        </div>\n      </CardContent>\n    </Card>\n\n    <!-- Configured Rules Table Card -->\n    <Card class=\"shadow-xs\">\n      <CardHeader class=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n        <div class=\"space-y-1\">\n          <div class=\"flex flex-wrap items-center gap-2\">\n            <CardTitle class=\"text-lg font-semibold\">Configured Rate Limiting Rules</CardTitle>\n            <Badge variant=\"secondary\" class=\"text-xs font-normal tabular-nums\">\n              {{ filteredRules.length }} Policies\n            </Badge>\n          </div>\n          <CardDescription class=\"text-xs\">\n            Priority-ordered edge firewall rules evaluated sequentially for incoming traffic.\n          </CardDescription>\n        </div>\n\n        <!-- Filter Search Bar -->\n        <div class=\"relative w-full sm:w-64\">\n          <Search class=\"text-muted-foreground absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2\" />\n          <input\n            v-model=\"searchQuery\"\n            type=\"text\"\n            placeholder=\"Search rules, paths, actions…\"\n            class=\"border-input bg-background placeholder:text-muted-foreground focus-visible:ring-ring/50 focus-visible:border-ring h-8.5 w-full rounded-md border pr-3 pl-8 text-xs shadow-xs outline-none focus-visible:ring-[3px]\"\n          />\n        </div>\n      </CardHeader>\n\n      <CardContent class=\"p-0\">\n        <div class=\"overflow-x-auto\">\n          <Table>\n            <TableHeader>\n              <TableRow>\n                <TableHead class=\"w-[280px]\">Rule Name & Scope</TableHead>\n                <TableHead class=\"w-[220px]\">Path Matcher</TableHead>\n                <TableHead class=\"w-[180px]\">Limit Threshold</TableHead>\n                <TableHead class=\"w-[200px]\">Mitigation Action</TableHead>\n                <TableHead class=\"w-[90px] text-center\">Status</TableHead>\n                <TableHead class=\"w-[60px] text-right\">Actions</TableHead>\n              </TableRow>\n            </TableHeader>\n            <TableBody>\n              <TableRow\n                v-for=\"rule in filteredRules\"\n                :key=\"rule.id\"\n                :class=\"cn(!rule.enabled && 'bg-muted/20 opacity-60')\"\n              >\n                <!-- Rule Name & Scope -->\n                <TableCell>\n                  <div class=\"space-y-0.5\">\n                    <div class=\"flex flex-wrap items-center gap-2\">\n                      <span class=\"text-foreground font-mono text-xs font-semibold\">\n                        {{ rule.name }}\n                      </span>\n                    </div>\n                    <div class=\"text-muted-foreground flex items-center gap-1.5 text-xs\">\n                      <span>{{ rule.scope }}</span>\n                      <span>·</span>\n                      <span class=\"tabular-nums\">{{ rule.blocked24h }} in 24h</span>\n                    </div>\n                  </div>\n                </TableCell>\n\n                <!-- Path Matcher -->\n                <TableCell>\n                  <div class=\"flex items-center gap-1.5\">\n                    <Badge variant=\"outline\" class=\"font-mono text-xs uppercase\">\n                      {{ rule.method }}\n                    </Badge>\n                    <code\n                      class=\"bg-muted/60 border-border text-foreground rounded border px-1.5 py-0.5 font-mono text-xs\"\n                    >\n                      {{ rule.path }}\n                    </code>\n                  </div>\n                </TableCell>\n\n                <!-- Limit Threshold -->\n                <TableCell>\n                  <div class=\"space-y-0.5\">\n                    <div class=\"text-foreground font-mono text-xs font-medium tabular-nums\">\n                      {{ rule.limitThreshold }}\n                    </div>\n                    <div class=\"text-muted-foreground text-xs\">Triggered {{ rule.lastTriggered }}</div>\n                  </div>\n                </TableCell>\n\n                <!-- Mitigation Action Badge -->\n                <TableCell>\n                  <Badge :variant=\"rule.actionVariant\" class=\"text-xs font-medium\">\n                    <span\n                      :class=\"[\n                        'mr-1 size-1.5 rounded-full',\n                        rule.actionVariant === 'warning'\n                          ? 'bg-warning'\n                          : rule.actionVariant === 'destructive'\n                            ? 'bg-destructive'\n                            : 'bg-secondary-foreground',\n                      ]\"\n                    ></span>\n                    {{ rule.mitigationAction }}\n                  </Badge>\n                </TableCell>\n\n                <!-- Status Switch -->\n                <TableCell class=\"text-center\">\n                  <Switch :model-value=\"rule.enabled\" @update:model-value=\"() => toggleRule(rule.id)\" />\n                </TableCell>\n\n                <!-- Actions Dropdown -->\n                <TableCell class=\"text-right\">\n                  <DropdownMenu>\n                    <DropdownMenuTrigger as-child>\n                      <Button variant=\"ghost\" size=\"icon\" class=\"size-8\">\n                        <MoreHorizontal class=\"size-4\" />\n                        <span class=\"sr-only\">Open menu</span>\n                      </Button>\n                    </DropdownMenuTrigger>\n                    <DropdownMenuContent align=\"end\" class=\"w-48\">\n                      <DropdownMenuLabel class=\"text-xs\">Rule Configuration</DropdownMenuLabel>\n                      <DropdownMenuItem class=\"gap-2 text-xs\">\n                        <Edit3 class=\"size-3.5\" />\n                        <span>Edit Rule</span>\n                      </DropdownMenuItem>\n                      <DropdownMenuItem class=\"gap-2 text-xs\">\n                        <Activity class=\"size-3.5\" />\n                        <span>View Metrics</span>\n                      </DropdownMenuItem>\n                      <DropdownMenuItem class=\"gap-2 text-xs\">\n                        <Copy class=\"size-3.5\" />\n                        <span>Duplicate Rule</span>\n                      </DropdownMenuItem>\n                      <DropdownMenuSeparator />\n                      <DropdownMenuItem class=\"text-destructive focus:text-destructive gap-2 text-xs\">\n                        <Trash2 class=\"size-3.5\" />\n                        <span>Delete Rule</span>\n                      </DropdownMenuItem>\n                    </DropdownMenuContent>\n                  </DropdownMenu>\n                </TableCell>\n              </TableRow>\n            </TableBody>\n          </Table>\n        </div>\n      </CardContent>\n    </Card>\n  </div>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/RateLimitingConfig.vue"
    }
  ],
  "dependencies": [
    "lucide-vue-next"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/vue/badge.json",
    "https://uipkge.dev/r/vue/button.json",
    "https://uipkge.dev/r/vue/card.json",
    "https://uipkge.dev/r/vue/dropdown-menu.json",
    "https://uipkge.dev/r/vue/progress.json",
    "https://uipkge.dev/r/vue/select.json",
    "https://uipkge.dev/r/vue/slider.json",
    "https://uipkge.dev/r/vue/switch.json",
    "https://uipkge.dev/r/vue/table.json"
  ],
  "description": "Cloudflare/Upstash style API rate limiting rules builder and token bucket traffic monitor with 4 health metrics cards, interactive token bucket vs sliding window simulation slider, and configured mitigation rules table with status controls and contextual action menus.",
  "categories": [
    "devops",
    "app",
    "dashboard"
  ]
}