@affectively/dash 5.0.1 → 5.1.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/dist/src/sync/aeon/config.d.ts +21 -0
- package/dist/src/sync/aeon/config.js +14 -0
- package/dist/src/sync/aeon/delta-adapter.d.ts +62 -0
- package/dist/src/sync/aeon/delta-adapter.js +98 -0
- package/dist/src/sync/aeon/index.d.ts +18 -0
- package/dist/src/sync/aeon/index.js +19 -0
- package/dist/src/sync/aeon/offline-adapter.d.ts +110 -0
- package/dist/src/sync/aeon/offline-adapter.js +223 -0
- package/dist/src/sync/aeon/presence-adapter.d.ts +114 -0
- package/dist/src/sync/aeon/presence-adapter.js +157 -0
- package/dist/src/sync/aeon/schema-adapter.d.ts +95 -0
- package/dist/src/sync/aeon/schema-adapter.js +163 -0
- package/dist/src/sync/hybrid-provider.d.ts +67 -2
- package/dist/src/sync/hybrid-provider.js +128 -9
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -1
|
@@ -6,6 +6,17 @@ import * as decoding from 'lib0/decoding';
|
|
|
6
6
|
import * as syncProtocol from 'y-protocols/sync';
|
|
7
7
|
// @ts-ignore
|
|
8
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
|
+
};
|
|
9
20
|
export class HybridProvider extends Observable {
|
|
10
21
|
doc;
|
|
11
22
|
ws = null;
|
|
@@ -17,12 +28,28 @@ export class HybridProvider extends Observable {
|
|
|
17
28
|
writer = null;
|
|
18
29
|
// "High Frequency" mode uses WebTransport for ephemeral data
|
|
19
30
|
highFrequencyMode = false;
|
|
20
|
-
|
|
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, } = {}) {
|
|
21
37
|
super();
|
|
22
38
|
this.url = url;
|
|
23
39
|
this.roomName = roomName;
|
|
24
40
|
this.doc = doc;
|
|
25
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
|
+
}
|
|
26
53
|
this.doc.on('update', this.onDocUpdate.bind(this));
|
|
27
54
|
this.awareness.on('update', this.onAwarenessUpdate.bind(this));
|
|
28
55
|
this.connect();
|
|
@@ -140,19 +167,28 @@ export class HybridProvider extends Observable {
|
|
|
140
167
|
}
|
|
141
168
|
}
|
|
142
169
|
handleMessage(buf) {
|
|
143
|
-
// Simple protocol: First byte is message type (0=Sync, 1=Awareness)
|
|
170
|
+
// Simple protocol: First byte is message type (0=Sync, 1=Awareness, 2=Delta)
|
|
144
171
|
// In strict binary mode, we might need a more robust header.
|
|
145
172
|
// For now assuming Y-protocol encoding.
|
|
146
173
|
// Note: The Relay DO sends raw messages back.
|
|
147
174
|
const decoder = decoding.createDecoder(buf);
|
|
148
175
|
const messageType = decoding.readVarUint(decoder);
|
|
149
176
|
switch (messageType) {
|
|
150
|
-
case
|
|
177
|
+
case MessageType.Sync:
|
|
151
178
|
syncProtocol.readSyncMessage(decoder, encoding.createEncoder(), this.doc, this);
|
|
152
179
|
break;
|
|
153
|
-
case
|
|
180
|
+
case MessageType.Awareness:
|
|
154
181
|
awarenessProtocol.applyAwarenessUpdate(this.awareness, decoding.readVarUint8Array(decoder), this);
|
|
155
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;
|
|
156
192
|
}
|
|
157
193
|
}
|
|
158
194
|
async send(message) {
|
|
@@ -170,10 +206,26 @@ export class HybridProvider extends Observable {
|
|
|
170
206
|
onDocUpdate(update, origin) {
|
|
171
207
|
if (origin === this)
|
|
172
208
|
return;
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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
|
+
}
|
|
177
229
|
}
|
|
178
230
|
onAwarenessUpdate({ added, updated, removed }, origin) {
|
|
179
231
|
if (origin === this)
|
|
@@ -189,10 +241,61 @@ export class HybridProvider extends Observable {
|
|
|
189
241
|
this.awareness.off('update', this.onAwarenessUpdate);
|
|
190
242
|
this.ws?.close();
|
|
191
243
|
this.wt?.close();
|
|
244
|
+
// Cleanup Aeon adapters
|
|
245
|
+
this.presenceAdapter?.destroy();
|
|
246
|
+
this.offlineAdapter?.destroy();
|
|
192
247
|
this.connected = false;
|
|
193
248
|
super.destroy();
|
|
194
249
|
}
|
|
195
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
|
+
// ============================================
|
|
196
299
|
// INTROSPECTION METHODS FOR DASH-STUDIO
|
|
197
300
|
// ============================================
|
|
198
301
|
/**
|
|
@@ -352,7 +455,23 @@ export class HybridProvider extends Observable {
|
|
|
352
455
|
peerCount: this.getPeerCount(),
|
|
353
456
|
states: this.getAwarenessStates()
|
|
354
457
|
},
|
|
355
|
-
document: this.getDocumentState()
|
|
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,
|
|
356
475
|
};
|
|
357
476
|
}
|
|
358
477
|
}
|