@varveai/adit-core 0.2.1
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/dist/config/index.d.ts +29 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +107 -0
- package/dist/config/index.js.map +1 -0
- package/dist/db/connection.d.ts +9 -0
- package/dist/db/connection.d.ts.map +1 -0
- package/dist/db/connection.js +48 -0
- package/dist/db/connection.js.map +1 -0
- package/dist/db/diffs.d.ts +22 -0
- package/dist/db/diffs.d.ts.map +1 -0
- package/dist/db/diffs.js +37 -0
- package/dist/db/diffs.js.map +1 -0
- package/dist/db/env-snapshots.d.ts +29 -0
- package/dist/db/env-snapshots.d.ts.map +1 -0
- package/dist/db/env-snapshots.js +57 -0
- package/dist/db/env-snapshots.js.map +1 -0
- package/dist/db/events.d.ts +91 -0
- package/dist/db/events.d.ts.map +1 -0
- package/dist/db/events.js +260 -0
- package/dist/db/events.js.map +1 -0
- package/dist/db/index.d.ts +10 -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/migrations.d.ts +13 -0
- package/dist/db/migrations.d.ts.map +1 -0
- package/dist/db/migrations.js +237 -0
- package/dist/db/migrations.js.map +1 -0
- package/dist/db/plans.d.ts +21 -0
- package/dist/db/plans.d.ts.map +1 -0
- package/dist/db/plans.js +52 -0
- package/dist/db/plans.js.map +1 -0
- package/dist/db/sessions.d.ts +23 -0
- package/dist/db/sessions.d.ts.map +1 -0
- package/dist/db/sessions.js +57 -0
- package/dist/db/sessions.js.map +1 -0
- package/dist/db/sync-state.d.ts +21 -0
- package/dist/db/sync-state.d.ts.map +1 -0
- package/dist/db/sync-state.js +36 -0
- package/dist/db/sync-state.js.map +1 -0
- package/dist/db/transcript-uploads.d.ts +57 -0
- package/dist/db/transcript-uploads.d.ts.map +1 -0
- package/dist/db/transcript-uploads.js +132 -0
- package/dist/db/transcript-uploads.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/perf/perf-log.d.ts +105 -0
- package/dist/perf/perf-log.d.ts.map +1 -0
- package/dist/perf/perf-log.js +280 -0
- package/dist/perf/perf-log.js.map +1 -0
- package/dist/security/content-redaction.d.ts +105 -0
- package/dist/security/content-redaction.d.ts.map +1 -0
- package/dist/security/content-redaction.js +365 -0
- package/dist/security/content-redaction.js.map +1 -0
- package/dist/sync/index.d.ts +3 -0
- package/dist/sync/index.d.ts.map +1 -0
- package/dist/sync/index.js +3 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/sync/ulid.d.ts +15 -0
- package/dist/sync/ulid.d.ts.map +1 -0
- package/dist/sync/ulid.js +34 -0
- package/dist/sync/ulid.js.map +1 -0
- package/dist/sync/vclock.d.ts +33 -0
- package/dist/sync/vclock.d.ts.map +1 -0
- package/dist/sync/vclock.js +69 -0
- package/dist/sync/vclock.js.map +1 -0
- package/dist/types/environment.d.ts +53 -0
- package/dist/types/environment.d.ts.map +1 -0
- package/dist/types/environment.js +8 -0
- package/dist/types/environment.js.map +1 -0
- package/dist/types/events.d.ts +88 -0
- package/dist/types/events.d.ts.map +1 -0
- package/dist/types/events.js +40 -0
- package/dist/types/events.js.map +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/plan.d.ts +30 -0
- package/dist/types/plan.d.ts.map +1 -0
- package/dist/types/plan.js +8 -0
- package/dist/types/plan.js.map +1 -0
- package/dist/types/session.d.ts +44 -0
- package/dist/types/session.d.ts.map +1 -0
- package/dist/types/session.js +8 -0
- package/dist/types/session.js.map +1 -0
- package/package.json +29 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Performance logging for time-sensitive operations.
|
|
3
|
+
*
|
|
4
|
+
* Records call timing for hook handlers, git operations, network calls,
|
|
5
|
+
* and other time-sensitive operations. Logs are stored as daily JSONL files
|
|
6
|
+
* in .adit/perf-logs/ and auto-pruned after 7 days.
|
|
7
|
+
*/
|
|
8
|
+
import { mkdirSync, appendFileSync, readdirSync, readFileSync, unlinkSync, existsSync, } from "node:fs";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
import { performance } from "node:perf_hooks";
|
|
11
|
+
const RETENTION_DAYS = 7;
|
|
12
|
+
const PERF_LOG_DIR = "perf-logs";
|
|
13
|
+
/** Get the perf log directory path */
|
|
14
|
+
function getPerfLogDir(dataDir) {
|
|
15
|
+
return join(dataDir, PERF_LOG_DIR);
|
|
16
|
+
}
|
|
17
|
+
/** Get today's date string (YYYY-MM-DD) */
|
|
18
|
+
function todayDateStr() {
|
|
19
|
+
return new Date().toISOString().slice(0, 10);
|
|
20
|
+
}
|
|
21
|
+
/** Get the log file path for a given date */
|
|
22
|
+
function logFilePath(dataDir, dateStr) {
|
|
23
|
+
return join(getPerfLogDir(dataDir), `${dateStr}.jsonl`);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Prune log files older than the retention period.
|
|
27
|
+
* Called on each write to keep the directory clean.
|
|
28
|
+
*/
|
|
29
|
+
export function pruneOldLogs(dataDir) {
|
|
30
|
+
const dir = getPerfLogDir(dataDir);
|
|
31
|
+
if (!existsSync(dir))
|
|
32
|
+
return;
|
|
33
|
+
const cutoff = new Date();
|
|
34
|
+
cutoff.setDate(cutoff.getDate() - RETENTION_DAYS);
|
|
35
|
+
const cutoffStr = cutoff.toISOString().slice(0, 10);
|
|
36
|
+
try {
|
|
37
|
+
const files = readdirSync(dir);
|
|
38
|
+
for (const file of files) {
|
|
39
|
+
if (!file.endsWith(".jsonl"))
|
|
40
|
+
continue;
|
|
41
|
+
const dateStr = file.replace(".jsonl", "");
|
|
42
|
+
if (dateStr < cutoffStr) {
|
|
43
|
+
try {
|
|
44
|
+
unlinkSync(join(dir, file));
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Best effort
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// Best effort
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Record a performance log entry.
|
|
58
|
+
*
|
|
59
|
+
* @param dataDir - The ADIT data directory (.adit/)
|
|
60
|
+
* @param entry - The performance entry to record
|
|
61
|
+
*/
|
|
62
|
+
export function recordPerf(dataDir, entry) {
|
|
63
|
+
try {
|
|
64
|
+
const dir = getPerfLogDir(dataDir);
|
|
65
|
+
mkdirSync(dir, { recursive: true });
|
|
66
|
+
const filePath = logFilePath(dataDir, todayDateStr());
|
|
67
|
+
const line = JSON.stringify(entry) + "\n";
|
|
68
|
+
appendFileSync(filePath, line, "utf-8");
|
|
69
|
+
// Prune old logs (best effort, non-blocking)
|
|
70
|
+
pruneOldLogs(dataDir);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// Fail-open: never let perf logging break the application
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Wrap an async function with performance logging.
|
|
78
|
+
*
|
|
79
|
+
* @param dataDir - The ADIT data directory (.adit/)
|
|
80
|
+
* @param category - Category of the operation
|
|
81
|
+
* @param operation - Name of the operation
|
|
82
|
+
* @param fn - The async function to measure
|
|
83
|
+
* @returns The result of the function
|
|
84
|
+
*/
|
|
85
|
+
export async function withPerf(dataDir, category, operation, fn) {
|
|
86
|
+
const start = performance.now();
|
|
87
|
+
const timestamp = new Date().toISOString();
|
|
88
|
+
try {
|
|
89
|
+
const result = await fn();
|
|
90
|
+
recordPerf(dataDir, {
|
|
91
|
+
timestamp,
|
|
92
|
+
category,
|
|
93
|
+
operation,
|
|
94
|
+
durationMs: Math.round((performance.now() - start) * 100) / 100,
|
|
95
|
+
success: true,
|
|
96
|
+
});
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
recordPerf(dataDir, {
|
|
101
|
+
timestamp,
|
|
102
|
+
category,
|
|
103
|
+
operation,
|
|
104
|
+
durationMs: Math.round((performance.now() - start) * 100) / 100,
|
|
105
|
+
success: false,
|
|
106
|
+
error: err instanceof Error ? err.message : String(err),
|
|
107
|
+
});
|
|
108
|
+
throw err;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Wrap a sync function with performance logging.
|
|
113
|
+
*/
|
|
114
|
+
export function withPerfSync(dataDir, category, operation, fn) {
|
|
115
|
+
const start = performance.now();
|
|
116
|
+
const timestamp = new Date().toISOString();
|
|
117
|
+
try {
|
|
118
|
+
const result = fn();
|
|
119
|
+
recordPerf(dataDir, {
|
|
120
|
+
timestamp,
|
|
121
|
+
category,
|
|
122
|
+
operation,
|
|
123
|
+
durationMs: Math.round((performance.now() - start) * 100) / 100,
|
|
124
|
+
success: true,
|
|
125
|
+
});
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
recordPerf(dataDir, {
|
|
130
|
+
timestamp,
|
|
131
|
+
category,
|
|
132
|
+
operation,
|
|
133
|
+
durationMs: Math.round((performance.now() - start) * 100) / 100,
|
|
134
|
+
success: false,
|
|
135
|
+
error: err instanceof Error ? err.message : String(err),
|
|
136
|
+
});
|
|
137
|
+
throw err;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Read all perf log entries within the retention window.
|
|
142
|
+
*
|
|
143
|
+
* @param dataDir - The ADIT data directory (.adit/)
|
|
144
|
+
* @param fromDate - Optional start date (YYYY-MM-DD). Defaults to 7 days ago.
|
|
145
|
+
* @param toDate - Optional end date (YYYY-MM-DD). Defaults to today.
|
|
146
|
+
* @returns Array of perf entries
|
|
147
|
+
*/
|
|
148
|
+
export function readPerfLogs(dataDir, fromDate, toDate) {
|
|
149
|
+
const dir = getPerfLogDir(dataDir);
|
|
150
|
+
if (!existsSync(dir))
|
|
151
|
+
return [];
|
|
152
|
+
const today = todayDateStr();
|
|
153
|
+
const defaultFrom = new Date();
|
|
154
|
+
defaultFrom.setDate(defaultFrom.getDate() - RETENTION_DAYS);
|
|
155
|
+
const from = fromDate ?? defaultFrom.toISOString().slice(0, 10);
|
|
156
|
+
const to = toDate ?? today;
|
|
157
|
+
const entries = [];
|
|
158
|
+
try {
|
|
159
|
+
const files = readdirSync(dir).filter((f) => f.endsWith(".jsonl")).sort();
|
|
160
|
+
for (const file of files) {
|
|
161
|
+
const dateStr = file.replace(".jsonl", "");
|
|
162
|
+
if (dateStr < from || dateStr > to)
|
|
163
|
+
continue;
|
|
164
|
+
const content = readFileSync(join(dir, file), "utf-8");
|
|
165
|
+
for (const line of content.split("\n")) {
|
|
166
|
+
if (!line.trim())
|
|
167
|
+
continue;
|
|
168
|
+
try {
|
|
169
|
+
entries.push(JSON.parse(line));
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
// Skip malformed lines
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
// Return whatever we collected
|
|
179
|
+
}
|
|
180
|
+
return entries;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Generate a stats report from perf log entries.
|
|
184
|
+
*
|
|
185
|
+
* @param entries - Array of perf entries to analyze
|
|
186
|
+
* @returns Stats report with per-operation aggregations
|
|
187
|
+
*/
|
|
188
|
+
export function generatePerfStats(entries) {
|
|
189
|
+
const now = new Date().toISOString();
|
|
190
|
+
if (entries.length === 0) {
|
|
191
|
+
return {
|
|
192
|
+
generatedAt: now,
|
|
193
|
+
fromDate: "",
|
|
194
|
+
toDate: "",
|
|
195
|
+
totalEntries: 0,
|
|
196
|
+
operations: [],
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
// Find date range
|
|
200
|
+
const timestamps = entries.map((e) => e.timestamp).sort();
|
|
201
|
+
const fromDate = timestamps[0].slice(0, 10);
|
|
202
|
+
const toDate = timestamps[timestamps.length - 1].slice(0, 10);
|
|
203
|
+
// Group by category:operation
|
|
204
|
+
const groups = new Map();
|
|
205
|
+
for (const entry of entries) {
|
|
206
|
+
const key = `${entry.category}:${entry.operation}`;
|
|
207
|
+
const group = groups.get(key);
|
|
208
|
+
if (group) {
|
|
209
|
+
group.push(entry);
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
groups.set(key, [entry]);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
// Compute per-operation stats
|
|
216
|
+
const operations = [];
|
|
217
|
+
for (const [, group] of groups) {
|
|
218
|
+
const durations = group.map((e) => e.durationMs).sort((a, b) => a - b);
|
|
219
|
+
const totalMs = durations.reduce((sum, d) => sum + d, 0);
|
|
220
|
+
const avgMs = totalMs / group.length;
|
|
221
|
+
const p95Index = Math.min(Math.ceil(durations.length * 0.95) - 1, durations.length - 1);
|
|
222
|
+
// Standard deviation
|
|
223
|
+
const variance = group.length > 1
|
|
224
|
+
? durations.reduce((sum, d) => sum + (d - avgMs) ** 2, 0) /
|
|
225
|
+
(group.length - 1)
|
|
226
|
+
: 0;
|
|
227
|
+
const stddevMs = Math.round(Math.sqrt(variance) * 100) / 100;
|
|
228
|
+
operations.push({
|
|
229
|
+
category: group[0].category,
|
|
230
|
+
operation: group[0].operation,
|
|
231
|
+
count: group.length,
|
|
232
|
+
avgMs: Math.round(avgMs * 100) / 100,
|
|
233
|
+
minMs: durations[0],
|
|
234
|
+
maxMs: durations[durations.length - 1],
|
|
235
|
+
p95Ms: durations[p95Index],
|
|
236
|
+
stddevMs,
|
|
237
|
+
failures: group.filter((e) => !e.success).length,
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
// Sort by call count descending
|
|
241
|
+
operations.sort((a, b) => b.count - a.count);
|
|
242
|
+
return {
|
|
243
|
+
generatedAt: now,
|
|
244
|
+
fromDate,
|
|
245
|
+
toDate,
|
|
246
|
+
totalEntries: entries.length,
|
|
247
|
+
operations,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Clear all performance logs.
|
|
252
|
+
*
|
|
253
|
+
* @param dataDir - The ADIT data directory (.adit/)
|
|
254
|
+
* @returns Number of files deleted
|
|
255
|
+
*/
|
|
256
|
+
export function clearPerfLogs(dataDir) {
|
|
257
|
+
const dir = getPerfLogDir(dataDir);
|
|
258
|
+
if (!existsSync(dir))
|
|
259
|
+
return 0;
|
|
260
|
+
let count = 0;
|
|
261
|
+
try {
|
|
262
|
+
const files = readdirSync(dir);
|
|
263
|
+
for (const file of files) {
|
|
264
|
+
if (!file.endsWith(".jsonl"))
|
|
265
|
+
continue;
|
|
266
|
+
try {
|
|
267
|
+
unlinkSync(join(dir, file));
|
|
268
|
+
count++;
|
|
269
|
+
}
|
|
270
|
+
catch {
|
|
271
|
+
// Best effort
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
catch {
|
|
276
|
+
// Best effort
|
|
277
|
+
}
|
|
278
|
+
return count;
|
|
279
|
+
}
|
|
280
|
+
//# sourceMappingURL=perf-log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"perf-log.js","sourceRoot":"","sources":["../../src/perf/perf-log.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content-aware secret redaction.
|
|
3
|
+
*
|
|
4
|
+
* Scans text content for secrets using two complementary techniques:
|
|
5
|
+
* 1. Shannon entropy scoring — flags high-entropy strings that look like
|
|
6
|
+
* randomly generated secrets (API keys, tokens, passwords).
|
|
7
|
+
* 2. Pattern matching — regex-based detection of known secret formats
|
|
8
|
+
* (AWS keys, GitHub tokens, JWTs, private keys, etc.).
|
|
9
|
+
*
|
|
10
|
+
* Inspired by gitleaks/trufflehog approaches. Designed to run on transcript
|
|
11
|
+
* data (prompts, responses, tool I/O) before writing to the database.
|
|
12
|
+
*/
|
|
13
|
+
/** Result of scanning a single string for secrets */
|
|
14
|
+
export interface RedactionResult {
|
|
15
|
+
/** The redacted text with secrets replaced */
|
|
16
|
+
redacted: string;
|
|
17
|
+
/** Number of secrets found and replaced */
|
|
18
|
+
secretsFound: number;
|
|
19
|
+
/** Details of each detection for logging/debugging */
|
|
20
|
+
detections: SecretDetection[];
|
|
21
|
+
}
|
|
22
|
+
export interface SecretDetection {
|
|
23
|
+
/** What triggered the detection */
|
|
24
|
+
method: "entropy" | "pattern";
|
|
25
|
+
/** Name of the matched pattern (if pattern-based) */
|
|
26
|
+
patternName?: string;
|
|
27
|
+
/** Character offset in the original string */
|
|
28
|
+
offset: number;
|
|
29
|
+
/** Length of the matched secret */
|
|
30
|
+
length: number;
|
|
31
|
+
}
|
|
32
|
+
/** Configuration for the content redaction pipeline */
|
|
33
|
+
export interface RedactionConfig {
|
|
34
|
+
/** Shannon entropy threshold (default: 4.5) */
|
|
35
|
+
entropyThreshold?: number;
|
|
36
|
+
/** Minimum token length to check for entropy (default: 8) */
|
|
37
|
+
minTokenLength?: number;
|
|
38
|
+
/** Maximum token length to check for entropy (default: 256) */
|
|
39
|
+
maxTokenLength?: number;
|
|
40
|
+
/** Replacement string for detected secrets (default: "[REDACTED]") */
|
|
41
|
+
replacement?: string;
|
|
42
|
+
/** Additional custom patterns to match */
|
|
43
|
+
customPatterns?: SecretPattern[];
|
|
44
|
+
/** Field names to skip scanning (e.g., "id", "signature") */
|
|
45
|
+
skipFields?: string[];
|
|
46
|
+
}
|
|
47
|
+
export interface SecretPattern {
|
|
48
|
+
/** Human-readable name for this pattern */
|
|
49
|
+
name: string;
|
|
50
|
+
/** Regex to match the secret */
|
|
51
|
+
pattern: RegExp;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Built-in secret patterns based on common formats.
|
|
55
|
+
* Covers major cloud providers, VCS platforms, payment processors,
|
|
56
|
+
* communication tools, and generic credential formats.
|
|
57
|
+
*/
|
|
58
|
+
export declare const builtinPatterns: SecretPattern[];
|
|
59
|
+
/**
|
|
60
|
+
* Default field names to skip when scanning structured data.
|
|
61
|
+
* These commonly contain high-entropy but non-secret data.
|
|
62
|
+
*/
|
|
63
|
+
export declare const defaultSkipFields: string[];
|
|
64
|
+
/**
|
|
65
|
+
* Compute Shannon entropy for a string.
|
|
66
|
+
*
|
|
67
|
+
* Shannon entropy measures the randomness/information density of a string.
|
|
68
|
+
* Random strings (like API keys) typically have entropy > 4.5 bits per character,
|
|
69
|
+
* while natural language text is usually below 4.0.
|
|
70
|
+
*
|
|
71
|
+
* @param s - The string to analyze
|
|
72
|
+
* @returns Entropy in bits per character (0 to log2(charset_size))
|
|
73
|
+
*/
|
|
74
|
+
export declare function shannonEntropy(s: string): number;
|
|
75
|
+
/**
|
|
76
|
+
* Redact secrets from a text string.
|
|
77
|
+
*
|
|
78
|
+
* Combines entropy-based and pattern-based scanning to detect
|
|
79
|
+
* and replace secrets with a configurable placeholder.
|
|
80
|
+
*
|
|
81
|
+
* @param text - The text to scan and redact
|
|
82
|
+
* @param config - Optional configuration overrides
|
|
83
|
+
* @returns The redacted text and detection details
|
|
84
|
+
*/
|
|
85
|
+
export declare function redactContent(text: string, config?: RedactionConfig): RedactionResult;
|
|
86
|
+
/**
|
|
87
|
+
* Check if a field name should be skipped during structured data scanning.
|
|
88
|
+
*
|
|
89
|
+
* Fields like "id", "signature", "hash" etc. often contain high-entropy
|
|
90
|
+
* strings that are not secrets.
|
|
91
|
+
*/
|
|
92
|
+
export declare function shouldSkipField(fieldName: string, skipFields?: string[]): boolean;
|
|
93
|
+
/**
|
|
94
|
+
* Recursively redact secrets from a structured object.
|
|
95
|
+
*
|
|
96
|
+
* Walks through all string values in the object tree and applies
|
|
97
|
+
* content-aware redaction. Skips fields that commonly contain
|
|
98
|
+
* non-secret high-entropy data (IDs, signatures, hashes).
|
|
99
|
+
*
|
|
100
|
+
* @param obj - The object to scan
|
|
101
|
+
* @param config - Optional redaction configuration
|
|
102
|
+
* @returns A new object with secrets redacted
|
|
103
|
+
*/
|
|
104
|
+
export declare function redactObject(obj: unknown, config?: RedactionConfig): unknown;
|
|
105
|
+
//# sourceMappingURL=content-redaction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-redaction.d.ts","sourceRoot":"","sources":["../../src/security/content-redaction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,qDAAqD;AACrD,MAAM,WAAW,eAAe;IAC9B,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,YAAY,EAAE,MAAM,CAAC;IACrB,sDAAsD;IACtD,UAAU,EAAE,eAAe,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,eAAe;IAC9B,mCAAmC;IACnC,MAAM,EAAE,SAAS,GAAG,SAAS,CAAC;IAC9B,qDAAqD;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,uDAAuD;AACvD,MAAM,WAAW,eAAe;IAC9B,+CAA+C;IAC/C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6DAA6D;IAC7D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+DAA+D;IAC/D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sEAAsE;IACtE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,cAAc,CAAC,EAAE,aAAa,EAAE,CAAC;IACjC,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,gCAAgC;IAChC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,aAAa,EA0E1C,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,UAU7B,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAiBhD;AAsKD;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,MAAM,GAAE,eAAoB,GAC3B,eAAe,CAwCjB;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,MAAM,EAAE,GACpB,OAAO,CAcT;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,OAAO,EACZ,MAAM,GAAE,eAAoB,GAC3B,OAAO,CAiCT"}
|