@nuxtseo/protocol 0.5.9 → 0.5.10

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.
@@ -749,17 +749,29 @@ export const performanceScansOperation = defineOperation({
749
749
  }],
750
750
  },
751
751
  });
752
+ /**
753
+ * Why the scheduler stopped scanning a Page. `gone`: the URL answers 404 or
754
+ * 410. `redirected`: it redirects to another page. `unreachable`: Scans keep
755
+ * timing out or failing. `rejected`: PageSpeed Insights keeps refusing it.
756
+ * Null while the Page is scanned on schedule.
757
+ */
758
+ const MONITORED_PAGE_PAUSE_REASONS = ['gone', 'redirected', 'unreachable', 'rejected'];
752
759
  export const monitoredPageSchema = defineResponseObject({
753
760
  id: schema.string().min(1),
754
761
  path: schema.string(),
755
762
  source: schema.string().nullable(),
756
763
  enabled: schema.boolean(),
764
+ pauseReason: schema.enum(MONITORED_PAGE_PAUSE_REASONS).nullable(),
765
+ pausedAt: schema.string().datetime().nullable(),
757
766
  lastScanAt: schema.string().datetime().nullable(),
758
767
  }, {
759
768
  id: schema.string().min(1),
760
769
  path: schema.string(),
761
770
  source: schema.string().nullable(),
762
771
  enabled: schema.boolean(),
772
+ // A client accepts reasons a newer server adds.
773
+ pauseReason: schema.string().min(1).nullable().optional(),
774
+ pausedAt: schema.string().datetime().nullable().optional(),
763
775
  lastScanAt: schema.string().datetime().nullable(),
764
776
  });
