Skip to content
AbloAblo
Esc
navigateopen⌘Jpreview
On this page

v0.3.0

Umbrella <AbloProvider> for React apps. One provider component now owns the full lifecycle — singleton rotation on auth change, Strict-Mode-safe bootstrap, beforeunload cleanup, session-expiry IndexedDB wipe, post-bootstrap hooks, mesh client construction. Replaces the ad-hoc provider glue every consumer had to write themselves.

Declarative props absorb every class of lifecycle glue; the status hook returns a tagged union so impossible states are unrepresentable. The reference integration shrank from 515 LOC of hand-rolled singleton/AbortController/beforeunload/reaction-bridge wiring to a 60-LOC thin wrapper that just passes props through.

Added

  • <AbloProvider> — umbrella provider at @abloatai/ablo/react. Props include data config (schema, url, userId, organizationId), auth (capabilityToken / apiKey / session cookie fallback), declarative behavior (preventUnsavedChanges, lostConnectionTimeout, postBootstrap), callbacks (onSessionExpired, onError, resolveUsers), and DI escape hatches.
  • <SyncGroupProvider id="matter:..."> + useSyncGroup() — per-entity scope context.
  • <ClientSideSuspense fallback={...}> — gate renders until the engine reports connected. Phase-1 non-Suspense; phase-2 upgrades to real Suspense.
  • useSyncStatus() rewritten as a tagged union: { name: 'initial' | 'connecting' | 'connected' | 'reconnecting' | 'disconnected' | 'needs-auth', ... }. Impossible states are unrepresentable.
  • useCurrentUserId() — returns the userId prop. Replaces downstream consumers’ defineProperty hacks on the store.
  • useErrorListener(cb) — imperative error callback (Sentry/Datadog).
  • useSync<R>() and useSyncStore<T>() accept generic parameters so consumers can widen to their concrete schema types without as unknown casts at call sites.
  • BaseSyncedStore.purge() / SyncEngine.purge() — disconnect + wipe every ablo_* / ablo-* IndexedDB. Called automatically on session expiry.
  • SyncEngine.onSessionError(listener) — subscribe to session-error events. Multiple subscribers supported.
  • Commit payload projection built into TransactionQueue. Mutations are automatically projected onto the model’s schema-declared fields (dropping framework internals __class / __typename / clientId / syncStatus and anything not declared), with field.json() values auto-stringified for TEXT columns and undefined dropped on updates. No config port, no consumer hook — the SDK derives correct wire payloads from the schema alone. Apps that previously maintained hand-rolled extractor tables can delete them entirely.

Breaking (continued)

  • Removed SyncEngineConfig.extractCreateInput and SyncEngineConfig.buildUpdateInput. The SDK’s built-in projection replaces them. Consumers who passed these in configOverrides should delete the override; the default now covers 100% of identity-column mutations. The configOverrides prop still exists but its remaining fields are all deprecated (see below) and scheduled for removal in v0.4.

Deprecated (vestigial — removal in v0.4)

  • SyncEngineConfig.modelCreatePriority, defaultCreatePriority, defaultNonCreatePriority — never read at runtime.
  • SyncEngineConfig.batchableModels — never read at runtime.
  • SyncEngineConfig.dedicatedDeleteModels — never read at runtime.
  • SyncEngineConfig.preserveCaseModels — never read at runtime.
  • SyncEngineConfig.essentialFields — used only in debug logging, no behavioral effect.
  • SyncEngineConfig.classNameFallbackMap — dead path; ModelRegistry.registerModelsFromSchema registers by constructor identity, bypassing the class-name fallback entirely.

Breaking

  • Removed <SyncProvider> — folded into <AbloProvider>. Migrate by swapping the provider and passing userId/organizationId/url instead of a pre-constructed store.
  • Removed createAbloContext() factory and its returned AbloProvider / useAblo / useParticipant triple. Mesh is now always-on inside <AbloProvider>; useAblo() and useParticipant(opts) are always available. Schema-typed mesh hooks are on the roadmap.
  • Removed withSync (no-op alias of observer). Import observer from mobx-react-lite directly if needed.
  • Removed useSyncContext from the public surface (never used outside the SDK’s test helpers).
  • useSyncStatus() return shape changed from six booleans to a tagged union. Migration: const { isReady } = useSyncStatus()const status = useSyncStatus(); const isReady = status.name === 'connected'.
  • SyncStoreContract gained six sync-status getters and a syncStatus field. Third-party classes implementing the contract must add these (additive for callers).

Migration

// Before (0.2.x)
const { AbloProvider, useAblo, useParticipant } = createAbloContext<typeof schema>();

function Root() {
  const sync = createSyncEngine({ url, schema, user });
  const ablo = new Ablo({ schema });
  return (
    <SyncProvider store={sync._store} organizationId={orgId}>
      <AbloProvider ablo={ablo}>
        <App />
      </AbloProvider>
    </SyncProvider>
  );
}

// After (0.3.0)
function Root() {
  return (
    <AbloProvider
      schema={schema}
      url={url}
      userId={userId}
      organizationId={orgId}
      preventUnsavedChanges
      onSessionExpired={() => router.replace('/signin')}
    >
      <ClientSideSuspense fallback={<Skeleton />}>
        <App />
      </ClientSideSuspense>
    </AbloProvider>
  );
}

No breaking change to useQuery / useOne / useMutate / useReader / useMutators / useUndoScope / usePresence / useIntent — call sites remain source-compatible.

Was this page helpful?