@abloatai/ablo 0.53.0 → 0.54.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 CHANGED
@@ -1,5 +1,135 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.54.0
4
+
5
+ ### A scoped session is scoped everywhere it is read
6
+
7
+ Seven surfaces each answered "which sync groups may this request see", and two of
8
+ them consulted only `effectiveSyncGroups` before falling back to an
9
+ organization-wide anchor. `syncGroups` is the only field an `ek_` session key
10
+ populates, so a session scoped to one workspace was correctly narrowed on five
11
+ surfaces and read organization-wide on the other two. Nothing failed while they
12
+ disagreed, because each surface's tests pinned that surface to itself.
13
+
14
+ One module now owns the precedence, and a plane states its difference as an
15
+ argument rather than as another copy of the rule. A declared set that is empty
16
+ means nothing rather than everything, so a session minted with no groups closes
17
+ instead of widening.
18
+
19
+ ### A change reaches the clients watching it, whatever the column is called
20
+
21
+ Deltas were written in two key shapes. The commit path wrote declared schema
22
+ field names; the replication echo wrote the customer's physical column names
23
+ undecoded. Neither reader reconciled them, because the client applies a delta
24
+ onto the model verbatim.
25
+
26
+ For a source whose columns are renamed, by `.from(...)` or simply by being
27
+ snake_case, every change reached subscribers keyed wrong, and the lookup that
28
+ stamps a scope-root group found nothing on a physical row. Such a delta kept only
29
+ its organization group, so a client joined to `workspace:<id>` was never sent a
30
+ change it was watching: the write landed, and nothing was announced to anyone
31
+ listening. Rows are renamed once now, where they enter, and one spelling holds
32
+ below that seam.
33
+
34
+ ### Reordering a claim queue takes effect
35
+
36
+ A reorder took effect for nobody. The route addressed the frame to an
37
+ organization group, which entity-scoped fan-out removes, so the frame was built
38
+ and then dropped as having no audience. A queue change now goes to the waiters in
39
+ that line, each of which recorded what it listens on when it enqueued.
40
+
41
+ ### A commit costs a fixed number of round trips
42
+
43
+ A direct write paid three round trips to the customer's database plus one per
44
+ row. Sharing a region that is a few milliseconds, but across continents it
45
+ dominated the wait: an engine in `eu-north-1` against a database in `us-east-2`
46
+ measured about four seconds per confirmed write, most of it in trips nobody had
47
+ counted.
48
+
49
+ Three changes remove trips without altering what the database sees. The session
50
+ bundle is one statement over parallel name and value arrays rather than eleven
51
+ settings awaited in turn, and is still transaction-scoped. The ledger completion
52
+ and the replication marker travel as one data-modifying statement, which Postgres
53
+ runs to completion whether or not the primary query reads it. And a direct commit
54
+ dispatches its operations before awaiting any of them, so the driver pipelines
55
+ them.
56
+
57
+ Ordering is unchanged: Postgres still runs those operations in order on the
58
+ connection, so a later one still sees an earlier one's write, two writes to the
59
+ same row stay well-defined last-write-wins, and each operation keeps its own
60
+ error so a failure still names itself.
61
+
62
+ ### Engine-reserved groups have a constructor
63
+
64
+ `identityAnchor` builds the sync groups the engine reserves, so the `kind:id`
65
+ convention has one home instead of being spelled inline:
66
+
67
+ ```ts
68
+ import { identityAnchor } from '@abloatai/ablo/schema';
69
+
70
+ identityAnchor('org', organizationId);
71
+ identityAnchor('user', participantId);
72
+ identityAnchor('project', projectId);
73
+ ```
74
+
75
+ `IDENTITY_ANCHOR_KINDS` and `IdentityAnchorKind` are exported alongside it.
76
+ Schema-declared roles continue to extend this vocabulary per application; these
77
+ three are the kinds the engine reserves.
78
+
79
+ ### The cross-organization scope is `organization:act-as`
80
+
81
+ The scope authorizing a secret key to mint a session into another organization is
82
+ now `organization:act-as`, and it names what it grants rather than the mechanism
83
+ it was first attached to. Keys already carrying `ephemeral:mint-any-org` keep
84
+ working, because the old spelling resolves to the new one.
85
+
86
+ ### An outbox event carries declared field names
87
+
88
+ A hand-written `events` handler must key its `data` by the model's declared
89
+ schema fields rather than by the table's columns. A field named `reviewStatus`
90
+ arrives as `reviewStatus` even when it reads from a `review_status` column:
91
+
92
+ ```ts
93
+ // the model declares reviewStatus from a review_status column
94
+ data: { id: row.id, reviewStatus: row.review_status },
95
+ ```
96
+
97
+ Ablo's own adapters rename the row before writing the outbox, so a source built
98
+ on one of them is already in this shape. Ablo reads that spelling and never falls
99
+ back to the physical one: two namespaces that can collide have no safe merge, and
100
+ a key read as the wrong field would route a change into another scope root.
101
+
102
+ ### CLI: report what got in your way
103
+
104
+ `ablo feedback` is the channel for the two things no counter can carry, because
105
+ neither is a sentence: the doc that was missing, and the thing that worked but
106
+ was hard.
107
+
108
+ ```
109
+ ablo feedback docs "no example of paging a filtered list" --yes
110
+ ```
111
+
112
+ `<kind>` is `bug`, `docs`, `feature`, or `friction`. Add `--detail <text>` for
113
+ the long version, where `-` reads stdin, and `--command` or `--error-code` to
114
+ pre-group the report from what you just saw. `--yes` sends without confirming
115
+ and `--json` returns a machine-readable receipt, so a non-interactive caller
116
+ needs no terminal.
117
+
118
+ It is never automatic. Nothing sends unless the command is run, and nothing
119
+ rides the telemetry queue, so turning telemetry off does not also turn off bug
120
+ reporting, and leaving it on does not start sending prose. The text is redacted
121
+ before it leaves, by the same rule error observations already pass through, and
122
+ on a terminal you see the redacted version before it is sent. Nothing is read
123
+ from your repository, and there is no flag to attach a file.
124
+
125
+ ### Removed
126
+
127
+ `normalizeAbloHostedBaseUrl` is removed, as 0.53.0 announced. Use
128
+ `normalizeAbloBaseUrl`, which the old name has resolved to since then.
129
+
130
+ `CapabilityExchangeResponse` is announced for removal in 0.55.0. Use
131
+ `CapabilityMintResponse`; both already resolve to the same contract.
132
+
3
133
  ## 0.53.0