765
777
  export const monitoredPagesDataSchema = defineResponseObject({
@@ -806,7 +818,7 @@ export const monitoredPagesOperation = defineOperation({
806
818
  lifecycle: { introduced: '1.2.0' },
807
819
  docs: {
808
820
  summary: 'List monitored Pages',
809
- description: 'Returns the Pages this Site scans on a schedule, in display order, with the last time each one was scanned. Start a Scan for a new Page with the Page scan operation.',
821
+ description: 'Returns the Pages this Site monitors, in display order, with the last time each one was scanned. A Page with a pauseReason is out of the schedule until the owner adds it again. Start a Scan for a new Page with the Page scan operation.',
810
822
  tags: ['Pages'],
811
823
  examples: [{
812
824
  request: { params: { siteId: 'site_01JXYZ' } },
@@ -814,8 +826,11 @@ export const monitoredPagesOperation = defineOperation({
814
826
  status: 200,
815
827
  body: {
816
828
  data: {
817
- pages: [{ id: 'lhp_01JXYZ', path: '/', source: 'homepage', enabled: true, lastScanAt: '2026-08-10T01:00:00.000Z' }],
818
- total: 1,
829
+ pages: [
830
+ { id: 'lhp_01JXYZ', path: '/pricing', source: 'auto-gsc', enabled: true, pauseReason: null, pausedAt: null, lastScanAt: '2026-08-10T01:00:00.000Z' },
831
+ { id: 'lhp_01JXZA', path: '/blog/old-post', source: 'auto-gsc', enabled: true, pauseReason: 'redirected', pausedAt: '2026-08-09T01:00:00.000Z', lastScanAt: '2026-08-09T01:00:00.000Z' },
832
+ ],
833
+ total: 2,
819
834
  },
820
835
  meta: { requestId: 'req_01JXYZ', version: '1.0' },
821
836
  },
@@ -937,6 +952,56 @@ export const lcpObservedTraceSchema = schema.discriminatedUnion('_tag', [
937
952
  context.addIssue({ code: 'custom', message: 'Trace phases must describe the observed LCP' });
938
953
  }
939
954
  });
955
+ const scanCruxVitalShape = {
956
+ p75: schema.number().nonnegative(),
957
+ rating: fieldVitalRatingSchema,
958
+ };
959
+ const scanCruxVitalClientShape = {
960
+ p75: schema.number(),
961
+ rating: schema.string().min(1),
962
+ };
963
+ /** CrUX for one scope as PSI returned it with a Scan. `no_data` means CrUX holds no record for that scope. */
964
+ const scanCruxReadingSchema = {
965
+ producer: schema.discriminatedUnion('_tag', [
966
+ schema.strictObject({
967
+ _tag: schema.literal('measured'),
968
+ target: schema.string(),
969
+ lcp: schema.strictObject(scanCruxVitalShape).nullable(),
970
+ inp: schema.strictObject(scanCruxVitalShape).nullable(),
971
+ cls: schema.strictObject(scanCruxVitalShape).nullable(),
972
+ }),
973
+ schema.strictObject({ _tag: schema.literal('no_data'), target: schema.string() }),
974
+ ]),
975
+ client: schema.discriminatedUnion('_tag', [
976
+ schema.looseObject({
977
+ _tag: schema.literal('measured'),
978
+ target: schema.string(),
979
+ lcp: schema.looseObject(scanCruxVitalClientShape).nullable(),
980
+ inp: schema.looseObject(scanCruxVitalClientShape).nullable(),
981
+ cls: schema.looseObject(scanCruxVitalClientShape).nullable(),
982
+ }),
983
+ schema.looseObject({ _tag: schema.literal('no_data'), target: schema.string() }),
984
+ ]),
985
+ };
986
+ /**
987
+ * The CrUX field reading PSI returned with the Scan: real Chrome users' p75
988
+ * over the 28 days before it, for the Scan URL and its origin. Null on a Scan
989
+ * processed before these readings were stored.
990
+ */
991
+ const scanCruxSchema = {
992
+ producer: schema.strictObject({
993
+ formFactor: schema.enum(['PHONE', 'DESKTOP']),
994
+ capturedAt: schema.string().datetime(),
995
+ url: scanCruxReadingSchema.producer.nullable(),
996
+ origin: scanCruxReadingSchema.producer.nullable(),
997
+ }).nullable(),
998
+ client: schema.looseObject({
999
+ formFactor: schema.string().min(1),
1000
+ capturedAt: schema.string().datetime(),
1001
+ url: scanCruxReadingSchema.client.nullable(),
1002
+ origin: scanCruxReadingSchema.client.nullable(),
1003
+ }).nullable(),
1004
+ };
940
1005
  export const performanceScanDetailDataSchema = defineResponseObject({
941
1006
  ...scanBaseShape,
942
1007
  fcp: nullableMetricSchema,
@@ -945,6 +1010,7 @@ export const performanceScanDetailDataSchema = defineResponseObject({
945
1010
  comparison: performanceScanComparisonSchema.producer,
946
1011
  javascript: schema.strictObject(scanJavascriptShape).nullable(),
947
1012
  observedTrace: lcpObservedTraceSchema.optional(),
1013
+ crux: scanCruxSchema.producer,
948
1014
  performanceIssues: schema.array(scanPerformanceIssueSchema.producer),
949
1015
  cachePolicy: schema.array(scanCachePolicySchema.producer),
950
1016
  thirdParties: schema.array(scanThirdPartySchema.producer),
@@ -964,6 +1030,7 @@ export const performanceScanDetailDataSchema = defineResponseObject({
964
1030
  comparison: performanceScanComparisonSchema.client.optional(),
965
1031
  javascript: schema.looseObject(scanJavascriptShape).nullable().optional(),
966
1032
  observedTrace: lcpObservedTraceSchema.optional(),
1033
+ crux: scanCruxSchema.client.optional(),
967
1034
  performanceIssues: schema.array(scanPerformanceIssueSchema.client),
968
1035
  cachePolicy: schema.array(scanCachePolicySchema.client),
969
1036
  thirdParties: schema.array(scanThirdPartySchema.client),
@@ -1013,7 +1080,7 @@ export const performanceScanDetailOperation = defineOperation({
1013
1080
  lifecycle: { introduced: '1.2.0' },
1014
1081
  docs: {
1015
1082
  summary: 'Get one Lighthouse Scan',
1016
- description: 'Returns one Scan with the evidence behind its scores: the wasteful assets, the repeat-visit cache policy, the third-party scripts, the LCP element, and every failing accessibility and best-practices check with the CSS selectors and DOM snippets that failed. It also returns why the Scan started, the Lighthouse version, and the comparison with the previous Scan of the same Page. A failed Scan carries its failureKind and error. Read coverage before quoting a total: elements and checks are both capped per Scan. A null blockingTime or wastedMs is unmeasured, never zero.',
1083
+ description: 'Returns one Scan with the evidence behind its scores: the wasteful assets, the repeat-visit cache policy, the third-party scripts, the LCP element, and every failing accessibility and best-practices check with the CSS selectors and DOM snippets that failed. It also returns why the Scan started, the Lighthouse version, and the comparison with the previous Scan of the same Page. crux is the CrUX p75 for the Scan URL and its origin that PSI returned with the Scan, null on a Scan stored before these readings. A failed Scan carries its failureKind and error. Read coverage before quoting a total: elements and checks are both capped per Scan. A null blockingTime or wastedMs is unmeasured, never zero.',
1017
1084
  tags: ['Pages'],
1018
1085
  examples: [{
1019
1086
  request: { params: { siteId: 'site_01JXYZ', scanId: 'scan_01JXYZ' } },
@@ -1047,6 +1114,18 @@ export const performanceScanDetailOperation = defineOperation({
1047
1114
  ],
1048
1115
  },
1049
1116
  javascript: null,
1117
+ crux: {
1118
+ formFactor: 'PHONE',
1119
+ capturedAt: '2026-08-10T00:58:00.000Z',
1120
+ url: { _tag: 'no_data', target: 'https://example.com/pricing' },
1121
+ origin: {
1122
+ _tag: 'measured',
1123
+ target: 'https://example.com',
1124
+ lcp: { p75: 2100, rating: 'good' },
1125
+ inp: { p75: 180, rating: 'good' },
1126
+ cls: { p75: 0.05, rating: 'good' },
1127
+ },
1128
+ },
1050
1129
  performanceIssues: [],
1051
1130
  cachePolicy: [],
1052
1131
  thirdParties: [],