Skip to content

[Swift] Make protocol agnostic to usage#307

Open
markmur wants to merge 7 commits into
mainfrom
agnostic-protocol-refactor
Open

[Swift] Make protocol agnostic to usage#307
markmur wants to merge 7 commits into
mainfrom
agnostic-protocol-refactor

Conversation

@markmur

@markmur markmur commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

The protocol/ package previously baked in opinions about which checkout events matter and how their payloads should be shaped, so every platform inherited the same curation and any tweak rippled through the shared layer. This splits the concerns: protocol/ becomes purely agnostic — transport (EmbeddedCheckoutProtocol, renamed from CheckoutProtocol), the full generated payload types, and a generated catalog of events, describing every OpenRPC method with no view on which surface — while each platform's CheckoutKit now owns curation and consumer-facing transformation. Swift's kit reclaims the CheckoutProtocol name as its curated namespace, exposing the six ec.* events plus window.open and rejecting everything else with a JSON-RPC method-not-found response.

Look at platforms/swift/Sources/ShopifyCheckoutKit/CheckoutProtocol.swift for the curation surface and run the Swift suite — CheckoutProtocolTests covers supported/unsupported method handling and window.open delegation.

Before — protocol/ owns the curation

// protocol/.../ShopifyCheckoutProtocol/CheckoutProtocol.swift
public enum CheckoutProtocol {
    public static let specVersion = "2026-04-08"
    public static let complete = NotificationDescriptor<Checkout>(method: "ec.complete")
    public static let start = NotificationDescriptor<Checkout>(method: "ec.start")
    // ...the rest of the curated events...

    package static let supportedProtocolMethods: Set<String> = [
        readyMethod, start.method, complete.method, error.method,
        lineItemsChange.method, messagesChange.method, totalsChange.method,
        windowOpen.method
    ]
    package static func methodNotFoundResponse(forUnsupportedProtocolRequest:) -> String? { ... }
}

After — protocol/ is agnostic, the kit curates

// protocol/ now only exposes transport + generated types:
//   EmbeddedCheckoutProtocol (transport), GeneratedProtocolCatalog (every method, uncurated)

// platforms/swift/.../ShopifyCheckoutKit/CheckoutProtocol.swift
public enum CheckoutProtocol {
    public typealias Client = EmbeddedCheckoutProtocol.Client

    public static let complete = EmbeddedCheckoutProtocol.Event.complete
    public static let start = EmbeddedCheckoutProtocol.Event.start
    // ...the six curated ec.* events...

    static let supportedProtocolMethods: Set<String> = [
        EmbeddedCheckoutProtocol.readyMethod,
        start.method, complete.method, error.method,
        lineItemsChange.method, messagesChange.method, totalsChange.method,
        windowOpen.method
    ]
    static func methodNotFoundResponse(forUnsupportedProtocolRequest:) -> String? { ... }
}

Call sites move from baked-in defaults to explicit curation

// Before
CheckoutProtocol.url(for: url)

// After — the kit passes its own curated delegations into the agnostic transport
EmbeddedCheckoutProtocol.url(for: url, delegations: CheckoutProtocol.defaultDelegations)

Comment on lines +51 to +58
epCartReady.method,
epCartAuth.method,
epCartError.method,
epCartStart.method,
epCartComplete.method,
epCartLineItemsChange.method,
epCartBuyerChange.method,
epCartMessagesChange.method,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

TBD on whether these events should be part of the generated API surface. They're part of the spec so arguably they should.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've dropped them. The EmbeddedCheckoutProtocol should only be concerned with ec events. We might consider adding an EmbeddedCartProtocol submodule later for ep events if needed

Comment on lines -1 to -34
import Foundation

