@evervault/react-native 2.6.0 → 2.6.2

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 (41) hide show
  1. package/package.json +3 -2
  2. package/src/Card/Cvc.test.tsx +41 -0
  3. package/src/Card/Cvc.tsx +58 -0
  4. package/src/Card/Expiry.tsx +26 -0
  5. package/src/Card/Holder.tsx +27 -0
  6. package/src/Card/Number.test.tsx +76 -0
  7. package/src/Card/Number.tsx +54 -0
  8. package/src/Card/Root.test.tsx +341 -0
  9. package/src/Card/Root.tsx +150 -0
  10. package/src/Card/index.ts +28 -0
  11. package/src/Card/schema.ts +41 -0
  12. package/src/Card/types.ts +57 -0
  13. package/src/Card/utils.test.ts +271 -0
  14. package/src/Card/utils.ts +129 -0
  15. package/src/EvervaultProvider.test.tsx +24 -0
  16. package/src/EvervaultProvider.tsx +43 -0
  17. package/src/Input.test.tsx +420 -0
  18. package/src/Input.tsx +182 -0
  19. package/src/ThreeDSecure/Frame.test.tsx +87 -0
  20. package/src/ThreeDSecure/Frame.tsx +50 -0
  21. package/src/ThreeDSecure/Root.test.tsx +67 -0
  22. package/src/ThreeDSecure/Root.tsx +23 -0
  23. package/src/ThreeDSecure/config.ts +3 -0
  24. package/src/ThreeDSecure/context.ts +6 -0
  25. package/src/ThreeDSecure/event.ts +19 -0
  26. package/src/ThreeDSecure/index.ts +17 -0
  27. package/src/ThreeDSecure/session.test.ts +524 -0
  28. package/src/ThreeDSecure/session.ts +184 -0
  29. package/src/ThreeDSecure/types.ts +80 -0
  30. package/src/ThreeDSecure/useThreeDSecure.test.tsx +244 -0
  31. package/src/ThreeDSecure/useThreeDSecure.ts +64 -0
  32. package/src/__mocks__/NativeEvervault.ts +13 -0
  33. package/src/__mocks__/react-native-webview.tsx +6 -0
  34. package/src/context.ts +14 -0
  35. package/src/index.ts +21 -0
  36. package/src/sdk.test.ts +122 -0
  37. package/src/sdk.ts +71 -0
  38. package/src/specs/NativeEvervault.ts +67 -0
  39. package/src/useEvervault.test.tsx +31 -0
  40. package/src/useEvervault.ts +14 -0
  41. package/src/utils.ts +41 -0
