@dabble/patches 0.2.4 → 0.2.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.
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Unsubscriber } from '../event-signal.js';
|
|
1
2
|
import type { JSONPatch } from '../json-patch/JSONPatch.js';
|
|
2
3
|
import type { Change, PatchesSnapshot } from '../types.js';
|
|
3
4
|
/**
|
|
@@ -29,12 +30,16 @@ export declare class PatchesDoc<T extends object = object> {
|
|
|
29
30
|
get id(): string | null;
|
|
30
31
|
/** Current local state (committed + sending + pending). */
|
|
31
32
|
get state(): T;
|
|
33
|
+
/** Alias for state. */
|
|
34
|
+
get value(): T;
|
|
32
35
|
/** Last committed revision number from the server. */
|
|
33
36
|
get committedRev(): number;
|
|
34
37
|
/** Are there changes currently awaiting server confirmation? */
|
|
35
38
|
get isSending(): boolean;
|
|
36
39
|
/** Are there local changes that haven't been sent yet? */
|
|
37
40
|
get hasPending(): boolean;
|
|
41
|
+
/** Subscribe to be notified whenever value changes. */
|
|
42
|
+
subscribe(onUpdate: (newValue: T) => void): Unsubscriber;
|
|
38
43
|
/**
|
|
39
44
|
* Exports the document state for persistence.
|
|
40
45
|
* NOTE: Any changes currently marked as `sending` are included in the
|
|
@@ -37,6 +37,10 @@ export class PatchesDoc {
|
|
|
37
37
|
get state() {
|
|
38
38
|
return this._state;
|
|
39
39
|
}
|
|
40
|
+
/** Alias for state. */
|
|
41
|
+
get value() {
|
|
42
|
+
return this._state;
|
|
43
|
+
}
|
|
40
44
|
/** Last committed revision number from the server. */
|
|
41
45
|
get committedRev() {
|
|
42
46
|
return this._committedRev;
|
|
@@ -49,6 +53,12 @@ export class PatchesDoc {
|
|
|
49
53
|
get hasPending() {
|
|
50
54
|
return this._pendingChanges.length > 0;
|
|
51
55
|
}
|
|
56
|
+
/** Subscribe to be notified whenever value changes. */
|
|
57
|
+
subscribe(onUpdate) {
|
|
58
|
+
const unsub = this.onUpdate(onUpdate);
|
|
59
|
+
onUpdate(this._state);
|
|
60
|
+
return unsub;
|
|
61
|
+
}
|
|
52
62
|
/**
|
|
53
63
|
* Exports the document state for persistence.
|
|
54
64
|
* NOTE: Any changes currently marked as `sending` are included in the
|
|
@@ -174,14 +174,14 @@ export class IndexedDBStore {
|
|
|
174
174
|
let docMeta = await docsStore.get(docId);
|
|
175
175
|
if (!docMeta) {
|
|
176
176
|
docMeta = { docId, committedRev: 0 };
|
|
177
|
-
await docsStore.
|
|
177
|
+
await docsStore.put(docMeta);
|
|
178
178
|
}
|
|
179
179
|
else if (docMeta.deleted) {
|
|
180
180
|
delete docMeta.deleted;
|
|
181
181
|
await docsStore.put(docMeta);
|
|
182
182
|
console.warn(`Revived document ${docId} by saving pending changes.`);
|
|
183
183
|
}
|
|
184
|
-
await Promise.all(changes.map(change => pendingChanges.
|
|
184
|
+
await Promise.all(changes.map(change => pendingChanges.put({ ...change, docId })));
|
|
185
185
|
this.onPendingChanges.emit(docId, changes);
|
|
186
186
|
await tx.complete();
|
|
187
187
|
}
|
|
@@ -206,7 +206,7 @@ export class IndexedDBStore {
|
|
|
206
206
|
async saveCommittedChanges(docId, changes, sentPendingRange) {
|
|
207
207
|
const [tx, committedChanges, pendingChanges, snapshots, docsStore] = await this.transaction(['committedChanges', 'pendingChanges', 'snapshots', 'docs'], 'readwrite');
|
|
208
208
|
// Save committed changes
|
|
209
|
-
await Promise.all(changes.map(change => committedChanges.
|
|
209
|
+
await Promise.all(changes.map(change => committedChanges.put({ ...change, docId })));
|
|
210
210
|
// Remove pending changes if range provided
|
|
211
211
|
if (sentPendingRange) {
|
|
212
212
|
await pendingChanges.delete([docId, sentPendingRange[0]], [docId, sentPendingRange[1]]);
|
|
@@ -226,7 +226,7 @@ export class IndexedDBStore {
|
|
|
226
226
|
if (!firstPending?.baseRev || firstPending?.baseRev >= lastRev) {
|
|
227
227
|
const state = applyChanges(snapshot?.state, committed);
|
|
228
228
|
await Promise.all([
|
|
229
|
-
snapshots.
|
|
229
|
+
snapshots.put({
|
|
230
230
|
docId,
|
|
231
231
|
rev: lastRev,
|
|
232
232
|
state,
|
|
@@ -266,7 +266,7 @@ export class IndexedDBStore {
|
|
|
266
266
|
}
|
|
267
267
|
else {
|
|
268
268
|
// If doesn't exist, add it
|
|
269
|
-
await docsStore.
|
|
269
|
+
await docsStore.put({ docId, committedRev: 0 });
|
|
270
270
|
}
|
|
271
271
|
}));
|
|
272
272
|
await tx.complete();
|
|
@@ -338,9 +338,9 @@ class IDBStoreWrapper {
|
|
|
338
338
|
request.onerror = () => reject(request.error);
|
|
339
339
|
});
|
|
340
340
|
}
|
|
341
|
-
async
|
|
341
|
+
async put(value) {
|
|
342
342
|
return new Promise((resolve, reject) => {
|
|
343
|
-
const request = this.store.
|
|
343
|
+
const request = this.store.put(value);
|
|
344
344
|
request.onsuccess = () => resolve(request.result);
|
|
345
345
|
request.onerror = () => reject(request.error);
|
|
346
346
|
});
|
|
@@ -374,11 +374,4 @@ class IDBStoreWrapper {
|
|
|
374
374
|
request.onerror = () => reject(request.error);
|
|
375
375
|
});
|
|
376
376
|
}
|
|
377
|
-
async put(value) {
|
|
378
|
-
return new Promise((resolve, reject) => {
|
|
379
|
-
const request = this.store.put(value);
|
|
380
|
-
request.onsuccess = () => resolve(request.result);
|
|
381
|
-
request.onerror = () => reject(request.error);
|
|
382
|
-
});
|
|
383
|
-
}
|
|
384
377
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dabble/patches",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"description": "Immutable JSON Patch implementation based on RFC 6902 supporting operational transformation and last-writer-wins",
|
|
5
5
|
"author": "Jacob Wright <jacwright@gmail.com>",
|
|
6
6
|
"bugs": {
|