@nuxtseo/protocol 0.5.1 → 0.5.4

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.
@@ -225,10 +225,12 @@ export const fieldVitalSummarySchema = defineResponseObject({
225
225
  p75: schema.number().nullable(),
226
226
  status: fieldVitalRatingSchema.nullable(),
227
227
  deltaOverPeriod: schema.number().nullable(),
228
+ asOf: schema.string().min(1).nullable(),
228
229
  }, {
229
230
  p75: schema.number().nullable(),
230
231
  status: fieldVitalRatingSchema.nullable(),
231
232
  deltaOverPeriod: schema.number().nullable(),
233
+ asOf: schema.string().min(1).nullable(),
232
234
  });
233
235
  export const fieldVitalPointSchema = defineResponseObject({ date: schema.string().min(1), p75: schema.number().nullable() }, { date: schema.string().min(1), p75: schema.number().nullable() });
234
236
  /**
@@ -330,9 +332,9 @@ export const fieldVitalsOperation = defineOperation({
330
332
  available: true,
331
333
  message: null,
332
334
  summary: {
333
- lcp: { p75: 2400, status: 'needs-improvement', deltaOverPeriod: -150 },
334
- inp: { p75: 180, status: 'good', deltaOverPeriod: 10 },
335
- cls: { p75: 0.08, status: 'good', deltaOverPeriod: null },
335
+ lcp: { p75: 2400, status: 'needs-improvement', deltaOverPeriod: -150, asOf: '2026-08-24' },
336
+ inp: { p75: 180, status: 'good', deltaOverPeriod: 10, asOf: '2026-08-24' },
337
+ cls: { p75: 0.08, status: 'good', deltaOverPeriod: null, asOf: '2026-08-24' },
336
338
  overall: 'ni',
337
339
  asOf: '2026-08-24',
338
340
  },
@@ -726,6 +728,42 @@ const scanCoverageShape = {
726
728
  bestPracticesChecksTotal: schema.number().int().nonnegative(),
727
729
  possiblyTruncated: schema.boolean(),
728
730
  };
731
+ const scanJavascriptShape = {
732
+ transferBytes: nullableMetricSchema,
733
+ decodedBytes: nullableMetricSchema,
734
+ scriptCount: schema.number().int().nonnegative().nullable(),
735
+ };
736
+ /** Trace timings are separate from the reported metric under simulated throttling. */
737
+ export const lcpObservedTraceSchema = schema.discriminatedUnion('_tag', [
738
+ schema.strictObject({
739
+ _tag: schema.literal('available'),
740
+ basis: schema.literal('observed'),
741
+ // PSI can omit the method while retaining valid observed trace timings.
742
+ throttlingMethod: schema.enum(['simulate', 'provided', 'devtools']).nullable(),
743
+ observedLcpMs: schema.number().positive(),
744
+ phases: schema.array(schema.strictObject({
745
+ id: schema.enum(['timeToFirstByte', 'resourceLoadDelay', 'resourceLoadDuration', 'elementRenderDelay']),
746
+ durationMs: schema.number().nonnegative(),
747
+ })).min(2).max(4),
748
+ }),
749
+ schema.strictObject({
750
+ _tag: schema.literal('unavailable'),
751
+ reason: schema.enum(['missing-report-data', 'invalid-report-data', 'legacy-projection', 'projection-missing', 'projection-unavailable']),
752
+ }),
753
+ ]).superRefine((trace, context) => {
754
+ if (trace._tag !== 'available')
755
+ return;
756
+ const ids = new Set(trace.phases.map(phase => phase.id));
757
+ const totalMs = trace.phases.reduce((total, phase) => total + phase.durationMs, 0);
758
+ // The metrics audit rounds observed LCP. Allow rounding, never substitute
759
+ // the separately reported metric as the phase total.
760
+ if (ids.size !== trace.phases.length
761
+ || !ids.has('timeToFirstByte') || !ids.has('elementRenderDelay')
762
+ || ids.has('resourceLoadDelay') !== ids.has('resourceLoadDuration')
763
+ || Math.abs(totalMs - trace.observedLcpMs) > 2) {
764
+ context.addIssue({ code: 'custom', message: 'Trace phases must describe the observed LCP' });
765
+ }
766
+ });
729
767
  export const performanceScanDetailDataSchema = defineResponseObject({
730
768
  id: schema.string().min(1),
731
769
  url: schema.string().min(1),
@@ -739,6 +777,8 @@ export const performanceScanDetailDataSchema = defineResponseObject({
739
777
  speedIndex: nullableMetricSchema,
740
778
  ttfb: nullableMetricSchema,
741
779
  completedAt: schema.string().datetime().nullable(),
780
+ javascript: schema.strictObject(scanJavascriptShape).nullable(),
781
+ observedTrace: lcpObservedTraceSchema.optional(),
742
782
  performanceIssues: schema.array(scanPerformanceIssueSchema.producer),
743
783
  cachePolicy: schema.array(scanCachePolicySchema.producer),
744
784
  thirdParties: schema.array(scanThirdPartySchema.producer),
@@ -763,6 +803,8 @@ export const performanceScanDetailDataSchema = defineResponseObject({
763
803
  speedIndex: nullableMetricSchema,
764
804
  ttfb: nullableMetricSchema,
765
805
  completedAt: schema.string().datetime().nullable(),
806
+ javascript: schema.looseObject(scanJavascriptShape).nullable().optional(),
807
+ observedTrace: lcpObservedTraceSchema.optional(),
766
808
  performanceIssues: schema.array(scanPerformanceIssueSchema.client),
767
809
  cachePolicy: schema.array(scanCachePolicySchema.client),
768
810
  thirdParties: schema.array(scanThirdPartySchema.client),
@@ -832,6 +874,7 @@ export const performanceScanDetailOperation = defineOperation({
832
874
  speedIndex: 2400,
833
875
  ttfb: 210,
834
876
  completedAt: '2026-08-10T01:00:00.000Z',
877
+ javascript: null,
835
878
  performanceIssues: [],
836
879
  cachePolicy: [],
837
880
  thirdParties: [],