@queno/agent-node 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/README.md +421 -0
  2. package/dist/agent.d.ts +222 -0
  3. package/dist/agent.d.ts.map +1 -0
  4. package/dist/agent.js +591 -0
  5. package/dist/agent.js.map +1 -0
  6. package/dist/api-discovery/discovery-buffer.d.ts +27 -0
  7. package/dist/api-discovery/discovery-buffer.d.ts.map +1 -0
  8. package/dist/api-discovery/discovery-buffer.js +50 -0
  9. package/dist/api-discovery/discovery-buffer.js.map +1 -0
  10. package/dist/api-discovery/endpoint-observer.d.ts +25 -0
  11. package/dist/api-discovery/endpoint-observer.d.ts.map +1 -0
  12. package/dist/api-discovery/endpoint-observer.js +127 -0
  13. package/dist/api-discovery/endpoint-observer.js.map +1 -0
  14. package/dist/api-discovery/route-normalizer.d.ts +15 -0
  15. package/dist/api-discovery/route-normalizer.d.ts.map +1 -0
  16. package/dist/api-discovery/route-normalizer.js +34 -0
  17. package/dist/api-discovery/route-normalizer.js.map +1 -0
  18. package/dist/config.d.ts +100 -0
  19. package/dist/config.d.ts.map +1 -0
  20. package/dist/config.js +101 -0
  21. package/dist/config.js.map +1 -0
  22. package/dist/db-hooks/correlate.d.ts +19 -0
  23. package/dist/db-hooks/correlate.d.ts.map +1 -0
  24. package/dist/db-hooks/correlate.js +45 -0
  25. package/dist/db-hooks/correlate.js.map +1 -0
  26. package/dist/db-hooks/instrument.d.ts +27 -0
  27. package/dist/db-hooks/instrument.d.ts.map +1 -0
  28. package/dist/db-hooks/instrument.js +194 -0
  29. package/dist/db-hooks/instrument.js.map +1 -0
  30. package/dist/detectors/base.d.ts +61 -0
  31. package/dist/detectors/base.d.ts.map +1 -0
  32. package/dist/detectors/base.js +57 -0
  33. package/dist/detectors/base.js.map +1 -0
  34. package/dist/detectors/bola.d.ts +60 -0
  35. package/dist/detectors/bola.d.ts.map +1 -0
  36. package/dist/detectors/bola.js +108 -0
  37. package/dist/detectors/bola.js.map +1 -0
  38. package/dist/detectors/command-injection.d.ts +22 -0
  39. package/dist/detectors/command-injection.d.ts.map +1 -0
  40. package/dist/detectors/command-injection.js +41 -0
  41. package/dist/detectors/command-injection.js.map +1 -0
  42. package/dist/detectors/custom-rule.d.ts +24 -0
  43. package/dist/detectors/custom-rule.d.ts.map +1 -0
  44. package/dist/detectors/custom-rule.js +65 -0
  45. package/dist/detectors/custom-rule.js.map +1 -0
  46. package/dist/detectors/index.d.ts +17 -0
  47. package/dist/detectors/index.d.ts.map +1 -0
  48. package/dist/detectors/index.js +31 -0
  49. package/dist/detectors/index.js.map +1 -0
  50. package/dist/detectors/nosql-injection.d.ts +23 -0
  51. package/dist/detectors/nosql-injection.d.ts.map +1 -0
  52. package/dist/detectors/nosql-injection.js +54 -0
  53. package/dist/detectors/nosql-injection.js.map +1 -0
  54. package/dist/detectors/path-traversal.d.ts +21 -0
  55. package/dist/detectors/path-traversal.d.ts.map +1 -0
  56. package/dist/detectors/path-traversal.js +54 -0
  57. package/dist/detectors/path-traversal.js.map +1 -0
  58. package/dist/detectors/prototype-pollution.d.ts +23 -0
  59. package/dist/detectors/prototype-pollution.d.ts.map +1 -0
  60. package/dist/detectors/prototype-pollution.js +50 -0
  61. package/dist/detectors/prototype-pollution.js.map +1 -0
  62. package/dist/detectors/sql-injection.d.ts +22 -0
  63. package/dist/detectors/sql-injection.d.ts.map +1 -0
  64. package/dist/detectors/sql-injection.js +42 -0
  65. package/dist/detectors/sql-injection.js.map +1 -0
  66. package/dist/detectors/ssrf.d.ts +26 -0
  67. package/dist/detectors/ssrf.d.ts.map +1 -0
  68. package/dist/detectors/ssrf.js +37 -0
  69. package/dist/detectors/ssrf.js.map +1 -0
  70. package/dist/detectors/suspicious-headers.d.ts +25 -0
  71. package/dist/detectors/suspicious-headers.d.ts.map +1 -0
  72. package/dist/detectors/suspicious-headers.js +87 -0
  73. package/dist/detectors/suspicious-headers.js.map +1 -0
  74. package/dist/detectors/template-injection.d.ts +27 -0
  75. package/dist/detectors/template-injection.d.ts.map +1 -0
  76. package/dist/detectors/template-injection.js +35 -0
  77. package/dist/detectors/template-injection.js.map +1 -0
  78. package/dist/detectors/xss.d.ts +22 -0
  79. package/dist/detectors/xss.d.ts.map +1 -0
  80. package/dist/detectors/xss.js +38 -0
  81. package/dist/detectors/xss.js.map +1 -0
  82. package/dist/index.d.ts +28 -0
  83. package/dist/index.d.ts.map +1 -0
  84. package/dist/index.js +24 -0
  85. package/dist/index.js.map +1 -0
  86. package/dist/integrations/express.d.ts +39 -0
  87. package/dist/integrations/express.d.ts.map +1 -0
  88. package/dist/integrations/express.js +62 -0
  89. package/dist/integrations/express.js.map +1 -0
  90. package/dist/integrations/fastify.d.ts +33 -0
  91. package/dist/integrations/fastify.d.ts.map +1 -0
  92. package/dist/integrations/fastify.js +63 -0
  93. package/dist/integrations/fastify.js.map +1 -0
  94. package/dist/integrations/nestjs.d.ts +40 -0
  95. package/dist/integrations/nestjs.d.ts.map +1 -0
  96. package/dist/integrations/nestjs.js +58 -0
  97. package/dist/integrations/nestjs.js.map +1 -0
  98. package/dist/policy/canonical.d.ts +23 -0
  99. package/dist/policy/canonical.d.ts.map +1 -0
  100. package/dist/policy/canonical.js +40 -0
  101. package/dist/policy/canonical.js.map +1 -0
  102. package/dist/policy/policy-manager.d.ts +43 -0
  103. package/dist/policy/policy-manager.d.ts.map +1 -0
  104. package/dist/policy/policy-manager.js +89 -0
  105. package/dist/policy/policy-manager.js.map +1 -0
  106. package/dist/policy/types.d.ts +70 -0
  107. package/dist/policy/types.d.ts.map +1 -0
  108. package/dist/policy/types.js +2 -0
  109. package/dist/policy/types.js.map +1 -0
  110. package/dist/policy/verify.d.ts +11 -0
  111. package/dist/policy/verify.d.ts.map +1 -0
  112. package/dist/policy/verify.js +61 -0
  113. package/dist/policy/verify.js.map +1 -0
  114. package/dist/redaction/audit-log.d.ts +40 -0
  115. package/dist/redaction/audit-log.d.ts.map +1 -0
  116. package/dist/redaction/audit-log.js +110 -0
  117. package/dist/redaction/audit-log.js.map +1 -0
  118. package/dist/redaction/engine.d.ts +50 -0
  119. package/dist/redaction/engine.d.ts.map +1 -0
  120. package/dist/redaction/engine.js +143 -0
  121. package/dist/redaction/engine.js.map +1 -0
  122. package/dist/redaction/patterns.d.ts +24 -0
  123. package/dist/redaction/patterns.d.ts.map +1 -0
  124. package/dist/redaction/patterns.js +142 -0
  125. package/dist/redaction/patterns.js.map +1 -0
  126. package/dist/runtime-context.d.ts +33 -0
  127. package/dist/runtime-context.d.ts.map +1 -0
  128. package/dist/runtime-context.js +46 -0
  129. package/dist/runtime-context.js.map +1 -0
  130. package/dist/self-protect.d.ts +34 -0
  131. package/dist/self-protect.d.ts.map +1 -0
  132. package/dist/self-protect.js +134 -0
  133. package/dist/self-protect.js.map +1 -0
  134. package/dist/transport/buffer.d.ts +52 -0
  135. package/dist/transport/buffer.d.ts.map +1 -0
  136. package/dist/transport/buffer.js +57 -0
  137. package/dist/transport/buffer.js.map +1 -0
  138. package/dist/transport/client.d.ts +77 -0
  139. package/dist/transport/client.d.ts.map +1 -0
  140. package/dist/transport/client.js +178 -0
  141. package/dist/transport/client.js.map +1 -0
  142. package/dist/transport/heartbeat.d.ts +86 -0
  143. package/dist/transport/heartbeat.d.ts.map +1 -0
  144. package/dist/transport/heartbeat.js +110 -0
  145. package/dist/transport/heartbeat.js.map +1 -0
  146. package/dist/transport/secure-request.d.ts +30 -0
  147. package/dist/transport/secure-request.d.ts.map +1 -0
  148. package/dist/transport/secure-request.js +95 -0
  149. package/dist/transport/secure-request.js.map +1 -0
  150. package/dist/types.d.ts +311 -0
  151. package/dist/types.d.ts.map +1 -0
  152. package/dist/types.js +12 -0
  153. package/dist/types.js.map +1 -0
  154. package/package.json +60 -0
