@edgebasejs/react-native 0.1.8 → 0.1.9

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 (145) hide show
  1. package/README.md +18 -0
  2. package/dist/client-core/src/index.d.ts +4 -0
  3. package/dist/client-core/src/index.d.ts.map +1 -1
  4. package/dist/client-core/src/index.js +4 -0
  5. package/dist/client-core/src/index.js.map +1 -1
  6. package/dist/client-core/src/mutations/batch-processor-client.d.ts +67 -0
  7. package/dist/client-core/src/mutations/batch-processor-client.d.ts.map +1 -0
  8. package/dist/client-core/src/mutations/batch-processor-client.js +64 -0
  9. package/dist/client-core/src/mutations/batch-processor-client.js.map +1 -0
  10. package/dist/client-core/src/mutations/transaction-hook.d.ts +80 -0
  11. package/dist/client-core/src/mutations/transaction-hook.d.ts.map +1 -0
  12. package/dist/client-core/src/mutations/transaction-hook.js +204 -0
  13. package/dist/client-core/src/mutations/transaction-hook.js.map +1 -0
  14. package/dist/client-core/src/realtime/realtime-sync-manager.d.ts +55 -0
  15. package/dist/client-core/src/realtime/realtime-sync-manager.d.ts.map +1 -0
  16. package/dist/client-core/src/realtime/realtime-sync-manager.js +208 -0
  17. package/dist/client-core/src/realtime/realtime-sync-manager.js.map +1 -0
  18. package/dist/client-core/src/realtime/subscription-handler.d.ts +74 -0
  19. package/dist/client-core/src/realtime/subscription-handler.d.ts.map +1 -0
  20. package/dist/client-core/src/realtime/subscription-handler.js +224 -0
  21. package/dist/client-core/src/realtime/subscription-handler.js.map +1 -0
  22. package/dist/client-core/src/sync/sync-engine.d.ts +10 -0
  23. package/dist/client-core/src/sync/sync-engine.d.ts.map +1 -1
  24. package/dist/client-core/src/sync/sync-engine.js +37 -5
  25. package/dist/client-core/src/sync/sync-engine.js.map +1 -1
  26. package/dist/client-react-native/src/hooks/index.d.ts +10 -0
  27. package/dist/client-react-native/src/hooks/index.d.ts.map +1 -1
  28. package/dist/client-react-native/src/hooks/index.js +8 -0
  29. package/dist/client-react-native/src/hooks/index.js.map +1 -1
  30. package/dist/client-react-native/src/hooks/use-audit.d.ts +65 -0
  31. package/dist/client-react-native/src/hooks/use-audit.d.ts.map +1 -0
  32. package/dist/client-react-native/src/hooks/use-audit.js +201 -0
  33. package/dist/client-react-native/src/hooks/use-audit.js.map +1 -0
  34. package/dist/client-react-native/src/hooks/use-batch-mutation.d.ts +56 -0
  35. package/dist/client-react-native/src/hooks/use-batch-mutation.d.ts.map +1 -0
  36. package/dist/client-react-native/src/hooks/use-batch-mutation.js +95 -0
  37. package/dist/client-react-native/src/hooks/use-batch-mutation.js.map +1 -0
  38. package/dist/client-react-native/src/hooks/use-encryption.d.ts +45 -0
  39. package/dist/client-react-native/src/hooks/use-encryption.d.ts.map +1 -0
  40. package/dist/client-react-native/src/hooks/use-encryption.js +143 -0
  41. package/dist/client-react-native/src/hooks/use-encryption.js.map +1 -0
  42. package/dist/client-react-native/src/hooks/use-file-manager.d.ts +38 -0
  43. package/dist/client-react-native/src/hooks/use-file-manager.d.ts.map +1 -0
  44. package/dist/client-react-native/src/hooks/use-file-manager.js +174 -0
  45. package/dist/client-react-native/src/hooks/use-file-manager.js.map +1 -0
  46. package/dist/client-react-native/src/hooks/use-file-upload.d.ts +34 -0
  47. package/dist/client-react-native/src/hooks/use-file-upload.d.ts.map +1 -0
  48. package/dist/client-react-native/src/hooks/use-file-upload.js +85 -0
  49. package/dist/client-react-native/src/hooks/use-file-upload.js.map +1 -0
  50. package/dist/client-react-native/src/hooks/use-mutation.d.ts.map +1 -1
  51. package/dist/client-react-native/src/hooks/use-mutation.js +34 -6
  52. package/dist/client-react-native/src/hooks/use-mutation.js.map +1 -1
  53. package/dist/client-react-native/src/hooks/use-search.d.ts +33 -0
  54. package/dist/client-react-native/src/hooks/use-search.d.ts.map +1 -0
  55. package/dist/client-react-native/src/hooks/use-search.js +174 -0
  56. package/dist/client-react-native/src/hooks/use-search.js.map +1 -0
  57. package/dist/client-react-native/src/hooks/use-subscribe.d.ts +14 -0
  58. package/dist/client-react-native/src/hooks/use-subscribe.d.ts.map +1 -0
  59. package/dist/client-react-native/src/hooks/use-subscribe.js +165 -0
  60. package/dist/client-react-native/src/hooks/use-subscribe.js.map +1 -0
  61. package/dist/client-react-native/src/hooks/use-transaction.d.ts +27 -0
  62. package/dist/client-react-native/src/hooks/use-transaction.d.ts.map +1 -0
  63. package/dist/client-react-native/src/hooks/use-transaction.js +160 -0
  64. package/dist/client-react-native/src/hooks/use-transaction.js.map +1 -0
  65. package/dist/client-react-native/src/provider.d.ts +5 -2
  66. package/dist/client-react-native/src/provider.d.ts.map +1 -1
  67. package/dist/client-react-native/src/provider.js +23 -23
  68. package/dist/client-react-native/src/provider.js.map +1 -1
  69. package/dist/core/src/access-rules/column-security.d.ts +80 -0
  70. package/dist/core/src/access-rules/column-security.d.ts.map +1 -0
  71. package/dist/core/src/access-rules/column-security.js +191 -0
  72. package/dist/core/src/access-rules/column-security.js.map +1 -0
  73. package/dist/core/src/access-rules/engine.d.ts +26 -0
  74. package/dist/core/src/access-rules/engine.d.ts.map +1 -0
  75. package/dist/core/src/access-rules/engine.js +76 -0
  76. package/dist/core/src/access-rules/engine.js.map +1 -0
  77. package/dist/core/src/access-rules/index.d.ts +3 -0
  78. package/dist/core/src/access-rules/index.d.ts.map +1 -0
  79. package/dist/core/src/access-rules/index.js +3 -0
  80. package/dist/core/src/access-rules/index.js.map +1 -0
  81. package/dist/core/src/audit/audit-manager.d.ts +108 -0
  82. package/dist/core/src/audit/audit-manager.d.ts.map +1 -0
  83. package/dist/core/src/audit/audit-manager.js +265 -0
  84. package/dist/core/src/audit/audit-manager.js.map +1 -0
  85. package/dist/core/src/auth/auth-service.d.ts +71 -0
  86. package/dist/core/src/auth/auth-service.d.ts.map +1 -0
  87. package/dist/core/src/auth/auth-service.js +177 -0
  88. package/dist/core/src/auth/auth-service.js.map +1 -0
  89. package/dist/core/src/auth/index.d.ts +4 -0
  90. package/dist/core/src/auth/index.d.ts.map +1 -0
  91. package/dist/core/src/auth/index.js +4 -0
  92. package/dist/core/src/auth/index.js.map +1 -0
  93. package/dist/core/src/encryption/encryption-manager.d.ts +97 -0
  94. package/dist/core/src/encryption/encryption-manager.d.ts.map +1 -0
  95. package/dist/core/src/encryption/encryption-manager.js +224 -0
  96. package/dist/core/src/encryption/encryption-manager.js.map +1 -0
  97. package/dist/core/src/index.d.ts +16 -0
  98. package/dist/core/src/index.d.ts.map +1 -0
  99. package/dist/core/src/index.js +16 -0
  100. package/dist/core/src/index.js.map +1 -0
  101. package/dist/core/src/realtime/change-notifier.d.ts +50 -0
  102. package/dist/core/src/realtime/change-notifier.d.ts.map +1 -0
  103. package/dist/core/src/realtime/change-notifier.js +145 -0
  104. package/dist/core/src/realtime/change-notifier.js.map +1 -0
  105. package/dist/core/src/realtime/message-types.d.ts +39 -0
  106. package/dist/core/src/realtime/message-types.d.ts.map +1 -0
  107. package/dist/core/src/realtime/message-types.js +5 -0
  108. package/dist/core/src/realtime/message-types.js.map +1 -0
  109. package/dist/core/src/realtime/subscription-manager.d.ts +67 -0
  110. package/dist/core/src/realtime/subscription-manager.d.ts.map +1 -0
  111. package/dist/core/src/realtime/subscription-manager.js +229 -0
  112. package/dist/core/src/realtime/subscription-manager.js.map +1 -0
  113. package/dist/core/src/search/search-manager.d.ts +93 -0
  114. package/dist/core/src/search/search-manager.d.ts.map +1 -0
  115. package/dist/core/src/search/search-manager.js +258 -0
  116. package/dist/core/src/search/search-manager.js.map +1 -0
  117. package/dist/core/src/storage/file-manager.d.ts +138 -0
  118. package/dist/core/src/storage/file-manager.d.ts.map +1 -0
  119. package/dist/core/src/storage/file-manager.js +224 -0
  120. package/dist/core/src/storage/file-manager.js.map +1 -0
  121. package/dist/core/src/sync/batch-processor.d.ts +97 -0
  122. package/dist/core/src/sync/batch-processor.d.ts.map +1 -0
  123. package/dist/core/src/sync/batch-processor.js +313 -0
  124. package/dist/core/src/sync/batch-processor.js.map +1 -0
  125. package/dist/core/src/sync/csv-processor.d.ts +66 -0
  126. package/dist/core/src/sync/csv-processor.d.ts.map +1 -0
  127. package/dist/core/src/sync/csv-processor.js +223 -0
  128. package/dist/core/src/sync/csv-processor.js.map +1 -0
  129. package/dist/core/src/sync/index.d.ts +3 -0
  130. package/dist/core/src/sync/index.d.ts.map +1 -0
  131. package/dist/core/src/sync/index.js +3 -0
  132. package/dist/core/src/sync/index.js.map +1 -0
  133. package/dist/core/src/sync/sync-engine.d.ts +68 -0
  134. package/dist/core/src/sync/sync-engine.d.ts.map +1 -0
  135. package/dist/core/src/sync/sync-engine.js +317 -0
  136. package/dist/core/src/sync/sync-engine.js.map +1 -0
  137. package/dist/core/src/sync/transaction-manager.d.ts +83 -0
  138. package/dist/core/src/sync/transaction-manager.d.ts.map +1 -0
  139. package/dist/core/src/sync/transaction-manager.js +227 -0
  140. package/dist/core/src/sync/transaction-manager.js.map +1 -0
  141. package/dist/core/src/webhooks/webhook-manager.d.ts +137 -0
  142. package/dist/core/src/webhooks/webhook-manager.d.ts.map +1 -0
  143. package/dist/core/src/webhooks/webhook-manager.js +334 -0
  144. package/dist/core/src/webhooks/webhook-manager.js.map +1 -0
  145. package/package.json +4 -6
@@ -0,0 +1,208 @@
1
+ /**
2
+ * Manages real-time sync between WebSocket changes and local storage
3
+ * Handles merging of server changes with local data
4
+ */
5
+ export class RealtimeSyncManager {
6
+ constructor(storage) {
7
+ this.storage = storage;
8
+ this.changeListeners = new Map();
9
+ }
10
+ /**
11
+ * Subscribe to changes for a specific entity
12
+ */
13
+ onEntityChange(entity, listener) {
14
+ if (!this.changeListeners.has(entity)) {
15
+ this.changeListeners.set(entity, new Set());
16
+ }
17
+ this.changeListeners.get(entity).add(listener);
18
+ // Return unsubscribe function
19
+ return () => {
20
+ this.changeListeners.get(entity)?.delete(listener);
21
+ };
22
+ }
23
+ /**
24
+ * Handle incoming WebSocket change message
25
+ * Merges with local storage using server-authoritative conflict resolution
26
+ */
27
+ async handleChange(change) {
28
+ try {
29
+ const { entity, operation, record, recordId, version, timestamp } = change;
30
+ switch (operation) {
31
+ case 'create':
32
+ case 'update':
33
+ if (!record || !recordId)
34
+ break;
35
+ // Store in local storage with new version
36
+ const key = `entity:${entity}:${recordId}`;
37
+ const storedData = {
38
+ ...record,
39
+ _version: version || 0,
40
+ _syncedAt: timestamp || Date.now(),
41
+ _synced: true, // Mark as synced from server
42
+ };
43
+ await this.storage.setItem(key, JSON.stringify(storedData));
44
+ // Notify listeners
45
+ this.notifyListeners(entity, change);
46
+ break;
47
+ case 'delete':
48
+ if (!recordId)
49
+ break;
50
+ // Remove from local storage
51
+ const deleteKey = `entity:${entity}:${recordId}`;
52
+ await this.storage.removeItem(deleteKey);
53
+ // Notify listeners
54
+ this.notifyListeners(entity, change);
55
+ break;
56
+ }
57
+ }
58
+ catch (error) {
59
+ console.error('Failed to handle real-time change:', error);
60
+ }
61
+ }
62
+ /**
63
+ * Notify listeners about a change
64
+ */
65
+ notifyListeners(entity, change) {
66
+ const listeners = this.changeListeners.get(entity);
67
+ if (listeners) {
68
+ for (const listener of listeners) {
69
+ try {
70
+ listener(change);
71
+ }
72
+ catch (error) {
73
+ console.error('Listener error:', error);
74
+ }
75
+ }
76
+ }
77
+ }
78
+ /**
79
+ * Get all data for an entity from local storage
80
+ */
81
+ async getEntityData(entity) {
82
+ try {
83
+ const allKeys = await this.storage.getAllKeys();
84
+ const entityKeys = allKeys.filter((key) => key.startsWith(`entity:${entity}:`));
85
+ const results = [];
86
+ for (const key of entityKeys) {
87
+ const data = await this.storage.getItem(key);
88
+ if (data) {
89
+ results.push(JSON.parse(data));
90
+ }
91
+ }
92
+ return results;
93
+ }
94
+ catch (error) {
95
+ console.error('Failed to get entity data:', error);
96
+ return [];
97
+ }
98
+ }
99
+ /**
100
+ * Get a single record by ID
101
+ */
102
+ async getRecord(entity, recordId) {
103
+ try {
104
+ const key = `entity:${entity}:${recordId}`;
105
+ const data = await this.storage.getItem(key);
106
+ if (data) {
107
+ return JSON.parse(data);
108
+ }
109
+ return null;
110
+ }
111
+ catch (error) {
112
+ console.error('Failed to get record:', error);
113
+ return null;
114
+ }
115
+ }
116
+ /**
117
+ * Merge outbox changes with server updates
118
+ * Used during sync to detect conflicts
119
+ */
120
+ async mergeWithOutbox(entity, recordId, serverRecord, serverVersion) {
121
+ try {
122
+ const key = `entity:${entity}:${recordId}`;
123
+ const stored = await this.storage.getItem(key);
124
+ let localData = stored ? JSON.parse(stored) : null;
125
+ if (!localData) {
126
+ // No local data, use server data
127
+ return {
128
+ resolved: true,
129
+ data: serverRecord,
130
+ };
131
+ }
132
+ // Check if there are local changes (indicated by _outbox flag)
133
+ if (localData._outbox) {
134
+ // Conflict: local changes conflict with server update
135
+ return {
136
+ resolved: false,
137
+ data: serverRecord, // Server wins (authoritative)
138
+ conflict: true,
139
+ };
140
+ }
141
+ // No local changes, use server data
142
+ return {
143
+ resolved: true,
144
+ data: serverRecord,
145
+ };
146
+ }
147
+ catch (error) {
148
+ console.error('Failed to merge with outbox:', error);
149
+ return {
150
+ resolved: true,
151
+ data: serverRecord,
152
+ };
153
+ }
154
+ }
155
+ /**
156
+ * Clear all data for an entity
157
+ */
158
+ async clearEntity(entity) {
159
+ try {
160
+ const allKeys = await this.storage.getAllKeys();
161
+ const entityKeys = allKeys.filter((key) => key.startsWith(`entity:${entity}:`));
162
+ for (const key of entityKeys) {
163
+ await this.storage.removeItem(key);
164
+ }
165
+ }
166
+ catch (error) {
167
+ console.error('Failed to clear entity:', error);
168
+ }
169
+ }
170
+ /**
171
+ * Get sync metadata for entity
172
+ * Used to track which records have been synced
173
+ */
174
+ async getSyncStatus(entity) {
175
+ try {
176
+ const data = await this.getEntityData(entity);
177
+ return {
178
+ entity,
179
+ totalRecords: data.length,
180
+ syncedRecords: data.filter((d) => d._synced).length,
181
+ pendingRecords: data.filter((d) => d._outbox).length,
182
+ lastUpdate: Math.max(...data.map((d) => d._syncedAt || 0), 0),
183
+ };
184
+ }
185
+ catch (error) {
186
+ console.error('Failed to get sync status:', error);
187
+ return {
188
+ entity,
189
+ totalRecords: 0,
190
+ syncedRecords: 0,
191
+ pendingRecords: 0,
192
+ lastUpdate: 0,
193
+ };
194
+ }
195
+ }
196
+ /**
197
+ * Listen for all changes across entities
198
+ */
199
+ onAnyChange(listener) {
200
+ const allListener = (change) => {
201
+ listener(change.entity, change);
202
+ };
203
+ // This is a catch-all listener that would need to be managed separately
204
+ // For now, return a no-op unsubscribe since we don't have a global listener yet
205
+ return () => { };
206
+ }
207
+ }
208
+ //# sourceMappingURL=realtime-sync-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-sync-manager.js","sourceRoot":"","sources":["../../../../../client-core/src/realtime/realtime-sync-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ import type { ChangeMessage } from '@edgebasejs/core';
2
+ export interface SubscriptionOptions {
3
+ entity: string;
4
+ filters?: Record<string, unknown>;
5
+ onData?: (change: ChangeMessage) => void;
6
+ onError?: (error: Error) => void;
7
+ onSubscribed?: (subscriptionId: string) => void;
8
+ onUnsubscribed?: () => void;
9
+ }
10
+ export interface ConnectionConfig {
11
+ url: string;
12
+ token: string;
13
+ reconnectAttempts?: number;
14
+ reconnectDelay?: number;
15
+ heartbeatInterval?: number;
16
+ }
17
+ /**
18
+ * Manages WebSocket connection and subscriptions on the client side
19
+ */
20
+ export declare class ClientSubscriptionHandler {
21
+ private config;
22
+ private ws;
23
+ private subscriptions;
24
+ private reconnectAttempts;
25
+ private reconnectTimeout;
26
+ private heartbeatTimeout;
27
+ private messageHandlers;
28
+ constructor(config: ConnectionConfig);
29
+ /**
30
+ * Connect to WebSocket server
31
+ */
32
+ connect(): Promise<void>;
33
+ /**
34
+ * Subscribe to entity changes
35
+ */
36
+ subscribe(options: SubscriptionOptions): string;
37
+ /**
38
+ * Unsubscribe from entity changes
39
+ */
40
+ unsubscribe(subscriptionId: string): void;
41
+ /**
42
+ * Handle incoming WebSocket messages
43
+ */
44
+ private handleMessage;
45
+ /**
46
+ * Send heartbeat to server
47
+ */
48
+ private sendHeartbeat;
49
+ /**
50
+ * Setup periodic heartbeat
51
+ */
52
+ private setupHeartbeat;
53
+ /**
54
+ * Clear heartbeat
55
+ */
56
+ private clearHeartbeat;
57
+ /**
58
+ * Attempt to reconnect with exponential backoff
59
+ */
60
+ private attemptReconnect;
61
+ /**
62
+ * Disconnect from WebSocket
63
+ */
64
+ disconnect(): void;
65
+ /**
66
+ * Check if connected
67
+ */
68
+ isConnected(): boolean;
69
+ /**
70
+ * Get subscription count
71
+ */
72
+ getSubscriptionCount(): number;
73
+ }
74
+ //# sourceMappingURL=subscription-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscription-handler.d.ts","sourceRoot":"","sources":["../../../../../client-core/src/realtime/subscription-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAuB,MAAM,kBAAkB,CAAC;AAE3E,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;IACzC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,YAAY,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,qBAAa,yBAAyB;IAQxB,OAAO,CAAC,MAAM;IAP1B,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,aAAa,CAA0C;IAC/D,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,gBAAgB,CAA8C;IACtE,OAAO,CAAC,gBAAgB,CAA+C;IACvE,OAAO,CAAC,eAAe,CAA6C;gBAEhD,MAAM,EAAE,gBAAgB;IAE5C;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAiC9B;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,mBAAmB,GAAG,MAAM;IAsC/C;;OAEG;IACH,WAAW,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI;IAkBzC;;OAEG;IACH,OAAO,CAAC,aAAa;IAsDrB;;OAEG;IACH,OAAO,CAAC,aAAa;IAUrB;;OAEG;IACH,OAAO,CAAC,cAAc;IAOtB;;OAEG;IACH,OAAO,CAAC,cAAc;IAOtB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAkBxB;;OAEG;IACH,UAAU,IAAI,IAAI;IAiBlB;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACH,oBAAoB,IAAI,MAAM;CAG/B"}
@@ -0,0 +1,224 @@
1
+ /**
2
+ * Manages WebSocket connection and subscriptions on the client side
3
+ */
4
+ export class ClientSubscriptionHandler {
5
+ constructor(config) {
6
+ this.config = config;
7
+ this.ws = null;
8
+ this.subscriptions = new Map();
9
+ this.reconnectAttempts = 0;
10
+ this.reconnectTimeout = null;
11
+ this.heartbeatTimeout = null;
12
+ this.messageHandlers = new Map();
13
+ }
14
+ /**
15
+ * Connect to WebSocket server
16
+ */
17
+ async connect() {
18
+ return new Promise((resolve, reject) => {
19
+ try {
20
+ const wsUrl = this.config.url.replace(/^http/, 'ws');
21
+ this.ws = new WebSocket(wsUrl);
22
+ this.ws.onopen = () => {
23
+ console.log('WebSocket connected');
24
+ this.reconnectAttempts = 0;
25
+ this.setupHeartbeat();
26
+ resolve();
27
+ };
28
+ this.ws.onmessage = (event) => {
29
+ this.handleMessage(event.data);
30
+ };
31
+ this.ws.onerror = (error) => {
32
+ console.error('WebSocket error:', error);
33
+ reject(new Error('WebSocket connection failed'));
34
+ };
35
+ this.ws.onclose = () => {
36
+ console.log('WebSocket disconnected');
37
+ this.clearHeartbeat();
38
+ this.attemptReconnect();
39
+ };
40
+ }
41
+ catch (error) {
42
+ reject(error);
43
+ }
44
+ });
45
+ }
46
+ /**
47
+ * Subscribe to entity changes
48
+ */
49
+ subscribe(options) {
50
+ const subscriptionId = `csub_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
51
+ // Store subscription locally
52
+ this.subscriptions.set(subscriptionId, options);
53
+ // Register message handler for this subscription
54
+ this.messageHandlers.set(subscriptionId, (message) => {
55
+ if (message.entity === options.entity) {
56
+ // Check if filters match
57
+ if (options.filters && message.record) {
58
+ let matches = true;
59
+ for (const [key, value] of Object.entries(options.filters)) {
60
+ if (message.record[key] !== value) {
61
+ matches = false;
62
+ break;
63
+ }
64
+ }
65
+ if (!matches)
66
+ return;
67
+ }
68
+ options.onData?.(message);
69
+ }
70
+ });
71
+ // Send subscription message to server
72
+ if (this.ws?.readyState === WebSocket.OPEN) {
73
+ const message = {
74
+ type: 'subscribe',
75
+ entity: options.entity,
76
+ filters: options.filters,
77
+ };
78
+ this.ws.send(JSON.stringify(message));
79
+ }
80
+ return subscriptionId;
81
+ }
82
+ /**
83
+ * Unsubscribe from entity changes
84
+ */
85
+ unsubscribe(subscriptionId) {
86
+ const options = this.subscriptions.get(subscriptionId);
87
+ if (!options)
88
+ return;
89
+ // Remove subscription
90
+ this.subscriptions.delete(subscriptionId);
91
+ this.messageHandlers.delete(subscriptionId);
92
+ // Send unsubscribe message to server
93
+ if (this.ws?.readyState === WebSocket.OPEN) {
94
+ const message = {
95
+ type: 'unsubscribe',
96
+ entity: options.entity,
97
+ };
98
+ this.ws.send(JSON.stringify(message));
99
+ }
100
+ }
101
+ /**
102
+ * Handle incoming WebSocket messages
103
+ */
104
+ handleMessage(data) {
105
+ try {
106
+ const message = JSON.parse(data);
107
+ switch (message.type) {
108
+ case 'change':
109
+ // Broadcast to all registered handlers
110
+ for (const handler of this.messageHandlers.values()) {
111
+ handler(message);
112
+ }
113
+ break;
114
+ case 'subscribed':
115
+ // Find the subscription that was just created
116
+ const subOptions = Array.from(this.subscriptions.values()).find((sub) => sub.entity === message.entity);
117
+ if (subOptions) {
118
+ subOptions.onSubscribed?.(message.subscriptionId);
119
+ }
120
+ break;
121
+ case 'unsubscribed':
122
+ const unsubOptions = Array.from(this.subscriptions.values()).find((sub) => sub.entity === message.entity);
123
+ if (unsubOptions) {
124
+ unsubOptions.onUnsubscribed?.();
125
+ }
126
+ break;
127
+ case 'error':
128
+ console.error(`Server error: ${message.code} - ${message.message}`);
129
+ for (const sub of this.subscriptions.values()) {
130
+ sub.onError?.(new Error(message.message));
131
+ }
132
+ break;
133
+ case 'connected':
134
+ console.log(`Connected to server with connectionId: ${message.connectionId}`);
135
+ break;
136
+ case 'heartbeat':
137
+ // Server heartbeat - no action needed
138
+ break;
139
+ default:
140
+ console.warn(`Unknown message type: ${message.type}`);
141
+ }
142
+ }
143
+ catch (error) {
144
+ console.error('Failed to parse WebSocket message:', error);
145
+ }
146
+ }
147
+ /**
148
+ * Send heartbeat to server
149
+ */
150
+ sendHeartbeat() {
151
+ if (this.ws?.readyState === WebSocket.OPEN) {
152
+ const message = {
153
+ type: 'heartbeat',
154
+ timestamp: Date.now(),
155
+ };
156
+ this.ws.send(JSON.stringify(message));
157
+ }
158
+ }
159
+ /**
160
+ * Setup periodic heartbeat
161
+ */
162
+ setupHeartbeat() {
163
+ const interval = this.config.heartbeatInterval || 30000;
164
+ this.heartbeatTimeout = setInterval(() => {
165
+ this.sendHeartbeat();
166
+ }, interval);
167
+ }
168
+ /**
169
+ * Clear heartbeat
170
+ */
171
+ clearHeartbeat() {
172
+ if (this.heartbeatTimeout) {
173
+ clearInterval(this.heartbeatTimeout);
174
+ this.heartbeatTimeout = null;
175
+ }
176
+ }
177
+ /**
178
+ * Attempt to reconnect with exponential backoff
179
+ */
180
+ attemptReconnect() {
181
+ const maxAttempts = this.config.reconnectAttempts || 5;
182
+ if (this.reconnectAttempts >= maxAttempts) {
183
+ console.error('Max reconnection attempts reached');
184
+ return;
185
+ }
186
+ this.reconnectAttempts++;
187
+ const delay = (this.config.reconnectDelay || 1000) * Math.pow(2, this.reconnectAttempts - 1);
188
+ console.log(`Attempting to reconnect in ${delay}ms...`);
189
+ this.reconnectTimeout = setTimeout(() => {
190
+ this.connect().catch((error) => {
191
+ console.error('Reconnection failed:', error);
192
+ });
193
+ }, delay);
194
+ }
195
+ /**
196
+ * Disconnect from WebSocket
197
+ */
198
+ disconnect() {
199
+ if (this.reconnectTimeout) {
200
+ clearTimeout(this.reconnectTimeout);
201
+ this.reconnectTimeout = null;
202
+ }
203
+ this.clearHeartbeat();
204
+ if (this.ws) {
205
+ this.ws.close();
206
+ this.ws = null;
207
+ }
208
+ this.subscriptions.clear();
209
+ this.messageHandlers.clear();
210
+ }
211
+ /**
212
+ * Check if connected
213
+ */
214
+ isConnected() {
215
+ return this.ws?.readyState === WebSocket.OPEN;
216
+ }
217
+ /**
218
+ * Get subscription count
219
+ */
220
+ getSubscriptionCount() {
221
+ return this.subscriptions.size;
222
+ }
223
+ }
224
+ //# sourceMappingURL=subscription-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscription-handler.js","sourceRoot":"","sources":["../../../../../client-core/src/realtime/subscription-handler.ts"],"names":[],"mappings":"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"}
@@ -5,6 +5,7 @@ export interface ClientSyncOptions {
5
5
  accessToken: string;
6
6
  storage: IStorageAdapter;
7
7
  outboxManager: OutboxManager;
8
+ autoSync?: boolean;
8
9
  onConflict?: (entity: string, recordId: string, serverData: Record<string, any>) => void;
9
10
  onError?: (error: Error) => void;
10
11
  }
@@ -24,6 +25,7 @@ export declare class ClientSyncEngine {
24
25
  private outboxManager;
25
26
  private onConflict?;
26
27
  private onError?;
28
+ private autoSync;
27
29
  private isSyncing;
28
30
  private lastSyncTimestamp;
29
31
  private syncStatusKey;
@@ -36,6 +38,10 @@ export declare class ClientSyncEngine {
36
38
  * Update access token (for when user logs in)
37
39
  */
38
40
  setAccessToken(token: string): void;
41
+ /**
42
+ * Enable or disable automatic synchronization
43
+ */
44
+ setAutoSync(enabled: boolean): void;
39
45
  /**
40
46
  * Get current sync status
41
47
  */
@@ -44,6 +50,10 @@ export declare class ClientSyncEngine {
44
50
  * Sync with server
45
51
  */
46
52
  sync(): Promise<void>;
53
+ /**
54
+ * Force a full sync (ignore lastSyncTimestamp)
55
+ */
56
+ syncFull(): Promise<void>;
47
57
  /**
48
58
  * Send sync request to server
49
59
  */
@@ -1 +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"}
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,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,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,QAAQ,CAAU;IAC1B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,iBAAiB,CAAuB;IAChD,OAAO,CAAC,aAAa,CAAwB;gBAEjC,OAAO,EAAE,iBAAiB;IAUtC;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAM3B;;OAEG;IACH,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAInC;;OAEG;IACH,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAInC;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,UAAU,CAAC;IAStC;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA0C3B;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAM/B;;OAEG;YACW,SAAS;IAiBvB;;OAEG;YACW,eAAe;IAiG7B;;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;IAoBhB;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAK7B;AAED,eAAe,gBAAgB,CAAC"}
@@ -14,6 +14,7 @@ export class ClientSyncEngine {
14
14
  this.outboxManager = options.outboxManager;
15
15
  this.onConflict = options.onConflict;
16
16
  this.onError = options.onError;
17
+ this.autoSync = options.autoSync ?? true;
17
18
  }
18
19
  /**
19
20
  * Initialize sync engine
@@ -29,6 +30,12 @@ export class ClientSyncEngine {
29
30
  setAccessToken(token) {
30
31
  this.accessToken = token;
31
32
  }
33
+ /**
34
+ * Enable or disable automatic synchronization
35
+ */
36
+ setAutoSync(enabled) {
37
+ this.autoSync = enabled;
38
+ }
32
39
  /**
33
40
  * Get current sync status
34
41
  */
@@ -80,6 +87,14 @@ export class ClientSyncEngine {
80
87
  this.isSyncing = false;
81
88
  }
82
89
  }
90
+ /**
91
+ * Force a full sync (ignore lastSyncTimestamp)
92
+ */
93
+ async syncFull() {
94
+ this.lastSyncTimestamp = null;
95
+ await this.storage.removeItem(this.syncStatusKey);
96
+ await this.sync();
97
+ }
83
98
  /**
84
99
  * Send sync request to server
85
100
  */
@@ -111,7 +126,19 @@ export class ClientSyncEngine {
111
126
  }
112
127
  // Update local storage with server version
113
128
  const storageKey = `entity:${change.entity}:${change.id}`;
114
- await this.storage.setItem(storageKey, JSON.stringify(change.data));
129
+ if (change.operation === 'delete') {
130
+ await this.storage.removeItem(storageKey);
131
+ }
132
+ else {
133
+ const existingRaw = await this.storage.getItem(storageKey);
134
+ const existing = existingRaw ? JSON.parse(existingRaw) : {};
135
+ const payload = {
136
+ ...existing,
137
+ ...(change.data || {}),
138
+ _version: change.version ?? (change.operation === 'create' ? 1 : 0),
139
+ };
140
+ await this.storage.setItem(storageKey, JSON.stringify(payload));
141
+ }
115
142
  }
116
143
  // Process conflicts
117
144
  for (const conflict of response.conflicts) {
@@ -126,7 +153,10 @@ export class ClientSyncEngine {
126
153
  });
127
154
  // Update local storage with resolved data
128
155
  const storageKey = `entity:${conflict.entity}:${conflict.id}`;
129
- await this.storage.setItem(storageKey, JSON.stringify(resolution.resolvedData));
156
+ await this.storage.setItem(storageKey, JSON.stringify({
157
+ ...resolution.resolvedData,
158
+ _version: conflict.serverVersion,
159
+ }));
130
160
  // Notify caller of conflict
131
161
  this.onConflict?.(conflict.entity, conflict.id, conflict.serverData);
132
162
  // Remove from outbox since server won
@@ -173,9 +203,11 @@ export class ClientSyncEngine {
173
203
  });
174
204
  // Try to sync (will be handled by background sync if fails)
175
205
  // Don't await to allow optimistic updates
176
- this.sync().catch(() => {
177
- // Sync failed - will retry in background
178
- });
206
+ if (this.autoSync) {
207
+ this.sync().catch(() => {
208
+ // Sync failed - will retry in background
209
+ });
210
+ }
179
211
  }
180
212
  /**
181
213
  * Clear sync state (for logout/reset)