@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.
Files changed (62) hide show
  1. package/README.md +10 -0
  2. package/dist/compression/index.cjs +580 -0
  3. package/dist/compression/index.cjs.map +1 -0
  4. package/dist/compression/index.d.cts +189 -0
  5. package/dist/compression/index.d.ts +189 -0
  6. package/dist/compression/index.js +573 -0
  7. package/dist/compression/index.js.map +1 -0
  8. package/dist/core/index.d.cts +70 -5
  9. package/dist/core/index.d.ts +70 -5
  10. package/dist/crypto/index.cjs +100 -0
  11. package/dist/crypto/index.cjs.map +1 -0
  12. package/dist/crypto/index.d.cts +407 -0
  13. package/dist/crypto/index.d.ts +407 -0
  14. package/dist/crypto/index.js +96 -0
  15. package/dist/crypto/index.js.map +1 -0
  16. package/dist/distributed/index.cjs +420 -23
  17. package/dist/distributed/index.cjs.map +1 -1
  18. package/dist/distributed/index.d.cts +901 -2
  19. package/dist/distributed/index.d.ts +901 -2
  20. package/dist/distributed/index.js +420 -23
  21. package/dist/distributed/index.js.map +1 -1
  22. package/dist/index.cjs +1222 -55
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.d.cts +11 -811
  25. package/dist/index.d.ts +11 -811
  26. package/dist/index.js +1221 -56
  27. package/dist/index.js.map +1 -1
  28. package/dist/offline/index.cjs +419 -0
  29. package/dist/offline/index.cjs.map +1 -0
  30. package/dist/offline/index.d.cts +148 -0
  31. package/dist/offline/index.d.ts +148 -0
  32. package/dist/offline/index.js +415 -0
  33. package/dist/offline/index.js.map +1 -0
  34. package/dist/optimization/index.cjs +797 -0
  35. package/dist/optimization/index.cjs.map +1 -0
  36. package/dist/optimization/index.d.cts +347 -0
  37. package/dist/optimization/index.d.ts +347 -0
  38. package/dist/optimization/index.js +787 -0
  39. package/dist/optimization/index.js.map +1 -0
  40. package/dist/persistence/index.cjs +145 -0
  41. package/dist/persistence/index.cjs.map +1 -0
  42. package/dist/persistence/index.d.cts +63 -0
  43. package/dist/persistence/index.d.ts +63 -0
  44. package/dist/persistence/index.js +142 -0
  45. package/dist/persistence/index.js.map +1 -0
  46. package/dist/presence/index.cjs +489 -0
  47. package/dist/presence/index.cjs.map +1 -0
  48. package/dist/presence/index.d.cts +283 -0
  49. package/dist/presence/index.d.ts +283 -0
  50. package/dist/presence/index.js +485 -0
  51. package/dist/presence/index.js.map +1 -0
  52. package/dist/types-CMxO7QF0.d.cts +33 -0
  53. package/dist/types-CMxO7QF0.d.ts +33 -0
  54. package/dist/versioning/index.cjs +296 -14
  55. package/dist/versioning/index.cjs.map +1 -1
  56. package/dist/versioning/index.d.cts +66 -1
  57. package/dist/versioning/index.d.ts +66 -1
  58. package/dist/versioning/index.js +296 -14
  59. package/dist/versioning/index.js.map +1 -1
  60. package/package.json +51 -1
  61. package/dist/index-C_4CMV5c.d.cts +0 -1207
  62. package/dist/index-C_4CMV5c.d.ts +0 -1207
