@abloatai/ablo 0.3.0 → 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.
Files changed (97) hide show
  1. package/CHANGELOG.md +43 -5
  2. package/NOTICE +2 -2
  3. package/README.md +30 -28
  4. package/dist/agent/Agent.d.ts +1 -1
  5. package/dist/agent/Agent.js +1 -1
  6. package/dist/agent/index.d.ts +4 -4
  7. package/dist/agent/index.js +6 -6
  8. package/dist/agent/types.d.ts +1 -1
  9. package/dist/ai-sdk/index.d.ts +3 -3
  10. package/dist/ai-sdk/index.js +3 -3
  11. package/dist/ai-sdk/intent-broadcast.d.ts +1 -1
  12. package/dist/ai-sdk/intent-broadcast.js +1 -1
  13. package/dist/auth/index.d.ts +1 -1
  14. package/dist/client/Ablo.d.ts +8 -14
  15. package/dist/client/Ablo.js +32 -1
  16. package/dist/client/auth.d.ts +3 -3
  17. package/dist/client/auth.js +5 -5
  18. package/dist/client/createModelProxy.d.ts +110 -32
  19. package/dist/client/createModelProxy.js +77 -38
  20. package/dist/client/index.d.ts +2 -2
  21. package/dist/client/index.js +2 -2
  22. package/dist/config/index.d.ts +1 -1
  23. package/dist/config/index.js +1 -1
  24. package/dist/core/index.d.ts +1 -1
  25. package/dist/core/index.js +2 -2
  26. package/dist/errors.d.ts +1 -1
  27. package/dist/errors.js +1 -1
  28. package/dist/index.d.ts +6 -6
  29. package/dist/index.js +9 -9
  30. package/dist/interfaces/headless.d.ts +1 -1
  31. package/dist/interfaces/headless.js +2 -2
  32. package/dist/policy/index.d.ts +2 -2
  33. package/dist/policy/index.js +2 -2
  34. package/dist/principal.d.ts +1 -1
  35. package/dist/principal.js +1 -1
  36. package/dist/react/ClientSideSuspense.d.ts +1 -1
  37. package/dist/react/SyncGroupProvider.js +1 -1
  38. package/dist/react/context.d.ts +1 -1
  39. package/dist/react/context.js +1 -1
  40. package/dist/react/index.d.ts +1 -1
  41. package/dist/react/index.js +1 -1
  42. package/dist/react/useCurrentUserId.js +1 -1
  43. package/dist/react/useErrorListener.js +1 -1
  44. package/dist/react/useMutate.d.ts +1 -1
  45. package/dist/react/useMutationFailureListener.js +1 -1
  46. package/dist/react/useReader.d.ts +1 -1
  47. package/dist/schema/field.d.ts +1 -1
  48. package/dist/schema/field.js +1 -1
  49. package/dist/schema/index.d.ts +2 -2
  50. package/dist/schema/index.js +2 -2
  51. package/dist/schema/model.d.ts +2 -2
  52. package/dist/schema/model.js +2 -2
  53. package/dist/schema/queries.d.ts +1 -1
  54. package/dist/schema/queries.js +1 -1
  55. package/dist/schema/relation.d.ts +1 -1
  56. package/dist/schema/relation.js +1 -1
  57. package/dist/schema/schema.d.ts +1 -1
  58. package/dist/schema/schema.js +1 -1
  59. package/dist/source/index.d.ts +22 -28
  60. package/dist/source/index.js +23 -20
  61. package/dist/source/pushQueue.d.ts +1 -1
  62. package/dist/source/pushQueue.js +2 -2
  63. package/dist/sync/SyncWebSocket.d.ts +14 -0
  64. package/dist/sync/createIntentStream.js +7 -0
  65. package/dist/testing/fixtures/models.d.ts +1 -1
  66. package/dist/testing/fixtures/models.js +1 -1
  67. package/dist/testing/helpers/react-wrapper.d.ts +2 -2
  68. package/dist/testing/helpers/react-wrapper.js +2 -2
  69. package/dist/testing/index.d.ts +1 -1
  70. package/dist/testing/index.js +1 -1
  71. package/dist/types/streams.d.ts +39 -0
  72. package/docs/api-keys.md +2 -2
  73. package/docs/api.md +81 -23
  74. package/docs/capabilities.md +1 -1
  75. package/docs/client-behavior.md +7 -7
  76. package/docs/data-sources.md +52 -18
  77. package/docs/examples/agent-human.md +3 -3
  78. package/docs/examples/ai-sdk-tool.md +16 -33
  79. package/docs/examples/existing-python-backend.md +10 -10
  80. package/docs/examples/nextjs.md +1 -1
  81. package/docs/examples/server-agent.md +2 -2
  82. package/docs/index.md +1 -1
  83. package/docs/integration-guide.md +15 -14
  84. package/docs/interaction-model.md +16 -4
  85. package/docs/mcp.md +1 -1
  86. package/docs/quickstart.md +23 -21
  87. package/docs/react.md +3 -3
  88. package/docs/roadmap.md +1 -1
  89. package/examples/README.md +3 -3
  90. package/examples/data-source/README.md +1 -1
  91. package/examples/data-source/ablo-driver.ts +5 -5
  92. package/examples/data-source/customer-server.ts +10 -10
  93. package/examples/data-source/run.ts +9 -11
  94. package/examples/data-source/schema.ts +1 -1
  95. package/examples/quickstart.ts +2 -2
  96. package/llms.txt +8 -8
  97. package/package.json +1 -1
