v0.30.0
Minor Changes
-
The
databaseUrlclient option is gone. Your database connects to Ablo out of band, not through the client. Ablo is Stripe-shaped: the client only ever talks to the engine. You build it withAblo({ schema, apiKey })— addtransport: 'http'for a stateless worker — and it reaches Ablo over WebSocket or HTTP. It never opens a Postgres connection of its own. How your data connects is a separate, one-time step, and it takes one of two shapes:- Logical replication, the default.
ablo connectregisters your database, and Ablo tails its write-ahead log. Your rows stay where they are; Ablo reads the change stream and keeps its own log. - A signed endpoint, the fallback. When a database can’t grant a
REPLICATIONrole, your app exposes a signed HTTP endpoint for Ablo to call. Same principle — the credentials stay with your app.
With no connection string in the client,
ablo initno longer scaffolds the--storage directconnector, the last thing that wrotedatabaseUrl: process.env.DATABASE_URLinto generated code. Runablo init --storage replication(the default) or--storage endpoint. - Logical replication, the default.
-
A claim’s work label is
description, notreason. A claim is an advisory lock: you take it on a row before editing, and other participants — agents or people — see it’s held and wait. The free-text note that says what you’re doing is nowdescription, the line a peer reads when it lands on a row you hold:ablo.<model>.claim({ id, description: 'Renaming the task to match the brief' }). The oldreasonoption is gone, with no alias, so a call still passing it won’t type-check — rename it. (This is a different field from thereasonon a rejected or lost claim —'conflict','expired','preempted'— which explains why coordination said no, and hasn’t changed.) -
Claim a key Ablo hasn’t synced:
ablo.<model>.claim(id). Claims now come in two shapes, matched to whether Ablo holds the row. The object form,claim({ id }), loads the row from Ablo’s synced pool and returns aHeldClaim<T>with its.data. The new string form,claim(id), locks a row that lives only in your database — one Ablo has never synced — skipping the pool load and theentity_not_foundthrow, and returns aHeldLease: aHeldClaimwithout the data. This is Rung 0 of the connect ladder: coordination with no replication grant, no schema change, noorganization_idcolumn — so you can coordinate agents against your database before wiring any sync at all.await usingreleases either shape at end of scope, and the object form is untouched, so nothing you’ve already written changes.
Patch Changes
-
ablo pushdefers provisioning instead of failing when a role can’t run DDL. When the engine role bound to a plane can’t create or alter tables,pushno longer aborts. It records the schema and defers the table changes for a role that can run them — so your models still register, rather than the whole command stalling on a privilege the plane may never grant the engine. -
Schema-drift stops false-alarming on
selectModels/omitModelsclients. A projected client carries a deliberate subset of the schema, so its hash differs from the full one by design. The check now compares against the projection’s own source hash — so a correctly projected app no longer sees a phantom drift warning at startup.