@thor-commerce/app-bridge-react 0.5.0 → 0.6.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 +5 -13
- package/dist/{chunk-RWPS2DOE.js → chunk-X5YISVIL.js} +160 -16
- package/dist/chunk-X5YISVIL.js.map +1 -0
- package/dist/index.cjs +159 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -4
- package/dist/index.d.ts +12 -4
- package/dist/index.js +1 -1
- package/dist/next.cjs +159 -15
- package/dist/next.cjs.map +1 -1
- package/dist/next.d.cts +2 -1
- package/dist/next.d.ts +2 -1
- package/dist/next.js +1 -1
- package/dist/next.js.map +1 -1
- package/dist/react-router.cjs +194 -16
- package/dist/react-router.cjs.map +1 -1
- package/dist/react-router.d.cts +2 -1
- package/dist/react-router.d.ts +2 -1
- package/dist/react-router.js +36 -2
- package/dist/react-router.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-RWPS2DOE.js.map +0 -1
package/README.md
CHANGED
|
@@ -24,6 +24,7 @@ const bridge = createAppBridge({
|
|
|
24
24
|
bridge.send("app:ready", { version: "1.0.0" });
|
|
25
25
|
|
|
26
26
|
const session = await bridge.request<undefined, { shopId: string }>("session:get");
|
|
27
|
+
const sessionToken = await bridge.getSessionToken({ clientId: "your-client-id" });
|
|
27
28
|
|
|
28
29
|
bridge.on("navigation:update", (message) => {
|
|
29
30
|
console.log(message.payload);
|
|
@@ -38,12 +39,7 @@ import { ReactRouterAppBridgeProvider } from "@thor-commerce/app-bridge-react/re
|
|
|
38
39
|
|
|
39
40
|
export default function App() {
|
|
40
41
|
return (
|
|
41
|
-
<ReactRouterAppBridgeProvider
|
|
42
|
-
source="embedded-app"
|
|
43
|
-
target="dashboard"
|
|
44
|
-
targetOrigin="https://dashboard.thorcommerce.com"
|
|
45
|
-
allowedOrigins={["https://dashboard.thorcommerce.com"]}
|
|
46
|
-
>
|
|
42
|
+
<ReactRouterAppBridgeProvider clientId="your-client-id">
|
|
47
43
|
<Outlet />
|
|
48
44
|
</ReactRouterAppBridgeProvider>
|
|
49
45
|
);
|
|
@@ -59,12 +55,7 @@ import { NextAppBridgeProvider } from "@thor-commerce/app-bridge-react/next";
|
|
|
59
55
|
|
|
60
56
|
export function Providers({ children }: { children: React.ReactNode }) {
|
|
61
57
|
return (
|
|
62
|
-
<NextAppBridgeProvider
|
|
63
|
-
source="embedded-app"
|
|
64
|
-
target="dashboard"
|
|
65
|
-
targetOrigin="https://dashboard.thorcommerce.com"
|
|
66
|
-
allowedOrigins={["https://dashboard.thorcommerce.com"]}
|
|
67
|
-
>
|
|
58
|
+
<NextAppBridgeProvider clientId="your-client-id">
|
|
68
59
|
{children}
|
|
69
60
|
</NextAppBridgeProvider>
|
|
70
61
|
);
|
|
@@ -88,9 +79,10 @@ If you are not using React Router or Next.js, use `AppBridgeProvider` from the r
|
|
|
88
79
|
- `AppBridgeProvider` manages the bridge lifecycle for React apps.
|
|
89
80
|
- `useAppBridge()` gives access to the underlying bridge instance for advanced cases.
|
|
90
81
|
- `ReactRouterAppBridgeProvider` and `NextAppBridgeProvider` are framework adapters with built-in navigation syncing.
|
|
91
|
-
- `
|
|
82
|
+
- `clientId` is the primary app identity input for the React providers. The provider infers the dashboard origin from `document.referrer` in embedded contexts.
|
|
92
83
|
- `bridge.send(type, payload)` sends a fire-and-forget event.
|
|
93
84
|
- `bridge.request(type, payload, options)` sends a request and waits for a response.
|
|
85
|
+
- `bridge.getSessionToken({clientId}, options)` requests a short-lived embedded app session token from the dashboard.
|
|
94
86
|
- `bridge.on(type, handler)` subscribes to events. Use `"*"` to listen to every incoming message.
|
|
95
87
|
- `bridge.onRequest(type, handler)` registers a request handler that can reply with a value or promise.
|
|
96
88
|
- `bridge.setTargetWindow(window)` updates the destination window after construction.
|
|
@@ -117,6 +117,7 @@ var AppBridge = class {
|
|
|
117
117
|
this.requestHandlers = /* @__PURE__ */ new Map();
|
|
118
118
|
this.pendingRequests = /* @__PURE__ */ new Map();
|
|
119
119
|
this.namespace = options.namespace ?? DEFAULT_NAMESPACE;
|
|
120
|
+
this.clientId = options.clientId;
|
|
120
121
|
this.source = options.source ?? "embedded-app";
|
|
121
122
|
this.target = options.target;
|
|
122
123
|
this.targetOrigin = options.targetOrigin ?? "*";
|
|
@@ -200,10 +201,14 @@ var AppBridge = class {
|
|
|
200
201
|
}
|
|
201
202
|
});
|
|
202
203
|
}
|
|
203
|
-
getSessionToken(options = {}) {
|
|
204
|
+
getSessionToken(request = {}, options = {}) {
|
|
205
|
+
const resolvedRequest = request.clientId || this.clientId ? {
|
|
206
|
+
...request,
|
|
207
|
+
clientId: request.clientId ?? this.clientId
|
|
208
|
+
} : request;
|
|
204
209
|
return this.request(
|
|
205
210
|
"thor:session-token:get",
|
|
206
|
-
|
|
211
|
+
resolvedRequest,
|
|
207
212
|
options
|
|
208
213
|
);
|
|
209
214
|
}
|
|
@@ -378,8 +383,8 @@ import {
|
|
|
378
383
|
import { jsx } from "react/jsx-runtime";
|
|
379
384
|
var AppBridgeContext = createContext(null);
|
|
380
385
|
function AppBridgeProvider({
|
|
381
|
-
allowedOrigins,
|
|
382
386
|
children,
|
|
387
|
+
clientId,
|
|
383
388
|
currentPath,
|
|
384
389
|
navigationEventType = "navigation:go",
|
|
385
390
|
navigationUpdateEventType = "navigation:update",
|
|
@@ -389,14 +394,13 @@ function AppBridgeProvider({
|
|
|
389
394
|
readyPayload,
|
|
390
395
|
requestTimeoutMs,
|
|
391
396
|
selfWindow,
|
|
392
|
-
source,
|
|
393
|
-
target,
|
|
394
397
|
targetOrigin,
|
|
395
398
|
targetWindow
|
|
396
399
|
}) {
|
|
397
400
|
const [bridge, setBridge] = useState(null);
|
|
398
401
|
const onNavigateRef = useRef(onNavigate);
|
|
399
|
-
const
|
|
402
|
+
const sessionTokenCacheRef = useRef(null);
|
|
403
|
+
const pendingSessionTokenRef = useRef(null);
|
|
400
404
|
useEffect(() => {
|
|
401
405
|
onNavigateRef.current = onNavigate;
|
|
402
406
|
}, [onNavigate]);
|
|
@@ -404,14 +408,17 @@ function AppBridgeProvider({
|
|
|
404
408
|
if (typeof window === "undefined" && !selfWindow) {
|
|
405
409
|
return;
|
|
406
410
|
}
|
|
411
|
+
const resolvedTargetOrigin = targetOrigin ?? getReferrerOrigin(selfWindow);
|
|
412
|
+
const resolvedAllowedOrigins = resolvedTargetOrigin ? [resolvedTargetOrigin] : void 0;
|
|
407
413
|
const nextBridge = createAppBridge({
|
|
408
|
-
allowedOrigins:
|
|
414
|
+
allowedOrigins: resolvedAllowedOrigins,
|
|
415
|
+
clientId,
|
|
409
416
|
namespace,
|
|
410
417
|
requestTimeoutMs,
|
|
411
418
|
selfWindow,
|
|
412
|
-
source,
|
|
413
|
-
target,
|
|
414
|
-
targetOrigin,
|
|
419
|
+
source: "embedded-app",
|
|
420
|
+
target: "dashboard",
|
|
421
|
+
targetOrigin: resolvedTargetOrigin,
|
|
415
422
|
targetWindow
|
|
416
423
|
});
|
|
417
424
|
setBridge(nextBridge);
|
|
@@ -420,12 +427,10 @@ function AppBridgeProvider({
|
|
|
420
427
|
nextBridge.destroy();
|
|
421
428
|
};
|
|
422
429
|
}, [
|
|
423
|
-
|
|
430
|
+
clientId,
|
|
424
431
|
namespace,
|
|
425
432
|
requestTimeoutMs,
|
|
426
433
|
selfWindow,
|
|
427
|
-
source,
|
|
428
|
-
target,
|
|
429
434
|
targetOrigin,
|
|
430
435
|
targetWindow
|
|
431
436
|
]);
|
|
@@ -433,8 +438,13 @@ function AppBridgeProvider({
|
|
|
433
438
|
if (!bridge || !bridge.hasTargetWindow()) {
|
|
434
439
|
return;
|
|
435
440
|
}
|
|
436
|
-
bridge.send(
|
|
437
|
-
|
|
441
|
+
bridge.send(
|
|
442
|
+
readyEventType,
|
|
443
|
+
readyPayload ?? {
|
|
444
|
+
clientId
|
|
445
|
+
}
|
|
446
|
+
);
|
|
447
|
+
}, [bridge, clientId, readyEventType, readyPayload]);
|
|
438
448
|
useEffect(() => {
|
|
439
449
|
if (!bridge || !bridge.hasTargetWindow() || !currentPath) {
|
|
440
450
|
return;
|
|
@@ -453,11 +463,145 @@ function AppBridgeProvider({
|
|
|
453
463
|
onNavigateRef.current?.(destination, message);
|
|
454
464
|
});
|
|
455
465
|
}, [bridge, navigationEventType, onNavigate]);
|
|
466
|
+
useEffect(() => {
|
|
467
|
+
if (!bridge || typeof window === "undefined") {
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
const originalFetch = window.fetch.bind(window);
|
|
471
|
+
window.fetch = async (input, init) => {
|
|
472
|
+
if (!shouldAttachSessionToken(input)) {
|
|
473
|
+
return originalFetch(input, init);
|
|
474
|
+
}
|
|
475
|
+
const existingAuthorization = getExistingAuthorization(input, init);
|
|
476
|
+
if (existingAuthorization) {
|
|
477
|
+
return originalFetch(input, init);
|
|
478
|
+
}
|
|
479
|
+
const nextHeaders = new Headers(
|
|
480
|
+
input instanceof Request ? input.headers : init?.headers
|
|
481
|
+
);
|
|
482
|
+
const sessionToken = await getSessionToken({
|
|
483
|
+
bridge,
|
|
484
|
+
clientId,
|
|
485
|
+
pendingSessionTokenRef,
|
|
486
|
+
sessionTokenCacheRef
|
|
487
|
+
});
|
|
488
|
+
nextHeaders.set("Authorization", `Bearer ${sessionToken}`);
|
|
489
|
+
if (input instanceof Request) {
|
|
490
|
+
return originalFetch(
|
|
491
|
+
new Request(input, {
|
|
492
|
+
headers: nextHeaders
|
|
493
|
+
})
|
|
494
|
+
);
|
|
495
|
+
}
|
|
496
|
+
return originalFetch(input, {
|
|
497
|
+
...init,
|
|
498
|
+
headers: nextHeaders
|
|
499
|
+
});
|
|
500
|
+
};
|
|
501
|
+
return () => {
|
|
502
|
+
window.fetch = originalFetch;
|
|
503
|
+
};
|
|
504
|
+
}, [bridge, clientId]);
|
|
456
505
|
return /* @__PURE__ */ jsx(AppBridgeContext.Provider, { value: bridge, children });
|
|
457
506
|
}
|
|
458
507
|
function useAppBridge() {
|
|
459
508
|
return useContext(AppBridgeContext);
|
|
460
509
|
}
|
|
510
|
+
function getReferrerOrigin(explicitWindow) {
|
|
511
|
+
const resolvedWindow = explicitWindow ?? (typeof window !== "undefined" ? window : void 0);
|
|
512
|
+
const referrer = resolvedWindow?.document?.referrer;
|
|
513
|
+
if (!referrer) {
|
|
514
|
+
return void 0;
|
|
515
|
+
}
|
|
516
|
+
try {
|
|
517
|
+
return new URL(referrer).origin;
|
|
518
|
+
} catch {
|
|
519
|
+
return void 0;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
async function getSessionToken({
|
|
523
|
+
bridge,
|
|
524
|
+
clientId,
|
|
525
|
+
pendingSessionTokenRef,
|
|
526
|
+
sessionTokenCacheRef
|
|
527
|
+
}) {
|
|
528
|
+
const cachedToken = sessionTokenCacheRef.current;
|
|
529
|
+
if (cachedToken && !isExpired(cachedToken.expiresAt)) {
|
|
530
|
+
return cachedToken.token;
|
|
531
|
+
}
|
|
532
|
+
if (pendingSessionTokenRef.current) {
|
|
533
|
+
return pendingSessionTokenRef.current;
|
|
534
|
+
}
|
|
535
|
+
const pendingToken = bridge.getSessionToken({ clientId }).then((response) => {
|
|
536
|
+
const token = response.sessionToken ?? response.idToken;
|
|
537
|
+
if (!token) {
|
|
538
|
+
throw new Error("Missing Thor embedded session token");
|
|
539
|
+
}
|
|
540
|
+
sessionTokenCacheRef.current = {
|
|
541
|
+
token,
|
|
542
|
+
expiresAt: normalizeTokenExpiry(token, response.exp)
|
|
543
|
+
};
|
|
544
|
+
pendingSessionTokenRef.current = null;
|
|
545
|
+
return token;
|
|
546
|
+
}).catch((error) => {
|
|
547
|
+
pendingSessionTokenRef.current = null;
|
|
548
|
+
throw error;
|
|
549
|
+
});
|
|
550
|
+
pendingSessionTokenRef.current = pendingToken;
|
|
551
|
+
return pendingToken;
|
|
552
|
+
}
|
|
553
|
+
function shouldAttachSessionToken(input) {
|
|
554
|
+
if (typeof window === "undefined") {
|
|
555
|
+
return false;
|
|
556
|
+
}
|
|
557
|
+
const requestUrl = resolveRequestUrl(input);
|
|
558
|
+
return requestUrl.origin === window.location.origin;
|
|
559
|
+
}
|
|
560
|
+
function resolveRequestUrl(input) {
|
|
561
|
+
if (input instanceof Request) {
|
|
562
|
+
return new URL(input.url);
|
|
563
|
+
}
|
|
564
|
+
if (input instanceof URL) {
|
|
565
|
+
return input;
|
|
566
|
+
}
|
|
567
|
+
return new URL(input, window.location.href);
|
|
568
|
+
}
|
|
569
|
+
function getExistingAuthorization(input, init) {
|
|
570
|
+
if (input instanceof Request && input.headers.has("Authorization")) {
|
|
571
|
+
return input.headers.get("Authorization");
|
|
572
|
+
}
|
|
573
|
+
if (!init?.headers) {
|
|
574
|
+
return null;
|
|
575
|
+
}
|
|
576
|
+
return new Headers(init.headers).get("Authorization");
|
|
577
|
+
}
|
|
578
|
+
function normalizeTokenExpiry(token, explicitExp) {
|
|
579
|
+
const tokenExp = explicitExp ?? decodeJwtExpiry(token);
|
|
580
|
+
return tokenExp ? tokenExp * 1e3 : void 0;
|
|
581
|
+
}
|
|
582
|
+
function decodeJwtExpiry(token) {
|
|
583
|
+
const [, payload] = token.split(".");
|
|
584
|
+
if (!payload || typeof window === "undefined") {
|
|
585
|
+
return void 0;
|
|
586
|
+
}
|
|
587
|
+
try {
|
|
588
|
+
const normalized = payload.replace(/-/g, "+").replace(/_/g, "/");
|
|
589
|
+
const padded = normalized.padEnd(
|
|
590
|
+
normalized.length + (4 - normalized.length % 4) % 4,
|
|
591
|
+
"="
|
|
592
|
+
);
|
|
593
|
+
const json = JSON.parse(window.atob(padded));
|
|
594
|
+
return typeof json.exp === "number" ? json.exp : void 0;
|
|
595
|
+
} catch {
|
|
596
|
+
return void 0;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
function isExpired(expiresAt) {
|
|
600
|
+
if (!expiresAt) {
|
|
601
|
+
return false;
|
|
602
|
+
}
|
|
603
|
+
return Date.now() >= expiresAt - 5e3;
|
|
604
|
+
}
|
|
461
605
|
|
|
462
606
|
export {
|
|
463
607
|
buildNavigationUpdatePayload,
|
|
@@ -468,4 +612,4 @@ export {
|
|
|
468
612
|
AppBridgeProvider,
|
|
469
613
|
useAppBridge
|
|
470
614
|
};
|
|
471
|
-
//# sourceMappingURL=chunk-
|
|
615
|
+
//# sourceMappingURL=chunk-X5YISVIL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/navigation.ts","../src/core.ts","../src/react.tsx"],"sourcesContent":["export interface BridgeNavigationGoPayload {\n path?: string;\n href?: string;\n pathname?: string;\n search?: string;\n hash?: string;\n}\n\nexport interface BridgeNavigationRedirectPayload extends BridgeNavigationGoPayload {}\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 resolveNavigationDestination,\n type BridgeNavigationGoPayload,\n type BridgeNavigationRedirectPayload\n} from \"./navigation\";\n\nexport 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 clientId?: string;\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 SessionTokenRequest {\n clientId?: string;\n}\n\nexport interface SessionTokenResponse {\n sessionToken?: string;\n idToken: string;\n exp?: number;\n project?: string;\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;\nconst DEFAULT_REDIRECT_EVENT_TYPE = \"navigation:redirect\";\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 isMessageTarget(value: unknown): value is Window {\n return !!value && typeof (value as Window).postMessage === \"function\";\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 clientId?: 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.clientId = options.clientId;\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 hasTargetWindow() {\n return this.targetWindow !== undefined;\n }\n\n redirect(payload: string | BridgeNavigationRedirectPayload) {\n const destination = resolveNavigationDestination(payload);\n if (!destination) {\n throw new Error(\"AppBridge redirect requires a valid destination.\");\n }\n\n if (!this.targetWindow) {\n this.navigateSelf(destination);\n return;\n }\n\n this.postMessage<BridgeNavigationRedirectPayload>({\n kind: \"event\",\n type: DEFAULT_REDIRECT_EVENT_TYPE,\n payload: typeof payload === \"string\" ? { href: payload } : payload\n });\n }\n\n redirectToRemote(href: string) {\n this.redirect({ href });\n }\n\n redirectToApp(path: string | BridgeNavigationGoPayload) {\n this.redirect(typeof path === \"string\" ? { path } : path);\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 getSessionToken(\n request: SessionTokenRequest = {},\n options: RequestOptions = {}\n ) {\n const resolvedRequest =\n request.clientId || this.clientId\n ? {\n ...request,\n clientId: request.clientId ?? this.clientId\n }\n : request;\n\n return this.request<SessionTokenRequest, SessionTokenResponse>(\n \"thor:session-token:get\",\n resolvedRequest,\n options\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 (\n message.kind === \"event\" &&\n message.type === DEFAULT_REDIRECT_EVENT_TYPE &&\n this.handleRedirectMessage(receivedMessage)\n ) {\n return;\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 const replyTarget = isMessageTarget(message.rawEvent.source)\n ? message.rawEvent.source\n : this.targetWindow;\n\n try {\n const payload = await handler(message.payload, message);\n this.postMessage(\n {\n kind: \"response\",\n type: message.type,\n payload,\n replyTo: message.id\n },\n replyTarget\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 {\n kind: \"response\",\n type: message.type,\n error: bridgeError,\n replyTo: message.id\n },\n replyTarget\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 targetWindowOverride?: Window\n ) {\n const targetWindow = targetWindowOverride ?? 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 private handleRedirectMessage(message: ReceivedBridgeMessage): boolean {\n const destination = resolveNavigationDestination(message.payload);\n if (!destination) {\n return false;\n }\n\n this.navigateSelf(destination);\n return true;\n }\n\n private navigateSelf(destination: string) {\n if (!this.selfWindow) {\n throw new Error(\"AppBridge could not resolve a browser window for redirect.\");\n }\n\n this.selfWindow.location.assign(destination);\n }\n}\n\nexport function createAppBridge(options: AppBridgeOptions = {}) {\n return new AppBridge(options);\n}\n","import {\n createContext,\n useContext,\n useEffect,\n useRef,\n useState,\n type MutableRefObject,\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\n extends Omit<AppBridgeOptions, \"source\" | \"target\" | \"allowedOrigins\"> {\n children: ReactNode;\n clientId: string;\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 children,\n clientId,\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 targetOrigin,\n targetWindow\n}: AppBridgeProviderProps) {\n const [bridge, setBridge] = useState<AppBridge | null>(null);\n const onNavigateRef = useRef(onNavigate);\n const sessionTokenCacheRef = useRef<{\n token: string;\n expiresAt?: number;\n } | null>(null);\n const pendingSessionTokenRef = useRef<Promise<string> | null>(null);\n\n useEffect(() => {\n onNavigateRef.current = onNavigate;\n }, [onNavigate]);\n\n useEffect(() => {\n if (typeof window === \"undefined\" && !selfWindow) {\n return;\n }\n\n const resolvedTargetOrigin = targetOrigin ?? getReferrerOrigin(selfWindow);\n const resolvedAllowedOrigins = resolvedTargetOrigin\n ? [resolvedTargetOrigin]\n : undefined;\n\n const nextBridge = createAppBridge({\n allowedOrigins: resolvedAllowedOrigins,\n clientId,\n namespace,\n requestTimeoutMs,\n selfWindow,\n source: \"embedded-app\",\n target: \"dashboard\",\n targetOrigin: resolvedTargetOrigin,\n targetWindow\n });\n\n setBridge(nextBridge);\n\n return () => {\n setBridge((currentBridge) => (currentBridge === nextBridge ? null : currentBridge));\n nextBridge.destroy();\n };\n }, [\n clientId,\n namespace,\n requestTimeoutMs,\n selfWindow,\n targetOrigin,\n targetWindow\n ]);\n\n useEffect(() => {\n if (!bridge || !bridge.hasTargetWindow()) {\n return;\n }\n\n bridge.send(\n readyEventType,\n readyPayload ?? {\n clientId\n }\n );\n }, [bridge, clientId, readyEventType, readyPayload]);\n\n useEffect(() => {\n if (!bridge || !bridge.hasTargetWindow() || !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 useEffect(() => {\n if (!bridge || typeof window === \"undefined\") {\n return;\n }\n\n const originalFetch = window.fetch.bind(window);\n\n window.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {\n if (!shouldAttachSessionToken(input)) {\n return originalFetch(input, init);\n }\n\n const existingAuthorization = getExistingAuthorization(input, init);\n if (existingAuthorization) {\n return originalFetch(input, init);\n }\n\n const nextHeaders = new Headers(\n input instanceof Request ? input.headers : init?.headers\n );\n const sessionToken = await getSessionToken({\n bridge,\n clientId,\n pendingSessionTokenRef,\n sessionTokenCacheRef\n });\n\n nextHeaders.set(\"Authorization\", `Bearer ${sessionToken}`);\n\n if (input instanceof Request) {\n return originalFetch(\n new Request(input, {\n headers: nextHeaders\n })\n );\n }\n\n return originalFetch(input, {\n ...init,\n headers: nextHeaders\n });\n };\n\n return () => {\n window.fetch = originalFetch;\n };\n }, [bridge, clientId]);\n\n return <AppBridgeContext.Provider value={bridge}>{children}</AppBridgeContext.Provider>;\n}\n\nexport function useAppBridge() {\n return useContext(AppBridgeContext);\n}\n\nfunction getReferrerOrigin(explicitWindow?: Window) {\n const resolvedWindow = explicitWindow ?? (typeof window !== \"undefined\" ? window : undefined);\n const referrer = resolvedWindow?.document?.referrer;\n\n if (!referrer) {\n return undefined;\n }\n\n try {\n return new URL(referrer).origin;\n } catch {\n return undefined;\n }\n}\n\nasync function getSessionToken({\n bridge,\n clientId,\n pendingSessionTokenRef,\n sessionTokenCacheRef\n}: {\n bridge: AppBridge;\n clientId: string;\n pendingSessionTokenRef: MutableRefObject<Promise<string> | null>;\n sessionTokenCacheRef: MutableRefObject<{\n token: string;\n expiresAt?: number;\n } | null>;\n}) {\n const cachedToken = sessionTokenCacheRef.current;\n if (cachedToken && !isExpired(cachedToken.expiresAt)) {\n return cachedToken.token;\n }\n\n if (pendingSessionTokenRef.current) {\n return pendingSessionTokenRef.current;\n }\n\n const pendingToken = bridge\n .getSessionToken({ clientId })\n .then((response) => {\n const token = response.sessionToken ?? response.idToken;\n if (!token) {\n throw new Error(\"Missing Thor embedded session token\");\n }\n\n sessionTokenCacheRef.current = {\n token,\n expiresAt: normalizeTokenExpiry(token, response.exp)\n };\n pendingSessionTokenRef.current = null;\n\n return token;\n })\n .catch((error) => {\n pendingSessionTokenRef.current = null;\n throw error;\n });\n\n pendingSessionTokenRef.current = pendingToken;\n return pendingToken;\n}\n\nfunction shouldAttachSessionToken(input: RequestInfo | URL) {\n if (typeof window === \"undefined\") {\n return false;\n }\n\n const requestUrl = resolveRequestUrl(input);\n return requestUrl.origin === window.location.origin;\n}\n\nfunction resolveRequestUrl(input: RequestInfo | URL) {\n if (input instanceof Request) {\n return new URL(input.url);\n }\n\n if (input instanceof URL) {\n return input;\n }\n\n return new URL(input, window.location.href);\n}\n\nfunction getExistingAuthorization(input: RequestInfo | URL, init?: RequestInit) {\n if (input instanceof Request && input.headers.has(\"Authorization\")) {\n return input.headers.get(\"Authorization\");\n }\n\n if (!init?.headers) {\n return null;\n }\n\n return new Headers(init.headers).get(\"Authorization\");\n}\n\nfunction normalizeTokenExpiry(token: string, explicitExp?: number) {\n const tokenExp = explicitExp ?? decodeJwtExpiry(token);\n return tokenExp ? tokenExp * 1000 : undefined;\n}\n\nfunction decodeJwtExpiry(token: string) {\n const [, payload] = token.split(\".\");\n if (!payload || typeof window === \"undefined\") {\n return undefined;\n }\n\n try {\n const normalized = payload.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padded = normalized.padEnd(\n normalized.length + ((4 - (normalized.length % 4)) % 4),\n \"=\"\n );\n const json = JSON.parse(window.atob(padded)) as { exp?: unknown };\n\n return typeof json.exp === \"number\" ? json.exp : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction isExpired(expiresAt?: number) {\n if (!expiresAt) {\n return false;\n }\n\n return Date.now() >= expiresAt - 5_000;\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.cjs
CHANGED
|
@@ -149,6 +149,7 @@ var AppBridge = class {
|
|
|
149
149
|
this.requestHandlers = /* @__PURE__ */ new Map();
|
|
150
150
|
this.pendingRequests = /* @__PURE__ */ new Map();
|
|
151
151
|
this.namespace = options.namespace ?? DEFAULT_NAMESPACE;
|
|
152
|
+
this.clientId = options.clientId;
|
|
152
153
|
this.source = options.source ?? "embedded-app";
|
|
153
154
|
this.target = options.target;
|
|
154
155
|
this.targetOrigin = options.targetOrigin ?? "*";
|
|
@@ -232,10 +233,14 @@ var AppBridge = class {
|
|
|
232
233
|
}
|
|
233
234
|
});
|
|
234
235
|
}
|
|
235
|
-
getSessionToken(options = {}) {
|
|
236
|
+
getSessionToken(request = {}, options = {}) {
|
|
237
|
+
const resolvedRequest = request.clientId || this.clientId ? {
|
|
238
|
+
...request,
|
|
239
|
+
clientId: request.clientId ?? this.clientId
|
|
240
|
+
} : request;
|
|
236
241
|
return this.request(
|
|
237
242
|
"thor:session-token:get",
|
|
238
|
-
|
|
243
|
+
resolvedRequest,
|
|
239
244
|
options
|
|
240
245
|
);
|
|
241
246
|
}
|
|
@@ -404,8 +409,8 @@ var import_react = require("react");
|
|
|
404
409
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
405
410
|
var AppBridgeContext = (0, import_react.createContext)(null);
|
|
406
411
|
function AppBridgeProvider({
|
|
407
|
-
allowedOrigins,
|
|
408
412
|
children,
|
|
413
|
+
clientId,
|
|
409
414
|
currentPath,
|
|
410
415
|
navigationEventType = "navigation:go",
|
|
411
416
|
navigationUpdateEventType = "navigation:update",
|
|
@@ -415,14 +420,13 @@ function AppBridgeProvider({
|
|
|
415
420
|
readyPayload,
|
|
416
421
|
requestTimeoutMs,
|
|
417
422
|
selfWindow,
|
|
418
|
-
source,
|
|
419
|
-
target,
|
|
420
423
|
targetOrigin,
|
|
421
424
|
targetWindow
|
|
422
425
|
}) {
|
|
423
426
|
const [bridge, setBridge] = (0, import_react.useState)(null);
|
|
424
427
|
const onNavigateRef = (0, import_react.useRef)(onNavigate);
|
|
425
|
-
const
|
|
428
|
+
const sessionTokenCacheRef = (0, import_react.useRef)(null);
|
|
429
|
+
const pendingSessionTokenRef = (0, import_react.useRef)(null);
|
|
426
430
|
(0, import_react.useEffect)(() => {
|
|
427
431
|
onNavigateRef.current = onNavigate;
|
|
428
432
|
}, [onNavigate]);
|
|
@@ -430,14 +434,17 @@ function AppBridgeProvider({
|
|
|
430
434
|
if (typeof window === "undefined" && !selfWindow) {
|
|
431
435
|
return;
|
|
432
436
|
}
|
|
437
|
+
const resolvedTargetOrigin = targetOrigin ?? getReferrerOrigin(selfWindow);
|
|
438
|
+
const resolvedAllowedOrigins = resolvedTargetOrigin ? [resolvedTargetOrigin] : void 0;
|
|
433
439
|
const nextBridge = createAppBridge({
|
|
434
|
-
allowedOrigins:
|
|
440
|
+
allowedOrigins: resolvedAllowedOrigins,
|
|
441
|
+
clientId,
|
|
435
442
|
namespace,
|
|
436
443
|
requestTimeoutMs,
|
|
437
444
|
selfWindow,
|
|
438
|
-
source,
|
|
439
|
-
target,
|
|
440
|
-
targetOrigin,
|
|
445
|
+
source: "embedded-app",
|
|
446
|
+
target: "dashboard",
|
|
447
|
+
targetOrigin: resolvedTargetOrigin,
|
|
441
448
|
targetWindow
|
|
442
449
|
});
|
|
443
450
|
setBridge(nextBridge);
|
|
@@ -446,12 +453,10 @@ function AppBridgeProvider({
|
|
|
446
453
|
nextBridge.destroy();
|
|
447
454
|
};
|
|
448
455
|
}, [
|
|
449
|
-
|
|
456
|
+
clientId,
|
|
450
457
|
namespace,
|
|
451
458
|
requestTimeoutMs,
|
|
452
459
|
selfWindow,
|
|
453
|
-
source,
|
|
454
|
-
target,
|
|
455
460
|
targetOrigin,
|
|
456
461
|
targetWindow
|
|
457
462
|
]);
|
|
@@ -459,8 +464,13 @@ function AppBridgeProvider({
|
|
|
459
464
|
if (!bridge || !bridge.hasTargetWindow()) {
|
|
460
465
|
return;
|
|
461
466
|
}
|
|
462
|
-
bridge.send(
|
|
463
|
-
|
|
467
|
+
bridge.send(
|
|
468
|
+
readyEventType,
|
|
469
|
+
readyPayload ?? {
|
|
470
|
+
clientId
|
|
471
|
+
}
|
|
472
|
+
);
|
|
473
|
+
}, [bridge, clientId, readyEventType, readyPayload]);
|
|
464
474
|
(0, import_react.useEffect)(() => {
|
|
465
475
|
if (!bridge || !bridge.hasTargetWindow() || !currentPath) {
|
|
466
476
|
return;
|
|
@@ -479,11 +489,145 @@ function AppBridgeProvider({
|
|
|
479
489
|
onNavigateRef.current?.(destination, message);
|
|
480
490
|
});
|
|
481
491
|
}, [bridge, navigationEventType, onNavigate]);
|
|
492
|
+
(0, import_react.useEffect)(() => {
|
|
493
|
+
if (!bridge || typeof window === "undefined") {
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
const originalFetch = window.fetch.bind(window);
|
|
497
|
+
window.fetch = async (input, init) => {
|
|
498
|
+
if (!shouldAttachSessionToken(input)) {
|
|
499
|
+
return originalFetch(input, init);
|
|
500
|
+
}
|
|
501
|
+
const existingAuthorization = getExistingAuthorization(input, init);
|
|
502
|
+
if (existingAuthorization) {
|
|
503
|
+
return originalFetch(input, init);
|
|
504
|
+
}
|
|
505
|
+
const nextHeaders = new Headers(
|
|
506
|
+
input instanceof Request ? input.headers : init?.headers
|
|
507
|
+
);
|
|
508
|
+
const sessionToken = await getSessionToken({
|
|
509
|
+
bridge,
|
|
510
|
+
clientId,
|
|
511
|
+
pendingSessionTokenRef,
|
|
512
|
+
sessionTokenCacheRef
|
|
513
|
+
});
|
|
514
|
+
nextHeaders.set("Authorization", `Bearer ${sessionToken}`);
|
|
515
|
+
if (input instanceof Request) {
|
|
516
|
+
return originalFetch(
|
|
517
|
+
new Request(input, {
|
|
518
|
+
headers: nextHeaders
|
|
519
|
+
})
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
return originalFetch(input, {
|
|
523
|
+
...init,
|
|
524
|
+
headers: nextHeaders
|
|
525
|
+
});
|
|
526
|
+
};
|
|
527
|
+
return () => {
|
|
528
|
+
window.fetch = originalFetch;
|
|
529
|
+
};
|
|
530
|
+
}, [bridge, clientId]);
|
|
482
531
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AppBridgeContext.Provider, { value: bridge, children });
|
|
483
532
|
}
|
|
484
533
|
function useAppBridge() {
|
|
485
534
|
return (0, import_react.useContext)(AppBridgeContext);
|
|
486
535
|
}
|
|
536
|
+
function getReferrerOrigin(explicitWindow) {
|
|
537
|
+
const resolvedWindow = explicitWindow ?? (typeof window !== "undefined" ? window : void 0);
|
|
538
|
+
const referrer = resolvedWindow?.document?.referrer;
|
|
539
|
+
if (!referrer) {
|
|
540
|
+
return void 0;
|
|
541
|
+
}
|
|
542
|
+
try {
|
|
543
|
+
return new URL(referrer).origin;
|
|
544
|
+
} catch {
|
|
545
|
+
return void 0;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
async function getSessionToken({
|
|
549
|
+
bridge,
|
|
550
|
+
clientId,
|
|
551
|
+
pendingSessionTokenRef,
|
|
552
|
+
sessionTokenCacheRef
|
|
553
|
+
}) {
|
|
554
|
+
const cachedToken = sessionTokenCacheRef.current;
|
|
555
|
+
if (cachedToken && !isExpired(cachedToken.expiresAt)) {
|
|
556
|
+
return cachedToken.token;
|
|
557
|
+
}
|
|
558
|
+
if (pendingSessionTokenRef.current) {
|
|
559
|
+
return pendingSessionTokenRef.current;
|
|
560
|
+
}
|
|
561
|
+
const pendingToken = bridge.getSessionToken({ clientId }).then((response) => {
|
|
562
|
+
const token = response.sessionToken ?? response.idToken;
|
|
563
|
+
if (!token) {
|
|
564
|
+
throw new Error("Missing Thor embedded session token");
|
|
565
|
+
}
|
|
566
|
+
sessionTokenCacheRef.current = {
|
|
567
|
+
token,
|
|
568
|
+
expiresAt: normalizeTokenExpiry(token, response.exp)
|
|
569
|
+
};
|
|
570
|
+
pendingSessionTokenRef.current = null;
|
|
571
|
+
return token;
|
|
572
|
+
}).catch((error) => {
|
|
573
|
+
pendingSessionTokenRef.current = null;
|
|
574
|
+
throw error;
|
|
575
|
+
});
|
|
576
|
+
pendingSessionTokenRef.current = pendingToken;
|
|
577
|
+
return pendingToken;
|
|
578
|
+
}
|
|
579
|
+
function shouldAttachSessionToken(input) {
|
|
580
|
+
if (typeof window === "undefined") {
|
|
581
|
+
return false;
|
|
582
|
+
}
|
|
583
|
+
const requestUrl = resolveRequestUrl(input);
|
|
584
|
+
return requestUrl.origin === window.location.origin;
|
|
585
|
+
}
|
|
586
|
+
function resolveRequestUrl(input) {
|
|
587
|
+
if (input instanceof Request) {
|
|
588
|
+
return new URL(input.url);
|
|
589
|
+
}
|
|
590
|
+
if (input instanceof URL) {
|
|
591
|
+
return input;
|
|
592
|
+
}
|
|
593
|
+
return new URL(input, window.location.href);
|
|
594
|
+
}
|
|
595
|
+
function getExistingAuthorization(input, init) {
|
|
596
|
+
if (input instanceof Request && input.headers.has("Authorization")) {
|
|
597
|
+
return input.headers.get("Authorization");
|
|
598
|
+
}
|
|
599
|
+
if (!init?.headers) {
|
|
600
|
+
return null;
|
|
601
|
+
}
|
|
602
|
+
return new Headers(init.headers).get("Authorization");
|
|
603
|
+
}
|
|
604
|
+
function normalizeTokenExpiry(token, explicitExp) {
|
|
605
|
+
const tokenExp = explicitExp ?? decodeJwtExpiry(token);
|
|
606
|
+
return tokenExp ? tokenExp * 1e3 : void 0;
|
|
607
|
+
}
|
|
608
|
+
function decodeJwtExpiry(token) {
|
|
609
|
+
const [, payload] = token.split(".");
|
|
610
|
+
if (!payload || typeof window === "undefined") {
|
|
611
|
+
return void 0;
|
|
612
|
+
}
|
|
613
|
+
try {
|
|
614
|
+
const normalized = payload.replace(/-/g, "+").replace(/_/g, "/");
|
|
615
|
+
const padded = normalized.padEnd(
|
|
616
|
+
normalized.length + (4 - normalized.length % 4) % 4,
|
|
617
|
+
"="
|
|
618
|
+
);
|
|
619
|
+
const json = JSON.parse(window.atob(padded));
|
|
620
|
+
return typeof json.exp === "number" ? json.exp : void 0;
|
|
621
|
+
} catch {
|
|
622
|
+
return void 0;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
function isExpired(expiresAt) {
|
|
626
|
+
if (!expiresAt) {
|
|
627
|
+
return false;
|
|
628
|
+
}
|
|
629
|
+
return Date.now() >= expiresAt - 5e3;
|
|
630
|
+
}
|
|
487
631
|
// Annotate the CommonJS export names for ESM import in node:
|
|
488
632
|
0 && (module.exports = {
|
|
489
633
|
AppBridge,
|