import * as T from "../types" import { once } from "../util" export type RequiredDependenciesOf = { [K in keyof Manifest["dependencies"]]: Manifest["dependencies"][K]["optional"] extends false ? K : never }[keyof Manifest["dependencies"]] export type OptionalDependenciesOf = Exclude< keyof Manifest["dependencies"], RequiredDependenciesOf > type DependencyRequirement = | { kind: "running" healthChecks: Array versionRange: string } | { kind: "exists" versionRange: string } type Matches = T extends U ? (U extends T ? null : never) : never const _checkType: Matches< DependencyRequirement & { id: T.PackageId }, T.DependencyRequirement > = null export type CurrentDependenciesResult = { [K in RequiredDependenciesOf]: DependencyRequirement } & { [K in OptionalDependenciesOf]?: DependencyRequirement } export function setupDependencies( fn: (options: { effects: T.Effects }) => Promise>, ): (options: { effects: T.Effects }) => Promise { const cell = { updater: async (_: { effects: T.Effects }) => null } cell.updater = async (options: { effects: T.Effects }) => { const childEffects = options.effects.child("setupDependencies") childEffects.constRetry = once(() => { cell.updater({ effects: options.effects }) }) const dependencyType = await fn({ effects: childEffects }) return await options.effects.setDependencies({ dependencies: Object.entries(dependencyType) .map(([k, v]) => [k, v as DependencyRequirement] as const) .map( ([id, { versionRange, ...x }]) => ({ id, ...x, versionRange: versionRange.toString(), }) as T.DependencyRequirement, ), }) } return cell.updater }