@frak-labs/core-sdk 0.2.0 → 0.2.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 (43) hide show
  1. package/cdn/bundle.js +3 -3
  2. package/dist/actions.cjs +1 -1
  3. package/dist/actions.d.cts +2 -2
  4. package/dist/actions.d.ts +2 -2
  5. package/dist/actions.js +1 -1
  6. package/dist/bundle.cjs +1 -1
  7. package/dist/bundle.d.cts +4 -4
  8. package/dist/bundle.d.ts +4 -4
  9. package/dist/bundle.js +1 -1
  10. package/dist/{computeLegacyProductId-Raks6FXg.d.cts → computeLegacyProductId-CCAZvLa5.d.cts} +45 -46
  11. package/dist/{computeLegacyProductId-BkyJ4rEY.d.ts → computeLegacyProductId-b5cUWdAm.d.ts} +45 -46
  12. package/dist/index.cjs +1 -1
  13. package/dist/index.d.cts +3 -3
  14. package/dist/index.d.ts +3 -3
  15. package/dist/index.js +1 -1
  16. package/dist/{openSso-BCJGchIb.d.cts → openSso-B0g7-807.d.cts} +40 -7
  17. package/dist/{openSso-DG-_9CED.d.ts → openSso-CMzwvaCa.d.ts} +40 -7
  18. package/dist/setupClient-BduY6Sym.cjs +13 -0
  19. package/dist/setupClient-ftmdQ-I8.js +13 -0
  20. package/dist/siweAuthenticate-BWmI2_TN.cjs +1 -0
  21. package/dist/{siweAuthenticate-Btem4QHs.d.ts → siweAuthenticate-CVigMOxz.d.cts} +28 -32
  22. package/dist/{siweAuthenticate-BH7Dn7nZ.d.cts → siweAuthenticate-CnCZ7mok.d.ts} +28 -32
  23. package/dist/siweAuthenticate-zczqxm0a.js +1 -0
  24. package/dist/trackEvent-CeLFVzZn.js +1 -0
  25. package/dist/trackEvent-Ew5r5zfI.cjs +1 -0
  26. package/package.json +1 -1
  27. package/src/actions/referral/processReferral.test.ts +109 -125
  28. package/src/actions/referral/processReferral.ts +134 -180
  29. package/src/actions/referral/referralInteraction.test.ts +3 -5
  30. package/src/actions/referral/referralInteraction.ts +2 -7
  31. package/src/index.ts +3 -0
  32. package/src/types/context.ts +48 -6
  33. package/src/types/index.ts +2 -1
  34. package/src/types/rpc/interaction.ts +5 -0
  35. package/src/types/tracking.ts +5 -34
  36. package/src/utils/FrakContext.test.ts +270 -186
  37. package/src/utils/FrakContext.ts +78 -56
  38. package/dist/setupClient-CQrMDGyZ.js +0 -13
  39. package/dist/setupClient-Ccv3XxwL.cjs +0 -13
  40. package/dist/siweAuthenticate-BJHbtty4.js +0 -1
  41. package/dist/siweAuthenticate-Cwj3HP0m.cjs +0 -1
  42. package/dist/trackEvent-M2RLTQ2p.js +0 -1
  43. package/dist/trackEvent-T_R9ER2S.cjs +0 -1
@@ -1,6 +1,5 @@
1
- import { FrakRpcError, RpcErrorCodes } from "@frak-labs/frame-connector";
2
1
  import type { Address } from "viem";
3
- import { vi } from "vitest"; // Keep vi from vitest for vi.mock() hoisting
2
+ import { vi } from "vitest";
4
3
  import {
5
4
  afterEach,
6
5
  beforeEach,
@@ -11,15 +10,11 @@ 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 dependencies
19
- vi.mock("../displayEmbeddedWallet", () => ({
20
- displayEmbeddedWallet: vi.fn(),
21
- }));
22
-
23
18
  vi.mock("../sendInteraction", () => ({
24
19
  sendInteraction: vi.fn().mockResolvedValue(undefined),
25
20
  }));
@@ -30,21 +25,18 @@ vi.mock("../../utils", () => ({
30
25
  },
31
26
  trackEvent: vi.fn(),
32
27
  resolveMerchantId: vi.fn().mockResolvedValue(undefined),
28
+ getClientId: vi.fn().mockReturnValue("test-client-id"),
33
29
  }));
