Guard / foldkit-guard/sync

GuardSync

namespace · packages/guard/src/sync.ts:73

const GuardSync = { document, opens, authorize, admit }

In the guides

Members

GuardSync.document

function · packages/guard/src/sync.ts:87

document<User>(
  edits: {
    readonly entity: AnyEntity
    readonly members: ReadonlyArray<string>
  },
  options: {
    readonly readers: ReadonlyArray<PrincipalGuard<User>>
  },
): GuardedDocument<User>

A document of edits to edits.entity's edits.members, opened by any of readers. Refused here, not discovered later: a member that is not a field of the Entity, a member with a Read rule of its own (its value would reach a reader the rule hides it from), a reader the row's Read rule does not name (it would receive edits to rows it cannot read), a guarded row with no readers, and always rules that read the row (no reader could be shown to pass them).

ts
const Edits = GuardSync.document(ProductEdits, { readers: [G.isStaff] })

GuardSync.opens

function · packages/guard/src/sync.ts:128

opens<User>(
  policy: Policy<User>,
  document: GuardedDocument<User>,
  principal: Option.Option<User>,
): Effect.Effect<boolean>

Whether principal may open the document: any of its readers (anyone, when it names none), and every always rule of the Entity. For journalExchange's opens.

GuardSync.authorize

function · packages/guard/src/sync.ts:159

authorize<User>(
  policy: Policy<User>,
  document: GuardedDocument<User>,
): (request: {
  readonly principal: Option.Option<User>
  readonly message: { readonly changes: ReadonlyArray<CellChange> }
}) => AuthorizeDecision

The journal's authorize for a Message of cell edits: refuses one whose row's Update or a changed member's Update the principal guards settle as refused, with an explain's sentence. It runs under the journal's lock, so it reads no row (admit does), and its bodies must not suspend.

ts
authorize: { EditedProducts: GuardSync.authorize(Policy, Edits) }

GuardSync.admit

function · packages/guard/src/sync.ts:192

admit<User, R>(
  policy: Policy<User>,
  document: GuardedDocument<User>,
  options: {
    readonly principal: Option.Option<User>
    readonly source: EntitySource<Option.Option<User>, R>
    readonly changesOf: (operation: Operation) => ReadonlyArray<CellChange>
  },
): (operation: Operation) => Effect.Effect<AuthorizeDecision, unknown, R>

The exchange's admit for principal: each row an operation's edits name is read through source (the Entity's guarded Source) and must let the principal update it, as it is and as it would be after all of the operation's edits to it, and each changed member must too. A row the principal cannot see is refused, as is an edit to a member outside the document or a value its member cannot encode. changesOf reads the edits from an operation; one with none is admitted.

The row is read from the table, which takes an edit only once its exchange settles: an edit that changes what a rule reads lets another, admitted before it lands, be judged against the row as it was.