VGSCollect

@MainActor
public class VGSCollect : @MainActor VGSCardAttributesLookupService

A collector object that registers secure input fields (VGSTextField) and submits their data/files to a VGS Vault.

Summary: Provides the orchestration layer for secure data collection: field registration, state observation, JSON/body construction, vault/network submission, tokenization/alias creation and file lifecycle management.

Responsibilities:

  • Registers text fields automatically when a VGSConfiguration referencing this collector is assigned.
  • Observes editing state via observeFieldState (focused field) and observeStates (all fields snapshot).
  • Submits values with sendData / sendFile (closure, async/await, Combine variants).
  • Performs tokenization (tokenizeData) and alias creation (createAliases), plus card creation via CMP (createCard).
  • Cleans up attached files after successful upload (cleanFiles).

Security:

  • Never logs or exposes raw sensitive values through public APIs.
  • Avoid adding PII or secrets to customHeaders & fieldName values; use them strictly for routing/auth metadata.
  • Internal storage is transient and cleared/replaced as input changes; persistence is the caller’s responsibility (and should only store aliases).

Usage:

  1. Initialize with vault id & environment: let collector = VGSCollect(id: vaultId, environment: .sandbox).
  2. Create a VGSConfiguration per field and assign to each VGSTextField (registration happens automatically).
  3. Optionally set observation closures for validation/UI updates.
  4. Validate all required fields (state.isValid) before calling a submit method.
  5. Parse response aliases/tokens; discard raw user input from UI components.
  6. After file submission success, call cleanFiles().

Invariants / Preconditions:

  • id must be a non-empty vault identifier.
  • All required fields should be valid before invoking submission APIs.
  • Only one logical file should be attached when calling sendFile.
  • For alias creation (createAliases), appropriate authentication must be provided in customHeaders.
  • UI access (field state collection) occurs on the main thread; ensure you invoke async calls from the main actor when updating UI.

See also:

Custom HTTP Headers

  • A dictionary of custom HTTP header key-value pairs applied to all subsequent network submissions initiated by this collector.

    Purpose: Provide route-specific auth tokens (e.g. Bearer JWT), idempotency or correlation identifiers.

    Security:

    • Never include raw PAN/CVC/SSN or other sensitive user input.

    Declaration

    Swift

    @MainActor
    public var customHeaders: [String : String]? { get set }

Observe VGSTextField states

  • Closure invoked on every editing event for the currently focused VGSTextField.

    Purpose: Supply real-time, field-specific validation feedback or UI updates (e.g. show/hide error label).

    Behavior:

    • Called after input changes or focus transitions.
    • Provides access to textField.state for validation and metadata (e.g. card brand via cast to VGSCardState).

    Usage:

    collector.observeFieldState = { tf in
      if !tf.state.isValid { /* highlight */ }
    }
    

    Declaration

    Swift

    @MainActor
    public var observeFieldState: ((_ textField: VGSTextField) -> Void)?
  • Closure invoked on every editing event with a snapshot array of all registered VGSTextField instances.

    Purpose: Evaluate aggregate form validity or enable/disable a submit button.

    Behavior:

    • Each field’s .state reflects latest formatting & validation outcome.

    Usage:

    collector.observeStates = { fields in
      submitButton.isEnabled = fields.allSatisfy { $0.state.isValid }
    }
    

    Declaration

    Swift

    @MainActor
    public var observeStates: ((_ form: [VGSTextField]) -> Void)?

Get Registered VGSTextFields

  • All text fields currently registered with this collector.

    Registration: Occurs automatically when a VGSConfiguration whose collector is this instance is assigned to a VGSTextField.

    Usage:

    let allValid = collector.textFields.allSatisfy { $0.state.isValid }
    

    Notes: Treat as read-only snapshot; use unsubscribe APIs to remove fields cleanly.

    Declaration

    Swift

    @MainActor
    public var textFields: [VGSTextField] { get }

