omnibox.ts RawHistoryFolder
1/**
2 * Omnibox Module Initialization
3 *
4 * Initializes the Svelte 5 omnibox component system
5 */
6
7import { mount } from "svelte";
8import { Omnibox } from "../../components/omnibox";
9import { ensureShadowMount } from "./shadowHost";
10import type { OmniboxConfig } from "../../components/omnibox/types";
11
12let omniboxComponent: ReturnType<typeof mount> | null = null;
13let isInitialized = false;
14
15export interface OmniboxInitConfig extends OmniboxConfig {
16 // Additional initialization options if needed
17 containerId?: string;
18}
19
20/**
21 * Initialize the omnibox component system
22 */
23export async function initializeOmnibox(
24 _config: OmniboxInitConfig = {},
25): Promise<void> {
26 if (isInitialized) {
27 console.warn("Omnibox already initialized");
28 return;
29 }
30
31 try {
32 // Ensure we're in the main frame (not an iframe)
33 if (window.self !== window.top) {
34 console.log("🚫 Omnibox skipped in iframe");
35 return;
36 }
37
38 // Check if DOM is ready
39 if (!document.body) {
40 console.warn("DOM body not ready for omnibox initialization");
41 return;
42 }
43
44 // Mount omnibox into the shared global Shadow DOM host
45 const mountEl = ensureShadowMount("dumber-omnibox");
46 omniboxComponent = mount(Omnibox, {
47 target: mountEl as unknown as Element,
48 });
49
50 // Wait for the component to mount and set up the global API
51 await new Promise<void>((resolve) => {
52 const checkAPI = () => {
53 if (
54 window.__dumber_omnibox &&
55 typeof window.__dumber_omnibox === "object"
56 ) {
57 console.log("✅ Omnibox component system initialized");
58 console.log(
59 "🔧 Global API is available:",
60 Object.keys(window.__dumber_omnibox),
61 );
62 isInitialized = true;
63 // Notify isolated bundle listeners that omnibox is ready
64 try {
65 document.dispatchEvent(new CustomEvent("dumber:omnibox-ready"));
66 } catch (e) {
67 console.warn("Failed to dispatch omnibox-ready event", e);
68 }
69 resolve();
70 } else {
71 setTimeout(checkAPI, 10); // Check again in 10ms
72 }
73 };
74 checkAPI();
75 });
76
77 // Bridge: listen for page-world events carrying suggestions and forward to API
78 const handleSuggestionsEvent = (e: Event) => {
79 try {
80 const detail = (e as CustomEvent).detail;
81 const suggestions = detail?.suggestions ?? detail;
82 if (
83 Array.isArray(suggestions) &&
84 window.__dumber_omnibox?.setSuggestions
85 ) {
86 console.log(
87 "🔗 [Bridge] Received page-world suggestions event:",
88 suggestions.length,
89 );
90 window.__dumber_omnibox.setSuggestions(suggestions);
91 } else {
92 console.warn(
93 "🔗 [Bridge] Suggestions event received but API not ready or invalid payload",
94 );
95 }
96 } catch (err) {
97 console.warn("🔗 [Bridge] Failed handling suggestions event:", err);
98 }
99 };
100
101 document.addEventListener(
102 "dumber:omnibox-suggestions",
103 handleSuggestionsEvent,
104 false,
105 );
106 // Unified event name
107 document.addEventListener(
108 "dumber:omnibox:suggestions",
109 handleSuggestionsEvent,
110 false,
111 );
112 } catch (error) {
113 console.error("❌ Failed to initialize omnibox component:", error);
114 throw error;
115 }
116}
117
118/**
119 * Get the current initialization status
120 */
121export function isOmniboxInitialized(): boolean {
122 return isInitialized;
123}
124
125/**
126 * Cleanup omnibox component (useful for hot reload during development)
127 */
128export function cleanupOmnibox(): void {
129 if (omniboxComponent) {
130 try {
131 omniboxComponent.$destroy?.();
132 } catch (error) {
133 console.warn("Error destroying omnibox component:", error);
134 }
135 omniboxComponent = null;
136 }
137
138 // The shared shadow host remains persistent; just log cleanup
139
140 isInitialized = false;
141 console.log("🧹 Omnibox component cleaned up");
142}