@frak-labs/core-sdk 1.0.2-beta.64c76510 → 1.0.2-beta.75bb63ae

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 (88) hide show
  1. package/README.md +0 -1
  2. package/package.json +4 -4
  3. package/src/actions/ensureIdentity.ts +3 -3
  4. package/src/actions/openSso.ts +4 -4
  5. package/src/actions/referral/processReferral.test.ts +38 -22
  6. package/src/actions/referral/processReferral.ts +6 -4
  7. package/src/actions/referral/referralInteraction.test.ts +7 -7
  8. package/src/actions/referral/referralInteraction.ts +1 -1
  9. package/src/actions/sendInteraction.ts +1 -1
  10. package/src/actions/trackPurchaseStatus.test.ts +4 -4
  11. package/src/actions/trackPurchaseStatus.ts +3 -3
  12. package/src/actions/wrapper/siweAuthenticate.test.ts +1 -5
  13. package/src/actions/wrapper/siweAuthenticate.ts +25 -1
  14. package/src/clients/createIFrameFrakClient.ts +5 -21
  15. package/src/clients/index.ts +0 -1
  16. package/src/clients/transports/iframeLifecycleManager.test.ts +10 -10
  17. package/src/clients/transports/iframeLifecycleManager.ts +3 -3
  18. package/src/config/index.ts +3 -0
  19. package/src/{utils → config}/sdkConfigStore.ts +1 -1
  20. package/src/{utils/constants.test.ts → constants.test.ts} +1 -6
  21. package/src/context/address.ts +76 -0
  22. package/src/{utils/FrakContext.test.ts → context/frakContext.test.ts} +4 -2
  23. package/src/{utils/FrakContext.ts → context/frakContext.ts} +4 -4
  24. package/src/{utils → context}/frakContextV2Codec.test.ts +1 -1
  25. package/src/{utils → context}/frakContextV2Codec.ts +6 -6
  26. package/src/context/index.ts +6 -0
  27. package/src/index.ts +17 -22
  28. package/src/stubs/rrweb.ts +8 -4
  29. package/src/types/client.ts +0 -3
  30. package/src/types/config.ts +11 -0
  31. package/src/types/index.ts +1 -0
  32. package/src/utils/{deepLinkWithFallback.ts → browser/deepLinkWithFallback.ts} +1 -1
  33. package/src/utils/{inAppBrowser.ts → browser/inAppBrowser.ts} +13 -0
  34. package/src/utils/browser/index.ts +13 -0
  35. package/src/utils/{formatAmount.test.ts → format/formatAmount.test.ts} +1 -1
  36. package/src/utils/{formatAmount.ts → format/formatAmount.ts} +1 -1
  37. package/src/utils/{getCurrencyAmountKey.test.ts → format/getCurrencyAmountKey.test.ts} +2 -2
  38. package/src/utils/{getCurrencyAmountKey.ts → format/getCurrencyAmountKey.ts} +1 -1
  39. package/src/utils/{getSupportedCurrency.test.ts → format/getSupportedCurrency.test.ts} +2 -2
  40. package/src/utils/{getSupportedCurrency.ts → format/getSupportedCurrency.ts} +2 -2
  41. package/src/utils/{getSupportedLocale.test.ts → format/getSupportedLocale.test.ts} +3 -3
  42. package/src/utils/{getSupportedLocale.ts → format/getSupportedLocale.ts} +2 -2
  43. package/src/utils/format/index.ts +4 -0
  44. package/src/utils/{iframeHelper.test.ts → iframe/iframeHelper.test.ts} +3 -3
  45. package/src/utils/{iframeHelper.ts → iframe/iframeHelper.ts} +3 -3
  46. package/src/utils/iframe/index.ts +6 -0
  47. package/src/utils/index.ts +31 -24
  48. package/src/utils/sso/index.ts +6 -0
  49. package/src/utils/{sso.ts → sso/sso.ts} +2 -2
  50. package/cdn/bundle.js +0 -14
  51. package/dist/actions-DihYM-OG.js +0 -1
  52. package/dist/actions-cYbmqewX.cjs +0 -1
  53. package/dist/actions.cjs +0 -1
  54. package/dist/actions.d.cts +0 -3
  55. package/dist/actions.d.ts +0 -3
  56. package/dist/actions.js +0 -1
  57. package/dist/bundle.cjs +0 -1
  58. package/dist/bundle.d.cts +0 -4
  59. package/dist/bundle.d.ts +0 -4
  60. package/dist/bundle.js +0 -1
  61. package/dist/index-BhBuaCRl.d.cts +0 -707
  62. package/dist/index-BsBbSMxk.d.cts +0 -646
  63. package/dist/index-CeX1Tl7W.d.ts +0 -707
  64. package/dist/index-quaxtKRh.d.ts +0 -646
  65. package/dist/index.cjs +0 -1
  66. package/dist/index.d.cts +0 -3
  67. package/dist/index.d.ts +0 -3
  68. package/dist/index.js +0 -1
  69. package/dist/openSso-DyUQew2K.d.ts +0 -1392
  70. package/dist/openSso-rQhLhPbq.d.cts +0 -1392
  71. package/dist/sdkConfigStore-BXzz5PlK.js +0 -1
  72. package/dist/sdkConfigStore-DDL_fjYX.cjs +0 -1
  73. package/dist/src-CMaRNkkJ.cjs +0 -13
  74. package/dist/src-DMFOQMm6.js +0 -13
  75. package/src/clients/DebugInfo.test.ts +0 -418
  76. package/src/clients/DebugInfo.ts +0 -182
  77. package/src/utils/computeLegacyProductId.ts +0 -11
  78. /package/src/{utils → clients}/ssoUrlListener.test.ts +0 -0
  79. /package/src/{utils → clients}/ssoUrlListener.ts +0 -0
  80. /package/src/{utils → config}/backendUrl.test.ts +0 -0
  81. /package/src/{utils → config}/backendUrl.ts +0 -0
  82. /package/src/{utils → config}/clientId.test.ts +0 -0
  83. /package/src/{utils → config}/clientId.ts +0 -0
  84. /package/src/{utils → config}/sdkConfigStore.test.ts +0 -0
  85. /package/src/{utils/constants.ts → constants.ts} +0 -0
  86. /package/src/{utils → context}/mergeAttribution.test.ts +0 -0
  87. /package/src/{utils → context}/mergeAttribution.ts +0 -0
  88. /package/src/utils/{deepLinkWithFallback.test.ts → browser/deepLinkWithFallback.test.ts} +0 -0