@@ -0,0 +1,87 @@
1
+ /** Threshold above which a single header value is treated as suspicious. */
2
+ const MAX_HEADER_VALUE_LENGTH = 8192;
3
+ /** Threshold above which the header count is treated as suspicious. */
4
+ const MAX_HEADERS_COUNT = 100;
5
+ /**
6
+ * Characters allowed in a legal `Host` header. Anything outside this set
7
+ * triggers a host-header-injection finding.
8
+ */
9
+ const HOST_INJECTION_PATTERN = /[^a-zA-Z0-9\-._:\[\]]/;
10
+ export class SuspiciousHeadersDetector {
11
+ name = "suspicious-headers";
12
+ detect(req) {
13
+ const headers = req.headers;
14
+ const entries = Object.entries(headers);
15
+ if (entries.length > MAX_HEADERS_COUNT) {
16
+ return {
17
+ detectorName: this.name,
18
+ eventType: "suspicious_headers",
19
+ severity: "medium",
20
+ description: `Abnormal header count: ${entries.length}`,
21
+ location: "headers",
22
+ };
23
+ }
24
+ for (const [name, value] of entries) {
25
+ const v = Array.isArray(value) ? value.join(", ") : value ?? "";
26
+ if (v.length > MAX_HEADER_VALUE_LENGTH) {
27
+ return {
28
+ detectorName: this.name,
29
+ eventType: "suspicious_headers",
30
+ severity: "medium",
31
+ description: `Oversized header value for '${name}' (${v.length} bytes)`,
32
+ location: `header:${name}`,
33
+ };
34
+ }
35
+ if (name.toLowerCase() === "host" && HOST_INJECTION_PATTERN.test(v)) {
36
+ return {
37
+ detectorName: this.name,
38
+ eventType: "host_header_injection",
39
+ severity: "medium",
40
+ description: "Suspicious characters in Host header",
41
+ matchedValue: v.slice(0, 200),
42
+ location: "header:host",
43
+ };
44
+ }
45
+ if (name.toLowerCase() === "x-forwarded-for") {
46
+ const ips = v.split(",").map((s) => s.trim());
47
+ for (const ip of ips) {
48
+ if (isPrivateIp(ip)) {
49
+ return {
50
+ detectorName: this.name,
51
+ eventType: "suspicious_headers",
52
+ severity: "medium",
53
+ description: "Private IP injected in X-Forwarded-For header",
54
+ matchedValue: ip,
55
+ location: "header:x-forwarded-for",
56
+ };
57
+ }
58
+ }
59
+ }
60
+ if (/[\r\n]/.test(v)) {
61
+ return {
62
+ detectorName: this.name,
63
+ eventType: "header_injection",
64
+ severity: "high",
65
+ description: `Newline injection detected in header '${name}'`,
66
+ matchedValue: v.slice(0, 200),
67
+ location: `header:${name}`,
68
+ };
69
+ }
70
+ }
71
+ return null;
72
+ }
73
+ }
74
+ /**
75
+ * True iff `ip` belongs to a loopback or RFC1918 private range.
76
+ *
77
+ * Used only to flag client-supplied `X-Forwarded-For` values pretending to
78
+ * originate from a trusted internal host.
79
+ */
80
+ function isPrivateIp(ip) {
81
+ return (/^127\./.test(ip) ||
82
+ /^10\./.test(ip) ||
83
+ /^192\.168\./.test(ip) ||
84
+ /^172\.(1[6-9]|2\d|3[01])\./.test(ip) ||
85
+ ip === "::1");
86
+ }
87
+ //# sourceMappingURL=suspicious-headers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suspicious-headers.js","sourceRoot":"","sources":["../../src/detectors/suspicious-headers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Server-Side Template Injection (SSTI) signature detector.
3
+ *
4
+ * Looks for the canonical delimiter shapes of popular server-side template
5
+ * engines:
6
+ * - `{{ … }}` / `{% … %}` - Twig, Jinja2, Nunjucks, Pebble.
7
+ * - `<% … %>` - ERB, EJS.
8
+ * - `{{{ … }}}` - Handlebars triple-stache.
9
+ * - `${ … }` - Thymeleaf (and JSP EL).
10
+ * - `#{ … }` - Velocity.
11
+ * - `<#… >` - Freemarker.
12
+ *
13
+ * Also matches the classic `7*7` math probe in each delimiter style - a
14
+ * cheap, very high-signal indicator.
15
+ *
16
+ * Severity: `high`.
17
+ *
18
+ * Known limits: applications that legitimately echo back template-like
19
+ * strings (CMS editors, code paste forms) may produce false positives.
20
+ */
21
+ import type { Detector } from "./base.js";
22
+ import type { DetectionResult, NormalizedRequest } from "../types.js";
23
+ export declare class TemplateInjectionDetector implements Detector {
24
+ readonly name = "template-injection";
25
+ detect(req: NormalizedRequest): DetectionResult | null;
26
+ }
27
+ //# sourceMappingURL=template-injection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-injection.d.ts","sourceRoot":"","sources":["../../src/detectors/template-injection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE1C,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAetE,qBAAa,yBAA0B,YAAW,QAAQ;IACxD,QAAQ,CAAC,IAAI,wBAAwB;IAErC,MAAM,CAAC,GAAG,EAAE,iBAAiB,GAAG,eAAe,GAAG,IAAI;CAmBvD"}
@@ -0,0 +1,35 @@
1
+ import { flattenValues } from "./base.js";
2
+ const SSTI_PATTERNS = [
3
+ /\{\{.*\}\}/s,
4
+ /\{%.*%\}/s,
5
+ /<%[=\-]?.*%>/s,
6
+ /\{\{\{.*\}\}\}/s,
7
+ /\$\{.*\}/s,
8
+ /#\{.*\}/s,
9
+ /<#.*>/s,
10
+ /\$\{7\s*\*\s*7\}/,
11
+ /\{\{7\s*\*\s*7\}\}/,
12
+ /<%=\s*7\s*\*\s*7\s*%>/,
13
+ ];
14
+ export class TemplateInjectionDetector {
15
+ name = "template-injection";
16
+ detect(req) {
17
+ const values = [...flattenValues(req.query), ...flattenValues(req.body)];
18
+ for (const val of values) {
19
+ for (const pattern of SSTI_PATTERNS) {
20
+ if (pattern.test(val)) {
21
+ return {
22
+ detectorName: this.name,
23
+ eventType: "template_injection",
24
+ severity: "high",
25
+ description: "Server-side template injection (SSTI) pattern detected",
26
+ matchedValue: val.slice(0, 200),
27
+ location: "query/body",
28
+ };
29
+ }
30
+ }
31
+ }
32
+ return null;
33
+ }
34
+ }
35
+ //# sourceMappingURL=template-injection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-injection.js","sourceRoot":"","sources":["../../src/detectors/template-injection.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1C,MAAM,aAAa,GAAG;IACpB,aAAa;IACb,WAAW;IACX,eAAe;IACf,iBAAiB;IACjB,WAAW;IACX,UAAU;IACV,QAAQ;IACR,kBAAkB;IAClB,oBAAoB;IACpB,uBAAuB;CACxB,CAAC;AAEF,MAAM,OAAO,yBAAyB;IAC3B,IAAI,GAAG,oBAAoB,CAAC;IAErC,MAAM,CAAC,GAAsB;QAC3B,MAAM,MAAM,GAAG,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;QAEzE,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;YACzB,KAAK,MAAM,OAAO,IAAI,aAAa,EAAE,CAAC;gBACpC,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;oBACtB,OAAO;wBACL,YAAY,EAAE,IAAI,CAAC,IAAI;wBACvB,SAAS,EAAE,oBAAoB;wBAC/B,QAAQ,EAAE,MAAM;wBAChB,WAAW,EAAE,wDAAwD;wBACrE,YAAY,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;wBAC/B,QAAQ,EAAE,YAAY;qBACvB,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Cross-Site Scripting (XSS) signature detector.
3
+ *
4
+ * Scans `query` and `body` values for the most common reflected/stored XSS
5
+ * payload shapes: `<script>`, `javascript:` URLs, inline event handlers,
6
+ * `<iframe>`, `<svg onload=…>`, IE `expression(…)`, and the canonical
7
+ * `<img src=x onerror=…>` probe.
8
+ *
9
+ * Severity: `high`.
10
+ *
11
+ * Known limits: signature-based, no HTML parser - an attacker who breaks the
12
+ * payload across multiple parameters or uses very unusual encoding may evade
13
+ * detection. The request `path` is not scanned to limit false positives on
14
+ * legitimate URLs containing the substring `script`.
15
+ */
16
+ import type { Detector } from "./base.js";
17
+ import type { DetectionResult, NormalizedRequest } from "../types.js";
18
+ export declare class XssDetector implements Detector {
19
+ readonly name = "xss";
20
+ detect(req: NormalizedRequest): DetectionResult | null;
21
+ }
22
+ //# sourceMappingURL=xss.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xss.d.ts","sourceRoot":"","sources":["../../src/detectors/xss.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE1C,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAetE,qBAAa,WAAY,YAAW,QAAQ;IAC1C,QAAQ,CAAC,IAAI,SAAS;IAEtB,MAAM,CAAC,GAAG,EAAE,iBAAiB,GAAG,eAAe,GAAG,IAAI;CAsBvD"}
@@ -0,0 +1,38 @@
1
+ import { flattenValues } from "./base.js";
2
+ const XSS_PATTERNS = [
3
+ /<script[\s>]/i,
4
+ /<\/script>/i,
5
+ /javascript\s*:/i,
6
+ /data\s*:\s*text\/html/i,
7
+ /on\w+\s*=\s*["']?[^"'>]*(alert|confirm|prompt|eval|fetch|document|window)/i,
8
+ /<iframe[\s>]/i,
9
+ /<svg[\s>].*?on\w+/is,
10
+ /expression\s*\(/i,
11
+ /vbscript\s*:/i,
12
+ /<img[^>]+src\s*=\s*["']?\s*x[^>]*onerror/i,
13
+ ];
14
+ export class XssDetector {
15
+ name = "xss";
16
+ detect(req) {
17
+ const values = [
18
+ ...flattenValues(req.query),
19
+ ...flattenValues(req.body),
20
+ ];
21
+ for (const val of values) {
22
+ for (const pattern of XSS_PATTERNS) {
23
+ if (pattern.test(val)) {
24
+ return {
25
+ detectorName: this.name,
26
+ eventType: "xss",
27
+ severity: "high",
28
+ description: "Cross-site scripting (XSS) pattern detected",
29
+ matchedValue: val.slice(0, 200),
30
+ location: "query/body",
31
+ };
32
+ }
33
+ }
34
+ }
35
+ return null;
36
+ }
37
+ }
38
+ //# sourceMappingURL=xss.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xss.js","sourceRoot":"","sources":["../../src/detectors/xss.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1C,MAAM,YAAY,GAAG;IACnB,eAAe;IACf,aAAa;IACb,iBAAiB;IACjB,wBAAwB;IACxB,4EAA4E;IAC5E,eAAe;IACf,qBAAqB;IACrB,kBAAkB;IAClB,eAAe;IACf,2CAA2C;CAC5C,CAAC;AAEF,MAAM,OAAO,WAAW;IACb,IAAI,GAAG,KAAK,CAAC;IAEtB,MAAM,CAAC,GAAsB;QAC3B,MAAM,MAAM,GAAG;YACb,GAAG,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC;YAC3B,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC;SAC3B,CAAC;QAEF,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;YACzB,KAAK,MAAM,OAAO,IAAI,YAAY,EAAE,CAAC;gBACnC,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;oBACtB,OAAO;wBACL,YAAY,EAAE,IAAI,CAAC,IAAI;wBACvB,SAAS,EAAE,KAAK;wBAChB,QAAQ,EAAE,MAAM;wBAChB,WAAW,EAAE,6CAA6C;wBAC1D,YAAY,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;wBAC/B,QAAQ,EAAE,YAAY;qBACvB,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Public entry point for `@queno/agent-node`.
3
+ *
4
+ * Re-exports the runtime surface that customer applications are expected to
5
+ * consume:
6
+ * - {@link RaspAgent} - the agent lifecycle object (start, stop, inspect).
7
+ * - {@link validateConfig} - Zod-backed config validator (throws on bad input).
8
+ * - Framework integrations: Express middleware, Fastify plugin, NestJS middleware.
9
+ * - Public types describing config, requests, detections, events and heartbeats.
10
+ * - The {@link Detector} contract and {@link createDefaultDetectors} factory so
11
+ * integrators can extend or replace the bundled detector set.
12
+ *
13
+ * Nothing else in `src/` is part of the supported API.
14
+ */
15
+ export { RaspAgent } from "./agent.js";
16
+ export { validateConfig } from "./config.js";
17
+ export { createExpressMiddleware } from "./integrations/express.js";
18
+ export { createFastifyPlugin } from "./integrations/fastify.js";
19
+ export { createNestMiddleware } from "./integrations/nestjs.js";
20
+ export type { RaspConfig, NormalizedRequest, DetectionResult, EventPayload, HeartbeatPayload, HeartbeatResponse, DiscoveryEntry, DiscoveryPayload, AuthStatus, Severity, AgentMode, AgentStatus, } from "./types.js";
21
+ export type { Detector } from "./detectors/index.js";
22
+ export { createDefaultDetectors } from "./detectors/index.js";
23
+ export { CustomRuleDetector } from "./detectors/custom-rule.js";
24
+ export { instrumentDatabaseDrivers, instrumentPrismaClient, verifyHookIntegrity, } from "./db-hooks/instrument.js";
25
+ export { SecureStore, startSelfProtection, detectDebugger, } from "./self-protect.js";
26
+ export type { SelfProtectionOptions } from "./self-protect.js";
27
+ export type { DistributedPolicy, CustomRuleSpec, RedactionConfig, DataResidencyConfig, IpRedactionMode, } from "./policy/types.js";
28
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAEhE,YAAY,EACV,UAAU,EACV,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,UAAU,EACV,QAAQ,EACR,SAAS,EACT,WAAW,GACZ,MAAM,YAAY,CAAC;AAEpB,YAAY,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EACL,yBAAyB,EACzB,sBAAsB,EACtB,mBAAmB,GACpB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EACL,WAAW,EACX,mBAAmB,EACnB,cAAc,GACf,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAE/D,YAAY,EACV,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,eAAe,GAChB,MAAM,mBAAmB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Public entry point for `@queno/agent-node`.
3
+ *
4
+ * Re-exports the runtime surface that customer applications are expected to
5
+ * consume:
6
+ * - {@link RaspAgent} - the agent lifecycle object (start, stop, inspect).
7
+ * - {@link validateConfig} - Zod-backed config validator (throws on bad input).
8
+ * - Framework integrations: Express middleware, Fastify plugin, NestJS middleware.
9
+ * - Public types describing config, requests, detections, events and heartbeats.
10
+ * - The {@link Detector} contract and {@link createDefaultDetectors} factory so
11
+ * integrators can extend or replace the bundled detector set.
12
+ *
13
+ * Nothing else in `src/` is part of the supported API.
14
+ */
15
+ export { RaspAgent } from "./agent.js";
16
+ export { validateConfig } from "./config.js";
17
+ export { createExpressMiddleware } from "./integrations/express.js";
18
+ export { createFastifyPlugin } from "./integrations/fastify.js";
19
+ export { createNestMiddleware } from "./integrations/nestjs.js";
20
+ export { createDefaultDetectors } from "./detectors/index.js";
21
+ export { CustomRuleDetector } from "./detectors/custom-rule.js";
22
+ export { instrumentDatabaseDrivers, instrumentPrismaClient, verifyHookIntegrity, } from "./db-hooks/instrument.js";
23
+ export { SecureStore, startSelfProtection, detectDebugger, } from "./self-protect.js";
24
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAkBhE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EACL,yBAAyB,EACzB,sBAAsB,EACtB,mBAAmB,GACpB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EACL,WAAW,EACX,mBAAmB,EACnB,cAAc,GACf,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Express integration.
3
+ *
4
+ * Exposes {@link createExpressMiddleware}, a factory that returns a standard
5
+ * `(req, res, next)` middleware bound to a {@link RaspAgent} instance.
6
+ *
7
+ * Behaviour:
8
+ * - Every request is normalised into a {@link NormalizedRequest} and run
9
+ * through `agent.inspect`.
10
+ * - In `monitor` mode the request always passes through, even on detection.
11
+ * - In `block` mode a detected request is short-circuited with `403`
12
+ * `{ error: "Request blocked by RASP", eventType }`.
13
+ * - Any thrown error inside the middleware is swallowed so the agent never
14
+ * takes down the host application (fail-open).
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * import express from "express";
19
+ * import { RaspAgent, createExpressMiddleware } from "@queno/agent-node";
20
+ *
21
+ * const agent = new RaspAgent({ apiKey, projectId, agentId, mode: "monitor" });
22
+ * agent.start();
23
+ *
24
+ * const app = express();
25
+ * app.use(express.json());
26
+ * app.use(createExpressMiddleware(agent));
27
+ * ```
28
+ */
29
+ import type { Request, Response, NextFunction } from "express";
30
+ import type { RaspAgent } from "../agent.js";
31
+ /**
32
+ * Build an Express middleware bound to a {@link RaspAgent}.
33
+ *
34
+ * The middleware must be registered **after** body parsing
35
+ * (`express.json()`, `express.urlencoded()`) so `req.body` is populated
36
+ * when detectors run.
37
+ */
38
+ export declare function createExpressMiddleware(agent: RaspAgent): (req: Request, res: Response, next: NextFunction) => void;
39
+ //# sourceMappingURL=express.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../src/integrations/express.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAG7C;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,SAAS,IACvB,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,KAAG,IAAI,CAwCtF"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Build an Express middleware bound to a {@link RaspAgent}.
3
+ *
4
+ * The middleware must be registered **after** body parsing
5
+ * (`express.json()`, `express.urlencoded()`) so `req.body` is populated
6
+ * when detectors run.
7
+ */
8
+ export function createExpressMiddleware(agent) {
9
+ return function raspMiddleware(req, res, next) {
10
+ try {
11
+ const normalized = {
12
+ method: req.method,
13
+ path: req.path,
14
+ query: req.query,
15
+ headers: req.headers,
16
+ body: req.body,
17
+ sourceIp: extractSourceIp(req),
18
+ };
19
+ // Bind a runtime context (DB correlation) before the handler runs.
20
+ const ctx = agent.beginRequest(normalized);
21
+ const detection = agent.inspect(normalized);
22
+ if (detection && agent.mode === "block") {
23
+ res.status(403).json({
24
+ error: "Request blocked by RASP",
25
+ eventType: detection.eventType,
26
+ });
27
+ return;
28
+ }
29
+ // Response-phase observation for traffic profiling + auth confirmation.
30
+ const start = Date.now();
31
+ res.on("finish", () => {
32
+ const r = req;
33
+ agent.endRequest(ctx, normalized, {
34
+ statusCode: res.statusCode,
35
+ durationMs: Date.now() - start,
36
+ authenticated: r.user != null || r.auth != null,
37
+ });
38
+ });
39
+ }
40
+ catch {
41
+ // Fail-open - see file-level note.
42
+ }
43
+ next();
44
+ };
45
+ }
46
+ /**
47
+ * Best-effort source IP resolution:
48
+ * 1. First entry of `X-Forwarded-For`, when present (string or array).
49
+ * 2. Fallback to `req.socket.remoteAddress`.
50
+ *
51
+ * No trust validation is performed - operators relying on `X-Forwarded-For`
52
+ * must terminate it at a known proxy.
53
+ */
54
+ function extractSourceIp(req) {
55
+ const forwarded = req.headers["x-forwarded-for"];
56
+ if (typeof forwarded === "string")
57
+ return forwarded.split(",")[0]?.trim();
58
+ if (Array.isArray(forwarded))
59
+ return forwarded[0]?.split(",")[0]?.trim();
60
+ return req.socket?.remoteAddress;
61
+ }
62
+ //# sourceMappingURL=express.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"express.js","sourceRoot":"","sources":["../../src/integrations/express.ts"],"names":[],"mappings":"AAgCA;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAgB;IACtD,OAAO,SAAS,cAAc,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB;QAC5E,IAAI,CAAC;YACH,MAAM,UAAU,GAAsB;gBACpC,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,KAAK,EAAE,GAAG,CAAC,KAAgC;gBAC3C,OAAO,EAAE,GAAG,CAAC,OAAwD;gBACrE,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,QAAQ,EAAE,eAAe,CAAC,GAAG,CAAC;aAC/B,CAAC;YAEF,mEAAmE;YACnE,MAAM,GAAG,GAAG,KAAK,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;YAE3C,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YAE5C,IAAI,SAAS,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBACxC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;oBACnB,KAAK,EAAE,yBAAyB;oBAChC,SAAS,EAAE,SAAS,CAAC,SAAS;iBAC/B,CAAC,CAAC;gBACH,OAAO;YACT,CAAC;YAED,wEAAwE;YACxE,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACzB,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;gBACpB,MAAM,CAAC,GAAG,GAAmD,CAAC;gBAC9D,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE,UAAU,EAAE;oBAChC,UAAU,EAAE,GAAG,CAAC,UAAU;oBAC1B,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;oBAC9B,aAAa,EAAE,CAAC,CAAC,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,IAAI;iBAChD,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,mCAAmC;QACrC,CAAC;QAED,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,eAAe,CAAC,GAAY;IACnC,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACjD,IAAI,OAAO,SAAS,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;IAC1E,IAAI,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;IACzE,OAAO,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC;AACnC,CAAC"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Fastify integration.
3
+ *
4
+ * Exposes {@link createFastifyPlugin}, a factory that returns a Fastify
5
+ * plugin attaching an `onRequest` hook bound to a {@link RaspAgent}.
6
+ *
7
+ * Behaviour mirrors the Express integration:
8
+ * - The request is normalised and inspected.
9
+ * - `monitor` mode lets the request continue regardless of the result.
10
+ * - `block` mode replies `403 { error, eventType }` and short-circuits
11
+ * the route handler.
12
+ * - Any thrown error is swallowed (fail-open).
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * import Fastify from "fastify";
17
+ * import { RaspAgent, createFastifyPlugin } from "@queno/agent-node";
18
+ *
19
+ * const agent = new RaspAgent({ apiKey, projectId, agentId });
20
+ * agent.start();
21
+ *
22
+ * const fastify = Fastify();
23
+ * await fastify.register(createFastifyPlugin(agent));
24
+ * ```
25
+ *
26
+ * @remarks The hook fires at `onRequest`, before body parsing. If body
27
+ * inspection is required, switch the hook to `preHandler` in this file or
28
+ * register a separate hook downstream.
29
+ */
30
+ import type { FastifyInstance } from "fastify";
31
+ import type { RaspAgent } from "../agent.js";
32
+ export declare function createFastifyPlugin(agent: RaspAgent): (fastify: FastifyInstance) => Promise<void>;
33
+ //# sourceMappingURL=fastify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fastify.d.ts","sourceRoot":"","sources":["../../src/integrations/fastify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,OAAO,KAAK,EAAE,eAAe,EAAgC,MAAM,SAAS,CAAC;AAC7E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAG7C,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,SAAS,IACjB,SAAS,eAAe,KAAG,OAAO,CAAC,IAAI,CAAC,CA4D1E"}
@@ -0,0 +1,63 @@
1
+ export function createFastifyPlugin(agent) {
2
+ return async function raspPlugin(fastify) {
3
+ fastify.addHook("onRequest", async (request, reply) => {
4
+ try {
5
+ const normalized = {
6
+ method: request.method,
7
+ path: request.url.split("?")[0] ?? request.url,
8
+ query: request.query ?? {},
9
+ headers: request.headers,
10
+ body: request.body,
11
+ sourceIp: extractSourceIp(request),
12
+ };
13
+ const ctx = agent.beginRequest(normalized);
14
+ request.__raspCtx = ctx;
15
+ const detection = agent.inspect(normalized);
16
+ if (detection && agent.mode === "block") {
17
+ return reply.status(403).send({
18
+ error: "Request blocked by RASP",
19
+ eventType: detection.eventType,
20
+ });
21
+ }
22
+ }
23
+ catch {
24
+ // Fail-open - see file-level note.
25
+ }
26
+ });
27
+ // Response-phase observation for traffic profiling + auth confirmation.
28
+ fastify.addHook("onResponse", async (request, reply) => {
29
+ try {
30
+ const normalized = {
31
+ method: request.method,
32
+ path: request.url.split("?")[0] ?? request.url,
33
+ query: request.query ?? {},
34
+ headers: request.headers,
35
+ body: request.body,
36
+ sourceIp: undefined,
37
+ };
38
+ const r = request;
39
+ agent.endRequest(r.__raspCtx ?? null, normalized, {
40
+ statusCode: reply.statusCode,
41
+ durationMs: Math.round(reply.elapsedTime),
42
+ authenticated: r.user != null || r.auth != null,
43
+ });
44
+ }
45
+ catch {
46
+ // Fail-open.
47
+ }
48
+ });
49
+ };
50
+ }
51
+ /**
52
+ * Best-effort source IP resolution; see the Express integration for the
53
+ * trust caveat.
54
+ */
55
+ function extractSourceIp(req) {
56
+ const forwarded = req.headers["x-forwarded-for"];
57
+ if (typeof forwarded === "string")
58
+ return forwarded.split(",")[0]?.trim();
59
+ if (Array.isArray(forwarded))
60
+ return forwarded[0]?.split(",")[0]?.trim();
61
+ return req.socket?.remoteAddress;
62
+ }
63
+ //# sourceMappingURL=fastify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fastify.js","sourceRoot":"","sources":["../../src/integrations/fastify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * NestJS integration.
3
+ *
4
+ * Exposes {@link createNestMiddleware}, a factory that returns a NestJS
5
+ * middleware **class** bound to a {@link RaspAgent} instance.
6
+ *
7
+ * Behaviour matches the Express adapter (Nest's middleware contract is
8
+ * Express-compatible by default):
9
+ * - The request is normalised and inspected.
10
+ * - `monitor` mode lets the request continue.
11
+ * - `block` mode replies `403 { error, eventType }` and skips the next
12
+ * handler.
13
+ * - Any thrown error is swallowed (fail-open).
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { MiddlewareConsumer, Module, NestModule } from "@nestjs/common";
18
+ * import { RaspAgent, createNestMiddleware } from "@queno/agent-node";
19
+ *
20
+ * const agent = new RaspAgent({ apiKey, projectId, agentId });
21
+ * agent.start();
22
+ *
23
+ * @Module({})
24
+ * export class AppModule implements NestModule {
25
+ * configure(consumer: MiddlewareConsumer) {
26
+ * consumer.apply(createNestMiddleware(agent)).forRoutes("*");
27
+ * }
28
+ * }
29
+ * ```
30
+ */
31
+ import type { NestMiddleware } from "@nestjs/common";
32
+ import type { RaspAgent } from "../agent.js";
33
+ /**
34
+ * Build a Nest middleware class bound to a {@link RaspAgent}.
35
+ *
36
+ * A class is returned (rather than an instance) because Nest itself
37
+ * instantiates middlewares from its DI container.
38
+ */
39
+ export declare function createNestMiddleware(agent: RaspAgent): new () => NestMiddleware;
40
+ //# sourceMappingURL=nestjs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nestjs.d.ts","sourceRoot":"","sources":["../../src/integrations/nestjs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAG7C;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,SAAS,GAAG,UAAU,cAAc,CA0C/E"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Build a Nest middleware class bound to a {@link RaspAgent}.
3
+ *
4
+ * A class is returned (rather than an instance) because Nest itself
5
+ * instantiates middlewares from its DI container.
6
+ */
7
+ export function createNestMiddleware(agent) {
8
+ class RaspNestMiddleware {
9
+ use(req, res, next) {
10
+ try {
11
+ const normalized = {
12
+ method: req.method,
13
+ path: req.path,
14
+ query: req.query,
15
+ headers: req.headers,
16
+ body: req.body,
17
+ sourceIp: extractSourceIp(req),
18
+ };
19
+ const ctx = agent.beginRequest(normalized);
20
+ const detection = agent.inspect(normalized);
21
+ if (detection && agent.mode === "block") {
22
+ res.status(403).json({
23
+ error: "Request blocked by RASP",
24
+ eventType: detection.eventType,
25
+ });
26
+ return;
27
+ }
28
+ const start = Date.now();
29
+ res.on("finish", () => {
30
+ const r = req;
31
+ agent.endRequest(ctx, normalized, {
32
+ statusCode: res.statusCode,
33
+ durationMs: Date.now() - start,
34
+ authenticated: r.user != null || r.auth != null,
35
+ });
36
+ });
37
+ }
38
+ catch {
39
+ // Fail-open - see file-level note.
40
+ }
41
+ next();
42
+ }
43
+ }
44
+ return RaspNestMiddleware;
45
+ }
46
+ /**
47
+ * Best-effort source IP resolution; see the Express integration for the
48
+ * trust caveat.
49
+ */
50
+ function extractSourceIp(req) {
51
+ const forwarded = req.headers["x-forwarded-for"];
52
+ if (typeof forwarded === "string")
53
+ return forwarded.split(",")[0]?.trim();
54
+ if (Array.isArray(forwarded))
55
+ return forwarded[0]?.split(",")[0]?.trim();
56
+ return req.socket?.remoteAddress;
57
+ }
58
+ //# sourceMappingURL=nestjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nestjs.js","sourceRoot":"","sources":["../../src/integrations/nestjs.ts"],"names":[],"mappings":"AAmCA;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAgB;IACnD,MAAM,kBAAkB;QACtB,GAAG,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB;YACjD,IAAI,CAAC;gBACH,MAAM,UAAU,GAAsB;oBACpC,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,IAAI,EAAE,GAAG,CAAC,IAAI;oBACd,KAAK,EAAE,GAAG,CAAC,KAAgC;oBAC3C,OAAO,EAAE,GAAG,CAAC,OAAwD;oBACrE,IAAI,EAAE,GAAG,CAAC,IAAI;oBACd,QAAQ,EAAE,eAAe,CAAC,GAAG,CAAC;iBAC/B,CAAC;gBAEF,MAAM,GAAG,GAAG,KAAK,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;gBAE3C,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;gBAE5C,IAAI,SAAS,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;oBACxC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;wBACnB,KAAK,EAAE,yBAAyB;wBAChC,SAAS,EAAE,SAAS,CAAC,SAAS;qBAC/B,CAAC,CAAC;oBACH,OAAO;gBACT,CAAC;gBAED,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBACzB,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;oBACpB,MAAM,CAAC,GAAG,GAAmD,CAAC;oBAC9D,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE,UAAU,EAAE;wBAChC,UAAU,EAAE,GAAG,CAAC,UAAU;wBAC1B,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;wBAC9B,aAAa,EAAE,CAAC,CAAC,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,IAAI;qBAChD,CAAC,CAAC;gBACL,CAAC,CAAC,CAAC;YACL,CAAC;YAAC,MAAM,CAAC;gBACP,mCAAmC;YACrC,CAAC;YACD,IAAI,EAAE,CAAC;QACT,CAAC;KACF;IAED,OAAO,kBAAkB,CAAC;AAC5B,CAAC;AAED;;;GAGG;AACH,SAAS,eAAe,CAAC,GAAY;IACnC,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACjD,IAAI,OAAO,SAAS,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;IAC1E,IAAI,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;IACzE,OAAQ,GAAG,CAAC,MAAiD,EAAE,aAAa,CAAC;AAC/E,CAAC"}