@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.
- 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 -1400
- package/dist/actions.d.ts +3 -1400
- package/dist/actions.js +1 -1
- package/dist/bundle.cjs +1 -13
- package/dist/bundle.d.cts +6 -2022
- package/dist/bundle.d.ts +6 -2022
- 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 -1373
- package/dist/index.d.ts +4 -1373
- 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 +27 -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.test.ts +357 -0
- package/src/actions/referral/processReferral.ts +230 -0
- package/src/actions/referral/referralInteraction.test.ts +153 -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.test.ts +253 -0
- package/src/actions/wrapper/modalBuilder.ts +212 -0
- package/src/actions/wrapper/sendTransaction.test.ts +164 -0
- package/src/actions/wrapper/sendTransaction.ts +62 -0
- package/src/actions/wrapper/siweAuthenticate.test.ts +290 -0
- package/src/actions/wrapper/siweAuthenticate.ts +94 -0
- package/src/bundle.ts +3 -0
- package/src/clients/DebugInfo.test.ts +418 -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.test.ts +128 -0
- package/src/constants/interactionTypes.ts +44 -0
- package/src/constants/locales.ts +14 -0
- package/src/constants/productTypes.test.ts +130 -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.test.ts +252 -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,387 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for displayModal action
|
|
3
|
+
* Tests modal display via RPC with various step configurations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Address } from "viem";
|
|
7
|
+
import { describe, expect, it, vi } from "../../tests/vitest-fixtures";
|
|
8
|
+
import type {
|
|
9
|
+
DisplayModalParamsType,
|
|
10
|
+
FrakClient,
|
|
11
|
+
ModalStepTypes,
|
|
12
|
+
} from "../types";
|
|
13
|
+
import { displayModal } from "./displayModal";
|
|
14
|
+
|
|
15
|
+
describe("displayModal", () => {
|
|
16
|
+
describe("basic modal display", () => {
|
|
17
|
+
it("should call client.request with correct method and params", async () => {
|
|
18
|
+
const mockResponse = {
|
|
19
|
+
login: {
|
|
20
|
+
wallet: "0x1234567890123456789012345678901234567890" as Address,
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const mockClient = {
|
|
25
|
+
config: {
|
|
26
|
+
metadata: {
|
|
27
|
+
name: "Test App",
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
request: vi.fn().mockResolvedValue(mockResponse),
|
|
31
|
+
} as unknown as FrakClient;
|
|
32
|
+
|
|
33
|
+
const params: DisplayModalParamsType<ModalStepTypes[]> = {
|
|
34
|
+
steps: {
|
|
35
|
+
login: { allowSso: true },
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
await displayModal(mockClient, params);
|
|
40
|
+
|
|
41
|
+
expect(mockClient.request).toHaveBeenCalledWith({
|
|
42
|
+
method: "frak_displayModal",
|
|
43
|
+
params: [params.steps, params.metadata, { name: "Test App" }],
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("should return modal results", async () => {
|
|
48
|
+
const mockResponse = {
|
|
49
|
+
login: {
|
|
50
|
+
wallet: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" as Address,
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const mockClient = {
|
|
55
|
+
config: {
|
|
56
|
+
metadata: {
|
|
57
|
+
name: "Test App",
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
request: vi.fn().mockResolvedValue(mockResponse),
|
|
61
|
+
} as unknown as FrakClient;
|
|
62
|
+
|
|
63
|
+
const params: DisplayModalParamsType<ModalStepTypes[]> = {
|
|
64
|
+
steps: {
|
|
65
|
+
login: { allowSso: false },
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const result = await displayModal(mockClient, params);
|
|
70
|
+
|
|
71
|
+
expect(result).toEqual(mockResponse);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe("modal with multiple steps", () => {
|
|
76
|
+
it("should handle login + openSession steps", async () => {
|
|
77
|
+
const mockResponse = {
|
|
78
|
+
login: {
|
|
79
|
+
wallet: "0x1234567890123456789012345678901234567890" as Address,
|
|
80
|
+
},
|
|
81
|
+
openSession: {
|
|
82
|
+
startTimestamp: 1234567890,
|
|
83
|
+
endTimestamp: 1234567900,
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const mockClient = {
|
|
88
|
+
config: {
|
|
89
|
+
metadata: {
|
|
90
|
+
name: "Test App",
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
request: vi.fn().mockResolvedValue(mockResponse),
|
|
94
|
+
} as unknown as FrakClient;
|
|
95
|
+
|
|
96
|
+
const params: DisplayModalParamsType<ModalStepTypes[]> = {
|
|
97
|
+
steps: {
|
|
98
|
+
login: { allowSso: true },
|
|
99
|
+
openSession: {},
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const result = await displayModal(mockClient, params);
|
|
104
|
+
|
|
105
|
+
expect(result).toEqual(mockResponse);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("should handle full modal flow", async () => {
|
|
109
|
+
const mockResponse = {
|
|
110
|
+
login: {
|
|
111
|
+
wallet: "0x1234567890123456789012345678901234567890" as Address,
|
|
112
|
+
},
|
|
113
|
+
openSession: {
|
|
114
|
+
startTimestamp: 1234567890,
|
|
115
|
+
endTimestamp: 1234567900,
|
|
116
|
+
},
|
|
117
|
+
sendTransaction: {
|
|
118
|
+
hash: "0xtxhash" as `0x${string}`,
|
|
119
|
+
},
|
|
120
|
+
final: {},
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const mockClient = {
|
|
124
|
+
config: {
|
|
125
|
+
metadata: {
|
|
126
|
+
name: "Test App",
|
|
127
|
+
logoUrl: "https://example.com/logo.png",
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
request: vi.fn().mockResolvedValue(mockResponse),
|
|
131
|
+
} as unknown as FrakClient;
|
|
132
|
+
|
|
133
|
+
const params: DisplayModalParamsType<ModalStepTypes[]> = {
|
|
134
|
+
steps: {
|
|
135
|
+
login: { allowSso: true },
|
|
136
|
+
openSession: {},
|
|
137
|
+
sendTransaction: {
|
|
138
|
+
tx: [
|
|
139
|
+
{
|
|
140
|
+
to: "0xdeadbeef" as Address,
|
|
141
|
+
data: "0xdata" as `0x${string}`,
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
},
|
|
145
|
+
final: {
|
|
146
|
+
action: { key: "reward" },
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const result = await displayModal(mockClient, params);
|
|
152
|
+
|
|
153
|
+
expect(result).toEqual(mockResponse);
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe("modal with metadata", () => {
|
|
158
|
+
it("should pass metadata to request", async () => {
|
|
159
|
+
const mockResponse = {
|
|
160
|
+
login: {
|
|
161
|
+
wallet: "0x1234567890123456789012345678901234567890" as Address,
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const mockClient = {
|
|
166
|
+
config: {
|
|
167
|
+
metadata: {
|
|
168
|
+
name: "Test App",
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
request: vi.fn().mockResolvedValue(mockResponse),
|
|
172
|
+
} as unknown as FrakClient;
|
|
173
|
+
|
|
174
|
+
const params: DisplayModalParamsType<ModalStepTypes[]> = {
|
|
175
|
+
steps: {
|
|
176
|
+
login: { allowSso: true },
|
|
177
|
+
},
|
|
178
|
+
metadata: {
|
|
179
|
+
header: {
|
|
180
|
+
title: "My Custom Title",
|
|
181
|
+
icon: "https://example.com/icon.png",
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
await displayModal(mockClient, params);
|
|
187
|
+
|
|
188
|
+
expect(mockClient.request).toHaveBeenCalledWith({
|
|
189
|
+
method: "frak_displayModal",
|
|
190
|
+
params: [
|
|
191
|
+
params.steps,
|
|
192
|
+
{
|
|
193
|
+
header: {
|
|
194
|
+
title: "My Custom Title",
|
|
195
|
+
icon: "https://example.com/icon.png",
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
{ name: "Test App" },
|
|
199
|
+
],
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it("should work without metadata", async () => {
|
|
204
|
+
const mockResponse = {
|
|
205
|
+
login: {
|
|
206
|
+
wallet: "0x1234567890123456789012345678901234567890" as Address,
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
const mockClient = {
|
|
211
|
+
config: {
|
|
212
|
+
metadata: {
|
|
213
|
+
name: "Test App",
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
request: vi.fn().mockResolvedValue(mockResponse),
|
|
217
|
+
} as unknown as FrakClient;
|
|
218
|
+
|
|
219
|
+
const params: DisplayModalParamsType<ModalStepTypes[]> = {
|
|
220
|
+
steps: {
|
|
221
|
+
login: { allowSso: true },
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
await displayModal(mockClient, params);
|
|
226
|
+
|
|
227
|
+
expect(mockClient.request).toHaveBeenCalledWith({
|
|
228
|
+
method: "frak_displayModal",
|
|
229
|
+
params: [params.steps, undefined, { name: "Test App" }],
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
describe("modal with SSO metadata", () => {
|
|
235
|
+
it("should handle SSO metadata in login step", async () => {
|
|
236
|
+
const mockResponse = {
|
|
237
|
+
login: {
|
|
238
|
+
wallet: "0x1234567890123456789012345678901234567890" as Address,
|
|
239
|
+
},
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
const mockClient = {
|
|
243
|
+
config: {
|
|
244
|
+
metadata: {
|
|
245
|
+
name: "Test App",
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
request: vi.fn().mockResolvedValue(mockResponse),
|
|
249
|
+
} as unknown as FrakClient;
|
|
250
|
+
|
|
251
|
+
const params: DisplayModalParamsType<ModalStepTypes[]> = {
|
|
252
|
+
steps: {
|
|
253
|
+
login: {
|
|
254
|
+
allowSso: true,
|
|
255
|
+
ssoMetadata: {
|
|
256
|
+
logoUrl: "https://example.com/logo.png",
|
|
257
|
+
homepageLink: "https://example.com",
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
await displayModal(mockClient, params);
|
|
264
|
+
|
|
265
|
+
expect(mockClient.request).toHaveBeenCalledWith({
|
|
266
|
+
method: "frak_displayModal",
|
|
267
|
+
params: [params.steps, undefined, { name: "Test App" }],
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
describe("modal with sharing action", () => {
|
|
273
|
+
it("should handle sharing final action", async () => {
|
|
274
|
+
const mockResponse = {
|
|
275
|
+
final: {},
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
const mockClient = {
|
|
279
|
+
config: {
|
|
280
|
+
metadata: {
|
|
281
|
+
name: "Test App",
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
request: vi.fn().mockResolvedValue(mockResponse),
|
|
285
|
+
} as unknown as FrakClient;
|
|
286
|
+
|
|
287
|
+
const params: DisplayModalParamsType<ModalStepTypes[]> = {
|
|
288
|
+
steps: {
|
|
289
|
+
final: {
|
|
290
|
+
action: {
|
|
291
|
+
key: "sharing",
|
|
292
|
+
options: {
|
|
293
|
+
popupTitle: "Share the app",
|
|
294
|
+
text: "Discover my app",
|
|
295
|
+
link: "https://example.com",
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
},
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
await displayModal(mockClient, params);
|
|
303
|
+
|
|
304
|
+
expect(mockClient.request).toHaveBeenCalledWith({
|
|
305
|
+
method: "frak_displayModal",
|
|
306
|
+
params: [params.steps, undefined, { name: "Test App" }],
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
it("should handle reward final action", async () => {
|
|
311
|
+
const mockResponse = {
|
|
312
|
+
final: {},
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
const mockClient = {
|
|
316
|
+
config: {
|
|
317
|
+
metadata: {
|
|
318
|
+
name: "Test App",
|
|
319
|
+
},
|
|
320
|
+
},
|
|
321
|
+
request: vi.fn().mockResolvedValue(mockResponse),
|
|
322
|
+
} as unknown as FrakClient;
|
|
323
|
+
|
|
324
|
+
const params: DisplayModalParamsType<ModalStepTypes[]> = {
|
|
325
|
+
steps: {
|
|
326
|
+
final: {
|
|
327
|
+
action: { key: "reward" },
|
|
328
|
+
autoSkip: true,
|
|
329
|
+
},
|
|
330
|
+
},
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
await displayModal(mockClient, params);
|
|
334
|
+
|
|
335
|
+
expect(mockClient.request).toHaveBeenCalledWith({
|
|
336
|
+
method: "frak_displayModal",
|
|
337
|
+
params: [params.steps, undefined, { name: "Test App" }],
|
|
338
|
+
});
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
describe("error handling", () => {
|
|
343
|
+
it("should propagate errors from client.request", async () => {
|
|
344
|
+
const error = new Error("Modal display failed");
|
|
345
|
+
const mockClient = {
|
|
346
|
+
config: {
|
|
347
|
+
metadata: {
|
|
348
|
+
name: "Test App",
|
|
349
|
+
},
|
|
350
|
+
},
|
|
351
|
+
request: vi.fn().mockRejectedValue(error),
|
|
352
|
+
} as unknown as FrakClient;
|
|
353
|
+
|
|
354
|
+
const params: DisplayModalParamsType<ModalStepTypes[]> = {
|
|
355
|
+
steps: {
|
|
356
|
+
login: { allowSso: true },
|
|
357
|
+
},
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
await expect(displayModal(mockClient, params)).rejects.toThrow(
|
|
361
|
+
"Modal display failed"
|
|
362
|
+
);
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
it("should handle network errors", async () => {
|
|
366
|
+
const error = new Error("Network timeout");
|
|
367
|
+
const mockClient = {
|
|
368
|
+
config: {
|
|
369
|
+
metadata: {
|
|
370
|
+
name: "Test App",
|
|
371
|
+
},
|
|
372
|
+
},
|
|
373
|
+
request: vi.fn().mockRejectedValue(error),
|
|
374
|
+
} as unknown as FrakClient;
|
|
375
|
+
|
|
376
|
+
const params: DisplayModalParamsType<ModalStepTypes[]> = {
|
|
377
|
+
steps: {
|
|
378
|
+
openSession: {},
|
|
379
|
+
},
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
await expect(displayModal(mockClient, params)).rejects.toThrow(
|
|
383
|
+
"Network timeout"
|
|
384
|
+
);
|
|
385
|
+
});
|
|
386
|
+
});
|
|
387
|
+
});
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
DisplayModalParamsType,
|
|
3
|
+
FrakClient,
|
|
4
|
+
ModalRpcStepsResultType,
|
|
5
|
+
ModalStepTypes,
|
|
6
|
+
} from "../types";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Function used to display a modal
|
|
10
|
+
* @param client - The current Frak Client
|
|
11
|
+
* @param args
|
|
12
|
+
* @param args.steps - The different steps of the modal
|
|
13
|
+
* @param args.metadata - The metadata for the modal (customization, etc)
|
|
14
|
+
* @returns The result of each modal steps
|
|
15
|
+
*
|
|
16
|
+
* @description This function will display a modal to the user with the provided steps and metadata.
|
|
17
|
+
*
|
|
18
|
+
* @remarks
|
|
19
|
+
* - The UI of the displayed modal can be configured with the `customCss` property in the `customizations.css` field of the top-level config.
|
|
20
|
+
* - The `login` and `openSession` steps will be automatically skipped if the user is already logged in or has an active session. It's safe to include these steps in all cases to ensure proper user state.
|
|
21
|
+
* - Steps are automatically reordered in the following sequence:
|
|
22
|
+
* 1. `login` (if needed)
|
|
23
|
+
* 2. `openSession` (if needed)
|
|
24
|
+
* 3. All other steps in the order specified
|
|
25
|
+
* 4. `success` (if included, always last)
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* Simple sharing modal with steps:
|
|
29
|
+
* 1. Login (Skipped if already logged in)
|
|
30
|
+
* 2. Open a session (Skipped if already opened)
|
|
31
|
+
* 3. Display a success message with sharing link option
|
|
32
|
+
*
|
|
33
|
+
* ```ts
|
|
34
|
+
* const results = await displayModal(frakConfig, {
|
|
35
|
+
* steps: {
|
|
36
|
+
* // Simple login with no SSO, nor customization
|
|
37
|
+
* login: { allowSso: false },
|
|
38
|
+
* // Simple session opening, with no customization
|
|
39
|
+
* openSession: {},
|
|
40
|
+
* // Success message
|
|
41
|
+
* final: {
|
|
42
|
+
* action: { key: "reward" },
|
|
43
|
+
* // Skip this step, it will be only displayed in the stepper within the modal
|
|
44
|
+
* autoSkip: true,
|
|
45
|
+
* },
|
|
46
|
+
* },
|
|
47
|
+
* });
|
|
48
|
+
*
|
|
49
|
+
* console.log("Login step - wallet", results.login.wallet);
|
|
50
|
+
* console.log("Open session step - start + end", {
|
|
51
|
+
* start: results.openSession.startTimestamp,
|
|
52
|
+
* end: results.openSession.endTimestamp,
|
|
53
|
+
* });
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* A full modal example, with a few customization options, with the steps:
|
|
58
|
+
* 1. Login (Skipped if already logged in)
|
|
59
|
+
* 2. Open a session (Skipped if already opened)
|
|
60
|
+
* 3. Authenticate via SIWE
|
|
61
|
+
* 4. Send a transaction
|
|
62
|
+
* 5. Display a success message with sharing link options
|
|
63
|
+
*
|
|
64
|
+
* ```ts
|
|
65
|
+
* const results = await displayModal(frakConfig, {
|
|
66
|
+
* steps: {
|
|
67
|
+
* // Login step
|
|
68
|
+
* login: {
|
|
69
|
+
* allowSso: true,
|
|
70
|
+
* ssoMetadata: {
|
|
71
|
+
* logoUrl: "https://my-app.com/logo.png",
|
|
72
|
+
* homepageLink: "https://my-app.com",
|
|
73
|
+
* },
|
|
74
|
+
* },
|
|
75
|
+
* // Simple session opening, with no customisation
|
|
76
|
+
* openSession: {},
|
|
77
|
+
* // Siwe authentication
|
|
78
|
+
* siweAuthenticate: {
|
|
79
|
+
* siwe: {
|
|
80
|
+
* domain: "my-app.com",
|
|
81
|
+
* uri: "https://my-app.com/",
|
|
82
|
+
* nonce: generateSiweNonce(),
|
|
83
|
+
* version: "1",
|
|
84
|
+
* },
|
|
85
|
+
* },
|
|
86
|
+
* // Send batched transaction
|
|
87
|
+
* sendTransaction: {
|
|
88
|
+
* tx: [
|
|
89
|
+
* { to: "0xdeadbeef", data: "0xdeadbeef" },
|
|
90
|
+
* { to: "0xdeadbeef", data: "0xdeadbeef" },
|
|
91
|
+
* ],
|
|
92
|
+
* },
|
|
93
|
+
* // Success message with sharing options
|
|
94
|
+
* final: {
|
|
95
|
+
* action: {
|
|
96
|
+
* key: "sharing",
|
|
97
|
+
* options: {
|
|
98
|
+
* popupTitle: "Share the app",
|
|
99
|
+
* text: "Discover my super app website",
|
|
100
|
+
* link: "https://my-app.com",
|
|
101
|
+
* },
|
|
102
|
+
* },
|
|
103
|
+
* dismissedMetadata: {
|
|
104
|
+
* title: "Dismiss",
|
|
105
|
+
* description: "You won't be rewarded for this sharing action",
|
|
106
|
+
* },
|
|
107
|
+
* },
|
|
108
|
+
* },
|
|
109
|
+
* metadata: {
|
|
110
|
+
* // Header of desktop modals
|
|
111
|
+
* header: {
|
|
112
|
+
* title: "My-App",
|
|
113
|
+
* icon: "https://my-app.com/logo.png",
|
|
114
|
+
* },
|
|
115
|
+
* // Context that will be present in every modal steps
|
|
116
|
+
* context: "My-app overkill flow",
|
|
117
|
+
* },
|
|
118
|
+
* });
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
export async function displayModal<
|
|
122
|
+
T extends ModalStepTypes[] = ModalStepTypes[],
|
|
123
|
+
>(
|
|
124
|
+
client: FrakClient,
|
|
125
|
+
{ steps, metadata }: DisplayModalParamsType<T>
|
|
126
|
+
): Promise<ModalRpcStepsResultType<T>> {
|
|
127
|
+
return (await client.request({
|
|
128
|
+
method: "frak_displayModal",
|
|
129
|
+
params: [steps, metadata, client.config.metadata],
|
|
130
|
+
})) as ModalRpcStepsResultType<T>;
|
|
131
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for getProductInformation action
|
|
3
|
+
* Tests fetching product information via RPC
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Address, Hex } from "viem";
|
|
7
|
+
import { describe, expect, it, vi } from "../../tests/vitest-fixtures";
|
|
8
|
+
import type { FrakClient, GetProductInformationReturnType } from "../types";
|
|
9
|
+
import { getProductInformation } from "./getProductInformation";
|
|
10
|
+
|
|
11
|
+
describe("getProductInformation", () => {
|
|
12
|
+
describe("success cases", () => {
|
|
13
|
+
it("should call client.request with correct method", async () => {
|
|
14
|
+
const mockResponse: GetProductInformationReturnType = {
|
|
15
|
+
id: "0x1234567890123456789012345678901234567890123456789012345678901234" as Hex,
|
|
16
|
+
onChainMetadata: {
|
|
17
|
+
name: "Test Product",
|
|
18
|
+
domain: "example.com",
|
|
19
|
+
productTypes: ["press"],
|
|
20
|
+
},
|
|
21
|
+
rewards: [],
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const mockClient = {
|
|
25
|
+
request: vi.fn().mockResolvedValue(mockResponse),
|
|
26
|
+
} as unknown as FrakClient;
|
|
27
|
+
|
|
28
|
+
await getProductInformation(mockClient);
|
|
29
|
+
|
|
30
|
+
expect(mockClient.request).toHaveBeenCalledWith({
|
|
31
|
+
method: "frak_getProductInformation",
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("should return product information", async () => {
|
|
36
|
+
const mockResponse: GetProductInformationReturnType = {
|
|
37
|
+
id: "0x1234567890123456789012345678901234567890123456789012345678901234" as Hex,
|
|
38
|
+
onChainMetadata: {
|
|
39
|
+
name: "Test Product",
|
|
40
|
+
domain: "example.com",
|
|
41
|
+
productTypes: ["press"],
|
|
42
|
+
},
|
|
43
|
+
rewards: [],
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const mockClient = {
|
|
47
|
+
request: vi.fn().mockResolvedValue(mockResponse),
|
|
48
|
+
} as unknown as FrakClient;
|
|
49
|
+
|
|
50
|
+
const result = await getProductInformation(mockClient);
|
|
51
|
+
|
|
52
|
+
expect(result).toEqual(mockResponse);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("should return product information with rewards", async () => {
|
|
56
|
+
const mockResponse: GetProductInformationReturnType = {
|
|
57
|
+
id: "0x1234567890123456789012345678901234567890123456789012345678901234" as Hex,
|
|
58
|
+
onChainMetadata: {
|
|
59
|
+
name: "Test Product",
|
|
60
|
+
domain: "example.com",
|
|
61
|
+
productTypes: ["press", "purchase"],
|
|
62
|
+
},
|
|
63
|
+
maxReferrer: {
|
|
64
|
+
amount: 100,
|
|
65
|
+
eurAmount: 10,
|
|
66
|
+
usdAmount: 12,
|
|
67
|
+
gbpAmount: 9,
|
|
68
|
+
},
|
|
69
|
+
maxReferee: {
|
|
70
|
+
amount: 50,
|
|
71
|
+
eurAmount: 5,
|
|
72
|
+
usdAmount: 6,
|
|
73
|
+
gbpAmount: 4.5,
|
|
74
|
+
},
|
|
75
|
+
rewards: [
|
|
76
|
+
{
|
|
77
|
+
token: "0x1234567890123456789012345678901234567890" as Address,
|
|
78
|
+
campaign:
|
|
79
|
+
"0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" as Address,
|
|
80
|
+
interactionTypeKey: "press.readArticle",
|
|
81
|
+
referrer: {
|
|
82
|
+
amount: 10,
|
|
83
|
+
eurAmount: 1,
|
|
84
|
+
usdAmount: 1.2,
|
|
85
|
+
gbpAmount: 0.9,
|
|
86
|
+
},
|
|
87
|
+
referee: {
|
|
88
|
+
amount: 5,
|
|
89
|
+
eurAmount: 0.5,
|
|
90
|
+
usdAmount: 0.6,
|
|
91
|
+
gbpAmount: 0.45,
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const mockClient = {
|
|
98
|
+
request: vi.fn().mockResolvedValue(mockResponse),
|
|
99
|
+
} as unknown as FrakClient;
|
|
100
|
+
|
|
101
|
+
const result = await getProductInformation(mockClient);
|
|
102
|
+
|
|
103
|
+
expect(result).toEqual(mockResponse);
|
|
104
|
+
expect(result.rewards).toHaveLength(1);
|
|
105
|
+
expect(result.maxReferrer).toBeDefined();
|
|
106
|
+
expect(result.maxReferee).toBeDefined();
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
describe("error handling", () => {
|
|
111
|
+
it("should propagate errors from client.request", async () => {
|
|
112
|
+
const error = new Error("RPC request failed");
|
|
113
|
+
const mockClient = {
|
|
114
|
+
request: vi.fn().mockRejectedValue(error),
|
|
115
|
+
} as unknown as FrakClient;
|
|
116
|
+
|
|
117
|
+
await expect(getProductInformation(mockClient)).rejects.toThrow(
|
|
118
|
+
"RPC request failed"
|
|
119
|
+
);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("should handle network timeout errors", async () => {
|
|
123
|
+
const error = new Error("Request timeout");
|
|
124
|
+
const mockClient = {
|
|
125
|
+
request: vi.fn().mockRejectedValue(error),
|
|
126
|
+
} as unknown as FrakClient;
|
|
127
|
+
|
|
128
|
+
await expect(getProductInformation(mockClient)).rejects.toThrow(
|
|
129
|
+
"Request timeout"
|
|
130
|
+
);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { FrakClient, GetProductInformationReturnType } from "../types";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Function used to get the current product information
|
|
5
|
+
* @param client - The current Frak Client
|
|
6
|
+
* @returns The product information in a promise
|
|
7
|
+
*/
|
|
8
|
+
export async function getProductInformation(
|
|
9
|
+
client: FrakClient
|
|
10
|
+
): Promise<GetProductInformationReturnType> {
|
|
11
|
+
return await client.request({
|
|
12
|
+
method: "frak_getProductInformation",
|
|
13
|
+
});
|
|
14
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export { displayEmbeddedWallet } from "./displayEmbeddedWallet";
|
|
2
|
+
export { displayModal } from "./displayModal";
|
|
3
|
+
export { getProductInformation } from "./getProductInformation";
|
|
4
|
+
export { openSso } from "./openSso";
|
|
5
|
+
export { prepareSso } from "./prepareSso";
|
|
6
|
+
export {
|
|
7
|
+
type ProcessReferralOptions,
|
|
8
|
+
processReferral,
|
|
9
|
+
} from "./referral/processReferral";
|
|
10
|
+
// Referral interaction
|
|
11
|
+
export { referralInteraction } from "./referral/referralInteraction";
|
|
12
|
+
export { sendInteraction } from "./sendInteraction";
|
|
13
|
+
// Helper to track the purchase status
|
|
14
|
+
export { trackPurchaseStatus } from "./trackPurchaseStatus";
|
|
15
|
+
export { watchWalletStatus } from "./watchWalletStatus";
|
|
16
|
+
export {
|
|
17
|
+
type ModalBuilder,
|
|
18
|
+
type ModalStepBuilder,
|
|
19
|
+
modalBuilder,
|
|
20
|
+
} from "./wrapper/modalBuilder";
|
|
21
|
+
export {
|
|
22
|
+
type SendTransactionParams,
|
|
23
|
+
sendTransaction,
|
|
24
|
+
} from "./wrapper/sendTransaction";
|
|
25
|
+
// Modal wrappers
|
|
26
|
+
export {
|
|
27
|
+
type SiweAuthenticateModalParams,
|
|
28
|
+
siweAuthenticate,
|
|
29
|
+
} from "./wrapper/siweAuthenticate";
|