Skip to content
AbloAblo
Esc
navigateopen⌘Jpreview
On this page

v0.4.0

Minor Changes

  • Per-entity coordination intents on the model accessor.

    Coordinate writes to an entity through the same accessor you read it with — ablo.<model>.intent(id), returning a ModelIntentHandle. Intent state is one self-describing object ({ object: 'intent', id, status, target, action, heldBy, participantKind, createdAt?, expiresAt? }) with a single lifecycle: status: 'active' | 'committed' | 'expired' | 'canceled'. An active intent is the lock.

    Added

    • ablo.<model>.intent(id)ModelIntentHandle<T>, beside create / update / retrieve / load on every model.
      • Read side (any participant, synchronous + reactive): current (the holder’s intent, or null), status ('idle' when free), settled().
      • Write side (the holder): acquire(), acquireOrAwait(), lease-guarded update(), release(), revoke().
      • AsyncDisposable: await using lock = ablo.<model>.intent(id) auto-releases on scope exit.
    • acquireOrAwait() — serialize-on-contention: take the lease, or wait out the current holder, re-read the changed row, then take it. The caller never branches on who holds the target — it just gets the target safely. Bind it to an agent’s write-tool boundary so agents never reason about coordination.
    • New exports: ModelIntentHandle, ModelIntentAcquireOptions.

    Changed

    • acquire() is fire-and-forget over the socket — it does not throw on conflict. Resolve contention with acquireOrAwait() (wait) or read current for a reactive “who’s editing” badge, rather than catching a rejection.

    Deprecated

    • Participant-level intents.claim() / onRejected() and the intent_rejected wire frame still work but are superseded by the per-model handle. Their removal is a future breaking change.

Unreleased

Schema-driven identity sync-group composition, plus a terser capability surface.

The convention for deriving a participant’s allowed sync-groups from its identity is now declared on the consumer’s schema as an open registration. Consumers with a { regionId, customerId } identity shape declare their own roles instead of receiving any built-in prefixes from the SDK.

Capability fields shed their redundant allowed prefix to match the surrounding vocabulary — capability inputs always describe what the bearer can touch, so the prefix was doing no disambiguation work for the consumer.

Added

  • DefineSchemaOptions.identityRoles?: readonly IdentityRole[] — open registration of identity-anchored sync-group roles on defineSchema(...). Each IdentityRole declares { kind, template, extract }: a diagnostic label, a '<prefix>:{id}' template, and a pure extractor function from an opaque identity context to zero-or-more ids. No closed enum; consumers fully control both the template strings and the extraction logic.
  • composeIdentitySyncGroups(identity, schema) exported from @abloatai/ablo/schema — walks the schema’s registered identityRoles, calls each extractor, and substitutes ids into templates. Stable, deduped output. Returns [] when no roles are registered.
  • Schema.identityRoles: readonly IdentityRole[] — the registered list, accessible on every defineSchema(...) result.
  • New exported types: IdentityRole, IdentityContext.

Breaking

  • capabilities.create({ allowedSyncGroups, allowedOperations })capabilities.create({ syncGroups, operations }). Both fields renamed at every public surface — capability create input, capability retrieve response, capability record, Identity returned from AuthProvider. Hard rename, no alias. Update the call sites; the field semantics are unchanged.

    // Before
    await api.capabilities.create({
      allowedSyncGroups: ['org:acme'],
      allowedOperations: ['tasks.update'],
      lease: '10m',
    });
    
    // After
    await api.capabilities.create({
      syncGroups: ['org:acme'],
      operations: ['tasks.update'],
      lease: '10m',
    });

Changed

  • docs/integration-guide.md §1 now shows identityRoles in the canonical defineSchema example plus a “Declaring scope on a model” subsection covering orgScoped / scopedVia / syncGroupFormat. docs/capabilities.md, docs/api.md, docs/mcp.md, and AGENTS.md cross-reference the identityRoles section and use the renamed fields throughout.

Was this page helpful?