@nikhil_telkar/codeshield 0.0.0-stage → 0.1.0

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 (103) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +289 -2
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +237 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/engine/fileWalker.d.ts +15 -0
  8. package/dist/engine/fileWalker.d.ts.map +1 -0
  9. package/dist/engine/fileWalker.js +170 -0
  10. package/dist/engine/fileWalker.js.map +1 -0
  11. package/dist/engine/index.d.ts +4 -0
  12. package/dist/engine/index.d.ts.map +1 -0
  13. package/dist/engine/index.js +4 -0
  14. package/dist/engine/index.js.map +1 -0
  15. package/dist/engine/projectDetector.d.ts +10 -0
  16. package/dist/engine/projectDetector.d.ts.map +1 -0
  17. package/dist/engine/projectDetector.js +44 -0
  18. package/dist/engine/projectDetector.js.map +1 -0
  19. package/dist/engine/runner.d.ts +8 -0
  20. package/dist/engine/runner.d.ts.map +1 -0
  21. package/dist/engine/runner.js +87 -0
  22. package/dist/engine/runner.js.map +1 -0
  23. package/dist/fix/fixer.d.ts +17 -0
  24. package/dist/fix/fixer.d.ts.map +1 -0
  25. package/dist/fix/fixer.js +190 -0
  26. package/dist/fix/fixer.js.map +1 -0
  27. package/dist/fix/history.d.ts +23 -0
  28. package/dist/fix/history.d.ts.map +1 -0
  29. package/dist/fix/history.js +107 -0
  30. package/dist/fix/history.js.map +1 -0
  31. package/dist/fix/index.d.ts +3 -0
  32. package/dist/fix/index.d.ts.map +1 -0
  33. package/dist/fix/index.js +3 -0
  34. package/dist/fix/index.js.map +1 -0
  35. package/dist/index.d.ts +8 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +8 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/report/colors.d.ts +21 -0
  40. package/dist/report/colors.d.ts.map +1 -0
  41. package/dist/report/colors.js +70 -0
  42. package/dist/report/colors.js.map +1 -0
  43. package/dist/report/index.d.ts +15 -0
  44. package/dist/report/index.d.ts.map +1 -0
  45. package/dist/report/index.js +39 -0
  46. package/dist/report/index.js.map +1 -0
  47. package/dist/report/sarif.d.ts +44 -0
  48. package/dist/report/sarif.d.ts.map +1 -0
  49. package/dist/report/sarif.js +69 -0
  50. package/dist/report/sarif.js.map +1 -0
  51. package/dist/report/score.d.ts +14 -0
  52. package/dist/report/score.d.ts.map +1 -0
  53. package/dist/report/score.js +62 -0
  54. package/dist/report/score.js.map +1 -0
  55. package/dist/report/terminal.d.ts +10 -0
  56. package/dist/report/terminal.d.ts.map +1 -0
  57. package/dist/report/terminal.js +77 -0
  58. package/dist/report/terminal.js.map +1 -0
  59. package/dist/scanners/code.d.ts +22 -0
  60. package/dist/scanners/code.d.ts.map +1 -0
  61. package/dist/scanners/code.js +319 -0
  62. package/dist/scanners/code.js.map +1 -0
  63. package/dist/scanners/dependencies.d.ts +10 -0
  64. package/dist/scanners/dependencies.d.ts.map +1 -0
  65. package/dist/scanners/dependencies.js +240 -0
  66. package/dist/scanners/dependencies.js.map +1 -0
  67. package/dist/scanners/env.d.ts +7 -0
  68. package/dist/scanners/env.d.ts.map +1 -0
  69. package/dist/scanners/env.js +195 -0
  70. package/dist/scanners/env.js.map +1 -0
  71. package/dist/scanners/helper.d.ts +27 -0
  72. package/dist/scanners/helper.d.ts.map +1 -0
  73. package/dist/scanners/helper.js +50 -0
  74. package/dist/scanners/helper.js.map +1 -0
  75. package/dist/scanners/index.d.ts +6 -0
  76. package/dist/scanners/index.d.ts.map +1 -0
  77. package/dist/scanners/index.js +6 -0
  78. package/dist/scanners/index.js.map +1 -0
  79. package/dist/scanners/secrets.d.ts +19 -0
  80. package/dist/scanners/secrets.d.ts.map +1 -0
  81. package/dist/scanners/secrets.js +213 -0
  82. package/dist/scanners/secrets.js.map +1 -0
  83. package/dist/types.d.ts +43 -0
  84. package/dist/types.d.ts.map +1 -0
  85. package/dist/types.js +2 -0
  86. package/dist/types.js.map +1 -0
  87. package/dist/utils/constants.d.ts +9 -0
  88. package/dist/utils/constants.d.ts.map +1 -0
  89. package/dist/utils/constants.js +54 -0
  90. package/dist/utils/constants.js.map +1 -0
  91. package/dist/utils/levenshtein.d.ts +2 -0
  92. package/dist/utils/levenshtein.d.ts.map +1 -0
  93. package/dist/utils/levenshtein.js +35 -0
  94. package/dist/utils/levenshtein.js.map +1 -0
  95. package/dist/utils/registry.d.ts +18 -0
  96. package/dist/utils/registry.d.ts.map +1 -0
  97. package/dist/utils/registry.js +106 -0
  98. package/dist/utils/registry.js.map +1 -0
  99. package/dist/utils/sanitize.d.ts +3 -0
  100. package/dist/utils/sanitize.d.ts.map +1 -0
  101. package/dist/utils/sanitize.js +10 -0
  102. package/dist/utils/sanitize.js.map +1 -0
  103. package/package.json +56 -4
