@prabhask5/stellar-engine 1.0.19 → 1.1.1

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.
@@ -0,0 +1,35 @@
1
+ /**
2
+ * CRDT Awareness (Presence) Management
3
+ *
4
+ * Manages Yjs Awareness protocol for user presence indicators
5
+ * (cursor positions, active users, etc.) via Supabase broadcast.
6
+ */
7
+ import { Awareness } from 'y-protocols/awareness';
8
+ import type { AwarenessUser } from './types';
9
+ /**
10
+ * Initialize awareness (presence) for a CRDT document.
11
+ *
12
+ * Creates an Awareness instance and sets up a dedicated broadcast channel
13
+ * for syncing presence state between clients.
14
+ *
15
+ * @param docId - Document/note ID
16
+ * @param userInfo - Current user's display info
17
+ * @returns The Awareness instance
18
+ */
19
+ export declare function initAwareness(docId: string, userInfo: AwarenessUser): Awareness;
20
+ /**
21
+ * Get the awareness instance for a document.
22
+ *
23
+ * @param docId - Document/note ID
24
+ * @returns The Awareness instance if initialized, undefined otherwise
25
+ */
26
+ export declare function getAwareness(docId: string): Awareness | undefined;
27
+ /**
28
+ * Destroy awareness for a document.
29
+ *
30
+ * Removes awareness state, closes the broadcast channel, and cleans up listeners.
31
+ *
32
+ * @param docId - Document/note ID
33
+ */
34
+ export declare function destroyAwareness(docId: string): Promise<void>;
35
+ //# sourceMappingURL=awareness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"awareness.d.ts","sourceRoot":"","sources":["../../src/crdt/awareness.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAOlD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AA2B7C;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,SAAS,CAkG/E;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAEjE;AAED;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA8BnE"}
@@ -0,0 +1,173 @@
1
+ /**
2
+ * CRDT Awareness (Presence) Management
3
+ *
4
+ * Manages Yjs Awareness protocol for user presence indicators
5
+ * (cursor positions, active users, etc.) via Supabase broadcast.
6
+ */
7
+ import { Awareness } from 'y-protocols/awareness';
8
+ import * as awarenessProtocol from 'y-protocols/awareness';
9
+ import { debugLog, debugWarn, debugError } from '../debug';
10
+ import { getDeviceId } from '../deviceId';
11
+ import { getEngineConfig } from '../config';
12
+ import { supabase } from '../supabase/client';
13
+ import { getCrdtDoc } from './doc';
14
+ /** Active awareness instances: docId → { awareness, channel, cleanup } */
15
+ const activeAwareness = new Map();
16
+ function uint8ArrayToBase64(bytes) {
17
+ let binary = '';
18
+ for (let i = 0; i < bytes.length; i++) {
19
+ binary += String.fromCharCode(bytes[i]);
20
+ }
21
+ return btoa(binary);
22
+ }
23
+ function base64ToUint8Array(base64) {
24
+ const binary = atob(base64);
25
+ const bytes = new Uint8Array(binary.length);
26
+ for (let i = 0; i < binary.length; i++) {
27
+ bytes[i] = binary.charCodeAt(i);
28
+ }
29
+ return bytes;
30
+ }
31
+ /**
32
+ * Initialize awareness (presence) for a CRDT document.
33
+ *
34
+ * Creates an Awareness instance and sets up a dedicated broadcast channel
35
+ * for syncing presence state between clients.
36
+ *
37
+ * @param docId - Document/note ID
38
+ * @param userInfo - Current user's display info
39
+ * @returns The Awareness instance
40
+ */
41
+ export function initAwareness(docId, userInfo) {
42
+ const existing = activeAwareness.get(docId);
43
+ if (existing) {
44
+ // Update user info on existing awareness
45
+ existing.awareness.setLocalStateField('user', userInfo);
46
+ debugLog('[CRDT Awareness] Updated user info for:', docId);
47
+ return existing.awareness;
48
+ }
49
+ const doc = getCrdtDoc(docId);
50
+ if (!doc) {
51
+ throw new Error(`Cannot init awareness - doc not initialized: ${docId}`);
52
+ }
53
+ debugLog('[CRDT Awareness] Initializing for:', docId);
54
+ const awareness = new Awareness(doc);
55
+ const deviceId = getDeviceId();
56
+ const prefix = getEngineConfig().prefix;
57
+ const channelName = `awareness_${prefix}_${docId}`;
58
+ const cleanup = [];
59
+ // Set local state
60
+ awareness.setLocalStateField('user', userInfo);
61
+ // Create a broadcast channel for awareness
62
+ const channel = supabase.channel(channelName, {
63
+ config: {
64
+ broadcast: { self: false }
65
+ }
66
+ });
67
+ // Listen for remote awareness updates
68
+ channel.on('broadcast', { event: 'awareness' }, (payload) => {
69
+ if (payload.payload.deviceId === deviceId)
70
+ return;
71
+ try {
72
+ const update = base64ToUint8Array(payload.payload.data);
73
+ awarenessProtocol.applyAwarenessUpdate(awareness, update, 'remote');
74
+ }
75
+ catch (e) {
76
+ debugError('[CRDT Awareness] Error applying remote update:', e);
77
+ }
78
+ });
79
+ // Broadcast local awareness changes
80
+ const onUpdate = ({ added, updated, removed }, origin) => {
81
+ if (origin === 'remote')
82
+ return;
83
+ const changedClients = added.concat(updated).concat(removed);
84
+ try {
85
+ const update = awarenessProtocol.encodeAwarenessUpdate(awareness, changedClients);
86
+ channel.send({
87
+ type: 'broadcast',
88
+ event: 'awareness',
89
+ payload: {
90
+ data: uint8ArrayToBase64(update),
91
+ deviceId
92
+ }
93
+ });
94
+ }
95
+ catch (e) {
96
+ debugError('[CRDT Awareness] Error broadcasting update:', e);
97
+ }
98
+ };
99
+ awareness.on('update', onUpdate);
100
+ cleanup.push(() => awareness.off('update', onUpdate));
101
+ // Subscribe to channel
102
+ channel.subscribe((status) => {
103
+ if (status === 'SUBSCRIBED') {
104
+ debugLog('[CRDT Awareness] Channel connected for:', docId);
105
+ // Send initial awareness state
106
+ const update = awarenessProtocol.encodeAwarenessUpdate(awareness, [doc.clientID]);
107
+ channel.send({
108
+ type: 'broadcast',
109
+ event: 'awareness',
110
+ payload: {
111
+ data: uint8ArrayToBase64(update),
112
+ deviceId
113
+ }
114
+ });
115
+ }
116
+ });
117
+ // Clean up awareness on window unload
118
+ const beforeUnload = () => {
119
+ awarenessProtocol.removeAwarenessStates(awareness, [doc.clientID], 'window-unload');
120
+ };
121
+ if (typeof window !== 'undefined') {
122
+ window.addEventListener('beforeunload', beforeUnload);
123
+ cleanup.push(() => window.removeEventListener('beforeunload', beforeUnload));
124
+ }
125
+ activeAwareness.set(docId, { awareness, channel, cleanup });
126
+ return awareness;
127
+ }
128
+ /**
129
+ * Get the awareness instance for a document.
130
+ *
131
+ * @param docId - Document/note ID
132
+ * @returns The Awareness instance if initialized, undefined otherwise
133
+ */
134
+ export function getAwareness(docId) {
135
+ return activeAwareness.get(docId)?.awareness;
136
+ }
137
+ /**
138
+ * Destroy awareness for a document.
139
+ *
140
+ * Removes awareness state, closes the broadcast channel, and cleans up listeners.
141
+ *
142
+ * @param docId - Document/note ID
143
+ */
144
+ export async function destroyAwareness(docId) {
145
+ const entry = activeAwareness.get(docId);
146
+ if (!entry)
147
+ return;
148
+ debugLog('[CRDT Awareness] Destroying for:', docId);
149
+ // Run cleanup callbacks
150
+ for (const fn of entry.cleanup) {
151
+ try {
152
+ fn();
153
+ }
154
+ catch (e) {
155
+ debugWarn('[CRDT Awareness] Cleanup error:', e);
156
+ }
157
+ }
158
+ // Remove awareness states
159
+ const doc = getCrdtDoc(docId);
160
+ if (doc) {
161
+ awarenessProtocol.removeAwarenessStates(entry.awareness, [doc.clientID], 'destroy');
162
+ }
163
+ // Close channel
164
+ try {
165
+ await supabase.removeChannel(entry.channel);
166
+ }
167
+ catch (e) {
168
+ debugWarn('[CRDT Awareness] Error removing channel:', e);
169
+ }
170
+ entry.awareness.destroy();
171
+ activeAwareness.delete(docId);
172
+ }
173
+ //# sourceMappingURL=awareness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"awareness.js","sourceRoot":"","sources":["../../src/crdt/awareness.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * CRDT Document Lifecycle Management
3
+ *
4
+ * Creates, manages, and destroys Yjs Y.Doc instances with y-indexeddb persistence.
5
+ * The engine fully owns all Yjs and y-indexeddb -- apps never import these directly.
6
+ */
7
+ import * as Y from 'yjs';
8
+ import { IndexeddbPersistence } from 'y-indexeddb';
9
+ import type { CrdtDocConfig, CrdtDocState } from './types';
10
+ /**
11
+ * Initialize a CRDT document with local IndexedDB persistence.
12
+ *
13
+ * Creates a Y.Doc and attaches IndexeddbPersistence for local durability.
14
+ * If the document already exists, returns the existing instance.
15
+ *
16
+ * @param docId - Unique identifier for the document (typically note ID)
17
+ * @param config - Optional configuration
18
+ * @returns The Y.Doc instance
19
+ */
20
+ export declare function initCrdtDoc(docId: string, config?: CrdtDocConfig): Y.Doc;
21
+ /**
22
+ * Get an active CRDT document by ID.
23
+ *
24
+ * @param docId - Document identifier
25
+ * @returns The Y.Doc if it exists, undefined otherwise
26
+ */
27
+ export declare function getCrdtDoc(docId: string): Y.Doc | undefined;
28
+ /**
29
+ * Wait for a document's IndexedDB persistence to finish syncing.
30
+ * Resolves immediately if already synced.
31
+ *
32
+ * @param docId - Document identifier
33
+ */
34
+ export declare function waitForCrdtSync(docId: string): Promise<void>;
35
+ /**
36
+ * Destroy a CRDT document and clean up all resources.
37
+ *
38
+ * Closes IndexedDB persistence, runs cleanup callbacks, and removes from active map.
39
+ *
40
+ * @param docId - Document identifier
41
+ */
42
+ export declare function destroyCrdtDoc(docId: string): Promise<void>;
43
+ /**
44
+ * Get the internal state for a document (used by other CRDT modules).
45
+ * @internal
46
+ */
47
+ export declare function _getDocEntry(docId: string): {
48
+ doc: Y.Doc;
49
+ persistence: IndexeddbPersistence;
50
+ state: CrdtDocState;
51
+ } | undefined;
52
+ /**
53
+ * Get all active document IDs.
54
+ */
55
+ export declare function getActiveCrdtDocIds(): string[];
56
+ //# sourceMappingURL=doc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doc.d.ts","sourceRoot":"","sources":["../../src/crdt/doc.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AACzB,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAGnD,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAU3D;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,CAAC,CAAC,GAAG,CA6BxE;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,CAAC,CAAC,GAAG,GAAG,SAAS,CAE3D;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBlE;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA8BjE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM;SA7HL,CAAC,CAAC,GAAG;iBAAe,oBAAoB;WAAS,YAAY;cA+HjG;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAE9C"}
@@ -0,0 +1,130 @@
1
+ /**
2
+ * CRDT Document Lifecycle Management
3
+ *
4
+ * Creates, manages, and destroys Yjs Y.Doc instances with y-indexeddb persistence.
5
+ * The engine fully owns all Yjs and y-indexeddb -- apps never import these directly.
6
+ */
7
+ import * as Y from 'yjs';
8
+ import { IndexeddbPersistence } from 'y-indexeddb';
9
+ import { debugLog, debugWarn } from '../debug';
10
+ import { getEngineConfig } from '../config';
11
+ /** Active documents map: docId → { doc, persistence, state } */
12
+ const activeDocs = new Map();
13
+ function getDbName(docId, config) {
14
+ const prefix = config?.dbPrefix || getEngineConfig().prefix;
15
+ return `${prefix}_crdt_${docId}`;
16
+ }
17
+ /**
18
+ * Initialize a CRDT document with local IndexedDB persistence.
19
+ *
20
+ * Creates a Y.Doc and attaches IndexeddbPersistence for local durability.
21
+ * If the document already exists, returns the existing instance.
22
+ *
23
+ * @param docId - Unique identifier for the document (typically note ID)
24
+ * @param config - Optional configuration
25
+ * @returns The Y.Doc instance
26
+ */
27
+ export function initCrdtDoc(docId, config) {
28
+ const existing = activeDocs.get(docId);
29
+ if (existing) {
30
+ debugLog('[CRDT] Doc already initialized:', docId);
31
+ return existing.doc;
32
+ }
33
+ debugLog('[CRDT] Initializing doc:', docId);
34
+ const doc = new Y.Doc();
35
+ const dbName = getDbName(docId, config);
36
+ const persistence = new IndexeddbPersistence(dbName, doc);
37
+ const cleanup = [];
38
+ const state = {
39
+ docId,
40
+ cleanup
41
+ };
42
+ // Log when persistence is synced from IndexedDB
43
+ const onSynced = () => {
44
+ debugLog('[CRDT] IndexedDB synced for doc:', docId);
45
+ };
46
+ persistence.on('synced', onSynced);
47
+ cleanup.push(() => persistence.off('synced', onSynced));
48
+ activeDocs.set(docId, { doc, persistence, state });
49
+ return doc;
50
+ }
51
+ /**
52
+ * Get an active CRDT document by ID.
53
+ *
54
+ * @param docId - Document identifier
55
+ * @returns The Y.Doc if it exists, undefined otherwise
56
+ */
57
+ export function getCrdtDoc(docId) {
58
+ return activeDocs.get(docId)?.doc;
59
+ }
60
+ /**
61
+ * Wait for a document's IndexedDB persistence to finish syncing.
62
+ * Resolves immediately if already synced.
63
+ *
64
+ * @param docId - Document identifier
65
+ */
66
+ export async function waitForCrdtSync(docId) {
67
+ const entry = activeDocs.get(docId);
68
+ if (!entry) {
69
+ debugWarn('[CRDT] Cannot wait for sync - doc not initialized:', docId);
70
+ return;
71
+ }
72
+ if (entry.persistence.synced)
73
+ return;
74
+ return new Promise((resolve) => {
75
+ const handler = () => {
76
+ entry.persistence.off('synced', handler);
77
+ resolve();
78
+ };
79
+ entry.persistence.on('synced', handler);
80
+ });
81
+ }
82
+ /**
83
+ * Destroy a CRDT document and clean up all resources.
84
+ *
85
+ * Closes IndexedDB persistence, runs cleanup callbacks, and removes from active map.
86
+ *
87
+ * @param docId - Document identifier
88
+ */
89
+ export async function destroyCrdtDoc(docId) {
90
+ const entry = activeDocs.get(docId);
91
+ if (!entry) {
92
+ debugLog('[CRDT] Doc not found for destroy:', docId);
93
+ return;
94
+ }
95
+ debugLog('[CRDT] Destroying doc:', docId);
96
+ // Run cleanup callbacks (removes event listeners)
97
+ for (const fn of entry.state.cleanup) {
98
+ try {
99
+ fn();
100
+ }
101
+ catch (e) {
102
+ debugWarn('[CRDT] Cleanup error for doc:', docId, e);
103
+ }
104
+ }
105
+ // Close IndexedDB persistence
106
+ try {
107
+ await entry.persistence.destroy();
108
+ }
109
+ catch (e) {
110
+ debugWarn('[CRDT] Error closing persistence for doc:', docId, e);
111
+ }
112
+ // Destroy the Y.Doc
113
+ entry.doc.destroy();
114
+ activeDocs.delete(docId);
115
+ debugLog('[CRDT] Doc destroyed:', docId);
116
+ }
117
+ /**
118
+ * Get the internal state for a document (used by other CRDT modules).
119
+ * @internal
120
+ */
121
+ export function _getDocEntry(docId) {
122
+ return activeDocs.get(docId);
123
+ }
124
+ /**
125
+ * Get all active document IDs.
126
+ */
127
+ export function getActiveCrdtDocIds() {
128
+ return Array.from(activeDocs.keys());
129
+ }
130
+ //# sourceMappingURL=doc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doc.js","sourceRoot":"","sources":["../../src/crdt/doc.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * CRDT Module Barrel Export
3
+ *
4
+ * Provides complete Yjs/CRDT management for collaborative editing.
5
+ * Apps should import everything from this module and never import
6
+ * yjs or y-indexeddb directly.
7
+ */
8
+ export { Doc as YDoc, Array as YArray, Map as YMap, Text as YText } from 'yjs';
9
+ export * as Y from 'yjs';
10
+ export { initCrdtDoc, getCrdtDoc, destroyCrdtDoc, waitForCrdtSync, getActiveCrdtDocIds } from './doc';
11
+ export { connectCrdtRealtime, disconnectCrdtRealtime, saveCrdtCheckpoint, loadCrdtFromRemote, getCrdtSyncState, isCrdtRealtimeConnected } from './sync';
12
+ export { initAwareness, getAwareness, destroyAwareness } from './awareness';
13
+ export { Awareness } from 'y-protocols/awareness';
14
+ export { cacheCrdtForOffline, removeCrdtOfflineCache, isCrdtCachedOffline, loadCrdtFromOfflineCache } from './offline';
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/crdt/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,GAAG,IAAI,IAAI,EAAE,KAAK,IAAI,MAAM,EAAE,GAAG,IAAI,IAAI,EAAE,IAAI,IAAI,KAAK,EAAE,MAAM,KAAK,CAAC;AAC/E,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAGzB,OAAO,EACL,WAAW,EACX,UAAU,EACV,cAAc,EACd,eAAe,EACf,mBAAmB,EACpB,MAAM,OAAO,CAAC;AAGf,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,uBAAuB,EACxB,MAAM,QAAQ,CAAC;AAGhB,OAAO,EACL,aAAa,EACb,YAAY,EACZ,gBAAgB,EACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGlD,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,mBAAmB,EACnB,wBAAwB,EACzB,MAAM,WAAW,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * CRDT Module Barrel Export
3
+ *
4
+ * Provides complete Yjs/CRDT management for collaborative editing.
5
+ * Apps should import everything from this module and never import
6
+ * yjs or y-indexeddb directly.
7
+ */
8
+ // Re-export Y for type access (apps need Y.Array, Y.Map, Y.Text, etc.)
9
+ export { Doc as YDoc, Array as YArray, Map as YMap, Text as YText } from 'yjs';
10
+ export * as Y from 'yjs';
11
+ // Document lifecycle
12
+ export { initCrdtDoc, getCrdtDoc, destroyCrdtDoc, waitForCrdtSync, getActiveCrdtDocIds } from './doc';
13
+ // Realtime sync
14
+ export { connectCrdtRealtime, disconnectCrdtRealtime, saveCrdtCheckpoint, loadCrdtFromRemote, getCrdtSyncState, isCrdtRealtimeConnected } from './sync';
15
+ // Awareness (presence)
16
+ export { initAwareness, getAwareness, destroyAwareness } from './awareness';
17
+ export { Awareness } from 'y-protocols/awareness';
18
+ // Offline cache
19
+ export { cacheCrdtForOffline, removeCrdtOfflineCache, isCrdtCachedOffline, loadCrdtFromOfflineCache } from './offline';
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/crdt/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,uEAAuE;AACvE,OAAO,EAAE,GAAG,IAAI,IAAI,EAAE,KAAK,IAAI,MAAM,EAAE,GAAG,IAAI,IAAI,EAAE,IAAI,IAAI,KAAK,EAAE,MAAM,KAAK,CAAC;AAC/E,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAEzB,qBAAqB;AACrB,OAAO,EACL,WAAW,EACX,UAAU,EACV,cAAc,EACd,eAAe,EACf,mBAAmB,EACpB,MAAM,OAAO,CAAC;AAEf,gBAAgB;AAChB,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,uBAAuB,EACxB,MAAM,QAAQ,CAAC;AAEhB,uBAAuB;AACvB,OAAO,EACL,aAAa,EACb,YAAY,EACZ,gBAAgB,EACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD,gBAAgB;AAChB,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,mBAAmB,EACnB,wBAAwB,EACzB,MAAM,WAAW,CAAC"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * CRDT Offline Cache Management
3
+ *
4
+ * Manages selective offline caching of Yjs document state.
5
+ * Uses a dedicated IndexedDB store separate from y-indexeddb persistence.
6
+ *
7
+ * The active y-indexeddb persistence (from doc.ts) handles documents that are
8
+ * currently open. This module handles explicit offline download/caching for
9
+ * documents the user wants available offline even when not actively editing.
10
+ */
11
+ import * as Y from 'yjs';
12
+ /**
13
+ * Cache a CRDT document for offline access.
14
+ *
15
+ * Serializes the current Yjs state and stores it in IndexedDB.
16
+ * If the document is currently active, uses its live state.
17
+ * Otherwise, fetches the state from Supabase.
18
+ *
19
+ * @param docId - Document/note ID
20
+ */
21
+ export declare function cacheCrdtForOffline(docId: string): Promise<void>;
22
+ /**
23
+ * Remove a document from the offline cache.
24
+ *
25
+ * @param docId - Document/note ID
26
+ */
27
+ export declare function removeCrdtOfflineCache(docId: string): Promise<void>;
28
+ /**
29
+ * Check if a document is cached for offline access.
30
+ *
31
+ * @param docId - Document/note ID
32
+ * @returns true if the document is cached
33
+ */
34
+ export declare function isCrdtCachedOffline(docId: string): Promise<boolean>;
35
+ /**
36
+ * Load a cached CRDT document state from offline storage.
37
+ *
38
+ * Creates a new Y.Doc and applies the cached state to it.
39
+ * The caller is responsible for destroying the returned doc.
40
+ *
41
+ * @param docId - Document/note ID
42
+ * @returns A Y.Doc with the cached state, or null if not cached
43
+ */
44
+ export declare function loadCrdtFromOfflineCache(docId: string): Promise<Y.Doc | null>;
45
+ //# sourceMappingURL=offline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"offline.d.ts","sourceRoot":"","sources":["../../src/crdt/offline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAkCzB;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA6DtE;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBzE;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAkBzE;AAED;;;;;;;;GAQG;AACH,wBAAsB,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,CA6BnF"}