@thor-commerce/app-bridge-react 0.1.2 → 0.2.0

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.
package/README.md CHANGED
@@ -10,7 +10,7 @@ Repository link: [thor-email-app](https://github.com/thor-commerce/thor-email-ap
10
10
  npm install @thor-commerce/app-bridge-react
11
11
  ```
12
12
 
13
- ## Usage
13
+ ## Core Usage
14
14
 
15
15
  ```ts
16
16
  import { createAppBridge } from "@thor-commerce/app-bridge-react";
@@ -30,9 +30,64 @@ bridge.on("navigation:update", (message) => {
30
30
  });
31
31
  ```
32
32
 
33
+ ## React Router
34
+
35
+ ```tsx
36
+ import { Outlet } from "react-router";
37
+ import { ReactRouterAppBridgeProvider } from "@thor-commerce/app-bridge-react/react-router";
38
+
39
+ export default function App() {
40
+ return (
41
+ <ReactRouterAppBridgeProvider
42
+ source="embedded-app"
43
+ target="dashboard"
44
+ targetOrigin="https://dashboard.thorcommerce.com"
45
+ allowedOrigins={["https://dashboard.thorcommerce.com"]}
46
+ >
47
+ <Outlet />
48
+ </ReactRouterAppBridgeProvider>
49
+ );
50
+ }
51
+ ```
52
+
53
+ ## Next.js App Router
54
+
55
+ ```tsx
56
+ "use client";
57
+
58
+ import { NextAppBridgeProvider } from "@thor-commerce/app-bridge-react/next";
59
+
60
+ export function Providers({ children }: { children: React.ReactNode }) {
61
+ return (
62
+ <NextAppBridgeProvider
63
+ source="embedded-app"
64
+ target="dashboard"
65
+ targetOrigin="https://dashboard.thorcommerce.com"
66
+ allowedOrigins={["https://dashboard.thorcommerce.com"]}
67
+ >
68
+ {children}
69
+ </NextAppBridgeProvider>
70
+ );
71
+ }
72
+ ```
73
+
74
+ `ReactRouterAppBridgeProvider` and `NextAppBridgeProvider` automatically:
75
+
76
+ - create the bridge on the client
77
+ - send `app:ready`
78
+ - emit `navigation:update` when the route changes
79
+ - listen for `navigation:go` and push the app to the requested route
80
+
81
+ ## Custom React Apps
82
+
83
+ If you are not using React Router or Next.js, use `AppBridgeProvider` from the root package and pass `currentPath` and `onNavigate` yourself.
84
+
33
85
  ## API
34
86
 
35
87
  - `createAppBridge(options)` creates a bridge instance and starts listening for `postMessage` events.
88
+ - `AppBridgeProvider` manages the bridge lifecycle for React apps.
89
+ - `useAppBridge()` gives access to the underlying bridge instance for advanced cases.
90
+ - `ReactRouterAppBridgeProvider` and `NextAppBridgeProvider` are framework adapters with built-in navigation syncing.
36
91
  - `targetOrigin` should be set explicitly on both sides of the bridge. The `"*"` fallback is kept for local development compatibility, but it is unsafe for production.
37
92
  - `bridge.send(type, payload)` sends a fire-and-forget event.
38
93
  - `bridge.request(type, payload, options)` sends a request and waits for a response.
@@ -0,0 +1,413 @@
1
+ // src/core.ts
2
+ var DEFAULT_NAMESPACE = "thorcommerce:app-bridge";
3
+ var DEFAULT_TIMEOUT_MS = 1e4;
4
+ function createMessageId() {
5
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
6
+ return crypto.randomUUID();
7
+ }
8
+ return `msg_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
9
+ }
10
+ function resolveSelfWindow(explicitWindow) {
11
+ if (explicitWindow) {
12
+ return explicitWindow;
13
+ }
14
+ if (typeof window !== "undefined") {
15
+ return window;
16
+ }
17
+ return void 0;
18
+ }
19
+ function resolveTargetWindow(selfWindow, targetWindow) {
20
+ if (targetWindow) {
21
+ return targetWindow;
22
+ }
23
+ if (!selfWindow) {
24
+ return void 0;
25
+ }
26
+ if (selfWindow.parent && selfWindow.parent !== selfWindow) {
27
+ return selfWindow.parent;
28
+ }
29
+ return void 0;
30
+ }
31
+ function isDevelopmentEnvironment() {
32
+ const nodeEnv = typeof globalThis !== "undefined" && "process" in globalThis ? globalThis.process?.env?.NODE_ENV : void 0;
33
+ if (nodeEnv) {
34
+ return nodeEnv !== "production";
35
+ }
36
+ return true;
37
+ }
38
+ function hasAllowedOrigin(origin, allowedOrigins) {
39
+ if (!allowedOrigins || allowedOrigins.length === 0) {
40
+ return true;
41
+ }
42
+ return allowedOrigins.includes(origin);
43
+ }
44
+ function omitUndefinedFields(value) {
45
+ return Object.fromEntries(
46
+ Object.entries(value).filter(([, fieldValue]) => fieldValue !== void 0)
47
+ );
48
+ }
49
+ function isBridgeMessage(value, namespace = DEFAULT_NAMESPACE) {
50
+ if (!value || typeof value !== "object") {
51
+ return false;
52
+ }
53
+ const message = value;
54
+ return message.namespace === namespace && message.version === "1.0" && typeof message.kind === "string" && typeof message.id === "string" && typeof message.type === "string" && typeof message.source === "string";
55
+ }
56
+ var AppBridge = class {
57
+ constructor(options = {}) {
58
+ this.eventHandlers = /* @__PURE__ */ new Map();
59
+ this.requestHandlers = /* @__PURE__ */ new Map();
60
+ this.pendingRequests = /* @__PURE__ */ new Map();
61
+ this.namespace = options.namespace ?? DEFAULT_NAMESPACE;
62
+ this.source = options.source ?? "embedded-app";
63
+ this.target = options.target;
64
+ this.targetOrigin = options.targetOrigin ?? "*";
65
+ this.allowedOrigins = options.allowedOrigins;
66
+ this.defaultTimeoutMs = options.requestTimeoutMs ?? DEFAULT_TIMEOUT_MS;
67
+ this.selfWindow = resolveSelfWindow(options.selfWindow);
68
+ this.targetWindow = resolveTargetWindow(this.selfWindow, options.targetWindow);
69
+ this.messageListener = (event) => {
70
+ this.handleMessage(event);
71
+ };
72
+ if (!this.selfWindow) {
73
+ throw new Error(
74
+ "AppBridge requires a browser window. Pass selfWindow explicitly when constructing it outside global window scope."
75
+ );
76
+ }
77
+ if (this.targetOrigin === "*" && isDevelopmentEnvironment()) {
78
+ console.warn(
79
+ 'AppBridge is using "*" as targetOrigin. Set targetOrigin explicitly for both the dashboard and embedded app in production.'
80
+ );
81
+ }
82
+ this.selfWindow.addEventListener("message", this.messageListener);
83
+ }
84
+ setTargetWindow(targetWindow) {
85
+ this.targetWindow = targetWindow ?? void 0;
86
+ }
87
+ send(type, payload) {
88
+ this.postMessage({
89
+ kind: "event",
90
+ type,
91
+ payload
92
+ });
93
+ }
94
+ request(type, payload, options = {}) {
95
+ const messageId = createMessageId();
96
+ const timeoutMs = options.timeoutMs ?? this.defaultTimeoutMs;
97
+ return new Promise((resolve, reject) => {
98
+ const timeoutId = setTimeout(() => {
99
+ this.pendingRequests.delete(messageId);
100
+ reject(new Error(`Bridge request timed out for "${type}" after ${timeoutMs}ms.`));
101
+ }, timeoutMs);
102
+ this.pendingRequests.set(messageId, {
103
+ resolve: (value) => resolve(value),
104
+ reject,
105
+ timeoutId
106
+ });
107
+ try {
108
+ this.postMessage({
109
+ id: messageId,
110
+ kind: "request",
111
+ type,
112
+ payload
113
+ });
114
+ } catch (error) {
115
+ clearTimeout(timeoutId);
116
+ this.pendingRequests.delete(messageId);
117
+ reject(error instanceof Error ? error : new Error("Failed to send bridge request."));
118
+ }
119
+ });
120
+ }
121
+ on(type, handler) {
122
+ const handlers = this.eventHandlers.get(type) ?? /* @__PURE__ */ new Set();
123
+ handlers.add(handler);
124
+ this.eventHandlers.set(type, handlers);
125
+ return () => {
126
+ handlers.delete(handler);
127
+ if (handlers.size === 0) {
128
+ this.eventHandlers.delete(type);
129
+ }
130
+ };
131
+ }
132
+ onRequest(type, handler) {
133
+ this.requestHandlers.set(type, handler);
134
+ return () => {
135
+ const registeredHandler = this.requestHandlers.get(type);
136
+ if (registeredHandler === handler) {
137
+ this.requestHandlers.delete(type);
138
+ }
139
+ };
140
+ }
141
+ destroy() {
142
+ if (this.selfWindow) {
143
+ this.selfWindow.removeEventListener("message", this.messageListener);
144
+ }
145
+ for (const pendingRequest of this.pendingRequests.values()) {
146
+ clearTimeout(pendingRequest.timeoutId);
147
+ pendingRequest.reject(new Error("AppBridge destroyed before a response was received."));
148
+ }
149
+ this.pendingRequests.clear();
150
+ this.eventHandlers.clear();
151
+ this.requestHandlers.clear();
152
+ }
153
+ handleMessage(event) {
154
+ if (!hasAllowedOrigin(event.origin, this.allowedOrigins)) {
155
+ return;
156
+ }
157
+ if (!isBridgeMessage(event.data, this.namespace)) {
158
+ return;
159
+ }
160
+ const message = event.data;
161
+ if (this.target && message.target && message.target !== this.source) {
162
+ return;
163
+ }
164
+ const receivedMessage = {
165
+ ...message,
166
+ origin: event.origin,
167
+ rawEvent: event
168
+ };
169
+ if (message.kind === "response" && message.replyTo) {
170
+ this.resolvePendingRequest(message.replyTo, message);
171
+ return;
172
+ }
173
+ this.emitHandlers(message.type, receivedMessage);
174
+ if (message.kind === "request") {
175
+ void this.handleRequest(receivedMessage);
176
+ }
177
+ }
178
+ emitHandlers(type, message) {
179
+ const typeHandlers = this.eventHandlers.get(type);
180
+ if (typeHandlers) {
181
+ for (const handler of typeHandlers) {
182
+ handler(message);
183
+ }
184
+ }
185
+ if (type === "*") {
186
+ return;
187
+ }
188
+ const wildcardHandlers = this.eventHandlers.get("*");
189
+ if (wildcardHandlers) {
190
+ for (const handler of wildcardHandlers) {
191
+ handler(message);
192
+ }
193
+ }
194
+ }
195
+ async handleRequest(message) {
196
+ const handler = this.requestHandlers.get(message.type);
197
+ if (!handler) {
198
+ return;
199
+ }
200
+ try {
201
+ const payload = await handler(message.payload, message);
202
+ this.postMessage({
203
+ kind: "response",
204
+ type: message.type,
205
+ payload,
206
+ replyTo: message.id
207
+ });
208
+ } catch (error) {
209
+ const bridgeError = error instanceof Error ? { code: "request_handler_error", message: error.message } : { code: "request_handler_error", message: "Unknown request handler error." };
210
+ this.postMessage({
211
+ kind: "response",
212
+ type: message.type,
213
+ error: bridgeError,
214
+ replyTo: message.id
215
+ });
216
+ }
217
+ }
218
+ resolvePendingRequest(messageId, message) {
219
+ const pendingRequest = this.pendingRequests.get(messageId);
220
+ if (!pendingRequest) {
221
+ return;
222
+ }
223
+ clearTimeout(pendingRequest.timeoutId);
224
+ this.pendingRequests.delete(messageId);
225
+ if (message.error) {
226
+ pendingRequest.reject(new Error(`${message.error.code}: ${message.error.message}`));
227
+ return;
228
+ }
229
+ pendingRequest.resolve(message.payload);
230
+ }
231
+ postMessage(partialMessage) {
232
+ const targetWindow = this.targetWindow;
233
+ if (!targetWindow) {
234
+ throw new Error(
235
+ "AppBridge could not resolve a target window. Pass targetWindow explicitly or call setTargetWindow()."
236
+ );
237
+ }
238
+ const message = omitUndefinedFields({
239
+ namespace: this.namespace,
240
+ version: "1.0",
241
+ id: partialMessage.id ?? createMessageId(),
242
+ kind: partialMessage.kind,
243
+ type: partialMessage.type,
244
+ source: this.source,
245
+ target: partialMessage.target ?? this.target,
246
+ payload: partialMessage.payload,
247
+ replyTo: partialMessage.replyTo,
248
+ error: partialMessage.error
249
+ });
250
+ targetWindow.postMessage(message, this.targetOrigin);
251
+ }
252
+ };
253
+ function createAppBridge(options = {}) {
254
+ return new AppBridge(options);
255
+ }
256
+
257
+ // src/navigation.ts
258
+ function normalizeSearch(search) {
259
+ if (!search) {
260
+ return "";
261
+ }
262
+ return search.startsWith("?") ? search : `?${search}`;
263
+ }
264
+ function normalizeHash(hash) {
265
+ if (!hash) {
266
+ return "";
267
+ }
268
+ return hash.startsWith("#") ? hash : `#${hash}`;
269
+ }
270
+ function buildNavigationUpdatePayload(path) {
271
+ let pathname = path;
272
+ let search = "";
273
+ let hash = "";
274
+ const hashIndex = pathname.indexOf("#");
275
+ if (hashIndex >= 0) {
276
+ hash = pathname.slice(hashIndex);
277
+ pathname = pathname.slice(0, hashIndex);
278
+ }
279
+ const searchIndex = pathname.indexOf("?");
280
+ if (searchIndex >= 0) {
281
+ search = pathname.slice(searchIndex);
282
+ pathname = pathname.slice(0, searchIndex);
283
+ }
284
+ return {
285
+ path: `${pathname || "/"}${search}${hash}`,
286
+ pathname: pathname || "/",
287
+ search,
288
+ hash
289
+ };
290
+ }
291
+ function resolveNavigationDestination(payload) {
292
+ if (typeof payload === "string") {
293
+ return payload;
294
+ }
295
+ if (!payload || typeof payload !== "object") {
296
+ return null;
297
+ }
298
+ const value = payload;
299
+ if (typeof value.path === "string" && value.path) {
300
+ return value.path;
301
+ }
302
+ if (typeof value.href === "string" && value.href) {
303
+ return value.href;
304
+ }
305
+ if (typeof value.pathname !== "string" || !value.pathname) {
306
+ return null;
307
+ }
308
+ return `${value.pathname}${normalizeSearch(value.search ?? "")}${normalizeHash(value.hash ?? "")}`;
309
+ }
310
+
311
+ // src/react.tsx
312
+ import {
313
+ createContext,
314
+ useContext,
315
+ useEffect,
316
+ useRef,
317
+ useState
318
+ } from "react";
319
+ import { jsx } from "react/jsx-runtime";
320
+ var AppBridgeContext = createContext(null);
321
+ function AppBridgeProvider({
322
+ allowedOrigins,
323
+ children,
324
+ currentPath,
325
+ navigationEventType = "navigation:go",
326
+ navigationUpdateEventType = "navigation:update",
327
+ namespace,
328
+ onNavigate,
329
+ readyEventType = "app:ready",
330
+ readyPayload,
331
+ requestTimeoutMs,
332
+ selfWindow,
333
+ source,
334
+ target,
335
+ targetOrigin,
336
+ targetWindow
337
+ }) {
338
+ const [bridge, setBridge] = useState(null);
339
+ const onNavigateRef = useRef(onNavigate);
340
+ const allowedOriginsKey = allowedOrigins?.join("\n") ?? "";
341
+ useEffect(() => {
342
+ onNavigateRef.current = onNavigate;
343
+ }, [onNavigate]);
344
+ useEffect(() => {
345
+ if (typeof window === "undefined" && !selfWindow) {
346
+ return;
347
+ }
348
+ const nextBridge = createAppBridge({
349
+ allowedOrigins: allowedOriginsKey ? allowedOriginsKey.split("\n") : void 0,
350
+ namespace,
351
+ requestTimeoutMs,
352
+ selfWindow,
353
+ source,
354
+ target,
355
+ targetOrigin,
356
+ targetWindow
357
+ });
358
+ setBridge(nextBridge);
359
+ nextBridge.send(readyEventType, readyPayload);
360
+ return () => {
361
+ setBridge((currentBridge) => currentBridge === nextBridge ? null : currentBridge);
362
+ nextBridge.destroy();
363
+ };
364
+ }, [
365
+ allowedOriginsKey,
366
+ namespace,
367
+ requestTimeoutMs,
368
+ selfWindow,
369
+ source,
370
+ target,
371
+ targetOrigin,
372
+ targetWindow
373
+ ]);
374
+ useEffect(() => {
375
+ if (!bridge) {
376
+ return;
377
+ }
378
+ bridge.send(readyEventType, readyPayload);
379
+ }, [bridge, readyEventType, readyPayload]);
380
+ useEffect(() => {
381
+ if (!bridge || !currentPath) {
382
+ return;
383
+ }
384
+ bridge.send(navigationUpdateEventType, buildNavigationUpdatePayload(currentPath));
385
+ }, [bridge, currentPath, navigationUpdateEventType]);
386
+ useEffect(() => {
387
+ if (!bridge || !onNavigate) {
388
+ return;
389
+ }
390
+ return bridge.on(navigationEventType, (message) => {
391
+ const destination = resolveNavigationDestination(message.payload);
392
+ if (!destination) {
393
+ return;
394
+ }
395
+ onNavigateRef.current?.(destination, message);
396
+ });
397
+ }, [bridge, navigationEventType, onNavigate]);
398
+ return /* @__PURE__ */ jsx(AppBridgeContext.Provider, { value: bridge, children });
399
+ }
400
+ function useAppBridge() {
401
+ return useContext(AppBridgeContext);
402
+ }
403
+
404
+ export {
405
+ isBridgeMessage,
406
+ AppBridge,
407
+ createAppBridge,
408
+ buildNavigationUpdatePayload,
409
+ resolveNavigationDestination,
410
+ AppBridgeProvider,
411
+ useAppBridge
412
+ };
413
+ //# sourceMappingURL=chunk-J4BEZO5J.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core.ts","../src/navigation.ts","../src/react.tsx"],"sourcesContent":["export type BridgeParticipant = \"embedded-app\" | \"dashboard\" | \"unknown\";\n\nexport type BridgeMessageKind = \"event\" | \"request\" | \"response\";\n\nexport interface BridgeErrorPayload {\n code: string;\n message: string;\n}\n\nexport interface BridgeMessage<TPayload = unknown> {\n namespace: string;\n version: \"1.0\";\n kind: BridgeMessageKind;\n id: string;\n type: string;\n source: BridgeParticipant;\n target?: BridgeParticipant;\n payload?: TPayload;\n replyTo?: string;\n error?: BridgeErrorPayload;\n}\n\nexport interface AppBridgeOptions {\n source?: BridgeParticipant;\n target?: BridgeParticipant;\n namespace?: string;\n targetOrigin?: string;\n allowedOrigins?: string[];\n requestTimeoutMs?: number;\n selfWindow?: Window;\n targetWindow?: Window | null;\n}\n\nexport interface RequestOptions {\n timeoutMs?: number;\n}\n\nexport interface ReceivedBridgeMessage<TPayload = unknown> extends BridgeMessage<TPayload> {\n origin: string;\n rawEvent: MessageEvent<unknown>;\n}\n\nexport type BridgeEventHandler<TPayload = unknown> = (\n message: ReceivedBridgeMessage<TPayload>\n) => void;\n\nexport type BridgeRequestHandler<TRequest = unknown, TResponse = unknown> = (\n payload: TRequest,\n message: ReceivedBridgeMessage<TRequest>\n) => TResponse | Promise<TResponse>;\n\nexport type Unsubscribe = () => void;\n\nconst DEFAULT_NAMESPACE = \"thorcommerce:app-bridge\";\nconst DEFAULT_TIMEOUT_MS = 10_000;\n\nfunction createMessageId() {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n\n return `msg_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction resolveSelfWindow(explicitWindow?: Window) {\n if (explicitWindow) {\n return explicitWindow;\n }\n\n if (typeof window !== \"undefined\") {\n return window;\n }\n\n return undefined;\n}\n\nfunction resolveTargetWindow(selfWindow: Window | undefined, targetWindow?: Window | null) {\n if (targetWindow) {\n return targetWindow;\n }\n\n if (!selfWindow) {\n return undefined;\n }\n\n if (selfWindow.parent && selfWindow.parent !== selfWindow) {\n return selfWindow.parent;\n }\n\n return undefined;\n}\n\nfunction isDevelopmentEnvironment() {\n const nodeEnv =\n typeof globalThis !== \"undefined\" && \"process\" in globalThis\n ? (\n globalThis as typeof globalThis & {\n process?: { env?: { NODE_ENV?: string } };\n }\n ).process?.env?.NODE_ENV\n : undefined;\n\n if (nodeEnv) {\n return nodeEnv !== \"production\";\n }\n\n return true;\n}\n\nfunction hasAllowedOrigin(origin: string, allowedOrigins?: string[]) {\n if (!allowedOrigins || allowedOrigins.length === 0) {\n return true;\n }\n\n return allowedOrigins.includes(origin);\n}\n\nfunction omitUndefinedFields<T extends object>(value: T): T {\n return Object.fromEntries(\n Object.entries(value).filter(([, fieldValue]) => fieldValue !== undefined)\n ) as T;\n}\n\nexport function isBridgeMessage<TPayload = unknown>(\n value: unknown,\n namespace = DEFAULT_NAMESPACE\n): value is BridgeMessage<TPayload> {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n\n const message = value as Partial<BridgeMessage<TPayload>>;\n\n return (\n message.namespace === namespace &&\n message.version === \"1.0\" &&\n typeof message.kind === \"string\" &&\n typeof message.id === \"string\" &&\n typeof message.type === \"string\" &&\n typeof message.source === \"string\"\n );\n}\n\nexport class AppBridge {\n private readonly namespace: string;\n private readonly source: BridgeParticipant;\n private readonly target: BridgeParticipant | undefined;\n private readonly targetOrigin: string;\n private readonly allowedOrigins?: string[];\n private readonly selfWindow?: Window;\n private readonly defaultTimeoutMs: number;\n private targetWindow?: Window;\n private readonly eventHandlers = new Map<string, Set<BridgeEventHandler>>();\n private readonly requestHandlers = new Map<string, BridgeRequestHandler>();\n private readonly pendingRequests = new Map<\n string,\n {\n resolve: (value: unknown) => void;\n reject: (error: Error) => void;\n timeoutId: ReturnType<typeof setTimeout>;\n }\n >();\n private readonly messageListener: (event: MessageEvent<unknown>) => void;\n\n constructor(options: AppBridgeOptions = {}) {\n this.namespace = options.namespace ?? DEFAULT_NAMESPACE;\n this.source = options.source ?? \"embedded-app\";\n this.target = options.target;\n this.targetOrigin = options.targetOrigin ?? \"*\";\n this.allowedOrigins = options.allowedOrigins;\n this.defaultTimeoutMs = options.requestTimeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.selfWindow = resolveSelfWindow(options.selfWindow);\n this.targetWindow = resolveTargetWindow(this.selfWindow, options.targetWindow);\n this.messageListener = (event) => {\n this.handleMessage(event);\n };\n\n if (!this.selfWindow) {\n throw new Error(\n \"AppBridge requires a browser window. Pass selfWindow explicitly when constructing it outside global window scope.\"\n );\n }\n\n if (this.targetOrigin === \"*\" && isDevelopmentEnvironment()) {\n console.warn(\n 'AppBridge is using \"*\" as targetOrigin. Set targetOrigin explicitly for both the dashboard and embedded app in production.'\n );\n }\n\n this.selfWindow.addEventListener(\"message\", this.messageListener);\n }\n\n setTargetWindow(targetWindow: Window | null) {\n this.targetWindow = targetWindow ?? undefined;\n }\n\n send<TPayload = unknown>(type: string, payload?: TPayload) {\n this.postMessage({\n kind: \"event\",\n type,\n payload\n });\n }\n\n request<TRequest = unknown, TResponse = unknown>(\n type: string,\n payload?: TRequest,\n options: RequestOptions = {}\n ) {\n const messageId = createMessageId();\n const timeoutMs = options.timeoutMs ?? this.defaultTimeoutMs;\n\n return new Promise<TResponse>((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n this.pendingRequests.delete(messageId);\n reject(new Error(`Bridge request timed out for \"${type}\" after ${timeoutMs}ms.`));\n }, timeoutMs);\n\n this.pendingRequests.set(messageId, {\n resolve: (value) => resolve(value as TResponse),\n reject,\n timeoutId\n });\n\n try {\n this.postMessage({\n id: messageId,\n kind: \"request\",\n type,\n payload\n });\n } catch (error) {\n clearTimeout(timeoutId);\n this.pendingRequests.delete(messageId);\n reject(error instanceof Error ? error : new Error(\"Failed to send bridge request.\"));\n }\n });\n }\n\n on<TPayload = unknown>(type: string, handler: BridgeEventHandler<TPayload>): Unsubscribe {\n const handlers = this.eventHandlers.get(type) ?? new Set<BridgeEventHandler>();\n handlers.add(handler as BridgeEventHandler);\n this.eventHandlers.set(type, handlers);\n\n return () => {\n handlers.delete(handler as BridgeEventHandler);\n if (handlers.size === 0) {\n this.eventHandlers.delete(type);\n }\n };\n }\n\n onRequest<TRequest = unknown, TResponse = unknown>(\n type: string,\n handler: BridgeRequestHandler<TRequest, TResponse>\n ): Unsubscribe {\n this.requestHandlers.set(type, handler as BridgeRequestHandler);\n\n return () => {\n const registeredHandler = this.requestHandlers.get(type);\n if (registeredHandler === handler) {\n this.requestHandlers.delete(type);\n }\n };\n }\n\n destroy() {\n if (this.selfWindow) {\n this.selfWindow.removeEventListener(\"message\", this.messageListener);\n }\n\n for (const pendingRequest of this.pendingRequests.values()) {\n clearTimeout(pendingRequest.timeoutId);\n pendingRequest.reject(new Error(\"AppBridge destroyed before a response was received.\"));\n }\n\n this.pendingRequests.clear();\n this.eventHandlers.clear();\n this.requestHandlers.clear();\n }\n\n private handleMessage(event: MessageEvent<unknown>) {\n if (!hasAllowedOrigin(event.origin, this.allowedOrigins)) {\n return;\n }\n\n if (!isBridgeMessage(event.data, this.namespace)) {\n return;\n }\n\n const message = event.data;\n\n if (this.target && message.target && message.target !== this.source) {\n return;\n }\n\n const receivedMessage: ReceivedBridgeMessage = {\n ...message,\n origin: event.origin,\n rawEvent: event\n };\n\n if (message.kind === \"response\" && message.replyTo) {\n this.resolvePendingRequest(message.replyTo, message);\n return;\n }\n\n this.emitHandlers(message.type, receivedMessage);\n\n if (message.kind === \"request\") {\n void this.handleRequest(receivedMessage);\n }\n }\n\n private emitHandlers(type: string, message: ReceivedBridgeMessage) {\n const typeHandlers = this.eventHandlers.get(type);\n if (typeHandlers) {\n for (const handler of typeHandlers) {\n handler(message);\n }\n }\n\n if (type === \"*\") {\n return;\n }\n\n const wildcardHandlers = this.eventHandlers.get(\"*\");\n if (wildcardHandlers) {\n for (const handler of wildcardHandlers) {\n handler(message);\n }\n }\n }\n\n private async handleRequest(message: ReceivedBridgeMessage) {\n const handler = this.requestHandlers.get(message.type);\n if (!handler) {\n return;\n }\n\n try {\n const payload = await handler(message.payload, message);\n this.postMessage({\n kind: \"response\",\n type: message.type,\n payload,\n replyTo: message.id\n });\n } catch (error) {\n const bridgeError =\n error instanceof Error\n ? { code: \"request_handler_error\", message: error.message }\n : { code: \"request_handler_error\", message: \"Unknown request handler error.\" };\n\n this.postMessage({\n kind: \"response\",\n type: message.type,\n error: bridgeError,\n replyTo: message.id\n });\n }\n }\n\n private resolvePendingRequest(messageId: string, message: BridgeMessage) {\n const pendingRequest = this.pendingRequests.get(messageId);\n if (!pendingRequest) {\n return;\n }\n\n clearTimeout(pendingRequest.timeoutId);\n this.pendingRequests.delete(messageId);\n\n if (message.error) {\n pendingRequest.reject(new Error(`${message.error.code}: ${message.error.message}`));\n return;\n }\n\n pendingRequest.resolve(message.payload);\n }\n\n private postMessage<TPayload = unknown>(\n partialMessage: Pick<BridgeMessage<TPayload>, \"kind\" | \"type\"> &\n Partial<Omit<BridgeMessage<TPayload>, \"namespace\" | \"version\" | \"source\">>\n ) {\n const targetWindow = this.targetWindow;\n if (!targetWindow) {\n throw new Error(\n \"AppBridge could not resolve a target window. Pass targetWindow explicitly or call setTargetWindow().\"\n );\n }\n\n const message = omitUndefinedFields({\n namespace: this.namespace,\n version: \"1.0\",\n id: partialMessage.id ?? createMessageId(),\n kind: partialMessage.kind,\n type: partialMessage.type,\n source: this.source,\n target: partialMessage.target ?? this.target,\n payload: partialMessage.payload,\n replyTo: partialMessage.replyTo,\n error: partialMessage.error\n }) as BridgeMessage<TPayload>;\n\n targetWindow.postMessage(message, this.targetOrigin);\n }\n}\n\nexport function createAppBridge(options: AppBridgeOptions = {}) {\n return new AppBridge(options);\n}\n","export interface BridgeNavigationGoPayload {\n path?: string;\n href?: string;\n pathname?: string;\n search?: string;\n hash?: string;\n}\n\nexport interface BridgeNavigationUpdatePayload {\n path: string;\n pathname: string;\n search: string;\n hash: string;\n}\n\nfunction normalizeSearch(search: string) {\n if (!search) {\n return \"\";\n }\n\n return search.startsWith(\"?\") ? search : `?${search}`;\n}\n\nfunction normalizeHash(hash: string) {\n if (!hash) {\n return \"\";\n }\n\n return hash.startsWith(\"#\") ? hash : `#${hash}`;\n}\n\nexport function buildNavigationUpdatePayload(path: string): BridgeNavigationUpdatePayload {\n let pathname = path;\n let search = \"\";\n let hash = \"\";\n\n const hashIndex = pathname.indexOf(\"#\");\n if (hashIndex >= 0) {\n hash = pathname.slice(hashIndex);\n pathname = pathname.slice(0, hashIndex);\n }\n\n const searchIndex = pathname.indexOf(\"?\");\n if (searchIndex >= 0) {\n search = pathname.slice(searchIndex);\n pathname = pathname.slice(0, searchIndex);\n }\n\n return {\n path: `${pathname || \"/\"}${search}${hash}`,\n pathname: pathname || \"/\",\n search,\n hash\n };\n}\n\nexport function resolveNavigationDestination(payload: unknown): string | null {\n if (typeof payload === \"string\") {\n return payload;\n }\n\n if (!payload || typeof payload !== \"object\") {\n return null;\n }\n\n const value = payload as BridgeNavigationGoPayload;\n\n if (typeof value.path === \"string\" && value.path) {\n return value.path;\n }\n\n if (typeof value.href === \"string\" && value.href) {\n return value.href;\n }\n\n if (typeof value.pathname !== \"string\" || !value.pathname) {\n return null;\n }\n\n return `${value.pathname}${normalizeSearch(value.search ?? \"\")}${normalizeHash(value.hash ?? \"\")}`;\n}\n","import {\n createContext,\n useContext,\n useEffect,\n useRef,\n useState,\n type ReactNode\n} from \"react\";\n\nimport {\n createAppBridge,\n type AppBridge,\n type AppBridgeOptions,\n type ReceivedBridgeMessage\n} from \"./core\";\nimport {\n buildNavigationUpdatePayload,\n resolveNavigationDestination,\n type BridgeNavigationGoPayload\n} from \"./navigation\";\n\nconst AppBridgeContext = createContext<AppBridge | null>(null);\n\nexport interface AppBridgeProviderProps extends AppBridgeOptions {\n children: ReactNode;\n readyEventType?: string;\n readyPayload?: unknown;\n currentPath?: string | null;\n navigationEventType?: string;\n navigationUpdateEventType?: string;\n onNavigate?: (\n path: string,\n message: ReceivedBridgeMessage<BridgeNavigationGoPayload>\n ) => void;\n}\n\nexport function AppBridgeProvider({\n allowedOrigins,\n children,\n currentPath,\n navigationEventType = \"navigation:go\",\n navigationUpdateEventType = \"navigation:update\",\n namespace,\n onNavigate,\n readyEventType = \"app:ready\",\n readyPayload,\n requestTimeoutMs,\n selfWindow,\n source,\n target,\n targetOrigin,\n targetWindow\n}: AppBridgeProviderProps) {\n const [bridge, setBridge] = useState<AppBridge | null>(null);\n const onNavigateRef = useRef(onNavigate);\n const allowedOriginsKey = allowedOrigins?.join(\"\\n\") ?? \"\";\n\n useEffect(() => {\n onNavigateRef.current = onNavigate;\n }, [onNavigate]);\n\n useEffect(() => {\n if (typeof window === \"undefined\" && !selfWindow) {\n return;\n }\n\n const nextBridge = createAppBridge({\n allowedOrigins: allowedOriginsKey ? allowedOriginsKey.split(\"\\n\") : undefined,\n namespace,\n requestTimeoutMs,\n selfWindow,\n source,\n target,\n targetOrigin,\n targetWindow\n });\n\n setBridge(nextBridge);\n nextBridge.send(readyEventType, readyPayload);\n\n return () => {\n setBridge((currentBridge) => (currentBridge === nextBridge ? null : currentBridge));\n nextBridge.destroy();\n };\n }, [\n allowedOriginsKey,\n namespace,\n requestTimeoutMs,\n selfWindow,\n source,\n target,\n targetOrigin,\n targetWindow\n ]);\n\n useEffect(() => {\n if (!bridge) {\n return;\n }\n\n bridge.send(readyEventType, readyPayload);\n }, [bridge, readyEventType, readyPayload]);\n\n useEffect(() => {\n if (!bridge || !currentPath) {\n return;\n }\n\n bridge.send(navigationUpdateEventType, buildNavigationUpdatePayload(currentPath));\n }, [bridge, currentPath, navigationUpdateEventType]);\n\n useEffect(() => {\n if (!bridge || !onNavigate) {\n return;\n }\n\n return bridge.on<BridgeNavigationGoPayload>(navigationEventType, (message) => {\n const destination = resolveNavigationDestination(message.payload);\n if (!destination) {\n return;\n }\n\n onNavigateRef.current?.(destination, message);\n });\n }, [bridge, navigationEventType, onNavigate]);\n\n return <AppBridgeContext.Provider value={bridge}>{children}</AppBridgeContext.Provider>;\n}\n\nexport function useAppBridge() {\n return useContext(AppBridgeContext);\n}\n"],"mappings":"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","names":[]}