# resolver.writes ## Purpose Implements the `write(uri, body, signal?)` semantics. Accepts either `Uint8Array` or `ReadableStream` for the body, forwards a native `createWriteStream` when the adapter exposes one and the body is a stream, and otherwise drains the stream (via `new Response(stream).arrayBuffer()`) into a single `adapter.set` call. The drain path increments `storage_uri.buffered_write_total{scheme}` so operators can alert on mis-composed adapters that quietly buffer large payloads. `SuaveplanError` subclasses thrown by `adapter.set` (any package's namespaced error — `DriveUriError`, `StorageHttpError`, etc.) pass through unchanged so consumers can route on the original `code`. Non-namespaced throwables (plain `Error`, foreign objects) are wrapped as `STORAGE_URI.WRITE_UNSUPPORTED` with the original preserved as `cause`, giving a normalised failure mode for read-only adapters that lack their own error class. ## Features - Branch on `body` shape via `getReader` duck-test. - Forward `createWriteStream` only when present AND body is a stream. - Drain-and-set fallback for both buffered bodies and missing `createWriteStream`. - `SuaveplanError` pass-through on `adapter.set` throw; `WRITE_UNSUPPORTED` wrap with `cause` preserved for non-namespaced throwables only. ## Usage: Basic ```ts import { writeViaPlugin } from "@suaveplan/storage-uri/resolver"; await writeViaPlugin(plugin, "file:///a.bin", "a.bin", new Uint8Array([1, 2, 3]), undefined); ``` ## Usage: Advanced ```ts async function writeStream(resolver: StorageUriResolver, uri: string, src: AsyncIterable): Promise { const stream = new ReadableStream({ async start(ctrl) { for await (const chunk of src) ctrl.enqueue(chunk); ctrl.close(); }, }); await resolver.write(uri, stream); } ``` ## API Reference - `function writeViaPlugin(plugin, uri, key, body, signal): Promise` ## Implementation Notes `new Response(stream).arrayBuffer()` is the cheapest cross-runtime way to drain a Web Stream into a contiguous buffer; it works in Node 18+, Bun, and every browser without any polyfill. The `WRITE_UNSUPPORTED` re-wrap is distinct from the `ADAPTER_ERROR` wrap in `resolver.ts` because callers typically branch on these two conditions differently — `WRITE_UNSUPPORTED` is a capability miss while `ADAPTER_ERROR` is a transient upstream fault.