/**
 * artifacts/s3Artifacts — the claim-check store in an S3 bucket.
 *
 * The third rung of the same ladder: `inMemoryArtifacts` for a test,
 * `fileArtifacts`/`sqliteArtifacts` for one machine, this for a fleet. Nothing
 * about the five verbs changes — a tool that stored a dataset against the
 * in-memory store stores it here by swapping one constructor, because the port
 * is the contract and this file is only a translation of it.
 *
 * Read `objectStore.ts` first: it holds the five laws both object adapters
 * obey (payload as canonical bytes in the body, ONE metadata entry carrying
 * the ticket, a checked metadata budget, 404-means-null-everything-else-means-
 * error, service-time ordering). What is genuinely S3's, and therefore lives
 * here:
 *
 * ── The object key ──────────────────────────────────────────────────────────
 * `[<prefix>/]<tenant>/<principal>/<conversation>/<ref>` — the scope
 * partitioned into key segments by `scopePath.ts`, the same percent-encoding
 * law the directory adapter uses, so a tenant of literally `'..'` is a NAME in
 * both. A ref alone opens nothing: a wrong scope computes a different key,
 * S3 answers 404, and the caller reads `null` — one indistinguishable miss,
 * never a cross-tenant read.
 *
 * ── The ticket rides as object metadata, not a sidecar ──────────────────────
 * `x-amz-meta-af-artifact`, one entry, ASCII JSON. Two reasons this beats a
 * second `<ref>.meta.json` object: `head()` becomes ONE HeadObject (the port
 * promises the render-by-ref decision without paying for the payload, and a
 * sidecar would make it a second GET), and `get()` returns the ticket AND the
 * bytes in a single GetObject — a sidecar would make every read two round
 * trips and open a window where one exists and the other does not.
 *
 * The cost is S3's cap: **2 KB of user metadata per object**, checked at put
 * and refused by name. A ticket is small (a ref, a kind, a media type, sizes,
 * a label); it only reaches 2 KB if the label is prose or `parentRefs` is a
 * bibliography, and the refusal says which.
 *
 * ── What a 404 is allowed to mean here ──────────────────────────────────────
 * S3 answers 404 for two different sentences: "no such key" and "no such
 * bucket". Only the first is the port's "no data", so this adapter reads the
 * CODE and not the status, and only the calls that named one object —
 * Head/Get/Delete — may read a 404 as `null` at all. A 404 from PutObject or
 * ListObjectsV2 means the bucket is not there; it goes through the sanitizer
 * like every other failure, because nothing downstream is waiting to turn it
 * into `null` and the SDK's text for it contains the object key.
 *
 * ── What a listing costs, said plainly ──────────────────────────────────────
 * `ListObjectsV2` returns keys, sizes and `LastModified` — never user
 * metadata. So `list()` pages the keys (cheap, 1000 per call), sorts by
 * `LastModified` (newest first, as the port promises), and issues one
 * `HeadObject` for each row IT RETURNS — not for the whole scope. An expired
 * object inside a page is dropped from that page rather than backfilled, so a
 * page can come back short while more pages remain. That is the honest trade;
 * an "index object" listing every ticket in a scope would be cheaper and
 * would be a lost-update race between two writers, which is worse than a
 * round trip.
 *
 * ── Retention, and the operator's bulk tool ─────────────────────────────────
 * The dials work exactly as everywhere else: `ttlMs` stamps `expiresAt` AT
 * MINT (stated, never sprung), and budgets evict oldest-first (S3 has no cheap
 * read-recency, the same statement `fileArtifacts` makes). Two S3-specific
 * facts:
 *
 *   • **Expiry is enforced on READ.** An expired object answers `null` from
 *     `head`/`get` and is deleted on the way past (a sweep on access), so an
 *     expired ticket can never be redeemed even if the object is still there.
 *   • **A put only SCANS the scope when a budget is configured.** With no
 *     `maxBytesPerScope`/`maxCountPerScope` there is nothing to plan, so a put
 *     is exactly one `PutObject` — and paying for a full scope listing on
 *     every write would be a real bill for no answer.
 *
 * Which leaves reclamation of storage for artifacts nobody reads again — and
 * that is what **S3 Lifecycle rules** are for. They are the operator's bulk
 * tool and this adapter does not create them (a lifecycle rule is a cost and
 * compliance decision that belongs to your infrastructure). Align them like
 * this:
 *
 * ```jsonc
 * // Expire objects 7 days after creation, under the store's prefix.
 * // Keep the rule LONGER than the store's ttlMs, never shorter:
 * // the store's expiresAt is the promise consumers read on the ticket, and a
 * // lifecycle rule that deletes first makes a live ticket resolve to null
 * // BEFORE the time it printed. Longer, and lifecycle is what it should be:
 * // the backstop that reclaims what the store's own sweep never revisited.
 * { "Rules": [{ "ID": "agentfootprint-artifacts", "Status": "Enabled",
 *               "Filter": { "Prefix": "artifacts/" },
 *               "Expiration": { "Days": 7 } }] }
 * ```
 *
 * ── Lazy peer dependency ────────────────────────────────────────────────────
 * `@aws-sdk/client-s3` is an OPTIONAL peer dependency, required at
 * CONSTRUCTION (the sqliteSessions law): importing the barrel costs a browser
 * bundle nothing, and a missing install refuses where the config was written
 * rather than at the first put of the first run. Pass `client` to share the
 * SDK configuration your app already has.
 *
 * ── Status ──────────────────────────────────────────────────────────────────
 * Contract-shaped and tested; awaiting field use. The five commands it
 * dispatches are pinned by `test/adapters/aws/aws-command-pin.test.ts`; the
 * behavior is proved against an emulation double that speaks the same five.
 * No live call has been made from this repository.
 */
