@zolomedia/bifrost-client 1.7.74

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 (140) hide show
  1. package/L1_Foundation/L1_Foundation.js +13 -0
  2. package/L1_Foundation/bootstrap/bootstrap.js +11 -0
  3. package/L1_Foundation/bootstrap/bootstrap_hooks.js +123 -0
  4. package/L1_Foundation/bootstrap/bootstrap_index.js +15 -0
  5. package/L1_Foundation/bootstrap/bootstrap_logger.js +135 -0
  6. package/L1_Foundation/bootstrap/cdn_loader.js +217 -0
  7. package/L1_Foundation/bootstrap/module_registry.js +102 -0
  8. package/L1_Foundation/bootstrap/prism_loader.js +164 -0
  9. package/L1_Foundation/config/client_config.js +110 -0
  10. package/L1_Foundation/config/config.js +7 -0
  11. package/L1_Foundation/connection/connection.js +8 -0
  12. package/L1_Foundation/connection/websocket_connection.js +122 -0
  13. package/L1_Foundation/constants/bifrost_constants.js +284 -0
  14. package/L1_Foundation/constants/constants.js +7 -0
  15. package/L1_Foundation/logger/logger.js +10 -0
  16. package/L2_Handling/L2_Handling.js +15 -0
  17. package/L2_Handling/cache/cache.js +22 -0
  18. package/L2_Handling/cache/cache_constants.js +69 -0
  19. package/L2_Handling/cache/orchestration/cache_manager.js +299 -0
  20. package/L2_Handling/cache/orchestration/cache_orchestrator.js +260 -0
  21. package/L2_Handling/cache/orchestration/orchestration.js +12 -0
  22. package/L2_Handling/cache/storage/session_manager.js +289 -0
  23. package/L2_Handling/cache/storage/storage.js +10 -0
  24. package/L2_Handling/cache/storage/storage_manager.js +590 -0
  25. package/L2_Handling/display/composite/composite.js +13 -0
  26. package/L2_Handling/display/composite/dashboard_renderer.js +221 -0
  27. package/L2_Handling/display/composite/swiper_renderer.js +564 -0
  28. package/L2_Handling/display/composite/terminal_renderer.js +922 -0
  29. package/L2_Handling/display/composite/wizard_conditional_renderer.js +274 -0
  30. package/L2_Handling/display/display.js +30 -0
  31. package/L2_Handling/display/feedback/feedback.js +11 -0
  32. package/L2_Handling/display/feedback/progressbar_renderer.js +418 -0
  33. package/L2_Handling/display/feedback/spinner_renderer.js +246 -0
  34. package/L2_Handling/display/inputs/button_renderer.js +634 -0
  35. package/L2_Handling/display/inputs/form_renderer.js +583 -0
  36. package/L2_Handling/display/inputs/input_renderer.js +658 -0
  37. package/L2_Handling/display/inputs/inputs.js +12 -0
  38. package/L2_Handling/display/navigation/menu_renderer.js +206 -0
  39. package/L2_Handling/display/navigation/navigation.js +11 -0
  40. package/L2_Handling/display/navigation/navigation_renderer.js +703 -0
  41. package/L2_Handling/display/orchestration/orchestration.js +11 -0
  42. package/L2_Handling/display/orchestration/renderer.js +430 -0
  43. package/L2_Handling/display/orchestration/zdisplay_orchestrator.js +1759 -0
  44. package/L2_Handling/display/outputs/alert_renderer.js +161 -0
  45. package/L2_Handling/display/outputs/audio_renderer.js +94 -0
  46. package/L2_Handling/display/outputs/card_renderer.js +229 -0
  47. package/L2_Handling/display/outputs/code_renderer.js +66 -0
  48. package/L2_Handling/display/outputs/dl_renderer.js +131 -0
  49. package/L2_Handling/display/outputs/header_renderer.js +162 -0
  50. package/L2_Handling/display/outputs/icon_renderer.js +107 -0
  51. package/L2_Handling/display/outputs/image_renderer.js +145 -0
  52. package/L2_Handling/display/outputs/list_renderer.js +190 -0
  53. package/L2_Handling/display/outputs/outputs.js +19 -0
  54. package/L2_Handling/display/outputs/table_renderer.js +765 -0
  55. package/L2_Handling/display/outputs/text_renderer.js +818 -0
  56. package/L2_Handling/display/outputs/typography_renderer.js +293 -0
  57. package/L2_Handling/display/outputs/video_renderer.js +116 -0
  58. package/L2_Handling/display/primitives/document_structure_primitives.js +319 -0
  59. package/L2_Handling/display/primitives/form_primitives.js +526 -0
  60. package/L2_Handling/display/primitives/generic_containers.js +109 -0
  61. package/L2_Handling/display/primitives/interactive_primitives.js +305 -0
  62. package/L2_Handling/display/primitives/link_primitives.js +552 -0
  63. package/L2_Handling/display/primitives/lists_primitives.js +262 -0
  64. package/L2_Handling/display/primitives/media_primitives.js +383 -0
  65. package/L2_Handling/display/primitives/primitives.js +19 -0
  66. package/L2_Handling/display/primitives/semantic_element_primitive.js +226 -0
  67. package/L2_Handling/display/primitives/table_primitives.js +528 -0
  68. package/L2_Handling/display/primitives/typography_primitives.js +175 -0
  69. package/L2_Handling/display/specialized/input_request_renderer.js +467 -0
  70. package/L2_Handling/display/specialized/specialized.js +10 -0
  71. package/L2_Handling/hooks/hooks.js +9 -0
  72. package/L2_Handling/hooks/menu_integration.js +57 -0
  73. package/L2_Handling/hooks/widget_hook_manager.js +292 -0
  74. package/L2_Handling/message/message.js +8 -0
  75. package/L2_Handling/message/message_handler.js +701 -0
  76. package/L2_Handling/navigation/navigation.js +8 -0
  77. package/L2_Handling/navigation/navigation_manager.js +403 -0
  78. package/L2_Handling/zhooks/features/cache_live.js +287 -0
  79. package/L2_Handling/zhooks/features/crumbs_live.js +292 -0
  80. package/L2_Handling/zhooks/zhooks_manager.js +65 -0
  81. package/L2_Handling/zvaf/zvaf.js +8 -0
  82. package/L2_Handling/zvaf/zvaf_manager.js +334 -0
  83. package/L3_Abstraction/L3_Abstraction.js +12 -0
  84. package/L3_Abstraction/orchestrator/container_unwrapper.js +101 -0
  85. package/L3_Abstraction/orchestrator/group_renderer.js +698 -0
  86. package/L3_Abstraction/orchestrator/input_event_handler.js +797 -0
  87. package/L3_Abstraction/orchestrator/metadata_processor.js +249 -0
  88. package/L3_Abstraction/orchestrator/navbar_builder.js +201 -0
  89. package/L3_Abstraction/orchestrator/orchestrator.js +13 -0
  90. package/L3_Abstraction/orchestrator/wizard_gate_handler.js +360 -0
  91. package/L3_Abstraction/renderer/renderer.js +1 -0
  92. package/L3_Abstraction/session/session.js +1 -0
  93. package/L4_Orchestration/L4_Orchestration.js +11 -0
  94. package/L4_Orchestration/client/client.js +1 -0
  95. package/L4_Orchestration/facade/facade.js +9 -0
  96. package/L4_Orchestration/facade/manager_registry.js +118 -0
  97. package/L4_Orchestration/facade/renderer_registry.js +274 -0
  98. package/L4_Orchestration/lifecycle/asset_loader.js +255 -0
  99. package/L4_Orchestration/lifecycle/initializer.js +135 -0
  100. package/L4_Orchestration/lifecycle/lifecycle.js +8 -0
  101. package/L4_Orchestration/rendering/facade.js +94 -0
  102. package/L4_Orchestration/rendering/rendering.js +7 -0
  103. package/LICENSE +21 -0
  104. package/README.md +82 -0
  105. package/bifrost_client.js +204 -0
  106. package/bifrost_core.js +1686 -0
  107. package/docs/ARCHITECTURE.md +111 -0
  108. package/docs/PROTOCOL.md +106 -0
  109. package/docs/RENDERERS.md +101 -0
  110. package/docs/SECURITY.md +92 -0
  111. package/package.json +24 -0
  112. package/syntax/prism-zconfig.js +41 -0
  113. package/syntax/prism-zenv.js +69 -0
  114. package/syntax/prism-zolo-theme.css +288 -0
  115. package/syntax/prism-zolo.js +380 -0
  116. package/syntax/prism-zschema.js +38 -0
  117. package/syntax/prism-zspark.js +25 -0
  118. package/syntax/prism-zui.js +68 -0
  119. package/zSys/accessibility/accessibility.js +10 -0
  120. package/zSys/accessibility/emoji_accessibility.js +173 -0
  121. package/zSys/dom/block_utils.js +122 -0
  122. package/zSys/dom/container_utils.js +370 -0
  123. package/zSys/dom/dom.js +13 -0
  124. package/zSys/dom/dom_utils.js +328 -0
  125. package/zSys/dom/encoding_utils.js +117 -0
  126. package/zSys/dom/style_utils.js +71 -0
  127. package/zSys/errors/error_display.js +299 -0
  128. package/zSys/errors/errors.js +10 -0
  129. package/zSys/theme/color_utils.js +274 -0
  130. package/zSys/theme/dark_mode_utils.js +272 -0
  131. package/zSys/theme/size_utils.js +256 -0
  132. package/zSys/theme/spacing_utils.js +405 -0
  133. package/zSys/theme/theme.js +14 -0
  134. package/zSys/theme/zbase.css +1735 -0
  135. package/zSys/theme/zbase_inject.js +161 -0
  136. package/zSys/theme/ztheme_utils.js +305 -0
  137. package/zSys/validation/error_boundary.js +201 -0
  138. package/zSys/validation/validation.js +11 -0
  139. package/zSys/validation/validation_utils.js +238 -0
  140. package/zSys/zSys.js +14 -0
