@dabble/patches 0.7.13 → 0.7.15

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.
@@ -53,7 +53,7 @@ declare class Patches {
53
53
  docId?: string;
54
54
  }) => void>;
55
55
  readonly onServerCommit: Signal<(docId: string, changes: Change[]) => void>;
56
- readonly onTrackDocs: Signal<(docIds: string[]) => void>;
56
+ readonly onTrackDocs: Signal<(docIds: string[], algorithmName: AlgorithmName) => void>;
57
57
  readonly onUntrackDocs: Signal<(docIds: string[]) => void>;
58
58
  readonly onDeleteDoc: Signal<(docId: string) => void>;
59
59
  /** Emitted when a doc has pending changes ready to send */
@@ -44,11 +44,11 @@ class Patches {
44
44
  * Extracted as a protected method so subclasses can override initialization behavior.
45
45
  */
46
46
  init() {
47
- const algorithms = Object.values(this.algorithms).filter(Boolean);
47
+ const entries = Object.entries(this.algorithms).filter(([, a]) => Boolean(a));
48
48
  Promise.all(
49
- algorithms.map(
50
- (algorithm) => algorithm.listDocs().then((docs) => {
51
- this.trackDocs(docs.map(({ docId }) => docId));
49
+ entries.map(
50
+ ([name, algorithm]) => algorithm.listDocs().then((docs) => {
51
+ this.trackDocs(docs.map(({ docId }) => docId), name);
52
52
  })
53
53
  )
54
54
  ).catch((err) => {
@@ -83,7 +83,7 @@ class Patches {
83
83
  docIds = docIds.filter((id) => !this.trackedDocs.has(id));
84
84
  if (!docIds.length) return;
85
85
  docIds.forEach(this.trackedDocs.add, this.trackedDocs);
86
- this.onTrackDocs.emit(docIds);
86
+ this.onTrackDocs.emit(docIds, algorithmName ?? this.defaultAlgorithm);
87
87
  const algorithm = this._getAlgorithm(algorithmName ?? this.defaultAlgorithm);
88
88
  await algorithm.trackDocs(docIds);
89
89
  }
@@ -202,9 +202,11 @@ function createOrderGetter(orderField) {
202
202
  function sortByOrder(items, orderField = "order") {
203
203
  const getOrder = createOrderGetter(orderField);
204
204
  return Object.entries(items).sort((a, b) => {
205
- const orderCmp = getOrder(a[1]).localeCompare(getOrder(b[1]));
205
+ const orderA = getOrder(a[1]);
206
+ const orderB = getOrder(b[1]);
207
+ const orderCmp = orderA < orderB ? -1 : orderA > orderB ? 1 : 0;
206
208
  if (orderCmp !== 0) return orderCmp;
207
- return a[0].localeCompare(b[0]);
209
+ return a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0;
208
210
  });
209
211
  }
210
212
  function healDuplicateOrders(items, orderField = "order") {
@@ -1,4 +1,5 @@
1
1
  import "../chunk-IZ2YBCUP.js";
2
+ import { escapePathComponent } from "./utils/escapePathComponent.js";
2
3
  const proxyFodder = {};
3
4
  const createPathProxy = pathProxy;
4
5
  function pathProxy(path = "") {
@@ -9,7 +10,7 @@ function pathProxy(path = "") {
9
10
  return path;
10
11
  };
11
12
  }
12
- return pathProxy(`${path}/${prop}`);
13
+ return pathProxy(`${path}/${escapePathComponent(prop)}`);
13
14
  },
14
15
  set(_, prop) {
15
16
  throw new Error(
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Escapes a single path component for use in a JSON Pointer (RFC 6901).
3
+ * `~` is escaped as `~0` and `/` is escaped as `~1`.
4
+ */
5
+ declare function escapePathComponent(component: string): string;
6
+
7
+ export { escapePathComponent };
@@ -0,0 +1,7 @@
1
+ import "../../chunk-IZ2YBCUP.js";
2
+ function escapePathComponent(component) {
3
+ return component.replace(/~/g, "~0").replace(/\//g, "~1");
4
+ }
5
+ export {
6
+ escapePathComponent
7
+ };
@@ -1,4 +1,5 @@
1
1
  export { deepEqual } from './deepEqual.js';
2
+ export { escapePathComponent } from './escapePathComponent.js';
2
3
  export { get } from './get.js';
3
4
  export { getOpData } from './getOpData.js';
4
5
  export { getType, getTypeLike } from './getType.js';
@@ -1,4 +1,5 @@
1
1
  export * from "./deepEqual.js";
2
+ export * from "./escapePathComponent.js";
2
3
  export * from "./get.js";
3
4
  export * from "./getOpData.js";
4
5
  export * from "./getType.js";
@@ -145,7 +145,7 @@ declare class PatchesSync {
145
145
  */
146
146
  protected _handleDocDeleted(docId: string): Promise<void>;
147
147
  protected _handleConnectionChange(connectionState: ConnectionState): void;
148
- protected _handleDocsTracked(docIds: string[]): Promise<void>;
148
+ protected _handleDocsTracked(docIds: string[], algorithmName?: AlgorithmName): Promise<void>;
149
149
  protected _handleDocsUntracked(docIds: string[]): Promise<void>;
150
150
  protected _handleDocChange(docId: string): Promise<void>;
151
151
  /**
@@ -377,19 +377,25 @@ class PatchesSync {
377
377
  this._resetSyncingStatuses();
378
378
  }
379
379
  }
380
- async _handleDocsTracked(docIds) {
380
+ async _handleDocsTracked(docIds, algorithmName) {
381
381
  const newIds = docIds.filter((id) => !this.trackedDocs.has(id));
382
382
  if (!newIds.length) return;
383
383
  const alreadySubscribed = this._getActiveSubscriptions();
384
384
  newIds.forEach((id) => this.trackedDocs.add(id));
385
- for (const docId of newIds) {
386
- for (const algorithm of Object.values(this.patches.algorithms)) {
387
- if (!algorithm) continue;
388
- const docs = await algorithm.listDocs(false);
389
- const tracked = docs.find((d) => d.docId === docId);
390
- if (tracked?.algorithm) {
391
- this.docAlgorithms.set(docId, tracked.algorithm);
392
- break;
385
+ if (algorithmName) {
386
+ for (const docId of newIds) {
387
+ this.docAlgorithms.set(docId, algorithmName);
388
+ }
389
+ } else {
390
+ for (const docId of newIds) {
391
+ for (const algorithm of Object.values(this.patches.algorithms)) {
392
+ if (!algorithm) continue;
393
+ const docs = await algorithm.listDocs(false);
394
+ const tracked = docs.find((d) => d.docId === docId);
395
+ if (tracked?.algorithm) {
396
+ this.docAlgorithms.set(docId, tracked.algorithm);
397
+ break;
398
+ }
393
399
  }
394
400
  }
395
401
  }
@@ -442,8 +448,7 @@ class PatchesSync {
442
448
  if (!this.trackedDocs.has(docId)) return;
443
449
  this._updateSyncedDoc(docId, { hasPending: true }, !this.state.connected);
444
450
  if (!this.state.connected) return;
445
- this._updateSyncedDoc(docId, { syncStatus: "syncing" });
446
- await this.flushDoc(docId);
451
+ await this.syncDoc(docId);
447
452
  }
448
453
  /**
449
454
  * Unified handler for remote document deletion (both real-time notifications and offline discovery).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dabble/patches",
3
- "version": "0.7.13",
3
+ "version": "0.7.15",
4
4
  "description": "Immutable JSON Patch implementation based on RFC 6902 supporting operational transformation and last-writer-wins",
5
5
  "author": "Jacob Wright <jacwright@gmail.com>",
6
6
  "bugs": {