@freshguard/freshguard-core 0.11.2

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 (180) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +644 -0
  3. package/dist/cli/index.d.ts +3 -0
  4. package/dist/cli/index.d.ts.map +1 -0
  5. package/dist/cli/index.js +350 -0
  6. package/dist/cli/index.js.map +1 -0
  7. package/dist/connectors/base-connector.d.ts +62 -0
  8. package/dist/connectors/base-connector.d.ts.map +1 -0
  9. package/dist/connectors/base-connector.js +549 -0
  10. package/dist/connectors/base-connector.js.map +1 -0
  11. package/dist/connectors/bigquery.d.ts +38 -0
  12. package/dist/connectors/bigquery.d.ts.map +1 -0
  13. package/dist/connectors/bigquery.js +406 -0
  14. package/dist/connectors/bigquery.js.map +1 -0
  15. package/dist/connectors/duckdb.d.ts +36 -0
  16. package/dist/connectors/duckdb.d.ts.map +1 -0
  17. package/dist/connectors/duckdb.js +364 -0
  18. package/dist/connectors/duckdb.js.map +1 -0
  19. package/dist/connectors/index.d.ts +7 -0
  20. package/dist/connectors/index.d.ts.map +1 -0
  21. package/dist/connectors/index.js +7 -0
  22. package/dist/connectors/index.js.map +1 -0
  23. package/dist/connectors/mysql.d.ts +32 -0
  24. package/dist/connectors/mysql.d.ts.map +1 -0
  25. package/dist/connectors/mysql.js +348 -0
  26. package/dist/connectors/mysql.js.map +1 -0
  27. package/dist/connectors/postgres.d.ts +31 -0
  28. package/dist/connectors/postgres.d.ts.map +1 -0
  29. package/dist/connectors/postgres.js +326 -0
  30. package/dist/connectors/postgres.js.map +1 -0
  31. package/dist/connectors/redshift.d.ts +32 -0
  32. package/dist/connectors/redshift.d.ts.map +1 -0
  33. package/dist/connectors/redshift.js +366 -0
  34. package/dist/connectors/redshift.js.map +1 -0
  35. package/dist/connectors/snowflake.d.ts +43 -0
  36. package/dist/connectors/snowflake.d.ts.map +1 -0
  37. package/dist/connectors/snowflake.js +442 -0
  38. package/dist/connectors/snowflake.js.map +1 -0
  39. package/dist/db/index.d.ts +9 -0
  40. package/dist/db/index.d.ts.map +1 -0
  41. package/dist/db/index.js +10 -0
  42. package/dist/db/index.js.map +1 -0
  43. package/dist/db/migrate.d.ts +12 -0
  44. package/dist/db/migrate.d.ts.map +1 -0
  45. package/dist/db/migrate.js +114 -0
  46. package/dist/db/migrate.js.map +1 -0
  47. package/dist/db/schema.d.ts +2053 -0
  48. package/dist/db/schema.d.ts.map +1 -0
  49. package/dist/db/schema.js +164 -0
  50. package/dist/db/schema.js.map +1 -0
  51. package/dist/errors/debug-factory.d.ts +23 -0
  52. package/dist/errors/debug-factory.d.ts.map +1 -0
  53. package/dist/errors/debug-factory.js +149 -0
  54. package/dist/errors/debug-factory.js.map +1 -0
  55. package/dist/errors/index.d.ts +119 -0
  56. package/dist/errors/index.d.ts.map +1 -0
  57. package/dist/errors/index.js +341 -0
  58. package/dist/errors/index.js.map +1 -0
  59. package/dist/index.d.ts +9 -0
  60. package/dist/index.d.ts.map +1 -0
  61. package/dist/index.js +6 -0
  62. package/dist/index.js.map +1 -0
  63. package/dist/metadata/duckdb-storage.d.ts +31 -0
  64. package/dist/metadata/duckdb-storage.d.ts.map +1 -0
  65. package/dist/metadata/duckdb-storage.js +230 -0
  66. package/dist/metadata/duckdb-storage.js.map +1 -0
  67. package/dist/metadata/factory.d.ts +4 -0
  68. package/dist/metadata/factory.d.ts.map +1 -0
  69. package/dist/metadata/factory.js +23 -0
  70. package/dist/metadata/factory.js.map +1 -0
  71. package/dist/metadata/index.d.ts +6 -0
  72. package/dist/metadata/index.d.ts.map +1 -0
  73. package/dist/metadata/index.js +4 -0
  74. package/dist/metadata/index.js.map +1 -0
  75. package/dist/metadata/interface.d.ts +26 -0
  76. package/dist/metadata/interface.d.ts.map +1 -0
  77. package/dist/metadata/interface.js +2 -0
  78. package/dist/metadata/interface.js.map +1 -0
  79. package/dist/metadata/postgresql-storage.d.ts +32 -0
  80. package/dist/metadata/postgresql-storage.d.ts.map +1 -0
  81. package/dist/metadata/postgresql-storage.js +242 -0
  82. package/dist/metadata/postgresql-storage.js.map +1 -0
  83. package/dist/metadata/schema-config.d.ts +30 -0
  84. package/dist/metadata/schema-config.d.ts.map +1 -0
  85. package/dist/metadata/schema-config.js +94 -0
  86. package/dist/metadata/schema-config.js.map +1 -0
  87. package/dist/metadata/types.d.ts +35 -0
  88. package/dist/metadata/types.d.ts.map +1 -0
  89. package/dist/metadata/types.js +2 -0
  90. package/dist/metadata/types.js.map +1 -0
  91. package/dist/monitor/baseline-calculator.d.ts +30 -0
  92. package/dist/monitor/baseline-calculator.d.ts.map +1 -0
  93. package/dist/monitor/baseline-calculator.js +192 -0
  94. package/dist/monitor/baseline-calculator.js.map +1 -0
  95. package/dist/monitor/baseline-config.d.ts +37 -0
  96. package/dist/monitor/baseline-config.d.ts.map +1 -0
  97. package/dist/monitor/baseline-config.js +156 -0
  98. package/dist/monitor/baseline-config.js.map +1 -0
  99. package/dist/monitor/freshness.d.ts +5 -0
  100. package/dist/monitor/freshness.d.ts.map +1 -0
  101. package/dist/monitor/freshness.js +239 -0
  102. package/dist/monitor/freshness.js.map +1 -0
  103. package/dist/monitor/index.d.ts +5 -0
  104. package/dist/monitor/index.d.ts.map +1 -0
  105. package/dist/monitor/index.js +5 -0
  106. package/dist/monitor/index.js.map +1 -0
  107. package/dist/monitor/schema-baseline.d.ts +22 -0
  108. package/dist/monitor/schema-baseline.d.ts.map +1 -0
  109. package/dist/monitor/schema-baseline.js +211 -0
  110. package/dist/monitor/schema-baseline.js.map +1 -0
  111. package/dist/monitor/schema-changes.d.ts +5 -0
  112. package/dist/monitor/schema-changes.d.ts.map +1 -0
  113. package/dist/monitor/schema-changes.js +289 -0
  114. package/dist/monitor/schema-changes.js.map +1 -0
  115. package/dist/monitor/volume.d.ts +5 -0
  116. package/dist/monitor/volume.d.ts.map +1 -0
  117. package/dist/monitor/volume.js +262 -0
  118. package/dist/monitor/volume.js.map +1 -0
  119. package/dist/observability/logger.d.ts +63 -0
  120. package/dist/observability/logger.d.ts.map +1 -0
  121. package/dist/observability/logger.js +282 -0
  122. package/dist/observability/logger.js.map +1 -0
  123. package/dist/observability/metrics.d.ts +106 -0
  124. package/dist/observability/metrics.d.ts.map +1 -0
  125. package/dist/observability/metrics.js +441 -0
  126. package/dist/observability/metrics.js.map +1 -0
  127. package/dist/query-analyzer.js +526 -0
  128. package/dist/resilience/circuit-breaker.d.ts +94 -0
  129. package/dist/resilience/circuit-breaker.d.ts.map +1 -0
  130. package/dist/resilience/circuit-breaker.js +379 -0
  131. package/dist/resilience/circuit-breaker.js.map +1 -0
  132. package/dist/resilience/index.d.ts +7 -0
  133. package/dist/resilience/index.d.ts.map +1 -0
  134. package/dist/resilience/index.js +7 -0
  135. package/dist/resilience/index.js.map +1 -0
  136. package/dist/resilience/retry-policy.d.ts +87 -0
  137. package/dist/resilience/retry-policy.d.ts.map +1 -0
  138. package/dist/resilience/retry-policy.js +423 -0
  139. package/dist/resilience/retry-policy.js.map +1 -0
  140. package/dist/resilience/timeout-manager.d.ts +97 -0
  141. package/dist/resilience/timeout-manager.d.ts.map +1 -0
  142. package/dist/resilience/timeout-manager.js +339 -0
  143. package/dist/resilience/timeout-manager.js.map +1 -0
  144. package/dist/security/query-analyzer.d.ts +82 -0
  145. package/dist/security/query-analyzer.d.ts.map +1 -0
  146. package/dist/security/query-analyzer.js +381 -0
  147. package/dist/security/query-analyzer.js.map +1 -0
  148. package/dist/security/schema-cache.d.ts +95 -0
  149. package/dist/security/schema-cache.d.ts.map +1 -0
  150. package/dist/security/schema-cache.js +344 -0
  151. package/dist/security/schema-cache.js.map +1 -0
  152. package/dist/types/connector.d.ts +68 -0
  153. package/dist/types/connector.d.ts.map +1 -0
  154. package/dist/types/connector.js +26 -0
  155. package/dist/types/connector.js.map +1 -0
  156. package/dist/types.d.ts +244 -0
  157. package/dist/types.d.ts.map +1 -0
  158. package/dist/types.js +2 -0
  159. package/dist/types.js.map +1 -0
  160. package/dist/validation/index.d.ts +7 -0
  161. package/dist/validation/index.d.ts.map +1 -0
  162. package/dist/validation/index.js +5 -0
  163. package/dist/validation/index.js.map +1 -0
  164. package/dist/validation/runtime-validator.d.ts +70 -0
  165. package/dist/validation/runtime-validator.d.ts.map +1 -0
  166. package/dist/validation/runtime-validator.js +206 -0
  167. package/dist/validation/runtime-validator.js.map +1 -0
  168. package/dist/validation/sanitizers.d.ts +56 -0
  169. package/dist/validation/sanitizers.d.ts.map +1 -0
  170. package/dist/validation/sanitizers.js +264 -0
  171. package/dist/validation/sanitizers.js.map +1 -0
  172. package/dist/validation/schemas.d.ts +224 -0
  173. package/dist/validation/schemas.d.ts.map +1 -0
  174. package/dist/validation/schemas.js +263 -0
  175. package/dist/validation/schemas.js.map +1 -0
  176. package/dist/validators/index.d.ts +18 -0
  177. package/dist/validators/index.d.ts.map +1 -0
  178. package/dist/validators/index.js +209 -0
  179. package/dist/validators/index.js.map +1 -0
  180. package/package.json +91 -0