Initialization

  • Creates a collector bound to a specific vault environment string.

    Parameters:

    • id: Non-empty vault identifier.
    • environment: Environment string (e.g. “sandbox”, “live”, “live-eu1”).
    • hostname: Optional custom hostname override (nil uses default vault routing).

    Preconditions:

    • id should be valid; empty values will lead to failing upstream requests.

    Behavior:

    • Initializes a collector for direct vault-based usage.
    • Tracks a CollectInit analytics event with formType=create.

    Usage:

    let collector = VGSCollect(id: vaultId, environment: "sandbox")
    

    Prefer the convenience initializer for typed environment + region when possible.

    Declaration

    Swift

    @MainActor
    public convenience init(id: String, environment: String, hostname: String? = nil)
  • Convenience initializer composing a regional environment string.

    Parameters:

    • id: Vault identifier.
    • environment: Enumerated environment (.sandbox or .live).
    • dataRegion: Optional region segment (e.g. “eu1”) appended to environment.
    • hostname: Optional custom hostname.

    Usage:

    let collector = VGSCollect(id: vaultId, environment: .live, dataRegion: "eu1")
    

    Declaration

    Swift

    @MainActor
    public convenience init(id: String, environment: Environment = .sandbox, dataRegion: String? = nil, hostname: String? = nil)

Async Factory

  • Asynchronously configures and initializes a VGSCollect instance.

    This method:

    1. Validates the provided form name.
    2. Loads the Form Configuration from the backend.
    3. Applies remote configuration, or caller-provided inline configuration when the remote configuration is unavailable.

    Behavior:

    • Valid remote configuration takes precedence over inline configuration.
    • A remote configuration failure is reported through onError; completion still receives a usable collector configured from the inline fallback when available.
    • Invalid form names remain terminal and are returned through completion as failures.

    Error Mapping:

    Usage:

    VGSCollect.session(with: formId, vaultId: vaultId, environment: .sandbox, dataRegion: nil) { result in
      switch result {
      case .success(let collector):
        self.collector = collector
      case .failure(_, _, _, let error):
        self.errorText = error?.localizedDescription
      }
    }
    

    Declaration

    Swift

    @MainActor
    public static func session(with form: String,
                               vaultId: String,
                               environment: Environment = .sandbox,
                               dataRegion: String? = nil,
                               completion: @escaping (VGSCollectSessionResponse) -> Void)

    Parameters

    form

    The unique Form Name.

    vaultId

    Vault identifier.

    environment

    The environment (e.g., “sandbox”, “live”).

    dataRegion

    Optional data region appended to the environment string.

    configuration

    Optional inline Form Configuration config object used only when remote configuration cannot be loaded.

    onError

    Optional callback for remote configuration loading errors.

    completion

    A closure returning VGSCollectSessionResponse.

  • Initializes a session collector with an optional inline fallback Form Configuration.

    Remote configuration takes precedence. If it cannot be loaded, onError receives the load error and the collector uses configuration when supplied.

    Declaration

    Swift

    @MainActor
    public static func session(with form: String,
                               vaultId: String,
                               environment: Environment = .sandbox,
                               dataRegion: String? = nil,
                               configuration: [String: Any]?,
                               onError: ((Error) -> Void)? = nil,
                               completion: @escaping (VGSCollectSessionResponse) -> Void)

