@frak-labs/react-sdk 0.1.1 → 0.2.0-beta.7898df5b

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 (38) hide show
  1. package/README.md +25 -0
  2. package/dist/index.cjs +1 -1
  3. package/dist/index.d.cts +29 -68
  4. package/dist/index.d.ts +28 -67
  5. package/dist/index.js +1 -1
  6. package/package.json +17 -16
  7. package/src/hook/helper/useReferralInteraction.test.ts +309 -0
  8. package/src/hook/helper/useReferralInteraction.ts +73 -0
  9. package/src/hook/index.ts +10 -0
  10. package/src/hook/useDisplayModal.test.ts +275 -0
  11. package/src/hook/useDisplayModal.ts +68 -0
  12. package/src/hook/useFrakClient.test.ts +119 -0
  13. package/src/hook/useFrakClient.ts +11 -0
  14. package/src/hook/useFrakConfig.test.ts +184 -0
  15. package/src/hook/useFrakConfig.ts +22 -0
  16. package/src/hook/useGetMerchantInformation.ts +56 -0
  17. package/src/hook/useOpenSso.test.ts +202 -0
  18. package/src/hook/useOpenSso.ts +51 -0
  19. package/src/hook/usePrepareSso.test.ts +197 -0
  20. package/src/hook/usePrepareSso.ts +55 -0
  21. package/src/hook/useSendTransaction.test.ts +218 -0
  22. package/src/hook/useSendTransaction.ts +62 -0
  23. package/src/hook/useSiweAuthenticate.test.ts +258 -0
  24. package/src/hook/useSiweAuthenticate.ts +66 -0
  25. package/src/hook/useWalletStatus.test.ts +112 -0
  26. package/src/hook/useWalletStatus.ts +55 -0
  27. package/src/hook/utils/useFrakContext.test.ts +157 -0
  28. package/src/hook/utils/useFrakContext.ts +42 -0
  29. package/src/hook/utils/useMounted.test.ts +70 -0
  30. package/src/hook/utils/useMounted.ts +12 -0
  31. package/src/hook/utils/useWindowLocation.test.ts +54 -0
  32. package/src/hook/utils/useWindowLocation.ts +40 -0
  33. package/src/index.ts +25 -0
  34. package/src/provider/FrakConfigProvider.test.ts +246 -0
  35. package/src/provider/FrakConfigProvider.ts +54 -0
  36. package/src/provider/FrakIFrameClientProvider.test.tsx +209 -0
  37. package/src/provider/FrakIFrameClientProvider.ts +86 -0
  38. package/src/provider/index.ts +7 -0
