@evervault/react-native 2.2.0 → 2.3.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.
- package/build/Card/schema.d.ts +2 -12
- package/build/Card/schema.d.ts.map +1 -1
- package/build/Card/types.d.ts +7 -1
- package/build/Card/types.d.ts.map +1 -1
- package/build/Card/utils.d.ts.map +1 -1
- package/build/index.cjs.js +43 -29
- package/build/index.cjs.js.map +1 -1
- package/build/index.esm.js +43 -29
- package/package.json +2 -2
- package/src/Card/Root.test.tsx +81 -0
- package/src/Card/schema.ts +25 -35
- package/src/Card/types.ts +7 -0
- package/src/Card/utils.ts +2 -0
package/build/index.esm.js
CHANGED
|
@@ -6774,7 +6774,7 @@ const h = [
|
|
|
6774
6774
|
isLocal: false,
|
|
6775
6775
|
numberValidationRules: {
|
|
6776
6776
|
luhnCheck: true,
|
|
6777
|
-
ranges: [[300, 305], 36, 38, 39],
|
|
6777
|
+
ranges: [[300, 305], 3095, 36, 38, 39],
|
|
6778
6778
|
lengths: [14, 16, 19]
|
|
6779
6779
|
},
|
|
6780
6780
|
securityCodeValidationRules: {
|
|
@@ -6786,7 +6786,7 @@ const h = [
|
|
|
6786
6786
|
isLocal: false,
|
|
6787
6787
|
numberValidationRules: {
|
|
6788
6788
|
luhnCheck: true,
|
|
6789
|
-
ranges: [6011, [644, 649],
|
|
6789
|
+
ranges: [6011, [644, 649], [65e4, 651999], [653150, 659999], 622],
|
|
6790
6790
|
lengths: [16, 19]
|
|
6791
6791
|
},
|
|
6792
6792
|
securityCodeValidationRules: {
|
|
@@ -6798,7 +6798,16 @@ const h = [
|
|
|
6798
6798
|
isLocal: false,
|
|
6799
6799
|
numberValidationRules: {
|
|
6800
6800
|
luhnCheck: true,
|
|
6801
|
-
ranges: [
|
|
6801
|
+
ranges: [
|
|
6802
|
+
2131,
|
|
6803
|
+
1800,
|
|
6804
|
+
[3088, 3094],
|
|
6805
|
+
[3096, 3102],
|
|
6806
|
+
[3112, 3120],
|
|
6807
|
+
[3158, 3159],
|
|
6808
|
+
[3337, 3349],
|
|
6809
|
+
[3528, 3589]
|
|
6810
|
+
],
|
|
6802
6811
|
lengths: [16, 17, 18, 19]
|
|
6803
6812
|
},
|
|
6804
6813
|
securityCodeValidationRules: {
|
|
@@ -6846,16 +6855,20 @@ const h = [
|
|
|
6846
6855
|
numberValidationRules: {
|
|
6847
6856
|
luhnCheck: true,
|
|
6848
6857
|
ranges: [
|
|
6858
|
+
5018,
|
|
6859
|
+
5020,
|
|
6860
|
+
5038,
|
|
6861
|
+
5893,
|
|
6862
|
+
6101,
|
|
6863
|
+
6304,
|
|
6864
|
+
6759,
|
|
6865
|
+
6761,
|
|
6866
|
+
6762,
|
|
6867
|
+
6763,
|
|
6849
6868
|
493698,
|
|
6850
6869
|
[5e5, 504174],
|
|
6851
6870
|
[504176, 506698],
|
|
6852
6871
|
[506779, 508999],
|
|
6853
|
-
[56, 59],
|
|
6854
|
-
60,
|
|
6855
|
-
61,
|
|
6856
|
-
63,
|
|
6857
|
-
64,
|
|
6858
|
-
67,
|
|
6859
6872
|
69
|
|
6860
6873
|
],
|
|
6861
6874
|
lengths: [12, 13, 14, 15, 16, 17, 18, 19]
|
|
@@ -6961,6 +6974,18 @@ const h = [
|
|
|
6961
6974
|
securityCodeValidationRules: {
|
|
6962
6975
|
lengths: [0]
|
|
6963
6976
|
}
|
|
6977
|
+
},
|
|
6978
|
+
{
|
|
6979
|
+
name: "rupay",
|
|
6980
|
+
isLocal: false,
|
|
6981
|
+
numberValidationRules: {
|
|
6982
|
+
luhnCheck: true,
|
|
6983
|
+
ranges: [60, 81, 82, 508, [652100, 653149], [817200, 819899]],
|
|
6984
|
+
lengths: [16]
|
|
6985
|
+
},
|
|
6986
|
+
securityCodeValidationRules: {
|
|
6987
|
+
lengths: [3]
|
|
6988
|
+
}
|
|
6964
6989
|
}
|
|
6965
6990
|
];
|
|
6966
6991
|
function g(n, e, t) {
|
|
@@ -7027,7 +7052,7 @@ function C(n, e) {
|
|
|
7027
7052
|
isValid: l
|
|
7028
7053
|
};
|
|
7029
7054
|
}
|
|
7030
|
-
function
|
|
7055
|
+
function R(n) {
|
|
7031
7056
|
var r;
|
|
7032
7057
|
const e = /^(0[1-9]|1[[0-2]).*$/, t = n.match(e), s = t ? parseInt(t[1].toString(), 10) : null, l = /^(0[1-9]|1[[0-2])(\d{2})$/, i = n.match(l), a = i ? parseInt(i[2].toString(), 10) : null;
|
|
7033
7058
|
if (s) {
|
|
@@ -7093,7 +7118,7 @@ function areValuesComplete(values) {
|
|
|
7093
7118
|
if ("number" in values && !f(values.number ?? "").isValid) {
|
|
7094
7119
|
return false;
|
|
7095
7120
|
}
|
|
7096
|
-
if ("expiry" in values && !
|
|
7121
|
+
if ("expiry" in values && !R(values.expiry ?? "").isValid) {
|
|
7097
7122
|
return false;
|
|
7098
7123
|
}
|
|
7099
7124
|
if ("cvc" in values &&
|
|
@@ -7105,6 +7130,8 @@ function areValuesComplete(values) {
|
|
|
7105
7130
|
function isAcceptedBrand(acceptedBrands, cardNumberValidationResult) {
|
|
7106
7131
|
if (!acceptedBrands?.length)
|
|
7107
7132
|
return true;
|
|
7133
|
+
if (!cardNumberValidationResult.isValid)
|
|
7134
|
+
return false;
|
|
7108
7135
|
const { brand, localBrands } = cardNumberValidationResult;
|
|
7109
7136
|
const acceptedBrandsSet = new Set(acceptedBrands);
|
|
7110
7137
|
const isBrandAccepted = brand !== null && acceptedBrandsSet.has(brand);
|
|
@@ -7112,7 +7139,7 @@ function isAcceptedBrand(acceptedBrands, cardNumberValidationResult) {
|
|
|
7112
7139
|
return isBrandAccepted || isLocalBrandAccepted;
|
|
7113
7140
|
}
|
|
7114
7141
|
function formatExpiry(expiry) {
|
|
7115
|
-
const parsedExpiry =
|
|
7142
|
+
const parsedExpiry = R(expiry);
|
|
7116
7143
|
if (!parsedExpiry.isValid) {
|
|
7117
7144
|
return null;
|
|
7118
7145
|
}
|
|
@@ -7123,19 +7150,19 @@ function formatExpiry(expiry) {
|
|
|
7123
7150
|
}
|
|
7124
7151
|
|
|
7125
7152
|
function getCardFormSchema(acceptedBrands) {
|
|
7126
|
-
return z
|
|
7127
|
-
.object({
|
|
7153
|
+
return z.object({
|
|
7128
7154
|
name: z.string().min(1, "Missing name"),
|
|
7129
7155
|
number: z
|
|
7130
7156
|
.string()
|
|
7131
7157
|
.min(1, "Required")
|
|
7132
7158
|
.refine((value) => f(value).isValid, {
|
|
7133
7159
|
message: "Invalid card number",
|
|
7134
|
-
})
|
|
7160
|
+
})
|
|
7161
|
+
.refine((value) => isAcceptedBrand(acceptedBrands, f(value)), { message: "Brand not accepted" }),
|
|
7135
7162
|
expiry: z
|
|
7136
7163
|
.string()
|
|
7137
7164
|
.min(1, "Required")
|
|
7138
|
-
.refine((value) =>
|
|
7165
|
+
.refine((value) => R(value).isValid, {
|
|
7139
7166
|
message: "Invalid expiry",
|
|
7140
7167
|
}),
|
|
7141
7168
|
cvc: z
|
|
@@ -7144,19 +7171,6 @@ function getCardFormSchema(acceptedBrands) {
|
|
|
7144
7171
|
.refine((value) => C(value).isValid, {
|
|
7145
7172
|
message: "Invalid CVC",
|
|
7146
7173
|
}),
|
|
7147
|
-
})
|
|
7148
|
-
.superRefine((value, ctx) => {
|
|
7149
|
-
const validation = f(value.number);
|
|
7150
|
-
if (!validation.isValid)
|
|
7151
|
-
return;
|
|
7152
|
-
const isAccepted = isAcceptedBrand(acceptedBrands, validation);
|
|
7153
|
-
if (!isAccepted) {
|
|
7154
|
-
ctx.addIssue({
|
|
7155
|
-
code: z.ZodIssueCode.custom,
|
|
7156
|
-
message: "Brand not accepted",
|
|
7157
|
-
path: ["number"],
|
|
7158
|
-
});
|
|
7159
|
-
}
|
|
7160
7174
|
});
|
|
7161
7175
|
}
|
|
7162
7176
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evervault/react-native",
|
|
3
3
|
"description": "Evervault SDK for React Native",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.3.0",
|
|
5
5
|
"source": "./src/index.ts",
|
|
6
6
|
"main": "./build/index.cjs.js",
|
|
7
7
|
"module": "./build/index.esm.js",
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"react-hook-form": "^7.54.2",
|
|
74
74
|
"react-native-mask-input": "^1.2.3",
|
|
75
75
|
"zod": "^3.24.2",
|
|
76
|
-
"@evervault/card-validator": "1.
|
|
76
|
+
"@evervault/card-validator": "1.4.0"
|
|
77
77
|
},
|
|
78
78
|
"scripts": {
|
|
79
79
|
"prebuild": "pnpm codegen",
|
package/src/Card/Root.test.tsx
CHANGED
|
@@ -258,3 +258,84 @@ it("adds Invalid error when input is blurred with an invalid value", async () =>
|
|
|
258
258
|
});
|
|
259
259
|
});
|
|
260
260
|
});
|
|
261
|
+
|
|
262
|
+
it("adds 'Brand not accepted' error when brand is not accepted", async () => {
|
|
263
|
+
const onChange = vi.fn();
|
|
264
|
+
const { getByTestId } = render(
|
|
265
|
+
<Card onChange={onChange} acceptedBrands={["american-express"]}>
|
|
266
|
+
<CardNumber testID="number" />
|
|
267
|
+
</Card>,
|
|
268
|
+
{ wrapper }
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
const number = getByTestId("number");
|
|
272
|
+
|
|
273
|
+
const user = userEvent.setup();
|
|
274
|
+
await user.type(number, "4242");
|
|
275
|
+
fireEvent(number, "blur");
|
|
276
|
+
|
|
277
|
+
await waitFor(() => {
|
|
278
|
+
expect(onChange).toHaveBeenLastCalledWith({
|
|
279
|
+
card: {
|
|
280
|
+
name: null,
|
|
281
|
+
brand: "visa",
|
|
282
|
+
localBrands: [],
|
|
283
|
+
number: null,
|
|
284
|
+
lastFour: null,
|
|
285
|
+
bin: null,
|
|
286
|
+
expiry: null,
|
|
287
|
+
cvc: null,
|
|
288
|
+
},
|
|
289
|
+
isValid: false,
|
|
290
|
+
isComplete: false,
|
|
291
|
+
errors: {
|
|
292
|
+
number: "Invalid card number",
|
|
293
|
+
},
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
await user.type(number, "4242 4242 4242");
|
|
298
|
+
fireEvent(number, "blur");
|
|
299
|
+
|
|
300
|
+
await waitFor(() => {
|
|
301
|
+
expect(onChange).toHaveBeenLastCalledWith({
|
|
302
|
+
card: {
|
|
303
|
+
name: null,
|
|
304
|
+
brand: "visa",
|
|
305
|
+
localBrands: [],
|
|
306
|
+
number: expect.any(String),
|
|
307
|
+
lastFour: "4242",
|
|
308
|
+
bin: "42424242",
|
|
309
|
+
expiry: null,
|
|
310
|
+
cvc: null,
|
|
311
|
+
},
|
|
312
|
+
isValid: false,
|
|
313
|
+
isComplete: true,
|
|
314
|
+
errors: {
|
|
315
|
+
number: "Brand not accepted",
|
|
316
|
+
},
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
await user.clear(number);
|
|
321
|
+
await user.type(number, "3782 822463 10005");
|
|
322
|
+
fireEvent(number, "blur");
|
|
323
|
+
|
|
324
|
+
await waitFor(() => {
|
|
325
|
+
expect(onChange).toHaveBeenLastCalledWith({
|
|
326
|
+
card: {
|
|
327
|
+
name: null,
|
|
328
|
+
brand: "american-express",
|
|
329
|
+
localBrands: [],
|
|
330
|
+
number: expect.any(String),
|
|
331
|
+
lastFour: "0005",
|
|
332
|
+
bin: "378282",
|
|
333
|
+
expiry: null,
|
|
334
|
+
cvc: null,
|
|
335
|
+
},
|
|
336
|
+
isValid: true,
|
|
337
|
+
isComplete: true,
|
|
338
|
+
errors: {},
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
});
|
package/src/Card/schema.ts
CHANGED
|
@@ -8,44 +8,34 @@ import { CardBrandName } from "./types";
|
|
|
8
8
|
import { isAcceptedBrand } from "./utils";
|
|
9
9
|
|
|
10
10
|
export function getCardFormSchema(acceptedBrands: CardBrandName[]) {
|
|
11
|
-
return z
|
|
12
|
-
.
|
|
13
|
-
name: z.string().min(1, "Missing name"),
|
|
11
|
+
return z.object({
|
|
12
|
+
name: z.string().min(1, "Missing name"),
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
number: z
|
|
15
|
+
.string()
|
|
16
|
+
.min(1, "Required")
|
|
17
|
+
.refine((value) => validateNumber(value).isValid, {
|
|
18
|
+
message: "Invalid card number",
|
|
19
|
+
})
|
|
20
|
+
.refine(
|
|
21
|
+
(value) => isAcceptedBrand(acceptedBrands, validateNumber(value)),
|
|
22
|
+
{ message: "Brand not accepted" }
|
|
23
|
+
),
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
expiry: z
|
|
26
|
+
.string()
|
|
27
|
+
.min(1, "Required")
|
|
28
|
+
.refine((value) => validateExpiry(value).isValid, {
|
|
29
|
+
message: "Invalid expiry",
|
|
30
|
+
}),
|
|
28
31
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
.superRefine((value, ctx) => {
|
|
37
|
-
const validation = validateNumber(value.number);
|
|
38
|
-
if (!validation.isValid) return;
|
|
39
|
-
|
|
40
|
-
const isAccepted = isAcceptedBrand(acceptedBrands, validation);
|
|
41
|
-
if (!isAccepted) {
|
|
42
|
-
ctx.addIssue({
|
|
43
|
-
code: z.ZodIssueCode.custom,
|
|
44
|
-
message: "Brand not accepted",
|
|
45
|
-
path: ["number"],
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
});
|
|
32
|
+
cvc: z
|
|
33
|
+
.string()
|
|
34
|
+
.min(1, "Required")
|
|
35
|
+
.refine((value) => validateCVC(value).isValid, {
|
|
36
|
+
message: "Invalid CVC",
|
|
37
|
+
}),
|
|
38
|
+
});
|
|
49
39
|
}
|
|
50
40
|
|
|
51
41
|
export type CardFormValues = z.infer<ReturnType<typeof getCardFormSchema>>;
|
package/src/Card/types.ts
CHANGED
|
@@ -13,11 +13,18 @@ export const CARD_BRAND_NAMES = [
|
|
|
13
13
|
"hiper",
|
|
14
14
|
"szep",
|
|
15
15
|
"uatp",
|
|
16
|
+
"rupay",
|
|
16
17
|
] as const;
|
|
17
18
|
|
|
18
19
|
export type CardBrandName = (typeof CARD_BRAND_NAMES)[number];
|
|
19
20
|
|
|
20
21
|
export interface CardConfig {
|
|
22
|
+
/**
|
|
23
|
+
* The brands that are accepted by the card form.
|
|
24
|
+
* Pass an empty array to accept all brands.
|
|
25
|
+
*
|
|
26
|
+
* @default []
|
|
27
|
+
*/
|
|
21
28
|
acceptedBrands?: CardBrandName[];
|
|
22
29
|
}
|
|
23
30
|
|
package/src/Card/utils.ts
CHANGED
|
@@ -101,6 +101,8 @@ export function isAcceptedBrand(
|
|
|
101
101
|
cardNumberValidationResult: CardNumberValidationResult
|
|
102
102
|
): boolean {
|
|
103
103
|
if (!acceptedBrands?.length) return true;
|
|
104
|
+
|
|
105
|
+
if (!cardNumberValidationResult.isValid) return false;
|
|
104
106
|
const { brand, localBrands } = cardNumberValidationResult;
|
|
105
107
|
|
|
106
108
|
const acceptedBrandsSet = new Set(acceptedBrands);
|