/**
 * artifacts/objectStore — the half every REMOTE OBJECT adapter shares.
 *
 * Two adapters put artifacts in somebody else's bucket. They speak different
 * SDKs and dispatch different operations, and that is exactly where a vendor
 * belongs — but the laws they follow must not fork, so the laws live here:
 *
 *   1. **The payload is the object body, and it is the CANONICAL BYTES** —
 *      the same bytes `meta.bytes` counts and a digest covers. Not a JSON
 *      envelope wrapping base64: a stored report should be downloadable with
 *      the vendor's own console and be the report. That choice is also what
 *      makes `getStream` possible at all — a body you have to parse is a body
 *      you cannot stream.
 *   2. **The meta rides as ONE object-metadata entry** ({@link ARTIFACT_META_KEY}),
 *      an ASCII-safe JSON envelope. One key, one truth: a "helpful" second
 *      copy of `kind` in a sibling field is a second thing that can disagree.
 *      ASCII because user metadata travels as an HTTP header on at least one
 *      of these services — a label with an em-dash in it must not be
 *      mangled at the transport — and JSON-with-escapes rather than base64
 *      because an operator reading the console should be able to SEE what the
 *      ticket says.
 *   3. **The metadata budget is checked at put and REFUSED by name.** Both
 *      services cap user metadata (the caps differ; each adapter states its
 *      own). A refusal that names the field to shorten beats a vendor's
 *      "MetadataTooLarge" at document 400, and beats silent truncation
 *      always.
 *   4. **Missing means null; unreadable means an error.** A 404 is the
 *      port's deliberate "no data" ambiguity — but only when the call ASKED
 *      ABOUT ONE OBJECT. A write and a listing do not ask that question, so a
 *      404 from one of them is the service saying something else entirely (the
 *      bucket does not exist, the endpoint is wrong); nobody downstream turns
 *      it into `null`, so letting it past the sanitizer hands the caller the
 *      SDK's own text — which contains the object key. That is what
 *      {@link NotFoundMeaning} makes each call site declare, and why the
 *      default is the safe one. Anything else — denied, throttled, a network
 *      failure — is NOT "no data" either, and answering `null` for it would
 *      report an empty scope over objects that exist. Each adapter maps its
 *      own SDK's missing-object shape; everything else raises through
 *      {@link objectSdkFailure}.
 *   5. **Listings order by the SERVICE's own creation time**, which comes back
 *      free on a listing, and page by offset over that sorted list. The port
 *      promises newest-first ACROSS pages; a bucket's key order is
 *      lexicographic, so a cursor that was the service's own continuation
 *      token would page in the wrong order and call it paging.
 *
 * Nothing in this file imports an SDK, names a vendor, or knows a wire
 * format. It is the part of an object adapter that can be unit-tested with
 * nothing but strings.
 */
import type { PayloadShape } from './payload.js';
import { type ArtifactListOptions, type ArtifactListResult, type ArtifactMeta } from './types.js';
/** The single object-metadata key that carries the ticket. */
export declare const ARTIFACT_META_KEY = "af-artifact";
/**
 * Encode a ticket for the object's metadata, refusing one that will not fit.
 *
 * @param meta    the minted ticket.
 * @param shape   how the payload must be rebuilt from the body's bytes.
 * @param budget  the service's user-metadata cap, in bytes.
 * @param adapter the factory name, for the refusal.
 * @throws InvalidArtifactError when the encoded ticket exceeds the budget —
 *         naming the fields that are big enough to be the reason.
 */
export declare function encodeArtifactMetaValue(meta: ArtifactMeta, shape: PayloadShape, budget: number, adapter: string): string;
/**
 * Read a ticket back off an object's metadata.
 *
 * `undefined` for anything this runtime must not interpret: no entry (not
 * ours — a foreign object in a shared bucket is left alone), unparseable, a
 * newer envelope version, or a ref that is not a minted ref. Refusing to
 * interpret is the point: a half-read ticket would be a confident description
 * of the wrong thing.
 */
export declare function decodeArtifactMetaValue(value: unknown): {
    readonly meta: ArtifactMeta;
    readonly shape: PayloadShape;
} | undefined;
/** Case-insensitive lookup in a metadata bag. At least one of these services
 *  lower-cases user-metadata keys in transit, so the key written and the key
 *  read back are not guaranteed to be the same string. */
