Skip to content

refactor: SDK existing file modifications for CheckoutComponents#1632

Open
bthebladeprimer wants to merge 7 commits into
bn/feature/cc-02-di-containerfrom
bn/feature/cc-03-sdk-refactors
Open

refactor: SDK existing file modifications for CheckoutComponents#1632
bthebladeprimer wants to merge 7 commits into
bn/feature/cc-02-di-containerfrom
bn/feature/cc-03-sdk-refactors

Conversation

@bthebladeprimer
Copy link
Copy Markdown
Contributor

Summary

  • Modifies 89 existing SDK files to support CheckoutComponents integration
  • Adds accessibility modifiers, new API endpoints, and protocol conformances needed by CheckoutComponents
  • Extends error handling, analytics, and data models with CheckoutComponents-specific cases
  • Updates Debug App with CheckoutComponents integration points
  • Adds new test files for DI, secure memory wipe, cache keys, and mock utilities

Context

PR 3 of 15 in the CheckoutComponents feature split. This is the highest-risk PR as it touches existing SDK files across the codebase. Depends on PR 2 (#1631).

Tracker: https://www.notion.so/32fca65dc30e81dabf66f33e2b58c3a1

Test plan

  • Verify existing unit tests pass with modifications
  • Review all 89 modified files for unintended changes
  • Confirm new test files compile and pass
  • Verify no breaking changes to public API surface
  • Run full test suite: xcodebuild -workspace PrimerSDK.xcworkspace -scheme PrimerSDKTests -destination "platform=iOS Simulator,name=iPhone 16" test

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 26, 2026

Warnings
⚠️ > Pull Request size seems relatively large. If this Pull Request contains multiple changes, please split each into separate PR will helps faster, easier review.

Generated by 🚫 Danger Swift against 9c8d8ab

@bthebladeprimer bthebladeprimer self-assigned this Mar 26, 2026
@bthebladeprimer bthebladeprimer marked this pull request as draft March 26, 2026 16:31
@bthebladeprimer bthebladeprimer marked this pull request as ready for review April 3, 2026 18:09
)
)

// Note: v3.0 breaking change — Mastercard formatting changed from [4, 10]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious where this change came from - product-led or something uncovered during development?

/// ```
/// - Note: **v3.0 breaking change**: This enum is now `public`. All cases are part of the
/// public API contract — no cases can be removed or renamed without a breaking change.
public enum PrimerPaymentMethodType: String, Codable, CaseIterable, Equatable, Hashable {
Copy link
Copy Markdown

@nquinn-primer nquinn-primer Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the rationale behind making this public?

I dont believe this is an exhaustive list due to how WEB_REDIRECT payment methods work, payment methods can be added and will work with the SDK without additions here. cc @henry-cooper-primer for a sense-check in case my worldview is out of date.

If it is not an exhaustive list of supported payment methods, it may be confusing to a merchant if exposed

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would also add that allowing the posibility for this to be extended by the merchant could cause unknown headaches

extension URLSession: URLSessionProtocol {}

final class DefaultRequestDispatcher: RequestDispatcher, LogReporter {
final class DefaultRequestDispatcher: RequestDispatcher, @unchecked Sendable, LogReporter {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@unchecked here makes me nervous. Why is it needed? I would like to see unit tests which test multi-threaded behaviour if we need it, I worry about races/crashes if this runs on multiple threads.

return text.contains("@") && text.contains(".")
default:
return true
return false
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A latent bug, or was this required because the cases were not exhaustive before?

DispatchQueue.main.async {
rawDataManager.delegate?.primerRawDataManager?(
rawDataManager,
metadataDidChange: ["cardNetwork": self.cardNetwork.rawValue]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

metadataDidChange is deprecated, but here we stop sending data there. I would say either remove it, or send to both until removed

Copy link
Copy Markdown

@nquinn-primer nquinn-primer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work, added some comments

@@ -298,70 +336,55 @@ extension MerchantHeadlessCheckoutRawDataViewController: PrimerHeadlessUniversal
let printableNetworks = metadata.detectedCardNetworks.items.map(\.network.rawValue).joined(separator: ", ")
print("[MerchantHeadlessCheckoutRawDataViewController] didReceiveCardMetadata: \(printableNetworks) forCardValidationState: \(cardState.cardNumber)")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldnt be exposing the unexposed cardnumber for PCI reasons. Can you check if we ever did this before with PrimerValidationState - is it something new in PrimerCardNumberEntryState?

.cvv,
.otp,
.phoneNumber:
case .cardNumber, .expiryDate, .cvv, .otp, .phoneNumber, .postalCode:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.postalCode has moved from .alphabet to .numberPad. This will cause issues in many countries where postalCode is not only numeric

return true
}

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DeepLink support removed? Is this intended?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it is handled elsewhere, then please make sure to test all redirect methods and E2E tests which rely on this

///
/// You can enable multiple dismissal mechanisms by passing an array to `PrimerUIOptions`.
/// For example, `[.gestures, .closeButton]` allows both swipe gestures and a close button.
public enum DismissalMechanism: String, Codable {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A breaking change - fine since we are going to 3.0 but we will need to keep track of these public breaking changes for the future CHANGELOG

case .firstName, .lastName:
return text.isValidNonDecimalString
case .email:
return text.contains("@") && text.contains(".")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we can use a more robust email regex - I would suggest aligning across platforms


/// Human-readable field name for display
var displayName: String {
switch self {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these display names be pulling from Localized strings?

return imgView
}

if Thread.isMainThread {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this required since the function is @mainactor?

XCTAssertEqual(report.recommendations.count, 2)
}

// MARK: - printDetailedReport / printReport Tests
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests are deleted but these code paths still exist in production. Intended?

@bthebladeprimer bthebladeprimer force-pushed the bn/feature/cc-02-di-container branch from 637b7c4 to 01baa63 Compare April 15, 2026 12:59
@bthebladeprimer bthebladeprimer force-pushed the bn/feature/cc-03-sdk-refactors branch from 2e87ec4 to 9c8d8ab Compare April 15, 2026 12:59
(internalText ?? "").isEmpty
}

func wipe() {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This leaves data behind in memory since utf8CString returns a copy - I wonder is now a good time to resolve this and work towards killing this VULN ticket at the same time cc @marjaimate

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants