@agelum/backend 0.1.0 → 0.1.2

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 (86) hide show
  1. package/README.md +184 -113
  2. package/dist/client/hooks.d.ts +2 -2
  3. package/dist/client/hooks.d.ts.map +1 -1
  4. package/dist/client/storage.d.ts +3 -1
  5. package/dist/client/storage.d.ts.map +1 -1
  6. package/dist/client.d.ts +8 -8
  7. package/dist/client.d.ts.map +1 -1
  8. package/dist/config/schema.d.ts +4 -15
  9. package/dist/config/schema.d.ts.map +1 -1
  10. package/dist/core/driver.d.ts +2 -2
  11. package/dist/core/driver.d.ts.map +1 -1
  12. package/dist/core/driver.js +4 -3
  13. package/dist/core/driver.js.map +1 -1
  14. package/dist/core/function.d.ts +17 -11
  15. package/dist/core/function.d.ts.map +1 -1
  16. package/dist/core/function.js +2 -2
  17. package/dist/core/function.js.map +1 -1
  18. package/dist/core/types.d.ts +26 -9
  19. package/dist/core/types.d.ts.map +1 -1
  20. package/dist/examples/teamhub-integration.d.ts +1 -1
  21. package/dist/examples/teamhub-integration.d.ts.map +1 -1
  22. package/dist/examples/teamhub-integration.js +9 -5
  23. package/dist/examples/teamhub-integration.js.map +1 -1
  24. package/dist/index.d.ts +13 -12
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +2 -2
  27. package/dist/index.js.map +1 -1
  28. package/dist/providers/localStorage.d.ts +1 -1
  29. package/dist/providers/localStorage.d.ts.map +1 -1
  30. package/dist/providers/redis.d.ts +1 -1
  31. package/dist/providers/redis.d.ts.map +1 -1
  32. package/dist/server.d.ts +13 -12
  33. package/dist/server.d.ts.map +1 -1
  34. package/dist/server.js +3 -3
  35. package/dist/server.js.map +1 -1
  36. package/dist/trpc/index.d.ts +9 -0
  37. package/dist/trpc/index.d.ts.map +1 -0
  38. package/dist/trpc/index.js +19 -0
  39. package/dist/trpc/index.js.map +1 -0
  40. package/dist/trpc/router.d.ts +3 -2
  41. package/dist/trpc/router.d.ts.map +1 -1
  42. package/dist/trpc/router.js +21 -4
  43. package/dist/trpc/router.js.map +1 -1
  44. package/dist/trpc/types.d.ts +21 -12
  45. package/dist/trpc/types.d.ts.map +1 -1
  46. package/package.json +13 -13
  47. package/dist/client/hooks.js +0 -339
  48. package/dist/client/hooks.js.map +0 -1
  49. package/dist/client/index.js +0 -37
  50. package/dist/client/index.js.map +0 -1
  51. package/dist/client/manager.js +0 -292
  52. package/dist/client/manager.js.map +0 -1
  53. package/dist/client/provider.js +0 -121
  54. package/dist/client/provider.js.map +0 -1
  55. package/dist/client/revalidation.js +0 -313
  56. package/dist/client/revalidation.js.map +0 -1
  57. package/dist/client/session.d.ts +0 -84
  58. package/dist/client/session.d.ts.map +0 -1
  59. package/dist/client/session.js +0 -186
  60. package/dist/client/session.js.map +0 -1
  61. package/dist/client/sse-client.js +0 -221
  62. package/dist/client/sse-client.js.map +0 -1
  63. package/dist/client/storage.js +0 -441
  64. package/dist/client/storage.js.map +0 -1
  65. package/dist/client/trpc.js +0 -36
  66. package/dist/client/trpc.js.map +0 -1
  67. package/dist/client/types.d.ts +0 -10
  68. package/dist/client/types.d.ts.map +0 -1
  69. package/dist/client/types.js +0 -3
  70. package/dist/client/types.js.map +0 -1
  71. package/dist/client.js +0 -26
  72. package/dist/client.js.map +0 -1
  73. package/dist/core/analyzer.js +0 -217
  74. package/dist/core/analyzer.js.map +0 -1
  75. package/dist/core/sse.js +0 -331
  76. package/dist/core/sse.js.map +0 -1
  77. package/dist/providers/localStorage.js +0 -64
  78. package/dist/providers/localStorage.js.map +0 -1
  79. package/dist/providers/memory.js +0 -40
  80. package/dist/providers/memory.js.map +0 -1
  81. package/dist/providers/redis.js +0 -36
  82. package/dist/providers/redis.js.map +0 -1
  83. package/dist/trpc/hooks.d.ts +0 -82
  84. package/dist/trpc/hooks.d.ts.map +0 -1
  85. package/dist/trpc/hooks.js +0 -282
  86. package/dist/trpc/hooks.js.map +0 -1
