@evervault/react-native 2.0.0

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 (177) hide show
  1. package/README.md +63 -0
  2. package/android/app/build/generated/source/codegen/java/com/facebook/fbreact/specs/NativeEvervaultSpec.java +60 -0
  3. package/android/app/build/generated/source/codegen/java/com/facebook/fbreact/specs/NativeRNCWebViewModuleSpec.java +42 -0
  4. package/android/app/build/generated/source/codegen/java/com/facebook/react/viewmanagers/RNCWebViewManagerDelegate.java +294 -0
  5. package/android/app/build/generated/source/codegen/java/com/facebook/react/viewmanagers/RNCWebViewManagerInterface.java +104 -0
  6. package/android/app/build/generated/source/codegen/jni/CMakeLists.txt +36 -0
  7. package/android/app/build/generated/source/codegen/jni/NativeEvervaultSpec-generated.cpp +62 -0
  8. package/android/app/build/generated/source/codegen/jni/NativeEvervaultSpec.h +31 -0
  9. package/android/app/build/generated/source/codegen/jni/RNCWebViewSpec-generated.cpp +38 -0
  10. package/android/app/build/generated/source/codegen/jni/RNCWebViewSpec.h +31 -0
  11. package/android/app/build/generated/source/codegen/jni/react/renderer/components/NativeEvervaultSpec/NativeEvervaultSpecJSI-generated.cpp +68 -0
  12. package/android/app/build/generated/source/codegen/jni/react/renderer/components/NativeEvervaultSpec/NativeEvervaultSpecJSI.h +112 -0
  13. package/android/app/build/generated/source/codegen/jni/react/renderer/components/RNCWebViewSpec/ComponentDescriptors.cpp +22 -0
  14. package/android/app/build/generated/source/codegen/jni/react/renderer/components/RNCWebViewSpec/ComponentDescriptors.h +24 -0
  15. package/android/app/build/generated/source/codegen/jni/react/renderer/components/RNCWebViewSpec/EventEmitters.cpp +241 -0
  16. package/android/app/build/generated/source/codegen/jni/react/renderer/components/RNCWebViewSpec/EventEmitters.h +263 -0
  17. package/android/app/build/generated/source/codegen/jni/react/renderer/components/RNCWebViewSpec/Props.cpp +99 -0
  18. package/android/app/build/generated/source/codegen/jni/react/renderer/components/RNCWebViewSpec/Props.h +488 -0
  19. package/android/app/build/generated/source/codegen/jni/react/renderer/components/RNCWebViewSpec/RNCWebViewSpecJSI-generated.cpp +35 -0
  20. package/android/app/build/generated/source/codegen/jni/react/renderer/components/RNCWebViewSpec/RNCWebViewSpecJSI.h +76 -0
  21. package/android/app/build/generated/source/codegen/jni/react/renderer/components/RNCWebViewSpec/ShadowNodes.cpp +17 -0
  22. package/android/app/build/generated/source/codegen/jni/react/renderer/components/RNCWebViewSpec/ShadowNodes.h +32 -0
  23. package/android/app/build/generated/source/codegen/jni/react/renderer/components/RNCWebViewSpec/States.cpp +16 -0
  24. package/android/app/build/generated/source/codegen/jni/react/renderer/components/RNCWebViewSpec/States.h +29 -0
  25. package/android/build.gradle +32 -0
  26. package/android/src/main/java/com/nativeevervault/EvervaultModule.kt +114 -0
  27. package/android/src/main/java/com/nativeevervault/EvervaultPackage.kt +29 -0
  28. package/build/Card/Cvc.d.ts +5 -0
  29. package/build/Card/Cvc.d.ts.map +1 -0
  30. package/build/Card/Cvc.test.d.ts +2 -0
  31. package/build/Card/Cvc.test.d.ts.map +1 -0
  32. package/build/Card/Expiry.d.ts +5 -0
  33. package/build/Card/Expiry.d.ts.map +1 -0
  34. package/build/Card/Holder.d.ts +5 -0
  35. package/build/Card/Holder.d.ts.map +1 -0
  36. package/build/Card/Number.d.ts +5 -0
  37. package/build/Card/Number.d.ts.map +1 -0
  38. package/build/Card/Number.test.d.ts +2 -0
  39. package/build/Card/Number.test.d.ts.map +1 -0
  40. package/build/Card/Root.d.ts +36 -0
  41. package/build/Card/Root.d.ts.map +1 -0
  42. package/build/Card/Root.test.d.ts +2 -0
  43. package/build/Card/Root.test.d.ts.map +1 -0
  44. package/build/Card/index.d.ts +23 -0
  45. package/build/Card/index.d.ts.map +1 -0
  46. package/build/Card/schema.d.ts +30 -0
  47. package/build/Card/schema.d.ts.map +1 -0
  48. package/build/Card/types.d.ts +31 -0
  49. package/build/Card/types.d.ts.map +1 -0
  50. package/build/Card/utils.d.ts +17 -0
  51. package/build/Card/utils.d.ts.map +1 -0
  52. package/build/Card/utils.test.d.ts +2 -0
  53. package/build/Card/utils.test.d.ts.map +1 -0
  54. package/build/EvervaultProvider.d.ts +7 -0
  55. package/build/EvervaultProvider.d.ts.map +1 -0
  56. package/build/EvervaultProvider.test.d.ts +2 -0
  57. package/build/EvervaultProvider.test.d.ts.map +1 -0
  58. package/build/Input.d.ts +14 -0
  59. package/build/Input.d.ts.map +1 -0
  60. package/build/Input.test.d.ts +2 -0
  61. package/build/Input.test.d.ts.map +1 -0
  62. package/build/ThreeDSecure/Frame.d.ts +6 -0
  63. package/build/ThreeDSecure/Frame.d.ts.map +1 -0
  64. package/build/ThreeDSecure/Frame.test.d.ts +2 -0
  65. package/build/ThreeDSecure/Frame.test.d.ts.map +1 -0
  66. package/build/ThreeDSecure/Root.d.ts +10 -0
  67. package/build/ThreeDSecure/Root.d.ts.map +1 -0
  68. package/build/ThreeDSecure/Root.test.d.ts +2 -0
  69. package/build/ThreeDSecure/Root.test.d.ts.map +1 -0
  70. package/build/ThreeDSecure/config.d.ts +3 -0
  71. package/build/ThreeDSecure/config.d.ts.map +1 -0
  72. package/build/ThreeDSecure/context.d.ts +3 -0
  73. package/build/ThreeDSecure/context.d.ts.map +1 -0
  74. package/build/ThreeDSecure/index.d.ts +10 -0
  75. package/build/ThreeDSecure/index.d.ts.map +1 -0
  76. package/build/ThreeDSecure/session.d.ts +6 -0
  77. package/build/ThreeDSecure/session.d.ts.map +1 -0
  78. package/build/ThreeDSecure/session.test.d.ts +2 -0
  79. package/build/ThreeDSecure/session.test.d.ts.map +1 -0
  80. package/build/ThreeDSecure/types.d.ts +57 -0
  81. package/build/ThreeDSecure/types.d.ts.map +1 -0
  82. package/build/ThreeDSecure/useThreeDSecure.d.ts +3 -0
  83. package/build/ThreeDSecure/useThreeDSecure.d.ts.map +1 -0
  84. package/build/ThreeDSecure/useThreeDSecure.test.d.ts +2 -0
  85. package/build/ThreeDSecure/useThreeDSecure.test.d.ts.map +1 -0
  86. package/build/__mocks__/NativeEvervault.d.ts +4 -0
  87. package/build/__mocks__/NativeEvervault.d.ts.map +1 -0
  88. package/build/__mocks__/react-native-webview.d.ts +3 -0
  89. package/build/__mocks__/react-native-webview.d.ts.map +1 -0
  90. package/build/context.d.ts +9 -0
  91. package/build/context.d.ts.map +1 -0
  92. package/build/generated/ios/FBReactNativeSpec/FBReactNativeSpec-generated.mm +2321 -0
  93. package/build/generated/ios/FBReactNativeSpec/FBReactNativeSpec.h +2761 -0
  94. package/build/generated/ios/FBReactNativeSpecJSI-generated.cpp +2923 -0
  95. package/build/generated/ios/FBReactNativeSpecJSI.h +7718 -0
  96. package/build/generated/ios/NativeEvervaultSpec/NativeEvervaultSpec-generated.mm +74 -0
  97. package/build/generated/ios/NativeEvervaultSpec/NativeEvervaultSpec.h +80 -0
  98. package/build/generated/ios/NativeEvervaultSpecJSI-generated.cpp +68 -0
  99. package/build/generated/ios/NativeEvervaultSpecJSI.h +112 -0
  100. package/build/generated/ios/RCTModulesConformingToProtocolsProvider.h +18 -0
  101. package/build/generated/ios/RCTModulesConformingToProtocolsProvider.mm +33 -0
  102. package/build/generated/ios/RNCWebViewSpec/RNCWebViewSpec-generated.mm +46 -0
  103. package/build/generated/ios/RNCWebViewSpec/RNCWebViewSpec.h +62 -0
  104. package/build/generated/ios/RNCWebViewSpecJSI-generated.cpp +35 -0
  105. package/build/generated/ios/RNCWebViewSpecJSI.h +76 -0
  106. package/build/generated/ios/react/renderer/components/RNCWebViewSpec/ComponentDescriptors.cpp +22 -0
  107. package/build/generated/ios/react/renderer/components/RNCWebViewSpec/ComponentDescriptors.h +24 -0
  108. package/build/generated/ios/react/renderer/components/RNCWebViewSpec/EventEmitters.cpp +241 -0
  109. package/build/generated/ios/react/renderer/components/RNCWebViewSpec/EventEmitters.h +263 -0
  110. package/build/generated/ios/react/renderer/components/RNCWebViewSpec/Props.cpp +99 -0
  111. package/build/generated/ios/react/renderer/components/RNCWebViewSpec/Props.h +488 -0
  112. package/build/generated/ios/react/renderer/components/RNCWebViewSpec/RCTComponentViewHelpers.h +218 -0
  113. package/build/generated/ios/react/renderer/components/RNCWebViewSpec/ShadowNodes.cpp +17 -0
  114. package/build/generated/ios/react/renderer/components/RNCWebViewSpec/ShadowNodes.h +32 -0
  115. package/build/generated/ios/react/renderer/components/RNCWebViewSpec/States.cpp +16 -0
  116. package/build/generated/ios/react/renderer/components/RNCWebViewSpec/States.h +29 -0
  117. package/build/index.cjs.js +7732 -0
  118. package/build/index.cjs.js.map +1 -0
  119. package/build/index.d.ts +9 -0
  120. package/build/index.d.ts.map +1 -0
  121. package/build/index.esm.js +7702 -0
  122. package/build/sdk.d.ts +9 -0
  123. package/build/sdk.d.ts.map +1 -0
  124. package/build/sdk.test.d.ts +2 -0
  125. package/build/sdk.test.d.ts.map +1 -0
  126. package/build/specs/NativeEvervault.d.ts +59 -0
  127. package/build/specs/NativeEvervault.d.ts.map +1 -0
  128. package/build/useEvervault.d.ts +2 -0
  129. package/build/useEvervault.d.ts.map +1 -0
  130. package/build/useEvervault.test.d.ts +2 -0
  131. package/build/useEvervault.test.d.ts.map +1 -0
  132. package/build/utils.d.ts +15 -0
  133. package/build/utils.d.ts.map +1 -0
  134. package/ios/NativeEvervault-Bridging-Header.h +2 -0
  135. package/ios/NativeEvervault.mm +38 -0
  136. package/ios/NativeEvervault.swift +62 -0
  137. package/native-evervault.podspec +20 -0
  138. package/package.json +85 -0
  139. package/src/Card/Cvc.test.tsx +41 -0
  140. package/src/Card/Cvc.tsx +51 -0
  141. package/src/Card/Expiry.tsx +26 -0
  142. package/src/Card/Holder.tsx +27 -0
  143. package/src/Card/Number.test.tsx +55 -0
  144. package/src/Card/Number.tsx +47 -0
  145. package/src/Card/Root.test.tsx +260 -0
  146. package/src/Card/Root.tsx +118 -0
  147. package/src/Card/index.ts +28 -0
  148. package/src/Card/schema.ts +51 -0
  149. package/src/Card/types.ts +50 -0
  150. package/src/Card/utils.test.ts +271 -0
  151. package/src/Card/utils.ts +127 -0
  152. package/src/EvervaultProvider.test.tsx +24 -0
  153. package/src/EvervaultProvider.tsx +43 -0
  154. package/src/Input.test.tsx +138 -0
  155. package/src/Input.tsx +136 -0
  156. package/src/ThreeDSecure/Frame.test.tsx +87 -0
  157. package/src/ThreeDSecure/Frame.tsx +50 -0
  158. package/src/ThreeDSecure/Root.test.tsx +67 -0
  159. package/src/ThreeDSecure/Root.tsx +23 -0
  160. package/src/ThreeDSecure/config.ts +3 -0
  161. package/src/ThreeDSecure/context.ts +6 -0
  162. package/src/ThreeDSecure/index.ts +17 -0
  163. package/src/ThreeDSecure/session.test.ts +329 -0
  164. package/src/ThreeDSecure/session.ts +132 -0
  165. package/src/ThreeDSecure/types.ts +67 -0
  166. package/src/ThreeDSecure/useThreeDSecure.test.tsx +133 -0
  167. package/src/ThreeDSecure/useThreeDSecure.ts +47 -0
  168. package/src/__mocks__/NativeEvervault.ts +13 -0
  169. package/src/__mocks__/react-native-webview.tsx +6 -0
  170. package/src/context.ts +14 -0
  171. package/src/index.ts +21 -0
  172. package/src/sdk.test.ts +122 -0
  173. package/src/sdk.ts +71 -0
  174. package/src/specs/NativeEvervault.ts +67 -0
  175. package/src/useEvervault.test.tsx +31 -0
  176. package/src/useEvervault.ts +14 -0
  177. package/src/utils.ts +41 -0
