mindcache 3.3.1 → 3.4.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.
@@ -142,7 +142,7 @@ declare class MindCache {
142
142
  private rootMap;
143
143
  private listeners;
144
144
  private globalListeners;
145
- readonly version = "3.3.1";
145
+ readonly version = "3.3.2";
146
146
  private _isRemoteUpdate;
147
147
  private normalizeSystemTags;
148
148
  private _cloudAdapter;
@@ -212,6 +212,11 @@ declare class MindCache {
212
212
  get isLoaded(): boolean;
213
213
  protected _getCloudAdapterClass(): Promise<any>;
214
214
  get isCloud(): boolean;
215
+ /**
216
+ * Browser network status. Returns true if online or in local-only mode.
217
+ * In cloud mode, this updates instantly when network status changes.
218
+ */
219
+ get isOnline(): boolean;
215
220
  waitForSync(): Promise<void>;
216
221
  disconnect(): void;
217
222
  isRemoteUpdate(): boolean;
@@ -401,11 +406,6 @@ declare class MindCache {
401
406
  * @returns Y.Text or undefined if key doesn't exist or isn't a document
402
407
  */
403
408
  get_document(key: string): Y.Text | undefined;
404
- /**
405
- * Get plain text content of a document key.
406
- * For collaborative editing, use get_document() and bind to an editor.
407
- */
408
- get_document_text(key: string): string | undefined;
409
409
  /**
410
410
  * Insert text at a position in a document key.
411
411
  */
@@ -415,15 +415,11 @@ declare class MindCache {
415
415
  */
416
416
  delete_text(key: string, index: number, length: number): void;
417
417
  /**
418
- * Replace all text in a document key.
418
+ * Replace all text in a document key (private - use set_value for public API).
419
419
  * Uses diff-based updates when changes are < diffThreshold (default 80%).
420
420
  * This preserves concurrent edits and provides better undo granularity.
421
- *
422
- * @param key - The document key
423
- * @param newText - The new text content
424
- * @param diffThreshold - Percentage (0-1) of change above which full replace is used (default: 0.8)
425
421
  */
426
- replace_document_text(key: string, newText: string, diffThreshold?: number): void;
422
+ private _replaceDocumentText;
427
423
  subscribe(key: string, listener: Listener): () => void;
428
424
  subscribeToAll(listener: GlobalListener): () => void;
429
425
  unsubscribeFromAll(listener: GlobalListener): void;
@@ -498,6 +494,8 @@ interface CloudAdapterEvents {
498
494
  disconnected: () => void;
499
495
  error: (error: Error) => void;
500
496
  synced: () => void;
497
+ network_online: () => void;
498
+ network_offline: () => void;
501
499
  }
502
500
 
503
501
  declare class CloudAdapter {
@@ -508,9 +506,16 @@ declare class CloudAdapter {
508
506
  private reconnectAttempts;
509
507
  private reconnectTimeout;
510
508
  private _state;
509
+ private _isOnline;
511
510
  private listeners;
512
511
  private token;
512
+ private handleOnline;
513
+ private handleOffline;
513
514
  constructor(config: CloudConfig);
515
+ /** Browser network status - instantly updated via navigator.onLine */
516
+ get isOnline(): boolean;
517
+ private setupNetworkDetection;
518
+ private cleanupNetworkDetection;
514
519
  setToken(token: string): void;
515
520
  setTokenProvider(provider: () => Promise<string>): void;
516
521
  get state(): ConnectionState;
@@ -142,7 +142,7 @@ declare class MindCache {
142
142
  private rootMap;
143
143
  private listeners;
144
144
  private globalListeners;
145
- readonly version = "3.3.1";
145
+ readonly version = "3.3.2";
146
146
  private _isRemoteUpdate;
147
147
  private normalizeSystemTags;
148
148
  private _cloudAdapter;
@@ -212,6 +212,11 @@ declare class MindCache {
212
212
  get isLoaded(): boolean;
213
213
  protected _getCloudAdapterClass(): Promise<any>;
214
214
  get isCloud(): boolean;
215
+ /**
216
+ * Browser network status. Returns true if online or in local-only mode.
217
+ * In cloud mode, this updates instantly when network status changes.
218
+ */
219
+ get isOnline(): boolean;
215
220
  waitForSync(): Promise<void>;
216
221
  disconnect(): void;
217
222
  isRemoteUpdate(): boolean;
@@ -401,11 +406,6 @@ declare class MindCache {
401
406
  * @returns Y.Text or undefined if key doesn't exist or isn't a document
402
407
  */
403
408
  get_document(key: string): Y.Text | undefined;
404
- /**
405
- * Get plain text content of a document key.
406
- * For collaborative editing, use get_document() and bind to an editor.
407
- */
408
- get_document_text(key: string): string | undefined;
409
409
  /**
410
410
  * Insert text at a position in a document key.
411
411
  */
@@ -415,15 +415,11 @@ declare class MindCache {
415
415
  */
416
416
  delete_text(key: string, index: number, length: number): void;
417
417
  /**
418
- * Replace all text in a document key.
418
+ * Replace all text in a document key (private - use set_value for public API).
419
419
  * Uses diff-based updates when changes are < diffThreshold (default 80%).
420
420
  * This preserves concurrent edits and provides better undo granularity.
421
- *
422
- * @param key - The document key
423
- * @param newText - The new text content
424
- * @param diffThreshold - Percentage (0-1) of change above which full replace is used (default: 0.8)
425
421
  */
426
- replace_document_text(key: string, newText: string, diffThreshold?: number): void;
422
+ private _replaceDocumentText;
427
423
  subscribe(key: string, listener: Listener): () => void;
428
424
  subscribeToAll(listener: GlobalListener): () => void;
429
425
  unsubscribeFromAll(listener: GlobalListener): void;
@@ -498,6 +494,8 @@ interface CloudAdapterEvents {
498
494
  disconnected: () => void;
499
495
  error: (error: Error) => void;
500
496
  synced: () => void;
497
+ network_online: () => void;
498
+ network_offline: () => void;
501
499
  }
502
500
 
503
501
  declare class CloudAdapter {
@@ -508,9 +506,16 @@ declare class CloudAdapter {
508
506
  private reconnectAttempts;
509
507
  private reconnectTimeout;
510
508
  private _state;
509
+ private _isOnline;
511
510
  private listeners;
512
511
  private token;
512
+ private handleOnline;
513
+ private handleOffline;
513
514
  constructor(config: CloudConfig);
515
+ /** Browser network status - instantly updated via navigator.onLine */
516
+ get isOnline(): boolean;
517
+ private setupNetworkDetection;
518
+ private cleanupNetworkDetection;
514
519
  setToken(token: string): void;
515
520
  setTokenProvider(provider: () => Promise<string>): void;
516
521
  get state(): ConnectionState;
@@ -1,5 +1,5 @@
1
- import { M as MindCache, h as CloudConfig, C as CloudAdapter } from '../CloudAdapter-BgpqZE00.mjs';
2
- export { m as ClearOperation, j as CloudAdapterEvents, i as ConnectionState, l as DeleteOperation, O as Operation, k as SetOperation } from '../CloudAdapter-BgpqZE00.mjs';
1
+ import { M as MindCache, h as CloudConfig, C as CloudAdapter } from '../CloudAdapter-WvuWM4fD.mjs';
2
+ export { m as ClearOperation, j as CloudAdapterEvents, i as ConnectionState, l as DeleteOperation, O as Operation, k as SetOperation } from '../CloudAdapter-WvuWM4fD.mjs';
3
3
  import 'yjs';
4
4
 
5
5
  /**
@@ -1,5 +1,5 @@
1
- import { M as MindCache, h as CloudConfig, C as CloudAdapter } from '../CloudAdapter-BgpqZE00.js';
2
- export { m as ClearOperation, j as CloudAdapterEvents, i as ConnectionState, l as DeleteOperation, O as Operation, k as SetOperation } from '../CloudAdapter-BgpqZE00.js';
1
+ import { M as MindCache, h as CloudConfig, C as CloudAdapter } from '../CloudAdapter-WvuWM4fD.js';
2
+ export { m as ClearOperation, j as CloudAdapterEvents, i as ConnectionState, l as DeleteOperation, O as Operation, k as SetOperation } from '../CloudAdapter-WvuWM4fD.js';
3
3
  import 'yjs';
4
4
 
5
5
  /**
@@ -210,6 +210,7 @@ var init_CloudAdapter = __esm({
210
210
  if (!config.baseUrl) {
211
211
  throw new Error("MindCache Cloud: baseUrl is required. Please provide the cloud API URL in your configuration.");
212
212
  }
213
+ this.setupNetworkDetection();
213
214
  }
214
215
  ws = null;
215
216
  mindcache = null;
@@ -217,8 +218,52 @@ var init_CloudAdapter = __esm({
217
218
  reconnectAttempts = 0;
218
219
  reconnectTimeout = null;
219
220
  _state = "disconnected";
221
+ _isOnline = true;
222
+ // Browser network status
220
223
  listeners = {};
221
224
  token = null;
225
+ handleOnline = null;
226
+ handleOffline = null;
227
+ /** Browser network status - instantly updated via navigator.onLine */
228
+ get isOnline() {
229
+ return this._isOnline;
230
+ }
231
+ setupNetworkDetection() {
232
+ if (typeof window === "undefined" || typeof navigator === "undefined") {
233
+ return;
234
+ }
235
+ this._isOnline = navigator.onLine;
236
+ this.handleOnline = () => {
237
+ console.log("\u2601\uFE0F CloudAdapter: Network is back online");
238
+ this._isOnline = true;
239
+ this.emit("network_online");
240
+ if (this._state === "disconnected" || this._state === "error") {
241
+ this.connect();
242
+ }
243
+ };
244
+ this.handleOffline = () => {
245
+ console.log("\u2601\uFE0F CloudAdapter: Network went offline");
246
+ this._isOnline = false;
247
+ this.emit("network_offline");
248
+ if (this._state === "connected" || this._state === "connecting") {
249
+ this._state = "disconnected";
250
+ this.emit("disconnected");
251
+ }
252
+ };
253
+ window.addEventListener("online", this.handleOnline);
254
+ window.addEventListener("offline", this.handleOffline);
255
+ }
256
+ cleanupNetworkDetection() {
257
+ if (typeof window === "undefined") {
258
+ return;
259
+ }
260
+ if (this.handleOnline) {
261
+ window.removeEventListener("online", this.handleOnline);
262
+ }
263
+ if (this.handleOffline) {
264
+ window.removeEventListener("offline", this.handleOffline);
265
+ }
266
+ }
222
267
  setToken(token) {
223
268
  this.token = token;
224
269
  }
@@ -312,6 +357,7 @@ var init_CloudAdapter = __esm({
312
357
  this.ws.close();
313
358
  this.ws = null;
314
359
  }
360
+ this.cleanupNetworkDetection();
315
361
  this._state = "disconnected";
316
362
  this.emit("disconnected");
317
363
  }
@@ -428,7 +474,7 @@ var MindCache = class {
428
474
  listeners = {};
429
475
  globalListeners = [];
430
476
  // Metadata
431
- version = "3.3.1";
477
+ version = "3.3.2";
432
478
  // Internal flag to prevent sync loops when receiving remote updates
433
479
  // (Less critical with Yjs but kept for API compat)
434
480
  _isRemoteUpdate = false;
@@ -501,14 +547,30 @@ var MindCache = class {
501
547
  break;
502
548
  }
503
549
  }
550
+ } else {
551
+ let current = event.target;
552
+ while (current && current.parent) {
553
+ if (current.parent.parent === this.rootMap) {
554
+ for (const [key, val] of this.rootMap) {
555
+ if (val === current.parent) {
556
+ keysAffected.add(key);
557
+ break;
558
+ }
559
+ }
560
+ break;
561
+ }
562
+ current = current.parent;
563
+ }
504
564
  }
505
565
  });
506
566
  keysAffected.forEach((key) => {
507
567
  const entryMap = this.rootMap.get(key);
508
568
  if (entryMap) {
509
569
  const value = entryMap.get("value");
570
+ const attrs = entryMap.get("attributes");
571
+ const resolvedValue = attrs?.type === "document" && value instanceof Y__namespace.Text ? value.toString() : value;
510
572
  if (this.listeners[key]) {
511
- this.listeners[key].forEach((l) => l(value));
573
+ this.listeners[key].forEach((l) => l(resolvedValue));
512
574
  }
513
575
  } else {
514
576
  if (this.listeners[key]) {
@@ -638,12 +700,19 @@ var MindCache = class {
638
700
  if (event.target === this.rootMap) {
639
701
  const mapEvent = event;
640
702
  mapEvent.keysChanged.forEach((key) => keysAffected.add(key));
641
- } else if (event.target.parent === this.rootMap) {
642
- for (const [key, val] of this.rootMap) {
643
- if (val === event.target) {
644
- keysAffected.add(key);
703
+ } else {
704
+ let current = event.target;
705
+ while (current && current.parent) {
706
+ if (current.parent === this.rootMap) {
707
+ for (const [key, val] of this.rootMap) {
708
+ if (val === current) {
709
+ keysAffected.add(key);
710
+ break;
711
+ }
712
+ }
645
713
  break;
646
714
  }
715
+ current = current.parent;
647
716
  }
648
717
  }
649
718
  });
@@ -783,6 +852,19 @@ var MindCache = class {
783
852
  get isCloud() {
784
853
  return this._cloudConfig !== null;
785
854
  }
855
+ /**
856
+ * Browser network status. Returns true if online or in local-only mode.
857
+ * In cloud mode, this updates instantly when network status changes.
858
+ */
859
+ get isOnline() {
860
+ if (!this._cloudAdapter) {
861
+ if (typeof navigator !== "undefined") {
862
+ return navigator.onLine;
863
+ }
864
+ return true;
865
+ }
866
+ return this._cloudAdapter.isOnline;
867
+ }
786
868
  async waitForSync() {
787
869
  if (this._isLoaded) {
788
870
  return;
@@ -1027,11 +1109,15 @@ var MindCache = class {
1027
1109
  const existingAttrs = existingEntry.get("attributes");
1028
1110
  if (existingAttrs?.type === "document") {
1029
1111
  if (typeof value === "string") {
1030
- this.replace_document_text(key, value);
1112
+ this._replaceDocumentText(key, value);
1031
1113
  }
1032
1114
  return;
1033
1115
  }
1034
1116
  }
1117
+ if (!existingEntry && attributes?.type === "document") {
1118
+ this.set_document(key, typeof value === "string" ? value : "", attributes);
1119
+ return;
1120
+ }
1035
1121
  let entryMap = this.rootMap.get(key);
1036
1122
  const isNewEntry = !entryMap;
1037
1123
  if (isNewEntry) {
@@ -1772,14 +1858,6 @@ var MindCache = class {
1772
1858
  }
1773
1859
  return void 0;
1774
1860
  }
1775
- /**
1776
- * Get plain text content of a document key.
1777
- * For collaborative editing, use get_document() and bind to an editor.
1778
- */
1779
- get_document_text(key) {
1780
- const yText = this.get_document(key);
1781
- return yText?.toString();
1782
- }
1783
1861
  /**
1784
1862
  * Insert text at a position in a document key.
1785
1863
  */
@@ -1799,15 +1877,11 @@ var MindCache = class {
1799
1877
  }
1800
1878
  }
1801
1879
  /**
1802
- * Replace all text in a document key.
1880
+ * Replace all text in a document key (private - use set_value for public API).
1803
1881
  * Uses diff-based updates when changes are < diffThreshold (default 80%).
1804
1882
  * This preserves concurrent edits and provides better undo granularity.
1805
- *
1806
- * @param key - The document key
1807
- * @param newText - The new text content
1808
- * @param diffThreshold - Percentage (0-1) of change above which full replace is used (default: 0.8)
1809
1883
  */
1810
- replace_document_text(key, newText, diffThreshold = 0.8) {
1884
+ _replaceDocumentText(key, newText, diffThreshold = 0.8) {
1811
1885
  const yText = this.get_document(key);
1812
1886
  if (!yText) {
1813
1887
  return;
@@ -1913,7 +1987,7 @@ var MindCache = class {
1913
1987
  },
1914
1988
  execute: async ({ value }) => {
1915
1989
  if (isDocument) {
1916
- this.replace_document_text(key, value);
1990
+ this._replaceDocumentText(key, value);
1917
1991
  } else {
1918
1992
  this.set_value(key, value);
1919
1993
  }
@@ -2069,7 +2143,7 @@ var MindCache = class {
2069
2143
  switch (action) {
2070
2144
  case "write":
2071
2145
  if (isDocument) {
2072
- this.replace_document_text(key, value);
2146
+ this._replaceDocumentText(key, value);
2073
2147
  } else {
2074
2148
  this.set_value(key, value);
2075
2149
  }