@abloatai/ablo 0.3.1 → 0.5.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 (92) hide show
  1. package/CHANGELOG.md +54 -1
  2. package/NOTICE +2 -2
  3. package/README.md +99 -78
  4. package/dist/BaseSyncedStore.d.ts +3 -2
  5. package/dist/agent/Agent.d.ts +1 -1
  6. package/dist/agent/Agent.js +1 -1
  7. package/dist/agent/index.d.ts +4 -4
  8. package/dist/agent/index.js +6 -6
  9. package/dist/agent/types.d.ts +1 -1
  10. package/dist/ai-sdk/index.d.ts +3 -3
  11. package/dist/ai-sdk/index.js +3 -3
  12. package/dist/ai-sdk/intent-broadcast.d.ts +1 -1
  13. package/dist/ai-sdk/intent-broadcast.js +1 -1
  14. package/dist/auth/index.d.ts +1 -1
  15. package/dist/client/Ablo.d.ts +53 -27
  16. package/dist/client/Ablo.js +32 -1
  17. package/dist/client/auth.d.ts +3 -3
  18. package/dist/client/auth.js +5 -5
  19. package/dist/client/createModelProxy.d.ts +118 -32
  20. package/dist/client/createModelProxy.js +87 -44
  21. package/dist/client/index.d.ts +3 -3
  22. package/dist/client/index.js +3 -3
  23. package/dist/config/index.d.ts +1 -1
  24. package/dist/config/index.js +1 -1
  25. package/dist/core/index.d.ts +1 -1
  26. package/dist/core/index.js +2 -2
  27. package/dist/errors.d.ts +9 -7
  28. package/dist/errors.js +9 -7
  29. package/dist/index.d.ts +20 -6
  30. package/dist/index.js +41 -22
  31. package/dist/interfaces/headless.d.ts +1 -1
  32. package/dist/interfaces/headless.js +2 -2
  33. package/dist/policy/index.d.ts +2 -2
  34. package/dist/policy/index.js +2 -2
  35. package/dist/policy/types.d.ts +10 -0
  36. package/dist/principal.d.ts +3 -3
  37. package/dist/principal.js +3 -3
  38. package/dist/query/client.d.ts +7 -6
  39. package/dist/react/AbloProvider.d.ts +44 -1
  40. package/dist/react/AbloProvider.js +3 -1
  41. package/dist/react/ClientSideSuspense.d.ts +1 -1
  42. package/dist/react/SyncGroupProvider.js +1 -1
  43. package/dist/react/context.d.ts +1 -1
  44. package/dist/react/context.js +1 -1
  45. package/dist/react/index.d.ts +1 -1
  46. package/dist/react/index.js +1 -1
  47. package/dist/react/useCurrentUserId.js +1 -1
  48. package/dist/react/useErrorListener.js +1 -1
  49. package/dist/react/useMutate.d.ts +1 -1
  50. package/dist/react/useMutationFailureListener.js +1 -1
  51. package/dist/react/useReader.d.ts +1 -1
  52. package/dist/schema/field.d.ts +1 -1
  53. package/dist/schema/field.js +1 -1
  54. package/dist/schema/index.d.ts +2 -2
  55. package/dist/schema/index.js +2 -2
  56. package/dist/schema/model.d.ts +2 -2
  57. package/dist/schema/model.js +2 -2
  58. package/dist/schema/queries.d.ts +1 -1
  59. package/dist/schema/queries.js +1 -1
  60. package/dist/schema/relation.d.ts +1 -1
  61. package/dist/schema/relation.js +1 -1
  62. package/dist/schema/schema.d.ts +1 -1
  63. package/dist/schema/schema.js +1 -1
  64. package/dist/source/index.d.ts +22 -28
  65. package/dist/source/index.js +23 -20
  66. package/dist/source/pushQueue.d.ts +1 -1
  67. package/dist/source/pushQueue.js +2 -2
  68. package/dist/sync/SyncWebSocket.d.ts +20 -5
  69. package/dist/sync/createIntentStream.js +7 -0
  70. package/dist/testing/fixtures/models.d.ts +1 -1
  71. package/dist/testing/fixtures/models.js +1 -1
  72. package/dist/testing/helpers/react-wrapper.d.ts +2 -2
  73. package/dist/testing/helpers/react-wrapper.js +2 -2
  74. package/dist/testing/index.d.ts +1 -1
  75. package/dist/testing/index.js +1 -1
  76. package/dist/types/streams.d.ts +41 -1
  77. package/docs/api.md +78 -20
  78. package/docs/data-sources.md +50 -16
  79. package/docs/examples/ai-sdk-tool.md +14 -31
  80. package/docs/examples/existing-python-backend.md +6 -6
  81. package/docs/integration-guide.md +8 -7
  82. package/docs/interaction-model.md +16 -4
  83. package/docs/mcp.md +1 -1
  84. package/docs/quickstart.md +20 -18
  85. package/examples/data-source/README.md +1 -1
  86. package/examples/data-source/ablo-driver.ts +5 -5
  87. package/examples/data-source/customer-server.ts +10 -10
  88. package/examples/data-source/run.ts +9 -11
  89. package/examples/data-source/schema.ts +1 -1
  90. package/examples/quickstart.ts +2 -2
  91. package/llms.txt +1 -1
  92. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @ablo/sync-engine/config — App initialization
