@syncular/react 0.7.0 → 0.8.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/README.md CHANGED
@@ -164,6 +164,9 @@ not need a custom retention effect.
164
164
  means an inbound pull/catch-up signal.
165
165
  - `useConflicts()` observes conflicts and rejections only when that domain
166
166
  changes.
167
+ - `useCommitOutcomes()` observes the durable newest-first final-outcome journal
168
+ from exact `outcomesChanged` batches. Resolve entries through
169
+ `useSyncClient().resolveCommitOutcome(...)`.
167
170
  - `usePresence(scopeKey)` observes ephemeral realtime peers.
168
171
  - `useSyncClient()` and `useReactiveStore()` expose the normalized low-level
169
172
  surfaces for integrations.
package/dist/client.d.ts CHANGED
@@ -11,7 +11,7 @@
11
11
  * value → read it) and wraps every result in `Promise.resolve`, so a hook
12
12
  * never has to care which core it holds.
13
13
  */
14
- import type { ClientChangeListener, ConflictRecord, InvalidationListener, LeaseState, MutationInput, PresencePeer, QueryReadSpec, QuerySnapshot, RejectionRecord, SchemaFloor, SqlRow, SqlValue, SyncStatusSnapshot, WindowBase, WindowState } from '@syncular/client';
14
+ import type { ClientChangeListener, CommitOutcome, CommitOutcomeQuery, ConflictRecord, InvalidationListener, LeaseState, MutationInput, PresencePeer, QueryReadSpec, QuerySnapshot, RejectionRecord, ResolveCommitOutcomeInput, SchemaFloor, SqlRow, SqlValue, SyncStatusSnapshot, WindowBase, WindowState } from '@syncular/client';
15
15
  /**
16
16
  * The structural union of `SyncClient` and `SyncClientHandle`. Members that
17
17
  * diverge are typed as "value or method, sync or promise"; {@link normalizeClient}
@@ -31,6 +31,9 @@ export interface SyncClientLike {
31
31
  statusSnapshot(): SyncStatusSnapshot | Promise<SyncStatusSnapshot>;
32
32
  conflicts: readonly ConflictRecord[] | (() => readonly ConflictRecord[] | Promise<readonly ConflictRecord[]>);
33
33
  rejections: readonly RejectionRecord[] | (() => readonly RejectionRecord[] | Promise<readonly RejectionRecord[]>);
34
+ commitOutcome(clientCommitId: string): CommitOutcome | undefined | Promise<CommitOutcome | undefined>;
35
+ commitOutcomes(query?: CommitOutcomeQuery): readonly CommitOutcome[] | Promise<readonly CommitOutcome[]>;
36
+ resolveCommitOutcome(input: ResolveCommitOutcomeInput): CommitOutcome | Promise<CommitOutcome>;
34
37
  schemaFloor: SchemaFloor | undefined | (() => SchemaFloor | undefined | Promise<SchemaFloor | undefined>);
35
38
  leaseState: LeaseState | undefined | (() => LeaseState | undefined | Promise<LeaseState | undefined>);
36
39
  upgrading: boolean | (() => boolean | Promise<boolean>);
@@ -57,6 +60,9 @@ export interface NormalizedClient {
57
60
  statusSnapshot(): Promise<SyncStatusSnapshot>;
58
61
  conflicts(): Promise<readonly ConflictRecord[]>;
59
62
  rejections(): Promise<readonly RejectionRecord[]>;
63
+ commitOutcome(clientCommitId: string): Promise<CommitOutcome | undefined>;
64
+ commitOutcomes(query?: CommitOutcomeQuery): Promise<readonly CommitOutcome[]>;
65
+ resolveCommitOutcome(input: ResolveCommitOutcomeInput): Promise<CommitOutcome>;
60
66
  schemaFloor(): Promise<SchemaFloor | undefined>;
61
67
  leaseState(): Promise<LeaseState | undefined>;
62
68
  upgrading(): Promise<boolean>;
package/dist/client.js CHANGED
@@ -22,6 +22,9 @@ export function normalizeClient(client) {
22
22
  statusSnapshot: () => Promise.resolve(client.statusSnapshot()),
23
23
  conflicts: () => resolveMember(client, 'conflicts'),
24
24
  rejections: () => resolveMember(client, 'rejections'),
25
+ commitOutcome: (clientCommitId) => Promise.resolve(client.commitOutcome(clientCommitId)),
26
+ commitOutcomes: (query) => Promise.resolve(client.commitOutcomes(query)),
27
+ resolveCommitOutcome: (input) => Promise.resolve(client.resolveCommitOutcome(input)),
25
28
  schemaFloor: () => resolveMember(client, 'schemaFloor'),
26
29
  leaseState: () => resolveMember(client, 'leaseState'),
27
30
  upgrading: () => resolveMember(client, 'upgrading'),
package/dist/index.d.ts CHANGED
@@ -13,6 +13,7 @@ export { inferTables } from './infer-tables.js';
13
13
  export { SyncContext, SyncProvider, type SyncProviderProps, SyncStoreContext, } from './provider.js';
14
14
  export { createSyncClientResource, isSyncClientResource, type SyncClientResource, type SyncClientResourceSnapshot, } from './resource.js';
15
15
  export { useReactiveStore, useSyncClient } from './use-client.js';
16
+ export { type UseCommitOutcomesResult, useCommitOutcomes, } from './use-commit-outcomes.js';
16
17
  export { type UseConflictsResult, useConflicts } from './use-conflicts.js';
17
18
  export { type SyncTableDescriptor, type UseMutationOptions, type UseMutationResult, type UseTableMutationResult, useMutation, } from './use-mutation.js';
18
19
  export { usePresence } from './use-presence.js';
package/dist/index.js CHANGED
@@ -6,6 +6,7 @@ export { inferTables } from './infer-tables.js';
6
6
  export { SyncContext, SyncProvider, SyncStoreContext, } from './provider.js';
7
7
  export { createSyncClientResource, isSyncClientResource, } from './resource.js';
8
8
  export { useReactiveStore, useSyncClient } from './use-client.js';
9
+ export { useCommitOutcomes, } from './use-commit-outcomes.js';
9
10
  export { useConflicts } from './use-conflicts.js';
10
11
  export { useMutation, } from './use-mutation.js';
11
12
  export { usePresence } from './use-presence.js';
@@ -0,0 +1,12 @@
1
+ import type { CommitOutcome } from '@syncular/client';
2
+ export interface UseCommitOutcomesResult {
3
+ readonly outcomes: readonly CommitOutcome[];
4
+ readonly isLoading: boolean;
5
+ readonly error: Error | undefined;
6
+ readonly refresh: () => void;
7
+ }
8
+ /**
9
+ * Durable newest-first commit history. It updates from the exact
10
+ * `outcomesChanged` transaction event, including resolution transitions.
11
+ */
12
+ export declare function useCommitOutcomes(): UseCommitOutcomesResult;
@@ -0,0 +1,17 @@
1
+ import { useCallback, useSyncExternalStore } from 'react';
2
+ import { useReactiveStore } from './use-client.js';
3
+ /**
4
+ * Durable newest-first commit history. It updates from the exact
5
+ * `outcomesChanged` transaction event, including resolution transitions.
6
+ */
7
+ export function useCommitOutcomes() {
8
+ const entry = useReactiveStore().outcomes;
9
+ const snapshot = useSyncExternalStore(entry.subscribe, entry.getSnapshot, entry.getSnapshot);
10
+ const refresh = useCallback(() => entry.refresh(), [entry]);
11
+ return {
12
+ outcomes: snapshot.outcomes,
13
+ isLoading: snapshot.isLoading,
14
+ error: snapshot.error,
15
+ refresh,
16
+ };
17
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syncular/react",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "React hooks for Syncular offline-first sync",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Benjamin Kniffler",
@@ -48,15 +48,15 @@
48
48
  "test": "bun test --preload ./test/setup.ts"
49
49
  },