import { type ArtifactRetention } from './retention.js';
import { type ArtifactStore } from './types.js';
/** A `*Client` as this adapter uses it: `send`, and nothing else. */
export interface S3ArtifactsClientLike {
    send(command: unknown): Promise<unknown>;
}
/** The five command constructors this adapter dispatches. */
export interface S3ArtifactsSdkModule {
    readonly S3Client?: new (config: {
        region?: string;
    }) => S3ArtifactsClientLike;
    readonly PutObjectCommand?: new (input: unknown) => unknown;
    readonly GetObjectCommand?: new (input: unknown) => unknown;
    readonly HeadObjectCommand?: new (input: unknown) => unknown;
    readonly DeleteObjectCommand?: new (input: unknown) => unknown;
    readonly ListObjectsV2Command?: new (input: unknown) => unknown;
}
/** Options for {@link s3Artifacts}. */
export interface S3ArtifactsOptions {
    /** The bucket. It must already exist — this library never creates one. */
    readonly bucket: string;
    /** Key prefix inside the bucket, so a bucket can be shared. The scope
     *  layout starts under it. Absent = at the root of the bucket. */
    readonly prefix?: string;
    /** Region for the client this factory builds. Ignored when `client` is
     *  passed — that client's configuration is yours. */
    readonly region?: string;
    /** Your own pre-built client; configuration and credentials stay yours. */
    readonly client?: S3ArtifactsClientLike;
    /** Retention dials. Budgets evict OLDEST-first here: S3 has no cheap
     *  read-recency, the same statement `fileArtifacts` makes about a
     *  directory. */
    readonly retention?: ArtifactRetention;
    /** @internal Test seam — the SDK module, injected. */
    readonly _sdk?: S3ArtifactsSdkModule;
    /** @internal Test seam — a client injected past the SDK entirely. */
    readonly _client?: S3ArtifactsClientLike;
    /** @internal Test seam — the clock. Defaults to `Date.now`. */
    readonly _now?: () => number;
}
/**
 * An artifact store in an S3 bucket.
 *
 * @example
 *   const store = s3Artifacts({ bucket: 'my-agent-artifacts', prefix: 'artifacts' });
 *   const agent = Agent.create({ provider, artifacts: store });
 */
export declare function s3Artifacts(options: S3ArtifactsOptions): ArtifactStore;
//# sourceMappingURL=s3Artifacts.d.ts.map