@@ -0,0 +1,209 @@
1
+ /**
2
+ * Tests for FrakIFrameClientProvider
3
+ * Tests iframe creation and FrakClient provider
4
+ */
5
+
6
+ import { vi } from "vitest";
7
+
8
+ vi.mock("@frak-labs/core-sdk", async () => {
9
+ const actual = await vi.importActual<typeof import("@frak-labs/core-sdk")>(
10
+ "@frak-labs/core-sdk"
11
+ );
12
+ return {
13
+ ...actual,
14
+ createIFrameFrakClient: vi.fn(),
15
+ };
16
+ });
17
+
18
+ import type { FrakClient } from "@frak-labs/core-sdk";
19
+ import { createIFrameFrakClient } from "@frak-labs/core-sdk";
20
+ import { render, waitFor } from "@testing-library/react";
21
+ import { createElement, type ReactNode } from "react";
22
+ import { describe, expect, test } from "../../tests/vitest-fixtures";
23
+ import { FrakConfigProvider } from "./FrakConfigProvider";
24
+ import { FrakIFrameClientProvider } from "./FrakIFrameClientProvider";
25
+
26
+ describe("FrakIFrameClientProvider", () => {
27
+ test("should render iframe with correct src", ({ mockFrakConfig }) => {
28
+ const Wrapper = ({ children }: { children: ReactNode }) =>
29
+ createElement(
30
+ FrakConfigProvider,
31
+ { config: mockFrakConfig },
32
+ children
33
+ );
34
+
35
+ render(createElement(FrakIFrameClientProvider), {
36
+ wrapper: Wrapper,
37
+ });
38
+
39
+ const iframe = document.querySelector("iframe");
40
+ expect(iframe).toBeDefined();
41
+ expect(iframe?.src).toContain(`${mockFrakConfig.walletUrl}/listener`);
42
+ });
43
+
44
+ test("should apply custom styles to iframe", ({ mockFrakConfig }) => {
45
+ const Wrapper = ({ children }: { children: ReactNode }) =>
46
+ createElement(
47
+ FrakConfigProvider,
48
+ { config: mockFrakConfig },
49
+ children
50
+ );
51
+
52
+ const customStyle = {
53
+ width: "500px",
54
+ height: "600px",
55
+ };
56
+
57
+ render(
58
+ createElement(FrakIFrameClientProvider, { style: customStyle }),
59
+ {
60
+ wrapper: Wrapper,
61
+ }
62
+ );
63
+
64
+ const iframe = document.querySelector("iframe");
65
+ expect(iframe?.style.width).toBe("500px");
66
+ expect(iframe?.style.height).toBe("600px");
67
+ });
68
+
69
+ test("should create FrakClient when iframe ref is set", async ({
70
+ mockFrakConfig,
71
+ }) => {
72
+ const Wrapper = ({ children }: { children: ReactNode }) =>
73
+ createElement(
74
+ FrakConfigProvider,
75
+ { config: mockFrakConfig },
76
+ children
77
+ );
78
+
79
+ const mockClient = { config: mockFrakConfig } as FrakClient;
80
+ vi.mocked(createIFrameFrakClient).mockReturnValue(mockClient);
81
+
82
+ render(createElement(FrakIFrameClientProvider), {
83
+ wrapper: Wrapper,
84
+ });
85
+
86
+ await waitFor(() => {
87
+ expect(createIFrameFrakClient).toHaveBeenCalled();
88
+ });
89
+ });
90
+
91
+ test("should not recreate client if already exists", async ({
92
+ mockFrakConfig,
93
+ }) => {
94
+ const Wrapper = ({ children }: { children: ReactNode }) =>
95
+ createElement(
96
+ FrakConfigProvider,
97
+ { config: mockFrakConfig },
98
+ children
99
+ );
100
+
101
+ const mockClient = { config: mockFrakConfig } as FrakClient;
102
+ vi.mocked(createIFrameFrakClient).mockReturnValue(mockClient);
103
+
104
+ const { rerender } = render(createElement(FrakIFrameClientProvider), {
105
+ wrapper: Wrapper,
106
+ });
107
+
108
+ await waitFor(() => {
109
+ expect(createIFrameFrakClient).toHaveBeenCalledTimes(1);
110
+ });
111
+
112
+ // Rerender the component
113
+ rerender(createElement(FrakIFrameClientProvider));
114
+
115
+ // Should still only be called once
116
+ expect(createIFrameFrakClient).toHaveBeenCalledTimes(1);
117
+ });
118
+
119
+ test("should render without children", ({ mockFrakConfig }) => {
120
+ const Wrapper = ({ children }: { children: ReactNode }) =>
121
+ createElement(
122
+ FrakConfigProvider,
123
+ { config: mockFrakConfig },
124
+ children
125
+ );
126
+
127
+ const { container } = render(createElement(FrakIFrameClientProvider), {
128
+ wrapper: Wrapper,
129
+ });
130
+
131
+ const iframe = container.querySelector("iframe");
132
+ expect(iframe).toBeDefined();
133
+ });
134
+
135
+ test("should use baseIframeProps for iframe attributes", ({
136
+ mockFrakConfig,
137
+ }) => {
138
+ const Wrapper = ({ children }: { children: ReactNode }) =>
139
+ createElement(
140
+ FrakConfigProvider,
141
+ { config: mockFrakConfig },
142
+ children
143
+ );
144
+
145
+ render(createElement(FrakIFrameClientProvider), {
146
+ wrapper: Wrapper,
147
+ });
148
+
149
+ const iframe = document.querySelector("iframe");
150
+ expect(iframe).toBeDefined();
151
+ // baseIframeProps should set these attributes
152
+ expect(iframe?.getAttribute("sandbox")).toBeDefined();
153
+ });
154
+
155
+ test("should handle iframe ref callback correctly", ({
156
+ mockFrakConfig,
157
+ }) => {
158
+ const Wrapper = ({ children }: { children: ReactNode }) =>
159
+ createElement(
160
+ FrakConfigProvider,
161
+ { config: mockFrakConfig },
162
+ children
163
+ );
164
+
165
+ const mockClient = { config: mockFrakConfig } as FrakClient;
166
+ let callCount = 0;
167
+
168
+ vi.mocked(createIFrameFrakClient).mockImplementation(() => {
169
+ callCount++;
170
+ return mockClient;
171
+ });
172
+
173
+ render(createElement(FrakIFrameClientProvider), {
174
+ wrapper: Wrapper,
175
+ });
176
+
177
+ // Client creation should be called at most once
178
+ expect(callCount).toBeLessThanOrEqual(1);
179
+ });
180
+
181
+ test("should pass config to createIFrameFrakClient", async ({
182
+ mockFrakConfig,
183
+ }) => {
184
+ const Wrapper = ({ children }: { children: ReactNode }) =>
185
+ createElement(
186
+ FrakConfigProvider,
187
+ { config: mockFrakConfig },
188
+ children
189
+ );
190
+
191
+ const mockClient = { config: mockFrakConfig } as FrakClient;
192
+ vi.mocked(createIFrameFrakClient).mockReturnValue(mockClient);
193
+
194
+ render(createElement(FrakIFrameClientProvider), {
195
+ wrapper: Wrapper,
196
+ });
197
+
198
+ await waitFor(() => {
199
+ expect(createIFrameFrakClient).toHaveBeenCalledWith(
200
+ expect.objectContaining({
201
+ config: expect.objectContaining({
202
+ domain: "example.com",
203
+ walletUrl: "https://wallet-test.frak.id",
204
+ }),
205
+ })
206
+ );
207
+ });
208
+ });
209
+ });
@@ -0,0 +1,86 @@
1
+ import {
2
+ baseIframeProps,
3
+ createIFrameFrakClient,
4
+ type FrakClient,
5
+ type FrakWalletSdkConfig,
6
+ } from "@frak-labs/core-sdk";
7
+ import {
8
+ type CSSProperties,
9
+ createContext,
10
+ createElement,
11
+ Fragment,
12
+ type ReactNode,
13
+ useState,
14
+ } from "react";
15
+ import { useFrakConfig } from "../hook";
16
+
17
+ /**
18
+ * The context that will keep the Frak Wallet SDK client
19
+ * @ignore
20
+ */
21
+ export const FrakIFrameClientContext = createContext<FrakClient | undefined>(
22
+ undefined
23
+ );
24
+
25
+ /**
26
+ * Props to instantiate the Frak Wallet SDK configuration provider
27
+ *
28
+ * @group provider
29
+ */
30
+ export type FrakIFrameClientProps = {
31
+ config: FrakWalletSdkConfig;
32
+ };
33
+
34
+ /**
35
+ * IFrame client provider for the Frak Wallet SDK
36
+ * It will automatically create the frak wallet iFrame (required for the wallet to communicate with the SDK securely), and provide it in the context
37
+ *
38
+ * @group provider
39
+ *
40
+ * @remarks
41
+ * This provider must be wrapped within a {@link FrakConfigProvider} to work properly
42
+ *
43
+ * @param args
44
+ * @param args.style - Some custom styles to apply to the iFrame
45
+ * @param args.children - Descedant components that will have access to the Frak Client
46
+ */
47
+ export function FrakIFrameClientProvider({
48
+ style,
49
+ children,
50
+ }: {
51
+ style?: CSSProperties;
52
+ children?: ReactNode;
53
+ }) {
54
+ const config = useFrakConfig();
55
+
56
+ // Using a state for the client since using directly a client built inside the ref cause re-render loop
57
+ const [client, setClient] = useState<FrakClient | undefined>(undefined);
58
+
59
+ // Create the iframe that will be used to communicate with the wallet
60
+ const iFrame = createElement("iframe", {
61
+ ...baseIframeProps,
62
+ src: `${config.walletUrl}/listener`,
63
+ style: style ?? baseIframeProps.style,
64
+ ref: (iframe: HTMLIFrameElement) => {
65
+ if (!iframe || client) {
66
+ return;
67
+ }
68
+ setClient(
69
+ createIFrameFrakClient({
70
+ iframe,
71
+ config,
72
+ })
73
+ );
74
+ },
75
+ });
76
+
77
+ // Create the component that will provide the client
78
+ const providerComponent = createElement(
79
+ FrakIFrameClientContext.Provider,
80
+ { value: client },
81
+ children
82
+ );
83
+
84
+ // Return both components
85
+ return createElement(Fragment, null, iFrame, providerComponent);
86
+ }
@@ -0,0 +1,7 @@
1
+ export type { FrakConfigProviderProps } from "./FrakConfigProvider";
2
+ export { FrakConfigContext, FrakConfigProvider } from "./FrakConfigProvider";
3
+ export type { FrakIFrameClientProps } from "./FrakIFrameClientProvider";
4
+ export {
5
+ FrakIFrameClientContext,
6
+ FrakIFrameClientProvider,
7
+ } from "./FrakIFrameClientProvider";