local-lite 0.0.1 → 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 +14 -2
- package/dist/core/client.d.ts +56 -3
- package/dist/core/client.js +212 -40
- package/dist/core/outbox-store.d.ts +32 -1
- package/dist/core/outbox-store.js +126 -2
- package/dist/core/query.d.ts +13 -0
- package/dist/core/query.js +150 -0
- package/dist/core/sync-worker.d.ts +16 -1
- package/dist/core/sync-worker.js +142 -4
- package/dist/core/types.d.ts +84 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/react/index.d.ts +21 -7
- package/dist/react/index.js +94 -12
- package/package.json +3 -3
package/dist/react/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.useLiveQuery = useLiveQuery;
|
|
4
|
-
exports.
|
|
4
|
+
exports.useSyncStatus = useSyncStatus;
|
|
5
|
+
exports.useSyncMetrics = useSyncMetrics;
|
|
5
6
|
const react_1 = require("react");
|
|
6
7
|
/**
|
|
7
8
|
* Hook to execute a live reactive table query that automatically re-runs
|
|
@@ -11,9 +12,9 @@ const react_1 = require("react");
|
|
|
11
12
|
* 1. Zero-SQL (all rows):
|
|
12
13
|
* const { data: todos } = useLiveQuery<Todo>(client, 'todos');
|
|
13
14
|
*
|
|
14
|
-
* 2. Declarative options (filtering & sorting without SQL):
|
|
15
|
+
* 2. Declarative options (filtering with rich operators & sorting without SQL):
|
|
15
16
|
* const { data: active } = useLiveQuery<Todo>(client, 'todos', {
|
|
16
|
-
* where: { completed: 0 },
|
|
17
|
+
* where: { completed: 0, priority: { $gte: 2 } },
|
|
17
18
|
* orderBy: 'created_at',
|
|
18
19
|
* order: 'desc'
|
|
19
20
|
* });
|
|
@@ -71,33 +72,114 @@ function useLiveQuery(client, tableName, queryOrOptions) {
|
|
|
71
72
|
return { data, refetch, loading };
|
|
72
73
|
}
|
|
73
74
|
/**
|
|
74
|
-
*
|
|
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.
|
|
75
77
|
*/
|
|
76
|
-
function
|
|
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);
|
|
77
82
|
const [pendingCount, setPendingCount] = (0, react_1.useState)(0);
|
|
78
83
|
const [pendingRecords, setPendingRecords] = (0, react_1.useState)([]);
|
|
84
|
+
const [lastSyncedAt, setLastSyncedAt] = (0, react_1.useState)(null);
|
|
79
85
|
const refresh = (0, react_1.useCallback)(async () => {
|
|
80
86
|
if (!client || !client.db)
|
|
81
87
|
return;
|
|
82
88
|
try {
|
|
83
|
-
const records = await
|
|
84
|
-
|
|
85
|
-
|
|
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
|
+
}
|
|
86
106
|
}
|
|
87
107
|
catch {
|
|
88
|
-
// Ignored if
|
|
108
|
+
// Ignored if client is stopping or tables initializing
|
|
89
109
|
}
|
|
90
110
|
}, [client]);
|
|
91
111
|
(0, react_1.useEffect)(() => {
|
|
92
112
|
if (!client || !client.db)
|
|
93
113
|
return;
|
|
94
114
|
refresh();
|
|
95
|
-
const
|
|
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', () => {
|
|
122
|
+
refresh();
|
|
123
|
+
});
|
|
124
|
+
const unsubPush = client.events.on('sync:push', () => {
|
|
125
|
+
refresh();
|
|
126
|
+
});
|
|
127
|
+
const unsubPull = client.events.on('sync:pull', () => {
|
|
96
128
|
refresh();
|
|
97
129
|
});
|
|
98
130
|
return () => {
|
|
99
|
-
|
|
131
|
+
unsubStatus();
|
|
132
|
+
unsubOutbox();
|
|
133
|
+
unsubPush();
|
|
134
|
+
unsubPull();
|
|
100
135
|
};
|
|
101
136
|
}, [client, refresh]);
|
|
102
|
-
return {
|
|
137
|
+
return {
|
|
138
|
+
isOnline,
|
|
139
|
+
isPushing,
|
|
140
|
+
isPulling,
|
|
141
|
+
isSyncing: isPushing || isPulling,
|
|
142
|
+
pendingCount,
|
|
143
|
+
pendingRecords,
|
|
144
|
+
lastSyncedAt,
|
|
145
|
+
refresh,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Hook that provides real-time sync telemetry and engine performance metrics.
|
|
150
|
+
*/
|
|
151
|
+
function useSyncMetrics(client, pollIntervalMs = 3000) {
|
|
152
|
+
const [metrics, setMetrics] = (0, react_1.useState)(null);
|
|
153
|
+
const refresh = (0, react_1.useCallback)(async () => {
|
|
154
|
+
if (!client)
|
|
155
|
+
return;
|
|
156
|
+
try {
|
|
157
|
+
const data = await client.getMetrics();
|
|
158
|
+
setMetrics(data);
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
// Ignored
|
|
162
|
+
}
|
|
163
|
+
}, [client]);
|
|
164
|
+
(0, react_1.useEffect)(() => {
|
|
165
|
+
if (!client)
|
|
166
|
+
return;
|
|
167
|
+
refresh();
|
|
168
|
+
// Listen to sync events for immediate refresh
|
|
169
|
+
const unsubs = [
|
|
170
|
+
client.events.on('sync:push', () => refresh()),
|
|
171
|
+
client.events.on('sync:pull', () => refresh()),
|
|
172
|
+
client.events.on('sync:status', () => refresh()),
|
|
173
|
+
];
|
|
174
|
+
let timer;
|
|
175
|
+
if (pollIntervalMs > 0) {
|
|
176
|
+
timer = setInterval(refresh, pollIntervalMs);
|
|
177
|
+
}
|
|
178
|
+
return () => {
|
|
179
|
+
unsubs.forEach((u) => u());
|
|
180
|
+
if (timer)
|
|
181
|
+
clearInterval(timer);
|
|
182
|
+
};
|
|
183
|
+
}, [client, refresh, pollIntervalMs]);
|
|
184
|
+
return { metrics, refresh };
|
|
103
185
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "local-lite",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.0.3",
|
|
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",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -130,4 +130,4 @@
|
|
|
130
130
|
"dependencies": {
|
|
131
131
|
"uuid": "^14.0.3"
|
|
132
132
|
}
|
|
133
|
-
}
|
|
133
|
+
}
|