diff --git a/.changeset/early-olives-explode.md b/.changeset/early-olives-explode.md new file mode 100644 index 000000000..be6e51f5b --- /dev/null +++ b/.changeset/early-olives-explode.md @@ -0,0 +1,5 @@ +--- +"@onflow/fcl": patch +--- + +Fix version normalization of services in FCL diff --git a/packages/fcl/src/current-user/build-user.js b/packages/fcl/src/current-user/build-user.js index 9889c5f2c..eee5358fb 100644 --- a/packages/fcl/src/current-user/build-user.js +++ b/packages/fcl/src/current-user/build-user.js @@ -4,6 +4,7 @@ import {fetchServices} from "./fetch-services" import {mergeServices} from "./merge-services" import {USER_PRAGMA} from "../normalizers/service/__vsn" import {normalizeService} from "../normalizers/service/service" +import {serviceOfType} from "./service-of-type" function deriveCompositeId(authn) { return rlp @@ -20,10 +21,6 @@ function normalizeData(data) { return data } -function findService(type, services) { - return services.find(d => d.type === type) -} - export async function buildUser(data) { data = normalizeData(data) @@ -34,7 +31,7 @@ export async function buildUser(data) { .map(service => normalizeService(service, data)) .filter(Boolean) - const authn = findService("authn", services) + const authn = serviceOfType(services, "authn") return { ...USER_PRAGMA, diff --git a/packages/fcl/src/current-user/service-of-type.js b/packages/fcl/src/current-user/service-of-type.js index 6347236d8..28ef5c3b6 100644 --- a/packages/fcl/src/current-user/service-of-type.js +++ b/packages/fcl/src/current-user/service-of-type.js @@ -1,3 +1,30 @@ +import {invariant} from "@onflow/util-invariant" + +function compareVersions(a, b) { + function helper(a, b) { + if (a.length === 0) return 0 + if (a[0] > b[0]) return true + if (a[0] < b[0]) return false + return helper(a.slice(1), b.slice(1)) + } + const aVsn = a.split(".") + const bVsn = b.split(".") + + invariant(aVsn.length === 3, "Invalid version: " + a) + invariant(bVsn.length === 3, "Invalid version: " + b) + + return helper(a.split("."), b.split(".")) +} + export function serviceOfType(services = [], type) { - return services.find(service => service.type === type) + // Find the greatest version of the service type + return services.reduce( + (service, mostRecent) => + !mostRecent || + (service.type === type && + compareVersions(service.f_vsn, mostRecent.f_vsn)) + ? service + : mostRecent, + null + ) }