package/src/Input.tsx ADDED
@@ -0,0 +1,136 @@
1
+ import {
2
+ ForwardedRef,
3
+ forwardRef,
4
+ ReactNode,
5
+ Ref,
6
+ RefObject,
7
+ useCallback,
8
+ useImperativeHandle,
9
+ useRef,
10
+ } from "react";
11
+ import { TextInput, TextInputProps } from "react-native";
12
+ import { mergeRefs } from "./utils";
13
+ import { Controller, useFormContext } from "react-hook-form";
14
+ import MaskInput, { Mask, MaskArray } from "react-native-mask-input";
15
+
16
+ export type EvervaultInput = Pick<
17
+ TextInput,
18
+ | "isFocused"
19
+ | "focus"
20
+ | "blur"
21
+ | "clear"
22
+ | "measure"
23
+ | "measureInWindow"
24
+ | "measureLayout"
25
+ >;
26
+
27
+ function useForwardedInputRef(
28
+ ref: ForwardedRef<EvervaultInput>
29
+ ): RefObject<TextInput> {
30
+ const inputRef = useRef<TextInput>(null);
31
+
32
+ useImperativeHandle<EvervaultInput, EvervaultInput>(
33
+ ref,
34
+ useCallback(
35
+ () => ({
36
+ isFocused() {
37
+ return inputRef.current?.isFocused() ?? false;
38
+ },
39
+ focus() {
40
+ inputRef.current?.focus();
41
+ },
42
+ blur() {
43
+ inputRef.current?.blur();
44
+ },
45
+ clear() {
46
+ inputRef.current?.clear();
47
+ },
48
+ measure(callback) {
49
+ inputRef.current?.measure(callback);
50
+ },
51
+ measureInWindow(callback) {
52
+ inputRef.current?.measureInWindow(callback);
53
+ },
54
+ measureLayout(relativeToNativeComponentRef, onSuccess, onFail) {
55
+ inputRef.current?.measureLayout(
56
+ relativeToNativeComponentRef,
57
+ onSuccess,
58
+ onFail
59
+ );
60
+ },
61
+ }),
62
+ [inputRef]
63
+ )
64
+ );
65
+
66
+ return inputRef;
67
+ }
68
+
69
+ export type BaseEvervaultInputProps = Omit<
70
+ TextInputProps,
71
+ "onChange" | "onChangeText" | "value" | "defaultValue"
72
+ >;
73
+
74
+ export function mask(format: string): MaskArray {
75
+ return format.split("").map((char) => {
76
+ if (char === "9") {
77
+ return /\d/;
78
+ }
79
+ return char;
80
+ });
81
+ }
82
+
83
+ export interface EvervaultInputProps<Values extends Record<string, unknown>>
84
+ extends BaseEvervaultInputProps {
85
+ name: keyof Values;
86
+ mask?: Mask;
87
+ }
88
+
89
+ export const EvervaultInput = forwardRef<
90
+ EvervaultInput,
91
+ EvervaultInputProps<Record<string, unknown>>
92
+ >(function EvervaultInput({ name, mask, ...props }, ref) {
93
+ const inputRef = useForwardedInputRef(ref);
94
+
95
+ const methods = useFormContext();
96
+
97
+ return (
98
+ <Controller
99
+ control={methods.control}
100
+ name={name}
101
+ shouldUnregister
102
+ render={({ field, fieldState }) => (
103
+ <MaskInput
104
+ // Overridable props
105
+ id={field.name}
106
+ {...props}
107
+ // Strict props
108
+ ref={mergeRefs(inputRef, field.ref)}
109
+ editable={!field.disabled && (props.editable ?? true)}
110
+ onBlur={(evt) => {
111
+ methods.setValue(field.name, field.value, {
112
+ shouldDirty: true,
113
+ shouldTouch: true,
114
+ shouldValidate: true,
115
+ });
116
+ props.onBlur?.(evt);
117
+ }}
118
+ mask={mask}
119
+ maskAutoComplete={!!mask}
120
+ value={field.value}
121
+ onChangeText={(masked, unmasked) => {
122
+ methods.setValue(field.name, unmasked, {
123
+ shouldDirty: true,
124
+ shouldValidate: !!fieldState.error || fieldState.isTouched,
125
+ });
126
+ }}
127
+ // Remove unwanted props
128
+ defaultValue={undefined}
129
+ onChange={undefined}
130
+ />
131
+ )}
132
+ />
133
+ );
134
+ }) as <Values extends Record<string, unknown>>(
135
+ props: EvervaultInputProps<Values> & { ref?: Ref<EvervaultInput> }
136
+ ) => ReactNode;
@@ -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,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";