/*! * Copyright (c) 2026 Interop Alliance. All rights reserved. */ /** * The descriptor-store seam: where a `CollectionEncryption` descriptor lives * and how it is compare-and-swapped. The recipient primitives (`initRecipients` * / `addRecipient` / `removeRecipient`) mutate a descriptor only through this * port, so the same key-epoch machinery manages a Collection's own `encryption` * descriptor (the classic host) or a descriptor hosted as a plain JSON Resource * (e.g. a per-user-key roster in a private collection). * * Two adapters: * * - {@link collectionDescriptorStore} -- the Collection Description's `encryption` * member, read with `describeWithEtag` and written back with * `replaceDescription` + `If-Match`. The server enforces the descriptor * invariants (append-only epochs, monotone `currentEpoch`, non-decreasing * `version`) on this path. * - {@link resourceDescriptorStore} -- a descriptor stored verbatim as a JSON Resource. * The server treats the resource as opaque content and enforces NO descriptor * invariants there; rollback/tamper detection rests on client-side epoch * pinning plus whatever governance the hosting profile adds -- for a * log-governed descriptor (the Resource Log Profile), the verified entry * proofs and the chain-head pin. Both the compare-and-swap and the * create-if-absent guard ride the backend's `conditional-writes` feature. * The hosting collection may be plaintext or encrypted -- a conditional * codec pins the write to the `ifMatch` passed here rather than to its own * pre-read -- but an encrypted host must be created under an id its codec * mints (the EDV codec refuses a human-readable resource id, which would * leak onto the URL). */ import type { Collection } from '../Collection.js'; import type { Resource } from '../Resource.js'; import type { CollectionEncryption } from '../types.js'; /** * Where a `CollectionEncryption` descriptor lives: a read-with-validator plus a * compare-and-swap write, the two operations the recipient primitives' CAS loop * needs. Implementations host the descriptor anywhere a versioned JSON value * can live; the two shipped adapters are {@link collectionDescriptorStore} and * {@link resourceDescriptorStore}. */ export interface EncryptionDescriptorStore { /** * Reads the current descriptor together with the opaque `etag` validator the * next {@link replace} must be compare-and-swapped against. Resolves `null` * when no descriptor exists yet AND this store can create one (the resource * adapter before the first `initRecipients`); a store whose host must * already exist (the description adapter) throws instead of resolving * `null`. Throws when the hosted value is not an `edv`-scheme descriptor. * * @returns {Promise<{ descriptor: CollectionEncryption; etag?: string } | null>} */ read(): Promise<{ descriptor: CollectionEncryption; etag?: string; } | null>; /** * Replaces the descriptor, compare-and-swapped against `ifMatch` (the * validator from {@link read}); a stale validator throws * `PreconditionFailedError` (412). Must follow a {@link read} on the same * store instance -- an adapter may forward sibling state observed by its most * recent read (the description adapter forwards the description's `name` / * `backend`). * * @param descriptor {CollectionEncryption} * @param options {object} * @param [options.ifMatch] {string} the validator from the prior read; * absent against a host that does not version its writes * @returns {Promise} */ replace(descriptor: CollectionEncryption, options: { ifMatch?: string; }): Promise; /** * Creates the FIRST descriptor where {@link read} resolved `null`, guarded * create-if-absent (`If-None-Match: *`); throws `PreconditionFailedError` * (412) when a concurrent writer created one first. Absent on stores whose * host always exists (the description adapter). * * @param descriptor {CollectionEncryption} * @returns {Promise} */ create?(descriptor: CollectionEncryption): Promise; } /** * The Collection Description adapter: the descriptor is the Description's * `encryption` member. Read fails closed when the Description is unreadable * (WAS masks unauthorized reads as 404) or the collection is not declared * encrypted with the `edv` scheme; the CAS write forwards the description's * sibling fields (`name` / `backend`) observed by the most recent read, so * the replace-semantics PUT does not drop them. No `create`: a Collection * Description always exists, so a first descriptor is declared via * `collection.configure({ encryption })`, never through this store. * * @param options {object} * @param options.collection {Collection} * @returns {EncryptionDescriptorStore} */ export declare function collectionDescriptorStore({ collection }: { collection: Collection; }): EncryptionDescriptorStore; /** * The plain-JSON-Resource adapter: the descriptor is the resource's entire * content, stored verbatim. Read resolves `null` when the resource is absent * (the pre-`initRecipients` state -- `create` then writes the first descriptor * with `If-None-Match: *`), and throws when the resource holds something other * than an `edv`-scheme descriptor object. * * The server enforces no descriptor invariants on a resource (unlike a * Collection Description): rollback/tamper detection rests on client-side * epoch pinning plus whatever governance the hosting profile adds (for a * log-governed descriptor, the Resource Log Profile's verified entry proofs * and chain-head pin), and the CAS/create guards ride the backend's * `conditional-writes` feature. The hosting collection may be plaintext or * encrypted: a conditional codec pins the write to the `ifMatch` this store * passes rather than to the ETag its own pre-read observed. On an encrypted * host the resource id must be one the codec mints, since the EDV codec * refuses to create a document under a human-readable id. * * @param options {object} * @param options.resource {Resource} * @returns {EncryptionDescriptorStore} */ export declare function resourceDescriptorStore({ resource }: { resource: Resource; }): EncryptionDescriptorStore; //# sourceMappingURL=descriptorStore.d.ts.map