local-lite 0.0.0-stage → 0.0.1
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/LICENSE +21 -0
- package/README.md +349 -2
- package/dist/adapters/local/better-sqlite3.d.ts +23 -0
- package/dist/adapters/local/better-sqlite3.js +46 -0
- package/dist/adapters/local/expo-sqlite.d.ts +8 -0
- package/dist/adapters/local/expo-sqlite.js +30 -0
- package/dist/adapters/local/index.d.ts +13 -0
- package/dist/adapters/local/index.js +22 -0
- package/dist/adapters/local/libsql.d.ts +24 -0
- package/dist/adapters/local/libsql.js +87 -0
- package/dist/adapters/local/node-sqlite.d.ts +24 -0
- package/dist/adapters/local/node-sqlite.js +44 -0
- package/dist/adapters/local/op-sqlite.d.ts +26 -0
- package/dist/adapters/local/op-sqlite.js +59 -0
- package/dist/adapters/local/sql-js.d.ts +26 -0
- package/dist/adapters/local/sql-js.js +63 -0
- package/dist/adapters/network/index.d.ts +11 -0
- package/dist/adapters/network/index.js +53 -0
- package/dist/adapters/remote/convex.d.ts +71 -0
- package/dist/adapters/remote/convex.js +185 -0
- package/dist/adapters/remote/demo.d.ts +21 -0
- package/dist/adapters/remote/demo.js +46 -0
- package/dist/adapters/remote/firestore.d.ts +64 -0
- package/dist/adapters/remote/firestore.js +302 -0
- package/dist/adapters/remote/index.d.ts +10 -0
- package/dist/adapters/remote/index.js +20 -0
- package/dist/adapters/remote/supabase.d.ts +97 -0
- package/dist/adapters/remote/supabase.js +276 -0
- package/dist/config/index.d.ts +24 -0
- package/dist/config/index.js +101 -0
- package/dist/config/resolve-local.d.ts +7 -0
- package/dist/config/resolve-local.js +68 -0
- package/dist/config/resolve-remote.d.ts +7 -0
- package/dist/config/resolve-remote.js +81 -0
- package/dist/config/types.d.ts +159 -0
- package/dist/config/types.js +2 -0
- package/dist/core/client.d.ts +100 -0
- package/dist/core/client.js +273 -0
- package/dist/core/conflict.d.ts +5 -0
- package/dist/core/conflict.js +38 -0
- package/dist/core/meta-store.d.ts +28 -0
- package/dist/core/meta-store.js +64 -0
- package/dist/core/outbox-store.d.ts +45 -0
- package/dist/core/outbox-store.js +141 -0
- package/dist/core/schema-manager.d.ts +39 -0
- package/dist/core/schema-manager.js +150 -0
- package/dist/core/sync-worker.d.ts +74 -0
- package/dist/core/sync-worker.js +335 -0
- package/dist/core/table-manager.d.ts +19 -0
- package/dist/core/table-manager.js +74 -0
- package/dist/core/types.d.ts +73 -0
- package/dist/core/types.js +2 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +33 -0
- package/dist/react/index.d.ts +34 -0
- package/dist/react/index.js +103 -0
- package/dist/reactive/event-emitter.d.ts +7 -0
- package/dist/reactive/event-emitter.js +34 -0
- package/dist/utils/logger.d.ts +51 -0
- package/dist/utils/logger.js +169 -0
- package/dist/utils/sql.d.ts +4 -0
- package/dist/utils/sql.js +9 -0
- package/dist/utils/uuid.d.ts +7 -0
- package/dist/utils/uuid.js +27 -0
- package/package.json +130 -3
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FirestoreRemoteAdapter = void 0;
|
|
4
|
+
const logger_js_1 = require("../../utils/logger.js");
|
|
5
|
+
/**
|
|
6
|
+
* Safely extracts epoch milliseconds from numbers, Firestore Timestamps, or ISO strings.
|
|
7
|
+
*/
|
|
8
|
+
function extractTimestamp(val) {
|
|
9
|
+
if (!val)
|
|
10
|
+
return Date.now();
|
|
11
|
+
if (typeof val === 'number')
|
|
12
|
+
return val;
|
|
13
|
+
if (typeof val.toMillis === 'function')
|
|
14
|
+
return val.toMillis();
|
|
15
|
+
if (typeof val.toDate === 'function')
|
|
16
|
+
return val.toDate().getTime();
|
|
17
|
+
if (typeof val.seconds === 'number') {
|
|
18
|
+
return val.seconds * 1000 + Math.floor((val.nanoseconds || 0) / 1000000);
|
|
19
|
+
}
|
|
20
|
+
if (typeof val.string === 'string') {
|
|
21
|
+
const parsed = Date.parse(val);
|
|
22
|
+
if (!isNaN(parsed))
|
|
23
|
+
return parsed;
|
|
24
|
+
}
|
|
25
|
+
return Date.now();
|
|
26
|
+
}
|
|
27
|
+
class FirestoreRemoteAdapter {
|
|
28
|
+
db;
|
|
29
|
+
tables;
|
|
30
|
+
primaryKey;
|
|
31
|
+
deletedColumn;
|
|
32
|
+
updatedAtColumn;
|
|
33
|
+
firestoreModule;
|
|
34
|
+
unsubscribers = [];
|
|
35
|
+
logger;
|
|
36
|
+
constructor(db, options = {}) {
|
|
37
|
+
if (!db) {
|
|
38
|
+
throw new Error('FirestoreRemoteAdapter requires a firestore db instance.');
|
|
39
|
+
}
|
|
40
|
+
this.db = db;
|
|
41
|
+
this.tables = options.tables ?? [];
|
|
42
|
+
this.primaryKey = options.primaryKey ?? 'id';
|
|
43
|
+
this.deletedColumn = options.deletedColumn ?? 'deleted';
|
|
44
|
+
this.updatedAtColumn = options.updatedAtColumn ?? 'updatedAt';
|
|
45
|
+
this.firestoreModule = options.firestoreModule;
|
|
46
|
+
if (options.logger instanceof logger_js_1.SyncLogger) {
|
|
47
|
+
this.logger = options.logger;
|
|
48
|
+
}
|
|
49
|
+
else if (typeof options.logger === 'boolean') {
|
|
50
|
+
this.logger = new logger_js_1.SyncLogger({ enabled: options.logger, level: options.logLevel });
|
|
51
|
+
}
|
|
52
|
+
else if (options.logger && typeof options.logger === 'object') {
|
|
53
|
+
this.logger = new logger_js_1.SyncLogger({ customLogger: options.logger, level: options.logLevel });
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
this.logger = options.logLevel ? new logger_js_1.SyncLogger({ level: options.logLevel }) : logger_js_1.defaultLogger;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
setTables(tables) {
|
|
60
|
+
this.tables = tables;
|
|
61
|
+
}
|
|
62
|
+
async getModule() {
|
|
63
|
+
if (this.firestoreModule) {
|
|
64
|
+
return this.firestoreModule;
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const dynamicImport = new Function('moduleName', 'return import(moduleName)');
|
|
68
|
+
this.firestoreModule = await dynamicImport('firebase/firestore');
|
|
69
|
+
return this.firestoreModule;
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Pushes outbox operations as batch writes to Firestore.
|
|
77
|
+
* Chunks operations into batches of 450 (below Firestore 500-write limit).
|
|
78
|
+
*/
|
|
79
|
+
async pushChanges(operations) {
|
|
80
|
+
if (!operations || operations.length === 0) {
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
const isCompat = typeof this.db.batch === 'function' && typeof this.db.collection === 'function';
|
|
85
|
+
const mod = isCompat ? null : await this.getModule();
|
|
86
|
+
const CHUNK_SIZE = 450;
|
|
87
|
+
for (let i = 0; i < operations.length; i += CHUNK_SIZE) {
|
|
88
|
+
const chunk = operations.slice(i, i + CHUNK_SIZE);
|
|
89
|
+
const now = Date.now();
|
|
90
|
+
if (isCompat) {
|
|
91
|
+
// React Native Firebase / Compat SDK
|
|
92
|
+
const batch = this.db.batch();
|
|
93
|
+
for (const op of chunk) {
|
|
94
|
+
const docRef = this.db.collection(op.tableName).doc(op.rowId);
|
|
95
|
+
if (op.operation === 'DELETE') {
|
|
96
|
+
batch.set(docRef, {
|
|
97
|
+
[this.primaryKey]: op.rowId,
|
|
98
|
+
[this.deletedColumn]: true,
|
|
99
|
+
[this.updatedAtColumn]: now,
|
|
100
|
+
}, { merge: true });
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
batch.set(docRef, {
|
|
104
|
+
...(op.payload || {}),
|
|
105
|
+
[this.primaryKey]: op.rowId,
|
|
106
|
+
[this.deletedColumn]: false,
|
|
107
|
+
[this.updatedAtColumn]: now,
|
|
108
|
+
}, { merge: true });
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
await batch.commit();
|
|
112
|
+
}
|
|
113
|
+
else if (mod && typeof mod.writeBatch === 'function') {
|
|
114
|
+
// Modular Firebase SDK
|
|
115
|
+
const batch = mod.writeBatch(this.db);
|
|
116
|
+
for (const op of chunk) {
|
|
117
|
+
const docRef = mod.doc(mod.collection(this.db, op.tableName), op.rowId);
|
|
118
|
+
if (op.operation === 'DELETE') {
|
|
119
|
+
batch.set(docRef, {
|
|
120
|
+
[this.primaryKey]: op.rowId,
|
|
121
|
+
[this.deletedColumn]: true,
|
|
122
|
+
[this.updatedAtColumn]: now,
|
|
123
|
+
}, { merge: true });
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
batch.set(docRef, {
|
|
127
|
+
...(op.payload || {}),
|
|
128
|
+
[this.primaryKey]: op.rowId,
|
|
129
|
+
[this.deletedColumn]: false,
|
|
130
|
+
[this.updatedAtColumn]: now,
|
|
131
|
+
}, { merge: true });
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
await batch.commit();
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
throw new Error('Firestore client does not have .batch() and modular firebase/firestore writeBatch could not be loaded.');
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
this.logger.error((0, logger_js_1.formatFirestoreError)(error, { operation: 'pushChanges' }));
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Fetches delta changes across tracked collections where updatedAt > sinceTimestamp.
|
|
149
|
+
*/
|
|
150
|
+
async fetchChanges(sinceTimestamp) {
|
|
151
|
+
if (!this.tables || this.tables.length === 0) {
|
|
152
|
+
return { timestamp: sinceTimestamp, changes: [] };
|
|
153
|
+
}
|
|
154
|
+
try {
|
|
155
|
+
const isCompat = typeof this.db.collection === 'function';
|
|
156
|
+
const mod = isCompat ? null : await this.getModule();
|
|
157
|
+
let maxServerTimestamp = sinceTimestamp;
|
|
158
|
+
const changes = [];
|
|
159
|
+
for (const table of this.tables) {
|
|
160
|
+
let docs = [];
|
|
161
|
+
if (isCompat) {
|
|
162
|
+
const snapshot = await this.db
|
|
163
|
+
.collection(table)
|
|
164
|
+
.where(this.updatedAtColumn, '>', sinceTimestamp)
|
|
165
|
+
.get();
|
|
166
|
+
docs = snapshot.docs || [];
|
|
167
|
+
}
|
|
168
|
+
else if (mod && typeof mod.getDocs === 'function') {
|
|
169
|
+
const q = mod.query(mod.collection(this.db, table), mod.where(this.updatedAtColumn, '>', sinceTimestamp));
|
|
170
|
+
const snapshot = await mod.getDocs(q);
|
|
171
|
+
docs = snapshot.docs || [];
|
|
172
|
+
}
|
|
173
|
+
for (const doc of docs) {
|
|
174
|
+
const data = typeof doc.data === 'function' ? doc.data() : doc;
|
|
175
|
+
const isSoftDeleted = Boolean(data[this.deletedColumn] === true ||
|
|
176
|
+
data[this.deletedColumn] === 1 ||
|
|
177
|
+
(data[this.deletedColumn] &&
|
|
178
|
+
!['false', '0', 'null', 'undefined'].includes(String(data[this.deletedColumn]).toLowerCase())));
|
|
179
|
+
const rowTime = extractTimestamp(data[this.updatedAtColumn]);
|
|
180
|
+
if (rowTime > maxServerTimestamp) {
|
|
181
|
+
maxServerTimestamp = rowTime;
|
|
182
|
+
}
|
|
183
|
+
const rowId = String(data[this.primaryKey] || doc.id || data.id);
|
|
184
|
+
const operation = isSoftDeleted ? 'DELETE' : 'UPDATE';
|
|
185
|
+
changes.push({
|
|
186
|
+
tableName: table,
|
|
187
|
+
operation,
|
|
188
|
+
rowId,
|
|
189
|
+
payload: isSoftDeleted ? null : data,
|
|
190
|
+
timestamp: rowTime,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
timestamp: changes.length > 0 ? maxServerTimestamp : sinceTimestamp,
|
|
196
|
+
changes,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
this.logger.error((0, logger_js_1.formatFirestoreError)(error, { operation: 'fetchChanges' }));
|
|
201
|
+
return { timestamp: sinceTimestamp, changes: [] };
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Subscribes to live real-time query updates via onSnapshot.
|
|
206
|
+
*/
|
|
207
|
+
subscribeToLiveChanges(callback) {
|
|
208
|
+
this.destroy();
|
|
209
|
+
if (!this.tables || this.tables.length === 0) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
const setupListeners = async () => {
|
|
213
|
+
const isCompat = typeof this.db.collection === 'function';
|
|
214
|
+
const mod = isCompat ? null : await this.getModule();
|
|
215
|
+
const currentCursor = Date.now() - 2000;
|
|
216
|
+
for (const table of this.tables) {
|
|
217
|
+
try {
|
|
218
|
+
const handleSnapshot = (snapshot) => {
|
|
219
|
+
if (!snapshot)
|
|
220
|
+
return;
|
|
221
|
+
let docList = [];
|
|
222
|
+
if (typeof snapshot.docChanges === 'function') {
|
|
223
|
+
const docChanges = snapshot.docChanges();
|
|
224
|
+
if (docChanges && docChanges.length > 0) {
|
|
225
|
+
docList = docChanges.map((dc) => ({
|
|
226
|
+
doc: dc.doc,
|
|
227
|
+
isRemoved: dc.type === 'removed',
|
|
228
|
+
}));
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
else if (snapshot.docs) {
|
|
232
|
+
docList = snapshot.docs.map((doc) => ({ doc, isRemoved: false }));
|
|
233
|
+
}
|
|
234
|
+
if (docList.length === 0)
|
|
235
|
+
return;
|
|
236
|
+
const changes = [];
|
|
237
|
+
for (const item of docList) {
|
|
238
|
+
const doc = item.doc;
|
|
239
|
+
const data = typeof doc.data === 'function' ? doc.data() : doc;
|
|
240
|
+
const isSoftDeleted = Boolean(item.isRemoved ||
|
|
241
|
+
data[this.deletedColumn] === true ||
|
|
242
|
+
data[this.deletedColumn] === 1);
|
|
243
|
+
const rowTime = extractTimestamp(data[this.updatedAtColumn]);
|
|
244
|
+
const rowId = String(data[this.primaryKey] || doc.id || data.id);
|
|
245
|
+
changes.push({
|
|
246
|
+
tableName: table,
|
|
247
|
+
operation: isSoftDeleted ? 'DELETE' : 'UPDATE',
|
|
248
|
+
rowId,
|
|
249
|
+
payload: isSoftDeleted ? null : data,
|
|
250
|
+
timestamp: rowTime,
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
if (changes.length > 0) {
|
|
254
|
+
const maxTime = Math.max(...changes.map((c) => c.timestamp || 0));
|
|
255
|
+
callback({
|
|
256
|
+
timestamp: maxTime > 0 ? maxTime : Date.now(),
|
|
257
|
+
changes,
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
if (isCompat) {
|
|
262
|
+
const unsub = this.db
|
|
263
|
+
.collection(table)
|
|
264
|
+
.where(this.updatedAtColumn, '>', currentCursor)
|
|
265
|
+
.onSnapshot(handleSnapshot, (err) => {
|
|
266
|
+
console.warn(`Firestore onSnapshot error on ${table}:`, err);
|
|
267
|
+
});
|
|
268
|
+
if (typeof unsub === 'function') {
|
|
269
|
+
this.unsubscribers.push(unsub);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
else if (mod && typeof mod.onSnapshot === 'function') {
|
|
273
|
+
const q = mod.query(mod.collection(this.db, table), mod.where(this.updatedAtColumn, '>', currentCursor));
|
|
274
|
+
const unsub = mod.onSnapshot(q, handleSnapshot, (err) => {
|
|
275
|
+
console.warn(`Firestore modular onSnapshot error on ${table}:`, err);
|
|
276
|
+
});
|
|
277
|
+
if (typeof unsub === 'function') {
|
|
278
|
+
this.unsubscribers.push(unsub);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
catch (err) {
|
|
283
|
+
console.warn(`Failed to initialize Firestore live listener for table ${table}:`, err);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
setupListeners();
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Cleans up all active real-time listeners.
|
|
291
|
+
*/
|
|
292
|
+
destroy() {
|
|
293
|
+
for (const unsub of this.unsubscribers) {
|
|
294
|
+
try {
|
|
295
|
+
unsub();
|
|
296
|
+
}
|
|
297
|
+
catch { }
|
|
298
|
+
}
|
|
299
|
+
this.unsubscribers = [];
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
exports.FirestoreRemoteAdapter = FirestoreRemoteAdapter;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { SyncOperation, DeltaChanges } from '../../core/types.js';
|
|
2
|
+
export interface RemoteDBAdapter {
|
|
3
|
+
pushChanges(operations: SyncOperation[]): Promise<boolean>;
|
|
4
|
+
fetchChanges(sinceTimestamp: number): Promise<DeltaChanges>;
|
|
5
|
+
subscribeToLiveChanges(callback: (changes: DeltaChanges) => void): void;
|
|
6
|
+
}
|
|
7
|
+
export * from './supabase.js';
|
|
8
|
+
export * from './demo.js';
|
|
9
|
+
export * from './convex.js';
|
|
10
|
+
export * from './firestore.js';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./supabase.js"), exports);
|
|
18
|
+
__exportStar(require("./demo.js"), exports);
|
|
19
|
+
__exportStar(require("./convex.js"), exports);
|
|
20
|
+
__exportStar(require("./firestore.js"), exports);
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { SupabaseClient } from '@supabase/supabase-js';
|
|
2
|
+
import { RemoteDBAdapter } from './index.js';
|
|
3
|
+
import { DeltaChanges, SyncOperation } from '../../core/types.js';
|
|
4
|
+
import { SyncLogger, CustomLogger, LogLevel } from '../../utils/logger.js';
|
|
5
|
+
export interface SupabaseAdapterOptions {
|
|
6
|
+
/**
|
|
7
|
+
* The list of Postgres tables to sync.
|
|
8
|
+
* e.g. ['todos', 'notes']
|
|
9
|
+
*/
|
|
10
|
+
tables?: string[];
|
|
11
|
+
/**
|
|
12
|
+
* Timestamp column name on Postgres tables used to track updates.
|
|
13
|
+
* Default: 'updated_at'
|
|
14
|
+
*/
|
|
15
|
+
updatedAtColumn?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Primary key column name on Postgres tables.
|
|
18
|
+
* Default: 'id'
|
|
19
|
+
*/
|
|
20
|
+
primaryKey?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Soft-delete column name (e.g. 'deleted', 'is_deleted', or 'deleted_at').
|
|
23
|
+
* Default: 'deleted'
|
|
24
|
+
*/
|
|
25
|
+
deletedColumn?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Value to write when soft-deleting a row.
|
|
28
|
+
* Default: true
|
|
29
|
+
*/
|
|
30
|
+
deletedValue?: any;
|
|
31
|
+
/**
|
|
32
|
+
* Legacy alias for deletedColumn.
|
|
33
|
+
*/
|
|
34
|
+
deletedAtColumn?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Optional custom Postgres RPC function name for batch pushing.
|
|
37
|
+
* If provided, will call `supabase.rpc(pushRpcName, { operations })`.
|
|
38
|
+
*/
|
|
39
|
+
pushRpcName?: string;
|
|
40
|
+
/**
|
|
41
|
+
* Postgres schema name.
|
|
42
|
+
* Default: 'public'
|
|
43
|
+
*/
|
|
44
|
+
schema?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Name of the Realtime channel.
|
|
47
|
+
* Default: 'local_first_sync'
|
|
48
|
+
*/
|
|
49
|
+
channelName?: string;
|
|
50
|
+
/**
|
|
51
|
+
* Custom logger or false to silence logs in production.
|
|
52
|
+
*/
|
|
53
|
+
logger?: SyncLogger | CustomLogger | boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Minimum log level. Default: 'info'
|
|
56
|
+
*/
|
|
57
|
+
logLevel?: LogLevel;
|
|
58
|
+
}
|
|
59
|
+
export declare class SupabaseRemoteAdapter implements RemoteDBAdapter {
|
|
60
|
+
private client;
|
|
61
|
+
private tables;
|
|
62
|
+
private updatedAtColumn;
|
|
63
|
+
private primaryKey;
|
|
64
|
+
private deletedColumn;
|
|
65
|
+
private deletedValue;
|
|
66
|
+
private pushRpcName?;
|
|
67
|
+
private schema;
|
|
68
|
+
private channelName;
|
|
69
|
+
private activeChannel?;
|
|
70
|
+
logger: SyncLogger;
|
|
71
|
+
constructor(client: SupabaseClient, options?: SupabaseAdapterOptions);
|
|
72
|
+
/**
|
|
73
|
+
* Set or update tracked tables dynamically.
|
|
74
|
+
*/
|
|
75
|
+
setTables(tables: string[]): void;
|
|
76
|
+
/**
|
|
77
|
+
* Pushes outbox operations to Supabase.
|
|
78
|
+
*/
|
|
79
|
+
pushChanges(operations: SyncOperation[]): Promise<boolean>;
|
|
80
|
+
/**
|
|
81
|
+
* Fetches delta changes from Supabase since a given timestamp.
|
|
82
|
+
* Reads updated records and checks `deleted: true` to propagate soft deletes.
|
|
83
|
+
*/
|
|
84
|
+
fetchChanges(sinceTimestamp: number): Promise<DeltaChanges>;
|
|
85
|
+
/**
|
|
86
|
+
* Helper to determine if a record represents a soft delete.
|
|
87
|
+
*/
|
|
88
|
+
private isSoftDeleted;
|
|
89
|
+
/**
|
|
90
|
+
* Subscribes to live realtime postgres_changes from Supabase.
|
|
91
|
+
*/
|
|
92
|
+
subscribeToLiveChanges(callback: (changes: DeltaChanges) => void): void;
|
|
93
|
+
/**
|
|
94
|
+
* Clean up active realtime channels.
|
|
95
|
+
*/
|
|
96
|
+
destroy(): void;
|
|
97
|
+
}
|