@frak-labs/core-sdk 0.1.1 → 0.2.0-beta.7898df5b

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 (130) 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/computeLegacyProductId-CCAZvLa5.d.cts +537 -0
  12. package/dist/computeLegacyProductId-b5cUWdAm.d.ts +537 -0
  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-B0g7-807.d.cts} +173 -136
  18. package/dist/{openSso-DsKJ4y0j.d.ts → openSso-CMzwvaCa.d.ts} +173 -136
  19. package/dist/setupClient-BICl5fdX.js +13 -0
  20. package/dist/setupClient-nl8Dhh4V.cjs +13 -0
  21. package/dist/siweAuthenticate-BWmI2_TN.cjs +1 -0
  22. package/dist/{index-d8xS4ryI.d.ts → siweAuthenticate-CVigMOxz.d.cts} +113 -92
  23. package/dist/{index-C6FxkWPC.d.cts → siweAuthenticate-CnCZ7mok.d.ts} +113 -92
  24. package/dist/siweAuthenticate-zczqxm0a.js +1 -0
  25. package/dist/trackEvent-CeLFVzZn.js +1 -0
  26. package/dist/trackEvent-Ew5r5zfI.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 +117 -242
  37. package/src/actions/referral/processReferral.ts +134 -204
  38. package/src/actions/referral/referralInteraction.test.ts +4 -12
  39. package/src/actions/referral/referralInteraction.ts +3 -13
  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 +27 -16
  52. package/src/types/config.ts +6 -0
  53. package/src/types/context.ts +48 -6
  54. package/src/types/index.ts +15 -11
  55. package/src/types/lifecycle/client.ts +24 -1
  56. package/src/types/lifecycle/iframe.ts +6 -0
  57. package/src/types/rpc/displayModal.ts +2 -4
  58. package/src/types/rpc/embedded/index.ts +2 -2
  59. package/src/types/rpc/interaction.ts +31 -39
  60. package/src/types/rpc/merchantInformation.ts +77 -0
  61. package/src/types/rpc/modal/index.ts +0 -4
  62. package/src/types/rpc/modal/login.ts +5 -1
  63. package/src/types/rpc/walletStatus.ts +1 -7
  64. package/src/types/rpc.ts +22 -30
  65. package/src/types/tracking.ts +31 -0
  66. package/src/utils/FrakContext.test.ts +270 -186
  67. package/src/utils/FrakContext.ts +78 -56
  68. package/src/utils/backendUrl.test.ts +83 -0
  69. package/src/utils/backendUrl.ts +62 -0
  70. package/src/utils/clientId.test.ts +41 -0
  71. package/src/utils/clientId.ts +43 -0
  72. package/src/utils/compression/compress.test.ts +1 -1
  73. package/src/utils/compression/compress.ts +2 -2
  74. package/src/utils/compression/decompress.test.ts +8 -4
  75. package/src/utils/compression/decompress.ts +2 -2
  76. package/src/utils/{computeProductId.ts → computeLegacyProductId.ts} +2 -2
  77. package/src/utils/constants.ts +5 -0
  78. package/src/utils/deepLinkWithFallback.test.ts +243 -0
  79. package/src/utils/deepLinkWithFallback.ts +103 -0
  80. package/src/utils/formatAmount.ts +6 -0
  81. package/src/utils/iframeHelper.test.ts +18 -5
  82. package/src/utils/iframeHelper.ts +10 -3
  83. package/src/utils/index.ts +16 -1
  84. package/src/utils/merchantId.test.ts +653 -0
  85. package/src/utils/merchantId.ts +143 -0
  86. package/src/utils/sso.ts +18 -11
  87. package/src/utils/trackEvent.test.ts +23 -5
  88. package/src/utils/trackEvent.ts +13 -0
  89. package/cdn/bundle.iife.js +0 -14
  90. package/dist/actions-B5j-i1p0.cjs +0 -1
  91. package/dist/actions-q090Z0oR.js +0 -1
  92. package/dist/index-7OZ39x1U.d.ts +0 -195
  93. package/dist/index-CRsQWnTs.d.cts +0 -351
  94. package/dist/index-Ck1hudEi.d.ts +0 -351
  95. package/dist/index-zDq-VlKx.d.cts +0 -195
  96. package/dist/interaction-DMJ3ZfaF.d.cts +0 -45
  97. package/dist/interaction-KX1h9a7V.d.ts +0 -45
  98. package/dist/interactions-DnfM3oe0.js +0 -1
  99. package/dist/interactions-EIXhNLf6.cjs +0 -1
  100. package/dist/interactions.cjs +0 -1
  101. package/dist/interactions.d.cts +0 -2
  102. package/dist/interactions.d.ts +0 -2
  103. package/dist/interactions.js +0 -1
  104. package/dist/productTypes-BUkXJKZ7.cjs +0 -1
  105. package/dist/productTypes-CGb1MmBF.js +0 -1
  106. package/dist/src-1LQ4eLq5.js +0 -13
  107. package/dist/src-hW71KjPN.cjs +0 -13
  108. package/dist/trackEvent-CHnYa85W.js +0 -1
  109. package/dist/trackEvent-GuQm_1Nm.cjs +0 -1
  110. package/src/actions/getProductInformation.ts +0 -14
  111. package/src/actions/openSso.test.ts +0 -407
  112. package/src/actions/sendInteraction.test.ts +0 -219
  113. package/src/constants/interactionTypes.test.ts +0 -128
  114. package/src/constants/productTypes.test.ts +0 -130
  115. package/src/constants/productTypes.ts +0 -33
  116. package/src/interactions/index.ts +0 -5
  117. package/src/interactions/pressEncoder.test.ts +0 -215
  118. package/src/interactions/pressEncoder.ts +0 -53
  119. package/src/interactions/purchaseEncoder.test.ts +0 -291
  120. package/src/interactions/purchaseEncoder.ts +0 -99
  121. package/src/interactions/referralEncoder.test.ts +0 -170
  122. package/src/interactions/referralEncoder.ts +0 -47
  123. package/src/interactions/retailEncoder.test.ts +0 -107
  124. package/src/interactions/retailEncoder.ts +0 -37
  125. package/src/interactions/webshopEncoder.test.ts +0 -56
  126. package/src/interactions/webshopEncoder.ts +0 -30
  127. package/src/types/rpc/modal/openSession.ts +0 -25
  128. package/src/types/rpc/productInformation.ts +0 -59
  129. package/src/utils/computeProductId.test.ts +0 -80
  130. package/src/utils/sso.test.ts +0 -361
