@frak-labs/core-sdk 0.1.1 → 0.2.0-beta.514ef378

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 (125) hide show
  1. package/README.md +58 -0
  2. package/cdn/bundle.js +14 -0
  3. package/dist/actions.cjs +1 -1
  4. package/dist/actions.d.cts +3 -3
  5. package/dist/actions.d.ts +3 -3
  6. package/dist/actions.js +1 -1
  7. package/dist/bundle.cjs +1 -1
  8. package/dist/bundle.d.cts +4 -6
  9. package/dist/bundle.d.ts +4 -6
  10. package/dist/bundle.js +1 -1
  11. package/dist/{index-CRsQWnTs.d.cts → computeLegacyProductId-BkyJ4rEY.d.ts} +197 -10
  12. package/dist/{index-Ck1hudEi.d.ts → computeLegacyProductId-Raks6FXg.d.cts} +197 -10
  13. package/dist/index.cjs +1 -1
  14. package/dist/index.d.cts +3 -4
  15. package/dist/index.d.ts +3 -4
  16. package/dist/index.js +1 -1
  17. package/dist/{openSso-D--Airj6.d.cts → openSso-BCJGchIb.d.cts} +135 -131
  18. package/dist/{openSso-DsKJ4y0j.d.ts → openSso-DG-_9CED.d.ts} +135 -131
  19. package/dist/setupClient-BEiAE56h.js +13 -0
  20. package/dist/setupClient-Ls3vKSlH.cjs +13 -0
  21. package/dist/{index-d8xS4ryI.d.ts → siweAuthenticate-BH7Dn7nZ.d.cts} +90 -65
  22. package/dist/siweAuthenticate-BJHbtty4.js +1 -0
  23. package/dist/{index-C6FxkWPC.d.cts → siweAuthenticate-Btem4QHs.d.ts} +90 -65
  24. package/dist/siweAuthenticate-Cwj3HP0m.cjs +1 -0
  25. package/dist/trackEvent-M2RLTQ2p.js +1 -0
  26. package/dist/trackEvent-T_R9ER2S.cjs +1 -0
  27. package/package.json +11 -22
  28. package/src/actions/displayEmbeddedWallet.ts +1 -0
  29. package/src/actions/displayModal.test.ts +12 -11
  30. package/src/actions/displayModal.ts +7 -18
  31. package/src/actions/ensureIdentity.ts +68 -0
  32. package/src/actions/{getProductInformation.test.ts → getMerchantInformation.test.ts} +33 -50
  33. package/src/actions/getMerchantInformation.ts +16 -0
  34. package/src/actions/index.ts +3 -2
  35. package/src/actions/openSso.ts +4 -2
  36. package/src/actions/referral/processReferral.test.ts +42 -151
  37. package/src/actions/referral/processReferral.ts +18 -42
  38. package/src/actions/referral/referralInteraction.test.ts +1 -7
  39. package/src/actions/referral/referralInteraction.ts +1 -6
  40. package/src/actions/sendInteraction.ts +46 -22
  41. package/src/actions/trackPurchaseStatus.test.ts +354 -141
  42. package/src/actions/trackPurchaseStatus.ts +48 -11
  43. package/src/actions/watchWalletStatus.ts +2 -3
  44. package/src/actions/wrapper/modalBuilder.test.ts +0 -14
  45. package/src/actions/wrapper/modalBuilder.ts +3 -12
  46. package/src/bundle.ts +0 -1
  47. package/src/clients/createIFrameFrakClient.ts +10 -5
  48. package/src/clients/transports/iframeLifecycleManager.test.ts +163 -4
  49. package/src/clients/transports/iframeLifecycleManager.ts +172 -33
  50. package/src/constants/interactionTypes.ts +12 -41
  51. package/src/index.ts +24 -16
  52. package/src/types/config.ts +6 -0
  53. package/src/types/index.ts +13 -10
  54. package/src/types/lifecycle/client.ts +24 -1
  55. package/src/types/lifecycle/iframe.ts +6 -0
  56. package/src/types/rpc/displayModal.ts +2 -4
  57. package/src/types/rpc/embedded/index.ts +2 -2
  58. package/src/types/rpc/interaction.ts +26 -39
  59. package/src/types/rpc/merchantInformation.ts +77 -0
  60. package/src/types/rpc/modal/index.ts +0 -4
  61. package/src/types/rpc/modal/login.ts +5 -1
  62. package/src/types/rpc/walletStatus.ts +1 -7
  63. package/src/types/rpc.ts +22 -30
  64. package/src/types/tracking.ts +60 -0
  65. package/src/utils/backendUrl.test.ts +83 -0
  66. package/src/utils/backendUrl.ts +62 -0
  67. package/src/utils/clientId.test.ts +41 -0
  68. package/src/utils/clientId.ts +43 -0
  69. package/src/utils/compression/compress.test.ts +1 -1
  70. package/src/utils/compression/compress.ts +2 -2
  71. package/src/utils/compression/decompress.test.ts +8 -4
  72. package/src/utils/compression/decompress.ts +2 -2
  73. package/src/utils/{computeProductId.ts → computeLegacyProductId.ts} +2 -2
  74. package/src/utils/constants.ts +5 -0
  75. package/src/utils/deepLinkWithFallback.test.ts +243 -0
  76. package/src/utils/deepLinkWithFallback.ts +103 -0
  77. package/src/utils/formatAmount.ts +6 -0
  78. package/src/utils/iframeHelper.test.ts +18 -5
  79. package/src/utils/iframeHelper.ts +10 -3
  80. package/src/utils/index.ts +16 -1
  81. package/src/utils/merchantId.test.ts +653 -0
  82. package/src/utils/merchantId.ts +143 -0
  83. package/src/utils/sso.ts +18 -11
  84. package/src/utils/trackEvent.test.ts +23 -5
  85. package/src/utils/trackEvent.ts +13 -0
  86. package/cdn/bundle.iife.js +0 -14
  87. package/dist/actions-B5j-i1p0.cjs +0 -1
  88. package/dist/actions-q090Z0oR.js +0 -1
  89. package/dist/index-7OZ39x1U.d.ts +0 -195
  90. package/dist/index-zDq-VlKx.d.cts +0 -195
  91. package/dist/interaction-DMJ3ZfaF.d.cts +0 -45
  92. package/dist/interaction-KX1h9a7V.d.ts +0 -45
  93. package/dist/interactions-DnfM3oe0.js +0 -1
  94. package/dist/interactions-EIXhNLf6.cjs +0 -1
  95. package/dist/interactions.cjs +0 -1
  96. package/dist/interactions.d.cts +0 -2
  97. package/dist/interactions.d.ts +0 -2
  98. package/dist/interactions.js +0 -1
  99. package/dist/productTypes-BUkXJKZ7.cjs +0 -1
  100. package/dist/productTypes-CGb1MmBF.js +0 -1
  101. package/dist/src-1LQ4eLq5.js +0 -13
  102. package/dist/src-hW71KjPN.cjs +0 -13
  103. package/dist/trackEvent-CHnYa85W.js +0 -1
  104. package/dist/trackEvent-GuQm_1Nm.cjs +0 -1
  105. package/src/actions/getProductInformation.ts +0 -14
  106. package/src/actions/openSso.test.ts +0 -407
  107. package/src/actions/sendInteraction.test.ts +0 -219
  108. package/src/constants/interactionTypes.test.ts +0 -128
  109. package/src/constants/productTypes.test.ts +0 -130
  110. package/src/constants/productTypes.ts +0 -33
  111. package/src/interactions/index.ts +0 -5
  112. package/src/interactions/pressEncoder.test.ts +0 -215
  113. package/src/interactions/pressEncoder.ts +0 -53
  114. package/src/interactions/purchaseEncoder.test.ts +0 -291
  115. package/src/interactions/purchaseEncoder.ts +0 -99
  116. package/src/interactions/referralEncoder.test.ts +0 -170
  117. package/src/interactions/referralEncoder.ts +0 -47
  118. package/src/interactions/retailEncoder.test.ts +0 -107
  119. package/src/interactions/retailEncoder.ts +0 -37
  120. package/src/interactions/webshopEncoder.test.ts +0 -56
  121. package/src/interactions/webshopEncoder.ts +0 -30
  122. package/src/types/rpc/modal/openSession.ts +0 -25
  123. package/src/types/rpc/productInformation.ts +0 -59
  124. package/src/utils/computeProductId.test.ts +0 -80
  125. package/src/utils/sso.test.ts +0 -361
