edmaxlabs-core 1.3.4 → 1.3.6

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/dist/index.d.cts CHANGED
@@ -1,7 +1,3 @@
1
- import * as idb from 'idb';
2
- import * as _socket_io_component_emitter from '@socket.io/component-emitter';
3
- import { Socket } from 'socket.io-client';
4
-
5
1
  interface TimestampData {
6
2
  seconds: number;
7
3
  nanoseconds: number;
@@ -95,6 +91,14 @@ declare class Authentication {
95
91
  }>;
96
92
  }
97
93
 
94
+ declare class DocumentSnapshot {
95
+ id: string;
96
+ data: Record<string, any>;
97
+ private constructor();
98
+ static fromMap(map: Record<string, any>): DocumentSnapshot;
99
+ toMap(): Record<string, any>;
100
+ }
101
+
98
102
  declare class ArraySnapshot {
99
103
  id?: string;
100
104
  data: Record<string, any>;
@@ -105,12 +109,19 @@ declare class ArraySnapshot {
105
109
  }
106
110
 
107
111
  declare class Array {
108
- db: EdmaxLabs;
109
- collection: string;
110
- key: string;
111
- docID: string;
112
- constructor(db: EdmaxLabs, collection: string, key: string, id: string);
112
+ private app;
113
+ readonly collection: string;
114
+ readonly key: string;
115
+ readonly docID: string;
116
+ private persistence;
117
+ private syncEngine;
118
+ private localStore;
119
+ constructor(app: EdmaxLabs, collection: string, key: string, id: string);
120
+ /**
121
+ * Get current array elements (offline-first: prefers local cache)
122
+ */
113
123
  show(): Promise<ArraySnapshot[]>;
124
+ private refreshFromRemote;
114
125
  push(data: any, id?: string): Promise<ArraySnapshot | null>;
115
126
  update(position: number, data: any, id?: string): Promise<ArraySnapshot | null>;
116
127
  insert(position: number, data: any, id?: string): Promise<ArraySnapshot | null>;
@@ -118,36 +129,59 @@ declare class Array {
118
129
  remove(position: number): Promise<ArraySnapshot | null>;
119
130
  }
120
131
 
121
- declare class DocumentSnapshot {
122
- id: string;
123
- data: Record<string, any>;
124
- private constructor();
125
- static fromMap(map: Record<string, any>): DocumentSnapshot;
126
- toMap(): Record<string, any>;
127
- }
128
-
129
132
  declare class DocumentRef {
130
- db: EdmaxLabs;
131
- collection: string;
132
- id: string;
133
- constructor(db: EdmaxLabs, collection: string, id: string);
133
+ private app;
134
+ readonly collection: string;
135
+ readonly id: string;
136
+ private persistence;
137
+ private syncEngine;
138
+ private localStore;
139
+ constructor(app: EdmaxLabs, collection: string, id: string);
134
140
  get(): Promise<DocumentSnapshot | null>;
135
- set(data: any): Promise<DocumentSnapshot | null>;
136
- update(data: any): Promise<DocumentSnapshot | null>;
137
- delete(): Promise<DocumentSnapshot | null>;
141
+ private refreshFromRemote;
142
+ set(data: Record<string, any>): Promise<DocumentSnapshot | null>;
143
+ update(data: Record<string, any>): Promise<DocumentSnapshot | null>;
144
+ delete(): Promise<boolean>;
138
145
  array(key: string): Array;
139
- /**
140
- * Realtime listener for a single document
141
- */
142
- onSnapshot(callback: (snapshot: DocumentSnapshot, change: string) => void): () => void;
146
+ onSnapshot(callback: (snapshot: DocumentSnapshot | null, change: string) => void): () => void;
143
147
  }
144
148
 
145
- declare class CollectionRef$1 {
146
- db: EdmaxLabs;
147
- constructor(db: EdmaxLabs);
148
- getIDB: (collection: string) => Promise<idb.IDBPDatabase<unknown>>;
149
- syncPendingWrite(id: string, collection?: string): Promise<boolean | undefined>;
150
- syncPendingWrites(collection: string): Promise<void>;
149
+ type ChangeType = "init" | "local_create" | "local_update" | "local_delete" | "remote_create" | "remote_update" | "remote_delete" | "sync" | "error";
150
+ type DocListener = (snapshot: DocumentSnapshot | null, change: ChangeType) => void;
151
+ /**
152
+ * For collection listeners we pass:
153
+ * - snapshots: all current documents in the collection
154
+ * - change: what triggered this emission
155
+ * - changedDocId?: which specific document changed (useful for granular updates)
156
+ */
157
+ type CollectionListener = (snapshots: DocumentSnapshot[], change: ChangeType, changedDocId?: string) => void;
158
+ declare class LocalStore {
159
+ private documentListeners;
160
+ private collectionListeners;
161
+ private docKey;
162
+ subscribeToDocument(collection: string, id: string, callback: DocListener): () => void;
163
+ subscribeToCollection(collection: string, callback: CollectionListener): () => void;
164
+ /**
165
+ * Notify all listeners for a specific document
166
+ */
167
+ emitDocument(collection: string, id: string, snapshot: DocumentSnapshot | null, change: ChangeType): void;
168
+ /**
169
+ * Notify all listeners for a collection.
170
+ * This is the most important fix — collection listeners now receive the full list.
171
+ */
172
+ emitCollection(collection: string, snapshots: DocumentSnapshot[], // ← Changed from single snapshot
173
+ change: ChangeType, changedDocId?: string): void;
174
+ /**
175
+ * Clear all listeners (useful for testing or when persistence is disabled)
176
+ */
177
+ clearAllListeners(): void;
178
+ /**
179
+ * Get current listener count (for debugging / dev tools)
180
+ */
181
+ get listenerCount(): {
182
+ documents: number;
183
+ collections: number;
184
+ };
151
185
  }
152
186
 
153
187
  type FilterExpression = {
@@ -156,48 +190,53 @@ type FilterExpression = {
156
190
  value: any;
157
191
  };
158
192
  declare class Query {
159
- db: EdmaxLabs;
160
- collection: string;
193
+ private app;
194
+ private collection;
161
195
  private filter;
162
- constructor(db: EdmaxLabs, collection: string);
163
- where(expression: FilterExpression): this;
196
+ constructor(app: EdmaxLabs, collection: string);
197
+ where(expression: FilterExpression): Query;
164
198
  private buildFilter;
165
199
  get(): Promise<DocumentSnapshot[]>;
166
- update(): Promise<DocumentSnapshot[]>;
167
- onSnapshot(callback: (snapshot: DocumentSnapshot, change: string) => void): () => void;
200
+ private refreshFromRemote;
201
+ update(data: Record<string, any>): Promise<any>;
202
+ onSnapshot(callback: CollectionListener): () => void;
168
203
  }
169
204
 
170
205
  declare class CollectionRef {
171
- db: EdmaxLabs;
172
- collection: string;
173
- persistence: CollectionRef$1;
174
- constructor(db: EdmaxLabs, collection: string);
206
+ private app;
207
+ readonly collection: string;
208
+ private persistence;
209
+ private syncEngine;
210
+ private localStore;
211
+ constructor(app: EdmaxLabs, collection: string);
175
212
  doc(id: string): DocumentRef;
176
213
  get query(): Query;
177
214
  get(): Promise<DocumentSnapshot[]>;
178
- add(data: any): Promise<DocumentSnapshot | null>;
179
- /**
180
- * Realtime listener for entire collection
181
- */
182
- onSnapshot(callback: (snapshot: DocumentSnapshot, change: string) => void): () => void;
215
+ private refreshFromRemote;
216
+ add(data: Record<string, any>): Promise<DocumentSnapshot | null>;
217
+ onSnapshot(callback: CollectionListener): () => void;
183
218
  }
184
219
 
185
220
  declare class Batch {
186
- app: EdmaxLabs;
187
- ops: any[];
221
+ private app;
222
+ private ops;
188
223
  constructor(app: EdmaxLabs);
189
- set(docRef: DocumentRef, data: any): this;
190
- update(docRef: DocumentRef, data: any): this;
191
- delete(docRef: DocumentRef): this;
224
+ set(docRef: DocumentRef, data: any): Batch;
225
+ update(docRef: DocumentRef, data: any): Batch;
226
+ delete(docRef: DocumentRef): Batch;
192
227
  commit(): Promise<any>;
193
228
  }
194
229
 
195
230
  declare class Database {
196
- app: EdmaxLabs;
231
+ private app;
197
232
  constructor(app: EdmaxLabs);
198
233
  collection(name: string): CollectionRef;
199
234
  doc(path: string): DocumentRef;
200
235
  batch(): Batch;
236
+ /**
237
+ * Server-side transaction (unchanged, but improved error handling)
238
+ * This remains online-only for now — offline transactions are complex and can be added later as opt-in.
239
+ */
201
240
  runTransaction(transactionFn: (tx: {
202
241
  ops: any[];
203
242
  get: (docRef: DocumentRef) => Promise<any>;
@@ -205,25 +244,45 @@ declare class Database {
205
244
  update: (docRef: DocumentRef, data: any) => void;
206
245
  delete: (docRef: DocumentRef) => void;
207
246
  }) => Promise<void>): Promise<any>;
247
+ /**
248
+ * Returns true if persistence is enabled and we are currently offline
249
+ */
250
+ private get shouldUseOffline();
251
+ /**
252
+ * Returns the SyncEngine if persistence is enabled
253
+ */
254
+ private get syncEngine();
255
+ /**
256
+ * Returns the RealtimeBridge if persistence is enabled
257
+ */
258
+ private get realtimeBridge();
208
259
  }
209
260
 
210
261
  declare class Realtime {
211
- db: EdmaxLabs;
212
- socket: Socket | null;
213
- events: string[];
214
- constructor(db: EdmaxLabs);
215
- connect(): Socket<_socket_io_component_emitter.DefaultEventsMap, _socket_io_component_emitter.DefaultEventsMap>;
262
+ private app;
263
+ private socket;
264
+ private readonly events;
265
+ private subscriptions;
266
+ constructor(app: EdmaxLabs);
267
+ private connect;
268
+ private setupSocketListeners;
216
269
  on(event: string, cb: (...args: any[]) => void): void;
217
270
  off(event: string, cb?: (...args: any[]) => void): void;
218
271
  emit(event: string, data: any): void;
219
272
  /**
220
- * Realtime listener for entire collection
273
+ * Low-level collection subscription (used by RealtimeBridge)
221
274
  */
222
- subscribeToCollection(collection: string, callback: (snapshot: DocumentSnapshot, change: string) => void, filter?: Record<string, any>): () => void;
275
+ subscribeToCollectionRaw(collection: string, callback: (payload: any, change: string) => void, filter?: Record<string, any>): () => void;
223
276
  /**
224
- * Realtime listener for a single document
277
+ * Low-level document subscription (used by RealtimeBridge)
225
278
  */
226
- subscribeToDocument(collection: string, id: string, callback: (snapshot: DocumentSnapshot, change: string) => void): () => void;
279
+ subscribeToDocumentRaw(collection: string, id: string, callback: (payload: any, change: string) => void): () => void;
280
+ private normalizePayload;
281
+ private registerSubscription;
282
+ private resubscribeAll;
283
+ private cleanupSubscription;
284
+ disconnect(): void;
285
+ dispose(): void;
227
286
  }
228
287
 
229
288
  declare class Functions {
@@ -232,10 +291,108 @@ declare class Functions {
232
291
  call(functionName: string, data?: Record<string, any>): Promise<any>;
233
292
  }
234
293
 
235
- declare class Hosting {
236
- app: EdmaxLabs;
237
- constructor(app: EdmaxLabs);
238
- createSubdomain(name: string): Promise<any>;
294
+ type LocalDocStatus = "synced" | "pending" | "failed";
295
+ interface LocalDoc {
296
+ key: string;
297
+ collection: string;
298
+ id: string;
299
+ data: Record<string, any>;
300
+ exists: boolean;
301
+ pending: number;
302
+ status: LocalDocStatus;
303
+ localOnly: boolean;
304
+ deleted: boolean;
305
+ updatedAt: number;
306
+ lastSyncedAt?: number;
307
+ revision?: string | number;
308
+ }
309
+
310
+ type MutationType = "create" | "update" | "delete" | "array_push" | "array_update" | "array_insert" | "array_remove";
311
+ type MutationStatus = "pending" | "syncing" | "failed";
312
+ interface MutationRecord {
313
+ mutationId: string;
314
+ collection: string;
315
+ documentId: string;
316
+ type: MutationType;
317
+ payload: Record<string, any> | null;
318
+ status: MutationStatus;
319
+ createdAt: number;
320
+ updatedAt: number;
321
+ retryCount: number;
322
+ error?: string;
323
+ baseRevision?: string | number;
324
+ }
325
+
326
+ declare class Persistence {
327
+ private dbPromise;
328
+ constructor();
329
+ private docKey;
330
+ private now;
331
+ private getDb;
332
+ getDoc(collection: string, id: string): Promise<LocalDoc | null>;
333
+ getDocSnapshot(collection: string, id: string): Promise<DocumentSnapshot | null>;
334
+ getCollection(collection: string): Promise<LocalDoc[]>;
335
+ getCollectionSnapshots(collection: string): Promise<DocumentSnapshot[]>;
336
+ upsertDoc(input: Omit<LocalDoc, "key" | "updatedAt"> & {
337
+ updatedAt?: number;
338
+ }): Promise<LocalDoc>;
339
+ markDeleted(collection: string, id: string, pending?: number): Promise<LocalDoc>;
340
+ enqueueMutation(mutation: Omit<MutationRecord, "updatedAt" | "createdAt" | "retryCount" | "status">): Promise<MutationRecord>;
341
+ getPendingMutations(): Promise<MutationRecord[]>;
342
+ setMutationStatus(mutationId: string, status: MutationRecord["status"], error?: string): Promise<MutationRecord | null>;
343
+ removeMutation(mutationId: string): Promise<void>;
344
+ replaceDocId(collection: string, oldId: string, newId: string): Promise<LocalDoc | null>;
345
+ applyRemoteDoc(collection: string, data: Record<string, any>, revision?: string | number): Promise<LocalDoc | null>;
346
+ applyRemoteDelete(collection: string, id: string): Promise<LocalDoc | null>;
347
+ createLocalId(): string;
348
+ createMutationId(): string;
349
+ clearAll(): Promise<void>;
350
+ getStorageUsage(): Promise<number>;
351
+ }
352
+
353
+ declare class RealtimeBridge {
354
+ private app;
355
+ private persistence;
356
+ private store;
357
+ private collectionUnsubs;
358
+ private documentUnsubs;
359
+ constructor(app: EdmaxLabs, persistence: Persistence, store: LocalStore);
360
+ private docKey;
361
+ watchCollection(collection: string, filter?: Record<string, any>): () => void;
362
+ watchDocument(collection: string, id: string): () => void;
363
+ private emitCurrentDocument;
364
+ private emitCurrentCollection;
365
+ private handleRemoteCreateOrUpdate;
366
+ private handleRemoteDelete;
367
+ /**
368
+ * Call this when Socket.IO reconnects or when going online
369
+ * Replays pending mutations + refreshes all active subscriptions from cache
370
+ */
371
+ onReconnect(): Promise<void>;
372
+ /**
373
+ * Clean up all subscriptions (call from EdmaxLabs destructor if needed)
374
+ */
375
+ dispose(): void;
376
+ }
377
+
378
+ declare class SyncEngine {
379
+ private app;
380
+ private persistence;
381
+ private store;
382
+ private realtimeBridge;
383
+ private syncing;
384
+ private retryTimeout;
385
+ private readonly MAX_RETRIES;
386
+ private readonly BASE_RETRY_DELAY;
387
+ constructor(app: EdmaxLabs, persistence: Persistence, store: LocalStore, realtimeBridge?: RealtimeBridge);
388
+ private onNetworkOnline;
389
+ flush(): Promise<void>;
390
+ private syncCreate;
391
+ private syncUpdate;
392
+ private syncDelete;
393
+ private scheduleRetry;
394
+ forceSync(): Promise<void>;
395
+ dispose(): void;
239
396
  }
240
397
 
241
398
  declare class StorageSnapshot {
@@ -247,8 +404,8 @@ declare class StorageSnapshot {
247
404
  }
248
405
 
249
406
  declare class StorageRef {
250
- db: EdmaxLabs;
251
- constructor(db: EdmaxLabs);
407
+ app: EdmaxLabs;
408
+ constructor(app: EdmaxLabs);
252
409
  get(id: string): Promise<StorageSnapshot | null | undefined>;
253
410
  getMeta(id: string): Promise<StorageSnapshot | null | undefined>;
254
411
  upload(srcFile: File): Promise<StorageSnapshot | null | undefined>;
@@ -267,31 +424,44 @@ declare class Storage {
267
424
  interface EdmaxLabsConfig {
268
425
  token: string;
269
426
  project: string;
427
+ persistence?: boolean;
428
+ default_bucket?: string;
270
429
  }
271
430
  declare class EdmaxLabs {
272
431
  static instance: EdmaxLabs | null;
273
432
  private baseUrl;
274
433
  private socketUrl;
275
- private auth;
276
434
  private _db;
435
+ private _realtime;
277
436
  private _hosting;
278
- private realtime;
437
+ private _config;
279
438
  private persistence;
280
- private persistence_worker;
281
- constructor({ token, project }: EdmaxLabsConfig);
282
- static allowPersistence(enable: boolean): void;
439
+ private localStore;
440
+ private syncEngine;
441
+ private realtimeBridge;
442
+ constructor(config: EdmaxLabsConfig);
443
+ /** Recommended for most React apps (creates fresh instance) */
444
+ static create(config: EdmaxLabsConfig): EdmaxLabs;
445
+ /** Firebase-style singleton (kept for backward compatibility) */
283
446
  static initialize(config: EdmaxLabsConfig): EdmaxLabs;
284
- get getPersistence(): boolean;
285
- get getAuth(): Record<string, any>;
286
- get getBaseUrl(): string;
287
- get getSocketUrl(): string;
288
- get database(): Database;
289
- get storage(): Storage;
290
- get hosting(): Hosting;
291
- get functions(): Functions;
292
- get rtdb(): Realtime;
293
- sync(id: string, collection?: string): Promise<boolean | undefined>;
294
- get authentication(): Authentication;
447
+ get getDatabase(): Database;
448
+ get getFunctions(): Functions;
449
+ get getStorage(): Storage;
450
+ get getAuthentication(): Authentication;
451
+ /** New clean offline namespace - highly recommended */
452
+ offline(): {
453
+ readonly persistence: Persistence | null;
454
+ readonly localStore: LocalStore | null;
455
+ readonly syncEngine: SyncEngine | null;
456
+ readonly realtimeBridge: RealtimeBridge | null;
457
+ readonly enabled: boolean;
458
+ };
459
+ getConfig(): EdmaxLabsConfig;
460
+ getBaseUrl(): string;
461
+ getSocketUrl(): string;
462
+ rtdb(): Realtime;
463
+ /** Call this when your app unmounts or user logs out */
464
+ dispose(): void;
295
465
  }
296
466
 
297
- export { ArraySnapshot, Authentication, Credentials, DisplayInfo, DocumentSnapshot, StorageSnapshot, Timestamp, EdmaxLabs as default };
467
+ export { ArraySnapshot, Authentication, Credentials, DisplayInfo, DocumentSnapshot, EdmaxLabsConfig, StorageSnapshot, Timestamp, EdmaxLabs as default };