local-lite 0.0.0-stage → 0.0.2

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.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +361 -2
  3. package/dist/adapters/local/better-sqlite3.d.ts +23 -0
  4. package/dist/adapters/local/better-sqlite3.js +46 -0
  5. package/dist/adapters/local/expo-sqlite.d.ts +8 -0
  6. package/dist/adapters/local/expo-sqlite.js +30 -0
  7. package/dist/adapters/local/index.d.ts +13 -0
  8. package/dist/adapters/local/index.js +22 -0
  9. package/dist/adapters/local/libsql.d.ts +24 -0
  10. package/dist/adapters/local/libsql.js +87 -0
  11. package/dist/adapters/local/node-sqlite.d.ts +24 -0
  12. package/dist/adapters/local/node-sqlite.js +44 -0
  13. package/dist/adapters/local/op-sqlite.d.ts +26 -0
  14. package/dist/adapters/local/op-sqlite.js +59 -0
  15. package/dist/adapters/local/sql-js.d.ts +26 -0
  16. package/dist/adapters/local/sql-js.js +63 -0
  17. package/dist/adapters/network/index.d.ts +11 -0
  18. package/dist/adapters/network/index.js +53 -0
  19. package/dist/adapters/remote/convex.d.ts +71 -0
  20. package/dist/adapters/remote/convex.js +185 -0
  21. package/dist/adapters/remote/demo.d.ts +21 -0
  22. package/dist/adapters/remote/demo.js +46 -0
  23. package/dist/adapters/remote/firestore.d.ts +64 -0
  24. package/dist/adapters/remote/firestore.js +302 -0
  25. package/dist/adapters/remote/index.d.ts +10 -0
  26. package/dist/adapters/remote/index.js +20 -0
  27. package/dist/adapters/remote/supabase.d.ts +97 -0
  28. package/dist/adapters/remote/supabase.js +276 -0
  29. package/dist/config/index.d.ts +24 -0
  30. package/dist/config/index.js +101 -0
  31. package/dist/config/resolve-local.d.ts +7 -0
  32. package/dist/config/resolve-local.js +68 -0
  33. package/dist/config/resolve-remote.d.ts +7 -0
  34. package/dist/config/resolve-remote.js +81 -0
  35. package/dist/config/types.d.ts +159 -0
  36. package/dist/config/types.js +2 -0
  37. package/dist/core/client.d.ts +153 -0
  38. package/dist/core/client.js +445 -0
  39. package/dist/core/conflict.d.ts +5 -0
  40. package/dist/core/conflict.js +38 -0
  41. package/dist/core/meta-store.d.ts +28 -0
  42. package/dist/core/meta-store.js +64 -0
  43. package/dist/core/outbox-store.d.ts +76 -0
  44. package/dist/core/outbox-store.js +265 -0
  45. package/dist/core/query.d.ts +13 -0
  46. package/dist/core/query.js +150 -0
  47. package/dist/core/schema-manager.d.ts +39 -0
  48. package/dist/core/schema-manager.js +150 -0
  49. package/dist/core/sync-worker.d.ts +89 -0
  50. package/dist/core/sync-worker.js +473 -0
  51. package/dist/core/table-manager.d.ts +19 -0
  52. package/dist/core/table-manager.js +74 -0
  53. package/dist/core/types.d.ts +156 -0
  54. package/dist/core/types.js +2 -0
  55. package/dist/index.d.ts +18 -0
  56. package/dist/index.js +34 -0
  57. package/dist/react/index.d.ts +50 -0
  58. package/dist/react/index.js +174 -0
  59. package/dist/reactive/event-emitter.d.ts +7 -0
  60. package/dist/reactive/event-emitter.js +34 -0
  61. package/dist/utils/logger.d.ts +51 -0
  62. package/dist/utils/logger.js +169 -0
  63. package/dist/utils/sql.d.ts +4 -0
  64. package/dist/utils/sql.js +9 -0
  65. package/dist/utils/uuid.d.ts +7 -0
  66. package/dist/utils/uuid.js +27 -0
  67. package/package.json +131 -4
