{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "synthetic-data-generator",
  "title": "Synthetic Data Generator",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/synthetic-data-generator/SyntheticDataGenerator.vue",
      "content": "<script setup lang=\"ts\">\nimport { computed, ref, watch, type HTMLAttributes } from 'vue'\nimport {\n  Check,\n  Code2,\n  Cpu,\n  Database,\n  Download,\n  FileSpreadsheet,\n  Info,\n  Layers,\n  Lock,\n  Plus,\n  RefreshCw,\n  ShieldCheck,\n  Sliders,\n  Sparkles,\n  Trash2,\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 { Input } from '@/components/ui/input'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'\nimport { Separator } from '@/components/ui/separator'\nimport { Slider } from '@/components/ui/slider'\nimport { Switch } from '@/components/ui/switch'\nimport type {\n  FieldDataType,\n  FidelityMetrics,\n  GeneratedRecord,\n  SchemaField,\n  SyntheticDataGeneratorProps,\n  TemplatePreset,\n} from './synthetic-data-types'\nimport {\n  boxMullerRandom as boxMullerRandomHelper,\n  CARD_BRANDS,\n  FIRST_NAMES,\n  LAST_NAMES,\n  TEMPLATES,\n} from './synthetic-data-templates'\nimport SyntheticDataPreview from './SyntheticDataPreview.vue'\n\nexport type {\n  FieldDataType,\n  FidelityMetrics,\n  GeneratedRecord,\n  SchemaField,\n  SyntheticDataGeneratorProps,\n  TemplatePreset,\n}\n\ninterface Props {\n  class?: HTMLAttributes['class']\n  initialTemplate?: string\n  initialRowCount?: number\n  initialEpsilon?: number\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n  initialTemplate: 'customer-transactions',\n  initialRowCount: 1000,\n  initialEpsilon: 1.2,\n})\n\n// --- STATE ---\nconst selectedTemplateKey = ref<string>(props.initialTemplate)\nconst outputFormat = ref<'csv' | 'jsonl'>('csv')\nconst rowCount = ref<number>(props.initialRowCount)\nconst epsilon = ref<number>(props.initialEpsilon)\nconst kAnonymity = ref<boolean>(true)\nconst saltedHash = ref<boolean>(true)\nconst noiseMechanism = ref<boolean>(true)\n\nconst activeFields = ref<SchemaField[]>([])\nconst isGenerating = ref<boolean>(false)\nconst copied = ref<boolean>(false)\nconst downloadToast = ref<string | null>(null)\nconst previewTab = ref<'table' | 'json' | 'metrics'>('table')\nconst generationSeed = ref<number>(48291)\n\n// Field addition form state\nconst showAddField = ref<boolean>(false)\nconst newFieldName = ref<string>('')\nconst newFieldType = ref<FieldDataType>('gaussian_float')\n\n// Load template fields\nfunction loadTemplate(key: string) {\n  const tpl = TEMPLATES[key]\n  if (tpl) {\n    activeFields.value = JSON.parse(JSON.stringify(tpl.fields))\n    triggerRegeneration()\n  }\n}\n\n// Watch template changes\nwatch(selectedTemplateKey, (newKey) => {\n  loadTemplate(newKey)\n})\n\n// Initialize fields\nloadTemplate(selectedTemplateKey.value)\n\nfunction boxMullerRandom(mean: number, stdDev: number, seedOffset: number): number {\n  return boxMullerRandomHelper(mean, stdDev, seedOffset, generationSeed.value, noiseMechanism.value, epsilon.value)\n}\n\nconst previewRecords = computed<GeneratedRecord[]>(() => {\n  const rows: GeneratedRecord[] = []\n  const count = 6 // Show first 6 realistic rows in preview\n\n  for (let i = 0; i < count; i++) {\n    const fn = FIRST_NAMES[(i * 3 + generationSeed.value) % FIRST_NAMES.length]\n    const ln = LAST_NAMES[(i * 5 + generationSeed.value + 2) % LAST_NAMES.length]\n    const fullName = `${fn} ${ln}`\n    const baseSlug = `${fn.charAt(0).toLowerCase()}.${ln.toLowerCase().replace(/[^a-z]/g, '')}`\n\n    const record: GeneratedRecord = {\n      id: saltedHash.value\n        ? `syn_${((generationSeed.value * 9301 + i * 49297) % 233280).toString(16).padStart(6, '0')}`\n        : `usr_${1000 + i}`,\n    }\n\n    for (const field of activeFields.value) {\n      if (field.name.includes('id') || field.name.includes('uuid') || field.name.includes('token')) {\n        record[field.name] = record.id\n        continue\n      }\n\n      switch (field.type) {\n        case 'name':\n          record[field.name] = fullName\n          break\n\n        case 'email': {\n          const dom = field.params.domain || 'synthetic-vault.io'\n          record[field.name] = `${baseSlug}@${dom}`\n          break\n        }\n\n        case 'credit_card': {\n          const last4 = (((generationSeed.value * 7 + i * 1337 + 1000) % 9000) + 1000).toString()\n          const brand = CARD_BRANDS[i % CARD_BRANDS.length]\n          record[field.name] = `${brand} •••• ${last4}`\n          break\n        }\n\n        case 'gaussian_float': {\n          const m = field.params.mean ?? 100\n          const s = field.params.stdDev ?? 20\n          const rawVal = boxMullerRandom(m, s, i)\n          const val = Math.max(m * 0.1, rawVal)\n\n          if (field.params.currency) {\n            record[field.name] = `${field.params.currency}${val.toFixed(2)}`\n          } else if (field.params.unit) {\n            record[field.name] = `${val.toFixed(1)} ${field.params.unit}`\n          } else {\n            record[field.name] = parseFloat(val.toFixed(2))\n          }\n          break\n        }\n\n        case 'category_weights': {\n          const cats = field.params.categories || ['Standard', 'Premium']\n          const catIndex = (i + Math.floor(generationSeed.value / 100)) % cats.length\n          record[field.name] = cats[catIndex]\n          break\n        }\n\n        case 'date_range': {\n          const day = ((10 + i * 4) % 28) + 1\n          const month = (i % 8) + 1\n          const dayStr = day.toString().padStart(2, '0')\n          const monthStr = month.toString().padStart(2, '0')\n          const hour = (8 + i * 3) % 24\n          const hourStr = hour.toString().padStart(2, '0')\n          record[field.name] = `2025-${monthStr}-${dayStr} ${hourStr}:24:18 UTC`\n          break\n        }\n\n        default:\n          record[field.name] = `value_${i}`\n      }\n    }\n\n    rows.push(record)\n  }\n\n  return rows\n})\n\n// --- STATISTICAL FIDELITY & DP METRICS ---\nconst fidelityMetrics = computed(() => {\n  const eps = epsilon.value\n  // Higher epsilon -> higher similarity, lower privacy\n  const rawSimilarity = Math.min(99.4, Math.max(82.0, 99.2 - ((5.0 - eps) / 4.9) * 9.6))\n  const similarity = parseFloat(rawSimilarity.toFixed(1))\n\n  // PII Leakage Risk is 0% when kAnonymity & Salted hash are enabled and eps <= 3.5\n  const leakageRisk = kAnonymity.value && saltedHash.value && eps <= 3.5 ? 0.0 : Math.max(0, (eps - 3.5) * 0.04)\n  const correlationRetention = parseFloat(Math.min(99.1, 98.6 - ((5.0 - eps) / 4.9) * 6.2).toFixed(1))\n  const wassersteinDistance = parseFloat((0.032 + ((5.0 - eps) / 4.9) * 0.024).toFixed(3))\n  const laplaceNoiseStd = (0.12 / Math.max(0.1, eps)).toFixed(3)\n\n  let privacyTier = 'Balanced Privacy & Utility'\n  let privacyBadgeColor = 'bg-info/10 text-info border-info/30'\n\n  if (eps <= 0.5) {\n    privacyTier = 'Maximum Privacy / High DP Noise'\n    privacyBadgeColor = 'bg-success/10 text-success border-success/30'\n  } else if (eps > 2.5) {\n    privacyTier = 'High Statistical Utility / Minimal Noise'\n    privacyBadgeColor = 'bg-warning/10 text-warning border-warning/30'\n  }\n\n  return {\n    similarity,\n    leakageRisk: leakageRisk.toFixed(2),\n    correlationRetention,\n    wassersteinDistance,\n    laplaceNoiseStd,\n    privacyTier,\n    privacyBadgeColor,\n  }\n})\n\n// Estimated file size calculation\nconst estimatedFileSize = computed(() => {\n  const bytesPerRow = outputFormat.value === 'csv' ? 180 : 380\n  const totalKb = (rowCount.value * bytesPerRow) / 1024\n  if (totalKb < 1024) {\n    return `~${totalKb.toFixed(1)} KB`\n  }\n  return `~${(totalKb / 1024).toFixed(2)} MB`\n})\n\n// --- ACTIONS ---\nfunction triggerRegeneration() {\n  isGenerating.value = true\n  generationSeed.value = Math.floor(Math.random() * 90000) + 10000\n\n  setTimeout(() => {\n    isGenerating.value = false\n  }, 450)\n}\n\nfunction handleAddCustomField() {\n  if (!newFieldName.value.trim()) return\n\n  const cleanName = newFieldName.value.trim().toLowerCase().replace(/\\s+/g, '_')\n  const newField: SchemaField = {\n    id: `f-custom-${Date.now()}`,\n    name: cleanName,\n    label: newFieldName.value.trim(),\n    type: newFieldType.value,\n    description: `Custom ${newFieldType.value} schema column`,\n    params:\n      newFieldType.value === 'gaussian_float'\n        ? { mean: 500, stdDev: 120, currency: '$' }\n        : newFieldType.value === 'category_weights'\n          ? { categories: ['Alpha', 'Beta', 'Gamma'], weights: [0.5, 0.3, 0.2] }\n          : {},\n  }\n\n  activeFields.value.push(newField)\n  newFieldName.value = ''\n  showAddField.value = false\n  triggerRegeneration()\n}\n\nfunction removeField(fieldId: string) {\n  if (activeFields.value.length <= 2) return // Keep at least 2 fields\n  activeFields.value = activeFields.value.filter((f) => f.id !== fieldId)\n  triggerRegeneration()\n}\n\nasync function copyJsonLines() {\n  try {\n    const jsonLinesText = previewRecords.value.map((r) => JSON.stringify(r)).join('\\n')\n    if (navigator?.clipboard?.writeText) {\n      await navigator.clipboard.writeText(jsonLinesText)\n    }\n    copied.value = true\n    setTimeout(() => {\n      copied.value = false\n    }, 2000)\n  } catch (err) {\n    console.error('Failed to copy to clipboard', err)\n  }\n}\n\nfunction handleDownloadDataset() {\n  const filename = `synthetic_${selectedTemplateKey.value}_${rowCount.value}_rows.${outputFormat.value === 'csv' ? 'csv' : 'jsonl'}`\n  downloadToast.value = `Downloaded ${rowCount.value.toLocaleString()} synthetic records (${filename})`\n  setTimeout(() => {\n    downloadToast.value = null\n  }, 3500)\n}\n\n// Watch row count / epsilon to retrigger subtle noise updates\nwatch([epsilon, kAnonymity, saltedHash, noiseMechanism], () => {\n  // Update without full spinning state\n})\n</script>\n\n<template>\n  <div data-slot=\"synthetic-data-generator\" :class=\"cn('mx-auto w-full max-w-7xl space-y-6', props.class)\">\n    <!-- TOP HEADER HERO -->\n    <Card class=\"border-border overflow-hidden shadow-xs\">\n      <CardHeader class=\"border-border/60 bg-muted/20 border-b pb-4\">\n        <div class=\"flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between\">\n          <div class=\"space-y-1\">\n            <div class=\"flex flex-wrap items-center gap-2\">\n              <div class=\"bg-primary/10 text-primary flex size-8 items-center justify-center rounded-lg\">\n                <Cpu class=\"size-4.5\" />\n              </div>\n              <CardTitle class=\"text-lg font-bold tracking-tight md:text-xl\">\n                Synthetic Dataset Generator &amp; Privacy Engine\n              </CardTitle>\n              <Badge variant=\"outline\" class=\"gap-1 text-xs font-normal\">\n                <span class=\"bg-success size-1.5 animate-pulse rounded-full\" />\n                Differential Privacy Enabled\n              </Badge>\n            </div>\n            <CardDescription class=\"text-xs md:text-sm\">\n              Mathematical &amp; LLM-guided synthetic tabular dataset synthesizer with configurable (ε, δ)-DP noise\n              injection.\n            </CardDescription>\n          </div>\n\n          <!-- Header Right Quick Actions -->\n          <div class=\"flex flex-wrap items-center gap-2.5\">\n            <!-- Format Selector Segmented Control -->\n            <div class=\"bg-muted/60 border-border inline-flex items-center rounded-lg border p-0.5 text-xs\">\n              <button\n                type=\"button\"\n                :class=\"\n                  cn(\n                    'flex cursor-pointer items-center gap-1.5 rounded-md px-2.5 py-1.5 font-medium transition-colors',\n                    outputFormat === 'csv'\n                      ? 'bg-background text-foreground shadow-xs'\n                      : 'text-muted-foreground hover:text-foreground',\n                  )\n                \"\n                @click=\"outputFormat = 'csv'\"\n              >\n                <FileSpreadsheet class=\"size-3.5\" />\n                <span>Tabular CSV</span>\n              </button>\n              <button\n                type=\"button\"\n                :class=\"\n                  cn(\n                    'flex cursor-pointer items-center gap-1.5 rounded-md px-2.5 py-1.5 font-medium transition-colors',\n                    outputFormat === 'jsonl'\n                      ? 'bg-background text-foreground shadow-xs'\n                      : 'text-muted-foreground hover:text-foreground',\n                  )\n                \"\n                @click=\"outputFormat = 'jsonl'\"\n              >\n                <Code2 class=\"size-3.5\" />\n                <span>JSON Lines</span>\n              </button>\n            </div>\n\n            <!-- Download Button -->\n            <Button\n              aria-label=\"Download attachment\"\n              variant=\"outline\"\n              size=\"sm\"\n              class=\"h-9 gap-1.5 text-xs font-medium\"\n              @click=\"handleDownloadDataset\"\n            >\n              <Download class=\"size-3.5\" />\n              <span>Download Dataset</span>\n            </Button>\n\n            <!-- Primary Generate Batch Button -->\n            <Button\n              variant=\"default\"\n              size=\"sm\"\n              :class=\"\n                cn(\n                  'h-9 gap-1.5 px-4 text-xs font-semibold shadow-xs transition-[color,background-color,border-color,box-shadow,opacity,transform,scale,translate,rotate] active:scale-95',\n                )\n              \"\n              :disabled=\"isGenerating\"\n              @click=\"triggerRegeneration\"\n            >\n              <RefreshCw v-if=\"isGenerating\" class=\"size-3.5 animate-spin\" />\n              <Sparkles v-else class=\"size-3.5\" />\n              <span>{{ isGenerating ? 'Synthesizing...' : 'Generate Synthetic Batch' }}</span>\n            </Button>\n          </div>\n        </div>\n\n        <!-- Template Selector Bar -->\n        <div\n          class=\"border-border/50 bg-background/50 mt-3 flex flex-wrap items-center justify-between gap-3 rounded-lg border px-3.5 py-2\"\n        >\n          <div class=\"flex items-center gap-2\">\n            <Layers class=\"text-muted-foreground size-4\" />\n            <span class=\"text-foreground text-xs font-semibold\">Schema Template:</span>\n          </div>\n\n          <div class=\"w-full min-w-0 sm:max-w-md sm:flex-1\">\n            <Select v-model=\"selectedTemplateKey\">\n              <SelectTrigger class=\"bg-background h-8.5 w-full text-xs font-medium [&>span]:truncate [&>svg]:shrink-0\">\n                <SelectValue placeholder=\"Select Schema Template\" />\n              </SelectTrigger>\n              <SelectContent>\n                <SelectItem v-for=\"(tpl, key) in TEMPLATES\" :key=\"key\" :value=\"key\" class=\"text-xs\">\n                  {{ tpl.name }}\n                </SelectItem>\n              </SelectContent>\n            </Select>\n          </div>\n\n          <div class=\"text-muted-foreground hidden items-center gap-2 text-xs sm:flex\">\n            <Badge variant=\"secondary\" class=\"px-2 py-0.5 text-xs font-normal\">\n              {{ TEMPLATES[selectedTemplateKey]?.category }}\n            </Badge>\n            <span>&bull;</span>\n            <span class=\"font-mono tabular-nums\">{{ activeFields.length }} fields configured</span>\n          </div>\n        </div>\n      </CardHeader>\n    </Card>\n\n    <!-- DOWNLOAD SUCCESS NOTIFICATION -->\n    <div\n      v-if=\"downloadToast\"\n      class=\"border-success/30 bg-success/10 text-success text-success flex items-center justify-between rounded-lg border px-4 py-2.5 text-xs font-medium shadow-xs\"\n    >\n      <div class=\"flex items-center gap-2\">\n        <Check class=\"size-4 stroke-[2.5]\" />\n        <span>{{ downloadToast }}</span>\n      </div>\n      <Badge variant=\"outline\" class=\"border-success/40 font-mono text-xs\">\n        {{ estimatedFileSize }}\n      </Badge>\n    </div>\n\n    <!-- 2-COLUMN STUDIO GENERATOR -->\n    <div class=\"grid grid-cols-1 gap-6 lg:grid-cols-12\">\n      <!-- LEFT COLUMN: SCHEMA & PRIVACY CONFIGURATION (40% / 5 Cols) -->\n      <div class=\"space-y-6 lg:col-span-5\">\n        <!-- CARD 1: ROW COUNT & BATCH SCALE -->\n        <Card class=\"border-border shadow-xs\">\n          <CardHeader class=\"border-border/50 border-b pb-3\">\n            <div class=\"flex items-center justify-between\">\n              <div class=\"flex items-center gap-2\">\n                <div class=\"bg-muted text-muted-foreground flex size-7 items-center justify-center rounded-md\">\n                  <Database class=\"size-3.5\" />\n                </div>\n                <CardTitle class=\"text-sm font-semibold\">Dataset Generation Volume</CardTitle>\n              </div>\n              <Badge variant=\"secondary\" class=\"font-mono text-xs font-semibold tabular-nums\">\n                {{ rowCount.toLocaleString() }} rows\n              </Badge>\n            </div>\n          </CardHeader>\n\n          <CardContent class=\"space-y-4 pt-4\">\n            <!-- Row Slider -->\n            <div class=\"space-y-2\">\n              <div class=\"text-muted-foreground flex items-center justify-between text-xs\">\n                <span>100 rows</span>\n                <span class=\"text-foreground font-mono font-medium\">Estimated: {{ estimatedFileSize }}</span>\n                <span>50,000 rows</span>\n              </div>\n\n              <Slider\n                :model-value=\"rowCount\"\n                :min=\"100\"\n                :max=\"50000\"\n                :step=\"100\"\n                class=\"w-full py-1\"\n                @update:model-value=\"(val) => (rowCount = Array.isArray(val) ? val[0] : val)\"\n              />\n            </div>\n\n            <!-- Quick Preset Chips -->\n            <div class=\"flex flex-wrap items-center gap-1.5 pt-1\">\n              <span class=\"text-muted-foreground mr-1 text-xs\">Presets:</span>\n              <button\n                v-for=\"preset in [100, 1000, 5000, 10000, 50000]\"\n                :key=\"preset\"\n                type=\"button\"\n                :class=\"\n                  cn(\n                    'cursor-pointer rounded-md border px-2.5 py-1 text-xs font-medium transition-colors',\n                    rowCount === preset\n                      ? 'bg-primary text-primary-foreground border-primary shadow-xs'\n                      : 'bg-muted/40 text-muted-foreground border-border hover:bg-muted hover:text-foreground',\n                  )\n                \"\n                @click=\"rowCount = preset\"\n              >\n                {{ preset >= 1000 ? `${preset / 1000}k` : preset }}\n              </button>\n            </div>\n          </CardContent>\n        </Card>\n\n        <!-- CARD 2: DIFFERENTIAL PRIVACY EPSILON (ε) CONTROLS -->\n        <Card class=\"border-border shadow-xs\">\n          <CardHeader class=\"border-border/50 border-b pb-3\">\n            <div class=\"flex items-center justify-between\">\n              <div class=\"flex items-center gap-2\">\n                <div class=\"bg-primary/10 text-primary flex size-7 items-center justify-center rounded-md\">\n                  <ShieldCheck class=\"size-3.5\" />\n                </div>\n                <div>\n                  <CardTitle class=\"text-sm font-semibold\">Differential Privacy Budget</CardTitle>\n                  <CardDescription class=\"text-xs\"> Laplace (ε, δ)-DP noise calibration </CardDescription>\n                </div>\n              </div>\n              <Badge variant=\"outline\" class=\"font-mono text-xs font-bold tabular-nums\">\n                &epsilon; = {{ epsilon.toFixed(1) }}\n              </Badge>\n            </div>\n          </CardHeader>\n\n          <CardContent class=\"space-y-4 pt-4\">\n            <!-- Epsilon Slider -->\n            <div class=\"space-y-2\">\n              <div class=\"flex items-center justify-between text-xs\">\n                <span class=\"text-success font-medium\">&epsilon;=0.1 (High Privacy)</span>\n                <span class=\"text-warning font-medium\">&epsilon;=5.0 (High Fidelity)</span>\n              </div>\n\n              <Slider\n                :model-value=\"epsilon\"\n                :min=\"0.1\"\n                :max=\"5.0\"\n                :step=\"0.1\"\n                class=\"w-full py-1\"\n                @update:model-value=\"(val) => (epsilon = Array.isArray(val) ? val[0] : val)\"\n              />\n            </div>\n\n            <!-- Epsilon Interpretation Banner -->\n            <div\n              :class=\"cn('flex items-start gap-2.5 rounded-lg border p-3 text-xs', fidelityMetrics.privacyBadgeColor)\"\n            >\n              <Info class=\"mt-0.5 size-4 shrink-0\" />\n              <div class=\"space-y-1\">\n                <div class=\"font-semibold\">{{ fidelityMetrics.privacyTier }}</div>\n                <p class=\"text-muted-foreground text-xs leading-relaxed\">\n                  Laplace noise scale:\n                  <span class=\"text-foreground font-mono font-medium\"\n                    >&sigma;=&plusmn;{{ fidelityMetrics.laplaceNoiseStd }}</span\n                  >\n                  &bull; Delta: <span class=\"text-foreground font-mono font-medium\">&delta;=10⁻⁵</span> &bull; Zero\n                  memorization guarantee.\n                </p>\n              </div>\n            </div>\n\n            <!-- Quick Epsilon Presets -->\n            <div class=\"grid grid-cols-3 gap-2 pt-1\">\n              <button\n                type=\"button\"\n                :class=\"\n                  cn(\n                    'cursor-pointer rounded-lg border p-2 text-center text-xs transition-colors',\n                    epsilon === 0.5\n                      ? 'border-primary bg-primary/10 text-primary font-semibold'\n                      : 'border-border bg-background text-muted-foreground hover:bg-muted/40',\n                  )\n                \"\n                @click=\"epsilon = 0.5\"\n              >\n                <div class=\"font-bold\">&epsilon; = 0.5</div>\n                <div class=\"text-muted-foreground text-xs\">Healthcare</div>\n              </button>\n              <button\n                type=\"button\"\n                :class=\"\n                  cn(\n                    'cursor-pointer rounded-lg border p-2 text-center text-xs transition-colors',\n                    epsilon === 1.2\n                      ? 'border-primary bg-primary/10 text-primary font-semibold'\n                      : 'border-border bg-background text-muted-foreground hover:bg-muted/40',\n                  )\n                \"\n                @click=\"epsilon = 1.2\"\n              >\n                <div class=\"font-bold\">&epsilon; = 1.2</div>\n                <div class=\"text-muted-foreground text-xs\">Standard</div>\n              </button>\n              <button\n                type=\"button\"\n                :class=\"\n                  cn(\n                    'cursor-pointer rounded-lg border p-2 text-center text-xs transition-colors',\n                    epsilon === 3.0\n                      ? 'border-primary bg-primary/10 text-primary font-semibold'\n                      : 'border-border bg-background text-muted-foreground hover:bg-muted/40',\n                  )\n                \"\n                @click=\"epsilon = 3.0\"\n              >\n                <div class=\"font-bold\">&epsilon; = 3.0</div>\n                <div class=\"text-muted-foreground text-xs\">Analytics</div>\n              </button>\n            </div>\n          </CardContent>\n        </Card>\n\n        <!-- CARD 3: FIELD SCHEMAS GENERATOR -->\n        <Card class=\"border-border shadow-xs\">\n          <CardHeader class=\"border-border/50 border-b pb-3\">\n            <div class=\"flex items-center justify-between\">\n              <div class=\"flex items-center gap-2\">\n                <div class=\"bg-muted text-muted-foreground flex size-7 items-center justify-center rounded-md\">\n                  <Sliders class=\"size-3.5\" />\n                </div>\n                <div>\n                  <CardTitle class=\"text-sm font-semibold\">Schema Fields Generator</CardTitle>\n                  <CardDescription class=\"text-xs\">\n                    {{ activeFields.length }} active synthesizer distributions\n                  </CardDescription>\n                </div>\n              </div>\n              <Button\n                variant=\"outline\"\n                size=\"sm\"\n                class=\"h-7.5 gap-1 px-2.5 text-xs\"\n                @click=\"showAddField = !showAddField\"\n              >\n                <Plus class=\"size-3.5\" />\n                <span>{{ showAddField ? 'Cancel' : 'Add Field' }}</span>\n              </Button>\n            </div>\n          </CardHeader>\n\n          <CardContent class=\"space-y-3 pt-4\">\n            <!-- Add Field Drawer / Form -->\n            <div v-if=\"showAddField\" class=\"border-border/80 bg-muted/30 space-y-3 rounded-lg border p-3.5 text-xs\">\n              <div class=\"text-foreground font-semibold\">Configure New Synthetic Field</div>\n              <div class=\"grid grid-cols-1 gap-2 sm:grid-cols-2\">\n                <div class=\"space-y-1\">\n                  <label class=\"text-muted-foreground text-xs\">Field Identifier</label>\n                  <Input v-model=\"newFieldName\" placeholder=\"e.g. account_balance\" class=\"h-8 text-xs\" />\n                </div>\n                <div class=\"space-y-1\">\n                  <label class=\"text-muted-foreground text-xs\">Data Distribution Type</label>\n                  <Select v-model=\"newFieldType\">\n                    <SelectTrigger class=\"bg-background h-8 w-full min-w-0 text-xs\">\n                      <SelectValue placeholder=\"Type\" />\n                    </SelectTrigger>\n                    <SelectContent>\n                      <SelectItem value=\"gaussian_float\" class=\"text-xs\">Float Gaussian Distribution</SelectItem>\n                      <SelectItem value=\"name\" class=\"text-xs\">Full Name Faker</SelectItem>\n                      <SelectItem value=\"email\" class=\"text-xs\">Email Faker</SelectItem>\n                      <SelectItem value=\"credit_card\" class=\"text-xs\">Credit Card Faker</SelectItem>\n                      <SelectItem value=\"category_weights\" class=\"text-xs\">Category Weights</SelectItem>\n                      <SelectItem value=\"date_range\" class=\"text-xs\">Date Range</SelectItem>\n                    </SelectContent>\n                  </Select>\n                </div>\n              </div>\n\n              <div class=\"flex justify-end gap-2 pt-1\">\n                <Button variant=\"ghost\" size=\"sm\" class=\"h-7.5 text-xs\" @click=\"showAddField = false\"> Cancel </Button>\n                <Button\n                  variant=\"default\"\n                  size=\"sm\"\n                  class=\"h-7.5 text-xs\"\n                  :disabled=\"!newFieldName.trim()\"\n                  @click=\"handleAddCustomField\"\n                >\n                  Add to Schema\n                </Button>\n              </div>\n            </div>\n\n            <!-- Fields List -->\n            <div class=\"divide-border/60 max-h-[320px] space-y-2 overflow-y-auto pr-1\">\n              <div\n                v-for=\"field in activeFields\"\n                :key=\"field.id\"\n                class=\"group border-border/70 bg-card hover:bg-muted/20 flex items-center justify-between rounded-lg border p-2.5 transition-colors\"\n              >\n                <div class=\"min-w-0 space-y-0.5\">\n                  <div class=\"flex items-center gap-2\">\n                    <span class=\"text-foreground font-mono text-xs font-semibold\">{{ field.name }}</span>\n                    <Badge\n                      variant=\"outline\"\n                      :class=\"\n                        cn(\n                          'px-1.5 py-0 text-xs font-semibold tracking-wider uppercase',\n                          field.type === 'gaussian_float' && 'border-info/20 bg-info/10 text-info',\n                          field.type === 'name' && 'border-chart-1/20 bg-chart-1/10 text-chart-1',\n                          field.type === 'email' && 'border-chart-2/20 bg-chart-2/10 text-chart-2',\n                          field.type === 'credit_card' && 'border-warning/20 bg-warning/10 text-warning',\n                          field.type === 'category_weights' && 'border-success/20 bg-success/10 text-success',\n                          field.type === 'date_range' && 'border-destructive/20 bg-destructive/10 text-destructive',\n                        )\n                      \"\n                    >\n                      {{ field.type.replace('_', ' ') }}\n                    </Badge>\n                  </div>\n                  <p class=\"text-muted-foreground truncate text-xs\">\n                    {{ field.description || 'Configured synthesizer parameter' }}\n                  </p>\n                </div>\n\n                <Button\n                  aria-label=\"Delete field\"\n                  variant=\"ghost\"\n                  size=\"sm\"\n                  class=\"text-muted-foreground hover:text-destructive h-7 w-7 p-0 opacity-80 group-hover:opacity-100\"\n                  :disabled=\"activeFields.length <= 2\"\n                  @click=\"removeField(field.id)\"\n                >\n                  <Trash2 class=\"size-3.5\" />\n                </Button>\n              </div>\n            </div>\n          </CardContent>\n        </Card>\n\n        <!-- CARD 4: PII ANONYMIZATION POLICY SWITCHES -->\n        <Card class=\"border-border shadow-xs\">\n          <CardHeader class=\"border-border/50 border-b pb-3\">\n            <div class=\"flex items-center gap-2\">\n              <div class=\"bg-muted text-muted-foreground flex size-7 items-center justify-center rounded-md\">\n                <Lock class=\"size-3.5\" />\n              </div>\n              <div>\n                <CardTitle class=\"text-sm font-semibold\">PII Anonymization Policy</CardTitle>\n                <CardDescription class=\"text-xs\"> Zero linkage &amp; re-identification guarantees </CardDescription>\n              </div>\n            </div>\n          </CardHeader>\n\n          <CardContent class=\"space-y-4 pt-4\">\n            <!-- K-Anonymity Switch -->\n            <div class=\"flex items-start justify-between gap-3\">\n              <div class=\"space-y-0.5\">\n                <div class=\"text-foreground text-xs font-semibold\">K-Anonymity (k = 5 Cohort Enforcement)</div>\n                <p class=\"text-muted-foreground text-xs leading-relaxed\">\n                  Generalizes quasi-identifiers so each demographic bucket contains ≥ 5 records.\n                </p>\n              </div>\n              <Switch :model-value=\"kAnonymity\" @update:model-value=\"(v) => (kAnonymity = v)\" />\n            </div>\n\n            <Separator />\n\n            <!-- Salted Hash Switch -->\n            <div class=\"flex items-start justify-between gap-3\">\n              <div class=\"space-y-0.5\">\n                <div class=\"text-foreground text-xs font-semibold\">Salted HMAC-SHA256 for Primary Keys</div>\n                <p class=\"text-muted-foreground text-xs leading-relaxed\">\n                  Deterministically pseudonymizes primary keys with ephemeral cryptographic salt.\n                </p>\n              </div>\n              <Switch :model-value=\"saltedHash\" @update:model-value=\"(v) => (saltedHash = v)\" />\n            </div>\n\n            <Separator />\n\n            <!-- Noise Injection Switch -->\n            <div class=\"flex items-start justify-between gap-3\">\n              <div class=\"space-y-0.5\">\n                <div class=\"text-foreground text-xs font-semibold\">Differential Privacy Gaussian Noise</div>\n                <p class=\"text-muted-foreground text-xs leading-relaxed\">\n                  Injects calibrated noise calibrated to global sensitivity (Δf / ε).\n                </p>\n              </div>\n              <Switch :model-value=\"noiseMechanism\" @update:model-value=\"(v) => (noiseMechanism = v)\" />\n            </div>\n          </CardContent>\n        </Card>\n      </div>\n\n      <!-- RIGHT COLUMN: LIVE GENERATED SYNTHETIC DATA PREVIEW (60% / 7 Cols) -->\n      <div class=\"space-y-6 lg:col-span-7\">\n        <SyntheticDataPreview\n          v-model:preview-tab=\"previewTab\"\n          :preview-records=\"previewRecords\"\n          :active-fields=\"activeFields\"\n          :fidelity-metrics=\"fidelityMetrics\"\n          :epsilon=\"epsilon\"\n          :row-count=\"rowCount\"\n          :output-format=\"outputFormat\"\n          :generation-seed=\"generationSeed\"\n          :copied=\"copied\"\n          @copy-json-lines=\"copyJsonLines\"\n        />\n      </div>\n    </div>\n  </div>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/SyntheticDataGenerator.vue"
    },
    {
      "path": "packages/registry-vue/blocks/synthetic-data-generator/SyntheticDataPreview.vue",
      "content": "<script setup lang=\"ts\">\nimport { BarChart3, Binary, Check, Code2, Copy, Shield, ShieldCheck, Table as TableIcon, Zap } from 'lucide-vue-next'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Progress } from '@/components/ui/progress'\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'\nimport { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs'\nimport type { FidelityMetrics, GeneratedRecord, SchemaField } from './synthetic-data-types'\n\ninterface Props {\n  previewTab: 'table' | 'json' | 'metrics'\n  previewRecords: GeneratedRecord[]\n  activeFields: SchemaField[]\n  fidelityMetrics: FidelityMetrics\n  epsilon: number\n  rowCount: number\n  outputFormat: 'csv' | 'jsonl'\n  generationSeed: number\n  copied: boolean\n}\n\nconst props = defineProps<Props>()\n\nconst emit = defineEmits<{\n  'update:previewTab': [val: 'table' | 'json' | 'metrics']\n  copyJsonLines: []\n}>()\n</script>\n\n<template>\n  <div class=\"space-y-6\">\n    <!-- TOP GAUGE BANNER: STATISTICAL FIDELITY VS PRIVACY -->\n    <Card class=\"border-border overflow-hidden shadow-xs\">\n      <div class=\"border-border/60 bg-success/10 dark:bg-success/10 border-b px-4 py-3\">\n        <div class=\"flex flex-wrap items-center justify-between gap-2\">\n          <div class=\"flex items-center gap-2\">\n            <ShieldCheck class=\"text-success size-4.5\" />\n            <span class=\"text-foreground font-mono text-sm font-bold tracking-tight\">\n              {{ fidelityMetrics.similarity }}% Distribution Similarity &bull; {{ fidelityMetrics.leakageRisk }}% PII\n              Leakage Risk\n            </span>\n          </div>\n          <Badge variant=\"outline\" class=\"bg-background border-success/40 text-success text-xs font-semibold\">\n            &epsilon;-DP Bound: &le; {{ epsilon.toFixed(1) }}\n          </Badge>\n        </div>\n      </div>\n\n      <CardContent class=\"grid grid-cols-1 gap-4 pt-4 sm:grid-cols-3\">\n        <!-- Metric 1: Fidelity Score -->\n        <div class=\"border-border/60 bg-muted/10 space-y-1.5 rounded-lg border p-3\">\n          <div class=\"text-muted-foreground flex items-center justify-between text-xs\">\n            <span>Fidelity Score</span>\n            <Zap class=\"text-warning size-3.5\" />\n          </div>\n          <div class=\"text-foreground font-mono text-lg font-bold tabular-nums\">{{ fidelityMetrics.similarity }}%</div>\n          <Progress :model-value=\"fidelityMetrics.similarity\" class=\"h-1.5\" />\n        </div>\n\n        <!-- Metric 2: Correlation Preservation -->\n        <div class=\"border-border/60 bg-muted/10 space-y-1.5 rounded-lg border p-3\">\n          <div class=\"text-muted-foreground flex items-center justify-between text-xs\">\n            <span>Covariance Retention</span>\n            <BarChart3 class=\"text-info size-3.5\" />\n          </div>\n          <div class=\"text-foreground font-mono text-lg font-bold tabular-nums\">\n            {{ fidelityMetrics.correlationRetention }}%\n          </div>\n          <Progress :model-value=\"fidelityMetrics.correlationRetention\" class=\"h-1.5\" />\n        </div>\n\n        <!-- Metric 3: Wasserstein Distance -->\n        <div class=\"border-border/60 bg-muted/10 space-y-1.5 rounded-lg border p-3\">\n          <div class=\"text-muted-foreground flex items-center justify-between text-xs\">\n            <span>Wasserstein Distance</span>\n            <Binary class=\"text-chart-1 size-3.5\" />\n          </div>\n          <div class=\"text-foreground font-mono text-lg font-bold tabular-nums\">\n            {{ fidelityMetrics.wassersteinDistance }}\n          </div>\n          <div class=\"text-muted-foreground text-xs\">Low error bound (&lt; 0.05)</div>\n        </div>\n      </CardContent>\n    </Card>\n\n    <!-- PREVIEW TABS CARD -->\n    <Card class=\"border-border shadow-xs\">\n      <CardHeader class=\"border-border/50 border-b pb-3\">\n        <div class=\"flex flex-wrap items-center justify-between gap-2\">\n          <div class=\"flex items-center gap-2\">\n            <div class=\"bg-muted text-muted-foreground flex size-7 items-center justify-center rounded-md\">\n              <TableIcon class=\"size-3.5\" />\n            </div>\n            <div>\n              <CardTitle class=\"text-sm font-semibold\">Live Generated Synthetic Data Preview</CardTitle>\n              <CardDescription class=\"text-xs\">\n                Real-time sampler showing first {{ previewRecords.length }} synthesized records\n              </CardDescription>\n            </div>\n          </div>\n\n          <!-- View Switcher -->\n          <Tabs\n            :model-value=\"previewTab\"\n            class=\"w-auto\"\n            @update:model-value=\"(val) => emit('update:previewTab', val as 'table' | 'json' | 'metrics')\"\n          >\n            <TabsList class=\"h-8\">\n              <TabsTrigger value=\"table\" class=\"h-7 px-2.5 text-xs\">\n                <TableIcon class=\"mr-1 size-3\" />\n                <span>Table</span>\n              </TabsTrigger>\n              <TabsTrigger value=\"json\" class=\"h-7 px-2.5 text-xs\">\n                <Code2 class=\"mr-1 size-3\" />\n                <span>JSONL</span>\n              </TabsTrigger>\n              <TabsTrigger value=\"metrics\" class=\"h-7 px-2.5 text-xs\">\n                <BarChart3 class=\"mr-1 size-3\" />\n                <span>Marginals</span>\n              </TabsTrigger>\n            </TabsList>\n          </Tabs>\n        </div>\n      </CardHeader>\n\n      <CardContent class=\"pt-4\">\n        <!-- TAB 1: TABULAR PREVIEW -->\n        <div v-if=\"previewTab === 'table'\" class=\"space-y-3\">\n          <div class=\"border-border overflow-hidden rounded-lg border\">\n            <div class=\"overflow-x-auto\">\n              <Table class=\"min-w-full text-xs\">\n                <TableHeader class=\"bg-muted/40\">\n                  <TableRow>\n                    <TableHead\n                      v-for=\"f in activeFields\"\n                      :key=\"f.id\"\n                      class=\"text-foreground font-mono text-xs font-semibold whitespace-nowrap\"\n                    >\n                      {{ f.name }}\n                    </TableHead>\n                  </TableRow>\n                </TableHeader>\n                <TableBody>\n                  <TableRow v-for=\"(row, idx) in previewRecords\" :key=\"idx\" class=\"hover:bg-muted/30 transition-colors\">\n                    <TableCell v-for=\"f in activeFields\" :key=\"f.id\" class=\"py-2.5 whitespace-nowrap\">\n                      <!-- Special cell styling based on data type -->\n                      <template\n                        v-if=\"\n                          f.name === 'id' ||\n                          f.name.includes('id') ||\n                          f.name.includes('uuid') ||\n                          f.name.includes('token')\n                        \"\n                      >\n                        <span class=\"text-muted-foreground font-mono font-medium\">{{ row[f.name] }}</span>\n                      </template>\n\n                      <template v-else-if=\"f.type === 'category_weights'\">\n                        <Badge variant=\"secondary\" class=\"font-mono text-xs font-medium\">\n                          {{ row[f.name] }}\n                        </Badge>\n                      </template>\n\n                      <template v-else-if=\"f.type === 'gaussian_float'\">\n                        <span class=\"text-foreground font-mono font-semibold tabular-nums\">\n                          {{ row[f.name] }}\n                        </span>\n                      </template>\n\n                      <template v-else-if=\"f.type === 'credit_card'\">\n                        <span class=\"text-foreground font-mono text-xs font-medium\">\n                          {{ row[f.name] }}\n                        </span>\n                      </template>\n\n                      <template v-else-if=\"f.type === 'email'\">\n                        <span class=\"text-primary font-mono text-xs font-normal\">\n                          {{ row[f.name] }}\n                        </span>\n                      </template>\n\n                      <template v-else>\n                        <span class=\"text-foreground font-medium\">{{ row[f.name] }}</span>\n                      </template>\n                    </TableCell>\n                  </TableRow>\n                </TableBody>\n              </Table>\n            </div>\n          </div>\n\n          <div class=\"text-muted-foreground flex flex-wrap items-center justify-between gap-2 px-1 text-xs\">\n            <span class=\"flex items-center gap-1.5 font-mono tabular-nums\">\n              <span class=\"bg-success size-1.5 rounded-full\" />\n              Showing {{ previewRecords.length }} sample records of {{ rowCount.toLocaleString() }} generated rows\n            </span>\n            <span class=\"text-muted-foreground font-mono text-xs\">Seed: #{{ generationSeed }}</span>\n          </div>\n        </div>\n\n        <!-- TAB 2: JSON LINES PREVIEW -->\n        <div v-else-if=\"previewTab === 'json'\" class=\"space-y-3\">\n          <div class=\"flex items-center justify-between\">\n            <span class=\"text-muted-foreground text-xs\">Streaming JSON Lines formatted output:</span>\n            <Button\n              variant=\"outline\"\n              size=\"sm\"\n              class=\"h-7.5 gap-1.5 px-2.5 text-xs font-medium\"\n              @click=\"emit('copyJsonLines')\"\n            >\n              <Check v-if=\"copied\" class=\"text-success size-3 stroke-[2.5]\" />\n              <Copy v-else class=\"size-3\" />\n              <span>{{ copied ? 'Copied JSONL' : 'Copy JSON Lines' }}</span>\n            </Button>\n          </div>\n\n          <div\n            class=\"border-border/80 bg-muted/40 max-h-[380px] overflow-x-auto overflow-y-auto rounded-lg border p-4 font-mono text-xs leading-relaxed\"\n          >\n            <div\n              v-for=\"(rec, idx) in previewRecords\"\n              :key=\"idx\"\n              class=\"hover:bg-muted/60 rounded px-1.5 py-1 whitespace-pre transition-colors\"\n            >\n              <span class=\"text-muted-foreground select-none\">{{ idx + 1 }}&nbsp;</span>\n              <span class=\"text-foreground\">{ </span>\n              <template v-for=\"(val, key, kIdx) in rec\" :key=\"key\">\n                <span class=\"text-info font-semibold\">\"{{ key }}\"</span>\n                <span class=\"text-muted-foreground\">: </span>\n                <span :class=\"typeof val === 'number' ? 'text-warning font-medium' : 'text-success'\">\n                  {{ typeof val === 'number' ? val : `\"${val}\"` }}\n                </span>\n                <span v-if=\"kIdx < Object.keys(rec).length - 1\" class=\"text-muted-foreground\">, </span>\n              </template>\n              <span class=\"text-foreground\"> }</span>\n            </div>\n          </div>\n        </div>\n\n        <!-- TAB 3: MARGINALS & FIDELITY DENSITY -->\n        <div v-else class=\"space-y-4\">\n          <div class=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n            <!-- Density Gauge 1 -->\n            <div class=\"border-border/60 bg-muted/20 space-y-2 rounded-lg border p-3.5\">\n              <div class=\"flex items-center justify-between text-xs\">\n                <span class=\"text-foreground font-semibold\">Gaussian Distribution Overlap</span>\n                <Badge variant=\"outline\" class=\"font-mono text-xs\">96.2%</Badge>\n              </div>\n              <p class=\"text-muted-foreground text-xs\">\n                Kolmogorov-Smirnov distance between synthetic batch and continuous Gaussian ground truth.\n              </p>\n              <Progress :model-value=\"96.2\" class=\"h-2\" />\n            </div>\n\n            <!-- Density Gauge 2 -->\n            <div class=\"border-border/60 bg-muted/20 space-y-2 rounded-lg border p-3.5\">\n              <div class=\"flex items-center justify-between text-xs\">\n                <span class=\"text-foreground font-semibold\">Categorical Frequency Prior</span>\n                <Badge variant=\"outline\" class=\"font-mono text-xs\">98.4%</Badge>\n              </div>\n              <p class=\"text-muted-foreground text-xs\">\n                Total variation distance across categorical weight assignments.\n              </p>\n              <Progress :model-value=\"98.4\" class=\"h-2\" />\n            </div>\n          </div>\n\n          <!-- Mathematical Guarantees Breakdown -->\n          <div class=\"border-border/60 bg-muted/10 space-y-2.5 rounded-lg border p-4 text-xs\">\n            <div class=\"text-foreground flex items-center gap-1.5 font-semibold\">\n              <Shield class=\"text-primary size-4\" />\n              <span>Mathematical Privacy Guarantees &bull; Formal Specs</span>\n            </div>\n            <div class=\"text-muted-foreground grid grid-cols-1 gap-2 sm:grid-cols-2\">\n              <div class=\"flex items-center gap-1.5\">\n                <Check class=\"text-success size-3.5\" />\n                <span>Differential Privacy (ε = {{ epsilon.toFixed(1) }}, δ = 10⁻⁵)</span>\n              </div>\n              <div class=\"flex items-center gap-1.5\">\n                <Check class=\"text-success size-3.5\" />\n                <span>K-Anonymity (k = 5) Cohort Clamping</span>\n              </div>\n              <div class=\"flex items-center gap-1.5\">\n                <Check class=\"text-success size-3.5\" />\n                <span>Zero Direct Row Memorization</span>\n              </div>\n              <div class=\"flex items-center gap-1.5\">\n                <Check class=\"text-success size-3.5\" />\n                <span>Ephemeral In-Memory Compute</span>\n              </div>\n            </div>\n          </div>\n        </div>\n      </CardContent>\n\n      <CardFooter\n        class=\"border-border/40 text-muted-foreground flex flex-wrap items-center justify-between border-t py-3 text-xs\"\n      >\n        <span class=\"flex items-center gap-1.5\">\n          <Zap class=\"text-warning size-3.5\" />\n          Powered by LLM Semantic Synthesis &amp; Laplace Noise Engine\n        </span>\n        <span class=\"font-mono tabular-nums\">\n          Output: {{ outputFormat.toUpperCase() }} &bull; {{ activeFields.length }} fields &bull;\n          {{ rowCount.toLocaleString() }} records\n        </span>\n      </CardFooter>\n    </Card>\n  </div>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/SyntheticDataPreview.vue"
    },
    {
      "path": "packages/registry-vue/blocks/synthetic-data-generator/synthetic-data-types.ts",
      "content": "import type { HTMLAttributes } from 'vue'\n\nexport type FieldDataType = 'name' | 'email' | 'credit_card' | 'gaussian_float' | 'date_range' | 'category_weights'\n\nexport interface SchemaField {\n  id: string\n  name: string\n  label: string\n  type: FieldDataType\n  description?: string\n  params: {\n    mean?: number\n    stdDev?: number\n    currency?: string\n    unit?: string\n    categories?: string[]\n    weights?: number[]\n    domain?: string\n    dateStart?: string\n    dateEnd?: string\n  }\n}\n\nexport interface TemplatePreset {\n  id: string\n  name: string\n  description: string\n  category: string\n  fields: SchemaField[]\n}\n\nexport interface GeneratedRecord {\n  id: string\n  [key: string]: string | number\n}\n\nexport interface FidelityMetrics {\n  similarity: number\n  leakageRisk: string\n  correlationRetention: number\n  wassersteinDistance: number\n  laplaceNoiseStd: string\n  privacyTier: string\n  privacyBadgeColor: string\n}\n\nexport interface SyntheticDataGeneratorProps {\n  class?: HTMLAttributes['class']\n  initialTemplate?: string\n  initialRowCount?: number\n  initialEpsilon?: number\n}\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/synthetic-data-types.ts"
    },
    {
      "path": "packages/registry-vue/blocks/synthetic-data-generator/synthetic-data-templates.ts",
      "content": "import type { TemplatePreset } from './synthetic-data-types'\n\nexport const TEMPLATES: Record<string, TemplatePreset> = {\n  'customer-transactions': {\n    id: 'customer-transactions',\n    name: 'Customer Transactions & Demographics Dataset',\n    description:\n      'High-dimensional e-commerce customer cohort, synthetic PII, spending distribution, and country codes.',\n    category: 'E-Commerce & Retail',\n    fields: [\n      {\n        id: 'f-id',\n        name: 'cust_id',\n        label: 'Customer ID',\n        type: 'name',\n        description: 'Salted pseudonymized primary key',\n        params: {},\n      },\n      {\n        id: 'f-name',\n        name: 'full_name',\n        label: 'Full Name',\n        type: 'name',\n        description: 'Synthetic person name generator',\n        params: {},\n      },\n      {\n        id: 'f-email',\n        name: 'email_address',\n        label: 'Synthetic Email',\n        type: 'email',\n        description: 'Faker email with domain isolation',\n        params: { domain: 'syn-corp.io' },\n      },\n      {\n        id: 'f-card',\n        name: 'masked_card',\n        label: 'Card PAN',\n        type: 'credit_card',\n        description: 'Luhn-compliant masked payment token',\n        params: {},\n      },\n      {\n        id: 'f-spend',\n        name: 'spending_amount',\n        label: 'Spending Amount',\n        type: 'gaussian_float',\n        description: 'Gaussian spending curve (μ=$342.50, σ=$85.20)',\n        params: { mean: 342.5, stdDev: 85.2, currency: '$' },\n      },\n      {\n        id: 'f-country',\n        name: 'country_code',\n        label: 'Country Region',\n        type: 'category_weights',\n        description: 'Categorical distribution [US, DE, GB, FR, JP]',\n        params: {\n          categories: ['US', 'DE', 'GB', 'FR', 'JP'],\n          weights: [0.45, 0.2, 0.15, 0.1, 0.1],\n        },\n      },\n      {\n        id: 'f-created',\n        name: 'created_at',\n        label: 'Registration Date',\n        type: 'date_range',\n        description: 'ISO-8601 timestamp range (2024-2025)',\n        params: { dateStart: '2024-01-01', dateEnd: '2025-08-20' },\n      },\n    ],\n  },\n  'healthcare-ehr': {\n    id: 'healthcare-ehr',\n    name: 'Healthcare Patient Clinical Records (EHR)',\n    description: 'HIPAA-compliant patient cohort with biomarker telemetry, blood pressure, and triage severity tiers.',\n    category: 'Healthcare & Life Sciences',\n    fields: [\n      {\n        id: 'f-h-id',\n        name: 'patient_id',\n        label: 'Patient ID',\n        type: 'name',\n        description: 'Deterministic HIPAA salted identifier',\n        params: {},\n      },\n      {\n        id: 'f-h-name',\n        name: 'patient_name',\n        label: 'Patient Name',\n        type: 'name',\n        description: 'Synthetic medical record moniker',\n        params: {},\n      },\n      {\n        id: 'f-h-email',\n        name: 'contact_email',\n        label: 'Contact Email',\n        type: 'email',\n        description: 'Synthetic provider contact',\n        params: { domain: 'med-synthetic.org' },\n      },\n      {\n        id: 'f-h-glucose',\n        name: 'blood_glucose',\n        label: 'Glucose (mg/dL)',\n        type: 'gaussian_float',\n        description: 'Fast fasting blood glucose (μ=108.4, σ=22.1)',\n        params: { mean: 108.4, stdDev: 22.1, unit: 'mg/dL' },\n      },\n      {\n        id: 'f-h-bp',\n        name: 'systolic_bp',\n        label: 'Systolic BP',\n        type: 'gaussian_float',\n        description: 'Arterial blood pressure (μ=124.0, σ=15.5)',\n        params: { mean: 124.0, stdDev: 15.5, unit: 'mmHg' },\n      },\n      {\n        id: 'f-h-tier',\n        name: 'triage_tier',\n        label: 'Triage Severity',\n        type: 'category_weights',\n        description: 'Clinical priority classification',\n        params: {\n          categories: ['Routine', 'Elevated', 'Urgent', 'Critical'],\n          weights: [0.52, 0.28, 0.14, 0.06],\n        },\n      },\n      {\n        id: 'f-h-date',\n        name: 'admission_date',\n        label: 'Admission Date',\n        type: 'date_range',\n        description: 'Encounter timestamps',\n        params: { dateStart: '2024-06-01', dateEnd: '2025-08-20' },\n      },\n    ],\n  },\n  'fintech-fraud': {\n    id: 'fintech-fraud',\n    name: 'Fintech Fraud Detection & Risk Scoring',\n    description: 'Transaction monitoring telemetry for anti-fraud classifiers with skewed anomalous patterns.',\n    category: 'Fintech & Risk',\n    fields: [\n      {\n        id: 'f-ff-id',\n        name: 'tx_token',\n        label: 'Transaction ID',\n        type: 'name',\n        description: 'Cryptographic ledger token',\n        params: {},\n      },\n      {\n        id: 'f-ff-name',\n        name: 'merchant_name',\n        label: 'Merchant Name',\n        type: 'name',\n        description: 'Synthetic counterparty vendor',\n        params: {},\n      },\n      {\n        id: 'f-ff-email',\n        name: 'auth_email',\n        label: 'Auth Email',\n        type: 'email',\n        description: 'Tokenized transaction origin email',\n        params: { domain: 'syn-pay.net' },\n      },\n      {\n        id: 'f-ff-card',\n        name: 'card_pan',\n        label: 'Card PAN',\n        type: 'credit_card',\n        description: 'Tokenized 16-digit card surrogate',\n        params: {},\n      },\n      {\n        id: 'f-ff-amt',\n        name: 'settlement_usd',\n        label: 'Settlement ($)',\n        type: 'gaussian_float',\n        description: 'Transaction gross volume (μ=$1420.00, σ=$480.00)',\n        params: { mean: 1420.0, stdDev: 480.0, currency: '$' },\n      },\n      {\n        id: 'f-ff-verdict',\n        name: 'risk_verdict',\n        label: 'Risk Verdict',\n        type: 'category_weights',\n        description: 'Ground truth classifier target',\n        params: {\n          categories: ['Legitimate', 'Suspicious', 'Flagged_Fraud'],\n          weights: [0.89, 0.08, 0.03],\n        },\n      },\n      {\n        id: 'f-ff-ts',\n        name: 'settled_at',\n        label: 'Settlement Time',\n        type: 'date_range',\n        description: 'High-precision event timestamp',\n        params: { dateStart: '2025-01-01', dateEnd: '2025-08-20' },\n      },\n    ],\n  },\n  'saas-telemetry': {\n    id: 'saas-telemetry',\n    name: 'SaaS Product Telemetry & Usage Metrics',\n    description: 'B2B subscription telemetry with active seat distribution, recurring revenue, and subscription tiers.',\n    category: 'Cloud Software & B2B',\n    fields: [\n      {\n        id: 'f-st-id',\n        name: 'org_uuid',\n        label: 'Organization UUID',\n        type: 'name',\n        description: 'Tenant identifier',\n        params: {},\n      },\n      {\n        id: 'f-st-name',\n        name: 'tenant_name',\n        label: 'Tenant Name',\n        type: 'name',\n        description: 'Synthetic enterprise tenant moniker',\n        params: {},\n      },\n      {\n        id: 'f-st-email',\n        name: 'admin_email',\n        label: 'Admin Email',\n        type: 'email',\n        description: 'Primary owner email',\n        params: { domain: 'syn-saas.io' },\n      },\n      {\n        id: 'f-st-seats',\n        name: 'active_seats',\n        label: 'Active Seats',\n        type: 'gaussian_float',\n        description: 'Provisioned enterprise seats (μ=48.0, σ=18.0)',\n        params: { mean: 48.0, stdDev: 18.0, unit: 'seats' },\n      },\n      {\n        id: 'f-st-mrr',\n        name: 'mrr_usd',\n        label: 'Monthly Revenue',\n        type: 'gaussian_float',\n        description: 'MRR ledger (μ=$2850.00, σ=$950.00)',\n        params: { mean: 2850.0, stdDev: 950.0, currency: '$' },\n      },\n      {\n        id: 'f-st-plan',\n        name: 'plan_tier',\n        label: 'Plan Tier',\n        type: 'category_weights',\n        description: 'Subscription entitlement level',\n        params: {\n          categories: ['Starter', 'Growth', 'Enterprise'],\n          weights: [0.48, 0.36, 0.16],\n        },\n      },\n      {\n        id: 'f-st-date',\n        name: 'provisioned_at',\n        label: 'Provisioned Date',\n        type: 'date_range',\n        description: 'Cohort subscription activation',\n        params: { dateStart: '2024-01-01', dateEnd: '2025-08-20' },\n      },\n    ],\n  },\n}\n\nexport const FIRST_NAMES = [\n  'Elena',\n  'Malik',\n  'Siddharth',\n  'Claire',\n  'Liam',\n  'Amara',\n  'Kenji',\n  'Sofia',\n  'Devon',\n  'Maya',\n  'Tobias',\n  'Fatima',\n  'Mateo',\n  'Astrid',\n  'Zara',\n]\n\nexport const LAST_NAMES = [\n  'Rostova',\n  'Al-Mansoor',\n  'Patel',\n  'Chen',\n  \"O'Connor\",\n  'Okafor',\n  'Sato',\n  'Alvarez',\n  'Vance',\n  'Lin',\n  'Richter',\n  'Zahra',\n  'Silva',\n  'Lindqvist',\n  'Novak',\n]\n\nexport const CARD_BRANDS = ['Visa', 'Mastercard', 'Amex']\n\nexport function boxMullerRandom(\n  mean: number,\n  stdDev: number,\n  seedOffset: number,\n  seed: number,\n  noiseMechanism: boolean,\n  epsilon: number,\n): number {\n  const u1 = Math.max(1e-6, Math.abs(Math.sin(seed + seedOffset * 17.3)))\n  const u2 = Math.max(1e-6, Math.abs(Math.cos(seed + seedOffset * 31.7)))\n  const z0 = Math.sqrt(-2.0 * Math.log(u1)) * Math.cos(2.0 * Math.PI * u2)\n\n  const dpNoiseScale = noiseMechanism ? stdDev / (Math.max(0.1, epsilon) * 12) : 0\n  const dpNoise = Math.sin(seed * 3.7 + seedOffset * 5.1) * dpNoiseScale\n\n  return mean + z0 * stdDev + dpNoise\n}\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/synthetic-data-templates.ts"
    }
  ],
  "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/input.json",
    "https://uipkge.dev/r/vue/progress.json",
    "https://uipkge.dev/r/vue/select.json",
    "https://uipkge.dev/r/vue/separator.json",
    "https://uipkge.dev/r/vue/slider.json",
    "https://uipkge.dev/r/vue/switch.json",
    "https://uipkge.dev/r/vue/table.json",
    "https://uipkge.dev/r/vue/tabs.json"
  ],
  "description": "Gretel and Tonic-style LLM and mathematical synthetic dataset generator with differential privacy epsilon controls, custom schema field builders, K-anonymity policy toggles, live tabular CSV preview, and streaming JSON Lines export.",
  "categories": [
    "ai",
    "data",
    "app",
    "security"
  ]
}