@frak-labs/core-sdk 0.2.1-beta.b38eef2e → 0.2.1-beta.c7fe645d

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +1 -2
  2. package/cdn/bundle.js +55 -3
  3. package/dist/actions.cjs +1 -1
  4. package/dist/actions.d.cts +3 -3
  5. package/dist/actions.d.ts +3 -3
  6. package/dist/actions.js +1 -1
  7. package/dist/bundle.cjs +1 -1
  8. package/dist/bundle.d.cts +4 -4
  9. package/dist/bundle.d.ts +4 -4
  10. package/dist/bundle.js +1 -1
  11. package/dist/{computeLegacyProductId-CCAZvLa5.d.cts → computeLegacyProductId-C35yITjX.d.ts} +91 -37
  12. package/dist/{computeLegacyProductId-b5cUWdAm.d.ts → computeLegacyProductId-mG4x5Cq0.d.cts} +91 -37
  13. package/dist/index.cjs +1 -1
  14. package/dist/index.d.cts +3 -3
  15. package/dist/index.d.ts +3 -3
  16. package/dist/index.js +1 -1
  17. package/dist/{openSso-B0g7-807.d.cts → openSso-7e-OKMhg.d.ts} +266 -46
  18. package/dist/{openSso-CMzwvaCa.d.ts → openSso-BebjXCq0.d.cts} +266 -46
  19. package/dist/setupClient-CUYyoXtI.js +13 -0
  20. package/dist/setupClient-LgwHIFJc.cjs +13 -0
  21. package/dist/{siweAuthenticate-CnCZ7mok.d.ts → siweAuthenticate-BQEMZRg3.d.cts} +102 -8
  22. package/dist/siweAuthenticate-CWcVvP-G.cjs +1 -0
  23. package/dist/{siweAuthenticate-CVigMOxz.d.cts → siweAuthenticate-CdLD-9W2.d.ts} +102 -8
  24. package/dist/siweAuthenticate-DQfdb5UQ.js +1 -0
  25. package/dist/trackEvent-Ce1XlsIE.js +1 -0
  26. package/dist/trackEvent-CvbJTTqA.cjs +1 -0
  27. package/package.json +8 -8
  28. package/src/actions/displayEmbeddedWallet.ts +6 -2
  29. package/src/actions/displayModal.ts +6 -2
  30. package/src/actions/displaySharingPage.ts +49 -0
  31. package/src/actions/ensureIdentity.ts +2 -2
  32. package/src/actions/getMerchantInformation.test.ts +13 -1
  33. package/src/actions/getMerchantInformation.ts +20 -5
  34. package/src/actions/getUserReferralStatus.ts +42 -0
  35. package/src/actions/index.ts +7 -1
  36. package/src/actions/referral/setupReferral.test.ts +79 -0
  37. package/src/actions/referral/setupReferral.ts +32 -0
  38. package/src/actions/trackPurchaseStatus.test.ts +32 -20
  39. package/src/actions/trackPurchaseStatus.ts +3 -5
  40. package/src/actions/wrapper/modalBuilder.test.ts +4 -2
  41. package/src/actions/wrapper/modalBuilder.ts +6 -8
  42. package/src/clients/createIFrameFrakClient.ts +150 -27
  43. package/src/clients/transports/iframeLifecycleManager.test.ts +14 -94
  44. package/src/clients/transports/iframeLifecycleManager.ts +15 -48
  45. package/src/index.ts +17 -4
  46. package/src/types/config.ts +10 -3
  47. package/src/types/index.ts +13 -1
  48. package/src/types/lifecycle/client.ts +22 -27
  49. package/src/types/lifecycle/iframe.ts +7 -8
  50. package/src/types/resolvedConfig.ts +123 -0
  51. package/src/types/rpc/displaySharingPage.ts +77 -0
  52. package/src/types/rpc/interaction.ts +4 -0
  53. package/src/types/rpc/userReferralStatus.ts +20 -0
  54. package/src/types/rpc.ts +42 -5
  55. package/src/utils/backendUrl.test.ts +2 -2
  56. package/src/utils/backendUrl.ts +1 -1
  57. package/src/utils/cache/index.ts +7 -0
  58. package/src/utils/cache/lruMap.test.ts +55 -0
  59. package/src/utils/cache/lruMap.ts +38 -0
  60. package/src/utils/cache/withCache.test.ts +162 -0
  61. package/src/utils/cache/withCache.ts +105 -0
  62. package/src/utils/inAppBrowser.ts +60 -0
  63. package/src/utils/index.ts +6 -4
  64. package/src/utils/sdkConfigStore.test.ts +405 -0
  65. package/src/utils/sdkConfigStore.ts +263 -0
  66. package/src/utils/sso.ts +3 -7
  67. package/dist/setupClient-CqTHGvVa.cjs +0 -13
  68. package/dist/setupClient-DTyvAPgh.js +0 -13
  69. package/dist/siweAuthenticate-BWmI2_TN.cjs +0 -1
  70. package/dist/siweAuthenticate-zczqxm0a.js +0 -1
  71. package/dist/trackEvent-CeLFVzZn.js +0 -1
  72. package/dist/trackEvent-Ew5r5zfI.cjs +0 -1
  73. package/src/utils/merchantId.test.ts +0 -653
  74. package/src/utils/merchantId.ts +0 -143
