skyflow-js 1.24.0 → 1.25.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/CHANGELOG.md +6 -0
- package/README.md +559 -62
- package/dist/sdkNodeBuild/index.js +1 -1
- package/dist/sdkNodeBuild/index.js.gz +0 -0
- package/package.json +1 -1
- package/types/utils/constants.d.ts +12 -0
- package/types/utils/helpers/index.d.ts +2 -0
- package/types/utils/logs.d.ts +3 -0
- package/types/utils/validators/index.d.ts +1 -0
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# skyflow-js
|
|
2
|
-
Skyflow’s
|
|
2
|
+
Skyflow’s JavaScript SDK can be used to securely collect, tokenize, and reveal sensitive data in the browser without exposing your front-end infrastructure to sensitive data.
|
|
3
3
|
|
|
4
4
|
---
|
|
5
5
|
|
|
@@ -11,6 +11,7 @@ Skyflow’s Javascript SDK can be used to securely collect, tokenize, and reveal
|
|
|
11
11
|
- [**Including Skyflow.js**](#Including-Skyflowjs)
|
|
12
12
|
- [**Initializing Skyflow.js**](#Initializing-Skyflowjs)
|
|
13
13
|
- [**Securely collecting data client-side**](#Securely-collecting-data-client-side)
|
|
14
|
+
- [**Securely collecting data client-side using Composable Elements**](#Securely-collecting-data-client-side-using-Composable-Elements)
|
|
14
15
|
- [**Securely revealing data client-side**](#Securely-revealing-data-client-side)
|
|
15
16
|
|
|
16
17
|
---
|
|
@@ -140,9 +141,9 @@ To insert data into the vault, use the `insert(records, options?)` method of the
|
|
|
140
141
|
const records = {
|
|
141
142
|
records: [
|
|
142
143
|
{
|
|
143
|
-
table: 'string',
|
|
144
|
+
table: 'string', // Table into which record should be inserted.
|
|
144
145
|
fields: {
|
|
145
|
-
column1: 'value',
|
|
146
|
+
column1: 'value', // Column names should match vault column names.
|
|
146
147
|
//...additional fields here
|
|
147
148
|
},
|
|
148
149
|
},
|
|
@@ -151,11 +152,11 @@ const records = {
|
|
|
151
152
|
};
|
|
152
153
|
|
|
153
154
|
const options = {
|
|
154
|
-
tokens: true,
|
|
155
|
-
upsert: [
|
|
155
|
+
tokens: true, // Indicates whether or not tokens should be returned for the inserted data. Defaults to 'true'
|
|
156
|
+
upsert: [ // Upsert operations support in the vault
|
|
156
157
|
{
|
|
157
|
-
table: 'string',
|
|
158
|
-
column: 'value',
|
|
158
|
+
table: 'string', // Table name
|
|
159
|
+
column: 'value', // Unique column in the table
|
|
159
160
|
}
|
|
160
161
|
]
|
|
161
162
|
}
|
|
@@ -229,13 +230,13 @@ The `table` and `column` fields indicate which table and column in the vault the
|
|
|
229
230
|
- Use dot delimited strings to specify columns nested inside JSON fields (e.g. `address.street.line1`)
|
|
230
231
|
|
|
231
232
|
The `inputStyles` field accepts a style object which consists of CSS properties that should be applied to the form element in the following states:
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
233
|
+
* `base`: all variants inherit from these styles
|
|
234
|
+
* `complete`: applied when the Element has valid input
|
|
235
|
+
* `empty`: applied when the Element has no input
|
|
236
|
+
* `focus`: applied when the Element has focus
|
|
237
|
+
* `invalid`: applied when the Element has invalid input
|
|
238
|
+
* `cardIcon`: applied to the card type icon in CARD_NUMBER Element
|
|
239
|
+
* `copyIcon`: applied to copy icon in Elements when enableCopy option is true
|
|
239
240
|
|
|
240
241
|
Styles are specified with [JSS](https://cssinjs.org/?v=v10.7.1).
|
|
241
242
|
|
|
@@ -307,7 +308,7 @@ Finally, the `type` field takes a Skyflow ElementType. Each type applies the app
|
|
|
307
308
|
- `FILE_INPUT`
|
|
308
309
|
|
|
309
310
|
|
|
310
|
-
The `INPUT_FIELD` type is a custom UI element without any built-in validations.
|
|
311
|
+
The `INPUT_FIELD` type is a custom UI element without any built-in validations. For information on validations, see [validations](#validations).
|
|
311
312
|
|
|
312
313
|
Along with CollectElement we can define other options which takes a object of optional parameters as described below:
|
|
313
314
|
|
|
@@ -403,26 +404,25 @@ When the form is ready to be submitted, call the `collect(options?)` method on t
|
|
|
403
404
|
|
|
404
405
|
```javascript
|
|
405
406
|
const options = {
|
|
406
|
-
tokens: true,
|
|
407
|
+
tokens: true, // Optional, indicates whether tokens for the collected data should be returned. Defaults to 'true'.
|
|
407
408
|
additionalFields: {
|
|
408
409
|
records: [
|
|
409
410
|
{
|
|
410
|
-
table: 'string',
|
|
411
|
+
table: 'string', // Table into which record should be inserted.
|
|
411
412
|
fields: {
|
|
412
|
-
column1: 'value',
|
|
413
|
+
column1: 'value', // Column names should match vault column names.
|
|
413
414
|
// ...additional fields here.
|
|
414
415
|
},
|
|
415
416
|
},
|
|
416
417
|
// ...additional records here.
|
|
417
418
|
],
|
|
418
|
-
},
|
|
419
|
-
upsert: [
|
|
420
|
-
// Upsert operations support in the vault
|
|
419
|
+
}, // Optional
|
|
420
|
+
upsert: [ // Upsert operations support in the vault
|
|
421
421
|
{
|
|
422
|
-
table: 'string',
|
|
423
|
-
column: 'value',
|
|
422
|
+
table: 'string', // Table name
|
|
423
|
+
column: 'value', // Unique column in the table
|
|
424
424
|
},
|
|
425
|
-
],
|
|
425
|
+
], // Optional
|
|
426
426
|
};
|
|
427
427
|
|
|
428
428
|
container.collect(options);
|
|
@@ -512,78 +512,78 @@ const container = skyflowClient.container(Skyflow.ContainerType.COLLECT)
|
|
|
512
512
|
|
|
513
513
|
//Step 2
|
|
514
514
|
const cardNumberElement = container.create({
|
|
515
|
-
table:
|
|
516
|
-
column:
|
|
515
|
+
table: 'cards',
|
|
516
|
+
column: 'card_number',
|
|
517
517
|
inputStyles: {
|
|
518
518
|
base: {
|
|
519
|
-
color:
|
|
519
|
+
color: '#1d1d1d',
|
|
520
520
|
},
|
|
521
521
|
cardIcon:{
|
|
522
|
-
position:
|
|
523
|
-
left:
|
|
524
|
-
bottom:
|
|
522
|
+
position: 'absolute',
|
|
523
|
+
left:'8px',
|
|
524
|
+
bottom:'calc(50% - 12px)'
|
|
525
525
|
},
|
|
526
526
|
},
|
|
527
527
|
labelStyles: {
|
|
528
528
|
base: {
|
|
529
|
-
fontSize:
|
|
530
|
-
fontWeight:
|
|
529
|
+
fontSize: '12px',
|
|
530
|
+
fontWeight: 'bold'
|
|
531
531
|
}
|
|
532
532
|
},
|
|
533
533
|
errorTextStyles: {
|
|
534
534
|
base: {
|
|
535
|
-
color:
|
|
535
|
+
color: '#f44336'
|
|
536
536
|
}
|
|
537
537
|
},
|
|
538
|
-
placeholder:
|
|
539
|
-
label:
|
|
538
|
+
placeholder: 'Card Number',
|
|
539
|
+
label: 'card_number',
|
|
540
540
|
type: Skyflow.ElementType.CARD_NUMBER
|
|
541
541
|
})
|
|
542
|
-
|
|
542
|
+
|
|
543
|
+
|
|
543
544
|
const cvvElement = container.create({
|
|
544
|
-
table:
|
|
545
|
-
column:
|
|
545
|
+
table: 'cards',
|
|
546
|
+
column: 'cvv',
|
|
546
547
|
inputStyles: {
|
|
547
548
|
base: {
|
|
548
|
-
color:
|
|
549
|
+
color: '#1d1d1d',
|
|
549
550
|
},
|
|
550
551
|
cardIcon:{
|
|
551
|
-
position:
|
|
552
|
-
left:
|
|
553
|
-
bottom:
|
|
552
|
+
position: 'absolute',
|
|
553
|
+
left:'8px',
|
|
554
|
+
bottom:'calc(50% - 12px)'
|
|
554
555
|
},
|
|
555
556
|
},
|
|
556
557
|
labelStyles: {
|
|
557
558
|
base: {
|
|
558
|
-
fontSize:
|
|
559
|
-
fontWeight:
|
|
559
|
+
fontSize: '12px',
|
|
560
|
+
fontWeight: 'bold'
|
|
560
561
|
}
|
|
561
562
|
},
|
|
562
563
|
errorTextStyles: {
|
|
563
564
|
base: {
|
|
564
|
-
color:
|
|
565
|
+
color: '#f44336'
|
|
565
566
|
}
|
|
566
567
|
},
|
|
567
|
-
placeholder:
|
|
568
|
-
label:
|
|
568
|
+
placeholder: 'CVV',
|
|
569
|
+
label: 'cvv',
|
|
569
570
|
type: Skyflow.ElementType.CVV
|
|
570
571
|
})
|
|
571
572
|
|
|
572
573
|
// Step 3
|
|
573
|
-
cardNumberElement.mount(
|
|
574
|
-
cvvElement.mount(
|
|
574
|
+
cardNumberElement.mount('#cardNumber') //Assumes there is a div with id='#cardNumber' in the webpage.
|
|
575
|
+
cvvElement.mount('#cvv'); //Assumes there is a div with id='#cvv' in the webpage.
|
|
575
576
|
|
|
576
577
|
// Step 4
|
|
577
578
|
container.collect({
|
|
578
579
|
tokens: true,
|
|
579
580
|
upsert: [
|
|
580
581
|
{
|
|
581
|
-
table:
|
|
582
|
-
column:
|
|
582
|
+
table: 'cards',
|
|
583
|
+
column: 'card_number',
|
|
583
584
|
}
|
|
584
585
|
]
|
|
585
586
|
})
|
|
586
|
-
|
|
587
587
|
```
|
|
588
588
|
**Skyflow returns tokens for the record you just inserted.**
|
|
589
589
|
```javascript
|
|
@@ -707,7 +707,7 @@ const elementMatchRule = {
|
|
|
707
707
|
type: Skyflow.ValidationRuleType.ELEMENT_VALUE_MATCH_RULE,
|
|
708
708
|
params: {
|
|
709
709
|
element: pinElement,
|
|
710
|
-
error:
|
|
710
|
+
error: 'PIN does not match',
|
|
711
711
|
},
|
|
712
712
|
};
|
|
713
713
|
|
|
@@ -758,9 +758,9 @@ state : {
|
|
|
758
758
|
```
|
|
759
759
|
|
|
760
760
|
`Note:`
|
|
761
|
-
values of SkyflowElements will be returned in
|
|
761
|
+
values of SkyflowElements will be returned in element state object only when `env` is `DEV`, else it is empty string i.e, '', but in case of CARD_NUMBER type element when the `env` is `PROD` for all the card types except AMEX, it will return first eight digits, for AMEX it will return first six digits and rest all digits in masked format.
|
|
762
762
|
|
|
763
|
-
##### Sample [code snippet](https://github.com/skyflowapi/skyflow-js/blob/master/samples/using-script-tag/collect-element-listeners.html) for using listeners
|
|
763
|
+
##### Sample [code snippet](https://github.com/skyflowapi/skyflow-js/blob/master/samples/using-script-tag/collect-element-listeners.html) for using listeners
|
|
764
764
|
```javascript
|
|
765
765
|
// Create Skyflow client.
|
|
766
766
|
const skyflowClient = Skyflow.init({
|
|
@@ -774,6 +774,11 @@ const skyflowClient = Skyflow.init({
|
|
|
774
774
|
|
|
775
775
|
const container = skyflowClient.container(Skyflow.ContainerType.COLLECT);
|
|
776
776
|
|
|
777
|
+
const cardHolderName = container.create({
|
|
778
|
+
table: 'pii_fields',
|
|
779
|
+
column: 'first_name',
|
|
780
|
+
type: Skyflow.ElementType.CARDHOLDER_NAME,
|
|
781
|
+
});
|
|
777
782
|
const cardNumber = container.create({
|
|
778
783
|
table: 'pii_fields',
|
|
779
784
|
column: 'primary_card.card_number',
|
|
@@ -781,6 +786,13 @@ const cardNumber = container.create({
|
|
|
781
786
|
});
|
|
782
787
|
|
|
783
788
|
cardNumber.mount('#cardNumberContainer');
|
|
789
|
+
cardHolderName.mount('#cardHolderNameContainer');
|
|
790
|
+
|
|
791
|
+
// Subscribing to CHANGE event, which gets triggered when element changes.
|
|
792
|
+
cardHolderName.on(Skyflow.EventName.CHANGE, state => {
|
|
793
|
+
// Your implementation when Change event occurs.
|
|
794
|
+
console.log(state);
|
|
795
|
+
});
|
|
784
796
|
|
|
785
797
|
// Subscribing to CHANGE event, which gets triggered when element changes.
|
|
786
798
|
cardNumber.on(Skyflow.EventName.CHANGE, state => {
|
|
@@ -792,24 +804,39 @@ cardNumber.on(Skyflow.EventName.CHANGE, state => {
|
|
|
792
804
|
##### Sample Element state object when `env` is `DEV`
|
|
793
805
|
|
|
794
806
|
```javascript
|
|
807
|
+
{
|
|
808
|
+
elementType: 'CARDHOLDER_NAME',
|
|
809
|
+
isEmpty: false,
|
|
810
|
+
isFocused: true,
|
|
811
|
+
isValid: false,
|
|
812
|
+
value: 'John',
|
|
813
|
+
};
|
|
795
814
|
{
|
|
796
815
|
elementType: 'CARD_NUMBER',
|
|
797
816
|
isEmpty: false,
|
|
798
817
|
isFocused: true,
|
|
799
818
|
isValid: false,
|
|
800
|
-
value: '
|
|
819
|
+
value: '4111-1111-1111-1111',
|
|
801
820
|
};
|
|
802
821
|
```
|
|
803
822
|
##### Sample Element state object when `env` is `PROD`
|
|
804
823
|
|
|
805
824
|
```javascript
|
|
806
825
|
{
|
|
807
|
-
elementType: '
|
|
826
|
+
elementType: 'CARDHOLDER_NAME',
|
|
808
827
|
isEmpty: false,
|
|
809
828
|
isFocused: true,
|
|
810
829
|
isValid: false,
|
|
811
830
|
value: '',
|
|
812
831
|
};
|
|
832
|
+
{
|
|
833
|
+
elementType: 'CARD_NUMBER',
|
|
834
|
+
isEmpty: false,
|
|
835
|
+
isFocused: true,
|
|
836
|
+
isValid: false,
|
|
837
|
+
value: '4111-1111-XXXX-XXXX',
|
|
838
|
+
};
|
|
839
|
+
|
|
813
840
|
```
|
|
814
841
|
|
|
815
842
|
### UI Error for Collect Elements
|
|
@@ -867,7 +894,446 @@ cardNumber.clearValue();
|
|
|
867
894
|
|
|
868
895
|
---
|
|
869
896
|
|
|
897
|
+
# Securely collecting data client-side using Composable Elements
|
|
898
|
+
|
|
899
|
+
Composable Elements combine multiple Skyflow Elements in a single iframe, letting you create multiple Skyflow Elements in a single row. The following steps create a composable element and securely collect data through it.
|
|
900
|
+
|
|
901
|
+
### Step 1: Create a composable container
|
|
902
|
+
|
|
903
|
+
Create a container for the composable element using the `container(Skyflow.ContainerType)` method of the Skyflow client:
|
|
904
|
+
|
|
905
|
+
``` javascript
|
|
906
|
+
const collectContainer = skyflow.container(Skyflow.ContainerType.COMPOSABLE,containerOptions);
|
|
907
|
+
```
|
|
908
|
+
The container requires an options object that contains the following keys:
|
|
909
|
+
|
|
910
|
+
1. `layout`: An array that indicates the number of rows in the container and the number of elements in each row. The index value of the array defines the number of rows, and each value in the array represents the number of elements in that row, in order.
|
|
911
|
+
|
|
912
|
+
For example: `[2,1]` means the container has two rows, with two elements in the first row and one element in the second row.
|
|
913
|
+
|
|
914
|
+
`Note`: The sum of values in the layout array should be equal to the number of elements created
|
|
915
|
+
|
|
916
|
+
2. `styles`: CSS styles to apply to the composable container.
|
|
917
|
+
3. `errorTextStyles`: CSS styles to apply if an error is encountered.
|
|
918
|
+
|
|
919
|
+
```javascript
|
|
920
|
+
const options = {
|
|
921
|
+
layout: [2, 1], // Required
|
|
922
|
+
styles: { // Optional
|
|
923
|
+
base: {
|
|
924
|
+
border: '1px solid #DFE3EB',
|
|
925
|
+
padding: '8px',
|
|
926
|
+
borderRadius: '4px',
|
|
927
|
+
margin: '12px 2px',
|
|
928
|
+
},
|
|
929
|
+
},
|
|
930
|
+
errorTextStyles: { // Optional
|
|
931
|
+
base: {
|
|
932
|
+
color: 'red',
|
|
933
|
+
},
|
|
934
|
+
},
|
|
935
|
+
};
|
|
936
|
+
```
|
|
937
|
+
|
|
938
|
+
### Step 2: Create Composable Elements
|
|
939
|
+
Composable Elements use the following schema:
|
|
940
|
+
|
|
941
|
+
```javascript
|
|
942
|
+
const composableElement = {
|
|
943
|
+
table: 'string', // Required. The table this data belongs to.
|
|
944
|
+
column: 'string', // Required. The column this data belongs to.
|
|
945
|
+
type: Skyflow.ElementType, // Skyflow.ElementType enum.
|
|
946
|
+
inputStyles: {}, // Optional. Styles applied to the form element.
|
|
947
|
+
labelStyles: {}, // Optional. Styles for the label of the collect element.
|
|
948
|
+
errorTextStyles: {}, // Optional. Styles for the errorText of the collect element.
|
|
949
|
+
label: 'string', // Optional. Label for the form element.
|
|
950
|
+
placeholder: 'string', // Optional. Placeholder for the form element.
|
|
951
|
+
altText: 'string', // (DEPRECATED) Initial value for the collect element.
|
|
952
|
+
validations: [], // Optional. Array of validation rules.
|
|
953
|
+
}
|
|
954
|
+
```
|
|
955
|
+
The `table` and `column` fields indicate which table and column in the vault the Element correspond to.
|
|
956
|
+
|
|
957
|
+
Note: Use dot-delimited strings to specify columns nested inside JSON fields (for example, `address.street.line1`).
|
|
958
|
+
|
|
959
|
+
All elements can be styled with [JSS](https://cssinjs.org/?v=v10.7.1) syntax.
|
|
960
|
+
|
|
961
|
+
The `inputStyles` field accepts an object of CSS properties to apply to the form element in the following states:
|
|
962
|
+
|
|
963
|
+
* `base`: all variants inherit from these styles
|
|
964
|
+
* `complete`: applied when the Element has valid input
|
|
965
|
+
* `empty`: applied when the Element has no input
|
|
966
|
+
* `focus`: applied when the Element has focus
|
|
967
|
+
* `invalid`: applied when the Element has invalid input
|
|
968
|
+
* `cardIcon`: applied to the card type icon in CARD_NUMBER Element
|
|
969
|
+
* `copyIcon`: applied to copy icon in Elements when enableCopy option is true
|
|
970
|
+
|
|
971
|
+
An example of an `inputStyles` object:
|
|
972
|
+
|
|
973
|
+
```javascript
|
|
974
|
+
inputStyles: {
|
|
975
|
+
base: {
|
|
976
|
+
border: '1px solid #eae8ee',
|
|
977
|
+
padding: '10px 16px',
|
|
978
|
+
borderRadius: '4px',
|
|
979
|
+
color: '#1d1d1d',
|
|
980
|
+
},
|
|
981
|
+
complete: {
|
|
982
|
+
color: '#4caf50',
|
|
983
|
+
},
|
|
984
|
+
empty: {},
|
|
985
|
+
focus: {},
|
|
986
|
+
invalid: {
|
|
987
|
+
color: '#f44336',
|
|
988
|
+
},
|
|
989
|
+
cardIcon: {
|
|
990
|
+
position: 'absolute',
|
|
991
|
+
left: '8px',
|
|
992
|
+
bottom: 'calc(50% - 12px)',
|
|
993
|
+
},
|
|
994
|
+
copyIcon: {
|
|
995
|
+
position: 'absolute',
|
|
996
|
+
right: '8px',
|
|
997
|
+
},
|
|
998
|
+
}
|
|
999
|
+
```
|
|
1000
|
+
The `labelStyles` field supports the `base` and `focus` states.
|
|
1001
|
+
|
|
1002
|
+
An example `labelStyles` object:
|
|
1003
|
+
|
|
1004
|
+
```javascript
|
|
1005
|
+
labelStyles: {
|
|
1006
|
+
base: {
|
|
1007
|
+
fontSize: '12px',
|
|
1008
|
+
fontWeight: 'bold'
|
|
1009
|
+
},
|
|
1010
|
+
focus: {
|
|
1011
|
+
color: '#1d1d1d'
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
```
|
|
1015
|
+
The `errorTextStyles` field only supports the `base` state, which appears when there is an error in the composable element.
|
|
1016
|
+
|
|
1017
|
+
An example `errorTextStyles` object:
|
|
1018
|
+
|
|
1019
|
+
```javascript
|
|
1020
|
+
errorTextStyles: {
|
|
1021
|
+
base: {
|
|
1022
|
+
color: '#f44336'
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
```
|
|
1026
|
+
The JS SDK supports the following composable elements:
|
|
1027
|
+
|
|
1028
|
+
- `CARDHOLDER_NAME`
|
|
1029
|
+
- `CARD_NUMBER`
|
|
1030
|
+
- `EXPIRATION_DATE`
|
|
1031
|
+
- `EXPIRATION_MONTH`
|
|
1032
|
+
- `EXPIRATION_YEAR`
|
|
1033
|
+
- `CVV`
|
|
1034
|
+
- `INPUT_FIELD`
|
|
1035
|
+
- `PIN`
|
|
1036
|
+
|
|
1037
|
+
`Note`: Only when the entered value in the below composable elements is valid, the focus shifts automatically. The element types are:
|
|
1038
|
+
- `CARD_NUMBER`
|
|
1039
|
+
- `EXPIRATION_DATE`
|
|
1040
|
+
- `EXPIRATION_MONTH`
|
|
1041
|
+
- `EXPIRATION_YEAR`
|
|
1042
|
+
|
|
1043
|
+
The `INPUT_FIELD` type is a custom UI element without any built-in validations. For information on validations, see [validations](#validations).
|
|
1044
|
+
|
|
1045
|
+
Along with the Composable Element definition, you can define additional options for the element:
|
|
1046
|
+
|
|
1047
|
+
```javascript
|
|
1048
|
+
const options = {
|
|
1049
|
+
required: false, // Optional, indicates whether the field is marked as required. Defaults to 'false'
|
|
1050
|
+
enableCardIcon: true, // Optional, indicates whether card icon should be enabled (only applicable for CARD_NUMBER ElementType)
|
|
1051
|
+
format: String, // Optional, format for the element (only applicable currently for EXPIRATION_DATE ElementType),
|
|
1052
|
+
enableCopy: false // Optional, enables the copy icon in collect and reveal elements to copy text to clipboard. Defaults to 'false')
|
|
1053
|
+
}
|
|
1054
|
+
```
|
|
1055
|
+
|
|
1056
|
+
- `required`: Whether or not the field is marked as required. Defaults to `false`.
|
|
1057
|
+
- `enableCardIcon`: Whether or not the icon is visible for the CARD_NUMBER element. Defaults to `true`.
|
|
1058
|
+
- `format`: Format pattern for the element. Only applicable to EXPIRATION_DATE and EXPIRATION_YEAR element types.
|
|
1059
|
+
- `enableCopy`: Whether or not the copy icon is visible in collect and reveal elements. Defaults to `false`.
|
|
1060
|
+
|
|
1061
|
+
The accepted `EXPIRATION_DATE` values are
|
|
1062
|
+
|
|
1063
|
+
- `MM/YY` (default)
|
|
1064
|
+
- `MM/YYYY`
|
|
1065
|
+
- `YY/MM`
|
|
1066
|
+
- `YYYY/MM`
|
|
1067
|
+
|
|
1068
|
+
|
|
1069
|
+
The accepted `EXPIRATION_YEAR` values are
|
|
1070
|
+
|
|
1071
|
+
- `YY` (default)
|
|
1072
|
+
- `YYYY`
|
|
1073
|
+
|
|
1074
|
+
|
|
1075
|
+
Once you define the Element object and options, add it to the container using the `create(element, options)` method:
|
|
1076
|
+
|
|
1077
|
+
```javascript
|
|
1078
|
+
const composableElement = {
|
|
1079
|
+
table: 'string', // Required, the table this data belongs to.
|
|
1080
|
+
column: 'string', // Required, the column into which this data should be inserted.
|
|
1081
|
+
type: Skyflow.ElementType, // Skyflow.ElementType enum.
|
|
1082
|
+
inputStyles: {}, // Optional, styles that should be applied to the form element.
|
|
1083
|
+
labelStyles: {}, // Optional, styles that will be applied to the label of the collect element.
|
|
1084
|
+
errorTextStyles: {}, // Optional, styles that will be applied to the errorText of the collect element.
|
|
1085
|
+
label: 'string', // Optional, label for the form element.
|
|
1086
|
+
placeholder: 'string', // Optional, placeholder for the form element.
|
|
1087
|
+
altText: 'string', // (DEPRECATED) string that acts as an initial value for the collect element.
|
|
1088
|
+
validations: [], // Optional, array of validation rules.
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
const options = {
|
|
1092
|
+
required: false, // Optional, indicates whether the field is marked as required. Defaults to 'false'.
|
|
1093
|
+
enableCardIcon: true, // Optional, indicates whether card icon should be enabled (only applicable for CARD_NUMBER ElementType).
|
|
1094
|
+
format: String, // Optional, format for the element (only applicable currently for EXPIRATION_DATE ElementType).
|
|
1095
|
+
enableCopy: false, // Optional, enables the copy icon in collect and reveal elements to copy text to clipboard. Defaults to 'false').
|
|
1096
|
+
};
|
|
1097
|
+
|
|
1098
|
+
const element = container.create(composableElement, options);
|
|
1099
|
+
```
|
|
1100
|
+
|
|
1101
|
+
### Step 3: Mount Container to the DOM
|
|
1102
|
+
|
|
1103
|
+
|
|
1104
|
+
To specify where the Elements are rendered on your page, create a placeholder `<div>` element with unique `id` attribute. Use this empty `<div>` placeholder to mount the composable container.
|
|
1105
|
+
|
|
1106
|
+
```javascript
|
|
1107
|
+
<form>
|
|
1108
|
+
<div id="composableContainer"/>
|
|
1109
|
+
<br/>
|
|
1110
|
+
<div id="button-id"/>
|
|
1111
|
+
<button type="submit">Submit</button>
|
|
1112
|
+
</form>
|
|
1113
|
+
```
|
|
1114
|
+
Use the composable container's `mount(domElement)` method to insert the container's Elements into the specified `<div>`. For instance, the following call inserts Elements into the `<div>` with the `id "#composableContainer"`.
|
|
1115
|
+
|
|
1116
|
+
```javacript
|
|
1117
|
+
container.mount('#composableContainer');
|
|
1118
|
+
```
|
|
1119
|
+
|
|
1120
|
+
### Step 4: Collect data from elements
|
|
1121
|
+
|
|
870
1122
|
|
|
1123
|
+
When the form is ready to be submitted, call the container's `collect(options?)` method. The options parameter takes an object of optional parameters as follows:
|
|
1124
|
+
- `tokens`: Whether or not tokens for the collected data are returned. Defaults to 'true'
|
|
1125
|
+
- `additionalFields`: Non-PCI elements data to insert into the vault, specified in the records object format.
|
|
1126
|
+
- `upsert`: To support upsert operations, the table containing the data and a column marked as unique in that table.
|
|
1127
|
+
|
|
1128
|
+
```javascript
|
|
1129
|
+
const options = {
|
|
1130
|
+
tokens: true, // Optional, indicates whether tokens for the collected data should be returned. Defaults to 'true'.
|
|
1131
|
+
additionalFields: {
|
|
1132
|
+
records: [
|
|
1133
|
+
{
|
|
1134
|
+
table: 'string', // Table into which record should be inserted.
|
|
1135
|
+
fields: {
|
|
1136
|
+
column1: 'value', // Column names should match vault column names.
|
|
1137
|
+
// ...additional fields here.
|
|
1138
|
+
},
|
|
1139
|
+
},
|
|
1140
|
+
// ...additional records here.
|
|
1141
|
+
],
|
|
1142
|
+
}, // Optional
|
|
1143
|
+
upsert: [ // Upsert operations support in the vault
|
|
1144
|
+
{
|
|
1145
|
+
table: 'string', // Table name
|
|
1146
|
+
column: 'value', // Unique column in the table
|
|
1147
|
+
},
|
|
1148
|
+
], // Optional
|
|
1149
|
+
};
|
|
1150
|
+
```
|
|
1151
|
+
|
|
1152
|
+
### End to end example of collecting data with Composable Elements
|
|
1153
|
+
|
|
1154
|
+
```javascript
|
|
1155
|
+
// Step 1
|
|
1156
|
+
const containerOptions = {
|
|
1157
|
+
layout: [2, 1],
|
|
1158
|
+
styles: {
|
|
1159
|
+
base: {
|
|
1160
|
+
border: '1px solid #eae8ee',
|
|
1161
|
+
padding: '10px 16px',
|
|
1162
|
+
borderRadius: '4px',
|
|
1163
|
+
margin: '12px 2px',
|
|
1164
|
+
},
|
|
1165
|
+
},
|
|
1166
|
+
errorTextStyles: {
|
|
1167
|
+
base: {
|
|
1168
|
+
color: 'red',
|
|
1169
|
+
},
|
|
1170
|
+
},
|
|
1171
|
+
};
|
|
1172
|
+
|
|
1173
|
+
const composableContainer = skyflow.container(
|
|
1174
|
+
Skyflow.ContainerType.COMPOSABLE,
|
|
1175
|
+
containerOptions
|
|
1176
|
+
);
|
|
1177
|
+
|
|
1178
|
+
// Step 2
|
|
1179
|
+
|
|
1180
|
+
const collectStylesOptions = {
|
|
1181
|
+
inputStyles: {
|
|
1182
|
+
base: {
|
|
1183
|
+
fontFamily: 'Inter',
|
|
1184
|
+
fontStyle: 'normal',
|
|
1185
|
+
fontWeight: 400,
|
|
1186
|
+
fontSize: '14px',
|
|
1187
|
+
lineHeight: '21px',
|
|
1188
|
+
width: '294px',
|
|
1189
|
+
},
|
|
1190
|
+
},
|
|
1191
|
+
labelStyles: {},
|
|
1192
|
+
errorTextStyles: {
|
|
1193
|
+
base: {},
|
|
1194
|
+
},
|
|
1195
|
+
};
|
|
1196
|
+
|
|
1197
|
+
const cardHolderNameElement = composableContainer.create({
|
|
1198
|
+
table: 'pii_fields',
|
|
1199
|
+
column: 'first_name',
|
|
1200
|
+
...collectStylesOptions,
|
|
1201
|
+
placeholder: 'Cardholder Name',
|
|
1202
|
+
type: Skyflow.ElementType.CARDHOLDER_NAME,
|
|
1203
|
+
});
|
|
1204
|
+
|
|
1205
|
+
const cardNumberElement = composableContainer.create({
|
|
1206
|
+
table: 'pii_fields',
|
|
1207
|
+
column: 'card_number',
|
|
1208
|
+
...collectStylesOptions,
|
|
1209
|
+
placeholder: 'Card Number',
|
|
1210
|
+
type: Skyflow.ElementType.CARD_NUMBER,
|
|
1211
|
+
});
|
|
1212
|
+
|
|
1213
|
+
const cvvElement = composableContainer.create({
|
|
1214
|
+
table: 'pii_fields',
|
|
1215
|
+
column: 'cvv',
|
|
1216
|
+
...collectStylesOptions,
|
|
1217
|
+
placeholder: 'CVV',
|
|
1218
|
+
type: Skyflow.ElementType.CVV,
|
|
1219
|
+
});
|
|
1220
|
+
|
|
1221
|
+
// Step 3
|
|
1222
|
+
composableContainer.mount('#composableContainer'); // Assumes there is a div with id='#composableContainer' in the webpage.
|
|
1223
|
+
|
|
1224
|
+
// Step 4
|
|
1225
|
+
composableContainer.collect({
|
|
1226
|
+
tokens: true,
|
|
1227
|
+
});
|
|
1228
|
+
```
|
|
1229
|
+
### Sample Response:
|
|
1230
|
+
|
|
1231
|
+
```javascript
|
|
1232
|
+
{
|
|
1233
|
+
"records": [
|
|
1234
|
+
{
|
|
1235
|
+
"table": "pii_fields",
|
|
1236
|
+
"fields": {
|
|
1237
|
+
"first_name": "63b5eeee-3624-493f-825e-137a9336f882",
|
|
1238
|
+
"card_number": "f3907186-e7e2-466f-91e5-48e12c2bcbc1",
|
|
1239
|
+
"cvv": "7baf5bda-aa22-4587-a5c5-412f6f783a19",
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
]
|
|
1243
|
+
}
|
|
1244
|
+
```
|
|
1245
|
+
For information on validations, see [validations](#validations).
|
|
1246
|
+
|
|
1247
|
+
### Set an event listener on Composable Elements:
|
|
1248
|
+
|
|
1249
|
+
You can communicate with Skyflow Elements by listening to element events:
|
|
1250
|
+
|
|
1251
|
+
```javascript
|
|
1252
|
+
element.on(Skyflow.EventName,handler:function)
|
|
1253
|
+
```
|
|
1254
|
+
|
|
1255
|
+
|
|
1256
|
+
The SDK supports four events:
|
|
1257
|
+
|
|
1258
|
+
- `CHANGE`:riggered when the Element's value changes.
|
|
1259
|
+
- `READY`:riggered when the Element is fully rendered.
|
|
1260
|
+
- `FOCUS`: Triggered when the Element gains focus.
|
|
1261
|
+
- `BLUR`: Triggered when the Element loses focus.
|
|
1262
|
+
|
|
1263
|
+
The handler `function(state) => void` is a callback function you provide that's called when the event is fired with a state object that uses the following schema:
|
|
1264
|
+
|
|
1265
|
+
```javascript
|
|
1266
|
+
state : {
|
|
1267
|
+
elementType: Skyflow.ElementType
|
|
1268
|
+
isEmpty: boolean
|
|
1269
|
+
isFocused: boolean
|
|
1270
|
+
isValid: boolean
|
|
1271
|
+
value: string
|
|
1272
|
+
}
|
|
1273
|
+
```
|
|
1274
|
+
`Note`: Events only include element values when in the state object when env is DEV. By default, value is an empty string.
|
|
1275
|
+
|
|
1276
|
+
### Example Usage of Event Listener on Composable Elements
|
|
1277
|
+
|
|
1278
|
+
```javascript
|
|
1279
|
+
const containerOptions = {
|
|
1280
|
+
layout: [1],
|
|
1281
|
+
styles: {
|
|
1282
|
+
base: {
|
|
1283
|
+
border: '1px solid #eae8ee',
|
|
1284
|
+
padding: '10px 16px',
|
|
1285
|
+
borderRadius: '4px',
|
|
1286
|
+
margin: '12px 2px',
|
|
1287
|
+
}
|
|
1288
|
+
},
|
|
1289
|
+
errorTextStyles: {
|
|
1290
|
+
base: {
|
|
1291
|
+
color: 'red'
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
const composableContainer = skyflow.container(Skyflow.ContainerType.COMPOSABLE, containerOptions);
|
|
1297
|
+
|
|
1298
|
+
const cvv = composableContainer.create({
|
|
1299
|
+
table: 'pii_fields',
|
|
1300
|
+
column: 'primary_card.cvv',
|
|
1301
|
+
type: Skyflow.ElementType.CVV,
|
|
1302
|
+
});
|
|
1303
|
+
|
|
1304
|
+
composableContainer.mount('#cvvContainer');
|
|
1305
|
+
|
|
1306
|
+
// Subscribing to CHANGE event, which gets triggered when element changes.
|
|
1307
|
+
cvv.on(Skyflow.EventName.CHANGE, state => {
|
|
1308
|
+
// Your implementation when Change event occurs.
|
|
1309
|
+
console.log(state);
|
|
1310
|
+
});
|
|
1311
|
+
```
|
|
1312
|
+
|
|
1313
|
+
Sample Element state object when env is `DEV`
|
|
1314
|
+
|
|
1315
|
+
```javascript
|
|
1316
|
+
{
|
|
1317
|
+
elementType: 'CVV'
|
|
1318
|
+
isEmpty: false
|
|
1319
|
+
isFocused: true
|
|
1320
|
+
isValid: false
|
|
1321
|
+
value: '411'
|
|
1322
|
+
}
|
|
1323
|
+
```
|
|
1324
|
+
|
|
1325
|
+
Sample Element state object when env is `PROD`
|
|
1326
|
+
|
|
1327
|
+
```javascript
|
|
1328
|
+
{
|
|
1329
|
+
elementType: 'CVV'
|
|
1330
|
+
isEmpty: false
|
|
1331
|
+
isFocused: true
|
|
1332
|
+
isValid: false
|
|
1333
|
+
value: ''
|
|
1334
|
+
}
|
|
1335
|
+
```
|
|
1336
|
+
---
|
|
871
1337
|
# Securely revealing data client-side
|
|
872
1338
|
- [**Retrieving data from the vault**](#retrieving-data-from-the-vault)
|
|
873
1339
|
- [**Using Skyflow Elements to reveal data**](#using-skyflow-elements-to-reveal-data)
|
|
@@ -887,10 +1353,13 @@ const records = {
|
|
|
887
1353
|
records: [
|
|
888
1354
|
{
|
|
889
1355
|
token: 'string', // Token for the record to be fetched.
|
|
1356
|
+
redaction: RedactionType // Optional. Redaction to be applied for retrieved data.
|
|
890
1357
|
},
|
|
891
1358
|
],
|
|
892
1359
|
};
|
|
893
1360
|
|
|
1361
|
+
Note: If you do not provide a redaction type, RedactionType.PLAIN_TEXT is the default.
|
|
1362
|
+
|
|
894
1363
|
skyflow.detokenize(records);
|
|
895
1364
|
```
|
|
896
1365
|
An [example](https://github.com/skyflowapi/skyflow-js/blob/master/samples/using-script-tag/pure-js.html) of a detokenize call:
|
|
@@ -901,6 +1370,10 @@ skyflow.detokenize({
|
|
|
901
1370
|
{
|
|
902
1371
|
token: '131e70dc-6f76-4319-bdd3-96281e051051',
|
|
903
1372
|
},
|
|
1373
|
+
{
|
|
1374
|
+
token: '1r434532-6f76-4319-bdd3-96281e051051',
|
|
1375
|
+
redaction: Skyflow.RedactionType.MASKED
|
|
1376
|
+
}
|
|
904
1377
|
],
|
|
905
1378
|
});
|
|
906
1379
|
```
|
|
@@ -912,7 +1385,11 @@ The sample response:
|
|
|
912
1385
|
{
|
|
913
1386
|
"token": "131e70dc-6f76-4319-bdd3-96281e051051",
|
|
914
1387
|
"value": "1990-01-01",
|
|
915
|
-
}
|
|
1388
|
+
},
|
|
1389
|
+
{
|
|
1390
|
+
"token": "1r434532-6f76-4319-bdd3-96281e051051",
|
|
1391
|
+
"value": "xxxxxxer",
|
|
1392
|
+
}
|
|
916
1393
|
]
|
|
917
1394
|
}
|
|
918
1395
|
```
|
|
@@ -1008,9 +1485,12 @@ const revealElement = {
|
|
|
1008
1485
|
errorTextStyles: {}, // Optional, styles that will be applied to the errorText of the reveal element.
|
|
1009
1486
|
label: 'string', // Optional, label for the form element.
|
|
1010
1487
|
altText: 'string', // Optional, string that is shown before reveal, will show token if altText is not provided.
|
|
1488
|
+
redaction: RedactionType, //Optional, Redaction Type to be applied to data, RedactionType.PLAIN_TEXT will be applied if not provided.
|
|
1011
1489
|
};
|
|
1012
1490
|
```
|
|
1013
1491
|
|
|
1492
|
+
Note: If you don't provide a redaction type, RedactionType.PLAIN_TEXT will apply by default.
|
|
1493
|
+
|
|
1014
1494
|
The `inputStyles`, `labelStyles` and `errorTextStyles` parameters accepts a styles object as described in the [previous section](#step-2-create-a-collect-element) for collecting data. But for reveal element, `inputStyles` accepts only `base` variant and `copyIcon` style object.
|
|
1015
1495
|
|
|
1016
1496
|
An example of a inputStyles object:
|
|
@@ -1102,6 +1582,7 @@ const cardNumberElement = container.create({
|
|
|
1102
1582
|
},
|
|
1103
1583
|
label: 'card_number',
|
|
1104
1584
|
altText: 'XXXX XXXX XXXX XXXX',
|
|
1585
|
+
redaction: SKyflow.RedactionType.MASKED
|
|
1105
1586
|
});
|
|
1106
1587
|
|
|
1107
1588
|
const cvvElement = container.create({
|
|
@@ -1115,9 +1596,20 @@ const cvvElement = container.create({
|
|
|
1115
1596
|
altText: 'XXX',
|
|
1116
1597
|
});
|
|
1117
1598
|
|
|
1599
|
+
const expiryDate= container.create({
|
|
1600
|
+
token: 'a4b24714-6a26-4256-b9d4-55ad69aa4047',
|
|
1601
|
+
inputStyles: {
|
|
1602
|
+
base: {
|
|
1603
|
+
color: '#1d1d1d',
|
|
1604
|
+
},
|
|
1605
|
+
},
|
|
1606
|
+
label: 'expiryDate',
|
|
1607
|
+
altText: 'MM/YYYY',
|
|
1608
|
+
});
|
|
1118
1609
|
// Step 3.
|
|
1119
1610
|
cardNumberElement.mount('#cardNumber'); // Assumes there is a placeholder div with id='cardNumber' on the page
|
|
1120
1611
|
cvvElement.mount('#cvv'); // Assumes there is a placeholder div with id='cvv' on the page
|
|
1612
|
+
expiryDate.mount('#expiryDate'); // Assumes there is a placeholder div with id='expiryDate' on the page
|
|
1121
1613
|
|
|
1122
1614
|
// Step 4.
|
|
1123
1615
|
container
|
|
@@ -1137,9 +1629,14 @@ The response below shows that some tokens assigned to the reveal elements get re
|
|
|
1137
1629
|
```
|
|
1138
1630
|
{
|
|
1139
1631
|
"success": [
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1632
|
+
{
|
|
1633
|
+
"token": "b63ec4e0-bbad-4e43-96e6-6bd50f483f75",
|
|
1634
|
+
"value": "xxxxxxxxx4163"
|
|
1635
|
+
},
|
|
1636
|
+
{
|
|
1637
|
+
"token": "a4b24714-6a26-4256-b9d4-55ad69aa4047",
|
|
1638
|
+
"value": "12/2098"
|
|
1639
|
+
}
|
|
1143
1640
|
],
|
|
1144
1641
|
"errors": [
|
|
1145
1642
|
{
|
|
@@ -1419,4 +1916,4 @@ container.uploadFiles();
|
|
|
1419
1916
|
|
|
1420
1917
|
## Reporting a Vulnerability
|
|
1421
1918
|
|
|
1422
|
-
If you discover a potential security issue in this project, please reach out to us at security@skyflow.com. Please do not create public GitHub issues or Pull Requests, as malicious actors could potentially view them.
|
|
1919
|
+
If you discover a potential security issue in this project, please reach out to us at security@skyflow.com. Please do not create public GitHub issues or Pull Requests, as malicious actors could potentially view them.
|