Skip to content

Commit

Permalink
Release v4.4.4 (#165)
Browse files Browse the repository at this point in the history
* Release 4.4.4

* Format + lint
  • Loading branch information
djoksimo authored May 10, 2024
1 parent 962e8d2 commit 6dac69d
Show file tree
Hide file tree
Showing 12 changed files with 121 additions and 126 deletions.
4 changes: 2 additions & 2 deletions ForageSDK.podspec
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
Pod::Spec.new do |spec|

spec.name = "ForageSDK"
spec.version = "4.4.3"
spec.version = "4.4.4"
spec.summary = "ForageSDK"
spec.description = "The ForageSDK process Electronic Benefit Transfer (EBT) payments in your e-commerce application."
spec.homepage = "https://github.com/teamforage/forage-ios-sdk"
spec.license = { :type => "MIT", :file => "LICENSE" }
spec.author = { "Rob Gormisky" => "[email protected]" }
spec.platform = :ios, "13.0"
spec.readme = "https://raw.githubusercontent.com/teamforage/forage-ios-sdk/main/README.md"
spec.source = { :git => "https://github.com/teamforage/forage-ios-sdk.git", :tag => "4.4.3" }
spec.source = { :git => "https://github.com/teamforage/forage-ios-sdk.git", :tag => "4.4.4" }
spec.source_files = ["Sources/ForageSDK/**/*.swift", "DatadogPrivate-Objc/**/*.{h,m}"]
spec.dependency 'VGSCollectSDK', '1.15.3'
spec.dependency 'LaunchDarkly', '9.6.0'
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ pod init
3. Add the following line to your `Podfile`:

```swift
pod 'ForageSDK', '~> 4.4.3'
pod 'ForageSDK', '~> 4.4.4'
```

4. Run the following command
Expand Down
2 changes: 1 addition & 1 deletion Sources/ForageSDK/ForageSDK.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class ForageSDK {

public var environment: Environment = .sandbox
// Don't update! Only updated when releasing.
public static let version = "4.4.3"
public static let version = "4.4.4"
public static let shared = ForageSDK()

// MARK: Init
Expand Down
32 changes: 16 additions & 16 deletions Sources/ForageSDK/Foundation/Network/Collector.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,11 @@ class VGSCollectWrapper: VaultCollector {
mutableHeaders["X-KEY"] = xKey["vgsXKey"]
vgsCollect.customHeaders = mutableHeaders
}
internal func handleResponse<T: Decodable>(code: Int, data: Data?, error: Error?, measurement: NetworkMonitor, completion: (T?, ForageError?) -> Void) {

func handleResponse<T: Decodable>(code: Int, data: Data?, error: Error?, measurement: NetworkMonitor, completion: (T?, ForageError?) -> Void) {
measurement.end()
measurement.setHttpStatusCode(code).logResult()

// If an error is explicitly returned from VGS, log the error and return
if let error = error {
logger?.critical(
Expand All @@ -92,7 +92,7 @@ class VGSCollectWrapper: VaultCollector {
)
return completion(nil, CommonErrors.UNKNOWN_SERVER_ERROR)
}

// If the response was a Forage error (ex. 429 throttled), catch it here and return
if let forageServiceError = try? JSONDecoder().decode(ForageServiceError.self, from: data) {
let forageCode = forageServiceError.errors[0].code
Expand All @@ -103,13 +103,13 @@ class VGSCollectWrapper: VaultCollector {
message: message
))
}

// If the code is a 204, we got a successful response from the deferred capture flow.
// In this scenario, we should just return
if (code == 204) {
if code == 204 {
return completion(nil, nil)
}

// Try to decode the response and return the expected object
do {
let decoder = JSONDecoder()
Expand Down Expand Up @@ -238,8 +238,8 @@ class BasisTheoryWrapper: VaultCollector {
}
}
}
internal func handleResponse<T: Decodable>(response: URLResponse?, data: JSON?, error: Error?, measurement: NetworkMonitor, completion: (T?, ForageError?) -> Void) {

func handleResponse<T: Decodable>(response: URLResponse?, data: JSON?, error: Error?, measurement: NetworkMonitor, completion: (T?, ForageError?) -> Void) {
measurement.end()

let httpStatusCode = (response as? HTTPURLResponse)?.statusCode
Expand All @@ -253,20 +253,20 @@ class BasisTheoryWrapper: VaultCollector {
])
return completion(nil, CommonErrors.UNKNOWN_SERVER_ERROR)
}

guard let data = data else {
logger?.critical("Basis Theory failed to respond with a data object", error: nil, attributes: [
"http_status": httpStatusCode
])
return completion(nil, CommonErrors.UNKNOWN_SERVER_ERROR)
}

// If the code is a 204, we got a successful response from the deferred capture flow.
// In this scenario, we should just return
if (httpStatusCode == 204) {
if httpStatusCode == 204 {
return completion(nil, nil)
}

// If we found `proxy_error` in the response, we know there was an issue with the BT proxy.
// We can't currently access any of the information returned from BT in this state.
if data["proxy_error"] != nil {
Expand All @@ -275,7 +275,7 @@ class BasisTheoryWrapper: VaultCollector {
])
return completion(nil, CommonErrors.UNKNOWN_SERVER_ERROR)
}

let dataObject: Data
// Try to decode the response and return the expected object
do {
Expand All @@ -290,7 +290,7 @@ class BasisTheoryWrapper: VaultCollector {
)
return completion(nil, CommonErrors.UNKNOWN_SERVER_ERROR)
}

// If the response was a Forage error (ex. 429 throttled), catch it here and return
if let forageServiceError = try? JSONDecoder().decode(ForageServiceError.self, from: dataObject) {
let forageCode = forageServiceError.errors[0].code
Expand All @@ -301,7 +301,7 @@ class BasisTheoryWrapper: VaultCollector {
message: message
))
}

// Try to decode the response and return the expected object
do {
let decoder = JSONDecoder()
Expand Down
2 changes: 1 addition & 1 deletion Sources/ForageSDK/Foundation/Network/ForageAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ extension ForageAPI: ServiceProtocol {
"content-type": "application/json",
"accept": "application/json",
"x-datadog-trace-id": ForageSDK.shared.traceId,
"API-VERSION": "default"
"API-VERSION": "default",
])
switch self {
case let .tokenizeNumber(
Expand Down
60 changes: 29 additions & 31 deletions Sources/ForageSDK/Foundation/Network/LiveForageService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class LiveForageService: ForageService {
do {
// If any of the preamble requests fail, return back a generic response to the user
let balanceRequest = try await createRequestModel(using: getTokenFromPaymentMethod, tokenRef: paymentMethodReference)

// If the vault request fails for some unforeseen reason, return back a generic response to the user
rawBalanceModel = try await submitPinToVault(
pinCollector: pinCollector,
Expand All @@ -56,7 +56,7 @@ class LiveForageService: ForageService {
} catch {
throw error
}

guard let rawBalanceModel = rawBalanceModel else {
logger?.critical(
"Received malformed Vault response",
Expand All @@ -65,12 +65,12 @@ class LiveForageService: ForageService {
)
throw CommonErrors.UNKNOWN_SERVER_ERROR
}

// Return the balance back to the user
if let balance = rawBalanceModel.balance {
return balance
}

// ELSE return back the expected EBT Network error to the user
if let vaultError = rawBalanceModel.error {
let forageError = ForageError.create(
Expand Down Expand Up @@ -110,7 +110,7 @@ class LiveForageService: ForageService {
} catch {
throw error
}

guard let paymentResponse = paymentResponse else {
logger?.critical(
"Received malformed Vault response",
Expand All @@ -119,7 +119,7 @@ class LiveForageService: ForageService {
)
throw CommonErrors.UNKNOWN_SERVER_ERROR
}

// Return back the expected EBT Network error to the user
if let vaultError = paymentResponse.error {
let forageError = ForageError.create(
Expand All @@ -129,18 +129,18 @@ class LiveForageService: ForageService {
)
throw forageError
}

return paymentResponse
}

typealias CollectTokenFunc = (_ sessionToken: String, _ merchantID: String, _ reference: String) async throws -> String

// MARK: Collect PIN

func collectPinForDeferredCapture(
pinCollector: VaultCollector,
paymentReference: String
) async throws -> Void {
) async throws {
do {
let _: Empty? = try await collectPinForPayment(
pinCollector: pinCollector,
Expand All @@ -151,14 +151,13 @@ class LiveForageService: ForageService {
} catch {
throw error
}

}

// MARK: Private structs

/// `Empty` used to signify a generic, decodable type that returns nothing
private struct Empty: Decodable {}

/// `ForageRequestModel` used for compose ForageSDK requests
private struct ForageRequestModel: Codable {
let authorization: String
Expand All @@ -168,7 +167,7 @@ class LiveForageService: ForageService {
}

// MARK: Private helper methods

/// Common logic required for all requests to the proxy.
private func createRequestModel(
using collectTokenFunc: CollectTokenFunc,
Expand All @@ -182,9 +181,9 @@ class LiveForageService: ForageService {
let xKeyModel = try await awaitResult { completion in
self.getXKey(sessionToken: sessionToken, merchantID: merchantID, completion: completion)
}

let token = try await collectTokenFunc(sessionToken, merchantID, tokenRef)

return ForageRequestModel(
authorization: sessionToken,
cardNumberToken: token,
Expand All @@ -200,7 +199,7 @@ class LiveForageService: ForageService {
throw error
}
}

/// Common Payment-related prologue across capturePayment and collectPin.
/// Both `deferPaymentCapture` and `capturePayment` involve the same
/// preliminerary data retrieval and a trip to the Vault (VGS or Basis Theory) Proxy
Expand All @@ -212,7 +211,7 @@ class LiveForageService: ForageService {
) async throws -> T? {
do {
let collectPinRequest = try await createRequestModel(using: getTokenFromPayment, tokenRef: paymentReference)

let basePath = "/api/payments/\(paymentReference)"

return try await submitPinToVault(
Expand All @@ -225,7 +224,6 @@ class LiveForageService: ForageService {
} catch {
throw error
}

}

/// Submit PIN to the Vault Proxy (Basis Theory or VGS)
Expand Down Expand Up @@ -263,15 +261,15 @@ class LiveForageService: ForageService {
continuation.resume(returning: (result, error))
}
}

if let error = error {
throw error
}

return result
}
}

private func getTokenFromPayment(sessionToken: String, merchantID: String, paymentRef: String) async throws -> String {
do {
/// We only decode what we need here using `ThinPaymentModel`
Expand All @@ -286,13 +284,13 @@ class LiveForageService: ForageService {
completion: completion
)
}

return try await getTokenFromPaymentMethod(sessionToken: sessionToken, merchantID: merchantID, paymentMethodRef: payment.paymentMethodRef)
} catch {
throw error
}
}

private func getTokenFromPaymentMethod(sessionToken: String, merchantID: String, paymentMethodRef: String) async throws -> String {
do {
let paymentMethod = try await awaitResult { completion in
Expand All @@ -303,27 +301,27 @@ class LiveForageService: ForageService {
completion: completion
)
}

return paymentMethod.card.token
} catch {
throw error
}
}
internal func getPayment<T : Decodable>(sessionToken: String, merchantID: String, paymentRef: String, completion: @escaping (Result<T, Error>) -> Void) {

func getPayment<T: Decodable>(sessionToken: String, merchantID: String, paymentRef: String, completion: @escaping (Result<T, Error>) -> Void) {
do { try provider.execute(model: T.self, endpoint: ForageAPI.getPayment(sessionToken: sessionToken, merchantID: merchantID, paymentRef: paymentRef), completion: completion) } catch { completion(.failure(error)) }
}
internal func getPaymentMethod(

func getPaymentMethod(
sessionToken: String,
merchantID: String,
paymentMethodRef: String,
completion: @escaping (Result<PaymentMethodModel, Error>) -> Void
) {
do { try provider.execute(model: PaymentMethodModel.self, endpoint: ForageAPI.getPaymentMethod(sessionToken: sessionToken, merchantID: merchantID, paymentMethodRef: paymentMethodRef), completion: completion) } catch { completion(.failure(error)) }
}
internal func getXKey(sessionToken: String, merchantID: String, completion: @escaping (Result<ForageXKeyModel, Error>) -> Void) {

func getXKey(sessionToken: String, merchantID: String, completion: @escaping (Result<ForageXKeyModel, Error>) -> Void) {
do { try provider.execute(model: ForageXKeyModel.self, endpoint: ForageAPI.xKey(sessionToken: sessionToken, merchantID: merchantID), completion: completion) } catch { completion(.failure(error)) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ struct ForageErrorSource: Codable {

/// Represents an error that occurs when a request to submit a `ForageElement` to the Forage API fails.
public struct ForageError: Error, Codable, Equatable {
public static func == (lhs: ForageError, rhs: ForageError) -> Bool {
return lhs.code == rhs.code && lhs.httpStatusCode == rhs.httpStatusCode && lhs.message == rhs.message && lhs.details == rhs.details
public static func ==(lhs: ForageError, rhs: ForageError) -> Bool {
lhs.code == rhs.code && lhs.httpStatusCode == rhs.httpStatusCode && lhs.message == rhs.message && lhs.details == rhs.details
}

/// A short string that helps identify the cause of the error.
/// [Learn more about SDK error codes](https://docs.joinforage.app/reference/errors#code-and-message-pairs-1)
///
Expand Down
8 changes: 4 additions & 4 deletions Sources/ForageSDK/Foundation/Network/Model/PaymentModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public struct PaymentModel: Codable {
public let merchantFixedSettlement: String?
public let platformFixedSettlement: String?
public let refunds: [String]
internal let error: VaultError?
let error: VaultError?

private enum CodingKeys: String, CodingKey {
case paymentRef = "ref"
Expand Down Expand Up @@ -112,9 +112,9 @@ public struct PaymentModel: Codable {
/// payment is updated and captured on the server-side.
/// In turn, we only grab what we need from `ThinPaymentModel` for
/// intermediate internal SDK requests to `GET /payments/`
internal struct ThinPaymentModel: Codable {
internal let paymentMethodRef: String
struct ThinPaymentModel: Codable {
let paymentMethodRef: String

private enum CodingKeys: String, CodingKey {
case paymentMethodRef = "payment_method"
}
Expand Down
Loading

0 comments on commit 6dac69d

Please sign in to comment.