@frak-labs/core-sdk 0.1.0-beta.afa252b0 → 0.1.0-beta.b0bd1f8a
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.
- package/cdn/bundle.iife.js +14 -0
- package/dist/actions-CEEObPYc.js +1 -0
- package/dist/actions-DbQhWYx8.cjs +1 -0
- package/dist/actions.cjs +1 -1
- package/dist/actions.d.cts +3 -1481
- package/dist/actions.d.ts +3 -1481
- package/dist/actions.js +1 -1
- package/dist/bundle.cjs +1 -13
- package/dist/bundle.d.cts +6 -2087
- package/dist/bundle.d.ts +6 -2087
- package/dist/bundle.js +1 -13
- package/dist/index-7OZ39x1U.d.ts +195 -0
- package/dist/index-C6FxkWPC.d.cts +511 -0
- package/dist/index-UFX7xCg3.d.ts +351 -0
- package/dist/index-d8xS4ryI.d.ts +511 -0
- package/dist/index-p4FqSp8z.d.cts +351 -0
- package/dist/index-zDq-VlKx.d.cts +195 -0
- package/dist/index.cjs +1 -13
- package/dist/index.d.cts +4 -1387
- package/dist/index.d.ts +4 -1387
- package/dist/index.js +1 -13
- package/dist/interaction-DMJ3ZfaF.d.cts +45 -0
- package/dist/interaction-KX1h9a7V.d.ts +45 -0
- package/dist/interactions-DnfM3oe0.js +1 -0
- package/dist/interactions-EIXhNLf6.cjs +1 -0
- package/dist/interactions.cjs +1 -1
- package/dist/interactions.d.cts +2 -182
- package/dist/interactions.d.ts +2 -182
- package/dist/interactions.js +1 -1
- package/dist/openSso-D--Airj6.d.cts +1018 -0
- package/dist/openSso-DsKJ4y0j.d.ts +1018 -0
- package/dist/productTypes-BUkXJKZ7.cjs +1 -0
- package/dist/productTypes-CGb1MmBF.js +1 -0
- package/dist/src-B_xO0AR6.cjs +13 -0
- package/dist/src-D2d52OZa.js +13 -0
- package/dist/trackEvent-CHnYa85W.js +1 -0
- package/dist/trackEvent-GuQm_1Nm.cjs +1 -0
- package/package.json +23 -18
- package/src/actions/displayEmbeddedWallet.test.ts +194 -0
- package/src/actions/displayEmbeddedWallet.ts +20 -0
- package/src/actions/displayModal.test.ts +387 -0
- package/src/actions/displayModal.ts +131 -0
- package/src/actions/getProductInformation.test.ts +133 -0
- package/src/actions/getProductInformation.ts +14 -0
- package/src/actions/index.ts +29 -0
- package/src/actions/openSso.test.ts +407 -0
- package/src/actions/openSso.ts +116 -0
- package/src/actions/prepareSso.test.ts +223 -0
- package/src/actions/prepareSso.ts +48 -0
- package/src/actions/referral/processReferral.ts +230 -0
- package/src/actions/referral/referralInteraction.ts +57 -0
- package/src/actions/sendInteraction.test.ts +219 -0
- package/src/actions/sendInteraction.ts +32 -0
- package/src/actions/trackPurchaseStatus.test.ts +287 -0
- package/src/actions/trackPurchaseStatus.ts +53 -0
- package/src/actions/watchWalletStatus.test.ts +372 -0
- package/src/actions/watchWalletStatus.ts +94 -0
- package/src/actions/wrapper/modalBuilder.ts +212 -0
- package/src/actions/wrapper/sendTransaction.ts +62 -0
- package/src/actions/wrapper/siweAuthenticate.ts +94 -0
- package/src/bundle.ts +3 -0
- package/src/clients/DebugInfo.ts +182 -0
- package/src/clients/createIFrameFrakClient.ts +287 -0
- package/src/clients/index.ts +3 -0
- package/src/clients/setupClient.test.ts +343 -0
- package/src/clients/setupClient.ts +73 -0
- package/src/clients/transports/iframeLifecycleManager.test.ts +399 -0
- package/src/clients/transports/iframeLifecycleManager.ts +90 -0
- package/src/constants/interactionTypes.ts +44 -0
- package/src/constants/locales.ts +14 -0
- package/src/constants/productTypes.ts +33 -0
- package/src/index.ts +101 -0
- package/src/interactions/index.ts +5 -0
- package/src/interactions/pressEncoder.test.ts +215 -0
- package/src/interactions/pressEncoder.ts +53 -0
- package/src/interactions/purchaseEncoder.test.ts +291 -0
- package/src/interactions/purchaseEncoder.ts +99 -0
- package/src/interactions/referralEncoder.test.ts +170 -0
- package/src/interactions/referralEncoder.ts +47 -0
- package/src/interactions/retailEncoder.test.ts +107 -0
- package/src/interactions/retailEncoder.ts +37 -0
- package/src/interactions/webshopEncoder.test.ts +56 -0
- package/src/interactions/webshopEncoder.ts +30 -0
- package/src/types/client.ts +14 -0
- package/src/types/compression.ts +22 -0
- package/src/types/config.ts +111 -0
- package/src/types/context.ts +13 -0
- package/src/types/index.ts +71 -0
- package/src/types/lifecycle/client.ts +46 -0
- package/src/types/lifecycle/iframe.ts +35 -0
- package/src/types/lifecycle/index.ts +2 -0
- package/src/types/rpc/displayModal.ts +84 -0
- package/src/types/rpc/embedded/index.ts +68 -0
- package/src/types/rpc/embedded/loggedIn.ts +55 -0
- package/src/types/rpc/embedded/loggedOut.ts +28 -0
- package/src/types/rpc/interaction.ts +43 -0
- package/src/types/rpc/modal/final.ts +46 -0
- package/src/types/rpc/modal/generic.ts +46 -0
- package/src/types/rpc/modal/index.ts +20 -0
- package/src/types/rpc/modal/login.ts +32 -0
- package/src/types/rpc/modal/openSession.ts +25 -0
- package/src/types/rpc/modal/siweAuthenticate.ts +37 -0
- package/src/types/rpc/modal/transaction.ts +33 -0
- package/src/types/rpc/productInformation.ts +59 -0
- package/src/types/rpc/sso.ts +80 -0
- package/src/types/rpc/walletStatus.ts +35 -0
- package/src/types/rpc.ts +158 -0
- package/src/types/transport.ts +34 -0
- package/src/utils/FrakContext.test.ts +407 -0
- package/src/utils/FrakContext.ts +158 -0
- package/src/utils/compression/b64.test.ts +181 -0
- package/src/utils/compression/b64.ts +29 -0
- package/src/utils/compression/compress.test.ts +123 -0
- package/src/utils/compression/compress.ts +11 -0
- package/src/utils/compression/decompress.test.ts +145 -0
- package/src/utils/compression/decompress.ts +11 -0
- package/src/utils/compression/index.ts +3 -0
- package/src/utils/computeProductId.test.ts +80 -0
- package/src/utils/computeProductId.ts +11 -0
- package/src/utils/constants.test.ts +23 -0
- package/src/utils/constants.ts +4 -0
- package/src/utils/formatAmount.test.ts +113 -0
- package/src/utils/formatAmount.ts +18 -0
- package/src/utils/getCurrencyAmountKey.test.ts +44 -0
- package/src/utils/getCurrencyAmountKey.ts +15 -0
- package/src/utils/getSupportedCurrency.test.ts +51 -0
- package/src/utils/getSupportedCurrency.ts +14 -0
- package/src/utils/getSupportedLocale.test.ts +64 -0
- package/src/utils/getSupportedLocale.ts +16 -0
- package/src/utils/iframeHelper.test.ts +450 -0
- package/src/utils/iframeHelper.ts +143 -0
- package/src/utils/index.ts +21 -0
- package/src/utils/sso.test.ts +361 -0
- package/src/utils/sso.ts +119 -0
- package/src/utils/ssoUrlListener.ts +60 -0
- package/src/utils/trackEvent.test.ts +162 -0
- package/src/utils/trackEvent.ts +26 -0
- package/cdn/bundle.js +0 -19
- package/cdn/bundle.js.LICENSE.txt +0 -10
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for base64url encoding and decoding utilities
|
|
3
|
+
* Tests encoding, decoding, and round-trip operations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, expect, it, test } from "../../../tests/vitest-fixtures";
|
|
7
|
+
import { base64urlDecode, base64urlEncode } from "./b64";
|
|
8
|
+
|
|
9
|
+
describe("base64urlEncode", () => {
|
|
10
|
+
test("should encode empty Uint8Array", ({ mockUint8Arrays }) => {
|
|
11
|
+
const result = base64urlEncode(mockUint8Arrays.empty);
|
|
12
|
+
|
|
13
|
+
expect(result).toBe("");
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test("should encode simple Uint8Array", ({ mockUint8Arrays }) => {
|
|
17
|
+
const result = base64urlEncode(mockUint8Arrays.simple);
|
|
18
|
+
|
|
19
|
+
// "Hello" should encode to "SGVsbG8"
|
|
20
|
+
expect(result).toBe("SGVsbG8");
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test("should replace + with - for URL safety", () => {
|
|
24
|
+
// Create data that would produce + in standard base64
|
|
25
|
+
const data = new Uint8Array([0xfb, 0xff]);
|
|
26
|
+
const result = base64urlEncode(data);
|
|
27
|
+
|
|
28
|
+
// Should not contain +
|
|
29
|
+
expect(result).not.toContain("+");
|
|
30
|
+
expect(result).toContain("-");
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("should replace / with _ for URL safety", () => {
|
|
34
|
+
// Create data that would produce / in standard base64
|
|
35
|
+
const data = new Uint8Array([0xff, 0xff]);
|
|
36
|
+
const result = base64urlEncode(data);
|
|
37
|
+
|
|
38
|
+
// Should not contain /
|
|
39
|
+
expect(result).not.toContain("/");
|
|
40
|
+
expect(result).toContain("_");
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("should remove padding =", () => {
|
|
44
|
+
// Create data that would have padding
|
|
45
|
+
const data = new Uint8Array([72]); // "H" -> "SA==" in standard base64
|
|
46
|
+
const result = base64urlEncode(data);
|
|
47
|
+
|
|
48
|
+
// Should not contain =
|
|
49
|
+
expect(result).not.toContain("=");
|
|
50
|
+
expect(result).toBe("SA");
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("should handle various byte lengths", () => {
|
|
54
|
+
const lengths = [1, 2, 3, 4, 5, 10, 20];
|
|
55
|
+
|
|
56
|
+
for (const length of lengths) {
|
|
57
|
+
const data = new Uint8Array(length).fill(65); // Fill with 'A' character code
|
|
58
|
+
const result = base64urlEncode(data);
|
|
59
|
+
|
|
60
|
+
// Should produce a string
|
|
61
|
+
expect(typeof result).toBe("string");
|
|
62
|
+
expect(result.length).toBeGreaterThan(0);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test("should handle complex byte array", ({ mockUint8Arrays }) => {
|
|
67
|
+
const result = base64urlEncode(mockUint8Arrays.complex);
|
|
68
|
+
|
|
69
|
+
// Should produce valid base64url string
|
|
70
|
+
expect(result).toMatch(/^[A-Za-z0-9_-]*$/);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe("base64urlDecode", () => {
|
|
75
|
+
test("should decode empty string", ({ mockBase64Strings }) => {
|
|
76
|
+
const result = base64urlDecode(mockBase64Strings.empty);
|
|
77
|
+
|
|
78
|
+
expect(result).toEqual(new Uint8Array([]));
|
|
79
|
+
expect(result.length).toBe(0);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test("should decode simple base64url string", ({ mockBase64Strings }) => {
|
|
83
|
+
const result = base64urlDecode(mockBase64Strings.simple);
|
|
84
|
+
|
|
85
|
+
// "SGVsbG8" should decode to "Hello"
|
|
86
|
+
const expected = new Uint8Array([72, 101, 108, 108, 111]);
|
|
87
|
+
expect(result).toEqual(expected);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("should handle strings without padding", () => {
|
|
91
|
+
// Base64url strings don't have padding
|
|
92
|
+
const encoded = "SGVsbG8"; // "Hello" without padding
|
|
93
|
+
const result = base64urlDecode(encoded);
|
|
94
|
+
|
|
95
|
+
const expected = new Uint8Array([72, 101, 108, 108, 111]);
|
|
96
|
+
expect(result).toEqual(expected);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test("should reverse URL-safe character replacements", ({
|
|
100
|
+
mockBase64Strings,
|
|
101
|
+
}) => {
|
|
102
|
+
const result = base64urlDecode(mockBase64Strings.withSpecialChars);
|
|
103
|
+
|
|
104
|
+
// Should handle - and _ characters
|
|
105
|
+
expect(result).toBeInstanceOf(Uint8Array);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test("should handle various valid base64url string lengths", () => {
|
|
109
|
+
// Use valid base64url strings
|
|
110
|
+
const testStrings = ["QQ", "QUI", "QUJD", "QUJDRA"]; // "A", "AB", "ABC", "ABCD" encoded
|
|
111
|
+
|
|
112
|
+
for (const str of testStrings) {
|
|
113
|
+
const result = base64urlDecode(str);
|
|
114
|
+
|
|
115
|
+
// Should produce Uint8Array
|
|
116
|
+
expect(result).toBeInstanceOf(Uint8Array);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
describe("base64url round-trip", () => {
|
|
122
|
+
test("should successfully round-trip empty data", ({ mockUint8Arrays }) => {
|
|
123
|
+
const encoded = base64urlEncode(mockUint8Arrays.empty);
|
|
124
|
+
const decoded = base64urlDecode(encoded);
|
|
125
|
+
|
|
126
|
+
expect(decoded).toEqual(mockUint8Arrays.empty);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test("should successfully round-trip simple data", ({
|
|
130
|
+
mockUint8Arrays,
|
|
131
|
+
}) => {
|
|
132
|
+
const encoded = base64urlEncode(mockUint8Arrays.simple);
|
|
133
|
+
const decoded = base64urlDecode(encoded);
|
|
134
|
+
|
|
135
|
+
expect(decoded).toEqual(mockUint8Arrays.simple);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test("should successfully round-trip complex data", ({
|
|
139
|
+
mockUint8Arrays,
|
|
140
|
+
}) => {
|
|
141
|
+
const encoded = base64urlEncode(mockUint8Arrays.complex);
|
|
142
|
+
const decoded = base64urlDecode(encoded);
|
|
143
|
+
|
|
144
|
+
expect(decoded).toEqual(mockUint8Arrays.complex);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it("should handle all byte values (0-255)", () => {
|
|
148
|
+
// Test with all possible byte values
|
|
149
|
+
const allBytes = new Uint8Array(256);
|
|
150
|
+
for (let i = 0; i < 256; i++) {
|
|
151
|
+
allBytes[i] = i;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const encoded = base64urlEncode(allBytes);
|
|
155
|
+
const decoded = base64urlDecode(encoded);
|
|
156
|
+
|
|
157
|
+
expect(decoded).toEqual(allBytes);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it("should preserve binary data integrity", () => {
|
|
161
|
+
const binaryData = new Uint8Array([0, 1, 127, 128, 255, 254, 100, 200]);
|
|
162
|
+
|
|
163
|
+
const encoded = base64urlEncode(binaryData);
|
|
164
|
+
const decoded = base64urlDecode(encoded);
|
|
165
|
+
|
|
166
|
+
expect(decoded).toEqual(binaryData);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it("should handle random data correctly", () => {
|
|
170
|
+
// Generate some pseudo-random data
|
|
171
|
+
const randomData = new Uint8Array(32);
|
|
172
|
+
for (let i = 0; i < 32; i++) {
|
|
173
|
+
randomData[i] = Math.floor(Math.random() * 256);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const encoded = base64urlEncode(randomData);
|
|
177
|
+
const decoded = base64urlDecode(encoded);
|
|
178
|
+
|
|
179
|
+
expect(decoded).toEqual(randomData);
|
|
180
|
+
});
|
|
181
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Encode a buffer to a base64url encoded string
|
|
3
|
+
* @param buffer The buffer to encode
|
|
4
|
+
* @returns The encoded string
|
|
5
|
+
*/
|
|
6
|
+
export function base64urlEncode(buffer: Uint8Array): string {
|
|
7
|
+
return btoa(Array.from(buffer, (b) => String.fromCharCode(b)).join(""))
|
|
8
|
+
.replace(/\+/g, "-")
|
|
9
|
+
.replace(/\//g, "_")
|
|
10
|
+
.replace(/=+$/, "");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Decode a base64url encoded string
|
|
15
|
+
* @param value The value to decode
|
|
16
|
+
* @returns The decoded value
|
|
17
|
+
*/
|
|
18
|
+
export function base64urlDecode(value: string): Uint8Array {
|
|
19
|
+
const m = value.length % 4;
|
|
20
|
+
return Uint8Array.from(
|
|
21
|
+
atob(
|
|
22
|
+
value
|
|
23
|
+
.replace(/-/g, "+")
|
|
24
|
+
.replace(/_/g, "/")
|
|
25
|
+
.padEnd(value.length + (m === 0 ? 0 : 4 - m), "=")
|
|
26
|
+
),
|
|
27
|
+
(c) => c.charCodeAt(0)
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for compressJsonToB64 utility function
|
|
3
|
+
* Tests JSON compression to base64url-encoded string
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { vi } from "vitest";
|
|
7
|
+
|
|
8
|
+
// Mock the frame-connector module - must be before imports
|
|
9
|
+
vi.mock("@frak-labs/frame-connector", () => ({
|
|
10
|
+
compressJson: vi.fn((data: unknown) => {
|
|
11
|
+
// Simple mock: convert JSON to Uint8Array
|
|
12
|
+
const jsonString = JSON.stringify(data);
|
|
13
|
+
return new TextEncoder().encode(jsonString);
|
|
14
|
+
}),
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
import { describe, expect, it } from "../../../tests/vitest-fixtures";
|
|
18
|
+
import { compressJsonToB64 } from "./compress";
|
|
19
|
+
|
|
20
|
+
describe("compressJsonToB64", () => {
|
|
21
|
+
describe("success cases", () => {
|
|
22
|
+
it("should compress and encode simple object", () => {
|
|
23
|
+
const data = { key: "value" };
|
|
24
|
+
const result = compressJsonToB64(data);
|
|
25
|
+
|
|
26
|
+
// Result should be a base64url-encoded string
|
|
27
|
+
expect(result).toBeDefined();
|
|
28
|
+
expect(typeof result).toBe("string");
|
|
29
|
+
expect(result.length).toBeGreaterThan(0);
|
|
30
|
+
// Base64url should not contain +, /, or = characters
|
|
31
|
+
expect(result).not.toMatch(/[+/=]/);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("should compress and encode array data", () => {
|
|
35
|
+
const data = [1, 2, 3, 4, 5];
|
|
36
|
+
const result = compressJsonToB64(data);
|
|
37
|
+
|
|
38
|
+
expect(result).toBeDefined();
|
|
39
|
+
expect(typeof result).toBe("string");
|
|
40
|
+
expect(result.length).toBeGreaterThan(0);
|
|
41
|
+
expect(result).not.toMatch(/[+/=]/);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("should compress and encode nested object", () => {
|
|
45
|
+
const data = {
|
|
46
|
+
user: {
|
|
47
|
+
name: "John",
|
|
48
|
+
address: {
|
|
49
|
+
city: "Paris",
|
|
50
|
+
country: "France",
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
const result = compressJsonToB64(data);
|
|
55
|
+
|
|
56
|
+
expect(result).toBeDefined();
|
|
57
|
+
expect(typeof result).toBe("string");
|
|
58
|
+
expect(result.length).toBeGreaterThan(0);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("should compress and encode string data", () => {
|
|
62
|
+
const data = "Hello, World!";
|
|
63
|
+
const result = compressJsonToB64(data);
|
|
64
|
+
|
|
65
|
+
expect(result).toBeDefined();
|
|
66
|
+
expect(typeof result).toBe("string");
|
|
67
|
+
expect(result.length).toBeGreaterThan(0);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("should compress and encode number data", () => {
|
|
71
|
+
const data = 12345;
|
|
72
|
+
const result = compressJsonToB64(data);
|
|
73
|
+
|
|
74
|
+
expect(result).toBeDefined();
|
|
75
|
+
expect(typeof result).toBe("string");
|
|
76
|
+
expect(result.length).toBeGreaterThan(0);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("should compress and encode boolean data", () => {
|
|
80
|
+
const data = true;
|
|
81
|
+
const result = compressJsonToB64(data);
|
|
82
|
+
|
|
83
|
+
expect(result).toBeDefined();
|
|
84
|
+
expect(typeof result).toBe("string");
|
|
85
|
+
expect(result.length).toBeGreaterThan(0);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it("should compress and encode null", () => {
|
|
89
|
+
const data = null;
|
|
90
|
+
const result = compressJsonToB64(data);
|
|
91
|
+
|
|
92
|
+
expect(result).toBeDefined();
|
|
93
|
+
expect(typeof result).toBe("string");
|
|
94
|
+
expect(result.length).toBeGreaterThan(0);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe("edge cases", () => {
|
|
99
|
+
it("should handle empty object", () => {
|
|
100
|
+
const data = {};
|
|
101
|
+
const result = compressJsonToB64(data);
|
|
102
|
+
|
|
103
|
+
expect(result).toBeDefined();
|
|
104
|
+
expect(typeof result).toBe("string");
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("should handle empty array", () => {
|
|
108
|
+
const data: unknown[] = [];
|
|
109
|
+
const result = compressJsonToB64(data);
|
|
110
|
+
|
|
111
|
+
expect(result).toBeDefined();
|
|
112
|
+
expect(typeof result).toBe("string");
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("should handle empty string", () => {
|
|
116
|
+
const data = "";
|
|
117
|
+
const result = compressJsonToB64(data);
|
|
118
|
+
|
|
119
|
+
expect(result).toBeDefined();
|
|
120
|
+
expect(typeof result).toBe("string");
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { compressJson } from "@frak-labs/frame-connector";
|
|
2
|
+
import { base64urlEncode } from "./b64";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Compress json data
|
|
6
|
+
* @param data
|
|
7
|
+
* @ignore
|
|
8
|
+
*/
|
|
9
|
+
export function compressJsonToB64(data: unknown): string {
|
|
10
|
+
return base64urlEncode(compressJson(data));
|
|
11
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for decompressJsonFromB64 utility function
|
|
3
|
+
* Tests decompression of base64url-encoded JSON strings
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { vi } from "vitest";
|
|
7
|
+
|
|
8
|
+
// Mock the frame-connector module - must be before imports
|
|
9
|
+
vi.mock("@frak-labs/frame-connector", () => ({
|
|
10
|
+
compressJson: vi.fn((data: unknown) => {
|
|
11
|
+
// Simple mock: convert JSON to Uint8Array
|
|
12
|
+
const jsonString = JSON.stringify(data);
|
|
13
|
+
return new TextEncoder().encode(jsonString);
|
|
14
|
+
}),
|
|
15
|
+
decompressJson: vi.fn((data: Uint8Array) => {
|
|
16
|
+
// Simple mock: convert Uint8Array back to JSON
|
|
17
|
+
const jsonString = new TextDecoder().decode(data);
|
|
18
|
+
return JSON.parse(jsonString);
|
|
19
|
+
}),
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
import { describe, expect, it } from "../../../tests/vitest-fixtures";
|
|
23
|
+
import { compressJsonToB64 } from "./compress";
|
|
24
|
+
import { decompressJsonFromB64 } from "./decompress";
|
|
25
|
+
|
|
26
|
+
describe("decompressJsonFromB64", () => {
|
|
27
|
+
describe("success cases", () => {
|
|
28
|
+
it("should decompress simple object", () => {
|
|
29
|
+
const original = { key: "value" };
|
|
30
|
+
const compressed = compressJsonToB64(original);
|
|
31
|
+
const decompressed =
|
|
32
|
+
decompressJsonFromB64<typeof original>(compressed);
|
|
33
|
+
|
|
34
|
+
expect(decompressed).toEqual(original);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("should decompress array data", () => {
|
|
38
|
+
const original = [1, 2, 3, 4, 5];
|
|
39
|
+
const compressed = compressJsonToB64(original);
|
|
40
|
+
const decompressed =
|
|
41
|
+
decompressJsonFromB64<typeof original>(compressed);
|
|
42
|
+
|
|
43
|
+
expect(decompressed).toEqual(original);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("should decompress nested object", () => {
|
|
47
|
+
const original = {
|
|
48
|
+
user: {
|
|
49
|
+
name: "John",
|
|
50
|
+
address: {
|
|
51
|
+
city: "Paris",
|
|
52
|
+
country: "France",
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
const compressed = compressJsonToB64(original);
|
|
57
|
+
const decompressed =
|
|
58
|
+
decompressJsonFromB64<typeof original>(compressed);
|
|
59
|
+
|
|
60
|
+
expect(decompressed).toEqual(original);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("should decompress string data", () => {
|
|
64
|
+
const original = "Hello, World!";
|
|
65
|
+
const compressed = compressJsonToB64(original);
|
|
66
|
+
const decompressed = decompressJsonFromB64<string>(compressed);
|
|
67
|
+
|
|
68
|
+
expect(decompressed).toBe(original);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("should decompress number data", () => {
|
|
72
|
+
const original = 12345;
|
|
73
|
+
const compressed = compressJsonToB64(original);
|
|
74
|
+
const decompressed = decompressJsonFromB64<number>(compressed);
|
|
75
|
+
|
|
76
|
+
expect(decompressed).toBe(original);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("should decompress boolean data", () => {
|
|
80
|
+
const original = true;
|
|
81
|
+
const compressed = compressJsonToB64(original);
|
|
82
|
+
const decompressed = decompressJsonFromB64<boolean>(compressed);
|
|
83
|
+
|
|
84
|
+
expect(decompressed).toBe(original);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("should decompress null", () => {
|
|
88
|
+
const original = null;
|
|
89
|
+
const compressed = compressJsonToB64(original);
|
|
90
|
+
const decompressed = decompressJsonFromB64<null>(compressed);
|
|
91
|
+
|
|
92
|
+
expect(decompressed).toBeNull();
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe("round-trip compression", () => {
|
|
97
|
+
it("should preserve data through compress-decompress cycle", () => {
|
|
98
|
+
const original = {
|
|
99
|
+
id: 123,
|
|
100
|
+
name: "Test User",
|
|
101
|
+
tags: ["tag1", "tag2", "tag3"],
|
|
102
|
+
metadata: {
|
|
103
|
+
created: "2024-01-01",
|
|
104
|
+
updated: "2024-01-02",
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const compressed = compressJsonToB64(original);
|
|
109
|
+
const decompressed =
|
|
110
|
+
decompressJsonFromB64<typeof original>(compressed);
|
|
111
|
+
|
|
112
|
+
expect(decompressed).toEqual(original);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("should handle empty object round-trip", () => {
|
|
116
|
+
const original = {};
|
|
117
|
+
const compressed = compressJsonToB64(original);
|
|
118
|
+
const decompressed =
|
|
119
|
+
decompressJsonFromB64<typeof original>(compressed);
|
|
120
|
+
|
|
121
|
+
expect(decompressed).toEqual(original);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("should handle empty array round-trip", () => {
|
|
125
|
+
const original: unknown[] = [];
|
|
126
|
+
const compressed = compressJsonToB64(original);
|
|
127
|
+
const decompressed =
|
|
128
|
+
decompressJsonFromB64<typeof original>(compressed);
|
|
129
|
+
|
|
130
|
+
expect(decompressed).toEqual(original);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
describe("edge cases", () => {
|
|
135
|
+
it("should handle empty object round-trip gracefully", () => {
|
|
136
|
+
// Empty objects should compress and decompress correctly
|
|
137
|
+
const original = {};
|
|
138
|
+
const compressed = compressJsonToB64(original);
|
|
139
|
+
const decompressed =
|
|
140
|
+
decompressJsonFromB64<typeof original>(compressed);
|
|
141
|
+
|
|
142
|
+
expect(decompressed).toEqual(original);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { decompressJson } from "@frak-labs/frame-connector";
|
|
2
|
+
import { base64urlDecode } from "./b64";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Decompress json data
|
|
6
|
+
* @param data
|
|
7
|
+
* @ignore
|
|
8
|
+
*/
|
|
9
|
+
export function decompressJsonFromB64<T>(data: string): T | null {
|
|
10
|
+
return decompressJson(base64urlDecode(data));
|
|
11
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for computeProductId utility function
|
|
3
|
+
* Tests product ID computation from domain names with normalization
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { keccak256, toHex } from "viem";
|
|
7
|
+
import { describe, expect, it } from "../../tests/vitest-fixtures";
|
|
8
|
+
import { computeProductId } from "./computeProductId";
|
|
9
|
+
|
|
10
|
+
describe("computeProductId", () => {
|
|
11
|
+
it("should compute product ID from current domain (window.location.host)", () => {
|
|
12
|
+
// In JSDOM test environment, window.location.host is "localhost:3000"
|
|
13
|
+
const productId = computeProductId();
|
|
14
|
+
|
|
15
|
+
// Should compute keccak256 hash of window.location.host
|
|
16
|
+
const expectedId = keccak256(toHex(window.location.host));
|
|
17
|
+
expect(productId).toBe(expectedId);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("should compute product ID from custom domain", () => {
|
|
21
|
+
const customDomain = "custom-domain.com";
|
|
22
|
+
const productId = computeProductId({ domain: customDomain });
|
|
23
|
+
|
|
24
|
+
// Should compute keccak256 hash of custom domain
|
|
25
|
+
const expectedId = keccak256(toHex(customDomain));
|
|
26
|
+
expect(productId).toBe(expectedId);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("should remove www. prefix from domain before hashing", () => {
|
|
30
|
+
const domainWithWww = "www.example.com";
|
|
31
|
+
const productId = computeProductId({ domain: domainWithWww });
|
|
32
|
+
|
|
33
|
+
// Should compute keccak256 hash of "example.com" (www. removed)
|
|
34
|
+
const expectedId = keccak256(toHex("example.com"));
|
|
35
|
+
expect(productId).toBe(expectedId);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("should produce same product ID for domain with and without www", () => {
|
|
39
|
+
const withWww = computeProductId({ domain: "www.example.com" });
|
|
40
|
+
const withoutWww = computeProductId({ domain: "example.com" });
|
|
41
|
+
|
|
42
|
+
// Both should produce the same hash
|
|
43
|
+
expect(withWww).toBe(withoutWww);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("should produce different product IDs for different domains", () => {
|
|
47
|
+
const domain1ProductId = computeProductId({ domain: "domain1.com" });
|
|
48
|
+
const domain2ProductId = computeProductId({ domain: "domain2.com" });
|
|
49
|
+
|
|
50
|
+
// Different domains should produce different hashes
|
|
51
|
+
expect(domain1ProductId).not.toBe(domain2ProductId);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("should use window.location.host when domain is not provided", () => {
|
|
55
|
+
// When no domain is provided, it should default to window.location.host
|
|
56
|
+
const productId = computeProductId();
|
|
57
|
+
|
|
58
|
+
// Should produce same result as using window.location.host explicitly
|
|
59
|
+
const expectedId = keccak256(toHex(window.location.host));
|
|
60
|
+
expect(productId).toBe(expectedId);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("should handle subdomains correctly", () => {
|
|
64
|
+
const subdomain = "blog.example.com";
|
|
65
|
+
const productId = computeProductId({ domain: subdomain });
|
|
66
|
+
|
|
67
|
+
// Should compute keccak256 hash of "blog.example.com" (subdomain preserved)
|
|
68
|
+
const expectedId = keccak256(toHex(subdomain));
|
|
69
|
+
expect(productId).toBe(expectedId);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("should only remove www prefix, not other w-prefixed subdomains", () => {
|
|
73
|
+
const domain = "web.example.com";
|
|
74
|
+
const productId = computeProductId({ domain });
|
|
75
|
+
|
|
76
|
+
// Should NOT remove "web." prefix, only "www."
|
|
77
|
+
const expectedId = keccak256(toHex("web.example.com"));
|
|
78
|
+
expect(productId).toBe(expectedId);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { keccak256, toHex } from "viem";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Compute the product id from a domain
|
|
5
|
+
* @ignore
|
|
6
|
+
*/
|
|
7
|
+
export function computeProductId({ domain }: { domain?: string } = {}) {
|
|
8
|
+
const effectiveDomain = domain ?? window.location.host;
|
|
9
|
+
const normalizedDomain = effectiveDomain.replace("www.", "");
|
|
10
|
+
return keccak256(toHex(normalizedDomain));
|
|
11
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for constants
|
|
3
|
+
* Tests backup key constant value
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, expect, it } from "../../tests/vitest-fixtures";
|
|
7
|
+
import { BACKUP_KEY } from "./constants";
|
|
8
|
+
|
|
9
|
+
describe("constants", () => {
|
|
10
|
+
describe("BACKUP_KEY", () => {
|
|
11
|
+
it("should have correct backup key value", () => {
|
|
12
|
+
expect(BACKUP_KEY).toBe("nexus-wallet-backup");
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("should be a string", () => {
|
|
16
|
+
expect(typeof BACKUP_KEY).toBe("string");
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("should not be empty", () => {
|
|
20
|
+
expect(BACKUP_KEY.length).toBeGreaterThan(0);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
});
|