@affectively/aeon 1.0.0 → 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 +10 -0
- package/dist/compression/index.cjs +580 -0
- package/dist/compression/index.cjs.map +1 -0
- package/dist/compression/index.d.cts +189 -0
- package/dist/compression/index.d.ts +189 -0
- package/dist/compression/index.js +573 -0
- package/dist/compression/index.js.map +1 -0
- package/dist/core/index.d.cts +70 -5
- package/dist/core/index.d.ts +70 -5
- package/dist/crypto/index.cjs +100 -0
- package/dist/crypto/index.cjs.map +1 -0
- package/dist/crypto/index.d.cts +407 -0
- package/dist/crypto/index.d.ts +407 -0
- package/dist/crypto/index.js +96 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/distributed/index.cjs +420 -23
- package/dist/distributed/index.cjs.map +1 -1
- package/dist/distributed/index.d.cts +901 -2
- package/dist/distributed/index.d.ts +901 -2
- package/dist/distributed/index.js +420 -23
- package/dist/distributed/index.js.map +1 -1
- package/dist/index.cjs +1222 -55
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -811
- package/dist/index.d.ts +11 -811
- package/dist/index.js +1221 -56
- package/dist/index.js.map +1 -1
- package/dist/offline/index.cjs +419 -0
- package/dist/offline/index.cjs.map +1 -0
- package/dist/offline/index.d.cts +148 -0
- package/dist/offline/index.d.ts +148 -0
- package/dist/offline/index.js +415 -0
- package/dist/offline/index.js.map +1 -0
- package/dist/optimization/index.cjs +797 -0
- package/dist/optimization/index.cjs.map +1 -0
- package/dist/optimization/index.d.cts +347 -0
- package/dist/optimization/index.d.ts +347 -0
- package/dist/optimization/index.js +787 -0
- package/dist/optimization/index.js.map +1 -0
- package/dist/persistence/index.cjs +145 -0
- package/dist/persistence/index.cjs.map +1 -0
- package/dist/persistence/index.d.cts +63 -0
- package/dist/persistence/index.d.ts +63 -0
- package/dist/persistence/index.js +142 -0
- package/dist/persistence/index.js.map +1 -0
- package/dist/presence/index.cjs +489 -0
- package/dist/presence/index.cjs.map +1 -0
- package/dist/presence/index.d.cts +283 -0
- package/dist/presence/index.d.ts +283 -0
- package/dist/presence/index.js +485 -0
- package/dist/presence/index.js.map +1 -0
- package/dist/types-CMxO7QF0.d.cts +33 -0
- package/dist/types-CMxO7QF0.d.ts +33 -0
- package/dist/versioning/index.cjs +296 -14
- package/dist/versioning/index.cjs.map +1 -1
- package/dist/versioning/index.d.cts +66 -1
- package/dist/versioning/index.d.ts +66 -1
- package/dist/versioning/index.js +296 -14
- package/dist/versioning/index.js.map +1 -1
- package/package.json +51 -1
- package/dist/index-C_4CMV5c.d.cts +0 -1207
- package/dist/index-C_4CMV5c.d.ts +0 -1207
|
@@ -0,0 +1,797 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/utils/logger.ts
|
|
4
|
+
var consoleLogger = {
|
|
5
|
+
debug: (...args) => {
|
|
6
|
+
console.debug("[AEON:DEBUG]", ...args);
|
|
7
|
+
},
|
|
8
|
+
info: (...args) => {
|
|
9
|
+
console.info("[AEON:INFO]", ...args);
|
|
10
|
+
},
|
|
11
|
+
warn: (...args) => {
|
|
12
|
+
console.warn("[AEON:WARN]", ...args);
|
|
13
|
+
},
|
|
14
|
+
error: (...args) => {
|
|
15
|
+
console.error("[AEON:ERROR]", ...args);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
var currentLogger = consoleLogger;
|
|
19
|
+
function getLogger() {
|
|
20
|
+
return currentLogger;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// src/optimization/PrefetchingEngine.ts
|
|
24
|
+
var logger = getLogger();
|
|
25
|
+
var PrefetchingEngine = class {
|
|
26
|
+
operationHistory = [];
|
|
27
|
+
patterns = /* @__PURE__ */ new Map();
|
|
28
|
+
prefetchCache = /* @__PURE__ */ new Map();
|
|
29
|
+
maxHistoryEntries = 1e3;
|
|
30
|
+
maxCachePerType = 5;
|
|
31
|
+
prefetchTTL = 5 * 60 * 1e3;
|
|
32
|
+
// 5 minutes
|
|
33
|
+
predictionThreshold = 0.3;
|
|
34
|
+
stats = {
|
|
35
|
+
totalPrefetched: 0,
|
|
36
|
+
totalHits: 0,
|
|
37
|
+
totalMisses: 0,
|
|
38
|
+
totalOverwrites: 0,
|
|
39
|
+
hitRatio: 0,
|
|
40
|
+
bandwidthSaved: 0,
|
|
41
|
+
patternsDetected: 0,
|
|
42
|
+
predictionAccuracy: 0
|
|
43
|
+
};
|
|
44
|
+
lastPredictionTime = 0;
|
|
45
|
+
predictionInterval = 30 * 1e3;
|
|
46
|
+
constructor() {
|
|
47
|
+
logger.debug("[PrefetchingEngine] Initialized", {
|
|
48
|
+
ttl: this.prefetchTTL,
|
|
49
|
+
threshold: this.predictionThreshold
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Record operation for pattern analysis
|
|
54
|
+
*/
|
|
55
|
+
recordOperation(operationType, size) {
|
|
56
|
+
const now = Date.now();
|
|
57
|
+
this.operationHistory.push({
|
|
58
|
+
type: operationType,
|
|
59
|
+
timestamp: now,
|
|
60
|
+
size
|
|
61
|
+
});
|
|
62
|
+
if (this.operationHistory.length > this.maxHistoryEntries) {
|
|
63
|
+
this.operationHistory.shift();
|
|
64
|
+
}
|
|
65
|
+
if (Math.random() < 0.1) {
|
|
66
|
+
this.cleanExpiredPrefetches();
|
|
67
|
+
}
|
|
68
|
+
logger.debug("[PrefetchingEngine] Operation recorded", {
|
|
69
|
+
type: operationType,
|
|
70
|
+
size,
|
|
71
|
+
historySize: this.operationHistory.length
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Analyze patterns in operation history
|
|
76
|
+
*/
|
|
77
|
+
analyzePatterns() {
|
|
78
|
+
if (this.operationHistory.length < 5) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const patterns = /* @__PURE__ */ new Map();
|
|
82
|
+
for (let length = 2; length <= 3; length++) {
|
|
83
|
+
for (let i = 0; i < this.operationHistory.length - length; i++) {
|
|
84
|
+
const sequence = this.operationHistory.slice(i, i + length).map((op) => op.type);
|
|
85
|
+
const key = sequence.join(" \u2192 ");
|
|
86
|
+
if (!patterns.has(key)) {
|
|
87
|
+
patterns.set(key, {
|
|
88
|
+
sequence,
|
|
89
|
+
frequency: 0,
|
|
90
|
+
probability: 0,
|
|
91
|
+
lastOccurred: 0,
|
|
92
|
+
avgIntervalMs: 0
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
const pattern = patterns.get(key);
|
|
96
|
+
pattern.frequency++;
|
|
97
|
+
pattern.lastOccurred = Date.now();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const totalSequences = this.operationHistory.length;
|
|
101
|
+
for (const [key, pattern] of patterns.entries()) {
|
|
102
|
+
pattern.probability = Math.min(1, pattern.frequency / totalSequences);
|
|
103
|
+
}
|
|
104
|
+
this.patterns = patterns;
|
|
105
|
+
this.stats.patternsDetected = patterns.size;
|
|
106
|
+
logger.debug("[PrefetchingEngine] Patterns analyzed", {
|
|
107
|
+
patternsFound: patterns.size
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Predict next operations
|
|
112
|
+
*/
|
|
113
|
+
predictNextOperations(recentOperations) {
|
|
114
|
+
const now = Date.now();
|
|
115
|
+
if (now - this.lastPredictionTime > this.predictionInterval) {
|
|
116
|
+
this.analyzePatterns();
|
|
117
|
+
this.lastPredictionTime = now;
|
|
118
|
+
}
|
|
119
|
+
if (this.patterns.size === 0) {
|
|
120
|
+
return [];
|
|
121
|
+
}
|
|
122
|
+
const predictions = [];
|
|
123
|
+
const recentTypeSequence = recentOperations.slice(-3).map((op) => op.type).join(" \u2192 ");
|
|
124
|
+
for (const [key, pattern] of this.patterns.entries()) {
|
|
125
|
+
if (key.includes(recentTypeSequence)) {
|
|
126
|
+
const nextType = pattern.sequence[pattern.sequence.length - 1];
|
|
127
|
+
const prediction = {
|
|
128
|
+
operationType: nextType,
|
|
129
|
+
probability: pattern.probability,
|
|
130
|
+
reason: `Detected pattern: ${key}`,
|
|
131
|
+
shouldPrefetch: pattern.probability > this.predictionThreshold,
|
|
132
|
+
estimatedTimeMs: pattern.avgIntervalMs
|
|
133
|
+
};
|
|
134
|
+
predictions.push(prediction);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const deduped = Array.from(
|
|
138
|
+
new Map(predictions.map((p) => [p.operationType, p])).values()
|
|
139
|
+
).sort((a, b) => b.probability - a.probability);
|
|
140
|
+
logger.debug("[PrefetchingEngine] Predictions", {
|
|
141
|
+
predictions: deduped.slice(0, 3).map((p) => ({
|
|
142
|
+
type: p.operationType,
|
|
143
|
+
probability: (p.probability * 100).toFixed(1) + "%"
|
|
144
|
+
}))
|
|
145
|
+
});
|
|
146
|
+
return deduped;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Add prefetched batch
|
|
150
|
+
*/
|
|
151
|
+
addPrefetchedBatch(operationType, compressed, originalSize) {
|
|
152
|
+
if (!this.prefetchCache.has(operationType)) {
|
|
153
|
+
this.prefetchCache.set(operationType, []);
|
|
154
|
+
}
|
|
155
|
+
const cache = this.prefetchCache.get(operationType);
|
|
156
|
+
if (cache.length >= this.maxCachePerType) {
|
|
157
|
+
const oldest = cache.shift();
|
|
158
|
+
if (oldest.hitCount === 0) {
|
|
159
|
+
this.stats.totalMisses++;
|
|
160
|
+
} else {
|
|
161
|
+
this.stats.totalOverwrites++;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
const batch = {
|
|
165
|
+
id: `prefetch-${operationType}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
166
|
+
operationType,
|
|
167
|
+
compressed,
|
|
168
|
+
compressedSize: compressed.length,
|
|
169
|
+
originalSize,
|
|
170
|
+
compressionRatio: 1 - compressed.length / originalSize,
|
|
171
|
+
compressed_at: Date.now(),
|
|
172
|
+
created_at: Date.now(),
|
|
173
|
+
ttl: this.prefetchTTL,
|
|
174
|
+
expiresAt: Date.now() + this.prefetchTTL,
|
|
175
|
+
hitCount: 0,
|
|
176
|
+
missCount: 0
|
|
177
|
+
};
|
|
178
|
+
cache.push(batch);
|
|
179
|
+
this.stats.totalPrefetched++;
|
|
180
|
+
this.stats.bandwidthSaved += originalSize - compressed.length;
|
|
181
|
+
logger.debug("[PrefetchingEngine] Prefetched batch added", {
|
|
182
|
+
type: operationType,
|
|
183
|
+
id: batch.id,
|
|
184
|
+
ratio: (batch.compressionRatio * 100).toFixed(1) + "%"
|
|
185
|
+
});
|
|
186
|
+
return batch;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Try to use prefetched batch
|
|
190
|
+
*/
|
|
191
|
+
getPrefetchedBatch(operationType) {
|
|
192
|
+
const cache = this.prefetchCache.get(operationType);
|
|
193
|
+
if (!cache || cache.length === 0) {
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
const now = Date.now();
|
|
197
|
+
for (let i = 0; i < cache.length; i++) {
|
|
198
|
+
const batch = cache[i];
|
|
199
|
+
if (batch.expiresAt > now) {
|
|
200
|
+
batch.hitCount++;
|
|
201
|
+
this.stats.totalHits++;
|
|
202
|
+
this.updatePredictionAccuracy(true);
|
|
203
|
+
logger.debug("[PrefetchingEngine] Prefetch hit", {
|
|
204
|
+
type: operationType,
|
|
205
|
+
id: batch.id
|
|
206
|
+
});
|
|
207
|
+
return batch;
|
|
208
|
+
} else {
|
|
209
|
+
cache.splice(i, 1);
|
|
210
|
+
i--;
|
|
211
|
+
batch.missCount++;
|
|
212
|
+
this.stats.totalMisses++;
|
|
213
|
+
this.updatePredictionAccuracy(false);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Update prediction accuracy metric
|
|
220
|
+
*/
|
|
221
|
+
updatePredictionAccuracy(hit) {
|
|
222
|
+
const total = this.stats.totalHits + this.stats.totalMisses;
|
|
223
|
+
if (total === 0) return;
|
|
224
|
+
this.stats.predictionAccuracy = this.stats.totalHits / total;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Clean expired prefetches
|
|
228
|
+
*/
|
|
229
|
+
cleanExpiredPrefetches() {
|
|
230
|
+
const now = Date.now();
|
|
231
|
+
let cleanedCount = 0;
|
|
232
|
+
for (const [type, cache] of this.prefetchCache.entries()) {
|
|
233
|
+
for (let i = cache.length - 1; i >= 0; i--) {
|
|
234
|
+
if (cache[i].expiresAt < now) {
|
|
235
|
+
const batch = cache.splice(i, 1)[0];
|
|
236
|
+
if (batch.hitCount === 0) {
|
|
237
|
+
this.stats.totalMisses++;
|
|
238
|
+
}
|
|
239
|
+
cleanedCount++;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
if (cache.length === 0) {
|
|
243
|
+
this.prefetchCache.delete(type);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
if (cleanedCount > 0) {
|
|
247
|
+
logger.debug("[PrefetchingEngine] Cleaned expired prefetches", {
|
|
248
|
+
count: cleanedCount
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Get statistics
|
|
254
|
+
*/
|
|
255
|
+
getStats() {
|
|
256
|
+
const total = this.stats.totalHits + this.stats.totalMisses;
|
|
257
|
+
this.stats.hitRatio = total > 0 ? this.stats.totalHits / total : 0;
|
|
258
|
+
return { ...this.stats };
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Clear all caches
|
|
262
|
+
*/
|
|
263
|
+
clear() {
|
|
264
|
+
this.operationHistory = [];
|
|
265
|
+
this.patterns.clear();
|
|
266
|
+
this.prefetchCache.clear();
|
|
267
|
+
this.stats = {
|
|
268
|
+
totalPrefetched: 0,
|
|
269
|
+
totalHits: 0,
|
|
270
|
+
totalMisses: 0,
|
|
271
|
+
totalOverwrites: 0,
|
|
272
|
+
hitRatio: 0,
|
|
273
|
+
bandwidthSaved: 0,
|
|
274
|
+
patternsDetected: 0,
|
|
275
|
+
predictionAccuracy: 0
|
|
276
|
+
};
|
|
277
|
+
logger.debug("[PrefetchingEngine] Cleared all caches");
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
var prefetchingEngineInstance = null;
|
|
281
|
+
function getPrefetchingEngine() {
|
|
282
|
+
if (!prefetchingEngineInstance) {
|
|
283
|
+
prefetchingEngineInstance = new PrefetchingEngine();
|
|
284
|
+
}
|
|
285
|
+
return prefetchingEngineInstance;
|
|
286
|
+
}
|
|
287
|
+
function resetPrefetchingEngine() {
|
|
288
|
+
prefetchingEngineInstance = null;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// src/optimization/BatchTimingOptimizer.ts
|
|
292
|
+
var logger2 = getLogger();
|
|
293
|
+
var BatchTimingOptimizer = class {
|
|
294
|
+
networkHistory = [];
|
|
295
|
+
activityHistory = [];
|
|
296
|
+
stats = {
|
|
297
|
+
totalBatches: 0,
|
|
298
|
+
immediateDeliveries: 0,
|
|
299
|
+
deferredBatches: 0,
|
|
300
|
+
averageWaitTimeMs: 0,
|
|
301
|
+
averageDeliveryTimeMs: 0,
|
|
302
|
+
networkWindowsUsed: 0,
|
|
303
|
+
congestionAvoided: 0,
|
|
304
|
+
userFocusedOptimizations: 0
|
|
305
|
+
};
|
|
306
|
+
lastActivityTime = Date.now();
|
|
307
|
+
isUserActive = true;
|
|
308
|
+
congestionDetectionWindow = 60 * 1e3;
|
|
309
|
+
optimalBatchSize = 50 * 1024;
|
|
310
|
+
constructor() {
|
|
311
|
+
logger2.debug("[BatchTimingOptimizer] Initialized", {
|
|
312
|
+
congestionWindow: this.congestionDetectionWindow,
|
|
313
|
+
optimalBatchSize: this.optimalBatchSize
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Record network measurement
|
|
318
|
+
*/
|
|
319
|
+
recordNetworkMeasurement(latencyMs, bandwidthMbps) {
|
|
320
|
+
const quality = this.assessNetworkQuality(latencyMs, bandwidthMbps);
|
|
321
|
+
this.networkHistory.push({
|
|
322
|
+
latencyMs,
|
|
323
|
+
bandwidthMbps,
|
|
324
|
+
timestamp: Date.now(),
|
|
325
|
+
quality
|
|
326
|
+
});
|
|
327
|
+
if (this.networkHistory.length > 100) {
|
|
328
|
+
this.networkHistory.shift();
|
|
329
|
+
}
|
|
330
|
+
this.stats.networkWindowsUsed++;
|
|
331
|
+
logger2.debug("[BatchTimingOptimizer] Network measured", {
|
|
332
|
+
latency: latencyMs + "ms",
|
|
333
|
+
bandwidth: bandwidthMbps.toFixed(1) + " Mbps",
|
|
334
|
+
quality
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Assess network quality
|
|
339
|
+
*/
|
|
340
|
+
assessNetworkQuality(latencyMs, bandwidthMbps) {
|
|
341
|
+
if (latencyMs < 20 && bandwidthMbps > 10) return "excellent";
|
|
342
|
+
if (latencyMs < 50 && bandwidthMbps > 5) return "good";
|
|
343
|
+
if (latencyMs < 100 && bandwidthMbps > 2) return "fair";
|
|
344
|
+
return "poor";
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Detect congestion in network
|
|
348
|
+
*/
|
|
349
|
+
detectCongestion() {
|
|
350
|
+
const recentMeasurements = this.networkHistory.filter(
|
|
351
|
+
(m) => Date.now() - m.timestamp < this.congestionDetectionWindow
|
|
352
|
+
);
|
|
353
|
+
if (recentMeasurements.length < 3) {
|
|
354
|
+
return 0;
|
|
355
|
+
}
|
|
356
|
+
const poorCount = recentMeasurements.filter(
|
|
357
|
+
(m) => m.quality === "poor"
|
|
358
|
+
).length;
|
|
359
|
+
return poorCount / recentMeasurements.length;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Find next optimal network window
|
|
363
|
+
*/
|
|
364
|
+
findOptimalWindow() {
|
|
365
|
+
const now = Date.now();
|
|
366
|
+
const recentMeasurements = this.networkHistory.slice(-20);
|
|
367
|
+
if (recentMeasurements.length === 0) {
|
|
368
|
+
return {
|
|
369
|
+
startTime: now,
|
|
370
|
+
endTime: now + 1e3,
|
|
371
|
+
expectedDurationMs: 1e3,
|
|
372
|
+
latencyMs: 50,
|
|
373
|
+
bandwidthMbps: 5,
|
|
374
|
+
quality: "good",
|
|
375
|
+
isStable: true,
|
|
376
|
+
congestionLevel: 0,
|
|
377
|
+
recommendedBatchSize: this.optimalBatchSize
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
const avgLatency = recentMeasurements.reduce((sum, m) => sum + m.latencyMs, 0) / recentMeasurements.length;
|
|
381
|
+
const avgBandwidth = recentMeasurements.reduce((sum, m) => sum + m.bandwidthMbps, 0) / recentMeasurements.length;
|
|
382
|
+
const latencyVariance = Math.sqrt(
|
|
383
|
+
recentMeasurements.reduce(
|
|
384
|
+
(sum, m) => sum + Math.pow(m.latencyMs - avgLatency, 2),
|
|
385
|
+
0
|
|
386
|
+
) / recentMeasurements.length
|
|
387
|
+
) / avgLatency;
|
|
388
|
+
const isStable = latencyVariance < 0.2;
|
|
389
|
+
const congestionLevel = this.detectCongestion();
|
|
390
|
+
const quality = this.assessNetworkQuality(avgLatency, avgBandwidth);
|
|
391
|
+
const recommendedBatchSize = Math.max(
|
|
392
|
+
10 * 1024,
|
|
393
|
+
Math.min(500 * 1024, avgBandwidth * 1024 * 100 / 8)
|
|
394
|
+
);
|
|
395
|
+
return {
|
|
396
|
+
startTime: now,
|
|
397
|
+
endTime: now + (isStable ? 30 * 1e3 : 10 * 1e3),
|
|
398
|
+
expectedDurationMs: isStable ? 30 * 1e3 : 10 * 1e3,
|
|
399
|
+
latencyMs: avgLatency,
|
|
400
|
+
bandwidthMbps: avgBandwidth,
|
|
401
|
+
quality,
|
|
402
|
+
isStable,
|
|
403
|
+
congestionLevel,
|
|
404
|
+
recommendedBatchSize
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Get scheduling decision for a batch
|
|
409
|
+
*/
|
|
410
|
+
getSchedulingDecision(batchSize, batchPriority = "normal", isUserTriggered = false) {
|
|
411
|
+
const now = Date.now();
|
|
412
|
+
const currentWindow = this.findOptimalWindow();
|
|
413
|
+
const congestionLevel = this.detectCongestion();
|
|
414
|
+
let shouldSendNow = false;
|
|
415
|
+
let recommendedDelay = 0;
|
|
416
|
+
let reason = "";
|
|
417
|
+
let priority = batchPriority;
|
|
418
|
+
if (priority === "critical") {
|
|
419
|
+
shouldSendNow = true;
|
|
420
|
+
reason = "Critical operation (bypass optimization)";
|
|
421
|
+
} else if (isUserTriggered && this.isUserActive) {
|
|
422
|
+
shouldSendNow = true;
|
|
423
|
+
reason = "User-triggered operation";
|
|
424
|
+
priority = "high";
|
|
425
|
+
} else if (currentWindow.quality === "excellent" || currentWindow.quality === "good") {
|
|
426
|
+
if (congestionLevel < 0.3) {
|
|
427
|
+
shouldSendNow = true;
|
|
428
|
+
reason = "Good network conditions";
|
|
429
|
+
} else {
|
|
430
|
+
shouldSendNow = true;
|
|
431
|
+
reason = "Good network despite some congestion";
|
|
432
|
+
recommendedDelay = 1e3 + Math.random() * 2e3;
|
|
433
|
+
}
|
|
434
|
+
} else if (currentWindow.quality === "fair") {
|
|
435
|
+
if (priority === "high") {
|
|
436
|
+
shouldSendNow = true;
|
|
437
|
+
reason = "High priority despite fair network";
|
|
438
|
+
} else {
|
|
439
|
+
shouldSendNow = false;
|
|
440
|
+
reason = "Fair network: waiting for better window";
|
|
441
|
+
recommendedDelay = 30 * 1e3 + Math.random() * 30 * 1e3;
|
|
442
|
+
}
|
|
443
|
+
} else {
|
|
444
|
+
shouldSendNow = false;
|
|
445
|
+
reason = "Poor network conditions: deferring";
|
|
446
|
+
if (priority === "high") {
|
|
447
|
+
recommendedDelay = 60 * 1e3 + Math.random() * 30 * 1e3;
|
|
448
|
+
} else {
|
|
449
|
+
recommendedDelay = 120 * 1e3 + Math.random() * 60 * 1e3;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
const estimatedDeliveryMs = batchSize / (currentWindow.bandwidthMbps * 1024 * 1024 / 8) * 1e3 + currentWindow.latencyMs + recommendedDelay;
|
|
453
|
+
const decision = {
|
|
454
|
+
shouldSendNow,
|
|
455
|
+
nextOptimalWindowMs: now + recommendedDelay,
|
|
456
|
+
recommendedDelay,
|
|
457
|
+
reason,
|
|
458
|
+
priority,
|
|
459
|
+
estimatedDeliveryMs
|
|
460
|
+
};
|
|
461
|
+
logger2.debug("[BatchTimingOptimizer] Scheduling decision", {
|
|
462
|
+
size: (batchSize / 1024).toFixed(1) + " KB",
|
|
463
|
+
shouldSendNow,
|
|
464
|
+
delay: recommendedDelay + "ms",
|
|
465
|
+
reason
|
|
466
|
+
});
|
|
467
|
+
return decision;
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Apply scheduling and update stats
|
|
471
|
+
*/
|
|
472
|
+
applyScheduling(batchSize, sendNow, actualDelay) {
|
|
473
|
+
this.stats.totalBatches++;
|
|
474
|
+
if (sendNow) {
|
|
475
|
+
this.stats.immediateDeliveries++;
|
|
476
|
+
} else {
|
|
477
|
+
this.stats.deferredBatches++;
|
|
478
|
+
}
|
|
479
|
+
const totalWait = this.stats.averageWaitTimeMs * (this.stats.totalBatches - 1) + actualDelay;
|
|
480
|
+
this.stats.averageWaitTimeMs = totalWait / this.stats.totalBatches;
|
|
481
|
+
if (this.detectCongestion() > 0.3 && !sendNow) {
|
|
482
|
+
this.stats.congestionAvoided++;
|
|
483
|
+
}
|
|
484
|
+
if (this.isUserActive) {
|
|
485
|
+
this.stats.userFocusedOptimizations++;
|
|
486
|
+
}
|
|
487
|
+
this.stats.networkWindowsUsed++;
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Get optimal batch size recommendation
|
|
491
|
+
*/
|
|
492
|
+
getOptimalBatchSize() {
|
|
493
|
+
const window = this.findOptimalWindow();
|
|
494
|
+
return window.recommendedBatchSize;
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Get current network window
|
|
498
|
+
*/
|
|
499
|
+
getCurrentNetworkWindow() {
|
|
500
|
+
return this.findOptimalWindow();
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Set user activity state
|
|
504
|
+
*/
|
|
505
|
+
setUserActive(active) {
|
|
506
|
+
this.isUserActive = active;
|
|
507
|
+
if (active) {
|
|
508
|
+
this.lastActivityTime = Date.now();
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Get statistics
|
|
513
|
+
*/
|
|
514
|
+
getStats() {
|
|
515
|
+
return { ...this.stats };
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
518
|
+
* Clear history
|
|
519
|
+
*/
|
|
520
|
+
clear() {
|
|
521
|
+
this.networkHistory = [];
|
|
522
|
+
this.activityHistory = [];
|
|
523
|
+
this.stats = {
|
|
524
|
+
totalBatches: 0,
|
|
525
|
+
immediateDeliveries: 0,
|
|
526
|
+
deferredBatches: 0,
|
|
527
|
+
averageWaitTimeMs: 0,
|
|
528
|
+
averageDeliveryTimeMs: 0,
|
|
529
|
+
networkWindowsUsed: 0,
|
|
530
|
+
congestionAvoided: 0,
|
|
531
|
+
userFocusedOptimizations: 0
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
};
|
|
535
|
+
var batchTimingOptimizerInstance = null;
|
|
536
|
+
function getBatchTimingOptimizer() {
|
|
537
|
+
if (!batchTimingOptimizerInstance) {
|
|
538
|
+
batchTimingOptimizerInstance = new BatchTimingOptimizer();
|
|
539
|
+
}
|
|
540
|
+
return batchTimingOptimizerInstance;
|
|
541
|
+
}
|
|
542
|
+
function resetBatchTimingOptimizer() {
|
|
543
|
+
batchTimingOptimizerInstance = null;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// src/optimization/AdaptiveCompressionOptimizer.ts
|
|
547
|
+
var logger3 = getLogger();
|
|
548
|
+
var AdaptiveCompressionOptimizer = class {
|
|
549
|
+
currentLevel = 6;
|
|
550
|
+
networkProfile = {
|
|
551
|
+
estimatedSpeedKbps: 5e3,
|
|
552
|
+
latencyMs: 50,
|
|
553
|
+
isOnline: true,
|
|
554
|
+
isWifi: false,
|
|
555
|
+
isFast: true,
|
|
556
|
+
isSlow: false,
|
|
557
|
+
isEmpty: false
|
|
558
|
+
};
|
|
559
|
+
deviceProfile = {
|
|
560
|
+
cpuCores: 4,
|
|
561
|
+
cpuUtilization: 0.3,
|
|
562
|
+
memoryAvailableMB: 512,
|
|
563
|
+
memoryTotalMB: 1024,
|
|
564
|
+
isConstrained: false,
|
|
565
|
+
isPremium: false,
|
|
566
|
+
supportsWebWorkers: true,
|
|
567
|
+
supportsWebAssembly: true
|
|
568
|
+
};
|
|
569
|
+
compressionHistory = [];
|
|
570
|
+
stats = {
|
|
571
|
+
currentLevel: 6,
|
|
572
|
+
averageCompressionMs: 10,
|
|
573
|
+
averageRatio: 0.85,
|
|
574
|
+
levelsUsed: /* @__PURE__ */ new Set([6]),
|
|
575
|
+
adjustmentCount: 0,
|
|
576
|
+
totalBatches: 0,
|
|
577
|
+
networkCondition: "normal"
|
|
578
|
+
};
|
|
579
|
+
constructor() {
|
|
580
|
+
logger3.debug("[AdaptiveCompressionOptimizer] Initialized", {
|
|
581
|
+
level: this.currentLevel
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* Update network conditions
|
|
586
|
+
*/
|
|
587
|
+
updateNetworkConditions(speedKbps, latencyMs, isOnline) {
|
|
588
|
+
this.networkProfile.estimatedSpeedKbps = speedKbps;
|
|
589
|
+
if (latencyMs !== void 0) {
|
|
590
|
+
this.networkProfile.latencyMs = latencyMs;
|
|
591
|
+
}
|
|
592
|
+
if (isOnline !== void 0) {
|
|
593
|
+
this.networkProfile.isOnline = isOnline;
|
|
594
|
+
}
|
|
595
|
+
this.networkProfile.isFast = speedKbps > 5e3;
|
|
596
|
+
this.networkProfile.isSlow = speedKbps < 1e3;
|
|
597
|
+
this.networkProfile.isEmpty = speedKbps < 100;
|
|
598
|
+
if (isOnline === false) {
|
|
599
|
+
this.stats.networkCondition = "offline";
|
|
600
|
+
} else if (this.networkProfile.isSlow) {
|
|
601
|
+
this.stats.networkCondition = "slow";
|
|
602
|
+
} else if (this.networkProfile.isFast) {
|
|
603
|
+
this.stats.networkCondition = "fast";
|
|
604
|
+
} else {
|
|
605
|
+
this.stats.networkCondition = "normal";
|
|
606
|
+
}
|
|
607
|
+
logger3.debug("[AdaptiveCompressionOptimizer] Network updated", {
|
|
608
|
+
speedKbps,
|
|
609
|
+
condition: this.stats.networkCondition
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* Update device resource usage
|
|
614
|
+
*/
|
|
615
|
+
updateDeviceResources(cpuUtilization, memoryAvailableMB) {
|
|
616
|
+
this.deviceProfile.cpuUtilization = Math.max(
|
|
617
|
+
0,
|
|
618
|
+
Math.min(1, cpuUtilization)
|
|
619
|
+
);
|
|
620
|
+
this.deviceProfile.memoryAvailableMB = memoryAvailableMB;
|
|
621
|
+
this.deviceProfile.isConstrained = memoryAvailableMB < 512;
|
|
622
|
+
this.deviceProfile.isPremium = memoryAvailableMB > 2048;
|
|
623
|
+
logger3.debug("[AdaptiveCompressionOptimizer] Device resources updated", {
|
|
624
|
+
cpuUtilization: (cpuUtilization * 100).toFixed(1) + "%",
|
|
625
|
+
memoryAvailableMB
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Record compression performance
|
|
630
|
+
*/
|
|
631
|
+
recordCompressionPerformance(level, compressionMs, ratio) {
|
|
632
|
+
this.compressionHistory.push({
|
|
633
|
+
level,
|
|
634
|
+
ratio,
|
|
635
|
+
timeMs: compressionMs,
|
|
636
|
+
timestamp: Date.now()
|
|
637
|
+
});
|
|
638
|
+
if (this.compressionHistory.length > 100) {
|
|
639
|
+
this.compressionHistory.shift();
|
|
640
|
+
}
|
|
641
|
+
this.stats.totalBatches++;
|
|
642
|
+
this.stats.averageCompressionMs = this.compressionHistory.reduce((sum, h) => sum + h.timeMs, 0) / this.compressionHistory.length;
|
|
643
|
+
this.stats.averageRatio = this.compressionHistory.reduce((sum, h) => sum + h.ratio, 0) / this.compressionHistory.length;
|
|
644
|
+
}
|
|
645
|
+
/**
|
|
646
|
+
* Get compression recommendation based on conditions
|
|
647
|
+
*/
|
|
648
|
+
getRecommendedLevel() {
|
|
649
|
+
const networkFactor = this.calculateNetworkFactor();
|
|
650
|
+
const deviceFactor = this.calculateDeviceFactor();
|
|
651
|
+
const combinedFactor = (networkFactor + deviceFactor) / 2;
|
|
652
|
+
const recommendedLevel = Math.max(
|
|
653
|
+
1,
|
|
654
|
+
Math.min(9, Math.round(combinedFactor * 9))
|
|
655
|
+
);
|
|
656
|
+
const estimatedCompressionMs = this.estimateCompressionTime(recommendedLevel);
|
|
657
|
+
const estimatedRatio = this.estimateCompressionRatio(recommendedLevel);
|
|
658
|
+
let reason = "";
|
|
659
|
+
if (networkFactor < 0.3 && deviceFactor < 0.3) {
|
|
660
|
+
reason = "Slow network + constrained device: using level 1-2 (fast)";
|
|
661
|
+
} else if (networkFactor > 0.7 && deviceFactor > 0.7) {
|
|
662
|
+
reason = "Fast network + premium device: using level 8-9 (best compression)";
|
|
663
|
+
} else if (networkFactor > 0.7) {
|
|
664
|
+
reason = "Fast network: prioritizing compression ratio";
|
|
665
|
+
} else if (deviceFactor < 0.3) {
|
|
666
|
+
reason = "Constrained device: prioritizing speed";
|
|
667
|
+
} else {
|
|
668
|
+
reason = "Normal conditions: balanced compression level";
|
|
669
|
+
}
|
|
670
|
+
const recommendation = {
|
|
671
|
+
recommendedLevel,
|
|
672
|
+
reason,
|
|
673
|
+
confidence: this.compressionHistory.length > 10 ? 0.9 : 0.5,
|
|
674
|
+
estimatedCompressionMs,
|
|
675
|
+
estimatedRatio,
|
|
676
|
+
networkFactor,
|
|
677
|
+
deviceFactor
|
|
678
|
+
};
|
|
679
|
+
logger3.debug(
|
|
680
|
+
"[AdaptiveCompressionOptimizer] Recommendation",
|
|
681
|
+
recommendation
|
|
682
|
+
);
|
|
683
|
+
return recommendation;
|
|
684
|
+
}
|
|
685
|
+
/**
|
|
686
|
+
* Calculate network factor (0-1)
|
|
687
|
+
*/
|
|
688
|
+
calculateNetworkFactor() {
|
|
689
|
+
if (!this.networkProfile.isOnline) return 0;
|
|
690
|
+
const speedMbps = this.networkProfile.estimatedSpeedKbps / 1e3;
|
|
691
|
+
if (speedMbps < 0.1) return 0;
|
|
692
|
+
if (speedMbps < 1) return 0.1 + speedMbps / 1 * 0.2;
|
|
693
|
+
if (speedMbps < 5) return 0.3 + (speedMbps - 1) / 4 * 0.3;
|
|
694
|
+
if (speedMbps < 20) return 0.6 + (speedMbps - 5) / 15 * 0.3;
|
|
695
|
+
return Math.min(1, 0.9 + (speedMbps - 20) / 200);
|
|
696
|
+
}
|
|
697
|
+
/**
|
|
698
|
+
* Calculate device factor (0-1)
|
|
699
|
+
*/
|
|
700
|
+
calculateDeviceFactor() {
|
|
701
|
+
let factor = 0.5;
|
|
702
|
+
if (this.deviceProfile.isPremium) {
|
|
703
|
+
factor = 0.8;
|
|
704
|
+
} else if (this.deviceProfile.isConstrained) {
|
|
705
|
+
factor = 0.2;
|
|
706
|
+
}
|
|
707
|
+
if (this.deviceProfile.cpuUtilization > 0.8) {
|
|
708
|
+
factor *= 0.7;
|
|
709
|
+
} else if (this.deviceProfile.cpuUtilization < 0.2) {
|
|
710
|
+
factor *= 1.1;
|
|
711
|
+
}
|
|
712
|
+
if (this.deviceProfile.supportsWebAssembly) {
|
|
713
|
+
factor = Math.min(1, factor + 0.1);
|
|
714
|
+
}
|
|
715
|
+
return Math.max(0, Math.min(1, factor));
|
|
716
|
+
}
|
|
717
|
+
/**
|
|
718
|
+
* Estimate compression time for a level (in ms)
|
|
719
|
+
*/
|
|
720
|
+
estimateCompressionTime(level) {
|
|
721
|
+
return Math.max(1, level * 2.5);
|
|
722
|
+
}
|
|
723
|
+
/**
|
|
724
|
+
* Estimate compression ratio for a level
|
|
725
|
+
*/
|
|
726
|
+
estimateCompressionRatio(level) {
|
|
727
|
+
return 0.6 + level / 9 * 0.3;
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* Apply recommendation and get new level
|
|
731
|
+
*/
|
|
732
|
+
applyRecommendation() {
|
|
733
|
+
const recommendation = this.getRecommendedLevel();
|
|
734
|
+
const oldLevel = this.currentLevel;
|
|
735
|
+
const shouldChange = recommendation.confidence > 0.7 || Math.abs(recommendation.recommendedLevel - oldLevel) > 2;
|
|
736
|
+
if (shouldChange) {
|
|
737
|
+
this.currentLevel = recommendation.recommendedLevel;
|
|
738
|
+
this.stats.levelsUsed.add(this.currentLevel);
|
|
739
|
+
if (oldLevel !== this.currentLevel) {
|
|
740
|
+
this.stats.adjustmentCount++;
|
|
741
|
+
logger3.debug("[AdaptiveCompressionOptimizer] Level adjusted", {
|
|
742
|
+
from: oldLevel,
|
|
743
|
+
to: this.currentLevel,
|
|
744
|
+
reason: recommendation.reason
|
|
745
|
+
});
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
this.stats.currentLevel = this.currentLevel;
|
|
749
|
+
return this.currentLevel;
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* Get current level
|
|
753
|
+
*/
|
|
754
|
+
getCurrentLevel() {
|
|
755
|
+
return this.currentLevel;
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* Get statistics
|
|
759
|
+
*/
|
|
760
|
+
getStats() {
|
|
761
|
+
return { ...this.stats };
|
|
762
|
+
}
|
|
763
|
+
/**
|
|
764
|
+
* Get detailed analysis
|
|
765
|
+
*/
|
|
766
|
+
getDetailedAnalysis() {
|
|
767
|
+
return {
|
|
768
|
+
stats: this.stats,
|
|
769
|
+
network: this.networkProfile,
|
|
770
|
+
device: this.deviceProfile,
|
|
771
|
+
recommendation: this.getRecommendedLevel(),
|
|
772
|
+
history: this.compressionHistory.slice(-20)
|
|
773
|
+
};
|
|
774
|
+
}
|
|
775
|
+
};
|
|
776
|
+
var adaptiveOptimizerInstance = null;
|
|
777
|
+
function getAdaptiveCompressionOptimizer() {
|
|
778
|
+
if (!adaptiveOptimizerInstance) {
|
|
779
|
+
adaptiveOptimizerInstance = new AdaptiveCompressionOptimizer();
|
|
780
|
+
}
|
|
781
|
+
return adaptiveOptimizerInstance;
|
|
782
|
+
}
|
|
783
|
+
function resetAdaptiveCompressionOptimizer() {
|
|
784
|
+
adaptiveOptimizerInstance = null;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
exports.AdaptiveCompressionOptimizer = AdaptiveCompressionOptimizer;
|
|
788
|
+
exports.BatchTimingOptimizer = BatchTimingOptimizer;
|
|
789
|
+
exports.PrefetchingEngine = PrefetchingEngine;
|
|
790
|
+
exports.getAdaptiveCompressionOptimizer = getAdaptiveCompressionOptimizer;
|
|
791
|
+
exports.getBatchTimingOptimizer = getBatchTimingOptimizer;
|
|
792
|
+
exports.getPrefetchingEngine = getPrefetchingEngine;
|
|
793
|
+
exports.resetAdaptiveCompressionOptimizer = resetAdaptiveCompressionOptimizer;
|
|
794
|
+
exports.resetBatchTimingOptimizer = resetBatchTimingOptimizer;
|
|
795
|
+
exports.resetPrefetchingEngine = resetPrefetchingEngine;
|
|
796
|
+
//# sourceMappingURL=index.cjs.map
|
|
797
|
+
//# sourceMappingURL=index.cjs.map
|