@frak-labs/core-sdk 0.1.1-beta.d96bc28d → 0.1.1-beta.df5fa6b3

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 (46) hide show
  1. package/README.md +58 -0
  2. package/cdn/bundle.js +3 -3
  3. package/dist/actions.cjs +1 -1
  4. package/dist/actions.d.cts +1 -1
  5. package/dist/actions.d.ts +1 -1
  6. package/dist/actions.js +1 -1
  7. package/dist/bundle.cjs +1 -1
  8. package/dist/bundle.d.cts +3 -3
  9. package/dist/bundle.d.ts +3 -3
  10. package/dist/bundle.js +1 -1
  11. package/dist/{computeLegacyProductId-WbD1gXV9.d.ts → computeLegacyProductId-CSSiQO4V.d.ts} +28 -15
  12. package/dist/{computeLegacyProductId-CscYhyUi.d.cts → computeLegacyProductId-fl_Sx8v5.d.cts} +28 -15
  13. package/dist/index.cjs +1 -1
  14. package/dist/index.d.cts +2 -2
  15. package/dist/index.d.ts +2 -2
  16. package/dist/index.js +1 -1
  17. package/dist/setupClient--zfx2pFM.cjs +13 -0
  18. package/dist/setupClient-CFQDaGKh.js +13 -0
  19. package/dist/siweAuthenticate-BKSiU7Ej.js +1 -0
  20. package/dist/{siweAuthenticate-udoruuy9.d.ts → siweAuthenticate-BOqz9Uww.d.ts} +46 -2
  21. package/dist/siweAuthenticate-CVMVEe3M.cjs +1 -0
  22. package/dist/{siweAuthenticate-CR4Dpji6.d.cts → siweAuthenticate-DfiQdngJ.d.cts} +46 -2
  23. package/dist/{trackEvent-YfUh4jrx.js → trackEvent-B0S5E6_h.js} +1 -1
  24. package/dist/{trackEvent-CGIryq5h.cjs → trackEvent-BbX2d3g_.cjs} +1 -1
  25. package/package.json +2 -2
  26. package/src/actions/displayEmbeddedWallet.ts +1 -0
  27. package/src/actions/getMerchantInformation.ts +7 -0
  28. package/src/actions/sendInteraction.ts +31 -0
  29. package/src/actions/trackPurchaseStatus.test.ts +354 -141
  30. package/src/actions/trackPurchaseStatus.ts +45 -11
  31. package/src/clients/createIFrameFrakClient.ts +2 -1
  32. package/src/clients/transports/iframeLifecycleManager.ts +58 -3
  33. package/src/index.ts +0 -1
  34. package/src/types/index.ts +0 -1
  35. package/src/utils/constants.ts +0 -5
  36. package/src/utils/deepLinkWithFallback.test.ts +2 -2
  37. package/src/utils/deepLinkWithFallback.ts +9 -3
  38. package/src/utils/formatAmount.ts +6 -0
  39. package/src/utils/merchantId.test.ts +90 -1
  40. package/src/utils/merchantId.ts +22 -1
  41. package/src/utils/sso.ts +2 -1
  42. package/src/utils/trackEvent.ts +10 -0
  43. package/dist/setupClient-BjIbK6XJ.cjs +0 -13
  44. package/dist/setupClient-D_HId3e2.js +0 -13
  45. package/dist/siweAuthenticate-B_Z2OZmj.cjs +0 -1
  46. package/dist/siweAuthenticate-CQ4OfPuA.js +0 -1
@@ -1,4 +1,6 @@
1
1
  import { getBackendUrl } from "../utils/backendUrl";
2
+ import { getClientId } from "../utils/clientId";
3
+ import { fetchMerchantId } from "../utils/merchantId";
2
4
 
3
5
  /**
4
6
  * Function used to track the status of a purchase
@@ -7,6 +9,7 @@ import { getBackendUrl } from "../utils/backendUrl";
7
9
  * @param args.customerId - The customer id that made the purchase (on your side)
8
10
  * @param args.orderId - The order id of the purchase (on your side)
9
11
  * @param args.token - The token of the purchase
12
+ * @param args.merchantId - Optional explicit merchant id to use for the tracking request
10
13
  *
11
14
  * @description This function will send a request to the backend to listen for the purchase status.
12
15
  *
@@ -16,41 +19,72 @@ import { getBackendUrl } from "../utils/backendUrl";
16
19
  * customerId: checkout.order.customer.id,
17
20
  * orderId: checkout.order.id,
18
21
  * token: checkout.token,
22
+ * merchantId: "your-merchant-id",
19
23
  * };
20
24
  *
21
25
  * await trackPurchaseStatus(payload);
22
26
  * }
23
27
  *
24
28
  * @remarks
25
- * - The `trackPurchaseStatus` function requires the `frak-wallet-interaction-token` stored in the session storage to authenticate the request.
26
- * - This function will print a warning if used in a non-browser environment or if the wallet interaction token is not available.
29
+ * - Merchant id is resolved in this order: explicit `args.merchantId`, `frak-merchant-id` from session storage, then `fetchMerchantId()`.
30
+ * - This function supports anonymous users and will use the `x-frak-client-id` header when available.
31
+ * - At least one identity source must exist (`frak-wallet-interaction-token` or `x-frak-client-id`), otherwise the tracking request is skipped.
32
+ * - This function will print a warning if used in a non-browser environment or if no identity / merchant id can be resolved.
27
33
  */
