import type { ClientContext } from './internal/request.js'; import type { FeatureProbe } from './internal/features.js'; import type { ResourceCodec } from './codec.js'; import type { EncryptionOverride, IZcap, Json, ResourceData, PolicyDocument, ResourceMetadata, ResourceMetadataCustom } from './types.js'; export declare class Resource { #private; readonly spaceId: string; readonly collectionId: string; readonly id: string; /** * @param options {object} * @param options.context {ClientContext} * @param options.spaceId {string} * @param options.collectionId {string} * @param options.resourceId {string} * @param [options.capability] {IZcap} capability attached to every request * @param [options.codec] {function} resolver sharing the parent collection's * codec, so a resource handle obtained via `collection.resource(id)` does * not repeat the backend() round-trip. A standalone resource resolves its * own. * @param [options.features] {FeatureProbe} the parent collection's shared * backend-feature probe. A standalone resource probes its own. * @param [options.encryption] {EncryptionOverride} per-handle encryption * override for a standalone resource (ignored when `codec` is supplied -- * the shared parent codec wins) */ constructor({ context, spaceId, collectionId, resourceId, capability, codec, features, encryption }: { context: ClientContext; spaceId: string; collectionId: string; resourceId: string; capability?: IZcap; codec?: () => Promise; features?: FeatureProbe; encryption?: EncryptionOverride; }); /** * Reads the resource, auto-parsing JSON to an object and returning binary as * a `Blob`. Returns `null` if the resource is missing or not visible to you * (WAS returns 404 for both not-found and unauthorized). * * @returns {Promise} */ get(): Promise; /** * Reads the resource together with its `ETag` validator (the backend's * `conditional-writes` feature) -- the Resource counterpart of * `Collection.describeWithEtag`. The `ETag` is the opaque validator to pass * to {@link put}'s `ifMatch` for a lost-update-safe (compare-and-swap) * write. The value is decoded like {@link get} (JSON parsed, binary as a * `Blob`, decrypted on an encrypted collection). Returns `null` if the * resource is missing or not visible to you (404 conflation caveat); `etag` * is absent against a backend that does not version resources. * * @returns {Promise<{ data: Json | Blob; etag?: string } | null>} */ getWithEtag(): Promise<{ data: Json | Blob; etag?: string; } | null>; /** * Reads the resource body as text. Returns `null` on a missing/unauthorized * resource (404 conflation caveat). A raw escape hatch: it does NOT run the * codec, so on an encrypted collection it never decrypts -- use `get()` to * decrypt. * * For a JSON content-type the request layer has already consumed and parsed * the body stream (`@interop/http-client` offers no opt-out through ezcap), * so the text is re-serialized from the parsed value: semantically identical * JSON, but not guaranteed byte-identical to what was uploaded (insignificant * whitespace is not preserved). * * @returns {Promise} */ getText(): Promise; /** * Reads the resource body as raw bytes. Returns `null` on a * missing/unauthorized resource (404 conflation caveat). A raw escape hatch: * it does NOT run the codec, so on an encrypted collection it never decrypts * -- use `get()` to decrypt. * * For a JSON content-type the request layer has already consumed and parsed * the body stream (`@interop/http-client` offers no opt-out through ezcap), * so the bytes are re-serialized from the parsed value: semantically * identical JSON, but not guaranteed byte-identical to what was uploaded * (insignificant whitespace is not preserved). * * @returns {Promise} */ getBytes(): Promise; /** * Creates or replaces the resource by id (upsert). JSON for plain * objects/arrays, binary for `Blob`/`Uint8Array`. Throws `NotFoundError` if * the parent collection does not exist (WAS does not auto-create parents). * * For binary data with no explicit `contentType` (and no `Blob.type`), the * content-type is guessed from the resource id's file extension for common * static-web types -- so `resource('index.html').put(bytes)` is sent as * `text/html`. An unrecognized/absent extension sends no content-type, and the * server applies its own required-`Content-Type` rule. * * Conditional writes (the backend's `conditional-writes` feature): pass * `ifMatch` (the ETag from a prior read/write) for an update-if-unchanged, or * `ifNoneMatch: true` for a create-if-absent. A failed precondition throws * `PreconditionFailedError` (412). They work the same on an encrypted * collection: the codec manages the precondition on its own when the caller * names none (the EDV `sequence` becomes the enforced ETag), and pins the * write to the caller's baseline when one is given. Because that codec * pre-reads the current document, updating an existing encrypted document * needs read access (a PUT-only capability can only create, and only against * a backend advertising `conditional-writes`; see `upsertResource`) -- and a * precondition the pre-read already contradicts fails locally with the same * `PreconditionFailedError` the server would return. Returns the new * `etag`. * * @param data {ResourceData} * @param options {object} * @param [options.contentType] {string} content-type for binary data * @param [options.ifMatch] {string} update only if the ETag matches * @param [options.ifNoneMatch] {boolean} create only if absent * @returns {Promise<{ etag?: string }>} the stored resource's new ETag */ put(data: ResourceData, options?: { contentType?: string; ifMatch?: string; ifNoneMatch?: boolean; }): Promise<{ etag?: string; }>; /** * Deletes the resource. Idempotent. Pass `ifMatch` (the backend's * `conditional-writes` feature) to delete only if the resource's current ETag * matches; a stale validator throws `PreconditionFailedError` (412). * * @param options {object} * @param [options.ifMatch] {string} delete only if the ETag matches * @returns {Promise} */ delete(options?: { ifMatch?: string; }): Promise; /** * Reads the resource's metadata object (server-managed `contentType` / `size` * / timestamps plus the user-writable `custom` object). Returns `null` if the * resource is missing or not visible to you (404 conflation caveat). A server * without metadata support surfaces its 501 as `NotImplementedError`. * * On an encrypted collection the stored `custom` is an opaque envelope; this * decodes it (decrypts, via the codec) so a caller always sees plaintext * `{ name, tags }`. A resource with no user metadata reports `custom` as `{}`. * * Against a backend with the `conditional-writes` feature the result also * carries the metadata's current `etag` (the `/meta` `metaVersion` validator) * -- pass it as `setMeta(meta, { ifMatch })` for a lost-update-safe metadata * update. * * @returns {Promise<(ResourceMetadata & { etag?: string }) | null>} */ meta(): Promise<(ResourceMetadata & { etag?: string; }) | null>; /** * Replaces the resource's user-writable metadata (`custom`). This is a full * replacement: any property omitted from `custom` is cleared, and an omitted * `custom` clears them all. Does not create the resource -- a `PUT` to the * metadata of a nonexistent resource throws `NotFoundError`. Servers without * metadata support surface their 501 as `NotImplementedError`. * * On an encrypted collection `custom` is encrypted into an opaque envelope by * the codec before it is sent, so `name` / `tags` are never stored as * server-visible plaintext -- transparently, the same call works on plaintext * and encrypted collections alike. * * Conditional metadata writes (the backend's `conditional-writes` feature): * pass `ifMatch` (the `etag` from a prior `meta()`) for an * update-if-unchanged, or `ifNoneMatch: true` for a write-only-if-no-metadata. * A failed precondition throws `PreconditionFailedError` (412). The `/meta` * ETag (`metaVersion`) is independent of the content ETag. Returns the new * `etag`. * * @param meta {object} * @param [meta.custom] {ResourceMetadataCustom} the user-writable properties * @param options {object} * @param [options.ifMatch] {string} update only if the `/meta` ETag matches * @param [options.ifNoneMatch] {boolean} write only if no metadata is set * @returns {Promise<{ etag?: string }>} the metadata's new ETag */ setMeta(meta?: { custom?: ResourceMetadataCustom; }, options?: { ifMatch?: string; ifNoneMatch?: boolean; }): Promise<{ etag?: string; }>; /** * Sets the resource's human-readable `name` (the value surfaced in collection * listings), preserving any existing `tags`. Convenience over `setMeta()`. * The write is pinned to the `etag` the `meta()` read returned (when the * backend supports `conditional-writes`), so a concurrent metadata write * surfaces as `PreconditionFailedError` instead of being silently erased by * this full-replacement write. * * @param name {string} * @returns {Promise} */ setName(name: string): Promise; /** * Sets the resource's `tags`, preserving any existing `name`. Convenience over * `setMeta()`. Pinned to the `meta()` read's `etag` like {@link setName}. * * @param tags {Record} * @returns {Promise} */ setTags(tags: Record): Promise; /** * Reads the resource's access-control policy. Returns `null` when no policy is * set (or it is not visible to you). Managing a policy is a controller-level * operation. * * @returns {Promise} */ getPolicy(): Promise; /** * Sets (creates or replaces) the resource's access-control policy. * * @param policy {PolicyDocument} * @returns {Promise} */ setPolicy(policy: PolicyDocument): Promise; /** * Makes this single resource world-readable: it becomes readable without * authorization. Sugar for `setPolicy({ type: 'PublicCanRead' })`. * * @returns {Promise} */ setPublic(): Promise; /** * Returns `true` when this resource policy is `PublicCanRead`. * * @returns {Promise} */ isPublic(): Promise; /** * Removes the resource's access-control policy, reverting it to * capability-only access. Idempotent. * * @returns {Promise} */ clearPolicy(): Promise; } //# sourceMappingURL=Resource.d.ts.map