@@ -1,221 +0,0 @@
1
- "use strict";
2
- /**
3
- * Client-side SSE client for real-time cache invalidation
4
- * NO HEARTBEATS - relies on event acknowledgments and connection health
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.SSEClient = void 0;
8
- /**
9
- * SSE Client for real-time cache invalidation
10
- * Uses event acknowledgments instead of heartbeats for reliability
11
- */
12
- class SSEClient {
13
- eventSource = null;
14
- reconnectTimer = null;
15
- isIntentionallyClosed = false;
16
- stats;
17
- options;
18
- constructor(options) {
19
- this.options = {
20
- maxReconnectAttempts: 5,
21
- reconnectDelay: 1000,
22
- onReconnect: () => { },
23
- ...options,
24
- };
25
- this.stats = {
26
- connectionAttempts: 0,
27
- successfulConnections: 0,
28
- failedConnections: 0,
29
- reconnectAttempts: 0,
30
- eventsReceived: 0,
31
- eventsAcknowledged: 0,
32
- lastEventTime: 0,
33
- totalUptime: 0,
34
- };
35
- }
36
- /**
37
- * Connect to SSE stream
38
- */
39
- connect() {
40
- if (this.eventSource) {
41
- this.disconnect();
42
- }
43
- this.stats.connectionAttempts++;
44
- this.stats.connectionStartTime = Date.now();
45
- try {
46
- this.eventSource = new EventSource(this.options.url);
47
- this.eventSource.onopen = () => {
48
- this.stats.successfulConnections++;
49
- console.log('[SSEClient] Connection opened');
50
- };
51
- this.eventSource.onmessage = (event) => {
52
- this.handleMessage(event);
53
- };
54
- this.eventSource.onerror = (error) => {
55
- this.stats.failedConnections++;
56
- console.warn('[SSEClient] Connection error:', error);
57
- this.handleConnectionError();
58
- };
59
- }
60
- catch (error) {
61
- this.stats.failedConnections++;
62
- console.error('[SSEClient] Failed to create connection:', error);
63
- this.handleConnectionError();
64
- }
65
- }
66
- /**
67
- * Disconnect from SSE stream
68
- */
69
- disconnect() {
70
- this.isIntentionallyClosed = true;
71
- this.clearReconnectTimer();
72
- if (this.eventSource) {
73
- this.eventSource.close();
74
- this.eventSource = null;
75
- }
76
- // Update uptime stats
77
- if (this.stats.connectionStartTime) {
78
- this.stats.totalUptime += Date.now() - this.stats.connectionStartTime;
79
- this.stats.connectionStartTime = undefined;
80
- }
81
- console.log('[SSEClient] Connection closed');
82
- }
83
- /**
84
- * Handle incoming SSE messages
85
- */
86
- handleMessage(event) {
87
- this.stats.lastEventTime = Date.now();
88
- this.stats.eventsReceived++;
89
- try {
90
- const data = JSON.parse(event.data);
91
- switch (data.type) {
92
- case 'connected':
93
- console.log('[SSEClient] Connection confirmed');
94
- break;
95
- // Removed heartbeat case - no heartbeats sent by server
96
- case 'invalidation':
97
- console.log(`[SSEClient] Invalidation received for table: ${data.table}`);
98
- this.handleInvalidationEvent(data);
99
- break;
100
- default:
101
- console.log('[SSEClient] Unknown event type:', data.type);
102
- }
103
- }
104
- catch (error) {
105
- console.warn('[SSEClient] Failed to parse event data:', error);
106
- this.options.onError(error);
107
- }
108
- }
109
- /**
110
- * Handle invalidation events
111
- */
112
- handleInvalidationEvent(event) {
113
- // Notify the invalidation handler
114
- this.options.onInvalidation(event);
115
- // Send acknowledgment if required
116
- if (event.requiresAck && event.eventId) {
117
- this.acknowledgeEvent(event.eventId);
118
- }
119
- }
120
- /**
121
- * Send event acknowledgment to server
122
- */
123
- async acknowledgeEvent(eventId) {
124
- try {
125
- const response = await fetch('/api/events/ack', {
126
- method: 'POST',
127
- headers: {
128
- 'Content-Type': 'application/json',
129
- },
130
- body: JSON.stringify({ eventId }),
131
- });
132
- if (response.ok) {
133
- this.stats.eventsAcknowledged++;
134
- console.log(`[SSEClient] Event acknowledged: ${eventId}`);
135
- }
136
- else {
137
- console.warn(`[SSEClient] Failed to acknowledge event: ${eventId}`);
138
- }
139
- }
140
- catch (error) {
141
- console.warn(`[SSEClient] Acknowledgment failed: ${eventId}`, error);
142
- // Silent fail - server will retry if needed
143
- }
144
- }
145
- /**
146
- * Schedule reconnection attempt
147
- */
148
- scheduleReconnect() {
149
- if (this.isIntentionallyClosed)
150
- return;
151
- if (this.stats.reconnectAttempts >= this.options.maxReconnectAttempts) {
152
- console.error(`[SSEClient] Max reconnect attempts (${this.options.maxReconnectAttempts}) reached`);
153
- this.options.onError(new Error('Max reconnection attempts exceeded'));
154
- return;
155
- }
156
- this.clearReconnectTimer();
157
- const delay = Math.min(this.options.reconnectDelay * Math.pow(2, this.stats.reconnectAttempts), 30000 // Max 30 seconds
158
- );
159
- console.log(`[SSEClient] Scheduling reconnect in ${delay}ms (attempt ${this.stats.reconnectAttempts + 1})`);
160
- this.reconnectTimer = setTimeout(() => {
161
- this.stats.reconnectAttempts++;
162
- this.connect();
163
- }, delay);
164
- }
165
- /**
166
- * Handle connection errors and schedule reconnection
167
- */
168
- handleConnectionError() {
169
- if (this.eventSource) {
170
- this.eventSource.close();
171
- this.eventSource = null;
172
- }
173
- // Update uptime stats
174
- if (this.stats.connectionStartTime) {
175
- this.stats.totalUptime += Date.now() - this.stats.connectionStartTime;
176
- this.stats.connectionStartTime = undefined;
177
- }
178
- // Schedule reconnection
179
- this.scheduleReconnect();
180
- }
181
- /**
182
- * Clear reconnection timer
183
- */
184
- clearReconnectTimer() {
185
- if (this.reconnectTimer) {
186
- clearTimeout(this.reconnectTimer);
187
- this.reconnectTimer = null;
188
- }
189
- }
190
- /**
191
- * Get connection statistics
192
- */
193
- getStats() {
194
- return { ...this.stats };
195
- }
196
- /**
197
- * Check if currently connected
198
- */
199
- isConnected() {
200
- return this.eventSource?.readyState === EventSource.OPEN;
201
- }
202
- /**
203
- * Get connection state
204
- */
205
- getConnectionState() {
206
- if (!this.eventSource)
207
- return 'closed';
208
- switch (this.eventSource.readyState) {
209
- case EventSource.CONNECTING:
210
- return 'connecting';
211
- case EventSource.OPEN:
212
- return 'open';
213
- case EventSource.CLOSED:
214
- return 'closed';
215
- default:
216
- return 'closed';
217
- }
218
- }
219
- }
220
- exports.SSEClient = SSEClient;
221
- //# sourceMappingURL=sse-client.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"sse-client.js","sourceRoot":"","sources":["../../src/client/sse-client.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AA0BH;;;GAGG;AACH,MAAa,SAAS;IACZ,WAAW,GAAuB,IAAI,CAAA;IACtC,cAAc,GAA0B,IAAI,CAAA;IAC5C,qBAAqB,GAAG,KAAK,CAAA;IAC7B,KAAK,CAAgB;IACrB,OAAO,CAA4B;IAE3C,YAAY,OAAyB;QACnC,IAAI,CAAC,OAAO,GAAG;YACb,oBAAoB,EAAE,CAAC;YACvB,cAAc,EAAE,IAAI;YACpB,WAAW,EAAE,GAAG,EAAE,GAAE,CAAC;YACrB,GAAG,OAAO;SACX,CAAA;QAED,IAAI,CAAC,KAAK,GAAG;YACX,kBAAkB,EAAE,CAAC;YACrB,qBAAqB,EAAE,CAAC;YACxB,iBAAiB,EAAE,CAAC;YACpB,iBAAiB,EAAE,CAAC;YACpB,cAAc,EAAE,CAAC;YACjB,kBAAkB,EAAE,CAAC;YACrB,aAAa,EAAE,CAAC;YAChB,WAAW,EAAE,CAAC;SACf,CAAA;IACH,CAAC;IAED;;OAEG;IACH,OAAO;QACL,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,IAAI,CAAC,UAAU,EAAE,CAAA;QACnB,CAAC;QAED,IAAI,CAAC,KAAK,CAAC,kBAAkB,EAAE,CAAA;QAC/B,IAAI,CAAC,KAAK,CAAC,mBAAmB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QAE3C,IAAI,CAAC;YACH,IAAI,CAAC,WAAW,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;YAEpD,IAAI,CAAC,WAAW,CAAC,MAAM,GAAG,GAAG,EAAE;gBAC7B,IAAI,CAAC,KAAK,CAAC,qBAAqB,EAAE,CAAA;gBAClC,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAA;YAC9C,CAAC,CAAA;YAED,IAAI,CAAC,WAAW,CAAC,SAAS,GAAG,CAAC,KAAK,EAAE,EAAE;gBACrC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;YAC3B,CAAC,CAAA;YAED,IAAI,CAAC,WAAW,CAAC,OAAO,GAAG,CAAC,KAAK,EAAE,EAAE;gBACnC,IAAI,CAAC,KAAK,CAAC,iBAAiB,EAAE,CAAA;gBAC9B,OAAO,CAAC,IAAI,CAAC,+BAA+B,EAAE,KAAK,CAAC,CAAA;gBACpD,IAAI,CAAC,qBAAqB,EAAE,CAAA;YAC9B,CAAC,CAAA;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,KAAK,CAAC,iBAAiB,EAAE,CAAA;YAC9B,OAAO,CAAC,KAAK,CAAC,0CAA0C,EAAE,KAAK,CAAC,CAAA;YAChE,IAAI,CAAC,qBAAqB,EAAE,CAAA;QAC9B,CAAC;IACH,CAAC;IAED;;OAEG;IACH,UAAU;QACR,IAAI,CAAC,qBAAqB,GAAG,IAAI,CAAA;QACjC,IAAI,CAAC,mBAAmB,EAAE,CAAA;QAE1B,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAA;YACxB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAA;QACzB,CAAC;QAED,sBAAsB;QACtB,IAAI,IAAI,CAAC,KAAK,CAAC,mBAAmB,EAAE,CAAC;YACnC,IAAI,CAAC,KAAK,CAAC,WAAW,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAA;YACrE,IAAI,CAAC,KAAK,CAAC,mBAAmB,GAAG,SAAS,CAAA;QAC5C,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAA;IAC9C,CAAC;IAED;;OAEG;IACK,aAAa,CAAC,KAAmB;QACvC,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QACrC,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,CAAA;QAE3B,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;YAEnC,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;gBAClB,KAAK,WAAW;oBACd,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAA;oBAC/C,MAAK;gBAEP,wDAAwD;gBAExD,KAAK,cAAc;oBACjB,OAAO,CAAC,GAAG,CACT,gDAAgD,IAAI,CAAC,KAAK,EAAE,CAC7D,CAAA;oBACD,IAAI,CAAC,uBAAuB,CAAC,IAAyB,CAAC,CAAA;oBACvD,MAAK;gBAEP;oBACE,OAAO,CAAC,GAAG,CAAC,iCAAiC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA;YAC7D,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,yCAAyC,EAAE,KAAK,CAAC,CAAA;YAC9D,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAc,CAAC,CAAA;QACtC,CAAC;IACH,CAAC;IAED;;OAEG;IACK,uBAAuB,CAAC,KAAwB;QACtD,kCAAkC;QAClC,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,CAAA;QAElC,kCAAkC;QAClC,IAAI,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YACvC,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QACtC,CAAC;IACH,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,gBAAgB,CAAC,OAAe;QAC5C,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,iBAAiB,EAAE;gBAC9C,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;iBACnC;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC;aAClC,CAAC,CAAA;YAEF,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;gBAChB,IAAI,CAAC,KAAK,CAAC,kBAAkB,EAAE,CAAA;gBAC/B,OAAO,CAAC,GAAG,CAAC,mCAAmC,OAAO,EAAE,CAAC,CAAA;YAC3D,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,IAAI,CAAC,4CAA4C,OAAO,EAAE,CAAC,CAAA;YACrE,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,sCAAsC,OAAO,EAAE,EAAE,KAAK,CAAC,CAAA;YACpE,4CAA4C;QAC9C,CAAC;IACH,CAAC;IAED;;OAEG;IACK,iBAAiB;QACvB,IAAI,IAAI,CAAC,qBAAqB;YAAE,OAAM;QAEtC,IAAI,IAAI,CAAC,KAAK,CAAC,iBAAiB,IAAI,IAAI,CAAC,OAAO,CAAC,oBAAoB,EAAE,CAAC;YACtE,OAAO,CAAC,KAAK,CACX,uCAAuC,IAAI,CAAC,OAAO,CAAC,oBAAoB,WAAW,CACpF,CAAA;YACD,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC,CAAA;YACrE,OAAM;QACR,CAAC;QAED,IAAI,CAAC,mBAAmB,EAAE,CAAA;QAE1B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CACpB,IAAI,CAAC,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,EACvE,KAAK,CAAC,iBAAiB;SACxB,CAAA;QAED,OAAO,CAAC,GAAG,CACT,uCAAuC,KAAK,eAC1C,IAAI,CAAC,KAAK,CAAC,iBAAiB,GAAG,CACjC,GAAG,CACJ,CAAA;QAED,IAAI,CAAC,cAAc,GAAG,UAAU,CAAC,GAAG,EAAE;YACpC,IAAI,CAAC,KAAK,CAAC,iBAAiB,EAAE,CAAA;YAC9B,IAAI,CAAC,OAAO,EAAE,CAAA;QAChB,CAAC,EAAE,KAAK,CAAC,CAAA;IACX,CAAC;IAED;;OAEG;IACK,qBAAqB;QAC3B,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAA;YACxB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAA;QACzB,CAAC;QAED,sBAAsB;QACtB,IAAI,IAAI,CAAC,KAAK,CAAC,mBAAmB,EAAE,CAAC;YACnC,IAAI,CAAC,KAAK,CAAC,WAAW,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAA;YACrE,IAAI,CAAC,KAAK,CAAC,mBAAmB,GAAG,SAAS,CAAA;QAC5C,CAAC;QAED,wBAAwB;QACxB,IAAI,CAAC,iBAAiB,EAAE,CAAA;IAC1B,CAAC;IAED;;OAEG;IACK,mBAAmB;QACzB,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;YACjC,IAAI,CAAC,cAAc,GAAG,IAAI,CAAA;QAC5B,CAAC;IACH,CAAC;IAED;;OAEG;IACH,QAAQ;QACN,OAAO,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,CAAA;IAC1B,CAAC;IAED;;OAEG;IACH,WAAW;QACT,OAAO,IAAI,CAAC,WAAW,EAAE,UAAU,KAAK,WAAW,CAAC,IAAI,CAAA;IAC1D,CAAC;IAED;;OAEG;IACH,kBAAkB;QAChB,IAAI,CAAC,IAAI,CAAC,WAAW;YAAE,OAAO,QAAQ,CAAA;QAEtC,QAAQ,IAAI,CAAC,WAAW,CAAC,UAAU,EAAE,CAAC;YACpC,KAAK,WAAW,CAAC,UAAU;gBACzB,OAAO,YAAY,CAAA;YACrB,KAAK,WAAW,CAAC,IAAI;gBACnB,OAAO,MAAM,CAAA;YACf,KAAK,WAAW,CAAC,MAAM;gBACrB,OAAO,QAAQ,CAAA;YACjB;gBACE,OAAO,QAAQ,CAAA;QACnB,CAAC;IACH,CAAC;CACF;AAvPD,8BAuPC"}
@@ -1,441 +0,0 @@
1
- "use strict";
2
- /**
3
- * Client-side storage management for reactive queries
4
- * Handles localStorage-based query registry and session persistence
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.ReactiveStorage = void 0;
8
- exports.createReactiveStorage = createReactiveStorage;
9
- class ReactiveStorage {
10
- storageKey = '@drizzle/reactive:registry';
11
- indexKey;
12
- activeHooks = new Map();
13
- sessionId;
14
- organizationId;
15
- constructor(organizationId) {
16
- this.organizationId = organizationId;
17
- this.indexKey = this.getIndexKey(organizationId);
18
- this.sessionId = this.generateSessionId();
19
- this.initializeRegistry();
20
- this.cleanupExpiredEntries();
21
- }
22
- /** Derive the per-org index key */
23
- getIndexKey(orgId) {
24
- return `reactive_registry_${orgId}`;
25
- }
26
- /** Derive per-query entry key */
27
- getEntryKey(orgId, queryKey) {
28
- return `@drizzle/reactive:entry:${orgId}:${this.hash(queryKey)}`;
29
- }
30
- /** Simple 32-bit hash for stable short keys */
31
- hash(input) {
32
- let h = 2166136261 >>> 0;
33
- for (let i = 0; i < input.length; i++) {
34
- h ^= input.charCodeAt(i);
35
- h = Math.imul(h, 16777619);
36
- }
37
- return (h >>> 0).toString(36);
38
- }
39
- /**
40
- * Initialize the query registry for this organization
41
- */
42
- initializeRegistry() {
43
- const existing = this.getRegistry();
44
- if (!existing || existing.organizationId !== this.organizationId) {
45
- // Create new registry for this organization
46
- const newRegistry = {
47
- organizationId: this.organizationId,
48
- queries: {},
49
- session: {
50
- startTime: Date.now(),
51
- lastSync: Date.now(),
52
- realtimeConnected: false,
53
- },
54
- };
55
- this.saveRegistry(newRegistry);
56
- }
57
- else {
58
- // Update session info
59
- existing.session.startTime = Date.now();
60
- existing.session.lastSync = Date.now();
61
- this.saveRegistry(existing);
62
- }
63
- }
64
- /**
65
- * Get the current query registry
66
- */
67
- getRegistry() {
68
- try {
69
- // Prefer per-org index; fallback to legacy single-key registry for migration
70
- const stored = localStorage.getItem(this.indexKey) ||
71
- localStorage.getItem(this.storageKey);
72
- if (!stored)
73
- return null;
74
- const registry = JSON.parse(stored);
75
- return registry;
76
- }
77
- catch (error) {
78
- console.warn('Failed to parse registry from localStorage', error instanceof Error ? error.message : String(error));
79
- return null;
80
- }
81
- }
82
- /**
83
- * Save the query registry to localStorage
84
- */
85
- saveRegistry(registry) {
86
- try {
87
- localStorage.setItem(this.indexKey, JSON.stringify(registry));
88
- }
89
- catch (error) {
90
- console.warn('Failed to save registry to localStorage', error instanceof Error ? error.message : String(error));
91
- // Handle localStorage quota exceeded
92
- this.cleanupOldEntries();
93
- try {
94
- localStorage.setItem(this.indexKey, JSON.stringify(registry));
95
- }
96
- catch (retryError) {
97
- console.error('Failed to save registry after cleanup to localStorage', retryError instanceof Error
98
- ? retryError.message
99
- : String(retryError));
100
- }
101
- }
102
- }
103
- /**
104
- * Register a query execution
105
- */
106
- registerQuery(queryKey, dependencies, data, ttl) {
107
- const registry = this.getRegistry();
108
- if (!registry)
109
- return;
110
- const now = Date.now();
111
- const existingQuery = registry.queries[queryKey];
112
- console.debug('Registering query in storage', {
113
- queryKey,
114
- hasExistingData: !!existingQuery,
115
- existingLastServerChange: existingQuery?.lastServerChange,
116
- newDataExists: !!data,
117
- timestamp: now,
118
- });
119
- // Check if data actually changed
120
- const dataChanged = !existingQuery ||
121
- JSON.stringify(existingQuery.data) !== JSON.stringify(data);
122
- // Write data to a separate entry to avoid huge single-key payloads
123
- try {
124
- const entryKey = this.getEntryKey(this.organizationId, queryKey);
125
- // Derive human-friendly fields for debugging in localStorage
126
- const [name, inputJson] = queryKey.split('::');
127
- const input = inputJson
128
- ? (() => {
129
- try {
130
- return JSON.parse(inputJson);
131
- }
132
- catch {
133
- return undefined;
134
- }
135
- })()
136
- : undefined;
137
- const entryPayload = JSON.stringify({ name, input, queryKey, data });
138
- localStorage.setItem(entryKey, entryPayload);
139
- }
140
- catch (e) {
141
- console.warn('Failed to write entry for', e instanceof Error ? e.message : String(e));
142
- }
143
- // Store only metadata in the index
144
- registry.queries[queryKey] = {
145
- lastRevalidated: now,
146
- // Only update lastServerChange if data actually changed
147
- lastServerChange: dataChanged
148
- ? now
149
- : existingQuery?.lastServerChange || now,
150
- };
151
- // Update session sync time
152
- registry.session.lastSync = now;
153
- this.saveRegistry(registry);
154
- console.debug('Query registered in storage', {
155
- queryKey,
156
- dataChanged,
157
- isStale: false, // Fresh data is never stale
158
- });
159
- }
160
- /**
161
- * Mark a query as stale (needs revalidation)
162
- */
163
- invalidateQuery(queryKey) {
164
- const registry = this.getRegistry();
165
- if (!registry)
166
- return;
167
- if (registry.queries[queryKey]) {
168
- // Keep the data but mark as needing revalidation
169
- registry.queries[queryKey].lastServerChange = Date.now();
170
- this.saveRegistry(registry);
171
- console.debug('Query marked as stale in storage', {
172
- queryKey,
173
- });
174
- }
175
- }
176
- /**
177
- * Mark a query as stale for testing (simulates server-side changes)
178
- */
179
- markQueryStaleForTesting(queryKey) {
180
- const registry = this.getRegistry();
181
- if (!registry)
182
- return;
183
- if (registry.queries[queryKey]) {
184
- // Simulate a server-side change by setting lastServerChange to future
185
- registry.queries[queryKey].lastServerChange = Date.now() + 1000; // 1 second in future
186
- this.saveRegistry(registry);
187
- console.debug('Query marked as stale for testing in storage', {
188
- queryKey,
189
- });
190
- }
191
- }
192
- /**
193
- * Invalidate queries based on table changes
194
- */
195
- invalidateByTable(table, relations) {
196
- const registry = this.getRegistry();
197
- if (!registry)
198
- return;
199
- const now = Date.now();
200
- let hasChanges = false;
201
- // Find all queries that depend on this table
202
- Object.keys(registry.queries).forEach((queryKey) => {
203
- // Simple heuristic: if query key contains table name or related tables
204
- const relatedTables = relations[table] || [];
205
- const allTables = [table, ...relatedTables];
206
- const shouldInvalidate = allTables.some((tableName) => queryKey.toLowerCase().includes(tableName.toLowerCase()));
207
- if (shouldInvalidate) {
208
- registry.queries[queryKey].lastServerChange = now;
209
- hasChanges = true;
210
- }
211
- });
212
- if (hasChanges) {
213
- registry.session.lastSync = now;
214
- this.saveRegistry(registry);
215
- }
216
- }
217
- /**
218
- * Get cached data for a query
219
- */
220
- getCachedData(queryKey) {
221
- const registry = this.getRegistry();
222
- if (!registry)
223
- return null;
224
- const queryData = registry.queries[queryKey];
225
- if (!queryData)
226
- return null;
227
- const isStale = queryData.lastServerChange !== undefined &&
228
- queryData.lastServerChange > queryData.lastRevalidated;
229
- console.debug('Getting cached data from storage', {
230
- queryKey,
231
- isStale,
232
- lastRevalidated: queryData.lastRevalidated,
233
- lastServerChange: queryData.lastServerChange,
234
- timestamp: Date.now(),
235
- });
236
- // Read data from its own entry key
237
- let data = undefined;
238
- try {
239
- const entryKey = this.getEntryKey(this.organizationId, queryKey);
240
- const raw = localStorage.getItem(entryKey);
241
- if (raw) {
242
- const parsed = JSON.parse(raw);
243
- data = parsed?.data;
244
- }
245
- }
246
- catch (e) {
247
- console.warn('Failed to read entry from localStorage', {
248
- queryKey,
249
- error: e instanceof Error ? e.message : String(e),
250
- });
251
- }
252
- return {
253
- data,
254
- isStale,
255
- lastRevalidated: queryData.lastRevalidated,
256
- };
257
- }
258
- /**
259
- * Detect session gaps and queries that need revalidation
260
- */
261
- detectSessionGap() {
262
- const registry = this.getRegistry();
263
- if (!registry) {
264
- return { hasGap: true, gapDuration: 0, staleQueries: [] };
265
- }
266
- const now = Date.now();
267
- const gapDuration = now - registry.session.lastSync;
268
- const hasGap = gapDuration > 30000; // 30 seconds threshold
269
- const staleQueries = [];
270
- if (hasGap) {
271
- // All queries are potentially stale after a gap
272
- Object.keys(registry.queries).forEach((queryKey) => {
273
- staleQueries.push(queryKey);
274
- });
275
- }
276
- else {
277
- // Only queries with server changes are stale
278
- Object.entries(registry.queries).forEach(([queryKey, queryData]) => {
279
- if (queryData.lastServerChange &&
280
- queryData.lastServerChange > queryData.lastRevalidated) {
281
- staleQueries.push(queryKey);
282
- }
283
- });
284
- }
285
- return { hasGap, gapDuration, staleQueries };
286
- }
287
- /**
288
- * Register an active hook for priority revalidation
289
- */
290
- registerActiveHook(queryKey, dependencies, organizationId) {
291
- this.activeHooks.set(queryKey, {
292
- queryKey,
293
- isActive: true,
294
- lastAccess: Date.now(),
295
- dependencies,
296
- organizationId,
297
- });
298
- }
299
- /**
300
- * Unregister an active hook
301
- */
302
- unregisterActiveHook(queryKey) {
303
- this.activeHooks.delete(queryKey);
304
- }
305
- /**
306
- * Get active hooks for priority revalidation
307
- */
308
- getActiveHooks() {
309
- return Array.from(this.activeHooks.values());
310
- }
311
- /**
312
- * Get active hooks sorted by priority (most recent access first)
313
- */
314
- getActiveHooksByPriority() {
315
- return this.getActiveHooks().sort((a, b) => b.lastAccess - a.lastAccess);
316
- }
317
- /**
318
- * Update real-time connection status
319
- */
320
- updateRealtimeStatus(connected) {
321
- const registry = this.getRegistry();
322
- if (!registry)
323
- return;
324
- registry.session.realtimeConnected = connected;
325
- registry.session.lastSync = Date.now();
326
- this.saveRegistry(registry);
327
- }
328
- /**
329
- * Get queries that should be revalidated first (active hooks)
330
- */
331
- getPriorityQueries() {
332
- const activeHooks = this.getActiveHooksByPriority();
333
- return activeHooks.map((hook) => hook.queryKey);
334
- }
335
- /**
336
- * Get background queries that can be revalidated later
337
- */
338
- getBackgroundQueries() {
339
- const registry = this.getRegistry();
340
- if (!registry)
341
- return [];
342
- const activeQueryKeys = new Set(this.getPriorityQueries());
343
- return Object.keys(registry.queries).filter((key) => !activeQueryKeys.has(key));
344
- }
345
- /**
346
- * Clean up expired entries to free up localStorage space
347
- */
348
- cleanupExpiredEntries() {
349
- const registry = this.getRegistry();
350
- if (!registry)
351
- return;
352
- const now = Date.now();
353
- const maxAge = 24 * 60 * 60 * 1000; // 24 hours
354
- let hasChanges = false;
355
- Object.keys(registry.queries).forEach((queryKey) => {
356
- const queryData = registry.queries[queryKey];
357
- if (now - queryData.lastRevalidated > maxAge) {
358
- delete registry.queries[queryKey];
359
- hasChanges = true;
360
- }
361
- });
362
- if (hasChanges) {
363
- this.saveRegistry(registry);
364
- }
365
- }
366
- /**
367
- * Clean up old entries when localStorage is full
368
- */
369
- cleanupOldEntries() {
370
- const registry = this.getRegistry();
371
- if (!registry)
372
- return;
373
- const entries = Object.entries(registry.queries);
374
- if (entries.length === 0)
375
- return;
376
- // Remove oldest 50% of entries
377
- entries.sort(([, a], [, b]) => a.lastRevalidated - b.lastRevalidated);
378
- const keepCount = Math.ceil(entries.length / 2);
379
- const newQueries = {};
380
- entries.slice(-keepCount).forEach(([key, value]) => {
381
- newQueries[key] = value;
382
- });
383
- registry.queries = newQueries;
384
- this.saveRegistry(registry);
385
- console.debug('Cleaned up old entries from storage', {
386
- keptCount: keepCount,
387
- totalEntries: entries.length,
388
- });
389
- }
390
- /**
391
- * Generate a unique session ID
392
- */
393
- generateSessionId() {
394
- return `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
395
- }
396
- /**
397
- * Get session information
398
- */
399
- getSessionInfo() {
400
- const registry = this.getRegistry();
401
- return registry?.session || null;
402
- }
403
- /**
404
- * Clear all stored data for this organization
405
- */
406
- clearRegistry() {
407
- try {
408
- // Remove index and all known entries for this org
409
- const registry = this.getRegistry();
410
- if (registry) {
411
- Object.keys(registry.queries).forEach((queryKey) => {
412
- const entryKey = this.getEntryKey(this.organizationId, queryKey);
413
- localStorage.removeItem(entryKey);
414
- });
415
- }
416
- localStorage.removeItem(this.indexKey);
417
- console.debug('Cleared all registry data for organization', {
418
- organizationId: this.organizationId,
419
- });
420
- }
421
- catch (error) {
422
- console.warn('Failed to clear registry', {
423
- error: error instanceof Error ? error.message : String(error),
424
- });
425
- }
426
- }
427
- /**
428
- * Export registry for debugging
429
- */
430
- exportRegistry() {
431
- return this.getRegistry();
432
- }
433
- }
434
- exports.ReactiveStorage = ReactiveStorage;
435
- /**
436
- * Create a storage instance for an organization
437
- */
438
- function createReactiveStorage(organizationId) {
439
- return new ReactiveStorage(organizationId);
440
- }
441
- //# sourceMappingURL=storage.js.map