28
34
  export async function trackPurchaseStatus(args: {
29
35
  customerId: string | number;
30
36
  orderId: string | number;
31
37
  token: string;
38
+ merchantId?: string;
32
39
  }) {
33
40
  if (typeof window === "undefined") {
34
41
  console.warn("[Frak] No window found, can't track purchase");
35
42
  return;
36
43
  }
44
+
37
45
  const interactionToken = window.sessionStorage.getItem(
38
46
  "frak-wallet-interaction-token"
39
47
  );
40
- if (!interactionToken) {
41
- console.warn("[Frak] No frak session found, skipping purchase check");
48
+
49
+ const clientId = getClientId();
50
+ if (!interactionToken && !clientId) {
51
+ console.warn("[Frak] No identity found, skipping purchase check");
52
+ return;
53
+ }
54
+
55
+ const merchantIdFromStorage =
56
+ window.sessionStorage.getItem("frak-merchant-id");
57
+ const merchantId =
58
+ args.merchantId ?? merchantIdFromStorage ?? (await fetchMerchantId());
59
+
60
+ if (!merchantId) {
61
+ console.warn("[Frak] No merchant id found, skipping purchase check");
42
62
  return;
43
63
  }
44
64
 
65
+ const headers: Record<string, string> = {
66
+ Accept: "application/json",
67
+ "Content-Type": "application/json",
68
+ };
69
+
70
+ if (interactionToken) {
71
+ headers["x-wallet-sdk-auth"] = interactionToken;
72
+ }
73
+
74
+ if (clientId) {
75
+ headers["x-frak-client-id"] = clientId;
76
+ }
77
+
45
78
  // Submit the listening request
46
79
  const backendUrl = getBackendUrl();
47
- await fetch(`${backendUrl}/interactions/listenForPurchase`, {
80
+ await fetch(`${backendUrl}/user/track/purchase`, {
48
81
  method: "POST",
49
- headers: {
50
- Accept: "application/json",
51
- "Content-Type": "application/json",
52
- "x-wallet-sdk-auth": interactionToken,
53
- },
54
- body: JSON.stringify(args),
82
+ headers,
83
+ body: JSON.stringify({
84
+ customerId: args.customerId,
85
+ orderId: args.orderId,
86
+ token: args.token,
87
+ merchantId,
88
+ }),
55
89
  });
56
90
  }
@@ -23,7 +23,8 @@ type SdkRpcClient = RpcClient<IFrameRpcSchema, FrakLifecycleEvent>;
23
23
  /**
24
24
  * Create a new iframe Frak client
25
25
  * @param args
26
- * @param args.config - The configuration to use for the Frak Wallet SDK
26
+ * @param args.config - The configuration to use for the Frak Wallet SDK.
27
+ * When `config.domain` is set, it is forwarded to the iframe handshake so the listener resolves the correct merchant in tunneled/proxied environments (e.g. Shopify dev with Cloudflare tunnel).
27
28
  * @param args.iframe - The iframe to use for the communication
28
29
  * @returns The created Frak Client
29
30
  *
@@ -8,6 +8,28 @@ import {
8
8
  } from "../../utils/deepLinkWithFallback";
9
9
  import { changeIframeVisibility } from "../../utils/iframeHelper";
10
10
 
11
+ /**
12
+ * Detect iOS in-app browsers (Instagram, Facebook) where server-side
13
+ * 302 redirects to custom URL schemes (x-safari-https://) are silently
14
+ * swallowed by WKWebView. Direct window.location.href assignment works.
15
+ */
16
+ const isIOSInAppBrowser = (() => {
17
+ if (typeof navigator === "undefined") return false;
18
+ const ua = navigator.userAgent;
19
+ // Standard iOS or iPadOS 13+ (reports as Macintosh with touch)
20
+ const isIOS =
21
+ /iPhone|iPad|iPod/i.test(ua) ||
22
+ (/Macintosh/i.test(ua) && navigator.maxTouchPoints > 1);
23
+ if (!isIOS) return false;
24
+ const lower = ua.toLowerCase();
25
+ return (
26
+ lower.includes("instagram") ||
27
+ lower.includes("fban") ||
28
+ lower.includes("fbav") ||
29
+ lower.includes("facebook")
30
+ );
31
+ })();
32
+
11
33
  /** @ignore */
12
34
  export type IframeLifecycleManager = {
13
35
  isConnected: Promise<boolean>;
@@ -26,7 +48,11 @@ function handleBackup(backup: string | undefined): void {
26
48
  }
27
49
 
28
50
  /**
29
- * Handle handshake with iframe
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
30
56
  */
31
57
  function handleHandshake(
32
58
  iframe: HTMLIFrameElement,
@@ -83,6 +109,27 @@ function computeRedirectUrl(
83
109
  }
84
110
  }
85
111
 
112
+ /**
113
+ * Redirect current page to Safari via x-safari-https:// scheme.
114
+ * Used on iOS in-app browsers where backend 302 → custom scheme fails.
115
+ */
116
+ function redirectToSafari(mergeToken?: string) {
117
+ const url = new URL(window.location.href);
118
+ if (mergeToken) {
119
+ url.searchParams.set("fmt", mergeToken);
120
+ }
121
+ const scheme =
122
+ url.protocol === "http:" ? "x-safari-http" : "x-safari-https";
123
+ window.location.href = `${scheme}://${url.host}${url.pathname}${url.search}${url.hash}`;
124
+ }
125
+
126
+ /**
127
+ * Check if this is a social/in-app-browser escape redirect (contains /common/social)
128
+ */
129
+ function isSocialRedirect(url: string): boolean {
130
+ return url.includes("/common/social");
131
+ }
132
+
86
133
  /**
87
134
  * Handle redirect with deep link fallback
88
135
  */
@@ -92,9 +139,8 @@ function handleRedirect(
92
139
  targetOrigin: string,
93
140
  mergeToken?: string
94
141
  ): void {
95
- const finalUrl = computeRedirectUrl(baseRedirectUrl, mergeToken);
96
-
97
142
  if (isFrakDeepLink(baseRedirectUrl)) {
143
+ const finalUrl = computeRedirectUrl(baseRedirectUrl, mergeToken);
98
144
  triggerDeepLinkWithFallback(finalUrl, {
99
145
  onFallback: () => {
100
146
  iframe.contentWindow?.postMessage(
@@ -106,13 +152,22 @@ function handleRedirect(
106
152
  );
107
153
  },
108
154
  });
155
+ } else if (isIOSInAppBrowser && isSocialRedirect(baseRedirectUrl)) {
156
+ // iOS WKWebView silently swallows 302 redirects to custom URL
157
+ // schemes — bypass the server redirect entirely
158
+ redirectToSafari(mergeToken);
109
159
  } else {
160
+ const finalUrl = computeRedirectUrl(baseRedirectUrl, mergeToken);
110
161
  window.location.href = finalUrl;
111
162
  }
112
163
  }
113
164
 
114
165
  /**
115
166
  * Create a new iframe lifecycle handler
167
+ * @param args
168
+ * @param args.iframe - The iframe element used for wallet communication
169
+ * @param args.targetOrigin - The wallet URL origin for postMessage security
170
+ * @param args.configDomain - Optional domain override forwarded during handshake for tunneled/proxied environments
116
171
  * @ignore
117
172
  */
118
173
  export function createIFrameLifecycleManager({
package/src/index.ts CHANGED
@@ -68,7 +68,6 @@ export type {
68
68
  SsoMetadata,
69
69
  TokenAmountType,
70
70
  // Tracking
71
- TrackArrivalInternalParams,
72
71
  TrackArrivalParams,
73
72
  TrackArrivalResult,
74
73
  UtmParams,
@@ -67,7 +67,6 @@ export type {
67
67
  export type { WalletStatusReturnType } from "./rpc/walletStatus";
68
68
  // Tracking
69
69
  export type {
70
- TrackArrivalInternalParams,
71
70
  TrackArrivalParams,
72
71
  TrackArrivalResult,
73
72
  UtmParams,
@@ -7,8 +7,3 @@ export const BACKUP_KEY = "nexus-wallet-backup";
7
7
  * Deep link scheme for Frak Wallet mobile app
8
8
  */
9
9
  export const DEEP_LINK_SCHEME = "frakwallet://";
10
-
11
- /**
12
- * Android package name for Frak Wallet (used in intent:// URLs)
13
- */
14
- export const ANDROID_PACKAGE = "id.frak.wallet";
@@ -182,7 +182,7 @@ describe("deepLinkWithFallback", () => {
182
182
  triggerDeepLinkWithFallback("frakwallet://wallet");
183
183
 
184
184
  expect(window.location.href).toBe(
185
- "intent://wallet#Intent;scheme=frakwallet;package=id.frak.wallet;end"
185
+ "intent://wallet#Intent;scheme=frakwallet;end"
186
186
  );
187
187
  });
188
188
 
@@ -194,7 +194,7 @@ describe("deepLinkWithFallback", () => {
194
194
  );
195
195
 
196
196
  expect(window.location.href).toBe(
197
- "intent://pair?id=abc-123&mode=embedded#Intent;scheme=frakwallet;package=id.frak.wallet;end"
197
+ "intent://pair?id=abc-123&mode=embedded#Intent;scheme=frakwallet;end"
198
198
  );
199
199
  });
200
200
 
@@ -1,4 +1,4 @@
1
- import { ANDROID_PACKAGE, DEEP_LINK_SCHEME } from "./constants";
1
+ import { DEEP_LINK_SCHEME } from "./constants";
2
2
 
3
3
  /**
4
4
  * Options for deep link with fallback
@@ -29,12 +29,18 @@ export function isChromiumAndroid(): boolean {
29
29
  * Intent URLs let Chromium browsers open the app directly without
30
30
  * showing the "Continue to app?" confirmation bar.
31
31
  *
32
- * Format: intent://path#Intent;scheme=frakwallet;package=id.frak.wallet;end
32
+ * Note: We intentionally omit the `package` parameter. Including it
33
+ * causes Chrome to redirect to the Play Store when the app is not
34
+ * installed, which breaks the visibility-based fallback detection.
35
+ * Without `package`, Chrome simply does nothing when the app is
36
+ * missing, allowing the fallback mechanism to fire correctly.
37
+ *
38
+ * Format: intent://path#Intent;scheme=frakwallet;end
33
39
  */
34
40
  export function toAndroidIntentUrl(deepLink: string): string {
35
41
  // Extract everything after "frakwallet://"
36
42
  const path = deepLink.slice(DEEP_LINK_SCHEME.length);
37
- return `intent://${path}#Intent;scheme=frakwallet;package=${ANDROID_PACKAGE};end`;
43
+ return `intent://${path}#Intent;scheme=frakwallet;end`;
38
44
  }
39
45
 
40
46
  /**
@@ -2,6 +2,12 @@ import type { Currency } from "../types";
2
2
  import { getSupportedCurrency } from "./getSupportedCurrency";
3
3
  import { getSupportedLocale } from "./getSupportedLocale";
4
4
 
5
+ /**
6
+ * Format a numeric amount as a localized currency string
7
+ * @param amount - The raw numeric amount to format
8
+ * @param currency - Optional currency config; defaults to EUR/fr-FR when omitted
9
+ * @returns Localized currency string (e.g. "1 500 €", "$1,500")
10
+ */
5
11
  export function formatAmount(amount: number, currency?: Currency) {
6
12
  // Get the supported locale (e.g. "fr-FR")
7
13
  const supportedLocale = getSupportedLocale(currency);
@@ -17,8 +17,9 @@ vi.mock("./backendUrl", () => ({
17
17
 
18
18
  describe("merchantId", () => {
19
19
  beforeEach(() => {
20
- // Clear cache before each test
20
+ // Clear cache before each test (also clears sessionStorage)
21
21
  clearMerchantIdCache();
22
+ window.sessionStorage.clear();
22
23
  // Clear all mocks
23
24
  vi.clearAllMocks();
24
25
  // Mock console methods to avoid noise in test output
@@ -263,6 +264,70 @@ describe("merchantId", () => {
263
264
  expect(result2).toBe("merchant-cached");
264
265
  expect(global.fetch).not.toHaveBeenCalled();
265
266
  });
267
+
268
+ it("should persist merchantId to sessionStorage after fetch", async () => {
269
+ const mockResponse = {
270
+ merchantId: "merchant-persisted",
271
+ name: "Test Merchant",
272
+ domain: "shop.example.com",
273
+ };
274
+
275
+ global.fetch = vi.fn().mockResolvedValueOnce({
276
+ ok: true,
277
+ json: async () => mockResponse,
278
+ });
279
+
280
+ await fetchMerchantId("shop.example.com");
281
+
282
+ expect(window.sessionStorage.getItem("frak-merchant-id")).toBe(
283
+ "merchant-persisted"
284
+ );
285
+ });
286
+
287
+ it("should restore merchantId from sessionStorage when in-memory cache is cleared", async () => {
288
+ const mockResponse = {
289
+ merchantId: "merchant-storage",
290
+ name: "Test Merchant",
291
+ domain: "shop.example.com",
292
+ };
293
+
294
+ global.fetch = vi.fn().mockResolvedValueOnce({
295
+ ok: true,
296
+ json: async () => mockResponse,
297
+ });
298
+
299
+ // First call populates both caches
300
+ const result1 = await fetchMerchantId("shop.example.com");
301
+ expect(result1).toBe("merchant-storage");
302
+ expect(global.fetch).toHaveBeenCalledTimes(1);
303
+
304
+ // Clear only in-memory cache (not sessionStorage)
305
+ vi.clearAllMocks();
306
+ global.fetch = vi.fn();
307
+
308
+ // Manually clear in-memory but keep sessionStorage
309
+ // We do this by calling the internal clear then restoring sessionStorage
310
+ const stored = window.sessionStorage.getItem("frak-merchant-id");
311
+ clearMerchantIdCache();
312
+ window.sessionStorage.setItem("frak-merchant-id", stored!);
313
+
314
+ // Second call should restore from sessionStorage without fetch
315
+ const result2 = await fetchMerchantId("shop.example.com");
316
+ expect(result2).toBe("merchant-storage");
317
+ expect(global.fetch).not.toHaveBeenCalled();
318
+ });
319
+
320
+ it("should not write to sessionStorage when fetch fails", async () => {
321
+ global.fetch = vi
322
+ .fn()
323
+ .mockRejectedValueOnce(new Error("Network error"));
324
+
325
+ await fetchMerchantId("shop.example.com");
326
+
327
+ expect(
328
+ window.sessionStorage.getItem("frak-merchant-id")
329
+ ).toBeNull();
330
+ });
266
331
  });
267
332
 
268
333
  describe("clearMerchantIdCache", () => {
@@ -324,6 +389,30 @@ describe("merchantId", () => {
324
389
  const result2 = await fetchMerchantId("shop2.example.com");
325
390
  expect(result2).toBe("merchant-second");
326
391
  });
392
+
393
+ it("should clear sessionStorage when clearing cache", async () => {
394
+ const mockResponse = {
395
+ merchantId: "merchant-session-clear",
396
+ name: "Test Merchant",
397
+ domain: "shop.example.com",
398
+ };
399
+
400
+ global.fetch = vi.fn().mockResolvedValueOnce({
401
+ ok: true,
402
+ json: async () => mockResponse,
403
+ });
404
+
405
+ await fetchMerchantId("shop.example.com");
406
+ expect(window.sessionStorage.getItem("frak-merchant-id")).toBe(
407
+ "merchant-session-clear"
408
+ );
409
+
410
+ clearMerchantIdCache();
411
+
412
+ expect(
413
+ window.sessionStorage.getItem("frak-merchant-id")
414
+ ).toBeNull();
415
+ });
327
416
  });
328
417
 
329
418
  describe("resolveMerchantId", () => {
@@ -4,6 +4,8 @@
4
4
 
5
5
  import { getBackendUrl } from "./backendUrl";
6
6
 
7
+ const MERCHANT_ID_STORAGE_KEY = "frak-merchant-id";
8
+
7
9
  /**
8
10
  * Response from the merchant lookup endpoint
9
11
  */
@@ -39,11 +41,20 @@ export async function fetchMerchantId(
39
41
  domain?: string,
40
42
  walletUrl?: string
41
43
  ): Promise<string | undefined> {
42
- // Use cached value if available
44
+ // Use in-memory cache if available
43
45
  if (cachedMerchantId) {
44
46
  return cachedMerchantId;
45
47
  }
46
48
 
49
+ // Check sessionStorage (survives page navigations)
50
+ if (typeof window !== "undefined") {
51
+ const stored = window.sessionStorage.getItem(MERCHANT_ID_STORAGE_KEY);
52
+ if (stored) {
53
+ cachedMerchantId = stored;
54
+ return stored;
55
+ }
56
+ }
57
+
47
58
  // If a fetch is already in progress, wait for it
48
59
  if (cachePromise) {
49
60
  return cachePromise;
@@ -85,6 +96,13 @@ async function fetchMerchantIdInternal(
85
96
 
86
97
  const data = (await response.json()) as MerchantLookupResponse;
87
98
  cachedMerchantId = data.merchantId;
99
+ // Persist to sessionStorage so it survives page navigations
100
+ if (typeof window !== "undefined") {
101
+ window.sessionStorage.setItem(
102
+ MERCHANT_ID_STORAGE_KEY,
103
+ data.merchantId
104
+ );
105
+ }
88
106
  return cachedMerchantId;
89
107
  } catch (error) {
90
108
  console.warn("[Frak SDK] Failed to fetch merchantId:", error);
@@ -99,6 +117,9 @@ async function fetchMerchantIdInternal(
99
117
  export function clearMerchantIdCache(): void {
100
118
  cachedMerchantId = undefined;
101
119
  cachePromise = undefined;
120
+ if (typeof window !== "undefined") {
121
+ window.sessionStorage.removeItem(MERCHANT_ID_STORAGE_KEY);
122
+ }
102
123
  }
103
124
 
104
125
  /**
package/src/utils/sso.ts CHANGED
@@ -23,9 +23,10 @@ export type FullSsoParams = Omit<PrepareSsoParamsType, "metadata"> & {
23
23
  *
24
24
  * @param walletUrl - Base wallet URL (e.g., "https://wallet.frak.id")
25
25
  * @param params - SSO parameters
26
- * @param productId - Product identifier
26
+ * @param merchantId - Merchant identifier
27
27
  * @param name - Application name
28
28
  * @param css - Optional custom CSS
29
+ * @param clientId - Optional client identifier (auto-generated if omitted)
29
30
  * @returns Complete SSO URL ready to open in popup or redirect
30
31
  *
31
32
  * @example
@@ -1,5 +1,8 @@
1
1
  import type { FrakClient } from "../types";
2
2
 
3
+ /**
4
+ * Analytics event names emitted by the SDK
5
+ */
3
6
  export type FrakEvent =
4
7
  | "share_button_clicked"
5
8
  | "wallet_button_clicked"
@@ -13,6 +16,13 @@ export type FrakEvent =
13
16
 
14
17
  type EventProps = Record<string, unknown>;
15
18
 
19
+ /**
20
+ * Track an analytics event via OpenPanel.
21
+ * Fire-and-forget: silently catches errors.
22
+ * @param client - The Frak client instance (no-op if undefined)
23
+ * @param event - The event name to track
24
+ * @param props - Optional event properties
25
+ */
16
26
  export function trackEvent(
17
27
  client: FrakClient | undefined,
18
28
  event: FrakEvent,
@@ -1,13 +0,0 @@
1
- const e=require(`./trackEvent-CGIryq5h.cjs`);let t=require(`@frak-labs/frame-connector`),n=require(`@openpanel/web`);const r=`nexus-wallet-backup`,i=`frakwallet://`;function a(e,t){if(typeof window>`u`)return;let n=new URL(window.location.href),r=n.searchParams.get(`sso`);r&&(t.then(()=>{e.sendLifecycle({clientLifecycle:`sso-redirect-complete`,data:{compressed:r}}),console.log(`[SSO URL Listener] Forwarded compressed SSO data to iframe`)}).catch(e=>{console.error(`[SSO URL Listener] Failed to forward SSO data:`,e)}),n.searchParams.delete(`sso`),window.history.replaceState({},``,n.toString()),console.log(`[SSO URL Listener] SSO parameter detected and URL cleaned`))}var o=class e{config;iframe;isSetupDone=!1;lastResponse=null;lastRequest=null;constructor(e,t){this.config=e,this.iframe=t,this.lastRequest=null,this.lastResponse=null}setLastResponse(e,t){this.lastResponse={message:e,response:t,timestamp:Date.now()}}setLastRequest(e){this.lastRequest={event:e,timestamp:Date.now()}}updateSetupStatus(e){this.isSetupDone=e}base64Encode(e){try{return btoa(JSON.stringify(e))}catch(e){return console.warn(`Failed to encode debug data`,e),btoa(`Failed to encode data`)}}getIframeStatus(){return this.iframe?{loading:this.iframe.hasAttribute(`loading`),url:this.iframe.src,readyState:this.iframe.contentDocument?.readyState?this.iframe.contentDocument.readyState===`complete`?1:0:-1,contentWindow:!!this.iframe.contentWindow,isConnected:this.iframe.isConnected}:null}getNavigatorInfo(){return navigator?{userAgent:navigator.userAgent,language:navigator.language,onLine:navigator.onLine,screenWidth:window.screen.width,screenHeight:window.screen.height,pixelRatio:window.devicePixelRatio}:null}gatherDebugInfo(e){let n=this.getIframeStatus(),r=this.getNavigatorInfo(),i=`Unknown`;return e instanceof t.FrakRpcError?i=`FrakRpcError: ${e.code} '${e.message}'`:e instanceof Error?i=e.message:typeof e==`string`&&(i=e),{timestamp:new Date().toISOString(),encodedUrl:btoa(window.location.href),encodedConfig:this.config?this.base64Encode(this.config):`no-config`,navigatorInfo:r?this.base64Encode(r):`no-navigator`,iframeStatus:n?this.base64Encode(n):`not-iframe`,lastRequest:this.lastRequest?this.base64Encode(this.lastRequest):`No Frak request logged`,lastResponse:this.lastResponse?this.base64Encode(this.lastResponse):`No Frak response logged`,clientStatus:this.isSetupDone?`setup`:`not-setup`,error:i}}static empty(){return new e}formatDebugInfo(e){let t=this.gatherDebugInfo(e);return`
2
- Debug Information:
3
- -----------------
4
- Timestamp: ${t.timestamp}
5
- URL: ${t.encodedUrl}
6
- Config: ${t.encodedConfig}
7
- Navigator Info: ${t.navigatorInfo}
8
- IFrame Status: ${t.iframeStatus}
9
- Last Request: ${t.lastRequest}
10
- Last Response: ${t.lastResponse}
11
- Client Status: ${t.clientStatus}
12
- Error: ${t.error}
13
- `.trim()}};function s(){let e=navigator.userAgent;return/Android/i.test(e)&&/Chrome\/\d+/i.test(e)}function c(e){return`intent://${e.slice(13)}#Intent;scheme=frakwallet;package=id.frak.wallet;end`}function l(e,t){let n=t?.timeout??2500,r=!1,i=()=>{document.hidden&&(r=!0)};document.addEventListener(`visibilitychange`,i);let a=s()&&u(e)?c(e):e;window.location.href=a,setTimeout(()=>{document.removeEventListener(`visibilitychange`,i),r||t?.onFallback?.()},n)}function u(e){return e.startsWith(i)}const d={id:`frak-wallet`,name:`frak-wallet`,title:`Frak Wallet`,allow:`publickey-credentials-get *; clipboard-write; web-share *`,style:{width:`0`,height:`0`,border:`0`,position:`absolute`,zIndex:2000001,top:`-1000px`,left:`-1000px`,colorScheme:`auto`}};function f({walletBaseUrl:e,config:t}){let n=document.querySelector(`#frak-wallet`);n&&n.remove();let r=document.createElement(`iframe`);return r.id=d.id,r.name=d.name,r.allow=d.allow,r.style.zIndex=d.style.zIndex.toString(),p({iframe:r,isVisible:!1}),r.src=`${t?.walletUrl??e??`https://wallet.frak.id`}/listener`,new Promise(e=>{r.addEventListener(`load`,()=>e(r)),document.body.appendChild(r)})}function p({iframe:e,isVisible:t}){if(!t){e.style.width=`0`,e.style.height=`0`,e.style.border=`0`,e.style.position=`fixed`,e.style.top=`-1000px`,e.style.left=`-1000px`;return}e.style.position=`fixed`,e.style.top=`0`,e.style.left=`0`,e.style.width=`100%`,e.style.height=`100%`,e.style.pointerEvents=`auto`}function m(e=`/listener`){if(!window.opener)return null;let t=t=>{try{return t.location.origin===window.location.origin&&t.location.pathname===e}catch{return!1}};if(t(window.opener))return window.opener;try{let e=window.opener.frames;for(let n=0;n<e.length;n++)if(t(e[n]))return e[n];return null}catch(t){return console.error(`[findIframeInOpener] Error finding iframe with pathname ${e}:`,t),null}}function h(e){e?localStorage.setItem(r,e):localStorage.removeItem(r)}function g(t,n,r,i){let a=new URL(window.location.href),o=a.searchParams.get(`fmt`)??void 0;t.contentWindow?.postMessage({clientLifecycle:`handshake-response`,data:{token:n,currentUrl:window.location.href,clientId:e.d(),pendingMergeToken:o,configDomain:i}},r),o&&(a.searchParams.delete(`fmt`),window.history.replaceState({},``,a.toString()))}function _(e,t){try{let n=new URL(e);return n.searchParams.has(`u`)?(n.searchParams.delete(`u`),n.searchParams.append(`u`,window.location.href),t&&n.searchParams.append(`fmt`,t),n.toString()):e}catch{return e}}function v(e,t,n,r){let i=_(t,r);u(t)?l(i,{onFallback:()=>{e.contentWindow?.postMessage({clientLifecycle:`deep-link-failed`,data:{originalUrl:i}},n)}}):window.location.href=i}function y({iframe:e,targetOrigin:n,configDomain:i}){let a=new t.Deferred;return{handleEvent:async t=>{if(!(`iframeLifecycle`in t))return;let{iframeLifecycle:o,data:s}=t;switch(o){case`connected`:a.resolve(!0);break;case`do-backup`:h(s.backup);break;case`remove-backup`:localStorage.removeItem(r);break;case`show`:case`hide`:p({iframe:e,isVisible:o===`show`});break;case`handshake`:g(e,s.token,n,i);break;case`redirect`:v(e,s.baseRedirectUrl,n,s.mergeToken);break}},isConnected:a.promise}}function b({config:e,iframe:r}){let i=e?.walletUrl??`https://wallet.frak.id`,a=y({iframe:r,targetOrigin:i,configDomain:e.domain}),s=new o(e,r);if(!r.contentWindow)throw new t.FrakRpcError(t.RpcErrorCodes.configError,`The iframe does not have a content window`);let c=(0,t.createRpcClient)({emittingTransport:r.contentWindow,listeningTransport:window,targetOrigin:i,middleware:[{async onRequest(e,n){if(!await a.isConnected)throw new t.FrakRpcError(t.RpcErrorCodes.clientNotConnected,`The iframe provider isn't connected yet`);return n}},{onRequest(e,t){return s.setLastRequest(e),t},onResponse(e,t){return s.setLastResponse(e,t),t}}],lifecycleHandlers:{iframeLifecycle:async(e,t)=>{await a.handleEvent(e)}}}),l=x(c,a),u=async()=>{l(),c.cleanup(),r.remove()},d;console.log(`[Frak SDK] Initializing OpenPanel`),d=new n.OpenPanel({apiUrl:`https://op-api.gcp.frak.id`,clientId:`6eacc8d7-49ac-4936-95e9-81ef29449570`,trackScreenViews:!0,trackOutgoingLinks:!0,trackAttributes:!1,filter:({type:e,payload:t})=>(e!==`track`||!t?.properties||`sdkVersion`in t.properties||(t.properties={...t.properties,sdkVersion:`0.1.1`}),!0)}),d.setGlobalProperties({sdkVersion:`0.1.1`}),d.init();let f=S({config:e,rpcClient:c,lifecycleManager:a}).then(()=>s.updateSetupStatus(!0));return{config:e,debugInfo:s,waitForConnection:a.isConnected,waitForSetup:f,request:c.request,listenerRequest:c.listen,destroy:u,openPanel:d}}function x(e,t){let n,r,i=()=>e.sendLifecycle({clientLifecycle:`heartbeat`});async function a(){i(),n=setInterval(i,1e3),r=setTimeout(()=>{o(),console.log(`Heartbeat timeout: connection failed`)},3e4),await t.isConnected,o()}function o(){n&&clearInterval(n),r&&clearTimeout(r)}return a(),o}async function S({config:e,rpcClient:t,lifecycleManager:n}){await n.isConnected,a(t,n.isConnected);async function i(){let n=e.customizations?.css;if(!n)return;let r={clientLifecycle:`modal-css`,data:{cssLink:n}};t.sendLifecycle(r)}async function o(){let n=e.customizations?.i18n;if(!n)return;let r={clientLifecycle:`modal-i18n`,data:{i18n:n}};t.sendLifecycle(r)}async function s(){if(typeof window>`u`)return;let e=window.localStorage.getItem(r);if(!e)return;let n={clientLifecycle:`restore-backup`,data:{backup:e}};t.sendLifecycle(n)}await Promise.allSettled([i(),o(),s()])}function C(n){return(0,t.jsonDecode)(e.l(n))}const w={eur:`fr-FR`,usd:`en-US`,gbp:`en-GB`};function T(e){return e&&e in w?e:`eur`}function E(e){return e?w[e]??w.eur:w.eur}function D(e,t){let n=E(t),r=T(t);return e.toLocaleString(n,{style:`currency`,currency:r,minimumFractionDigits:0,maximumFractionDigits:2})}function O(e){return e?`${e}Amount`:`eurAmount`}let k,A;async function j(e,t){if(k)return k;if(A)return A;A=M(e,t);let n=await A;return A=void 0,n}async function M(t,n){let r=t??(typeof window<`u`?window.location.hostname:``);if(r)try{let t=e.r(n),i=await fetch(`${t}/user/merchant/resolve?domain=${encodeURIComponent(r)}`);if(!i.ok){console.warn(`[Frak SDK] Merchant lookup failed for domain ${r}: ${i.status}`);return}return k=(await i.json()).merchantId,k}catch(e){console.warn(`[Frak SDK] Failed to fetch merchantId:`,e);return}}function N(){k=void 0,A=void 0}async function P(e,t){return e.metadata?.merchantId?e.metadata.merchantId:j(void 0,t)}async function F({config:e}){let t=I(e),n=await f({config:t});if(!n){console.error(`Failed to create iframe`);return}let r=b({config:t,iframe:n});if(await r.waitForSetup,!await r.waitForConnection){console.error(`Failed to connect to client`);return}return r}function I(e){let t=T(e.metadata?.currency);return{...e,metadata:{...e.metadata,currency:t}}}Object.defineProperty(exports,`_`,{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return O}}),Object.defineProperty(exports,`b`,{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return T}}),Object.defineProperty(exports,`d`,{enumerable:!0,get:function(){return b}}),Object.defineProperty(exports,`f`,{enumerable:!0,get:function(){return d}}),Object.defineProperty(exports,`g`,{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,`h`,{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return P}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return w}}),Object.defineProperty(exports,`m`,{enumerable:!0,get:function(){return m}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return N}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return D}}),Object.defineProperty(exports,`p`,{enumerable:!0,get:function(){return f}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return j}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return E}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return F}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return C}}),Object.defineProperty(exports,`v`,{enumerable:!0,get:function(){return l}}),Object.defineProperty(exports,`y`,{enumerable:!0,get:function(){return o}});
@@ -1,13 +0,0 @@
1
- import{d as e,l as t,r as n}from"./trackEvent-YfUh4jrx.js";import{Deferred as r,FrakRpcError as i,RpcErrorCodes as a,createRpcClient as o,jsonDecode as s}from"@frak-labs/frame-connector";import{OpenPanel as c}from"@openpanel/web";const l=`nexus-wallet-backup`,u=`frakwallet://`;function d(e,t){if(typeof window>`u`)return;let n=new URL(window.location.href),r=n.searchParams.get(`sso`);r&&(t.then(()=>{e.sendLifecycle({clientLifecycle:`sso-redirect-complete`,data:{compressed:r}}),console.log(`[SSO URL Listener] Forwarded compressed SSO data to iframe`)}).catch(e=>{console.error(`[SSO URL Listener] Failed to forward SSO data:`,e)}),n.searchParams.delete(`sso`),window.history.replaceState({},``,n.toString()),console.log(`[SSO URL Listener] SSO parameter detected and URL cleaned`))}var f=class e{config;iframe;isSetupDone=!1;lastResponse=null;lastRequest=null;constructor(e,t){this.config=e,this.iframe=t,this.lastRequest=null,this.lastResponse=null}setLastResponse(e,t){this.lastResponse={message:e,response:t,timestamp:Date.now()}}setLastRequest(e){this.lastRequest={event:e,timestamp:Date.now()}}updateSetupStatus(e){this.isSetupDone=e}base64Encode(e){try{return btoa(JSON.stringify(e))}catch(e){return console.warn(`Failed to encode debug data`,e),btoa(`Failed to encode data`)}}getIframeStatus(){return this.iframe?{loading:this.iframe.hasAttribute(`loading`),url:this.iframe.src,readyState:this.iframe.contentDocument?.readyState?this.iframe.contentDocument.readyState===`complete`?1:0:-1,contentWindow:!!this.iframe.contentWindow,isConnected:this.iframe.isConnected}:null}getNavigatorInfo(){return navigator?{userAgent:navigator.userAgent,language:navigator.language,onLine:navigator.onLine,screenWidth:window.screen.width,screenHeight:window.screen.height,pixelRatio:window.devicePixelRatio}:null}gatherDebugInfo(e){let t=this.getIframeStatus(),n=this.getNavigatorInfo(),r=`Unknown`;return e instanceof i?r=`FrakRpcError: ${e.code} '${e.message}'`:e instanceof Error?r=e.message:typeof e==`string`&&(r=e),{timestamp:new Date().toISOString(),encodedUrl:btoa(window.location.href),encodedConfig:this.config?this.base64Encode(this.config):`no-config`,navigatorInfo:n?this.base64Encode(n):`no-navigator`,iframeStatus:t?this.base64Encode(t):`not-iframe`,lastRequest:this.lastRequest?this.base64Encode(this.lastRequest):`No Frak request logged`,lastResponse:this.lastResponse?this.base64Encode(this.lastResponse):`No Frak response logged`,clientStatus:this.isSetupDone?`setup`:`not-setup`,error:r}}static empty(){return new e}formatDebugInfo(e){let t=this.gatherDebugInfo(e);return`
2
- Debug Information:
3
- -----------------
4
- Timestamp: ${t.timestamp}
5
- URL: ${t.encodedUrl}
6
- Config: ${t.encodedConfig}
7
- Navigator Info: ${t.navigatorInfo}
8
- IFrame Status: ${t.iframeStatus}
9
- Last Request: ${t.lastRequest}
10
- Last Response: ${t.lastResponse}
11
- Client Status: ${t.clientStatus}
12
- Error: ${t.error}
13
- `.trim()}};function p(){let e=navigator.userAgent;return/Android/i.test(e)&&/Chrome\/\d+/i.test(e)}function m(e){return`intent://${e.slice(13)}#Intent;scheme=frakwallet;package=id.frak.wallet;end`}function h(e,t){let n=t?.timeout??2500,r=!1,i=()=>{document.hidden&&(r=!0)};document.addEventListener(`visibilitychange`,i);let a=p()&&g(e)?m(e):e;window.location.href=a,setTimeout(()=>{document.removeEventListener(`visibilitychange`,i),r||t?.onFallback?.()},n)}function g(e){return e.startsWith(u)}const _={id:`frak-wallet`,name:`frak-wallet`,title:`Frak Wallet`,allow:`publickey-credentials-get *; clipboard-write; web-share *`,style:{width:`0`,height:`0`,border:`0`,position:`absolute`,zIndex:2000001,top:`-1000px`,left:`-1000px`,colorScheme:`auto`}};function v({walletBaseUrl:e,config:t}){let n=document.querySelector(`#frak-wallet`);n&&n.remove();let r=document.createElement(`iframe`);return r.id=_.id,r.name=_.name,r.allow=_.allow,r.style.zIndex=_.style.zIndex.toString(),y({iframe:r,isVisible:!1}),r.src=`${t?.walletUrl??e??`https://wallet.frak.id`}/listener`,new Promise(e=>{r.addEventListener(`load`,()=>e(r)),document.body.appendChild(r)})}function y({iframe:e,isVisible:t}){if(!t){e.style.width=`0`,e.style.height=`0`,e.style.border=`0`,e.style.position=`fixed`,e.style.top=`-1000px`,e.style.left=`-1000px`;return}e.style.position=`fixed`,e.style.top=`0`,e.style.left=`0`,e.style.width=`100%`,e.style.height=`100%`,e.style.pointerEvents=`auto`}function b(e=`/listener`){if(!window.opener)return null;let t=t=>{try{return t.location.origin===window.location.origin&&t.location.pathname===e}catch{return!1}};if(t(window.opener))return window.opener;try{let e=window.opener.frames;for(let n=0;n<e.length;n++)if(t(e[n]))return e[n];return null}catch(t){return console.error(`[findIframeInOpener] Error finding iframe with pathname ${e}:`,t),null}}function x(e){e?localStorage.setItem(l,e):localStorage.removeItem(l)}function S(t,n,r,i){let a=new URL(window.location.href),o=a.searchParams.get(`fmt`)??void 0;t.contentWindow?.postMessage({clientLifecycle:`handshake-response`,data:{token:n,currentUrl:window.location.href,clientId:e(),pendingMergeToken:o,configDomain:i}},r),o&&(a.searchParams.delete(`fmt`),window.history.replaceState({},``,a.toString()))}function C(e,t){try{let n=new URL(e);return n.searchParams.has(`u`)?(n.searchParams.delete(`u`),n.searchParams.append(`u`,window.location.href),t&&n.searchParams.append(`fmt`,t),n.toString()):e}catch{return e}}function w(e,t,n,r){let i=C(t,r);g(t)?h(i,{onFallback:()=>{e.contentWindow?.postMessage({clientLifecycle:`deep-link-failed`,data:{originalUrl:i}},n)}}):window.location.href=i}function T({iframe:e,targetOrigin:t,configDomain:n}){let i=new r;return{handleEvent:async r=>{if(!(`iframeLifecycle`in r))return;let{iframeLifecycle:a,data:o}=r;switch(a){case`connected`:i.resolve(!0);break;case`do-backup`:x(o.backup);break;case`remove-backup`:localStorage.removeItem(l);break;case`show`:case`hide`:y({iframe:e,isVisible:a===`show`});break;case`handshake`:S(e,o.token,t,n);break;case`redirect`:w(e,o.baseRedirectUrl,t,o.mergeToken);break}},isConnected:i.promise}}function E({config:e,iframe:t}){let n=e?.walletUrl??`https://wallet.frak.id`,r=T({iframe:t,targetOrigin:n,configDomain:e.domain}),s=new f(e,t);if(!t.contentWindow)throw new i(a.configError,`The iframe does not have a content window`);let l=o({emittingTransport:t.contentWindow,listeningTransport:window,targetOrigin:n,middleware:[{async onRequest(e,t){if(!await r.isConnected)throw new i(a.clientNotConnected,`The iframe provider isn't connected yet`);return t}},{onRequest(e,t){return s.setLastRequest(e),t},onResponse(e,t){return s.setLastResponse(e,t),t}}],lifecycleHandlers:{iframeLifecycle:async(e,t)=>{await r.handleEvent(e)}}}),u=D(l,r),d=async()=>{u(),l.cleanup(),t.remove()},p;console.log(`[Frak SDK] Initializing OpenPanel`),p=new c({apiUrl:`https://op-api.gcp.frak.id`,clientId:`6eacc8d7-49ac-4936-95e9-81ef29449570`,trackScreenViews:!0,trackOutgoingLinks:!0,trackAttributes:!1,filter:({type:e,payload:t})=>(e!==`track`||!t?.properties||`sdkVersion`in t.properties||(t.properties={...t.properties,sdkVersion:`0.1.1`}),!0)}),p.setGlobalProperties({sdkVersion:`0.1.1`}),p.init();let m=O({config:e,rpcClient:l,lifecycleManager:r}).then(()=>s.updateSetupStatus(!0));return{config:e,debugInfo:s,waitForConnection:r.isConnected,waitForSetup:m,request:l.request,listenerRequest:l.listen,destroy:d,openPanel:p}}function D(e,t){let n,r,i=()=>e.sendLifecycle({clientLifecycle:`heartbeat`});async function a(){i(),n=setInterval(i,1e3),r=setTimeout(()=>{o(),console.log(`Heartbeat timeout: connection failed`)},3e4),await t.isConnected,o()}function o(){n&&clearInterval(n),r&&clearTimeout(r)}return a(),o}async function O({config:e,rpcClient:t,lifecycleManager:n}){await n.isConnected,d(t,n.isConnected);async function r(){let n=e.customizations?.css;if(!n)return;let r={clientLifecycle:`modal-css`,data:{cssLink:n}};t.sendLifecycle(r)}async function i(){let n=e.customizations?.i18n;if(!n)return;let r={clientLifecycle:`modal-i18n`,data:{i18n:n}};t.sendLifecycle(r)}async function a(){if(typeof window>`u`)return;let e=window.localStorage.getItem(l);if(!e)return;let n={clientLifecycle:`restore-backup`,data:{backup:e}};t.sendLifecycle(n)}await Promise.allSettled([r(),i(),a()])}function k(e){return s(t(e))}const A={eur:`fr-FR`,usd:`en-US`,gbp:`en-GB`};function j(e){return e&&e in A?e:`eur`}function M(e){return e?A[e]??A.eur:A.eur}function N(e,t){let n=M(t),r=j(t);return e.toLocaleString(n,{style:`currency`,currency:r,minimumFractionDigits:0,maximumFractionDigits:2})}function P(e){return e?`${e}Amount`:`eurAmount`}let F,I;async function L(e,t){if(F)return F;if(I)return I;I=R(e,t);let n=await I;return I=void 0,n}async function R(e,t){let r=e??(typeof window<`u`?window.location.hostname:``);if(r)try{let e=n(t),i=await fetch(`${e}/user/merchant/resolve?domain=${encodeURIComponent(r)}`);if(!i.ok){console.warn(`[Frak SDK] Merchant lookup failed for domain ${r}: ${i.status}`);return}return F=(await i.json()).merchantId,F}catch(e){console.warn(`[Frak SDK] Failed to fetch merchantId:`,e);return}}function z(){F=void 0,I=void 0}async function B(e,t){return e.metadata?.merchantId?e.metadata.merchantId:L(void 0,t)}async function V({config:e}){let t=H(e),n=await v({config:t});if(!n){console.error(`Failed to create iframe`);return}let r=E({config:t,iframe:n});if(await r.waitForSetup,!await r.waitForConnection){console.error(`Failed to connect to client`);return}return r}function H(e){let t=j(e.metadata?.currency);return{...e,metadata:{...e.metadata,currency:t}}}export{m as _,P as a,u as b,j as c,E as d,_ as f,g,p as h,B as i,A as l,b as m,z as n,N as o,v as p,L as r,M as s,V as t,k as u,h as v,f as y};
@@ -1 +0,0 @@
1
- const e=require(`./trackEvent-CGIryq5h.cjs`);let t=require(`viem`),n=require(`@frak-labs/frame-connector`),r=require(`viem/siwe`);async function i(e,t){return await e.request({method:`frak_displayEmbeddedWallet`,params:[t,e.config.metadata]})}async function a(e,{steps:t,metadata:n}){return await e.request({method:`frak_displayModal`,params:[t,n,e.config.metadata]})}async function o(e){return await e.request({method:`frak_getMerchantInformation`})}async function s(e,t){let{metadata:n,customizations:r}=e.config;return await e.request({method:`frak_prepareSso`,params:[t,n.name,r?.css]})}async function c(e,t){try{await e.request({method:`frak_sendInteraction`,params:[t]})}catch{console.warn(`[Frak SDK] Failed to send interaction:`,t.type)}}async function l(t,{walletStatus:r,frakContext:i,modalConfig:a,options:o}){if(!i?.r)return`no-referrer`;e.t(t,`user_referred_started`,{properties:{referrer:i?.r,walletStatus:r?.key}}),c(t,{type:`arrival`,referrerWallet:i.r,landingUrl:typeof window<`u`?window.location.href:void 0});let s=!1;async function l(){if(!s)return s=!0,d(t,{modalConfig:{...a,loggedIn:{action:{key:`referred`}}},walletStatus:r})}try{let{status:n,currentWallet:a}=await u({initialWalletStatus:r,getFreshWalletStatus:l,frakContext:i});return e.n.replaceUrl({url:window.location?.href,context:o?.alwaysAppendUrl?{r:a}:null}),e.t(t,`user_referred_completed`,{properties:{status:n,referrer:i?.r,wallet:a}}),n}catch(a){return console.log(`Error processing referral`,{error:a}),e.t(t,`user_referred_error`,{properties:{referrer:i?.r,error:a instanceof n.FrakRpcError?`[${a.code}] ${a.name} - ${a.message}`:a instanceof Error?a.message:`undefined`}}),e.n.replaceUrl({url:window.location?.href,context:o?.alwaysAppendUrl?{r:r?.wallet}:null}),f(a)}}async function u({initialWalletStatus:e,getFreshWalletStatus:n,frakContext:r}){let i=e?.wallet;return i||=await n(),i&&(0,t.isAddressEqual)(r.r,i)?{status:`self-referral`,currentWallet:i}:{status:`success`,currentWallet:i}}async function d(e,{modalConfig:t,walletStatus:n}){return n?.key===`connected`?n.wallet??void 0:(await i(e,t??{}))?.wallet??void 0}function f(e){if(e instanceof n.FrakRpcError)switch(e.code){case n.RpcErrorCodes.walletNotConnected:return`no-wallet`;default:return`error`}return`error`}async function p(t,{modalConfig:n,options:r}={}){let i=e.n.parse({url:window.location.href}),a=await h(t);try{return await l(t,{walletStatus:a,frakContext:i,modalConfig:n,options:r})}catch(e){console.warn(`Error processing referral`,{error:e})}}async function m(t){if(typeof window>`u`){console.warn(`[Frak] No window found, can't track purchase`);return}let n=window.sessionStorage.getItem(`frak-wallet-interaction-token`);if(!n){console.warn(`[Frak] No frak session found, skipping purchase check`);return}let r=e.r();await fetch(`${r}/interactions/listenForPurchase`,{method:`POST`,headers:{Accept:`application/json`,"Content-Type":`application/json`,"x-wallet-sdk-auth":n},body:JSON.stringify(t)})}function h(e,t){if(!t)return e.request({method:`frak_listenToWalletStatus`}).then(t=>(g(e,t),t));let r=new n.Deferred,i=!1;return e.listenerRequest({method:`frak_listenToWalletStatus`},n=>{g(e,n),t(n),i||=(r.resolve(n),!0)}),r.promise}function g(e,t){typeof window>`u`||(e.openPanel?.setGlobalProperties({wallet:t.wallet??null}),t.interactionToken?window.sessionStorage.setItem(`frak-wallet-interaction-token`,t.interactionToken):window.sessionStorage.removeItem(`frak-wallet-interaction-token`))}function _(e,{metadata:t,login:n}){return v(e,{steps:{login:n??{}},metadata:t})}function v(e,t){function n(n){return v(e,{...t,steps:{...t.steps,sendTransaction:n}})}function r(n){return v(e,{...t,steps:{...t.steps,final:{...n,action:{key:`reward`}}}})}function i(n,r){return v(e,{...t,steps:{...t.steps,final:{...r,action:{key:`sharing`,options:n}}}})}async function o(n){return n&&(t.metadata=n(t.metadata??{})),await a(e,t)}return{params:t,sendTx:n,reward:r,sharing:i,display:o}}async function y(e,{tx:t,metadata:n}){return(await a(e,{metadata:n,steps:{login:{},sendTransaction:{tx:t}}})).sendTransaction}async function b(e,{siwe:t,metadata:n}){let i=e.config?.domain??window.location.host,o=t?.statement??`I confirm that I want to use my Frak wallet on: ${e.config.metadata.name}`;return(await a(e,{metadata:n,steps:{login:{},siweAuthenticate:{siwe:{...t,statement:o,nonce:t?.nonce??(0,r.generateSiweNonce)(),uri:t?.uri??`https://${i}`,version:t?.version??`1`,domain:i}}}})).siweAuthenticate}Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return m}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,`d`,{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,`f`,{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return h}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return y}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return l}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return b}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return o}});
@@ -1 +0,0 @@
1
- import{n as e,r as t,t as n}from"./trackEvent-YfUh4jrx.js";import{isAddressEqual as r}from"viem";import{Deferred as i,FrakRpcError as a,RpcErrorCodes as o}from"@frak-labs/frame-connector";import{generateSiweNonce as s}from"viem/siwe";async function c(e,t){return await e.request({method:`frak_displayEmbeddedWallet`,params:[t,e.config.metadata]})}async function l(e,{steps:t,metadata:n}){return await e.request({method:`frak_displayModal`,params:[t,n,e.config.metadata]})}async function u(e){return await e.request({method:`frak_getMerchantInformation`})}async function d(e,t){let{metadata:n,customizations:r}=e.config;return await e.request({method:`frak_prepareSso`,params:[t,n.name,r?.css]})}async function f(e,t){try{await e.request({method:`frak_sendInteraction`,params:[t]})}catch{console.warn(`[Frak SDK] Failed to send interaction:`,t.type)}}async function p(t,{walletStatus:r,frakContext:i,modalConfig:o,options:s}){if(!i?.r)return`no-referrer`;n(t,`user_referred_started`,{properties:{referrer:i?.r,walletStatus:r?.key}}),f(t,{type:`arrival`,referrerWallet:i.r,landingUrl:typeof window<`u`?window.location.href:void 0});let c=!1;async function l(){if(!c)return c=!0,h(t,{modalConfig:{...o,loggedIn:{action:{key:`referred`}}},walletStatus:r})}try{let{status:a,currentWallet:o}=await m({initialWalletStatus:r,getFreshWalletStatus:l,frakContext:i});return e.replaceUrl({url:window.location?.href,context:s?.alwaysAppendUrl?{r:o}:null}),n(t,`user_referred_completed`,{properties:{status:a,referrer:i?.r,wallet:o}}),a}catch(o){return console.log(`Error processing referral`,{error:o}),n(t,`user_referred_error`,{properties:{referrer:i?.r,error:o instanceof a?`[${o.code}] ${o.name} - ${o.message}`:o instanceof Error?o.message:`undefined`}}),e.replaceUrl({url:window.location?.href,context:s?.alwaysAppendUrl?{r:r?.wallet}:null}),g(o)}}async function m({initialWalletStatus:e,getFreshWalletStatus:t,frakContext:n}){let i=e?.wallet;return i||=await t(),i&&r(n.r,i)?{status:`self-referral`,currentWallet:i}:{status:`success`,currentWallet:i}}async function h(e,{modalConfig:t,walletStatus:n}){return n?.key===`connected`?n.wallet??void 0:(await c(e,t??{}))?.wallet??void 0}function g(e){if(e instanceof a)switch(e.code){case o.walletNotConnected:return`no-wallet`;default:return`error`}return`error`}async function _(t,{modalConfig:n,options:r}={}){let i=e.parse({url:window.location.href}),a=await y(t);try{return await p(t,{walletStatus:a,frakContext:i,modalConfig:n,options:r})}catch(e){console.warn(`Error processing referral`,{error:e})}}async function v(e){if(typeof window>`u`){console.warn(`[Frak] No window found, can't track purchase`);return}let n=window.sessionStorage.getItem(`frak-wallet-interaction-token`);if(!n){console.warn(`[Frak] No frak session found, skipping purchase check`);return}let r=t();await fetch(`${r}/interactions/listenForPurchase`,{method:`POST`,headers:{Accept:`application/json`,"Content-Type":`application/json`,"x-wallet-sdk-auth":n},body:JSON.stringify(e)})}function y(e,t){if(!t)return e.request({method:`frak_listenToWalletStatus`}).then(t=>(b(e,t),t));let n=new i,r=!1;return e.listenerRequest({method:`frak_listenToWalletStatus`},i=>{b(e,i),t(i),r||=(n.resolve(i),!0)}),n.promise}function b(e,t){typeof window>`u`||(e.openPanel?.setGlobalProperties({wallet:t.wallet??null}),t.interactionToken?window.sessionStorage.setItem(`frak-wallet-interaction-token`,t.interactionToken):window.sessionStorage.removeItem(`frak-wallet-interaction-token`))}function x(e,{metadata:t,login:n}){return S(e,{steps:{login:n??{}},metadata:t})}function S(e,t){function n(n){return S(e,{...t,steps:{...t.steps,sendTransaction:n}})}function r(n){return S(e,{...t,steps:{...t.steps,final:{...n,action:{key:`reward`}}}})}function i(n,r){return S(e,{...t,steps:{...t.steps,final:{...r,action:{key:`sharing`,options:n}}}})}async function a(n){return n&&(t.metadata=n(t.metadata??{})),await l(e,t)}return{params:t,sendTx:n,reward:r,sharing:i,display:a}}async function C(e,{tx:t,metadata:n}){return(await l(e,{metadata:n,steps:{login:{},sendTransaction:{tx:t}}})).sendTransaction}async function w(e,{siwe:t,metadata:n}){let r=e.config?.domain??window.location.host,i=t?.statement??`I confirm that I want to use my Frak wallet on: ${e.config.metadata.name}`;return(await l(e,{metadata:n,steps:{login:{},siweAuthenticate:{siwe:{...t,statement:i,nonce:t?.nonce??s(),uri:t?.uri??`https://${r}`,version:t?.version??`1`,domain:r}}}})).siweAuthenticate}export{v as a,f as c,l as d,c as f,y as i,d as l,C as n,_ as o,x as r,p as s,w as t,u};