lighthouse 13.4.1 → 13.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. package/build-tracker.config.js +1 -1
  2. package/cli/test/smokehouse/lighthouse-runners/bundle.js +3 -3
  3. package/cli/test/smokehouse/lighthouse-runners/devtools-mcp.js +2 -1
  4. package/core/audits/accessibility/accesskeys.js +1 -1
  5. package/core/audits/accessibility/aria-allowed-attr.js +1 -1
  6. package/core/audits/accessibility/aria-allowed-role.js +1 -1
  7. package/core/audits/accessibility/aria-command-name.js +1 -1
  8. package/core/audits/accessibility/aria-conditional-attr.js +1 -1
  9. package/core/audits/accessibility/aria-deprecated-role.js +1 -1
  10. package/core/audits/accessibility/aria-dialog-name.js +1 -1
  11. package/core/audits/accessibility/aria-hidden-body.js +1 -1
  12. package/core/audits/accessibility/aria-hidden-focus.js +1 -1
  13. package/core/audits/accessibility/aria-input-field-name.js +1 -1
  14. package/core/audits/accessibility/aria-meter-name.js +1 -1
  15. package/core/audits/accessibility/aria-progressbar-name.js +1 -1
  16. package/core/audits/accessibility/aria-prohibited-attr.js +1 -1
  17. package/core/audits/accessibility/aria-required-attr.js +1 -1
  18. package/core/audits/accessibility/aria-required-children.js +1 -1
  19. package/core/audits/accessibility/aria-required-parent.js +1 -1
  20. package/core/audits/accessibility/aria-roles.js +1 -1
  21. package/core/audits/accessibility/aria-text.js +1 -1
  22. package/core/audits/accessibility/aria-toggle-field-name.js +1 -1
  23. package/core/audits/accessibility/aria-tooltip-name.js +1 -1
  24. package/core/audits/accessibility/aria-treeitem-name.js +1 -1
  25. package/core/audits/accessibility/aria-valid-attr-value.js +1 -1
  26. package/core/audits/accessibility/aria-valid-attr.js +1 -1
  27. package/core/audits/accessibility/autocomplete-valid.js +1 -1
  28. package/core/audits/accessibility/button-name.js +1 -1
  29. package/core/audits/accessibility/bypass.js +1 -1
  30. package/core/audits/accessibility/color-contrast.js +1 -1
  31. package/core/audits/accessibility/definition-list.js +1 -1
  32. package/core/audits/accessibility/dlitem.js +1 -1
  33. package/core/audits/accessibility/document-title.js +1 -1
  34. package/core/audits/accessibility/duplicate-id-aria.js +1 -1
  35. package/core/audits/accessibility/empty-heading.js +1 -1
  36. package/core/audits/accessibility/form-field-multiple-labels.js +1 -1
  37. package/core/audits/accessibility/frame-title.js +1 -1
  38. package/core/audits/accessibility/heading-order.js +1 -1
  39. package/core/audits/accessibility/html-has-lang.js +1 -1
  40. package/core/audits/accessibility/html-lang-valid.js +1 -1
  41. package/core/audits/accessibility/html-xml-lang-mismatch.js +1 -1
  42. package/core/audits/accessibility/identical-links-same-purpose.js +1 -1
  43. package/core/audits/accessibility/image-alt.js +1 -1
  44. package/core/audits/accessibility/image-redundant-alt.js +1 -1
  45. package/core/audits/accessibility/input-button-name.js +1 -1
  46. package/core/audits/accessibility/input-image-alt.js +1 -1
  47. package/core/audits/accessibility/label-content-name-mismatch.js +1 -1
  48. package/core/audits/accessibility/label.js +1 -1
  49. package/core/audits/accessibility/landmark-one-main.js +1 -1
  50. package/core/audits/accessibility/link-in-text-block.js +1 -1
  51. package/core/audits/accessibility/link-name.js +1 -1
  52. package/core/audits/accessibility/list.js +1 -1
  53. package/core/audits/accessibility/listitem.js +1 -1
  54. package/core/audits/accessibility/meta-refresh.js +1 -1
  55. package/core/audits/accessibility/meta-viewport.js +1 -1
  56. package/core/audits/accessibility/object-alt.js +1 -1
  57. package/core/audits/accessibility/presentation-role-conflict.js +1 -1
  58. package/core/audits/accessibility/select-name.js +1 -1
  59. package/core/audits/accessibility/skip-link.js +1 -1
  60. package/core/audits/accessibility/svg-img-alt.js +1 -1
  61. package/core/audits/accessibility/tabindex.js +1 -1
  62. package/core/audits/accessibility/table-duplicate-name.js +1 -1
  63. package/core/audits/accessibility/table-fake-caption.js +1 -1
  64. package/core/audits/accessibility/target-size.js +1 -1
  65. package/core/audits/accessibility/td-has-header.js +1 -1
  66. package/core/audits/accessibility/td-headers-attr.js +1 -1
  67. package/core/audits/accessibility/th-has-data-cells.js +1 -1
  68. package/core/audits/accessibility/valid-lang.js +1 -1
  69. package/core/audits/accessibility/video-caption.js +1 -1
  70. package/core/audits/agentic/ard-schema.d.ts +19 -0
  71. package/core/audits/agentic/ard-schema.js +135 -0
  72. package/core/audits/baseline.d.ts +23 -10
  73. package/core/audits/deprecations.js +1 -2
  74. package/core/audits/webmcp-form-coverage.js +3 -1
  75. package/core/audits/webmcp-registered-tools.d.ts +2 -0
  76. package/core/audits/webmcp-registered-tools.js +16 -1
  77. package/core/audits/webmcp-schema-validity.js +1 -1
  78. package/core/computed/metrics/interactive.js +1 -1
  79. package/core/computed/metrics/lantern-metric.js +1 -1
  80. package/core/computed/trace-engine-result.d.ts +3 -3
  81. package/core/computed/trace-engine-result.js +4 -4
  82. package/core/computed/unused-javascript-summary.d.ts +0 -1
  83. package/core/computed/unused-javascript-summary.js +0 -1
  84. package/core/config/agentic-browsing-config.d.ts +2 -0
  85. package/core/config/agentic-browsing-config.js +13 -1
  86. package/core/config/default-config.js +13 -1
  87. package/core/config/validation.js +6 -0
  88. package/core/gather/driver/execution-context.js +0 -2
  89. package/core/gather/driver/navigation.d.ts +1 -0
  90. package/core/gather/driver/navigation.js +35 -7
  91. package/core/gather/driver/wait-for-condition.d.ts +5 -7
  92. package/core/gather/driver/wait-for-condition.js +15 -9
  93. package/core/gather/fetcher.d.ts +9 -2
  94. package/core/gather/fetcher.js +30 -4
  95. package/core/gather/gatherers/accessibility.js +1 -3
  96. package/core/gather/gatherers/agentic/ard.d.ts +30 -0
  97. package/core/gather/gatherers/agentic/ard.js +125 -0
  98. package/core/gather/gatherers/anchor-elements.js +0 -2
  99. package/core/gather/gatherers/full-page-screenshot.js +0 -4
  100. package/core/gather/gatherers/iframe-elements.js +0 -2
  101. package/core/gather/gatherers/image-elements.js +1 -13
  102. package/core/gather/gatherers/inputs.js +0 -2
  103. package/core/gather/gatherers/link-elements.js +0 -2
  104. package/core/gather/gatherers/meta-elements.js +0 -3
  105. package/core/gather/gatherers/seo/robots-txt.d.ts +1 -0
  106. package/core/gather/gatherers/seo/robots-txt.js +3 -0
  107. package/core/gather/gatherers/stacks.d.ts +1 -1
  108. package/core/gather/gatherers/stacks.js +1 -3
  109. package/core/gather/gatherers/trace-elements.js +1 -3
  110. package/core/gather/gatherers/viewport-dimensions.js +0 -2
  111. package/core/gather/navigation-runner.d.ts +3 -1
  112. package/core/gather/navigation-runner.js +6 -3
  113. package/core/gather/session.js +1 -0
  114. package/core/index.cjs +5 -5
  115. package/core/index.d.cts +5 -5
  116. package/core/lib/arbitrary-equality-map.d.ts +2 -2
  117. package/core/lib/arbitrary-equality-map.js +1 -1
  118. package/core/lib/baseline/web-features-data.json +52 -28
  119. package/core/lib/baseline/web-features-metadata.json +1 -1
  120. package/core/lib/deprecation-description.js +1 -1
  121. package/core/lib/page-functions.d.ts +0 -3
  122. package/core/lib/page-functions.js +0 -3
  123. package/core/lib/rect-helpers.js +0 -8
  124. package/core/runner.js +21 -0
  125. package/core/user-flow.d.ts +3 -0
  126. package/core/user-flow.js +12 -0
  127. package/dist/report/bundle.esm.js +10 -3
  128. package/dist/report/flow.js +20 -13
  129. package/dist/report/standalone.js +10 -3
  130. package/package.json +19 -14
  131. package/report/assets/styles.css +7 -0
  132. package/report/renderer/components.js +1 -1
  133. package/report/renderer/details-renderer.js +7 -5
  134. package/report/renderer/drop-down-menu.d.ts +2 -2
  135. package/report/renderer/drop-down-menu.js +1 -1
  136. package/report/renderer/report-renderer.js +24 -3
  137. package/report/renderer/report-utils.js +1 -1
  138. package/report/renderer/snippet-renderer.d.ts +4 -4
  139. package/report/renderer/snippet-renderer.js +3 -3
  140. package/report/renderer/text-encoding.js +2 -2
  141. package/shared/localization/locales/ar-XB.json +111 -72
  142. package/shared/localization/locales/ar.json +113 -74
  143. package/shared/localization/locales/bg.json +112 -73
  144. package/shared/localization/locales/ca.json +112 -73
  145. package/shared/localization/locales/cs.json +112 -73
  146. package/shared/localization/locales/da.json +112 -73
  147. package/shared/localization/locales/de.json +112 -73
  148. package/shared/localization/locales/el.json +112 -73
  149. package/shared/localization/locales/en-GB.json +111 -72
  150. package/shared/localization/locales/en-US.json +102 -66
  151. package/shared/localization/locales/en-XA.json +111 -72
  152. package/shared/localization/locales/en-XL.json +102 -66
  153. package/shared/localization/locales/es-419.json +112 -73
  154. package/shared/localization/locales/es.json +112 -73
  155. package/shared/localization/locales/fi.json +112 -73
  156. package/shared/localization/locales/fil.json +112 -73
  157. package/shared/localization/locales/fr.json +112 -73
  158. package/shared/localization/locales/he.json +112 -73
  159. package/shared/localization/locales/hi.json +112 -73
  160. package/shared/localization/locales/hr.json +112 -73
  161. package/shared/localization/locales/hu.json +112 -73
  162. package/shared/localization/locales/id.json +112 -73
  163. package/shared/localization/locales/it.json +113 -74
  164. package/shared/localization/locales/ja.json +112 -73
  165. package/shared/localization/locales/ko.json +112 -73
  166. package/shared/localization/locales/lt.json +112 -73
  167. package/shared/localization/locales/lv.json +112 -73
  168. package/shared/localization/locales/nl.json +112 -73
  169. package/shared/localization/locales/no.json +112 -73
  170. package/shared/localization/locales/pl.json +112 -73
  171. package/shared/localization/locales/pt-PT.json +112 -73
  172. package/shared/localization/locales/pt.json +112 -73
  173. package/shared/localization/locales/ro.json +112 -73
  174. package/shared/localization/locales/ru.json +112 -73
  175. package/shared/localization/locales/sk.json +112 -73
  176. package/shared/localization/locales/sl.json +112 -73
  177. package/shared/localization/locales/sr-Latn.json +112 -73
  178. package/shared/localization/locales/sr.json +112 -73
  179. package/shared/localization/locales/sv.json +124 -85
  180. package/shared/localization/locales/ta.json +112 -73
  181. package/shared/localization/locales/te.json +112 -73
  182. package/shared/localization/locales/th.json +112 -73
  183. package/shared/localization/locales/tr.json +113 -74
  184. package/shared/localization/locales/uk.json +112 -73
  185. package/shared/localization/locales/vi.json +112 -73
  186. package/shared/localization/locales/zh-HK.json +112 -73
  187. package/shared/localization/locales/zh-TW.json +113 -74
  188. package/shared/localization/locales/zh.json +113 -74
  189. package/shared/util.d.ts +6 -0
  190. package/shared/util.js +9 -0
  191. package/third-party/ard/LICENSE +201 -0
  192. package/third-party/ard/README.md +27 -0
  193. package/third-party/ard/ard-test.d.ts +2 -0
  194. package/third-party/ard/ard-test.js +358 -0
  195. package/third-party/ard/ard.d.ts +34 -0
  196. package/third-party/ard/ard.js +204 -0
  197. package/third-party/ard/schema-validator.d.ts +20 -0
  198. package/third-party/ard/schema-validator.js +1700 -0
  199. package/third-party/ard/spec/schemas/ai-catalog.schema.json +292 -0
  200. package/tsconfig.json +1 -0
  201. package/types/artifacts.d.ts +14 -0