@@ -1,22 +1,16 @@
1
- /**
2
- * Tests for getProductInformation action
3
- * Tests fetching product information via RPC
4
- */
5
-
6
1
  import type { Address, Hex } from "viem";
7
2
  import { describe, expect, it, vi } from "../../tests/vitest-fixtures";
8
- import type { FrakClient, GetProductInformationReturnType } from "../types";
9
- import { getProductInformation } from "./getProductInformation";
3
+ import type { FrakClient, GetMerchantInformationReturnType } from "../types";
4
+ import { getMerchantInformation } from "./getMerchantInformation";
10
5
 
11
- describe("getProductInformation", () => {
6
+ describe("getMerchantInformation", () => {
12
7
  describe("success cases", () => {
13
8
  it("should call client.request with correct method", async () => {
14
- const mockResponse: GetProductInformationReturnType = {
9
+ const mockResponse: GetMerchantInformationReturnType = {
15
10
  id: "0x1234567890123456789012345678901234567890123456789012345678901234" as Hex,
16
11
  onChainMetadata: {
17
- name: "Test Product",
12
+ name: "Test Merchant",
18
13
  domain: "example.com",
19
- productTypes: ["press"],
20
14
  },
21
15
  rewards: [],
22
16
  };
@@ -25,20 +19,19 @@ describe("getProductInformation", () => {
25
19
  request: vi.fn().mockResolvedValue(mockResponse),
26
20
  } as unknown as FrakClient;
27
21
 
28
- await getProductInformation(mockClient);
22
+ await getMerchantInformation(mockClient);
29
23
 
30
24
  expect(mockClient.request).toHaveBeenCalledWith({
31
- method: "frak_getProductInformation",
25
+ method: "frak_getMerchantInformation",
32
26
  });
33
27
  });
34
28
 
35
- it("should return product information", async () => {
36
- const mockResponse: GetProductInformationReturnType = {
29
+ it("should return merchant information", async () => {
30
+ const mockResponse: GetMerchantInformationReturnType = {
37
31
  id: "0x1234567890123456789012345678901234567890123456789012345678901234" as Hex,
38
32
  onChainMetadata: {
39
- name: "Test Product",
33
+ name: "Test Merchant",
40
34
  domain: "example.com",
41
- productTypes: ["press"],
42
35
  },
43
36
  rewards: [],
44
37
  };
@@ -47,48 +40,40 @@ describe("getProductInformation", () => {
47
40
  request: vi.fn().mockResolvedValue(mockResponse),
48
41
  } as unknown as FrakClient;
49
42
 
50
- const result = await getProductInformation(mockClient);
43
+ const result = await getMerchantInformation(mockClient);
51
44
 
52
45
  expect(result).toEqual(mockResponse);
53
46
  });
54
47
 
55
- it("should return product information with rewards", async () => {
56
- const mockResponse: GetProductInformationReturnType = {
48
+ it("should return merchant information with rewards", async () => {
49
+ const mockResponse: GetMerchantInformationReturnType = {
57
50
  id: "0x1234567890123456789012345678901234567890123456789012345678901234" as Hex,
58
51
  onChainMetadata: {
59
- name: "Test Product",
52
+ name: "Test Merchant",
60
53
  domain: "example.com",
61
- productTypes: ["press", "purchase"],
62
- },
63
- maxReferrer: {
64
- amount: 100,
65
- eurAmount: 10,
66
- usdAmount: 12,
67
- gbpAmount: 9,
68
- },
69
- maxReferee: {
70
- amount: 50,
71
- eurAmount: 5,
72
- usdAmount: 6,
73
- gbpAmount: 4.5,
74
54
  },
75
55
  rewards: [
76
56
  {
77
57
  token: "0x1234567890123456789012345678901234567890" as Address,
78
- campaign:
79
- "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" as Address,
80
- interactionTypeKey: "press.readArticle",
58
+ campaignId: "campaign-1",
59
+ interactionTypeKey: "referral",
81
60
  referrer: {
82
- amount: 10,
83
- eurAmount: 1,
84
- usdAmount: 1.2,
85
- gbpAmount: 0.9,
61
+ payoutType: "fixed",
62
+ amount: {
63
+ amount: 10,
64
+ eurAmount: 1,
65
+ usdAmount: 1.2,
66
+ gbpAmount: 0.9,
67
+ },
86
68
  },
87
69
  referee: {
88
- amount: 5,
89
- eurAmount: 0.5,
90
- usdAmount: 0.6,
91
- gbpAmount: 0.45,
70
+ payoutType: "fixed",
71
+ amount: {
72
+ amount: 5,
73
+ eurAmount: 0.5,
74
+ usdAmount: 0.6,
75
+ gbpAmount: 0.45,
76
+ },
92
77
  },
93
78
  },
94
79
  ],
@@ -98,12 +83,10 @@ describe("getProductInformation", () => {
98
83
  request: vi.fn().mockResolvedValue(mockResponse),
99
84
  } as unknown as FrakClient;
100
85
 
101
- const result = await getProductInformation(mockClient);
86
+ const result = await getMerchantInformation(mockClient);
102
87
 
103
88
  expect(result).toEqual(mockResponse);
104
89
  expect(result.rewards).toHaveLength(1);
105
- expect(result.maxReferrer).toBeDefined();
106
- expect(result.maxReferee).toBeDefined();
107
90
  });
108
91
  });
109
92
 
@@ -114,7 +97,7 @@ describe("getProductInformation", () => {
114
97
  request: vi.fn().mockRejectedValue(error),
115
98
  } as unknown as FrakClient;
116
99
 
117
- await expect(getProductInformation(mockClient)).rejects.toThrow(
100
+ await expect(getMerchantInformation(mockClient)).rejects.toThrow(
118
101
  "RPC request failed"
119
102
  );
120
103
  });
@@ -125,7 +108,7 @@ describe("getProductInformation", () => {
125
108
  request: vi.fn().mockRejectedValue(error),
126
109
  } as unknown as FrakClient;
127
110
 
128
- await expect(getProductInformation(mockClient)).rejects.toThrow(
111
+ await expect(getMerchantInformation(mockClient)).rejects.toThrow(
129
112
  "Request timeout"
130
113
  );
131
114
  });
@@ -0,0 +1,16 @@
1
+ import type { FrakClient, GetMerchantInformationReturnType } from "../types";
2
+
3
+ /**
4
+ * Fetch the current merchant information (name, rewards, tiers) from the wallet iframe
5
+ * @param client - The current Frak Client
6
+ * @returns The merchant information including available reward tiers
7
+ *
8
+ * @see {@link @frak-labs/core-sdk!index.GetMerchantInformationReturnType | `GetMerchantInformationReturnType`} for the return type shape
9
+ */
10
+ export async function getMerchantInformation(
11
+ client: FrakClient
12
+ ): Promise<GetMerchantInformationReturnType> {
13
+ return await client.request({
14
+ method: "frak_getMerchantInformation",
15
+ });
16
+ }
@@ -1,6 +1,7 @@
1
1
  export { displayEmbeddedWallet } from "./displayEmbeddedWallet";
2
2
  export { displayModal } from "./displayModal";
3
- export { getProductInformation } from "./getProductInformation";
3
+ export { ensureIdentity } from "./ensureIdentity";
4
+ export { getMerchantInformation } from "./getMerchantInformation";
4
5
  export { openSso } from "./openSso";
5
6
  export { prepareSso } from "./prepareSso";
6
7
  export {
@@ -13,6 +14,7 @@ export { sendInteraction } from "./sendInteraction";
13
14
  // Helper to track the purchase status
14
15
  export { trackPurchaseStatus } from "./trackPurchaseStatus";
15
16
  export { watchWalletStatus } from "./watchWalletStatus";
17
+ // Modal wrappers
16
18
  export {
17
19
  type ModalBuilder,
18
20
  type ModalStepBuilder,
@@ -22,7 +24,6 @@ export {
22
24
  type SendTransactionParams,
23
25
  sendTransaction,
24
26
  } from "./wrapper/sendTransaction";
25
- // Modal wrappers
26
27
  export {
27
28
  type SiweAuthenticateModalParams,
28
29
  siweAuthenticate,
@@ -3,7 +3,8 @@ import type {
3
3
  OpenSsoParamsType,
4
4
  OpenSsoReturnType,
5
5
  } from "../types";
6
- import { computeProductId } from "../utils/computeProductId";
6
+ import { getClientId } from "../utils/clientId";
7
+ import { computeLegacyProductId } from "../utils/computeLegacyProductId";
7
8
  import { generateSsoUrl } from "../utils/sso";
8
9
 
9
10
  // SSO popup configuration
@@ -91,8 +92,9 @@ export async function openSso(
91
92
  generateSsoUrl(
92
93
  walletUrl ?? "https://wallet.frak.id",
93
94
  args,
94
- computeProductId(),
95
+ computeLegacyProductId(),
95
96
  metadata.name,
97
+ getClientId(),
96
98
  customizations?.css
97
99
  );
98
100
 
@@ -1,5 +1,5 @@
1
1
  import { FrakRpcError, RpcErrorCodes } from "@frak-labs/frame-connector";
2
- import type { Address, Hex } from "viem";
2
+ import type { Address } from "viem";
3
3
  import { vi } from "vitest"; // Keep vi from vitest for vi.mock() hoisting
4
4
  import {
5
5
  afterEach,
@@ -15,18 +15,13 @@ import type {
15
15
  } from "../../types";
16
16
  import { processReferral } from "./processReferral";
17
17
 
18
- // Mock computeProductId first
19
- vi.mock("../../utils/computeProductId", () => ({
20
- computeProductId: vi.fn(
21
- () =>
22
- "0x0000000000000000000000000000000000000000000000000000000000000001" as Hex
23
- ),
24
- }));
25
-
26
18
  // Mock dependencies
27
- vi.mock("../../index", () => ({
19
+ vi.mock("../displayEmbeddedWallet", () => ({
28
20
  displayEmbeddedWallet: vi.fn(),
29
- sendInteraction: vi.fn(),
21
+ }));
22
+
23
+ vi.mock("../sendInteraction", () => ({
24
+ sendInteraction: vi.fn().mockResolvedValue(undefined),
30
25
  }));
31
26
 
32
27
  vi.mock("../../utils", () => ({
@@ -34,22 +29,13 @@ vi.mock("../../utils", () => ({
34
29
  replaceUrl: vi.fn(),
35
30
  },
36
31
  trackEvent: vi.fn(),
37
- }));
38
-
39
- vi.mock("../../interactions", () => ({
40
- ReferralInteractionEncoder: {
41
- referred: vi.fn(({ referrer }: { referrer: Address }) => ({
42
- interactionData: `0x${referrer.slice(2)}` as Hex,
43
- handlerTypeDenominator: "0x01" as Hex,
44
- })),
45
- },
32
+ resolveMerchantId: vi.fn().mockResolvedValue(undefined),
46
33
  }));
47
34
 
48
35
  describe("processReferral", () => {
49
36
  let mockClient: FrakClient;
50
37
  let mockAddress: Address;
51
38
  let mockReferrerAddress: Address;
52
- let mockProductId: Hex;
53
39
  let mockWalletStatus: WalletStatusReturnType;
54
40
  let mockFrakContext: Partial<FrakContext>;
55
41
 
@@ -59,8 +45,6 @@ describe("processReferral", () => {
59
45
  mockAddress = "0x1234567890123456789012345678901234567890" as Address;
60
46
  mockReferrerAddress =
61
47
  "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" as Address;
62
- mockProductId =
63
- "0x0000000000000000000000000000000000000000000000000000000000000001" as Hex;
64
48
 
65
49
  mockClient = {
66
50
  openPanel: {
@@ -78,10 +62,6 @@ describe("processReferral", () => {
78
62
  mockWalletStatus = {
79
63
  key: "connected" as const,
80
64
  wallet: mockAddress,
81
- interactionSession: {
82
- startTimestamp: Date.now() - 3600000,
83
- endTimestamp: Date.now() + 3600000,
84
- },
85
65
  };
86
66
 
87
67
  mockFrakContext = {
@@ -102,16 +82,12 @@ describe("processReferral", () => {
102
82
  });
103
83
 
104
84
  it("should return 'no-referrer' when frakContext has no referrer", async () => {
105
- const utils = await import("../../utils");
106
-
107
85
  const result = await processReferral(mockClient, {
108
86
  walletStatus: mockWalletStatus,
109
87
  frakContext: {},
110
88
  });
111
89
 
112
90
  expect(result).toBe("no-referrer");
113
- // sendInteraction should not be called when there's no referrer
114
- expect(utils.FrakContextManager.replaceUrl).toHaveBeenCalled();
115
91
  });
116
92
 
117
93
  it("should return 'no-referrer' when frakContext is null", async () => {
@@ -121,7 +97,6 @@ describe("processReferral", () => {
121
97
  });
122
98
 
123
99
  expect(result).toBe("no-referrer");
124
- // sendInteraction should not be called when there's no referrer
125
100
  });
126
101
 
127
102
  it("should return 'self-referral' when referrer equals current wallet", async () => {
@@ -133,140 +108,99 @@ describe("processReferral", () => {
133
108
  });
134
109
 
135
110
  expect(result).toBe("self-referral");
136
- // sendInteraction should not be called for self-referrals
137
111
  });
138
112
 
139
113
  it("should successfully process referral when all conditions are met", async () => {
140
114
  const utils = await import("../../utils");
141
115
 
142
- // Mock client.request for sendInteraction
143
- vi.mocked(mockClient.request).mockResolvedValue({
144
- delegationId: "delegation-123",
145
- } as any);
146
-
147
116
  const result = await processReferral(mockClient, {
148
117
  walletStatus: mockWalletStatus,
149
118
  frakContext: mockFrakContext,
150
- productId: mockProductId,
151
119
  });
152
120
 
153
121
  expect(result).toBe("success");
154
122
 
155
- // sendInteraction uses client.request internally
156
- expect(mockClient.request).toHaveBeenCalled();
157
123
  expect(utils.trackEvent).toHaveBeenCalledWith(
158
124
  mockClient,
159
- "user_referred",
125
+ "user_referred_started",
126
+ {
127
+ properties: {
128
+ referrer: mockReferrerAddress,
129
+ walletStatus: "connected",
130
+ },
131
+ }
132
+ );
133
+
134
+ expect(utils.trackEvent).toHaveBeenCalledWith(
135
+ mockClient,
136
+ "user_referred_completed",
160
137
  {
161
138
  properties: {
139
+ status: "success",
162
140
  referrer: mockReferrerAddress,
141
+ wallet: mockAddress,
163
142
  },
164
143
  }
165
144
  );
166
145
  });
167
146
 
168
147
  it("should handle wallet not connected scenario", async () => {
169
- // Mock client.request for displayEmbeddedWallet and sendInteraction
170
- vi.mocked(mockClient.request)
171
- .mockResolvedValueOnce({
172
- wallet: mockAddress,
173
- } as any)
174
- .mockResolvedValueOnce({
175
- delegationId: "delegation-123",
176
- } as any);
177
-
178
- const result = await processReferral(mockClient, {
179
- walletStatus: undefined,
180
- frakContext: mockFrakContext,
181
- });
182
-
183
- expect(result).toBe("success");
184
- expect(mockClient.request).toHaveBeenCalled();
185
- });
148
+ const { displayEmbeddedWallet } = await import(
149
+ "../displayEmbeddedWallet"
150
+ );
186
151
 
187
- it("should handle missing interaction session", async () => {
188
- const statusWithoutSession: WalletStatusReturnType = {
189
- key: "connected" as const,
152
+ // Mock displayEmbeddedWallet to return a wallet
153
+ vi.mocked(displayEmbeddedWallet).mockResolvedValue({
190
154
  wallet: mockAddress,
191
- interactionSession: undefined,
192
- };
193
-
194
- // Mock client.request for displayEmbeddedWallet and sendInteraction
195
- vi.mocked(mockClient.request)
196
- .mockResolvedValueOnce({
197
- wallet: mockAddress,
198
- } as any)
199
- .mockResolvedValueOnce({
200
- delegationId: "delegation-123",
201
- } as any);
155
+ } as any);
202
156
 
203
157
  const result = await processReferral(mockClient, {
204
- walletStatus: statusWithoutSession,
158
+ walletStatus: undefined,
205
159
  frakContext: mockFrakContext,
206
160
  });
207
161
 
208
162
  expect(result).toBe("success");
209
- expect(mockClient.request).toHaveBeenCalled();
163
+ expect(displayEmbeddedWallet).toHaveBeenCalled();
210
164
  });
211
165
 
212
- it("should return 'error' when wallet connection fails", async () => {
166
+ it("should return 'no-wallet' when wallet connection fails", async () => {
167
+ const { displayEmbeddedWallet } = await import(
168
+ "../displayEmbeddedWallet"
169
+ );
170
+
213
171
  const error = new FrakRpcError(
214
172
  RpcErrorCodes.walletNotConnected,
215
173
  "Wallet not connected"
216
174
  );
217
- // Mock client.request to throw error for displayEmbeddedWallet
218
- vi.mocked(mockClient.request).mockRejectedValue(error);
175
+ vi.mocked(displayEmbeddedWallet).mockRejectedValue(error);
219
176
 
220
177
  const result = await processReferral(mockClient, {
221
178
  walletStatus: undefined,
222
179
  frakContext: mockFrakContext,
223
180
  });
224
181
 
225
- // The error gets caught and mapped
226
- expect(["error", "no-wallet", "success"]).toContain(result);
182
+ expect(result).toBe("no-wallet");
227
183
  });
228
184
 
229
- it("should return 'no-session' when interaction delegation fails", async () => {
230
- const error = new FrakRpcError(
231
- RpcErrorCodes.serverErrorForInteractionDelegation,
232
- "Server error"
185
+ it("should return 'error' for unknown errors", async () => {
186
+ const { displayEmbeddedWallet } = await import(
187
+ "../displayEmbeddedWallet"
233
188
  );
234
- // Mock client.request to throw error for sendInteraction
235
- vi.mocked(mockClient.request).mockRejectedValue(error);
236
189
 
237
- const result = await processReferral(mockClient, {
238
- walletStatus: mockWalletStatus,
239
- frakContext: mockFrakContext,
240
- });
241
-
242
- // sendInteraction is in Promise.allSettled, so errors are caught
243
- // The function might still succeed or return error depending on implementation
244
- expect(["no-session", "error", "success"]).toContain(result);
245
- });
246
-
247
- it("should return 'error' for unknown errors", async () => {
248
190
  const error = new Error("Unknown error");
249
- // Mock client.request to throw error for sendInteraction
250
- vi.mocked(mockClient.request).mockRejectedValue(error);
191
+ vi.mocked(displayEmbeddedWallet).mockRejectedValue(error);
251
192
 
252
193
  const result = await processReferral(mockClient, {
253
- walletStatus: mockWalletStatus,
194
+ walletStatus: undefined,
254
195
  frakContext: mockFrakContext,
255
196
  });
256
197
 
257
- // sendInteraction is called inside pushReferralInteraction which is inside Promise.allSettled
258
- // So the error might be caught and the function might still succeed
259
- expect(["error", "success"]).toContain(result);
198
+ expect(result).toBe("error");
260
199
  });
261
200
 
262
201
  it("should update URL context when alwaysAppendUrl is true", async () => {
263
202
  const utils = await import("../../utils");
264
203
 
265
- // Mock client.request for sendInteraction
266
- vi.mocked(mockClient.request).mockResolvedValue({
267
- delegationId: "delegation-123",
268
- } as any);
269
-
270
204
  await processReferral(mockClient, {
271
205
  walletStatus: mockWalletStatus,
272
206
  frakContext: mockFrakContext,
@@ -284,11 +218,6 @@ describe("processReferral", () => {
284
218
  it("should remove URL context when alwaysAppendUrl is false", async () => {
285
219
  const utils = await import("../../utils");
286
220
 
287
- // Mock client.request for sendInteraction
288
- vi.mocked(mockClient.request).mockResolvedValue({
289
- delegationId: "delegation-123",
290
- } as any);
291
-
292
221
  await processReferral(mockClient, {
293
222
  walletStatus: mockWalletStatus,
294
223
  frakContext: mockFrakContext,
@@ -306,11 +235,6 @@ describe("processReferral", () => {
306
235
  it("should remove URL context by default", async () => {
307
236
  const utils = await import("../../utils");
308
237
 
309
- // Mock client.request for sendInteraction
310
- vi.mocked(mockClient.request).mockResolvedValue({
311
- delegationId: "delegation-123",
312
- } as any);
313
-
314
238
  await processReferral(mockClient, {
315
239
  walletStatus: mockWalletStatus,
316
240
  frakContext: mockFrakContext,
@@ -321,37 +245,4 @@ describe("processReferral", () => {
321
245
  context: null,
322
246
  });
323
247
  });
324
-
325
- it("should handle sendInteraction failures gracefully", async () => {
326
- const utils = await import("../../utils");
327
-
328
- // Mock client.request to throw error only for sendInteraction call
329
- // Note: sendInteraction uses Promise.allSettled, so errors are caught
330
- // We use mockImplementation to ensure the rejection is properly handled
331
- // by returning a rejected promise that will be caught by Promise.allSettled
332
- vi.mocked(mockClient.request).mockImplementation(async (request) => {
333
- // Only reject for frak_sendInteraction calls (sendInteraction)
334
- if (request.method === "frak_sendInteraction") {
335
- // Return a rejected promise that will be caught by Promise.allSettled
336
- return Promise.reject(new Error("Network error"));
337
- }
338
- // For any other calls (e.g., displayEmbeddedWallet), resolve successfully
339
- return { delegationId: "delegation-123" } as any;
340
- });
341
- // trackEvent errors are also caught in Promise.allSettled
342
- // Even though trackEvent is synchronous (returns void), we return a rejected promise
343
- // so that Promise.allSettled can properly catch it without causing unhandled rejections
344
- vi.mocked(utils.trackEvent).mockImplementation(() => {
345
- return Promise.reject(new Error("Track failed")) as any;
346
- });
347
-
348
- const result = await processReferral(mockClient, {
349
- walletStatus: mockWalletStatus,
350
- frakContext: mockFrakContext,
351
- });
352
-
353
- // sendInteraction is in Promise.allSettled, so errors are caught
354
- // The function might still succeed or return error depending on implementation
355
- expect(["error", "success"]).toContain(result);
356
- });
357
248
  });