2
+ * @abloatai/ablo/config — App initialization
3
3
  *
4
4
  * One-time setup at app boot. Provides DI interface types
5
5
  * and the initSyncEngine() function to wire real implementations.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @ablo/sync-engine-internal/core — Framework extension
2
+ * @abloatai/ablo/core — Framework extension
3
3
  *
4
4
  * Only imported by SyncedStore.ts and ApplicationStore.ts —
5
5
  * the 2-3 files that extend or orchestrate the sync engine.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @ablo/sync-engine-internal/core — Framework extension
2
+ * @abloatai/ablo/core — Framework extension
3
3
  *
4
4
  * Only imported by SyncedStore.ts and ApplicationStore.ts —
5
5
  * the 2-3 files that extend or orchestrate the sync engine.
@@ -13,7 +13,7 @@ export { Database } from '../Database.js';
13
13
  export { ObjectPool, ModelScope } from '../ObjectPool.js';
14
14
  export { Model } from '../Model.js';
15
15
  export { LazyReferenceCollection } from '../LazyReferenceCollection.js';
16
- // Undo runtime — `useUndoScope` hook from `@ablo/sync-engine/react` is
16
+ // Undo runtime — `useUndoScope` hook from `@abloatai/ablo/react` is
17
17
  // the canonical access path. Type counterparts (`Ablo.Mutator.UndoScope`,
18
18
  // `Ablo.Mutator.UndoEntry`, `Ablo.Mutator.InverseOp`) live on the main `Ablo`
19
19
  // namespace. Direct class access (tests, non-React hosts) imports via
package/dist/errors.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Typed error hierarchy for `@ablo/sync-engine`.
2
+ * Typed error hierarchy for `@abloatai/ablo`.
3
3
  *
4
4
  * Inlined directly so the publishable dist is self-contained. The public
5
5
  * package should never reference an unpublished internal package from emitted
@@ -186,16 +186,18 @@ export interface CommitReceipt {
186
186
  };
187
187
  }
188
188
  /**
189
- * Biscuit capability token failed verification — either it's
190
- * malformed / unknown / revoked (`capability_invalid`), or its
191
- * caveats deny the attempted action (`capability_scope_denied`).
189
+ * A scoped credential was denied — either the key is unknown / revoked /
190
+ * expired (`capability_invalid`), or the connection's resolved scope
191
+ * doesn't cover the attempted action (`capability_scope_denied`). With
192
+ * opaque restricted (`rk_`) API keys this is a server-side check against
193
+ * the key's `syncGroups` / `operations`, not a signed-caveat verification.
192
194
  *
193
195
  * Extends `AbloPermissionError` so existing `instanceof CapabilityError`
194
196
  * checks keep working AND broader `instanceof AbloPermissionError`
195
- * matches for consumers who don't care about the Biscuit specifics.
197
+ * matches for consumers who don't care about the scope specifics.
196
198
  *
197
- * `requiredCapability` (when present) describes what an attenuated
198
- * capability must satisfy for the request to succeed on retry.
199
+ * `requiredCapability` (when present) describes the scope a key must
200
+ * carry for the request to succeed on retry.
199
201
  */
200
202
  export declare class CapabilityError extends AbloPermissionError {
201
203
  readonly requiredCapability?: RequiredCapability;
package/dist/errors.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Typed error hierarchy for `@ablo/sync-engine`.
2
+ * Typed error hierarchy for `@abloatai/ablo`.
3
3
  *
4
4
  * Inlined directly so the publishable dist is self-contained. The public
5
5
  * package should never reference an unpublished internal package from emitted
@@ -125,16 +125,18 @@ export class AbloBusyError extends AbloError {
125
125
  }
126
126
  }
127
127
  /**
128
- * Biscuit capability token failed verification — either it's
129
- * malformed / unknown / revoked (`capability_invalid`), or its
130
- * caveats deny the attempted action (`capability_scope_denied`).
128
+ * A scoped credential was denied — either the key is unknown / revoked /
129
+ * expired (`capability_invalid`), or the connection's resolved scope
130
+ * doesn't cover the attempted action (`capability_scope_denied`). With
131
+ * opaque restricted (`rk_`) API keys this is a server-side check against
132
+ * the key's `syncGroups` / `operations`, not a signed-caveat verification.
131
133
  *
132
134
  * Extends `AbloPermissionError` so existing `instanceof CapabilityError`
133
135
  * checks keep working AND broader `instanceof AbloPermissionError`
134
- * matches for consumers who don't care about the Biscuit specifics.
136
+ * matches for consumers who don't care about the scope specifics.
135
137
  *
136
- * `requiredCapability` (when present) describes what an attenuated
137
- * capability must satisfy for the request to succeed on retry.
138
+ * `requiredCapability` (when present) describes the scope a key must
139
+ * carry for the request to succeed on retry.
138
140
  */