@@ -1,6 +1,5 @@
1
- import { FrakRpcError, RpcErrorCodes } from "@frak-labs/frame-connector";
2
- import type { Address, Hex } from "viem";
3
- import { vi } from "vitest"; // Keep vi from vitest for vi.mock() hoisting
1
+ import type { Address } from "viem";
2
+ import { vi } from "vitest";
4
3
  import {
5
4
  afterEach,
6
5
  beforeEach,
@@ -11,22 +10,13 @@ import {
11
10
  import type {
12
11
  FrakClient,
13
12
  FrakContext,
13
+ FrakContextV2,
14
14
  WalletStatusReturnType,
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
- // Mock dependencies
27
- vi.mock("../../index", () => ({
28
- displayEmbeddedWallet: vi.fn(),
29
- sendInteraction: vi.fn(),
18
+ vi.mock("../sendInteraction", () => ({
19
+ sendInteraction: vi.fn().mockResolvedValue(undefined),
30
20
  }));
31
21
 
32
22
  vi.mock("../../utils", () => ({
@@ -34,33 +24,19 @@ vi.mock("../../utils", () => ({
34
24
  replaceUrl: vi.fn(),
35
25
  },
36
26
  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
- },
27
+ resolveMerchantId: vi.fn().mockResolvedValue(undefined),
28
+ getClientId: vi.fn().mockReturnValue("test-client-id"),
46
29
  }));
47
30
 
48
31
  describe("processReferral", () => {
49
32
  let mockClient: FrakClient;
50
33
  let mockAddress: Address;
51
- let mockReferrerAddress: Address;
52
- let mockProductId: Hex;
53
34
  let mockWalletStatus: WalletStatusReturnType;
54
- let mockFrakContext: Partial<FrakContext>;
55
35
 
56
36
  beforeEach(async () => {
57
37
  vi.clearAllMocks();
58
38
 
59
39
  mockAddress = "0x1234567890123456789012345678901234567890" as Address;
60
- mockReferrerAddress =
61
- "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" as Address;
62
- mockProductId =
63
- "0x0000000000000000000000000000000000000000000000000000000000000001" as Hex;
64
40
 
65
41
  mockClient = {
66
42
  openPanel: {
@@ -78,17 +54,8 @@ describe("processReferral", () => {
78
54
  mockWalletStatus = {
79
55
  key: "connected" as const,
80
56
  wallet: mockAddress,
81
- interactionSession: {
82
- startTimestamp: Date.now() - 3600000,
83
- endTimestamp: Date.now() + 3600000,
84
- },
85
57
  };
86
58
 
87
- mockFrakContext = {
88
- r: mockReferrerAddress,
89
- };
90
-
91
- // Mock window.location
92
59
  Object.defineProperty(window, "location", {
93
60
  value: {
94
61
  href: "https://example.com/test",
@@ -101,19 +68,6 @@ describe("processReferral", () => {
101
68
  vi.clearAllMocks();
102
69
  });
103
70
 
104
- it("should return 'no-referrer' when frakContext has no referrer", async () => {
105
- const utils = await import("../../utils");
106
-
107
- const result = await processReferral(mockClient, {
108
- walletStatus: mockWalletStatus,
109
- frakContext: {},
110
- });
111
-
112
- expect(result).toBe("no-referrer");
113
- // sendInteraction should not be called when there's no referrer
114
- expect(utils.FrakContextManager.replaceUrl).toHaveBeenCalled();
115
- });
116
-
117
71
  it("should return 'no-referrer' when frakContext is null", async () => {
118
72
  const result = await processReferral(mockClient, {
119
73
  walletStatus: mockWalletStatus,
@@ -121,177 +75,150 @@ describe("processReferral", () => {
121
75
  });
122
76
 
123
77
  expect(result).toBe("no-referrer");
124
- // sendInteraction should not be called when there's no referrer
125
78
  });
126
79
 
127
- it("should return 'self-referral' when referrer equals current wallet", async () => {
128
- const result = await processReferral(mockClient, {
129
- walletStatus: mockWalletStatus,
130
- frakContext: {
131
- r: mockAddress, // Same as wallet
132
- },
133
- });
134
-
135
- expect(result).toBe("self-referral");
136
- // sendInteraction should not be called for self-referrals
137
- });
138
-
139
- it("should successfully process referral when all conditions are met", async () => {
140
- const utils = await import("../../utils");
141
-
142
- // Mock client.request for sendInteraction
143
- vi.mocked(mockClient.request).mockResolvedValue({
144
- delegationId: "delegation-123",
145
- } as any);
146
-
147
- const result = await processReferral(mockClient, {
148
- walletStatus: mockWalletStatus,
149
- frakContext: mockFrakContext,
150
- productId: mockProductId,
151
- });
152
-
153
- expect(result).toBe("success");
154
-
155
- // sendInteraction uses client.request internally
156
- expect(mockClient.request).toHaveBeenCalled();
157
- expect(utils.trackEvent).toHaveBeenCalledWith(
158
- mockClient,
159
- "user_referred",
160
- {
161
- properties: {
162
- referrer: mockReferrerAddress,
163
- },
164
- }
165
- );
166
- });
167
-
168
- 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
- });
186
-
187
- it("should handle missing interaction session", async () => {
188
- const statusWithoutSession: WalletStatusReturnType = {
189
- key: "connected" as const,
190
- wallet: mockAddress,
191
- interactionSession: undefined,
80
+ describe("V2 context", () => {
81
+ const v2Context: FrakContextV2 = {
82
+ v: 2,
83
+ c: "referrer-client-id",
84
+ m: "merchant-uuid",
85
+ t: 1709654400,
192
86
  };
193
87
 
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);
202
-
203
- const result = await processReferral(mockClient, {
204
- walletStatus: statusWithoutSession,
205
- frakContext: mockFrakContext,
206
- });
207
-
208
- expect(result).toBe("success");
209
- expect(mockClient.request).toHaveBeenCalled();
210
- });
211
-
212
- it("should return 'error' when wallet connection fails", async () => {
213
- const error = new FrakRpcError(
214
- RpcErrorCodes.walletNotConnected,
215
- "Wallet not connected"
216
- );
217
- // Mock client.request to throw error for displayEmbeddedWallet
218
- vi.mocked(mockClient.request).mockRejectedValue(error);
219
-
220
- const result = await processReferral(mockClient, {
221
- walletStatus: undefined,
222
- frakContext: mockFrakContext,
88
+ it("should successfully process v2 referral", async () => {
89
+ const utils = await import("../../utils");
90
+ const { sendInteraction } = await import("../sendInteraction");
91
+
92
+ const result = await processReferral(mockClient, {
93
+ walletStatus: mockWalletStatus,
94
+ frakContext: v2Context,
95
+ });
96
+
97
+ expect(result).toBe("success");
98
+
99
+ expect(utils.trackEvent).toHaveBeenCalledWith(
100
+ mockClient,
101
+ "user_referred_started",
102
+ {
103
+ properties: {
104
+ referrerClientId: "referrer-client-id",
105
+ walletStatus: "connected",
106
+ },
107
+ }
108
+ );
109
+
110
+ expect(sendInteraction).toHaveBeenCalledWith(mockClient, {
111
+ type: "arrival",
112
+ referrerClientId: "referrer-client-id",
113
+ referrerMerchantId: "merchant-uuid",
114
+ referralTimestamp: 1709654400,
115
+ landingUrl: "https://example.com/test",
116
+ });
117
+ });
118
+
119
+ it("should return 'self-referral' when v2 context has same clientId as current user", async () => {
120
+ const utils = await import("../../utils");
121
+ vi.mocked(utils.getClientId).mockReturnValue("referrer-client-id");
122
+
123
+ const v2SelfReferralContext: FrakContextV2 = {
124
+ v: 2,
125
+ c: "referrer-client-id",
126
+ m: "merchant-uuid",
127
+ t: 1709654400,
128
+ };
129
+
130
+ const result = await processReferral(mockClient, {
131
+ walletStatus: mockWalletStatus,
132
+ frakContext: v2SelfReferralContext,
133
+ });
134
+
135
+ expect(result).toBe("self-referral");
136
+ vi.mocked(utils.getClientId).mockReturnValue("test-client-id");
223
137
  });
224
-
225
- // The error gets caught and mapped
226
- expect(["error", "no-wallet", "success"]).toContain(result);
227
138
  });
228
139
 
229
- it("should return 'no-session' when interaction delegation fails", async () => {
230
- const error = new FrakRpcError(
231
- RpcErrorCodes.serverErrorForInteractionDelegation,
232
- "Server error"
233
- );
234
- // Mock client.request to throw error for sendInteraction
235
- vi.mocked(mockClient.request).mockRejectedValue(error);
236
-
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
- });
140
+ describe("V1 context (backward compat)", () => {
141
+ const v1Context: FrakContext = {
142
+ r: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" as Address,
143
+ };
246
144
 
247
- it("should return 'error' for unknown errors", async () => {
248
- const error = new Error("Unknown error");
249
- // Mock client.request to throw error for sendInteraction
250
- vi.mocked(mockClient.request).mockRejectedValue(error);
145
+ it("should successfully process v1 referral", async () => {
146
+ const utils = await import("../../utils");
147
+
148
+ const result = await processReferral(mockClient, {
149
+ walletStatus: mockWalletStatus,
150
+ frakContext: v1Context,
151
+ });
152
+
153
+ expect(result).toBe("success");
154
+
155
+ expect(utils.trackEvent).toHaveBeenCalledWith(
156
+ mockClient,
157
+ "user_referred_started",
158
+ {
159
+ properties: {
160
+ referrer: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
161
+ walletStatus: "connected",
162
+ },
163
+ }
164
+ );
165
+ });
166
+
167
+ it("should return 'self-referral' when v1 referrer matches current wallet", async () => {
168
+ const result = await processReferral(mockClient, {
169
+ walletStatus: mockWalletStatus,
170
+ frakContext: {
171
+ r: mockAddress,
172
+ },
173
+ });
251
174
 
252
- const result = await processReferral(mockClient, {
253
- walletStatus: mockWalletStatus,
254
- frakContext: mockFrakContext,
175
+ expect(result).toBe("self-referral");
255
176
  });
256
-
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);
260
177
  });
261
178
 
262
179
  it("should update URL context when alwaysAppendUrl is true", async () => {
263
180
  const utils = await import("../../utils");
264
181
 
265
- // Mock client.request for sendInteraction
266
- vi.mocked(mockClient.request).mockResolvedValue({
267
- delegationId: "delegation-123",
268
- } as any);
182
+ const v2Context: FrakContextV2 = {
183
+ v: 2,
184
+ c: "referrer-client-id",
185
+ m: "merchant-uuid",
186
+ t: 1709654400,
187
+ };
269
188
 
270
189
  await processReferral(mockClient, {
271
190
  walletStatus: mockWalletStatus,
272
- frakContext: mockFrakContext,
191
+ frakContext: v2Context,
273
192
  options: {
274
193
  alwaysAppendUrl: true,
275
194
  },
276
195
  });
277
196
 
197
+ expect(utils.getClientId()).toBe("test-client-id");
198
+
278
199
  expect(utils.FrakContextManager.replaceUrl).toHaveBeenCalledWith({
279
200
  url: window.location.href,
280
- context: { r: mockAddress },
201
+ context: expect.objectContaining({
202
+ v: 2,
203
+ c: "test-client-id",
204
+ m: "merchant-uuid",
205
+ }),
281
206
  });
282
207
  });
283
208
 
284
209
  it("should remove URL context when alwaysAppendUrl is false", async () => {
285
210
  const utils = await import("../../utils");
286
211
 
287
- // Mock client.request for sendInteraction
288
- vi.mocked(mockClient.request).mockResolvedValue({
289
- delegationId: "delegation-123",
290
- } as any);
212
+ const v2Context: FrakContextV2 = {
213
+ v: 2,
214
+ c: "referrer-client-id",
215
+ m: "merchant-uuid",
216
+ t: 1709654400,
217
+ };
291
218
 
292
219
  await processReferral(mockClient, {
293
220
  walletStatus: mockWalletStatus,
294
- frakContext: mockFrakContext,
221
+ frakContext: v2Context,
295
222
  options: {
296
223
  alwaysAppendUrl: false,
297
224
  },
@@ -302,56 +229,4 @@ describe("processReferral", () => {
302
229
  context: null,
303
230
  });
304
231
  });
305
-
306
- it("should remove URL context by default", async () => {
307
- const utils = await import("../../utils");
308
-
309
- // Mock client.request for sendInteraction
310
- vi.mocked(mockClient.request).mockResolvedValue({
311
- delegationId: "delegation-123",
312
- } as any);
313
-
314
- await processReferral(mockClient, {
315
- walletStatus: mockWalletStatus,
316
- frakContext: mockFrakContext,
317
- });
318
-
319
- expect(utils.FrakContextManager.replaceUrl).toHaveBeenCalledWith({
320
- url: window.location.href,
321
- context: null,
322
- });
323
- });
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
232
  });