@fourteensystems/shipguard 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 (139) hide show
  1. package/README.md +213 -0
  2. package/bin/shipguard.mjs +2 -0
  3. package/dist/cli/commands/baseline.d.ts +7 -0
  4. package/dist/cli/commands/baseline.d.ts.map +1 -0
  5. package/dist/cli/commands/baseline.js +22 -0
  6. package/dist/cli/commands/baseline.js.map +1 -0
  7. package/dist/cli/commands/ci.d.ts +13 -0
  8. package/dist/cli/commands/ci.d.ts.map +1 -0
  9. package/dist/cli/commands/ci.js +91 -0
  10. package/dist/cli/commands/ci.js.map +1 -0
  11. package/dist/cli/commands/explain.d.ts +2 -0
  12. package/dist/cli/commands/explain.d.ts.map +1 -0
  13. package/dist/cli/commands/explain.js +20 -0
  14. package/dist/cli/commands/explain.js.map +1 -0
  15. package/dist/cli/commands/init.d.ts +7 -0
  16. package/dist/cli/commands/init.d.ts.map +1 -0
  17. package/dist/cli/commands/init.js +91 -0
  18. package/dist/cli/commands/init.js.map +1 -0
  19. package/dist/cli/commands/rules.d.ts +2 -0
  20. package/dist/cli/commands/rules.d.ts.map +1 -0
  21. package/dist/cli/commands/rules.js +13 -0
  22. package/dist/cli/commands/rules.js.map +1 -0
  23. package/dist/cli/commands/scan.d.ts +10 -0
  24. package/dist/cli/commands/scan.d.ts.map +1 -0
  25. package/dist/cli/commands/scan.js +55 -0
  26. package/dist/cli/commands/scan.js.map +1 -0
  27. package/dist/cli/commands/waive.d.ts +8 -0
  28. package/dist/cli/commands/waive.d.ts.map +1 -0
  29. package/dist/cli/commands/waive.js +34 -0
  30. package/dist/cli/commands/waive.js.map +1 -0
  31. package/dist/cli/index.d.ts +2 -0
  32. package/dist/cli/index.d.ts.map +1 -0
  33. package/dist/cli/index.js +63 -0
  34. package/dist/cli/index.js.map +1 -0
  35. package/dist/engine/baseline.d.ts +11 -0
  36. package/dist/engine/baseline.d.ts.map +1 -0
  37. package/dist/engine/baseline.js +39 -0
  38. package/dist/engine/baseline.js.map +1 -0
  39. package/dist/engine/config.d.ts +8 -0
  40. package/dist/engine/config.d.ts.map +1 -0
  41. package/dist/engine/config.js +130 -0
  42. package/dist/engine/config.js.map +1 -0
  43. package/dist/engine/extensions/load.d.ts +11 -0
  44. package/dist/engine/extensions/load.d.ts.map +1 -0
  45. package/dist/engine/extensions/load.js +26 -0
  46. package/dist/engine/extensions/load.js.map +1 -0
  47. package/dist/engine/extensions/registry.d.ts +5 -0
  48. package/dist/engine/extensions/registry.d.ts.map +1 -0
  49. package/dist/engine/extensions/registry.js +11 -0
  50. package/dist/engine/extensions/registry.js.map +1 -0
  51. package/dist/engine/extensions/types.d.ts +51 -0
  52. package/dist/engine/extensions/types.d.ts.map +1 -0
  53. package/dist/engine/extensions/types.js +2 -0
  54. package/dist/engine/extensions/types.js.map +1 -0
  55. package/dist/engine/report.d.ts +5 -0
  56. package/dist/engine/report.d.ts.map +1 -0
  57. package/dist/engine/report.js +88 -0
  58. package/dist/engine/report.js.map +1 -0
  59. package/dist/engine/run.d.ts +9 -0
  60. package/dist/engine/run.d.ts.map +1 -0
  61. package/dist/engine/run.js +101 -0
  62. package/dist/engine/run.js.map +1 -0
  63. package/dist/engine/sarif.d.ts +3 -0
  64. package/dist/engine/sarif.d.ts.map +1 -0
  65. package/dist/engine/sarif.js +58 -0
  66. package/dist/engine/sarif.js.map +1 -0
  67. package/dist/engine/score.d.ts +13 -0
  68. package/dist/engine/score.d.ts.map +1 -0
  69. package/dist/engine/score.js +97 -0
  70. package/dist/engine/score.js.map +1 -0
  71. package/dist/engine/types.d.ts +119 -0
  72. package/dist/engine/types.d.ts.map +1 -0
  73. package/dist/engine/types.js +2 -0
  74. package/dist/engine/types.js.map +1 -0
  75. package/dist/engine/version.d.ts +5 -0
  76. package/dist/engine/version.d.ts.map +1 -0
  77. package/dist/engine/version.js +15 -0
  78. package/dist/engine/version.js.map +1 -0
  79. package/dist/engine/waivers.d.ts +9 -0
  80. package/dist/engine/waivers.d.ts.map +1 -0
  81. package/dist/engine/waivers.js +55 -0
  82. package/dist/engine/waivers.js.map +1 -0
  83. package/dist/index.d.ts +12 -0
  84. package/dist/index.d.ts.map +1 -0
  85. package/dist/index.js +11 -0
  86. package/dist/index.js.map +1 -0
  87. package/dist/next/deps.d.ts +4 -0
  88. package/dist/next/deps.d.ts.map +1 -0
  89. package/dist/next/deps.js +102 -0
  90. package/dist/next/deps.js.map +1 -0
  91. package/dist/next/detect.d.ts +10 -0
  92. package/dist/next/detect.d.ts.map +1 -0
  93. package/dist/next/detect.js +57 -0
  94. package/dist/next/detect.js.map +1 -0
  95. package/dist/next/index.d.ts +5 -0
  96. package/dist/next/index.d.ts.map +1 -0
  97. package/dist/next/index.js +41 -0
  98. package/dist/next/index.js.map +1 -0
  99. package/dist/next/middleware.d.ts +3 -0
  100. package/dist/next/middleware.d.ts.map +1 -0
  101. package/dist/next/middleware.js +33 -0
  102. package/dist/next/middleware.js.map +1 -0
  103. package/dist/next/routes.d.ts +5 -0
  104. package/dist/next/routes.d.ts.map +1 -0
  105. package/dist/next/routes.js +125 -0
  106. package/dist/next/routes.js.map +1 -0
  107. package/dist/next/server-actions.d.ts +4 -0
  108. package/dist/next/server-actions.d.ts.map +1 -0
  109. package/dist/next/server-actions.js +107 -0
  110. package/dist/next/server-actions.js.map +1 -0
  111. package/dist/next/trpc.d.ts +3 -0
  112. package/dist/next/trpc.d.ts.map +1 -0
  113. package/dist/next/trpc.js +339 -0
  114. package/dist/next/trpc.js.map +1 -0
  115. package/dist/next/types.d.ts +100 -0
  116. package/dist/next/types.d.ts.map +1 -0
  117. package/dist/next/types.js +2 -0
  118. package/dist/next/types.js.map +1 -0
  119. package/dist/rules/auth-boundary-missing.d.ts +5 -0
  120. package/dist/rules/auth-boundary-missing.d.ts.map +1 -0
  121. package/dist/rules/auth-boundary-missing.js +278 -0
  122. package/dist/rules/auth-boundary-missing.js.map +1 -0
  123. package/dist/rules/index.d.ts +12 -0
  124. package/dist/rules/index.d.ts.map +1 -0
  125. package/dist/rules/index.js +41 -0
  126. package/dist/rules/index.js.map +1 -0
  127. package/dist/rules/rate-limit-missing.d.ts +5 -0
  128. package/dist/rules/rate-limit-missing.d.ts.map +1 -0
  129. package/dist/rules/rate-limit-missing.js +230 -0
  130. package/dist/rules/rate-limit-missing.js.map +1 -0
  131. package/dist/rules/tenancy-scope-missing.d.ts +5 -0
  132. package/dist/rules/tenancy-scope-missing.d.ts.map +1 -0
  133. package/dist/rules/tenancy-scope-missing.js +149 -0
  134. package/dist/rules/tenancy-scope-missing.js.map +1 -0
  135. package/dist/util/paths.d.ts +6 -0
  136. package/dist/util/paths.d.ts.map +1 -0
  137. package/dist/util/paths.js +18 -0
  138. package/dist/util/paths.js.map +1 -0
  139. package/package.json +55 -0