@@ -0,0 +1,419 @@
1
+ 'use strict';
2
+
3
+ var eventemitter3 = require('eventemitter3');
4
+
5
+ // src/offline/OfflineOperationQueue.ts
6
+
7
+ // src/utils/logger.ts
8
+ var consoleLogger = {
9
+ debug: (...args) => {
10
+ console.debug("[AEON:DEBUG]", ...args);
11
+ },
12
+ info: (...args) => {
13
+ console.info("[AEON:INFO]", ...args);
14
+ },
15
+ warn: (...args) => {
16
+ console.warn("[AEON:WARN]", ...args);
17
+ },
18
+ error: (...args) => {
19
+ console.error("[AEON:ERROR]", ...args);
20
+ }
21
+ };
22
+ var currentLogger = consoleLogger;
23
+ function getLogger() {
24
+ return currentLogger;
25
+ }
26
+
27
+ // src/offline/OfflineOperationQueue.ts
28
+ var logger = getLogger();
29
+ var OfflineOperationQueue = class _OfflineOperationQueue extends eventemitter3.EventEmitter {
30
+ static DEFAULT_PERSIST_KEY = "aeon:offline-queue:v1";
31
+ queue = /* @__PURE__ */ new Map();
32
+ syncingIds = /* @__PURE__ */ new Set();
33
+ maxQueueSize = 1e3;
34
+ defaultMaxRetries = 3;
35
+ persistence = null;
36
+ persistTimer = null;
37
+ persistInFlight = false;
38
+ persistPending = false;
39
+ constructor(maxQueueSizeOrOptions = 1e3, defaultMaxRetries = 3) {
40
+ super();
41
+ if (typeof maxQueueSizeOrOptions === "number") {
42
+ this.maxQueueSize = maxQueueSizeOrOptions;
43
+ this.defaultMaxRetries = defaultMaxRetries;
44
+ } else {
45
+ this.maxQueueSize = maxQueueSizeOrOptions.maxQueueSize ?? 1e3;
46
+ this.defaultMaxRetries = maxQueueSizeOrOptions.defaultMaxRetries ?? 3;
47
+ if (maxQueueSizeOrOptions.persistence) {
48
+ this.persistence = {
49
+ ...maxQueueSizeOrOptions.persistence,
50
+ key: maxQueueSizeOrOptions.persistence.key ?? _OfflineOperationQueue.DEFAULT_PERSIST_KEY,
51
+ autoPersist: maxQueueSizeOrOptions.persistence.autoPersist ?? true,
52
+ autoLoad: maxQueueSizeOrOptions.persistence.autoLoad ?? false,
53
+ persistDebounceMs: maxQueueSizeOrOptions.persistence.persistDebounceMs ?? 25
54
+ };
55
+ if (this.persistence.autoLoad) {
56
+ void this.loadFromPersistence().catch((error) => {
57
+ logger.error("[OfflineOperationQueue] Failed to load persistence", {
58
+ key: this.persistence?.key,
59
+ error: error instanceof Error ? error.message : String(error)
60
+ });
61
+ });
62
+ }
63
+ }
64
+ }
65
+ logger.debug("[OfflineOperationQueue] Initialized", {
66
+ maxQueueSize: this.maxQueueSize,
67
+ defaultMaxRetries: this.defaultMaxRetries,
68
+ persistenceEnabled: this.persistence !== null
69
+ });
70
+ }
71
+ /**
72
+ * Add operation to the queue
73
+ */
74
+ enqueue(type, data, sessionId, priority = "normal", maxRetries) {
75
+ if (this.queue.size >= this.maxQueueSize) {
76
+ const oldest = this.findOldestLowPriority();
77
+ if (oldest) {
78
+ this.queue.delete(oldest.id);
79
+ logger.warn("[OfflineOperationQueue] Queue full, removed oldest", {
80
+ removedId: oldest.id
81
+ });
82
+ }
83
+ }
84
+ const operation = {
85
+ id: `op-${Date.now()}-${Math.random().toString(36).slice(2)}`,
86
+ type,
87
+ data,
88
+ sessionId,
89
+ priority,
90
+ createdAt: Date.now(),
91
+ retryCount: 0,
92
+ maxRetries: maxRetries ?? this.defaultMaxRetries,
93
+ status: "pending"
94
+ };
95
+ this.queue.set(operation.id, operation);
96
+ this.emit("operation-added", operation);
97
+ this.schedulePersist();
98
+ logger.debug("[OfflineOperationQueue] Operation enqueued", {
99
+ id: operation.id,
100
+ type,
101
+ priority,
102
+ queueSize: this.queue.size
103
+ });
104
+ return operation;
105
+ }
106
+ /**
107
+ * Get next operations to sync (by priority)
108
+ */
109
+ getNextBatch(batchSize = 10) {
110
+ const pending = Array.from(this.queue.values()).filter((op) => op.status === "pending" && !this.syncingIds.has(op.id)).sort((a, b) => {
111
+ const priorityOrder = { high: 0, normal: 1, low: 2 };
112
+ const priorityDiff = priorityOrder[a.priority] - priorityOrder[b.priority];
113
+ if (priorityDiff !== 0) return priorityDiff;
114
+ return a.createdAt - b.createdAt;
115
+ });
116
+ return pending.slice(0, batchSize);
117
+ }
118
+ /**
119
+ * Mark operations as syncing
120
+ */
121
+ markSyncing(operationIds) {
122
+ let changed = false;
123
+ for (const id of operationIds) {
124
+ const op = this.queue.get(id);
125
+ if (op) {
126
+ op.status = "syncing";
127
+ this.syncingIds.add(id);
128
+ changed = true;
129
+ }
130
+ }
131
+ if (changed) {
132
+ this.schedulePersist();
133
+ }
134
+ }
135
+ /**
136
+ * Mark operation as synced
137
+ */
138
+ markSynced(operationId) {
139
+ const op = this.queue.get(operationId);
140
+ if (op) {
141
+ op.status = "synced";
142
+ this.syncingIds.delete(operationId);
143
+ this.emit("operation-synced", op);
144
+ this.schedulePersist();
145
+ setTimeout(() => {
146
+ this.queue.delete(operationId);
147
+ this.schedulePersist();
148
+ if (this.getPendingCount() === 0) {
149
+ this.emit("queue-empty");
150
+ }
151
+ }, 1e3);
152
+ }
153
+ }
154
+ /**
155
+ * Mark operation as failed
156
+ */
157
+ markFailed(operationId, error) {
158
+ const op = this.queue.get(operationId);
159
+ if (op) {
160
+ op.retryCount++;
161
+ op.lastError = error.message;
162
+ this.syncingIds.delete(operationId);
163
+ if (op.retryCount >= op.maxRetries) {
164
+ op.status = "failed";
165
+ this.emit("operation-failed", op, error);
166
+ logger.error("[OfflineOperationQueue] Operation permanently failed", {
167
+ id: operationId,
168
+ retries: op.retryCount,
169
+ error: error.message
170
+ });
171
+ } else {
172
+ op.status = "pending";
173
+ logger.warn("[OfflineOperationQueue] Operation failed, will retry", {
174
+ id: operationId,
175
+ retryCount: op.retryCount,
176
+ maxRetries: op.maxRetries
177
+ });
178
+ }
179
+ this.schedulePersist();
180
+ }
181
+ }
182
+ /**
183
+ * Get operation by ID
184
+ */
185
+ getOperation(operationId) {
186
+ return this.queue.get(operationId);
187
+ }
188
+ /**
189
+ * Get all pending operations
190
+ */
191
+ getPendingOperations() {
192
+ return Array.from(this.queue.values()).filter(
193
+ (op) => op.status === "pending"
194
+ );
195
+ }
196
+ /**
197
+ * Get pending count
198
+ */
199
+ getPendingCount() {
200
+ return Array.from(this.queue.values()).filter(
201
+ (op) => op.status === "pending"
202
+ ).length;
203
+ }
204
+ /**
205
+ * Get queue statistics
206
+ */
207
+ getStats() {
208
+ const operations = Array.from(this.queue.values());
209
+ const pending = operations.filter((op) => op.status === "pending").length;
210
+ const syncing = operations.filter((op) => op.status === "syncing").length;
211
+ const failed = operations.filter((op) => op.status === "failed").length;
212
+ const synced = operations.filter((op) => op.status === "synced").length;
213
+ const pendingOps = operations.filter((op) => op.status === "pending");
214
+ const oldestPendingMs = pendingOps.length > 0 ? Date.now() - Math.min(...pendingOps.map((op) => op.createdAt)) : 0;
215
+ const averageRetries = operations.length > 0 ? operations.reduce((sum, op) => sum + op.retryCount, 0) / operations.length : 0;
216
+ return {
217
+ pending,
218
+ syncing,
219
+ failed,
220
+ synced,
221
+ totalOperations: operations.length,
222
+ oldestPendingMs,
223
+ averageRetries
224
+ };
225
+ }
226
+ /**
227
+ * Clear all operations
228
+ */
229
+ clear() {
230
+ this.queue.clear();
231
+ this.syncingIds.clear();
232
+ this.schedulePersist();
233
+ logger.debug("[OfflineOperationQueue] Queue cleared");
234
+ }
235
+ /**
236
+ * Clear failed operations
237
+ */
238
+ clearFailed() {
239
+ let changed = false;
240
+ for (const [id, op] of this.queue.entries()) {
241
+ if (op.status === "failed") {
242
+ this.queue.delete(id);
243
+ changed = true;
244
+ }
245
+ }
246
+ if (changed) {
247
+ this.schedulePersist();
248
+ }
249
+ }
250
+ /**
251
+ * Retry failed operations
252
+ */
253
+ retryFailed() {
254
+ let changed = false;
255
+ for (const op of this.queue.values()) {
256
+ if (op.status === "failed") {
257
+ op.status = "pending";
258
+ op.retryCount = 0;
259
+ changed = true;
260
+ }
261
+ }
262
+ if (changed) {
263
+ this.schedulePersist();
264
+ }
265
+ }
266
+ /**
267
+ * Find oldest low-priority operation
268
+ */
269
+ findOldestLowPriority() {
270
+ const lowPriority = Array.from(this.queue.values()).filter((op) => op.priority === "low" && op.status === "pending").sort((a, b) => a.createdAt - b.createdAt);
271
+ return lowPriority[0] ?? null;
272
+ }
273
+ /**
274
+ * Export queue for persistence
275
+ */
276
+ export() {
277
+ return Array.from(this.queue.values());
278
+ }
279
+ /**
280
+ * Import queue from persistence
281
+ */
282
+ import(operations) {
283
+ this.queue.clear();
284
+ this.syncingIds.clear();
285
+ for (const op of operations) {
286
+ if (this.isValidOfflineOperation(op)) {
287
+ this.queue.set(op.id, {
288
+ ...op,
289
+ status: op.status === "syncing" ? "pending" : op.status
290
+ });
291
+ }
292
+ }
293
+ this.schedulePersist();
294
+ logger.debug("[OfflineOperationQueue] Imported operations", {
295
+ count: this.queue.size
296
+ });
297
+ }
298
+ /**
299
+ * Persist current queue snapshot.
300
+ */
301
+ async saveToPersistence() {
302
+ if (!this.persistence) {
303
+ return;
304
+ }
305
+ const envelope = {
306
+ version: 1,
307
+ updatedAt: Date.now(),
308
+ data: this.export()
309
+ };
310
+ const serialize = this.persistence.serializer ?? ((value) => JSON.stringify(value));
311
+ const raw = serialize(envelope);
312
+ await this.persistence.adapter.setItem(this.persistence.key, raw);
313
+ }
314
+ /**
315
+ * Load queue snapshot from persistence.
316
+ */
317
+ async loadFromPersistence() {
318
+ if (!this.persistence) {
319
+ return 0;
320
+ }
321
+ const raw = await this.persistence.adapter.getItem(this.persistence.key);
322
+ if (!raw) {
323
+ return 0;
324
+ }
325
+ const deserialize = this.persistence.deserializer ?? ((value) => JSON.parse(value));
326
+ const envelope = deserialize(raw);
327
+ if (envelope.version !== 1 || !Array.isArray(envelope.data)) {
328
+ throw new Error("Invalid offline queue persistence payload");
329
+ }
330
+ this.queue.clear();
331
+ this.syncingIds.clear();
332
+ let imported = 0;
333
+ for (const operation of envelope.data) {
334
+ if (this.isValidOfflineOperation(operation)) {
335
+ this.queue.set(operation.id, {
336
+ ...operation,
337
+ status: operation.status === "syncing" ? "pending" : operation.status
338
+ });
339
+ imported++;
340
+ }
341
+ }
342
+ logger.debug("[OfflineOperationQueue] Loaded from persistence", {
343
+ key: this.persistence.key,
344
+ imported
345
+ });
346
+ return imported;
347
+ }
348
+ /**
349
+ * Remove persisted queue snapshot.
350
+ */
351
+ async clearPersistence() {
352
+ if (!this.persistence) {
353
+ return;
354
+ }
355
+ await this.persistence.adapter.removeItem(this.persistence.key);
356
+ }
357
+ schedulePersist() {
358
+ if (!this.persistence || this.persistence.autoPersist === false) {
359
+ return;
360
+ }
361
+ if (this.persistTimer) {
362
+ clearTimeout(this.persistTimer);
363
+ }
364
+ this.persistTimer = setTimeout(() => {
365
+ void this.persistSafely();
366
+ }, this.persistence.persistDebounceMs ?? 25);
367
+ }
368
+ async persistSafely() {
369
+ if (!this.persistence) {
370
+ return;
371
+ }
372
+ if (this.persistInFlight) {
373
+ this.persistPending = true;
374
+ return;
375
+ }
376
+ this.persistInFlight = true;
377
+ try {
378
+ await this.saveToPersistence();
379
+ } catch (error) {
380
+ logger.error("[OfflineOperationQueue] Persistence write failed", {
381
+ key: this.persistence.key,
382
+ error: error instanceof Error ? error.message : String(error)
383
+ });
384
+ } finally {
385
+ this.persistInFlight = false;
386
+ const shouldRunAgain = this.persistPending;
387
+ this.persistPending = false;
388
+ if (shouldRunAgain) {
389
+ void this.persistSafely();
390
+ }
391
+ }
392
+ }
393
+ isValidOfflineOperation(value) {
394
+ if (typeof value !== "object" || value === null) {
395
+ return false;
396
+ }
397
+ const candidate = value;
398
+ const validType = candidate.type === "create" || candidate.type === "update" || candidate.type === "delete" || candidate.type === "sync" || candidate.type === "batch";
399
+ const validPriority = candidate.priority === "high" || candidate.priority === "normal" || candidate.priority === "low";
400
+ const validStatus = candidate.status === "pending" || candidate.status === "syncing" || candidate.status === "failed" || candidate.status === "synced";
401
+ return typeof candidate.id === "string" && validType && typeof candidate.data === "object" && candidate.data !== null && !Array.isArray(candidate.data) && typeof candidate.sessionId === "string" && validPriority && typeof candidate.createdAt === "number" && typeof candidate.retryCount === "number" && typeof candidate.maxRetries === "number" && validStatus;
402
+ }
403
+ };
404
+ var offlineQueueInstance = null;
405
+ function getOfflineOperationQueue() {
406
+ if (!offlineQueueInstance) {
407
+ offlineQueueInstance = new OfflineOperationQueue();
408
+ }
409
+ return offlineQueueInstance;
410
+ }
411
+ function resetOfflineOperationQueue() {
412
+ offlineQueueInstance = null;
413
+ }
414
+
415
+ exports.OfflineOperationQueue = OfflineOperationQueue;
416
+ exports.getOfflineOperationQueue = getOfflineOperationQueue;
417
+ exports.resetOfflineOperationQueue = resetOfflineOperationQueue;
418
+ //# sourceMappingURL=index.cjs.map
419
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utils/logger.ts","../../src/offline/OfflineOperationQueue.ts"],"names":["EventEmitter"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Aeon Logger Interface\n *\n * Provides a pluggable logging interface that can be configured\n * by consumers to integrate with their preferred logging solution.\n */\n\n/**\n * Logger interface that consumers can implement\n */\nexport interface Logger {\n debug: (...args: unknown[]) => void;\n info: (...args: unknown[]) => void;\n warn: (...args: unknown[]) => void;\n error: (...args: unknown[]) => void;\n}\n\n/**\n * Default console logger implementation\n */\nconst consoleLogger: Logger = {\n debug: (...args: unknown[]) => {\n // eslint-disable-next-line no-console\n console.debug('[AEON:DEBUG]', ...args);\n },\n info: (...args: unknown[]) => {\n // eslint-disable-next-line no-console\n console.info('[AEON:INFO]', ...args);\n },\n warn: (...args: unknown[]) => {\n // eslint-disable-next-line no-console\n console.warn('[AEON:WARN]', ...args);\n },\n error: (...args: unknown[]) => {\n // eslint-disable-next-line no-console\n console.error('[AEON:ERROR]', ...args);\n },\n};\n\n/**\n * No-op logger for production or when logging is disabled\n */\nconst noopLogger: Logger = {\n debug: () => {},\n info: () => {},\n warn: () => {},\n error: () => {},\n};\n\n/**\n * Current logger instance\n */\nlet currentLogger: Logger = consoleLogger;\n\n/**\n * Get the current logger instance\n */\nexport function getLogger(): Logger {\n return currentLogger;\n}\n\n/**\n * Set a custom logger implementation\n */\nexport function setLogger(logger: Logger): void {\n currentLogger = logger;\n}\n\n/**\n * Reset to the default console logger\n */\nexport function resetLogger(): void {\n currentLogger = consoleLogger;\n}\n\n/**\n * Disable all logging\n */\nexport function disableLogging(): void {\n currentLogger = noopLogger;\n}\n\n/**\n * Create a namespaced logger\n */\nexport function createNamespacedLogger(namespace: string): Logger {\n const logger = getLogger();\n return {\n debug: (...args: unknown[]) => logger.debug(`[${namespace}]`, ...args),\n info: (...args: unknown[]) => logger.info(`[${namespace}]`, ...args),\n warn: (...args: unknown[]) => logger.warn(`[${namespace}]`, ...args),\n error: (...args: unknown[]) => logger.error(`[${namespace}]`, ...args),\n };\n}\n\n// Export default logger for convenience\nexport const logger: Logger = {\n debug: (...args: unknown[]) => getLogger().debug(...args),\n info: (...args: unknown[]) => getLogger().info(...args),\n warn: (...args: unknown[]) => getLogger().warn(...args),\n error: (...args: unknown[]) => getLogger().error(...args),\n};\n","/**\n * Offline Operation Queue (Phase 11)\n *\n * Manages pending operations for offline-first clients.\n * Provides priority-based queuing, persistence, and retry logic.\n */\n\nimport { EventEmitter } from 'eventemitter3';\nimport { getLogger } from '../utils/logger';\nimport type { Operation, OperationPriority } from '../core/types';\nimport type {\n PersistedEnvelope,\n PersistenceDeserializer,\n PersistenceSerializer,\n StorageAdapter,\n} from '../persistence';\n\nconst logger = getLogger();\n\n// Re-export OperationPriority from core\nexport type { OperationPriority } from '../core/types';\n\nexport interface OfflineOperation {\n id: string;\n type: Operation['type'];\n data: Record<string, unknown>;\n sessionId: string;\n priority: OperationPriority;\n createdAt: number;\n retryCount: number;\n maxRetries: number;\n lastError?: string;\n status: 'pending' | 'syncing' | 'failed' | 'synced';\n}\n\nexport interface OfflineQueueStats {\n pending: number;\n syncing: number;\n failed: number;\n synced: number;\n totalOperations: number;\n oldestPendingMs: number;\n averageRetries: number;\n}\n\nexport interface OfflineQueueEvents {\n 'operation-added': (operation: OfflineOperation) => void;\n 'operation-synced': (operation: OfflineOperation) => void;\n 'operation-failed': (operation: OfflineOperation, error: Error) => void;\n 'queue-empty': () => void;\n 'sync-started': () => void;\n 'sync-completed': (stats: { synced: number; failed: number }) => void;\n}\n\nexport interface OfflineQueuePersistenceConfig {\n adapter: StorageAdapter;\n key?: string;\n autoPersist?: boolean;\n autoLoad?: boolean;\n persistDebounceMs?: number;\n serializer?: PersistenceSerializer<OfflineOperation[]>;\n deserializer?: PersistenceDeserializer<OfflineOperation[]>;\n}\n\nexport interface OfflineOperationQueueOptions {\n maxQueueSize?: number;\n defaultMaxRetries?: number;\n persistence?: OfflineQueuePersistenceConfig;\n}\n\n// ============================================================================\n// Offline Operation Queue\n// ============================================================================\n\nexport class OfflineOperationQueue extends EventEmitter<OfflineQueueEvents> {\n private static readonly DEFAULT_PERSIST_KEY = 'aeon:offline-queue:v1';\n private queue: Map<string, OfflineOperation> = new Map();\n private syncingIds: Set<string> = new Set();\n private maxQueueSize = 1000;\n private defaultMaxRetries = 3;\n private persistence: (OfflineQueuePersistenceConfig & { key: string }) | null =\n null;\n private persistTimer: ReturnType<typeof setTimeout> | null = null;\n private persistInFlight = false;\n private persistPending = false;\n\n constructor(\n maxQueueSizeOrOptions: number | OfflineOperationQueueOptions = 1000,\n defaultMaxRetries = 3,\n ) {\n super();\n\n if (typeof maxQueueSizeOrOptions === 'number') {\n this.maxQueueSize = maxQueueSizeOrOptions;\n this.defaultMaxRetries = defaultMaxRetries;\n } else {\n this.maxQueueSize = maxQueueSizeOrOptions.maxQueueSize ?? 1000;\n this.defaultMaxRetries = maxQueueSizeOrOptions.defaultMaxRetries ?? 3;\n\n if (maxQueueSizeOrOptions.persistence) {\n this.persistence = {\n ...maxQueueSizeOrOptions.persistence,\n key:\n maxQueueSizeOrOptions.persistence.key ??\n OfflineOperationQueue.DEFAULT_PERSIST_KEY,\n autoPersist: maxQueueSizeOrOptions.persistence.autoPersist ?? true,\n autoLoad: maxQueueSizeOrOptions.persistence.autoLoad ?? false,\n persistDebounceMs:\n maxQueueSizeOrOptions.persistence.persistDebounceMs ?? 25,\n };\n\n if (this.persistence.autoLoad) {\n void this.loadFromPersistence().catch((error) => {\n logger.error('[OfflineOperationQueue] Failed to load persistence', {\n key: this.persistence?.key,\n error: error instanceof Error ? error.message : String(error),\n });\n });\n }\n }\n }\n\n logger.debug('[OfflineOperationQueue] Initialized', {\n maxQueueSize: this.maxQueueSize,\n defaultMaxRetries: this.defaultMaxRetries,\n persistenceEnabled: this.persistence !== null,\n });\n }\n\n /**\n * Add operation to the queue\n */\n enqueue(\n type: Operation['type'],\n data: Record<string, unknown>,\n sessionId: string,\n priority: OperationPriority = 'normal',\n maxRetries?: number,\n ): OfflineOperation {\n if (this.queue.size >= this.maxQueueSize) {\n // Remove oldest low-priority operation\n const oldest = this.findOldestLowPriority();\n if (oldest) {\n this.queue.delete(oldest.id);\n logger.warn('[OfflineOperationQueue] Queue full, removed oldest', {\n removedId: oldest.id,\n });\n }\n }\n\n const operation: OfflineOperation = {\n id: `op-${Date.now()}-${Math.random().toString(36).slice(2)}`,\n type,\n data,\n sessionId,\n priority,\n createdAt: Date.now(),\n retryCount: 0,\n maxRetries: maxRetries ?? this.defaultMaxRetries,\n status: 'pending',\n };\n\n this.queue.set(operation.id, operation);\n this.emit('operation-added', operation);\n this.schedulePersist();\n\n logger.debug('[OfflineOperationQueue] Operation enqueued', {\n id: operation.id,\n type,\n priority,\n queueSize: this.queue.size,\n });\n\n return operation;\n }\n\n /**\n * Get next operations to sync (by priority)\n */\n getNextBatch(batchSize = 10): OfflineOperation[] {\n const pending = Array.from(this.queue.values())\n .filter((op) => op.status === 'pending' && !this.syncingIds.has(op.id))\n .sort((a, b) => {\n // Sort by priority first, then by creation time\n const priorityOrder = { high: 0, normal: 1, low: 2 };\n const priorityDiff =\n priorityOrder[a.priority] - priorityOrder[b.priority];\n if (priorityDiff !== 0) return priorityDiff;\n return a.createdAt - b.createdAt;\n });\n\n return pending.slice(0, batchSize);\n }\n\n /**\n * Mark operations as syncing\n */\n markSyncing(operationIds: string[]): void {\n let changed = false;\n for (const id of operationIds) {\n const op = this.queue.get(id);\n if (op) {\n op.status = 'syncing';\n this.syncingIds.add(id);\n changed = true;\n }\n }\n\n if (changed) {\n this.schedulePersist();\n }\n }\n\n /**\n * Mark operation as synced\n */\n markSynced(operationId: string): void {\n const op = this.queue.get(operationId);\n if (op) {\n op.status = 'synced';\n this.syncingIds.delete(operationId);\n this.emit('operation-synced', op);\n this.schedulePersist();\n\n // Remove synced operations after short delay\n setTimeout(() => {\n this.queue.delete(operationId);\n this.schedulePersist();\n if (this.getPendingCount() === 0) {\n this.emit('queue-empty');\n }\n }, 1000);\n }\n }\n\n /**\n * Mark operation as failed\n */\n markFailed(operationId: string, error: Error): void {\n const op = this.queue.get(operationId);\n if (op) {\n op.retryCount++;\n op.lastError = error.message;\n this.syncingIds.delete(operationId);\n\n if (op.retryCount >= op.maxRetries) {\n op.status = 'failed';\n this.emit('operation-failed', op, error);\n logger.error('[OfflineOperationQueue] Operation permanently failed', {\n id: operationId,\n retries: op.retryCount,\n error: error.message,\n });\n } else {\n op.status = 'pending';\n logger.warn('[OfflineOperationQueue] Operation failed, will retry', {\n id: operationId,\n retryCount: op.retryCount,\n maxRetries: op.maxRetries,\n });\n }\n\n this.schedulePersist();\n }\n }\n\n /**\n * Get operation by ID\n */\n getOperation(operationId: string): OfflineOperation | undefined {\n return this.queue.get(operationId);\n }\n\n /**\n * Get all pending operations\n */\n getPendingOperations(): OfflineOperation[] {\n return Array.from(this.queue.values()).filter(\n (op) => op.status === 'pending',\n );\n }\n\n /**\n * Get pending count\n */\n getPendingCount(): number {\n return Array.from(this.queue.values()).filter(\n (op) => op.status === 'pending',\n ).length;\n }\n\n /**\n * Get queue statistics\n */\n getStats(): OfflineQueueStats {\n const operations = Array.from(this.queue.values());\n\n const pending = operations.filter((op) => op.status === 'pending').length;\n const syncing = operations.filter((op) => op.status === 'syncing').length;\n const failed = operations.filter((op) => op.status === 'failed').length;\n const synced = operations.filter((op) => op.status === 'synced').length;\n\n const pendingOps = operations.filter((op) => op.status === 'pending');\n const oldestPendingMs =\n pendingOps.length > 0\n ? Date.now() - Math.min(...pendingOps.map((op) => op.createdAt))\n : 0;\n\n const averageRetries =\n operations.length > 0\n ? operations.reduce((sum, op) => sum + op.retryCount, 0) /\n operations.length\n : 0;\n\n return {\n pending,\n syncing,\n failed,\n synced,\n totalOperations: operations.length,\n oldestPendingMs,\n averageRetries,\n };\n }\n\n /**\n * Clear all operations\n */\n clear(): void {\n this.queue.clear();\n this.syncingIds.clear();\n this.schedulePersist();\n logger.debug('[OfflineOperationQueue] Queue cleared');\n }\n\n /**\n * Clear failed operations\n */\n clearFailed(): void {\n let changed = false;\n for (const [id, op] of this.queue.entries()) {\n if (op.status === 'failed') {\n this.queue.delete(id);\n changed = true;\n }\n }\n\n if (changed) {\n this.schedulePersist();\n }\n }\n\n /**\n * Retry failed operations\n */\n retryFailed(): void {\n let changed = false;\n for (const op of this.queue.values()) {\n if (op.status === 'failed') {\n op.status = 'pending';\n op.retryCount = 0;\n changed = true;\n }\n }\n\n if (changed) {\n this.schedulePersist();\n }\n }\n\n /**\n * Find oldest low-priority operation\n */\n private findOldestLowPriority(): OfflineOperation | null {\n const lowPriority = Array.from(this.queue.values())\n .filter((op) => op.priority === 'low' && op.status === 'pending')\n .sort((a, b) => a.createdAt - b.createdAt);\n\n return lowPriority[0] ?? null;\n }\n\n /**\n * Export queue for persistence\n */\n export(): OfflineOperation[] {\n return Array.from(this.queue.values());\n }\n\n /**\n * Import queue from persistence\n */\n import(operations: OfflineOperation[]): void {\n this.queue.clear();\n this.syncingIds.clear();\n\n for (const op of operations) {\n if (this.isValidOfflineOperation(op)) {\n this.queue.set(op.id, {\n ...op,\n status: op.status === 'syncing' ? 'pending' : op.status,\n });\n }\n }\n\n this.schedulePersist();\n\n logger.debug('[OfflineOperationQueue] Imported operations', {\n count: this.queue.size,\n });\n }\n\n /**\n * Persist current queue snapshot.\n */\n async saveToPersistence(): Promise<void> {\n if (!this.persistence) {\n return;\n }\n\n const envelope: PersistedEnvelope<OfflineOperation[]> = {\n version: 1,\n updatedAt: Date.now(),\n data: this.export(),\n };\n\n const serialize =\n this.persistence.serializer ??\n ((value: PersistedEnvelope<OfflineOperation[]>) => JSON.stringify(value));\n const raw = serialize(envelope);\n\n await this.persistence.adapter.setItem(this.persistence.key, raw);\n }\n\n /**\n * Load queue snapshot from persistence.\n */\n async loadFromPersistence(): Promise<number> {\n if (!this.persistence) {\n return 0;\n }\n\n const raw = await this.persistence.adapter.getItem(this.persistence.key);\n if (!raw) {\n return 0;\n }\n\n const deserialize =\n this.persistence.deserializer ??\n ((value: string) =>\n JSON.parse(value) as PersistedEnvelope<OfflineOperation[]>);\n\n const envelope = deserialize(raw);\n if (envelope.version !== 1 || !Array.isArray(envelope.data)) {\n throw new Error('Invalid offline queue persistence payload');\n }\n\n this.queue.clear();\n this.syncingIds.clear();\n\n let imported = 0;\n for (const operation of envelope.data) {\n if (this.isValidOfflineOperation(operation)) {\n this.queue.set(operation.id, {\n ...operation,\n status: operation.status === 'syncing' ? 'pending' : operation.status,\n });\n imported++;\n }\n }\n\n logger.debug('[OfflineOperationQueue] Loaded from persistence', {\n key: this.persistence.key,\n imported,\n });\n\n return imported;\n }\n\n /**\n * Remove persisted queue snapshot.\n */\n async clearPersistence(): Promise<void> {\n if (!this.persistence) {\n return;\n }\n await this.persistence.adapter.removeItem(this.persistence.key);\n }\n\n private schedulePersist(): void {\n if (!this.persistence || this.persistence.autoPersist === false) {\n return;\n }\n\n if (this.persistTimer) {\n clearTimeout(this.persistTimer);\n }\n\n this.persistTimer = setTimeout(() => {\n void this.persistSafely();\n }, this.persistence.persistDebounceMs ?? 25);\n }\n\n private async persistSafely(): Promise<void> {\n if (!this.persistence) {\n return;\n }\n\n if (this.persistInFlight) {\n this.persistPending = true;\n return;\n }\n\n this.persistInFlight = true;\n\n try {\n await this.saveToPersistence();\n } catch (error) {\n logger.error('[OfflineOperationQueue] Persistence write failed', {\n key: this.persistence.key,\n error: error instanceof Error ? error.message : String(error),\n });\n } finally {\n this.persistInFlight = false;\n const shouldRunAgain = this.persistPending;\n this.persistPending = false;\n if (shouldRunAgain) {\n void this.persistSafely();\n }\n }\n }\n\n private isValidOfflineOperation(value: unknown): value is OfflineOperation {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n\n const candidate = value as Partial<OfflineOperation>;\n const validType =\n candidate.type === 'create' ||\n candidate.type === 'update' ||\n candidate.type === 'delete' ||\n candidate.type === 'sync' ||\n candidate.type === 'batch';\n const validPriority =\n candidate.priority === 'high' ||\n candidate.priority === 'normal' ||\n candidate.priority === 'low';\n const validStatus =\n candidate.status === 'pending' ||\n candidate.status === 'syncing' ||\n candidate.status === 'failed' ||\n candidate.status === 'synced';\n\n return (\n typeof candidate.id === 'string' &&\n validType &&\n typeof candidate.data === 'object' &&\n candidate.data !== null &&\n !Array.isArray(candidate.data) &&\n typeof candidate.sessionId === 'string' &&\n validPriority &&\n typeof candidate.createdAt === 'number' &&\n typeof candidate.retryCount === 'number' &&\n typeof candidate.maxRetries === 'number' &&\n validStatus\n );\n }\n}\n\n// ============================================================================\n// Singleton Instance\n// ============================================================================\n\nlet offlineQueueInstance: OfflineOperationQueue | null = null;\n\nexport function getOfflineOperationQueue(): OfflineOperationQueue {\n if (!offlineQueueInstance) {\n offlineQueueInstance = new OfflineOperationQueue();\n }\n return offlineQueueInstance;\n}\n\nexport function resetOfflineOperationQueue(): void {\n offlineQueueInstance = null;\n}\n"]}
@@ -0,0 +1,148 @@
1
+ import { EventEmitter } from 'eventemitter3';
2
+ import { Operation, OperationPriority } from '../core/index.cjs';
3
+ import { S as StorageAdapter, b as PersistenceSerializer, a as PersistenceDeserializer } from '../types-CMxO7QF0.cjs';
4
+
5
+ /**
6
+ * Offline Operation Queue (Phase 11)
7
+ *
8
+ * Manages pending operations for offline-first clients.
9
+ * Provides priority-based queuing, persistence, and retry logic.
10
+ */
11
+
12
+ interface OfflineOperation {
13
+ id: string;
14
+ type: Operation['type'];
15
+ data: Record<string, unknown>;
16
+ sessionId: string;
17
+ priority: OperationPriority;
18
+ createdAt: number;
19
+ retryCount: number;
20
+ maxRetries: number;
21
+ lastError?: string;
22
+ status: 'pending' | 'syncing' | 'failed' | 'synced';
23
+ }
24
+ interface OfflineQueueStats {
25
+ pending: number;
26
+ syncing: number;
27
+ failed: number;
28
+ synced: number;
29
+ totalOperations: number;
30
+ oldestPendingMs: number;
31
+ averageRetries: number;
32
+ }
33
+ interface OfflineQueueEvents {
34
+ 'operation-added': (operation: OfflineOperation) => void;
35
+ 'operation-synced': (operation: OfflineOperation) => void;
36
+ 'operation-failed': (operation: OfflineOperation, error: Error) => void;
37
+ 'queue-empty': () => void;
38
+ 'sync-started': () => void;
39
+ 'sync-completed': (stats: {
40
+ synced: number;
41
+ failed: number;
42
+ }) => void;
43
+ }
44
+ interface OfflineQueuePersistenceConfig {
45
+ adapter: StorageAdapter;
46
+ key?: string;
47
+ autoPersist?: boolean;
48
+ autoLoad?: boolean;
49
+ persistDebounceMs?: number;
50
+ serializer?: PersistenceSerializer<OfflineOperation[]>;
51
+ deserializer?: PersistenceDeserializer<OfflineOperation[]>;
52
+ }
53
+ interface OfflineOperationQueueOptions {
54
+ maxQueueSize?: number;
55
+ defaultMaxRetries?: number;
56
+ persistence?: OfflineQueuePersistenceConfig;
57
+ }
58
+ declare class OfflineOperationQueue extends EventEmitter<OfflineQueueEvents> {
59
+ private static readonly DEFAULT_PERSIST_KEY;
60
+ private queue;
61
+ private syncingIds;
62
+ private maxQueueSize;
63
+ private defaultMaxRetries;
64
+ private persistence;
65
+ private persistTimer;
66
+ private persistInFlight;
67
+ private persistPending;
68
+ constructor(maxQueueSizeOrOptions?: number | OfflineOperationQueueOptions, defaultMaxRetries?: number);
69
+ /**
70
+ * Add operation to the queue
71
+ */
72
+ enqueue(type: Operation['type'], data: Record<string, unknown>, sessionId: string, priority?: OperationPriority, maxRetries?: number): OfflineOperation;
73
+ /**
74
+ * Get next operations to sync (by priority)
75
+ */
76
+ getNextBatch(batchSize?: number): OfflineOperation[];
77
+ /**
78
+ * Mark operations as syncing
79
+ */
80
+ markSyncing(operationIds: string[]): void;
81
+ /**
82
+ * Mark operation as synced
83
+ */
84
+ markSynced(operationId: string): void;
85
+ /**
86
+ * Mark operation as failed
87
+ */
88
+ markFailed(operationId: string, error: Error): void;
89
+ /**
90
+ * Get operation by ID
91
+ */
92
+ getOperation(operationId: string): OfflineOperation | undefined;
93
+ /**
94
+ * Get all pending operations
95
+ */
96
+ getPendingOperations(): OfflineOperation[];
97
+ /**
98
+ * Get pending count
99
+ */
100
+ getPendingCount(): number;
101
+ /**
102
+ * Get queue statistics
103
+ */
104
+ getStats(): OfflineQueueStats;
105
+ /**
106
+ * Clear all operations
107
+ */
108
+ clear(): void;
109
+ /**
110
+ * Clear failed operations
111
+ */
112
+ clearFailed(): void;
113
+ /**
114
+ * Retry failed operations
115
+ */
116
+ retryFailed(): void;
117
+ /**
118
+ * Find oldest low-priority operation
119
+ */
120
+ private findOldestLowPriority;
121
+ /**
122
+ * Export queue for persistence
123
+ */
124
+ export(): OfflineOperation[];
125
+ /**
126
+ * Import queue from persistence
127
+ */
128
+ import(operations: OfflineOperation[]): void;
129
+ /**
130
+ * Persist current queue snapshot.
131
+ */
132
+ saveToPersistence(): Promise<void>;
133
+ /**
134
+ * Load queue snapshot from persistence.
135
+ */
136
+ loadFromPersistence(): Promise<number>;
137
+ /**
138
+ * Remove persisted queue snapshot.
139
+ */
140
+ clearPersistence(): Promise<void>;
141
+ private schedulePersist;
142
+ private persistSafely;
143
+ private isValidOfflineOperation;
144
+ }
145
+ declare function getOfflineOperationQueue(): OfflineOperationQueue;
146
+ declare function resetOfflineOperationQueue(): void;
147
+
148
+ export { type OfflineOperation, OfflineOperationQueue, type OfflineOperationQueueOptions, type OfflineQueueEvents, type OfflineQueuePersistenceConfig, type OfflineQueueStats, OperationPriority, getOfflineOperationQueue, resetOfflineOperationQueue };