import * as T from "../../../base/lib/types" import { MountOptions } from "../util/SubContainer" type MountArray = { mountpoint: string; options: MountOptions }[] type SharedOptions = { /** The path within the resource to mount. Use `null` to mount the entire resource */ subpath: string | null /** Where to mount the resource. e.g. /data */ mountpoint: string /** * Whether to mount this as a file or directory * * defaults to "directory" * */ type?: "file" | "directory" | "infer" } type VolumeOpts = { /** The ID of the volume to mount. Must be one of the volume IDs defined in the manifest */ volumeId: Manifest["volumes"][number] /** Whether or not the resource should be readonly for this subcontainer */ readonly: boolean } & SharedOptions type DependencyOpts = { /** The ID of the dependency */ dependencyId: Manifest["id"] /** The ID of the volume to mount. Must be one of the volume IDs defined in the manifest of the dependency */ volumeId: Manifest["volumes"][number] /** Whether or not the resource should be readonly for this subcontainer */ readonly: boolean } & SharedOptions export class Mounts< Manifest extends T.SDKManifest, Backups extends SharedOptions = never, > { private constructor( readonly volumes: VolumeOpts[], readonly assets: SharedOptions[], readonly dependencies: DependencyOpts[], readonly backups: Backups[], ) {} static of() { return new Mounts([], [], [], []) } mountVolume(options: VolumeOpts) { return new Mounts( [...this.volumes, options], [...this.assets], [...this.dependencies], [...this.backups], ) } mountAssets(options: SharedOptions) { return new Mounts( [...this.volumes], [...this.assets, options], [...this.dependencies], [...this.backups], ) } mountDependency( options: DependencyOpts, ) { return new Mounts( [...this.volumes], [...this.assets], [...this.dependencies, options], [...this.backups], ) } mountBackups(options: SharedOptions) { return new Mounts< Manifest, { subpath: string | null mountpoint: string } >( [...this.volumes], [...this.assets], [...this.dependencies], [...this.backups, options], ) } build(): MountArray { const mountpoints = new Set() for (let mountpoint of this.volumes .map((v) => v.mountpoint) .concat(this.assets.map((a) => a.mountpoint)) .concat(this.dependencies.map((d) => d.mountpoint))) { if (mountpoints.has(mountpoint)) { throw new Error( `cannot mount more than once to mountpoint ${mountpoint}`, ) } mountpoints.add(mountpoint) } return ([] as MountArray) .concat( this.volumes.map((v) => ({ mountpoint: v.mountpoint, options: { type: "volume", volumeId: v.volumeId, subpath: v.subpath, readonly: v.readonly, filetype: v.type ?? "directory", }, })), ) .concat( this.assets.map((a) => ({ mountpoint: a.mountpoint, options: { type: "assets", subpath: a.subpath, filetype: a.type ?? "directory", }, })), ) .concat( this.dependencies.map((d) => ({ mountpoint: d.mountpoint, options: { type: "pointer", packageId: d.dependencyId, volumeId: d.volumeId, subpath: d.subpath, readonly: d.readonly, filetype: d.type ?? "directory", }, })), ) } } const a = Mounts.of().mountBackups({ subpath: null, mountpoint: "" }) // @ts-expect-error const m: Mounts = a