4
134
 
5
135
  ### A collection read says where the collection ends
package/docs/api-keys.md CHANGED
@@ -217,7 +217,7 @@ restricted to exactly those grants:
217
217
  - `project:manage` — list, create, and rename projects.
218
218
  - `branch:manage` — list, create, and delete child branches and mint their
219
219
  temporary credentials.
220
- - `ephemeral:mint-any-org` — cross-organization authority to mint a short-lived
220
+ - `organization:act-as` — cross-organization authority to mint a short-lived
221
221
  user session into a customer organization. It follows the Stripe Connect shape:
222
222
  the request names the customer organization, but the resulting session is
223
223
  still bounded by its `can` grant and expiry. A key restricted to this scope
@@ -234,7 +234,7 @@ manage siblings or gain root authority.
234
234
 
235
235
  ### Cross-organization mint keys
236
236
 
237
- Most applications do not need `ephemeral:mint-any-org`: their backend key mints
237
+ Most applications do not need `organization:act-as`: their backend key mints
238
238
  users into its own organization. A multi-organization backend needs it only
239
239
  when each customer is a separate Ablo organization and one trusted service
240
240
  mints sessions for all of them.
@@ -242,7 +242,7 @@ mints sessions for all of them.
242
242
  Treat that key as a dedicated minting credential:
243
243
 
244
244
  - keep it in a server-side secret manager, never a browser or repository;
245
- - grant only `ephemeral:mint-any-org`, with no data or schema scopes;
245
+ - grant only `organization:act-as`, with no data or schema scopes;
246
246
  - mint short-lived sessions with the smallest typed `can` grant;
247
247
  - rotate it on a schedule and revoke it immediately after suspected exposure;
248
248
  - log the target `organizationId`, minted session id, and request id for audit.
@@ -26,7 +26,7 @@ user session names that customer organization.
26
26
 
27
27
  - An owning project containing the schema every customer uses.
28
28
  - The schema pushed to that project's production root.
29
- - A server-side `sk_` carrying only `ephemeral:mint-any-org`.
29
+ - A server-side `sk_` carrying only `organization:act-as`.
30
30
  - A customer `organizationId` resolved from your authenticated application
31
31
  membership, never accepted unchecked from the browser.
32
32
  - A model-by-model `can` grant for the UI being opened.
@@ -159,7 +159,7 @@ through the control-plane process you use for provisioning.
159
159
  ## Security checklist
160
160
 
161
161
  - Store the cross-organization key only in the backend secret manager.
162
- - Give it only `ephemeral:mint-any-org`; do not combine minting with schema or
162
+ - Give it only `organization:act-as`; do not combine minting with schema or
163
163
  data authority.
164
164
  - Resolve `organizationId` from authenticated membership server-side.
165
165
  - Keep `can` to the smallest model/verb set the UI needs.
@@ -175,7 +175,7 @@ through the control-plane process you use for provisioning.
175
175
  ### The mint is forbidden
176
176
 
177
177
  The presenting credential must be a secret `sk_` with
178
- `ephemeral:mint-any-org`. A normal project key can mint users into its own
178
+ `organization:act-as`. A normal project key can mint users into its own
179
179
  organization but cannot name another one. Run `npx ablo whoami --json` in the
180
180
  backend environment to confirm which project and branch the configured key
181
181
  actually belongs to; the command never prints the full secret.
package/docs/identity.md CHANGED
@@ -238,7 +238,7 @@ shared schema only *describes* the shape; the data plane stays the customer's an
238
238
  can't cross-leak. `schemaProject: { organizationId, projectId }` remains
239
239
  available as an explicit override for migrations or advanced routing. Omit
