@dabble/patches 0.7.6 → 0.7.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/{BaseDoc-DkP3tUhT.d.ts → BaseDoc-_Rsau70J.d.ts} +9 -9
  2. package/dist/algorithms/lww/consolidateOps.d.ts +1 -1
  3. package/dist/algorithms/lww/consolidateOps.js +42 -0
  4. package/dist/client/BaseDoc.d.ts +1 -1
  5. package/dist/client/BaseDoc.js +2 -2
  6. package/dist/client/ClientAlgorithm.d.ts +1 -1
  7. package/dist/client/IndexedDBStore.d.ts +11 -11
  8. package/dist/client/IndexedDBStore.js +14 -14
  9. package/dist/client/LWWAlgorithm.d.ts +1 -1
  10. package/dist/client/LWWDoc.d.ts +3 -3
  11. package/dist/client/LWWIndexedDBStore.d.ts +1 -1
  12. package/dist/client/OTAlgorithm.d.ts +1 -1
  13. package/dist/client/OTDoc.d.ts +1 -1
  14. package/dist/client/OTIndexedDBStore.d.ts +1 -1
  15. package/dist/client/Patches.d.ts +12 -6
  16. package/dist/client/PatchesDoc.d.ts +1 -1
  17. package/dist/client/factories.d.ts +1 -1
  18. package/dist/client/index.d.ts +2 -2
  19. package/dist/index.d.ts +2 -2
  20. package/dist/net/PatchesClient.d.ts +1 -1
  21. package/dist/net/PatchesClient.js +2 -2
  22. package/dist/net/PatchesSync.d.ts +1 -1
  23. package/dist/net/index.d.ts +1 -1
  24. package/dist/net/protocol/JSONRPCClient.js +2 -0
  25. package/dist/net/protocol/JSONRPCServer.js +7 -1
  26. package/dist/net/protocol/types.d.ts +1 -1
  27. package/dist/net/websocket/WebSocketServer.d.ts +4 -10
  28. package/dist/net/websocket/WebSocketServer.js +5 -9
  29. package/dist/server/LWWBranchManager.d.ts +2 -2
  30. package/dist/server/LWWBranchManager.js +3 -3
  31. package/dist/server/OTBranchManager.d.ts +1 -1
  32. package/dist/server/OTBranchManager.js +2 -2
  33. package/dist/server/branchUtils.d.ts +1 -1
  34. package/dist/server/branchUtils.js +2 -2
  35. package/dist/shared/doc-manager.d.ts +3 -3
  36. package/dist/shared/doc-manager.js +2 -2
  37. package/dist/solid/context.d.ts +1 -1
  38. package/dist/solid/doc-manager.d.ts +1 -1
  39. package/dist/solid/index.d.ts +1 -1
  40. package/dist/solid/primitives.d.ts +10 -5
  41. package/dist/solid/primitives.js +80 -132
  42. package/dist/vue/composables.d.ts +9 -4
  43. package/dist/vue/composables.js +93 -148
  44. package/dist/vue/doc-manager.d.ts +1 -1
  45. package/dist/vue/index.d.ts +1 -1
  46. package/dist/vue/managed-docs.d.ts +10 -1
  47. package/dist/vue/managed-docs.js +3 -2
  48. package/dist/vue/provider.d.ts +1 -1
  49. package/package.json +1 -1