@@ -0,0 +1,7 @@
1
+ import { Finding, ScanContext, Scanner } from '../types.js';
2
+ export declare function isRealEnvFile(filePath: string): boolean;
3
+ export declare function isEnvExampleFile(filePath: string): boolean;
4
+ export declare function isEnvIgnoredByGitignore(envRelativePath: string, gitignoreContent: string): boolean;
5
+ export declare function scanEnv(context: ScanContext): Finding[];
6
+ export declare const envScanner: Scanner;
7
+ //# sourceMappingURL=env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/scanners/env.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE5D,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAkBvD;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAU1D;AAED,wBAAgB,uBAAuB,CACrC,eAAe,EAAE,MAAM,EACvB,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAmCT;AAqCD,wBAAgB,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,EAAE,CAyGvD;AAED,eAAO,MAAM,UAAU,EAAE,OAGxB,CAAC"}
@@ -0,0 +1,195 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ export function isRealEnvFile(filePath) {
4
+ const base = path.basename(filePath).toLowerCase();
5
+ if (!base.startsWith('.env'))
6
+ return false;
7
+ if (base === '.env.example' ||
8
+ base === '.env.sample' ||
9
+ base === '.env.template' ||
10
+ base === '.env.dist' ||
11
+ base === '.env.defaults' ||
12
+ base.endsWith('.example') ||
13
+ base.endsWith('.sample') ||
14
+ base.endsWith('.template')) {
15
+ return false;
16
+ }
17
+ return true;
18
+ }
19
+ export function isEnvExampleFile(filePath) {
20
+ const base = path.basename(filePath).toLowerCase();
21
+ return (base === '.env.example' ||
22
+ base === '.env.sample' ||
23
+ base === '.env.template' ||
24
+ base.endsWith('.example') ||
25
+ base.endsWith('.sample') ||
26
+ base.endsWith('.template'));
27
+ }
28
+ export function isEnvIgnoredByGitignore(envRelativePath, gitignoreContent) {
29
+ const envFileName = path.basename(envRelativePath);
30
+ const normalizedEnvPath = envRelativePath.replace(/\\/g, '/');
31
+ const lines = gitignoreContent.split(/\r?\n/);
32
+ for (const rawLine of lines) {
33
+ let line = rawLine.trim();
34
+ if (!line || line.startsWith('#'))
35
+ continue;
36
+ if (line.startsWith('/')) {
37
+ line = line.slice(1);
38
+ }
39
+ if (line === envFileName || line === normalizedEnvPath)
40
+ return true;
41
+ if (line === '.env' && envFileName === '.env')
42
+ return true;
43
+ if (line === '.env*' && (envFileName === '.env' || envFileName.startsWith('.env.')))
44
+ return true;
45
+ if (line === '*.env' && envFileName.endsWith('.env'))
46
+ return true;
47
+ if (line === '.env.*' && envFileName.startsWith('.env.'))
48
+ return true;
49
+ if (line === '**/.env' && envFileName === '.env')
50
+ return true;
51
+ if (line.endsWith('/.env') && envFileName === '.env')
52
+ return true;
53
+ if (line.endsWith('/.env*') && (envFileName === '.env' || envFileName.startsWith('.env.')))
54
+ return true;
55
+ if (line.includes('*')) {
56
+ const escaped = line.replace(/[.+?^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*');
57
+ try {
58
+ const re = new RegExp(`^${escaped}$`);
59
+ if (re.test(envFileName) || re.test(normalizedEnvPath))
60
+ return true;
61
+ }
62
+ catch {
63
+ // ignore invalid regex
64
+ }
65
+ }
66
+ }
67
+ return false;
68
+ }
69
+ const BUILD_CONFIG_FILES = new Set([
70
+ 'next.config.js',
71
+ 'next.config.mjs',
72
+ 'next.config.ts',
73
+ 'next.config.cjs',
74
+ 'vite.config.js',
75
+ 'vite.config.ts',
76
+ 'vite.config.mjs',
77
+ 'vite.config.cjs',
78
+ 'webpack.config.js',
79
+ 'webpack.config.ts',
80
+ 'webpack.config.mjs',
81
+ 'webpack.config.cjs',
82
+ ]);
83
+ const SOURCE_MAP_PATTERNS = [
84
+ {
85
+ name: 'Next.js productionBrowserSourceMaps',
86
+ regex: /\bproductionBrowserSourceMaps\s*:\s*true\b/,
87
+ },
88
+ {
89
+ name: 'Vite build sourcemap',
90
+ regex: /\bsourcemap\s*:\s*(?:true|['"]inline['"]|['"]hidden['"])\b/,
91
+ },
92
+ {
93
+ name: 'Webpack production devtool sourcemap',
94
+ regex: /\bdevtool\s*:\s*['"](?:source-map|inline-source-map|eval-source-map|cheap-module-source-map)['"]/,
95
+ },
96
+ ];
97
+ export function scanEnv(context) {
98
+ const findings = [];
99
+ let gitignoreContent = null;
100
+ const gitignoreFile = context.files.find(f => path.basename(f.relativePath).toLowerCase() === '.gitignore');
101
+ if (gitignoreFile) {
102
+ gitignoreContent = gitignoreFile.content;
103
+ }
104
+ else {
105
+ try {
106
+ const diskPath = path.join(context.root, '.gitignore');
107
+ if (fs.existsSync(diskPath)) {
108
+ gitignoreContent = fs.readFileSync(diskPath, 'utf8');
109
+ }
110
+ }
111
+ catch {
112
+ gitignoreContent = null;
113
+ }
114
+ }
115
+ const realEnvFiles = context.files.filter(f => isRealEnvFile(f.relativePath));
116
+ const hasExampleFile = context.files.some(f => isEnvExampleFile(f.relativePath)) ||
117
+ fs.existsSync(path.join(context.root, '.env.example')) ||
118
+ fs.existsSync(path.join(context.root, '.env.sample')) ||
119
+ fs.existsSync(path.join(context.root, '.env.template'));
120
+ for (const envFile of realEnvFiles) {
121
+ const baseName = path.basename(envFile.relativePath);
122
+ const isIgnored = gitignoreContent !== null && isEnvIgnoredByGitignore(envFile.relativePath, gitignoreContent);
123
+ if (!isIgnored) {
124
+ findings.push({
125
+ ruleId: 'ENV-001',
126
+ severity: 'critical',
127
+ title: `Unignored ${baseName} File Not Covered by .gitignore`,
128
+ cwe: 'CWE-798',
129
+ plainExplanation: `The environment file "${envFile.relativePath}" was found, but it is not ignored in .gitignore. Any API keys, database credentials, or auth secrets inside this file are at risk of being committed to Git and leaked publicly.`,
130
+ file: envFile.relativePath,
131
+ line: 1,
132
+ fix: `Add "${baseName}" or ".env*" to your .gitignore file immediately.`,
133
+ aiPrompt: `Add the following lines to .gitignore to ensure environment files are never committed:\n.env\n.env.*\n!.env.example\n!.env.sample`,
134
+ });
135
+ findings.push({
136
+ ruleId: 'ENV-002',
137
+ severity: 'high',
138
+ title: `Risk of Committed Secrets in ${baseName}`,
139
+ cwe: 'CWE-312',
140
+ plainExplanation: `The file "${envFile.relativePath}" exists in the repository without .gitignore protection. If this repository is shared or pushed to GitHub/GitLab, the secrets in this file may be permanently exposed in commit history.`,
141
+ file: envFile.relativePath,
142
+ line: 1,
143
+ fix: `Stop tracking the file with "git rm --cached ${envFile.relativePath}" and ensure it is listed in .gitignore.`,
144
+ aiPrompt: `Provide the git commands to untrack "${envFile.relativePath}" without deleting the local file:\ngit rm --cached ${envFile.relativePath}\ngit commit -m "Untrack ${baseName}"`,
145
+ });
146
+ }
147
+ }
148
+ if (realEnvFiles.length > 0 && !hasExampleFile) {
149
+ const primaryEnv = realEnvFiles[0];
150
+ findings.push({
151
+ ruleId: 'ENV-003',
152
+ severity: 'low',
153
+ title: 'Missing .env.example Template File',
154
+ cwe: 'CWE-1059',
155
+ plainExplanation: `A .env file was found, but no ".env.example" or ".env.sample" template exists. Without an example template, other developers or AI assistants cannot know which environment variables are required to run the project.`,
156
+ file: primaryEnv.relativePath,
157
+ line: 1,
158
+ fix: `Create a .env.example file containing all required variable names with dummy placeholder values (never real secrets).`,
159
+ aiPrompt: `Read ${primaryEnv.relativePath} and generate a safe .env.example file with all keys preserved, but with dummy values (e.g. DATABASE_URL="postgres://user:YOUR_PASSWORD@localhost:5432/mydb").`,
160
+ });
161
+ }
162
+ for (const file of context.files) {
163
+ const baseName = path.basename(file.relativePath).toLowerCase();
164
+ if (!BUILD_CONFIG_FILES.has(baseName)) {
165
+ continue;
166
+ }
167
+ for (let lineIdx = 0; lineIdx < file.lines.length; lineIdx++) {
168
+ const line = file.lines[lineIdx] ?? '';
169
+ if (line.trim().startsWith('//') || line.trim().startsWith('/*') || line.trim().startsWith('*')) {
170
+ continue;
171
+ }
172
+ for (const pattern of SOURCE_MAP_PATTERNS) {
173
+ if (pattern.regex.test(line)) {
174
+ findings.push({
175
+ ruleId: 'ENV-004',
176
+ severity: 'medium',
177
+ title: 'Production Source Maps Enabled in Build Config',
178
+ cwe: 'CWE-540',
179
+ plainExplanation: `Production source maps are enabled (${pattern.name}) on line ${lineIdx + 1} of "${file.relativePath}". When source maps are uploaded to production, anyone can open browser Developer Tools and view your original unminified source code, proprietary algorithms, and internal comments.`,
180
+ file: file.relativePath,
181
+ line: lineIdx + 1,
182
+ fix: `Disable production source maps in "${baseName}" (set productionBrowserSourceMaps: false or sourcemap: false).`,
183
+ aiPrompt: `In "${file.relativePath}", disable production source maps on line ${lineIdx + 1} by setting the option to false.`,
184
+ });
185
+ }
186
+ }
187
+ }
188
+ }
189
+ return findings;
190
+ }
191
+ export const envScanner = {
192
+ name: 'env',
193
+ scan: scanEnv,
194
+ };
195
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/scanners/env.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { Finding, Severity } from '../types.js';
2
+ export interface RuleContext {
3
+ file: string;
4
+ content: string;
5
+ lines: string[];
6
+ }
7
+ export interface Rule {
8
+ id: string;
9
+ name: string;
10
+ severity: Severity;
11
+ description: string;
12
+ remediation: string;
13
+ check: (context: RuleContext) => Finding[];
14
+ }
15
+ export interface RegexRuleOptions {
16
+ id: string;
17
+ name: string;
18
+ severity: Severity;
19
+ description: string;
20
+ remediation: string;
21
+ regex: RegExp;
22
+ isSecret?: boolean;
23
+ extensions?: string[];
24
+ customMessage?: (match: RegExpExecArray) => string;
25
+ }
26
+ export declare function createLineRegexRule(options: RegexRuleOptions): Rule;
27
+ //# sourceMappingURL=helper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../../src/scanners/helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAwB,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGtE,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,EAAE,CAAC;CAC5C;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,MAAM,CAAC;CACpD;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAsDnE"}
@@ -0,0 +1,50 @@
1
+ import { maskSecret, sanitize } from '../utils/sanitize.js';
2
+ export function createLineRegexRule(options) {
3
+ return {
4
+ id: options.id,
5
+ name: options.name,
6
+ severity: options.severity,
7
+ description: options.description,
8
+ remediation: options.remediation,
9
+ check(context) {
10
+ if (options.extensions && options.extensions.length > 0) {
11
+ const matchesExt = options.extensions.some(ext => context.file.toLowerCase().endsWith(ext.toLowerCase()));
12
+ if (!matchesExt)
13
+ return [];
14
+ }
15
+ const findings = [];
16
+ for (let lineIdx = 0; lineIdx < context.lines.length; lineIdx++) {
17
+ const line = context.lines[lineIdx] ?? '';
18
+ const re = new RegExp(options.regex.source, options.regex.flags);
19
+ let match;
20
+ while ((match = re.exec(line)) !== null) {
21
+ let snippet = sanitize(line.trim());
22
+ if (options.isSecret) {
23
+ const secretValue = match[1] ?? match[0];
24
+ snippet = snippet.replace(secretValue, maskSecret(secretValue));
25
+ }
26
+ const message = options.customMessage
27
+ ? options.customMessage(match)
28
+ : options.description;
29
+ findings.push({
30
+ ruleId: options.id,
31
+ severity: options.severity,
32
+ title: options.name,
33
+ plainExplanation: message,
34
+ file: context.file,
35
+ line: lineIdx + 1,
36
+ fix: options.remediation,
37
+ aiPrompt: `Fix security issue "${options.name}" (${options.id}): ${message}. Remediation: ${options.remediation}. Code: ${snippet}`,
38
+ });
39
+ if (!re.global)
40
+ break;
41
+ if (match.index === re.lastIndex) {
42
+ re.lastIndex++;
43
+ }
44
+ }
45
+ }
46
+ return findings;
47
+ },
48
+ };
49
+ }
50
+ //# sourceMappingURL=helper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helper.js","sourceRoot":"","sources":["../../src/scanners/helper.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AA6B5D,MAAM,UAAU,mBAAmB,CAAC,OAAyB;IAC3D,OAAO;QACL,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,KAAK,CAAC,OAAoB;YACxB,IAAI,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxD,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAC/C,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CACvD,CAAC;gBACF,IAAI,CAAC,UAAU;oBAAE,OAAO,EAAE,CAAC;YAC7B,CAAC;YAED,MAAM,QAAQ,GAAc,EAAE,CAAC;YAE/B,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,CAAC;gBAChE,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;gBAC1C,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBAEjE,IAAI,KAA6B,CAAC;gBAClC,OAAO,CAAC,KAAK,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;oBACxC,IAAI,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;oBACpC,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;wBACrB,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC;wBACzC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC;oBAClE,CAAC;oBAED,MAAM,OAAO,GAAG,OAAO,CAAC,aAAa;wBACnC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC;wBAC9B,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;oBAExB,QAAQ,CAAC,IAAI,CAAC;wBACZ,MAAM,EAAE,OAAO,CAAC,EAAE;wBAClB,QAAQ,EAAE,OAAO,CAAC,QAAQ;wBAC1B,KAAK,EAAE,OAAO,CAAC,IAAI;wBACnB,gBAAgB,EAAE,OAAO;wBACzB,IAAI,EAAE,OAAO,CAAC,IAAI;wBAClB,IAAI,EAAE,OAAO,GAAG,CAAC;wBACjB,GAAG,EAAE,OAAO,CAAC,WAAW;wBACxB,QAAQ,EAAE,uBAAuB,OAAO,CAAC,IAAI,MAAM,OAAO,CAAC,EAAE,MAAM,OAAO,kBAAkB,OAAO,CAAC,WAAW,WAAW,OAAO,EAAE;qBACpI,CAAC,CAAC;oBAEH,IAAI,CAAC,EAAE,CAAC,MAAM;wBAAE,MAAM;oBACtB,IAAI,KAAK,CAAC,KAAK,KAAK,EAAE,CAAC,SAAS,EAAE,CAAC;wBACjC,EAAE,CAAC,SAAS,EAAE,CAAC;oBACjB,CAAC;gBACH,CAAC;YACH,CAAC;YAED,OAAO,QAAQ,CAAC;QAClB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,6 @@
1
+ export * from './helper.js';
2
+ export * from './secrets.js';
3
+ export * from './env.js';
4
+ export * from './dependencies.js';
5
+ export * from './code.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scanners/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,mBAAmB,CAAC;AAClC,cAAc,WAAW,CAAC"}
@@ -0,0 +1,6 @@
1
+ export * from './helper.js';
2
+ export * from './secrets.js';
3
+ export * from './env.js';
4
+ export * from './dependencies.js';
5
+ export * from './code.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/scanners/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,mBAAmB,CAAC;AAClC,cAAc,WAAW,CAAC"}
@@ -0,0 +1,19 @@
1
+ import { Finding, ScanContext, Scanner, Severity } from '../types.js';
2
+ export declare function isPlaceholder(val: string): boolean;
3
+ export declare function isLineIgnored(line: string): boolean;
4
+ export declare function isTestOrFixture(relativePath: string, content: string): boolean;
5
+ export interface SecretRuleDefinition {
6
+ id: string;
7
+ severity: Severity;
8
+ title: string;
9
+ cwe?: string;
10
+ plainExplanation: string;
11
+ fix: string;
12
+ aiPromptTemplate: string;
13
+ regex: RegExp;
14
+ extractSecret?: (match: RegExpExecArray) => string | null;
15
+ }
16
+ export declare const SECRET_RULES: SecretRuleDefinition[];
17
+ export declare function scanSecrets(context: ScanContext): Finding[];
18
+ export declare const secretsScanner: Scanner;
19
+ //# sourceMappingURL=secrets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secrets.d.ts","sourceRoot":"","sources":["../../src/scanners/secrets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAkCtE,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAKlD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAG9E;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,MAAM,CAAC;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,gBAAgB,EAAE,MAAM,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,MAAM,GAAG,IAAI,CAAC;CAC3D;AAED,eAAO,MAAM,YAAY,EAAE,oBAAoB,EAmI9C,CAAC;AAEF,wBAAgB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,EAAE,CAyD3D;AAED,eAAO,MAAM,cAAc,EAAE,OAG5B,CAAC"}
@@ -0,0 +1,213 @@
1
+ import { maskSecret, sanitize } from '../utils/sanitize.js';
2
+ const PLACEHOLDER_STRINGS = new Set([
3
+ 'your_api_key',
4
+ 'your_secret_key',
5
+ 'your_jwt_secret',
6
+ 'your_password',
7
+ 'your_token',
8
+ 'your_key_here',
9
+ 'my_api_key',
10
+ 'my_secret_key',
11
+ 'changeme',
12
+ 'replace_me',
13
+ 'placeholder',
14
+ 'dummy_token',
15
+ 'example_key',
16
+ 'test_secret',
17
+ 'undefined',
18
+ 'null',
19
+ ]);
20
+ const PLACEHOLDER_REGEXES = [
21
+ /your[_-]?(?:api[_-]?)?(?:key|secret|token|password)/i,
22
+ /replace[_-]?me/i,
23
+ /enter[_-]?your/i,
24
+ /insert[_-]?here/i,
25
+ /<[^>]+>/,
26
+ /\.{3,}/,
27
+ /0{12,}/,
28
+ /x{12,}/i,
29
+ /^1234567890*$/,
30
+ ];
31
+ export function isPlaceholder(val) {
32
+ const clean = val.trim().toLowerCase();
33
+ if (clean.length < 6)
34
+ return true;
35
+ if (PLACEHOLDER_STRINGS.has(clean))
36
+ return true;
37
+ return PLACEHOLDER_REGEXES.some(re => re.test(clean));
38
+ }
39
+ export function isLineIgnored(line) {
40
+ return /codeshield-ignore|@codeshield-ignore|codeshield-disable/i.test(line);
41
+ }
42
+ export function isTestOrFixture(relativePath, content) {
43
+ if (content.includes('codeshield-ignore-file'))
44
+ return true;
45
+ return false;
46
+ }
47
+ export const SECRET_RULES = [
48
+ {
49
+ id: 'SEC-001',
50
+ severity: 'critical',
51
+ title: 'Hardcoded AWS Access Key',
52
+ cwe: 'CWE-798',
53
+ plainExplanation: 'An Amazon Web Services (AWS) Access Key ID was found directly in your source code. If committed to GitHub or shared, attackers can scan for this key and access your cloud infrastructure, potentially deleting services or incurring thousands of dollars in unauthorized usage.',
54
+ fix: 'Store the AWS Access Key in an environment variable (such as AWS_ACCESS_KEY_ID) or use IAM Roles instead of hardcoded credentials.',
55
+ aiPromptTemplate: 'Refactor this code to remove the hardcoded AWS Access Key on line {LINE}. Use process.env.AWS_ACCESS_KEY_ID and update .env.example with a placeholder.',
56
+ regex: /\b(AKIA[0-9A-Z]{16})\b/g,
57
+ extractSecret: m => m[1] ?? null,
58
+ },
59
+ {
60
+ id: 'SEC-002',
61
+ severity: 'critical',
62
+ title: 'Hardcoded Stripe Live Secret Key',
63
+ cwe: 'CWE-798',
64
+ plainExplanation: 'A live Stripe secret API key was found in your code. Live Stripe keys have full administrative access to your Stripe account, allowing anyone who finds them to view customer payment details, initiate refunds, or charge cards.',
65
+ fix: 'Move your Stripe secret key to a server-side environment variable (e.g., STRIPE_SECRET_KEY in a .env file that is ignored by Git). Never commit live secret keys.',
66
+ aiPromptTemplate: 'Remove the hardcoded Stripe live key on line {LINE}. Use process.env.STRIPE_SECRET_KEY and document how to configure it in .env.',
67
+ regex: /\b(sk_live_[0-9a-zA-Z]{24,})\b/g,
68
+ extractSecret: m => m[1] ?? null,
69
+ },
70
+ {
71
+ id: 'SEC-003',
72
+ severity: 'critical',
73
+ title: 'Hardcoded GitHub Personal Access Token',
74
+ cwe: 'CWE-798',
75
+ plainExplanation: 'A GitHub personal access token (PAT) or OAuth token was found in your code. Anyone with this token can access your private GitHub repositories, alter code, or delete repositories.',
76
+ fix: 'Revoke this token immediately in your GitHub developer settings, generate a new one, and inject it securely via environment variables or CI/CD secrets (e.g. GITHUB_TOKEN).',
77
+ aiPromptTemplate: 'Replace the hardcoded GitHub token on line {LINE} with process.env.GITHUB_TOKEN.',
78
+ regex: /\b(ghp_[0-9a-zA-Z]{36}|gho_[0-9a-zA-Z]{36}|github_pat_[0-9a-zA-Z_]{22,})\b/g,
79
+ extractSecret: m => m[1] ?? null,
80
+ },
81
+ {
82
+ id: 'SEC-004',
83
+ severity: 'critical',
84
+ title: 'Hardcoded AI Provider API Key (OpenAI / Anthropic)',
85
+ cwe: 'CWE-798',
86
+ plainExplanation: 'An API key for an AI model provider (OpenAI or Anthropic) was found hardcoded in this file. Exposed AI keys are frequently scraped by bots within minutes of being pushed, resulting in immediate unauthorized API usage and billing fees.',
87
+ fix: 'Move the key to your .env file as OPENAI_API_KEY or ANTHROPIC_API_KEY, and make sure .env is included in your .gitignore.',
88
+ aiPromptTemplate: 'Refactor this code to remove the hardcoded AI API key on line {LINE}. Load it from process.env.OPENAI_API_KEY (or ANTHROPIC_API_KEY) and verify that error handling exists if the environment variable is missing.',
89
+ regex: /\b(sk-(?:proj-|ant-)?[0-9a-zA-Z_-]{20,})\b/g,
90
+ extractSecret: m => m[1] ?? null,
91
+ },
92
+ {
93
+ id: 'SEC-005',
94
+ severity: 'critical',
95
+ title: 'Hardcoded Supabase service_role Key',
96
+ cwe: 'CWE-798',
97
+ plainExplanation: 'A Supabase service_role key was found hardcoded in your code. The service_role key completely bypasses all Supabase Row Level Security (RLS) policies and grants full administrative access to your entire database. It must NEVER be hardcoded or exposed to the frontend.',
98
+ fix: 'Store the service_role key in a secure server-side environment variable (SUPABASE_SERVICE_ROLE_KEY). For client-side code, use only the public anon key with strict RLS policies.',
99
+ aiPromptTemplate: 'Refactor line {LINE} to remove the hardcoded Supabase service_role key. Use process.env.SUPABASE_SERVICE_ROLE_KEY on the backend, and ensure this key is never passed to frontend components.',
100
+ regex: /(?:service_role|supabase_service)[^=\n]{0,30}=\s*['"](eyJ[A-Za-z0-9_-]{15,}\.[A-Za-z0-9_-]{15,}\.[A-Za-z0-9_-]{15,})['"]/i,
101
+ extractSecret: m => m[1] ?? null,
102
+ },
103
+ {
104
+ id: 'SEC-006',
105
+ severity: 'critical',
106
+ title: 'Hardcoded Private Cryptographic Key',
107
+ cwe: 'CWE-321',
108
+ plainExplanation: 'An unencrypted private encryption or signing key block was found in this file. Private keys are meant to be kept secret; exposing them allows attackers to decrypt private communications, forge signatures, or impersonate your server.',
109
+ fix: 'Store private keys in a secrets manager or load them at runtime from a secure file path specified in an environment variable (e.g. PRIVATE_KEY_PATH).',
110
+ aiPromptTemplate: 'Remove the hardcoded private key block starting at line {LINE}. Load the key securely from an environment variable or file system path configured via process.env.',
111
+ regex: /-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/g,
112
+ extractSecret: m => m[0],
113
+ },
114
+ {
115
+ id: 'SEC-007',
116
+ severity: 'high',
117
+ title: 'Database Connection String with Embedded Password',
118
+ cwe: 'CWE-798',
119
+ plainExplanation: 'A database connection string containing a raw username and password was found in your code. Exposing database credentials allows unauthorized users to read, modify, or drop your database tables.',
120
+ fix: 'Extract the database connection string into a DATABASE_URL environment variable in your .env file, and ensure .env is listed in .gitignore.',
121
+ aiPromptTemplate: 'Remove the hardcoded database connection string on line {LINE}. Use process.env.DATABASE_URL instead and provide a .env.example with dummy credentials.',
122
+ regex: /\b(?:postgres|postgresql|mysql|mongodb|mongodb\+srv|redis|mariadb):\/\/[^:\s'"]+:([^@\s'"]+)@[^\s'"]+/g,
123
+ extractSecret: m => m[1] ?? null,
124
+ },
125
+ {
126
+ id: 'SEC-008',
127
+ severity: 'high',
128
+ title: 'Hardcoded or Weak JWT Secret',
129
+ cwe: 'CWE-798',
130
+ plainExplanation: 'A JSON Web Token (JWT) secret key was found hardcoded as a plain string. Attackers can use this secret to forge authentication tokens and impersonate any user, including administrators.',
131
+ fix: 'Move the JWT secret to process.env.JWT_SECRET and ensure it is generated using a cryptographically secure random value with at least 256 bits of entropy.',
132
+ aiPromptTemplate: 'Update line {LINE} to remove the hardcoded JWT secret. Use process.env.JWT_SECRET and throw an error if the environment variable is not set.',
133
+ regex: /\b(?:jwt(?:Secret|_secret)?|JWT_SECRET)\s*[:=]\s*['"]([^'"]{4,})['"]|\bjwt\.sign\s*\([^,]+,\s*['"]([^'"]{4,})['"]/g,
134
+ extractSecret: m => m[1] ?? m[2] ?? null,
135
+ },
136
+ {
137
+ id: 'SEC-009',
138
+ severity: 'high',
139
+ title: 'Hardcoded Generic API Secret or Token',
140
+ cwe: 'CWE-798',
141
+ plainExplanation: 'A generic secret key, API token, or access credential was found hardcoded. Anyone who views this source code will have access to the associated third-party service.',
142
+ fix: 'Store this secret in an environment variable and load it via process.env.',
143
+ aiPromptTemplate: 'Extract the hardcoded API credential on line {LINE} into an environment variable loaded through process.env.',
144
+ regex: /\b(?:api_key|apiKey|api_secret|apiSecret|access_token|accessToken|secret_key|secretKey|private_token)\s*[:=]\s*['"]([0-9a-zA-Z_\-]{24,})['"]/g,
145
+ extractSecret: m => m[1] ?? null,
146
+ },
147
+ {
148
+ id: 'SEC-010',
149
+ severity: 'critical',
150
+ title: 'Private Key or Secret Leaked to Public Client Variable',
151
+ cwe: 'CWE-200',
152
+ plainExplanation: 'Environment variables prefixed with NEXT_PUBLIC_ or VITE_ are embedded into the client-side JavaScript bundle during build and sent to every browser that visits your website. A private key, service role key, or administrative secret was assigned to a public variable name, exposing it directly to all site visitors.',
153
+ fix: 'Remove the NEXT_PUBLIC_ or VITE_ prefix so the secret remains strictly on the server, and only access it in server-side routes (e.g. Next.js API routes or server components).',
154
+ aiPromptTemplate: 'The secret on line {LINE} is prefixed with NEXT_PUBLIC_ or VITE_, which bundles it into client-side code sent to users. Refactor this to remove the public prefix, move the secret to server-only code, and handle any necessary operations via a backend API route.',
155
+ regex: /\b(NEXT_PUBLIC_[A-Z0-9_]*(?:SECRET|PRIVATE_KEY|SERVICE_ROLE|ADMIN_KEY|TOKEN)|VITE_[A-Z0-9_]*(?:SECRET|PRIVATE_KEY|SERVICE_ROLE|ADMIN_KEY|TOKEN))\s*[:=]\s*['"]?([^'"\s;,\n]+)/g,
156
+ extractSecret: m => m[2] ?? null,
157
+ },
158
+ ];
159
+ export function scanSecrets(context) {
160
+ const findings = [];
161
+ for (const file of context.files) {
162
+ if (isTestOrFixture(file.relativePath, file.content)) {
163
+ continue;
164
+ }
165
+ for (let lineIdx = 0; lineIdx < file.lines.length; lineIdx++) {
166
+ const line = file.lines[lineIdx] ?? '';
167
+ if (isLineIgnored(line)) {
168
+ continue;
169
+ }
170
+ for (const rule of SECRET_RULES) {
171
+ const re = new RegExp(rule.regex.source, rule.regex.flags);
172
+ let match;
173
+ while ((match = re.exec(line)) !== null) {
174
+ const rawSecret = rule.extractSecret ? rule.extractSecret(match) : match[0];
175
+ if (!rawSecret || isPlaceholder(rawSecret)) {
176
+ if (!re.global)
177
+ break;
178
+ if (match.index === re.lastIndex)
179
+ re.lastIndex++;
180
+ continue;
181
+ }
182
+ const maskedVal = maskSecret(rawSecret);
183
+ const sanitizedLine = sanitize(line.trim());
184
+ const maskedSnippet = sanitizedLine.replace(rawSecret, maskedVal);
185
+ const aiPrompt = `${rule.aiPromptTemplate.replace('{LINE}', String(lineIdx + 1))} Code: ${maskedSnippet}`;
186
+ const finding = {
187
+ ruleId: rule.id,
188
+ severity: rule.severity,
189
+ title: rule.title,
190
+ plainExplanation: rule.plainExplanation,
191
+ file: file.relativePath,
192
+ line: lineIdx + 1,
193
+ fix: rule.fix,
194
+ aiPrompt,
195
+ snippet: maskedSnippet,
196
+ ...(rule.cwe ? { cwe: rule.cwe } : {}),
197
+ };
198
+ findings.push(finding);
199
+ if (!re.global)
200
+ break;
201
+ if (match.index === re.lastIndex)
202
+ re.lastIndex++;
203
+ }
204
+ }
205
+ }
206
+ }
207
+ return findings;
208
+ }
209
+ export const secretsScanner = {
210
+ name: 'secrets',
211
+ scan: scanSecrets,
212
+ };
213
+ //# sourceMappingURL=secrets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../src/scanners/secrets.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ export type Severity = 'critical' | 'high' | 'medium' | 'low' | 'info';
2
+ export type ProjectType = 'nextjs' | 'vite-react' | 'express' | 'plain-html' | 'unknown';
3
+ export interface Finding {
4
+ ruleId: string;
5
+ severity: Severity;
6
+ title: string;
7
+ plainExplanation: string;
8
+ file: string;
9
+ line: number;
10
+ fix: string;
11
+ aiPrompt: string;
12
+ cwe?: string;
13
+ snippet?: string;
14
+ }
15
+ export interface ScannedFile {
16
+ path: string;
17
+ relativePath: string;
18
+ content: string;
19
+ lines: string[];
20
+ }
21
+ export interface ScanContext {
22
+ root: string;
23
+ projectType: ProjectType;
24
+ files: ScannedFile[];
25
+ }
26
+ export interface Scanner {
27
+ name: string;
28
+ scan: (context: ScanContext) => Finding[];
29
+ }
30
+ export interface ScanResult {
31
+ projectType: ProjectType;
32
+ findings: Finding[];
33
+ filesScanned: number;
34
+ filesSkipped: number;
35
+ truncated: boolean;
36
+ durationMs: number;
37
+ }
38
+ export interface RunnerOptions {
39
+ root: string;
40
+ minSeverity?: Severity;
41
+ scanners?: Scanner[];
42
+ }
43
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;AAEvE,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,YAAY,GAAG,SAAS,GAAG,YAAY,GAAG,SAAS,CAAC;AAEzF,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,WAAW,CAAC;IACzB,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,EAAE,CAAC;CAC3C;AAED,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,WAAW,CAAC;IACzB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;CACtB"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}