import type { ByteSource } from '../../io/types.ts';
import type { Accessor } from '../../accessor/base.ts';
import { type ConditionSupport, type KnownVersions, type WriteCondition } from '../../cache/types.ts';
import type { StaleWriteError } from '../../errors/types.ts';
import type { DirListing, FileStat, PathSpec } from '../../types.ts';
import type { ConditionLostError } from './errors.ts';
export type ReaddirFn<A extends Accessor> = (accessor: A, path: PathSpec, limit?: number) => Promise<FileStat[] | DirListing>;
export type TreeFn<A extends Accessor> = (accessor: A, path: PathSpec, limit?: number) => Promise<Map<string, FileStat> | null>;
export type StatFn<A extends Accessor> = (accessor: A, path: PathSpec) => Promise<FileStat>;
export type ExistsFn<A extends Accessor> = (accessor: A, path: PathSpec) => Promise<boolean>;
export type PathFn<A extends Accessor> = (accessor: A, path: PathSpec) => Promise<void>;
export type CreateFn<A extends Accessor> = (accessor: A, path: PathSpec) => Promise<FileStat | null>;
export type PairFn<A extends Accessor> = (accessor: A, src: PathSpec, dst: PathSpec) => Promise<void>;
export type WriteFn<A extends Accessor> = (accessor: A, path: PathSpec, data: ByteSource, signal?: AbortSignal) => Promise<FileStat | null>;
export type MkdirFn<A extends Accessor> = (accessor: A, path: PathSpec, parents?: boolean) => Promise<void>;
export type TruncateFn<A extends Accessor> = (accessor: A, path: PathSpec, length: number, noCreate?: boolean) => Promise<FileStat | null>;
/**
 * One entry a driver saw while listing the immediate children of a
 * prefix.
 *
 * `marker` entries carry no name of their own (the zero-byte marker
 * keyed at the listed prefix itself, or a key the delimiter listing
 * cannot classify); they still prove the prefix holds a key, which is
 * what separates an empty directory from a missing one.
 */
export interface ChildEntry {
    /** Raw backend key, no trailing slash for files and directories. */
    key: string;
    /** File, directory, or a key that only proves existence. */
    kind: 'f' | 'd' | 'marker';
    /** File byte size; null/absent when the store did not report one. */
    size?: number | null;
    /** ISO-8601 mtime; empty/absent when unknown. */
    modified?: string;
}
/** One key of a recursive listing, directory markers included. */
export interface TreeEntry {
    /** Raw backend key; a directory marker keeps its trailing slash. */
    key: string;
    /** Byte size; markers report 0 and may omit it. */
    size?: number;
    modified?: string;
}
/** What a point lookup of one key returned. */
export interface ObjectMeta {
    /** Byte size of the object; null when the store omitted it. */
    size: number | null;
    /** ISO-8601 mtime, when the store has one. */
    modified?: string | null;
    /** Content identity (ETag, revision id). */
    fingerprint?: string | null;
    /** Addressable revision id, when the store versions objects. */
    revision?: string | null;
    /** Backend-shaped stat extras, forwarded into `FileStat.extra` verbatim. */
    extra?: Record<string, string>;
}
/**
 * One open connection a kit op holds for its whole body.
 *
 * Python's driver exposes `connect` as an async context manager; the
 * TS equivalent is this open/close handle consumed with try/finally.
 * The existing `withClient(config, fn)` callback style was not reused
 * because a callback cannot live in a record field without fixing the
 * callback's return type, and the handle lets every kit op scope one
 * connection over listings, probes and mutations alike. A store that
 * keeps a live client on its accessor returns the accessor itself with
 * a no-op close.
 */
export interface ObjectStoreConnection<C> {
    conn: C;
    close: () => Promise<void>;
}
/**
 * The native surface of one keyed byte store.
 *
 * Everything above this line — readdir with its index write-back,
 * stat's probe ladder, find's implicit-directory synthesis, du, and
 * the mutation family — derives from
 * these primitives in `core/object_store`; a backend supplies only
 * the raw store calls.
 *
 * Directory semantics the primitives must honor: a directory is a key
 * prefix, an empty directory is a zero-byte marker object keyed at the
 * prefix itself (`key/`) on stores that accept one (`markersSupported`),
 * and symlinks or hardlinks do not exist — ops that would need them
 * stay unwired, which the dispatcher already surfaces as ENOTSUP.
 */