@@ -0,0 +1,34 @@
1
+ import pc from "picocolors";
2
+ import { addWaiver } from "../../engine/waivers.js";
3
+ import { loadConfigIfExists, DEFAULT_CONFIG } from "../../engine/config.js";
4
+ export async function cmdWaive(ruleId, opts) {
5
+ try {
6
+ // Validate expiry date if provided
7
+ if (opts.expiry) {
8
+ const d = new Date(opts.expiry);
9
+ if (isNaN(d.getTime())) {
10
+ console.error(pc.red(` Invalid expiry date: "${opts.expiry}". Use ISO format (e.g., 2025-12-31)`));
11
+ process.exit(1);
12
+ }
13
+ }
14
+ const rootDir = process.cwd();
15
+ const config = loadConfigIfExists(rootDir) ?? DEFAULT_CONFIG;
16
+ const waiver = addWaiver(rootDir, config.waiversFile, {
17
+ ruleId,
18
+ file: opts.file,
19
+ reason: opts.reason,
20
+ expiry: opts.expiry,
21
+ });
22
+ console.log(pc.green(` Waiver added for ${ruleId}`));
23
+ console.log(pc.dim(` File: ${waiver.file}`));
24
+ console.log(pc.dim(` Reason: ${waiver.reason}`));
25
+ if (waiver.expiry) {
26
+ console.log(pc.dim(` Expires: ${waiver.expiry}`));
27
+ }
28
+ }
29
+ catch (err) {
30
+ console.error(pc.red(` Error: ${err instanceof Error ? err.message : String(err)}`));
31
+ process.exit(1);
32
+ }
33
+ }
34
+ //# sourceMappingURL=waive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"waive.js","sourceRoot":"","sources":["../../../src/cli/commands/waive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAQ5E,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,MAAc,EAAE,IAAkB;IAC/D,IAAI,CAAC;QACH,mCAAmC;QACnC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAChC,IAAI,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;gBACvB,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,2BAA2B,IAAI,CAAC,MAAM,sCAAsC,CAAC,CAAC,CAAC;gBACpG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;QAED,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,kBAAkB,CAAC,OAAO,CAAC,IAAI,cAAc,CAAC;QAE7D,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,WAAW,EAAE;YACpD,MAAM;YACN,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,sBAAsB,MAAM,EAAE,CAAC,CAAC,CAAC;QACtD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAC9C,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,aAAa,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAClD,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,cAAc,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QACtF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,63 @@
1
+ import { Command } from "commander";
2
+ import { cmdScan } from "./commands/scan.js";
3
+ import { cmdCi } from "./commands/ci.js";
4
+ import { cmdInit } from "./commands/init.js";
5
+ import { cmdBaseline } from "./commands/baseline.js";
6
+ import { cmdWaive } from "./commands/waive.js";
7
+ import { cmdRules } from "./commands/rules.js";
8
+ import { cmdExplain } from "./commands/explain.js";
9
+ const program = new Command();
10
+ program
11
+ .name("shipguard")
12
+ .description("Code-level operational maturity analysis for Next.js projects")
13
+ .version("0.1.0");
14
+ program
15
+ .command("init")
16
+ .description("Detect framework, generate config, and run first scan")
17
+ .option("--force", "Overwrite existing config")
18
+ .option("--dry-run", "Print what would happen without writing files")
19
+ .action(cmdInit);
20
+ program
21
+ .command("scan", { isDefault: true })
22
+ .description("Scan the project and print readiness report")
23
+ .option("--format <format>", "Output format: pretty, json, sarif", "pretty")
24
+ .option("--output <path>", "Write report to file")
25
+ .option("--only <rules>", "Run only specified rules (comma-separated)")
26
+ .option("--exclude <globs>", "Additional exclude patterns (comma-separated)")
27
+ .option("--min-confidence <level>", "Minimum confidence to report: low, med, high")
28
+ .action(cmdScan);
29
+ program
30
+ .command("ci")
31
+ .description("CI mode: enforce thresholds and fail on regressions")
32
+ .option("--fail-on <severity>", "Minimum severity to fail: low, med, high, critical", "critical")
33
+ .option("--min-confidence <level>", "Minimum confidence to fail: low, med, high", "high")
34
+ .option("--min-score <score>", "Minimum passing score", "70")
35
+ .option("--baseline <path>", "Baseline file for regression detection")
36
+ .option("--max-new-critical <n>", "Max new critical findings allowed", "0")
37
+ .option("--max-new-high <n>", "Max new high findings allowed")
38
+ .option("--format <format>", "Output format: pretty, json, sarif", "pretty")
39
+ .option("--output <path>", "Write report to file")
40
+ .action(cmdCi);
41
+ program
42
+ .command("baseline")
43
+ .description("Write or update baseline snapshot")
44
+ .option("--write", "Write baseline file")
45
+ .option("--output <path>", "Baseline output path")
46
+ .action(cmdBaseline);
47
+ program
48
+ .command("waive <rule>")
49
+ .description("Add a waiver for a specific finding")
50
+ .requiredOption("--file <path>", "File to waive")
51
+ .requiredOption("--reason <reason>", "Reason for waiver")
52
+ .option("--expiry <date>", "Waiver expiry date (ISO format)")
53
+ .action(cmdWaive);
54
+ program
55
+ .command("rules")
56
+ .description("List all available rules")
57
+ .action(cmdRules);
58
+ program
59
+ .command("explain <rule>")
60
+ .description("Show detailed explanation for a rule")
61
+ .action(cmdExplain);
62
+ program.parse();
63
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { Baseline, Finding, ScanResult } from "./types.js";
2
+ export declare function findingKey(f: Finding): string;
3
+ export declare function writeBaseline(rootDir: string, result: ScanResult, filePath?: string): string;
4
+ export declare function loadBaseline(filePath: string): Baseline | undefined;
5
+ export interface BaselineDiff {
6
+ newFindings: Finding[];
7
+ resolvedKeys: string[];
8
+ scoreDelta: number;
9
+ }
10
+ export declare function diffBaseline(baseline: Baseline, current: ScanResult): BaselineDiff;
11
+ //# sourceMappingURL=baseline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baseline.d.ts","sourceRoot":"","sources":["../../src/engine/baseline.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAGhE,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAE7C;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAa5F;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAOnE;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,OAAO,EAAE,CAAC;IACvB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,UAAU,GAClB,YAAY,CASd"}
@@ -0,0 +1,39 @@
1
+ import path from "node:path";
2
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { SHIPGUARD_VERSION, INDEX_VERSION } from "./version.js";
4
+ export function findingKey(f) {
5
+ return `${f.ruleId}::${f.file}::${f.line ?? 0}`;
6
+ }
7
+ export function writeBaseline(rootDir, result, filePath) {
8
+ const dest = filePath ?? path.join(rootDir, "shipguard.baseline.json");
9
+ const baseline = {
10
+ version: 1,
11
+ shipguardVersion: SHIPGUARD_VERSION,
12
+ configHash: result.configHash,
13
+ indexVersion: INDEX_VERSION,
14
+ createdAt: new Date().toISOString(),
15
+ score: result.score,
16
+ findingKeys: result.findings.map(findingKey),
17
+ };
18
+ writeFileSync(dest, JSON.stringify(baseline, null, 2) + "\n");
19
+ return dest;
20
+ }
21
+ export function loadBaseline(filePath) {
22
+ if (!existsSync(filePath))
23
+ return undefined;
24
+ try {
25
+ return JSON.parse(readFileSync(filePath, "utf8"));
26
+ }
27
+ catch (err) {
28
+ throw new Error(`Failed to parse baseline ${filePath}: ${err instanceof Error ? err.message : String(err)}`);
29
+ }
30
+ }
31
+ export function diffBaseline(baseline, current) {
32
+ const currentKeys = new Set(current.findings.map(findingKey));
33
+ const baselineKeys = new Set(baseline.findingKeys);
34
+ const newFindings = current.findings.filter((f) => !baselineKeys.has(findingKey(f)));
35
+ const resolvedKeys = baseline.findingKeys.filter((k) => !currentKeys.has(k));
36
+ const scoreDelta = current.score - baseline.score;
37
+ return { newFindings, resolvedKeys, scoreDelta };
38
+ }
39
+ //# sourceMappingURL=baseline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baseline.js","sourceRoot":"","sources":["../../src/engine/baseline.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAElE,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAEhE,MAAM,UAAU,UAAU,CAAC,CAAU;IACnC,OAAO,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAe,EAAE,MAAkB,EAAE,QAAiB;IAClF,MAAM,IAAI,GAAG,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,yBAAyB,CAAC,CAAC;IACvE,MAAM,QAAQ,GAAa;QACzB,OAAO,EAAE,CAAC;QACV,gBAAgB,EAAE,iBAAiB;QACnC,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,YAAY,EAAE,aAAa;QAC3B,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,WAAW,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC;KAC7C,CAAC;IACF,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAC9D,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,QAAgB;IAC3C,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,SAAS,CAAC;IAC5C,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAa,CAAC;IAChE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,4BAA4B,QAAQ,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC/G,CAAC;AACH,CAAC;AAQD,MAAM,UAAU,YAAY,CAC1B,QAAkB,EAClB,OAAmB;IAEnB,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC;IAC9D,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IAEnD,MAAM,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrF,MAAM,YAAY,GAAG,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7E,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC;IAElD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC;AACnD,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { ShipguardConfig } from "./types.js";
2
+ export declare function findConfigFile(rootDir: string): string | undefined;
3
+ export declare function loadConfigIfExists(rootDir: string): ShipguardConfig | undefined;
4
+ export declare const DEFAULT_CONFIG: ShipguardConfig;
5
+ export declare function writeDefaultConfig(rootDir: string, opts: {
6
+ force?: boolean;
7
+ }): void;
8
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/engine/config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAQlD,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAMlE;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAc/E;AAED,eAAO,MAAM,cAAc,EAAE,eA+C5B,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAoDnF"}
@@ -0,0 +1,130 @@
1
+ import path from "node:path";
2
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
3
+ const CONFIG_FILES = [
4
+ "shipguard.config.ts",
5
+ "shipguard.config.js",
6
+ "shipguard.config.json",
7
+ ];
8
+ export function findConfigFile(rootDir) {
9
+ for (const name of CONFIG_FILES) {
10
+ const abs = path.join(rootDir, name);
11
+ if (existsSync(abs))
12
+ return abs;
13
+ }
14
+ return undefined;
15
+ }
16
+ export function loadConfigIfExists(rootDir) {
17
+ const file = findConfigFile(rootDir);
18
+ if (!file)
19
+ return undefined;
20
+ if (file.endsWith(".json")) {
21
+ try {
22
+ return JSON.parse(readFileSync(file, "utf8"));
23
+ }
24
+ catch (err) {
25
+ throw new Error(`Failed to parse ${file}: ${err instanceof Error ? err.message : String(err)}`);
26
+ }
27
+ }
28
+ // TS/JS config requires a loader (tsx, jiti) — not yet supported.
29
+ return undefined;
30
+ }
31
+ export const DEFAULT_CONFIG = {
32
+ framework: "next-app-router",
33
+ include: ["app/**", "src/**"],
34
+ exclude: ["**/*.test.*", "**/*.spec.*", "**/node_modules/**"],
35
+ ci: {
36
+ failOn: "critical",
37
+ minConfidence: "high",
38
+ minScore: 70,
39
+ maxNewCritical: 0,
40
+ },
41
+ scoring: {
42
+ start: 100,
43
+ penalties: { critical: 25, high: 10, med: 3, low: 1 },
44
+ },
45
+ hints: {
46
+ auth: {
47
+ functions: [
48
+ "auth", "getServerSession", "getSession", "currentUser",
49
+ "requireUser", "requireAuth",
50
+ "withAuth", // NextAuth v4 / WorkOS
51
+ "getKindeServerSession", // Kinde
52
+ "validateRequest", // Lucia
53
+ "getIronSession", // iron-session
54
+ "withApiAuthRequired", // Auth0
55
+ "verifyIdToken", // Firebase Admin
56
+ "getTokens", // next-firebase-auth-edge
57
+ ],
58
+ middlewareFiles: ["middleware.ts"],
59
+ allowlistPaths: [],
60
+ },
61
+ rateLimit: {
62
+ wrappers: [
63
+ "rateLimit", "withRateLimit", "ratelimit", "limit",
64
+ "checkRateLimitAndThrowError", "ratelimitOrThrow", "rateLimitOrThrow",
65
+ ],
66
+ allowlistPaths: [],
67
+ },
68
+ tenancy: {
69
+ orgFieldNames: ["orgId", "tenantId", "workspaceId", "organizationId", "teamId", "accountId"],
70
+ },
71
+ },
72
+ rules: {
73
+ "AUTH-BOUNDARY-MISSING": { severity: "critical" },
74
+ "RATE-LIMIT-MISSING": { severity: "critical" },
75
+ "TENANCY-SCOPE-MISSING": { severity: "critical" },
76
+ },
77
+ waiversFile: "shipguard.waivers.json",
78
+ };
79
+ export function writeDefaultConfig(rootDir, opts) {
80
+ const dest = path.join(rootDir, "shipguard.config.json");
81
+ if (existsSync(dest) && !opts.force) {
82
+ return;
83
+ }
84
+ const config = {
85
+ $schema: "https://shipguard.dev/schema.json",
86
+ framework: "next-app-router",
87
+ include: ["app/**", "src/**"],
88
+ exclude: ["**/*.test.*", "**/*.spec.*"],
89
+ ci: {
90
+ failOn: "critical",
91
+ minConfidence: "high",
92
+ minScore: 70,
93
+ maxNewCritical: 0,
94
+ },
95
+ hints: {
96
+ auth: {
97
+ functions: [
98
+ "auth", "getServerSession", "getSession", "currentUser",
99
+ "requireUser", "requireAuth",
100
+ "withAuth", "getKindeServerSession", "validateRequest",
101
+ "getIronSession", "withApiAuthRequired", "verifyIdToken", "getTokens"
102
+ ],
103
+ middlewareFiles: ["middleware.ts"],
104
+ allowlistPaths: []
105
+ },
106
+ rateLimit: {
107
+ wrappers: [
108
+ "rateLimit", "withRateLimit", "limit",
109
+ "checkRateLimitAndThrowError", "ratelimitOrThrow", "rateLimitOrThrow"
110
+ ],
111
+ allowlistPaths: []
112
+ },
113
+ tenancy: {
114
+ orgFieldNames: ["orgId", "tenantId", "workspaceId", "organizationId", "teamId", "accountId"]
115
+ },
116
+ },
117
+ rules: {
118
+ "AUTH-BOUNDARY-MISSING": { severity: "critical" },
119
+ "RATE-LIMIT-MISSING": { severity: "critical" },
120
+ "TENANCY-SCOPE-MISSING": { severity: "critical" },
121
+ },
122
+ scoring: {
123
+ start: 100,
124
+ penalties: { critical: 25, high: 10, med: 3, low: 1 },
125
+ },
126
+ waiversFile: "shipguard.waivers.json",
127
+ };
128
+ writeFileSync(dest, JSON.stringify(config, null, 2) + "\n");
129
+ }
130
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/engine/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { ShipguardConfig } from "../types.js";
2
+ /**
3
+ * Attempts to load the governance module if a license key is present.
4
+ * Soft-fails: OSS core runs fine without governance installed.
5
+ *
6
+ * NOTE: Not wired into run.ts yet. Will be integrated when governance
7
+ * module is built. The extension types and registry are reserved now
8
+ * so the boundary is defined.
9
+ */
10
+ export declare function loadGovernanceIfPresent(config: ShipguardConfig): Promise<void>;
11
+ //# sourceMappingURL=load.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../../../src/engine/extensions/load.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD;;;;;;;GAOG;AACH,wBAAsB,uBAAuB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAcpF"}
@@ -0,0 +1,26 @@
1
+ import { registerExtension } from "./registry.js";
2
+ /**
3
+ * Attempts to load the governance module if a license key is present.
4
+ * Soft-fails: OSS core runs fine without governance installed.
5
+ *
6
+ * NOTE: Not wired into run.ts yet. Will be integrated when governance
7
+ * module is built. The extension types and registry are reserved now
8
+ * so the boundary is defined.
9
+ */
10
+ export async function loadGovernanceIfPresent(config) {
11
+ if (!config.license?.key)
12
+ return;
13
+ try {
14
+ // @ts-expect-error — governance module is optional; not installed in OSS
15
+ const mod = await import("@shipguard/governance");
16
+ if (typeof mod.registerGovernance === "function") {
17
+ mod.registerGovernance({
18
+ registerExtension,
19
+ });
20
+ }
21
+ }
22
+ catch {
23
+ // Governance not installed — this is fine for OSS usage.
24
+ }
25
+ }
26
+ //# sourceMappingURL=load.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load.js","sourceRoot":"","sources":["../../../src/engine/extensions/load.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAGlD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,MAAuB;IACnE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,GAAG;QAAE,OAAO;IAEjC,IAAI,CAAC;QACH,yEAAyE;QACzE,MAAM,GAAG,GAA4B,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAC;QAC3E,IAAI,OAAO,GAAG,CAAC,kBAAkB,KAAK,UAAU,EAAE,CAAC;YAChD,GAAG,CAAC,kBAAqF,CAAC;gBACzF,iBAAiB;aAClB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,yDAAyD;IAC3D,CAAC;AACH,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { ShipguardExtension } from "./types.js";
2
+ export declare function registerExtension(ext: ShipguardExtension): void;
3
+ export declare function getExtensions(): readonly ShipguardExtension[];
4
+ export declare function clearExtensions(): void;
5
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/engine/extensions/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAIrD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,kBAAkB,GAAG,IAAI,CAE/D;AAED,wBAAgB,aAAa,IAAI,SAAS,kBAAkB,EAAE,CAE7D;AAED,wBAAgB,eAAe,IAAI,IAAI,CAEtC"}
@@ -0,0 +1,11 @@
1
+ const extensions = [];
2
+ export function registerExtension(ext) {
3
+ extensions.push(ext);
4
+ }
5
+ export function getExtensions() {
6
+ return extensions;
7
+ }
8
+ export function clearExtensions() {
9
+ extensions.length = 0;
10
+ }
11
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/engine/extensions/registry.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,GAAyB,EAAE,CAAC;AAE5C,MAAM,UAAU,iBAAiB,CAAC,GAAuB;IACvD,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;AACxB,CAAC"}
@@ -0,0 +1,51 @@
1
+ import type { Finding, ScanResult, ShipguardConfig } from "../types.js";
2
+ export type ExtensionId = string;
3
+ export type GateResult = {
4
+ ok: true;
5
+ } | {
6
+ ok: false;
7
+ exitCode: number;
8
+ message: string;
9
+ details?: unknown;
10
+ };
11
+ export interface RunContext {
12
+ rootDir: string;
13
+ mode: "scan" | "ci" | "init";
14
+ }
15
+ export interface ExtensionHooks {
16
+ /** Called after config is loaded. Can validate config or gate. */
17
+ onConfigLoaded?: (args: {
18
+ config: ShipguardConfig;
19
+ ctx: RunContext;
20
+ }) => GateResult | void;
21
+ /** Called after analysis, before scoring. Can mutate findings or gate. */
22
+ onFindings?: (args: {
23
+ config: ShipguardConfig;
24
+ ctx: RunContext;
25
+ findings: Finding[];
26
+ }) => GateResult | void;
27
+ /** Called after scoring. Useful for policy gates. */
28
+ onScored?: (args: {
29
+ config: ShipguardConfig;
30
+ ctx: RunContext;
31
+ score: number;
32
+ findings: Finding[];
33
+ }) => GateResult | void;
34
+ /** Called before writing outputs. Can attach extra report sections. */
35
+ onReport?: (args: {
36
+ config: ShipguardConfig;
37
+ ctx: RunContext;
38
+ result: ScanResult;
39
+ }) => GateResult | void;
40
+ /** Called during `shipguard init`. Can add setup messages. */
41
+ onInit?: (args: {
42
+ config: ShipguardConfig;
43
+ ctx: RunContext;
44
+ messages: string[];
45
+ }) => void;
46
+ }
47
+ export interface ShipguardExtension {
48
+ id: ExtensionId;
49
+ hooks: ExtensionHooks;
50
+ }
51
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/engine/extensions/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAExE,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC;AAEjC,MAAM,MAAM,UAAU,GAClB;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GACZ;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAExE,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,cAAc;IAC7B,kEAAkE;IAClE,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE;QACtB,MAAM,EAAE,eAAe,CAAC;QACxB,GAAG,EAAE,UAAU,CAAC;KACjB,KAAK,UAAU,GAAG,IAAI,CAAC;IAExB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE;QAClB,MAAM,EAAE,eAAe,CAAC;QACxB,GAAG,EAAE,UAAU,CAAC;QAChB,QAAQ,EAAE,OAAO,EAAE,CAAC;KACrB,KAAK,UAAU,GAAG,IAAI,CAAC;IAExB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE;QAChB,MAAM,EAAE,eAAe,CAAC;QACxB,GAAG,EAAE,UAAU,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,OAAO,EAAE,CAAC;KACrB,KAAK,UAAU,GAAG,IAAI,CAAC;IAExB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE;QAChB,MAAM,EAAE,eAAe,CAAC;QACxB,GAAG,EAAE,UAAU,CAAC;QAChB,MAAM,EAAE,UAAU,CAAC;KACpB,KAAK,UAAU,GAAG,IAAI,CAAC;IAExB,8DAA8D;IAC9D,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE;QACd,MAAM,EAAE,eAAe,CAAC;QACxB,GAAG,EAAE,UAAU,CAAC;QAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB,KAAK,IAAI,CAAC;CACZ;AAED,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,WAAW,CAAC;IAChB,KAAK,EAAE,cAAc,CAAC;CACvB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/engine/extensions/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,5 @@
1
+ import type { ScanResult } from "./types.js";
2
+ import type { BaselineDiff } from "./baseline.js";
3
+ export declare function formatPretty(result: ScanResult, diff?: BaselineDiff): string;
4
+ export declare function formatJson(result: ScanResult): string;
5
+ //# sourceMappingURL=report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/engine/report.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAW,MAAM,YAAY,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAGlD,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,MAAM,CAgF5E;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAErD"}
@@ -0,0 +1,88 @@
1
+ import pc from "picocolors";
2
+ import { scoreStatus, buildDetectedList } from "./score.js";
3
+ export function formatPretty(result, diff) {
4
+ const lines = [];
5
+ const { score, findings, waivedFindings, summary } = result;
6
+ // Header with detected stack
7
+ const detected = buildDetectedList(result);
8
+ const status = scoreStatus(score);
9
+ const scoreColor = status === "PASS" ? pc.green : status === "WARN" ? pc.yellow : pc.red;
10
+ lines.push("");
11
+ lines.push(` ${pc.bold("Shipguard")} ${pc.dim(result.shipguardVersion)}`);
12
+ lines.push(` ${pc.dim("Detected:")} ${detected.join(" · ")}`);
13
+ lines.push(` ${pc.dim("Score:")} ${scoreColor(String(score))} ${scoreColor(status)}`);
14
+ if (diff) {
15
+ const deltaStr = diff.scoreDelta >= 0 ? `+${diff.scoreDelta}` : `${diff.scoreDelta}`;
16
+ lines.push(` Delta from baseline: ${diff.scoreDelta >= 0 ? pc.green(deltaStr) : pc.red(deltaStr)}`);
17
+ if (diff.newFindings.length > 0) {
18
+ lines.push(` New findings: ${pc.red(String(diff.newFindings.length))}`);
19
+ }
20
+ if (diff.resolvedKeys.length > 0) {
21
+ lines.push(` Resolved: ${pc.green(String(diff.resolvedKeys.length))}`);
22
+ }
23
+ }
24
+ lines.push("");
25
+ // Group by severity
26
+ const grouped = groupBySeverity(findings);
27
+ for (const [severity, items] of Object.entries(grouped)) {
28
+ if (items.length === 0)
29
+ continue;
30
+ const color = severity === "critical" ? pc.red : severity === "high" ? pc.yellow : pc.dim;
31
+ lines.push(` ${color(severity.toUpperCase())} (${items.length})`);
32
+ for (const f of items) {
33
+ const loc = f.line ? `:${f.line}` : "";
34
+ const conf = pc.dim(`(${f.confidence} confidence)`);
35
+ lines.push(` ${f.ruleId} ${conf}`);
36
+ lines.push(` ${pc.dim(f.file + loc)}`);
37
+ if (f.evidence.length > 0) {
38
+ for (const e of f.evidence) {
39
+ lines.push(` - ${e}`);
40
+ }
41
+ }
42
+ lines.push(` ${pc.dim(`Why ${f.confidence}: ${f.confidenceRationale}`)}`);
43
+ }
44
+ lines.push("");
45
+ }
46
+ // Remediation
47
+ const remediations = new Map();
48
+ for (const f of findings) {
49
+ if (!remediations.has(f.ruleId)) {
50
+ remediations.set(f.ruleId, f.remediation);
51
+ }
52
+ }
53
+ if (remediations.size > 0) {
54
+ lines.push(" Suggested fixes:");
55
+ for (const [ruleId, fixes] of remediations) {
56
+ for (const fix of fixes) {
57
+ lines.push(` - ${fix}`);
58
+ }
59
+ }
60
+ lines.push("");
61
+ }
62
+ // Waivers
63
+ if (waivedFindings.length > 0) {
64
+ lines.push(` ${pc.dim(`Waived: ${waivedFindings.length} finding(s)`)}`);
65
+ lines.push("");
66
+ }
67
+ // Tip
68
+ lines.push(pc.dim(" Tip: Use `shipguard waive <RULE> --file <path> --reason \"...\"` to waive known exceptions."));
69
+ lines.push(pc.dim(" Tip: Configure hints in shipguard.config.json to reduce false positives."));
70
+ lines.push("");
71
+ return lines.join("\n");
72
+ }
73
+ export function formatJson(result) {
74
+ return JSON.stringify(result, null, 2);
75
+ }
76
+ function groupBySeverity(findings) {
77
+ const groups = {
78
+ critical: [],
79
+ high: [],
80
+ med: [],
81
+ low: [],
82
+ };
83
+ for (const f of findings) {
84
+ groups[f.severity]?.push(f);
85
+ }
86
+ return groups;
87
+ }
88
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/engine/report.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { ShipguardConfig, ScanResult } from "./types.js";
2
+ export interface RunOptions {
3
+ rootDir: string;
4
+ configOverrides?: Partial<ShipguardConfig>;
5
+ /** Additional exclude globs appended to config excludes (not replacing) */
6
+ additionalExclude?: string[];
7
+ }
8
+ export declare function runScan(opts: RunOptions): Promise<ScanResult>;
9
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/engine/run.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAW,MAAM,YAAY,CAAC;AAQvE,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IAC3C,2EAA2E;IAC3E,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC9B;AAED,wBAAsB,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAoFnE"}