fix(desktop): derive MAS review state from OTA versions
This commit is contained in:
parent
34fd039ff9
commit
5aba30eb4f
|
|
@ -4,6 +4,7 @@ import PKG from "@pkg"
|
|||
import { atomWithStorage } from "jotai/utils"
|
||||
|
||||
import { createAtomHooks } from "~/lib/jotai"
|
||||
import { isLocalMASVersionInReview } from "~/lib/mas-review"
|
||||
|
||||
export const [, , useServerConfigs, , getServerConfigs, setServerConfigs] = createAtomHooks(
|
||||
atomWithStorage<Nullable<ExtractResponseData<GetStatusConfigsResponse>>>(
|
||||
|
|
@ -16,26 +17,32 @@ export const [, , useServerConfigs, , getServerConfigs, setServerConfigs] = crea
|
|||
),
|
||||
)
|
||||
|
||||
export const [, , useMASStoreVersion, , getMASStoreVersion, setMASStoreVersion] = createAtomHooks(
|
||||
atomWithStorage<null | string>(getStorageNS("mas-store-version"), null, undefined, {
|
||||
getOnInit: true,
|
||||
}),
|
||||
)
|
||||
|
||||
export type ServerConfigs = ExtractResponseData<GetStatusConfigsResponse>
|
||||
export type PaymentPlan = ServerConfigs["PAYMENT_PLAN_LIST"][number]
|
||||
export type PaymentFeature = PaymentPlan["limit"]
|
||||
|
||||
export const useIsInMASReview = () => {
|
||||
const serverConfigs = useServerConfigs()
|
||||
return (
|
||||
typeof process !== "undefined" &&
|
||||
process.mas &&
|
||||
serverConfigs?.MAS_IN_REVIEW_VERSION === PKG.version
|
||||
)
|
||||
const masStoreVersion = useMASStoreVersion()
|
||||
return isLocalMASVersionInReview({
|
||||
isMASBuild: typeof process !== "undefined" && !!process.mas,
|
||||
localVersion: PKG.version,
|
||||
storeVersion: masStoreVersion,
|
||||
})
|
||||
}
|
||||
|
||||
export const getIsInMASReview = () => {
|
||||
const serverConfigs = getServerConfigs()
|
||||
return (
|
||||
typeof process !== "undefined" &&
|
||||
process.mas &&
|
||||
serverConfigs?.MAS_IN_REVIEW_VERSION === PKG.version
|
||||
)
|
||||
const masStoreVersion = getMASStoreVersion()
|
||||
return isLocalMASVersionInReview({
|
||||
isMASBuild: typeof process !== "undefined" && !!process.mas,
|
||||
localVersion: PKG.version,
|
||||
storeVersion: masStoreVersion,
|
||||
})
|
||||
}
|
||||
|
||||
export const useIsPaymentEnabled = () => {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
import { describe, expect, it } from "vitest"
|
||||
|
||||
import { getMASStoreVersionFromOTAVersions, isLocalMASVersionInReview } from "../mas-review"
|
||||
|
||||
describe("getMASStoreVersionFromOTAVersions", () => {
|
||||
it("reads the MAS version from the OTA payload", () => {
|
||||
expect(
|
||||
getMASStoreVersionFromOTAVersions({
|
||||
store: {
|
||||
desktop: {
|
||||
mas: {
|
||||
version: "1.6.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
).toBe("1.6.0")
|
||||
})
|
||||
|
||||
it("returns null when the OTA payload has no MAS version", () => {
|
||||
expect(getMASStoreVersionFromOTAVersions({})).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe("isLocalMASVersionInReview", () => {
|
||||
it("returns true when the local MAS build is newer than the store version", () => {
|
||||
expect(
|
||||
isLocalMASVersionInReview({
|
||||
isMASBuild: true,
|
||||
localVersion: "1.6.1",
|
||||
storeVersion: "1.6.0",
|
||||
}),
|
||||
).toBe(true)
|
||||
})
|
||||
|
||||
it("returns false when the local version matches the store version", () => {
|
||||
expect(
|
||||
isLocalMASVersionInReview({
|
||||
isMASBuild: true,
|
||||
localVersion: "1.6.1",
|
||||
storeVersion: "1.6.1",
|
||||
}),
|
||||
).toBe(false)
|
||||
})
|
||||
|
||||
it("returns false when the build is not a MAS build", () => {
|
||||
expect(
|
||||
isLocalMASVersionInReview({
|
||||
isMASBuild: false,
|
||||
localVersion: "1.6.1",
|
||||
storeVersion: "1.6.0",
|
||||
}),
|
||||
).toBe(false)
|
||||
})
|
||||
|
||||
it("returns false when the store version is missing or invalid", () => {
|
||||
expect(
|
||||
isLocalMASVersionInReview({
|
||||
isMASBuild: true,
|
||||
localVersion: "1.6.1",
|
||||
storeVersion: null,
|
||||
}),
|
||||
).toBe(false)
|
||||
|
||||
expect(
|
||||
isLocalMASVersionInReview({
|
||||
isMASBuild: true,
|
||||
localVersion: "1.6.1",
|
||||
storeVersion: "latest",
|
||||
}),
|
||||
).toBe(false)
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
import { gt, valid } from "semver"
|
||||
|
||||
export interface OTAVersionsResponse {
|
||||
store?: {
|
||||
desktop?: {
|
||||
mas?: {
|
||||
version?: null | string
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const normalizeVersion = (version?: null | string) => {
|
||||
if (!version) {
|
||||
return null
|
||||
}
|
||||
|
||||
return valid(version.trim())
|
||||
}
|
||||
|
||||
export const getMASStoreVersionFromOTAVersions = (payload: OTAVersionsResponse) =>
|
||||
payload.store?.desktop?.mas?.version ?? null
|
||||
|
||||
export const isLocalMASVersionInReview = ({
|
||||
isMASBuild,
|
||||
localVersion,
|
||||
storeVersion,
|
||||
}: {
|
||||
isMASBuild: boolean
|
||||
localVersion: string
|
||||
storeVersion?: null | string
|
||||
}) => {
|
||||
if (!isMASBuild) {
|
||||
return false
|
||||
}
|
||||
|
||||
const normalizedLocalVersion = normalizeVersion(localVersion)
|
||||
const normalizedStoreVersion = normalizeVersion(storeVersion)
|
||||
|
||||
if (!normalizedLocalVersion || !normalizedStoreVersion) {
|
||||
return false
|
||||
}
|
||||
|
||||
return gt(normalizedLocalVersion, normalizedStoreVersion)
|
||||
}
|
||||
|
|
@ -1,11 +1,13 @@
|
|||
import { useEffect } from "react"
|
||||
|
||||
import { setServerConfigs } from "~/atoms/server-configs"
|
||||
import { setMASStoreVersion, setServerConfigs } from "~/atoms/server-configs"
|
||||
import { syncServerShortcuts } from "~/atoms/settings/ai"
|
||||
import { useMASStoreVersionQuery } from "~/queries/ota-versions"
|
||||
import { useServerConfigsQuery } from "~/queries/server-configs"
|
||||
|
||||
export const ServerConfigsProvider = () => {
|
||||
const serverConfigs = useServerConfigsQuery()
|
||||
const masStoreVersion = useMASStoreVersionQuery()
|
||||
|
||||
useEffect(() => {
|
||||
if (!serverConfigs) return
|
||||
|
|
@ -13,5 +15,10 @@ export const ServerConfigsProvider = () => {
|
|||
syncServerShortcuts(serverConfigs.AI_SHORTCUTS)
|
||||
}, [serverConfigs])
|
||||
|
||||
useEffect(() => {
|
||||
if (masStoreVersion === undefined) return
|
||||
setMASStoreVersion(masStoreVersion)
|
||||
}, [masStoreVersion])
|
||||
|
||||
return null
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
import { useQuery } from "@tanstack/react-query"
|
||||
import { ofetch } from "ofetch"
|
||||
|
||||
import type { OTAVersionsResponse } from "~/lib/mas-review"
|
||||
import { getMASStoreVersionFromOTAVersions } from "~/lib/mas-review"
|
||||
|
||||
const OTA_VERSIONS_URL = "https://ota.folo.is/versions"
|
||||
|
||||
const isMASBuild = () => typeof process !== "undefined" && !!process.mas
|
||||
|
||||
export const useMASStoreVersionQuery = () => {
|
||||
const { data } = useQuery({
|
||||
queryKey: ["ota-versions", "store", "desktop", "mas"],
|
||||
queryFn: async () => {
|
||||
const response = await ofetch<OTAVersionsResponse>(OTA_VERSIONS_URL, {
|
||||
cache: "no-store",
|
||||
})
|
||||
|
||||
return getMASStoreVersionFromOTAVersions(response)
|
||||
},
|
||||
enabled: isMASBuild(),
|
||||
})
|
||||
|
||||
return data
|
||||
}
|
||||
Loading…
Reference in New Issue