@flamingo-stack/openframe-frontend-core 0.0.581-snapshot.20260901141954 → 0.0.581

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/dist/{chunk-CR7GPMCM.js → chunk-3GXNCJZI.js} +3 -3
  2. package/dist/{chunk-A5VD6R7N.cjs → chunk-6U45VX5J.cjs} +43 -43
  3. package/dist/{chunk-A5VD6R7N.cjs.map → chunk-6U45VX5J.cjs.map} +1 -1
  4. package/dist/{chunk-SVQVAGZK.js → chunk-7CP5KY5W.js} +3 -3
  5. package/dist/{chunk-WQ236GO3.cjs → chunk-AIALG25H.cjs} +69 -69
  6. package/dist/{chunk-WQ236GO3.cjs.map → chunk-AIALG25H.cjs.map} +1 -1
  7. package/dist/{chunk-ALSLHGBH.cjs → chunk-BTKMTVN5.cjs} +4 -4
  8. package/dist/{chunk-ALSLHGBH.cjs.map → chunk-BTKMTVN5.cjs.map} +1 -1
  9. package/dist/{chunk-FYVL6A4Z.cjs → chunk-DSPQVZFE.cjs} +24 -24
  10. package/dist/{chunk-FYVL6A4Z.cjs.map → chunk-DSPQVZFE.cjs.map} +1 -1
  11. package/dist/{chunk-HQF7VE7B.js → chunk-ESWXXWCL.js} +2 -2
  12. package/dist/{chunk-FRWQ67UM.js → chunk-EZVABFEO.js} +2 -2
  13. package/dist/{chunk-6EUYXDV3.js → chunk-GAHKWML7.js} +6 -6
  14. package/dist/{chunk-L4E2TOSF.cjs → chunk-GMQEHDN2.cjs} +5 -5
  15. package/dist/{chunk-L4E2TOSF.cjs.map → chunk-GMQEHDN2.cjs.map} +1 -1
  16. package/dist/{chunk-K5SCFOD5.cjs → chunk-GUC4JK6O.cjs} +9 -9
  17. package/dist/{chunk-K5SCFOD5.cjs.map → chunk-GUC4JK6O.cjs.map} +1 -1
  18. package/dist/{chunk-U2ZRM3YB.js → chunk-GVM37TRU.js} +4 -4
  19. package/dist/{chunk-F227VMPL.js → chunk-HJVKPG55.js} +15 -125
  20. package/dist/{chunk-F227VMPL.js.map → chunk-HJVKPG55.js.map} +1 -1
  21. package/dist/{chunk-7HHRJTIY.js → chunk-HVSZYUGP.js} +5 -5
  22. package/dist/{chunk-KBOBPKMU.js → chunk-IHFQ5VVR.js} +5 -5
  23. package/dist/{chunk-A3SVEK7A.js → chunk-JW53WPB5.js} +3 -3
  24. package/dist/{chunk-646JEAY4.js → chunk-KAEVE7W2.js} +2 -2
  25. package/dist/{chunk-R3J2ERH2.cjs → chunk-KNBXZ22O.cjs} +3 -3
  26. package/dist/{chunk-R3J2ERH2.cjs.map → chunk-KNBXZ22O.cjs.map} +1 -1
  27. package/dist/{chunk-BUOYMIFJ.js → chunk-LWDIDSCF.js} +3 -3
  28. package/dist/{chunk-ORQQZQBB.cjs → chunk-M4KQWGEL.cjs} +32 -32
  29. package/dist/{chunk-ORQQZQBB.cjs.map → chunk-M4KQWGEL.cjs.map} +1 -1
  30. package/dist/{chunk-SKGMU7TZ.js → chunk-OKA3DJJ3.js} +2 -2
  31. package/dist/{chunk-DQVM4FTL.cjs → chunk-PBRXT7TD.cjs} +10 -10
  32. package/dist/{chunk-DQVM4FTL.cjs.map → chunk-PBRXT7TD.cjs.map} +1 -1
  33. package/dist/{chunk-4KWAHIYA.js → chunk-R5JVRFSW.js} +3 -3
  34. package/dist/{chunk-BQPCCBGO.cjs → chunk-SEZ25E22.cjs} +10 -10
  35. package/dist/{chunk-BQPCCBGO.cjs.map → chunk-SEZ25E22.cjs.map} +1 -1
  36. package/dist/{chunk-DGZPX2G3.cjs → chunk-U3W2ZVN4.cjs} +159 -159
  37. package/dist/{chunk-DGZPX2G3.cjs.map → chunk-U3W2ZVN4.cjs.map} +1 -1
  38. package/dist/{chunk-KAOXOYRT.cjs → chunk-UKHM2S6I.cjs} +15 -15
  39. package/dist/{chunk-KAOXOYRT.cjs.map → chunk-UKHM2S6I.cjs.map} +1 -1
  40. package/dist/{chunk-J5I3TKAH.cjs → chunk-VDRCKHML.cjs} +3 -3
  41. package/dist/{chunk-J5I3TKAH.cjs.map → chunk-VDRCKHML.cjs.map} +1 -1
  42. package/dist/{chunk-GD3OAM4T.js → chunk-VXUUSLD5.js} +2 -2
  43. package/dist/{chunk-T32XVOFP.cjs → chunk-W2TXSZTM.cjs} +21 -21
  44. package/dist/{chunk-T32XVOFP.cjs.map → chunk-W2TXSZTM.cjs.map} +1 -1
  45. package/dist/{chunk-RMOUILHT.cjs → chunk-WHFEG6UU.cjs} +22 -22
  46. package/dist/{chunk-RMOUILHT.cjs.map → chunk-WHFEG6UU.cjs.map} +1 -1
  47. package/dist/{chunk-LOJ5KQ6B.cjs → chunk-YU2UJPAT.cjs} +356 -466
  48. package/dist/chunk-YU2UJPAT.cjs.map +1 -0
  49. package/dist/{chunk-QDSVTIO5.js → chunk-ZEZMGXYV.js} +5 -5
  50. package/dist/components/case-studies/index.cjs +9 -9
  51. package/dist/components/case-studies/index.js +3 -3
  52. package/dist/components/chat/index.cjs +2 -2
  53. package/dist/components/chat/index.js +1 -1
  54. package/dist/components/contact/index.cjs +4 -4
  55. package/dist/components/contact/index.js +3 -3
  56. package/dist/components/docs/index.cjs +7 -7
  57. package/dist/components/docs/index.js +6 -6
  58. package/dist/components/embeds/index.cjs +4 -4
  59. package/dist/components/embeds/index.js +3 -3
  60. package/dist/components/faq/index.cjs +4 -4
  61. package/dist/components/faq/index.js +3 -3
  62. package/dist/components/features/index.cjs +3 -5
  63. package/dist/components/features/index.cjs.map +1 -1
  64. package/dist/components/features/index.js +2 -4
  65. package/dist/components/features/video.d.ts +0 -12
  66. package/dist/components/features/video.d.ts.map +1 -1
  67. package/dist/components/help-center-pages/index.cjs +23 -23
  68. package/dist/components/help-center-pages/index.js +14 -14
  69. package/dist/components/index.cjs +121 -123
  70. package/dist/components/index.cjs.map +1 -1
  71. package/dist/components/index.js +13 -15
  72. package/dist/components/index.js.map +1 -1
  73. package/dist/components/meeting-scheduler/index.cjs +21 -21
  74. package/dist/components/meeting-scheduler/index.js +2 -2
  75. package/dist/components/navigation/index.cjs +6 -6
  76. package/dist/components/navigation/index.js +5 -5
  77. package/dist/components/onboarding-guides/index.cjs +6 -6
  78. package/dist/components/onboarding-guides/index.js +5 -5
  79. package/dist/components/tickets/index.cjs +7 -7
  80. package/dist/components/tickets/index.js +6 -6
  81. package/dist/components/ui/index.cjs +3 -3
  82. package/dist/components/ui/index.js +2 -2
  83. package/dist/index.cjs +7 -9
  84. package/dist/index.cjs.map +1 -1
  85. package/dist/index.js +6 -8
  86. package/dist/index.js.map +1 -1
  87. package/package.json +1 -1
  88. package/src/components/features/video.tsx +16 -198
  89. package/dist/chunk-LOJ5KQ6B.cjs.map +0 -1
  90. package/src/components/features/__tests__/video-playback-failure.test.tsx +0 -250
  91. /package/dist/{chunk-CR7GPMCM.js.map → chunk-3GXNCJZI.js.map} +0 -0
  92. /package/dist/{chunk-SVQVAGZK.js.map → chunk-7CP5KY5W.js.map} +0 -0
  93. /package/dist/{chunk-HQF7VE7B.js.map → chunk-ESWXXWCL.js.map} +0 -0
  94. /package/dist/{chunk-FRWQ67UM.js.map → chunk-EZVABFEO.js.map} +0 -0
  95. /package/dist/{chunk-6EUYXDV3.js.map → chunk-GAHKWML7.js.map} +0 -0
  96. /package/dist/{chunk-U2ZRM3YB.js.map → chunk-GVM37TRU.js.map} +0 -0
  97. /package/dist/{chunk-7HHRJTIY.js.map → chunk-HVSZYUGP.js.map} +0 -0
  98. /package/dist/{chunk-KBOBPKMU.js.map → chunk-IHFQ5VVR.js.map} +0 -0
  99. /package/dist/{chunk-A3SVEK7A.js.map → chunk-JW53WPB5.js.map} +0 -0
  100. /package/dist/{chunk-646JEAY4.js.map → chunk-KAEVE7W2.js.map} +0 -0
  101. /package/dist/{chunk-BUOYMIFJ.js.map → chunk-LWDIDSCF.js.map} +0 -0
  102. /package/dist/{chunk-SKGMU7TZ.js.map → chunk-OKA3DJJ3.js.map} +0 -0
  103. /package/dist/{chunk-4KWAHIYA.js.map → chunk-R5JVRFSW.js.map} +0 -0
  104. /package/dist/{chunk-GD3OAM4T.js.map → chunk-VXUUSLD5.js.map} +0 -0
  105. /package/dist/{chunk-QDSVTIO5.js.map → chunk-ZEZMGXYV.js.map} +0 -0
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  SoftwareInfo,
10
10
  SoftwareSourceBadge,