@@ -0,0 +1,159 @@
1
+ import { LocalDBAdapter } from '../adapters/local/index.js';
2
+ import { RemoteDBAdapter } from '../adapters/remote/index.js';
3
+ import { ConflictResolver, ConflictStrategy, NetworkStatusProvider, RetryConfig } from '../core/types.js';
4
+ import { SyncLogger, CustomLogger, LogLevel } from '../utils/logger.js';
5
+ export interface SupabaseConfigOptions {
6
+ url?: string;
7
+ anonKey?: string;
8
+ client?: any;
9
+ schema?: string;
10
+ updatedAtColumn?: string;
11
+ deletedColumn?: string;
12
+ deletedValue?: any;
13
+ deletedAtColumn?: string;
14
+ pushRpcName?: string;
15
+ channelName?: string;
16
+ }
17
+ export interface ConvexConfigOptions {
18
+ /**
19
+ * ConvexClient instance.
20
+ */
21
+ client: any;
22
+ /**
23
+ * Primary key field name. Default: config.primaryKey or 'id'
24
+ */
25
+ primaryKey?: string;
26
+ /**
27
+ * Convex mutation function or name for pushing changes.
28
+ * Default: 'sync:pushBatch'
29
+ */
30
+ pushMutation?: any;
31
+ /**
32
+ * Convex query function or name for pulling changes.
33
+ * Default: 'sync:pullDeltas'
34
+ */
35
+ pullQuery?: any;
36
+ /**
37
+ * Column used for soft deletes. Default: 'deleted'
38
+ */
39
+ deletedColumn?: string;
40
+ /**
41
+ * Column used for updatedAt timestamp. Default: 'updatedAt'
42
+ */
43
+ updatedAtColumn?: string;
44
+ }
45
+ export interface FirebaseConfigOptions {
46
+ /**
47
+ * Firestore database instance (from modular firebase/firestore, @react-native-firebase/firestore, or compat SDK).
48
+ */
49
+ firestore: any;
50
+ /**
51
+ * Primary key field name. Default: config.primaryKey or 'id'
52
+ */
53
+ primaryKey?: string;
54
+ /**
55
+ * Field used for soft deletes. Default: 'deleted'
56
+ */
57
+ deletedColumn?: string;
58
+ /**
59
+ * Field used for updatedAt timestamp tracking. Default: 'updatedAt'
60
+ */
61
+ updatedAtColumn?: string;
62
+ /**
63
+ * Optional reference to modular firebase/firestore module if not globally available.
64
+ */
65
+ firestoreModule?: any;
66
+ }
67
+ export interface LocalLiteConfig {
68
+ /**
69
+ * Local SQLite Database instance, name, factory function, or LocalDBAdapter.
70
+ * - Pass an Expo database instance (e.g. from SQLite.openDatabaseAsync('app.db'))
71
+ * - Pass a factory: () => SQLite.openDatabaseAsync('app.db')
72
+ * - Pass a database file name: 'app.db'
73
+ * - Or a custom LocalDBAdapter
74
+ */
75
+ database?: any | string | (() => Promise<any> | any) | LocalDBAdapter;
76
+ /**
77
+ * Database name if database is not provided. Default: 'local_lite.db'
78
+ */
79
+ databaseName?: string;
80
+ /**
81
+ * List of tables to sync.
82
+ * e.g. ['todos', 'notes']
83
+ */
84
+ tables?: string[];
85
+ /**
86
+ * Initial SQL table schema migration queries to execute on startup.
87
+ * e.g. ["CREATE TABLE IF NOT EXISTS todos (id TEXT PRIMARY KEY, title TEXT);"]
88
+ */
89
+ migrations?: string[];
90
+ /**
91
+ * Automatically create tables and columns dynamically on the fly without manual SQL migrations.
92
+ * When true (default if migrations is not provided), tables in `tables` are created automatically,
93
+ * and any missing columns are added dynamically on insert/update/pull.
94
+ */
95
+ autoSchema?: boolean;
96
+ /**
97
+ * Primary key column. Default: 'id'
98
+ */
99
+ primaryKey?: string;
100
+ /**
101
+ * Supabase backend connection options.
102
+ */
103
+ supabase?: SupabaseConfigOptions;
104
+ /**
105
+ * Convex backend connection options.
106
+ */
107
+ convex?: ConvexConfigOptions;
108
+ /**
109
+ * Firebase / Firestore backend connection options.
110
+ */
111
+ firebase?: FirebaseConfigOptions;
112
+ /**
113
+ * Custom remote adapter (overrides Supabase / Convex / Firebase).
114
+ */
115
+ remote?: RemoteDBAdapter;
116
+ /**
117
+ * Whether to use an in-memory simulated remote backend if Supabase, Convex, or Firebase credentials are not provided.
118
+ * Allows running and testing full local-first sync workflows without cloud infrastructure.
119
+ * Default: true
120
+ */
121
+ inMemoryRemote?: boolean;
122
+ /**
123
+ * Conflict resolution strategy. Default: 'last-write-wins'
124
+ */
125
+ conflictResolver?: ConflictStrategy | ConflictResolver;
126
+ /**
127
+ * Periodic outbox push interval in ms. Default: 5000
128
+ */
129
+ pushIntervalMs?: number;
130
+ /**
131
+ * Periodic remote pull interval in ms. Default: 10000
132
+ */
133
+ pullIntervalMs?: number;
134
+ /**
135
+ * Maximum retry attempts for failed push items. Default: 5
136
+ */
137
+ maxRetries?: number;
138
+ /**
139
+ * Advanced retry configuration with exponential backoff and custom retry predicates.
140
+ */
141
+ retry?: number | RetryConfig;
142
+ /**
143
+ * Custom logger or false to silence logs in production.
144
+ */
145
+ logger?: SyncLogger | CustomLogger | boolean;
146
+ /**
147
+ * Minimum log level. Default: 'info'
148
+ */
149
+ logLevel?: LogLevel;
150
+ /**
151
+ * Network status provider. Default: DefaultNetworkStatusProvider
152
+ */
153
+ network?: NetworkStatusProvider;
154
+ /**
155
+ * Automatically call client.initialize() and create tables.
156
+ * Default: true
157
+ */
158
+ autoInitialize?: boolean;
159
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,153 @@
1
+ import { LocalDBAdapter, LocalTransaction } from '../adapters/local/index.js';
2
+ import { RemoteDBAdapter } from '../adapters/remote/index.js';
3
+ import { EventEmitter } from '../reactive/event-emitter.js';
4
+ import { SyncWorker } from './sync-worker.js';
5
+ import { SchemaManager } from './schema-manager.js';
6
+ import { BatchMutation, ConflictResolver, ConflictStrategy, MutateOptions, NetworkStatusProvider, OutboxRecord, OutboxStatus, QueryOptions, RetryConfig, SyncMetrics, SyncOp, TableChangeEvent } from './types.js';
7
+ import { SyncLogger, CustomLogger, LogLevel } from '../utils/logger.js';
8
+ export interface LocalFirstClientConfig {
9
+ local: LocalDBAdapter;
10
+ remote: RemoteDBAdapter;
11
+ network?: NetworkStatusProvider;
12
+ conflictResolver?: ConflictStrategy | ConflictResolver;
13
+ primaryKey?: string;
14
+ pushIntervalMs?: number;
15
+ pullIntervalMs?: number;
16
+ maxRetries?: number;
17
+ retry?: number | RetryConfig;
18
+ logger?: SyncLogger | CustomLogger | boolean;
19
+ logLevel?: LogLevel;
20
+ autoSchema?: boolean;
21
+ tables?: string[];
22
+ }
23
+ export declare class TransactionalClient {
24
+ private parent;
25
+ private tx;
26
+ private queuedTableEvents;
27
+ private queuedOutboxIds;
28
+ constructor(parent: LocalFirstClient, tx: LocalTransaction, queuedTableEvents: Array<{
29
+ tableName: string;
30
+ event: TableChangeEvent;
31
+ }>, queuedOutboxIds: string[]);
32
+ mutate(tableName: string, rowId: string, operation: SyncOp, payload: Record<string, any> | null, options?: MutateOptions): Promise<void>;
33
+ insert(tableName: string, rowIdOrPayload: string | Record<string, any>, payloadOrOptions?: Record<string, any> | MutateOptions, options?: MutateOptions): Promise<string>;
34
+ update(tableName: string, rowId: string, payload: Record<string, any>, options?: MutateOptions): Promise<void>;
35
+ delete(tableName: string, rowId: string, options?: MutateOptions): Promise<void>;
36
+ get rawTx(): LocalTransaction;
37
+ }
38
+ export declare class LocalFirstClient {
39
+ db: LocalDBAdapter;
40
+ remote: RemoteDBAdapter;
41
+ events: EventEmitter;
42
+ syncWorker: SyncWorker;
43
+ schemaManager: SchemaManager;
44
+ autoSchema: boolean;
45
+ tables: string[];
46
+ private primaryKey;
47
+ constructor(config: LocalFirstClientConfig);
48
+ getPrimaryKey(): string;
49
+ /**
50
+ * Initializes the client: creates sync_outbox schema, ensures autoSchema tables if enabled,
51
+ * and starts the background sync worker.
52
+ */
53
+ initialize(): Promise<void>;
54
+ /**
55
+ * Performs an atomic dual-write: mutates the local data table AND writes
56
+ * to sync_outbox within the same database transaction.
57
+ */
58
+ mutate(tableName: string, rowId: string, operation: SyncOp, payload: Record<string, any> | null, options?: MutateOptions): Promise<void>;
59
+ /**
60
+ * Executes multiple mutations in a single atomic database transaction.
61
+ * Inserts all corresponding outbox entries together and schedules a single push.
62
+ */
63
+ batch(mutations: BatchMutation[], options?: MutateOptions): Promise<string[]>;
64
+ /**
65
+ * Convenience helper to insert an array of records into a table atomically.
66
+ */
67
+ insertMany(tableName: string, records: Record<string, any>[], options?: MutateOptions): Promise<string[]>;
68
+ /**
69
+ * Runs an arbitrary callback inside an atomic transaction with a scoped TransactionalClient.
70
+ * If the callback resolves, all changes and outbox records commit and events are emitted.
71
+ * If the callback throws, SQLite rolls back and no change events are emitted.
72
+ */
73
+ transaction<T>(action: (txClient: TransactionalClient) => Promise<T>): Promise<T>;
74
+ /**
75
+ * Convenience helper to insert a record into a table.
76
+ * Auto-generates a UUID if rowId is omitted or passed inside payload.
77
+ *
78
+ * Example:
79
+ * await client.insert('todos', { title: 'Buy milk' });
80
+ * await client.insert('todos', 'custom-id', { title: 'Buy milk' });
81
+ */
82
+ insert(tableName: string, rowIdOrPayload: string | Record<string, any>, payloadOrOptions?: Record<string, any> | MutateOptions, options?: MutateOptions): Promise<string>;
83
+ /**
84
+ * Convenience helper to update an existing record by ID.
85
+ *
86
+ * Example:
87
+ * await client.update('todos', 'todo-1', { completed: 1 });
88
+ */
89
+ update(tableName: string, rowId: string, payload: Record<string, any>, options?: MutateOptions): Promise<void>;
90
+ /**
91
+ * Convenience helper to delete a record by ID.
92
+ *
93
+ * Example:
94
+ * await client.delete('todos', 'todo-1');
95
+ */
96
+ delete(tableName: string, rowId: string, options?: MutateOptions): Promise<void>;
97
+ /**
98
+ * Reads records from a local SQLite table without requiring manual SQL.
99
+ * Supports where filtering with rich operators ($in, $gt, $contains, $or, etc.), order, limit, and offset.
100
+ * Gracefully returns [] if table or columns have not been populated yet on empty schemas.
101
+ *
102
+ * Example:
103
+ * const tenants = await client.findMany('tenants', { where: { status: 'ACTIVE' }, orderBy: 'name' });
104
+ * const expensive = await client.findMany('properties', { where: { rent: { $gte: 2000 } } });
105
+ */
106
+ findMany<T = any>(tableName: string, options?: QueryOptions): Promise<T[]>;
107
+ /**
108
+ * Finds a single record by primary key.
109
+ *
110
+ * Example:
111
+ * const tenant = await client.findById('tenants', 'ten-1');
112
+ */
113
+ findById<T = any>(tableName: string, id: string): Promise<T | null>;
114
+ /**
115
+ * Tracks an existing mutation into sync_outbox without modifying the table.
116
+ * Can accept an external transaction `options.tx` for custom atomic SQL workflows.
117
+ */
118
+ trackMutation(tableName: string, rowId: string, operation: SyncOp, payload: Record<string, any> | null, options?: MutateOptions): Promise<string>;
119
+ /**
120
+ * Returns real-time telemetry metrics captured by the sync engine.
121
+ */
122
+ getMetrics(): Promise<SyncMetrics>;
123
+ /**
124
+ * Fetches outbox records with optional status filtering and pagination.
125
+ */
126
+ getOutboxRecords(options?: {
127
+ status?: OutboxStatus;
128
+ limit?: number;
129
+ offset?: number;
130
+ }): Promise<OutboxRecord[]>;
131
+ /**
132
+ * Re-queues failed outbox mutations for retry by resetting their status to PENDING.
133
+ * Triggers an immediate sync push.
134
+ */
135
+ retryFailedMutations(ids?: string[]): Promise<number>;
136
+ /**
137
+ * Permanently clears failed mutations (removes poison-pill outbox records).
138
+ */
139
+ clearFailedMutations(ids?: string[]): Promise<number>;
140
+ /**
141
+ * Retrieves the persisted last_synced_at timestamp cursor (in ms).
142
+ */
143
+ getLastSyncedAt(): Promise<number>;
144
+ /**
145
+ * Resets the persistent sync cursor back to 0, forcing the next pull
146
+ * to query all remote records.
147
+ */
148
+ resetSyncCursor(): Promise<void>;
149
+ /**
150
+ * Stops all active intervals, background sync loops, and network listeners.
151
+ */
152
+ stop(): void;
153
+ }