Files
amethyst/gradle
Claude fa3287f737 fix(quartz): match java.net.URLEncoder on native; drop the urlencoder dep
Both native targets delegated UrlEncoder to
net.thauvin.erik.urlencoder.UrlEncoderUtil, which implements RFC 3986
percent-encoding. The JVM/Android actual is java.net.URLEncoder/URLDecoder,
which implements application/x-www-form-urlencoded. Different specifications,
and the difference was observable:

                      JVM/Android    UrlEncoderUtil
  encode(" ")         "+"            "%20"
  encode("*")         "*"            "%2A"
  decode("a+b")       "a b"          "a+b"

This is not cosmetic. encode() builds strings that leave the device —
TorrentEvent puts it in magnet links, Nip54InlineMetadata in inline metadata,
Nip47DeepLink in the callback/appname/value parameters of NWC deep links — so
Android and iOS emitted different bytes for the same title. The decode row is
worse: a link written by Android carries '+' for its spaces, and reading it on
iOS or desktop-native gave back literal plus signs, silently, with no error.

Replaced with one UrlEncoder.native.kt in nativeMain, shared by linuxX64 and
every Apple target, matching URLEncoder/URLDecoder exactly — unreserved set is
alphanumerics plus -_.* (note '*' survives and '~' does not, the opposite of
RFC 3986), space to '+', uppercase %XX of UTF-8 bytes otherwise, and '+' back
to space on the way in. Escape runs are encoded and decoded as runs so surrogate
pairs and multi-byte sequences survive, and both directions short-circuit on a
string with nothing to change, as the java.net pair does.

UriParser.linux now delegates to UrlEncoder.decode rather than carrying its own
copy of the decoder added in the previous commit.

The new UrlEncoderTest lives in commonTest, so it pins every target against the
JVM's answers — it is what found all three rows above, by passing on jvmTest and
failing three of ten on linuxX64.

net.thauvin.erik:urlencoder-lib had no other user and is removed from both
source sets and the version catalog.

One deliberate edge difference from the JVM, documented at the call site: an
unpaired UTF-16 surrogate encodes as %EF%BF%BD rather than %3F.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HxQ1QuyzSkR38iFHbREjoS
2026-09-01 19:38:00 +00:00
..