@feltdb/core 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/LICENSE +19 -0
  2. package/dist/analytics-backend.d.ts +39 -0
  3. package/dist/analytics-backend.d.ts.map +1 -0
  4. package/dist/analytics-backend.js +152 -0
  5. package/dist/application-contract.d.ts +49 -0
  6. package/dist/application-contract.d.ts.map +1 -0
  7. package/dist/application-contract.js +13 -0
  8. package/dist/application-manifest.d.ts +305 -0
  9. package/dist/application-manifest.d.ts.map +1 -0
  10. package/dist/application-manifest.js +26 -0
  11. package/dist/artifact.d.ts +73 -0
  12. package/dist/artifact.d.ts.map +1 -0
  13. package/dist/artifact.js +21 -0
  14. package/dist/authorization.d.ts +99 -0
  15. package/dist/authorization.d.ts.map +1 -0
  16. package/dist/authorization.js +15 -0
  17. package/dist/bundle.d.ts +55 -0
  18. package/dist/bundle.d.ts.map +1 -0
  19. package/dist/bundle.js +13 -0
  20. package/dist/collection.d.ts +28 -0
  21. package/dist/collection.d.ts.map +1 -1
  22. package/dist/collection.js +83 -0
  23. package/dist/db.d.ts +18 -0
  24. package/dist/db.d.ts.map +1 -1
  25. package/dist/db.js +20 -8
  26. package/dist/distributed-indexing.d.ts +170 -0
  27. package/dist/distributed-indexing.d.ts.map +1 -0
  28. package/dist/distributed-indexing.js +260 -0
  29. package/dist/flowspec.d.ts +4 -0
  30. package/dist/flowspec.d.ts.map +1 -1
  31. package/dist/flowspec.js +8 -0
  32. package/dist/http-client.d.ts +35 -0
  33. package/dist/http-client.d.ts.map +1 -0
  34. package/dist/http-client.js +70 -0
  35. package/dist/identity.d.ts +40 -0
  36. package/dist/identity.d.ts.map +1 -0
  37. package/dist/identity.js +10 -0
  38. package/dist/index-analytics.d.ts +121 -0
  39. package/dist/index-analytics.d.ts.map +1 -0
  40. package/dist/index-analytics.js +279 -0
  41. package/dist/index-backend.d.ts +26 -0
  42. package/dist/index-backend.d.ts.map +1 -0
  43. package/dist/index-backend.js +115 -0
  44. package/dist/index-dashboard.d.ts +114 -0
  45. package/dist/index-dashboard.d.ts.map +1 -0
  46. package/dist/index-dashboard.js +256 -0
  47. package/dist/index-manager.d.ts +18 -0
  48. package/dist/index-manager.d.ts.map +1 -0
  49. package/dist/index-manager.js +333 -0
  50. package/dist/index-monitoring.d.ts +133 -0
  51. package/dist/index-monitoring.d.ts.map +1 -0
  52. package/dist/index-monitoring.js +218 -0
  53. package/dist/index-recovery.d.ts +57 -0
  54. package/dist/index-recovery.d.ts.map +1 -0
  55. package/dist/index-recovery.js +117 -0
  56. package/dist/index-store.d.ts +62 -0
  57. package/dist/index-store.d.ts.map +1 -0
  58. package/dist/index-store.js +141 -0
  59. package/dist/index-types.d.ts +70 -0
  60. package/dist/index-types.d.ts.map +1 -0
  61. package/dist/index-types.js +6 -0
  62. package/dist/index.d.ts +26 -0
  63. package/dist/index.d.ts.map +1 -1
  64. package/dist/index.js +26 -0
  65. package/dist/observe.d.ts +51 -0
  66. package/dist/observe.d.ts.map +1 -0
  67. package/dist/observe.js +14 -0
  68. package/dist/protocol.d.ts +25 -0
  69. package/dist/protocol.d.ts.map +1 -0
  70. package/dist/protocol.js +18 -0
  71. package/dist/provider.d.ts +61 -0
  72. package/dist/provider.d.ts.map +1 -0
  73. package/dist/provider.js +17 -0
  74. package/dist/query-planner.d.ts +69 -0
  75. package/dist/query-planner.d.ts.map +1 -0
  76. package/dist/query-planner.js +184 -0
  77. package/dist/release.d.ts +60 -0
  78. package/dist/release.d.ts.map +1 -0
  79. package/dist/release.js +18 -0
  80. package/dist/sharding.d.ts +159 -0
  81. package/dist/sharding.d.ts.map +1 -0
  82. package/dist/sharding.js +317 -0
  83. package/dist/state-contract.d.ts +173 -0
  84. package/dist/state-contract.d.ts.map +1 -0
  85. package/dist/state-contract.js +24 -0
  86. package/dist/sync-contract.d.ts +101 -0
  87. package/dist/sync-contract.d.ts.map +1 -0
  88. package/dist/sync-contract.js +90 -0
  89. package/dist/worker.d.ts +90 -0
  90. package/dist/worker.d.ts.map +1 -0
  91. package/dist/worker.js +26 -0
  92. package/dist/workload.d.ts +102 -0
  93. package/dist/workload.d.ts.map +1 -0
  94. package/dist/workload.js +23 -0
  95. package/package.json +17 -5
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Index Analytics and Performance Monitoring
3
+ *
4
+ * Tracks index usage, query performance, and generates optimization recommendations.
5
+ * Uses Rust implementation via WASM for performance-critical operations,
6
+ * with TypeScript fallback when WASM unavailable.
7
+ */
8
+ export interface IndexMetrics {
9
+ name: string;
10
+ reads: number;
11
+ writes: number;
12
+ hitRate: number;
13
+ avgQueryTimeMs: number;
14
+ avgWriteTimeMs: number;
15
+ entries: number;
16
+ lastUsedAt: number;
17
+ createdAt: number;
18
+ }
19
+ export interface QueryTrace {
20
+ timestamp: number;
21
+ fields: string[];
22
+ operator: string;
23
+ indexUsed?: string;
24
+ executionTimeMs: number;
25
+ rowsScanned: number;
26
+ resultCount: number;
27
+ }
28
+ export interface PerformanceReport {
29
+ collectionName: string;
30
+ period: 'hourly' | 'daily' | 'weekly';
31
+ totalQueries: number;
32
+ indexedQueries: number;
33
+ fullScans: number;
34
+ avgQueryTimeMs: number;
35
+ slowestQuery?: QueryTrace;
36
+ indexMetrics: IndexMetrics[];
37
+ recommendations: TuningRecommendation[];
38
+ timestamp: number;
39
+ }
40
+ export interface TuningRecommendation {
41
+ type: 'create_index' | 'drop_index' | 'optimize_index';
42
+ priority: 'high' | 'medium' | 'low';
43
+ indexName?: string;
44
+ reason: string;
45
+ expectedSpeedup?: number;
46
+ estimatedROI?: number;
47
+ }
48
+ /**
49
+ * Tracks index usage and query performance.
50
+ */
51
+ export declare class IndexAnalytics {
52
+ private metrics;
53
+ private queryTraces;
54
+ private fieldQueryCount;
55
+ private maxTraces;
56
+ /**
57
+ * Record an index usage event.
58
+ */
59
+ recordIndexUsage(indexName: string, operation: 'read' | 'write', timeMs: number): void;
60
+ /**
61
+ * Record a query execution.
62
+ */
63
+ recordQuery(fields: string[], operator: string, executionTimeMs: number, rowsScanned: number, resultCount: number, indexUsed?: string): void;
64
+ /**
65
+ * Get metrics for an index.
66
+ */
67
+ getIndexMetrics(indexName: string): IndexMetrics | null;
68
+ /**
69
+ * Get all index metrics.
70
+ */
71
+ getAllMetrics(): IndexMetrics[];
72
+ /**
73
+ * Get query traces (for performance analysis).
74
+ */
75
+ getQueryTraces(limit?: number): QueryTrace[];
76
+ /**
77
+ * Get slowest queries.
78
+ */
79
+ getSlowestQueries(limit?: number): QueryTrace[];
80
+ /**
81
+ * Get most frequently queried fields.
82
+ */
83
+ getFrequentFields(limit?: number): Array<[string, number]>;
84
+ /**
85
+ * Calculate hit rate for an index.
86
+ */
87
+ calculateHitRate(indexName: string): number;
88
+ /**
89
+ * Generate performance report.
90
+ */
91
+ generateReport(collectionName: string, period?: 'hourly' | 'daily' | 'weekly'): PerformanceReport;
92
+ /**
93
+ * Generate tuning recommendations based on usage patterns.
94
+ */
95
+ private generateRecommendations;
96
+ /**
97
+ * Reset analytics (for testing or period rollover).
98
+ */
99
+ reset(): void;
100
+ }
101
+ /**
102
+ * Automatic tuning engine - applies recommendations automatically.
103
+ */
104
+ export declare class AutoTuner {
105
+ private analytics;
106
+ private appliedRecommendations;
107
+ constructor(analytics: IndexAnalytics);
108
+ /**
109
+ * Check if a recommendation should be auto-applied.
110
+ */
111
+ shouldAutoApply(recommendation: TuningRecommendation): boolean;
112
+ /**
113
+ * Apply a recommendation.
114
+ */
115
+ applyRecommendation(recommendation: TuningRecommendation): boolean;
116
+ /**
117
+ * Get recommendations that are ready for auto-apply.
118
+ */
119
+ getAutoApplyableRecommendations(report: PerformanceReport): TuningRecommendation[];
120
+ }
121
+ //# sourceMappingURL=index-analytics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-analytics.d.ts","sourceRoot":"","sources":["../src/index-analytics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,279 @@
1
+ /**
2
+ * Index Analytics and Performance Monitoring
3
+ *
4
+ * Tracks index usage, query performance, and generates optimization recommendations.
5
+ * Uses Rust implementation via WASM for performance-critical operations,
6
+ * with TypeScript fallback when WASM unavailable.
7
+ */
8
+ /**
9
+ * Tracks index usage and query performance.
10
+ */
11
+ export class IndexAnalytics {
12
+ constructor() {
13
+ this.metrics = new Map();
14
+ this.queryTraces = [];
15
+ this.fieldQueryCount = new Map();
16
+ this.maxTraces = 10000; // Keep last 10K queries
17
+ }
18
+ /**
19
+ * Record an index usage event.
20
+ */
21
+ recordIndexUsage(indexName, operation, timeMs) {
22
+ if (!this.metrics.has(indexName)) {
23
+ this.metrics.set(indexName, {
24
+ name: indexName,
25
+ reads: 0,
26
+ writes: 0,
27
+ hitRate: 0,
28
+ avgQueryTimeMs: 0,
29
+ avgWriteTimeMs: 0,
30
+ entries: 0,
31
+ lastUsedAt: Date.now(),
32
+ createdAt: Date.now(),
33
+ });
34
+ }
35
+ const metric = this.metrics.get(indexName);
36
+ if (operation === 'read') {
37
+ metric.reads++;
38
+ metric.avgQueryTimeMs = (metric.avgQueryTimeMs * (metric.reads - 1) + timeMs) / metric.reads;
39
+ }
40
+ else {
41
+ metric.writes++;
42
+ metric.avgWriteTimeMs = (metric.avgWriteTimeMs * (metric.writes - 1) + timeMs) / metric.writes;
43
+ }
44
+ metric.lastUsedAt = Date.now();
45
+ }
46
+ /**
47
+ * Record a query execution.
48
+ */
49
+ recordQuery(fields, operator, executionTimeMs, rowsScanned, resultCount, indexUsed) {
50
+ const trace = {
51
+ timestamp: Date.now(),
52
+ fields,
53
+ operator,
54
+ indexUsed,
55
+ executionTimeMs,
56
+ rowsScanned,
57
+ resultCount,
58
+ };
59
+ this.queryTraces.push(trace);
60
+ if (this.queryTraces.length > this.maxTraces) {
61
+ this.queryTraces.shift();
62
+ }
63
+ // Track field access patterns
64
+ for (const field of fields) {
65
+ this.fieldQueryCount.set(field, (this.fieldQueryCount.get(field) || 0) + 1);
66
+ }
67
+ // Update hit rate
68
+ if (indexUsed && this.metrics.has(indexUsed)) {
69
+ const metric = this.metrics.get(indexUsed);
70
+ metric.reads++;
71
+ }
72
+ }
73
+ /**
74
+ * Get metrics for an index.
75
+ */
76
+ getIndexMetrics(indexName) {
77
+ return this.metrics.get(indexName) || null;
78
+ }
79
+ /**
80
+ * Get all index metrics.
81
+ */
82
+ getAllMetrics() {
83
+ return Array.from(this.metrics.values());
84
+ }
85
+ /**
86
+ * Get query traces (for performance analysis).
87
+ */
88
+ getQueryTraces(limit = 100) {
89
+ return this.queryTraces.slice(-limit);
90
+ }
91
+ /**
92
+ * Get slowest queries.
93
+ */
94
+ getSlowestQueries(limit = 10) {
95
+ return [...this.queryTraces]
96
+ .sort((a, b) => b.executionTimeMs - a.executionTimeMs)
97
+ .slice(0, limit);
98
+ }
99
+ /**
100
+ * Get most frequently queried fields.
101
+ */
102
+ getFrequentFields(limit = 20) {
103
+ return [...this.fieldQueryCount.entries()]
104
+ .sort((a, b) => b[1] - a[1])
105
+ .slice(0, limit);
106
+ }
107
+ /**
108
+ * Calculate hit rate for an index.
109
+ */
110
+ calculateHitRate(indexName) {
111
+ const metric = this.metrics.get(indexName);
112
+ if (!metric || metric.reads === 0)
113
+ return 0;
114
+ const queriesUsingIndex = this.queryTraces.filter(q => q.indexUsed === indexName).length;
115
+ const totalQueries = this.queryTraces.length;
116
+ return totalQueries > 0 ? queriesUsingIndex / totalQueries : 0;
117
+ }
118
+ /**
119
+ * Generate performance report.
120
+ */
121
+ generateReport(collectionName, period = 'daily') {
122
+ const now = Date.now();
123
+ const cutoff = period === 'hourly'
124
+ ? now - 3600000
125
+ : period === 'daily'
126
+ ? now - 86400000
127
+ : now - 604800000;
128
+ const recentTraces = this.queryTraces.filter(t => t.timestamp > cutoff);
129
+ const indexedQueries = recentTraces.filter(t => t.indexUsed).length;
130
+ const fullScans = recentTraces.length - indexedQueries;
131
+ const avgQueryTime = recentTraces.length > 0
132
+ ? recentTraces.reduce((sum, t) => sum + t.executionTimeMs, 0) / recentTraces.length
133
+ : 0;
134
+ const slowestQuery = recentTraces.length > 0
135
+ ? [...recentTraces].sort((a, b) => b.executionTimeMs - a.executionTimeMs)[0]
136
+ : undefined;
137
+ const metrics = this.getAllMetrics().map(m => ({
138
+ ...m,
139
+ hitRate: this.calculateHitRate(m.name),
140
+ }));
141
+ const recommendations = this.generateRecommendations(recentTraces, metrics);
142
+ return {
143
+ collectionName,
144
+ period,
145
+ totalQueries: recentTraces.length,
146
+ indexedQueries,
147
+ fullScans,
148
+ avgQueryTimeMs: avgQueryTime,
149
+ slowestQuery,
150
+ indexMetrics: metrics,
151
+ recommendations,
152
+ timestamp: now,
153
+ };
154
+ }
155
+ /**
156
+ * Generate tuning recommendations based on usage patterns.
157
+ */
158
+ generateRecommendations(traces, metrics) {
159
+ const recommendations = [];
160
+ if (traces.length === 0)
161
+ return recommendations;
162
+ // Recommend indexes for frequently scanned fields
163
+ const fieldScans = new Map();
164
+ for (const trace of traces) {
165
+ if (!trace.indexUsed && trace.rowsScanned > 1000) {
166
+ // Full scan with many rows
167
+ for (const field of trace.fields) {
168
+ fieldScans.set(field, (fieldScans.get(field) || 0) + trace.rowsScanned);
169
+ }
170
+ }
171
+ }
172
+ // Recommend creating indexes for high-cost full scans
173
+ for (const [field, totalRowsScanned] of fieldScans) {
174
+ const avgScannedPerQuery = totalRowsScanned / traces.length;
175
+ if (avgScannedPerQuery > 1000) {
176
+ recommendations.push({
177
+ type: 'create_index',
178
+ priority: 'high',
179
+ reason: `Field '${field}' scanned ${avgScannedPerQuery.toFixed(0)} rows per query`,
180
+ expectedSpeedup: avgScannedPerQuery / 10, // Estimate 10x speedup with index
181
+ });
182
+ }
183
+ }
184
+ // Recommend dropping unused indexes
185
+ const unusedThreshold = 0.01; // Hit rate < 1%
186
+ for (const metric of metrics) {
187
+ if (metric.hitRate < unusedThreshold && metric.lastUsedAt < Date.now() - 86400000) {
188
+ // Not used in last 24 hours
189
+ recommendations.push({
190
+ type: 'drop_index',
191
+ priority: 'low',
192
+ indexName: metric.name,
193
+ reason: `Index has ${(metric.hitRate * 100).toFixed(1)}% hit rate and unused for 24h`,
194
+ estimatedROI: -0.01, // Minor cleanup benefit
195
+ });
196
+ }
197
+ }
198
+ // Recommend compound indexes
199
+ const fieldPairs = new Map();
200
+ for (const trace of traces) {
201
+ if (trace.fields.length === 2) {
202
+ const key = [...trace.fields].sort().join('|');
203
+ fieldPairs.set(key, (fieldPairs.get(key) || 0) + 1);
204
+ }
205
+ }
206
+ for (const [fields, count] of fieldPairs) {
207
+ if (count > traces.length * 0.1) {
208
+ // Used in > 10% of queries
209
+ const fieldArray = fields.split('|');
210
+ recommendations.push({
211
+ type: 'create_index',
212
+ priority: 'medium',
213
+ reason: `Fields '${fieldArray.join(', ')}' queried together in ${count} queries`,
214
+ expectedSpeedup: 5, // Estimate 5x speedup with compound index
215
+ });
216
+ }
217
+ }
218
+ // Sort by priority and expected impact
219
+ recommendations.sort((a, b) => {
220
+ const priorityOrder = { high: 0, medium: 1, low: 2 };
221
+ const priorityDiff = priorityOrder[a.priority] - priorityOrder[b.priority];
222
+ if (priorityDiff !== 0)
223
+ return priorityDiff;
224
+ return (b.expectedSpeedup || 0) - (a.expectedSpeedup || 0);
225
+ });
226
+ return recommendations.slice(0, 5); // Top 5 recommendations
227
+ }
228
+ /**
229
+ * Reset analytics (for testing or period rollover).
230
+ */
231
+ reset() {
232
+ this.metrics.clear();
233
+ this.queryTraces = [];
234
+ this.fieldQueryCount.clear();
235
+ }
236
+ }
237
+ /**
238
+ * Automatic tuning engine - applies recommendations automatically.
239
+ */
240
+ export class AutoTuner {
241
+ constructor(analytics) {
242
+ this.appliedRecommendations = new Set();
243
+ this.analytics = analytics;
244
+ }
245
+ /**
246
+ * Check if a recommendation should be auto-applied.
247
+ */
248
+ shouldAutoApply(recommendation) {
249
+ // Only auto-apply high-priority recommendations
250
+ if (recommendation.priority !== 'high')
251
+ return false;
252
+ // Don't apply the same recommendation twice
253
+ const key = `${recommendation.type}:${recommendation.indexName || recommendation.reason}`;
254
+ if (this.appliedRecommendations.has(key))
255
+ return false;
256
+ // Expected speedup should be significant (5x or more)
257
+ if ((recommendation.expectedSpeedup || 0) < 5)
258
+ return false;
259
+ return true;
260
+ }
261
+ /**
262
+ * Apply a recommendation.
263
+ */
264
+ applyRecommendation(recommendation) {
265
+ if (!this.shouldAutoApply(recommendation))
266
+ return false;
267
+ const key = `${recommendation.type}:${recommendation.indexName || recommendation.reason}`;
268
+ this.appliedRecommendations.add(key);
269
+ // Implementation would call collection.createIndex() or drop index
270
+ // For now, just track that we would apply it
271
+ return true;
272
+ }
273
+ /**
274
+ * Get recommendations that are ready for auto-apply.
275
+ */
276
+ getAutoApplyableRecommendations(report) {
277
+ return report.recommendations.filter(r => this.shouldAutoApply(r));
278
+ }
279
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Index Backend - Dynamically selects between WASM and TypeScript implementations
3
+ *
4
+ * Uses Rust/WASM for production performance, falls back to TS for testing/development
5
+ */
6
+ import type { IndexConfig, IndexQuery } from './index-types.js';
7
+ export interface IIndexBackend {
8
+ createIndex(config: IndexConfig): void;
9
+ updateRecord(recordId: string, oldValue: Record<string, any> | null, newValue: Record<string, any>): void;
10
+ queryIndex(name: string, query: IndexQuery): string[];
11
+ queryCompoundIndex(name: string, values: Record<string, any>): string[];
12
+ listIndexes(): IndexConfig[];
13
+ }
14
+ export declare class IndexBackend implements IIndexBackend {
15
+ private tsBackend;
16
+ private wasmBackend;
17
+ private useWasm;
18
+ constructor();
19
+ initializeWasm(): Promise<void>;
20
+ createIndex(config: IndexConfig): void;
21
+ updateRecord(recordId: string, oldValue: Record<string, any> | null, newValue: Record<string, any>): void;
22
+ queryIndex(name: string, query: IndexQuery): string[];
23
+ queryCompoundIndex(name: string, values: Record<string, any>): string[];
24
+ listIndexes(): IndexConfig[];
25
+ }
26
+ //# sourceMappingURL=index-backend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-backend.d.ts","sourceRoot":"","sources":["../src/index-backend.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEhE,MAAM,WAAW,aAAa;IAC5B,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IACvC,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;IAC1G,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,MAAM,EAAE,CAAC;IACtD,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,EAAE,CAAC;IACxE,WAAW,IAAI,WAAW,EAAE,CAAC;CAC9B;AAyBD,qBAAa,YAAa,YAAW,aAAa;IAChD,OAAO,CAAC,SAAS,CAA+B;IAChD,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,OAAO,CAAkB;;IAM3B,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAcrC,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IAYtC,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAezG,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,MAAM,EAAE;IAYrD,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,EAAE;IAgBvE,WAAW,IAAI,WAAW,EAAE;CAW7B"}
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Index Backend - Dynamically selects between WASM and TypeScript implementations
3
+ *
4
+ * Uses Rust/WASM for production performance, falls back to TS for testing/development
5
+ */
6
+ let wasmIndexModule = null;
7
+ let wasmAvailable = false;
8
+ async function loadWasm() {
9
+ if (wasmIndexModule !== null)
10
+ return wasmIndexModule;
11
+ try {
12
+ // Try to import WASM module
13
+ // @ts-ignore - WASM module is optional and built separately
14
+ const wasmModule = await import('@feltdb/wasm');
15
+ wasmIndexModule = wasmModule;
16
+ wasmAvailable = true;
17
+ return wasmModule;
18
+ }
19
+ catch {
20
+ // Fall back to TypeScript implementation
21
+ wasmAvailable = false;
22
+ return null;
23
+ }
24
+ }
25
+ // Import TS implementation for fallback
26
+ import { IndexManager as TsIndexManager } from './index-manager.js';
27
+ export class IndexBackend {
28
+ constructor() {
29
+ this.tsBackend = null;
30
+ this.wasmBackend = null;
31
+ this.useWasm = false;
32
+ this.tsBackend = new TsIndexManager();
33
+ }
34
+ async initializeWasm() {
35
+ if (this.wasmBackend !== null)
36
+ return;
37
+ const wasm = await loadWasm();
38
+ if (wasm && wasm.WasmIndexManager) {
39
+ try {
40
+ this.wasmBackend = new wasm.WasmIndexManager();
41
+ this.useWasm = true;
42
+ }
43
+ catch {
44
+ this.useWasm = false;
45
+ }
46
+ }
47
+ }
48
+ createIndex(config) {
49
+ if (this.useWasm && this.wasmBackend) {
50
+ try {
51
+ this.wasmBackend.create_index(JSON.stringify(config));
52
+ return;
53
+ }
54
+ catch {
55
+ // Fall back to TS
56
+ }
57
+ }
58
+ this.tsBackend?.createIndex(config);
59
+ }
60
+ updateRecord(recordId, oldValue, newValue) {
61
+ if (this.useWasm && this.wasmBackend) {
62
+ try {
63
+ // Convert record to index-friendly string format
64
+ const oldStr = oldValue ? JSON.stringify(oldValue) : null;
65
+ const newStr = JSON.stringify(newValue);
66
+ this.wasmBackend.update_record(recordId, oldStr, newStr);
67
+ return;
68
+ }
69
+ catch {
70
+ // Fall back to TS
71
+ }
72
+ }
73
+ this.tsBackend?.updateRecord(recordId, oldValue, newValue);
74
+ }
75
+ queryIndex(name, query) {
76
+ if (this.useWasm && this.wasmBackend) {
77
+ try {
78
+ const results = this.wasmBackend.query_index(name, query.operator, String(query.value || ''));
79
+ return JSON.parse(results);
80
+ }
81
+ catch {
82
+ // Fall back to TS
83
+ }
84
+ }
85
+ return this.tsBackend?.queryIndex(name, query) || [];
86
+ }
87
+ queryCompoundIndex(name, values) {
88
+ if (this.useWasm && this.wasmBackend) {
89
+ try {
90
+ const valueString = Object.values(values)
91
+ .map(v => String(v))
92
+ .join('\0');
93
+ const results = this.wasmBackend.query_index(name, 'eq', valueString);
94
+ return JSON.parse(results);
95
+ }
96
+ catch {
97
+ // Fall back to TS
98
+ }
99
+ }
100
+ // For TS backend, this would need a similar compound query interface
101
+ return [];
102
+ }
103
+ listIndexes() {
104
+ if (this.useWasm && this.wasmBackend) {
105
+ try {
106
+ const indexes = this.wasmBackend.list_indexes();
107
+ return JSON.parse(indexes);
108
+ }
109
+ catch {
110
+ // Fall back to TS
111
+ }
112
+ }
113
+ return this.tsBackend?.listIndexes() || [];
114
+ }
115
+ }
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Index Performance Dashboard
3
+ *
4
+ * Real-time visualization and monitoring of index performance metrics.
5
+ */
6
+ import type { IndexMetrics, PerformanceReport, TuningRecommendation } from './index-analytics.js';
7
+ export interface DashboardMetrics {
8
+ timestamp: number;
9
+ indexes: IndexDashboard[];
10
+ queryPerformance: QueryPerformanceSummary;
11
+ recommendations: TuningRecommendation[];
12
+ }
13
+ export interface IndexDashboard {
14
+ name: string;
15
+ type: string;
16
+ reads: number;
17
+ writes: number;
18
+ hitRate: number;
19
+ avgQueryMs: number;
20
+ avgWriteMs: number;
21
+ entries: number;
22
+ lastUsedRelative: string;
23
+ health: 'healthy' | 'warning' | 'critical';
24
+ healthReason?: string;
25
+ }
26
+ export interface QueryPerformanceSummary {
27
+ totalQueries: number;
28
+ indexedQueries: number;
29
+ fullScans: number;
30
+ indexUsageRate: number;
31
+ avgQueryMs: number;
32
+ p50QueryMs: number;
33
+ p95QueryMs: number;
34
+ p99QueryMs: number;
35
+ slowQueries: number;
36
+ }
37
+ /**
38
+ * Dashboard formatter - converts raw metrics to display format.
39
+ */
40
+ export declare class DashboardFormatter {
41
+ /**
42
+ * Format index metrics for display.
43
+ */
44
+ static formatIndexMetrics(metrics: IndexMetrics): IndexDashboard;
45
+ /**
46
+ * Format performance report for display.
47
+ */
48
+ static formatReport(report: PerformanceReport): DashboardMetrics;
49
+ /**
50
+ * Format duration for display.
51
+ */
52
+ private static formatDuration;
53
+ /**
54
+ * Generate ASCII dashboard.
55
+ */
56
+ static renderASCII(dashboard: DashboardMetrics): string;
57
+ /**
58
+ * Generate JSON dashboard data.
59
+ */
60
+ static renderJSON(dashboard: DashboardMetrics): string;
61
+ }
62
+ /**
63
+ * Real-time dashboard updates via events.
64
+ */
65
+ export declare class LiveDashboard {
66
+ private metrics;
67
+ private listeners;
68
+ private updateInterval;
69
+ private intervalHandle?;
70
+ /**
71
+ * Start streaming dashboard updates.
72
+ */
73
+ start(updateFn: () => DashboardMetrics, interval?: number): void;
74
+ /**
75
+ * Stop streaming updates.
76
+ */
77
+ stop(): void;
78
+ /**
79
+ * Subscribe to dashboard updates.
80
+ */
81
+ subscribe(listener: (metrics: DashboardMetrics) => void): () => void;
82
+ /**
83
+ * Get current dashboard state.
84
+ */
85
+ getCurrent(): DashboardMetrics | null;
86
+ private notifyListeners;
87
+ }
88
+ /**
89
+ * Alert system for performance anomalies.
90
+ */
91
+ export interface PerformanceAlert {
92
+ severity: 'info' | 'warning' | 'critical';
93
+ type: 'slow_query' | 'high_full_scans' | 'unused_index' | 'index_overhead';
94
+ message: string;
95
+ timestamp: number;
96
+ metrics?: Record<string, number | string>;
97
+ }
98
+ export declare class PerformanceAlerter {
99
+ private alerts;
100
+ private thresholds;
101
+ /**
102
+ * Check dashboard against thresholds and generate alerts.
103
+ */
104
+ checkThresholds(dashboard: DashboardMetrics): PerformanceAlert[];
105
+ /**
106
+ * Get recent alerts.
107
+ */
108
+ getRecentAlerts(limit?: number): PerformanceAlert[];
109
+ /**
110
+ * Clear old alerts.
111
+ */
112
+ clearOldAlerts(olderThanMs?: number): void;
113
+ }
114
+ //# sourceMappingURL=index-dashboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-dashboard.d.ts","sourceRoot":"","sources":["../src/index-dashboard.ts"],"names":[],"mappings":"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"}