11
11
  ToolBadge
12
- } from "./chunk-CR7GPMCM.js";
12
+ } from "./chunk-3GXNCJZI.js";
13
13
  import {
14
14
  AppHeader,
15
15
  AppLayout,
@@ -28,14 +28,14 @@ import {
28
28
  SlidingSidebar,
29
29
  TicketAlertsButton,
30
30
  TopNavigation
31
- } from "./chunk-U2ZRM3YB.js";
31
+ } from "./chunk-GVM37TRU.js";
32
32
  import {
33
33
  MobileNavigationDropdown,
34
34
  MultiLevelNavigation,
35
35
  StickySectionNav,
36
36
  useSectionNavigation
37
- } from "./chunk-646JEAY4.js";
38
- import "./chunk-4KWAHIYA.js";
37
+ } from "./chunk-KAEVE7W2.js";
38
+ import "./chunk-R5JVRFSW.js";
39
39
  import {
40
40
  ADMIN_APPROVAL_REQUEST_CONTEXT_TYPE,
41
41
  AIEnrichButton,
@@ -577,7 +577,7 @@ import {
577
577
  withFirstTouchAttribution,
578
578
  withWalkthroughOpenParam,
579
579
  writeDismissCookie
580
- } from "./chunk-GD3OAM4T.js";
580
+ } from "./chunk-VXUUSLD5.js";
581
581
  import "./chunk-L2SLFCXP.js";
