snow-flow 3.0.10 → 3.0.13

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.
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+ /**
3
+ * ServiceNow Eventual Consistency Handler
4
+ *
5
+ * ServiceNow uses a distributed database architecture with eventual consistency:
6
+ * - Write operations go to primary database (immediate)
7
+ * - Read operations may use read replicas (1-3 second lag)
8
+ * - This causes race conditions in deployment verification
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.appConsistency = exports.flowConsistency = exports.widgetConsistency = exports.CONSISTENCY_CONFIGS = exports.ServiceNowEventualConsistency = void 0;
12
+ const logger_js_1 = require("./logger.js");
13
+ class ServiceNowEventualConsistency {
14
+ constructor(loggerName = 'EventualConsistency') {
15
+ this.logger = new logger_js_1.Logger(loggerName);
16
+ }
17
+ /**
18
+ * Retry a ServiceNow operation with exponential backoff
19
+ * Designed specifically for post-deployment verification
20
+ */
21
+ async retryWithBackoff(operation, config = {}) {
22
+ const { maxRetries = 5, baseDelay = 1000, maxDelay = 8000, backoffMultiplier = 1.5 } = config;
23
+ let lastError;
24
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
25
+ try {
26
+ if (attempt > 0) {
27
+ const delay = Math.min(baseDelay * Math.pow(backoffMultiplier, attempt), maxDelay);
28
+ this.logger.info(`⏳ Retry attempt ${attempt + 1}/${maxRetries} (waiting ${delay}ms for consistency)`);
29
+ await this.sleep(delay);
30
+ }
31
+ const result = await operation();
32
+ if (result) {
33
+ this.logger.info(`✅ Operation succeeded on attempt ${attempt + 1}`);
34
+ return { result, success: true, attempts: attempt + 1 };
35
+ }
36
+ }
37
+ catch (error) {
38
+ lastError = error;
39
+ if (this.isPermanentError(error)) {
40
+ this.logger.error(`❌ Permanent error detected:`, error);
41
+ return { result: null, success: false, attempts: attempt + 1 };
42
+ }
43
+ if (attempt === 0) {
44
+ this.logger.info(`⏳ ${this.getErrorDescription(error)} - typical ServiceNow consistency issue`);
45
+ }
46
+ else {
47
+ this.logger.info(`⏳ Still getting ${error.status || 'error'}, retrying...`);
48
+ }
49
+ }
50
+ }
51
+ this.logger.warn(`⚠️ Operation failed after ${maxRetries} attempts`);
52
+ this.logger.warn(`⚠️ Last error: ${lastError?.message || 'Unknown'}`);
53
+ return { result: null, success: false, attempts: maxRetries };
54
+ }
55
+ /**
56
+ * Verify a ServiceNow record exists with retry logic
57
+ */
58
+ async verifyRecordExists(client, table, sys_id, config = {}) {
59
+ this.logger.info(`🔍 Verifying ${table} record ${sys_id} (handling eventual consistency)`);
60
+ const operation = async () => {
61
+ const response = await client.getRecord(table, sys_id);
62
+ return response && response.sys_id === sys_id ? response : null;
63
+ };
64
+ const { result, success, attempts } = await this.retryWithBackoff(operation, config);
65
+ if (!success) {
66
+ const isLikelyTimingIssue = this.assessIfTimingIssue(attempts, config.maxRetries);
67
+ if (isLikelyTimingIssue) {
68
+ this.logger.warn(`⚠️ This appears to be a ServiceNow consistency issue, not a deployment failure`);
69
+ this.logger.warn(`⚠️ Check directly: /${table}.do?sys_id=${sys_id}`);
70
+ }
71
+ return {
72
+ success: false,
73
+ attempts,
74
+ isLikelyTimingIssue
75
+ };
76
+ }
77
+ return {
78
+ success: true,
79
+ attempts,
80
+ isLikelyTimingIssue: false
81
+ };
82
+ }
83
+ /**
84
+ * Verify multiple records exist (batch verification)
85
+ */
86
+ async verifyMultipleRecords(client, verifications, config = {}) {
87
+ const results = [];
88
+ for (const verification of verifications) {
89
+ const result = await this.verifyRecordExists(client, verification.table, verification.sys_id, config);
90
+ results.push({
91
+ ...result,
92
+ table: verification.table,
93
+ sys_id: verification.sys_id,
94
+ name: verification.name
95
+ });
96
+ // Small delay between verifications to avoid rate limiting
97
+ if (verifications.length > 1) {
98
+ await this.sleep(200);
99
+ }
100
+ }
101
+ return results;
102
+ }
103
+ /**
104
+ * Execute operation with eventual consistency retry
105
+ * Generic wrapper for any ServiceNow operation that might fail due to timing
106
+ */
107
+ async executeWithRetry(operationName, operation, validator, config = {}) {
108
+ this.logger.info(`🚀 Executing ${operationName} with consistency handling`);
109
+ const { result, success, attempts } = await this.retryWithBackoff(async () => {
110
+ const opResult = await operation();
111
+ return validator(opResult) ? opResult : null;
112
+ }, config);
113
+ return {
114
+ result,
115
+ success,
116
+ metadata: {
117
+ operationName,
118
+ attempts,
119
+ isLikelyTimingIssue: !success && this.assessIfTimingIssue(attempts, config.maxRetries)
120
+ }
121
+ };
122
+ }
123
+ /**
124
+ * Sleep utility
125
+ */
126
+ sleep(ms) {
127
+ return new Promise(resolve => setTimeout(resolve, ms));
128
+ }
129
+ /**
130
+ * Determine if an error indicates a permanent failure vs timing issue
131
+ */
132
+ isPermanentError(error) {
133
+ // Permanent errors that shouldn't be retried
134
+ if (error.status === 401)
135
+ return true; // Authentication
136
+ if (error.status === 400 && !error.message?.includes('null'))
137
+ return true; // Bad request
138
+ if (error.message?.includes('table does not exist'))
139
+ return true; // Invalid table
140
+ if (error.message?.includes('permission denied') && error.status !== 403)
141
+ return true; // Real permission issues
142
+ return false;
143
+ }
144
+ /**
145
+ * Get user-friendly error description
146
+ */
147
+ getErrorDescription(error) {
148
+ if (error.status === 403)
149
+ return 'Access temporarily denied (403)';
150
+ if (error.status === 404)
151
+ return 'Record not found (404)';
152
+ if (error.message?.includes('null'))
153
+ return 'Null response received';
154
+ return `Error ${error.status || 'unknown'}`;
155
+ }
156
+ /**
157
+ * Assess if failure is likely due to timing issues
158
+ */
159
+ assessIfTimingIssue(attempts, maxRetries = 5) {
160
+ // If we exhausted all retries and got timing-related errors, it's likely a timing issue
161
+ return attempts >= maxRetries;
162
+ }
163
+ /**
164
+ * Create a pre-configured instance for widget deployments
165
+ */
166
+ static createForWidgets() {
167
+ return new ServiceNowEventualConsistency('WidgetConsistency');
168
+ }
169
+ /**
170
+ * Create a pre-configured instance for flow deployments
171
+ */
172
+ static createForFlows() {
173
+ return new ServiceNowEventualConsistency('FlowConsistency');
174
+ }
175
+ /**
176
+ * Create a pre-configured instance for application deployments
177
+ */
178
+ static createForApplications() {
179
+ return new ServiceNowEventualConsistency('AppConsistency');
180
+ }
181
+ }
182
+ exports.ServiceNowEventualConsistency = ServiceNowEventualConsistency;
183
+ /**
184
+ * Default configuration for different deployment types
185
+ */
186
+ exports.CONSISTENCY_CONFIGS = {
187
+ // Fast retry for simple records
188
+ WIDGET: {
189
+ maxRetries: 5,
190
+ baseDelay: 800,
191
+ maxDelay: 6000,
192
+ backoffMultiplier: 1.4
193
+ },
194
+ // Medium retry for complex records
195
+ FLOW: {
196
+ maxRetries: 6,
197
+ baseDelay: 1200,
198
+ maxDelay: 8000,
199
+ backoffMultiplier: 1.5
200
+ },
201
+ // Longer retry for applications with dependencies
202
+ APPLICATION: {
203
+ maxRetries: 8,
204
+ baseDelay: 1500,
205
+ maxDelay: 12000,
206
+ backoffMultiplier: 1.6
207
+ },
208
+ // Quick check for batch operations
209
+ BATCH: {
210
+ maxRetries: 3,
211
+ baseDelay: 500,
212
+ maxDelay: 3000,
213
+ backoffMultiplier: 1.3
214
+ }
215
+ };
216
+ // Export singleton instances
217
+ exports.widgetConsistency = ServiceNowEventualConsistency.createForWidgets();
218
+ exports.flowConsistency = ServiceNowEventualConsistency.createForFlows();
219
+ exports.appConsistency = ServiceNowEventualConsistency.createForApplications();
220
+ //# sourceMappingURL=servicenow-eventual-consistency.js.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "snow-flow",
3
- "version": "3.0.10",
4
- "description": "Snow-Flow v3.0.10: REPORTING & DASHBOARD FIXES! Complete overhaul of reporting and dashboard MCPs. Fixed dashboard visibility in ServiceNow (now uses pa_dashboards, sys_portal_page with intelligent fallback). Reports now properly fetch data with correct field configuration. KPIs and Performance Analytics work correctly. All dashboard and report creation tools now functional with proper ServiceNow API integration. Plus all previous features: Codespaces support, Claude Code integration, 100+ MCP tools.",
3
+ "version": "3.0.13",
4
+ "description": "Snow-Flow v3.0.13: ZERO MOCK DATA GUARANTEE! 🔥 All reporting, dashboards, and analytics tools now use 100% REAL ServiceNow data with anti-mock validation. Advanced AI table discovery, race condition fixes, and comprehensive real-data enforcement. NO demo/sample/test data ever used - only live data from your actual ServiceNow instance. Plus intelligent reporting, deployment fixes, and 100+ MCP tools.",
5
5
  "main": "dist/index.js",
6
6
  "type": "commonjs",
7
7
  "bin": {
@@ -358,7 +358,8 @@
358
358
  "mcpCapabilities": {
359
359
  "realApiIntegration": true,
360
360
  "noMockData": true,
361
- "mockDataNote": "NO MOCK DATA - All ML operations require real ServiceNow PA/PI licenses",
361
+ "mockDataNote": "🔥 ZERO MOCK DATA GUARANTEE - All reports, dashboards, and analytics use 100% REAL ServiceNow data from your actual instance. NO demo/sample/test data ever used.",
362
+ "reportingDataPolicy": "ALL LIVE DATA - Every report, dashboard, chart, and KPI populated exclusively with real records from your ServiceNow tables",
362
363
  "productionReady": true,
363
364
  "batchOptimization": true,
364
365
  "intelligentAnalysis": true,