/*! * Copyright (c) 2026 Interop Alliance. All rights reserved. */ /** * JSON-vs-binary detection and body coercion for resource writes, plus * content-type-aware parsing for resource reads. A plain object/array is sent * as JSON; a `Blob`/`Uint8Array`/`Buffer` is sent as binary, with the * content-type taken from `options.contentType`, the `Blob.type`, a guess from * the resource id's file extension (`options.filename`), or * `application/octet-stream`. */ import type { HttpResponse } from '@interop/http-client'; import type { ResponseLike } from '../codec.js'; import type { Json, ResourceData } from '../types.js'; /** * The shared `TextEncoder` (stateless, so one instance serves the whole * library): serializing an explicitly-typed JSON write to bytes here, * re-serializing a pre-parsed JSON body in `Resource.getBytes()`, and encoding * EDV envelope bytes (re-exported by `edv/constants.ts`). */ export declare const ENCODER: TextEncoder; /** * The shared `TextDecoder` (stateless in its default non-fatal, non-streaming * mode, so one instance serves the whole library): reading back UTF-8 bodies * that were written through {@link ENCODER} -- envelope bytes on the EDV write * path, protected-header bytes on the read path. */ export declare const DECODER: TextDecoder; /** * Whether a content type denotes UTF-8-safe text that should be stored inline as * a plain string (legible, no ~33% base64 inflation) rather than as opaque * binary -- `text/*`, plus the XML/SVG family that is textual despite an * `application/` or `image/` prefix (`application/xml`, any `+xml` structured * suffix such as `image/svg+xml` / `application/atom+xml`). Kept deliberately * narrow: an unlisted type is treated as binary (base64), which is always * byte-safe, and the caller additionally gates on valid UTF-8 before choosing * text. Any `; charset=...` parameter is ignored. * * @param contentType {string} * @returns {boolean} */ export declare function isTextContentType(contentType: string): boolean; /** * Guesses a content-type from a resource id's file extension, limited to the * static-web types in `WEB_CONTENT_TYPES`. Returns `undefined` when the id has * no extension, is a leading-dot dotfile (e.g. `.gitignore`), or carries an * unrecognized extension -- never a generic fallback, so the caller stays in * control of a miss. * * @param id {string} the resource id (often a filename like `index.html`) * @returns {string | undefined} */ export declare function guessContentTypeFromId(id: string): string | undefined; /** * A write body resolved into either a JSON payload (passed to ezcap as `json`) * or a binary payload with its content-type (passed as `body` + header). */ interface PreparedBody { json?: object; body?: Uint8Array | Blob; contentType?: string; } /** * Whether a value is a `Blob`, guarding for environments where `Blob` is * undefined. * * @param value {unknown} * @returns {boolean} */ export declare function isBlob(value: unknown): value is Blob; /** * Coerces a `Uint8Array` (including a Node `Buffer`, which is a subclass) to a * plain `Uint8Array` view, as ezcap's `body` type expects. * * @param bytes {Uint8Array} * @returns {Uint8Array} */ export declare function toPlainBytes(bytes: Uint8Array): Uint8Array; /** * Write data classified by `resolvePayload`: binary (a `Blob`/`Uint8Array` * with its resolved content-type), JSON (a plain object/array), or invalid (a * bare primitive -- the caller throws its own error message). */ type ResolvedPayload = { kind: 'binary'; data: Blob | Uint8Array; contentType: string; } | { kind: 'json'; } | { kind: 'invalid'; }; /** * Classifies write data as binary or JSON and resolves the binary * content-type -- the single source of the detection and precedence rules * shared by the plaintext `prepareBody` and the EDV codec's document builder. * * The binary content-type resolves in precedence order: an explicit * `contentType`, then a non-empty `Blob.type`, then a guess from the resource * `id`'s extension, then `application/octet-stream`. (Coalescing with `||` * rather than `??` so an empty-string `Blob.type` -- a typeless Blob -- falls * through to the guess instead of becoming an empty content-type.) * * @param options {object} * @param options.data {ResourceData} the resource content * @param [options.contentType] {string} overrides the inferred content-type * for binary data * @param [options.id] {string} resource id used to guess a * content-type by extension when none is given (binary data only) * @returns {ResolvedPayload} */ export declare function resolvePayload({ data, contentType, id }: { data: ResourceData; contentType?: string; id?: string; }): ResolvedPayload; /** * Inspects write data and resolves it to a JSON or binary payload, using * {@link resolvePayload} for the detection and content-type precedence rules. * * @param data {ResourceData} the resource content * @param options {object} * @param [options.contentType] {string} overrides the inferred content-type * for binary data * @param [options.filename] {string} resource id used to guess a * content-type by extension when none is given (binary data only) * @returns {PreparedBody} */ export declare function prepareBody(data: ResourceData, options?: { contentType?: string; filename?: string; }): PreparedBody; /** * Extracts the id of a just-created resource from a create response, together * with the raw `Location` header it carried (if any). Prefers the response * body's `id`; for a body-less 2xx falls back to the last path segment of the * `Location` header (decoded, since the server emits a percent-encoded path). * Throws a `WasServerError` when the response carries neither -- a malformed * create response -- rather than letting an absent body surface as a raw * `TypeError` on `data.id`. * * The header is read once and returned verbatim so a caller that also needs * the created resource's URL (`Collection.add`, which resolves it against the * items URL) does not re-read and re-parse it. * * @param response {HttpResponse | null} * @returns {{ id: string; location?: string }} */ export declare function createdResource(response: HttpResponse | null): { id: string; location?: string; }; /** * The id of a just-created resource -- {@link createdResource} for callers that * need only the id. * * @param response {HttpResponse | null} * @returns {string} */ export declare function createdId(response: HttpResponse | null): string; /** * Unwraps a read response's pre-parsed JSON `data` as `T`, mapping a `null` * response (a 404 that a `read` request resolved to `null`) to `null`. The * http-client leaves `data` undefined for a non-JSON content-type or a 204; * that is also mapped to `null`, so the declared `T | null` is correct and a * caller never dereferences `undefined` cast as `T`. * * @param response {HttpResponse | null} * @returns {T | null} */ export declare function dataOrNull(response: HttpResponse | null): T | null; /** * Reads a JSON response body, preferring the http-client's pre-parsed `data` * and falling back to `response.json()` when it is absent. * * `@interop/http-client` pre-consumes the body into `.data` for JSON * content-types, so a stored top-level `null` arrives as `.data === null`. * Test for `undefined` rather than using `??`; otherwise the nullish fallback * would re-invoke `.json()` on the already-consumed stream and throw. * * @param response {ResponseLike} * @returns {Promise} */ export declare function readJsonData(response: ResponseLike): Promise; /** * Presents an already-in-hand stored body to the codec seam as the * {@link ResponseLike} the seam is typed against. Used wherever a body arrives * outside the ordinary GET path -- a local replica's envelope, or one of the * documents a search returned inline -- so those callers need no fake response * object. The headers stub resolves an ETag lookup to "no validator", which is * accurate: such a body carries no version of its own. * * @param body {unknown} the stored body * @returns {ResponseLike} */ export declare function storedResponse(body: unknown): ResponseLike; /** * Parses a resource GET response: returns the parsed object when the stored * content-type is JSON, otherwise a `Blob` whose `.type` carries the * content-type. A `null` response (404) passes through as `null`. * * @param response {HttpResponse | null} * @returns {Promise} */ export declare function parseResource(response: HttpResponse | null): Promise; export {}; //# sourceMappingURL=content.d.ts.map