@@ -9,7 +9,7 @@ Ablo-managed state versus a Data Source that calls your existing API service.
9
9
  ## 1. Install
10
10
 
11
11
  ```bash
12
- npm install @ablo/sync-engine
12
+ npm install @abloatai/ablo
13
13
  ```
14
14
 
15
15
  ## 2. Set a Sandbox Key
@@ -26,8 +26,8 @@ provider with a scoped capability/session route, not a bundled API key.
26
26
  ## 3. Declare a Schema
27
27
 
28
28
  ```ts
29
- import Ablo from '@ablo/sync-engine';
30
- import { defineSchema, model, z } from '@ablo/sync-engine/schema';
29
+ import Ablo from '@abloatai/ablo';
30
+ import { defineSchema, model, z } from '@abloatai/ablo/schema';
31
31
 
32
32
  const schema = defineSchema({
33
33
  weatherReports: model({
@@ -43,8 +43,9 @@ export const ablo = Ablo({
43
43
  });
44
44
  ```
45
45
 
46
- Pass `schema` for typed model resources. Omit it only for advanced server-side
47
- resource clients such as custom agents and MCP routes.
46
+ Customer apps should always pass `schema`. Treat it like Prisma's schema file:
47
+ it is the source of truth for typed model resources, realtime subscriptions,
48
+ agent writes, and Data Source requests.
48
49
 
49
50
  ## 4. Create and Update
50
51
 
@@ -79,33 +80,34 @@ ABLO_API_KEY=sk_test_... npx tsx quickstart.ts
79
80
 
80
81
  ## 6. AI Activity on Existing State
81
82
 
82
- Use `edit` when AI or background work will touch an existing row for more than a
83
- quick write. Other participants can see the activity while your code runs. The
84
- activity is cleared when `update` finishes; call `release` if the work ends
85
- without a write.
83
+ When AI or background work will touch an existing row for more than a quick
84
+ write, coordinate through `ablo.<model>.intent(id)`. It returns a handle
85
+ synchronously read `.current` to see who's working on the row, `acquire()` to
86
+ claim it, `update()` to write under the claim (which auto-releases).
86
87
 
87
88
  ```ts
88
- const edit = await ablo.weatherReports.edit('weather_stockholm', {
89
- activity: 'checking_weather',
90
- field: 'forecast',
91
- ttl: '2m',
92
- });
89
+ const report = ablo.weatherReports.intent('weather_stockholm');
90
+
91
+ // If another participant holds it, wait for them to finish.
92
+ if (report.current) await report.settled();
93
+
94
+ // Claim it so other participants yield while we work.
95
+ await report.acquire({ action: 'checking_weather', field: 'forecast', ttl: '2m' });
93
96
 
94
97
  // Your existing weather tool or agent call. While this runs, other clients see
95
98
  // that weather_stockholm is being checked.
96
- const weather = await weatherAgent.getWeather(edit.current.location, {
97
- signal: edit.signal,
98
- });
99
+ const row = ablo.weatherReports.retrieve('weather_stockholm');
100
+ const weather = await weatherAgent.getWeather(row.location);
99
101
 
100
- await edit.update({
102
+ await report.update({
101
103
  status: 'ready',
102
104
  forecast: weather.summary,
103
105
  });
104
106
  ```
105
107
 
