@abloatai/humans 0.63.1 → 0.64.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Ablo.d.ts +4 -0
- package/dist/client.d.ts +11 -31
- package/dist/local/client/reactiveEngine.js +4 -5
- package/dist/{react/useSyncStatus.d.ts → local/client/status.d.ts} +4 -3
- package/dist/local/client/status.js +14 -0
- package/dist/local/client/storeLifecycle.js +2 -2
- package/dist/local/storeContract.d.ts +3 -4
- package/dist/presence/index.js +6 -2
- package/dist/react/AbloProvider.d.ts +57 -121
- package/dist/react/AbloProvider.js +49 -154
- package/dist/react/createAbloReact.d.ts +10 -32
- package/dist/react/createAbloReact.js +10 -54
- package/dist/react/internalContext.d.ts +3 -20
- package/dist/react/snapshot.d.ts +4 -0
- package/dist/react/snapshot.js +75 -0
- package/dist/react/useAblo.d.ts +27 -44
- package/dist/react/useAblo.js +39 -74
- package/dist/react/useMutators.d.ts +20 -17
- package/dist/react/usePresence.js +7 -6
- package/dist/react/useReactive.d.ts +12 -0
- package/dist/react/useReactive.js +57 -0
- package/dist/react/useUndoScope.d.ts +15 -29
- package/dist/react/useUndoScope.js +17 -0
- package/dist/react.d.ts +7 -19
- package/dist/react.js +7 -15
- package/package.json +4 -3
- package/src/Ablo.ts +5 -0
- package/src/client.ts +12 -31
- package/src/local/client/reactiveEngine.ts +4 -5
- package/src/local/client/status.ts +20 -0
- package/src/local/client/storeLifecycle.ts +2 -2
- package/src/local/storeContract.ts +3 -4
- package/src/presence/index.ts +6 -2
- package/src/react/AbloProvider.tsx +80 -255
- package/src/react/createAbloReact.ts +18 -99
- package/src/react/internalContext.ts +3 -20
- package/src/react/snapshot.ts +67 -0
- package/src/react/useAblo.ts +70 -136
- package/src/react/useMutators.ts +30 -26
- package/src/react/usePresence.ts +7 -12
- package/src/react/useReactive.ts +56 -0
- package/src/react/useUndoScope.ts +18 -14
- package/src/react.ts +7 -69
- package/dist/react/ClientSideSuspense.d.ts +0 -36
- package/dist/react/ClientSideSuspense.js +0 -17
- package/dist/react/useCurrentUserId.d.ts +0 -2
- package/dist/react/useCurrentUserId.js +0 -12
- package/dist/react/useErrorListener.d.ts +0 -2
- package/dist/react/useErrorListener.js +0 -14
- package/dist/react/useMutationFailureListener.d.ts +0 -8
- package/dist/react/useMutationFailureListener.js +0 -19
- package/dist/react/useSyncStatus.js +0 -48
- package/dist/useReactive.d.ts +0 -6
- package/dist/useReactive.js +0 -41
- package/src/react/ClientSideSuspense.tsx +0 -57
- package/src/react/useCurrentUserId.ts +0 -17
- package/src/react/useErrorListener.ts +0 -22
- package/src/react/useMutationFailureListener.ts +0 -34
- package/src/react/useSyncStatus.ts +0 -53
- package/src/useReactive.ts +0 -49
package/dist/Ablo.d.ts
CHANGED
|
@@ -86,6 +86,10 @@ import type * as _Global from '@abloatai/transaction/types/global';
|
|
|
86
86
|
* into one of the public subpaths.
|
|
87
87
|
*/
|
|
88
88
|
export declare namespace Ablo {
|
|
89
|
+
/** Payload delivered by the core client's onMutationFailure subscription. */
|
|
90
|
+
type MutationFailure = Parameters<Parameters<AbloClient<SchemaRecord>['onMutationFailure']>[0]>[0];
|
|
91
|
+
/** Current client lifecycle, also selected through React's useAblo. */
|
|
92
|
+
type Status = import('./local/client/status.js').ClientStatus;
|
|
89
93
|
type Options<S extends SchemaRecord = SchemaRecord> = AbloOptions<S>;
|
|
90
94
|
/**
|
|
91
95
|
* The read view of the client that `useAblo` selectors receive: model reads
|
package/dist/client.d.ts
CHANGED
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import type { Schema, SchemaRecord, Model, InferCreate, InferRow } from '@abloatai/transaction/schema/schema';
|
|
14
14
|
import type { InstanceCache } from './local/InstanceCache.js';
|
|
15
|
-
import type { SyncStoreContract } from './
|
|
15
|
+
import type { SyncStoreContract } from './local/storeContract.js';
|
|
16
16
|
import type { SyncWebSocket, CoreSyncEventMap } from './local/sync/SyncWebSocket.js';
|
|
17
|
-
import type {
|
|
17
|
+
import type { ClientStatus } from './local/client/status.js';
|
|
18
18
|
import type { ModelOperations } from './local/client/createModelOperations.js';
|
|
19
19
|
import type { ClaimResource, CommitResource } from '@abloatai/transaction/client/resources/httpResources';
|
|
20
20
|
import type { EffectiveAuthority } from '@abloatai/transaction/auth';
|
|
@@ -25,7 +25,9 @@ export type { LocalReadOptions } from './local/client/resourceTypes.js';
|
|
|
25
25
|
/** The typed sync engine client — one property per model in the schema */
|
|
26
26
|
export type AbloClient<S extends SchemaRecord> = {
|
|
27
27
|
readonly [K in keyof S & string]: ModelOperations<Model<Schema<S>, K>, InferCreate<Schema<S>, K>>;
|
|
28
|
-
} &
|
|
28
|
+
} & AbloCore<S>;
|
|
29
|
+
/** Core members stay intact even when the model schema is not registered. */
|
|
30
|
+
interface AbloCore<S extends SchemaRecord> {
|
|
29
31
|
/**
|
|
30
32
|
* Wait for the sync engine to finish its initial bootstrap.
|
|
31
33
|
* Resolves once entity data is loaded and the WebSocket is connected.
|
|
@@ -50,7 +52,7 @@ export type AbloClient<S extends SchemaRecord> = {
|
|
|
50
52
|
* acknowledged everything before continuing — for example, before
|
|
51
53
|
* navigating away, before triggering a server-side workflow, or in tests.
|
|
52
54
|
*
|
|
53
|
-
* Resolves when
|
|
55
|
+
* Resolves when all pending local changes are confirmed. If the engine is
|
|
54
56
|
* offline, this waits until reconnect + flush completes.
|
|
55
57
|
*
|
|
56
58
|
* ```ts
|
|
@@ -171,32 +173,10 @@ export type AbloClient<S extends SchemaRecord> = {
|
|
|
171
173
|
*/
|
|
172
174
|
waitForConfirmation(modelName: string, modelId: string): Promise<void>;
|
|
173
175
|
/**
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
* Single source of truth for "what's the sync engine doing?" Contains:
|
|
177
|
-
* - `state`: `'idle' | 'syncing' | 'error' | 'offline' | 'reconnecting'`
|
|
178
|
-
* - `progress`: 0-100 for bootstrap progress
|
|
179
|
-
* - `error?`: Error object when `state === 'error'`
|
|
180
|
-
* - `pendingChanges`: Number of unconfirmed mutations in the queue
|
|
181
|
-
* - `lastSyncAt?`: Timestamp of the last successful delta processing
|
|
182
|
-
* - `offlineSince?`: When the connection dropped
|
|
183
|
-
* - `isSessionError`: True when the error requires re-authentication
|
|
184
|
-
*
|
|
185
|
-
* React components using `observer()` re-render automatically when
|
|
186
|
-
* any field changes — no manual subscription or polling needed.
|
|
187
|
-
*
|
|
188
|
-
* ```tsx
|
|
189
|
-
* import { observer } from 'mobx-react-lite';
|
|
190
|
-
*
|
|
191
|
-
* const SyncIndicator = observer(() => {
|
|
192
|
-
* if (sync.syncStatus.state === 'syncing') return <Spinner />;
|
|
193
|
-
* if (sync.syncStatus.state === 'error') return <Error msg={sync.syncStatus.error} />;
|
|
194
|
-
* if (sync.syncStatus.state === 'offline') return <OfflineBadge />;
|
|
195
|
-
* return null;
|
|
196
|
-
* });
|
|
197
|
-
* ```
|
|
176
|
+
* Current connection and confirmation state. Available before ready().
|
|
177
|
+
* React reads the same value with `useAblo(ablo => ablo.status)`.
|
|
198
178
|
*/
|
|
199
|
-
readonly
|
|
179
|
+
readonly status: ClientStatus;
|
|
200
180
|
/**
|
|
201
181
|
* Session-owned live activity projected from this client's existing
|
|
202
182
|
* connection. Use `active` for every visible activity, `others` to exclude
|
|
@@ -243,7 +223,7 @@ export type AbloClient<S extends SchemaRecord> = {
|
|
|
243
223
|
* no window in which this is absent and nothing needs to guard for one.
|
|
244
224
|
*/
|
|
245
225
|
readonly _ws: SyncWebSocket;
|
|
246
|
-
}
|
|
226
|
+
}
|
|
247
227
|
/**
|
|
248
228
|
* The reactive-read client a `useAblo` selector receives. The same surface as
|
|
249
229
|
* {@link AbloClient}, except model reads are typed as reactive rows
|
|
@@ -253,6 +233,6 @@ export type AbloClient<S extends SchemaRecord> = {
|
|
|
253
233
|
* compile error here instead of a silent runtime `undefined`; compose
|
|
254
234
|
* relations through selectors or hooks that resolve the pool's instance.
|
|
255
235
|
*/
|
|
256
|
-
export type AbloReads<S extends SchemaRecord> =
|
|
236
|
+
export type AbloReads<S extends SchemaRecord> = AbloCore<S> & {
|
|
257
237
|
readonly [K in keyof S & string]: ModelOperations<InferRow<Schema<S>, K>, InferCreate<Schema<S>, K>>;
|
|
258
238
|
};
|
|
@@ -15,6 +15,7 @@ import { omittedModelError } from '@abloatai/transaction/schema/select';
|
|
|
15
15
|
import { durableCommitOperationSchema, } from '@abloatai/transaction/commit';
|
|
16
16
|
import { AbloConnectionError, AbloValidationError, claimedError } from '@abloatai/transaction/errors';
|
|
17
17
|
import { batchFence, claimIdFor, fenceTokenFor, modelTarget, streamTarget, subTarget, } from '@abloatai/transaction/coordination';
|
|
18
|
+
import { readStatus } from './status.js';
|
|
18
19
|
import { validateAbloOptions } from './validateAbloOptions.js';
|
|
19
20
|
import { startStoreLifecycle } from './storeLifecycle.js';
|
|
20
21
|
import { createClaimStream } from '../sync/createClaimStream.js';
|
|
@@ -605,11 +606,9 @@ export function buildReactiveEngine(inputs) {
|
|
|
605
606
|
waitForConfirmation(modelName, modelId) {
|
|
606
607
|
return store.waitForConfirmation(modelName, modelId);
|
|
607
608
|
},
|
|
608
|
-
//
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
get syncStatus() {
|
|
612
|
-
return store.syncStatus;
|
|
609
|
+
// One core lifecycle projection; React selects the same observable reads.
|
|
610
|
+
get status() {
|
|
611
|
+
return readStatus(store);
|
|
613
612
|
},
|
|
614
613
|
// The humans capability owns the connection-backed presence projection.
|
|
615
614
|
// Keep it on the base client as well as in the plugin surface so the
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import type { SyncStoreContract } from '../storeContract.js';
|
|
2
|
+
/** The client lifecycle, shared by every framework binding. */
|
|
3
|
+
export type ClientStatus = {
|
|
2
4
|
readonly name: 'initial';
|
|
3
5
|
} | {
|
|
4
6
|
readonly name: 'connecting';
|
|
@@ -15,5 +17,4 @@ export type SyncStatusSnapshot = {
|
|
|
15
17
|
} | {
|
|
16
18
|
readonly name: 'needs-auth';
|
|
17
19
|
};
|
|
18
|
-
|
|
19
|
-
export declare function useSyncStatus(): SyncStatusSnapshot;
|
|
20
|
+
export declare function readStatus(store: SyncStoreContract): ClientStatus;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function readStatus(store) {
|
|
2
|
+
const { state, progress, pendingChanges, isSessionError, error } = store.syncStatus;
|
|
3
|
+
if (isSessionError)
|
|
4
|
+
return { name: 'needs-auth' };
|
|
5
|
+
if (state === 'reconnecting')
|
|
6
|
+
return { name: 'reconnecting', reason: error?.message };
|
|
7
|
+
if (state === 'offline')
|
|
8
|
+
return { name: 'disconnected', reason: 'offline' };
|
|
9
|
+
if (state === 'error')
|
|
10
|
+
return { name: 'disconnected', reason: error?.message };
|
|
11
|
+
if (store.isReady)
|
|
12
|
+
return { name: 'connected', hasUnsyncedChanges: pendingChanges > 0 };
|
|
13
|
+
return { name: 'connecting', progress };
|
|
14
|
+
}
|
|
@@ -183,7 +183,7 @@ export function startStoreLifecycle(deps) {
|
|
|
183
183
|
//
|
|
184
184
|
// The store.initialize() generator updates store.syncStatus as it
|
|
185
185
|
// progresses (syncing → idle on success, error on failure), so the
|
|
186
|
-
// consumer's `
|
|
186
|
+
// consumer's `ablo.status` projection reflects real-time state.
|
|
187
187
|
// Resolve bootstrap mode: explicit option wins; otherwise
|
|
188
188
|
// agents default to 'none' (transactional participant — see
|
|
189
189
|
// option doc) and everyone else defaults to 'full'.
|
|
@@ -260,7 +260,7 @@ export function startStoreLifecycle(deps) {
|
|
|
260
260
|
if (!validationError && internalOptions.autoStart) {
|
|
261
261
|
void ready().catch(() => {
|
|
262
262
|
// Error is captured in store.syncStatus; consumers should check
|
|
263
|
-
// `
|
|
263
|
+
// `ablo.status.name === 'disconnected'` to detect failures.
|
|
264
264
|
});
|
|
265
265
|
}
|
|
266
266
|
return {
|
|
@@ -17,8 +17,7 @@ import type { GroupScope } from './sync/scopeGroups.js';
|
|
|
17
17
|
/**
|
|
18
18
|
* A snapshot of the client's synchronization state, shaped for binding to UI.
|
|
19
19
|
* {@link SyncStoreContract.syncStatus} exposes a reactive instance of this, and
|
|
20
|
-
* the
|
|
21
|
-
* indicators.
|
|
20
|
+
* the client projects it into `ablo.status` for connection indicators.
|
|
22
21
|
*/
|
|
23
22
|
export interface SyncStatus {
|
|
24
23
|
state: 'idle' | 'syncing' | 'error' | 'offline' | 'reconnecting';
|
|
@@ -112,7 +111,7 @@ export interface SyncStoreContract {
|
|
|
112
111
|
* are backed by observable computeds, so reading them inside a reactive
|
|
113
112
|
* context — an observer component or a reaction — re-runs that context when
|
|
114
113
|
* the state changes. Code that prefers not to work with the reactivity system
|
|
115
|
-
* directly can read the same values through
|
|
114
|
+
* directly can read the same values through `useAblo(ablo => ablo.status)`.
|
|
116
115
|
*/
|
|
117
116
|
readonly isReady: boolean;
|
|
118
117
|
readonly isSyncing: boolean;
|
|
@@ -136,7 +135,7 @@ export interface SyncStoreContract {
|
|
|
136
135
|
pinScope?(scope: GroupScope): Promise<void>;
|
|
137
136
|
unpinScope?(scope: GroupScope): Promise<void>;
|
|
138
137
|
/**
|
|
139
|
-
* The full reactive {@link SyncStatus} record. The
|
|
138
|
+
* The full reactive {@link SyncStatus} record. The client status projection
|
|
140
139
|
* reads its fields — `state`, `progress`, `pendingChanges`, `isSessionError`,
|
|
141
140
|
* and `error` — to present the current sync state. It is part of the contract
|
|
142
141
|
* so hooks and test doubles can read or set it directly.
|
package/dist/presence/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { observable, runInAction } from 'mobx';
|
|
1
2
|
import { createPresenceProjection, } from '@abloatai/transaction/presence';
|
|
2
3
|
import { startReadActivity, } from './readActivity.js';
|
|
3
4
|
const clientPresence = new WeakMap();
|
|
@@ -14,10 +15,12 @@ export function presenceOfClient(client) {
|
|
|
14
15
|
export function createPresence(transport = null) {
|
|
15
16
|
let projection = null;
|
|
16
17
|
let attachedTransport = null;
|
|
18
|
+
const version = observable.box(0);
|
|
17
19
|
const listeners = new Set();
|
|
18
20
|
const reads = new Set();
|
|
19
21
|
let unsubscribe = null;
|
|
20
22
|
const notify = () => {
|
|
23
|
+
runInAction(() => { version.set(version.get() + 1); });
|
|
21
24
|
for (const listener of listeners)
|
|
22
25
|
listener();
|
|
23
26
|
};
|
|
@@ -32,8 +35,8 @@ export function createPresence(transport = null) {
|
|
|
32
35
|
if (transport !== null)
|
|
33
36
|
attach(transport);
|
|
34
37
|
return {
|
|
35
|
-
get active() { return projection?.active ?? []; },
|
|
36
|
-
get others() { return projection?.others ?? []; },
|
|
38
|
+
get active() { version.get(); return projection?.active ?? []; },
|
|
39
|
+
get others() { version.get(); return projection?.others ?? []; },
|
|
37
40
|
onChange(listener) {
|
|
38
41
|
listeners.add(listener);
|
|
39
42
|
return () => { listeners.delete(listener); };
|
|
@@ -50,6 +53,7 @@ export function createPresence(transport = null) {
|
|
|
50
53
|
};
|
|
51
54
|
},
|
|
52
55
|
forModel(model, recordId) {
|
|
56
|
+
version.get();
|
|
53
57
|
return projection?.forModel(model, recordId) ?? [];
|
|
54
58
|
},
|
|
55
59
|
dispose() {
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
2
|
import type { SchemaRecord } from '@abloatai/transaction/schema/schema';
|
|
3
3
|
import type { AbloClient as Ablo } from '../client.js';
|
|
4
|
-
import type { PresenceSession } from '@abloatai/transaction/presence';
|
|
5
|
-
import type { GroupScope } from '../local/sync/scopeGroups.js';
|
|
6
|
-
import { type SyncStoreContract } from './context.js';
|
|
7
4
|
/** Reactive binding over an application-owned client. Starts readiness,
|
|
8
5
|
* forwards errors and gates bootstrap; the application owns client disposal.
|
|
9
6
|
*/
|
|
@@ -25,127 +22,66 @@ import { type SyncStoreContract } from './context.js';
|
|
|
25
22
|
* </AbloProvider>
|
|
26
23
|
* ```
|
|
27
24
|
*
|
|
28
|
-
* That's it for most apps.
|
|
25
|
+
* That's it for most apps. The `fallback`,
|
|
29
26
|
* `preventUnsavedChanges`, and `on*` props are opt-in app glue; and the
|
|
30
27
|
* block tagged "Optional DI (advanced)" below is escape-hatch wiring for
|
|
31
28
|
* tests and platform builders — if you don't recognize a prop there, you
|
|
32
29
|
* don't need it.
|
|
33
30
|
*/
|
|
34
|
-
export
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
fallback?: ReactNode | 'passthrough';
|
|
91
|
-
children: ReactNode;
|
|
31
|
+
export declare function AbloProvider<R extends SchemaRecord = SchemaRecord>(props: AbloProvider.Props<R>): React.ReactElement;
|
|
32
|
+
/** Props for wrappers around the provider, using the same schema parameter. */
|
|
33
|
+
export declare namespace AbloProvider {
|
|
34
|
+
interface Props<R extends SchemaRecord = SchemaRecord> {
|
|
35
|
+
/**
|
|
36
|
+
* A prebuilt {@link Ablo} client — **the only way to configure the engine.**
|
|
37
|
+
* Construct it yourself with `Ablo({ schema, apiKey, ... })` and pass the
|
|
38
|
+
* instance: the CLIENT owns auth, the credential lifecycle, transport, and
|
|
39
|
+
* connection; this provider is the thin REACTIVE binding over it (context,
|
|
40
|
+
* the bootstrap gate, error/session forwarding).
|
|
41
|
+
*
|
|
42
|
+
* Memoize it (build it once, e.g. with `useMemo` or module scope) — a new
|
|
43
|
+
* instance each render re-keys the bootstrap gate and tears down the socket.
|
|
44
|
+
*/
|
|
45
|
+
client: Ablo<R>;
|
|
46
|
+
/**
|
|
47
|
+
* Block tab close while there are unsynced local writes (the standard
|
|
48
|
+
* `beforeunload` prompt). Browsers ignore custom messages — don't pass one.
|
|
49
|
+
*/
|
|
50
|
+
preventUnsavedChanges?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Fired after the client has completed its terminal authentication cleanup
|
|
53
|
+
* (or surfaced a cleanup failure). Use it for app side effects such as a
|
|
54
|
+
* redirect to sign-in or clearing analytics identity.
|
|
55
|
+
*/
|
|
56
|
+
onSessionExpired?: () => void | Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Fired on any error the provider surfaces (engine/WebSocket/bootstrap). For
|
|
59
|
+
* Sentry/Datadog or application error UI.
|
|
60
|
+
*/
|
|
61
|
+
onError?: (error: Error) => void;
|
|
62
|
+
/** @internal placeholder so the old WS-URL prop shape doesn't silently leak in. */
|
|
63
|
+
url?: never;
|
|
64
|
+
/**
|
|
65
|
+
* Rendered in place of `children` during the *first* bootstrap pass —
|
|
66
|
+
* while the engine is actively transitioning from `initial` →
|
|
67
|
+
* `connected` and has never successfully connected before. Once the
|
|
68
|
+
* engine reaches `connected` the gate latches open for the lifetime
|
|
69
|
+
* of this provider instance; transient `reconnecting` / `needs-auth`
|
|
70
|
+
* states do NOT re-show the fallback (the app's own UI handles those
|
|
71
|
+
* by then).
|
|
72
|
+
*
|
|
73
|
+
* Defaults to `<DefaultFallback />` — a neutral theme-adaptive
|
|
74
|
+
* spinner that uses `currentColor`, ships with zero design-system
|
|
75
|
+
* dependencies, and self-centers in a full-parent container. Pass
|
|
76
|
+
* your own `<Skeleton />` for a branded loading UX. Pass `null` to
|
|
77
|
+
* render nothing during bootstrap. Pass the string literal
|
|
78
|
+
* `"passthrough"` to opt out of the gate entirely — children render
|
|
79
|
+
* immediately and consumers are responsible for their own gating
|
|
80
|
+
* (for example, `useAblo(ablo => ablo.status)` checks).
|
|
81
|
+
* Useful for pages that mount debug helpers, error boundaries, or
|
|
82
|
+
* analytics that must run pre-ready.
|
|
83
|
+
*/
|
|
84
|
+
fallback?: ReactNode | 'passthrough';
|
|
85
|
+
children: ReactNode;
|
|
86
|
+
}
|
|
92
87
|
}
|
|
93
|
-
export declare function AbloProvider<R extends SchemaRecord = SchemaRecord>(props: AbloProviderProps<R>): React.ReactElement;
|
|
94
|
-
export type { GroupScope };
|
|
95
|
-
/**
|
|
96
|
-
* Read-only presence: the other sessions currently visible to this
|
|
97
|
-
* connection, bridged to React. This is a pure reader of the engine's
|
|
98
|
-
* already-flowing presence stream; it does not mutate connection groups.
|
|
99
|
-
*
|
|
100
|
-
* Pass `scope` to narrow to the peers on that scope's sync group(s); omit
|
|
101
|
-
* it to get everyone on the engine's groups. Membership is driven entirely
|
|
102
|
-
* by the presence channel (set server-side on connect, independent of any
|
|
103
|
-
* cursor/collaboration traffic), so reading it never affects what the
|
|
104
|
-
* connection is subscribed to and can't deadlock against a gated channel.
|
|
105
|
-
*
|
|
106
|
-
* Use this to answer "is anyone else here?", for example to suppress
|
|
107
|
-
* live-cursor broadcasts while alone.
|
|
108
|
-
*
|
|
109
|
-
* ```ts
|
|
110
|
-
* const peers = usePeers({ reports: reportId });
|
|
111
|
-
* const alone = !peers.some((p) => p.participantKind === 'user');
|
|
112
|
-
* ```
|
|
113
|
-
*/
|
|
114
|
-
export declare function usePeers(scope?: GroupScope): readonly PresenceSession[];
|
|
115
|
-
/**
|
|
116
|
-
* Returns the raw `SyncEngine` proxy. Typically you want the typed
|
|
117
|
-
* hooks (`useQuery`, `useOne`, `useMutate`) — this is for rare cases
|
|
118
|
-
* where you need direct access (e.g., `sync.items.onChange(cb)`).
|
|
119
|
-
*
|
|
120
|
-
* The generic parameter narrows the return type to your schema's
|
|
121
|
-
* model record so call sites get typed `sync.items.findMany()` /
|
|
122
|
-
* `sync.sections.create(...)` without a cast at the call site:
|
|
123
|
-
*
|
|
124
|
-
* ```ts
|
|
125
|
-
* const sync = useSync<(typeof schema)['models']>();
|
|
126
|
-
* ```
|
|
127
|
-
*
|
|
128
|
-
* The runtime value is the exact engine the provider constructed;
|
|
129
|
-
* the generic just widens the compile-time type.
|
|
130
|
-
*/
|
|
131
|
-
export declare function useSync<R extends SchemaRecord = SchemaRecord>(): Ablo<R>;
|
|
132
|
-
/**
|
|
133
|
-
* Returns the underlying `SyncStoreContract` (the BaseSyncedStore).
|
|
134
|
-
* Most consumers should prefer the typed hooks (`useQuery` etc.); this
|
|
135
|
-
* is for advanced cases like direct InstanceCache access or custom
|
|
136
|
-
* reactive bridges. Throws if the provider hasn't mounted the store
|
|
137
|
-
* yet — wrap consumers in `<ClientSideSuspense>` to gate correctly.
|
|
138
|
-
*
|
|
139
|
-
* The generic parameter lets consumers widen the return type to a
|
|
140
|
-
* concrete `BaseSyncedStore<...>` subclass if they track one:
|
|
141
|
-
*
|
|
142
|
-
* ```ts
|
|
143
|
-
* type AppStore = BaseSyncedStore<AppEvents, typeof schema>;
|
|
144
|
-
* const store = useSyncStore<AppStore>(); // no cast needed at call site
|
|
145
|
-
* ```
|
|
146
|
-
*
|
|
147
|
-
* The runtime value is always the concrete store the SDK constructed,
|
|
148
|
-
* so widening the type is safe. The bounded generic (`T extends
|
|
149
|
-
* SyncStoreContract`) keeps the widening honest.
|
|
150
|
-
*/
|
|
151
|
-
export declare function useSyncStore<T extends SyncStoreContract = SyncStoreContract>(): T;
|