@edgebasejs/core 0.1.7 → 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 (63) hide show
  1. package/README.md +15 -0
  2. package/dist/core/src/access-rules/column-security.d.ts +80 -0
  3. package/dist/core/src/access-rules/column-security.d.ts.map +1 -0
  4. package/dist/core/src/access-rules/column-security.js +191 -0
  5. package/dist/core/src/access-rules/column-security.js.map +1 -0
  6. package/dist/core/src/access-rules/engine.d.ts.map +1 -1
  7. package/dist/core/src/access-rules/engine.js +2 -1
  8. package/dist/core/src/access-rules/engine.js.map +1 -1
  9. package/dist/core/src/audit/audit-manager.d.ts +108 -0
  10. package/dist/core/src/audit/audit-manager.d.ts.map +1 -0
  11. package/dist/core/src/audit/audit-manager.js +265 -0
  12. package/dist/core/src/audit/audit-manager.js.map +1 -0
  13. package/dist/core/src/encryption/encryption-manager.d.ts +97 -0
  14. package/dist/core/src/encryption/encryption-manager.d.ts.map +1 -0
  15. package/dist/core/src/encryption/encryption-manager.js +224 -0
  16. package/dist/core/src/encryption/encryption-manager.js.map +1 -0
  17. package/dist/core/src/index.d.ts +12 -0
  18. package/dist/core/src/index.d.ts.map +1 -1
  19. package/dist/core/src/index.js +12 -0
  20. package/dist/core/src/index.js.map +1 -1
  21. package/dist/core/src/realtime/change-notifier.d.ts +50 -0
  22. package/dist/core/src/realtime/change-notifier.d.ts.map +1 -0
  23. package/dist/core/src/realtime/change-notifier.js +145 -0
  24. package/dist/core/src/realtime/change-notifier.js.map +1 -0
  25. package/dist/core/src/realtime/message-types.d.ts +39 -0
  26. package/dist/core/src/realtime/message-types.d.ts.map +1 -0
  27. package/dist/core/src/realtime/message-types.js +5 -0
  28. package/dist/core/src/realtime/message-types.js.map +1 -0
  29. package/dist/core/src/realtime/subscription-manager.d.ts +67 -0
  30. package/dist/core/src/realtime/subscription-manager.d.ts.map +1 -0
  31. package/dist/core/src/realtime/subscription-manager.js +229 -0
  32. package/dist/core/src/realtime/subscription-manager.js.map +1 -0
  33. package/dist/core/src/search/search-manager.d.ts +93 -0
  34. package/dist/core/src/search/search-manager.d.ts.map +1 -0
  35. package/dist/core/src/search/search-manager.js +258 -0
  36. package/dist/core/src/search/search-manager.js.map +1 -0
  37. package/dist/core/src/storage/file-manager.d.ts +138 -0
  38. package/dist/core/src/storage/file-manager.d.ts.map +1 -0
  39. package/dist/core/src/storage/file-manager.js +224 -0
  40. package/dist/core/src/storage/file-manager.js.map +1 -0
  41. package/dist/core/src/sync/batch-processor.d.ts +97 -0
  42. package/dist/core/src/sync/batch-processor.d.ts.map +1 -0
  43. package/dist/core/src/sync/batch-processor.js +313 -0
  44. package/dist/core/src/sync/batch-processor.js.map +1 -0
  45. package/dist/core/src/sync/csv-processor.d.ts +66 -0
  46. package/dist/core/src/sync/csv-processor.d.ts.map +1 -0
  47. package/dist/core/src/sync/csv-processor.js +223 -0
  48. package/dist/core/src/sync/csv-processor.js.map +1 -0
  49. package/dist/core/src/sync/sync-engine.d.ts +22 -0
  50. package/dist/core/src/sync/sync-engine.d.ts.map +1 -1
  51. package/dist/core/src/sync/sync-engine.js +123 -10
  52. package/dist/core/src/sync/sync-engine.js.map +1 -1
  53. package/dist/core/src/sync/transaction-manager.d.ts +83 -0
  54. package/dist/core/src/sync/transaction-manager.d.ts.map +1 -0
  55. package/dist/core/src/sync/transaction-manager.js +227 -0
  56. package/dist/core/src/sync/transaction-manager.js.map +1 -0
  57. package/dist/core/src/webhooks/webhook-manager.d.ts +137 -0
  58. package/dist/core/src/webhooks/webhook-manager.d.ts.map +1 -0
  59. package/dist/core/src/webhooks/webhook-manager.js +334 -0
  60. package/dist/core/src/webhooks/webhook-manager.js.map +1 -0
  61. package/dist/index.d.ts +0 -1
  62. package/dist/index.js +0 -1
  63. package/package.json +2 -2
