/** * portable-bundle-import.ts — import side of the lossless machine-migration * bundle (manifest v2). * * Order of operations (nothing is placed until everything is verified): * 1. decrypt (streamed) and extract into a staging directory; * 2. verify the manifest self-hash, every file's size + SHA-256, and * `PRAGMA integrity_check` on every database; * 3. resolve destinations (`--target` for a single project, `--map` * prefix rewrites, else the original paths) and refuse to overwrite * live data without `force`; * 4. relocate the STAGED copies (paths, registry rows) when a project * moves; * 5. place files and databases (tmp + rename, stale WAL sidecars removed); * 6. re-count every table of every placed database and compare with the * manifest — any mismatch fails the import; * 7. encrypted bundles: unseal the passphrase-sealed credentials and * re-encrypt each under the TARGET home's machine-key (the bundle never * carries the source machine-key), reporting any that must be re-entered. * * @task T12318 * @epic T12317 * @module store/portable-bundle-import */ import type { PortableBundleManifest, PortableImportResult, PortableImportSectionResult } from '@cleocode/contracts'; /** One `--map =` prefix rewrite. */ export interface PathMapping { /** Old absolute prefix. */ from: string; /** New absolute prefix. */ to: string; } /** Input for {@link importPortableBundle}. */ export interface ImportPortableBundleInput { /** Bundle file. */ bundlePath: string; /** Passphrase for encrypted bundles. */ passphrase?: string; /** Destination project root for a single-project bundle. */ target?: string; /** Prefix rewrites applied to project paths (longest match wins). */ maps?: readonly PathMapping[]; /** Destination global home (defaults to `getCleoHome()`). */ cleoHome?: string; /** Destination config home (defaults to `getCleoConfigDir()`). */ configHome?: string; /** Overwrite existing live data. */ force?: boolean; /** * Directory the import was invoked from (T12708); supplied by the CLI layer. * A project section placed into the owning project's store from one of its * worktrees needs {@link ImportPortableBundleInput.confirmOwnerStore}. */ cwd: string; /** Confirm overwriting the owning project's LIVE store from a worktree (T12708). */ confirmOwnerStore?: boolean; /** * Throw `E_RESTORE_MISMATCH` (carrying the full report) when any restored * table count differs from the manifest, instead of returning `lossless: false`. */ requireLossless?: boolean; /** Directory in which to create the staging directory (defaults to the parent of `cleoHome`). */ stagingParent?: string; /** * Called after placement for projects whose global registry row could not be * rewritten in a bundled global store (project-only bundles). Receives the * projectId and new root; returns the registry outcome. */ registerProject?: (projectId: string | null, newRoot: string) => Promise>; /** * Called after the staged bundle is extracted and its integrity verified, * before anything is placed (T12336). A throw aborts the import with * nothing activated: the cloud vault checks the snapshot's per-table counts * and hashes here. */ onStaged?: (extractDir: string, manifest: PortableBundleManifest) => void | Promise; /** * Plain files this machine keeps, by path in their section (T13005): `keep` * leaves the destination's copy where it has one (the bundle's is placed * only where it has none); `skip` never places the bundle's copy. Every * other file is placed. The cloud vault keeps machine-local files this way. */ machineLocalFile?: (relPath: string) => 'keep' | 'skip' | null; } /** * Parse `--map` values (`=`). * * @param values - Raw flag values. * @returns Parsed mappings with resolved absolute prefixes. * @throws {PortableBundleError} `E_BUNDLE_FORMAT` on a malformed value. */ export declare function parsePathMappings(values: readonly string[]): PathMapping[]; /** * Apply the longest matching prefix mapping to a path. * * @param original - Original absolute path. * @param maps - Mappings. * @returns The mapped path (unchanged when nothing matches). */ export declare function applyPathMappings(original: string, maps: readonly PathMapping[]): string; /** * Peek at a bundle and report whether it is a portable (manifest v2) bundle. * * Encrypted bundles are identified by their format version byte; unencrypted * ones by the `format` field of their first entry, `manifest.json`. * * @param bundlePath - Bundle file. * @returns `v2`, `v1`, or `unknown`. */ export declare function detectBundleFormat(bundlePath: string): Promise<'v1' | 'v2' | 'unknown'>; /** * Decrypt (when encrypted), extract and verify a portable (manifest v2) * bundle under `stagingDir/bundle`, placing nothing. `importPortableBundle` * stages through it; the copy reconcile restores a checkpoint's store into a * scratch directory with it (T13335). * * @param bundlePath - The `.cleobundle.tar.gz` (or its encrypted form). * @param stagingDir - An existing, empty directory the caller owns and removes. * @param passphrase - The passphrase of an encrypted bundle. * @returns The extracted directory and the verified manifest. * @throws {PortableBundleError} On a wrong format, a missing passphrase, a * decrypt failure or a manifest that does not verify. */ export declare function extractPortableBundle(bundlePath: string, stagingDir: string, passphrase?: string): Promise<{ extractDir: string; manifest: PortableBundleManifest; }>; /** * Import a portable (manifest v2) bundle. * * @param input - Import options. * @returns Per-section outcomes; `lossless` is true only when every table of * every placed database re-counts to the manifest value. * @throws {PortableBundleError} On decrypt/format/integrity failure, existing * live data without `force`, or an ambiguous destination. * * @example * ```ts * const r = await importPortableBundle({ bundlePath: '/b/p.cleobundle.tar.gz', target: '/new/p' }); * if (!r.lossless) throw new Error('restore is not lossless'); * ``` */ export declare function importPortableBundle(input: ImportPortableBundleInput): Promise; /** * Point the ambient global registry at a relocated project: move the existing * row (keyed by projectId) or register the project when it is absent. * * Uses the canonical nexus registry API against the CURRENT `getCleoHome()`, * so callers must run it with the destination home active. * * @param projectId - Stable projectId from project-info.json (null when absent). * @param newRoot - New project root. * @returns Registry outcome. */ export declare function registerRelocatedProject(projectId: string | null, newRoot: string): Promise>; //# sourceMappingURL=portable-bundle-import.d.ts.map