/**
 * Node-only `Assets` namespace enrichments (v1.48 unified-apply).
 *
 * `NodeAssets` extends the isomorphic {@link Assets} with directory-walking
 * helpers — `uploadDir` (additive), `syncDir` (declarative prune), and
 * `prepareDir` (pre-commit URL injection) — that read bytes from disk
 * lazily, compute SHA-256s in streaming chunks, and submit through the
 * single hero `r.project(id).apply(spec)` engine. See design D8/D10/D11.
 *
 * Imports `node:fs/promises` via `fileSetFromDir`, so this module is
 * Node-only — V8 isolates use `r.project(id).assets.putMany(items)` with
 * in-memory byte sources.
 */
import { Assets } from "../namespaces/assets.js";
import { LocalError } from "../errors.js";
import type { AssetPutEntryInput, AssetSpec, AssetSyncPruneConfirm, ContentSource, DeployEvent, LocalDirRef } from "../namespaces/deploy.types.js";
/**
 * SDK-input-only marker for "walk this directory at submission time." The
 * canonical type now lives in `deploy.types.ts` so the isomorphic SDK can
 * reference it from `SiteSpec` / `AssetSpec` without a dependency on this
 * Node-only module. Re-exported here for backwards compatibility with
 * `@run402/sdk/node` callers (and to keep `dir()` co-located with its
 * return type).
 *
 * The gateway never sees a `LocalDirRef` — submitting one in a JSON body
 * is rejected with HTTP 400 `INVALID_WIRE_SCHEMA`. The kind discriminator
 * `"local-dir"` is stable for type-narrowing.
 */
export type { LocalDirRef };
export interface DirOptions {
    /** Optional key prefix applied to every walked entry. `"static/"` →
     *  every file's relative path becomes `"static/<path>"`. */
    prefix?: string;
    /** Additional file/dir names to skip at any depth. Merged with the
     *  defaults (`.git`, `node_modules`, `.DS_Store`, and sensitive
     *  filenames unless `includeSensitive: true`). */
    ignore?: ReadonlyArray<string>;
    /** Opt in to collecting `.env`-style files. Same semantics as
     *  `fileSetFromDir`. */
    includeSensitive?: boolean;
}
/**
 * Build a `LocalDirRef` for the given filesystem path. Synchronous — the
 * actual filesystem walk happens at `apply()` submission time per design
 * D12 ("dir(path) returns synchronous LocalDirRef; SDK-input-only").
 *
 * Accepted as `site.replace` and `site.patch.put` on `r.project(p).apply`.
 * For assets, use `r.project(p).assets.uploadDir(path)` /
 * `syncDir` / `prepareDir` — those wrap a `LocalDirRef` walk into the
 * unified-apply pipeline with directory-specific options (prune, prepare,
 * progress events).
 *
 * @example
 *   import { dir, run402 } from "@run402/sdk/node";
 *   const r = run402();
 *   await r.project(p).apply({
 *     site: dir("./dist"),
 *   });
 *   await r.project(p).assets.uploadDir("./assets", { prefix: "static/" });
 */
export declare function dir(path: string, opts?: DirOptions): LocalDirRef;
/**
 * Walk a `LocalDirRef` and emit `AssetPutEntryInput[]` carrying a
 * `ContentSource` per file (rather than a pre-computed SHA). The actual
 * hashing + byte-reader registration happens inside the SDK's
 * `normalizeAssetSlice` pipeline so the bytes are uploaded via the shared
 * `byteReaders` map (v1.48 unified-apply). Returning wire-shaped entries
 * here would skip byte-reader registration and the deploy would fail with
 * `Missing bytes for sha=<...>` at upload time.
 *
 * The prefix is applied to relative keys. content_type/visibility/immutable
 * are left to the normalizer's defaults (visibility=public, immutable=true,
 * content_type derived from extension).
 */
export declare function entriesFromLocalDir(ref: LocalDirRef): Promise<AssetPutEntryInput[]>;
export interface AssetManifestEntry {
    key: string;
    sha256: string;
    size_bytes: number;
    content_type: string;
    visibility: "public" | "private";
    url: string | null;
    immutable_url: string | null;
    cdn_url: string | null;
    cdn_immutable_url: string | null;
    sri: string | null;
    etag: string | null;
    content_digest: string | null;
}
export interface AssetManifestTotals {
    files: number;
    bytes_uploaded: number;
    bytes_reused: number;
    duration_ms: number;
}
/**
 * Batch asset operation result (per design D9). `list` and `byKey`
 * share the same `AssetManifestEntry` instances in memory; `manifest`
 * is a plain-data shallow copy suitable for JSON serialization.
 * `byKey` and `manifest` are constructed with `Object.create(null)` so
 * attacker-controlled keys like `__proto__` don't collide with
 * `Object.prototype`.
 *
 * Note: v1.48 surfaces plain-data entries (URLs + sha + metadata) only.
 * The richer `AssetRef` shape with HTML tag emitters lands once the
 * gateway plan-response enrichment is wired (Phase 3.5 follow-up).
 */
