FamilyStore
KIT · interface · Type contract
CAS must cover every writer and the active pointer in one real storage commit.
Import
import type { FamilyStore } from '@jangts/agent-core/kits/family';/** @typedef {import('@jangts/agent-core/kits/family').FamilyStore} FamilyStore */Other public entry points:@jangts/agent-core/types, @jangts/agent-core/structs, @jangts/agent-core/kits, @jangts/agent-core/kits/family.
Definition
interface FamilyStore<State>Type parameters
| Type parameter | Constraint | Default type |
|---|---|---|
State | — | — |
Field structure
| Field | Type | Required | Description |
|---|---|---|---|
load | (id: string) => Promise<FamilyRecord<State> | undefined> | Required | Returns the record, or undefined when it does not exist. |
compareAndSwap | (id: string, expectedRevision: number | undefined, next: FamilyRecord<State>) => Promise<boolean> | Required | Commits next only when the stored revision equals expectedRevision; returns success. |
Member index
| Member | Purpose |
|---|---|
load | Returns the record, or undefined when it does not exist. |
compareAndSwap | Commits next only when the stored revision equals expectedRevision; returns success. |
Member details
load
Returns the record, or undefined when it does not exist.
FamilyStore.load(id: string): Promise<FamilyRecord<State> | undefined>Returns the record, or undefined when it does not exist.
| Parameter | Type | Passing | Description |
|---|---|---|---|
id | string | Required | — |
Returns: Promise<FamilyRecord<State> \| undefined>.
Awaited value: FamilyRecord<State> \| undefined.
Optional shapes of Return value: choose one shape; required fields for each branch are listed separately.
Branch 1
undefined
Branch 2
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Required | Read-only. Family id; also the store key. |
revision | number | Required | Read-only. Optimistic concurrency token; every accepted mutation increments it by one. |
activeId | string | Required | Read-only. Id of the active version; promotion moves this pointer. |
expiresAtMs | number | Required | Read-only. Instant after which the record is no longer retained, in epoch milliseconds. |
versions | readonly FamilyVersion<State>[] | Required | Read-only. Versions in creation order; bounded by maxVersions when configured. |
compareAndSwap
Commits next only when the stored revision equals expectedRevision; returns success.
FamilyStore.compareAndSwap(id: string, expectedRevision: number | undefined, next: FamilyRecord<State>): Promise<boolean>Commits next only when the stored revision equals expectedRevision; returns success.
| Parameter | Type | Passing | Description |
|---|---|---|---|
id | string | Required | — |
expectedRevision | number | undefined | Required | — |
next | FamilyRecord<State> | Required | — |
Fields of next
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Required | Read-only. Family id; also the store key. |
revision | number | Required | Read-only. Optimistic concurrency token; every accepted mutation increments it by one. |
activeId | string | Required | Read-only. Id of the active version; promotion moves this pointer. |
expiresAtMs | number | Required | Read-only. Instant after which the record is no longer retained, in epoch milliseconds. |
versions | readonly FamilyVersion<State>[] | Required | Read-only. Versions in creation order; bounded by maxVersions when configured. |
Returns: Promise<boolean>.
Awaited value: boolean.
Examples
- Agent family: versions, merge, and explicit promotion: Manage data branches on real CAS storage; candidate versions are explicitly promoted after checks and authorization.
Configure state checks, source verification, and three-way merge
Configuration · Node.js
import { defineAgentFamily } from '@jangts/agent-core/kits/family';
import type { FamilyStore } from '@jangts/agent-core/kits/family';
import type { OperationContext } from '@jangts/agent-core';
type State = { goal: string; sourceRevision: string };
export function family<App>(store: FamilyStore<State>,
authorize: (context: OperationContext<App>) => Promise<void>,
verify: (state: State) => Promise<void>) {
return defineAgentFamily<State, App>({
store, maxVersions: 16, retentionMs: 7 * 86400000,
isState: (value): value is State => !!value && typeof (value as State).goal === 'string'
&& typeof (value as State).sourceRevision === 'string',
authorize: (_operation, _record, context) => authorize(context),
validate: candidate => verify(candidate.state),
async merge({ base, target, source }) {
if (target.goal !== base.goal && source.goal !== base.goal && target.goal !== source.goal)
return { conflicts: ['goal'] };
return { value: target.goal === base.goal ? source : target, conflicts: [] };
},
});
}import { defineAgentFamily } from '@jangts/agent-core/kits/family';
export function family(store, authorize, verify) {
return defineAgentFamily({
store, maxVersions: 16, retentionMs: 7 * 86400000,
isState: (value) => !!value && typeof value.goal === 'string'
&& typeof value.sourceRevision === 'string',
authorize: (_operation, _record, context) => authorize(context),
validate: candidate => verify(candidate.state),
async merge({ base, target, source }) {
if (target.goal !== base.goal && source.goal !== base.goal && target.goal !== source.goal)
return { conflicts: ['goal'] };
return { value: target.goal === base.goal ? source : target, conflicts: [] };
},
});
}Explicitly promote an approved candidate version
Extension · Node.js
The App calls this after real approval; promote still re-runs source, authorization, revision, and CAS checks.
import type { AgentFamily } from '@jangts/agent-core/kits/family';
import type { OperationContext } from '@jangts/agent-core';
export async function activate<State, App>(family: AgentFamily<State, App>, id: string,
candidateId: string, context: OperationContext<App>) {
const record = await family.read(id, context);
return family.promote({ id, revision: record.revision, candidateId,
expectedActiveId: record.activeId }, context);
}export async function activate(family, id, candidateId, context) {
const record = await family.read(id, context);
return family.promote({ id, revision: record.revision, candidateId,
expectedActiveId: record.activeId }, context);
}