@dabble/patches 0.7.23 → 0.8.0

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 (47) hide show
  1. package/dist/{BaseDoc-CD5wZQMm.d.ts → BaseDoc-BT18xPxU.d.ts} +1 -1
  2. package/dist/algorithms/ot/server/createVersion.d.ts +1 -1
  3. package/dist/algorithms/ot/shared/changeBatching.js +3 -3
  4. package/dist/client/BaseDoc.d.ts +1 -1
  5. package/dist/client/ClientAlgorithm.d.ts +1 -1
  6. package/dist/client/LWWAlgorithm.d.ts +1 -1
  7. package/dist/client/LWWDoc.d.ts +1 -1
  8. package/dist/client/OTAlgorithm.d.ts +1 -1
  9. package/dist/client/OTDoc.d.ts +1 -1
  10. package/dist/client/Patches.d.ts +1 -1
  11. package/dist/client/Patches.js +1 -0
  12. package/dist/client/PatchesDoc.d.ts +1 -1
  13. package/dist/client/factories.d.ts +1 -1
  14. package/dist/client/index.d.ts +1 -1
  15. package/dist/compression/lz.js +3 -4
  16. package/dist/index.d.ts +1 -1
  17. package/dist/json-patch/invertPatch.js +2 -1
  18. package/dist/json-patch/utils/getType.d.ts +1 -1
  19. package/dist/net/PatchesConnection.d.ts +27 -0
  20. package/dist/net/PatchesConnection.js +0 -0
  21. package/dist/net/PatchesSync.d.ts +23 -18
  22. package/dist/net/PatchesSync.js +38 -29
  23. package/dist/net/index.d.ts +5 -1
  24. package/dist/net/index.js +2 -0
  25. package/dist/net/rest/PatchesREST.d.ts +75 -0
  26. package/dist/net/rest/PatchesREST.js +234 -0
  27. package/dist/net/rest/SSEServer.d.ts +151 -0
  28. package/dist/net/rest/SSEServer.js +248 -0
  29. package/dist/net/rest/index.d.ts +12 -0
  30. package/dist/net/rest/index.js +8 -0
  31. package/dist/net/rest/utils.d.ts +14 -0
  32. package/dist/net/rest/utils.js +11 -0
  33. package/dist/net/websocket/PatchesWebSocket.d.ts +5 -1
  34. package/dist/net/websocket/PatchesWebSocket.js +8 -0
  35. package/dist/server/PatchesHistoryManager.js +2 -2
  36. package/dist/server/branchUtils.js +1 -1
  37. package/dist/shared/doc-manager.d.ts +1 -1
  38. package/dist/solid/context.d.ts +3 -4
  39. package/dist/solid/doc-manager.d.ts +1 -1
  40. package/dist/solid/index.d.ts +3 -4
  41. package/dist/solid/primitives.d.ts +1 -1
  42. package/dist/vue/composables.d.ts +1 -1
  43. package/dist/vue/doc-manager.d.ts +1 -1
  44. package/dist/vue/index.d.ts +3 -4
  45. package/dist/vue/managed-docs.d.ts +2 -2
  46. package/dist/vue/provider.d.ts +3 -4
  47. package/package.json +13 -12
@@ -237,4 +237,4 @@ declare abstract class BaseDoc<T extends object = object> extends ReadonlyStoreC
237
237
  abstract import(snapshot: PatchesSnapshot<T>): void;
238
238
  }
239
239
 
240
- export { BaseDoc as B, OTDoc as O, type PatchesDocOptions as P, type PatchesDoc as a };
240
+ export { BaseDoc as B, OTDoc as O, type PatchesDoc as P, type PatchesDocOptions as a };
@@ -1,5 +1,5 @@
1
1
  import { OTStoreBackend } from '../../../server/types.js';
2
- import { EditableVersionMetadata, VersionMetadata, Change } from '../../../types.js';
2
+ import { EditableVersionMetadata, Change, VersionMetadata } from '../../../types.js';
3
3
  import '../../../json-patch/types.js';
4
4
  import '../../../json-patch/JSONPatch.js';
5
5
  import '@dabble/delta';
@@ -7,7 +7,7 @@ function getJSONByteSize(data) {
7
7
  return stringified ? new TextEncoder().encode(stringified).length : 0;
8
8
  } catch (e) {
9
9
  console.error("Error calculating JSON size:", e);
10
- throw new Error("Error calculating JSON size: " + e);
10
+ throw new Error("Error calculating JSON size", { cause: e });
11
11
  }
12
12
  }
