| 1 | import { |
| 2 | AuthEnvironmentMaintainScope, |
| 3 | sessionGrantsScope, |
| 4 | type AuthSessionState, |
| 5 | type ExecutionEnvironmentCapabilities, |
| 6 | type ServerProvider, |
| 7 | } from "@t3tools/contracts"; |
| 8 | import { |
| 9 | cliReleaseChannelOf, |
| 10 | cliReleaseIndexPageUrl, |
| 11 | newestCliReleaseVersion, |
| 12 | } from "@t3tools/shared/cliRelease"; |
| 13 | import { compareSemverVersions } from "@t3tools/shared/semver"; |
| 14 | import * as Schema from "effect/Schema"; |
| 15 | |
| 16 | export function canMaintainEnvironment(session: AuthSessionState | null, connected: boolean) { |
| 17 | return ( |
| 18 | connected && |
| 19 | session?.authenticated === true && |
| 20 | sessionGrantsScope(session, AuthEnvironmentMaintainScope) |
| 21 | ); |
| 22 | } |
| 23 | |
| 24 | export function supportsEnvironmentUpdate( |
| 25 | capabilities: Pick<ExecutionEnvironmentCapabilities, "serverSelfUpdate" | "desktopAppUpdate">, |
| 26 | ) { |
| 27 | return ( |
| 28 | capabilities.serverSelfUpdate !== undefined && |
| 29 | (capabilities.serverSelfUpdate !== "desktop-managed" || capabilities.desktopAppUpdate === true) |
| 30 | ); |
| 31 | } |
| 32 | |
| 33 | export function canUpdateEnvironmentProvider(provider: ServerProvider) { |
| 34 | const compatibility = provider.compatibilityAdvisory?.latestVersionStatus; |
| 35 | return ( |
| 36 | provider.installed && |
| 37 | provider.availability !== "unavailable" && |
| 38 | provider.versionAdvisory?.status === "behind_latest" && |
| 39 | provider.versionAdvisory.canUpdate && |
| 40 | provider.versionAdvisory.latestVersion !== null && |
| 41 | compatibility !== "broken" && |
| 42 | compatibility !== "unsupported" && |
| 43 | provider.updateState?.status !== "running" && |
| 44 | provider.updateState?.status !== "queued" |
| 45 | ); |
| 46 | } |
| 47 | |
| 48 | const Releases = Schema.Array( |
| 49 | Schema.Struct({ |
| 50 | tag_name: Schema.String, |
| 51 | draft: Schema.optionalKey(Schema.Boolean), |
| 52 | }), |
| 53 | ); |
| 54 | const decodeReleases = Schema.decodeUnknownSync(Releases); |
| 55 | |
| 56 | /** Preserve the host's release channel and never offer a downgrade. */ |
| 57 | export async function findEnvironmentUpdate(currentVersion: string, signal: AbortSignal) { |
| 58 | const channel = cliReleaseChannelOf(currentVersion); |
| 59 | for (let page = 1; ; page++) { |
| 60 | const response = await fetch(cliReleaseIndexPageUrl(page), { signal }); |
| 61 | if (!response.ok) throw new Error(`Could not check releases (${response.status}). Try again.`); |
| 62 | const releases = decodeReleases(await response.json()); |
| 63 | const version = newestCliReleaseVersion(releases, channel); |
| 64 | if (version !== undefined) { |
| 65 | return compareSemverVersions(version, currentVersion) > 0 ? version : null; |
| 66 | } |
| 67 | if (releases.length < 100) throw new Error(`No ${channel} release was found.`); |
| 68 | } |
| 69 | } |