@centrali-io/centrali-sdk 2.2.3 → 2.3.1

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.
package/index.ts CHANGED
@@ -19,10 +19,25 @@ const EventSourceImpl: typeof EventSource = typeof EventSource !== 'undefined'
19
19
  // =====================================================
20
20
 
21
21
  /**
22
- * Event types emitted by the realtime service.
22
+ * Record event types emitted by the realtime service.
23
+ */
24
+ export type RecordEventType = 'record_created' | 'record_updated' | 'record_deleted';
25
+
26
+ /**
27
+ * Validation event types emitted by the realtime service.
28
+ */
29
+ export type ValidationEventType = 'validation_suggestion_created' | 'validation_batch_completed';
30
+
31
+ /**
32
+ * Anomaly event types emitted by the realtime service.
33
+ */
34
+ export type AnomalyEventType = 'anomaly_insight_created' | 'anomaly_detection_completed';
35
+
36
+ /**
37
+ * All event types emitted by the realtime service.
23
38
  * Matches: services/backend/realtime/internal/redis/message.go
24
39
  */
25
- export type RealtimeEventType = 'record_created' | 'record_updated' | 'record_deleted';
40
+ export type RealtimeEventType = RecordEventType | ValidationEventType | AnomalyEventType;
26
41
 
27
42
  /**
28
43
  * Record event payload from the realtime service.
@@ -30,7 +45,7 @@ export type RealtimeEventType = 'record_created' | 'record_updated' | 'record_de
30
45
  */