@@ -0,0 +1,192 @@
1
+ import { MonitoringError } from '../errors/index.js';
2
+ export class BaselineCalculator {
3
+ config;
4
+ constructor(config) {
5
+ this.config = config;
6
+ }
7
+ calculateBaseline(historicalData, currentRowCount) {
8
+ const dataPoints = this.convertToDataPoints(historicalData);
9
+ const filteredData = this.filterData(dataPoints);
10
+ if (filteredData.length < this.config.minimumDataPoints) {
11
+ return {
12
+ mean: currentRowCount,
13
+ deviationPercent: 0,
14
+ dataPointsUsed: filteredData.length,
15
+ calculationMethod: this.config.calculationMethod,
16
+ seasonalAdjusted: false,
17
+ };
18
+ }
19
+ try {
20
+ const adjustedData = this.config.seasonalAdjustment
21
+ ? this.applySeasonalAdjustment(filteredData)
22
+ : filteredData;
23
+ const seasonalAdjustmentApplied = this.config.seasonalAdjustment && filteredData.length >= 14;
24
+ const baseline = this.calculateStatistic(adjustedData);
25
+ const adjustedCurrentRowCount = seasonalAdjustmentApplied
26
+ ? this.adjustCurrentValueForSeason(filteredData, currentRowCount)
27
+ : currentRowCount;
28
+ const deviationPercent = this.calculateDeviation(baseline, adjustedCurrentRowCount);
29
+ return {
30
+ mean: Math.round(baseline),
31
+ deviationPercent: Math.round(deviationPercent * 100) / 100,
32
+ dataPointsUsed: adjustedData.length,
33
+ calculationMethod: this.config.calculationMethod,
34
+ seasonalAdjusted: seasonalAdjustmentApplied,
35
+ };
36
+ }
37
+ catch (error) {
38
+ return {
39
+ mean: currentRowCount,
40
+ deviationPercent: 0,
41
+ dataPointsUsed: filteredData.length,
42
+ calculationMethod: 'fallback',
43
+ seasonalAdjusted: false,
44
+ };
45
+ }
46
+ }
47
+ convertToDataPoints(executions) {
48
+ return executions
49
+ .filter(e => e.rowCount !== undefined && e.executedAt)
50
+ .map(e => ({
51
+ rowCount: e.rowCount,
52
+ executedAt: e.executedAt,
53
+ }));
54
+ }
55
+ filterData(dataPoints) {
56
+ if (!this.config.excludeWeekends) {
57
+ return dataPoints;
58
+ }
59
+ return dataPoints.filter(point => {
60
+ const dayOfWeek = point.executedAt.getDay();
61
+ return dayOfWeek !== 0 && dayOfWeek !== 6;
62
+ });
63
+ }
64
+ applySeasonalAdjustment(dataPoints) {
65
+ if (dataPoints.length < 14) {
66
+ return dataPoints;
67
+ }
68
+ const dayOfWeekStats = this.calculateDayOfWeekStats(dataPoints);
69
+ const overallMean = this.calculateMean(dataPoints.map(p => p.rowCount));
70
+ const adjustedPoints = dataPoints.map(point => {
71
+ const dayOfWeek = point.executedAt.getDay();
72
+ const dayStats = dayOfWeekStats[dayOfWeek];
73
+ if (!dayStats || dayStats.count < 2) {
74
+ return point;
75
+ }
76
+ const dayFactor = overallMean / dayStats.mean;
77
+ const adjustedRowCount = point.rowCount * dayFactor;
78
+ return {
79
+ ...point,
80
+ rowCount: adjustedRowCount,
81
+ };
82
+ });
83
+ return adjustedPoints;
84
+ }
85
+ adjustCurrentValueForSeason(dataPoints, currentRowCount) {
86
+ if (dataPoints.length < 14) {
87
+ return currentRowCount;
88
+ }
89
+ const dayOfWeekStats = this.calculateDayOfWeekStats(dataPoints);
90
+ const overallMean = this.calculateMean(dataPoints.map(p => p.rowCount));
91
+ const currentDayOfWeek = new Date().getDay();
92
+ const currentDayStats = dayOfWeekStats[currentDayOfWeek];
93
+ if (!currentDayStats || currentDayStats.count < 2) {
94
+ return currentRowCount;
95
+ }
96
+ const dayFactor = overallMean / currentDayStats.mean;
97
+ const adjustedCurrentRowCount = currentRowCount * dayFactor;
98
+ return adjustedCurrentRowCount;
99
+ }
100
+ calculateDayOfWeekStats(dataPoints) {
101
+ const stats = {};
102
+ dataPoints.forEach(point => {
103
+ const dayOfWeek = point.executedAt.getDay();
104
+ if (!stats[dayOfWeek]) {
105
+ stats[dayOfWeek] = { mean: 0, count: 0 };
106
+ }
107
+ stats[dayOfWeek].mean += point.rowCount;
108
+ stats[dayOfWeek].count += 1;
109
+ });
110
+ Object.values(stats).forEach(stat => {
111
+ if (stat.count > 0) {
112
+ stat.mean = stat.mean / stat.count;
113
+ }
114
+ });
115
+ return stats;
116
+ }
117
+ calculateStatistic(dataPoints) {
118
+ const values = dataPoints.map(p => p.rowCount);
119
+ this.validateValues(values);
120
+ switch (this.config.calculationMethod) {
121
+ case 'mean':
122
+ return this.calculateMean(values);
123
+ case 'median':
124
+ return this.calculateMedian(values);
125
+ case 'trimmed_mean':
126
+ return this.calculateTrimmedMean(values, this.config.trimmedMeanPercentile);
127
+ default:
128
+ throw new MonitoringError(`Unknown calculation method: ${this.config.calculationMethod}`, 'volume', undefined, undefined);
129
+ }
130
+ }
131
+ validateValues(values) {
132
+ if (values.length === 0) {
133
+ throw new MonitoringError('No valid data points for baseline calculation', 'volume');
134
+ }
135
+ if (values.some(value => isNaN(value) || value < 0)) {
136
+ throw new MonitoringError('Invalid row count values detected', 'volume');
137
+ }
138
+ }
139
+ calculateMean(values) {
140
+ const sum = values.reduce((a, b) => {
141
+ const result = a + b;
142
+ if (result > Number.MAX_SAFE_INTEGER) {
143
+ throw new MonitoringError('Statistical calculation overflow', 'volume');
144
+ }
145
+ return result;
146
+ }, 0);
147
+ return sum / values.length;
148
+ }
149
+ calculateMedian(values) {
150
+ const sorted = [...values].sort((a, b) => a - b);
151
+ const mid = Math.floor(sorted.length / 2);
152
+ if (sorted.length % 2 === 0) {
153
+ const left = sorted[mid - 1];
154
+ const right = sorted[mid];
155
+ if (left === undefined || right === undefined) {
156
+ throw new MonitoringError('Invalid data for median calculation', 'volume');
157
+ }
158
+ return (left + right) / 2;
159
+ }
160
+ else {
161
+ const middle = sorted[mid];
162
+ if (middle === undefined) {
163
+ throw new MonitoringError('Invalid data for median calculation', 'volume');
164
+ }
165
+ return middle;
166
+ }
167
+ }
168
+ calculateTrimmedMean(values, trimPercentile) {
169
+ if (values.length < 4) {
170
+ return this.calculateMean(values);
171
+ }
172
+ const sorted = [...values].sort((a, b) => a - b);
173
+ const trimCount = Math.floor((sorted.length * trimPercentile) / 100);
174
+ const trimmedValues = sorted.slice(trimCount, sorted.length - trimCount);
175
+ if (trimmedValues.length === 0) {
176
+ return this.calculateMean(values);
177
+ }
178
+ return this.calculateMean(trimmedValues);
179
+ }
180
+ calculateDeviation(baseline, currentValue) {
181
+ if (baseline <= 0) {
182
+ return 0;
183
+ }
184
+ const deviation = Math.abs(currentValue - baseline);
185
+ const deviationPercent = (deviation / baseline) * 100;
186
+ if (isNaN(deviationPercent) || deviationPercent === Infinity) {
187
+ return 0;
188
+ }
189
+ return deviationPercent;
190
+ }
191
+ }
192
+ //# sourceMappingURL=baseline-calculator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baseline-calculator.js","sourceRoot":"","sources":["../../src/monitor/baseline-calculator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import type { MonitoringRule } from '../types.js';
2
+ export interface ResolvedBaselineConfig {
3
+ windowDays: number;
4
+ minimumDataPoints: number;
5
+ timeoutSeconds: number;
6
+ excludeWeekends: boolean;
7
+ calculationMethod: 'mean' | 'median' | 'trimmed_mean';
8
+ trimmedMeanPercentile: number;
9
+ seasonalAdjustment: boolean;
10
+ deviationThresholdPercent: number;
11
+ minimumRowCount: number;
12
+ }
13
+ export declare class BaselineConfigResolver {
14
+ private readonly config;
15
+ constructor(rule: MonitoringRule);
16
+ getConfig(): ResolvedBaselineConfig;
17
+ getWindowDays(): number;
18
+ getMinimumDataPoints(): number;
19
+ getTimeoutSeconds(): number;
20
+ shouldExcludeWeekends(): boolean;
21
+ getCalculationMethod(): 'mean' | 'median' | 'trimmed_mean';
22
+ getTrimmedMeanPercentile(): number;
23
+ shouldApplySeasonalAdjustment(): boolean;
24
+ getDeviationThresholdPercent(): number;
25
+ getMinimumRowCount(): number;
26
+ private resolveConfiguration;
27
+ private resolveWindowDays;
28
+ private validateConfiguration;
29
+ private validateWindowDays;
30
+ private validateMinimumDataPoints;
31
+ private validateTimeoutSeconds;
32
+ private validateCalculationMethod;
33
+ private validateTrimmedMeanPercentile;
34
+ private validateDeviationThresholdPercent;
35
+ private validateMinimumRowCount;
36
+ }
37
+ //# sourceMappingURL=baseline-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baseline-config.d.ts","sourceRoot":"","sources":["../../src/monitor/baseline-config.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAMlD,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,OAAO,CAAC;IACzB,iBAAiB,EAAE,MAAM,GAAG,QAAQ,GAAG,cAAc,CAAC;IACtD,qBAAqB,EAAE,MAAM,CAAC;IAC9B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,yBAAyB,EAAE,MAAM,CAAC;IAClC,eAAe,EAAE,MAAM,CAAC;CACzB;AAQD,qBAAa,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyB;gBAEpC,IAAI,EAAE,cAAc;IAQhC,SAAS,IAAI,sBAAsB;IAOnC,aAAa,IAAI,MAAM;IAOvB,oBAAoB,IAAI,MAAM;IAO9B,iBAAiB,IAAI,MAAM;IAO3B,qBAAqB,IAAI,OAAO;IAOhC,oBAAoB,IAAI,MAAM,GAAG,QAAQ,GAAG,cAAc;IAO1D,wBAAwB,IAAI,MAAM;IAOlC,6BAA6B,IAAI,OAAO;IAOxC,4BAA4B,IAAI,MAAM;IAOtC,kBAAkB,IAAI,MAAM;IAO5B,OAAO,CAAC,oBAAoB;IAgC5B,OAAO,CAAC,iBAAiB;IAgBzB,OAAO,CAAC,qBAAqB;IAa7B,OAAO,CAAC,kBAAkB;IA+B1B,OAAO,CAAC,yBAAyB;IA+BjC,OAAO,CAAC,sBAAsB;IA+B9B,OAAO,CAAC,yBAAyB;IAgBjC,OAAO,CAAC,6BAA6B;IA4BrC,OAAO,CAAC,iCAAiC;IA+BzC,OAAO,CAAC,uBAAuB;CAmBhC"}
@@ -0,0 +1,156 @@
1
+ import { ConfigurationError } from '../errors/index.js';
2
+ export class BaselineConfigResolver {
3
+ config;
4
+ constructor(rule) {
5
+ this.config = this.resolveConfiguration(rule);
6
+ this.validateConfiguration();
7
+ }
8
+ getConfig() {
9
+ return this.config;
10
+ }
11
+ getWindowDays() {
12
+ return this.config.windowDays;
13
+ }
14
+ getMinimumDataPoints() {
15
+ return this.config.minimumDataPoints;
16
+ }
17
+ getTimeoutSeconds() {
18
+ return this.config.timeoutSeconds;
19
+ }
20
+ shouldExcludeWeekends() {
21
+ return this.config.excludeWeekends;
22
+ }
23
+ getCalculationMethod() {
24
+ return this.config.calculationMethod;
25
+ }
26
+ getTrimmedMeanPercentile() {
27
+ return this.config.trimmedMeanPercentile;
28
+ }
29
+ shouldApplySeasonalAdjustment() {
30
+ return this.config.seasonalAdjustment;
31
+ }
32
+ getDeviationThresholdPercent() {
33
+ return this.config.deviationThresholdPercent;
34
+ }
35
+ getMinimumRowCount() {
36
+ return this.config.minimumRowCount;
37
+ }
38
+ resolveConfiguration(rule) {
39
+ const baselineConfig = rule.baselineConfig || {};
40
+ const windowDays = this.resolveWindowDays(rule, baselineConfig);
41
+ const deviationThresholdPercent = rule.deviationThresholdPercent || 20;
42
+ const minimumRowCount = rule.minimumRowCount || 0;
43
+ const minimumDataPoints = baselineConfig.minimumDataPoints ?? 3;
44
+ const timeoutSeconds = baselineConfig.timeoutSeconds ?? 30;
45
+ const excludeWeekends = baselineConfig.excludeWeekends || false;
46
+ const calculationMethod = baselineConfig.calculationMethod || 'mean';
47
+ const trimmedMeanPercentile = baselineConfig.trimmedMeanPercentile || 10;
48
+ const seasonalAdjustment = baselineConfig.seasonalAdjustment || false;
49
+ return {
50
+ windowDays,
51
+ minimumDataPoints,
52
+ timeoutSeconds,
53
+ excludeWeekends,
54
+ calculationMethod,
55
+ trimmedMeanPercentile,
56
+ seasonalAdjustment,
57
+ deviationThresholdPercent,
58
+ minimumRowCount,
59
+ };
60
+ }
61
+ resolveWindowDays(rule, baselineConfig) {
62
+ if (baselineConfig.windowDays !== undefined) {
63
+ return baselineConfig.windowDays;
64
+ }
65
+ if (rule.baselineWindowDays !== undefined) {
66
+ return rule.baselineWindowDays;
67
+ }
68
+ return 30;
69
+ }
70
+ validateConfiguration() {
71
+ this.validateWindowDays();
72
+ this.validateMinimumDataPoints();
73
+ this.validateTimeoutSeconds();
74
+ this.validateCalculationMethod();
75
+ this.validateTrimmedMeanPercentile();
76
+ this.validateDeviationThresholdPercent();
77
+ this.validateMinimumRowCount();
78
+ }
79
+ validateWindowDays() {
80
+ const { windowDays } = this.config;
81
+ if (typeof windowDays !== 'number' || !Number.isInteger(windowDays)) {
82
+ throw ConfigurationError.invalidValue('baselineConfig.windowDays', windowDays.toString(), 'integer');
83
+ }
84
+ if (windowDays < 1) {
85
+ throw ConfigurationError.invalidValue('baselineConfig.windowDays', windowDays.toString(), 'positive integer (minimum 1)');
86
+ }
87
+ if (windowDays > 365) {
88
+ throw ConfigurationError.invalidValue('baselineConfig.windowDays', windowDays.toString(), 'integer between 1 and 365');
89
+ }
90
+ }
91
+ validateMinimumDataPoints() {
92
+ const { minimumDataPoints } = this.config;
93
+ if (typeof minimumDataPoints !== 'number' || !Number.isInteger(minimumDataPoints)) {
94
+ throw ConfigurationError.invalidValue('baselineConfig.minimumDataPoints', minimumDataPoints.toString(), 'integer');
95
+ }
96
+ if (minimumDataPoints < 1) {
97
+ throw ConfigurationError.invalidValue('baselineConfig.minimumDataPoints', minimumDataPoints.toString(), 'positive integer (minimum 1)');
98
+ }
99
+ if (minimumDataPoints > 1000) {
100
+ throw ConfigurationError.invalidValue('baselineConfig.minimumDataPoints', minimumDataPoints.toString(), 'integer between 1 and 1000');
101
+ }
102
+ }
103
+ validateTimeoutSeconds() {
104
+ const { timeoutSeconds } = this.config;
105
+ if (typeof timeoutSeconds !== 'number' || !Number.isInteger(timeoutSeconds)) {
106
+ throw ConfigurationError.invalidValue('baselineConfig.timeoutSeconds', timeoutSeconds.toString(), 'integer');
107
+ }
108
+ if (timeoutSeconds < 1) {
109
+ throw ConfigurationError.invalidValue('baselineConfig.timeoutSeconds', timeoutSeconds.toString(), 'positive integer (minimum 1)');
110
+ }
111
+ if (timeoutSeconds > 600) {
112
+ throw ConfigurationError.invalidValue('baselineConfig.timeoutSeconds', timeoutSeconds.toString(), 'integer between 1 and 600');
113
+ }
114
+ }
115
+ validateCalculationMethod() {
116
+ const { calculationMethod } = this.config;
117
+ const validMethods = ['mean', 'median', 'trimmed_mean'];
118
+ if (!validMethods.includes(calculationMethod)) {
119
+ throw ConfigurationError.invalidValue('baselineConfig.calculationMethod', calculationMethod, 'mean, median, or trimmed_mean');
120
+ }
121
+ }
122
+ validateTrimmedMeanPercentile() {
123
+ const { trimmedMeanPercentile, calculationMethod } = this.config;
124
+ if (calculationMethod !== 'trimmed_mean') {
125
+ return;
126
+ }
127
+ if (typeof trimmedMeanPercentile !== 'number') {
128
+ throw ConfigurationError.invalidValue('baselineConfig.trimmedMeanPercentile', String(trimmedMeanPercentile), 'number');
129
+ }
130
+ if (trimmedMeanPercentile < 0 || trimmedMeanPercentile > 50) {
131
+ throw ConfigurationError.invalidValue('baselineConfig.trimmedMeanPercentile', String(trimmedMeanPercentile), 'number between 0 and 50');
132
+ }
133
+ }
134
+ validateDeviationThresholdPercent() {
135
+ const { deviationThresholdPercent } = this.config;
136
+ if (typeof deviationThresholdPercent !== 'number') {
137
+ throw ConfigurationError.invalidValue('deviationThresholdPercent', String(deviationThresholdPercent), 'number');
138
+ }
139
+ if (deviationThresholdPercent < 0) {
140
+ throw ConfigurationError.invalidValue('deviationThresholdPercent', String(deviationThresholdPercent), 'non-negative number');
141
+ }
142
+ if (deviationThresholdPercent > 1000) {
143
+ throw ConfigurationError.invalidValue('deviationThresholdPercent', String(deviationThresholdPercent), 'number between 0 and 1000');
144
+ }
145
+ }
146
+ validateMinimumRowCount() {
147
+ const { minimumRowCount } = this.config;
148
+ if (typeof minimumRowCount !== 'number' || !Number.isInteger(minimumRowCount)) {
149
+ throw ConfigurationError.invalidValue('minimumRowCount', String(minimumRowCount), 'integer');
150
+ }
151
+ if (minimumRowCount < 0) {
152
+ throw ConfigurationError.invalidValue('minimumRowCount', String(minimumRowCount), 'non-negative integer');
153
+ }
154
+ }
155
+ }
156
+ //# sourceMappingURL=baseline-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baseline-config.js","sourceRoot":"","sources":["../../src/monitor/baseline-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { CheckResult, MonitoringRule, FreshGuardConfig } from '../types.js';
2
+ import type { Connector } from '../types/connector.js';
3
+ import type { MetadataStorage } from '../metadata/interface.js';
4
+ export declare function checkFreshness(connector: Connector, rule: MonitoringRule, metadataStorage?: MetadataStorage, config?: FreshGuardConfig): Promise<CheckResult>;
5
+ //# sourceMappingURL=freshness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"freshness.d.ts","sourceRoot":"","sources":["../../src/monitor/freshness.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,gBAAgB,EAAe,MAAM,aAAa,CAAC;AAC9F,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAoBhE,wBAAsB,cAAc,CAClC,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,cAAc,EACpB,eAAe,CAAC,EAAE,eAAe,EACjC,MAAM,CAAC,EAAE,gBAAgB,GACxB,OAAO,CAAC,WAAW,CAAC,CA2KtB"}
@@ -0,0 +1,239 @@
1
+ import { validateTableName, validateColumnName } from '../validators/index.js';
2
+ import { QueryError, TimeoutError, ConfigurationError, ErrorHandler } from '../errors/index.js';
3
+ import { DebugErrorFactory, mergeDebugConfig } from '../errors/debug-factory.js';
4
+ export async function checkFreshness(connector, rule, metadataStorage, config) {
5
+ const startTime = Date.now();
6
+ const debugConfig = mergeDebugConfig(config?.debug);
7
+ const debugFactory = new DebugErrorFactory(debugConfig);
8
+ const debugId = `fg-${Date.now().toString(36)}-${Math.random().toString(36).substr(2, 5)}`;
9
+ try {
10
+ if (debugConfig.enabled) {
11
+ console.log(`[DEBUG-${debugId}] Starting freshness check:`, {
12
+ table: rule.tableName,
13
+ ruleId: rule.id,
14
+ timestamp: new Date().toISOString()
15
+ });
16
+ }
17
+ validateFreshnessRule(rule);
18
+ const timestampColumn = rule.timestampColumn || 'updated_at';
19
+ const toleranceMinutes = rule.toleranceMinutes || 60;
20
+ validateTableName(rule.tableName);
21
+ validateColumnName(timestampColumn);
22
+ if (toleranceMinutes < 1 || toleranceMinutes > 10080) {
23
+ throw new ConfigurationError('Tolerance minutes must be between 1 and 10080 (1 week)');
24
+ }
25
+ const queryResult = await executeWithTimeout(() => executeFreshnessQuery(connector, rule.tableName, timestampColumn, debugConfig, debugFactory), config?.timeoutMs || 30000, 'Freshness check query timeout');
26
+ if (!queryResult?.row) {
27
+ throw new QueryError('Query returned no results', 'freshness_query', rule.tableName);
28
+ }
29
+ const { rowCount, lastUpdate } = queryResult;
30
+ if (isNaN(rowCount) || rowCount < 0) {
31
+ throw new QueryError('Invalid row count returned from query', 'freshness_query', rule.tableName);
32
+ }
33
+ if (rowCount === 0) {
34
+ const executedAt = new Date();
35
+ const executionDurationMs = Date.now() - startTime;
36
+ await saveExecutionResult(metadataStorage, {
37
+ ruleId: rule.id,
38
+ status: 'alert',
39
+ rowCount: 0,
40
+ executionDurationMs,
41
+ executedAt,
42
+ error: 'Table is empty',
43
+ }, debugConfig);
44
+ return createSecureCheckResult('alert', {
45
+ rowCount: 0,
46
+ error: 'Table is empty',
47
+ executionDurationMs,
48
+ executedAt,
49
+ });
50
+ }
51
+ if (!lastUpdate) {
52
+ const executedAt = new Date();
53
+ const executionDurationMs = Date.now() - startTime;
54
+ await saveExecutionResult(metadataStorage, {
55
+ ruleId: rule.id,
56
+ status: 'alert',
57
+ rowCount,
58
+ executionDurationMs,
59
+ executedAt,
60
+ error: 'No timestamp found in specified column',
61
+ }, debugConfig);
62
+ return createSecureCheckResult('alert', {
63
+ rowCount,
64
+ error: 'No timestamp found in specified column',
65
+ executionDurationMs,
66
+ executedAt,
67
+ });
68
+ }
69
+ const currentTime = Date.now();
70
+ const updateTime = new Date(lastUpdate).getTime();
71
+ if (updateTime > currentTime + 3600000) {
72
+ throw new QueryError('Invalid timestamp: future date detected', 'freshness_query', rule.tableName);
73
+ }
74
+ const lagMs = currentTime - updateTime;
75
+ const lagMinutes = Math.floor(lagMs / 60000);
76
+ const isStale = lagMinutes > toleranceMinutes;
77
+ const status = isStale ? 'alert' : 'ok';
78
+ const executedAt = new Date();
79
+ const executionDurationMs = Date.now() - startTime;
80
+ const safeLagMinutes = Math.max(0, lagMinutes);
81
+ await saveExecutionResult(metadataStorage, {
82
+ ruleId: rule.id,
83
+ status,
84
+ rowCount,
85
+ lagMinutes: safeLagMinutes,
86
+ executionDurationMs,
87
+ executedAt,
88
+ }, debugConfig);
89
+ return createSecureCheckResult(status, {
90
+ rowCount,
91
+ lastUpdate: new Date(lastUpdate),
92
+ lagMinutes: safeLagMinutes,
93
+ executionDurationMs,
94
+ executedAt,
95
+ });
96
+ }
97
+ catch (error) {
98
+ const userMessage = ErrorHandler.getUserMessage(error);
99
+ const executedAt = new Date();
100
+ const executionDurationMs = Date.now() - startTime;
101
+ if (debugConfig.enabled) {
102
+ console.error(`[DEBUG-${debugId}] Freshness check failed:`, {
103
+ table: rule.tableName,
104
+ ruleId: rule.id,
105
+ error: userMessage,
106
+ rawError: debugConfig.exposeRawErrors && error instanceof Error ? error.message : undefined,
107
+ duration: executionDurationMs
108
+ });
109
+ }
110
+ if (rule?.id) {
111
+ await saveExecutionResult(metadataStorage, {
112
+ ruleId: rule.id,
113
+ status: 'failed',
114
+ executionDurationMs,
115
+ executedAt,
116
+ error: userMessage,
117
+ }, debugConfig);
118
+ }
119
+ const result = createSecureCheckResult('failed', {
120
+ error: userMessage,
121
+ executionDurationMs,
122
+ executedAt,
123
+ debugId,
124
+ });
125
+ if (debugConfig.enabled && error instanceof Error && 'debug' in error) {
126
+ result.debug = error.debug;
127
+ }
128
+ return result;
129
+ }
130
+ }
131
+ async function saveExecutionResult(metadataStorage, execution, debugConfig) {
132
+ if (!metadataStorage)
133
+ return;
134
+ try {
135
+ await metadataStorage.saveExecution({
136
+ ruleId: execution.ruleId,
137
+ status: execution.status,
138
+ rowCount: execution.rowCount,
139
+ lagMinutes: execution.lagMinutes,
140
+ executionDurationMs: execution.executionDurationMs,
141
+ executedAt: execution.executedAt,
142
+ error: execution.error,
143
+ });
144
+ }
145
+ catch (error) {
146
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
147
+ if (debugConfig?.enabled) {
148
+ console.error('[DEBUG] Failed to save execution history:', {
149
+ ruleId: execution.ruleId,
150
+ error: errorMessage,
151
+ rawError: debugConfig.exposeRawErrors ? errorMessage : undefined
152
+ });
153
+ }
154
+ else {
155
+ console.warn(`Failed to save execution history for rule ${execution.ruleId}: ${errorMessage}`);
156
+ }
157
+ }
158
+ }
159
+ function validateFreshnessRule(rule) {
160
+ if (!rule) {
161
+ throw new ConfigurationError('Monitoring rule is required');
162
+ }
163
+ if (!rule.tableName || typeof rule.tableName !== 'string') {
164
+ throw new ConfigurationError('Table name is required and must be a string');
165
+ }
166
+ if (rule.tableName.length > 256) {
167
+ throw new ConfigurationError('Table name too long (max 256 characters)');
168
+ }
169
+ if (rule.timestampColumn && typeof rule.timestampColumn !== 'string') {
170
+ throw new ConfigurationError('Timestamp column must be a string');
171
+ }
172
+ if (rule.timestampColumn && rule.timestampColumn.length > 256) {
173
+ throw new ConfigurationError('Timestamp column name too long (max 256 characters)');
174
+ }
175
+ if (rule.toleranceMinutes && (typeof rule.toleranceMinutes !== 'number' || !Number.isInteger(rule.toleranceMinutes))) {
176
+ throw new ConfigurationError('Tolerance minutes must be an integer');
177
+ }
178
+ if (rule.ruleType !== 'freshness') {
179
+ throw new ConfigurationError('Rule type must be "freshness" for freshness checks');
180
+ }
181
+ }
182
+ async function executeFreshnessQuery(connector, tableName, timestampColumn, debugConfig, debugFactory) {
183
+ const startTime = performance.now();
184
+ const queryContext = {
185
+ sql: `connector.getRowCount('${tableName}') + connector.getMaxTimestamp('${tableName}', '${timestampColumn}')`,
186
+ params: [],
187
+ table: tableName,
188
+ column: timestampColumn,
189
+ operation: 'freshness_query'
190
+ };
191
+ try {
192
+ if (debugConfig.enabled) {
193
+ console.log(`[DEBUG] Executing freshness check via connector:`, {
194
+ table: tableName,
195
+ column: timestampColumn,
196
+ operations: debugConfig.exposeQueries
197
+ ? `getRowCount('${tableName}'), getMaxTimestamp('${tableName}', '${timestampColumn}')`
198
+ : '[Connector operations hidden]'
199
+ });
200
+ }
201
+ const [rowCount, lastUpdate] = await Promise.all([
202
+ connector.getRowCount(tableName),
203
+ connector.getMaxTimestamp(tableName, timestampColumn)
204
+ ]);
205
+ queryContext.duration = performance.now() - startTime;
206
+ if (isNaN(rowCount) || rowCount < 0) {
207
+ throw debugFactory.createQueryError('Invalid row count returned from connector', undefined, queryContext);
208
+ }
209
+ const row = {
210
+ row_count: rowCount.toString(),
211
+ last_update: lastUpdate
212
+ };
213
+ return { rowCount, lastUpdate, row };
214
+ }
215
+ catch (error) {
216
+ queryContext.duration = performance.now() - startTime;
217
+ throw debugFactory.createQueryError('Failed to execute freshness check via connector', error instanceof Error ? error : undefined, queryContext);
218
+ }
219
+ }
220
+ async function executeWithTimeout(operation, timeoutMs, timeoutMessage) {
221
+ return new Promise((resolve, reject) => {
222
+ const timer = setTimeout(() => {
223
+ reject(new TimeoutError(timeoutMessage, 'freshness_check', timeoutMs));
224
+ }, timeoutMs);
225
+ operation()
226
+ .then(resolve)
227
+ .catch(reject)
228
+ .finally(() => clearTimeout(timer));
229
+ });
230
+ }
231
+ function createSecureCheckResult(status, data) {
232
+ return {
233
+ status,
234
+ executedAt: data.executedAt || new Date(),
235
+ executionDurationMs: data.executionDurationMs,
236
+ ...data
237
+ };
238
+ }
239
+ //# sourceMappingURL=freshness.js.map