@abloatai/ablo 0.42.0 → 0.43.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/docs/sessions.md CHANGED
@@ -31,8 +31,7 @@ the raw agent token.
31
31
  It exists because of one rule: **the browser can never hold a secret.** Your
32
32
  `sk_` lives on the server; the browser only ever holds a minted session token
33
33
  (which already names your org). So the per-actor credential is minted
34
- server-side, scoped, and expires in minutes — the model Stripe uses for
35
- client-side SDKs.
34
+ server-side, scoped, and expires in minutes.
36
35
 
37
36
  ## Why
38
37
 
@@ -90,7 +89,7 @@ export function Providers({ children }: { children: React.ReactNode }) {
90
89
  ```
91
90
 
92
91
  The client owns auth, the credential lifecycle, and the connection; the provider
93
- is the thin reactive binding over it (Stripe's `<Elements stripe={...}>` model).
92
+ is only the thin reactive binding over it.
94
93
  Build the client **once** at module scope — a new instance per render tears down
95
94
  the socket. Need custom headers or a
96
95
  body on the exchange? `authEndpoint` also accepts an async resolver that
package/docs/webhooks.md CHANGED
@@ -8,8 +8,8 @@ database; Ablo holds only the log. **Webhooks stream that log to your systems as
8
8
  signed events:** every committed change is POSTed to an endpoint in your app, and
9
9
  your handler decides what to do with it.
10
10
 
11
- It's the same two-sided shape as Stripe: you call Ablo to make changes (the
12
- client), and Ablo calls you with each change (this webhook). Webhooks are the
11
+ You call Ablo to make changes through the client, and Ablo calls your webhook
12
+ with each committed change. Webhooks are the
13
13
  *push* way to keep a store in step with the log — your own database, a warehouse,
14
14
  a search index, a background job. The *direct* alternative is `ablo connect`,
15
15
  where Ablo reads your write-ahead log and writes back through a scoped role. Either
@@ -30,18 +30,8 @@ There are two ways data flows out of Ablo, and they're for different jobs:
30
30
  Most apps use both: the realtime stream for the UI, the webhook stream to keep
31
31
  their database in sync. This page is the webhook stream.
32
32
 
33
- If you know Stripe, you already know the shape:
34
-
35
- | Stripe | Ablo |
36
- |---|---|
37
- | `stripe.x.create(...)`: make the change | the Ablo client: make the change (+ live sync) |
38
- | `/stripe-webhook`: confirm and persist | `/api/ablo/[...all]`: persist into your database |
39
- | Stripe owns the charges | Ablo owns the transaction log |
40
- | you mirror charges into your database | you mirror the log into your database |
41
-
42
- The difference in Ablo's favor: every event carries `syncId`, a monotonic log
43
- position, so you can both dedupe **and** apply in order — Ablo guarantees the
44
- order because it owns the log.
33
+ Every event carries `syncId`, a monotonic log position, so you can both dedupe
34
+ **and** apply in order. Ablo guarantees the order because it owns the log.
45
35
 
46
36
  ## The event object
47
37
 
@@ -52,7 +42,7 @@ Every delivery is a batch of events. Each event:
52
42
  | `type` | `"<model>.<verb>"` with the model name lowercased, e.g. `task.updated` |
53
43
  | `model` | the model name exactly as declared in your schema: the table to write |
54
44
  | `objectId` | the changed row's id |
55
- | `data` | the post-change row, or `null` on delete (like Stripe's `event.data.object`) |
45
+ | `data` | the post-change row, or `null` on delete |
56
46
  | `syncId` | monotonic log position: **dedupe and order by this** |
57
47
  | `id` | `String(syncId)`: the event id |
58
48
  | `createdAt` | ISO commit timestamp |
@@ -38,7 +38,7 @@ root and a bare `quickstart.ts` won't be found.
38
38
 
39
39
  ```bash
40
40
  cd packages/ablo
41
- ABLO_API_KEY=sk_test_... npx tsx examples/quickstart.ts
41
+ ABLO_API_KEY=sk_... npx tsx examples/quickstart.ts
42
42
  ```
43
43
 
44
44
  ## Data Source (customer-owned database)
@@ -23,7 +23,7 @@ import { handleAbloSource, _inspectStore } from './customer-server';
23
23
  import { AbloDriver } from './ablo-driver';
24
24
 
25
25
  const API_KEY =
26
- process.env.ABLO_API_KEY ?? 'sk_test_example_key_do_not_use_in_prod';
26
+ process.env.ABLO_API_KEY ?? 'sk_example_key_do_not_use';
27
27
 
28
28
  // `dataSource()` reads `options.apiKey` at request time; we re-export
29
29
  // the same value to the driver so signer and verifier agree.
@@ -70,7 +70,7 @@ async function main() {
70
70
  log('\n--- 5. signature failure (wrong API key) ---');
71
71
  const badDriver = new AbloDriver({
72
72
  handler: handleAbloSource,
73
- apiKey: 'sk_test_wrong_key',
73
+ apiKey: 'sk_wrong_example_key',
74
74
  });
75
75
  try {
76
76
  await badDriver.load('tasks', 'task_seed');
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Run:
5
5
  *
6
- * ABLO_API_KEY=sk_test_... npx tsx examples/quickstart.ts
6
+ * ABLO_API_KEY=sk_... npx tsx examples/quickstart.ts
7
7
  */
8
8
 
9
9
  import Ablo from '@ablo/ablo';
package/llms.txt CHANGED
@@ -25,11 +25,13 @@ First action when integrating into an app: run `npx ablo init --yes --framework
25
25
 
26
26
  Second: make sure a key exists — WITHOUT printing it. The key is a secret; it must never appear in your output, your reasoning, or a file you echo (it would live in the conversation history forever). Check PRESENCE only: `[ -n "$ABLO_API_KEY" ] && echo set` and `grep -cq '^ABLO_API_KEY=' .env.local && echo wired` — never `cat .env.local`, never `echo $ABLO_API_KEY`. If neither check passes, ask the HUMAN to run `npx ablo login` once — it opens a browser and saves a project-scoped branch-management key locally; an agent must NOT run it. You never copy a runtime key by hand: the next step mints one for the development branch, writes it into `.env.local`, and gitignores it.
27
27
 
28
- Then PREPARE THE BRANCH AND PUSH — this is the step everything depends on. The server keeps its OWN copy of the schema. Run `npx ablo dev --no-watch --branch <git-or-ci-ref>`: it ensures an isolated child branch, exchanges the CLI key for an expiring branch-only `sk_test_` key, writes that key to gitignored `.env.local`, pushes `ablo/schema.ts`, and exits. Until the schema is pushed, EVERY write to a new or changed model fails with `server_execute_unknown_model`. Re-run it after schema changes. Plain `dev` watches forever; never run it bare in an agent. `push` is the lower-level one-shot command for an already selected credential, including a reviewed production deployment.
28
+ Then PREPARE THE BRANCH AND PUSH — this is the step everything depends on. The server keeps its OWN copy of the schema. Run `npx ablo dev --no-watch --branch <git-or-ci-ref>`: it ensures an isolated child branch, exchanges the CLI key for an expiring branch-only `sk_` key, writes that key to gitignored `.env.local`, pushes `ablo/schema.ts`, and exits. Until the schema is pushed, EVERY write to a new or changed model fails with `server_execute_unknown_model`. Re-run it after schema changes. Plain `dev` watches forever; never run it bare in an agent. `push` is the lower-level one-shot command for an already selected credential, including a reviewed production deployment.
29
+
30
+ Branches replace manual environment-key juggling. Runtime code always reads ONE `ABLO_API_KEY`; `ablo dev` wires the Git branch's expiring value. Do not create permanent `ABLO_STAGING_KEY` / `ABLO_DEV_KEY` selectors. `npx ablo whoami` strictly confirms the current key's project + immutable branch; `npx ablo whoami --key-env <NAME>` explicitly inspects a named process/`.env.local`/`.env` value for CI, migration, or stranded-plane recovery without putting the secret in argv. `status` is the broad readiness report; `whoami` is the narrow identity answer.
29
31
 
30
32
  ## Projects (one org, many apps)
31
33
 
32
- Each app gets its own PROJECT inside the org — its own schema, its own sandbox/production data planes, its own keys (the Neon/Supabase shape). `npx ablo init` creates one automatically (slug from package.json name; `--project <slug>` to choose, `--no-project` for the org default). A key belongs to exactly ONE project, fixed at mint; everything it mints inherits it. Touching another project's models fails typed: `project_scope_denied` (403) — the fix is a key minted for THAT project, never `ablo push`. Manage: `npx ablo projects list|create <slug>|use <slug|default>`; `npx ablo status` shows the active project. Wire: `GET/POST /api/v1/projects` (sk_ bearer; duplicate slug → `project_slug_taken` 409).
34
+ Each app gets its own PROJECT inside the org — its own production root + development/preview child branches, each with branch-bound schema, rows, database registration, claims, log, and credentials (the Neon/Supabase shape). `npx ablo init` creates one automatically (slug from package.json name; `--project <slug>` to choose, `--no-project` for the org default). A key belongs to exactly ONE project and branch, fixed at mint; everything it mints inherits that scope. Touching another project's models fails typed: `project_scope_denied` (403) — the fix is a key minted for THAT project, never `ablo push`. Manage: `npx ablo projects list|create <slug>|use <slug|default>`; `npx ablo status` shows readiness and `npx ablo whoami` strictly confirms the credential target. Wire: `GET/POST /api/v1/projects` (management authority; duplicate slug → `project_slug_taken` 409).
33
35
 
34
36
  ## Use this API
35
37
 
@@ -175,20 +177,20 @@ export const { POST } = dataSourceNext({
175
177
 
176
178
  Connect a database with `npx ablo connect` (logical replication — the one path above). The signed Data Source endpoint (code above) is the fallback when app database credentials must stay private; scaffold it with `npx ablo init --storage endpoint` — Ablo only calls the endpoint.
177
179
 
178
- ## Sandboxes
180
+ ## Public demo and development branches
179
181
 
180
182
  Public `/sandbox` is a deterministic visual demo. It should teach shared state,
181
183
  claims, stale-write rejection, receipts, and deltas, but it does not use a real
182
184
  API key. It also exposes a Claude Code / Codex handoff prompt. Prefer that shape
183
185
  when an agent is asked to "make Ablo work" in an existing app.
184
186
 
185
- Authenticated development branches are real test environments. `ablo dev`
186
- derives one from Git and mints an expiring `sk_test_*` key bound to its immutable
187
- branch id. A branch CAN host rows in Ablo's test plane, so you can try Ablo with
188
- NO database — `apiKey` only, nothing else. (In production, your own Postgres is
189
- the system of record.) Branch schemas and rows are isolated from siblings and
190
- production. There is no shared-sandbox escape hatch. Use `sk_live_*` only for
191
- production.
187
+ Authenticated development branches are real isolated environments. `ablo dev`
188
+ derives one from Git and mints an expiring `sk_*` key bound to its immutable
189
+ branch id. A child CAN host rows without your own database, so you can try Ablo
190
+ with `apiKey` only. (On the production root, your own Postgres is the system of
191
+ record.) Branch schemas and rows are isolated from siblings and production.
192
+ There is no shared-sandbox escape hatch and no different production key class:
193
+ the persisted branch binding distinguishes child from root.
192
194
 
193
195
  For coding agents, the development success path is: pick one shared model,
194
196
  declare schema, prepare an explicit branch with
@@ -198,9 +200,9 @@ one direct mutation with a typed `ablo.<model>.update(...)`, use selector
198
200
 
199
201
  ## Production
200
202
 
201
- A PLANE is what a credential acts on: `production` is the root branch and development/preview branches are children. Rows, the registered database, and the active schema artifact are all PER PLANE. A key's immutable branch binding is fixed at mint (`sk_live_` production; `sk_test_` → one child), so app code never passes an environment. A child copies its parent's active schema at creation and owns its artifact after that. A CHILD push does NOT reach production. Production gets models only when the reviewed deployment pushes to the root.
203
+ A PLANE is what a credential acts on: `production` is the root branch and development/preview branches are children. Rows, the registered database, and the active schema artifact are all PER PLANE. Every `sk_` has an immutable persisted branch binding; its spelling does not distinguish root from child, so app code never passes an environment. A child copies its parent's active schema at creation and owns its artifact after that. A CHILD push does NOT reach production. Production gets models only when the reviewed deployment pushes to the root.
202
204
 
203
- Going live is three things, each done with a `sk_live_` key: register the production database (`ablo connect apply` — the DIRECT host, never a pooler; a pooler refuses in the words of a wrong password), push the schema AHEAD of the code that needs it, and hold the right credential per runtime (server/serverless `sk_live_`; browser `pk_live_` read-only or an `authEndpoint` minting `ek_`). The live key `ablo login` stores is a RESTRICTED observe-only `rk_live_` and CANNOT push schema — a production push needs a dashboard `sk_live_` in `ABLO_API_KEY`. Gate a deploy on `npx ablo status --json` having an EMPTY `blockers` array; each blocker carries a `problem` and the one `fix`. Your agents do NOT each hold a database connection — they talk to Ablo, and Ablo holds at most 4 connections per plane (`application_name = 'ablo-direct-writer'`) however many callers write behind them, so size the database for that number and not for your agent count. Read `deployment` for the full path.
205
+ Going live is three things, each done with a root-bound `sk_` key: register the production database (`ablo connect apply` — the DIRECT host, never a pooler; a pooler refuses in the words of a wrong password), push the schema AHEAD of the code that needs it, and hold the right credential per runtime (server/serverless `sk_`; browser `pk_` read-only or an `authEndpoint` minting `ek_`). `ablo login` stores an `mk_` management credential and CANNOT read/write application data or push the production schema — a production push needs a root-bound `sk_` in `ABLO_API_KEY`. Gate a deploy on `npx ablo status --json` having an EMPTY `blockers` array; each blocker carries a `problem` and the one `fix`. Your agents do NOT each hold a database connection — they talk to Ablo, and Ablo holds at most 4 connections per plane (`application_name = 'ablo-direct-writer'`) however many callers write behind them, so size the database for that number and not for your agent count. Read `deployment` for the full path.
204
206
 
205
207
  ## Public Surface
206
208
 
@@ -227,7 +229,7 @@ Do not teach `/api`, `/agent`, `/core`, `/realtime`, or internal subpaths. (`/so
227
229
  - `npx ablo connect` connects your database via logical replication — the read path (prints the `wal_level=logical` + publication + `REPLICATION`-role SQL); `npx ablo connect register` registers it, `npx ablo connect check` validates the registered database from Ablo's own side and needs only `ABLO_API_KEY` (no database credential in your environment). `npx ablo connect apply` does the whole setup from a one-time admin connection and leaves your app holding only `ABLO_API_KEY`.
228
230
  - Key: see "Start here" — env → `.env.local` → ask the human to `npx ablo login`; never run `login` yourself, never copy keys by hand (`ablo dev` mints and wires the temporary branch key).
229
231
  - Adopt an existing DB: `npx ablo pull prisma [path]` / `npx ablo pull drizzle <module>`.
230
- - `npx ablo dev --no-watch --branch <git-or-ci-ref>` ensures an isolated branch, mints and wires its temporary key, pushes once, and exits. Plain `dev` watches forever. `npx ablo branch check <id-or-slug>` prints lifecycle, schema/parent compatibility, datasource identity, and readiness. `npx ablo push` pushes with the already selected key and does NOT choose a branch for you. A PRODUCTION push (`sk_live_` key) needs `--yes`: with no TTY it REFUSES rather than deploying unattended, and interactively it demands the destination project typed by name. Destructive steps (dropped model/field, narrowed enum, lossy cast) need `--force`; a new required field on a populated table needs `--backfill model.field=value`. `npx ablo logs --no-follow` exits instead of tailing forever. `npx ablo push`/`status`/`pull`/`check`/`generate` are one-shot.
232
+ - `npx ablo dev --no-watch --branch <git-or-ci-ref>` ensures an isolated branch, mints and wires its temporary key, pushes once, and exits. Plain `dev` watches forever. `npx ablo branch check <id-or-slug>` prints lifecycle, schema/parent compatibility, datasource identity, and readiness. `npx ablo push` pushes with the already selected key and does NOT choose a branch for you. A PRODUCTION push (`sk_` key) needs `--yes`: with no TTY it REFUSES rather than deploying unattended, and interactively it demands the destination project typed by name. Destructive steps (dropped model/field, narrowed enum, lossy cast) need `--force`; a new required field on a populated table needs `--backfill model.field=value`. `npx ablo logs --no-follow` exits instead of tailing forever. `npx ablo push`/`status`/`pull`/`check`/`generate` are one-shot.
231
233
 
232
234
  - `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.
233
235
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abloatai/ablo",
3
- "version": "0.42.0",
3
+ "version": "0.43.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.42.0",
128
- "@abloatai/transaction": "^0.42.0"
127
+ "@abloatai/humans": "^0.43.0",
128
+ "@abloatai/transaction": "^0.43.0"
129
129
  },
130
130
  "peerDependencies": {
131
131
  "ai": "^6.0.0 || ^7.0.0",