139
141
  export class CapabilityError extends AbloPermissionError {
140
142
  requiredCapability;
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  /**
2
- * @ablo/sync-engine — The Collaboration Layer for AI and Humans
2
+ * @abloatai/ablo — The Collaboration Layer for AI and Humans
3
3
  *
4
4
  * ```ts
5
- * import Ablo from '@ablo/sync-engine';
5
+ * import Ablo from '@abloatai/ablo';
6
6
  *
7
7
  * const ablo = Ablo({ schema, apiKey: process.env.ABLO_API_KEY });
8
8
  * await ablo.tasks.load({ where: { id: 'task_123' } });
@@ -19,16 +19,30 @@
19
19
  * reached via dot-access on the engine, types via namespace dots.
20
20
  *
21
21
  * Public subpaths:
22
- * @ablo/sync-engine/schema — defineSchema, model, z (Zod)
23
- * @ablo/sync-engine/react — <AbloProvider>, useQuery, useMutate
24
- * @ablo/sync-engine/testing — test harnesses + mocks
22
+ * @abloatai/ablo/schema — defineSchema, model, z (Zod)
23
+ * @abloatai/ablo/react — <AbloProvider>, useQuery, useMutate
24
+ * @abloatai/ablo/testing — test harnesses + mocks
25
25
  *
26
26
  * Consumer code should converge on `ablo.<model>.load(...)`, which routes
27
27
  * through the engine's `HydrationCoordinator` and dedupes single-flight
28
28
  * hydrations.
29
+ *
30
+ * ── What to import (read this first) ────────────────────────────────
31
+ * Default path — this is all most apps and agents ever need:
32
+ * • `Ablo` (default export) + `AbloOptions` + the `Model*Options` bags
33
+ * • the `Ablo*Error` classes, to discriminate failures in catch blocks
34
+ * That's it. If you're reaching past those, you're in advanced territory.
35
+ *
36
+ * Advanced — opt-in, most apps never import these (each is tagged
37
+ * "Advanced —" at its export below, with the one situation it's for):
38
+ * • `dataSource` / `abloSource` — only if your own DB stays canonical
39
+ * • `session` / `agent` — only for delegated agent principals
40
+ * • `defaultPolicy` — only to customize conflict resolution
41
+ * • `defineMutators` / `createTransaction` — only for custom mutators
42
+ * If you don't recognize one, you don't need it — the default path covers you.
29
43
  */
30
44
  export { Ablo } from './client/Ablo.js';
31
- export type { AbloOptions, ModelCountOptions, ModelListOptions, ModelListScope, ModelLoadOptions, ModelEditHandle, ModelEditOptions, ModelOperations, } from './client/Ablo.js';
45
+ export type { AbloOptions, ModelCountOptions, ModelListOptions, ModelListScope, ModelLoadOptions, ModelIntentHandle, ModelIntentAcquireOptions, ModelOperations, } from './client/Ablo.js';
32
46
  export type { AbloPersistence } from './client/persistence.js';
33
47
  export { session, agent } from './principal.js';
34
48
  import { Ablo } from './client/Ablo.js';
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  /**
2
- * @ablo/sync-engine — The Collaboration Layer for AI and Humans
2
+ * @abloatai/ablo — The Collaboration Layer for AI and Humans
3
3
  *
4
4
  * ```ts
5
- * import Ablo from '@ablo/sync-engine';
5
+ * import Ablo from '@abloatai/ablo';
6
6
  *
7
7
  * const ablo = Ablo({ schema, apiKey: process.env.ABLO_API_KEY });
8
8
  * await ablo.tasks.load({ where: { id: 'task_123' } });
@@ -19,44 +19,61 @@
19
19
  * reached via dot-access on the engine, types via namespace dots.
20
20
  *
21
21
  * Public subpaths:
22
- * @ablo/sync-engine/schema — defineSchema, model, z (Zod)
23
- * @ablo/sync-engine/react — <AbloProvider>, useQuery, useMutate
24
- * @ablo/sync-engine/testing — test harnesses + mocks
22
+ * @abloatai/ablo/schema — defineSchema, model, z (Zod)
23
+ * @abloatai/ablo/react — <AbloProvider>, useQuery, useMutate
24
+ * @abloatai/ablo/testing — test harnesses + mocks
25
25
  *
26
26
  * Consumer code should converge on `ablo.<model>.load(...)`, which routes
27
27
  * through the engine's `HydrationCoordinator` and dedupes single-flight
28
28
  * hydrations.
29
+ *
30
+ * ── What to import (read this first) ────────────────────────────────
31
+ * Default path — this is all most apps and agents ever need:
32
+ * • `Ablo` (default export) + `AbloOptions` + the `Model*Options` bags
33
+ * • the `Ablo*Error` classes, to discriminate failures in catch blocks
34
+ * That's it. If you're reaching past those, you're in advanced territory.
35
+ *
36
+ * Advanced — opt-in, most apps never import these (each is tagged
37
+ * "Advanced —" at its export below, with the one situation it's for):
38
+ * • `dataSource` / `abloSource` — only if your own DB stays canonical
39
+ * • `session` / `agent` — only for delegated agent principals
40
+ * • `defaultPolicy` — only to customize conflict resolution
41
+ * • `defineMutators` / `createTransaction` — only for custom mutators
42
+ * If you don't recognize one, you don't need it — the default path covers you.
29
43
  */
30
44
  // ── Consumer API ──────────────────────────────────────────────────────────
31
45
  // These are the only symbols external consumers should need from this path.
32
46
  // Everything else is in a subpath.
33
47
  // The canonical surface — `Ablo` is a function, type, and namespace under
34
48
  // one name. Matches `Stripe`, `OpenAI`, `Anthropic`. Default export so
35
- // `import Ablo from '@ablo/sync-engine'` works; named export so
49
+ // `import Ablo from '@abloatai/ablo'` works; named export so
36
50
  // `import { Ablo }` also compiles.
37
51
  export { Ablo } from './client/Ablo.js';
38
52
  // Participant types live under `Ablo.Participant.*` —
39
53
  // `Ablo.Participant.Joined`, `Ablo.Participant.Manager`,
40
54
  // `Ablo.Participant.JoinOptions`, etc. Same dot-access shape as
41
55
  // `Ablo.Peer`, `Ablo.Claim`, `Ablo.Turn`. No flat re-exports.
42
- // Principal constructors explicit factories for delegation paths
43
- // (`Ablo({ kind: 'agent', as: session({...}) })`). Function exports
44
- // because they're constructors, not types.
56
+ // Advancedmost apps never import this. Principal constructors for
57
+ // delegated agent paths (`Ablo({ kind: 'agent', as: session({...}) })`).
58
+ // The default `Ablo({ schema, apiKey })` resolves identity from the key;
59
+ // reach for these only when minting a delegated agent principal.
45
60
  export { session, agent } from './principal.js';
46
61
  import { Ablo } from './client/Ablo.js';
47
62
  export default Ablo;
48
- // Customer-owned storage adapter. Used only when Ablo Cloud coordinates
49
- // state while canonical rows remain in the customer's database. Runtime
50
- // helpers ship flat; type counterparts live under `Ablo.Source.*`
51
- // (`Ablo.Source.Operation`, `Ablo.Source.Commit.Params`, etc.).
63
+ // Advanced most apps never import this. Customer-owned storage adapter
64
+ // for Data Source mode: only when Ablo Cloud coordinates state while
65
+ // canonical rows stay in YOUR database. The default is Ablo-managed
66
+ // storage if you haven't deliberately chosen to keep your own DB
67
+ // canonical, skip this entirely. Type counterparts live under
68
+ // `Ablo.Source.*` (`Ablo.Source.Operation`, `Ablo.Source.Commit.Params`).
52
69
  export { dataSource, abloSource, signAbloSourceRequest, verifyAbloSourceRequest, } from './source/index.js';
53
- // Schema DSL is intentionally published from `@ablo/sync-engine/schema`.
70
+ // Schema DSL is intentionally published from `@abloatai/ablo/schema`.
54
71
  // Keeping it out of the root import preserves one clean runtime surface:
55
- // `import Ablo from '@ablo/sync-engine'`.
56
- // Conflict policy `defaultPolicy` (the rejecting default) is a value
57
- // callers reference if they want to compose. The type counterparts
58
- // (`Conflict`, `ConflictPolicy`, etc.) live under `Ablo.Conflict`,
59
- // `Ablo.Conflict.Policy` on the namespace.
72
+ // `import Ablo from '@abloatai/ablo'`.
73
+ // Advancedmost apps never import this. Conflict policy: `defaultPolicy`
74
+ // (reject-on-stale) is already applied server-side, so you only import it
75
+ // to COMPOSE a custom policy. Leave it alone and stale writes are rejected
76
+ // safely by default. Type counterparts live under `Ablo.Conflict.*`.
60
77
  export { defaultPolicy } from './policy/index.js';
61
78
  // Typed error hierarchy — Stripe-style. One import gets every class
62
79
  // consumers need to discriminate failures (`e instanceof AbloX` or
@@ -66,8 +83,10 @@ export { SyncSessionError, AbloError, AbloAuthenticationError, AbloPermissionErr
66
83
  // Intents/UserMeta once in a `.d.ts` via `declare global { interface AbloSync
67
84
  // { ... } }`. Resolver types live under the `Ablo` namespace —
68
85
  // `Ablo.ResolveSchema`, `Ablo.ResolvePresence`, etc. — pure type-level.
69
- // Custom mutators runtime entry point only.
70
- // Type counterparts moved to the `Ablo` namespace:
86
+ // Advancedmost apps never import this. Custom (Zero-style) mutators:
87
+ // `ablo.<model>.create/update/delete` already covers normal writes. Reach
88
+ // for `defineMutators` only when you need a named, multi-step mutation with
89
+ // custom undo. Type counterparts live under the `Ablo` namespace:
71
90
  // Ablo.Mutator.Fn, Ablo.Transaction
72
91
  // Ablo.Mutator.UndoEntry, Ablo.Mutator.InverseOp
73
92
  // Ablo.Query, Ablo.QueryBatch, Ablo.QueryBatchResult
@@ -79,4 +98,4 @@ export { defineMutators } from './mutators/defineMutators.js';
79
98
  // pass it as `{ tx, args }` to the mutator function.
80
99
  export { createTransaction } from './mutators/Transaction.js';
81
100
  // Undo runtime is intentionally not part of the public root surface. App code
82
- // uses `useUndoScope` from `@ablo/sync-engine/react`.
101
+ // uses `useUndoScope` from `@abloatai/ablo/react`.
@@ -12,7 +12,7 @@
12
12
  * const engine = createSyncEngine({ url, userId, organizationId });
13
13
  *
14
14
  * // Node.js / agent / sidecar (headless — DI overrides)
15
- * import { inMemoryStorage, alwaysOnline } from '@ablo/sync-engine/headless';
15
+ * import { inMemoryStorage, alwaysOnline } from '@abloatai/ablo/headless';
16
16
  * const engine = createSyncEngine({
17
17
  * url, userId, organizationId,
18
18
  * storage: inMemoryStorage(),
@@ -12,7 +12,7 @@
12
12
  * const engine = createSyncEngine({ url, userId, organizationId });
13
13
  *
14
14
  * // Node.js / agent / sidecar (headless — DI overrides)
15
- * import { inMemoryStorage, alwaysOnline } from '@ablo/sync-engine/headless';
15
+ * import { inMemoryStorage, alwaysOnline } from '@abloatai/ablo/headless';
16
16
  * const engine = createSyncEngine({
17
17
  * url, userId, organizationId,
18
18
  * storage: inMemoryStorage(),
@@ -32,7 +32,7 @@ export {};
32
32
  //
33
33
  // These will be the public API that headless consumers import:
34
34
  //
35
- // import { inMemoryStorage, alwaysOnline } from '@ablo/sync-engine/headless';
35
+ // import { inMemoryStorage, alwaysOnline } from '@abloatai/ablo/headless';
36
36
  //
37
37
  // Stubs below show the intended signatures. Implementation is Phase 1 work.
38
38
  // export function inMemoryStorage(): StorageProvider { ... }
@@ -1,11 +1,11 @@
1
1
  /**
2
- * @ablo/sync-engine/policy — pluggable conflict resolution.
2
+ * @abloatai/ablo/policy — pluggable conflict resolution.
3
3
  *
4
4
  * The engine detects conflicts; the policy decides. Customer code
5
5
  * implements `ConflictPolicy` and registers it at the sync-server.
6
6
  *
7
7
  * ```ts
8
- * import { type ConflictPolicy, defaultPolicy } from '@ablo/sync-engine/policy';
8
+ * import { type ConflictPolicy, defaultPolicy } from '@abloatai/ablo/policy';
9
9
  *
10
10
  * export const myPolicy: ConflictPolicy = (ctx) => {
11
11
  * if (ctx.committer.id.startsWith('linter:')) {
@@ -1,11 +1,11 @@
1
1
  /**
2
- * @ablo/sync-engine/policy — pluggable conflict resolution.
2
+ * @abloatai/ablo/policy — pluggable conflict resolution.
3
3
  *
4
4
  * The engine detects conflicts; the policy decides. Customer code
5
5
  * implements `ConflictPolicy` and registers it at the sync-server.
6
6
  *
7
7
  * ```ts
8
- * import { type ConflictPolicy, defaultPolicy } from '@ablo/sync-engine/policy';
8
+ * import { type ConflictPolicy, defaultPolicy } from '@abloatai/ablo/policy';
9
9
  *
10
10
  * export const myPolicy: ConflictPolicy = (ctx) => {
11
11
  * if (ctx.committer.id.startsWith('linter:')) {
@@ -29,6 +29,16 @@ export interface StaleContextConflict extends ConflictBase {
29
29
  readonly readAt: number;
30
30
  /** Most recent delta id on the target. */
31
31
  readonly observedSyncId: number;
32
+ /**
33
+ * The fields whose concurrent change triggered this conflict — the
34
+ * intersection of the committer's written fields and the columns a
35
+ * newer delta touched. Empty array means the conflicting delta was a
36
+ * whole-entity change (CREATE/DELETE, or a pre-`changed_fields`
37
+ * legacy delta), which conflicts with any write. Lets a policy decide
38
+ * at field granularity, e.g. allow when the only collision is on a
39
+ * cosmetic field. See `docs/internal/per-field-conflict-detection.md`.
40
+ */
41
+ readonly conflictingFields?: readonly string[];
32
42
  }
33
43
  export interface IntentHeldConflict extends ConflictBase {
34
44
  readonly kind: 'intent_held';
@@ -4,7 +4,7 @@
4
4
  * the discriminated-union tags.
5
5
  *
6
6
  * ```ts
7
- * import Ablo, { session } from '@ablo/sync-engine';
7
+ * import Ablo, { session } from '@abloatai/ablo';
8
8
  *
9
9
  * const ablo = Ablo({ schema, apiKey });
10
10
  * const participant = await ablo.participants.join({
@@ -18,8 +18,8 @@
18
18
  * participant layer handles attenuation.
19
19
  *
20
20
  * These are pure — no I/O, no hidden state. If the shape ever grows a
21
- * required field (say, a Biscuit scope hint), the helper is the one
22
- * place to flag migrations.
21
+ * required field (say, a scope hint for the restricted key), the helper
22
+ * is the one place to flag migrations.
23
23
  */
24
24
  import type { AgentRef, SessionRef } from './types/streams.js';
25
25
  /**
package/dist/principal.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * the discriminated-union tags.
5
5
  *
6
6
  * ```ts
7
- * import Ablo, { session } from '@ablo/sync-engine';
7
+ * import Ablo, { session } from '@abloatai/ablo';
8
8
  *
9
9
  * const ablo = Ablo({ schema, apiKey });
10
10
  * const participant = await ablo.participants.join({
@@ -18,8 +18,8 @@
18
18
  * participant layer handles attenuation.
19
19
  *
20
20
  * These are pure — no I/O, no hidden state. If the shape ever grows a
21
- * required field (say, a Biscuit scope hint), the helper is the one
22
- * place to flag migrations.
21
+ * required field (say, a scope hint for the restricted key), the helper
22
+ * is the one place to flag migrations.
23
23
  */
24
24
  /**
25
25
  * Build a `SessionRef` from the identifiers your auth system already
@@ -22,13 +22,14 @@ export interface PostQueryOptions {
22
22
  /** Timeout in ms for the fetch request. Default: 30000. */
23
23
  fetchTimeout?: number;
24
24
  /**
25
- * Capability token (Biscuit) to attach as `Authorization: Bearer <token>`.
26
- * Required for Node consumers (agent-worker, server-side tests) that
27
- * have no session cookie to ride. Browser consumers can omit this and
28
- * fall back to `credentials: 'include'`. When both are present the
29
- * server prefers the Bearer header (see `agentTokenProvider` in
25
+ * Bearer credential — a restricted (`rk_`) API key attached as
26
+ * `Authorization: Bearer <token>`. Required for Node consumers
27
+ * (agent-worker, server-side tests) that have no session cookie to
28
+ * ride. Browser consumers can omit this and fall back to
29
+ * `credentials: 'include'`. When both are present the server prefers
30
+ * the Bearer header (see `apiKeyProvider` in
30
31
  * `apps/sync-server/src/auth`), so passing the token in browser code
31
- * is harmless.
32
+ * is harmless. (Field name predates the Biscuit→opaque-key migration.)
32
33
  */
33
34
  capabilityToken?: string;
34
35
  }
@@ -29,8 +29,29 @@ import { type SyncStoreContract } from './context.js';
29
29
  * only when `userId` / account scope / `url` change. React
30
30
  * Strict Mode double-mount does not leak a second WebSocket.
31
31
  */
32
+ /**
33
+ * Props for `<AbloProvider>`.
34
+ *
35
+ * The default path is one prop:
36
+ *
37
+ * ```tsx
38
+ * <AbloProvider schema={schema}>
39
+ * <App />
40
+ * </AbloProvider>
41
+ * ```
42
+ *
43
+ * That's it for most apps — the provider resolves identity, account
44
+ * scope, and realtime permissions from auth. `userId`/`apiKey`/`url`
45
+ * are situational; the `bootstrapMode`, `persistence`, and `fallback`
46
+ * props are opt-in tuning; and the block tagged "Optional DI (advanced)"
47
+ * below is escape-hatch wiring for tests and platform builders — if you
48
+ * don't recognize a prop there, you don't need it.
49
+ */
32
50
  export interface AbloProviderProps<R extends SchemaRecord = SchemaRecord> {
33
- /** Schema from `defineSchema()`. Determines the typed hook surface. */
51
+ /**
52
+ * Schema from `defineSchema()`. Determines the typed hook surface.
53
+ * This is the only prop most apps pass — start here.
54
+ */
34
55
  schema: Schema<R>;
35
56
  /**
36
57
  * WebSocket URL of the sync server (`wss://...` or `ws://...`).
@@ -103,6 +124,28 @@ export interface AbloProviderProps<R extends SchemaRecord = SchemaRecord> {
103
124
  * for the full semantics.
104
125
  */
105
126
  persistence?: AbloPersistence;
127
+ /**
128
+ * How aggressively this provider pulls baseline state at startup.
129
+ *
130
+ * - `'full'` (default): pull every delta in the configured sync
131
+ * groups before the engine reports ready — a local replica of the
132
+ * org's tenant plane. Right for collaborative editors and any page
133
+ * that reads a lot of shared state.
134
+ * - `'none'`: open the connection and process live deltas only — no
135
+ * baseline fetch. Reads round-trip via `ablo.<model>.retrieve(...)`
136
+ * and subscriptions populate the pool lazily. Right for read-light
137
+ * pages (a mostly-static dashboard, a settings screen) that don't
138
+ * want to download the whole org to render.
139
+ *
140
+ * Note: `'none'` still opens the realtime connection — it skips the
141
+ * baseline pull, not the socket. A fully connection-free mode for
142
+ * pages that do zero multiplayer is a separate follow-up (the socket
143
+ * open lives inside `engine.ready()`, so deferring it needs
144
+ * engine-level lazy-connect support, not just a provider prop).
145
+ *
146
+ * Mirrors `AbloOptions.bootstrapMode`. Changing it rotates the engine.
147
+ */
148
+ bootstrapMode?: 'full' | 'none';
106
149
  /**
107
150
  * Rendered in place of `children` during the *first* bootstrap pass —
108
151
  * while the engine is actively transitioning from `initial` →
@@ -32,7 +32,7 @@ function createErrorEmitter() {
32
32
  };
33
33
  }
34
34
  export function AbloProvider(props) {
35
- const { schema, url = 'wss://mesh.ablo.finance', userId, teamIds, apiKey, preventUnsavedChanges, onSessionExpired, onError, observability, logger, mutationExecutor, mutationDispatcher, sessionErrorDetector, onlineStatus, configOverrides, syncGroups, bootstrapBaseUrl, maxPoolSize, persistence, fallback = _jsx(DefaultFallback, {}), children, } = props;
35
+ const { schema, url = 'wss://mesh.ablo.finance', userId, teamIds, apiKey, preventUnsavedChanges, onSessionExpired, onError, observability, logger, mutationExecutor, mutationDispatcher, sessionErrorDetector, onlineStatus, configOverrides, syncGroups, bootstrapBaseUrl, maxPoolSize, persistence, bootstrapMode, fallback = _jsx(DefaultFallback, {}), children, } = props;
36
36
  // Account scope is no longer accepted from props. The engine learns
37
37
  // it from auth (capability token) at bootstrap and we read it back
38
38
  // out of `_store.orgId` once `engine.ready()` resolves.
@@ -62,6 +62,7 @@ export function AbloProvider(props) {
62
62
  const engineKey = JSON.stringify({
63
63
  userId: userId ?? null,
64
64
  url,
65
+ bootstrapMode: bootstrapMode ?? null,
65
66
  });
66
67
  const [engineState, setEngineState] = useState({ key: engineKey, engine: null });
67
68
  // Keep a ref to the current engine key so the rotation effect can
@@ -89,6 +90,7 @@ export function AbloProvider(props) {
89
90
  bootstrapBaseUrl,
90
91
  maxPoolSize,
91
92
  persistence,
93
+ ...(bootstrapMode ? { bootstrapMode } : {}),
92
94
  autoStart: false,
93
95
  };
94
96
  const engine = Ablo(engineOptions);
@@ -15,7 +15,7 @@ import { type ReactNode } from 'react';
15
15
  *
16
16
  * v0.3.x implementation is non-Suspense: reads `useSyncStatus()` and
17
17
  * conditionally renders. v0.3.x+ will ship a
18
- * `@ablo/sync-engine/react/suspense` subpath where `useQuery` / `useOne`
18
+ * `@abloatai/ablo/react/suspense` subpath where `useQuery` / `useOne`
19
19
  * actually throw Promises; this component becomes a thin wrapper around
20
20
  * React's real `<Suspense>` at that point.
21
21
  *
@@ -38,7 +38,7 @@ export function useSyncGroup() {
38
38
  if (!id) {
39
39
  throw new AbloValidationError('useSyncGroup: no <SyncGroupProvider> mounted above this component. ' +
40
40
  'Wrap your tree with <SyncGroupProvider id="matter:..."> from ' +
41
- '@ablo/sync-engine/react.', { code: 'no_sync_group_provider' });
41
+ '@abloatai/ablo/react.', { code: 'no_sync_group_provider' });
42
42
  }
43
43
  return id;
44
44
  }
@@ -148,7 +148,7 @@ export interface SyncProviderProps {
148
148
  * (useModel, useModels, useMutations) can access it.
149
149
  *
150
150
  * @example
151
- * import { SyncProvider } from '@ablo/sync-engine/react';
151
+ * import { SyncProvider } from '@abloatai/ablo/react';
152
152
  *
153
153
  * function App() {
154
154
  * return (
@@ -20,7 +20,7 @@ export function useSyncContext() {
20
20
  * (useModel, useModels, useMutations) can access it.
21
21
  *
22
22
  * @example
23
- * import { SyncProvider } from '@ablo/sync-engine/react';
23
+ * import { SyncProvider } from '@abloatai/ablo/react';
24
24
  *
25
25
  * function App() {
26
26
  * return (
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @ablo/sync-engine/react — React bindings (v0.3.0)
2
+ * @abloatai/ablo/react — React bindings (v0.3.0)
3
3
  *
4
4
  * Umbrella provider:
5
5
  * <AbloProvider schema={...} userId={...} orgId={...} fallback={<Skeleton/>}>
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @ablo/sync-engine/react — React bindings (v0.3.0)
2
+ * @abloatai/ablo/react — React bindings (v0.3.0)
3
3
  *
4
4
  * Umbrella provider:
5
5
  * <AbloProvider schema={...} userId={...} orgId={...} fallback={<Skeleton/>}>
@@ -27,7 +27,7 @@ export function useCurrentUserId() {
27
27
  if (!ctx) {
28
28
  throw new AbloValidationError('useCurrentUserId: no <AbloProvider> mounted above this component. ' +
29
29
  'Wrap your tree with <AbloProvider ...> from ' +
30
- '@ablo/sync-engine/react.', { code: 'no_ablo_provider' });
30
+ '@abloatai/ablo/react.', { code: 'no_ablo_provider' });
31
31
  }
32
32
  return ctx.currentUserId;
33
33
  }
@@ -25,7 +25,7 @@ export function useErrorListener(listener) {
25
25
  const ctx = useContext(AbloInternalContext);
26
26
  if (!ctx) {
27
27
  throw new AbloValidationError('useErrorListener: no <AbloProvider> mounted above this component. ' +
28
- 'Wrap your tree with <AbloProvider ...> from @ablo/sync-engine/react.', { code: 'no_ablo_provider' });
28
+ 'Wrap your tree with <AbloProvider ...> from @abloatai/ablo/react.', { code: 'no_ablo_provider' });
29
29
  }
30
30
  // Stash the latest callback in a ref so the effect subscription
31
31
  // stays stable across renders. Matches the `useEventCallback`
@@ -13,7 +13,7 @@ type GlobalMutateActions<K extends string> = ResolveSchema extends Schema ? K ex
13
13
  *
14
14
  * @example
15
15
  * import { schema } from '@ablo/schema';
16
- * import { useMutate } from '@ablo/sync-engine/react';
16
+ * import { useMutate } from '@abloatai/ablo/react';
17
17
  *
18
18
  * const tasks = useMutate(schema, 'tasks');
19
19
  *
@@ -25,7 +25,7 @@ export function useMutationFailureListener(listener) {
25
25
  const ctx = useContext(AbloInternalContext);
26
26
  if (!ctx) {
27
27
  throw new AbloValidationError('useMutationFailureListener: no <AbloProvider> mounted above this component. ' +
28
- 'Wrap your tree with <AbloProvider ...> from @ablo/sync-engine/react.', { code: 'no_ablo_provider' });
28
+ 'Wrap your tree with <AbloProvider ...> from @abloatai/ablo/react.', { code: 'no_ablo_provider' });
29
29
  }
30
30
  const ref = useRef(listener);
31
31
  ref.current = listener;
@@ -21,7 +21,7 @@ type GlobalReaderActions<K extends string> = ResolveSchema extends Schema ? K ex
21
21
  *
22
22
  * @example
23
23
  * import { schema } from '@ablo/schema';
24
- * import { useReader } from '@ablo/sync-engine/react';
24
+ * import { useReader } from '@abloatai/ablo/react';
25
25
  *
26
26
  * function useTaskMutations() {
27
27
  * const read = useReader(schema, 'tasks');
@@ -6,7 +6,7 @@
6
6
  * survives `.optional()`, `.nullable()`, and `.default()` chain calls.
7
7
  *
8
8
  * Usage:
9
- * import { field } from '@ablo/sync-engine/schema';
9
+ * import { field } from '@abloatai/ablo/schema';
10
10
  *
11
11
  * const tasks = model({
12
12
  * title: field.string(),
@@ -6,7 +6,7 @@
6
6
  * survives `.optional()`, `.nullable()`, and `.default()` chain calls.
7
7
  *
8
8
  * Usage:
9
- * import { field } from '@ablo/sync-engine/schema';
9
+ * import { field } from '@abloatai/ablo/schema';
10
10
  *
11
11
  * const tasks = model({
12
12
  * title: field.string(),
@@ -1,11 +1,11 @@
1
1
  /**
2
- * @ablo/sync-engine/schema — Schema Definition DSL
2
+ * @abloatai/ablo/schema — Schema Definition DSL
3
3
  *
4
4
  * Define your data models with Zod. Types are inferred automatically.
5
5
  *
6
6
  * ```ts
7
7
  * import { z } from 'zod';
8
- * import { defineSchema, model, relation } from '@ablo/sync-engine/schema';
8
+ * import { defineSchema, model, relation } from '@abloatai/ablo/schema';
9
9
  *
10
10
  * export const schema = defineSchema({
11
11
  * tasks: model({