@dabble/patches 0.7.6 → 0.7.7
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/algorithms/lww/consolidateOps.js +41 -0
- package/dist/client/Patches.d.ts +11 -5
- package/dist/client/index.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/shared/doc-manager.d.ts +2 -2
- package/dist/shared/doc-manager.js +2 -2
- package/dist/solid/primitives.d.ts +9 -4
- package/dist/solid/primitives.js +80 -132
- package/dist/vue/composables.d.ts +8 -3
- package/dist/vue/composables.js +93 -148
- package/dist/vue/managed-docs.d.ts +10 -1
- package/dist/vue/managed-docs.js +3 -2
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import "../../chunk-IZ2YBCUP.js";
|
|
2
2
|
import { applyBitmask, combineBitmasks } from "../../json-patch/ops/bitmask.js";
|
|
3
|
+
import { isEmptyContainer } from "../../json-patch/utils/softWrites.js";
|
|
3
4
|
const combinableOps = {
|
|
4
5
|
"@inc": {
|
|
5
6
|
apply: (a, b) => a + b,
|
|
@@ -33,6 +34,9 @@ function consolidateFieldOp(existing, incoming) {
|
|
|
33
34
|
}
|
|
34
35
|
return { ...incoming, op, value };
|
|
35
36
|
}
|
|
37
|
+
if (isSoftOp(incoming)) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
36
40
|
if (isExistingNewer(existing.ts, incoming.ts)) {
|
|
37
41
|
return null;
|
|
38
42
|
}
|
|
@@ -58,6 +62,19 @@ function consolidateOps(existingOps, newOps) {
|
|
|
58
62
|
opsToSave.push(consolidated);
|
|
59
63
|
}
|
|
60
64
|
} else {
|
|
65
|
+
if (isSoftOp(newOp)) {
|
|
66
|
+
let dataExists = false;
|
|
67
|
+
for (const existingPath of existingByPath.keys()) {
|
|
68
|
+
if (existingPath.startsWith(newOp.path + "/")) {
|
|
69
|
+
dataExists = true;
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (!dataExists) {
|
|
74
|
+
dataExists = pathExistsInParentOp(newOp.path, existingByPath);
|
|
75
|
+
}
|
|
76
|
+
if (dataExists) continue;
|
|
77
|
+
}
|
|
61
78
|
for (const existingPath of existingByPath.keys()) {
|
|
62
79
|
if (existingPath.startsWith(newOp.path + "/")) {
|
|
63
80
|
pathsToDelete.add(existingPath);
|
|
@@ -92,6 +109,30 @@ function parentFixes(path, existing) {
|
|
|
92
109
|
}
|
|
93
110
|
return pathsToDelete;
|
|
94
111
|
}
|
|
112
|
+
function pathExistsInParentOp(path, existingByPath) {
|
|
113
|
+
let parent = path;
|
|
114
|
+
while (parent.lastIndexOf("/") > 0) {
|
|
115
|
+
parent = parent.substring(0, parent.lastIndexOf("/"));
|
|
116
|
+
const parentOp = existingByPath.get(parent);
|
|
117
|
+
if (parentOp && isObject(parentOp.value)) {
|
|
118
|
+
const remainingKeys = path.substring(parent.length + 1).split("/");
|
|
119
|
+
let current = parentOp.value;
|
|
120
|
+
let found = true;
|
|
121
|
+
for (const key of remainingKeys) {
|
|
122
|
+
if (!isObject(current) || !(key in current)) {
|
|
123
|
+
found = false;
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
current = current[key];
|
|
127
|
+
}
|
|
128
|
+
if (found) return true;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
function isSoftOp(op) {
|
|
134
|
+
return op.soft === true || op.op === "add" && isEmptyContainer(op.value);
|
|
135
|
+
}
|
|
95
136
|
function isObject(value) {
|
|
96
137
|
return value !== null && typeof value === "object";
|
|
97
138
|
}
|
package/dist/client/Patches.d.ts
CHANGED
|
@@ -7,6 +7,15 @@ import { AlgorithmName } from './PatchesStore.js';
|
|
|
7
7
|
import '../json-patch/JSONPatch.js';
|
|
8
8
|
import '@dabble/delta';
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Options for opening a document, passed through to `patches.openDoc()`.
|
|
12
|
+
*/
|
|
13
|
+
interface OpenDocOptions {
|
|
14
|
+
/** Optional metadata to attach to the document. */
|
|
15
|
+
metadata?: Record<string, any>;
|
|
16
|
+
/** Override the algorithm for this document (defaults to the Patches instance default). */
|
|
17
|
+
algorithm?: AlgorithmName;
|
|
18
|
+
}
|
|
10
19
|
/**
|
|
11
20
|
* Options for creating a Patches instance.
|
|
12
21
|
* Provides algorithms map and optional default algorithm.
|
|
@@ -85,10 +94,7 @@ declare class Patches {
|
|
|
85
94
|
* @param opts - Optional metadata and algorithm override.
|
|
86
95
|
* @returns The opened PatchesDoc instance.
|
|
87
96
|
*/
|
|
88
|
-
openDoc<T extends object>(docId: string, opts?:
|
|
89
|
-
metadata?: Record<string, any>;
|
|
90
|
-
algorithm?: AlgorithmName;
|
|
91
|
-
}): Promise<PatchesDoc<T>>;
|
|
97
|
+
openDoc<T extends object>(docId: string, opts?: OpenDocOptions): Promise<PatchesDoc<T>>;
|
|
92
98
|
/**
|
|
93
99
|
* Closes an open document by ID, removing listeners and optionally untracking it.
|
|
94
100
|
* @param docId - The document ID to close.
|
|
@@ -122,4 +128,4 @@ declare class Patches {
|
|
|
122
128
|
protected _handleDocChange<T extends object>(docId: string, ops: JSONPatchOp[], doc: PatchesDoc<T>, algorithm: ClientAlgorithm, metadata: Record<string, any>): Promise<void>;
|
|
123
129
|
}
|
|
124
130
|
|
|
125
|
-
export { Patches, type PatchesOptions };
|
|
131
|
+
export { type OpenDocOptions, Patches, type PatchesOptions };
|
package/dist/client/index.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export { LWWDoc } from './LWWDoc.js';
|
|
|
9
9
|
export { LWWAlgorithm } from './LWWAlgorithm.js';
|
|
10
10
|
export { LWWBatcher } from './LWWBatcher.js';
|
|
11
11
|
export { OTAlgorithm } from './OTAlgorithm.js';
|
|
12
|
-
export { Patches, PatchesOptions } from './Patches.js';
|
|
12
|
+
export { OpenDocOptions, Patches, PatchesOptions } from './Patches.js';
|
|
13
13
|
export { PatchesHistoryClient } from './PatchesHistoryClient.js';
|
|
14
14
|
export { AlgorithmName, PatchesStore, TrackedDoc } from './PatchesStore.js';
|
|
15
15
|
export { OTClientStore } from './OTClientStore.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export { LWWDoc } from './client/LWWDoc.js';
|
|
|
10
10
|
export { LWWAlgorithm } from './client/LWWAlgorithm.js';
|
|
11
11
|
export { LWWBatcher } from './client/LWWBatcher.js';
|
|
12
12
|
export { OTAlgorithm } from './client/OTAlgorithm.js';
|
|
13
|
-
export { Patches, PatchesOptions } from './client/Patches.js';
|
|
13
|
+
export { OpenDocOptions, Patches, PatchesOptions } from './client/Patches.js';
|
|
14
14
|
export { PatchesHistoryClient } from './client/PatchesHistoryClient.js';
|
|
15
15
|
export { AlgorithmName, PatchesStore, TrackedDoc } from './client/PatchesStore.js';
|
|
16
16
|
export { OTClientStore } from './client/OTClientStore.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Patches } from '../client/Patches.js';
|
|
1
|
+
import { Patches, OpenDocOptions } from '../client/Patches.js';
|
|
2
2
|
import { a as PatchesDoc } from '../BaseDoc-DkP3tUhT.js';
|
|
3
3
|
import '../event-signal.js';
|
|
4
4
|
import '../json-patch/types.js';
|
|
@@ -31,7 +31,7 @@ declare class DocManager {
|
|
|
31
31
|
* @param docId - Document ID to open
|
|
32
32
|
* @returns Promise resolving to PatchesDoc instance
|
|
33
33
|
*/
|
|
34
|
-
openDoc<T extends object>(patches: Patches, docId: string): Promise<PatchesDoc<T>>;
|
|
34
|
+
openDoc<T extends object>(patches: Patches, docId: string, opts?: OpenDocOptions): Promise<PatchesDoc<T>>;
|
|
35
35
|
/**
|
|
36
36
|
* Closes a document with reference counting.
|
|
37
37
|
*
|
|
@@ -13,7 +13,7 @@ class DocManager {
|
|
|
13
13
|
* @param docId - Document ID to open
|
|
14
14
|
* @returns Promise resolving to PatchesDoc instance
|
|
15
15
|
*/
|
|
16
|
-
async openDoc(patches, docId) {
|
|
16
|
+
async openDoc(patches, docId, opts) {
|
|
17
17
|
const currentCount = this.refCounts.get(docId) || 0;
|
|
18
18
|
if (currentCount === 0 && this.pendingOps.has(docId)) {
|
|
19
19
|
const doc = await this.pendingOps.get(docId);
|
|
@@ -28,7 +28,7 @@ class DocManager {
|
|
|
28
28
|
}
|
|
29
29
|
return doc;
|
|
30
30
|
}
|
|
31
|
-
const openPromise = patches.openDoc(docId);
|
|
31
|
+
const openPromise = patches.openDoc(docId, opts);
|
|
32
32
|
this.pendingOps.set(docId, openPromise);
|
|
33
33
|
try {
|
|
34
34
|
const doc = await openPromise;
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { Accessor } from 'solid-js';
|
|
2
|
+
import { OpenDocOptions } from '../client/Patches.js';
|
|
2
3
|
import { a as PatchesDoc } from '../BaseDoc-DkP3tUhT.js';
|
|
3
4
|
import { JSONPatch } from '../json-patch/JSONPatch.js';
|
|
4
5
|
import { ChangeMutator } from '../types.js';
|
|
5
6
|
import '../event-signal.js';
|
|
6
7
|
import '../json-patch/types.js';
|
|
8
|
+
import '../client/ClientAlgorithm.js';
|
|
9
|
+
import '../client/PatchesStore.js';
|
|
7
10
|
import '@dabble/delta';
|
|
8
11
|
|
|
9
12
|
/**
|
|
10
13
|
* Options for usePatchesDoc primitive (eager mode with docId).
|
|
11
14
|
*/
|
|
12
|
-
interface UsePatchesDocOptions {
|
|
15
|
+
interface UsePatchesDocOptions extends OpenDocOptions {
|
|
13
16
|
/**
|
|
14
17
|
* Controls document lifecycle management on cleanup.
|
|
15
18
|
*
|
|
@@ -89,8 +92,9 @@ interface UsePatchesDocLazyReturn<T extends object> extends UsePatchesDocReturn<
|
|
|
89
92
|
* Open a document by path. Closes any previously loaded document first.
|
|
90
93
|
*
|
|
91
94
|
* @param docPath - The document path to open
|
|
95
|
+
* @param options - Optional algorithm and metadata overrides
|
|
92
96
|
*/
|
|
93
|
-
load: (docPath: string) => Promise<void>;
|
|
97
|
+
load: (docPath: string, options?: OpenDocOptions) => Promise<void>;
|
|
94
98
|
/**
|
|
95
99
|
* Close the current document, unsubscribe, and reset all state.
|
|
96
100
|
* Calls `patches.closeDoc()` but does not untrack — tracking is managed separately.
|
|
@@ -102,8 +106,9 @@ interface UsePatchesDocLazyReturn<T extends object> extends UsePatchesDocReturn<
|
|
|
102
106
|
*
|
|
103
107
|
* @param docPath - The document path to create
|
|
104
108
|
* @param initialState - Initial state object or JSONPatch to apply
|
|
109
|
+
* @param options - Optional algorithm and metadata overrides
|
|
105
110
|
*/
|
|
106
|
-
create: (docPath: string, initialState: T | JSONPatch) => Promise<void>;
|
|
111
|
+
create: (docPath: string, initialState: T | JSONPatch, options?: OpenDocOptions) => Promise<void>;
|
|
107
112
|
}
|
|
108
113
|
/**
|
|
109
114
|
* Solid primitive for reactive Patches document state.
|
|
@@ -185,7 +190,7 @@ type MaybeAccessor<T> = T | Accessor<T>;
|
|
|
185
190
|
/**
|
|
186
191
|
* Props for the Provider component returned by createPatchesDoc.
|
|
187
192
|
*/
|
|
188
|
-
interface PatchesDocProviderProps {
|
|
193
|
+
interface PatchesDocProviderProps extends OpenDocOptions {
|
|
189
194
|
docId: MaybeAccessor<string>;
|
|
190
195
|
autoClose?: boolean | 'untrack';
|
|
191
196
|
children: any;
|
package/dist/solid/primitives.js
CHANGED
|
@@ -10,47 +10,87 @@ import {
|
|
|
10
10
|
import { JSONPatch } from "../json-patch/JSONPatch.js";
|
|
11
11
|
import { usePatchesContext } from "./context.js";
|
|
12
12
|
import { getDocManager } from "./doc-manager.js";
|
|
13
|
-
function
|
|
14
|
-
|
|
15
|
-
return _usePatchesDocEager(docIdOrOptions, options ?? {});
|
|
16
|
-
}
|
|
17
|
-
return _usePatchesDocLazy(docIdOrOptions ?? {});
|
|
18
|
-
}
|
|
19
|
-
function _usePatchesDocEager(docId, options) {
|
|
20
|
-
const { patches } = usePatchesContext();
|
|
21
|
-
const autoClose = options.autoClose ?? false;
|
|
22
|
-
const shouldUntrack = autoClose === "untrack";
|
|
13
|
+
function createDocReactiveState(options) {
|
|
14
|
+
const { initialLoading = true, transformState, changeBehavior } = options;
|
|
23
15
|
const [doc, setDoc] = createSignal(void 0);
|
|
24
16
|
const [data, setData] = createSignal(void 0);
|
|
25
|
-
const [loading, setLoading] = createSignal(
|
|
17
|
+
const [loading, setLoading] = createSignal(initialLoading);
|
|
26
18
|
const [error, setError] = createSignal(null);
|
|
27
19
|
const [rev, setRev] = createSignal(0);
|
|
28
20
|
const [hasPending, setHasPending] = createSignal(false);
|
|
29
|
-
const manager = getDocManager(patches);
|
|
30
|
-
const docIdAccessor = toAccessor(docId);
|
|
31
21
|
function setupDoc(patchesDoc) {
|
|
32
22
|
setDoc(patchesDoc);
|
|
33
23
|
const unsubState = patchesDoc.subscribe((state) => {
|
|
24
|
+
if (transformState && state) {
|
|
25
|
+
state = transformState(state, patchesDoc);
|
|
26
|
+
}
|
|
34
27
|
setData(() => state);
|
|
35
28
|
setRev(patchesDoc.committedRev);
|
|
36
29
|
setHasPending(patchesDoc.hasPending);
|
|
37
30
|
});
|
|
38
|
-
onCleanup(() => unsubState());
|
|
39
31
|
const unsubSync = patchesDoc.onSyncing((syncState) => {
|
|
40
32
|
setLoading(syncState === "initial" || syncState === "updating");
|
|
41
33
|
setError(syncState instanceof Error ? syncState : null);
|
|
42
34
|
});
|
|
43
|
-
onCleanup(() => unsubSync());
|
|
44
35
|
setLoading(patchesDoc.syncing !== null);
|
|
36
|
+
return () => {
|
|
37
|
+
unsubState();
|
|
38
|
+
unsubSync();
|
|
39
|
+
};
|
|
45
40
|
}
|
|
41
|
+
function resetSignals() {
|
|
42
|
+
setDoc(void 0);
|
|
43
|
+
setData(void 0);
|
|
44
|
+
setLoading(false);
|
|
45
|
+
setError(null);
|
|
46
|
+
setRev(0);
|
|
47
|
+
setHasPending(false);
|
|
48
|
+
}
|
|
49
|
+
function change(mutator) {
|
|
50
|
+
if (changeBehavior === "throw") {
|
|
51
|
+
const currentDoc = doc();
|
|
52
|
+
if (!currentDoc) {
|
|
53
|
+
throw new Error("Cannot make changes: document not loaded yet");
|
|
54
|
+
}
|
|
55
|
+
currentDoc.change(mutator);
|
|
56
|
+
} else {
|
|
57
|
+
doc()?.change(mutator);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const baseReturn = {
|
|
61
|
+
data,
|
|
62
|
+
loading,
|
|
63
|
+
error,
|
|
64
|
+
rev,
|
|
65
|
+
hasPending,
|
|
66
|
+
change,
|
|
67
|
+
doc
|
|
68
|
+
};
|
|
69
|
+
return { doc, setDoc, data, setData, loading, setLoading, error, setError, rev, setRev, hasPending, setHasPending, setupDoc, resetSignals, change, baseReturn };
|
|
70
|
+
}
|
|
71
|
+
function usePatchesDoc(docIdOrOptions, options) {
|
|
72
|
+
if (typeof docIdOrOptions === "string" || typeof docIdOrOptions === "function") {
|
|
73
|
+
return _usePatchesDocEager(docIdOrOptions, options ?? {});
|
|
74
|
+
}
|
|
75
|
+
return _usePatchesDocLazy(docIdOrOptions ?? {});
|
|
76
|
+
}
|
|
77
|
+
function _usePatchesDocEager(docId, options) {
|
|
78
|
+
const { patches } = usePatchesContext();
|
|
79
|
+
const { autoClose = false, algorithm, metadata } = options;
|
|
80
|
+
const shouldUntrack = autoClose === "untrack";
|
|
81
|
+
const openDocOpts = { algorithm, metadata };
|
|
82
|
+
const manager = getDocManager(patches);
|
|
83
|
+
const { setupDoc, setError, setLoading, baseReturn } = createDocReactiveState({ changeBehavior: "throw" });
|
|
84
|
+
const docIdAccessor = toAccessor(docId);
|
|
46
85
|
if (autoClose) {
|
|
47
86
|
const [docResource] = createResource(docIdAccessor, async (id) => {
|
|
48
|
-
return await manager.openDoc(patches, id);
|
|
87
|
+
return await manager.openDoc(patches, id, openDocOpts);
|
|
49
88
|
});
|
|
50
89
|
createEffect(() => {
|
|
51
90
|
const loadedDoc = docResource();
|
|
52
91
|
if (loadedDoc) {
|
|
53
|
-
setupDoc(loadedDoc);
|
|
92
|
+
const unsub = setupDoc(loadedDoc);
|
|
93
|
+
onCleanup(() => unsub());
|
|
54
94
|
}
|
|
55
95
|
const resourceError = docResource.error;
|
|
56
96
|
if (resourceError) {
|
|
@@ -72,75 +112,31 @@ function _usePatchesDocEager(docId, options) {
|
|
|
72
112
|
);
|
|
73
113
|
}
|
|
74
114
|
manager.incrementRefCount(id);
|
|
75
|
-
setupDoc(patchesDoc);
|
|
115
|
+
const unsub = setupDoc(patchesDoc);
|
|
76
116
|
onCleanup(() => {
|
|
117
|
+
unsub();
|
|
77
118
|
manager.decrementRefCount(id);
|
|
78
119
|
});
|
|
79
120
|
});
|
|
80
121
|
}
|
|
81
|
-
|
|
82
|
-
const currentDoc = doc();
|
|
83
|
-
if (!currentDoc) {
|
|
84
|
-
throw new Error("Cannot make changes: document not loaded yet");
|
|
85
|
-
}
|
|
86
|
-
currentDoc.change(mutator);
|
|
87
|
-
}
|
|
88
|
-
return {
|
|
89
|
-
data,
|
|
90
|
-
loading,
|
|
91
|
-
error,
|
|
92
|
-
rev,
|
|
93
|
-
hasPending,
|
|
94
|
-
change,
|
|
95
|
-
doc
|
|
96
|
-
};
|
|
122
|
+
return baseReturn;
|
|
97
123
|
}
|
|
98
124
|
function _usePatchesDocLazy(options) {
|
|
99
125
|
const { patches } = usePatchesContext();
|
|
100
126
|
const { idProp } = options;
|
|
101
|
-
|
|
127
|
+
const { setupDoc, resetSignals, setError, setLoading, baseReturn } = createDocReactiveState({
|
|
128
|
+
initialLoading: false,
|
|
129
|
+
changeBehavior: "noop",
|
|
130
|
+
transformState: idProp ? (state, patchesDoc) => ({ ...state, [idProp]: patchesDoc.id }) : void 0
|
|
131
|
+
});
|
|
102
132
|
let unsubscribe = null;
|
|
103
133
|
const [path, setPath] = createSignal(null);
|
|
104
|
-
const [doc, setDoc] = createSignal(void 0);
|
|
105
|
-
const [data, setData] = createSignal(void 0);
|
|
106
|
-
const [loading, setLoading] = createSignal(false);
|
|
107
|
-
const [error, setError] = createSignal(null);
|
|
108
|
-
const [rev, setRev] = createSignal(0);
|
|
109
|
-
const [hasPending, setHasPending] = createSignal(false);
|
|
110
|
-
function setupDoc(patchesDoc) {
|
|
111
|
-
currentDoc = patchesDoc;
|
|
112
|
-
setDoc(patchesDoc);
|
|
113
|
-
unsubscribe = patchesDoc.subscribe((state) => {
|
|
114
|
-
if (state && idProp && currentDoc) {
|
|
115
|
-
state = { ...state, [idProp]: currentDoc.id };
|
|
116
|
-
}
|
|
117
|
-
setData(() => state);
|
|
118
|
-
setRev(patchesDoc.committedRev);
|
|
119
|
-
setHasPending(patchesDoc.hasPending);
|
|
120
|
-
});
|
|
121
|
-
const unsubSync = patchesDoc.onSyncing((syncState) => {
|
|
122
|
-
setLoading(syncState === "initial" || syncState === "updating");
|
|
123
|
-
setError(syncState instanceof Error ? syncState : null);
|
|
124
|
-
});
|
|
125
|
-
const origUnsub = unsubscribe;
|
|
126
|
-
unsubscribe = () => {
|
|
127
|
-
origUnsub();
|
|
128
|
-
unsubSync();
|
|
129
|
-
};
|
|
130
|
-
setLoading(patchesDoc.syncing !== null);
|
|
131
|
-
}
|
|
132
134
|
function teardown() {
|
|
133
135
|
unsubscribe?.();
|
|
134
136
|
unsubscribe = null;
|
|
135
|
-
|
|
136
|
-
setDoc(void 0);
|
|
137
|
-
setData(void 0);
|
|
138
|
-
setLoading(false);
|
|
139
|
-
setError(null);
|
|
140
|
-
setRev(0);
|
|
141
|
-
setHasPending(false);
|
|
137
|
+
resetSignals();
|
|
142
138
|
}
|
|
143
|
-
async function load(docPath) {
|
|
139
|
+
async function load(docPath, options2) {
|
|
144
140
|
if (path()) {
|
|
145
141
|
const prevPath = path();
|
|
146
142
|
teardown();
|
|
@@ -148,8 +144,8 @@ function _usePatchesDocLazy(options) {
|
|
|
148
144
|
}
|
|
149
145
|
setPath(docPath);
|
|
150
146
|
try {
|
|
151
|
-
const patchesDoc = await patches.openDoc(docPath);
|
|
152
|
-
setupDoc(patchesDoc);
|
|
147
|
+
const patchesDoc = await patches.openDoc(docPath, options2);
|
|
148
|
+
unsubscribe = setupDoc(patchesDoc);
|
|
153
149
|
} catch (err) {
|
|
154
150
|
setError(err);
|
|
155
151
|
setLoading(false);
|
|
@@ -163,8 +159,8 @@ function _usePatchesDocLazy(options) {
|
|
|
163
159
|
await patches.closeDoc(prevPath);
|
|
164
160
|
}
|
|
165
161
|
}
|
|
166
|
-
async function create(docPath, initialState) {
|
|
167
|
-
const newDoc = await patches.openDoc(docPath);
|
|
162
|
+
async function create(docPath, initialState, options2) {
|
|
163
|
+
const newDoc = await patches.openDoc(docPath, options2);
|
|
168
164
|
newDoc.change((patch, root) => {
|
|
169
165
|
if (initialState instanceof JSONPatch) {
|
|
170
166
|
patch.ops = initialState.ops;
|
|
@@ -176,22 +172,7 @@ function _usePatchesDocLazy(options) {
|
|
|
176
172
|
});
|
|
177
173
|
await patches.closeDoc(docPath);
|
|
178
174
|
}
|
|
179
|
-
|
|
180
|
-
currentDoc?.change(mutator);
|
|
181
|
-
}
|
|
182
|
-
return {
|
|
183
|
-
data,
|
|
184
|
-
loading,
|
|
185
|
-
error,
|
|
186
|
-
rev,
|
|
187
|
-
hasPending,
|
|
188
|
-
change,
|
|
189
|
-
doc,
|
|
190
|
-
path,
|
|
191
|
-
load,
|
|
192
|
-
close,
|
|
193
|
-
create
|
|
194
|
-
};
|
|
175
|
+
return { ...baseReturn, path, load, close, create };
|
|
195
176
|
}
|
|
196
177
|
function usePatchesSync() {
|
|
197
178
|
const { sync } = usePatchesContext();
|
|
@@ -225,36 +206,18 @@ function createPatchesDoc(name) {
|
|
|
225
206
|
const manager = getDocManager(patches);
|
|
226
207
|
const autoClose = props.autoClose ?? false;
|
|
227
208
|
const shouldUntrack = autoClose === "untrack";
|
|
228
|
-
const
|
|
229
|
-
const
|
|
230
|
-
const [loading, setLoading] = createSignal(true);
|
|
231
|
-
const [error, setError] = createSignal(null);
|
|
232
|
-
const [rev, setRev] = createSignal(0);
|
|
233
|
-
const [hasPending, setHasPending] = createSignal(false);
|
|
234
|
-
function setupDoc(patchesDoc) {
|
|
235
|
-
setDoc(patchesDoc);
|
|
236
|
-
const unsubState = patchesDoc.subscribe((state) => {
|
|
237
|
-
setData(() => state);
|
|
238
|
-
setRev(patchesDoc.committedRev);
|
|
239
|
-
setHasPending(patchesDoc.hasPending);
|
|
240
|
-
});
|
|
241
|
-
onCleanup(() => unsubState());
|
|
242
|
-
const unsubSync = patchesDoc.onSyncing((syncState) => {
|
|
243
|
-
setLoading(syncState === "initial" || syncState === "updating");
|
|
244
|
-
setError(syncState instanceof Error ? syncState : null);
|
|
245
|
-
});
|
|
246
|
-
onCleanup(() => unsubSync());
|
|
247
|
-
setLoading(patchesDoc.syncing !== null);
|
|
248
|
-
}
|
|
209
|
+
const openDocOpts = { algorithm: props.algorithm, metadata: props.metadata };
|
|
210
|
+
const { setupDoc, setError, setLoading, baseReturn } = createDocReactiveState({ changeBehavior: "throw" });
|
|
249
211
|
const docIdAccessor = toAccessor(props.docId);
|
|
250
212
|
if (autoClose) {
|
|
251
213
|
const [docResource] = createResource(docIdAccessor, async (id) => {
|
|
252
|
-
return await manager.openDoc(patches, id);
|
|
214
|
+
return await manager.openDoc(patches, id, openDocOpts);
|
|
253
215
|
});
|
|
254
216
|
createEffect(() => {
|
|
255
217
|
const loadedDoc = docResource();
|
|
256
218
|
if (loadedDoc) {
|
|
257
|
-
setupDoc(loadedDoc);
|
|
219
|
+
const unsub = setupDoc(loadedDoc);
|
|
220
|
+
onCleanup(() => unsub());
|
|
258
221
|
}
|
|
259
222
|
const resourceError = docResource.error;
|
|
260
223
|
if (resourceError) {
|
|
@@ -286,7 +249,8 @@ function createPatchesDoc(name) {
|
|
|
286
249
|
);
|
|
287
250
|
}
|
|
288
251
|
manager.incrementRefCount(id);
|
|
289
|
-
setupDoc(patchesDoc);
|
|
252
|
+
const unsub = setupDoc(patchesDoc);
|
|
253
|
+
onCleanup(() => unsub());
|
|
290
254
|
return id;
|
|
291
255
|
});
|
|
292
256
|
onCleanup(() => {
|
|
@@ -294,23 +258,7 @@ function createPatchesDoc(name) {
|
|
|
294
258
|
manager.decrementRefCount(id);
|
|
295
259
|
});
|
|
296
260
|
}
|
|
297
|
-
|
|
298
|
-
const currentDoc = doc();
|
|
299
|
-
if (!currentDoc) {
|
|
300
|
-
throw new Error("Cannot make changes: document not loaded yet");
|
|
301
|
-
}
|
|
302
|
-
currentDoc.change(mutator);
|
|
303
|
-
}
|
|
304
|
-
const value = {
|
|
305
|
-
data,
|
|
306
|
-
loading,
|
|
307
|
-
error,
|
|
308
|
-
rev,
|
|
309
|
-
hasPending,
|
|
310
|
-
change,
|
|
311
|
-
doc
|
|
312
|
-
};
|
|
313
|
-
return /* @__PURE__ */ React.createElement(Context.Provider, { value, children: props.children });
|
|
261
|
+
return /* @__PURE__ */ React.createElement(Context.Provider, { value: baseReturn, children: props.children });
|
|
314
262
|
}
|
|
315
263
|
function useDoc() {
|
|
316
264
|
const context = useContext(Context);
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { ShallowRef, Ref, MaybeRef } from 'vue';
|
|
2
|
+
import { OpenDocOptions } from '../client/Patches.js';
|
|
2
3
|
import { a as PatchesDoc } from '../BaseDoc-DkP3tUhT.js';
|
|
3
4
|
import { JSONPatch } from '../json-patch/JSONPatch.js';
|
|
4
5
|
import { ChangeMutator } from '../types.js';
|
|
5
6
|
import '../event-signal.js';
|
|
6
7
|
import '../json-patch/types.js';
|
|
8
|
+
import '../client/ClientAlgorithm.js';
|
|
9
|
+
import '../client/PatchesStore.js';
|
|
7
10
|
import '@dabble/delta';
|
|
8
11
|
|
|
9
12
|
/**
|
|
10
13
|
* Options for usePatchesDoc composable (eager mode with docId).
|
|
11
14
|
*/
|
|
12
|
-
interface UsePatchesDocOptions {
|
|
15
|
+
interface UsePatchesDocOptions extends OpenDocOptions {
|
|
13
16
|
/**
|
|
14
17
|
* Controls document lifecycle management on component unmount.
|
|
15
18
|
*
|
|
@@ -89,8 +92,9 @@ interface UsePatchesDocLazyReturn<T extends object> extends UsePatchesDocReturn<
|
|
|
89
92
|
* Open a document by path. Closes any previously loaded document first.
|
|
90
93
|
*
|
|
91
94
|
* @param docPath - The document path to open
|
|
95
|
+
* @param options - Optional algorithm and metadata overrides
|
|
92
96
|
*/
|
|
93
|
-
load: (docPath: string) => Promise<void>;
|
|
97
|
+
load: (docPath: string, options?: OpenDocOptions) => Promise<void>;
|
|
94
98
|
/**
|
|
95
99
|
* Close the current document, unsubscribe, and reset all state.
|
|
96
100
|
* Calls `patches.closeDoc()` but does not untrack — tracking is managed separately.
|
|
@@ -102,8 +106,9 @@ interface UsePatchesDocLazyReturn<T extends object> extends UsePatchesDocReturn<
|
|
|
102
106
|
*
|
|
103
107
|
* @param docPath - The document path to create
|
|
104
108
|
* @param initialState - Initial state object or JSONPatch to apply
|
|
109
|
+
* @param options - Optional algorithm and metadata overrides
|
|
105
110
|
*/
|
|
106
|
-
create: (docPath: string, initialState: T | JSONPatch) => Promise<void>;
|
|
111
|
+
create: (docPath: string, initialState: T | JSONPatch, options?: OpenDocOptions) => Promise<void>;
|
|
107
112
|
}
|
|
108
113
|
/**
|
|
109
114
|
* Vue composable for reactive Patches document state.
|
package/dist/vue/composables.js
CHANGED
|
@@ -11,48 +11,86 @@ import {
|
|
|
11
11
|
import { JSONPatch } from "../json-patch/JSONPatch.js";
|
|
12
12
|
import { usePatchesContext } from "./provider.js";
|
|
13
13
|
import { getDocManager } from "./doc-manager.js";
|
|
14
|
-
function
|
|
15
|
-
|
|
16
|
-
return _usePatchesDocEager(docIdOrOptions, options ?? {});
|
|
17
|
-
}
|
|
18
|
-
return _usePatchesDocLazy(docIdOrOptions ?? {});
|
|
19
|
-
}
|
|
20
|
-
function _usePatchesDocEager(docId, options) {
|
|
21
|
-
const { patches } = usePatchesContext();
|
|
22
|
-
const { autoClose = false } = options;
|
|
23
|
-
const shouldUntrack = autoClose === "untrack";
|
|
14
|
+
function createDocReactiveState(options) {
|
|
15
|
+
const { initialLoading = true, transformState, changeBehavior } = options;
|
|
24
16
|
const doc = ref(void 0);
|
|
25
17
|
const data = shallowRef(void 0);
|
|
26
|
-
const loading = ref(
|
|
18
|
+
const loading = ref(initialLoading);
|
|
27
19
|
const error = ref(null);
|
|
28
20
|
const rev = ref(0);
|
|
29
21
|
const hasPending = ref(false);
|
|
30
|
-
const unsubscribers = [];
|
|
31
|
-
const manager = getDocManager(patches);
|
|
32
22
|
function setupDoc(patchesDoc) {
|
|
33
23
|
doc.value = patchesDoc;
|
|
34
24
|
const unsubState = patchesDoc.subscribe((state) => {
|
|
25
|
+
if (transformState && state) {
|
|
26
|
+
state = transformState(state, patchesDoc);
|
|
27
|
+
}
|
|
35
28
|
data.value = state;
|
|
36
29
|
rev.value = patchesDoc.committedRev;
|
|
37
30
|
hasPending.value = patchesDoc.hasPending;
|
|
38
31
|
});
|
|
39
|
-
unsubscribers.push(unsubState);
|
|
40
32
|
const unsubSync = patchesDoc.onSyncing((syncState) => {
|
|
41
33
|
loading.value = syncState === "initial" || syncState === "updating";
|
|
42
34
|
error.value = syncState instanceof Error ? syncState : null;
|
|
43
35
|
});
|
|
44
|
-
unsubscribers.push(unsubSync);
|
|
45
36
|
loading.value = patchesDoc.syncing !== null;
|
|
37
|
+
return () => {
|
|
38
|
+
unsubState();
|
|
39
|
+
unsubSync();
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function resetRefs() {
|
|
43
|
+
doc.value = void 0;
|
|
44
|
+
data.value = void 0;
|
|
45
|
+
loading.value = false;
|
|
46
|
+
error.value = null;
|
|
47
|
+
rev.value = 0;
|
|
48
|
+
hasPending.value = false;
|
|
49
|
+
}
|
|
50
|
+
function change(mutator) {
|
|
51
|
+
if (changeBehavior === "throw") {
|
|
52
|
+
if (!doc.value) {
|
|
53
|
+
throw new Error("Cannot make changes: document not loaded yet");
|
|
54
|
+
}
|
|
55
|
+
doc.value.change(mutator);
|
|
56
|
+
} else {
|
|
57
|
+
doc.value?.change(mutator);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const baseReturn = {
|
|
61
|
+
data,
|
|
62
|
+
loading,
|
|
63
|
+
error,
|
|
64
|
+
rev,
|
|
65
|
+
hasPending,
|
|
66
|
+
change,
|
|
67
|
+
doc
|
|
68
|
+
};
|
|
69
|
+
return { doc, data, loading, error, rev, hasPending, setupDoc, resetRefs, change, baseReturn };
|
|
70
|
+
}
|
|
71
|
+
function usePatchesDoc(docIdOrOptions, options) {
|
|
72
|
+
if (typeof docIdOrOptions === "string") {
|
|
73
|
+
return _usePatchesDocEager(docIdOrOptions, options ?? {});
|
|
46
74
|
}
|
|
75
|
+
return _usePatchesDocLazy(docIdOrOptions ?? {});
|
|
76
|
+
}
|
|
77
|
+
function _usePatchesDocEager(docId, options) {
|
|
78
|
+
const { patches } = usePatchesContext();
|
|
79
|
+
const { autoClose = false, algorithm, metadata } = options;
|
|
80
|
+
const shouldUntrack = autoClose === "untrack";
|
|
81
|
+
const openDocOpts = { algorithm, metadata };
|
|
82
|
+
const manager = getDocManager(patches);
|
|
83
|
+
const { setupDoc, baseReturn } = createDocReactiveState({ changeBehavior: "throw" });
|
|
84
|
+
let unsubscribe = null;
|
|
47
85
|
if (autoClose) {
|
|
48
|
-
manager.openDoc(patches, docId).then((patchesDoc) => {
|
|
49
|
-
setupDoc(patchesDoc);
|
|
86
|
+
manager.openDoc(patches, docId, openDocOpts).then((patchesDoc) => {
|
|
87
|
+
unsubscribe = setupDoc(patchesDoc);
|
|
50
88
|
}).catch((err) => {
|
|
51
|
-
error.value = err;
|
|
52
|
-
loading.value = false;
|
|
89
|
+
baseReturn.error.value = err;
|
|
90
|
+
baseReturn.loading.value = false;
|
|
53
91
|
});
|
|
54
92
|
onBeforeUnmount(() => {
|
|
55
|
-
|
|
93
|
+
unsubscribe?.();
|
|
56
94
|
manager.closeDoc(patches, docId, shouldUntrack);
|
|
57
95
|
});
|
|
58
96
|
} else {
|
|
@@ -63,74 +101,30 @@ function _usePatchesDocEager(docId, options) {
|
|
|
63
101
|
);
|
|
64
102
|
}
|
|
65
103
|
manager.incrementRefCount(docId);
|
|
66
|
-
setupDoc(patchesDoc);
|
|
104
|
+
unsubscribe = setupDoc(patchesDoc);
|
|
67
105
|
onBeforeUnmount(() => {
|
|
68
|
-
|
|
106
|
+
unsubscribe?.();
|
|
69
107
|
manager.decrementRefCount(docId);
|
|
70
108
|
});
|
|
71
109
|
}
|
|
72
|
-
|
|
73
|
-
if (!doc.value) {
|
|
74
|
-
throw new Error("Cannot make changes: document not loaded yet");
|
|
75
|
-
}
|
|
76
|
-
doc.value.change(mutator);
|
|
77
|
-
}
|
|
78
|
-
return {
|
|
79
|
-
data,
|
|
80
|
-
loading,
|
|
81
|
-
error,
|
|
82
|
-
rev,
|
|
83
|
-
hasPending,
|
|
84
|
-
change,
|
|
85
|
-
doc
|
|
86
|
-
};
|
|
110
|
+
return baseReturn;
|
|
87
111
|
}
|
|
88
112
|
function _usePatchesDocLazy(options) {
|
|
89
113
|
const { patches } = usePatchesContext();
|
|
90
114
|
const { idProp } = options;
|
|
91
|
-
|
|
115
|
+
const { setupDoc, resetRefs, baseReturn } = createDocReactiveState({
|
|
116
|
+
initialLoading: false,
|
|
117
|
+
changeBehavior: "noop",
|
|
118
|
+
transformState: idProp ? (state, patchesDoc) => ({ ...state, [idProp]: patchesDoc.id }) : void 0
|
|
119
|
+
});
|
|
92
120
|
let unsubscribe = null;
|
|
93
121
|
const path = ref(null);
|
|
94
|
-
const doc = ref(void 0);
|
|
95
|
-
const data = shallowRef(void 0);
|
|
96
|
-
const loading = ref(false);
|
|
97
|
-
const error = ref(null);
|
|
98
|
-
const rev = ref(0);
|
|
99
|
-
const hasPending = ref(false);
|
|
100
|
-
function setupDoc(patchesDoc) {
|
|
101
|
-
currentDoc = patchesDoc;
|
|
102
|
-
doc.value = patchesDoc;
|
|
103
|
-
unsubscribe = patchesDoc.subscribe((state) => {
|
|
104
|
-
if (state && idProp && currentDoc) {
|
|
105
|
-
state = { ...state, [idProp]: currentDoc.id };
|
|
106
|
-
}
|
|
107
|
-
data.value = state;
|
|
108
|
-
rev.value = patchesDoc.committedRev;
|
|
109
|
-
hasPending.value = patchesDoc.hasPending;
|
|
110
|
-
});
|
|
111
|
-
const unsubSync = patchesDoc.onSyncing((syncState) => {
|
|
112
|
-
loading.value = syncState === "initial" || syncState === "updating";
|
|
113
|
-
error.value = syncState instanceof Error ? syncState : null;
|
|
114
|
-
});
|
|
115
|
-
const origUnsub = unsubscribe;
|
|
116
|
-
unsubscribe = () => {
|
|
117
|
-
origUnsub();
|
|
118
|
-
unsubSync();
|
|
119
|
-
};
|
|
120
|
-
loading.value = patchesDoc.syncing !== null;
|
|
121
|
-
}
|
|
122
122
|
function teardown() {
|
|
123
123
|
unsubscribe?.();
|
|
124
124
|
unsubscribe = null;
|
|
125
|
-
|
|
126
|
-
doc.value = void 0;
|
|
127
|
-
data.value = void 0;
|
|
128
|
-
loading.value = false;
|
|
129
|
-
error.value = null;
|
|
130
|
-
rev.value = 0;
|
|
131
|
-
hasPending.value = false;
|
|
125
|
+
resetRefs();
|
|
132
126
|
}
|
|
133
|
-
async function load(docPath) {
|
|
127
|
+
async function load(docPath, options2) {
|
|
134
128
|
if (path.value) {
|
|
135
129
|
const prevPath = path.value;
|
|
136
130
|
teardown();
|
|
@@ -138,11 +132,11 @@ function _usePatchesDocLazy(options) {
|
|
|
138
132
|
}
|
|
139
133
|
path.value = docPath;
|
|
140
134
|
try {
|
|
141
|
-
const patchesDoc = await patches.openDoc(docPath);
|
|
142
|
-
setupDoc(patchesDoc);
|
|
135
|
+
const patchesDoc = await patches.openDoc(docPath, options2);
|
|
136
|
+
unsubscribe = setupDoc(patchesDoc);
|
|
143
137
|
} catch (err) {
|
|
144
|
-
error.value = err;
|
|
145
|
-
loading.value = false;
|
|
138
|
+
baseReturn.error.value = err;
|
|
139
|
+
baseReturn.loading.value = false;
|
|
146
140
|
}
|
|
147
141
|
}
|
|
148
142
|
async function close() {
|
|
@@ -153,8 +147,8 @@ function _usePatchesDocLazy(options) {
|
|
|
153
147
|
await patches.closeDoc(prevPath);
|
|
154
148
|
}
|
|
155
149
|
}
|
|
156
|
-
async function create(docPath, initialState) {
|
|
157
|
-
const newDoc = await patches.openDoc(docPath);
|
|
150
|
+
async function create(docPath, initialState, options2) {
|
|
151
|
+
const newDoc = await patches.openDoc(docPath, options2);
|
|
158
152
|
newDoc.change((patch, root) => {
|
|
159
153
|
if (initialState instanceof JSONPatch) {
|
|
160
154
|
patch.ops = initialState.ops;
|
|
@@ -166,22 +160,7 @@ function _usePatchesDocLazy(options) {
|
|
|
166
160
|
});
|
|
167
161
|
await patches.closeDoc(docPath);
|
|
168
162
|
}
|
|
169
|
-
|
|
170
|
-
currentDoc?.change(mutator);
|
|
171
|
-
}
|
|
172
|
-
return {
|
|
173
|
-
data,
|
|
174
|
-
loading,
|
|
175
|
-
error,
|
|
176
|
-
rev,
|
|
177
|
-
hasPending,
|
|
178
|
-
change,
|
|
179
|
-
doc,
|
|
180
|
-
path,
|
|
181
|
-
load,
|
|
182
|
-
close,
|
|
183
|
-
create
|
|
184
|
-
};
|
|
163
|
+
return { ...baseReturn, path, load, close, create };
|
|
185
164
|
}
|
|
186
165
|
function usePatchesSync() {
|
|
187
166
|
const { sync } = usePatchesContext();
|
|
@@ -210,43 +189,24 @@ function createDocInjectionKey(name) {
|
|
|
210
189
|
}
|
|
211
190
|
function providePatchesDoc(name, docId, options = {}) {
|
|
212
191
|
const { patches } = usePatchesContext();
|
|
213
|
-
const { autoClose = false } = options;
|
|
192
|
+
const { autoClose = false, algorithm, metadata } = options;
|
|
214
193
|
const shouldUntrack = autoClose === "untrack";
|
|
194
|
+
const openDocOpts = { algorithm, metadata };
|
|
215
195
|
const manager = getDocManager(patches);
|
|
216
|
-
const
|
|
217
|
-
const data = shallowRef(void 0);
|
|
218
|
-
const loading = ref(true);
|
|
219
|
-
const error = ref(null);
|
|
220
|
-
const rev = ref(0);
|
|
221
|
-
const hasPending = ref(false);
|
|
196
|
+
const { setupDoc, baseReturn } = createDocReactiveState({ changeBehavior: "throw" });
|
|
222
197
|
const currentDocId = ref(unref(docId));
|
|
223
|
-
|
|
224
|
-
function setupDoc(patchesDoc) {
|
|
225
|
-
unsubscribers.forEach((unsub) => unsub());
|
|
226
|
-
unsubscribers.length = 0;
|
|
227
|
-
doc.value = patchesDoc;
|
|
228
|
-
const unsubState = patchesDoc.subscribe((state) => {
|
|
229
|
-
data.value = state;
|
|
230
|
-
rev.value = patchesDoc.committedRev;
|
|
231
|
-
hasPending.value = patchesDoc.hasPending;
|
|
232
|
-
});
|
|
233
|
-
unsubscribers.push(unsubState);
|
|
234
|
-
const unsubSync = patchesDoc.onSyncing((syncState) => {
|
|
235
|
-
loading.value = syncState === "initial" || syncState === "updating";
|
|
236
|
-
error.value = syncState instanceof Error ? syncState : null;
|
|
237
|
-
});
|
|
238
|
-
unsubscribers.push(unsubSync);
|
|
239
|
-
loading.value = patchesDoc.syncing !== null;
|
|
240
|
-
}
|
|
198
|
+
let unsubscribe = null;
|
|
241
199
|
async function initDoc(id) {
|
|
242
200
|
currentDocId.value = id;
|
|
201
|
+
unsubscribe?.();
|
|
202
|
+
unsubscribe = null;
|
|
243
203
|
if (autoClose) {
|
|
244
204
|
try {
|
|
245
|
-
const patchesDoc = await manager.openDoc(patches, id);
|
|
246
|
-
setupDoc(patchesDoc);
|
|
205
|
+
const patchesDoc = await manager.openDoc(patches, id, openDocOpts);
|
|
206
|
+
unsubscribe = setupDoc(patchesDoc);
|
|
247
207
|
} catch (err) {
|
|
248
|
-
error.value = err;
|
|
249
|
-
loading.value = false;
|
|
208
|
+
baseReturn.error.value = err;
|
|
209
|
+
baseReturn.loading.value = false;
|
|
250
210
|
}
|
|
251
211
|
} else {
|
|
252
212
|
try {
|
|
@@ -257,36 +217,21 @@ function providePatchesDoc(name, docId, options = {}) {
|
|
|
257
217
|
);
|
|
258
218
|
}
|
|
259
219
|
manager.incrementRefCount(id);
|
|
260
|
-
setupDoc(patchesDoc);
|
|
220
|
+
unsubscribe = setupDoc(patchesDoc);
|
|
261
221
|
} catch (err) {
|
|
262
|
-
error.value = err;
|
|
263
|
-
loading.value = false;
|
|
222
|
+
baseReturn.error.value = err;
|
|
223
|
+
baseReturn.loading.value = false;
|
|
264
224
|
}
|
|
265
225
|
}
|
|
266
226
|
}
|
|
267
|
-
function change(mutator) {
|
|
268
|
-
if (!doc.value) {
|
|
269
|
-
throw new Error("Cannot make changes: document not loaded yet");
|
|
270
|
-
}
|
|
271
|
-
doc.value.change(mutator);
|
|
272
|
-
}
|
|
273
|
-
const docReturn = {
|
|
274
|
-
data,
|
|
275
|
-
loading,
|
|
276
|
-
error,
|
|
277
|
-
rev,
|
|
278
|
-
hasPending,
|
|
279
|
-
change,
|
|
280
|
-
doc
|
|
281
|
-
};
|
|
282
227
|
const key = createDocInjectionKey(name);
|
|
283
|
-
provide(key,
|
|
228
|
+
provide(key, baseReturn);
|
|
284
229
|
initDoc(unref(docId));
|
|
285
230
|
if (typeof docId !== "string") {
|
|
286
231
|
watch(docId, async (newDocId, oldDocId) => {
|
|
287
232
|
if (newDocId === oldDocId) return;
|
|
288
|
-
|
|
289
|
-
|
|
233
|
+
unsubscribe?.();
|
|
234
|
+
unsubscribe = null;
|
|
290
235
|
if (autoClose) {
|
|
291
236
|
await manager.closeDoc(patches, oldDocId, shouldUntrack);
|
|
292
237
|
} else {
|
|
@@ -296,14 +241,14 @@ function providePatchesDoc(name, docId, options = {}) {
|
|
|
296
241
|
});
|
|
297
242
|
}
|
|
298
243
|
onBeforeUnmount(async () => {
|
|
299
|
-
|
|
244
|
+
unsubscribe?.();
|
|
300
245
|
if (autoClose) {
|
|
301
246
|
await manager.closeDoc(patches, currentDocId.value, shouldUntrack);
|
|
302
247
|
} else {
|
|
303
248
|
manager.decrementRefCount(currentDocId.value);
|
|
304
249
|
}
|
|
305
250
|
});
|
|
306
|
-
return
|
|
251
|
+
return baseReturn;
|
|
307
252
|
}
|
|
308
253
|
function useCurrentDoc(name) {
|
|
309
254
|
const key = createDocInjectionKey(name);
|
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
import { Ref, ShallowRef } from 'vue';
|
|
2
|
+
import { OpenDocOptions } from '../client/Patches.js';
|
|
3
|
+
import '../event-signal.js';
|
|
4
|
+
import '../json-patch/types.js';
|
|
5
|
+
import '../types.js';
|
|
6
|
+
import '../json-patch/JSONPatch.js';
|
|
7
|
+
import '@dabble/delta';
|
|
8
|
+
import '../client/ClientAlgorithm.js';
|
|
9
|
+
import '../BaseDoc-DkP3tUhT.js';
|
|
10
|
+
import '../client/PatchesStore.js';
|
|
2
11
|
|
|
3
12
|
/**
|
|
4
13
|
* Options for useManagedDocs composable.
|
|
5
14
|
*/
|
|
6
|
-
interface UseManagedDocsOptions {
|
|
15
|
+
interface UseManagedDocsOptions extends OpenDocOptions {
|
|
7
16
|
/**
|
|
8
17
|
* Inject doc.id into state under this key on every state update.
|
|
9
18
|
* Useful when the document ID is derived from the path but needed in the data.
|
package/dist/vue/managed-docs.js
CHANGED
|
@@ -5,7 +5,8 @@ import { areSetsEqual } from "./utils.js";
|
|
|
5
5
|
const emptyPaths = /* @__PURE__ */ new Set();
|
|
6
6
|
function useManagedDocs(pathsRef, initialData, reducer, options) {
|
|
7
7
|
const { patches } = usePatchesContext();
|
|
8
|
-
const { idProp } = options ?? {};
|
|
8
|
+
const { idProp, algorithm, metadata } = options ?? {};
|
|
9
|
+
const openDocOpts = { algorithm, metadata };
|
|
9
10
|
const data = shallowRef(initialData);
|
|
10
11
|
const docs = /* @__PURE__ */ new Map();
|
|
11
12
|
const unsubscribes = /* @__PURE__ */ new Map();
|
|
@@ -28,7 +29,7 @@ function useManagedDocs(pathsRef, initialData, reducer, options) {
|
|
|
28
29
|
});
|
|
29
30
|
async function openPath(path) {
|
|
30
31
|
try {
|
|
31
|
-
const doc = await patches.openDoc(path);
|
|
32
|
+
const doc = await patches.openDoc(path, openDocOpts);
|
|
32
33
|
if (currentPaths.has(path)) {
|
|
33
34
|
docs.set(path, doc);
|
|
34
35
|
let initialState = doc.state;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dabble/patches",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.7",
|
|
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": {
|