@abloatai/ablo 0.9.1 → 0.9.3
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/AGENTS.md +84 -0
- package/CHANGELOG.md +40 -0
- package/README.md +53 -27
- package/dist/BaseSyncedStore.d.ts +2 -36
- package/dist/BaseSyncedStore.js +11 -55
- package/dist/NetworkMonitor.js +4 -1
- package/dist/SyncClient.d.ts +22 -5
- package/dist/SyncClient.js +77 -0
- package/dist/SyncEngineContext.js +5 -1
- package/dist/agent/index.js +1 -1
- package/dist/api/index.d.ts +1 -1
- package/dist/auth/index.js +3 -1
- package/dist/cli.cjs +302645 -0
- package/dist/client/Ablo.d.ts +19 -52
- package/dist/client/Ablo.js +30 -106
- package/dist/client/ApiClient.d.ts +1 -113
- package/dist/client/ApiClient.js +39 -238
- package/dist/client/auth.js +32 -2
- package/dist/client/createInternalComponents.js +1 -1
- package/dist/client/createModelProxy.d.ts +9 -0
- package/dist/client/createModelProxy.js +34 -10
- package/dist/client/httpClient.d.ts +5 -6
- package/dist/client/httpClient.js +2 -3
- package/dist/client/index.d.ts +1 -1
- package/dist/client/persistence.d.ts +6 -1
- package/dist/client/persistence.js +1 -1
- package/dist/client/registerDataSource.d.ts +4 -4
- package/dist/client/registerDataSource.js +39 -31
- package/dist/client/writeOptionsSchema.d.ts +50 -0
- package/dist/client/writeOptionsSchema.js +57 -0
- package/dist/core/index.d.ts +18 -26
- package/dist/core/index.js +22 -46
- package/dist/errorCodes.d.ts +13 -0
- package/dist/errorCodes.js +19 -4
- package/dist/index.d.ts +3 -0
- package/dist/index.js +8 -1
- package/dist/interfaces/index.d.ts +14 -4
- package/dist/mutators/UndoManager.d.ts +48 -5
- package/dist/mutators/UndoManager.js +166 -1
- package/dist/react/AbloProvider.d.ts +18 -8
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.js +1 -1
- package/dist/react/useUndoScope.js +7 -0
- package/dist/schema/ddl.js +2 -1
- package/dist/schema/field.js +2 -1
- package/dist/schema/serialize.js +2 -1
- package/dist/server/commit.d.ts +4 -5
- package/dist/server/storage-mode.d.ts +7 -0
- package/dist/server/storage-mode.js +6 -0
- package/dist/source/adapters/drizzle.js +3 -2
- package/dist/source/adapters/kysely.d.ts +68 -0
- package/dist/source/adapters/kysely.js +210 -0
- package/dist/source/adapters/memory.js +2 -1
- package/dist/source/adapters/prisma.js +3 -2
- package/dist/source/index.js +2 -1
- package/dist/transactions/TransactionQueue.d.ts +6 -7
- package/dist/transactions/TransactionQueue.js +33 -9
- package/dist/types/streams.d.ts +2 -1
- package/dist/utils/duration.js +3 -2
- package/dist/wire/frames.d.ts +6 -8
- package/docs/api.md +1 -1
- package/docs/cli.md +17 -4
- package/docs/client-behavior.md +1 -1
- package/docs/data-sources.md +129 -125
- package/docs/examples/ai-sdk-tool.md +11 -5
- package/docs/examples/existing-python-backend.md +26 -4
- package/docs/examples/nextjs.md +3 -2
- package/docs/examples/scoped-agent.md +38 -11
- package/docs/guarantees.md +2 -2
- package/docs/identity.md +86 -59
- package/docs/index.md +2 -2
- package/docs/integration-guide.md +89 -61
- package/docs/mcp.md +1 -1
- package/docs/quickstart.md +84 -37
- package/docs/react.md +39 -28
- package/docs/schema-contract.md +2 -4
- package/llms-full.txt +360 -0
- package/llms.txt +30 -18
- package/package.json +23 -3
package/llms.txt
CHANGED
|
@@ -6,6 +6,14 @@ Here is the problem it solves. Two writers touch `report_stockholm` at once. The
|
|
|
6
6
|
|
|
7
7
|
Use AI SDK for the agent loop. Use Ablo when agent reads and writes must persist, coordinate with concurrent work, and leave an audit trail.
|
|
8
8
|
|
|
9
|
+
## Start here
|
|
10
|
+
|
|
11
|
+
First action when integrating into an app: run `npx ablo init --yes --framework <nextjs|vite|remix|vanilla> --storage datasource`. Agents have no TTY — `--yes` is REQUIRED or it HANGS. It scaffolds `ablo/schema.ts`, the client, the Data Source endpoint, and (for Next.js) the browser provider + session route, all on the current API. Edit the generated files rather than hand-writing from this doc.
|
|
12
|
+
|
|
13
|
+
Second: make sure a key exists. Check `ABLO_API_KEY` in the environment, then `.env.local`. If neither has one, ask the HUMAN to run `npx ablo login` once — it opens a browser and saves a `sk_test_` key locally; an agent must NOT run it. You never copy the key by hand: the next step writes it into `.env.local` for you.
|
|
14
|
+
|
|
15
|
+
Then PUSH — this is the step everything depends on. The server keeps its OWN copy of the schema. Run `npx ablo dev --no-watch`: it pushes `ablo/schema.ts` (test mode) AND writes `ABLO_API_KEY` into `.env.local` from the stored login. 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 (`npx ablo push` also works once the key is wired; bare `npx ablo dev` watches forever — don't, you have no TTY).
|
|
16
|
+
|
|
9
17
|
## Use this API
|
|
10
18
|
|
|
11
19
|
```ts
|
|
@@ -23,15 +31,16 @@ const schema = defineSchema({
|
|
|
23
31
|
|
|
24
32
|
const ablo = Ablo({ schema, apiKey: process.env.ABLO_API_KEY });
|
|
25
33
|
|
|
26
|
-
const report = await ablo.weatherReports.retrieve('report_stockholm');
|
|
34
|
+
const report = await ablo.weatherReports.retrieve({ id: 'report_stockholm' });
|
|
27
35
|
if (!report) throw new Error('Row not found');
|
|
28
36
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
)
|
|
37
|
+
// Claim the row (waits if someone else holds it), read the fresh copy off
|
|
38
|
+
// `claim.data`, write, then auto-release at the end of this scope (`await using`).
|
|
39
|
+
await using claim = await ablo.weatherReports.claim({ id: 'report_stockholm' });
|
|
40
|
+
const updated = await ablo.weatherReports.update({
|
|
41
|
+
id: claim.data.id,
|
|
42
|
+
data: { status: 'ready', forecast: await getForecast(claim.data) },
|
|
43
|
+
wait: 'confirmed',
|
|
35
44
|
});
|
|
36
45
|
```
|
|
37
46
|
|
|
@@ -43,10 +52,10 @@ hosted schema push, and schema-version gating. Do not invent a parallel
|
|
|
43
52
|
string-keyed write path for rows that belong to a schema model.
|
|
44
53
|
|
|
45
54
|
For full integrations, use `integration-guide` as the canonical doc. It covers
|
|
46
|
-
the same model API across
|
|
55
|
+
the same model API across your own Data Source-backed app databases,
|
|
47
56
|
React selectors, multiplayer, and future agent workers.
|
|
48
57
|
|
|
49
|
-
Reads come in two flavors, and you pick by whether you can wait. `retrieve(id)`
|
|
58
|
+
Reads come in two flavors, and you pick by whether you can wait. `retrieve({ id })`
|
|
50
59
|
(one row) and `list({ where })` (many) are async — they hit the server and return
|
|
51
60
|
a Promise, so await them. `get(id)`, `getAll({ where })`, and `getCount({ where })`
|
|
52
61
|
are synchronous — they read the local graph and are reactive in render, so no
|
|
@@ -68,7 +77,7 @@ first integration path.
|
|
|
68
77
|
Multiplayer is not a separate mode. When human UI, server actions, and agents use
|
|
69
78
|
the same schema client and write through `ablo.<model>`, Ablo coordinates the
|
|
70
79
|
shared model stream: confirmed deltas fan out to subscribers, active claims are
|
|
71
|
-
visible through `claim.state(id)`, and stale writes can be rejected with `readAt`.
|
|
80
|
+
visible through `claim.state({ id })`, and stale writes can be rejected with `readAt`.
|
|
72
81
|
|
|
73
82
|
If an app writes directly to its own database outside Ablo, that write bypasses
|
|
74
83
|
coordination until the app reports it through Data Source events.
|
|
@@ -76,7 +85,7 @@ coordination until the app reports it through Data Source events.
|
|
|
76
85
|
## Nouns
|
|
77
86
|
|
|
78
87
|
- `Model client` is the typed `ablo.<model>` object generated from schema.
|
|
79
|
-
- `Claim` holds a model row while slow work runs; `claim.state(id)` observes it.
|
|
88
|
+
- `Claim` holds a model row while slow work runs; `claim.state({ id })` observes it.
|
|
80
89
|
- `Commit` is the durable protocol write behind `ablo.<model>.update(...)`.
|
|
81
90
|
- `Receipt` confirms the commit.
|
|
82
91
|
|
|
@@ -109,23 +118,25 @@ A schema is model fields and relations. Advanced schema helpers such as `mutable
|
|
|
109
118
|
|
|
110
119
|
Do not add `databaseURL` to `Ablo(...)`. Application and agent code use `ABLO_API_KEY`.
|
|
111
120
|
|
|
112
|
-
Every schema model
|
|
121
|
+
Every schema model is backed by a database, and the default is YOUR OWN. Keep your rows in your Postgres and expose a Data Source endpoint that hands Ablo an ORM `adapter` (Drizzle is the default; Prisma and Kysely are also supported) — it owns the transaction, exactly-once idempotency, and outbox in ONE pass (no hand-written `commit`/`events`). Your `DATABASE_URL` lives in your app, never in `Ablo(...)`; run `npx ablo migrate` to provision the synced-model tables in your DB.
|
|
113
122
|
|
|
114
123
|
```ts
|
|
115
124
|
// app/api/ablo/source/route.ts
|
|
116
125
|
import { dataSourceNext } from '@abloatai/ablo/source/next';
|
|
117
|
-
import {
|
|
126
|
+
import { drizzleDataSource } from '@abloatai/ablo/source/drizzle';
|
|
118
127
|
import { schema } from '@/ablo/schema';
|
|
119
|
-
import {
|
|
128
|
+
import { db } from '@/db';
|
|
129
|
+
|
|
130
|
+
export const runtime = 'nodejs'; // the route touches your database
|
|
120
131
|
|
|
121
132
|
export const { POST } = dataSourceNext({
|
|
122
133
|
schema,
|
|
123
134
|
apiKey: process.env.ABLO_API_KEY!,
|
|
124
|
-
adapter:
|
|
135
|
+
adapter: drizzleDataSource(db, schema), // or prismaDataSource(prisma, schema) / kyselyDataSource(db, schema)
|
|
125
136
|
});
|
|
126
137
|
```
|
|
127
138
|
|
|
128
|
-
`npx ablo init`
|
|
139
|
+
`npx ablo init` defaults to this — it scaffolds the endpoint and the `DATABASE_URL` for you (see CLI below). Your app database credentials stay private — Ablo only calls the endpoint.
|
|
129
140
|
|
|
130
141
|
## Sandboxes
|
|
131
142
|
|
|
@@ -156,6 +167,7 @@ Import from these public paths only:
|
|
|
156
167
|
- `@abloatai/ablo/source` — `dataSource`, the `DataSourceAdapter` spine, `prismaDataSource`. For a customer-canonical Data Source endpoint.
|
|
157
168
|
- `@abloatai/ablo/source/next` — `dataSourceNext` (Next.js App Router `{ POST }`).
|
|
158
169
|
- `@abloatai/ablo/source/drizzle` — `drizzleDataSource`.
|
|
170
|
+
- `@abloatai/ablo/source/kysely` — `kyselyDataSource`.
|
|
159
171
|
- `@abloatai/ablo/source/conformance` — `runDataSourceTests` to prove a custom adapter/handler.
|
|
160
172
|
|
|
161
173
|
Do not teach `/api`, `/agent`, `/ai-sdk`, `/core`, `/realtime`, or internal subpaths. (`/source` IS public — it's the Data Source endpoint surface above.)
|
|
@@ -165,8 +177,8 @@ Do not teach `/api`, `/agent`, `/ai-sdk`, `/core`, `/realtime`, or internal subp
|
|
|
165
177
|
`ablo init` and other prompts need a TTY; an agent/CI run has none and will HANG. Always:
|
|
166
178
|
|
|
167
179
|
- `npx ablo init --yes` (flags: `--framework`, `--auth`, `--storage`, `--no-agent`, `--no-pull`, `--no-install`, `--no-login`). Generates `ablo/schema.ts` + the `ablo/data-source.ts` endpoint above.
|
|
168
|
-
-
|
|
180
|
+
- 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` writes `.env.local`).
|
|
169
181
|
- Adopt an existing DB: `npx ablo pull prisma [path]` / `npx ablo pull drizzle <module>`.
|
|
170
|
-
- `npx ablo dev --no-watch` (default watches forever); `npx ablo logs --no-follow` (default tails forever); `npx ablo mode test|live` (always pass the arg). `npx ablo push`/`status`/`pull`/`check`/`generate` are one-shot.
|
|
182
|
+
- `npx ablo dev --no-watch` pushes the schema (test mode) AND writes `ABLO_API_KEY` to `.env.local` (default watches forever); `npx ablo logs --no-follow` (default tails forever); `npx ablo mode test|live` (always pass the arg). `npx ablo push`/`status`/`pull`/`check`/`generate` are one-shot.
|
|
171
183
|
|
|
172
184
|
Canonical docs to read before integrating: `quickstart`, `schema-contract`, `integration-guide`, `guarantees`, `client-behavior`, `data-sources`, `examples/existing-python-backend`, `api`, `examples/ai-sdk-tool`, and `examples/server-agent`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abloatai/ablo",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.3",
|
|
4
4
|
"description": "State control API for AI agents and collaborative apps.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
},
|
|
10
10
|
"main": "./dist/index.js",
|
|
11
11
|
"types": "./dist/index.d.ts",
|
|
12
|
+
"bin": {
|
|
13
|
+
"ablo": "./dist/cli.cjs"
|
|
14
|
+
},
|
|
12
15
|
"exports": {
|
|
13
16
|
".": {
|
|
14
17
|
"types": "./dist/index.d.ts",
|
|
@@ -65,6 +68,11 @@
|
|
|
65
68
|
"import": "./dist/source/adapters/drizzle.js",
|
|
66
69
|
"default": "./dist/source/adapters/drizzle.js"
|
|
67
70
|
},
|
|
71
|
+
"./source/kysely": {
|
|
72
|
+
"types": "./dist/source/adapters/kysely.d.ts",
|
|
73
|
+
"import": "./dist/source/adapters/kysely.js",
|
|
74
|
+
"default": "./dist/source/adapters/kysely.js"
|
|
75
|
+
},
|
|
68
76
|
"./source/next": {
|
|
69
77
|
"types": "./dist/source/next.d.ts",
|
|
70
78
|
"import": "./dist/source/next.js",
|
|
@@ -106,6 +114,7 @@
|
|
|
106
114
|
"examples",
|
|
107
115
|
"AGENTS.md",
|
|
108
116
|
"llms.txt",
|
|
117
|
+
"llms-full.txt",
|
|
109
118
|
"LICENSE",
|
|
110
119
|
"NOTICE",
|
|
111
120
|
"README.md",
|
|
@@ -113,13 +122,17 @@
|
|
|
113
122
|
],
|
|
114
123
|
"scripts": {
|
|
115
124
|
"clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
116
|
-
"build": "npm run clean && tsc -p tsconfig.build.json",
|
|
125
|
+
"build": "npm run clean && tsc -p tsconfig.build.json && npm run build:cli",
|
|
126
|
+
"build:cli": "tsup --config tsup.cli.config.ts",
|
|
127
|
+
"typecheck:cli": "tsc -p tsconfig.cli.json",
|
|
117
128
|
"pack:check": "npm_config_cache=${TMPDIR:-/tmp}/ablo-npm-cache npm pack --dry-run",
|
|
118
129
|
"lint:imports": "node scripts/check-js-extensions.mjs",
|
|
119
130
|
"generate:errors": "tsx scripts/generate-error-docs.mts",
|
|
120
131
|
"lint:errors": "tsx scripts/check-error-docs.mts",
|
|
121
132
|
"lint:pkg": "publint",
|
|
122
133
|
"prepublishOnly": "npm run build && npm run lint:pkg",
|
|
134
|
+
"check:dist": "node scripts/check-dist-fresh.mjs",
|
|
135
|
+
"pretest": "node scripts/check-dist-fresh.mjs",
|
|
123
136
|
"test": "jest",
|
|
124
137
|
"test:unit": "jest --testPathPattern=__tests__/unit",
|
|
125
138
|
"test:integration": "jest --testPathPattern=__tests__/integration",
|
|
@@ -159,7 +172,7 @@
|
|
|
159
172
|
},
|
|
160
173
|
"peerDependencies": {
|
|
161
174
|
"react": "^19.0.0",
|
|
162
|
-
"drizzle-orm": ">=0.
|
|
175
|
+
"drizzle-orm": ">=0.44.0"
|
|
163
176
|
},
|
|
164
177
|
"peerDependenciesMeta": {
|
|
165
178
|
"react": {
|
|
@@ -177,6 +190,8 @@
|
|
|
177
190
|
},
|
|
178
191
|
"devDependencies": {
|
|
179
192
|
"@ai-sdk/provider": "^3.0.0",
|
|
193
|
+
"@clack/prompts": "^0.11.0",
|
|
194
|
+
"@prisma/client": "^7.3.0",
|
|
180
195
|
"@types/jest": "^29.5.0",
|
|
181
196
|
"@types/node": "^22.0.0",
|
|
182
197
|
"@types/react": "^19.0.0",
|
|
@@ -189,10 +204,15 @@
|
|
|
189
204
|
"fast-check": "^3.0.0",
|
|
190
205
|
"jest": "^29.7.0",
|
|
191
206
|
"jest-environment-jsdom": "^29.7.0",
|
|
207
|
+
"jiti": "^2.7.0",
|
|
192
208
|
"mobx": "^6.13.7",
|
|
209
|
+
"picocolors": "^1.1.0",
|
|
210
|
+
"postgres": "^3.4.0",
|
|
193
211
|
"react": "^19.0.0",
|
|
194
212
|
"react-dom": "^19.0.0",
|
|
195
213
|
"ts-jest": "^29.4.0",
|
|
214
|
+
"ts-morph": "^26.0.0",
|
|
215
|
+
"tsup": "^8.0.0",
|
|
196
216
|
"typescript": "^5.8.3",
|
|
197
217
|
"publint": "^0.3.21"
|
|
198
218
|
}
|