@sudobility/testomniac_runner_service 0.1.171 → 0.1.173
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/browser/performance-snapshot.d.ts +27 -0
- package/dist/browser/performance-snapshot.d.ts.map +1 -0
- package/dist/browser/performance-snapshot.js +75 -0
- package/dist/browser/performance-snapshot.js.map +1 -0
- package/dist/expertise/accessibility-expertise.d.ts +4 -0
- package/dist/expertise/accessibility-expertise.d.ts.map +1 -1
- package/dist/expertise/accessibility-expertise.js +132 -1
- package/dist/expertise/accessibility-expertise.js.map +1 -1
- package/dist/expertise/content-expertise.d.ts +5 -0
- package/dist/expertise/content-expertise.d.ts.map +1 -1
- package/dist/expertise/content-expertise.js +193 -1
- package/dist/expertise/content-expertise.js.map +1 -1
- package/dist/expertise/page-health-outcomes.d.ts +5 -0
- package/dist/expertise/page-health-outcomes.d.ts.map +1 -0
- package/dist/expertise/page-health-outcomes.js +16 -0
- package/dist/expertise/page-health-outcomes.js.map +1 -0
- package/dist/expertise/performance-expertise.d.ts +10 -0
- package/dist/expertise/performance-expertise.d.ts.map +1 -1
- package/dist/expertise/performance-expertise.js +245 -1
- package/dist/expertise/performance-expertise.js.map +1 -1
- package/dist/expertise/rule-id.d.ts +4 -0
- package/dist/expertise/rule-id.d.ts.map +1 -0
- package/dist/expertise/rule-id.js +7 -0
- package/dist/expertise/rule-id.js.map +1 -0
- package/dist/expertise/security-expertise.d.ts +4 -0
- package/dist/expertise/security-expertise.d.ts.map +1 -1
- package/dist/expertise/security-expertise.js +116 -1
- package/dist/expertise/security-expertise.js.map +1 -1
- package/dist/expertise/seo-expertise.d.ts +7 -0
- package/dist/expertise/seo-expertise.d.ts.map +1 -1
- package/dist/expertise/seo-expertise.js +169 -6
- package/dist/expertise/seo-expertise.js.map +1 -1
- package/dist/expertise/tester-expertise.d.ts.map +1 -1
- package/dist/expertise/tester-expertise.js +96 -41
- package/dist/expertise/tester-expertise.js.map +1 -1
- package/dist/expertise/types.d.ts +6 -1
- package/dist/expertise/types.d.ts.map +1 -1
- package/dist/expertise/ui-expertise.d.ts +4 -0
- package/dist/expertise/ui-expertise.d.ts.map +1 -1
- package/dist/expertise/ui-expertise.js +103 -1
- package/dist/expertise/ui-expertise.js.map +1 -1
- package/dist/orchestrator/runner.d.ts.map +1 -1
- package/dist/orchestrator/runner.js +0 -13
- package/dist/orchestrator/runner.js.map +1 -1
- package/dist/orchestrator/test-interaction-executor.d.ts.map +1 -1
- package/dist/orchestrator/test-interaction-executor.js +60 -70
- package/dist/orchestrator/test-interaction-executor.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type ExpertiseRuleId } from "@sudobility/testomniac_types";
|
|
2
|
+
import type { PageHealthIssue } from "../scanner/page-health-evaluator";
|
|
3
|
+
import type { Outcome } from "./types";
|
|
4
|
+
export declare function outcomesFromPageHealth(issues: PageHealthIssue[] | undefined, ruleIdsByType: Readonly<Partial<Record<PageHealthIssue["type"], ExpertiseRuleId>>>): Outcome[];
|
|
5
|
+
//# sourceMappingURL=page-health-outcomes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-health-outcomes.d.ts","sourceRoot":"","sources":["../../src/expertise/page-health-outcomes.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEvC,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,eAAe,EAAE,GAAG,SAAS,EACrC,aAAa,EAAE,QAAQ,CACrB,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,eAAe,CAAC,CAAC,CAC1D,GACA,OAAO,EAAE,CAcX"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ExpectationSeverity, } from "@sudobility/testomniac_types";
|
|
2
|
+
export function outcomesFromPageHealth(issues, ruleIdsByType) {
|
|
3
|
+
return (issues ?? [])
|
|
4
|
+
.filter(issue => ruleIdsByType[issue.type])
|
|
5
|
+
.map(issue => ({
|
|
6
|
+
ruleId: ruleIdsByType[issue.type],
|
|
7
|
+
expected: issue.title,
|
|
8
|
+
observed: issue.description,
|
|
9
|
+
result: issue.severity,
|
|
10
|
+
severity: issue.severity === "error"
|
|
11
|
+
? ExpectationSeverity.MustPass
|
|
12
|
+
: ExpectationSeverity.ShouldPass,
|
|
13
|
+
priority: issue.priority,
|
|
14
|
+
}));
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=page-health-outcomes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-health-outcomes.js","sourceRoot":"","sources":["../../src/expertise/page-health-outcomes.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,GAEpB,MAAM,8BAA8B,CAAC;AAItC,MAAM,UAAU,sBAAsB,CACpC,MAAqC,EACrC,aAEC;IAED,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC;SAClB,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;SAC1C,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACb,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC;QACjC,QAAQ,EAAE,KAAK,CAAC,KAAK;QACrB,QAAQ,EAAE,KAAK,CAAC,WAAW;QAC3B,MAAM,EAAE,KAAK,CAAC,QAAQ;QACtB,QAAQ,EACN,KAAK,CAAC,QAAQ,KAAK,OAAO;YACxB,CAAC,CAAC,mBAAmB,CAAC,QAAQ;YAC9B,CAAC,CAAC,mBAAmB,CAAC,UAAU;QACpC,QAAQ,EAAE,KAAK,CAAC,QAAQ;KACzB,CAAC,CAAC,CAAC;AACR,CAAC"}
|
|
@@ -6,5 +6,15 @@ import type { Expertise, ExpertiseContext, Outcome } from "./types";
|
|
|
6
6
|
export declare class PerformanceExpertise implements Expertise {
|
|
7
7
|
name: string;
|
|
8
8
|
evaluate(context: ExpertiseContext): Outcome[];
|
|
9
|
+
private checkRenderBlockingCount;
|
|
10
|
+
private checkDomSize;
|
|
11
|
+
private checkHtmlPayloadSize;
|
|
12
|
+
private checkDuplicateStaticDownloads;
|
|
13
|
+
private checkNavigationTiming;
|
|
14
|
+
private checkTransferBudget;
|
|
15
|
+
private checkSlowResourceTiming;
|
|
16
|
+
private checkLargestResources;
|
|
17
|
+
private checkBrowserDuplicateResources;
|
|
18
|
+
private checkBrowserRenderBlockingResources;
|
|
9
19
|
}
|
|
10
20
|
//# sourceMappingURL=performance-expertise.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"performance-expertise.d.ts","sourceRoot":"","sources":["../../src/expertise/performance-expertise.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"performance-expertise.d.ts","sourceRoot":"","sources":["../../src/expertise/performance-expertise.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AA4CpE;;;GAGG;AACH,qBAAa,oBAAqB,YAAW,SAAS;IACpD,IAAI,SAAiB;IAErB,QAAQ,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,EAAE;IAqF9C,OAAO,CAAC,wBAAwB;IAiBhC,OAAO,CAAC,YAAY;IAkBpB,OAAO,CAAC,oBAAoB;IAkB5B,OAAO,CAAC,6BAA6B;IA+BrC,OAAO,CAAC,qBAAqB;IAyC7B,OAAO,CAAC,mBAAmB;IAqC3B,OAAO,CAAC,uBAAuB;IAmB/B,OAAO,CAAC,qBAAqB;IAsB7B,OAAO,CAAC,8BAA8B;IAmBtC,OAAO,CAAC,mCAAmC;CAoB5C"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { ExpertiseRuleId } from "@sudobility/testomniac_types";
|
|
2
|
+
import { applyRuleIds } from "./rule-id";
|
|
1
3
|
const RENDER_BLOCKING_TYPES = [
|
|
2
4
|
"text/html",
|
|
3
5
|
"text/css",
|
|
@@ -5,6 +7,23 @@ const RENDER_BLOCKING_TYPES = [
|
|
|
5
7
|
"text/javascript",
|
|
6
8
|
];
|
|
7
9
|
const THRESHOLD_MS = 500;
|
|
10
|
+
const PERFORMANCE_RULE_IDS = {
|
|
11
|
+
[`Render-blocking resource should respond within ${THRESHOLD_MS}ms`]: ExpertiseRuleId.PerformanceRenderBlockingResponse,
|
|
12
|
+
[`All render-blocking resources should respond within ${THRESHOLD_MS}ms`]: ExpertiseRuleId.PerformanceRenderBlockingResponse,
|
|
13
|
+
"Pages should limit render-blocking resources": ExpertiseRuleId.PerformanceRenderBlockingCount,
|
|
14
|
+
"DOM size should stay within a reasonable budget": ExpertiseRuleId.PerformanceDomSize,
|
|
15
|
+
"Initial HTML payload should not be excessively large": ExpertiseRuleId.PerformanceHtmlPayloadSize,
|
|
16
|
+
"Static resources should not be downloaded repeatedly": ExpertiseRuleId.PerformanceDuplicateStaticDownloads,
|
|
17
|
+
"Mutation requests should not be duplicated": ExpertiseRuleId.PerformanceDuplicateMutationRequests,
|
|
18
|
+
"Network responses should complete within 3 seconds": ExpertiseRuleId.PerformanceSlowNetworkResponses,
|
|
19
|
+
"Browser navigation timing should be available": ExpertiseRuleId.PerformanceNavigationTiming,
|
|
20
|
+
"Core page lifecycle timings should stay responsive": ExpertiseRuleId.PerformanceNavigationTiming,
|
|
21
|
+
"Transferred page resources should stay within a reasonable budget": ExpertiseRuleId.PerformanceTransferBudget,
|
|
22
|
+
"Individual resources should not take more than 1.5 seconds": ExpertiseRuleId.PerformanceSlowResourceTiming,
|
|
23
|
+
"Single resources should not dominate page weight": ExpertiseRuleId.PerformanceLargestResources,
|
|
24
|
+
"Browser resource timing should not show repeated downloads": ExpertiseRuleId.PerformanceBrowserDuplicateResources,
|
|
25
|
+
"Browser should not report excessive render-blocking resources": ExpertiseRuleId.PerformanceBrowserRenderBlockingResources,
|
|
26
|
+
};
|
|
8
27
|
/**
|
|
9
28
|
* Checks network log timing to ensure render-blocking content
|
|
10
29
|
* is returned within the threshold (500ms).
|
|
@@ -37,6 +56,16 @@ export class PerformanceExpertise {
|
|
|
37
56
|
priority: 1,
|
|
38
57
|
});
|
|
39
58
|
}
|
|
59
|
+
outcomes.push(this.checkRenderBlockingCount(renderBlockingLogs.length));
|
|
60
|
+
outcomes.push(this.checkDomSize(context.html));
|
|
61
|
+
outcomes.push(this.checkHtmlPayloadSize(context.html));
|
|
62
|
+
outcomes.push(this.checkDuplicateStaticDownloads(context));
|
|
63
|
+
outcomes.push(this.checkNavigationTiming(context));
|
|
64
|
+
outcomes.push(this.checkTransferBudget(context));
|
|
65
|
+
outcomes.push(this.checkSlowResourceTiming(context));
|
|
66
|
+
outcomes.push(this.checkLargestResources(context));
|
|
67
|
+
outcomes.push(this.checkBrowserDuplicateResources(context));
|
|
68
|
+
outcomes.push(this.checkBrowserRenderBlockingResources(context));
|
|
40
69
|
// Check for duplicate mutation requests (same POST/PUT/PATCH/DELETE URL)
|
|
41
70
|
const mutationCounts = new Map();
|
|
42
71
|
for (const log of context.networkLogs) {
|
|
@@ -66,7 +95,222 @@ export class PerformanceExpertise {
|
|
|
66
95
|
priority: 3,
|
|
67
96
|
});
|
|
68
97
|
}
|
|
69
|
-
return outcomes;
|
|
98
|
+
return applyRuleIds(outcomes, PERFORMANCE_RULE_IDS);
|
|
99
|
+
}
|
|
100
|
+
checkRenderBlockingCount(count) {
|
|
101
|
+
if (count > 20) {
|
|
102
|
+
return {
|
|
103
|
+
expected: "Pages should limit render-blocking resources",
|
|
104
|
+
observed: `${count} render-blocking resource(s) were detected`,
|
|
105
|
+
result: "warning",
|
|
106
|
+
priority: 3,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
expected: "Pages should limit render-blocking resources",
|
|
111
|
+
observed: `${count} render-blocking resource(s) detected`,
|
|
112
|
+
result: "pass",
|
|
113
|
+
priority: 3,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
checkDomSize(html) {
|
|
117
|
+
const nodeCount = (html.match(/<\w[\s>]/g) ?? []).length;
|
|
118
|
+
if (nodeCount > 2500) {
|
|
119
|
+
return {
|
|
120
|
+
expected: "DOM size should stay within a reasonable budget",
|
|
121
|
+
observed: `HTML contains roughly ${nodeCount} element nodes`,
|
|
122
|
+
result: "warning",
|
|
123
|
+
priority: 3,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
expected: "DOM size should stay within a reasonable budget",
|
|
128
|
+
observed: `HTML contains roughly ${nodeCount} element nodes`,
|
|
129
|
+
result: "pass",
|
|
130
|
+
priority: 3,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
checkHtmlPayloadSize(html) {
|
|
134
|
+
const bytes = new TextEncoder().encode(html).length;
|
|
135
|
+
if (bytes > 750_000) {
|
|
136
|
+
return {
|
|
137
|
+
expected: "Initial HTML payload should not be excessively large",
|
|
138
|
+
observed: `HTML payload is approximately ${Math.round(bytes / 1024)} KB`,
|
|
139
|
+
result: "warning",
|
|
140
|
+
priority: 3,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
expected: "Initial HTML payload should not be excessively large",
|
|
145
|
+
observed: `HTML payload is approximately ${Math.round(bytes / 1024)} KB`,
|
|
146
|
+
result: "pass",
|
|
147
|
+
priority: 3,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
checkDuplicateStaticDownloads(context) {
|
|
151
|
+
const counts = new Map();
|
|
152
|
+
for (const log of context.networkLogs) {
|
|
153
|
+
if (log.method !== "GET")
|
|
154
|
+
continue;
|
|
155
|
+
if (!/\.(css|js|mjs|png|jpe?g|webp|gif|svg|woff2?)(\?|$)/i.test(log.url)) {
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
counts.set(log.url, (counts.get(log.url) ?? 0) + 1);
|
|
159
|
+
}
|
|
160
|
+
const duplicates = Array.from(counts.entries()).filter(([, count]) => count > 1);
|
|
161
|
+
if (duplicates.length > 0) {
|
|
162
|
+
const [url, count] = duplicates[0];
|
|
163
|
+
return {
|
|
164
|
+
expected: "Static resources should not be downloaded repeatedly",
|
|
165
|
+
observed: `${duplicates.length} duplicate static resource(s); ${url.slice(0, 100)} loaded ${count}x`,
|
|
166
|
+
result: "warning",
|
|
167
|
+
priority: 3,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
expected: "Static resources should not be downloaded repeatedly",
|
|
172
|
+
observed: "No duplicate static resource downloads detected",
|
|
173
|
+
result: "pass",
|
|
174
|
+
priority: 3,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
checkNavigationTiming(context) {
|
|
178
|
+
const snapshot = context.performanceSnapshot;
|
|
179
|
+
if (!snapshot) {
|
|
180
|
+
return {
|
|
181
|
+
expected: "Browser navigation timing should be available",
|
|
182
|
+
observed: "No browser performance snapshot was available",
|
|
183
|
+
result: "pass",
|
|
184
|
+
priority: 4,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
const slow = [];
|
|
188
|
+
if (snapshot.ttfbMs != null && snapshot.ttfbMs > 800) {
|
|
189
|
+
slow.push(`TTFB ${snapshot.ttfbMs}ms`);
|
|
190
|
+
}
|
|
191
|
+
if (snapshot.domContentLoadedMs != null &&
|
|
192
|
+
snapshot.domContentLoadedMs > 2500) {
|
|
193
|
+
slow.push(`DOMContentLoaded ${snapshot.domContentLoadedMs}ms`);
|
|
194
|
+
}
|
|
195
|
+
if (snapshot.loadEventMs != null && snapshot.loadEventMs > 5000) {
|
|
196
|
+
slow.push(`load ${snapshot.loadEventMs}ms`);
|
|
197
|
+
}
|
|
198
|
+
if (slow.length > 0) {
|
|
199
|
+
return {
|
|
200
|
+
expected: "Core page lifecycle timings should stay responsive",
|
|
201
|
+
observed: `Slow lifecycle timing(s): ${slow.join(", ")}`,
|
|
202
|
+
result: "warning",
|
|
203
|
+
priority: 2,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
return {
|
|
207
|
+
expected: "Core page lifecycle timings should stay responsive",
|
|
208
|
+
observed: `TTFB ${snapshot.ttfbMs ?? "n/a"}ms, DOMContentLoaded ${snapshot.domContentLoadedMs ?? "n/a"}ms, load ${snapshot.loadEventMs ?? "n/a"}ms`,
|
|
209
|
+
result: "pass",
|
|
210
|
+
priority: 2,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
checkTransferBudget(context) {
|
|
214
|
+
const snapshot = context.performanceSnapshot;
|
|
215
|
+
if (!snapshot || snapshot.totalTransferSizeBytes === 0) {
|
|
216
|
+
return {
|
|
217
|
+
expected: "Transferred page resources should stay within a reasonable budget",
|
|
218
|
+
observed: "No resource transfer-size data was available",
|
|
219
|
+
result: "pass",
|
|
220
|
+
priority: 4,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
const totalKb = Math.round(snapshot.totalTransferSizeBytes / 1024);
|
|
224
|
+
const scriptKb = Math.round(snapshot.scriptTransferSizeBytes / 1024);
|
|
225
|
+
const imageKb = Math.round(snapshot.imageTransferSizeBytes / 1024);
|
|
226
|
+
if (snapshot.totalTransferSizeBytes > 3_000_000 ||
|
|
227
|
+
snapshot.scriptTransferSizeBytes > 1_000_000 ||
|
|
228
|
+
snapshot.imageTransferSizeBytes > 2_000_000) {
|
|
229
|
+
return {
|
|
230
|
+
expected: "Transferred page resources should stay within a reasonable budget",
|
|
231
|
+
observed: `Transferred ${totalKb} KB total (${scriptKb} KB scripts, ${imageKb} KB images)`,
|
|
232
|
+
result: "warning",
|
|
233
|
+
priority: 3,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
return {
|
|
237
|
+
expected: "Transferred page resources should stay within a reasonable budget",
|
|
238
|
+
observed: `Transferred ${totalKb} KB total (${scriptKb} KB scripts, ${imageKb} KB images)`,
|
|
239
|
+
result: "pass",
|
|
240
|
+
priority: 3,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
checkSlowResourceTiming(context) {
|
|
244
|
+
const slow = context.performanceSnapshot?.slowResources ?? [];
|
|
245
|
+
if (slow.length === 0) {
|
|
246
|
+
return {
|
|
247
|
+
expected: "Individual resources should not take more than 1.5 seconds",
|
|
248
|
+
observed: "No slow browser resource timing entries detected",
|
|
249
|
+
result: "pass",
|
|
250
|
+
priority: 3,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
const first = slow[0];
|
|
254
|
+
return {
|
|
255
|
+
expected: "Individual resources should not take more than 1.5 seconds",
|
|
256
|
+
observed: `${slow.length} slow resource(s); slowest ${first.durationMs}ms ${first.name.slice(0, 100)}`,
|
|
257
|
+
result: "warning",
|
|
258
|
+
priority: 3,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
checkLargestResources(context) {
|
|
262
|
+
const largest = context.performanceSnapshot?.largestResources ?? [];
|
|
263
|
+
const oversized = largest.filter(resource => resource.transferSizeBytes > 750_000);
|
|
264
|
+
if (oversized.length === 0) {
|
|
265
|
+
return {
|
|
266
|
+
expected: "Single resources should not dominate page weight",
|
|
267
|
+
observed: "No individual resource over 750 KB detected",
|
|
268
|
+
result: "pass",
|
|
269
|
+
priority: 3,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
const first = oversized[0];
|
|
273
|
+
return {
|
|
274
|
+
expected: "Single resources should not dominate page weight",
|
|
275
|
+
observed: `${oversized.length} oversized resource(s); largest ${Math.round(first.transferSizeBytes / 1024)} KB ${first.name.slice(0, 100)}`,
|
|
276
|
+
result: "warning",
|
|
277
|
+
priority: 3,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
checkBrowserDuplicateResources(context) {
|
|
281
|
+
const duplicates = context.performanceSnapshot?.duplicateResourceUrls ?? [];
|
|
282
|
+
if (duplicates.length === 0) {
|
|
283
|
+
return {
|
|
284
|
+
expected: "Browser resource timing should not show repeated downloads",
|
|
285
|
+
observed: "No duplicate browser resource timing entries detected",
|
|
286
|
+
result: "pass",
|
|
287
|
+
priority: 3,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
const first = duplicates[0];
|
|
291
|
+
return {
|
|
292
|
+
expected: "Browser resource timing should not show repeated downloads",
|
|
293
|
+
observed: `${duplicates.length} duplicated resource URL(s); ${first.url.slice(0, 100)} loaded ${first.count}x`,
|
|
294
|
+
result: "warning",
|
|
295
|
+
priority: 3,
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
checkBrowserRenderBlockingResources(context) {
|
|
299
|
+
const count = context.performanceSnapshot?.renderBlockingResourceCount ?? 0;
|
|
300
|
+
if (count > 10) {
|
|
301
|
+
return {
|
|
302
|
+
expected: "Browser should not report excessive render-blocking resources",
|
|
303
|
+
observed: `${count} browser resource timing entries were marked render-blocking`,
|
|
304
|
+
result: "warning",
|
|
305
|
+
priority: 3,
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
return {
|
|
309
|
+
expected: "Browser should not report excessive render-blocking resources",
|
|
310
|
+
observed: `${count} browser resource timing entries marked render-blocking`,
|
|
311
|
+
result: "pass",
|
|
312
|
+
priority: 3,
|
|
313
|
+
};
|
|
70
314
|
}
|
|
71
315
|
}
|
|
72
316
|
//# sourceMappingURL=performance-expertise.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"performance-expertise.js","sourceRoot":"","sources":["../../src/expertise/performance-expertise.ts"],"names":[],"mappings":"AAEA,MAAM,qBAAqB,GAAG;IAC5B,WAAW;IACX,UAAU;IACV,wBAAwB;IACxB,iBAAiB;CAClB,CAAC;AAEF,MAAM,YAAY,GAAG,GAAG,CAAC;AAEzB;;;GAGG;AACH,MAAM,OAAO,oBAAoB;IAC/B,IAAI,GAAG,aAAa,CAAC;IAErB,QAAQ,CAAC,OAAyB;QAChC,MAAM,QAAQ,GAAc,EAAE,CAAC;QAC/B,MAAM,kBAAkB,GAAG,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC1D,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CACpE,CAAC;QAEF,4DAA4D;QAC5D,oEAAoE;QACpE,mEAAmE;QACnE,kEAAkE;QAClE,MAAM,YAAY,GAAG,kBAAkB,CAAC,MAAM,CAC5C,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,CAC7C,CAAC;QAEF,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;gBAC/B,QAAQ,CAAC,IAAI,CAAC;oBACZ,QAAQ,EAAE,kDAAkD,YAAY,IAAI;oBAC5E,QAAQ,EAAE,iCAAiC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,aAAa,GAAG,CAAC,MAAM,GAAG;oBAC1F,MAAM,EAAE,SAAS;oBACjB,QAAQ,EAAE,CAAC;iBACZ,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,QAAQ,CAAC,IAAI,CAAC;gBACZ,QAAQ,EAAE,uDAAuD,YAAY,IAAI;gBACjF,QAAQ,EAAE,GAAG,kBAAkB,CAAC,MAAM,kDAAkD;gBACxF,MAAM,EAAE,MAAM;gBACd,QAAQ,EAAE,CAAC;aACZ,CAAC,CAAC;QACL,CAAC;QAED,yEAAyE;QACzE,MAAM,cAAc,GAAG,IAAI,GAAG,EAAkB,CAAC;QACjD,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;YACtC,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC5D,MAAM,GAAG,GAAG,GAAG,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,GAAG,EAAE,CAAC;gBACvC,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC;QACD,MAAM,kBAAkB,GAAG,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,CACpE,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,CACzB,CAAC;QACF,IAAI,kBAAkB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClC,MAAM,KAAK,GAAG,kBAAkB,CAAC,CAAC,CAAE,CAAC;YACrC,QAAQ,CAAC,IAAI,CAAC;gBACZ,QAAQ,EAAE,4CAA4C;gBACtD,QAAQ,EAAE,GAAG,kBAAkB,CAAC,MAAM,2BAA2B,KAAK,CAAC,CAAC,CAAC,WAAW,KAAK,CAAC,CAAC,CAAC,GAAG;gBAC/F,MAAM,EAAE,SAAS;gBACjB,QAAQ,EAAE,CAAC;aACZ,CAAC,CAAC;QACL,CAAC;QAED,kCAAkC;QAClC,MAAM,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC,MAAM,CAC9C,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,IAAI,IAAI,IAAI,GAAG,CAAC,WAAW,GAAG,IAAI,CACzD,CAAC;QACF,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAC5C,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CACpD,CAAC;YACF,QAAQ,CAAC,IAAI,CAAC;gBACZ,QAAQ,EAAE,oDAAoD;gBAC9D,QAAQ,EAAE,GAAG,aAAa,CAAC,MAAM,+BAA+B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,OAAO,CAAC,WAAW,KAAK;gBACrH,MAAM,EAAE,SAAS;gBACjB,QAAQ,EAAE,CAAC;aACZ,CAAC,CAAC;QACL,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF"}
|
|
1
|
+
{"version":3,"file":"performance-expertise.js","sourceRoot":"","sources":["../../src/expertise/performance-expertise.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ExpertiseRuleId } from "@sudobility/testomniac_types";
|
|
2
|
+
import type { Outcome } from "./types";
|
|
3
|
+
export declare function applyRuleIds(outcomes: Outcome[], ruleIdsByExpected: Readonly<Record<string, ExpertiseRuleId>>): Outcome[];
|
|
4
|
+
//# sourceMappingURL=rule-id.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-id.d.ts","sourceRoot":"","sources":["../../src/expertise/rule-id.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEvC,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,OAAO,EAAE,EACnB,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,GAC3D,OAAO,EAAE,CAKX"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-id.js","sourceRoot":"","sources":["../../src/expertise/rule-id.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,YAAY,CAC1B,QAAmB,EACnB,iBAA4D;IAE5D,OAAO,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC9B,GAAG,OAAO;QACV,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,iBAAiB,CAAC,OAAO,CAAC,QAAQ,CAAC;KAC9D,CAAC,CAAC,CAAC;AACN,CAAC"}
|
|
@@ -8,7 +8,11 @@ export declare class SecurityExpertise implements Expertise {
|
|
|
8
8
|
evaluate(context: ExpertiseContext): Outcome[];
|
|
9
9
|
private checkApiKeysInUrls;
|
|
10
10
|
private checkInsecureRequests;
|
|
11
|
+
private checkSensitiveDataInUrls;
|
|
12
|
+
private checkMixedContent;
|
|
11
13
|
private checkInsecureFormActions;
|
|
12
14
|
private checkWrongInputTypes;
|
|
15
|
+
private checkPasswordFieldsOnHttps;
|
|
16
|
+
private checkUnsafeBlankTargets;
|
|
13
17
|
}
|
|
14
18
|
//# sourceMappingURL=security-expertise.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security-expertise.d.ts","sourceRoot":"","sources":["../../src/expertise/security-expertise.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"security-expertise.d.ts","sourceRoot":"","sources":["../../src/expertise/security-expertise.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAgCpE;;;GAGG;AACH,qBAAa,iBAAkB,YAAW,SAAS;IACjD,IAAI,SAAc;IAElB,QAAQ,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,EAAE;IAqB9C,OAAO,CAAC,kBAAkB;IA8B1B,OAAO,CAAC,qBAAqB;IA2B7B,OAAO,CAAC,wBAAwB;IA0BhC,OAAO,CAAC,iBAAiB;IA8BzB,OAAO,CAAC,wBAAwB;IAgChC,OAAO,CAAC,oBAAoB;IA+C5B,OAAO,CAAC,0BAA0B;IAgClC,OAAO,CAAC,uBAAuB;CAwBhC"}
|
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
import { ExpertiseRuleId } from "@sudobility/testomniac_types";
|
|
2
|
+
import { outcomesFromPageHealth } from "./page-health-outcomes";
|
|
3
|
+
import { applyRuleIds } from "./rule-id";
|
|
4
|
+
const SECURITY_PAGE_HEALTH_RULE_IDS = {
|
|
5
|
+
missing_noopener: ExpertiseRuleId.SecurityPageHealthNoopener,
|
|
6
|
+
};
|
|
7
|
+
const SECURITY_RULE_IDS = {
|
|
8
|
+
"API keys should not be exposed in URLs": ExpertiseRuleId.SecurityApiKeysInUrls,
|
|
9
|
+
"Sensitive user data should not be sent in URL parameters": ExpertiseRuleId.SecuritySensitiveDataInUrls,
|
|
10
|
+
"All requests should use HTTPS": ExpertiseRuleId.SecurityHttpsRequests,
|
|
11
|
+
"HTTPS pages should not load insecure HTTP subresources": ExpertiseRuleId.SecurityMixedContent,
|
|
12
|
+
"Forms should not submit over insecure HTTP": ExpertiseRuleId.SecurityInsecureFormActions,
|
|
13
|
+
"Forms should not submit over insecure HTTP on HTTPS pages": ExpertiseRuleId.SecurityInsecureFormActions,
|
|
14
|
+
"Password fields should only appear on HTTPS pages": ExpertiseRuleId.SecurityPasswordFieldsHttps,
|
|
15
|
+
"Input fields should use semantic types (email, tel, url) for better validation": ExpertiseRuleId.SecuritySemanticInputTypes,
|
|
16
|
+
'Links opening a new tab should use rel="noopener noreferrer"': ExpertiseRuleId.SecurityBlankTargetRel,
|
|
17
|
+
};
|
|
1
18
|
const API_KEY_PATTERNS = [
|
|
2
19
|
/[?&](api[_-]?key|apikey|key|token|secret|access[_-]?token)=([^&]+)/i,
|
|
3
20
|
/[?&](authorization)=([^&]+)/i,
|
|
@@ -11,10 +28,15 @@ export class SecurityExpertise {
|
|
|
11
28
|
evaluate(context) {
|
|
12
29
|
const outcomes = [];
|
|
13
30
|
outcomes.push(...this.checkApiKeysInUrls(context));
|
|
31
|
+
outcomes.push(...this.checkSensitiveDataInUrls(context));
|
|
14
32
|
outcomes.push(...this.checkInsecureRequests(context));
|
|
33
|
+
outcomes.push(this.checkMixedContent(context));
|
|
15
34
|
outcomes.push(this.checkInsecureFormActions(context));
|
|
35
|
+
outcomes.push(this.checkPasswordFieldsOnHttps(context));
|
|
16
36
|
outcomes.push(this.checkWrongInputTypes(context.html));
|
|
17
|
-
|
|
37
|
+
outcomes.push(this.checkUnsafeBlankTargets(context.html));
|
|
38
|
+
outcomes.push(...outcomesFromPageHealth(context.pageHealthIssues, SECURITY_PAGE_HEALTH_RULE_IDS));
|
|
39
|
+
return applyRuleIds(outcomes, SECURITY_RULE_IDS);
|
|
18
40
|
}
|
|
19
41
|
checkApiKeysInUrls(context) {
|
|
20
42
|
const outcomes = [];
|
|
@@ -63,6 +85,53 @@ export class SecurityExpertise {
|
|
|
63
85
|
},
|
|
64
86
|
];
|
|
65
87
|
}
|
|
88
|
+
checkSensitiveDataInUrls(context) {
|
|
89
|
+
const sensitive = context.networkLogs.filter(log => /[?&](password|pass|pwd|email|session|jwt|id_token)=([^&]+)/i.test(log.url));
|
|
90
|
+
if (sensitive.length === 0) {
|
|
91
|
+
return [
|
|
92
|
+
{
|
|
93
|
+
expected: "Sensitive user data should not be sent in URL parameters",
|
|
94
|
+
observed: "No sensitive query parameters detected in network URLs",
|
|
95
|
+
result: "pass",
|
|
96
|
+
priority: 1,
|
|
97
|
+
},
|
|
98
|
+
];
|
|
99
|
+
}
|
|
100
|
+
return [
|
|
101
|
+
{
|
|
102
|
+
expected: "Sensitive user data should not be sent in URL parameters",
|
|
103
|
+
observed: `${sensitive.length} request(s) include sensitive-looking query parameters; first: ${sensitive[0].url.slice(0, 120)}`,
|
|
104
|
+
result: "error",
|
|
105
|
+
priority: 0,
|
|
106
|
+
},
|
|
107
|
+
];
|
|
108
|
+
}
|
|
109
|
+
checkMixedContent(context) {
|
|
110
|
+
const pageUrl = context.currentUrl || context.initialUrl || "";
|
|
111
|
+
if (!pageUrl.startsWith("https://")) {
|
|
112
|
+
return {
|
|
113
|
+
expected: "HTTPS pages should not load insecure HTTP subresources",
|
|
114
|
+
observed: "Page is not HTTPS, skipping mixed-content check",
|
|
115
|
+
result: "pass",
|
|
116
|
+
priority: 2,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
const insecureSubresources = context.networkLogs.filter(log => log.url.startsWith("http://") && !log.url.startsWith("http://localhost"));
|
|
120
|
+
if (insecureSubresources.length > 0) {
|
|
121
|
+
return {
|
|
122
|
+
expected: "HTTPS pages should not load insecure HTTP subresources",
|
|
123
|
+
observed: `${insecureSubresources.length} insecure subresource request(s); first: ${insecureSubresources[0].url.slice(0, 120)}`,
|
|
124
|
+
result: "warning",
|
|
125
|
+
priority: 2,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
expected: "HTTPS pages should not load insecure HTTP subresources",
|
|
130
|
+
observed: "No mixed-content requests detected",
|
|
131
|
+
result: "pass",
|
|
132
|
+
priority: 2,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
66
135
|
checkInsecureFormActions(context) {
|
|
67
136
|
const pageUrl = context.currentUrl || context.initialUrl || "";
|
|
68
137
|
const isHttps = pageUrl.startsWith("https://");
|
|
@@ -120,5 +189,51 @@ export class SecurityExpertise {
|
|
|
120
189
|
priority: 4,
|
|
121
190
|
};
|
|
122
191
|
}
|
|
192
|
+
checkPasswordFieldsOnHttps(context) {
|
|
193
|
+
const hasPasswordField = /<input\b[^>]*type=["']password["'][^>]*>/i.test(context.html);
|
|
194
|
+
if (!hasPasswordField) {
|
|
195
|
+
return {
|
|
196
|
+
expected: "Password fields should only appear on HTTPS pages",
|
|
197
|
+
observed: "No password fields detected",
|
|
198
|
+
result: "pass",
|
|
199
|
+
priority: 0,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
const pageUrl = context.currentUrl || context.initialUrl || "";
|
|
203
|
+
if (!pageUrl.startsWith("https://") &&
|
|
204
|
+
!pageUrl.startsWith("http://localhost")) {
|
|
205
|
+
return {
|
|
206
|
+
expected: "Password fields should only appear on HTTPS pages",
|
|
207
|
+
observed: `Password field detected on non-HTTPS page: ${pageUrl || "unknown URL"}`,
|
|
208
|
+
result: "error",
|
|
209
|
+
priority: 0,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
return {
|
|
213
|
+
expected: "Password fields should only appear on HTTPS pages",
|
|
214
|
+
observed: "Password fields are on HTTPS or localhost",
|
|
215
|
+
result: "pass",
|
|
216
|
+
priority: 0,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
checkUnsafeBlankTargets(html) {
|
|
220
|
+
const blankLinks = html.match(/<a\b[^>]*target=["']_blank["'][^>]*>/gi) ?? [];
|
|
221
|
+
const unsafe = blankLinks.filter(link => !/\brel=["'][^"']*\bnoopener\b/i.test(link) ||
|
|
222
|
+
!/\brel=["'][^"']*\bnoreferrer\b/i.test(link));
|
|
223
|
+
if (unsafe.length > 0) {
|
|
224
|
+
return {
|
|
225
|
+
expected: 'Links opening a new tab should use rel="noopener noreferrer"',
|
|
226
|
+
observed: `${unsafe.length} target="_blank" link(s) are missing noopener or noreferrer`,
|
|
227
|
+
result: "warning",
|
|
228
|
+
priority: 3,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
return {
|
|
232
|
+
expected: 'Links opening a new tab should use rel="noopener noreferrer"',
|
|
233
|
+
observed: "All new-tab links include safe rel attributes",
|
|
234
|
+
result: "pass",
|
|
235
|
+
priority: 3,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
123
238
|
}
|
|
124
239
|
//# sourceMappingURL=security-expertise.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security-expertise.js","sourceRoot":"","sources":["../../src/expertise/security-expertise.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"security-expertise.js","sourceRoot":"","sources":["../../src/expertise/security-expertise.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,9 +6,16 @@ import type { Expertise, ExpertiseContext, Outcome } from "./types";
|
|
|
6
6
|
export declare class SeoExpertise implements Expertise {
|
|
7
7
|
name: string;
|
|
8
8
|
evaluate(context: ExpertiseContext): Outcome[];
|
|
9
|
+
private extractTitle;
|
|
10
|
+
private extractMetaContent;
|
|
9
11
|
private checkTag;
|
|
10
12
|
private checkMetaTag;
|
|
11
13
|
private checkLinkTag;
|
|
12
14
|
private checkMetaProperty;
|
|
15
|
+
private checkTitleLength;
|
|
16
|
+
private checkMetaDescriptionLength;
|
|
17
|
+
private checkCanonicalTarget;
|
|
18
|
+
private checkRobotsIndexability;
|
|
19
|
+
private checkDescriptiveAnchors;
|
|
13
20
|
}
|
|
14
21
|
//# sourceMappingURL=seo-expertise.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"seo-expertise.d.ts","sourceRoot":"","sources":["../../src/expertise/seo-expertise.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"seo-expertise.d.ts","sourceRoot":"","sources":["../../src/expertise/seo-expertise.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AA0BpE;;;GAGG;AACH,qBAAa,YAAa,YAAW,SAAS;IAC5C,IAAI,SAAS;IAEb,QAAQ,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,EAAE;IAqB9C,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,kBAAkB;IAY1B,OAAO,CAAC,QAAQ;IAkBhB,OAAO,CAAC,YAAY;IAkBpB,OAAO,CAAC,YAAY;IAsBpB,OAAO,CAAC,iBAAiB;IA0BzB,OAAO,CAAC,gBAAgB;IA0BxB,OAAO,CAAC,0BAA0B;IA0BlC,OAAO,CAAC,oBAAoB;IA2C5B,OAAO,CAAC,uBAAuB;IA0B/B,OAAO,CAAC,uBAAuB;CAyBhC"}
|