@abloatai/ablo 0.6.0 → 0.7.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 +45 -0
- package/README.md +64 -35
- package/dist/BaseSyncedStore.d.ts +1 -1
- package/dist/BaseSyncedStore.js +1 -1
- package/dist/client/Ablo.d.ts +1 -0
- package/dist/client/Ablo.js +1 -0
- package/dist/client/createModelProxy.d.ts +26 -3
- package/dist/client/createModelProxy.js +4 -1
- package/dist/client/validateAbloOptions.js +2 -2
- package/dist/coordination/index.d.ts +6 -0
- package/dist/coordination/index.js +6 -0
- package/dist/coordination/schema.d.ts +329 -0
- package/dist/coordination/schema.js +209 -0
- package/dist/core/QueryView.d.ts +4 -1
- package/dist/core/QueryView.js +1 -1
- package/dist/core/query-utils.d.ts +7 -10
- package/dist/core/query-utils.js +2 -3
- package/dist/errorCodes.d.ts +264 -0
- package/dist/errorCodes.js +251 -0
- package/dist/errors.d.ts +51 -6
- package/dist/errors.js +56 -3
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -2
- package/dist/policy/index.d.ts +1 -1
- package/dist/policy/index.js +1 -1
- package/dist/policy/types.d.ts +31 -0
- package/dist/policy/types.js +15 -0
- package/dist/react/AbloProvider.d.ts +12 -0
- package/dist/react/AbloProvider.js +11 -3
- package/dist/schema/ddl.d.ts +62 -0
- package/dist/schema/ddl.js +317 -0
- package/dist/schema/diff.d.ts +6 -0
- package/dist/schema/diff.js +21 -3
- package/dist/schema/field.d.ts +16 -19
- package/dist/schema/field.js +30 -17
- package/dist/schema/index.d.ts +7 -4
- package/dist/schema/index.js +9 -3
- package/dist/schema/model.d.ts +87 -25
- package/dist/schema/model.js +33 -3
- package/dist/schema/relation.d.ts +17 -0
- package/dist/schema/roles.d.ts +148 -0
- package/dist/schema/roles.js +149 -0
- package/dist/schema/schema.d.ts +2 -112
- package/dist/schema/schema.js +50 -62
- package/dist/schema/select.d.ts +25 -0
- package/dist/schema/select.js +55 -0
- package/dist/schema/serialize.d.ts +13 -9
- package/dist/schema/serialize.js +14 -10
- package/dist/schema/sugar.d.ts +20 -3
- package/dist/schema/sugar.js +5 -1
- package/dist/schema/tenancy.d.ts +66 -0
- package/dist/schema/tenancy.js +58 -0
- package/dist/sync/HydrationCoordinator.d.ts +2 -0
- package/dist/sync/HydrationCoordinator.js +23 -17
- package/dist/sync/createIntentStream.d.ts +2 -1
- package/dist/sync/createIntentStream.js +46 -1
- package/dist/sync/participants.js +5 -14
- package/dist/types/streams.d.ts +53 -33
- package/docs/api-keys.md +44 -0
- package/docs/api.md +11 -22
- package/docs/cli.md +212 -0
- package/docs/client-behavior.md +1 -1
- package/docs/coordination.md +61 -12
- package/docs/data-sources.md +2 -2
- package/docs/examples/existing-python-backend.md +3 -3
- package/docs/examples/scoped-agent.md +78 -0
- package/docs/guarantees.md +5 -2
- package/docs/identity.md +139 -68
- package/docs/index.md +6 -0
- package/docs/integration-guide.md +31 -35
- package/docs/interaction-model.md +3 -0
- package/docs/react.md +3 -3
- package/docs/roadmap.md +14 -2
- package/package.json +8 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,50 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.7.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Structured error contract, schema/migration engine, and a full `ablo` CLI.
|
|
8
|
+
- **Structured error contract across HTTP + WS planes.** A closed, canonical
|
|
9
|
+
error-code registry is now the `code` tier of a Stripe-style error model. A
|
|
10
|
+
single HTTP egress funnel converts every throw to a canonical
|
|
11
|
+
`{ type, code, message, doc_url, request_id, ...details }` envelope; the WS
|
|
12
|
+
plane narrows mutation/claim error codes to the same union.
|
|
13
|
+
- **Versioned contract + drift guard.** `ERROR_CONTRACT_VERSION` (date-based)
|
|
14
|
+
ships in `errors.json` and on the `Ablo-Version` response header, so consumers
|
|
15
|
+
detect contract changes without diffing docs. Generated `errors.mdx` /
|
|
16
|
+
`errors.json` plus a CI drift guard keep the docs, OpenAPI spec, and SDK from
|
|
17
|
+
silently diverging from the registry.
|
|
18
|
+
- **Always-on request correlation.** Every response carries a `req_…` request id
|
|
19
|
+
(honoring an inbound `x-request-id`), stamped into the envelope's `request_id`.
|
|
20
|
+
- **OpenAPI parity.** The stale `{ error, reason }` schema is replaced by the
|
|
21
|
+
canonical envelope plus a generated `ErrorCode` enum.
|
|
22
|
+
|
|
23
|
+
CLI + schema:
|
|
24
|
+
- **Schema diff + migration planning engine** (`generateProvisionPlan` /
|
|
25
|
+
`generateMigrationPlan` in `@abloatai/ablo/schema`) — pure diff, classify,
|
|
26
|
+
apply, and constant-value backfill for required-field migrations.
|
|
27
|
+
- **`ablo generate`** — emit TypeScript types from the pushed schema.
|
|
28
|
+
- **Full `ablo` CLI suite**, Stripe-CLI-shaped: `init`, `login` / `logout` /
|
|
29
|
+
`status`, `mode [test|live]`, `dev` (push schema to the test sandbox + watch),
|
|
30
|
+
`logs` (tail your scope's commit activity), and the data-source commands below.
|
|
31
|
+
Authentication is the OAuth 2.0 device flow; `login` provisions and stores a
|
|
32
|
+
test and a live key, and `mode` switches the active one.
|
|
33
|
+
- **Database-URL structure (bring-your-own-database).** The CLI is split by where
|
|
34
|
+
it writes:
|
|
35
|
+
- `ablo pull` / `ablo check` / `ablo migrate` operate on **your own
|
|
36
|
+
`DATABASE_URL`** — `pull` introspects it to emit `defineSchema(...)` from
|
|
37
|
+
existing tables (read-only, like `prisma db pull`), `check` verifies tables
|
|
38
|
+
fit the schema with no DDL, and `migrate` applies DDL to `DATABASE_URL`.
|
|
39
|
+
- `ablo schema push` / `ablo dev` target the **hosted** test/live sandbox; the
|
|
40
|
+
server diffs, migrates, and activates the uploaded schema. `dev` never
|
|
41
|
+
touches live data.
|
|
42
|
+
|
|
43
|
+
**BREAKING** — removed the legacy React hooks `useQuery` / `useOne` / `useMutate`
|
|
44
|
+
/ `useReader`. Use `useAblo()` + `ablo.<model>.*` instead. The `MutateActions`,
|
|
45
|
+
`ReaderActions`, and `ReaderFindOptions` types are still re-exported for callers
|
|
46
|
+
that referenced them.
|
|
47
|
+
|
|
3
48
|
## 0.6.0
|
|
4
49
|
|
|
5
50
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Ablo
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@abloatai/ablo)
|
|
4
|
+
[](./LICENSE)
|
|
5
|
+
[](#)
|
|
6
|
+
[](#keys--runtime)
|
|
7
|
+
|
|
3
8
|
Ablo is a typed sync engine for shared app state — the kind that humans,
|
|
4
9
|
server code, and AI agents all edit at once.
|
|
5
10
|
|
|
@@ -11,29 +16,46 @@ of who changed what.
|
|
|
11
16
|
schema -> ablo.<model>.create/retrieve/update/claim(...)
|
|
12
17
|
```
|
|
13
18
|
|
|
19
|
+
## Why Ablo
|
|
20
|
+
|
|
21
|
+
- **Real-time by default.** Every `create` / `update` / `delete` fans out
|
|
22
|
+
confirmed deltas to all subscribers — humans and agents — with no separate
|
|
23
|
+
"multiplayer mode" to switch on.
|
|
24
|
+
- **No silent clobbers.** Writes are guarded against stale reads, and `claim`
|
|
25
|
+
holds a row across a slow read → LLM → write gap so concurrent edits queue
|
|
26
|
+
instead of overwriting.
|
|
27
|
+
- **Built for agents.** See who's mid-edit (`claimState` / `queue`), coordinate a
|
|
28
|
+
fair line, and ship an `llms.txt` so coding agents integrate from the real API.
|
|
29
|
+
- **Typed end to end.** Your Zod schema produces typed model proxies
|
|
30
|
+
(`ablo.<model>.update(...)`), optimistic local reads, and reactive React hooks.
|
|
31
|
+
- **Bring your own auth and database.** Ablo scopes realtime data to *sync
|
|
32
|
+
groups* from your existing identity, and can leave your database as the source
|
|
33
|
+
of truth via a Data Source.
|
|
34
|
+
|
|
35
|
+
**Built for:** collaborative editors, AI agent workflows, internal tools, and any
|
|
36
|
+
app where multiple actors mutate shared state and everyone must see it live.
|
|
37
|
+
|
|
14
38
|
## Set up
|
|
15
39
|
|
|
16
40
|
```bash
|
|
17
41
|
npm install @abloatai/ablo
|
|
18
42
|
```
|
|
19
43
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
> `<AbloProvider>`, wire my first create / retrieve / update, and use `claim`
|
|
26
|
-
> for anything an agent edits across a slow step (read → LLM → write).
|
|
44
|
+
**Keys & runtime.** Ablo needs Node 22+ and TypeScript 5+. Grab an `sk_test_*`
|
|
45
|
+
key for a sandbox
|
|
46
|
+
(`export ABLO_API_KEY=sk_test_...`); keep keys in trusted server runtimes only.
|
|
47
|
+
In the browser, `<AbloProvider>` authenticates with the signed-in user's
|
|
48
|
+
session — never the raw key.
|
|
27
49
|
|
|
28
|
-
|
|
29
|
-
|
|
50
|
+
Then wire it by hand — the [Quick Start](#quick-start) below is the shape to
|
|
51
|
+
copy. For production (React, an existing backend, Data Source, agents), the
|
|
30
52
|
[Integration Guide](./docs/integration-guide.md) is the deeper map.
|
|
31
53
|
|
|
32
|
-
**
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
54
|
+
**Prefer to let an agent wire it?** The package ships an `llms.txt` — a precise
|
|
55
|
+
map of the API — so Claude Code or Cursor integrates from the real surface
|
|
56
|
+
instead of guessing:
|
|
57
|
+
|
|
58
|
+
> Read `node_modules/@abloatai/ablo/llms.txt`, then add an Ablo schema, a `<AbloProvider>`, and my first create / retrieve / update.
|
|
37
59
|
|
|
38
60
|
## Quick Start
|
|
39
61
|
|
|
@@ -87,23 +109,23 @@ reactive under `useAblo`/`subscribe`. `load(...)` fetches from the server when a
|
|
|
87
109
|
row may not be local yet.
|
|
88
110
|
|
|
89
111
|
```ts
|
|
90
|
-
ablo.weatherReports.retrieve('report_stockholm');
|
|
112
|
+
ablo.weatherReports.retrieve('report_stockholm');
|
|
91
113
|
|
|
92
|
-
// Synchronous, from the local cache → row[]
|
|
93
114
|
const pending = ablo.weatherReports.list({
|
|
94
|
-
where: { status: 'pending' },
|
|
115
|
+
where: { status: 'pending' },
|
|
95
116
|
orderBy: { location: 'asc' },
|
|
96
117
|
limit: 20,
|
|
97
118
|
});
|
|
98
119
|
|
|
99
|
-
// Server fetch → Promise<row[]>. 'complete' waits for the server; 'unknown'
|
|
100
|
-
// returns what's local now and refreshes in the background.
|
|
101
120
|
const ready = await ablo.weatherReports.load({
|
|
102
121
|
where: { status: 'ready' },
|
|
103
122
|
type: 'complete',
|
|
104
123
|
});
|
|
105
124
|
```
|
|
106
125
|
|
|
126
|
+
An array value in `where` means `IN`. On `load`, `type: 'complete'` waits for
|
|
127
|
+
the server; `'unknown'` returns what's local now and refreshes in the background.
|
|
128
|
+
|
|
107
129
|
## Writing
|
|
108
130
|
|
|
109
131
|
`create` / `update` apply optimistically and resolve to the row. Two options
|
|
@@ -128,30 +150,35 @@ meanwhile, or worse, acts on stale state. `claim` holds the row across that gap:
|
|
|
128
150
|
|
|
129
151
|
```ts
|
|
130
152
|
await ablo.weatherReports.claim('report_stockholm', async (report) => {
|
|
131
|
-
|
|
132
|
-
// so `report` is the current row, never a stale snapshot. Reads stay open by
|
|
133
|
-
// default; only acting-on-the-row serializes.
|
|
134
|
-
|
|
135
|
-
const forecast = await weatherAgent.getWeather(report.location); // slow LLM gap
|
|
153
|
+
const forecast = await weatherAgent.getWeather(report.location);
|
|
136
154
|
await ablo.weatherReports.update(report.id, { forecast, status: 'ready' });
|
|
137
|
-
});
|
|
155
|
+
});
|
|
138
156
|
```
|
|
139
157
|
|
|
158
|
+
If someone else holds the row, `claim()` waits in a fair queue, then re-reads —
|
|
159
|
+
so `report` is the current row, never a stale snapshot. Reads stay open by
|
|
160
|
+
default; only acting on the row serializes. The claim releases when the callback
|
|
161
|
+
returns or throws.
|
|
162
|
+
|
|
140
163
|
See who's mid-edit before you act — decide to wait, or skip:
|
|
141
164
|
|
|
142
165
|
```ts
|
|
143
|
-
ablo.weatherReports.claimState('report_stockholm');
|
|
144
|
-
ablo.weatherReports.queue('report_stockholm');
|
|
166
|
+
ablo.weatherReports.claimState('report_stockholm');
|
|
167
|
+
ablo.weatherReports.queue('report_stockholm');
|
|
145
168
|
|
|
146
169
|
await ablo.weatherReports.claim(id, async (report) => {
|
|
147
170
|
/* do the held work */
|
|
148
|
-
}, { wait: false });
|
|
171
|
+
}, { wait: false });
|
|
149
172
|
|
|
150
173
|
await ablo.weatherReports.claim(id, async (report) => {
|
|
151
174
|
/* do the held work */
|
|
152
|
-
}, { maxQueueDepth: 2 });
|
|
175
|
+
}, { maxQueueDepth: 2 });
|
|
153
176
|
```
|
|
154
177
|
|
|
178
|
+
`claimState` returns the holder (or `null`); `queue` returns the line waiting
|
|
179
|
+
behind it. `wait: false` skips rather than waiting when the row is held;
|
|
180
|
+
`maxQueueDepth: 2` bails when two or more are already ahead.
|
|
181
|
+
|
|
155
182
|
Default reads keep working while a row is claimed. Server reads that need claimed
|
|
156
183
|
semantics can opt in with `ifClaimed: 'return' | 'wait' | 'fail'`.
|
|
157
184
|
|
|
@@ -179,7 +206,7 @@ everything inside is live.
|
|
|
179
206
|
|
|
180
207
|
```tsx
|
|
181
208
|
import { AbloProvider, useAblo } from '@abloatai/ablo/react';
|
|
182
|
-
import { schema } from './ablo
|
|
209
|
+
import { schema } from './ablo/schema';
|
|
183
210
|
|
|
184
211
|
function App() {
|
|
185
212
|
return (
|
|
@@ -190,14 +217,11 @@ function App() {
|
|
|
190
217
|
}
|
|
191
218
|
|
|
192
219
|
function Report({ id }: { id: string }) {
|
|
193
|
-
// Reactive read: this re-renders whenever the row changes — whether you,
|
|
194
|
-
// a teammate, or an agent changed it.
|
|
195
220
|
const report = useAblo((ablo) => ablo.weatherReports.retrieve(id));
|
|
196
221
|
const ablo = useAblo();
|
|
197
222
|
|
|
198
223
|
if (!report) return null;
|
|
199
224
|
|
|
200
|
-
// Write: same method as the server example above. Optimistic; fans out.
|
|
201
225
|
return (
|
|
202
226
|
<button onClick={() => ablo?.weatherReports.update(id, { status: 'ready' })}>
|
|
203
227
|
{report.status}
|
|
@@ -206,6 +230,10 @@ function Report({ id }: { id: string }) {
|
|
|
206
230
|
}
|
|
207
231
|
```
|
|
208
232
|
|
|
233
|
+
The `useAblo(selector)` read re-renders whenever the row changes — whether you,
|
|
234
|
+
a teammate, or an agent changed it. The write is the same optimistic, fan-out
|
|
235
|
+
method as the server example above.
|
|
236
|
+
|
|
209
237
|
`<AbloProvider>` owns the connection — no API key in the browser. That's the
|
|
210
238
|
whole loop: read with `useAblo(selector)`, write with `ablo.<model>`, and every
|
|
211
239
|
other client (human or agent) on that row sees it in real time. See
|
|
@@ -226,8 +254,9 @@ the browser connects as an already-scoped participant — it never holds the key
|
|
|
226
254
|
and can't widen its own scope. Your schema's `identityRoles` map that identity
|
|
227
255
|
to sync-group strings.
|
|
228
256
|
|
|
257
|
+
`userId` / `teamIds` come from your auth, resolved server-side:
|
|
258
|
+
|
|
229
259
|
```tsx
|
|
230
|
-
// userId / teamIds come from YOUR auth, resolved server-side
|
|
231
260
|
<AbloProvider schema={schema} userId={user.id} teamIds={user.teamIds}>
|
|
232
261
|
<App />
|
|
233
262
|
</AbloProvider>
|
|
@@ -262,7 +291,7 @@ HTTP endpoint when a server-to-server caller needs to write without opening a
|
|
|
262
291
|
WebSocket:
|
|
263
292
|
|
|
264
293
|
```bash
|
|
265
|
-
curl https://api.
|
|
294
|
+
curl https://api.abloatai.com/v1/commits \
|
|
266
295
|
-H "Authorization: Bearer sk_test_..." \
|
|
267
296
|
-H "Content-Type: application/json" \
|
|
268
297
|
-d '{ "operations": [
|
|
@@ -662,7 +662,7 @@ export declare class BaseSyncedStore<TCollaboration extends EventMap<TCollaborat
|
|
|
662
662
|
*/
|
|
663
663
|
queryByClass(modelClass: ModelConstructor<Model>, options?: {
|
|
664
664
|
predicate?: (model: Model) => boolean;
|
|
665
|
-
|
|
665
|
+
state?: ModelScope;
|
|
666
666
|
orderBy?: keyof Model;
|
|
667
667
|
order?: 'asc' | 'desc';
|
|
668
668
|
limit?: number;
|
package/dist/BaseSyncedStore.js
CHANGED
|
@@ -1688,7 +1688,7 @@ export class BaseSyncedStore {
|
|
|
1688
1688
|
const modelName = this.objectPool.registry.getModelNameFromConstructor(modelClass);
|
|
1689
1689
|
if (!modelName)
|
|
1690
1690
|
return { data: [], total: 0, hasMore: false };
|
|
1691
|
-
let allModels = this.objectPool.getByType(modelClass, options?.
|
|
1691
|
+
let allModels = this.objectPool.getByType(modelClass, options?.state ?? ModelScope.live);
|
|
1692
1692
|
// Filter out pending deletes
|
|
1693
1693
|
allModels = allModels.filter((m) => !this.pendingDeletes.has(m.id));
|
|
1694
1694
|
// Apply predicate
|
package/dist/client/Ablo.d.ts
CHANGED
|
@@ -784,6 +784,7 @@ export declare namespace Ablo {
|
|
|
784
784
|
type ActiveIntent = _Streams.ActiveIntent;
|
|
785
785
|
type Claim = _Streams.Claim;
|
|
786
786
|
type IntentRejection = _Streams.IntentRejection;
|
|
787
|
+
type IntentLost = _Streams.IntentLost;
|
|
787
788
|
type Snapshot<TSchema extends _SchemaTypes.Schema = _SchemaTypes.Schema, K extends keyof TSchema['models'] = keyof TSchema['models']> = _Streams.Snapshot<TSchema, K>;
|
|
788
789
|
type Turn = import('./Ablo.js').Turn;
|
|
789
790
|
namespace Auth {
|
package/dist/client/Ablo.js
CHANGED
|
@@ -1211,6 +1211,7 @@ export function Ablo(options) {
|
|
|
1211
1211
|
entities: { [modelKey]: id },
|
|
1212
1212
|
}),
|
|
1213
1213
|
queue: (target) => publicIntents.queueFor({ type: target.model, id: target.id }),
|
|
1214
|
+
reorder: (target, order) => publicIntents.reorder({ type: target.model, id: target.id }, order),
|
|
1214
1215
|
observe: (target) => {
|
|
1215
1216
|
// The live intent stream only tracks *open* (active) claims;
|
|
1216
1217
|
// terminal states (committed / expired / canceled) drop out of
|
|
@@ -35,10 +35,12 @@ export interface ModelListOptions<T> {
|
|
|
35
35
|
};
|
|
36
36
|
limit?: number;
|
|
37
37
|
offset?: number;
|
|
38
|
-
/** Lifecycle
|
|
39
|
-
|
|
38
|
+
/** Lifecycle filter — `live` (default), `archived`, or `all`. Named `state`
|
|
39
|
+
* (GitHub's open/closed/all precedent) so it doesn't collide with the
|
|
40
|
+
* sync-group `scope`. */
|
|
41
|
+
state?: ModelListScope;
|
|
40
42
|
}
|
|
41
|
-
export type ModelCountOptions<T> = Pick<ModelListOptions<T>, 'where' | 'filter' | '
|
|
43
|
+
export type ModelCountOptions<T> = Pick<ModelListOptions<T>, 'where' | 'filter' | 'state'>;
|
|
42
44
|
export interface ModelLoadOptions<T> {
|
|
43
45
|
/**
|
|
44
46
|
* Filter for the lookup. Accepts:
|
|
@@ -109,6 +111,14 @@ export interface ModelCollaboration<T> {
|
|
|
109
111
|
model: string;
|
|
110
112
|
id: string;
|
|
111
113
|
}): readonly Intent[];
|
|
114
|
+
/**
|
|
115
|
+
* Re-rank the wait queue on a target (privileged — server-gated). `order` is
|
|
116
|
+
* the desired front-of-line ordering, taken from `queue(target)`.
|
|
117
|
+
*/
|
|
118
|
+
reorder(target: {
|
|
119
|
+
model: string;
|
|
120
|
+
id: string;
|
|
121
|
+
}, order: readonly Intent[]): void;
|
|
112
122
|
/**
|
|
113
123
|
* Resolve once no participant holds an active intent on the target.
|
|
114
124
|
* The contender's "wait until it's free" — delegates to the intent
|
|
@@ -226,6 +236,19 @@ export interface ModelOperations<T, CreateInput> {
|
|
|
226
236
|
readonly object: 'list';
|
|
227
237
|
readonly data: readonly Intent[];
|
|
228
238
|
};
|
|
239
|
+
/**
|
|
240
|
+
* Re-rank the wait queue on a record — move waiters to the front in the
|
|
241
|
+
* given order. Pass the `Intent[]` from `queue(id).data`, reordered. A
|
|
242
|
+
* privileged operation: the server gates it (the caller needs the
|
|
243
|
+
* `intent.reorder` capability), so it's fire-and-forget — the new order
|
|
244
|
+
* arrives reactively through `queue(id)`.
|
|
245
|
+
*
|
|
246
|
+
* ```ts
|
|
247
|
+
* const { data } = ablo.decks.queue('deck_1');
|
|
248
|
+
* ablo.decks.reorder('deck_1', [data[2], data[0], data[1]]); // promote #2
|
|
249
|
+
* ```
|
|
250
|
+
*/
|
|
251
|
+
reorder(id: string, order: readonly Intent[]): void;
|
|
229
252
|
/** Release a claim you hold early. Usually implicit (scope exit). */
|
|
230
253
|
release(id: string): Promise<void>;
|
|
231
254
|
/** Listen for changes (callback called on every change). */
|
|
@@ -134,7 +134,7 @@ export function createModelProxy(schemaKey, registeredModelName, objectPool, syn
|
|
|
134
134
|
return objectPool.get(id);
|
|
135
135
|
},
|
|
136
136
|
list(options) {
|
|
137
|
-
const all = objectPool.getByType(ModelClass, (options?.
|
|
137
|
+
const all = objectPool.getByType(ModelClass, (options?.state ?? ModelScope.live));
|
|
138
138
|
let result = all;
|
|
139
139
|
if (options?.where) {
|
|
140
140
|
const where = options.where;
|
|
@@ -220,6 +220,9 @@ export function createModelProxy(schemaKey, registeredModelName, objectPool, syn
|
|
|
220
220
|
data: collaboration?.queue({ model: schemaKey, id }) ?? [],
|
|
221
221
|
};
|
|
222
222
|
},
|
|
223
|
+
reorder(id, order) {
|
|
224
|
+
collaboration?.reorder({ model: schemaKey, id }, order);
|
|
225
|
+
},
|
|
223
226
|
release(id) {
|
|
224
227
|
return releaseClaim(id);
|
|
225
228
|
},
|
|
@@ -15,7 +15,7 @@ export function validateAbloOptions(input) {
|
|
|
15
15
|
const kind = options.kind ?? 'user';
|
|
16
16
|
if (!url) {
|
|
17
17
|
return new Error('Ablo: `url` is required. Pass the sync server URL, e.g. ' +
|
|
18
|
-
`Ablo({ baseURL: 'wss://sync.
|
|
18
|
+
`Ablo({ baseURL: 'wss://sync.abloatai.com', schema, user })`);
|
|
19
19
|
}
|
|
20
20
|
// Schema is optional for the model-first API:
|
|
21
21
|
// Ablo({ apiKey }).model('clauses').retrieve(...)
|
|
@@ -37,7 +37,7 @@ export function validateAbloOptions(input) {
|
|
|
37
37
|
if (!configuredApiKey && !configuredAuthToken && kind === 'agent' && !options.capabilityToken) {
|
|
38
38
|
return new Error('Ablo: provide either `apiKey` (hosted cloud — SDK exchanges internally) ' +
|
|
39
39
|
'or `capabilityToken` (self-hosted — your auth layer mints + hands in). ' +
|
|
40
|
-
'See https://
|
|
40
|
+
'See https://abloatai.com/docs/api-keys for the full pattern.');
|
|
41
41
|
}
|
|
42
42
|
return null;
|
|
43
43
|
}
|