@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.
- package/LICENSE +21 -0
- package/README.md +644 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +350 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/connectors/base-connector.d.ts +62 -0
- package/dist/connectors/base-connector.d.ts.map +1 -0
- package/dist/connectors/base-connector.js +549 -0
- package/dist/connectors/base-connector.js.map +1 -0
- package/dist/connectors/bigquery.d.ts +38 -0
- package/dist/connectors/bigquery.d.ts.map +1 -0
- package/dist/connectors/bigquery.js +406 -0
- package/dist/connectors/bigquery.js.map +1 -0
- package/dist/connectors/duckdb.d.ts +36 -0
- package/dist/connectors/duckdb.d.ts.map +1 -0
- package/dist/connectors/duckdb.js +364 -0
- package/dist/connectors/duckdb.js.map +1 -0
- package/dist/connectors/index.d.ts +7 -0
- package/dist/connectors/index.d.ts.map +1 -0
- package/dist/connectors/index.js +7 -0
- package/dist/connectors/index.js.map +1 -0
- package/dist/connectors/mysql.d.ts +32 -0
- package/dist/connectors/mysql.d.ts.map +1 -0
- package/dist/connectors/mysql.js +348 -0
- package/dist/connectors/mysql.js.map +1 -0
- package/dist/connectors/postgres.d.ts +31 -0
- package/dist/connectors/postgres.d.ts.map +1 -0
- package/dist/connectors/postgres.js +326 -0
- package/dist/connectors/postgres.js.map +1 -0
- package/dist/connectors/redshift.d.ts +32 -0
- package/dist/connectors/redshift.d.ts.map +1 -0
- package/dist/connectors/redshift.js +366 -0
- package/dist/connectors/redshift.js.map +1 -0
- package/dist/connectors/snowflake.d.ts +43 -0
- package/dist/connectors/snowflake.d.ts.map +1 -0
- package/dist/connectors/snowflake.js +442 -0
- package/dist/connectors/snowflake.js.map +1 -0
- package/dist/db/index.d.ts +9 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +10 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/migrate.d.ts +12 -0
- package/dist/db/migrate.d.ts.map +1 -0
- package/dist/db/migrate.js +114 -0
- package/dist/db/migrate.js.map +1 -0
- package/dist/db/schema.d.ts +2053 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +164 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/errors/debug-factory.d.ts +23 -0
- package/dist/errors/debug-factory.d.ts.map +1 -0
- package/dist/errors/debug-factory.js +149 -0
- package/dist/errors/debug-factory.js.map +1 -0
- package/dist/errors/index.d.ts +119 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +341 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/metadata/duckdb-storage.d.ts +31 -0
- package/dist/metadata/duckdb-storage.d.ts.map +1 -0
- package/dist/metadata/duckdb-storage.js +230 -0
- package/dist/metadata/duckdb-storage.js.map +1 -0
- package/dist/metadata/factory.d.ts +4 -0
- package/dist/metadata/factory.d.ts.map +1 -0
- package/dist/metadata/factory.js +23 -0
- package/dist/metadata/factory.js.map +1 -0
- package/dist/metadata/index.d.ts +6 -0
- package/dist/metadata/index.d.ts.map +1 -0
- package/dist/metadata/index.js +4 -0
- package/dist/metadata/index.js.map +1 -0
- package/dist/metadata/interface.d.ts +26 -0
- package/dist/metadata/interface.d.ts.map +1 -0
- package/dist/metadata/interface.js +2 -0
- package/dist/metadata/interface.js.map +1 -0
- package/dist/metadata/postgresql-storage.d.ts +32 -0
- package/dist/metadata/postgresql-storage.d.ts.map +1 -0
- package/dist/metadata/postgresql-storage.js +242 -0
- package/dist/metadata/postgresql-storage.js.map +1 -0
- package/dist/metadata/schema-config.d.ts +30 -0
- package/dist/metadata/schema-config.d.ts.map +1 -0
- package/dist/metadata/schema-config.js +94 -0
- package/dist/metadata/schema-config.js.map +1 -0
- package/dist/metadata/types.d.ts +35 -0
- package/dist/metadata/types.d.ts.map +1 -0
- package/dist/metadata/types.js +2 -0
- package/dist/metadata/types.js.map +1 -0
- package/dist/monitor/baseline-calculator.d.ts +30 -0
- package/dist/monitor/baseline-calculator.d.ts.map +1 -0
- package/dist/monitor/baseline-calculator.js +192 -0
- package/dist/monitor/baseline-calculator.js.map +1 -0
- package/dist/monitor/baseline-config.d.ts +37 -0
- package/dist/monitor/baseline-config.d.ts.map +1 -0
- package/dist/monitor/baseline-config.js +156 -0
- package/dist/monitor/baseline-config.js.map +1 -0
- package/dist/monitor/freshness.d.ts +5 -0
- package/dist/monitor/freshness.d.ts.map +1 -0
- package/dist/monitor/freshness.js +239 -0
- package/dist/monitor/freshness.js.map +1 -0
- package/dist/monitor/index.d.ts +5 -0
- package/dist/monitor/index.d.ts.map +1 -0
- package/dist/monitor/index.js +5 -0
- package/dist/monitor/index.js.map +1 -0
- package/dist/monitor/schema-baseline.d.ts +22 -0
- package/dist/monitor/schema-baseline.d.ts.map +1 -0
- package/dist/monitor/schema-baseline.js +211 -0
- package/dist/monitor/schema-baseline.js.map +1 -0
- package/dist/monitor/schema-changes.d.ts +5 -0
- package/dist/monitor/schema-changes.d.ts.map +1 -0
- package/dist/monitor/schema-changes.js +289 -0
- package/dist/monitor/schema-changes.js.map +1 -0
- package/dist/monitor/volume.d.ts +5 -0
- package/dist/monitor/volume.d.ts.map +1 -0
- package/dist/monitor/volume.js +262 -0
- package/dist/monitor/volume.js.map +1 -0
- package/dist/observability/logger.d.ts +63 -0
- package/dist/observability/logger.d.ts.map +1 -0
- package/dist/observability/logger.js +282 -0
- package/dist/observability/logger.js.map +1 -0
- package/dist/observability/metrics.d.ts +106 -0
- package/dist/observability/metrics.d.ts.map +1 -0
- package/dist/observability/metrics.js +441 -0
- package/dist/observability/metrics.js.map +1 -0
- package/dist/query-analyzer.js +526 -0
- package/dist/resilience/circuit-breaker.d.ts +94 -0
- package/dist/resilience/circuit-breaker.d.ts.map +1 -0
- package/dist/resilience/circuit-breaker.js +379 -0
- package/dist/resilience/circuit-breaker.js.map +1 -0
- package/dist/resilience/index.d.ts +7 -0
- package/dist/resilience/index.d.ts.map +1 -0
- package/dist/resilience/index.js +7 -0
- package/dist/resilience/index.js.map +1 -0
- package/dist/resilience/retry-policy.d.ts +87 -0
- package/dist/resilience/retry-policy.d.ts.map +1 -0
- package/dist/resilience/retry-policy.js +423 -0
- package/dist/resilience/retry-policy.js.map +1 -0
- package/dist/resilience/timeout-manager.d.ts +97 -0
- package/dist/resilience/timeout-manager.d.ts.map +1 -0
- package/dist/resilience/timeout-manager.js +339 -0
- package/dist/resilience/timeout-manager.js.map +1 -0
- package/dist/security/query-analyzer.d.ts +82 -0
- package/dist/security/query-analyzer.d.ts.map +1 -0
- package/dist/security/query-analyzer.js +381 -0
- package/dist/security/query-analyzer.js.map +1 -0
- package/dist/security/schema-cache.d.ts +95 -0
- package/dist/security/schema-cache.d.ts.map +1 -0
- package/dist/security/schema-cache.js +344 -0
- package/dist/security/schema-cache.js.map +1 -0
- package/dist/types/connector.d.ts +68 -0
- package/dist/types/connector.d.ts.map +1 -0
- package/dist/types/connector.js +26 -0
- package/dist/types/connector.js.map +1 -0
- package/dist/types.d.ts +244 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/validation/index.d.ts +7 -0
- package/dist/validation/index.d.ts.map +1 -0
- package/dist/validation/index.js +5 -0
- package/dist/validation/index.js.map +1 -0
- package/dist/validation/runtime-validator.d.ts +70 -0
- package/dist/validation/runtime-validator.d.ts.map +1 -0
- package/dist/validation/runtime-validator.js +206 -0
- package/dist/validation/runtime-validator.js.map +1 -0
- package/dist/validation/sanitizers.d.ts +56 -0
- package/dist/validation/sanitizers.d.ts.map +1 -0
- package/dist/validation/sanitizers.js +264 -0
- package/dist/validation/sanitizers.js.map +1 -0
- package/dist/validation/schemas.d.ts +224 -0
- package/dist/validation/schemas.d.ts.map +1 -0
- package/dist/validation/schemas.js +263 -0
- package/dist/validation/schemas.js.map +1 -0
- package/dist/validators/index.d.ts +18 -0
- package/dist/validators/index.d.ts.map +1 -0
- package/dist/validators/index.js +209 -0
- package/dist/validators/index.js.map +1 -0
- package/package.json +91 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 FreshGuard
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,644 @@
|
|
|
1
|
+
# FreshGuard Core
|
|
2
|
+
|
|
3
|
+
**Open source data pipeline freshness monitoring engine for self-hosting.**
|
|
4
|
+
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[](https://www.npmjs.com/package/@freshguard/freshguard-core)
|
|
7
|
+
|
|
8
|
+
## What is FreshGuard Core?
|
|
9
|
+
|
|
10
|
+
Monitor when your data pipelines go stale. Get alerts when:
|
|
11
|
+
- **Data hasn't updated in X minutes** (freshness checks)
|
|
12
|
+
- **Row counts deviate unexpectedly** (volume anomaly detection)
|
|
13
|
+
- **Database schemas change unexpectedly** (schema change monitoring)
|
|
14
|
+
|
|
15
|
+
Supports PostgreSQL, DuckDB, BigQuery, and Snowflake. Self-hosted. Free forever.
|
|
16
|
+
|
|
17
|
+
## 🔒 Security Features
|
|
18
|
+
|
|
19
|
+
FreshGuard Core includes basic security protections for self-hosted deployments:
|
|
20
|
+
|
|
21
|
+
**🛡️ Query Security**
|
|
22
|
+
- ✅ **SQL Injection Protection** - Input validation and pattern analysis
|
|
23
|
+
- ✅ **Query Validation** - Basic checks for dangerous operations
|
|
24
|
+
- ✅ **Input Sanitization** - Identifier validation and parameter checking
|
|
25
|
+
|
|
26
|
+
**🔄 Resilience Features**
|
|
27
|
+
- ✅ **Circuit Breaker Protection** - Automatic failure detection and recovery
|
|
28
|
+
- ✅ **Retry Logic** - Exponential backoff with jitter
|
|
29
|
+
- ✅ **Timeout Protection** - Query and connection timeouts
|
|
30
|
+
- ✅ **Connection Management** - Basic connection pooling
|
|
31
|
+
|
|
32
|
+
**📊 Observability**
|
|
33
|
+
- ✅ **Structured Logging** - JSON logging with Pino
|
|
34
|
+
- ✅ **Error Handling** - Sanitized error messages
|
|
35
|
+
- ✅ **Performance Tracking** - Basic query performance metrics
|
|
36
|
+
|
|
37
|
+
**🔐 Security Basics**
|
|
38
|
+
- ✅ **SSL/TLS Support** - Secure database connections
|
|
39
|
+
- ✅ **Environment Variables** - Secure credential management
|
|
40
|
+
- ✅ **Error Sanitization** - Safe error messages
|
|
41
|
+
|
|
42
|
+
**📋 [Complete Security Guide →](docs/SECURITY_FOR_SELF_HOSTERS.md)** | **🚀 [Integration Guide →](docs/INTEGRATION_GUIDE.md)**
|
|
43
|
+
|
|
44
|
+
## Quick Start
|
|
45
|
+
|
|
46
|
+
### 1. Install
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pnpm install @freshguard/freshguard-core
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 2. Check Freshness
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import { checkFreshness, PostgresConnector } from '@freshguard/freshguard-core';
|
|
56
|
+
import type { MonitoringRule } from '@freshguard/freshguard-core';
|
|
57
|
+
|
|
58
|
+
// Connect to your database
|
|
59
|
+
const connector = new PostgresConnector({
|
|
60
|
+
host: process.env.DB_HOST || 'localhost',
|
|
61
|
+
port: Number(process.env.DB_PORT) || 5432,
|
|
62
|
+
database: process.env.DB_NAME || 'mydb',
|
|
63
|
+
username: process.env.DB_USER!,
|
|
64
|
+
password: process.env.DB_PASSWORD!,
|
|
65
|
+
ssl: true, // Enable SSL for secure connections
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const rule: MonitoringRule = {
|
|
69
|
+
id: 'orders-freshness',
|
|
70
|
+
sourceId: 'prod_db',
|
|
71
|
+
name: 'Orders Freshness',
|
|
72
|
+
tableName: 'orders',
|
|
73
|
+
ruleType: 'freshness',
|
|
74
|
+
toleranceMinutes: 60,
|
|
75
|
+
timestampColumn: 'updated_at',
|
|
76
|
+
checkIntervalMinutes: 5,
|
|
77
|
+
isActive: true,
|
|
78
|
+
createdAt: new Date(),
|
|
79
|
+
updatedAt: new Date(),
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const result = await checkFreshness(connector, rule);
|
|
83
|
+
|
|
84
|
+
if (result.status === 'alert') {
|
|
85
|
+
console.log(`⚠️ Data is ${result.lagMinutes}m stale!`);
|
|
86
|
+
} else {
|
|
87
|
+
console.log(`✅ Data is fresh (lag: ${result.lagMinutes}m)`);
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 3. Check Volume Anomalies
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
import { checkVolumeAnomaly, PostgresConnector } from '@freshguard/freshguard-core';
|
|
95
|
+
|
|
96
|
+
const connector = new PostgresConnector({
|
|
97
|
+
host: process.env.DB_HOST!,
|
|
98
|
+
database: process.env.DB_NAME!,
|
|
99
|
+
username: process.env.DB_USER!,
|
|
100
|
+
password: process.env.DB_PASSWORD!,
|
|
101
|
+
ssl: true,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const result = await checkVolumeAnomaly(connector, rule);
|
|
105
|
+
|
|
106
|
+
if (result.status === 'alert') {
|
|
107
|
+
console.log(`⚠️ Volume anomaly detected: ${result.deviation}% deviation from baseline`);
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 4. Monitor Schema Changes
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
import { checkSchemaChanges, PostgresConnector } from '@freshguard/freshguard-core';
|
|
115
|
+
|
|
116
|
+
const schemaRule: MonitoringRule = {
|
|
117
|
+
id: 'users-schema',
|
|
118
|
+
sourceId: 'prod_db',
|
|
119
|
+
name: 'Users Table Schema Monitor',
|
|
120
|
+
tableName: 'users',
|
|
121
|
+
ruleType: 'schema_change',
|
|
122
|
+
checkIntervalMinutes: 60,
|
|
123
|
+
isActive: true,
|
|
124
|
+
trackColumnChanges: true,
|
|
125
|
+
trackTableChanges: true,
|
|
126
|
+
schemaChangeConfig: {
|
|
127
|
+
adaptationMode: 'manual', // 'auto' | 'manual' | 'alert_only'
|
|
128
|
+
monitoringMode: 'full', // 'full' | 'partial'
|
|
129
|
+
trackedColumns: {
|
|
130
|
+
alertLevel: 'medium', // 'low' | 'medium' | 'high'
|
|
131
|
+
trackTypes: true, // Monitor data type changes
|
|
132
|
+
trackNullability: false // Don't track nullability changes
|
|
133
|
+
},
|
|
134
|
+
baselineRefreshDays: 30 // Auto-refresh baseline monthly
|
|
135
|
+
},
|
|
136
|
+
createdAt: new Date(),
|
|
137
|
+
updatedAt: new Date(),
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const result = await checkSchemaChanges(connector, schemaRule, metadataStorage);
|
|
141
|
+
|
|
142
|
+
if (result.status === 'alert') {
|
|
143
|
+
console.log(`⚠️ Schema changes detected: ${result.schemaChanges?.summary}`);
|
|
144
|
+
|
|
145
|
+
// Check specific changes
|
|
146
|
+
if (result.schemaChanges?.addedColumns?.length > 0) {
|
|
147
|
+
console.log('New columns:', result.schemaChanges.addedColumns.map(c => c.columnName));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (result.schemaChanges?.removedColumns?.length > 0) {
|
|
151
|
+
console.log('Removed columns:', result.schemaChanges.removedColumns.map(c => c.columnName));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (result.schemaChanges?.modifiedColumns?.length > 0) {
|
|
155
|
+
console.log('Modified columns:', result.schemaChanges.modifiedColumns.map(c =>
|
|
156
|
+
`${c.columnName} (${c.changeType}): ${c.oldValue} → ${c.newValue}`
|
|
157
|
+
));
|
|
158
|
+
}
|
|
159
|
+
} else {
|
|
160
|
+
console.log(`✅ Schema is stable (${result.schemaChanges?.changeCount || 0} changes)`);
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**Schema Change Adaptation Modes:**
|
|
165
|
+
- **`auto`** - Automatically adapt to safe changes (column additions, safe type changes)
|
|
166
|
+
- **`manual`** - Require manual approval for all changes (default)
|
|
167
|
+
- **`alert_only`** - Always alert, never update baseline automatically
|
|
168
|
+
|
|
169
|
+
**Monitoring Modes:**
|
|
170
|
+
- **`full`** - Monitor all columns in the table (default)
|
|
171
|
+
- **`partial`** - Monitor only specified columns in `trackedColumns.columns` array
|
|
172
|
+
|
|
173
|
+
## 📊 Metadata Storage
|
|
174
|
+
|
|
175
|
+
FreshGuard tracks execution history for volume anomaly detection and monitoring analytics. Choose between **DuckDB** (embedded, zero-setup) or **PostgreSQL** (production-ready) storage.
|
|
176
|
+
|
|
177
|
+
### Quick Setup (Zero Configuration)
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
import { createMetadataStorage, checkVolumeAnomaly, PostgresConnector } from '@freshguard/freshguard-core';
|
|
181
|
+
|
|
182
|
+
// Create database connector
|
|
183
|
+
const connector = new PostgresConnector({
|
|
184
|
+
host: process.env.DB_HOST!,
|
|
185
|
+
database: process.env.DB_NAME!,
|
|
186
|
+
username: process.env.DB_USER!,
|
|
187
|
+
password: process.env.DB_PASSWORD!,
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// Automatic setup - creates ./freshguard-metadata.db
|
|
191
|
+
const metadataStorage = await createMetadataStorage();
|
|
192
|
+
|
|
193
|
+
// Use with monitoring functions
|
|
194
|
+
const result = await checkVolumeAnomaly(connector, rule, metadataStorage);
|
|
195
|
+
|
|
196
|
+
// Clean up
|
|
197
|
+
await metadataStorage.close();
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Storage Options
|
|
201
|
+
|
|
202
|
+
**DuckDB (Recommended for Self-Hosting)**
|
|
203
|
+
- ✅ Zero database server setup
|
|
204
|
+
- ✅ Single file storage (`./freshguard-metadata.db`)
|
|
205
|
+
- ✅ Perfect for Docker containers
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
// Custom path
|
|
209
|
+
const storage = await createMetadataStorage({
|
|
210
|
+
type: 'duckdb',
|
|
211
|
+
path: './my-freshguard-data.db'
|
|
212
|
+
});
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**PostgreSQL (Recommended for Production)**
|
|
216
|
+
- ✅ Full ACID compliance
|
|
217
|
+
- ✅ Concurrent access support
|
|
218
|
+
- ✅ Backup/restore capabilities
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
// Production setup
|
|
222
|
+
const storage = await createMetadataStorage({
|
|
223
|
+
type: 'postgresql',
|
|
224
|
+
url: 'postgresql://user:pass@host:5432/freshguard_metadata'
|
|
225
|
+
});
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**📋 [Complete Metadata Storage Guide →](docs/METADATA_STORAGE.md)**
|
|
229
|
+
|
|
230
|
+
### 🚨 Error Handling
|
|
231
|
+
|
|
232
|
+
FreshGuard Core exports comprehensive error classes for proper error handling:
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
import {
|
|
236
|
+
checkFreshness,
|
|
237
|
+
PostgresConnector,
|
|
238
|
+
SecurityError,
|
|
239
|
+
ConnectionError,
|
|
240
|
+
TimeoutError,
|
|
241
|
+
QueryError,
|
|
242
|
+
ConfigurationError,
|
|
243
|
+
MonitoringError
|
|
244
|
+
} from '@freshguard/freshguard-core';
|
|
245
|
+
|
|
246
|
+
try {
|
|
247
|
+
const result = await checkFreshness(connector, rule);
|
|
248
|
+
console.log(`✅ Check completed: ${result.status}`);
|
|
249
|
+
} catch (error) {
|
|
250
|
+
// Handle specific error types
|
|
251
|
+
if (error instanceof SecurityError) {
|
|
252
|
+
console.error('🔒 Security violation:', error.message);
|
|
253
|
+
// Log security incident, block request source
|
|
254
|
+
} else if (error instanceof ConnectionError) {
|
|
255
|
+
console.error('🔌 Database connection failed:', error.message);
|
|
256
|
+
// Retry with backoff, check network connectivity
|
|
257
|
+
} else if (error instanceof TimeoutError) {
|
|
258
|
+
console.error('⏱️ Query timeout:', error.message);
|
|
259
|
+
// Check query complexity, database performance
|
|
260
|
+
} else if (error instanceof QueryError) {
|
|
261
|
+
console.error('📊 Query execution failed:', error.message);
|
|
262
|
+
// Check table exists, column names, permissions
|
|
263
|
+
} else if (error instanceof ConfigurationError) {
|
|
264
|
+
console.error('⚙️ Configuration error:', error.message);
|
|
265
|
+
// Check environment variables, config file
|
|
266
|
+
} else if (error instanceof MonitoringError) {
|
|
267
|
+
console.error('📈 Monitoring check failed:', error.message);
|
|
268
|
+
// Check rule configuration, data availability
|
|
269
|
+
} else {
|
|
270
|
+
console.error('❌ Unknown error:', error.message);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
**Error Properties:**
|
|
276
|
+
- `error.code` - Machine-readable error code (e.g., "SECURITY_VIOLATION")
|
|
277
|
+
- `error.timestamp` - When the error occurred
|
|
278
|
+
- `error.sanitized` - Whether error message is safe for user display
|
|
279
|
+
|
|
280
|
+
## Features
|
|
281
|
+
|
|
282
|
+
### 📊 Monitoring
|
|
283
|
+
✅ **Freshness Monitoring** - Detect stale data based on last update time
|
|
284
|
+
✅ **Volume Anomaly Detection** - Identify unexpected row count changes
|
|
285
|
+
✅ **Schema Change Monitoring** - Track database schema evolution with configurable adaptation modes
|
|
286
|
+
|
|
287
|
+
### 🗄️ Database Support
|
|
288
|
+
✅ **PostgreSQL** - Production-ready with SSL/TLS support
|
|
289
|
+
✅ **DuckDB** - Analytics and local development
|
|
290
|
+
✅ **BigQuery** - Google Cloud data warehouses
|
|
291
|
+
✅ **Snowflake** - Enterprise data platforms
|
|
292
|
+
|
|
293
|
+
### 🔒 Security
|
|
294
|
+
✅ **Security Basics** - Input validation and secure connections
|
|
295
|
+
✅ **Error Sanitization** - Safe error handling and logging
|
|
296
|
+
✅ **Open Source** - Transparent and auditable code
|
|
297
|
+
|
|
298
|
+
### 🛠️ Developer Experience
|
|
299
|
+
✅ **Type-Safe** - Written in TypeScript with full type definitions
|
|
300
|
+
✅ **CLI Tool** - Secure command-line interface for self-hosters
|
|
301
|
+
✅ **Self-Hosted** - Run on your own infrastructure
|
|
302
|
+
✅ **MIT Licensed** - Free to use, modify, and distribute
|
|
303
|
+
|
|
304
|
+
## 🖥️ CLI Usage
|
|
305
|
+
|
|
306
|
+
FreshGuard Core includes a CLI tool for self-hosters:
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
# Set up environment variables
|
|
310
|
+
export FRESHGUARD_DATABASE_URL="postgresql://user:password@localhost:5432/db?sslmode=require"
|
|
311
|
+
|
|
312
|
+
# Initialize monitoring configuration
|
|
313
|
+
pnpm exec freshguard init
|
|
314
|
+
|
|
315
|
+
# Test connection
|
|
316
|
+
pnpm exec freshguard test
|
|
317
|
+
|
|
318
|
+
# Run monitoring scheduler
|
|
319
|
+
pnpm exec freshguard run
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
**Features:**
|
|
323
|
+
- 🔐 **Environment variables** - Secure credential management
|
|
324
|
+
- 📝 **Configuration validation** - Proper setup verification
|
|
325
|
+
- 🔒 **SSL support** - Secure database connections
|
|
326
|
+
- 📊 **Monitoring commands** - Run checks and view results
|
|
327
|
+
|
|
328
|
+
**📋 [Security Guide →](docs/SECURITY_FOR_SELF_HOSTERS.md)**
|
|
329
|
+
|
|
330
|
+
## 🚀 Self-Hosting
|
|
331
|
+
|
|
332
|
+
### Production Deployment
|
|
333
|
+
|
|
334
|
+
**📋 [Security Guide →](docs/SECURITY_FOR_SELF_HOSTERS.md)**
|
|
335
|
+
|
|
336
|
+
Important considerations for production deployments:
|
|
337
|
+
- **🔒 Security checklist and best practices**
|
|
338
|
+
- **🗄️ Database security configuration** (PostgreSQL, BigQuery, Snowflake)
|
|
339
|
+
- **🌐 Network configuration**
|
|
340
|
+
- **🔑 Credential management**
|
|
341
|
+
- **📊 Monitoring and logging**
|
|
342
|
+
|
|
343
|
+
### Deployment Guides
|
|
344
|
+
|
|
345
|
+
See the [Self-Hosting Guide](docs/SELF_HOSTING.md) for:
|
|
346
|
+
- Docker deployment with security hardening
|
|
347
|
+
- Kubernetes setup with secrets management
|
|
348
|
+
- Environment configuration examples
|
|
349
|
+
- Custom alerting integration
|
|
350
|
+
|
|
351
|
+
## What's Not Included
|
|
352
|
+
|
|
353
|
+
This is the **open source core**. It does not include:
|
|
354
|
+
- Managed hosting (you manage uptime)
|
|
355
|
+
- Multi-user dashboard and config UI (use config files instead)
|
|
356
|
+
|
|
357
|
+
Want these features? Check out **[FreshGuard Cloud](https://freshguard.dev)** - our managed SaaS.
|
|
358
|
+
|
|
359
|
+
## Architecture
|
|
360
|
+
|
|
361
|
+
FreshGuard uses an **Open Core** model:
|
|
362
|
+
|
|
363
|
+
- **`@freshguard/freshguard-core`** (this package) - MIT licensed, open source monitoring engine
|
|
364
|
+
- **`freshguard`** - Proprietary multi-tenant SaaS (optional)
|
|
365
|
+
|
|
366
|
+
You can self-host the core or use our managed cloud service.
|
|
367
|
+
|
|
368
|
+
## Contributing
|
|
369
|
+
|
|
370
|
+
We welcome contributions! See [CONTRIBUTING.md](docs/CONTRIBUTING.md).
|
|
371
|
+
|
|
372
|
+
## Examples
|
|
373
|
+
|
|
374
|
+
### 📊 Database Connections
|
|
375
|
+
|
|
376
|
+
```typescript
|
|
377
|
+
import { PostgresConnector, BigQueryConnector } from '@freshguard/freshguard-core';
|
|
378
|
+
|
|
379
|
+
// PostgreSQL connection
|
|
380
|
+
const pgConfig = {
|
|
381
|
+
host: 'localhost',
|
|
382
|
+
port: 5432,
|
|
383
|
+
database: 'myapp',
|
|
384
|
+
username: process.env.DB_USER!,
|
|
385
|
+
password: process.env.DB_PASSWORD!,
|
|
386
|
+
ssl: true, // Enable SSL for secure connections
|
|
387
|
+
};
|
|
388
|
+
const postgres = new PostgresConnector(pgConfig);
|
|
389
|
+
|
|
390
|
+
// BigQuery connection
|
|
391
|
+
const bqConfig = {
|
|
392
|
+
host: 'bigquery.googleapis.com',
|
|
393
|
+
database: 'my-project',
|
|
394
|
+
password: process.env.BIGQUERY_SERVICE_ACCOUNT_JSON!,
|
|
395
|
+
ssl: true,
|
|
396
|
+
};
|
|
397
|
+
const bigquery = new BigQueryConnector(bqConfig);
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
### 🔔 Custom Alerting
|
|
401
|
+
|
|
402
|
+
```typescript
|
|
403
|
+
import { checkFreshness } from '@freshguard/freshguard-core';
|
|
404
|
+
import { PostgresConnector } from '@freshguard/freshguard-core';
|
|
405
|
+
import { sendSlackAlert } from './alerts.js';
|
|
406
|
+
|
|
407
|
+
// Database connection
|
|
408
|
+
const connector = new PostgresConnector({
|
|
409
|
+
host: process.env.DB_HOST!,
|
|
410
|
+
database: process.env.DB_NAME!,
|
|
411
|
+
username: process.env.DB_USER!,
|
|
412
|
+
password: process.env.DB_PASSWORD!,
|
|
413
|
+
ssl: true,
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
const result = await checkFreshness(connector, rule);
|
|
417
|
+
|
|
418
|
+
if (result.status === 'alert') {
|
|
419
|
+
await sendSlackAlert({
|
|
420
|
+
channel: '#data-alerts',
|
|
421
|
+
message: `⚠️ ${rule.name} is stale (${result.lagMinutes}m lag)`,
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
### 📅 Scheduled Monitoring
|
|
427
|
+
|
|
428
|
+
```typescript
|
|
429
|
+
import { checkFreshness, checkVolumeAnomaly, checkSchemaChanges } from '@freshguard/freshguard-core';
|
|
430
|
+
import { PostgresConnector } from '@freshguard/freshguard-core';
|
|
431
|
+
import cron from 'node-cron';
|
|
432
|
+
|
|
433
|
+
const connector = new PostgresConnector({
|
|
434
|
+
host: process.env.DB_HOST!,
|
|
435
|
+
database: process.env.DB_NAME!,
|
|
436
|
+
username: process.env.DB_USER!,
|
|
437
|
+
password: process.env.DB_PASSWORD!,
|
|
438
|
+
ssl: true,
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
// Run every 5 minutes with comprehensive error handling
|
|
442
|
+
cron.schedule('*/5 * * * *', async () => {
|
|
443
|
+
try {
|
|
444
|
+
const result = await checkFreshness(connector, rule);
|
|
445
|
+
console.log(`✅ Check result: ${result.status}`);
|
|
446
|
+
} catch (error) {
|
|
447
|
+
// Import error classes for specific handling
|
|
448
|
+
const { SecurityError, ConnectionError, TimeoutError } = require('@freshguard/freshguard-core');
|
|
449
|
+
|
|
450
|
+
if (error instanceof ConnectionError) {
|
|
451
|
+
console.error(`🔌 Database connection failed: ${error.message}`);
|
|
452
|
+
// Implement reconnection logic
|
|
453
|
+
} else if (error instanceof TimeoutError) {
|
|
454
|
+
console.error(`⏱️ Query timeout: ${error.message}`);
|
|
455
|
+
// Alert ops team about performance issues
|
|
456
|
+
} else if (error instanceof SecurityError) {
|
|
457
|
+
console.error(`🔒 Security violation: ${error.message}`);
|
|
458
|
+
// Log security incident for investigation
|
|
459
|
+
} else {
|
|
460
|
+
console.error(`❌ Monitoring failed: ${error.message}`);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
// Monitor schema changes hourly
|
|
466
|
+
cron.schedule('0 * * * *', async () => {
|
|
467
|
+
try {
|
|
468
|
+
const schemaRule = {
|
|
469
|
+
id: 'user-schema-monitor',
|
|
470
|
+
sourceId: 'prod_db',
|
|
471
|
+
name: 'User Table Schema Monitor',
|
|
472
|
+
tableName: 'users',
|
|
473
|
+
ruleType: 'schema_change',
|
|
474
|
+
checkIntervalMinutes: 60,
|
|
475
|
+
isActive: true,
|
|
476
|
+
schemaChangeConfig: {
|
|
477
|
+
adaptationMode: 'manual', // Require manual approval
|
|
478
|
+
monitoringMode: 'full', // Monitor all columns
|
|
479
|
+
trackedColumns: {
|
|
480
|
+
alertLevel: 'high', // High-priority alerts
|
|
481
|
+
trackTypes: true,
|
|
482
|
+
trackNullability: false
|
|
483
|
+
}
|
|
484
|
+
},
|
|
485
|
+
createdAt: new Date(),
|
|
486
|
+
updatedAt: new Date(),
|
|
487
|
+
};
|
|
488
|
+
|
|
489
|
+
const result = await checkSchemaChanges(connector, schemaRule, metadataStorage);
|
|
490
|
+
|
|
491
|
+
if (result.status === 'alert') {
|
|
492
|
+
console.log(`🚨 Schema changes detected in users table: ${result.schemaChanges?.summary}`);
|
|
493
|
+
// Send critical alert to operations team
|
|
494
|
+
} else {
|
|
495
|
+
console.log(`✅ Schema check passed: ${result.schemaChanges?.changeCount || 0} changes`);
|
|
496
|
+
}
|
|
497
|
+
} catch (error) {
|
|
498
|
+
console.error(`❌ Schema monitoring failed: ${error.message}`);
|
|
499
|
+
}
|
|
500
|
+
});
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
## 📚 API Documentation
|
|
505
|
+
|
|
506
|
+
### Database Connectors
|
|
507
|
+
|
|
508
|
+
```typescript
|
|
509
|
+
// Import connectors, monitoring functions, and error classes
|
|
510
|
+
import {
|
|
511
|
+
PostgresConnector,
|
|
512
|
+
DuckDBConnector,
|
|
513
|
+
BigQueryConnector,
|
|
514
|
+
SnowflakeConnector,
|
|
515
|
+
checkFreshness,
|
|
516
|
+
checkVolumeAnomaly,
|
|
517
|
+
checkSchemaChanges,
|
|
518
|
+
SecurityError,
|
|
519
|
+
ConnectionError,
|
|
520
|
+
TimeoutError,
|
|
521
|
+
QueryError,
|
|
522
|
+
ConfigurationError,
|
|
523
|
+
MonitoringError
|
|
524
|
+
} from '@freshguard/freshguard-core';
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
### Error Classes
|
|
528
|
+
|
|
529
|
+
FreshGuard Core provides comprehensive error handling with specific error types:
|
|
530
|
+
|
|
531
|
+
- **`SecurityError`** - SQL injection attempts, invalid identifiers, blocked queries
|
|
532
|
+
- **`ConnectionError`** - Database connection failures, authentication issues
|
|
533
|
+
- **`TimeoutError`** - Query timeouts, connection timeouts
|
|
534
|
+
- **`QueryError`** - Syntax errors, table/column not found, execution failures
|
|
535
|
+
- **`ConfigurationError`** - Missing required fields, invalid configuration values
|
|
536
|
+
- **`MonitoringError`** - Freshness check failures, volume anomaly detection errors
|
|
537
|
+
|
|
538
|
+
All errors include:
|
|
539
|
+
- `error.code` - Machine-readable error code
|
|
540
|
+
- `error.timestamp` - Error occurrence timestamp
|
|
541
|
+
- `error.sanitized` - Whether the message is safe for user display
|
|
542
|
+
|
|
543
|
+
### `checkFreshness(connector, rule)`
|
|
544
|
+
|
|
545
|
+
Check data freshness for a given monitoring rule.
|
|
546
|
+
|
|
547
|
+
**Parameters:**
|
|
548
|
+
- `connector` - Database connector (PostgresConnector, BigQueryConnector, etc.)
|
|
549
|
+
- `rule` - Monitoring rule configuration
|
|
550
|
+
|
|
551
|
+
**Returns:** `Promise<CheckResult>` with status and lag information
|
|
552
|
+
|
|
553
|
+
### `checkVolumeAnomaly(connector, rule)`
|
|
554
|
+
|
|
555
|
+
Check for volume anomalies in row counts.
|
|
556
|
+
|
|
557
|
+
**Parameters:**
|
|
558
|
+
- `connector` - Database connector
|
|
559
|
+
- `rule` - Monitoring rule configuration
|
|
560
|
+
|
|
561
|
+
**Returns:** `Promise<CheckResult>` with anomaly detection results
|
|
562
|
+
|
|
563
|
+
### `checkSchemaChanges(connector, rule)`
|
|
564
|
+
|
|
565
|
+
Monitor database schema changes with configurable adaptation modes.
|
|
566
|
+
|
|
567
|
+
**Parameters:**
|
|
568
|
+
- `connector` - Secure database connector
|
|
569
|
+
- `rule` - Monitoring rule with `ruleType: 'schema_change'` and optional `schemaChangeConfig`
|
|
570
|
+
- `metadataStorage` (optional) - Metadata storage for baseline persistence
|
|
571
|
+
|
|
572
|
+
**Returns:** `Promise<CheckResult>` with `schemaChanges` field containing:
|
|
573
|
+
- `hasChanges` - Boolean indicating if changes were detected
|
|
574
|
+
- `addedColumns` - Array of newly added columns
|
|
575
|
+
- `removedColumns` - Array of removed columns (breaking changes)
|
|
576
|
+
- `modifiedColumns` - Array of type/constraint changes
|
|
577
|
+
- `summary` - Human-readable change summary
|
|
578
|
+
- `changeCount` - Total number of changes
|
|
579
|
+
- `severity` - Change impact level ('low', 'medium', 'high')
|
|
580
|
+
|
|
581
|
+
### Database Connectors
|
|
582
|
+
|
|
583
|
+
**PostgresConnector** - PostgreSQL databases with SSL support
|
|
584
|
+
```typescript
|
|
585
|
+
const connector = new PostgresConnector({
|
|
586
|
+
host: 'localhost',
|
|
587
|
+
port: 5432,
|
|
588
|
+
database: 'myapp',
|
|
589
|
+
username: process.env.DB_USER!,
|
|
590
|
+
password: process.env.DB_PASSWORD!,
|
|
591
|
+
ssl: true, // Enable SSL for secure connections
|
|
592
|
+
});
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
**BigQueryConnector** - Google Cloud BigQuery data warehouses
|
|
596
|
+
**SnowflakeConnector** - Snowflake data platform integration
|
|
597
|
+
**DuckDBConnector** - DuckDB for analytics and development
|
|
598
|
+
|
|
599
|
+
### 🔧 Environment Setup
|
|
600
|
+
|
|
601
|
+
Copy `.env.example` to `.env` for secure configuration:
|
|
602
|
+
|
|
603
|
+
```bash
|
|
604
|
+
cp .env.example .env
|
|
605
|
+
# Edit .env with your secure credentials
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
The `.env.example` file includes comprehensive security guidelines and examples for all supported databases.
|
|
609
|
+
|
|
610
|
+
## License
|
|
611
|
+
|
|
612
|
+
MIT - See [LICENSE](./LICENSE)
|
|
613
|
+
|
|
614
|
+
## 📞 Support
|
|
615
|
+
|
|
616
|
+
### 📋 Documentation
|
|
617
|
+
|
|
618
|
+
**🚀 Getting Started**
|
|
619
|
+
- **🔧 [Integration Guide](docs/INTEGRATION_GUIDE.md)** - Complete integration examples for developers
|
|
620
|
+
- **🏠 [Self-Hosting Guide](docs/SELF_HOSTING.md)** - Production deployment with security features
|
|
621
|
+
- **🤝 [Contributing Guide](docs/CONTRIBUTING.md)** - Development setup and guidelines
|
|
622
|
+
|
|
623
|
+
**🔒 Security & Production**
|
|
624
|
+
- **🛡️ [Security Guide](docs/SECURITY_FOR_SELF_HOSTERS.md)**
|
|
625
|
+
|
|
626
|
+
**🏗️ Advanced Topics**
|
|
627
|
+
- **⚙️ Configuration Examples** - Environment-specific setups (dev/staging/prod)
|
|
628
|
+
- **📈 Monitoring & Observability** - Structured logging, metrics, and alerting
|
|
629
|
+
- **🔄 Multi-Database Setup** - PostgreSQL, BigQuery, Snowflake, DuckDB integration
|
|
630
|
+
- **🚨 Circuit Breakers & Resilience** - Automatic failure recovery and protection
|
|
631
|
+
|
|
632
|
+
### 💬 Community
|
|
633
|
+
- **🐛 [Issues](https://github.com/freshguard/freshguard/issues)** - Bug reports and feature requests
|
|
634
|
+
- **💭 [Discussions](https://github.com/freshguard/freshguard/discussions)** - Questions and community support
|
|
635
|
+
|
|
636
|
+
## Need Managed Hosting?
|
|
637
|
+
|
|
638
|
+
Self-hosting requires ops. Want a managed experience?
|
|
639
|
+
|
|
640
|
+
**[Try FreshGuard Cloud (COMING SOON)](https://freshguard.dev)**
|
|
641
|
+
|
|
642
|
+
---
|
|
643
|
+
|
|
644
|
+
Built with ❤️ by the FreshGuard community
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
|