@@ -0,0 +1,87 @@
1
+ import { render } from "@testing-library/react-native";
2
+ import { WebView } from "../__mocks__/react-native-webview";
3
+ import { ThreeDSecureFrame } from "./Frame";
4
+ import { ErrorBoundary } from "../utils";
5
+ import { EvervaultProvider } from "../EvervaultProvider";
6
+ import { ThreeDSecure } from "./Root";
7
+ import { CHALLENGE_DOMAIN_3DS } from "./config";
8
+
9
+ vi.mock("react-native-webview", () => ({ WebView }));
10
+
11
+ it("throws an error if used outside of an EvervaultProvider", () => {
12
+ const onError = vi.fn();
13
+ render(
14
+ <ErrorBoundary onError={onError}>
15
+ <ThreeDSecureFrame />
16
+ </ErrorBoundary>
17
+ );
18
+
19
+ expect(onError).toHaveBeenCalledWith(
20
+ new Error("`useEvervault` must be used within an `EvervaultProvider`.")
21
+ );
22
+ });
23
+
24
+ it("throws an error if used outside of a ThreeDSecure component", () => {
25
+ const onError = vi.fn();
26
+ render(
27
+ <ErrorBoundary onError={onError}>
28
+ <EvervaultProvider teamId="team_123" appId="app_123">
29
+ <ThreeDSecureFrame />
30
+ </EvervaultProvider>
31
+ </ErrorBoundary>
32
+ );
33
+
34
+ expect(onError).toHaveBeenCalledWith(
35
+ new Error(
36
+ "`ThreeDSecure.Frame` must be used within a `ThreeDSecure` component."
37
+ )
38
+ );
39
+ });
40
+
41
+ it("renders null if there is no session", () => {
42
+ const { queryByTestId } = render(
43
+ <EvervaultProvider teamId="team_123" appId="app_123">
44
+ <ThreeDSecure
45
+ state={{
46
+ session: null,
47
+ isVisible: false,
48
+ cancel: vi.fn(),
49
+ start: vi.fn(),
50
+ }}
51
+ >
52
+ <ThreeDSecureFrame />
53
+ </ThreeDSecure>
54
+ </EvervaultProvider>
55
+ );
56
+
57
+ expect(queryByTestId("webview")).toBeNull();
58
+ });
59
+
60
+ it("renders a webview with the correct url", () => {
61
+ const { getByTestId } = render(
62
+ <EvervaultProvider teamId="team_123" appId="app_123">
63
+ <ThreeDSecure
64
+ state={{
65
+ session: {
66
+ sessionId: "session_123",
67
+ cancel: vi.fn(),
68
+ get: vi.fn(),
69
+ },
70
+ isVisible: true,
71
+ cancel: vi.fn(),
72
+ start: vi.fn(),
73
+ }}
74
+ >
75
+ <ThreeDSecureFrame />
76
+ </ThreeDSecure>
77
+ </EvervaultProvider>
78
+ );
79
+
80
+ const webview = getByTestId("webview");
81
+ expect(webview).toBeOnTheScreen();
82
+ expect(webview).toHaveProp("source", {
83
+ uri: `https://${CHALLENGE_DOMAIN_3DS}/?session=session_123&app=app_123&team=team_123`,
84
+ });
85
+ expect(webview).toHaveProp("hideKeyboardAccessoryView", true);
86
+ expect(webview).toHaveProp("overScrollMode", "content");
87
+ });
@@ -0,0 +1,50 @@
1
+ import { useContext, useMemo } from "react";
2
+ import { StyleProp, StyleSheet, ViewStyle } from "react-native";
3
+ import { useEvervault } from "../useEvervault";
4
+ import { WebView } from "react-native-webview";
5
+ import { CHALLENGE_DOMAIN_3DS } from "./config";
6
+ import { ThreeDSecureContext } from "./context";
7
+
8
+ export interface ThreeDSecureFrameProps {
9
+ style?: StyleProp<ViewStyle>;
10
+ }
11
+
12
+ export function ThreeDSecureFrame({ style }: ThreeDSecureFrameProps) {
13
+ const evervault = useEvervault();
14
+
15
+ const context = useContext(ThreeDSecureContext);
16
+ if (!context) {
17
+ throw new Error(
18
+ "`ThreeDSecure.Frame` must be used within a `ThreeDSecure` component."
19
+ );
20
+ }
21
+
22
+ const uri = useMemo(() => {
23
+ if (!context.session) return null;
24
+
25
+ const params = new URLSearchParams();
26
+ params.set("session", context.session.sessionId);
27
+ params.set("app", evervault.appId);
28
+ params.set("team", evervault.teamId);
29
+
30
+ return `https://${CHALLENGE_DOMAIN_3DS}/?${params.toString()}`;
31
+ }, [context.session, evervault.appId, evervault.teamId]);
32
+
33
+ if (!uri) return null;
34
+
35
+ return (
36
+ <WebView
37
+ containerStyle={[defaultStyles.webView, style]}
38
+ source={{ uri }}
39
+ hideKeyboardAccessoryView
40
+ overScrollMode="content"
41
+ />
42
+ );
43
+ }
44
+
45
+ const defaultStyles = StyleSheet.create({
46
+ webView: {
47
+ flex: 1,
48
+ width: "100%",
49
+ },
50
+ });
@@ -0,0 +1,67 @@
1
+ import { PropsWithChildren } from "react";
2
+ import { EvervaultProvider } from "../EvervaultProvider";
3
+ import { render, screen } from "@testing-library/react-native";
4
+ import { ThreeDSecure } from "./Root";
5
+ import { Text } from "react-native";
6
+
7
+ function wrapper({ children }: PropsWithChildren) {
8
+ return (
9
+ <EvervaultProvider teamId="team_123" appId="app_123">
10
+ {children}
11
+ </EvervaultProvider>
12
+ );
13
+ }
14
+
15
+ it("renders null when the session is null", () => {
16
+ render(
17
+ <ThreeDSecure
18
+ state={{
19
+ session: null,
20
+ isVisible: false,
21
+ cancel: vi.fn(),
22
+ start: vi.fn(),
23
+ }}
24
+ >
25
+ <Text testID="child">Hello</Text>
26
+ </ThreeDSecure>,
27
+ { wrapper }
28
+ );
29
+
30
+ expect(screen.queryByTestId("child")).toBeNull();
31
+ });
32
+
33
+ it("renders null when the session is not visible", () => {
34
+ render(
35
+ <ThreeDSecure
36
+ state={{
37
+ session: { sessionId: "session_123", cancel: vi.fn(), get: vi.fn() },
38
+ isVisible: false,
39
+ cancel: vi.fn(),
40
+ start: vi.fn(),
41
+ }}
42
+ >
43
+ <Text testID="child">Hello</Text>
44
+ </ThreeDSecure>,
45
+ { wrapper }
46
+ );
47
+
48
+ expect(screen.queryByTestId("child")).toBeNull();
49
+ });
50
+
51
+ it("renders the children when the session defined and visible", () => {
52
+ render(
53
+ <ThreeDSecure
54
+ state={{
55
+ session: { sessionId: "session_123", cancel: vi.fn(), get: vi.fn() },
56
+ isVisible: true,
57
+ cancel: vi.fn(),
58
+ start: vi.fn(),
59
+ }}
60
+ >
61
+ <Text testID="child">Hello</Text>
62
+ </ThreeDSecure>,
63
+ { wrapper }
64
+ );
65
+
66
+ expect(screen.getByTestId("child")).toBeOnTheScreen();
67
+ });
@@ -0,0 +1,23 @@
1
+ import { ThreeDSecureState } from "./types";
2
+ import { useEvervault } from "../useEvervault";
3
+ import { ThreeDSecureContext } from "./context";
4
+ import { PropsWithChildren } from "react";
5
+
6
+ export interface ThreeDSecureProps extends PropsWithChildren {
7
+ /**
8
+ * The 3DS session state returned from the `useThreeDSecure` hook.
9
+ */
10
+ state: ThreeDSecureState;
11
+ }
12
+
13
+ export function ThreeDSecure({ state, children }: ThreeDSecureProps) {
14
+ useEvervault();
15
+
16
+ if (!state.session) return null;
17
+
18
+ return (
19
+ <ThreeDSecureContext.Provider value={state}>
20
+ {state.isVisible && children}
21
+ </ThreeDSecureContext.Provider>
22
+ );
23
+ }
@@ -0,0 +1,3 @@
1
+ export const EV_API_DOMAIN = process.env.EV_API_DOMAIN || "api.evervault.com";
2
+ export const CHALLENGE_DOMAIN_3DS =
3
+ process.env.CHALLENGE_DOMAIN_3DS || "3ds.evervault.com";
@@ -0,0 +1,6 @@
1
+ import { createContext } from "react";
2
+ import { ThreeDSecureState } from "./types";
3
+
4
+ export const ThreeDSecureContext = createContext<ThreeDSecureState | null>(
5
+ null
6
+ );
@@ -0,0 +1,19 @@
1
+ import { ThreeDSecureSession } from "./types";
2
+
3
+ export type ThreeDSecureEventType = "requestChallenge";
4
+
5
+ export class ThreeDSecureEvent {
6
+ constructor(
7
+ public readonly type: ThreeDSecureEventType,
8
+ public readonly session: ThreeDSecureSession,
9
+ private _defaultPrevented: boolean = false
10
+ ) {}
11
+
12
+ public preventDefault() {
13
+ this._defaultPrevented = true;
14
+ }
15
+
16
+ public get defaultPrevented() {
17
+ return this._defaultPrevented;
18
+ }
19
+ }
@@ -0,0 +1,17 @@
1
+ import { ThreeDSecure as ThreeDSecureRoot } from "./Root";
2
+ import { ThreeDSecureFrame } from "./Frame";
3
+
4
+ export const ThreeDSecure = Object.assign(ThreeDSecureRoot, {
5
+ Frame: ThreeDSecureFrame,
6
+ });
7
+
8
+ export type { ThreeDSecureProps } from "./Root";
9
+ export type { ThreeDSecureFrameProps } from "./Frame";
10
+
11
+ export type {
12
+ ThreeDSecureState,
13
+ ThreeDSecureSession,
14
+ ThreeDSecureCallbacks,
15
+ } from "./types";
16
+
17
+ export { useThreeDSecure } from "./useThreeDSecure";