From 9e2b983947df9c63ad018b6eea4ed86b7e815e4f Mon Sep 17 00:00:00 2001 From: skyflow-shravan <121150537+skyflow-shravan@users.noreply.github.com> Date: Mon, 30 Jun 2025 22:55:32 +0530 Subject: [PATCH 01/23] SK-2126 insert unformatted card number to vault (#107) * SK-2126 insert unformatted card number to vault * SK-2126 change default collect error to Invalid value * SK-2126 ability to pass testIDs for collect elements * SK-2126 ability to pass testIDs for collect elements --- .../__snapshots__/components.test.js.snap | 9 ++++++ __tests__/core-utils/collect.test.js | 30 ++++++++++++++++++- __tests__/core/collectElement.test.js | 12 ++++++++ .../CardHolderNameElement/index.tsx | 3 +- src/components/CardNumberElement/index.tsx | 3 +- src/components/CvvElement/index.tsx | 3 +- .../ExpirationDateElement/index.tsx | 3 +- .../ExpirationMonthElement/index.tsx | 3 +- .../ExpirationYearElement/index.tsx | 3 +- src/components/InputFieldElement/index.tsx | 3 +- src/components/PinElement/index.tsx | 3 +- src/components/RevealElement/index.tsx | 4 +-- src/core-utils/collect/index.ts | 16 ++++++---- src/core/CollectElement/index.ts | 4 +++ src/core/constants/index.ts | 2 +- src/utils/constants/index.ts | 2 ++ 16 files changed, 86 insertions(+), 17 deletions(-) diff --git a/__tests__/components/__snapshots__/components.test.js.snap b/__tests__/components/__snapshots__/components.test.js.snap index ad718fd..53f6bc9 100644 --- a/__tests__/components/__snapshots__/components.test.js.snap +++ b/__tests__/components/__snapshots__/components.test.js.snap @@ -26,6 +26,7 @@ exports[`test Collect And Reveal Elements Components test CardHolderNameElement /> `; @@ -89,6 +90,7 @@ exports[`test Collect And Reveal Elements Components test CardNumberElement comp `; @@ -121,6 +123,7 @@ exports[`test Collect And Reveal Elements Components test CvvElement component 1 /> `; @@ -153,6 +156,7 @@ exports[`test Collect And Reveal Elements Components test ExpirationDateElement /> `; @@ -185,6 +189,7 @@ exports[`test Collect And Reveal Elements Components test ExpirationMonthElement /> `; @@ -217,6 +222,7 @@ exports[`test Collect And Reveal Elements Components test ExpirationYearElement /> `; @@ -247,6 +253,7 @@ exports[`test Collect And Reveal Elements Components test InputFieldElement comp /> `; @@ -279,6 +286,7 @@ exports[`test Collect And Reveal Elements Components test PinElement component 1 /> `; @@ -298,6 +306,7 @@ Array [ , , ] `; diff --git a/__tests__/core-utils/collect.test.js b/__tests__/core-utils/collect.test.js index e223c7e..48eca10 100644 --- a/__tests__/core-utils/collect.test.js +++ b/__tests__/core-utils/collect.test.js @@ -1,7 +1,7 @@ /* Copyright (c) 2022 Skyflow, Inc. */ -import { tokenize } from '../../src/core-utils/collect'; +import { tokenize, getElementValueToInsert } from '../../src/core-utils/collect'; import CollectElement from '../../src/core/CollectElement'; import Skyflow from '../../src/core/Skyflow'; import { ElementType, Env, LogLevel } from '../../src/utils/constants'; @@ -525,3 +525,31 @@ describe('test collect utils class', () => { }); }); + +describe('getVaultInsertValue', () => { + class MockCollectElement { + constructor(type, value) { + this.type = type; + this.value = value; + } + getClientState() { + return { elementType: this.type }; + } + getUnformattedValue() { + return this.value.replace(/[\s-]/g, ''); + } + getInternalState() { + return { value: this.value }; + } + } + + test('returns unformatted value for CARD_NUMBER', () => { + const element = new MockCollectElement(ElementType.CARD_NUMBER, '4111 1111 1111 1111'); + expect(getElementValueToInsert(element)).toBe('4111111111111111'); + }); + + test('returns value as is for non-CARD_NUMBER', () => { + const element = new MockCollectElement(ElementType.CVV, '123'); + expect(getElementValueToInsert(element)).toBe('123'); + }); +}); diff --git a/__tests__/core/collectElement.test.js b/__tests__/core/collectElement.test.js index 185c480..34433e8 100644 --- a/__tests__/core/collectElement.test.js +++ b/__tests__/core/collectElement.test.js @@ -517,4 +517,16 @@ describe('test Collect Element class', () => { cardNumberElement.onChangeElement('', true); expect(cardNumberElement.getClientState().selectedCardScheme).toEqual('DISCOVER'); }) + + it('should remove spaces from value', () => { + const elementInput = { + table: 'cards', + column: 'number', + type: ElementType.CARD_NUMBER, + containerType: ContainerType.COLLECT, + }; + const collectElement = new CollectElement(elementInput, {}, context); + collectElement.updateValue('4111 1111 1111 1111'); + expect(collectElement.getUnformattedValue()).toBe('4111111111111111'); + }); }); \ No newline at end of file diff --git a/src/components/CardHolderNameElement/index.tsx b/src/components/CardHolderNameElement/index.tsx index e9ec317..8bd1307 100644 --- a/src/components/CardHolderNameElement/index.tsx +++ b/src/components/CardHolderNameElement/index.tsx @@ -49,6 +49,7 @@ const CardHolderNameElement: React.FC = ({ container, optio ref={textInputRef} value={elementValue} placeholder={rest.placeholder} + testID={rest?.testID} onChangeText={(text) => { element?.onChangeElement(text) setElementValue(element.getInternalState().value) @@ -75,7 +76,7 @@ const CardHolderNameElement: React.FC = ({ container, optio { container && container?.type === ContainerType.COLLECT && - {errorText} + {errorText} } ); diff --git a/src/components/CardNumberElement/index.tsx b/src/components/CardNumberElement/index.tsx index de3b8b3..0ce2ba4 100644 --- a/src/components/CardNumberElement/index.tsx +++ b/src/components/CardNumberElement/index.tsx @@ -109,6 +109,7 @@ const CardNumberElement: React.FC = ({ container, options, ref={textInputRef} value={elementValue} placeholder={rest.placeholder} + testID={rest?.testID} onChangeText={(text) => { element?.onChangeElement(text) setElementValue(element.getInternalState().value) @@ -141,7 +142,7 @@ const CardNumberElement: React.FC = ({ container, options, { container && container?.type === ContainerType.COLLECT && - {errorText} + {errorText} } ); } diff --git a/src/components/CvvElement/index.tsx b/src/components/CvvElement/index.tsx index dddbe8d..5754c7a 100644 --- a/src/components/CvvElement/index.tsx +++ b/src/components/CvvElement/index.tsx @@ -49,6 +49,7 @@ const CvvElement: React.FC = ({ container, options = { requ ref={textInputRef} value={elementValue} placeholder={rest.placeholder} + testID={rest?.testID} onChangeText={(text) => { element?.onChangeElement(text); setElementValue(element.getInternalState().value) @@ -76,7 +77,7 @@ const CvvElement: React.FC = ({ container, options = { requ { container && container?.type === ContainerType.COLLECT && - {errorText} + {errorText} } ); } diff --git a/src/components/ExpirationDateElement/index.tsx b/src/components/ExpirationDateElement/index.tsx index 04cd240..af9c071 100644 --- a/src/components/ExpirationDateElement/index.tsx +++ b/src/components/ExpirationDateElement/index.tsx @@ -54,6 +54,7 @@ const ExpirationDateElement: React.FC = ({ container, optio ref={textInputRef} value={elementValue} placeholder={rest.placeholder} + testID={rest?.testID} onChangeText={(text) => { element?.onChangeElement(text); setElementValue(element.getInternalState().value) @@ -84,7 +85,7 @@ const ExpirationDateElement: React.FC = ({ container, optio { container && container?.type === ContainerType.COLLECT && - {errorText} + {errorText} } ); } diff --git a/src/components/ExpirationMonthElement/index.tsx b/src/components/ExpirationMonthElement/index.tsx index 8092770..6e61fe7 100644 --- a/src/components/ExpirationMonthElement/index.tsx +++ b/src/components/ExpirationMonthElement/index.tsx @@ -49,6 +49,7 @@ const ExpirationMonthElement: React.FC = ({ container, opti ref={textInputRef} value={elementValue} placeholder={rest.placeholder} + testID={rest?.testID} onChangeText={(text) => { element?.onChangeElement(text); setElementValue(element.getInternalState().value) @@ -79,7 +80,7 @@ const ExpirationMonthElement: React.FC = ({ container, opti { container && container?.type === ContainerType.COLLECT && - {errorText} + {errorText} } ); } diff --git a/src/components/ExpirationYearElement/index.tsx b/src/components/ExpirationYearElement/index.tsx index c21439e..adba727 100644 --- a/src/components/ExpirationYearElement/index.tsx +++ b/src/components/ExpirationYearElement/index.tsx @@ -55,6 +55,7 @@ const ExpirationYearElement: React.FC = ({ container, optio ref={textInputRef} value={elementValue} placeholder={rest.placeholder} + testID={rest?.testID} onChangeText={(text) => { element?.onChangeElement(text); setElementValue(element.getInternalState().value) @@ -85,7 +86,7 @@ const ExpirationYearElement: React.FC = ({ container, optio { container && container?.type === ContainerType.COLLECT && - {errorText} + {errorText} } ); } diff --git a/src/components/InputFieldElement/index.tsx b/src/components/InputFieldElement/index.tsx index 0825173..35e85ae 100644 --- a/src/components/InputFieldElement/index.tsx +++ b/src/components/InputFieldElement/index.tsx @@ -51,6 +51,7 @@ const InputFieldElement: React.FC = ({ container, options = ref={textInputRef} value={elementValue} placeholder={rest.placeholder} + testID={rest?.testID} onChangeText={(text) => { element?.onChangeElement(text); setElementValue(element.getInternalState().value) @@ -76,7 +77,7 @@ const InputFieldElement: React.FC = ({ container, options = { container && container?.type === ContainerType.COLLECT && - {errorText} + {errorText} } ); } diff --git a/src/components/PinElement/index.tsx b/src/components/PinElement/index.tsx index 6bab3dc..79576a6 100644 --- a/src/components/PinElement/index.tsx +++ b/src/components/PinElement/index.tsx @@ -49,6 +49,7 @@ const PinElement: React.FC = ({ container, options = { requ ref={textInputRef} value={elementValue} placeholder={rest.placeholder} + testID={rest?.testID} onChangeText={(text) => { element?.onChangeElement(text) setElementValue(element.getInternalState().value) @@ -76,7 +77,7 @@ const PinElement: React.FC = ({ container, options = { requ { container && container?.type === ContainerType.COLLECT && - {errorText} + {errorText} } ); } diff --git a/src/components/RevealElement/index.tsx b/src/components/RevealElement/index.tsx index d08872a..5aa885a 100644 --- a/src/components/RevealElement/index.tsx +++ b/src/components/RevealElement/index.tsx @@ -27,8 +27,8 @@ const RevealElement: React.FC = ({ container, label, ...rest return <> {label} - {value} - {errorText} + {value} + {errorText} } diff --git a/src/core-utils/collect/index.ts b/src/core-utils/collect/index.ts index 5d2cc3d..5280bfa 100644 --- a/src/core-utils/collect/index.ts +++ b/src/core-utils/collect/index.ts @@ -7,7 +7,7 @@ import _ from 'lodash'; import Skyflow from '../../core/Skyflow'; import SkyflowError from '../../utils/skyflow-error'; import SKYFLOW_ERROR_CODE from '../../utils/skyflow-error-code'; -import { IInsertRecord, IInsertResponse } from '../../../src/utils/constants'; +import { ElementType, IInsertRecord, IInsertResponse } from '../../../src/utils/constants'; import omit from 'lodash/omit'; const set = require('set-value'); @@ -184,6 +184,12 @@ export const constructElementsInsertReq = (req: any, options: any) => { return { records }; }; +export function getElementValueToInsert(element: CollectElement) { + return element.getClientState().elementType === ElementType.CARD_NUMBER + ? element.getUnformattedValue() + : element.getInternalState().value; +} + export const tokenize = ( skyflowClient: Skyflow, elementList: CollectElement[], @@ -223,14 +229,14 @@ export const tokenize = ( set( elementsUpdateData[skyflowID], column, - currentElement.getInternalState().value, + getElementValueToInsert(currentElement), ); } else { elementsUpdateData[skyflowID] = {}; set( elementsUpdateData[skyflowID], column, - currentElement.getInternalState().value, + getElementValueToInsert(currentElement), ); set( elementsUpdateData[skyflowID], @@ -240,10 +246,10 @@ export const tokenize = ( } } else if (elementsData[table]) { - set(elementsData[table], column, currentElement.getInternalState().value); + set(elementsData[table], column, getElementValueToInsert(currentElement)); } else { elementsData[table] = {}; - set(elementsData[table], column, currentElement.getInternalState().value); + set(elementsData[table], column, getElementValueToInsert(currentElement)); } }); diff --git a/src/core/CollectElement/index.ts b/src/core/CollectElement/index.ts index 68f79bf..53c0405 100644 --- a/src/core/CollectElement/index.ts +++ b/src/core/CollectElement/index.ts @@ -136,6 +136,10 @@ class CollectElement extends SkyflowElement { return this.#state; } + getUnformattedValue() { + return this.#state.value.trim().replace(/[\s-]/g, ''); + } + getElementInput() { return this.#elementInput; } diff --git a/src/core/constants/index.ts b/src/core/constants/index.ts index 0924bcd..111c708 100644 --- a/src/core/constants/index.ts +++ b/src/core/constants/index.ts @@ -163,7 +163,7 @@ export const DEFAULT_CARD_INPUT_MAX_LENGTH = 23; export const REVEAL_ELEMENT_ERROR_TEXT = 'Invalid Token'; -export const DEFAULT_COLLECT_ELEMENT_ERROR_TEXT = 'Invalid Value'; +export const DEFAULT_COLLECT_ELEMENT_ERROR_TEXT = 'Invalid value'; export const DEFAULT_VALIDATION_ERROR_TEXT = 'Validation Failed'; diff --git a/src/utils/constants/index.ts b/src/utils/constants/index.ts index 97bc0b5..ab507ad 100644 --- a/src/utils/constants/index.ts +++ b/src/utils/constants/index.ts @@ -55,6 +55,7 @@ export interface CollectElementProps { errorTextStyles?: StylesBaseVariant; containerMethods?: Record; skyflowID?: string; + testID?: string; } export enum ElementType { @@ -114,6 +115,7 @@ export interface RevealElementProps { labelStyles?: StylesBaseVariant; errorTextStyles?: StylesBaseVariant; redaction?: RedactionType; + testID?: string; } export enum MessageType { From dbbc6f12ddd1b7c7274a22e5c2f81f722630f82b Mon Sep 17 00:00:00 2001 From: skyflow-shravan Date: Mon, 30 Jun 2025 17:26:29 +0000 Subject: [PATCH 02/23] [AUTOMATED] Private Release 1.9.0-dev.9e2b983 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 03d5000..ca10170 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "skyflow-react-native", - "version": "1.9.0", + "version": "1.9.0-dev.9e2b983", "description": "Skyflow React Native SDK", "main": "lib/commonjs/index", "module": "lib/module/index", From dde97df3e00dfbf7338f272b53694e3686fa6fa7 Mon Sep 17 00:00:00 2001 From: raushan-skyflow Date: Tue, 8 Jul 2025 16:20:40 +0530 Subject: [PATCH 03/23] SK-2131 fix expiry date validation (#109) * SK-2131 fix expiry date validation --- .../core-utils/element-validations.test.js | 36 +++++++++++++++++++ src/core-utils/element-validations/index.ts | 11 ++++-- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/__tests__/core-utils/element-validations.test.js b/__tests__/core-utils/element-validations.test.js index b9960f6..9f46068 100644 --- a/__tests__/core-utils/element-validations.test.js +++ b/__tests__/core-utils/element-validations.test.js @@ -8,6 +8,7 @@ import { validatePin, validateRevealElementRecords, validateGetInput, + validateExpiryDate, } from '../../src/core-utils/element-validations'; import SKYFLOW_ERROR_CODE from '../../src/utils/skyflow-error-code'; import { parameterizedString } from '../../src/utils/logs-helper'; @@ -186,6 +187,41 @@ describe('test validatePin function', () => { }); }); +describe('test validateExpiryDate function with various format', () => { + it('should return true for current month/year', () => { + const today = new Date(); + const month = (today.getMonth() + 1).toString().padStart(2, '0'); + const year = today.getFullYear(); + expect(validateExpiryDate(`${month}/${year}`, 'MM/YYYY')).toBe(true); + expect(validateExpiryDate(`${year}/${month}`, 'YYYY/MM')).toBe(true); + + const yearTwoDigit = year % 100; + expect(validateExpiryDate(`${month}/${yearTwoDigit}`, 'MM/YY')).toBe(true); + expect(validateExpiryDate(`${yearTwoDigit}/${month}`, 'YY/MM')).toBe(true); + }); + + it('should return true for valid future date', () => { + expect(validateExpiryDate('07/2074', 'MM/YYYY')).toBe(true); + expect(validateExpiryDate('2074/04', 'YYYY/MM')).toBe(true); + expect(validateExpiryDate('01/35', 'MM/YY')).toBe(true); + expect(validateExpiryDate('35/04', 'YY/MM')).toBe(true); + }); + + it('should return false for expired dates', () => { + expect(validateExpiryDate('01/2020', 'MM/YYYY')).toBe(false); + expect(validateExpiryDate('2000/04', 'YYYY/MM')).toBe(false); + expect(validateExpiryDate('04/20', 'MM/YY')).toBe(false); + expect(validateExpiryDate('20/04', 'YY/MM')).toBe(false); + }); + + it('should return false for invalid month for expired date', () => { + expect(validateExpiryDate('15/2040', 'MM/YYYY')).toBe(false); + expect(validateExpiryDate('2040/16', 'YYYY/MM')).toBe(false); + expect(validateExpiryDate('14/20', 'MM/YY')).toBe(false); + expect(validateExpiryDate('40/14', 'YY/MM')).toBe(false); + }); +}); + describe('test validateRevealElementRecords', () => { it('should throw error when invalid redaction type is passed', (done) => { try { diff --git a/src/core-utils/element-validations/index.ts b/src/core-utils/element-validations/index.ts index b9491bf..9f20042 100644 --- a/src/core-utils/element-validations/index.ts +++ b/src/core-utils/element-validations/index.ts @@ -58,13 +58,20 @@ export const validateExpiryDate = (date: string, format: string) => { if (date.trim().length === 0) return true; if (!date.includes('/')) return false; const { month, year } = getYearAndMonthBasedOnFormat(date, format); - const expiryDate = new Date(`${year}-${month}-01`); + + if (month < 1 || month > 12) return false; + + const expiryDate = new Date(Number(year), Number(month) - 1, 1); const today = new Date(); + today.setDate(1); + today.setHours(0, 0, 0, 0); const maxDate = new Date(); maxDate.setFullYear(today.getFullYear() + 50); + maxDate.setDate(1); + maxDate.setHours(0, 0, 0, 0); - return expiryDate > today && expiryDate <= maxDate; + return expiryDate >= today && expiryDate <= maxDate; }; export const validateCreditCardNumber = (cardNumber: string) => { From c040c47a4d01596c18cbbce2f48ad31b75accc91 Mon Sep 17 00:00:00 2001 From: raushan-skyflow Date: Tue, 8 Jul 2025 10:51:38 +0000 Subject: [PATCH 04/23] [AUTOMATED] Private Release 1.9.0-dev.dde97df --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ca10170..987a23b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "skyflow-react-native", - "version": "1.9.0-dev.9e2b983", + "version": "1.9.0-dev.dde97df", "description": "Skyflow React Native SDK", "main": "lib/commonjs/index", "module": "lib/module/index", From 915c8c968ced0783d60bd865cf58cf743658622a Mon Sep 17 00:00:00 2001 From: raushan-skyflow Date: Tue, 8 Jul 2025 16:54:59 +0530 Subject: [PATCH 05/23] SK-2157 custom input formatting for collect elements (#108) * SK-2157 custom input formatting for collect elements * SK-2168 input formatting with combination of constants & dynamic input in InputFieldElement --- __tests__/core/collectElement.test.js | 128 +++++++++++- __tests__/utils/helper.test.js | 220 +++++++++++++++++++++ src/components/CardNumberElement/index.tsx | 6 +- src/components/InputFieldElement/index.tsx | 5 +- src/core/CollectElement/index.ts | 6 +- src/core/constants/index.ts | 8 + src/utils/helpers/index.ts | 108 +++++++++- src/utils/logs/index.ts | 2 + 8 files changed, 472 insertions(+), 11 deletions(-) diff --git a/__tests__/core/collectElement.test.js b/__tests__/core/collectElement.test.js index 34433e8..403b859 100644 --- a/__tests__/core/collectElement.test.js +++ b/__tests__/core/collectElement.test.js @@ -257,7 +257,11 @@ describe('test Collect Element class', () => { new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_COLUMN_IN_COLLECT, [], true) ); - collecteElement = new CollectElement({ table: 'cards', column: 'test', skyflowID: '' }, {}, context); + collecteElement = new CollectElement( + { table: 'cards', column: 'test', skyflowID: '' }, + {}, + context + ); expect(isValid).toThrow( new SkyflowError(SKYFLOW_ERROR_CODE.EMPTY_SKYFLOW_ID_COLLECT, [], true) ); @@ -515,8 +519,10 @@ describe('test Collect Element class', () => { ); cardNumberElement.onDropdownSelect(CardType.DISCOVER); cardNumberElement.onChangeElement('', true); - expect(cardNumberElement.getClientState().selectedCardScheme).toEqual('DISCOVER'); - }) + expect(cardNumberElement.getClientState().selectedCardScheme).toEqual( + 'DISCOVER' + ); + }); it('should remove spaces from value', () => { const elementInput = { @@ -529,4 +535,118 @@ describe('test Collect Element class', () => { collectElement.updateValue('4111 1111 1111 1111'); expect(collectElement.getUnformattedValue()).toBe('4111111111111111'); }); -}); \ No newline at end of file + + it('test format option in card number element', () => { + const formatTestCases = [ + // Test different valid formats for the card number + { + format: 'XXXX-XXXX-XXXX-XXXX', + input: '4111111111111111', + expected: '4111-1111-1111-1111', + }, + { + format: 'XXXX XXXX XXXX XXXX', + input: '4111111111111111', + expected: '4111 1111 1111 1111', + }, + // Test partial input + { + format: 'XXXX-XXXX-XXXX-XXXX', + input: '411111', + expected: '4111-11', + }, + { + format: 'XXXX XXXX XXXX XXXX', + input: '411111', + expected: '4111 11', + }, + // Test for invalid format, It will fallback to default format + { + format: ' xxxx-xxxx-xxxx ', + input: ' 4111111111111111 ', + expected: '4111 1111 1111 1111', + }, + ]; + + formatTestCases.forEach((testCase) => { + const collectElement = new CollectElement( + { + table: 'cards', + column: 'card_number', + type: ElementType.CARD_NUMBER, + containerType: ContainerType.COLLECT, + }, + { + format: testCase.format, + }, + context + ); + + collectElement.onChangeElement(testCase.input); + expect(collectElement.getInternalState().value).toBe(testCase.expected); + }); + }); + + it('test format option in input field element', () => { + const formatTestCases = [ + { + format: 'XX-XX-XX', + input: '123456', + expected: '12-34-56', + }, + { + format: 'XXX XXX', + input: '123456', + expected: '123 456', + }, + { + format: 'XX/XX/XX', + input: '123456', + expected: '12/34/56', + }, + // Test partial input + { + format: 'XX-XX-XX', + input: '1234', + expected: '12-34', + }, + // Test with special characters + { + format: 'XX@XX#XX', + input: '123456', + expected: '12@34#56', + }, + // Test input longer than format + { + format: 'XX-XX', + input: '123456', + expected: '12-34', + }, + // Test input with leading, trailing spaces & small format + { + format: ' xx-xx-xxx ', + input: ' 1234567 ', + expected: ' xx-xx-xxx ', + }, + ]; + + formatTestCases.forEach((testCase) => { + const collectElement = new CollectElement( + { + table: 'table', + column: 'column', + type: ElementType.INPUT_FIELD, + containerType: ContainerType.COLLECT, + }, + { + format: testCase.format, + }, + context + ); + + collectElement.onChangeElement(testCase.input); + expect(collectElement.getInternalState().value).toBe(testCase.expected); + expect(collectElement.getInternalState().isValid).toBe(true); + }); + }); +}); diff --git a/__tests__/utils/helper.test.js b/__tests__/utils/helper.test.js index c1a2a36..13b2ca4 100644 --- a/__tests__/utils/helper.test.js +++ b/__tests__/utils/helper.test.js @@ -16,6 +16,7 @@ import { getYearAndMonthBasedOnFormat, getMetaObject, getDeviceModel, + formatInputFieldValue, } from '../../src/utils/helpers'; import { CardType, @@ -300,4 +301,223 @@ describe('test getYearAndMonthBasedOnFormat function', () => { year: '2032', }); }); + + it('should format expiration date options correctly', () => { + const validFormats = ['MM/YY', 'MM/YYYY', 'YYYY/MM', 'YY/MM']; + validFormats.forEach((format) => { + const result = formatCollectElementOptions( + ElementType.EXPIRATION_DATE, + { format }, + LogLevel.WARN + ); + expect(result).toEqual({ + format, + required: false, + }); + }); + }); + + it('should use default format for invalid expiration date format', () => { + const result = formatCollectElementOptions( + ElementType.EXPIRATION_DATE, + { format: 'INVALID' }, + LogLevel.WARN + ); + expect(result).toEqual({ + format: DEFAULT_EXPIRATION_DATE_FORMAT, + required: false, + }); + expect(printLog).toBeCalled(); + }); + + it('should format expiration year options correctly', () => { + const validFormats = ['YY', 'YYYY']; + validFormats.forEach((format) => { + const result = formatCollectElementOptions( + ElementType.EXPIRATION_YEAR, + { format }, + LogLevel.WARN + ); + expect(result).toEqual({ + format, + required: false, + }); + }); + }); + + it('should use default format for invalid expiration year format', () => { + const result = formatCollectElementOptions( + ElementType.EXPIRATION_YEAR, + { format: 'INVALID' }, + LogLevel.WARN + ); + expect(result).toEqual({ + format: DEFAULT_EXPIRATION_YEAR_FORMAT, + required: false, + }); + expect(printLog).toBeCalled(); + }); +}); + +describe('test formatCardNumber with different formats', () => { + const testCases = [ + { + input: '4111111111111111', + type: CardType.VISA, + format: 'XXXX-XXXX-XXXX-XXXX', + expected: '4111-1111-1111-1111', + }, + { + input: '378282246310005', + type: CardType.AMEX, + format: 'XXXX-XXXX-XXXX-XXXX', + expected: '3782-822463-10005', + }, + { + input: '6011111111111117', + type: CardType.DISCOVER, + format: 'XXXX XXXX XXXX XXXX', + expected: '6011 1111 1111 1117', + }, + // Test partial inputs + { + input: '411111', + type: CardType.VISA, + format: 'XXXX-XXXX-XXXX-XXXX', + expected: '4111-11', + }, + // Test empty input + { + input: '', + type: CardType.DEFAULT, + format: 'XXXX-XXXX-XXXX-XXXX', + expected: '', + }, + ]; + + testCases.forEach((testCase) => { + it(`should format ${testCase.type} card number correctly with format ${testCase.format}`, () => { + expect( + formatCardNumber(testCase.input, testCase.type, testCase.format) + ).toBe(testCase.expected); + }); + }); +}); + +describe('test formatInputFieldValue with different formats', () => { + const testCases = [ + { + input: '123456', + format: 'XX-XX-XX', + expected: '12-34-56', + }, + { + input: '123456', + format: 'XXX XXX', + expected: '123 456', + }, + { + input: '12345', + format: 'XX/XX/X', + expected: '12/34/5', + }, + { + input: '1567C89', + format: 'XX/XYX/X', + translation: { X: '[5-9]', Y: '[A-C]' }, + expected: '56/7C8/9', + }, + // Combination of constants and dynamic inputs + { + input: '1234121234', + format: '+91 XXXX-XX-XXXX', + expected: '+91 1234-12-1234', + }, + { + input: 'B5678978C7QAB97', + format: '91 YXX-XZX-XXY-XZYXX', + translation: { X: '[5-9]', Y: '[A-C]' }, + expected: '91 B56-7Z8-97C-7ZA97', + }, + // Test with special characters in format + { + input: '123456', + format: 'XX@XX#XX', + expected: '12@34#56', + }, + // Test partial input + { + input: '123', + format: 'XX-XX-XX', + expected: '12-3', + }, + // Test input longer than format + { + input: '1234567', + format: 'XX-XX', + expected: '12-34', + }, + // Test empty input + { + input: '', + format: 'XX-XX', + expected: '', + }, + // Test with no format + { + input: '123456', + format: '', + expected: '123456', + }, + ]; + + testCases.forEach((testCase) => { + const translation = testCase.translation || { + X: '[0-9]', + }; + it(`should format input '${testCase.input}' with format '${ + testCase.format + }' & translation '${JSON.stringify(translation)}' correctly`, () => { + expect( + formatInputFieldValue( + testCase.input, + testCase.format, + testCase?.translation + ) + ).toBe(testCase.expected); + }); + }); +}); + +describe('test formatCollectElementOptions for different element types', () => { + it('should format card number options correctly', () => { + const options = { + format: 'XXXX-XXXX-XXXX-XXXX', + required: true, + }; + const result = formatCollectElementOptions( + ElementType.CARD_NUMBER, + options, + LogLevel.WARN + ); + expect(result).toEqual({ + format: 'XXXX-XXXX-XXXX-XXXX', + required: true, + }); + }); + + it('should preserve other options while formatting', () => { + const options = { + format: 'XXXX-XXXX-XXXX-XXXX', + required: true, + enableCardIcon: true, + customOption: 'value', + }; + const result = formatCollectElementOptions( + ElementType.CARD_NUMBER, + options, + LogLevel.WARN + ); + expect(result).toEqual(options); + }); }); diff --git a/src/components/CardNumberElement/index.tsx b/src/components/CardNumberElement/index.tsx index 0ce2ba4..0817f0e 100644 --- a/src/components/CardNumberElement/index.tsx +++ b/src/components/CardNumberElement/index.tsx @@ -5,11 +5,12 @@ import React, { useEffect, useRef } from "react"; import { Image, Text, TextInput, View } from "react-native"; import type CollectElement from "../../core/CollectElement"; import { CARD_ENCODED_ICONS, CARD_NUMBER_MASK, CardType, CardTypeValues, DEFAULT_CARD_INPUT_MAX_LENGTH } from "../../core/constants"; -import { CollectElementProps, ElementType, ELEMENT_REQUIRED_ASTERISK, REQUIRED_MARK_DEFAULT_STYLE, ContainerType, CARD_NUMBER_ELEMENT_DEFAULT_STYLE, CARD_ICON_DEFAULT_STYLE, IListItem } from "../../utils/constants"; +import { CollectElementProps, ElementType, ELEMENT_REQUIRED_ASTERISK, REQUIRED_MARK_DEFAULT_STYLE, ContainerType, CARD_NUMBER_ELEMENT_DEFAULT_STYLE, CARD_ICON_DEFAULT_STYLE, IListItem, CollectElementOptions } from "../../utils/constants"; import SkyflowError from "../../utils/skyflow-error"; import SKYFLOW_ERROR_CODE from "../../utils/skyflow-error-code"; import uuid from 'react-native-uuid'; import Dropdown from "../../core/Dropdown"; +import { formatCollectElementOptions } from "../../utils/helpers"; const CardNumberElement: React.FC = ({ container, options, ...rest }) => { @@ -33,7 +34,8 @@ const CardNumberElement: React.FC = ({ container, options, useEffect(() => { if (container) { - const element: CollectElement = container.create({ ...rest, type: ElementType.CARD_NUMBER, containerType: container.type }, mergedOptions); + const elementOptions: CollectElementOptions = formatCollectElementOptions(ElementType.CARD_NUMBER, options, container.getContext().logLevel); + const element: CollectElement = container.create({ ...rest, type: ElementType.CARD_NUMBER, containerType: container.type }, {...mergedOptions , ...elementOptions}); setElement(element); if (container.type === ContainerType.COLLECT) element.setMethods(setErrorText, { setInputStyles: setInputStyles, setLabelStyles: setLabelStyles }); diff --git a/src/components/InputFieldElement/index.tsx b/src/components/InputFieldElement/index.tsx index 35e85ae..8fd6177 100644 --- a/src/components/InputFieldElement/index.tsx +++ b/src/components/InputFieldElement/index.tsx @@ -4,7 +4,7 @@ import React, { useEffect, useRef } from "react"; import { Text, TextInput, View } from "react-native"; import type CollectElement from "../../core/CollectElement"; -import { CollectElementProps, ElementType, ELEMENT_REQUIRED_ASTERISK, REQUIRED_MARK_DEFAULT_STYLE, ContainerType } from "../../utils/constants"; +import { CollectElementProps, ElementType, ELEMENT_REQUIRED_ASTERISK, REQUIRED_MARK_DEFAULT_STYLE, ContainerType, CollectElementOptions } from "../../utils/constants"; import SkyflowError from "../../utils/skyflow-error"; import SKYFLOW_ERROR_CODE from "../../utils/skyflow-error-code"; import uuid from 'react-native-uuid'; @@ -48,10 +48,11 @@ const InputFieldElement: React.FC = ({ container, options = ) } { element?.onChangeElement(text); setElementValue(element.getInternalState().value) diff --git a/src/core/CollectElement/index.ts b/src/core/CollectElement/index.ts index 53c0405..13bf271 100644 --- a/src/core/CollectElement/index.ts +++ b/src/core/CollectElement/index.ts @@ -32,6 +32,7 @@ import { appendZeroToOne, detectCardType, formatCardNumber, + formatInputFieldValue, formatExpirationDate, formatExpirationMonthValue, getReturnValue, @@ -190,7 +191,10 @@ class CollectElement extends SkyflowElement { break; case ElementType.CARD_NUMBER: this.#cardType = detectCardType(value); - this.updateElement(formatCardNumber(value, this.#cardType)); + this.updateElement(formatCardNumber(value, this.#cardType, this.#options.format)); + break; + case ElementType.INPUT_FIELD: + this.updateElement(formatInputFieldValue(value, this.#options.format, this.#options.translation)); break; default: this.updateElement(value); diff --git a/src/core/constants/index.ts b/src/core/constants/index.ts index 111c708..3be2ea7 100644 --- a/src/core/constants/index.ts +++ b/src/core/constants/index.ts @@ -40,6 +40,7 @@ export const DEFAULT_EXPIRATION_YEAR_FORMAT = 'YY'; export const FOUR_DIGIT_YEAR_FORMAT = 'YYYY'; export const DEFAULT_EXPIRATION_DATE_FORMAT = 'MM/YY'; +export const DEFAULT_CARD_NUMBER_FORMAT = 'XXXX XXXX XXXX XXXX'; export const MONTH_FORMAT = 'MM'; @@ -166,6 +167,9 @@ export const REVEAL_ELEMENT_ERROR_TEXT = 'Invalid Token'; export const DEFAULT_COLLECT_ELEMENT_ERROR_TEXT = 'Invalid value'; export const DEFAULT_VALIDATION_ERROR_TEXT = 'Validation Failed'; +export const DEFAULT_INPUT_FIELD_TRANSLATION: Record = { + 'X': '[0-9]', +}; export const ALLOWED_EXPIRY_YEAR_FORMATS = [ DEFAULT_EXPIRATION_YEAR_FORMAT, @@ -178,6 +182,10 @@ export const ALLOWED_EXPIRY_DATE_FORMATS = [ 'YY/MM', 'MM/YYYY', ]; +export const ALLOWED_CARD_NUMBER_FORMATS = [ + DEFAULT_CARD_NUMBER_FORMAT, + 'XXXX-XXXX-XXXX-XXXX', +] export const DEFAULT_COLLECT_ELEMENT_REQUIRED_TEXT = 'Field is required'; diff --git a/src/utils/helpers/index.ts b/src/utils/helpers/index.ts index 8c523de..4fe207c 100644 --- a/src/utils/helpers/index.ts +++ b/src/utils/helpers/index.ts @@ -12,6 +12,9 @@ import { DEFAULT_EXPIRATION_DATE_FORMAT, ALLOWED_EXPIRY_DATE_FORMATS, ALLOWED_EXPIRY_YEAR_FORMATS, + ALLOWED_CARD_NUMBER_FORMATS, + DEFAULT_CARD_NUMBER_FORMAT, + DEFAULT_INPUT_FIELD_TRANSLATION, } from '../../core/constants'; import { ElementType, MessageType } from '../constants'; import logs from '../logs'; @@ -141,8 +144,81 @@ export const detectCardType = (cardNumber: string) => { return detectedType; }; -export const formatCardNumber = (cardNumber, type) => { - return applyMask(cardNumber, CARD_NUMBER_MASK[type]); +export const formatCardNumber = ( + cardNumber: string, + type: string | number, + format = DEFAULT_CARD_NUMBER_FORMAT +) => { + if (!cardNumber || cardNumber.length === 0) return ''; + const isvalidFormat = isValidCardNumberFormat( + format + ); + + if (!isvalidFormat) { + format = DEFAULT_CARD_NUMBER_FORMAT; + }; + + const mask = CARD_NUMBER_MASK[type] || CARD_NUMBER_MASK[CardType.DEFAULT]; + const maskedValue = applyMask(cardNumber, mask); + const separator = format.includes('-') ? '-' : ' '; + const formattedValue = maskedValue.replace(/[\s-]+/g, separator).trim(); + + return formattedValue; +}; + +export const formatInputFieldValue = ( + input: string, + format: string, + translation: Record = DEFAULT_INPUT_FIELD_TRANSLATION +): string => { + if (!format || format.length === 0) return input; + if (!input || input.length === 0) return ''; + + const inputArray = Array.from(input); + const formatArray = Array.from(format); + let formattedOutput = ''; + let formatIndex = 0; + + for (let inputIndex = 0; inputIndex < inputArray.length; inputIndex++) { + const inputChar = inputArray[inputIndex]; + + if (formatIndex < formatArray.length) { + const currentFormatChar = formatArray[formatIndex]; + + if (translation[currentFormatChar]) { + const regex = new RegExp(translation[currentFormatChar]); + if (regex.test(inputChar)) { + formattedOutput += inputChar; + formatIndex++; + } + } else { + if (inputChar === currentFormatChar) { + formattedOutput += inputChar; + formatIndex++; + } else { + for (let scanIndex = formatIndex; scanIndex < formatArray.length; scanIndex++) { + const nextFormatChar = formatArray[scanIndex]; + + if (translation[nextFormatChar]) { + const regex = new RegExp(translation[nextFormatChar]); + if (regex.test(inputChar)) { + formattedOutput += inputChar; + formatIndex = scanIndex + 1; + } + break; + } else { + formattedOutput += nextFormatChar; + formatIndex = scanIndex + 1; + } + } + } + } + } else { + break; + } + } + + return formattedOutput; }; export const getReturnValue = ( @@ -204,6 +280,13 @@ export const isValidExpiryYearFormat = (format: string): boolean => { return false; }; +export const isValidCardNumberFormat = (format: string): boolean => { + if (format) { + return ALLOWED_CARD_NUMBER_FORMATS.includes(format); + } + return false; +}; + export const formatCollectElementOptions = ( elementType: ElementType, options, @@ -259,6 +342,27 @@ export const formatCollectElementOptions = ( ? formattedOptions.format.toUpperCase() : DEFAULT_EXPIRATION_YEAR_FORMAT, }; + } else if (elementType === ElementType.CARD_NUMBER) { + let isvalidFormat = false; + if (formattedOptions.format) { + isvalidFormat = isValidCardNumberFormat( + formattedOptions.format.toUpperCase() + ); + if (!isvalidFormat) { + printLog( + parameterizedString( + logs.warnLogs.INVALID_CARD_NUMBER_FORMAT, + ALLOWED_CARD_NUMBER_FORMATS.toString() + ), + MessageType.WARN, + logLevel + ); + } + } + formattedOptions = { + ...formattedOptions, + format: isvalidFormat ? formattedOptions.format : DEFAULT_CARD_NUMBER_FORMAT, + }; } return formattedOptions; }; diff --git a/src/utils/logs/index.ts b/src/utils/logs/index.ts index fb6a125..b140d95 100644 --- a/src/utils/logs/index.ts +++ b/src/utils/logs/index.ts @@ -226,6 +226,8 @@ const logs = { 'EXPIRATION_DATE format must be in one of %s1, the format is set to default MM/YY', INVALID_EXPIRATION_YEAR_FORMAT: 'EXPIRATION_YEAR format must be in one of %s1, the format is set to default YY', + INVALID_CARD_NUMBER_FORMAT: + `CARD_NUMBER format must be in one of %s1, the format is set to default XXXX XXXX XXXX XXXX`, }, }; From e797cf600046e60831efd33aa374052243beb375 Mon Sep 17 00:00:00 2001 From: raushan-skyflow Date: Tue, 8 Jul 2025 11:25:58 +0000 Subject: [PATCH 06/23] [AUTOMATED] Private Release 1.9.0-dev.915c8c9 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 987a23b..29485f1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "skyflow-react-native", - "version": "1.9.0-dev.dde97df", + "version": "1.9.0-dev.915c8c9", "description": "Skyflow React Native SDK", "main": "lib/commonjs/index", "module": "lib/module/index", From f3edc4a1f2cdb1f8df5bcd544c75ca01dc111c42 Mon Sep 17 00:00:00 2001 From: raushan-skyflow Date: Fri, 11 Jul 2025 11:07:49 +0530 Subject: [PATCH 07/23] SK-2173 support input formatting in reveal elements (#110) --- .../__snapshots__/components.test.js.snap | 20 +-- __tests__/components/components.test.js | 128 +++++++++++++----- src/components/RevealElement/index.tsx | 14 +- src/utils/constants/index.ts | 2 + 4 files changed, 116 insertions(+), 48 deletions(-) diff --git a/__tests__/components/__snapshots__/components.test.js.snap b/__tests__/components/__snapshots__/components.test.js.snap index 53f6bc9..792f7d3 100644 --- a/__tests__/components/__snapshots__/components.test.js.snap +++ b/__tests__/components/__snapshots__/components.test.js.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`test Collect And Reveal Elements Components test CardHolderNameElement component 1`] = ` +exports[`test Collect Elements Components test CardHolderNameElement component 1`] = ` `; -exports[`test Collect And Reveal Elements Components test CardNumberElement component 1`] = ` +exports[`test Collect Elements Components test CardNumberElement component 1`] = ` `; -exports[`test Collect And Reveal Elements Components test CvvElement component 1`] = ` +exports[`test Collect Elements Components test CvvElement component 1`] = ` `; -exports[`test Collect And Reveal Elements Components test ExpirationDateElement component 1`] = ` +exports[`test Collect Elements Components test ExpirationDateElement component 1`] = ` `; -exports[`test Collect And Reveal Elements Components test ExpirationMonthElement component 1`] = ` +exports[`test Collect Elements Components test ExpirationMonthElement component 1`] = ` `; -exports[`test Collect And Reveal Elements Components test ExpirationYearElement component 1`] = ` +exports[`test Collect Elements Components test ExpirationYearElement component 1`] = ` `; -exports[`test Collect And Reveal Elements Components test InputFieldElement component 1`] = ` +exports[`test Collect Elements Components test InputFieldElement component 1`] = ` `; -exports[`test Collect And Reveal Elements Components test PinElement component 1`] = ` +exports[`test Collect Elements Components test PinElement component 1`] = ` `; -exports[`test Collect And Reveal Elements Components test RevealElement component 1`] = ` +exports[`test Collect Elements Components test Reveal Elements Components renders correctly with the handler & snapshot 1`] = ` Array [ Provider Childern diff --git a/__tests__/components/components.test.js b/__tests__/components/components.test.js index aa2fb49..f08a705 100644 --- a/__tests__/components/components.test.js +++ b/__tests__/components/components.test.js @@ -37,7 +37,7 @@ const changeTrigger = jest.fn(); const foucsTrigger = jest.fn(); const blurTrigger = jest.fn(); -describe('test Collect And Reveal Elements Components', () => { +describe('test Collect Elements Components', () => { let collectContainer; beforeEach(() => { jest.clearAllMocks(); @@ -558,44 +558,102 @@ describe('test Collect And Reveal Elements Components', () => { } }); - it('test RevealElement component', () => { - const revealSetMethodMock = jest.fn(); - const revealContainer = new RevealContainer(testSkyflowClient); - jest.spyOn(revealContainer, 'create').mockImplementation(() => ({ - setMethods: revealSetMethodMock, - })); + describe('test Reveal Elements Components', () => { + it('renders correctly with the handler & snapshot', () => { + const revealSetMethodMock = jest.fn(); + const revealContainer = new RevealContainer(testSkyflowClient); + jest.spyOn(revealContainer, 'create').mockImplementation(() => ({ + setMethods: revealSetMethodMock, + })); + + const revealElement = render( + + ); - const revealElement = render( - - ); + expect(revealElement).toMatchSnapshot(); + expect(revealSetMethodMock).toBeCalledTimes(1); - expect(revealElement).toMatchSnapshot(); - expect(revealSetMethodMock).toBeCalledTimes(1); + // render without alttext + const revealElement2 = render( + + ); + try { + render(); + } catch (err) { + expect(err).toEqual( + new SkyflowError( + SKYFLOW_ERROR_CODE.CONTAINER_OBJECT_IS_REQUIRED, + ['Reveal', 'useRevealContainer()'], + true + ) + ); + } + }); + + it('renders formatted value when format is provided', () => { + const revealSetMethodMock = jest.fn(); + const revealContainer = new RevealContainer(testSkyflowClient); + jest.spyOn(revealContainer, 'create').mockImplementation(() => ({ + setMethods: revealSetMethodMock, + })); + + const format = 'XXXX XXXX XXXX XXXX'; + const altText = '4111111111111111'; - // render without alttext - const revealElement2 = render( - - ); - try { - render(); - } catch (err) { - expect(err).toEqual( - new SkyflowError( - SKYFLOW_ERROR_CODE.CONTAINER_OBJECT_IS_REQUIRED, - ['Reveal', 'useRevealContainer()'], - true - ) + render( + ); - } + + // Should format altText using format + expect(screen.getByTestId('reveal-format').props.children).toBe( + '4111 1111 1111 1111' + ); + }); + + it('renders formatted value when format and translation are provided', () => { + const revealSetMethodMock = jest.fn(); + const revealContainer = new RevealContainer(testSkyflowClient); + jest.spyOn(revealContainer, 'create').mockImplementation(() => ({ + setMethods: revealSetMethodMock, + })); + + const format = 'XX-XX-XX-YYZ-ZZX'; + const translation = { X: '[0-9]', Y: '[A-Z]' }; + const altText = '123456AB7'; + + render( + + ); + + // Should format altText using format and translation + expect( + screen.getByTestId('reveal-format-translation').props.children + ).toBe('12-34-56-ABZ-ZZ7'); + }); }); it('test skyflow provider', () => { diff --git a/src/components/RevealElement/index.tsx b/src/components/RevealElement/index.tsx index 5aa885a..36bbbf6 100644 --- a/src/components/RevealElement/index.tsx +++ b/src/components/RevealElement/index.tsx @@ -7,13 +7,22 @@ import RevealSkyflowElement from "../../core/RevealSkyflowElement"; import { RevealElementProps } from "../../utils/constants" import SkyflowError from "../../utils/skyflow-error"; import SKYFLOW_ERROR_CODE from "../../utils/skyflow-error-code"; +import { formatInputFieldValue } from "../../utils/helpers"; +import { DEFAULT_INPUT_FIELD_TRANSLATION } from "../../core/constants"; -const RevealElement: React.FC = ({ container, label, ...rest }) => { +const RevealElement: React.FC = ({ container, label, format, translation, ...rest }) => { const [element, setElement] = React.useState(undefined); const [errorText, setErrorText] = React.useState(''); const [value, setValue] = React.useState(rest?.altText || rest.token); + const formattedValue = React.useMemo(() => { + if (!format) return value; + const valueTranslation = translation ?? DEFAULT_INPUT_FIELD_TRANSLATION; + const formattedText = formatInputFieldValue(value, format, valueTranslation); + return formattedText ? formattedText : value; + }, [value, format, translation]); + useEffect(() => { if (container) { const revealElement = container.create(rest); @@ -22,12 +31,11 @@ const RevealElement: React.FC = ({ container, label, ...rest } else { throw new SkyflowError(SKYFLOW_ERROR_CODE.CONTAINER_OBJECT_IS_REQUIRED, ['Reveal', 'useRevealContainer()'], true) } - }, []); return <> {label} - {value} + {formattedValue} {errorText} diff --git a/src/utils/constants/index.ts b/src/utils/constants/index.ts index ab507ad..e6f8786 100644 --- a/src/utils/constants/index.ts +++ b/src/utils/constants/index.ts @@ -109,6 +109,8 @@ export interface RevealElementInput { export interface RevealElementProps { token: string; container: RevealContainer; + format?: string + translation?: Record; label?: string; altText?: string; inputStyles?: StylesBaseVariant; From 044185e48ebc25d4e209eb6482107b440896508d Mon Sep 17 00:00:00 2001 From: raushan-skyflow Date: Fri, 11 Jul 2025 05:38:45 +0000 Subject: [PATCH 08/23] [AUTOMATED] Private Release 1.9.0-dev.f3edc4a --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 29485f1..872b782 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "skyflow-react-native", - "version": "1.9.0-dev.915c8c9", + "version": "1.9.0-dev.f3edc4a", "description": "Skyflow React Native SDK", "main": "lib/commonjs/index", "module": "lib/module/index", From 40c7b7de3ece3ad0d5e71018898fcd752d36c977 Mon Sep 17 00:00:00 2001 From: raushan-skyflow Date: Thu, 17 Jul 2025 09:43:19 +0530 Subject: [PATCH 09/23] SK-2173 fix card number regex (#111) * SK-2173 fix the card number regex for proper bin lookup --- __tests__/core/collectElement.test.js | 12 ++++++++++++ __tests__/utils/helper.test.js | 10 ++++++++++ src/utils/helpers/index.ts | 2 +- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/__tests__/core/collectElement.test.js b/__tests__/core/collectElement.test.js index 403b859..5f37845 100644 --- a/__tests__/core/collectElement.test.js +++ b/__tests__/core/collectElement.test.js @@ -536,6 +536,18 @@ describe('test Collect Element class', () => { expect(collectElement.getUnformattedValue()).toBe('4111111111111111'); }); + it('should remove hyphens from value', () => { + const elementInput = { + table: 'cards', + column: 'number', + type: ElementType.CARD_NUMBER, + containerType: ContainerType.COLLECT, + }; + const collectElement = new CollectElement(elementInput, {}, context); + collectElement.updateValue('4111-1111-1111-1111'); + expect(collectElement.getUnformattedValue()).toBe('4111111111111111'); + }); + it('test format option in card number element', () => { const formatTestCases = [ // Test different valid formats for the card number diff --git a/__tests__/utils/helper.test.js b/__tests__/utils/helper.test.js index 13b2ca4..708ad0f 100644 --- a/__tests__/utils/helper.test.js +++ b/__tests__/utils/helper.test.js @@ -219,6 +219,16 @@ describe('test getReturnValue function', () => { ).toBe('4111111111111111'); }); + it('should return unformatted value for card number element', () => { + expect( + getReturnValue('4111 1111 1111 1111', true, ElementType.CARD_NUMBER) + ).toBe('4111111111111111'); + + expect( + getReturnValue('4111-1111-1111-1111', true, ElementType.CARD_NUMBER) + ).toBe('4111111111111111'); + }); + it('should return non string value when return value is true', () => { expect(getReturnValue(1000, true, ElementType.INPUT_FIELD)).toBe(1000); }); diff --git a/src/utils/helpers/index.ts b/src/utils/helpers/index.ts index 4fe207c..face546 100644 --- a/src/utils/helpers/index.ts +++ b/src/utils/helpers/index.ts @@ -229,7 +229,7 @@ export const getReturnValue = ( ) => { if (typeof value === 'string') { if (elementType === ElementType.CARD_NUMBER) { - value = value && value.replace(/\s/g, ''); + value = value && value.replace(/[\s-]/g, ''); if (!doesReturnValue) { const threshold = cardType !== CardType.DEFAULT && cardType === CardType.AMEX ? 6 : 8; From d365d2ae621b005ab5c698efdf882cbc92aef6d9 Mon Sep 17 00:00:00 2001 From: raushan-skyflow Date: Thu, 17 Jul 2025 04:14:21 +0000 Subject: [PATCH 10/23] [AUTOMATED] Private Release 1.9.0-dev.40c7b7d --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 872b782..98c1fcc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "skyflow-react-native", - "version": "1.9.0-dev.f3edc4a", + "version": "1.9.0-dev.40c7b7d", "description": "Skyflow React Native SDK", "main": "lib/commonjs/index", "module": "lib/module/index", From 4e22480abf32c267629bc8803df6d4a7fb75fd72 Mon Sep 17 00:00:00 2001 From: raushan-skyflow Date: Fri, 18 Jul 2025 17:18:20 +0530 Subject: [PATCH 11/23] SK-2173 revert unformatted card no insertion to vault (#112) --- __tests__/core-utils/collect.test.js | 30 +-------------------------- __tests__/core/collectElement.test.js | 24 --------------------- src/core-utils/collect/index.ts | 8 +++---- 3 files changed, 5 insertions(+), 57 deletions(-) diff --git a/__tests__/core-utils/collect.test.js b/__tests__/core-utils/collect.test.js index 48eca10..e223c7e 100644 --- a/__tests__/core-utils/collect.test.js +++ b/__tests__/core-utils/collect.test.js @@ -1,7 +1,7 @@ /* Copyright (c) 2022 Skyflow, Inc. */ -import { tokenize, getElementValueToInsert } from '../../src/core-utils/collect'; +import { tokenize } from '../../src/core-utils/collect'; import CollectElement from '../../src/core/CollectElement'; import Skyflow from '../../src/core/Skyflow'; import { ElementType, Env, LogLevel } from '../../src/utils/constants'; @@ -525,31 +525,3 @@ describe('test collect utils class', () => { }); }); - -describe('getVaultInsertValue', () => { - class MockCollectElement { - constructor(type, value) { - this.type = type; - this.value = value; - } - getClientState() { - return { elementType: this.type }; - } - getUnformattedValue() { - return this.value.replace(/[\s-]/g, ''); - } - getInternalState() { - return { value: this.value }; - } - } - - test('returns unformatted value for CARD_NUMBER', () => { - const element = new MockCollectElement(ElementType.CARD_NUMBER, '4111 1111 1111 1111'); - expect(getElementValueToInsert(element)).toBe('4111111111111111'); - }); - - test('returns value as is for non-CARD_NUMBER', () => { - const element = new MockCollectElement(ElementType.CVV, '123'); - expect(getElementValueToInsert(element)).toBe('123'); - }); -}); diff --git a/__tests__/core/collectElement.test.js b/__tests__/core/collectElement.test.js index 5f37845..f3a176b 100644 --- a/__tests__/core/collectElement.test.js +++ b/__tests__/core/collectElement.test.js @@ -524,30 +524,6 @@ describe('test Collect Element class', () => { ); }); - it('should remove spaces from value', () => { - const elementInput = { - table: 'cards', - column: 'number', - type: ElementType.CARD_NUMBER, - containerType: ContainerType.COLLECT, - }; - const collectElement = new CollectElement(elementInput, {}, context); - collectElement.updateValue('4111 1111 1111 1111'); - expect(collectElement.getUnformattedValue()).toBe('4111111111111111'); - }); - - it('should remove hyphens from value', () => { - const elementInput = { - table: 'cards', - column: 'number', - type: ElementType.CARD_NUMBER, - containerType: ContainerType.COLLECT, - }; - const collectElement = new CollectElement(elementInput, {}, context); - collectElement.updateValue('4111-1111-1111-1111'); - expect(collectElement.getUnformattedValue()).toBe('4111111111111111'); - }); - it('test format option in card number element', () => { const formatTestCases = [ // Test different valid formats for the card number diff --git a/src/core-utils/collect/index.ts b/src/core-utils/collect/index.ts index 5280bfa..436afdc 100644 --- a/src/core-utils/collect/index.ts +++ b/src/core-utils/collect/index.ts @@ -229,14 +229,14 @@ export const tokenize = ( set( elementsUpdateData[skyflowID], column, - getElementValueToInsert(currentElement), + currentElement.getInternalState().value, ); } else { elementsUpdateData[skyflowID] = {}; set( elementsUpdateData[skyflowID], column, - getElementValueToInsert(currentElement), + currentElement.getInternalState().value, ); set( elementsUpdateData[skyflowID], @@ -246,10 +246,10 @@ export const tokenize = ( } } else if (elementsData[table]) { - set(elementsData[table], column, getElementValueToInsert(currentElement)); + set(elementsData[table], column, currentElement.getInternalState().value); } else { elementsData[table] = {}; - set(elementsData[table], column, getElementValueToInsert(currentElement)); + set(elementsData[table], column, currentElement.getInternalState().value); } }); From ffdb6b426e319bb97e98c3e8c58dec30ecc10092 Mon Sep 17 00:00:00 2001 From: raushan-skyflow Date: Fri, 18 Jul 2025 11:49:16 +0000 Subject: [PATCH 12/23] [AUTOMATED] Private Release 1.9.0-dev.4e22480 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 98c1fcc..05afab8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "skyflow-react-native", - "version": "1.9.0-dev.40c7b7d", + "version": "1.9.0-dev.4e22480", "description": "Skyflow React Native SDK", "main": "lib/commonjs/index", "module": "lib/module/index", From 80b44eb86e7cfbd807cccf8b375bcd6b25633d9c Mon Sep 17 00:00:00 2001 From: raushan-skyflow Date: Tue, 22 Jul 2025 18:36:07 +0530 Subject: [PATCH 13/23] SK-2167 fix critical vulnerabilities (#113) --- example/package.json | 5 +++ example/yarn.lock | 87 ++++++++++++++++++++++++------------ package.json | 5 ++- yarn.lock | 103 ++++++++++++++++++++++++++++++------------- 4 files changed, 140 insertions(+), 60 deletions(-) diff --git a/example/package.json b/example/package.json index c0c7860..97db816 100644 --- a/example/package.json +++ b/example/package.json @@ -14,6 +14,11 @@ "react": "18.2.0", "react-native": "^0.71.19" }, + "resolutions": { + "@babel/runtime": "^7.26.10", + "@babel/helpers": "^7.26.10", + "brace-expansion": "^1.1.12" + }, "devDependencies": { "@babel/core": "^7.12.10", "@babel/runtime": "^7.12.5", diff --git a/example/yarn.lock b/example/yarn.lock index 6dc241b..1ce7df6 100644 --- a/example/yarn.lock +++ b/example/yarn.lock @@ -19,6 +19,15 @@ js-tokens "^4.0.0" picocolors "^1.0.0" +"@babel/code-frame@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be" + integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg== + dependencies: + "@babel/helper-validator-identifier" "^7.27.1" + js-tokens "^4.0.0" + picocolors "^1.1.1" + "@babel/compat-data@^7.20.5", "@babel/compat-data@^7.22.6", "@babel/compat-data@^7.25.9": version "7.26.3" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.3.tgz#99488264a56b2aded63983abd6a417f03b92ed02" @@ -182,11 +191,21 @@ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c" integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA== +"@babel/helper-string-parser@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687" + integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA== + "@babel/helper-validator-identifier@^7.25.9": version "7.25.9" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7" integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== +"@babel/helper-validator-identifier@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8" + integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow== + "@babel/helper-validator-option@^7.25.9": version "7.25.9" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz#86e45bd8a49ab7e03f276577f96179653d41da72" @@ -201,13 +220,13 @@ "@babel/traverse" "^7.25.9" "@babel/types" "^7.25.9" -"@babel/helpers@^7.26.0": - version "7.26.0" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.26.0.tgz#30e621f1eba5aa45fe6f4868d2e9154d884119a4" - integrity sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw== +"@babel/helpers@^7.26.0", "@babel/helpers@^7.26.10": + version "7.27.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.27.6.tgz#6456fed15b2cb669d2d1fabe84b66b34991d812c" + integrity sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug== dependencies: - "@babel/template" "^7.25.9" - "@babel/types" "^7.26.0" + "@babel/template" "^7.27.2" + "@babel/types" "^7.27.6" "@babel/parser@^7.13.16", "@babel/parser@^7.14.0", "@babel/parser@^7.20.0", "@babel/parser@^7.25.9", "@babel/parser@^7.26.0", "@babel/parser@^7.26.3": version "7.26.3" @@ -216,6 +235,13 @@ dependencies: "@babel/types" "^7.26.3" +"@babel/parser@^7.27.2": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.0.tgz#979829fbab51a29e13901e5a80713dbcb840825e" + integrity sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g== + dependencies: + "@babel/types" "^7.28.0" + "@babel/plugin-proposal-async-generator-functions@^7.0.0": version "7.20.7" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz#bfb7276d2d573cb67ba379984a2334e262ba5326" @@ -633,12 +659,10 @@ pirates "^4.0.6" source-map-support "^0.5.16" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.8.4": - version "7.26.0" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.0.tgz#8600c2f595f277c60815256418b85356a65173c1" - integrity sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw== - dependencies: - regenerator-runtime "^0.14.0" +"@babel/runtime@^7.0.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.26.10", "@babel/runtime@^7.8.4": + version "7.27.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.27.6.tgz#ec4070a04d76bae8ddbb10770ba55714a417b7c6" + integrity sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q== "@babel/template@^7.0.0", "@babel/template@^7.25.9": version "7.25.9" @@ -649,6 +673,15 @@ "@babel/parser" "^7.25.9" "@babel/types" "^7.25.9" +"@babel/template@^7.27.2": + version "7.27.2" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.2.tgz#fa78ceed3c4e7b63ebf6cb39e5852fca45f6809d" + integrity sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/parser" "^7.27.2" + "@babel/types" "^7.27.1" + "@babel/traverse@^7.20.0", "@babel/traverse@^7.25.9": version "7.26.4" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.26.4.tgz#ac3a2a84b908dde6d463c3bfa2c5fdc1653574bd" @@ -670,6 +703,14 @@ "@babel/helper-string-parser" "^7.25.9" "@babel/helper-validator-identifier" "^7.25.9" +"@babel/types@^7.27.1", "@babel/types@^7.27.6", "@babel/types@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.0.tgz#2fd0159a6dc7353933920c43136335a9b264d950" + integrity sha512-jYnje+JyZG5YThjHiF28oT4SIZLnYOcSBb6+SDaFIyzDVSkXQmQQYclJ2R+YxcdmK0AX6x1E5OQNtuh3jHDrUg== + dependencies: + "@babel/helper-string-parser" "^7.27.1" + "@babel/helper-validator-identifier" "^7.27.1" + "@hapi/hoek@^9.0.0", "@hapi/hoek@^9.3.0": version "9.3.0" resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb" @@ -1282,21 +1323,14 @@ bl@^4.1.0: inherits "^2.0.4" readable-stream "^3.4.0" -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== +brace-expansion@^1.1.12, brace-expansion@^1.1.7, brace-expansion@^2.0.1: + version "1.1.12" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.12.tgz#ab9b454466e5a8cc3a187beaad580412a9c5b843" + integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg== dependencies: balanced-match "^1.0.0" concat-map "0.0.1" -brace-expansion@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" - integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== - dependencies: - balanced-match "^1.0.0" - braces@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" @@ -3059,7 +3093,7 @@ path-scurry@^1.6.1: lru-cache "^10.2.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" -picocolors@^1.0.0, picocolors@^1.1.0: +picocolors@^1.0.0, picocolors@^1.1.0, picocolors@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== @@ -3321,11 +3355,6 @@ regenerator-runtime@^0.13.2: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== -regenerator-runtime@^0.14.0: - version "0.14.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" - integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== - regenerator-transform@^0.15.2: version "0.15.2" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.2.tgz#5bbae58b522098ebdf09bca2f83838929001c7a4" diff --git a/package.json b/package.json index 05afab8..c16e302 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,10 @@ "typescript": "^4.5.2" }, "resolutions": { - "@types/react": "17.0.21" + "@types/react": "17.0.21", + "@babel/runtime": "^7.26.10", + "@babel/helpers": "^7.26.10", + "brace-expansion": "^1.1.12" }, "peerDependencies": { "react": "^17.0.2 || ^18.0.0", diff --git a/yarn.lock b/yarn.lock index 21546bc..50752c4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -24,6 +24,15 @@ js-tokens "^4.0.0" picocolors "^1.0.0" +"@babel/code-frame@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be" + integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg== + dependencies: + "@babel/helper-validator-identifier" "^7.27.1" + js-tokens "^4.0.0" + picocolors "^1.1.1" + "@babel/compat-data@^7.20.5", "@babel/compat-data@^7.22.6", "@babel/compat-data@^7.25.9", "@babel/compat-data@^7.26.0": version "7.26.3" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.3.tgz#99488264a56b2aded63983abd6a417f03b92ed02" @@ -196,11 +205,21 @@ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c" integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA== +"@babel/helper-string-parser@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687" + integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA== + "@babel/helper-validator-identifier@^7.25.9": version "7.25.9" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7" integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== +"@babel/helper-validator-identifier@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8" + integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow== + "@babel/helper-validator-option@^7.25.9": version "7.25.9" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz#86e45bd8a49ab7e03f276577f96179653d41da72" @@ -215,13 +234,13 @@ "@babel/traverse" "^7.25.9" "@babel/types" "^7.25.9" -"@babel/helpers@^7.26.0": - version "7.26.0" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.26.0.tgz#30e621f1eba5aa45fe6f4868d2e9154d884119a4" - integrity sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw== +"@babel/helpers@^7.26.0", "@babel/helpers@^7.26.10": + version "7.27.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.27.6.tgz#6456fed15b2cb669d2d1fabe84b66b34991d812c" + integrity sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug== dependencies: - "@babel/template" "^7.25.9" - "@babel/types" "^7.26.0" + "@babel/template" "^7.27.2" + "@babel/types" "^7.27.6" "@babel/parser@^7.1.0", "@babel/parser@^7.13.16", "@babel/parser@^7.14.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.0", "@babel/parser@^7.20.7", "@babel/parser@^7.25.9", "@babel/parser@^7.26.0", "@babel/parser@^7.26.3": version "7.26.3" @@ -230,6 +249,13 @@ dependencies: "@babel/types" "^7.26.3" +"@babel/parser@^7.27.2": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.0.tgz#979829fbab51a29e13901e5a80713dbcb840825e" + integrity sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g== + dependencies: + "@babel/types" "^7.28.0" + "@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.25.9": version "7.25.9" resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz#cc2e53ebf0a0340777fff5ed521943e253b4d8fe" @@ -1082,12 +1108,10 @@ pirates "^4.0.6" source-map-support "^0.5.16" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.8.4": - version "7.26.0" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.0.tgz#8600c2f595f277c60815256418b85356a65173c1" - integrity sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw== - dependencies: - regenerator-runtime "^0.14.0" +"@babel/runtime@^7.0.0", "@babel/runtime@^7.26.10", "@babel/runtime@^7.8.4": + version "7.27.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.27.6.tgz#ec4070a04d76bae8ddbb10770ba55714a417b7c6" + integrity sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q== "@babel/template@^7.0.0", "@babel/template@^7.25.9", "@babel/template@^7.3.3": version "7.25.9" @@ -1098,6 +1122,15 @@ "@babel/parser" "^7.25.9" "@babel/types" "^7.25.9" +"@babel/template@^7.27.2": + version "7.27.2" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.2.tgz#fa78ceed3c4e7b63ebf6cb39e5852fca45f6809d" + integrity sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/parser" "^7.27.2" + "@babel/types" "^7.27.1" + "@babel/traverse@^7.20.0", "@babel/traverse@^7.25.9", "@babel/traverse@^7.7.2": version "7.26.4" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.26.4.tgz#ac3a2a84b908dde6d463c3bfa2c5fdc1653574bd" @@ -1119,6 +1152,14 @@ "@babel/helper-string-parser" "^7.25.9" "@babel/helper-validator-identifier" "^7.25.9" +"@babel/types@^7.27.1", "@babel/types@^7.27.6", "@babel/types@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.0.tgz#2fd0159a6dc7353933920c43136335a9b264d950" + integrity sha512-jYnje+JyZG5YThjHiF28oT4SIZLnYOcSBb6+SDaFIyzDVSkXQmQQYclJ2R+YxcdmK0AX6x1E5OQNtuh3jHDrUg== + dependencies: + "@babel/helper-string-parser" "^7.27.1" + "@babel/helper-validator-identifier" "^7.27.1" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" @@ -2112,7 +2153,16 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@17.0.21", "@types/react@~17.0.21": +"@types/react@*", "@types/react@17.0.21": + version "17.0.21" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.21.tgz#069c43177cd419afaab5ce26bb4e9056549f7ea6" + integrity sha512-GzzXCpOthOjXvrAUFQwU/svyxu658cwu00Q9ugujS4qc1zXgLFaO0kS2SLOaMWLt2Jik781yuHCWB7UcYdGAeQ== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + +"@types/react@~17.0.21": version "17.0.83" resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.83.tgz#b477c56387b74279281149dcf5ba2a1e2216d131" integrity sha512-l0m4ArKJvmFtR4e8UmKrj1pB4tUgOhJITf+mADyF/p69Ts1YAR/E+G9XEM0mHXKVRa1dQNHseyyDNzeuAXfXQw== @@ -2121,6 +2171,11 @@ "@types/scheduler" "^0.16" csstype "^3.0.2" +"@types/scheduler@*": + version "0.26.0" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.26.0.tgz#2b7183b9bbb622d130b23bedf06899b7fec7eed5" + integrity sha512-WFHp9YUJQ6CKshqoC37iOlHnQSmxNc795UhB26CyBBttrN9svdIrUjl/NjnNmfcwtncN0h/0PPAFWv9ovP8mLA== + "@types/scheduler@^0.16": version "0.16.8" resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.8.tgz#ce5ace04cfeabe7ef87c0091e50752e36707deff" @@ -2678,21 +2733,14 @@ bl@^4.1.0: inherits "^2.0.4" readable-stream "^3.4.0" -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== +brace-expansion@^1.1.12, brace-expansion@^1.1.7, brace-expansion@^2.0.1: + version "1.1.12" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.12.tgz#ab9b454466e5a8cc3a187beaad580412a9c5b843" + integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg== dependencies: balanced-match "^1.0.0" concat-map "0.0.1" -brace-expansion@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" - integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== - dependencies: - balanced-match "^1.0.0" - braces@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" @@ -6285,7 +6333,7 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== -picocolors@^1.0.0, picocolors@^1.1.0: +picocolors@^1.0.0, picocolors@^1.1.0, picocolors@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== @@ -6667,11 +6715,6 @@ regenerator-runtime@^0.13.2: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== -regenerator-runtime@^0.14.0: - version "0.14.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" - integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== - regenerator-transform@^0.15.2: version "0.15.2" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.2.tgz#5bbae58b522098ebdf09bca2f83838929001c7a4" From 5968122adb825688d68d010b33990b1217c4d9b6 Mon Sep 17 00:00:00 2001 From: raushan-skyflow Date: Tue, 22 Jul 2025 13:07:03 +0000 Subject: [PATCH 14/23] [AUTOMATED] Private Release 1.9.0-dev.80b44eb --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index c16e302..bb21399 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "skyflow-react-native", - "version": "1.9.0-dev.4e22480", + "version": "1.9.0-dev.80b44eb", "description": "Skyflow React Native SDK", "main": "lib/commonjs/index", "module": "lib/module/index", @@ -67,7 +67,7 @@ "@types/react": "17.0.21", "@babel/runtime": "^7.26.10", "@babel/helpers": "^7.26.10", - "brace-expansion": "^1.1.12" + "brace-expansion": "^1.1.12" }, "peerDependencies": { "react": "^17.0.2 || ^18.0.0", From 7036b4559efcc0c27e5905bcc31a0d5bcb8cd150 Mon Sep 17 00:00:00 2001 From: saileshwar-skyflow <156889717+saileshwar-skyflow@users.noreply.github.com> Date: Fri, 19 Dec 2025 15:09:01 +0530 Subject: [PATCH 15/23] SK-2050: Add Set Token in Reveal Element (#117) * SK-2050: set tokens in reveal elements --- .../__snapshots__/components.test.js.snap | 21 ++++- __tests__/components/components.test.js | 81 ++++++++++++++++++- __tests__/core/RevealContainer.test.js | 52 ++++++++++++ src/components/RevealElement/index.tsx | 34 +++++--- src/core/RevealContainer/index.ts | 17 +++- src/core/RevealSkyflowElement/index.ts | 4 + src/utils/logs/index.ts | 2 + src/utils/skyflow-error-code/index.ts | 4 + 8 files changed, 202 insertions(+), 13 deletions(-) diff --git a/__tests__/components/__snapshots__/components.test.js.snap b/__tests__/components/__snapshots__/components.test.js.snap index ad718fd..11db7c9 100644 --- a/__tests__/components/__snapshots__/components.test.js.snap +++ b/__tests__/components/__snapshots__/components.test.js.snap @@ -302,8 +302,27 @@ Array [ ] `; +exports[`test Collect And Reveal Elements Components test RevealElement component rendering 1`] = ` +Array [ + + Card Number + , + + XXXX XXXX XXXX XXXX + , + , +] +`; + exports[`test Collect And Reveal Elements Components test skyflow provider 1`] = ` - Provider Childern + Provider Children `; diff --git a/__tests__/components/components.test.js b/__tests__/components/components.test.js index aa2fb49..207df89 100644 --- a/__tests__/components/components.test.js +++ b/__tests__/components/components.test.js @@ -21,6 +21,7 @@ import { Text } from 'react-native'; import SkyflowError from '../../src/utils/skyflow-error'; import SKYFLOW_ERROR_CODE from '../../src/utils/skyflow-error-code'; import { ContainerType, ElementType } from '../../src/utils/constants'; +import { act } from 'react-test-renderer'; const testSkyflowClient = new Skyflow({ vaultID: '1234', @@ -598,6 +599,84 @@ describe('test Collect And Reveal Elements Components', () => { } }); + it('test RevealElement component rendering', () => { + const revealSetMethodMock = jest.fn(); + const revealSetTokenMock = jest.fn(); + const revealContainer = new RevealContainer(testSkyflowClient); + + jest.spyOn(revealContainer, 'create').mockImplementation(() => ({ + setMethods: revealSetMethodMock, + setToken: revealSetTokenMock, + })); + + const revealElement = render( + + ); + + expect(revealElement).toMatchSnapshot(); + expect(revealSetMethodMock).toBeCalledTimes(1); + + render( + + ); + expect(screen.getByText('test_token_no_alt')).toBeTruthy(); + + try { + render(); + } catch (err) { + expect(err).toEqual( + new SkyflowError( + SKYFLOW_ERROR_CODE.CONTAINER_OBJECT_IS_REQUIRED, + ['Reveal', 'useRevealContainer()'], + true + ) + ); + } + }); + + it('test RevealElement setToken via ref updates UI and internal element', () => { + const revealSetMethodMock = jest.fn(); + const revealSetTokenMock = jest.fn(); + const revealContainer = new RevealContainer(testSkyflowClient); + + jest.spyOn(revealContainer, 'create').mockImplementation(() => ({ + setMethods: revealSetMethodMock, + setToken: revealSetTokenMock, + })); + + const ref = React.createRef(); + const initialToken = 'initial_token_123'; + const newToken = 'updated_token_456'; + + const { getByText } = render( + + ); + + expect(getByText(initialToken)).toBeTruthy(); + + act(() => { + ref.current.setToken(newToken); + }); + + expect(revealSetTokenMock).toHaveBeenCalledWith(newToken); + + expect(getByText(newToken)).toBeTruthy(); + }); + it('test skyflow provider', () => { const testSkyflowConfig = { vaultID: '1234', @@ -607,7 +686,7 @@ describe('test Collect And Reveal Elements Components', () => { const providerElement = render( - Provider Childern + Provider Children ); expect(providerElement).toMatchSnapshot(); diff --git a/__tests__/core/RevealContainer.test.js b/__tests__/core/RevealContainer.test.js index a126ee6..9fb5530 100644 --- a/__tests__/core/RevealContainer.test.js +++ b/__tests__/core/RevealContainer.test.js @@ -146,4 +146,56 @@ describe('test RevealConatiner Class', () => { } }); }); + + it('test reveal method uses updated token when setToken is called', (done) => { + const initialToken = 'initial_token'; + const updatedToken = 'updated_token'; + + const revealElement = revealContainer.create({ + token: initialToken, + }); + + const revealSuccessValue = { + records: [ + { + token: updatedToken, + value: 'revealed_value', + }, + ], + }; + + const fetchSpy = jest + .spyOn(revealUtils, 'fetchRecordsByTokenId') + .mockResolvedValue(revealSuccessValue); + + const setValueMock = jest.fn(); + const setErrorMock = jest.fn(); + revealElement.setMethods(setValueMock, setErrorMock); + + revealElement.setToken(updatedToken); + + revealContainer + .reveal() + .then((res) => { + try { + expect(fetchSpy).toHaveBeenCalledWith( + expect.anything(), + expect.arrayContaining([ + expect.objectContaining({ + token: updatedToken, + elementId: revealElement.elementId, + }), + ]) + ); + + expect(res).toEqual({ success: [{ token: updatedToken }] }); + done(); + } catch (assertionError) { + done(assertionError); + } + }) + .catch((err) => { + done(err); + }); + }); }); diff --git a/src/components/RevealElement/index.tsx b/src/components/RevealElement/index.tsx index d08872a..41ab521 100644 --- a/src/components/RevealElement/index.tsx +++ b/src/components/RevealElement/index.tsx @@ -1,16 +1,16 @@ /* Copyright (c) 2022 Skyflow, Inc. */ -import React, { useEffect } from "react"; +import React, { useEffect, useImperativeHandle, forwardRef } from "react"; import { Text } from "react-native"; import RevealSkyflowElement from "../../core/RevealSkyflowElement"; import { RevealElementProps } from "../../utils/constants" import SkyflowError from "../../utils/skyflow-error"; import SKYFLOW_ERROR_CODE from "../../utils/skyflow-error-code"; - -const RevealElement: React.FC = ({ container, label, ...rest }) => { - const [element, setElement] = React.useState(undefined); +const RevealElement = forwardRef((props: RevealElementProps, ref) => { + const { container, label, ...rest } = props; + const [element, setElement] = React.useState(undefined); const [errorText, setErrorText] = React.useState(''); const [value, setValue] = React.useState(rest?.altText || rest.token); @@ -25,12 +25,26 @@ const RevealElement: React.FC = ({ container, label, ...rest }, []); - return <> - {label} - {value} - {errorText} - + useImperativeHandle(ref, () => ({ + setToken: (newToken: string) => { + if (element) { + element.setToken(newToken); + setValue(newToken); + } else { + throw new SkyflowError(SKYFLOW_ERROR_CODE.ELEMENT_NOT_FOUND, ['RevealElement'], true); + } + } + }), [element]); + + return ( + <> + {label} + {value} + {errorText} + + ); +}); -} +RevealElement.displayName = 'RevealElement'; export default RevealElement; \ No newline at end of file diff --git a/src/core/RevealContainer/index.ts b/src/core/RevealContainer/index.ts index 35552ae..bd20cc4 100644 --- a/src/core/RevealContainer/index.ts +++ b/src/core/RevealContainer/index.ts @@ -70,7 +70,22 @@ class RevealContainer extends Container { try { validateInitConfig(this.#skyflowClient.getSkyflowConfig()); validateRevealElementRecords(this.#revealRecords); - fetchRecordsByTokenId(this.#skyflowClient, this.#tokensList).then( + + const freshTokensList = this.#tokensList.map((record) => { + const elementInstance = this.#elementList.find( + (e) => e.elementId === record.elementId + ); + + if (elementInstance) { + return { + ...record, + token: elementInstance.getToken(), + }; + } + return record; + }); + + fetchRecordsByTokenId(this.#skyflowClient, freshTokensList).then( (resolvedResult) => { const formattedResult = formatRecordsForIframe(resolvedResult); this.setRevealValuesInElements(formattedResult); diff --git a/src/core/RevealSkyflowElement/index.ts b/src/core/RevealSkyflowElement/index.ts index bd4986c..c56e984 100644 --- a/src/core/RevealSkyflowElement/index.ts +++ b/src/core/RevealSkyflowElement/index.ts @@ -27,6 +27,10 @@ class RevealSkyflowElement extends SkyflowElement { this.#setErrorText(REVEAL_ELEMENT_ERROR_TEXT); } + setToken(newToken: string) { + this.#token = newToken; + } + getToken() { return this.#token; } diff --git a/src/utils/logs/index.ts b/src/utils/logs/index.ts index fb6a125..622246f 100644 --- a/src/utils/logs/index.ts +++ b/src/utils/logs/index.ts @@ -133,6 +133,8 @@ const logs = { `Skyflow ${SDK_NAME_VERSION} initialization failed - SkyflowProvider config is missing. `, CONTAINER_OBJECT_IS_REQUIRED: `${SDK_NAME_VERSION} cannot create %s1 element without container object, create a container using %s2 hook.`, + ELEMENT_NOT_FOUND: + `${SDK_NAME_VERSION} %s1 not found. The specified element does not exist in the container.`, INVALID_UPSERT_OPTION_TYPE: `${SDK_NAME_VERSION} Validation error. Invalid \'upsert\' key in insert options. Specify a value of type array instead`, EMPTY_UPSERT_OPTIONS_ARRAY: diff --git a/src/utils/skyflow-error-code/index.ts b/src/utils/skyflow-error-code/index.ts index 14e93eb..333351f 100644 --- a/src/utils/skyflow-error-code/index.ts +++ b/src/utils/skyflow-error-code/index.ts @@ -190,6 +190,10 @@ const SKYFLOW_ERROR_CODE = { code: 400, description: logs.errorLogs.CONTAINER_OBJECT_IS_REQUIRED, }, + ELEMENT_NOT_FOUND: { + code: 400, + description: logs.errorLogs.ELEMENT_NOT_FOUND, + }, INVALID_UPSERT_OPTION_TYPE: { code: 400, description: logs.errorLogs.INVALID_UPSERT_OPTION_TYPE, From 48cf8c6cd8fe3e73e878b34336ad750b08f15163 Mon Sep 17 00:00:00 2001 From: saileshwar-skyflow Date: Fri, 19 Dec 2025 09:40:01 +0000 Subject: [PATCH 16/23] [AUTOMATED] Private Release 1.9.0-dev.7036b45 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 03d5000..f49668c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "skyflow-react-native", - "version": "1.9.0", + "version": "1.9.0-dev.7036b45", "description": "Skyflow React Native SDK", "main": "lib/commonjs/index", "module": "lib/module/index", From 999b188a64b65bd242cee101b6157979c85fe997 Mon Sep 17 00:00:00 2001 From: saileshwar-skyflow Date: Sat, 20 Dec 2025 17:23:08 +0000 Subject: [PATCH 17/23] [AUTOMATED] Private Release 1.9.0-dev.896cf63 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9fd5a3d..6f64d63 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "skyflow-react-native", - "version": "1.9.0-dev.7036b45", + "version": "1.9.0-dev.896cf63", "description": "Skyflow React Native SDK", "main": "lib/commonjs/index", "module": "lib/module/index", From ef764b9f9449d3b425a58a443979bb0abcf0cc41 Mon Sep 17 00:00:00 2001 From: saileshwar-skyflow Date: Mon, 22 Dec 2025 13:28:05 +0530 Subject: [PATCH 18/23] SK-2050: add SkyflowRevealElementRef type --- example/src/App.tsx | 35 +++++++++++++++++++------- example/src/ElementView.tsx | 4 +-- example/src/RevealElements.tsx | 33 +++++++++++------------- src/components/RevealElement/index.tsx | 4 +-- src/index.ts | 1 + src/utils/constants/index.ts | 4 +++ 6 files changed, 49 insertions(+), 32 deletions(-) diff --git a/example/src/App.tsx b/example/src/App.tsx index c22b8ff..380fe4c 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -26,11 +26,28 @@ const App = () => { return new Promise((resolve, reject) => { const Http = new XMLHttpRequest(); - resolve('eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2MiOiJiOTYzZTcxMjFkZDY0YTZkOTY0MGQ3ZTNlNGNjODdhNyIsImF1ZCI6Imh0dHBzOi8vbWFuYWdlLWJsaXR6LnNreWZsb3dhcGlzLmRldiIsImV4cCI6MTc2NjMyNzg5NCwiaWF0IjoxNzY2MjQxNDk0LCJpc3MiOiJzYS1hdXRoQG1hbmFnZS1ibGl0ei5za3lmbG93YXBpcy5kZXYiLCJqdGkiOiJwZWViYTFiYmExZTA0ODFjODk0ZGM2MWVjN2ZhODk5OSIsInN1YiI6Im0xODQ2YzA2M2FlODQ4MjhhNzM4OWQ3ZTc0OTE5MzE5In0.c1n87PWuKU0LJ2-tSwlK5rsTUfjE_zKKAkeDYclkP0Xh_6gnAynA83UoxJV8qDbPsmu1zuCXW7Pt4-M6kCDUViVkv2KhHYDbDByXl_PG7cVNrj0d6kxkUm_FORRFmyyCWZKy3S2tomdw_gQar2LakuENuWXAR2gL5LSywb_XZmJxgolLe6RdqcHxdSQTV5j7PkjbhfSnkuMaFK0_z8fA8Wdm-44aCa-eALAFEHCZ0-YiQqlB_24ERQxL9bfD6dxiVJqyWVEg-hrGUE0WDUtNQVhoevbcQdC7GxH7AA_yk2xUxxJh7w7OzN1-YBmQWXGgQUZg4DXT9qnugNxeH8B6Tg') + Http.onreadystatechange = () => { + if (Http.readyState === 4) { + if (Http.status === 200) { + const response = JSON.parse(Http.responseText); + resolve(response.accessToken); + } else { + reject('Error occured'); + } + } + }; + + Http.onerror = error => { + reject('Error occured'); + }; + + const url = ''; + Http.open('GET', url); + Http.send(); }); }, - vaultID: 'tfe60a6eef66434b82e982285610e668', - vaultURL: 'https://qhdmceurtnlz.vault.skyflowapis.dev', + vaultID: '', + vaultURL: '', options: { logLevel: LogLevel.ERROR, env: Env.PROD, @@ -40,7 +57,7 @@ const App = () => { return ( - {/* {!displayCollect && !displayComposable && !displayCobrandedCard && <> + {!displayCollect && !displayComposable && !displayCobrandedCard && <>