@certscore/mcp 0.2.11 → 0.2.15

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/dist/server.d.ts CHANGED
@@ -5,6 +5,7 @@ export interface CertScoreMcpOptions {
5
5
  forwardedClientIp?: string | null;
6
6
  anonymousRequesterSecret?: string | null;
7
7
  timeout?: number;
8
+ toolProfile?: "full" | "light";
8
9
  }
9
10
  export declare function createCertScoreMcpServer(options?: CertScoreMcpOptions): McpServer;
10
11
  //# sourceMappingURL=server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,wBAAwB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAsDD,wBAAgB,wBAAwB,CAAC,OAAO,GAAE,mBAAwB,aAoSzE"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,wBAAwB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAChC;AAyED,wBAAgB,wBAAwB,CAAC,OAAO,GAAE,mBAAwB,aAkSzE"}
package/dist/server.js CHANGED
@@ -2,9 +2,20 @@ import { CertScoreClient, CertScoreTimeoutError } from "@certscore/sdk";
2
2
  import { certScoreMcpToolContracts } from "@certscore/api-contracts";
3
3
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
4
  import { CERTSCORE_MCP_VERSION } from "./version.js";
5
- import { boundEvidencePacket, buildScanBundle, exportFindings, limitPreConsentRows, normalizeDetail, normalizeFormat, paginateFindingList, scanIdFromStatus, toToolError, toToolResult } from "./tools.js";
6
- let createScanDeprecationWarningPrinted = false;
5
+ import { boundEvidencePacket, buildScanBundle, exportFindings, limitPreConsentRows, normalizeDetail, normalizeFormat, paginateFindingList, toInvalidArgumentsToolError, toToolError, toToolResult, withMcpAgentGuidance } from "./tools.js";
7
6
  const DEFAULT_MCP_SCAN_WAIT_MS = 45_000;
