infrawise 0.8.2 → 0.8.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.
@@ -58,7 +58,9 @@ export async function runDoctor(options = {}) {
58
58
  }
59
59
  catch (err) {
60
60
  return {
61
- name: 'Config validation', status: 'fail', message: 'Invalid config',
61
+ name: 'Config validation',
62
+ status: 'fail',
63
+ message: 'Invalid config',
62
64
  detail: err instanceof Error ? err.message : String(err),
63
65
  };
64
66
  }
@@ -75,7 +77,11 @@ export async function runDoctor(options = {}) {
75
77
  detail: hasCreds ? undefined : 'Run: aws configure',
76
78
  };
77
79
  }));
78
- const awsCfg = { region: config?.aws?.region, profile: config?.aws?.profile, endpoint: config?.aws?.endpoint };
80
+ const awsCfg = {
81
+ region: config?.aws?.region,
82
+ profile: config?.aws?.profile,
83
+ endpoint: config?.aws?.endpoint,
84
+ };
79
85
  // DynamoDB
80
86
  results.push(await runCheck('Testing DynamoDB access...', async () => {
81
87
  if (!config)
@@ -84,11 +90,16 @@ export async function runDoctor(options = {}) {
84
90
  return { name: 'DynamoDB', status: 'skip', message: 'Disabled in config' };
85
91
  try {
86
92
  await probeDynamoAccess(config);
87
- return { name: 'DynamoDB', status: 'pass', message: `Connected (profile: ${config.aws?.profile ?? 'default'})` };
93
+ return {
94
+ name: 'DynamoDB',
95
+ status: 'pass',
96
+ message: `Connected (profile: ${config.aws?.profile ?? 'default'})`,
97
+ };
88
98
  }
89
99
  catch (err) {
90
100
  return {
91
- name: 'DynamoDB', status: 'warn',
101
+ name: 'DynamoDB',
102
+ status: 'warn',
92
103
  message: err instanceof Error ? err.message : String(err),
93
104
  detail: 'Check IAM: dynamodb:ListTables, dynamodb:DescribeTable',
94
105
  };
@@ -104,7 +115,8 @@ export async function runDoctor(options = {}) {
104
115
  }
105
116
  catch (err) {
106
117
  return {
107
- name: 'SQS', status: 'warn',
118
+ name: 'SQS',
119
+ status: 'warn',
108
120
  message: err instanceof Error ? err.message : String(err),
109
121
  detail: 'Check IAM: sqs:ListQueues, sqs:GetQueueAttributes',
110
122
  };
@@ -120,7 +132,8 @@ export async function runDoctor(options = {}) {
120
132
  }
121
133
  catch (err) {
122
134
  return {
123
- name: 'SNS', status: 'warn',
135
+ name: 'SNS',
136
+ status: 'warn',
124
137
  message: err instanceof Error ? err.message : String(err),
125
138
  detail: 'Check IAM: sns:ListTopics, sns:GetTopicAttributes, sns:ListSubscriptionsByTopic',
126
139
  };
@@ -136,7 +149,8 @@ export async function runDoctor(options = {}) {
136
149
  }
137
150
  catch (err) {
138
151
  return {
139
- name: 'SSM', status: 'warn',
152
+ name: 'SSM',
153
+ status: 'warn',
140
154
  message: err instanceof Error ? err.message : String(err),
141
155
  detail: 'Check IAM: ssm:DescribeParameters',
142
156
  };
@@ -148,11 +162,16 @@ export async function runDoctor(options = {}) {
148
162
  return { name: 'Secrets Manager', status: 'skip', message: 'Disabled in config' };
149
163
  try {
150
164
  await validateSecretsAccess(awsCfg);
151
- return { name: 'Secrets Manager', status: 'pass', message: 'Connected (names/rotation only)' };
165
+ return {
166
+ name: 'Secrets Manager',
167
+ status: 'pass',
168
+ message: 'Connected (names/rotation only)',
169
+ };
152
170
  }
153
171
  catch (err) {
154
172
  return {
155
- name: 'Secrets Manager', status: 'warn',
173
+ name: 'Secrets Manager',
174
+ status: 'warn',
156
175
  message: err instanceof Error ? err.message : String(err),
157
176
  detail: 'Check IAM: secretsmanager:ListSecrets',
158
177
  };
@@ -168,7 +187,8 @@ export async function runDoctor(options = {}) {
168
187
  }
169
188
  catch (err) {
170
189
  return {
171
- name: 'Lambda', status: 'warn',
190
+ name: 'Lambda',
191
+ status: 'warn',
172
192
  message: err instanceof Error ? err.message : String(err),
173
193
  detail: 'Check IAM: lambda:ListFunctions',
174
194
  };
@@ -184,7 +204,8 @@ export async function runDoctor(options = {}) {
184
204
  }
185
205
  catch (err) {
186
206
  return {
187
- name: 'EventBridge', status: 'warn',
207
+ name: 'EventBridge',
208
+ status: 'warn',
188
209
  message: err instanceof Error ? err.message : String(err),
189
210
  detail: 'Check IAM: events:ListRules, events:ListTargetsByRule',
190
211
  };
@@ -200,7 +221,8 @@ export async function runDoctor(options = {}) {
200
221
  }
201
222
  catch (err) {
202
223
  return {
203
- name: 'S3', status: 'warn',
224
+ name: 'S3',
225
+ status: 'warn',
204
226
  message: err instanceof Error ? err.message : String(err),
205
227
  detail: 'Check IAM: s3:ListBuckets, s3:GetBucketNotificationConfiguration, s3:GetBucketVersioning, s3:GetBucketEncryption, s3:GetPublicAccessBlock',
206
228
  };
@@ -216,7 +238,8 @@ export async function runDoctor(options = {}) {
216
238
  }
217
239
  catch (err) {
218
240
  return {
219
- name: 'CloudWatch Logs', status: 'warn',
241
+ name: 'CloudWatch Logs',
242
+ status: 'warn',
220
243
  message: err instanceof Error ? err.message : String(err),
221
244
  detail: 'Check IAM: logs:DescribeLogGroups, logs:FilterLogEvents',
222
245
  };
@@ -230,13 +253,18 @@ export async function runDoctor(options = {}) {
230
253
  try {
231
254
  const ok = await validatePostgresAccess(config.postgres.connectionString);
232
255
  return {
233
- name: 'PostgreSQL', status: ok ? 'pass' : 'fail',
256
+ name: 'PostgreSQL',
257
+ status: ok ? 'pass' : 'fail',
234
258
  message: ok ? 'Connected' : 'Cannot connect',
235
259
  detail: ok ? undefined : 'Check connection string and security group',
236
260
  };
237
261
  }
238
262
  catch (err) {
239
- return { name: 'PostgreSQL', status: 'fail', message: err instanceof Error ? err.message : String(err) };
263
+ return {
264
+ name: 'PostgreSQL',
265
+ status: 'fail',
266
+ message: err instanceof Error ? err.message : String(err),
267
+ };
240
268
  }
241
269
  }));
242
270
  // MySQL
@@ -247,13 +275,18 @@ export async function runDoctor(options = {}) {
247
275
  try {
248
276
  const ok = await validateMySQLAccess(config.mysql.connectionString);
249
277
  return {
250
- name: 'MySQL', status: ok ? 'pass' : 'fail',
278
+ name: 'MySQL',
279
+ status: ok ? 'pass' : 'fail',
251
280
  message: ok ? 'Connected' : 'Cannot connect',
252
281
  detail: ok ? undefined : 'Check connection string, host, port 3306',
253
282
  };
254
283
  }
255
284
  catch (err) {
256
- return { name: 'MySQL', status: 'fail', message: err instanceof Error ? err.message : String(err) };
285
+ return {
286
+ name: 'MySQL',
287
+ status: 'fail',
288
+ message: err instanceof Error ? err.message : String(err),
289
+ };
257
290
  }
258
291
  }));
259
292
  // MongoDB
@@ -264,13 +297,18 @@ export async function runDoctor(options = {}) {
264
297
  try {
265
298
  const ok = await validateMongoAccess(config.mongodb.connectionString);
266
299
  return {
267
- name: 'MongoDB', status: ok ? 'pass' : 'fail',
300
+ name: 'MongoDB',
301
+ status: ok ? 'pass' : 'fail',
268
302
  message: ok ? 'Connected' : 'Cannot connect',
269
303
  detail: ok ? undefined : 'Check connection string and port 27017',
270
304
  };
271
305
  }
272
306
  catch (err) {
273
- return { name: 'MongoDB', status: 'fail', message: err instanceof Error ? err.message : String(err) };
307
+ return {
308
+ name: 'MongoDB',
309
+ status: 'fail',
310
+ message: err instanceof Error ? err.message : String(err),
311
+ };
274
312
  }
275
313
  }));
276
314
  // Project type
@@ -288,11 +326,13 @@ export async function runDoctor(options = {}) {
288
326
  results.push(await runCheck('Detecting IaC files...', async () => {
289
327
  const cwd = process.cwd();
290
328
  const hasTfFile = (dir) => fs.existsSync(dir) && fs.readdirSync(dir).some((f) => f.endsWith('.tf'));
291
- const hasTF = hasTfFile(cwd) || fs.readdirSync(cwd).some((entry) => {
292
- const full = path.join(cwd, entry);
293
- return fs.statSync(full).isDirectory() && hasTfFile(full);
294
- });
295
- const hasCFN = fs.existsSync(path.join(cwd, 'template.yaml')) || fs.existsSync(path.join(cwd, 'template.json'));
329
+ const hasTF = hasTfFile(cwd) ||
330
+ fs.readdirSync(cwd).some((entry) => {
331
+ const full = path.join(cwd, entry);
332
+ return fs.statSync(full).isDirectory() && hasTfFile(full);
333
+ });
334
+ const hasCFN = fs.existsSync(path.join(cwd, 'template.yaml')) ||
335
+ fs.existsSync(path.join(cwd, 'template.json'));
296
336
  const hasCDK = fs.existsSync(path.join(cwd, 'cdk.json'));
297
337
  const hasCDKOut = fs.existsSync(path.join(cwd, 'cdk.out'));
298
338
  const found = [];
@@ -184,24 +184,42 @@ export async function runInit(options = {}) {
184
184
  ]);
185
185
  // ── Build config ───────────────────────────────────────────────────────────
186
186
  const includeTables = services.dynamoTables
187
- ? services.dynamoTables.split(',').map((t) => t.trim()).filter(Boolean)
187
+ ? services.dynamoTables
188
+ .split(',')
189
+ .map((t) => t.trim())
190
+ .filter(Boolean)
188
191
  : [];
189
192
  const ssmPaths = services.ssmPaths
190
- ? services.ssmPaths.split(',').map((p) => p.trim()).filter(Boolean)
193
+ ? services.ssmPaths
194
+ .split(',')
195
+ .map((p) => p.trim())
196
+ .filter(Boolean)
191
197
  : [];
192
198
  const logGroupPrefixes = services.logGroupPrefixes
193
- ? services.logGroupPrefixes.split(',').map((p) => p.trim()).filter(Boolean)
199
+ ? services.logGroupPrefixes
200
+ .split(',')
201
+ .map((p) => p.trim())
202
+ .filter(Boolean)
194
203
  : [];
195
204
  const isLocalStack = core.awsProfile === '__localstack__';
196
205
  const isEnvVars = core.awsProfile === '__env__';
197
206
  const resolvedProfile = isLocalStack || isEnvVars ? '' : core.awsProfile;
198
- const resolvedEndpoint = isLocalStack ? (core.endpoint || 'http://localhost:4566') : undefined;
207
+ const resolvedEndpoint = isLocalStack ? core.endpoint || 'http://localhost:4566' : undefined;
199
208
  const configContent = generateDefaultConfig(core.project, {
200
209
  aws: { profile: resolvedProfile, region: core.region, endpoint: resolvedEndpoint },
201
210
  dynamodb: { enabled: services.dynamoEnabled, includeTables },
202
- postgres: { enabled: databases.pgEnabled, connectionString: databases.pgConnectionString ?? '' },
203
- mysql: { enabled: databases.mysqlEnabled, connectionString: databases.mysqlConnectionString ?? '' },
204
- mongodb: { enabled: databases.mongoEnabled, connectionString: databases.mongoConnectionString ?? '' },
211
+ postgres: {
212
+ enabled: databases.pgEnabled,
213
+ connectionString: databases.pgConnectionString ?? '',
214
+ },
215
+ mysql: {
216
+ enabled: databases.mysqlEnabled,
217
+ connectionString: databases.mysqlConnectionString ?? '',
218
+ },
219
+ mongodb: {
220
+ enabled: databases.mongoEnabled,
221
+ connectionString: databases.mongoConnectionString ?? '',
222
+ },
205
223
  sqs: { enabled: services.sqsEnabled },
206
224
  sns: { enabled: services.snsEnabled },
207
225
  ssm: { enabled: services.ssmEnabled, paths: ssmPaths },
package/dist/cli/utils.js CHANGED
@@ -90,10 +90,14 @@ export const log = {
90
90
  // ─── Findings ────────────────────────────────────────────────────────────────
91
91
  function severityBadge(severity) {
92
92
  switch (severity) {
93
- case 'high': return chalk.bgRed.white.bold(` HIGH `);
94
- case 'medium': return chalk.bgYellow.black.bold(` MED `);
95
- case 'low': return chalk.bgCyan.black.bold(` LOW `);
96
- case 'verify': return chalk.bgBlue.white.bold(` VER? `);
93
+ case 'high':
94
+ return chalk.bgRed.white.bold(` HIGH `);
95
+ case 'medium':
96
+ return chalk.bgYellow.black.bold(` MED `);
97
+ case 'low':
98
+ return chalk.bgCyan.black.bold(` LOW `);
99
+ case 'verify':
100
+ return chalk.bgBlue.white.bold(` VER? `);
97
101
  }
98
102
  }
99
103
  export function printFinding(finding, index) {
@@ -112,11 +116,21 @@ export function printSummaryBox(findings) {
112
116
  console.log(chalk.dim(' ┌─────────────────────────────┐'));
113
117
  console.log(chalk.dim(' │') + chalk.bold(' Analysis Summary ') + chalk.dim('│'));
114
118
  console.log(chalk.dim(' ├─────────────────────────────┤'));
115
- console.log(chalk.dim(' │') + ` ${chalk.red('●')} High ${chalk.red.bold(String(high).padStart(3))} ` + chalk.dim('│'));
116
- console.log(chalk.dim(' │') + ` ${chalk.yellow('●')} Medium ${chalk.yellow.bold(String(medium).padStart(3))} ` + chalk.dim('│'));
117
- console.log(chalk.dim(' │') + ` ${chalk.cyan('●')} Low ${chalk.cyan.bold(String(low).padStart(3))} ` + chalk.dim('│'));
118
- console.log(chalk.dim(' │') + ` ${chalk.blue('●')} Verify ${chalk.blue.bold(String(verify).padStart(3))} ` + chalk.dim('│'));
119
+ console.log(chalk.dim(' │') +
120
+ ` ${chalk.red('●')} High ${chalk.red.bold(String(high).padStart(3))} ` +
121
+ chalk.dim('│'));
122
+ console.log(chalk.dim(' │') +
123
+ ` ${chalk.yellow('●')} Medium ${chalk.yellow.bold(String(medium).padStart(3))} ` +
124
+ chalk.dim('│'));
125
+ console.log(chalk.dim(' │') +
126
+ ` ${chalk.cyan('●')} Low ${chalk.cyan.bold(String(low).padStart(3))} ` +
127
+ chalk.dim('│'));
128
+ console.log(chalk.dim(' │') +
129
+ ` ${chalk.blue('●')} Verify ${chalk.blue.bold(String(verify).padStart(3))} ` +
130
+ chalk.dim('│'));
119
131
  console.log(chalk.dim(' ├─────────────────────────────┤'));
120
- console.log(chalk.dim(' │') + ` Total ${chalk.bold(String(findings.length).padStart(3))} ` + chalk.dim('│'));
132
+ console.log(chalk.dim(' │') +
133
+ ` Total ${chalk.bold(String(findings.length).padStart(3))} ` +
134
+ chalk.dim('│'));
121
135
  console.log(chalk.dim(' └─────────────────────────────┘'));
122
136
  }
@@ -23,7 +23,16 @@ const DYNAMO_OPERATIONS = new Set([
23
23
  ]);
24
24
  const DYNAMO_CLIENT_PATTERNS = ['DynamoDBClient', 'DynamoDB', 'dynamoDB', 'dynamo', 'ddb'];
25
25
  const POSTGRES_QUERY_METHODS = new Set(['query', 'execute', 'exec']);
26
- const KNEX_METHODS = new Set(['select', 'where', 'join', 'from', 'insert', 'update', 'delete', 'del']);
26
+ const KNEX_METHODS = new Set([
27
+ 'select',
28
+ 'where',
29
+ 'join',
30
+ 'from',
31
+ 'insert',
32
+ 'update',
33
+ 'delete',
34
+ 'del',
35
+ ]);
27
36
  // MySQL-specific patterns
28
37
  const MYSQL_QUERY_METHODS = new Set(['query', 'execute', 'exec']);
29
38
  const MYSQL_CLIENT_PATTERNS = ['mysql', 'mysql2', 'connection', 'pool', 'conn'];
@@ -44,14 +53,29 @@ const MONGO_READ_METHODS = new Set([
44
53
  ]);
45
54
  const MONGO_COLLECTION_METHODS = new Set(['collection']);
46
55
  // ── AWS service patterns ──────────────────────────────────────────────────────
47
- const SQS_COMMANDS = new Set(['SendMessageCommand', 'SendMessageBatchCommand', 'ReceiveMessageCommand', 'DeleteMessageCommand', 'sendMessage', 'sendMessageBatch', 'receiveMessage']);
56
+ const SQS_COMMANDS = new Set([
57
+ 'SendMessageCommand',
58
+ 'SendMessageBatchCommand',
59
+ 'ReceiveMessageCommand',
60
+ 'DeleteMessageCommand',
61
+ 'sendMessage',
62
+ 'sendMessageBatch',
63
+ 'receiveMessage',
64
+ ]);
48
65
  const SNS_COMMANDS = new Set(['PublishCommand', 'PublishBatchCommand', 'publish', 'publishBatch']);
49
66
  // kafkajs patterns — detection relies on variable naming (producer/consumer/kafka)
50
67
  const KAFKA_PRODUCER_METHODS = new Set(['send', 'sendBatch']);
51
68
  const KAFKA_CONSUMER_METHODS = new Set(['subscribe']);
52
69
  const KAFKA_CLIENT_PATTERNS = ['kafka', 'producer', 'consumer'];
53
70
  const KAFKA_TOPIC_KEYS = ['topic'];
54
- const SSM_COMMANDS = new Set(['GetParameterCommand', 'GetParametersCommand', 'GetParametersByPathCommand', 'getParameter', 'getParameters', 'getParametersByPath']);
71
+ const SSM_COMMANDS = new Set([
72
+ 'GetParameterCommand',
73
+ 'GetParametersCommand',
74
+ 'GetParametersByPathCommand',
75
+ 'getParameter',
76
+ 'getParameters',
77
+ 'getParametersByPath',
78
+ ]);
55
79
  const SECRETS_COMMANDS = new Set(['GetSecretValueCommand', 'getSecretValue']);
56
80
  const LAMBDA_COMMANDS = new Set(['InvokeCommand', 'InvokeAsyncCommand', 'invoke', 'invokeAsync']);
57
81
  const SQS_ARG_KEYS = ['QueueUrl', 'QueueName'];
@@ -247,9 +271,7 @@ function detectPostgresOperations(callExpr, filePath) {
247
271
  if (KNEX_METHODS.has(methodName)) {
248
272
  const calleeText = objExpr.getText();
249
273
  // Check if it's a chained knex call
250
- if (calleeText.includes('knex') ||
251
- calleeText.includes('db(') ||
252
- calleeText.includes('trx(')) {
274
+ if (calleeText.includes('knex') || calleeText.includes('db(') || calleeText.includes('trx(')) {
253
275
  return {
254
276
  functionName: getEnclosingFunctionName(callExpr),
255
277
  operationType: methodName,
@@ -261,7 +283,10 @@ function detectPostgresOperations(callExpr, filePath) {
261
283
  // Knex call expression style: knex('users').select(...)
262
284
  if (Node.isCallExpression(objExpr)) {
263
285
  const innerExpr = objExpr.getExpression();
264
- if (innerExpr.getText().toLowerCase().match(/knex|db|trx/)) {
286
+ if (innerExpr
287
+ .getText()
288
+ .toLowerCase()
289
+ .match(/knex|db|trx/)) {
265
290
  const innerArgs = objExpr.getArguments();
266
291
  const tableName = innerArgs.length > 0 && Node.isStringLiteral(innerArgs[0])
267
292
  ? innerArgs[0].getLiteralValue()
@@ -513,7 +538,8 @@ function detectAWSServiceOperations(callExpr, filePath) {
513
538
  filePath,
514
539
  };
515
540
  }
516
- if (SSM_COMMANDS.has(methodName) && (objText.includes('ssm') || objText.includes('parameter'))) {
541
+ if (SSM_COMMANDS.has(methodName) &&
542
+ (objText.includes('ssm') || objText.includes('parameter'))) {
517
543
  return {
518
544
  functionName: getEnclosingFunctionName(callExpr),
519
545
  operationType: methodName,
@@ -522,7 +548,8 @@ function detectAWSServiceOperations(callExpr, filePath) {
522
548
  filePath,
523
549
  };
524
550
  }
525
- if (SECRETS_COMMANDS.has(methodName) && (objText.includes('secret') || objText.includes('secrets'))) {
551
+ if (SECRETS_COMMANDS.has(methodName) &&
552
+ (objText.includes('secret') || objText.includes('secrets'))) {
526
553
  return {
527
554
  functionName: getEnclosingFunctionName(callExpr),
528
555
  operationType: methodName,
@@ -1,10 +1,13 @@
1
1
  import * as fs from 'fs';
2
2
  import * as path from 'path';
3
3
  const CACHE_VERSION = '1.0.0';
4
- const CACHE_DIR = path.join(process.cwd(), '.infrawise', 'cache');
4
+ let cacheDir = path.join(process.cwd(), '.infrawise', 'cache');
5
+ export function setCacheDir(dir) {
6
+ cacheDir = path.join(dir, '.infrawise', 'cache');
7
+ }
5
8
  function ensureCacheDir() {
6
- if (!fs.existsSync(CACHE_DIR)) {
7
- fs.mkdirSync(CACHE_DIR, { recursive: true });
9
+ if (!fs.existsSync(cacheDir)) {
10
+ fs.mkdirSync(cacheDir, { recursive: true });
8
11
  }
9
12
  }
10
13
  export function writeCache(key, data) {
@@ -14,11 +17,11 @@ export function writeCache(key, data) {
14
17
  data,
15
18
  version: CACHE_VERSION,
16
19
  };
17
- const filePath = path.join(CACHE_DIR, `${key}.json`);
20
+ const filePath = path.join(cacheDir, `${key}.json`);
18
21
  fs.writeFileSync(filePath, JSON.stringify(entry, null, 2), 'utf-8');
19
22
  }
20
23
  export function readCache(key, maxAgeMs = 3600000) {
21
- const filePath = path.join(CACHE_DIR, `${key}.json`);
24
+ const filePath = path.join(cacheDir, `${key}.json`);
22
25
  if (!fs.existsSync(filePath))
23
26
  return null;
24
27
  try {
@@ -36,15 +39,15 @@ export function readCache(key, maxAgeMs = 3600000) {
36
39
  }
37
40
  export function clearCache(key) {
38
41
  if (key) {
39
- const filePath = path.join(CACHE_DIR, `${key}.json`);
42
+ const filePath = path.join(cacheDir, `${key}.json`);
40
43
  if (fs.existsSync(filePath))
41
44
  fs.unlinkSync(filePath);
42
45
  }
43
46
  else {
44
- if (fs.existsSync(CACHE_DIR)) {
45
- const files = fs.readdirSync(CACHE_DIR);
47
+ if (fs.existsSync(cacheDir)) {
48
+ const files = fs.readdirSync(cacheDir);
46
49
  for (const file of files) {
47
- fs.unlinkSync(path.join(CACHE_DIR, file));
50
+ fs.unlinkSync(path.join(cacheDir, file));
48
51
  }
49
52
  }
50
53
  }
@@ -12,44 +12,63 @@ export const InfrawiseConfigSchema = z.object({
12
12
  })
13
13
  .optional()
14
14
  .default({ profile: 'default', region: 'us-east-1' }),
15
- dynamodb: z.object({ enabled: z.boolean().optional().default(true), includeTables: z.array(z.string()).optional() }).optional(),
16
- postgres: z.object({
15
+ dynamodb: z
16
+ .object({
17
+ enabled: z.boolean().optional().default(true),
18
+ includeTables: z.array(z.string()).optional(),
19
+ })
20
+ .optional(),
21
+ postgres: z
22
+ .object({
17
23
  enabled: z.boolean().optional().default(false),
18
24
  connectionString: z.string().optional(),
19
- }).optional(),
20
- mysql: z.object({
25
+ })
26
+ .optional(),
27
+ mysql: z
28
+ .object({
21
29
  enabled: z.boolean().optional().default(false),
22
30
  connectionString: z.string().optional(),
23
- }).optional(),
24
- mongodb: z.object({
31
+ })
32
+ .optional(),
33
+ mongodb: z
34
+ .object({
25
35
  enabled: z.boolean().optional().default(false),
26
36
  connectionString: z.string().optional(),
27
37
  databases: z.array(z.string()).optional(),
28
- }).optional(),
38
+ })
39
+ .optional(),
29
40
  terraform: z.object({ enabled: z.boolean().optional().default(true) }).optional(),
30
41
  sqs: z.object({ enabled: z.boolean().optional().default(true) }).optional(),
31
42
  sns: z.object({ enabled: z.boolean().optional().default(true) }).optional(),
32
- ssm: z.object({
43
+ ssm: z
44
+ .object({
33
45
  enabled: z.boolean().optional().default(true),
34
46
  paths: z.array(z.string()).optional(),
35
- }).optional(),
47
+ })
48
+ .optional(),
36
49
  secretsManager: z.object({ enabled: z.boolean().optional().default(true) }).optional(),
37
- lambda: z.object({
50
+ lambda: z
51
+ .object({
38
52
  enabled: z.boolean().optional().default(true),
39
53
  includeFunctions: z.array(z.string()).optional(),
40
- }).optional(),
54
+ })
55
+ .optional(),
41
56
  eventbridge: z.object({ enabled: z.boolean().optional().default(true) }).optional(),
42
57
  rds: z.object({ enabled: z.boolean().optional().default(false) }).optional(),
43
58
  s3: z.object({ enabled: z.boolean().optional().default(false) }).optional(),
44
59
  kafka: z.object({ enabled: z.boolean().optional().default(false) }).optional(),
45
- cloudwatchLogs: z.object({
60
+ cloudwatchLogs: z
61
+ .object({
46
62
  enabled: z.boolean().optional().default(false),
47
63
  logGroupPrefixes: z.array(z.string()).optional(),
48
64
  windowHours: z.number().int().positive().optional().default(24),
49
- }).optional(),
50
- analysis: z.object({
65
+ })
66
+ .optional(),
67
+ analysis: z
68
+ .object({
51
69
  sampleSize: z.number().int().positive().optional().default(100),
52
- }).optional(),
70
+ })
71
+ .optional(),
53
72
  });
54
73
  export class ConfigError extends Error {
55
74
  details;
@@ -103,7 +122,10 @@ export function generateDefaultConfig(projectName, options) {
103
122
  region: options?.aws?.region ?? 'us-east-1',
104
123
  ...(options?.aws?.endpoint ? { endpoint: options.aws.endpoint } : {}),
105
124
  },
106
- dynamodb: { enabled: options?.dynamodb?.enabled ?? true, includeTables: options?.dynamodb?.includeTables ?? [] },
125
+ dynamodb: {
126
+ enabled: options?.dynamodb?.enabled ?? true,
127
+ includeTables: options?.dynamodb?.includeTables ?? [],
128
+ },
107
129
  postgres: {
108
130
  enabled: options?.postgres?.enabled ?? false,
109
131
  connectionString: options?.postgres?.connectionString ?? '',
@@ -1,4 +1,4 @@
1
- export { loadConfig, generateDefaultConfig, InfrawiseConfigSchema, ConfigError as ConfigValidationError } from './config.js';
1
+ export { loadConfig, generateDefaultConfig, InfrawiseConfigSchema, ConfigError as ConfigValidationError, } from './config.js';
2
2
  export { logger } from './logger.js';
3
3
  export { InfrawiseError, AWSConnectionError, DynamoDBError, PostgresConnectionError, RepositoryScanError, ConfigError, formatError, } from './errors.js';
4
- export { writeCache, readCache, clearCache } from './cache.js';
4
+ export { writeCache, readCache, clearCache, setCacheDir } from './cache.js';