34
30
 
35
31
  describe("processReferral", () => {
36
32
  let mockClient: FrakClient;
37
33
  let mockAddress: Address;
38
- let mockReferrerAddress: Address;
39
34
  let mockWalletStatus: WalletStatusReturnType;
40
- let mockFrakContext: Partial<FrakContext>;
41
35
 
42
36
  beforeEach(async () => {
43
37
  vi.clearAllMocks();
44
38
 
45
39
  mockAddress = "0x1234567890123456789012345678901234567890" as Address;
46
- mockReferrerAddress =
47
- "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" as Address;
48
40
 
49
41
  mockClient = {
50
42
  openPanel: {
@@ -64,11 +56,6 @@ describe("processReferral", () => {
64
56
  wallet: mockAddress,
65
57
  };
66
58
 
67
- mockFrakContext = {
68
- r: mockReferrerAddress,
69
- };
70
-
71
- // Mock window.location
72
59
  Object.defineProperty(window, "location", {
73
60
  value: {
74
61
  href: "https://example.com/test",
@@ -81,15 +68,6 @@ describe("processReferral", () => {
81
68
  vi.clearAllMocks();
82
69
  });
83
70
 
84
- it("should return 'no-referrer' when frakContext has no referrer", async () => {
85
- const result = await processReferral(mockClient, {
86
- walletStatus: mockWalletStatus,
87
- frakContext: {},
88
- });
89
-
90
- expect(result).toBe("no-referrer");
91
- });
92
-
93
71
  it("should return 'no-referrer' when frakContext is null", async () => {
94
72
  const result = await processReferral(mockClient, {
95
73
  walletStatus: mockWalletStatus,
@@ -99,128 +77,148 @@ describe("processReferral", () => {
99
77
  expect(result).toBe("no-referrer");
100
78
  });
101
79
 
102
- it("should return 'self-referral' when referrer equals current wallet", async () => {
103
- const result = await processReferral(mockClient, {
104
- walletStatus: mockWalletStatus,
105
- frakContext: {
106
- r: mockAddress, // Same as wallet
107
- },
108
- });
109
-
110
- expect(result).toBe("self-referral");
111
- });
112
-
113
- it("should successfully process referral when all conditions are met", async () => {
114
- const utils = await import("../../utils");
80
+ describe("V2 context", () => {
81
+ const v2Context: FrakContextV2 = {
82
+ v: 2,
83
+ c: "referrer-client-id",
84
+ m: "merchant-uuid",
85
+ t: 1709654400,
86
+ };
115
87
 
116
- const result = await processReferral(mockClient, {
117
- walletStatus: mockWalletStatus,
118
- 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
+ });
119
117
  });
120
118
 
121
- expect(result).toBe("success");
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
122
 
123
- expect(utils.trackEvent).toHaveBeenCalledWith(
124
- mockClient,
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",
137
- {
138
- properties: {
139
- status: "success",
140
- referrer: mockReferrerAddress,
141
- wallet: mockAddress,
142
- },
143
- }
144
- );
145
- });
123
+ const v2SelfReferralContext: FrakContextV2 = {
124
+ v: 2,
125
+ c: "referrer-client-id",
126
+ m: "merchant-uuid",
127
+ t: 1709654400,
128
+ };
146
129
 
147
- it("should handle wallet not connected scenario", async () => {
148
- const { displayEmbeddedWallet } = await import(
149
- "../displayEmbeddedWallet"
150
- );
130
+ const result = await processReferral(mockClient, {
131
+ walletStatus: mockWalletStatus,
132
+ frakContext: v2SelfReferralContext,
133
+ });
151
134
 
152
- // Mock displayEmbeddedWallet to return a wallet
153
- vi.mocked(displayEmbeddedWallet).mockResolvedValue({
154
- wallet: mockAddress,
155
- } as any);
156
-
157
- const result = await processReferral(mockClient, {
158
- walletStatus: undefined,
159
- frakContext: mockFrakContext,
135
+ expect(result).toBe("self-referral");
136
+ vi.mocked(utils.getClientId).mockReturnValue("test-client-id");
160
137
  });
161
-
162
- expect(result).toBe("success");
163
- expect(displayEmbeddedWallet).toHaveBeenCalled();
164
138
  });
165
139
 
166
- it("should return 'no-wallet' when wallet connection fails", async () => {
167
- const { displayEmbeddedWallet } = await import(
168
- "../displayEmbeddedWallet"
169
- );
170
-
171
- const error = new FrakRpcError(
172
- RpcErrorCodes.walletNotConnected,
173
- "Wallet not connected"
174
- );
175
- vi.mocked(displayEmbeddedWallet).mockRejectedValue(error);
140
+ describe("V1 context (backward compat)", () => {
141
+ const v1Context: FrakContext = {
142
+ r: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" as Address,
143
+ };
176
144
 
177
- const result = await processReferral(mockClient, {
178
- walletStatus: undefined,
179
- frakContext: mockFrakContext,
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
+ );
180
165
  });
181
166
 
182
- expect(result).toBe("no-wallet");
183
- });
184
-
185
- it("should return 'error' for unknown errors", async () => {
186
- const { displayEmbeddedWallet } = await import(
187
- "../displayEmbeddedWallet"
188
- );
189
-
190
- const error = new Error("Unknown error");
191
- vi.mocked(displayEmbeddedWallet).mockRejectedValue(error);
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
+ });
192
174
 
193
- const result = await processReferral(mockClient, {
194
- walletStatus: undefined,
195
- frakContext: mockFrakContext,
175
+ expect(result).toBe("self-referral");
196
176
  });
197
-
198
- expect(result).toBe("error");
199
177
  });
200
178
 
201
179
  it("should update URL context when alwaysAppendUrl is true", async () => {
202
180
  const utils = await import("../../utils");
203
181
 
182
+ const v2Context: FrakContextV2 = {
183
+ v: 2,
184
+ c: "referrer-client-id",
185
+ m: "merchant-uuid",
186
+ t: 1709654400,
187
+ };
188
+
204
189
  await processReferral(mockClient, {
205
190
  walletStatus: mockWalletStatus,
206
- frakContext: mockFrakContext,
191
+ frakContext: v2Context,
207
192
  options: {
208
193
  alwaysAppendUrl: true,
209
194
  },
210
195
  });
211
196
 
197
+ expect(utils.getClientId()).toBe("test-client-id");
198
+
212
199
  expect(utils.FrakContextManager.replaceUrl).toHaveBeenCalledWith({
213
200
  url: window.location.href,
214
- context: { r: mockAddress },
201
+ context: expect.objectContaining({
202
+ v: 2,
203
+ c: "test-client-id",
204
+ m: "merchant-uuid",
205
+ }),
215
206
  });
216
207
  });
217
208
 
218
209
  it("should remove URL context when alwaysAppendUrl is false", async () => {
219
210
  const utils = await import("../../utils");
220
211
 
212
+ const v2Context: FrakContextV2 = {
213
+ v: 2,
214
+ c: "referrer-client-id",
215
+ m: "merchant-uuid",
216
+ t: 1709654400,
217
+ };
218
+
221
219
  await processReferral(mockClient, {
222
220
  walletStatus: mockWalletStatus,
223
- frakContext: mockFrakContext,
221
+ frakContext: v2Context,
224
222
  options: {
225
223
  alwaysAppendUrl: false,
226
224
  },
@@ -231,18 +229,4 @@ describe("processReferral", () => {
231
229
  context: null,
232
230
  });
233
231
  });
234
-
235
- it("should remove URL context by default", async () => {
236
- const utils = await import("../../utils");
237
-
238
- await processReferral(mockClient, {
239
- walletStatus: mockWalletStatus,
240
- frakContext: mockFrakContext,
241
- });
242
-
243
- expect(utils.FrakContextManager.replaceUrl).toHaveBeenCalledWith({
244
- url: window.location.href,
245
- context: null,
246
- });
247
- });
248
232
  });