public enum CheckoutProtocol {
public static let specVersion = "2026-04-08"

public static let defaultDelegations: [String] = ["window.open"]

package static let readyMethod = "ec.ready"
package static let parseErrorCode = -32700
package static let parseErrorMessage = "Parse error"
package static let methodNotFoundCode = -32601
package static let methodNotFoundMessage = "Method not found"

public static let complete = NotificationDescriptor<Checkout>(method: "ec.complete")
public static let error = NotificationDescriptor<ErrorResponse>(method: "ec.error")
public static let lineItemsChange = NotificationDescriptor<Checkout>(
method: "ec.line_items.change"
)
public static let messagesChange = NotificationDescriptor<Checkout>(
method: "ec.messages.change"
)
public static let start = NotificationDescriptor<Checkout>(method: "ec.start")
public static let totalsChange = NotificationDescriptor<Checkout>(method: "ec.totals.change")

package static let supportedProtocolMethods: Set<String> = [
readyMethod,
start.method,
complete.method,
error.method,
lineItemsChange.method,
messagesChange.method,
totalsChange.method,
windowOpen.method
]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This change lifts the curation out of the protocol into the kit - since that's where the abstraction should live

@markmur markmur force-pushed the agnostic-protocol-refactor branch from 9b8bfaf to a5da2b9 Compare June 19, 2026 11:22
@markmur markmur marked this pull request as ready for review June 22, 2026 08:24
@markmur markmur requested a review from a team as a code owner June 22, 2026 08:24
@github-actions

github-actions Bot commented Jun 22, 2026

Copy link
Copy Markdown

React Native — Coverage Report

Lines Statements Branches Functions
Coverage: 92%
91.66% (319/348) 87.86% (181/206) 100% (82/82)

@markmur markmur marked this pull request as draft June 22, 2026 09:02
@markmur markmur changed the title Make protocol agnostic to usage [Draft] Make protocol agnostic to usage Jun 22, 2026
@markmur markmur self-assigned this Jun 22, 2026
@markmur markmur marked this pull request as ready for review June 22, 2026 09:37
@markmur

markmur commented Jun 22, 2026

Copy link
Copy Markdown
Contributor Author

Marking as ready for review to run CI

@markmur markmur force-pushed the agnostic-protocol-refactor branch from e27325e to 4aa6560 Compare June 22, 2026 09:51
Comment on lines +6 to +34
public enum CheckoutProtocol {
public typealias Client = CheckoutTransport.Client

public static func url(for url: URL) -> URL {
CheckoutTransport.url(for: url, delegations: defaultDelegations)
}

static let defaultDelegations: [String] = ["window.open"]

static let methodNotFoundCode = -32601
static let methodNotFoundMessage = "Method not found"

public static let complete = GeneratedProtocolCatalog.ecComplete
public static let error = GeneratedProtocolCatalog.ecError
public static let lineItemsChange = GeneratedProtocolCatalog.ecLineItemsChange
public static let messagesChange = GeneratedProtocolCatalog.ecMessagesChange
public static let start = GeneratedProtocolCatalog.ecStart
public static let totalsChange = GeneratedProtocolCatalog.ecTotalsChange

static let supportedProtocolMethods: Set<String> = [
CheckoutTransport.readyMethod,
start.method,
complete.method,
error.method,
lineItemsChange.method,
messagesChange.method,
totalsChange.method,
windowOpen.method
]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is essentially a facade which curates the set of supported events and lives in the kit itself

@github-actions

github-actions Bot commented Jun 22, 2026

Copy link
Copy Markdown

Package Size

Platform Artifact Base Head Delta
Android release AAR 613.4 KiB 613.4 KiB 0 B

Measured from the PR base SHA and PR head SHA. This comment reports package artifact sizes only; it is not a final app binary-size report.

/// Returns the given checkout URL with the query parameters required to
/// initiate the Embedded Checkout Protocol handshake (`ec_version`,
/// `ec_delegate`).
public static func url(
for url: URL,
delegations: [String] = defaultDelegations
delegations: [String] = []

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

CheckoutProtocol now uses this under the hood and supplies the defaults in the kit. This function is constrained to the package

@markmur markmur force-pushed the agnostic-protocol-refactor branch 2 times, most recently from 2403a3c to 979df1e Compare June 22, 2026 13:13
@markmur markmur force-pushed the agnostic-protocol-refactor branch from 979df1e to c8cf90e Compare June 22, 2026 13:14
@markmur markmur force-pushed the agnostic-protocol-refactor branch from 214a61f to ff95bae Compare June 22, 2026 13:27
@markmur markmur changed the title [Draft] Make protocol agnostic to usage [Swift] Make protocol agnostic to usage Jun 22, 2026
@markmur markmur requested review from kiftio and westeezy June 22, 2026 15:25
Comment on lines +3 to 27
public enum EmbeddedCheckoutProtocol {
public static let specVersion = "2026-04-08"

package static let readyMethod = "ec.ready"
package static let parseErrorCode = -32700
package static let parseErrorMessage = "Parse error"

/// Returns the given checkout URL with the query parameters required to
/// initiate the Embedded Checkout Protocol handshake (`ec_version`,
/// `ec_delegate`).
public static func url(
for url: URL,
delegations: [String] = defaultDelegations
delegations: [String] = []
) -> URL {
guard var components = URLComponents(url: url, resolvingAgainstBaseURL: false) else {
return url
}
var queryItems = components.queryItems ?? []
queryItems.removeAll { $0.name == "ec_version" || $0.name == "ec_delegate" }

queryItems.append(URLQueryItem(name: "ec_version", value: specVersion))
if !delegations.isEmpty {
queryItems.append(URLQueryItem(name: "ec_delegate", value: delegations.joined(separator: ",")))
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Heads up that I'm going to add support for ec_auth and ec_color_scheme here in a follow-up so that non-kit consumers can use the fully compliant protocol

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant