@abloatai/ablo 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (278) hide show
  1. package/CHANGELOG.md +208 -0
  2. package/LICENSE +201 -0
  3. package/NOTICE +12 -0
  4. package/README.md +230 -0
  5. package/dist/BaseSyncedStore.d.ts +709 -0
  6. package/dist/BaseSyncedStore.js +1843 -0
  7. package/dist/Database.d.ts +344 -0
  8. package/dist/Database.js +1259 -0
  9. package/dist/LazyReferenceCollection.d.ts +181 -0
  10. package/dist/LazyReferenceCollection.js +460 -0
  11. package/dist/Model.d.ts +339 -0
  12. package/dist/Model.js +715 -0
  13. package/dist/ModelRegistry.d.ts +200 -0
  14. package/dist/ModelRegistry.js +535 -0
  15. package/dist/NetworkMonitor.d.ts +27 -0
  16. package/dist/NetworkMonitor.js +73 -0
  17. package/dist/ObjectPool.d.ts +202 -0
  18. package/dist/ObjectPool.js +1106 -0
  19. package/dist/SyncClient.d.ts +489 -0
  20. package/dist/SyncClient.js +1555 -0
  21. package/dist/SyncEngineContext.d.ts +46 -0
  22. package/dist/SyncEngineContext.js +74 -0
  23. package/dist/adapters/alwaysOnline.d.ts +16 -0
  24. package/dist/adapters/alwaysOnline.js +19 -0
  25. package/dist/adapters/inMemoryStorage.d.ts +30 -0
  26. package/dist/adapters/inMemoryStorage.js +94 -0
  27. package/dist/agent/Agent.d.ts +358 -0
  28. package/dist/agent/Agent.js +500 -0
  29. package/dist/agent/index.d.ts +115 -0
  30. package/dist/agent/index.js +128 -0
  31. package/dist/agent/session.d.ts +90 -0
  32. package/dist/agent/session.js +156 -0
  33. package/dist/agent/types.d.ts +73 -0
  34. package/dist/agent/types.js +10 -0
  35. package/dist/ai-sdk/coordination-context.d.ts +51 -0
  36. package/dist/ai-sdk/coordination-context.js +107 -0
  37. package/dist/ai-sdk/index.d.ts +68 -0
  38. package/dist/ai-sdk/index.js +68 -0
  39. package/dist/ai-sdk/intent-broadcast.d.ts +77 -0
  40. package/dist/ai-sdk/intent-broadcast.js +72 -0
  41. package/dist/ai-sdk/wrap.d.ts +67 -0
  42. package/dist/ai-sdk/wrap.js +45 -0
  43. package/dist/api/index.d.ts +10 -0
  44. package/dist/api/index.js +9 -0
  45. package/dist/auth/index.d.ts +137 -0
  46. package/dist/auth/index.js +246 -0
  47. package/dist/client/Ablo.d.ts +835 -0
  48. package/dist/client/Ablo.js +1440 -0
  49. package/dist/client/ApiClient.d.ts +200 -0
  50. package/dist/client/ApiClient.js +659 -0
  51. package/dist/client/auth.d.ts +79 -0
  52. package/dist/client/auth.js +81 -0
  53. package/dist/client/createInternalComponents.d.ts +44 -0
  54. package/dist/client/createInternalComponents.js +88 -0
  55. package/dist/client/createModelProxy.d.ts +152 -0
  56. package/dist/client/createModelProxy.js +199 -0
  57. package/dist/client/identity.d.ts +63 -0
  58. package/dist/client/identity.js +156 -0
  59. package/dist/client/index.d.ts +36 -0
  60. package/dist/client/index.js +33 -0
  61. package/dist/client/persistence.d.ts +7 -0
  62. package/dist/client/persistence.js +11 -0
  63. package/dist/client/validateAbloOptions.d.ts +42 -0
  64. package/dist/client/validateAbloOptions.js +43 -0
  65. package/dist/config/index.d.ts +10 -0
  66. package/dist/config/index.js +12 -0
  67. package/dist/context.d.ts +27 -0
  68. package/dist/context.js +58 -0
  69. package/dist/core/DatabaseManager.d.ts +108 -0
  70. package/dist/core/DatabaseManager.js +361 -0
  71. package/dist/core/QueryProcessor.d.ts +77 -0
  72. package/dist/core/QueryProcessor.js +262 -0
  73. package/dist/core/QueryView.d.ts +64 -0
  74. package/dist/core/QueryView.js +219 -0
  75. package/dist/core/StoreManager.d.ts +131 -0
  76. package/dist/core/StoreManager.js +334 -0
  77. package/dist/core/ViewRegistry.d.ts +20 -0
  78. package/dist/core/ViewRegistry.js +55 -0
  79. package/dist/core/index.d.ts +34 -0
  80. package/dist/core/index.js +59 -0
  81. package/dist/core/openIDBWithTimeout.d.ts +27 -0
  82. package/dist/core/openIDBWithTimeout.js +63 -0
  83. package/dist/core/query-utils.d.ts +37 -0
  84. package/dist/core/query-utils.js +60 -0
  85. package/dist/errors.d.ts +235 -0
  86. package/dist/errors.js +243 -0
  87. package/dist/index.d.ts +41 -0
  88. package/dist/index.js +82 -0
  89. package/dist/interfaces/headless.d.ts +95 -0
  90. package/dist/interfaces/headless.js +41 -0
  91. package/dist/interfaces/index.d.ts +321 -0
  92. package/dist/interfaces/index.js +8 -0
  93. package/dist/mutators/RecordingTransaction.d.ts +36 -0
  94. package/dist/mutators/RecordingTransaction.js +216 -0
  95. package/dist/mutators/Transaction.d.ts +48 -0
  96. package/dist/mutators/Transaction.js +64 -0
  97. package/dist/mutators/UndoManager.d.ts +114 -0
  98. package/dist/mutators/UndoManager.js +143 -0
  99. package/dist/mutators/defineMutators.d.ts +55 -0
  100. package/dist/mutators/defineMutators.js +28 -0
  101. package/dist/policy/index.d.ts +19 -0
  102. package/dist/policy/index.js +18 -0
  103. package/dist/policy/types.d.ts +74 -0
  104. package/dist/policy/types.js +17 -0
  105. package/dist/principal.d.ts +44 -0
  106. package/dist/principal.js +49 -0
  107. package/dist/query/client.d.ts +43 -0
  108. package/dist/query/client.js +84 -0
  109. package/dist/query/index.d.ts +6 -0
  110. package/dist/query/index.js +5 -0
  111. package/dist/query/types.d.ts +143 -0
  112. package/dist/query/types.js +36 -0
  113. package/dist/react/AbloProvider.d.ts +205 -0
  114. package/dist/react/AbloProvider.js +398 -0
  115. package/dist/react/ClientSideSuspense.d.ts +36 -0
  116. package/dist/react/ClientSideSuspense.js +17 -0
  117. package/dist/react/DefaultFallback.d.ts +24 -0
  118. package/dist/react/DefaultFallback.js +43 -0
  119. package/dist/react/SyncGroupProvider.d.ts +19 -0
  120. package/dist/react/SyncGroupProvider.js +44 -0
  121. package/dist/react/context.d.ts +161 -0
  122. package/dist/react/context.js +35 -0
  123. package/dist/react/index.d.ts +64 -0
  124. package/dist/react/index.js +73 -0
  125. package/dist/react/internalContext.d.ts +35 -0
  126. package/dist/react/internalContext.js +3 -0
  127. package/dist/react/useAblo.d.ts +72 -0
  128. package/dist/react/useAblo.js +63 -0
  129. package/dist/react/useCurrentUserId.d.ts +21 -0
  130. package/dist/react/useCurrentUserId.js +33 -0
  131. package/dist/react/useErrorListener.d.ts +20 -0
  132. package/dist/react/useErrorListener.js +39 -0
  133. package/dist/react/useIntent.d.ts +29 -0
  134. package/dist/react/useIntent.js +42 -0
  135. package/dist/react/useMutate.d.ts +83 -0
  136. package/dist/react/useMutate.js +122 -0
  137. package/dist/react/useMutationFailureListener.d.ts +26 -0
  138. package/dist/react/useMutationFailureListener.js +38 -0
  139. package/dist/react/useMutators.d.ts +56 -0
  140. package/dist/react/useMutators.js +66 -0
  141. package/dist/react/usePresence.d.ts +32 -0
  142. package/dist/react/usePresence.js +41 -0
  143. package/dist/react/useQuery.d.ts +123 -0
  144. package/dist/react/useQuery.js +145 -0
  145. package/dist/react/useReactive.d.ts +35 -0
  146. package/dist/react/useReactive.js +111 -0
  147. package/dist/react/useReader.d.ts +69 -0
  148. package/dist/react/useReader.js +73 -0
  149. package/dist/react/useSyncStatus.d.ts +61 -0
  150. package/dist/react/useSyncStatus.js +76 -0
  151. package/dist/react/useUndoScope.d.ts +36 -0
  152. package/dist/react/useUndoScope.js +73 -0
  153. package/dist/realtime/index.d.ts +10 -0
  154. package/dist/realtime/index.js +9 -0
  155. package/dist/schema/field.d.ts +134 -0
  156. package/dist/schema/field.js +264 -0
  157. package/dist/schema/index.d.ts +29 -0
  158. package/dist/schema/index.js +38 -0
  159. package/dist/schema/model.d.ts +326 -0
  160. package/dist/schema/model.js +89 -0
  161. package/dist/schema/queries.d.ts +203 -0
  162. package/dist/schema/queries.js +145 -0
  163. package/dist/schema/relation.d.ts +172 -0
  164. package/dist/schema/relation.js +104 -0
  165. package/dist/schema/schema.d.ts +259 -0
  166. package/dist/schema/schema.js +188 -0
  167. package/dist/schema/sugar.d.ts +129 -0
  168. package/dist/schema/sugar.js +94 -0
  169. package/dist/source/index.d.ts +423 -0
  170. package/dist/source/index.js +320 -0
  171. package/dist/source/pushQueue.d.ts +112 -0
  172. package/dist/source/pushQueue.js +249 -0
  173. package/dist/stores/ObjectStore.d.ts +103 -0
  174. package/dist/stores/ObjectStore.js +371 -0
  175. package/dist/stores/ObjectStoreContract.d.ts +39 -0
  176. package/dist/stores/ObjectStoreContract.js +1 -0
  177. package/dist/stores/SyncActionStore.d.ts +101 -0
  178. package/dist/stores/SyncActionStore.js +481 -0
  179. package/dist/sync/BootstrapHelper.d.ts +127 -0
  180. package/dist/sync/BootstrapHelper.js +434 -0
  181. package/dist/sync/ConnectionManager.d.ts +136 -0
  182. package/dist/sync/ConnectionManager.js +465 -0
  183. package/dist/sync/HydrationCoordinator.d.ts +137 -0
  184. package/dist/sync/HydrationCoordinator.js +468 -0
  185. package/dist/sync/NetworkProbe.d.ts +43 -0
  186. package/dist/sync/NetworkProbe.js +113 -0
  187. package/dist/sync/OfflineFlush.d.ts +9 -0
  188. package/dist/sync/OfflineFlush.js +22 -0
  189. package/dist/sync/OfflineTransactionStore.d.ts +37 -0
  190. package/dist/sync/OfflineTransactionStore.js +263 -0
  191. package/dist/sync/SyncWebSocket.d.ts +663 -0
  192. package/dist/sync/SyncWebSocket.js +1336 -0
  193. package/dist/sync/createIntentStream.d.ts +33 -0
  194. package/dist/sync/createIntentStream.js +243 -0
  195. package/dist/sync/createPresenceStream.d.ts +46 -0
  196. package/dist/sync/createPresenceStream.js +192 -0
  197. package/dist/sync/createSnapshot.d.ts +33 -0
  198. package/dist/sync/createSnapshot.js +124 -0
  199. package/dist/sync/participants.d.ts +114 -0
  200. package/dist/sync/participants.js +336 -0
  201. package/dist/sync/schemas.d.ts +79 -0
  202. package/dist/sync/schemas.js +78 -0
  203. package/dist/testing/fixtures/bootstrap.d.ts +45 -0
  204. package/dist/testing/fixtures/bootstrap.js +53 -0
  205. package/dist/testing/fixtures/deltas.d.ts +86 -0
  206. package/dist/testing/fixtures/deltas.js +139 -0
  207. package/dist/testing/fixtures/models.d.ts +82 -0
  208. package/dist/testing/fixtures/models.js +270 -0
  209. package/dist/testing/helpers/react-wrapper.d.ts +66 -0
  210. package/dist/testing/helpers/react-wrapper.js +64 -0
  211. package/dist/testing/helpers/sync-engine-harness.d.ts +55 -0
  212. package/dist/testing/helpers/sync-engine-harness.js +70 -0
  213. package/dist/testing/helpers/wait.d.ts +25 -0
  214. package/dist/testing/helpers/wait.js +44 -0
  215. package/dist/testing/index.d.ts +21 -0
  216. package/dist/testing/index.js +32 -0
  217. package/dist/testing/mocks/MockMutationExecutor.d.ts +65 -0
  218. package/dist/testing/mocks/MockMutationExecutor.js +139 -0
  219. package/dist/testing/mocks/MockNetworkMonitor.d.ts +20 -0
  220. package/dist/testing/mocks/MockNetworkMonitor.js +46 -0
  221. package/dist/testing/mocks/MockSyncContext.d.ts +64 -0
  222. package/dist/testing/mocks/MockSyncContext.js +100 -0
  223. package/dist/testing/mocks/MockSyncStore.d.ts +88 -0
  224. package/dist/testing/mocks/MockSyncStore.js +171 -0
  225. package/dist/testing/mocks/MockWebSocket.d.ts +66 -0
  226. package/dist/testing/mocks/MockWebSocket.js +117 -0
  227. package/dist/transactions/OptimisticEchoTracker.d.ts +82 -0
  228. package/dist/transactions/OptimisticEchoTracker.js +104 -0
  229. package/dist/transactions/TransactionQueue.d.ts +499 -0
  230. package/dist/transactions/TransactionQueue.js +1895 -0
  231. package/dist/transactions/index.d.ts +16 -0
  232. package/dist/transactions/index.js +7 -0
  233. package/dist/transactions/mutation-error-handler.d.ts +5 -0
  234. package/dist/transactions/mutation-error-handler.js +39 -0
  235. package/dist/types/global.d.ts +107 -0
  236. package/dist/types/global.js +38 -0
  237. package/dist/types/index.d.ts +241 -0
  238. package/dist/types/index.js +70 -0
  239. package/dist/types/streams.d.ts +495 -0
  240. package/dist/types/streams.js +11 -0
  241. package/dist/utils/asyncIterator.d.ts +41 -0
  242. package/dist/utils/asyncIterator.js +142 -0
  243. package/dist/utils/duration.d.ts +28 -0
  244. package/dist/utils/duration.js +47 -0
  245. package/dist/utils/mobx-setup.d.ts +42 -0
  246. package/dist/utils/mobx-setup.js +381 -0
  247. package/docs/api-keys.md +24 -0
  248. package/docs/api.md +230 -0
  249. package/docs/audit.md +81 -0
  250. package/docs/capabilities.md +163 -0
  251. package/docs/client-behavior.md +202 -0
  252. package/docs/data-sources.md +214 -0
  253. package/docs/examples/agent-human.md +84 -0
  254. package/docs/examples/ai-sdk-tool.md +92 -0
  255. package/docs/examples/existing-python-backend.md +249 -0
  256. package/docs/examples/nextjs.md +88 -0
  257. package/docs/examples/server-agent.md +86 -0
  258. package/docs/guarantees.md +148 -0
  259. package/docs/index.md +97 -0
  260. package/docs/integration-guide.md +493 -0
  261. package/docs/interaction-model.md +140 -0
  262. package/docs/mcp/claude-code.md +43 -0
  263. package/docs/mcp/cursor.md +53 -0
  264. package/docs/mcp/windsurf.md +46 -0
  265. package/docs/mcp.md +59 -0
  266. package/docs/quickstart.md +152 -0
  267. package/docs/react.md +115 -0
  268. package/docs/roadmap.md +45 -0
  269. package/examples/README.md +54 -0
  270. package/examples/data-source/README.md +102 -0
  271. package/examples/data-source/ablo-driver.ts +89 -0
  272. package/examples/data-source/customer-server.ts +208 -0
  273. package/examples/data-source/run.ts +101 -0
  274. package/examples/data-source/schema.ts +25 -0
  275. package/examples/quickstart.ts +54 -0
  276. package/examples/tsconfig.json +16 -0
  277. package/llms.txt +143 -0
  278. package/package.json +147 -0
