@frak-labs/core-sdk 1.0.0 → 1.0.1

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 (59) hide show
  1. package/cdn/bundle.js +3 -3
  2. package/dist/actions-BlCQVBQJ.js +1 -0
  3. package/dist/actions-Bwj4zSdB.cjs +1 -0
  4. package/dist/actions.cjs +1 -1
  5. package/dist/actions.d.cts +2 -2
  6. package/dist/actions.d.ts +2 -2
  7. package/dist/actions.js +1 -1
  8. package/dist/bundle.cjs +1 -1
  9. package/dist/bundle.d.cts +4 -4
  10. package/dist/bundle.d.ts +4 -4
  11. package/dist/bundle.js +1 -1
  12. package/dist/{index-Dwmo109y.d.cts → index-9TdOc_ub.d.ts} +169 -44
  13. package/dist/{index-BphwTmKA.d.cts → index-BWic1g0J.d.cts} +1 -1
  14. package/dist/{index-BV5D9DsW.d.ts → index-DPIqLMCR.d.cts} +169 -44
  15. package/dist/{index-_f8EuN_1.d.ts → index-Du4nB3qO.d.ts} +1 -1
  16. package/dist/index.cjs +1 -1
  17. package/dist/index.d.cts +3 -3
  18. package/dist/index.d.ts +3 -3
  19. package/dist/index.js +1 -1
  20. package/dist/{openSso-BwEK2M98.d.cts → openSso-3YqtmSkM.d.ts} +116 -10
  21. package/dist/{openSso-C1Wzl5-i.d.ts → openSso-SP6T9cHA.d.cts} +115 -9
  22. package/dist/sdkConfigStore-BXzz5PlK.js +1 -0
  23. package/dist/sdkConfigStore-DDL_fjYX.cjs +1 -0
  24. package/dist/src-CqKED785.cjs +13 -0
  25. package/dist/src-u4vW9qh0.js +13 -0
  26. package/package.json +1 -1
  27. package/src/actions/referral/processReferral.test.ts +129 -8
  28. package/src/actions/referral/processReferral.ts +27 -17
  29. package/src/clients/createIFrameFrakClient.ts +84 -3
  30. package/src/index.ts +8 -1
  31. package/src/types/config.ts +9 -0
  32. package/src/types/context.ts +16 -4
  33. package/src/types/index.ts +2 -0
  34. package/src/types/lifecycle/client.ts +7 -0
  35. package/src/types/resolvedConfig.ts +10 -0
  36. package/src/types/rpc/displaySharingPage.ts +18 -0
  37. package/src/types/rpc/interaction.ts +1 -1
  38. package/src/types/tracking.ts +37 -1
  39. package/src/utils/FrakContext.test.ts +239 -9
  40. package/src/utils/FrakContext.ts +83 -21
  41. package/src/utils/analytics/events/component.ts +58 -0
  42. package/src/utils/analytics/events/index.ts +20 -0
  43. package/src/utils/analytics/events/lifecycle.ts +26 -0
  44. package/src/utils/analytics/events/referral.ts +11 -0
  45. package/src/utils/analytics/index.ts +8 -0
  46. package/src/utils/{trackEvent.test.ts → analytics/trackEvent.test.ts} +22 -30
  47. package/src/utils/analytics/trackEvent.ts +34 -0
  48. package/src/utils/frakContextV2Codec.test.ts +241 -0
  49. package/src/utils/frakContextV2Codec.ts +197 -0
  50. package/src/utils/index.ts +5 -1
  51. package/src/utils/mergeAttribution.test.ts +153 -0
  52. package/src/utils/mergeAttribution.ts +75 -0
  53. package/dist/actions-D4aBXbdp.cjs +0 -1
  54. package/dist/actions-Dq_uN-wn.js +0 -1
  55. package/dist/src-B1eliIi6.cjs +0 -13
  56. package/dist/src-C0UH1GsN.js +0 -13
  57. package/dist/trackEvent-BqJqRZ-u.cjs +0 -1
  58. package/dist/trackEvent-Bqq4jd6R.js +0 -1
  59. package/src/utils/trackEvent.ts +0 -41
@@ -1,8 +1,65 @@
1
- import { OpenPanel } from "@openpanel/web";
2
- import { LifecycleMessage, RpcClient } from "@frak-labs/frame-connector";
3
1
  import { Address, Hex } from "viem";
2
+ import { LifecycleMessage, RpcClient } from "@frak-labs/frame-connector";
3
+ import { OpenPanel } from "@openpanel/web";
4
4
  import { SiweMessage } from "viem/siwe";
5
5
 
6
+ //#region src/types/tracking.d.ts
7
+ type UtmParams = {
8
+ source?: string;
9
+ medium?: string;
10
+ campaign?: string;
11
+ term?: string;
12
+ content?: string;
13
+ };
14
+ /**
15
+ * Attribution parameters appended to outbound sharing URLs.
16
+ *
17
+ * Defaults are derived from the V2 Frak context when available:
18
+ * - `utmSource`: `"frak"`
19
+ * - `utmMedium`: `"referral"`
20
+ * - `utmCampaign`: merchantId (`context.m`)
21
+ * - `via`: `"frak"`
22
+ * - `ref`: clientId (`context.c`)
23
+ *
24
+ * Fields explicitly set here override the defaults. Existing params on the
25
+ * base URL are preserved (gap-fill policy) to respect merchant-provided UTMs.
26
+ */
27
+ type AttributionParams = {
28
+ utmSource?: string;
29
+ utmMedium?: string;
30
+ utmCampaign?: string;
31
+ utmContent?: string;
32
+ utmTerm?: string;
33
+ via?: string;
34
+ ref?: string;
35
+ };
36
+ /**
37
+ * Merchant-level attribution defaults.
38
+ *
39
+ * Same shape as {@link AttributionParams} minus `utmContent`, because
40
+ * `utm_content` describes the specific content/creative being shared and is
41
+ * inherently per-call or per-product (never a merchant-wide default).
42
+ *
43
+ * Used as the shape for both:
44
+ * - `FrakWalletSdkConfig.attribution` (SDK-side compile-time defaults)
45
+ * - Backend merchant-config attribution (dashboard-driven defaults)
46
+ */
47
+ type AttributionDefaults = Omit<AttributionParams, "utmContent">;
48
+ type TrackArrivalParams = {
49
+ /** Sharer wallet address. Accepted in both V1 (legacy) and V2 (authenticated sharer) contexts. */referrerWallet?: Address;
50
+ referrerClientId?: string;
51
+ referrerMerchantId?: string; /** Epoch seconds timestamp from the referral link creation */
52
+ referralTimestamp?: number;
53
+ landingUrl?: string;
54
+ utmParams?: UtmParams;
55
+ };
56
+ type TrackArrivalResult = {
57
+ success: boolean;
58
+ identityGroupId?: string;
59
+ touchpointId?: string;
60
+ error?: string;
61
+ };
62
+ //#endregion
6
63
  //#region src/types/config.d.ts
7
64
  /**
8
65
  * All the currencies available
@@ -82,6 +139,13 @@ type FrakWalletSdkConfig = {
82
139
  * @defaultValue true
83
140
  */
84
141
  waitForBackendConfig?: boolean;
142
+ /**
143
+ * Default attribution params (UTM / via / ref) appended to outbound
144
+ * sharing URLs. Per-call `displaySharingPage` overrides win, then backend
145
+ * config, then this SDK-level default. `utm_content` is intentionally
146
+ * excluded — it is per-content/per-product, never a merchant-wide default.
147
+ */
148
+ attribution?: AttributionDefaults;
85
149
  };
86
150
  /**
87
151
  * Custom i18n configuration for the modal
@@ -199,6 +263,12 @@ type ResolvedSdkConfig = {
199
263
  translations?: Record<string, string>;
200
264
  placements?: Record<string, ResolvedPlacement>; /** Global component defaults (used when no placement override exists) */
201
265
  components?: ResolvedPlacement["components"];
266
+ /**
267
+ * Default attribution params applied when building outbound sharing URLs.
268
+ * Per-call overrides win over these backend defaults; `utm_content` is
269
+ * intentionally excluded (per-content/per-product, never a merchant default).
270
+ */
271
+ attribution?: AttributionDefaults;
202
272
  };
203
273
  /**
204
274
  * Internal SDK config store state
@@ -221,7 +291,8 @@ type SdkResolvedConfig = {
221
291
  css?: string; /** Global translations (for reference / component fallback) */
222
292
  translations?: Record<string, string>; /** Named placements (keyed by placement ID) */
223
293
  placements?: Record<string, ResolvedPlacement>; /** Global component defaults (fallback for placement-level overrides) */
224
- components?: ResolvedPlacement["components"];
294
+ components?: ResolvedPlacement["components"]; /** Merged attribution defaults: backend > SDK static config */
295
+ attribution?: AttributionDefaults;
225
296
  };
226
297
  //#endregion
227
298
  //#region src/types/lifecycle/client.d.ts
@@ -276,6 +347,13 @@ type ResolvedConfigEvent = {
276
347
  * When present, listener should execute identity merge in background.
277
348
  */
278
349
  pendingMergeToken?: string;
350
+ /**
351
+ * Persistent per-origin anonymous id generated on the partner site
352
+ * (SDK-side localStorage). Propagated here so the listener can
353
+ * set it as an OpenPanel global property and stitch SDK events
354
+ * with listener events in the same funnel.
355
+ */
356
+ sdkAnonymousId?: string;
279
357
  sdkConfig?: ResolvedSdkConfig;
280
358
  };
281
359
  };
