/**
 * Portable bundle — the third representation of a spec (alongside live HEAD and
 * versioned history). A `tar.gz` holding the full, self-contained state of a
 * release N, derived ONLY from the versioning tables (via `getReleaseSnapshot`),
 * never from `pagesDir` on disk or entity HEADs.
 *
 * Spec reference: brief `0-1-27-to-0-1-28.md`. Direct consumers (future):
 * M25 (push to remote) writes; M26 (`c4s import`) reads. The restore direction
 * lives in `ReleaseService.restoreBundleArchive` (contract-only in v1).
 *
 * This module owns the pure write logic + the constants/types M26 will import.
 * The two public methods stay on `ReleaseService` per the M17 contract; they
 * are thin delegations to `buildBundleArchive(...)` here.
 */
import type { Release, SpecSnapshot } from '../../shared/entities.js';
import type { Config } from '../config.js';
/**
 * Bundle layout version. Bump = breaking change in the bundle shape (layout,
 * manifest, sanitization semantics). M26 import compares
 * `manifest.bundleSchemaVersion` against the highest version it supports →
 * mismatch ⇒ `BUNDLE_SCHEMA_UNSUPPORTED`. NOT bumped when an entity's
 * `serializer_version` changes — each bundle is self-contained w.r.t. entity
 * schema (carried per-type in the manifest's `serializerVersions`).
 */
export declare const BUNDLE_SCHEMA_VERSION: 1;
/**
 * Strict singular entity type → plural bundle file name. Published for M26
 * (read direction maps plural file → entity type via the reverse).
 */
export declare const ENTITY_TYPE_TO_PLURAL_FILE: Record<string, string>;
/** Reverse of {@link ENTITY_TYPE_TO_PLURAL_FILE} — read direction (M27 clone). */
export declare const PLURAL_FILE_TO_ENTITY_TYPE: Record<string, string>;
/** Sanitized `config.json` shape embedded in the bundle (white-list, see below). */
export interface BundleConfig {
    $schemaVersion: number;
    name: string;
    pagesDir: string;
    mode: 'dev' | 'prod';
    writingStyle: string | null;
    onboardingCompleted: boolean;
    entities?: string[];
    agent?: {
        claudeUsePreset?: boolean;
    };
}
export interface BundleManifest {
    bundleSchemaVersion: 1;
    release: {
        id: number;
        name: string;
        description: string;
        createdAt: string;
    };
    /** Informational (debug/audit) — M26 does NOT reject by this, only by `bundleSchemaVersion`. */
    c4sVersion: string;
    /** Build moment — `new Date().toISOString()`, distinct from `release.createdAt`. */
    createdAt: string;
    /**
     * Per-type serializer versions at capture time (keys: endpoint, dto,
     * database-table, ui-view, ac, page). The snapshot model carries serializer
     * versions per-type, not per-entity — see the brief drift patch. M26 reads
     * the version per type and delegates to the matching deserializer.
     */
    serializerVersions: Record<string, string>;
}
export interface BuildBundleResult {
    tarGzPath: string;
    sizeBytes: number;
    sha256: string;
    bundleSchemaVersion: number;
}
export declare const C4S_VERSION: string;
/**
 * Explicit allow-list (fail-closed). This is the ONLY edit point when M01 adds
 * a new `Config` field: a new field is dropped from the bundle until someone
 * consciously decides to keep it here. No allow-list entry → no leak.
 */
export declare function sanitizeConfigForBundle(config: Config): BundleConfig;
/** Streaming SHA-256 over a file → lowercase hex64. */
export declare function sha256File(file: string): Promise<string>;
/**
 * Build a portable `tar.gz` for release N from an already-resolved snapshot.
 *
 * Pure `(snapshot, release, config) → bytes` — no DB / disk reads beyond the
 * temp working dir. The caller (`ReleaseService.buildBundleArchive`) resolves
 * `snapshot`/`release` from the versioning tables and `config` via `readConfig`.
 *
 * Determinism: entries are sorted and tar headers use `portable` + `noMtime` to
 * strip system-specific noise. The returned `sha256` is an integrity hash over
 * the ACTUAL produced bytes (round-trip self-consistent) — gzip OS-byte/level
 * differences mean it is NOT a cross-machine reproducible build hash.
 *
 * `tarGzPath` is NOT cleaned up here — the consumer (M25 push / M26 import /
 * test) owns it. The internal temp dir IS cleaned up in `finally`.
 */
export declare function buildBundleArchive(snapshot: SpecSnapshot, release: Release, config: Config): Promise<BuildBundleResult>;
/**
 * Extract a bundle `tar.gz` stream into `destDir`. The inverse transport step of
 * {@link buildBundleArchive}'s `tarCreate`. Caller owns `destDir` (cleanup).
 */
export declare function extractBundleStream(stream: NodeJS.ReadableStream, destDir: string): Promise<void>;
/**
 * Cheaply read just `manifest.json` + `config.json` out of an already-downloaded
 * bundle tar.gz. Consumed by the M27 clone service for the `release_import`
 * audit row's `bundle_schema_version` and for the post-restore config patch
 * (name / entities) — facts that the `restoreBundleArchive(): Promise<SpecSnapshot>`
 * signature cannot carry. Missing manifest ⇒ `BUNDLE_MANIFEST_MISSING`.
 */
export declare function readBundleMeta(tarGzPath: string): Promise<{
    manifest: BundleManifest;
    config: BundleConfig | null;
}>;