Manage VGSTextFields

  • Returns the first registered field matching a given fieldName.

    Parameter:

    Returns:

    • VGSTextField? found or nil if no match.

    Usage:

    if let cardField = collector.getTextField(fieldName: "card_number"), cardField.state.isValid { /* ... */ }
    

    Declaration

    Swift

    @MainActor
    public func getTextField(fieldName: String) -> VGSTextField?
  • Unregisters a single text field from this collector.

    Parameter:

    • textField: Field instance to detach.

    Effects:

    • Field is excluded from future submissions and observation callbacks.

    Usage:

    collector.unsubscribeTextField(nameField)
    

    Declaration

    Swift

    @MainActor
    public func unsubscribeTextField(_ textField: VGSTextField)
  • Unregisters multiple text fields.

    Parameter:

    • textFields: Array of field instances to detach.

    Usage:

    collector.unsubscribeTextFields([cardField, expField])
    

    Declaration

    Swift

    @MainActor
    public func unsubscribeTextFields(_ textFields: [VGSTextField])
  • Unregisters all currently registered text fields.

    Purpose: Simplify form teardown (e.g. view controller disappearing) to prevent accidental resubmission.

    Usage:

    collector.unsubscribeAllTextFields()
    

    Declaration

    Swift

    @MainActor
    public func unsubscribeAllTextFields()

Manage Files

  • Detaches all selected/attached files from this collector.

    Purpose: Free ephemeral memory and avoid unintended re-use of stale file data after successful upload or cancellation.

    Behavior: Safe to call multiple times; subsequent invocations are no-ops once files are cleared.

    Usage:

    collector.sendFile(path: "/post") { resp in
      if case .success = resp { collector.cleanFiles() }
    }
    

    Declaration

    Swift

    @MainActor
    public func cleanFiles()

Card Attributes Lookup Callbacks

  • Callback invoked immediately before the SDK starts the asynchronous card attributes lookup.

    Triggered when the user types the 11th digit in a field with configuration.type = .cardNumber. Use this to update your UI state (e.g., disable submit button, show spinner).

    Declaration

    Swift

    @MainActor
    public var willBeginCardAttributesLookup: (() -> Void)?
  • Callback invoked when attributes are successfully parsed from a successful lookup response.

    Use this convenience callback to populate UI with bank logos, card type labels, etc. For raw response bytes, use cardAttributesLookupResponse.

    Declaration

    Swift

    @MainActor
    public var didRetrieveCardAttributes: (([String : Any]) -> Void)?

    Parameters

    attributes

    Parsed lookup payload object.

  • Callback invoked when the lookup request completes.

    Use this when you need the raw HTTP response data for both success and failure cases.

    Declaration

    Swift

    @MainActor
    public var cardAttributesLookupResponse: ((VGSCardAttributesLookupResponse) -> Void)?

    Parameters

    response

    Raw lookup response result.

  • Callback invoked when the attributes lookup fails.

    Follows the same payload shape as VGSResponse.failure(code, data, response, error).

    Declaration

    Swift

    @MainActor
    public var didFailToRetrieveCardAttributes: ((Int, Data?, URLResponse?, Error?) -> Void)?
  • Callback to request a fresh JWT token for VGS API authentication.

    The SDK calls this when it needs to authenticate the lookup request. You must call the provided completion block with your token or an error.

    Declaration

    Swift

    @MainActor
    public var authHandler: ((_ completion: @escaping (Result<String, Error>) -> Void) -> Void)?

CMP create card

  • Creates a card through CMP using authHandler and the in-memory JWT cache.

    Declaration

    Swift

    @MainActor
    public func createCard(extraData: [String: Any]? = nil,
                           completion block: @escaping (VGSResponse) -> Void)

    Parameters

    extraData

    Additional CMP card attributes. Supply the contents of data.attributes; the SDK adds the JSON:API envelope. Attribute names and value types must match the Card Management API schema or CMP can return a 4xx response.

  • Creates a card through CMP using an explicit access token.

    Declaration

    Swift

    @MainActor
    public func createCard(token: String,
                           extraData: [String: Any]? = nil,
                           completion block: @escaping (VGSResponse) -> Void)

    Parameters

    token

    Card Management API access token.

    extraData

    Additional CMP card attributes. Supply the contents of data.attributes; the SDK adds the JSON:API envelope. Attribute names and value types must match the Card Management API schema or CMP can return a 4xx response.

CMP update card

Send data

Tokenization(Vault API) requests

VGSCollect + async

VGSCollect + Combine