782 lines · 27.4 KB · TypeScript
RawDownload
import {  defaultInstanceIdForDriver,  PROVIDER_DISPLAY_NAMES,  type EnvironmentId,  type ExecutionEnvironmentPlatformOs,  type ProviderDriverKind,  type ProviderInstanceId,  type ServerProvider,} from "@t3tools/contracts";import {  squashAtomCommandFailure,  type AtomCommandResult,} from "@t3tools/client-runtime/state/runtime"; export type ProviderUpdateCandidate = ServerProvider & {  readonly versionAdvisory: NonNullable<ServerProvider["versionAdvisory"]> & {    readonly status: "behind_latest";    readonly latestVersion: string;  };}; export type ProviderSettingsUpdateCandidate = ServerProvider & {  readonly versionAdvisory: NonNullable<ServerProvider["versionAdvisory"]> & {    readonly canUpdate: true;    readonly updateCommand: string;  };}; export type ProviderUpdateToastType = "warning" | "loading" | "error" | "success";export type ProviderUpdateToastPhase = "initial" | "running" | "failed" | "unchanged" | "succeeded"; export interface ProviderUpdateToastView {  readonly phase: ProviderUpdateToastPhase;  readonly type: ProviderUpdateToastType;  readonly title: string;  readonly description: string;  readonly dismissAfterVisibleMs?: number;} /** * Terminal update phases — outcomes that are safe to persist as a one-shot row * result. A non-terminal ("initial"/"running") snapshot never re-polls itself, * so storing one pins an update row's spinner indefinitely once its pending flag * expires; such phases must be dropped in favor of the live per-environment * provider state instead of being persisted. */export function isTerminalProviderUpdatePhase(phase: ProviderUpdateToastPhase): boolean {  return phase === "succeeded" || phase === "failed" || phase === "unchanged";} export type ProviderUpdateSidebarPillTone = "loading" | "warning" | "error" | "success"; export interface ProviderUpdateSidebarPillView {  readonly key: string;  readonly tone: ProviderUpdateSidebarPillTone;  readonly title: string;  readonly description: string;  readonly dismissible?: boolean;  readonly dismissAfterVisibleMs?: number;} interface ProviderUpdateSidebarPillOptions {  readonly visibleAfterIso?: string;  readonly dismissedKeys?: ReadonlySet<string>;} const PROVIDER_UPDATE_SUCCESS_VISIBLE_MS = 3_000; function formatVersion(value: string): string {  return value.startsWith("v") ? value : `v${value}`;} function chooseRepresentativeProvider(  current: ServerProvider | undefined,  candidate: ServerProvider,): ServerProvider {  if (!current) {    return candidate;  }  const defaultInstanceId = defaultInstanceIdForDriver(candidate.driver);  if (candidate.instanceId === defaultInstanceId) {    return candidate;  }  if (current.instanceId === defaultInstanceId) {    return current;  }  return candidate.checkedAt.localeCompare(current.checkedAt) >= 0 ? candidate : current;} function dedupeProvidersByDriver<T extends ServerProvider>(providers: ReadonlyArray<T>): T[] {  const latestProviderByDriver = new Map<ProviderDriverKind, T>();   for (const provider of providers) {    latestProviderByDriver.set(      provider.driver,      chooseRepresentativeProvider(latestProviderByDriver.get(provider.driver), provider) as T,    );  }   return [...latestProviderByDriver.values()];} function dedupeProvidersByInstanceId<T extends ServerProvider>(providers: ReadonlyArray<T>): T[] {  const latestProviderByInstanceId = new Map<ProviderInstanceId, T>();   for (const provider of providers) {    const current = latestProviderByInstanceId.get(provider.instanceId);    if (!current || provider.checkedAt.localeCompare(current.checkedAt) >= 0) {      latestProviderByInstanceId.set(provider.instanceId, provider);    }  }   return [...latestProviderByInstanceId.values()];} function getProviderUpdatedTitle(provider: Pick<ServerProvider, "driver" | "version">): string {  const providerName = PROVIDER_DISPLAY_NAMES[provider.driver] ?? provider.driver;  return provider.version    ? `${providerName} updated: ${formatVersion(provider.version)}`    : `${providerName} updated`;} function getProviderUpdatedDescription(providerCount: number): string {  return providerCount === 1    ? "New sessions will use the updated provider."    : "New sessions will use the updated providers.";} function getProviderFailedUpdateTitle(  provider: Pick<ServerProvider, "driver" | "versionAdvisory">,): string {  const providerName = PROVIDER_DISPLAY_NAMES[provider.driver] ?? provider.driver;  const attemptedVersion = provider.versionAdvisory?.latestVersion;  return attemptedVersion    ? `${providerName} ${formatVersion(attemptedVersion)} update failed`    : `${providerName} update failed`;} export function isProviderUpdateCandidate(  provider: ServerProvider,): provider is ProviderUpdateCandidate {  return (    provider.enabled &&    provider.versionAdvisory?.status === "behind_latest" &&    provider.versionAdvisory.latestVersion !== null  );} export function isProviderUpdateActive(provider: Pick<ServerProvider, "updateState">): boolean {  return provider.updateState?.status === "queued" || provider.updateState?.status === "running";} export function collectProviderUpdateCandidates(  providers: ReadonlyArray<ServerProvider>,): ProviderUpdateCandidate[] {  return dedupeProvidersByDriver(providers.filter(isProviderUpdateCandidate));} export function isProviderSettingsUpdateCandidate(  provider: ServerProvider,): provider is ProviderSettingsUpdateCandidate {  return (    provider.enabled &&    provider.versionAdvisory?.status === "behind_latest" &&    provider.versionAdvisory.canUpdate === true &&    provider.versionAdvisory.updateCommand !== null  );} export function hasOneClickUpdateProviderCandidate(  candidate: ProviderUpdateCandidate,  providers: ReadonlyArray<ServerProvider>,): boolean {  if (    candidate.versionAdvisory.canUpdate !== true ||    candidate.versionAdvisory.updateCommand === null  ) {    return false;  }   const driverProviders = providers.filter((provider) => provider.driver === candidate.driver);  if (driverProviders.length === 0) {    return false;  }   const updateCommands = new Set<string>();  for (const provider of driverProviders) {    if (!isProviderUpdateCandidate(provider)) {      continue;    }    const advisory = provider.versionAdvisory;    if (!advisory || advisory.canUpdate !== true || advisory.updateCommand === null) {      return false;    }    updateCommands.add(advisory.updateCommand);  }   return updateCommands.size === 1;} export function canOneClickUpdateProviderCandidate(  candidate: ProviderUpdateCandidate,  providers: ReadonlyArray<ServerProvider>,): boolean {  return (    !isProviderUpdateActive(candidate) && hasOneClickUpdateProviderCandidate(candidate, providers)  );} export function providerUpdateNotificationKey(  providers: ReadonlyArray<ProviderUpdateCandidate>,): string | null {  const parts = dedupeProvidersByDriver(providers)    .map((provider) => {      const advisory = provider.versionAdvisory;      return [provider.driver, advisory.latestVersion].join(":");    })    .toSorted();   return parts.length > 0 ? parts.join("|") : null;} function formatProviderList(providers: ReadonlyArray<Pick<ServerProvider, "driver">>) {  const names = providers.map(    (provider) => PROVIDER_DISPLAY_NAMES[provider.driver] ?? provider.driver,  );  if (names.length <= 2) {    return names.join(" and ");  }  return `${names.slice(0, -1).join(", ")}, and ${names[names.length - 1]}`;} export function getProviderUpdateInitialToastView(input: {  readonly updateProviders: ReadonlyArray<ProviderUpdateCandidate>;  readonly oneClickProviders: ReadonlyArray<ProviderUpdateCandidate>;}): ProviderUpdateToastView {  return {    phase: "initial",    type: "warning",    title: getProviderUpdateInitialToastTitle(input.updateProviders),    description:      input.oneClickProviders.length > 0        ? "Install the update now or review provider settings."        : `${formatProviderList(input.updateProviders)} can be updated from provider settings.`,  };} export function shouldShowPrimaryProviderUpdateToast(view: ProviderUpdateToastView): boolean {  return view.phase !== "running";} function getProviderUpdateRunningToastView(providerCount: number): ProviderUpdateToastView {  return {    phase: "running",    type: "loading",    title: providerCount === 1 ? "Updating provider" : "Updating providers",    description: "Running provider update command.",  };} export function getProviderUpdateRejectedToastView(  providerCount: number,  message: string,): ProviderUpdateToastView {  return {    phase: "failed",    type: "error",    title: providerCount === 1 ? "Provider update failed" : "Provider updates failed",    description: message,  };} export function getProviderUpdateProgressToastView(input: {  readonly providers: ReadonlyArray<ServerProvider>;  readonly providerCount: number;}): ProviderUpdateToastView {  const providers = dedupeProvidersByDriver(input.providers);  const failedProviders = providers.filter((provider) => provider.updateState?.status === "failed");  if (failedProviders.length > 0) {    return {      phase: "failed",      type: "error",      title: failedProviders.length === 1 ? "Provider update failed" : "Provider updates failed",      description: getFailedProviderUpdateDescription(failedProviders),    };  }   const unchangedProviders = providers.filter(    (provider) => provider.updateState?.status === "unchanged",  );  if (unchangedProviders.length > 0) {    return {      phase: "unchanged",      type: "warning",      title:        unchangedProviders.length === 1          ? "Provider still needs an update"          : "Providers still need updates",      description: `${formatProviderList(unchangedProviders)} ${        unchangedProviders.length === 1 ? "still appears" : "still appear"      } outdated. Check provider settings for details.`,    };  }   if (providers.some(isProviderUpdateActive)) {    return getProviderUpdateRunningToastView(input.providerCount);  }   const hasCompleteProviderSnapshots = providers.length >= input.providerCount;  const allProvidersUpdated =    hasCompleteProviderSnapshots &&    providers.every(      (provider) =>        provider.updateState?.status === "succeeded" || !isProviderUpdateCandidate(provider),    );  if (allProvidersUpdated) {    return {      phase: "succeeded",      type: "success",      title: input.providerCount === 1 ? "Provider updated" : "Provider updates finished",      description: getProviderUpdatedDescription(input.providerCount),      dismissAfterVisibleMs: PROVIDER_UPDATE_SUCCESS_VISIBLE_MS,    };  }   return getProviderUpdateRunningToastView(input.providerCount);} export function collectUpdatedProviderSnapshots(input: {  readonly results: ReadonlyArray<    AtomCommandResult<{ readonly providers: ReadonlyArray<ServerProvider> }, unknown>  >;  readonly providerInstanceIds: ReadonlySet<ProviderInstanceId>;}): ServerProvider[] {  const matchedProviders: ServerProvider[] = [];   for (const result of input.results) {    if (result._tag === "Failure") {      continue;    }    for (const provider of result.value.providers) {      if (input.providerInstanceIds.has(provider.instanceId)) {        matchedProviders.push(provider);      }    }  }   return dedupeProvidersByInstanceId(matchedProviders);} export function firstFailedProviderUpdateMessage(  results: ReadonlyArray<AtomCommandResult<unknown, unknown>>,): string | null {  const failed = results.find((result) => result._tag === "Failure");  if (!failed || failed._tag !== "Failure") {    return null;  }  const error = squashAtomCommandFailure(failed);  return error instanceof Error ? error.message : "Provider update failed.";} function getUpdateFinishedAt(provider: ServerProvider): string | null {  return provider.updateState?.finishedAt ?? null;} function isRecentTerminalProvider(  provider: ServerProvider,  visibleAfterIso: string | undefined,): boolean {  const status = provider.updateState?.status;  if (status !== "failed" && status !== "unchanged" && status !== "succeeded") {    return false;  }  if (visibleAfterIso === undefined) {    return true;  }  const finishedAt = getUpdateFinishedAt(provider);  return finishedAt !== null && finishedAt >= visibleAfterIso;} function latestFinishedAtForProviders(providers: ReadonlyArray<ServerProvider>): string | null {  return providers.reduce<string | null>((latest, provider) => {    const finishedAt = getUpdateFinishedAt(provider);    if (finishedAt === null) {      return latest;    }    return latest === null || finishedAt > latest ? finishedAt : latest;  }, null);} export function getProviderUpdateSidebarPillView(  providers: ReadonlyArray<ServerProvider>,  options?: ProviderUpdateSidebarPillOptions,): ProviderUpdateSidebarPillView | null {  const dedupedProviders = dedupeProvidersByDriver(providers);  const activeProviders = dedupedProviders.filter(isProviderUpdateActive);  if (activeProviders.length > 0) {    const activeProvider = activeProviders[0]!;    const activeProviderName =      PROVIDER_DISPLAY_NAMES[activeProvider.driver] ?? activeProvider.driver;    return {      key: `loading:${activeProviders        .map((provider) => `${provider.driver}:${provider.updateState?.status ?? "idle"}`)        .toSorted()        .join("|")}`,      tone: "loading",      title:        activeProviders.length === 1          ? `Updating ${activeProviderName}`          : `Updating ${activeProviders.length} providers`,      description:        activeProviders.length === 1          ? `${formatProviderList(activeProviders)} update in progress.`          : `${formatProviderList(activeProviders)} updates are in progress.`,    };  }   const recentTerminalProviders = dedupedProviders.filter((provider) =>    isRecentTerminalProvider(provider, options?.visibleAfterIso),  );  const terminalCandidates: ProviderUpdateSidebarPillView[] = [];   const failedProviders = recentTerminalProviders.filter(    (provider) => provider.updateState?.status === "failed",  );  if (failedProviders.length > 0) {    const failedProvider = failedProviders[0]!;    terminalCandidates.push({      key: `failed:${failedProviders        .map(          (provider) =>            `${provider.driver}:${provider.updateState?.finishedAt ?? "pending"}:${provider.updateState?.message ?? ""}`,        )        .toSorted()        .join("|")}`,      tone: "error",      title:        failedProviders.length === 1          ? getProviderFailedUpdateTitle(failedProvider)          : `${failedProviders.length} provider updates failed`,      description: getFailedProviderUpdateDescription(failedProviders),      dismissible: true,    });  }   const unchangedProviders = recentTerminalProviders.filter(    (provider) => provider.updateState?.status === "unchanged",  );  if (unchangedProviders.length > 0) {    const unchangedProvider = unchangedProviders[0]!;    const unchangedProviderName =      PROVIDER_DISPLAY_NAMES[unchangedProvider.driver] ?? unchangedProvider.driver;    terminalCandidates.push({      key: `unchanged:${unchangedProviders        .map(          (provider) =>            `${provider.driver}:${provider.updateState?.finishedAt ?? "pending"}:${provider.updateState?.message ?? ""}`,        )        .toSorted()        .join("|")}`,      tone: "warning",      title:        unchangedProviders.length === 1          ? `${unchangedProviderName} still needs an update`          : `${unchangedProviders.length} providers still need updates`,      description: `${formatProviderList(unchangedProviders)} ${        unchangedProviders.length === 1 ? "still appears" : "still appear"      } outdated. Review provider settings for details.`,      dismissible: true,    });  }   const succeededProviders = recentTerminalProviders.filter(    (provider) => provider.updateState?.status === "succeeded",  );  if (succeededProviders.length > 0) {    const succeededProvider = succeededProviders[0]!;    terminalCandidates.push({      key: `succeeded:${succeededProviders        .map(          (provider) =>            `${provider.driver}:${provider.updateState?.finishedAt ?? "pending"}:${provider.updateState?.message ?? ""}`,        )        .toSorted()        .join("|")}`,      tone: "success",      title:        succeededProviders.length === 1          ? getProviderUpdatedTitle(succeededProvider)          : `${succeededProviders.length} providers updated`,      description: getProviderUpdatedDescription(succeededProviders.length),      dismissAfterVisibleMs: PROVIDER_UPDATE_SUCCESS_VISIBLE_MS,    });  }   return (    terminalCandidates      .toSorted((left, right) => {        const leftProviders =          left.tone === "error"

Lines 1–500 of 782.