@affectively/dash 5.2.1 → 5.3.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.
- package/dist/index.d.ts +62 -0
- package/dist/index.js +31 -0
- package/dist/sync/index.d.ts +6 -0
- package/dist/sync/index.js +4 -0
- package/package.json +45 -66
- package/README.md +0 -193
- package/dist/src/api/firebase/auth/index.d.ts +0 -137
- package/dist/src/api/firebase/auth/index.js +0 -352
- package/dist/src/api/firebase/auth/providers.d.ts +0 -254
- package/dist/src/api/firebase/auth/providers.js +0 -518
- package/dist/src/api/firebase/database/index.d.ts +0 -108
- package/dist/src/api/firebase/database/index.js +0 -368
- package/dist/src/api/firebase/errors.d.ts +0 -15
- package/dist/src/api/firebase/errors.js +0 -215
- package/dist/src/api/firebase/firestore/data-types.d.ts +0 -116
- package/dist/src/api/firebase/firestore/data-types.js +0 -280
- package/dist/src/api/firebase/firestore/index.d.ts +0 -7
- package/dist/src/api/firebase/firestore/index.js +0 -13
- package/dist/src/api/firebase/firestore/listeners.d.ts +0 -20
- package/dist/src/api/firebase/firestore/listeners.js +0 -50
- package/dist/src/api/firebase/firestore/operations.d.ts +0 -123
- package/dist/src/api/firebase/firestore/operations.js +0 -490
- package/dist/src/api/firebase/firestore/query.d.ts +0 -118
- package/dist/src/api/firebase/firestore/query.js +0 -418
- package/dist/src/api/firebase/index.d.ts +0 -11
- package/dist/src/api/firebase/index.js +0 -17
- package/dist/src/api/firebase/storage/index.d.ts +0 -100
- package/dist/src/api/firebase/storage/index.js +0 -286
- package/dist/src/api/firebase/types.d.ts +0 -341
- package/dist/src/api/firebase/types.js +0 -4
- package/dist/src/auth/manager.d.ts +0 -182
- package/dist/src/auth/manager.js +0 -598
- package/dist/src/engine/ai.d.ts +0 -10
- package/dist/src/engine/ai.js +0 -76
- package/dist/src/engine/sqlite.d.ts +0 -298
- package/dist/src/engine/sqlite.js +0 -1088
- package/dist/src/engine/vec_extension.d.ts +0 -5
- package/dist/src/engine/vec_extension.js +0 -10
- package/dist/src/index.d.ts +0 -15
- package/dist/src/index.js +0 -24
- package/dist/src/mcp/server.d.ts +0 -8
- package/dist/src/mcp/server.js +0 -87
- package/dist/src/reactivity/signal.d.ts +0 -3
- package/dist/src/reactivity/signal.js +0 -31
- package/dist/src/schema/lens.d.ts +0 -29
- package/dist/src/schema/lens.js +0 -122
- package/dist/src/sync/aeon/config.d.ts +0 -21
- package/dist/src/sync/aeon/config.js +0 -14
- package/dist/src/sync/aeon/delta-adapter.d.ts +0 -62
- package/dist/src/sync/aeon/delta-adapter.js +0 -98
- package/dist/src/sync/aeon/index.d.ts +0 -18
- package/dist/src/sync/aeon/index.js +0 -19
- package/dist/src/sync/aeon/offline-adapter.d.ts +0 -110
- package/dist/src/sync/aeon/offline-adapter.js +0 -227
- package/dist/src/sync/aeon/presence-adapter.d.ts +0 -114
- package/dist/src/sync/aeon/presence-adapter.js +0 -157
- package/dist/src/sync/aeon/schema-adapter.d.ts +0 -95
- package/dist/src/sync/aeon/schema-adapter.js +0 -163
- package/dist/src/sync/backup.d.ts +0 -12
- package/dist/src/sync/backup.js +0 -44
- package/dist/src/sync/connection.d.ts +0 -20
- package/dist/src/sync/connection.js +0 -50
- package/dist/src/sync/d1-provider.d.ts +0 -97
- package/dist/src/sync/d1-provider.js +0 -345
- package/dist/src/sync/hybrid-provider.d.ts +0 -172
- package/dist/src/sync/hybrid-provider.js +0 -477
- package/dist/src/sync/provider.d.ts +0 -11
- package/dist/src/sync/provider.js +0 -67
- package/dist/src/sync/verify.d.ts +0 -1
- package/dist/src/sync/verify.js +0 -23
- package/dist/tsconfig.tsbuildinfo +0 -1
|
@@ -1,477 +0,0 @@
|
|
|
1
|
-
import * as Y from 'yjs';
|
|
2
|
-
import { Observable } from 'lib0/observable';
|
|
3
|
-
import * as encoding from 'lib0/encoding';
|
|
4
|
-
import * as decoding from 'lib0/decoding';
|
|
5
|
-
// @ts-ignore
|
|
6
|
-
import * as syncProtocol from 'y-protocols/sync';
|
|
7
|
-
// @ts-ignore
|
|
8
|
-
import * as awarenessProtocol from 'y-protocols/awareness';
|
|
9
|
-
// Aeon integration
|
|
10
|
-
import { defaultAeonConfig } from './aeon/config.js';
|
|
11
|
-
import { DashDeltaAdapter } from './aeon/delta-adapter.js';
|
|
12
|
-
import { DashPresenceAdapter } from './aeon/presence-adapter.js';
|
|
13
|
-
import { DashOfflineAdapter } from './aeon/offline-adapter.js';
|
|
14
|
-
// Message types
|
|
15
|
-
const MessageType = {
|
|
16
|
-
Sync: 0,
|
|
17
|
-
Awareness: 1,
|
|
18
|
-
Delta: 2, // New: Aeon delta-compressed sync
|
|
19
|
-
};
|
|
20
|
-
export class HybridProvider extends Observable {
|
|
21
|
-
doc;
|
|
22
|
-
ws = null;
|
|
23
|
-
wt = null;
|
|
24
|
-
connected = false;
|
|
25
|
-
url;
|
|
26
|
-
roomName;
|
|
27
|
-
awareness;
|
|
28
|
-
writer = null;
|
|
29
|
-
// "High Frequency" mode uses WebTransport for ephemeral data
|
|
30
|
-
highFrequencyMode = false;
|
|
31
|
-
// Aeon integration
|
|
32
|
-
aeonConfig;
|
|
33
|
-
deltaAdapter = null;
|
|
34
|
-
presenceAdapter = null;
|
|
35
|
-
offlineAdapter = null;
|
|
36
|
-
constructor(url, roomName, doc, { awareness = new awarenessProtocol.Awareness(doc), aeonConfig = defaultAeonConfig, } = {}) {
|
|
37
|
-
super();
|
|
38
|
-
this.url = url;
|
|
39
|
-
this.roomName = roomName;
|
|
40
|
-
this.doc = doc;
|
|
41
|
-
this.awareness = awareness;
|
|
42
|
-
this.aeonConfig = aeonConfig;
|
|
43
|
-
// Initialize Aeon adapters
|
|
44
|
-
if (aeonConfig.enableDeltaSync) {
|
|
45
|
-
this.deltaAdapter = new DashDeltaAdapter(roomName, aeonConfig.deltaThreshold);
|
|
46
|
-
}
|
|
47
|
-
if (aeonConfig.enableRichPresence) {
|
|
48
|
-
this.presenceAdapter = new DashPresenceAdapter(roomName, awareness);
|
|
49
|
-
}
|
|
50
|
-
if (aeonConfig.enableOfflineQueue) {
|
|
51
|
-
this.offlineAdapter = new DashOfflineAdapter(doc, roomName, aeonConfig.maxOfflineQueueSize, aeonConfig.maxOfflineRetries);
|
|
52
|
-
}
|
|
53
|
-
this.doc.on('update', this.onDocUpdate.bind(this));
|
|
54
|
-
this.awareness.on('update', this.onAwarenessUpdate.bind(this));
|
|
55
|
-
this.connect();
|
|
56
|
-
}
|
|
57
|
-
connect() {
|
|
58
|
-
this.connectWebSocket();
|
|
59
|
-
}
|
|
60
|
-
connectWebSocket() {
|
|
61
|
-
// Protocol: switch http/https to ws/wss
|
|
62
|
-
// Protocol: switch http/https to ws/wss
|
|
63
|
-
// 1. Get Token
|
|
64
|
-
// Ideally await this before connecting, but construction is sync.
|
|
65
|
-
// We'll make connect async internally or fire-and-forget with token wait.
|
|
66
|
-
this.getAuthToken().then(token => {
|
|
67
|
-
const wsUrl = this.url.replace(/^http/, 'ws') + '/sync/' + this.roomName + '?token=' + token;
|
|
68
|
-
this.ws = new WebSocket(wsUrl);
|
|
69
|
-
this.ws.binaryType = 'arraybuffer';
|
|
70
|
-
this.ws.onopen = () => {
|
|
71
|
-
this.connected = true;
|
|
72
|
-
this.emit('status', [{ status: 'connected' }]);
|
|
73
|
-
this.sendSyncStep1();
|
|
74
|
-
};
|
|
75
|
-
// ... rest of event handlers
|
|
76
|
-
this.ws.onmessage = (event) => {
|
|
77
|
-
this.handleMessage(new Uint8Array(event.data));
|
|
78
|
-
};
|
|
79
|
-
this.ws.onclose = () => {
|
|
80
|
-
this.connected = false;
|
|
81
|
-
this.ws = null;
|
|
82
|
-
this.emit('status', [{ status: 'disconnected' }]);
|
|
83
|
-
// Reconnect logic
|
|
84
|
-
setTimeout(() => this.connectWebSocket(), 3000);
|
|
85
|
-
};
|
|
86
|
-
this.ws.onerror = (err) => {
|
|
87
|
-
console.error('WebSocket error', err);
|
|
88
|
-
};
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
async getAuthToken() {
|
|
92
|
-
// Lazy load auth to avoid circular dependency issues if any
|
|
93
|
-
const { auth } = await import('../auth/manager.js');
|
|
94
|
-
// For MVP, we assume the Relay allows any DID to connect if they sign it.
|
|
95
|
-
// In prod, you'd know the Relay's DID.
|
|
96
|
-
return auth.issueRoomToken("did:web:relay.buley.dev", this.roomName);
|
|
97
|
-
}
|
|
98
|
-
async enterHighFrequencyMode() {
|
|
99
|
-
if (this.highFrequencyMode)
|
|
100
|
-
return;
|
|
101
|
-
try {
|
|
102
|
-
// Connect WebTransport
|
|
103
|
-
// Just an example URL construction, depends on server routing
|
|
104
|
-
const wtUrl = this.url + '/sync/' + this.roomName;
|
|
105
|
-
this.wt = new WebTransport(wtUrl);
|
|
106
|
-
await this.wt.ready;
|
|
107
|
-
const stream = await this.wt.createBidirectionalStream();
|
|
108
|
-
this.writer = stream.writable;
|
|
109
|
-
this.readLoop(stream.readable);
|
|
110
|
-
this.highFrequencyMode = true;
|
|
111
|
-
console.log('Upgraded to WebTransport (High Frequency Mode)');
|
|
112
|
-
}
|
|
113
|
-
catch (e) {
|
|
114
|
-
console.error('Failed to upgrade to WebTransport', e);
|
|
115
|
-
// Fallback: stay on WebSocket
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
sendSyncStep1() {
|
|
119
|
-
const encoder = encoding.createEncoder();
|
|
120
|
-
encoding.writeVarUint(encoder, 0); // MessageType.Sync
|
|
121
|
-
syncProtocol.writeSyncStep1(encoder, this.doc);
|
|
122
|
-
this.send(encoding.toUint8Array(encoder));
|
|
123
|
-
}
|
|
124
|
-
async readLoop(readable) {
|
|
125
|
-
let reader;
|
|
126
|
-
try {
|
|
127
|
-
// @ts-ignore
|
|
128
|
-
reader = readable.getReader({ mode: 'byob' });
|
|
129
|
-
}
|
|
130
|
-
catch (e) {
|
|
131
|
-
reader = readable.getReader();
|
|
132
|
-
}
|
|
133
|
-
// Pre-allocate buffer (64KB) to emulate Zero-Copy / WASM Heap view
|
|
134
|
-
// In a future update, this could be a view into `sqlite3.wasm.memory`.
|
|
135
|
-
let buffer = new Uint8Array(65536);
|
|
136
|
-
try {
|
|
137
|
-
while (true) {
|
|
138
|
-
let result;
|
|
139
|
-
if (reader.readAtLeast) {
|
|
140
|
-
// BYOB Reader
|
|
141
|
-
// We pass the view. The reader detaches it and returns a new view (potentially same backing store).
|
|
142
|
-
result = await reader.read(new Uint8Array(buffer.buffer, 0, buffer.byteLength));
|
|
143
|
-
if (result.value) {
|
|
144
|
-
buffer = result.value; // Update our reference to the valid buffer
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
else {
|
|
148
|
-
// Default Reader
|
|
149
|
-
result = await reader.read();
|
|
150
|
-
}
|
|
151
|
-
if (result.done)
|
|
152
|
-
break;
|
|
153
|
-
if (result.value) {
|
|
154
|
-
// Processing: In true zero-copy, we'd pass the offset/length to SQL directly.
|
|
155
|
-
// Here we pass the view.
|
|
156
|
-
this.handleMessage(result.value);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
catch (e) {
|
|
161
|
-
console.error('WebTransport Read loop error', e);
|
|
162
|
-
}
|
|
163
|
-
finally {
|
|
164
|
-
this.highFrequencyMode = false;
|
|
165
|
-
this.writer = null;
|
|
166
|
-
this.wt = null;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
handleMessage(buf) {
|
|
170
|
-
// Simple protocol: First byte is message type (0=Sync, 1=Awareness, 2=Delta)
|
|
171
|
-
// In strict binary mode, we might need a more robust header.
|
|
172
|
-
// For now assuming Y-protocol encoding.
|
|
173
|
-
// Note: The Relay DO sends raw messages back.
|
|
174
|
-
const decoder = decoding.createDecoder(buf);
|
|
175
|
-
const messageType = decoding.readVarUint(decoder);
|
|
176
|
-
switch (messageType) {
|
|
177
|
-
case MessageType.Sync:
|
|
178
|
-
syncProtocol.readSyncMessage(decoder, encoding.createEncoder(), this.doc, this);
|
|
179
|
-
break;
|
|
180
|
-
case MessageType.Awareness:
|
|
181
|
-
awarenessProtocol.applyAwarenessUpdate(this.awareness, decoding.readVarUint8Array(decoder), this);
|
|
182
|
-
break;
|
|
183
|
-
case MessageType.Delta:
|
|
184
|
-
// Handle Aeon delta-compressed sync
|
|
185
|
-
if (this.deltaAdapter) {
|
|
186
|
-
const deltaPayloadBytes = decoding.readVarUint8Array(decoder);
|
|
187
|
-
const deltaPayload = this.deltaAdapter.decodePayload(deltaPayloadBytes);
|
|
188
|
-
const update = this.deltaAdapter.unwrapDelta(deltaPayload);
|
|
189
|
-
Y.applyUpdate(this.doc, update, this);
|
|
190
|
-
}
|
|
191
|
-
break;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
async send(message) {
|
|
195
|
-
if (this.writer && this.highFrequencyMode) {
|
|
196
|
-
// High Priority -> WebTransport
|
|
197
|
-
const writer = this.writer.getWriter();
|
|
198
|
-
await writer.write(message);
|
|
199
|
-
writer.releaseLock();
|
|
200
|
-
}
|
|
201
|
-
else if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
202
|
-
// Default -> WebSocket
|
|
203
|
-
this.ws.send(message);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
onDocUpdate(update, origin) {
|
|
207
|
-
if (origin === this)
|
|
208
|
-
return;
|
|
209
|
-
// Check if we should queue (offline)
|
|
210
|
-
if (this.offlineAdapter?.shouldQueue()) {
|
|
211
|
-
this.offlineAdapter.queueUpdate(update);
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
// Use delta compression if enabled
|
|
215
|
-
if (this.deltaAdapter) {
|
|
216
|
-
const deltaPayload = this.deltaAdapter.wrapUpdate(update, origin);
|
|
217
|
-
const encoder = encoding.createEncoder();
|
|
218
|
-
encoding.writeVarUint(encoder, MessageType.Delta);
|
|
219
|
-
encoding.writeVarUint8Array(encoder, this.deltaAdapter.encodePayload(deltaPayload));
|
|
220
|
-
this.send(encoding.toUint8Array(encoder));
|
|
221
|
-
}
|
|
222
|
-
else {
|
|
223
|
-
// Standard Yjs sync
|
|
224
|
-
const encoder = encoding.createEncoder();
|
|
225
|
-
encoding.writeVarUint(encoder, MessageType.Sync);
|
|
226
|
-
syncProtocol.writeUpdate(encoder, update);
|
|
227
|
-
this.send(encoding.toUint8Array(encoder));
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
onAwarenessUpdate({ added, updated, removed }, origin) {
|
|
231
|
-
if (origin === this)
|
|
232
|
-
return;
|
|
233
|
-
const changedClients = added.concat(updated).concat(removed);
|
|
234
|
-
const encoder = encoding.createEncoder();
|
|
235
|
-
encoding.writeVarUint(encoder, 1); // MessageType.Awareness
|
|
236
|
-
encoding.writeVarUint8Array(encoder, awarenessProtocol.encodeAwarenessUpdate(this.awareness, changedClients));
|
|
237
|
-
this.send(encoding.toUint8Array(encoder));
|
|
238
|
-
}
|
|
239
|
-
destroy() {
|
|
240
|
-
this.doc.off('update', this.onDocUpdate);
|
|
241
|
-
this.awareness.off('update', this.onAwarenessUpdate);
|
|
242
|
-
this.ws?.close();
|
|
243
|
-
this.wt?.close();
|
|
244
|
-
// Cleanup Aeon adapters
|
|
245
|
-
this.presenceAdapter?.destroy();
|
|
246
|
-
this.offlineAdapter?.destroy();
|
|
247
|
-
this.connected = false;
|
|
248
|
-
super.destroy();
|
|
249
|
-
}
|
|
250
|
-
// ============================================
|
|
251
|
-
// AEON ADAPTER ACCESSORS
|
|
252
|
-
// ============================================
|
|
253
|
-
/**
|
|
254
|
-
* Get the delta adapter for compression stats
|
|
255
|
-
*/
|
|
256
|
-
getDeltaAdapter() {
|
|
257
|
-
return this.deltaAdapter;
|
|
258
|
-
}
|
|
259
|
-
/**
|
|
260
|
-
* Get the presence adapter for rich presence features
|
|
261
|
-
*/
|
|
262
|
-
getPresenceAdapter() {
|
|
263
|
-
return this.presenceAdapter;
|
|
264
|
-
}
|
|
265
|
-
/**
|
|
266
|
-
* Get the offline adapter for queue management
|
|
267
|
-
*/
|
|
268
|
-
getOfflineAdapter() {
|
|
269
|
-
return this.offlineAdapter;
|
|
270
|
-
}
|
|
271
|
-
/**
|
|
272
|
-
* Get Aeon configuration
|
|
273
|
-
*/
|
|
274
|
-
getAeonConfig() {
|
|
275
|
-
return this.aeonConfig;
|
|
276
|
-
}
|
|
277
|
-
/**
|
|
278
|
-
* Process offline queue when back online
|
|
279
|
-
*/
|
|
280
|
-
async processOfflineQueue() {
|
|
281
|
-
if (!this.offlineAdapter) {
|
|
282
|
-
return { synced: 0, failed: 0 };
|
|
283
|
-
}
|
|
284
|
-
return this.offlineAdapter.processQueue(async (update) => {
|
|
285
|
-
const encoder = encoding.createEncoder();
|
|
286
|
-
if (this.deltaAdapter) {
|
|
287
|
-
const deltaPayload = this.deltaAdapter.wrapUpdate(update);
|
|
288
|
-
encoding.writeVarUint(encoder, MessageType.Delta);
|
|
289
|
-
encoding.writeVarUint8Array(encoder, this.deltaAdapter.encodePayload(deltaPayload));
|
|
290
|
-
}
|
|
291
|
-
else {
|
|
292
|
-
encoding.writeVarUint(encoder, MessageType.Sync);
|
|
293
|
-
syncProtocol.writeUpdate(encoder, update);
|
|
294
|
-
}
|
|
295
|
-
await this.send(encoding.toUint8Array(encoder));
|
|
296
|
-
});
|
|
297
|
-
}
|
|
298
|
-
// ============================================
|
|
299
|
-
// INTROSPECTION METHODS FOR DASH-STUDIO
|
|
300
|
-
// ============================================
|
|
301
|
-
/**
|
|
302
|
-
* Get comprehensive connection status
|
|
303
|
-
*/
|
|
304
|
-
getConnectionStatus() {
|
|
305
|
-
let wsState = 'closed';
|
|
306
|
-
if (this.ws) {
|
|
307
|
-
switch (this.ws.readyState) {
|
|
308
|
-
case WebSocket.CONNECTING:
|
|
309
|
-
wsState = 'connecting';
|
|
310
|
-
break;
|
|
311
|
-
case WebSocket.OPEN:
|
|
312
|
-
wsState = 'open';
|
|
313
|
-
break;
|
|
314
|
-
case WebSocket.CLOSING:
|
|
315
|
-
wsState = 'closing';
|
|
316
|
-
break;
|
|
317
|
-
case WebSocket.CLOSED:
|
|
318
|
-
wsState = 'closed';
|
|
319
|
-
break;
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
return {
|
|
323
|
-
connected: this.connected,
|
|
324
|
-
roomName: this.roomName,
|
|
325
|
-
url: this.url,
|
|
326
|
-
websocket: {
|
|
327
|
-
state: wsState,
|
|
328
|
-
connected: this.ws !== null && this.ws.readyState === WebSocket.OPEN
|
|
329
|
-
},
|
|
330
|
-
webTransport: {
|
|
331
|
-
connected: this.wt !== null,
|
|
332
|
-
highFrequencyMode: this.highFrequencyMode
|
|
333
|
-
},
|
|
334
|
-
transport: this.highFrequencyMode ? 'WebTransport' : 'WebSocket'
|
|
335
|
-
};
|
|
336
|
-
}
|
|
337
|
-
/**
|
|
338
|
-
* Get all awareness states from connected peers
|
|
339
|
-
*/
|
|
340
|
-
getAwarenessStates() {
|
|
341
|
-
const states = [];
|
|
342
|
-
const awarenessStates = this.awareness.getStates();
|
|
343
|
-
awarenessStates.forEach((state, clientId) => {
|
|
344
|
-
states.push({
|
|
345
|
-
clientId,
|
|
346
|
-
state,
|
|
347
|
-
isLocal: clientId === this.awareness.clientID
|
|
348
|
-
});
|
|
349
|
-
});
|
|
350
|
-
return states;
|
|
351
|
-
}
|
|
352
|
-
/**
|
|
353
|
-
* Get the local client ID
|
|
354
|
-
*/
|
|
355
|
-
getLocalClientId() {
|
|
356
|
-
return this.awareness.clientID;
|
|
357
|
-
}
|
|
358
|
-
/**
|
|
359
|
-
* Get connected peer count (excluding local)
|
|
360
|
-
*/
|
|
361
|
-
getPeerCount() {
|
|
362
|
-
const states = this.awareness.getStates();
|
|
363
|
-
return Math.max(0, states.size - 1); // Exclude self
|
|
364
|
-
}
|
|
365
|
-
/**
|
|
366
|
-
* Get document state information
|
|
367
|
-
*/
|
|
368
|
-
getDocumentState() {
|
|
369
|
-
const stateVector = Y.encodeStateVector(this.doc);
|
|
370
|
-
const update = Y.encodeStateAsUpdate(this.doc);
|
|
371
|
-
// Get shared types info
|
|
372
|
-
const sharedTypes = [];
|
|
373
|
-
this.doc.share.forEach((type, name) => {
|
|
374
|
-
let typeKind = 'unknown';
|
|
375
|
-
let size = 0;
|
|
376
|
-
if (type instanceof Y.Map) {
|
|
377
|
-
typeKind = 'YMap';
|
|
378
|
-
size = type.size;
|
|
379
|
-
}
|
|
380
|
-
else if (type instanceof Y.Array) {
|
|
381
|
-
typeKind = 'YArray';
|
|
382
|
-
size = type.length;
|
|
383
|
-
}
|
|
384
|
-
else if (type instanceof Y.Text) {
|
|
385
|
-
typeKind = 'YText';
|
|
386
|
-
size = type.length;
|
|
387
|
-
}
|
|
388
|
-
else if (type instanceof Y.XmlFragment) {
|
|
389
|
-
typeKind = 'YXmlFragment';
|
|
390
|
-
size = type.length;
|
|
391
|
-
}
|
|
392
|
-
sharedTypes.push({
|
|
393
|
-
name,
|
|
394
|
-
type: typeKind,
|
|
395
|
-
size
|
|
396
|
-
});
|
|
397
|
-
});
|
|
398
|
-
return {
|
|
399
|
-
clientId: this.doc.clientID,
|
|
400
|
-
guid: this.doc.guid,
|
|
401
|
-
stateVectorSize: stateVector.byteLength,
|
|
402
|
-
updateSize: update.byteLength,
|
|
403
|
-
sharedTypes,
|
|
404
|
-
transactionCount: 0, // Yjs doesn't expose this directly
|
|
405
|
-
gcEnabled: this.doc.gc
|
|
406
|
-
};
|
|
407
|
-
}
|
|
408
|
-
/**
|
|
409
|
-
* Get a snapshot of the Yjs document for inspection
|
|
410
|
-
*/
|
|
411
|
-
getDocumentSnapshot() {
|
|
412
|
-
const content = {};
|
|
413
|
-
this.doc.share.forEach((type, name) => {
|
|
414
|
-
try {
|
|
415
|
-
if (type instanceof Y.Map) {
|
|
416
|
-
content[name] = type.toJSON();
|
|
417
|
-
}
|
|
418
|
-
else if (type instanceof Y.Array) {
|
|
419
|
-
content[name] = type.toJSON();
|
|
420
|
-
}
|
|
421
|
-
else if (type instanceof Y.Text) {
|
|
422
|
-
content[name] = type.toString();
|
|
423
|
-
}
|
|
424
|
-
else if (type instanceof Y.XmlFragment) {
|
|
425
|
-
content[name] = type.toString();
|
|
426
|
-
}
|
|
427
|
-
else {
|
|
428
|
-
content[name] = '[unsupported type]';
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
catch (e) {
|
|
432
|
-
content[name] = '[error reading content]';
|
|
433
|
-
}
|
|
434
|
-
});
|
|
435
|
-
return {
|
|
436
|
-
timestamp: new Date().toISOString(),
|
|
437
|
-
roomName: this.roomName,
|
|
438
|
-
content
|
|
439
|
-
};
|
|
440
|
-
}
|
|
441
|
-
/**
|
|
442
|
-
* Set local awareness state for introspection (admin view)
|
|
443
|
-
*/
|
|
444
|
-
setLocalAwareness(state) {
|
|
445
|
-
this.awareness.setLocalState(state);
|
|
446
|
-
}
|
|
447
|
-
/**
|
|
448
|
-
* Get full provider status for debugging
|
|
449
|
-
*/
|
|
450
|
-
getProviderStatus() {
|
|
451
|
-
return {
|
|
452
|
-
connection: this.getConnectionStatus(),
|
|
453
|
-
awareness: {
|
|
454
|
-
localClientId: this.awareness.clientID,
|
|
455
|
-
peerCount: this.getPeerCount(),
|
|
456
|
-
states: this.getAwarenessStates()
|
|
457
|
-
},
|
|
458
|
-
document: this.getDocumentState(),
|
|
459
|
-
aeon: this.getAeonStatus()
|
|
460
|
-
};
|
|
461
|
-
}
|
|
462
|
-
/**
|
|
463
|
-
* Get Aeon-specific status
|
|
464
|
-
*/
|
|
465
|
-
getAeonStatus() {
|
|
466
|
-
return {
|
|
467
|
-
enabled: {
|
|
468
|
-
deltaSync: this.aeonConfig.enableDeltaSync,
|
|
469
|
-
richPresence: this.aeonConfig.enableRichPresence,
|
|
470
|
-
offlineQueue: this.aeonConfig.enableOfflineQueue,
|
|
471
|
-
},
|
|
472
|
-
delta: this.deltaAdapter?.getStats() ?? null,
|
|
473
|
-
offline: this.offlineAdapter?.getStats() ?? null,
|
|
474
|
-
presence: this.presenceAdapter?.getStats() ?? null,
|
|
475
|
-
};
|
|
476
|
-
}
|
|
477
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import * as Y from 'yjs';
|
|
2
|
-
export declare class YjsSqliteProvider {
|
|
3
|
-
private doc;
|
|
4
|
-
private roomName;
|
|
5
|
-
whenSynced: Promise<void>;
|
|
6
|
-
constructor(roomName: string, doc: Y.Doc);
|
|
7
|
-
private persistUpdate;
|
|
8
|
-
private loadState;
|
|
9
|
-
private toBase64;
|
|
10
|
-
private fromBase64;
|
|
11
|
-
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import * as Y from 'yjs';
|
|
2
|
-
import { dash } from '../engine/sqlite.js';
|
|
3
|
-
export class YjsSqliteProvider {
|
|
4
|
-
doc;
|
|
5
|
-
roomName;
|
|
6
|
-
whenSynced;
|
|
7
|
-
constructor(roomName, doc) {
|
|
8
|
-
this.roomName = roomName;
|
|
9
|
-
this.doc = doc;
|
|
10
|
-
// Listen to local updates
|
|
11
|
-
doc.on('update', (update, origin) => {
|
|
12
|
-
if (origin !== this) {
|
|
13
|
-
this.persistUpdate(update);
|
|
14
|
-
}
|
|
15
|
-
});
|
|
16
|
-
// Load initial state
|
|
17
|
-
this.whenSynced = this.loadState();
|
|
18
|
-
}
|
|
19
|
-
async persistUpdate(update) {
|
|
20
|
-
await dash.ready();
|
|
21
|
-
const blob = this.toBase64(update);
|
|
22
|
-
dash.execute('INSERT INTO dash_sync_updates (room, update_blob) VALUES (?, ?)', [this.roomName, blob]);
|
|
23
|
-
}
|
|
24
|
-
async loadState() {
|
|
25
|
-
await dash.ready();
|
|
26
|
-
// Ensure sync table exists
|
|
27
|
-
dash.execute(`
|
|
28
|
-
CREATE TABLE IF NOT EXISTS dash_sync_updates (
|
|
29
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
30
|
-
room TEXT,
|
|
31
|
-
update_blob TEXT,
|
|
32
|
-
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
33
|
-
)
|
|
34
|
-
`);
|
|
35
|
-
const rows = dash.execute('SELECT update_blob FROM dash_sync_updates WHERE room = ? ORDER BY id ASC', [this.roomName]);
|
|
36
|
-
console.log(`[YjsProvider] Loaded ${rows.length} updates for room ${this.roomName}`);
|
|
37
|
-
if (rows.length > 0) {
|
|
38
|
-
Y.transact(this.doc, () => {
|
|
39
|
-
rows.forEach((row) => {
|
|
40
|
-
const update = this.fromBase64(row.update_blob);
|
|
41
|
-
Y.applyUpdate(this.doc, update);
|
|
42
|
-
});
|
|
43
|
-
}, this);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
// Environment-safe Base64 helpers
|
|
47
|
-
toBase64(bytes) {
|
|
48
|
-
if (typeof Buffer !== 'undefined')
|
|
49
|
-
return Buffer.from(bytes).toString('base64');
|
|
50
|
-
let binary = '';
|
|
51
|
-
const len = bytes.byteLength;
|
|
52
|
-
for (let i = 0; i < len; i++) {
|
|
53
|
-
binary += String.fromCharCode(bytes[i]);
|
|
54
|
-
}
|
|
55
|
-
return btoa(binary);
|
|
56
|
-
}
|
|
57
|
-
fromBase64(str) {
|
|
58
|
-
if (typeof Buffer !== 'undefined')
|
|
59
|
-
return new Uint8Array(Buffer.from(str, 'base64'));
|
|
60
|
-
const binary = atob(str);
|
|
61
|
-
const bytes = new Uint8Array(binary.length);
|
|
62
|
-
for (let i = 0; i < binary.length; i++) {
|
|
63
|
-
bytes[i] = binary.charCodeAt(i);
|
|
64
|
-
}
|
|
65
|
-
return bytes;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/src/sync/verify.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import * as Y from 'yjs';
|
|
2
|
-
import { HybridProvider } from './hybrid-provider.js';
|
|
3
|
-
async function verify() {
|
|
4
|
-
console.log('Starting verification...');
|
|
5
|
-
const doc = new Y.Doc();
|
|
6
|
-
// Use deployed relay URL
|
|
7
|
-
const provider = new HybridProvider('https://dash-relay.taylorbuley.workers.dev', 'production-test-room', doc);
|
|
8
|
-
provider.on('status', (status) => {
|
|
9
|
-
console.log('Provider Status:', status);
|
|
10
|
-
});
|
|
11
|
-
// Wait for connection
|
|
12
|
-
await new Promise(r => setTimeout(r, 2000));
|
|
13
|
-
console.log('Attempting High Frequency Mode Upgrade...');
|
|
14
|
-
await provider.enterHighFrequencyMode();
|
|
15
|
-
// Create a change
|
|
16
|
-
doc.getText('test').insert(0, 'Hello World');
|
|
17
|
-
// Wait for sync
|
|
18
|
-
await new Promise(r => setTimeout(r, 1000));
|
|
19
|
-
console.log('Verification steps executed.');
|
|
20
|
-
provider.destroy();
|
|
21
|
-
process.exit(0);
|
|
22
|
-
}
|
|
23
|
-
verify().catch(console.error);
|