@edgebasejs/react-native 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 (147) 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/dist/index.d.ts +0 -1
  146. package/dist/index.js +0 -1
  147. package/package.json +4 -6
@@ -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":["../../../../../core/src/realtime/subscription-manager.ts"],"names":[],"mappings":"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"}
@@ -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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-manager.d.ts","sourceRoot":"","sources":["../../../../../core/src/search/search-manager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAC9C,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IACjD,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;CACpD;AAED;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,EAAE,CAAiB;IAC3B,OAAO,CAAC,OAAO,CAAuC;gBAE1C,EAAE,EAAE,cAAc;IAI9B;;OAEG;IACH,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;IAIvC;;OAEG;IACG,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAyCtD;;OAEG;YACW,kBAAkB;IAuChC;;OAEG;IACG,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAwBnD;;OAEG;IACG,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC;IA0FzD;;OAEG;IACH,OAAO,CAAC,aAAa;IA4BrB;;OAEG;IACG,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAetD;;OAEG;IACG,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKlD;;OAEG;IACG,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QAC3C,MAAM,EAAE,MAAM,CAAC;QACf,aAAa,EAAE,MAAM,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IAoBF;;OAEG;IACH,oBAAoB,IAAI,WAAW,EAAE;IAIrC;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;CAGlC"}
@@ -0,0 +1,258 @@
1
+ /**
2
+ * Full-text search manager using SQLite FTS5
3
+ * Handles search index creation, updating, and querying
4
+ */
5
+ /**
6
+ * Search manager for full-text search
7
+ */
8
+ export class SearchManager {
9
+ constructor(db) {
10
+ this.indexes = new Map();
11
+ this.db = db;
12
+ }
13
+ /**
14
+ * Register a search index for an entity
15
+ */
16
+ registerIndex(index) {
17
+ this.indexes.set(index.entity, index);
18
+ }
19
+ /**
20
+ * Create FTS5 virtual table for an entity
21
+ */
22
+ async createSearchIndex(entity) {
23
+ const index = this.indexes.get(entity);
24
+ if (!index) {
25
+ throw new Error(`No search index configured for entity: ${entity}`);
26
+ }
27
+ const ftsTableName = `${entity}_fts`;
28
+ // Build FTS5 options
29
+ const ftsOptions = [];
30
+ // Add columns
31
+ ftsOptions.push(...index.columns);
32
+ // Add tokenizer
33
+ if (index.tokenize) {
34
+ ftsOptions.push(`tokenize='${index.tokenize}'`);
35
+ }
36
+ else {
37
+ ftsOptions.push(`tokenize='porter unicode61'`); // Default: porter stemming + unicode
38
+ }
39
+ // Add prefix indexes for autocomplete
40
+ if (index.prefix && index.prefix.length > 0) {
41
+ ftsOptions.push(`prefix='${index.prefix.join(' ')}'`);
42
+ }
43
+ // Contentless option (smaller index, no snippet support)
44
+ if (index.contentless) {
45
+ ftsOptions.push(`content=''`);
46
+ }
47
+ else {
48
+ ftsOptions.push(`content='${entity}'`);
49
+ }
50
+ // Create FTS5 virtual table
51
+ const createSQL = `CREATE VIRTUAL TABLE IF NOT EXISTS ${ftsTableName} USING fts5(${ftsOptions.join(', ')})`;
52
+ await this.db.run(createSQL, []);
53
+ // Create triggers to keep FTS index in sync with main table
54
+ await this.createSyncTriggers(entity, index);
55
+ }
56
+ /**
57
+ * Create triggers to automatically update FTS index
58
+ */
59
+ async createSyncTriggers(entity, index) {
60
+ const ftsTableName = `${entity}_fts`;
61
+ const columns = index.columns.join(', ');
62
+ const columnValues = index.columns.map((col) => `NEW.${col}`).join(', ');
63
+ // Insert trigger
64
+ await this.db.run(`CREATE TRIGGER IF NOT EXISTS ${entity}_fts_insert
65
+ AFTER INSERT ON ${entity}
66
+ BEGIN
67
+ INSERT INTO ${ftsTableName} (rowid, ${columns})
68
+ VALUES (NEW.rowid, ${columnValues});
69
+ END`, []);
70
+ // Update trigger
71
+ await this.db.run(`CREATE TRIGGER IF NOT EXISTS ${entity}_fts_update
72
+ AFTER UPDATE ON ${entity}
73
+ BEGIN
74
+ UPDATE ${ftsTableName}
75
+ SET ${index.columns.map((col) => `${col} = NEW.${col}`).join(', ')}
76
+ WHERE rowid = NEW.rowid;
77
+ END`, []);
78
+ // Delete trigger
79
+ await this.db.run(`CREATE TRIGGER IF NOT EXISTS ${entity}_fts_delete
80
+ AFTER DELETE ON ${entity}
81
+ BEGIN
82
+ DELETE FROM ${ftsTableName} WHERE rowid = OLD.rowid;
83
+ END`, []);
84
+ }
85
+ /**
86
+ * Rebuild search index from scratch
87
+ */
88
+ async rebuildIndex(entity) {
89
+ const index = this.indexes.get(entity);
90
+ if (!index) {
91
+ throw new Error(`No search index configured for entity: ${entity}`);
92
+ }
93
+ const ftsTableName = `${entity}_fts`;
94
+ // Clear existing FTS data
95
+ await this.db.run(`DELETE FROM ${ftsTableName}`, []);
96
+ // Rebuild from main table
97
+ const columns = index.columns.join(', ');
98
+ const insertSQL = `
99
+ INSERT INTO ${ftsTableName} (rowid, ${columns})
100
+ SELECT rowid, ${columns} FROM ${entity}
101
+ `;
102
+ await this.db.run(insertSQL, []);
103
+ // Get count
104
+ const result = await this.db.getOne(`SELECT COUNT(*) as count FROM ${ftsTableName}`, []);
105
+ return result?.count || 0;
106
+ }
107
+ /**
108
+ * Search for records
109
+ */
110
+ async search(query) {
111
+ const index = this.indexes.get(query.entity);
112
+ if (!index) {
113
+ throw new Error(`No search index configured for entity: ${query.entity}`);
114
+ }
115
+ const ftsTableName = `${query.entity}_fts`;
116
+ const limit = query.limit || 20;
117
+ const offset = query.offset || 0;
118
+ // Build FTS5 query
119
+ const ftsQuery = this.buildFTSQuery(query.query, query.columns);
120
+ // Build SQL with optional ranking and highlighting
121
+ let sql = `
122
+ SELECT
123
+ ${query.entity}.id,
124
+ ${query.entity}.*
125
+ `;
126
+ if (query.rank) {
127
+ sql += `, ${ftsTableName}.rank as _rank`;
128
+ }
129
+ if (query.highlight) {
130
+ // Use snippet function for highlighting
131
+ const snippetColumns = (query.columns || index.columns).map((col) => {
132
+ return `snippet(${ftsTableName}, ${index.columns.indexOf(col)}, '<mark>', '</mark>', '...', 32)`;
133
+ });
134
+ sql += `, ${snippetColumns[0]} as _snippet`;
135
+ }
136
+ sql += `
137
+ FROM ${ftsTableName}
138
+ JOIN ${query.entity} ON ${ftsTableName}.rowid = ${query.entity}.rowid
139
+ WHERE ${ftsTableName} MATCH ?
140
+ `;
141
+ if (query.rank) {
142
+ sql += ` ORDER BY ${ftsTableName}.rank`;
143
+ }
144
+ sql += ` LIMIT ? OFFSET ?`;
145
+ const results = await this.db.getAll(sql, [ftsQuery, limit + 1, offset]);
146
+ // Check if there are more results
147
+ const hasMore = results.length > limit;
148
+ const trimmedResults = hasMore ? results.slice(0, limit) : results;
149
+ // Get total count
150
+ const countSQL = `
151
+ SELECT COUNT(*) as total
152
+ FROM ${ftsTableName}
153
+ WHERE ${ftsTableName} MATCH ?
154
+ `;
155
+ const countResult = await this.db.getOne(countSQL, [ftsQuery]);
156
+ const total = countResult?.total || 0;
157
+ // Format results
158
+ const formattedResults = trimmedResults.map((row) => {
159
+ const result = {
160
+ id: row.id,
161
+ };
162
+ if (query.rank) {
163
+ result.rank = row._rank;
164
+ }
165
+ if (query.highlight) {
166
+ result.snippet = row._snippet;
167
+ }
168
+ // Add all other columns
169
+ for (const key in row) {
170
+ if (key !== '_rank' && key !== '_snippet' && key !== 'rowid') {
171
+ result[key] = row[key];
172
+ }
173
+ }
174
+ return result;
175
+ });
176
+ return {
177
+ results: formattedResults,
178
+ total,
179
+ hasMore,
180
+ };
181
+ }
182
+ /**
183
+ * Build FTS5 query string from user query
184
+ */
185
+ buildFTSQuery(query, columns) {
186
+ // Escape special FTS5 characters
187
+ let escapedQuery = query.replace(/["']/g, '');
188
+ // If specific columns are specified, use column filter
189
+ if (columns && columns.length > 0) {
190
+ const columnQueries = columns.map((col) => `${col}:${escapedQuery}`);
191
+ return columnQueries.join(' OR ');
192
+ }
193
+ // Support phrase queries (quoted strings)
194
+ if (query.includes('"')) {
195
+ return query;
196
+ }
197
+ // Support prefix matching with *
198
+ if (!query.endsWith('*')) {
199
+ const words = escapedQuery.split(/\s+/).filter((w) => w.length > 0);
200
+ // Add prefix matching to last word for autocomplete
201
+ if (words.length > 0) {
202
+ words[words.length - 1] += '*';
203
+ }
204
+ return words.join(' ');
205
+ }
206
+ return escapedQuery;
207
+ }
208
+ /**
209
+ * Delete search index
210
+ */
211
+ async deleteSearchIndex(entity) {
212
+ const ftsTableName = `${entity}_fts`;
213
+ // Drop triggers
214
+ await this.db.run(`DROP TRIGGER IF EXISTS ${entity}_fts_insert`, []);
215
+ await this.db.run(`DROP TRIGGER IF EXISTS ${entity}_fts_update`, []);
216
+ await this.db.run(`DROP TRIGGER IF EXISTS ${entity}_fts_delete`, []);
217
+ // Drop FTS table
218
+ await this.db.run(`DROP TABLE IF EXISTS ${ftsTableName}`, []);
219
+ // Remove from registered indexes
220
+ this.indexes.delete(entity);
221
+ }
222
+ /**
223
+ * Optimize search index (FTS5 optimize)
224
+ */
225
+ async optimizeIndex(entity) {
226
+ const ftsTableName = `${entity}_fts`;
227
+ await this.db.run(`INSERT INTO ${ftsTableName}(${ftsTableName}) VALUES('optimize')`, []);
228
+ }
229
+ /**
230
+ * Get search index statistics
231
+ */
232
+ async getIndexStats(entity) {
233
+ const ftsTableName = `${entity}_fts`;
234
+ const countResult = await this.db.getOne(`SELECT COUNT(*) as count FROM ${ftsTableName}`, []);
235
+ const documentCount = countResult?.count || 0;
236
+ // Get index size (approximate)
237
+ const sizeResult = await this.db.getOne(`SELECT page_count * page_size as size FROM pragma_page_count('${ftsTableName}'), pragma_page_size()`, []);
238
+ const indexSize = sizeResult?.size || 0;
239
+ return {
240
+ entity,
241
+ documentCount,
242
+ indexSize,
243
+ };
244
+ }
245
+ /**
246
+ * Get all registered indexes
247
+ */
248
+ getRegisteredIndexes() {
249
+ return Array.from(this.indexes.values());
250
+ }
251
+ /**
252
+ * Check if an entity has a search index
253
+ */
254
+ hasIndex(entity) {
255
+ return this.indexes.has(entity);
256
+ }
257
+ }
258
+ //# sourceMappingURL=search-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-manager.js","sourceRoot":"","sources":["../../../../../core/src/search/search-manager.ts"],"names":[],"mappings":"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"}