7
+ async function retryTransientOriginFailure(operation) {
8
+ try {
9
+ return await operation();
10
+ }
11
+ catch (error) {
12
+ const retryable = error instanceof Error && "status" in error && [502, 503, 504].includes(Number(error.status));
13
+ if (!retryable) {
14
+ throw error;
15
+ }
16
+ return operation();
17
+ }
18
+ }
8
19
  function scanCreationMetadata(value) {
9
20
  return {
10
21
  executionMode: value.executionMode,
@@ -14,7 +25,9 @@ function scanCreationMetadata(value) {
14
25
  quotaConsumed: value.quotaConsumed,
15
26
  anonymousQuotaLimit: value.anonymousQuotaLimit,
16
27
  anonymousQuotaRemaining: value.anonymousQuotaRemaining,
17
- anonymousQuotaResetAt: value.anonymousQuotaResetAt
28
+ anonymousQuotaResetAt: value.anonymousQuotaResetAt,
29
+ upgradeSupportEmail: value.upgradeSupportEmail,
30
+ upgradeMessage: value.upgradeMessage
18
31
  };
19
32
  }
20
33
  function toolContract(name) {
@@ -43,79 +56,69 @@ export function createCertScoreMcpServer(options = {}) {
43
56
  name: "certscore",
44
57
  version: CERTSCORE_MCP_VERSION
45
58
  });
46
- const registerTool = server.registerTool.bind(server);
47
- async function createPulseScanTool(input) {
48
- const result = await client.submitScan(input.url, {
49
- detail: normalizeDetail(input.detail),
50
- format: normalizeFormat(input.format),
51
- freshness: input.freshness ?? "latest",
52
- scanFrom: input.scanFrom
53
- });
54
- return {
55
- type: "certscore_mcp_scan_created",
56
- status: result.status,
57
- jobId: result.jobId ?? null,
58
- scanId: result.scanId ?? result.scan_id ?? null,
59
- completed: result.completed ?? false,
60
- statusUrl: result.statusUrl ?? result.nextCheckUrl ?? null,
61
- resultUrl: result.resultUrl ?? null,
62
- reportUrl: result.reportUrl ?? null,
63
- pulse: result.pulse ?? null,
64
- resultDisposition: result.resultDisposition ?? result.pulse?.resultDisposition ?? null,
65
- noGo: result.noGo ?? result.pulse?.noGo ?? null
66
- };
67
- }
68
- registerTool("create_scan", toolContract("create_scan"), async (input) => {
69
- try {
70
- if (!createScanDeprecationWarningPrinted) {
71
- createScanDeprecationWarningPrinted = true;
72
- console.error("[certscore-mcp] create_scan is deprecated in the 0.2.x line. Use scan_site for new integrations.");
73
- }
74
- return toToolResult(await createPulseScanTool(input));
59
+ const sdkCreateToolError = server.createToolError.bind(server);
60
+ server.createToolError = (message) => message.includes("Input validation error:")
61
+ ? toInvalidArgumentsToolError(message)
62
+ : sdkCreateToolError(message);
63
+ const lightTools = new Set(["certscore_scan_site", "certscore_get_scan_status", "certscore_get_scan_bundle"]);
64
+ const registerMcpTool = server.registerTool.bind(server);
65
+ const registerTool = (name, contract, handler) => {
66
+ if (options.toolProfile === "light" && !lightTools.has(name)) {
67
+ return;
75
68
  }
76
- catch (error) {
77
- return toToolError(error);
78
- }
79
- });
80
- registerTool("scan_site", toolContract("scan_site"), async (input) => {
69
+ registerMcpTool(name, contract, handler);
70
+ };
71
+ registerTool("certscore_scan_site", toolContract("certscore_scan_site"), async (input) => {
81
72
  try {
82
73
  const created = await client.scans.create(input.url, {
83
74
  freshness: input.freshness ?? "latest",
84
75
  scanFrom: input.scanFrom
85
76
  });
86
77
  if (input.waitForCompletion === false || created.type === "certscore_scan") {
87
- return toToolResult(created);
78
+ return toToolResult(withMcpAgentGuidance(created));
88
79
  }
89
80
  try {
90
81
  const completed = await client.scans.wait(created, {
91
82
  maxWaitMs: Math.min(input.maxWaitSeconds ? input.maxWaitSeconds * 1_000 : DEFAULT_MCP_SCAN_WAIT_MS, DEFAULT_MCP_SCAN_WAIT_MS)
92
83
  });
93
- return toToolResult({
84
+ return toToolResult(withMcpAgentGuidance({
94
85
  ...completed,
95
- ...scanCreationMetadata(created),
96
- recommendedNextTool: "get_scan_bundle"
97
- });
86
+ ...scanCreationMetadata(created)
87
+ }));
98
88
  }
99
89
  catch (error) {
100
- if (!(error instanceof CertScoreTimeoutError)) {
101
- throw error;
102
- }
103
90
  const scanId = created.scanId ?? created.scan_id;
104
- if (scanId) {
105
- return toToolResult({
106
- ...(await client.scans.status(scanId)),
107
- ...scanCreationMetadata(created),
108
- recommendedNextTool: "get_scan_status"
109
- });
91
+ console.warn(JSON.stringify({
92
+ event: "mcp.certscore_scan_site.wait_deferred",
93
+ errorName: error instanceof Error ? error.name : "UnknownError",
94
+ jobId: created.jobId ?? null,
95
+ scanId: scanId ?? null,
96
+ status: created.status ?? null
97
+ }));
98
+ if (error instanceof CertScoreTimeoutError && scanId) {
99
+ try {
100
+ return toToolResult(withMcpAgentGuidance({
101
+ ...(await client.scans.status(scanId)),
102
+ ...scanCreationMetadata(created)
103
+ }));
104
+ }
105
+ catch {
106
+ // Creation already succeeded. Preserve that stable identity when
107
+ // the follow-up status read is briefly unavailable.
108
+ }
110
109
  }
111
- return toToolResult(created);
110
+ // Waiting is a convenience layered on top of scan creation. Once the
111
+ // API has accepted a scan, never turn a transient polling or hydration
112
+ // failure into an identity-less tool error that encourages callers to
113
+ // submit a second, non-idempotent certscore_scan_site request.
114
+ return toToolResult(withMcpAgentGuidance(created));
112
115
  }
113
116
  }
114
117
  catch (error) {
115
118
  return toToolError(error);
116
119
  }
117
120
  });
118
- registerTool("get_scan", toolContract("get_scan"), async ({ scanId }) => {
121
+ registerTool("certscore_get_scan", toolContract("certscore_get_scan"), async ({ scanId }) => {
119
122
  try {
120
123
  return toToolResult(await client.scans.get(scanId));
121
124
  }
@@ -123,53 +126,47 @@ export function createCertScoreMcpServer(options = {}) {
123
126
  return toToolError(error);
124
127
  }
125
128
  });
126
- registerTool("get_scan_status", toolContract("get_scan_status"), async ({ jobId, scanId }) => {
129
+ registerTool("certscore_get_scan_status", toolContract("certscore_get_scan_status"), async ({ scanId }) => {
127
130
  try {
128
- if (scanId) {
129
- const status = await client.scans.status(scanId);
130
- const needsTerminalHydration = status.status === "completed" || status.status === "completed_limited";
131
- if (needsTerminalHydration) {
132
- try {
133
- const scan = await client.scans.get(scanId);
134
- return toToolResult({
135
- ...status,
136
- type: "certscore_scan_job",
137
- status: scan.status,
138
- domain: scan.domain,
139
- resultDisposition: scan.resultDisposition,
140
- noGo: scan.noGo,
141
- startedAt: scan.startedAt,
142
- completedAt: scan.completedAt,
143
- scanTimeSeconds: scan.scanTimeSeconds,
144
- recommendedNextTool: "get_scan_bundle"
145
- });
146
- }
147
- catch {
148
- // Preserve the API status response if the terminal scan resource is
149
- // briefly unavailable during eventual-consistency windows.
150
- }
131
+ const status = await client.scans.status(scanId);
132
+ const needsTerminalHydration = status.status === "completed" || status.status === "completed_limited";
133
+ if (needsTerminalHydration) {
134
+ try {
135
+ const scan = await client.scans.get(scanId);
136
+ return toToolResult(withMcpAgentGuidance({
137
+ ...status,
138
+ type: "certscore_scan_job",
139
+ status: scan.status,
140
+ domain: scan.domain,
141
+ url: scan.url ?? null,
142
+ resultDisposition: scan.resultDisposition,
143
+ noGo: scan.noGo,
144
+ createdAt: scan.createdAt ?? null,
145
+ startedAt: scan.startedAt,
146
+ completedAt: scan.completedAt,
147
+ scanTimeSeconds: scan.scanTimeSeconds,
148
+ score: scan.score ?? null,
149
+ scoreStatus: scan.scoreStatus,
150
+ scoreVersion: scan.scoreVersion ?? null,
151
+ scoreUpdatedAt: scan.scoreUpdatedAt ?? null,
152
+ riskLevel: scan.riskLevel ?? null,
153
+ coverage: scan.coverage ?? null,
154
+ reportUrl: scan.links?.report ?? status.reportUrl ?? null,
155
+ links: { ...status.links, ...scan.links }
156
+ }));
157
+ }
158
+ catch {
159
+ // Preserve the API status response if the terminal scan resource is
160
+ // briefly unavailable during eventual-consistency windows.
151
161
  }
152
- return toToolResult(status);
153
- }
154
- if (!jobId) {
155
- return toToolResult({
156
- error: {
157
- name: "InvalidToolInput",
158
- message: "Provide either scanId for API v2 scan status or jobId for Pulse job status."
159
- }
160
- });
161
162
  }
162
- const status = await client.getJobStatus(jobId);
163
- return toToolResult({
164
- ...status,
165
- scanId: scanIdFromStatus(status)
166
- });
163
+ return toToolResult(withMcpAgentGuidance(status));
167
164
  }
168
165
  catch (error) {
169
166
  return toToolError(error);
170
167
  }
171
168
  });
172
- registerTool("get_report", toolContract("get_report"), async ({ scanId, detail, format }) => {
169
+ registerTool("certscore_get_report", toolContract("certscore_get_report"), async ({ scanId, detail, format }) => {
173
170
  try {
174
171
  const normalizedFormat = normalizeFormat(format);
175
172
  const result = normalizedFormat === "markdown"
@@ -187,7 +184,7 @@ export function createCertScoreMcpServer(options = {}) {
187
184
  return toToolError(error);
188
185
  }
189
186
  });
190
- registerTool("get_evidence", toolContract("get_evidence"), async ({ scanId }) => {
187
+ registerTool("certscore_get_evidence", toolContract("certscore_get_evidence"), async ({ scanId }) => {
191
188
  try {
192
189
  return toToolResult(boundEvidencePacket(await client.getScan(scanId, { detail: "evidence", format: "json" })));
193
190
  }
@@ -195,18 +192,37 @@ export function createCertScoreMcpServer(options = {}) {
195
192
  return toToolError(error);
196
193
  }
197
194
  });
198
- registerTool("get_scan_bundle", toolContract("get_scan_bundle"), async ({ scanId, maxFindings, maxPreConsentRows }) => {
195
+ registerTool("certscore_get_scan_bundle", toolContract("certscore_get_scan_bundle"), async ({ scanId, detail = "summary", maxBytes, maxFindings, maxPreConsentRows }) => {
199
196
  try {
200
- const [scan, report, evidence, findings, preConsentCookiesTrackers] = await Promise.all([
201
- client.scans.get(scanId),
202
- client.getScan(scanId, { detail: "summary", format: "json" }),
203
- client.getScan(scanId, { detail: "evidence", format: "json" }),
204
- client.findings.list(scanId),
205
- client.scans.preConsentCookiesTrackers(scanId)
197
+ const scan = await retryTransientOriginFailure(() => client.scans.get(scanId));
198
+ if (scan.status === "completed_limited" && scan.resultDisposition === "no_go") {
199
+ return toToolResult(buildScanBundle({
200
+ detail,
201
+ evidence: null,
202
+ findings: { type: "certscore_finding_list", scanId, findings: [] },
203
+ maxBytes,
204
+ maxFindings,
205
+ maxPreConsentRows,
206
+ preConsentCookiesTrackers: null,
207
+ report: null,
208
+ scan
209
+ }));
210
+ }
211
+ const includeEvidence = detail === "evidence" || detail === "full";
212
+ const reportDetail = detail === "full" ? "full" : includeEvidence ? "evidence" : "summary";
213
+ const [report, findings, preConsentCookiesTrackers] = await Promise.all([
214
+ retryTransientOriginFailure(() => client.getScan(scanId, { detail: reportDetail, format: "json" })),
215
+ retryTransientOriginFailure(() => client.findings.list(scanId)),
216
+ includeEvidence
217
+ ? retryTransientOriginFailure(() => client.scans.preConsentCookiesTrackers(scanId))
218
+ : Promise.resolve(null)
206
219
  ]);
220
+ const evidence = includeEvidence ? report : null;
207
221
  return toToolResult(buildScanBundle({
222
+ detail,
208
223
  evidence,
209
224
  findings,
225
+ maxBytes,
210
226
  maxFindings,
211
227
  maxPreConsentRows,
212
228
  preConsentCookiesTrackers,
@@ -218,7 +234,7 @@ export function createCertScoreMcpServer(options = {}) {
218
234
  return toToolError(error);
219
235
  }
220
236
  });
221
- registerTool("export_findings", toolContract("export_findings"), async ({ scanId }) => {
237
+ registerTool("certscore_export_findings", toolContract("certscore_export_findings"), async ({ scanId }) => {
222
238
  try {
223
239
  const report = await client.getScan(scanId, { detail: "full", format: "json" });
224
240
  return toToolResult(exportFindings(report));
@@ -227,7 +243,7 @@ export function createCertScoreMcpServer(options = {}) {
227
243
  return toToolError(error);
228
244
  }
229
245
  });
230
- registerTool("list_findings", toolContract("list_findings"), async ({ limit, offset, scanId }) => {
246
+ registerTool("certscore_list_findings", toolContract("certscore_list_findings"), async ({ limit, offset, scanId }) => {
231
247
  try {
232
248
  return toToolResult(paginateFindingList(await client.findings.list(scanId), { limit, offset }));
233
249
  }
@@ -235,7 +251,7 @@ export function createCertScoreMcpServer(options = {}) {
235
251
  return toToolError(error);
236
252
  }
237
253
  });
238
- registerTool("get_pre_consent_cookies_trackers", toolContract("get_pre_consent_cookies_trackers"), async ({ maxRows, scanId }) => {
254
+ registerTool("certscore_get_pre_consent_cookies_trackers", toolContract("certscore_get_pre_consent_cookies_trackers"), async ({ maxRows, scanId }) => {
239
255
  try {
240
256
  return toToolResult(limitPreConsentRows(await client.scans.preConsentCookiesTrackers(scanId), { maxRows }));
241
257
  }
@@ -243,7 +259,7 @@ export function createCertScoreMcpServer(options = {}) {
243
259
  return toToolError(error);
244
260
  }
245
261
  });
246
- registerTool("explain_finding", toolContract("explain_finding"), async ({ scanId, findingId }) => {
262
+ registerTool("certscore_explain_finding", toolContract("certscore_explain_finding"), async ({ scanId, findingId }) => {
247
263
  try {
248
264
  return toToolResult(await client.findings.explain(scanId, findingId));
249
265
  }
@@ -251,7 +267,7 @@ export function createCertScoreMcpServer(options = {}) {
251
267
  return toToolError(error);
252
268
  }
253
269
  });
254
- registerTool("get_latest_domain_scan", toolContract("get_latest_domain_scan"), async ({ domain, scanFrom }) => {
270
+ registerTool("certscore_get_latest_domain_scan", toolContract("certscore_get_latest_domain_scan"), async ({ domain, scanFrom }) => {
255
271
  try {
256
272
  return toToolResult(await client.domains.latest(domain, { scanFrom }));
257
273
  }
@@ -259,7 +275,7 @@ export function createCertScoreMcpServer(options = {}) {
259
275
  return toToolError(error);
260
276
  }
261
277
  });
262
- registerTool("get_latest_domain_pre_consent_cookies_trackers", toolContract("get_latest_domain_pre_consent_cookies_trackers"), async ({ domain, maxRows, scanFrom }) => {
278
+ registerTool("certscore_get_latest_domain_pre_consent_cookies_trackers", toolContract("certscore_get_latest_domain_pre_consent_cookies_trackers"), async ({ domain, maxRows, scanFrom }) => {
263
279
  try {
264
280
  return toToolResult(limitPreConsentRows(await client.domains.latestPreConsentCookiesTrackers(domain, { scanFrom }), { maxRows }));
265
281
  }
package/dist/tools.d.ts CHANGED
@@ -1,8 +1,22 @@
1
1
  import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
2
2
  import { type FindingList, type JobStatus, type PreConsentCookiesTrackers, type PulseDetail, type PulseFormat, type PulseResult, type ScanResource, type TopFinding } from "@certscore/sdk";
3
3
  export declare const MAX_EVIDENCE_PACKET_CHARS = 250000;
4
+ type ActionableError = {
5
+ code: string;
6
+ message: string;
7
+ retryable: boolean;
8
+ retryAfterSeconds: number | null;
9
+ recommendedNextAction: string;
10
+ field?: string;
11
+ mcpCode?: number;
12
+ };
4
13
  export declare function toToolResult(payload: unknown): CallToolResult;
5
14
  export declare function toToolError(error: unknown): CallToolResult;
15
+ export declare function toInvalidArgumentsToolError(errorMessage: string): CallToolResult;
16
+ export declare function withMcpAgentGuidance<T extends Record<string, any>>(value: T): T & {
17
+ error: ActionableError | null;
18
+ observationOnlyDisclaimer: string;
19
+ };
6
20
  export declare function boundEvidencePacket<T>(payload: T, maxSerializedChars?: number): T | Record<string, unknown>;
7
21
  export declare function normalizeDetail(detail: PulseDetail | undefined): PulseDetail;
8
22
  export declare function normalizeFormat(format: PulseFormat | undefined): PulseFormat;
@@ -38,68 +52,16 @@ export declare function limitPreConsentRows<T extends Record<string, unknown>>(p
38
52
  maxRows?: number;
39
53
  }): T;
40
54
  export declare function buildScanBundle(input: {
41
- evidence: PulseResult;
55
+ detail?: "summary" | "findings" | "evidence" | "full";
56
+ evidence?: PulseResult | null;
42
57
  findings: FindingList;
43
58
  maxFindings?: number;
59
+ maxBytes?: number;
44
60
  maxPreConsentRows?: number;
45
- preConsentCookiesTrackers: PreConsentCookiesTrackers;
46
- report: PulseResult;
61
+ preConsentCookiesTrackers?: PreConsentCookiesTrackers | null;
62
+ report: PulseResult | null;
47
63
  scan: ScanResource;
48
- }): {
49
- type: string;
50
- scanId: string;
51
- status: import("packages/certscore-sdk/dist/types.js").PulseJobStatus;
52
- resultDisposition: "no_go" | null;
53
- noGo: import("@certscore/sdk").ScanNoGoResult | null;
54
- scan: ScanResource;
55
- summary: {
56
- summary: {} | null;
57
- executiveSummary: {} | null;
58
- counts: {} | null;
59
- coverage: {} | null;
60
- agentInterpretation: {} | null;
61
- };
62
- findings: import("packages/certscore-sdk/dist/types.js").FindingSummary[];
63
- findingsMetadata: {
64
- shown: number;
65
- total: number;
66
- truncated: boolean;
67
- };
68
- evidenceSummary: {
69
- evidenceSafetyNotes: {} | null;
70
- projectionDiagnostics: {} | null;
71
- projectedFindings: unknown;
72
- coverageDiagnostics: unknown;
73
- policySurfaceCoverage: unknown;
74
- };
75
- preConsentCookiesTrackers: {
76
- summary: {
77
- [key: string]: unknown;
78
- rowCount: number;
79
- trackerCount: number;
80
- cookieCount: number;
81
- requestCount: number;
82
- totalRowCount?: number;
83
- truncated?: boolean;
84
- };
85
- rows: import("packages/certscore-sdk/dist/types.js").PreConsentCookiesTrackersRow[];
86
- shown: number;
87
- total: number;
88
- truncated: boolean;
89
- };
90
- links: {
91
- [key: string]: string | undefined;
92
- self?: string;
93
- status?: string;
94
- findings?: string;
95
- pulse?: string;
96
- report?: string;
97
- latestDomainScan?: string;
98
- docs?: string;
99
- };
100
- recommendedNextTool: string | null;
101
- disclaimer: string | null;
102
- };
64
+ }): Record<string, any>;
103
65
  export declare function explainFinding(report: PulseResult, findingId: string): {
104
66
  type: string;
105
67
  scanId: string | null;
@@ -143,4 +105,5 @@ export declare function explainFinding(report: PulseResult, findingId: string):
143
105
  message?: undefined;
144
106
  availableFindingIds?: undefined;
145
107
  };
108
+ export {};
146
109
  //# sourceMappingURL=tools.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,EAAkB,KAAK,WAAW,EAAE,KAAK,SAAS,EAAE,KAAK,yBAAyB,EAAE,KAAK,WAAW,EAAE,KAAK,WAAW,EAAE,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAG5M,eAAO,MAAM,yBAAyB,SAAU,CAAC;AAKjD,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,cAAc,CAa7D;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,CA0B1D;AAED,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,kBAAkB,SAA4B,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA0C9H;AA6ID,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,WAAW,CAE5E;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,WAAW,CAE5E;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,iBAEjD;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,iBAGlD;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,GAAG,UAAU,EAAE,CAQpE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW;;;;;;;;;;;;;;;;;;;;EAsBjD;AAED,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnE,OAAO,EAAE,CAAC,EACV,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAChD,CAAC,CAoBH;AAED,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnE,OAAO,EAAE,CAAC,EACV,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GACjC,CAAC,CAiBH;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE;IACrC,QAAQ,EAAE,WAAW,CAAC;IACtB,QAAQ,EAAE,WAAW,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,yBAAyB,EAAE,yBAAyB,CAAC;IACrD,MAAM,EAAE,WAAW,CAAC;IACpB,IAAI,EAAE,YAAY,CAAC;CACpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmEA;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiCpE"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}