@@ -0,0 +1,76 @@
1
+ import type { Address } from "viem";
2
+
3
+ /**
4
+ * Address utilities — minimal, dependency-free replacements for the subset of
5
+ * `viem` helpers we used to import. Keeping these in-house lets the SDK ship
6
+ * without pulling viem's checksum/keccak/error chain into the bundle.
7
+ *
8
+ * Scope is intentionally narrow:
9
+ * - `isAddress`: shape-only validation (no EIP-55 checksum)
10
+ * - `areAddressesEqual`: case-insensitive equality
11
+ * - `addressToBytes` / `bytesToAddress`: fixed 20-byte conversion
12
+ */
13
+
14
+ /** Matches a 0x-prefixed 40-char hex string regardless of case. */
15
+ const ADDRESS_REGEX = /^0x[a-fA-F0-9]{40}$/;
16
+
17
+ /**
18
+ * Check whether a value is a syntactically valid Ethereum address.
19
+ *
20
+ * This intentionally skips EIP-55 checksum validation: the SDK never produces
21
+ * checksum-cased payloads, and downstream consumers (wallet, indexer) treat
22
+ * addresses case-insensitively. Avoiding the checksum path drops keccak256 +
23
+ * @noble/hashes from the bundle.
24
+ */
25
+ export function isAddress(value: unknown): value is Address {
26
+ return typeof value === "string" && ADDRESS_REGEX.test(value);
27
+ }
28
+
29
+ /**
30
+ * Case-insensitive equality check for two Ethereum addresses.
31
+ *
32
+ * Both inputs are assumed to be syntactically valid addresses; callers that
33
+ * receive untrusted input should validate via {@link isAddress} first.
34
+ */
35
+ export function areAddressesEqual(a: Address, b: Address): boolean {
36
+ return a.toLowerCase() === b.toLowerCase();
37
+ }
38
+
39
+ /**
40
+ * Decode a 20-byte Ethereum address into a fixed-size Uint8Array(20).
41
+ *
42
+ * Throws when the input is not exactly `0x` + 40 hex chars — callers wrap
43
+ * the call in try/catch (see {@link FrakContextManager.compress}) so any
44
+ * malformed input degrades to a graceful undefined return.
45
+ */
46
+ export function addressToBytes(address: Address): Uint8Array {
47
+ const bytes = new Uint8Array(20);
48
+ for (let i = 0; i < 20; i++) {
49
+ const byte = Number.parseInt(
50
+ address.substring(2 + i * 2, 4 + i * 2),
51
+ 16
52
+ );
53
+ if (Number.isNaN(byte)) {
54
+ throw new Error(`Invalid address: ${address}`);
55
+ }
56
+ bytes[i] = byte;
57
+ }
58
+ return bytes;
59
+ }
60
+
61
+ /** Lookup table avoids `padStart` overhead in the hot encode loop. */
62
+ const HEX_BYTE = /*#__PURE__*/ Array.from({ length: 256 }, (_, i) =>
63
+ i.toString(16).padStart(2, "0")
64
+ );
65
+
66
+ /**
67
+ * Encode a 20-byte Uint8Array (or a 20-byte subarray view) into a lowercase
68
+ * hex Ethereum address. The caller MUST guarantee `bytes.length === 20`.
69
+ */
70
+ export function bytesToAddress(bytes: Uint8Array): Address {
71
+ let out = "0x";
72
+ for (let i = 0; i < 20; i++) {
73
+ out += HEX_BYTE[bytes[i]];
74
+ }
75
+ return out as Address;
76
+ }
@@ -9,7 +9,7 @@ import {
9
9
  vi,
10
10
  } from "../../tests/vitest-fixtures";
