{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "upstash-ratelimit",
  "title": "Upstash Ratelimit",
  "description": "Visual rate limit indicator with progress bar, remaining count, and reset timer. Perfect for displaying @upstash/ratelimit responses.",
  "dependencies": [
    "@upstash/ratelimit",
    "@upstash/redis"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/default/blocks/upstash/upstash-ratelimit/components/elements/upstash-ratelimit.tsx",
      "content": "\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { cn } from \"@/lib/utils\";\n\ninterface UpstashRatelimitProps {\n  limit: number;\n  remaining: number;\n  reset: number;\n  success?: boolean;\n  showResetTimer?: boolean;\n  size?: \"sm\" | \"md\" | \"lg\";\n  className?: string;\n}\n\nfunction ShieldIcon({ className }: { className?: string }) {\n  return (\n    <svg\n      className={className}\n      viewBox=\"0 0 24 24\"\n      fill=\"none\"\n      stroke=\"currentColor\"\n      strokeWidth={2}\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n    >\n      <path d=\"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z\" />\n    </svg>\n  );\n}\n\nfunction formatTimeRemaining(ms: number): string {\n  if (ms <= 0) return \"0s\";\n  const seconds = Math.floor(ms / 1000);\n  const minutes = Math.floor(seconds / 60);\n  const hours = Math.floor(minutes / 60);\n\n  if (hours > 0) return `${hours}h ${minutes % 60}m`;\n  if (minutes > 0) return `${minutes}m ${seconds % 60}s`;\n  return `${seconds}s`;\n}\n\nconst SIZE_CLASSES = {\n  sm: { container: \"p-3 gap-2\", icon: \"w-4 h-4\", text: \"text-xs\", bar: \"h-1.5\" },\n  md: { container: \"p-4 gap-3\", icon: \"w-5 h-5\", text: \"text-sm\", bar: \"h-2\" },\n  lg: { container: \"p-5 gap-4\", icon: \"w-6 h-6\", text: \"text-base\", bar: \"h-2.5\" },\n};\n\nexport function UpstashRatelimit({\n  limit,\n  remaining,\n  reset,\n  success = true,\n  showResetTimer = true,\n  size = \"md\",\n  className,\n}: UpstashRatelimitProps) {\n  const [timeRemaining, setTimeRemaining] = useState(reset - Date.now());\n  const percentage = (remaining / limit) * 100;\n  const sizes = SIZE_CLASSES[size];\n\n  useEffect(() => {\n    if (!showResetTimer) return;\n\n    const interval = setInterval(() => {\n      const newTime = reset - Date.now();\n      setTimeRemaining(newTime > 0 ? newTime : 0);\n    }, 1000);\n\n    return () => clearInterval(interval);\n  }, [reset, showResetTimer]);\n\n  const getStatusColor = () => {\n    if (!success) return \"text-destructive\";\n    if (percentage > 50) return \"text-green-500\";\n    if (percentage > 20) return \"text-yellow-500\";\n    return \"text-orange-500\";\n  };\n\n  const getBarColor = () => {\n    if (!success) return \"bg-destructive\";\n    if (percentage > 50) return \"bg-green-500\";\n    if (percentage > 20) return \"bg-yellow-500\";\n    return \"bg-orange-500\";\n  };\n\n  return (\n    <div\n      data-slot=\"upstash-ratelimit\"\n      className={cn(\n        \"rounded-lg border border-border bg-card\",\n        \"flex flex-col\",\n        sizes.container,\n        className\n      )}\n    >\n      <div className=\"flex items-center justify-between\">\n        <div className=\"flex items-center gap-2\">\n          <ShieldIcon className={cn(sizes.icon, getStatusColor())} />\n          <span className={cn(\"font-medium\", sizes.text)}>Rate Limit</span>\n        </div>\n        <div className={cn(\"font-mono\", sizes.text, getStatusColor())}>\n          {remaining} / {limit}\n        </div>\n      </div>\n\n      <div className={cn(\"w-full bg-muted rounded-full overflow-hidden\", sizes.bar)}>\n        <div\n          className={cn(\n            \"h-full rounded-full transition-all duration-500 ease-out\",\n            getBarColor()\n          )}\n          style={{ width: `${Math.max(percentage, 0)}%` }}\n        />\n      </div>\n\n      <div className=\"flex items-center justify-between\">\n        <span className={cn(\"text-muted-foreground\", sizes.text)}>\n          {success ? \"Requests available\" : \"Rate limit exceeded\"}\n        </span>\n        {showResetTimer && timeRemaining > 0 && (\n          <span className={cn(\"text-muted-foreground font-mono\", sizes.text)}>\n            Resets in {formatTimeRemaining(timeRemaining)}\n          </span>\n        )}\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:component"
    }
  ],
  "docs": "Self-contained rate limit indicator showing remaining requests, limit, and countdown to reset. Supports multiple sizes and automatic color states.",
  "categories": [
    "upstash"
  ],
  "type": "registry:block"
}