@dabble/patches 0.4.4 → 0.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/dist/algorithms/client/applyCommittedChanges.d.ts +8 -2
  2. package/dist/algorithms/client/applyCommittedChanges.js +30 -38
  3. package/dist/algorithms/client/batching.d.ts +8 -2
  4. package/dist/algorithms/client/batching.js +38 -37
  5. package/dist/algorithms/client/breakChange.d.ts +8 -2
  6. package/dist/algorithms/client/breakChange.js +191 -240
  7. package/dist/algorithms/client/createStateFromSnapshot.d.ts +8 -2
  8. package/dist/algorithms/client/createStateFromSnapshot.js +7 -8
  9. package/dist/algorithms/client/getJSONByteSize.d.ts +3 -1
  10. package/dist/algorithms/client/getJSONByteSize.js +12 -11
  11. package/dist/algorithms/client/makeChange.d.ts +8 -2
  12. package/dist/algorithms/client/makeChange.js +28 -36
  13. package/dist/algorithms/server/commitChanges.d.ts +9 -3
  14. package/dist/algorithms/server/commitChanges.js +69 -78
  15. package/dist/algorithms/server/createVersion.d.ts +9 -3
  16. package/dist/algorithms/server/createVersion.js +21 -27
  17. package/dist/algorithms/server/getSnapshotAtRevision.d.ts +9 -3
  18. package/dist/algorithms/server/getSnapshotAtRevision.js +27 -28
  19. package/dist/algorithms/server/getStateAtRevision.d.ts +9 -3
  20. package/dist/algorithms/server/getStateAtRevision.js +13 -17
  21. package/dist/algorithms/server/handleOfflineSessionsAndBatches.d.ts +9 -3
  22. package/dist/algorithms/server/handleOfflineSessionsAndBatches.js +60 -77
  23. package/dist/algorithms/server/transformIncomingChanges.d.ts +8 -2
  24. package/dist/algorithms/server/transformIncomingChanges.js +27 -39
  25. package/dist/algorithms/shared/applyChanges.d.ts +8 -2
  26. package/dist/algorithms/shared/applyChanges.js +11 -16
  27. package/dist/algorithms/shared/rebaseChanges.d.ts +8 -2
  28. package/dist/algorithms/shared/rebaseChanges.js +30 -49
  29. package/dist/chunk-IZ2YBCUP.js +56 -0
  30. package/dist/client/InMemoryStore.d.ts +9 -3
  31. package/dist/client/InMemoryStore.js +92 -101
  32. package/dist/client/IndexedDBStore.d.ts +9 -3
  33. package/dist/client/IndexedDBStore.js +378 -491
  34. package/dist/client/Patches.d.ts +18 -13
  35. package/dist/client/Patches.js +152 -207
  36. package/dist/client/PatchesDoc.d.ts +14 -8
  37. package/dist/client/PatchesDoc.js +147 -154
  38. package/dist/client/PatchesHistoryClient.d.ts +12 -5
  39. package/dist/client/PatchesHistoryClient.js +110 -117
  40. package/dist/client/PatchesStore.d.ts +9 -3
  41. package/dist/client/PatchesStore.js +0 -1
  42. package/dist/client/index.d.ts +12 -6
  43. package/dist/client/index.js +5 -5
  44. package/dist/data/change.d.ts +9 -3
  45. package/dist/data/change.js +23 -15
  46. package/dist/data/version.d.ts +9 -3
  47. package/dist/data/version.js +11 -15
  48. package/dist/event-signal.d.ts +7 -6
  49. package/dist/event-signal.js +24 -39
  50. package/dist/index-CvQws3AB.d.ts +36 -0
  51. package/dist/index.d.ts +27 -5
  52. package/dist/index.js +10 -4
  53. package/dist/json-patch/JSONPatch.d.ts +9 -5
  54. package/dist/json-patch/JSONPatch.js +175 -183
  55. package/dist/json-patch/applyPatch.d.ts +5 -2
  56. package/dist/json-patch/applyPatch.js +27 -35
  57. package/dist/json-patch/composePatch.d.ts +5 -2
  58. package/dist/json-patch/composePatch.js +34 -34
  59. package/dist/json-patch/createJSONPatch.d.ts +7 -2
  60. package/dist/json-patch/createJSONPatch.js +11 -38
  61. package/dist/json-patch/index.d.ts +14 -6
  62. package/dist/json-patch/index.js +20 -9
  63. package/dist/json-patch/invertPatch.d.ts +5 -2
  64. package/dist/json-patch/invertPatch.js +31 -30
  65. package/dist/json-patch/ops/add.d.ts +5 -2
  66. package/dist/json-patch/ops/add.js +53 -51
  67. package/dist/json-patch/ops/bitmask.d.ts +8 -5
  68. package/dist/json-patch/ops/bitmask.js +41 -44
  69. package/dist/json-patch/ops/copy.d.ts +5 -2
  70. package/dist/json-patch/ops/copy.js +32 -33
  71. package/dist/json-patch/ops/increment.d.ts +5 -2
  72. package/dist/json-patch/ops/increment.js +21 -20
  73. package/dist/json-patch/ops/index.d.ts +10 -21
  74. package/dist/json-patch/ops/index.js +34 -24
  75. package/dist/json-patch/ops/move.d.ts +5 -2
  76. package/dist/json-patch/ops/move.js +132 -198
  77. package/dist/json-patch/ops/remove.d.ts +5 -2
  78. package/dist/json-patch/ops/remove.js +33 -30
  79. package/dist/json-patch/ops/replace.d.ts +5 -2
  80. package/dist/json-patch/ops/replace.js +45 -43
  81. package/dist/json-patch/ops/test.d.ts +5 -2
  82. package/dist/json-patch/ops/test.js +25 -21
  83. package/dist/json-patch/ops/text.d.ts +5 -2
  84. package/dist/json-patch/ops/text.js +54 -54
  85. package/dist/json-patch/pathProxy.d.ts +9 -3
  86. package/dist/json-patch/pathProxy.js +27 -48
  87. package/dist/json-patch/state.d.ts +5 -2
  88. package/dist/json-patch/state.js +11 -7
  89. package/dist/json-patch/transformPatch.d.ts +6 -2
  90. package/dist/json-patch/transformPatch.js +21 -24
  91. package/dist/json-patch/types.d.ts +9 -7
  92. package/dist/json-patch/types.js +0 -1
  93. package/dist/json-patch/utils/deepEqual.d.ts +3 -1
  94. package/dist/json-patch/utils/deepEqual.js +32 -28
  95. package/dist/json-patch/utils/exit.d.ts +5 -2
  96. package/dist/json-patch/utils/exit.js +7 -3
  97. package/dist/json-patch/utils/get.d.ts +5 -2
  98. package/dist/json-patch/utils/get.js +8 -4
  99. package/dist/json-patch/utils/getOpData.d.ts +5 -2
  100. package/dist/json-patch/utils/getOpData.js +12 -9
  101. package/dist/json-patch/utils/getType.d.ts +6 -3
  102. package/dist/json-patch/utils/getType.js +9 -4
  103. package/dist/json-patch/utils/index.d.ts +15 -14
  104. package/dist/json-patch/utils/index.js +14 -14
  105. package/dist/json-patch/utils/log.d.ts +4 -2
  106. package/dist/json-patch/utils/log.js +8 -3
  107. package/dist/json-patch/utils/ops.d.ts +8 -5
  108. package/dist/json-patch/utils/ops.js +83 -100
  109. package/dist/json-patch/utils/paths.d.ts +12 -9
  110. package/dist/json-patch/utils/paths.js +54 -51
  111. package/dist/json-patch/utils/pluck.d.ts +8 -5
  112. package/dist/json-patch/utils/pluck.js +32 -26
  113. package/dist/json-patch/utils/shallowCopy.d.ts +3 -1
  114. package/dist/json-patch/utils/shallowCopy.js +22 -18
  115. package/dist/json-patch/utils/softWrites.d.ts +6 -3
  116. package/dist/json-patch/utils/softWrites.js +17 -16
  117. package/dist/json-patch/utils/toArrayIndex.d.ts +3 -1
  118. package/dist/json-patch/utils/toArrayIndex.js +14 -10
  119. package/dist/json-patch/utils/toKeys.d.ts +3 -1
  120. package/dist/json-patch/utils/toKeys.js +15 -11
  121. package/dist/json-patch/utils/updateArrayIndexes.d.ts +5 -2
  122. package/dist/json-patch/utils/updateArrayIndexes.js +33 -37
  123. package/dist/json-patch/utils/updateArrayPath.d.ts +5 -2
  124. package/dist/json-patch/utils/updateArrayPath.js +29 -42
  125. package/dist/net/PatchesClient.d.ts +128 -0
  126. package/dist/net/PatchesClient.js +161 -0
  127. package/dist/net/PatchesSync.d.ts +19 -9
  128. package/dist/net/PatchesSync.js +291 -386
  129. package/dist/net/error.d.ts +3 -1
  130. package/dist/net/error.js +9 -6
  131. package/dist/net/http/FetchTransport.d.ts +21 -0
  132. package/dist/net/http/FetchTransport.js +34 -0
  133. package/dist/net/index.d.ts +26 -12
  134. package/dist/net/index.js +12 -10
  135. package/dist/net/protocol/JSONRPCClient.d.ts +11 -4
  136. package/dist/net/protocol/JSONRPCClient.js +95 -103
  137. package/dist/net/protocol/JSONRPCServer.d.ts +15 -8
  138. package/dist/net/protocol/JSONRPCServer.js +101 -123
  139. package/dist/net/protocol/types.d.ts +21 -15
  140. package/dist/net/protocol/types.js +0 -1
  141. package/dist/net/protocol/utils.d.ts +12 -0
  142. package/dist/net/protocol/utils.js +15 -0
  143. package/dist/net/types.d.ts +4 -2
  144. package/dist/net/types.js +0 -1
  145. package/dist/net/webrtc/WebRTCAwareness.d.ts +14 -4
  146. package/dist/net/webrtc/WebRTCAwareness.js +111 -120
  147. package/dist/net/webrtc/WebRTCTransport.d.ts +16 -8
  148. package/dist/net/webrtc/WebRTCTransport.js +149 -157
  149. package/dist/net/webrtc/index.d.ts +10 -2
  150. package/dist/net/webrtc/index.js +2 -2
  151. package/dist/net/websocket/AuthorizationProvider.d.ts +7 -5
  152. package/dist/net/websocket/AuthorizationProvider.js +12 -17
  153. package/dist/net/websocket/PatchesWebSocket.d.ts +14 -109
  154. package/dist/net/websocket/PatchesWebSocket.js +37 -184
  155. package/dist/net/websocket/RPCServer.d.ts +19 -10
  156. package/dist/net/websocket/RPCServer.js +190 -192
  157. package/dist/net/websocket/SignalingService.d.ts +12 -32
  158. package/dist/net/websocket/SignalingService.js +126 -133
  159. package/dist/net/websocket/WebSocketServer.d.ts +17 -4
  160. package/dist/net/websocket/WebSocketServer.js +64 -72
  161. package/dist/net/websocket/WebSocketTransport.d.ts +13 -5
  162. package/dist/net/websocket/WebSocketTransport.js +178 -207
  163. package/dist/net/websocket/onlineState.d.ts +6 -3
  164. package/dist/net/websocket/onlineState.js +25 -21
  165. package/dist/server/PatchesBranchManager.d.ts +12 -5
  166. package/dist/server/PatchesBranchManager.js +132 -142
  167. package/dist/server/PatchesHistoryManager.d.ts +11 -3
  168. package/dist/server/PatchesHistoryManager.js +81 -84
  169. package/dist/server/PatchesServer.d.ts +16 -10
  170. package/dist/server/PatchesServer.js +131 -137
  171. package/dist/server/index.d.ts +7 -2
  172. package/dist/server/index.js +9 -3
  173. package/dist/server/types.d.ts +9 -3
  174. package/dist/server/types.js +0 -1
  175. package/dist/types.d.ts +49 -19
  176. package/dist/types.js +1 -1
  177. package/dist/utils/concurrency.d.ts +7 -5
  178. package/dist/utils/concurrency.js +43 -53
  179. package/dist/utils/deferred.d.ts +4 -2
  180. package/dist/utils/deferred.js +25 -21
  181. package/package.json +5 -7
