@resolveio/server-lib 22.2.4 → 22.2.7

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 (45) hide show
  1. package/collections/app-setting.collection.d.ts +3 -0
  2. package/collections/app-setting.collection.js +103 -0
  3. package/collections/app-setting.collection.js.map +1 -0
  4. package/managers/customer-notification-content.manager.d.ts +55 -0
  5. package/managers/customer-notification-content.manager.js +158 -0
  6. package/managers/customer-notification-content.manager.js.map +1 -0
  7. package/managers/diagnostic-manager-bootstrap.d.ts +9 -0
  8. package/managers/diagnostic-manager-bootstrap.js +260 -0
  9. package/managers/diagnostic-manager-bootstrap.js.map +1 -0
  10. package/managers/error-auto-fix.manager.d.ts +143 -0
  11. package/managers/error-auto-fix.manager.js +2934 -0
  12. package/managers/error-auto-fix.manager.js.map +1 -0
  13. package/managers/method.manager.js +2 -0
  14. package/managers/method.manager.js.map +1 -1
  15. package/managers/slow-query-verifier.manager.d.ts +114 -0
  16. package/managers/slow-query-verifier.manager.js +3358 -0
  17. package/managers/slow-query-verifier.manager.js.map +1 -0
  18. package/managers/slow-query.manager.d.ts +28 -0
  19. package/managers/slow-query.manager.js +468 -0
  20. package/managers/slow-query.manager.js.map +1 -0
  21. package/managers/subscription.manager.js +2 -0
  22. package/managers/subscription.manager.js.map +1 -1
  23. package/methods/app-settings.d.ts +2 -0
  24. package/methods/app-settings.js +169 -0
  25. package/methods/app-settings.js.map +1 -0
  26. package/methods/customer-notifications.js +77 -9
  27. package/methods/customer-notifications.js.map +1 -1
  28. package/methods.ts +3 -0
  29. package/models/app-setting.model.d.ts +16 -0
  30. package/models/app-setting.model.js +4 -0
  31. package/models/app-setting.model.js.map +1 -0
  32. package/package.json +3 -1
  33. package/public_api.d.ts +9 -0
  34. package/public_api.js +9 -0
  35. package/public_api.js.map +1 -1
  36. package/publications/app-settings.d.ts +2 -0
  37. package/publications/app-settings.js +28 -0
  38. package/publications/app-settings.js.map +1 -0
  39. package/publications.ts +6 -0
  40. package/types/error-report.d.ts +25 -0
  41. package/types/error-report.js +4 -0
  42. package/types/error-report.js.map +1 -0
  43. package/types/slow-query-report.d.ts +27 -0
  44. package/types/slow-query-report.js +6 -0
  45. package/types/slow-query-report.js.map +1 -0
