{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "secrets-rotation-scheduler",
  "title": "Secrets Rotation Scheduler",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/secrets-rotation-scheduler/SecretsRotationScheduler.vue",
      "content": "<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\nimport type { HTMLAttributes } from 'vue'\nimport {\n  AlertCircle,\n  AlertTriangle,\n  ArrowRight,\n  Calendar,\n  Check,\n  CheckCircle2,\n  Clock,\n  Copy,\n  Database,\n  Globe,\n  Info,\n  KeyRound,\n  Lock,\n  MoreHorizontal,\n  Pause,\n  Pencil,\n  Play,\n  Plus,\n  RefreshCw,\n  Search,\n  Server,\n  ShieldAlert,\n  ShieldCheck,\n  Terminal,\n  X,\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  Dialog,\n  DialogContent,\n  DialogDescription,\n  DialogFooter,\n  DialogHeader,\n  DialogTitle,\n} from '@/components/ui/dialog'\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuLabel,\n  DropdownMenuSeparator,\n  DropdownMenuTrigger,\n} from '@/components/ui/dropdown-menu'\nimport { Input } from '@/components/ui/input'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'\n\nexport type SecretType = 'Postgres DB' | 'API Key' | 'RSA Keypair' | 'KMS Key' | 'Redis Auth' | 'MySQL DB'\nexport type RotationStatus = 'healthy' | 'due-soon' | 'manual-needed' | 'paused' | 'rotating'\n\nexport interface RotationSchedule {\n  interval: string\n  daysInterval: number\n  lambdaArn?: string\n  zeroDowntimeVerified: boolean\n}\n\nexport interface ManagedSecret {\n  id: string\n  name: string\n  arn: string\n  type: SecretType\n  schedule: RotationSchedule\n  lastRotated: string\n  nextRotationDue: string\n  dueRelative: string\n  status: RotationStatus\n  currentVersion: string\n  stagingVersion?: string\n  lastLogSnippet?: string\n}\n\nexport interface SecretsRotationStats {\n  totalSecrets: number\n  autoRotationActive: number\n  autoRotationPercentage: number\n  dueSoonCount: number\n  overdueCount: number\n}\n\ninterface Props {\n  initialSecrets?: ManagedSecret[]\n  initialStats?: SecretsRotationStats\n  class?: HTMLAttributes['class']\n}\n\nconst defaultSecrets: ManagedSecret[] = [\n  {\n    id: 'sec-1',\n    name: 'prod/postgres/master-credentials',\n    arn: 'arn:aws:secretsmanager:us-east-1:182938491029:secret:prod/postgres/master-cred-9aF1x',\n    type: 'Postgres DB',\n    schedule: {\n      interval: 'Every 30 Days',\n      daysInterval: 30,\n      lambdaArn: 'arn:aws:lambda:us-east-1:182938491029:function:RotatePostgresMaster',\n      zeroDowntimeVerified: true,\n    },\n    lastRotated: 'Aug 10, 2026',\n    nextRotationDue: 'Sep 09, 2026',\n    dueRelative: 'in 19 days',\n    status: 'healthy',\n    currentVersion: 'v2.4 (AWSCURRENT)',\n    stagingVersion: 'v2.5 (AWSPENDING)',\n    lastLogSnippet:\n      'Postgres dual-user handshake verified. Master role privileges synchronized with 0 connection terminations.',\n  },\n  {\n    id: 'sec-2',\n    name: 'prod/stripe/webhook-secret',\n    arn: 'arn:aws:secretsmanager:us-east-1:182938491029:secret:prod/stripe/wh-sec-48k2p',\n    type: 'API Key',\n    schedule: {\n      interval: 'Every 90 Days',\n      daysInterval: 90,\n      lambdaArn: 'arn:aws:lambda:us-east-1:182938491029:function:RotateStripeWebhook',\n      zeroDowntimeVerified: true,\n    },\n    lastRotated: 'Jul 14, 2026',\n    nextRotationDue: 'Aug 22, 2026',\n    dueRelative: 'in 24 hours',\n    status: 'due-soon',\n    currentVersion: 'v1.8 (AWSCURRENT)',\n    stagingVersion: 'v1.9 (AWSPENDING)',\n    lastLogSnippet: 'Dual webhook signature validation window active. Webhook endpoint test passed with 200 OK.',\n  },\n  {\n    id: 'sec-3',\n    name: 'prod/jwt/signing-key-rsa',\n    arn: 'arn:aws:secretsmanager:us-east-1:182938491029:secret:prod/jwt/rsa-pair-71b3e',\n    type: 'RSA Keypair',\n    schedule: {\n      interval: 'Every 7 Days',\n      daysInterval: 7,\n      lambdaArn: 'arn:aws:lambda:us-east-1:182938491029:function:RotateJWTRSAKeys',\n      zeroDowntimeVerified: true,\n    },\n    lastRotated: 'Aug 18, 2026',\n    nextRotationDue: 'Aug 25, 2026',\n    dueRelative: 'in 4 days',\n    status: 'healthy',\n    currentVersion: 'v9.1 (AWSCURRENT)',\n    stagingVersion: 'v9.2 (AWSPENDING)',\n    lastLogSnippet:\n      'JWKS endpoint updated with secondary public key kid:rsa-2026-w34. Token signature verification succeeded.',\n  },\n  {\n    id: 'sec-4',\n    name: 'prod/aws/kms-envelope-key',\n    arn: 'arn:aws:kms:us-east-1:182938491029:key/mrk-8492019a-9e1b-4f21-99ad',\n    type: 'KMS Key',\n    schedule: {\n      interval: 'Every 365 Days',\n      daysInterval: 365,\n      lambdaArn: 'arn:aws:lambda:us-east-1:182938491029:function:KmsEnvelopeRotationHandler',\n      zeroDowntimeVerified: true,\n    },\n    lastRotated: 'Oct 01, 2025',\n    nextRotationDue: 'Oct 01, 2026',\n    dueRelative: 'in 41 days',\n    status: 'healthy',\n    currentVersion: 'v3.0 (AWSCURRENT)',\n    stagingVersion: 'v3.1 (AWSPENDING)',\n    lastLogSnippet:\n      'Hardware Security Module (HSM) backing key refreshed. Transparent decryption verified for existing ciphertexts.',\n  },\n  {\n    id: 'sec-5',\n    name: 'prod/redis/cache-auth',\n    arn: 'arn:aws:secretsmanager:us-east-1:182938491029:secret:prod/redis/auth-token-6c90d',\n    type: 'Redis Auth',\n    schedule: {\n      interval: 'Manual Only',\n      daysInterval: 0,\n      zeroDowntimeVerified: false,\n    },\n    lastRotated: 'May 12, 2026',\n    nextRotationDue: 'Aug 20, 2026',\n    dueRelative: 'Overdue (1 day)',\n    status: 'manual-needed',\n    currentVersion: 'v1.0 (AWSCURRENT)',\n    stagingVersion: undefined,\n    lastLogSnippet:\n      'Automated lambda execution unconfigured. Dual-AUTH token rotation requires manual trigger or handler attachment.',\n  },\n]\n\nconst props = defineProps<Props>()\n\nconst stats = computed(\n  () =>\n    props.initialStats ?? {\n      totalSecrets: 18,\n      autoRotationActive: 15,\n      autoRotationPercentage: 83.3,\n      dueSoonCount: 2,\n      overdueCount: 0,\n    },\n)\n\nconst secrets = ref<ManagedSecret[]>([...(props.initialSecrets ?? defaultSecrets)])\nconst search = ref('')\nconst statusFilter = ref<string>('all')\nconst bannerMessage = ref<{ type: 'success' | 'info'; text: string } | null>(null)\nconst rotatingSecretId = ref<string | null>(null)\nconst copiedArn = ref<string | null>(null)\n\n// Dialogs state\nconst isRotateModalOpen = ref(false)\nconst selectedSecretForRotate = ref<ManagedSecret | null>(null)\nconst isRotatingInProgress = ref(false)\n\nconst isScheduleModalOpen = ref(false)\nconst editingSecret = ref<ManagedSecret | null>(null)\nconst formName = ref('')\nconst formArn = ref('')\nconst formType = ref<SecretType>('Postgres DB')\nconst formInterval = ref('Every 30 Days')\nconst formLambdaArn = ref('')\nconst formZeroDowntime = ref(true)\n\nconst isLogsModalOpen = ref(false)\nconst selectedSecretForLogs = ref<ManagedSecret | null>(null)\n\nconst filteredSecrets = computed(() => {\n  const q = search.value.trim().toLowerCase()\n  return secrets.value.filter((sec) => {\n    const matchesStatus =\n      statusFilter.value === 'all' ||\n      sec.status === statusFilter.value ||\n      (statusFilter.value === 'healthy' && sec.status === 'healthy') ||\n      (statusFilter.value === 'due-soon' && sec.status === 'due-soon') ||\n      (statusFilter.value === 'manual-needed' && sec.status === 'manual-needed') ||\n      (statusFilter.value === 'paused' && sec.status === 'paused')\n\n    const matchesSearch =\n      !q ||\n      sec.name.toLowerCase().includes(q) ||\n      sec.arn.toLowerCase().includes(q) ||\n      sec.type.toLowerCase().includes(q)\n\n    return matchesStatus && matchesSearch\n  })\n})\n\nasync function copyToClipboard(text: string, id: string) {\n  try {\n    await navigator.clipboard.writeText(text)\n    copiedArn.value = id\n    setTimeout(() => {\n      copiedArn.value = null\n    }, 2000)\n  } catch {\n    copiedArn.value = id\n    setTimeout(() => {\n      copiedArn.value = null\n    }, 2000)\n  }\n}\n\nfunction openInstantRotate(secret: ManagedSecret) {\n  selectedSecretForRotate.value = secret\n  isRotateModalOpen.value = true\n}\n\nfunction executeRotation() {\n  if (!selectedSecretForRotate.value) return\n  isRotatingInProgress.value = true\n  const targetId = selectedSecretForRotate.value.id\n  rotatingSecretId.value = targetId\n\n  setTimeout(() => {\n    isRotatingInProgress.value = false\n    isRotateModalOpen.value = false\n    rotatingSecretId.value = null\n\n    const idx = secrets.value.findIndex((s) => s.id === targetId)\n    if (idx !== -1) {\n      secrets.value[idx] = {\n        ...secrets.value[idx],\n        lastRotated: 'Just now',\n        nextRotationDue: 'Sep 20, 2026',\n        dueRelative: 'in 30 days',\n        status: 'healthy',\n        currentVersion: 'v2.5 (AWSCURRENT)',\n        stagingVersion: undefined,\n        lastLogSnippet:\n          'Zero-downtime rotation completed successfully. Version B verified, promoted to AWSCURRENT, and staged safely.',\n      }\n    }\n\n    bannerMessage.value = {\n      type: 'success',\n      text: `Zero-downtime rotation successfully completed for \"${selectedSecretForRotate.value?.name}\". Credentials validated with 0 dropped sockets.`,\n    }\n  }, 1400)\n}\n\nfunction openScheduleModal(secret?: ManagedSecret) {\n  if (secret) {\n    editingSecret.value = secret\n    formName.value = secret.name\n    formArn.value = secret.arn\n    formType.value = secret.type\n    formInterval.value = secret.schedule.interval\n    formLambdaArn.value = secret.schedule.lambdaArn || ''\n    formZeroDowntime.value = secret.schedule.zeroDowntimeVerified\n  } else {\n    editingSecret.value = null\n    formName.value = ''\n    formArn.value = ''\n    formType.value = 'Postgres DB'\n    formInterval.value = 'Every 30 Days'\n    formLambdaArn.value = 'arn:aws:lambda:us-east-1:182938491029:function:RotateSecretHandler'\n    formZeroDowntime.value = true\n  }\n  isScheduleModalOpen.value = true\n}\n\nfunction saveSchedule() {\n  if (!formName.value.trim()) return\n\n  if (editingSecret.value) {\n    const idx = secrets.value.findIndex((s) => s.id === editingSecret.value?.id)\n    if (idx !== -1) {\n      secrets.value[idx] = {\n        ...secrets.value[idx],\n        name: formName.value.trim(),\n        arn: formArn.value.trim() || secrets.value[idx].arn,\n        type: formType.value,\n        schedule: {\n          ...secrets.value[idx].schedule,\n          interval: formInterval.value,\n          lambdaArn: formLambdaArn.value.trim() || undefined,\n          zeroDowntimeVerified: formZeroDowntime.value,\n        },\n      }\n    }\n    bannerMessage.value = {\n      type: 'info',\n      text: `Rotation schedule for \"${formName.value}\" updated successfully.`,\n    }\n  } else {\n    const newId = `sec-${Date.now()}`\n    const generatedArn =\n      formArn.value.trim() ||\n      `arn:aws:secretsmanager:us-east-1:182938491029:secret:${formName.value.trim().toLowerCase()}-${Math.random().toString(36).substring(2, 7)}`\n\n    const newSecret: ManagedSecret = {\n      id: newId,\n      name: formName.value.trim(),\n      arn: generatedArn,\n      type: formType.value,\n      schedule: {\n        interval: formInterval.value,\n        daysInterval: formInterval.value.includes('7') ? 7 : formInterval.value.includes('90') ? 90 : 30,\n        lambdaArn: formLambdaArn.value.trim() || undefined,\n        zeroDowntimeVerified: formZeroDowntime.value,\n      },\n      lastRotated: 'Never (Initial)',\n      nextRotationDue: 'Pending First Run',\n      dueRelative: 'in 2 hours',\n      status: 'healthy',\n      currentVersion: 'v1.0 (AWSCURRENT)',\n      stagingVersion: undefined,\n      lastLogSnippet: 'Initial rotation schedule registered with automated zero-downtime dual-version handshake.',\n    }\n    secrets.value.unshift(newSecret)\n    bannerMessage.value = {\n      type: 'success',\n      text: `New secret rotation schedule registered for \"${newSecret.name}\".`,\n    }\n  }\n  isScheduleModalOpen.value = false\n}\n\nfunction togglePause(secret: ManagedSecret) {\n  const nextStatus: RotationStatus = secret.status === 'paused' ? 'healthy' : 'paused'\n  secret.status = nextStatus\n  bannerMessage.value = {\n    type: 'info',\n    text: `Rotation schedule for \"${secret.name}\" ${nextStatus === 'paused' ? 'paused' : 'resumed'}.`,\n  }\n}\n\nfunction openLogsModal(secret: ManagedSecret) {\n  selectedSecretForLogs.value = secret\n  isLogsModalOpen.value = true\n}\n\nfunction getTypeBadgeVariant(type: SecretType): 'default' | 'secondary' | 'outline' | 'info' | 'warning' {\n  switch (type) {\n    case 'Postgres DB':\n    case 'MySQL DB':\n      return 'info'\n    case 'API Key':\n      return 'secondary'\n    case 'RSA Keypair':\n      return 'outline'\n    case 'KMS Key':\n      return 'default'\n    case 'Redis Auth':\n      return 'warning'\n    default:\n      return 'outline'\n  }\n}\n</script>\n\n<template>\n  <div data-slot=\"secrets-rotation-scheduler\" :class=\"cn('w-full space-y-6', props.class)\">\n    <!-- Header -->\n    <div 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 items-center gap-2\">\n          <div class=\"bg-primary/10 text-primary flex size-8 items-center justify-center rounded-lg\">\n            <Lock class=\"size-4.5\" />\n          </div>\n          <h1 class=\"text-foreground text-2xl font-bold tracking-tight\">Automated Secrets Rotation & Key Lifecycle</h1>\n        </div>\n        <p class=\"text-muted-foreground text-sm\">\n          Configure zero-downtime rotation schedules for database credentials, API keys, and certificates.\n        </p>\n      </div>\n\n      <div class=\"flex items-center gap-2\">\n        <Button @click=\"openScheduleModal()\">\n          <Plus class=\"mr-1.5 size-4\" />\n          Schedule New Rotation\n        </Button>\n      </div>\n    </div>\n\n    <!-- Notification / Action banner -->\n    <div\n      v-if=\"bannerMessage\"\n      class=\"border-border bg-card flex items-center justify-between gap-3 rounded-lg border p-3 shadow-xs\"\n    >\n      <div class=\"flex items-center gap-2.5 text-sm\">\n        <CheckCircle2 v-if=\"bannerMessage.type === 'success'\" class=\"text-success size-4 shrink-0\" />\n        <Info v-else class=\"text-primary size-4 shrink-0\" />\n        <span class=\"text-foreground font-medium\">{{ bannerMessage.text }}</span>\n      </div>\n      <Button variant=\"ghost\" size=\"icon\" class=\"size-7\" @click=\"bannerMessage = null\">\n        <X class=\"size-3.5\" />\n        <span class=\"sr-only\">Dismiss</span>\n      </Button>\n    </div>\n\n    <!-- 4 Key Lifecycle Telemetry Cards -->\n    <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n      <!-- Total Managed Secrets -->\n      <Card class=\"shadow-xs\">\n        <CardHeader class=\"flex flex-row items-center justify-between pb-2\">\n          <CardTitle class=\"text-muted-foreground text-sm font-medium\">Total Managed Secrets</CardTitle>\n          <div class=\"bg-primary/10 text-primary rounded-lg p-2\">\n            <KeyRound class=\"size-4\" />\n          </div>\n        </CardHeader>\n        <CardContent class=\"space-y-1\">\n          <div class=\"text-foreground text-2xl font-bold tracking-tight\">{{ stats.totalSecrets }} credentials</div>\n          <p class=\"text-muted-foreground text-xs\">Across 4 cloud regions</p>\n        </CardContent>\n      </Card>\n\n      <!-- Auto-Rotation Active -->\n      <Card class=\"shadow-xs\">\n        <CardHeader class=\"flex flex-row items-center justify-between pb-2\">\n          <CardTitle class=\"text-muted-foreground text-sm font-medium\">Auto-Rotation Active</CardTitle>\n          <div class=\"bg-success/10 text-success rounded-lg p-2\">\n            <RefreshCw class=\"size-4\" />\n          </div>\n        </CardHeader>\n        <CardContent class=\"space-y-1\">\n          <div class=\"flex items-center gap-2\">\n            <span class=\"text-foreground text-2xl font-bold tracking-tight\">\n              {{ stats.autoRotationActive }} / {{ stats.totalSecrets }} secrets\n            </span>\n            <Badge variant=\"success\" class=\"text-xs\"> {{ stats.autoRotationPercentage }}% </Badge>\n          </div>\n          <p class=\"text-muted-foreground text-xs\">Zero-downtime dual versioning enabled</p>\n        </CardContent>\n      </Card>\n\n      <!-- Rotation Due Soon -->\n      <Card class=\"border-warning/30 bg-warning/5 bg-warning/10 shadow-xs\">\n        <CardHeader class=\"flex flex-row items-center justify-between pb-2\">\n          <CardTitle class=\"text-warning text-sm font-medium\">Rotation Due Soon</CardTitle>\n          <div class=\"bg-warning/20 text-warning rounded-lg p-2\">\n            <Clock class=\"size-4\" />\n          </div>\n        </CardHeader>\n        <CardContent class=\"space-y-1\">\n          <div class=\"flex items-center gap-2\">\n            <span class=\"text-warning text-2xl font-bold tracking-tight\"> {{ stats.dueSoonCount }} secrets </span>\n            <Badge variant=\"warning\" class=\"text-xs\">Next 48h</Badge>\n          </div>\n          <p class=\"text-warning/90 text-xs\">Automated queue pre-scheduled</p>\n        </CardContent>\n      </Card>\n\n      <!-- Expired / Overdue -->\n      <Card class=\"shadow-xs\">\n        <CardHeader class=\"flex flex-row items-center justify-between pb-2\">\n          <CardTitle class=\"text-muted-foreground text-sm font-medium\">Expired / Overdue</CardTitle>\n          <div class=\"bg-success/10 text-success rounded-lg p-2\">\n            <ShieldCheck class=\"size-4\" />\n          </div>\n        </CardHeader>\n        <CardContent class=\"space-y-1\">\n          <div class=\"flex items-center gap-2\">\n            <span class=\"text-foreground text-2xl font-bold tracking-tight\">\n              {{ stats.overdueCount }} critical overdue\n            </span>\n            <Badge variant=\"outline\" class=\"text-xs\">Compliant</Badge>\n          </div>\n          <p class=\"text-muted-foreground text-xs\">Zero security compliance violations</p>\n        </CardContent>\n      </Card>\n    </div>\n\n    <!-- Secrets Rotation Table Card -->\n    <Card class=\"shadow-xs\">\n      <CardHeader class=\"pb-3\">\n        <div class=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n          <div>\n            <CardTitle class=\"text-lg font-semibold\">Managed Secrets & Automated Rotation</CardTitle>\n            <CardDescription class=\"text-xs\">\n              {{ filteredSecrets.length }} of {{ secrets.length }} cryptographic secrets configured for automated\n              lifecycle management.\n            </CardDescription>\n          </div>\n\n          <div class=\"flex flex-wrap items-center gap-2\">\n            <div class=\"relative w-full min-w-0 sm:w-64\">\n              <Search\n                class=\"text-muted-foreground pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2\"\n              />\n              <Input v-model=\"search\" placeholder=\"Search secrets or ARN\" class=\"h-8 pl-9 text-xs\" />\n            </div>\n\n            <Select v-model=\"statusFilter\">\n              <SelectTrigger class=\"h-8 w-36 text-xs\">\n                <SelectValue placeholder=\"All Statuses\" />\n              </SelectTrigger>\n              <SelectContent>\n                <SelectItem value=\"all\">All Statuses</SelectItem>\n                <SelectItem value=\"healthy\">Automated · Healthy</SelectItem>\n                <SelectItem value=\"due-soon\">Due Soon (&lt;48h)</SelectItem>\n                <SelectItem value=\"manual-needed\">Manual Needed</SelectItem>\n                <SelectItem value=\"paused\">Paused</SelectItem>\n              </SelectContent>\n            </Select>\n\n            <Badge variant=\"outline\" class=\"hidden h-8 items-center gap-1 font-mono text-xs md:inline-flex\">\n              <Globe class=\"size-3\" />\n              AWS us-east-1\n            </Badge>\n          </div>\n        </div>\n      </CardHeader>\n\n      <CardContent class=\"p-0\">\n        <div class=\"overflow-x-auto\">\n          <Table>\n            <TableHeader>\n              <TableRow class=\"hover:bg-transparent\">\n                <TableHead class=\"min-w-[260px]\">Secret Name & ARN Identifier</TableHead>\n                <TableHead class=\"min-w-[130px]\">Secret Type</TableHead>\n                <TableHead class=\"min-w-[170px]\">Rotation Interval</TableHead>\n                <TableHead class=\"min-w-[200px]\">Last Rotated & Next Due</TableHead>\n                <TableHead class=\"min-w-[170px]\">Rotation Status</TableHead>\n                <TableHead class=\"w-16 text-right\">Actions</TableHead>\n              </TableRow>\n            </TableHeader>\n            <TableBody>\n              <TableRow v-for=\"secret in filteredSecrets\" :key=\"secret.id\" class=\"group transition-colors\">\n                <!-- Secret Name & ARN Identifier -->\n                <TableCell class=\"py-3.5\">\n                  <div class=\"space-y-1\">\n                    <div class=\"flex items-center gap-1.5\">\n                      <span class=\"text-foreground text-sm font-medium\">{{ secret.name }}</span>\n                      <RefreshCw\n                        v-if=\"rotatingSecretId === secret.id\"\n                        class=\"text-primary size-3.5 animate-spin\"\n                        aria-label=\"Rotating now\"\n                      />\n                    </div>\n                    <div class=\"flex items-center gap-1.5\">\n                      <code\n                        class=\"text-muted-foreground max-w-[260px] truncate font-mono text-xs sm:max-w-[320px]\"\n                        :title=\"secret.arn\"\n                      >\n                        {{ secret.arn }}\n                      </code>\n                      <button\n                        type=\"button\"\n                        class=\"text-muted-foreground hover:text-foreground inline-flex size-4 shrink-0 items-center justify-center transition-colors\"\n                        :aria-label=\"'Copy ARN for ' + secret.name\"\n                        @click=\"copyToClipboard(secret.arn, secret.id)\"\n                      >\n                        <Check v-if=\"copiedArn === secret.id\" class=\"text-success size-3\" />\n                        <Copy v-else class=\"size-3\" />\n                      </button>\n                    </div>\n                  </div>\n                </TableCell>\n\n                <!-- Secret Type Badge -->\n                <TableCell class=\"py-3.5\">\n                  <Badge :variant=\"getTypeBadgeVariant(secret.type)\" class=\"gap-1 text-xs\">\n                    <Database v-if=\"secret.type === 'Postgres DB' || secret.type === 'MySQL DB'\" class=\"size-3\" />\n                    <KeyRound v-else-if=\"secret.type === 'API Key'\" class=\"size-3\" />\n                    <ShieldCheck v-else-if=\"secret.type === 'RSA Keypair'\" class=\"size-3\" />\n                    <Lock v-else-if=\"secret.type === 'KMS Key'\" class=\"size-3\" />\n                    <Server v-else-if=\"secret.type === 'Redis Auth'\" class=\"size-3\" />\n                    {{ secret.type }}\n                  </Badge>\n                </TableCell>\n\n                <!-- Rotation Interval -->\n                <TableCell class=\"py-3.5\">\n                  <div class=\"space-y-0.5\">\n                    <div class=\"flex items-center gap-1.5 text-xs font-medium\">\n                      <Clock class=\"text-muted-foreground size-3.5 shrink-0\" />\n                      <span class=\"text-foreground\">{{ secret.schedule.interval }}</span>\n                    </div>\n                    <p\n                      v-if=\"secret.schedule.lambdaArn\"\n                      class=\"text-muted-foreground max-w-[160px] truncate font-mono text-xs\"\n                      :title=\"secret.schedule.lambdaArn\"\n                    >\n                      λ {{ secret.schedule.lambdaArn.split(':function:')[1] || 'Lambda' }}\n                    </p>\n                    <p v-else class=\"text-muted-foreground font-mono text-xs\">Manual trigger</p>\n                  </div>\n                </TableCell>\n\n                <!-- Last Rotated & Next Due -->\n                <TableCell class=\"py-3.5\">\n                  <div class=\"space-y-0.5 text-xs\">\n                    <div class=\"text-foreground font-medium\">\n                      {{ secret.nextRotationDue }}\n                      <span v-if=\"secret.status === 'due-soon'\" class=\"text-warning font-semibold\">\n                        ({{ secret.dueRelative }})\n                      </span>\n                      <span v-else class=\"text-muted-foreground\"> ({{ secret.dueRelative }}) </span>\n                    </div>\n                    <p class=\"text-muted-foreground text-xs\">\n                      Last: <span class=\"font-mono\">{{ secret.lastRotated }}</span>\n                    </p>\n                  </div>\n                </TableCell>\n\n                <!-- Rotation Status Badge -->\n                <TableCell class=\"py-3.5\">\n                  <div class=\"space-y-1\">\n                    <Badge v-if=\"secret.status === 'healthy'\" variant=\"success\" class=\"gap-1 text-xs\">\n                      <span class=\"bg-success size-1.5 animate-pulse rounded-full\" />\n                      Automated · Healthy\n                    </Badge>\n                    <Badge v-else-if=\"secret.status === 'due-soon'\" variant=\"warning\" class=\"gap-1 text-xs\">\n                      <Clock class=\"size-3\" />\n                      Rotation Due Soon\n                    </Badge>\n                    <Badge v-else-if=\"secret.status === 'manual-needed'\" variant=\"warning\" class=\"gap-1 text-xs\">\n                      <AlertTriangle class=\"size-3\" />\n                      Manual Rotation Needed\n                    </Badge>\n                    <Badge v-else-if=\"secret.status === 'paused'\" variant=\"secondary\" class=\"gap-1 text-xs\">\n                      <Pause class=\"size-3\" />\n                      Paused\n                    </Badge>\n                    <Badge v-else variant=\"outline\" class=\"gap-1 text-xs\">\n                      <RefreshCw class=\"size-3 animate-spin\" />\n                      Rotating\n                    </Badge>\n\n                    <div class=\"text-muted-foreground font-mono text-xs\">\n                      {{ secret.currentVersion }}\n                    </div>\n                  </div>\n                </TableCell>\n\n                <!-- Actions Menu -->\n                <TableCell class=\"py-3.5 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 actions menu</span>\n                      </Button>\n                    </DropdownMenuTrigger>\n                    <DropdownMenuContent align=\"end\" class=\"w-56\">\n                      <DropdownMenuLabel class=\"text-xs\">Rotation Controls</DropdownMenuLabel>\n                      <DropdownMenuSeparator />\n                      <DropdownMenuItem class=\"cursor-pointer\" @click=\"openInstantRotate(secret)\">\n                        <Play class=\"text-success mr-2 size-4\" />\n                        <span>Rotate Now (Zero Downtime)</span>\n                      </DropdownMenuItem>\n                      <DropdownMenuItem class=\"cursor-pointer\" @click=\"openScheduleModal(secret)\">\n                        <Pencil class=\"mr-2 size-4\" />\n                        <span>Edit Schedule</span>\n                      </DropdownMenuItem>\n                      <DropdownMenuItem class=\"cursor-pointer\" @click=\"openLogsModal(secret)\">\n                        <Terminal class=\"mr-2 size-4\" />\n                        <span>View Rotation Lambda Log</span>\n                      </DropdownMenuItem>\n                      <DropdownMenuSeparator />\n                      <DropdownMenuItem class=\"cursor-pointer\" @click=\"togglePause(secret)\">\n                        <Pause v-if=\"secret.status !== 'paused'\" class=\"mr-2 size-4\" />\n                        <Play v-else class=\"text-success mr-2 size-4\" />\n                        <span>{{ secret.status !== 'paused' ? 'Pause Auto-Rotation' : 'Resume Auto-Rotation' }}</span>\n                      </DropdownMenuItem>\n                    </DropdownMenuContent>\n                  </DropdownMenu>\n                </TableCell>\n              </TableRow>\n\n              <TableRow v-if=\"filteredSecrets.length === 0\">\n                <TableCell colspan=\"6\" class=\"text-muted-foreground h-32 text-center text-sm\">\n                  No secrets found matching the selected filter criteria.\n                </TableCell>\n              </TableRow>\n            </TableBody>\n          </Table>\n        </div>\n      </CardContent>\n    </Card>\n\n    <!-- Instant Rotate Modal / Dialog (Zero-Downtime Confirmation) -->\n    <Dialog v-model:open=\"isRotateModalOpen\">\n      <DialogContent class=\"sm:max-w-xl\">\n        <DialogHeader>\n          <div class=\"flex items-center gap-2\">\n            <div class=\"bg-success/10 text-success rounded-lg p-2\">\n              <RefreshCw class=\"size-5\" />\n            </div>\n            <div>\n              <DialogTitle>Trigger Zero-Downtime Rotation</DialogTitle>\n              <DialogDescription class=\"text-xs\">\n                AWS Secrets Manager 4-step staging promotion for credential lifecycle safety.\n              </DialogDescription>\n            </div>\n          </div>\n        </DialogHeader>\n\n        <div class=\"space-y-4 py-2\">\n          <!-- Target Secret Summary -->\n          <div class=\"border-border bg-muted/50 space-y-2 rounded-lg border p-3\">\n            <div class=\"flex items-center justify-between text-xs\">\n              <span class=\"text-muted-foreground\">Target Secret:</span>\n              <span class=\"text-foreground font-mono font-semibold\">{{ selectedSecretForRotate?.name }}</span>\n            </div>\n            <div class=\"flex items-center justify-between text-xs\">\n              <span class=\"text-muted-foreground\">Current Active:</span>\n              <Badge variant=\"outline\" class=\"font-mono text-xs\">\n                {{ selectedSecretForRotate?.currentVersion }}\n              </Badge>\n            </div>\n            <div class=\"flex items-center justify-between text-xs\">\n              <span class=\"text-muted-foreground\">Staging Target:</span>\n              <Badge variant=\"info\" class=\"font-mono text-xs\">\n                {{ selectedSecretForRotate?.stagingVersion || 'v2.5 (AWSPENDING)' }}\n              </Badge>\n            </div>\n          </div>\n\n          <!-- 4-Step Zero-Downtime Process Visualizer -->\n          <div class=\"space-y-2\">\n            <span class=\"text-foreground text-xs font-semibold tracking-wider uppercase\">\n              Dual-Version Execution Workflow\n            </span>\n            <div class=\"border-border bg-card space-y-2.5 rounded-lg border p-3.5 text-xs\">\n              <div class=\"flex items-start gap-2.5\">\n                <div\n                  class=\"bg-primary text-primary-foreground flex size-5 shrink-0 items-center justify-center rounded-full text-xs font-bold\"\n                >\n                  1\n                </div>\n                <div class=\"space-y-0.5\">\n                  <p class=\"text-foreground font-semibold\">createSecret (Staging)</p>\n                  <p class=\"text-muted-foreground text-xs\">\n                    Generates 32-byte cryptographic entropy and provisions version\n                    <code class=\"font-mono font-semibold\">AWSPENDING</code>.\n                  </p>\n                </div>\n              </div>\n\n              <div class=\"flex items-start gap-2.5\">\n                <div\n                  class=\"bg-primary text-primary-foreground flex size-5 shrink-0 items-center justify-center rounded-full text-xs font-bold\"\n                >\n                  2\n                </div>\n                <div class=\"space-y-0.5\">\n                  <p class=\"text-foreground font-semibold\">setSecret (Dual-Authentication)</p>\n                  <p class=\"text-muted-foreground text-xs\">\n                    Updates target resource (Postgres / API / KMS) so both Version A and Version B remain valid.\n                  </p>\n                </div>\n              </div>\n\n              <div class=\"flex items-start gap-2.5\">\n                <div\n                  class=\"bg-primary text-primary-foreground flex size-5 shrink-0 items-center justify-center rounded-full text-xs font-bold\"\n                >\n                  3\n                </div>\n                <div class=\"space-y-0.5\">\n                  <p class=\"text-foreground font-semibold\">testSecret (Handshake Verification)</p>\n                  <p class=\"text-muted-foreground text-xs\">\n                    Lambda executes synthetic database query using new credentials to verify validity.\n                  </p>\n                </div>\n              </div>\n\n              <div class=\"flex items-start gap-2.5\">\n                <div\n                  class=\"bg-primary text-primary-foreground flex size-5 shrink-0 items-center justify-center rounded-full text-xs font-bold\"\n                >\n                  4\n                </div>\n                <div class=\"space-y-0.5\">\n                  <p class=\"text-foreground font-semibold\">finishSecret (Label Promotion)</p>\n                  <p class=\"text-muted-foreground text-xs\">\n                    Moves <code class=\"font-mono font-semibold\">AWSCURRENT</code> to Version B and demotes old version\n                    to <code class=\"font-mono font-semibold\">AWSPREVIOUS</code>.\n                  </p>\n                </div>\n              </div>\n            </div>\n          </div>\n\n          <!-- Zero-Downtime Guarantee Banner -->\n          <div\n            class=\"border-success/20 bg-success/5 text-success flex items-center gap-2.5 rounded-lg border p-3 text-xs\"\n          >\n            <ShieldCheck class=\"text-success size-5 shrink-0\" />\n            <span>\n              <strong>Zero-Downtime Guarantee:</strong> Existing connections continue using Version A until Version B is\n              100% verified. No dropped TCP sockets or authentication spikes.\n            </span>\n          </div>\n        </div>\n\n        <DialogFooter>\n          <Button variant=\"outline\" :disabled=\"isRotatingInProgress\" @click=\"isRotateModalOpen = false\">\n            Cancel\n          </Button>\n          <Button :disabled=\"isRotatingInProgress\" class=\"gap-1.5\" @click=\"executeRotation\">\n            <RefreshCw v-if=\"isRotatingInProgress\" class=\"size-4 animate-spin\" />\n            <Play v-else class=\"size-4\" />\n            {{ isRotatingInProgress ? 'Executing Dual-Stage Rotation...' : 'Confirm & Rotate Immediately' }}\n          </Button>\n        </DialogFooter>\n      </DialogContent>\n    </Dialog>\n\n    <!-- Schedule / Edit Schedule Dialog -->\n    <Dialog v-model:open=\"isScheduleModalOpen\">\n      <DialogContent class=\"sm:max-w-lg\">\n        <DialogHeader>\n          <DialogTitle>{{ editingSecret ? 'Edit Rotation Schedule' : 'Schedule Secret Rotation' }}</DialogTitle>\n          <DialogDescription class=\"text-xs\">\n            Configure automated periodic rotation interval and AWS Lambda rotation handler.\n          </DialogDescription>\n        </DialogHeader>\n\n        <div class=\"space-y-4 py-2\">\n          <div class=\"space-y-1.5\">\n            <label for=\"form-secret-name\" class=\"text-foreground text-xs font-medium\">Secret Name / Path</label>\n            <Input\n              id=\"form-secret-name\"\n              v-model=\"formName\"\n              placeholder=\"e.g. prod/postgres/replica-credentials\"\n              class=\"text-xs\"\n            />\n          </div>\n\n          <div class=\"grid grid-cols-2 gap-3\">\n            <div class=\"space-y-1.5\">\n              <label for=\"form-secret-type\" class=\"text-foreground text-xs font-medium\">Secret Type</label>\n              <Select v-model=\"formType\">\n                <SelectTrigger id=\"form-secret-type\" class=\"text-xs\">\n                  <SelectValue placeholder=\"Secret Type\" />\n                </SelectTrigger>\n                <SelectContent>\n                  <SelectItem value=\"Postgres DB\">Postgres DB</SelectItem>\n                  <SelectItem value=\"MySQL DB\">MySQL DB</SelectItem>\n                  <SelectItem value=\"API Key\">API Key</SelectItem>\n                  <SelectItem value=\"RSA Keypair\">RSA Keypair</SelectItem>\n                  <SelectItem value=\"KMS Key\">KMS Key</SelectItem>\n                  <SelectItem value=\"Redis Auth\">Redis Auth</SelectItem>\n                </SelectContent>\n              </Select>\n            </div>\n\n            <div class=\"space-y-1.5\">\n              <label for=\"form-secret-interval\" class=\"text-foreground text-xs font-medium\">Rotation Interval</label>\n              <Select v-model=\"formInterval\">\n                <SelectTrigger id=\"form-secret-interval\" class=\"text-xs\">\n                  <SelectValue placeholder=\"Interval\" />\n                </SelectTrigger>\n                <SelectContent>\n                  <SelectItem value=\"Every 7 Days\">Every 7 Days</SelectItem>\n                  <SelectItem value=\"Every 30 Days\">Every 30 Days</SelectItem>\n                  <SelectItem value=\"Every 60 Days\">Every 60 Days</SelectItem>\n                  <SelectItem value=\"Every 90 Days\">Every 90 Days</SelectItem>\n                  <SelectItem value=\"Every 365 Days\">Every 365 Days</SelectItem>\n                  <SelectItem value=\"Manual Only\">Manual Only</SelectItem>\n                </SelectContent>\n              </Select>\n            </div>\n          </div>\n\n          <div class=\"space-y-1.5\">\n            <label for=\"form-secret-lambda\" class=\"text-foreground text-xs font-medium\">\n              Rotation Lambda Function ARN\n            </label>\n            <Input\n              id=\"form-secret-lambda\"\n              v-model=\"formLambdaArn\"\n              placeholder=\"arn:aws:lambda:us-east-1:182938491029:function:RotateSecret\"\n              class=\"font-mono text-xs\"\n            />\n          </div>\n\n          <div class=\"border-border bg-muted/40 flex items-center justify-between rounded-lg border p-3\">\n            <div class=\"space-y-0.5\">\n              <p class=\"text-foreground text-xs font-medium\">Zero-Downtime Dual Versioning</p>\n              <p class=\"text-muted-foreground text-xs\">Verify staging version before promoting AWSCURRENT</p>\n            </div>\n            <Badge variant=\"success\" class=\"text-xs\">Active</Badge>\n          </div>\n        </div>\n\n        <DialogFooter>\n          <Button variant=\"outline\" @click=\"isScheduleModalOpen = false\">Cancel</Button>\n          <Button :disabled=\"!formName.trim()\" @click=\"saveSchedule\">\n            {{ editingSecret ? 'Save Changes' : 'Create Rotation Schedule' }}\n          </Button>\n        </DialogFooter>\n      </DialogContent>\n    </Dialog>\n\n    <!-- View Rotation Lambda Log Dialog -->\n    <Dialog v-model:open=\"isLogsModalOpen\">\n      <DialogContent class=\"sm:max-w-2xl\">\n        <DialogHeader>\n          <div class=\"flex items-center gap-2\">\n            <Terminal class=\"text-primary size-5\" />\n            <DialogTitle class=\"font-mono text-base\">{{ selectedSecretForLogs?.name }}</DialogTitle>\n          </div>\n          <DialogDescription class=\"font-mono text-xs\">\n            Lambda Handler: {{ selectedSecretForLogs?.schedule.lambdaArn || 'arn:aws:lambda:...:RotateDefault' }}\n          </DialogDescription>\n        </DialogHeader>\n\n        <div class=\"space-y-3 py-1\">\n          <div class=\"border-border bg-muted/60 flex items-center justify-between rounded-md border px-3 py-2 text-xs\">\n            <div class=\"flex items-center gap-2\">\n              <span class=\"text-muted-foreground\">Last Invocation:</span>\n              <span class=\"text-foreground font-mono font-medium\">{{ selectedSecretForLogs?.lastRotated }}</span>\n            </div>\n            <div class=\"flex items-center gap-2\">\n              <span class=\"text-muted-foreground\">Status:</span>\n              <Badge variant=\"success\" class=\"font-mono text-xs\">200 OK - SUCCESS</Badge>\n            </div>\n          </div>\n\n          <!-- Terminal Output Simulation -->\n          <div\n            class=\"border-border text-success space-y-1.5 overflow-x-auto rounded-lg border bg-black/90 p-4 font-mono text-xs dark:bg-black\"\n          >\n            <p class=\"text-muted-foreground\">START RequestId: 4f8b91a2-631c-4b89-9801-ec8492019a Version: $LATEST</p>\n            <p class=\"text-success\">\n              [INFO] Step 1/4 createSecret: Generating 32-byte cryptographic entropy for AWSPENDING...\n            </p>\n            <p class=\"text-success\">\n              [INFO] Step 2/4 setSecret: Applying shadow credentials to destination cluster. Dual-auth enabled.\n            </p>\n            <p class=\"text-success\">\n              [INFO] Step 3/4 testSecret: Executing test query `SELECT 1` from staging connection pool -> Verified\n              (6.4ms)\n            </p>\n            <p class=\"text-success\">\n              [INFO] Step 4/4 finishSecret: Swapped AWSCURRENT label to staging version. Previous marked AWSPREVIOUS.\n            </p>\n            <p class=\"text-muted-foreground\">END RequestId: 4f8b91a2-631c-4b89-9801-ec8492019a</p>\n            <p class=\"text-muted-foreground\">\n              REPORT RequestId: 4f8b91a2-631c-4b89-9801-ec8492019a Duration: 342.15 ms Billed Duration: 343 ms Memory\n              Size: 256 MB Max Memory Used: 68 MB\n            </p>\n          </div>\n        </div>\n\n        <DialogFooter>\n          <Button variant=\"outline\" @click=\"isLogsModalOpen = false\">Close Logs</Button>\n        </DialogFooter>\n      </DialogContent>\n    </Dialog>\n  </div>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/SecretsRotationScheduler.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/dialog.json",
    "https://uipkge.dev/r/vue/dropdown-menu.json",
    "https://uipkge.dev/r/vue/input.json",
    "https://uipkge.dev/r/vue/select.json",
    "https://uipkge.dev/r/vue/table.json"
  ],
  "description": "AWS Secrets Manager style automated credential rotation scheduler and security key audit with lifecycle telemetry cards, zero-downtime dual-version rotation workflow, rotation lambda log inspection, and schedule configuration dialogs.",
  "categories": [
    "security",
    "app",
    "devops",
    "dashboard"
  ]
}