@thor-commerce/app-bridge-react 0.1.0 → 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.
@@ -0,0 +1,449 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/react-router.tsx
21
+ var react_router_exports = {};
22
+ __export(react_router_exports, {
23
+ ReactRouterAppBridgeProvider: () => ReactRouterAppBridgeProvider
24
+ });
25
+ module.exports = __toCommonJS(react_router_exports);
26
+ var import_react_router = require("react-router");
27
+
28
+ // src/react.tsx
29
+ var import_react = require("react");
30
+
31
+ // src/core.ts
32
+ var DEFAULT_NAMESPACE = "thorcommerce:app-bridge";
33
+ var DEFAULT_TIMEOUT_MS = 1e4;
34
+ function createMessageId() {
35
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
36
+ return crypto.randomUUID();
37
+ }
38
+ return `msg_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
39
+ }
40
+ function resolveSelfWindow(explicitWindow) {
41
+ if (explicitWindow) {
42
+ return explicitWindow;
43
+ }
44
+ if (typeof window !== "undefined") {
45
+ return window;
46
+ }
47
+ return void 0;
48
+ }
49
+ function resolveTargetWindow(selfWindow, targetWindow) {
50
+ if (targetWindow) {
51
+ return targetWindow;
52
+ }
53
+ if (!selfWindow) {
54
+ return void 0;
55
+ }
56
+ if (selfWindow.parent && selfWindow.parent !== selfWindow) {
57
+ return selfWindow.parent;
58
+ }
59
+ return void 0;
60
+ }
61
+ function isDevelopmentEnvironment() {
62
+ const nodeEnv = typeof globalThis !== "undefined" && "process" in globalThis ? globalThis.process?.env?.NODE_ENV : void 0;
63
+ if (nodeEnv) {
64
+ return nodeEnv !== "production";
65
+ }
66
+ return true;
67
+ }
68
+ function hasAllowedOrigin(origin, allowedOrigins) {
69
+ if (!allowedOrigins || allowedOrigins.length === 0) {
70
+ return true;
71
+ }
72
+ return allowedOrigins.includes(origin);
73
+ }
74
+ function omitUndefinedFields(value) {
75
+ return Object.fromEntries(
76
+ Object.entries(value).filter(([, fieldValue]) => fieldValue !== void 0)
77
+ );
78
+ }
79
+ function isBridgeMessage(value, namespace = DEFAULT_NAMESPACE) {
80
+ if (!value || typeof value !== "object") {
81
+ return false;
82
+ }
83
+ const message = value;
84
+ return message.namespace === namespace && message.version === "1.0" && typeof message.kind === "string" && typeof message.id === "string" && typeof message.type === "string" && typeof message.source === "string";
85
+ }
86
+ var AppBridge = class {
87
+ constructor(options = {}) {
88
+ this.eventHandlers = /* @__PURE__ */ new Map();
89
+ this.requestHandlers = /* @__PURE__ */ new Map();
90
+ this.pendingRequests = /* @__PURE__ */ new Map();
91
+ this.namespace = options.namespace ?? DEFAULT_NAMESPACE;
92
+ this.source = options.source ?? "embedded-app";
93
+ this.target = options.target;
94
+ this.targetOrigin = options.targetOrigin ?? "*";
95
+ this.allowedOrigins = options.allowedOrigins;
96
+ this.defaultTimeoutMs = options.requestTimeoutMs ?? DEFAULT_TIMEOUT_MS;
97
+ this.selfWindow = resolveSelfWindow(options.selfWindow);
98
+ this.targetWindow = resolveTargetWindow(this.selfWindow, options.targetWindow);
99
+ this.messageListener = (event) => {
100
+ this.handleMessage(event);
101
+ };
102
+ if (!this.selfWindow) {
103
+ throw new Error(
104
+ "AppBridge requires a browser window. Pass selfWindow explicitly when constructing it outside global window scope."
105
+ );
106
+ }
107
+ if (this.targetOrigin === "*" && isDevelopmentEnvironment()) {
108
+ console.warn(
109
+ 'AppBridge is using "*" as targetOrigin. Set targetOrigin explicitly for both the dashboard and embedded app in production.'
110
+ );
111
+ }
112
+ this.selfWindow.addEventListener("message", this.messageListener);
113
+ }
114
+ setTargetWindow(targetWindow) {
115
+ this.targetWindow = targetWindow ?? void 0;
116
+ }
117
+ send(type, payload) {
118
+ this.postMessage({
119
+ kind: "event",
120
+ type,
121
+ payload
122
+ });
123
+ }
124
+ request(type, payload, options = {}) {
125
+ const messageId = createMessageId();
126
+ const timeoutMs = options.timeoutMs ?? this.defaultTimeoutMs;
127
+ return new Promise((resolve, reject) => {
128
+ const timeoutId = setTimeout(() => {
129
+ this.pendingRequests.delete(messageId);
130
+ reject(new Error(`Bridge request timed out for "${type}" after ${timeoutMs}ms.`));
131
+ }, timeoutMs);
132
+ this.pendingRequests.set(messageId, {
133
+ resolve: (value) => resolve(value),
134
+ reject,
135
+ timeoutId
136
+ });
137
+ try {
138
+ this.postMessage({
139
+ id: messageId,
140
+ kind: "request",
141
+ type,
142
+ payload
143
+ });
144
+ } catch (error) {
145
+ clearTimeout(timeoutId);
146
+ this.pendingRequests.delete(messageId);
147
+ reject(error instanceof Error ? error : new Error("Failed to send bridge request."));
148
+ }
149
+ });
150
+ }
151
+ on(type, handler) {
152
+ const handlers = this.eventHandlers.get(type) ?? /* @__PURE__ */ new Set();
153
+ handlers.add(handler);
154
+ this.eventHandlers.set(type, handlers);
155
+ return () => {
156
+ handlers.delete(handler);
157
+ if (handlers.size === 0) {
158
+ this.eventHandlers.delete(type);
159
+ }
160
+ };
161
+ }
162
+ onRequest(type, handler) {
163
+ this.requestHandlers.set(type, handler);
164
+ return () => {
165
+ const registeredHandler = this.requestHandlers.get(type);
166
+ if (registeredHandler === handler) {
167
+ this.requestHandlers.delete(type);
168
+ }
169
+ };
170
+ }
171
+ destroy() {
172
+ if (this.selfWindow) {
173
+ this.selfWindow.removeEventListener("message", this.messageListener);
174
+ }
175
+ for (const pendingRequest of this.pendingRequests.values()) {
176
+ clearTimeout(pendingRequest.timeoutId);
177
+ pendingRequest.reject(new Error("AppBridge destroyed before a response was received."));
178
+ }
179
+ this.pendingRequests.clear();
180
+ this.eventHandlers.clear();
181
+ this.requestHandlers.clear();
182
+ }
183
+ handleMessage(event) {
184
+ if (!hasAllowedOrigin(event.origin, this.allowedOrigins)) {
185
+ return;
186
+ }
187
+ if (!isBridgeMessage(event.data, this.namespace)) {
188
+ return;
189
+ }
190
+ const message = event.data;
191
+ if (this.target && message.target && message.target !== this.source) {
192
+ return;
193
+ }
194
+ const receivedMessage = {
195
+ ...message,
196
+ origin: event.origin,
197
+ rawEvent: event
198
+ };
199
+ if (message.kind === "response" && message.replyTo) {
200
+ this.resolvePendingRequest(message.replyTo, message);
201
+ return;
202
+ }
203
+ this.emitHandlers(message.type, receivedMessage);
204
+ if (message.kind === "request") {
205
+ void this.handleRequest(receivedMessage);
206
+ }
207
+ }
208
+ emitHandlers(type, message) {
209
+ const typeHandlers = this.eventHandlers.get(type);
210
+ if (typeHandlers) {
211
+ for (const handler of typeHandlers) {
212
+ handler(message);
213
+ }
214
+ }
215
+ if (type === "*") {
216
+ return;
217
+ }
218
+ const wildcardHandlers = this.eventHandlers.get("*");
219
+ if (wildcardHandlers) {
220
+ for (const handler of wildcardHandlers) {
221
+ handler(message);
222
+ }
223
+ }
224
+ }
225
+ async handleRequest(message) {
226
+ const handler = this.requestHandlers.get(message.type);
227
+ if (!handler) {
228
+ return;
229
+ }
230
+ try {
231
+ const payload = await handler(message.payload, message);
232
+ this.postMessage({
233
+ kind: "response",
234
+ type: message.type,
235
+ payload,
236
+ replyTo: message.id
237
+ });
238
+ } catch (error) {
239
+ const bridgeError = error instanceof Error ? { code: "request_handler_error", message: error.message } : { code: "request_handler_error", message: "Unknown request handler error." };
240
+ this.postMessage({
241
+ kind: "response",
242
+ type: message.type,
243
+ error: bridgeError,
244
+ replyTo: message.id
245
+ });
246
+ }
247
+ }
248
+ resolvePendingRequest(messageId, message) {
249
+ const pendingRequest = this.pendingRequests.get(messageId);
250
+ if (!pendingRequest) {
251
+ return;
252
+ }
253
+ clearTimeout(pendingRequest.timeoutId);
254
+ this.pendingRequests.delete(messageId);
255
+ if (message.error) {
256
+ pendingRequest.reject(new Error(`${message.error.code}: ${message.error.message}`));
257
+ return;
258
+ }
259
+ pendingRequest.resolve(message.payload);
260
+ }
261
+ postMessage(partialMessage) {
262
+ const targetWindow = this.targetWindow;
263
+ if (!targetWindow) {
264
+ throw new Error(
265
+ "AppBridge could not resolve a target window. Pass targetWindow explicitly or call setTargetWindow()."
266
+ );
267
+ }
268
+ const message = omitUndefinedFields({
269
+ namespace: this.namespace,
270
+ version: "1.0",
271
+ id: partialMessage.id ?? createMessageId(),
272
+ kind: partialMessage.kind,
273
+ type: partialMessage.type,
274
+ source: this.source,
275
+ target: partialMessage.target ?? this.target,
276
+ payload: partialMessage.payload,
277
+ replyTo: partialMessage.replyTo,
278
+ error: partialMessage.error
279
+ });
280
+ targetWindow.postMessage(message, this.targetOrigin);
281
+ }
282
+ };
283
+ function createAppBridge(options = {}) {
284
+ return new AppBridge(options);
285
+ }
286
+
287
+ // src/navigation.ts
288
+ function normalizeSearch(search) {
289
+ if (!search) {
290
+ return "";
291
+ }
292
+ return search.startsWith("?") ? search : `?${search}`;
293
+ }
294
+ function normalizeHash(hash) {
295
+ if (!hash) {
296
+ return "";
297
+ }
298
+ return hash.startsWith("#") ? hash : `#${hash}`;
299
+ }
300
+ function buildNavigationUpdatePayload(path) {
301
+ let pathname = path;
302
+ let search = "";
303
+ let hash = "";
304
+ const hashIndex = pathname.indexOf("#");
305
+ if (hashIndex >= 0) {
306
+ hash = pathname.slice(hashIndex);
307
+ pathname = pathname.slice(0, hashIndex);
308
+ }
309
+ const searchIndex = pathname.indexOf("?");
310
+ if (searchIndex >= 0) {
311
+ search = pathname.slice(searchIndex);
312
+ pathname = pathname.slice(0, searchIndex);
313
+ }
314
+ return {
315
+ path: `${pathname || "/"}${search}${hash}`,
316
+ pathname: pathname || "/",
317
+ search,
318
+ hash
319
+ };
320
+ }
321
+ function resolveNavigationDestination(payload) {
322
+ if (typeof payload === "string") {
323
+ return payload;
324
+ }
325
+ if (!payload || typeof payload !== "object") {
326
+ return null;
327
+ }
328
+ const value = payload;
329
+ if (typeof value.path === "string" && value.path) {
330
+ return value.path;
331
+ }
332
+ if (typeof value.href === "string" && value.href) {
333
+ return value.href;
334
+ }
335
+ if (typeof value.pathname !== "string" || !value.pathname) {
336
+ return null;
337
+ }
338
+ return `${value.pathname}${normalizeSearch(value.search ?? "")}${normalizeHash(value.hash ?? "")}`;
339
+ }
340
+
341
+ // src/react.tsx
342
+ var import_jsx_runtime = require("react/jsx-runtime");
343
+ var AppBridgeContext = (0, import_react.createContext)(null);
344
+ function AppBridgeProvider({
345
+ allowedOrigins,
346
+ children,
347
+ currentPath,
348
+ navigationEventType = "navigation:go",
349
+ navigationUpdateEventType = "navigation:update",
350
+ namespace,
351
+ onNavigate,
352
+ readyEventType = "app:ready",
353
+ readyPayload,
354
+ requestTimeoutMs,
355
+ selfWindow,
356
+ source,
357
+ target,
358
+ targetOrigin,
359
+ targetWindow
360
+ }) {
361
+ const [bridge, setBridge] = (0, import_react.useState)(null);
362
+ const onNavigateRef = (0, import_react.useRef)(onNavigate);
363
+ const allowedOriginsKey = allowedOrigins?.join("\n") ?? "";
364
+ (0, import_react.useEffect)(() => {
365
+ onNavigateRef.current = onNavigate;
366
+ }, [onNavigate]);
367
+ (0, import_react.useEffect)(() => {
368
+ if (typeof window === "undefined" && !selfWindow) {
369
+ return;
370
+ }
371
+ const nextBridge = createAppBridge({
372
+ allowedOrigins: allowedOriginsKey ? allowedOriginsKey.split("\n") : void 0,
373
+ namespace,
374
+ requestTimeoutMs,
375
+ selfWindow,
376
+ source,
377
+ target,
378
+ targetOrigin,
379
+ targetWindow
380
+ });
381
+ setBridge(nextBridge);
382
+ nextBridge.send(readyEventType, readyPayload);
383
+ return () => {
384
+ setBridge((currentBridge) => currentBridge === nextBridge ? null : currentBridge);
385
+ nextBridge.destroy();
386
+ };
387
+ }, [
388
+ allowedOriginsKey,
389
+ namespace,
390
+ requestTimeoutMs,
391
+ selfWindow,
392
+ source,
393
+ target,
394
+ targetOrigin,
395
+ targetWindow
396
+ ]);
397
+ (0, import_react.useEffect)(() => {
398
+ if (!bridge) {
399
+ return;
400
+ }
401
+ bridge.send(readyEventType, readyPayload);
402
+ }, [bridge, readyEventType, readyPayload]);
403
+ (0, import_react.useEffect)(() => {
404
+ if (!bridge || !currentPath) {
405
+ return;
406
+ }
407
+ bridge.send(navigationUpdateEventType, buildNavigationUpdatePayload(currentPath));
408
+ }, [bridge, currentPath, navigationUpdateEventType]);
409
+ (0, import_react.useEffect)(() => {
410
+ if (!bridge || !onNavigate) {
411
+ return;
412
+ }
413
+ return bridge.on(navigationEventType, (message) => {
414
+ const destination = resolveNavigationDestination(message.payload);
415
+ if (!destination) {
416
+ return;
417
+ }
418
+ onNavigateRef.current?.(destination, message);
419
+ });
420
+ }, [bridge, navigationEventType, onNavigate]);
421
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AppBridgeContext.Provider, { value: bridge, children });
422
+ }
423
+
424
+ // src/react-router.tsx
425
+ var import_jsx_runtime2 = require("react/jsx-runtime");
426
+ function ReactRouterAppBridgeProvider({
427
+ children,
428
+ ...props
429
+ }) {
430
+ const location = (0, import_react_router.useLocation)();
431
+ const navigate = (0, import_react_router.useNavigate)();
432
+ const currentPath = `${location.pathname}${location.search}${location.hash}`;
433
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
434
+ AppBridgeProvider,
435
+ {
436
+ ...props,
437
+ currentPath,
438
+ onNavigate: (path) => {
439
+ void navigate(path);
440
+ },
441
+ children
442
+ }
443
+ );
444
+ }
445
+ // Annotate the CommonJS export names for ESM import in node:
446
+ 0 && (module.exports = {
447
+ ReactRouterAppBridgeProvider
448
+ });
449
+ //# sourceMappingURL=react-router.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react-router.tsx","../src/react.tsx","../src/core.ts","../src/navigation.ts"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { useLocation, useNavigate } from \"react-router\";\n\nimport {\n AppBridgeProvider,\n type AppBridgeProviderProps\n} from \"./react\";\n\nexport interface ReactRouterAppBridgeProviderProps\n extends Omit<AppBridgeProviderProps, \"currentPath\" | \"onNavigate\"> {\n children: ReactNode;\n}\n\nexport function ReactRouterAppBridgeProvider({\n children,\n ...props\n}: ReactRouterAppBridgeProviderProps) {\n const location = useLocation();\n const navigate = useNavigate();\n const currentPath = `${location.pathname}${location.search}${location.hash}`;\n\n return (\n <AppBridgeProvider\n {...props}\n currentPath={currentPath}\n onNavigate={(path) => {\n void navigate(path);\n }}\n >\n {children}\n </AppBridgeProvider>\n );\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","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"],"mappings":"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","names":["import_jsx_runtime"]}
@@ -0,0 +1,10 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+ import { AppBridgeProviderProps } from './index.cjs';
4
+
5
+ interface ReactRouterAppBridgeProviderProps extends Omit<AppBridgeProviderProps, "currentPath" | "onNavigate"> {
6
+ children: ReactNode;
7
+ }
8
+ declare function ReactRouterAppBridgeProvider({ children, ...props }: ReactRouterAppBridgeProviderProps): react_jsx_runtime.JSX.Element;
9
+
10
+ export { ReactRouterAppBridgeProvider, type ReactRouterAppBridgeProviderProps };
@@ -0,0 +1,10 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+ import { AppBridgeProviderProps } from './index.js';
4
+
5
+ interface ReactRouterAppBridgeProviderProps extends Omit<AppBridgeProviderProps, "currentPath" | "onNavigate"> {
6
+ children: ReactNode;
7
+ }
8
+ declare function ReactRouterAppBridgeProvider({ children, ...props }: ReactRouterAppBridgeProviderProps): react_jsx_runtime.JSX.Element;
9
+
10
+ export { ReactRouterAppBridgeProvider, type ReactRouterAppBridgeProviderProps };
@@ -0,0 +1,30 @@
1
+ import {
2
+ AppBridgeProvider
3
+ } from "./chunk-J4BEZO5J.js";
4
+
5
+ // src/react-router.tsx
6
+ import { useLocation, useNavigate } from "react-router";
7
+ import { jsx } from "react/jsx-runtime";
8
+ function ReactRouterAppBridgeProvider({
9
+ children,
10
+ ...props
11
+ }) {
12
+ const location = useLocation();
13
+ const navigate = useNavigate();
14
+ const currentPath = `${location.pathname}${location.search}${location.hash}`;
15
+ return /* @__PURE__ */ jsx(
16
+ AppBridgeProvider,
17
+ {
18
+ ...props,
19
+ currentPath,
20
+ onNavigate: (path) => {
21
+ void navigate(path);
22
+ },
23
+ children
24
+ }
25
+ );
26
+ }
27
+ export {
28
+ ReactRouterAppBridgeProvider
29
+ };
30
+ //# sourceMappingURL=react-router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react-router.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { useLocation, useNavigate } from \"react-router\";\n\nimport {\n AppBridgeProvider,\n type AppBridgeProviderProps\n} from \"./react\";\n\nexport interface ReactRouterAppBridgeProviderProps\n extends Omit<AppBridgeProviderProps, \"currentPath\" | \"onNavigate\"> {\n children: ReactNode;\n}\n\nexport function ReactRouterAppBridgeProvider({\n children,\n ...props\n}: ReactRouterAppBridgeProviderProps) {\n const location = useLocation();\n const navigate = useNavigate();\n const currentPath = `${location.pathname}${location.search}${location.hash}`;\n\n return (\n <AppBridgeProvider\n {...props}\n currentPath={currentPath}\n onNavigate={(path) => {\n void navigate(path);\n }}\n >\n {children}\n </AppBridgeProvider>\n );\n}\n"],"mappings":";;;;;AACA,SAAS,aAAa,mBAAmB;AAqBrC;AATG,SAAS,6BAA6B;AAAA,EAC3C;AAAA,EACA,GAAG;AACL,GAAsC;AACpC,QAAM,WAAW,YAAY;AAC7B,QAAM,WAAW,YAAY;AAC7B,QAAM,cAAc,GAAG,SAAS,QAAQ,GAAG,SAAS,MAAM,GAAG,SAAS,IAAI;AAE1E,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ;AAAA,MACA,YAAY,CAAC,SAAS;AACpB,aAAK,SAAS,IAAI;AAAA,MACpB;AAAA,MAEC;AAAA;AAAA,EACH;AAEJ;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thor-commerce/app-bridge-react",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Communication bridge between embedded apps and the Thor Commerce dashboard",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -11,6 +11,16 @@
11
11
  "types": "./dist/index.d.ts",