@@ -0,0 +1,204 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import log from 'lighthouse-logger';
8
+ import validateAiCatalog from './schema-validator.js';
9
+
10
+ // Strict URN Regex matching urn:air:<publisher>:<namespace>:<agent-name>
11
+ const URN_REGEX = /^urn:air:([a-zA-Z0-9.-]+)(?::([a-zA-Z0-9._:-]+))?:([a-zA-Z0-9._-]+)$/;
12
+
13
+ /**
14
+ * @typedef {{
15
+ * element: string,
16
+ * message: string,
17
+ * }} ValidationError
18
+ */
19
+
20
+ class ConformanceTester {
21
+ constructor() {
22
+ /** @type {ValidationError[]} */
23
+ this.errors = [];
24
+ /** @type {ValidationError[]} */
25
+ this.warnings = [];
26
+ }
27
+
28
+ /**
29
+ * @param {string} message
30
+ * @param {string} [element='Root']
31
+ */
32
+ add_error(message, element = 'Root') {
33
+ this.errors.push({element, message});
34
+ log.verbose('ARD', `Validation Error [${element}]: ${message}`);
35
+ }
36
+
37
+ /**
38
+ * @param {string} message
39
+ * @param {string} [element='Root']
40
+ */
41
+ add_warning(message, element = 'Root') {
42
+ this.warnings.push({element, message});
43
+ log.verbose('ARD', `Validation Warning [${element}]: ${message}`);
44
+ }
45
+
46
+ /** @param {any} manifest_data */
47
+ run_json_schema_validation(manifest_data) {
48
+ try {
49
+ const valid = validateAiCatalog(manifest_data);
50
+
51
+ if (valid) {
52
+ log.verbose('ARD', 'Strict JSON Schema validation passed.');
53
+ return true;
54
+ } else {
55
+ const errors = /** @type {any} */ (validateAiCatalog).errors;
56
+ const e = errors?.[0];
57
+ const propertyPath = e?.instancePath ? e.instancePath.replace(/^\//, '').replace(/\//g, '.') : 'root';
58
+ let msg = e?.message || 'unknown schema error';
59
+ if (e?.keyword === 'required') {
60
+ msg = `'${e.params.missingProperty}' is a required property`;
61
+ }
62
+ this.add_error(`JSON Schema Validation Failed: ${msg} at path '${propertyPath}'`, 'Root');
63
+ return false;
64
+ }
65
+ } catch (e) {
66
+ this.add_warning(`Failed to run JSON Schema validator: ${e}`, 'Root');
67
+ return true;
68
+ }
69
+ }
70
+
71
+ /**
72
+ * @param {string} raw_content
73
+ * @param {string} source_label
74
+ */
75
+ validate_manifest(raw_content, source_label) {
76
+ log.verbose('ARD', `Validating Manifest: ${source_label}`);
77
+
78
+ // 1. Basic JSON Parsing
79
+ let data;
80
+ try {
81
+ data = JSON.parse(raw_content);
82
+ log.verbose('ARD', 'Manifest parsed successfully as valid JSON.');
83
+ } catch (e) {
84
+ this.add_error(`Malformed JSON in manifest: ${e}`, 'Root');
85
+ return false;
86
+ }
87
+
88
+ // 2. Strict JSON Schema Validation
89
+ this.run_json_schema_validation(data);
90
+
91
+ // 3. Custom Semantic and Protocol-Specific Validation
92
+ log.verbose('ARD', 'Running custom semantic checks...');
93
+
94
+ const spec_ver = data["specVersion"];
95
+ if (!spec_ver) {
96
+ this.add_error("Missing required 'specVersion' root property.", 'Root');
97
+ } else if (spec_ver !== "1.0") {
98
+ this.add_warning(`Unrecognized 'specVersion': ${spec_ver}. Expected '1.0'.`, 'Root');
99
+ }
100
+
101
+ const entries = data["entries"];
102
+ if (entries === undefined || entries === null) {
103
+ this.add_error("Missing required 'entries' array.", 'Root');
104
+ return false;
105
+ } else if (!Array.isArray(entries)) {
106
+ this.add_error("'entries' must be a JSON array.", 'Root');
107
+ return false;
108
+ }
109
+
110
+ log.verbose('ARD', `Found ${entries.length} entries to validate.`);
111
+ entries.forEach((entry, idx) => {
112
+ const label = entry["displayName"] || entry["identifier"] || `Entry #${idx}`;
113
+
114
+ // Required properties
115
+ const ident = entry["identifier"];
116
+ if (!ident) {
117
+ this.add_error("Missing required 'identifier'.", label);
118
+ } else {
119
+ // URN pattern checks
120
+ const match = URN_REGEX.exec(ident);
121
+ if (!match) {
122
+ this.add_error(`Identifier '${ident}' does not match RFC 8141 URN pattern 'urn:air:<publisher>:<namespace>:<agent-name>'.`, label);
123
+ } else {
124
+ const publisher = match[1];
125
+ const name = match[3];
126
+ log.verbose('ARD', `[${label}] Valid URN format. Publisher: '${publisher}', Name: '${name}'.`);
127
+ }
128
+ }
129
+
130
+ const disp_name = entry["displayName"];
131
+ if (!disp_name) {
132
+ this.add_error("Missing required 'displayName'.", label);
133
+ }
134
+
135
+ const media_type = entry["type"];
136
+ if (!media_type) {
137
+ this.add_error("Missing required 'type' (mediaType).", label);
138
+ } else {
139
+ const valid_types = [
140
+ "application/ai-catalog+json",
141
+ "application/agent-card+json",
142
+ "application/a2a-agent-card+json",
143
+ "application/mcp-server-card+json",
144
+ "application/agent-skills+zip",
145
+ "application/agent-skills+gzip",
146
+ "text/markdown; profile=\"urn:air:agent-skills\"",
147
+ "application/ai-registry",
148
+ "application/ai-registry+json"
149
+ ];
150
+ if (!valid_types.includes(media_type)) {
151
+ this.add_warning(`Media type '${media_type}' is not one of standard discovery types: ${valid_types}.`, label);
152
+ }
153
+ }
154
+
155
+ // Strict Value-or-Reference checks
156
+ const has_url = entry["url"] !== undefined;
157
+ const has_data = entry["data"] !== undefined;
158
+ if (has_url && has_data) {
159
+ this.add_error("Constraint violation: both 'url' and 'data' are provided. MUST provide exactly one.", label);
160
+ } else if (!has_url && !has_data) {
161
+ this.add_error("Constraint violation: neither 'url' nor 'data' is provided. MUST provide exactly one.", label);
162
+ }
163
+
164
+ // Custom constraints for representativeQueries
165
+ const queries = entry["representativeQueries"];
166
+ if (queries === undefined || queries === null) {
167
+ this.add_warning("Missing 'representativeQueries'. 2 to 5 queries are recommended for vector index embedding.", label);
168
+ } else if (!Array.isArray(queries)) {
169
+ this.add_error("'representativeQueries' must be an array of strings.", label);
170
+ } else {
171
+ if (queries.length < 2 || queries.length > 5) {
172
+ this.add_warning(`'representativeQueries' array has size ${queries.length}. 2 to 5 queries are recommended for vector index embedding.`, label);
173
+ }
174
+ for (const q of queries) {
175
+ if (typeof q !== 'string') {
176
+ this.add_error(`Query '${q}' is not a string.`, label);
177
+ }
178
+ }
179
+ }
180
+
181
+ // Progressive trust checks
182
+ const trust = entry["trustManifest"];
183
+ if (trust !== undefined && trust !== null) {
184
+ if (typeof trust !== 'object' || Array.isArray(trust)) {
185
+ this.add_error("'trustManifest' must be a JSON object.", label);
186
+ } else {
187
+ const trust_id = trust["identity"];
188
+ if (!trust_id) {
189
+ this.add_error("'trustManifest' is missing required 'identity' field.", label);
190
+ }
191
+ }
192
+ }
193
+ });
194
+
195
+ // Top-level deprecated property check
196
+ if ("collections" in data) {
197
+ this.add_error("Deprecated field check: Found 'collections' array at root. Top-level collections were REMOVED in ADR-0003. Catalog hierarchies MUST be modeled inside 'entries' using 'type: application/ai-catalog+json'.", 'Root');
198
+ }
199
+
200
+ return this.errors.length === 0;
201
+ }
202
+ }
203
+
204
+ export { ConformanceTester };
@@ -0,0 +1,20 @@
1
+ export function validate(data: any, { instancePath, parentData, parentDataProperty, rootData, dynamicAnchors }?: {
2
+ instancePath?: string | undefined;
3
+ rootData?: any;
4
+ dynamicAnchors?: {} | undefined;
5
+ }): boolean;
6
+ export namespace validate {
7
+ namespace evaluated {
8
+ let props: boolean;
9
+ let dynamicProps: boolean;
10
+ let dynamicItems: boolean;
11
+ }
12
+ }
13
+ export default validate20;
14
+ declare function validate20(data: any, { instancePath, parentData, parentDataProperty, rootData, dynamicAnchors }?: {
15
+ instancePath?: string | undefined;
16
+ rootData?: any;
17
+ dynamicAnchors?: {} | undefined;
18
+ }): boolean;
19
+ declare namespace validate20 { }
20
+ //# sourceMappingURL=schema-validator.d.ts.map