@canonry/canonry 4.160.0 → 4.161.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 (24) hide show
  1. package/assets/assets/{AuditHistoryPanel-AtgoG2AH.js → AuditHistoryPanel-C_1twF00.js} +1 -1
  2. package/assets/assets/{BacklinksPage-DrOSF7Mu.js → BacklinksPage-CfAuMCaN.js} +1 -1
  3. package/assets/assets/{HistoryPage-CGQXleJc.js → HistoryPage-DrRxOL3j.js} +1 -1
  4. package/assets/assets/{MeasurementPropertyPage-C7D2OgIQ.js → MeasurementPropertyPage-BFtxx5Jw.js} +1 -1
  5. package/assets/assets/{ProjectPage-Lp1VjNvL.js → ProjectPage-Djvhx4HD.js} +9 -9
  6. package/assets/assets/{RunRow-BdzKKODo.js → RunRow-DVZXibR2.js} +1 -1
  7. package/assets/assets/{RunsPage-BU96L07S.js → RunsPage-CAUMy7By.js} +1 -1
  8. package/assets/assets/{SettingsPage-LEca0kDH.js → SettingsPage-CcSOmQAl.js} +1 -1
  9. package/assets/assets/{SiteHealthSection-CKM4DUfE.js → SiteHealthSection-DYjEWd1I.js} +3 -3
  10. package/assets/assets/{TrafficPage-tU9wl1F_.js → TrafficPage-BWM33jnJ.js} +1 -1
  11. package/assets/assets/{TrafficSourceDetailPage-DZTpnU9f.js → TrafficSourceDetailPage-DvEZ_JGY.js} +1 -1
  12. package/assets/assets/{extract-error-message-BAyN-ftk.js → extract-error-message-CnKOJkYB.js} +1 -1
  13. package/assets/assets/{index-Wqv7kvs-.js → index-CQGAqmDx.js} +13 -13
  14. package/assets/assets/{react-sigma_core.esm.min-DlZOAc_w.js → react-sigma_core.esm.min-CHCAIMBW.js} +1 -1
  15. package/assets/index.html +1 -1
  16. package/dist/{chunk-7M7T5QXS.js → chunk-EXDO7EPL.js} +27 -1
  17. package/dist/{chunk-HQAVEK42.js → chunk-HCGTKQCG.js} +1 -1
  18. package/dist/{chunk-X7CYY5Q7.js → chunk-J27J2DF6.js} +172 -37
  19. package/dist/{chunk-XGESWHFP.js → chunk-W6OWEPZG.js} +35 -18
  20. package/dist/cli.js +17 -11
  21. package/dist/index.js +4 -4
  22. package/dist/{intelligence-service-6XQMM466.js → intelligence-service-HKDIVTZB.js} +2 -2
  23. package/dist/mcp.js +2 -2
  24. package/package.json +8 -8