11
11
  import type { FrakContextV1, FrakContextV2 } from "../types";
12
- import { FrakContextManager } from "./FrakContext";
12
+ import { FrakContextManager } from "./frakContext";
13
13
 
14
14
  describe("FrakContextManager", () => {
15
15
  let consoleErrorSpy: any;
@@ -144,7 +144,9 @@ describe("FrakContextManager", () => {
144
144
  const { encodeFrakContextV2 } = await import(
145
145
  "./frakContextV2Codec"
146
146
  );
147
- const { base64urlEncode } = await import("./compression/b64");
147
+ const { base64urlEncode } = await import(
148
+ "../utils/compression/b64"
149
+ );
148
150
  const encoded = encodeFrakContextV2(v2Context);
149
151
  expect(encoded).toBeDefined();
150
152
  const tampered = new Uint8Array(encoded as Uint8Array);
@@ -1,4 +1,3 @@
1
- import { type Address, bytesToHex, hexToBytes, isAddress } from "viem";
2
1
  import type {
3
2
  AttributionParams,
4
3
  FrakContext,
@@ -6,7 +5,8 @@ import type {
6
5
  FrakContextV2,
7
6
  } from "../types";
8
7
  import { isV2Context } from "../types";
9
- import { base64urlDecode, base64urlEncode } from "./compression/b64";
8
+ import { base64urlDecode, base64urlEncode } from "../utils/compression/b64";
9
+ import { addressToBytes, bytesToAddress, isAddress } from "./address";
10
10
  import { decodeFrakContextV2, encodeFrakContextV2 } from "./frakContextV2Codec";
11
11
 
12
12
  /**
@@ -34,7 +34,7 @@ function compress(context?: FrakContextV1 | FrakContextV2): string | undefined {
34
34
  }
35
35
 
36
36
  // V1 legacy: compress wallet address as raw bytes
37
- const bytes = hexToBytes(context.r);
37
+ const bytes = addressToBytes(context.r);
38
38
  return base64urlEncode(bytes);
39
39
  } catch (e) {
40
40
  console.error("Error compressing Frak context", { e, context });
@@ -64,7 +64,7 @@ function decompress(context?: string): FrakContext | undefined {
64
64
  return undefined;
65
65
  }
66
66
 
67
- const hex = bytesToHex(bytes, { size: 20 }) as Address;
67
+ const hex = bytesToAddress(bytes);
68
68
  if (isAddress(hex)) {
69
69
  return { r: hex };
70
70
  }
@@ -1,7 +1,7 @@
1
1
  import type { Address } from "viem";
2
2
  import { describe, expect, it } from "../../tests/vitest-fixtures";
3
3
  import type { FrakContextV2 } from "../types";
4
- import { base64urlEncode } from "./compression/b64";
4
+ import { base64urlEncode } from "../utils/compression/b64";
5
5
  import {
6
6
  decodeFrakContextV2,
7
7
  encodeFrakContextV2,
@@ -28,8 +28,9 @@
28
28
  *
29
29
  * @ignore
30
30
  */
31
- import { type Address, bytesToHex, hexToBytes, isAddress } from "viem";
31
+ import type { Address } from "viem";
32
32
  import type { FrakContextV2 } from "../types";
33
+ import { addressToBytes, bytesToAddress, isAddress } from "./address";
33
34
 
34
35
  const VERSION_V2 = 0x02;
35
36
  const VERSION_MASK = 0x0f;
@@ -111,7 +112,7 @@ export function encodeFrakContextV2(ctx: FrakContextV2): Uint8Array | null {
111
112
  }
112
113
 
113
114
  if (hasW) {
114
- buf.set(hexToBytes(ctx.w as Address), offset);
115
+ buf.set(addressToBytes(ctx.w as Address), offset);
115
116
  offset += ADDRESS_BYTES;
116
117
  }
117
118
 
@@ -165,10 +166,9 @@ export function decodeFrakContextV2(buf: Uint8Array): FrakContextV2 | null {
165
166
  }
166
167
 
167
168
  if (hasW) {
168
- const walletHex = bytesToHex(
169
- buf.subarray(offset, offset + ADDRESS_BYTES),
170
- { size: ADDRESS_BYTES }
171
- ) as Address;
169
+ const walletHex = bytesToAddress(
170
+ buf.subarray(offset, offset + ADDRESS_BYTES)
171
+ );
172
172
  if (!isAddress(walletHex)) return null;
173
173
  out.w = walletHex;
174
174
  offset += ADDRESS_BYTES;
@@ -0,0 +1,6 @@
1
+ export { areAddressesEqual } from "./address";
2
+ export { FrakContextManager } from "./frakContext";
3
+ export {
4
+ type MergeAttributionInput,
5
+ mergeAttribution,
6
+ } from "./mergeAttribution";
package/src/index.ts CHANGED
@@ -1,15 +1,22 @@
1
1
  // Clients
2
2
 
3
3
  export { ssoPopupFeatures, ssoPopupName } from "./actions/openSso";
4
+ export { createIFrameFrakClient, setupClient } from "./clients";
5
+ // Config (reactive merchant config + identity)
4
6
  export {
5
- createIFrameFrakClient,
6
- DebugInfoGatherer,
7
- setupClient,
8
- } from "./clients";
9
-
7
+ getBackendUrl,
8
+ getClientId,
9
+ sdkConfigStore,
10
+ } from "./config";
11
+ // Constants
12
+ export { DEEP_LINK_SCHEME } from "./constants";
10
13
  export type { InteractionTypeKey } from "./constants/interactionTypes";
11
- export { type LocalesKey, locales } from "./constants/locales";
12
-
14
+ // Context (FrakContext URL codec + attribution merge)
15
+ export {
16
+ FrakContextManager,
17
+ type MergeAttributionInput,
18
+ mergeAttribution,
19
+ } from "./context";
13
20
  // Types
14
21
  export type {
15
22
  AttributionDefaults,
@@ -48,6 +55,7 @@ export type {
48
55
  // Compression
49
56
  KeyProvider,
50
57
  Language,
58
+ ListenerPreloadOption,
51
59
  LocalizedI18nConfig,
52
60
  LoggedInEmbeddedView,
53
61
  LoggedOutEmbeddedView,
@@ -87,7 +95,7 @@ export type {
87
95
  UtmParams,
88
96
  WalletStatusReturnType,
89
97
  } from "./types";
90
- export { isV1Context, isV2Context } from "./types";
98
+
91
99
  // Utils
92
100
  export {
93
101
  type AppSpecificSsoMetadata,
@@ -97,30 +105,18 @@ export {
97
105
  type CompressedSsoData,
98
106
  clearAllCache,
99
107
  compressJsonToB64,
100
- createIframe,
101
- DEEP_LINK_SCHEME,
102
108
  type DeepLinkFallbackOptions,
103
109
  decompressJsonFromB64,
104
- FrakContextManager,
105
110
  type FullSsoParams,
106
111
  findIframeInOpener,
107
112
  formatAmount,
108
113
  generateSsoUrl,
109
- getBackendUrl,
110
- getCache,
111
- getClientId,
112
114
  getCurrencyAmountKey,
113
115
  getSupportedCurrency,
114
- getSupportedLocale,
115
- isChromiumAndroid,
116
- isFrakDeepLink,
117
116
  isInAppBrowser,
118
117
  isIOS,
119
- type MergeAttributionInput,
120
- mergeAttribution,
118
+ isMobile,
121
119
  redirectToExternalBrowser,
122
- sdkConfigStore,
123
- toAndroidIntentUrl,
124
120
  trackEvent,
125
121
  triggerDeepLinkWithFallback,
126
122
  withCache,
@@ -129,4 +125,3 @@ export type {
129
125
  SdkEventMap,
130
126
  SdkHandshakeFailureReason,
131
127
  } from "./utils/analytics";
132
- export { computeLegacyProductId } from "./utils/computeLegacyProductId";
@@ -1,8 +1,12 @@
1
1
  /**
2
- * Stub for rrweb. The @openpanel/web package statically imports `record` from
3
- * rrweb even when session replay is disabled. This stub replaces the module so
4
- * that rrweb is not included in the bundle.
5
- * @see https://github.com/Openpanel-dev/openpanel/issues/336
2
+ * Stub for rrweb. The IIFE/CDN bundles inline every dependency
3
+ * (alwaysBundle catch-all), which would also pull in rrweb via the dynamic
4
+ * `replay` chunk loaded by @openpanel/web. Session replay is disabled in our
5
+ * SDK, so we alias rrweb to a noop record() to keep the CDN bundle small.
6
+ *
7
+ * The NPM ESM/CJS builds don't need this alias: @openpanel/web 1.4.1+ loads
8
+ * rrweb through a dynamic `import("./replay-…")`, so consumers' bundlers can
9
+ * tree-shake / code-split it on their own.
6
10
  */
7
11
  export function record() {
8
12
  return () => {};
@@ -7,8 +7,5 @@ import type { IFrameTransport } from "./transport";
7
7
  */
8
8
  export type FrakClient = {
9
9
  config: FrakWalletSdkConfig;
10
- debugInfo: {
11
- formatDebugInfo: (error: Error | unknown | string) => string;
12
- };
13
10
  openPanel?: OpenPanel;
14
11
  } & IFrameTransport;
@@ -87,6 +87,11 @@ export type FrakWalletSdkConfig = {
87
87
  * excluded — it is per-content/per-product, never a merchant-wide default.
88
88
  */
89
89
  attribution?: AttributionDefaults;
90
+ /**
91
+ * Preload specific UI views inside the listener iframe for better UX.
92
+ * Default: ["sharing"]
93
+ */
94
+ preload?: ListenerPreloadOption[];
90
95
  };
91
96
 
92
97
  /**
@@ -126,6 +131,12 @@ export type I18nConfig =
126
131
  | Record<Language, LocalizedI18nConfig>
127
132
  | LocalizedI18nConfig;
128
133
 
134
+ /**
135
+ * Options for preloading the listener UI
136
+ * @category Config
137
+ */
138
+ export type ListenerPreloadOption = "modal" | "sharing";
139
+
129
140
  /**
130
141
  * A localized i18n config (inline objects only — URL-based i18n removed)
131
142
  * @category Config
@@ -12,6 +12,7 @@ export type {
12
12
  FrakWalletSdkConfig,
13
13
  I18nConfig,
14
14
  Language,
15
+ ListenerPreloadOption,
15
16
  LocalizedI18nConfig,
16
17
  } from "./config";
17
18
  // Utils
@@ -1,4 +1,4 @@
1
- import { DEEP_LINK_SCHEME } from "./constants";
1
+ import { DEEP_LINK_SCHEME } from "../../constants";
2
2
 
3
3
  /**
4
4
  * Options for deep link with fallback
@@ -16,6 +16,19 @@ function checkIsIOS(): boolean {
16
16
  */
17
17
  export const isIOS: boolean = checkIsIOS();
18
18
 
19
+ /**
20
+ * Check if the current device is a mobile device (iOS, iPadOS, Android,
21
+ * webOS, BlackBerry, IEMobile, Opera Mini). Reuses {@link isIOS} so the
22
+ * iPadOS-13+ Macintosh heuristic stays in one place.
23
+ */
24
+ export function isMobile(): boolean {
25
+ if (typeof navigator === "undefined") return false;
26
+ if (isIOS) return true;
27
+ return /Android|webOS|BlackBerry|IEMobile|Opera Mini/i.test(
28
+ navigator.userAgent
29
+ );
30
+ }
31
+
19
32
  /**
20
33
  * Check if the current browser is a social media in-app browser
21
34
  * (Instagram, Facebook WebView).
@@ -0,0 +1,13 @@
1
+ export {
2
+ type DeepLinkFallbackOptions,
3
+ isChromiumAndroid,
4
+ isFrakDeepLink,
5
+ toAndroidIntentUrl,
6
+ triggerDeepLinkWithFallback,
7
+ } from "./deepLinkWithFallback";
8
+ export {
9
+ isInAppBrowser,
10
+ isIOS,
11
+ isMobile,
12
+ redirectToExternalBrowser,
13
+ } from "./inAppBrowser";
@@ -3,7 +3,7 @@
3
3
  * Tests currency formatting with proper locale support
4
4
  */
5
5
 
6
- import { describe, expect, it } from "../../tests/vitest-fixtures";
6
+ import { describe, expect, it } from "../../../tests/vitest-fixtures";
7
7
  import { formatAmount } from "./formatAmount";
8
8
 
9
9
  describe("formatAmount", () => {
@@ -1,4 +1,4 @@
1
- import type { Currency } from "../types";
1
+ import type { Currency } from "../../types";
2
2
  import { getSupportedCurrency } from "./getSupportedCurrency";
3
3
  import { getSupportedLocale } from "./getSupportedLocale";
4
4
 
@@ -3,8 +3,8 @@
3
3
  * Tests currency amount key generation
4
4
  */
5
5
 
6
- import { describe, expect, it } from "../../tests/vitest-fixtures";
7
- import type { Currency } from "../types";
6
+ import { describe, expect, it } from "../../../tests/vitest-fixtures";
7
+ import type { Currency } from "../../types";
8
8
  import { getCurrencyAmountKey } from "./getCurrencyAmountKey";
9
9
 
10
10
  describe("getCurrencyAmountKey", () => {
@@ -1,4 +1,4 @@
1
- import type { Currency, TokenAmountType } from "../types";
1
+ import type { Currency, TokenAmountType } from "../../types";
2
2
 
3
3
  /**
4
4
  * Get the currency amount key for a given currency
@@ -3,8 +3,8 @@
3
3
  * Tests currency validation and fallback behavior
4
4
  */
5
5
 
6
- import { describe, expect, it } from "../../tests/vitest-fixtures";
7
- import type { Currency } from "../types";
6
+ import { describe, expect, it } from "../../../tests/vitest-fixtures";
7
+ import type { Currency } from "../../types";
8
8
  import { getSupportedCurrency } from "./getSupportedCurrency";
9
9
 
10
10
  describe("getSupportedCurrency", () => {
@@ -1,5 +1,5 @@
1
- import { locales } from "../constants/locales";
2
- import type { Currency } from "../types";
1
+ import { locales } from "../../constants/locales";
2
+ import type { Currency } from "../../types";
3
3
 
4
4
  /**
5
5
  * Get the supported currency for a given currency
@@ -3,9 +3,9 @@
3
3
  * Tests locale resolution from currency
4
4
  */
5
5
 
6
- import { describe, expect, it } from "../../tests/vitest-fixtures";
7
- import { locales } from "../constants/locales";
8
- import type { Currency } from "../types";
6
+ import { describe, expect, it } from "../../../tests/vitest-fixtures";
7
+ import { locales } from "../../constants/locales";
8
+ import type { Currency } from "../../types";
9
9
  import { getSupportedLocale } from "./getSupportedLocale";
10
10
 
11
11
  describe("getSupportedLocale", () => {
@@ -1,5 +1,5 @@
1
- import { type LocalesKey, locales } from "../constants/locales";
2
- import type { Currency } from "../types";
1
+ import { type LocalesKey, locales } from "../../constants/locales";
2
+ import type { Currency } from "../../types";
3
3
 
4
4
  /**
5
5
  * Get the supported locale for a given currency
@@ -0,0 +1,4 @@
1
+ export { formatAmount } from "./formatAmount";
2
+ export { getCurrencyAmountKey } from "./getCurrencyAmountKey";
3
+ export { getSupportedCurrency } from "./getSupportedCurrency";
4
+ export { getSupportedLocale } from "./getSupportedLocale";
@@ -1,6 +1,6 @@
1
1
  import { vi } from "vitest";
2
2
 
3
- vi.mock("./clientId", () => ({
3
+ vi.mock("../../config/clientId", () => ({
4
4
  getClientId: vi.fn(() => "mock-client-id-for-test"),
5
5
  }));
6
6
 
@@ -15,8 +15,8 @@ import {
15
15
  describe,
16
16
  expect,
17
17
  it,
18
- } from "../../tests/vitest-fixtures";
19
- import type { FrakWalletSdkConfig } from "../types";
18
+ } from "../../../tests/vitest-fixtures";
19
+ import type { FrakWalletSdkConfig } from "../../types";
20
20
  import {
21
21
  baseIframeProps,
22
22
  changeIframeVisibility,
@@ -1,6 +1,6 @@
1
- import type { FrakWalletSdkConfig } from "../types";
2
- import { getBackendUrl } from "./backendUrl";
3
- import { getClientId } from "./clientId";
1
+ import { getBackendUrl } from "../../config/backendUrl";
2
+ import { getClientId } from "../../config/clientId";
3
+ import type { FrakWalletSdkConfig } from "../../types";
4
4
 
5
5
  /**
6
6
  * Base props for the iframe
@@ -0,0 +1,6 @@
1
+ export {
2
+ baseIframeProps,
3
+ changeIframeVisibility,
4
+ createIframe,
5
+ findIframeInOpener,
6
+ } from "./iframeHelper";
@@ -1,42 +1,49 @@
1
+ // Generic, framework-agnostic utilities. Stateful concerns (config store,
2
+ // client identifiers) live in `src/config/`; URL/binary codecs for the
3
+ // referral context live in `src/context/`; SSO URL listener belongs to the
4
+ // iframe client lifecycle in `src/clients/`. Keep this surface narrow.
1
5
  export { Deferred } from "@frak-labs/frame-connector";
6
+
7
+ // Analytics
2
8
  export { trackEvent } from "./analytics";
3
- export { getBackendUrl } from "./backendUrl";
4
- export { clearAllCache, getCache, withCache } from "./cache";
5
- export { getClientId } from "./clientId";
6
- export { base64urlDecode, base64urlEncode } from "./compression/b64";
7
- export { compressJsonToB64 } from "./compression/compress";
8
- export { decompressJsonFromB64 } from "./compression/decompress";
9
- export { DEEP_LINK_SCHEME } from "./constants";
9
+ // Browser / deep linking
10
10
  export {
11
11
  type DeepLinkFallbackOptions,
12
12
  isChromiumAndroid,
13
13
  isFrakDeepLink,
14
14
  toAndroidIntentUrl,
15
15
  triggerDeepLinkWithFallback,
16
- } from "./deepLinkWithFallback";
17
- export { FrakContextManager } from "./FrakContext";
18
- export { formatAmount } from "./formatAmount";
19
- export { getCurrencyAmountKey } from "./getCurrencyAmountKey";
20
- export { getSupportedCurrency } from "./getSupportedCurrency";
21
- export { getSupportedLocale } from "./getSupportedLocale";
22
- export {
23
- baseIframeProps,
24
- createIframe,
25
- findIframeInOpener,
26
- } from "./iframeHelper";
16
+ } from "./browser/deepLinkWithFallback";
27
17
  export {
28
18
  isInAppBrowser,
29
19
  isIOS,
20
+ isMobile,
30
21
  redirectToExternalBrowser,
31
- } from "./inAppBrowser";
22
+ } from "./browser/inAppBrowser";
23
+ // Cache
24
+ export { clearAllCache, getCache, withCache } from "./cache";
25
+ // Compression / encoding
26
+ export { base64urlDecode, base64urlEncode } from "./compression/b64";
27
+ export { compressJsonToB64 } from "./compression/compress";
28
+ export { decompressJsonFromB64 } from "./compression/decompress";
29
+
30
+ // Formatting / i18n
31
+ export { formatAmount } from "./format/formatAmount";
32
+ export { getCurrencyAmountKey } from "./format/getCurrencyAmountKey";
33
+ export { getSupportedCurrency } from "./format/getSupportedCurrency";
34
+ export { getSupportedLocale } from "./format/getSupportedLocale";
35
+
36
+ // Iframe DOM helpers
32
37
  export {
33
- type MergeAttributionInput,
34
- mergeAttribution,
35
- } from "./mergeAttribution";
36
- export { sdkConfigStore } from "./sdkConfigStore";
38
+ baseIframeProps,
39
+ createIframe,
40
+ findIframeInOpener,
41
+ } from "./iframe/iframeHelper";
42
+
43
+ // SSO URL builder
37
44
  export {
38
45
  type AppSpecificSsoMetadata,
39
46
  type CompressedSsoData,
40
47
  type FullSsoParams,
41
48
  generateSsoUrl,
42
- } from "./sso";
49
+ } from "./sso/sso";
@@ -0,0 +1,6 @@
1
+ export {
2
+ type AppSpecificSsoMetadata,
3
+ type CompressedSsoData,
4
+ type FullSsoParams,
5
+ generateSsoUrl,
6
+ } from "./sso";
@@ -1,6 +1,6 @@
1
1
  import type { Hex } from "viem";
2
- import type { PrepareSsoParamsType, SsoMetadata } from "../types";
3
- import { compressJsonToB64 } from "./compression/compress";
2
+ import type { PrepareSsoParamsType, SsoMetadata } from "../../types";
3
+ import { compressJsonToB64 } from "../compression/compress";
4
4
 
5
5
  export type AppSpecificSsoMetadata = SsoMetadata & {
6
6
  name?: string;