@@ -651,6 +729,11 @@ type SharingPageProduct = {
651
729
  * When provided and the product is selected, this link is used instead of the default sharing link
652
730
  */
653
731
  link?: string;
732
+ /**
733
+ * Optional `utm_content` value to apply when this product is selected.
734
+ * Falls back to the page-level `attribution.utmContent` when omitted.
735
+ */
736
+ utmContent?: string;
654
737
  };
655
738
  /**
656
739
  * Parameters to display the sharing page
@@ -668,6 +751,18 @@ type DisplaySharingPageParamsType = {
668
751
  * If not provided, the sharing link will be generated from the current page URL + merchant context
669
752
  */
670
753
  link?: string;
754
+ /**
755
+ * Optional attribution overrides for the outbound sharing URL.
756
+ *
757
+ * When provided (even as an empty object), Frak adds standard affiliation
758
+ * params (`utm_source=frak`, `utm_medium=referral`, `utm_campaign=<merchantId>`,
759
+ * `ref=<clientId>`, `via=frak`) alongside `fCtx`. Existing UTMs on the base
760
+ * URL are preserved (gap-fill). Set this to `null` to disable attribution
761
+ * params entirely (only `fCtx` is added).
762
+ *
763
+ * @default {} — defaults applied
764
+ */
765
+ attribution?: AttributionParams | null;
671
766
  /**
672
767
  * Optional metadata overrides for the sharing page
673
768
  */
@@ -856,7 +951,7 @@ type DisplayEmbeddedWalletResultType = {
856
951
  * @group RPC Schema
857
952
  */
858
953
  type SendInteractionParamsType = {
859
- type: "arrival"; /** @deprecated V1 legacy use referrerClientId for v2 */
954
+ type: "arrival"; /** Sharer wallet address. Accepted in both V1 (legacy, wallet-only) and V2 (authenticated sharer) contexts. */
860
955
  referrerWallet?: Address;
861
956
  referrerClientId?: string;
862
957
  referrerMerchantId?: string; /** Epoch seconds timestamp from the referral link creation */
@@ -1201,15 +1296,26 @@ type FrakContextV1 = {
1201
1296
  /** Referrer wallet address */r: Address;
1202
1297
  };
1203
1298
  /**
1204
- * V2 Frak Context — anonymous-first referral context.
1205
- * Contains the sharer's clientId, merchantId, and link creation timestamp.
1299
+ * V2 Frak Context — anonymous-first referral context with optional wallet.
1300
+ *
1301
+ * Carries merchant context (`m`) and creation timestamp (`t`) unconditionally.
1302
+ * Identifies the sharer via either the anonymous clientId (`c`) or, when the
1303
+ * sharer is authenticated, the stronger wallet identifier (`w`). A valid V2
1304
+ * context MUST contain at least one of `c` or `w`; both may be present when
1305
+ * a logged-in user shares a link (best attribution signal).
1306
+ *
1307
+ * `w` takes precedence as the source of truth because the wallet is bound to
1308
+ * the user's WebAuthn credential, survives localStorage clears, and is global
1309
+ * across merchants — unlike `c`, which is a per-browser UUID.
1310
+ *
1206
1311
  * @ignore
1207
1312
  */
1208
1313
  type FrakContextV2 = {
1209
- /** Version discriminator */v: 2; /** Sharer's anonymous clientId (UUID from localStorage) */
1210
- c: string; /** Merchant ID (UUID) */
1314
+ /** Version discriminator */v: 2; /** Merchant ID (UUID) */
1211
1315
  m: string; /** Link creation timestamp (epoch seconds) */
1212
- t: number;
1316
+ t: number; /** Sharer's anonymous clientId (UUID from localStorage). Optional when `w` is provided. */
1317
+ c?: string; /** Sharer's wallet address. Preferred source of truth when the sharer is authenticated. Optional when `c` is provided. */
1318
+ w?: Address;
1213
1319
  };
1214
1320
  /**
1215
1321
  * The current Frak Context — union of all versions.
@@ -1291,4 +1397,4 @@ declare const ssoPopupName = "frak-sso";
1291
1397
  */
1292
1398
  declare function openSso(client: FrakClient, args: OpenSsoParamsType): Promise<OpenSsoReturnType>;
1293
1399
  //#endregion
1294
- export { ResolvedPlacement as $, ModalRpcMetadata as A, LoginModalStepType as B, EmbeddedViewActionReferred as C, DisplaySharingPageResultType as D, DisplaySharingPageParamsType as E, SendTransactionReturnType as F, SsoMetadata as G, OpenSsoReturnType as H, SendTransactionTxType as I, ModalStepMetadata as J, FinalActionType as K, SiweAuthenticateModalStepType as L, ModalRpcStepsResultType as M, ModalStepTypes as N, SharingPageProduct as O, SendTransactionModalStepType as P, MerchantConfigResponse as Q, SiweAuthenticateReturnType as R, LoggedOutEmbeddedView as S, LoggedInEmbeddedView as T, PrepareSsoParamsType as U, OpenSsoParamsType as V, PrepareSsoReturnType as W, IFrameLifecycleEvent as X, InteractionTypeKey as Y, ClientLifecycleEvent as Z, RewardTier as _, FrakContextV1 as a, Language as at, DisplayEmbeddedWalletParamsType as b, isV2Context as c, IFrameTransport as d, ResolvedSdkConfig as et, IFrameRpcSchema as f, GetMerchantInformationReturnType as g, EstimatedReward as h, FrakContext as i, I18nConfig as it, ModalRpcStepsInput as j, DisplayModalParamsType as k, FrakClient as l, UserReferralStatusType as m, ssoPopupFeatures as n, Currency as nt, FrakContextV2 as o, LocalizedI18nConfig as ot, WalletStatusReturnType as p, FinalModalStepType as q, ssoPopupName as r, FrakWalletSdkConfig as rt, isV1Context as s, openSso as t, SdkResolvedConfig as tt, FrakLifecycleEvent as u, TokenAmountType as v, EmbeddedViewActionSharing as w, DisplayEmbeddedWalletResultType as x, SendInteractionParamsType as y, SiweAuthenticationParams as z };
1400
+ export { ResolvedPlacement as $, ModalRpcMetadata as A, LoginModalStepType as B, EmbeddedViewActionReferred as C, DisplaySharingPageResultType as D, DisplaySharingPageParamsType as E, SendTransactionReturnType as F, SsoMetadata as G, OpenSsoReturnType as H, SendTransactionTxType as I, ModalStepMetadata as J, FinalActionType as K, SiweAuthenticateModalStepType as L, ModalRpcStepsResultType as M, ModalStepTypes as N, SharingPageProduct as O, SendTransactionModalStepType as P, MerchantConfigResponse as Q, SiweAuthenticateReturnType as R, LoggedOutEmbeddedView as S, LoggedInEmbeddedView as T, PrepareSsoParamsType as U, OpenSsoParamsType as V, PrepareSsoReturnType as W, IFrameLifecycleEvent as X, InteractionTypeKey as Y, ClientLifecycleEvent as Z, RewardTier as _, FrakContextV1 as a, Language as at, DisplayEmbeddedWalletParamsType as b, isV2Context as c, AttributionParams as ct, IFrameTransport as d, UtmParams as dt, ResolvedSdkConfig as et, IFrameRpcSchema as f, GetMerchantInformationReturnType as g, EstimatedReward as h, FrakContext as i, I18nConfig as it, ModalRpcStepsInput as j, DisplayModalParamsType as k, FrakClient as l, TrackArrivalParams as lt, UserReferralStatusType as m, ssoPopupFeatures as n, Currency as nt, FrakContextV2 as o, LocalizedI18nConfig as ot, WalletStatusReturnType as p, FinalModalStepType as q, ssoPopupName as r, FrakWalletSdkConfig as rt, isV1Context as s, AttributionDefaults as st, openSso as t, SdkResolvedConfig as tt, FrakLifecycleEvent as u, TrackArrivalResult as ut, TokenAmountType as v, EmbeddedViewActionSharing as w, DisplayEmbeddedWalletResultType as x, SendInteractionParamsType as y, SiweAuthenticationParams as z };
@@ -1,8 +1,65 @@
1
+ import { OpenPanel } from "@openpanel/web";
1
2
  import { Address, Hex } from "viem";
2
3
  import { LifecycleMessage, RpcClient } from "@frak-labs/frame-connector";
3
- import { OpenPanel } from "@openpanel/web";
4
4
  import { SiweMessage } from "viem/siwe";
5
5
 
6
+ //#region src/types/tracking.d.ts
7
+ type UtmParams = {
8
+ source?: string;
9
+ medium?: string;
10
+ campaign?: string;
11
+ term?: string;
12
+ content?: string;
13
+ };
14
+ /**
15
+ * Attribution parameters appended to outbound sharing URLs.
16
+ *
17
+ * Defaults are derived from the V2 Frak context when available:
18
+ * - `utmSource`: `"frak"`
19
+ * - `utmMedium`: `"referral"`
20
+ * - `utmCampaign`: merchantId (`context.m`)
21
+ * - `via`: `"frak"`
22
+ * - `ref`: clientId (`context.c`)
23
+ *
24
+ * Fields explicitly set here override the defaults. Existing params on the
25
+ * base URL are preserved (gap-fill policy) to respect merchant-provided UTMs.
26
+ */
27
+ type AttributionParams = {
28
+ utmSource?: string;
29
+ utmMedium?: string;
30
+ utmCampaign?: string;
31
+ utmContent?: string;
32
+ utmTerm?: string;
33
+ via?: string;
34
+ ref?: string;
35
+ };
36
+ /**
37
+ * Merchant-level attribution defaults.
38
+ *
39
+ * Same shape as {@link AttributionParams} minus `utmContent`, because
40
+ * `utm_content` describes the specific content/creative being shared and is
41
+ * inherently per-call or per-product (never a merchant-wide default).
42
+ *
43
+ * Used as the shape for both:
44
+ * - `FrakWalletSdkConfig.attribution` (SDK-side compile-time defaults)
45
+ * - Backend merchant-config attribution (dashboard-driven defaults)
46
+ */
47
+ type AttributionDefaults = Omit<AttributionParams, "utmContent">;
48
+ type TrackArrivalParams = {
49
+ /** Sharer wallet address. Accepted in both V1 (legacy) and V2 (authenticated sharer) contexts. */referrerWallet?: Address;
50
+ referrerClientId?: string;
51
+ referrerMerchantId?: string; /** Epoch seconds timestamp from the referral link creation */
52
+ referralTimestamp?: number;
53
+ landingUrl?: string;
54
+ utmParams?: UtmParams;
55
+ };
56
+ type TrackArrivalResult = {
57
+ success: boolean;
58
+ identityGroupId?: string;
59
+ touchpointId?: string;
60
+ error?: string;
61
+ };
62
+ //#endregion
6
63
  //#region src/types/config.d.ts
7
64
  /**
8
65
  * All the currencies available
@@ -82,6 +139,13 @@ type FrakWalletSdkConfig = {
82
139
  * @defaultValue true
83
140
  */
84
141
  waitForBackendConfig?: boolean;
142
+ /**
143
+ * Default attribution params (UTM / via / ref) appended to outbound
144
+ * sharing URLs. Per-call `displaySharingPage` overrides win, then backend
145
+ * config, then this SDK-level default. `utm_content` is intentionally
146
+ * excluded — it is per-content/per-product, never a merchant-wide default.
147
+ */
148
+ attribution?: AttributionDefaults;
85
149
  };
86
150
  /**
87
151
  * Custom i18n configuration for the modal
@@ -199,6 +263,12 @@ type ResolvedSdkConfig = {
199
263
  translations?: Record<string, string>;
200
264
  placements?: Record<string, ResolvedPlacement>; /** Global component defaults (used when no placement override exists) */
201
265
  components?: ResolvedPlacement["components"];
266
+ /**
267
+ * Default attribution params applied when building outbound sharing URLs.
268
+ * Per-call overrides win over these backend defaults; `utm_content` is
269
+ * intentionally excluded (per-content/per-product, never a merchant default).
270
+ */
271
+ attribution?: AttributionDefaults;
202
272
  };