12
12
  "import": "./dist/index.js",
13
13
  "require": "./dist/index.cjs"
14
+ },
15
+ "./react-router": {
16
+ "types": "./dist/react-router.d.ts",
17
+ "import": "./dist/react-router.js",
18
+ "require": "./dist/react-router.cjs"
19
+ },
20
+ "./next": {
21
+ "types": "./dist/next.d.ts",
22
+ "import": "./dist/next.js",
23
+ "require": "./dist/next.cjs"
14
24
  }
15
25
  },
16
26
  "files": [
@@ -19,19 +29,64 @@
19
29
  "scripts": {
20
30
  "build": "tsup",
21
31
  "dev": "tsup --watch",
32
+ "release": "semantic-release",
22
33
  "test": "tsx --test test/*.test.ts",
23
34
  "typecheck": "tsc --noEmit",
24
35
  "prepublishOnly": "npm run build"
25
36
  },
37
+ "release": {
38
+ "branches": [
39
+ "main"
40
+ ],
41
+ "tagFormat": "v${version}",
42
+ "plugins": [
43
+ "@semantic-release/commit-analyzer",
44
+ "@semantic-release/release-notes-generator",
45
+ [
46
+ "@semantic-release/npm",
47
+ {
48
+ "npmPublish": true
49
+ }
50
+ ]
51
+ ]
52
+ },
26
53
  "devDependencies": {
54
+ "@semantic-release/commit-analyzer": "^13.0.1",
55
+ "@semantic-release/npm": "^13.1.5",
56
+ "@semantic-release/release-notes-generator": "^14.1.0",
27
57
  "@types/node": "^25.5.0",
58
+ "@types/react": "^19.2.14",
59
+ "react": "^19.2.4",
60
+ "react-router": "^7.13.1",
61
+ "semantic-release": "^25.0.3",
28
62
  "tsup": "^8.0.0",
29
63
  "tsx": "^4.21.0",
30
64
  "typescript": "^5.5.0"
31
65
  },
32
66
  "license": "MIT",
67
+ "peerDependencies": {
68
+ "next": ">=13.4.0",
69
+ "react": ">=18.2.0",
70
+ "react-router": ">=7.0.0"
71
+ },
72
+ "peerDependenciesMeta": {
73
+ "next": {
74
+ "optional": true
75
+ },
76
+ "react-router": {
77
+ "optional": true
78
+ }
79
+ },
33
80
  "repository": {
34
- "type": "git"
81
+ "type": "git",
82
+ "url": "git+https://github.com/thor-commerce/thor-app-bridge.git"
83
+ },
84
+ "homepage": "https://github.com/thor-commerce/thor-email-app",
85
+ "bugs": {
86
+ "url": "https://github.com/thor-commerce/thor-app-bridge/issues"
87
+ },
88
+ "publishConfig": {
89
+ "access": "public"
35
90
  },
36
91
  "keywords": [
37
92
  "thor-commerce",