@abloatai/ablo 0.3.1 → 0.4.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 +39 -1
- package/NOTICE +2 -2
- package/README.md +27 -25
- package/dist/agent/Agent.d.ts +1 -1
- package/dist/agent/Agent.js +1 -1
- package/dist/agent/index.d.ts +4 -4
- package/dist/agent/index.js +6 -6
- package/dist/agent/types.d.ts +1 -1
- package/dist/ai-sdk/index.d.ts +3 -3
- package/dist/ai-sdk/index.js +3 -3
- package/dist/ai-sdk/intent-broadcast.d.ts +1 -1
- package/dist/ai-sdk/intent-broadcast.js +1 -1
- package/dist/auth/index.d.ts +1 -1
- package/dist/client/Ablo.d.ts +8 -14
- package/dist/client/Ablo.js +32 -1
- package/dist/client/auth.d.ts +3 -3
- package/dist/client/auth.js +5 -5
- package/dist/client/createModelProxy.d.ts +110 -32
- package/dist/client/createModelProxy.js +77 -38
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.js +2 -2
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.js +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.js +2 -2
- package/dist/errors.d.ts +1 -1
- package/dist/errors.js +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.js +9 -9
- package/dist/interfaces/headless.d.ts +1 -1
- package/dist/interfaces/headless.js +2 -2
- package/dist/policy/index.d.ts +2 -2
- package/dist/policy/index.js +2 -2
- package/dist/principal.d.ts +1 -1
- package/dist/principal.js +1 -1
- package/dist/react/ClientSideSuspense.d.ts +1 -1
- package/dist/react/SyncGroupProvider.js +1 -1
- package/dist/react/context.d.ts +1 -1
- package/dist/react/context.js +1 -1
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.js +1 -1
- package/dist/react/useCurrentUserId.js +1 -1
- package/dist/react/useErrorListener.js +1 -1
- package/dist/react/useMutate.d.ts +1 -1
- package/dist/react/useMutationFailureListener.js +1 -1
- package/dist/react/useReader.d.ts +1 -1
- package/dist/schema/field.d.ts +1 -1
- package/dist/schema/field.js +1 -1
- package/dist/schema/index.d.ts +2 -2
- package/dist/schema/index.js +2 -2
- package/dist/schema/model.d.ts +2 -2
- package/dist/schema/model.js +2 -2
- package/dist/schema/queries.d.ts +1 -1
- package/dist/schema/queries.js +1 -1
- package/dist/schema/relation.d.ts +1 -1
- package/dist/schema/relation.js +1 -1
- package/dist/schema/schema.d.ts +1 -1
- package/dist/schema/schema.js +1 -1
- package/dist/source/index.d.ts +22 -28
- package/dist/source/index.js +23 -20
- package/dist/source/pushQueue.d.ts +1 -1
- package/dist/source/pushQueue.js +2 -2
- package/dist/sync/SyncWebSocket.d.ts +14 -0
- package/dist/sync/createIntentStream.js +7 -0
- package/dist/testing/fixtures/models.d.ts +1 -1
- package/dist/testing/fixtures/models.js +1 -1
- package/dist/testing/helpers/react-wrapper.d.ts +2 -2
- package/dist/testing/helpers/react-wrapper.js +2 -2
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.js +1 -1
- package/dist/types/streams.d.ts +39 -0
- package/docs/api.md +78 -20
- package/docs/data-sources.md +50 -16
- package/docs/examples/ai-sdk-tool.md +14 -31
- package/docs/examples/existing-python-backend.md +6 -6
- package/docs/integration-guide.md +8 -7
- package/docs/interaction-model.md +16 -4
- package/docs/mcp.md +1 -1
- package/docs/quickstart.md +20 -18
- package/examples/data-source/README.md +1 -1
- package/examples/data-source/ablo-driver.ts +5 -5
- package/examples/data-source/customer-server.ts +10 -10
- package/examples/data-source/run.ts +9 -11
- package/examples/data-source/schema.ts +1 -1
- package/examples/quickstart.ts +2 -2
- package/llms.txt +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,50 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Per-entity coordination intents on the model accessor.
|
|
8
|
+
|
|
9
|
+
Coordinate writes to an entity through the same accessor you read it with —
|
|
10
|
+
`ablo.<model>.intent(id)`, returning a `ModelIntentHandle`. Intent state is one
|
|
11
|
+
self-describing object (`{ object: 'intent', id, status, target, action, heldBy,
|
|
12
|
+
participantKind, createdAt?, expiresAt? }`) with a single lifecycle:
|
|
13
|
+
`status: 'active' | 'committed' | 'expired' | 'canceled'`. An `active` intent is
|
|
14
|
+
the lock.
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
- `ablo.<model>.intent(id)` → `ModelIntentHandle<T>`, beside `create` / `update`
|
|
18
|
+
/ `retrieve` / `load` on every model.
|
|
19
|
+
- Read side (any participant, synchronous + reactive): `current` (the holder's
|
|
20
|
+
intent, or `null`), `status` (`'idle'` when free), `settled()`.
|
|
21
|
+
- Write side (the holder): `acquire()`, `acquireOrAwait()`, lease-guarded
|
|
22
|
+
`update()`, `release()`, `revoke()`.
|
|
23
|
+
- `AsyncDisposable`: `await using lock = ablo.<model>.intent(id)` auto-releases
|
|
24
|
+
on scope exit.
|
|
25
|
+
- `acquireOrAwait()` — serialize-on-contention: take the lease, or wait out the
|
|
26
|
+
current holder, re-read the changed row, then take it. The caller never branches
|
|
27
|
+
on who holds the target — it just gets the target safely. Bind it to an agent's
|
|
28
|
+
write-tool boundary so agents never reason about coordination.
|
|
29
|
+
- New exports: `ModelIntentHandle`, `ModelIntentAcquireOptions`.
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
- `acquire()` is fire-and-forget over the socket — it does not throw on conflict.
|
|
33
|
+
Resolve contention with `acquireOrAwait()` (wait) or read `current` for a
|
|
34
|
+
reactive "who's editing" badge, rather than catching a rejection.
|
|
35
|
+
|
|
36
|
+
### Deprecated
|
|
37
|
+
- Participant-level `intents.claim()` / `onRejected()` and the `intent_rejected`
|
|
38
|
+
wire frame still work but are superseded by the per-model handle. Their removal
|
|
39
|
+
is a future breaking change.
|
|
40
|
+
|
|
3
41
|
## Unreleased
|
|
4
42
|
|
|
5
43
|
Schema-driven identity sync-group composition, plus a terser capability surface.
|
|
6
44
|
|
|
7
45
|
The convention for deriving a participant's allowed sync-groups from its identity is now declared on the consumer's schema as an open registration. Consumers with a `{ regionId, customerId }` identity shape declare their own roles instead of receiving any built-in prefixes from the SDK.
|
|
8
46
|
|
|
9
|
-
Capability fields shed their redundant `allowed` prefix to match the surrounding vocabulary — capability inputs always describe what the bearer
|
|
47
|
+
Capability fields shed their redundant `allowed` prefix to match the surrounding vocabulary — capability inputs always describe what the bearer _can_ touch, so the prefix was doing no disambiguation work for the consumer.
|
|
10
48
|
|
|
11
49
|
### Added
|
|
12
50
|
|
package/NOTICE
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
@ablo
|
|
1
|
+
@abloatai/ablo
|
|
2
2
|
Copyright 2025-2026 Fablo Innovation AB
|
|
3
3
|
|
|
4
4
|
This product includes software developed by Fablo Innovation AB
|
|
@@ -7,6 +7,6 @@ This product includes software developed by Fablo Innovation AB
|
|
|
7
7
|
"Ablo" is a trademark of Fablo Innovation AB. This license does not grant
|
|
8
8
|
permission to use the Ablo name, logo, or trademarks. Third parties
|
|
9
9
|
may describe their use of or compatibility with Ablo factually (e.g.,
|
|
10
|
-
"built with @ablo
|
|
10
|
+
"built with @abloatai/ablo") but may not use the Ablo name in a way
|
|
11
11
|
that suggests endorsement, affiliation, or origin without written
|
|
12
12
|
permission.
|
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ provider. Do not ship `ABLO_API_KEY` in a browser bundle.
|
|
|
32
32
|
|
|
33
33
|
## Quick Start
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
````ts
|
|
36
36
|
import Ablo from '@abloatai/ablo';
|
|
37
37
|
import { defineSchema, model, z } from '@abloatai/ablo/schema';
|
|
38
38
|
|
|
@@ -64,13 +64,13 @@ const updated = await ablo.weatherReports.update(created.id, {
|
|
|
64
64
|
console.log({ id: updated.id, status: updated.status });
|
|
65
65
|
|
|
66
66
|
await ablo.dispose();
|
|
67
|
-
```
|
|
67
|
+
```c
|
|
68
68
|
|
|
69
69
|
Expected output:
|
|
70
70
|
|
|
71
71
|
```txt
|
|
72
72
|
{ id: '...', status: 'ready' }
|
|
73
|
-
|
|
73
|
+
````
|
|
74
74
|
|
|
75
75
|
Pass `schema` for typed model resources. Omit it only for advanced server-side
|
|
76
76
|
resource clients such as custom agents and MCP routes.
|
|
@@ -87,33 +87,37 @@ future agents, read [Integration Guide](./docs/integration-guide.md).
|
|
|
87
87
|
|
|
88
88
|
## AI Activity on Existing State
|
|
89
89
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
When AI or background work will touch an existing row for more than a quick
|
|
91
|
+
write, coordinate through `ablo.<model>.intent(id)` — the coordination accessor
|
|
92
|
+
that sits beside `create`/`update`/`retrieve`. It returns a handle
|
|
93
|
+
synchronously, so you can see who's already working on a row before you start.
|
|
94
94
|
|
|
95
95
|
```ts
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
96
|
+
const report = ablo.weatherReports.intent('weather_stockholm');
|
|
97
|
+
|
|
98
|
+
// Read side: is someone already on it? Wait for them to finish.
|
|
99
|
+
if (report.current) {
|
|
100
|
+
report.current.heldBy; // 'agent:forecaster'
|
|
101
|
+
await report.settled();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Write side: acquire so other participants yield while we work.
|
|
105
|
+
await report.acquire({ action: 'checking_weather', field: 'forecast', ttl: '2m' });
|
|
101
106
|
|
|
102
107
|
// Your existing weather tool or agent call. While this runs, other clients see
|
|
103
108
|
// that weather_stockholm is being checked.
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
});
|
|
109
|
+
const row = ablo.weatherReports.retrieve('weather_stockholm');
|
|
110
|
+
const weather = await weatherAgent.getWeather(row.location);
|
|
107
111
|
|
|
108
|
-
await
|
|
112
|
+
await report.update({
|
|
109
113
|
status: 'ready',
|
|
110
114
|
forecast: weather.summary,
|
|
111
115
|
});
|
|
112
116
|
```
|
|
113
117
|
|
|
114
|
-
Ablo does not fetch the weather. It keeps the activity visible
|
|
115
|
-
|
|
116
|
-
|
|
118
|
+
Ablo does not fetch the weather. It keeps the activity visible while the work
|
|
119
|
+
runs, rejects `report.update(...)` with `AbloStaleContextError` if the row
|
|
120
|
+
changed under you, and releases the intent automatically once the write lands.
|
|
117
121
|
|
|
118
122
|
## Multiplayer
|
|
119
123
|
|
|
@@ -123,8 +127,8 @@ the same shared resource stream.
|
|
|
123
127
|
|
|
124
128
|
- `ablo.<model>.create/update/delete` fan out confirmed deltas to subscribers.
|
|
125
129
|
- `useAblo(...)` gives React clients the live row plus active intents.
|
|
126
|
-
- `ablo.<model>.
|
|
127
|
-
- `ablo.intents` remains available for custom lower-level coordination.
|
|
130
|
+
- `ablo.<model>.intent(id)` lets humans and agents see and coordinate active work before a write lands.
|
|
131
|
+
- `ablo.intents` remains available for custom lower-level coordination across resources.
|
|
128
132
|
|
|
129
133
|
If a team writes directly to its own database outside Ablo, that write bypasses
|
|
130
134
|
the multiplayer stream until the app reports it through Data Source events.
|
|
@@ -162,9 +166,7 @@ if (busy.length > 0) {
|
|
|
162
166
|
console.log(`${busy[0].actor} is ${busy[0].action}`);
|
|
163
167
|
}
|
|
164
168
|
|
|
165
|
-
await ablo.intents.waitFor(
|
|
166
|
-
{ resource: 'weatherReports', id: 'weather_stockholm' },
|
|
167
|
-
);
|
|
169
|
+
await ablo.intents.waitFor({ resource: 'weatherReports', id: 'weather_stockholm' });
|
|
168
170
|
```
|
|
169
171
|
|
|
170
172
|
Policy names are literal:
|
|
@@ -203,7 +205,7 @@ Data Source endpoint. Your app keeps the database credentials; Ablo sends signed
|
|
|
203
205
|
commit requests to your route.
|
|
204
206
|
|
|
205
207
|
```bash
|
|
206
|
-
|
|
208
|
+
ABLO_API_KEY=sk_live_...
|
|
207
209
|
```
|
|
208
210
|
|
|
209
211
|
See [Connect Your Database](./docs/data-sources.md) for the route and commit shape.
|
package/dist/agent/Agent.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* ```ts
|
|
11
11
|
* import { generateText, tool, stepCountIs } from 'ai';
|
|
12
|
-
* import { Agent } from '@ablo/
|
|
12
|
+
* import { Agent } from '@abloatai/ablo/agent';
|
|
13
13
|
*
|
|
14
14
|
* const perception = new Agent({
|
|
15
15
|
* syncServerUrl: 'http://localhost:8080',
|
package/dist/agent/Agent.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* ```ts
|
|
11
11
|
* import { generateText, tool, stepCountIs } from 'ai';
|
|
12
|
-
* import { Agent } from '@ablo/
|
|
12
|
+
* import { Agent } from '@abloatai/ablo/agent';
|
|
13
13
|
*
|
|
14
14
|
* const perception = new Agent({
|
|
15
15
|
* syncServerUrl: 'http://localhost:8080',
|
package/dist/agent/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @ablo/
|
|
2
|
+
* @abloatai/ablo/agent — Agent SDK helpers
|
|
3
3
|
*
|
|
4
4
|
* Two entry points depending on agent lifetime:
|
|
5
5
|
*
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* server-issued capability token instead of session cookies.
|
|
13
13
|
*
|
|
14
14
|
* ```ts
|
|
15
|
-
* import Ablo from '@ablo
|
|
15
|
+
* import Ablo from '@abloatai/ablo';
|
|
16
16
|
*
|
|
17
17
|
* const ablo = Ablo({
|
|
18
18
|
* schema,
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
*
|
|
45
45
|
* ```ts
|
|
46
46
|
* import { generateText, tool, stepCountIs } from 'ai';
|
|
47
|
-
* import { Agent } from '@ablo/
|
|
47
|
+
* import { Agent } from '@abloatai/ablo/agent';
|
|
48
48
|
*
|
|
49
49
|
* const perception = new Agent({
|
|
50
50
|
* syncServerUrl: 'http://localhost:8080',
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
* ```ts
|
|
79
79
|
* import { tool } from 'ai';
|
|
80
80
|
* import { z } from 'zod';
|
|
81
|
-
* import { Agent, type AgentContext } from '@ablo/
|
|
81
|
+
* import { Agent, type AgentContext } from '@abloatai/ablo/agent';
|
|
82
82
|
*
|
|
83
83
|
* export const updateSlideTool = () => tool({
|
|
84
84
|
* description: 'Update a slide title',
|
package/dist/agent/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @ablo/
|
|
2
|
+
* @abloatai/ablo/agent — Agent SDK helpers
|
|
3
3
|
*
|
|
4
4
|
* Two entry points depending on agent lifetime:
|
|
5
5
|
*
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* server-issued capability token instead of session cookies.
|
|
13
13
|
*
|
|
14
14
|
* ```ts
|
|
15
|
-
* import Ablo from '@ablo
|
|
15
|
+
* import Ablo from '@abloatai/ablo';
|
|
16
16
|
*
|
|
17
17
|
* const ablo = Ablo({
|
|
18
18
|
* schema,
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
*
|
|
45
45
|
* ```ts
|
|
46
46
|
* import { generateText, tool, stepCountIs } from 'ai';
|
|
47
|
-
* import { Agent } from '@ablo/
|
|
47
|
+
* import { Agent } from '@abloatai/ablo/agent';
|
|
48
48
|
*
|
|
49
49
|
* const perception = new Agent({
|
|
50
50
|
* syncServerUrl: 'http://localhost:8080',
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
* ```ts
|
|
79
79
|
* import { tool } from 'ai';
|
|
80
80
|
* import { z } from 'zod';
|
|
81
|
-
* import { Agent, type AgentContext } from '@ablo/
|
|
81
|
+
* import { Agent, type AgentContext } from '@abloatai/ablo/agent';
|
|
82
82
|
*
|
|
83
83
|
* export const updateSlideTool = () => tool({
|
|
84
84
|
* description: 'Update a slide title',
|
|
@@ -117,12 +117,12 @@
|
|
|
117
117
|
// `Agent` is the class AND the namespace for its types. Reach for
|
|
118
118
|
// options, context, and session options via dot access:
|
|
119
119
|
//
|
|
120
|
-
// import { Agent } from '@ablo/
|
|
120
|
+
// import { Agent } from '@abloatai/ablo/agent';
|
|
121
121
|
// const opts: Agent.Options = { ... };
|
|
122
122
|
// const ctx: Agent.Context = { perception };
|
|
123
123
|
// const s: Agent.SessionOptions = { ... };
|
|
124
124
|
//
|
|
125
125
|
// Everything else (Activity, Claim, Turn, Peer, ActiveIntent, ...)
|
|
126
126
|
// lives on the `Ablo.*` namespace via
|
|
127
|
-
// `import type { Ablo } from '@ablo
|
|
127
|
+
// `import type { Ablo } from '@abloatai/ablo'`.
|
|
128
128
|
export { Agent } from './Agent.js';
|
package/dist/agent/types.d.ts
CHANGED
|
@@ -35,7 +35,7 @@ export interface PresenceAnnouncer {
|
|
|
35
35
|
*
|
|
36
36
|
* ```ts
|
|
37
37
|
* import { generateText, tool } from 'ai';
|
|
38
|
-
* import { Agent, type AgentContext } from '@ablo/
|
|
38
|
+
* import { Agent, type AgentContext } from '@abloatai/ablo/agent';
|
|
39
39
|
*
|
|
40
40
|
* const updateSlideTool = () => tool({
|
|
41
41
|
* inputSchema: z.object({ id: z.string(), title: z.string() }),
|
package/dist/ai-sdk/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `@ablo/
|
|
2
|
+
* `@abloatai/ablo/ai-sdk` — multiplayer-with-AI as language model
|
|
3
3
|
* middleware.
|
|
4
4
|
*
|
|
5
5
|
* Two cross-cutting middlewares for any AI SDK consumer using
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* import {
|
|
25
25
|
* intentBroadcastMiddleware,
|
|
26
26
|
* coordinationContextMiddleware,
|
|
27
|
-
* } from '@ablo/
|
|
27
|
+
* } from '@abloatai/ablo/ai-sdk';
|
|
28
28
|
*
|
|
29
29
|
* const target = { entityType: 'SlideDeck', entityId: 'deck-abc' };
|
|
30
30
|
*
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
* Or use the convenience composition for the common case:
|
|
49
49
|
*
|
|
50
50
|
* ```ts
|
|
51
|
-
* import { wrapWithMultiplayer } from '@ablo/
|
|
51
|
+
* import { wrapWithMultiplayer } from '@abloatai/ablo/ai-sdk';
|
|
52
52
|
*
|
|
53
53
|
* const wrappedModel = wrapWithMultiplayer({
|
|
54
54
|
* model: anthropic('claude-opus-4-7'),
|
package/dist/ai-sdk/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `@ablo/
|
|
2
|
+
* `@abloatai/ablo/ai-sdk` — multiplayer-with-AI as language model
|
|
3
3
|
* middleware.
|
|
4
4
|
*
|
|
5
5
|
* Two cross-cutting middlewares for any AI SDK consumer using
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* import {
|
|
25
25
|
* intentBroadcastMiddleware,
|
|
26
26
|
* coordinationContextMiddleware,
|
|
27
|
-
* } from '@ablo/
|
|
27
|
+
* } from '@abloatai/ablo/ai-sdk';
|
|
28
28
|
*
|
|
29
29
|
* const target = { entityType: 'SlideDeck', entityId: 'deck-abc' };
|
|
30
30
|
*
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
* Or use the convenience composition for the common case:
|
|
49
49
|
*
|
|
50
50
|
* ```ts
|
|
51
|
-
* import { wrapWithMultiplayer } from '@ablo/
|
|
51
|
+
* import { wrapWithMultiplayer } from '@abloatai/ablo/ai-sdk';
|
|
52
52
|
*
|
|
53
53
|
* const wrappedModel = wrapWithMultiplayer({
|
|
54
54
|
* model: anthropic('claude-opus-4-7'),
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*
|
|
12
12
|
* Open-source-clean: depends only on `@ai-sdk/provider` types and
|
|
13
13
|
* the package's own `SyncAgent`. No app-specific assumptions —
|
|
14
|
-
* Ablo's web app uses this, but so can any consumer of `@ablo
|
|
14
|
+
* Ablo's web app uses this, but so can any consumer of `@abloatai/ablo`.
|
|
15
15
|
*
|
|
16
16
|
* Cost: one WS frame at stream start (`intent_begin`), one at end
|
|
17
17
|
* (`intent_abandon`). No DB I/O, no extra LLM tokens.
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*
|
|
12
12
|
* Open-source-clean: depends only on `@ai-sdk/provider` types and
|
|
13
13
|
* the package's own `SyncAgent`. No app-specific assumptions —
|
|
14
|
-
* Ablo's web app uses this, but so can any consumer of `@ablo
|
|
14
|
+
* Ablo's web app uses this, but so can any consumer of `@abloatai/ablo`.
|
|
15
15
|
*
|
|
16
16
|
* Cost: one WS frame at stream start (`intent_begin`), one at end
|
|
17
17
|
* (`intent_abandon`). No DB I/O, no extra LLM tokens.
|
package/dist/auth/index.d.ts
CHANGED
|
@@ -63,7 +63,7 @@ export declare function resolveIdentity(options: ResolveIdentityRequest): Promis
|
|
|
63
63
|
/**
|
|
64
64
|
* Capability-token refresh scheduler.
|
|
65
65
|
*
|
|
66
|
-
* Long-lived `@ablo
|
|
66
|
+
* Long-lived `@abloatai/ablo` clients hold a server-issued capability
|
|
67
67
|
* token whose TTL (1h default) is shorter than typical browser sessions.
|
|
68
68
|
* Without proactive refresh, the WebSocket would either be force-closed
|
|
69
69
|
* by the server at expiry (code 1008) or fail its next reconnect with
|
package/dist/client/Ablo.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* bootstrap, offline queue, DI adapters) behind a single function call.
|
|
6
6
|
*
|
|
7
7
|
* Usage:
|
|
8
|
-
* import { Ablo } from '@ablo/
|
|
8
|
+
* import { Ablo } from '@abloatai/ablo/client';
|
|
9
9
|
* import { schema } from './schema';
|
|
10
10
|
*
|
|
11
11
|
* const sync = Ablo({ schema, apiKey: process.env.ABLO_API_KEY });
|
|
@@ -21,7 +21,7 @@ import { ObjectPool } from '../ObjectPool.js';
|
|
|
21
21
|
import type { SyncStoreContract } from '../react/context.js';
|
|
22
22
|
import type { SyncWebSocket } from '../sync/SyncWebSocket.js';
|
|
23
23
|
import { type SyncStatus } from '../BaseSyncedStore.js';
|
|
24
|
-
import type { IntentStream, PresenceStream, Snapshot } from '../types/streams.js';
|
|
24
|
+
import type { IntentStream, IntentWaitOptions, PresenceStream, Snapshot } from '../types/streams.js';
|
|
25
25
|
import type { ParticipantManager } from '../sync/participants.js';
|
|
26
26
|
import type { ActiveIntent, Duration, TargetRange } from '../types/streams.js';
|
|
27
27
|
import { type AbloApi, type AbloApiClientOptions, type AbloApiIntents } from './ApiClient.js';
|
|
@@ -48,7 +48,7 @@ export interface Turn {
|
|
|
48
48
|
* `ApiKeySetter` exactly so any rotation pattern that works with
|
|
49
49
|
* `@anthropic-ai/sdk` works here.
|
|
50
50
|
*
|
|
51
|
-
* Re-exported from `./auth` so existing import paths (`@ablo
|
|
51
|
+
* Re-exported from `./auth` so existing import paths (`@abloatai/ablo`)
|
|
52
52
|
* keep resolving; the canonical definition lives there alongside the
|
|
53
53
|
* resolvers that consume it.
|
|
54
54
|
*/
|
|
@@ -69,8 +69,7 @@ export interface AbloOptions<S extends SchemaRecord = SchemaRecord> {
|
|
|
69
69
|
*/
|
|
70
70
|
authToken?: string | null | undefined;
|
|
71
71
|
/**
|
|
72
|
-
* Override the Ablo API base URL. Defaults to hosted production
|
|
73
|
-
* `process.env['ABLO_BASE_URL']` if unset.
|
|
72
|
+
* Override the Ablo API base URL. Defaults to hosted production.
|
|
74
73
|
*/
|
|
75
74
|
baseURL?: string | null | undefined;
|
|
76
75
|
/** Per-request timeout in milliseconds. */
|
|
@@ -118,7 +117,7 @@ export interface InternalAbloOptions<S extends SchemaRecord = SchemaRecord> {
|
|
|
118
117
|
apiKey?: string | ApiKeySetter | null | undefined;
|
|
119
118
|
/**
|
|
120
119
|
* Bearer auth token. Sent as `Authorization: Bearer <token>` on
|
|
121
|
-
* every request.
|
|
120
|
+
* every request.
|
|
122
121
|
*
|
|
123
122
|
* Use this for self-hosted deployments where your auth layer mints
|
|
124
123
|
* cap tokens directly. Hosted-cloud consumers pass `apiKey` instead;
|
|
@@ -129,7 +128,6 @@ export interface InternalAbloOptions<S extends SchemaRecord = SchemaRecord> {
|
|
|
129
128
|
* Override the default base URL. Defaults to
|
|
130
129
|
* `wss://mesh.ablo.finance` for hosted production; pass an explicit
|
|
131
130
|
* URL for self-hosted or staging (e.g. `wss://mesh-staging.ablo.finance`).
|
|
132
|
-
* Reads `process.env['ABLO_BASE_URL']` if unset.
|
|
133
131
|
*/
|
|
134
132
|
baseURL?: string | null | undefined;
|
|
135
133
|
/**
|
|
@@ -327,7 +325,7 @@ export interface InternalAbloOptions<S extends SchemaRecord = SchemaRecord> {
|
|
|
327
325
|
* deprecated aliases for one release cycle so consumers can migrate
|
|
328
326
|
* without a flag day.
|
|
329
327
|
*/
|
|
330
|
-
export type { ModelCountOptions, ModelListOptions, ModelListScope, ModelLoadOptions,
|
|
328
|
+
export type { ModelCountOptions, ModelListOptions, ModelListScope, ModelLoadOptions, ModelIntentAcquireOptions, ModelIntentHandle, ModelOperations, } from './createModelProxy.js';
|
|
331
329
|
import type { ModelOperations } from './createModelProxy.js';
|
|
332
330
|
export type ResourceOperationAction = 'create' | 'update' | 'delete' | 'archive' | 'unarchive';
|
|
333
331
|
export type CommitWait = 'queued' | 'confirmed';
|
|
@@ -366,11 +364,7 @@ export interface BusyOptions {
|
|
|
366
364
|
/** HTTP API polling interval while waiting. WebSocket clients ignore it. */
|
|
367
365
|
readonly busyPollInterval?: number;
|
|
368
366
|
}
|
|
369
|
-
export
|
|
370
|
-
readonly timeout?: number;
|
|
371
|
-
readonly pollInterval?: number;
|
|
372
|
-
readonly signal?: AbortSignal;
|
|
373
|
-
}
|
|
367
|
+
export type { IntentWaitOptions } from '../types/streams.js';
|
|
374
368
|
export interface ResourceReadOptions extends BusyOptions {
|
|
375
369
|
}
|
|
376
370
|
export interface IntentCreateOptions {
|
|
@@ -816,7 +810,7 @@ export declare namespace Ablo {
|
|
|
816
810
|
type Event = import('../source/index.js').SourceEvent;
|
|
817
811
|
type EventsResult = import('../source/index.js').SourceEventsResult;
|
|
818
812
|
type Scope = import('../source/index.js').SourceScope;
|
|
819
|
-
type
|
|
813
|
+
type ApiKey = import('../source/index.js').SourceApiKey;
|
|
820
814
|
type Options<S extends _SchemaTypes.SchemaRecord = _SchemaTypes.SchemaRecord, TAuth = unknown> = import('../source/index.js').AbloSourceOptions<S, TAuth>;
|
|
821
815
|
type ModelHandlers<Row, CreateInput, TAuth = unknown> = import('../source/index.js').SourceModelHandlers<Row, CreateInput, TAuth>;
|
|
822
816
|
type SignatureVerificationResult = import('../source/index.js').SourceSignatureVerificationResult;
|
package/dist/client/Ablo.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* bootstrap, offline queue, DI adapters) behind a single function call.
|
|
6
6
|
*
|
|
7
7
|
* Usage:
|
|
8
|
-
* import { Ablo } from '@ablo/
|
|
8
|
+
* import { Ablo } from '@abloatai/ablo/client';
|
|
9
9
|
* import { schema } from './schema';
|
|
10
10
|
*
|
|
11
11
|
* const sync = Ablo({ schema, apiKey: process.env.ABLO_API_KEY });
|
|
@@ -1147,6 +1147,37 @@ export function Ablo(options) {
|
|
|
1147
1147
|
getLastSyncId: () => store.getSyncWebSocket()?.getLastSyncId() ?? store.lastSyncId ?? 0,
|
|
1148
1148
|
entities: { [modelKey]: id },
|
|
1149
1149
|
}),
|
|
1150
|
+
observe: (target) => {
|
|
1151
|
+
// The live intent stream only tracks *open* (active) claims;
|
|
1152
|
+
// terminal states (committed / expired / canceled) drop out of
|
|
1153
|
+
// the list entirely — exactly the ephemeral coordination model.
|
|
1154
|
+
// So a present entry is, by definition, `status: 'active'`.
|
|
1155
|
+
const held = publicIntents.list({
|
|
1156
|
+
resource: target.resource,
|
|
1157
|
+
id: target.id,
|
|
1158
|
+
})[0];
|
|
1159
|
+
if (!held)
|
|
1160
|
+
return null;
|
|
1161
|
+
return {
|
|
1162
|
+
object: 'intent',
|
|
1163
|
+
id: held.id,
|
|
1164
|
+
status: 'active',
|
|
1165
|
+
target: {
|
|
1166
|
+
type: held.target.resource,
|
|
1167
|
+
id: held.target.id,
|
|
1168
|
+
...(held.target.path ? { path: held.target.path } : {}),
|
|
1169
|
+
...(held.target.range ? { range: held.target.range } : {}),
|
|
1170
|
+
...(held.target.field ? { field: held.target.field } : {}),
|
|
1171
|
+
...(held.target.meta ? { meta: held.target.meta } : {}),
|
|
1172
|
+
},
|
|
1173
|
+
action: held.action,
|
|
1174
|
+
heldBy: held.actor,
|
|
1175
|
+
participantKind: held.participantKind,
|
|
1176
|
+
expiresAt: held.expiresAt,
|
|
1177
|
+
};
|
|
1178
|
+
},
|
|
1179
|
+
waitFor: (target, waitOptions) => publicIntents.waitFor({ resource: target.resource, id: target.id }, waitOptions),
|
|
1180
|
+
selfParticipantId: participantId,
|
|
1150
1181
|
});
|
|
1151
1182
|
}
|
|
1152
1183
|
const commits = {
|
package/dist/client/auth.d.ts
CHANGED
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
* with an actionable message — so the constructor reads as a
|
|
8
8
|
* sequence of named decisions rather than a stream of `??`-chains.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* Customer-facing env surface is intentionally small: `ABLO_API_KEY`
|
|
11
|
+
* is the only environment fallback. Other routing/auth overrides are
|
|
12
|
+
* explicit options so generated apps do not accrete hidden env knobs.
|
|
13
13
|
*/
|
|
14
14
|
/**
|
|
15
15
|
* Async callable that resolves to a fresh API key. Mirrors the shape
|
package/dist/client/auth.js
CHANGED
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
* with an actionable message — so the constructor reads as a
|
|
8
8
|
* sequence of named decisions rather than a stream of `??`-chains.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* Customer-facing env surface is intentionally small: `ABLO_API_KEY`
|
|
11
|
+
* is the only environment fallback. Other routing/auth overrides are
|
|
12
|
+
* explicit options so generated apps do not accrete hidden env knobs.
|
|
13
13
|
*/
|
|
14
14
|
import { AbloAuthenticationError } from '../errors.js';
|
|
15
15
|
/**
|
|
@@ -25,11 +25,11 @@ export function resolveApiKey(input) {
|
|
|
25
25
|
return input.options.apiKey ?? input.env.ABLO_API_KEY ?? null;
|
|
26
26
|
}
|
|
27
27
|
export function resolveAuthToken(input) {
|
|
28
|
-
return input.options.authToken ??
|
|
28
|
+
return input.options.authToken ?? null;
|
|
29
29
|
}
|
|
30
30
|
export const ABLO_DEFAULT_BASE_URL = 'wss://mesh.ablo.finance';
|
|
31
31
|
export function resolveBaseURL(input) {
|
|
32
|
-
return
|
|
32
|
+
return input.options.baseURL ?? ABLO_DEFAULT_BASE_URL;
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
35
35
|
* Browser guard — apiKey is server-side-only by default. Same check
|