@@ -102,7 +102,7 @@ describe("createIFrameLifecycleManager", () => {
102
102
  iframeLifecycle: "connected" as const,
103
103
  };
104
104
 
105
- await manager.handleEvent(event);
105
+ manager.handleEvent(event);
106
106
 
107
107
  await expect(manager.isConnected).resolves.toBe(true);
108
108
  });
@@ -126,7 +126,7 @@ describe("createIFrameLifecycleManager", () => {
126
126
  data: { backup },
127
127
  };
128
128
 
129
- await manager.handleEvent(event);
129
+ manager.handleEvent(event);
130
130
 
131
131
  expect(localStorage.getItem("frak-backup-key")).toBe(backup);
132
132
  });
@@ -150,7 +150,7 @@ describe("createIFrameLifecycleManager", () => {
150
150
  data: {},
151
151
  };
152
152
 
153
- await manager.handleEvent(event);
153
+ manager.handleEvent(event);
154
154
 
155
155
  expect(localStorage.getItem("frak-backup-key")).toBeNull();
156
156
  });
@@ -173,7 +173,7 @@ describe("createIFrameLifecycleManager", () => {
173
173
  iframeLifecycle: "remove-backup" as const,
174
174
  };
175
175
 
176
- await manager.handleEvent(event);
176
+ manager.handleEvent(event);
177
177
 
178
178
  expect(localStorage.getItem("frak-backup-key")).toBeNull();
179
179
  });
