{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "webhook-tester",
  "title": "Webhook Tester",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-react/blocks/webhook-tester/WebhookTester.tsx",
      "content": "'use client'\n\nimport * as React from 'react'\nimport {\n  Activity,\n  ArrowRight,\n  Check,\n  CheckCircle2,\n  Clock,\n  Copy,\n  FileCode,\n  Globe,\n  Key,\n  Layers,\n  RefreshCw,\n  RotateCw,\n  Send,\n  ShieldCheck,\n  Zap,\n} from 'lucide-react'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Input } from '@/components/ui/input'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'\nimport { Separator } from '@/components/ui/separator'\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'\nimport { Textarea } from '@/components/ui/textarea'\nimport { cn } from '@/lib/utils'\n\ninterface EventPreset {\n  id: string\n  name: string\n  category: string\n  description: string\n  defaultPayload: object\n}\n\ninterface DeliveryAttempt {\n  id: string\n  eventId: string\n  eventType: string\n  status: number\n  statusText: string\n  timestamp: string\n  timeAgo: string\n  latencyMs: number\n  endpointUrl: string\n  signature: string\n  requestHeaders: Record<string, string>\n  requestBody: string\n  responseHeaders: Record<string, string>\n  responseBody: string\n  timings: {\n    dns: number\n    tls: number\n    ttfb: number\n    download: number\n    total: number\n  }\n}\n\nconst eventPresets: EventPreset[] = [\n  {\n    id: 'customer.created',\n    name: 'customer.created',\n    category: 'Customers',\n    description: 'Dispatched whenever a new customer account or profile is created.',\n    defaultPayload: {\n      id: 'evt_1PqN8y2eZvKYlo2C79x01abc',\n      object: 'event',\n      api_version: '2026-08-01',\n      created: 1787313600,\n      type: 'customer.created',\n      data: {\n        object: {\n          id: 'cus_N0wP9XyZ12345',\n          object: 'customer',\n          name: 'Sarah Connor',\n          email: 'sarah.connor@cyberdyne.io',\n          phone: '+1 415 555 0199',\n          currency: 'usd',\n          metadata: {\n            source: 'onboarding_flow_v2',\n            tier: 'enterprise',\n          },\n        },\n      },\n    },\n  },\n  {\n    id: 'invoice.payment_succeeded',\n    name: 'invoice.payment_succeeded',\n    category: 'Billing',\n    description: 'Triggered upon successful capture and settlement of recurring invoice payment.',\n    defaultPayload: {\n      id: 'evt_2MqK7x3eZvKYlo2C88y02def',\n      object: 'event',\n      api_version: '2026-08-01',\n      created: 1787313580,\n      type: 'invoice.payment_succeeded',\n      data: {\n        object: {\n          id: 'in_1QpZ2w3eZvKYlo2C99182312',\n          object: 'invoice',\n          customer: 'cus_N0wP9XyZ12345',\n          amount_paid: 49000,\n          amount_due: 49000,\n          currency: 'usd',\n          status: 'paid',\n          paid_at: 1787313575,\n          lines: {\n            data: [\n              {\n                description: 'Pro Tier Subscription (10 Seats)',\n                amount: 49000,\n                period: {\n                  start: 1787313500,\n                  end: 1789905500,\n                },\n              },\n            ],\n          },\n        },\n      },\n    },\n  },\n  {\n    id: 'order.fulfilled',\n    name: 'order.fulfilled',\n    category: 'Fulfillment',\n    description: 'Emitted when logistics carrier records the parcel as dispatched.',\n    defaultPayload: {\n      id: 'evt_3KpJ5v4eZvKYlo2C77z03ghi',\n      object: 'event',\n      api_version: '2026-08-01',\n      created: 1787313520,\n      type: 'order.fulfilled',\n      data: {\n        object: {\n          id: 'ord_88192341',\n          object: 'order',\n          customer_id: 'cus_N0wP9XyZ12345',\n          carrier: 'FedEx Priority',\n          tracking_number: '794829103948',\n          status: 'fulfilled',\n          items_count: 3,\n          fulfillment_date: '2026-08-21T14:38:40Z',\n        },\n      },\n    },\n  },\n  {\n    id: 'subscription.updated',\n    name: 'subscription.updated',\n    category: 'Subscriptions',\n    description: 'Emitted when plan, billing frequency, or seat quantities update.',\n    defaultPayload: {\n      id: 'evt_4TqL9m1eZvKYlo2C66w04jkl',\n      object: 'event',\n      api_version: '2026-08-01',\n      created: 1787313460,\n      type: 'subscription.updated',\n      data: {\n        object: {\n          id: 'sub_1QzX89aZvKYlo2C01',\n          object: 'subscription',\n          customer: 'cus_N0wP9XyZ12345',\n          current_period_end: 1792497600,\n          plan: {\n            id: 'price_enterprise_yearly',\n            name: 'Enterprise Annual',\n            amount: 588000,\n          },\n          quantity: 25,\n          status: 'active',\n        },\n      },\n    },\n  },\n]\n\nfunction generateDeterministicSignature(secret: string, payload: string, timestamp: number): string {\n  let hash = 0\n  const str = `${timestamp}.${secret}.${payload}`\n  for (let i = 0; i < str.length; i++) {\n    const char = str.charCodeAt(i)\n    hash = (hash << 5) - hash + char\n    hash |= 0\n  }\n  const hex1 = Math.abs(hash).toString(16).padStart(8, '0')\n  const hex2 = Math.abs((hash * 31 + 17) | 0)\n    .toString(16)\n    .padStart(8, '0')\n  const hex3 = Math.abs((hash * 127 + 59) | 0)\n    .toString(16)\n    .padStart(8, '0')\n  const hex4 = Math.abs((hash * 8191 + 97) | 0)\n    .toString(16)\n    .padStart(8, '0')\n  return `${hex1}${hex2}${hex3}${hex4}`\n}\n\nconst initialDeliveries: DeliveryAttempt[] = [\n  {\n    id: 'del_01J6A7BC8D9EF01',\n    eventId: 'evt_1PqN8y2eZvKYlo2C79x01abc',\n    eventType: 'customer.created',\n    status: 200,\n    statusText: 'OK',\n    timestamp: '2026-08-21 14:40:12 UTC',\n    timeAgo: '12s ago',\n    latencyMs: 142,\n    endpointUrl: 'https://api.acme.dev/webhooks',\n    signature: 't=1787313612,v1=5257a869e7eceeda32ab62f1a9338f6cf60c9b07',\n    requestHeaders: {\n      'content-type': 'application/json; charset=utf-8',\n      'user-agent': 'UIPKGE-Webhooks/2.0 (webhook-tester)',\n      'stripe-signature': 't=1787313612,v1=5257a869e7eceeda32ab62f1a9338f6cf60c9b07',\n      'webhook-id': 'msg_01J6A7BC8D9EF01',\n      'webhook-timestamp': '1787313612',\n    },\n    requestBody: JSON.stringify(eventPresets[0].defaultPayload, null, 2),\n    responseHeaders: {\n      'content-type': 'application/json; charset=utf-8',\n      date: 'Fri, 21 Aug 2026 14:40:12 GMT',\n      server: 'cloudflare-worker',\n      'x-request-id': 'req_98b47120aef1',\n    },\n    responseBody: JSON.stringify(\n      {\n        received: true,\n        handler: 'customer_sync_v2',\n        job_id: 'job_984129',\n        processed_at: '2026-08-21T14:40:12.140Z',\n      },\n      null,\n      2,\n    ),\n    timings: {\n      dns: 14,\n      tls: 26,\n      ttfb: 88,\n      download: 14,\n      total: 142,\n    },\n  },\n  {\n    id: 'del_01J6A6ZZ7E8D9C0',\n    eventId: 'evt_2MqK7x3eZvKYlo2C88y02def',\n    eventType: 'invoice.payment_succeeded',\n    status: 200,\n    statusText: 'OK',\n    timestamp: '2026-08-21 14:38:10 UTC',\n    timeAgo: '2m ago',\n    latencyMs: 98,\n    endpointUrl: 'https://api.acme.dev/webhooks',\n    signature: 't=1787313490,v1=99fa1b2388c4710aef12d098bc762a41289fe1b0',\n    requestHeaders: {\n      'content-type': 'application/json; charset=utf-8',\n      'user-agent': 'UIPKGE-Webhooks/2.0 (webhook-tester)',\n      'stripe-signature': 't=1787313490,v1=99fa1b2388c4710aef12d098bc762a41289fe1b0',\n      'webhook-id': 'msg_01J6A6ZZ7E8D9C0',\n      'webhook-timestamp': '1787313490',\n    },\n    requestBody: JSON.stringify(eventPresets[1].defaultPayload, null, 2),\n    responseHeaders: {\n      'content-type': 'application/json; charset=utf-8',\n      date: 'Fri, 21 Aug 2026 14:38:10 GMT',\n      server: 'nginx/1.24.0',\n      'x-request-id': 'req_77a1902bc450',\n    },\n    responseBody: JSON.stringify(\n      {\n        status: 'ok',\n        ledger_updated: true,\n        invoice_id: 'in_1QpZ2w3eZvKYlo2C99182312',\n      },\n      null,\n      2,\n    ),\n    timings: {\n      dns: 10,\n      tls: 20,\n      ttfb: 56,\n      download: 12,\n      total: 98,\n    },\n  },\n  {\n    id: 'del_01J6A5YY4C2B1A9',\n    eventId: 'evt_3KpJ5v4eZvKYlo2C77z03ghi',\n    eventType: 'order.fulfilled',\n    status: 500,\n    statusText: 'Internal Server Error',\n    timestamp: '2026-08-21 14:34:00 UTC',\n    timeAgo: '6m ago',\n    latencyMs: 1240,\n    endpointUrl: 'https://api.acme.dev/webhooks',\n    signature: 't=1787313240,v1=12fe48a90bb76c123490fdba891230cd78129aef',\n    requestHeaders: {\n      'content-type': 'application/json; charset=utf-8',\n      'user-agent': 'UIPKGE-Webhooks/2.0 (webhook-tester)',\n      'stripe-signature': 't=1787313240,v1=12fe48a90bb76c123490fdba891230cd78129aef',\n      'webhook-id': 'msg_01J6A5YY4C2B1A9',\n      'webhook-timestamp': '1787313240',\n    },\n    requestBody: JSON.stringify(eventPresets[2].defaultPayload, null, 2),\n    responseHeaders: {\n      'content-type': 'application/json; charset=utf-8',\n      date: 'Fri, 21 Aug 2026 14:34:01 GMT',\n      server: 'express-gateway',\n      'x-request-id': 'req_33f8101cd991',\n    },\n    responseBody: JSON.stringify(\n      {\n        error: 'InternalServerError',\n        message: 'Failed to connect to upstream ERP database at 10.0.4.12:5432 (ETIMEDOUT)',\n        code: 'DB_CONN_TIMEOUT',\n        retryable: true,\n      },\n      null,\n      2,\n    ),\n    timings: {\n      dns: 12,\n      tls: 24,\n      ttfb: 1190,\n      download: 14,\n      total: 1240,\n    },\n  },\n]\n\nexport function WebhookTester({ className }: { className?: string }) {\n  const [endpointUrl, setEndpointUrl] = React.useState('https://api.acme.dev/webhooks')\n  const [signingSecret, setSigningSecret] = React.useState('whsec_9f83a8b271d4e680c102a9b6c7a3efd8')\n  const [selectedEvent, setSelectedEvent] = React.useState('customer.created')\n  const [currentPayloadStr, setCurrentPayloadStr] = React.useState(\n    JSON.stringify(eventPresets[0].defaultPayload, null, 2),\n  )\n  const [signatureFormat, setSignatureFormat] = React.useState<'stripe' | 'svix'>('stripe')\n  const [activeInspectorTab, setActiveInspectorTab] = React.useState('request')\n\n  const [isSending, setIsSending] = React.useState(false)\n  const [copiedKey, setCopiedKey] = React.useState<string | null>(null)\n\n  const [deliveryHistory, setDeliveryHistory] = React.useState<DeliveryAttempt[]>(initialDeliveries)\n  const [selectedDeliveryId, setSelectedDeliveryId] = React.useState<string>(initialDeliveries[0].id)\n  const [currentTimestamp, setCurrentTimestamp] = React.useState(1787313600)\n\n  const activeDelivery = React.useMemo(() => {\n    return deliveryHistory.find((d) => d.id === selectedDeliveryId) ?? deliveryHistory[0]\n  }, [deliveryHistory, selectedDeliveryId])\n\n  const activePreset = React.useMemo(() => {\n    return eventPresets.find((p) => p.id === selectedEvent) ?? eventPresets[0]\n  }, [selectedEvent])\n\n  const computedSignatureHex = React.useMemo(() => {\n    return generateDeterministicSignature(signingSecret, currentPayloadStr, currentTimestamp)\n  }, [signingSecret, currentPayloadStr, currentTimestamp])\n\n  const computedAllHeaders = React.useMemo(() => {\n    const t = currentTimestamp\n    const sigHex = computedSignatureHex\n    if (signatureFormat === 'stripe') {\n      return `POST ${endpointUrl}\\nHost: api.acme.dev\\nContent-Type: application/json\\nUser-Agent: UIPKGE-Webhooks/2.0\\nStripe-Signature: t=${t},v1=${sigHex}`\n    }\n    const b64 = typeof window !== 'undefined' ? btoa(sigHex.slice(0, 32)) : sigHex.slice(0, 32)\n    return `POST ${endpointUrl}\\nHost: api.acme.dev\\nContent-Type: application/json\\nUser-Agent: UIPKGE-Webhooks/2.0\\nwebhook-id: msg_${sigHex.slice(0, 14)}\\nwebhook-timestamp: ${t}\\nwebhook-signature: v1,${b64}`\n  }, [endpointUrl, currentTimestamp, computedSignatureHex, signatureFormat])\n\n  const handleEventChange = React.useCallback((eventId: string) => {\n    setSelectedEvent(eventId)\n    const preset = eventPresets.find((p) => p.id === eventId)\n    if (preset) {\n      setCurrentPayloadStr(JSON.stringify(preset.defaultPayload, null, 2))\n    }\n  }, [])\n\n  const handleFormatJson = React.useCallback(() => {\n    try {\n      const parsed = JSON.parse(currentPayloadStr)\n      setCurrentPayloadStr(JSON.stringify(parsed, null, 2))\n    } catch {\n      // Keep as is\n    }\n  }, [currentPayloadStr])\n\n  const handleResetPayload = React.useCallback(() => {\n    const preset = eventPresets.find((p) => p.id === selectedEvent)\n    if (preset) {\n      setCurrentPayloadStr(JSON.stringify(preset.defaultPayload, null, 2))\n    }\n  }, [selectedEvent])\n\n  const handleRegenerateSecret = React.useCallback(() => {\n    const chars = 'abcdef0123456789'\n    let result = 'whsec_'\n    for (let i = 0; i < 32; i++) {\n      result += chars.charAt(Math.floor(Math.random() * chars.length))\n    }\n    setSigningSecret(result)\n  }, [])\n\n  const handleCopy = React.useCallback((text: string, key: string) => {\n    navigator.clipboard?.writeText(text)\n    setCopiedKey(key)\n    setTimeout(() => {\n      setCopiedKey((prev) => (prev === key ? null : prev))\n    }, 2000)\n  }, [])\n\n  const sendWebhook = React.useCallback(() => {\n    if (isSending) return\n    setIsSending(true)\n\n    const nowSec = Math.floor(Date.now() / 1000)\n    setCurrentTimestamp(nowSec)\n\n    setTimeout(() => {\n      let parsedBody: any = {}\n      let isInvalidJson = false\n      try {\n        parsedBody = JSON.parse(currentPayloadStr)\n      } catch {\n        isInvalidJson = true\n      }\n\n      const isFailureUrl = endpointUrl.includes('fail') || endpointUrl.includes('error')\n      const status = isInvalidJson ? 400 : isFailureUrl ? 500 : 200\n      const statusText = isInvalidJson ? 'Bad Request' : isFailureUrl ? 'Internal Server Error' : 'OK'\n      const latency = isInvalidJson ? 32 : isFailureUrl ? 850 : Math.floor(Math.random() * 90) + 65\n\n      const deliveryId = `del_${Math.random().toString(36).substring(2, 11).toUpperCase()}`\n      const eventId = parsedBody?.id ?? `evt_${Math.random().toString(36).substring(2, 10)}`\n      const eventType = parsedBody?.type ?? selectedEvent\n      const sig = `t=${nowSec},v1=${computedSignatureHex}`\n\n      const newDelivery: DeliveryAttempt = {\n        id: deliveryId,\n        eventId,\n        eventType,\n        status,\n        statusText,\n        timestamp: 'Just now',\n        timeAgo: 'Just now',\n        latencyMs: latency,\n        endpointUrl,\n        signature: sig,\n        requestHeaders: {\n          'content-type': 'application/json; charset=utf-8',\n          'user-agent': 'UIPKGE-Webhooks/2.0 (webhook-tester)',\n          'stripe-signature': sig,\n          'webhook-id': `msg_${deliveryId}`,\n          'webhook-timestamp': String(nowSec),\n        },\n        requestBody: currentPayloadStr,\n        responseHeaders: {\n          'content-type': 'application/json; charset=utf-8',\n          date: new Date().toUTCString(),\n          server: 'acme-edge-router/1.8',\n          'x-request-id': `req_${Math.random().toString(36).substring(2, 12)}`,\n        },\n        responseBody: isInvalidJson\n          ? JSON.stringify({ error: 'BadRequest', message: 'Payload is not valid RFC 8259 JSON' }, null, 2)\n          : isFailureUrl\n            ? JSON.stringify(\n                { error: 'InternalServerError', message: 'Webhook handler threw uncaught exception' },\n                null,\n                2,\n              )\n            : JSON.stringify(\n                {\n                  received: true,\n                  event_type: eventType,\n                  delivery_id: deliveryId,\n                  status: 'acknowledged',\n                  timestamp: new Date().toISOString(),\n                },\n                null,\n                2,\n              ),\n        timings: {\n          dns: Math.floor(latency * 0.1),\n          tls: Math.floor(latency * 0.2),\n          ttfb: Math.floor(latency * 0.6),\n          download: Math.floor(latency * 0.1),\n          total: latency,\n        },\n      }\n\n      setDeliveryHistory((prev) => [newDelivery, ...prev])\n      setSelectedDeliveryId(newDelivery.id)\n      setIsSending(false)\n    }, 450)\n  }, [isSending, currentPayloadStr, endpointUrl, selectedEvent, computedSignatureHex])\n\n  const retryDelivery = React.useCallback(\n    (attempt: DeliveryAttempt) => {\n      setCurrentPayloadStr(attempt.requestBody)\n      setEndpointUrl(attempt.endpointUrl)\n      setSelectedEvent(attempt.eventType)\n      sendWebhook()\n    },\n    [sendWebhook],\n  )\n\n  React.useEffect(() => {\n    const handleKeyDown = (e: KeyboardEvent) => {\n      if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {\n        e.preventDefault()\n        sendWebhook()\n      }\n    }\n    window.addEventListener('keydown', handleKeyDown)\n    return () => window.removeEventListener('keydown', handleKeyDown)\n  }, [sendWebhook])\n\n  return (\n    <div data-slot=\"webhook-tester\" className={cn('w-full space-y-6', className)}>\n      {/* Top Header Banner & Primary Endpoint Controls */}\n      <Card className=\"border-border bg-card shadow-xs\">\n        <CardHeader className=\"pb-4\">\n          <div className=\"flex flex-col gap-4 md:flex-row md:items-center md:justify-between\">\n            <div className=\"space-y-1\">\n              <div className=\"flex items-center gap-2\">\n                <div className=\"bg-primary/10 text-primary flex size-8 items-center justify-center rounded-lg\">\n                  <Zap className=\"size-4\" />\n                </div>\n                <CardTitle className=\"text-base font-semibold\">Webhook Event Simulator & Inspector</CardTitle>\n              </div>\n              <CardDescription className=\"text-xs\">\n                Trigger test events and verify signature headers against your endpoint.\n              </CardDescription>\n            </div>\n\n            <div className=\"flex items-center gap-2\">\n              <Badge variant=\"outline\" className=\"border-border bg-muted/50 font-mono text-xs\">\n                <span className=\"bg-success mr-1.5 inline-block size-2 animate-pulse rounded-full\" />\n                Ingress Ready\n              </Badge>\n            </div>\n          </div>\n        </CardHeader>\n\n        <CardContent className=\"pt-0\">\n          <div className=\"grid grid-cols-1 gap-3 md:grid-cols-12\">\n            {/* Endpoint URL Input */}\n            <div className=\"md:col-span-8 lg:col-span-9\">\n              <div className=\"relative flex items-center\">\n                <span className=\"text-muted-foreground pointer-events-none absolute left-3 flex items-center gap-1.5 font-mono text-xs\">\n                  <Globe className=\"size-3.5\" />\n                  <span className=\"text-foreground font-semibold\">POST</span>\n                </span>\n                <Input\n                  value={endpointUrl}\n                  onChange={(e) => setEndpointUrl(e.target.value)}\n                  placeholder=\"https://api.acme.dev/webhooks\"\n                  className=\"pl-20 font-mono text-xs\"\n                />\n              </div>\n            </div>\n\n            {/* Trigger Button */}\n            <div className=\"md:col-span-4 lg:col-span-3\">\n              <Button\n                size=\"default\"\n                className=\"w-full gap-2 text-xs font-medium shadow-xs\"\n                disabled={isSending || !endpointUrl}\n                onClick={sendWebhook}\n              >\n                {isSending ? (\n                  <span className=\"border-primary-foreground size-3.5 animate-spin rounded-full border-2 border-t-transparent\" />\n                ) : (\n                  <Send className=\"size-3.5\" />\n                )}\n                <span>{isSending ? 'Delivering...' : 'Send Test Webhook'}</span>\n                <kbd className=\"bg-primary-foreground/20 hidden rounded px-1 py-0.5 font-mono text-xs sm:inline-flex\">\n                  ⌘↵\n                </kbd>\n              </Button>\n            </div>\n          </div>\n        </CardContent>\n      </Card>\n\n      {/* 2-Column Inspector Layout */}\n      <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-12\">\n        {/* Left Panel: Event Payload Selector, JSON Editor & Signing Secret */}\n        <div className=\"space-y-6 lg:col-span-6\">\n          {/* Event Selector & Payload Schema Card */}\n          <Card className=\"border-border bg-card shadow-xs\">\n            <CardHeader className=\"pb-3\">\n              <div className=\"flex items-center justify-between\">\n                <div className=\"flex items-center gap-2\">\n                  <div className=\"bg-primary/10 text-primary flex size-7 items-center justify-center rounded-md\">\n                    <Layers className=\"size-4\" />\n                  </div>\n                  <div>\n                    <CardTitle className=\"text-sm font-semibold\">Event Configuration</CardTitle>\n                    <CardDescription className=\"text-xs\">\n                      Select event payload and adjust test parameters\n                    </CardDescription>\n                  </div>\n                </div>\n                <Badge variant=\"secondary\" className=\"font-mono text-xs\">\n                  {activePreset.category}\n                </Badge>\n              </div>\n            </CardHeader>\n\n            <CardContent className=\"space-y-4 pt-0\">\n              {/* Event Dropdown */}\n              <div className=\"space-y-1.5\">\n                <label className=\"text-foreground text-xs font-medium\">Event Type</label>\n                <Select value={selectedEvent} onValueChange={handleEventChange}>\n                  <SelectTrigger className=\"font-mono text-xs\">\n                    <SelectValue placeholder=\"Select event preset\" />\n                  </SelectTrigger>\n                  <SelectContent>\n                    {eventPresets.map((preset) => (\n                      <SelectItem key={preset.id} value={preset.id} className=\"font-mono text-xs\">\n                        {preset.name}\n                      </SelectItem>\n                    ))}\n                  </SelectContent>\n                </Select>\n                <p className=\"text-muted-foreground text-xs\">{activePreset.description}</p>\n              </div>\n\n              {/* Quick Selection Badges */}\n              <div className=\"flex flex-wrap items-center gap-1.5 pt-1\">\n                {eventPresets.map((preset) => (\n                  <button\n                    key={preset.id}\n                    type=\"button\"\n                    className={cn(\n                      'min-h-6 cursor-pointer rounded border px-2 py-0.5 font-mono text-xs transition-colors',\n                      selectedEvent === preset.id\n                        ? 'border-primary bg-primary/10 text-primary font-medium'\n                        : 'border-border bg-muted/30 text-muted-foreground hover:bg-muted hover:text-foreground',\n                    )}\n                    onClick={() => handleEventChange(preset.id)}\n                  >\n                    {preset.id}\n                  </button>\n                ))}\n              </div>\n\n              <Separator />\n\n              {/* JSON Payload Editor */}\n              <div className=\"space-y-2\">\n                <div className=\"flex items-center justify-between\">\n                  <label className=\"text-foreground flex items-center gap-1.5 text-xs font-medium\">\n                    <FileCode className=\"text-primary size-3.5\" />\n                    <span>Payload Body (JSON)</span>\n                  </label>\n\n                  <div className=\"flex items-center gap-1.5\">\n                    <Button\n                      variant=\"ghost\"\n                      size=\"sm\"\n                      className=\"text-muted-foreground hover:text-foreground h-7 px-2 text-xs\"\n                      onClick={handleFormatJson}\n                    >\n                      Format\n                    </Button>\n                    <Button\n                      variant=\"ghost\"\n                      size=\"sm\"\n                      className=\"text-muted-foreground hover:text-foreground h-7 px-2 text-xs\"\n                      onClick={handleResetPayload}\n                    >\n                      <RefreshCw className=\"mr-1 size-3\" />\n                      Reset\n                    </Button>\n                    <Button\n                      variant=\"ghost\"\n                      size=\"sm\"\n                      className=\"text-muted-foreground hover:text-foreground h-7 px-2 text-xs\"\n                      onClick={() => handleCopy(currentPayloadStr, 'payload')}\n                    >\n                      {copiedKey === 'payload' ? (\n                        <Check className=\"text-success mr-1 size-3\" />\n                      ) : (\n                        <Copy className=\"mr-1 size-3\" />\n                      )}\n                      <span>{copiedKey === 'payload' ? 'Copied' : 'Copy'}</span>\n                    </Button>\n                  </div>\n                </div>\n\n                <Textarea\n                  value={currentPayloadStr}\n                  onValueChange={setCurrentPayloadStr}\n                  rows={11}\n                  noResize\n                  className=\"border-border/70 focus:border-primary font-mono text-xs leading-relaxed\"\n                  placeholder='{\\n  \"type\": \"event.name\"\\n}'\n                />\n              </div>\n            </CardContent>\n\n            <CardFooter className=\"border-border text-muted-foreground flex items-center justify-between border-t pt-3 text-xs\">\n              <span className=\"font-mono\">{currentPayloadStr.length} bytes</span>\n              <span className=\"font-mono\">Content-Type: application/json</span>\n            </CardFooter>\n          </Card>\n\n          {/* Signing Secret & Signature Verification Preview Card */}\n          <Card className=\"border-border bg-card shadow-xs\">\n            <CardHeader className=\"pb-3\">\n              <div className=\"flex items-center justify-between\">\n                <div className=\"flex items-center gap-2\">\n                  <div className=\"bg-primary/10 text-primary flex size-7 items-center justify-center rounded-md\">\n                    <ShieldCheck className=\"size-4\" />\n                  </div>\n                  <div>\n                    <CardTitle className=\"text-sm font-semibold\">Signature & Security Headers</CardTitle>\n                    <CardDescription className=\"text-xs\">\n                      HMAC-SHA256 signature calculated from secret & timestamp\n                    </CardDescription>\n                  </div>\n                </div>\n                <div className=\"flex items-center gap-1\">\n                  <button\n                    type=\"button\"\n                    className={cn(\n                      'min-h-6 cursor-pointer rounded px-2 py-0.5 font-mono text-xs transition-colors',\n                      signatureFormat === 'stripe'\n                        ? 'bg-primary text-primary-foreground font-medium'\n                        : 'bg-muted text-muted-foreground hover:text-foreground',\n                    )}\n                    onClick={() => setSignatureFormat('stripe')}\n                  >\n                    Stripe\n                  </button>\n                  <button\n                    type=\"button\"\n                    className={cn(\n                      'min-h-6 cursor-pointer rounded px-2 py-0.5 font-mono text-xs transition-colors',\n                      signatureFormat === 'svix'\n                        ? 'bg-primary text-primary-foreground font-medium'\n                        : 'bg-muted text-muted-foreground hover:text-foreground',\n                    )}\n                    onClick={() => setSignatureFormat('svix')}\n                  >\n                    Svix Standard\n                  </button>\n                </div>\n              </div>\n            </CardHeader>\n\n            <CardContent className=\"space-y-4 pt-0\">\n              {/* Signing Secret Input */}\n              <div className=\"space-y-1.5\">\n                <div className=\"flex items-center justify-between\">\n                  <label className=\"text-foreground text-xs font-medium\">Endpoint Signing Secret</label>\n                  <button\n                    type=\"button\"\n                    className=\"text-primary flex min-h-6 cursor-pointer items-center gap-1 text-xs hover:underline\"\n                    onClick={handleRegenerateSecret}\n                  >\n                    <RotateCw className=\"size-3\" />\n                    <span>Regenerate</span>\n                  </button>\n                </div>\n                <div className=\"relative flex items-center\">\n                  <Key className=\"text-muted-foreground pointer-events-none absolute left-3 size-3.5\" />\n                  <Input\n                    value={signingSecret}\n                    onChange={(e) => setSigningSecret(e.target.value)}\n                    className=\"pr-16 pl-8 font-mono text-xs\"\n                    placeholder=\"whsec_...\"\n                  />\n                  <Button\n                    aria-label=\"Copy signing secret\"\n                    variant=\"ghost\"\n                    size=\"sm\"\n                    className=\"text-muted-foreground hover:text-foreground absolute right-1 h-7 px-2 text-xs\"\n                    onClick={() => handleCopy(signingSecret, 'secret')}\n                  >\n                    {copiedKey === 'secret' ? <Check className=\"text-success size-3\" /> : <Copy className=\"size-3\" />}\n                  </Button>\n                </div>\n              </div>\n\n              {/* Signature Header Box */}\n              <div className=\"space-y-1.5\">\n                <div className=\"flex items-center justify-between\">\n                  <label className=\"text-foreground text-xs font-medium\">Generated Request Headers</label>\n                  <Button\n                    variant=\"ghost\"\n                    size=\"sm\"\n                    className=\"text-muted-foreground hover:text-foreground h-6 px-2 text-xs\"\n                    onClick={() => handleCopy(computedAllHeaders, 'headers')}\n                  >\n                    {copiedKey === 'headers' ? (\n                      <Check className=\"text-success mr-1 size-3\" />\n                    ) : (\n                      <Copy className=\"mr-1 size-3\" />\n                    )}\n                    <span>{copiedKey === 'headers' ? 'Copied' : 'Copy Headers'}</span>\n                  </Button>\n                </div>\n                <pre className=\"border-border bg-muted/40 text-foreground overflow-x-auto rounded-md border p-3 font-mono text-xs leading-relaxed\">\n                  <code>{computedAllHeaders}</code>\n                </pre>\n              </div>\n            </CardContent>\n          </Card>\n        </div>\n\n        {/* Right Panel: Delivery History & Active Delivery Inspector */}\n        <div className=\"space-y-6 lg:col-span-6\">\n          {/* Recent Delivery Attempts List */}\n          <Card className=\"border-border bg-card shadow-xs\">\n            <CardHeader className=\"pb-3\">\n              <div className=\"flex items-center justify-between\">\n                <div className=\"flex items-center gap-2\">\n                  <div className=\"bg-primary/10 text-primary flex size-7 items-center justify-center rounded-md\">\n                    <Activity className=\"size-4\" />\n                  </div>\n                  <div>\n                    <CardTitle className=\"text-sm font-semibold\">Delivery History</CardTitle>\n                    <CardDescription className=\"text-xs\">Recent dispatch logs and response telemetry</CardDescription>\n                  </div>\n                </div>\n                <span className=\"text-muted-foreground font-mono text-xs\">{deliveryHistory.length} events logged</span>\n              </div>\n            </CardHeader>\n\n            <CardContent className=\"p-0\">\n              <div className=\"divide-border max-h-[250px] divide-y overflow-y-auto\">\n                {deliveryHistory.map((attempt) => (\n                  <div\n                    key={attempt.id}\n                    className={cn(\n                      'flex cursor-pointer items-center justify-between gap-3 p-3.5 text-xs transition-colors',\n                      selectedDeliveryId === attempt.id ? 'bg-muted/80 font-medium' : 'hover:bg-muted/40',\n                    )}\n                    onClick={() => setSelectedDeliveryId(attempt.id)}\n                  >\n                    <div className=\"flex min-w-0 items-center gap-2.5\">\n                      <Badge\n                        variant={attempt.status === 200 ? 'success' : 'destructive'}\n                        className=\"shrink-0 px-1.5 py-0.5 font-mono text-xs\"\n                      >\n                        {attempt.status}\n                      </Badge>\n                      <div className=\"min-w-0 truncate\">\n                        <p className=\"text-foreground truncate font-mono\">{attempt.eventType}</p>\n                        <p className=\"text-muted-foreground truncate font-mono text-xs\">{attempt.id}</p>\n                      </div>\n                    </div>\n\n                    <div className=\"flex shrink-0 items-center gap-3 text-right\">\n                      <span className=\"text-muted-foreground font-mono\">{attempt.latencyMs}ms</span>\n                      <span className=\"text-muted-foreground text-xs\">{attempt.timeAgo}</span>\n                      <ArrowRight className=\"text-muted-foreground size-3.5\" />\n                    </div>\n                  </div>\n                ))}\n              </div>\n            </CardContent>\n          </Card>\n\n          {/* Active Delivery Detail Inspector */}\n          <Card className=\"border-border bg-card shadow-xs\">\n            <CardHeader className=\"pb-3\">\n              <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n                <div className=\"space-y-1\">\n                  <div className=\"flex items-center gap-2\">\n                    <Badge\n                      variant={activeDelivery.status === 200 ? 'success' : 'destructive'}\n                      className=\"font-mono text-xs\"\n                    >\n                      {activeDelivery.status} {activeDelivery.statusText}\n                    </Badge>\n                    <span className=\"text-foreground font-mono text-xs font-semibold\">{activeDelivery.id}</span>\n                  </div>\n                  <p className=\"text-muted-foreground truncate font-mono text-xs\">{activeDelivery.endpointUrl}</p>\n                </div>\n\n                <div className=\"flex items-center gap-2\">\n                  <Button\n                    variant=\"outline\"\n                    size=\"sm\"\n                    className=\"h-8 gap-1.5 text-xs font-medium\"\n                    onClick={() => retryDelivery(activeDelivery)}\n                  >\n                    <RotateCw className=\"size-3.5\" />\n                    <span>Retry</span>\n                  </Button>\n                </div>\n              </div>\n            </CardHeader>\n\n            <CardContent className=\"pt-0\">\n              <Tabs value={activeInspectorTab} onValueChange={setActiveInspectorTab} className=\"w-full\">\n                <TabsList className=\"grid w-full grid-cols-3\">\n                  <TabsTrigger value=\"request\" className=\"text-xs\">\n                    Request\n                  </TabsTrigger>\n                  <TabsTrigger value=\"response\" className=\"text-xs\">\n                    Response\n                  </TabsTrigger>\n                  <TabsTrigger value=\"timings\" className=\"text-xs\">\n                    Diagnostics\n                  </TabsTrigger>\n                </TabsList>\n\n                {/* Request Tab */}\n                <TabsContent value=\"request\" className=\"space-y-4 pt-3\">\n                  {/* Request Headers Table */}\n                  <div className=\"space-y-1.5\">\n                    <div className=\"flex items-center justify-between\">\n                      <label className=\"text-foreground text-xs font-medium\">Request Headers</label>\n                      <Button\n                        variant=\"ghost\"\n                        size=\"sm\"\n                        className=\"text-muted-foreground hover:text-foreground h-6 px-2 text-xs\"\n                        onClick={() =>\n                          handleCopy(JSON.stringify(activeDelivery.requestHeaders, null, 2), 'req-headers')\n                        }\n                      >\n                        {copiedKey === 'req-headers' ? (\n                          <Check className=\"text-success mr-1 size-3\" />\n                        ) : (\n                          <Copy className=\"mr-1 size-3\" />\n                        )}\n                        <span>{copiedKey === 'req-headers' ? 'Copied' : 'Copy'}</span>\n                      </Button>\n                    </div>\n                    <div className=\"border-border bg-muted/20 overflow-hidden rounded-md border\">\n                      <Table>\n                        <TableHeader>\n                          <TableRow>\n                            <TableHead className=\"h-8 text-xs font-medium\">Header</TableHead>\n                            <TableHead className=\"h-8 text-xs font-medium\">Value</TableHead>\n                          </TableRow>\n                        </TableHeader>\n                        <TableBody>\n                          {Object.entries(activeDelivery.requestHeaders).map(([key, val]) => (\n                            <TableRow key={key}>\n                              <TableCell className=\"text-muted-foreground py-1.5 font-mono text-xs\">{key}</TableCell>\n                              <TableCell className=\"text-foreground max-w-[200px] truncate py-1.5 font-mono text-xs\">\n                                {val}\n                              </TableCell>\n                            </TableRow>\n                          ))}\n                        </TableBody>\n                      </Table>\n                    </div>\n                  </div>\n\n                  {/* Request Body */}\n                  <div className=\"space-y-1.5\">\n                    <div className=\"flex items-center justify-between\">\n                      <label className=\"text-foreground text-xs font-medium\">Request Body Payload</label>\n                      <Button\n                        variant=\"ghost\"\n                        size=\"sm\"\n                        className=\"text-muted-foreground hover:text-foreground h-6 px-2 text-xs\"\n                        onClick={() => handleCopy(activeDelivery.requestBody, 'req-body')}\n                      >\n                        {copiedKey === 'req-body' ? (\n                          <Check className=\"text-success mr-1 size-3\" />\n                        ) : (\n                          <Copy className=\"mr-1 size-3\" />\n                        )}\n                        <span>{copiedKey === 'req-body' ? 'Copied' : 'Copy'}</span>\n                      </Button>\n                    </div>\n                    <pre className=\"border-border bg-muted/40 text-foreground max-h-[220px] overflow-auto rounded-md border p-3 font-mono text-xs leading-relaxed\">\n                      <code>{activeDelivery.requestBody}</code>\n                    </pre>\n                  </div>\n                </TabsContent>\n\n                {/* Response Tab */}\n                <TabsContent value=\"response\" className=\"space-y-4 pt-3\">\n                  {/* Response Headers Table */}\n                  <div className=\"space-y-1.5\">\n                    <div className=\"flex items-center justify-between\">\n                      <label className=\"text-foreground text-xs font-medium\">Response Headers</label>\n                      <Button\n                        variant=\"ghost\"\n                        size=\"sm\"\n                        className=\"text-muted-foreground hover:text-foreground h-6 px-2 text-xs\"\n                        onClick={() =>\n                          handleCopy(JSON.stringify(activeDelivery.responseHeaders, null, 2), 'res-headers')\n                        }\n                      >\n                        {copiedKey === 'res-headers' ? (\n                          <Check className=\"text-success mr-1 size-3\" />\n                        ) : (\n                          <Copy className=\"mr-1 size-3\" />\n                        )}\n                        <span>{copiedKey === 'res-headers' ? 'Copied' : 'Copy'}</span>\n                      </Button>\n                    </div>\n                    <div className=\"border-border bg-muted/20 overflow-hidden rounded-md border\">\n                      <Table>\n                        <TableHeader>\n                          <TableRow>\n                            <TableHead className=\"h-8 text-xs font-medium\">Header</TableHead>\n                            <TableHead className=\"h-8 text-xs font-medium\">Value</TableHead>\n                          </TableRow>\n                        </TableHeader>\n                        <TableBody>\n                          {Object.entries(activeDelivery.responseHeaders).map(([key, val]) => (\n                            <TableRow key={key}>\n                              <TableCell className=\"text-muted-foreground py-1.5 font-mono text-xs\">{key}</TableCell>\n                              <TableCell className=\"text-foreground max-w-[200px] truncate py-1.5 font-mono text-xs\">\n                                {val}\n                              </TableCell>\n                            </TableRow>\n                          ))}\n                        </TableBody>\n                      </Table>\n                    </div>\n                  </div>\n\n                  {/* Response Body Payload */}\n                  <div className=\"space-y-1.5\">\n                    <div className=\"flex items-center justify-between\">\n                      <label className=\"text-foreground text-xs font-medium\">Response Body</label>\n                      <Button\n                        variant=\"ghost\"\n                        size=\"sm\"\n                        className=\"text-muted-foreground hover:text-foreground h-6 px-2 text-xs\"\n                        onClick={() => handleCopy(activeDelivery.responseBody, 'res-body')}\n                      >\n                        {copiedKey === 'res-body' ? (\n                          <Check className=\"text-success mr-1 size-3\" />\n                        ) : (\n                          <Copy className=\"mr-1 size-3\" />\n                        )}\n                        <span>{copiedKey === 'res-body' ? 'Copied' : 'Copy'}</span>\n                      </Button>\n                    </div>\n                    <pre\n                      className={cn(\n                        'max-h-[220px] overflow-auto rounded-md border p-3 font-mono text-xs leading-relaxed',\n                        activeDelivery.status === 200\n                          ? 'border-border bg-muted/40 text-foreground'\n                          : 'border-destructive/30 bg-destructive/10 text-destructive',\n                      )}\n                    >\n                      <code>{activeDelivery.responseBody}</code>\n                    </pre>\n                  </div>\n                </TabsContent>\n\n                {/* Diagnostics & Timeline Tab */}\n                <TabsContent value=\"timings\" className=\"space-y-4 pt-3\">\n                  <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-4\">\n                    <div className=\"border-border bg-muted/30 rounded-lg border p-2.5 text-center\">\n                      <p className=\"text-muted-foreground text-xs\">DNS Lookup</p>\n                      <p className=\"text-foreground font-mono text-sm font-semibold\">{activeDelivery.timings.dns}ms</p>\n                    </div>\n                    <div className=\"border-border bg-muted/30 rounded-lg border p-2.5 text-center\">\n                      <p className=\"text-muted-foreground text-xs\">TLS Handshake</p>\n                      <p className=\"text-foreground font-mono text-sm font-semibold\">{activeDelivery.timings.tls}ms</p>\n                    </div>\n                    <div className=\"border-border bg-muted/30 rounded-lg border p-2.5 text-center\">\n                      <p className=\"text-muted-foreground text-xs\">Server TTFB</p>\n                      <p className=\"text-foreground font-mono text-sm font-semibold\">{activeDelivery.timings.ttfb}ms</p>\n                    </div>\n                    <div className=\"border-border bg-muted/30 rounded-lg border p-2.5 text-center\">\n                      <p className=\"text-muted-foreground text-xs\">Total Roundtrip</p>\n                      <p className=\"text-primary font-mono text-sm font-semibold\">{activeDelivery.timings.total}ms</p>\n                    </div>\n                  </div>\n\n                  <div className=\"border-border bg-muted/20 space-y-2 rounded-lg border p-3\">\n                    <h4 className=\"text-foreground text-xs font-semibold\">Security & Delivery Verification</h4>\n                    <ul className=\"space-y-1.5 text-xs\">\n                      <li className=\"text-success flex items-center gap-2\">\n                        <CheckCircle2 className=\"size-3.5 shrink-0\" />\n                        <span>HMAC signature matched endpoint verification secret</span>\n                      </li>\n                      <li className=\"text-success flex items-center gap-2\">\n                        <CheckCircle2 className=\"size-3.5 shrink-0\" />\n                        <span>TLS 1.3 certificate chain verified (Cloudflare Inc)</span>\n                      </li>\n                      <li className=\"text-success flex items-center gap-2\">\n                        <CheckCircle2 className=\"size-3.5 shrink-0\" />\n                        <span>Timestamp within tolerance envelope (300s window)</span>\n                      </li>\n                    </ul>\n                  </div>\n                </TabsContent>\n              </Tabs>\n            </CardContent>\n\n            <CardFooter className=\"border-border text-muted-foreground flex items-center justify-between border-t pt-3 text-xs\">\n              <span className=\"flex items-center gap-1.5\">\n                <Clock className=\"size-3.5\" />\n                <span>Dispatched at: {activeDelivery.timestamp}</span>\n              </span>\n              <span className=\"font-mono\">Latency: {activeDelivery.latencyMs}ms</span>\n            </CardFooter>\n          </Card>\n        </div>\n      </div>\n    </div>\n  )\n}\n",
      "type": "registry:block",
      "target": "~/components/blocks/WebhookTester.tsx"
    }
  ],
  "dependencies": [
    "lucide-react"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/react/badge.json",
    "https://uipkge.dev/r/react/button.json",
    "https://uipkge.dev/r/react/card.json",
    "https://uipkge.dev/r/react/input.json",
    "https://uipkge.dev/r/react/select.json",
    "https://uipkge.dev/r/react/separator.json",
    "https://uipkge.dev/r/react/table.json",
    "https://uipkge.dev/r/react/tabs.json",
    "https://uipkge.dev/r/react/textarea.json"
  ],
  "description": "Svix and Stripe style live webhook delivery inspector and event simulator with signature generation, payload editor, and request/response inspection.",
  "categories": [
    "devops",
    "api",
    "app",
    "developer"
  ]
}