export interface ObjectStoreDriver<A extends Accessor, C> {
    readonly conditionSupport?: ConditionSupport;
    /** VFS name, used in op records and log lines. */
    vfs: string;
    /** Listing size above which readdir logs a warning. */
    scopeError: number;
    /** Mount key prefix from the accessor's config ('' for the whole store). */
    keyPrefixOf: (accessor: A) => string;
    /** Per-op connection handle; see {@link ObjectStoreConnection}. */
    connect: (accessor: A) => Promise<ObjectStoreConnection<C>>;
    /**
     * One-level listing of a prefix as {@link ChildEntry} items; may
     * repeat directories, the kit deduplicates.
     */
    listChildren: (conn: C, pfx: string) => AsyncIterable<ChildEntry>;
    /**
     * The key at `stem` itself plus every key under `stem + '/'` — du's
     * walk, which must not match sibling keys sharing the stem as a
     * name prefix.
     */
    listSubtree: (conn: C, stem: string) => AsyncIterable<TreeEntry>;
    /**
     * Point lookup of one key, null when absent; a key the store refuses this
     * caller throws EACCES, which stat and mkdir check against `probePrefix`; other
     * classification failures propagate.
     */
    head: (conn: C, key: string) => Promise<ObjectMeta | null>;
    /** Full object bytes, null when absent. */
    get: (conn: C, key: string) => Promise<Uint8Array | null>;
    /**
     * Write one object, returning what the store's write response said
     * about it, or null when the store's write API reports nothing at all
     * (opendal). The meta is partial: `size` is the bytes written and
     * `fingerprint` is the store's token, spelled exactly as `head` spells
     * it so the two can be compared; `modified` is absent, because no
     * store's write response carries one. A response without a token can
     * still confirm size. The write factory returns these facts as a
     * FileStat for index retention.
     * A store error meaning the container is absent
     * (`isNotFound`) propagates, and the write factory restates it as
     * ENOENT on the path.
     */
    put: (conn: C, key: string, data: Uint8Array) => Promise<ObjectMeta | null>;
    /**
     * Delete one key (every revision on a versioned store); silent on a
     * missing key.
     */
    deleteFile: (conn: C, key: string) => Promise<void>;
    /** Delete every key under a prefix. */
    deletePrefix: (conn: C, pfx: string) => Promise<void>;
    /** Whether any key sits under a prefix; a refused listing throws EACCES. */
    probePrefix: (conn: C, pfx: string) => Promise<boolean>;
    /** Whether a store error means the key is absent. */
    isNotFound: (err: unknown) => boolean;
    /**
     * Relocate one object; false when the source names no object. Absent
     * when the store has no native move — rename stays unwired then,
     * which the dispatcher surfaces as ENOTSUP.
     */
    moveFile?: (conn: C, srcKey: string, dstKey: string) => Promise<boolean>;
    /**
     * Relocate every key under a prefix; false when the source prefix
     * holds nothing. Absence follows `moveFile`.
     */
    movePrefix?: (conn: C, srcPfx: string, dstPfx: string) => Promise<boolean>;
    /**
     * Copy one object; false when the source names no object, if the
     * store can tell cheaply. Absent when the store has no native copy —
     * copy stays unwired then.
     */
    copyFile?: (conn: C, srcKey: string, dstKey: string) => Promise<boolean>;
    /**
     * Point lookup of one revision of a key by the token `head` spells, null
     * when it is gone. A stat pinned by a snapshot asks this, so a revision
     * the store still holds under another name (a trash, a version) answers.
     */
    headRevision?: (conn: C, key: string, revision: string) => Promise<ObjectMeta | null>;
    /**
     * Whether the store accepts the zero-byte `key/` marker object;
     * absent means true. False when the store refuses one client-side
     * (hf): an empty directory cannot exist there, `makeMkdir` has
     * nothing to write, and a directory exists exactly while it holds a
     * key.
     */
    markersSupported?: boolean;
    /**
     * `put` carrying a write condition; a lost one throws `ConditionLostError`.
     * Absent when the store cannot condition a write.
     */
    putStream?: (conn: C, key: string, data: ByteSource, cond: WriteCondition) => Promise<ObjectMeta>;
    putIf?: (conn: C, key: string, data: Uint8Array, cond: WriteCondition) => Promise<ObjectMeta | null>;
    /** `get` plus the token of the bytes returned, for an op that writes back what it read; a revision reads that revision. */
    getVersioned?: (conn: C, key: string, revision: string | null) => Promise<[Uint8Array, string | null] | null>;
    /** `copyFile` with the destination's condition. */
    copyIf?: (conn: C, srcKey: string, dstKey: string, cond: WriteCondition) => Promise<boolean>;
    /** `deleteFile` with a condition. */
    deleteIf?: (conn: C, key: string, cond: WriteCondition) => Promise<void>;
    /**
     * `moveFile` whose copy and delete are both conditioned on the source's
     * version (the one given, else the one its own lookup sees), and whose
     * copy carries the destination's.
     */
    moveFileIf?: (conn: C, srcKey: string, dstKey: string, cond: WriteCondition, source: string | null) => Promise<boolean>;
    /**
     * `movePrefix` moving each key only if it is still the version the mount
     * saw (`known`), else the one listed, onto a destination key the mount
     * holds a version for (`dstKnown`) only if it is still that version; the
     * keys that changed stay where they were and are thrown in a ConditionLostError,
     * and one changed before its copy keeps every source key where it was.
     */
    movePrefixIf?: (conn: C, srcPfx: string, dstPfx: string, known: KnownVersions, dstKnown: KnownVersions) => Promise<boolean>;
    /**
     * `deletePrefix` deleting each key only if it is still the version the
     * mount saw, else the one listed.
     */
    deletePrefixIf?: (conn: C, pfx: string, known: KnownVersions) => Promise<void>;
}
/** The refusal for a one-path op whose condition lost. Mirrors Python's `refused`. */
export declare function refused(path: PathSpec, err: ConditionLostError, cond: WriteCondition | null): Promise<StaleWriteError>;
/**
 * Keep every lost key's version, then throw the walk's later error. Mirrors
 * Python's `keep_all_lost`.
 */