@@ -0,0 +1,50 @@
1
+ import type { SubscriptionManager } from './subscription-manager';
2
+ import type { ChangeMessage } from './message-types';
3
+ import type { User } from '@edgebasejs/types';
4
+ export interface WebSocketClient {
5
+ send(message: string): void;
6
+ close(): void;
7
+ isOpen(): boolean;
8
+ }
9
+ /**
10
+ * Notifies subscribed clients about data changes
11
+ * Manages broadcasting changes to WebSocket connections
12
+ */
13
+ export declare class ChangeNotifier {
14
+ private subscriptionManager;
15
+ private clients;
16
+ constructor(subscriptionManager: SubscriptionManager);
17
+ /**
18
+ * Register a WebSocket client connection
19
+ */
20
+ registerClient(connectionId: string, client: WebSocketClient): void;
21
+ /**
22
+ * Unregister a WebSocket client connection
23
+ */
24
+ unregisterClient(connectionId: string): void;
25
+ /**
26
+ * Broadcast a change to all subscribed clients
27
+ */
28
+ notifyChange(entity: string, operation: 'create' | 'update' | 'delete', record: Record<string, unknown>, recordId: string, user: User, version?: number): Promise<void>;
29
+ /**
30
+ * Send a message to a specific connection
31
+ */
32
+ private sendToConnection;
33
+ /**
34
+ * Broadcast a message to all clients
35
+ */
36
+ broadcastToAll(message: ChangeMessage, filterSubscriptions?: string[]): void;
37
+ /**
38
+ * Send heartbeat to all connected clients
39
+ */
40
+ sendHeartbeat(): void;
41
+ /**
42
+ * Send error message to a specific client
43
+ */
44
+ sendError(connectionId: string, code: string, message: string): void;
45
+ /**
46
+ * Get connected clients count
47
+ */
48
+ getConnectedClientsCount(): number;
49
+ }
50
+ //# sourceMappingURL=change-notifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"change-notifier.d.ts","sourceRoot":"","sources":["../../../../src/realtime/change-notifier.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAE9C,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,IAAI,IAAI,CAAC;IACd,MAAM,IAAI,OAAO,CAAC;CACnB;AAED;;;GAGG;AACH,qBAAa,cAAc;IAGb,OAAO,CAAC,mBAAmB;IAFvC,OAAO,CAAC,OAAO,CAAsC;gBAEjC,mBAAmB,EAAE,mBAAmB;IAE5D;;OAEG;IACH,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI;IAInE;;OAEG;IACH,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;IAI5C;;OAEG;IACG,YAAY,CAChB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,EACzC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,IAAI,EACV,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;IA+BhB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAgBxB;;OAEG;IACH,cAAc,CAAC,OAAO,EAAE,aAAa,EAAE,mBAAmB,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI;IA8B5E;;OAEG;IACH,aAAa,IAAI,IAAI;IAqBrB;;OAEG;IACH,SAAS,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAoBpE;;OAEG;IACH,wBAAwB,IAAI,MAAM;CAGnC"}
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Notifies subscribed clients about data changes
3
+ * Manages broadcasting changes to WebSocket connections
4
+ */
5
+ export class ChangeNotifier {
6
+ constructor(subscriptionManager) {
7
+ this.subscriptionManager = subscriptionManager;
8
+ this.clients = new Map();
9
+ }
10
+ /**
11
+ * Register a WebSocket client connection
12
+ */
13
+ registerClient(connectionId, client) {
14
+ this.clients.set(connectionId, client);
15
+ }
16
+ /**
17
+ * Unregister a WebSocket client connection
18
+ */
19
+ unregisterClient(connectionId) {
20
+ this.clients.delete(connectionId);
21
+ }
22
+ /**
23
+ * Broadcast a change to all subscribed clients
24
+ */
25
+ async notifyChange(entity, operation, record, recordId, user, version) {
26
+ const subscriptions = this.subscriptionManager.getSubscriptionsForEntity(entity);
27
+ for (const subscription of subscriptions) {
28
+ // Check if user has access (basic check - should be extended with full access rules)
29
+ // For now, assume user can see their own data
30
+ if (subscription.userId !== user.id) {
31
+ // In production, would check RLS rules here
32
+ continue;
33
+ }
34
+ // Check if subscription filters match the record
35
+ if (!this.subscriptionManager.matchesFilter(subscription, record)) {
36
+ continue;
37
+ }
38
+ // Send change message to client
39
+ const message = {
40
+ type: 'change',
41
+ entity,
42
+ operation,
43
+ record: operation !== 'delete' ? record : undefined,
44
+ recordId,
45
+ timestamp: Date.now(),
46
+ version,
47
+ };
48
+ this.sendToConnection(subscription.subscriptionId, message);
49
+ }
50
+ }
51
+ /**
52
+ * Send a message to a specific connection
53
+ */
54
+ sendToConnection(subscriptionId, message) {
55
+ const subscription = this.subscriptionManager.getSubscription(subscriptionId);
56
+ if (!subscription)
57
+ return;
58
+ // Find the connection for this subscription
59
+ const subscriptions = this.subscriptionManager.getSubscriptionsForEntity(subscription.entity);
60
+ const matchingSub = subscriptions.find((s) => s.subscriptionId === subscriptionId);
61
+ if (!matchingSub)
62
+ return;
63
+ // This is a placeholder - in actual implementation, we'd need to track
64
+ // which connection ID corresponds to which subscription
65
+ // For now, we'll send to all connections and let them filter
66
+ this.broadcastToAll(message, [subscriptionId]);
67
+ }
68
+ /**
69
+ * Broadcast a message to all clients
70
+ */
71
+ broadcastToAll(message, filterSubscriptions) {
72
+ const messageStr = JSON.stringify(message);
73
+ for (const [connectionId, client] of this.clients.entries()) {
74
+ if (!client.isOpen()) {
75
+ this.unregisterClient(connectionId);
76
+ continue;
77
+ }
78
+ // If filter subscriptions provided, only send to relevant clients
79
+ if (filterSubscriptions) {
80
+ const subscriptions = this.subscriptionManager.getSubscriptionsForConnection(connectionId);
81
+ const hasMatchingSubscription = subscriptions.some((sub) => filterSubscriptions.includes(sub.subscriptionId));
82
+ if (!hasMatchingSubscription) {
83
+ continue;
84
+ }
85
+ }
86
+ try {
87
+ client.send(messageStr);
88
+ }
89
+ catch (error) {
90
+ console.error(`Failed to send message to client ${connectionId}:`, error);
91
+ this.unregisterClient(connectionId);
92
+ }
93
+ }
94
+ }
95
+ /**
96
+ * Send heartbeat to all connected clients
97
+ */
98
+ sendHeartbeat() {
99
+ const heartbeatMsg = JSON.stringify({
100
+ type: 'heartbeat',
101
+ timestamp: Date.now(),
102
+ });
103
+ for (const [connectionId, client] of this.clients.entries()) {
104
+ if (!client.isOpen()) {
105
+ this.unregisterClient(connectionId);
106
+ continue;
107
+ }
108
+ try {
109
+ client.send(heartbeatMsg);
110
+ }
111
+ catch (error) {
112
+ console.error(`Failed to send heartbeat to client ${connectionId}:`, error);
113
+ this.unregisterClient(connectionId);
114
+ }
115
+ }
116
+ }
117
+ /**
118
+ * Send error message to a specific client
119
+ */
120
+ sendError(connectionId, code, message) {
121
+ const client = this.clients.get(connectionId);
122
+ if (!client || !client.isOpen()) {
123
+ return;
124
+ }
125
+ const errorMsg = JSON.stringify({
126
+ type: 'error',
127
+ code,
128
+ message,
129
+ });
130
+ try {
131
+ client.send(errorMsg);
132
+ }
133
+ catch (error) {
134
+ console.error(`Failed to send error to client ${connectionId}:`, error);
135
+ this.unregisterClient(connectionId);
136
+ }
137
+ }
138
+ /**
139
+ * Get connected clients count
140
+ */
141
+ getConnectedClientsCount() {
142
+ return this.clients.size;
143
+ }
144
+ }
145
+ //# sourceMappingURL=change-notifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"change-notifier.js","sourceRoot":"","sources":["../../../../src/realtime/change-notifier.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * WebSocket message types for real-time subscriptions
3
+ */
4
+ export type SubscriptionMessage = SubscribeMessage | UnsubscribeMessage | ChangeMessage | ErrorMessage | HeartbeatMessage;
5
+ export interface SubscribeMessage {
6
+ type: 'subscribe';
7
+ entity: string;
8
+ filters?: Record<string, unknown>;
9
+ }
10
+ export interface UnsubscribeMessage {
11
+ type: 'unsubscribe';
12
+ entity: string;
13
+ }
14
+ export interface ChangeMessage {
15
+ type: 'change';
16
+ entity: string;
17
+ operation: 'create' | 'update' | 'delete';
18
+ record?: Record<string, unknown>;
19
+ recordId?: string;
20
+ timestamp: number;
21
+ version?: number;
22
+ }
23
+ export interface ErrorMessage {
24
+ type: 'error';
25
+ code: string;
26
+ message: string;
27
+ }
28
+ export interface HeartbeatMessage {
29
+ type: 'heartbeat';
30
+ timestamp: number;
31
+ }
32
+ export interface SubscriptionState {
33
+ subscriptionId: string;
34
+ userId: string;
35
+ entity: string;
36
+ filters?: Record<string, unknown>;
37
+ createdAt: number;
38
+ }
39
+ //# sourceMappingURL=message-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-types.d.ts","sourceRoot":"","sources":["../../../../src/realtime/message-types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,mBAAmB,GAC3B,gBAAgB,GAChB,kBAAkB,GAClB,aAAa,GACb,YAAY,GACZ,gBAAgB,CAAC;AAErB,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,WAAW,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC;CACnB"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * WebSocket message types for real-time subscriptions
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=message-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-types.js","sourceRoot":"","sources":["../../../../src/realtime/message-types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,67 @@
1
+ import type { SyncDatabase } from '../sync/sync-engine';
2
+ import type { SubscriptionState } from './message-types';
3
+ /**
4
+ * Manages active WebSocket subscriptions
5
+ * Tracks which clients are subscribed to which entities and filters
6
+ */
7
+ export declare class SubscriptionManager {
8
+ private db;
9
+ private subscriptions;
10
+ private userSubscriptions;
11
+ private entitySubscriptions;
12
+ private connectionSubscriptions;
13
+ constructor(db: SyncDatabase);
14
+ /**
15
+ * Create a new subscription
16
+ */
17
+ subscribe(userId: string, connectionId: string, entity: string, filters?: Record<string, unknown>): Promise<string>;
18
+ /**
19
+ * Remove a subscription
20
+ */
21
+ unsubscribe(subscriptionId: string): Promise<void>;
22
+ /**
23
+ * Remove all subscriptions for a connection
24
+ */
25
+ disconnectClient(connectionId: string): Promise<void>;
26
+ /**
27
+ * Get all subscriptions for an entity
28
+ */
29
+ getSubscriptionsForEntity(entity: string): SubscriptionState[];
30
+ /**
31
+ * Get all subscriptions for a user
32
+ */
33
+ getSubscriptionsForUser(userId: string): SubscriptionState[];
34
+ /**
35
+ * Get all subscriptions for a connection
36
+ */
37
+ getSubscriptionsForConnection(connectionId: string): SubscriptionState[];
38
+ /**
39
+ * Update last heartbeat for a subscription
40
+ */
41
+ updateHeartbeat(subscriptionId: string): Promise<void>;
42
+ /**
43
+ * Get subscription by ID
44
+ */
45
+ getSubscription(subscriptionId: string): SubscriptionState | undefined;
46
+ /**
47
+ * Check if a subscription matches a filter
48
+ */
49
+ matchesFilter(subscription: SubscriptionState, data: Record<string, unknown>): boolean;
50
+ /**
51
+ * Load subscriptions from database on startup
52
+ */
53
+ loadFromDatabase(): Promise<void>;
54
+ /**
55
+ * Cleanup expired subscriptions
56
+ */
57
+ cleanup(): Promise<void>;
58
+ /**
59
+ * Get subscription statistics
60
+ */
61
+ getStats(): {
62
+ totalSubscriptions: number;
63
+ activeConnections: number;
64
+ entitiesWithSubscriptions: number;
65
+ };
66
+ }
67
+ //# sourceMappingURL=subscription-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscription-manager.d.ts","sourceRoot":"","sources":["../../../../src/realtime/subscription-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD;;;GAGG;AACH,qBAAa,mBAAmB;IAMlB,OAAO,CAAC,EAAE;IALtB,OAAO,CAAC,aAAa,CAAwC;IAC7D,OAAO,CAAC,iBAAiB,CAAkC;IAC3D,OAAO,CAAC,mBAAmB,CAAkC;IAC7D,OAAO,CAAC,uBAAuB,CAAkC;gBAE7C,EAAE,EAAE,YAAY;IAEpC;;OAEG;IACG,SAAS,CACb,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,OAAO,CAAC,MAAM,CAAC;IAqDlB;;OAEG;IACG,WAAW,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAyBxD;;OAEG;IACG,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS3D;;OAEG;IACH,yBAAyB,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,EAAE;IAS9D;;OAEG;IACH,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,EAAE;IAS5D;;OAEG;IACH,6BAA6B,CAAC,YAAY,EAAE,MAAM,GAAG,iBAAiB,EAAE;IASxE;;OAEG;IACG,eAAe,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAU5D;;OAEG;IACH,eAAe,CAAC,cAAc,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAItE;;OAEG;IACH,aAAa,CAAC,YAAY,EAAE,iBAAiB,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO;IAatF;;OAEG;IACG,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IA4DvC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAmB9B;;OAEG;IACH,QAAQ,IAAI;QACV,kBAAkB,EAAE,MAAM,CAAC;QAC3B,iBAAiB,EAAE,MAAM,CAAC;QAC1B,yBAAyB,EAAE,MAAM,CAAC;KACnC;CAOF"}
@@ -0,0 +1,229 @@
1
+ /**
2
+ * Manages active WebSocket subscriptions
3
+ * Tracks which clients are subscribed to which entities and filters
4
+ */
5
+ export class SubscriptionManager {
6
+ constructor(db) {
7
+ this.db = db;
8
+ this.subscriptions = new Map();
9
+ this.userSubscriptions = new Map();
10
+ this.entitySubscriptions = new Map();
11
+ this.connectionSubscriptions = new Map();
12
+ }
13
+ /**
14
+ * Create a new subscription
15
+ */
16
+ async subscribe(userId, connectionId, entity, filters) {
17
+ const subscriptionId = `sub_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
18
+ const now = Date.now();
19
+ const subscription = {
20
+ subscriptionId,
21
+ userId,
22
+ entity,
23
+ filters,
24
+ createdAt: now,
25
+ };
26
+ // Store in memory
27
+ this.subscriptions.set(subscriptionId, subscription);
28
+ // Update indexes
29
+ if (!this.userSubscriptions.has(userId)) {
30
+ this.userSubscriptions.set(userId, new Set());
31
+ }
32
+ this.userSubscriptions.get(userId).add(subscriptionId);
33
+ if (!this.entitySubscriptions.has(entity)) {
34
+ this.entitySubscriptions.set(entity, new Set());
35
+ }
36
+ this.entitySubscriptions.get(entity).add(subscriptionId);
37
+ if (!this.connectionSubscriptions.has(connectionId)) {
38
+ this.connectionSubscriptions.set(connectionId, new Set());
39
+ }
40
+ this.connectionSubscriptions.get(connectionId).add(subscriptionId);
41
+ // Persist to database
42
+ await this.db.run(`INSERT INTO subscriptions (id, user_id, entity, connection_id, created_at, last_heartbeat)
43
+ VALUES (?, ?, ?, ?, ?, ?)`, [subscriptionId, userId, entity, connectionId, now, now]);
44
+ // Store filters if provided
45
+ if (filters) {
46
+ for (const [key, value] of Object.entries(filters)) {
47
+ const filterId = `filter_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
48
+ await this.db.run(`INSERT INTO subscription_filters (id, subscription_id, filter_key, filter_value, created_at)
49
+ VALUES (?, ?, ?, ?, ?)`, [filterId, subscriptionId, key, JSON.stringify(value), now]);
50
+ }
51
+ }
52
+ return subscriptionId;
53
+ }
54
+ /**
55
+ * Remove a subscription
56
+ */
57
+ async unsubscribe(subscriptionId) {
58
+ const subscription = this.subscriptions.get(subscriptionId);
59
+ if (!subscription)
60
+ return;
61
+ // Remove from memory
62
+ this.subscriptions.delete(subscriptionId);
63
+ // Update indexes
64
+ this.userSubscriptions.get(subscription.userId)?.delete(subscriptionId);
65
+ this.entitySubscriptions.get(subscription.entity)?.delete(subscriptionId);
66
+ // Find and update connection subscriptions
67
+ for (const [connId, subs] of this.connectionSubscriptions.entries()) {
68
+ if (subs.has(subscriptionId)) {
69
+ subs.delete(subscriptionId);
70
+ if (subs.size === 0) {
71
+ this.connectionSubscriptions.delete(connId);
72
+ }
73
+ }
74
+ }
75
+ // Remove from database
76
+ await this.db.run('DELETE FROM subscriptions WHERE id = ?', [subscriptionId]);
77
+ }
78
+ /**
79
+ * Remove all subscriptions for a connection
80
+ */
81
+ async disconnectClient(connectionId) {
82
+ const subscriptionIds = this.connectionSubscriptions.get(connectionId);
83
+ if (!subscriptionIds)
84
+ return;
85
+ for (const subId of subscriptionIds) {
86
+ await this.unsubscribe(subId);
87
+ }
88
+ }
89
+ /**
90
+ * Get all subscriptions for an entity
91
+ */
92
+ getSubscriptionsForEntity(entity) {
93
+ const subscriptionIds = this.entitySubscriptions.get(entity);
94
+ if (!subscriptionIds)
95
+ return [];
96
+ return Array.from(subscriptionIds)
97
+ .map((id) => this.subscriptions.get(id))
98
+ .filter((sub) => sub !== undefined);
99
+ }
100
+ /**
101
+ * Get all subscriptions for a user
102
+ */
103
+ getSubscriptionsForUser(userId) {
104
+ const subscriptionIds = this.userSubscriptions.get(userId);
105
+ if (!subscriptionIds)
106
+ return [];
107
+ return Array.from(subscriptionIds)
108
+ .map((id) => this.subscriptions.get(id))
109
+ .filter((sub) => sub !== undefined);
110
+ }
111
+ /**
112
+ * Get all subscriptions for a connection
113
+ */
114
+ getSubscriptionsForConnection(connectionId) {
115
+ const subscriptionIds = this.connectionSubscriptions.get(connectionId);
116
+ if (!subscriptionIds)
117
+ return [];
118
+ return Array.from(subscriptionIds)
119
+ .map((id) => this.subscriptions.get(id))
120
+ .filter((sub) => sub !== undefined);
121
+ }
122
+ /**
123
+ * Update last heartbeat for a subscription
124
+ */
125
+ async updateHeartbeat(subscriptionId) {
126
+ const subscription = this.subscriptions.get(subscriptionId);
127
+ if (!subscription)
128
+ return;
129
+ const now = Date.now();
130
+ subscription.createdAt = now; // Update in-memory
131
+ await this.db.run('UPDATE subscriptions SET last_heartbeat = ? WHERE id = ?', [now, subscriptionId]);
132
+ }
133
+ /**
134
+ * Get subscription by ID
135
+ */
136
+ getSubscription(subscriptionId) {
137
+ return this.subscriptions.get(subscriptionId);
138
+ }
139
+ /**
140
+ * Check if a subscription matches a filter
141
+ */
142
+ matchesFilter(subscription, data) {
143
+ if (!subscription.filters)
144
+ return true;
145
+ for (const [key, filterValue] of Object.entries(subscription.filters)) {
146
+ const dataValue = data[key];
147
+ if (dataValue !== filterValue) {
148
+ return false;
149
+ }
150
+ }
151
+ return true;
152
+ }
153
+ /**
154
+ * Load subscriptions from database on startup
155
+ */
156
+ async loadFromDatabase() {
157
+ try {
158
+ const results = await this.db.getAll(`SELECT id, user_id, entity, connection_id, created_at
159
+ FROM subscriptions
160
+ WHERE last_heartbeat > ?`, [Date.now() - 3600000] // Only load subscriptions from last hour
161
+ );
162
+ for (const row of results) {
163
+ const subscriptionId = row.id;
164
+ const userId = row.user_id;
165
+ const entity = row.entity;
166
+ const connectionId = row.connection_id;
167
+ const createdAt = row.created_at;
168
+ // Load filters for this subscription
169
+ const filterResults = await this.db.getAll('SELECT filter_key, filter_value FROM subscription_filters WHERE subscription_id = ?', [subscriptionId]);
170
+ const filters = {};
171
+ for (const filterRow of filterResults) {
172
+ const key = filterRow.filter_key;
173
+ const value = JSON.parse(filterRow.filter_value);
174
+ filters[key] = value;
175
+ }
176
+ const subscription = {
177
+ subscriptionId,
178
+ userId,
179
+ entity,
180
+ filters: Object.keys(filters).length > 0 ? filters : undefined,
181
+ createdAt,
182
+ };
183
+ this.subscriptions.set(subscriptionId, subscription);
184
+ // Update indexes
185
+ if (!this.userSubscriptions.has(userId)) {
186
+ this.userSubscriptions.set(userId, new Set());
187
+ }
188
+ this.userSubscriptions.get(userId).add(subscriptionId);
189
+ if (!this.entitySubscriptions.has(entity)) {
190
+ this.entitySubscriptions.set(entity, new Set());
191
+ }
192
+ this.entitySubscriptions.get(entity).add(subscriptionId);
193
+ if (!this.connectionSubscriptions.has(connectionId)) {
194
+ this.connectionSubscriptions.set(connectionId, new Set());
195
+ }
196
+ this.connectionSubscriptions.get(connectionId).add(subscriptionId);
197
+ }
198
+ }
199
+ catch (error) {
200
+ console.error('Failed to load subscriptions from database:', error);
201
+ }
202
+ }
203
+ /**
204
+ * Cleanup expired subscriptions
205
+ */
206
+ async cleanup() {
207
+ const oneDayAgo = Date.now() - 86400000;
208
+ // Delete old subscriptions from database
209
+ await this.db.run('DELETE FROM subscriptions WHERE last_heartbeat < ?', [oneDayAgo]);
210
+ // Remove disconnected subscriptions from memory
211
+ const staleSubscriptions = Array.from(this.subscriptions.entries())
212
+ .filter(([_, sub]) => sub.createdAt < oneDayAgo)
213
+ .map(([id]) => id);
214
+ for (const subId of staleSubscriptions) {
215
+ this.subscriptions.delete(subId);
216
+ }
217
+ }
218
+ /**
219
+ * Get subscription statistics
220
+ */
221
+ getStats() {
222
+ return {
223
+ totalSubscriptions: this.subscriptions.size,
224
+ activeConnections: this.connectionSubscriptions.size,
225
+ entitiesWithSubscriptions: this.entitySubscriptions.size,
226
+ };
227
+ }
228
+ }
229
+ //# sourceMappingURL=subscription-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscription-manager.js","sourceRoot":"","sources":["../../../../src/realtime/subscription-manager.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,MAAM,OAAO,mBAAmB;IAM9B,YAAoB,EAAgB;QAAhB,OAAE,GAAF,EAAE,CAAc;QAL5B,kBAAa,GAAG,IAAI,GAAG,EAA6B,CAAC;QACrD,sBAAiB,GAAG,IAAI,GAAG,EAAuB,CAAC;QACnD,wBAAmB,GAAG,IAAI,GAAG,EAAuB,CAAC;QACrD,4BAAuB,GAAG,IAAI,GAAG,EAAuB,CAAC;IAE1B,CAAC;IAExC;;OAEG;IACH,KAAK,CAAC,SAAS,CACb,MAAc,EACd,YAAoB,EACpB,MAAc,EACd,OAAiC;QAEjC,MAAM,cAAc,GAAG,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QACtF,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEvB,MAAM,YAAY,GAAsB;YACtC,cAAc;YACd,MAAM;YACN,MAAM;YACN,OAAO;YACP,SAAS,EAAE,GAAG;SACf,CAAC;QAEF,kBAAkB;QAClB,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;QAErD,iBAAiB;QACjB,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YACxC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;QAChD,CAAC;QACD,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAE,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QAExD,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1C,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;QAClD,CAAC;QACD,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAE,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QAE1D,IAAI,CAAC,IAAI,CAAC,uBAAuB,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;YACpD,IAAI,CAAC,uBAAuB,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;QAC5D,CAAC;QACD,IAAI,CAAC,uBAAuB,CAAC,GAAG,CAAC,YAAY,CAAE,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QAEpE,sBAAsB;QACtB,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CACf;iCAC2B,EAC3B,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,GAAG,CAAC,CACzD,CAAC;QAEF,4BAA4B;QAC5B,IAAI,OAAO,EAAE,CAAC;YACZ,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;gBACnD,MAAM,QAAQ,GAAG,UAAU,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;gBACnF,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CACf;kCACwB,EACxB,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAC5D,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,cAAc,CAAC;IACxB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW,CAAC,cAAsB;QACtC,MAAM,YAAY,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QAC5D,IAAI,CAAC,YAAY;YAAE,OAAO;QAE1B,qBAAqB;QACrB,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;QAE1C,iBAAiB;QACjB,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC,CAAC;QACxE,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC,CAAC;QAE1E,2CAA2C;QAC3C,KAAK,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,uBAAuB,CAAC,OAAO,EAAE,EAAE,CAAC;YACpE,IAAI,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC;gBAC7B,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;gBAC5B,IAAI,IAAI,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;oBACpB,IAAI,CAAC,uBAAuB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBAC9C,CAAC;YACH,CAAC;QACH,CAAC;QAED,uBAAuB;QACvB,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,wCAAwC,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC;IAChF,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,gBAAgB,CAAC,YAAoB;QACzC,MAAM,eAAe,GAAG,IAAI,CAAC,uBAAuB,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QACvE,IAAI,CAAC,eAAe;YAAE,OAAO;QAE7B,KAAK,MAAM,KAAK,IAAI,eAAe,EAAE,CAAC;YACpC,MAAM,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED;;OAEG;IACH,yBAAyB,CAAC,MAAc;QACtC,MAAM,eAAe,GAAG,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC7D,IAAI,CAAC,eAAe;YAAE,OAAO,EAAE,CAAC;QAEhC,OAAO,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC;aAC/B,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;aACvC,MAAM,CAAC,CAAC,GAAG,EAA4B,EAAE,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC;IAClE,CAAC;IAED;;OAEG;IACH,uBAAuB,CAAC,MAAc;QACpC,MAAM,eAAe,GAAG,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC3D,IAAI,CAAC,eAAe;YAAE,OAAO,EAAE,CAAC;QAEhC,OAAO,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC;aAC/B,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;aACvC,MAAM,CAAC,CAAC,GAAG,EAA4B,EAAE,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC;IAClE,CAAC;IAED;;OAEG;IACH,6BAA6B,CAAC,YAAoB;QAChD,MAAM,eAAe,GAAG,IAAI,CAAC,uBAAuB,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QACvE,IAAI,CAAC,eAAe;YAAE,OAAO,EAAE,CAAC;QAEhC,OAAO,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC;aAC/B,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;aACvC,MAAM,CAAC,CAAC,GAAG,EAA4B,EAAE,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC;IAClE,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe,CAAC,cAAsB;QAC1C,MAAM,YAAY,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QAC5D,IAAI,CAAC,YAAY;YAAE,OAAO;QAE1B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,YAAY,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC,mBAAmB;QAEjD,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,0DAA0D,EAAE,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC;IACvG,CAAC;IAED;;OAEG;IACH,eAAe,CAAC,cAAsB;QACpC,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChD,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,YAA+B,EAAE,IAA6B;QAC1E,IAAI,CAAC,YAAY,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAEvC,KAAK,MAAM,CAAC,GAAG,EAAE,WAAW,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC;YACtE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;YAC5B,IAAI,SAAS,KAAK,WAAW,EAAE,CAAC;gBAC9B,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,gBAAgB;QACpB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,MAAM,CAClC;;kCAE0B,EAC1B,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,CAAC,yCAAyC;aACjE,CAAC;YAEF,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;gBAC1B,MAAM,cAAc,GAAG,GAAG,CAAC,EAAY,CAAC;gBACxC,MAAM,MAAM,GAAG,GAAG,CAAC,OAAiB,CAAC;gBACrC,MAAM,MAAM,GAAG,GAAG,CAAC,MAAgB,CAAC;gBACpC,MAAM,YAAY,GAAG,GAAG,CAAC,aAAuB,CAAC;gBACjD,MAAM,SAAS,GAAG,GAAG,CAAC,UAAoB,CAAC;gBAE3C,qCAAqC;gBACrC,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,MAAM,CACxC,qFAAqF,EACrF,CAAC,cAAc,CAAC,CACjB,CAAC;gBAEF,MAAM,OAAO,GAA4B,EAAE,CAAC;gBAC5C,KAAK,MAAM,SAAS,IAAI,aAAa,EAAE,CAAC;oBACtC,MAAM,GAAG,GAAG,SAAS,CAAC,UAAoB,CAAC;oBAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,YAAsB,CAAC,CAAC;oBAC3D,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;gBACvB,CAAC;gBAED,MAAM,YAAY,GAAsB;oBACtC,cAAc;oBACd,MAAM;oBACN,MAAM;oBACN,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;oBAC9D,SAAS;iBACV,CAAC;gBAEF,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;gBAErD,iBAAiB;gBACjB,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;oBACxC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;gBAChD,CAAC;gBACD,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAE,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;gBAExD,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;oBAC1C,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;gBAClD,CAAC;gBACD,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAE,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;gBAE1D,IAAI,CAAC,IAAI,CAAC,uBAAuB,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;oBACpD,IAAI,CAAC,uBAAuB,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;gBAC5D,CAAC;gBACD,IAAI,CAAC,uBAAuB,CAAC,GAAG,CAAC,YAAY,CAAE,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;YACtE,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,6CAA6C,EAAE,KAAK,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,OAAO;QACX,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC;QAExC,yCAAyC;QACzC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CACf,oDAAoD,EACpD,CAAC,SAAS,CAAC,CACZ,CAAC;QAEF,gDAAgD;QAChD,MAAM,kBAAkB,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,CAAC;aAChE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC;aAC/C,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;QAErB,KAAK,MAAM,KAAK,IAAI,kBAAkB,EAAE,CAAC;YACvC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;IAED;;OAEG;IACH,QAAQ;QAKN,OAAO;YACL,kBAAkB,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI;YAC3C,iBAAiB,EAAE,IAAI,CAAC,uBAAuB,CAAC,IAAI;YACpD,yBAAyB,EAAE,IAAI,CAAC,mBAAmB,CAAC,IAAI;SACzD,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Full-text search manager using SQLite FTS5
3
+ * Handles search index creation, updating, and querying
4
+ */
5
+ export interface SearchIndex {
6
+ entity: string;
7
+ columns: string[];
8
+ tokenize?: string;
9
+ prefix?: number[];
10
+ contentless?: boolean;
11
+ }
12
+ export interface SearchQuery {
13
+ entity: string;
14
+ query: string;
15
+ columns?: string[];
16
+ limit?: number;
17
+ offset?: number;
18
+ highlight?: boolean;
19
+ rank?: boolean;
20
+ }
21
+ export interface SearchResult {
22
+ id: string;
23
+ rank?: number;
24
+ snippet?: string;
25
+ [key: string]: any;
26
+ }
27
+ export interface SearchResponse {
28
+ results: SearchResult[];
29
+ total: number;
30
+ hasMore: boolean;
31
+ }
32
+ export interface SearchDatabase {
33
+ run(sql: string, params: any[]): Promise<any>;
34
+ getOne(sql: string, params: any[]): Promise<any>;
35
+ getAll(sql: string, params: any[]): Promise<any[]>;
36
+ }
37
+ /**
38
+ * Search manager for full-text search
39
+ */
40
+ export declare class SearchManager {
41
+ private db;
42
+ private indexes;
43
+ constructor(db: SearchDatabase);
44
+ /**
45
+ * Register a search index for an entity
46
+ */
47
+ registerIndex(index: SearchIndex): void;
48
+ /**
49
+ * Create FTS5 virtual table for an entity
50
+ */
51
+ createSearchIndex(entity: string): Promise<void>;
52
+ /**
53
+ * Create triggers to automatically update FTS index
54
+ */
55
+ private createSyncTriggers;
56
+ /**
57
+ * Rebuild search index from scratch
58
+ */
59
+ rebuildIndex(entity: string): Promise<number>;
60
+ /**
61
+ * Search for records
62
+ */
63
+ search(query: SearchQuery): Promise<SearchResponse>;
64
+ /**
65
+ * Build FTS5 query string from user query
66
+ */
67
+ private buildFTSQuery;
68
+ /**
69
+ * Delete search index
70
+ */
71
+ deleteSearchIndex(entity: string): Promise<void>;
72
+ /**
73
+ * Optimize search index (FTS5 optimize)
74
+ */
75
+ optimizeIndex(entity: string): Promise<void>;
76
+ /**
77
+ * Get search index statistics
78
+ */
79
+ getIndexStats(entity: string): Promise<{
80
+ entity: string;
81
+ documentCount: number;
82
+ indexSize: number;
83
+ }>;
84
+ /**
85
+ * Get all registered indexes
86
+ */
87
+ getRegisteredIndexes(): SearchIndex[];
88
+ /**
89
+ * Check if an entity has a search index
90
+ */
91
+ hasIndex(entity: string): boolean;
92
+ }
93
+ //# sourceMappingURL=search-manager.d.ts.map