-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathoffline-queue.ts
More file actions
133 lines (125 loc) · 4.56 KB
/
offline-queue.ts
File metadata and controls
133 lines (125 loc) · 4.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// src/infra/offline/offline-queue.ts
/**
* FILE: offline-queue.ts
* LAYER: infra/offline
* ---------------------------------------------------------------------
* PURPOSE:
* Queue write operations (mutations / uploads) attempted while the app
* is offline. When the device reconnects, sync-engine replays queued
* operations in FIFO order.
*
* RESPONSIBILITIES:
* - push(operation, variables, tags?) → store new offline task.
* - getAll() → return snapshot for replay/inspection.
* - remove(id) → remove successfully replayed mutation.
* - clear() → wipe queue on logout or environment reset.
*
* DATA-FLOW:
* service.mutate()
* → transport.mutate()
* → offline? → offlineQueue.push(operation, variables, tags?)
*
* connectivity restored (NetInfo)
* → syncEngine.onConnected()
* → replayOfflineMutations()
* → transport.mutate()
* → (optional) invalidate by tags
* → offlineQueue.remove(id)
*
* DESIGN NOTES:
* - In-memory array used only for development.
* - Replace with MMKV/SQLite for persistence (recommended).
*
* EXTENSION GUIDELINES:
* - Add retry metadata: { retryCount, lastAttempt, lastError }.
* - Add conflict-resolution strategies:
* optimistic merge, server-wins, client-wins, CRDT.
* - Add deduplication based on operation + payload hash.
* - Add TTL (“discard after X hours offline”).
* - Add encryption if persistent storage contains sensitive data.
*
* THREAD SAFETY:
* - JS thread is single-threaded → array operations are safe.
* - When using SQLite/MMKV ensure atomic writes.
* ---------------------------------------------------------------------
*/
// src/infra/offline/offline-queue.ts
/**
* FILE: offline-queue.ts
* LAYER: infra/offline
* ---------------------------------------------------------------------
* PURPOSE:
* Queue write operations (mutations / uploads) attempted while the app
* is offline. When the device reconnects, sync-engine replays queued
* operations in FIFO order.
*
* RESPONSIBILITIES:
* - push(operation, variables, tags?) → store new offline task.
* - getAll() → return snapshot for replay/inspection.
* - remove(id) → remove successfully replayed mutation.
* - clear() → wipe queue on logout or environment reset.
*
* DATA-FLOW:
* service.mutate()
* → transport.mutate()
* → offline? → offlineQueue.push(operation, variables, tags?)
*
* connectivity restored (NetInfo)
* → syncEngine.onConnected()
* → replayOfflineMutations()
* → transport.mutate()
* → (optional) invalidate by tags
* → offlineQueue.remove(id)
*
* DESIGN NOTES:
* - In-memory array used only for development.
* - Replace with MMKV/SQLite for persistence (recommended).
*
* EXTENSION GUIDELINES:
* - Add retry metadata: { retryCount, lastAttempt, lastError }.
* - Add conflict-resolution strategies:
* optimistic merge, server-wins, client-wins, CRDT.
* - Add deduplication based on operation + payload hash.
* - Add TTL (“discard after X hours offline”).
* - Add encryption if persistent storage contains sensitive data.
*
* THREAD SAFETY:
* - JS thread is single-threaded → array operations are safe.
* - When using SQLite/MMKV ensure atomic writes.
* ---------------------------------------------------------------------
*/
import type { Tag } from '@/shared/services/api/query/tags'
import type { Operation } from '@/shared/services/api/transport/operations'
export interface OfflineMutation {
id: string
operation: Operation
variables: unknown
createdAt: number
tags?: Tag[] // stored as mutable copy
}
const MEMORY_QUEUE: OfflineMutation[] = []
export const offlineQueue = {
/**
* Push a new offline mutation into the FIFO queue.
* Backward-compatible: `tags` is optional.
*/
push(operation: Operation, variables: unknown, tags?: readonly Tag[]) {
MEMORY_QUEUE.push({
id: Math.random().toString(36).slice(2),
operation,
variables,
createdAt: Date.now(),
tags: tags ? [...tags] : undefined, // ✅ copy readonly -> mutable
})
},
getAll(): OfflineMutation[] {
return [...MEMORY_QUEUE]
},
remove(id: string) {
const index = MEMORY_QUEUE.findIndex(q => q.id === id)
if (index !== -1) MEMORY_QUEUE.splice(index, 1)
},
clear() {
MEMORY_QUEUE.length = 0
},
}