xploitscan 1.0.20 → 1.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.
- package/README.md +15 -3
- package/dist/{api-HTHCG6QE.js → api-UURQGULS.js} +2 -2
- package/dist/{chunk-RJUUWD2F.js → chunk-HHYGPI7J.js} +45 -9
- package/dist/chunk-HHYGPI7J.js.map +1 -0
- package/dist/index.js +43949 -44
- package/dist/index.js.map +1 -1
- package/package.json +6 -4
- package/dist/chunk-RJUUWD2F.js.map +0 -1
- /package/dist/{api-HTHCG6QE.js.map → api-UURQGULS.js.map} +0 -0
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
**Security scanner for AI-generated code.** Find vulnerabilities before attackers do.
|
|
7
7
|
|
|
8
|
-
Built for developers shipping code via Cursor, Lovable, Bolt, Replit, and Claude Code.
|
|
8
|
+
Built for developers shipping code via Cursor, Lovable, Bolt, Replit, and Claude Code. 206 security rules. Plain-English results. Copy-paste fixes.
|
|
9
9
|
|
|
10
10
|
## Quick Start
|
|
11
11
|
|
|
@@ -17,7 +17,7 @@ No install, no config, no account required. Your code stays 100% local.
|
|
|
17
17
|
|
|
18
18
|
## What It Catches
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
206 rules across 15+ categories:
|
|
21
21
|
|
|
22
22
|
| Category | Examples | Rules |
|
|
23
23
|
|----------|---------|-------|
|
|
@@ -32,6 +32,18 @@ No install, no config, no account required. Your code stays 100% local.
|
|
|
32
32
|
|
|
33
33
|
Every finding includes OWASP Top 10 and CWE compliance mappings.
|
|
34
34
|
|
|
35
|
+
## Detection Quality
|
|
36
|
+
|
|
37
|
+
Detection is scored publicly on a labeled fixture corpus that's refreshed on every commit. Current numbers live at **[xploitscan.com/benchmark](https://xploitscan.com/benchmark)**:
|
|
38
|
+
|
|
39
|
+
- **100% precision** (zero false positives) across 151 labeled fixtures covering 25+ vulnerability classes
|
|
40
|
+
- **80%+ recall** on rules with active test coverage
|
|
41
|
+
- Side-by-side comparison with Semgrep (community rulesets) and Bearer on the same corpus
|
|
42
|
+
|
|
43
|
+
The scanner uses a two-layer architecture: a fast regex pre-filter for pattern-based rules (secrets, missing headers, container misconfigs), and a Babel-parsed AST layer with local taint tracking for data-flow rules (SSRF, prototype pollution, mass assignment, SSTI, command injection from user input). Recognized taint sources: Express / Fastify / Koa / Next.js App Router / Web Fetch API / AWS Lambda.
|
|
44
|
+
|
|
45
|
+
Methodology, fixture format, and reproducibility instructions: **[xploitscan.com/docs/detection-methodology](https://xploitscan.com/docs/detection-methodology)**.
|
|
46
|
+
|
|
35
47
|
## Installation
|
|
36
48
|
|
|
37
49
|
```bash
|
|
@@ -130,7 +142,7 @@ Scan via the web at [xploitscan.com](https://xploitscan.com):
|
|
|
130
142
|
- SOC2/ISO27001 compliance mapping
|
|
131
143
|
- Slack and Discord webhook notifications
|
|
132
144
|
|
|
133
|
-
**Free**: 5 scans/day, 30 core rules. **Pro** ($
|
|
145
|
+
**Free**: 5 scans/day, 30 core rules. **Indie** ($9/mo): 500 scans/month, all 206 rules, scan history. **Pro** ($19/mo): unlimited scans, all 206 rules, PDF reports, compliance mapping, webhooks, AI false-positive filter. **Team** ($99/mo): everything in Pro plus 5 seats, shared scan history, RBAC, and portfolio reports. Annual plans save 40%.
|
|
134
146
|
|
|
135
147
|
## Supported Languages
|
|
136
148
|
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
storeToken,
|
|
13
13
|
syncUser,
|
|
14
14
|
uploadScanResults
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-HHYGPI7J.js";
|
|
16
16
|
export {
|
|
17
17
|
checkUsage,
|
|
18
18
|
clearProRulesCache,
|
|
@@ -27,4 +27,4 @@ export {
|
|
|
27
27
|
syncUser,
|
|
28
28
|
uploadScanResults
|
|
29
29
|
};
|
|
30
|
-
//# sourceMappingURL=api-
|
|
30
|
+
//# sourceMappingURL=api-UURQGULS.js.map
|
|
@@ -1,10 +1,35 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
2
8
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
3
9
|
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
4
10
|
}) : x)(function(x) {
|
|
5
11
|
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
6
12
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
7
13
|
});
|
|
14
|
+
var __commonJS = (cb, mod) => function __require2() {
|
|
15
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
16
|
+
};
|
|
17
|
+
var __copyProps = (to, from, except, desc) => {
|
|
18
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
19
|
+
for (let key of __getOwnPropNames(from))
|
|
20
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
21
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
22
|
+
}
|
|
23
|
+
return to;
|
|
24
|
+
};
|
|
25
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
26
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
27
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
28
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
29
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
30
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
31
|
+
mod
|
|
32
|
+
));
|
|
8
33
|
|
|
9
34
|
// src/utils/api.ts
|
|
10
35
|
import { readFileSync, writeFileSync, mkdirSync, existsSync, unlinkSync } from "fs";
|
|
@@ -17,6 +42,13 @@ var PRO_RULES_FILE = join(CONFIG_DIR, "pro-rules.cjs");
|
|
|
17
42
|
var PRO_RULES_META = join(CONFIG_DIR, "pro-rules-meta.json");
|
|
18
43
|
var API_BASE = process.env.XPLOITSCAN_API_URL ?? "https://api.xploitscan.com";
|
|
19
44
|
var WEB_BASE = process.env.XPLOITSCAN_WEB_URL ?? "https://xploitscan.com";
|
|
45
|
+
function getApiKey() {
|
|
46
|
+
const fromEnv = process.env.XPLOITSCAN_API_KEY;
|
|
47
|
+
if (fromEnv && fromEnv.startsWith("xpls_")) return fromEnv;
|
|
48
|
+
const stored = getStoredToken();
|
|
49
|
+
if (stored && stored.token.startsWith("xpls_")) return stored.token;
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
20
52
|
if (API_BASE.startsWith("http://") && !API_BASE.includes("localhost") && !API_BASE.includes("127.0.0.1")) {
|
|
21
53
|
throw new Error("API URL must use HTTPS for security. Set XPLOITSCAN_API_URL to an https:// URL.");
|
|
22
54
|
}
|
|
@@ -66,13 +98,13 @@ async function apiRequest(path, options = {}) {
|
|
|
66
98
|
});
|
|
67
99
|
}
|
|
68
100
|
async function checkUsage() {
|
|
69
|
-
const
|
|
70
|
-
if (!
|
|
101
|
+
const apiKey = getApiKey();
|
|
102
|
+
if (!apiKey) {
|
|
71
103
|
return { allowed: true, plan: "anonymous", remaining: -1, limit: -1 };
|
|
72
104
|
}
|
|
73
105
|
try {
|
|
74
106
|
const res = await fetch(`${WEB_BASE}/api/cli/usage`, {
|
|
75
|
-
headers: { Authorization: `Bearer ${
|
|
107
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
76
108
|
});
|
|
77
109
|
if (!res.ok) {
|
|
78
110
|
return { allowed: true, plan: "unknown", remaining: -1, limit: -1 };
|
|
@@ -103,10 +135,11 @@ async function uploadScanResults(result) {
|
|
|
103
135
|
}
|
|
104
136
|
async function syncUser() {
|
|
105
137
|
const token = getStoredToken();
|
|
106
|
-
|
|
138
|
+
const apiKey = getApiKey();
|
|
139
|
+
if (!apiKey || !token) return null;
|
|
107
140
|
try {
|
|
108
141
|
const res = await fetch(`${WEB_BASE}/api/cli/usage`, {
|
|
109
|
-
headers: { Authorization: `Bearer ${
|
|
142
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
110
143
|
});
|
|
111
144
|
if (!res.ok) return null;
|
|
112
145
|
const data = await res.json();
|
|
@@ -127,11 +160,11 @@ async function getCheckoutUrl() {
|
|
|
127
160
|
}
|
|
128
161
|
var PRO_RULES_CACHE_HOURS = 24;
|
|
129
162
|
async function downloadProRulesBundle() {
|
|
130
|
-
const
|
|
131
|
-
if (!
|
|
163
|
+
const apiKey = getApiKey();
|
|
164
|
+
if (!apiKey) return false;
|
|
132
165
|
try {
|
|
133
166
|
const res = await fetch(`${WEB_BASE}/api/cli/rules-bundle`, {
|
|
134
|
-
headers: { Authorization: `Bearer ${
|
|
167
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
135
168
|
});
|
|
136
169
|
if (!res.ok) return false;
|
|
137
170
|
const bundle = await res.text();
|
|
@@ -183,6 +216,9 @@ function clearProRulesCache() {
|
|
|
183
216
|
}
|
|
184
217
|
|
|
185
218
|
export {
|
|
219
|
+
__require,
|
|
220
|
+
__commonJS,
|
|
221
|
+
__toESM,
|
|
186
222
|
getStoredToken,
|
|
187
223
|
storeToken,
|
|
188
224
|
clearToken,
|
|
@@ -196,4 +232,4 @@ export {
|
|
|
196
232
|
loadCachedProRules,
|
|
197
233
|
clearProRulesCache
|
|
198
234
|
};
|
|
199
|
-
//# sourceMappingURL=chunk-
|
|
235
|
+
//# sourceMappingURL=chunk-HHYGPI7J.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/api.ts"],"sourcesContent":["import { readFileSync, writeFileSync, mkdirSync, existsSync, unlinkSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { createHash } from \"node:crypto\";\n\nconst CONFIG_DIR = join(homedir(), \".xploitscan\");\nconst TOKEN_FILE = join(CONFIG_DIR, \"token.json\");\nconst PRO_RULES_FILE = join(CONFIG_DIR, \"pro-rules.cjs\");\nconst PRO_RULES_META = join(CONFIG_DIR, \"pro-rules-meta.json\");\n\nconst API_BASE = process.env.XPLOITSCAN_API_URL ?? \"https://api.xploitscan.com\";\nconst WEB_BASE = process.env.XPLOITSCAN_WEB_URL ?? \"https://xploitscan.com\";\n\n/**\n * Resolve the credential to send to xploitscan.com endpoints that require\n * an `xpls_` API key (currently `/api/cli/usage` and `/api/cli/rules-bundle`).\n *\n * Order of precedence:\n * 1. `XPLOITSCAN_API_KEY` env var — how the GitHub Action and CI flows\n * pass a long-lived key (matches the variable name documented in\n * `packages/action/action.yml` and the Settings → API Keys docs).\n * 2. The locally stored token from `xploitscan auth login` — only useful\n * if the user pasted an `xpls_` key during login. The legacy Clerk\n * JWT path is no longer accepted by the server (security fix C-1).\n *\n * Returns null when no `xpls_`-shaped credential is available.\n */\nfunction getApiKey(): string | null {\n const fromEnv = process.env.XPLOITSCAN_API_KEY;\n if (fromEnv && fromEnv.startsWith(\"xpls_\")) return fromEnv;\n const stored = getStoredToken();\n if (stored && stored.token.startsWith(\"xpls_\")) return stored.token;\n return null;\n}\n\nif (API_BASE.startsWith(\"http://\") && !API_BASE.includes(\"localhost\") && !API_BASE.includes(\"127.0.0.1\")) {\n throw new Error(\"API URL must use HTTPS for security. Set XPLOITSCAN_API_URL to an https:// URL.\");\n}\nif (WEB_BASE.startsWith(\"http://\") && !WEB_BASE.includes(\"localhost\") && !WEB_BASE.includes(\"127.0.0.1\")) {\n throw new Error(\"Web URL must use HTTPS for security. Set XPLOITSCAN_WEB_URL to an https:// URL.\");\n}\n\ninterface TokenData {\n token: string;\n userId: string;\n email: string;\n expiresAt?: number;\n}\n\nexport function getStoredToken(): TokenData | null {\n try {\n if (!existsSync(TOKEN_FILE)) return null;\n const data = JSON.parse(readFileSync(TOKEN_FILE, \"utf-8\"));\n if (data.expiresAt && Date.now() > data.expiresAt) {\n // Token expired\n unlinkSync(TOKEN_FILE);\n return null;\n }\n return data;\n } catch {\n return null;\n }\n}\n\nexport function storeToken(data: TokenData): void {\n mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });\n writeFileSync(TOKEN_FILE, JSON.stringify(data, null, 2), { mode: 0o600 });\n}\n\nexport function clearToken(): void {\n try {\n if (existsSync(TOKEN_FILE)) {\n unlinkSync(TOKEN_FILE);\n }\n } catch {\n // ignore\n }\n}\n\nexport function isAuthenticated(): boolean {\n return getStoredToken() !== null;\n}\n\nasync function apiRequest(\n path: string,\n options: RequestInit = {},\n): Promise<Response> {\n const token = getStoredToken();\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...(options.headers as Record<string, string>),\n };\n\n if (token) {\n headers.Authorization = `Bearer ${token.token}`;\n }\n\n return fetch(`${API_BASE}${path}`, {\n ...options,\n headers,\n });\n}\n\nexport async function checkUsage(): Promise<{\n allowed: boolean;\n plan: string;\n // Set to \"indie\" when the server wants the CLI to message a monthly\n // (rather than daily) cap. Other tiers don't set this field.\n tier?: string;\n remaining: number;\n limit: number;\n}> {\n const apiKey = getApiKey();\n if (!apiKey) {\n // No xpls_ key available — anonymous local-scan path (or a stale\n // Clerk-JWT login that the server no longer accepts).\n return { allowed: true, plan: \"anonymous\", remaining: -1, limit: -1 };\n }\n\n try {\n // Use web app API for real subscription lookup\n const res = await fetch(`${WEB_BASE}/api/cli/usage`, {\n headers: { Authorization: `Bearer ${apiKey}` },\n });\n if (!res.ok) {\n return { allowed: true, plan: \"unknown\", remaining: -1, limit: -1 };\n }\n return await res.json();\n } catch {\n // Network error — allow local scan\n return { allowed: true, plan: \"offline\", remaining: -1, limit: -1 };\n }\n}\n\nexport async function incrementUsage(): Promise<void> {\n const token = getStoredToken();\n if (!token) return;\n\n try {\n await apiRequest(\"/api/usage/increment\", { method: \"POST\" });\n } catch {\n // Silent fail — don't block scan\n }\n}\n\nexport async function uploadScanResults(result: {\n directory: string;\n filesScanned: number;\n findings: unknown[];\n duration: number;\n}): Promise<void> {\n const token = getStoredToken();\n if (!token) return;\n\n try {\n await apiRequest(\"/api/scans\", {\n method: \"POST\",\n body: JSON.stringify(result),\n });\n } catch {\n // Silent fail\n }\n}\n\nexport async function syncUser(): Promise<{ plan: string; email: string } | null> {\n const token = getStoredToken();\n const apiKey = getApiKey();\n if (!apiKey || !token) return null;\n try {\n const res = await fetch(`${WEB_BASE}/api/cli/usage`, {\n headers: { Authorization: `Bearer ${apiKey}` },\n });\n if (!res.ok) return null;\n const data = await res.json();\n return { plan: data.plan, email: token.email };\n } catch {\n return null;\n }\n}\n\nexport async function getCheckoutUrl(): Promise<string | null> {\n try {\n const res = await apiRequest(\"/api/billing/checkout\", { method: \"POST\" });\n if (!res.ok) return null;\n const data = await res.json();\n return data.url;\n } catch {\n return null;\n }\n}\n\n// ── Pro Rules Bundle (Server-Side Delivery) ──────────────────────────────\n\nconst PRO_RULES_CACHE_HOURS = 24;\n\nexport async function downloadProRulesBundle(): Promise<boolean> {\n const apiKey = getApiKey();\n if (!apiKey) return false;\n\n try {\n const res = await fetch(`${WEB_BASE}/api/cli/rules-bundle`, {\n headers: { Authorization: `Bearer ${apiKey}` },\n });\n if (!res.ok) return false;\n\n const bundle = await res.text();\n if (!bundle || bundle.length < 100) return false;\n\n // Basic integrity check: verify bundle contains expected exports\n if (!bundle.includes(\"proOnlyRules\") || !bundle.includes(\"exports\")) {\n return false;\n }\n\n const hash = createHash(\"sha256\").update(bundle).digest(\"hex\");\n mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });\n writeFileSync(PRO_RULES_FILE, bundle, { mode: 0o600 });\n writeFileSync(PRO_RULES_META, JSON.stringify({\n cachedAt: Date.now(),\n expiresAt: Date.now() + PRO_RULES_CACHE_HOURS * 60 * 60 * 1000,\n sha256: hash,\n }), { mode: 0o600 });\n return true;\n } catch {\n return false;\n }\n}\n\nexport function loadCachedProRules(): unknown[] | null {\n try {\n if (!existsSync(PRO_RULES_FILE) || !existsSync(PRO_RULES_META)) return null;\n\n const meta = JSON.parse(readFileSync(PRO_RULES_META, \"utf-8\"));\n if (Date.now() > meta.expiresAt) {\n clearProRulesCache();\n return null;\n }\n\n // Verify integrity before loading\n if (meta.sha256) {\n const fileContent = readFileSync(PRO_RULES_FILE, \"utf-8\");\n const currentHash = createHash(\"sha256\").update(fileContent).digest(\"hex\");\n if (currentHash !== meta.sha256) {\n clearProRulesCache();\n return null;\n }\n }\n\n // Dynamic require of the cached CJS bundle\n const mod = require(PRO_RULES_FILE);\n return mod.proOnlyRules || null;\n } catch {\n return null;\n }\n}\n\nexport function clearProRulesCache(): void {\n try {\n if (existsSync(PRO_RULES_FILE)) unlinkSync(PRO_RULES_FILE);\n if (existsSync(PRO_RULES_META)) unlinkSync(PRO_RULES_META);\n } catch { /* ignore */ }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,cAAc,eAAe,WAAW,YAAY,kBAAkB;AAC/E,SAAS,YAAY;AACrB,SAAS,eAAe;AACxB,SAAS,kBAAkB;AAE3B,IAAM,aAAa,KAAK,QAAQ,GAAG,aAAa;AAChD,IAAM,aAAa,KAAK,YAAY,YAAY;AAChD,IAAM,iBAAiB,KAAK,YAAY,eAAe;AACvD,IAAM,iBAAiB,KAAK,YAAY,qBAAqB;AAE7D,IAAM,WAAW,QAAQ,IAAI,sBAAsB;AACnD,IAAM,WAAW,QAAQ,IAAI,sBAAsB;AAgBnD,SAAS,YAA2B;AAClC,QAAM,UAAU,QAAQ,IAAI;AAC5B,MAAI,WAAW,QAAQ,WAAW,OAAO,EAAG,QAAO;AACnD,QAAM,SAAS,eAAe;AAC9B,MAAI,UAAU,OAAO,MAAM,WAAW,OAAO,EAAG,QAAO,OAAO;AAC9D,SAAO;AACT;AAEA,IAAI,SAAS,WAAW,SAAS,KAAK,CAAC,SAAS,SAAS,WAAW,KAAK,CAAC,SAAS,SAAS,WAAW,GAAG;AACxG,QAAM,IAAI,MAAM,iFAAiF;AACnG;AACA,IAAI,SAAS,WAAW,SAAS,KAAK,CAAC,SAAS,SAAS,WAAW,KAAK,CAAC,SAAS,SAAS,WAAW,GAAG;AACxG,QAAM,IAAI,MAAM,iFAAiF;AACnG;AASO,SAAS,iBAAmC;AACjD,MAAI;AACF,QAAI,CAAC,WAAW,UAAU,EAAG,QAAO;AACpC,UAAM,OAAO,KAAK,MAAM,aAAa,YAAY,OAAO,CAAC;AACzD,QAAI,KAAK,aAAa,KAAK,IAAI,IAAI,KAAK,WAAW;AAEjD,iBAAW,UAAU;AACrB,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,WAAW,MAAuB;AAChD,YAAU,YAAY,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AACtD,gBAAc,YAAY,KAAK,UAAU,MAAM,MAAM,CAAC,GAAG,EAAE,MAAM,IAAM,CAAC;AAC1E;AAEO,SAAS,aAAmB;AACjC,MAAI;AACF,QAAI,WAAW,UAAU,GAAG;AAC1B,iBAAW,UAAU;AAAA,IACvB;AAAA,EACF,QAAQ;AAAA,EAER;AACF;AAEO,SAAS,kBAA2B;AACzC,SAAO,eAAe,MAAM;AAC9B;AAEA,eAAe,WACb,MACA,UAAuB,CAAC,GACL;AACnB,QAAM,QAAQ,eAAe;AAC7B,QAAM,UAAkC;AAAA,IACtC,gBAAgB;AAAA,IAChB,GAAI,QAAQ;AAAA,EACd;AAEA,MAAI,OAAO;AACT,YAAQ,gBAAgB,UAAU,MAAM,KAAK;AAAA,EAC/C;AAEA,SAAO,MAAM,GAAG,QAAQ,GAAG,IAAI,IAAI;AAAA,IACjC,GAAG;AAAA,IACH;AAAA,EACF,CAAC;AACH;AAEA,eAAsB,aAQnB;AACD,QAAM,SAAS,UAAU;AACzB,MAAI,CAAC,QAAQ;AAGX,WAAO,EAAE,SAAS,MAAM,MAAM,aAAa,WAAW,IAAI,OAAO,GAAG;AAAA,EACtE;AAEA,MAAI;AAEF,UAAM,MAAM,MAAM,MAAM,GAAG,QAAQ,kBAAkB;AAAA,MACnD,SAAS,EAAE,eAAe,UAAU,MAAM,GAAG;AAAA,IAC/C,CAAC;AACD,QAAI,CAAC,IAAI,IAAI;AACX,aAAO,EAAE,SAAS,MAAM,MAAM,WAAW,WAAW,IAAI,OAAO,GAAG;AAAA,IACpE;AACA,WAAO,MAAM,IAAI,KAAK;AAAA,EACxB,QAAQ;AAEN,WAAO,EAAE,SAAS,MAAM,MAAM,WAAW,WAAW,IAAI,OAAO,GAAG;AAAA,EACpE;AACF;AAEA,eAAsB,iBAAgC;AACpD,QAAM,QAAQ,eAAe;AAC7B,MAAI,CAAC,MAAO;AAEZ,MAAI;AACF,UAAM,WAAW,wBAAwB,EAAE,QAAQ,OAAO,CAAC;AAAA,EAC7D,QAAQ;AAAA,EAER;AACF;AAEA,eAAsB,kBAAkB,QAKtB;AAChB,QAAM,QAAQ,eAAe;AAC7B,MAAI,CAAC,MAAO;AAEZ,MAAI;AACF,UAAM,WAAW,cAAc;AAAA,MAC7B,QAAQ;AAAA,MACR,MAAM,KAAK,UAAU,MAAM;AAAA,IAC7B,CAAC;AAAA,EACH,QAAQ;AAAA,EAER;AACF;AAEA,eAAsB,WAA4D;AAChF,QAAM,QAAQ,eAAe;AAC7B,QAAM,SAAS,UAAU;AACzB,MAAI,CAAC,UAAU,CAAC,MAAO,QAAO;AAC9B,MAAI;AACF,UAAM,MAAM,MAAM,MAAM,GAAG,QAAQ,kBAAkB;AAAA,MACnD,SAAS,EAAE,eAAe,UAAU,MAAM,GAAG;AAAA,IAC/C,CAAC;AACD,QAAI,CAAC,IAAI,GAAI,QAAO;AACpB,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,WAAO,EAAE,MAAM,KAAK,MAAM,OAAO,MAAM,MAAM;AAAA,EAC/C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,iBAAyC;AAC7D,MAAI;AACF,UAAM,MAAM,MAAM,WAAW,yBAAyB,EAAE,QAAQ,OAAO,CAAC;AACxE,QAAI,CAAC,IAAI,GAAI,QAAO;AACpB,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,WAAO,KAAK;AAAA,EACd,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAIA,IAAM,wBAAwB;AAE9B,eAAsB,yBAA2C;AAC/D,QAAM,SAAS,UAAU;AACzB,MAAI,CAAC,OAAQ,QAAO;AAEpB,MAAI;AACF,UAAM,MAAM,MAAM,MAAM,GAAG,QAAQ,yBAAyB;AAAA,MAC1D,SAAS,EAAE,eAAe,UAAU,MAAM,GAAG;AAAA,IAC/C,CAAC;AACD,QAAI,CAAC,IAAI,GAAI,QAAO;AAEpB,UAAM,SAAS,MAAM,IAAI,KAAK;AAC9B,QAAI,CAAC,UAAU,OAAO,SAAS,IAAK,QAAO;AAG3C,QAAI,CAAC,OAAO,SAAS,cAAc,KAAK,CAAC,OAAO,SAAS,SAAS,GAAG;AACnE,aAAO;AAAA,IACT;AAEA,UAAM,OAAO,WAAW,QAAQ,EAAE,OAAO,MAAM,EAAE,OAAO,KAAK;AAC7D,cAAU,YAAY,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AACtD,kBAAc,gBAAgB,QAAQ,EAAE,MAAM,IAAM,CAAC;AACrD,kBAAc,gBAAgB,KAAK,UAAU;AAAA,MAC3C,UAAU,KAAK,IAAI;AAAA,MACnB,WAAW,KAAK,IAAI,IAAI,wBAAwB,KAAK,KAAK;AAAA,MAC1D,QAAQ;AAAA,IACV,CAAC,GAAG,EAAE,MAAM,IAAM,CAAC;AACnB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,qBAAuC;AACrD,MAAI;AACF,QAAI,CAAC,WAAW,cAAc,KAAK,CAAC,WAAW,cAAc,EAAG,QAAO;AAEvE,UAAM,OAAO,KAAK,MAAM,aAAa,gBAAgB,OAAO,CAAC;AAC7D,QAAI,KAAK,IAAI,IAAI,KAAK,WAAW;AAC/B,yBAAmB;AACnB,aAAO;AAAA,IACT;AAGA,QAAI,KAAK,QAAQ;AACf,YAAM,cAAc,aAAa,gBAAgB,OAAO;AACxD,YAAM,cAAc,WAAW,QAAQ,EAAE,OAAO,WAAW,EAAE,OAAO,KAAK;AACzE,UAAI,gBAAgB,KAAK,QAAQ;AAC/B,2BAAmB;AACnB,eAAO;AAAA,MACT;AAAA,IACF;AAGA,UAAM,MAAM,UAAQ,cAAc;AAClC,WAAO,IAAI,gBAAgB;AAAA,EAC7B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,qBAA2B;AACzC,MAAI;AACF,QAAI,WAAW,cAAc,EAAG,YAAW,cAAc;AACzD,QAAI,WAAW,cAAc,EAAG,YAAW,cAAc;AAAA,EAC3D,QAAQ;AAAA,EAAe;AACzB;","names":[]}
|