@@ -0,0 +1,43 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ /**
4
+ * Neutral loading placeholder — the default value of `<AbloProvider>`'s
5
+ * `fallback` prop. Rendered during the first bootstrap pass when the
6
+ * consumer hasn't supplied their own skeleton.
7
+ *
8
+ * Design goals:
9
+ * - Zero design-system dependency. Inline styles only; no CSS file,
10
+ * no UI-lib imports, no Tailwind assumptions.
11
+ * - Theme-adaptive. Uses `currentColor` for the ring so the spinner
12
+ * inherits the text color from whichever ancestor defines it —
13
+ * works in light + dark contexts without a prop.
14
+ * - Self-centering. Flex-centered in a full-parent container so the
15
+ * common case (provider at the layout root) renders a spinner in
16
+ * the middle of the viewport. Consumers who need different
17
+ * positioning compose their own fallback and pass it explicitly.
18
+ * - Minimal bundle footprint. The whole component + keyframe is ~50
19
+ * bytes gzipped.
20
+ *
21
+ * Consumers wanting a branded loader should pass `fallback={<YourSkeleton />}`
22
+ * on `<AbloProvider>`. Consumers wanting NO visual during bootstrap
23
+ * pass `fallback={null}`. Consumers who want to skip the gate entirely
24
+ * pass `fallback="passthrough"`.
25
+ */
26
+ export function DefaultFallback() {
27
+ return (_jsxs("div", { role: "status", "aria-live": "polite", "aria-label": "Loading", style: {
28
+ display: 'flex',
29
+ alignItems: 'center',
30
+ justifyContent: 'center',
31
+ width: '100%',
32
+ minHeight: '100vh',
33
+ color: 'currentColor',
34
+ }, children: [_jsx("div", { style: {
35
+ width: 24,
36
+ height: 24,
37
+ border: '2px solid currentColor',
38
+ borderTopColor: 'transparent',
39
+ borderRadius: '50%',
40
+ opacity: 0.6,
41
+ animation: 'ablo-default-fallback-spin 0.8s linear infinite',
42
+ } }), _jsx("style", { children: `@keyframes ablo-default-fallback-spin { to { transform: rotate(360deg); } }` })] }));
43
+ }
@@ -0,0 +1,19 @@
1
+ import { type ReactNode } from 'react';
2
+ export interface SyncGroupProviderProps {
3
+ /** The sync-group identifier — e.g., `matter:abc-123`, `deck:xyz`. */
4
+ id: string;
5
+ children: ReactNode;
6
+ }
7
+ export declare function SyncGroupProvider({ id, children }: SyncGroupProviderProps): import("react/jsx-runtime").JSX.Element;
8
+ /**
9
+ * Returns the ID of the nearest `<SyncGroupProvider>`. Throws if
10
+ * called outside one — sync-group awareness is mandatory by design,
11
+ * so the error points the consumer at the provider instead of
12
+ * returning undefined and letting downstream code silently miss scope.
13
+ *
14
+ * If a component legitimately renders both inside and outside a
15
+ * group, structure the tree so the hook is only called on the
16
+ * inside path (e.g., split into two components). Silent nulls are
17
+ * never the right answer.
18
+ */
19
+ export declare function useSyncGroup(): string;
@@ -0,0 +1,44 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { createContext, useContext, useMemo } from 'react';
4
+ import { AbloValidationError } from '../errors.js';
5
+ /**
6
+ * Narrow context for a per-entity sync-group scope. Maps directly onto
7
+ * Liveblocks' `<RoomProvider id="...">`: wrap a subtree, and any hooks
8
+ * inside can read `useSyncGroup()` to discover "which entity am I
9
+ * scoped to?" without threading the ID through props.
10
+ *
11
+ * Typical IDs follow the multiplayer sync-group convention: `matter:<id>`,
12
+ * `deck:<id>`, `project:<id>`. The ID is an opaque string — the
13
+ * provider doesn't parse it.
14
+ *
15
+ * v0.3.0 scope: this is a thin passthrough. Future versions will
16
+ * scope `useQuery` / `useOne` results to the group automatically.
17
+ */
18
+ const SyncGroupContext = createContext(null);
19
+ export function SyncGroupProvider({ id, children }) {
20
+ // Stabilize the context value so consumers memoized on it don't
21
+ // re-render when the provider re-renders for unrelated reasons.
22
+ const value = useMemo(() => id, [id]);
23
+ return _jsx(SyncGroupContext.Provider, { value: value, children: children });
24
+ }
25
+ /**
26
+ * Returns the ID of the nearest `<SyncGroupProvider>`. Throws if
27
+ * called outside one — sync-group awareness is mandatory by design,
28
+ * so the error points the consumer at the provider instead of
29
+ * returning undefined and letting downstream code silently miss scope.
30
+ *
31
+ * If a component legitimately renders both inside and outside a
32
+ * group, structure the tree so the hook is only called on the
33
+ * inside path (e.g., split into two components). Silent nulls are
34
+ * never the right answer.
35
+ */
36
+ export function useSyncGroup() {
37
+ const id = useContext(SyncGroupContext);
38
+ if (!id) {
39
+ throw new AbloValidationError('useSyncGroup: no <SyncGroupProvider> mounted above this component. ' +
40
+ 'Wrap your tree with <SyncGroupProvider id="matter:..."> from ' +
41
+ '@ablo/sync-engine/react.', { code: 'no_sync_group_provider' });
42
+ }
43
+ return id;
44
+ }
@@ -0,0 +1,161 @@
1
+ import { type ReactNode } from 'react';
2
+ import type { Model } from '../Model.js';
3
+ import type { ModelScope } from '../types/index.js';
4
+ import type { QueryView, QueryViewOptions } from '../core/QueryView.js';
5
+ import type { ViewRegistry } from '../core/ViewRegistry.js';
6
+ import type { Schema } from '../schema/schema.js';
7
+ import type { SyncStatus } from '../BaseSyncedStore.js';
8
+ /**
9
+ * Minimal store interface that the SDK hooks need.
10
+ * Consumers provide their concrete store (e.g., SyncedStore) that implements this.
11
+ */
12
+ export interface SyncStoreContract {
13
+ retrieve(modelClass: abstract new (...args: never[]) => Model, id: string): Model | undefined;
14
+ queryByClass(modelClass: abstract new (...args: never[]) => Model, options?: {
15
+ predicate?: (model: Model) => boolean;
16
+ scope?: ModelScope;
17
+ orderBy?: keyof Model;
18
+ order?: 'asc' | 'desc';
19
+ limit?: number;
20
+ offset?: number;
21
+ }): {
22
+ data: Model[];
23
+ };
24
+ /**
25
+ * Save (create or update) one entity. Calling `save` in a tight loop
26
+ * produces a single wire commit with one `batchIndex`: the SyncClient
27
+ * debounces IDB persistence and the server push to one microtask, and
28
+ * TransactionQueue coalesces every transaction staged in the tick into
29
+ * one batch. There is intentionally no `saveMany` — Zero, Replicache,
30
+ * and the rest of the local-first lineage all expose one-row writes
31
+ * and rely on the implicit tick boundary.
32
+ *
33
+ * `skipValidation` exists for trusted bulk paths (AI sandbox layer
34
+ * generation, PPTX import, hydration) where the producer has already
35
+ * type-checked and per-row Zod is a measurable cost.
36
+ */
37
+ save(model: Model, options?: {
38
+ skipValidation?: boolean;
39
+ }): Promise<void>;
40
+ delete(model: Model): Promise<void>;
41
+ archive(model: Model): Promise<void>;
42
+ unarchive(model: Model): Promise<void>;
43
+ /** The ObjectPool — for entity/collection lookups by ID or typename. */
44
+ pool: {
45
+ get(id: string): Model | undefined;
46
+ getByTypeName(typename: string, scope?: ModelScope): Model[];
47
+ getByForeignKey(modelName: string, fieldName: string, fieldValue: string): Model[];
48
+ createFromData(data: Record<string, unknown>): Model | null;
49
+ hasForeignKeyIndex(typename: string, fieldName: string): boolean;
50
+ createView<T extends Record<string, unknown>>(typename: string, options?: QueryViewOptions<T>): QueryView<T>;
51
+ viewRegistry: ViewRegistry;
52
+ };
53
+ /**
54
+ * Reactive sync-status getters. Powered by MobX `computed` inside
55
+ * `BaseSyncedStore`, so they're safe to read in `observer` components
56
+ * and inside `reaction(() => store.isReady, ...)`. Consumers that
57
+ * don't want to touch MobX should prefer the `useSyncStatus()` hook.
58
+ */
59
+ readonly isReady: boolean;
60
+ readonly isSyncing: boolean;
61
+ readonly isOffline: boolean;
62
+ readonly isReconnecting: boolean;
63
+ readonly isError: boolean;
64
+ readonly hasUnsyncedChanges: boolean;
65
+ /**
66
+ * Raw MobX-observable `SyncStatus` record. `useSyncStatus()` reads
67
+ * `state`, `progress`, `pendingChanges`, `isSessionError`, `error`
68
+ * from this to build its tagged union. Exposed on the contract so
69
+ * consumer-facing hooks and test doubles can manipulate it directly.
70
+ */
71
+ readonly syncStatus: SyncStatus;
72
+ }
73
+ export interface SyncReactContext {
74
+ store: SyncStoreContract;
75
+ /** Current organization ID for default entity context */
76
+ organizationId: string;
77
+ /**
78
+ * Optional schema reference. When set, compatibility hook overloads
79
+ * (`useQuery('tasks')`, `useOne('tasks', id)`, etc.) resolve their
80
+ * model metadata from this schema — consumers don't pass `schema` at
81
+ * every call site. When absent, hooks fall back to the legacy
82
+ * `(schema, modelKey, …)` signatures so non-opting consumers keep
83
+ * working unchanged.
84
+ *
85
+ * The stored reference is untyped here (`Schema` with default
86
+ * parameters) because the React context is a single runtime value
87
+ * shared by every hook. The compile-time types flow from the
88
+ * consumer's `declare global { interface AbloSync { Schema: ... } }`
89
+ * augmentation — see `src/types/global.ts`.
90
+ */
91
+ schema?: Schema;
92
+ /**
93
+ * Optional presence source. When set, `usePresence()` returns this
94
+ * value cast to the consumer's `ResolvePresence` type (declared via
95
+ * `interface AbloSync { Presence: ... }`). The SDK doesn't own a
96
+ * presence wire format — consumers plug whatever backs their cursors,
97
+ * status, or activity state (a MobX store, a Zustand slice, a custom
98
+ * subscription). The typed-global gives it a call-site-ergonomic
99
+ * type without the SDK dictating the transport.
100
+ */
101
+ presence?: unknown;
102
+ /**
103
+ * Optional intent initiator. Same pattern as presence — consumers
104
+ * plug a function that turns an intent claim into a handle they
105
+ * control (WebSocket send, optimistic local update, whatever).
106
+ * `useIntent(name)` returns a typed invoker for the named intent
107
+ * from `interface AbloSync { Intents: ... }`.
108
+ */
109
+ beginIntent?: (intentName: string, claim: unknown) => unknown;
110
+ }
111
+ export declare const SyncContext: import("react").Context<SyncReactContext | null>;
112
+ /**
113
+ * Access the sync store from React components.
114
+ * Must be used within a SyncProvider.
115
+ */
116
+ export declare function useSyncContext(): SyncReactContext;
117
+ /**
118
+ * Props for SyncProvider.
119
+ */
120
+ export interface SyncProviderProps {
121
+ /** The sync store (must implement SyncStoreContract). */
122
+ store: SyncStoreContract;
123
+ /** Current organization ID for default entity context. */
124
+ organizationId: string;
125
+ /**
126
+ * Optional schema. Wire this when you want compatibility string-keyed hooks
127
+ * (`useQuery('tasks')`) — the schema type also narrows via the
128
+ * consumer's global `AbloSync` declaration. Omit to keep hooks on
129
+ * their legacy `(schema, modelKey, …)` signatures.
130
+ */
131
+ schema?: Schema;
132
+ /**
133
+ * Optional presence source for `usePresence()`. See
134
+ * {@link SyncReactContext.presence} — the consumer plugs whatever
135
+ * backs their presence state; the hook returns it with
136
+ * `ResolvePresence` typing.
137
+ */
138
+ presence?: unknown;
139
+ /**
140
+ * Optional intent initiator for `useIntent()`. See
141
+ * {@link SyncReactContext.beginIntent}.
142
+ */
143
+ beginIntent?: (intentName: string, claim: unknown) => unknown;
144
+ children?: ReactNode;
145
+ }
146
+ /**
147
+ * SyncProvider wires the sync store into React so SDK hooks
148
+ * (useModel, useModels, useMutations) can access it.
149
+ *
150
+ * @example
151
+ * import { SyncProvider } from '@ablo/sync-engine/react';
152
+ *
153
+ * function App() {
154
+ * return (
155
+ * <SyncProvider store={syncStore} organizationId={orgId}>
156
+ * <YourApp />
157
+ * </SyncProvider>
158
+ * );
159
+ * }
160
+ */
161
+ export declare function SyncProvider({ store, organizationId, schema, presence, beginIntent, children, }: SyncProviderProps): import("react").FunctionComponentElement<import("react").ProviderProps<SyncReactContext | null>>;
@@ -0,0 +1,35 @@
1
+ 'use client';
2
+ import { createContext, createElement, useContext } from 'react';
3
+ import { AbloValidationError } from '../errors.js';
4
+ export const SyncContext = createContext(null);
5
+ /**
6
+ * Access the sync store from React components.
7
+ * Must be used within a SyncProvider.
8
+ */
9
+ export function useSyncContext() {
10
+ const ctx = useContext(SyncContext);
11
+ if (!ctx) {
12
+ throw new AbloValidationError('useSyncContext must be used within a SyncProvider', {
13
+ code: 'sync_context_missing_provider',
14
+ });
15
+ }
16
+ return ctx;
17
+ }
18
+ /**
19
+ * SyncProvider wires the sync store into React so SDK hooks
20
+ * (useModel, useModels, useMutations) can access it.
21
+ *
22
+ * @example
23
+ * import { SyncProvider } from '@ablo/sync-engine/react';
24
+ *
25
+ * function App() {
26
+ * return (
27
+ * <SyncProvider store={syncStore} organizationId={orgId}>
28
+ * <YourApp />
29
+ * </SyncProvider>
30
+ * );
31
+ * }
32
+ */
33
+ export function SyncProvider({ store, organizationId, schema, presence, beginIntent, children, }) {
34
+ return createElement(SyncContext.Provider, { value: { store, organizationId, schema, presence, beginIntent } }, children);
35
+ }
@@ -0,0 +1,64 @@
1
+ /**
2
+ * @ablo/sync-engine/react — React bindings (v0.3.0)
3
+ *
4
+ * Umbrella provider:
5
+ * <AbloProvider schema={...} userId={...} orgId={...} fallback={<Skeleton/>}>
6
+ * — owns sync engine + multiplayer lifecycle; the `fallback` prop
7
+ * gates children on first bootstrap. Pass `fallback="passthrough"`
8
+ * to disable the gate.
9
+ * <SyncGroupProvider id="matter:..."> — per-entity scope
10
+ * <ClientSideSuspense fallback={<Skeleton/>}> — NESTED gate inside an
11
+ * already-ready provider. Use only when you need a separate gate
12
+ * for a heavy subtree (e.g. a canvas) while app chrome renders
13
+ * immediately. The provider-level `fallback` is the default path.
14
+ *
15
+ * Data hooks:
16
+ * useAblo((ablo) => ablo.tasks.retrieve(id)) — primary React read API
17
+ * useAblo() — typed client for callbacks/effects
18
+ * useQuery/useOne/useReader/useMutate — compatibility helpers for older
19
+ * string-keyed integrations
20
+ * useMutators(defs, opts?) — Zero-style custom mutators
21
+ * useUndoScope(name) — per-surface undo/redo
22
+ *
23
+ * Status + errors:
24
+ * useSyncStatus() — tagged-union lifecycle snapshot
25
+ * useErrorListener(cb) — imperative error callback (Sentry/Datadog)
26
+ * useCurrentUserId() — the provider's userId prop
27
+ *
28
+ * Multiplayer (always available — `<AbloProvider>` always constructs a client):
29
+ * useAblo((ablo) => ablo.intents.list(...)) — reactive coordination reads
30
+ * useParticipant({ scope }) — join multiplayer for a scope, get peers/claims
31
+ * usePresence() — typed presence view
32
+ * useIntent(name) — typed intent dispatcher
33
+ *
34
+ * ── Breaking changes from v0.2.x ───────────────────────────────────
35
+ * Removed: <SyncProvider>, SyncContext, useSyncContext — folded into
36
+ * <AbloProvider>. Access the raw engine with `useSync()`.
37
+ * Removed: createAbloContext() factory + its returned AbloProvider —
38
+ * multiplayer is now always-on inside <AbloProvider>. Schema-typed
39
+ * participant hooks ship in a follow-up release.
40
+ * Removed: withSync (no-op alias of observer). Import observer
41
+ * from mobx-react-lite directly if you still need it.
42
+ * Changed: useSyncStatus() now returns a discriminated union. See the
43
+ * migration notes in CHANGELOG.md.
44
+ */
45
+ export type { DefaultSyncShape, ResolveSchema, ResolvePresence, ResolveIntents, ResolveUserMeta, ResolveModelKey, } from '../types/global.js';
46
+ export { AbloProvider, useParticipant, useSync, useSyncStore, type AbloProviderProps, type ParticipantScope, type ParticipantStatus, type UseParticipantOptions, type UseParticipantReturn, type MeshParticipantStatus, } from './AbloProvider.js';
47
+ export { SyncGroupProvider, useSyncGroup, type SyncGroupProviderProps, } from './SyncGroupProvider.js';
48
+ export { ClientSideSuspense, type ClientSideSuspenseProps, } from './ClientSideSuspense.js';
49
+ export { DefaultFallback } from './DefaultFallback.js';
50
+ export type { SyncStoreContract } from './context.js';
51
+ export { useSyncStatus, type SyncStatusSnapshot, } from './useSyncStatus.js';
52
+ export { useErrorListener } from './useErrorListener.js';
53
+ export { useMutationFailureListener, type MutationFailurePayload, } from './useMutationFailureListener.js';
54
+ export { useCurrentUserId } from './useCurrentUserId.js';
55
+ export { useReactive } from './useReactive.js';
56
+ export { useQuery, useOne, type QueryOptions } from './useQuery.js';
57
+ export { useMutate, type MutateActions } from './useMutate.js';
58
+ export { useReader, type ReaderActions, type ReaderFindOptions } from './useReader.js';
59
+ export { useMutators, type MutatorInvokers, type InvokerFor, type UseMutatorsOptions, } from './useMutators.js';
60
+ export { useUndoScope, type UseUndoScopeResult } from './useUndoScope.js';
61
+ export { useAblo, type UseAbloHydratedModelResult, type UseAbloModelOptions, type UseAbloModelResult, } from './useAblo.js';
62
+ export { usePresence } from './usePresence.js';
63
+ export { useIntent } from './useIntent.js';
64
+ export { ModelScope } from '../types/index.js';
@@ -0,0 +1,73 @@
1
+ /**
2
+ * @ablo/sync-engine/react — React bindings (v0.3.0)
3
+ *
4
+ * Umbrella provider:
5
+ * <AbloProvider schema={...} userId={...} orgId={...} fallback={<Skeleton/>}>
6
+ * — owns sync engine + multiplayer lifecycle; the `fallback` prop
7
+ * gates children on first bootstrap. Pass `fallback="passthrough"`
8
+ * to disable the gate.
9
+ * <SyncGroupProvider id="matter:..."> — per-entity scope
10
+ * <ClientSideSuspense fallback={<Skeleton/>}> — NESTED gate inside an
11
+ * already-ready provider. Use only when you need a separate gate
12
+ * for a heavy subtree (e.g. a canvas) while app chrome renders
13
+ * immediately. The provider-level `fallback` is the default path.
14
+ *
15
+ * Data hooks:
16
+ * useAblo((ablo) => ablo.tasks.retrieve(id)) — primary React read API
17
+ * useAblo() — typed client for callbacks/effects
18
+ * useQuery/useOne/useReader/useMutate — compatibility helpers for older
19
+ * string-keyed integrations
20
+ * useMutators(defs, opts?) — Zero-style custom mutators
21
+ * useUndoScope(name) — per-surface undo/redo
22
+ *
23
+ * Status + errors:
24
+ * useSyncStatus() — tagged-union lifecycle snapshot
25
+ * useErrorListener(cb) — imperative error callback (Sentry/Datadog)
26
+ * useCurrentUserId() — the provider's userId prop
27
+ *
28
+ * Multiplayer (always available — `<AbloProvider>` always constructs a client):
29
+ * useAblo((ablo) => ablo.intents.list(...)) — reactive coordination reads
30
+ * useParticipant({ scope }) — join multiplayer for a scope, get peers/claims
31
+ * usePresence() — typed presence view
32
+ * useIntent(name) — typed intent dispatcher
33
+ *
34
+ * ── Breaking changes from v0.2.x ───────────────────────────────────
35
+ * Removed: <SyncProvider>, SyncContext, useSyncContext — folded into
36
+ * <AbloProvider>. Access the raw engine with `useSync()`.
37
+ * Removed: createAbloContext() factory + its returned AbloProvider —
38
+ * multiplayer is now always-on inside <AbloProvider>. Schema-typed
39
+ * participant hooks ship in a follow-up release.
40
+ * Removed: withSync (no-op alias of observer). Import observer
41
+ * from mobx-react-lite directly if you still need it.
42
+ * Changed: useSyncStatus() now returns a discriminated union. See the
43
+ * migration notes in CHANGELOG.md.
44
+ */
45
+ // ── Umbrella provider + lifecycle hooks ────────────────────────────
46
+ export { AbloProvider, useParticipant, useSync, useSyncStore, } from './AbloProvider.js';
47
+ export { SyncGroupProvider, useSyncGroup, } from './SyncGroupProvider.js';
48
+ export { ClientSideSuspense, } from './ClientSideSuspense.js';
49
+ export { DefaultFallback } from './DefaultFallback.js';
50
+ // ── Status + errors + identity ─────────────────────────────────────
51
+ export { useSyncStatus, } from './useSyncStatus.js';
52
+ export { useErrorListener } from './useErrorListener.js';
53
+ export { useMutationFailureListener, } from './useMutationFailureListener.js';
54
+ export { useCurrentUserId } from './useCurrentUserId.js';
55
+ // ── Primitive for building custom reactive hooks ──────────────────
56
+ //
57
+ // Consumers building bespoke hooks on top of the SDK should call
58
+ // `useReactive(() => compute())` instead of reaching for React's
59
+ // lower-level `useSyncExternalStore`. Hides the cached-snapshot
60
+ // contract and handles default structural equality for arrays.
61
+ export { useReactive } from './useReactive.js';
62
+ // ── Data hooks ─────────────────────────────────────────────────────
63
+ export { useQuery, useOne } from './useQuery.js';
64
+ export { useMutate } from './useMutate.js';
65
+ export { useReader } from './useReader.js';
66
+ export { useMutators, } from './useMutators.js';
67
+ export { useUndoScope } from './useUndoScope.js';
68
+ export { useAblo, } from './useAblo.js';
69
+ // ── Presence + intent (typed via AbloSync global augmentation) ─────
70
+ export { usePresence } from './usePresence.js';
71
+ export { useIntent } from './useIntent.js';
72
+ // ── ModelScope re-export ───────────────────────────────────────────
73
+ export { ModelScope } from '../types/index.js';
@@ -0,0 +1,35 @@
1
+ import type { Ablo } from '../client/Ablo.js';
2
+ import type { SchemaRecord } from '../schema/schema.js';
3
+ /**
4
+ * Internal context populated by `<AbloProvider>`. Separate from
5
+ * `SyncContext` (which carries the store + schema for the data
6
+ * hooks) because these fields are owned by the umbrella provider
7
+ * and don't belong on the raw `SyncStoreContract`.
8
+ *
9
+ * Consumers should NOT use this directly — access the fields via
10
+ * the typed hooks (`useCurrentUserId`, `useErrorListener`, etc.).
11
+ */
12
+ export interface AbloInternalContextValue {
13
+ /**
14
+ * Optional app user id when the application passed one. Hosted Ablo
15
+ * identity is server-derived, so this may be null.
16
+ */
17
+ currentUserId: string | null;
18
+ /** Subscribe to provider-level errors (engine errors, bootstrap failures, session issues). */
19
+ subscribeError: (listener: (error: Error) => void) => () => void;
20
+ /** Fire an error to all subscribed listeners. Called internally by the provider. */
21
+ emitError: (error: Error) => void;
22
+ /**
23
+ * The SyncEngine proxy for this provider. `null` before bootstrap
24
+ * resolves. Exposed through the internal context so `useSync()`
25
+ * can return it without having to reach into the store — the two
26
+ * are sibling objects constructed together by `createSyncEngine`
27
+ * and shouldn't be coerced through each other.
28
+ *
29
+ * Typed as `Ablo<SchemaRecord>` on the context because
30
+ * generics don't flow through React context. `useSync<R>()` widens
31
+ * via its own generic — runtime value is the concrete engine.
32
+ */
33
+ engine: Ablo<SchemaRecord> | null;
34
+ }
35
+ export declare const AbloInternalContext: import("react").Context<AbloInternalContextValue | null>;
@@ -0,0 +1,3 @@
1
+ 'use client';
2
+ import { createContext } from 'react';
3
+ export const AbloInternalContext = createContext(null);
@@ -0,0 +1,72 @@
1
+ import type { Ablo, ResourceIntent } from '../client/Ablo.js';
2
+ import type { ModelOperations } from '../client/createModelProxy.js';
3
+ import type { SchemaRecord } from '../schema/schema.js';
4
+ import type { ResolveSchema } from '../types/global.js';
5
+ /**
6
+ * Resolved schema-record type for the consumer's app. Reads the
7
+ * `AbloSync` global augmentation if declared, falls back to the
8
+ * loose `SchemaRecord` if not. This lets `useAblo()` produce a
9
+ * fully typed engine handle without the consumer having to pass
10
+ * `<(typeof schema)['models']>` at every call site.
11
+ */
12
+ type DefaultModels = ResolveSchema extends {
13
+ models: infer M;
14
+ } ? M extends SchemaRecord ? M : SchemaRecord : SchemaRecord;
15
+ type ModelResourceSelector<R extends SchemaRecord, T, C> = (ablo: Ablo<R>) => ModelOperations<T, C>;
16
+ type AbloSelector<R extends SchemaRecord, T> = (ablo: Ablo<R>) => T;
17
+ export interface UseAbloModelOptions<T> {
18
+ /**
19
+ * Initial row, usually from a Server Component or loader. The hook returns it
20
+ * until the model resource has a newer row in the local pool.
21
+ */
22
+ readonly initial?: T;
23
+ }
24
+ export interface UseAbloModelResult<T> {
25
+ /** Current row for the id, or `initial` until the row has hydrated. */
26
+ readonly data: T | undefined;
27
+ /** Active work claims on this model row. */
28
+ readonly intents: readonly ResourceIntent[];
29
+ /** Convenience flag for disabling UI while another participant is active. */
30
+ readonly busy: boolean;
31
+ }
32
+ export type UseAbloHydratedModelResult<T> = Omit<UseAbloModelResult<T>, 'data'> & {
33
+ readonly data: T;
34
+ };
35
+ /**
36
+ * useAblo — access the typed engine instance, or subscribe to a specific
37
+ * `ablo.<model>` row from inside an `<AbloProvider>` subtree.
38
+ *
39
+ * Zero-arg when the consumer declares the `AbloSync` global
40
+ * augmentation (`declare global { interface AbloSync { Schema:
41
+ * typeof schema } }`). The default generic resolves through
42
+ * `ResolveSchema['models']` so call sites stay clean:
43
+ *
44
+ * ```ts
45
+ * // With AbloSync augmentation (recommended):
46
+ * const ablo = useAblo();
47
+ * if (!ablo) return <Loading />;
48
+ * const docs = await ablo.documents.load({ where: { id } });
49
+ *
50
+ * // Reactive selector:
51
+ * const doc = useAblo((ablo) => ablo.documents.retrieve(id)) ?? serverDoc;
52
+ * const intents = useAblo((ablo) => ablo.intents.list({ resource: 'documents', id }));
53
+ *
54
+ * // Without augmentation, pass the schema generic:
55
+ * const ablo = useAblo<(typeof schema)['models']>();
56
+ * ```
57
+ *
58
+ * Returns `null` while the engine is bootstrapping. Branch on null
59
+ * and render a loading state (or use `useSyncStatus()` to gate on
60
+ * `'connected'`) before reaching for model methods.
61
+ */
62
+ export declare function useAblo<R extends SchemaRecord = DefaultModels>(): Ablo<R> | null;
63
+ export declare function useAblo<R extends SchemaRecord = DefaultModels, T = unknown>(select: AbloSelector<R, T>): T | undefined;
64
+ export declare function useAblo<T, C>(resource: ModelOperations<T, C>, id: string, options: UseAbloModelOptions<T> & {
65
+ readonly initial: T;
66
+ }): UseAbloHydratedModelResult<T>;
67
+ export declare function useAblo<R extends SchemaRecord = DefaultModels, T = Record<string, unknown>, C = unknown>(select: ModelResourceSelector<R, T, C>, id: string, options: UseAbloModelOptions<T> & {
68
+ readonly initial: T;
69
+ }): UseAbloHydratedModelResult<T>;
70
+ export declare function useAblo<T, C>(resource: ModelOperations<T, C>, id: string, options?: UseAbloModelOptions<T>): UseAbloModelResult<T>;
71
+ export declare function useAblo<R extends SchemaRecord = DefaultModels, T = Record<string, unknown>, C = unknown>(select: ModelResourceSelector<R, T, C>, id: string, options?: UseAbloModelOptions<T>): UseAbloModelResult<T>;
72
+ export {};
@@ -0,0 +1,63 @@
1
+ 'use client';
2
+ import { useContext, useEffect, useState } from 'react';
3
+ import { AbloInternalContext } from './internalContext.js';
4
+ import { getModelResourceMeta } from '../client/createModelProxy.js';
5
+ import { Model, modelAsRow } from '../Model.js';
6
+ import { useReactive } from './useReactive.js';
7
+ const EMPTY_INTENTS = Object.freeze([]);
8
+ function readModelResult(engine, resource, id, initial) {
9
+ if (!resource || id === undefined) {
10
+ return { data: initial, intents: EMPTY_INTENTS, busy: false };
11
+ }
12
+ const data = snapshotValue(resource.retrieve(id) ?? initial);
13
+ const meta = getModelResourceMeta(resource);
14
+ const intents = meta && engine
15
+ ? engine.intents.list({ resource: meta.key, id })
16
+ : EMPTY_INTENTS;
17
+ return { data, intents, busy: intents.length > 0 };
18
+ }
19
+ function snapshotValue(value) {
20
+ if (value instanceof Model) {
21
+ return modelAsRow(value);
22
+ }
23
+ if (Array.isArray(value)) {
24
+ return value.map((item) => snapshotValue(item));
25
+ }
26
+ return value;
27
+ }
28
+ export function useAblo(resourceOrSelect, id, options) {
29
+ const ctx = useContext(AbloInternalContext);
30
+ const engine = ctx?.engine ?? null;
31
+ const initial = options?.initial;
32
+ const hasSelection = resourceOrSelect !== undefined;
33
+ const isSelectorOnly = typeof resourceOrSelect === 'function' && id === undefined;
34
+ const resource = typeof resourceOrSelect === 'function' && id !== undefined
35
+ ? engine
36
+ ? resourceOrSelect(engine)
37
+ : undefined
38
+ : typeof resourceOrSelect === 'function'
39
+ ? undefined
40
+ : resourceOrSelect;
41
+ const [intentVersion, setIntentVersion] = useState(0);
42
+ useEffect(() => {
43
+ if (!engine || !hasSelection)
44
+ return;
45
+ return engine.intents.subscribe(() => setIntentVersion((version) => version + 1));
46
+ }, [engine, hasSelection]);
47
+ const selected = useReactive(() => {
48
+ void intentVersion;
49
+ if (!engine || !isSelectorOnly || typeof resourceOrSelect !== 'function') {
50
+ return undefined;
51
+ }
52
+ return snapshotValue(resourceOrSelect(engine));
53
+ });
54
+ const modelResult = useReactive(() => {
55
+ void intentVersion;
56
+ return readModelResult(engine, resource, id, initial);
57
+ });
58
+ if (isSelectorOnly)
59
+ return selected;
60
+ if (resourceOrSelect)
61
+ return modelResult;
62
+ return engine;
63
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Returns the app user ID passed to the nearest `<AbloProvider>`, when
3
+ * the app chose to provide one.
4
+ *
5
+ * Hosted Ablo identity is resolved server-side from the API key, session,
6
+ * or capability token. This hook is only for app-owned fields like
7
+ * `assigneeId`; it is not required for Ablo sync to connect.
8
+ *
9
+ * Use this in leaf components that need the current user ID for
10
+ * mutation payloads, presence labels, permission checks, etc.
11
+ * @example
12
+ * function TaskRow({ id }) {
13
+ * const userId = useCurrentUserId();
14
+ * const ablo = useAblo();
15
+ * if (!userId) return null;
16
+ * return <button onClick={() => ablo?.tasks.update(id, { assigneeId: userId })}>
17
+ * Assign to me
18
+ * </button>;
19
+ * }
20
+ */
21
+ export declare function useCurrentUserId(): string | null;