@@ -198,7 +198,7 @@ describe("createIFrameLifecycleManager", () => {
198
198
  iframeLifecycle: "show" as const,
199
199
  };
200
200
 
201
- await manager.handleEvent(event);
201
+ manager.handleEvent(event);
202
202
 
203
203
  expect(changeIframeVisibility).toHaveBeenCalledWith({
204
204
  iframe: mockIframe,
@@ -224,7 +224,7 @@ describe("createIFrameLifecycleManager", () => {
224
224
  iframeLifecycle: "hide" as const,
225
225
  };
226
226
 
227
- await manager.handleEvent(event);
227
+ manager.handleEvent(event);
228
228
 
229
229
  expect(changeIframeVisibility).toHaveBeenCalledWith({
230
230
  iframe: mockIframe,
@@ -233,86 +233,6 @@ describe("createIFrameLifecycleManager", () => {
233
233
  });
234
234
  });
235
235
 
236
- describe("handshake event", () => {
237
- test("should post handshake-response with token to iframe origin", async () => {
238
- const { createIFrameLifecycleManager } = await import(
239
- "./iframeLifecycleManager"
240
- );
241
-
242
- const mockPostMessage = vi.fn();
243
- const mockIframe = {
244
- src: "https://wallet.frak.id/listener",
245
- contentWindow: {
246
- postMessage: mockPostMessage,
247
- },
248
- } as any;
249
-
250
- const manager = createIFrameLifecycleManager({
251
- iframe: mockIframe,
252
- targetOrigin: WALLET_ORIGIN,
253
- });
254
-
255
- const event = {
256
- iframeLifecycle: "handshake" as const,
257
- data: { token: "handshake-token-123" },
258
- };
259
-
260
- await manager.handleEvent(event);
261
-
262
- expect(mockPostMessage).toHaveBeenCalledWith(
263
- {
264
- clientLifecycle: "handshake-response",
265
- data: {
266
- token: "handshake-token-123",
267
- currentUrl: "https://test.com",
268
- clientId: "mock-client-id",
269
- },
270
- },
271
- "https://wallet.frak.id"
272
- );
273
- });
274
-
275
- test("should include current URL in handshake response", async () => {
276
- const { createIFrameLifecycleManager } = await import(
277
- "./iframeLifecycleManager"
278
- );
279
-
280
- Object.defineProperty(window, "location", {
281
- value: { href: "https://example.com/page?param=value" },
282
- writable: true,
283
- });
284
-
285
- const mockPostMessage = vi.fn();
286
- const mockIframe = {
287
- src: "https://wallet.frak.id/listener",
288
- contentWindow: {
289
- postMessage: mockPostMessage,
290
- },
291
- } as any;
292
-
293
- const manager = createIFrameLifecycleManager({
294
- iframe: mockIframe,
295
- targetOrigin: WALLET_ORIGIN,
296
- });
297
-
298
- const event = {
299
- iframeLifecycle: "handshake" as const,
300
- data: { token: "token" },
301
- };
302
-
303
- await manager.handleEvent(event);
304
-
305
- expect(mockPostMessage).toHaveBeenCalledWith(
306
- expect.objectContaining({
307
- data: expect.objectContaining({
308
- currentUrl: "https://example.com/page?param=value",
309
- }),
310
- }),
311
- "https://wallet.frak.id"
312
- );
313
- });
314
- });
315
-
316
236
  describe("redirect event", () => {
317
237
  test("should redirect with appended current URL for HTTP URLs", async () => {
318
238
  const { createIFrameLifecycleManager } = await import(
@@ -339,7 +259,7 @@ describe("createIFrameLifecycleManager", () => {
339
259
  },
340
260
  };
341
261
 
342
- await manager.handleEvent(event);
262
+ manager.handleEvent(event);
343
263
 
344
264
  expect(window.location.href).toBe(
345
265
  "https://redirect.com/?u=https%3A%2F%2Foriginal.com"
@@ -371,7 +291,7 @@ describe("createIFrameLifecycleManager", () => {
371
291
  },
372
292
  };
373
293
 
374
- await manager.handleEvent(event);
294
+ manager.handleEvent(event);
375
295
 
376
296
  expect(window.location.href).toBe("https://redirect.com/path");
377
297
  });
@@ -405,7 +325,7 @@ describe("createIFrameLifecycleManager", () => {
405
325
  },
406
326
  };
407
327
 
408
- await manager.handleEvent(event);
328
+ manager.handleEvent(event);
409
329
 
410
330
  expect(triggerDeepLinkWithFallback).toHaveBeenCalledWith(
411
331
  "frakwallet://wallet",
@@ -450,7 +370,7 @@ describe("createIFrameLifecycleManager", () => {
450
370
  },
451
371
  };
452
372
 
453
- await manager.handleEvent(event);
373
+ manager.handleEvent(event);
454
374
 
455
375
  // Extract the onFallback callback from the mock call
456
376
  const callArgs = (triggerDeepLinkWithFallback as any).mock.calls[0];
@@ -499,7 +419,7 @@ describe("createIFrameLifecycleManager", () => {
499
419
  },
500
420
  };
501
421
 
502
- await manager.handleEvent(event);
422
+ manager.handleEvent(event);
503
423
 
504
424
  // Should NOT call fallback detection
505
425
  expect(triggerDeepLinkWithFallback).not.toHaveBeenCalled();
@@ -525,7 +445,7 @@ describe("createIFrameLifecycleManager", () => {
525
445
  } as any;
526
446
 
527
447
  // Should not throw
528
- await expect(manager.handleEvent(event)).resolves.toBeUndefined();
448
+ expect(manager.handleEvent(event)).toBeUndefined();
529
449
  });
530
450
 
531
451
  test("should only process events with iframeLifecycle", async () => {
@@ -543,13 +463,13 @@ describe("createIFrameLifecycleManager", () => {
543
463
  });
544
464
 
545
465
  // Event without iframeLifecycle
546
- await manager.handleEvent({ randomEvent: "show" } as any);
466
+ manager.handleEvent({ randomEvent: "show" } as any);
547
467
 
548
468
  // changeIframeVisibility should not be called
549
469
  expect(changeIframeVisibility).not.toHaveBeenCalled();
550
470
 
551
471
  // Event with iframeLifecycle
552
- await manager.handleEvent({ iframeLifecycle: "show" as const });
472
+ manager.handleEvent({ iframeLifecycle: "show" as const });
553
473
 
554
474
  // Now it should be called
555
475
  expect(changeIframeVisibility).toHaveBeenCalled();
@@ -1,6 +1,5 @@
1
1
  import { Deferred } from "@frak-labs/frame-connector";
2
2
  import type { FrakLifecycleEvent } from "../../types";
3
- import { getClientId } from "../../utils/clientId";
4
3
  import { BACKUP_KEY } from "../../utils/constants";
5
4
  import {
6
5
  isFrakDeepLink,
@@ -33,7 +32,7 @@ const isIOSInAppBrowser = (() => {
33
32
  /** @ignore */
34
33
  export type IframeLifecycleManager = {
35
34
  isConnected: Promise<boolean>;
36
- handleEvent: (messageEvent: FrakLifecycleEvent) => Promise<void>;
35
+ handleEvent: (messageEvent: FrakLifecycleEvent) => void;
37
36
  };
38
37
 
39
38
  /**
@@ -47,42 +46,6 @@ function handleBackup(backup: string | undefined): void {
47
46
  }
48
47
  }
49
48
 
50
- /**
51
- * Handle handshake with iframe — sends client metadata so the listener can resolve the correct merchant
52
- * @param iframe - The iframe element to post the handshake response to
53
- * @param token - The handshake token received from the iframe
54
- * @param targetOrigin - The target origin for postMessage security
55
- * @param configDomain - Optional override domain for merchant resolution in tunneled/proxied environments
56
- */
57
- function handleHandshake(
58
- iframe: HTMLIFrameElement,
59
- token: string,
60
- targetOrigin: string,
61
- configDomain?: string
62
- ): void {
63
- const url = new URL(window.location.href);
64
- const pendingMergeToken = url.searchParams.get("fmt") ?? undefined;
65
-
66
- iframe.contentWindow?.postMessage(
67
- {
68
- clientLifecycle: "handshake-response",
69
- data: {
70
- token,
71
- currentUrl: window.location.href,
72
- pendingMergeToken,
73
- configDomain,
74
- clientId: getClientId(),
75
- },
76
- },
77
- targetOrigin
78
- );
79
-
80
- if (pendingMergeToken) {
81
- url.searchParams.delete("fmt");
82
- window.history.replaceState({}, "", url.toString());
83
- }
84
- }
85
-
86
49
  /**
87
50
  * Compute final redirect URL with parameter substitution
88
51
  */
@@ -137,8 +100,18 @@ function handleRedirect(
137
100
  iframe: HTMLIFrameElement,
138
101
  baseRedirectUrl: string,
139
102
  targetOrigin: string,
140
- mergeToken?: string
103
+ mergeToken?: string,
104
+ openInNewTab?: boolean
141
105
  ): void {
106
+ // If requested, open in a new tab instead of navigating the current page.
107
+ // This preserves the merchant page while triggering universal links.
108
+ // Requires the iframe postMessage to include user activation delegation.
109
+ if (openInNewTab) {
110
+ const finalUrl = computeRedirectUrl(baseRedirectUrl, mergeToken);
111
+ window.open(finalUrl, "_blank");
112
+ return;
113
+ }
114
+
142
115
  if (isFrakDeepLink(baseRedirectUrl)) {
143
116
  const finalUrl = computeRedirectUrl(baseRedirectUrl, mergeToken);
144
117
  triggerDeepLinkWithFallback(finalUrl, {
@@ -167,23 +140,20 @@ function handleRedirect(
167
140
  * @param args
168
141
  * @param args.iframe - The iframe element used for wallet communication
169
142
  * @param args.targetOrigin - The wallet URL origin for postMessage security
170
- * @param args.configDomain - Optional domain override forwarded during handshake for tunneled/proxied environments
171
143
  * @ignore
172
144
  */
173
145
  export function createIFrameLifecycleManager({
174
146
  iframe,
175
147
  targetOrigin,
176
- configDomain,
177
148
  }: {
178
149
  iframe: HTMLIFrameElement;
179
150
  targetOrigin: string;
180
- configDomain?: string;
181
151
  }): IframeLifecycleManager {
182
152
  // Create the isConnected listener
183
153
  const isConnectedDeferred = new Deferred<boolean>();
184
154
 
185
155
  // Build the handler itself
186
- const handler = async (messageEvent: FrakLifecycleEvent) => {
156
+ const handler = (messageEvent: FrakLifecycleEvent) => {
187
157
  if (!("iframeLifecycle" in messageEvent)) return;
188
158
 
189
159
  const { iframeLifecycle: event, data } = messageEvent;
@@ -206,17 +176,14 @@ export function createIFrameLifecycleManager({
206
176
  case "hide":
207
177
  changeIframeVisibility({ iframe, isVisible: event === "show" });
208
178
  break;
209
- // Handshake handling
210
- case "handshake":
211
- handleHandshake(iframe, data.token, targetOrigin, configDomain);
212
- break;
213
179
  // Redirect handling
214
180
  case "redirect":
215
181
  handleRedirect(
216
182
  iframe,
217
183
  data.baseRedirectUrl,
218
184
  targetOrigin,
219
- data.mergeToken
185
+ data.mergeToken,
186
+ data.openInNewTab
220
187
  );
221
188
  break;
222
189
  }
package/src/index.ts CHANGED
@@ -19,6 +19,9 @@ export type {
19
19
  DisplayEmbeddedWalletParamsType,
20
20
  DisplayEmbeddedWalletResultType,
21
21
  DisplayModalParamsType,
22
+ // RPC Sharing page
23
+ DisplaySharingPageParamsType,
24
+ DisplaySharingPageResultType,
22
25
  EmbeddedViewActionReferred,
23
26
  EmbeddedViewActionSharing,
24
27
  EstimatedReward,
@@ -47,6 +50,7 @@ export type {
47
50
  LoggedInEmbeddedView,
48
51
  LoggedOutEmbeddedView,
49
52
  LoginModalStepType,
53
+ MerchantConfigResponse,
50
54
  ModalRpcMetadata,
51
55
  ModalRpcStepsInput,
52
56
  ModalRpcStepsResultType,
@@ -58,12 +62,16 @@ export type {
58
62
  OpenSsoReturnType,
59
63
  PrepareSsoParamsType,
60
64
  PrepareSsoReturnType,
65
+ ResolvedPlacement,
66
+ ResolvedSdkConfig,
61
67
  RewardTier,
68
+ SdkResolvedConfig,
62
69
  // RPC Interaction
63
70
  SendInteractionParamsType,
64
71
  SendTransactionModalStepType,
65
72
  SendTransactionReturnType,
66
73
  SendTransactionTxType,
74
+ SharingPageProduct,
67
75
  SiweAuthenticateModalStepType,
68
76
  SiweAuthenticateReturnType,
69
77
  SiweAuthenticationParams,
@@ -72,8 +80,9 @@ export type {
72
80
  // Tracking
73
81
  TrackArrivalParams,
74
82
  TrackArrivalResult,
75
- UtmParams,
76
83
  // Rpc
84
+ UserReferralStatusType,
85
+ UtmParams,
77
86
  WalletStatusReturnType,
78
87
  } from "./types";
79
88
  export { isV1Context, isV2Context } from "./types";
@@ -84,7 +93,7 @@ export {
84
93
  base64urlEncode,
85
94
  baseIframeProps,
86
95
  type CompressedSsoData,
87
- clearMerchantIdCache,
96
+ clearAllCache,
88
97
  compressJsonToB64,
89
98
  createIframe,
90
99
  DEEP_LINK_SCHEME,
@@ -93,20 +102,24 @@ export {
93
102
  FrakContextManager,
94
103
  type FrakEvent,
95
104
  type FullSsoParams,
96
- fetchMerchantId,
97
105
  findIframeInOpener,
98
106
  formatAmount,
99
107
  generateSsoUrl,
100
108
  getBackendUrl,
109
+ getCache,
101
110
  getClientId,
102
111
  getCurrencyAmountKey,
103
112
  getSupportedCurrency,
104
113
  getSupportedLocale,
105
114
  isChromiumAndroid,
106
115
  isFrakDeepLink,
107
- resolveMerchantId,
116
+ isInAppBrowser,
117
+ isIOS,
118
+ redirectToExternalBrowser,
119
+ sdkConfigStore,
108
120
  toAndroidIntentUrl,
109
121
  trackEvent,
110
122
  triggerDeepLinkWithFallback,
123
+ withCache,
111
124
  } from "./utils";
112
125
  export { computeLegacyProductId } from "./utils/computeLegacyProductId";
@@ -27,7 +27,7 @@ export type FrakWalletSdkConfig = {
27
27
  /**
28
28
  * Your application name (will be displayed in a few modals and in SSO)
29
29
  */
30
- name: string;
30
+ name?: string;
31
31
  /**
32
32
  * Your merchant ID from the Frak dashboard (UUID format)
33
33
  * Used for referral tracking and analytics
@@ -71,6 +71,13 @@ export type FrakWalletSdkConfig = {
71
71
  * @defaultValue window.location.host
72
72
  */
73
73
  domain?: string;
74
+ /**
75
+ * Wait for backend config before rendering components.
76
+ * When true (default), components show a spinner until backend config is resolved.
77
+ * When false, components render immediately with SDK static config / HTML attributes.
78
+ * @defaultValue true
79
+ */
80
+ waitForBackendConfig?: boolean;
74
81
  };
75
82
 
76
83
  /**
@@ -111,7 +118,7 @@ export type I18nConfig =
111
118
  | LocalizedI18nConfig;
112
119
 
113
120
  /**
114
- * A localized i18n config
121
+ * A localized i18n config (inline objects only — URL-based i18n removed)
115
122
  * @category Config
116
123
  */
117
- export type LocalizedI18nConfig = `${string}.css` | { [key: string]: string };
124
+ export type LocalizedI18nConfig = { [key: string]: string };
@@ -17,11 +17,16 @@ export type {
17
17
  // Utils
18
18
  export type { FrakContext, FrakContextV1, FrakContextV2 } from "./context";
19
19
  export { isV1Context, isV2Context } from "./context";
20
-
21
20
  export type {
22
21
  ClientLifecycleEvent,
23
22
  IFrameLifecycleEvent,
24
23
  } from "./lifecycle";
24
+ export type {
25
+ MerchantConfigResponse,
26
+ ResolvedPlacement,
27
+ ResolvedSdkConfig,
28
+ SdkResolvedConfig,
29
+ } from "./resolvedConfig";
25
30
  export type { IFrameRpcSchema } from "./rpc";
26
31
  // Modal related
27
32
  export type {
@@ -31,6 +36,12 @@ export type {
31
36
  ModalRpcStepsResultType,
32
37
  ModalStepTypes,
33
38
  } from "./rpc/displayModal";
39
+ // Sharing page related
40
+ export type {
41
+ DisplaySharingPageParamsType,
42
+ DisplaySharingPageResultType,
43
+ SharingPageProduct,
44
+ } from "./rpc/displaySharingPage";
34
45
  export type {
35
46
  DisplayEmbeddedWalletParamsType,
36
47
  DisplayEmbeddedWalletResultType,
@@ -65,6 +76,7 @@ export type {
65
76
  PrepareSsoReturnType,
66
77
  SsoMetadata,
67
78
  } from "./rpc/sso";
79
+ export type { UserReferralStatusType } from "./rpc/userReferralStatus";
68
80
  export type { WalletStatusReturnType } from "./rpc/walletStatus";
69
81
  // Tracking
70
82
  export type {
@@ -1,4 +1,5 @@
1
1
  import type { I18nConfig } from "../config";
2
+ import type { ResolvedSdkConfig } from "../resolvedConfig";
2
3
 
3
4
  /**
4
5
  * Event related to the iframe lifecycle
@@ -9,9 +10,9 @@ export type ClientLifecycleEvent =
9
10
  | CustomI18nEvent
10
11
  | RestoreBackupEvent
11
12
  | HearbeatEvent
12
- | HandshakeResponse
13
13
  | SsoRedirectCompleteEvent
14
- | DeepLinkFailedEvent;
14
+ | DeepLinkFailedEvent
15
+ | ResolvedConfigEvent;
15
16
 
16
17
  type CustomCssEvent = {
17
18
  clientLifecycle: "modal-css";
@@ -33,31 +34,6 @@ type HearbeatEvent = {
33
34
  data?: never;
34
35
  };
35
36
 
36
- type HandshakeResponse = {
37
- clientLifecycle: "handshake-response";
38
- data: {
39
- token: string;
40
- currentUrl: string;
41
- /**
42
- * Pending merge token extracted from URL (?fmt= parameter)
43
- * When present, listener should execute identity merge in background
44
- * URL is cleaned after handshake response is sent
45
- */
46
- pendingMergeToken?: string;
47
- /**
48
- * Client ID for identity tracking (belt & suspenders fallback)
49
- * Primary delivery is via iframe URL query param; handshake is backup for SSR
50
- */
51
- clientId?: string;
52
- /**
53
- * Explicit domain from SDK config (FrakWalletSdkConfig.domain)
54
- * When present, listener should prefer this over URL-derived domain
55
- * for merchant resolution (handles proxied/tunneled environments)
56
- */
57
- configDomain?: string;
58
- };
59
- };
60
-
61
37
  type SsoRedirectCompleteEvent = {
62
38
  clientLifecycle: "sso-redirect-complete";
63
39
  data: { compressed: string };
@@ -67,3 +43,22 @@ type DeepLinkFailedEvent = {
67
43
  clientLifecycle: "deep-link-failed";
68
44
  data: { originalUrl: string };
69
45
  };
46
+
47
+ type ResolvedConfigEvent = {
48
+ clientLifecycle: "resolved-config";
49
+ data: {
50
+ merchantId: string;
51
+ /** The domain the backend resolved this config for */
52
+ domain: string;
53
+ /** All domains registered for this merchant (for domain proof) */
54
+ allowedDomains: string[];
55
+ /** Full URL of the parent page (for interaction tracking) */
56
+ sourceUrl: string;
57
+ /**
58
+ * Pending merge token extracted from URL (?fmt= parameter).
59
+ * When present, listener should execute identity merge in background.
60
+ */
61
+ pendingMergeToken?: string;
62
+ sdkConfig?: ResolvedSdkConfig;
63
+ };
64
+ };
@@ -8,7 +8,6 @@ export type IFrameLifecycleEvent =
8
8
  data?: never;
9
9
  }
10
10
  | DoBackupEvent
11
- | HandshakeRequestEvent
12
11
  | RedirectRequestEvent;
13
12
 
14
13
  type DoBackupEvent = {
@@ -16,13 +15,6 @@ type DoBackupEvent = {
16
15
  data: { backup?: string };
17
16
  };
18
17
 
19
- type HandshakeRequestEvent = {
20
- iframeLifecycle: "handshake";
21
- data: {
22
- token: string;
23
- };
24
- };
25
-
26
18
  type RedirectRequestEvent = {
27
19
  iframeLifecycle: "redirect";
28
20
  data: {
@@ -37,5 +29,12 @@ type RedirectRequestEvent = {
37
29
  * Used when redirecting out of social browsers to preserve identity across contexts
38
30
  */
39
31
  mergeToken?: string;
32
+ /**
33
+ * When true, open the URL in a new tab via window.open(_blank)
34
+ * instead of navigating the current page.
35
+ * Requires the postMessage to include user activation delegation
36
+ * (includeUserActivation: true) so Safari allows the popup.
37
+ */
38
+ openInNewTab?: boolean;
40
39
  };
41
40
  };