fhir-package-installer
Version:
A utility module for downloading, indexing, caching, and managing FHIR packages from the FHIR Package Registry and Simplifier
340 lines (330 loc) • 13.9 kB
TypeScript
import { Logger, FhirPackageIdentifier, PackageIndex, PackageManifest } from '@outburn/types';
export { FileInPackageIndex, PackageIndex, PackageManifest } from '@outburn/types';
/**
* © Copyright Outburn Ltd. 2022-2025 All Rights Reserved
* Project name: FHIR-Package-Installer
*/
/**
* A basic interface for a resource file in a package
*/
interface PackageResource {
id: string;
resourceType: string;
[key: string]: any | any[];
}
/**
* © Copyright Outburn Ltd. 2022-2025 All Rights Reserved
* Project name: FHIR-Package-Installer
*/
/**
* The structure of the FPI constructor config object.
*/
interface FpiConfig {
logger?: Logger;
registryUrl?: string;
registryToken?: string;
cachePath?: string;
skipExamples?: boolean;
allowHttp?: boolean;
requestTimeoutMs?: number;
extractTimeoutMs?: number;
/**
* TTL (ms) for cached registry lookups (unversioned package documents, dist-tags, etc).
* Default: 30 minutes.
*/
registryTtlMs?: number;
}
/**
* © Copyright Outburn Ltd. 2022-2025 All Rights Reserved
* Project name: FHIR-Package-Installer
*/
/**
* Options for the downloadPackage function.
* @param destination The directory path where the package should be saved or extracted.
* Defaults to the current working directory.
* @param overwrite Whether to overwrite the existing package if it already exists.
* Defaults to false.
* @param extract Whether to extract the package after downloading.
* If true, the tarball will be extracted into a subdirectory of `destination`.
*/
interface DownloadPackageOptions {
destination?: string;
overwrite?: boolean;
extract?: boolean;
}
/**
* © Copyright Outburn Ltd. 2022-2025 All Rights Reserved
* Project name: FHIR-Package-Installer
*/
/**
* Options for installing a package.
* @param packageId Specifies a custom package ID to be installed. Defaults to the package identifier from the `package.json` file.
* @param override Whether to override the existing package if it already exists. Defaults to false.
* @param installDependencies Whether to install dependencies of the package. Defaults to false.
*/
interface InstallPackageOptions {
packageId?: string | FhirPackageIdentifier;
override?: boolean;
installDependencies?: boolean;
}
/**
* © Copyright Outburn Ltd. 2022-2025 All Rights Reserved
* Project name: FHIR-Package-Installer
*/
type GetDependenciesOptions = {
rootPackage?: string | FhirPackageIdentifier;
explicitImplicitVersions?: ReadonlyMap<string, string>;
includePlanningFallbacks?: boolean;
};
declare class FhirPackageInstaller {
private logger;
private registryUrl;
private registryDisabled;
private registryToken?;
private requestTimeoutMs;
private extractTimeoutMs;
private registryTtlMs;
/**
* Path to the FHIR package cache directory.
* This directory is used to store downloaded and extracted FHIR packages.
* If the directory does not exist, it will be created.
* Default location follows FHIR spec:
* - User apps: ~/.fhir/packages (Windows: C:\Users\<user>\.fhir\packages)
* - System services: /var/lib/.fhir/packages (Windows: %ProgramData%\.fhir\packages)
*/
private cachePath;
private skipExamples;
private allowHttp;
private resolvingImplicitDeps;
private installingPackages;
private formatPackageForDebug;
private formatMaterializationStatusForDebug;
private describePackageInstallWaitState;
private formatElapsedMs;
private withDebugTiming;
private getPackageKey;
private normalizeDependencies;
constructor(config?: FpiConfig);
/**
* Determines the default FHIR package cache path based on FHIR specifications:
* https://confluence.hl7.org/display/FHIR/FHIR+Package+Cache
*
* For user applications:
* - Windows: C:\Users\<username>\.fhir\packages
* - Unix/Linux: ~/.fhir/packages
*
* For system services (daemons):
* - Windows: %ProgramData%\.fhir\packages (typically C:\ProgramData\.fhir\packages)
* - Unix/Linux: /var/lib/.fhir/packages
*
* Behavior can be overridden via the FHIR_PACKAGE_CACHE_MODE environment variable:
* - FHIR_PACKAGE_CACHE_MODE=system -> always use system service paths
* - FHIR_PACKAGE_CACHE_MODE=user -> always use user paths
*/
private getDefaultCachePath;
private withDiskLock;
private tryWithDiskLock;
private ensureDiskCacheSubdir;
private createWorkingTempDir;
private getPackageInstallLockKey;
private getInstallParticipantDir;
private withInstallParticipant;
private countActiveInstallParticipants;
private isPackageInstallLockHeld;
private waitForPeerDependencyHandoff;
private withPackageInstallLock;
private tryWithPackageInstallLock;
private getStagingPath;
private cleanupStaleStagingDirectories;
private createStagingDirectory;
private buildPackageIndexFromPackageDir;
private normalizeIndexEntry;
private normalizePackageIndex;
private persistMaterializedPackageIndex;
private tryMaterializeLegacyPackageIndex;
private materializePackageIndex;
private getPackageMaterializationStatus;
private stagePackageForPublish;
private isAlreadyExistsError;
private isRetryableStagePublishError;
private getDiskCacheKeyPrefix;
private readDiskCacheJson;
private writeDiskCacheJson;
private writeDiskCacheJsonNoTtl;
private getDiskRegistryMetadataCachePath;
private getDiskIndexCachePath;
private getDiskTarballCacheKey;
private getDiskTarballCachePaths;
private readDiskTarballCache;
private writeDiskTarballDoneMarker;
private getIndexMemKey;
private getIndexDiskLockKey;
private getMaterializationMarkerPath;
private writeMaterializationMarker;
private hasFreshMaterializationMarker;
private isRegistryDisabled;
private formatRegistryDisabledMessage;
private hasShallowInstalledPackage;
private isStrictlyMaterialized;
private hasReadableManifest;
private collectMissingPackages;
private collectPlannedDependencyClosure;
private withRetries;
/**
* Takes a FhirPackageIdentifier Object and returns the corresponding directory name of the package
* @param packageObject A PackageObject with both name and version keys
* @returns (string) Directory name in the standard format `name#version`
*/
private toDirName;
/**
* Takes a FhirPackageIdentifier Object and returns the path to the package folder in the cache
* @param packageObject A FhirPackageIdentifier Object with both name and version keys
* @returns The full path to the package directory
*/
getPackageDirPath(packageId: FhirPackageIdentifier | string): Promise<string>;
/**
* Get the full path to the .fpi.index.json file in the package folder
* @param packageObject A FhirPackageIdentifier Object with both name and version keys
* @returns (string) The path to the package index file
*/
private getPackageIndexPath;
/**
* Scans a package folder and generates a new `.fpi.index.json` file
* @param packageObject The package identifier object
* @returns PackageIndex
*/
private generatePackageIndex;
/**
* Generates HTTP options including authorization header for registry requests
* @param url The URL being requested
* @returns HTTP options object with headers if needed
*/
private getHttpOptions;
private fetchJson;
private fetchStream;
private getPackageDataFromRegistry;
private getTarballUrl;
private downloadFile;
private downloadTarball;
private getOrDownloadDiskCachedTarball;
/**
* Extracts a tarball to a temporary directory and generates a new `.fpi.index.json` file.
* The tarball can be a file path or a stream.
* @param src The source tarball, either a file path or a Readable stream.
* @returns The path to the temporary directory where the package was extracted.
*/
private extractTarball;
private downloadAndExtractTarball;
/**
* Caches the package in the FHIR package cache directory.
* If the package is already installed, it will not be reinstalled.
* @param packageObject The package identifier object
* @param src The source path of the package to be cached
* @param move Whether to move the package to the cache or copy it. Defaults to **true**.
* @returns The path to the cached package directory
*/
private cachePackage;
/**
* Extracts the version of the package from a raw package identifier string.
* Supported formats: `name@version`, `name#version`, or just `name`
* @param packageId Raw package identifier string
* @returns The version part or 'latest' if not supplied
*/
private getVersionFromPackageString;
isInstalled(packageId: FhirPackageIdentifier | string, options?: {
deep?: boolean;
}): Promise<boolean>;
getPackageIndexFile(packageId: FhirPackageIdentifier | string): Promise<PackageIndex>;
checkLatestPackageDist(packageName: string): Promise<string>;
toPackageObject(packageId: string | FhirPackageIdentifier): Promise<FhirPackageIdentifier>;
private getImplicitEffectiveCacheKey;
private getImplicitPlanningCacheKeys;
private readManifestFile;
private waitForManifestDuringActiveInstall;
getManifest(packageId: string | FhirPackageIdentifier): Promise<PackageManifest>;
/**
* Get the path to the FHIR package cache directory.
* This directory is used to store downloaded and extracted FHIR packages.
* If the directory does not exist, it will be created.
* @returns {string} The path to the FHIR package cache directory
*/
getCachePath(): string;
/**
* Get the logger instance used by this FhirPackageInstaller.
*/
getLogger(): Logger;
/**
* Scan cache directory for installed versions of a package
* @param packageName Package name to search for
* @returns Array of installed versions sorted in descending order (latest first)
*/
private getInstalledVersions;
/**
* Resolve an implicit package dependency to an effective version that is installed and manifest-valid.
*
* This is the materializing resolver used by code paths that need a real readable package entry,
* not just a plannable version candidate.
*/
protected resolveImplicitPackageVersionWithFallbacks(packageName: string): Promise<string>;
private resolveImplicitPackageVersionForPlanning;
/**
* Get implicit dependencies for a given package
* @param packageObject The package to check for implicit dependencies
* @returns Promise resolving to record of implicit dependencies
*/
private getImplicitDependencies;
/**
* Get explicit dependencies from package.json only (internal use)
* @param packageObject The package to get explicit dependencies for
* @returns Promise resolving to record of explicit dependencies only
*/
private getExplicitDependencies;
private getExplicitDependenciesFromTarballManifest;
private getExplicitDependenciesFromRegistryMetadata;
private getExplicitDependenciesForPlanning;
private getDependenciesForPlanning;
private collectExplicitDependencyClosure;
/**
* Get all dependencies for a package, including both explicit dependencies from package.json
* and automatic implicit dependencies for core FHIR packages.
*
* For core FHIR packages (hl7.fhir.r3.core, hl7.fhir.r4.core, hl7.fhir.r5.core),
* this automatically includes essential terminology and extension packages.
*
* @param packageObject The package to get dependencies for
* @param options Optional root/context information for graph-aware implicit package version selection
* @returns Promise resolving to record of all dependencies (explicit + implicit)
*/
getDependencies(packageObject: FhirPackageIdentifier, options?: GetDependenciesOptions): Promise<Record<string, string>>;
install(packageId: string | FhirPackageIdentifier): Promise<boolean>;
private materializePackageWithoutDependencies;
private installPackageDependencies;
/**
* Installs a package from a local file or directory.
* The package can be a tarball file or a directory containing the package files.
* @param src The path to the local package file or directory.
* @param options Options for installing the package.
* @returns A promise that resolves to true if the package was installed successfully,
* or false if it was already installed.
*/
installLocalPackage(src: string, options?: InstallPackageOptions): Promise<boolean>;
/**
* Downloads a package tarball and optionally extracts it to a destination directory.
*
* Behavior:
* - If `extract` is false or omitted: downloads the tarball as a .tgz file to the destination directory.
* - If `extract` is true: downloads and extracts the package into a subdirectory of the destination path.
*
* @param packageId A package identifier string or a FhirPackageIdentifier object.
* @param options Options controlling the download and extraction behavior.
* @returns
* - If `extract` is false: the full path to the downloaded tarball file.
* - If `extract` is true: the full path to the extracted package directory.
*/
downloadPackage(packageId: string | FhirPackageIdentifier, options?: DownloadPackageOptions): Promise<string>;
}
/**
* Default instance export for convenience
*/
declare const fpi: FhirPackageInstaller;
export { type DownloadPackageOptions, FhirPackageInstaller, type FpiConfig, type InstallPackageOptions, type PackageResource, fpi as default };