@dabble/patches 0.8.8 → 0.8.10
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/ot/shared/changeBatching.js +1 -1
- package/dist/client/BranchClientStore.d.ts +71 -0
- package/dist/client/BranchClientStore.js +0 -0
- package/dist/client/ClientAlgorithm.d.ts +12 -0
- package/dist/client/IndexedDBStore.d.ts +13 -2
- package/dist/client/IndexedDBStore.js +125 -1
- package/dist/client/LWWInMemoryStore.js +5 -3
- package/dist/client/LWWIndexedDBStore.d.ts +1 -0
- package/dist/client/LWWIndexedDBStore.js +14 -5
- package/dist/client/OTAlgorithm.d.ts +3 -0
- package/dist/client/OTAlgorithm.js +4 -0
- package/dist/client/OTClientStore.d.ts +11 -0
- package/dist/client/OTIndexedDBStore.d.ts +9 -0
- package/dist/client/OTIndexedDBStore.js +15 -3
- package/dist/client/Patches.d.ts +6 -0
- package/dist/client/Patches.js +11 -0
- package/dist/client/PatchesBranchClient.d.ts +73 -12
- package/dist/client/PatchesBranchClient.js +143 -14
- package/dist/client/index.d.ts +3 -1
- package/dist/compression/index.d.ts +15 -7
- package/dist/compression/index.js +13 -2
- package/dist/index.d.ts +4 -2
- package/dist/net/PatchesClient.d.ts +13 -8
- package/dist/net/PatchesClient.js +17 -10
- package/dist/net/PatchesSync.d.ts +36 -3
- package/dist/net/PatchesSync.js +72 -0
- package/dist/net/index.d.ts +2 -1
- package/dist/net/protocol/types.d.ts +5 -4
- package/dist/net/rest/PatchesREST.d.ts +8 -5
- package/dist/net/rest/PatchesREST.js +30 -20
- package/dist/net/rest/index.d.ts +1 -1
- package/dist/net/rest/index.js +1 -2
- package/dist/net/rest/utils.d.ts +1 -9
- package/dist/net/rest/utils.js +0 -4
- package/dist/server/BranchManager.d.ts +11 -10
- package/dist/server/LWWBranchManager.d.ts +10 -9
- package/dist/server/LWWBranchManager.js +48 -31
- package/dist/server/LWWMemoryStoreBackend.d.ts +5 -2
- package/dist/server/LWWMemoryStoreBackend.js +21 -3
- package/dist/server/OTBranchManager.d.ts +14 -12
- package/dist/server/OTBranchManager.js +58 -66
- package/dist/server/branchUtils.d.ts +6 -15
- package/dist/server/branchUtils.js +16 -13
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +2 -2
- package/dist/server/types.d.ts +8 -2
- package/dist/solid/context.d.ts +1 -0
- package/dist/solid/index.d.ts +2 -1
- package/dist/solid/primitives.d.ts +30 -155
- package/dist/solid/primitives.js +53 -219
- package/dist/types.d.ts +35 -6
- package/dist/vue/composables.d.ts +29 -170
- package/dist/vue/composables.js +59 -200
- package/dist/vue/index.d.ts +2 -1
- package/dist/vue/provider.d.ts +1 -0
- package/package.json +1 -1
package/dist/solid/primitives.js
CHANGED
|
@@ -7,14 +7,12 @@ import {
|
|
|
7
7
|
createEffect,
|
|
8
8
|
onCleanup
|
|
9
9
|
} from "solid-js";
|
|
10
|
-
import { JSONPatch } from "../json-patch/JSONPatch.js";
|
|
11
10
|
import { usePatchesContext } from "./context.js";
|
|
12
11
|
import { getDocManager } from "./doc-manager.js";
|
|
13
|
-
function createDocReactiveState(
|
|
14
|
-
const { initialLoading = true, hasSyncContext = false, transformState, changeBehavior } = options;
|
|
12
|
+
function createDocReactiveState(hasSyncContext) {
|
|
15
13
|
const [doc, setDoc] = createSignal(void 0);
|
|
16
14
|
const [data, setData] = createSignal(void 0);
|
|
17
|
-
const [loading, setLoading] = createSignal(
|
|
15
|
+
const [loading, setLoading] = createSignal(false);
|
|
18
16
|
const [error, setError] = createSignal();
|
|
19
17
|
const [rev, setRev] = createSignal(0);
|
|
20
18
|
const [hasPending, setHasPending] = createSignal(false);
|
|
@@ -34,9 +32,6 @@ function createDocReactiveState(options) {
|
|
|
34
32
|
}
|
|
35
33
|
}
|
|
36
34
|
const unsubState = patchesDoc.subscribe((state) => {
|
|
37
|
-
if (transformState && state) {
|
|
38
|
-
state = transformState(state, patchesDoc);
|
|
39
|
-
}
|
|
40
35
|
setData(() => state);
|
|
41
36
|
setRev(patchesDoc.committedRev);
|
|
42
37
|
setHasPending(patchesDoc.hasPending);
|
|
@@ -60,155 +55,60 @@ function createDocReactiveState(options) {
|
|
|
60
55
|
setHasPending(false);
|
|
61
56
|
}
|
|
62
57
|
function change(mutator) {
|
|
63
|
-
|
|
64
|
-
const currentDoc = doc();
|
|
65
|
-
if (!currentDoc) {
|
|
66
|
-
throw new Error("Cannot make changes: document not loaded yet");
|
|
67
|
-
}
|
|
68
|
-
currentDoc.change(mutator);
|
|
69
|
-
} else {
|
|
70
|
-
doc()?.change(mutator);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
const baseReturn = {
|
|
74
|
-
data,
|
|
75
|
-
loading,
|
|
76
|
-
error,
|
|
77
|
-
rev,
|
|
78
|
-
hasPending,
|
|
79
|
-
change,
|
|
80
|
-
doc
|
|
81
|
-
};
|
|
82
|
-
return {
|
|
83
|
-
doc,
|
|
84
|
-
setDoc,
|
|
85
|
-
data,
|
|
86
|
-
setData,
|
|
87
|
-
loading,
|
|
88
|
-
setLoading,
|
|
89
|
-
error,
|
|
90
|
-
setError,
|
|
91
|
-
rev,
|
|
92
|
-
setRev,
|
|
93
|
-
hasPending,
|
|
94
|
-
setHasPending,
|
|
95
|
-
setupDoc,
|
|
96
|
-
resetSignals,
|
|
97
|
-
change,
|
|
98
|
-
baseReturn
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
function usePatchesDoc(docIdOrOptions, options) {
|
|
102
|
-
if (typeof docIdOrOptions === "string" || typeof docIdOrOptions === "function") {
|
|
103
|
-
return _usePatchesDocEager(docIdOrOptions, options ?? {});
|
|
58
|
+
doc()?.change(mutator);
|
|
104
59
|
}
|
|
105
|
-
|
|
60
|
+
const baseReturn = { data, loading, error, rev, hasPending, change, doc };
|
|
61
|
+
return { setupDoc, resetSignals, setError, baseReturn };
|
|
106
62
|
}
|
|
107
|
-
function
|
|
63
|
+
function usePatchesDoc(docId, options) {
|
|
108
64
|
const { patches, sync } = usePatchesContext();
|
|
109
|
-
const {
|
|
110
|
-
const shouldUntrack = autoClose === "untrack";
|
|
65
|
+
const { untrack: shouldUntrack = false, algorithm, metadata } = options ?? {};
|
|
111
66
|
const openDocOpts = { algorithm, metadata };
|
|
112
67
|
const manager = getDocManager(patches);
|
|
113
|
-
const { setupDoc,
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
68
|
+
const { setupDoc, resetSignals, setError, baseReturn } = createDocReactiveState(!!sync);
|
|
69
|
+
const source = typeof docId === "string" ? () => docId : () => docId() || null;
|
|
70
|
+
let currentId = null;
|
|
71
|
+
const [docResource] = createResource(source, async (id) => {
|
|
72
|
+
return await manager.openDoc(patches, id, openDocOpts);
|
|
117
73
|
});
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
setLoading(false);
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
|
-
onCleanup(() => {
|
|
136
|
-
const id = docIdAccessor();
|
|
137
|
-
manager.closeDoc(patches, id, shouldUntrack);
|
|
138
|
-
});
|
|
139
|
-
} else {
|
|
140
|
-
createEffect(() => {
|
|
141
|
-
const id = docIdAccessor();
|
|
142
|
-
const patchesDoc = patches.getOpenDoc(id);
|
|
143
|
-
if (!patchesDoc) {
|
|
144
|
-
throw new Error(
|
|
145
|
-
`Document "${id}" is not open. Either open it with patches.openDoc() first, or use { autoClose: true } option.`
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
manager.incrementRefCount(id);
|
|
149
|
-
const unsub = setupDoc(patchesDoc);
|
|
150
|
-
onCleanup(() => {
|
|
151
|
-
unsub();
|
|
152
|
-
manager.decrementRefCount(id);
|
|
153
|
-
});
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
return baseReturn;
|
|
157
|
-
}
|
|
158
|
-
function _usePatchesDocLazy(options) {
|
|
159
|
-
const { patches, sync } = usePatchesContext();
|
|
160
|
-
const { idProp } = options;
|
|
161
|
-
const { setupDoc, resetSignals, setError, setLoading, baseReturn } = createDocReactiveState({
|
|
162
|
-
initialLoading: false,
|
|
163
|
-
hasSyncContext: !!sync,
|
|
164
|
-
changeBehavior: "noop",
|
|
165
|
-
transformState: idProp ? (state, patchesDoc) => ({ ...state, [idProp]: patchesDoc.id }) : void 0
|
|
74
|
+
createEffect(() => {
|
|
75
|
+
const currentSource = source();
|
|
76
|
+
const loadedDoc = docResource();
|
|
77
|
+
if (currentSource && loadedDoc) {
|
|
78
|
+
currentId = currentSource;
|
|
79
|
+
const unsub = setupDoc(loadedDoc);
|
|
80
|
+
onCleanup(() => unsub());
|
|
81
|
+
} else {
|
|
82
|
+
resetSignals();
|
|
83
|
+
}
|
|
84
|
+
const resourceError = docResource.error;
|
|
85
|
+
if (resourceError) {
|
|
86
|
+
setError(resourceError);
|
|
87
|
+
}
|
|
166
88
|
});
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
resetSignals();
|
|
173
|
-
}
|
|
174
|
-
async function load(docPath, options2) {
|
|
175
|
-
if (path()) {
|
|
176
|
-
const prevPath = path();
|
|
177
|
-
teardown();
|
|
178
|
-
await patches.closeDoc(prevPath);
|
|
89
|
+
createEffect((prevId) => {
|
|
90
|
+
const id = source();
|
|
91
|
+
if (prevId && prevId !== id) {
|
|
92
|
+
currentId = null;
|
|
93
|
+
manager.closeDoc(patches, prevId, shouldUntrack);
|
|
179
94
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
95
|
+
return id;
|
|
96
|
+
});
|
|
97
|
+
baseReturn.close = async () => {
|
|
98
|
+
if (currentId) {
|
|
99
|
+
const id = currentId;
|
|
100
|
+
currentId = null;
|
|
101
|
+
resetSignals();
|
|
102
|
+
await manager.closeDoc(patches, id, shouldUntrack);
|
|
188
103
|
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
if (
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
setPath(null);
|
|
195
|
-
await patches.closeDoc(prevPath);
|
|
104
|
+
};
|
|
105
|
+
onCleanup(() => {
|
|
106
|
+
if (currentId) {
|
|
107
|
+
manager.closeDoc(patches, currentId, shouldUntrack);
|
|
108
|
+
currentId = null;
|
|
196
109
|
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
const newDoc = await patches.openDoc(docPath, options2);
|
|
200
|
-
newDoc.change((patch, root) => {
|
|
201
|
-
if (initialState instanceof JSONPatch) {
|
|
202
|
-
patch.ops = initialState.ops;
|
|
203
|
-
} else {
|
|
204
|
-
const state = { ...initialState };
|
|
205
|
-
if (idProp) delete state[idProp];
|
|
206
|
-
patch.replace(root, state);
|
|
207
|
-
}
|
|
208
|
-
});
|
|
209
|
-
await patches.closeDoc(docPath);
|
|
210
|
-
}
|
|
211
|
-
return { ...baseReturn, path, load, close, create };
|
|
110
|
+
});
|
|
111
|
+
return baseReturn;
|
|
212
112
|
}
|
|
213
113
|
function usePatchesSync() {
|
|
214
114
|
const { sync } = usePatchesContext();
|
|
@@ -226,79 +126,16 @@ function usePatchesSync() {
|
|
|
226
126
|
onCleanup(() => {
|
|
227
127
|
unsubscribe();
|
|
228
128
|
});
|
|
229
|
-
return {
|
|
230
|
-
connected,
|
|
231
|
-
syncing,
|
|
232
|
-
online
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
function toAccessor(value) {
|
|
236
|
-
return typeof value === "function" ? value : () => value;
|
|
129
|
+
return { connected, syncing, online };
|
|
237
130
|
}
|
|
238
131
|
function createPatchesDoc(name) {
|
|
239
132
|
const Context = createContext();
|
|
240
133
|
function Provider(props) {
|
|
241
|
-
const
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
const { setupDoc, setError, setLoading, baseReturn } = createDocReactiveState({
|
|
247
|
-
initialLoading: !!autoClose,
|
|
248
|
-
hasSyncContext: !!sync,
|
|
249
|
-
changeBehavior: "throw"
|
|
250
|
-
});
|
|
251
|
-
const docIdAccessor = toAccessor(props.docId);
|
|
252
|
-
if (autoClose) {
|
|
253
|
-
const [docResource] = createResource(docIdAccessor, async (id) => {
|
|
254
|
-
return await manager.openDoc(patches, id, openDocOpts);
|
|
255
|
-
});
|
|
256
|
-
createEffect(() => {
|
|
257
|
-
const loadedDoc = docResource();
|
|
258
|
-
if (loadedDoc) {
|
|
259
|
-
const unsub = setupDoc(loadedDoc);
|
|
260
|
-
onCleanup(() => unsub());
|
|
261
|
-
}
|
|
262
|
-
const resourceError = docResource.error;
|
|
263
|
-
if (resourceError) {
|
|
264
|
-
setError(resourceError);
|
|
265
|
-
setLoading(false);
|
|
266
|
-
}
|
|
267
|
-
});
|
|
268
|
-
createEffect((prevId) => {
|
|
269
|
-
const currentId = docIdAccessor();
|
|
270
|
-
if (prevId && prevId !== currentId) {
|
|
271
|
-
manager.closeDoc(patches, prevId, shouldUntrack);
|
|
272
|
-
}
|
|
273
|
-
return currentId;
|
|
274
|
-
});
|
|
275
|
-
onCleanup(() => {
|
|
276
|
-
const id = docIdAccessor();
|
|
277
|
-
manager.closeDoc(patches, id, shouldUntrack);
|
|
278
|
-
});
|
|
279
|
-
} else {
|
|
280
|
-
createEffect((prevId) => {
|
|
281
|
-
const id = docIdAccessor();
|
|
282
|
-
if (prevId && prevId !== id) {
|
|
283
|
-
manager.decrementRefCount(prevId);
|
|
284
|
-
}
|
|
285
|
-
const patchesDoc = patches.getOpenDoc(id);
|
|
286
|
-
if (!patchesDoc) {
|
|
287
|
-
throw new Error(
|
|
288
|
-
`Document "${id}" is not open. Either open it with patches.openDoc() first, or use autoClose option.`
|
|
289
|
-
);
|
|
290
|
-
}
|
|
291
|
-
manager.incrementRefCount(id);
|
|
292
|
-
const unsub = setupDoc(patchesDoc);
|
|
293
|
-
onCleanup(() => unsub());
|
|
294
|
-
return id;
|
|
295
|
-
});
|
|
296
|
-
onCleanup(() => {
|
|
297
|
-
const id = docIdAccessor();
|
|
298
|
-
manager.decrementRefCount(id);
|
|
299
|
-
});
|
|
300
|
-
}
|
|
301
|
-
return /* @__PURE__ */ React.createElement(Context.Provider, { value: baseReturn, children: props.children });
|
|
134
|
+
const result = usePatchesDoc(
|
|
135
|
+
typeof props.docId === "function" ? props.docId : props.docId,
|
|
136
|
+
{ untrack: props.untrack, algorithm: props.algorithm, metadata: props.metadata }
|
|
137
|
+
);
|
|
138
|
+
return /* @__PURE__ */ React.createElement(Context.Provider, { value: result, children: props.children });
|
|
302
139
|
}
|
|
303
140
|
function useDoc() {
|
|
304
141
|
const context = useContext(Context);
|
|
@@ -309,10 +146,7 @@ function createPatchesDoc(name) {
|
|
|
309
146
|
}
|
|
310
147
|
return context;
|
|
311
148
|
}
|
|
312
|
-
return {
|
|
313
|
-
Provider,
|
|
314
|
-
useDoc
|
|
315
|
-
};
|
|
149
|
+
return { Provider, useDoc };
|
|
316
150
|
}
|
|
317
151
|
export {
|
|
318
152
|
createPatchesDoc,
|
package/dist/types.d.ts
CHANGED
|
@@ -81,8 +81,6 @@ interface DocSyncState {
|
|
|
81
81
|
syncError?: Error;
|
|
82
82
|
isLoaded: boolean;
|
|
83
83
|
}
|
|
84
|
-
/** Status options for a branch */
|
|
85
|
-
type BranchStatus = 'open' | 'closed' | 'merged' | 'archived' | 'abandoned';
|
|
86
84
|
interface Branch {
|
|
87
85
|
/** The ID of the branch document. */
|
|
88
86
|
id: string;
|
|
@@ -92,10 +90,10 @@ interface Branch {
|
|
|
92
90
|
branchedAtRev: number;
|
|
93
91
|
/** Unix timestamp in milliseconds when the branch was created. */
|
|
94
92
|
createdAt: number;
|
|
93
|
+
/** Unix timestamp in milliseconds when the branch was last modified. Updated on metadata changes. */
|
|
94
|
+
modifiedAt: number;
|
|
95
95
|
/** Optional user-friendly name for the branch. */
|
|
96
96
|
name?: string;
|
|
97
|
-
/** Current status of the branch. */
|
|
98
|
-
status: BranchStatus;
|
|
99
97
|
/**
|
|
100
98
|
* The first revision on the branch that contains user content (after initialization changes).
|
|
101
99
|
* Initialization changes (e.g. the root-replace that seeds the branch with source state)
|
|
@@ -104,10 +102,41 @@ interface Branch {
|
|
|
104
102
|
* across multiple changes due to size limits.
|
|
105
103
|
*/
|
|
106
104
|
contentStartRev: number;
|
|
105
|
+
/**
|
|
106
|
+
* The branch-side revision through which changes have already been merged.
|
|
107
|
+
* Set after each merge so subsequent merges only pick up new changes.
|
|
108
|
+
* Undefined means the branch has never been merged.
|
|
109
|
+
*/
|
|
110
|
+
lastMergedRev?: number;
|
|
111
|
+
/** The pending operation to sync to the server. Set by BranchClientStore methods. */
|
|
112
|
+
pendingOp?: 'create' | 'update' | 'delete';
|
|
113
|
+
/** True when this branch has been deleted. Stored as a tombstone for incremental sync. */
|
|
114
|
+
deleted?: true;
|
|
107
115
|
/** Optional arbitrary metadata associated with the branch record. */
|
|
108
116
|
[metadata: string]: any;
|
|
109
117
|
}
|
|
110
|
-
type EditableBranchMetadata = Disallowed<Branch, 'id' | 'docId' | 'branchedAtRev' | 'createdAt' | '
|
|
118
|
+
type EditableBranchMetadata = Disallowed<Branch, 'id' | 'docId' | 'branchedAtRev' | 'createdAt' | 'modifiedAt' | 'contentStartRev' | 'pendingOp' | 'deleted'>;
|
|
119
|
+
/**
|
|
120
|
+
* Metadata for creating a new branch.
|
|
121
|
+
* Allows `id` and `contentStartRev` in addition to the fields allowed by `EditableBranchMetadata`.
|
|
122
|
+
* - `id`: Client-provided branch document ID. Required for offline branch creation.
|
|
123
|
+
* - `contentStartRev`: The first revision of user content. Set by the client when creating
|
|
124
|
+
* initial changes offline (the server uses this to know where user content begins during merge).
|
|
125
|
+
*/
|
|
126
|
+
type CreateBranchMetadata = Omit<Disallowed<Branch, 'docId' | 'branchedAtRev' | 'createdAt' | 'modifiedAt' | 'pendingOp' | 'deleted'>, 'contentStartRev'> & {
|
|
127
|
+
contentStartRev?: number;
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* Options for listing branches.
|
|
131
|
+
*/
|
|
132
|
+
interface ListBranchesOptions {
|
|
133
|
+
/**
|
|
134
|
+
* Only return branches modified after this timestamp (Unix ms).
|
|
135
|
+
* Enables incremental sync: after the initial full list, subsequent calls can pass the
|
|
136
|
+
* most recent `modifiedAt` value to fetch only updates.
|
|
137
|
+
*/
|
|
138
|
+
since?: number;
|
|
139
|
+
}
|
|
111
140
|
/**
|
|
112
141
|
* Represents a tombstone for a deleted document.
|
|
113
142
|
* Tombstones persist after deletion to inform late-connecting clients
|
|
@@ -247,4 +276,4 @@ type PathProxy<T = any> = IsAny<T> extends true ? DeepPathProxy : {
|
|
|
247
276
|
*/
|
|
248
277
|
type ChangeMutator<T> = (patch: JSONPatch, root: PathProxy<T>) => void;
|
|
249
278
|
|
|
250
|
-
export type { Branch,
|
|
279
|
+
export type { Branch, Change, ChangeInput, ChangeMutator, CommitChangesOptions, CreateBranchMetadata, DeleteDocOptions, DocSyncState, DocSyncStatus, DocumentTombstone, EditableBranchMetadata, EditableVersionMetadata, ListBranchesOptions, ListChangesOptions, ListVersionsOptions, PatchesSnapshot, PatchesState, PathProxy, VersionMetadata };
|
|
@@ -1,243 +1,102 @@
|
|
|
1
|
-
import { ShallowRef, Ref, MaybeRef } from 'vue';
|
|
1
|
+
import { ShallowRef, Ref, MaybeRef, MaybeRefOrGetter } from 'vue';
|
|
2
2
|
import { OpenDocOptions } from '../client/Patches.js';
|
|
3
3
|
import { P as PatchesDoc } from '../BaseDoc-BT18xPxU.js';
|
|
4
|
-
import { JSONPatch } from '../json-patch/JSONPatch.js';
|
|
5
4
|
import { ChangeMutator } from '../types.js';
|
|
6
5
|
import 'easy-signal';
|
|
7
6
|
import '../json-patch/types.js';
|
|
8
7
|
import '../client/ClientAlgorithm.js';
|
|
9
8
|
import '../client/PatchesStore.js';
|
|
9
|
+
import '../json-patch/JSONPatch.js';
|
|
10
10
|
import '@dabble/delta';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* Options for usePatchesDoc composable
|
|
13
|
+
* Options for usePatchesDoc composable.
|
|
14
14
|
*/
|
|
15
15
|
interface UsePatchesDocOptions extends OpenDocOptions {
|
|
16
16
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* - `false` (default): Explicit mode. Assumes doc is already open. Throws if not.
|
|
20
|
-
* - `true`: Opens doc on mount with ref counting, closes on unmount (doc stays tracked).
|
|
21
|
-
* - `'untrack'`: Opens doc on mount, closes AND untracks on unmount (removes from sync).
|
|
22
|
-
*
|
|
23
|
-
* @default false
|
|
17
|
+
* When true, the document is removed from sync tracking on close.
|
|
18
|
+
* By default documents stay tracked after closing.
|
|
24
19
|
*/
|
|
25
|
-
|
|
20
|
+
untrack?: boolean;
|
|
26
21
|
}
|
|
27
22
|
/**
|
|
28
|
-
*
|
|
29
|
-
*/
|
|
30
|
-
interface UsePatchesDocLazyOptions {
|
|
31
|
-
/**
|
|
32
|
-
* Inject doc.id into state under this key on every state update.
|
|
33
|
-
* Useful when the document ID is derived from the path but needed in the data.
|
|
34
|
-
*/
|
|
35
|
-
idProp?: string;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Return type for usePatchesDoc composable (eager mode).
|
|
23
|
+
* Return type for usePatchesDoc composable.
|
|
39
24
|
*/
|
|
40
25
|
interface UsePatchesDocReturn<T extends object> {
|
|
41
|
-
/**
|
|
42
|
-
* Reactive reference to the document state.
|
|
43
|
-
* Updated whenever the document changes (local or remote).
|
|
44
|
-
*/
|
|
26
|
+
/** Reactive reference to the document state. */
|
|
45
27
|
data: ShallowRef<T | undefined>;
|
|
46
|
-
/**
|
|
47
|
-
* Whether the document is currently loading/syncing.
|
|
48
|
-
* - `true` during initial load or updates
|
|
49
|
-
* - `false` when fully synced
|
|
50
|
-
*/
|
|
28
|
+
/** Whether the document is currently loading. */
|
|
51
29
|
loading: Ref<boolean>;
|
|
52
|
-
/**
|
|
53
|
-
* Error that occurred during sync, if any.
|
|
54
|
-
*/
|
|
30
|
+
/** Error that occurred during sync, if any. */
|
|
55
31
|
error: Ref<Error | undefined>;
|
|
56
|
-
/**
|
|
57
|
-
* The committed revision number.
|
|
58
|
-
* Increments each time the server confirms changes.
|
|
59
|
-
*/
|
|
32
|
+
/** The committed revision number. */
|
|
60
33
|
rev: Ref<number>;
|
|
61
|
-
/**
|
|
62
|
-
* Whether there are pending local changes not yet committed by server.
|
|
63
|
-
*/
|
|
34
|
+
/** Whether there are pending local changes not yet committed by server. */
|
|
64
35
|
hasPending: Ref<boolean>;
|
|
65
|
-
/**
|
|
66
|
-
* Make changes to the document.
|
|
67
|
-
*
|
|
68
|
-
* @example
|
|
69
|
-
* ```typescript
|
|
70
|
-
* change((patch, root) => {
|
|
71
|
-
* patch.replace(root.title!, 'New Title')
|
|
72
|
-
* })
|
|
73
|
-
* ```
|
|
74
|
-
*/
|
|
36
|
+
/** Make changes to the document. No-ops if the document is not loaded. */
|
|
75
37
|
change: (mutator: ChangeMutator<T>) => void;
|
|
76
|
-
/**
|
|
77
|
-
* The underlying PatchesDoc instance.
|
|
78
|
-
* Useful for advanced operations.
|
|
79
|
-
*/
|
|
80
|
-
doc: ShallowRef<PatchesDoc<T> | undefined>;
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Return type for usePatchesDoc composable (lazy mode).
|
|
84
|
-
* Extends the eager return type with lifecycle management methods.
|
|
85
|
-
*/
|
|
86
|
-
interface UsePatchesDocLazyReturn<T extends object> extends UsePatchesDocReturn<T> {
|
|
87
|
-
/**
|
|
88
|
-
* Current document path. `null` when no document is loaded.
|
|
89
|
-
*/
|
|
90
|
-
path: Ref<string | null>;
|
|
91
|
-
/**
|
|
92
|
-
* Open a document by path. Closes any previously loaded document first.
|
|
93
|
-
*
|
|
94
|
-
* @param docPath - The document path to open
|
|
95
|
-
* @param options - Optional algorithm and metadata overrides
|
|
96
|
-
*/
|
|
97
|
-
load: (docPath: string, options?: OpenDocOptions) => Promise<void>;
|
|
98
|
-
/**
|
|
99
|
-
* Close the current document, unsubscribe, and reset all state.
|
|
100
|
-
* Calls `patches.closeDoc()` but does not untrack — tracking is managed separately.
|
|
101
|
-
*/
|
|
38
|
+
/** Close the document and reset state. Useful for explicit cleanup without unmounting. */
|
|
102
39
|
close: () => Promise<void>;
|
|
103
|
-
/**
|
|
104
|
-
|
|
105
|
-
* A one-shot operation that doesn't bind the document to this handle.
|
|
106
|
-
*
|
|
107
|
-
* @param docPath - The document path to create
|
|
108
|
-
* @param initialState - Initial state object or JSONPatch to apply
|
|
109
|
-
* @param options - Optional algorithm and metadata overrides
|
|
110
|
-
*/
|
|
111
|
-
create: (docPath: string, initialState: T | JSONPatch, options?: OpenDocOptions) => Promise<void>;
|
|
40
|
+
/** The underlying PatchesDoc instance. */
|
|
41
|
+
doc: ShallowRef<PatchesDoc<T> | undefined>;
|
|
112
42
|
}
|
|
113
43
|
/**
|
|
114
44
|
* Vue composable for reactive Patches document state.
|
|
115
45
|
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
* @example
|
|
121
|
-
* ```typescript
|
|
122
|
-
* // Explicit lifecycle — you control open/close
|
|
123
|
-
* const { data, loading, change } = usePatchesDoc('doc-123')
|
|
124
|
-
*
|
|
125
|
-
* // Auto lifecycle — opens on mount, closes on unmount
|
|
126
|
-
* const { data, loading, change } = usePatchesDoc('doc-123', { autoClose: true })
|
|
127
|
-
* ```
|
|
128
|
-
*
|
|
129
|
-
* ## Lazy Mode (without docId)
|
|
130
|
-
*
|
|
131
|
-
* Returns a deferred handle with `load()`, `close()`, and `create()` methods.
|
|
132
|
-
* Ideal for Pinia stores where the document path isn't known at creation time.
|
|
133
|
-
* Does NOT use `onBeforeUnmount` — caller manages lifecycle.
|
|
46
|
+
* Opens the document automatically and closes it on unmount (or when the path
|
|
47
|
+
* changes). Accepts a static string, a ref, or a getter. When the value is
|
|
48
|
+
* `null` or `undefined`, no document is loaded.
|
|
134
49
|
*
|
|
135
50
|
* @example
|
|
136
51
|
* ```typescript
|
|
137
|
-
* //
|
|
138
|
-
* const { data,
|
|
52
|
+
* // Static
|
|
53
|
+
* const { data, change } = usePatchesDoc('doc-123')
|
|
139
54
|
*
|
|
140
|
-
* //
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
* // When leaving:
|
|
144
|
-
* await close()
|
|
55
|
+
* // Reactive — swaps automatically
|
|
56
|
+
* const { data, change } = usePatchesDoc(() => currentId.value && `projects/${currentId.value}`)
|
|
145
57
|
* ```
|
|
146
58
|
*/
|
|
147
59
|
declare function usePatchesDoc<T extends object>(docId: string, options?: UsePatchesDocOptions): UsePatchesDocReturn<T>;
|
|
148
|
-
declare function usePatchesDoc<T extends object>(options?:
|
|
60
|
+
declare function usePatchesDoc<T extends object>(docId: MaybeRefOrGetter<string | null | undefined>, options?: UsePatchesDocOptions): UsePatchesDocReturn<T>;
|
|
149
61
|
/**
|
|
150
62
|
* Return type for usePatchesSync composable.
|
|
151
63
|
*/
|
|
152
64
|
interface UsePatchesSyncReturn {
|
|
153
|
-
/**
|
|
154
|
-
* Whether the WebSocket connection is established.
|
|
155
|
-
*/
|
|
156
65
|
connected: Ref<boolean>;
|
|
157
|
-
/**
|
|
158
|
-
* Whether documents are currently syncing with the server.
|
|
159
|
-
*/
|
|
160
66
|
syncing: Ref<boolean>;
|
|
161
|
-
/**
|
|
162
|
-
* Whether the client believes it has network connectivity.
|
|
163
|
-
*/
|
|
164
67
|
online: Ref<boolean>;
|
|
165
68
|
}
|
|
166
69
|
/**
|
|
167
70
|
* Vue composable for reactive Patches sync state.
|
|
168
71
|
*
|
|
169
|
-
* Provides reactive access to PatchesSync connection and sync status.
|
|
170
|
-
* Useful for showing "Offline" banners, global loading indicators, etc.
|
|
171
|
-
*
|
|
172
72
|
* @example
|
|
173
73
|
* ```typescript
|
|
174
74
|
* const { connected, syncing, online } = usePatchesSync()
|
|
175
|
-
*
|
|
176
|
-
* // Show offline banner
|
|
177
|
-
* if (!connected) {
|
|
178
|
-
* // Display "You are offline"
|
|
179
|
-
* }
|
|
180
75
|
* ```
|
|
181
|
-
*
|
|
182
|
-
* @returns Reactive sync state
|
|
183
|
-
* @throws Error if Patches context not provided
|
|
184
|
-
* @throws Error if PatchesSync was not provided to context
|
|
185
76
|
*/
|
|
186
77
|
declare function usePatchesSync(): UsePatchesSyncReturn;
|
|
187
78
|
/**
|
|
188
79
|
* Provides a Patches document in the component tree with a given name.
|
|
189
80
|
*
|
|
190
|
-
*
|
|
191
|
-
* without needing to pass the docId down through props. Supports both static and
|
|
192
|
-
* reactive docIds.
|
|
193
|
-
*
|
|
194
|
-
* ## Use Cases
|
|
195
|
-
*
|
|
196
|
-
* **Static document (user settings):**
|
|
81
|
+
* @example
|
|
197
82
|
* ```typescript
|
|
83
|
+
* // Static
|
|
198
84
|
* providePatchesDoc('user', 'user-123')
|
|
199
|
-
* ```
|
|
200
85
|
*
|
|
201
|
-
*
|
|
202
|
-
* ```typescript
|
|
203
|
-
* const activeTabId = ref('design-1')
|
|
204
|
-
* providePatchesDoc('whiteboard', activeTabId) // Keeps all docs open, switches between them
|
|
205
|
-
* ```
|
|
206
|
-
*
|
|
207
|
-
* **Reactive document (single-doc with autoClose: true):**
|
|
208
|
-
* ```typescript
|
|
86
|
+
* // Reactive
|
|
209
87
|
* const currentDocId = ref('doc-1')
|
|
210
|
-
* providePatchesDoc('document', currentDocId
|
|
88
|
+
* providePatchesDoc('document', currentDocId)
|
|
211
89
|
* ```
|
|
212
|
-
*
|
|
213
|
-
* @param name - Unique identifier for this document context (e.g., 'whiteboard', 'user')
|
|
214
|
-
* @param docId - Document ID (static string or reactive ref)
|
|
215
|
-
* @param options - Configuration options (autoClose, etc.)
|
|
216
|
-
*
|
|
217
|
-
* @throws Error if Patches context not provided
|
|
218
|
-
* @throws Error if doc not open in explicit mode
|
|
219
90
|
*/
|
|
220
91
|
declare function providePatchesDoc<T extends object>(name: string, docId: MaybeRef<string>, options?: UsePatchesDocOptions): UsePatchesDocReturn<T>;
|
|
221
92
|
/**
|
|
222
93
|
* Injects a Patches document provided by `providePatchesDoc`.
|
|
223
94
|
*
|
|
224
|
-
* Use this in child components to access a document provided higher up in the
|
|
225
|
-
* component tree without passing the docId through props.
|
|
226
|
-
*
|
|
227
95
|
* @example
|
|
228
96
|
* ```typescript
|
|
229
|
-
* // Parent component
|
|
230
|
-
* const whiteboardId = ref('whiteboard-123')
|
|
231
|
-
* providePatchesDoc('whiteboard', whiteboardId)
|
|
232
|
-
*
|
|
233
|
-
* // Child component (anywhere in tree)
|
|
234
97
|
* const { data, loading, change } = useCurrentDoc<WhiteboardDoc>('whiteboard')
|
|
235
98
|
* ```
|
|
236
|
-
*
|
|
237
|
-
* @param name - The name used in providePatchesDoc
|
|
238
|
-
* @returns Reactive document state and utilities
|
|
239
|
-
* @throws Error if no document provided with that name
|
|
240
99
|
*/
|
|
241
100
|
declare function useCurrentDoc<T extends object>(name: string): UsePatchesDocReturn<T>;
|
|
242
101
|
|
|
243
|
-
export { type
|
|
102
|
+
export { type UsePatchesDocOptions, type UsePatchesDocReturn, type UsePatchesSyncReturn, providePatchesDoc, useCurrentDoc, usePatchesDoc, usePatchesSync };
|