export declare function keepAllLost(root: PathSpec, keyPrefix: string, err: ConditionLostError): Promise<never>;
/**
 * Keep what a walk's refusal measured, and name the key it reports: every
 * lost key but the named one keeps its version; a later error that stopped
 * the walk is thrown instead, with every version kept. Mirrors Python's
 * `keep_walk`.
 */
export declare function keepWalk(root: PathSpec, keyPrefix: string, err: ConditionLostError): Promise<string>;
/**
 * Keep the version of each key a walk lost on, except `skip`, which the
 * refusal itself names and keeps. A key found gone keeps what the session
 * last saw of it. Mirrors Python's `keep_lost`.
 */
export declare function keepLost(root: PathSpec, keyPrefix: string, err: ConditionLostError, skip: string | null): Promise<void>;
/**
 * The `*If` hook a conditional op calls. Every `write: conditional` object
 * store is on the S3 driver, which carries them all; Box and Dropbox condition
 * their own ops and never reach here.
 */
export declare function requireHook<F>(hook: F | undefined): F;
/**
 * Whether a prefix holds a child, as `readdir` would list one. The prefix's
 * own marker is no child: it proves only that the directory exists, and one
 * made again after a removal is a later `mkdir`, not a key the removal
 * missed. The listing stops at the first child. Mirrors Python's
 * `holds_child`.
 */
export declare function holdsChild<A extends Accessor, C>(driver: ObjectStoreDriver<A, C>, conn: C, pfx: string): Promise<boolean>;
//# sourceMappingURL=driver.d.ts.map