Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
138c46b
SK-3005 flowdb support
skyflow-bharti Jul 22, 2026
fb3c3c1
SK-3005 added update by skyflow id flowdb support
skyflow-bharti Jul 22, 2026
8d17511
SK-3005 added reveal flowdb support
skyflow-bharti Jul 22, 2026
2209d08
SK-3005 added reveal flowdb support
skyflow-bharti Jul 23, 2026
02807b1
SK-3005 added unit test cases
skyflow-bharti Jul 24, 2026
e83abe3
SK-3005 request and response structure change for flowvaults
skyflow-bharti Jul 27, 2026
7534467
SK-3005 request and response structure change for flowvaults
skyflow-bharti Jul 28, 2026
06bb4b4
SK-3005 update readme and sample
skyflow-bharti Jul 28, 2026
95576da
SK-3005 update collect and reveal strcuture
skyflow-bharti Jul 28, 2026
03ed970
SK-3005 update type for additional fields
skyflow-bharti Jul 28, 2026
837f518
SK-3005 update type for additional fields and redaction option in rev…
skyflow-bharti Jul 29, 2026
7d38bd6
SK-3005 update readme
skyflow-bharti Jul 29, 2026
443b493
SK-3005 added tests
skyflow-bharti Jul 29, 2026
17f8c55
SK-3005 update callbacks in readme
skyflow-bharti Jul 29, 2026
d9919aa
Merge pull request #314 from skyflowapi/SK-3005-flow-db-feature-parit…
skyflow-bharti Jul 29, 2026
d3b43a7
[AUTOMATED] Private Release 1.25.1.d9919aa
skyflow-bharti Jul 29, 2026
e2a50fc
SK-3005 update readme for skyflowid
skyflow-bharti Jul 30, 2026
caf0faa
SK-3005 update readme for skyflowid
skyflow-bharti Jul 30, 2026
95754f9
SK-3005 update readme for skyflowid
skyflow-bharti Jul 30, 2026
cd8322d
SK-3005 update readme
skyflow-bharti Jul 30, 2026
2b08349
Merge pull request #319 from skyflowapi/SK-3005-flow-db-feature-parit…
skyflow-bharti Jul 30, 2026
4e283ea
[AUTOMATED] Private Release 1.25.1.2b08349
skyflow-bharti Jul 30, 2026
f0289ba
SK-3005 added the validations
skyflow-bharti Jul 31, 2026
c3acf8d
SK-3005 update table name key
skyflow-bharti Jul 31, 2026
d6221b5
[AUTOMATED] Private Release 1.25.1.c3acf8d
skyflow-bharti Jul 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
991 changes: 505 additions & 486 deletions README.md

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class CardBrandChoiceSampleViewController: UIViewController {
let iconStyles = Skyflow.Styles(base: Style(cardIconAlignment: .right))

// create card number element
let collectCardNumberInput = Skyflow.CollectElementInput(table: "<TABLE_NAME>", column: "<COLUMN_NAME>", inputStyles: inputStyles, iconStyles: Styles(base: Style(cardIconAlignment: .right)),label: "Card Number", placeholder: "XXXXXXXXXXXXX", type: Skyflow.ElementType.CARD_NUMBER)
let collectCardNumberInput = Skyflow.CollectElementInput(tableName: "<TABLE_NAME>", column: "<COLUMN_NAME>", inputStyles: inputStyles, iconStyles: Styles(base: Style(cardIconAlignment: .right)),label: "Card Number", placeholder: "XXXXXXXXXXXXX", type: Skyflow.ElementType.CARD_NUMBER)
let requiredOption = Skyflow.CollectElementOptions(required: true, enableCardIcon: true, enableCopy: false)

collectCardNumberElement = container?.create(input: collectCardNumberInput, options: requiredOption)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class CollectAndRevealViewController: UIViewController {
private var revealButton: UIButton!

private var revealed = false
private var tokenGroupRedactions: [Skyflow.TokenGroupRedaction] = []


override func viewDidLoad() {
Expand Down Expand Up @@ -67,39 +68,39 @@ class CollectAndRevealViewController: UIViewController {
)

let collectCardNumberInput = Skyflow.CollectElementInput(
table: "credit_cards",
tableName: "credit_cards",
column: "card_number",
inputStyles: styles,
label: "Card Number",
placeholder: "4111-1111-1111-1111",
type: Skyflow.ElementType.CARD_NUMBER
)
let collectNameInput = Skyflow.CollectElementInput(
table: "credit_cards",
tableName: "credit_cards",
column: "cardholder_name",
inputStyles: styles,
label: "Card Holder Name",
placeholder: "John Doe",
type: Skyflow.ElementType.CARDHOLDER_NAME
)
let collectCVVInput = Skyflow.CollectElementInput(
table: "credit_cards",
tableName: "credit_cards",
column: "cvv",
inputStyles: styles,
label: "CVV",
placeholder: "***",
type: .CVV
)
let collectExpMonthInput = Skyflow.CollectElementInput(
table: "credit_cards",
tableName: "credit_cards",
column: "expiry_month",
inputStyles: styles,
label: "Expiration Month",
placeholder: "MM",
type: .EXPIRATION_MONTH
)
let collectExpYearInput = Skyflow.CollectElementInput(
table: "credit_cards",
tableName: "credit_cards",
column: "expiry_year",
inputStyles: styles,
label: "Expiration Year",
Expand Down Expand Up @@ -127,23 +128,23 @@ class CollectAndRevealViewController: UIViewController {
stackView.addArrangedSubview(collectExpMonth!)
stackView.addArrangedSubview(collectExpYear!)
stackView.addArrangedSubview(collectButton)

stackView.axis = .vertical
stackView.distribution = .fill
stackView.spacing = 5
stackView.alignment = .fill
stackView.translatesAutoresizingMaskIntoConstraints = false

let scrollView = UIScrollView(frame: .zero)
scrollView.isScrollEnabled = true
scrollView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(scrollView)

scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 2).isActive = true
scrollView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor, constant: 2).isActive = true
scrollView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor, constant: -10).isActive = true
scrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true

scrollView.addSubview(stackView)
stackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor, constant: -10).isActive = true
stackView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
Expand All @@ -153,26 +154,51 @@ class CollectAndRevealViewController: UIViewController {
}
}
@objc func revealForm() {
self.revealContainer?.reveal(callback: ExampleAPICallback())
let revealCallback = Skyflow.RevealCallback(
onSuccess: { (response: Skyflow.RevealResponse) in
for record in response.records {
if let error = record.error {
print("reveal failed:", error, "httpCode:", record.httpCode)
} else {
print("revealed:", record.token ?? "", record.tokenGroupName ?? "", record.metadata ?? [:])
}
}
},
onFailure: { (error: Skyflow.SkyflowError) in print("reveal failure:", error.httpCode, error.message) }
)
let revealOptions = Skyflow.RevealOptions(tokenGroupRedactions: self.tokenGroupRedactions.isEmpty ? nil : self.tokenGroupRedactions)
self.revealContainer?.reveal(callback: revealCallback, options: revealOptions)
}
@objc func submitForm() {
let exampleAPICallback = ExampleAPICallback(updateSuccess: updateSuccess, updateFailure: updateFailure)
container!.collect(callback: exampleAPICallback, options: Skyflow.CollectOptions(tokens: true))
let collectCallback = Skyflow.CollectCallback(onSuccess: updateSuccess, onFailure: updateFailure)
container!.collect(callback: collectCallback, options: Skyflow.CollectOptions())
}
internal func updateSuccess(_ response: SuccessResponse) {
internal func updateSuccess(_ response: Skyflow.CollectResponse) {
print(response)
retryCount = 0
updateRevealInputs(tokens: response.records[0].fields)
for result in response.records {
if let error = result.error {
print("Record failed:", error, "httpCode:", result.httpCode)
}
}
if let tokens = response.records.first?.tokens {
updateRevealInputs(tokens: tokens)
}
print("Successfully got response:", response)
}
internal func updateFailure(error: Any) {
if((error as AnyObject).contains("Invalid Bearer token") && retryCount <= 2){ // To do, it will be replaced with error code in the future
internal func updateFailure(error: Skyflow.SkyflowError) {
if(error.message.contains("Invalid Bearer token") && retryCount <= 2){ // To do, it will be replaced with error code in the future
retryCount += 1
submitForm()
}
print("Failed Operation", error)
print("Failed Operation", error.httpCode, error.message, error.grpcCode ?? "", error.httpStatus ?? "", error.details ?? "")
}
internal func updateRevealInputs(tokens: Fields) {
// fields is [String: Any] - column name -> array of {"token","tokenGroupName"} dicts.
internal func firstToken(_ fields: [String: Any], column: String) -> (token: String, tokenGroupName: String?) {
guard let entries = fields[column] as? [[String: Any]], let first = entries.first else { return ("", nil) }
return (first["token"] as? String ?? "", first["tokenGroupName"] as? String)
}
internal func updateRevealInputs(tokens: [String: Any]) {
let revealBaseStyle = Skyflow.Style(
borderColor: UIColor.black,
cornerRadius: 20,
Expand All @@ -188,40 +214,48 @@ class CollectAndRevealViewController: UIViewController {
} else {
self.revealed = true
}
// tokenGroupRedactions: request-level redaction per token group, applied when
// reveal() is called (see revealForm()) - not per reveal element.
self.tokenGroupRedactions = []
func addTokenGroupRedaction(_ redaction: String, forColumn column: String) {
if let tokenGroupName = self.firstToken(tokens, column: column).tokenGroupName {
self.tokenGroupRedactions.append(Skyflow.TokenGroupRedaction(tokenGroupName: tokenGroupName, redaction: redaction))
}
}
addTokenGroupRedaction("REDACTED", forColumn: "card_number")
addTokenGroupRedaction("MASKED", forColumn: "cvv")
addTokenGroupRedaction("DEFAULT", forColumn: "cardholder_name")
addTokenGroupRedaction("PLAIN_TEXT", forColumn: "expiry_month")

let revealCardNumberInput = Skyflow.RevealElementInput(
token: tokens.card_number,
token: self.firstToken(tokens, column: "card_number").token,
inputStyles: revealStyles,
label: "Card Number",
redaction: .REDACTED
label: "Card Number"
)
self.revealCardNumber = self.revealContainer?.create(
input: revealCardNumberInput,
options: Skyflow.RevealElementOptions()
)
let revealCVVtInput = Skyflow.RevealElementInput(
token: tokens.cvv,
token: self.firstToken(tokens, column: "cvv").token,
inputStyles: revealStyles,
label: "CVV",
redaction: .MASKED
label: "CVV"
)
self.revealCVV = self.revealContainer?.create(input: revealCVVtInput)
let revealNameInput = Skyflow.RevealElementInput(
token: tokens.cardholder_name,
token: self.firstToken(tokens, column: "cardholder_name").token,
inputStyles: revealStyles,
label: "Card Holder Name",
redaction: .DEFAULT

label: "Card Holder Name"
)
self.revealName = self.revealContainer?.create(input: revealNameInput)
let revealExpirationMonthInput = Skyflow.RevealElementInput(
token: tokens.expiry_month,
token: self.firstToken(tokens, column: "expiry_month").token,
inputStyles: revealStyles,
label: "Expiration Month",
redaction: .PLAIN_TEXT
label: "Expiration Month"
)
self.revealExpirationMonth = self.revealContainer?.create(input: revealExpirationMonthInput)
let revealExpirationYearInput = Skyflow.RevealElementInput(
token: tokens.expiry_year,
token: self.firstToken(tokens, column: "expiry_year").token,
inputStyles: revealStyles,
label: "Expiration Year"
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,47 +2,6 @@
* Copyright (c) 2022 Skyflow
*/

import Foundation
import Skyflow

public class ExampleAPICallback: Skyflow.Callback {
private var updateSuccess: ((SuccessResponse) -> Void)?
private var updateFailure: ((Any) -> Void)?
private var decoder: JSONDecoder?

internal init(updateSuccess: @escaping (SuccessResponse) -> Void, updateFailure: @escaping (Any) -> Void) {
self.updateSuccess = updateSuccess
self.updateFailure = updateFailure
self.decoder = JSONDecoder()
}

internal init() {
}

public func onSuccess(_ responseBody: Any) {
if updateSuccess == nil {
print("success:", responseBody)
return
}
do {
let dataString = String(data: try! JSONSerialization.data(withJSONObject: responseBody), encoding: .utf8)
let responseData = Data(dataString!.utf8)
let jsonResponse = try decoder!.decode(SuccessResponse.self, from: responseData)

updateSuccess!(jsonResponse)

print("success:", jsonResponse)
} catch {
print("error deserializing", error)
}
}

public func onFailure(_ error: Any) {
print(error)
if updateFailure != nil {
print("failure:", error)
return
}
print("onfailure", error)
}
}
// No longer needed - use Skyflow.CollectCallback / Skyflow.RevealCallback directly
// (see CollectAndRevealViewController.swift), which already deliver typed responses
// (Skyflow.CollectResponse / Skyflow.RevealResponse) without a custom Callback subclass.
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,6 @@
* Copyright (c) 2022 Skyflow
*/

import Foundation

struct SuccessResponse: Codable {
let records: [Records]
}

struct Records: Codable {
let fields: Fields
let table: String
}

struct Fields: Codable {
let cardholder_name: String
let card_number: String
let expiry_month: String
let expiry_year: String
let cvv: String
let skyflow_id: String
}
// No longer needed - the SDK now provides typed responses directly
// (Skyflow.CollectResponse / Skyflow.RevealResponse), so this sample no longer
// needs to declare its own local response structs.
3 changes: 1 addition & 2 deletions Samples/CollectAndRevealSample/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ source 'https://github.com/CocoaPods/Specs.git'

target 'CollectAndRevealSample' do
#use_frameworks!
pod 'AEXML', '4.6.1'

# Pods for skyflow-iOS-sample-app
pod 'Skyflow', ">= 1.23.0"
pod 'Skyflow', ">= 1.25.0"

end
Original file line number Diff line number Diff line change
Expand Up @@ -2,47 +2,6 @@
* Copyright (c) 2022 Skyflow
*/

import Foundation
import Skyflow

public class ExampleAPICallback: Skyflow.Callback {
private var updateSuccess: ((SuccessResponse) -> Void)?
private var updateFailure: ((Any) -> Void)?
private var decoder: JSONDecoder?

internal init(updateSuccess: @escaping (SuccessResponse) -> Void, updateFailure: @escaping (Any) -> Void) {
self.updateSuccess = updateSuccess
self.updateFailure = updateFailure
self.decoder = JSONDecoder()
}

internal init() {
}

public func onSuccess(_ responseBody: Any) {
if updateSuccess == nil {
print("success:", responseBody)
return
}
do {
let dataString = String(data: try! JSONSerialization.data(withJSONObject: responseBody), encoding: .utf8)
let responseData = Data(dataString!.utf8)
let jsonResponse = try decoder!.decode(SuccessResponse.self, from: responseData)

updateSuccess!(jsonResponse)

print("success:", jsonResponse)
} catch {
print("error deserializing", error)
}
}

public func onFailure(_ error: Any) {
print(error)
if updateFailure != nil {
print("failure:", error)
return
}
print("onfailure", error)
}
}
// No longer needed - use Skyflow.CollectCallback / Skyflow.RevealCallback directly
// (see ViewController.swift), which already deliver typed responses
// (Skyflow.CollectResponse / Skyflow.RevealResponse) without a custom Callback subclass.
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,6 @@
* Copyright (c) 2022 Skyflow
*/

import Foundation

struct SuccessResponse: Codable {
let records: [Records]
}

struct Records: Codable {
let fields: Fields
let table: String
}

struct Fields: Codable {
let cardholder_name: String
let card_number: String
let expiry_month: String
let expiry_year: String
let cvv: String
let skyflow_id: String
}
// No longer needed - the SDK now provides typed responses directly
// (Skyflow.CollectResponse / Skyflow.RevealResponse), so this sample no longer
// needs to declare its own local response structs.
Loading
Loading