582
582
  import "./chunk-BJXDHKUX.js";
583
583
  import {
@@ -892,7 +892,6 @@ import {
892
892
  TooltipProvider,
893
893
  TooltipTrigger,
894
894
  UnarchiveChatModal,
895
- VIDEO_PLAYBACK_FAILED_EVENT,
896
895
  Video,
897
896
  VideoBiteCard,
898
897
  VideoBitesStrip,
@@ -1055,7 +1054,7 @@ import {
1055
1054
  useVideoOriginPreconnect,
1056
1055
  useVideoWarmup,
1057
1056
  usesCanonicalStatusStyle
1058
- } from "./chunk-F227VMPL.js";
1057
+ } from "./chunk-HJVKPG55.js";
1059
1058
  import {
1060
1059
  HEADING_EMOJI_RE,
1061
1060
  HUB_HEADER_OFFSET_PX,
@@ -2505,7 +2504,6 @@ export {
2505
2504
  UserIcon,
2506
2505
  UsersGroupIcon,
2507
2506
  UsersIcon,
2508
- VIDEO_PLAYBACK_FAILED_EVENT,
2509
2507
  VendorDirectoryIcon,
2510
2508
  VendorShowcaseMainIcon,
2511
2509
  VendorsIcon,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/logs-list.tsx","../src/components/log-severity-dot.tsx","../src/types/logs.types.ts","../src/assets/index.ts"],"sourcesContent":["import { type FC, forwardRef, useRef } from 'react';\nimport type { LogsListProps, LogEntry } from '../types/logs.types';\nimport { cn } from '../utils/cn';\nimport { LogSeverityDot } from './log-severity-dot';\nimport { ToolIcon } from './tool-icon';\n\nconst formatTimestamp = (timestamp: string | Date): string => {\n const date = timestamp instanceof Date ? timestamp : new Date(timestamp);\n\n // UTC getters so the timestamp is identical on server (UTC) and client\n // (local) — otherwise React #418 hydration mismatch.\n const year = date.getUTCFullYear();\n const month = String(date.getUTCMonth() + 1).padStart(2, '0');\n const day = String(date.getUTCDate()).padStart(2, '0');\n const hours = String(date.getUTCHours()).padStart(2, '0');\n const minutes = String(date.getUTCMinutes()).padStart(2, '0');\n\n return `${year}/${month}/${day},${hours}:${minutes}`;\n};\n\nconst LogCard: FC<{\n log: LogEntry;\n isLast: boolean;\n showConnector: boolean;\n onClick?: () => void;\n}> = ({ log, isLast, showConnector, onClick }) => {\n return (\n <div className=\"relative\">\n <div\n className={cn(\n 'relative box-border flex w-full items-start gap-3 rounded px-1 py-2',\n 'cursor-pointer transition-colors hover:bg-ods-bg-hover/50',\n )}\n onClick={onClick}\n role=\"button\"\n tabIndex={0}\n onKeyDown={e => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onClick?.();\n }\n }}\n >\n <LogSeverityDot severity={log.severity} size=\"md\" />\n\n <div className=\"min-w-0 flex-1 space-y-1\">\n <p className=\"text-ods-text-primary text-h6\">{log.title}</p>\n <div className=\"flex items-center gap-2\">\n <p className=\"text-ods-text-secondary text-h5\">{formatTimestamp(log.timestamp)}</p>\n {log.toolType && <ToolIcon toolType={log.toolType} size={16} />}\n </div>\n </div>\n </div>\n\n {showConnector && !isLast && (\n <div\n className=\"absolute left-[15px] w-[2px] bg-ods-border\"\n style={{\n top: '28px',\n bottom: '-10px',\n }}\n aria-hidden=\"true\"\n />\n )}\n </div>\n );\n};\n\nexport const LogsList = forwardRef<HTMLDivElement, LogsListProps>(\n (\n {\n logs,\n maxHeight = '400px',\n showConnector = true,\n onLogClick,\n loading = false,\n emptyMessage = 'No logs to display',\n className,\n },\n ref,\n ) => {\n const containerRef = useRef<HTMLDivElement>(null);\n\n const isFullHeight = maxHeight === '100%';\n\n const getContainerStyles = () => {\n if (isFullHeight) return undefined;\n return { maxHeight, minHeight: '200px' };\n };\n\n const getContainerClasses = () => {\n if (isFullHeight) return 'h-full';\n return '';\n };\n\n if (loading) {\n return (\n <div\n ref={ref}\n className={cn(\n 'rounded-lg border border-ods-border bg-ods-card p-4',\n 'flex items-center justify-center',\n getContainerClasses(),\n className,\n )}\n style={getContainerStyles()}\n >\n <div className=\"text-ods-text-muted text-h6\">Loading logs...</div>\n </div>\n );\n }\n\n if (logs.length === 0) {\n return (\n <div\n ref={ref}\n className={cn(\n 'rounded-lg border border-ods-border bg-ods-card p-4',\n 'flex items-center justify-center',\n getContainerClasses(),\n className,\n )}\n style={getContainerStyles()}\n >\n <div className=\"text-ods-text-muted text-h6\">{emptyMessage}</div>\n </div>\n );\n }\n\n return (\n <div\n ref={ref}\n className={cn(\n 'relative rounded-lg border border-ods-border bg-ods-card',\n 'flex flex-col overflow-hidden',\n getContainerClasses(),\n className,\n )}\n style={getContainerStyles()}\n >\n <div ref={containerRef} className=\"flex-1 overflow-y-auto px-4 py-3\">\n {logs.map((log, index) => (\n <LogCard\n key={log.id}\n log={log}\n isLast={index === logs.length - 1}\n showConnector={showConnector}\n onClick={() => onLogClick?.(log)}\n />\n ))}\n </div>\n </div>\n );\n },\n);\n\nLogsList.displayName = 'LogsList';\n","import { forwardRef } from 'react';\nimport { type LogSeverityDotProps, LOG_SEVERITY_COLORS, LOG_SEVERITY_LABELS } from '../types/logs.types';\nimport { cn } from '../utils/cn';\n\nexport const LogSeverityDot = forwardRef<HTMLDivElement, LogSeverityDotProps>(\n ({ severity, size = 'md', className }, ref) => {\n const sizeClasses = {\n sm: 'w-4 h-4',\n md: 'w-6 h-6',\n lg: 'w-8 h-8',\n };\n\n const dotSizeClasses = {\n sm: 'w-2 h-2',\n md: 'w-3 h-3',\n lg: 'w-4 h-4',\n };\n\n return (\n <div\n ref={ref}\n className={cn('relative flex shrink-0 items-center justify-center', sizeClasses[size], className)}\n aria-label={`${LOG_SEVERITY_LABELS[severity]} severity`}\n >\n <div\n className={cn('rounded-full', dotSizeClasses[size])}\n style={{ backgroundColor: LOG_SEVERITY_COLORS[severity] }}\n />\n </div>\n );\n },\n);\n\nLogSeverityDot.displayName = 'LogSeverityDot';\n","import type { ToolType } from './tool.types';\n\nexport type LogSeverity = 'DEBUG' | 'INFO' | 'WARNING' | 'ERROR' | 'CRITICAL';\n\nexport interface LogEntry {\n id: string;\n ingestDay: string;\n eventType: string;\n severity: LogSeverity;\n title: string;\n timestamp: string | Date;\n toolType?: ToolType;\n toolIcon?: string;\n message?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface LogsListProps {\n logs: LogEntry[];\n maxHeight?: string | number;\n showConnector?: boolean;\n onLogClick?: (log: LogEntry) => void;\n loading?: boolean;\n emptyMessage?: string;\n className?: string;\n}\n\nexport interface LogSeverityDotProps {\n severity: LogSeverity;\n size?: 'sm' | 'md' | 'lg';\n className?: string;\n}\n\nexport const LOG_SEVERITY_COLORS: Record<LogSeverity, string> = {\n DEBUG: '#888888',\n INFO: '#888888',\n WARNING: '#e1b32f',\n ERROR: '#f36666',\n CRITICAL: '#b43b3b',\n};\n\nexport const LOG_SEVERITY_LABELS: Record<LogSeverity, string> = {\n DEBUG: 'Debug',\n INFO: 'Info',\n WARNING: 'Warning',\n ERROR: 'Error',\n CRITICAL: 'Critical',\n};\n","// Assets exports\n// Font files and other static assets\n// Platform utilities will be available when needed\n\nexport const assets = {} as const;\nexport * from './fae-avatar';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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","names":["forwardRef","jsx","forwardRef"]}
1
+ {"version":3,"sources":["../src/components/logs-list.tsx","../src/components/log-severity-dot.tsx","../src/types/logs.types.ts","../src/assets/index.ts"],"sourcesContent":["import { type FC, forwardRef, useRef } from 'react';\nimport type { LogsListProps, LogEntry } from '../types/logs.types';\nimport { cn } from '../utils/cn';\nimport { LogSeverityDot } from './log-severity-dot';\nimport { ToolIcon } from './tool-icon';\n\nconst formatTimestamp = (timestamp: string | Date): string => {\n const date = timestamp instanceof Date ? timestamp : new Date(timestamp);\n\n // UTC getters so the timestamp is identical on server (UTC) and client\n // (local) — otherwise React #418 hydration mismatch.\n const year = date.getUTCFullYear();\n const month = String(date.getUTCMonth() + 1).padStart(2, '0');\n const day = String(date.getUTCDate()).padStart(2, '0');\n const hours = String(date.getUTCHours()).padStart(2, '0');\n const minutes = String(date.getUTCMinutes()).padStart(2, '0');\n\n return `${year}/${month}/${day},${hours}:${minutes}`;\n};\n\nconst LogCard: FC<{\n log: LogEntry;\n isLast: boolean;\n showConnector: boolean;\n onClick?: () => void;\n}> = ({ log, isLast, showConnector, onClick }) => {\n return (\n <div className=\"relative\">\n <div\n className={cn(\n 'relative box-border flex w-full items-start gap-3 rounded px-1 py-2',\n 'cursor-pointer transition-colors hover:bg-ods-bg-hover/50',\n )}\n onClick={onClick}\n role=\"button\"\n tabIndex={0}\n onKeyDown={e => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onClick?.();\n }\n }}\n >\n <LogSeverityDot severity={log.severity} size=\"md\" />\n\n <div className=\"min-w-0 flex-1 space-y-1\">\n <p className=\"text-ods-text-primary text-h6\">{log.title}</p>\n <div className=\"flex items-center gap-2\">\n <p className=\"text-ods-text-secondary text-h5\">{formatTimestamp(log.timestamp)}</p>\n {log.toolType && <ToolIcon toolType={log.toolType} size={16} />}\n </div>\n </div>\n </div>\n\n {showConnector && !isLast && (\n <div\n className=\"absolute left-[15px] w-[2px] bg-ods-border\"\n style={{\n top: '28px',\n bottom: '-10px',\n }}\n aria-hidden=\"true\"\n />\n )}\n </div>\n );\n};\n\nexport const LogsList = forwardRef<HTMLDivElement, LogsListProps>(\n (\n {\n logs,\n maxHeight = '400px',\n showConnector = true,\n onLogClick,\n loading = false,\n emptyMessage = 'No logs to display',\n className,\n },\n ref,\n ) => {\n const containerRef = useRef<HTMLDivElement>(null);\n\n const isFullHeight = maxHeight === '100%';\n\n const getContainerStyles = () => {\n if (isFullHeight) return undefined;\n return { maxHeight, minHeight: '200px' };\n };\n\n const getContainerClasses = () => {\n if (isFullHeight) return 'h-full';\n return '';\n };\n\n if (loading) {\n return (\n <div\n ref={ref}\n className={cn(\n 'rounded-lg border border-ods-border bg-ods-card p-4',\n 'flex items-center justify-center',\n getContainerClasses(),\n className,\n )}\n style={getContainerStyles()}\n >\n <div className=\"text-ods-text-muted text-h6\">Loading logs...</div>\n </div>\n );\n }\n\n if (logs.length === 0) {\n return (\n <div\n ref={ref}\n className={cn(\n 'rounded-lg border border-ods-border bg-ods-card p-4',\n 'flex items-center justify-center',\n getContainerClasses(),\n className,\n )}\n style={getContainerStyles()}\n >\n <div className=\"text-ods-text-muted text-h6\">{emptyMessage}</div>\n </div>\n );\n }\n\n return (\n <div\n ref={ref}\n className={cn(\n 'relative rounded-lg border border-ods-border bg-ods-card',\n 'flex flex-col overflow-hidden',\n getContainerClasses(),\n className,\n )}\n style={getContainerStyles()}\n >\n <div ref={containerRef} className=\"flex-1 overflow-y-auto px-4 py-3\">\n {logs.map((log, index) => (\n <LogCard\n key={log.id}\n log={log}\n isLast={index === logs.length - 1}\n showConnector={showConnector}\n onClick={() => onLogClick?.(log)}\n />\n ))}\n </div>\n </div>\n );\n },\n);\n\nLogsList.displayName = 'LogsList';\n","import { forwardRef } from 'react';\nimport { type LogSeverityDotProps, LOG_SEVERITY_COLORS, LOG_SEVERITY_LABELS } from '../types/logs.types';\nimport { cn } from '../utils/cn';\n\nexport const LogSeverityDot = forwardRef<HTMLDivElement, LogSeverityDotProps>(\n ({ severity, size = 'md', className }, ref) => {\n const sizeClasses = {\n sm: 'w-4 h-4',\n md: 'w-6 h-6',\n lg: 'w-8 h-8',\n };\n\n const dotSizeClasses = {\n sm: 'w-2 h-2',\n md: 'w-3 h-3',\n lg: 'w-4 h-4',\n };\n\n return (\n <div\n ref={ref}\n className={cn('relative flex shrink-0 items-center justify-center', sizeClasses[size], className)}\n aria-label={`${LOG_SEVERITY_LABELS[severity]} severity`}\n >\n <div\n className={cn('rounded-full', dotSizeClasses[size])}\n style={{ backgroundColor: LOG_SEVERITY_COLORS[severity] }}\n />\n </div>\n );\n },\n);\n\nLogSeverityDot.displayName = 'LogSeverityDot';\n","import type { ToolType } from './tool.types';\n\nexport type LogSeverity = 'DEBUG' | 'INFO' | 'WARNING' | 'ERROR' | 'CRITICAL';\n\nexport interface LogEntry {\n id: string;\n ingestDay: string;\n eventType: string;\n severity: LogSeverity;\n title: string;\n timestamp: string | Date;\n toolType?: ToolType;\n toolIcon?: string;\n message?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface LogsListProps {\n logs: LogEntry[];\n maxHeight?: string | number;\n showConnector?: boolean;\n onLogClick?: (log: LogEntry) => void;\n loading?: boolean;\n emptyMessage?: string;\n className?: string;\n}\n\nexport interface LogSeverityDotProps {\n severity: LogSeverity;\n size?: 'sm' | 'md' | 'lg';\n className?: string;\n}\n\nexport const LOG_SEVERITY_COLORS: Record<LogSeverity, string> = {\n DEBUG: '#888888',\n INFO: '#888888',\n WARNING: '#e1b32f',\n ERROR: '#f36666',\n CRITICAL: '#b43b3b',\n};\n\nexport const LOG_SEVERITY_LABELS: Record<LogSeverity, string> = {\n DEBUG: 'Debug',\n INFO: 'Info',\n WARNING: 'Warning',\n ERROR: 'Error',\n CRITICAL: 'Critical',\n};\n","// Assets exports\n// Font files and other static assets\n// Platform utilities will be available when needed\n\nexport const assets = {} as const;\nexport * from './fae-avatar';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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","names":["forwardRef","jsx","forwardRef"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flamingo-stack/openframe-frontend-core",
3
- "version": "0.0.581-snapshot.20260901141954",
3
+ "version": "0.0.581",
4
4
  "description": "Shared design system and components for all Flamingo platforms",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -35,7 +35,6 @@ import type React from 'react';
35
35
  import { useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
36
36
  import { useAuthedAssetSrc } from '../../hooks/use-authed-asset-src';
37
37
  import { fetchPriorityProp } from '../../utils/fetch-priority';
38
- import { Button } from '../ui/button';
39
38
  import { useIosNativeVideoFullscreen } from './use-ios-native-video-fullscreen';
40
39
  import { saveDataEnabled } from './use-video-warmup';
41
40
  import { VideoPlayBadge, VideoUnmuteGlyph } from './video-center-badge';
@@ -281,76 +280,6 @@ export function extractYouTubeId(url: string): string | null {
281
280
  return m ? m[1] : null;
282
281
  }
283
282
 
284
- // =============================================================================
285
- // Playback-failure handling
286
- // =============================================================================
287
- //
288
- // A stalled or errored player leaves the user on an endless spinner with no way
289
- // out. Every failure surfaces a retry (`VideoErrorOverlay`) and is reported on
290
- // a `window` CustomEvent the host subscribes to — no vendor analytics global is
291
- // touched from here; this package ships to consumers that load different (or
292
- // no) analytics.
293
-
294
- export type VideoFailureKind = 'file' | 'youtube';
295
- /** `stall`: buffering that never cleared while playback was expected. */
296
- export type VideoFailureReason = 'error' | 'stall';
297
-
298
- export interface VideoPlaybackFailureDetail {
299
- kind: VideoFailureKind;
300
- /** File URL or YouTube video id — enough to group failures by source. */
301
- src: string;
302
- reason: VideoFailureReason;
303
- /** YouTube IFrame API error code, when the embed reported one. */
304
- errorCode?: number;
305
- }
306
-
307
- export const VIDEO_PLAYBACK_FAILED_EVENT = 'flamingo:video-playback-failed';
308
-
309
- function reportPlaybackFailure(detail: VideoPlaybackFailureDetail): void {
310
- if (typeof window === 'undefined') return;
311
- try {
312
- window.dispatchEvent(new CustomEvent(VIDEO_PLAYBACK_FAILED_EVENT, { detail }));
313
- } catch {
314
- // Analytics must never break playback recovery.
315
- }
316
- }
317
-
318
- // Buffering longer than this while playback is expected reads as "broken", not
319
- // "loading" — surface a retry instead of spinning forever. This is what an
320
- // `error` callback alone misses: a video that played, then stalled mid-way.
321
- const VIDEO_STALL_TIMEOUT_MS = 15_000;
322
-
323
- /** `watchOnYouTubeId` adds the one recovery that survives an embed the owner
324
- * disabled: opening the video on YouTube itself. */
325
- function VideoErrorOverlay({
326
- onRetry,
327
- watchOnYouTubeId,
328
- }: {
329
- onRetry: () => void;
330
- watchOnYouTubeId?: string;
331
- }): React.ReactElement {
332
- return (
333
- <div className="absolute inset-0 z-10 flex flex-col items-center justify-center gap-[var(--spacing-system-sf)] bg-ods-overlay p-[var(--spacing-system-lf)] text-center">
334
- <p className="text-ods-text-secondary text-h6">This video failed to play.</p>
335
- <div className="flex items-center gap-[var(--spacing-system-sf)]">
336
- <Button variant="outline" size="small" onClick={onRetry}>
337
- Try again
338
- </Button>
339
- {watchOnYouTubeId ? (
340
- <Button
341
- variant="transparent"
342
- size="small"
343
- href={`https://www.youtube.com/watch?v=${watchOnYouTubeId}`}
344
- openInNewTab
345
- >
346
- Watch on YouTube
347
- </Button>
348
- ) : null}
349
- </div>
350
- </div>
351
- );
352
- }
353
-
354
283
  // =============================================================================
355
284
  // Props
356
285
  // =============================================================================
@@ -761,13 +690,11 @@ function FilePlayer({
761
690
  const hoverPlayerRef = useRef<{
762
691
  play?: () => Promise<void> | void;
763
692
  pause?: () => void;
764
- load?: () => void;
765
693
  muted?: boolean;
766
694
  volume?: number;
767
695
  currentTime?: number;
768
696
  duration?: number;
769
697
  paused?: boolean;
770
- ended?: boolean;
771
698
  addEventListener?: (type: string, listener: () => void) => void;
772
699
  removeEventListener?: (type: string, listener: () => void) => void;
773
700
  } | null>(null);
@@ -1173,93 +1100,9 @@ function FilePlayer({
1173
1100
  );
1174
1101
  }
1175
1102
 
1176
- // Only chrome-bearing surfaces (a user actively watching) monitor health —
1177
- // decorative first-frame and hover previews pass `chromeless` and stay silent.
1178
- const monitorHealth = !chromeless;
1179
- const [playbackFailed, setPlaybackFailed] = useState(false);
1180
- const stallTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
1181
- const clearStallTimer = useCallback(() => {
1182
- if (stallTimerRef.current !== null) {
1183
- clearTimeout(stallTimerRef.current);
1184
- stallTimerRef.current = null;
1185
- }
1186
- }, []);
1187
- useEffect(() => clearStallTimer, [clearStallTimer]);
1188
-
1189
- const failPlayback = useCallback(
1190
- (reason: VideoFailureReason) => {
1191
- clearStallTimer();
1192
- setPlaybackFailed(true);
1193
- reportPlaybackFailure({ kind: 'file', src: url, reason });
1194
- },
1195
- [clearStallTimer, url],
1196
- );
1197
-
1198
- // A manually paused or finished video is never a stall.
1199
- const armStallTimer = useCallback(() => {
1200
- if (!monitorHealth) return;
1201
- const el = hoverPlayerRef.current;
1202
- if (!el || el.paused || el.ended) return;
1203
- if (stallTimerRef.current !== null) return;
1204
- stallTimerRef.current = setTimeout(() => {
1205
- stallTimerRef.current = null;
1206
- failPlayback('stall');
1207
- }, VIDEO_STALL_TIMEOUT_MS);
1208
- }, [monitorHealth, failPlayback]);
1209
-
1210
- // Progress means the player is alive — a stall that self-heals clears its own
1211
- // overlay.
1212
- const handlePlaybackProgress = useCallback(() => {
1213
- clearStallTimer();
1214
- setPlaybackFailed(false);
1215
- }, [clearStallTimer]);
1216
-
1217
- const handleMediaError = useCallback(() => {
1218
- if (!monitorHealth) return;
1219
- failPlayback('error');
1220
- }, [monitorHealth, failPlayback]);
1221
-
1222
- // `load()` re-inits the HLS pipeline (`play()` alone can't) but rewinds to
1223
- // zero — stash the position and seek back on `loadedmetadata`, since an
1224
- // earlier assignment is dropped while the fresh source has no seekable range.
1225
- const retryPlayback = useCallback(() => {
1226
- setPlaybackFailed(false);
1227
- clearStallTimer();
1228
- const el = hoverPlayerRef.current;
1229
- if (!el) return;
1230
- const resumeAt = typeof el.currentTime === 'number' ? el.currentTime : 0;
1231
- try {
1232
- el.load?.();
1233
- if (resumeAt > 0 && el.addEventListener && el.removeEventListener) {
1234
- const seekBack = () => {
1235
- el.removeEventListener?.('loadedmetadata', seekBack);
1236
- try {
1237
- el.currentTime = resumeAt;
1238
- } catch {
1239
- /* source shorter than the stashed position — start from the top */
1240
- }
1241
- };
1242
- el.addEventListener('loadedmetadata', seekBack);
1243
- }
1244
- (el.play?.() as Promise<void> | undefined)?.catch?.(() => {
1245
- /* a re-rejected play surfaces again via the error/stall handlers */
1246
- });
1247
- } catch {
1248
- /* element torn down */
1249
- }
1250
- }, [clearStallTimer]);
1251
-
1252
- const errorOverlay = monitorHealth && playbackFailed ? <VideoErrorOverlay onRetry={retryPlayback} /> : null;
1253
-
1254
1103
  const player = (
1255
1104
  <MuxPlayer
1256
1105
  ref={hoverPlayerRef as React.Ref<never>}
1257
- onError={handleMediaError}
1258
- onWaiting={armStallTimer}
1259
- onStalled={armStallTimer}
1260
- onPlaying={handlePlaybackProgress}
1261
- onTimeUpdate={handlePlaybackProgress}
1262
- onPause={clearStallTimer}
1263
1106
  src={url}
1264
1107
  poster={poster || undefined}
1265
1108
  streamType="on-demand"
@@ -1344,18 +1187,26 @@ function FilePlayer({
1344
1187
  <div className="relative h-full w-full" onPointerEnter={handleHoverEnter} onPointerLeave={handleHoverLeave}>
1345
1188
  {player}
1346
1189
  {unmuteBadge}
1347
- {errorOverlay}
1348
1190
  </div>
1349
1191
  );
1350
1192
  }
1351
- // A relative wrapper so the unmute badge and the error overlay can dock. The
1352
- // bare `player` return is left only for chromeless previews (never monitored).
1353
- if (hoverControlled || autoPlayUnmuted || startMuted || monitorHealth) {
1193
+ if (hoverControlled) {
1194
+ return (
1195
+ <div className="relative h-full w-full">
1196
+ {player}
1197
+ {unmuteBadge}
1198
+ </div>
1199
+ );
1200
+ }
1201
+ // Handoff surfaces (autoPlayUnmuted / startMuted) need the relative wrapper so
1202
+ // the internal center unmute badge can dock — the bare branch has none. Hosts
1203
+ // that render their OWN control pass hideMutedBadge (unmuteBadge is null then,
1204
+ // but the wrapper is harmless).
1205
+ if (autoPlayUnmuted || startMuted) {
1354
1206
  return (
1355
1207
  <div className="relative h-full w-full">
1356
1208
  {player}
1357
1209
  {unmuteBadge}
1358
- {errorOverlay}
1359
1210
  </div>
1360
1211
  );
1361
1212
  }
@@ -1437,9 +1288,6 @@ const YT_PLAYING_BLUR_DELAY_MS = 1000;
1437
1288
  interface YouTubeInfoDeliveryMessage {
1438
1289
  event?: string;
1439
1290
  info?: { playerState?: number };
1440
- /** `onError` carries its code as a bare number in `info`, not an object:
1441
- * `{"event":"onError","info":150}` (101/150 = embedding disabled). */
1442
- errorCode?: number;
1443
1291
  }
1444
1292
 
1445
1293
  /**
@@ -1459,7 +1307,6 @@ function toYouTubeMessage(parsed: unknown): YouTubeInfoDeliveryMessage | null {
1459
1307
  return {
1460
1308
  event: typeof event === 'string' ? event : undefined,
1461
1309
  info: { playerState: typeof playerState === 'number' ? playerState : undefined },
1462
- errorCode: typeof info === 'number' ? info : undefined,
1463
1310
  };
1464
1311
  }
1465
1312
 
@@ -1473,18 +1320,8 @@ function YouTubeFacadeInner({
1473
1320
  suspended,
1474
1321
  }: YouTubeFacadeInnerProps): React.ReactElement {
1475
1322
  const [activated, setActivated] = useState(Boolean(autoActivate));
1476
- // The embed reported a hard player error (see the `onError` branch below).
1477
- // Retry remounts the iframe via `reloadNonce` — a fresh element, since there
1478
- // is no way to re-init a cross-origin player from outside.
1479
- const [failed, setFailed] = useState(false);
1480
- const [reloadNonce, setReloadNonce] = useState(0);
1481
1323
  const iframeRef = useRef<HTMLIFrameElement | null>(null);
1482
1324
 
1483
- const retry = useCallback(() => {
1484
- setFailed(false);
1485
- setReloadNonce(n => n + 1);
1486
- }, []);
1487
-
1488
1325
  // Embed URL + poster URLs only change when `videoId` or `minimalControls`
1489
1326
  // do — memoize so we don't rebuild URLSearchParams on every render.
1490
1327
  //
@@ -1577,7 +1414,7 @@ function YouTubeFacadeInner({
1577
1414
  // end-of-video (ENDED).
1578
1415
  // ---------------------------------------------------------------------------
1579
1416
  useEffect(() => {
1580
- if (!activated || failed) return undefined;
1417
+ if (!activated) return undefined;
1581
1418
  const iframe = iframeRef.current;
1582
1419
  if (!iframe) return undefined;
1583
1420
 
@@ -1590,10 +1427,6 @@ function YouTubeFacadeInner({
1590
1427
 
1591
1428
  let blurTimer: ReturnType<typeof setTimeout> | null = null;
1592
1429
 
1593
- // No "never reached PLAYING within N seconds" watchdog on purpose: an embed
1594
- // whose unmuted autoplay Safari/iOS blocked, or one whose jsapi channel is
1595
- // dead, is healthy and silent — a timeout would tear those down, and retry
1596
- // would re-arm it. Only an explicit `onError` is a definitive failure.
1597
1430
  function handleMessage(event: MessageEvent) {
1598
1431
  if (event.origin !== YT_NOCOOKIE_ORIGIN) return;
1599
1432
  if (typeof event.data !== 'string') return;
@@ -1603,13 +1436,7 @@ function YouTubeFacadeInner({
1603
1436
  } catch {
1604
1437
  return;
1605
1438
  }
1606
- if (!payload) return;
1607
- if (payload.event === 'onError') {
1608
- setFailed(true);
1609
- reportPlaybackFailure({ kind: 'youtube', src: videoId, reason: 'error', errorCode: payload.errorCode });
1610
- return;
1611
- }
1612
- if (payload.event !== 'infoDelivery') return;
1439
+ if (!payload || payload.event !== 'infoDelivery') return;
1613
1440
  const state = payload.info?.playerState;
1614
1441
  if (typeof state !== 'number') return;
1615
1442
 
@@ -1632,7 +1459,7 @@ function YouTubeFacadeInner({
1632
1459
  window.removeEventListener('message', handleMessage);
1633
1460
  if (blurTimer !== null) clearTimeout(blurTimer);
1634
1461
  };
1635
- }, [activated, failed, reloadNonce, videoId]);
1462
+ }, [activated]);
1636
1463
 
1637
1464
  // Close-side pause: a closing dialog flips `suspended` false→true. Post the
1638
1465
  // pauseVideo command over the same enablejsapi channel so the iframe stops
@@ -1655,19 +1482,10 @@ function YouTubeFacadeInner({
1655
1482
  const wrapperClass = `relative w-full ${className ?? ''}`;
1656
1483
  const wrapperStyle = { paddingBottom: '56.25%' as const };
1657
1484
 
1658
- if (activated && failed) {
1659
- return (
1660
- <div className={wrapperClass} style={wrapperStyle}>
1661
- <VideoErrorOverlay onRetry={retry} watchOnYouTubeId={videoId} />
1662
- </div>
1663
- );
1664
- }
1665
-
1666
1485
  if (activated) {
1667
1486
  return (
1668
1487
  <div className={wrapperClass} style={wrapperStyle}>
1669
1488
  <iframe
1670
- key={reloadNonce}
1671
1489
  ref={iframeRef}
1672
1490
  src={embedUrl}
1673
1491
  allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"