31
46
  export interface RealtimeRecordEvent {
32
47
  /** Event type */
33
- event: RealtimeEventType;
48
+ event: RecordEventType;
34
49
  /** Workspace slug where the event occurred */
35
50
  workspaceSlug: string;
36
51
  /** Structure's record slug (e.g., "order") */
@@ -49,6 +64,184 @@ export interface RealtimeRecordEvent {
49
64
  deletedBy?: string;
50
65
  }
51
66
 
67
+ /**
68
+ * Validation suggestion data nested in the event.
69
+ */
70
+ export interface ValidationSuggestionData {
71
+ /** Structure slug */
72
+ structureSlug: string;
73
+ /** Field with the issue */
74
+ field: string;
75
+ /** Type of issue */
76
+ issueType: 'format' | 'typo' | 'duplicate' | 'semantic';
77
+ /** Original value */
78
+ originalValue: string | null;
79
+ /** Suggested value */
80
+ suggestedValue: string | null;
81
+ /** Confidence score 0-1 */
82
+ confidence: number;
83
+ /** Suggestion status */
84
+ status: 'pending' | 'auto-applied';
85
+ /** Batch ID if from a batch scan */
86
+ batchId: string | null;
87
+ }
88
+
89
+ /**
90
+ * Validation suggestion created event payload.
91
+ * Matches the format published by process_validation_events.ts
92
+ */
93
+ export interface RealtimeValidationSuggestionEvent {
94
+ /** Event type */
95
+ event: 'validation_suggestion_created';
96
+ /** Workspace slug */
97
+ workspaceSlug: string;
98
+ /** Record slug (structure slug for filtering) */
99
+ recordSlug: string;
100
+ /** Record ID the suggestion applies to */
101
+ recordId: string;
102
+ /** ISO timestamp */
103
+ timestamp: string;
104
+ /** Validation-specific data */
105
+ data: ValidationSuggestionData;
106
+ }
107
+
108
+ /**
109
+ * Validation batch data nested in the event.
110
+ */
111
+ export interface ValidationBatchData {
112
+ /** Structure slug that was scanned */
113
+ structureSlug: string;
114
+ /** Batch ID */
115
+ batchId: string;
116
+ /** Total records processed */
117
+ processed: number;
118
+ /** Issues found */
119
+ issuesFound: number;
120
+ /** Issues auto-applied */
121
+ autoApplied: number;
122
+ /** Final status */
123
+ status: 'completed' | 'failed';
124
+ /** Error message if failed */
125
+ error?: string;
126
+ /** When scan started */
127
+ startedAt: string;
128
+ /** When scan completed */
129
+ completedAt: string;
130
+ }
131
+
132
+ /**
133
+ * Validation batch completed event payload.
134
+ * Matches the format published by process_validation_events.ts
135
+ */
136
+ export interface RealtimeValidationBatchEvent {
137
+ /** Event type */
138
+ event: 'validation_batch_completed';
139
+ /** Workspace slug */
140
+ workspaceSlug: string;
141
+ /** Record slug (structure slug for filtering) */
142
+ recordSlug: string;
143
+ /** Record ID (batch ID for tracking) */
144
+ recordId: string;
145
+ /** ISO timestamp */
146
+ timestamp: string;
147
+ /** Batch-specific data */
148
+ data: ValidationBatchData;
149
+ }
150
+
151
+ /**
152
+ * Anomaly insight data nested in the event.
153
+ */
154
+ export interface AnomalyInsightData {
155
+ /** Structure ID */
156
+ structureId: string;
157
+ /** Structure slug */
158
+ structureSlug: string;
159
+ /** Insight ID */
160
+ insightId: string;
161
+ /** Type of anomaly detected */
162
+ insightType: 'time_series_anomaly' | 'statistical_outlier' | 'pattern_deviation' | 'volume_spike' | 'missing_data' | 'orphaned_reference' | 'reference_integrity';
163
+ /** Severity level */
164
+ severity: 'info' | 'warning' | 'critical';
165
+ /** Short title */
166
+ title: string;
167
+ /** Detailed description */
168
+ description: string;
169
+ /** Affected field if applicable */
170
+ affectedField?: string;
171
+ /** IDs of affected records */
172
+ affectedRecordIds?: string[];
173
+ /** Confidence score 0-1 */
174
+ confidence: number;
175
+ /** Batch ID if from batch analysis */
176
+ batchId?: string;
177
+ }
178
+
179
+ /**
180
+ * Anomaly insight created event payload.
181
+ * Matches the format published by process_anomaly_events.ts
182
+ */
183
+ export interface RealtimeAnomalyInsightEvent {
184
+ /** Event type */
185
+ event: 'anomaly_insight_created';
186
+ /** Workspace slug */
187
+ workspaceSlug: string;
188
+ /** Record slug (structure slug for filtering) */
189
+ recordSlug: string;
190
+ /** Record ID (insight ID for tracking) */
191
+ recordId: string;
192
+ /** ISO timestamp */
193
+ timestamp: string;
194
+ /** Anomaly insight data */
195
+ data: AnomalyInsightData;
196
+ }
197
+
198
+ /**
199
+ * Anomaly detection batch data nested in the event.
200
+ */
201
+ export interface AnomalyDetectionData {
202
+ /** Structure ID */
203
+ structureId: string;
204
+ /** Structure slug */
205
+ structureSlug: string;
206
+ /** Batch ID */
207
+ batchId: string;
208
+ /** Number of insights created */
209
+ insightsCreated: number;
210
+ /** Number of records analyzed */
211
+ recordsAnalyzed: number;
212
+ /** Types of analysis performed */
213
+ analysisTypes: string[];
214
+ /** Count of critical severity insights */
215
+ criticalCount: number;
216
+ /** Count of warning severity insights */
217
+ warningCount: number;
218
+ /** Count of info severity insights */
219
+ infoCount: number;
220
+ /** When analysis started */
221
+ startedAt: string;
222
+ /** When analysis completed */
223
+ completedAt: string;
224
+ }
225
+
226
+ /**
227
+ * Anomaly detection completed event payload.
228
+ * Matches the format published by process_anomaly_events.ts
229
+ */
230
+ export interface RealtimeAnomalyDetectionEvent {
231
+ /** Event type */
232
+ event: 'anomaly_detection_completed';
233
+ /** Workspace slug */
234
+ workspaceSlug: string;
235
+ /** Record slug (structure slug for filtering) */
236
+ recordSlug: string;
237
+ /** Record ID (batch ID for tracking) */
238
+ recordId: string;
239
+ /** ISO timestamp */
240
+ timestamp: string;
241
+ /** Anomaly detection data */
242
+ data: AnomalyDetectionData;
243
+ }
244
+
52
245
  /**
53
246
  * Close event payload from the realtime service.
54
247
  */
@@ -62,7 +255,7 @@ export interface RealtimeCloseEvent {
62
255
  /**
63
256
  * Union type of all realtime events.
64
257
  */
65
- export type RealtimeEvent = RealtimeRecordEvent;
258
+ export type RealtimeEvent = RealtimeRecordEvent | RealtimeValidationSuggestionEvent | RealtimeValidationBatchEvent | RealtimeAnomalyInsightEvent | RealtimeAnomalyDetectionEvent;
66
259
 
67
260
  /**
68
261
  * Error object for realtime connection errors.
@@ -381,6 +574,287 @@ export interface SearchResponse {
381
574
  query: string;
382
575
  }
383
576
 
577
+ // =====================================================
578
+ // Anomaly Insights Types
579
+ // =====================================================
580
+
581
+ /**
582
+ * Anomaly insight types.
583
+ */
584
+ export type InsightType = 'time_series_anomaly' | 'statistical_outlier' | 'pattern_deviation' | 'volume_spike' | 'missing_data' | 'orphaned_reference' | 'reference_integrity';
585
+
586
+ /**
587
+ * Anomaly insight severity levels.
588
+ */
589
+ export type InsightSeverity = 'info' | 'warning' | 'critical';
590
+
591
+ /**
592
+ * Anomaly insight status.
593
+ */
594
+ export type InsightStatus = 'active' | 'acknowledged' | 'dismissed';
595
+
596
+ /**
597
+ * Anomaly insight record.
598
+ */
599
+ export interface AnomalyInsight {
600
+ /** Unique identifier */
601
+ id: string;
602
+ /** Workspace slug */
603
+ workspaceSlug: string;
604
+ /** Structure ID */
605
+ structureId: string;
606
+ /** Structure slug */
607
+ structureSlug: string;
608
+ /** Batch ID if created in batch */
609
+ batchId: string | null;
610
+ /** Type of insight */
611
+ insightType: InsightType;
612
+ /** Severity level */
613
+ severity: InsightSeverity;
614
+ /** Short title */
615
+ title: string;
616
+ /** Detailed description */
617
+ description: string;
618
+ /** Affected field if applicable */
619
+ affectedField: string | null;
620
+ /** IDs of affected records */
621
+ affectedRecordIds: string[] | null;
622
+ /** Additional metadata */
623
+ metadata: Record<string, any>;
624
+ /** Confidence score 0-1 */
625
+ confidence: number;
626
+ /** Current status */
627
+ status: InsightStatus;
628
+ /** When acknowledged */
629
+ acknowledgedAt: string | null;
630
+ /** Who acknowledged */
631
+ acknowledgedBy: string | null;
632
+ /** Creation timestamp */
633
+ createdAt: string;
634
+ /** Last update timestamp */
635
+ updatedAt: string;
636
+ }
637
+
638
+ /**
639
+ * Options for listing anomaly insights.
640
+ */
641
+ export interface ListInsightsOptions {
642
+ /** Filter by severity */
643
+ severity?: InsightSeverity;
644
+ /** Filter by status */
645
+ status?: InsightStatus;
646
+ /** Filter by insight type */
647
+ type?: InsightType;
648
+ /** Filter by structure slug */
649
+ structureSlug?: string;
650
+ /** Maximum results */
651
+ limit?: number;
652
+ /** Offset for pagination */
653
+ offset?: number;
654
+ }
655
+
656
+ /**
657
+ * Result of triggering anomaly analysis.
658
+ */
659
+ export interface AnomalyAnalysisResult {
660
+ /** Whether the analysis was triggered */
661
+ success: boolean;
662
+ /** Status message */
663
+ message: string;
664
+ /** Batch ID for tracking (if triggered) */
665
+ batchId?: string;
666
+ }
667
+
668
+ /**
669
+ * Summary of anomaly insights.
670
+ */
671
+ export interface InsightsSummary {
672
+ /** Total insights */
673
+ total: number;
674
+ /** Active insights */
675
+ active: number;
676
+ /** Acknowledged insights */
677
+ acknowledged: number;
678
+ /** Dismissed insights */
679
+ dismissed: number;
680
+ /** Breakdown by severity */
681
+ bySeverity: {
682
+ critical: number;
683
+ warning: number;
684
+ info: number;
685
+ };
686
+ /** Breakdown by type */
687
+ byType: Record<string, number>;
688
+ }
689
+
690
+ // =====================================================
691
+ // Validation Types (Data Quality)
692
+ // =====================================================
693
+
694
+ /**
695
+ * Validation issue types.
696
+ * - 'type': Schema type mismatch (e.g., string where array expected) - rule-based
697
+ * - 'format': Format validation (email, phone, url patterns) - rule-based
698
+ * - 'typo': Spelling/typo detection - AI-based
699
+ * - 'duplicate': Duplicate record detection - rule-based
700
+ * - 'semantic': Logical/semantic issues - AI-based
701
+ */
702
+ export type ValidationIssueType = 'type' | 'format' | 'typo' | 'duplicate' | 'semantic';
703
+
704
+ /**
705
+ * Validation suggestion status.
706
+ */
707
+ export type ValidationSuggestionStatus = 'pending' | 'accepted' | 'rejected' | 'auto-applied';
708
+
709
+ /**
710
+ * A validation suggestion from the AI validation system.
711
+ */
712
+ export interface ValidationSuggestion {
713
+ /** Unique identifier */
714
+ id: string;
715
+ /** Workspace slug */
716
+ workspaceSlug: string;
717
+ /** Structure ID */
718
+ structureId: string;
719
+ /** Record ID */
720
+ recordId: string;
721
+ /** Structure's record slug */
722
+ recordSlug: string;
723
+ /** Field name with the issue */
724
+ field: string;
725
+ /** Type of issue detected */
726
+ issueType: ValidationIssueType;
727
+ /** Original value in the field */
728
+ originalValue: string | null;
729
+ /** Suggested corrected value */
730
+ suggestedValue: string | null;
731
+ /** Confidence score 0-1 */
732
+ confidence: number;
733
+ /** Current status */
734
+ status: ValidationSuggestionStatus;
735
+ /** Batch ID if created during batch scan */
736
+ batchId: string | null;
737
+ /** Additional metadata */
738
+ metadata: Record<string, any>;
739
+ /** Creation timestamp */
740
+ createdAt: string;
741
+ /** Last update timestamp */
742
+ updatedAt: string;
743
+ /** When resolved (accepted/rejected) */
744
+ resolvedAt: string | null;
745
+ /** Who resolved */
746
+ resolvedBy: string | null;
747
+ }
748
+
749
+ /**
750
+ * Options for listing validation suggestions.
751
+ */
752
+ export interface ListValidationSuggestionsOptions {
753
+ /** Filter by structure ID */
754
+ structureId?: string;
755
+ /** Filter by record ID */
756
+ recordId?: string;
757
+ /** Filter by status */
758
+ status?: ValidationSuggestionStatus;
759
+ /** Filter by issue type */
760
+ issueType?: ValidationIssueType;
761
+ /** Filter by batch ID */
762
+ batchId?: string;
763
+ /** Minimum confidence threshold */
764
+ minConfidence?: number;
765
+ /** Maximum results (default: 50, max: 100) */
766
+ limit?: number;
767
+ /** Offset for pagination */
768
+ offset?: number;
769
+ }
770
+
771
+ /**
772
+ * Batch scan status.
773
+ */
774
+ export type BatchScanStatus = 'queued' | 'pending' | 'processing' | 'completed' | 'failed';
775
+
776
+ /**
777
+ * Result from triggering a batch validation scan.
778
+ */
779
+ export interface BatchScanResult {
780
+ /** Unique batch identifier */
781
+ batchId: string;
782
+ /** Current status */
783
+ status: BatchScanStatus;
784
+ /** Total records to scan */
785
+ total: number;
786
+ /** Records processed so far */
787
+ processed: number;
788
+ /** Issues found so far */
789
+ issuesFound: number;
790
+ /** When the scan started */
791
+ startedAt: string;
792
+ /** When the scan completed (if finished) */
793
+ completedAt?: string;
794
+ /** Error message if failed */
795
+ error?: string;
796
+ }
797
+
798
+ /**
799
+ * Options for triggering a batch scan.
800
+ */
801
+ export interface TriggerScanOptions {
802
+ /** Validation types to run (defaults to structure config) */
803
+ validationTypes?: ValidationIssueType[];
804
+ }
805
+
806
+ /**
807
+ * Options for waiting for a scan to complete.
808
+ */
809
+ export interface WaitForScanOptions {
810
+ /** Poll interval in milliseconds (default: 5000) */
811
+ pollInterval?: number;
812
+ /** Timeout in milliseconds (default: 300000 = 5 minutes) */
813
+ timeout?: number;
814
+ }
815
+
816
+ /**
817
+ * Summary of validation suggestions.
818
+ */
819
+ export interface ValidationSummary {
820
+ /** Total suggestions */
821
+ total: number;
822
+ /** Pending suggestions */
823
+ pending: number;
824
+ /** Accepted suggestions */
825
+ accepted: number;
826
+ /** Rejected suggestions */
827
+ rejected: number;
828
+ /** Auto-applied suggestions */
829
+ autoApplied: number;
830
+ /** Breakdown by issue type */
831
+ byIssueType: Record<string, number>;
832
+ }
833
+
834
+ /**
835
+ * Result from accepting a suggestion.
836
+ */
837
+ export interface AcceptSuggestionResult {
838
+ /** The updated suggestion */
839
+ suggestion: ValidationSuggestion;
840
+ /** Whether the record was updated */
841
+ recordUpdated: boolean;
842
+ /** Status message */
843
+ message: string;
844
+ }
845
+
846
+ /**
847
+ * Result from bulk operations.
848
+ */
849
+ export interface BulkOperationResult {
850
+ /** Number of successful operations */
851
+ count: number;
852
+ /** Errors for failed operations */
853
+ errors?: Array<{ id: string; error: string }>;
854
+ /** Status message */
855
+ message: string;
856
+ }
857
+
384
858
  /**
385
859
  * Generate the API URL from the base URL by adding the 'api.' subdomain.
386
860
  * E.g., https://centrali.io -> https://api.centrali.io
@@ -769,6 +1243,126 @@ export function getSearchApiPath(workspaceId: string): string {
769
1243
  return `search/workspace/${workspaceId}/api/v1/records/search`;
770
1244
  }
771
1245
 
1246
+ /**
1247
+ * Generate Anomaly Insights base API URL PATH.
1248
+ */
1249
+ export function getAnomalyInsightsApiPath(workspaceId: string, insightId?: string): string {
1250
+ const basePath = `data/workspace/${workspaceId}/api/v1/ai/insights`;
1251
+ return insightId ? `${basePath}/${insightId}` : basePath;
1252
+ }
1253
+
1254
+ /**
1255
+ * Generate Anomaly Insights summary API URL PATH.
1256
+ */
1257
+ export function getAnomalyInsightsSummaryApiPath(workspaceId: string): string {
1258
+ return `data/workspace/${workspaceId}/api/v1/ai/insights/summary`;
1259
+ }
1260
+
1261
+ /**
1262
+ * Generate Anomaly Insights acknowledge API URL PATH.
1263
+ */
1264
+ export function getAnomalyInsightAcknowledgeApiPath(workspaceId: string, insightId: string): string {
1265
+ return `data/workspace/${workspaceId}/api/v1/ai/insights/${insightId}/acknowledge`;
1266
+ }
1267
+
1268
+ /**
1269
+ * Generate Anomaly Insights dismiss API URL PATH.
1270
+ */
1271
+ export function getAnomalyInsightDismissApiPath(workspaceId: string, insightId: string): string {
1272
+ return `data/workspace/${workspaceId}/api/v1/ai/insights/${insightId}/dismiss`;
1273
+ }
1274
+
1275
+ /**
1276
+ * Generate Anomaly Insights bulk acknowledge API URL PATH.
1277
+ */
1278
+ export function getAnomalyInsightsBulkAcknowledgeApiPath(workspaceId: string): string {
1279
+ return `data/workspace/${workspaceId}/api/v1/ai/insights/bulk-acknowledge`;
1280
+ }
1281
+
1282
+ /**
1283
+ * Generate Anomaly analysis trigger API URL PATH.
1284
+ */
1285
+ export function getAnomalyAnalysisTriggerApiPath(workspaceId: string): string {
1286
+ return `data/workspace/${workspaceId}/api/v1/ai/anomalies/analyze`;
1287
+ }
1288
+
1289
+ /**
1290
+ * Generate structure-scoped anomaly insights API URL PATH.
1291
+ */
1292
+ export function getStructureInsightsApiPath(workspaceId: string, structureSlug: string): string {
1293
+ return `data/workspace/${workspaceId}/api/v1/structures/${structureSlug}/insights`;
1294
+ }
1295
+
1296
+ // =====================================================
1297
+ // Validation API Path Helpers
1298
+ // =====================================================
1299
+
1300
+ /**
1301
+ * Generate Validation suggestions base API URL PATH.
1302
+ */
1303
+ export function getValidationSuggestionsApiPath(workspaceId: string, suggestionId?: string): string {
1304
+ const basePath = `data/workspace/${workspaceId}/api/v1/ai/validation/suggestions`;
1305
+ return suggestionId ? `${basePath}/${suggestionId}` : basePath;
1306
+ }
1307
+
1308
+ /**
1309
+ * Generate Validation suggestion accept API URL PATH.
1310
+ */
1311
+ export function getValidationSuggestionAcceptApiPath(workspaceId: string, suggestionId: string): string {
1312
+ return `data/workspace/${workspaceId}/api/v1/ai/validation/suggestions/${suggestionId}/accept`;
1313
+ }
1314
+
1315
+ /**
1316
+ * Generate Validation suggestion reject API URL PATH.
1317
+ */
1318
+ export function getValidationSuggestionRejectApiPath(workspaceId: string, suggestionId: string): string {
1319
+ return `data/workspace/${workspaceId}/api/v1/ai/validation/suggestions/${suggestionId}/reject`;
1320
+ }
1321
+
1322
+ /**
1323
+ * Generate Validation bulk accept API URL PATH.
1324
+ */
1325
+ export function getValidationBulkAcceptApiPath(workspaceId: string): string {
1326
+ return `data/workspace/${workspaceId}/api/v1/ai/validation/suggestions/bulk-accept`;
1327
+ }
1328
+
1329
+ /**
1330
+ * Generate Validation bulk reject API URL PATH.
1331
+ */
1332
+ export function getValidationBulkRejectApiPath(workspaceId: string): string {
1333
+ return `data/workspace/${workspaceId}/api/v1/ai/validation/suggestions/bulk-reject`;
1334
+ }
1335
+
1336
+ /**
1337
+ * Generate Validation summary API URL PATH.
1338
+ */
1339
+ export function getValidationSummaryApiPath(workspaceId: string): string {
1340
+ return `data/workspace/${workspaceId}/api/v1/ai/validation/summary`;
1341
+ }
1342
+
1343
+ /**
1344
+ * Generate Validation record suggestions API URL PATH.
1345
+ */
1346
+ export function getValidationRecordSuggestionsApiPath(workspaceId: string, recordId: string): string {
1347
+ return `data/workspace/${workspaceId}/api/v1/ai/validation/records/${recordId}/suggestions`;
1348
+ }
1349
+
1350
+ /**
1351
+ * Generate Validation structure pending count API URL PATH.
1352
+ */
1353
+ export function getValidationPendingCountApiPath(workspaceId: string, structureId: string): string {
1354
+ return `data/workspace/${workspaceId}/api/v1/ai/validation/structures/${structureId}/pending-count`;
1355
+ }
1356
+
1357
+ /**
1358
+ * Generate Validation batch scan API URL PATH (AI Service).
1359
+ * Note: This routes to the AI service, not the Data service.
1360
+ */
1361
+ export function getValidationScanApiPath(workspaceId: string, batchId?: string): string {
1362
+ const basePath = `ai/workspace/${workspaceId}/api/v1/validate/scan`;
1363
+ return batchId ? `${basePath}/${batchId}` : basePath;
1364
+ }
1365
+
772
1366
  // =====================================================
773
1367
  // Triggers Manager
774
1368
  // =====================================================
@@ -1082,6 +1676,475 @@ export class SmartQueriesManager {
1082
1676
  }
1083
1677
  }
1084
1678
 
1679
+ // =====================================================
1680
+ // Anomaly Insights Manager
1681
+ // =====================================================
1682
+
1683
+ /**
1684
+ * AnomalyInsightsManager provides methods for querying and managing AI-generated anomaly insights.
1685
+ * Access via `client.anomalyInsights`.
1686
+ *
1687
+ * Usage:
1688
+ * ```ts
1689
+ * // List all active insights
1690
+ * const insights = await client.anomalyInsights.list({ status: 'active' });
1691
+ *
1692
+ * // Get insights for a specific structure
1693
+ * const orderInsights = await client.anomalyInsights.listByStructure('orders');
1694
+ *
1695
+ * // Get insight summary
1696
+ * const summary = await client.anomalyInsights.getSummary();
1697
+ *
1698
+ * // Acknowledge an insight
1699
+ * await client.anomalyInsights.acknowledge('insight-id');
1700
+ *
1701
+ * // Dismiss an insight
1702
+ * await client.anomalyInsights.dismiss('insight-id');
1703
+ * ```
1704
+ */
1705
+ export class AnomalyInsightsManager {
1706
+ private requestFn: <T>(method: Method, path: string, data?: any, queryParams?: Record<string, any>) => Promise<ApiResponse<T>>;
1707
+ private workspaceId: string;
1708
+
1709
+ constructor(
1710
+ workspaceId: string,
1711
+ requestFn: <T>(method: Method, path: string, data?: any, queryParams?: Record<string, any>) => Promise<ApiResponse<T>>
1712
+ ) {
1713
+ this.workspaceId = workspaceId;
1714
+ this.requestFn = requestFn;
1715
+ }
1716
+
1717
+ /**
1718
+ * List anomaly insights with optional filters.
1719
+ *
1720
+ * @param options - Optional filter and pagination options
1721
+ * @returns List of anomaly insights
1722
+ *
1723
+ * @example
1724
+ * ```ts
1725
+ * // List all active critical insights
1726
+ * const insights = await client.anomalyInsights.list({
1727
+ * status: 'active',
1728
+ * severity: 'critical'
1729
+ * });
1730
+ *
1731
+ * // List insights for a specific structure
1732
+ * const orderInsights = await client.anomalyInsights.list({
1733
+ * structureSlug: 'orders'
1734
+ * });
1735
+ * ```
1736
+ */
1737
+ public list(options?: ListInsightsOptions): Promise<ApiResponse<AnomalyInsight[]>> {
1738
+ const path = getAnomalyInsightsApiPath(this.workspaceId);
1739
+ return this.requestFn<AnomalyInsight[]>('GET', path, null, options);
1740
+ }
1741
+
1742
+ /**
1743
+ * List insights for a specific structure.
1744
+ *
1745
+ * @param structureSlug - The structure's record slug
1746
+ * @param options - Optional filter options
1747
+ * @returns List of insights for the structure
1748
+ *
1749
+ * @example
1750
+ * ```ts
1751
+ * const insights = await client.anomalyInsights.listByStructure('orders');
1752
+ * ```
1753
+ */
1754
+ public listByStructure(
1755
+ structureSlug: string,
1756
+ options?: Omit<ListInsightsOptions, 'structureSlug'>
1757
+ ): Promise<ApiResponse<AnomalyInsight[]>> {
1758
+ const path = getStructureInsightsApiPath(this.workspaceId, structureSlug);
1759
+ return this.requestFn<AnomalyInsight[]>('GET', path, null, options);
1760
+ }
1761
+
1762
+ /**
1763
+ * Get a single insight by ID.
1764
+ *
1765
+ * @param insightId - The insight UUID
1766
+ * @returns The insight details
1767
+ *
1768
+ * @example
1769
+ * ```ts
1770
+ * const insight = await client.anomalyInsights.get('insight-id');
1771
+ * console.log('Insight:', insight.data.title);
1772
+ * ```
1773
+ */
1774
+ public get(insightId: string): Promise<ApiResponse<AnomalyInsight>> {
1775
+ const path = getAnomalyInsightsApiPath(this.workspaceId, insightId);
1776
+ return this.requestFn<AnomalyInsight>('GET', path);
1777
+ }
1778
+
1779
+ /**
1780
+ * Acknowledge an insight.
1781
+ * Marks the insight as reviewed/handled.
1782
+ *
1783
+ * @param insightId - The insight UUID
1784
+ * @returns The updated insight
1785
+ *
1786
+ * @example
1787
+ * ```ts
1788
+ * await client.anomalyInsights.acknowledge('insight-id');
1789
+ * ```
1790
+ */
1791
+ public acknowledge(insightId: string): Promise<ApiResponse<AnomalyInsight>> {
1792
+ const path = getAnomalyInsightAcknowledgeApiPath(this.workspaceId, insightId);
1793
+ return this.requestFn<AnomalyInsight>('POST', path);
1794
+ }
1795
+
1796
+ /**
1797
+ * Dismiss an insight.
1798
+ * Marks the insight as not relevant/false positive.
1799
+ *
1800
+ * @param insightId - The insight UUID
1801
+ * @returns The updated insight
1802
+ *
1803
+ * @example
1804
+ * ```ts
1805
+ * await client.anomalyInsights.dismiss('insight-id');
1806
+ * ```
1807
+ */
1808
+ public dismiss(insightId: string): Promise<ApiResponse<AnomalyInsight>> {
1809
+ const path = getAnomalyInsightDismissApiPath(this.workspaceId, insightId);
1810
+ return this.requestFn<AnomalyInsight>('POST', path);
1811
+ }
1812
+
1813
+ /**
1814
+ * Bulk acknowledge multiple insights.
1815
+ *
1816
+ * @param ids - Array of insight IDs to acknowledge
1817
+ * @returns Result with count of updated insights
1818
+ *
1819
+ * @example
1820
+ * ```ts
1821
+ * const result = await client.anomalyInsights.bulkAcknowledge(['id1', 'id2']);
1822
+ * console.log('Acknowledged:', result.data.updated);
1823
+ * ```
1824
+ */
1825
+ public bulkAcknowledge(ids: string[]): Promise<ApiResponse<{ updated: number; message: string }>> {
1826
+ const path = getAnomalyInsightsBulkAcknowledgeApiPath(this.workspaceId);
1827
+ return this.requestFn<{ updated: number; message: string }>('POST', path, { ids });
1828
+ }
1829
+
1830
+ /**
1831
+ * Get insights summary/statistics.
1832
+ *
1833
+ * @param structureSlug - Optional structure to filter summary
1834
+ * @returns Summary of insights by status and severity
1835
+ *
1836
+ * @example
1837
+ * ```ts
1838
+ * // Get overall summary
1839
+ * const summary = await client.anomalyInsights.getSummary();
1840
+ * console.log('Critical insights:', summary.data.bySeverity.critical);
1841
+ *
1842
+ * // Get summary for a specific structure
1843
+ * const orderSummary = await client.anomalyInsights.getSummary('orders');
1844
+ * ```
1845
+ */
1846
+ public getSummary(structureSlug?: string): Promise<ApiResponse<InsightsSummary>> {
1847
+ const path = getAnomalyInsightsSummaryApiPath(this.workspaceId);
1848
+ const params = structureSlug ? { structureSlug } : undefined;
1849
+ return this.requestFn<InsightsSummary>('GET', path, null, params);
1850
+ }
1851
+
1852
+ /**
1853
+ * Trigger anomaly analysis for a structure.
1854
+ * Starts an AI-powered analysis to detect anomalies in the structure's data.
1855
+ *
1856
+ * @param structureSlug - The structure's record slug to analyze
1857
+ * @returns Result indicating if analysis was triggered and the batch ID
1858
+ *
1859
+ * @example
1860
+ * ```ts
1861
+ * const result = await client.anomalyInsights.triggerAnalysis('orders');
1862
+ * if (result.data.success) {
1863
+ * console.log('Analysis started:', result.data.batchId);
1864
+ * }
1865
+ * ```
1866
+ */
1867
+ public triggerAnalysis(structureSlug: string): Promise<ApiResponse<AnomalyAnalysisResult>> {
1868
+ const path = getAnomalyAnalysisTriggerApiPath(this.workspaceId);
1869
+ return this.requestFn<AnomalyAnalysisResult>('POST', path, { structureSlug });
1870
+ }
1871
+ }
1872
+
1873
+ // =====================================================
1874
+ // Validation Manager (Data Quality)
1875
+ // =====================================================
1876
+
1877
+ /**
1878
+ * ValidationManager provides methods for AI-powered data quality validation.
1879
+ * Access via `client.validation`.
1880
+ *
1881
+ * Features:
1882
+ * - Trigger batch validation scans on structures
1883
+ * - List and manage validation suggestions (typos, format issues, duplicates)
1884
+ * - Accept or reject suggestions to fix data
1885
+ * - Get validation summaries and statistics
1886
+ *
1887
+ * Usage:
1888
+ * ```ts
1889
+ * // Trigger a batch scan
1890
+ * const batch = await client.validation.triggerScan('orders');
1891
+ * console.log('Scan started:', batch.data.batchId);
1892
+ *
1893
+ * // Wait for completion
1894
+ * const result = await client.validation.waitForScan(batch.data.batchId);
1895
+ *
1896
+ * // List pending suggestions
1897
+ * const suggestions = await client.validation.listSuggestions({ status: 'pending' });
1898
+ *
1899
+ * // Accept a suggestion (applies the fix)
1900
+ * await client.validation.accept('suggestion-id');
1901
+ *
1902
+ * // Bulk accept high-confidence suggestions
1903
+ * const highConfidence = suggestions.data.filter(s => s.confidence >= 0.95);
1904
+ * await client.validation.bulkAccept(highConfidence.map(s => s.id));
1905
+ * ```
1906
+ */
1907
+ export class ValidationManager {
1908
+ private requestFn: <T>(method: Method, path: string, data?: any, queryParams?: Record<string, any>) => Promise<ApiResponse<T>>;
1909
+ private workspaceId: string;
1910
+
1911
+ constructor(
1912
+ workspaceId: string,
1913
+ requestFn: <T>(method: Method, path: string, data?: any, queryParams?: Record<string, any>) => Promise<ApiResponse<T>>
1914
+ ) {
1915
+ this.workspaceId = workspaceId;
1916
+ this.requestFn = requestFn;
1917
+ }
1918
+
1919
+ /**
1920
+ * Trigger a batch validation scan on a structure.
1921
+ *
1922
+ * @param structureSlug - The structure's slug to scan
1923
+ * @param options - Optional scan configuration
1924
+ * @returns The batch scan result with batchId for tracking
1925
+ *
1926
+ * @example
1927
+ * ```ts
1928
+ * const batch = await client.validation.triggerScan('orders');
1929
+ * console.log('Batch ID:', batch.data.batchId);
1930
+ * console.log('Records to scan:', batch.data.total);
1931
+ * ```
1932
+ */
1933
+ public triggerScan(
1934
+ structureSlug: string,
1935
+ options?: TriggerScanOptions
1936
+ ): Promise<ApiResponse<BatchScanResult>> {
1937
+ const path = getValidationScanApiPath(this.workspaceId);
1938
+ // Note: workspaceSlug is in URL path, not body
1939
+ return this.requestFn<BatchScanResult>('POST', path, {
1940
+ structureSlug,
1941
+ validationTypes: options?.validationTypes,
1942
+ });
1943
+ }
1944
+
1945
+ /**
1946
+ * Get the status of a batch validation scan.
1947
+ *
1948
+ * @param batchId - The batch scan ID
1949
+ * @returns Current scan status and progress
1950
+ *
1951
+ * @example
1952
+ * ```ts
1953
+ * const status = await client.validation.getScanStatus('batch-id');
1954
+ * console.log('Progress:', status.data.processed, '/', status.data.total);
1955
+ * ```
1956
+ */
1957
+ public getScanStatus(batchId: string): Promise<ApiResponse<BatchScanResult>> {
1958
+ const path = getValidationScanApiPath(this.workspaceId, batchId);
1959
+ return this.requestFn<BatchScanResult>('GET', path);
1960
+ }
1961
+
1962
+ /**
1963
+ * Wait for a batch scan to complete with polling.
1964
+ *
1965
+ * @param batchId - The batch scan ID
1966
+ * @param options - Polling configuration
1967
+ * @returns The final scan result
1968
+ * @throws Error if scan fails or times out
1969
+ *
1970
+ * @example
1971
+ * ```ts
1972
+ * const result = await client.validation.waitForScan('batch-id', {
1973
+ * pollInterval: 5000, // 5 seconds
1974
+ * timeout: 300000 // 5 minutes
1975
+ * });
1976
+ * console.log('Scan complete:', result.data.issuesFound, 'issues found');
1977
+ * ```
1978
+ */
1979
+ public async waitForScan(
1980
+ batchId: string,
1981
+ options?: WaitForScanOptions
1982
+ ): Promise<ApiResponse<BatchScanResult>> {
1983
+ const pollInterval = options?.pollInterval ?? 5000;
1984
+ const timeout = options?.timeout ?? 300000;
1985
+ const startTime = Date.now();
1986
+
1987
+ while (true) {
1988
+ const result = await this.getScanStatus(batchId);
1989
+ const status = result.data.status;
1990
+
1991
+ if (status === 'completed') {
1992
+ return result;
1993
+ }
1994
+
1995
+ if (status === 'failed') {
1996
+ throw new Error(`Scan failed: ${result.data.error || 'Unknown error'}`);
1997
+ }
1998
+
1999
+ if (Date.now() - startTime > timeout) {
2000
+ throw new Error(`Scan timed out after ${timeout}ms`);
2001
+ }
2002
+
2003
+ await new Promise(resolve => setTimeout(resolve, pollInterval));
2004
+ }
2005
+ }
2006
+
2007
+ /**
2008
+ * List validation suggestions with optional filters.
2009
+ *
2010
+ * @param options - Filter and pagination options
2011
+ * @returns List of validation suggestions
2012
+ *
2013
+ * @example
2014
+ * ```ts
2015
+ * // List all pending suggestions
2016
+ * const pending = await client.validation.listSuggestions({ status: 'pending' });
2017
+ *
2018
+ * // List high-confidence typo suggestions
2019
+ * const typos = await client.validation.listSuggestions({
2020
+ * issueType: 'typo',
2021
+ * minConfidence: 0.9
2022
+ * });
2023
+ * ```
2024
+ */
2025
+ public listSuggestions(
2026
+ options?: ListValidationSuggestionsOptions
2027
+ ): Promise<ApiResponse<ValidationSuggestion[]>> {
2028
+ const path = getValidationSuggestionsApiPath(this.workspaceId);
2029
+ return this.requestFn<ValidationSuggestion[]>('GET', path, null, options);
2030
+ }
2031
+
2032
+ /**
2033
+ * Get a single validation suggestion by ID.
2034
+ *
2035
+ * @param suggestionId - The suggestion UUID
2036
+ * @returns The suggestion details
2037
+ */
2038
+ public getSuggestion(suggestionId: string): Promise<ApiResponse<ValidationSuggestion>> {
2039
+ const path = getValidationSuggestionsApiPath(this.workspaceId, suggestionId);
2040
+ return this.requestFn<ValidationSuggestion>('GET', path);
2041
+ }
2042
+
2043
+ /**
2044
+ * Get all suggestions for a specific record.
2045
+ *
2046
+ * @param recordId - The record UUID
2047
+ * @param status - Optional status filter
2048
+ * @returns List of suggestions for the record
2049
+ */
2050
+ public getRecordSuggestions(
2051
+ recordId: string,
2052
+ status?: ValidationSuggestionStatus
2053
+ ): Promise<ApiResponse<ValidationSuggestion[]>> {
2054
+ const path = getValidationRecordSuggestionsApiPath(this.workspaceId, recordId);
2055
+ const params = status ? { status } : undefined;
2056
+ return this.requestFn<ValidationSuggestion[]>('GET', path, null, params);
2057
+ }
2058
+
2059
+ /**
2060
+ * Accept a validation suggestion and apply the fix to the record.
2061
+ *
2062
+ * @param suggestionId - The suggestion UUID
2063
+ * @returns Result with updated suggestion and record status
2064
+ *
2065
+ * @example
2066
+ * ```ts
2067
+ * const result = await client.validation.accept('suggestion-id');
2068
+ * if (result.data.recordUpdated) {
2069
+ * console.log('Fix applied successfully');
2070
+ * }
2071
+ * ```
2072
+ */
2073
+ public accept(suggestionId: string): Promise<ApiResponse<AcceptSuggestionResult>> {
2074
+ const path = getValidationSuggestionAcceptApiPath(this.workspaceId, suggestionId);
2075
+ return this.requestFn<AcceptSuggestionResult>('POST', path);
2076
+ }
2077
+
2078
+ /**
2079
+ * Reject a validation suggestion.
2080
+ *
2081
+ * @param suggestionId - The suggestion UUID
2082
+ * @returns The updated suggestion
2083
+ */
2084
+ public reject(suggestionId: string): Promise<ApiResponse<ValidationSuggestion>> {
2085
+ const path = getValidationSuggestionRejectApiPath(this.workspaceId, suggestionId);
2086
+ return this.requestFn<ValidationSuggestion>('POST', path);
2087
+ }
2088
+
2089
+ /**
2090
+ * Bulk accept multiple suggestions.
2091
+ *
2092
+ * @param ids - Array of suggestion IDs to accept (max 100)
2093
+ * @returns Result with count and any errors
2094
+ *
2095
+ * @example
2096
+ * ```ts
2097
+ * const result = await client.validation.bulkAccept(['id1', 'id2', 'id3']);
2098
+ * console.log('Accepted:', result.data.count);
2099
+ * ```
2100
+ */
2101
+ public bulkAccept(ids: string[]): Promise<ApiResponse<BulkOperationResult>> {
2102
+ const path = getValidationBulkAcceptApiPath(this.workspaceId);
2103
+ return this.requestFn<BulkOperationResult>('POST', path, { ids });
2104
+ }
2105
+
2106
+ /**
2107
+ * Bulk reject multiple suggestions.
2108
+ *
2109
+ * @param ids - Array of suggestion IDs to reject (max 100)
2110
+ * @returns Result with count and any errors
2111
+ */
2112
+ public bulkReject(ids: string[]): Promise<ApiResponse<BulkOperationResult>> {
2113
+ const path = getValidationBulkRejectApiPath(this.workspaceId);
2114
+ return this.requestFn<BulkOperationResult>('POST', path, { ids });
2115
+ }
2116
+
2117
+ /**
2118
+ * Get validation summary statistics.
2119
+ *
2120
+ * @param structureId - Optional structure ID to filter summary
2121
+ * @returns Summary of suggestions by status and type
2122
+ *
2123
+ * @example
2124
+ * ```ts
2125
+ * const summary = await client.validation.getSummary();
2126
+ * console.log('Pending:', summary.data.pending);
2127
+ * console.log('By type:', summary.data.byIssueType);
2128
+ * ```
2129
+ */
2130
+ public getSummary(structureId?: string): Promise<ApiResponse<ValidationSummary>> {
2131
+ const path = getValidationSummaryApiPath(this.workspaceId);
2132
+ const params = structureId ? { structureId } : undefined;
2133
+ return this.requestFn<ValidationSummary>('GET', path, null, params);
2134
+ }
2135
+
2136
+ /**
2137
+ * Get the count of pending suggestions for a structure.
2138
+ *
2139
+ * @param structureId - The structure UUID
2140
+ * @returns Object with pending count
2141
+ */
2142
+ public getPendingCount(structureId: string): Promise<ApiResponse<{ structureId: string; pendingCount: number }>> {
2143
+ const path = getValidationPendingCountApiPath(this.workspaceId, structureId);
2144
+ return this.requestFn<{ structureId: string; pendingCount: number }>('GET', path);
2145
+ }
2146
+ }
2147
+
1085
2148
  /**
1086
2149
  * Main Centrali SDK client.
1087
2150
  */
@@ -1092,6 +2155,8 @@ export class CentraliSDK {
1092
2155
  private _realtime: RealtimeManager | null = null;
1093
2156
  private _triggers: TriggersManager | null = null;
1094
2157
  private _smartQueries: SmartQueriesManager | null = null;
2158
+ private _anomalyInsights: AnomalyInsightsManager | null = null;
2159
+ private _validation: ValidationManager | null = null;
1095
2160
 
1096
2161
  constructor(options: CentraliSDKOptions) {
1097
2162
  this.options = options;
@@ -1235,6 +2300,74 @@ export class CentraliSDK {
1235
2300
  return this._smartQueries;
1236
2301
  }
1237
2302
 
2303
+ /**
2304
+ * Anomaly Insights namespace for querying and managing AI-generated insights.
2305
+ *
2306
+ * Usage:
2307
+ * ```ts
2308
+ * // List all active critical insights
2309
+ * const insights = await client.anomalyInsights.list({
2310
+ * status: 'active',
2311
+ * severity: 'critical'
2312
+ * });
2313
+ *
2314
+ * // Get insights for a specific structure
2315
+ * const orderInsights = await client.anomalyInsights.listByStructure('orders');
2316
+ *
2317
+ * // Get insight summary
2318
+ * const summary = await client.anomalyInsights.getSummary();
2319
+ * console.log('Critical:', summary.data.bySeverity.critical);
2320
+ *
2321
+ * // Acknowledge an insight
2322
+ * await client.anomalyInsights.acknowledge('insight-id');
2323
+ *
2324
+ * // Dismiss an insight
2325
+ * await client.anomalyInsights.dismiss('insight-id');
2326
+ * ```
2327
+ */
2328
+ public get anomalyInsights(): AnomalyInsightsManager {
2329
+ if (!this._anomalyInsights) {
2330
+ this._anomalyInsights = new AnomalyInsightsManager(
2331
+ this.options.workspaceId,
2332
+ this.request.bind(this)
2333
+ );
2334
+ }
2335
+ return this._anomalyInsights;
2336
+ }
2337
+
2338
+ /**
2339
+ * Validation namespace for AI-powered data quality validation.
2340
+ *
2341
+ * Features:
2342
+ * - Trigger batch validation scans on structures
2343
+ * - List and manage validation suggestions (typos, format issues, duplicates)
2344
+ * - Accept or reject suggestions to fix data
2345
+ *
2346
+ * Usage:
2347
+ * ```ts
2348
+ * // Trigger a batch scan
2349
+ * const batch = await client.validation.triggerScan('orders');
2350
+ *
2351
+ * // Wait for completion
2352
+ * const result = await client.validation.waitForScan(batch.data.batchId);
2353
+ *
2354
+ * // List pending suggestions
2355
+ * const suggestions = await client.validation.listSuggestions({ status: 'pending' });
2356
+ *
2357
+ * // Accept a suggestion (applies the fix)
2358
+ * await client.validation.accept('suggestion-id');
2359
+ * ```
2360
+ */
2361
+ public get validation(): ValidationManager {
2362
+ if (!this._validation) {
2363
+ this._validation = new ValidationManager(
2364
+ this.options.workspaceId,
2365
+ this.request.bind(this)
2366
+ );
2367
+ }
2368
+ return this._validation;
2369
+ }
2370
+
1238
2371
  /**
1239
2372
  * Manually set or update the bearer token for subsequent requests.
1240
2373
  */