106
- Ablo does not fetch the weather. It keeps the activity visible, gives the agent
107
- call an abort signal if the row changes, and clears the activity when
108
- `edit.update(...)` finishes.
108
+ Ablo does not fetch the weather. It keeps the activity visible while the work
109
+ runs, rejects `report.update(...)` with `AbloStaleContextError` if the row
110
+ changed under you, and releases the intent automatically once the write lands.
109
111
 
110
112
  ## 7. Multiplayer and Busy Work
111
113
 
package/docs/react.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # React
2
2
 
3
- The React bindings for `@ablo/sync-engine`. Use them when you want live
3
+ The React bindings for `@abloatai/ablo`. Use them when you want live
4
4
  data on the client without writing fetch + WebSocket plumbing yourself.
5
5
 
6
6
  For the full app structure, including server loads, existing backends, and
@@ -11,7 +11,7 @@ agents, start with [Integration Guide](/docs/integration-guide).
11
11
  The React bindings ship with the main package — no extra install.
12
12
 
13
13
  ```ts
14
- import { useAblo } from '@ablo/sync-engine/react';
14
+ import { useAblo } from '@abloatai/ablo/react';
15
15
  ```
16
16
 
17
17
  ## useAblo — model resource
@@ -19,7 +19,7 @@ import { useAblo } from '@ablo/sync-engine/react';
19
19
  ```tsx
20
20
  'use client';
21
21
 
22
- import { useAblo } from '@ablo/sync-engine/react';
22
+ import { useAblo } from '@abloatai/ablo/react';
23
23
 
24
24
  export function TaskView({ task: serverTask }: { task: { id: string; title: string } }) {
25
25
  const task = useAblo((ablo) => ablo.tasks.retrieve(serverTask.id)) ?? serverTask;
package/docs/roadmap.md CHANGED
@@ -8,7 +8,7 @@ What is shipped, what is next, and what we will not build.
8
8
  - **Capability tokens** — Biscuit-signed, scoped, attenuable, hot-revocable.
9
9
  - **Audit log** — hash-chained per principal, with `delegationChainRoot`.
10
10
  - **MCP transport** — HTTP server at `/api/mcp`.
11
- - **TypeScript SDK** — `@ablo/sync-engine`, with React bindings.
11
+ - **TypeScript SDK** — `@abloatai/ablo`, with React bindings.
12
12
  - **Dashboard** — keys, audit, metrics, allowed origins.
13
13
 
14
14
  ## In flight
@@ -1,11 +1,11 @@
1
- # @ablo/sync-engine Examples
1
+ # @abloatai/ablo Examples
2
2
 
3
3
  The examples teach the same path as the README and docs: declare a schema,
4
4
  create or load typed models, and write through `ablo.<model>`.
5
5
 
6
6
  ```ts
7
- import Ablo from '@ablo/sync-engine';
8
- import { defineSchema, model, z } from '@ablo/sync-engine/schema';
7
+ import Ablo from '@abloatai/ablo';
8
+ import { defineSchema, model, z } from '@abloatai/ablo/schema';
9
9
 