203
273
  /**
204
274
  * Internal SDK config store state
@@ -221,7 +291,8 @@ type SdkResolvedConfig = {
221
291
  css?: string; /** Global translations (for reference / component fallback) */
222
292
  translations?: Record<string, string>; /** Named placements (keyed by placement ID) */
223
293
  placements?: Record<string, ResolvedPlacement>; /** Global component defaults (fallback for placement-level overrides) */
224
- components?: ResolvedPlacement["components"];
294
+ components?: ResolvedPlacement["components"]; /** Merged attribution defaults: backend > SDK static config */
295
+ attribution?: AttributionDefaults;
225
296
  };
226
297
  //#endregion
227
298
  //#region src/types/lifecycle/client.d.ts
@@ -276,6 +347,13 @@ type ResolvedConfigEvent = {
276
347
  * When present, listener should execute identity merge in background.
277
348
  */
278
349
  pendingMergeToken?: string;
350
+ /**
351
+ * Persistent per-origin anonymous id generated on the partner site
352
+ * (SDK-side localStorage). Propagated here so the listener can
353
+ * set it as an OpenPanel global property and stitch SDK events
354
+ * with listener events in the same funnel.
355
+ */
356
+ sdkAnonymousId?: string;
279
357
  sdkConfig?: ResolvedSdkConfig;
280
358
  };
281
359
  };
@@ -651,6 +729,11 @@ type SharingPageProduct = {
651
729
  * When provided and the product is selected, this link is used instead of the default sharing link
652
730
  */
653
731
  link?: string;
732
+ /**
733
+ * Optional `utm_content` value to apply when this product is selected.
734
+ * Falls back to the page-level `attribution.utmContent` when omitted.
735
+ */
736
+ utmContent?: string;
654
737
  };
655
738
  /**
656
739
  * Parameters to display the sharing page
@@ -668,6 +751,18 @@ type DisplaySharingPageParamsType = {
668
751
  * If not provided, the sharing link will be generated from the current page URL + merchant context
669
752
  */
670
753
  link?: string;
754
+ /**
755
+ * Optional attribution overrides for the outbound sharing URL.
756
+ *
757
+ * When provided (even as an empty object), Frak adds standard affiliation
758
+ * params (`utm_source=frak`, `utm_medium=referral`, `utm_campaign=<merchantId>`,
759
+ * `ref=<clientId>`, `via=frak`) alongside `fCtx`. Existing UTMs on the base
760
+ * URL are preserved (gap-fill). Set this to `null` to disable attribution
761
+ * params entirely (only `fCtx` is added).
762
+ *
763
+ * @default {} — defaults applied
764
+ */
765
+ attribution?: AttributionParams | null;
671
766
  /**
672
767
  * Optional metadata overrides for the sharing page
673
768
  */
