@edgebasejs/react-native 0.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/client-core/src/auth/auth-manager.d.ts +73 -0
- package/dist/client-core/src/auth/auth-manager.d.ts.map +1 -0
- package/dist/client-core/src/auth/auth-manager.js +226 -0
- package/dist/client-core/src/auth/auth-manager.js.map +1 -0
- package/dist/client-core/src/auth/index.d.ts +2 -0
- package/dist/client-core/src/auth/index.d.ts.map +1 -0
- package/dist/client-core/src/auth/index.js +2 -0
- package/dist/client-core/src/auth/index.js.map +1 -0
- package/dist/client-core/src/conflict/conflict-resolver.d.ts +62 -0
- package/dist/client-core/src/conflict/conflict-resolver.d.ts.map +1 -0
- package/dist/client-core/src/conflict/conflict-resolver.js +102 -0
- package/dist/client-core/src/conflict/conflict-resolver.js.map +1 -0
- package/dist/client-core/src/conflict/index.d.ts +2 -0
- package/dist/client-core/src/conflict/index.d.ts.map +1 -0
- package/dist/client-core/src/conflict/index.js +2 -0
- package/dist/client-core/src/conflict/index.js.map +1 -0
- package/dist/client-core/src/index.d.ts +6 -0
- package/dist/client-core/src/index.d.ts.map +1 -0
- package/dist/client-core/src/index.js +6 -0
- package/dist/client-core/src/index.js.map +1 -0
- package/dist/client-core/src/outbox/index.d.ts +2 -0
- package/dist/client-core/src/outbox/index.d.ts.map +1 -0
- package/dist/client-core/src/outbox/index.js +2 -0
- package/dist/client-core/src/outbox/index.js.map +1 -0
- package/dist/client-core/src/outbox/outbox-manager.d.ts +82 -0
- package/dist/client-core/src/outbox/outbox-manager.d.ts.map +1 -0
- package/dist/client-core/src/outbox/outbox-manager.js +143 -0
- package/dist/client-core/src/outbox/outbox-manager.js.map +1 -0
- package/dist/client-core/src/storage/index.d.ts +2 -0
- package/dist/client-core/src/storage/index.d.ts.map +1 -0
- package/dist/client-core/src/storage/index.js +2 -0
- package/dist/client-core/src/storage/index.js.map +1 -0
- package/dist/client-core/src/storage/storage-adapter.d.ts +54 -0
- package/dist/client-core/src/storage/storage-adapter.d.ts.map +1 -0
- package/dist/client-core/src/storage/storage-adapter.js +38 -0
- package/dist/client-core/src/storage/storage-adapter.js.map +1 -0
- package/dist/client-core/src/sync/index.d.ts +2 -0
- package/dist/client-core/src/sync/index.d.ts.map +1 -0
- package/dist/client-core/src/sync/index.js +2 -0
- package/dist/client-core/src/sync/index.js.map +1 -0
- package/dist/client-core/src/sync/sync-engine.d.ts +65 -0
- package/dist/client-core/src/sync/sync-engine.d.ts.map +1 -0
- package/dist/client-core/src/sync/sync-engine.js +190 -0
- package/dist/client-core/src/sync/sync-engine.js.map +1 -0
- package/dist/client-react-native/src/hooks/index.d.ts +5 -0
- package/dist/client-react-native/src/hooks/index.d.ts.map +1 -0
- package/dist/client-react-native/src/hooks/index.js +5 -0
- package/dist/client-react-native/src/hooks/index.js.map +1 -0
- package/dist/client-react-native/src/hooks/use-auth.d.ts +17 -0
- package/dist/client-react-native/src/hooks/use-auth.d.ts.map +1 -0
- package/dist/client-react-native/src/hooks/use-auth.js +78 -0
- package/dist/client-react-native/src/hooks/use-auth.js.map +1 -0
- package/dist/client-react-native/src/hooks/use-mutation.d.ts +14 -0
- package/dist/client-react-native/src/hooks/use-mutation.d.ts.map +1 -0
- package/dist/client-react-native/src/hooks/use-mutation.js +95 -0
- package/dist/client-react-native/src/hooks/use-mutation.js.map +1 -0
- package/dist/client-react-native/src/hooks/use-query.d.ts +14 -0
- package/dist/client-react-native/src/hooks/use-query.d.ts.map +1 -0
- package/dist/client-react-native/src/hooks/use-query.js +77 -0
- package/dist/client-react-native/src/hooks/use-query.js.map +1 -0
- package/dist/client-react-native/src/hooks/use-sync.d.ts +14 -0
- package/dist/client-react-native/src/hooks/use-sync.d.ts.map +1 -0
- package/dist/client-react-native/src/hooks/use-sync.js +67 -0
- package/dist/client-react-native/src/hooks/use-sync.js.map +1 -0
- package/dist/client-react-native/src/index.d.ts +9 -0
- package/dist/client-react-native/src/index.d.ts.map +1 -0
- package/dist/client-react-native/src/index.js +9 -0
- package/dist/client-react-native/src/index.js.map +1 -0
- package/dist/client-react-native/src/provider.d.ts +21 -0
- package/dist/client-react-native/src/provider.d.ts.map +1 -0
- package/dist/client-react-native/src/provider.js +92 -0
- package/dist/client-react-native/src/provider.js.map +1 -0
- package/dist/client-react-native/src/storage/async-storage-adapter.d.ts +16 -0
- package/dist/client-react-native/src/storage/async-storage-adapter.d.ts.map +1 -0
- package/dist/client-react-native/src/storage/async-storage-adapter.js +78 -0
- package/dist/client-react-native/src/storage/async-storage-adapter.js.map +1 -0
- package/dist/client-react-native/src/storage/index.d.ts +2 -0
- package/dist/client-react-native/src/storage/index.d.ts.map +1 -0
- package/dist/client-react-native/src/storage/index.js +2 -0
- package/dist/client-react-native/src/storage/index.js.map +1 -0
- package/dist/shared-types/src/admin.d.ts +101 -0
- package/dist/shared-types/src/admin.d.ts.map +1 -0
- package/dist/shared-types/src/admin.js +3 -0
- package/dist/shared-types/src/admin.js.map +1 -0
- package/dist/shared-types/src/auth.d.ts +27 -0
- package/dist/shared-types/src/auth.d.ts.map +1 -0
- package/dist/shared-types/src/auth.js +2 -0
- package/dist/shared-types/src/auth.js.map +1 -0
- package/dist/shared-types/src/index.d.ts +5 -0
- package/dist/shared-types/src/index.d.ts.map +1 -0
- package/dist/shared-types/src/index.js +5 -0
- package/dist/shared-types/src/index.js.map +1 -0
- package/dist/shared-types/src/schema.d.ts +34 -0
- package/dist/shared-types/src/schema.d.ts.map +1 -0
- package/dist/shared-types/src/schema.js +2 -0
- package/dist/shared-types/src/schema.js.map +1 -0
- package/dist/shared-types/src/sync.d.ts +37 -0
- package/dist/shared-types/src/sync.d.ts.map +1 -0
- package/dist/shared-types/src/sync.js +2 -0
- package/dist/shared-types/src/sync.js.map +1 -0
- package/package.json +36 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
// Outbox manager for tracking offline changes
|
|
2
|
+
/**
|
|
3
|
+
* Outbox manager - tracks offline changes waiting to be synced
|
|
4
|
+
*/
|
|
5
|
+
export class OutboxManager {
|
|
6
|
+
constructor(storage, options = {}) {
|
|
7
|
+
this.outboxKey = 'outbox:items';
|
|
8
|
+
this.entries = new Map();
|
|
9
|
+
this.storage = storage;
|
|
10
|
+
this.maxRetries = options.maxRetries || 3;
|
|
11
|
+
this.retryDelayMs = options.retryDelayMs || 1000;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Initialize outbox from storage
|
|
15
|
+
*/
|
|
16
|
+
async init() {
|
|
17
|
+
try {
|
|
18
|
+
const data = await this.storage.getItem(this.outboxKey);
|
|
19
|
+
if (data) {
|
|
20
|
+
const entries = JSON.parse(data);
|
|
21
|
+
for (const entry of entries) {
|
|
22
|
+
this.entries.set(entry.id, entry);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
console.error('Outbox init error:', error);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Add entry to outbox
|
|
32
|
+
*/
|
|
33
|
+
async add(entry) {
|
|
34
|
+
const id = `outbox_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
35
|
+
const outboxEntry = {
|
|
36
|
+
...entry,
|
|
37
|
+
id,
|
|
38
|
+
attempts: 0,
|
|
39
|
+
};
|
|
40
|
+
this.entries.set(id, outboxEntry);
|
|
41
|
+
await this.persist();
|
|
42
|
+
return outboxEntry;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Get all pending entries
|
|
46
|
+
*/
|
|
47
|
+
async getPending() {
|
|
48
|
+
return Array.from(this.entries.values()).filter((entry) => entry.attempts < this.maxRetries);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Get pending entries for an entity
|
|
52
|
+
*/
|
|
53
|
+
async getPendingForEntity(entity) {
|
|
54
|
+
return (await this.getPending()).filter((entry) => entry.entity === entity);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Mark entry as synced (remove from outbox)
|
|
58
|
+
*/
|
|
59
|
+
async markSynced(entryId) {
|
|
60
|
+
this.entries.delete(entryId);
|
|
61
|
+
await this.persist();
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Mark multiple entries as synced
|
|
65
|
+
*/
|
|
66
|
+
async markSyncedBatch(entryIds) {
|
|
67
|
+
for (const id of entryIds) {
|
|
68
|
+
this.entries.delete(id);
|
|
69
|
+
}
|
|
70
|
+
await this.persist();
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Record failed sync attempt
|
|
74
|
+
*/
|
|
75
|
+
async recordFailure(entryId, error) {
|
|
76
|
+
const entry = this.entries.get(entryId);
|
|
77
|
+
if (entry) {
|
|
78
|
+
entry.attempts++;
|
|
79
|
+
entry.lastError = error;
|
|
80
|
+
entry.lastAttempt = Date.now();
|
|
81
|
+
await this.persist();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Check if entry is ready to retry (exponential backoff)
|
|
86
|
+
*/
|
|
87
|
+
async isReadyToRetry(entryId) {
|
|
88
|
+
const entry = this.entries.get(entryId);
|
|
89
|
+
if (!entry || !entry.lastAttempt) {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
// Exponential backoff: 2^attempts * baseDelay
|
|
93
|
+
const backoffMs = Math.pow(2, entry.attempts) * this.retryDelayMs;
|
|
94
|
+
const now = Date.now();
|
|
95
|
+
return now - entry.lastAttempt >= backoffMs;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Get entries ready for retry
|
|
99
|
+
*/
|
|
100
|
+
async getReadyForRetry() {
|
|
101
|
+
const pending = await this.getPending();
|
|
102
|
+
const ready = [];
|
|
103
|
+
for (const entry of pending) {
|
|
104
|
+
if (await this.isReadyToRetry(entry.id)) {
|
|
105
|
+
ready.push(entry);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return ready;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Clear outbox
|
|
112
|
+
*/
|
|
113
|
+
async clear() {
|
|
114
|
+
this.entries.clear();
|
|
115
|
+
await this.persist();
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Get entry by ID
|
|
119
|
+
*/
|
|
120
|
+
async getEntry(id) {
|
|
121
|
+
return this.entries.get(id) || null;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Get all entries (for debugging)
|
|
125
|
+
*/
|
|
126
|
+
async getAll() {
|
|
127
|
+
return Array.from(this.entries.values());
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Persist entries to storage
|
|
131
|
+
*/
|
|
132
|
+
async persist() {
|
|
133
|
+
try {
|
|
134
|
+
const entries = Array.from(this.entries.values());
|
|
135
|
+
await this.storage.setItem(this.outboxKey, JSON.stringify(entries));
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
console.error('Outbox persist error:', error);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
export default OutboxManager;
|
|
143
|
+
//# sourceMappingURL=outbox-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbox-manager.js","sourceRoot":"","sources":["../../../../../client-core/src/outbox/outbox-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../client-core/src/storage/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../client-core/src/storage/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Abstract storage adapter interface
|
|
3
|
+
* Implementations can use AsyncStorage (React Native), localStorage (Web), SQLite (Desktop), etc.
|
|
4
|
+
*/
|
|
5
|
+
export interface IStorageAdapter {
|
|
6
|
+
/**
|
|
7
|
+
* Get item from storage
|
|
8
|
+
*/
|
|
9
|
+
getItem(key: string): Promise<string | null>;
|
|
10
|
+
/**
|
|
11
|
+
* Set item in storage
|
|
12
|
+
*/
|
|
13
|
+
setItem(key: string, value: string): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Remove item from storage
|
|
16
|
+
*/
|
|
17
|
+
removeItem(key: string): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Clear all items from storage
|
|
20
|
+
*/
|
|
21
|
+
clear(): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Get all keys in storage
|
|
24
|
+
*/
|
|
25
|
+
getAllKeys(): Promise<string[]>;
|
|
26
|
+
/**
|
|
27
|
+
* Get multiple items at once
|
|
28
|
+
*/
|
|
29
|
+
multiGet(keys: string[]): Promise<Array<[string, string | null]>>;
|
|
30
|
+
/**
|
|
31
|
+
* Set multiple items at once
|
|
32
|
+
*/
|
|
33
|
+
multiSet(items: Array<[string, string]>): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Remove multiple items at once
|
|
36
|
+
*/
|
|
37
|
+
multiRemove(keys: string[]): Promise<void>;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* In-memory storage adapter for testing
|
|
41
|
+
*/
|
|
42
|
+
export declare class MemoryStorageAdapter implements IStorageAdapter {
|
|
43
|
+
private store;
|
|
44
|
+
getItem(key: string): Promise<string | null>;
|
|
45
|
+
setItem(key: string, value: string): Promise<void>;
|
|
46
|
+
removeItem(key: string): Promise<void>;
|
|
47
|
+
clear(): Promise<void>;
|
|
48
|
+
getAllKeys(): Promise<string[]>;
|
|
49
|
+
multiGet(keys: string[]): Promise<Array<[string, string | null]>>;
|
|
50
|
+
multiSet(items: Array<[string, string]>): Promise<void>;
|
|
51
|
+
multiRemove(keys: string[]): Promise<void>;
|
|
52
|
+
}
|
|
53
|
+
export default IStorageAdapter;
|
|
54
|
+
//# sourceMappingURL=storage-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-adapter.d.ts","sourceRoot":"","sources":["../../../../../client-core/src/storage/storage-adapter.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAE7C;;OAEG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnD;;OAEG;IACH,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvC;;OAEG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;OAEG;IACH,UAAU,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAEhC;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAElE;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAExD;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5C;AAED;;GAEG;AACH,qBAAa,oBAAqB,YAAW,eAAe;IAC1D,OAAO,CAAC,KAAK,CAAkC;IAEzC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAI5C,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlD,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAItC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,UAAU,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAI/B,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IAIjE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAMvD,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAKjD;AAED,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Storage adapter abstraction - allows different storage implementations
|
|
2
|
+
/**
|
|
3
|
+
* In-memory storage adapter for testing
|
|
4
|
+
*/
|
|
5
|
+
export class MemoryStorageAdapter {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.store = new Map();
|
|
8
|
+
}
|
|
9
|
+
async getItem(key) {
|
|
10
|
+
return this.store.get(key) || null;
|
|
11
|
+
}
|
|
12
|
+
async setItem(key, value) {
|
|
13
|
+
this.store.set(key, value);
|
|
14
|
+
}
|
|
15
|
+
async removeItem(key) {
|
|
16
|
+
this.store.delete(key);
|
|
17
|
+
}
|
|
18
|
+
async clear() {
|
|
19
|
+
this.store.clear();
|
|
20
|
+
}
|
|
21
|
+
async getAllKeys() {
|
|
22
|
+
return Array.from(this.store.keys());
|
|
23
|
+
}
|
|
24
|
+
async multiGet(keys) {
|
|
25
|
+
return keys.map((key) => [key, this.store.get(key) || null]);
|
|
26
|
+
}
|
|
27
|
+
async multiSet(items) {
|
|
28
|
+
for (const [key, value] of items) {
|
|
29
|
+
this.store.set(key, value);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async multiRemove(keys) {
|
|
33
|
+
for (const key of keys) {
|
|
34
|
+
this.store.delete(key);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=storage-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-adapter.js","sourceRoot":"","sources":["../../../../../client-core/src/storage/storage-adapter.ts"],"names":[],"mappings":"AAAA,yEAAyE;AAgDzE;;GAEG;AACH,MAAM,OAAO,oBAAoB;IAAjC;QACU,UAAK,GAAwB,IAAI,GAAG,EAAE,CAAC;IAqCjD,CAAC;IAnCC,KAAK,CAAC,OAAO,CAAC,GAAW;QACvB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,GAAW,EAAE,KAAa;QACtC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,GAAW;QAC1B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,UAAU;QACd,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,IAAc;QAC3B,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;IAC/D,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,KAA8B;QAC3C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,KAAK,EAAE,CAAC;YACjC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,IAAc;QAC9B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../client-core/src/sync/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../client-core/src/sync/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { OutboxManager } from '../outbox/outbox-manager';
|
|
2
|
+
import type { IStorageAdapter } from '../storage/storage-adapter';
|
|
3
|
+
export interface ClientSyncOptions {
|
|
4
|
+
apiUrl: string;
|
|
5
|
+
accessToken: string;
|
|
6
|
+
storage: IStorageAdapter;
|
|
7
|
+
outboxManager: OutboxManager;
|
|
8
|
+
onConflict?: (entity: string, recordId: string, serverData: Record<string, any>) => void;
|
|
9
|
+
onError?: (error: Error) => void;
|
|
10
|
+
}
|
|
11
|
+
export interface SyncStatus {
|
|
12
|
+
isSyncing: boolean;
|
|
13
|
+
lastSyncTimestamp: number | null;
|
|
14
|
+
pendingChanges: number;
|
|
15
|
+
lastError?: Error;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Client-side sync engine
|
|
19
|
+
*/
|
|
20
|
+
export declare class ClientSyncEngine {
|
|
21
|
+
private apiUrl;
|
|
22
|
+
private accessToken;
|
|
23
|
+
private storage;
|
|
24
|
+
private outboxManager;
|
|
25
|
+
private onConflict?;
|
|
26
|
+
private onError?;
|
|
27
|
+
private isSyncing;
|
|
28
|
+
private lastSyncTimestamp;
|
|
29
|
+
private syncStatusKey;
|
|
30
|
+
constructor(options: ClientSyncOptions);
|
|
31
|
+
/**
|
|
32
|
+
* Initialize sync engine
|
|
33
|
+
*/
|
|
34
|
+
init(): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Update access token (for when user logs in)
|
|
37
|
+
*/
|
|
38
|
+
setAccessToken(token: string): void;
|
|
39
|
+
/**
|
|
40
|
+
* Get current sync status
|
|
41
|
+
*/
|
|
42
|
+
getStatus(): Promise<SyncStatus>;
|
|
43
|
+
/**
|
|
44
|
+
* Sync with server
|
|
45
|
+
*/
|
|
46
|
+
sync(): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Send sync request to server
|
|
49
|
+
*/
|
|
50
|
+
private fetchSync;
|
|
51
|
+
/**
|
|
52
|
+
* Process sync response
|
|
53
|
+
*/
|
|
54
|
+
private processResponse;
|
|
55
|
+
/**
|
|
56
|
+
* Add a local change to outbox and sync
|
|
57
|
+
*/
|
|
58
|
+
addChange(entity: string, operation: 'create' | 'update' | 'delete', recordId: string, data: Record<string, any>, version?: number): Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* Clear sync state (for logout/reset)
|
|
61
|
+
*/
|
|
62
|
+
clear(): Promise<void>;
|
|
63
|
+
}
|
|
64
|
+
export default ClientSyncEngine;
|
|
65
|
+
//# sourceMappingURL=sync-engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-engine.d.ts","sourceRoot":"","sources":["../../../../../client-core/src/sync/sync-engine.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAoB,MAAM,0BAA0B,CAAC;AAC3E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAElE,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,eAAe,CAAC;IACzB,aAAa,EAAE,aAAa,CAAC;IAC7B,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC;IACzF,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,KAAK,CAAC;CACnB;AAED;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,UAAU,CAAC,CAA8E;IACjG,OAAO,CAAC,OAAO,CAAC,CAAyB;IACzC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,iBAAiB,CAAuB;IAChD,OAAO,CAAC,aAAa,CAAwB;gBAEjC,OAAO,EAAE,iBAAiB;IAStC;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAM3B;;OAEG;IACH,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAInC;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,UAAU,CAAC;IAStC;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA0C3B;;OAEG;YACW,SAAS;IAiBvB;;OAEG;YACW,eAAe;IAgF7B;;OAEG;IACG,SAAS,CACb,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,EACzC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACzB,OAAO,GAAE,MAAU,GAClB,OAAO,CAAC,IAAI,CAAC;IAkBhB;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAK7B;AAED,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
// Client-side synchronization engine
|
|
2
|
+
import { ConflictResolver } from '../conflict/conflict-resolver';
|
|
3
|
+
/**
|
|
4
|
+
* Client-side sync engine
|
|
5
|
+
*/
|
|
6
|
+
export class ClientSyncEngine {
|
|
7
|
+
constructor(options) {
|
|
8
|
+
this.isSyncing = false;
|
|
9
|
+
this.lastSyncTimestamp = null;
|
|
10
|
+
this.syncStatusKey = 'sync:lastTimestamp';
|
|
11
|
+
this.apiUrl = options.apiUrl;
|
|
12
|
+
this.accessToken = options.accessToken;
|
|
13
|
+
this.storage = options.storage;
|
|
14
|
+
this.outboxManager = options.outboxManager;
|
|
15
|
+
this.onConflict = options.onConflict;
|
|
16
|
+
this.onError = options.onError;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Initialize sync engine
|
|
20
|
+
*/
|
|
21
|
+
async init() {
|
|
22
|
+
await this.outboxManager.init();
|
|
23
|
+
const timestamp = await this.storage.getItem(this.syncStatusKey);
|
|
24
|
+
this.lastSyncTimestamp = timestamp ? parseInt(timestamp, 10) : null;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Update access token (for when user logs in)
|
|
28
|
+
*/
|
|
29
|
+
setAccessToken(token) {
|
|
30
|
+
this.accessToken = token;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Get current sync status
|
|
34
|
+
*/
|
|
35
|
+
async getStatus() {
|
|
36
|
+
const pending = await this.outboxManager.getPending();
|
|
37
|
+
return {
|
|
38
|
+
isSyncing: this.isSyncing,
|
|
39
|
+
lastSyncTimestamp: this.lastSyncTimestamp,
|
|
40
|
+
pendingChanges: pending.length,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Sync with server
|
|
45
|
+
*/
|
|
46
|
+
async sync() {
|
|
47
|
+
if (this.isSyncing) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
this.isSyncing = true;
|
|
51
|
+
try {
|
|
52
|
+
// Get pending changes
|
|
53
|
+
const pending = await this.outboxManager.getPending();
|
|
54
|
+
// Build sync request
|
|
55
|
+
const request = {
|
|
56
|
+
lastSyncTimestamp: this.lastSyncTimestamp,
|
|
57
|
+
changes: pending.map((entry) => ({
|
|
58
|
+
entity: entry.entity,
|
|
59
|
+
operation: entry.operation,
|
|
60
|
+
id: entry.recordId,
|
|
61
|
+
data: entry.data,
|
|
62
|
+
clientTimestamp: entry.clientTimestamp,
|
|
63
|
+
version: entry.version,
|
|
64
|
+
})),
|
|
65
|
+
};
|
|
66
|
+
// Send to server
|
|
67
|
+
const response = await this.fetchSync(request);
|
|
68
|
+
// Process response
|
|
69
|
+
await this.processResponse(response, pending);
|
|
70
|
+
// Update last sync timestamp
|
|
71
|
+
this.lastSyncTimestamp = response.serverTimestamp;
|
|
72
|
+
await this.storage.setItem(this.syncStatusKey, this.lastSyncTimestamp.toString());
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
const err = error instanceof Error ? error : new Error('Sync failed');
|
|
76
|
+
this.onError?.(err);
|
|
77
|
+
throw err;
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
this.isSyncing = false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Send sync request to server
|
|
85
|
+
*/
|
|
86
|
+
async fetchSync(request) {
|
|
87
|
+
const response = await fetch(`${this.apiUrl}/sync`, {
|
|
88
|
+
method: 'POST',
|
|
89
|
+
headers: {
|
|
90
|
+
'Content-Type': 'application/json',
|
|
91
|
+
Authorization: `Bearer ${this.accessToken}`,
|
|
92
|
+
},
|
|
93
|
+
body: JSON.stringify(request),
|
|
94
|
+
});
|
|
95
|
+
if (!response.ok) {
|
|
96
|
+
throw new Error(`Sync request failed: ${response.statusText}`);
|
|
97
|
+
}
|
|
98
|
+
return response.json();
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Process sync response
|
|
102
|
+
*/
|
|
103
|
+
async processResponse(response, outboxEntries) {
|
|
104
|
+
// Process successful changes
|
|
105
|
+
const successfulIds = new Set();
|
|
106
|
+
for (const change of response.changes) {
|
|
107
|
+
// Find corresponding outbox entry
|
|
108
|
+
const entry = outboxEntries.find((e) => e.entity === change.entity && e.recordId === change.id && e.operation === change.operation);
|
|
109
|
+
if (entry) {
|
|
110
|
+
successfulIds.add(entry.id);
|
|
111
|
+
}
|
|
112
|
+
// Update local storage with server version
|
|
113
|
+
const storageKey = `entity:${change.entity}:${change.id}`;
|
|
114
|
+
await this.storage.setItem(storageKey, JSON.stringify(change.data));
|
|
115
|
+
}
|
|
116
|
+
// Process conflicts
|
|
117
|
+
for (const conflict of response.conflicts) {
|
|
118
|
+
// Resolve conflict (default: server wins)
|
|
119
|
+
const resolution = ConflictResolver.resolveLWW({
|
|
120
|
+
entity: conflict.entity,
|
|
121
|
+
recordId: conflict.id,
|
|
122
|
+
clientVersion: conflict.clientVersion,
|
|
123
|
+
serverVersion: conflict.serverVersion,
|
|
124
|
+
clientData: {}, // Client data not in conflict object
|
|
125
|
+
serverData: conflict.serverData,
|
|
126
|
+
});
|
|
127
|
+
// Update local storage with resolved data
|
|
128
|
+
const storageKey = `entity:${conflict.entity}:${conflict.id}`;
|
|
129
|
+
await this.storage.setItem(storageKey, JSON.stringify(resolution.resolvedData));
|
|
130
|
+
// Notify caller of conflict
|
|
131
|
+
this.onConflict?.(conflict.entity, conflict.id, conflict.serverData);
|
|
132
|
+
// Remove from outbox since server won
|
|
133
|
+
const entry = outboxEntries.find((e) => e.entity === conflict.entity && e.recordId === conflict.id);
|
|
134
|
+
if (entry) {
|
|
135
|
+
successfulIds.add(entry.id);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// Process errors
|
|
139
|
+
for (const error of response.errors) {
|
|
140
|
+
// Find outbox entry
|
|
141
|
+
const entry = outboxEntries.find((e) => e.entity === error.entity && e.recordId === error.id && e.operation === error.operation);
|
|
142
|
+
if (entry) {
|
|
143
|
+
if (error.code === 'ACCESS_DENIED') {
|
|
144
|
+
// Access denied - remove from outbox and revert local changes
|
|
145
|
+
successfulIds.add(entry.id);
|
|
146
|
+
// Revert to previous state or delete from local storage
|
|
147
|
+
const storageKey = `entity:${error.entity}:${error.id}`;
|
|
148
|
+
await this.storage.removeItem(storageKey);
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
// Other errors - record failure for retry
|
|
152
|
+
await this.outboxManager.recordFailure(entry.id, error.error);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// Remove successful entries from outbox
|
|
157
|
+
if (successfulIds.size > 0) {
|
|
158
|
+
await this.outboxManager.markSyncedBatch(Array.from(successfulIds));
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Add a local change to outbox and sync
|
|
163
|
+
*/
|
|
164
|
+
async addChange(entity, operation, recordId, data, version = 1) {
|
|
165
|
+
// Add to outbox
|
|
166
|
+
await this.outboxManager.add({
|
|
167
|
+
entity,
|
|
168
|
+
operation,
|
|
169
|
+
recordId,
|
|
170
|
+
data,
|
|
171
|
+
clientTimestamp: Date.now(),
|
|
172
|
+
version,
|
|
173
|
+
});
|
|
174
|
+
// Try to sync (will be handled by background sync if fails)
|
|
175
|
+
// Don't await to allow optimistic updates
|
|
176
|
+
this.sync().catch(() => {
|
|
177
|
+
// Sync failed - will retry in background
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Clear sync state (for logout/reset)
|
|
182
|
+
*/
|
|
183
|
+
async clear() {
|
|
184
|
+
this.lastSyncTimestamp = null;
|
|
185
|
+
await this.outboxManager.clear();
|
|
186
|
+
await this.storage.removeItem(this.syncStatusKey);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
export default ClientSyncEngine;
|
|
190
|
+
//# sourceMappingURL=sync-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-engine.js","sourceRoot":"","sources":["../../../../../client-core/src/sync/sync-engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { User } from '@edgebasejs/types';
|
|
2
|
+
export interface UseAuthResult {
|
|
3
|
+
user: User | null;
|
|
4
|
+
isAuthenticated: boolean;
|
|
5
|
+
isLoading: boolean;
|
|
6
|
+
error: Error | null;
|
|
7
|
+
login: (email: string, password: string) => Promise<void>;
|
|
8
|
+
register: (email: string, password: string) => Promise<void>;
|
|
9
|
+
logout: () => Promise<void>;
|
|
10
|
+
refreshToken: () => Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Hook to access authentication state and functions
|
|
14
|
+
*/
|
|
15
|
+
export declare function useAuth(): UseAuthResult;
|
|
16
|
+
export default useAuth;
|
|
17
|
+
//# sourceMappingURL=use-auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-auth.d.ts","sourceRoot":"","sources":["../../../../src/hooks/use-auth.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAI9C,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAClB,eAAe,EAAE,OAAO,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACnC;AAED;;GAEG;AACH,wBAAgB,OAAO,IAAI,aAAa,CA+EvC;AAED,eAAe,OAAO,CAAC"}
|