@dabble/patches 0.7.1 → 0.7.2
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/client/IndexedDBStore.js +1 -1
- package/dist/client/LWWAlgorithm.js +3 -2
- package/dist/client/LWWDoc.d.ts +3 -1
- package/dist/client/LWWDoc.js +4 -2
- package/dist/client/Patches.d.ts +5 -0
- package/dist/client/Patches.js +16 -2
- package/dist/compression/index.js +1 -6
- package/dist/net/index.d.ts +0 -1
- package/dist/net/protocol/JSONRPCServer.js +5 -3
- package/dist/net/webrtc/WebRTCAwareness.js +2 -3
- package/dist/net/websocket/WebSocketTransport.js +5 -2
- package/dist/server/OTServer.js +1 -2
- package/dist/shared/doc-manager.d.ts +89 -0
- package/dist/shared/doc-manager.js +126 -0
- package/dist/shared/utils.d.ts +22 -0
- package/dist/shared/utils.js +22 -0
- package/dist/solid/doc-manager.d.ts +3 -81
- package/dist/solid/doc-manager.js +1 -120
- package/dist/solid/index.d.ts +4 -2
- package/dist/solid/index.js +4 -0
- package/dist/solid/managed-docs.d.ts +63 -0
- package/dist/solid/managed-docs.js +105 -0
- package/dist/solid/primitives.d.ts +73 -68
- package/dist/solid/primitives.js +111 -4
- package/dist/solid/utils.d.ts +1 -0
- package/dist/solid/utils.js +6 -0
- package/dist/vue/composables.d.ts +67 -35
- package/dist/vue/composables.js +111 -4
- package/dist/vue/doc-manager.d.ts +3 -81
- package/dist/vue/doc-manager.js +1 -120
- package/dist/vue/index.d.ts +4 -2
- package/dist/vue/index.js +4 -0
- package/dist/vue/managed-docs.d.ts +66 -0
- package/dist/vue/managed-docs.js +101 -0
- package/dist/vue/utils.d.ts +1 -0
- package/dist/vue/utils.js +6 -0
- package/package.json +1 -1
- package/dist/net/types.d.ts +0 -8
- package/dist/net/types.js +0 -0
|
@@ -26,7 +26,7 @@ class LWWAlgorithm {
|
|
|
26
26
|
const committedRev = doc?.committedRev ?? await this.store.getCommittedRev(docId);
|
|
27
27
|
const changes = [createChange(committedRev, committedRev + 1, timedOps, metadata)];
|
|
28
28
|
if (doc) {
|
|
29
|
-
doc.applyChanges(changes);
|
|
29
|
+
doc.applyChanges(changes, true);
|
|
30
30
|
}
|
|
31
31
|
return changes;
|
|
32
32
|
}
|
|
@@ -52,7 +52,8 @@ class LWWAlgorithm {
|
|
|
52
52
|
const localOps = [...sendingChange?.ops ?? [], ...pendingOps];
|
|
53
53
|
const mergedChanges = mergeServerWithLocal(serverChanges, localOps);
|
|
54
54
|
if (doc) {
|
|
55
|
-
|
|
55
|
+
const hasPending = localOps.length > 0;
|
|
56
|
+
doc.applyChanges(mergedChanges, hasPending);
|
|
56
57
|
}
|
|
57
58
|
return mergedChanges;
|
|
58
59
|
}
|
package/dist/client/LWWDoc.d.ts
CHANGED
|
@@ -49,8 +49,10 @@ declare class LWWDoc<T extends object = object> extends BaseDoc<T> {
|
|
|
49
49
|
* - `committedAt === 0`: Pending local change (marks hasPending = true)
|
|
50
50
|
*
|
|
51
51
|
* @param changes Array of changes to apply
|
|
52
|
+
* @param hasPending If provided, overrides the inferred pending state.
|
|
53
|
+
* Used by LWWAlgorithm which knows the true pending state from the store.
|
|
52
54
|
*/
|
|
53
|
-
applyChanges(changes: Change[]): void;
|
|
55
|
+
applyChanges(changes: Change[], hasPending?: boolean): void;
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
export { LWWDoc };
|
package/dist/client/LWWDoc.js
CHANGED
|
@@ -57,8 +57,10 @@ class LWWDoc extends BaseDoc {
|
|
|
57
57
|
* - `committedAt === 0`: Pending local change (marks hasPending = true)
|
|
58
58
|
*
|
|
59
59
|
* @param changes Array of changes to apply
|
|
60
|
+
* @param hasPending If provided, overrides the inferred pending state.
|
|
61
|
+
* Used by LWWAlgorithm which knows the true pending state from the store.
|
|
60
62
|
*/
|
|
61
|
-
applyChanges(changes) {
|
|
63
|
+
applyChanges(changes, hasPending) {
|
|
62
64
|
if (changes.length === 0) return;
|
|
63
65
|
for (const change of changes) {
|
|
64
66
|
for (const op of change.ops) {
|
|
@@ -75,7 +77,7 @@ class LWWDoc extends BaseDoc {
|
|
|
75
77
|
}
|
|
76
78
|
}
|
|
77
79
|
this._committedRev = lastCommittedRev;
|
|
78
|
-
this._hasPending = hasPendingChanges;
|
|
80
|
+
this._hasPending = hasPending ?? hasPendingChanges;
|
|
79
81
|
this.onUpdate.emit(this._state);
|
|
80
82
|
}
|
|
81
83
|
}
|
package/dist/client/Patches.d.ts
CHANGED
|
@@ -50,6 +50,11 @@ declare class Patches {
|
|
|
50
50
|
/** Emitted when a doc has pending changes ready to send */
|
|
51
51
|
readonly onChange: Signal<(docId: string) => void>;
|
|
52
52
|
constructor(opts: PatchesOptions);
|
|
53
|
+
/**
|
|
54
|
+
* Loads tracked docs from all registered algorithm stores.
|
|
55
|
+
* Extracted as a protected method so subclasses can override initialization behavior.
|
|
56
|
+
*/
|
|
57
|
+
protected init(): void;
|
|
53
58
|
/**
|
|
54
59
|
* Gets an algorithm by name, throwing if not found.
|
|
55
60
|
*/
|
package/dist/client/Patches.js
CHANGED
|
@@ -37,8 +37,22 @@ class Patches {
|
|
|
37
37
|
throw new Error(`Default algorithm '${this.defaultAlgorithm}' not found in algorithms map`);
|
|
38
38
|
}
|
|
39
39
|
this.docOptions = opts.docOptions ?? {};
|
|
40
|
-
this.
|
|
41
|
-
|
|
40
|
+
this.init();
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Loads tracked docs from all registered algorithm stores.
|
|
44
|
+
* Extracted as a protected method so subclasses can override initialization behavior.
|
|
45
|
+
*/
|
|
46
|
+
init() {
|
|
47
|
+
const algorithms = Object.values(this.algorithms).filter(Boolean);
|
|
48
|
+
Promise.all(
|
|
49
|
+
algorithms.map(
|
|
50
|
+
(algorithm) => algorithm.listDocs().then((docs) => {
|
|
51
|
+
this.trackDocs(docs.map(({ docId }) => docId));
|
|
52
|
+
})
|
|
53
|
+
)
|
|
54
|
+
).catch((err) => {
|
|
55
|
+
console.error("Failed to load tracked docs during initialization:", err);
|
|
42
56
|
});
|
|
43
57
|
}
|
|
44
58
|
/**
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import "../chunk-IZ2YBCUP.js";
|
|
2
|
-
import {
|
|
3
|
-
compressToBase64,
|
|
4
|
-
compressToUint8Array,
|
|
5
|
-
decompressFromBase64,
|
|
6
|
-
decompressFromUint8Array
|
|
7
|
-
} from "./lz.js";
|
|
2
|
+
import { compressToBase64, compressToUint8Array, decompressFromBase64, decompressFromUint8Array } from "./lz.js";
|
|
8
3
|
const compressedSizeBase64 = (data) => {
|
|
9
4
|
if (data === void 0) return 0;
|
|
10
5
|
try {
|
package/dist/net/index.d.ts
CHANGED
|
@@ -6,7 +6,6 @@ export { AccessLevel, ApiDefinition, ConnectionSignalSubscriber, JSONRPCServer,
|
|
|
6
6
|
export { getAuthContext, getClientId } from './serverContext.js';
|
|
7
7
|
export { AwarenessUpdateNotificationParams, ClientTransport, ConnectionState, JsonRpcNotification, JsonRpcRequest, JsonRpcResponse, ListOptions, Message, PatchesAPI, PatchesNotificationParams, ServerTransport, SignalNotificationParams } from './protocol/types.js';
|
|
8
8
|
export { rpcError, rpcNotification, rpcResponse } from './protocol/utils.js';
|
|
9
|
-
export { PatchesState, SyncingState } from './types.js';
|
|
10
9
|
export { Access, AuthContext, AuthorizationProvider, allowAll, assertNotDeleted, denyAll } from './websocket/AuthorizationProvider.js';
|
|
11
10
|
export { onlineState } from './websocket/onlineState.js';
|
|
12
11
|
export { PatchesWebSocket } from './websocket/PatchesWebSocket.js';
|
|
@@ -152,9 +152,11 @@ class JSONRPCServer {
|
|
|
152
152
|
}
|
|
153
153
|
const args = Array.isArray(params) ? params : params === void 0 ? [] : [params];
|
|
154
154
|
setAuthContext(ctx);
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
155
|
+
try {
|
|
156
|
+
return await handler(...args);
|
|
157
|
+
} finally {
|
|
158
|
+
clearAuthContext();
|
|
159
|
+
}
|
|
158
160
|
}
|
|
159
161
|
}
|
|
160
162
|
export {
|
|
@@ -64,9 +64,8 @@ class WebRTCAwareness {
|
|
|
64
64
|
* @param value - The new local awareness state to set and broadcast
|
|
65
65
|
*/
|
|
66
66
|
set localState(value) {
|
|
67
|
-
|
|
68
|
-
this._localState
|
|
69
|
-
this.transport.send(JSON.stringify(value));
|
|
67
|
+
this._localState = { ...value, id: this.myId };
|
|
68
|
+
this.transport.send(JSON.stringify(this._localState));
|
|
70
69
|
}
|
|
71
70
|
/**
|
|
72
71
|
* Handles a new peer connection by sending the local state to the new peer.
|
|
@@ -169,9 +169,12 @@ class WebSocketTransport {
|
|
|
169
169
|
if (!this.onlineUnsubscriber) {
|
|
170
170
|
this.onlineUnsubscriber = onlineState.onOnlineChange((isOnline) => {
|
|
171
171
|
if (isOnline && this.shouldBeConnected && !this.connecting && this.state !== "connected") {
|
|
172
|
-
const
|
|
172
|
+
const oldDeferred = this.connectionDeferred;
|
|
173
173
|
this.connectionDeferred = null;
|
|
174
|
-
this.connect()
|
|
174
|
+
const connectPromise = this.connect();
|
|
175
|
+
if (oldDeferred) {
|
|
176
|
+
connectPromise.then(oldDeferred.resolve, oldDeferred.reject);
|
|
177
|
+
}
|
|
175
178
|
} else if (!isOnline && this.ws) {
|
|
176
179
|
this.ws.close();
|
|
177
180
|
}
|
package/dist/server/OTServer.js
CHANGED
|
@@ -127,8 +127,7 @@ class OTServer {
|
|
|
127
127
|
async captureCurrentVersion(docId, metadata) {
|
|
128
128
|
assertVersionMetadata(metadata);
|
|
129
129
|
const { state: initialState, changes } = await getSnapshotAtRevision(this.store, docId);
|
|
130
|
-
|
|
131
|
-
state = applyChanges(state, changes);
|
|
130
|
+
const state = applyChanges(initialState, changes);
|
|
132
131
|
const version = await createVersion(this.store, docId, state, changes, metadata);
|
|
133
132
|
if (!version) {
|
|
134
133
|
return null;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { Patches } from '../client/Patches.js';
|
|
2
|
+
import { a as PatchesDoc } from '../BaseDoc-DkP3tUhT.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 '../client/PatchesStore.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Reference counting manager for PatchesDoc instances.
|
|
13
|
+
*
|
|
14
|
+
* Tracks how many components are using each document and only opens/closes
|
|
15
|
+
* documents when the reference count goes to/from zero.
|
|
16
|
+
*
|
|
17
|
+
* This prevents the footgun where multiple components open the same doc but the
|
|
18
|
+
* first one to unmount closes it for everyone else.
|
|
19
|
+
*/
|
|
20
|
+
declare class DocManager {
|
|
21
|
+
private refCounts;
|
|
22
|
+
private pendingOps;
|
|
23
|
+
/**
|
|
24
|
+
* Opens a document with reference counting.
|
|
25
|
+
*
|
|
26
|
+
* - If this is the first reference, calls patches.openDoc()
|
|
27
|
+
* - If doc is already open, returns existing instance and increments count
|
|
28
|
+
* - Handles concurrent opens to the same doc safely
|
|
29
|
+
*
|
|
30
|
+
* @param patches - Patches instance
|
|
31
|
+
* @param docId - Document ID to open
|
|
32
|
+
* @returns Promise resolving to PatchesDoc instance
|
|
33
|
+
*/
|
|
34
|
+
openDoc<T extends object>(patches: Patches, docId: string): Promise<PatchesDoc<T>>;
|
|
35
|
+
/**
|
|
36
|
+
* Closes a document with reference counting.
|
|
37
|
+
*
|
|
38
|
+
* - Decrements the reference count
|
|
39
|
+
* - Only calls patches.closeDoc() when count reaches zero
|
|
40
|
+
* - Safe to call even if doc was never opened
|
|
41
|
+
*
|
|
42
|
+
* @param patches - Patches instance
|
|
43
|
+
* @param docId - Document ID to close
|
|
44
|
+
* @param untrack - Whether to also untrack the doc when closing (default: false)
|
|
45
|
+
*/
|
|
46
|
+
closeDoc(patches: Patches, docId: string, untrack?: boolean): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Increments the reference count for a document without opening it.
|
|
49
|
+
*
|
|
50
|
+
* Used in explicit mode to track usage and prevent premature closes
|
|
51
|
+
* from autoClose mode.
|
|
52
|
+
*
|
|
53
|
+
* @param docId - Document ID
|
|
54
|
+
*/
|
|
55
|
+
incrementRefCount(docId: string): void;
|
|
56
|
+
/**
|
|
57
|
+
* Decrements the reference count for a document without closing it.
|
|
58
|
+
*
|
|
59
|
+
* Used in explicit mode to release usage tracking.
|
|
60
|
+
*
|
|
61
|
+
* @param docId - Document ID
|
|
62
|
+
*/
|
|
63
|
+
decrementRefCount(docId: string): void;
|
|
64
|
+
/**
|
|
65
|
+
* Gets the current reference count for a document.
|
|
66
|
+
*
|
|
67
|
+
* Useful for debugging or advanced use cases.
|
|
68
|
+
*
|
|
69
|
+
* @param docId - Document ID
|
|
70
|
+
* @returns Current reference count (0 if not tracked)
|
|
71
|
+
*/
|
|
72
|
+
getRefCount(docId: string): number;
|
|
73
|
+
/**
|
|
74
|
+
* Clears all reference counts without closing documents.
|
|
75
|
+
*
|
|
76
|
+
* Use with caution - this is mainly for testing or cleanup scenarios
|
|
77
|
+
* where you want to reset the manager state.
|
|
78
|
+
*/
|
|
79
|
+
reset(): void;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Gets or creates a DocManager for a Patches instance.
|
|
83
|
+
*
|
|
84
|
+
* @param patches - Patches instance
|
|
85
|
+
* @returns DocManager for this Patches instance
|
|
86
|
+
*/
|
|
87
|
+
declare function getDocManager(patches: Patches): DocManager;
|
|
88
|
+
|
|
89
|
+
export { DocManager, getDocManager };
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import "../chunk-IZ2YBCUP.js";
|
|
2
|
+
class DocManager {
|
|
3
|
+
refCounts = /* @__PURE__ */ new Map();
|
|
4
|
+
pendingOps = /* @__PURE__ */ new Map();
|
|
5
|
+
/**
|
|
6
|
+
* Opens a document with reference counting.
|
|
7
|
+
*
|
|
8
|
+
* - If this is the first reference, calls patches.openDoc()
|
|
9
|
+
* - If doc is already open, returns existing instance and increments count
|
|
10
|
+
* - Handles concurrent opens to the same doc safely
|
|
11
|
+
*
|
|
12
|
+
* @param patches - Patches instance
|
|
13
|
+
* @param docId - Document ID to open
|
|
14
|
+
* @returns Promise resolving to PatchesDoc instance
|
|
15
|
+
*/
|
|
16
|
+
async openDoc(patches, docId) {
|
|
17
|
+
const currentCount = this.refCounts.get(docId) || 0;
|
|
18
|
+
if (currentCount === 0 && this.pendingOps.has(docId)) {
|
|
19
|
+
const doc = await this.pendingOps.get(docId);
|
|
20
|
+
this.refCounts.set(docId, (this.refCounts.get(docId) || 0) + 1);
|
|
21
|
+
return doc;
|
|
22
|
+
}
|
|
23
|
+
if (currentCount > 0) {
|
|
24
|
+
this.refCounts.set(docId, currentCount + 1);
|
|
25
|
+
const doc = patches.getOpenDoc(docId);
|
|
26
|
+
if (!doc) {
|
|
27
|
+
throw new Error(`Document ${docId} has ref count ${currentCount} but is not open in Patches`);
|
|
28
|
+
}
|
|
29
|
+
return doc;
|
|
30
|
+
}
|
|
31
|
+
const openPromise = patches.openDoc(docId);
|
|
32
|
+
this.pendingOps.set(docId, openPromise);
|
|
33
|
+
try {
|
|
34
|
+
const doc = await openPromise;
|
|
35
|
+
this.refCounts.set(docId, 1);
|
|
36
|
+
return doc;
|
|
37
|
+
} catch (error) {
|
|
38
|
+
this.refCounts.delete(docId);
|
|
39
|
+
throw error;
|
|
40
|
+
} finally {
|
|
41
|
+
this.pendingOps.delete(docId);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Closes a document with reference counting.
|
|
46
|
+
*
|
|
47
|
+
* - Decrements the reference count
|
|
48
|
+
* - Only calls patches.closeDoc() when count reaches zero
|
|
49
|
+
* - Safe to call even if doc was never opened
|
|
50
|
+
*
|
|
51
|
+
* @param patches - Patches instance
|
|
52
|
+
* @param docId - Document ID to close
|
|
53
|
+
* @param untrack - Whether to also untrack the doc when closing (default: false)
|
|
54
|
+
*/
|
|
55
|
+
async closeDoc(patches, docId, untrack = false) {
|
|
56
|
+
const currentCount = this.refCounts.get(docId) || 0;
|
|
57
|
+
if (currentCount === 0) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (currentCount === 1) {
|
|
61
|
+
this.refCounts.delete(docId);
|
|
62
|
+
await patches.closeDoc(docId, { untrack });
|
|
63
|
+
} else {
|
|
64
|
+
this.refCounts.set(docId, currentCount - 1);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Increments the reference count for a document without opening it.
|
|
69
|
+
*
|
|
70
|
+
* Used in explicit mode to track usage and prevent premature closes
|
|
71
|
+
* from autoClose mode.
|
|
72
|
+
*
|
|
73
|
+
* @param docId - Document ID
|
|
74
|
+
*/
|
|
75
|
+
incrementRefCount(docId) {
|
|
76
|
+
const currentCount = this.refCounts.get(docId) || 0;
|
|
77
|
+
this.refCounts.set(docId, currentCount + 1);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Decrements the reference count for a document without closing it.
|
|
81
|
+
*
|
|
82
|
+
* Used in explicit mode to release usage tracking.
|
|
83
|
+
*
|
|
84
|
+
* @param docId - Document ID
|
|
85
|
+
*/
|
|
86
|
+
decrementRefCount(docId) {
|
|
87
|
+
const currentCount = this.refCounts.get(docId) || 0;
|
|
88
|
+
if (currentCount > 0) {
|
|
89
|
+
this.refCounts.set(docId, currentCount - 1);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Gets the current reference count for a document.
|
|
94
|
+
*
|
|
95
|
+
* Useful for debugging or advanced use cases.
|
|
96
|
+
*
|
|
97
|
+
* @param docId - Document ID
|
|
98
|
+
* @returns Current reference count (0 if not tracked)
|
|
99
|
+
*/
|
|
100
|
+
getRefCount(docId) {
|
|
101
|
+
return this.refCounts.get(docId) || 0;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Clears all reference counts without closing documents.
|
|
105
|
+
*
|
|
106
|
+
* Use with caution - this is mainly for testing or cleanup scenarios
|
|
107
|
+
* where you want to reset the manager state.
|
|
108
|
+
*/
|
|
109
|
+
reset() {
|
|
110
|
+
this.refCounts.clear();
|
|
111
|
+
this.pendingOps.clear();
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const managers = /* @__PURE__ */ new WeakMap();
|
|
115
|
+
function getDocManager(patches) {
|
|
116
|
+
let manager = managers.get(patches);
|
|
117
|
+
if (!manager) {
|
|
118
|
+
manager = new DocManager();
|
|
119
|
+
managers.set(patches, manager);
|
|
120
|
+
}
|
|
121
|
+
return manager;
|
|
122
|
+
}
|
|
123
|
+
export {
|
|
124
|
+
DocManager,
|
|
125
|
+
getDocManager
|
|
126
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves a path template by replacing `:param` placeholders with values.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```typescript
|
|
6
|
+
* fillPath('projects/:projectId/content', { projectId: 'abc' })
|
|
7
|
+
* // => 'projects/abc/content'
|
|
8
|
+
* ```
|
|
9
|
+
*
|
|
10
|
+
* @param template - Path template with `:param` placeholders
|
|
11
|
+
* @param params - Object mapping parameter names to values
|
|
12
|
+
* @returns Resolved path string
|
|
13
|
+
* @throws Error if a parameter in the template is missing from params
|
|
14
|
+
*/
|
|
15
|
+
declare function fillPath(template: string, params: Record<string, string>): string;
|
|
16
|
+
/**
|
|
17
|
+
* Compares two sets for equality.
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
20
|
+
declare function areSetsEqual(a: Set<string>, b: Set<string>): boolean;
|
|
21
|
+
|
|
22
|
+
export { areSetsEqual, fillPath };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import "../chunk-IZ2YBCUP.js";
|
|
2
|
+
function fillPath(template, params) {
|
|
3
|
+
return template.replace(/:(\w+)/g, (match, name) => {
|
|
4
|
+
const value = params[name];
|
|
5
|
+
if (value == null) {
|
|
6
|
+
throw new Error(`Missing parameter ":${name}" for path "${template}"`);
|
|
7
|
+
}
|
|
8
|
+
return value;
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
function areSetsEqual(a, b) {
|
|
12
|
+
if (a === b) return true;
|
|
13
|
+
if (a.size !== b.size) return false;
|
|
14
|
+
for (const item of a) {
|
|
15
|
+
if (!b.has(item)) return false;
|
|
16
|
+
}
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
export {
|
|
20
|
+
areSetsEqual,
|
|
21
|
+
fillPath
|
|
22
|
+
};
|
|
@@ -1,88 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
1
|
+
export { DocManager, getDocManager } from '../shared/doc-manager.js';
|
|
2
|
+
import '../client/Patches.js';
|
|
3
3
|
import '../event-signal.js';
|
|
4
4
|
import '../json-patch/types.js';
|
|
5
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
10
|
import '../client/PatchesStore.js';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Reference counting manager for PatchesDoc instances.
|
|
13
|
-
*
|
|
14
|
-
* Tracks how many Solid components are using each document and only opens/closes
|
|
15
|
-
* documents when the reference count goes to/from zero.
|
|
16
|
-
*
|
|
17
|
-
* This prevents the footgun where multiple components open the same doc but the
|
|
18
|
-
* first one to unmount closes it for everyone else.
|
|
19
|
-
*/
|
|
20
|
-
declare class DocManager {
|
|
21
|
-
private refCounts;
|
|
22
|
-
private pendingOps;
|
|
23
|
-
/**
|
|
24
|
-
* Opens a document with reference counting.
|
|
25
|
-
*
|
|
26
|
-
* - If this is the first reference, calls patches.openDoc()
|
|
27
|
-
* - If doc is already open, returns existing instance and increments count
|
|
28
|
-
* - Handles concurrent opens to the same doc safely
|
|
29
|
-
*
|
|
30
|
-
* @param patches - Patches instance
|
|
31
|
-
* @param docId - Document ID to open
|
|
32
|
-
* @returns Promise resolving to PatchesDoc instance
|
|
33
|
-
*/
|
|
34
|
-
openDoc<T extends object>(patches: Patches, docId: string): Promise<PatchesDoc<T>>;
|
|
35
|
-
/**
|
|
36
|
-
* Closes a document with reference counting.
|
|
37
|
-
*
|
|
38
|
-
* - Decrements the reference count
|
|
39
|
-
* - Only calls patches.closeDoc() when count reaches zero
|
|
40
|
-
* - Safe to call even if doc was never opened
|
|
41
|
-
*
|
|
42
|
-
* @param patches - Patches instance
|
|
43
|
-
* @param docId - Document ID to close
|
|
44
|
-
*/
|
|
45
|
-
closeDoc(patches: Patches, docId: string): Promise<void>;
|
|
46
|
-
/**
|
|
47
|
-
* Increments the reference count for a document without opening it.
|
|
48
|
-
*
|
|
49
|
-
* Used in explicit mode to track usage and prevent premature closes
|
|
50
|
-
* from autoClose mode.
|
|
51
|
-
*
|
|
52
|
-
* @param docId - Document ID
|
|
53
|
-
*/
|
|
54
|
-
incrementRefCount(docId: string): void;
|
|
55
|
-
/**
|
|
56
|
-
* Decrements the reference count for a document without closing it.
|
|
57
|
-
*
|
|
58
|
-
* Used in explicit mode to release usage tracking.
|
|
59
|
-
*
|
|
60
|
-
* @param docId - Document ID
|
|
61
|
-
*/
|
|
62
|
-
decrementRefCount(docId: string): void;
|
|
63
|
-
/**
|
|
64
|
-
* Gets the current reference count for a document.
|
|
65
|
-
*
|
|
66
|
-
* Useful for debugging or advanced use cases.
|
|
67
|
-
*
|
|
68
|
-
* @param docId - Document ID
|
|
69
|
-
* @returns Current reference count (0 if not tracked)
|
|
70
|
-
*/
|
|
71
|
-
getRefCount(docId: string): number;
|
|
72
|
-
/**
|
|
73
|
-
* Clears all reference counts without closing documents.
|
|
74
|
-
*
|
|
75
|
-
* Use with caution - this is mainly for testing or cleanup scenarios
|
|
76
|
-
* where you want to reset the manager state.
|
|
77
|
-
*/
|
|
78
|
-
reset(): void;
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Gets or creates a DocManager for a Patches instance.
|
|
82
|
-
*
|
|
83
|
-
* @param patches - Patches instance
|
|
84
|
-
* @returns DocManager for this Patches instance
|
|
85
|
-
*/
|
|
86
|
-
declare function getDocManager(patches: Patches): DocManager;
|
|
87
|
-
|
|
88
|
-
export { DocManager, getDocManager };
|
|
@@ -1,124 +1,5 @@
|
|
|
1
1
|
import "../chunk-IZ2YBCUP.js";
|
|
2
|
-
|
|
3
|
-
refCounts = /* @__PURE__ */ new Map();
|
|
4
|
-
pendingOps = /* @__PURE__ */ new Map();
|
|
5
|
-
/**
|
|
6
|
-
* Opens a document with reference counting.
|
|
7
|
-
*
|
|
8
|
-
* - If this is the first reference, calls patches.openDoc()
|
|
9
|
-
* - If doc is already open, returns existing instance and increments count
|
|
10
|
-
* - Handles concurrent opens to the same doc safely
|
|
11
|
-
*
|
|
12
|
-
* @param patches - Patches instance
|
|
13
|
-
* @param docId - Document ID to open
|
|
14
|
-
* @returns Promise resolving to PatchesDoc instance
|
|
15
|
-
*/
|
|
16
|
-
async openDoc(patches, docId) {
|
|
17
|
-
const currentCount = this.refCounts.get(docId) || 0;
|
|
18
|
-
if (currentCount === 0 && this.pendingOps.has(docId)) {
|
|
19
|
-
const doc = await this.pendingOps.get(docId);
|
|
20
|
-
this.refCounts.set(docId, (this.refCounts.get(docId) || 0) + 1);
|
|
21
|
-
return doc;
|
|
22
|
-
}
|
|
23
|
-
if (currentCount > 0) {
|
|
24
|
-
this.refCounts.set(docId, currentCount + 1);
|
|
25
|
-
const doc = patches.getOpenDoc(docId);
|
|
26
|
-
if (!doc) {
|
|
27
|
-
throw new Error(`Document ${docId} has ref count ${currentCount} but is not open in Patches`);
|
|
28
|
-
}
|
|
29
|
-
return doc;
|
|
30
|
-
}
|
|
31
|
-
const openPromise = patches.openDoc(docId);
|
|
32
|
-
this.pendingOps.set(docId, openPromise);
|
|
33
|
-
try {
|
|
34
|
-
const doc = await openPromise;
|
|
35
|
-
this.refCounts.set(docId, 1);
|
|
36
|
-
return doc;
|
|
37
|
-
} catch (error) {
|
|
38
|
-
this.refCounts.delete(docId);
|
|
39
|
-
throw error;
|
|
40
|
-
} finally {
|
|
41
|
-
this.pendingOps.delete(docId);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Closes a document with reference counting.
|
|
46
|
-
*
|
|
47
|
-
* - Decrements the reference count
|
|
48
|
-
* - Only calls patches.closeDoc() when count reaches zero
|
|
49
|
-
* - Safe to call even if doc was never opened
|
|
50
|
-
*
|
|
51
|
-
* @param patches - Patches instance
|
|
52
|
-
* @param docId - Document ID to close
|
|
53
|
-
*/
|
|
54
|
-
async closeDoc(patches, docId) {
|
|
55
|
-
const currentCount = this.refCounts.get(docId) || 0;
|
|
56
|
-
if (currentCount === 0) {
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
if (currentCount === 1) {
|
|
60
|
-
this.refCounts.delete(docId);
|
|
61
|
-
await patches.closeDoc(docId, { untrack: true });
|
|
62
|
-
} else {
|
|
63
|
-
this.refCounts.set(docId, currentCount - 1);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Increments the reference count for a document without opening it.
|
|
68
|
-
*
|
|
69
|
-
* Used in explicit mode to track usage and prevent premature closes
|
|
70
|
-
* from autoClose mode.
|
|
71
|
-
*
|
|
72
|
-
* @param docId - Document ID
|
|
73
|
-
*/
|
|
74
|
-
incrementRefCount(docId) {
|
|
75
|
-
const currentCount = this.refCounts.get(docId) || 0;
|
|
76
|
-
this.refCounts.set(docId, currentCount + 1);
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Decrements the reference count for a document without closing it.
|
|
80
|
-
*
|
|
81
|
-
* Used in explicit mode to release usage tracking.
|
|
82
|
-
*
|
|
83
|
-
* @param docId - Document ID
|
|
84
|
-
*/
|
|
85
|
-
decrementRefCount(docId) {
|
|
86
|
-
const currentCount = this.refCounts.get(docId) || 0;
|
|
87
|
-
if (currentCount > 0) {
|
|
88
|
-
this.refCounts.set(docId, currentCount - 1);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Gets the current reference count for a document.
|
|
93
|
-
*
|
|
94
|
-
* Useful for debugging or advanced use cases.
|
|
95
|
-
*
|
|
96
|
-
* @param docId - Document ID
|
|
97
|
-
* @returns Current reference count (0 if not tracked)
|
|
98
|
-
*/
|
|
99
|
-
getRefCount(docId) {
|
|
100
|
-
return this.refCounts.get(docId) || 0;
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Clears all reference counts without closing documents.
|
|
104
|
-
*
|
|
105
|
-
* Use with caution - this is mainly for testing or cleanup scenarios
|
|
106
|
-
* where you want to reset the manager state.
|
|
107
|
-
*/
|
|
108
|
-
reset() {
|
|
109
|
-
this.refCounts.clear();
|
|
110
|
-
this.pendingOps.clear();
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
const managers = /* @__PURE__ */ new WeakMap();
|
|
114
|
-
function getDocManager(patches) {
|
|
115
|
-
let manager = managers.get(patches);
|
|
116
|
-
if (!manager) {
|
|
117
|
-
manager = new DocManager();
|
|
118
|
-
managers.set(patches, manager);
|
|
119
|
-
}
|
|
120
|
-
return manager;
|
|
121
|
-
}
|
|
2
|
+
import { DocManager, getDocManager } from "../shared/doc-manager.js";
|
|
122
3
|
export {
|
|
123
4
|
DocManager,
|
|
124
5
|
getDocManager
|
package/dist/solid/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export { PatchesContextValue, PatchesProvider, PatchesProviderProps, usePatchesContext } from './context.js';
|
|
2
|
-
export { MaybeAccessor, UsePatchesDocOptions, UsePatchesDocReturn, UsePatchesSyncReturn, createPatchesDoc, usePatchesDoc, usePatchesSync } from './primitives.js';
|
|
3
|
-
export {
|
|
2
|
+
export { MaybeAccessor, PatchesDocProviderProps, UsePatchesDocLazyOptions, UsePatchesDocLazyReturn, UsePatchesDocOptions, UsePatchesDocReturn, UsePatchesSyncReturn, createPatchesDoc, usePatchesDoc, usePatchesSync } from './primitives.js';
|
|
3
|
+
export { CreateManagedDocsOptions, CreateManagedDocsReturn, createManagedDocs } from './managed-docs.js';
|
|
4
|
+
export { fillPath } from '../shared/utils.js';
|
|
5
|
+
export { DocManager, getDocManager } from '../shared/doc-manager.js';
|
|
4
6
|
import 'solid-js';
|
|
5
7
|
import '../client/Patches.js';
|
|
6
8
|
import '../event-signal.js';
|