export interface AssetManifest {
    list: AssetManifestEntry[];
    byKey: Record<string, AssetManifestEntry>;
    manifest: Record<string, AssetManifestEntry>;
    totals: AssetManifestTotals;
    /** Present when `syncDir({ prune: true })` ran. */
    pruned?: string[];
}
export interface PutManyItem {
    key: string;
    source: ContentSource;
    contentType?: string;
    visibility?: "public" | "private";
    immutable?: boolean;
    /** v1.50: per-item caller-provided metadata. Same shape and validation
     *  as {@link AssetPutEntryInput.metadata}. */
    metadata?: Record<string, string | number | boolean | string[]>;
    /** v1.50: per-item EXIF policy override. */
    exifPolicy?: "keep" | "strip";
}
export interface UploadDirOptions extends DirOptions {
    /** Project id the apply targets. */
    project: string;
    /** Optional progress callback. */
    onEvent?: (event: DeployEvent) => void;
    /** v1.50: default metadata applied to every entry walked from the
     *  directory. Per-call default — entries that need per-key metadata
     *  should use {@link NodeAssets.putMany} instead. */
    metadata?: Record<string, string | number | boolean | string[]>;
    /** v1.50: default EXIF policy applied to every entry walked from the
     *  directory. */
    exifPolicy?: "keep" | "strip";
}
export interface SyncDirOptions extends UploadDirOptions {
    /** Without `prune: true`, behaves additively (equivalent to
     *  `uploadDir`). With `prune: true`, the apply is destructive and
     *  requires a confirmation token from a prior plan call. */
    prune?: boolean;
    /** When the caller already has a confirmation block from a prior plan,
     *  passing it commits in one round-trip. Without it on a destructive
     *  call, the SDK throws `LocalError` with code
     *  `PRUNE_CONFIRMATION_REQUIRED` carrying the values to acknowledge. */
    confirm?: AssetSyncPruneConfirm;
}
export interface PrepareDirOptions extends DirOptions {
    /** Project id the apply targets. */
    project: string;
}
/**
 * Error thrown by `syncDir({ prune: true })` when called without a
 * `confirm` token. Carries the values the caller must echo back to
 * commit the destructive operation. The SDK auto-throws this before the
 * destructive apply lands so the agent has a chance to surface the
 * planned delete set to the user.
 */
export declare class PruneConfirmationRequired extends LocalError {
    readonly code: "PRUNE_CONFIRMATION_REQUIRED";
    readonly base_revision: string;
    readonly delete_set_digest: string;
    readonly expected_delete_count: number;
    readonly sample_keys: string[];
    constructor(args: {
        base_revision: string;
        delete_set_digest: string;
        expected_delete_count: number;
        sample_keys: string[];
    });
}
export declare class NodeAssets extends Assets {
    /**
     * Additive directory upload. Existing keys under the (optional) prefix
     * that aren't in the new directory are left untouched. Per design
     * D10. Wraps `r._applyEngine.apply({ project, assets: { put: ... } })`.
     */
    uploadDir(path: string, opts: UploadDirOptions): Promise<AssetManifest>;
    /**
     * Declarative directory sync. Per design D10:
     * - Without `prune: true`, behaves identically to {@link uploadDir}
     *   (additive only).
     * - With `prune: true` AND no `confirm` token, runs a plan first and
     *   throws {@link PruneConfirmationRequired} carrying the values the
     *   caller must echo back to commit.
     * - With `prune: true` AND a `confirm` token, commits the destructive
     *   sync. The gateway's activation-time drift check
     *   (`ASSET_SYNC_DRIFT`) catches the narrower race where inventory
     *   mutates between commit and activation.
     */
    syncDir(path: string, opts: SyncDirOptions): Promise<AssetManifest>;
    /**
     * Pre-commit URL injection helper (design D8 / spec Requirement
     * "assets.prepareDir"). Runs a plan against `r.project(id).apply.plan`
     * and returns `{ manifest, applySlice }` so the caller can render HTML
     * against the final resolved URLs and submit the same `applySlice` to
     * the commit step without re-uploading. Currently a thin shim — the
     * full plan-response enrichment lands in a follow-up.
     */
    prepareDir(path: string, opts: PrepareDirOptions): Promise<{
        manifest: AssetManifest;
        applySlice: AssetSpec;
    }>;
    /**
     * In-memory batch upload. Each item carries the key + an in-memory
     * `ContentSource` (string, Uint8Array, ArrayBuffer, Blob). SHA-256 is
     * computed locally, then a single apply call submits all entries.
     * Returns `AssetManifest`.
     */
    putMany(items: PutManyItem[], opts: {
        project: string;
        onEvent?: (event: DeployEvent) => void;
    }): Promise<AssetManifest>;
    /**
     * Internal: instantiate a Deploy (engine) bound to the same Client
     * this Assets instance was constructed with. Avoids requiring a
     * separate apply-engine parameter on the namespace constructor.
     */
    private applyEngine;
}
//# sourceMappingURL=assets-node.d.ts.map