@@ -1,8 +1,12 @@
1
- import { type Unsubscriber } from '../event-signal.js';
2
- import type { Change } from '../types.js';
3
- import { PatchesDoc, type PatchesDocOptions } from './PatchesDoc.js';
4
- import type { PatchesStore } from './PatchesStore.js';
5
- export interface PatchesOptions {
1
+ import { Unsubscriber, Signal } from '../event-signal.js';
2
+ import { Change } from '../types.js';
3
+ import { PatchesDocOptions, PatchesDoc } from './PatchesDoc.js';
4
+ import { PatchesStore } from './PatchesStore.js';
5
+ import '../json-patch/JSONPatch.js';
6
+ import '@dabble/delta';
7
+ import '../json-patch/types.js';
8
+
9
+ interface PatchesOptions {
6
10
  /** Persistence layer instance (e.g., new IndexedDBStore('my-db') or new InMemoryStore()). */
7
11
  store: PatchesStore;
8
12
  /** Initial metadata to attach to changes from this client (merged with per-doc metadata). */
@@ -19,20 +23,20 @@ interface ManagedDoc<T extends object> {
19
23
  * Manages document instances (`PatchesDoc`) and persistence (`PatchesStore`).
20
24
  * Can be used standalone or with PatchesSync for network synchronization.
21
25
  */
22
- export declare class Patches {
26
+ declare class Patches {
23
27
  protected options: PatchesOptions;
24
28
  protected docs: Map<string, ManagedDoc<any>>;
25
29
  readonly docOptions: PatchesDocOptions;
26
30
  readonly store: PatchesStore;
27
31
  readonly trackedDocs: Set<string>;
28
- readonly onError: import("../event-signal.js").Signal<(error: Error, context?: {
32
+ readonly onError: Signal<(error: Error, context?: {
29
33
  docId?: string;
30
34
  }) => void>;
31
- readonly onServerCommit: import("../event-signal.js").Signal<(docId: string, changes: Change[]) => void>;
32
- readonly onTrackDocs: import("../event-signal.js").Signal<(docIds: string[]) => void>;
33
- readonly onUntrackDocs: import("../event-signal.js").Signal<(docIds: string[]) => void>;
34
- readonly onDeleteDoc: import("../event-signal.js").Signal<(docId: string) => void>;
35
- readonly onChange: import("../event-signal.js").Signal<(docId: string, changes: Change[]) => void>;
35
+ readonly onServerCommit: Signal<(docId: string, changes: Change[]) => void>;
36
+ readonly onTrackDocs: Signal<(docIds: string[]) => void>;
37
+ readonly onUntrackDocs: Signal<(docIds: string[]) => void>;
38
+ readonly onDeleteDoc: Signal<(docId: string) => void>;
39
+ readonly onChange: Signal<(docId: string, changes: Change[]) => void>;
36
40
  constructor(opts: PatchesOptions);
37
41
  /**
38
42
  * Tracks the given document IDs, adding them to the set of tracked documents and notifying listeners.
@@ -91,4 +95,5 @@ export declare class Patches {
91
95
  */
92
96
  protected _savePendingChanges(docId: string, changes: Change[]): Promise<void>;
93
97
  }
94
- export {};
98
+
99
+ export { Patches, type PatchesOptions };
@@ -1,210 +1,155 @@
1
- var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
2
- var useValue = arguments.length > 2;
3
- for (var i = 0; i < initializers.length; i++) {
4
- value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
1
+ import {
2
+ __decorateElement,
3
+ __decoratorMetadata,
4
+ __decoratorStart,
5
+ __publicField,
6
+ __runInitializers
7
+ } from "../chunk-IZ2YBCUP.js";
8
+ var _openDoc_dec, _init;
9
+ import { signal } from "../event-signal.js";
10
+ import { singleInvocation } from "../utils/concurrency.js";
11
+ import { PatchesDoc } from "./PatchesDoc.js";
12
+ _openDoc_dec = [singleInvocation(true)];
13
+ class Patches {
14
+ constructor(opts) {
15
+ __runInitializers(_init, 5, this);
16
+ __publicField(this, "options");
17
+ __publicField(this, "docs", /* @__PURE__ */ new Map());
18
+ __publicField(this, "docOptions");
19
+ __publicField(this, "store");
20
+ __publicField(this, "trackedDocs", /* @__PURE__ */ new Set());
21
+ // Public signals
22
+ __publicField(this, "onError", signal());
23
+ __publicField(this, "onServerCommit", signal());
24
+ __publicField(this, "onTrackDocs", signal());
25
+ __publicField(this, "onUntrackDocs", signal());
26
+ __publicField(this, "onDeleteDoc", signal());
27
+ __publicField(this, "onChange", signal());
28
+ this.options = opts;
29
+ this.store = opts.store;
30
+ this.docOptions = opts.docOptions ?? {};
31
+ this.store.listDocs().then((docs) => {
32
+ this.trackDocs(docs.map(({ docId }) => docId));
33
+ });
34
+ }
35
+ // --- Public API Methods ---
36
+ /**
37
+ * Tracks the given document IDs, adding them to the set of tracked documents and notifying listeners.
38
+ * Tracked docs are kept in sync with the server, even when not open locally.
39
+ * This allows for background syncing and updates of unopened documents.
40
+ * @param docIds - Array of document IDs to track.
41
+ */
42
+ async trackDocs(docIds) {
43
+ docIds = docIds.filter((id) => !this.trackedDocs.has(id));
44
+ if (!docIds.length) return;
45
+ docIds.forEach(this.trackedDocs.add, this.trackedDocs);
46
+ this.onTrackDocs.emit(docIds);
47
+ await this.store.trackDocs(docIds);
48
+ }
49
+ /**
50
+ * Untracks the given document IDs, removing them from the set of tracked documents and notifying listeners.
51
+ * Untracked docs will no longer be kept in sync with the server, even if not open locally.
52
+ * Closes any open docs and removes them from the store.
53
+ * @param docIds - Array of document IDs to untrack.
54
+ */
55
+ async untrackDocs(docIds) {
56
+ docIds = docIds.filter((id) => this.trackedDocs.has(id));
57
+ if (!docIds.length) return;
58
+ docIds.forEach(this.trackedDocs.delete, this.trackedDocs);
59
+ this.onUntrackDocs.emit(docIds);
60
+ const closedPromises = docIds.filter((id) => this.docs.has(id)).map((id) => this.closeDoc(id));
61
+ await Promise.all(closedPromises);
62
+ await this.store.untrackDocs(docIds);
63
+ }
64
+ // ensure a second call to openDoc with the same docId returns the same promise while opening
65
+ async openDoc(docId, opts = {}) {
66
+ const existing = this.docs.get(docId);
67
+ if (existing) return existing.doc;
68
+ await this.trackDocs([docId]);
69
+ const snapshot = await this.store.getDoc(docId);
70
+ const initialState = snapshot?.state ?? {};
71
+ const mergedMetadata = { ...this.options.metadata, ...opts.metadata };
72
+ const doc = new PatchesDoc(initialState, mergedMetadata, this.docOptions);
73
+ doc.setId(docId);
74
+ if (snapshot) {
75
+ doc.import(snapshot);
5
76
  }
6
- return useValue ? value : void 0;
7
- };
8
- var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
9
- function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
10
- var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
11
- var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
12
- var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
13
- var _, done = false;
14
- for (var i = decorators.length - 1; i >= 0; i--) {
15
- var context = {};
16
- for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
17
- for (var p in contextIn.access) context.access[p] = contextIn.access[p];
18
- context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
19
- var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
20
- if (kind === "accessor") {
21
- if (result === void 0) continue;
22
- if (result === null || typeof result !== "object") throw new TypeError("Object expected");
23
- if (_ = accept(result.get)) descriptor.get = _;
24
- if (_ = accept(result.set)) descriptor.set = _;
25
- if (_ = accept(result.init)) initializers.unshift(_);
26
- }
27
- else if (_ = accept(result)) {
28
- if (kind === "field") initializers.unshift(_);
29
- else descriptor[key] = _;
30
- }
77
+ const unsubscribe = doc.onChange((changes) => this._savePendingChanges(docId, changes));
78
+ this.docs.set(docId, { doc, unsubscribe });
79
+ return doc;
80
+ }
81
+ /**
82
+ * Closes an open document by ID, removing listeners and optionally untracking it.
83
+ * @param docId - The document ID to close.
84
+ * @param options - Optional: set untrack to true to also untrack the doc.
85
+ */
86
+ async closeDoc(docId, { untrack = false } = {}) {
87
+ const managed = this.docs.get(docId);
88
+ if (managed) {
89
+ managed.unsubscribe();
90
+ this.docs.delete(docId);
91
+ if (untrack) {
92
+ await this.untrackDocs([docId]);
93
+ }
94
+ }
95
+ }
96
+ /**
97
+ * Deletes a document by ID, closing it if open, untracking it, and removing it from the store.
98
+ * Emits the onDeleteDoc signal.
99
+ * @param docId - The document ID to delete.
100
+ */
101
+ async deleteDoc(docId) {
102
+ if (this.docs.has(docId)) {
103
+ await this.closeDoc(docId);
104
+ }
105
+ if (this.trackedDocs.has(docId)) {
106
+ await this.untrackDocs([docId]);
107
+ }
108
+ await this.store.deleteDoc(docId);
109
+ this.onDeleteDoc.emit(docId);
110
+ }
111
+ /**
112
+ * Gets an open document instance by ID, if it exists.
113
+ * Used by PatchesSync for applying server changes to open docs.
114
+ * @param docId - The document ID to get.
115
+ * @returns The PatchesDoc instance or undefined if not open.
116
+ */
117
+ getOpenDoc(docId) {
118
+ return this.docs.get(docId)?.doc;
119
+ }
120
+ /**
121
+ * Closes all open documents and cleans up listeners and store connections.
122
+ * Should be called when shutting down the client.
123
+ */
124
+ close() {
125
+ this.docs.forEach((managed) => managed.unsubscribe());
126
+ this.docs.clear();
127
+ this.store.close();
128
+ this.onChange.clear();
129
+ this.onDeleteDoc.clear();
130
+ this.onUntrackDocs.clear();
131
+ this.onTrackDocs.clear();
132
+ this.onServerCommit.clear();
133
+ this.onError.clear();
134
+ }
135
+ /**
136
+ * Internal handler for saving pending changes to the store.
137
+ * @param docId - The document ID to save the changes for.
138
+ * @param changes - The changes to save.
139
+ */
140
+ async _savePendingChanges(docId, changes) {
141
+ try {
142
+ await this.store.savePendingChanges(docId, changes);
143
+ this.onChange.emit(docId, changes);
144
+ } catch (err) {
145
+ console.error(`Error saving pending changes for doc ${docId}:`, err);
146
+ this.onError.emit(err, { docId });
31
147
  }
32
- if (target) Object.defineProperty(target, contextIn.name, descriptor);
33
- done = true;
148
+ }
149
+ }
150
+ _init = __decoratorStart(null);
151
+ __decorateElement(_init, 1, "openDoc", _openDoc_dec, Patches);
152
+ __decoratorMetadata(_init, Patches);
153
+ export {
154
+ Patches
34
155
  };
35
- import { signal } from '../event-signal.js';
36
- import { singleInvocation } from '../utils/concurrency.js';
37
- import { PatchesDoc } from './PatchesDoc.js';
38
- /**
39
- * Main client-side entry point for the Patches library.
40
- * Manages document instances (`PatchesDoc`) and persistence (`PatchesStore`).
41
- * Can be used standalone or with PatchesSync for network synchronization.
42
- */
43
- let Patches = (() => {
44
- let _instanceExtraInitializers = [];
45
- let _openDoc_decorators;
46
- return class Patches {
47
- static {
48
- const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
49
- _openDoc_decorators = [singleInvocation(true)];
50
- __esDecorate(this, null, _openDoc_decorators, { kind: "method", name: "openDoc", static: false, private: false, access: { has: obj => "openDoc" in obj, get: obj => obj.openDoc }, metadata: _metadata }, null, _instanceExtraInitializers);
51
- if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
52
- }
53
- options = __runInitializers(this, _instanceExtraInitializers);
54
- docs = new Map();
55
- docOptions;
56
- store;
57
- trackedDocs = new Set();
58
- // Public signals
59
- onError = signal();
60
- onServerCommit = signal();
61
- onTrackDocs = signal();
62
- onUntrackDocs = signal();
63
- onDeleteDoc = signal();
64
- onChange = signal();
65
- constructor(opts) {
66
- this.options = opts;
67
- this.store = opts.store;
68
- this.docOptions = opts.docOptions ?? {};
69
- this.store.listDocs().then(docs => {
70
- this.trackDocs(docs.map(({ docId }) => docId));
71
- });
72
- }
73
- // --- Public API Methods ---
74
- /**
75
- * Tracks the given document IDs, adding them to the set of tracked documents and notifying listeners.
76
- * Tracked docs are kept in sync with the server, even when not open locally.
77
- * This allows for background syncing and updates of unopened documents.
78
- * @param docIds - Array of document IDs to track.
79
- */
80
- async trackDocs(docIds) {
81
- docIds = docIds.filter(id => !this.trackedDocs.has(id));
82
- if (!docIds.length)
83
- return;
84
- docIds.forEach(this.trackedDocs.add, this.trackedDocs);
85
- this.onTrackDocs.emit(docIds);
86
- await this.store.trackDocs(docIds);
87
- }
88
- /**
89
- * Untracks the given document IDs, removing them from the set of tracked documents and notifying listeners.
90
- * Untracked docs will no longer be kept in sync with the server, even if not open locally.
91
- * Closes any open docs and removes them from the store.
92
- * @param docIds - Array of document IDs to untrack.
93
- */
94
- async untrackDocs(docIds) {
95
- docIds = docIds.filter(id => this.trackedDocs.has(id));
96
- if (!docIds.length)
97
- return;
98
- docIds.forEach(this.trackedDocs.delete, this.trackedDocs);
99
- this.onUntrackDocs.emit(docIds);
100
- // Close any open PatchesDoc instances first
101
- const closedPromises = docIds.filter(id => this.docs.has(id)).map(id => this.closeDoc(id)); // closeDoc removes from this.docs map
102
- await Promise.all(closedPromises);
103
- // Remove from store
104
- await this.store.untrackDocs(docIds);
105
- }
106
- /**
107
- * Opens a document by ID, loading its state from the store and setting up change listeners.
108
- * If the doc is already open, returns the existing instance.
109
- * @param docId - The document ID to open.
110
- * @param opts - Optional metadata to merge with the doc's metadata.
111
- * @returns The opened PatchesDoc instance.
112
- */
113
- async openDoc(docId, opts = {}) {
114
- const existing = this.docs.get(docId);
115
- if (existing)
116
- return existing.doc;
117
- // Ensure the doc is tracked before proceeding
118
- await this.trackDocs([docId]);
119
- // Load initial state from store
120
- const snapshot = await this.store.getDoc(docId);
121
- const initialState = (snapshot?.state ?? {});
122
- const mergedMetadata = { ...this.options.metadata, ...opts.metadata };
123
- const doc = new PatchesDoc(initialState, mergedMetadata, this.docOptions);
124
- doc.setId(docId);
125
- if (snapshot) {
126
- doc.import(snapshot);
127
- }
128
- // Set up local listener -> store
129
- const unsubscribe = doc.onChange(changes => this._savePendingChanges(docId, changes));
130
- this.docs.set(docId, { doc, unsubscribe });
131
- return doc;
132
- }
133
- /**
134
- * Closes an open document by ID, removing listeners and optionally untracking it.
135
- * @param docId - The document ID to close.
136
- * @param options - Optional: set untrack to true to also untrack the doc.
137
- */
138
- async closeDoc(docId, { untrack = false } = {}) {
139
- const managed = this.docs.get(docId);
140
- if (managed) {
141
- managed.unsubscribe();
142
- this.docs.delete(docId);
143
- if (untrack) {
144
- await this.untrackDocs([docId]);
145
- }
146
- }
147
- }
148
- /**
149
- * Deletes a document by ID, closing it if open, untracking it, and removing it from the store.
150
- * Emits the onDeleteDoc signal.
151
- * @param docId - The document ID to delete.
152
- */
153
- async deleteDoc(docId) {
154
- // Close if open locally
155
- if (this.docs.has(docId)) {
156
- await this.closeDoc(docId);
157
- }
158
- // Unsubscribe from server if tracked (deletes the doc from the store before the next step adds a tombstone)
159
- if (this.trackedDocs.has(docId)) {
160
- await this.untrackDocs([docId]);
161
- }
162
- // Mark document as deleted in store (adds a tombstone until sync commits it)
163
- await this.store.deleteDoc(docId);
164
- this.onDeleteDoc.emit(docId);
165
- }
166
- /**
167
- * Gets an open document instance by ID, if it exists.
168
- * Used by PatchesSync for applying server changes to open docs.
169
- * @param docId - The document ID to get.
170
- * @returns The PatchesDoc instance or undefined if not open.
171
- */
172
- getOpenDoc(docId) {
173
- return this.docs.get(docId)?.doc;
174
- }
175
- /**
176
- * Closes all open documents and cleans up listeners and store connections.
177
- * Should be called when shutting down the client.
178
- */
179
- close() {
180
- // Clean up local PatchesDoc listeners
181
- this.docs.forEach(managed => managed.unsubscribe());
182
- this.docs.clear();
183
- // Close store connection
184
- this.store.close();
185
- this.onChange.clear();
186
- this.onDeleteDoc.clear();
187
- this.onUntrackDocs.clear();
188
- this.onTrackDocs.clear();
189
- this.onServerCommit.clear();
190
- this.onError.clear();
191
- }
192
- /**
193
- * Internal handler for saving pending changes to the store.
194
- * @param docId - The document ID to save the changes for.
195
- * @param changes - The changes to save.
196
- */
197
- async _savePendingChanges(docId, changes) {
198
- try {
199
- await this.store.savePendingChanges(docId, changes);
200
- // Only after it is persisted, emit the change (for PatchesSync to flush)
201
- this.onChange.emit(docId, changes);
202
- }
203
- catch (err) {
204
- console.error(`Error saving pending changes for doc ${docId}:`, err);
205
- this.onError.emit(err, { docId });
206
- }
207
- }
208
- };
209
- })();
210
- export { Patches };
@@ -1,9 +1,13 @@
1
- import { type Unsubscriber } from '../event-signal.js';
2
- import type { Change, ChangeMutator, PatchesSnapshot, SyncingState } from '../types.js';
1
+ import { Signal, Unsubscriber } from '../event-signal.js';
2
+ import { PatchesSnapshot, SyncingState, Change, ChangeMutator } from '../types.js';
3
+ import '../json-patch/JSONPatch.js';
4
+ import '@dabble/delta';
5
+ import '../json-patch/types.js';
6
+
3
7
  /**
4
8
  * Options for creating a PatchesDoc instance
5
9
  */
6
- export interface PatchesDocOptions {
10
+ interface PatchesDocOptions {
7
11
  /**
8
12
  * Maximum size in bytes for a single payload (network message).
9
13
  * Changes exceeding this will be split into multiple smaller changes.
@@ -15,7 +19,7 @@ export interface PatchesDocOptions {
15
19
  * Manages committed state, pending (local-only) changes, and
16
20
  * changes currently being sent to the server.
17
21
  */
18
- export declare class PatchesDoc<T extends object = object> {
22
+ declare class PatchesDoc<T extends object = object> {
19
23
  protected _id: string | null;
20
24
  protected _state: T;
21
25
  protected _snapshot: PatchesSnapshot<T>;
@@ -23,13 +27,13 @@ export declare class PatchesDoc<T extends object = object> {
23
27
  protected _syncing: SyncingState;
24
28
  protected readonly _maxPayloadBytes?: number;
25
29
  /** Subscribe to be notified before local state changes. */
26
- readonly onBeforeChange: import("../event-signal.js").Signal<(change: Change) => void>;
30
+ readonly onBeforeChange: Signal<(change: Change) => void>;
27
31
  /** Subscribe to be notified after local state changes are applied. */
28
- readonly onChange: import("../event-signal.js").Signal<(changes: Change[]) => void>;
32
+ readonly onChange: Signal<(changes: Change[]) => void>;
29
33
  /** Subscribe to be notified whenever state changes from any source. */
30
- readonly onUpdate: import("../event-signal.js").Signal<(newState: T) => void>;
34
+ readonly onUpdate: Signal<(newState: T) => void>;
31
35
  /** Subscribe to be notified when syncing state changes. */
32
- readonly onSyncing: import("../event-signal.js").Signal<(newSyncing: SyncingState) => void>;
36
+ readonly onSyncing: Signal<(newSyncing: SyncingState) => void>;
33
37
  /**
34
38
  * Creates an instance of PatchesDoc.
35
39
  * @param initialState Optional initial state.
@@ -95,3 +99,5 @@ export declare class PatchesDoc<T extends object = object> {
95
99
  updateSyncing(newSyncing: SyncingState): void;
96
100
  toJSON(): PatchesSnapshot<T>;
97
101
  }
102
+
103
+ export { PatchesDoc, type PatchesDocOptions };