13
13
  function breakChanges(changes, maxBytes, sizeCalculator) {
@@ -262,14 +262,14 @@ function breakLargeValueOp(origChange, op, maxBytes, startRev, sizeCalculator) {
262
262
  chunkOp.path = op.path;
263
263
  chunkOp.appendArray = currentChunk;
264
264
  }
265
- results.push(deriveNewChange(origChange, rev++, [chunkOp]));
265
+ results.push(deriveNewChange(origChange, rev, [chunkOp]));
266
266
  }
267
267
  return results;
268
268
  }
269
269
  console.warn(
270
270
  `Warning: Single operation of type ${op.op} (path: ${op.path}) could not be split further by breakLargeValueOp despite exceeding maxBytes. Including as is.`
271
271
  );
272
- return [deriveNewChange(origChange, rev++, [op])];
272
+ return [deriveNewChange(origChange, rev, [op])];
273
273
  }
274
274
  function deriveNewChange(origChange, rev, ops) {
275
275
  const { id: _id, ops: _o, rev: _r, baseRev: _br, created: _c, batchId: _bi, ...metadata } = origChange;
@@ -1,6 +1,6 @@
1
1
  import 'easy-signal';
2
2
  import '../json-patch/types.js';
3
3
  import '../types.js';
4
- export { B as BaseDoc } from '../BaseDoc-CD5wZQMm.js';
4
+ export { B as BaseDoc } from '../BaseDoc-BT18xPxU.js';
5
5
  import '../json-patch/JSONPatch.js';
6
6
  import '@dabble/delta';
@@ -1,6 +1,6 @@
1
1
  import { JSONPatchOp } from '../json-patch/types.js';
2
2
  import { PatchesSnapshot, Change } from '../types.js';
3
- import { a as PatchesDoc } from '../BaseDoc-CD5wZQMm.js';
3
+ import { P as PatchesDoc } from '../BaseDoc-BT18xPxU.js';
4
4
  import { PatchesStore, TrackedDoc } from './PatchesStore.js';
5
5
  import '../json-patch/JSONPatch.js';
6
6
  import '@dabble/delta';
@@ -2,7 +2,7 @@ import { JSONPatchOp } from '../json-patch/types.js';
2
2
  import { PatchesSnapshot, Change } from '../types.js';
3
3
  import { ClientAlgorithm } from './ClientAlgorithm.js';
4
4
  import { LWWClientStore } from './LWWClientStore.js';
5
- import { a as PatchesDoc } from '../BaseDoc-CD5wZQMm.js';
5
+ import { P as PatchesDoc } from '../BaseDoc-BT18xPxU.js';
6
6
  import { TrackedDoc } from './PatchesStore.js';
7
7
  import '../json-patch/JSONPatch.js';
8
8
  import '@dabble/delta';
@@ -1,5 +1,5 @@
1
1
  import { PatchesSnapshot, Change } from '../types.js';
2
- import { B as BaseDoc } from '../BaseDoc-CD5wZQMm.js';
2
+ import { B as BaseDoc } from '../BaseDoc-BT18xPxU.js';
3
3
  import '../json-patch/JSONPatch.js';
4
4
  import '@dabble/delta';
5
5
  import '../json-patch/types.js';
@@ -2,7 +2,7 @@ import { JSONPatchOp } from '../json-patch/types.js';
2
2
  import { PatchesSnapshot, Change } from '../types.js';
3
3
  import { ClientAlgorithm } from './ClientAlgorithm.js';
4
4
  import { OTClientStore } from './OTClientStore.js';
5
- import { P as PatchesDocOptions, a as PatchesDoc } from '../BaseDoc-CD5wZQMm.js';
5
+ import { a as PatchesDocOptions, P as PatchesDoc } from '../BaseDoc-BT18xPxU.js';
6
6
  import { TrackedDoc } from './PatchesStore.js';
7
7
  import '../json-patch/JSONPatch.js';
8
8
  import '@dabble/delta';
@@ -1,5 +1,5 @@
1
1
  import '../types.js';
2
- export { O as OTDoc } from '../BaseDoc-CD5wZQMm.js';
2
+ export { O as OTDoc } from '../BaseDoc-BT18xPxU.js';
3
3
  import '../json-patch/JSONPatch.js';
4
4
  import '@dabble/delta';
5
5
  import '../json-patch/types.js';
@@ -3,7 +3,7 @@ import { Unsubscriber } from 'easy-signal';
3
3
  import { JSONPatchOp } from '../json-patch/types.js';
4
4
  import { Change } from '../types.js';
5
5
  import { ClientAlgorithm } from './ClientAlgorithm.js';
6
- import { P as PatchesDocOptions, a as PatchesDoc } from '../BaseDoc-CD5wZQMm.js';
6
+ import { a as PatchesDocOptions, P as PatchesDoc } from '../BaseDoc-BT18xPxU.js';
7
7
  import { AlgorithmName } from './PatchesStore.js';
8
8
  import '../json-patch/JSONPatch.js';
9
9
  import '@dabble/delta';
@@ -208,6 +208,7 @@ class Patches {
208
208
  const current = prev.then(() => this._processDocChange(docId, ops, doc, algorithm, metadata));
209
209
  this._changeQueues.set(
210
210
  docId,
211
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
211
212
  current.catch(() => {
212
213
  })
213
214
  );
@@ -1,6 +1,6 @@
1
1
  import 'easy-signal';
2
2
  import '../json-patch/types.js';
3
3
  import '../types.js';
4
- export { O as OTDoc, a as PatchesDoc, O as PatchesDocClass, P as PatchesDocOptions } from '../BaseDoc-CD5wZQMm.js';
4
+ export { O as OTDoc, P as PatchesDoc, O as PatchesDocClass, a as PatchesDocOptions } from '../BaseDoc-BT18xPxU.js';
5
5
  import '../json-patch/JSONPatch.js';
6
6
  import '@dabble/delta';
@@ -1,6 +1,6 @@
1
1
  import { AlgorithmName } from './PatchesStore.js';
2
2
  import { Patches } from './Patches.js';
3
- import { P as PatchesDocOptions } from '../BaseDoc-CD5wZQMm.js';
3
+ import { a as PatchesDocOptions } from '../BaseDoc-BT18xPxU.js';
4
4
  import '../types.js';
5
5
  import '../json-patch/JSONPatch.js';
6
6
  import '@dabble/delta';
@@ -1,4 +1,4 @@
1
- export { B as BaseDoc, O as OTDoc, a as PatchesDoc, O as PatchesDocClass, P as PatchesDocOptions } from '../BaseDoc-CD5wZQMm.js';
1
+ export { B as BaseDoc, O as OTDoc, P as PatchesDoc, O as PatchesDocClass, a as PatchesDocOptions } from '../BaseDoc-BT18xPxU.js';
2
2
  export { IndexedDBFactoryOptions, MultiAlgorithmFactoryOptions, MultiAlgorithmIndexedDBFactoryOptions, PatchesFactoryOptions, createLWWIndexedDBPatches, createLWWPatches, createMultiAlgorithmIndexedDBPatches, createMultiAlgorithmPatches, createOTIndexedDBPatches, createOTPatches } from './factories.js';
3
3
  export { IDBStoreWrapper, IDBTransactionWrapper, IndexedDBStore } from './IndexedDBStore.js';
4
4
  export { OTIndexedDBStore } from './OTIndexedDBStore.js';
@@ -93,8 +93,8 @@ function _compress(uncompressed, bitsPerChar, getCharFromInt) {
93
93
  let value;
94
94
  const context_dictionary = {};
95
95
  const context_dictionaryToCreate = {};
96
- let context_c = "";
97
- let context_wc = "";
96
+ let context_c;
97
+ let context_wc;
98
98
  let context_w = "";
99
99
  let context_enlargeIn = 2;
100
100
  let context_dictSize = 3;
@@ -264,7 +264,6 @@ function _compress(uncompressed, bitsPerChar, getCharFromInt) {
264
264
  }
265
265
  context_enlargeIn--;
266
266
  if (context_enlargeIn === 0) {
267
- context_enlargeIn = Math.pow(2, context_numBits);
268
267
  context_numBits++;
269
268
  }
270
269
  }
@@ -294,7 +293,7 @@ function _decompress(length, resetValue, getNextValue) {
294
293
  let enlargeIn = 4;
295
294
  let dictSize = 4;
296
295
  let numBits = 3;
297
- let entry = "";
296
+ let entry;
298
297
  const result = [];
299
298
  let w;
300
299
  let bits;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { Delta } from '@dabble/delta';
2
- export { B as BaseDoc, O as OTDoc, a as PatchesDoc, O as PatchesDocClass, P as PatchesDocOptions } from './BaseDoc-CD5wZQMm.js';
2
+ export { B as BaseDoc, O as OTDoc, P as PatchesDoc, O as PatchesDocClass, a as PatchesDocOptions } from './BaseDoc-BT18xPxU.js';
3
3
  export { IndexedDBFactoryOptions, MultiAlgorithmFactoryOptions, MultiAlgorithmIndexedDBFactoryOptions, PatchesFactoryOptions, createLWWIndexedDBPatches, createLWWPatches, createMultiAlgorithmIndexedDBPatches, createMultiAlgorithmPatches, createOTIndexedDBPatches, createOTPatches } from './client/factories.js';
4
4
  export { IDBStoreWrapper, IDBTransactionWrapper, IndexedDBStore } from './client/IndexedDBStore.js';
5
5
  export { OTIndexedDBStore } from './client/OTIndexedDBStore.js';
@@ -18,7 +18,8 @@ function invertPatch(object, ops, custom = {}) {
18
18
  isIndex = prop >= 0;
19
19
  } catch (err) {
20
20
  throw new Error(
21
- `Patch mismatch. This patch was not applied to the provided object and cannot be inverted. ${err.message || err}`
21
+ `Patch mismatch. This patch was not applied to the provided object and cannot be inverted. ${err.message || err}`,
22
+ { cause: err }
22
23
  );
23
24
  }
24
25
  const handler = getType(state, op)?.invert;
@@ -1,6 +1,6 @@
1
1
  import { State, JSONPatchOp, JSONPatchOpHandler } from '../types.js';
2
2
 
3
3
  declare function getType(state: State, patch: JSONPatchOp): JSONPatchOpHandler;
4
- declare function getTypeLike(state: State, patch: JSONPatchOp): "add" | "remove" | "replace" | "move" | "copy" | "test";
4
+ declare function getTypeLike(state: State, patch: JSONPatchOp): "test" | "add" | "remove" | "replace" | "copy" | "move";
5
5
 
6
6
  export { getType, getTypeLike };
@@ -0,0 +1,27 @@
1
+ import { Signal } from 'easy-signal';
2
+ import { Change, CommitChangesOptions } from '../types.js';
3
+ import { PatchesAPI, ConnectionState } from './protocol/types.js';
4
+ import '../json-patch/JSONPatch.js';
5
+ import '@dabble/delta';
6
+ import '../json-patch/types.js';
7
+
8
+ /**
9
+ * Common interface for transport connections that PatchesSync can use.
10
+ * Implemented by PatchesWebSocket (WebSocket transport) and PatchesREST (SSE + fetch transport).
11
+ */
12
+ interface PatchesConnection extends PatchesAPI {
13
+ /** The server URL. Readable and writable — setting while connected triggers reconnection. */
14
+ url: string;
15
+ /** Establish the connection to the server. */
16
+ connect(): Promise<void>;
17
+ /** Tear down the connection. */
18
+ disconnect(): void;
19
+ /** Signal emitted when the connection state changes. */
20
+ readonly onStateChange: Signal<(state: ConnectionState) => void>;
21
+ /** Signal emitted when the server pushes committed changes for a subscribed document. */
22
+ readonly onChangesCommitted: Signal<(docId: string, changes: Change[], options?: CommitChangesOptions) => void>;
23
+ /** Signal emitted when a subscribed document is deleted remotely. */
24
+ readonly onDocDeleted: Signal<(docId: string) => void>;
25
+ }
26
+
27
+ export type { PatchesConnection };
File without changes
@@ -1,20 +1,19 @@
1
1
  import * as easy_signal from 'easy-signal';
2
2
  import { ReadonlyStoreClass, Store } from 'easy-signal';
3
- import { ConnectionState } from './protocol/types.js';
4
- import { DocSyncStatus, DocSyncState, Change } from '../types.js';
5
- import { JSONRPCClient } from './protocol/JSONRPCClient.js';
6
- import { PatchesWebSocket } from './websocket/PatchesWebSocket.js';
7
- import { WebSocketOptions } from './websocket/WebSocketTransport.js';
8
3
  import { SizeCalculator } from '../algorithms/ot/shared/changeBatching.js';
9
4
  import { ClientAlgorithm } from '../client/ClientAlgorithm.js';
10
5
  import { Patches } from '../client/Patches.js';
11
6
  import { AlgorithmName } from '../client/PatchesStore.js';
7
+ import { DocSyncStatus, DocSyncState, Change } from '../types.js';
8
+ import { PatchesConnection } from './PatchesConnection.js';
9
+ import { JSONRPCClient } from './protocol/JSONRPCClient.js';
10
+ import { ConnectionState } from './protocol/types.js';
11
+ import { WebSocketOptions } from './websocket/WebSocketTransport.js';
12
+ import '../json-patch/types.js';
13
+ import '../BaseDoc-BT18xPxU.js';
12
14
  import '../json-patch/JSONPatch.js';
13
15
  import '@dabble/delta';
14
- import '../json-patch/types.js';
15
- import './PatchesClient.js';
16
16
  import '../utils/deferred.js';
17
- import '../BaseDoc-CD5wZQMm.js';
18
17
 
19
18
  interface PatchesSyncState {
20
19
  online: boolean;
@@ -24,6 +23,7 @@ interface PatchesSyncState {
24
23
  }
25
24
  interface PatchesSyncOptions {
26
25
  subscribeFilter?: (docIds: string[]) => string[];
26
+ /** WebSocket options. Only used when a URL string is passed to the constructor. */
27
27
  websocket?: WebSocketOptions;
28
28
  /** Wire batch limit for network transmission. Defaults to 1MB. */
29
29
  maxPayloadBytes?: number;
@@ -33,9 +33,12 @@ interface PatchesSyncOptions {
33
33
  sizeCalculator?: SizeCalculator;
34
34
  }
35
35
  /**
36
- * Handles WebSocket connection, document subscriptions, and syncing logic between
36
+ * Handles server connection, document subscriptions, and syncing logic between
37
37
  * the Patches instance and the server.
38
38
  *
39
+ * Accepts either a URL string (creates a WebSocket connection) or a PatchesConnection
40
+ * instance (e.g. PatchesREST for SSE + fetch).
41
+ *
39
42
  * PatchesSync is algorithm-agnostic. It delegates to algorithm methods for:
40
43
  * - Getting pending changes to send
41
44
  * - Applying server changes
@@ -43,7 +46,7 @@ interface PatchesSyncOptions {
43
46
  */
44
47
  declare class PatchesSync extends ReadonlyStoreClass<PatchesSyncState> {
45
48
  protected options?: PatchesSyncOptions | undefined;
46
- protected ws: PatchesWebSocket;
49
+ protected connection: PatchesConnection;
47
50
  protected patches: Patches;
48
51
  protected maxPayloadBytes?: number;
49
52
  protected maxStorageBytes?: number;
@@ -66,36 +69,38 @@ declare class PatchesSync extends ReadonlyStoreClass<PatchesSyncState> {
66
69
  * Provides the pending changes that were discarded so the application can handle them.
67
70
  */
68
71
  readonly onRemoteDocDeleted: easy_signal.Signal<(docId: string, pendingChanges: Change[]) => void>;
69
- constructor(patches: Patches, url: string, options?: PatchesSyncOptions | undefined);
72
+ constructor(patches: Patches, url: string, options?: PatchesSyncOptions);
73
+ constructor(patches: Patches, connection: PatchesConnection, options?: PatchesSyncOptions);
70
74
  /**
71
75
  * Gets the algorithm for a document. Uses the open doc's algorithm if available,
72
76
  * otherwise falls back to the default algorithm.
73
77
  */
74
78
  protected _getAlgorithm(docId: string): ClientAlgorithm;
75
79
  /**
76
- * Gets the URL of the WebSocket connection.
80
+ * Gets the server URL.
77
81
  */
78
82
  get url(): string;
79
83
  /**
80
- * Sets the URL of the WebSocket connection.
84
+ * Sets the server URL. Reconnects if currently connected.
81
85
  */
82
86
  set url(url: string);
83
87
  /**
84
88
  * Gets the JSON-RPC client for making custom RPC calls.
85
- * Useful for application-specific methods not part of the Patches protocol.
89
+ * Only available when using a WebSocket connection (PatchesWebSocket or PatchesClient).
90
+ * Returns undefined when using REST transport.
86
91
  */
87
- get rpc(): JSONRPCClient;
92
+ get rpc(): JSONRPCClient | undefined;
88
93
  /**
89
94
  * Updates the sync state.
90
95
  * @param update - The partial state to update.
91
96
  */
92
97
  protected updateState(update: Partial<PatchesSyncState>): void;
93
98
  /**
94
- * Connects to the WebSocket server and starts syncing if online. If not online, it will wait for online state.
99
+ * Connects to the server and starts syncing if online. If not online, it will wait for online state.
95
100
  */
96
101
  connect(): Promise<void>;
97
102
  /**
98
- * Disconnects from the WebSocket server and stops syncing.
103
+ * Disconnects from the server and stops syncing.
99
104
  */
100
105
  disconnect(): void;
101
106
  /**
@@ -155,7 +160,7 @@ declare class PatchesSync extends ReadonlyStoreClass<PatchesSyncState> {
155
160
  protected _resetSyncingStatuses(): void;
156
161
  /**
157
162
  * Applies the subscribeFilter option to a list of doc IDs, returning the subset
158
- * that should be sent to ws.subscribe/unsubscribe. Returns the full list if no filter is set.
163
+ * that should be sent to subscribe/unsubscribe. Returns the full list if no filter is set.
159
164
  */
160
165
  protected _filterSubscribeIds(docIds: string[]): string[];
161
166
  /**
@@ -13,6 +13,7 @@ import { BaseDoc } from "../client/BaseDoc.js";
13
13
  import { Patches } from "../client/Patches.js";
14
14
  import { isDocLoaded } from "../shared/utils.js";
15
15
  import { blockable } from "../utils/concurrency.js";
16
+ import { ErrorCodes, StatusError } from "./error.js";
16
17
  import { PatchesWebSocket } from "./websocket/PatchesWebSocket.js";
17
18
  import { onlineState } from "./websocket/onlineState.js";
18
19
  const EMPTY_DOC_STATE = {
@@ -22,7 +23,7 @@ const EMPTY_DOC_STATE = {
22
23
  isLoaded: false
23
24
  };
24
25
  class PatchesSync extends (_a = ReadonlyStoreClass, _syncDoc_dec = [blockable], __receiveCommittedChanges_dec = [blockable], _a) {
25
- constructor(patches, url, options) {
26
+ constructor(patches, urlOrConnection, options) {
26
27
  super({
27
28
  online: onlineState.isOnline,
28
29
  connected: false,
@@ -30,7 +31,7 @@ class PatchesSync extends (_a = ReadonlyStoreClass, _syncDoc_dec = [blockable],
30
31
  });
31
32
  this.options = options;
32
33
  __runInitializers(_init, 5, this);
33
- __publicField(this, "ws");
34
+ __publicField(this, "connection");
34
35
  __publicField(this, "patches");
35
36
  __publicField(this, "maxPayloadBytes");
36
37
  __publicField(this, "maxStorageBytes");
@@ -55,13 +56,17 @@ class PatchesSync extends (_a = ReadonlyStoreClass, _syncDoc_dec = [blockable],
55
56
  this.maxPayloadBytes = options?.maxPayloadBytes;
56
57
  this.maxStorageBytes = options?.maxStorageBytes ?? patches.docOptions?.maxStorageBytes;
57
58
  this.sizeCalculator = options?.sizeCalculator ?? patches.docOptions?.sizeCalculator;
58
- this.ws = new PatchesWebSocket(url, options?.websocket);
59
+ if (typeof urlOrConnection === "string") {
60
+ this.connection = new PatchesWebSocket(urlOrConnection, options?.websocket);
61
+ } else {
62
+ this.connection = urlOrConnection;
63
+ }
59
64
  this.docStates = store({});
60
65
  this.trackedDocs = new Set(patches.trackedDocs);
61
66
  onlineState.onOnlineChange((online) => this.updateState({ online }));
62
- this.ws.onStateChange(this._handleConnectionChange.bind(this));
63
- this.ws.onChangesCommitted(this._receiveCommittedChanges.bind(this));
64
- this.ws.onDocDeleted((docId) => this._handleRemoteDocDeleted(docId));
67
+ this.connection.onStateChange(this._handleConnectionChange.bind(this));
68
+ this.connection.onChangesCommitted(this._receiveCommittedChanges.bind(this));
69
+ this.connection.onDocDeleted((docId) => this._handleRemoteDocDeleted(docId));
65
70
  patches.onTrackDocs(this._handleDocsTracked.bind(this));
66
71
  patches.onUntrackDocs(this._handleDocsUntracked.bind(this));
67
72
  patches.onDeleteDoc(this._handleDocDeleted.bind(this));
@@ -82,27 +87,31 @@ class PatchesSync extends (_a = ReadonlyStoreClass, _syncDoc_dec = [blockable],
82
87
  return algorithm;
83
88
  }
84
89
  /**
85
- * Gets the URL of the WebSocket connection.
90
+ * Gets the server URL.
86
91
  */
87
92
  get url() {
88
- return this.ws.transport.url;
93
+ return this.connection.url;
89
94
  }
90
95
  /**
91
- * Sets the URL of the WebSocket connection.
96
+ * Sets the server URL. Reconnects if currently connected.
92
97
  */
93
98
  set url(url) {
94
- this.ws.transport.url = url;
99
+ this.connection.url = url;
95
100
  if (this.state.connected) {
96
- this.ws.disconnect();
97
- this.ws.connect();
101
+ this.connection.disconnect();
102
+ this.connection.connect();
98
103
  }
99
104
  }
100
105
  /**
101
106
  * Gets the JSON-RPC client for making custom RPC calls.
102
- * Useful for application-specific methods not part of the Patches protocol.
107
+ * Only available when using a WebSocket connection (PatchesWebSocket or PatchesClient).
108
+ * Returns undefined when using REST transport.
103
109
  */
104
110
  get rpc() {
105
- return this.ws.rpc;
111
+ if ("rpc" in this.connection) {
112
+ return this.connection.rpc;
113
+ }
114
+ return void 0;
106
115
  }
107
116
  /**
108
117
  * Updates the sync state.
@@ -118,11 +127,11 @@ class PatchesSync extends (_a = ReadonlyStoreClass, _syncDoc_dec = [blockable],
118
127
  }
119
128
  }
120
129
  /**
121
- * Connects to the WebSocket server and starts syncing if online. If not online, it will wait for online state.
130
+ * Connects to the server and starts syncing if online. If not online, it will wait for online state.
122
131
  */
123
132
  async connect() {
124
133
  try {
125
- await this.ws.connect();
134
+ await this.connection.connect();
126
135
  } catch (err) {
127
136
  console.error("PatchesSync connection failed:", err);
128
137
  const error = err instanceof Error ? err : new Error(String(err));
@@ -132,10 +141,10 @@ class PatchesSync extends (_a = ReadonlyStoreClass, _syncDoc_dec = [blockable],
132
141
  }
133
142
  }
134
143
  /**
135
- * Disconnects from the WebSocket server and stops syncing.
144
+ * Disconnects from the server and stops syncing.
136
145
  */
137
146
  disconnect() {
138
- this.ws.disconnect();
147
+ this.connection.disconnect();
139
148
  this.updateState({ connected: false, syncStatus: "unsynced" });
140
149
  this._resetSyncingStatuses();
141
150
  }
@@ -181,7 +190,7 @@ class PatchesSync extends (_a = ReadonlyStoreClass, _syncDoc_dec = [blockable],
181
190
  try {
182
191
  const subscribeIds = this._filterSubscribeIds(activeDocIds);
183
192
  if (subscribeIds.length) {
184
- await this.ws.subscribe(subscribeIds);
193
+ await this.connection.subscribe(subscribeIds);
185
194
  }
186
195
  } catch (err) {
187
196
  console.warn("Error subscribing to active docs during sync:", err);
@@ -192,7 +201,7 @@ class PatchesSync extends (_a = ReadonlyStoreClass, _syncDoc_dec = [blockable],
192
201
  const deletePromises = deletedDocs.map(async ({ docId }) => {
193
202
  try {
194
203
  console.info(`Attempting server delete for tombstoned doc: ${docId}`);
195
- await this.ws.deleteDoc(docId);
204
+ await this.connection.deleteDoc(docId);
196
205
  const algorithm = this._getAlgorithm(docId);
197
206
  await algorithm.confirmDeleteDoc(docId);
198
207
  console.info(`Successfully deleted and untracked doc: ${docId}`);
@@ -226,12 +235,12 @@ class PatchesSync extends (_a = ReadonlyStoreClass, _syncDoc_dec = [blockable],
226
235
  } else {
227
236
  const committedRev = await algorithm.getCommittedRev(docId);
228
237
  if (committedRev) {
229
- const serverChanges = await this.ws.getChangesSince(docId, committedRev);
238
+ const serverChanges = await this.connection.getChangesSince(docId, committedRev);
230
239
  if (serverChanges.length > 0) {
231
240
  await this._applyServerChangesToDoc(docId, serverChanges);
232
241
  }
233
242
  } else {
234
- const snapshot = await this.ws.getDoc(docId);
243
+ const snapshot = await this.connection.getDoc(docId);
235
244
  await algorithm.store.saveDoc(docId, snapshot);
236
245
  this._updateDocSyncState(docId, { committedRev: snapshot.rev });
237
246
  if (baseDoc) {
@@ -286,10 +295,10 @@ class PatchesSync extends (_a = ReadonlyStoreClass, _syncDoc_dec = [blockable],
286
295
  if (!this.state.connected) {
287
296
  throw new Error("Disconnected during flush");
288
297
  }
289
- const { changes: committed, docReloadRequired } = await this.ws.commitChanges(docId, changeBatch);
298
+ const { changes: committed, docReloadRequired } = await this.connection.commitChanges(docId, changeBatch);
290
299
  if (docReloadRequired) {
291
300
  await algorithm.confirmSent(docId, changeBatch);
292
- const snapshot = await this.ws.getDoc(docId);
301
+ const snapshot = await this.connection.getDoc(docId);
293
302
  await algorithm.store.saveDoc(docId, snapshot);
294
303
  this._updateDocSyncState(docId, { committedRev: snapshot.rev });
295
304
  const openDoc = this.patches.getOpenDoc(docId);
@@ -344,7 +353,7 @@ class PatchesSync extends (_a = ReadonlyStoreClass, _syncDoc_dec = [blockable],
344
353
  if (this.state.connected) {
345
354
  try {
346
355
  const algorithm = this._getAlgorithm(docId);
347
- await this.ws.deleteDoc(docId);
356
+ await this.connection.deleteDoc(docId);
348
357
  await algorithm.confirmDeleteDoc(docId);
349
358
  } catch (err) {
350
359
  console.error(`Server delete failed for doc ${docId}, will retry on reconnect/resync.`, err);
@@ -412,7 +421,7 @@ class PatchesSync extends (_a = ReadonlyStoreClass, _syncDoc_dec = [blockable],
412
421
  try {
413
422
  const subscribeIds = this._filterSubscribeIds(newIds).filter((id) => !alreadySubscribed.has(id));
414
423
  if (subscribeIds.length) {
415
- await this.ws.subscribe(subscribeIds);
424
+ await this.connection.subscribe(subscribeIds);
416
425
  }
417
426
  await Promise.all(newIds.map((id) => this.syncDoc(id)));
418
427
  } catch (err) {
@@ -433,7 +442,7 @@ class PatchesSync extends (_a = ReadonlyStoreClass, _syncDoc_dec = [blockable],
433
442
  const unsubscribeIds = [...subscribedBefore].filter((id) => !subscribedAfter.has(id));
434
443
  if (this.state.connected && unsubscribeIds.length) {
435
444
  try {
436
- await this.ws.unsubscribe(unsubscribeIds);
445
+ await this.connection.unsubscribe(unsubscribeIds);
437
446
  } catch (err) {
438
447
  console.warn(`Failed to unsubscribe docs: ${unsubscribeIds.join(", ")}`, err);
439
448
  }
@@ -504,7 +513,7 @@ class PatchesSync extends (_a = ReadonlyStoreClass, _syncDoc_dec = [blockable],
504
513
  }
505
514
  /**
506
515
  * Applies the subscribeFilter option to a list of doc IDs, returning the subset
507
- * that should be sent to ws.subscribe/unsubscribe. Returns the full list if no filter is set.
516
+ * that should be sent to subscribe/unsubscribe. Returns the full list if no filter is set.
508
517
  */
509
518
  _filterSubscribeIds(docIds) {
510
519
  return this.options?.subscribeFilter?.(docIds) || docIds;
@@ -520,7 +529,7 @@ class PatchesSync extends (_a = ReadonlyStoreClass, _syncDoc_dec = [blockable],
520
529
  * Helper to detect DOC_DELETED (410) errors from the server.
521
530
  */
522
531
  _isDocDeletedError(err) {
523
- return typeof err === "object" && err !== null && "code" in err && err.code === 410;
532
+ return err instanceof StatusError && err.code === ErrorCodes.DOC_DELETED;
524
533
  }
525
534
  }
526
535
  _init = __decoratorStart(_a);
@@ -1,6 +1,10 @@
1
1
  export { FetchTransport } from './http/FetchTransport.js';
2
2
  export { PatchesClient } from './PatchesClient.js';
3
+ export { PatchesConnection } from './PatchesConnection.js';
3
4
  export { PatchesSync, PatchesSyncOptions, PatchesSyncState } from './PatchesSync.js';
5
+ export { PatchesREST, PatchesRESTOptions } from './rest/PatchesREST.js';
6
+ export { BufferedEvent, SSEServer, SSEServerOptions } from './rest/SSEServer.js';
7
+ export { encodeDocId, normalizeIds } from './rest/utils.js';
4
8
  export { JSONRPCClient } from './protocol/JSONRPCClient.js';
5
9
  export { AccessLevel, ApiDefinition, ConnectionSignalSubscriber, JSONRPCServer, JSONRPCServerOptions, MessageHandler } from './protocol/JSONRPCServer.js';
6
10
  export { getAuthContext, getClientId } from './serverContext.js';
@@ -17,7 +21,7 @@ import 'easy-signal';
17
21
  import '../algorithms/ot/shared/changeBatching.js';
18
22
  import '../client/ClientAlgorithm.js';
19
23
  import '../json-patch/types.js';
20
- import '../BaseDoc-CD5wZQMm.js';
24
+ import '../BaseDoc-BT18xPxU.js';
21
25
  import '../client/PatchesStore.js';
22
26
  import '../client/Patches.js';
23
27
  import '../server/types.js';
package/dist/net/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  import "../chunk-IZ2YBCUP.js";
2
2
  export * from "./http/FetchTransport.js";
3
3
  export * from "./PatchesClient.js";
4
+ export * from "./PatchesConnection.js";
4
5
  export * from "./PatchesSync.js";
6
+ export * from "./rest/index.js";
5
7
  export * from "./protocol/JSONRPCClient.js";
6
8
  export * from "./protocol/JSONRPCServer.js";
7
9
  import { getAuthContext, getClientId } from "./serverContext.js";