@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.
- package/assets/assets/{AuditHistoryPanel-AtgoG2AH.js → AuditHistoryPanel-C_1twF00.js} +1 -1
- package/assets/assets/{BacklinksPage-DrOSF7Mu.js → BacklinksPage-CfAuMCaN.js} +1 -1
- package/assets/assets/{HistoryPage-CGQXleJc.js → HistoryPage-DrRxOL3j.js} +1 -1
- package/assets/assets/{MeasurementPropertyPage-C7D2OgIQ.js → MeasurementPropertyPage-BFtxx5Jw.js} +1 -1
- package/assets/assets/{ProjectPage-Lp1VjNvL.js → ProjectPage-Djvhx4HD.js} +9 -9
- package/assets/assets/{RunRow-BdzKKODo.js → RunRow-DVZXibR2.js} +1 -1
- package/assets/assets/{RunsPage-BU96L07S.js → RunsPage-CAUMy7By.js} +1 -1
- package/assets/assets/{SettingsPage-LEca0kDH.js → SettingsPage-CcSOmQAl.js} +1 -1
- package/assets/assets/{SiteHealthSection-CKM4DUfE.js → SiteHealthSection-DYjEWd1I.js} +3 -3
- package/assets/assets/{TrafficPage-tU9wl1F_.js → TrafficPage-BWM33jnJ.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-DZTpnU9f.js → TrafficSourceDetailPage-DvEZ_JGY.js} +1 -1
- package/assets/assets/{extract-error-message-BAyN-ftk.js → extract-error-message-CnKOJkYB.js} +1 -1
- package/assets/assets/{index-Wqv7kvs-.js → index-CQGAqmDx.js} +13 -13
- package/assets/assets/{react-sigma_core.esm.min-DlZOAc_w.js → react-sigma_core.esm.min-CHCAIMBW.js} +1 -1
- package/assets/index.html +1 -1
- package/dist/{chunk-7M7T5QXS.js → chunk-EXDO7EPL.js} +27 -1
- package/dist/{chunk-HQAVEK42.js → chunk-HCGTKQCG.js} +1 -1
- package/dist/{chunk-X7CYY5Q7.js → chunk-J27J2DF6.js} +172 -37
- package/dist/{chunk-XGESWHFP.js → chunk-W6OWEPZG.js} +35 -18
- package/dist/cli.js +17 -11
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-6XQMM466.js → intelligence-service-HKDIVTZB.js} +2 -2
- package/dist/mcp.js +2 -2
- package/package.json +8 -8
package/assets/assets/{react-sigma_core.esm.min-DlZOAc_w.js → react-sigma_core.esm.min-CHCAIMBW.js}
RENAMED
|
@@ -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-
|
|
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-
|
|
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,
|
|
@@ -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-
|
|
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,
|
|
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,
|
|
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,
|
|
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 >
|
|
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,
|
|
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,
|
|
19445
|
+
return Math.min(parsed, max2);
|
|
19419
19446
|
}
|
|
19420
|
-
function parseOptionalPositiveInt(value,
|
|
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,
|
|
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
|
|
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 =
|
|
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
|
|
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 /
|
|
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
|
|
22654
|
+
const max2 = Math.max(...buckets.map((b) => b.count), 1);
|
|
22588
22655
|
const rows = buckets.map((b) => {
|
|
22589
|
-
const pct = b.count /
|
|
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
|
|
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 /
|
|
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(
|
|
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
|
|
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,
|
|
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,
|
|
35019
|
-
return value.length <=
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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(
|
|
58977
|
+
return Math.min(max2, Math.floor(n));
|
|
58845
58978
|
}
|
|
58846
|
-
function parseBoundedLimit(value, fallback,
|
|
58847
|
-
const parsed = parsePositiveInt(value, fallback,
|
|
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,
|