50
50
  "dependencies": {
51
- "@syncular/client": "0.7.0"
51
+ "@syncular/client": "0.8.0"
52
52
  },
53
53
  "peerDependencies": {
54
54
  "react": ">=18.0.0"
55
55
  },
56
56
  "devDependencies": {
57
57
  "@happy-dom/global-registrator": "^15.11.0",
58
- "@syncular/core": "0.7.0",
59
- "@syncular/server": "0.7.0",
58
+ "@syncular/core": "0.8.0",
59
+ "@syncular/server": "0.8.0",
60
60
  "@testing-library/react": "^16.1.0",
61
61
  "@types/react": "^18.3.0",
62
62
  "react": "^18.3.1",
package/src/client.ts CHANGED
@@ -13,6 +13,8 @@
13
13
  */
14
14
  import type {
15
15
  ClientChangeListener,
16
+ CommitOutcome,
17
+ CommitOutcomeQuery,
16
18
  ConflictRecord,
17
19
  InvalidationListener,
18
20
  LeaseState,
@@ -21,6 +23,7 @@ import type {
21
23
  QueryReadSpec,
22
24
  QuerySnapshot,
23
25
  RejectionRecord,
26
+ ResolveCommitOutcomeInput,
24
27
  SchemaFloor,
25
28
  SqlRow,
26
29
  SqlValue,
@@ -60,6 +63,15 @@ export interface SyncClientLike {
60
63
  rejections:
61
64
  | readonly RejectionRecord[]
62
65
  | (() => readonly RejectionRecord[] | Promise<readonly RejectionRecord[]>);
66
+ commitOutcome(
67
+ clientCommitId: string,
68
+ ): CommitOutcome | undefined | Promise<CommitOutcome | undefined>;
69
+ commitOutcomes(
70
+ query?: CommitOutcomeQuery,
71
+ ): readonly CommitOutcome[] | Promise<readonly CommitOutcome[]>;
72
+ resolveCommitOutcome(
73
+ input: ResolveCommitOutcomeInput,
74
+ ): CommitOutcome | Promise<CommitOutcome>;
63
75
  schemaFloor:
64
76
  | SchemaFloor
65
77
  | undefined
@@ -118,6 +130,11 @@ export interface NormalizedClient {
118
130
  statusSnapshot(): Promise<SyncStatusSnapshot>;
119
131
  conflicts(): Promise<readonly ConflictRecord[]>;
120
132
  rejections(): Promise<readonly RejectionRecord[]>;
133
+ commitOutcome(clientCommitId: string): Promise<CommitOutcome | undefined>;
134
+ commitOutcomes(query?: CommitOutcomeQuery): Promise<readonly CommitOutcome[]>;
135
+ resolveCommitOutcome(
136
+ input: ResolveCommitOutcomeInput,
137
+ ): Promise<CommitOutcome>;
121
138
  schemaFloor(): Promise<SchemaFloor | undefined>;
122
139
  leaseState(): Promise<LeaseState | undefined>;
123
140
  upgrading(): Promise<boolean>;
@@ -145,6 +162,11 @@ export function normalizeClient(client: SyncClientLike): NormalizedClient {
145
162
  statusSnapshot: () => Promise.resolve(client.statusSnapshot()),
146
163
  conflicts: () => resolveMember(client, 'conflicts'),
147
164
  rejections: () => resolveMember(client, 'rejections'),
165
+ commitOutcome: (clientCommitId) =>
166
+ Promise.resolve(client.commitOutcome(clientCommitId)),
167
+ commitOutcomes: (query) => Promise.resolve(client.commitOutcomes(query)),
168
+ resolveCommitOutcome: (input) =>
169
+ Promise.resolve(client.resolveCommitOutcome(input)),
148
170
  schemaFloor: () => resolveMember(client, 'schemaFloor'),
149
171
  leaseState: () => resolveMember(client, 'leaseState'),
150
172
  upgrading: () => resolveMember(client, 'upgrading'),
package/src/index.ts CHANGED
@@ -29,6 +29,10 @@ export {
29
29
  type SyncClientResourceSnapshot,
30
30
  } from './resource';
31
31
  export { useReactiveStore, useSyncClient } from './use-client';
32
+ export {
33
+ type UseCommitOutcomesResult,
34
+ useCommitOutcomes,
35
+ } from './use-commit-outcomes';
32
36
  export { type UseConflictsResult, useConflicts } from './use-conflicts';
33
37
  export {
34
38
  type SyncTableDescriptor,
@@ -0,0 +1,30 @@
1
+ import type { CommitOutcome } from '@syncular/client';
2
+ import { useCallback, useSyncExternalStore } from 'react';
3
+ import { useReactiveStore } from './use-client';
4
+
5
+ export interface UseCommitOutcomesResult {
6
+ readonly outcomes: readonly CommitOutcome[];
7
+ readonly isLoading: boolean;
8
+ readonly error: Error | undefined;
9
+ readonly refresh: () => void;
10
+ }
11
+
12
+ /**
13
+ * Durable newest-first commit history. It updates from the exact
14
+ * `outcomesChanged` transaction event, including resolution transitions.
15
+ */
16
+ export function useCommitOutcomes(): UseCommitOutcomesResult {
17
+ const entry = useReactiveStore().outcomes;
18
+ const snapshot = useSyncExternalStore(
19
+ entry.subscribe,
20
+ entry.getSnapshot,
21
+ entry.getSnapshot,
22
+ );
23
+ const refresh = useCallback(() => entry.refresh(), [entry]);
24
+ return {
25
+ outcomes: snapshot.outcomes,
26
+ isLoading: snapshot.isLoading,
27
+ error: snapshot.error,
28
+ refresh,
29
+ };
30
+ }