@@ -39,19 +39,17 @@ class WebSocketServer {
39
39
  /**
40
40
  * Subscribes the client to one or more documents to receive real-time updates.
41
41
  * If a document has been deleted (tombstone exists), sends immediate docDeleted notification.
42
- * @param params - The subscription parameters
43
- * @param params.ids - Document ID or IDs to subscribe to
42
+ * @param ids - Document ID or IDs to subscribe to
44
43
  */
45
- async subscribe(params) {
44
+ async subscribe(ids) {
46
45
  const ctx = getAuthContext();
47
46
  if (!ctx?.clientId) return [];
48
- const { ids } = params;
49
47
  const allIds = Array.isArray(ids) ? ids : [ids];
50
48
  const allowed = [];
51
49
  await Promise.all(
52
50
  allIds.map(async (id) => {
53
51
  try {
54
- if (await this.auth.canAccess(ctx, id, "read", "subscribe", params)) {
52
+ if (await this.auth.canAccess(ctx, id, "read", "subscribe")) {
55
53
  allowed.push(id);
56
54
  }
57
55
  } catch (err) {
@@ -75,13 +73,11 @@ class WebSocketServer {
75
73
  }
76
74
  /**
77
75
  * Unsubscribes the client from one or more documents.
78
- * @param params - The unsubscription parameters
79
- * @param params.ids - Document ID or IDs to unsubscribe from
76
+ * @param ids - Document ID or IDs to unsubscribe from
80
77
  */
81
- async unsubscribe(params) {
78
+ async unsubscribe(ids) {
82
79
  const ctx = getAuthContext();
83
80
  if (!ctx?.clientId) return [];
84
- const { ids } = params;
85
81
  return this.transport.removeSubscription(ctx.clientId, Array.isArray(ids) ? ids : [ids]);
86
82
  }
87
83
  }
@@ -64,11 +64,11 @@ declare class LWWBranchManager implements BranchManager {
64
64
  * @param branchId - The branch document ID.
65
65
  * @param status - The status to set (defaults to 'closed').
66
66
  */
67
- closeBranch(branchId: string, status?: Exclude<BranchStatus, 'open'>): Promise<void>;
67
+ closeBranch(branchId: string, status?: Exclude<BranchStatus, 'open'> | null): Promise<void>;
68
68
  /**
69
69
  * Merges a branch back into its source document.
70
70
  *
71
- * LWW merge strategy:
71
+ * LWW merge algorithm:
72
72
  * 1. Get all ops changes made on the branch since it was created
73
73
  * 2. Apply those changes to the source document
74
74
  * 3. Timestamps automatically resolve any conflicts (later wins)
@@ -61,13 +61,13 @@ class LWWBranchManager {
61
61
  * @param branchId - The branch document ID.
62
62
  * @param status - The status to set (defaults to 'closed').
63
63
  */
64
- async closeBranch(branchId, status = "closed") {
65
- await this.store.updateBranch(branchId, { status });
64
+ async closeBranch(branchId, status) {
65
+ await this.store.updateBranch(branchId, { status: status ?? "closed" });
66
66
  }
67
67
  /**
68
68
  * Merges a branch back into its source document.
69
69
  *
70
- * LWW merge strategy:
70
+ * LWW merge algorithm:
71
71
  * 1. Get all ops changes made on the branch since it was created
72
72
  * 2. Apply those changes to the source document
73
73
  * 3. Timestamps automatically resolve any conflicts (later wins)
@@ -60,7 +60,7 @@ declare class OTBranchManager implements BranchManager {
60
60
  * @param branchId - The ID of the branch to close.
61
61
  * @param status - The status to set for the branch.
62
62
  */
63
- closeBranch(branchId: string, status?: Exclude<BranchStatus, 'open'>): Promise<void>;
63
+ closeBranch(branchId: string, status?: Exclude<BranchStatus, 'open'> | null): Promise<void>;
64
64
  /**
65
65
  * Merges changes from a branch back into its source document.
66
66
  * @param branchId - The ID of the branch document to merge.
@@ -70,8 +70,8 @@ class OTBranchManager {
70
70
  * @param branchId - The ID of the branch to close.
71
71
  * @param status - The status to set for the branch.
72
72
  */
73
- async closeBranch(branchId, status = "closed") {
74
- await this.store.updateBranch(branchId, { status });
73
+ async closeBranch(branchId, status) {
74
+ await this.store.updateBranch(branchId, { status: status ?? "closed" });
75
75
  }
76
76
  /**
77
77
  * Merges changes from a branch back into its source document.
@@ -77,6 +77,6 @@ declare function wrapMergeCommit<T>(branchId: string, sourceDocId: string, commi
77
77
  */
78
78
  declare function closeBranch(store: {
79
79
  updateBranch(branchId: string, updates: Partial<Pick<Branch, 'status' | 'name'>>): Promise<void>;
80
- }, branchId: string, status?: Exclude<BranchStatus, 'open'>): Promise<void>;
80
+ }, branchId: string, status?: Exclude<BranchStatus, 'open'> | null): Promise<void>;
81
81
 
82
82
  export { type BranchIdGenerator, type BranchLoader, assertBranchMetadata, assertBranchOpenForMerge, assertNotABranch, branchManagerApi, closeBranch, createBranchRecord, generateBranchId, wrapMergeCommit };
@@ -51,8 +51,8 @@ async function wrapMergeCommit(branchId, sourceDocId, commitFn) {
51
51
  throw new Error(`Merge failed: ${error instanceof Error ? error.message : String(error)}`);
52
52
  }
53
53
  }
54
- async function closeBranch(store, branchId, status = "closed") {
55
- await store.updateBranch(branchId, { status });
54
+ async function closeBranch(store, branchId, status) {
55
+ await store.updateBranch(branchId, { status: status ?? "closed" });
56
56
  }
57
57
  export {
58
58
  assertBranchMetadata,
@@ -1,5 +1,5 @@
1
- import { Patches } from '../client/Patches.js';
2
- import { a as PatchesDoc } from '../BaseDoc-DkP3tUhT.js';
1
+ import { Patches, OpenDocOptions } from '../client/Patches.js';
2
+ import { a as PatchesDoc } from '../BaseDoc-_Rsau70J.js';
3
3
  import '../event-signal.js';
4
4
  import '../json-patch/types.js';
5
5
  import '../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;
@@ -7,7 +7,7 @@ import '../types.js';
7
7
  import '../json-patch/JSONPatch.js';
8
8
  import '@dabble/delta';
9
9
  import '../client/ClientAlgorithm.js';
10
- import '../BaseDoc-DkP3tUhT.js';
10
+ import '../BaseDoc-_Rsau70J.js';
11
11
  import '../client/PatchesStore.js';
12
12
  import '../net/protocol/types.js';
13
13
  import '../net/protocol/JSONRPCClient.js';
@@ -6,5 +6,5 @@ import '../types.js';
6
6
  import '../json-patch/JSONPatch.js';
7
7
  import '@dabble/delta';
8
8
  import '../client/ClientAlgorithm.js';
9
- import '../BaseDoc-DkP3tUhT.js';
9
+ import '../BaseDoc-_Rsau70J.js';
10
10
  import '../client/PatchesStore.js';
@@ -11,7 +11,7 @@ import '../types.js';
11
11
  import '../json-patch/JSONPatch.js';
12
12
  import '@dabble/delta';
13
13
  import '../client/ClientAlgorithm.js';
14
- import '../BaseDoc-DkP3tUhT.js';
14
+ import '../BaseDoc-_Rsau70J.js';
15
15
  import '../client/PatchesStore.js';
16
16
  import '../net/PatchesSync.js';
17
17
  import '../net/protocol/types.js';
@@ -1,15 +1,18 @@
1
1
  import { Accessor } from 'solid-js';
2
- import { a as PatchesDoc } from '../BaseDoc-DkP3tUhT.js';
2
+ import { OpenDocOptions } from '../client/Patches.js';
3
+ import { a as PatchesDoc } from '../BaseDoc-_Rsau70J.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;
@@ -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 usePatchesDoc(docIdOrOptions, options) {
14
- if (typeof docIdOrOptions === "string" || typeof docIdOrOptions === "function") {
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(true);
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
- function change(mutator) {
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
- let currentDoc = null;
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
- currentDoc = null;
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
- function change(mutator) {
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 [doc, setDoc] = createSignal(void 0);
229
- const [data, setData] = createSignal(void 0);
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
- function change(mutator) {
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 { a as PatchesDoc } from '../BaseDoc-DkP3tUhT.js';
2
+ import { OpenDocOptions } from '../client/Patches.js';
3
+ import { a as PatchesDoc } from '../BaseDoc-_Rsau70J.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.