10
10
  const schema = defineSchema({
11
11
  weatherReports: model({
@@ -22,7 +22,7 @@ npx tsx data-source/run.ts
22
22
 
23
23
  No network port, no env vars, no cloud credentials. The orchestrator
24
24
  calls the handler in-process. Signer and verifier still exchange
25
- signed bytes — flip the secret and you'll see a 401.
25
+ signed bytes — flip the API key and you'll see a 401.
26
26
 
27
27
  ## What it proves
28
28
 
@@ -7,7 +7,7 @@
7
7
  * locally without standing up the cloud.
8
8
  *
9
9
  * In production:
10
- * - Ablo Cloud holds the signing secret in its config
10
+ * - Ablo Cloud holds the API key in its config
11
11
  * - It signs each outbound POST with `signAbloSourceRequest`
12
12
  * - The customer's `dataSource(...)` handler verifies the signature
13
13
  * - The response feeds back into Ablo Cloud's hosted realtime layer
@@ -19,7 +19,7 @@
19
19
  import {
20
20
  signAbloSourceRequest,
21
21
  type Ablo,
22
- } from '@ablo/sync-engine';
22
+ } from '@abloatai/ablo';
23
23
 
24
24
  export interface AbloDriverOptions {
25
25
  /**
@@ -27,8 +27,8 @@ export interface AbloDriverOptions {
27
27
  * the handler directly so there's no http port to manage.
28
28
  */
29
29
  readonly handler: (request: Request) => Promise<Response>;
30
- /** Same secret the customer's `dataSource(...)` is configured with. */
31
- readonly signingSecret: string;
30
+ /** Same API key the customer's `dataSource(...)` is configured with. */
31
+ readonly apiKey: string;
32
32
  }
33
33
 
34
34
  export class AbloDriver {
@@ -68,7 +68,7 @@ export class AbloDriver {
68
68
  const body = JSON.stringify(payload);
69
69
  const messageId = `msg_${Date.now()}_${this.messageCounter}`;
70
70
  const signed = await signAbloSourceRequest({
71
- secret: this.options.signingSecret,
71
+ apiKey: this.options.apiKey,
72
72
  body,
73
73
  messageId,
74
74
  });
@@ -15,7 +15,7 @@
15
15
  * inside a transaction. The shape of the handlers stays identical.
16
16
  */
17
17
 
18
- import Ablo, { dataSource } from '@ablo/sync-engine';
18
+ import Ablo, { dataSource } from '@abloatai/ablo';
19
19
  import { schema } from './schema';
20
20
 
21
21
  type TaskRow = {
@@ -68,20 +68,20 @@ taskStore.set('task_seed', {
68
68
  export const handleAbloSource = dataSource({
69
69
  schema,
70
70
 
71
- // The signing secret pairs with what Ablo Cloud is configured with.
72
- // Wrong secret -> 401 with `source_signature_invalid`. Passing a
73
- // function (instead of the env value directly) re-reads the secret
74
- // on every request convenient for rotation, and required by the
71
+ // The API key pairs with what Ablo Cloud is configured with.
72
+ // Wrong key -> 401 with `source_signature_invalid`. Passing a
73
+ // function (instead of the env value directly) re-reads the key
74
+ // on every request and is required by the
75
75
  // example because `run.ts` configures the env after this module is
76
76
  // imported.
77
- signingSecret: () => {
78
- const secret = process.env.ABLO_DATA_SOURCE_SIGNING_SECRET;
79
- if (!secret) {
77
+ apiKey: () => {
78
+ const apiKey = process.env.ABLO_API_KEY;
79
+ if (!apiKey) {
80
80
  throw new Error(
81
- 'ABLO_DATA_SOURCE_SIGNING_SECRET is not set — refusing to accept unsigned requests',
81
+ 'ABLO_API_KEY is not set — refusing to accept unsigned requests',
82
82
  );
83
83
  }
84
- return secret;
84
+ return apiKey;
85
85
  },
86
86
 
87
87
  // `authorize` runs before any handler. Use it to map the signed
@@ -9,7 +9,7 @@
9
9
  * What this proves:
10
10
  *
11
11
  * 1. Ablo Cloud's signer + the customer's verifier interop. A wrong
12
- * secret produces `source_signature_invalid`.
12
+ * API key produces `source_signature_invalid`.
13
13
  * 2. `load`, `list`, `commit`, and `events` all flow through the
14
14
  * same Fetch-API handler.
15
15
  * 3. The customer's "database" (here a Map) holds canonical rows.
@@ -21,19 +21,17 @@
21
21
  import { handleAbloSource, _inspectStore } from './customer-server';
22
22
  import { AbloDriver } from './ablo-driver';
23
23
 
24
- const SIGNING_SECRET =
25
- process.env.ABLO_DATA_SOURCE_SIGNING_SECRET ?? 'whsec_example_secret_do_not_use_in_prod';
24
+ const API_KEY =
25
+ process.env.ABLO_API_KEY ?? 'sk_test_example_key_do_not_use_in_prod';
26
26
 
27
- // `dataSource()` reads `options.signingSecret` at construction; we
28
- // re-export the same value to the driver so signer and verifier agree.
29
- // In production this is one secret shared between Ablo Cloud config
30
- // and the customer's environment.
31
- process.env.ABLO_DATA_SOURCE_SIGNING_SECRET = SIGNING_SECRET;
27
+ // `dataSource()` reads `options.apiKey` at request time; we re-export
28
+ // the same value to the driver so signer and verifier agree.
29
+ process.env.ABLO_API_KEY = API_KEY;
32
30
 
33
31
  async function main() {
34
32
  const driver = new AbloDriver({
35
33
  handler: handleAbloSource,
36
- signingSecret: SIGNING_SECRET,
34
+ apiKey: API_KEY,
37
35
  });
38
36
 
39
37
  log('--- 1. load (existing seeded row) ---');
@@ -68,10 +66,10 @@ async function main() {
68
66
  const events = await driver.events();
69
67
  log('events:', events);
70
68
 
71
- log('\n--- 5. signature failure (wrong secret) ---');
69
+ log('\n--- 5. signature failure (wrong API key) ---');
72
70
  const badDriver = new AbloDriver({
73
71
  handler: handleAbloSource,
74
- signingSecret: 'whsec_wrong_secret',
72
+ apiKey: 'sk_test_wrong_key',
75
73
  });
76
74
  try {
77
75
  await badDriver.load('tasks', 'task_seed');
@@ -12,7 +12,7 @@
12
12
  * side without the other is a compile error.
13
13
  */
14
14
 
15
- import { defineSchema, model, z } from '@ablo/sync-engine/schema';
15
+ import { defineSchema, model, z } from '@abloatai/ablo/schema';
16
16
 
17
17
  export const schema = defineSchema({
18
18
  tasks: model({
@@ -6,8 +6,8 @@
6
6
  * ABLO_API_KEY=sk_test_... npx tsx quickstart.ts
7
7
  */
8
8
 
9
- import Ablo from '@ablo/sync-engine';
10
- import { defineSchema, model, z } from '@ablo/sync-engine/schema';
9
+ import Ablo from '@abloatai/ablo';
10
+ import { defineSchema, model, z } from '@abloatai/ablo/schema';
11
11
 
12
12
  const schema = defineSchema({
13
13
  weatherReports: model({
package/llms.txt CHANGED
@@ -7,8 +7,8 @@ Use AI SDK for the agent loop. Use Ablo when agent reads and writes must persist
7
7
  ## Use this API
8
8
 
9
9
  ```ts
10
- import Ablo from '@ablo/sync-engine';
11
- import { defineSchema, model, z } from '@ablo/sync-engine/schema';
10
+ import Ablo from '@abloatai/ablo';
11
+ import { defineSchema, model, z } from '@abloatai/ablo/schema';
12
12
 
13
13
  const schema = defineSchema({
14
14
  tasks: model({
@@ -103,12 +103,12 @@ Teach schema as model fields and relations first. Advanced schema helpers such a
103
103
 
104
104
  Do not add `databaseURL` to `Ablo(...)`. Application and agent code use `ABLO_API_KEY`.
105
105
 
106
- Every schema model has a backing store. By default, Ablo stores rows for declared models, so `ablo.<model>.create/update/delete` write to Ablo-managed state. If the customer database is canonical, add a Data Source URL in Ablo, store `ABLO_DATA_SOURCE_SIGNING_SECRET` in the app, then expose a signed `dataSource({ schema, signingSecret, load, list, commit, events })` route from the customer app. Customer-owned app database credentials stay private.
106
+ Every schema model has a backing store. By default, Ablo stores rows for declared models, so `ablo.<model>.create/update/delete` write to Ablo-managed state. If the customer database is canonical, expose a Data Source endpoint and pass `apiKey: process.env.ABLO_API_KEY` to `dataSource({ schema, apiKey, load, list, commit, events })`. Customer-owned app database credentials stay private.
107
107
 
108
108
  Use `dataSource` from the root import:
109
109
 
110
110
  ```ts
111
- import { dataSource } from '@ablo/sync-engine';
111
+ import { dataSource } from '@abloatai/ablo';
112
112
  ```
113
113
 
114
114
  ## Sandboxes
@@ -133,10 +133,10 @@ two-writer stale/intent smoke test.
133
133
 
134
134
  Import from these public paths only:
135
135
 
136
- - `@ablo/sync-engine` — `Ablo`, errors, typed model resources, intents, `dataSource`, and advanced protocol resources.
137
- - `@ablo/sync-engine/schema` — schema DSL.
138
- - `@ablo/sync-engine/react` — React provider and hooks.
139
- - `@ablo/sync-engine/testing` — test harnesses and mocks.
136
+ - `@abloatai/ablo` — `Ablo`, errors, typed model resources, intents, `dataSource`, and advanced protocol resources.
137
+ - `@abloatai/ablo/schema` — schema DSL.
138
+ - `@abloatai/ablo/react` — React provider and hooks.
139
+ - `@abloatai/ablo/testing` — test harnesses and mocks.
140
140
 
141
141
  Do not teach `/api`, `/agent`, `/ai-sdk`, `/core`, `/realtime`, `/source`, or internal subpaths.
142
142
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abloatai/ablo",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "State control API for AI agents and collaborative apps.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",