/*! * Copyright (c) 2026 Interop Alliance. All rights reserved. */ /** * The shared write orchestration. `sendEncodedWrite` turns a codec's * {@link EncodedWrite} plus a conditional-write precondition into request * headers and sends it (the shape `Collection.add` and `Resource.put` would * otherwise each re-implement). Two flows layer on top: `insertResource` (the * create path behind `Collection.add` -- encode, the minted-id `PUT` vs * server-minting `POST` branch, and the precondition selection) and * `upsertResource` (the write-by-id path behind `Resource.put` -- the * conditional-codec pre-read of the current document, the codec-vs-caller * precondition selection, and the masked-404 policy for a document that exists * but is not readable with the bound capability). * * A codec may also answer `encode` with a multi-request `ChunkedWrite` plan * rather than an `EncodedWrite`. `insertResource` runs the plan over the * signed-request context built here (`codecRequestContext`); `upsertResource` * refuses one, since auto-routing is an insert-path affordance. */ import type { HttpResponse } from '@interop/http-client'; import type { CodecRequestContext, EncodedWrite, ResourceCodec } from '../codec.js'; import type { IZcap, ResourceData } from '../types.js'; import type { ClientContext } from './request.js'; import type { FeatureProbe } from './features.js'; import type { WritePrecondition } from './conditional.js'; /** * Sends an encoded write (`PUT`/`POST`) to a resource path, applying the * encoded body (`json` or `body`), its content-type, and the conditional-write * precondition. A write is never a `read`, so the response is always present * (errors throw via `send`). * * @param context {ClientContext} * @param options {object} * @param options.path {string} the resource path to write * @param options.method {string} `PUT` or `POST` * @param options.encoded {EncodedWrite} the codec's encoded write * @param [options.capability] {IZcap} * @param [options.precondition] {WritePrecondition} conditional-write headers * @returns {Promise} */ export declare function sendEncodedWrite(context: ClientContext, { path, method, encoded, capability, precondition }: { path: string; method: string; encoded: EncodedWrite; capability?: IZcap; precondition?: WritePrecondition; }): Promise; /** * Builds the {@link CodecRequestContext} core hands a codec that drives its own * I/O: the signed-request primitive bound to this handle's capability, plus the * handle's memoized backend-feature probe. The codec never sees the zcap * machinery, and the raw `HttpResponse` it gets back matches the * `was.request()` escape hatch, which is what `WasTransport` consumes. * * Requests go through the same mapped `send` path the core write paths use, so * a codec-driven write fails with the typed `WasError` subclasses the calling * method documents (a document `PUT` that 404s is a `NotFoundError`, not a raw * ky/ezcap error). The typed errors carry the HTTP `status`, so a consumer that * dispatches on status keeps working. * * @param context {ClientContext} * @param options {object} * @param options.features {FeatureProbe} the handle's memoized backend-feature * probe * @param [options.capability] {IZcap} capability attached to each request * @returns {CodecRequestContext} */ export declare function codecRequestContext(context: ClientContext, { features, capability }: { features: FeatureProbe; capability?: IZcap; }): CodecRequestContext; /** * The outcome of {@link insertResource}: either the ordinary single-request * write (the codec's encoding, the path written, and the response) or the * result of a codec's multi-request {@link ChunkedWrite} plan, which has no one * canonical response. */ export type InsertOutcome = { chunked?: false; encoded: EncodedWrite; path: string; response: HttpResponse; } | { chunked: true; id: string; path: string; contentType?: string; etag?: string; }; /** * Creates a resource with a codec-minted or server-minted id (insert) through * its codec, owning the create orchestration in one place: the encode, the * `PUT`-vs-`POST` branch, and the precondition selection. * * A codec may also answer the encode with a multi-request plan (the EDV codec's * chunked blob write). The plan is then executed over the handle's signed * request context instead of being sent as one request; it owns its own * preconditions and feature gating. * * A codec that mints its own id (e.g. the encrypting codec's EDV id) writes it * by `PUT` to that id's path; a codec that mints none (the identity codec) * `POST`s to the items path and lets the server mint one. A conditional codec * computes the precondition itself (the EDV codec guards its fresh insert with * `If-None-Match: *`); an insert through a non-conditional codec is * unconditional, since `add()` names no target revision to pin against. * * Returns the codec's encoded write and the path actually written alongside the * response, so the caller can shape its result (the created id and URL) without * re-deriving either. * * @param context {ClientContext} * @param options {object} * @param options.itemsPath {string} the collection's items path, the * `POST` target when the codec mints no id * @param options.pathForId {function} builds the resource path for a * codec-minted id * @param options.codec {ResourceCodec} the collection's resolved codec * @param options.data {ResourceData} the plaintext value * @param options.features {FeatureProbe} the handle's shared backend-feature * probe, handed to a codec's multi-request plan so its affordance gate costs * no extra round trip * @param [options.contentType] {string} caller-supplied content type * @param [options.capability] {IZcap} * @returns {Promise} */ export declare function insertResource(context: ClientContext, { itemsPath, pathForId, codec, data, features, contentType, capability }: { itemsPath: string; pathForId: (id: string) => string; codec: ResourceCodec; data: ResourceData; features: FeatureProbe; contentType?: string; capability?: IZcap; }): Promise; /** * Creates or replaces a resource by id (upsert) through its codec, owning the * conditional-write orchestration in one place: * * - A conditional codec (e.g. the EDV codec) needs the current stored document * to advance its sequence and pin the write to the current ETag, so the * current document is pre-read; the codec then computes the precondition * itself. A plaintext codec needs no pre-read and defers to the caller's * explicit precondition. * - The pre-read cannot distinguish "absent" from "unreadable with this * capability" (WAS masks unauthorized reads as 404), so a conditional codec * encodes a fresh insert (`If-None-Match: *`) in both cases. When the target * in fact exists, a conditional-writes backend rejects that insert with 412; * that 412 is re-thrown here with a message naming the real cause, instead * of surfacing as an inexplicable failed create. Conditional codecs * therefore need read access to update an existing document. * - A backend that does NOT advertise `conditional-writes` ignores the * `If-None-Match: *` guard, so the 412 safety net above never fires there: a * masked-404 insert would silently overwrite the existing document and reset * its sequence. The insert-after-null-pre-read is therefore refused (fail * closed) unless the backend advertises the feature. * * @param context {ClientContext} * @param options {object} * @param options.path {string} the resource path to write * @param options.codec {ResourceCodec} the collection's resolved codec * @param options.id {string} the resource id * @param options.data {ResourceData} the plaintext value * @param options.features {FeatureProbe} the handle's shared * `BackendFeatures` probe; consulted only for a conditional codec's * insert-after-null-pre-read * @param [options.contentType] {string} caller-supplied content type * @param [options.capability] {IZcap} * @param [options.precondition] {WritePrecondition} the caller's explicit * precondition (used only for a non-conditional codec) * @returns {Promise} */ export declare function upsertResource(context: ClientContext, { path, codec, id, data, features, contentType, capability, precondition }: { path: string; codec: ResourceCodec; id: string; data: ResourceData; features: FeatureProbe; contentType?: string; capability?: IZcap; precondition?: WritePrecondition; }): Promise; //# sourceMappingURL=write.d.ts.map