@abloatai/ablo 0.43.0 → 0.44.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 +27 -0
- package/docs/debugging.md +61 -6
- package/docs/deployment.md +2 -2
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.44.0
|
|
4
|
+
|
|
5
|
+
### A scope denial names the wall it hit
|
|
6
|
+
|
|
7
|
+
`capability_scope_denied` now distinguishes the Ablo capability allowlist
|
|
8
|
+
from the customer database's row-level security. The error carries the
|
|
9
|
+
required capability, the resolved operations, the participant and user
|
|
10
|
+
principal, the branch, the organization and project, and any applied session
|
|
11
|
+
settings, so "permission denied" is a diagnosis instead of a dead end: you
|
|
12
|
+
can see whether your grant was missing a verb or whether your own database's
|
|
13
|
+
row policy rejected the session context Ablo applied.
|
|
14
|
+
|
|
15
|
+
### Write failures carry their request id
|
|
16
|
+
|
|
17
|
+
A WebSocket write failure now carries the `requestId` the server logged it
|
|
18
|
+
under, and a `wait: 'confirmed'` write rejects with the complete typed error
|
|
19
|
+
rather than a bare failure, so the error you catch is the error the server
|
|
20
|
+
recorded.
|
|
21
|
+
|
|
22
|
+
### `doctor` reports readiness, not destiny
|
|
23
|
+
|
|
24
|
+
`doctor` now says infrastructure is ready rather than promising a write will
|
|
25
|
+
succeed, because database constraints and row-level security still apply at
|
|
26
|
+
write time. The debugging guide explains how to read the new diagnostics,
|
|
27
|
+
and documents that `list()` may answer from the local pool while
|
|
28
|
+
`list({ type: 'complete' })` waits for the server round trip.
|
|
29
|
+
|
|
3
30
|
## 0.43.0
|
|
4
31
|
|
|
5
32
|
### Keys are branch-first
|
package/docs/debugging.md
CHANGED
|
@@ -15,12 +15,13 @@ const ablo = Ablo({ schema, apiKey: process.env.ABLO_API_KEY, debug: true });
|
|
|
15
15
|
|
|
16
16
|
## CLI environment and target
|
|
17
17
|
|
|
18
|
-
`
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
Read-only diagnostics (`status`, `whoami`, `logs`, and `connect locate/check`)
|
|
19
|
+
may inspect the application-facing chain: exported `ABLO_API_KEY`,
|
|
20
|
+
`.env.local`, `.env`, then the stored credential. An exported value wins over
|
|
21
|
+
project files. Mutations (`push` and `connect apply/rotate/register/deregister`)
|
|
22
|
+
are intentionally stricter: they read the process environment, an explicit
|
|
23
|
+
`--env-file`, or a stored compatibility credential. An ambient file cannot
|
|
24
|
+
silently choose the branch a mutation acts on.
|
|
24
25
|
|
|
25
26
|
Use the two diagnostics according to the question:
|
|
26
27
|
|
|
@@ -232,3 +233,57 @@ AbloValidationError [model_required_field_missing]: A required field was absent.
|
|
|
232
233
|
```
|
|
233
234
|
|
|
234
235
|
Branch on `err.code` (stable) — never on the message (rewordable). See [Client Behavior](./client-behavior.md) for the full error model and which codes are safe to retry.
|
|
236
|
+
|
|
237
|
+
### Diagnosing `capability_scope_denied`
|
|
238
|
+
|
|
239
|
+
The same stable code covers two different enforcement layers, so inspect
|
|
240
|
+
`error.details.origin`:
|
|
241
|
+
|
|
242
|
+
- `capability_allowlist`: the branch/session credential did not grant the
|
|
243
|
+
operation. `requiredCapability.scope` names the missing `model.verb`, and
|
|
244
|
+
`details.resolvedOperations` shows the grants the server actually resolved.
|
|
245
|
+
- `database_row_level_security`: Ablo's capability gate allowed the operation,
|
|
246
|
+
but Postgres rejected it under the customer table's RLS policy.
|
|
247
|
+
`details.databaseSessionContext` shows the organization, project, branch,
|
|
248
|
+
participant kind, user principal, and custom session-setting values applied
|
|
249
|
+
to that transaction.
|
|
250
|
+
|
|
251
|
+
Every rejected live commit carries `requestId` on the thrown error and
|
|
252
|
+
`request_id` in its JSON form and warning line:
|
|
253
|
+
|
|
254
|
+
```ts
|
|
255
|
+
import { AbloError } from '@abloatai/ablo';
|
|
256
|
+
|
|
257
|
+
try {
|
|
258
|
+
await ablo.documents.create({
|
|
259
|
+
data,
|
|
260
|
+
wait: 'confirmed',
|
|
261
|
+
});
|
|
262
|
+
} catch (error) {
|
|
263
|
+
if (error instanceof AbloError) {
|
|
264
|
+
console.error(error.code, error.requestId, error.requiredCapability, error.details);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
With `wait: 'confirmed'`, the awaited call rejects with that complete typed
|
|
270
|
+
error. `onMutationFailure` remains the notification channel for optimistic
|
|
271
|
+
writes that return before the server answers; it is not required to recover
|
|
272
|
+
details from a confirmed write.
|
|
273
|
+
|
|
274
|
+
### Local reads versus a confirmed server read
|
|
275
|
+
|
|
276
|
+
`list()` without a completeness option may return the current local pool
|
|
277
|
+
immediately. That is why it can be empty while Postgres contains rows: it is not
|
|
278
|
+
evidence that the replication source has no history.
|
|
279
|
+
|
|
280
|
+
Use:
|
|
281
|
+
|
|
282
|
+
```ts
|
|
283
|
+
await ablo.documents.list({ type: 'complete' });
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
`type: 'complete'` waits for a server round trip and returns the confirmed
|
|
287
|
+
result. `type: 'unknown'` returns the local result immediately and refreshes it
|
|
288
|
+
in the background. The distinction is freshness/completeness, not claimed
|
|
289
|
+
versus unclaimed data.
|
package/docs/deployment.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> What production takes: a database Ablo can reach, a key minted for the plane you mean, and a schema push in the deploy.
|
|
4
4
|
|
|
5
|
-
One command answers the
|
|
5
|
+
One command answers whether the infrastructure needed for a write is ready
|
|
6
6
|
right now, and if not, why:
|
|
7
7
|
|
|
8
8
|
```bash
|
|
@@ -25,7 +25,7 @@ ABLO_API_KEY=sk_… npx ablo status
|
|
|
25
25
|
• fulfilments typename=fulfilments
|
|
26
26
|
• reviews typename=reviews
|
|
27
27
|
|
|
28
|
-
✓ ready —
|
|
28
|
+
✓ write infrastructure is ready — database constraints and row-level policies still apply
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
`status` asks the routing authority rather than sampling a read, because reads
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abloatai/ablo",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.44.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.44.0",
|
|
128
|
+
"@abloatai/transaction": "^0.44.0"
|
|
129
129
|
},
|
|
130
130
|
"peerDependencies": {
|
|
131
131
|
"ai": "^6.0.0 || ^7.0.0",
|