@@ -0,0 +1,117 @@
1
+ /**
2
+ * ═══════════════════════════════════════════════════════════════
3
+ * Encoding Utilities - String Encoding/Decoding (Layer 2)
4
+ * ═══════════════════════════════════════════════════════════════
5
+ *
6
+ * Pure utility functions for string encoding and decoding operations.
7
+ * Extracted from duplicate implementations in 4 renderer files.
8
+ *
9
+ * @module utils/encoding_utils
10
+ * @layer 2 (Utilities - Pure functions)
11
+ *
12
+ * Dependencies: None (Layer 0 - Browser APIs only)
13
+ *
14
+ * Exports:
15
+ * - decodeUnicodeEscapes(text): Decode Unicode escape sequences
16
+ * - escapeHtml(text): Escape the 5 HTML-significant chars (SSOT — text & attr safe)
17
+ * - safeHref(url): Block dangerous URL schemes + attr-escape (SSOT for href values)
18
+ *
19
+ * Example:
20
+ * ```javascript
21
+ * import { decodeUnicodeEscapes, escapeHtml, safeHref } from '../../zSys/dom/encoding_utils.js';
22
+ * const decoded = decodeUnicodeEscapes('Hello \\u2764\\uFE0F'); // "Hello ❤️"
23
+ * el.innerHTML = `<a href="${safeHref(url)}">${escapeHtml(label)}</a>`;
24
+ * ```
25
+ */
26
+
27
+ // ─────────────────────────────────────────────────────────────────
28
+ // HTML Escaping (SSOT) — replaces per-renderer ad-hoc escape chains
29
+ // ─────────────────────────────────────────────────────────────────
30
+
31
+ const _HTML_ESCAPES = {
32
+ '&': '&amp;',
33
+ '<': '&lt;',
34
+ '>': '&gt;',
35
+ '"': '&quot;',
36
+ "'": '&#039;',
37
+ };
38
+
39
+ /**
40
+ * Escape the five HTML-significant characters. Safe for both element text and
41
+ * double/single-quoted attribute contexts (escapes both " and '). Deterministic,
42
+ * no DOM dependency. This is the single source of truth for HTML escaping in the
43
+ * client — renderers must not hand-roll their own `.replace(/&/g, ...)` chains.
44
+ *
45
+ * @param {*} text - Value to escape (coerced to string; null/undefined → '')
46
+ * @returns {string} Escaped string
47
+ */
48
+ export function escapeHtml(text) {
49
+ if (text === null || text === undefined) return '';
50
+ return String(text).replace(/[&<>"']/g, (ch) => _HTML_ESCAPES[ch]);
51
+ }
52
+
53
+ // Schemes that can execute script / smuggle payloads when placed in href/src.
54
+ const _DANGEROUS_SCHEME = /^(javascript|data|vbscript):/i;
55
+
56
+ /**
57
+ * Sanitize a URL for safe embedding in an href/src attribute. Blocks dangerous
58
+ * schemes (javascript:, data:, vbscript:) — including whitespace/control-char
59
+ * obfuscation — then attribute-escapes the result. Returns '#' for blocked or
60
+ * empty input. http(s)/mailto/tel/anchor/relative/zPath URLs pass through.
61
+ *
62
+ * @param {*} url - Candidate URL (already zPath-resolved by the caller)
63
+ * @returns {string} Safe, attribute-escaped URL or '#'
64
+ */
65
+ export function safeHref(url) {
66
+ if (url === null || url === undefined) return '#';
67
+ const raw = String(url).trim();
68
+ if (!raw) return '#';
69
+ // Strip whitespace + control chars before the scheme test so "java\tscript:"
70
+ // and " javascript:" cannot slip past the guard.
71
+ const probe = raw.replace(/[\u0000-\u001F\u007F\s]/g, '');
72
+ if (_DANGEROUS_SCHEME.test(probe)) return '#';
73
+ return escapeHtml(raw);
74
+ }
75
+
76
+ // ─────────────────────────────────────────────────────────────────
77
+ // Unicode Decoding
78
+ // ─────────────────────────────────────────────────────────────────
79
+
80
+ /**
81
+ * Decode Unicode escape sequences in text
82
+ *
83
+ * Handles multiple Unicode escape formats:
84
+ * - \uXXXX: Standard 4-digit Unicode escape (e.g., \u2764 → ❤)
85
+ * - \UXXXXXXXX: Extended 4-8 digit for supplementary characters & emojis
86
+ * - Basic escape sequences: \n, \t, \r, etc.
87
+ *
88
+ * @param {string} text - Text containing Unicode escapes
89
+ * @returns {string} Decoded text
90
+ *
91
+ * @example
92
+ * decodeUnicodeEscapes('Hello \\u2764\\uFE0F'); // "Hello ❤️"
93
+ * decodeUnicodeEscapes('Line 1\\nLine 2'); // "Line 1\nLine 2"
94
+ * decodeUnicodeEscapes('\\U0001F600'); // "😀"
95
+ */
96
+ export function decodeUnicodeEscapes(text) {
97
+ if (!text || typeof text !== 'string') return text;
98
+
99
+ // Replace \uXXXX format (standard 4-digit Unicode escape)
100
+ text = text.replace(/\\u([0-9A-Fa-f]{4})/g, (match, hexCode) => {
101
+ return String.fromCodePoint(parseInt(hexCode, 16));
102
+ });
103
+
104
+ // Replace \UXXXXXXXX format (extended 4-8 digit for supplementary characters & emojis)
105
+ text = text.replace(/\\U([0-9A-Fa-f]{4,8})/g, (match, hexCode) => {
106
+ return String.fromCodePoint(parseInt(hexCode, 16));
107
+ });
108
+
109
+ // Replace basic escape sequences (literal strings like \\n, \\t, etc.)
110
+ // These come from JSON where Python sends "\n" which becomes "\\n" in JSON
111
+ text = text.replace(/\\n/g, '\n');
112
+ text = text.replace(/\\r/g, '\r');
113
+ text = text.replace(/\\t/g, '\t');
114
+ text = text.replace(/\\\\/g, '\\');
115
+
116
+ return text;
117
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * zSys/dom/style_utils.js
3
+ *
4
+ * Style Conversion Utilities
5
+ *
6
+ * Handles _zStyle metadata conversion from various formats to CSS strings.
7
+ * Supports both legacy inline string format and new nested object syntax.
8
+ *
9
+ * Created: 2026-04-19 - Phase 1.0 - _zStyle nested syntax migration
10
+ */
11
+
12
+ /**
13
+ * Convert _zStyle to CSS string
14
+ *
15
+ * Supports two formats:
16
+ * 1. String (legacy): "color: red; font-size: 16px"
17
+ * 2. Object (nested): { "color": "red", "font-size": "16px" }
18
+ *
19
+ * @param {string|Object} style - CSS string or object with CSS properties
20
+ * @param {Object} [logger=null] - Optional logger for warnings
21
+ * @returns {string} CSS string for style attribute (empty string if invalid)
22
+ *
23
+ * @example
24
+ * // String passthrough (legacy/inline)
25
+ * convertStyleToString("color: red; font-size: 16px")
26
+ * // => "color: red; font-size: 16px"
27
+ *
28
+ * @example
29
+ * // Object to CSS string (new nested syntax)
30
+ * convertStyleToString({
31
+ * "border-bottom": "2px solid var(--color-primary)",
32
+ * "background": "red",
33
+ * "letter-spacing": "0.1em"
34
+ * })
35
+ * // => "border-bottom: 2px solid var(--color-primary); background: red; letter-spacing: 0.1em"
36
+ *
37
+ * @example
38
+ * // CSS variables work in both formats
39
+ * convertStyleToString({ "color": "var(--color-primary)" })
40
+ * // => "color: var(--color-primary)"
41
+ *
42
+ * @example
43
+ * // Empty/null/undefined values filtered out
44
+ * convertStyleToString({ "color": "red", "background": null, "font-size": "" })
45
+ * // => "color: red"
46
+ */
47
+ export function convertStyleToString(style, logger = null) {
48
+ // Handle null/undefined
49
+ if (style === null || style === undefined || style === '') {
50
+ return '';
51
+ }
52
+
53
+ // Legacy format: inline CSS string
54
+ if (typeof style === 'string') {
55
+ return style.trim();
56
+ }
57
+
58
+ // New format: nested object (CSS-in-YAML)
59
+ if (typeof style === 'object' && !Array.isArray(style)) {
60
+ const cssString = Object.entries(style)
61
+ .filter(([_, value]) => value !== undefined && value !== null && value !== '')
62
+ .map(([prop, value]) => `${prop}: ${value}`)
63
+ .join('; ');
64
+
65
+ return cssString;
66
+ }
67
+
68
+ // Invalid type
69
+ logger?.warn(`[StyleUtils] Invalid _zStyle type: ${typeof style}`, style);
70
+ return '';
71
+ }
@@ -0,0 +1,299 @@
1
+ /**
2
+ *
3
+ * Error Display Module - Visual Error Boundaries for UI
4
+ *
5
+ */
6
+
7
+ export class ErrorDisplay {
8
+ constructor(options = {}) {
9
+ this.containerId = options.containerId || 'bifrost-errors';
10
+ this.autoCreate = options.autoCreate !== false; // Default true
11
+ this.maxErrors = options.maxErrors || 5; // Max errors to show
12
+ this.autoDismiss = options.autoDismiss || 10000; // TIMEOUTS.AUTO_DISMISS (UMD limitation, can't import)
13
+ this.position = options.position || 'top-right'; // top-right, top-left, bottom-right, bottom-left
14
+
15
+ this.errors = [];
16
+ this.container = null;
17
+ // Dedup: collapse repeated identical errors (e.g. WebSocket reconnect loops,
18
+ // missing _requestId) into ONE toast with a ×N counter. Repeats after the
19
+ // first go to the console only — dev-accurate without the UX spam.
20
+ this._active = new Map(); // key -> { el, countEl, count, timer }
21
+
22
+ if (this.autoCreate) {
23
+ this._createContainer();
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Create error container if it doesn't exist
29
+ * @private
30
+ */
31
+ _createContainer() {
32
+ // Check if container already exists
33
+ this.container = document.getElementById(this.containerId);
34
+
35
+ if (!this.container) {
36
+ this.container = document.createElement('div');
37
+ this.container.id = this.containerId;
38
+
39
+ // Canonical, class-based styling (SSOT in zbase.css) — no inline styles.
40
+ // A corner modifier selects the fixed position.
41
+ const corner = ['top-right', 'top-left', 'bottom-right', 'bottom-left']
42
+ .includes(this.position) ? this.position : 'top-right';
43
+ this.container.className =
44
+ `bifrost-error-container bifrost-error-container--${corner}`;
45
+
46
+ // Centralize under the <zVaF> root (SSOT — all bifrost chrome lives there);
47
+ // fall back to <body> if the root isn't present yet.
48
+ const root = document.querySelector('zVaF') || document.body;
49
+ root.appendChild(this.container);
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Display an error in the UI
55
+ */
56
+ show(errorInfo) {
57
+ if (!this.container) {
58
+ this._createContainer();
59
+ }
60
+
61
+ // ── Dedup ──────────────────────────────────────────────────────────────
62
+ // Same title+message already on screen → don't stack another toast. Bump its
63
+ // ×N counter, refresh its auto-dismiss, and log the repeat to the console.
64
+ const dedupeKey = `${this._getErrorTitle(errorInfo)}::${errorInfo.message || ''}`;
65
+ const existing = this._active.get(dedupeKey);
66
+ if (existing && existing.el && existing.el.parentNode) {
67
+ existing.count += 1;
68
+ if (existing.countEl) existing.countEl.textContent = ` ×${existing.count}`;
69
+ if (typeof console !== 'undefined' && console.warn) {
70
+ console.warn('[Bifrost][repeat suppressed]', dedupeKey, errorInfo);
71
+ }
72
+ if (existing.timer) clearTimeout(existing.timer);
73
+ if (this.autoDismiss) {
74
+ existing.timer = setTimeout(() => this._dismissError(existing.el), this.autoDismiss);
75
+ }
76
+ return;
77
+ }
78
+
79
+ // Create error element
80
+ const errorEl = document.createElement('div');
81
+ errorEl.className = 'bifrost-error';
82
+ errorEl.style.cssText = `
83
+ background: #fee;
84
+ border-left: 4px solid #c33;
85
+ padding: 1rem;
86
+ margin-bottom: 0.5rem;
87
+ border-radius: 4px;
88
+ box-shadow: 0 2px 8px rgba(0,0,0,0.15);
89
+ pointer-events: auto;
90
+ animation: slideIn 0.3s ease-out;
91
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
92
+ font-size: 0.875rem;
93
+ line-height: 1.5;
94
+ `;
95
+
96
+ // Error title
97
+ const title = document.createElement('div');
98
+ title.style.cssText = `
99
+ font-weight: 600;
100
+ color: #c33;
101
+ margin-bottom: 0.5rem;
102
+ display: flex;
103
+ justify-content: space-between;
104
+ align-items: center;
105
+ `;
106
+ title.innerHTML = `
107
+ <span>[WARN] ${this._getErrorTitle(errorInfo)}<span class="bifrost-error-count" style="font-weight:600;"></span></span>
108
+ <button style="
109
+ background: none;
110
+ border: none;
111
+ color: #c33;
112
+ cursor: pointer;
113
+ font-size: 1.2rem;
114
+ padding: 0;
115
+ margin-left: 0.5rem;
116
+ line-height: 1;
117
+ " title="Dismiss">×</button>
118
+ `;
119
+
120
+ // Error message
121
+ const message = document.createElement('div');
122
+ message.style.cssText = 'color: #600; margin-bottom: 0.5rem;';
123
+ message.textContent = errorInfo.message || 'An error occurred';
124
+
125
+ // Error details (collapsible)
126
+ const details = document.createElement('details');
127
+ details.style.cssText = 'color: #800; font-size: 0.75rem; margin-top: 0.5rem;';
128
+ details.innerHTML = `
129
+ <summary style="cursor: pointer; user-select: none;">Show details</summary>
130
+ <pre style="
131
+ margin-top: 0.5rem;
132
+ padding: 0.5rem;
133
+ background: #fff;
134
+ border-radius: 3px;
135
+ overflow-x: auto;
136
+ font-size: 0.7rem;
137
+ white-space: pre-wrap;
138
+ word-wrap: break-word;
139
+ ">${this._formatStack(errorInfo)}</pre>
140
+ `;
141
+
142
+ errorEl.appendChild(title);
143
+ errorEl.appendChild(message);
144
+ errorEl.appendChild(details);
145
+
146
+ // Add dismiss handler
147
+ const dismissBtn = title.querySelector('button');
148
+ dismissBtn.onclick = () => this._dismissError(errorEl);
149
+
150
+ // Add to container
151
+ this.container.appendChild(errorEl);
152
+ this.errors.push(errorEl);
153
+
154
+ // Register as the active toast for this dedupe key
155
+ const countEl = title.querySelector('.bifrost-error-count');
156
+ const entry = { el: errorEl, countEl, count: 1, timer: null, key: dedupeKey };
157
+ errorEl.dataset.dedupeKey = dedupeKey;
158
+ this._active.set(dedupeKey, entry);
159
+
160
+ // Remove oldest error if we exceed max
161
+ if (this.errors.length > this.maxErrors) {
162
+ const oldest = this.errors.shift();
163
+ if (oldest && oldest.parentNode) {
164
+ oldest.remove();
165
+ }
166
+ }
167
+
168
+ // Auto-dismiss after timeout
169
+ if (this.autoDismiss) {
170
+ entry.timer = setTimeout(() => this._dismissError(errorEl), this.autoDismiss);
171
+ }
172
+
173
+ // Add slide-in animation
174
+ this._addAnimationStyles();
175
+ }
176
+
177
+ /**
178
+ * Dismiss an error
179
+ * @private
180
+ */
181
+ _dismissError(errorEl) {
182
+ if (!errorEl || !errorEl.parentNode) {
183
+ return;
184
+ }
185
+
186
+ // Fade out animation
187
+ errorEl.style.animation = 'fadeOut 0.3s ease-out';
188
+
189
+ // Release the dedupe slot so a later occurrence can toast fresh
190
+ const key = errorEl.dataset ? errorEl.dataset.dedupeKey : null;
191
+ if (key && this._active.get(key)?.el === errorEl) {
192
+ const entry = this._active.get(key);
193
+ if (entry.timer) clearTimeout(entry.timer);
194
+ this._active.delete(key);
195
+ }
196
+
197
+ setTimeout(() => {
198
+ if (errorEl.parentNode) {
199
+ errorEl.remove();
200
+ }
201
+ const index = this.errors.indexOf(errorEl);
202
+ if (index > -1) {
203
+ this.errors.splice(index, 1);
204
+ }
205
+ }, 300); // TIMEOUTS.FADE_TRANSITION (UMD limitation, can't import)
206
+ }
207
+
208
+ /**
209
+ * Get error title based on error type
210
+ * @private
211
+ */
212
+ _getErrorTitle(errorInfo) {
213
+ if (errorInfo.type === 'hook_error') {
214
+ return `Hook Error: ${errorInfo.hookName}`;
215
+ }
216
+ if (errorInfo.type === 'render_error') {
217
+ return 'Rendering Error';
218
+ }
219
+ if (errorInfo.type === 'connection_error') {
220
+ return 'Connection Error';
221
+ }
222
+ return 'BifrostClient Error';
223
+ }
224
+
225
+ /**
226
+ * Format error stack for display
227
+ * @private
228
+ */
229
+ _formatStack(errorInfo) {
230
+ if (errorInfo.stack) {
231
+ return errorInfo.stack;
232
+ }
233
+ if (errorInfo.error && errorInfo.error.stack) {
234
+ return errorInfo.error.stack;
235
+ }
236
+ return JSON.stringify(errorInfo, null, 2);
237
+ }
238
+
239
+ /**
240
+ * Add animation styles to document
241
+ * @private
242
+ */
243
+ _addAnimationStyles() {
244
+ if (document.getElementById('bifrost-error-styles')) {
245
+ return;
246
+ }
247
+
248
+ const style = document.createElement('style');
249
+ style.id = 'bifrost-error-styles';
250
+ style.textContent = `
251
+ @keyframes slideIn {
252
+ from {
253
+ transform: translateX(100%);
254
+ opacity: 0;
255
+ }
256
+ to {
257
+ transform: translateX(0);
258
+ opacity: 1;
259
+ }
260
+ }
261
+
262
+ @keyframes fadeOut {
263
+ from {
264
+ opacity: 1;
265
+ }
266
+ to {
267
+ opacity: 0;
268
+ }
269
+ }
270
+ `;
271
+ document.head.appendChild(style);
272
+ }
273
+
274
+ /**
275
+ * Clear all errors
276
+ */
277
+ clearAll() {
278
+ this.errors.forEach(errorEl => {
279
+ if (errorEl.parentNode) {
280
+ errorEl.remove();
281
+ }
282
+ });
283
+ this.errors = [];
284
+ this._active.forEach(entry => { if (entry.timer) clearTimeout(entry.timer); });
285
+ this._active.clear();
286
+ }
287
+
288
+ /**
289
+ * Destroy error display (remove container)
290
+ */
291
+ destroy() {
292
+ this.clearAll();
293
+ if (this.container && this.container.parentNode) {
294
+ this.container.remove();
295
+ }
296
+ this.container = null;
297
+ }
298
+ }
299
+
@@ -0,0 +1,10 @@
1
+ /**
2
+ * zSys/errors - Error Utilities Barrel
3
+ *
4
+ * Error display and formatting utilities.
5
+ *
6
+ * @module zSys/errors
7
+ * @layer zSys (System Utilities)
8
+ */
9
+
10
+ export * from './error_display.js';