{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "audit-event-stream",
  "title": "Audit Event Stream",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/audit-event-stream/audit-event-stream.component.ts",
      "content": "import { ChangeDetectionStrategy, Component, Input, OnInit, computed, signal } from '@angular/core'\nimport {\n  Activity,\n  AlertCircle,\n  AlertTriangle,\n  Check,\n  ChevronDown,\n  ChevronRight,\n  Download,\n  Filter,\n  Info,\n  Layers,\n  LucideAngularModule,\n  Pause,\n  Play,\n  RotateCcw,\n  Search,\n  Shield,\n  ShieldAlert,\n  Trash2,\n  Zap,\n} from 'lucide-angular'\nimport { cn } from '@/lib/utils'\nimport { UiAvatarComponent, UiAvatarFallbackComponent } from '@/ui/avatar/avatar.component'\nimport { UiBadgeComponent } from '@/ui/badge/badge.component'\nimport { UiButtonComponent } from '@/ui/button/button.component'\nimport { UiCardComponent, UiCardContentComponent } from '@/ui/card/card.component'\nimport { UiInputComponent } from '@/ui/input/input.component'\nimport { UiSeparatorComponent } from '@/ui/separator/separator.component'\nimport { UiEventDetailDrawerComponent } from './event-detail-drawer.component'\n\nexport type EventSeverity = 'info' | 'warning' | 'critical'\n\nexport interface AuditStreamEvent {\n  id: string\n  timestamp: string\n  severity: EventSeverity\n  action: string\n  actor: {\n    name: string\n    type: 'user' | 'service' | 'system'\n  }\n  sourceIp: string\n  geo: string\n  target: string\n  summary: string\n  metadata: Record<string, unknown>\n}\n\nconst defaultEvents: AuditStreamEvent[] = [\n  {\n    id: 'evt-1094',\n    timestamp: '2026-08-21T14:32:05.812Z',\n    severity: 'critical',\n    action: 'policy.access.denied',\n    actor: {\n      name: 'd.vader@contractor.io',\n      type: 'user',\n    },\n    sourceIp: '45.33.32.156',\n    geo: 'AP-East (HK)',\n    target: 'arn:aws:s3:::prod-customer-pii-cold-storage/*',\n    summary: 'Cross-boundary access violation to restricted cold storage bucket',\n    metadata: {\n      request_id: 'req_88f912c9a01',\n      resource_arn: 'arn:aws:s3:::prod-customer-pii-cold-storage/*',\n      requested_action: 's3:GetObject',\n      violation_code: 'UNAUTHORIZED_GEOLOCATION_ACCESS',\n      risk_score: 94,\n      enforcement: 'blocked_by_guardduty',\n      user_agent: 'aws-cli/2.15.30 Python/3.11.8 Darwin/24.1.0',\n    },\n  },\n  {\n    id: 'evt-1093',\n    timestamp: '2026-08-21T14:31:58.240Z',\n    severity: 'critical',\n    action: 'vpc.security_group.ingress_created',\n    actor: {\n      name: 'devops-ci-orchestrator',\n      type: 'service',\n    },\n    sourceIp: '172.31.0.4',\n    geo: 'EU-West (IE)',\n    target: 'sg-08f912c9aa30 (prod-bastion-sg)',\n    summary: 'Security group rule added opening SSH (0.0.0.0/0:22) to public internet',\n    metadata: {\n      request_id: 'req_39b201a44e',\n      security_group_id: 'sg-08f912c9aa30',\n      rule: {\n        protocol: 'tcp',\n        from_port: 22,\n        to_port: 22,\n        cidr: '0.0.0.0/0',\n      },\n      compliance_impact: 'NON_COMPLIANT_SOC2_CC6',\n      alert: 'AUTOMATIC_SECURITY_REMEDIATION_TRIGGERED',\n      quarantine_status: 'isolated_pending_approval',\n    },\n  },\n  {\n    id: 'evt-1092',\n    timestamp: '2026-08-21T14:31:44.102Z',\n    severity: 'warning',\n    action: 'api.rate_limit.exceeded',\n    actor: {\n      name: 'api-gateway-edge',\n      type: 'service',\n    },\n    sourceIp: '203.0.113.195',\n    geo: 'EU-Central (FRA)',\n    target: 'api.acme.com/v2/organizations/billing/sync',\n    summary: 'Customer exceeded tier rate limit of 10,000 req/min (current: 14,820 req/min)',\n    metadata: {\n      request_id: 'req_a44019bf08',\n      client_id: 'app_pub_8829104',\n      tier: 'pro_tier',\n      limit: '10,000 req/min',\n      current_rate: '14,820 req/min',\n      burst_allowance: 'exhausted',\n      enforced_action: 'http_429_throttled',\n      retry_after_seconds: 45,\n    },\n  },\n  {\n    id: 'evt-1091',\n    timestamp: '2026-08-21T14:31:22.955Z',\n    severity: 'warning',\n    action: 'auth.mfa.challenge_failed',\n    actor: {\n      name: 'marcus.lee@acme.corp',\n      type: 'user',\n    },\n    sourceIp: '192.0.2.142',\n    geo: 'US-West (SFO)',\n    target: 'identity.acme.corp/mfa/challenge',\n    summary: 'Multiple consecutive invalid TOTP code attempts detected',\n    metadata: {\n      request_id: 'req_77d812ef90',\n      user_id: 'usr_8830192a',\n      attempt_count: 3,\n      max_allowed: 5,\n      failure_reason: 'totp_token_mismatch',\n      client_fingerprint: 'fp_993b2a0018f',\n      risk_flag: 'SUSPICIOUS_DEVICE_FINGERPRINT',\n    },\n  },\n  {\n    id: 'evt-1090',\n    timestamp: '2026-08-21T14:31:05.419Z',\n    severity: 'warning',\n    action: 'storage.bucket.policy_updated',\n    actor: {\n      name: 'elena.rostova@acme.corp',\n      type: 'user',\n    },\n    sourceIp: '84.190.201.3',\n    geo: 'EU-Central (BER)',\n    target: 'prod-exports-transfers-bucket',\n    summary: 'CORS origins and bucket policy permissions updated',\n    metadata: {\n      request_id: 'req_1204891ff3',\n      bucket: 'prod-exports-transfers-bucket',\n      changes: {\n        public_read: false,\n        cors_origins: ['https://app.acme.com', 'https://staging.acme.com'],\n        ssl_enforced: true,\n      },\n      review_status: 'PENDING_AUDIT_SIGNOFF',\n    },\n  },\n  {\n    id: 'evt-1089',\n    timestamp: '2026-08-21T14:30:48.331Z',\n    severity: 'info',\n    action: 'iam.user.login_success',\n    actor: {\n      name: 'sarah.connor@acme.corp',\n      type: 'user',\n    },\n    sourceIp: '198.51.100.24',\n    geo: 'US-East (NYC)',\n    target: 'auth.acme.corp/oauth/callback',\n    summary: 'Successful SAML SSO login with WebAuthn hardware token verification',\n    metadata: {\n      request_id: 'req_66c29188e1',\n      auth_provider: 'okta_saml_enterprise',\n      mfa_type: 'fido2_yubikey',\n      session_id: 'sess_9f82c1a003',\n      user_agent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 14_4) AppleWebKit/537.36',\n    },\n  },\n  {\n    id: 'evt-1088',\n    timestamp: '2026-08-21T14:30:19.780Z',\n    severity: 'info',\n    action: 'db.secret.rotated',\n    actor: {\n      name: 'vault-agent-worker',\n      type: 'service',\n    },\n    sourceIp: '10.240.12.88',\n    geo: 'US-West (OR)',\n    target: 'kv/prod/aurora-primary/credentials',\n    summary: 'Automated 30-day credential rotation for primary PostgreSQL cluster',\n    metadata: {\n      request_id: 'req_55104882c9',\n      vault_cluster: 'prod-vault-cluster-01',\n      path: 'kv/prod/aurora-primary/credentials',\n      ttl_seconds: 2592000,\n      databases_updated: ['aurora-writer-01', 'aurora-reader-01', 'aurora-reader-02'],\n      status: 'ROTATION_SUCCESS',\n    },\n  },\n  {\n    id: 'evt-1087',\n    timestamp: '2026-08-21T14:29:55.104Z',\n    severity: 'info',\n    action: 'repo.deployment.started',\n    actor: {\n      name: 'github-actions[bot]',\n      type: 'service',\n    },\n    sourceIp: '140.82.112.22',\n    geo: 'US-East (IAD)',\n    target: 'uipkge/core-registry:main (a3f89b1)',\n    summary: 'Production deployment triggered via merge pull request #412',\n    metadata: {\n      request_id: 'req_44910283aa',\n      repository: 'uipkge/core-registry',\n      commit_hash: 'a3f89b14e9f',\n      environment: 'production',\n      pipeline_id: 'pipe_883019',\n      runner: 'runner-edge-iad-4',\n    },\n  },\n  {\n    id: 'evt-1086',\n    timestamp: '2026-08-21T14:29:12.650Z',\n    severity: 'info',\n    action: 'kms.key.decrypted',\n    actor: {\n      name: 'payment-service-daemon',\n      type: 'service',\n    },\n    sourceIp: '10.128.4.19',\n    geo: 'US-East (VA)',\n    target: 'arn:aws:kms:us-east-1:992019482:key/cmk-cardholder-01',\n    summary: 'Authorized envelope decryption operation for card tokenization',\n    metadata: {\n      request_id: 'req_338192001e',\n      key_arn: 'arn:aws:kms:us-east-1:992019482:key/cmk-cardholder-01',\n      algorithm: 'AES_GCM_256',\n      caller_service: 'checkout-v2-pod-88x',\n      auth_context: { transaction_id: 'tx_9981203', environment: 'production' },\n    },\n  },\n  {\n    id: 'evt-1085',\n    timestamp: '2026-08-21T14:28:40.091Z',\n    severity: 'info',\n    action: 'service.token.revoked',\n    actor: {\n      name: 'security-automations',\n      type: 'system',\n    },\n    sourceIp: '127.0.0.1',\n    geo: 'Internal',\n    target: 'tok_expired_929104882',\n    summary: 'Routine cleanup revoked expired machine-to-machine JWT token',\n    metadata: {\n      request_id: 'req_227198300a',\n      token_id: 'tok_expired_929104882',\n      reason: 'ttl_expiration',\n      issued_at: '2026-08-14T00:00:00Z',\n      revoked_by: 'system_cron_daemon',\n    },\n  },\n]\n\nfunction initials(name: string): string {\n  if (name.includes('@')) {\n    return name.slice(0, 2).toUpperCase()\n  }\n  return (\n    name\n      .replace(/[^a-zA-Z0-9\\s]/g, '')\n      .split(' ')\n      .filter(Boolean)\n      .map((part) => part[0])\n      .slice(0, 2)\n      .join('')\n      .toUpperCase() || 'SA'\n  )\n}\n\nfunction matchesSearch(event: AuditStreamEvent, query: string): boolean {\n  if (!query.trim()) return true\n  const q = query.trim()\n\n  if (q.startsWith('/') && q.length > 1) {\n    const lastSlash = q.lastIndexOf('/')\n    if (lastSlash > 0) {\n      const pattern = q.slice(1, lastSlash)\n      const flags = q.slice(lastSlash + 1)\n      try {\n        const re = new RegExp(pattern, flags)\n        return (\n          re.test(event.action) ||\n          re.test(event.actor.name) ||\n          re.test(event.sourceIp) ||\n          re.test(event.geo) ||\n          re.test(event.target) ||\n          re.test(event.summary) ||\n          re.test(JSON.stringify(event.metadata))\n        )\n      } catch {\n        // Fall back to plain search on invalid regex syntax\n      }\n    }\n  }\n\n  const lower = q.toLowerCase()\n  return (\n    event.action.toLowerCase().includes(lower) ||\n    event.actor.name.toLowerCase().includes(lower) ||\n    event.sourceIp.toLowerCase().includes(lower) ||\n    event.geo.toLowerCase().includes(lower) ||\n    event.target.toLowerCase().includes(lower) ||\n    event.summary.toLowerCase().includes(lower) ||\n    JSON.stringify(event.metadata).toLowerCase().includes(lower)\n  )\n}\n\nfunction formatTimestamp(iso: string): string {\n  try {\n    const d = new Date(iso)\n    return d.toISOString().replace('T', ' ').replace('Z', ' UTC')\n  } catch {\n    return iso\n  }\n}\n\nconst PILL_BASE =\n  'focus-visible:ring-ring inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none'\n\n/**\n * AuditEventStream -- the React block, 1:1: live audit log viewer with pause/resume,\n * regex + keyword search, severity filter pills, expandable JSON payload rows and\n * ingestion telemetry stats.\n */\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-audit-event-stream, [ui-audit-event-stream]',\n  standalone: true,\n  host: { class: 'block' },\n  imports: [\n    LucideAngularModule,\n    UiAvatarComponent,\n    UiAvatarFallbackComponent,\n    UiBadgeComponent,\n    UiButtonComponent,\n    UiCardComponent,\n    UiCardContentComponent,\n    UiInputComponent,\n    UiSeparatorComponent,\n    UiEventDetailDrawerComponent,\n  ],\n  template: `\n    <div data-slot=\"audit-event-stream\" [class]=\"rootClass\">\n      <!-- Top Header & Live Telemetry Status -->\n      <div class=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n        <div class=\"flex items-center gap-3\">\n          <div class=\"bg-card flex size-10 items-center justify-center rounded-lg border shadow-xs\">\n            <lucide-icon [img]=\"ShieldAlert\" class=\"text-primary size-5\" aria-hidden=\"true\" />\n          </div>\n          <div>\n            <div class=\"flex items-center gap-2\">\n              <h2 class=\"text-2xl font-bold tracking-tight\">Audit Event Stream</h2>\n              @if (!isPaused()) {\n                <div\n                  class=\"border-success/30 bg-success/10 text-success inline-flex items-center gap-1.5 rounded-full border px-2.5 py-0.5 text-xs font-medium\"\n                >\n                  <span class=\"relative flex size-2 shrink-0\">\n                    <span class=\"bg-success absolute inline-flex h-full w-full rounded-full opacity-75\"></span>\n                    <span class=\"bg-success relative inline-flex size-2 rounded-full\"></span>\n                  </span>\n                  Live Stream · Connected\n                </div>\n              } @else {\n                <div\n                  class=\"border-warning/30 bg-warning/10 text-warning inline-flex items-center gap-1.5 rounded-full border px-2.5 py-0.5 text-xs font-medium\"\n                >\n                  <span class=\"bg-warning relative inline-flex size-2 rounded-full\"></span>\n                  Stream Paused\n                </div>\n              }\n            </div>\n            <p class=\"text-muted-foreground text-xs\">\n              Real-time security telemetry feed and structured audit trail inspector\n            </p>\n          </div>\n        </div>\n\n        <div class=\"flex flex-wrap items-center gap-2\">\n          <button\n            ui-button\n            variant=\"outline\"\n            size=\"sm\"\n            [class]=\"isPaused() ? 'border-warning/40 text-warning' : ''\"\n            (click)=\"togglePause()\"\n          >\n            @if (isPaused()) {\n              <lucide-icon [img]=\"Play\" class=\"size-3.5 fill-current\" aria-hidden=\"true\" />\n            } @else {\n              <lucide-icon [img]=\"Pause\" class=\"size-3.5\" aria-hidden=\"true\" />\n            }\n            <span>{{ isPaused() ? 'Resume Stream' : 'Pause Stream' }}</span>\n          </button>\n\n          <button ui-button variant=\"outline\" size=\"sm\" [disabled]=\"events().length === 0\" (click)=\"clearStream()\">\n            <lucide-icon [img]=\"Trash2\" class=\"size-3.5\" aria-hidden=\"true\" />\n            <span>Clear Stream</span>\n          </button>\n\n          <button\n            ui-button\n            aria-label=\"Download attachment\"\n            variant=\"default\"\n            size=\"sm\"\n            [disabled]=\"filteredEvents().length === 0\"\n            (click)=\"exportJson()\"\n          >\n            @if (exportedNotice()) {\n              <lucide-icon [img]=\"Check\" class=\"text-success size-3.5\" aria-hidden=\"true\" />\n            } @else {\n              <lucide-icon [img]=\"Download\" class=\"size-3.5\" aria-hidden=\"true\" />\n            }\n            <span>{{ exportedNotice() ? 'Exported JSON' : 'Export JSON' }}</span>\n          </button>\n        </div>\n      </div>\n\n      <!-- Filter & Search Toolbar -->\n      <ui-card class=\"border-border shadow-xs\">\n        <ui-card-content class=\"p-3\">\n          <div class=\"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between\">\n            <!-- Search Input with Regex Support -->\n            <div class=\"relative flex-1\">\n              <lucide-icon\n                [img]=\"Search\"\n                class=\"text-muted-foreground pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2\"\n                aria-hidden=\"true\"\n              />\n              <ui-input\n                [value]=\"searchQuery()\"\n                (valueChange)=\"searchQuery.set($event)\"\n                placeholder=\"Search event action, actor, IP, target, or /regex/...\"\n                class=\"pl-9 text-xs\"\n              />\n            </div>\n\n            <!-- Severity Filter Pills -->\n            <div class=\"flex flex-wrap items-center gap-1.5\">\n              <span class=\"text-muted-foreground mr-1 flex items-center gap-1 text-xs font-medium\">\n                <lucide-icon [img]=\"Filter\" class=\"size-3\" aria-hidden=\"true\" />\n                Severity:\n              </span>\n\n              <button type=\"button\" [class]=\"pillClass('all')\" (click)=\"selectedSeverity.set('all')\">\n                All\n                <span [class]=\"countClass('all')\">{{ severityCounts().all }}</span>\n              </button>\n\n              <button type=\"button\" [class]=\"pillClass('critical')\" (click)=\"selectedSeverity.set('critical')\">\n                <span class=\"bg-destructive size-1.5 rounded-full\"></span>\n                Critical\n                <span [class]=\"countClass('critical')\">{{ severityCounts().critical }}</span>\n              </button>\n\n              <button type=\"button\" [class]=\"pillClass('warning')\" (click)=\"selectedSeverity.set('warning')\">\n                <span class=\"bg-warning size-1.5 rounded-full\"></span>\n                Warning\n                <span [class]=\"countClass('warning')\">{{ severityCounts().warning }}</span>\n              </button>\n\n              <button type=\"button\" [class]=\"pillClass('info')\" (click)=\"selectedSeverity.set('info')\">\n                <span class=\"bg-info size-1.5 rounded-full\"></span>\n                Info\n                <span [class]=\"countClass('info')\">{{ severityCounts().info }}</span>\n              </button>\n            </div>\n          </div>\n        </ui-card-content>\n      </ui-card>\n\n      <!-- Main Log Stream Feed Terminal Card -->\n      <ui-card class=\"border-border shadow-xs\">\n        <!-- Terminal Header Bar -->\n        <div class=\"bg-muted/40 flex items-center justify-between gap-x-2 border-b px-4 py-2.5\">\n          <div class=\"flex items-center gap-2\">\n            <div class=\"flex items-center gap-1.5\">\n              <span class=\"bg-destructive/80 size-2.5 rounded-full\"></span>\n              <span class=\"bg-warning/80 size-2.5 rounded-full\"></span>\n              <span class=\"bg-success/80 size-2.5 rounded-full\"></span>\n            </div>\n            <span class=\"text-muted-foreground font-mono text-xs\">\n              telemetry-stream-us-east-1 · ingester-v2 · tcp+tls\n            </span>\n          </div>\n\n          <div class=\"flex items-center gap-3\">\n            <span class=\"text-muted-foreground hidden font-mono text-xs sm:inline\">\n              Matches: {{ filteredEvents().length }} / {{ events().length }}\n            </span>\n            <button\n              ui-button\n              variant=\"ghost\"\n              size=\"xs\"\n              class=\"h-6 gap-1 px-2 text-xs\"\n              [disabled]=\"filteredEvents().length === 0\"\n              (click)=\"toggleAllExpand()\"\n            >\n              @if (allExpanded()) {\n                <lucide-icon [img]=\"ChevronDown\" class=\"size-3\" aria-hidden=\"true\" />\n              } @else {\n                <lucide-icon [img]=\"ChevronRight\" class=\"size-3\" aria-hidden=\"true\" />\n              }\n              <span>{{ allExpanded() ? 'Collapse All' : 'Expand All' }}</span>\n            </button>\n          </div>\n        </div>\n\n        <!-- Feed Rows Container -->\n        <ui-card-content class=\"p-0\">\n          @if (filteredEvents().length === 0) {\n            <!-- Empty State when 0 matching events -->\n            <div class=\"flex flex-col items-center justify-center gap-3 px-4 py-16 text-center\">\n              <div class=\"bg-muted flex size-12 items-center justify-center rounded-full\">\n                <lucide-icon [img]=\"Shield\" class=\"text-muted-foreground size-6 opacity-60\" aria-hidden=\"true\" />\n              </div>\n              <div class=\"space-y-1\">\n                <p class=\"text-foreground text-sm font-semibold\">No audit events match your criteria</p>\n                <p class=\"text-muted-foreground text-xs\">\n                  {{\n                    events().length === 0\n                      ? 'The event buffer was cleared. Restore default stream data to resume inspection.'\n                      : 'Try loosening your severity filter or search query.'\n                  }}\n                </p>\n              </div>\n              <button ui-button variant=\"outline\" size=\"sm\" class=\"mt-2 text-xs\" (click)=\"resetStream()\">\n                <lucide-icon [img]=\"RotateCcw\" class=\"size-3.5\" aria-hidden=\"true\" />\n                Restore stream data\n              </button>\n            </div>\n          } @else {\n            <ul class=\"divide-border/60 divide-y\">\n              @for (event of filteredEvents(); track event.id) {\n                <li [class]=\"rowClass(event.id)\">\n                  <!-- Primary Row Trigger -->\n                  <div\n                    role=\"button\"\n                    tabindex=\"0\"\n                    [attr.aria-expanded]=\"isExpanded(event.id)\"\n                    class=\"focus-visible:ring-ring flex cursor-pointer flex-col gap-3 p-3.5 focus-visible:ring-2 focus-visible:outline-none focus-visible:ring-inset sm:flex-row sm:items-center sm:justify-between\"\n                    (click)=\"toggleExpand(event.id)\"\n                    (keydown)=\"onRowKeydown($event, event.id)\"\n                  >\n                    <!-- Left Rail: Expand Indicator + Timestamp + Severity + Action -->\n                    <div class=\"flex min-w-0 items-start gap-3 sm:items-center\">\n                      <button type=\"button\" aria-label=\"Toggle payload details\" [class]=\"chevronClass(event.id)\">\n                        <lucide-icon [img]=\"ChevronRight\" class=\"size-4\" aria-hidden=\"true\" />\n                      </button>\n\n                      <div class=\"space-y-1 sm:space-y-0.5\">\n                        <div class=\"flex flex-wrap items-center gap-2\">\n                          <span class=\"text-muted-foreground font-mono text-xs whitespace-nowrap\">\n                            {{ formatTimestamp(event.timestamp) }}\n                          </span>\n\n                          @if (event.severity === 'critical') {\n                            <span ui-badge variant=\"destructive\" class=\"gap-1 font-mono text-xs uppercase\">\n                              <lucide-icon [img]=\"AlertCircle\" class=\"size-3\" aria-hidden=\"true\" />\n                              CRIT\n                            </span>\n                          } @else if (event.severity === 'warning') {\n                            <span ui-badge variant=\"warning\" class=\"gap-1 font-mono text-xs uppercase\">\n                              <lucide-icon [img]=\"AlertTriangle\" class=\"size-3\" aria-hidden=\"true\" />\n                              WARN\n                            </span>\n                          } @else {\n                            <span ui-badge variant=\"info\" class=\"gap-1 font-mono text-xs uppercase\">\n                              <lucide-icon [img]=\"Info\" class=\"size-3\" aria-hidden=\"true\" />\n                              INFO\n                            </span>\n                          }\n\n                          <span class=\"text-foreground font-mono text-xs font-semibold\">{{ event.action }}</span>\n                        </div>\n\n                        <p class=\"text-muted-foreground text-xs font-normal\">{{ event.summary }}</p>\n                      </div>\n                    </div>\n\n                    <!-- Right Rail: Actor Avatar & Tag + IP & Geo Flag -->\n                    <div class=\"flex shrink-0 flex-wrap items-center gap-3 sm:justify-end\">\n                      <div class=\"bg-muted/60 flex items-center gap-1.5 rounded-md border px-2 py-1 text-xs\">\n                        <ui-avatar class=\"size-4\">\n                          <ui-avatar-fallback class=\"bg-primary/10 text-primary text-xs font-medium\">\n                            {{ initials(event.actor.name) }}\n                          </ui-avatar-fallback>\n                        </ui-avatar>\n                        <span class=\"text-foreground max-w-[130px] truncate font-medium sm:max-w-[180px]\">\n                          {{ event.actor.name }}\n                        </span>\n                      </div>\n\n                      <div class=\"text-muted-foreground flex items-center gap-1.5 font-mono text-xs\">\n                        <span>{{ event.sourceIp }}</span>\n                        <span class=\"opacity-50\">·</span>\n                        <span class=\"text-foreground/80\">{{ event.geo }}</span>\n                      </div>\n                    </div>\n                  </div>\n\n                  <!-- Expanded Payload Accordion Detail View -->\n                  @if (isExpanded(event.id)) {\n                    <ui-event-detail-drawer\n                      [event]=\"event\"\n                      [copied]=\"copiedId() === event.id\"\n                      (copy)=\"copyPayload(event.id, event.metadata)\"\n                    />\n                  }\n                </li>\n              }\n            </ul>\n          }\n        </ui-card-content>\n\n        <!-- Bottom Telemetry Stats Bar -->\n        <div\n          class=\"bg-muted/40 flex flex-col gap-2.5 border-t px-4 py-3 text-xs sm:flex-row sm:items-center sm:justify-between\"\n        >\n          <div class=\"text-muted-foreground flex flex-wrap items-center gap-4\">\n            <div class=\"text-foreground flex items-center gap-1.5 font-medium\">\n              <lucide-icon [img]=\"Activity\" class=\"text-success size-3.5\" aria-hidden=\"true\" />\n              <span>Ingestion Rate:</span>\n              <span class=\"font-mono\">{{ isPaused() ? '0 evt/s (Paused)' : '42 events/sec' }}</span>\n            </div>\n\n            <ui-separator orientation=\"vertical\" class=\"hidden h-3.5 sm:block\" />\n\n            <div class=\"flex items-center gap-1.5\">\n              <lucide-icon [img]=\"Layers\" class=\"size-3.5\" aria-hidden=\"true\" />\n              <span>Buffer Size:</span>\n              <span class=\"text-foreground font-mono\">1.2 MB / 10 MB (12%)</span>\n            </div>\n\n            <ui-separator orientation=\"vertical\" class=\"hidden h-3.5 sm:block\" />\n\n            <div class=\"flex items-center gap-1.5\">\n              <lucide-icon [img]=\"Zap\" class=\"text-warning size-3.5\" aria-hidden=\"true\" />\n              <span>Latency:</span>\n              <span class=\"text-foreground font-mono\">~18ms p99</span>\n            </div>\n          </div>\n\n          <div class=\"text-muted-foreground flex items-center gap-2 font-mono\">\n            <span class=\"bg-success size-1.5 rounded-full\"></span>\n            <span>TLS v1.3 · TCP Keep-Alive · us-east-1a</span>\n          </div>\n        </div>\n      </ui-card>\n    </div>\n  `,\n})\nexport class UiAuditEventStreamComponent implements OnInit {\n  @Input() initialEvents?: AuditStreamEvent[]\n  @Input() initialPaused = false\n  @Input() initialSeverity: 'all' | EventSeverity = 'all'\n  @Input() initialSearch = ''\n  @Input('class') className?: string\n\n  readonly events = signal<AuditStreamEvent[]>([...defaultEvents])\n  readonly isPaused = signal(false)\n  readonly selectedSeverity = signal<'all' | EventSeverity>('all')\n  readonly searchQuery = signal('')\n  readonly expandedIds = signal<Record<string, boolean>>({ 'evt-1094': true })\n  readonly copiedId = signal<string | null>(null)\n  readonly exportedNotice = signal(false)\n\n  readonly filteredEvents = computed(() => {\n    const severity = this.selectedSeverity()\n    const query = this.searchQuery()\n    return this.events().filter((event) => {\n      const matchesSeverity = severity === 'all' || event.severity === severity\n      return matchesSeverity && matchesSearch(event, query)\n    })\n  })\n\n  readonly severityCounts = computed(() => {\n    const events = this.events()\n    return {\n      all: events.length,\n      critical: events.filter((e) => e.severity === 'critical').length,\n      warning: events.filter((e) => e.severity === 'warning').length,\n      info: events.filter((e) => e.severity === 'info').length,\n    }\n  })\n\n  readonly allExpanded = computed(() => {\n    const filtered = this.filteredEvents()\n    const expanded = this.expandedIds()\n    return filtered.length > 0 && filtered.every((e) => expanded[e.id])\n  })\n\n  protected readonly Activity = Activity\n  protected readonly AlertCircle = AlertCircle\n  protected readonly AlertTriangle = AlertTriangle\n  protected readonly Check = Check\n  protected readonly ChevronDown = ChevronDown\n  protected readonly ChevronRight = ChevronRight\n  protected readonly Download = Download\n  protected readonly Filter = Filter\n  protected readonly Info = Info\n  protected readonly Layers = Layers\n  protected readonly Pause = Pause\n  protected readonly Play = Play\n  protected readonly RotateCcw = RotateCcw\n  protected readonly Search = Search\n  protected readonly Shield = Shield\n  protected readonly ShieldAlert = ShieldAlert\n  protected readonly Trash2 = Trash2\n  protected readonly Zap = Zap\n\n  protected readonly initials = initials\n  protected readonly formatTimestamp = formatTimestamp\n\n  ngOnInit(): void {\n    this.events.set(this.initialEvents ? [...this.initialEvents] : [...defaultEvents])\n    this.isPaused.set(this.initialPaused)\n    this.selectedSeverity.set(this.initialSeverity)\n    this.searchQuery.set(this.initialSearch)\n  }\n\n  get rootClass(): string {\n    return cn('w-full space-y-4', this.className)\n  }\n\n  isExpanded(id: string): boolean {\n    return !!this.expandedIds()[id]\n  }\n\n  rowClass(id: string): string {\n    return cn('group transition-colors', this.isExpanded(id) ? 'bg-muted/30' : 'hover:bg-muted/20')\n  }\n\n  chevronClass(id: string): string {\n    return cn(\n      'text-muted-foreground group-hover:text-foreground mt-0.5 shrink-0 transition-transform sm:mt-0',\n      this.isExpanded(id) && 'text-foreground rotate-90',\n    )\n  }\n\n  pillClass(severity: 'all' | EventSeverity): string {\n    const active = this.selectedSeverity() === severity\n    switch (severity) {\n      case 'all':\n        return cn(\n          PILL_BASE,\n          active\n            ? 'border-primary bg-primary text-primary-foreground shadow-xs'\n            : 'border-border bg-card text-muted-foreground hover:bg-accent hover:text-foreground',\n        )\n      case 'critical':\n        return cn(\n          PILL_BASE,\n          active\n            ? 'border-destructive bg-destructive text-white shadow-xs'\n            : 'border-border bg-card text-muted-foreground hover:border-destructive/40 hover:text-destructive',\n        )\n      case 'warning':\n        return cn(\n          PILL_BASE,\n          active\n            ? 'border-warning bg-warning text-white shadow-xs'\n            : 'border-border bg-card text-muted-foreground hover:text-warning hover:border-warning/40',\n        )\n      case 'info':\n        return cn(\n          PILL_BASE,\n          active\n            ? 'border-info bg-info text-white shadow-xs'\n            : 'border-border bg-card text-muted-foreground hover:text-info hover:border-info/40',\n        )\n    }\n  }\n\n  countClass(severity: 'all' | EventSeverity): string {\n    const active = this.selectedSeverity() === severity\n    switch (severity) {\n      case 'all':\n        return cn(\n          'py-0.2 rounded-full px-1.5 text-xs',\n          active ? 'bg-primary-foreground/20 text-primary-foreground' : 'bg-muted text-muted-foreground',\n        )\n      case 'critical':\n        return cn(\n          'py-0.2 rounded-full px-1.5 text-xs',\n          active ? 'bg-white/20 text-white' : 'bg-destructive/10 text-destructive',\n        )\n      case 'warning':\n        return cn(\n          'py-0.2 rounded-full px-1.5 text-xs',\n          active ? 'bg-white/20 text-white' : 'bg-warning/10 text-warning',\n        )\n      case 'info':\n        return cn('py-0.2 rounded-full px-1.5 text-xs', active ? 'bg-white/20 text-white' : 'bg-info/10 text-info')\n    }\n  }\n\n  togglePause(): void {\n    this.isPaused.update((prev) => !prev)\n  }\n\n  toggleExpand(id: string): void {\n    this.expandedIds.update((prev) => ({ ...prev, [id]: !prev[id] }))\n  }\n\n  onRowKeydown(e: KeyboardEvent, id: string): void {\n    if (e.key === 'Enter' || e.key === ' ') {\n      e.preventDefault()\n      this.toggleExpand(id)\n    }\n  }\n\n  toggleAllExpand(): void {\n    if (this.allExpanded()) {\n      this.expandedIds.set({})\n    } else {\n      const next: Record<string, boolean> = {}\n      this.filteredEvents().forEach((e) => {\n        next[e.id] = true\n      })\n      this.expandedIds.set(next)\n    }\n  }\n\n  clearStream(): void {\n    this.events.set([])\n    this.expandedIds.set({})\n  }\n\n  resetStream(): void {\n    this.events.set(this.initialEvents ? [...this.initialEvents] : [...defaultEvents])\n    this.searchQuery.set('')\n    this.selectedSeverity.set('all')\n    this.expandedIds.set({ 'evt-1094': true })\n  }\n\n  copyPayload(id: string, metadata: Record<string, unknown>): void {\n    if (typeof navigator !== 'undefined' && navigator.clipboard) {\n      navigator.clipboard.writeText(JSON.stringify(metadata, null, 2))\n      this.copiedId.set(id)\n      setTimeout(() => {\n        this.copiedId.update((current) => (current === id ? null : current))\n      }, 2000)\n    }\n  }\n\n  exportJson(): void {\n    const dataStr = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(this.filteredEvents(), null, 2))\n    if (typeof document !== 'undefined') {\n      const downloadAnchor = document.createElement('a')\n      downloadAnchor.setAttribute('href', dataStr)\n      downloadAnchor.setAttribute(\n        'download',\n        `audit-event-stream-${new Date().toISOString().slice(0, 19).replace(/:/g, '-')}.json`,\n      )\n      document.body.appendChild(downloadAnchor)\n      downloadAnchor.click()\n      downloadAnchor.remove()\n      this.exportedNotice.set(true)\n      setTimeout(() => {\n        this.exportedNotice.set(false)\n      }, 2000)\n    }\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/audit-event-stream/audit-event-stream.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/audit-event-stream/event-detail-drawer.component.ts",
      "content": "import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'\nimport { Bot, Check, Copy, LucideAngularModule, Server, Terminal, User } from 'lucide-angular'\nimport { UiBadgeComponent } from '@/ui/badge/badge.component'\nimport { UiButtonComponent } from '@/ui/button/button.component'\nimport type { AuditStreamEvent } from './audit-event-stream.component'\n\n/** Expanded payload view for one audit event: target banner + syntax-styled JSON metadata box. */\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-event-detail-drawer, [ui-event-detail-drawer]',\n  standalone: true,\n  host: { class: 'block' },\n  imports: [LucideAngularModule, UiBadgeComponent, UiButtonComponent],\n  template: `\n    <div class=\"bg-muted/15 border-t px-4 py-3.5\">\n      <div class=\"space-y-3\">\n        <!-- Target Resource Banner -->\n        <div\n          class=\"bg-card flex flex-col gap-2 rounded-md border p-2.5 text-xs sm:flex-row sm:items-center sm:justify-between\"\n        >\n          <div class=\"flex min-w-0 items-center gap-2\">\n            <span class=\"text-muted-foreground shrink-0 font-medium\">Target:</span>\n            <span class=\"text-foreground truncate font-mono font-medium\">{{ event.target }}</span>\n          </div>\n          <div class=\"flex items-center gap-2\">\n            <span class=\"text-muted-foreground text-xs\">Actor Type:</span>\n            <span ui-badge variant=\"outline\" class=\"font-mono text-xs capitalize\">\n              @if (event.actor.type === 'user') {\n                <lucide-icon [img]=\"User\" class=\"size-3\" aria-hidden=\"true\" />\n              } @else if (event.actor.type === 'service') {\n                <lucide-icon [img]=\"Bot\" class=\"size-3\" aria-hidden=\"true\" />\n              } @else {\n                <lucide-icon [img]=\"Server\" class=\"size-3\" aria-hidden=\"true\" />\n              }\n              {{ event.actor.type }}\n            </span>\n          </div>\n        </div>\n\n        <!-- Syntax Styled JSON Metadata Box -->\n        <div class=\"overflow-hidden rounded-md border bg-zinc-950 font-mono text-xs text-zinc-100 shadow-inner\">\n          <div class=\"flex items-center justify-between gap-x-2 border-b border-zinc-800 bg-zinc-900/90 px-3 py-1.5\">\n            <div class=\"flex items-center gap-2\">\n              <lucide-icon [img]=\"Terminal\" class=\"text-muted-foreground size-3.5\" aria-hidden=\"true\" />\n              <span class=\"text-muted-foreground text-xs\">payload_metadata.json</span>\n            </div>\n            <button\n              ui-button\n              variant=\"ghost\"\n              size=\"xs\"\n              class=\"h-6 gap-1 px-2 text-xs text-zinc-300 hover:bg-zinc-800 hover:text-zinc-100\"\n              (click)=\"copy.emit()\"\n            >\n              @if (copied) {\n                <lucide-icon [img]=\"Check\" class=\"text-success size-3\" aria-hidden=\"true\" />\n              } @else {\n                <lucide-icon [img]=\"Copy\" class=\"size-3\" aria-hidden=\"true\" />\n              }\n              <span>{{ copied ? 'Copied' : 'Copy JSON' }}</span>\n            </button>\n          </div>\n\n          <pre\n            class=\"max-h-56 overflow-x-auto overflow-y-auto p-3 text-xs leading-relaxed select-text\"\n          ><code class=\"text-success\">{{ json }}</code></pre>\n        </div>\n      </div>\n    </div>\n  `,\n})\nexport class UiEventDetailDrawerComponent {\n  @Input({ required: true }) event!: AuditStreamEvent\n  @Input() copied = false\n  @Output() readonly copy = new EventEmitter<void>()\n\n  protected readonly Bot = Bot\n  protected readonly Check = Check\n  protected readonly Copy = Copy\n  protected readonly Server = Server\n  protected readonly Terminal = Terminal\n  protected readonly User = User\n\n  get json(): string {\n    return JSON.stringify(this.event.metadata, null, 2)\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/audit-event-stream/event-detail-drawer.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/audit-event-stream/index.ts",
      "content": "export { UiAuditEventStreamComponent, type AuditStreamEvent, type EventSeverity } from './audit-event-stream.component'\nexport { UiEventDetailDrawerComponent } from './event-detail-drawer.component'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/audit-event-stream/index.ts"
    }
  ],
  "dependencies": [
    "lucide-angular"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/angular/avatar.json",
    "https://uipkge.dev/r/angular/badge.json",
    "https://uipkge.dev/r/angular/button.json",
    "https://uipkge.dev/r/angular/card.json",
    "https://uipkge.dev/r/angular/input.json",
    "https://uipkge.dev/r/angular/separator.json"
  ],
  "description": "Real-time live streaming audit log viewer and security telemetry feed with status indicators, stream pause/resume controls, regex and keyword log filtering, severity badges, expandable JSON payload inspectors, and ingestion telemetry stats.",
  "categories": [
    "devops",
    "app"
  ]
}