From 587d706fc5ed120cc53d8d6fcd78190dbaea7e4f Mon Sep 17 00:00:00 2001 From: Daniel Kift Date: Tue, 19 May 2026 15:14:34 +0100 Subject: [PATCH] parse all error messages --- platforms/android/lib/api/lib.api | 31 ------------------- .../shopify/checkoutkit/CheckoutProtocol.kt | 16 +++------- .../checkoutkit/CheckoutProtocolTest.kt | 20 +++++++++--- 3 files changed, 19 insertions(+), 48 deletions(-) diff --git a/platforms/android/lib/api/lib.api b/platforms/android/lib/api/lib.api index 246dc1fb..0d60d3fc 100644 --- a/platforms/android/lib/api/lib.api +++ b/platforms/android/lib/api/lib.api @@ -633,37 +633,6 @@ public abstract interface class com/shopify/checkoutkit/CheckoutCommunicationCli public abstract fun process (Ljava/lang/String;)Ljava/lang/String; } -public final class com/shopify/checkoutkit/CheckoutError { - public static final field Companion Lcom/shopify/checkoutkit/CheckoutError$Companion; - public fun ()V - public final fun component1 ()Ljava/lang/String; - public final fun component2 ()Ljava/lang/String; - public final fun component3 ()Ljava/lang/String; - public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lcom/shopify/checkoutkit/CheckoutError; - public static synthetic fun copy$default (Lcom/shopify/checkoutkit/CheckoutError;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lcom/shopify/checkoutkit/CheckoutError; - public fun equals (Ljava/lang/Object;)Z - public final fun getCode ()Ljava/lang/String; - public final fun getContent ()Ljava/lang/String; - public final fun getSeverity ()Ljava/lang/String; - public fun hashCode ()I - public fun toString ()Ljava/lang/String; -} - -public final class com/shopify/checkoutkit/CheckoutError$$serializer : kotlinx/serialization/internal/GeneratedSerializer { - public static final field INSTANCE Lcom/shopify/checkoutkit/CheckoutError$$serializer; - public fun childSerializers ()[Lkotlinx/serialization/KSerializer; - public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lcom/shopify/checkoutkit/CheckoutError; - public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; - public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; - public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lcom/shopify/checkoutkit/CheckoutError;)V - public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V - public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer; -} - -public final class com/shopify/checkoutkit/CheckoutError$Companion { - public final fun serializer ()Lkotlinx/serialization/KSerializer; -} - public abstract class com/shopify/checkoutkit/CheckoutException : java/lang/Exception { public static final field Companion Lcom/shopify/checkoutkit/CheckoutException$Companion; public synthetic fun (ILjava/lang/String;Ljava/lang/String;ZLkotlinx/serialization/internal/SerializationConstructorMarker;)V diff --git a/platforms/android/lib/src/main/java/com/shopify/checkoutkit/CheckoutProtocol.kt b/platforms/android/lib/src/main/java/com/shopify/checkoutkit/CheckoutProtocol.kt index 133675ba..81772024 100644 --- a/platforms/android/lib/src/main/java/com/shopify/checkoutkit/CheckoutProtocol.kt +++ b/platforms/android/lib/src/main/java/com/shopify/checkoutkit/CheckoutProtocol.kt @@ -67,14 +67,14 @@ public object CheckoutProtocol { public val lineItemsChange: NotificationDescriptor = checkoutDescriptor("ec.line_items.change") internal val buyerChange: NotificationDescriptor = checkoutDescriptor("ec.buyer.change") public val totalsChange: NotificationDescriptor = checkoutDescriptor("ec.totals.change") - public val error: NotificationDescriptor = NotificationDescriptor( + public val error: NotificationDescriptor = NotificationDescriptor( method = "ec.error", decode = { params -> - params?.jsonObject?.get("messages")?.let { + params?.jsonObject?.get("error")?.let { try { - json.decodeFromJsonElement>(it).firstOrNull() + json.decodeFromJsonElement(it) } catch (e: Exception) { - log.d(BaseWebView.ECP_LOG_TAG, "Failed to decode ec.error messages: $e raw=$it") + log.d(BaseWebView.ECP_LOG_TAG, "Failed to decode ec.error params: $e raw=$it") null } } @@ -320,14 +320,6 @@ internal sealed class WindowOpenResult { data class Rejected(val reason: String? = null) : WindowOpenResult() } -/** Payload delivered with the [CheckoutProtocol.error] notification. */ -@Serializable -public data class CheckoutError internal constructor( - public val code: String? = null, - public val content: String? = null, - public val severity: String? = null, -) - // UCP wire envelopes for delegation responses. Mirror Swift's UCPSuccess / UCPError / // WindowOpenRejectedBody (origin/swift/window.open_request: ShopifyCheckoutProtocol/Codec.swift + // WindowOpen.swift). UcpEnvelope / UcpMessage are intentionally generic so the next delegation diff --git a/platforms/android/lib/src/test/java/com/shopify/checkoutkit/CheckoutProtocolTest.kt b/platforms/android/lib/src/test/java/com/shopify/checkoutkit/CheckoutProtocolTest.kt index 22a3c104..61e85376 100644 --- a/platforms/android/lib/src/test/java/com/shopify/checkoutkit/CheckoutProtocolTest.kt +++ b/platforms/android/lib/src/test/java/com/shopify/checkoutkit/CheckoutProtocolTest.kt @@ -135,18 +135,28 @@ class CheckoutProtocolTest { @Test fun `process dispatches ec error to registered handler with decoded payload`() { - var received: CheckoutError? = null + var received: ErrorResponse? = null val client = CheckoutProtocol.Client() .on(CheckoutProtocol.error) { received = it } val errorMsg = """{"jsonrpc":"2.0","method":"ec.error","params":""" + - """{"messages":[{"code":"unknown_error","content":"fail","severity":"unrecoverable"}]}}""" + """{"error":{"ucp":{"version":"2026-04-08","status":"error"},"messages":[""" + + """{"type":"error","code":"unknown_error","content":"fail","severity":"unrecoverable"},""" + + """{"type":"error","code":"session_expired","content":"expired","severity":"recoverable"}""" + + """],"continue_url":"https://example.com/retry"}}}""" client.process(errorMsg) shadowOf(Looper.getMainLooper()).runToEndOfTasks() - assertThat(received?.code).isEqualTo("unknown_error") - assertThat(received?.content).isEqualTo("fail") - assertThat(received?.severity).isEqualTo("unrecoverable") + assertThat(received?.ucp?.version).isEqualTo("2026-04-08") + assertThat(received?.ucp?.status).isEqualTo(StatusEnum.Error) + assertThat(received?.messages).hasSize(2) + assertThat(received?.messages?.get(0)?.type).isEqualTo(MessageType.Error) + assertThat(received?.messages?.get(0)?.code).isEqualTo("unknown_error") + assertThat(received?.messages?.get(0)?.content).isEqualTo("fail") + assertThat(received?.messages?.get(0)?.severity).isEqualTo(Severity.Unrecoverable) + assertThat(received?.messages?.get(1)?.code).isEqualTo("session_expired") + assertThat(received?.messages?.get(1)?.severity).isEqualTo(Severity.Recoverable) + assertThat(received?.continueURL).isEqualTo("https://example.com/retry") } @Test