240
240
  `organizationId` for the single-organization default above. Requires a dedicated
241
- `sk_` with `ephemeral:mint-any-org`; see
241
+ `sk_` with `organization:act-as`; see
242
242
  [Customer Organizations](./customer-organizations.md).
243
243
 
244
244
  ## The two halves of scoping
package/docs/sessions.md CHANGED
@@ -154,7 +154,7 @@ for the actor.
154
154
  |---|---|---|
155
155
  | `user` / `agent` | both | The actor. `id` becomes the token's `participantId`. Pass exactly one. |
156
156
  | `can` | both | Required non-empty per-model operation allowlist, typed off the schema. |
157
- | `organizationId` | user | Mint into a customer organization instead of the key's own. Requires `ephemeral:mint-any-org`. |
157
+ | `organizationId` | user | Mint into a customer organization instead of the key's own. Requires `organization:act-as`. |
158
158
  | `schemaProject` | user | Override the schema project for a cross-org mint. Usually omitted because the owning key's project is the default. |
159
159
  | `syncGroups` | both | Narrow the session below its default scope. Omit to inherit. |
160
160
  | `ttlSeconds` | both | Lifetime in seconds. Defaults to `900` (15m). |
@@ -286,7 +286,7 @@ plane (connection + row-level isolation) stays the customer's. A shared schema
286
286
  can't leak data across orgs.
287
287
 
288
288
  <Note>
289
- This requires a dedicated `sk_` carrying the `ephemeral:mint-any-org` scope —
289
+ This requires a dedicated `sk_` carrying the `organization:act-as` scope —
290
290
  only a trusted cross-organization key can mint a session into another org. Omit
291
291
  `organizationId` and you get the default above: one project, one schema, all
292
292
  your users in the key's own organization.
package/llms.txt CHANGED
@@ -243,4 +243,20 @@ Do not teach `/api`, `/agent`, `/core`, `/realtime`, or internal subpaths. (`/so
243
243
 
244
244
  - `npx ablo docs` lists every documentation page; `npx ablo docs <page>` prints one as markdown. These pages ship INSIDE the installed package, so they describe the version in `node_modules` and need no network. Prefer them over a docs URL whenever the project pins a version: a website always describes the newest release, so on an older pin it will hand you a call your package does not have (`retrieve`/`list` replaced `get`/`getAll`/`getCount` in 0.35.0). One-shot, safe to run unattended.
245
245
 
246
- Canonical docs to read before integrating: `quickstart`, `branch-development`, `schema-contract`, `integration-guide`, `deployment`, `guarantees`, `client-behavior`, `data-sources`, `examples/existing-python-backend`, `api`, `examples/ai-sdk-tool`, and `examples/server-agent` — read each with `npx ablo docs <page>`. When upgrading an existing integration, read `migration` — every breaking change, what to change, and which version introduced it. When the customer's database has row-level-security policies, read `session-settings` — the identity context Ablo sets before every write, and how to map it to the setting names those policies already read.
246
+ ## Documentation
247
+
248
+ Canonical docs to read before integrating, in this order. Read each with `npx ablo docs <page>` when the project pins a version; the links describe the newest release.
249
+
250
+ - [Quickstart](https://docs.abloatai.com/quickstart)
251
+ - [Branch-first development](https://docs.abloatai.com/branch-development)
252
+ - [Schema Contract](https://docs.abloatai.com/schema-contract)
253
+ - [Integration Guide](https://docs.abloatai.com/integration-guide)
254
+ - [Deployment](https://docs.abloatai.com/deployment)
255
+ - [Guarantees](https://docs.abloatai.com/guarantees)
256
+ - [Client Behavior](https://docs.abloatai.com/client-behavior)
257
+ - [Connect Your Database](https://docs.abloatai.com/data-sources)
258
+ - [API](https://docs.abloatai.com/api)
259
+ - Examples: [Existing Python Backend](https://docs.abloatai.com/examples/existing-python-backend), [AI SDK Tool](https://docs.abloatai.com/examples/ai-sdk-tool), [Server Agent](https://docs.abloatai.com/examples/server-agent)
260
+ - [Upgrade Guide](https://docs.abloatai.com/migration): when upgrading an existing integration; every breaking change, what to change, and which version introduced it.
261
+ - [Session Settings](https://docs.abloatai.com/session-settings): when the customer's database has row-level-security policies; the identity context Ablo sets before every write, and how to map it to the setting names those policies read.
262
+ - [Every page, one line each](https://docs.abloatai.com/llms.txt), or [the full docs as one file](https://docs.abloatai.com/llms-full.txt).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abloatai/ablo",
3
- "version": "0.53.0",
3
+ "version": "0.54.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",
@@ -137,8 +137,8 @@
137
137
  "directory": "packages/ablo"
138
138
  },
139
139
  "dependencies": {
140
- "@abloatai/humans": "^0.53.0",
141
- "@abloatai/transaction": "^0.53.0",
140
+ "@abloatai/humans": "^0.54.0",
141
+ "@abloatai/transaction": "^0.54.0",
142
142
  "zod": "^4.4.3"
143
143
  },
144
144
  "peerDependencies": {