@@ -0,0 +1,3358 @@
1
+ "use strict";
2
+ var __extends = (this && this.__extends) || (function () {
3
+ var extendStatics = function (d, b) {
4
+ extendStatics = Object.setPrototypeOf ||
5
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
+ function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
7
+ return extendStatics(d, b);
8
+ };
9
+ return function (d, b) {
10
+ if (typeof b !== "function" && b !== null)
11
+ throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
12
+ extendStatics(d, b);
13
+ function __() { this.constructor = d; }
14
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
15
+ };
16
+ })();
17
+ var __assign = (this && this.__assign) || function () {
18
+ __assign = Object.assign || function(t) {
19
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
20
+ s = arguments[i];
21
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
22
+ t[p] = s[p];
23
+ }
24
+ return t;
25
+ };
26
+ return __assign.apply(this, arguments);
27
+ };
28
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
29
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
30
+ return new (P || (P = Promise))(function (resolve, reject) {
31
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
32
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
33
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
34
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
35
+ });
36
+ };
37
+ var __generator = (this && this.__generator) || function (thisArg, body) {
38
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
39
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
40
+ function verb(n) { return function (v) { return step([n, v]); }; }
41
+ function step(op) {
42
+ if (f) throw new TypeError("Generator is already executing.");
43
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
44
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
45
+ if (y = 0, t) op = [op[0] & 2, t.value];
46
+ switch (op[0]) {
47
+ case 0: case 1: t = op; break;
48
+ case 4: _.label++; return { value: op[1], done: false };
49
+ case 5: _.label++; y = op[1]; op = [0]; continue;
50
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
51
+ default:
52
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
53
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
54
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
55
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
56
+ if (t[2]) _.ops.pop();
57
+ _.trys.pop(); continue;
58
+ }
59
+ op = body.call(thisArg, _);
60
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
61
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
62
+ }
63
+ };
64
+ var __asyncValues = (this && this.__asyncValues) || function (o) {
65
+ if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
66
+ var m = o[Symbol.asyncIterator], i;
67
+ return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
68
+ function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
69
+ function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
70
+ };
71
+ var __values = (this && this.__values) || function(o) {
72
+ var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
73
+ if (m) return m.call(o);
74
+ if (o && typeof o.length === "number") return {
75
+ next: function () {
76
+ if (o && i >= o.length) o = void 0;
77
+ return { value: o && o[i++], done: !o };
78
+ }
79
+ };
80
+ throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
81
+ };
82
+ var __read = (this && this.__read) || function (o, n) {
83
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
84
+ if (!m) return o;
85
+ var i = m.call(o), r, ar = [], e;
86
+ try {
87
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
88
+ }
89
+ catch (error) { e = { error: error }; }
90
+ finally {
91
+ try {
92
+ if (r && !r.done && (m = i["return"])) m.call(i);
93
+ }
94
+ finally { if (e) throw e.error; }
95
+ }
96
+ return ar;
97
+ };
98
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
99
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
100
+ if (ar || !(i in from)) {
101
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
102
+ ar[i] = from[i];
103
+ }
104
+ }
105
+ return to.concat(ar || Array.prototype.slice.call(from));
106
+ };
107
+ Object.defineProperty(exports, "__esModule", { value: true });
108
+ exports.SlowQueryVerifier = void 0;
109
+ exports.registerSlowQueryVerifierDependencies = registerSlowQueryVerifierDependencies;
110
+ exports.ensureSlowQueryVerifier = ensureSlowQueryVerifier;
111
+ var crypto_1 = require("crypto");
112
+ var resolveio_server_app_1 = require("../resolveio-server-app");
113
+ var common_1 = require("../util/common");
114
+ var mongodb_1 = require("mongodb");
115
+ var user_collection_1 = require("../collections/user.collection");
116
+ var customer_notification_content_manager_1 = require("./customer-notification-content.manager");
117
+ var OPTIONAL_COLLECTION = {
118
+ findOne: function () { return Promise.resolve(null); },
119
+ find: function () { return Promise.resolve([]); }
120
+ };
121
+ var AICoderApps = OPTIONAL_COLLECTION;
122
+ var AIDashboardJobs = OPTIONAL_COLLECTION;
123
+ var ClientDBs = OPTIONAL_COLLECTION;
124
+ var Clients = OPTIONAL_COLLECTION;
125
+ var SlowQueryLogs = null;
126
+ var DEFAULT_CHECK_AICODER_TOKEN_ELIGIBILITY = function () {
127
+ return Promise.resolve({
128
+ eligible: true
129
+ });
130
+ };
131
+ var checkAICoderTokenEligibility = DEFAULT_CHECK_AICODER_TOKEN_ELIGIBILITY;
132
+ var configuredSlowQueryVerifierDependencies = null;
133
+ function resolveSlowQueryVerifierDependencies(overrides) {
134
+ var resolved = __assign(__assign({}, (configuredSlowQueryVerifierDependencies || {})), (overrides || {}));
135
+ if (!resolved.SlowQueryLogs) {
136
+ throw new Error('SlowQueryVerifier dependencies are not configured.');
137
+ }
138
+ return resolved;
139
+ }
140
+ function applySlowQueryVerifierDependencies(dependencies) {
141
+ configuredSlowQueryVerifierDependencies = dependencies;
142
+ ClientDBs = dependencies.ClientDBs || OPTIONAL_COLLECTION;
143
+ Clients = dependencies.Clients || OPTIONAL_COLLECTION;
144
+ SlowQueryLogs = dependencies.SlowQueryLogs;
145
+ AICoderApps = dependencies.AICoderApps || OPTIONAL_COLLECTION;
146
+ AIDashboardJobs = dependencies.AIDashboardJobs || OPTIONAL_COLLECTION;
147
+ checkAICoderTokenEligibility = dependencies.checkAICoderTokenEligibility || DEFAULT_CHECK_AICODER_TOKEN_ELIGIBILITY;
148
+ }
149
+ function registerSlowQueryVerifierDependencies(dependencies) {
150
+ applySlowQueryVerifierDependencies(dependencies);
151
+ ensureSlowQueryVerifier();
152
+ }
153
+ var VERIFICATION_CHECK_INTERVAL_MS = 60 * 1000;
154
+ var VERIFICATION_INTERVAL_MS = 5 * 60 * 1000;
155
+ var VERIFICATION_ATTEMPTS = 3;
156
+ var VERIFICATION_THRESHOLD_MS = 2000;
157
+ var AUTO_OPTIMIZE_DEFAULT_IMPROVEMENT_RATIO = 0.7;
158
+ var AUTO_OPTIMIZE_DEFAULT_RETURNED_DOC_TOLERANCE = 0.15;
159
+ var AUTO_OPTIMIZE_DEFAULT_MAX_ATTEMPTS_PER_QUERY = 3;
160
+ var AUTO_OPTIMIZE_DEFAULT_COOLDOWN_MINUTES = 120;
161
+ var AUTO_OPTIMIZE_DEFAULT_MAX_ATTEMPTS_PER_FINGERPRINT = 4;
162
+ var AUTO_OPTIMIZE_DEFAULT_FINGERPRINT_WINDOW_HOURS = 24;
163
+ var AUTO_OPTIMIZE_DEFAULT_OUTPUT_COMPARE_MAX_DOCS = 10000;
164
+ var DEFAULT_ERROR_ALERT_EMAIL = 'dev@resolveio.com';
165
+ var MAX_LOCAL_NOTIFICATION_USERS = 5000;
166
+ function ensureSlowQueryVerifier(serverConfig) {
167
+ var existing = resolveio_server_app_1.ResolveIOServer['SlowQueryVerifier'];
168
+ if (existing) {
169
+ return existing;
170
+ }
171
+ if (!configuredSlowQueryVerifierDependencies) {
172
+ return null;
173
+ }
174
+ var resolvedServerConfig = serverConfig || resolveio_server_app_1.ResolveIOServer.getServerConfig();
175
+ if (!resolvedServerConfig) {
176
+ return null;
177
+ }
178
+ var verifier = new SlowQueryVerifier(resolvedServerConfig);
179
+ resolveio_server_app_1.ResolveIOServer['SlowQueryVerifier'] = verifier;
180
+ return verifier;
181
+ }
182
+ var SlowQueryVerifierError = /** @class */ (function (_super) {
183
+ __extends(SlowQueryVerifierError, _super);
184
+ function SlowQueryVerifierError(code, message) {
185
+ var _this = _super.call(this, message) || this;
186
+ _this.code = code;
187
+ return _this;
188
+ }
189
+ return SlowQueryVerifierError;
190
+ }(Error));
191
+ var SlowQueryVerifier = /** @class */ (function () {
192
+ function SlowQueryVerifier(serverConfig, dependencies) {
193
+ var _this = this;
194
+ this.autoOptimizeInFlight = new Set();
195
+ var resolvedDependencies = resolveSlowQueryVerifierDependencies(dependencies);
196
+ applySlowQueryVerifierDependencies(resolvedDependencies);
197
+ this.config = SlowQueryVerifier.resolveConfig(serverConfig);
198
+ if (!resolvedDependencies.AICoderApps || !resolvedDependencies.AIDashboardJobs) {
199
+ this.config.autoOptimizeEnabled = false;
200
+ }
201
+ if (this.config.enabled) {
202
+ this._timer = setInterval(function () {
203
+ // eslint-disable-next-line no-restricted-syntax
204
+ _this.poll().catch(function (err) {
205
+ console.error('Slow query verifier poll failed', err);
206
+ });
207
+ }, VERIFICATION_CHECK_INTERVAL_MS);
208
+ // eslint-disable-next-line no-restricted-syntax
209
+ this.poll().catch(function (err) {
210
+ console.error('Slow query verifier failed to start', err);
211
+ });
212
+ }
213
+ }
214
+ SlowQueryVerifier.resolveConfig = function (serverConfig) {
215
+ var slowQueryConfig = (serverConfig && (serverConfig.slowQuery || serverConfig.SLOW_QUERY)) || {};
216
+ var verifierConfig = (slowQueryConfig && (slowQueryConfig.verifier || slowQueryConfig.slowQueryVerifier)) || {};
217
+ var getBoolean = function (envKey, configKey, fallback) {
218
+ if (fallback === void 0) { fallback = true; }
219
+ if (typeof process.env[envKey] !== 'undefined') {
220
+ return process.env[envKey] === 'true';
221
+ }
222
+ if (typeof verifierConfig[configKey] !== 'undefined') {
223
+ return !!verifierConfig[configKey];
224
+ }
225
+ return fallback;
226
+ };
227
+ var getNumber = function (envKey, configKey, fallback) {
228
+ if (typeof process.env[envKey] !== 'undefined') {
229
+ var parsedEnv = Number(process.env[envKey]);
230
+ if (Number.isFinite(parsedEnv)) {
231
+ return parsedEnv;
232
+ }
233
+ }
234
+ if (typeof verifierConfig[configKey] !== 'undefined') {
235
+ var parsedConfig = Number(verifierConfig[configKey]);
236
+ if (Number.isFinite(parsedConfig)) {
237
+ return parsedConfig;
238
+ }
239
+ }
240
+ return fallback;
241
+ };
242
+ var parseEmails = function (value) {
243
+ if (Array.isArray(value)) {
244
+ return value.map(function (item) { return "".concat(item || '').trim().toLowerCase(); }).filter(Boolean);
245
+ }
246
+ if (typeof value === 'string') {
247
+ return value.split(',').map(function (item) { return item.trim().toLowerCase(); }).filter(Boolean);
248
+ }
249
+ return [];
250
+ };
251
+ var clampRatio = function (value, fallback) {
252
+ if (!Number.isFinite(value)) {
253
+ return fallback;
254
+ }
255
+ if (value <= 0 || value >= 1) {
256
+ return fallback;
257
+ }
258
+ return value;
259
+ };
260
+ var normalizePositiveInt = function (value, fallback) {
261
+ if (!Number.isFinite(value) || value <= 0) {
262
+ return fallback;
263
+ }
264
+ return Math.floor(value);
265
+ };
266
+ var normalizeNonNegativeInt = function (value, fallback) {
267
+ if (fallback === void 0) { fallback = 0; }
268
+ if (!Number.isFinite(value) || value < 0) {
269
+ return fallback;
270
+ }
271
+ return Math.floor(value);
272
+ };
273
+ var escalationEmails = parseEmails(process.env.SLOW_QUERY_ESCALATION_EMAILS
274
+ || verifierConfig.escalationEmails
275
+ || slowQueryConfig.escalationEmails
276
+ || slowQueryConfig.notifyEmails);
277
+ return {
278
+ enabled: getBoolean('SLOW_QUERY_VERIFIER_ENABLED', 'enabled', true),
279
+ fallbackToMainDB: getBoolean('SLOW_QUERY_VERIFIER_FALLBACK_MAIN_DB', 'fallbackToMainDB', true),
280
+ debugLogging: getBoolean('SLOW_QUERY_VERIFIER_DEBUG_LOGS', 'debugLogging', false),
281
+ configSource: process.env.SLOW_QUERY_VERIFIER_ENABLED ? 'environment' : (Object.keys(verifierConfig).length ? 'serverConfig' : 'defaults'),
282
+ autoOptimizeEnabled: getBoolean('SLOW_QUERY_AUTO_OPTIMIZE_ENABLED', 'autoOptimizeEnabled', true),
283
+ autoOptimizeWaitTimeoutMs: getNumber('SLOW_QUERY_AUTO_OPTIMIZE_WAIT_TIMEOUT_MS', 'autoOptimizeWaitTimeoutMs', 45 * 60 * 1000),
284
+ autoOptimizeDurationRatioTarget: clampRatio(getNumber('SLOW_QUERY_AUTO_OPTIMIZE_DURATION_RATIO', 'autoOptimizeDurationRatioTarget', AUTO_OPTIMIZE_DEFAULT_IMPROVEMENT_RATIO), AUTO_OPTIMIZE_DEFAULT_IMPROVEMENT_RATIO),
285
+ autoOptimizeDocsRatioTarget: clampRatio(getNumber('SLOW_QUERY_AUTO_OPTIMIZE_DOCS_RATIO', 'autoOptimizeDocsRatioTarget', AUTO_OPTIMIZE_DEFAULT_IMPROVEMENT_RATIO), AUTO_OPTIMIZE_DEFAULT_IMPROVEMENT_RATIO),
286
+ autoOptimizeReturnedDocsTolerance: clampRatio(getNumber('SLOW_QUERY_AUTO_OPTIMIZE_RETURNED_DOCS_TOLERANCE', 'autoOptimizeReturnedDocsTolerance', AUTO_OPTIMIZE_DEFAULT_RETURNED_DOC_TOLERANCE), AUTO_OPTIMIZE_DEFAULT_RETURNED_DOC_TOLERANCE),
287
+ autoOptimizeMaxAttemptsPerQuery: normalizePositiveInt(getNumber('SLOW_QUERY_AUTO_OPTIMIZE_MAX_ATTEMPTS_PER_QUERY', 'autoOptimizeMaxAttemptsPerQuery', AUTO_OPTIMIZE_DEFAULT_MAX_ATTEMPTS_PER_QUERY), AUTO_OPTIMIZE_DEFAULT_MAX_ATTEMPTS_PER_QUERY),
288
+ autoOptimizeCooldownMinutes: normalizeNonNegativeInt(getNumber('SLOW_QUERY_AUTO_OPTIMIZE_COOLDOWN_MINUTES', 'autoOptimizeCooldownMinutes', AUTO_OPTIMIZE_DEFAULT_COOLDOWN_MINUTES), AUTO_OPTIMIZE_DEFAULT_COOLDOWN_MINUTES),
289
+ autoOptimizeMaxAttemptsPerFingerprint: normalizePositiveInt(getNumber('SLOW_QUERY_AUTO_OPTIMIZE_MAX_ATTEMPTS_PER_FINGERPRINT', 'autoOptimizeMaxAttemptsPerFingerprint', AUTO_OPTIMIZE_DEFAULT_MAX_ATTEMPTS_PER_FINGERPRINT), AUTO_OPTIMIZE_DEFAULT_MAX_ATTEMPTS_PER_FINGERPRINT),
290
+ autoOptimizeFingerprintWindowHours: normalizePositiveInt(getNumber('SLOW_QUERY_AUTO_OPTIMIZE_FINGERPRINT_WINDOW_HOURS', 'autoOptimizeFingerprintWindowHours', AUTO_OPTIMIZE_DEFAULT_FINGERPRINT_WINDOW_HOURS), AUTO_OPTIMIZE_DEFAULT_FINGERPRINT_WINDOW_HOURS),
291
+ autoOptimizeRequiredTokens: normalizeNonNegativeInt(getNumber('SLOW_QUERY_AUTO_OPTIMIZE_REQUIRED_TOKENS', 'autoOptimizeRequiredTokens', 0), 0),
292
+ autoOptimizeOutputCompareEnabled: getBoolean('SLOW_QUERY_AUTO_OPTIMIZE_OUTPUT_COMPARE_ENABLED', 'autoOptimizeOutputCompareEnabled', true),
293
+ autoOptimizeOutputCompareMaxDocs: normalizePositiveInt(getNumber('SLOW_QUERY_AUTO_OPTIMIZE_OUTPUT_COMPARE_MAX_DOCS', 'autoOptimizeOutputCompareMaxDocs', AUTO_OPTIMIZE_DEFAULT_OUTPUT_COMPARE_MAX_DOCS), AUTO_OPTIMIZE_DEFAULT_OUTPUT_COMPARE_MAX_DOCS),
294
+ escalationEmails: escalationEmails
295
+ };
296
+ };
297
+ SlowQueryVerifier.prototype.poll = function () {
298
+ return __awaiter(this, void 0, void 0, function () {
299
+ var now, candidates, candidates_1, candidates_1_1, candidate, e_1_1;
300
+ var e_1, _a;
301
+ return __generator(this, function (_b) {
302
+ switch (_b.label) {
303
+ case 0:
304
+ now = new Date();
305
+ return [4 /*yield*/, SlowQueryLogs.find({
306
+ ignored: {
307
+ $ne: true
308
+ },
309
+ verification_status: {
310
+ $in: [null, 'pending']
311
+ },
312
+ $or: [
313
+ {
314
+ verification_next_run_at: {
315
+ $exists: false
316
+ }
317
+ },
318
+ {
319
+ verification_next_run_at: {
320
+ $lte: now
321
+ }
322
+ }
323
+ ]
324
+ }, {
325
+ sort: {
326
+ verification_next_run_at: 1,
327
+ last_seen_at: -1
328
+ },
329
+ limit: 5
330
+ })];
331
+ case 1:
332
+ candidates = _b.sent();
333
+ _b.label = 2;
334
+ case 2:
335
+ _b.trys.push([2, 7, 8, 9]);
336
+ candidates_1 = __values(candidates), candidates_1_1 = candidates_1.next();
337
+ _b.label = 3;
338
+ case 3:
339
+ if (!!candidates_1_1.done) return [3 /*break*/, 6];
340
+ candidate = candidates_1_1.value;
341
+ return [4 /*yield*/, this.processCandidate(candidate)];
342
+ case 4:
343
+ _b.sent();
344
+ _b.label = 5;
345
+ case 5:
346
+ candidates_1_1 = candidates_1.next();
347
+ return [3 /*break*/, 3];
348
+ case 6: return [3 /*break*/, 9];
349
+ case 7:
350
+ e_1_1 = _b.sent();
351
+ e_1 = { error: e_1_1 };
352
+ return [3 /*break*/, 9];
353
+ case 8:
354
+ try {
355
+ if (candidates_1_1 && !candidates_1_1.done && (_a = candidates_1.return)) _a.call(candidates_1);
356
+ }
357
+ finally { if (e_1) throw e_1.error; }
358
+ return [7 /*endfinally*/];
359
+ case 9: return [2 /*return*/];
360
+ }
361
+ });
362
+ });
363
+ };
364
+ SlowQueryVerifier.prototype.processCandidate = function (candidate) {
365
+ return __awaiter(this, void 0, void 0, function () {
366
+ var claimAt, result, err_1;
367
+ return __generator(this, function (_a) {
368
+ switch (_a.label) {
369
+ case 0:
370
+ if (!candidate || !candidate._id) {
371
+ return [2 /*return*/];
372
+ }
373
+ claimAt = new Date(Date.now() + VERIFICATION_INTERVAL_MS);
374
+ return [4 /*yield*/, SlowQueryLogs.updateOne({ _id: candidate._id }, {
375
+ $set: {
376
+ verification_next_run_at: claimAt
377
+ }
378
+ })];
379
+ case 1:
380
+ _a.sent();
381
+ _a.label = 2;
382
+ case 2:
383
+ _a.trys.push([2, 5, , 7]);
384
+ return [4 /*yield*/, this.runExplain(candidate)];
385
+ case 3:
386
+ result = _a.sent();
387
+ return [4 /*yield*/, this.handleExplainResult(candidate, result)];
388
+ case 4:
389
+ _a.sent();
390
+ return [3 /*break*/, 7];
391
+ case 5:
392
+ err_1 = _a.sent();
393
+ return [4 /*yield*/, this.handleExplainError(candidate, err_1)];
394
+ case 6:
395
+ _a.sent();
396
+ return [3 /*break*/, 7];
397
+ case 7: return [2 /*return*/];
398
+ }
399
+ });
400
+ });
401
+ };
402
+ SlowQueryVerifier.prototype.generateExplainForLog = function (logId) {
403
+ return __awaiter(this, void 0, void 0, function () {
404
+ var log, result, err_2;
405
+ return __generator(this, function (_a) {
406
+ switch (_a.label) {
407
+ case 0:
408
+ if (!logId) {
409
+ throw new Error('Slow query log ID is required.');
410
+ }
411
+ return [4 /*yield*/, SlowQueryLogs.findOne({ _id: logId })];
412
+ case 1:
413
+ log = _a.sent();
414
+ if (!log) {
415
+ throw new Error('Slow query log not found.');
416
+ }
417
+ _a.label = 2;
418
+ case 2:
419
+ _a.trys.push([2, 5, , 7]);
420
+ return [4 /*yield*/, this.runExplain(log)];
421
+ case 3:
422
+ result = _a.sent();
423
+ return [4 /*yield*/, this.handleExplainResult(log, result)];
424
+ case 4:
425
+ _a.sent();
426
+ return [3 /*break*/, 7];
427
+ case 5:
428
+ err_2 = _a.sent();
429
+ return [4 /*yield*/, this.handleExplainError(log, err_2)];
430
+ case 6:
431
+ _a.sent();
432
+ throw err_2;
433
+ case 7: return [2 /*return*/];
434
+ }
435
+ });
436
+ });
437
+ };
438
+ SlowQueryVerifier.prototype.runExplain = function (log, overrides) {
439
+ return __awaiter(this, void 0, void 0, function () {
440
+ var collectionName, target, client, db, effectiveLog, pipeline_1, filter, findOptions, aggregateOptions_1, explainResponse, usedVerbosity, explainAggregate, cursor, err_3, code, codeName, message, fallbackErr_1, durationMs_1, cursor, _a, durationMs_2, durationMs, explainPlanRaw, explainStatsRaw, stageSummaries, explainPlan, explainStats;
441
+ var _this = this;
442
+ var _b, _c, _d, _e;
443
+ return __generator(this, function (_f) {
444
+ switch (_f.label) {
445
+ case 0:
446
+ collectionName = log.collection;
447
+ if (!collectionName) {
448
+ throw new Error('Slow query missing collection name.');
449
+ }
450
+ return [4 /*yield*/, this.resolveExplainTarget(log)];
451
+ case 1:
452
+ target = _f.sent();
453
+ _f.label = 2;
454
+ case 2:
455
+ _f.trys.push([2, , 31, 34]);
456
+ if (!(target.type === 'client')) return [3 /*break*/, 4];
457
+ if (!target.uri) {
458
+ throw new SlowQueryVerifierError('client_db_missing_uri', 'Client DB missing uri.');
459
+ }
460
+ return [4 /*yield*/, mongodb_1.MongoClient.connect(target.uri, {
461
+ connectTimeoutMS: 10000,
462
+ serverSelectionTimeoutMS: 10000,
463
+ readPreference: 'secondaryPreferred'
464
+ })];
465
+ case 3:
466
+ client = _f.sent();
467
+ db = client.db(target.dbName);
468
+ return [3 /*break*/, 5];
469
+ case 4:
470
+ db = resolveio_server_app_1.ResolveIOServer.getMainDB();
471
+ _f.label = 5;
472
+ case 5:
473
+ if (!db) {
474
+ throw new SlowQueryVerifierError('main_db_unavailable', 'Main server DB is not available.');
475
+ }
476
+ effectiveLog = SlowQueryVerifier.applyQueryOverrides(log, overrides);
477
+ pipeline_1 = SlowQueryVerifier.extractPipelineFromLog(effectiveLog);
478
+ filter = (_b = effectiveLog.filter) !== null && _b !== void 0 ? _b : {};
479
+ findOptions = SlowQueryVerifier.extractFindOptions(effectiveLog.options);
480
+ aggregateOptions_1 = SlowQueryVerifier.extractAggregateOptions(effectiveLog.options);
481
+ explainResponse = void 0;
482
+ usedVerbosity = 'executionStats';
483
+ explainAggregate = function (verbosity) { return __awaiter(_this, void 0, void 0, function () {
484
+ var err_4;
485
+ return __generator(this, function (_a) {
486
+ switch (_a.label) {
487
+ case 0:
488
+ if (SlowQueryVerifier.pipelineHasWriteStage(pipeline_1)) {
489
+ throw new SlowQueryVerifierError('aggregate_write_stage', 'Aggregate pipeline includes a write stage; verification skipped.');
490
+ }
491
+ _a.label = 1;
492
+ case 1:
493
+ _a.trys.push([1, 3, , 6]);
494
+ return [4 /*yield*/, db.collection(collectionName)
495
+ .aggregate(pipeline_1, __assign(__assign({}, (aggregateOptions_1 || {})), { readPreference: 'secondaryPreferred' }))
496
+ .explain(verbosity)];
497
+ case 2: return [2 /*return*/, _a.sent()];
498
+ case 3:
499
+ err_4 = _a.sent();
500
+ if (!SlowQueryVerifier.isAggregateExplainWriteConcernError(err_4)) return [3 /*break*/, 5];
501
+ return [4 /*yield*/, db.command(SlowQueryVerifier.buildAggregateExplainCommand(collectionName, pipeline_1, aggregateOptions_1, verbosity), { readPreference: 'secondaryPreferred' })];
502
+ case 4: return [2 /*return*/, _a.sent()];
503
+ case 5: throw err_4;
504
+ case 6: return [2 /*return*/];
505
+ }
506
+ });
507
+ }); };
508
+ _f.label = 6;
509
+ case 6:
510
+ _f.trys.push([6, 11, , 28]);
511
+ if (!pipeline_1) return [3 /*break*/, 8];
512
+ return [4 /*yield*/, explainAggregate('executionStats')];
513
+ case 7:
514
+ explainResponse = _f.sent();
515
+ return [3 /*break*/, 10];
516
+ case 8:
517
+ cursor = SlowQueryVerifier.buildFindCursor(db.collection(collectionName), filter, findOptions);
518
+ return [4 /*yield*/, cursor.explain('executionStats')];
519
+ case 9:
520
+ explainResponse = _f.sent();
521
+ _f.label = 10;
522
+ case 10: return [3 /*break*/, 28];
523
+ case 11:
524
+ err_3 = _f.sent();
525
+ code = err_3 === null || err_3 === void 0 ? void 0 : err_3.code;
526
+ codeName = "".concat((err_3 === null || err_3 === void 0 ? void 0 : err_3.codeName) || '').trim();
527
+ message = "".concat((err_3 === null || err_3 === void 0 ? void 0 : err_3.message) || '').toLowerCase();
528
+ if (code === 26 || codeName === 'NamespaceNotFound' || message.includes('ns does not exist')) {
529
+ throw new SlowQueryVerifierError('collection_missing', "Collection '".concat(collectionName, "' not found in ").concat(target.type, " DB."));
530
+ }
531
+ if (!pipeline_1) return [3 /*break*/, 20];
532
+ if (!SlowQueryVerifier.isBsonObjectTooLargeError(err_3)) return [3 /*break*/, 18];
533
+ _f.label = 12;
534
+ case 12:
535
+ _f.trys.push([12, 14, , 17]);
536
+ return [4 /*yield*/, explainAggregate('queryPlanner')];
537
+ case 13:
538
+ explainResponse = _f.sent();
539
+ usedVerbosity = 'queryPlanner';
540
+ return [3 /*break*/, 17];
541
+ case 14:
542
+ fallbackErr_1 = _f.sent();
543
+ if (!SlowQueryVerifier.isBsonObjectTooLargeError(fallbackErr_1)) return [3 /*break*/, 16];
544
+ return [4 /*yield*/, SlowQueryVerifier.measureExecution(db, collectionName, pipeline_1, filter, findOptions, aggregateOptions_1)];
545
+ case 15:
546
+ durationMs_1 = _f.sent();
547
+ if (!SlowQueryVerifier.isValidDuration(durationMs_1)) {
548
+ throw new SlowQueryVerifierError('bson_too_large', 'Explain/query payload too large to verify.');
549
+ }
550
+ return [2 /*return*/, {
551
+ durationMs: durationMs_1,
552
+ explainPlan: {},
553
+ explainStats: {},
554
+ stageSummaries: []
555
+ }];
556
+ case 16: throw fallbackErr_1;
557
+ case 17: return [3 /*break*/, 19];
558
+ case 18: throw err_3;
559
+ case 19: return [3 /*break*/, 27];
560
+ case 20:
561
+ if (!SlowQueryVerifier.isBsonObjectTooLargeError(err_3)) return [3 /*break*/, 26];
562
+ _f.label = 21;
563
+ case 21:
564
+ _f.trys.push([21, 23, , 25]);
565
+ cursor = SlowQueryVerifier.buildFindCursor(db.collection(collectionName), filter, findOptions);
566
+ return [4 /*yield*/, cursor.explain('queryPlanner')];
567
+ case 22:
568
+ explainResponse = _f.sent();
569
+ usedVerbosity = 'queryPlanner';
570
+ return [3 /*break*/, 25];
571
+ case 23:
572
+ _a = _f.sent();
573
+ return [4 /*yield*/, SlowQueryVerifier.measureExecution(db, collectionName, pipeline_1, filter, findOptions, aggregateOptions_1)];
574
+ case 24:
575
+ durationMs_2 = _f.sent();
576
+ if (!SlowQueryVerifier.isValidDuration(durationMs_2)) {
577
+ throw new SlowQueryVerifierError('bson_too_large', 'Explain/query payload too large to verify.');
578
+ }
579
+ return [2 /*return*/, {
580
+ durationMs: durationMs_2,
581
+ explainPlan: {},
582
+ explainStats: {},
583
+ stageSummaries: []
584
+ }];
585
+ case 25: return [3 /*break*/, 27];
586
+ case 26: throw err_3;
587
+ case 27: return [3 /*break*/, 28];
588
+ case 28:
589
+ durationMs = SlowQueryVerifier.resolveDurationMs(explainResponse);
590
+ if (!!SlowQueryVerifier.isValidDuration(durationMs)) return [3 /*break*/, 30];
591
+ return [4 /*yield*/, SlowQueryVerifier.measureExecution(db, collectionName, pipeline_1, filter, findOptions, aggregateOptions_1)];
592
+ case 29:
593
+ durationMs = _f.sent();
594
+ _f.label = 30;
595
+ case 30:
596
+ explainPlanRaw = (_d = (_c = explainResponse === null || explainResponse === void 0 ? void 0 : explainResponse.queryPlanner) !== null && _c !== void 0 ? _c : explainResponse) !== null && _d !== void 0 ? _d : {};
597
+ explainStatsRaw = usedVerbosity === 'queryPlanner' ? {} : ((_e = explainResponse === null || explainResponse === void 0 ? void 0 : explainResponse.executionStats) !== null && _e !== void 0 ? _e : {});
598
+ stageSummaries = SlowQueryVerifier.extractStageSummaries(explainResponse, explainStatsRaw);
599
+ explainPlan = SlowQueryVerifier.sanitizeExplainPayload(SlowQueryVerifier.normalizeExplainPayload(explainPlanRaw));
600
+ explainStats = SlowQueryVerifier.sanitizeExplainPayload(SlowQueryVerifier.normalizeExplainPayload(explainStatsRaw));
601
+ return [2 /*return*/, {
602
+ durationMs: durationMs,
603
+ explainPlan: explainPlan,
604
+ explainStats: explainStats,
605
+ stageSummaries: stageSummaries
606
+ }];
607
+ case 31:
608
+ if (!client) return [3 /*break*/, 33];
609
+ return [4 /*yield*/, client.close()];
610
+ case 32:
611
+ _f.sent();
612
+ _f.label = 33;
613
+ case 33: return [7 /*endfinally*/];
614
+ case 34: return [2 /*return*/];
615
+ }
616
+ });
617
+ });
618
+ };
619
+ SlowQueryVerifier.prototype.measureQuery = function (log, overrides) {
620
+ return __awaiter(this, void 0, void 0, function () {
621
+ return __generator(this, function (_a) {
622
+ return [2 /*return*/, this.runExplain(log, overrides)];
623
+ });
624
+ });
625
+ };
626
+ SlowQueryVerifier.prototype.handleExplainResult = function (log, result) {
627
+ return __awaiter(this, void 0, void 0, function () {
628
+ var existingRuns, durationValid, previousInvalidAttempts, invalidAttempts, shouldFail, nextRunAt_1, updateOps_1, runs, hasFastRun, hasEnoughRuns, status, nextRunAt, updateOps;
629
+ return __generator(this, function (_a) {
630
+ switch (_a.label) {
631
+ case 0:
632
+ if (!log._id) {
633
+ return [2 /*return*/];
634
+ }
635
+ existingRuns = (Array.isArray(log.verification_runs) ? log.verification_runs : [])
636
+ .filter(function (run) { return SlowQueryVerifier.isValidDuration(run.duration_ms); });
637
+ durationValid = SlowQueryVerifier.isValidDuration(result.durationMs);
638
+ if (!!durationValid) return [3 /*break*/, 2];
639
+ if (this.config.debugLogging) {
640
+ console.warn('Slow query verification reported invalid duration; keeping log pending.', log.collection, result.durationMs);
641
+ }
642
+ previousInvalidAttempts = typeof log.verification_invalid_attempts === 'number'
643
+ ? log.verification_invalid_attempts
644
+ : 0;
645
+ invalidAttempts = previousInvalidAttempts + 1;
646
+ shouldFail = invalidAttempts >= VERIFICATION_ATTEMPTS;
647
+ nextRunAt_1 = new Date(Date.now() + VERIFICATION_INTERVAL_MS);
648
+ updateOps_1 = {
649
+ $set: {
650
+ verification_runs: existingRuns,
651
+ verification_status: shouldFail ? 'failed' : 'pending',
652
+ verification_invalid_attempts: invalidAttempts,
653
+ explain_plan: result.explainPlan,
654
+ explain_execution_stats: result.explainStats,
655
+ explain_generated_at: new Date(),
656
+ verification_notes: shouldFail ? 'Verification failed: invalid duration' : 'Explain returned invalid duration'
657
+ }
658
+ };
659
+ if (shouldFail) {
660
+ updateOps_1.$unset = {
661
+ verification_next_run_at: ''
662
+ };
663
+ }
664
+ else {
665
+ updateOps_1.$set.verification_next_run_at = nextRunAt_1;
666
+ }
667
+ return [4 /*yield*/, SlowQueryLogs.updateOne({ _id: log._id }, updateOps_1)];
668
+ case 1:
669
+ _a.sent();
670
+ return [2 /*return*/];
671
+ case 2:
672
+ runs = existingRuns
673
+ .concat([
674
+ {
675
+ timestamp: new Date(),
676
+ duration_ms: result.durationMs
677
+ }
678
+ ])
679
+ .slice(-VERIFICATION_ATTEMPTS);
680
+ hasFastRun = runs.some(function (run) { return run.duration_ms < VERIFICATION_THRESHOLD_MS; });
681
+ if (!hasFastRun) return [3 /*break*/, 4];
682
+ // const durations = runs.map(run => `${run.duration_ms}ms`).join(', ');
683
+ // console.info('Removing slow query log; not consistently slow.', log.collection, durations);
684
+ return [4 /*yield*/, SlowQueryLogs.deleteOne({ _id: log._id })];
685
+ case 3:
686
+ // const durations = runs.map(run => `${run.duration_ms}ms`).join(', ');
687
+ // console.info('Removing slow query log; not consistently slow.', log.collection, durations);
688
+ _a.sent();
689
+ return [2 /*return*/];
690
+ case 4:
691
+ hasEnoughRuns = runs.length >= VERIFICATION_ATTEMPTS;
692
+ status = hasEnoughRuns ? 'passed' : 'pending';
693
+ if (!hasEnoughRuns) {
694
+ nextRunAt = new Date(Date.now() + VERIFICATION_INTERVAL_MS);
695
+ }
696
+ updateOps = {
697
+ $set: {
698
+ verification_runs: runs,
699
+ verification_status: status,
700
+ verification_invalid_attempts: 0,
701
+ explain_plan: result.explainPlan,
702
+ explain_execution_stats: result.explainStats,
703
+ explain_generated_at: new Date()
704
+ }
705
+ };
706
+ if (nextRunAt) {
707
+ updateOps.$set.verification_next_run_at = nextRunAt;
708
+ }
709
+ else {
710
+ updateOps.$unset = updateOps.$unset || {};
711
+ updateOps.$unset.verification_next_run_at = '';
712
+ }
713
+ return [4 /*yield*/, SlowQueryLogs.updateOne({ _id: log._id }, updateOps)];
714
+ case 5:
715
+ _a.sent();
716
+ if (!(status === 'passed')) return [3 /*break*/, 7];
717
+ return [4 /*yield*/, this.assignSlowQueryCounter(log._id)];
718
+ case 6:
719
+ _a.sent();
720
+ this.scheduleAutoOptimization(log._id);
721
+ _a.label = 7;
722
+ case 7: return [2 /*return*/];
723
+ }
724
+ });
725
+ });
726
+ };
727
+ SlowQueryVerifier.prototype.handleExplainError = function (log, err) {
728
+ return __awaiter(this, void 0, void 0, function () {
729
+ var message, code, permanentFailure, nextRunAt;
730
+ return __generator(this, function (_a) {
731
+ switch (_a.label) {
732
+ case 0:
733
+ if (!log._id) {
734
+ return [2 /*return*/];
735
+ }
736
+ message = typeof err === 'string' ? err : (err === null || err === void 0 ? void 0 : err.message) || 'Unknown error';
737
+ code = err instanceof SlowQueryVerifierError ? err.code : null;
738
+ permanentFailure = !!code && ['client_db_not_found', 'client_db_missing_uri', 'client_db_missing_database', 'main_db_unavailable', 'aggregate_write_stage', 'bson_too_large', 'collection_missing'].includes(code);
739
+ if (this.config.debugLogging) {
740
+ console.error('Slow query verification error for', log.collection, message);
741
+ }
742
+ else if (!permanentFailure) {
743
+ console.warn('Slow query verification error for', log.collection, message);
744
+ }
745
+ if (!permanentFailure) return [3 /*break*/, 2];
746
+ return [4 /*yield*/, SlowQueryLogs.updateOne({ _id: log._id }, {
747
+ $set: {
748
+ verification_status: 'failed',
749
+ verification_notes: "Verification failed: ".concat(message)
750
+ },
751
+ $unset: {
752
+ verification_next_run_at: ''
753
+ }
754
+ })];
755
+ case 1:
756
+ _a.sent();
757
+ return [2 /*return*/];
758
+ case 2:
759
+ nextRunAt = new Date(Date.now() + VERIFICATION_INTERVAL_MS);
760
+ return [4 /*yield*/, SlowQueryLogs.updateOne({ _id: log._id }, {
761
+ $set: {
762
+ verification_next_run_at: nextRunAt,
763
+ verification_notes: "Verification error: ".concat(message)
764
+ }
765
+ })];
766
+ case 3:
767
+ _a.sent();
768
+ return [2 /*return*/];
769
+ }
770
+ });
771
+ });
772
+ };
773
+ SlowQueryVerifier.prototype.assignSlowQueryCounter = function (logId) {
774
+ return __awaiter(this, void 0, void 0, function () {
775
+ var latest, hasNumber, counterValue, counterString;
776
+ return __generator(this, function (_a) {
777
+ switch (_a.label) {
778
+ case 0:
779
+ if (!logId) {
780
+ return [2 /*return*/];
781
+ }
782
+ return [4 /*yield*/, SlowQueryLogs.findOne({ _id: logId })];
783
+ case 1:
784
+ latest = _a.sent();
785
+ if (!latest) {
786
+ return [2 /*return*/];
787
+ }
788
+ hasNumber = typeof latest.slow_query_count === 'number' && latest.slow_query_count > 0;
789
+ if (hasNumber) {
790
+ return [2 /*return*/];
791
+ }
792
+ return [4 /*yield*/, resolveio_server_app_1.ResolveIOServer.getMainServer().getMethodManager().callMethod('incCounter', 'slow_query')];
793
+ case 2:
794
+ counterValue = _a.sent();
795
+ counterString = (0, common_1.pad)(counterValue, 6);
796
+ return [4 /*yield*/, SlowQueryLogs.updateOne({ _id: logId }, {
797
+ $set: {
798
+ slow_query_count: counterValue,
799
+ slow_query_count_string: counterString
800
+ }
801
+ })];
802
+ case 3:
803
+ _a.sent();
804
+ return [2 /*return*/];
805
+ }
806
+ });
807
+ });
808
+ };
809
+ SlowQueryVerifier.prototype.scheduleAutoOptimization = function (logId) {
810
+ if (!this.config.autoOptimizeEnabled || !logId) {
811
+ return;
812
+ }
813
+ if (this.autoOptimizeInFlight.has(logId)) {
814
+ return;
815
+ }
816
+ this.autoOptimizeInFlight.add(logId);
817
+ this.runAutoOptimizationInBackground(logId);
818
+ };
819
+ SlowQueryVerifier.prototype.runAutoOptimizationInBackground = function (logId) {
820
+ var _this = this;
821
+ setImmediate(function () { return __awaiter(_this, void 0, void 0, function () {
822
+ var error_1;
823
+ return __generator(this, function (_a) {
824
+ switch (_a.label) {
825
+ case 0:
826
+ _a.trys.push([0, 2, 3, 4]);
827
+ return [4 /*yield*/, this.runAutoOptimization(logId)];
828
+ case 1:
829
+ _a.sent();
830
+ return [3 /*break*/, 4];
831
+ case 2:
832
+ error_1 = _a.sent();
833
+ console.error('Slow query auto optimization failed', { logId: logId, error: (error_1 === null || error_1 === void 0 ? void 0 : error_1.message) || error_1 });
834
+ return [3 /*break*/, 4];
835
+ case 3:
836
+ this.autoOptimizeInFlight.delete(logId);
837
+ return [7 /*endfinally*/];
838
+ case 4: return [2 /*return*/];
839
+ }
840
+ });
841
+ }); });
842
+ };
843
+ SlowQueryVerifier.prototype.escapeRegex = function (value) {
844
+ return String(value || '').replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
845
+ };
846
+ SlowQueryVerifier.prototype.getEscalationRecipients = function () {
847
+ var unique = new Set();
848
+ (this.config.escalationEmails || []).forEach(function (entry) {
849
+ var normalized = String(entry || '').trim().toLowerCase();
850
+ if (normalized) {
851
+ unique.add(normalized);
852
+ }
853
+ });
854
+ if (!unique.size) {
855
+ unique.add(DEFAULT_ERROR_ALERT_EMAIL);
856
+ }
857
+ return Array.from(unique);
858
+ };
859
+ SlowQueryVerifier.prototype.sendSlowQueryEscalationNotice = function (log, reason) {
860
+ return __awaiter(this, void 0, void 0, function () {
861
+ var recipients, subject, body, methodManager, recipients_1, recipients_1_1, recipient, error_2, e_2_1;
862
+ var e_2, _a;
863
+ return __generator(this, function (_b) {
864
+ switch (_b.label) {
865
+ case 0:
866
+ recipients = this.getEscalationRecipients();
867
+ if (!recipients.length || !(log === null || log === void 0 ? void 0 : log._id)) {
868
+ return [2 /*return*/];
869
+ }
870
+ subject = "ResolveIO Slow Query Escalation: ".concat(log.slow_query_count_string || log._id);
871
+ body = [
872
+ 'Slow-query auto optimization budget was exhausted and additional autonomous attempts were stopped.',
873
+ '',
874
+ "Reason: ".concat(reason),
875
+ "Slow Query Log ID: ".concat(log._id),
876
+ "Slow Query Counter: ".concat(log.slow_query_count_string || 'n/a'),
877
+ "Collection: ".concat(log.collection || 'unknown'),
878
+ "Query Hash: ".concat(log.query_hash || 'n/a'),
879
+ "Client: ".concat(log.client_name || log.client_slug || 'unknown'),
880
+ "Environment: ".concat(log.environment || 'unknown'),
881
+ "Attempts: ".concat(log.auto_fix_attempt_count || 0, "/").concat(this.config.autoOptimizeMaxAttemptsPerQuery),
882
+ '',
883
+ 'The query has been marked ignored to protect customer AI credits. Manual tuning or explicit allow-list override is required.'
884
+ ].join('\n');
885
+ methodManager = resolveio_server_app_1.ResolveIOServer.getMainServer().getMethodManager();
886
+ _b.label = 1;
887
+ case 1:
888
+ _b.trys.push([1, 8, 9, 10]);
889
+ recipients_1 = __values(recipients), recipients_1_1 = recipients_1.next();
890
+ _b.label = 2;
891
+ case 2:
892
+ if (!!recipients_1_1.done) return [3 /*break*/, 7];
893
+ recipient = recipients_1_1.value;
894
+ _b.label = 3;
895
+ case 3:
896
+ _b.trys.push([3, 5, , 6]);
897
+ return [4 /*yield*/, methodManager.sendEmail(recipient, subject, body)];
898
+ case 4:
899
+ _b.sent();
900
+ return [3 /*break*/, 6];
901
+ case 5:
902
+ error_2 = _b.sent();
903
+ console.error('Failed sending slow-query escalation email', { recipient: recipient, logId: log._id, error: error_2 });
904
+ return [3 /*break*/, 6];
905
+ case 6:
906
+ recipients_1_1 = recipients_1.next();
907
+ return [3 /*break*/, 2];
908
+ case 7: return [3 /*break*/, 10];
909
+ case 8:
910
+ e_2_1 = _b.sent();
911
+ e_2 = { error: e_2_1 };
912
+ return [3 /*break*/, 10];
913
+ case 9:
914
+ try {
915
+ if (recipients_1_1 && !recipients_1_1.done && (_a = recipients_1.return)) _a.call(recipients_1);
916
+ }
917
+ finally { if (e_2) throw e_2.error; }
918
+ return [7 /*endfinally*/];
919
+ case 10: return [2 /*return*/];
920
+ }
921
+ });
922
+ });
923
+ };
924
+ SlowQueryVerifier.prototype.resolveSlowQueryClientTarget = function (log) {
925
+ return __awaiter(this, void 0, void 0, function () {
926
+ var directId, candidates, candidates_2, candidates_2_1, candidate, escaped, match, e_3_1;
927
+ var e_3, _a;
928
+ return __generator(this, function (_b) {
929
+ switch (_b.label) {
930
+ case 0:
931
+ directId = String((log === null || log === void 0 ? void 0 : log.id_client) || '').trim();
932
+ if (directId) {
933
+ return [2 /*return*/, {
934
+ idClient: directId,
935
+ clientName: String((log === null || log === void 0 ? void 0 : log.client_name) || '').trim()
936
+ }];
937
+ }
938
+ candidates = [
939
+ String((log === null || log === void 0 ? void 0 : log.client_slug) || '').trim(),
940
+ String((log === null || log === void 0 ? void 0 : log.client_name) || '').trim(),
941
+ String((log === null || log === void 0 ? void 0 : log.source_app) || '').trim()
942
+ ].filter(Boolean);
943
+ _b.label = 1;
944
+ case 1:
945
+ _b.trys.push([1, 6, 7, 8]);
946
+ candidates_2 = __values(candidates), candidates_2_1 = candidates_2.next();
947
+ _b.label = 2;
948
+ case 2:
949
+ if (!!candidates_2_1.done) return [3 /*break*/, 5];
950
+ candidate = candidates_2_1.value;
951
+ escaped = this.escapeRegex(candidate);
952
+ return [4 /*yield*/, Clients.findOne({
953
+ $or: [
954
+ { name: { $regex: "^".concat(escaped, "$"), $options: 'i' } },
955
+ { demo_name: { $regex: "^".concat(escaped, "$"), $options: 'i' } },
956
+ { project: { $regex: "^".concat(escaped, "$"), $options: 'i' } },
957
+ { repo: { $regex: "^".concat(escaped, "$"), $options: 'i' } }
958
+ ]
959
+ }, {
960
+ projection: {
961
+ _id: 1,
962
+ name: 1
963
+ }
964
+ })];
965
+ case 3:
966
+ match = _b.sent();
967
+ if (match === null || match === void 0 ? void 0 : match._id) {
968
+ return [2 /*return*/, {
969
+ idClient: String(match._id || '').trim(),
970
+ clientName: String(match.name || (log === null || log === void 0 ? void 0 : log.client_name) || candidate || '').trim()
971
+ }];
972
+ }
973
+ _b.label = 4;
974
+ case 4:
975
+ candidates_2_1 = candidates_2.next();
976
+ return [3 /*break*/, 2];
977
+ case 5: return [3 /*break*/, 8];
978
+ case 6:
979
+ e_3_1 = _b.sent();
980
+ e_3 = { error: e_3_1 };
981
+ return [3 /*break*/, 8];
982
+ case 7:
983
+ try {
984
+ if (candidates_2_1 && !candidates_2_1.done && (_a = candidates_2.return)) _a.call(candidates_2);
985
+ }
986
+ finally { if (e_3) throw e_3.error; }
987
+ return [7 /*endfinally*/];
988
+ case 8: return [2 /*return*/, {
989
+ idClient: '',
990
+ clientName: String((log === null || log === void 0 ? void 0 : log.client_name) || '').trim()
991
+ }];
992
+ }
993
+ });
994
+ });
995
+ };
996
+ SlowQueryVerifier.prototype.buildLocalInternalUserCriteria = function () {
997
+ return {
998
+ $and: [
999
+ {
1000
+ is_customer: {
1001
+ $ne: true
1002
+ }
1003
+ },
1004
+ {
1005
+ $nor: [
1006
+ {
1007
+ 'other.id_customer': {
1008
+ $exists: true,
1009
+ $nin: ['', null]
1010
+ }
1011
+ },
1012
+ {
1013
+ id_customer: {
1014
+ $exists: true,
1015
+ $nin: ['', null]
1016
+ }
1017
+ }
1018
+ ]
1019
+ }
1020
+ ]
1021
+ };
1022
+ };
1023
+ SlowQueryVerifier.prototype.buildLocalAdminUserCriteria = function () {
1024
+ return {
1025
+ $or: [
1026
+ {
1027
+ 'roles.super_admin': true
1028
+ },
1029
+ {
1030
+ 'roles.groups.name': {
1031
+ $regex: 'admin',
1032
+ $options: 'i'
1033
+ }
1034
+ },
1035
+ {
1036
+ 'roles.groups.views': {
1037
+ $regex: '^/manage'
1038
+ }
1039
+ },
1040
+ {
1041
+ 'roles.groups.views': '/manage'
1042
+ }
1043
+ ]
1044
+ };
1045
+ };
1046
+ SlowQueryVerifier.prototype.resolveLocalNotificationUserIds = function (isGeneratedApp) {
1047
+ return __awaiter(this, void 0, void 0, function () {
1048
+ var andClauses, users, unique, users_1, users_1_1, user, idUser;
1049
+ var e_4, _a;
1050
+ return __generator(this, function (_b) {
1051
+ switch (_b.label) {
1052
+ case 0:
1053
+ andClauses = [
1054
+ {
1055
+ active: true
1056
+ },
1057
+ {
1058
+ username: {
1059
+ $exists: true
1060
+ }
1061
+ }
1062
+ ];
1063
+ if (isGeneratedApp) {
1064
+ andClauses.push(this.buildLocalInternalUserCriteria());
1065
+ }
1066
+ else {
1067
+ andClauses.push(this.buildLocalAdminUserCriteria());
1068
+ }
1069
+ return [4 /*yield*/, user_collection_1.Users.find({
1070
+ $and: andClauses
1071
+ }, {
1072
+ projection: {
1073
+ _id: 1
1074
+ },
1075
+ limit: MAX_LOCAL_NOTIFICATION_USERS
1076
+ })];
1077
+ case 1:
1078
+ users = _b.sent();
1079
+ if (!Array.isArray(users) || !users.length) {
1080
+ return [2 /*return*/, []];
1081
+ }
1082
+ unique = new Set();
1083
+ try {
1084
+ for (users_1 = __values(users), users_1_1 = users_1.next(); !users_1_1.done; users_1_1 = users_1.next()) {
1085
+ user = users_1_1.value;
1086
+ idUser = String((user === null || user === void 0 ? void 0 : user._id) || '').trim();
1087
+ if (idUser) {
1088
+ unique.add(idUser);
1089
+ }
1090
+ if (unique.size >= MAX_LOCAL_NOTIFICATION_USERS) {
1091
+ break;
1092
+ }
1093
+ }
1094
+ }
1095
+ catch (e_4_1) { e_4 = { error: e_4_1 }; }
1096
+ finally {
1097
+ try {
1098
+ if (users_1_1 && !users_1_1.done && (_a = users_1.return)) _a.call(users_1);
1099
+ }
1100
+ finally { if (e_4) throw e_4.error; }
1101
+ }
1102
+ return [2 /*return*/, Array.from(unique)];
1103
+ }
1104
+ });
1105
+ });
1106
+ };
1107
+ SlowQueryVerifier.prototype.isGeneratedAICoderClient = function (idClient) {
1108
+ return __awaiter(this, void 0, void 0, function () {
1109
+ var normalizedClientId, match;
1110
+ return __generator(this, function (_a) {
1111
+ switch (_a.label) {
1112
+ case 0:
1113
+ normalizedClientId = String(idClient || '').trim();
1114
+ if (!normalizedClientId) {
1115
+ return [2 /*return*/, false];
1116
+ }
1117
+ return [4 /*yield*/, AICoderApps.findOne({
1118
+ client_id: normalizedClientId
1119
+ }, {
1120
+ projection: {
1121
+ _id: 1
1122
+ }
1123
+ })];
1124
+ case 1:
1125
+ match = _a.sent();
1126
+ return [2 /*return*/, !!(match === null || match === void 0 ? void 0 : match._id)];
1127
+ }
1128
+ });
1129
+ });
1130
+ };
1131
+ SlowQueryVerifier.prototype.buildAICoderSlowQuerySummary = function (stage, log, extra) {
1132
+ var _a, _b, _c, _d;
1133
+ return (0, customer_notification_content_manager_1.buildGeneratedSlowQuerySummary)(stage, {
1134
+ collection: String((log === null || log === void 0 ? void 0 : log.collection) || '').trim(),
1135
+ source_app: String((log === null || log === void 0 ? void 0 : log.source_app) || '').trim(),
1136
+ environment: String((log === null || log === void 0 ? void 0 : log.environment) || '').trim(),
1137
+ baseline_duration_ms: Number((_b = (_a = log === null || log === void 0 ? void 0 : log.auto_fix_result) === null || _a === void 0 ? void 0 : _a.baseline) === null || _b === void 0 ? void 0 : _b.durationMs),
1138
+ after_duration_ms: Number((_d = (_c = log === null || log === void 0 ? void 0 : log.auto_fix_result) === null || _c === void 0 ? void 0 : _c.after) === null || _d === void 0 ? void 0 : _d.durationMs),
1139
+ reason: extra === null || extra === void 0 ? void 0 : extra.reason,
1140
+ notes: extra === null || extra === void 0 ? void 0 : extra.notes
1141
+ }, extra);
1142
+ };
1143
+ SlowQueryVerifier.prototype.buildResolveIOProjectSlowQueryDetails = function (log, extra) {
1144
+ var _a, _b, _c, _d;
1145
+ var runDurations = Array.isArray(log === null || log === void 0 ? void 0 : log.verification_runs)
1146
+ ? log.verification_runs
1147
+ .map(function (run) { return Number(run === null || run === void 0 ? void 0 : run.duration_ms); })
1148
+ .filter(function (duration) { return Number.isFinite(duration) && duration >= 0; })
1149
+ : [];
1150
+ return (0, customer_notification_content_manager_1.buildResolveIOProjectSlowQueryDetails)({
1151
+ collection: log.collection || '',
1152
+ client_name: log.client_name || log.client_slug || '',
1153
+ source_app: log.source_app || '',
1154
+ environment: log.environment || '',
1155
+ query_hash: log.query_hash || '',
1156
+ baseline_duration_ms: Number((_b = (_a = log === null || log === void 0 ? void 0 : log.auto_fix_result) === null || _a === void 0 ? void 0 : _a.baseline) === null || _b === void 0 ? void 0 : _b.durationMs),
1157
+ after_duration_ms: Number((_d = (_c = log === null || log === void 0 ? void 0 : log.auto_fix_result) === null || _c === void 0 ? void 0 : _c.after) === null || _d === void 0 ? void 0 : _d.durationMs),
1158
+ verification_run_durations_ms: runDurations,
1159
+ log_id: log._id || '',
1160
+ reason: extra === null || extra === void 0 ? void 0 : extra.reason,
1161
+ notes: extra === null || extra === void 0 ? void 0 : extra.notes
1162
+ });
1163
+ };
1164
+ SlowQueryVerifier.prototype.notifyCustomerSlowQueryStatus = function (stage, log, extra) {
1165
+ return __awaiter(this, void 0, void 0, function () {
1166
+ var target, isGeneratedApp, generatedApp, issueKey, dedupeKey, metadata, targetPayload, idUsers, payload, error_3;
1167
+ return __generator(this, function (_a) {
1168
+ switch (_a.label) {
1169
+ case 0:
1170
+ if (!(log === null || log === void 0 ? void 0 : log._id)) {
1171
+ return [2 /*return*/];
1172
+ }
1173
+ return [4 /*yield*/, this.resolveSlowQueryClientTarget(log)];
1174
+ case 1:
1175
+ target = _a.sent();
1176
+ isGeneratedApp = false;
1177
+ if (!target.idClient) return [3 /*break*/, 3];
1178
+ return [4 /*yield*/, this.isGeneratedAICoderClient(target.idClient)];
1179
+ case 2:
1180
+ isGeneratedApp = _a.sent();
1181
+ return [3 /*break*/, 5];
1182
+ case 3: return [4 /*yield*/, this.resolveAutoOptimizeApp(log)];
1183
+ case 4:
1184
+ generatedApp = _a.sent();
1185
+ isGeneratedApp = !!generatedApp;
1186
+ _a.label = 5;
1187
+ case 5:
1188
+ if (!isGeneratedApp && stage !== 'completed_success') {
1189
+ return [2 /*return*/];
1190
+ }
1191
+ issueKey = String(log.query_hash || log._id || '').trim();
1192
+ dedupeKey = "slow-query:".concat(issueKey, ":").concat(stage);
1193
+ metadata = {
1194
+ log_id: log._id,
1195
+ query_hash: log.query_hash || '',
1196
+ collection: log.collection || '',
1197
+ environment: log.environment || '',
1198
+ source_app: log.source_app || '',
1199
+ reason: (extra === null || extra === void 0 ? void 0 : extra.reason) || '',
1200
+ notes: (extra === null || extra === void 0 ? void 0 : extra.notes) || ''
1201
+ };
1202
+ targetPayload = {};
1203
+ if (!target.idClient) return [3 /*break*/, 6];
1204
+ targetPayload.target_type = isGeneratedApp ? 'client_internal' : 'client_admins';
1205
+ targetPayload.id_client = target.idClient;
1206
+ targetPayload.client_name = target.clientName || undefined;
1207
+ return [3 /*break*/, 8];
1208
+ case 6: return [4 /*yield*/, this.resolveLocalNotificationUserIds(isGeneratedApp)];
1209
+ case 7:
1210
+ idUsers = _a.sent();
1211
+ if (!idUsers.length) {
1212
+ return [2 /*return*/];
1213
+ }
1214
+ targetPayload.target_type = 'users';
1215
+ targetPayload.id_users = idUsers;
1216
+ targetPayload.client_name = target.clientName || undefined;
1217
+ _a.label = 8;
1218
+ case 8:
1219
+ payload = {};
1220
+ if (isGeneratedApp) {
1221
+ if (stage === 'detected_auto_optimize_enabled') {
1222
+ payload = {
1223
+ title: 'Slow query detected. Auto-optimization is running.',
1224
+ message: 'We detected a slow query and started an automatic optimization workflow. We will notify you when it is complete.',
1225
+ severity: 'info',
1226
+ details: this.buildAICoderSlowQuerySummary(stage, log, extra)
1227
+ };
1228
+ }
1229
+ else if (stage === 'completed_success') {
1230
+ payload = {
1231
+ title: 'Slow query optimization completed.',
1232
+ message: "We optimized slow performance for ".concat(log.collection || 'a collection', " and published the improvement."),
1233
+ severity: 'success',
1234
+ details: this.buildAICoderSlowQuerySummary(stage, log, extra)
1235
+ };
1236
+ }
1237
+ else {
1238
+ payload = {
1239
+ title: 'Slow query needs manual review.',
1240
+ message: 'We could not complete automatic optimization for a slow query. Manual tuning is required.',
1241
+ severity: 'warning',
1242
+ details: this.buildAICoderSlowQuerySummary(stage, log, extra)
1243
+ };
1244
+ }
1245
+ }
1246
+ else {
1247
+ payload = {
1248
+ title: 'ResolveIO project slow query optimized',
1249
+ message: "Slow-query optimization completed for ".concat(log.collection || 'a collection', "."),
1250
+ severity: 'success',
1251
+ details: this.buildResolveIOProjectSlowQueryDetails(log, extra)
1252
+ };
1253
+ }
1254
+ _a.label = 9;
1255
+ case 9:
1256
+ _a.trys.push([9, 11, , 12]);
1257
+ return [4 /*yield*/, resolveio_server_app_1.ResolveIOServer.getMainServer().getMethodManager().callMethod('createCustomerNotification', __assign(__assign(__assign({}, targetPayload), { category: 'slow-query', source: 'slow-query-auto-optimize', source_id: String(log._id || '').trim() || undefined, dedupe_key: dedupeKey, metadata: metadata }), payload))];
1258
+ case 10:
1259
+ _a.sent();
1260
+ return [3 /*break*/, 12];
1261
+ case 11:
1262
+ error_3 = _a.sent();
1263
+ if (this.config.debugLogging) {
1264
+ console.warn('Slow query customer notification failed', {
1265
+ logId: log._id,
1266
+ stage: stage,
1267
+ error: (error_3 === null || error_3 === void 0 ? void 0 : error_3.message) || error_3
1268
+ });
1269
+ }
1270
+ return [3 /*break*/, 12];
1271
+ case 12: return [2 /*return*/];
1272
+ }
1273
+ });
1274
+ });
1275
+ };
1276
+ SlowQueryVerifier.prototype.parseDate = function (value) {
1277
+ if (!value) {
1278
+ return null;
1279
+ }
1280
+ if (value instanceof Date && !Number.isNaN(value.getTime())) {
1281
+ return value;
1282
+ }
1283
+ var parsed = new Date(value);
1284
+ return Number.isNaN(parsed.getTime()) ? null : parsed;
1285
+ };
1286
+ SlowQueryVerifier.prototype.resolveFingerprintScopeKey = function (log) {
1287
+ var explicit = String((log === null || log === void 0 ? void 0 : log.fingerprint_scope_key) || '').trim();
1288
+ if (explicit) {
1289
+ return explicit;
1290
+ }
1291
+ var normalize = function (value) {
1292
+ var normalized = String(value || '')
1293
+ .trim()
1294
+ .toLowerCase()
1295
+ .replace(/\s+/g, ' ');
1296
+ return normalized || '_';
1297
+ };
1298
+ var clientKey = normalize((log === null || log === void 0 ? void 0 : log.client_slug) || (log === null || log === void 0 ? void 0 : log.client_name) || '');
1299
+ var sourceApp = normalize((log === null || log === void 0 ? void 0 : log.source_app) || '');
1300
+ var environment = normalize((log === null || log === void 0 ? void 0 : log.environment) || '');
1301
+ var publication = normalize((log === null || log === void 0 ? void 0 : log.publication) || '');
1302
+ var serverUrl = normalize((log === null || log === void 0 ? void 0 : log.server_url) || '');
1303
+ return [clientKey, sourceApp, environment, publication, serverUrl].join('|');
1304
+ };
1305
+ SlowQueryVerifier.prototype.buildFingerprintMatchQuery = function (log) {
1306
+ var conditions = [];
1307
+ var collection = String((log === null || log === void 0 ? void 0 : log.collection) || '').trim();
1308
+ if (collection) {
1309
+ conditions.push({ collection: collection });
1310
+ }
1311
+ var explicitScopeKey = String((log === null || log === void 0 ? void 0 : log.fingerprint_scope_key) || '').trim();
1312
+ var scopeKey = this.resolveFingerprintScopeKey(log);
1313
+ if (scopeKey) {
1314
+ var legacyScopeQuery = {};
1315
+ if (String((log === null || log === void 0 ? void 0 : log.client_slug) || '').trim()) {
1316
+ legacyScopeQuery.client_slug = log.client_slug;
1317
+ }
1318
+ if (String((log === null || log === void 0 ? void 0 : log.environment) || '').trim()) {
1319
+ legacyScopeQuery.environment = log.environment;
1320
+ }
1321
+ if (String((log === null || log === void 0 ? void 0 : log.source_app) || '').trim()) {
1322
+ legacyScopeQuery.source_app = log.source_app;
1323
+ }
1324
+ if (String((log === null || log === void 0 ? void 0 : log.publication) || '').trim()) {
1325
+ legacyScopeQuery.publication = log.publication;
1326
+ }
1327
+ if (String((log === null || log === void 0 ? void 0 : log.server_url) || '').trim()) {
1328
+ legacyScopeQuery.server_url = log.server_url;
1329
+ }
1330
+ if (explicitScopeKey) {
1331
+ conditions.push({ fingerprint_scope_key: scopeKey });
1332
+ }
1333
+ else {
1334
+ var scopeCandidates = [{ _id: (log === null || log === void 0 ? void 0 : log._id) || '' }, { fingerprint_scope_key: scopeKey }];
1335
+ if (Object.keys(legacyScopeQuery).length) {
1336
+ scopeCandidates.push(legacyScopeQuery);
1337
+ }
1338
+ conditions.push({ $or: scopeCandidates });
1339
+ }
1340
+ }
1341
+ var canonicalHash = String((log === null || log === void 0 ? void 0 : log.canonical_fingerprint_hash) || '').trim();
1342
+ var queryHash = String((log === null || log === void 0 ? void 0 : log.query_hash) || '').trim();
1343
+ if (canonicalHash && queryHash && canonicalHash !== queryHash) {
1344
+ conditions.push({
1345
+ $or: [
1346
+ { canonical_fingerprint_hash: canonicalHash },
1347
+ {
1348
+ canonical_fingerprint_hash: { $exists: false },
1349
+ query_hash: queryHash
1350
+ }
1351
+ ]
1352
+ });
1353
+ }
1354
+ else if (canonicalHash) {
1355
+ conditions.push({ canonical_fingerprint_hash: canonicalHash });
1356
+ }
1357
+ else if (queryHash) {
1358
+ conditions.push({ query_hash: queryHash });
1359
+ }
1360
+ else if (log === null || log === void 0 ? void 0 : log._id) {
1361
+ conditions.push({ _id: log._id });
1362
+ }
1363
+ if (!conditions.length) {
1364
+ return { _id: (log === null || log === void 0 ? void 0 : log._id) || '' };
1365
+ }
1366
+ if (conditions.length === 1) {
1367
+ return conditions[0];
1368
+ }
1369
+ return { $and: conditions };
1370
+ };
1371
+ SlowQueryVerifier.prototype.countAttemptsWithinWindow = function (log, windowStart) {
1372
+ var _this = this;
1373
+ var history = Array.isArray(log === null || log === void 0 ? void 0 : log.auto_fix_attempt_history)
1374
+ ? log.auto_fix_attempt_history
1375
+ : [];
1376
+ var attemptsInWindow = 0;
1377
+ history.forEach(function (entry) {
1378
+ var attemptAt = _this.parseDate(entry);
1379
+ if (attemptAt && attemptAt.getTime() >= windowStart.getTime()) {
1380
+ attemptsInWindow += 1;
1381
+ }
1382
+ });
1383
+ if (attemptsInWindow > 0) {
1384
+ return attemptsInWindow;
1385
+ }
1386
+ var lastAttemptAt = this.parseDate(log === null || log === void 0 ? void 0 : log.auto_fix_last_attempt_at);
1387
+ var attemptsUsed = Number.isFinite(Number(log === null || log === void 0 ? void 0 : log.auto_fix_attempt_count))
1388
+ ? Number(log.auto_fix_attempt_count)
1389
+ : 0;
1390
+ if (lastAttemptAt && lastAttemptAt.getTime() >= windowStart.getTime() && attemptsUsed > 0) {
1391
+ return 1;
1392
+ }
1393
+ return 0;
1394
+ };
1395
+ SlowQueryVerifier.prototype.resolveFingerprintAttemptsInWindow = function (log, windowStart) {
1396
+ return __awaiter(this, void 0, void 0, function () {
1397
+ var matchQuery, matches, attempts;
1398
+ var _this = this;
1399
+ return __generator(this, function (_a) {
1400
+ switch (_a.label) {
1401
+ case 0:
1402
+ matchQuery = this.buildFingerprintMatchQuery(log);
1403
+ return [4 /*yield*/, SlowQueryLogs.find(matchQuery, {
1404
+ limit: 200,
1405
+ projection: {
1406
+ _id: 1,
1407
+ auto_fix_attempt_history: 1,
1408
+ auto_fix_attempt_count: 1,
1409
+ auto_fix_last_attempt_at: 1
1410
+ }
1411
+ })];
1412
+ case 1:
1413
+ matches = _a.sent();
1414
+ attempts = 0;
1415
+ matches.forEach(function (entry) {
1416
+ attempts += _this.countAttemptsWithinWindow(entry, windowStart);
1417
+ });
1418
+ return [2 /*return*/, attempts];
1419
+ }
1420
+ });
1421
+ });
1422
+ };
1423
+ SlowQueryVerifier.prototype.resolveCooldownDeadline = function (log) {
1424
+ var cooldownMinutes = Number.isFinite(Number(this.config.autoOptimizeCooldownMinutes))
1425
+ ? Number(this.config.autoOptimizeCooldownMinutes)
1426
+ : 0;
1427
+ if (cooldownMinutes <= 0) {
1428
+ return null;
1429
+ }
1430
+ var lastAttemptAt = this.parseDate(log === null || log === void 0 ? void 0 : log.auto_fix_last_attempt_at);
1431
+ if (!lastAttemptAt) {
1432
+ return null;
1433
+ }
1434
+ return new Date(lastAttemptAt.getTime() + (cooldownMinutes * 60 * 1000));
1435
+ };
1436
+ SlowQueryVerifier.prototype.markAutoOptimizeCooldownActive = function (log, cooldownUntil) {
1437
+ return __awaiter(this, void 0, void 0, function () {
1438
+ var reason;
1439
+ return __generator(this, function (_a) {
1440
+ switch (_a.label) {
1441
+ case 0:
1442
+ if (!(log === null || log === void 0 ? void 0 : log._id)) {
1443
+ return [2 /*return*/];
1444
+ }
1445
+ reason = "Auto optimize cooldown is active until ".concat(cooldownUntil.toISOString(), ".");
1446
+ return [4 /*yield*/, SlowQueryLogs.updateOne({ _id: log._id }, {
1447
+ $set: {
1448
+ status: 'investigating',
1449
+ auto_fix_status: 'failed',
1450
+ auto_fix_disabled_reason: reason,
1451
+ verification_notes: reason,
1452
+ verification_status: 'pending',
1453
+ verification_next_run_at: cooldownUntil,
1454
+ last_triaged_by: 'auto-slow-query',
1455
+ last_triaged_at: new Date()
1456
+ }
1457
+ })];
1458
+ case 1:
1459
+ _a.sent();
1460
+ return [2 /*return*/];
1461
+ }
1462
+ });
1463
+ });
1464
+ };
1465
+ SlowQueryVerifier.prototype.markAutoOptimizeTokenIneligible = function (log, reason) {
1466
+ return __awaiter(this, void 0, void 0, function () {
1467
+ var message, refreshed;
1468
+ return __generator(this, function (_a) {
1469
+ switch (_a.label) {
1470
+ case 0:
1471
+ if (!(log === null || log === void 0 ? void 0 : log._id)) {
1472
+ return [2 /*return*/];
1473
+ }
1474
+ message = "Auto optimize blocked by AI credit preflight: ".concat(reason);
1475
+ return [4 /*yield*/, SlowQueryLogs.updateOne({ _id: log._id }, {
1476
+ $set: {
1477
+ status: 'ignored',
1478
+ ignored: true,
1479
+ auto_fix_status: 'failed',
1480
+ auto_fix_disabled_reason: message,
1481
+ verification_notes: message,
1482
+ last_triaged_by: 'auto-slow-query',
1483
+ last_triaged_at: new Date()
1484
+ },
1485
+ $unset: {
1486
+ verification_next_run_at: ''
1487
+ }
1488
+ })];
1489
+ case 1:
1490
+ _a.sent();
1491
+ return [4 /*yield*/, SlowQueryLogs.findOne({ _id: log._id })];
1492
+ case 2:
1493
+ refreshed = (_a.sent()) || log;
1494
+ return [4 /*yield*/, this.sendSlowQueryEscalationNotice(refreshed, message)];
1495
+ case 3:
1496
+ _a.sent();
1497
+ return [4 /*yield*/, this.notifyCustomerSlowQueryStatus('completed_failed', refreshed, { reason: message })];
1498
+ case 4:
1499
+ _a.sent();
1500
+ return [2 /*return*/];
1501
+ }
1502
+ });
1503
+ });
1504
+ };
1505
+ SlowQueryVerifier.prototype.markAutoOptimizeBudgetExceeded = function (log, reason) {
1506
+ return __awaiter(this, void 0, void 0, function () {
1507
+ var attemptsUsed, maxAttempts, attemptSummary, message, matchQuery, refreshed;
1508
+ return __generator(this, function (_a) {
1509
+ switch (_a.label) {
1510
+ case 0:
1511
+ if (!(log === null || log === void 0 ? void 0 : log._id)) {
1512
+ return [2 /*return*/];
1513
+ }
1514
+ attemptsUsed = Number.isFinite(Number(log.auto_fix_attempt_count))
1515
+ ? Number(log.auto_fix_attempt_count)
1516
+ : 0;
1517
+ maxAttempts = Number.isFinite(Number(this.config.autoOptimizeMaxAttemptsPerQuery))
1518
+ ? Number(this.config.autoOptimizeMaxAttemptsPerQuery)
1519
+ : 0;
1520
+ attemptSummary = maxAttempts > 0
1521
+ ? "Attempts on this log: ".concat(attemptsUsed, "/").concat(maxAttempts, ".")
1522
+ : "Attempts on this log: ".concat(attemptsUsed, ".");
1523
+ message = "".concat(reason, " Query marked ignored pending manual intervention. ").concat(attemptSummary);
1524
+ matchQuery = this.buildFingerprintMatchQuery(log);
1525
+ return [4 /*yield*/, SlowQueryLogs.updateMany(matchQuery, {
1526
+ $set: {
1527
+ status: 'ignored',
1528
+ ignored: true,
1529
+ auto_fix_status: 'failed',
1530
+ auto_fix_disabled_reason: message,
1531
+ verification_notes: message,
1532
+ verification_status: 'failed',
1533
+ last_triaged_by: 'auto-slow-query',
1534
+ last_triaged_at: new Date()
1535
+ },
1536
+ $unset: {
1537
+ verification_next_run_at: ''
1538
+ }
1539
+ })];
1540
+ case 1:
1541
+ _a.sent();
1542
+ return [4 /*yield*/, SlowQueryLogs.findOne({ _id: log._id })];
1543
+ case 2:
1544
+ refreshed = (_a.sent()) || log;
1545
+ return [4 /*yield*/, this.sendSlowQueryEscalationNotice(refreshed, reason)];
1546
+ case 3:
1547
+ _a.sent();
1548
+ return [4 /*yield*/, this.notifyCustomerSlowQueryStatus('completed_failed', refreshed, { reason: reason })];
1549
+ case 4:
1550
+ _a.sent();
1551
+ return [2 /*return*/];
1552
+ }
1553
+ });
1554
+ });
1555
+ };
1556
+ SlowQueryVerifier.prototype.maybeStopAutoOptimizeAfterFailure = function (logId, reason) {
1557
+ return __awaiter(this, void 0, void 0, function () {
1558
+ var maxAttempts, latest, attemptsUsed;
1559
+ return __generator(this, function (_a) {
1560
+ switch (_a.label) {
1561
+ case 0:
1562
+ if (!logId) {
1563
+ return [2 /*return*/];
1564
+ }
1565
+ maxAttempts = Number.isFinite(Number(this.config.autoOptimizeMaxAttemptsPerQuery))
1566
+ ? Number(this.config.autoOptimizeMaxAttemptsPerQuery)
1567
+ : 0;
1568
+ if (maxAttempts <= 0) {
1569
+ return [2 /*return*/];
1570
+ }
1571
+ return [4 /*yield*/, SlowQueryLogs.findOne({ _id: logId })];
1572
+ case 1:
1573
+ latest = _a.sent();
1574
+ if (!latest || latest.ignored) {
1575
+ return [2 /*return*/];
1576
+ }
1577
+ attemptsUsed = Number.isFinite(Number(latest.auto_fix_attempt_count))
1578
+ ? Number(latest.auto_fix_attempt_count)
1579
+ : 0;
1580
+ if (attemptsUsed < maxAttempts) {
1581
+ return [2 /*return*/];
1582
+ }
1583
+ return [4 /*yield*/, this.markAutoOptimizeBudgetExceeded(latest, reason)];
1584
+ case 2:
1585
+ _a.sent();
1586
+ return [2 /*return*/];
1587
+ }
1588
+ });
1589
+ });
1590
+ };
1591
+ SlowQueryVerifier.prototype.shouldFallbackDashboardMethod = function (error) {
1592
+ var message = "".concat((error === null || error === void 0 ? void 0 : error.message) || '').toLowerCase();
1593
+ return message.includes('not found')
1594
+ || message.includes('worker dispatch unavailable')
1595
+ || message.includes('no worker')
1596
+ || message.includes('unavailable for aidashboard');
1597
+ };
1598
+ SlowQueryVerifier.prototype.createDashboardJob = function (payload) {
1599
+ return __awaiter(this, void 0, void 0, function () {
1600
+ var methodManager, error_4, manager;
1601
+ return __generator(this, function (_a) {
1602
+ switch (_a.label) {
1603
+ case 0:
1604
+ methodManager = resolveio_server_app_1.ResolveIOServer.getMainServer().getMethodManager();
1605
+ _a.label = 1;
1606
+ case 1:
1607
+ _a.trys.push([1, 3, , 4]);
1608
+ return [4 /*yield*/, methodManager.callMethod('aiDashboardCreateJob', payload)];
1609
+ case 2: return [2 /*return*/, _a.sent()];
1610
+ case 3:
1611
+ error_4 = _a.sent();
1612
+ if (!this.shouldFallbackDashboardMethod(error_4)) {
1613
+ throw error_4;
1614
+ }
1615
+ return [3 /*break*/, 4];
1616
+ case 4:
1617
+ manager = resolveio_server_app_1.ResolveIOServer['AIDashboardManager'];
1618
+ if (!(manager && manager.isEnabled && manager.isEnabled())) return [3 /*break*/, 6];
1619
+ return [4 /*yield*/, manager.createJob(payload)];
1620
+ case 5: return [2 /*return*/, _a.sent()];
1621
+ case 6: throw new Error('AI Dashboard manager is not available.');
1622
+ }
1623
+ });
1624
+ });
1625
+ };
1626
+ SlowQueryVerifier.prototype.waitForDashboardJobStop = function (jobId, timeoutMs) {
1627
+ return __awaiter(this, void 0, void 0, function () {
1628
+ var methodManager, error_5, manager;
1629
+ return __generator(this, function (_a) {
1630
+ switch (_a.label) {
1631
+ case 0:
1632
+ methodManager = resolveio_server_app_1.ResolveIOServer.getMainServer().getMethodManager();
1633
+ _a.label = 1;
1634
+ case 1:
1635
+ _a.trys.push([1, 3, , 4]);
1636
+ return [4 /*yield*/, methodManager.callMethod('aiDashboardWaitForJobStop', jobId, timeoutMs)];
1637
+ case 2:
1638
+ _a.sent();
1639
+ return [2 /*return*/];
1640
+ case 3:
1641
+ error_5 = _a.sent();
1642
+ if (!this.shouldFallbackDashboardMethod(error_5)) {
1643
+ throw error_5;
1644
+ }
1645
+ return [3 /*break*/, 4];
1646
+ case 4:
1647
+ manager = resolveio_server_app_1.ResolveIOServer['AIDashboardManager'];
1648
+ if (!(manager && manager.isEnabled && manager.isEnabled())) return [3 /*break*/, 6];
1649
+ return [4 /*yield*/, manager.waitForJobStop(jobId, timeoutMs)];
1650
+ case 5:
1651
+ _a.sent();
1652
+ return [2 /*return*/];
1653
+ case 6: throw new Error('AI Dashboard manager is not available.');
1654
+ }
1655
+ });
1656
+ });
1657
+ };
1658
+ SlowQueryVerifier.prototype.isDashboardJobRunning = function (jobId) {
1659
+ return __awaiter(this, void 0, void 0, function () {
1660
+ var methodManager, running, error_6, manager;
1661
+ return __generator(this, function (_a) {
1662
+ switch (_a.label) {
1663
+ case 0:
1664
+ methodManager = resolveio_server_app_1.ResolveIOServer.getMainServer().getMethodManager();
1665
+ _a.label = 1;
1666
+ case 1:
1667
+ _a.trys.push([1, 3, , 4]);
1668
+ return [4 /*yield*/, methodManager.callMethod('aiDashboardIsJobRunning', jobId)];
1669
+ case 2:
1670
+ running = _a.sent();
1671
+ return [2 /*return*/, !!running];
1672
+ case 3:
1673
+ error_6 = _a.sent();
1674
+ if (!this.shouldFallbackDashboardMethod(error_6)) {
1675
+ throw error_6;
1676
+ }
1677
+ return [3 /*break*/, 4];
1678
+ case 4:
1679
+ manager = resolveio_server_app_1.ResolveIOServer['AIDashboardManager'];
1680
+ if (manager && manager.isEnabled && manager.isEnabled()) {
1681
+ return [2 /*return*/, !!manager.isJobRunning(jobId)];
1682
+ }
1683
+ throw new Error('AI Dashboard manager is not available.');
1684
+ }
1685
+ });
1686
+ });
1687
+ };
1688
+ SlowQueryVerifier.prototype.evaluateDashboardPublishOutcome = function (job) {
1689
+ var logEntries = Array.isArray(job === null || job === void 0 ? void 0 : job.log) ? job.log : [];
1690
+ var lastMatch = function (predicate) {
1691
+ for (var i = logEntries.length - 1; i >= 0; i -= 1) {
1692
+ if (predicate(logEntries[i] || '')) {
1693
+ return logEntries[i];
1694
+ }
1695
+ }
1696
+ return '';
1697
+ };
1698
+ var failureEntry = lastMatch(function (entry) { return /publish failed|artifact publish failed|deploy failed/i.test(entry || ''); });
1699
+ if (failureEntry) {
1700
+ return { success: false, message: failureEntry };
1701
+ }
1702
+ var publishEntry = lastMatch(function (entry) { return /Published build to /i.test(entry || ''); });
1703
+ if (publishEntry) {
1704
+ return { success: true, message: publishEntry };
1705
+ }
1706
+ var skippedEntry = lastMatch(function (entry) { return /Publish skipped/i.test(entry || ''); });
1707
+ if (skippedEntry) {
1708
+ return { success: false, message: skippedEntry };
1709
+ }
1710
+ return {
1711
+ success: false,
1712
+ message: 'Dashboard job completed without a publish confirmation log entry.'
1713
+ };
1714
+ };
1715
+ SlowQueryVerifier.prototype.resolveBaselineDurationMs = function (log) {
1716
+ var _a;
1717
+ var runs = Array.isArray(log.verification_runs) ? log.verification_runs : [];
1718
+ for (var i = runs.length - 1; i >= 0; i -= 1) {
1719
+ var duration = (_a = runs[i]) === null || _a === void 0 ? void 0 : _a.duration_ms;
1720
+ if (SlowQueryVerifier.isValidDuration(duration)) {
1721
+ return duration;
1722
+ }
1723
+ }
1724
+ if (SlowQueryVerifier.isValidDuration(log.duration_ms)) {
1725
+ return log.duration_ms;
1726
+ }
1727
+ if (SlowQueryVerifier.isValidDuration(log.avg_duration_ms)) {
1728
+ return log.avg_duration_ms;
1729
+ }
1730
+ return undefined;
1731
+ };
1732
+ SlowQueryVerifier.collectMetricValues = function (node, keySet, output) {
1733
+ if (!node || typeof node !== 'object') {
1734
+ return;
1735
+ }
1736
+ if (Array.isArray(node)) {
1737
+ node.forEach(function (entry) { return SlowQueryVerifier.collectMetricValues(entry, keySet, output); });
1738
+ return;
1739
+ }
1740
+ Object.keys(node).forEach(function (key) {
1741
+ var value = node[key];
1742
+ if (keySet.has(key) && typeof value === 'number' && Number.isFinite(value) && value >= 0) {
1743
+ output.push(value);
1744
+ }
1745
+ SlowQueryVerifier.collectMetricValues(value, keySet, output);
1746
+ });
1747
+ };
1748
+ SlowQueryVerifier.asNonNegativeNumber = function (value) {
1749
+ return typeof value === 'number' && Number.isFinite(value) && value >= 0
1750
+ ? value
1751
+ : undefined;
1752
+ };
1753
+ SlowQueryVerifier.maxNumber = function (values) {
1754
+ var candidates = values.filter(function (value) { return typeof value === 'number'; });
1755
+ return candidates.length ? Math.max.apply(Math, __spreadArray([], __read(candidates), false)) : undefined;
1756
+ };
1757
+ SlowQueryVerifier.sortStageSummaries = function (input) {
1758
+ return input.slice().sort(function (left, right) {
1759
+ var _a, _b, _c, _d, _e, _f;
1760
+ var timeDiff = ((_a = right.executionTimeMs) !== null && _a !== void 0 ? _a : -1) - ((_b = left.executionTimeMs) !== null && _b !== void 0 ? _b : -1);
1761
+ if (timeDiff !== 0) {
1762
+ return timeDiff;
1763
+ }
1764
+ var docsDiff = ((_c = right.docsExamined) !== null && _c !== void 0 ? _c : -1) - ((_d = left.docsExamined) !== null && _d !== void 0 ? _d : -1);
1765
+ if (docsDiff !== 0) {
1766
+ return docsDiff;
1767
+ }
1768
+ var keysDiff = ((_e = right.keysExamined) !== null && _e !== void 0 ? _e : -1) - ((_f = left.keysExamined) !== null && _f !== void 0 ? _f : -1);
1769
+ if (keysDiff !== 0) {
1770
+ return keysDiff;
1771
+ }
1772
+ return "".concat(left.path, "|").concat(left.stage).localeCompare("".concat(right.path, "|").concat(right.stage));
1773
+ });
1774
+ };
1775
+ SlowQueryVerifier.collectExecutionTreeStages = function (node, path, output) {
1776
+ if (!node || typeof node !== 'object') {
1777
+ return;
1778
+ }
1779
+ var stageName = typeof node.stage === 'string' ? node.stage : 'execution-stage';
1780
+ var executionTimeMs = SlowQueryVerifier.maxNumber([
1781
+ SlowQueryVerifier.asNonNegativeNumber(node.executionTimeMillis),
1782
+ SlowQueryVerifier.asNonNegativeNumber(node.executionTimeMillisEstimate)
1783
+ ]);
1784
+ var docsExamined = SlowQueryVerifier.maxNumber([
1785
+ SlowQueryVerifier.asNonNegativeNumber(node.totalDocsExamined),
1786
+ SlowQueryVerifier.asNonNegativeNumber(node.docsExamined)
1787
+ ]);
1788
+ var keysExamined = SlowQueryVerifier.maxNumber([
1789
+ SlowQueryVerifier.asNonNegativeNumber(node.totalKeysExamined),
1790
+ SlowQueryVerifier.asNonNegativeNumber(node.keysExamined)
1791
+ ]);
1792
+ var nReturned = SlowQueryVerifier.maxNumber([
1793
+ SlowQueryVerifier.asNonNegativeNumber(node.nReturned)
1794
+ ]);
1795
+ if (typeof executionTimeMs === 'number'
1796
+ || typeof docsExamined === 'number'
1797
+ || typeof keysExamined === 'number'
1798
+ || typeof nReturned === 'number') {
1799
+ output.push({
1800
+ stage: stageName,
1801
+ path: path || 'executionStats.executionStages',
1802
+ executionTimeMs: executionTimeMs,
1803
+ docsExamined: docsExamined,
1804
+ keysExamined: keysExamined,
1805
+ nReturned: nReturned
1806
+ });
1807
+ }
1808
+ var recurse = function (child, childPath) {
1809
+ if (!child) {
1810
+ return;
1811
+ }
1812
+ if (Array.isArray(child)) {
1813
+ child.forEach(function (entry, index) {
1814
+ SlowQueryVerifier.collectExecutionTreeStages(entry, "".concat(childPath, "[").concat(index, "]"), output);
1815
+ });
1816
+ return;
1817
+ }
1818
+ SlowQueryVerifier.collectExecutionTreeStages(child, childPath, output);
1819
+ };
1820
+ recurse(node.inputStage, "".concat(path, ".inputStage"));
1821
+ recurse(node.inputStages, "".concat(path, ".inputStages"));
1822
+ recurse(node.executionStages, "".concat(path, ".executionStages"));
1823
+ recurse(node.outerStage, "".concat(path, ".outerStage"));
1824
+ recurse(node.innerStage, "".concat(path, ".innerStage"));
1825
+ recurse(node.leftChild, "".concat(path, ".leftChild"));
1826
+ recurse(node.rightChild, "".concat(path, ".rightChild"));
1827
+ recurse(node.thenStage, "".concat(path, ".thenStage"));
1828
+ recurse(node.elseStage, "".concat(path, ".elseStage"));
1829
+ recurse(node.shards, "".concat(path, ".shards"));
1830
+ };
1831
+ SlowQueryVerifier.extractStageSummaries = function (explainResponse, explainStats) {
1832
+ var _a;
1833
+ var summaries = [];
1834
+ var stages = explainResponse === null || explainResponse === void 0 ? void 0 : explainResponse.stages;
1835
+ if (Array.isArray(stages)) {
1836
+ stages.forEach(function (stageEntry, index) {
1837
+ var _a;
1838
+ if (!stageEntry || typeof stageEntry !== 'object') {
1839
+ return;
1840
+ }
1841
+ var stageKey = Object.keys(stageEntry).find(function (key) { return key.startsWith('$'); }) || "stage_".concat(index);
1842
+ var stagePayload = stageEntry[stageKey];
1843
+ var metricsSource = stageKey === '$cursor' && (stagePayload === null || stagePayload === void 0 ? void 0 : stagePayload.executionStats)
1844
+ ? stagePayload.executionStats
1845
+ : stagePayload;
1846
+ var executionStages = (metricsSource === null || metricsSource === void 0 ? void 0 : metricsSource.executionStages) || ((_a = stagePayload === null || stagePayload === void 0 ? void 0 : stagePayload.executionStats) === null || _a === void 0 ? void 0 : _a.executionStages);
1847
+ var executionTimeMs = SlowQueryVerifier.maxNumber([
1848
+ SlowQueryVerifier.asNonNegativeNumber(metricsSource === null || metricsSource === void 0 ? void 0 : metricsSource.executionTimeMillis),
1849
+ SlowQueryVerifier.asNonNegativeNumber(metricsSource === null || metricsSource === void 0 ? void 0 : metricsSource.executionTimeMillisEstimate),
1850
+ SlowQueryVerifier.asNonNegativeNumber(executionStages === null || executionStages === void 0 ? void 0 : executionStages.executionTimeMillis),
1851
+ SlowQueryVerifier.asNonNegativeNumber(executionStages === null || executionStages === void 0 ? void 0 : executionStages.executionTimeMillisEstimate)
1852
+ ]);
1853
+ var docsExamined = SlowQueryVerifier.maxNumber([
1854
+ SlowQueryVerifier.asNonNegativeNumber(metricsSource === null || metricsSource === void 0 ? void 0 : metricsSource.totalDocsExamined),
1855
+ SlowQueryVerifier.asNonNegativeNumber(metricsSource === null || metricsSource === void 0 ? void 0 : metricsSource.docsExamined),
1856
+ SlowQueryVerifier.asNonNegativeNumber(executionStages === null || executionStages === void 0 ? void 0 : executionStages.totalDocsExamined),
1857
+ SlowQueryVerifier.asNonNegativeNumber(executionStages === null || executionStages === void 0 ? void 0 : executionStages.docsExamined)
1858
+ ]);
1859
+ var keysExamined = SlowQueryVerifier.maxNumber([
1860
+ SlowQueryVerifier.asNonNegativeNumber(metricsSource === null || metricsSource === void 0 ? void 0 : metricsSource.totalKeysExamined),
1861
+ SlowQueryVerifier.asNonNegativeNumber(metricsSource === null || metricsSource === void 0 ? void 0 : metricsSource.keysExamined),
1862
+ SlowQueryVerifier.asNonNegativeNumber(executionStages === null || executionStages === void 0 ? void 0 : executionStages.totalKeysExamined),
1863
+ SlowQueryVerifier.asNonNegativeNumber(executionStages === null || executionStages === void 0 ? void 0 : executionStages.keysExamined)
1864
+ ]);
1865
+ var nReturned = SlowQueryVerifier.maxNumber([
1866
+ SlowQueryVerifier.asNonNegativeNumber(metricsSource === null || metricsSource === void 0 ? void 0 : metricsSource.nReturned),
1867
+ SlowQueryVerifier.asNonNegativeNumber(executionStages === null || executionStages === void 0 ? void 0 : executionStages.nReturned)
1868
+ ]);
1869
+ if (typeof executionTimeMs === 'number'
1870
+ || typeof docsExamined === 'number'
1871
+ || typeof keysExamined === 'number'
1872
+ || typeof nReturned === 'number') {
1873
+ summaries.push({
1874
+ stage: stageKey,
1875
+ path: "stages[".concat(index, "]"),
1876
+ executionTimeMs: executionTimeMs,
1877
+ docsExamined: docsExamined,
1878
+ keysExamined: keysExamined,
1879
+ nReturned: nReturned
1880
+ });
1881
+ }
1882
+ if (executionStages) {
1883
+ SlowQueryVerifier.collectExecutionTreeStages(executionStages, "stages[".concat(index, "].").concat(stageKey, ".executionStages"), summaries);
1884
+ }
1885
+ });
1886
+ }
1887
+ var executionRoot = (explainStats === null || explainStats === void 0 ? void 0 : explainStats.executionStages)
1888
+ || ((_a = explainResponse === null || explainResponse === void 0 ? void 0 : explainResponse.executionStats) === null || _a === void 0 ? void 0 : _a.executionStages)
1889
+ || (explainResponse === null || explainResponse === void 0 ? void 0 : explainResponse.executionStats);
1890
+ if (executionRoot) {
1891
+ SlowQueryVerifier.collectExecutionTreeStages(executionRoot, 'executionStats.executionStages', summaries);
1892
+ }
1893
+ var deduped = new Map();
1894
+ summaries.forEach(function (summary) {
1895
+ var key = [
1896
+ summary.path,
1897
+ summary.stage,
1898
+ typeof summary.executionTimeMs === 'number' ? summary.executionTimeMs : '',
1899
+ typeof summary.docsExamined === 'number' ? summary.docsExamined : '',
1900
+ typeof summary.keysExamined === 'number' ? summary.keysExamined : '',
1901
+ typeof summary.nReturned === 'number' ? summary.nReturned : ''
1902
+ ].join('|');
1903
+ if (!deduped.has(key)) {
1904
+ deduped.set(key, summary);
1905
+ }
1906
+ });
1907
+ return SlowQueryVerifier.sortStageSummaries(Array.from(deduped.values()));
1908
+ };
1909
+ SlowQueryVerifier.prototype.resolveExecutionMetrics = function (explainStats, fallbackDuration, stageSummaries) {
1910
+ if (stageSummaries === void 0) { stageSummaries = []; }
1911
+ var docsCandidates = [];
1912
+ var returnedCandidates = [];
1913
+ SlowQueryVerifier.collectMetricValues(explainStats || {}, new Set(['totalDocsExamined', 'docsExamined']), docsCandidates);
1914
+ SlowQueryVerifier.collectMetricValues(explainStats || {}, new Set(['nReturned']), returnedCandidates);
1915
+ var stageDocsCandidates = stageSummaries
1916
+ .map(function (stage) { return stage.docsExamined; })
1917
+ .filter(function (value) { return typeof value === 'number'; });
1918
+ var stageReturnedCandidates = stageSummaries
1919
+ .map(function (stage) { return stage.nReturned; })
1920
+ .filter(function (value) { return typeof value === 'number'; });
1921
+ var docsExamined = docsCandidates.length
1922
+ ? Math.max.apply(Math, __spreadArray([], __read(docsCandidates), false)) : (stageDocsCandidates.length ? Math.max.apply(Math, __spreadArray([], __read(stageDocsCandidates), false)) : undefined);
1923
+ var nReturned = returnedCandidates.length
1924
+ ? Math.max.apply(Math, __spreadArray([], __read(returnedCandidates), false)) : (stageReturnedCandidates.length ? Math.max.apply(Math, __spreadArray([], __read(stageReturnedCandidates), false)) : undefined);
1925
+ var durationMs = SlowQueryVerifier.isValidDuration(fallbackDuration)
1926
+ ? fallbackDuration
1927
+ : undefined;
1928
+ return {
1929
+ durationMs: durationMs,
1930
+ docsExamined: docsExamined,
1931
+ nReturned: nReturned,
1932
+ topStages: stageSummaries.slice(0, 5)
1933
+ };
1934
+ };
1935
+ SlowQueryVerifier.prototype.evaluateOptimizationOutcome = function (baseline, after, outputEquivalence) {
1936
+ if (outputEquivalence && !outputEquivalence.passed) {
1937
+ return {
1938
+ passed: false,
1939
+ reason: "Output equivalence failed: ".concat(outputEquivalence.reason),
1940
+ outputEquivalence: outputEquivalence
1941
+ };
1942
+ }
1943
+ if (!SlowQueryVerifier.isValidDuration(baseline.durationMs) || !SlowQueryVerifier.isValidDuration(after.durationMs)) {
1944
+ return {
1945
+ passed: false,
1946
+ reason: 'Unable to compare baseline and post-fix duration.',
1947
+ outputEquivalence: outputEquivalence
1948
+ };
1949
+ }
1950
+ var durationRatio = baseline.durationMs > 0 ? (after.durationMs / baseline.durationMs) : 1;
1951
+ if (durationRatio > this.config.autoOptimizeDurationRatioTarget) {
1952
+ return {
1953
+ passed: false,
1954
+ reason: "Duration did not improve enough (".concat((0, common_1.round)(durationRatio * 100, 0), "% of baseline)."),
1955
+ durationRatio: durationRatio,
1956
+ outputEquivalence: outputEquivalence
1957
+ };
1958
+ }
1959
+ if (typeof baseline.docsExamined !== 'number' || typeof after.docsExamined !== 'number' || baseline.docsExamined <= 0) {
1960
+ return {
1961
+ passed: false,
1962
+ reason: 'Docs examined metrics are missing for baseline or post-fix explain.',
1963
+ durationRatio: durationRatio,
1964
+ outputEquivalence: outputEquivalence
1965
+ };
1966
+ }
1967
+ var docsRatio = after.docsExamined / baseline.docsExamined;
1968
+ if (docsRatio > this.config.autoOptimizeDocsRatioTarget) {
1969
+ return {
1970
+ passed: false,
1971
+ reason: "Docs examined did not improve enough (".concat((0, common_1.round)(docsRatio * 100, 0), "% of baseline)."),
1972
+ durationRatio: durationRatio,
1973
+ docsRatio: docsRatio,
1974
+ outputEquivalence: outputEquivalence
1975
+ };
1976
+ }
1977
+ if (typeof baseline.nReturned === 'number' && typeof after.nReturned === 'number') {
1978
+ var denominator = Math.max(baseline.nReturned, 1);
1979
+ var nReturnedDeltaRatio = Math.abs(after.nReturned - baseline.nReturned) / denominator;
1980
+ if (nReturnedDeltaRatio > this.config.autoOptimizeReturnedDocsTolerance) {
1981
+ return {
1982
+ passed: false,
1983
+ reason: "Returned document count changed too much (".concat((0, common_1.round)(nReturnedDeltaRatio * 100, 0), "% delta)."),
1984
+ durationRatio: durationRatio,
1985
+ docsRatio: docsRatio,
1986
+ nReturnedDeltaRatio: nReturnedDeltaRatio,
1987
+ outputEquivalence: outputEquivalence
1988
+ };
1989
+ }
1990
+ return {
1991
+ passed: true,
1992
+ reason: 'Query performance improved while keeping returned document count stable.',
1993
+ durationRatio: durationRatio,
1994
+ docsRatio: docsRatio,
1995
+ nReturnedDeltaRatio: nReturnedDeltaRatio,
1996
+ outputEquivalence: outputEquivalence
1997
+ };
1998
+ }
1999
+ return {
2000
+ passed: false,
2001
+ reason: 'Returned document metrics are missing for baseline or post-fix explain.',
2002
+ durationRatio: durationRatio,
2003
+ docsRatio: docsRatio,
2004
+ outputEquivalence: outputEquivalence
2005
+ };
2006
+ };
2007
+ SlowQueryVerifier.prototype.formatStageSummaryForPrompt = function (stage, index) {
2008
+ var metrics = [];
2009
+ if (typeof stage.executionTimeMs === 'number') {
2010
+ metrics.push("time=".concat(stage.executionTimeMs, "ms"));
2011
+ }
2012
+ if (typeof stage.docsExamined === 'number') {
2013
+ metrics.push("docs=".concat(stage.docsExamined));
2014
+ }
2015
+ if (typeof stage.keysExamined === 'number') {
2016
+ metrics.push("keys=".concat(stage.keysExamined));
2017
+ }
2018
+ if (typeof stage.nReturned === 'number') {
2019
+ metrics.push("returned=".concat(stage.nReturned));
2020
+ }
2021
+ return "".concat(index + 1, ". ").concat(stage.stage, " @ ").concat(stage.path).concat(metrics.length ? " (".concat(metrics.join(', '), ")") : '');
2022
+ };
2023
+ SlowQueryVerifier.prototype.buildSlowQueryAutoOptimizeDescription = function (log, app, baseline) {
2024
+ var _this = this;
2025
+ var topStages = Array.isArray(baseline.topStages) ? baseline.topStages : [];
2026
+ var lookupExprInCount = SlowQueryVerifier.countLookupExprInPattern(Array.isArray(log.pipeline) ? log.pipeline : []);
2027
+ var lines = __spreadArray(__spreadArray([
2028
+ 'Autonomous slow-query optimization request.',
2029
+ '',
2030
+ 'Hard requirements:',
2031
+ '1. Before changing code, query the project MongoDB diagnostics logs for the latest slow-query context.',
2032
+ '2. Query `slow-query-logs` using `_id` and `query_hash` from this task, then use the newest matching records.',
2033
+ '3. If a previous dashboard job id is provided, query `ai-development-jobs` by that `_id` and review recent failure logs before retrying.',
2034
+ '4. Treat `.dashboard-output/build-*.log` as primary build evidence, and `.build-output/build-*.log` as retained history when diagnosing failures.',
2035
+ '5. Locate the source query in app code and optimize it safely (query shape contract must remain compatible).',
2036
+ '6. Add or adjust indexes/code paths so docs examined and processing time drop significantly.',
2037
+ '7. Measure before/after `explain(\"executionStats\")` and identify the slowest stages by execution time/docs examined.',
2038
+ '8. Keep returned data behavior stable for existing consumers (output fingerprint + row count must remain equivalent).',
2039
+ '9. In `$lookup`, avoid `$expr` + `$in` when equivalent `localField` / `foreignField` joins are possible and index-friendly.',
2040
+ '10. Run build/lint checks and iterate until green.',
2041
+ '11. Publish to default branch and deploy artifacts automatically after build success.',
2042
+ '',
2043
+ "App: ".concat(app.name || app._id),
2044
+ "Repo: ".concat(app.repo || 'unknown'),
2045
+ "Slow Query #: ".concat(log.slow_query_count_string || log._id || ''),
2046
+ "Collection: ".concat(log.collection),
2047
+ "Query Hash: ".concat(log.query_hash),
2048
+ "Slow Query Log Id: ".concat(String((log === null || log === void 0 ? void 0 : log._id) || '').trim() || 'n/a'),
2049
+ "Previous Dashboard Job Id: ".concat(String((log === null || log === void 0 ? void 0 : log.openai_task_id) || '').trim() || 'n/a'),
2050
+ "Source App: ".concat(log.source_app || 'n/a'),
2051
+ "Environment: ".concat(log.environment || 'n/a'),
2052
+ "Baseline Duration (ms): ".concat(typeof baseline.durationMs === 'number' ? baseline.durationMs : 'unknown'),
2053
+ "Baseline Docs Examined: ".concat(typeof baseline.docsExamined === 'number' ? baseline.docsExamined : 'unknown'),
2054
+ "Baseline Returned Docs: ".concat(typeof baseline.nReturned === 'number' ? baseline.nReturned : 'unknown'),
2055
+ "Detected $lookup with $expr+$in: ".concat(lookupExprInCount),
2056
+ '',
2057
+ 'Baseline Hot Stages:'
2058
+ ], __read((topStages.length
2059
+ ? topStages.map(function (stage, index) { return _this.formatStageSummaryForPrompt(stage, index); })
2060
+ : ['No stage-level metrics were captured.'])), false), [
2061
+ '',
2062
+ 'Filter:',
2063
+ '```json',
2064
+ JSON.stringify(log.filter || {}, null, 2),
2065
+ '```',
2066
+ '',
2067
+ 'Pipeline:',
2068
+ '```json',
2069
+ JSON.stringify(Array.isArray(log.pipeline) ? log.pipeline : [], null, 2),
2070
+ '```',
2071
+ '',
2072
+ 'Options:',
2073
+ '```json',
2074
+ JSON.stringify(log.options || {}, null, 2),
2075
+ '```'
2076
+ ], false);
2077
+ return lines.join('\n');
2078
+ };
2079
+ SlowQueryVerifier.queryHasExplicitSort = function (pipeline, findOptions) {
2080
+ var hasFindSort = !!((findOptions === null || findOptions === void 0 ? void 0 : findOptions.sort) && typeof findOptions.sort === 'object' && Object.keys(findOptions.sort).length);
2081
+ if (hasFindSort) {
2082
+ return true;
2083
+ }
2084
+ if (!Array.isArray(pipeline)) {
2085
+ return false;
2086
+ }
2087
+ return pipeline.some(function (stage) {
2088
+ if (!stage || typeof stage !== 'object') {
2089
+ return false;
2090
+ }
2091
+ var sort = stage.$sort;
2092
+ return !!(sort && typeof sort === 'object' && Object.keys(sort).length);
2093
+ });
2094
+ };
2095
+ SlowQueryVerifier.countLookupExprInPattern = function (pipeline) {
2096
+ if (!Array.isArray(pipeline)) {
2097
+ return 0;
2098
+ }
2099
+ var count = 0;
2100
+ pipeline.forEach(function (stage) {
2101
+ var lookup = stage && typeof stage === 'object' ? stage.$lookup : undefined;
2102
+ if (!lookup || typeof lookup !== 'object' || !Array.isArray(lookup.pipeline)) {
2103
+ return;
2104
+ }
2105
+ var lookupPipelineJson = JSON.stringify(lookup.pipeline);
2106
+ if (lookupPipelineJson.includes('"$expr"') && lookupPipelineJson.includes('"$in"')) {
2107
+ count += 1;
2108
+ }
2109
+ });
2110
+ return count;
2111
+ };
2112
+ SlowQueryVerifier.buildBoundedPipelineForOutputCompare = function (pipeline, maxDocs) {
2113
+ var cloned = SlowQueryVerifier.deepClone(pipeline);
2114
+ if (!Number.isFinite(maxDocs) || maxDocs <= 0) {
2115
+ return cloned;
2116
+ }
2117
+ cloned.push({
2118
+ $limit: maxDocs + 1
2119
+ });
2120
+ return cloned;
2121
+ };
2122
+ SlowQueryVerifier.buildBoundedFindOptionsForOutputCompare = function (findOptions, maxDocs) {
2123
+ var bounded = findOptions ? SlowQueryVerifier.deepClone(findOptions) : {};
2124
+ if (!Number.isFinite(maxDocs) || maxDocs <= 0) {
2125
+ return Object.keys(bounded).length ? bounded : undefined;
2126
+ }
2127
+ var compareLimit = maxDocs + 1;
2128
+ if (typeof bounded.limit === 'number' && bounded.limit > 0) {
2129
+ bounded.limit = Math.min(bounded.limit, compareLimit);
2130
+ }
2131
+ else {
2132
+ bounded.limit = compareLimit;
2133
+ }
2134
+ return Object.keys(bounded).length ? bounded : undefined;
2135
+ };
2136
+ SlowQueryVerifier.normalizeOutputValue = function (value) {
2137
+ if (value === null) {
2138
+ return null;
2139
+ }
2140
+ if (typeof value === 'undefined') {
2141
+ return null;
2142
+ }
2143
+ if (value instanceof Date) {
2144
+ return { $date: value.toISOString() };
2145
+ }
2146
+ if (Buffer.isBuffer(value)) {
2147
+ return { $binary: value.toString('base64') };
2148
+ }
2149
+ var valueType = typeof value;
2150
+ if (valueType === 'string' || valueType === 'boolean') {
2151
+ return value;
2152
+ }
2153
+ if (valueType === 'number') {
2154
+ if (!Number.isFinite(value)) {
2155
+ return '__non_finite_number__';
2156
+ }
2157
+ return value;
2158
+ }
2159
+ if (valueType === 'bigint') {
2160
+ return value.toString();
2161
+ }
2162
+ if (valueType === 'function') {
2163
+ return '__function__';
2164
+ }
2165
+ if (Array.isArray(value)) {
2166
+ return value.map(function (entry) { return SlowQueryVerifier.normalizeOutputValue(entry); });
2167
+ }
2168
+ if (valueType === 'object') {
2169
+ if (typeof value.toHexString === 'function') {
2170
+ try {
2171
+ return { $oid: value.toHexString() };
2172
+ }
2173
+ catch (_a) {
2174
+ // continue into generic object handling
2175
+ }
2176
+ }
2177
+ if (typeof value.toJSON === 'function') {
2178
+ try {
2179
+ return SlowQueryVerifier.normalizeOutputValue(value.toJSON());
2180
+ }
2181
+ catch (_b) {
2182
+ // continue into generic object handling
2183
+ }
2184
+ }
2185
+ var normalized_1 = {};
2186
+ Object.keys(value).sort().forEach(function (key) {
2187
+ normalized_1[key] = SlowQueryVerifier.normalizeOutputValue(value[key]);
2188
+ });
2189
+ return normalized_1;
2190
+ }
2191
+ return "".concat(value);
2192
+ };
2193
+ SlowQueryVerifier.digestOutputDocument = function (doc) {
2194
+ var normalized = SlowQueryVerifier.normalizeOutputValue(doc);
2195
+ var serialized = JSON.stringify(normalized);
2196
+ return (0, crypto_1.createHash)('sha256').update(serialized, 'utf8').digest('hex');
2197
+ };
2198
+ SlowQueryVerifier.prototype.captureOutputFingerprint = function (log, overrides) {
2199
+ return __awaiter(this, void 0, void 0, function () {
2200
+ var collectionName, target, client, db, maxDocs, effectiveMaxDocs, effectiveLog, pipeline, filter, findOptions, aggregateOptions, explicitSort, cursor, boundedPipeline, boundedFindOptions, orderedHasher, unorderedSum, unorderedXor, docsCompared, truncated, firstDocDigest, lastDocDigest, startedAt, _a, cursor_1, cursor_1_1, doc, docDigest, head, tail, e_5_1, durationMs;
2201
+ var _b, e_5, _c, _d;
2202
+ var _e;
2203
+ return __generator(this, function (_f) {
2204
+ switch (_f.label) {
2205
+ case 0:
2206
+ collectionName = log.collection;
2207
+ if (!collectionName) {
2208
+ throw new Error('Slow query missing collection name.');
2209
+ }
2210
+ return [4 /*yield*/, this.resolveExplainTarget(log)];
2211
+ case 1:
2212
+ target = _f.sent();
2213
+ _f.label = 2;
2214
+ case 2:
2215
+ _f.trys.push([2, , 23, 26]);
2216
+ if (!(target.type === 'client')) return [3 /*break*/, 4];
2217
+ if (!target.uri) {
2218
+ throw new SlowQueryVerifierError('client_db_missing_uri', 'Client DB missing uri.');
2219
+ }
2220
+ return [4 /*yield*/, mongodb_1.MongoClient.connect(target.uri, {
2221
+ connectTimeoutMS: 10000,
2222
+ serverSelectionTimeoutMS: 10000,
2223
+ readPreference: 'secondaryPreferred'
2224
+ })];
2225
+ case 3:
2226
+ client = _f.sent();
2227
+ db = client.db(target.dbName);
2228
+ return [3 /*break*/, 5];
2229
+ case 4:
2230
+ db = resolveio_server_app_1.ResolveIOServer.getMainDB();
2231
+ _f.label = 5;
2232
+ case 5:
2233
+ if (!db) {
2234
+ throw new SlowQueryVerifierError('main_db_unavailable', 'Main server DB is not available.');
2235
+ }
2236
+ maxDocs = Number.isFinite(Number(this.config.autoOptimizeOutputCompareMaxDocs))
2237
+ ? Number(this.config.autoOptimizeOutputCompareMaxDocs)
2238
+ : AUTO_OPTIMIZE_DEFAULT_OUTPUT_COMPARE_MAX_DOCS;
2239
+ effectiveMaxDocs = maxDocs > 0 ? Math.floor(maxDocs) : AUTO_OPTIMIZE_DEFAULT_OUTPUT_COMPARE_MAX_DOCS;
2240
+ effectiveLog = SlowQueryVerifier.applyQueryOverrides(log, overrides);
2241
+ pipeline = SlowQueryVerifier.extractPipelineFromLog(effectiveLog);
2242
+ filter = (_e = effectiveLog.filter) !== null && _e !== void 0 ? _e : {};
2243
+ findOptions = SlowQueryVerifier.extractFindOptions(effectiveLog.options);
2244
+ aggregateOptions = SlowQueryVerifier.extractAggregateOptions(effectiveLog.options);
2245
+ explicitSort = SlowQueryVerifier.queryHasExplicitSort(pipeline, findOptions);
2246
+ cursor = void 0;
2247
+ if (pipeline) {
2248
+ if (SlowQueryVerifier.pipelineHasWriteStage(pipeline)) {
2249
+ throw new SlowQueryVerifierError('aggregate_write_stage', 'Aggregate pipeline includes a write stage; output comparison skipped.');
2250
+ }
2251
+ boundedPipeline = SlowQueryVerifier.buildBoundedPipelineForOutputCompare(pipeline, effectiveMaxDocs);
2252
+ cursor = db.collection(collectionName)
2253
+ .aggregate(boundedPipeline, __assign(__assign({}, (aggregateOptions || {})), { readPreference: 'secondaryPreferred' }));
2254
+ }
2255
+ else {
2256
+ boundedFindOptions = SlowQueryVerifier.buildBoundedFindOptionsForOutputCompare(findOptions, effectiveMaxDocs);
2257
+ cursor = SlowQueryVerifier.buildFindCursor(db.collection(collectionName), filter, boundedFindOptions);
2258
+ }
2259
+ orderedHasher = (0, crypto_1.createHash)('sha256');
2260
+ unorderedSum = 0;
2261
+ unorderedXor = 0;
2262
+ docsCompared = 0;
2263
+ truncated = false;
2264
+ firstDocDigest = '';
2265
+ lastDocDigest = '';
2266
+ startedAt = Date.now();
2267
+ _f.label = 6;
2268
+ case 6:
2269
+ _f.trys.push([6, , 19, 22]);
2270
+ _f.label = 7;
2271
+ case 7:
2272
+ _f.trys.push([7, 12, 13, 18]);
2273
+ _a = true, cursor_1 = __asyncValues(cursor);
2274
+ _f.label = 8;
2275
+ case 8: return [4 /*yield*/, cursor_1.next()];
2276
+ case 9:
2277
+ if (!(cursor_1_1 = _f.sent(), _b = cursor_1_1.done, !_b)) return [3 /*break*/, 11];
2278
+ _d = cursor_1_1.value;
2279
+ _a = false;
2280
+ doc = _d;
2281
+ if (docsCompared >= effectiveMaxDocs) {
2282
+ truncated = true;
2283
+ return [3 /*break*/, 11];
2284
+ }
2285
+ docDigest = SlowQueryVerifier.digestOutputDocument(doc);
2286
+ if (!firstDocDigest) {
2287
+ firstDocDigest = docDigest;
2288
+ }
2289
+ lastDocDigest = docDigest;
2290
+ orderedHasher.update(docDigest, 'utf8');
2291
+ head = (parseInt(docDigest.slice(0, 8), 16) ^ parseInt(docDigest.slice(8, 16), 16)) >>> 0;
2292
+ tail = (parseInt(docDigest.slice(16, 24), 16) ^ parseInt(docDigest.slice(24, 32), 16)) >>> 0;
2293
+ unorderedSum = (unorderedSum + head + tail) >>> 0;
2294
+ unorderedXor = (unorderedXor ^ head ^ tail) >>> 0;
2295
+ docsCompared += 1;
2296
+ _f.label = 10;
2297
+ case 10:
2298
+ _a = true;
2299
+ return [3 /*break*/, 8];
2300
+ case 11: return [3 /*break*/, 18];
2301
+ case 12:
2302
+ e_5_1 = _f.sent();
2303
+ e_5 = { error: e_5_1 };
2304
+ return [3 /*break*/, 18];
2305
+ case 13:
2306
+ _f.trys.push([13, , 16, 17]);
2307
+ if (!(!_a && !_b && (_c = cursor_1.return))) return [3 /*break*/, 15];
2308
+ return [4 /*yield*/, _c.call(cursor_1)];
2309
+ case 14:
2310
+ _f.sent();
2311
+ _f.label = 15;
2312
+ case 15: return [3 /*break*/, 17];
2313
+ case 16:
2314
+ if (e_5) throw e_5.error;
2315
+ return [7 /*endfinally*/];
2316
+ case 17: return [7 /*endfinally*/];
2317
+ case 18: return [3 /*break*/, 22];
2318
+ case 19:
2319
+ if (!(cursor && typeof cursor.close === 'function')) return [3 /*break*/, 21];
2320
+ return [4 /*yield*/, cursor.close()];
2321
+ case 20:
2322
+ _f.sent();
2323
+ _f.label = 21;
2324
+ case 21: return [7 /*endfinally*/];
2325
+ case 22:
2326
+ durationMs = Date.now() - startedAt;
2327
+ return [2 /*return*/, {
2328
+ explicitSort: explicitSort,
2329
+ docsCompared: docsCompared,
2330
+ truncated: truncated,
2331
+ orderedDigest: orderedHasher.digest('hex'),
2332
+ unorderedDigest: "".concat(unorderedSum.toString(16).padStart(8, '0'), ":").concat(unorderedXor.toString(16).padStart(8, '0')),
2333
+ firstDocDigest: firstDocDigest,
2334
+ lastDocDigest: lastDocDigest,
2335
+ durationMs: SlowQueryVerifier.isValidDuration(durationMs) ? durationMs : -1,
2336
+ maxDocs: effectiveMaxDocs
2337
+ }];
2338
+ case 23:
2339
+ if (!client) return [3 /*break*/, 25];
2340
+ return [4 /*yield*/, client.close()];
2341
+ case 24:
2342
+ _f.sent();
2343
+ _f.label = 25;
2344
+ case 25: return [7 /*endfinally*/];
2345
+ case 26: return [2 /*return*/];
2346
+ }
2347
+ });
2348
+ });
2349
+ };
2350
+ SlowQueryVerifier.prototype.compareOutputEquivalence = function (baseline, after) {
2351
+ var mode = (baseline.explicitSort || after.explicitSort)
2352
+ ? 'ordered'
2353
+ : 'unordered';
2354
+ if (baseline.truncated || after.truncated) {
2355
+ return {
2356
+ passed: false,
2357
+ reason: "Result set exceeded output comparison cap (".concat(Math.max(baseline.maxDocs, after.maxDocs), " docs)."),
2358
+ mode: mode,
2359
+ baseline: baseline,
2360
+ after: after
2361
+ };
2362
+ }
2363
+ if (baseline.docsCompared !== after.docsCompared) {
2364
+ return {
2365
+ passed: false,
2366
+ reason: "Returned row count changed (".concat(baseline.docsCompared, " -> ").concat(after.docsCompared, ")."),
2367
+ mode: mode,
2368
+ baseline: baseline,
2369
+ after: after
2370
+ };
2371
+ }
2372
+ if (mode === 'ordered') {
2373
+ if (baseline.orderedDigest !== after.orderedDigest) {
2374
+ return {
2375
+ passed: false,
2376
+ reason: 'Ordered output digest changed.',
2377
+ mode: mode,
2378
+ baseline: baseline,
2379
+ after: after
2380
+ };
2381
+ }
2382
+ }
2383
+ else if (baseline.unorderedDigest !== after.unorderedDigest) {
2384
+ return {
2385
+ passed: false,
2386
+ reason: 'Output set digest changed.',
2387
+ mode: mode,
2388
+ baseline: baseline,
2389
+ after: after
2390
+ };
2391
+ }
2392
+ return {
2393
+ passed: true,
2394
+ reason: 'Output fingerprints are equivalent.',
2395
+ mode: mode,
2396
+ baseline: baseline,
2397
+ after: after
2398
+ };
2399
+ };
2400
+ SlowQueryVerifier.prototype.resolveAutoOptimizeApp = function (log) {
2401
+ return __awaiter(this, void 0, void 0, function () {
2402
+ var exactRepoCandidate, escaped, byRepo, clientCandidates, clientCandidates_1, clientCandidates_1_1, candidate, escaped, byApp, clientDoc, byClient, e_6_1;
2403
+ var e_6, _a;
2404
+ return __generator(this, function (_b) {
2405
+ switch (_b.label) {
2406
+ case 0:
2407
+ exactRepoCandidate = String(log.environment || '').trim();
2408
+ if (!(exactRepoCandidate && exactRepoCandidate.includes('/'))) return [3 /*break*/, 2];
2409
+ escaped = this.escapeRegex(exactRepoCandidate);
2410
+ return [4 /*yield*/, AICoderApps.findOne({
2411
+ repo: { $regex: "^".concat(escaped, "$"), $options: 'i' }
2412
+ }, {
2413
+ sort: {
2414
+ updatedAt: -1,
2415
+ createdAt: -1
2416
+ }
2417
+ })];
2418
+ case 1:
2419
+ byRepo = _b.sent();
2420
+ if (byRepo) {
2421
+ return [2 /*return*/, byRepo];
2422
+ }
2423
+ _b.label = 2;
2424
+ case 2:
2425
+ clientCandidates = [
2426
+ String(log.client_slug || '').trim(),
2427
+ String(log.client_name || '').trim(),
2428
+ String(log.source_app || '').trim()
2429
+ ].filter(Boolean);
2430
+ _b.label = 3;
2431
+ case 3:
2432
+ _b.trys.push([3, 10, 11, 12]);
2433
+ clientCandidates_1 = __values(clientCandidates), clientCandidates_1_1 = clientCandidates_1.next();
2434
+ _b.label = 4;
2435
+ case 4:
2436
+ if (!!clientCandidates_1_1.done) return [3 /*break*/, 9];
2437
+ candidate = clientCandidates_1_1.value;
2438
+ escaped = this.escapeRegex(candidate);
2439
+ return [4 /*yield*/, AICoderApps.findOne({
2440
+ $or: [
2441
+ { slug: { $regex: "^".concat(escaped, "$"), $options: 'i' } },
2442
+ { name: { $regex: "^".concat(escaped, "$"), $options: 'i' } }
2443
+ ]
2444
+ }, {
2445
+ sort: {
2446
+ updatedAt: -1,
2447
+ createdAt: -1
2448
+ }
2449
+ })];
2450
+ case 5:
2451
+ byApp = _b.sent();
2452
+ if (byApp) {
2453
+ return [2 /*return*/, byApp];
2454
+ }
2455
+ return [4 /*yield*/, Clients.findOne({
2456
+ $or: [
2457
+ { name: { $regex: "^".concat(escaped, "$"), $options: 'i' } },
2458
+ { demo_name: { $regex: "^".concat(escaped, "$"), $options: 'i' } },
2459
+ { project: { $regex: "^".concat(escaped, "$"), $options: 'i' } },
2460
+ { repo: { $regex: "^".concat(escaped, "$"), $options: 'i' } }
2461
+ ]
2462
+ })];
2463
+ case 6:
2464
+ clientDoc = _b.sent();
2465
+ if (!(clientDoc === null || clientDoc === void 0 ? void 0 : clientDoc._id)) {
2466
+ return [3 /*break*/, 8];
2467
+ }
2468
+ return [4 /*yield*/, AICoderApps.findOne({ client_id: clientDoc._id }, {
2469
+ sort: {
2470
+ updatedAt: -1,
2471
+ createdAt: -1
2472
+ }
2473
+ })];
2474
+ case 7:
2475
+ byClient = _b.sent();
2476
+ if (byClient) {
2477
+ return [2 /*return*/, byClient];
2478
+ }
2479
+ _b.label = 8;
2480
+ case 8:
2481
+ clientCandidates_1_1 = clientCandidates_1.next();
2482
+ return [3 /*break*/, 4];
2483
+ case 9: return [3 /*break*/, 12];
2484
+ case 10:
2485
+ e_6_1 = _b.sent();
2486
+ e_6 = { error: e_6_1 };
2487
+ return [3 /*break*/, 12];
2488
+ case 11:
2489
+ try {
2490
+ if (clientCandidates_1_1 && !clientCandidates_1_1.done && (_a = clientCandidates_1.return)) _a.call(clientCandidates_1);
2491
+ }
2492
+ finally { if (e_6) throw e_6.error; }
2493
+ return [7 /*endfinally*/];
2494
+ case 12: return [2 /*return*/, null];
2495
+ }
2496
+ });
2497
+ });
2498
+ };
2499
+ SlowQueryVerifier.prototype.runAutoOptimization = function (logId) {
2500
+ return __awaiter(this, void 0, void 0, function () {
2501
+ var log, attemptsUsed, maxAttempts, cooldownDeadline, fingerprintMaxAttempts, windowHours, windowStart, fingerprintAttempts, app, tokenEligibility, reason, baselineExplain, error_7, baselineFallbackDuration, baselineDurationMs, baselineMetrics, baselineOutputFingerprint, error_8, title, description, job, error_9, jobId, attemptStartedAt, queuedLog, error_10, isRunning, error_11, finalJob, publishOutcome, refreshedLog, afterExplain, error_12, afterMetrics, outputEquivalence, afterOutputFingerprint, error_13, validation, autoFixResult, optimizedLog;
2502
+ return __generator(this, function (_a) {
2503
+ switch (_a.label) {
2504
+ case 0:
2505
+ if (!logId || !this.config.autoOptimizeEnabled) {
2506
+ return [2 /*return*/];
2507
+ }
2508
+ return [4 /*yield*/, SlowQueryLogs.findOne({ _id: logId })];
2509
+ case 1:
2510
+ log = _a.sent();
2511
+ if (!log || !log._id || log.ignored) {
2512
+ return [2 /*return*/];
2513
+ }
2514
+ if (log.status === 'optimized') {
2515
+ return [2 /*return*/];
2516
+ }
2517
+ if (log.auto_fix_status === 'running' || log.auto_fix_status === 'queued') {
2518
+ return [2 /*return*/];
2519
+ }
2520
+ attemptsUsed = Number.isFinite(Number(log.auto_fix_attempt_count))
2521
+ ? Number(log.auto_fix_attempt_count)
2522
+ : 0;
2523
+ maxAttempts = Number.isFinite(Number(this.config.autoOptimizeMaxAttemptsPerQuery))
2524
+ ? Number(this.config.autoOptimizeMaxAttemptsPerQuery)
2525
+ : 0;
2526
+ if (!(maxAttempts > 0 && attemptsUsed >= maxAttempts)) return [3 /*break*/, 3];
2527
+ return [4 /*yield*/, this.markAutoOptimizeBudgetExceeded(log, 'Auto optimize skipped')];
2528
+ case 2:
2529
+ _a.sent();
2530
+ return [2 /*return*/];
2531
+ case 3:
2532
+ cooldownDeadline = this.resolveCooldownDeadline(log);
2533
+ if (!(cooldownDeadline && cooldownDeadline.getTime() > Date.now())) return [3 /*break*/, 5];
2534
+ return [4 /*yield*/, this.markAutoOptimizeCooldownActive(log, cooldownDeadline)];
2535
+ case 4:
2536
+ _a.sent();
2537
+ return [2 /*return*/];
2538
+ case 5:
2539
+ fingerprintMaxAttempts = Number.isFinite(Number(this.config.autoOptimizeMaxAttemptsPerFingerprint))
2540
+ ? Number(this.config.autoOptimizeMaxAttemptsPerFingerprint)
2541
+ : 0;
2542
+ if (!(fingerprintMaxAttempts > 0)) return [3 /*break*/, 8];
2543
+ windowHours = Number.isFinite(Number(this.config.autoOptimizeFingerprintWindowHours))
2544
+ ? Number(this.config.autoOptimizeFingerprintWindowHours)
2545
+ : AUTO_OPTIMIZE_DEFAULT_FINGERPRINT_WINDOW_HOURS;
2546
+ windowStart = new Date(Date.now() - (windowHours * 60 * 60 * 1000));
2547
+ return [4 /*yield*/, this.resolveFingerprintAttemptsInWindow(log, windowStart)];
2548
+ case 6:
2549
+ fingerprintAttempts = _a.sent();
2550
+ if (!(fingerprintAttempts >= fingerprintMaxAttempts)) return [3 /*break*/, 8];
2551
+ return [4 /*yield*/, this.markAutoOptimizeBudgetExceeded(log, "Auto optimize skipped: fingerprint budget reached (".concat(fingerprintAttempts, "/").concat(fingerprintMaxAttempts, ") in the last ").concat(windowHours, "h."))];
2552
+ case 7:
2553
+ _a.sent();
2554
+ return [2 /*return*/];
2555
+ case 8: return [4 /*yield*/, this.resolveAutoOptimizeApp(log)];
2556
+ case 9:
2557
+ app = _a.sent();
2558
+ if (!(!(app === null || app === void 0 ? void 0 : app._id) || !app.repo)) return [3 /*break*/, 11];
2559
+ return [4 /*yield*/, SlowQueryLogs.updateOne({ _id: logId }, {
2560
+ $set: {
2561
+ status: 'investigating',
2562
+ auto_fix_status: 'failed',
2563
+ verification_notes: 'Auto optimize skipped: unable to map slow query to AI Coder app/repo.',
2564
+ last_triaged_by: 'auto-slow-query',
2565
+ last_triaged_at: new Date()
2566
+ }
2567
+ })];
2568
+ case 10:
2569
+ _a.sent();
2570
+ return [2 /*return*/];
2571
+ case 11: return [4 /*yield*/, checkAICoderTokenEligibility(app._id, this.config.autoOptimizeRequiredTokens > 0 ? this.config.autoOptimizeRequiredTokens : undefined)];
2572
+ case 12:
2573
+ tokenEligibility = _a.sent();
2574
+ if (!!tokenEligibility.allowed) return [3 /*break*/, 14];
2575
+ reason = "".concat(tokenEligibility.message, " Available: ").concat(tokenEligibility.summary.available_tokens.toLocaleString(), " tokens; required: ").concat(tokenEligibility.required_tokens.toLocaleString(), ".");
2576
+ return [4 /*yield*/, this.markAutoOptimizeTokenIneligible(log, reason)];
2577
+ case 13:
2578
+ _a.sent();
2579
+ return [2 /*return*/];
2580
+ case 14:
2581
+ _a.trys.push([14, 16, , 19]);
2582
+ return [4 /*yield*/, this.runExplain(log)];
2583
+ case 15:
2584
+ baselineExplain = _a.sent();
2585
+ return [3 /*break*/, 19];
2586
+ case 16:
2587
+ error_7 = _a.sent();
2588
+ return [4 /*yield*/, SlowQueryLogs.updateOne({ _id: logId }, {
2589
+ $set: {
2590
+ status: 'investigating',
2591
+ auto_fix_status: 'failed',
2592
+ auto_fix_result: {
2593
+ baseline_error: (error_7 === null || error_7 === void 0 ? void 0 : error_7.message) || 'unknown'
2594
+ },
2595
+ verification_notes: "Auto optimize baseline measurement failed: ".concat((error_7 === null || error_7 === void 0 ? void 0 : error_7.message) || 'unknown error'),
2596
+ last_triaged_by: 'auto-slow-query',
2597
+ last_triaged_at: new Date()
2598
+ }
2599
+ })];
2600
+ case 17:
2601
+ _a.sent();
2602
+ return [4 /*yield*/, this.maybeStopAutoOptimizeAfterFailure(logId, 'Auto optimize baseline measurement failed')];
2603
+ case 18:
2604
+ _a.sent();
2605
+ return [2 /*return*/];
2606
+ case 19:
2607
+ baselineFallbackDuration = this.resolveBaselineDurationMs(log);
2608
+ baselineDurationMs = SlowQueryVerifier.isValidDuration(baselineExplain.durationMs)
2609
+ ? baselineExplain.durationMs
2610
+ : baselineFallbackDuration;
2611
+ baselineMetrics = this.resolveExecutionMetrics(baselineExplain.explainStats || {}, baselineDurationMs, baselineExplain.stageSummaries || []);
2612
+ if (!this.config.autoOptimizeOutputCompareEnabled) return [3 /*break*/, 25];
2613
+ _a.label = 20;
2614
+ case 20:
2615
+ _a.trys.push([20, 22, , 25]);
2616
+ return [4 /*yield*/, this.captureOutputFingerprint(log)];
2617
+ case 21:
2618
+ baselineOutputFingerprint = _a.sent();
2619
+ return [3 /*break*/, 25];
2620
+ case 22:
2621
+ error_8 = _a.sent();
2622
+ return [4 /*yield*/, SlowQueryLogs.updateOne({ _id: logId }, {
2623
+ $set: {
2624
+ status: 'investigating',
2625
+ auto_fix_status: 'failed',
2626
+ auto_fix_result: {
2627
+ baseline_error: (error_8 === null || error_8 === void 0 ? void 0 : error_8.message) || 'unknown'
2628
+ },
2629
+ verification_notes: "Auto optimize baseline output comparison failed: ".concat((error_8 === null || error_8 === void 0 ? void 0 : error_8.message) || 'unknown error'),
2630
+ last_triaged_by: 'auto-slow-query',
2631
+ last_triaged_at: new Date()
2632
+ }
2633
+ })];
2634
+ case 23:
2635
+ _a.sent();
2636
+ return [4 /*yield*/, this.maybeStopAutoOptimizeAfterFailure(logId, 'Auto optimize baseline output comparison failed')];
2637
+ case 24:
2638
+ _a.sent();
2639
+ return [2 /*return*/];
2640
+ case 25:
2641
+ title = "Optimize slow query ".concat(log.slow_query_count_string || log.collection);
2642
+ description = this.buildSlowQueryAutoOptimizeDescription(log, app, baselineMetrics);
2643
+ _a.label = 26;
2644
+ case 26:
2645
+ _a.trys.push([26, 28, , 31]);
2646
+ return [4 /*yield*/, this.createDashboardJob({
2647
+ project: app._id,
2648
+ title: title,
2649
+ description: description,
2650
+ repo: app.repo,
2651
+ path: app.git_local_path || undefined,
2652
+ projectRoot: app.project_root || undefined
2653
+ })];
2654
+ case 27:
2655
+ job = _a.sent();
2656
+ return [3 /*break*/, 31];
2657
+ case 28:
2658
+ error_9 = _a.sent();
2659
+ return [4 /*yield*/, SlowQueryLogs.updateOne({ _id: logId }, {
2660
+ $set: {
2661
+ status: 'investigating',
2662
+ auto_fix_status: 'failed',
2663
+ verification_notes: "Auto optimize enqueue failed: ".concat((error_9 === null || error_9 === void 0 ? void 0 : error_9.message) || 'unknown error'),
2664
+ last_triaged_by: 'auto-slow-query',
2665
+ last_triaged_at: new Date()
2666
+ }
2667
+ })];
2668
+ case 29:
2669
+ _a.sent();
2670
+ return [4 /*yield*/, this.maybeStopAutoOptimizeAfterFailure(logId, 'Auto optimize wait failed')];
2671
+ case 30:
2672
+ _a.sent();
2673
+ return [2 /*return*/];
2674
+ case 31:
2675
+ jobId = String((job === null || job === void 0 ? void 0 : job._id) || '').trim();
2676
+ if (!!jobId) return [3 /*break*/, 33];
2677
+ return [4 /*yield*/, SlowQueryLogs.updateOne({ _id: logId }, {
2678
+ $set: {
2679
+ status: 'investigating',
2680
+ auto_fix_status: 'failed',
2681
+ verification_notes: 'Auto optimize enqueue failed: dashboard job id missing.',
2682
+ last_triaged_by: 'auto-slow-query',
2683
+ last_triaged_at: new Date()
2684
+ }
2685
+ })];
2686
+ case 32:
2687
+ _a.sent();
2688
+ return [2 /*return*/];
2689
+ case 33:
2690
+ attemptStartedAt = new Date();
2691
+ return [4 /*yield*/, SlowQueryLogs.updateOne({ _id: logId }, {
2692
+ $inc: {
2693
+ auto_fix_attempt_count: 1
2694
+ },
2695
+ $push: {
2696
+ auto_fix_attempt_history: {
2697
+ $each: [attemptStartedAt],
2698
+ $slice: -100
2699
+ }
2700
+ },
2701
+ $set: {
2702
+ status: 'queued',
2703
+ auto_fix_status: 'running',
2704
+ openai_task_id: jobId,
2705
+ auto_fix_last_attempt_at: attemptStartedAt,
2706
+ auto_fix_disabled_reason: '',
2707
+ verification_notes: "Auto optimize job queued (".concat(jobId, ")."),
2708
+ last_triaged_by: 'auto-slow-query',
2709
+ last_triaged_at: new Date()
2710
+ }
2711
+ })];
2712
+ case 34:
2713
+ _a.sent();
2714
+ return [4 /*yield*/, SlowQueryLogs.findOne({ _id: logId })];
2715
+ case 35:
2716
+ queuedLog = (_a.sent()) || log;
2717
+ return [4 /*yield*/, this.notifyCustomerSlowQueryStatus('detected_auto_optimize_enabled', queuedLog)];
2718
+ case 36:
2719
+ _a.sent();
2720
+ _a.label = 37;
2721
+ case 37:
2722
+ _a.trys.push([37, 39, , 42]);
2723
+ return [4 /*yield*/, this.waitForDashboardJobStop(jobId, this.config.autoOptimizeWaitTimeoutMs)];
2724
+ case 38:
2725
+ _a.sent();
2726
+ return [3 /*break*/, 42];
2727
+ case 39:
2728
+ error_10 = _a.sent();
2729
+ return [4 /*yield*/, SlowQueryLogs.updateOne({ _id: logId }, {
2730
+ $set: {
2731
+ status: 'investigating',
2732
+ auto_fix_status: 'failed',
2733
+ auto_fix_result: {
2734
+ job_id: jobId,
2735
+ error: (error_10 === null || error_10 === void 0 ? void 0 : error_10.message) || 'timeout'
2736
+ },
2737
+ verification_notes: "Auto optimize wait failed: ".concat((error_10 === null || error_10 === void 0 ? void 0 : error_10.message) || 'timeout'),
2738
+ last_triaged_by: 'auto-slow-query',
2739
+ last_triaged_at: new Date()
2740
+ }
2741
+ })];
2742
+ case 40:
2743
+ _a.sent();
2744
+ return [4 /*yield*/, this.maybeStopAutoOptimizeAfterFailure(logId, 'Auto optimize job state check failed')];
2745
+ case 41:
2746
+ _a.sent();
2747
+ return [2 /*return*/];
2748
+ case 42:
2749
+ isRunning = false;
2750
+ _a.label = 43;
2751
+ case 43:
2752
+ _a.trys.push([43, 45, , 47]);
2753
+ return [4 /*yield*/, this.isDashboardJobRunning(jobId)];
2754
+ case 44:
2755
+ isRunning = _a.sent();
2756
+ return [3 /*break*/, 47];
2757
+ case 45:
2758
+ error_11 = _a.sent();
2759
+ return [4 /*yield*/, SlowQueryLogs.updateOne({ _id: logId }, {
2760
+ $set: {
2761
+ status: 'investigating',
2762
+ auto_fix_status: 'failed',
2763
+ auto_fix_result: {
2764
+ job_id: jobId,
2765
+ error: (error_11 === null || error_11 === void 0 ? void 0 : error_11.message) || 'unknown'
2766
+ },
2767
+ verification_notes: "Unable to confirm dashboard job state: ".concat((error_11 === null || error_11 === void 0 ? void 0 : error_11.message) || 'unknown error'),
2768
+ last_triaged_by: 'auto-slow-query',
2769
+ last_triaged_at: new Date()
2770
+ }
2771
+ })];
2772
+ case 46:
2773
+ _a.sent();
2774
+ return [2 /*return*/];
2775
+ case 47:
2776
+ if (!isRunning) return [3 /*break*/, 50];
2777
+ return [4 /*yield*/, SlowQueryLogs.updateOne({ _id: logId }, {
2778
+ $set: {
2779
+ status: 'investigating',
2780
+ auto_fix_status: 'failed',
2781
+ auto_fix_result: {
2782
+ job_id: jobId,
2783
+ error: 'still_running_after_timeout'
2784
+ },
2785
+ verification_notes: "Auto optimize timed out while waiting for dashboard job ".concat(jobId, "."),
2786
+ last_triaged_by: 'auto-slow-query',
2787
+ last_triaged_at: new Date()
2788
+ }
2789
+ })];
2790
+ case 48:
2791
+ _a.sent();
2792
+ return [4 /*yield*/, this.maybeStopAutoOptimizeAfterFailure(logId, 'Auto optimize timed out')];
2793
+ case 49:
2794
+ _a.sent();
2795
+ return [2 /*return*/];
2796
+ case 50: return [4 /*yield*/, AIDashboardJobs.findOne({ _id: jobId })];
2797
+ case 51:
2798
+ finalJob = _a.sent();
2799
+ if (!(!finalJob || finalJob.phase !== 'COMPLETE' || finalJob.paused)) return [3 /*break*/, 54];
2800
+ return [4 /*yield*/, SlowQueryLogs.updateOne({ _id: logId }, {
2801
+ $set: {
2802
+ status: 'investigating',
2803
+ auto_fix_status: 'failed',
2804
+ auto_fix_result: {
2805
+ job_id: jobId,
2806
+ job_phase: (finalJob === null || finalJob === void 0 ? void 0 : finalJob.phase) || 'missing',
2807
+ job_paused: !!(finalJob === null || finalJob === void 0 ? void 0 : finalJob.paused)
2808
+ },
2809
+ verification_notes: "Auto optimize job ".concat(jobId, " did not complete successfully."),
2810
+ last_triaged_by: 'auto-slow-query',
2811
+ last_triaged_at: new Date()
2812
+ }
2813
+ })];
2814
+ case 52:
2815
+ _a.sent();
2816
+ return [4 /*yield*/, this.maybeStopAutoOptimizeAfterFailure(logId, 'Auto optimize job did not complete')];
2817
+ case 53:
2818
+ _a.sent();
2819
+ return [2 /*return*/];
2820
+ case 54:
2821
+ publishOutcome = this.evaluateDashboardPublishOutcome(finalJob);
2822
+ if (!!publishOutcome.success) return [3 /*break*/, 57];
2823
+ return [4 /*yield*/, SlowQueryLogs.updateOne({ _id: logId }, {
2824
+ $set: {
2825
+ status: 'investigating',
2826
+ auto_fix_status: 'failed',
2827
+ auto_fix_result: {
2828
+ job_id: jobId,
2829
+ publish_message: publishOutcome.message
2830
+ },
2831
+ verification_notes: "Auto optimize publish/deploy failed: ".concat(publishOutcome.message),
2832
+ last_triaged_by: 'auto-slow-query',
2833
+ last_triaged_at: new Date()
2834
+ }
2835
+ })];
2836
+ case 55:
2837
+ _a.sent();
2838
+ return [4 /*yield*/, this.maybeStopAutoOptimizeAfterFailure(logId, 'Auto optimize publish/deploy failed')];
2839
+ case 56:
2840
+ _a.sent();
2841
+ return [2 /*return*/];
2842
+ case 57: return [4 /*yield*/, SlowQueryLogs.findOne({ _id: logId })];
2843
+ case 58:
2844
+ refreshedLog = (_a.sent()) || log;
2845
+ _a.label = 59;
2846
+ case 59:
2847
+ _a.trys.push([59, 61, , 64]);
2848
+ return [4 /*yield*/, this.runExplain(refreshedLog)];
2849
+ case 60:
2850
+ afterExplain = _a.sent();
2851
+ return [3 /*break*/, 64];
2852
+ case 61:
2853
+ error_12 = _a.sent();
2854
+ return [4 /*yield*/, SlowQueryLogs.updateOne({ _id: logId }, {
2855
+ $set: {
2856
+ status: 'investigating',
2857
+ auto_fix_status: 'failed',
2858
+ auto_fix_result: {
2859
+ job_id: jobId,
2860
+ publish_message: publishOutcome.message,
2861
+ validation_error: (error_12 === null || error_12 === void 0 ? void 0 : error_12.message) || 'unknown'
2862
+ },
2863
+ verification_notes: "Post-deploy validation failed: ".concat((error_12 === null || error_12 === void 0 ? void 0 : error_12.message) || 'unknown error'),
2864
+ last_triaged_by: 'auto-slow-query',
2865
+ last_triaged_at: new Date()
2866
+ }
2867
+ })];
2868
+ case 62:
2869
+ _a.sent();
2870
+ return [4 /*yield*/, this.maybeStopAutoOptimizeAfterFailure(logId, 'Auto optimize post-deploy validation failed')];
2871
+ case 63:
2872
+ _a.sent();
2873
+ return [2 /*return*/];
2874
+ case 64:
2875
+ afterMetrics = this.resolveExecutionMetrics(afterExplain.explainStats || {}, afterExplain.durationMs, afterExplain.stageSummaries || []);
2876
+ if (!this.config.autoOptimizeOutputCompareEnabled) return [3 /*break*/, 70];
2877
+ if (!!baselineOutputFingerprint) return [3 /*break*/, 65];
2878
+ outputEquivalence = {
2879
+ passed: false,
2880
+ reason: 'Baseline output fingerprint missing.',
2881
+ mode: 'unknown'
2882
+ };
2883
+ return [3 /*break*/, 70];
2884
+ case 65:
2885
+ _a.trys.push([65, 67, , 70]);
2886
+ return [4 /*yield*/, this.captureOutputFingerprint(refreshedLog)];
2887
+ case 66:
2888
+ afterOutputFingerprint = _a.sent();
2889
+ outputEquivalence = this.compareOutputEquivalence(baselineOutputFingerprint, afterOutputFingerprint);
2890
+ return [3 /*break*/, 70];
2891
+ case 67:
2892
+ error_13 = _a.sent();
2893
+ return [4 /*yield*/, SlowQueryLogs.updateOne({ _id: logId }, {
2894
+ $set: {
2895
+ status: 'investigating',
2896
+ auto_fix_status: 'failed',
2897
+ auto_fix_result: {
2898
+ job_id: jobId,
2899
+ publish_message: publishOutcome.message,
2900
+ baseline: baselineMetrics,
2901
+ after: afterMetrics,
2902
+ output_equivalence_error: (error_13 === null || error_13 === void 0 ? void 0 : error_13.message) || 'unknown'
2903
+ },
2904
+ verification_notes: "Post-deploy output comparison failed: ".concat((error_13 === null || error_13 === void 0 ? void 0 : error_13.message) || 'unknown error'),
2905
+ explain_plan: afterExplain.explainPlan,
2906
+ explain_execution_stats: afterExplain.explainStats,
2907
+ explain_generated_at: new Date(),
2908
+ last_triaged_by: 'auto-slow-query',
2909
+ last_triaged_at: new Date()
2910
+ },
2911
+ $push: {
2912
+ verification_runs: {
2913
+ timestamp: new Date(),
2914
+ duration_ms: afterExplain.durationMs
2915
+ }
2916
+ }
2917
+ })];
2918
+ case 68:
2919
+ _a.sent();
2920
+ return [4 /*yield*/, this.maybeStopAutoOptimizeAfterFailure(logId, 'Auto optimize output comparison failed')];
2921
+ case 69:
2922
+ _a.sent();
2923
+ return [2 /*return*/];
2924
+ case 70:
2925
+ validation = this.evaluateOptimizationOutcome(baselineMetrics, afterMetrics, outputEquivalence);
2926
+ autoFixResult = {
2927
+ job_id: jobId,
2928
+ publish_message: publishOutcome.message,
2929
+ baseline: baselineMetrics,
2930
+ after: afterMetrics,
2931
+ output_equivalence: outputEquivalence,
2932
+ validation: validation
2933
+ };
2934
+ if (!!validation.passed) return [3 /*break*/, 73];
2935
+ return [4 /*yield*/, SlowQueryLogs.updateOne({ _id: logId }, {
2936
+ $set: {
2937
+ status: 'investigating',
2938
+ auto_fix_status: 'failed',
2939
+ auto_fix_result: autoFixResult,
2940
+ verification_notes: "Auto optimize validation failed: ".concat(validation.reason),
2941
+ explain_plan: afterExplain.explainPlan,
2942
+ explain_execution_stats: afterExplain.explainStats,
2943
+ explain_generated_at: new Date(),
2944
+ last_triaged_by: 'auto-slow-query',
2945
+ last_triaged_at: new Date()
2946
+ },
2947
+ $push: {
2948
+ verification_runs: {
2949
+ timestamp: new Date(),
2950
+ duration_ms: afterExplain.durationMs
2951
+ }
2952
+ }
2953
+ })];
2954
+ case 71:
2955
+ _a.sent();
2956
+ return [4 /*yield*/, this.maybeStopAutoOptimizeAfterFailure(logId, 'Auto optimize validation failed')];
2957
+ case 72:
2958
+ _a.sent();
2959
+ return [2 /*return*/];
2960
+ case 73: return [4 /*yield*/, SlowQueryLogs.updateOne({ _id: logId }, {
2961
+ $set: {
2962
+ status: 'optimized',
2963
+ auto_fix_status: 'completed',
2964
+ auto_fix_result: autoFixResult,
2965
+ verification_notes: "Auto optimize completed: ".concat(validation.reason),
2966
+ explain_plan: afterExplain.explainPlan,
2967
+ explain_execution_stats: afterExplain.explainStats,
2968
+ explain_generated_at: new Date(),
2969
+ last_triaged_by: 'auto-slow-query',
2970
+ last_triaged_at: new Date()
2971
+ },
2972
+ $push: {
2973
+ verification_runs: {
2974
+ timestamp: new Date(),
2975
+ duration_ms: afterExplain.durationMs
2976
+ }
2977
+ }
2978
+ })];
2979
+ case 74:
2980
+ _a.sent();
2981
+ return [4 /*yield*/, SlowQueryLogs.findOne({ _id: logId })];
2982
+ case 75:
2983
+ optimizedLog = (_a.sent()) || log;
2984
+ return [4 /*yield*/, this.notifyCustomerSlowQueryStatus('completed_success', optimizedLog, { notes: validation.reason })];
2985
+ case 76:
2986
+ _a.sent();
2987
+ return [2 /*return*/];
2988
+ }
2989
+ });
2990
+ });
2991
+ };
2992
+ SlowQueryVerifier.prototype.resolveClientDB = function (log) {
2993
+ return __awaiter(this, void 0, void 0, function () {
2994
+ var candidates, matches, prodMatch, devMatch;
2995
+ return __generator(this, function (_a) {
2996
+ switch (_a.label) {
2997
+ case 0:
2998
+ candidates = [
2999
+ log.client_slug,
3000
+ log.client_name,
3001
+ log.source_app
3002
+ ].filter(Boolean);
3003
+ if (!candidates.length) {
3004
+ return [2 /*return*/, undefined];
3005
+ }
3006
+ return [4 /*yield*/, ClientDBs.find({
3007
+ $or: [
3008
+ { client: { $in: candidates } },
3009
+ { name: { $in: candidates } }
3010
+ ]
3011
+ }, {
3012
+ limit: 10
3013
+ })];
3014
+ case 1:
3015
+ matches = _a.sent();
3016
+ if (!Array.isArray(matches) || !matches.length) {
3017
+ return [2 /*return*/, undefined];
3018
+ }
3019
+ prodMatch = matches.find(function (match) { return match && match.dev_server === false; });
3020
+ if (prodMatch) {
3021
+ return [2 /*return*/, prodMatch];
3022
+ }
3023
+ devMatch = matches.find(function (match) { return match && match.dev_server === true; });
3024
+ if (devMatch) {
3025
+ return [2 /*return*/, devMatch];
3026
+ }
3027
+ return [2 /*return*/, matches[0]];
3028
+ }
3029
+ });
3030
+ });
3031
+ };
3032
+ SlowQueryVerifier.prototype.resolveExplainTarget = function (log) {
3033
+ return __awaiter(this, void 0, void 0, function () {
3034
+ var clientDB, dbName, mainDb, mainDbName;
3035
+ return __generator(this, function (_a) {
3036
+ switch (_a.label) {
3037
+ case 0: return [4 /*yield*/, this.resolveClientDB(log)];
3038
+ case 1:
3039
+ clientDB = _a.sent();
3040
+ if (clientDB) {
3041
+ dbName = clientDB.database || clientDB.name;
3042
+ if (!dbName) {
3043
+ throw new SlowQueryVerifierError('client_db_missing_database', 'Client DB missing database name.');
3044
+ }
3045
+ return [2 /*return*/, {
3046
+ type: 'client',
3047
+ dbName: dbName,
3048
+ uri: clientDB.uri
3049
+ }];
3050
+ }
3051
+ if (!this.config.fallbackToMainDB) {
3052
+ throw new SlowQueryVerifierError('client_db_not_found', 'Could not resolve client DB for slow query verification.');
3053
+ }
3054
+ mainDb = resolveio_server_app_1.ResolveIOServer.getMainDB();
3055
+ mainDbName = mainDb === null || mainDb === void 0 ? void 0 : mainDb.databaseName;
3056
+ if (!mainDb || !mainDbName) {
3057
+ throw new SlowQueryVerifierError('main_db_unavailable', 'Main server DB is not available.');
3058
+ }
3059
+ return [2 /*return*/, {
3060
+ type: 'main',
3061
+ dbName: mainDbName
3062
+ }];
3063
+ }
3064
+ });
3065
+ });
3066
+ };
3067
+ SlowQueryVerifier.extractPipelineFromLog = function (log) {
3068
+ if (!log) {
3069
+ return undefined;
3070
+ }
3071
+ if (Array.isArray(log.pipeline)) {
3072
+ return log.pipeline;
3073
+ }
3074
+ if (log.filter && Array.isArray(log.filter.pipeline)) {
3075
+ return log.filter.pipeline;
3076
+ }
3077
+ return SlowQueryVerifier.extractPipelineOptions(log.options);
3078
+ };
3079
+ SlowQueryVerifier.applyQueryOverrides = function (log, overrides) {
3080
+ if (!overrides) {
3081
+ return log;
3082
+ }
3083
+ var merged = __assign({}, log);
3084
+ if (overrides.filter !== undefined) {
3085
+ merged.filter = overrides.filter;
3086
+ }
3087
+ if (overrides.options !== undefined) {
3088
+ merged.options = overrides.options;
3089
+ }
3090
+ if (overrides.pipeline !== undefined) {
3091
+ merged.pipeline = overrides.pipeline;
3092
+ }
3093
+ return merged;
3094
+ };
3095
+ SlowQueryVerifier.extractPipelineOptions = function (options) {
3096
+ if (!options) {
3097
+ return undefined;
3098
+ }
3099
+ if (Array.isArray(options)) {
3100
+ return options;
3101
+ }
3102
+ if (Array.isArray(options.pipeline)) {
3103
+ return options.pipeline;
3104
+ }
3105
+ return undefined;
3106
+ };
3107
+ SlowQueryVerifier.extractFindOptions = function (options) {
3108
+ if (!options || Array.isArray(options)) {
3109
+ return undefined;
3110
+ }
3111
+ var normalized = __assign({}, options);
3112
+ if (Array.isArray(normalized.pipeline)) {
3113
+ delete normalized.pipeline;
3114
+ }
3115
+ if (!Object.keys(normalized).length) {
3116
+ return undefined;
3117
+ }
3118
+ return normalized;
3119
+ };
3120
+ SlowQueryVerifier.resolveDurationMs = function (explainResponse) {
3121
+ var e_7, _a, e_8, _b, e_9, _c;
3122
+ var _d, _e, _f, _g, _h;
3123
+ var stats = explainResponse === null || explainResponse === void 0 ? void 0 : explainResponse.executionStats;
3124
+ if (!stats) {
3125
+ var stages = explainResponse === null || explainResponse === void 0 ? void 0 : explainResponse.stages;
3126
+ if (Array.isArray(stages)) {
3127
+ try {
3128
+ for (var stages_1 = __values(stages), stages_1_1 = stages_1.next(); !stages_1_1.done; stages_1_1 = stages_1.next()) {
3129
+ var stage = stages_1_1.value;
3130
+ var stageStats = (_d = stage === null || stage === void 0 ? void 0 : stage.$cursor) === null || _d === void 0 ? void 0 : _d.executionStats;
3131
+ var candidates_5 = [
3132
+ stageStats === null || stageStats === void 0 ? void 0 : stageStats.executionTimeMillis,
3133
+ stageStats === null || stageStats === void 0 ? void 0 : stageStats.executionTimeMillisEstimate,
3134
+ (_e = stageStats === null || stageStats === void 0 ? void 0 : stageStats.executionStages) === null || _e === void 0 ? void 0 : _e.executionTimeMillis,
3135
+ (_f = stageStats === null || stageStats === void 0 ? void 0 : stageStats.executionStages) === null || _f === void 0 ? void 0 : _f.executionTimeMillisEstimate
3136
+ ];
3137
+ try {
3138
+ for (var candidates_3 = (e_8 = void 0, __values(candidates_5)), candidates_3_1 = candidates_3.next(); !candidates_3_1.done; candidates_3_1 = candidates_3.next()) {
3139
+ var candidate = candidates_3_1.value;
3140
+ if (SlowQueryVerifier.isValidDuration(candidate)) {
3141
+ return candidate;
3142
+ }
3143
+ }
3144
+ }
3145
+ catch (e_8_1) { e_8 = { error: e_8_1 }; }
3146
+ finally {
3147
+ try {
3148
+ if (candidates_3_1 && !candidates_3_1.done && (_b = candidates_3.return)) _b.call(candidates_3);
3149
+ }
3150
+ finally { if (e_8) throw e_8.error; }
3151
+ }
3152
+ }
3153
+ }
3154
+ catch (e_7_1) { e_7 = { error: e_7_1 }; }
3155
+ finally {
3156
+ try {
3157
+ if (stages_1_1 && !stages_1_1.done && (_a = stages_1.return)) _a.call(stages_1);
3158
+ }
3159
+ finally { if (e_7) throw e_7.error; }
3160
+ }
3161
+ }
3162
+ return -1;
3163
+ }
3164
+ var candidates = [
3165
+ stats.executionTimeMillis,
3166
+ stats.executionTimeMillisEstimate,
3167
+ (_g = stats.executionStages) === null || _g === void 0 ? void 0 : _g.executionTimeMillis,
3168
+ (_h = stats.executionStages) === null || _h === void 0 ? void 0 : _h.executionTimeMillisEstimate
3169
+ ];
3170
+ try {
3171
+ for (var candidates_4 = __values(candidates), candidates_4_1 = candidates_4.next(); !candidates_4_1.done; candidates_4_1 = candidates_4.next()) {
3172
+ var candidate = candidates_4_1.value;
3173
+ if (SlowQueryVerifier.isValidDuration(candidate)) {
3174
+ return candidate;
3175
+ }
3176
+ }
3177
+ }
3178
+ catch (e_9_1) { e_9 = { error: e_9_1 }; }
3179
+ finally {
3180
+ try {
3181
+ if (candidates_4_1 && !candidates_4_1.done && (_c = candidates_4.return)) _c.call(candidates_4);
3182
+ }
3183
+ finally { if (e_9) throw e_9.error; }
3184
+ }
3185
+ return -1;
3186
+ };
3187
+ SlowQueryVerifier.pipelineHasWriteStage = function (pipeline) {
3188
+ if (!Array.isArray(pipeline)) {
3189
+ return false;
3190
+ }
3191
+ return pipeline.some(function (stage) {
3192
+ if (!stage || typeof stage !== 'object') {
3193
+ return false;
3194
+ }
3195
+ return typeof stage.$out !== 'undefined' || typeof stage.$merge !== 'undefined';
3196
+ });
3197
+ };
3198
+ SlowQueryVerifier.extractAggregateOptions = function (options) {
3199
+ if (!options || Array.isArray(options) || typeof options !== 'object') {
3200
+ return undefined;
3201
+ }
3202
+ var allowedKeys = [
3203
+ 'allowDiskUse',
3204
+ 'bypassDocumentValidation',
3205
+ 'collation',
3206
+ 'comment',
3207
+ 'hint',
3208
+ 'let',
3209
+ 'maxTimeMS',
3210
+ 'maxAwaitTimeMS'
3211
+ ];
3212
+ var result = {};
3213
+ allowedKeys.forEach(function (key) {
3214
+ if (typeof options[key] !== 'undefined') {
3215
+ result[key] = options[key];
3216
+ }
3217
+ });
3218
+ return Object.keys(result).length ? result : undefined;
3219
+ };
3220
+ SlowQueryVerifier.buildAggregateExplainCommand = function (collectionName, pipeline, options, verbosity) {
3221
+ if (verbosity === void 0) { verbosity = 'executionStats'; }
3222
+ var aggregateCommand = {
3223
+ aggregate: collectionName,
3224
+ pipeline: pipeline,
3225
+ cursor: {}
3226
+ };
3227
+ if (options && typeof options === 'object') {
3228
+ Object.keys(options).forEach(function (key) {
3229
+ if (typeof options[key] !== 'undefined') {
3230
+ aggregateCommand[key] = options[key];
3231
+ }
3232
+ });
3233
+ }
3234
+ return {
3235
+ explain: aggregateCommand,
3236
+ verbosity: verbosity
3237
+ };
3238
+ };
3239
+ SlowQueryVerifier.isAggregateExplainWriteConcernError = function (err) {
3240
+ var message = "".concat((err === null || err === void 0 ? void 0 : err.message) || '');
3241
+ return message.includes('Option "explain" cannot be used on an aggregate call with writeConcern');
3242
+ };
3243
+ SlowQueryVerifier.isBsonObjectTooLargeError = function (err) {
3244
+ var message = "".concat((err === null || err === void 0 ? void 0 : err.message) || '');
3245
+ return message.includes('BSONObj size:') && message.includes('is invalid');
3246
+ };
3247
+ SlowQueryVerifier.isValidDuration = function (value) {
3248
+ return typeof value === 'number' && !Number.isNaN(value) && value >= 0;
3249
+ };
3250
+ SlowQueryVerifier.buildFindCursor = function (collection, filter, findOptions) {
3251
+ var _a;
3252
+ var cursorOptions = {};
3253
+ if (findOptions) {
3254
+ Object.keys(findOptions).forEach(function (key) {
3255
+ if (['sort', 'skip', 'limit', 'projection', 'fields'].includes(key)) {
3256
+ return;
3257
+ }
3258
+ cursorOptions[key] = findOptions[key];
3259
+ });
3260
+ }
3261
+ cursorOptions.readPreference = 'secondaryPreferred';
3262
+ var cursor = collection.find(filter || {}, cursorOptions);
3263
+ var projection = (_a = findOptions === null || findOptions === void 0 ? void 0 : findOptions.projection) !== null && _a !== void 0 ? _a : findOptions === null || findOptions === void 0 ? void 0 : findOptions.fields;
3264
+ if (projection && typeof projection === 'object') {
3265
+ cursor = cursor.project(projection);
3266
+ }
3267
+ var sort = findOptions === null || findOptions === void 0 ? void 0 : findOptions.sort;
3268
+ if (sort && typeof sort === 'object') {
3269
+ cursor = cursor.sort(sort);
3270
+ }
3271
+ var skip = findOptions === null || findOptions === void 0 ? void 0 : findOptions.skip;
3272
+ if (typeof skip === 'number') {
3273
+ cursor = cursor.skip(skip);
3274
+ }
3275
+ var limit = findOptions === null || findOptions === void 0 ? void 0 : findOptions.limit;
3276
+ if (typeof limit === 'number') {
3277
+ cursor = cursor.limit(limit);
3278
+ }
3279
+ return cursor;
3280
+ };
3281
+ SlowQueryVerifier.measureExecution = function (db, collectionName, pipeline, filter, findOptions, aggregateOptions) {
3282
+ return __awaiter(this, void 0, void 0, function () {
3283
+ var start, cursor, err_5, duration;
3284
+ return __generator(this, function (_a) {
3285
+ switch (_a.label) {
3286
+ case 0:
3287
+ start = Date.now();
3288
+ _a.label = 1;
3289
+ case 1:
3290
+ _a.trys.push([1, 6, , 7]);
3291
+ if (!Array.isArray(pipeline)) return [3 /*break*/, 3];
3292
+ return [4 /*yield*/, db.collection(collectionName)
3293
+ .aggregate(pipeline, __assign(__assign({}, (aggregateOptions || {})), { readPreference: 'secondaryPreferred' }))
3294
+ .toArray()];
3295
+ case 2:
3296
+ _a.sent();
3297
+ return [3 /*break*/, 5];
3298
+ case 3:
3299
+ cursor = SlowQueryVerifier.buildFindCursor(db.collection(collectionName), filter !== null && filter !== void 0 ? filter : {}, findOptions);
3300
+ return [4 /*yield*/, cursor.toArray()];
3301
+ case 4:
3302
+ _a.sent();
3303
+ _a.label = 5;
3304
+ case 5: return [3 /*break*/, 7];
3305
+ case 6:
3306
+ err_5 = _a.sent();
3307
+ if (!SlowQueryVerifier.isBsonObjectTooLargeError(err_5)) {
3308
+ console.error('Slow query measurement execution failed for', collectionName, err_5);
3309
+ }
3310
+ return [2 /*return*/, -1];
3311
+ case 7:
3312
+ duration = Date.now() - start;
3313
+ return [2 /*return*/, SlowQueryVerifier.isValidDuration(duration) ? duration : -1];
3314
+ }
3315
+ });
3316
+ });
3317
+ };
3318
+ SlowQueryVerifier.normalizeExplainPayload = function (input) {
3319
+ var cloned = SlowQueryVerifier.deepClone(input !== null && input !== void 0 ? input : {});
3320
+ return typeof cloned === 'object' && cloned !== null ? cloned : {};
3321
+ };
3322
+ SlowQueryVerifier.sanitizeExplainPayload = function (payload, maxBytes) {
3323
+ if (maxBytes === void 0) { maxBytes = 2 * 1024 * 1024; }
3324
+ try {
3325
+ var json = JSON.stringify(payload);
3326
+ var bytes = Buffer.byteLength(json, 'utf8');
3327
+ return bytes <= maxBytes ? payload : {};
3328
+ }
3329
+ catch (_a) {
3330
+ return {};
3331
+ }
3332
+ };
3333
+ SlowQueryVerifier.deepClone = function (value) {
3334
+ if (value === null || typeof value !== 'object') {
3335
+ return value;
3336
+ }
3337
+ if (Array.isArray(value)) {
3338
+ return value.map(function (item) { return SlowQueryVerifier.deepClone(item); });
3339
+ }
3340
+ if (typeof value.toJSON === 'function') {
3341
+ try {
3342
+ return SlowQueryVerifier.deepClone(value.toJSON());
3343
+ }
3344
+ catch (_a) {
3345
+ // fall through to manual clone
3346
+ }
3347
+ }
3348
+ var result = {};
3349
+ Object.keys(value).forEach(function (key) {
3350
+ result[key] = SlowQueryVerifier.deepClone(value[key]);
3351
+ });
3352
+ return result;
3353
+ };
3354
+ return SlowQueryVerifier;
3355
+ }());
3356
+ exports.SlowQueryVerifier = SlowQueryVerifier;
3357
+
3358
+ //# sourceMappingURL=slow-query-verifier.manager.js.map