@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,8 +1,3 @@
1
- /**
2
- * Tests for FrakContextManager utility
3
- * Tests Frak context compression, URL parsing, and management
4
- */
5
-
6
1
  import { mockWindowHistory } from "@frak-labs/test-foundation";
7
2
  import type { Address } from "viem";
8
3
  import {
@@ -13,7 +8,7 @@ import {
13
8
  it,
14
9
  vi,
15
10
  } from "../../tests/vitest-fixtures";
16
- import type { FrakContext } from "../types";
11
+ import type { FrakContextV1, FrakContextV2 } from "../types";
17
12
  import { FrakContextManager } from "./FrakContext";
18
13
 
19
14
  describe("FrakContextManager", () => {
@@ -29,244 +24,316 @@ describe("FrakContextManager", () => {
29
24
  consoleErrorSpy.mockRestore();
30
25
  });
31
26
 
32
- describe("compress", () => {
33
- it("should compress context with referrer address", () => {
34
- const context: Partial<FrakContext> = {
35
- r: "0x1234567890123456789012345678901234567890" as Address,
36
- };
27
+ describe("V2 context", () => {
28
+ const v2Context: FrakContextV2 = {
29
+ v: 2,
30
+ c: "test-client-id-uuid",
31
+ m: "merchant-uuid-1234",
32
+ t: 1709654400,
33
+ };
34
+
35
+ describe("compress", () => {
36
+ it("should compress v2 context with all fields", () => {
37
+ const result = FrakContextManager.compress(v2Context);
38
+
39
+ expect(result).toBeDefined();
40
+ expect(typeof result).toBe("string");
41
+ expect(result?.length).toBeGreaterThan(0);
42
+ expect(result).not.toMatch(/[+/=]/);
43
+ });
37
44
 
38
- const result = FrakContextManager.compress(context);
45
+ it("should return undefined when v2 context is missing clientId", () => {
46
+ const partial = { v: 2 as const, m: "m", t: 123 };
47
+ const result = FrakContextManager.compress(
48
+ partial as FrakContextV2
49
+ );
50
+ expect(result).toBeUndefined();
51
+ });
39
52
 
40
- expect(result).toBeDefined();
41
- expect(typeof result).toBe("string");
42
- expect(result?.length).toBeGreaterThan(0);
43
- // Base64url should not contain +, /, or =
44
- expect(result).not.toMatch(/[+/=]/);
45
- });
53
+ it("should return undefined when v2 context is missing merchantId", () => {
54
+ const partial = { v: 2 as const, c: "c", t: 123 };
55
+ const result = FrakContextManager.compress(
56
+ partial as FrakContextV2
57
+ );
58
+ expect(result).toBeUndefined();
59
+ });
46
60
 
47
- it("should return undefined when context has no referrer", () => {
48
- const context: Partial<FrakContext> = {};
61
+ it("should return undefined when v2 context is missing timestamp", () => {
62
+ const partial = { v: 2 as const, c: "c", m: "m" };
63
+ const result = FrakContextManager.compress(
64
+ partial as FrakContextV2
65
+ );
66
+ expect(result).toBeUndefined();
67
+ });
68
+ });
49
69
 
50
- const result = FrakContextManager.compress(context);
70
+ describe("decompress", () => {
71
+ it("should round-trip compress and decompress v2 context", () => {
72
+ const compressed = FrakContextManager.compress(v2Context);
73
+ const decompressed = FrakContextManager.decompress(compressed);
51
74
 
52
- expect(result).toBeUndefined();
75
+ expect(decompressed).toEqual(v2Context);
76
+ });
53
77
  });
54
78
 
55
- it("should return undefined when context is undefined", () => {
56
- const result = FrakContextManager.compress(undefined);
79
+ describe("parse", () => {
80
+ it("should parse URL with v2 fCtx parameter", () => {
81
+ const compressed = FrakContextManager.compress(v2Context);
82
+ const url = `https://example.com?fCtx=${compressed}`;
57
83
 
58
- expect(result).toBeUndefined();
84
+ const result = FrakContextManager.parse({ url });
85
+
86
+ expect(result).toBeDefined();
87
+ expect(result).toHaveProperty("v", 2);
88
+ const v2 = result as FrakContextV2;
89
+ expect(v2.c).toBe("test-client-id-uuid");
90
+ expect(v2.m).toBe("merchant-uuid-1234");
91
+ expect(v2.t).toBe(1709654400);
92
+ });
59
93
  });
60
94
 
61
- it("should handle compression errors gracefully", () => {
62
- const invalidContext = {
63
- r: "invalid-address" as Address,
64
- };
95
+ describe("update", () => {
96
+ it("should add v2 fCtx to URL", () => {
97
+ const url = "https://example.com";
65
98
 
66
- const result = FrakContextManager.compress(invalidContext);
99
+ const result = FrakContextManager.update({
100
+ url,
101
+ context: v2Context,
102
+ });
67
103
 
68
- expect(consoleErrorSpy).toHaveBeenCalled();
69
- expect(result).toBeUndefined();
70
- });
71
- });
104
+ expect(result).toBeDefined();
105
+ expect(result).toContain("fCtx=");
106
+ expect(result).toContain("https://example.com");
72
107
 
73
- describe("decompress", () => {
74
- it("should decompress valid base64url context", () => {
75
- // First compress a context
76
- const originalContext: FrakContext = {
77
- r: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" as Address,
78
- };
79
- const compressed = FrakContextManager.compress(originalContext);
108
+ const parsed = FrakContextManager.parse({ url: result! });
109
+ expect(parsed).toEqual(v2Context);
110
+ });
80
111
 
81
- // Then decompress it
82
- const result = FrakContextManager.decompress(compressed);
112
+ it("should preserve other URL parameters", () => {
113
+ const url = "https://example.com?foo=bar&baz=qux";
83
114
 
84
- expect(result).toBeDefined();
85
- expect(result?.r).toBe(
86
- "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"
87
- );
115
+ const result = FrakContextManager.update({
116
+ url,
117
+ context: v2Context,
118
+ });
119
+
120
+ expect(result).toContain("foo=bar");
121
+ expect(result).toContain("baz=qux");
122
+ expect(result).toContain("fCtx=");
123
+ });
88
124
  });
125
+ });
89
126
 
90
- it("should return undefined for empty string", () => {
91
- const result = FrakContextManager.decompress("");
127
+ describe("V1 backward compatibility", () => {
128
+ describe("compress", () => {
129
+ it("should compress context with referrer address", () => {
130
+ const context: FrakContextV1 = {
131
+ r: "0x1234567890123456789012345678901234567890" as Address,
132
+ };
92
133
 
93
- expect(result).toBeUndefined();
94
- });
134
+ const result = FrakContextManager.compress(context);
95
135
 
96
- it("should return undefined for undefined input", () => {
97
- const result = FrakContextManager.decompress(undefined);
136
+ expect(result).toBeDefined();
137
+ expect(typeof result).toBe("string");
138
+ expect(result?.length).toBeGreaterThan(0);
139
+ expect(result).not.toMatch(/[+/=]/);
140
+ });
98
141
 
99
- expect(result).toBeUndefined();
100
- });
142
+ it("should return undefined when context has no referrer", () => {
143
+ const context = {} as FrakContextV1;
101
144
 
102
- it("should handle decompression errors gracefully", () => {
103
- const result = FrakContextManager.decompress(
104
- "invalid-base64url!@#"
105
- );
145
+ const result = FrakContextManager.compress(context);
106
146
 
107
- expect(consoleErrorSpy).toHaveBeenCalled();
108
- expect(result).toBeUndefined();
109
- });
147
+ expect(result).toBeUndefined();
148
+ });
110
149
 
111
- it("should round-trip compress and decompress", () => {
112
- const original: FrakContext = {
113
- r: "0x1234567890123456789012345678901234567890" as Address,
114
- };
150
+ it("should return undefined when context is undefined", () => {
151
+ const result = FrakContextManager.compress(undefined);
115
152
 
116
- const compressed = FrakContextManager.compress(original);
117
- const decompressed = FrakContextManager.decompress(compressed);
153
+ expect(result).toBeUndefined();
154
+ });
118
155
 
119
- expect(decompressed).toEqual(original);
156
+ it("should handle compression errors gracefully", () => {
157
+ const invalidContext = {
158
+ r: "invalid-address" as Address,
159
+ };
160
+
161
+ const result = FrakContextManager.compress(invalidContext);
162
+
163
+ expect(consoleErrorSpy).toHaveBeenCalled();
164
+ expect(result).toBeUndefined();
165
+ });
120
166
  });
121
- });
122
167
 
123
- describe("parse", () => {
124
- it("should parse URL with fCtx parameter", () => {
125
- const context: FrakContext = {
126
- r: "0x1234567890123456789012345678901234567890" as Address,
127
- };
128
- const compressed = FrakContextManager.compress(context);
129
- const url = `https://example.com?fCtx=${compressed}`;
168
+ describe("decompress", () => {
169
+ it("should decompress valid v1 base64url context", () => {
170
+ const originalContext: FrakContextV1 = {
171
+ r: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" as Address,
172
+ };
173
+ const compressed = FrakContextManager.compress(originalContext);
130
174
 
131
- const result = FrakContextManager.parse({ url });
175
+ const result = FrakContextManager.decompress(compressed);
132
176
 
133
- expect(result).toBeDefined();
134
- expect(result?.r).toBe(
135
- "0x1234567890123456789012345678901234567890"
136
- );
137
- });
177
+ expect(result).toBeDefined();
178
+ expect((result as FrakContextV1).r).toBe(
179
+ "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"
180
+ );
181
+ });
138
182
 
139
- it("should return null for URL without fCtx parameter", () => {
140
- const url = "https://example.com?other=param";
183
+ it("should return undefined for empty string", () => {
184
+ const result = FrakContextManager.decompress("");
141
185
 
142
- const result = FrakContextManager.parse({ url });
186
+ expect(result).toBeUndefined();
187
+ });
143
188
 
144
- expect(result).toBeNull();
145
- });
189
+ it("should return undefined for undefined input", () => {
190
+ const result = FrakContextManager.decompress(undefined);
146
191
 
147
- it("should return null for empty URL", () => {
148
- const result = FrakContextManager.parse({ url: "" });
192
+ expect(result).toBeUndefined();
193
+ });
149
194
 
150
- expect(result).toBeNull();
151
- });
195
+ it("should handle decompression errors gracefully", () => {
196
+ const result = FrakContextManager.decompress(
197
+ "invalid-base64url!@#"
198
+ );
152
199
 
153
- it("should parse URL with multiple parameters", () => {
154
- const context: FrakContext = {
155
- r: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" as Address,
156
- };
157
- const compressed = FrakContextManager.compress(context);
158
- const url = `https://example.com?foo=bar&fCtx=${compressed}&baz=qux`;
200
+ expect(consoleErrorSpy).toHaveBeenCalled();
201
+ expect(result).toBeUndefined();
202
+ });
159
203
 
160
- const result = FrakContextManager.parse({ url });
204
+ it("should round-trip compress and decompress v1", () => {
205
+ const original: FrakContextV1 = {
206
+ r: "0x1234567890123456789012345678901234567890" as Address,
207
+ };
161
208
 
162
- expect(result).toBeDefined();
163
- expect(result?.r).toBe(
164
- "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"
165
- );
209
+ const compressed = FrakContextManager.compress(original);
210
+ const decompressed = FrakContextManager.decompress(compressed);
211
+
212
+ expect(decompressed).toEqual(original);
213
+ });
166
214
  });
167
215
 
168
- it("should return undefined for malformed fCtx parameter", () => {
169
- // Use a string that will fail base64url decoding
170
- const url = "https://example.com?fCtx=!!!invalid!!!";
216
+ describe("parse", () => {
217
+ it("should parse URL with v1 fCtx parameter", () => {
218
+ const context: FrakContextV1 = {
219
+ r: "0x1234567890123456789012345678901234567890" as Address,
220
+ };
221
+ const compressed = FrakContextManager.compress(context);
222
+ const url = `https://example.com?fCtx=${compressed}`;
171
223
 
172
- const result = FrakContextManager.parse({ url });
224
+ const result = FrakContextManager.parse({ url });
173
225
 
174
- // Should handle the error and return undefined
175
- expect(result).toBeUndefined();
176
- });
177
- });
226
+ expect(result).toBeDefined();
227
+ expect((result as FrakContextV1).r).toBe(
228
+ "0x1234567890123456789012345678901234567890"
229
+ );
230
+ });
178
231
 
179
- describe("update", () => {
180
- it("should add fCtx to URL without existing context", () => {
181
- const url = "https://example.com";
182
- const context: FrakContext = {
183
- r: "0x1234567890123456789012345678901234567890" as Address,
184
- };
232
+ it("should return null for URL without fCtx parameter", () => {
233
+ const url = "https://example.com?other=param";
185
234
 
186
- const result = FrakContextManager.update({ url, context });
235
+ const result = FrakContextManager.parse({ url });
187
236
 
188
- expect(result).toBeDefined();
189
- expect(result).toContain("fCtx=");
190
- expect(result).toContain("https://example.com");
191
- });
237
+ expect(result).toBeNull();
238
+ });
192
239
 
193
- it("should merge with existing context in URL", () => {
194
- const existingContext: FrakContext = {
195
- r: "0x1234567890123456789012345678901234567890" as Address,
196
- };
197
- const compressed = FrakContextManager.compress(existingContext);
198
- const url = `https://example.com?fCtx=${compressed}`;
240
+ it("should return null for empty URL", () => {
241
+ const result = FrakContextManager.parse({ url: "" });
199
242
 
200
- const newContext: FrakContext = {
201
- r: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" as Address,
202
- };
243
+ expect(result).toBeNull();
244
+ });
203
245
 
204
- const result = FrakContextManager.update({
205
- url,
206
- context: newContext,
246
+ it("should parse URL with multiple parameters", () => {
247
+ const context: FrakContextV1 = {
248
+ r: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" as Address,
249
+ };
250
+ const compressed = FrakContextManager.compress(context);
251
+ const url = `https://example.com?foo=bar&fCtx=${compressed}&baz=qux`;
252
+
253
+ const result = FrakContextManager.parse({ url });
254
+
255
+ expect(result).toBeDefined();
256
+ expect((result as FrakContextV1).r).toBe(
257
+ "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"
258
+ );
207
259
  });
208
260
 
209
- expect(result).toBeDefined();
210
- expect(result).toContain("fCtx=");
261
+ it("should return undefined for malformed fCtx parameter", () => {
262
+ const url = "https://example.com?fCtx=!!!invalid!!!";
211
263
 
212
- // Parse the result and check it has the new referrer
213
- const parsedResult = FrakContextManager.parse({ url: result! });
214
- expect(parsedResult?.r).toBe(
215
- "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"
216
- );
264
+ const result = FrakContextManager.parse({ url });
265
+
266
+ expect(result).toBeUndefined();
267
+ });
217
268
  });
218
269
 
219
- it("should return null when URL is undefined", () => {
220
- const context: FrakContext = {
221
- r: "0x1234567890123456789012345678901234567890" as Address,
222
- };
270
+ describe("update", () => {
271
+ it("should add v1 fCtx to URL without existing context", () => {
272
+ const url = "https://example.com";
273
+ const context: FrakContextV1 = {
274
+ r: "0x1234567890123456789012345678901234567890" as Address,
275
+ };
223
276
 
224
- const result = FrakContextManager.update({
225
- url: undefined,
226
- context,
277
+ const result = FrakContextManager.update({ url, context });
278
+
279
+ expect(result).toBeDefined();
280
+ expect(result).toContain("fCtx=");
281
+ expect(result).toContain("https://example.com");
227
282
  });
228
283
 
229
- expect(result).toBeNull();
230
- });
284
+ it("should return null when URL is undefined", () => {
285
+ const context: FrakContextV1 = {
286
+ r: "0x1234567890123456789012345678901234567890" as Address,
287
+ };
231
288
 
232
- it("should return null when context has no referrer", () => {
233
- const url = "https://example.com";
234
- const context: Partial<FrakContext> = {};
289
+ const result = FrakContextManager.update({
290
+ url: undefined,
291
+ context,
292
+ });
235
293
 
236
- const result = FrakContextManager.update({ url, context });
294
+ expect(result).toBeNull();
295
+ });
237
296
 
238
- expect(result).toBeNull();
239
- });
297
+ it("should return null when context has no data", () => {
298
+ const url = "https://example.com";
299
+ // Runtime robustness: invalid object shape should return null.
300
+ const context = {} as any;
240
301
 
241
- it("should preserve other URL parameters", () => {
242
- const url = "https://example.com?foo=bar&baz=qux";
243
- const context: FrakContext = {
244
- r: "0x1234567890123456789012345678901234567890" as Address,
245
- };
302
+ const result = FrakContextManager.update({ url, context });
246
303
 
247
- const result = FrakContextManager.update({ url, context });
304
+ expect(result).toBeNull();
305
+ });
248
306
 
249
- expect(result).toContain("foo=bar");
250
- expect(result).toContain("baz=qux");
251
- expect(result).toContain("fCtx=");
252
- });
307
+ it("should preserve other URL parameters", () => {
308
+ const url = "https://example.com?foo=bar&baz=qux";
309
+ const context: FrakContextV1 = {
310
+ r: "0x1234567890123456789012345678901234567890" as Address,
311
+ };
253
312
 
254
- it("should preserve URL hash", () => {
255
- const url = "https://example.com#section";
256
- const context: FrakContext = {
257
- r: "0x1234567890123456789012345678901234567890" as Address,
258
- };
313
+ const result = FrakContextManager.update({ url, context });
259
314
 
260
- const result = FrakContextManager.update({ url, context });
315
+ expect(result).toContain("foo=bar");
316
+ expect(result).toContain("baz=qux");
317
+ expect(result).toContain("fCtx=");
318
+ });
261
319
 
262
- expect(result).toContain("#section");
263
- expect(result).toContain("fCtx=");
320
+ it("should preserve URL hash", () => {
321
+ const url = "https://example.com#section";
322
+ const context: FrakContextV1 = {
323
+ r: "0x1234567890123456789012345678901234567890" as Address,
324
+ };
325
+
326
+ const result = FrakContextManager.update({ url, context });
327
+
328
+ expect(result).toContain("#section");
329
+ expect(result).toContain("fCtx=");
330
+ });
264
331
  });
265
332
  });
266
333
 
267
334
  describe("remove", () => {
268
335
  it("should remove fCtx parameter from URL", () => {
269
- const context: FrakContext = {
336
+ const context: FrakContextV1 = {
270
337
  r: "0x1234567890123456789012345678901234567890" as Address,
271
338
  };
272
339
  const compressed = FrakContextManager.compress(context);
@@ -279,7 +346,7 @@ describe("FrakContextManager", () => {
279
346
  });
280
347
 
281
348
  it("should preserve other parameters when removing fCtx", () => {
282
- const context: FrakContext = {
349
+ const context: FrakContextV1 = {
283
350
  r: "0x1234567890123456789012345678901234567890" as Address,
284
351
  };
285
352
  const compressed = FrakContextManager.compress(context);
@@ -316,7 +383,6 @@ describe("FrakContextManager", () => {
316
383
  "0x1234567890123456789012345678901234567890" as Address;
317
384
 
318
385
  beforeEach(() => {
319
- // Mock window.location.href
320
386
  Object.defineProperty(window, "location", {
321
387
  writable: true,
322
388
  value: {
@@ -324,13 +390,12 @@ describe("FrakContextManager", () => {
324
390
  },
325
391
  });
326
392
 
327
- // Mock window.history using our test utility
328
393
  mockWindowHistory(vi);
329
394
  });
330
395
 
331
- it("should update window.location with context", () => {
396
+ it("should update window.location with v1 context", () => {
332
397
  const url = "https://example.com/test";
333
- const context: FrakContext = { r: mockAddress };
398
+ const context: FrakContextV1 = { r: mockAddress };
334
399
 
335
400
  FrakContextManager.replaceUrl({ url, context });
336
401
 
@@ -347,9 +412,30 @@ describe("FrakContextManager", () => {
347
412
  expect(calledUrl).toContain("fCtx=");
348
413
  });
349
414
 
415
+ it("should update window.location with v2 context", () => {
416
+ const url = "https://example.com/test";
417
+ const context: FrakContextV2 = {
418
+ v: 2,
419
+ c: "client-id",
420
+ m: "merchant-id",
421
+ t: 1709654400,
422
+ };
423
+
424
+ FrakContextManager.replaceUrl({ url, context });
425
+
426
+ const historySpy = vi.mocked(window.history.replaceState);
427
+ expect(historySpy).toHaveBeenCalledTimes(1);
428
+
429
+ const calledUrl = historySpy.mock.calls[0]?.[2] as string;
430
+ expect(calledUrl).toContain("fCtx=");
431
+
432
+ const parsed = FrakContextManager.parse({ url: calledUrl });
433
+ expect(parsed).toEqual(context);
434
+ });
435
+
350
436
  it("should use provided URL instead of window.location.href", () => {
351
437
  const customUrl = "https://custom.com/path";
352
- const context: FrakContext = { r: mockAddress };
438
+ const context: FrakContextV1 = { r: mockAddress };
353
439
 
354
440
  FrakContextManager.replaceUrl({ url: customUrl, context });
355
441
 
@@ -372,9 +458,9 @@ describe("FrakContextManager", () => {
372
458
  expect(calledUrl).not.toContain("fCtx=");
373
459
  });
374
460
 
375
- it("should not call replaceState when context has no referrer", () => {
461
+ it("should not call replaceState when context has no data", () => {
376
462
  const url = "https://example.com/test";
377
- const context: Partial<FrakContext> = {};
463
+ const context = {} as FrakContextV1;
378
464
 
379
465
  FrakContextManager.replaceUrl({ url, context });
380
466
 
@@ -383,16 +469,14 @@ describe("FrakContextManager", () => {
383
469
  });
384
470
 
385
471
  it("should handle missing window gracefully", () => {
386
- // Remove window.location to simulate missing window
387
472
  Object.defineProperty(window, "location", {
388
473
  writable: true,
389
474
  value: undefined,
390
475
  });
391
476
 
392
477
  const url = "https://example.com/test";
393
- const context: FrakContext = { r: mockAddress };
478
+ const context: FrakContextV1 = { r: mockAddress };
394
479
 
395
- // Should not throw error
396
480
  expect(() => {
397
481
  FrakContextManager.replaceUrl({ url, context });
398
482
  }).not.toThrow();