@@ -856,7 +951,7 @@ type DisplayEmbeddedWalletResultType = {
856
951
  * @group RPC Schema
857
952
  */
858
953
  type SendInteractionParamsType = {
859
- type: "arrival"; /** @deprecated V1 legacy use referrerClientId for v2 */
954
+ type: "arrival"; /** Sharer wallet address. Accepted in both V1 (legacy, wallet-only) and V2 (authenticated sharer) contexts. */
860
955
  referrerWallet?: Address;
861
956
  referrerClientId?: string;
862
957
  referrerMerchantId?: string; /** Epoch seconds timestamp from the referral link creation */
@@ -1201,15 +1296,26 @@ type FrakContextV1 = {
1201
1296
  /** Referrer wallet address */r: Address;
1202
1297
  };
1203
1298
  /**
1204
- * V2 Frak Context — anonymous-first referral context.
1205
- * Contains the sharer's clientId, merchantId, and link creation timestamp.
1299
+ * V2 Frak Context — anonymous-first referral context with optional wallet.
1300
+ *
1301
+ * Carries merchant context (`m`) and creation timestamp (`t`) unconditionally.
1302
+ * Identifies the sharer via either the anonymous clientId (`c`) or, when the
1303
+ * sharer is authenticated, the stronger wallet identifier (`w`). A valid V2
1304
+ * context MUST contain at least one of `c` or `w`; both may be present when
1305
+ * a logged-in user shares a link (best attribution signal).
1306
+ *
1307
+ * `w` takes precedence as the source of truth because the wallet is bound to
1308
+ * the user's WebAuthn credential, survives localStorage clears, and is global
1309
+ * across merchants — unlike `c`, which is a per-browser UUID.
1310
+ *
1206
1311
  * @ignore
1207
1312
  */
1208
1313
  type FrakContextV2 = {
1209
- /** Version discriminator */v: 2; /** Sharer's anonymous clientId (UUID from localStorage) */
1210
- c: string; /** Merchant ID (UUID) */
1314
+ /** Version discriminator */v: 2; /** Merchant ID (UUID) */
1211
1315
  m: string; /** Link creation timestamp (epoch seconds) */
1212
- t: number;
1316
+ t: number; /** Sharer's anonymous clientId (UUID from localStorage). Optional when `w` is provided. */
1317
+ c?: string; /** Sharer's wallet address. Preferred source of truth when the sharer is authenticated. Optional when `c` is provided. */
1318
+ w?: Address;
1213
1319
  };
1214
1320
  /**
1215
1321
  * The current Frak Context — union of all versions.
@@ -1291,4 +1397,4 @@ declare const ssoPopupName = "frak-sso";
1291
1397
  */
1292
1398
  declare function openSso(client: FrakClient, args: OpenSsoParamsType): Promise<OpenSsoReturnType>;
1293
1399
  //#endregion
1294
- export { ResolvedPlacement as $, ModalRpcMetadata as A, LoginModalStepType as B, EmbeddedViewActionReferred as C, DisplaySharingPageResultType as D, DisplaySharingPageParamsType as E, SendTransactionReturnType as F, SsoMetadata as G, OpenSsoReturnType as H, SendTransactionTxType as I, ModalStepMetadata as J, FinalActionType as K, SiweAuthenticateModalStepType as L, ModalRpcStepsResultType as M, ModalStepTypes as N, SharingPageProduct as O, SendTransactionModalStepType as P, MerchantConfigResponse as Q, SiweAuthenticateReturnType as R, LoggedOutEmbeddedView as S, LoggedInEmbeddedView as T, PrepareSsoParamsType as U, OpenSsoParamsType as V, PrepareSsoReturnType as W, IFrameLifecycleEvent as X, InteractionTypeKey as Y, ClientLifecycleEvent as Z, RewardTier as _, FrakContextV1 as a, Language as at, DisplayEmbeddedWalletParamsType as b, isV2Context as c, IFrameTransport as d, ResolvedSdkConfig as et, IFrameRpcSchema as f, GetMerchantInformationReturnType as g, EstimatedReward as h, FrakContext as i, I18nConfig as it, ModalRpcStepsInput as j, DisplayModalParamsType as k, FrakClient as l, UserReferralStatusType as m, ssoPopupFeatures as n, Currency as nt, FrakContextV2 as o, LocalizedI18nConfig as ot, WalletStatusReturnType as p, FinalModalStepType as q, ssoPopupName as r, FrakWalletSdkConfig as rt, isV1Context as s, openSso as t, SdkResolvedConfig as tt, FrakLifecycleEvent as u, TokenAmountType as v, EmbeddedViewActionSharing as w, DisplayEmbeddedWalletResultType as x, SendInteractionParamsType as y, SiweAuthenticationParams as z };
1400
+ export { ResolvedPlacement as $, ModalRpcMetadata as A, LoginModalStepType as B, EmbeddedViewActionReferred as C, DisplaySharingPageResultType as D, DisplaySharingPageParamsType as E, SendTransactionReturnType as F, SsoMetadata as G, OpenSsoReturnType as H, SendTransactionTxType as I, ModalStepMetadata as J, FinalActionType as K, SiweAuthenticateModalStepType as L, ModalRpcStepsResultType as M, ModalStepTypes as N, SharingPageProduct as O, SendTransactionModalStepType as P, MerchantConfigResponse as Q, SiweAuthenticateReturnType as R, LoggedOutEmbeddedView as S, LoggedInEmbeddedView as T, PrepareSsoParamsType as U, OpenSsoParamsType as V, PrepareSsoReturnType as W, IFrameLifecycleEvent as X, InteractionTypeKey as Y, ClientLifecycleEvent as Z, RewardTier as _, FrakContextV1 as a, Language as at, DisplayEmbeddedWalletParamsType as b, isV2Context as c, AttributionParams as ct, IFrameTransport as d, UtmParams as dt, ResolvedSdkConfig as et, IFrameRpcSchema as f, GetMerchantInformationReturnType as g, EstimatedReward as h, FrakContext as i, I18nConfig as it, ModalRpcStepsInput as j, DisplayModalParamsType as k, FrakClient as l, TrackArrivalParams as lt, UserReferralStatusType as m, ssoPopupFeatures as n, Currency as nt, FrakContextV2 as o, LocalizedI18nConfig as ot, WalletStatusReturnType as p, FinalModalStepType as q, ssoPopupName as r, FrakWalletSdkConfig as rt, isV1Context as s, AttributionDefaults as st, openSso as t, SdkResolvedConfig as tt, FrakLifecycleEvent as u, TrackArrivalResult as ut, TokenAmountType as v, EmbeddedViewActionSharing as w, DisplayEmbeddedWalletResultType as x, SendInteractionParamsType as y, SiweAuthenticationParams as z };
@@ -0,0 +1 @@
1
+ import{bytesToHex as e,hexToBytes as t,isAddress as n,keccak256 as r,toHex as i}from"viem";import{jsonEncode as a}from"@frak-labs/frame-connector";const o=`frak-client-id`;function s(){return typeof crypto<`u`&&crypto.randomUUID?crypto.randomUUID():`xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`.replace(/[xy]/g,e=>{let t=Math.random()*16|0;return(e===`x`?t:t&3|8).toString(16)})}function c(){if(typeof window>`u`||!window.localStorage)return console.warn(`[Frak SDK] No Window / localStorage available to save the clientId`),s();let e=localStorage.getItem(o);return e||(e=s(),localStorage.setItem(o,e)),e}function l({domain:e}={}){return r(i((e??window.location.host).replace(`www.`,``)))}function u(e){return btoa(Array.from(e,e=>String.fromCharCode(e)).join(``)).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/,``)}function d(e){let t=e.length%4;return Uint8Array.from(atob(e.replace(/-/g,`+`).replace(/_/g,`/`).padEnd(e.length+(t===0?0:4-t),`=`)),e=>e.charCodeAt(0))}function f(e){return u(a(e))}function p(e,t,n,r,i,a){let o=f(m({redirectUrl:t.redirectUrl,directExit:t.directExit,lang:t.lang,merchantId:n,metadata:{name:r,css:a,logoUrl:t.metadata?.logoUrl,homepageLink:t.metadata?.homepageLink},clientId:i})),s=new URL(e);return s.pathname=`/sso`,s.searchParams.set(`p`,o),s.toString()}function m(e){return{r:e.redirectUrl,cId:e.clientId,d:e.directExit,l:e.lang,m:e.merchantId,md:{n:e.metadata?.name,css:e.metadata?.css,l:e.metadata?.logoUrl,h:e.metadata?.homepageLink}}}const h=`menubar=no,status=no,scrollbars=no,fullscreen=no,width=500, height=800`,g=`frak-sso`;async function ee(e,t){let{metadata:n,customizations:r,walletUrl:i}=e.config;if(t.openInSameWindow??!!t.redirectUrl)return await e.request({method:`frak_openSso`,params:[t,n.name,r?.css]});let a=t.ssoPopupUrl??p(i??`https://wallet.frak.id`,t,l(),n.name,c(),r?.css),o=window.open(a,g,h);if(!o)throw Error(`Popup was blocked. Please allow popups for this site.`);return o.focus(),await e.request({method:`frak_openSso`,params:[t,n.name,r?.css]})??{}}function te(e,t,n){if(!e){console.debug(`[Frak] No client provided, skipping event tracking`);return}try{e.openPanel?.track(t,n)}catch(e){console.debug(`[Frak] Failed to track event:`,t,e)}}const _=`https://backend.frak.id`;function ne(e){return e.includes(`localhost:3000`)||e.includes(`localhost:3010`)}function v(e){return ne(e)?`https://localhost:3030`:e.includes(`wallet-dev.frak.id`)||e.includes(`wallet.gcp-dev.frak.id`)?`https://backend.gcp-dev.frak.id`:_}function y(e){if(e)return v(e);if(typeof window<`u`){let e=window.FrakSetup?.client?.config?.walletUrl;if(e)return v(e)}return _}var b=class extends Map{maxSize;constructor(e){super(),this.maxSize=e}get(e){let t=super.get(e);return super.has(e)&&(super.delete(e),super.set(e,t)),t}set(e,t){if(super.has(e)&&super.delete(e),super.set(e,t),this.maxSize&&this.size>this.maxSize){let e=super.keys().next().value;e!==void 0&&super.delete(e)}return this}};const x=new b(1024),S=new b(1024),C=3e4,w=new b(1024);async function T(e,{cacheKey:t,cacheTime:n=C}){if(n>0){let e=S.get(t);if(e&&Date.now()-e.created<n)return e.data}let r=w.get(t);if(r&&Date.now()-r<1e3)throw Error(`Cache: ${t} recently failed, backing off`);let i=x.get(t);i||(i=e(),x.set(t,i));try{let e=await i;return S.set(t,{data:e,created:Date.now()}),w.delete(t),e}catch(e){throw w.set(t,Date.now()),e}finally{x.delete(t)}}function E(e){return{clear:()=>{x.delete(e),S.delete(e)},has:(t=C)=>{let n=S.get(e);return n?Date.now()-n.created<t:!1}}}function D(){x.clear(),S.clear(),w.clear()}function re(e){return`r`in e&&!(`v`in e)}function O(e){return`v`in e&&e.v===2}const k=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function A(e){return typeof e==`string`&&k.test(e)}function j(e){let t=e.replace(/-/g,``),n=new Uint8Array(16);for(let e=0;e<16;e++)n[e]=Number.parseInt(t.substring(e*2,e*2+2),16);return n}function M(e){let t=``;for(let n=0;n<16;n++)t+=e[n].toString(16).padStart(2,`0`);return`${t.slice(0,8)}-${t.slice(8,12)}-${t.slice(12,16)}-${t.slice(16,20)}-${t.slice(20,32)}`}function ie(e){if(!A(e.m)||!Number.isInteger(e.t)||e.t<0||e.t>4294967295)return null;let r=typeof e.c==`string`&&e.c.length>0,i=typeof e.w==`string`&&n(e.w);if(!r&&!i||r&&!A(e.c))return null;let a=new Uint8Array(21+(r?16:0)+(i?20:0)),o=new DataView(a.buffer,a.byteOffset,a.byteLength),s=0;return a[s++]=2|(r?16:0)|(i?32:0),a.set(j(e.m),s),s+=16,o.setUint32(s,e.t,!1),s+=4,r&&(a.set(j(e.c),s),s+=16),i&&(a.set(t(e.w),s),s+=20),a}function ae(t){if(t.length<21)return null;let r=t[0];if((r&15)!=2||r&192)return null;let i=(r&16)!=0,a=(r&32)!=0;if(!i&&!a)return null;let o=21+(i?16:0)+(a?20:0);if(t.length!==o)return null;let s=1,c=M(t.subarray(s,s+16));s+=16;let l=new DataView(t.buffer,t.byteOffset,t.byteLength).getUint32(s,!1);s+=4;let u={v:2,m:c,t:l};if(i&&(u.c=M(t.subarray(s,s+16)),s+=16),a){let r=e(t.subarray(s,s+20),{size:20});if(!n(r))return null;u.w=r,s+=20}return u}const N=`fCtx`;function P(e){if(e)try{if(O(e)){let t=ie(e);return t?u(t):void 0}return u(t(e.r))}catch(t){console.error(`Error compressing Frak context`,{e:t,context:e})}}function F(t){if(!(!t||t.length===0))try{let r=d(t);if(r.length!==20)return ae(r)||void 0;let i=e(r,{size:20});if(n(i))return{r:i}}catch(e){console.error(`Error decompressing Frak context`,{e,context:t})}}function I({url:e}){if(!e)return null;let t=new URL(e).searchParams.get(N);return t?F(t):null}const L=`frak`;function oe(e,t){let n=O(e);return{utm_source:t.utmSource??L,utm_medium:t.utmMedium??`referral`,utm_campaign:t.utmCampaign??(n?e.m:void 0),utm_content:t.utmContent,utm_term:t.utmTerm,via:t.via??L,ref:t.ref??(n?e.c:void 0)}}function se(e,t,n){let r=oe(t,n??{});for(let[t,n]of Object.entries(r))n===void 0||n===``||e.searchParams.has(t)||e.searchParams.set(t,n)}function R({url:e,context:t,attribution:n}){if(!e)return null;let r=P(t);if(!r)return null;let i=new URL(e);return i.searchParams.set(N,r),se(i,t,n),i.toString()}function z(e){let t=new URL(e);return t.searchParams.delete(N),t.toString()}function ce({url:e,context:t}){if(!window.location?.href||typeof window>`u`){console.error(`No window found, can't update context`);return}let n=e??window.location.href,r;r=t===null?z(n):R({url:n,context:t}),r&&window.history.replaceState(null,``,r.toString())}const B={compress:P,decompress:F,parse:I,update:R,remove:z,replaceUrl:ce},V=`__frakSdkConfig`,H=`frak-config-cache`,U=`frak-merchant-id`,W={key:H},G=typeof window<`u`;function K(){return{isResolved:!1,merchantId:``}}let q=null;function J(){if(!G)return null;try{let e=localStorage.getItem(W.key);if(!e)return null;let t=JSON.parse(e);return t.config?.isResolved?(q=t,t):null}catch{return null}}function Y(){return(q??J())?.config}function le(){let e=q??J();return e?Date.now()-e.timestamp<3e4:!1}function ue(e){if(!(!G||!e.isResolved))try{let t={config:e,timestamp:Date.now()};localStorage.setItem(W.key,JSON.stringify(t)),q=t}catch{}}function X(){if(G){q=null;try{localStorage.removeItem(W.key)}catch{}}}function de(){G&&(window[V]||(window[V]=Y()??K()))}de();function Z(){return G?window[V]??K():K()}function Q(e){G&&window.dispatchEvent(new CustomEvent(`frak:config`,{detail:e}))}function fe(e){return e??(G?window.location.hostname:``)}async function pe(e,t,n){try{let r=y(t),i=n?`&lang=${encodeURIComponent(n)}`:``,a=await fetch(`${r}/user/merchant/resolve?domain=${encodeURIComponent(e)}${i}`);if(!a.ok){console.warn(`[Frak SDK] Merchant lookup failed for domain ${e}: ${a.status}`);return}let o=await a.json();if(G)try{sessionStorage.setItem(U,o.merchantId)}catch{}return o}catch(e){console.warn(`[Frak SDK] Failed to fetch merchant config:`,e);return}}const $={getConfig:Z,get isResolved(){return Z().isResolved},get isCacheFresh(){return le()},setCacheScope(e,t){W.key=`${H}:${`${e}:${t??``}`}`,q=null},setConfig(e){if(G&&(window[V]=e),ue(e),Q(e),G&&e.merchantId)try{sessionStorage.setItem(U,e.merchantId)}catch{}},reset(){let e=Y()??K();G&&(window[V]=e),Q(e)},clearCache(){if(X(),D(),G)try{sessionStorage.removeItem(U)}catch{}},resolve(e,t,n){let r=fe(e);return r?T(async()=>{let e=await pe(r,t,n);if(!e)throw Error(`Config resolution returned empty`);return e},{cacheKey:`sdkConfig:${r}:${n??``}`,cacheTime:1/0}).catch(()=>void 0):Promise.resolve(void 0)},getMerchantId(){let e=Z();if(e.isResolved&&e.merchantId)return e.merchantId;if(G)try{return sessionStorage.getItem(U)??void 0}catch{}},async resolveMerchantId(e,t){return $.getMerchantId()||(await $.resolve(e,t))?.merchantId}};export{l as _,D as a,y as c,h as d,g as f,u as g,d as h,O as i,te as l,f as m,B as n,E as o,p,re as r,T as s,$ as t,ee as u,c as v};
@@ -0,0 +1 @@
1
+ let e=require(`viem`),t=require(`@frak-labs/frame-connector`);const n=`frak-client-id`;function r(){return typeof crypto<`u`&&crypto.randomUUID?crypto.randomUUID():`xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`.replace(/[xy]/g,e=>{let t=Math.random()*16|0;return(e===`x`?t:t&3|8).toString(16)})}function i(){if(typeof window>`u`||!window.localStorage)return console.warn(`[Frak SDK] No Window / localStorage available to save the clientId`),r();let e=localStorage.getItem(n);return e||(e=r(),localStorage.setItem(n,e)),e}function a({domain:t}={}){return(0,e.keccak256)((0,e.toHex)((t??window.location.host).replace(`www.`,``)))}function o(e){return btoa(Array.from(e,e=>String.fromCharCode(e)).join(``)).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/,``)}function s(e){let t=e.length%4;return Uint8Array.from(atob(e.replace(/-/g,`+`).replace(/_/g,`/`).padEnd(e.length+(t===0?0:4-t),`=`)),e=>e.charCodeAt(0))}function c(e){return o((0,t.jsonEncode)(e))}function l(e,t,n,r,i,a){let o=c(u({redirectUrl:t.redirectUrl,directExit:t.directExit,lang:t.lang,merchantId:n,metadata:{name:r,css:a,logoUrl:t.metadata?.logoUrl,homepageLink:t.metadata?.homepageLink},clientId:i})),s=new URL(e);return s.pathname=`/sso`,s.searchParams.set(`p`,o),s.toString()}function u(e){return{r:e.redirectUrl,cId:e.clientId,d:e.directExit,l:e.lang,m:e.merchantId,md:{n:e.metadata?.name,css:e.metadata?.css,l:e.metadata?.logoUrl,h:e.metadata?.homepageLink}}}const d=`menubar=no,status=no,scrollbars=no,fullscreen=no,width=500, height=800`,f=`frak-sso`;async function ee(e,t){let{metadata:n,customizations:r,walletUrl:o}=e.config;if(t.openInSameWindow??!!t.redirectUrl)return await e.request({method:`frak_openSso`,params:[t,n.name,r?.css]});let s=t.ssoPopupUrl??l(o??`https://wallet.frak.id`,t,a(),n.name,i(),r?.css),c=window.open(s,f,d);if(!c)throw Error(`Popup was blocked. Please allow popups for this site.`);return c.focus(),await e.request({method:`frak_openSso`,params:[t,n.name,r?.css]})??{}}function p(e,t,n){if(!e){console.debug(`[Frak] No client provided, skipping event tracking`);return}try{e.openPanel?.track(t,n)}catch(e){console.debug(`[Frak] Failed to track event:`,t,e)}}const m=`https://backend.frak.id`;function h(e){return e.includes(`localhost:3000`)||e.includes(`localhost:3010`)}function g(e){return h(e)?`https://localhost:3030`:e.includes(`wallet-dev.frak.id`)||e.includes(`wallet.gcp-dev.frak.id`)?`https://backend.gcp-dev.frak.id`:m}function _(e){if(e)return g(e);if(typeof window<`u`){let e=window.FrakSetup?.client?.config?.walletUrl;if(e)return g(e)}return m}var v=class extends Map{maxSize;constructor(e){super(),this.maxSize=e}get(e){let t=super.get(e);return super.has(e)&&(super.delete(e),super.set(e,t)),t}set(e,t){if(super.has(e)&&super.delete(e),super.set(e,t),this.maxSize&&this.size>this.maxSize){let e=super.keys().next().value;e!==void 0&&super.delete(e)}return this}};const y=new v(1024),b=new v(1024),x=3e4,S=new v(1024);async function C(e,{cacheKey:t,cacheTime:n=x}){if(n>0){let e=b.get(t);if(e&&Date.now()-e.created<n)return e.data}let r=S.get(t);if(r&&Date.now()-r<1e3)throw Error(`Cache: ${t} recently failed, backing off`);let i=y.get(t);i||(i=e(),y.set(t,i));try{let e=await i;return b.set(t,{data:e,created:Date.now()}),S.delete(t),e}catch(e){throw S.set(t,Date.now()),e}finally{y.delete(t)}}function w(e){return{clear:()=>{y.delete(e),b.delete(e)},has:(t=x)=>{let n=b.get(e);return n?Date.now()-n.created<t:!1}}}function T(){y.clear(),b.clear(),S.clear()}function te(e){return`r`in e&&!(`v`in e)}function E(e){return`v`in e&&e.v===2}const D=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function O(e){return typeof e==`string`&&D.test(e)}function k(e){let t=e.replace(/-/g,``),n=new Uint8Array(16);for(let e=0;e<16;e++)n[e]=Number.parseInt(t.substring(e*2,e*2+2),16);return n}function A(e){let t=``;for(let n=0;n<16;n++)t+=e[n].toString(16).padStart(2,`0`);return`${t.slice(0,8)}-${t.slice(8,12)}-${t.slice(12,16)}-${t.slice(16,20)}-${t.slice(20,32)}`}function j(t){if(!O(t.m)||!Number.isInteger(t.t)||t.t<0||t.t>4294967295)return null;let n=typeof t.c==`string`&&t.c.length>0,r=typeof t.w==`string`&&(0,e.isAddress)(t.w);if(!n&&!r||n&&!O(t.c))return null;let i=new Uint8Array(21+(n?16:0)+(r?20:0)),a=new DataView(i.buffer,i.byteOffset,i.byteLength),o=0;return i[o++]=2|(n?16:0)|(r?32:0),i.set(k(t.m),o),o+=16,a.setUint32(o,t.t,!1),o+=4,n&&(i.set(k(t.c),o),o+=16),r&&(i.set((0,e.hexToBytes)(t.w),o),o+=20),i}function ne(t){if(t.length<21)return null;let n=t[0];if((n&15)!=2||n&192)return null;let r=(n&16)!=0,i=(n&32)!=0;if(!r&&!i)return null;let a=21+(r?16:0)+(i?20:0);if(t.length!==a)return null;let o=1,s=A(t.subarray(o,o+16));o+=16;let c=new DataView(t.buffer,t.byteOffset,t.byteLength).getUint32(o,!1);o+=4;let l={v:2,m:s,t:c};if(r&&(l.c=A(t.subarray(o,o+16)),o+=16),i){let n=(0,e.bytesToHex)(t.subarray(o,o+20),{size:20});if(!(0,e.isAddress)(n))return null;l.w=n,o+=20}return l}const M=`fCtx`;function N(t){if(t)try{if(E(t)){let e=j(t);return e?o(e):void 0}return o((0,e.hexToBytes)(t.r))}catch(e){console.error(`Error compressing Frak context`,{e,context:t})}}function P(t){if(!(!t||t.length===0))try{let n=s(t);if(n.length!==20)return ne(n)||void 0;let r=(0,e.bytesToHex)(n,{size:20});if((0,e.isAddress)(r))return{r}}catch(e){console.error(`Error decompressing Frak context`,{e,context:t})}}function F({url:e}){if(!e)return null;let t=new URL(e).searchParams.get(M);return t?P(t):null}const I=`frak`;function L(e,t){let n=E(e);return{utm_source:t.utmSource??I,utm_medium:t.utmMedium??`referral`,utm_campaign:t.utmCampaign??(n?e.m:void 0),utm_content:t.utmContent,utm_term:t.utmTerm,via:t.via??I,ref:t.ref??(n?e.c:void 0)}}function R(e,t,n){let r=L(t,n??{});for(let[t,n]of Object.entries(r))n===void 0||n===``||e.searchParams.has(t)||e.searchParams.set(t,n)}function z({url:e,context:t,attribution:n}){if(!e)return null;let r=N(t);if(!r)return null;let i=new URL(e);return i.searchParams.set(M,r),R(i,t,n),i.toString()}function B(e){let t=new URL(e);return t.searchParams.delete(M),t.toString()}function re({url:e,context:t}){if(!window.location?.href||typeof window>`u`){console.error(`No window found, can't update context`);return}let n=e??window.location.href,r;r=t===null?B(n):z({url:n,context:t}),r&&window.history.replaceState(null,``,r.toString())}const V={compress:N,decompress:P,parse:F,update:z,remove:B,replaceUrl:re},H=`__frakSdkConfig`,U=`frak-config-cache`,W=`frak-merchant-id`,G={key:U},K=typeof window<`u`;function q(){return{isResolved:!1,merchantId:``}}let J=null;function Y(){if(!K)return null;try{let e=localStorage.getItem(G.key);if(!e)return null;let t=JSON.parse(e);return t.config?.isResolved?(J=t,t):null}catch{return null}}function X(){return(J??Y())?.config}function ie(){let e=J??Y();return e?Date.now()-e.timestamp<3e4:!1}function ae(e){if(!(!K||!e.isResolved))try{let t={config:e,timestamp:Date.now()};localStorage.setItem(G.key,JSON.stringify(t)),J=t}catch{}}function oe(){if(K){J=null;try{localStorage.removeItem(G.key)}catch{}}}function se(){K&&(window[H]||(window[H]=X()??q()))}se();function Z(){return K?window[H]??q():q()}function Q(e){K&&window.dispatchEvent(new CustomEvent(`frak:config`,{detail:e}))}function ce(e){return e??(K?window.location.hostname:``)}async function le(e,t,n){try{let r=_(t),i=n?`&lang=${encodeURIComponent(n)}`:``,a=await fetch(`${r}/user/merchant/resolve?domain=${encodeURIComponent(e)}${i}`);if(!a.ok){console.warn(`[Frak SDK] Merchant lookup failed for domain ${e}: ${a.status}`);return}let o=await a.json();if(K)try{sessionStorage.setItem(W,o.merchantId)}catch{}return o}catch(e){console.warn(`[Frak SDK] Failed to fetch merchant config:`,e);return}}const $={getConfig:Z,get isResolved(){return Z().isResolved},get isCacheFresh(){return ie()},setCacheScope(e,t){G.key=`${U}:${`${e}:${t??``}`}`,J=null},setConfig(e){if(K&&(window[H]=e),ae(e),Q(e),K&&e.merchantId)try{sessionStorage.setItem(W,e.merchantId)}catch{}},reset(){let e=X()??q();K&&(window[H]=e),Q(e)},clearCache(){if(oe(),T(),K)try{sessionStorage.removeItem(W)}catch{}},resolve(e,t,n){let r=ce(e);return r?C(async()=>{let e=await le(r,t,n);if(!e)throw Error(`Config resolution returned empty`);return e},{cacheKey:`sdkConfig:${r}:${n??``}`,cacheTime:1/0}).catch(()=>void 0):Promise.resolve(void 0)},getMerchantId(){let e=Z();if(e.isResolved&&e.merchantId)return e.merchantId;if(K)try{return sessionStorage.getItem(W)??void 0}catch{}},async resolveMerchantId(e,t){return $.getMerchantId()||(await $.resolve(e,t))?.merchantId}};Object.defineProperty(exports,`_`,{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return T}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,`d`,{enumerable:!0,get:function(){return d}}),Object.defineProperty(exports,`f`,{enumerable:!0,get:function(){return f}}),Object.defineProperty(exports,`g`,{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,`h`,{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return E}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,`m`,{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return V}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return w}}),Object.defineProperty(exports,`p`,{enumerable:!0,get:function(){return l}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return te}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return C}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return $}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return ee}}),Object.defineProperty(exports,`v`,{enumerable:!0,get:function(){return i}});
@@ -0,0 +1,13 @@
1
+ const e=require(`./sdkConfigStore-DDL_fjYX.cjs`);let t=require(`@frak-labs/frame-connector`),n=require(`@openpanel/web`);function r(n){return(0,t.jsonDecode)(e.h(n))}const i=`nexus-wallet-backup`,a=`frakwallet://`;function o(){let e=navigator.userAgent;return/Android/i.test(e)&&/Chrome\/\d+/i.test(e)}function s(e){return`intent://${e.slice(13)}#Intent;scheme=frakwallet;end`}function c(e,t){let n=t?.timeout??2500,r=!1,i=()=>{document.hidden&&(r=!0)};document.addEventListener(`visibilitychange`,i);let a=o()&&l(e)?s(e):e;window.location.href=a,setTimeout(()=>{document.removeEventListener(`visibilitychange`,i),r||t?.onFallback?.()},n)}function l(e){return e.startsWith(a)}const u={eur:`fr-FR`,usd:`en-US`,gbp:`en-GB`};function d(e){return e&&e in u?e:`eur`}function f(e){return e?u[e]??u.eur:u.eur}function p(e,t){let n=f(t),r=d(t);return e.toLocaleString(n,{style:`currency`,currency:r,minimumFractionDigits:0,maximumFractionDigits:2})}function m(e){return e?`${e}Amount`:`eurAmount`}const h={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 g({walletBaseUrl:t,config:n}){let r=document.querySelector(`#frak-wallet`);r&&r.remove();let i=document.createElement(`iframe`);i.id=h.id,i.name=h.name,i.allow=h.allow,i.style.zIndex=h.style.zIndex.toString(),_({iframe:i,isVisible:!1});let a=n?.walletUrl??t??`https://wallet.frak.id`,o=e.v();return i.src=`${a}/listener?clientId=${encodeURIComponent(o)}`,new Promise(e=>{i.addEventListener(`load`,()=>e(i)),document.body.appendChild(i)})}function _({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 v(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 y(){if(typeof navigator>`u`)return!1;let e=navigator.userAgent;return!!(/iPhone|iPad|iPod/i.test(e)||/Macintosh/i.test(e)&&navigator.maxTouchPoints>1)}const b=y();function x(){if(typeof navigator>`u`)return!1;let e=navigator.userAgent.toLowerCase();return e.includes(`instagram`)||e.includes(`fban`)||e.includes(`fbav`)||e.includes(`facebook`)}const S=x();function C(e){b&&e.startsWith(`https://`)?window.location.href=`x-safari-https://${e.slice(8)}`:b&&e.startsWith(`http://`)?window.location.href=`x-safari-http://${e.slice(7)}`:window.location.href=`https://backend.frak.id/common/social?u=${encodeURIComponent(e)}`}function w({perCall:e,defaults:t,productUtmContent:n}){if(e===null)return;let r=e!==void 0,i=t!==void 0&&Object.keys(t).length>0;if(!r&&!i&&!(n!==void 0&&n!==``))return;let a={...t,...e??{}},o=n??e?.utmContent;return o!==void 0&&o!==``?a.utmContent=o:delete a.utmContent,a}function T(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 E=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,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()}};const D=(()=>{if(typeof navigator>`u`)return!1;let e=navigator.userAgent;if(!(/iPhone|iPad|iPod/i.test(e)||/Macintosh/i.test(e)&&navigator.maxTouchPoints>1))return!1;let t=e.toLowerCase();return t.includes(`instagram`)||t.includes(`fban`)||t.includes(`fbav`)||t.includes(`facebook`)})();function O(e){e?localStorage.setItem(i,e):localStorage.removeItem(i)}function k(e,t){try{let n=new URL(e);if(!n.searchParams.has(`u`))return e;let r=M(window.location.href,t);return n.searchParams.delete(`u`),n.searchParams.append(`u`,r),n.toString()}catch{return e}}function A(e){let t=new URL(window.location.href);e&&t.searchParams.set(`fmt`,e);let n=t.protocol===`http:`?`x-safari-http`:`x-safari-https`;window.location.href=`${n}://${t.host}${t.pathname}${t.search}${t.hash}`}function j(e){return e.includes(`/common/social`)}function M(e,t){if(!t)return e;try{let n=new URL(e);return n.searchParams.set(`fmt`,t),n.toString()}catch{return`${e}${e.includes(`?`)?`&`:`?`}fmt=${encodeURIComponent(t)}`}}function N(e,t,n,r,i){if(i){let e=k(t,r);window.open(e,`_blank`);return}if(l(t)){let i=k(t,r);c(i,{onFallback:()=>{e.contentWindow?.postMessage({clientLifecycle:`deep-link-failed`,data:{originalUrl:i}},n)}})}else if(D&&j(t))A(r);else{let e=k(t,r);window.location.href=e}}function P({iframe:e,targetOrigin:n}){let r=new t.Deferred;return{handleEvent:t=>{if(!(`iframeLifecycle`in t))return;let{iframeLifecycle:a,data:o}=t;switch(a){case`connected`:r.resolve(!0);break;case`do-backup`:O(o.backup);break;case`remove-backup`:localStorage.removeItem(i);break;case`show`:case`hide`:_({iframe:e,isVisible:a===`show`});break;case`redirect`:N(e,o.baseRedirectUrl,n,o.mergeToken,o.openInNewTab);break}},isConnected:r.promise}}function F({config:r,iframe:i}){let a=r?.walletUrl??`https://wallet.frak.id`,o=typeof navigator<`u`?navigator.language?.split(`-`)[0]:void 0,s=r.metadata.lang??(o===`en`||o===`fr`?o:void 0),c=r.domain??(typeof window<`u`?window.location.hostname:``);e.t.setCacheScope(c,s),e.t.reset();let l=e.t.isCacheFresh?void 0:e.t.resolve(r.domain,r.walletUrl,s),u=P({iframe:i,targetOrigin:a}),d=new t.Deferred,f=Date.now(),p=new E(r,i);if(!i.contentWindow)throw new t.FrakRpcError(t.RpcErrorCodes.configError,`The iframe does not have a content window`);let m=(0,t.createRpcClient)({emittingTransport:i.contentWindow,listeningTransport:window,targetOrigin:a,middleware:[{async onRequest(e,n){if(!await u.isConnected)throw new t.FrakRpcError(t.RpcErrorCodes.clientNotConnected,`The iframe provider isn't connected yet`);return await d.promise,n}},{onRequest(e,t){return p.setLastRequest(e),t},onResponse(e,t){return p.setLastResponse(e,t),t}}],lifecycleHandlers:{iframeLifecycle:(e,t)=>{u.handleEvent(e)}}}),h=I(m,u),g=async()=>{h(),m.cleanup(),i.remove(),e.a(),e.t.clearCache(),e.t.reset()},_;{console.log(`[Frak SDK] Initializing OpenPanel`),_=new n.OpenPanel({apiUrl:`https://op-api.gcp.frak.id`,clientId:`f305d11d-b93b-487c-80d4-92deb7903e98`,trackScreenViews:!0,trackOutgoingLinks:!0,trackAttributes:!1,filter:({type:t,payload:n})=>(t!==`track`||!n?.properties||`sdkVersion`in n.properties||(n.properties={...n.properties,sdkVersion:`1.0.1`,userAnonymousClientId:e.v()}),!0)}),_.setGlobalProperties({sdkVersion:`1.0.1`,userAnonymousClientId:e.v()}),_.init(),_.track(`sdk_initialized`,{sdkVersion:`1.0.1`});let t=!1,r=setTimeout(()=>{t||(t=!0,_?.track(`sdk_iframe_handshake_failed`,{reason:`timeout`}))},3e4);u.isConnected.then(()=>{t||(t=!0,clearTimeout(r),_?.track(`sdk_iframe_connected`,{handshake_duration_ms:Date.now()-f}))}).catch(()=>{t||(t=!0,clearTimeout(r),_?.track(`sdk_iframe_handshake_failed`,{reason:`unknown`}))})}let v=L({config:r,rpcClient:m,lifecycleManager:u,configPromise:l,contextSent:d,openPanel:_}).then(()=>p.updateSetupStatus(!0)).catch(e=>{throw d.reject(e),e});return{config:r,debugInfo:p,waitForConnection:u.isConnected,waitForSetup:v,request:m.request,listenerRequest:m.listen,destroy:g,openPanel:_}}function I(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 L({config:t,rpcClient:n,lifecycleManager:r,configPromise:a,contextSent:o,openPanel:s}){await r.isConnected,T(n,r.isConnected);let c=new URL(window.location.href),l=c.searchParams.get(`fmt`)??void 0;l&&(c.searchParams.delete(`fmt`),window.history.replaceState({},``,c.toString()));let u=n=>{let r=n?.merchantId??t.metadata.merchantId??``,i=n?.domain??``,a=n?.allowedDomains??[],o=n?.sdkConfig,s=o?.attribution||t.attribution?{...t.attribution,...o?.attribution}:void 0;e.t.setConfig(o?{isResolved:!0,merchantId:r,domain:i,allowedDomains:a,hasRawSdkConfig:!0,name:o.name??t.metadata.name,logoUrl:o.logoUrl??t.metadata.logoUrl,homepageLink:o.homepageLink??t.metadata.homepageLink,lang:o.lang??t.metadata.lang,currency:o.currency??t.metadata.currency,hidden:o.hidden,css:o.css,translations:o.translations,placements:o.placements,components:o.components,attribution:s}:{isResolved:!0,merchantId:r,domain:i,allowedDomains:a,name:t.metadata.name,logoUrl:t.metadata.logoUrl,homepageLink:t.metadata.homepageLink,lang:t.metadata.lang,currency:t.metadata.currency,attribution:s})},d=!1,f=t=>{let r=d?void 0:l;d=!0;let i=t.hasRawSdkConfig?{name:t.name,logoUrl:t.logoUrl,homepageLink:t.homepageLink,lang:t.lang,currency:t.currency,hidden:t.hidden,css:t.css,translations:t.translations,placements:t.placements,attribution:t.attribution}:t.attribution?{attribution:t.attribution}:void 0,a=e.v();if(s){let e=s.global??{};s.setGlobalProperties({...e,merchantId:t.merchantId,domain:t.domain??``})}n.sendLifecycle({clientLifecycle:`resolved-config`,data:{merchantId:t.merchantId,domain:t.domain??``,allowedDomains:t.allowedDomains??[],sourceUrl:window.location.href,...a&&{sdkAnonymousId:a},...r&&{pendingMergeToken:r},...i&&{sdkConfig:i}}})};e.t.isResolved&&(f(e.t.getConfig()),o.resolve()),a&&(u(await a),f(e.t.getConfig()),o.resolve());async function p(){let e=t.customizations?.css;e&&n.sendLifecycle({clientLifecycle:`modal-css`,data:{cssLink:e}})}async function m(){let e=t.customizations?.i18n;e&&n.sendLifecycle({clientLifecycle:`modal-i18n`,data:{i18n:e}})}async function h(){if(typeof window>`u`)return;let e=window.localStorage.getItem(i);e&&n.sendLifecycle({clientLifecycle:`restore-backup`,data:{backup:e}})}(await Promise.allSettled([p(),m(),h()])).some(e=>e.status===`rejected`)&&s?.track(`sdk_iframe_handshake_failed`,{reason:`asset_push`})}async function R({config:e}){let t=z(e),n=await g({config:t});if(!n){console.error(`Failed to create iframe`);return}let r=F({config:t,iframe:n});if(await r.waitForSetup,!await r.waitForConnection){console.error(`Failed to connect to client`);return}return r}function z(e){let t=d(e.metadata?.currency);return{...e,metadata:{...e.metadata,currency:t}}}Object.defineProperty(exports,`_`,{enumerable:!0,get:function(){return l}}),Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return b}}),Object.defineProperty(exports,`b`,{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return h}}),Object.defineProperty(exports,`d`,{enumerable:!0,get:function(){return m}}),Object.defineProperty(exports,`f`,{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,`g`,{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,`h`,{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return w}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return g}}),Object.defineProperty(exports,`m`,{enumerable:!0,get:function(){return d}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return F}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return S}}),Object.defineProperty(exports,`p`,{enumerable:!0,get:function(){return f}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return E}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return C}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return R}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return v}}),Object.defineProperty(exports,`v`,{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,`x`,{enumerable:!0,get:function(){return r}}),Object.defineProperty(exports,`y`,{enumerable:!0,get:function(){return c}});
@@ -0,0 +1,13 @@
1
+ import{a as e,h as t,t as n,v as r}from"./sdkConfigStore-BXzz5PlK.js";import{Deferred as i,FrakRpcError as a,RpcErrorCodes as o,createRpcClient as s,jsonDecode as c}from"@frak-labs/frame-connector";import{OpenPanel as l}from"@openpanel/web";function u(e){return c(t(e))}const d=`nexus-wallet-backup`,f=`frakwallet://`;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;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(f)}const _={eur:`fr-FR`,usd:`en-US`,gbp:`en-GB`};function v(e){return e&&e in _?e:`eur`}function y(e){return e?_[e]??_.eur:_.eur}function b(e,t){let n=y(t),r=v(t);return e.toLocaleString(n,{style:`currency`,currency:r,minimumFractionDigits:0,maximumFractionDigits:2})}function x(e){return e?`${e}Amount`:`eurAmount`}const S={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 C({walletBaseUrl:e,config:t}){let n=document.querySelector(`#frak-wallet`);n&&n.remove();let i=document.createElement(`iframe`);i.id=S.id,i.name=S.name,i.allow=S.allow,i.style.zIndex=S.style.zIndex.toString(),w({iframe:i,isVisible:!1});let a=t?.walletUrl??e??`https://wallet.frak.id`,o=r();return i.src=`${a}/listener?clientId=${encodeURIComponent(o)}`,new Promise(e=>{i.addEventListener(`load`,()=>e(i)),document.body.appendChild(i)})}function w({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 T(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 E(){if(typeof navigator>`u`)return!1;let e=navigator.userAgent;return!!(/iPhone|iPad|iPod/i.test(e)||/Macintosh/i.test(e)&&navigator.maxTouchPoints>1)}const D=E();function O(){if(typeof navigator>`u`)return!1;let e=navigator.userAgent.toLowerCase();return e.includes(`instagram`)||e.includes(`fban`)||e.includes(`fbav`)||e.includes(`facebook`)}const k=O();function A(e){D&&e.startsWith(`https://`)?window.location.href=`x-safari-https://${e.slice(8)}`:D&&e.startsWith(`http://`)?window.location.href=`x-safari-http://${e.slice(7)}`:window.location.href=`https://backend.frak.id/common/social?u=${encodeURIComponent(e)}`}function j({perCall:e,defaults:t,productUtmContent:n}){if(e===null)return;let r=e!==void 0,i=t!==void 0&&Object.keys(t).length>0;if(!r&&!i&&!(n!==void 0&&n!==``))return;let a={...t,...e??{}},o=n??e?.utmContent;return o!==void 0&&o!==``?a.utmContent=o:delete a.utmContent,a}function M(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 N=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,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 a?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()}};const P=(()=>{if(typeof navigator>`u`)return!1;let e=navigator.userAgent;if(!(/iPhone|iPad|iPod/i.test(e)||/Macintosh/i.test(e)&&navigator.maxTouchPoints>1))return!1;let t=e.toLowerCase();return t.includes(`instagram`)||t.includes(`fban`)||t.includes(`fbav`)||t.includes(`facebook`)})();function F(e){e?localStorage.setItem(d,e):localStorage.removeItem(d)}function I(e,t){try{let n=new URL(e);if(!n.searchParams.has(`u`))return e;let r=z(window.location.href,t);return n.searchParams.delete(`u`),n.searchParams.append(`u`,r),n.toString()}catch{return e}}function L(e){let t=new URL(window.location.href);e&&t.searchParams.set(`fmt`,e);let n=t.protocol===`http:`?`x-safari-http`:`x-safari-https`;window.location.href=`${n}://${t.host}${t.pathname}${t.search}${t.hash}`}function R(e){return e.includes(`/common/social`)}function z(e,t){if(!t)return e;try{let n=new URL(e);return n.searchParams.set(`fmt`,t),n.toString()}catch{return`${e}${e.includes(`?`)?`&`:`?`}fmt=${encodeURIComponent(t)}`}}function B(e,t,n,r,i){if(i){let e=I(t,r);window.open(e,`_blank`);return}if(g(t)){let i=I(t,r);h(i,{onFallback:()=>{e.contentWindow?.postMessage({clientLifecycle:`deep-link-failed`,data:{originalUrl:i}},n)}})}else if(P&&R(t))L(r);else{let e=I(t,r);window.location.href=e}}function V({iframe:e,targetOrigin:t}){let n=new i;return{handleEvent:r=>{if(!(`iframeLifecycle`in r))return;let{iframeLifecycle:i,data:a}=r;switch(i){case`connected`:n.resolve(!0);break;case`do-backup`:F(a.backup);break;case`remove-backup`:localStorage.removeItem(d);break;case`show`:case`hide`:w({iframe:e,isVisible:i===`show`});break;case`redirect`:B(e,a.baseRedirectUrl,t,a.mergeToken,a.openInNewTab);break}},isConnected:n.promise}}function H({config:t,iframe:c}){let u=t?.walletUrl??`https://wallet.frak.id`,d=typeof navigator<`u`?navigator.language?.split(`-`)[0]:void 0,f=t.metadata.lang??(d===`en`||d===`fr`?d:void 0),p=t.domain??(typeof window<`u`?window.location.hostname:``);n.setCacheScope(p,f),n.reset();let m=n.isCacheFresh?void 0:n.resolve(t.domain,t.walletUrl,f),h=V({iframe:c,targetOrigin:u}),g=new i,_=Date.now(),v=new N(t,c);if(!c.contentWindow)throw new a(o.configError,`The iframe does not have a content window`);let y=s({emittingTransport:c.contentWindow,listeningTransport:window,targetOrigin:u,middleware:[{async onRequest(e,t){if(!await h.isConnected)throw new a(o.clientNotConnected,`The iframe provider isn't connected yet`);return await g.promise,t}},{onRequest(e,t){return v.setLastRequest(e),t},onResponse(e,t){return v.setLastResponse(e,t),t}}],lifecycleHandlers:{iframeLifecycle:(e,t)=>{h.handleEvent(e)}}}),b=U(y,h),x=async()=>{b(),y.cleanup(),c.remove(),e(),n.clearCache(),n.reset()},S;{console.log(`[Frak SDK] Initializing OpenPanel`),S=new l({apiUrl:`https://op-api.gcp.frak.id`,clientId:`f305d11d-b93b-487c-80d4-92deb7903e98`,trackScreenViews:!0,trackOutgoingLinks:!0,trackAttributes:!1,filter:({type:e,payload:t})=>(e!==`track`||!t?.properties||`sdkVersion`in t.properties||(t.properties={...t.properties,sdkVersion:`1.0.1`,userAnonymousClientId:r()}),!0)}),S.setGlobalProperties({sdkVersion:`1.0.1`,userAnonymousClientId:r()}),S.init(),S.track(`sdk_initialized`,{sdkVersion:`1.0.1`});let e=!1,t=setTimeout(()=>{e||(e=!0,S?.track(`sdk_iframe_handshake_failed`,{reason:`timeout`}))},3e4);h.isConnected.then(()=>{e||(e=!0,clearTimeout(t),S?.track(`sdk_iframe_connected`,{handshake_duration_ms:Date.now()-_}))}).catch(()=>{e||(e=!0,clearTimeout(t),S?.track(`sdk_iframe_handshake_failed`,{reason:`unknown`}))})}let C=W({config:t,rpcClient:y,lifecycleManager:h,configPromise:m,contextSent:g,openPanel:S}).then(()=>v.updateSetupStatus(!0)).catch(e=>{throw g.reject(e),e});return{config:t,debugInfo:v,waitForConnection:h.isConnected,waitForSetup:C,request:y.request,listenerRequest:y.listen,destroy:x,openPanel:S}}function U(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 W({config:e,rpcClient:t,lifecycleManager:i,configPromise:a,contextSent:o,openPanel:s}){await i.isConnected,M(t,i.isConnected);let c=new URL(window.location.href),l=c.searchParams.get(`fmt`)??void 0;l&&(c.searchParams.delete(`fmt`),window.history.replaceState({},``,c.toString()));let u=t=>{let r=t?.merchantId??e.metadata.merchantId??``,i=t?.domain??``,a=t?.allowedDomains??[],o=t?.sdkConfig,s=o?.attribution||e.attribution?{...e.attribution,...o?.attribution}:void 0;n.setConfig(o?{isResolved:!0,merchantId:r,domain:i,allowedDomains:a,hasRawSdkConfig:!0,name:o.name??e.metadata.name,logoUrl:o.logoUrl??e.metadata.logoUrl,homepageLink:o.homepageLink??e.metadata.homepageLink,lang:o.lang??e.metadata.lang,currency:o.currency??e.metadata.currency,hidden:o.hidden,css:o.css,translations:o.translations,placements:o.placements,components:o.components,attribution:s}:{isResolved:!0,merchantId:r,domain:i,allowedDomains:a,name:e.metadata.name,logoUrl:e.metadata.logoUrl,homepageLink:e.metadata.homepageLink,lang:e.metadata.lang,currency:e.metadata.currency,attribution:s})},f=!1,p=e=>{let n=f?void 0:l;f=!0;let i=e.hasRawSdkConfig?{name:e.name,logoUrl:e.logoUrl,homepageLink:e.homepageLink,lang:e.lang,currency:e.currency,hidden:e.hidden,css:e.css,translations:e.translations,placements:e.placements,attribution:e.attribution}:e.attribution?{attribution:e.attribution}:void 0,a=r();if(s){let t=s.global??{};s.setGlobalProperties({...t,merchantId:e.merchantId,domain:e.domain??``})}t.sendLifecycle({clientLifecycle:`resolved-config`,data:{merchantId:e.merchantId,domain:e.domain??``,allowedDomains:e.allowedDomains??[],sourceUrl:window.location.href,...a&&{sdkAnonymousId:a},...n&&{pendingMergeToken:n},...i&&{sdkConfig:i}}})};n.isResolved&&(p(n.getConfig()),o.resolve()),a&&(u(await a),p(n.getConfig()),o.resolve());async function m(){let n=e.customizations?.css;n&&t.sendLifecycle({clientLifecycle:`modal-css`,data:{cssLink:n}})}async function h(){let n=e.customizations?.i18n;n&&t.sendLifecycle({clientLifecycle:`modal-i18n`,data:{i18n:n}})}async function g(){if(typeof window>`u`)return;let e=window.localStorage.getItem(d);e&&t.sendLifecycle({clientLifecycle:`restore-backup`,data:{backup:e}})}(await Promise.allSettled([m(),h(),g()])).some(e=>e.status===`rejected`)&&s?.track(`sdk_iframe_handshake_failed`,{reason:`asset_push`})}async function G({config:e}){let t=K(e),n=await C({config:t});if(!n){console.error(`Failed to create iframe`);return}let r=H({config:t,iframe:n});if(await r.waitForSetup,!await r.waitForConnection){console.error(`Failed to connect to client`);return}return r}function K(e){let t=v(e.metadata?.currency);return{...e,metadata:{...e.metadata,currency:t}}}export{g as _,D as a,f as b,S as c,x as d,b as f,p as g,_ as h,j as i,C as l,v as m,H as n,k as o,y as p,N as r,A as s,G as t,T as u,m as v,u as x,h as y};
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "url": "https://twitter.com/QNivelais"
12
12
  }
13
13
  ],
14
- "version": "1.0.0",
14
+ "version": "1.0.1",
15
15
  "description": "Core SDK of the Frak wallet, low level library to interact directly with the frak ecosystem.",
16
16
  "repository": {
17
17
  "url": "https://github.com/frak-id/wallet",