@frak-labs/core-sdk 0.0.19 → 0.1.0-beta.00226d62

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 (148) hide show
  1. package/cdn/bundle.iife.js +14 -0
  2. package/dist/actions-CEEObPYc.js +1 -0
  3. package/dist/actions-DbQhWYx8.cjs +1 -0
  4. package/dist/actions.cjs +1 -1
  5. package/dist/actions.d.cts +3 -1400
  6. package/dist/actions.d.ts +3 -1400
  7. package/dist/actions.js +1 -1
  8. package/dist/bundle.cjs +1 -13
  9. package/dist/bundle.d.cts +6 -2022
  10. package/dist/bundle.d.ts +6 -2022
  11. package/dist/bundle.js +1 -13
  12. package/dist/index-7OZ39x1U.d.ts +195 -0
  13. package/dist/index-C6FxkWPC.d.cts +511 -0
  14. package/dist/index-UFX7xCg3.d.ts +351 -0
  15. package/dist/index-d8xS4ryI.d.ts +511 -0
  16. package/dist/index-p4FqSp8z.d.cts +351 -0
  17. package/dist/index-zDq-VlKx.d.cts +195 -0
  18. package/dist/index.cjs +1 -13
  19. package/dist/index.d.cts +4 -1373
  20. package/dist/index.d.ts +4 -1373
  21. package/dist/index.js +1 -13
  22. package/dist/interaction-DMJ3ZfaF.d.cts +45 -0
  23. package/dist/interaction-KX1h9a7V.d.ts +45 -0
  24. package/dist/interactions-DnfM3oe0.js +1 -0
  25. package/dist/interactions-EIXhNLf6.cjs +1 -0
  26. package/dist/interactions.cjs +1 -1
  27. package/dist/interactions.d.cts +2 -182
  28. package/dist/interactions.d.ts +2 -182
  29. package/dist/interactions.js +1 -1
  30. package/dist/openSso-D--Airj6.d.cts +1018 -0
  31. package/dist/openSso-DsKJ4y0j.d.ts +1018 -0
  32. package/dist/productTypes-BUkXJKZ7.cjs +1 -0
  33. package/dist/productTypes-CGb1MmBF.js +1 -0
  34. package/dist/src-B_xO0AR6.cjs +13 -0
  35. package/dist/src-D2d52OZa.js +13 -0
  36. package/dist/trackEvent-CHnYa85W.js +1 -0
  37. package/dist/trackEvent-GuQm_1Nm.cjs +1 -0
  38. package/package.json +27 -18
  39. package/src/actions/displayEmbeddedWallet.test.ts +194 -0
  40. package/src/actions/displayEmbeddedWallet.ts +20 -0
  41. package/src/actions/displayModal.test.ts +387 -0
  42. package/src/actions/displayModal.ts +131 -0
  43. package/src/actions/getProductInformation.test.ts +133 -0
  44. package/src/actions/getProductInformation.ts +14 -0
  45. package/src/actions/index.ts +29 -0
  46. package/src/actions/openSso.test.ts +407 -0
  47. package/src/actions/openSso.ts +116 -0
  48. package/src/actions/prepareSso.test.ts +223 -0
  49. package/src/actions/prepareSso.ts +48 -0
  50. package/src/actions/referral/processReferral.test.ts +357 -0
  51. package/src/actions/referral/processReferral.ts +230 -0
  52. package/src/actions/referral/referralInteraction.test.ts +153 -0
  53. package/src/actions/referral/referralInteraction.ts +57 -0
  54. package/src/actions/sendInteraction.test.ts +219 -0
  55. package/src/actions/sendInteraction.ts +32 -0
  56. package/src/actions/trackPurchaseStatus.test.ts +287 -0
  57. package/src/actions/trackPurchaseStatus.ts +53 -0
  58. package/src/actions/watchWalletStatus.test.ts +372 -0
  59. package/src/actions/watchWalletStatus.ts +94 -0
  60. package/src/actions/wrapper/modalBuilder.test.ts +253 -0
  61. package/src/actions/wrapper/modalBuilder.ts +212 -0
  62. package/src/actions/wrapper/sendTransaction.test.ts +164 -0
  63. package/src/actions/wrapper/sendTransaction.ts +62 -0
  64. package/src/actions/wrapper/siweAuthenticate.test.ts +290 -0
  65. package/src/actions/wrapper/siweAuthenticate.ts +94 -0
  66. package/src/bundle.ts +3 -0
  67. package/src/clients/DebugInfo.test.ts +418 -0
  68. package/src/clients/DebugInfo.ts +182 -0
  69. package/src/clients/createIFrameFrakClient.ts +287 -0
  70. package/src/clients/index.ts +3 -0
  71. package/src/clients/setupClient.test.ts +343 -0
  72. package/src/clients/setupClient.ts +73 -0
  73. package/src/clients/transports/iframeLifecycleManager.test.ts +399 -0
  74. package/src/clients/transports/iframeLifecycleManager.ts +90 -0
  75. package/src/constants/interactionTypes.test.ts +128 -0
  76. package/src/constants/interactionTypes.ts +44 -0
  77. package/src/constants/locales.ts +14 -0
  78. package/src/constants/productTypes.test.ts +130 -0
  79. package/src/constants/productTypes.ts +33 -0
  80. package/src/index.ts +101 -0
  81. package/src/interactions/index.ts +5 -0
  82. package/src/interactions/pressEncoder.test.ts +215 -0
  83. package/src/interactions/pressEncoder.ts +53 -0
  84. package/src/interactions/purchaseEncoder.test.ts +291 -0
  85. package/src/interactions/purchaseEncoder.ts +99 -0
  86. package/src/interactions/referralEncoder.test.ts +170 -0
  87. package/src/interactions/referralEncoder.ts +47 -0
  88. package/src/interactions/retailEncoder.test.ts +107 -0
  89. package/src/interactions/retailEncoder.ts +37 -0
  90. package/src/interactions/webshopEncoder.test.ts +56 -0
  91. package/src/interactions/webshopEncoder.ts +30 -0
  92. package/src/types/client.ts +14 -0
  93. package/src/types/compression.ts +22 -0
  94. package/src/types/config.ts +111 -0
  95. package/src/types/context.ts +13 -0
  96. package/src/types/index.ts +71 -0
  97. package/src/types/lifecycle/client.ts +46 -0
  98. package/src/types/lifecycle/iframe.ts +35 -0
  99. package/src/types/lifecycle/index.ts +2 -0
  100. package/src/types/rpc/displayModal.ts +84 -0
  101. package/src/types/rpc/embedded/index.ts +68 -0
  102. package/src/types/rpc/embedded/loggedIn.ts +55 -0
  103. package/src/types/rpc/embedded/loggedOut.ts +28 -0
  104. package/src/types/rpc/interaction.ts +43 -0
  105. package/src/types/rpc/modal/final.ts +46 -0
  106. package/src/types/rpc/modal/generic.ts +46 -0
  107. package/src/types/rpc/modal/index.ts +20 -0
  108. package/src/types/rpc/modal/login.ts +32 -0
  109. package/src/types/rpc/modal/openSession.ts +25 -0
  110. package/src/types/rpc/modal/siweAuthenticate.ts +37 -0
  111. package/src/types/rpc/modal/transaction.ts +33 -0
  112. package/src/types/rpc/productInformation.ts +59 -0
  113. package/src/types/rpc/sso.ts +80 -0
  114. package/src/types/rpc/walletStatus.ts +35 -0
  115. package/src/types/rpc.ts +158 -0
  116. package/src/types/transport.ts +34 -0
  117. package/src/utils/FrakContext.test.ts +407 -0
  118. package/src/utils/FrakContext.ts +158 -0
  119. package/src/utils/compression/b64.test.ts +181 -0
  120. package/src/utils/compression/b64.ts +29 -0
  121. package/src/utils/compression/compress.test.ts +123 -0
  122. package/src/utils/compression/compress.ts +11 -0
  123. package/src/utils/compression/decompress.test.ts +145 -0
  124. package/src/utils/compression/decompress.ts +11 -0
  125. package/src/utils/compression/index.ts +3 -0
  126. package/src/utils/computeProductId.test.ts +80 -0
  127. package/src/utils/computeProductId.ts +11 -0
  128. package/src/utils/constants.test.ts +23 -0
  129. package/src/utils/constants.ts +4 -0
  130. package/src/utils/formatAmount.test.ts +113 -0
  131. package/src/utils/formatAmount.ts +18 -0
  132. package/src/utils/getCurrencyAmountKey.test.ts +44 -0
  133. package/src/utils/getCurrencyAmountKey.ts +15 -0
  134. package/src/utils/getSupportedCurrency.test.ts +51 -0
  135. package/src/utils/getSupportedCurrency.ts +14 -0
  136. package/src/utils/getSupportedLocale.test.ts +64 -0
  137. package/src/utils/getSupportedLocale.ts +16 -0
  138. package/src/utils/iframeHelper.test.ts +450 -0
  139. package/src/utils/iframeHelper.ts +143 -0
  140. package/src/utils/index.ts +21 -0
  141. package/src/utils/sso.test.ts +361 -0
  142. package/src/utils/sso.ts +119 -0
  143. package/src/utils/ssoUrlListener.test.ts +252 -0
  144. package/src/utils/ssoUrlListener.ts +60 -0
  145. package/src/utils/trackEvent.test.ts +162 -0
  146. package/src/utils/trackEvent.ts +26 -0
  147. package/cdn/bundle.js +0 -19
  148. package/cdn/bundle.js.LICENSE.txt +0 -10
