Skip to content

UCANACL

Defined in: packages/core/src/ucan-acl.ts:166

UCAN-based ACL with fine-grained capability support.

Capability metadata and local revocation tombstones are process-local; only membership in the backing ACL is replicated. Capability checks therefore require current backing membership first, so a remote removal takes effect locally even while a stale metadata entry remains cached. Because generic backing changes do not identify affected users, a remote merge never clears a local tombstone: a remotely re-added identity is denied every capability until an explicit local add or grant. Membership queries without a capability report the replicated backing membership instead, so the re-added identity is visible there and callers can remove it again. A removal observed only through a remote merge cannot create such a tombstone, so this wrapper does not provide distributed strong-removal semantics by itself.

The generic ACL contract exposes one opaque mutable state and does not promise key-isolated commits, so overlapping calls could derive changes from the same document-wide baseline. All asynchronous backing operations are therefore single-flight, and each backing ACL instance may be wrapped by at most one UCANACL so that admission state is never split across independent wrappers. Checks, listings, entry lookups, mutations, and the synchronous current() snapshot reject with a retryable conflict while another public operation is unresolved, rather than risk observing partially changed backing state or deadlocking on deferred backing-to-wrapper recursion. External orchestration may wait for that conflict to settle and retry. Backing ACL implementations and identity codecs must instead propagate it because they may own the operation that must settle. Direct synchronous backing-to-wrapper recursion is also rejected. Any rejected local opaque mutation poisons the instance because the generic ACL contract does not identify which memberships may already have changed. A rejected remote merge does not, so malformed remote input cannot disable the ACL.

A backing commit claim consumed by this wrapper must be a plain record whose immediate prototype is Object.prototype or null. Class instances are rejected so a custom constructor or Promise species hook cannot disguise an asynchronous claim as a synchronous record. A claim record must not have a then property, even a non-callable one: any visible then is rejected as asynchronous, so a native Promise that shadows its then cannot pass as a claim. Promise.prototype is allowed only through inspection so a safe rejection handler can be attached before the asynchronous result is rejected; a Promise is never accepted as a claim. Promises with unsafe constructor/species hooks cannot be safely observed and may still produce an unhandled rejection; backing providers must not return asynchronous values from synchronous operations. Backing current() returns an opaque generic ChangesType value. Its synchronous contract is mandatory: runtime checks detect ordinary native Promises and visible thenables, but JavaScript exposes no hook-free Promise brand predicate for an object with deliberately forged prototype and constructor state.

The identity serializer must be canonical and collision-free for the provider’s identity domain, and must capture caller-owned state before its first asynchronous suspension. The deserializer must return an identity with the same canonical encoding; object and function identities must also be fully detached from the caller’s value. Listing caches retain only bounded, private canonical templates for one backing revision, and every identity returned to a caller is freshly detached. Backing listings above MAX_UCAN_ACL_LISTING_IDENTITIES fail before identity codecs start, so sparse or proxied arrays cannot schedule unbounded snapshot work, and listings with holes are rejected instead of serializing a missing entry.

ChangesType

PublicKey

  • ACL<ChangesType, PublicKey>

new UCANACL<ChangesType, PublicKey>(_backing, _serializePublicKey, _deserializePublicKey): UCANACL<ChangesType, PublicKey>

Defined in: packages/core/src/ucan-acl.ts:188

ACL<ChangesType, PublicKey>

(key) => Promise<string>

(serialized) => Promise<PublicKey>

UCANACL<ChangesType, PublicKey>

add(publicKey): Promise<ChangesType>

Defined in: packages/core/src/ucan-acl.ts:1013

Add a new user to the ACL.

PublicKey

User’s public key.

Promise<ChangesType>

A block of change(s) for the addition to the ACL.

ACL.add


check(publicKey, capability?): Promise<boolean>

Defined in: packages/core/src/ucan-acl.ts:1267

Checks to see if the specified user has a specific capability. If capability is undefined, checks if the user is in the ACL at all.

PublicKey

User’s public key.

string

Optional capability string to check for.

Promise<boolean>

true if the user has the specified capability (or is in the ACL if no capability specified).

ACL.check


current(): ChangesType

Defined in: packages/core/src/ucan-acl.ts:1229

Gets a block of change(s) describing the current state of the ACL.

ChangesType

A block of change(s) describing the whole ACL.

ACL.current


getEntry(publicKey): Promise<UCANACLEntry | undefined>

Defined in: packages/core/src/ucan-acl.ts:1428

Get the ACL entry for a specific user.

PublicKey

Promise<UCANACLEntry | undefined>


grant(publicKey, capability, documentId, issuerPrivateKey, issuerPublicKeyBase64, proofs?, epochId?): Promise<ChangesType>

Defined in: packages/core/src/ucan-acl.ts:1374

Grant a capability to a user via UCAN delegation.

PublicKey

DocumentCapability

string

CryptoKey

string

string[] = []

Uint8Array<ArrayBufferLike>

Promise<ChangesType>


merge(changes): boolean | void

Defined in: packages/core/src/ucan-acl.ts:1245

Apply remote membership only while no local mutation is admitted or executing. Callers must retry the same changes after the local operation settles when this method rejects with a retryable conflict. A rejected backing merge does not poison the wrapper: remote changes may already change arbitrary memberships, so a partially applied merge leaves no local metadata invariant that depends on which memberships changed.

ChangesType

boolean | void

ACL.merge


prepareAdd(publicKey): Promise<PreparedACLChange<ChangesType>>

Defined in: packages/core/src/ucan-acl.ts:1030

Stage a user addition without mutating the live ACL.

Callers can finish fallible publication work before invoking the synchronous commit. Implementations MUST detach changes from both the caller and the private staged state and reject a repeated or stale commit before mutation. A successful commit MUST apply the staged state completely. Generic callers MUST treat any other commit exception as an indeterminate backing state and fail closed; they cannot assume a custom implementation rolled back a partially applied commit. The shipped CRDT adapters complete fallible work during preparation and atomically swap their private staged state only after all commit checks pass.

PublicKey

Promise<PreparedACLChange<ChangesType>>

ACL.prepareAdd


prepareRemove(publicKey): Promise<PreparedACLChange<ChangesType>>

Defined in: packages/core/src/ucan-acl.ts:1139

Stage a user removal without mutating the live ACL.

Callers can finish fallible publication work before invoking the synchronous commit. Implementations MUST detach changes from both the caller and the private staged state and reject a repeated or stale commit before mutation. A successful commit MUST apply the staged state completely. Generic callers MUST treat any other commit exception as an indeterminate backing state and fail closed; they cannot assume a custom implementation rolled back a partially applied commit. The shipped CRDT adapters complete fallible work during preparation and atomically swap their private staged state only after all commit checks pass.

PublicKey

Promise<PreparedACLChange<ChangesType>>

ACL.prepareRemove


remove(publicKey): Promise<ChangesType>

Defined in: packages/core/src/ucan-acl.ts:1117

Remove a user from the ACL.

PublicKey

User’s public key.

Promise<ChangesType>

A block of change(s) for the removal from the ACL.

ACL.remove


revoke(publicKey): Promise<ChangesType>

Defined in: packages/core/src/ucan-acl.ts:1421

Revoke a user’s access. This invalidates their UCAN and all downstream delegations.

PublicKey

Promise<ChangesType>


users(capability?): Promise<PublicKey[]>

Defined in: packages/core/src/ucan-acl.ts:1301

Returns the list of users with a specific capability. If capability is undefined, returns all users.

string

Optional capability to filter users by.

Promise<PublicKey[]>

ACL.users