@abloatai/ablo 0.3.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 +208 -0
- package/LICENSE +201 -0
- package/NOTICE +12 -0
- package/README.md +230 -0
- package/dist/BaseSyncedStore.d.ts +709 -0
- package/dist/BaseSyncedStore.js +1843 -0
- package/dist/Database.d.ts +344 -0
- package/dist/Database.js +1259 -0
- package/dist/LazyReferenceCollection.d.ts +181 -0
- package/dist/LazyReferenceCollection.js +460 -0
- package/dist/Model.d.ts +339 -0
- package/dist/Model.js +715 -0
- package/dist/ModelRegistry.d.ts +200 -0
- package/dist/ModelRegistry.js +535 -0
- package/dist/NetworkMonitor.d.ts +27 -0
- package/dist/NetworkMonitor.js +73 -0
- package/dist/ObjectPool.d.ts +202 -0
- package/dist/ObjectPool.js +1106 -0
- package/dist/SyncClient.d.ts +489 -0
- package/dist/SyncClient.js +1555 -0
- package/dist/SyncEngineContext.d.ts +46 -0
- package/dist/SyncEngineContext.js +74 -0
- package/dist/adapters/alwaysOnline.d.ts +16 -0
- package/dist/adapters/alwaysOnline.js +19 -0
- package/dist/adapters/inMemoryStorage.d.ts +30 -0
- package/dist/adapters/inMemoryStorage.js +94 -0
- package/dist/agent/Agent.d.ts +358 -0
- package/dist/agent/Agent.js +500 -0
- package/dist/agent/index.d.ts +115 -0
- package/dist/agent/index.js +128 -0
- package/dist/agent/session.d.ts +90 -0
- package/dist/agent/session.js +156 -0
- package/dist/agent/types.d.ts +73 -0
- package/dist/agent/types.js +10 -0
- package/dist/ai-sdk/coordination-context.d.ts +51 -0
- package/dist/ai-sdk/coordination-context.js +107 -0
- package/dist/ai-sdk/index.d.ts +68 -0
- package/dist/ai-sdk/index.js +68 -0
- package/dist/ai-sdk/intent-broadcast.d.ts +77 -0
- package/dist/ai-sdk/intent-broadcast.js +72 -0
- package/dist/ai-sdk/wrap.d.ts +67 -0
- package/dist/ai-sdk/wrap.js +45 -0
- package/dist/api/index.d.ts +10 -0
- package/dist/api/index.js +9 -0
- package/dist/auth/index.d.ts +137 -0
- package/dist/auth/index.js +246 -0
- package/dist/client/Ablo.d.ts +835 -0
- package/dist/client/Ablo.js +1440 -0
- package/dist/client/ApiClient.d.ts +200 -0
- package/dist/client/ApiClient.js +659 -0
- package/dist/client/auth.d.ts +79 -0
- package/dist/client/auth.js +81 -0
- package/dist/client/createInternalComponents.d.ts +44 -0
- package/dist/client/createInternalComponents.js +88 -0
- package/dist/client/createModelProxy.d.ts +152 -0
- package/dist/client/createModelProxy.js +199 -0
- package/dist/client/identity.d.ts +63 -0
- package/dist/client/identity.js +156 -0
- package/dist/client/index.d.ts +36 -0
- package/dist/client/index.js +33 -0
- package/dist/client/persistence.d.ts +7 -0
- package/dist/client/persistence.js +11 -0
- package/dist/client/validateAbloOptions.d.ts +42 -0
- package/dist/client/validateAbloOptions.js +43 -0
- package/dist/config/index.d.ts +10 -0
- package/dist/config/index.js +12 -0
- package/dist/context.d.ts +27 -0
- package/dist/context.js +58 -0
- package/dist/core/DatabaseManager.d.ts +108 -0
- package/dist/core/DatabaseManager.js +361 -0
- package/dist/core/QueryProcessor.d.ts +77 -0
- package/dist/core/QueryProcessor.js +262 -0
- package/dist/core/QueryView.d.ts +64 -0
- package/dist/core/QueryView.js +219 -0
- package/dist/core/StoreManager.d.ts +131 -0
- package/dist/core/StoreManager.js +334 -0
- package/dist/core/ViewRegistry.d.ts +20 -0
- package/dist/core/ViewRegistry.js +55 -0
- package/dist/core/index.d.ts +34 -0
- package/dist/core/index.js +59 -0
- package/dist/core/openIDBWithTimeout.d.ts +27 -0
- package/dist/core/openIDBWithTimeout.js +63 -0
- package/dist/core/query-utils.d.ts +37 -0
- package/dist/core/query-utils.js +60 -0
- package/dist/errors.d.ts +235 -0
- package/dist/errors.js +243 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +82 -0
- package/dist/interfaces/headless.d.ts +95 -0
- package/dist/interfaces/headless.js +41 -0
- package/dist/interfaces/index.d.ts +321 -0
- package/dist/interfaces/index.js +8 -0
- package/dist/mutators/RecordingTransaction.d.ts +36 -0
- package/dist/mutators/RecordingTransaction.js +216 -0
- package/dist/mutators/Transaction.d.ts +48 -0
- package/dist/mutators/Transaction.js +64 -0
- package/dist/mutators/UndoManager.d.ts +114 -0
- package/dist/mutators/UndoManager.js +143 -0
- package/dist/mutators/defineMutators.d.ts +55 -0
- package/dist/mutators/defineMutators.js +28 -0
- package/dist/policy/index.d.ts +19 -0
- package/dist/policy/index.js +18 -0
- package/dist/policy/types.d.ts +74 -0
- package/dist/policy/types.js +17 -0
- package/dist/principal.d.ts +44 -0
- package/dist/principal.js +49 -0
- package/dist/query/client.d.ts +43 -0
- package/dist/query/client.js +84 -0
- package/dist/query/index.d.ts +6 -0
- package/dist/query/index.js +5 -0
- package/dist/query/types.d.ts +143 -0
- package/dist/query/types.js +36 -0
- package/dist/react/AbloProvider.d.ts +205 -0
- package/dist/react/AbloProvider.js +398 -0
- package/dist/react/ClientSideSuspense.d.ts +36 -0
- package/dist/react/ClientSideSuspense.js +17 -0
- package/dist/react/DefaultFallback.d.ts +24 -0
- package/dist/react/DefaultFallback.js +43 -0
- package/dist/react/SyncGroupProvider.d.ts +19 -0
- package/dist/react/SyncGroupProvider.js +44 -0
- package/dist/react/context.d.ts +161 -0
- package/dist/react/context.js +35 -0
- package/dist/react/index.d.ts +64 -0
- package/dist/react/index.js +73 -0
- package/dist/react/internalContext.d.ts +35 -0
- package/dist/react/internalContext.js +3 -0
- package/dist/react/useAblo.d.ts +72 -0
- package/dist/react/useAblo.js +63 -0
- package/dist/react/useCurrentUserId.d.ts +21 -0
- package/dist/react/useCurrentUserId.js +33 -0
- package/dist/react/useErrorListener.d.ts +20 -0
- package/dist/react/useErrorListener.js +39 -0
- package/dist/react/useIntent.d.ts +29 -0
- package/dist/react/useIntent.js +42 -0
- package/dist/react/useMutate.d.ts +83 -0
- package/dist/react/useMutate.js +122 -0
- package/dist/react/useMutationFailureListener.d.ts +26 -0
- package/dist/react/useMutationFailureListener.js +38 -0
- package/dist/react/useMutators.d.ts +56 -0
- package/dist/react/useMutators.js +66 -0
- package/dist/react/usePresence.d.ts +32 -0
- package/dist/react/usePresence.js +41 -0
- package/dist/react/useQuery.d.ts +123 -0
- package/dist/react/useQuery.js +145 -0
- package/dist/react/useReactive.d.ts +35 -0
- package/dist/react/useReactive.js +111 -0
- package/dist/react/useReader.d.ts +69 -0
- package/dist/react/useReader.js +73 -0
- package/dist/react/useSyncStatus.d.ts +61 -0
- package/dist/react/useSyncStatus.js +76 -0
- package/dist/react/useUndoScope.d.ts +36 -0
- package/dist/react/useUndoScope.js +73 -0
- package/dist/realtime/index.d.ts +10 -0
- package/dist/realtime/index.js +9 -0
- package/dist/schema/field.d.ts +134 -0
- package/dist/schema/field.js +264 -0
- package/dist/schema/index.d.ts +29 -0
- package/dist/schema/index.js +38 -0
- package/dist/schema/model.d.ts +326 -0
- package/dist/schema/model.js +89 -0
- package/dist/schema/queries.d.ts +203 -0
- package/dist/schema/queries.js +145 -0
- package/dist/schema/relation.d.ts +172 -0
- package/dist/schema/relation.js +104 -0
- package/dist/schema/schema.d.ts +259 -0
- package/dist/schema/schema.js +188 -0
- package/dist/schema/sugar.d.ts +129 -0
- package/dist/schema/sugar.js +94 -0
- package/dist/source/index.d.ts +423 -0
- package/dist/source/index.js +320 -0
- package/dist/source/pushQueue.d.ts +112 -0
- package/dist/source/pushQueue.js +249 -0
- package/dist/stores/ObjectStore.d.ts +103 -0
- package/dist/stores/ObjectStore.js +371 -0
- package/dist/stores/ObjectStoreContract.d.ts +39 -0
- package/dist/stores/ObjectStoreContract.js +1 -0
- package/dist/stores/SyncActionStore.d.ts +101 -0
- package/dist/stores/SyncActionStore.js +481 -0
- package/dist/sync/BootstrapHelper.d.ts +127 -0
- package/dist/sync/BootstrapHelper.js +434 -0
- package/dist/sync/ConnectionManager.d.ts +136 -0
- package/dist/sync/ConnectionManager.js +465 -0
- package/dist/sync/HydrationCoordinator.d.ts +137 -0
- package/dist/sync/HydrationCoordinator.js +468 -0
- package/dist/sync/NetworkProbe.d.ts +43 -0
- package/dist/sync/NetworkProbe.js +113 -0
- package/dist/sync/OfflineFlush.d.ts +9 -0
- package/dist/sync/OfflineFlush.js +22 -0
- package/dist/sync/OfflineTransactionStore.d.ts +37 -0
- package/dist/sync/OfflineTransactionStore.js +263 -0
- package/dist/sync/SyncWebSocket.d.ts +663 -0
- package/dist/sync/SyncWebSocket.js +1336 -0
- package/dist/sync/createIntentStream.d.ts +33 -0
- package/dist/sync/createIntentStream.js +243 -0
- package/dist/sync/createPresenceStream.d.ts +46 -0
- package/dist/sync/createPresenceStream.js +192 -0
- package/dist/sync/createSnapshot.d.ts +33 -0
- package/dist/sync/createSnapshot.js +124 -0
- package/dist/sync/participants.d.ts +114 -0
- package/dist/sync/participants.js +336 -0
- package/dist/sync/schemas.d.ts +79 -0
- package/dist/sync/schemas.js +78 -0
- package/dist/testing/fixtures/bootstrap.d.ts +45 -0
- package/dist/testing/fixtures/bootstrap.js +53 -0
- package/dist/testing/fixtures/deltas.d.ts +86 -0
- package/dist/testing/fixtures/deltas.js +139 -0
- package/dist/testing/fixtures/models.d.ts +82 -0
- package/dist/testing/fixtures/models.js +270 -0
- package/dist/testing/helpers/react-wrapper.d.ts +66 -0
- package/dist/testing/helpers/react-wrapper.js +64 -0
- package/dist/testing/helpers/sync-engine-harness.d.ts +55 -0
- package/dist/testing/helpers/sync-engine-harness.js +70 -0
- package/dist/testing/helpers/wait.d.ts +25 -0
- package/dist/testing/helpers/wait.js +44 -0
- package/dist/testing/index.d.ts +21 -0
- package/dist/testing/index.js +32 -0
- package/dist/testing/mocks/MockMutationExecutor.d.ts +65 -0
- package/dist/testing/mocks/MockMutationExecutor.js +139 -0
- package/dist/testing/mocks/MockNetworkMonitor.d.ts +20 -0
- package/dist/testing/mocks/MockNetworkMonitor.js +46 -0
- package/dist/testing/mocks/MockSyncContext.d.ts +64 -0
- package/dist/testing/mocks/MockSyncContext.js +100 -0
- package/dist/testing/mocks/MockSyncStore.d.ts +88 -0
- package/dist/testing/mocks/MockSyncStore.js +171 -0
- package/dist/testing/mocks/MockWebSocket.d.ts +66 -0
- package/dist/testing/mocks/MockWebSocket.js +117 -0
- package/dist/transactions/OptimisticEchoTracker.d.ts +82 -0
- package/dist/transactions/OptimisticEchoTracker.js +104 -0
- package/dist/transactions/TransactionQueue.d.ts +499 -0
- package/dist/transactions/TransactionQueue.js +1895 -0
- package/dist/transactions/index.d.ts +16 -0
- package/dist/transactions/index.js +7 -0
- package/dist/transactions/mutation-error-handler.d.ts +5 -0
- package/dist/transactions/mutation-error-handler.js +39 -0
- package/dist/types/global.d.ts +107 -0
- package/dist/types/global.js +38 -0
- package/dist/types/index.d.ts +241 -0
- package/dist/types/index.js +70 -0
- package/dist/types/streams.d.ts +495 -0
- package/dist/types/streams.js +11 -0
- package/dist/utils/asyncIterator.d.ts +41 -0
- package/dist/utils/asyncIterator.js +142 -0
- package/dist/utils/duration.d.ts +28 -0
- package/dist/utils/duration.js +47 -0
- package/dist/utils/mobx-setup.d.ts +42 -0
- package/dist/utils/mobx-setup.js +381 -0
- package/docs/api-keys.md +24 -0
- package/docs/api.md +230 -0
- package/docs/audit.md +81 -0
- package/docs/capabilities.md +163 -0
- package/docs/client-behavior.md +202 -0
- package/docs/data-sources.md +214 -0
- package/docs/examples/agent-human.md +84 -0
- package/docs/examples/ai-sdk-tool.md +92 -0
- package/docs/examples/existing-python-backend.md +249 -0
- package/docs/examples/nextjs.md +88 -0
- package/docs/examples/server-agent.md +86 -0
- package/docs/guarantees.md +148 -0
- package/docs/index.md +97 -0
- package/docs/integration-guide.md +493 -0
- package/docs/interaction-model.md +140 -0
- package/docs/mcp/claude-code.md +43 -0
- package/docs/mcp/cursor.md +53 -0
- package/docs/mcp/windsurf.md +46 -0
- package/docs/mcp.md +59 -0
- package/docs/quickstart.md +152 -0
- package/docs/react.md +115 -0
- package/docs/roadmap.md +45 -0
- package/examples/README.md +54 -0
- package/examples/data-source/README.md +102 -0
- package/examples/data-source/ablo-driver.ts +89 -0
- package/examples/data-source/customer-server.ts +208 -0
- package/examples/data-source/run.ts +101 -0
- package/examples/data-source/schema.ts +25 -0
- package/examples/quickstart.ts +54 -0
- package/examples/tsconfig.json +16 -0
- package/llms.txt +143 -0
- package/package.json +147 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Next.js Example
|
|
2
|
+
|
|
3
|
+
A production-shaped Next.js + Ablo Sync app. App Router, Server Actions, React
|
|
4
|
+
Server Components, and live client subscriptions.
|
|
5
|
+
|
|
6
|
+
## Structure
|
|
7
|
+
|
|
8
|
+
```txt
|
|
9
|
+
app/
|
|
10
|
+
tasks/
|
|
11
|
+
[id]/
|
|
12
|
+
page.tsx # RSC: retrieve + render
|
|
13
|
+
actions.ts # Server Action: schema update with stale-state check
|
|
14
|
+
TaskEditor.tsx # Client: live updates
|
|
15
|
+
lib/
|
|
16
|
+
ablo.ts # Schema-backed Ablo client for server actions
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## RSC Initial Render
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
// app/tasks/[id]/page.tsx
|
|
23
|
+
import { ablo } from '@/lib/ablo';
|
|
24
|
+
|
|
25
|
+
export default async function TaskPage({
|
|
26
|
+
params,
|
|
27
|
+
}: { params: { id: string } }) {
|
|
28
|
+
await ablo.ready();
|
|
29
|
+
const [task] = await ablo.tasks.load({ where: { id: params.id } });
|
|
30
|
+
if (!task) return null;
|
|
31
|
+
|
|
32
|
+
return <TaskEditor task={task} />;
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Server Action Commit
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
// app/tasks/[id]/actions.ts
|
|
40
|
+
'use server';
|
|
41
|
+
|
|
42
|
+
import { ablo } from '@/lib/ablo';
|
|
43
|
+
|
|
44
|
+
export async function markDone(id: string) {
|
|
45
|
+
const busy = ablo.intents.list({ resource: 'tasks', id });
|
|
46
|
+
if (busy.length > 0) return { status: 'busy', intents: busy };
|
|
47
|
+
|
|
48
|
+
const snap = ablo.snapshot({ tasks: id });
|
|
49
|
+
const task = await ablo.tasks.update(
|
|
50
|
+
id,
|
|
51
|
+
{ status: 'done' },
|
|
52
|
+
{ readAt: snap.stamp, onStale: 'reject', wait: 'confirmed' },
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
return { status: 'done', task };
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
If another participant commits between the read and the write, the commit
|
|
60
|
+
rejects. The action can re-fetch and ask the user to retry.
|
|
61
|
+
|
|
62
|
+
## Live Client
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
'use client';
|
|
66
|
+
|
|
67
|
+
import { useAblo } from '@ablo/sync-engine/react';
|
|
68
|
+
|
|
69
|
+
export function TaskEditor({ task: serverTask }: Props) {
|
|
70
|
+
const data = useAblo((ablo) => ablo.tasks.retrieve(serverTask.id)) ?? serverTask;
|
|
71
|
+
const intents = useAblo((ablo) =>
|
|
72
|
+
ablo.intents.list({ resource: 'tasks', id: serverTask.id }),
|
|
73
|
+
) ?? [];
|
|
74
|
+
const busy = intents.length > 0;
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<button disabled={busy || data.status === 'done'}>
|
|
78
|
+
{busy ? 'Someone is editing' : 'Mark done'}
|
|
79
|
+
</button>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## More
|
|
85
|
+
|
|
86
|
+
- [Next.js landing](/nextjs) — the product overview.
|
|
87
|
+
- [React reference](/docs/react) — every option on `useAblo`.
|
|
88
|
+
- [API reference](/docs/api) — every option on the write path.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Server Agent
|
|
2
|
+
|
|
3
|
+
Most server agents should import the app schema and use the same model methods
|
|
4
|
+
as the product UI.
|
|
5
|
+
|
|
6
|
+
```ts
|
|
7
|
+
import Ablo from '@ablo/sync-engine';
|
|
8
|
+
import { defineSchema, model, z } from '@ablo/sync-engine/schema';
|
|
9
|
+
|
|
10
|
+
const schema = defineSchema({
|
|
11
|
+
tasks: model({
|
|
12
|
+
title: z.string(),
|
|
13
|
+
status: z.enum(['todo', 'doing', 'done']),
|
|
14
|
+
summary: z.string().optional(),
|
|
15
|
+
}),
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const ablo = Ablo({
|
|
19
|
+
schema,
|
|
20
|
+
apiKey: process.env.ABLO_API_KEY,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export async function completeTask(taskId: string) {
|
|
24
|
+
await ablo.ready();
|
|
25
|
+
|
|
26
|
+
const [task] = await ablo.tasks.load({ where: { id: taskId } });
|
|
27
|
+
if (!task) return { status: 'not_found' };
|
|
28
|
+
|
|
29
|
+
const busy = ablo.intents.list({ resource: 'tasks', id: taskId });
|
|
30
|
+
if (busy.length > 0) {
|
|
31
|
+
return { status: 'busy', intents: busy };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const snap = ablo.snapshot({ tasks: taskId });
|
|
35
|
+
const updated = await ablo.tasks.update(
|
|
36
|
+
taskId,
|
|
37
|
+
{ status: 'done' },
|
|
38
|
+
{ readAt: snap.stamp, onStale: 'reject', wait: 'confirmed' },
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
return { status: 'done', task: updated };
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Advanced Schema-Less Run
|
|
46
|
+
|
|
47
|
+
Use `agent.run(...)` when the worker intentionally cannot import the app schema.
|
|
48
|
+
It creates the run envelope and returns `done`, `failed`, or `cancelled`.
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
const api = Ablo({ apiKey: process.env.ABLO_API_KEY });
|
|
52
|
+
|
|
53
|
+
const result = await api.agent('task-writer', {
|
|
54
|
+
can: ['tasks.retrieve', 'tasks.update'],
|
|
55
|
+
syncGroups: ['workspace:acme'],
|
|
56
|
+
}).run(
|
|
57
|
+
{
|
|
58
|
+
prompt: 'Mark task_123 done.',
|
|
59
|
+
surface: 'agent_worker',
|
|
60
|
+
},
|
|
61
|
+
async ({ resource }) => {
|
|
62
|
+
const tasks = resource<{ title: string; status: string }>('tasks');
|
|
63
|
+
|
|
64
|
+
const { data, stamp, intents } = await tasks.retrieve('task_123', {
|
|
65
|
+
ifBusy: 'return',
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
if (intents.length > 0) {
|
|
69
|
+
return { skipped: true, reason: 'busy' };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return tasks.update(
|
|
73
|
+
'task_123',
|
|
74
|
+
{ status: 'done' },
|
|
75
|
+
{ readAt: stamp, onStale: 'reject', wait: 'confirmed' },
|
|
76
|
+
);
|
|
77
|
+
},
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
if (result.status === 'failed') throw result.error;
|
|
81
|
+
if (result.status === 'cancelled') return;
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Use the schema-backed version first. The schema-less version is for generic
|
|
85
|
+
agent infrastructure, MCP routes, and platform code.
|
|
86
|
+
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# Guarantees
|
|
2
|
+
|
|
3
|
+
This page is the short contract for what Ablo Sync guarantees at the state
|
|
4
|
+
boundary.
|
|
5
|
+
|
|
6
|
+
## Confirmed Writes
|
|
7
|
+
|
|
8
|
+
`wait: 'confirmed'` resolves only after the server accepts the write and returns
|
|
9
|
+
the authoritative sync cursor.
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
const updated = await ablo.tasks.update(
|
|
13
|
+
'task_123',
|
|
14
|
+
{ status: 'done' },
|
|
15
|
+
{ wait: 'confirmed' },
|
|
16
|
+
);
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
If the call resolves, the write was accepted by the server. If it rejects, the
|
|
20
|
+
error explains whether the write was rejected for auth, validation, stale state,
|
|
21
|
+
active intent conflict, idempotency, rate limit, or transport failure.
|
|
22
|
+
|
|
23
|
+
Schema model writes return the updated model row. Advanced resource writes and
|
|
24
|
+
`commits.create(...)` return a receipt with the commit status and sync cursor.
|
|
25
|
+
|
|
26
|
+
## Optimistic Local State
|
|
27
|
+
|
|
28
|
+
Schema model writes update local state optimistically. This keeps UI and agent
|
|
29
|
+
tools responsive while the commit is sent to the server.
|
|
30
|
+
|
|
31
|
+
- With `wait: 'queued'` or omitted, the promise resolves after the local mutation
|
|
32
|
+
is queued.
|
|
33
|
+
- With `wait: 'confirmed'`, the promise waits for server confirmation.
|
|
34
|
+
- If the server rejects the write, the SDK rolls back the optimistic change and
|
|
35
|
+
raises a typed error.
|
|
36
|
+
|
|
37
|
+
The server remains the source of truth.
|
|
38
|
+
|
|
39
|
+
## Stale-Write Protection
|
|
40
|
+
|
|
41
|
+
Use `snapshot(...)` and `readAt` when a write depends on state the agent already
|
|
42
|
+
read:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
const snap = ablo.snapshot({ tasks: 'task_123' });
|
|
46
|
+
|
|
47
|
+
await ablo.tasks.update(
|
|
48
|
+
'task_123',
|
|
49
|
+
{ status: 'done' },
|
|
50
|
+
{ readAt: snap.stamp, onStale: 'reject', wait: 'confirmed' },
|
|
51
|
+
);
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`onStale: 'reject'` prevents lost updates. If the target changed after the
|
|
55
|
+
snapshot, the server rejects the write instead of applying stale reasoning.
|
|
56
|
+
|
|
57
|
+
Advanced policies exist for controlled product flows:
|
|
58
|
+
|
|
59
|
+
- `reject` fails the write when state moved.
|
|
60
|
+
- `force` applies the write without stale protection.
|
|
61
|
+
- `flag` accepts the write and marks it for product review.
|
|
62
|
+
- `merge` is reserved for server-defined merge behavior.
|
|
63
|
+
|
|
64
|
+
## Intent Coordination
|
|
65
|
+
|
|
66
|
+
Intents are live coordination signals. They are not database locks.
|
|
67
|
+
|
|
68
|
+
When another human or agent is active on the same target, the caller chooses the
|
|
69
|
+
behavior:
|
|
70
|
+
|
|
71
|
+
- `ifBusy: 'return'` returns active intents immediately.
|
|
72
|
+
- `ifBusy: 'wait'` waits until the matching intent clears.
|
|
73
|
+
- `ifBusy: 'fail'` throws `AbloBusyError` with the active intents attached.
|
|
74
|
+
|
|
75
|
+
Schema clients wait from the realtime intent stream. Schema-less HTTP callers
|
|
76
|
+
must pass an explicit `busyPollInterval` if they choose `ifBusy: 'wait'`; Ablo
|
|
77
|
+
does not hide a hard-coded polling loop. `busyTimeout` is only a maximum wait.
|
|
78
|
+
|
|
79
|
+
## Agent Runs
|
|
80
|
+
|
|
81
|
+
`agent.run(...)` is the advanced schema-less run envelope for workers that cannot
|
|
82
|
+
import the app schema. It returns one of three statuses:
|
|
83
|
+
|
|
84
|
+
- `done` — the handler returned successfully.
|
|
85
|
+
- `failed` — the handler threw or the commit failed.
|
|
86
|
+
- `cancelled` — the run signal aborted.
|
|
87
|
+
|
|
88
|
+
Normal schema-backed agents should import the same schema as the app and write
|
|
89
|
+
through `ablo.<model>.update(...)`. The lower-level run envelope exists for
|
|
90
|
+
platform runtimes that need capability and task management without app code.
|
|
91
|
+
|
|
92
|
+
## Capabilities and Tasks
|
|
93
|
+
|
|
94
|
+
Capabilities scope what an agent is allowed to do. Tasks group a run for audit
|
|
95
|
+
and cost attribution.
|
|
96
|
+
|
|
97
|
+
Most users do not create either one manually. The SDK and hosted API manage the
|
|
98
|
+
common case. Manual capability and task APIs are for platform builders, custom
|
|
99
|
+
agent runtimes, and internal infrastructure.
|
|
100
|
+
|
|
101
|
+
Use `lease` as a crash cleanup window. A successful agent run still closes when
|
|
102
|
+
the handler returns, fails, or is cancelled.
|
|
103
|
+
|
|
104
|
+
## Audit Trail
|
|
105
|
+
|
|
106
|
+
Accepted writes can be attributed to:
|
|
107
|
+
|
|
108
|
+
- the actor that wrote,
|
|
109
|
+
- the human or system the actor worked on behalf of,
|
|
110
|
+
- the capability that scoped the write,
|
|
111
|
+
- the task or run that caused it,
|
|
112
|
+
- the resource, operation, and state cursor.
|
|
113
|
+
|
|
114
|
+
For agent work, this is what lets an audit surface answer: "what changed, who
|
|
115
|
+
authorized it, which run did it, and what state was it based on?"
|
|
116
|
+
|
|
117
|
+
## Persistence
|
|
118
|
+
|
|
119
|
+
Ablo defaults to volatile local persistence. That keeps the SDK focused on
|
|
120
|
+
coordination and audit instead of silently becoming a browser storage product.
|
|
121
|
+
|
|
122
|
+
Opt into durable browser cache and offline queueing when you need it:
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
const ablo = Ablo({
|
|
126
|
+
schema,
|
|
127
|
+
apiKey: process.env.ABLO_API_KEY,
|
|
128
|
+
persistence: 'indexeddb',
|
|
129
|
+
});
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Node, SSR, tests, and agents use volatile in-memory persistence automatically.
|
|
133
|
+
|
|
134
|
+
## Storage Boundary
|
|
135
|
+
|
|
136
|
+
Ablo does not need a customer database URL. When your own database is canonical,
|
|
137
|
+
Ablo calls a signed Data Source endpoint and records the coordination result for
|
|
138
|
+
receipts, realtime fanout, and audit. See [Connect Your Database](./data-sources.md).
|
|
139
|
+
|
|
140
|
+
## Batches
|
|
141
|
+
|
|
142
|
+
Most apps should use `ablo.<model>.create/update/delete`. Use
|
|
143
|
+
`commits.create(...)` only when you need a low-level batch or a schema-less
|
|
144
|
+
runtime.
|
|
145
|
+
|
|
146
|
+
Each operation in the commit carries its own target, data, stale policy, and
|
|
147
|
+
idempotency context. The server validates authorization, stale state, active
|
|
148
|
+
intent conflicts, and idempotency before accepting the commit.
|
package/docs/index.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Ablo Docs
|
|
2
|
+
|
|
3
|
+
Ablo is a state control API for **humans and AI agents editing the same
|
|
4
|
+
typed state in real time, with attribution, conflict handling, and
|
|
5
|
+
fast cutoff**.
|
|
6
|
+
|
|
7
|
+
It gives agents a narrow way to write production state: declare models, load current state, coordinate active work, and write with stale-state checks. Capabilities, tasks, commits, and receipts are the protocol underneath, not first-integration ceremony.
|
|
8
|
+
|
|
9
|
+
Multiplayer is not a separate product mode. If humans, server actions, and agents
|
|
10
|
+
use the same `Ablo({ schema, apiKey })` client and write through
|
|
11
|
+
`ablo.<model>`, Ablo fans out confirmed deltas, exposes active intents, and
|
|
12
|
+
rejects stale writes for every participant.
|
|
13
|
+
|
|
14
|
+
## What you get, in three commitments
|
|
15
|
+
|
|
16
|
+
These commitments drive every design choice in the rest of the docs; if
|
|
17
|
+
they don't match what you're building, the trade-offs land elsewhere
|
|
18
|
+
(Replicache, ElectricSQL, PowerSync for human-only real-time; Zero for
|
|
19
|
+
query-shaped sync).
|
|
20
|
+
|
|
21
|
+
- **One model API for every actor.** `ablo.<model>.update(...)` is the
|
|
22
|
+
call from React components, server actions, background workers, and
|
|
23
|
+
AI agents alike. No separate "agent SDK," no parallel mutation path.
|
|
24
|
+
Attribution comes from the credential, not the call site.
|
|
25
|
+
- **Server owns the scope convention.** Tenancy / per-entity scope
|
|
26
|
+
prefixes (`org:`, `deck:`, or your own `region:` / `customer:`) are
|
|
27
|
+
declared once on the schema's `identityRoles`. Consumer code never
|
|
28
|
+
composes group strings. Same boundary Liveblocks (`prepareSession`),
|
|
29
|
+
PowerSync (named streams), and Zero (synced queries) settled on.
|
|
30
|
+
- **Capabilities, not API keys, for agents.** Per-run, per-scope, leased
|
|
31
|
+
credentials with per-request signature verification and instant
|
|
32
|
+
revocation. The 2025-26 AI-agent auth consensus (OAuth 2.1 / MCP,
|
|
33
|
+
AWS STS, Vault leases, Auth0 Token Vault) converged on this shape;
|
|
34
|
+
capabilities are Ablo's instance. See
|
|
35
|
+
[Capabilities](./capabilities.md#why-capabilities-not-api-keys) for
|
|
36
|
+
the design rationale.
|
|
37
|
+
|
|
38
|
+
## Start here
|
|
39
|
+
|
|
40
|
+
- [Quickstart](./quickstart.md) — Make your first schema-backed write.
|
|
41
|
+
- [Integration Guide](./integration-guide.md) — Choose Ablo-managed state, Data Source, React, multiplayer, and agent patterns.
|
|
42
|
+
- [Guarantees](./guarantees.md) — What confirmed writes, stale checks, and intents guarantee.
|
|
43
|
+
- [Interaction Model](./interaction-model.md) — The commit plane and control plane.
|
|
44
|
+
- [API Reference](./api.md) — Resource-by-resource method shape.
|
|
45
|
+
- [Client Behavior](./client-behavior.md) — Options, errors, retries, timeouts, and imports.
|
|
46
|
+
- [Connect Your Database](./data-sources.md) — Keep canonical rows in your app database without giving Ablo database credentials.
|
|
47
|
+
- [API Keys](./api-keys.md) — Bearer tokens for the public API.
|
|
48
|
+
|
|
49
|
+
## API shape
|
|
50
|
+
|
|
51
|
+
| Plane | Primitives | Purpose |
|
|
52
|
+
|---|---|---|
|
|
53
|
+
| State | `Schema`, `Model`, `Intent`, `Receipt` | The product path. Load, coordinate, write, confirm. |
|
|
54
|
+
| Commit | `Resource`, `Commit` | Advanced protocol path for custom runtimes and batches. |
|
|
55
|
+
| Control | `Capability`, `Task`, `Usage` | The authority path. Scope, attribute, meter, audit. |
|
|
56
|
+
| Storage | `Managed State`, `Data Source` | Ablo stores declared models by default; existing app tables use a signed Data Source. |
|
|
57
|
+
|
|
58
|
+
## Use cases
|
|
59
|
+
|
|
60
|
+
- **Let agents write to shared state** — Give an AI agent scoped, revocable write access to your typed data.
|
|
61
|
+
- **Coordinate multiple actors** — Use intents to broadcast pre-write declarations across humans and agents.
|
|
62
|
+
- **Audit every agent action** — Trace any write back to a human in one query.
|
|
63
|
+
- **Build collaborative editors** — Humans and agents on the same record, with realtime updates and stale-read protection.
|
|
64
|
+
- **Meter and gate API usage** — Per-key, per-team usage reports and quota enforcement.
|
|
65
|
+
- **Integrate with A2A and MCP** — Speak the same protocols as Claude, Cursor, Gemini.
|
|
66
|
+
|
|
67
|
+
## Concepts
|
|
68
|
+
|
|
69
|
+
- [Model Methods](./api.md#model-methods) — Load and write typed state.
|
|
70
|
+
- [Integration Guide](./integration-guide.md) — The normal app path and optional pieces.
|
|
71
|
+
- [Guarantees](./guarantees.md) — Confirmed writes, optimistic state, stale-write protection, and agent lifecycle.
|
|
72
|
+
- [Intent](./api.md#intent) — Broadcast proposed work before committing.
|
|
73
|
+
- [Advanced Commit API](./api.md#advanced-commit-api) — Apply custom batch mutations.
|
|
74
|
+
- [Connect Your Database](./data-sources.md) — Where data lands when your app database is canonical.
|
|
75
|
+
- [Receipt](./api.md#receipt) — Confirm what landed.
|
|
76
|
+
- [Capability](./api.md#capability) — Signed credentials for a bounded actor, operation set, sync group, and lease.
|
|
77
|
+
- [Task](./api.md#task) — One agent run; the audit envelope for commits and cost.
|
|
78
|
+
- [Usage](./api.md#usage) — Metering and audit dimensions.
|
|
79
|
+
|
|
80
|
+
## Examples
|
|
81
|
+
|
|
82
|
+
- [AI SDK Tool](./examples/ai-sdk-tool.md) — Put Ablo inside an AI SDK tool call.
|
|
83
|
+
- [Existing Python Backend](./examples/existing-python-backend.md) — Add multiplayer and future agent writes without replacing a Python API server.
|
|
84
|
+
- [Agent + Human](./examples/agent-human.md) — Yield when a human is editing the same task.
|
|
85
|
+
- [Server Agent](./examples/server-agent.md) — Schema-backed worker plus advanced schema-less run.
|
|
86
|
+
- [Next.js](./examples/nextjs.md) — App-router setup with React bindings.
|
|
87
|
+
|
|
88
|
+
## Runtime builds
|
|
89
|
+
|
|
90
|
+
- `@ablo/sync-engine` — schema-powered sync client for typed model operations, realtime, intents, and receipts.
|
|
91
|
+
- `Ablo({ apiKey })` — advanced resource client for runtimes that intentionally cannot import a schema.
|
|
92
|
+
|
|
93
|
+
## More
|
|
94
|
+
|
|
95
|
+
- [README](../README.md) — product overview and first example.
|
|
96
|
+
- [AGENTS.md](../AGENTS.md) — short installation guidance for coding assistants.
|
|
97
|
+
- [Changelog](../CHANGELOG.md) — what shipped recently.
|