@@ -1,4 +1,4 @@
1
- import{g as Bt,t as S,r as C}from"./vendor-tanstack-Dock0eH1.js";import{e as Ht,G as Wt}from"./SiteHealthSection-CKM4DUfE.js";import"./index-Wqv7kvs-.js";import"./vendor-radix-4UOaVWza.js";import"./vendor-recharts-D8rt5lKn.js";import"./vendor-lucide-nYKv-BB7.js";import"./vendor-markdown-Bn7fRwrx.js";import"./vendor-yaml-GWJz5H2G.js";import"./ChartPrimitives-DXVLCdBi.js";function Vt(r,n){if(typeof r!="object"||!r)return r;var i=r[Symbol.toPrimitive];if(i!==void 0){var e=i.call(r,n);if(typeof e!="object")return e;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(r)}function ae(r){var n=Vt(r,"string");return typeof n=="symbol"?n:n+""}function A(r,n){if(!(r instanceof n))throw new TypeError("Cannot call a class as a function")}function He(r,n){for(var i=0;i<n.length;i++){var e=n[i];e.enumerable=e.enumerable||!1,e.configurable=!0,"value"in e&&(e.writable=!0),Object.defineProperty(r,ae(e.key),e)}}function L(r,n,i){return n&&He(r.prototype,n),i&&He(r,i),Object.defineProperty(r,"prototype",{writable:!1}),r}function Q(r){return Q=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(n){return n.__proto__||Object.getPrototypeOf(n)},Q(r)}function yt(){try{var r=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch{}return(yt=function(){return!!r})()}function jt(r){if(r===void 0)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return r}function Zt(r,n){if(n&&(typeof n=="object"||typeof n=="function"))return n;if(n!==void 0)throw new TypeError("Derived constructors may only return object or undefined");return jt(r)}function I(r,n,i){return n=Q(n),Zt(r,yt()?Reflect.construct(n,i||[],Q(r).constructor):n.apply(r,i))}function xe(r,n){return xe=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(i,e){return i.__proto__=e,i},xe(r,n)}function G(r,n){if(typeof n!="function"&&n!==null)throw new TypeError("Super expression must either be null or a function");r.prototype=Object.create(n&&n.prototype,{constructor:{value:r,writable:!0,configurable:!0}}),Object.defineProperty(r,"prototype",{writable:!1}),n&&xe(r,n)}function qt(r){if(Array.isArray(r))return r}function Yt(r,n){var i=r==null?null:typeof Symbol<"u"&&r[Symbol.iterator]||r["@@iterator"];if(i!=null){var e,t,a,o,s=[],l=!0,h=!1;try{if(a=(i=i.call(r)).next,n===0){if(Object(i)!==i)return;l=!1}else for(;!(l=(e=a.call(i)).done)&&(s.push(e.value),s.length!==n);l=!0);}catch(u){h=!0,t=u}finally{try{if(!l&&i.return!=null&&(o=i.return(),Object(o)!==o))return}finally{if(h)throw t}}return s}}function Se(r,n){(n==null||n>r.length)&&(n=r.length);for(var i=0,e=Array(n);i<n;i++)e[i]=r[i];return e}function Tt(r,n){if(r){if(typeof r=="string")return Se(r,n);var i={}.toString.call(r).slice(8,-1);return i==="Object"&&r.constructor&&(i=r.constructor.name),i==="Map"||i==="Set"?Array.from(r):i==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(i)?Se(r,n):void 0}}function Xt(){throw new TypeError(`Invalid attempt to destructure non-iterable instance.
1
+ import{g as Bt,t as S,r as C}from"./vendor-tanstack-Dock0eH1.js";import{e as Ht,G as Wt}from"./SiteHealthSection-DYjEWd1I.js";import"./index-CQGAqmDx.js";import"./vendor-radix-4UOaVWza.js";import"./vendor-recharts-D8rt5lKn.js";import"./vendor-lucide-nYKv-BB7.js";import"./vendor-markdown-Bn7fRwrx.js";import"./vendor-yaml-GWJz5H2G.js";import"./ChartPrimitives-DXVLCdBi.js";function Vt(r,n){if(typeof r!="object"||!r)return r;var i=r[Symbol.toPrimitive];if(i!==void 0){var e=i.call(r,n);if(typeof e!="object")return e;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(r)}function ae(r){var n=Vt(r,"string");return typeof n=="symbol"?n:n+""}function A(r,n){if(!(r instanceof n))throw new TypeError("Cannot call a class as a function")}function He(r,n){for(var i=0;i<n.length;i++){var e=n[i];e.enumerable=e.enumerable||!1,e.configurable=!0,"value"in e&&(e.writable=!0),Object.defineProperty(r,ae(e.key),e)}}function L(r,n,i){return n&&He(r.prototype,n),i&&He(r,i),Object.defineProperty(r,"prototype",{writable:!1}),r}function Q(r){return Q=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(n){return n.__proto__||Object.getPrototypeOf(n)},Q(r)}function yt(){try{var r=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch{}return(yt=function(){return!!r})()}function jt(r){if(r===void 0)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return r}function Zt(r,n){if(n&&(typeof n=="object"||typeof n=="function"))return n;if(n!==void 0)throw new TypeError("Derived constructors may only return object or undefined");return jt(r)}function I(r,n,i){return n=Q(n),Zt(r,yt()?Reflect.construct(n,i||[],Q(r).constructor):n.apply(r,i))}function xe(r,n){return xe=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(i,e){return i.__proto__=e,i},xe(r,n)}function G(r,n){if(typeof n!="function"&&n!==null)throw new TypeError("Super expression must either be null or a function");r.prototype=Object.create(n&&n.prototype,{constructor:{value:r,writable:!0,configurable:!0}}),Object.defineProperty(r,"prototype",{writable:!1}),n&&xe(r,n)}function qt(r){if(Array.isArray(r))return r}function Yt(r,n){var i=r==null?null:typeof Symbol<"u"&&r[Symbol.iterator]||r["@@iterator"];if(i!=null){var e,t,a,o,s=[],l=!0,h=!1;try{if(a=(i=i.call(r)).next,n===0){if(Object(i)!==i)return;l=!1}else for(;!(l=(e=a.call(i)).done)&&(s.push(e.value),s.length!==n);l=!0);}catch(u){h=!0,t=u}finally{try{if(!l&&i.return!=null&&(o=i.return(),Object(o)!==o))return}finally{if(h)throw t}}return s}}function Se(r,n){(n==null||n>r.length)&&(n=r.length);for(var i=0,e=Array(n);i<n;i++)e[i]=r[i];return e}function Tt(r,n){if(r){if(typeof r=="string")return Se(r,n);var i={}.toString.call(r).slice(8,-1);return i==="Object"&&r.constructor&&(i=r.constructor.name),i==="Map"||i==="Set"?Array.from(r):i==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(i)?Se(r,n):void 0}}function Xt(){throw new TypeError(`Invalid attempt to destructure non-iterable instance.
2
2
  In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function ee(r,n){return qt(r)||Yt(r,n)||Tt(r,n)||Xt()}var pe={black:"#000000",silver:"#C0C0C0",gray:"#808080",grey:"#808080",white:"#FFFFFF",maroon:"#800000",red:"#FF0000",purple:"#800080",fuchsia:"#FF00FF",green:"#008000",lime:"#00FF00",olive:"#808000",yellow:"#FFFF00",navy:"#000080",blue:"#0000FF",teal:"#008080",aqua:"#00FFFF",darkblue:"#00008B",mediumblue:"#0000CD",darkgreen:"#006400",darkcyan:"#008B8B",deepskyblue:"#00BFFF",darkturquoise:"#00CED1",mediumspringgreen:"#00FA9A",springgreen:"#00FF7F",cyan:"#00FFFF",midnightblue:"#191970",dodgerblue:"#1E90FF",lightseagreen:"#20B2AA",forestgreen:"#228B22",seagreen:"#2E8B57",darkslategray:"#2F4F4F",darkslategrey:"#2F4F4F",limegreen:"#32CD32",mediumseagreen:"#3CB371",turquoise:"#40E0D0",royalblue:"#4169E1",steelblue:"#4682B4",darkslateblue:"#483D8B",mediumturquoise:"#48D1CC",indigo:"#4B0082",darkolivegreen:"#556B2F",cadetblue:"#5F9EA0",cornflowerblue:"#6495ED",rebeccapurple:"#663399",mediumaquamarine:"#66CDAA",dimgray:"#696969",dimgrey:"#696969",slateblue:"#6A5ACD",olivedrab:"#6B8E23",slategray:"#708090",slategrey:"#708090",lightslategray:"#778899",lightslategrey:"#778899",mediumslateblue:"#7B68EE",lawngreen:"#7CFC00",chartreuse:"#7FFF00",aquamarine:"#7FFFD4",skyblue:"#87CEEB",lightskyblue:"#87CEFA",blueviolet:"#8A2BE2",darkred:"#8B0000",darkmagenta:"#8B008B",saddlebrown:"#8B4513",darkseagreen:"#8FBC8F",lightgreen:"#90EE90",mediumpurple:"#9370DB",darkviolet:"#9400D3",palegreen:"#98FB98",darkorchid:"#9932CC",yellowgreen:"#9ACD32",sienna:"#A0522D",brown:"#A52A2A",darkgray:"#A9A9A9",darkgrey:"#A9A9A9",lightblue:"#ADD8E6",greenyellow:"#ADFF2F",paleturquoise:"#AFEEEE",lightsteelblue:"#B0C4DE",powderblue:"#B0E0E6",firebrick:"#B22222",darkgoldenrod:"#B8860B",mediumorchid:"#BA55D3",rosybrown:"#BC8F8F",darkkhaki:"#BDB76B",mediumvioletred:"#C71585",indianred:"#CD5C5C",peru:"#CD853F",chocolate:"#D2691E",tan:"#D2B48C",lightgray:"#D3D3D3",lightgrey:"#D3D3D3",thistle:"#D8BFD8",orchid:"#DA70D6",goldenrod:"#DAA520",palevioletred:"#DB7093",crimson:"#DC143C",gainsboro:"#DCDCDC",plum:"#DDA0DD",burlywood:"#DEB887",lightcyan:"#E0FFFF",lavender:"#E6E6FA",darksalmon:"#E9967A",violet:"#EE82EE",palegoldenrod:"#EEE8AA",lightcoral:"#F08080",khaki:"#F0E68C",aliceblue:"#F0F8FF",honeydew:"#F0FFF0",azure:"#F0FFFF",sandybrown:"#F4A460",wheat:"#F5DEB3",beige:"#F5F5DC",whitesmoke:"#F5F5F5",mintcream:"#F5FFFA",ghostwhite:"#F8F8FF",salmon:"#FA8072",antiquewhite:"#FAEBD7",linen:"#FAF0E6",lightgoldenrodyellow:"#FAFAD2",oldlace:"#FDF5E6",magenta:"#FF00FF",deeppink:"#FF1493",orangered:"#FF4500",tomato:"#FF6347",hotpink:"#FF69B4",coral:"#FF7F50",darkorange:"#FF8C00",lightsalmon:"#FFA07A",orange:"#FFA500",lightpink:"#FFB6C1",pink:"#FFC0CB",gold:"#FFD700",peachpuff:"#FFDAB9",navajowhite:"#FFDEAD",moccasin:"#FFE4B5",bisque:"#FFE4C4",mistyrose:"#FFE4E1",blanchedalmond:"#FFEBCD",papayawhip:"#FFEFD5",lavenderblush:"#FFF0F5",seashell:"#FFF5EE",cornsilk:"#FFF8DC",lemonchiffon:"#FFFACD",floralwhite:"#FFFAF0",snow:"#FFFAFA",lightyellow:"#FFFFE0",ivory:"#FFFFF0"},Ct=new Int8Array(4),be=new Int32Array(Ct.buffer,0,1),$t=new Float32Array(Ct.buffer,0,1),Kt=/^\s*rgba?\s*\(/,Jt=/^\s*rgba?\s*\(\s*([0-9]*)\s*,\s*([0-9]*)\s*,\s*([0-9]*)(?:\s*,\s*(.*)?)?\)\s*$/;function Qt(r){var n=0,i=0,e=0,t=1;if(r[0]==="#")r.length===4?(n=parseInt(r.charAt(1)+r.charAt(1),16),i=parseInt(r.charAt(2)+r.charAt(2),16),e=parseInt(r.charAt(3)+r.charAt(3),16)):(n=parseInt(r.charAt(1)+r.charAt(2),16),i=parseInt(r.charAt(3)+r.charAt(4),16),e=parseInt(r.charAt(5)+r.charAt(6),16)),r.length===9&&(t=parseInt(r.charAt(7)+r.charAt(8),16)/255);else if(Kt.test(r)){var a=r.match(Jt);a&&(n=+a[1],i=+a[2],e=+a[3],a[4]&&(t=+a[4]))}return{r:n,g:i,b:e,a:t}}var J={};for(var le in pe)J[le]=oe(pe[le]),J[pe[le]]=J[le];function Rt(r,n,i,e,t){return be[0]=e<<24|i<<16|n<<8|r,be[0]=be[0]&4278190079,$t[0]}function oe(r){if(r=r.toLowerCase(),typeof J[r]<"u")return J[r];var n=Qt(r),i=n.r,e=n.g,t=n.b,a=n.a;a=a*255|0;var o=Rt(i,e,t,a);return J[r]=o,o}var Ee={};function _t(r){if(typeof Ee[r]<"u")return Ee[r];var n=(r&16711680)>>>16,i=(r&65280)>>>8,e=r&255,t=255,a=Rt(n,i,e,t);return Ee[r]=a,a}function We(r,n,i,e){return i+(n<<8)+(r<<16)}function Ve(r,n,i,e,t,a){var o=Math.floor(i/a*t),s=Math.floor(r.drawingBufferHeight/a-e/a*t),l=new Uint8Array(4);r.bindFramebuffer(r.FRAMEBUFFER,n),r.readPixels(o,s,1,1,r.RGBA,r.UNSIGNED_BYTE,l);var h=ee(l,4),u=h[0],d=h[1],f=h[2],g=h[3];return[u,d,f,g]}function c(r,n,i){return(n=ae(n))in r?Object.defineProperty(r,n,{value:i,enumerable:!0,configurable:!0,writable:!0}):r[n]=i,r}function je(r,n){var i=Object.keys(r);if(Object.getOwnPropertySymbols){var e=Object.getOwnPropertySymbols(r);n&&(e=e.filter(function(t){return Object.getOwnPropertyDescriptor(r,t).enumerable})),i.push.apply(i,e)}return i}function b(r){for(var n=1;n<arguments.length;n++){var i=arguments[n]!=null?arguments[n]:{};n%2?je(Object(i),!0).forEach(function(e){c(r,e,i[e])}):Object.getOwnPropertyDescriptors?Object.defineProperties(r,Object.getOwnPropertyDescriptors(i)):je(Object(i)).forEach(function(e){Object.defineProperty(r,e,Object.getOwnPropertyDescriptor(i,e))})}return r}function ei(r,n){for(;!{}.hasOwnProperty.call(r,n)&&(r=Q(r))!==null;);return r}function Ae(){return Ae=typeof Reflect<"u"&&Reflect.get?Reflect.get.bind():function(r,n,i){var e=ei(r,n);if(e){var t=Object.getOwnPropertyDescriptor(e,n);return t.get?t.get.call(arguments.length<3?r:i):t.value}},Ae.apply(null,arguments)}function wt(r,n,i,e){var t=Ae(Q(r.prototype),n,i);return typeof t=="function"?function(a){return t.apply(i,a)}:t}function ti(r){return r.normalized?1:r.size}function ye(r){var n=0;return r.forEach(function(i){return n+=ti(i)}),n}function xt(r,n,i){var e=r==="VERTEX"?n.VERTEX_SHADER:n.FRAGMENT_SHADER,t=n.createShader(e);if(t===null)throw new Error("loadShader: error while creating the shader");n.shaderSource(t,i),n.compileShader(t);var a=n.getShaderParameter(t,n.COMPILE_STATUS);if(!a){var o=n.getShaderInfoLog(t);throw n.deleteShader(t),new Error(`loadShader: error while compiling the shader:
3
3
  `.concat(o,`
4
4
  `).concat(i))}return t}function ii(r,n){return xt("VERTEX",r,n)}function ri(r,n){return xt("FRAGMENT",r,n)}function ni(r,n){var i=r.createProgram();if(i===null)throw new Error("loadProgram: error while creating the program.");var e,t;for(e=0,t=n.length;e<t;e++)r.attachShader(i,n[e]);r.linkProgram(i);var a=r.getProgramParameter(i,r.LINK_STATUS);if(!a){var o=r.getProgramInfoLog(i);throw r.deleteProgram(i),new Error("loadProgram: error while linking the program: ".concat(o))}return i}function Ze(r){var n=r.gl,i=r.buffer,e=r.program,t=r.vertexShader,a=r.fragmentShader;n.deleteShader(t),n.deleteShader(a),n.deleteProgram(e),n.deleteBuffer(i)}var qe=`#define PICKING_MODE
package/assets/index.html CHANGED
@@ -12,7 +12,7 @@
12
12
  <link rel="icon" type="image/png" sizes="32x32" href="./favicon-32.png" />
13
13
  <link rel="apple-touch-icon" href="./apple-touch-icon.png" />
14
14
  <title>Canonry</title>
15
- <script type="module" crossorigin src="./assets/index-Wqv7kvs-.js"></script>
15
+ <script type="module" crossorigin src="./assets/index-CQGAqmDx.js"></script>
16
16
  <link rel="modulepreload" crossorigin href="./assets/vendor-tanstack-Dock0eH1.js">
17
17
  <link rel="modulepreload" crossorigin href="./assets/vendor-radix-4UOaVWza.js">
18
18
  <link rel="modulepreload" crossorigin href="./assets/vendor-recharts-D8rt5lKn.js">
@@ -7453,6 +7453,24 @@ var gscPerformanceDailyPointSchema = z17.object({
7453
7453
  impressions: z17.number(),
7454
7454
  ctr: z17.number()
7455
7455
  });
7456
+ var gscWindowRangeSchema = z17.object({
7457
+ /** Inclusive lower bound, or `null` for the `all` window. */
7458
+ startDate: z17.string().nullable(),
7459
+ /** Inclusive upper bound: the last date the property published. */
7460
+ endDate: z17.string().nullable(),
7461
+ /** `MAX(date)` across the project's GSC data, ignoring the window. */
7462
+ latestDataDate: z17.string().nullable(),
7463
+ /**
7464
+ * Calendar days since the last day with recorded traffic, on GSC's Pacific
7465
+ * calendar. `null` with no data.
7466
+ *
7467
+ * NOT Google's publication lag: Search Analytics omits zero-data days, so a
7468
+ * quiet tail is indistinguishable from an unpublished one and inflates this
7469
+ * number. Render it as "data through <endDate>", never as "Search Console is
7470
+ * N days behind".
7471
+ */
7472
+ daysSinceLatestData: z17.number().nullable()
7473
+ });
7456
7474
  var gscPerformanceDailyDtoSchema = z17.object({
7457
7475
  totals: z17.object({
7458
7476
  clicks: z17.number(),
@@ -7460,7 +7478,14 @@ var gscPerformanceDailyDtoSchema = z17.object({
7460
7478
  ctr: z17.number(),
7461
7479
  days: z17.number()
7462
7480
  }),
7463
- daily: z17.array(gscPerformanceDailyPointSchema)
7481
+ daily: z17.array(gscPerformanceDailyPointSchema),
7482
+ /**
7483
+ * Optional because a server older than this field omits it. Both the web and
7484
+ * the CLI guard for that skew; declaring it required here would tell a
7485
+ * generated consumer it may dereference the field safely against a legacy
7486
+ * response, which is exactly the crash those guards exist to prevent.
7487
+ */
7488
+ window: gscWindowRangeSchema.optional()
7464
7489
  });
7465
7490
  var gscTopPageRowSchema = z17.object({
7466
7491
  page: z17.string(),
@@ -14900,6 +14925,7 @@ export {
14900
14925
  formatDate,
14901
14926
  formatIsoDate,
14902
14927
  formatIsoDateInTimeZone,
14928
+ shiftIsoCalendarDate,
14903
14929
  isoDateDaysBeforeInTimeZone,
14904
14930
  startOfDayHourInTimeZone,
14905
14931
  formatDateRange,
@@ -81,7 +81,7 @@ import {
81
81
  trafficConnectWordpressRequestSchema,
82
82
  trafficEventKindSchema,
83
83
  trafficSeriesGranularitySchema
84
- } from "./chunk-7M7T5QXS.js";
84
+ } from "./chunk-EXDO7EPL.js";
85
85
 
86
86
  // src/config.ts
87
87
  import fs from "fs";
@@ -499,6 +499,7 @@ import {
499
499
  segmentCrawlerHits,
500
500
  serializeRunError,
501
501
  settingsDtoSchema,
502
+ shiftIsoCalendarDate,
502
503
  siteAuditLivePageHealthSchema,
503
504
  siteAuditPageFactorSchema,
504
505
  siteAuditPagesResponseSchema,
@@ -577,7 +578,7 @@ import {
577
578
  wordpressSchemaDeployResultDtoSchema,
578
579
  wordpressSchemaStatusResultDtoSchema,
579
580
  wordpressStatusDtoSchema
580
- } from "./chunk-7M7T5QXS.js";
581
+ } from "./chunk-EXDO7EPL.js";
581
582
 
582
583
  // src/intelligence-service.ts
583
584
  import { eq as eq59, desc as desc26, asc as asc11, and as and47, ne as ne7, or as or13, inArray as inArray21, gte as gte14, lte as lte12 } from "drizzle-orm";
@@ -641,6 +642,7 @@ __export(schema_exports, {
641
642
  googleConnections: () => googleConnections,
642
643
  gscCoverageSnapshots: () => gscCoverageSnapshots,
643
644
  gscDailyTotals: () => gscDailyTotals,
645
+ gscDataWatermarks: () => gscDataWatermarks,
644
646
  gscQueryDailyTotals: () => gscQueryDailyTotals,
645
647
  gscSearchData: () => gscSearchData,
646
648
  gscUrlInspections: () => gscUrlInspections,
@@ -1141,6 +1143,12 @@ var gscSearchData = sqliteTable("gsc_search_data", {
1141
1143
  index("idx_gsc_search_query").on(table.query),
1142
1144
  index("idx_gsc_search_run").on(table.syncRunId)
1143
1145
  ]);
1146
+ var gscDataWatermarks = sqliteTable("gsc_data_watermarks", {
1147
+ projectId: text("project_id").primaryKey().references(() => projects.id, { onDelete: "cascade" }),
1148
+ dataThroughDate: text("data_through_date").notNull(),
1149
+ syncedThroughDate: text("synced_through_date"),
1150
+ updatedAt: text("updated_at").notNull()
1151
+ });
1144
1152
  var gscDailyTotals = sqliteTable("gsc_daily_totals", {
1145
1153
  id: text("id").primaryKey(),
1146
1154
  projectId: text("project_id").notNull().references(() => projects.id, { onDelete: "cascade" }),
@@ -6177,6 +6185,25 @@ var MIGRATION_VERSIONS = [
6177
6185
  `ALTER TABLE traffic_sources ADD COLUMN queue_backlog_count INTEGER`,
6178
6186
  `ALTER TABLE traffic_sources ADD COLUMN queue_backlog_observed_at TEXT`
6179
6187
  ]
6188
+ },
6189
+ {
6190
+ version: 137,
6191
+ name: "gsc-data-watermark",
6192
+ // The furthest GSC reporting date this project has EVER observed.
6193
+ //
6194
+ // `MAX(date)` over the stored rows is not a frontier: Search Analytics
6195
+ // returns no row for a day with no data, so a quiet tail makes the observed
6196
+ // max walk BACKWARD and drags every anchored window back with it. This
6197
+ // column is monotonic — a sync may only advance it — so a zero-traffic
6198
+ // stretch can never move the frontier the wrong way.
6199
+ statements: [
6200
+ `CREATE TABLE IF NOT EXISTS gsc_data_watermarks (
6201
+ project_id TEXT PRIMARY KEY REFERENCES projects(id) ON DELETE CASCADE,
6202
+ data_through_date TEXT NOT NULL,
6203
+ synced_through_date TEXT,
6204
+ updated_at TEXT NOT NULL
6205
+ )`
6206
+ ]
6180
6207
  }
6181
6208
  ];
6182
6209
  function addRunsMeasurementPlanVersionForeignKey(tx) {
@@ -12194,13 +12221,13 @@ function parseRunTriggerRequest(value) {
12194
12221
  }))
12195
12222
  });
12196
12223
  }
12197
- function parseListLimit(raw, defaultValue, max) {
12224
+ function parseListLimit(raw, defaultValue, max2) {
12198
12225
  if (raw === void 0) return defaultValue;
12199
12226
  const parsed = Number(raw);
12200
12227
  if (!Number.isFinite(parsed) || parsed < 1 || !Number.isInteger(parsed)) {
12201
12228
  throw validationError('"limit" must be a positive integer');
12202
12229
  }
12203
- return Math.min(parsed, max);
12230
+ return Math.min(parsed, max2);
12204
12231
  }
12205
12232
  function parseListKind(raw) {
12206
12233
  if (raw === void 0 || raw === "") return null;
@@ -18576,7 +18603,7 @@ function validateCron(expr) {
18576
18603
  }
18577
18604
  return true;
18578
18605
  }
18579
- function validateCronField(field, min, max) {
18606
+ function validateCronField(field, min, max2) {
18580
18607
  if (field === "*") return true;
18581
18608
  const segments = field.split(",");
18582
18609
  for (const segment of segments) {
@@ -18592,7 +18619,7 @@ function validateCronField(field, min, max) {
18592
18619
  if (rangeParts.length > 2) return false;
18593
18620
  for (const part of rangeParts) {
18594
18621
  const num = parseInt(part, 10);
18595
- if (isNaN(num) || num < min || num > max) return false;
18622
+ if (isNaN(num) || num < min || num > max2) return false;
18596
18623
  }
18597
18624
  }
18598
18625
  return true;
@@ -19412,16 +19439,16 @@ function addAuditHistoryFilters(filters, query) {
19412
19439
  if (query.actor) filters.push(eq22(auditLog.actor, query.actor));
19413
19440
  if (query.entityType) filters.push(eq22(auditLog.entityType, query.entityType));
19414
19441
  }
19415
- function parseBoundedInt(value, fallback, max) {
19442
+ function parseBoundedInt(value, fallback, max2) {
19416
19443
  const parsed = Number.parseInt(value ?? "", 10);
19417
19444
  if (!Number.isFinite(parsed) || parsed < 0) return fallback;
19418
- return Math.min(parsed, max);
19445
+ return Math.min(parsed, max2);
19419
19446
  }
19420
- function parseOptionalPositiveInt(value, max) {
19447
+ function parseOptionalPositiveInt(value, max2) {
19421
19448
  if (value == null) return void 0;
19422
19449
  const parsed = Number.parseInt(value, 10);
19423
19450
  if (!Number.isFinite(parsed) || parsed <= 0) return void 0;
19424
- return Math.min(parsed, max);
19451
+ return Math.min(parsed, max2);
19425
19452
  }
19426
19453
 
19427
19454
  // ../api-routes/src/analytics.ts
@@ -21168,7 +21195,47 @@ function winnabilityClassRank(winnabilityClass) {
21168
21195
  }
21169
21196
 
21170
21197
  // ../api-routes/src/gsc-totals.ts
21171
- import { and as and21, asc as asc4, eq as eq27, sql as sql8 } from "drizzle-orm";
21198
+ import { and as and21, asc as asc4, eq as eq27, sql as sql8, max } from "drizzle-orm";
21199
+ var WINDOW_DAYS = { "7d": 7, "30d": 30, "90d": 90 };
21200
+ function resolveGscWindowRange(window, latestDataDate, today) {
21201
+ if (window === "all") {
21202
+ return {
21203
+ startDate: null,
21204
+ endDate: latestDataDate,
21205
+ latestDataDate,
21206
+ daysSinceLatestData: gscDaysSinceLatestData(latestDataDate, today)
21207
+ };
21208
+ }
21209
+ return resolveGscWindowDays(WINDOW_DAYS[window], latestDataDate, today);
21210
+ }
21211
+ function resolveGscWindowDays(days, latestDataDate, today) {
21212
+ if (latestDataDate === null) {
21213
+ return {
21214
+ startDate: shiftIsoCalendarDate(today, -days),
21215
+ endDate: null,
21216
+ latestDataDate: null,
21217
+ daysSinceLatestData: null
21218
+ };
21219
+ }
21220
+ return {
21221
+ startDate: shiftIsoCalendarDate(latestDataDate, -(days - 1)),
21222
+ endDate: latestDataDate,
21223
+ latestDataDate,
21224
+ daysSinceLatestData: gscDaysSinceLatestData(latestDataDate, today)
21225
+ };
21226
+ }
21227
+ function gscDaysSinceLatestData(latestDataDate, today) {
21228
+ if (latestDataDate === null) return null;
21229
+ return Math.max(0, Math.round(
21230
+ (Date.parse(`${today}T00:00:00Z`) - Date.parse(`${latestDataDate}T00:00:00Z`)) / 864e5
21231
+ ));
21232
+ }
21233
+ function readLatestGscDataDate(db, projectId) {
21234
+ const watermark = db.select({ through: gscDataWatermarks.dataThroughDate }).from(gscDataWatermarks).where(eq27(gscDataWatermarks.projectId, projectId)).get()?.through ?? null;
21235
+ const property = db.select({ latest: max(gscDailyTotals.date) }).from(gscDailyTotals).where(eq27(gscDailyTotals.projectId, projectId)).get()?.latest ?? null;
21236
+ const dimensioned = db.select({ latest: max(gscSearchData.date) }).from(gscSearchData).where(eq27(gscSearchData.projectId, projectId)).get()?.latest ?? null;
21237
+ return [watermark, property, dimensioned].filter((d) => d !== null).reduce((maxDate, d) => maxDate === null || d > maxDate ? d : maxDate, null);
21238
+ }
21172
21239
  function readGscDailyTotals(db, projectId, startDate, endDate) {
21173
21240
  const rows = db.select({
21174
21241
  date: gscDailyTotals.date,
@@ -22427,7 +22494,7 @@ function renderWhatsChanged(report, audience) {
22427
22494
  }
22428
22495
  function renderProviderBars(rates) {
22429
22496
  if (rates.length === 0) return "";
22430
- const max = Math.max(...rates.map((r) => r.citationRate), 100);
22497
+ const max2 = Math.max(...rates.map((r) => r.citationRate), 100);
22431
22498
  const width = 600;
22432
22499
  const height = Math.max(rates.length * 32 + 24, 80);
22433
22500
  const labelWidth = 80;
@@ -22436,7 +22503,7 @@ function renderProviderBars(rates) {
22436
22503
  const bars = rates.map((r, i) => {
22437
22504
  const y = i * 32 + padding;
22438
22505
  const barHeight = 22;
22439
- const w = max > 0 ? r.citationRate / max * barWidth : 0;
22506
+ const w = max2 > 0 ? r.citationRate / max2 * barWidth : 0;
22440
22507
  const color = COLORS.series[i % COLORS.series.length];
22441
22508
  return `
22442
22509
  <text x="${labelWidth - 8}" y="${y + 16}" fill="${COLORS.textMuted}" font-size="11" text-anchor="end">${escapeHtml(r.provider)}</text>
@@ -22486,14 +22553,14 @@ function renderCitationScorecard(report) {
22486
22553
  }
22487
22554
  function renderLandscapeBars(data, heading, ariaLabel) {
22488
22555
  if (data.length <= 1) return "";
22489
- const max = Math.max(...data.map((d) => d.count), 1);
22556
+ const max2 = Math.max(...data.map((d) => d.count), 1);
22490
22557
  const width = 600;
22491
22558
  const height = data.length * 28 + 16;
22492
22559
  const labelWidth = 160;
22493
22560
  const bars = data.map((d, i) => {
22494
22561
  const y = i * 28 + 8;
22495
22562
  const barHeight = 18;
22496
- const w = d.count / max * (width - labelWidth - 60);
22563
+ const w = d.count / max2 * (width - labelWidth - 60);
22497
22564
  const color = d.isProject ? COLORS.accent : COLORS.series[(i + 1) % COLORS.series.length];
22498
22565
  return `
22499
22566
  <text x="${labelWidth - 8}" y="${y + 13}" fill="${COLORS.textMuted}" font-size="11" text-anchor="end">${escapeHtml(d.label)}</text>
@@ -22584,9 +22651,9 @@ function renderCategoryBars(buckets) {
22584
22651
  if (buckets.length === 0) return "";
22585
22652
  const total = buckets.reduce((s, b) => s + b.count, 0);
22586
22653
  if (total === 0) return "";
22587
- const max = Math.max(...buckets.map((b) => b.count), 1);
22654
+ const max2 = Math.max(...buckets.map((b) => b.count), 1);
22588
22655
  const rows = buckets.map((b) => {
22589
- const pct = b.count / max * 100;
22656
+ const pct = b.count / max2 * 100;
22590
22657
  const tone = SOURCE_CATEGORY_TONE[b.category] ?? "neutral";
22591
22658
  const color = tone === "negative" ? COLORS.negative : tone === "caution" ? COLORS.caution : COLORS.accent;
22592
22659
  return `
@@ -22662,11 +22729,11 @@ function renderLineChart(points, color, title, height = 200) {
22662
22729
  const padY = 24;
22663
22730
  const usableW = width - padX * 2;
22664
22731
  const usableH = height - padY * 2;
22665
- const max = Math.max(...points.map((p) => p.y), 1);
22732
+ const max2 = Math.max(...points.map((p) => p.y), 1);
22666
22733
  const stepX = points.length > 1 ? usableW / (points.length - 1) : 0;
22667
22734
  const xy = points.map((p, i) => ({
22668
22735
  x: padX + i * stepX,
22669
- y: padY + usableH - p.y / max * usableH,
22736
+ y: padY + usableH - p.y / max2 * usableH,
22670
22737
  raw: p
22671
22738
  }));
22672
22739
  const path8 = xy.map((p, i) => `${i === 0 ? "M" : "L"} ${p.x.toFixed(1)} ${p.y.toFixed(1)}`).join(" ");
@@ -22679,7 +22746,7 @@ function renderLineChart(points, color, title, height = 200) {
22679
22746
  <h3>${escapeHtml(title)}</h3>
22680
22747
  <svg viewBox="0 0 ${width} ${height}" width="100%" preserveAspectRatio="xMinYMin meet" role="img" aria-label="${escapeHtml(title)} line chart">
22681
22748
  <line x1="${padX}" y1="${padY + usableH}" x2="${padX + usableW}" y2="${padY + usableH}" stroke="${COLORS.border}" stroke-width="1" />
22682
- <text x="${padX - 6}" y="${(padY + 4).toFixed(1)}" fill="${COLORS.textFaint}" font-size="9" text-anchor="end">${formatNumber(max)}</text>
22749
+ <text x="${padX - 6}" y="${(padY + 4).toFixed(1)}" fill="${COLORS.textFaint}" font-size="9" text-anchor="end">${formatNumber(max2)}</text>
22683
22750
  <text x="${padX - 6}" y="${(padY + usableH).toFixed(1)}" fill="${COLORS.textFaint}" font-size="9" text-anchor="end">0</text>
22684
22751
  <path d="${path8}" stroke="${color}" stroke-width="2" fill="none" />
22685
22752
  ${dots}
@@ -27371,7 +27438,12 @@ function summarizeTransitionsFromSnapshots(latest, previous, since) {
27371
27438
  return { since, gained, lost, emerging };
27372
27439
  }
27373
27440
  function buildSuggestedQueriesFromGsc(app, projectId, trackedQueries) {
27374
- const cutoff = new Date(Date.now() - 28 * 24 * 60 * 60 * 1e3).toISOString().slice(0, 10);
27441
+ const suggestionWindow = resolveGscWindowDays(
27442
+ 28,
27443
+ readLatestGscDataDate(app.db, projectId),
27444
+ (/* @__PURE__ */ new Date()).toISOString().slice(0, 10)
27445
+ );
27446
+ const cutoff = suggestionWindow.startDate ?? "";
27375
27447
  const dimensionedRows = app.db.select({
27376
27448
  date: gscSearchData.date,
27377
27449
  query: gscSearchData.query,
@@ -27384,11 +27456,14 @@ function buildSuggestedQueriesFromGsc(app, projectId, trackedQueries) {
27384
27456
  }).from(gscSearchData).where(and28(
27385
27457
  eq34(gscSearchData.projectId, projectId),
27386
27458
  sql12`${gscSearchData.date} >= ${cutoff}`,
27459
+ // Same upper bound as the accurate source below. The merge picks a source
27460
+ // PER DAY, so an asymmetric range would let a dimensioned-only day past
27461
+ // the window's end into a basket the other source cannot balance.
27462
+ sql12`${gscSearchData.date} <= ${suggestionWindow.endDate ?? "9999-12-31"}`,
27387
27463
  sql12`${gscSearchData.impressions} > 0`
27388
27464
  )).groupBy(gscSearchData.date, gscSearchData.query).all();
27389
- const todayIso = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
27390
27465
  const merged = mergeGscQueryTotalsWithFallback(
27391
- readGscQueryDailyRows(app.db, projectId, cutoff, todayIso),
27466
+ readGscQueryDailyRows(app.db, projectId, cutoff, suggestionWindow.endDate ?? "9999-12-31"),
27392
27467
  dimensionedRows.map((r) => ({
27393
27468
  date: r.date,
27394
27469
  query: r.query,
@@ -30850,6 +30925,12 @@ var routeCatalog = [
30850
30925
  nameParameter,
30851
30926
  { name: "startDate", in: "query", description: "Filter by start date.", schema: stringSchema },
30852
30927
  { name: "endDate", in: "query", description: "Filter by end date.", schema: stringSchema },
30928
+ {
30929
+ name: "days",
30930
+ in: "query",
30931
+ description: "Relative span in days, resolved server-side against the last published GSC date. Prefer this over client-computed start/end dates: those bypass the published-day anchoring and are pinned to the caller's clock rather than Google's Pacific calendar.",
30932
+ schema: stringSchema
30933
+ },
30853
30934
  { name: "query", in: "query", description: "Filter by search query.", schema: stringSchema },
30854
30935
  { name: "page", in: "query", description: "Filter by page URL.", schema: stringSchema },
30855
30936
  {
@@ -35015,8 +35096,8 @@ var SEVERITY_ICONS = {
35015
35096
  [AlertSeverities.success]: "\u2705",
35016
35097
  [AlertSeverities.info]: "\u{1F4CA}"
35017
35098
  };
35018
- function clamp(value, max) {
35019
- return value.length <= max ? value : `${value.slice(0, max - 1)}\u2026`;
35099
+ function clamp(value, max2) {
35100
+ return value.length <= max2 ? value : `${value.slice(0, max2 - 1)}\u2026`;
35020
35101
  }
35021
35102
  function absoluteLink(url) {
35022
35103
  if (!url) return void 0;
@@ -35405,6 +35486,7 @@ var INDEXING_SCOPE = "https://www.googleapis.com/auth/indexing";
35405
35486
  var GSC_API_BASE = "https://www.googleapis.com/webmasters/v3";
35406
35487
  var URL_INSPECTION_API = "https://searchconsole.googleapis.com/v1/urlInspection/index:inspect";
35407
35488
  var GSC_MAX_ROWS_PER_REQUEST = 25e3;
35489
+ var GSC_REPORTING_TIME_ZONE = "America/Los_Angeles";
35408
35490
  var GSC_DATA_LAG_DAYS = 3;
35409
35491
  var INDEXING_API_BASE = "https://indexing.googleapis.com/v3";
35410
35492
  var INDEXING_API_DAILY_LIMIT = 200;
@@ -36448,11 +36530,11 @@ async function fetchDailyTotals(accessToken, propertyId, days) {
36448
36530
  ga4Log("info", "fetch-daily-totals.done", { propertyId, days: syncDays, rows: rows.length });
36449
36531
  return rows;
36450
36532
  }
36451
- var WINDOW_DAYS = { "7d": 7, "30d": 30, "90d": 90 };
36533
+ var WINDOW_DAYS2 = { "7d": 7, "30d": 30, "90d": 90 };
36452
36534
  async function fetchWindowSummary(accessToken, propertyId, windowKey) {
36453
36535
  validateAccessToken2(accessToken);
36454
36536
  validatePropertyId(propertyId);
36455
- const days = WINDOW_DAYS[windowKey];
36537
+ const days = WINDOW_DAYS2[windowKey];
36456
36538
  if (!days) {
36457
36539
  throw new GA4ApiError(`Unsupported windowKey "${windowKey}" \u2014 must be 7d, 30d, or 90d`, 400);
36458
36540
  }
@@ -37027,6 +37109,26 @@ function stableStringify3(value) {
37027
37109
  }
37028
37110
 
37029
37111
  // ../api-routes/src/google.ts
37112
+ function resolveReportedWindow(resolved, startDate, endDate) {
37113
+ const start = startDate ?? resolved.startDate;
37114
+ const end = endDate ?? resolved.endDate;
37115
+ if (start === null || end === null || start <= end) {
37116
+ return { ...resolved, startDate: start, endDate: end };
37117
+ }
37118
+ return {
37119
+ ...resolved,
37120
+ startDate: startDate ? start : null,
37121
+ endDate: endDate ? end : null
37122
+ };
37123
+ }
37124
+ function assertForwardRange(startDate, endDate) {
37125
+ if (startDate && endDate && startDate > endDate) {
37126
+ throw validationError(`startDate "${startDate}" is after endDate "${endDate}".`);
37127
+ }
37128
+ }
37129
+ function gscToday() {
37130
+ return formatIsoDateInTimeZone((/* @__PURE__ */ new Date()).toISOString(), GSC_REPORTING_TIME_ZONE);
37131
+ }
37030
37132
  var GOOGLE_OAUTH_COMPLETE_MESSAGE = "canonry:google-oauth-complete";
37031
37133
  function googleOAuthSuccessHtml(type) {
37032
37134
  const message = JSON.stringify({
@@ -37457,11 +37559,19 @@ async function googleRoutes(app, opts) {
37457
37559
  );
37458
37560
  }
37459
37561
  const orderBy = parsedOrderBy.data;
37460
- const cutoffDate = !startDate ? windowCutoff(parseWindow(request.query.window))?.slice(0, 10) ?? null : null;
37562
+ assertForwardRange(startDate, endDate);
37563
+ const daysParam = request.query.days === void 0 ? null : Number(request.query.days);
37564
+ if (daysParam !== null && (!Number.isInteger(daysParam) || daysParam < 1)) {
37565
+ throw validationError('"days" must be a positive integer');
37566
+ }
37567
+ const latestDataDate = readLatestGscDataDate(app.db, project.id);
37568
+ const resolvedWindow = daysParam === null ? resolveGscWindowRange(parseWindow(request.query.window), latestDataDate, gscToday()) : resolveGscWindowDays(daysParam, latestDataDate, gscToday());
37569
+ const cutoffDate = startDate ? null : resolvedWindow.startDate;
37570
+ const effectiveEndDate = endDate ?? (daysParam === null ? void 0 : resolvedWindow.endDate ?? void 0);
37461
37571
  const conditions = [eq39(gscSearchData.projectId, project.id)];
37462
37572
  if (startDate) conditions.push(sql13`${gscSearchData.date} >= ${startDate}`);
37463
37573
  else if (cutoffDate) conditions.push(sql13`${gscSearchData.date} >= ${cutoffDate}`);
37464
- if (endDate) conditions.push(sql13`${gscSearchData.date} <= ${endDate}`);
37574
+ if (effectiveEndDate) conditions.push(sql13`${gscSearchData.date} <= ${effectiveEndDate}`);
37465
37575
  if (query) conditions.push(sql13`${gscSearchData.query} LIKE ${"%" + escapeLikePattern(query) + "%"} ESCAPE '\\'`);
37466
37576
  if (page) conditions.push(sql13`${gscSearchData.page} LIKE ${"%" + escapeLikePattern(page) + "%"} ESCAPE '\\'`);
37467
37577
  const limitVal = Math.max(parseInt(limit ?? "500", 10) || 0, 1);
@@ -37498,9 +37608,15 @@ async function googleRoutes(app, opts) {
37498
37608
  app.get("/projects/:name/google/gsc/performance/daily", async (request) => {
37499
37609
  const project = resolveProject(app.db, request.params.name);
37500
37610
  const { startDate, endDate } = request.query;
37501
- const cutoffDate = !startDate ? windowCutoff(parseWindow(request.query.window))?.slice(0, 10) ?? null : null;
37611
+ assertForwardRange(startDate, endDate);
37612
+ const resolvedWindow = resolveGscWindowRange(
37613
+ parseWindow(request.query.window),
37614
+ readLatestGscDataDate(app.db, project.id),
37615
+ gscToday()
37616
+ );
37617
+ const cutoffDate = startDate ? null : resolvedWindow.startDate;
37502
37618
  const windowStart = startDate ?? cutoffDate ?? "";
37503
- const windowEnd = endDate ?? "9999-12-31";
37619
+ const windowEnd = endDate ?? resolvedWindow.endDate ?? "9999-12-31";
37504
37620
  const dailyTotals = readGscDailyTotals(app.db, project.id, windowStart, windowEnd);
37505
37621
  const conditions = [eq39(gscSearchData.projectId, project.id)];
37506
37622
  if (startDate) conditions.push(sql13`${gscSearchData.date} >= ${startDate}`);
@@ -37534,13 +37650,30 @@ async function googleRoutes(app, opts) {
37534
37650
  ctr: totalImpressions > 0 ? totalClicks / totalImpressions : 0,
37535
37651
  days: daily.length
37536
37652
  },
37537
- daily
37653
+ daily,
37654
+ // The period actually returned. An explicit start/end wins over the
37655
+ // label, so echo what was used rather than what the window would have
37656
+ // chosen — a caller must be able to label the data it got.
37657
+ //
37658
+ // Mixing one explicit bound with the computed opposite one can invert the
37659
+ // range (an explicit `startDate` of 2030-01-01 against a computed
37660
+ // `endDate` of 2026-01-06), which would describe a period that cannot
37661
+ // contain the rows beside it. When only one side is given, the other is
37662
+ // dropped rather than reported reversed: an absent bound is honest about
37663
+ // being unspecified, a reversed pair is not.
37664
+ window: resolveReportedWindow(resolvedWindow, startDate, endDate)
37538
37665
  };
37539
37666
  });
37540
37667
  app.get("/projects/:name/google/gsc/top-pages", async (request) => {
37541
37668
  const project = resolveProject(app.db, request.params.name);
37542
37669
  const { startDate, endDate, limit } = request.query;
37543
- const cutoffDate = !startDate ? windowCutoff(parseWindow(request.query.window))?.slice(0, 10) ?? null : null;
37670
+ assertForwardRange(startDate, endDate);
37671
+ const resolvedWindow = resolveGscWindowRange(
37672
+ parseWindow(request.query.window),
37673
+ readLatestGscDataDate(app.db, project.id),
37674
+ gscToday()
37675
+ );
37676
+ const cutoffDate = startDate ? null : resolvedWindow.startDate;
37544
37677
  const conditions = [eq39(gscSearchData.projectId, project.id)];
37545
37678
  if (startDate) conditions.push(sql13`${gscSearchData.date} >= ${startDate}`);
37546
37679
  else if (cutoffDate) conditions.push(sql13`${gscSearchData.date} >= ${cutoffDate}`);
@@ -37552,7 +37685,7 @@ async function googleRoutes(app, opts) {
37552
37685
  impressions: sql13`COALESCE(SUM(${gscSearchData.impressions}), 0)`
37553
37686
  }).from(gscSearchData).where(and30(...conditions)).groupBy(gscSearchData.page).orderBy(desc17(sql13`SUM(${gscSearchData.clicks})`), desc17(sql13`SUM(${gscSearchData.impressions})`)).limit(limitVal).all();
37554
37687
  const windowStart = startDate ?? cutoffDate ?? "";
37555
- const windowEnd = endDate ?? "9999-12-31";
37688
+ const windowEnd = endDate ?? resolvedWindow.endDate ?? "9999-12-31";
37556
37689
  const dailyTotals = readGscDailyTotals(app.db, project.id, windowStart, windowEnd);
37557
37690
  const totalClicks = dailyTotals.reduce((sum, d) => sum + d.clicks, 0);
37558
37691
  const totalImpressions = dailyTotals.reduce((sum, d) => sum + d.impressions, 0);
@@ -58838,13 +58971,13 @@ function emptyScore(projectName) {
58838
58971
  prioritizedFixes: []
58839
58972
  };
58840
58973
  }
58841
- function parsePositiveInt(value, fallback, max) {
58974
+ function parsePositiveInt(value, fallback, max2) {
58842
58975
  const n = typeof value === "string" ? Number.parseInt(value, 10) : typeof value === "number" ? value : NaN;
58843
58976
  if (!Number.isFinite(n) || n < 0) return fallback;
58844
- return Math.min(max, Math.floor(n));
58977
+ return Math.min(max2, Math.floor(n));
58845
58978
  }
58846
- function parseBoundedLimit(value, fallback, max) {
58847
- const parsed = parsePositiveInt(value, fallback, max);
58979
+ function parseBoundedLimit(value, fallback, max2) {
58980
+ const parsed = parsePositiveInt(value, fallback, max2);
58848
58981
  return Math.max(1, parsed);
58849
58982
  }
58850
58983
  function parseSiteHealthState(value) {
@@ -62025,6 +62158,7 @@ export {
62025
62158
  doctorHealthState,
62026
62159
  notifications,
62027
62160
  gscSearchData,
62161
+ gscDataWatermarks,
62028
62162
  gscDailyTotals,
62029
62163
  gscQueryDailyTotals,
62030
62164
  gscUrlInspections,
@@ -62101,6 +62235,7 @@ export {
62101
62235
  renderReportHtml,
62102
62236
  toAlertView,
62103
62237
  resolveDestination,
62238
+ GSC_REPORTING_TIME_ZONE,
62104
62239
  GSC_DATA_LAG_DAYS,
62105
62240
  refreshAccessToken,
62106
62241
  fetchSearchAnalytics,