@@ -0,0 +1,399 @@
1
+ import { beforeEach, describe, expect, test, vi } from "vitest";
2
+
3
+ // Mock dependencies
4
+ vi.mock("@frak-labs/frame-connector", () => ({
5
+ Deferred: class {
6
+ promise: Promise<any>;
7
+ resolve!: (value: any) => void;
8
+ reject!: (error: any) => void;
9
+
10
+ constructor() {
11
+ this.promise = new Promise((resolve, reject) => {
12
+ this.resolve = resolve;
13
+ this.reject = reject;
14
+ });
15
+ }
16
+ },
17
+ }));
18
+
19
+ vi.mock("../../utils/constants", () => ({
20
+ BACKUP_KEY: "frak-backup-key",
21
+ }));
22
+
23
+ vi.mock("../../utils/iframeHelper", () => ({
24
+ changeIframeVisibility: vi.fn(),
25
+ }));
26
+
27
+ describe("createIFrameLifecycleManager", () => {
28
+ beforeEach(() => {
29
+ vi.clearAllMocks();
30
+ // Reset localStorage
31
+ localStorage.clear();
32
+ // Mock window.location
33
+ Object.defineProperty(window, "location", {
34
+ value: { href: "https://test.com" },
35
+ writable: true,
36
+ });
37
+ });
38
+
39
+ describe("manager initialization", () => {
40
+ test("should create manager with correct properties", async () => {
41
+ const { createIFrameLifecycleManager } = await import(
42
+ "./iframeLifecycleManager"
43
+ );
44
+
45
+ const mockIframe = document.createElement("iframe");
46
+ const manager = createIFrameLifecycleManager({
47
+ iframe: mockIframe,
48
+ });
49
+
50
+ expect(manager).toBeDefined();
51
+ expect(manager.isConnected).toBeInstanceOf(Promise);
52
+ expect(manager.handleEvent).toBeInstanceOf(Function);
53
+ });
54
+
55
+ test("should start with unresolved isConnected promise", async () => {
56
+ const { createIFrameLifecycleManager } = await import(
57
+ "./iframeLifecycleManager"
58
+ );
59
+
60
+ const mockIframe = document.createElement("iframe");
61
+ const manager = createIFrameLifecycleManager({
62
+ iframe: mockIframe,
63
+ });
64
+
65
+ let resolved = false;
66
+ manager.isConnected.then(() => {
67
+ resolved = true;
68
+ });
69
+
70
+ // Wait a tick
71
+ await new Promise((resolve) => setTimeout(resolve, 0));
72
+ expect(resolved).toBe(false);
73
+ });
74
+ });
75
+
76
+ describe("connected event", () => {
77
+ test("should resolve isConnected on connected event", async () => {
78
+ const { createIFrameLifecycleManager } = await import(
79
+ "./iframeLifecycleManager"
80
+ );
81
+
82
+ const mockIframe = document.createElement("iframe");
83
+ const manager = createIFrameLifecycleManager({
84
+ iframe: mockIframe,
85
+ });
86
+
87
+ const event = {
88
+ iframeLifecycle: "connected" as const,
89
+ };
90
+
91
+ await manager.handleEvent(event);
92
+
93
+ await expect(manager.isConnected).resolves.toBe(true);
94
+ });
95
+ });
96
+
97
+ describe("backup events", () => {
98
+ test("should save backup to localStorage on do-backup", async () => {
99
+ const { createIFrameLifecycleManager } = await import(
100
+ "./iframeLifecycleManager"
101
+ );
102
+
103
+ const mockIframe = document.createElement("iframe");
104
+ const manager = createIFrameLifecycleManager({
105
+ iframe: mockIframe,
106
+ });
107
+
108
+ const backup = "encrypted-backup-data";
109
+ const event = {
110
+ iframeLifecycle: "do-backup" as const,
111
+ data: { backup },
112
+ };
113
+
114
+ await manager.handleEvent(event);
115
+
116
+ expect(localStorage.getItem("frak-backup-key")).toBe(backup);
117
+ });
118
+
119
+ test("should remove backup when data.backup is undefined", async () => {
120
+ const { createIFrameLifecycleManager } = await import(
121
+ "./iframeLifecycleManager"
122
+ );
123
+
124
+ const mockIframe = document.createElement("iframe");
125
+ const manager = createIFrameLifecycleManager({
126
+ iframe: mockIframe,
127
+ });
128
+
129
+ // First set a backup
130
+ localStorage.setItem("frak-backup-key", "old-backup");
131
+
132
+ const event = {
133
+ iframeLifecycle: "do-backup" as const,
134
+ data: {},
135
+ };
136
+
137
+ await manager.handleEvent(event);
138
+
139
+ expect(localStorage.getItem("frak-backup-key")).toBeNull();
140
+ });
141
+
142
+ test("should remove backup on remove-backup event", async () => {
143
+ const { createIFrameLifecycleManager } = await import(
144
+ "./iframeLifecycleManager"
145
+ );
146
+
147
+ const mockIframe = document.createElement("iframe");
148
+ const manager = createIFrameLifecycleManager({
149
+ iframe: mockIframe,
150
+ });
151
+
152
+ // First set a backup
153
+ localStorage.setItem("frak-backup-key", "backup-to-remove");
154
+
155
+ const event = {
156
+ iframeLifecycle: "remove-backup" as const,
157
+ };
158
+
159
+ await manager.handleEvent(event);
160
+
161
+ expect(localStorage.getItem("frak-backup-key")).toBeNull();
162
+ });
163
+ });
164
+
165
+ describe("visibility events", () => {
166
+ test("should show iframe on show event", async () => {
167
+ const { createIFrameLifecycleManager } = await import(
168
+ "./iframeLifecycleManager"
169
+ );
170
+ const { changeIframeVisibility } = await import(
171
+ "../../utils/iframeHelper"
172
+ );
173
+
174
+ const mockIframe = document.createElement("iframe");
175
+ const manager = createIFrameLifecycleManager({
176
+ iframe: mockIframe,
177
+ });
178
+
179
+ const event = {
180
+ iframeLifecycle: "show" as const,
181
+ };
182
+
183
+ await manager.handleEvent(event);
184
+
185
+ expect(changeIframeVisibility).toHaveBeenCalledWith({
186
+ iframe: mockIframe,
187
+ isVisible: true,
188
+ });
189
+ });
190
+
191
+ test("should hide iframe on hide event", async () => {
192
+ const { createIFrameLifecycleManager } = await import(
193
+ "./iframeLifecycleManager"
194
+ );
195
+ const { changeIframeVisibility } = await import(
196
+ "../../utils/iframeHelper"
197
+ );
198
+
199
+ const mockIframe = document.createElement("iframe");
200
+ const manager = createIFrameLifecycleManager({
201
+ iframe: mockIframe,
202
+ });
203
+
204
+ const event = {
205
+ iframeLifecycle: "hide" as const,
206
+ };
207
+
208
+ await manager.handleEvent(event);
209
+
210
+ expect(changeIframeVisibility).toHaveBeenCalledWith({
211
+ iframe: mockIframe,
212
+ isVisible: false,
213
+ });
214
+ });
215
+ });
216
+
217
+ describe("handshake event", () => {
218
+ test("should post handshake-response with token", async () => {
219
+ const { createIFrameLifecycleManager } = await import(
220
+ "./iframeLifecycleManager"
221
+ );
222
+
223
+ const mockPostMessage = vi.fn();
224
+ const mockIframe = {
225
+ contentWindow: {
226
+ postMessage: mockPostMessage,
227
+ },
228
+ } as any;
229
+
230
+ const manager = createIFrameLifecycleManager({
231
+ iframe: mockIframe,
232
+ });
233
+
234
+ const event = {
235
+ iframeLifecycle: "handshake" as const,
236
+ data: { token: "handshake-token-123" },
237
+ };
238
+
239
+ await manager.handleEvent(event);
240
+
241
+ expect(mockPostMessage).toHaveBeenCalledWith(
242
+ {
243
+ clientLifecycle: "handshake-response",
244
+ data: {
245
+ token: "handshake-token-123",
246
+ currentUrl: "https://test.com",
247
+ },
248
+ },
249
+ "*"
250
+ );
251
+ });
252
+
253
+ test("should include current URL in handshake response", async () => {
254
+ const { createIFrameLifecycleManager } = await import(
255
+ "./iframeLifecycleManager"
256
+ );
257
+
258
+ Object.defineProperty(window, "location", {
259
+ value: { href: "https://example.com/page?param=value" },
260
+ writable: true,
261
+ });
262
+
263
+ const mockPostMessage = vi.fn();
264
+ const mockIframe = {
265
+ contentWindow: {
266
+ postMessage: mockPostMessage,
267
+ },
268
+ } as any;
269
+
270
+ const manager = createIFrameLifecycleManager({
271
+ iframe: mockIframe,
272
+ });
273
+
274
+ const event = {
275
+ iframeLifecycle: "handshake" as const,
276
+ data: { token: "token" },
277
+ };
278
+
279
+ await manager.handleEvent(event);
280
+
281
+ expect(mockPostMessage).toHaveBeenCalledWith(
282
+ expect.objectContaining({
283
+ data: expect.objectContaining({
284
+ currentUrl: "https://example.com/page?param=value",
285
+ }),
286
+ }),
287
+ "*"
288
+ );
289
+ });
290
+ });
291
+
292
+ describe("redirect event", () => {
293
+ test("should redirect with appended current URL", async () => {
294
+ const { createIFrameLifecycleManager } = await import(
295
+ "./iframeLifecycleManager"
296
+ );
297
+
298
+ Object.defineProperty(window, "location", {
299
+ value: {
300
+ href: "https://original.com",
301
+ },
302
+ writable: true,
303
+ });
304
+
305
+ const mockIframe = document.createElement("iframe");
306
+ const manager = createIFrameLifecycleManager({
307
+ iframe: mockIframe,
308
+ });
309
+
310
+ const event = {
311
+ iframeLifecycle: "redirect" as const,
312
+ data: {
313
+ baseRedirectUrl: "https://redirect.com?u=placeholder",
314
+ },
315
+ };
316
+
317
+ await manager.handleEvent(event);
318
+
319
+ expect(window.location.href).toBe(
320
+ "https://redirect.com/?u=https%3A%2F%2Foriginal.com"
321
+ );
322
+ });
323
+
324
+ test("should redirect without modification if no u parameter", async () => {
325
+ const { createIFrameLifecycleManager } = await import(
326
+ "./iframeLifecycleManager"
327
+ );
328
+
329
+ Object.defineProperty(window, "location", {
330
+ value: {
331
+ href: "https://original.com",
332
+ },
333
+ writable: true,
334
+ });
335
+
336
+ const mockIframe = document.createElement("iframe");
337
+ const manager = createIFrameLifecycleManager({
338
+ iframe: mockIframe,
339
+ });
340
+
341
+ const event = {
342
+ iframeLifecycle: "redirect" as const,
343
+ data: {
344
+ baseRedirectUrl: "https://redirect.com/path",
345
+ },
346
+ };
347
+
348
+ await manager.handleEvent(event);
349
+
350
+ expect(window.location.href).toBe("https://redirect.com/path");
351
+ });
352
+ });
353
+
354
+ describe("event filtering", () => {
355
+ test("should ignore events without iframeLifecycle property", async () => {
356
+ const { createIFrameLifecycleManager } = await import(
357
+ "./iframeLifecycleManager"
358
+ );
359
+
360
+ const mockIframe = document.createElement("iframe");
361
+ const manager = createIFrameLifecycleManager({
362
+ iframe: mockIframe,
363
+ });
364
+
365
+ const event = {
366
+ someOtherEvent: "value",
367
+ } as any;
368
+
369
+ // Should not throw
370
+ await expect(manager.handleEvent(event)).resolves.toBeUndefined();
371
+ });
372
+
373
+ test("should only process events with iframeLifecycle", async () => {
374
+ const { createIFrameLifecycleManager } = await import(
375
+ "./iframeLifecycleManager"
376
+ );
377
+ const { changeIframeVisibility } = await import(
378
+ "../../utils/iframeHelper"
379
+ );
380
+
381
+ const mockIframe = document.createElement("iframe");
382
+ const manager = createIFrameLifecycleManager({
383
+ iframe: mockIframe,
384
+ });
385
+
386
+ // Event without iframeLifecycle
387
+ await manager.handleEvent({ randomEvent: "show" } as any);
388
+
389
+ // changeIframeVisibility should not be called
390
+ expect(changeIframeVisibility).not.toHaveBeenCalled();
391
+
392
+ // Event with iframeLifecycle
393
+ await manager.handleEvent({ iframeLifecycle: "show" as const });
394
+
395
+ // Now it should be called
396
+ expect(changeIframeVisibility).toHaveBeenCalled();
397
+ });
398
+ });
399
+ });
@@ -0,0 +1,90 @@
1
+ import { Deferred } from "@frak-labs/frame-connector";
2
+ import type { FrakLifecycleEvent } from "../../types";
3
+ import { BACKUP_KEY } from "../../utils/constants";
4
+ import { changeIframeVisibility } from "../../utils/iframeHelper";
5
+
6
+ /** @ignore */
7
+ export type IframeLifecycleManager = {
8
+ isConnected: Promise<boolean>;
9
+ handleEvent: (messageEvent: FrakLifecycleEvent) => Promise<void>;
10
+ };
11
+
12
+ /**
13
+ * Create a new iframe lifecycle handler
14
+ * @ignore
15
+ */
16
+ export function createIFrameLifecycleManager({
17
+ iframe,
18
+ }: {
19
+ iframe: HTMLIFrameElement;
20
+ }): IframeLifecycleManager {
21
+ // Create the isConnected listener
22
+ const isConnectedDeferred = new Deferred<boolean>();
23
+
24
+ // Build the handler itself
25
+ const handler = async (messageEvent: FrakLifecycleEvent) => {
26
+ if (!("iframeLifecycle" in messageEvent)) return;
27
+
28
+ const { iframeLifecycle: event, data } = messageEvent;
29
+
30
+ switch (event) {
31
+ // Resolve the isConnected promise
32
+ case "connected":
33
+ isConnectedDeferred.resolve(true);
34
+ break;
35
+ // Perform a frak backup
36
+ case "do-backup":
37
+ if (data.backup) {
38
+ localStorage.setItem(BACKUP_KEY, data.backup);
39
+ } else {
40
+ localStorage.removeItem(BACKUP_KEY);
41
+ }
42
+ break;
43
+ // Remove frak backup
44
+ case "remove-backup":
45
+ localStorage.removeItem(BACKUP_KEY);
46
+ break;
47
+ // Change iframe visibility
48
+ case "show":
49
+ case "hide":
50
+ changeIframeVisibility({
51
+ iframe,
52
+ isVisible: event === "show",
53
+ });
54
+ break;
55
+ // Handshake handling
56
+ case "handshake": {
57
+ iframe.contentWindow?.postMessage(
58
+ {
59
+ clientLifecycle: "handshake-response",
60
+ data: {
61
+ token: data.token,
62
+ currentUrl: window.location.href,
63
+ },
64
+ },
65
+ "*"
66
+ );
67
+ break;
68
+ }
69
+ // Redirect handling
70
+ case "redirect": {
71
+ const redirectUrl = new URL(data.baseRedirectUrl);
72
+
73
+ // If we got a u append the current location dynamicly
74
+ if (redirectUrl.searchParams.has("u")) {
75
+ redirectUrl.searchParams.delete("u");
76
+ redirectUrl.searchParams.append("u", window.location.href);
77
+ window.location.href = redirectUrl.toString();
78
+ } else {
79
+ window.location.href = data.baseRedirectUrl;
80
+ }
81
+ break;
82
+ }
83
+ }
84
+ };
85
+
86
+ return {
87
+ handleEvent: handler,
88
+ isConnected: isConnectedDeferred.promise,
89
+ };
90
+ }
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Tests for interactionTypes constants
3
+ * Tests interaction type definitions and type utilities
4
+ */
5
+
6
+ import { describe, expect, it } from "vitest";
7
+ import { interactionTypes } from "./interactionTypes";
8
+
9
+ describe("interactionTypes", () => {
10
+ describe("structure", () => {
11
+ it("should have all expected categories", () => {
12
+ expect(interactionTypes).toHaveProperty("press");
13
+ expect(interactionTypes).toHaveProperty("dapp");
14
+ expect(interactionTypes).toHaveProperty("webshop");
15
+ expect(interactionTypes).toHaveProperty("referral");
16
+ expect(interactionTypes).toHaveProperty("purchase");
17
+ expect(interactionTypes).toHaveProperty("retail");
18
+ });
19
+
20
+ it("should have press interactions", () => {
21
+ expect(interactionTypes.press).toEqual({
22
+ openArticle: "0xc0a24ffb",
23
+ readArticle: "0xd5bd0fbe",
24
+ });
25
+ });
26
+
27
+ it("should have dapp interactions", () => {
28
+ expect(interactionTypes.dapp).toEqual({
29
+ proofVerifiableStorageUpdate: "0x2ab2aeef",
30
+ callableVerifiableStorageUpdate: "0xa07da986",
31
+ });
32
+ });
33
+
34
+ it("should have webshop interactions", () => {
35
+ expect(interactionTypes.webshop).toEqual({
36
+ open: "0xb311798f",
37
+ });
38
+ });
39
+
40
+ it("should have referral interactions", () => {
41
+ expect(interactionTypes.referral).toEqual({
42
+ referred: "0x010cc3b9",
43
+ createLink: "0xb2c0f17c",
44
+ });
45
+ });
46
+
47
+ it("should have purchase interactions", () => {
48
+ expect(interactionTypes.purchase).toEqual({
49
+ started: "0xd87e90c3",
50
+ completed: "0x8403aeb4",
51
+ unsafeCompleted: "0x4d5b14e0",
52
+ });
53
+ });
54
+
55
+ it("should have retail interactions", () => {
56
+ expect(interactionTypes.retail).toEqual({
57
+ customerMeeting: "0x74489004",
58
+ });
59
+ });
60
+ });
61
+
62
+ describe("interaction values", () => {
63
+ it("should have all interaction values as hex strings", () => {
64
+ Object.values(interactionTypes).forEach((category) => {
65
+ Object.values(category).forEach((value) => {
66
+ expect(value).toMatch(/^0x[a-f0-9]{8}$/);
67
+ });
68
+ });
69
+ });
70
+
71
+ it("should have unique interaction values across all categories", () => {
72
+ const allValues = Object.values(interactionTypes).flatMap(
73
+ (category) => Object.values(category)
74
+ );
75
+ const uniqueValues = new Set(allValues);
76
+ expect(allValues.length).toBe(uniqueValues.size);
77
+ });
78
+ });
79
+
80
+ describe("specific interactions", () => {
81
+ it("should have correct press.openArticle value", () => {
82
+ expect(interactionTypes.press.openArticle).toBe("0xc0a24ffb");
83
+ });
84
+
85
+ it("should have correct press.readArticle value", () => {
86
+ expect(interactionTypes.press.readArticle).toBe("0xd5bd0fbe");
87
+ });
88
+
89
+ it("should have correct webshop.open value", () => {
90
+ expect(interactionTypes.webshop.open).toBe("0xb311798f");
91
+ });
92
+
93
+ it("should have correct referral.referred value", () => {
94
+ expect(interactionTypes.referral.referred).toBe("0x010cc3b9");
95
+ });
96
+
97
+ it("should have correct purchase.completed value", () => {
98
+ expect(interactionTypes.purchase.completed).toBe("0x8403aeb4");
99
+ });
100
+
101
+ it("should have correct purchase.unsafeCompleted value", () => {
102
+ expect(interactionTypes.purchase.unsafeCompleted).toBe(
103
+ "0x4d5b14e0"
104
+ );
105
+ });
106
+
107
+ it("should have correct retail.customerMeeting value", () => {
108
+ expect(interactionTypes.retail.customerMeeting).toBe("0x74489004");
109
+ });
110
+ });
111
+
112
+ describe("type safety", () => {
113
+ it("should be readonly (as const)", () => {
114
+ // TypeScript ensures this is readonly, but we can verify structure
115
+ expect(Object.isFrozen(interactionTypes)).toBe(false);
116
+ // The values should be consistent
117
+ expect(typeof interactionTypes.press.openArticle).toBe("string");
118
+ });
119
+
120
+ it("should have consistent structure across categories", () => {
121
+ Object.values(interactionTypes).forEach((category) => {
122
+ expect(typeof category).toBe("object");
123
+ expect(category).not.toBeNull();
124
+ expect(Array.isArray(category)).toBe(false);
125
+ });
126
+ });
127
+ });
128
+ });
@@ -0,0 +1,44 @@
1
+ /**
2
+ * The final keys for each interaction types (e.g. `openArticle`) -> interaction type
3
+ * @inline
4
+ */
5
+ export type InteractionTypesKey = {
6
+ [K in keyof typeof interactionTypes]: keyof (typeof interactionTypes)[K];
7
+ }[keyof typeof interactionTypes];
8
+
9
+ /**
10
+ * The keys for each interaction types (e.g. `press.openArticle`) -> category_type.interaction_type
11
+ * @inline
12
+ */
13
+ export type FullInteractionTypesKey = {
14
+ [Category in keyof typeof interactionTypes]: `${Category & string}.${keyof (typeof interactionTypes)[Category] & string}`;
15
+ }[keyof typeof interactionTypes];
16
+
17
+ /**
18
+ * Each interactions types according to the product types
19
+ */
20
+ export const interactionTypes = {
21
+ press: {
22
+ openArticle: "0xc0a24ffb",
23
+ readArticle: "0xd5bd0fbe",
24
+ },
25
+ dapp: {
26
+ proofVerifiableStorageUpdate: "0x2ab2aeef",
27
+ callableVerifiableStorageUpdate: "0xa07da986",
28
+ },
29
+ webshop: {
30
+ open: "0xb311798f",
31
+ },
32
+ referral: {
33
+ referred: "0x010cc3b9",
34
+ createLink: "0xb2c0f17c",
35
+ },
36
+ purchase: {
37
+ started: "0xd87e90c3",
38
+ completed: "0x8403aeb4",
39
+ unsafeCompleted: "0x4d5b14e0",
40
+ },
41
+ retail: {
42
+ customerMeeting: "0x74489004",
43
+ },
44
+ } as const;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * The keys for each locales
3
+ * @inline
4
+ */
5
+ export type LocalesKey = keyof typeof locales;
6
+
7
+ /**
8
+ * Map the currency to the locale
9
+ */
10
+ export const locales = {
11
+ eur: "fr-FR",
12
+ usd: "en-US",
13
+ gbp: "en-GB",
14
+ } as const;