local-lite 0.0.2 → 0.0.3

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
@@ -13,7 +13,7 @@ Built around the **Transactional Outbox Pattern**, `local-lite` ensures instant,
13
13
  * **[Configuration Reference](docs/configuration.md)** - Options for `defineSyncConfig()`, retries, and loggers
14
14
  * **[Local SQLite Adapters](docs/adapters-local.md)** - Expo SQLite, OP-SQLite, better-sqlite3, node:sqlite, and LibSQL
15
15
  * **[Remote Cloud Adapters](docs/adapters-remote.md)** - Supabase, Convex, Cloud Firestore, and custom adapters
16
- * **[React & Expo Hooks](docs/react-hooks.md)** - `useLiveQuery()` and `useOutboxStatus()`
16
+ * **[React & Expo Hooks](docs/react-hooks.md)** - `useLiveQuery()` and `useSyncStatus()`
17
17
  * **[Conflict Resolution](docs/conflict-resolution.md)** - LWW, Client-Wins, Server-Wins, and custom resolvers
18
18
 
19
19
  ---
@@ -147,7 +147,7 @@ export const client = await createSyncClient(syncConfig);
147
147
  ### 2. Use in React Native / Expo UI
148
148
 
149
149
  ```tsx
150
- import { useLiveQuery, useOutboxStatus } from 'local-lite';
150
+ import { useLiveQuery, useSyncStatus } from 'local-lite/react';
151
151
  import { client } from './sync.config';
152
152
 
153
153
  export function TodoScreen() {
@@ -157,7 +157,7 @@ export function TodoScreen() {
157
157
  order: 'desc',
158
158
  });
159
159
 
160
- const { pendingCount } = useOutboxStatus(client);
160
+ const { pendingCount, isOnline, isSyncing } = useSyncStatus(client);
161
161
 
162
162
  const addTodo = async (title: string) => {
163
163
  await client.insert('todos', {
package/dist/index.d.ts CHANGED
@@ -12,7 +12,7 @@ export * from './adapters/local/index.js';
12
12
  export * from './adapters/remote/index.js';
13
13
  export * from './adapters/network/index.js';
14
14
  export * from './config/index.js';
15
- export * from './react/index.js';
15
+ export type * from './react/index.js';
16
16
  export * from './utils/uuid.js';
17
17
  export * from './utils/sql.js';
18
18
  export * from './utils/logger.js';
package/dist/index.js CHANGED
@@ -28,7 +28,6 @@ __exportStar(require("./adapters/local/index.js"), exports);
28
28
  __exportStar(require("./adapters/remote/index.js"), exports);
29
29
  __exportStar(require("./adapters/network/index.js"), exports);
30
30
  __exportStar(require("./config/index.js"), exports);
31
- __exportStar(require("./react/index.js"), exports);
32
31
  __exportStar(require("./utils/uuid.js"), exports);
33
32
  __exportStar(require("./utils/sql.js"), exports);
34
33
  __exportStar(require("./utils/logger.js"), exports);
@@ -24,23 +24,21 @@ export declare function useLiveQuery<T = any>(client: LocalFirstClient | null |
24
24
  refetch: () => Promise<void>;
25
25
  loading: boolean;
26
26
  };
27
- /**
28
- * Hook that tracks the status and pending items in sync_outbox in real time.
29
- */
30
- export declare function useOutboxStatus(client: LocalFirstClient | null | undefined): {
27
+ export interface UseSyncStatusResult {
28
+ isOnline: boolean;
29
+ isPushing: boolean;
30
+ isPulling: boolean;
31
+ isSyncing: boolean;
31
32
  pendingCount: number;
32
33
  pendingRecords: any[];
34
+ lastSyncedAt: number | null;
33
35
  refresh: () => Promise<void>;
34
- };
36
+ }
35
37
  /**
36
- * Hook that tracks real-time sync connectivity and sync worker activity (pushing/pulling).
38
+ * Consolidated hook that tracks real-time sync connectivity, sync worker activity
39
+ * (pushing/pulling/syncing), and pending items in the local SQLite outbox queue.
37
40
  */
38
- export declare function useSyncStatus(client: LocalFirstClient | null | undefined): {
39
- isOnline: boolean;
40
- isPushing: boolean;
41
- isPulling: boolean;
42
- pendingCount: number;
43
- };
41
+ export declare function useSyncStatus(client: LocalFirstClient | null | undefined): UseSyncStatusResult;
44
42
  /**
45
43
  * Hook that provides real-time sync telemetry and engine performance metrics.
46
44
  */
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useLiveQuery = useLiveQuery;
4
- exports.useOutboxStatus = useOutboxStatus;
5
4
  exports.useSyncStatus = useSyncStatus;
6
5
  exports.useSyncMetrics = useSyncMetrics;
7
6
  const react_1 = require("react");
@@ -73,66 +72,78 @@ function useLiveQuery(client, tableName, queryOrOptions) {
73
72
  return { data, refetch, loading };
74
73
  }
75
74
  /**
76
- * Hook that tracks the status and pending items in sync_outbox in real time.
75
+ * Consolidated hook that tracks real-time sync connectivity, sync worker activity
76
+ * (pushing/pulling/syncing), and pending items in the local SQLite outbox queue.
77
77
  */
78
- function useOutboxStatus(client) {
78
+ function useSyncStatus(client) {
79
+ const [isOnline, setIsOnline] = (0, react_1.useState)(true);
80
+ const [isPushing, setIsPushing] = (0, react_1.useState)(false);
81
+ const [isPulling, setIsPulling] = (0, react_1.useState)(false);
79
82
  const [pendingCount, setPendingCount] = (0, react_1.useState)(0);
80
83
  const [pendingRecords, setPendingRecords] = (0, react_1.useState)([]);
84
+ const [lastSyncedAt, setLastSyncedAt] = (0, react_1.useState)(null);
81
85
  const refresh = (0, react_1.useCallback)(async () => {
82
86
  if (!client || !client.db)
83
87
  return;
84
88
  try {
85
- const records = await client.getOutboxRecords();
86
- setPendingRecords(records || []);
87
- setPendingCount(records.filter((r) => r.status === 'PENDING').length);
89
+ const [metrics, records, lastSynced] = await Promise.all([
90
+ client.getMetrics().catch(() => null),
91
+ client.getOutboxRecords().catch(() => []),
92
+ client.getLastSyncedAt().catch(() => null),
93
+ ]);
94
+ if (metrics) {
95
+ setIsOnline(metrics.isOnline);
96
+ setIsPushing(metrics.isPushing);
97
+ setIsPulling(metrics.isPulling);
98
+ }
99
+ if (records) {
100
+ setPendingRecords(records);
101
+ setPendingCount(records.filter((r) => r.status === 'PENDING').length);
102
+ }
103
+ if (lastSynced !== null && lastSynced !== undefined) {
104
+ setLastSyncedAt(lastSynced > 0 ? lastSynced : null);
105
+ }
88
106
  }
89
107
  catch {
90
- // Ignored if table doesn't exist yet
108
+ // Ignored if client is stopping or tables initializing
91
109
  }
92
110
  }, [client]);
93
111
  (0, react_1.useEffect)(() => {
94
112
  if (!client || !client.db)
95
113
  return;
96
114
  refresh();
97
- const unsubscribe = client.events.on('sync_outbox', () => {
115
+ const unsubStatus = client.events.on('sync:status', (e) => {
116
+ setIsOnline(e.isOnline);
117
+ setIsPushing(e.isPushing);
118
+ setIsPulling(e.isPulling);
119
+ setPendingCount(e.pendingCount);
120
+ });
121
+ const unsubOutbox = client.events.on('sync_outbox', () => {
98
122
  refresh();
99
123
  });
100
- return () => {
101
- unsubscribe();
102
- };
103
- }, [client, refresh]);
104
- return { pendingCount, pendingRecords, refresh };
105
- }
106
- /**
107
- * Hook that tracks real-time sync connectivity and sync worker activity (pushing/pulling).
108
- */
109
- function useSyncStatus(client) {
110
- const [status, setStatus] = (0, react_1.useState)({
111
- isOnline: true,
112
- isPushing: false,
113
- isPulling: false,
114
- pendingCount: 0,
115
- });
116
- (0, react_1.useEffect)(() => {
117
- if (!client)
118
- return;
119
- // Fetch initial metrics
120
- client.getMetrics().then((m) => {
121
- setStatus({
122
- isOnline: m.isOnline,
123
- isPushing: m.isPushing,
124
- isPulling: m.isPulling,
125
- pendingCount: m.outboxPendingCount,
126
- });
127
- }).catch(() => { });
128
- const unsubscribe = client.events.on('sync:status', (e) => {
129
- setStatus(e);
124
+ const unsubPush = client.events.on('sync:push', () => {
125
+ refresh();
126
+ });
127
+ const unsubPull = client.events.on('sync:pull', () => {
128
+ refresh();
130
129
  });
131
130
  return () => {
132
- unsubscribe();
131
+ unsubStatus();
132
+ unsubOutbox();
133
+ unsubPush();
134
+ unsubPull();
133
135
  };
134
- }, [client]);
135
- return status;
136
+ }, [client, refresh]);
137
+ return {
138
+ isOnline,
139
+ isPushing,
140
+ isPulling,
141
+ isSyncing: isPushing || isPulling,
142
+ pendingCount,
143
+ pendingRecords,
144
+ lastSyncedAt,
145
+ refresh,
146
+ };
136
147
  }
137
148
  /**
138
149
  * Hook that provides real-time sync telemetry and engine performance metrics.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "local-lite",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "Never let a lost connection break a promise. Local-first sync that faithfully keeps data safe until you're back online.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",