export declare function readMetadataEntry(bag: Record<string, unknown> | undefined, key: string): unknown;
/** Has the calendar passed this ticket? The one expiry predicate both object
 *  adapters use, so "expired" cannot mean two things. */
export declare function isExpiredMeta(meta: ArtifactMeta, now: number): boolean;
/**
 * Re-raise a failed SDK call WITHOUT its text (the `sdkFailure` law, applied
 * to object storage).
 *
 * A cloud SDK reports transport and validation failures by echoing request
 * detail into the message: the bucket, the KEY — which here contains the
 * tenant, the principal and the conversation id — and sometimes a signed URL
 * or a header the request carried. This library then hands that string to the
 * LLM as a tool result, puts it on the commit log, and ships it to every sink
 * attached. One echo and the scope tuple is in the conversation.
 *
 * So the text does not come through. What does is the part that is both safe
 * and actionable: which operation failed, the exception's NAME, and the HTTP
 * status. The original is deliberately NOT attached as `cause` — a cause
 * travels into every serializer that walks own properties, which would undo
 * all of this in one `JSON.stringify`.
 */
export declare function objectSdkFailure(adapter: string, operation: string, err: unknown): Error;
/**
 * What a "not found" from ONE call is allowed to mean.
 *
 * The distinction is not academic: it decides whether an SDK error object
 * leaves this library intact.
 *
 * • `'missing-object'` — the call named one object and asked whether it is
 *   there. Not-found is the port's deliberate "no data", so the SDK's own
 *   error travels back to the CALL SITE, which immediately converts it to
 *   `null`/`undefined`. It never leaves the adapter, so its text never reaches
 *   an event, a log, or a model.
 *
 * • `'not-an-answer'` — the call asked no such question (it wrote, or it
 *   listed). A not-found here means something the caller did not ask about is
 *   wrong — most often that the bucket itself is not there — and NOTHING
 *   downstream is waiting to convert it. It goes through
 *   {@link objectSdkFailure} like every other failure.
 *
 * This is the DEFAULT for exactly that reason: a call site that says nothing
 * gets the sanitizer. Leaking has to be typed out on purpose, next to the
 * `catch` that proves the error is caught.
 */
export type NotFoundMeaning = 'missing-object' | 'not-an-answer';
/**
 * The one gate every object adapter runs its SDK failures through.
 *
 * Returns what to throw — the sanitized error for anything the caller is not
 * standing by to interpret, the original ONLY for a genuine missing object at
 * a call site that declared it asks about one, and our own refusals verbatim
 * (an {@link InvalidArtifactError} is this library's sentence, already written
 * for a human, and re-wrapping it would replace a teaching refusal with a
 * transport complaint).
 *
 * Built once per adapter so the vendor's not-found detection is bound in one
 * place: two call sites in the same adapter cannot end up disagreeing about
 * what "missing" looks like.
 *
 * @param adapter        the factory name, for the message.
 * @param isMissingObject the adapter's own reading of its SDK's
 *                       "no such object" — the one genuinely per-vendor part.
 */
export declare function objectFailurePolicy(adapter: string, isMissingObject: (err: unknown) => boolean): (operation: string, err: unknown, meaning: NotFoundMeaning) => unknown;
/** One row of a scope listing, before the tickets are paged. */
export interface ObjectListingRow {
    readonly meta: ArtifactMeta;
    /** The service's own creation time for the object (ms). The sort key —
     *  see law 5 in the module header. */
    readonly serviceCreatedAt: number;
}
/**
 * The port's paging law over a scope's rows: newest first, offset cursor.
 *
 * Sorted by the SERVICE's creation time (falling back to the ticket's own
 * `createdAt` when a listing did not carry one), ties broken by ref so two
 * objects written in the same millisecond still page deterministically.
 */
export declare function pageObjectListing(rows: readonly ObjectListingRow[], options: ArtifactListOptions | undefined): ArtifactListResult;
/** The offset a cursor names. Total: a cursor this store did not mint reads
 *  as "start at the beginning" rather than as an error — a caller cannot
 *  learn anything about another scope by guessing one. */
export declare function decodeOffsetCursor(cursor: string | undefined): number;
/** Validate a bucket name option at construction — the same shape of refusal
 *  every adapter here gives for a missing required option. */
export declare function assertBucketOption(adapter: string, option: string, value: unknown): string;
