@prabhask5/stellar-engine 1.1.18 → 1.2.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.
- package/README.md +55 -1
- package/dist/bin/install-pwa.js +50 -0
- package/dist/bin/install-pwa.js.map +1 -1
- package/dist/config.d.ts +11 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +8 -2
- package/dist/config.js.map +1 -1
- package/dist/crdt/awareness.d.ts +128 -0
- package/dist/crdt/awareness.d.ts.map +1 -0
- package/dist/crdt/awareness.js +284 -0
- package/dist/crdt/awareness.js.map +1 -0
- package/dist/crdt/channel.d.ts +165 -0
- package/dist/crdt/channel.d.ts.map +1 -0
- package/dist/crdt/channel.js +522 -0
- package/dist/crdt/channel.js.map +1 -0
- package/dist/crdt/config.d.ts +58 -0
- package/dist/crdt/config.d.ts.map +1 -0
- package/dist/crdt/config.js +123 -0
- package/dist/crdt/config.js.map +1 -0
- package/dist/crdt/helpers.d.ts +104 -0
- package/dist/crdt/helpers.d.ts.map +1 -0
- package/dist/crdt/helpers.js +116 -0
- package/dist/crdt/helpers.js.map +1 -0
- package/dist/crdt/offline.d.ts +58 -0
- package/dist/crdt/offline.d.ts.map +1 -0
- package/dist/crdt/offline.js +130 -0
- package/dist/crdt/offline.js.map +1 -0
- package/dist/crdt/persistence.d.ts +65 -0
- package/dist/crdt/persistence.d.ts.map +1 -0
- package/dist/crdt/persistence.js +171 -0
- package/dist/crdt/persistence.js.map +1 -0
- package/dist/crdt/provider.d.ts +109 -0
- package/dist/crdt/provider.d.ts.map +1 -0
- package/dist/crdt/provider.js +543 -0
- package/dist/crdt/provider.js.map +1 -0
- package/dist/crdt/store.d.ts +111 -0
- package/dist/crdt/store.d.ts.map +1 -0
- package/dist/crdt/store.js +158 -0
- package/dist/crdt/store.js.map +1 -0
- package/dist/crdt/types.d.ts +281 -0
- package/dist/crdt/types.d.ts.map +1 -0
- package/dist/crdt/types.js +26 -0
- package/dist/crdt/types.js.map +1 -0
- package/dist/database.d.ts +1 -1
- package/dist/database.d.ts.map +1 -1
- package/dist/database.js +28 -7
- package/dist/database.js.map +1 -1
- package/dist/diagnostics.d.ts +75 -0
- package/dist/diagnostics.d.ts.map +1 -1
- package/dist/diagnostics.js +114 -2
- package/dist/diagnostics.js.map +1 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +21 -1
- package/dist/engine.js.map +1 -1
- package/dist/entries/crdt.d.ts +32 -0
- package/dist/entries/crdt.d.ts.map +1 -0
- package/dist/entries/crdt.js +52 -0
- package/dist/entries/crdt.js.map +1 -0
- package/dist/entries/types.d.ts +1 -0
- package/dist/entries/types.d.ts.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/package.json +7 -2
- package/dist/operations.d.ts +0 -73
- package/dist/operations.d.ts.map +0 -1
- package/dist/operations.js +0 -227
- package/dist/operations.js.map +0 -1
- package/dist/reconnectHandler.d.ts +0 -16
- package/dist/reconnectHandler.d.ts.map +0 -1
- package/dist/reconnectHandler.js +0 -21
- package/dist/reconnectHandler.js.map +0 -1
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview CRDT IndexedDB Persistence Layer
|
|
3
|
+
*
|
|
4
|
+
* Provides CRUD operations for the two CRDT-specific IndexedDB tables:
|
|
5
|
+
* - `crdtDocuments` — Full Yjs document state snapshots
|
|
6
|
+
* - `crdtPendingUpdates` — Incremental Yjs update deltas for crash recovery
|
|
7
|
+
*
|
|
8
|
+
* These tables are conditionally created by {@link ../database.ts#buildDexie}
|
|
9
|
+
* only when `crdt` config is provided to `initEngine()`.
|
|
10
|
+
*
|
|
11
|
+
* This module also exposes offline management query functions:
|
|
12
|
+
* - {@link isOfflineEnabled} — check if a document is stored for offline
|
|
13
|
+
* - {@link getOfflineDocuments} — list all offline-enabled documents
|
|
14
|
+
* - {@link getOfflineDocumentCount} — count for limit enforcement
|
|
15
|
+
*
|
|
16
|
+
* All functions access Dexie via the engine-managed instance from
|
|
17
|
+
* {@link ../database.ts#getDb}. Binary Yjs state is stored directly as
|
|
18
|
+
* `Uint8Array` — Dexie/IndexedDB handles binary data natively.
|
|
19
|
+
*
|
|
20
|
+
* @see {@link ./types.ts} for record shapes (CRDTDocumentRecord, CRDTPendingUpdate)
|
|
21
|
+
* @see {@link ./provider.ts} for the orchestrator that calls these functions
|
|
22
|
+
* @see {@link ../database.ts} for conditional CRDT table creation
|
|
23
|
+
*/
|
|
24
|
+
import { getDb } from '../database';
|
|
25
|
+
import { debugLog } from '../debug';
|
|
26
|
+
// =============================================================================
|
|
27
|
+
// Document State CRUD
|
|
28
|
+
// =============================================================================
|
|
29
|
+
/**
|
|
30
|
+
* Load a CRDT document record from IndexedDB.
|
|
31
|
+
*
|
|
32
|
+
* @param documentId - The unique document identifier.
|
|
33
|
+
* @returns The document record, or `undefined` if not found.
|
|
34
|
+
*/
|
|
35
|
+
export async function loadDocumentState(documentId) {
|
|
36
|
+
const db = getDb();
|
|
37
|
+
return db.table('crdtDocuments').get(documentId);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Save a full CRDT document state snapshot to IndexedDB.
|
|
41
|
+
*
|
|
42
|
+
* Uses Dexie's `put()` for upsert semantics — creates a new record if the
|
|
43
|
+
* document doesn't exist, or overwrites the existing one.
|
|
44
|
+
*
|
|
45
|
+
* @param record - The full document record to persist.
|
|
46
|
+
*/
|
|
47
|
+
export async function saveDocumentState(record) {
|
|
48
|
+
const db = getDb();
|
|
49
|
+
await db.table('crdtDocuments').put(record);
|
|
50
|
+
debugLog(`[CRDT] Document ${record.documentId}: local save (${record.stateSize} bytes to IndexedDB)`);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Delete a CRDT document record from IndexedDB.
|
|
54
|
+
*
|
|
55
|
+
* Also clears all associated pending updates for the document.
|
|
56
|
+
*
|
|
57
|
+
* @param documentId - The document to delete.
|
|
58
|
+
*/
|
|
59
|
+
export async function deleteDocumentState(documentId) {
|
|
60
|
+
const db = getDb();
|
|
61
|
+
await db.table('crdtDocuments').delete(documentId);
|
|
62
|
+
await clearPendingUpdates(documentId);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Load a CRDT document record by page ID.
|
|
66
|
+
*
|
|
67
|
+
* Pages may have at most one CRDT document. Returns the first match.
|
|
68
|
+
*
|
|
69
|
+
* @param pageId - The page/entity ID to look up.
|
|
70
|
+
* @returns The document record, or `undefined` if not found.
|
|
71
|
+
*/
|
|
72
|
+
export async function loadDocumentByPageId(pageId) {
|
|
73
|
+
const db = getDb();
|
|
74
|
+
return db.table('crdtDocuments').where('pageId').equals(pageId).first();
|
|
75
|
+
}
|
|
76
|
+
// =============================================================================
|
|
77
|
+
// Pending Updates (Crash Recovery)
|
|
78
|
+
// =============================================================================
|
|
79
|
+
/**
|
|
80
|
+
* Append an incremental Yjs update to the pending updates table.
|
|
81
|
+
*
|
|
82
|
+
* Called on every `doc.on('update')` event for crash safety. If the browser
|
|
83
|
+
* crashes between full-state saves (every 5s), these deltas can be replayed
|
|
84
|
+
* to recover the document.
|
|
85
|
+
*
|
|
86
|
+
* @param documentId - The document this update belongs to.
|
|
87
|
+
* @param update - The incremental Yjs update delta.
|
|
88
|
+
*/
|
|
89
|
+
export async function appendPendingUpdate(documentId, update) {
|
|
90
|
+
const db = getDb();
|
|
91
|
+
const record = {
|
|
92
|
+
documentId,
|
|
93
|
+
update,
|
|
94
|
+
timestamp: new Date().toISOString()
|
|
95
|
+
};
|
|
96
|
+
await db.table('crdtPendingUpdates').add(record);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Load all pending updates for a specific document, ordered by ID (insertion order).
|
|
100
|
+
*
|
|
101
|
+
* Used during document opening to replay any updates that weren't captured
|
|
102
|
+
* in the last full-state save.
|
|
103
|
+
*
|
|
104
|
+
* @param documentId - The document to load updates for.
|
|
105
|
+
* @returns Array of pending update records, oldest first.
|
|
106
|
+
*/
|
|
107
|
+
export async function loadPendingUpdates(documentId) {
|
|
108
|
+
const db = getDb();
|
|
109
|
+
return db.table('crdtPendingUpdates').where('documentId').equals(documentId).sortBy('id');
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Clear all pending updates for a document.
|
|
113
|
+
*
|
|
114
|
+
* Called after a successful full-state save to IndexedDB or Supabase persist,
|
|
115
|
+
* since the updates have been captured in the full state snapshot.
|
|
116
|
+
*
|
|
117
|
+
* @param documentId - The document to clear updates for.
|
|
118
|
+
* @returns The number of updates cleared.
|
|
119
|
+
*/
|
|
120
|
+
export async function clearPendingUpdates(documentId) {
|
|
121
|
+
const db = getDb();
|
|
122
|
+
return db.table('crdtPendingUpdates').where('documentId').equals(documentId).delete();
|
|
123
|
+
}
|
|
124
|
+
// =============================================================================
|
|
125
|
+
// Offline Management Queries
|
|
126
|
+
// =============================================================================
|
|
127
|
+
/**
|
|
128
|
+
* Check whether a specific document is stored for offline access.
|
|
129
|
+
*
|
|
130
|
+
* @param documentId - The document to check.
|
|
131
|
+
* @returns `true` if the document has `offlineEnabled: 1` in IndexedDB.
|
|
132
|
+
*/
|
|
133
|
+
export async function isOfflineEnabled(documentId) {
|
|
134
|
+
const record = await loadDocumentState(documentId);
|
|
135
|
+
return record?.offlineEnabled === 1;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Get all documents that are stored for offline access.
|
|
139
|
+
*
|
|
140
|
+
* @returns Array of document records with `offlineEnabled: 1`.
|
|
141
|
+
*/
|
|
142
|
+
export async function getOfflineDocuments() {
|
|
143
|
+
const db = getDb();
|
|
144
|
+
return db.table('crdtDocuments').where('offlineEnabled').equals(1).toArray();
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Count the number of documents currently stored for offline access.
|
|
148
|
+
*
|
|
149
|
+
* Used by {@link ./offline.ts#enableOffline} to enforce the
|
|
150
|
+
* `maxOfflineDocuments` limit.
|
|
151
|
+
*
|
|
152
|
+
* @returns The number of offline-enabled documents.
|
|
153
|
+
*/
|
|
154
|
+
export async function getOfflineDocumentCount() {
|
|
155
|
+
const db = getDb();
|
|
156
|
+
return db.table('crdtDocuments').where('offlineEnabled').equals(1).count();
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/crdt/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview CRDT Subsystem Type Definitions
|
|
3
|
+
*
|
|
4
|
+
* Defines all TypeScript interfaces and types used by the CRDT collaborative
|
|
5
|
+
* editing subsystem. This includes:
|
|
6
|
+
* - {@link CRDTConfig} — configuration passed via `initEngine({ crdt: ... })`
|
|
7
|
+
* - {@link CRDTDocumentRecord} — IndexedDB record shape for persisted CRDT state
|
|
8
|
+
* - {@link CRDTPendingUpdate} — crash-safe incremental update records
|
|
9
|
+
* - {@link UserPresenceState} — per-user cursor/presence state for awareness
|
|
10
|
+
* - {@link OpenDocumentOptions} — options bag for `openDocument()`
|
|
11
|
+
* - {@link BroadcastMessage} — union of all Broadcast channel message types
|
|
12
|
+
*
|
|
13
|
+
* Architecture note:
|
|
14
|
+
* The CRDT subsystem is an optional layer on top of the existing sync engine.
|
|
15
|
+
* It uses Yjs for conflict-free document merging, Supabase Broadcast for
|
|
16
|
+
* real-time update distribution, Supabase Presence for cursor/awareness,
|
|
17
|
+
* and IndexedDB (via Dexie) for local persistence. Consumers never import
|
|
18
|
+
* yjs directly — all Yjs types are re-exported from the engine.
|
|
19
|
+
*
|
|
20
|
+
* @see {@link ./config.ts} for configuration singleton management
|
|
21
|
+
* @see {@link ./provider.ts} for the per-document lifecycle orchestrator
|
|
22
|
+
* @see {@link ./channel.ts} for Broadcast message handling
|
|
23
|
+
* @see {@link ./awareness.ts} for Supabase Presence ↔ Yjs Awareness bridge
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* Configuration for the CRDT collaborative editing subsystem.
|
|
27
|
+
*
|
|
28
|
+
* Passed as the `crdt` field of {@link SyncEngineConfig} in `initEngine()`.
|
|
29
|
+
* All fields are optional with sensible defaults. When this config is provided,
|
|
30
|
+
* the engine creates additional IndexedDB tables for CRDT document storage and
|
|
31
|
+
* enables the `@prabhask5/stellar-engine/crdt` API surface.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* initEngine({
|
|
35
|
+
* prefix: 'myapp',
|
|
36
|
+
* tables: [...],
|
|
37
|
+
* database: { name: 'myapp-db', versions: [...] },
|
|
38
|
+
* crdt: {
|
|
39
|
+
* persistIntervalMs: 60000, // Persist to Supabase every 60s
|
|
40
|
+
* maxOfflineDocuments: 100, // Allow up to 100 docs offline
|
|
41
|
+
* },
|
|
42
|
+
* });
|
|
43
|
+
*/
|
|
44
|
+
export interface CRDTConfig {
|
|
45
|
+
/**
|
|
46
|
+
* Supabase table name for CRDT document storage.
|
|
47
|
+
* @default 'crdt_documents'
|
|
48
|
+
*/
|
|
49
|
+
supabaseTable?: string;
|
|
50
|
+
/**
|
|
51
|
+
* Columns to SELECT from Supabase (egress optimization).
|
|
52
|
+
* @default 'id,page_id,state,state_vector,state_size,device_id,updated_at,created_at'
|
|
53
|
+
*/
|
|
54
|
+
columns?: string;
|
|
55
|
+
/**
|
|
56
|
+
* How often to persist dirty documents to Supabase (ms).
|
|
57
|
+
* Lower values reduce data loss risk on crash but increase Supabase writes.
|
|
58
|
+
* @default 30000 (30 seconds)
|
|
59
|
+
*/
|
|
60
|
+
persistIntervalMs?: number;
|
|
61
|
+
/**
|
|
62
|
+
* Broadcast debounce window (ms). Updates within this window are merged
|
|
63
|
+
* via `Y.mergeUpdates()` into a single Broadcast payload.
|
|
64
|
+
* @default 100
|
|
65
|
+
*/
|
|
66
|
+
broadcastDebounceMs?: number;
|
|
67
|
+
/**
|
|
68
|
+
* How long to debounce local IndexedDB full-state saves (ms).
|
|
69
|
+
* Writes full Yjs state to IndexedDB on this interval to ensure recovery
|
|
70
|
+
* from crashes without storing every single keystroke.
|
|
71
|
+
* @default 5000 (5 seconds)
|
|
72
|
+
*/
|
|
73
|
+
localSaveDebounceMs?: number;
|
|
74
|
+
/**
|
|
75
|
+
* Cursor/presence update debounce (ms). Limits the rate at which
|
|
76
|
+
* cursor position changes are broadcast to other users.
|
|
77
|
+
* @default 50
|
|
78
|
+
*/
|
|
79
|
+
cursorDebounceMs?: number;
|
|
80
|
+
/**
|
|
81
|
+
* Maximum number of documents stored locally for offline access.
|
|
82
|
+
* When the limit is reached, `enableOffline()` will reject new documents.
|
|
83
|
+
* @default 50
|
|
84
|
+
*/
|
|
85
|
+
maxOfflineDocuments?: number;
|
|
86
|
+
/**
|
|
87
|
+
* Maximum Broadcast payload size in bytes before chunking.
|
|
88
|
+
* Supabase Broadcast has a ~1MB hard limit; we chunk well below that.
|
|
89
|
+
* @default 250000 (250KB)
|
|
90
|
+
*/
|
|
91
|
+
maxBroadcastPayloadBytes?: number;
|
|
92
|
+
/**
|
|
93
|
+
* Timeout (ms) waiting for peer sync-step-2 responses on reconnect.
|
|
94
|
+
* If no peers respond within this window, falls back to Supabase fetch.
|
|
95
|
+
* @default 3000
|
|
96
|
+
*/
|
|
97
|
+
syncPeerTimeoutMs?: number;
|
|
98
|
+
/**
|
|
99
|
+
* Maximum reconnection attempts for the Broadcast channel.
|
|
100
|
+
* After this many failures, the channel enters a permanent error state
|
|
101
|
+
* and must be manually reconnected.
|
|
102
|
+
* @default 5
|
|
103
|
+
*/
|
|
104
|
+
maxReconnectAttempts?: number;
|
|
105
|
+
/**
|
|
106
|
+
* Base delay (ms) for exponential backoff on channel reconnect.
|
|
107
|
+
* Actual delay: `baseDelay * 2^(attemptNumber - 1)`.
|
|
108
|
+
* @default 1000
|
|
109
|
+
*/
|
|
110
|
+
reconnectBaseDelayMs?: number;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Fully resolved CRDT configuration with all defaults applied.
|
|
114
|
+
*
|
|
115
|
+
* Created by {@link config.ts#_initCRDT} from the user-provided
|
|
116
|
+
* {@link CRDTConfig}. All fields are required (no `undefined` values).
|
|
117
|
+
*
|
|
118
|
+
* @internal
|
|
119
|
+
*/
|
|
120
|
+
export interface ResolvedCRDTConfig {
|
|
121
|
+
supabaseTable: string;
|
|
122
|
+
columns: string;
|
|
123
|
+
persistIntervalMs: number;
|
|
124
|
+
broadcastDebounceMs: number;
|
|
125
|
+
localSaveDebounceMs: number;
|
|
126
|
+
cursorDebounceMs: number;
|
|
127
|
+
maxOfflineDocuments: number;
|
|
128
|
+
maxBroadcastPayloadBytes: number;
|
|
129
|
+
syncPeerTimeoutMs: number;
|
|
130
|
+
maxReconnectAttempts: number;
|
|
131
|
+
reconnectBaseDelayMs: number;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Shape of a record in the `crdtDocuments` IndexedDB table.
|
|
135
|
+
*
|
|
136
|
+
* Stores the full Yjs document state as a binary `Uint8Array`, along with
|
|
137
|
+
* metadata for sync, offline management, and diagnostics.
|
|
138
|
+
*
|
|
139
|
+
* The `offlineEnabled` field uses `0 | 1` instead of `boolean` because
|
|
140
|
+
* Dexie/IndexedDB cannot index boolean fields.
|
|
141
|
+
*/
|
|
142
|
+
export interface CRDTDocumentRecord {
|
|
143
|
+
/** Unique document identifier (primary key). */
|
|
144
|
+
documentId: string;
|
|
145
|
+
/** The page/entity this document belongs to. Indexed for lookups. */
|
|
146
|
+
pageId: string;
|
|
147
|
+
/** Full Yjs document state (`Y.encodeStateAsUpdate(doc)`). */
|
|
148
|
+
state: Uint8Array;
|
|
149
|
+
/** Yjs state vector for delta sync (`Y.encodeStateVector(doc)`). */
|
|
150
|
+
stateVector: Uint8Array;
|
|
151
|
+
/**
|
|
152
|
+
* Whether this document is stored locally for offline access.
|
|
153
|
+
* Uses `0 | 1` because IndexedDB cannot index booleans.
|
|
154
|
+
*/
|
|
155
|
+
offlineEnabled: 0 | 1;
|
|
156
|
+
/** ISO 8601 timestamp of the last local modification. */
|
|
157
|
+
localUpdatedAt: string;
|
|
158
|
+
/** ISO 8601 timestamp of the last successful Supabase write, or `null` if never persisted. */
|
|
159
|
+
lastPersistedAt: string | null;
|
|
160
|
+
/** Byte size of the `state` field, for diagnostics and compaction decisions. */
|
|
161
|
+
stateSize: number;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Shape of a record in the `crdtPendingUpdates` IndexedDB table.
|
|
165
|
+
*
|
|
166
|
+
* Stores incremental Yjs update deltas for crash safety. These are written
|
|
167
|
+
* on every `doc.on('update')` event so that if the browser crashes between
|
|
168
|
+
* full-state saves (every 5s), the pending deltas can be replayed to recover
|
|
169
|
+
* the document to its last known state.
|
|
170
|
+
*
|
|
171
|
+
* Cleared after a successful full-state save to IndexedDB or Supabase persist.
|
|
172
|
+
*/
|
|
173
|
+
export interface CRDTPendingUpdate {
|
|
174
|
+
/** Auto-increment primary key (assigned by IndexedDB). */
|
|
175
|
+
id?: number;
|
|
176
|
+
/** Which document this update belongs to. Indexed for efficient batch queries. */
|
|
177
|
+
documentId: string;
|
|
178
|
+
/** Incremental Yjs update delta (`Uint8Array` from `doc.on('update')`). */
|
|
179
|
+
update: Uint8Array;
|
|
180
|
+
/** ISO 8601 timestamp of when the update was received. */
|
|
181
|
+
timestamp: string;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Per-user presence state broadcast via Supabase Presence and bridged to
|
|
185
|
+
* Yjs Awareness. This is what other users see when collaborating on a document.
|
|
186
|
+
*
|
|
187
|
+
* The `cursor` and `selection` fields are intentionally typed as `unknown`
|
|
188
|
+
* because their shape depends on the editor implementation (Tiptap, Prosemirror,
|
|
189
|
+
* CodeMirror, etc.). The CRDT engine transports them opaquely.
|
|
190
|
+
*/
|
|
191
|
+
export interface UserPresenceState {
|
|
192
|
+
/** Supabase user UUID. */
|
|
193
|
+
userId: string;
|
|
194
|
+
/** Display name (e.g., first name or email). */
|
|
195
|
+
name: string;
|
|
196
|
+
/** Avatar URL, if available. */
|
|
197
|
+
avatarUrl?: string;
|
|
198
|
+
/**
|
|
199
|
+
* Deterministic color assigned from userId hash.
|
|
200
|
+
* Used for cursor color, selection highlight, avatar ring, etc.
|
|
201
|
+
*/
|
|
202
|
+
color: string;
|
|
203
|
+
/** Editor-specific cursor position (opaque to the engine). */
|
|
204
|
+
cursor?: unknown;
|
|
205
|
+
/** Editor-specific selection range (opaque to the engine). */
|
|
206
|
+
selection?: unknown;
|
|
207
|
+
/** Device identifier for multi-tab dedup. */
|
|
208
|
+
deviceId: string;
|
|
209
|
+
/** ISO 8601 timestamp of the user's last activity in this document. */
|
|
210
|
+
lastActiveAt: string;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Options for {@link provider.ts#openDocument}.
|
|
214
|
+
*/
|
|
215
|
+
export interface OpenDocumentOptions {
|
|
216
|
+
/**
|
|
217
|
+
* If `true`, the document will be persisted to IndexedDB for offline access.
|
|
218
|
+
* When `false` or omitted, the document exists only in memory and is lost
|
|
219
|
+
* when the provider is destroyed.
|
|
220
|
+
* @default false
|
|
221
|
+
*/
|
|
222
|
+
offlineEnabled?: boolean;
|
|
223
|
+
/**
|
|
224
|
+
* Initial user presence state to announce when joining the document.
|
|
225
|
+
* If omitted, no presence is announced until `updateCursor()` is called.
|
|
226
|
+
*/
|
|
227
|
+
initialPresence?: {
|
|
228
|
+
name: string;
|
|
229
|
+
avatarUrl?: string;
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Connection state of a CRDT document's Broadcast channel.
|
|
234
|
+
*/
|
|
235
|
+
export type CRDTConnectionState = 'disconnected' | 'connecting' | 'connected';
|
|
236
|
+
/**
|
|
237
|
+
* A CRDT document update distributed via Supabase Broadcast.
|
|
238
|
+
*
|
|
239
|
+
* Contains the merged Yjs update (possibly the result of debouncing multiple
|
|
240
|
+
* rapid edits) encoded as a base64 string for JSON transport.
|
|
241
|
+
*/
|
|
242
|
+
export interface BroadcastUpdateMessage {
|
|
243
|
+
type: 'update';
|
|
244
|
+
data: string;
|
|
245
|
+
deviceId: string;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Sync step 1: sent on channel join to request missing updates from peers.
|
|
249
|
+
* Contains the local state vector so peers can compute the delta.
|
|
250
|
+
*/
|
|
251
|
+
export interface BroadcastSyncStep1Message {
|
|
252
|
+
type: 'sync-step-1';
|
|
253
|
+
stateVector: string;
|
|
254
|
+
deviceId: string;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Sync step 2: response to a sync-step-1 request.
|
|
258
|
+
* Contains the computed delta update for the requester.
|
|
259
|
+
*/
|
|
260
|
+
export interface BroadcastSyncStep2Message {
|
|
261
|
+
type: 'sync-step-2';
|
|
262
|
+
update: string;
|
|
263
|
+
deviceId: string;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* A chunk of a large Broadcast payload that exceeds the max payload size.
|
|
267
|
+
* The receiver reassembles chunks by matching `chunkId` and ordering by `index`.
|
|
268
|
+
*/
|
|
269
|
+
export interface BroadcastChunkMessage {
|
|
270
|
+
type: 'chunk';
|
|
271
|
+
chunkId: string;
|
|
272
|
+
index: number;
|
|
273
|
+
total: number;
|
|
274
|
+
data: string;
|
|
275
|
+
deviceId: string;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Union of all Broadcast message types sent over the CRDT channel.
|
|
279
|
+
*/
|
|
280
|
+
export type BroadcastMessage = BroadcastUpdateMessage | BroadcastSyncStep1Message | BroadcastSyncStep2Message | BroadcastChunkMessage;
|
|
281
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/crdt/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview CRDT Subsystem Type Definitions
|
|
3
|
+
*
|
|
4
|
+
* Defines all TypeScript interfaces and types used by the CRDT collaborative
|
|
5
|
+
* editing subsystem. This includes:
|
|
6
|
+
* - {@link CRDTConfig} — configuration passed via `initEngine({ crdt: ... })`
|
|
7
|
+
* - {@link CRDTDocumentRecord} — IndexedDB record shape for persisted CRDT state
|
|
8
|
+
* - {@link CRDTPendingUpdate} — crash-safe incremental update records
|
|
9
|
+
* - {@link UserPresenceState} — per-user cursor/presence state for awareness
|
|
10
|
+
* - {@link OpenDocumentOptions} — options bag for `openDocument()`
|
|
11
|
+
* - {@link BroadcastMessage} — union of all Broadcast channel message types
|
|
12
|
+
*
|
|
13
|
+
* Architecture note:
|
|
14
|
+
* The CRDT subsystem is an optional layer on top of the existing sync engine.
|
|
15
|
+
* It uses Yjs for conflict-free document merging, Supabase Broadcast for
|
|
16
|
+
* real-time update distribution, Supabase Presence for cursor/awareness,
|
|
17
|
+
* and IndexedDB (via Dexie) for local persistence. Consumers never import
|
|
18
|
+
* yjs directly — all Yjs types are re-exported from the engine.
|
|
19
|
+
*
|
|
20
|
+
* @see {@link ./config.ts} for configuration singleton management
|
|
21
|
+
* @see {@link ./provider.ts} for the per-document lifecycle orchestrator
|
|
22
|
+
* @see {@link ./channel.ts} for Broadcast message handling
|
|
23
|
+
* @see {@link ./awareness.ts} for Supabase Presence ↔ Yjs Awareness bridge
|
|
24
|
+
*/
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/crdt/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG"}
|
package/dist/database.d.ts
CHANGED
|
@@ -62,7 +62,7 @@ export interface DatabaseConfig {
|
|
|
62
62
|
* @param config - Database name and version declarations.
|
|
63
63
|
* @returns The opened Dexie instance, ready for use.
|
|
64
64
|
*/
|
|
65
|
-
export declare function createDatabase(config: DatabaseConfig): Promise<Dexie>;
|
|
65
|
+
export declare function createDatabase(config: DatabaseConfig, crdtEnabled?: boolean): Promise<Dexie>;
|
|
66
66
|
/**
|
|
67
67
|
* Get the engine-managed Dexie instance.
|
|
68
68
|
*
|
package/dist/database.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAM1B;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACpC,iFAAiF;IACjF,OAAO,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,sEAAsE;IACtE,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,OAAO,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9D;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,2EAA2E;IAC3E,QAAQ,EAAE,qBAAqB,EAAE,CAAC;CACnC;
|
|
1
|
+
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAM1B;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACpC,iFAAiF;IACjF,OAAO,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,sEAAsE;IACtE,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,OAAO,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9D;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,2EAA2E;IAC3E,QAAQ,EAAE,qBAAqB,EAAE,CAAC;CACnC;AAoDD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,cAAc,EAAE,WAAW,UAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,CAsDhG;AAoCD;;;;;GAKG;AACH,wBAAgB,KAAK,IAAI,KAAK,CAK7B;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,KAAK,GAAG,IAAI,CAE7C;AAMD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAyB5D"}
|
package/dist/database.js
CHANGED
|
@@ -41,6 +41,22 @@ const SYSTEM_TABLES = {
|
|
|
41
41
|
offlineSession: 'id',
|
|
42
42
|
singleUserConfig: 'id'
|
|
43
43
|
};
|
|
44
|
+
/**
|
|
45
|
+
* CRDT tables — only included when the CRDT subsystem is enabled via
|
|
46
|
+
* `initEngine({ crdt: {...} })`.
|
|
47
|
+
*
|
|
48
|
+
* - `crdtDocuments` — Full Yjs document state snapshots for offline access
|
|
49
|
+
* and cross-session recovery
|
|
50
|
+
* - `crdtPendingUpdates` — Incremental Yjs update deltas for crash safety
|
|
51
|
+
* (replayed if browser crashes between full saves)
|
|
52
|
+
*
|
|
53
|
+
* @see {@link ./crdt/types.ts} for record shapes
|
|
54
|
+
* @see {@link ./crdt/store.ts} for CRUD operations on these tables
|
|
55
|
+
*/
|
|
56
|
+
const CRDT_SYSTEM_TABLES = {
|
|
57
|
+
crdtDocuments: 'documentId, pageId, offlineEnabled',
|
|
58
|
+
crdtPendingUpdates: '++id, documentId, timestamp'
|
|
59
|
+
};
|
|
44
60
|
// =============================================================================
|
|
45
61
|
// Module State
|
|
46
62
|
// =============================================================================
|
|
@@ -67,8 +83,8 @@ let managedDb = null;
|
|
|
67
83
|
* @param config - Database name and version declarations.
|
|
68
84
|
* @returns The opened Dexie instance, ready for use.
|
|
69
85
|
*/
|
|
70
|
-
export async function createDatabase(config) {
|
|
71
|
-
let db = buildDexie(config);
|
|
86
|
+
export async function createDatabase(config, crdtEnabled = false) {
|
|
87
|
+
let db = buildDexie(config, crdtEnabled);
|
|
72
88
|
try {
|
|
73
89
|
/*
|
|
74
90
|
* Open eagerly to trigger version upgrade NOW, not lazily on first access.
|
|
@@ -94,7 +110,7 @@ export async function createDatabase(config) {
|
|
|
94
110
|
`DB version: ${idb.version}, Dexie version: ${db.verno}. Deleting and recreating...`);
|
|
95
111
|
db.close();
|
|
96
112
|
await Dexie.delete(config.name);
|
|
97
|
-
db = buildDexie(config);
|
|
113
|
+
db = buildDexie(config, crdtEnabled);
|
|
98
114
|
await db.open();
|
|
99
115
|
}
|
|
100
116
|
}
|
|
@@ -113,7 +129,7 @@ export async function createDatabase(config) {
|
|
|
113
129
|
/* Ignore close errors — the connection may already be broken. */
|
|
114
130
|
}
|
|
115
131
|
await Dexie.delete(config.name);
|
|
116
|
-
db = buildDexie(config);
|
|
132
|
+
db = buildDexie(config, crdtEnabled);
|
|
117
133
|
await db.open();
|
|
118
134
|
}
|
|
119
135
|
managedDb = db;
|
|
@@ -128,11 +144,16 @@ export async function createDatabase(config) {
|
|
|
128
144
|
* @param config - Database name and version declarations.
|
|
129
145
|
* @returns An unopened Dexie instance with all versions declared.
|
|
130
146
|
*/
|
|
131
|
-
function buildDexie(config) {
|
|
147
|
+
function buildDexie(config, crdtEnabled = false) {
|
|
132
148
|
const db = new Dexie(config.name);
|
|
133
149
|
for (const ver of config.versions) {
|
|
134
|
-
/* Merge app tables with system tables — system tables always included.
|
|
135
|
-
|
|
150
|
+
/* Merge app tables with system tables — system tables always included.
|
|
151
|
+
* CRDT tables are only included when the CRDT subsystem is enabled. */
|
|
152
|
+
const mergedStores = {
|
|
153
|
+
...ver.stores,
|
|
154
|
+
...SYSTEM_TABLES,
|
|
155
|
+
...(crdtEnabled ? CRDT_SYSTEM_TABLES : {})
|
|
156
|
+
};
|
|
136
157
|
if (ver.upgrade) {
|
|
137
158
|
db.version(ver.version).stores(mergedStores).upgrade(ver.upgrade);
|
|
138
159
|
}
|
package/dist/database.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.js","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AA+B1B,gFAAgF;AAChF,gBAAgB;AAChB,gFAAgF;AAEhF;;;;;;;;;GASG;AACH,MAAM,aAAa,GAA2B;IAC5C,SAAS,EAAE,kCAAkC;IAC7C,eAAe,EAAE,uCAAuC;IACxD,kBAAkB,EAAE,IAAI;IACxB,cAAc,EAAE,IAAI;IACpB,gBAAgB,EAAE,IAAI;CACvB,CAAC;AAEF,gFAAgF;AAChF,eAAe;AACf,gFAAgF;AAEhF,kFAAkF;AAClF,IAAI,SAAS,GAAiB,IAAI,CAAC;AAEnC,gFAAgF;AAChF,oBAAoB;AACpB,gFAAgF;AAEhF;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,MAAsB;
|
|
1
|
+
{"version":3,"file":"database.js","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"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"}
|