@abloatai/ablo 0.47.0 → 0.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +118 -6
- package/README.md +20 -0
- package/docs/cli.md +9 -1
- package/docs/data-sources.md +65 -0
- package/docs/internal/structure.md +4 -0
- package/package.json +3 -3
- package/docs/internal/agent-orchestration.md +0 -57
package/CHANGELOG.md
CHANGED
|
@@ -1,16 +1,128 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.48.0
|
|
4
|
+
|
|
5
|
+
### A branch is unbound until you connect a database to it
|
|
6
|
+
|
|
7
|
+
A branch keeps its own storage, and it does not quietly get Ablo's. Until a
|
|
8
|
+
database is connected to that branch, a request needing one fails with
|
|
9
|
+
`no_data_source_registered` and says what to do:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
This branch is not connected to your database yet.
|
|
13
|
+
Run `ablo connect` for this branch, then retry.
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The old `test_database_not_registered` is gone. It described a sandbox that no
|
|
17
|
+
longer exists, it arrived on requests that had nothing to do with a test
|
|
18
|
+
database, and its advice pointed at options the SDK had already removed. A
|
|
19
|
+
branch created by `ablo dev` now reports its state plainly rather than looking
|
|
20
|
+
ready and then refusing the first schema push.
|
|
21
|
+
|
|
22
|
+
**Action required.** Replace any handler matching `test_database_not_registered`
|
|
23
|
+
with `no_data_source_registered`. The new code carries the same 4xx meaning and
|
|
24
|
+
a recovery path a caller can act on.
|
|
25
|
+
|
|
26
|
+
### Failures say which branch they happened on
|
|
27
|
+
|
|
28
|
+
An unconnected branch previously returned its refusal with nothing written
|
|
29
|
+
server-side, so a support question about one customer's branch could not be
|
|
30
|
+
answered from logs at all. These now carry the request, organization, project,
|
|
31
|
+
branch, key kind and storage state, indexed in Sentry, so a failure can be
|
|
32
|
+
looked up by branch instead of reconstructed from database tables.
|
|
33
|
+
|
|
34
|
+
### Replication uses your branch's own publication and slot
|
|
35
|
+
|
|
36
|
+
Registration, validation, writer checks, replication, drift detection and
|
|
37
|
+
`ablo connect` all require the branch-scoped names recorded when the source was
|
|
38
|
+
registered. Nothing falls back to a shared `ablo_publication` or `ablo_slot`
|
|
39
|
+
any more, so two branches on one database can never quietly share a stream.
|
|
40
|
+
`ablo connect scan` reports legacy unsuffixed objects as retired.
|
|
41
|
+
|
|
42
|
+
Once your engine is on this release and `ablo connect check` is clean, the
|
|
43
|
+
temporary alias can go:
|
|
44
|
+
|
|
45
|
+
```sql
|
|
46
|
+
DROP PUBLICATION IF EXISTS "ablo_publication";
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Renamed
|
|
50
|
+
|
|
51
|
+
`FootprintPlane` is now `DataSourceIdentity`, with the same three fields. The
|
|
52
|
+
old name described an internal layout; the new one describes what it
|
|
53
|
+
identifies.
|
|
54
|
+
|
|
3
55
|
## 0.47.0
|
|
4
56
|
|
|
5
|
-
###
|
|
57
|
+
### Local Postgres works with Ablo Cloud
|
|
58
|
+
|
|
59
|
+
Run `npx ablo dev --local` to serve the generated signed Data Source handler
|
|
60
|
+
over an outbound, protocol-scoped connector. Postgres remains private on the
|
|
61
|
+
developer's machine and its connection string never leaves the app process.
|
|
62
|
+
The Data Source guide now explains exactly which writes are visible without
|
|
63
|
+
WAL, and the public error reference includes actionable `source_connector_*`
|
|
64
|
+
codes for every connector lifecycle failure.
|
|
65
|
+
|
|
66
|
+
### Awaiting a model write now means it is confirmed
|
|
67
|
+
|
|
68
|
+
`create`, `update`, and `delete` change local reactive state immediately and
|
|
69
|
+
return a promise with a single meaning: the write reached authoritative
|
|
70
|
+
confirmation. An interface stays responsive without awaiting anything, and code
|
|
71
|
+
that needs to know a write survived can await the same call it already makes.
|
|
72
|
+
|
|
73
|
+
The `wait` option is gone from the client and from individual model calls.
|
|
74
|
+
Awaiting a model write always waits for confirmation, so there is nothing left
|
|
75
|
+
to configure. Explicit control over a queued versus confirmed receipt remains on
|
|
76
|
+
`commits.create`, which still hands back the receipt and its confirmation
|
|
77
|
+
separately.
|
|
78
|
+
|
|
79
|
+
**Action required.** Remove `wait` from `Ablo({ ... })` and from every
|
|
80
|
+
`create`, `update`, and `delete` call.
|
|
81
|
+
|
|
82
|
+
- `wait: 'confirmed'` behaves identically once removed.
|
|
83
|
+
- `wait: 'queued'` on a call you never awaited behaves identically once removed.
|
|
84
|
+
- `wait: 'queued'` on a call you did await now waits for confirmation. Move to
|
|
85
|
+
`commits.create` if the queued receipt was the reason for the option.
|
|
86
|
+
|
|
87
|
+
### Customer branches connect before accepting a schema
|
|
88
|
+
|
|
89
|
+
A customer branch now remains in provisioning until it has an active Data
|
|
90
|
+
Source. Ablo does not invent internal storage for customer data: it reads the
|
|
91
|
+
customer's database through WAL and writes through the separately scoped DML
|
|
92
|
+
credential (or uses the explicitly registered signed endpoint fallback).
|
|
93
|
+
|
|
94
|
+
Database validation now uses the branch-scoped publication and replication slot
|
|
95
|
+
persisted with that Data Source. It no longer falls back to the shared
|
|
96
|
+
`ablo_publication` / `ablo_slot` names, so `ablo connect check` validates the
|
|
97
|
+
same objects that `ablo connect apply` created.
|
|
98
|
+
|
|
99
|
+
The sandbox-only `test_database_not_registered` error has been removed. An
|
|
100
|
+
unconnected customer branch now consistently returns `no_data_source_registered`
|
|
101
|
+
with the `ablo connect` recovery step.
|
|
102
|
+
|
|
103
|
+
**Action required for type imports.** `FootprintPlane` has been removed. Import
|
|
104
|
+
`DataSourceIdentity` from `@abloatai/ablo/source` instead; its fields remain
|
|
105
|
+
`organizationId`, optional `projectId`, and `branchId`.
|
|
106
|
+
|
|
107
|
+
### The CLI names the problem it actually hit
|
|
108
|
+
|
|
109
|
+
A refused push no longer reports every failure as a missing `schema:push`
|
|
110
|
+
capability. That advice was wrong for most refusals: a database privilege error,
|
|
111
|
+
a row-level security misconfiguration, and an unregistered development database
|
|
112
|
+
each need a different fix, and none of them is a different API key. Each now
|
|
113
|
+
leads with the server's own message and the remedy for that specific cause.
|
|
6
114
|
|
|
7
|
-
|
|
115
|
+
Project names also resolve correctly under a branch-bound key. Listing projects
|
|
116
|
+
is a management operation that such a key is deliberately not allowed to
|
|
117
|
+
perform, so `ablo status` and `ablo push` reported a correctly minted key's
|
|
118
|
+
project as `unnamed` alongside a permission error. The name now comes from the
|
|
119
|
+
stored management credential.
|
|
8
120
|
|
|
9
|
-
###
|
|
121
|
+
### Deprecations
|
|
10
122
|
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
|
|
123
|
+
`METER_EVENT_COUNTS` is deprecated in favour of its per-surface members, and the
|
|
124
|
+
`DatasourceResnapshotResponse` type and its schema are deprecated. All three
|
|
125
|
+
still ship and still work; they will be removed in a later release.
|
|
14
126
|
|
|
15
127
|
## 0.46.0
|
|
16
128
|
|
package/README.md
CHANGED
|
@@ -22,6 +22,10 @@
|
|
|
22
22
|
|
|
23
23
|
---
|
|
24
24
|
|
|
25
|
+
> **Reading the implementation?** Start with the
|
|
26
|
+
> **[source code map](./CODEMAP.md)**. It shows which files own `create`,
|
|
27
|
+
> `update`, `delete`, `claim`, schemas, transports, and the reactive client.
|
|
28
|
+
|
|
25
29
|
Safely coordinate AI agents, humans, workflows, and services writing to the
|
|
26
30
|
same database.
|
|
27
31
|
|
|
@@ -114,6 +118,22 @@ authority, commits, claims, and ordered changes.
|
|
|
114
118
|
Read the [Quickstart](https://docs.abloatai.com/quickstart), browse
|
|
115
119
|
[docs.abloatai.com](https://docs.abloatai.com), or run `npx ablo docs`.
|
|
116
120
|
|
|
121
|
+
## Navigating the source
|
|
122
|
+
|
|
123
|
+
This repository preserves the package ownership boundaries instead of
|
|
124
|
+
flattening the implementation into `packages/ablo`:
|
|
125
|
+
|
|
126
|
+
- `packages/ablo` is the branded public facade. Its files mostly re-export the
|
|
127
|
+
package that owns each API.
|
|
128
|
+
- `packages/transaction` owns the shared model-operation contracts and the
|
|
129
|
+
stateless HTTP implementation.
|
|
130
|
+
- `packages/humans` owns the reactive WebSocket/local/React implementation.
|
|
131
|
+
|
|
132
|
+
That means searching only inside `packages/ablo/src` will not find the
|
|
133
|
+
implementation of `create`, `update`, `delete`, or `claim`. Read the
|
|
134
|
+
**[source code map](./CODEMAP.md)** for a verb-by-verb ownership table and
|
|
135
|
+
guided call traces for both the default and reactive clients.
|
|
136
|
+
|
|
117
137
|
## Contributing
|
|
118
138
|
|
|
119
139
|
Ablo is free and open source. You can help by
|
package/docs/cli.md
CHANGED
|
@@ -122,7 +122,7 @@ bypasses profiles for project/branch administration; the runtime key remains
|
|
|
122
122
|
| `ablo init` | Scaffold `ablo/` (`schema.ts`, client, optional Data Source / agent / component), write `.env`, install the SDK. Offers to log in at the end. |: |
|
|
123
123
|
| `ablo login` / `logout` / `whoami` / `status` | Authentication, exact credential identity, and readiness (above). | `whoami --key-env <NAME>`, `whoami --json`, `status --json` |
|
|
124
124
|
| `ablo projects list\|create\|use\|rename` | Manage projects and the active one (see [Projects](#projects)). Each project's keys/schema/data are isolated. | `--name "<display>"` (create/rename) |
|
|
125
|
-
| `ablo dev` |
|
|
125
|
+
| `ablo dev` | Ensure an isolated Git branch, wire its temporary key, push, then watch `ablo/schema.ts`. `--local` also serves local Postgres over an outbound signed connector. | `--branch <slug>`, `--branch-ttl-hours <1-168>`, `--local`, `--source <path>`, `--no-watch`, `--schema`, `--export`, `--url` |
|
|
126
126
|
| `ablo branch list\|status\|check\|create\|ensure\|credential\|delete` | Manage and diagnose immutable branch planes and expiring credentials. | Run `ablo branch --help`; use `--json` for automation. |
|
|
127
127
|
| `ablo logs` | Tail the resolved runtime credential's branch activity. Follows by default. | `-n, --tail <N>`, `--since <dur\|ts>`, `--model`, `--op`, `--json`, `--no-follow` |
|
|
128
128
|
| `ablo push` | **Hosted**: upload the schema to Ablo; the server diffs, migrates, and activates it. | `--force`, `--rename old:new`, `--backfill model.field=value`, `--schema`, `--export`, `--url` |
|
|
@@ -166,8 +166,16 @@ npx ablo dev # discover from Git, push + watch
|
|
|
166
166
|
npx ablo dev --branch preview-pr-482 # explicit branch
|
|
167
167
|
npx ablo dev --no-watch # prepare, push once, exit
|
|
168
168
|
npx ablo dev --branch-ttl-hours 24 # change temporary-key lifetime
|
|
169
|
+
npx ablo dev --local # keep Postgres private on localhost
|
|
169
170
|
```
|
|
170
171
|
|
|
172
|
+
`--local` loads `ablo/data-source.ts` (override with `--source <path>`), registers
|
|
173
|
+
the branch as connector-only, and opens an outbound authenticated WebSocket to
|
|
174
|
+
Ablo. Commit, load, list, and outbox-event requests run through the same signed
|
|
175
|
+
Data Source handler as production; no database credential leaves your process
|
|
176
|
+
and no public tunnel is opened. Because the connector is long-lived, `--local`
|
|
177
|
+
cannot be combined with `--no-watch`.
|
|
178
|
+
|
|
171
179
|
It does not start your app, run migrations, create a database-provider branch,
|
|
172
180
|
or copy production rows. Read [Branch-first development](./branch-development.md)
|
|
173
181
|
for the exact discovery order, CI flow, database boundary, and troubleshooting.
|
package/docs/data-sources.md
CHANGED
|
@@ -2,6 +2,71 @@
|
|
|
2
2
|
|
|
3
3
|
> Keep the rows in your own Postgres while Ablo coordinates and confirms every write.
|
|
4
4
|
|
|
5
|
+
## Localhost development
|
|
6
|
+
|
|
7
|
+
Ablo Cloud cannot dial `localhost`: from a cloud server, that name means the
|
|
8
|
+
cloud server itself, not your Mac or development container. A development child
|
|
9
|
+
branch can still use Postgres that listens only on your machine by running a
|
|
10
|
+
signed Data Source over Ablo's outbound reverse channel:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npx ablo migrate # once: models + ablo_idempotency + ablo_outbox
|
|
14
|
+
npx ablo dev --local
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The command loads `ablo/data-source.ts`, registers the current child branch as
|
|
18
|
+
connector-only, and dials out to Ablo over an authenticated WebSocket. Postgres
|
|
19
|
+
continues listening only on your machine; `DATABASE_URL` never leaves the
|
|
20
|
+
process. This is protocol-scoped, not a general-purpose tunnel: only signed
|
|
21
|
+
Data Source load, list, commit, and event requests traverse it. Use
|
|
22
|
+
`--source <path>` when the handler lives elsewhere.
|
|
23
|
+
|
|
24
|
+
Keep `ablo dev --local` running alongside the application. It pushes schema
|
|
25
|
+
changes and owns the database connector; stopping it deliberately makes the
|
|
26
|
+
branch's database unavailable instead of silently writing somewhere else.
|
|
27
|
+
|
|
28
|
+
### Is this full Ablo?
|
|
29
|
+
|
|
30
|
+
Yes for the Ablo application path: model reads and lists, coordinated writes,
|
|
31
|
+
claims, subscriptions, idempotency, confirmations, and transactional outbox
|
|
32
|
+
settlement all work against localhost Postgres. The browser, server code, and
|
|
33
|
+
agents still connect to Ablo Cloud; only database operations cross the narrow
|
|
34
|
+
signed connector to your machine.
|
|
35
|
+
|
|
36
|
+
It is not logical replication. Visibility depends on how a row is written:
|
|
37
|
+
|
|
38
|
+
| Write origin | Visible to Ablo in localhost mode? | Why |
|
|
39
|
+
|---|---:|---|
|
|
40
|
+
| `ablo.<model>.create/update/delete` | Yes | Ablo coordinates the write, the local adapter commits it with idempotency + outbox, and the outbox event confirms it. |
|
|
41
|
+
| Code using the signed Data Source adapter | Yes | The adapter records the row and authoritative event in one transaction. |
|
|
42
|
+
| A supported source push/outbox integration | Yes | It explicitly publishes the authoritative event to Ablo. |
|
|
43
|
+
| Raw SQL, `psql`, or an unrelated ORM write | No, not automatically | There is no WAL reader in signed-endpoint mode, and bypassing the adapter does not append `ablo_outbox`. |
|
|
44
|
+
|
|
45
|
+
If Ablo must observe every arbitrary SQL/ORM write, use the direct logical-WAL
|
|
46
|
+
path with a network-reachable Postgres endpoint, PrivateLink/peering/VPN, or a
|
|
47
|
+
database-capable secure tunnel. Do not expose Postgres without TLS,
|
|
48
|
+
authentication, and network restrictions.
|
|
49
|
+
|
|
50
|
+
### Local connector errors
|
|
51
|
+
|
|
52
|
+
Every stable code links to the generated [error reference](https://docs.abloatai.com/errors):
|
|
53
|
+
|
|
54
|
+
| Code | Meaning and fix |
|
|
55
|
+
|---|---|
|
|
56
|
+
| `source_connector_not_attached` | The branch is connector-only but no process is attached. Start or restart `ablo dev --local`. |
|
|
57
|
+
| `source_connector_unauthenticated` | The temporary branch key is missing, expired, or rejected. Rerun `ablo dev --local` to mint a fresh key. |
|
|
58
|
+
| `source_connector_requires_secret_key` | The connector received the wrong key kind. Let `ablo dev` supply its branch-bound `sk_` key. |
|
|
59
|
+
| `source_connector_no_source_registered` | No endpoint source exists for this branch. Upgrade/rerun the CLI so registration happens before socket attachment. |
|
|
60
|
+
| `source_connector_localhost_required` | Connector-only registration used a non-local descriptor. Use `ablo dev --local`; deployed handlers use ordinary HTTPS endpoint registration. |
|
|
61
|
+
| `source_connector_timeout` | The handler or local Postgres exceeded the request deadline. Inspect the local process and database. |
|
|
62
|
+
| `source_connector_handler_error` | `ablo/data-source.ts` or its adapter threw. The local terminal contains the underlying error. |
|
|
63
|
+
| `source_connector_protocol_error` | CLI/SDK and service connector protocols disagree. Upgrade the CLI and SDK together. |
|
|
64
|
+
| `source_connector_production_not_enabled` | A root/production key attempted the development connector. Use a supported production route or explicitly enable production reverse-channel support. |
|
|
65
|
+
|
|
66
|
+
Disconnects, service restarts, and connector replacement are retryable. Keep the
|
|
67
|
+
same idempotency key: Ablo never falls back from this branch to hosted storage or
|
|
68
|
+
another database.
|
|
69
|
+
|
|
5
70
|
You write through Ablo, and Ablo writes to your Postgres. A call to
|
|
6
71
|
`ablo.<model>.create / update / delete` enters Ablo's commit chokepoint — where
|
|
7
72
|
claims, ordering, and idempotency are enforced — and Ablo applies the change to
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Repository Structure
|
|
2
2
|
|
|
3
|
+
For a verb-by-verb guide to declarations and implementations—including exactly
|
|
4
|
+
where `create`, `update`, `delete`, and `claim` live—read the public
|
|
5
|
+
[`CODEMAP.md`](../../CODEMAP.md).
|
|
6
|
+
|
|
3
7
|
The public repository preserves the same ownership boundaries as the main
|
|
4
8
|
monorepo. `@abloatai/ablo` is the product package; the packages beneath it are
|
|
5
9
|
implementation owners and first-party extension surfaces.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abloatai/ablo",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.48.0",
|
|
4
4
|
"description": "The public Ablo SDK for coordinated reads, commits, claims, observation, and reactive applications.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -124,8 +124,8 @@
|
|
|
124
124
|
"directory": "packages/ablo"
|
|
125
125
|
},
|
|
126
126
|
"dependencies": {
|
|
127
|
-
"@abloatai/humans": "^0.
|
|
128
|
-
"@abloatai/transaction": "^0.
|
|
127
|
+
"@abloatai/humans": "^0.48.0",
|
|
128
|
+
"@abloatai/transaction": "^0.48.0"
|
|
129
129
|
},
|
|
130
130
|
"peerDependencies": {
|
|
131
131
|
"ai": "^6.0.0 || ^7.0.0",
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
# Agent Orchestration
|
|
2
|
-
|
|
3
|
-
Do not model parent and child agents as directly talking to each other over WebSocket.
|
|
4
|
-
|
|
5
|
-
Model them as actors coordinating through models:
|
|
6
|
-
|
|
7
|
-
```txt
|
|
8
|
-
parent creates job -> child claims job -> child commits result -> parent reads result
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
The WebSocket is delivery infrastructure. The product model is shared state.
|
|
12
|
-
|
|
13
|
-
## Model Shape
|
|
14
|
-
|
|
15
|
-
A parent creates a job through its typed model client:
|
|
16
|
-
|
|
17
|
-
```ts
|
|
18
|
-
const jobId = `forecast:${runId}`;
|
|
19
|
-
await ablo.agentJobs.create({
|
|
20
|
-
id: jobId,
|
|
21
|
-
idempotencyKey: `job:${runId}`,
|
|
22
|
-
data: {
|
|
23
|
-
status: 'open',
|
|
24
|
-
kind: 'forecast_report',
|
|
25
|
-
target: { model: 'weatherReports', id: 'report_stockholm', field: 'forecast' },
|
|
26
|
-
},
|
|
27
|
-
});
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
The child claims the job. If another worker holds it, the claim waits fairly,
|
|
31
|
-
then returns the fresh row:
|
|
32
|
-
|
|
33
|
-
```ts
|
|
34
|
-
await using claim = await ablo.agentJobs.claim({
|
|
35
|
-
id: jobId,
|
|
36
|
-
description: 'complete',
|
|
37
|
-
ttl: '5m',
|
|
38
|
-
});
|
|
39
|
-
const job = claim.data;
|
|
40
|
-
|
|
41
|
-
await ablo.agentJobs.update({
|
|
42
|
-
id: job.id,
|
|
43
|
-
data: {
|
|
44
|
-
status: 'completed',
|
|
45
|
-
result: { text },
|
|
46
|
-
},
|
|
47
|
-
});
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
The child commits completion through the normal `update`, which is stale-guarded
|
|
51
|
-
under the held claim. The claim releases when its scope exits.
|
|
52
|
-
|
|
53
|
-
The parent retrieves the job result by model ID. Later, `ablo.events` can make that reactive, but the state model does not change.
|
|
54
|
-
|
|
55
|
-
## Rule
|
|
56
|
-
|
|
57
|
-
Nested agents should create or complete models. They should not require a separate agent-to-agent protocol for normal work.
|