@canonry/canonry 4.176.0 → 4.177.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 (28) hide show
  1. package/assets/agent-workspace/skills/canonry/references/server-side-traffic.md +15 -0
  2. package/assets/assets/{AuditHistoryPanel-aEUCJheK.js → AuditHistoryPanel-YZvGU1la.js} +1 -1
  3. package/assets/assets/{BacklinksPage-BcWequGL.js → BacklinksPage-CB2uJWWy.js} +1 -1
  4. package/assets/assets/{HistoryPage-D0BWQK0c.js → HistoryPage-D9IxxbQ9.js} +1 -1
  5. package/assets/assets/{MeasurementPropertyPage-D96eQnYJ.js → MeasurementPropertyPage-CxgnnPdp.js} +1 -1
  6. package/assets/assets/{ProjectPage-CoRkwGec.js → ProjectPage-CPmaXzhL.js} +8 -8
  7. package/assets/assets/{RunRow--3y-0dSr.js → RunRow-2KxOta8F.js} +1 -1
  8. package/assets/assets/{RunsPage-7wdCl_J3.js → RunsPage-ya8vTkyd.js} +1 -1
  9. package/assets/assets/{SettingsPage-D37dV5-m.js → SettingsPage-lTy3o2bo.js} +1 -1
  10. package/assets/assets/{SiteHealthSection-B9WF97sJ.js → SiteHealthSection-Cyu7MIv2.js} +3 -3
  11. package/assets/assets/TrafficPage-DjhKfw57.js +1 -0
  12. package/assets/assets/TrafficSourceDetailPage-Pwi-Dl9Q.js +1 -0
  13. package/assets/assets/{extract-error-message-DlPqK0mV.js → extract-error-message-I1FVWHLH.js} +1 -1
  14. package/assets/assets/{index-CiQNKNMG.js → index-BeLVKN3H.js} +3 -3
  15. package/assets/assets/{react-sigma_core.esm.min-Dc7_SFjo.js → react-sigma_core.esm.min-BX6mOEq5.js} +1 -1
  16. package/assets/index.html +1 -1
  17. package/dist/{chunk-TIEHKR6K.js → chunk-F4ZZKGAC.js} +1 -1
  18. package/dist/{chunk-OSMUOPBR.js → chunk-UXXXKDW4.js} +70 -6
  19. package/dist/{chunk-HYKZOCBT.js → chunk-WW7TDVLV.js} +2 -2
  20. package/dist/{chunk-J3RVQCCQ.js → chunk-X776E66Z.js} +680 -634
  21. package/dist/{chunk-DSGX2IAI.js → chunk-YWFNRDLK.js} +4 -4
  22. package/dist/cli.js +7 -7
  23. package/dist/index.js +4 -4
  24. package/dist/{intelligence-service-RSZTVVX2.js → intelligence-service-QLLGPZOC.js} +2 -2
  25. package/dist/mcp.js +3 -3
  26. package/package.json +9 -9
  27. package/assets/assets/TrafficPage-Bn1yDSRr.js +0 -1
  28. package/assets/assets/TrafficSourceDetailPage-CURlB_yO.js +0 -1
@@ -61,6 +61,7 @@ import {
61
61
  GoogleMarketingProviders,
62
62
  GtmConnectionStates,
63
63
  GtmSnapshotKinds,
64
+ LOCATION_REDIRECT_STATUSES,
64
65
  LOGIN_FAILED_MESSAGE,
65
66
  MEASUREMENT_DRAFT_MAX_ASSIGNMENTS,
66
67
  MEASUREMENT_DRAFT_MAX_ASSIGNMENTS_PER_ACTION,
@@ -361,6 +362,7 @@ import {
361
362
  indexingRequestResponseDtoSchema,
362
363
  internalError,
363
364
  isBrowserProvider,
365
+ isLocationRedirectStatus,
364
366
  isReadOnlyKey,
365
367
  isRetryableHttpError,
366
368
  isTemplateLinkRatio,
@@ -628,10 +630,10 @@ import {
628
630
  wordpressSchemaDeployResultDtoSchema,
629
631
  wordpressSchemaStatusResultDtoSchema,
630
632
  wordpressStatusDtoSchema
631
- } from "./chunk-OSMUOPBR.js";
633
+ } from "./chunk-UXXXKDW4.js";
632
634
 
633
635
  // src/intelligence-service.ts
634
- import { eq as eq61, desc as desc27, asc as asc11, and as and49, ne as ne8, or as or14, inArray as inArray21, gte as gte14, lte as lte12 } from "drizzle-orm";
636
+ import { eq as eq61, desc as desc27, asc as asc11, and as and50, ne as ne8, or as or14, inArray as inArray21, gte as gte14, lte as lte12 } from "drizzle-orm";
635
637
 
636
638
  // ../db/src/client.ts
637
639
  import { mkdirSync } from "fs";
@@ -14367,7 +14369,7 @@ async function requestFollowingValidatedRedirects(startUrl, resolveTarget, trans
14367
14369
  timeoutMs: remainingTime(deadlineAt),
14368
14370
  maxBodyBytes: limits.maxBodyBytes
14369
14371
  }), deadlineAt);
14370
- if (!isRedirect(response.status)) return response;
14372
+ if (!isLocationRedirectStatus(response.status)) return response;
14371
14373
  if (redirects >= limits.maxRedirects) throw new Error(`Sitemap redirect count exceeds the maximum of ${limits.maxRedirects}`);
14372
14374
  const location = firstHeader(response.headers.location);
14373
14375
  if (!location) throw new Error("Sitemap redirect response has no Location header");
@@ -14562,9 +14564,6 @@ function normalizeSitemapUrl(value) {
14562
14564
  function decodeXmlEntities(value) {
14563
14565
  return value.replace(/&(?:amp|lt|gt|quot|apos);/g, (entity) => ({ "&amp;": "&", "&lt;": "<", "&gt;": ">", "&quot;": '"', "&apos;": "'" })[entity]);
14564
14566
  }
14565
- function isRedirect(status) {
14566
- return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
14567
- }
14568
14567
  function firstHeader(value) {
14569
14568
  return Array.isArray(value) ? value[0] : value;
14570
14569
  }
@@ -21743,15 +21742,48 @@ async function intelligenceRoutes(app) {
21743
21742
  });
21744
21743
  }
21745
21744
 
21745
+ // ../api-routes/src/ai-referral-status.ts
21746
+ import { and as and19, sql as sql8 } from "drizzle-orm";
21747
+ var REDIRECT_LIST = sql8.join([...LOCATION_REDIRECT_STATUSES].map((s) => sql8`${s}`), sql8`, `);
21748
+ function referralLandedCondition() {
21749
+ return sql8`${aiReferralEventsHourly.status} NOT IN (${REDIRECT_LIST})`;
21750
+ }
21751
+ function countableReferralCondition() {
21752
+ return and19(nonSubresourceReferralPathCondition(), referralLandedCondition());
21753
+ }
21754
+ function nonSubresourceReferralPathCondition() {
21755
+ return sql8`
21756
+ LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '/_next/static/%'
21757
+ AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '/assets/%'
21758
+ AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '/static/%'
21759
+ AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '/favicon.%'
21760
+ AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.avif'
21761
+ AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.css'
21762
+ AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.gif'
21763
+ AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.ico'
21764
+ AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.jpeg'
21765
+ AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.jpg'
21766
+ AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.js'
21767
+ AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.map'
21768
+ AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.mjs'
21769
+ AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.otf'
21770
+ AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.png'
21771
+ AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.svg'
21772
+ AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.webmanifest'
21773
+ AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.woff'
21774
+ AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.woff2'
21775
+ `;
21776
+ }
21777
+
21746
21778
  // ../api-routes/src/report.ts
21747
- import { and as and22, desc as desc12, eq as eq28, gte as gte5, inArray as inArray12, lt as lt5, lte as lte3, ne as ne3, or as or4, sql as sql9 } from "drizzle-orm";
21779
+ import { and as and23, desc as desc12, eq as eq28, gte as gte5, inArray as inArray12, lt as lt5, lte as lte3, ne as ne3, or as or4, sql as sql10 } from "drizzle-orm";
21748
21780
 
21749
21781
  // ../api-routes/src/content.ts
21750
21782
  import crypto21 from "crypto";
21751
- import { and as and20, desc as desc11, eq as eq26 } from "drizzle-orm";
21783
+ import { and as and21, desc as desc11, eq as eq26 } from "drizzle-orm";
21752
21784
 
21753
21785
  // ../api-routes/src/content-data.ts
21754
- import { and as and19, eq as eq25, desc as desc10, inArray as inArray11 } from "drizzle-orm";
21786
+ import { and as and20, eq as eq25, desc as desc10, inArray as inArray11 } from "drizzle-orm";
21755
21787
  var RECENT_RUNS_WINDOW = 5;
21756
21788
  function loadOrchestratorInput(db, project, locationFilter = void 0) {
21757
21789
  const projectId = project.id;
@@ -21881,7 +21913,7 @@ function listCompetitorDomains(db, projectId) {
21881
21913
  }
21882
21914
  function listRecentAnswerVisibilityRunIds(db, projectId, limit, locationFilter) {
21883
21915
  const rows = db.select({ id: runs.id, location: runs.location }).from(runs).where(
21884
- and19(
21916
+ and20(
21885
21917
  eq25(runs.projectId, projectId),
21886
21918
  eq25(runs.kind, RunKinds["answer-visibility"]),
21887
21919
  // Queued/running/failed/cancelled runs may have partial or no
@@ -21923,7 +21955,7 @@ function buildGaTrafficByPage(db, projectId) {
21923
21955
  }
21924
21956
  function sumAiReferralSessions(db, projectId) {
21925
21957
  const rows = db.select({ sessions: gaAiReferrals.sessions }).from(gaAiReferrals).where(
21926
- and19(
21958
+ and20(
21927
21959
  eq25(gaAiReferrals.projectId, projectId),
21928
21960
  eq25(gaAiReferrals.sourceDimension, "session")
21929
21961
  )
@@ -22267,7 +22299,7 @@ async function contentRoutes(app, opts = {}) {
22267
22299
  dismissedAt: now
22268
22300
  }
22269
22301
  }).run();
22270
- const row = app.db.select().from(contentTargetDismissals).where(and20(
22302
+ const row = app.db.select().from(contentTargetDismissals).where(and21(
22271
22303
  eq26(contentTargetDismissals.projectId, project.id),
22272
22304
  eq26(contentTargetDismissals.targetRef, targetRef)
22273
22305
  )).get();
@@ -22277,7 +22309,7 @@ async function contentRoutes(app, opts = {}) {
22277
22309
  app.delete("/projects/:name/content/dismissals/:targetRef", async (request, reply) => {
22278
22310
  const project = resolveProject(app.db, request.params.name);
22279
22311
  const { targetRef } = request.params;
22280
- const result = app.db.delete(contentTargetDismissals).where(and20(
22312
+ const result = app.db.delete(contentTargetDismissals).where(and21(
22281
22313
  eq26(contentTargetDismissals.projectId, project.id),
22282
22314
  eq26(contentTargetDismissals.targetRef, targetRef)
22283
22315
  )).run();
@@ -22288,7 +22320,7 @@ async function contentRoutes(app, opts = {}) {
22288
22320
  });
22289
22321
  app.get("/projects/:name/content/recommendations/:targetRef/analysis", async (request, reply) => {
22290
22322
  const project = resolveProject(app.db, request.params.name);
22291
- const row = app.db.select().from(recommendationExplanations).where(and20(
22323
+ const row = app.db.select().from(recommendationExplanations).where(and21(
22292
22324
  eq26(recommendationExplanations.projectId, project.id),
22293
22325
  eq26(recommendationExplanations.targetRef, request.params.targetRef)
22294
22326
  )).orderBy(desc11(recommendationExplanations.generatedAt)).limit(1).get();
@@ -22316,7 +22348,7 @@ async function contentRoutes(app, opts = {}) {
22316
22348
  throw notFound("contentRecommendation", targetRef);
22317
22349
  }
22318
22350
  if (!body.forceRefresh) {
22319
- const cached = app.db.select().from(recommendationExplanations).where(and20(
22351
+ const cached = app.db.select().from(recommendationExplanations).where(and21(
22320
22352
  eq26(recommendationExplanations.projectId, project.id),
22321
22353
  eq26(recommendationExplanations.targetRef, targetRef)
22322
22354
  )).orderBy(desc11(recommendationExplanations.generatedAt)).limit(1).get();
@@ -22355,7 +22387,7 @@ async function contentRoutes(app, opts = {}) {
22355
22387
  generatedAt: now
22356
22388
  }
22357
22389
  }).run();
22358
- const row = app.db.select().from(recommendationExplanations).where(and20(
22390
+ const row = app.db.select().from(recommendationExplanations).where(and21(
22359
22391
  eq26(recommendationExplanations.projectId, project.id),
22360
22392
  eq26(recommendationExplanations.targetRef, targetRef),
22361
22393
  eq26(recommendationExplanations.promptVersion, result.promptVersion)
@@ -22439,7 +22471,7 @@ async function contentRoutes(app, opts = {}) {
22439
22471
  generatedAt: now
22440
22472
  }
22441
22473
  }).run();
22442
- const row = app.db.select().from(recommendationBriefs).where(and20(
22474
+ const row = app.db.select().from(recommendationBriefs).where(and21(
22443
22475
  eq26(recommendationBriefs.projectId, project.id),
22444
22476
  eq26(recommendationBriefs.targetRef, targetRef),
22445
22477
  eq26(recommendationBriefs.promptVersion, result.promptVersion)
@@ -22469,7 +22501,7 @@ function lookupCachedBrief(db, projectId, targetRef, promptVersion) {
22469
22501
  if (promptVersion !== void 0) {
22470
22502
  conditions.push(eq26(recommendationBriefs.promptVersion, promptVersion));
22471
22503
  }
22472
- return db.select().from(recommendationBriefs).where(and20(...conditions)).orderBy(desc11(recommendationBriefs.generatedAt)).limit(1).get();
22504
+ return db.select().from(recommendationBriefs).where(and21(...conditions)).orderBy(desc11(recommendationBriefs.generatedAt)).limit(1).get();
22473
22505
  }
22474
22506
  function parseLimitParam(raw) {
22475
22507
  if (raw === void 0) return void 0;
@@ -22495,7 +22527,7 @@ function winnabilityClassRank(winnabilityClass) {
22495
22527
  }
22496
22528
 
22497
22529
  // ../api-routes/src/gsc-totals.ts
22498
- import { and as and21, asc as asc4, eq as eq27, sql as sql8, max } from "drizzle-orm";
22530
+ import { and as and22, asc as asc4, eq as eq27, sql as sql9, max } from "drizzle-orm";
22499
22531
  var WINDOW_DAYS = { "7d": 7, "30d": 30, "90d": 90 };
22500
22532
  function resolveGscWindowRange(window, latestDataDate, today) {
22501
22533
  if (window === "all") {
@@ -22543,10 +22575,10 @@ function readGscDailyTotals(db, projectId, startDate, endDate) {
22543
22575
  impressions: gscDailyTotals.impressions,
22544
22576
  position: gscDailyTotals.position
22545
22577
  }).from(gscDailyTotals).where(
22546
- and21(
22578
+ and22(
22547
22579
  eq27(gscDailyTotals.projectId, projectId),
22548
- sql8`${gscDailyTotals.date} >= ${startDate}`,
22549
- sql8`${gscDailyTotals.date} <= ${endDate}`
22580
+ sql9`${gscDailyTotals.date} >= ${startDate}`,
22581
+ sql9`${gscDailyTotals.date} <= ${endDate}`
22550
22582
  )
22551
22583
  ).orderBy(asc4(gscDailyTotals.date)).all();
22552
22584
  return rows.map((r) => {
@@ -22573,10 +22605,10 @@ function readGscQueryDailyRows(db, projectId, startDate, endDate) {
22573
22605
  impressions: gscQueryDailyTotals.impressions,
22574
22606
  position: gscQueryDailyTotals.position
22575
22607
  }).from(gscQueryDailyTotals).where(
22576
- and21(
22608
+ and22(
22577
22609
  eq27(gscQueryDailyTotals.projectId, projectId),
22578
- sql8`${gscQueryDailyTotals.date} >= ${startDate}`,
22579
- sql8`${gscQueryDailyTotals.date} <= ${endDate}`
22610
+ sql9`${gscQueryDailyTotals.date} >= ${startDate}`,
22611
+ sql9`${gscQueryDailyTotals.date} <= ${endDate}`
22580
22612
  )
22581
22613
  ).all();
22582
22614
  return rows.map((r) => {
@@ -24304,7 +24336,8 @@ function renderServerActivity(report, audience) {
24304
24336
  if (!copy) return "";
24305
24337
  return `<span class="tone-${deltaTone(d.deltaPct)}">${escapeHtml(copy)}</span>`;
24306
24338
  };
24307
- const referralSubtitle = [formatDelta(sa.referralArrivals, "sessions"), escapeHtml(sa.referralArrivalsClassSummary)].filter(Boolean).join(" \xB7 ");
24339
+ const referralRedirectNote = sa.referralRedirects > 0 ? `${formatNumber(sa.referralRedirects)} blocked by redirects` : "";
24340
+ const referralSubtitle = [formatDelta(sa.referralArrivals, "sessions"), escapeHtml(sa.referralArrivalsClassSummary), referralRedirectNote].filter(Boolean).join(" \xB7 ");
24308
24341
  if (isClient) {
24309
24342
  const crawlerRequests = {
24310
24343
  current: sa.verifiedCrawlerHits.current + sa.unverifiedCrawlerHits.current,
@@ -24971,13 +25004,13 @@ function loadQueryLookup(db, projectId) {
24971
25004
  return { byId };
24972
25005
  }
24973
25006
  function buildGscSection(db, projectId, projectBrandNames, canonicalDomain, trackedQueries, windowDays2) {
24974
- const maxSearch = db.select({ m: sql9`MAX(${gscSearchData.date})` }).from(gscSearchData).where(eq28(gscSearchData.projectId, projectId)).get()?.m ?? "";
24975
- const maxDaily = db.select({ m: sql9`MAX(${gscDailyTotals.date})` }).from(gscDailyTotals).where(eq28(gscDailyTotals.projectId, projectId)).get()?.m ?? "";
25007
+ const maxSearch = db.select({ m: sql10`MAX(${gscSearchData.date})` }).from(gscSearchData).where(eq28(gscSearchData.projectId, projectId)).get()?.m ?? "";
25008
+ const maxDaily = db.select({ m: sql10`MAX(${gscDailyTotals.date})` }).from(gscDailyTotals).where(eq28(gscDailyTotals.projectId, projectId)).get()?.m ?? "";
24976
25009
  const maxDate = maxSearch > maxDaily ? maxSearch : maxDaily;
24977
25010
  if (!maxDate) return null;
24978
25011
  const startDate = windowStartDate(maxDate, windowDays2);
24979
25012
  const rows = db.select().from(gscSearchData).where(
24980
- and22(
25013
+ and23(
24981
25014
  eq28(gscSearchData.projectId, projectId),
24982
25015
  gte5(gscSearchData.date, startDate),
24983
25016
  lte3(gscSearchData.date, maxDate)
@@ -25077,20 +25110,20 @@ function buildGscSection(db, projectId, projectBrandNames, canonicalDomain, trac
25077
25110
  function buildGaSection(db, projectId, windowDays2) {
25078
25111
  const gaWindowKey = GA_WINDOW_SUMMARY_KEYS[windowDays2];
25079
25112
  const windowSummary = gaWindowKey ? db.select().from(gaTrafficWindowSummaries).where(
25080
- and22(
25113
+ and23(
25081
25114
  eq28(gaTrafficWindowSummaries.projectId, projectId),
25082
25115
  eq28(gaTrafficWindowSummaries.windowKey, gaWindowKey)
25083
25116
  )
25084
25117
  ).limit(1).get() : void 0;
25085
25118
  const fallbackSummary = windowSummary ? null : db.select().from(gaTrafficSummaries).where(eq28(gaTrafficSummaries.projectId, projectId)).orderBy(desc12(gaTrafficSummaries.syncedAt)).limit(1).get();
25086
25119
  const matchingFallbackSummary = fallbackSummary && inclusiveDayCount(fallbackSummary.periodStart, fallbackSummary.periodEnd) === windowDays2 ? fallbackSummary : null;
25087
- const snapshotMaxDate = db.select({ m: sql9`MAX(${gaTrafficSnapshots.date})` }).from(gaTrafficSnapshots).where(eq28(gaTrafficSnapshots.projectId, projectId)).get()?.m ?? "";
25120
+ const snapshotMaxDate = db.select({ m: sql10`MAX(${gaTrafficSnapshots.date})` }).from(gaTrafficSnapshots).where(eq28(gaTrafficSnapshots.projectId, projectId)).get()?.m ?? "";
25088
25121
  if (!windowSummary && !matchingFallbackSummary && !snapshotMaxDate) return null;
25089
25122
  const summaryPeriod = windowSummary ?? matchingFallbackSummary;
25090
25123
  const snapshotMaxInWindow = summaryPeriod?.periodEnd || snapshotMaxDate;
25091
25124
  const snapshotStartDate = summaryPeriod?.periodStart || (snapshotMaxDate ? windowStartDate(snapshotMaxDate, windowDays2) : "");
25092
25125
  const snapshotRows = snapshotStartDate ? db.select().from(gaTrafficSnapshots).where(
25093
- and22(
25126
+ and23(
25094
25127
  eq28(gaTrafficSnapshots.projectId, projectId),
25095
25128
  gte5(gaTrafficSnapshots.date, snapshotStartDate),
25096
25129
  lte3(gaTrafficSnapshots.date, snapshotMaxInWindow)
@@ -25127,8 +25160,8 @@ function buildGaSection(db, projectId, windowDays2) {
25127
25160
  const aiSessionRows = db.select({
25128
25161
  trafficClass: gaAiReferrals.trafficClass,
25129
25162
  channelGroup: gaAiReferrals.channelGroup,
25130
- sessions: sql9`COALESCE(SUM(${gaAiReferrals.sessions}), 0)`
25131
- }).from(gaAiReferrals).where(and22(...aiConditions)).groupBy(gaAiReferrals.trafficClass, gaAiReferrals.channelGroup).all();
25163
+ sessions: sql10`COALESCE(SUM(${gaAiReferrals.sessions}), 0)`
25164
+ }).from(gaAiReferrals).where(and23(...aiConditions)).groupBy(gaAiReferrals.trafficClass, gaAiReferrals.channelGroup).all();
25132
25165
  let paidAiSessions = 0;
25133
25166
  let organicAiSessions = 0;
25134
25167
  let aiOrganicOverlap = 0;
@@ -25208,7 +25241,7 @@ function buildSocialReferrals(db, projectId) {
25208
25241
  }
25209
25242
  function resolveAiReferralWindow(db, projectId, windowDays2) {
25210
25243
  const windowKey = GA_WINDOW_SUMMARY_KEYS[windowDays2];
25211
- const windowSummary = windowKey ? db.select({ periodStart: gaTrafficWindowSummaries.periodStart, periodEnd: gaTrafficWindowSummaries.periodEnd }).from(gaTrafficWindowSummaries).where(and22(
25244
+ const windowSummary = windowKey ? db.select({ periodStart: gaTrafficWindowSummaries.periodStart, periodEnd: gaTrafficWindowSummaries.periodEnd }).from(gaTrafficWindowSummaries).where(and23(
25212
25245
  eq28(gaTrafficWindowSummaries.projectId, projectId),
25213
25246
  eq28(gaTrafficWindowSummaries.windowKey, windowKey)
25214
25247
  )).get() : void 0;
@@ -25219,10 +25252,10 @@ function resolveAiReferralWindow(db, projectId, windowDays2) {
25219
25252
  }
25220
25253
  function buildAiReferrals(db, projectId, windowDays2) {
25221
25254
  const window = resolveAiReferralWindow(db, projectId, windowDays2);
25222
- const rows = db.select().from(gaAiReferrals).where(and22(
25255
+ const rows = db.select().from(gaAiReferrals).where(and23(
25223
25256
  eq28(gaAiReferrals.projectId, projectId),
25224
- sql9`${gaAiReferrals.date} >= ${window.start}`,
25225
- sql9`${gaAiReferrals.date} <= ${window.end}`
25257
+ sql10`${gaAiReferrals.date} >= ${window.start}`,
25258
+ sql10`${gaAiReferrals.date} <= ${window.end}`
25226
25259
  )).all();
25227
25260
  if (rows.length === 0) return null;
25228
25261
  const dimSessionsByTuple = /* @__PURE__ */ new Map();
@@ -25297,32 +25330,9 @@ function buildAiReferrals(db, projectId, windowDays2) {
25297
25330
  topLandingPages
25298
25331
  };
25299
25332
  }
25300
- function nonSubresourceReferralPathCondition() {
25301
- return sql9`
25302
- LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '/_next/static/%'
25303
- AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '/assets/%'
25304
- AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '/static/%'
25305
- AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '/favicon.%'
25306
- AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.avif'
25307
- AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.css'
25308
- AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.gif'
25309
- AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.ico'
25310
- AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.jpeg'
25311
- AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.jpg'
25312
- AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.js'
25313
- AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.map'
25314
- AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.mjs'
25315
- AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.otf'
25316
- AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.png'
25317
- AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.svg'
25318
- AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.webmanifest'
25319
- AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.woff'
25320
- AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.woff2'
25321
- `;
25322
- }
25323
25333
  function buildServerActivity(db, projectId, windowDays2) {
25324
25334
  const sourceRows = db.select({ id: trafficSources.id }).from(trafficSources).where(
25325
- and22(
25335
+ and23(
25326
25336
  eq28(trafficSources.projectId, projectId),
25327
25337
  ne3(trafficSources.status, TrafficSourceStatuses.archived)
25328
25338
  )
@@ -25337,8 +25347,8 @@ function buildServerActivity(db, projectId, windowDays2) {
25337
25347
  const priorStart = new Date(priorStartMs).toISOString();
25338
25348
  const trendStart = new Date(trendStartMs).toISOString();
25339
25349
  const sumVerifiedCrawlers = (windowStartIso, windowEndIso, exclusiveEnd = false) => Number(
25340
- db.select({ total: sql9`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
25341
- and22(
25350
+ db.select({ total: sql10`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
25351
+ and23(
25342
25352
  eq28(crawlerEventsHourly.projectId, projectId),
25343
25353
  eq28(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
25344
25354
  gte5(crawlerEventsHourly.tsHour, windowStartIso),
@@ -25347,8 +25357,8 @@ function buildServerActivity(db, projectId, windowDays2) {
25347
25357
  ).get()?.total ?? 0
25348
25358
  );
25349
25359
  const sumUnverifiedCrawlers = (windowStartIso, windowEndIso, exclusiveEnd = false) => Number(
25350
- db.select({ total: sql9`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
25351
- and22(
25360
+ db.select({ total: sql10`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
25361
+ and23(
25352
25362
  eq28(crawlerEventsHourly.projectId, projectId),
25353
25363
  ne3(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
25354
25364
  gte5(crawlerEventsHourly.tsHour, windowStartIso),
@@ -25358,13 +25368,13 @@ function buildServerActivity(db, projectId, windowDays2) {
25358
25368
  );
25359
25369
  const sumReferrals = (windowStartIso, windowEndIso, exclusiveEnd = false) => {
25360
25370
  const row = db.select({
25361
- total: sql9`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`,
25362
- paid: sql9`COALESCE(SUM(${aiReferralEventsHourly.paidSessionsOrHits}), 0)`,
25363
- organic: sql9`COALESCE(SUM(${aiReferralEventsHourly.organicSessionsOrHits}), 0)`
25371
+ total: sql10`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`,
25372
+ paid: sql10`COALESCE(SUM(${aiReferralEventsHourly.paidSessionsOrHits}), 0)`,
25373
+ organic: sql10`COALESCE(SUM(${aiReferralEventsHourly.organicSessionsOrHits}), 0)`
25364
25374
  }).from(aiReferralEventsHourly).where(
25365
- and22(
25375
+ and23(
25366
25376
  eq28(aiReferralEventsHourly.projectId, projectId),
25367
- nonSubresourceReferralPathCondition(),
25377
+ countableReferralCondition(),
25368
25378
  gte5(aiReferralEventsHourly.tsHour, windowStartIso),
25369
25379
  exclusiveEnd ? lt5(aiReferralEventsHourly.tsHour, windowEndIso) : lte3(aiReferralEventsHourly.tsHour, windowEndIso)
25370
25380
  )
@@ -25372,8 +25382,8 @@ function buildServerActivity(db, projectId, windowDays2) {
25372
25382
  return aiReferralClassCounts(Number(row?.total ?? 0), Number(row?.paid ?? 0), Number(row?.organic ?? 0));
25373
25383
  };
25374
25384
  const sumUserFetches = (windowStartIso, windowEndIso, exclusiveEnd = false) => Number(
25375
- db.select({ total: sql9`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
25376
- and22(
25385
+ db.select({ total: sql10`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
25386
+ and23(
25377
25387
  eq28(aiUserFetchEventsHourly.projectId, projectId),
25378
25388
  gte5(aiUserFetchEventsHourly.tsHour, windowStartIso),
25379
25389
  exclusiveEnd ? lt5(aiUserFetchEventsHourly.tsHour, windowEndIso) : lte3(aiUserFetchEventsHourly.tsHour, windowEndIso)
@@ -25387,13 +25397,24 @@ function buildServerActivity(db, projectId, windowDays2) {
25387
25397
  const userFetchCurrent = sumUserFetches(headlineStart, headlineEnd);
25388
25398
  const userFetchPrior = sumUserFetches(priorStart, headlineStart, true);
25389
25399
  const referralCurrent = sumReferrals(headlineStart, headlineEnd);
25400
+ const referralAllCurrent = Number(
25401
+ db.select({ total: sql10`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
25402
+ and23(
25403
+ eq28(aiReferralEventsHourly.projectId, projectId),
25404
+ nonSubresourceReferralPathCondition(),
25405
+ gte5(aiReferralEventsHourly.tsHour, headlineStart),
25406
+ lte3(aiReferralEventsHourly.tsHour, headlineEnd)
25407
+ )
25408
+ ).get()?.total ?? 0
25409
+ );
25410
+ const referralRedirects = Math.max(0, referralAllCurrent - referralCurrent.total);
25390
25411
  const referralPrior = sumReferrals(priorStart, headlineStart, true);
25391
25412
  const crawlerByOperatorRows = db.select({
25392
25413
  operator: crawlerEventsHourly.operator,
25393
25414
  verificationStatus: crawlerEventsHourly.verificationStatus,
25394
- hits: sql9`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
25415
+ hits: sql10`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
25395
25416
  }).from(crawlerEventsHourly).where(
25396
- and22(
25417
+ and23(
25397
25418
  eq28(crawlerEventsHourly.projectId, projectId),
25398
25419
  gte5(crawlerEventsHourly.tsHour, headlineStart),
25399
25420
  lte3(crawlerEventsHourly.tsHour, headlineEnd)
@@ -25401,9 +25422,9 @@ function buildServerActivity(db, projectId, windowDays2) {
25401
25422
  ).groupBy(crawlerEventsHourly.operator, crawlerEventsHourly.verificationStatus).all();
25402
25423
  const crawlerByOperatorPriorRows = db.select({
25403
25424
  operator: crawlerEventsHourly.operator,
25404
- hits: sql9`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
25425
+ hits: sql10`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
25405
25426
  }).from(crawlerEventsHourly).where(
25406
- and22(
25427
+ and23(
25407
25428
  eq28(crawlerEventsHourly.projectId, projectId),
25408
25429
  eq28(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
25409
25430
  gte5(crawlerEventsHourly.tsHour, priorStart),
@@ -25412,20 +25433,20 @@ function buildServerActivity(db, projectId, windowDays2) {
25412
25433
  ).groupBy(crawlerEventsHourly.operator).all();
25413
25434
  const referralByOperatorRows = db.select({
25414
25435
  operator: aiReferralEventsHourly.operator,
25415
- hits: sql9`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`
25436
+ hits: sql10`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`
25416
25437
  }).from(aiReferralEventsHourly).where(
25417
- and22(
25438
+ and23(
25418
25439
  eq28(aiReferralEventsHourly.projectId, projectId),
25419
- nonSubresourceReferralPathCondition(),
25440
+ countableReferralCondition(),
25420
25441
  gte5(aiReferralEventsHourly.tsHour, headlineStart),
25421
25442
  lte3(aiReferralEventsHourly.tsHour, headlineEnd)
25422
25443
  )
25423
25444
  ).groupBy(aiReferralEventsHourly.operator).all();
25424
25445
  const userFetchByOperatorRows = db.select({
25425
25446
  operator: aiUserFetchEventsHourly.operator,
25426
- hits: sql9`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)`
25447
+ hits: sql10`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)`
25427
25448
  }).from(aiUserFetchEventsHourly).where(
25428
- and22(
25449
+ and23(
25429
25450
  eq28(aiUserFetchEventsHourly.projectId, projectId),
25430
25451
  gte5(aiUserFetchEventsHourly.tsHour, headlineStart),
25431
25452
  lte3(aiUserFetchEventsHourly.tsHour, headlineEnd)
@@ -25466,16 +25487,16 @@ function buildServerActivity(db, projectId, windowDays2) {
25466
25487
  );
25467
25488
  const topPathsRows = db.select({
25468
25489
  path: crawlerEventsHourly.pathNormalized,
25469
- hits: sql9`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`,
25470
- operators: sql9`COUNT(DISTINCT ${crawlerEventsHourly.operator})`
25490
+ hits: sql10`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`,
25491
+ operators: sql10`COUNT(DISTINCT ${crawlerEventsHourly.operator})`
25471
25492
  }).from(crawlerEventsHourly).where(
25472
- and22(
25493
+ and23(
25473
25494
  eq28(crawlerEventsHourly.projectId, projectId),
25474
25495
  eq28(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
25475
25496
  gte5(crawlerEventsHourly.tsHour, headlineStart),
25476
25497
  lte3(crawlerEventsHourly.tsHour, headlineEnd)
25477
25498
  )
25478
- ).groupBy(crawlerEventsHourly.pathNormalized).orderBy(desc12(sql9`SUM(${crawlerEventsHourly.hits})`)).limit(SERVER_ACTIVITY_TOP_PATHS_LIMIT).all();
25499
+ ).groupBy(crawlerEventsHourly.pathNormalized).orderBy(desc12(sql10`SUM(${crawlerEventsHourly.hits})`)).limit(SERVER_ACTIVITY_TOP_PATHS_LIMIT).all();
25479
25500
  const topCrawledPaths = topPathsRows.map((r) => ({
25480
25501
  path: r.path,
25481
25502
  verifiedHits: Number(r.hits),
@@ -25483,16 +25504,16 @@ function buildServerActivity(db, projectId, windowDays2) {
25483
25504
  }));
25484
25505
  const referralProductsRows = db.select({
25485
25506
  product: aiReferralEventsHourly.product,
25486
- arrivals: sql9`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`,
25487
- landingPaths: sql9`COUNT(DISTINCT ${aiReferralEventsHourly.landingPathNormalized})`
25507
+ arrivals: sql10`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`,
25508
+ landingPaths: sql10`COUNT(DISTINCT ${aiReferralEventsHourly.landingPathNormalized})`
25488
25509
  }).from(aiReferralEventsHourly).where(
25489
- and22(
25510
+ and23(
25490
25511
  eq28(aiReferralEventsHourly.projectId, projectId),
25491
- nonSubresourceReferralPathCondition(),
25512
+ countableReferralCondition(),
25492
25513
  gte5(aiReferralEventsHourly.tsHour, headlineStart),
25493
25514
  lte3(aiReferralEventsHourly.tsHour, headlineEnd)
25494
25515
  )
25495
- ).groupBy(aiReferralEventsHourly.product).orderBy(desc12(sql9`SUM(${aiReferralEventsHourly.sessionsOrHits})`)).all();
25516
+ ).groupBy(aiReferralEventsHourly.product).orderBy(desc12(sql10`SUM(${aiReferralEventsHourly.sessionsOrHits})`)).all();
25496
25517
  const referralProducts = referralProductsRows.map((r) => ({
25497
25518
  product: r.product,
25498
25519
  arrivals: Number(r.arrivals),
@@ -25500,53 +25521,53 @@ function buildServerActivity(db, projectId, windowDays2) {
25500
25521
  }));
25501
25522
  const topReferralRows = db.select({
25502
25523
  path: aiReferralEventsHourly.landingPathNormalized,
25503
- arrivals: sql9`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`,
25504
- products: sql9`COUNT(DISTINCT ${aiReferralEventsHourly.product})`
25524
+ arrivals: sql10`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`,
25525
+ products: sql10`COUNT(DISTINCT ${aiReferralEventsHourly.product})`
25505
25526
  }).from(aiReferralEventsHourly).where(
25506
- and22(
25527
+ and23(
25507
25528
  eq28(aiReferralEventsHourly.projectId, projectId),
25508
- nonSubresourceReferralPathCondition(),
25529
+ countableReferralCondition(),
25509
25530
  gte5(aiReferralEventsHourly.tsHour, headlineStart),
25510
25531
  lte3(aiReferralEventsHourly.tsHour, headlineEnd)
25511
25532
  )
25512
- ).groupBy(aiReferralEventsHourly.landingPathNormalized).orderBy(desc12(sql9`SUM(${aiReferralEventsHourly.sessionsOrHits})`)).limit(SERVER_ACTIVITY_TOP_PATHS_LIMIT).all();
25533
+ ).groupBy(aiReferralEventsHourly.landingPathNormalized).orderBy(desc12(sql10`SUM(${aiReferralEventsHourly.sessionsOrHits})`)).limit(SERVER_ACTIVITY_TOP_PATHS_LIMIT).all();
25513
25534
  const topReferralLandingPaths = topReferralRows.map((r) => ({
25514
25535
  path: r.path,
25515
25536
  arrivals: Number(r.arrivals),
25516
25537
  distinctProducts: Number(r.products)
25517
25538
  }));
25518
25539
  const crawlerTrendRows = db.select({
25519
- date: sql9`SUBSTR(${crawlerEventsHourly.tsHour}, 1, 10)`,
25520
- hits: sql9`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
25540
+ date: sql10`SUBSTR(${crawlerEventsHourly.tsHour}, 1, 10)`,
25541
+ hits: sql10`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
25521
25542
  }).from(crawlerEventsHourly).where(
25522
- and22(
25543
+ and23(
25523
25544
  eq28(crawlerEventsHourly.projectId, projectId),
25524
25545
  eq28(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
25525
25546
  gte5(crawlerEventsHourly.tsHour, trendStart),
25526
25547
  lte3(crawlerEventsHourly.tsHour, headlineEnd)
25527
25548
  )
25528
- ).groupBy(sql9`SUBSTR(${crawlerEventsHourly.tsHour}, 1, 10)`).all();
25549
+ ).groupBy(sql10`SUBSTR(${crawlerEventsHourly.tsHour}, 1, 10)`).all();
25529
25550
  const referralTrendRows = db.select({
25530
- date: sql9`SUBSTR(${aiReferralEventsHourly.tsHour}, 1, 10)`,
25531
- hits: sql9`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`
25551
+ date: sql10`SUBSTR(${aiReferralEventsHourly.tsHour}, 1, 10)`,
25552
+ hits: sql10`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`
25532
25553
  }).from(aiReferralEventsHourly).where(
25533
- and22(
25554
+ and23(
25534
25555
  eq28(aiReferralEventsHourly.projectId, projectId),
25535
- nonSubresourceReferralPathCondition(),
25556
+ countableReferralCondition(),
25536
25557
  gte5(aiReferralEventsHourly.tsHour, trendStart),
25537
25558
  lte3(aiReferralEventsHourly.tsHour, headlineEnd)
25538
25559
  )
25539
- ).groupBy(sql9`SUBSTR(${aiReferralEventsHourly.tsHour}, 1, 10)`).all();
25560
+ ).groupBy(sql10`SUBSTR(${aiReferralEventsHourly.tsHour}, 1, 10)`).all();
25540
25561
  const userFetchTrendRows = db.select({
25541
- date: sql9`SUBSTR(${aiUserFetchEventsHourly.tsHour}, 1, 10)`,
25542
- hits: sql9`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)`
25562
+ date: sql10`SUBSTR(${aiUserFetchEventsHourly.tsHour}, 1, 10)`,
25563
+ hits: sql10`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)`
25543
25564
  }).from(aiUserFetchEventsHourly).where(
25544
- and22(
25565
+ and23(
25545
25566
  eq28(aiUserFetchEventsHourly.projectId, projectId),
25546
25567
  gte5(aiUserFetchEventsHourly.tsHour, trendStart),
25547
25568
  lte3(aiUserFetchEventsHourly.tsHour, headlineEnd)
25548
25569
  )
25549
- ).groupBy(sql9`SUBSTR(${aiUserFetchEventsHourly.tsHour}, 1, 10)`).all();
25570
+ ).groupBy(sql10`SUBSTR(${aiUserFetchEventsHourly.tsHour}, 1, 10)`).all();
25550
25571
  const emptyTrendEntry = () => ({ verifiedCrawlerHits: 0, userFetchHits: 0, referralArrivals: 0 });
25551
25572
  const dailyTrendMap = /* @__PURE__ */ new Map();
25552
25573
  for (const r of crawlerTrendRows) {
@@ -25568,7 +25589,7 @@ function buildServerActivity(db, projectId, windowDays2) {
25568
25589
  return {
25569
25590
  windowStart: headlineStart,
25570
25591
  windowEnd: headlineEnd,
25571
- hasData: verifiedCurrent + unverifiedCurrent + userFetchCurrent + referralCurrent.total + verifiedPrior + unverifiedPrior + userFetchPrior + referralPrior.total > 0 || byOperator.length > 0 || topCrawledPaths.length > 0 || referralProducts.length > 0,
25592
+ hasData: verifiedCurrent + unverifiedCurrent + userFetchCurrent + referralCurrent.total + verifiedPrior + unverifiedPrior + userFetchPrior + referralPrior.total + referralRedirects > 0 || byOperator.length > 0 || topCrawledPaths.length > 0 || referralProducts.length > 0,
25572
25593
  verifiedCrawlerHits: {
25573
25594
  current: verifiedCurrent,
25574
25595
  prior: verifiedPrior,
@@ -25589,6 +25610,7 @@ function buildServerActivity(db, projectId, windowDays2) {
25589
25610
  prior: referralPrior.total,
25590
25611
  deltaPct: deltaPercent(referralCurrent.total, referralPrior.total)
25591
25612
  },
25613
+ referralRedirects,
25592
25614
  referralArrivalsByClass: {
25593
25615
  paid: {
25594
25616
  current: referralCurrent.paid,
@@ -25644,7 +25666,7 @@ function buildIndexingHealth(db, projectId) {
25644
25666
  return null;
25645
25667
  }
25646
25668
  function buildCitationsTrend(db, projectId, queryLookup, locationFilter) {
25647
- const visibilityRuns = db.select().from(runs).where(and22(eq28(runs.projectId, projectId), eq28(runs.kind, RunKinds["answer-visibility"]), notProbeRun())).all().filter((r) => locationFilter === void 0 || (r.location ?? null) === locationFilter);
25669
+ const visibilityRuns = db.select().from(runs).where(and23(eq28(runs.projectId, projectId), eq28(runs.kind, RunKinds["answer-visibility"]), notProbeRun())).all().filter((r) => locationFilter === void 0 || (r.location ?? null) === locationFilter);
25648
25670
  const totalQueries = queryLookup.byId.size;
25649
25671
  const points = [];
25650
25672
  for (const run of visibilityRuns) {
@@ -25692,7 +25714,7 @@ function buildCitationsTrend(db, projectId, queryLookup, locationFilter) {
25692
25714
  }
25693
25715
  function buildInsightList(db, projectId, locationFilter) {
25694
25716
  const recentRunIds = db.select({ id: runs.id, location: runs.location }).from(runs).where(
25695
- and22(
25717
+ and23(
25696
25718
  eq28(runs.projectId, projectId),
25697
25719
  eq28(runs.kind, RunKinds["answer-visibility"]),
25698
25720
  or4(eq28(runs.status, RunStatuses.completed), eq28(runs.status, RunStatuses.partial)),
@@ -25700,7 +25722,7 @@ function buildInsightList(db, projectId, locationFilter) {
25700
25722
  )
25701
25723
  ).orderBy(desc12(runs.createdAt)).all().filter((r) => locationFilter === void 0 || (r.location ?? null) === locationFilter).slice(0, INSIGHT_LOOKBACK_RUNS).map((r) => r.id);
25702
25724
  if (recentRunIds.length === 0) return [];
25703
- const rows = db.select().from(insights).where(and22(eq28(insights.projectId, projectId), inArray12(insights.runId, recentRunIds))).orderBy(desc12(insights.createdAt)).all();
25725
+ const rows = db.select().from(insights).where(and23(eq28(insights.projectId, projectId), inArray12(insights.runId, recentRunIds))).orderBy(desc12(insights.createdAt)).all();
25704
25726
  const severityRank = { critical: 0, high: 1, medium: 2, low: 3 };
25705
25727
  const flat = rows.filter((r) => !r.dismissed).map((r) => {
25706
25728
  const recommendation = r.recommendation;
@@ -26252,7 +26274,7 @@ function buildProjectReport(db, projectName, periodDays) {
26252
26274
  const project = resolveProject(db, projectName);
26253
26275
  const queryLookup = loadQueryLookup(db, project.id);
26254
26276
  const comparisonWindowDays = reportComparisonWindowDays(periodDays);
26255
- const allRuns = db.select().from(runs).where(and22(eq28(runs.projectId, project.id), notProbeRun())).orderBy(desc12(runs.createdAt), desc12(runs.id)).all();
26277
+ const allRuns = db.select().from(runs).where(and23(eq28(runs.projectId, project.id), notProbeRun())).orderBy(desc12(runs.createdAt), desc12(runs.id)).all();
26256
26278
  const visibilityRuns = allRuns.filter((r) => r.kind === RunKinds["answer-visibility"]);
26257
26279
  const completedVisRunGroups = groupRunsByCreatedAt(
26258
26280
  visibilityRuns.filter((r) => r.status === RunStatuses.completed || r.status === RunStatuses.partial)
@@ -26484,10 +26506,10 @@ async function reportRoutes(app) {
26484
26506
  }
26485
26507
 
26486
26508
  // ../api-routes/src/organic-evidence.ts
26487
- import { and as and24, desc as desc13, eq as eq30, gte as gte7, lte as lte5, or as or6, sql as sql11 } from "drizzle-orm";
26509
+ import { and as and25, desc as desc13, eq as eq30, gte as gte7, lte as lte5, or as or6, sql as sql12 } from "drizzle-orm";
26488
26510
 
26489
26511
  // ../api-routes/src/ga-measurement-analysis.ts
26490
- import { and as and23, eq as eq29, gte as gte6, lte as lte4, or as or5, sql as sql10 } from "drizzle-orm";
26512
+ import { and as and24, eq as eq29, gte as gte6, lte as lte4, or as or5, sql as sql11 } from "drizzle-orm";
26491
26513
  var UNKNOWN_LANDING_PAGE = "(not set)";
26492
26514
  function addDays(date, offset) {
26493
26515
  const value = /* @__PURE__ */ new Date(`${date}T00:00:00.000Z`);
@@ -26659,55 +26681,55 @@ function buildGaMeasurementAnalysis(db, projectName, options = {}) {
26659
26681
  const scopedConditions = (hostColumn, normalizedPathColumn, rawPathColumn) => {
26660
26682
  const conditions = [];
26661
26683
  if (parsedHostScope.data === "marketing") {
26662
- const lowerHost = sql10`lower(${hostColumn})`;
26663
- const normalizedHost2 = sql10`case when ${lowerHost} like 'www.%' then substr(${lowerHost}, 5) else ${lowerHost} end`;
26684
+ const lowerHost = sql11`lower(${hostColumn})`;
26685
+ const normalizedHost2 = sql11`case when ${lowerHost} like 'www.%' then substr(${lowerHost}, 5) else ${lowerHost} end`;
26664
26686
  conditions.push(or5(...marketingHosts.flatMap((host) => [
26665
- sql10`${normalizedHost2} = ${host}`,
26666
- sql10`${normalizedHost2} like ${`%.${host}`}`
26687
+ sql11`${normalizedHost2} = ${host}`,
26688
+ sql11`${normalizedHost2} like ${`%.${host}`}`
26667
26689
  ])));
26668
26690
  }
26669
26691
  if (pathPrefix && pathPrefix !== "/") {
26670
- const rawPath = sql10`case when instr(${rawPathColumn}, '?') = 0 then ${rawPathColumn} else substr(${rawPathColumn}, 1, instr(${rawPathColumn}, '?') - 1) end`;
26671
- const landingPath = sql10`case when trim(coalesce(${normalizedPathColumn}, '')) = '' then ${rawPath} else ${normalizedPathColumn} end`;
26672
- conditions.push(or5(sql10`${landingPath} = ${pathPrefix}`, sql10`${landingPath} like ${`${pathPrefix}/%`}`));
26692
+ const rawPath = sql11`case when instr(${rawPathColumn}, '?') = 0 then ${rawPathColumn} else substr(${rawPathColumn}, 1, instr(${rawPathColumn}, '?') - 1) end`;
26693
+ const landingPath = sql11`case when trim(coalesce(${normalizedPathColumn}, '')) = '' then ${rawPath} else ${normalizedPathColumn} end`;
26694
+ conditions.push(or5(sql11`${landingPath} = ${pathPrefix}`, sql11`${landingPath} like ${`${pathPrefix}/%`}`));
26673
26695
  }
26674
26696
  return conditions;
26675
26697
  };
26676
26698
  const acquisitionScope = scopedConditions(gaAcquisitionDaily.hostName, gaAcquisitionDaily.landingPageNormalized, gaAcquisitionDaily.landingPage);
26677
26699
  const leadLandingScope = scopedConditions(gaLeadEventsDaily.hostName, gaLeadEventsDaily.landingPageNormalized, gaLeadEventsDaily.landingPage);
26678
- const acquisitionAnchor = db.select({ date: sql10`max(${gaAcquisitionDaily.date})` }).from(gaAcquisitionDaily).where(and23(eq29(gaAcquisitionDaily.projectId, project.id), ...acquisitionScope)).get()?.date ?? null;
26679
- const leadAnchor = db.select({ date: sql10`max(${gaLeadEventsDaily.date})` }).from(gaLeadEventsDaily).where(and23(eq29(gaLeadEventsDaily.projectId, project.id), or5(
26700
+ const acquisitionAnchor = db.select({ date: sql11`max(${gaAcquisitionDaily.date})` }).from(gaAcquisitionDaily).where(and24(eq29(gaAcquisitionDaily.projectId, project.id), ...acquisitionScope)).get()?.date ?? null;
26701
+ const leadAnchor = db.select({ date: sql11`max(${gaLeadEventsDaily.date})` }).from(gaLeadEventsDaily).where(and24(eq29(gaLeadEventsDaily.projectId, project.id), or5(
26680
26702
  eq29(gaLeadEventsDaily.attributionScope, "channel"),
26681
- and23(eq29(gaLeadEventsDaily.attributionScope, "landing-page"), ...leadLandingScope)
26703
+ and24(eq29(gaLeadEventsDaily.attributionScope, "landing-page"), ...leadLandingScope)
26682
26704
  ))).get()?.date ?? null;
26683
26705
  const gaAnchor = [acquisitionAnchor, leadAnchor].filter((date) => date !== null).sort().at(-1) ?? null;
26684
26706
  const gaPeriods = gaAnchor ? buildPeriods(gaAnchor, days) : [];
26685
26707
  const gaStartDate = gaPeriods[0]?.startDate;
26686
- const acquisitionRows = gaStartDate ? db.select().from(gaAcquisitionDaily).where(and23(eq29(gaAcquisitionDaily.projectId, project.id), gte6(gaAcquisitionDaily.date, gaStartDate), lte4(gaAcquisitionDaily.date, gaAnchor))).all() : [];
26687
- const leadRows = gaStartDate ? db.select().from(gaLeadEventsDaily).where(and23(eq29(gaLeadEventsDaily.projectId, project.id), gte6(gaLeadEventsDaily.date, gaStartDate), lte4(gaLeadEventsDaily.date, gaAnchor))).all() : [];
26688
- const engagementAnchor = db.select({ date: sql10`max(${gaDailyTotals.date})` }).from(gaDailyTotals).where(eq29(gaDailyTotals.projectId, project.id)).get()?.date ?? null;
26708
+ const acquisitionRows = gaStartDate ? db.select().from(gaAcquisitionDaily).where(and24(eq29(gaAcquisitionDaily.projectId, project.id), gte6(gaAcquisitionDaily.date, gaStartDate), lte4(gaAcquisitionDaily.date, gaAnchor))).all() : [];
26709
+ const leadRows = gaStartDate ? db.select().from(gaLeadEventsDaily).where(and24(eq29(gaLeadEventsDaily.projectId, project.id), gte6(gaLeadEventsDaily.date, gaStartDate), lte4(gaLeadEventsDaily.date, gaAnchor))).all() : [];
26710
+ const engagementAnchor = db.select({ date: sql11`max(${gaDailyTotals.date})` }).from(gaDailyTotals).where(eq29(gaDailyTotals.projectId, project.id)).get()?.date ?? null;
26689
26711
  const engagementPeriodWindow = engagementAnchor ? buildPeriods(engagementAnchor, days) : [];
26690
26712
  const engagementStartDate = engagementPeriodWindow[0]?.startDate;
26691
- const engagementRows = engagementStartDate ? db.select().from(gaDailyTotals).where(and23(
26713
+ const engagementRows = engagementStartDate ? db.select().from(gaDailyTotals).where(and24(
26692
26714
  eq29(gaDailyTotals.projectId, project.id),
26693
26715
  gte6(gaDailyTotals.date, engagementStartDate),
26694
26716
  lte4(gaDailyTotals.date, engagementAnchor)
26695
26717
  )).all() : [];
26696
26718
  const engagementAvailableFrom = db.select({
26697
- date: sql10`min(${gaDailyTotals.date})`
26698
- }).from(gaDailyTotals).where(and23(
26719
+ date: sql11`min(${gaDailyTotals.date})`
26720
+ }).from(gaDailyTotals).where(and24(
26699
26721
  eq29(gaDailyTotals.projectId, project.id),
26700
26722
  or5(
26701
- sql10`${gaDailyTotals.engagementRate} is not null`,
26702
- sql10`${gaDailyTotals.newUsers} is not null`
26723
+ sql11`${gaDailyTotals.engagementRate} is not null`,
26724
+ sql11`${gaDailyTotals.newUsers} is not null`
26703
26725
  )
26704
26726
  )).get()?.date ?? null;
26705
- const gscAnchor = db.select({ date: sql10`max(${gscDailyTotals.date})` }).from(gscDailyTotals).where(eq29(gscDailyTotals.projectId, project.id)).get()?.date ?? null;
26727
+ const gscAnchor = db.select({ date: sql11`max(${gscDailyTotals.date})` }).from(gscDailyTotals).where(eq29(gscDailyTotals.projectId, project.id)).get()?.date ?? null;
26706
26728
  const gscPeriods = gscAnchor ? buildPeriods(gscAnchor, days) : [];
26707
26729
  const gscStartDate = gscPeriods[0]?.startDate;
26708
- const propertyRows = gscStartDate ? db.select().from(gscDailyTotals).where(and23(eq29(gscDailyTotals.projectId, project.id), gte6(gscDailyTotals.date, gscStartDate), lte4(gscDailyTotals.date, gscAnchor))).all() : [];
26709
- const queryRows = gscStartDate ? db.select().from(gscQueryDailyTotals).where(and23(eq29(gscQueryDailyTotals.projectId, project.id), gte6(gscQueryDailyTotals.date, gscStartDate), lte4(gscQueryDailyTotals.date, gscAnchor))).all() : [];
26710
- const rawPageRows = gscStartDate ? db.select().from(gscSearchData).where(and23(eq29(gscSearchData.projectId, project.id), gte6(gscSearchData.date, gscStartDate), lte4(gscSearchData.date, gscAnchor))).all() : [];
26730
+ const propertyRows = gscStartDate ? db.select().from(gscDailyTotals).where(and24(eq29(gscDailyTotals.projectId, project.id), gte6(gscDailyTotals.date, gscStartDate), lte4(gscDailyTotals.date, gscAnchor))).all() : [];
26731
+ const queryRows = gscStartDate ? db.select().from(gscQueryDailyTotals).where(and24(eq29(gscQueryDailyTotals.projectId, project.id), gte6(gscQueryDailyTotals.date, gscStartDate), lte4(gscQueryDailyTotals.date, gscAnchor))).all() : [];
26732
+ const rawPageRows = gscStartDate ? db.select().from(gscSearchData).where(and24(eq29(gscSearchData.projectId, project.id), gte6(gscSearchData.date, gscStartDate), lte4(gscSearchData.date, gscAnchor))).all() : [];
26711
26733
  const state = db.select().from(gaMeasurementSyncStates).where(eq29(gaMeasurementSyncStates.projectId, project.id)).get();
26712
26734
  const acquisition = acquisitionRows.filter((row) => {
26713
26735
  const landingPage = normalizeLandingPage(row.landingPageNormalized ?? row.landingPage);
@@ -27029,22 +27051,22 @@ function buildOrganicEvidence(db, projectName, periodDays) {
27029
27051
  const nativeStartDate = nativeAcquisition.periods[0]?.startDate;
27030
27052
  const nativeEndDate = nativeAcquisition.periods.at(-1)?.endDate;
27031
27053
  const gscCoverage = aggregateCoverage(db.select({
27032
- startDate: sql11`min(${gscDailyTotals.date})`,
27033
- endDate: sql11`max(${gscDailyTotals.date})`,
27034
- observedDays: sql11`count(distinct ${gscDailyTotals.date})`
27054
+ startDate: sql12`min(${gscDailyTotals.date})`,
27055
+ endDate: sql12`max(${gscDailyTotals.date})`,
27056
+ observedDays: sql12`count(distinct ${gscDailyTotals.date})`
27035
27057
  }).from(gscDailyTotals).where(eq30(gscDailyTotals.projectId, project.id)).get());
27036
27058
  const legacyGaCoverage = aggregateCoverage(db.select({
27037
- startDate: sql11`min(${gaTrafficSnapshots.date})`,
27038
- endDate: sql11`max(${gaTrafficSnapshots.date})`,
27039
- observedDays: sql11`count(distinct ${gaTrafficSnapshots.date})`
27059
+ startDate: sql12`min(${gaTrafficSnapshots.date})`,
27060
+ endDate: sql12`max(${gaTrafficSnapshots.date})`,
27061
+ observedDays: sql12`count(distinct ${gaTrafficSnapshots.date})`
27040
27062
  }).from(gaTrafficSnapshots).where(eq30(gaTrafficSnapshots.projectId, project.id)).get());
27041
27063
  const nativeCoverage = nativeAcquisitionActive && normalizedMarketingHosts.length ? aggregateCoverage(db.select({
27042
- startDate: sql11`min(${gaAcquisitionDaily.date})`,
27043
- endDate: sql11`max(${gaAcquisitionDaily.date})`,
27044
- observedDays: sql11`count(distinct ${gaAcquisitionDaily.date})`
27045
- }).from(gaAcquisitionDaily).where(and24(
27064
+ startDate: sql12`min(${gaAcquisitionDaily.date})`,
27065
+ endDate: sql12`max(${gaAcquisitionDaily.date})`,
27066
+ observedDays: sql12`count(distinct ${gaAcquisitionDaily.date})`
27067
+ }).from(gaAcquisitionDaily).where(and25(
27046
27068
  eq30(gaAcquisitionDaily.projectId, project.id),
27047
- or6(...normalizedMarketingHosts.map((candidate) => sql11`lower(trim(${gaAcquisitionDaily.hostName})) = ${candidate} or lower(trim(${gaAcquisitionDaily.hostName})) like ${`%.${candidate}`}`))
27069
+ or6(...normalizedMarketingHosts.map((candidate) => sql12`lower(trim(${gaAcquisitionDaily.hostName})) = ${candidate} or lower(trim(${gaAcquisitionDaily.hostName})) like ${`%.${candidate}`}`))
27048
27070
  )).get()) : null;
27049
27071
  const gaCoverage = nativeAcquisitionActive ? nativeCoverage : legacyGaCoverage;
27050
27072
  const asOfDate = gscCoverage?.endDate ?? gaCoverage?.endDate ?? null;
@@ -27057,17 +27079,17 @@ function buildOrganicEvidence(db, projectName, periodDays) {
27057
27079
  const startDate = gscStartDate ?? gaStartDate ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
27058
27080
  const endDate = gscEndDate ?? gaEndDate ?? startDate;
27059
27081
  const isInWindow = (date) => inRange(date, startDate, endDate);
27060
- const gscRows = gscStartDate && gscEndDate ? db.select().from(gscDailyTotals).where(and24(
27082
+ const gscRows = gscStartDate && gscEndDate ? db.select().from(gscDailyTotals).where(and25(
27061
27083
  eq30(gscDailyTotals.projectId, project.id),
27062
27084
  gte7(gscDailyTotals.date, gscStartDate),
27063
27085
  lte5(gscDailyTotals.date, gscEndDate)
27064
27086
  )).all() : [];
27065
- const gaRows = gaStartDate && gaEndDate ? db.select().from(gaTrafficSnapshots).where(and24(
27087
+ const gaRows = gaStartDate && gaEndDate ? db.select().from(gaTrafficSnapshots).where(and25(
27066
27088
  eq30(gaTrafficSnapshots.projectId, project.id),
27067
27089
  gte7(gaTrafficSnapshots.date, gaStartDate),
27068
27090
  lte5(gaTrafficSnapshots.date, gaEndDate)
27069
27091
  )).all() : [];
27070
- const nativeAcquisitionRows = nativeAcquisitionActive && nativeStartDate && nativeEndDate ? db.select().from(gaAcquisitionDaily).where(and24(
27092
+ const nativeAcquisitionRows = nativeAcquisitionActive && nativeStartDate && nativeEndDate ? db.select().from(gaAcquisitionDaily).where(and25(
27071
27093
  eq30(gaAcquisitionDaily.projectId, project.id),
27072
27094
  gte7(gaAcquisitionDaily.date, nativeStartDate),
27073
27095
  lte5(gaAcquisitionDaily.date, nativeEndDate)
@@ -27106,7 +27128,7 @@ function buildOrganicEvidence(db, projectName, periodDays) {
27106
27128
  project.canonicalDomain,
27107
27129
  [project.displayName, ...project.aliases]
27108
27130
  );
27109
- const namedRows = db.select().from(gscQueryDailyTotals).where(and24(
27131
+ const namedRows = db.select().from(gscQueryDailyTotals).where(and25(
27110
27132
  eq30(gscQueryDailyTotals.projectId, project.id),
27111
27133
  gte7(gscQueryDailyTotals.date, startDate),
27112
27134
  lte5(gscQueryDailyTotals.date, endDate)
@@ -27135,7 +27157,7 @@ function buildOrganicEvidence(db, projectName, periodDays) {
27135
27157
  totals: sumSearchRows(gscRows.filter((row) => inRange(row.date, cohort.startDate, cohort.endDate)))
27136
27158
  }))
27137
27159
  } : null;
27138
- const pageSearchRows = db.select().from(gscSearchData).where(and24(eq30(gscSearchData.projectId, project.id), gte7(gscSearchData.date, startDate), lte5(gscSearchData.date, endDate))).all().filter((row) => pageMatchesMarketingHost(row.page, marketingHosts));
27160
+ const pageSearchRows = db.select().from(gscSearchData).where(and25(eq30(gscSearchData.projectId, project.id), gte7(gscSearchData.date, startDate), lte5(gscSearchData.date, endDate))).all().filter((row) => pageMatchesMarketingHost(row.page, marketingHosts));
27139
27161
  const gaWindow = gaStartDate && gaEndDate ? gaRows.filter((row) => inRange(row.date, gaStartDate, gaEndDate)) : [];
27140
27162
  const legacyGaCohorts = gaCohorts.map((cohort) => ({
27141
27163
  ...cohort,
@@ -27162,7 +27184,7 @@ function buildOrganicEvidence(db, projectName, periodDays) {
27162
27184
  }))
27163
27185
  };
27164
27186
  }
27165
- const allGaAiRows = db.select().from(gaAiReferrals).where(and24(eq30(gaAiReferrals.projectId, project.id), gte7(gaAiReferrals.date, gaStartDate ?? startDate), lte5(gaAiReferrals.date, gaEndDate ?? endDate))).all().filter((row) => row.sourceDimension === "session");
27187
+ const allGaAiRows = db.select().from(gaAiReferrals).where(and25(eq30(gaAiReferrals.projectId, project.id), gte7(gaAiReferrals.date, gaStartDate ?? startDate), lte5(gaAiReferrals.date, gaEndDate ?? endDate))).all().filter((row) => row.sourceDimension === "session");
27166
27188
  const aiRows = gaStartDate && gaEndDate ? allGaAiRows.filter((row) => inRange(row.date, gaStartDate, gaEndDate)) : [];
27167
27189
  const gaAiReferralSummary = allGaAiRows.length ? {
27168
27190
  paidSessions: aiRows.filter((row) => row.trafficClass === AiReferralTrafficClasses.paid).reduce((count2, row) => count2 + row.sessions, 0),
@@ -27171,10 +27193,10 @@ function buildOrganicEvidence(db, projectName, periodDays) {
27171
27193
  const serverSources = db.select().from(trafficSources).where(eq30(trafficSources.projectId, project.id)).all();
27172
27194
  const serverStart = `${startDate}T00:00:00`;
27173
27195
  const serverEnd = `${endDate}T23:59:59.999Z`;
27174
- const allCrawlers = db.select().from(crawlerEventsHourly).where(and24(eq30(crawlerEventsHourly.projectId, project.id), gte7(crawlerEventsHourly.tsHour, serverStart), lte5(crawlerEventsHourly.tsHour, serverEnd))).all();
27175
- const allFetches = db.select().from(aiUserFetchEventsHourly).where(and24(eq30(aiUserFetchEventsHourly.projectId, project.id), gte7(aiUserFetchEventsHourly.tsHour, serverStart), lte5(aiUserFetchEventsHourly.tsHour, serverEnd))).all();
27176
- const allReferrals = db.select().from(aiReferralEventsHourly).where(and24(eq30(aiReferralEventsHourly.projectId, project.id), gte7(aiReferralEventsHourly.tsHour, serverStart), lte5(aiReferralEventsHourly.tsHour, serverEnd))).all();
27177
- const [serverCoverageRow] = db.all(sql11`
27196
+ const allCrawlers = db.select().from(crawlerEventsHourly).where(and25(eq30(crawlerEventsHourly.projectId, project.id), gte7(crawlerEventsHourly.tsHour, serverStart), lte5(crawlerEventsHourly.tsHour, serverEnd))).all();
27197
+ const allFetches = db.select().from(aiUserFetchEventsHourly).where(and25(eq30(aiUserFetchEventsHourly.projectId, project.id), gte7(aiUserFetchEventsHourly.tsHour, serverStart), lte5(aiUserFetchEventsHourly.tsHour, serverEnd))).all();
27198
+ const allReferrals = db.select().from(aiReferralEventsHourly).where(and25(eq30(aiReferralEventsHourly.projectId, project.id), countableReferralCondition(), gte7(aiReferralEventsHourly.tsHour, serverStart), lte5(aiReferralEventsHourly.tsHour, serverEnd))).all();
27199
+ const [serverCoverageRow] = db.all(sql12`
27178
27200
  select
27179
27201
  min(day) as startDate,
27180
27202
  max(day) as endDate,
@@ -27191,6 +27213,7 @@ function buildOrganicEvidence(db, projectName, periodDays) {
27191
27213
  select substr(${aiReferralEventsHourly.tsHour}, 1, 10) as day
27192
27214
  from ${aiReferralEventsHourly}
27193
27215
  where ${aiReferralEventsHourly.projectId} = ${project.id}
27216
+ and ${countableReferralCondition()}
27194
27217
  )
27195
27218
  `);
27196
27219
  const serverCoverage = aggregateCoverage(serverCoverageRow);
@@ -27200,7 +27223,7 @@ function buildOrganicEvidence(db, projectName, periodDays) {
27200
27223
  const referrals = allReferrals.filter((row) => serverInWindow(row.tsHour));
27201
27224
  const serverSummary = summarizeServer(crawlers, fetches, referrals);
27202
27225
  const server = serverSources.length ? serverSummary.summary : null;
27203
- const latest = db.select().from(runs).where(and24(
27226
+ const latest = db.select().from(runs).where(and25(
27204
27227
  eq30(runs.projectId, project.id),
27205
27228
  eq30(runs.kind, RunKinds["answer-visibility"]),
27206
27229
  eq30(runs.status, RunStatuses.completed),
@@ -27445,7 +27468,7 @@ async function organicEvidenceRoutes(app) {
27445
27468
  }
27446
27469
 
27447
27470
  // ../api-routes/src/citations.ts
27448
- import { and as and25, eq as eq31, inArray as inArray13 } from "drizzle-orm";
27471
+ import { and as and26, eq as eq31, inArray as inArray13 } from "drizzle-orm";
27449
27472
  async function citationRoutes(app) {
27450
27473
  app.get("/projects/:name/citations/visibility", async (request, reply) => {
27451
27474
  const project = resolveProject(app.db, request.params.name);
@@ -27454,7 +27477,7 @@ async function citationRoutes(app) {
27454
27477
  if (projectQueries.length === 0) {
27455
27478
  return reply.send(emptyCitationVisibility("no-queries"));
27456
27479
  }
27457
- const projectRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(and25(eq31(runs.projectId, project.id), notProbeRun())).all();
27480
+ const projectRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(and26(eq31(runs.projectId, project.id), notProbeRun())).all();
27458
27481
  if (projectRuns.length === 0) {
27459
27482
  return reply.send(emptyCitationVisibility("no-runs-yet"));
27460
27483
  }
@@ -27606,7 +27629,7 @@ function computeCitationVisibility(input) {
27606
27629
  }
27607
27630
 
27608
27631
  // ../api-routes/src/visibility-stats.ts
27609
- import { and as and26, desc as desc14, eq as eq32, inArray as inArray14 } from "drizzle-orm";
27632
+ import { and as and27, desc as desc14, eq as eq32, inArray as inArray14 } from "drizzle-orm";
27610
27633
 
27611
27634
  // ../api-routes/src/visibility-compare.ts
27612
27635
  var VISIBILITY_COMPARE_MIN_RUNS = 5;
@@ -28033,7 +28056,7 @@ async function visibilityStatsRoutes(app) {
28033
28056
  lastRuns = n;
28034
28057
  }
28035
28058
  const projectQueries = app.db.select({ id: queries.id, query: queries.query }).from(queries).where(eq32(queries.projectId, project.id)).all();
28036
- let projectRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt, status: runs.status }).from(runs).where(and26(eq32(runs.projectId, project.id), eq32(runs.kind, RunKinds["answer-visibility"]), notProbeRun())).orderBy(desc14(runs.createdAt)).all().filter((r) => r.status === RunStatuses.completed || r.status === RunStatuses.partial);
28059
+ let projectRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt, status: runs.status }).from(runs).where(and27(eq32(runs.projectId, project.id), eq32(runs.kind, RunKinds["answer-visibility"]), notProbeRun())).orderBy(desc14(runs.createdAt)).all().filter((r) => r.status === RunStatuses.completed || r.status === RunStatuses.partial);
28037
28060
  if (sinceMs !== null) projectRuns = projectRuns.filter((r) => Date.parse(r.createdAt) >= sinceMs);
28038
28061
  if (untilMs !== null) projectRuns = projectRuns.filter((r) => Date.parse(r.createdAt) <= untilMs);
28039
28062
  if (lastRuns !== null) projectRuns = projectRuns.slice(0, lastRuns);
@@ -28135,7 +28158,7 @@ async function visibilityStatsRoutes(app) {
28135
28158
  const loadMonth = (bounds) => {
28136
28159
  const sinceMs = Date.parse(bounds.since);
28137
28160
  const untilMs = Date.parse(bounds.until);
28138
- const monthRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt, status: runs.status }).from(runs).where(and26(eq32(runs.projectId, project.id), eq32(runs.kind, RunKinds["answer-visibility"]), notProbeRun())).all().filter(
28161
+ const monthRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt, status: runs.status }).from(runs).where(and27(eq32(runs.projectId, project.id), eq32(runs.kind, RunKinds["answer-visibility"]), notProbeRun())).all().filter(
28139
28162
  (r) => (r.status === RunStatuses.completed || r.status === RunStatuses.partial) && Date.parse(r.createdAt) >= sinceMs && Date.parse(r.createdAt) <= untilMs
28140
28163
  );
28141
28164
  const runIds = monthRuns.map((r) => r.id);
@@ -28166,7 +28189,7 @@ async function visibilityStatsRoutes(app) {
28166
28189
  }
28167
28190
 
28168
28191
  // ../api-routes/src/results-export.ts
28169
- import { and as and27, asc as asc5, eq as eq33, gte as gte8, lte as lte6 } from "drizzle-orm";
28192
+ import { and as and28, asc as asc5, eq as eq33, gte as gte8, lte as lte6 } from "drizzle-orm";
28170
28193
  var CSV_COLUMNS = [
28171
28194
  "export_schema_version",
28172
28195
  "project_id",
@@ -28336,7 +28359,7 @@ async function resultsExportRoutes(app) {
28336
28359
  recommendedCompetitors: querySnapshots.recommendedCompetitors,
28337
28360
  answerText: querySnapshots.answerText,
28338
28361
  rawResponse: querySnapshots.rawResponse
28339
- }).from(querySnapshots).innerJoin(runs, eq33(querySnapshots.runId, runs.id)).leftJoin(queries, eq33(querySnapshots.queryId, queries.id)).where(and27(...conditions)).orderBy(asc5(runs.createdAt), asc5(runs.id), asc5(querySnapshots.createdAt), asc5(querySnapshots.id)).all();
28362
+ }).from(querySnapshots).innerJoin(runs, eq33(querySnapshots.runId, runs.id)).leftJoin(queries, eq33(querySnapshots.queryId, queries.id)).where(and28(...conditions)).orderBy(asc5(runs.createdAt), asc5(runs.id), asc5(querySnapshots.createdAt), asc5(querySnapshots.id)).all();
28340
28363
  const records = rows.map((row) => {
28341
28364
  const evidence = readEvidence(row.rawResponse);
28342
28365
  const citationState = row.citationState === CitationStates.cited ? CitationStates.cited : CitationStates["not-cited"];
@@ -28404,7 +28427,7 @@ async function resultsExportRoutes(app) {
28404
28427
  }
28405
28428
 
28406
28429
  // ../api-routes/src/composites.ts
28407
- import { eq as eq34, and as and28, desc as desc15, sql as sql12, like as like2, or as or7, inArray as inArray15 } from "drizzle-orm";
28430
+ import { eq as eq34, and as and29, desc as desc15, sql as sql13, like as like2, or as or7, inArray as inArray15 } from "drizzle-orm";
28408
28431
  var TOP_INSIGHT_LIMIT = 5;
28409
28432
  var SEARCH_HIT_HARD_LIMIT = 50;
28410
28433
  var SEARCH_SNIPPET_RADIUS = 80;
@@ -28424,7 +28447,7 @@ async function compositeRoutes(app) {
28424
28447
  const project = resolveProject(app.db, request.params.name);
28425
28448
  const filterLocation = (request.query.location ?? "").trim() || null;
28426
28449
  const sinceIso = parseSinceFilter(request.query.since);
28427
- const allRunsRaw = app.db.select().from(runs).where(and28(eq34(runs.projectId, project.id), notProbeRun())).orderBy(desc15(runs.createdAt), desc15(runs.id)).all();
28450
+ const allRunsRaw = app.db.select().from(runs).where(and29(eq34(runs.projectId, project.id), notProbeRun())).orderBy(desc15(runs.createdAt), desc15(runs.id)).all();
28428
28451
  const allRuns = allRunsRaw.filter((r) => runMatchesFilters(r, filterLocation, sinceIso));
28429
28452
  const totalRuns = allRuns.length;
28430
28453
  const visibilityRuns = allRuns.filter((r) => r.kind === RunKinds["answer-visibility"]);
@@ -28591,25 +28614,25 @@ async function compositeRoutes(app) {
28591
28614
  rawResponse: querySnapshots.rawResponse,
28592
28615
  createdAt: querySnapshots.createdAt
28593
28616
  }).from(querySnapshots).innerJoin(queries, eq34(querySnapshots.queryId, queries.id)).where(
28594
- and28(
28617
+ and29(
28595
28618
  eq34(queries.projectId, project.id),
28596
28619
  or7(
28597
- sql12`${querySnapshots.answerText} LIKE ${pattern} ESCAPE '\\'`,
28598
- sql12`${querySnapshots.citedDomains} LIKE ${pattern} ESCAPE '\\'`,
28599
- sql12`${querySnapshots.citedUrls} LIKE ${pattern} ESCAPE '\\'`,
28600
- sql12`${querySnapshots.rawResponse} LIKE ${pattern} ESCAPE '\\'`,
28620
+ sql13`${querySnapshots.answerText} LIKE ${pattern} ESCAPE '\\'`,
28621
+ sql13`${querySnapshots.citedDomains} LIKE ${pattern} ESCAPE '\\'`,
28622
+ sql13`${querySnapshots.citedUrls} LIKE ${pattern} ESCAPE '\\'`,
28623
+ sql13`${querySnapshots.rawResponse} LIKE ${pattern} ESCAPE '\\'`,
28601
28624
  like2(queries.query, pattern)
28602
28625
  )
28603
28626
  )
28604
28627
  ).orderBy(desc15(querySnapshots.createdAt)).limit(limit + 1).all());
28605
28628
  const insightMatches = app.db.select().from(insights).where(
28606
- and28(
28629
+ and29(
28607
28630
  eq34(insights.projectId, project.id),
28608
28631
  or7(
28609
28632
  like2(insights.title, pattern),
28610
28633
  like2(insights.query, pattern),
28611
- sql12`${insights.recommendation} LIKE ${pattern} ESCAPE '\\'`,
28612
- sql12`${insights.cause} LIKE ${pattern} ESCAPE '\\'`
28634
+ sql13`${insights.recommendation} LIKE ${pattern} ESCAPE '\\'`,
28635
+ sql13`${insights.cause} LIKE ${pattern} ESCAPE '\\'`
28613
28636
  )
28614
28637
  )
28615
28638
  ).orderBy(desc15(insights.createdAt)).limit(limit + 1).all();
@@ -28832,20 +28855,20 @@ function buildSuggestedQueriesFromGsc(app, projectId, trackedQueries) {
28832
28855
  const dimensionedRows = app.db.select({
28833
28856
  date: gscSearchData.date,
28834
28857
  query: gscSearchData.query,
28835
- impressions: sql12`COALESCE(SUM(${gscSearchData.impressions}), 0)`,
28836
- clicks: sql12`COALESCE(SUM(${gscSearchData.clicks}), 0)`,
28858
+ impressions: sql13`COALESCE(SUM(${gscSearchData.impressions}), 0)`,
28859
+ clicks: sql13`COALESCE(SUM(${gscSearchData.clicks}), 0)`,
28837
28860
  // Weighted average: SUM(position * impressions) / SUM(impressions).
28838
28861
  // NULLIF guards the degenerate impressions=0 case (SQLite returns NULL,
28839
28862
  // which the JS coerces to 0 — caught by the impression floor anyway).
28840
- avgPosition: sql12`COALESCE(SUM(${gscSearchData.position} * ${gscSearchData.impressions}) * 1.0 / NULLIF(SUM(${gscSearchData.impressions}), 0), 0)`
28841
- }).from(gscSearchData).where(and28(
28863
+ avgPosition: sql13`COALESCE(SUM(${gscSearchData.position} * ${gscSearchData.impressions}) * 1.0 / NULLIF(SUM(${gscSearchData.impressions}), 0), 0)`
28864
+ }).from(gscSearchData).where(and29(
28842
28865
  eq34(gscSearchData.projectId, projectId),
28843
- sql12`${gscSearchData.date} >= ${cutoff}`,
28866
+ sql13`${gscSearchData.date} >= ${cutoff}`,
28844
28867
  // Same upper bound as the accurate source below. The merge picks a source
28845
28868
  // PER DAY, so an asymmetric range would let a dimensioned-only day past
28846
28869
  // the window's end into a basket the other source cannot balance.
28847
- sql12`${gscSearchData.date} <= ${suggestionWindow.endDate ?? "9999-12-31"}`,
28848
- sql12`${gscSearchData.impressions} > 0`
28870
+ sql13`${gscSearchData.date} <= ${suggestionWindow.endDate ?? "9999-12-31"}`,
28871
+ sql13`${gscSearchData.impressions} > 0`
28849
28872
  )).groupBy(gscSearchData.date, gscSearchData.query).all();
28850
28873
  const merged = mergeGscQueryTotalsWithFallback(
28851
28874
  readGscQueryDailyRows(app.db, projectId, cutoff, suggestionWindow.endDate ?? "9999-12-31"),
@@ -36668,7 +36691,7 @@ async function telemetryRoutes(app, opts) {
36668
36691
 
36669
36692
  // ../api-routes/src/schedules.ts
36670
36693
  import crypto24 from "crypto";
36671
- import { and as and29, eq as eq37 } from "drizzle-orm";
36694
+ import { and as and30, eq as eq37 } from "drizzle-orm";
36672
36695
  function parseKindParam(raw) {
36673
36696
  if (raw === void 0 || raw === null || raw === "") return SchedulableRunKinds["answer-visibility"];
36674
36697
  const parsed = schedulableRunKindSchema.safeParse(raw);
@@ -36740,7 +36763,7 @@ async function scheduleRoutes(app, opts) {
36740
36763
  }
36741
36764
  const now = (/* @__PURE__ */ new Date()).toISOString();
36742
36765
  const enabledBool = enabled !== false;
36743
- const existing = app.db.select().from(schedules).where(and29(eq37(schedules.projectId, project.id), eq37(schedules.kind, kind))).get();
36766
+ const existing = app.db.select().from(schedules).where(and30(eq37(schedules.projectId, project.id), eq37(schedules.kind, kind))).get();
36744
36767
  if (existing) {
36745
36768
  app.db.update(schedules).set({
36746
36769
  cronExpr,
@@ -36774,13 +36797,13 @@ async function scheduleRoutes(app, opts) {
36774
36797
  diff: { kind, cronExpr, preset, timezone, providers, sourceId }
36775
36798
  });
36776
36799
  opts.onScheduleUpdated?.("upsert", project.id, kind);
36777
- const schedule = app.db.select().from(schedules).where(and29(eq37(schedules.projectId, project.id), eq37(schedules.kind, kind))).get();
36800
+ const schedule = app.db.select().from(schedules).where(and30(eq37(schedules.projectId, project.id), eq37(schedules.kind, kind))).get();
36778
36801
  return reply.status(existing ? 200 : 201).send(formatSchedule(schedule));
36779
36802
  });
36780
36803
  app.get("/projects/:name/schedule", async (request, reply) => {
36781
36804
  const project = resolveProject(app.db, request.params.name);
36782
36805
  const kind = parseKindParam(request.query?.kind);
36783
- const schedule = app.db.select().from(schedules).where(and29(eq37(schedules.projectId, project.id), eq37(schedules.kind, kind))).get();
36806
+ const schedule = app.db.select().from(schedules).where(and30(eq37(schedules.projectId, project.id), eq37(schedules.kind, kind))).get();
36784
36807
  if (!schedule) {
36785
36808
  throw notFound("Schedule", `${request.params.name} (kind=${kind})`);
36786
36809
  }
@@ -36789,7 +36812,7 @@ async function scheduleRoutes(app, opts) {
36789
36812
  app.delete("/projects/:name/schedule", async (request, reply) => {
36790
36813
  const project = resolveProject(app.db, request.params.name);
36791
36814
  const kind = parseKindParam(request.query?.kind);
36792
- const schedule = app.db.select().from(schedules).where(and29(eq37(schedules.projectId, project.id), eq37(schedules.kind, kind))).get();
36815
+ const schedule = app.db.select().from(schedules).where(and30(eq37(schedules.projectId, project.id), eq37(schedules.kind, kind))).get();
36793
36816
  if (!schedule) {
36794
36817
  throw notFound("Schedule", `${request.params.name} (kind=${kind})`);
36795
36818
  }
@@ -37159,7 +37182,7 @@ function formatNotification(row) {
37159
37182
 
37160
37183
  // ../api-routes/src/google.ts
37161
37184
  import crypto30 from "crypto";
37162
- import { eq as eq39, and as and30, desc as desc17, sql as sql13, inArray as inArray16 } from "drizzle-orm";
37185
+ import { eq as eq39, and as and31, desc as desc17, sql as sql14, inArray as inArray16 } from "drizzle-orm";
37163
37186
 
37164
37187
  // ../api-routes/src/gsc-period-comparison.ts
37165
37188
  var DAY_MS = 864e5;
@@ -39587,11 +39610,11 @@ async function googleRoutes(app, opts) {
39587
39610
  const cutoffDate = startDate ? null : resolvedWindow.startDate;
39588
39611
  const effectiveEndDate = endDate ?? (daysParam === null ? void 0 : resolvedWindow.endDate ?? void 0);
39589
39612
  const conditions = [eq39(gscSearchData.projectId, project.id)];
39590
- if (startDate) conditions.push(sql13`${gscSearchData.date} >= ${startDate}`);
39591
- else if (cutoffDate) conditions.push(sql13`${gscSearchData.date} >= ${cutoffDate}`);
39592
- if (effectiveEndDate) conditions.push(sql13`${gscSearchData.date} <= ${effectiveEndDate}`);
39593
- if (query) conditions.push(sql13`${gscSearchData.query} LIKE ${"%" + escapeLikePattern(query) + "%"} ESCAPE '\\'`);
39594
- if (page) conditions.push(sql13`${gscSearchData.page} LIKE ${"%" + escapeLikePattern(page) + "%"} ESCAPE '\\'`);
39613
+ if (startDate) conditions.push(sql14`${gscSearchData.date} >= ${startDate}`);
39614
+ else if (cutoffDate) conditions.push(sql14`${gscSearchData.date} >= ${cutoffDate}`);
39615
+ if (effectiveEndDate) conditions.push(sql14`${gscSearchData.date} <= ${effectiveEndDate}`);
39616
+ if (query) conditions.push(sql14`${gscSearchData.query} LIKE ${"%" + escapeLikePattern(query) + "%"} ESCAPE '\\'`);
39617
+ if (page) conditions.push(sql14`${gscSearchData.page} LIKE ${"%" + escapeLikePattern(page) + "%"} ESCAPE '\\'`);
39595
39618
  const limitVal = Math.max(parseInt(limit ?? "500", 10) || 0, 1);
39596
39619
  const offsetVal = Math.max(parseInt(offset ?? "0", 10) || 0, 0);
39597
39620
  const orderColumns = {
@@ -39599,9 +39622,9 @@ async function googleRoutes(app, opts) {
39599
39622
  impressions: [desc17(gscSearchData.impressions), desc17(gscSearchData.date), gscSearchData.query],
39600
39623
  date: [desc17(gscSearchData.date), desc17(gscSearchData.clicks), gscSearchData.query]
39601
39624
  }[orderBy];
39602
- const rows = app.db.select().from(gscSearchData).where(and30(...conditions)).orderBy(...orderColumns).limit(limitVal).offset(offsetVal).all();
39603
- const totalMatching = app.db.select({ total: sql13`COUNT(*)` }).from(gscSearchData).where(and30(...conditions)).get()?.total ?? 0;
39604
- const latestAvailableDate = app.db.select({ latest: sql13`MAX(${gscSearchData.date})` }).from(gscSearchData).where(eq39(gscSearchData.projectId, project.id)).get()?.latest ?? null;
39625
+ const rows = app.db.select().from(gscSearchData).where(and31(...conditions)).orderBy(...orderColumns).limit(limitVal).offset(offsetVal).all();
39626
+ const totalMatching = app.db.select({ total: sql14`COUNT(*)` }).from(gscSearchData).where(and31(...conditions)).get()?.total ?? 0;
39627
+ const latestAvailableDate = app.db.select({ latest: sql14`MAX(${gscSearchData.date})` }).from(gscSearchData).where(eq39(gscSearchData.projectId, project.id)).get()?.latest ?? null;
39605
39628
  return {
39606
39629
  rows: rows.map((r) => ({
39607
39630
  date: r.date,
@@ -39637,14 +39660,14 @@ async function googleRoutes(app, opts) {
39637
39660
  const windowEnd = endDate ?? resolvedWindow.endDate ?? "9999-12-31";
39638
39661
  const dailyTotals = readGscDailyTotals(app.db, project.id, windowStart, windowEnd);
39639
39662
  const conditions = [eq39(gscSearchData.projectId, project.id)];
39640
- if (startDate) conditions.push(sql13`${gscSearchData.date} >= ${startDate}`);
39641
- else if (cutoffDate) conditions.push(sql13`${gscSearchData.date} >= ${cutoffDate}`);
39642
- if (endDate) conditions.push(sql13`${gscSearchData.date} <= ${endDate}`);
39663
+ if (startDate) conditions.push(sql14`${gscSearchData.date} >= ${startDate}`);
39664
+ else if (cutoffDate) conditions.push(sql14`${gscSearchData.date} >= ${cutoffDate}`);
39665
+ if (endDate) conditions.push(sql14`${gscSearchData.date} <= ${endDate}`);
39643
39666
  const dimensionedRows = app.db.select({
39644
39667
  date: gscSearchData.date,
39645
- clicks: sql13`COALESCE(SUM(${gscSearchData.clicks}), 0)`,
39646
- impressions: sql13`COALESCE(SUM(${gscSearchData.impressions}), 0)`
39647
- }).from(gscSearchData).where(and30(...conditions)).groupBy(gscSearchData.date).orderBy(gscSearchData.date).all();
39668
+ clicks: sql14`COALESCE(SUM(${gscSearchData.clicks}), 0)`,
39669
+ impressions: sql14`COALESCE(SUM(${gscSearchData.impressions}), 0)`
39670
+ }).from(gscSearchData).where(and31(...conditions)).groupBy(gscSearchData.date).orderBy(gscSearchData.date).all();
39648
39671
  const propertyDates = new Set(dailyTotals.map((d) => d.date));
39649
39672
  const daily = mergeGscDailyTotalsWithFallback(
39650
39673
  dailyTotals,
@@ -39740,24 +39763,24 @@ async function googleRoutes(app, opts) {
39740
39763
  );
39741
39764
  const cutoffDate = startDate ? null : resolvedWindow.startDate;
39742
39765
  const conditions = [eq39(gscSearchData.projectId, project.id)];
39743
- if (startDate) conditions.push(sql13`${gscSearchData.date} >= ${startDate}`);
39744
- else if (cutoffDate) conditions.push(sql13`${gscSearchData.date} >= ${cutoffDate}`);
39745
- if (endDate) conditions.push(sql13`${gscSearchData.date} <= ${endDate}`);
39766
+ if (startDate) conditions.push(sql14`${gscSearchData.date} >= ${startDate}`);
39767
+ else if (cutoffDate) conditions.push(sql14`${gscSearchData.date} >= ${cutoffDate}`);
39768
+ if (endDate) conditions.push(sql14`${gscSearchData.date} <= ${endDate}`);
39746
39769
  const limitVal = Math.max(parseInt(limit ?? "50", 10) || 0, 1);
39747
39770
  const rows = app.db.select({
39748
39771
  page: gscSearchData.page,
39749
- clicks: sql13`COALESCE(SUM(${gscSearchData.clicks}), 0)`,
39750
- impressions: sql13`COALESCE(SUM(${gscSearchData.impressions}), 0)`
39751
- }).from(gscSearchData).where(and30(...conditions)).groupBy(gscSearchData.page).orderBy(desc17(sql13`SUM(${gscSearchData.clicks})`), desc17(sql13`SUM(${gscSearchData.impressions})`)).limit(limitVal).all();
39772
+ clicks: sql14`COALESCE(SUM(${gscSearchData.clicks}), 0)`,
39773
+ impressions: sql14`COALESCE(SUM(${gscSearchData.impressions}), 0)`
39774
+ }).from(gscSearchData).where(and31(...conditions)).groupBy(gscSearchData.page).orderBy(desc17(sql14`SUM(${gscSearchData.clicks})`), desc17(sql14`SUM(${gscSearchData.impressions})`)).limit(limitVal).all();
39752
39775
  const windowStart = startDate ?? cutoffDate ?? "";
39753
39776
  const windowEnd = endDate ?? resolvedWindow.endDate ?? "9999-12-31";
39754
39777
  const dailyTotals = readGscDailyTotals(app.db, project.id, windowStart, windowEnd);
39755
39778
  const totalClicks = dailyTotals.reduce((sum, d) => sum + d.clicks, 0);
39756
39779
  const totalImpressions = dailyTotals.reduce((sum, d) => sum + d.impressions, 0);
39757
39780
  const rankedSpan = app.db.select({
39758
- first: sql13`MIN(${gscSearchData.date})`,
39759
- last: sql13`MAX(${gscSearchData.date})`
39760
- }).from(gscSearchData).where(and30(...conditions)).get();
39781
+ first: sql14`MIN(${gscSearchData.date})`,
39782
+ last: sql14`MAX(${gscSearchData.date})`
39783
+ }).from(gscSearchData).where(and31(...conditions)).get();
39761
39784
  const coveredFrom = dailyTotals.length > 0 ? dailyTotals[0].date : null;
39762
39785
  const coveredThrough = dailyTotals.length > 0 ? dailyTotals[dailyTotals.length - 1].date : null;
39763
39786
  const totalsComplete = Boolean(
@@ -39851,7 +39874,7 @@ async function googleRoutes(app, opts) {
39851
39874
  const { url, limit } = request.query;
39852
39875
  const conditions = [eq39(gscUrlInspections.projectId, project.id)];
39853
39876
  if (url) conditions.push(eq39(gscUrlInspections.url, url));
39854
- const rows = app.db.select().from(gscUrlInspections).where(and30(...conditions)).orderBy(desc17(gscUrlInspections.inspectedAt)).limit(parseInt(limit ?? "100", 10)).all();
39877
+ const rows = app.db.select().from(gscUrlInspections).where(and31(...conditions)).orderBy(desc17(gscUrlInspections.inspectedAt)).limit(parseInt(limit ?? "100", 10)).all();
39855
39878
  return rows.map((r) => ({
39856
39879
  id: r.id,
39857
39880
  url: r.url,
@@ -40417,7 +40440,7 @@ async function googleRoutes(app, opts) {
40417
40440
  app.db.transaction((tx) => {
40418
40441
  if (switching) clearGbpProjectData(tx, project.id);
40419
40442
  for (const remote of remoteLocations) {
40420
- const existing = tx.select().from(gbpLocations).where(and30(eq39(gbpLocations.projectId, project.id), eq39(gbpLocations.locationName, remote.name))).get();
40443
+ const existing = tx.select().from(gbpLocations).where(and31(eq39(gbpLocations.projectId, project.id), eq39(gbpLocations.locationName, remote.name))).get();
40421
40444
  const profile = buildLocationProfileFields(remote);
40422
40445
  if (existing) {
40423
40446
  tx.update(gbpLocations).set({
@@ -40515,7 +40538,7 @@ async function googleRoutes(app, opts) {
40515
40538
  throw validationError(parsed.error.issues[0]?.message ?? "Invalid selection request");
40516
40539
  }
40517
40540
  const { selected } = parsed.data;
40518
- const existing = app.db.select().from(gbpLocations).where(and30(eq39(gbpLocations.projectId, project.id), eq39(gbpLocations.locationName, locationName))).get();
40541
+ const existing = app.db.select().from(gbpLocations).where(and31(eq39(gbpLocations.projectId, project.id), eq39(gbpLocations.locationName, locationName))).get();
40519
40542
  if (!existing) throw notFound("GBP location", locationName);
40520
40543
  const now = (/* @__PURE__ */ new Date()).toISOString();
40521
40544
  app.db.transaction((tx) => {
@@ -40575,7 +40598,7 @@ async function googleRoutes(app, opts) {
40575
40598
  const conditions = [eq39(gbpDailyMetrics.projectId, project.id)];
40576
40599
  if (request.query.locationName) conditions.push(eq39(gbpDailyMetrics.locationName, request.query.locationName));
40577
40600
  if (request.query.metric) conditions.push(eq39(gbpDailyMetrics.metric, request.query.metric));
40578
- const rows = app.db.select().from(gbpDailyMetrics).where(and30(...conditions)).orderBy(desc17(gbpDailyMetrics.date)).all();
40601
+ const rows = app.db.select().from(gbpDailyMetrics).where(and31(...conditions)).orderBy(desc17(gbpDailyMetrics.date)).all();
40579
40602
  return {
40580
40603
  metrics: rows.map((r) => ({ locationName: r.locationName, date: r.date, metric: r.metric, value: r.value })),
40581
40604
  total: rows.length
@@ -40585,7 +40608,7 @@ async function googleRoutes(app, opts) {
40585
40608
  const project = resolveProject(app.db, request.params.name);
40586
40609
  const conditions = [eq39(gbpKeywordImpressions.projectId, project.id)];
40587
40610
  if (request.query.locationName) conditions.push(eq39(gbpKeywordImpressions.locationName, request.query.locationName));
40588
- const rows = app.db.select().from(gbpKeywordImpressions).where(and30(...conditions)).all();
40611
+ const rows = app.db.select().from(gbpKeywordImpressions).where(and31(...conditions)).all();
40589
40612
  rows.sort((a, b) => (b.valueCount ?? -1) - (a.valueCount ?? -1));
40590
40613
  const thresholded = rows.filter((r) => r.valueThreshold !== null).length;
40591
40614
  return {
@@ -40605,7 +40628,7 @@ async function googleRoutes(app, opts) {
40605
40628
  const project = resolveProject(app.db, request.params.name);
40606
40629
  const conditions = [eq39(gbpPlaceActions.projectId, project.id)];
40607
40630
  if (request.query.locationName) conditions.push(eq39(gbpPlaceActions.locationName, request.query.locationName));
40608
- const rows = app.db.select().from(gbpPlaceActions).where(and30(...conditions)).all();
40631
+ const rows = app.db.select().from(gbpPlaceActions).where(and31(...conditions)).all();
40609
40632
  return {
40610
40633
  placeActions: rows.map((r) => ({
40611
40634
  locationName: r.locationName,
@@ -40622,7 +40645,7 @@ async function googleRoutes(app, opts) {
40622
40645
  const project = resolveProject(app.db, request.params.name);
40623
40646
  const conditions = [eq39(gbpLodgingSnapshots.projectId, project.id)];
40624
40647
  if (request.query.locationName) conditions.push(eq39(gbpLodgingSnapshots.locationName, request.query.locationName));
40625
- const rows = app.db.select().from(gbpLodgingSnapshots).where(and30(...conditions)).orderBy(desc17(gbpLodgingSnapshots.syncedAt)).all();
40648
+ const rows = app.db.select().from(gbpLodgingSnapshots).where(and31(...conditions)).orderBy(desc17(gbpLodgingSnapshots.syncedAt)).all();
40626
40649
  const latestByLocation = /* @__PURE__ */ new Map();
40627
40650
  for (const row of rows) {
40628
40651
  if (!latestByLocation.has(row.locationName)) latestByLocation.set(row.locationName, row);
@@ -40639,7 +40662,7 @@ async function googleRoutes(app, opts) {
40639
40662
  const project = resolveProject(app.db, request.params.name);
40640
40663
  const conditions = [eq39(gbpAttributesSnapshots.projectId, project.id)];
40641
40664
  if (request.query.locationName) conditions.push(eq39(gbpAttributesSnapshots.locationName, request.query.locationName));
40642
- const rows = app.db.select().from(gbpAttributesSnapshots).where(and30(...conditions)).orderBy(desc17(gbpAttributesSnapshots.syncedAt)).all();
40665
+ const rows = app.db.select().from(gbpAttributesSnapshots).where(and31(...conditions)).orderBy(desc17(gbpAttributesSnapshots.syncedAt)).all();
40643
40666
  const latestByLocation = /* @__PURE__ */ new Map();
40644
40667
  for (const row of rows) {
40645
40668
  if (!latestByLocation.has(row.locationName)) latestByLocation.set(row.locationName, row);
@@ -40659,7 +40682,7 @@ async function googleRoutes(app, opts) {
40659
40682
  const project = resolveProject(app.db, request.params.name);
40660
40683
  const conditions = [eq39(gbpPlaceDetails.projectId, project.id)];
40661
40684
  if (request.query.locationName) conditions.push(eq39(gbpPlaceDetails.locationName, request.query.locationName));
40662
- const rows = app.db.select().from(gbpPlaceDetails).where(and30(...conditions)).orderBy(desc17(gbpPlaceDetails.syncedAt)).all();
40685
+ const rows = app.db.select().from(gbpPlaceDetails).where(and31(...conditions)).orderBy(desc17(gbpPlaceDetails.syncedAt)).all();
40663
40686
  const latestByLocation = /* @__PURE__ */ new Map();
40664
40687
  for (const row of rows) {
40665
40688
  if (!latestByLocation.has(row.locationName)) latestByLocation.set(row.locationName, row);
@@ -40678,7 +40701,7 @@ async function googleRoutes(app, opts) {
40678
40701
  app.get("/projects/:name/gbp/summary", async (request) => {
40679
40702
  const project = resolveProject(app.db, request.params.name);
40680
40703
  const locationName = request.query.locationName ?? null;
40681
- const locationNames = locationName ? [locationName] : app.db.select({ n: gbpLocations.locationName }).from(gbpLocations).where(and30(eq39(gbpLocations.projectId, project.id), eq39(gbpLocations.selected, true))).all().map((r) => r.n);
40704
+ const locationNames = locationName ? [locationName] : app.db.select({ n: gbpLocations.locationName }).from(gbpLocations).where(and31(eq39(gbpLocations.projectId, project.id), eq39(gbpLocations.selected, true))).all().map((r) => r.n);
40682
40705
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
40683
40706
  if (locationNames.length === 0) {
40684
40707
  return buildGbpSummary({
@@ -40692,10 +40715,10 @@ async function googleRoutes(app, opts) {
40692
40715
  locationProfiles: []
40693
40716
  });
40694
40717
  }
40695
- const metricRows = app.db.select().from(gbpDailyMetrics).where(and30(eq39(gbpDailyMetrics.projectId, project.id), inArray16(gbpDailyMetrics.locationName, locationNames))).all();
40696
- const keywordRows = app.db.select().from(gbpKeywordImpressions).where(and30(eq39(gbpKeywordImpressions.projectId, project.id), inArray16(gbpKeywordImpressions.locationName, locationNames))).all();
40697
- const placeActionRows = app.db.select().from(gbpPlaceActions).where(and30(eq39(gbpPlaceActions.projectId, project.id), inArray16(gbpPlaceActions.locationName, locationNames))).all();
40698
- const lodgingRows = app.db.select().from(gbpLodgingSnapshots).where(and30(eq39(gbpLodgingSnapshots.projectId, project.id), inArray16(gbpLodgingSnapshots.locationName, locationNames))).orderBy(desc17(gbpLodgingSnapshots.syncedAt)).all();
40718
+ const metricRows = app.db.select().from(gbpDailyMetrics).where(and31(eq39(gbpDailyMetrics.projectId, project.id), inArray16(gbpDailyMetrics.locationName, locationNames))).all();
40719
+ const keywordRows = app.db.select().from(gbpKeywordImpressions).where(and31(eq39(gbpKeywordImpressions.projectId, project.id), inArray16(gbpKeywordImpressions.locationName, locationNames))).all();
40720
+ const placeActionRows = app.db.select().from(gbpPlaceActions).where(and31(eq39(gbpPlaceActions.projectId, project.id), inArray16(gbpPlaceActions.locationName, locationNames))).all();
40721
+ const lodgingRows = app.db.select().from(gbpLodgingSnapshots).where(and31(eq39(gbpLodgingSnapshots.projectId, project.id), inArray16(gbpLodgingSnapshots.locationName, locationNames))).orderBy(desc17(gbpLodgingSnapshots.syncedAt)).all();
40699
40722
  const latestLodgingByLocation = /* @__PURE__ */ new Map();
40700
40723
  for (const row of lodgingRows) {
40701
40724
  if (!latestLodgingByLocation.has(row.locationName)) {
@@ -40709,7 +40732,7 @@ async function googleRoutes(app, opts) {
40709
40732
  regularHours: gbpLocations.regularHours,
40710
40733
  primaryPhone: gbpLocations.primaryPhone,
40711
40734
  openStatus: gbpLocations.openStatus
40712
- }).from(gbpLocations).where(and30(eq39(gbpLocations.projectId, project.id), inArray16(gbpLocations.locationName, locationNames))).all();
40735
+ }).from(gbpLocations).where(and31(eq39(gbpLocations.projectId, project.id), inArray16(gbpLocations.locationName, locationNames))).all();
40713
40736
  return buildGbpSummary({
40714
40737
  locationName,
40715
40738
  locationCount: locationNames.length,
@@ -40725,7 +40748,7 @@ async function googleRoutes(app, opts) {
40725
40748
 
40726
40749
  // ../api-routes/src/google-marketing.ts
40727
40750
  import crypto31 from "crypto";
40728
- import { and as and31, desc as desc18, eq as eq40, isNull as isNull2, lt as lt6, ne as ne4, or as or8, sql as sql14 } from "drizzle-orm";
40751
+ import { and as and32, desc as desc18, eq as eq40, isNull as isNull2, lt as lt6, ne as ne4, or as or8, sql as sql15 } from "drizzle-orm";
40729
40752
  import { z as z4 } from "zod";
40730
40753
  var snapshotPageQuerySchema = z4.object({
40731
40754
  limit: z4.coerce.number().int().min(1).max(GOOGLE_MARKETING_STORED_SNAPSHOT_PAGE_MAX).optional(),
@@ -41007,7 +41030,7 @@ function toGtmSnapshot(row) {
41007
41030
  }
41008
41031
  function selectedGoogleAdsCustomer(app, projectId, selection) {
41009
41032
  if (!selection.lastCustomerSnapshotId) return null;
41010
- const row = app.db.select().from(googleAdsRawSnapshots).where(and31(
41033
+ const row = app.db.select().from(googleAdsRawSnapshots).where(and32(
41011
41034
  eq40(googleAdsRawSnapshots.projectId, projectId),
41012
41035
  eq40(googleAdsRawSnapshots.id, selection.lastCustomerSnapshotId),
41013
41036
  eq40(googleAdsRawSnapshots.connectionId, selection.connectionId),
@@ -41030,7 +41053,7 @@ function hasMatchingGtmGraphEvidence(app, projectId, selection) {
41030
41053
  eq40(gtmRawSnapshots.capturedAt, selection.lastSnapshotAt)
41031
41054
  ];
41032
41055
  conditions.push(selection.workspaceId === null ? isNull2(gtmRawSnapshots.workspaceId) : eq40(gtmRawSnapshots.workspaceId, selection.workspaceId));
41033
- const row = app.db.select().from(gtmRawSnapshots).where(and31(...conditions)).get();
41056
+ const row = app.db.select().from(gtmRawSnapshots).where(and32(...conditions)).get();
41034
41057
  if (!row) return false;
41035
41058
  const snapshot = toGtmSnapshot(row);
41036
41059
  return Boolean(
@@ -41150,7 +41173,7 @@ function latestGoogleAdsSnapshot(app, projectId) {
41150
41173
  eq40(googleAdsRawSnapshots.kind, GoogleAdsSnapshotKinds.inventory),
41151
41174
  eq40(googleAdsRawSnapshots.capturedAt, connection.lastInventorySnapshotAt)
41152
41175
  ];
41153
- const row = app.db.select().from(googleAdsRawSnapshots).where(and31(...conditions)).get();
41176
+ const row = app.db.select().from(googleAdsRawSnapshots).where(and32(...conditions)).get();
41154
41177
  const snapshot = row ? toGoogleAdsSnapshot(row) : null;
41155
41178
  if (!snapshot || snapshot.metadata.id !== connection.lastInventorySnapshotId || snapshot.metadata.connectionId !== connection.id || snapshot.metadata.customerId !== connection.selectedCustomerId || snapshot.metadata.capturedAt !== connection.lastInventorySnapshotAt || snapshot.payload.kind !== GoogleAdsSnapshotKinds.inventory || snapshot.payload.data.customerId !== connection.selectedCustomerId) return null;
41156
41179
  return snapshot;
@@ -41171,7 +41194,7 @@ function latestGtmSnapshot(app, projectId) {
41171
41194
  eq40(gtmRawSnapshots.kind, GtmSnapshotKinds.container)
41172
41195
  ];
41173
41196
  conditions.push(connection.selectedWorkspaceId === null ? isNull2(gtmRawSnapshots.workspaceId) : eq40(gtmRawSnapshots.workspaceId, connection.selectedWorkspaceId));
41174
- const row = app.db.select().from(gtmRawSnapshots).where(and31(...conditions)).get();
41197
+ const row = app.db.select().from(gtmRawSnapshots).where(and32(...conditions)).get();
41175
41198
  const snapshot = row ? toGtmSnapshot(row) : null;
41176
41199
  if (!snapshot || snapshot.metadata.id !== connection.lastSnapshotId || snapshot.metadata.connectionId !== connection.id || snapshot.metadata.accountId !== connection.selectedAccountId || snapshot.metadata.containerId !== connection.selectedContainerId || snapshot.metadata.workspaceId !== connection.selectedWorkspaceId || snapshot.metadata.capturedAt !== connection.lastSnapshotAt || snapshot.payload.kind !== GtmSnapshotKinds.container) return null;
41177
41200
  return snapshot;
@@ -41482,7 +41505,7 @@ async function googleMarketingRoutes(app, opts) {
41482
41505
  selectedCustomerCurrencyCode: null,
41483
41506
  selectedCustomerTimeZone: null,
41484
41507
  selectedCustomerStatus: null,
41485
- selectionGeneration: sql14`${googleAdsConnections.selectionGeneration} + 1`,
41508
+ selectionGeneration: sql15`${googleAdsConnections.selectionGeneration} + 1`,
41486
41509
  scopes: tokens.scopes,
41487
41510
  lastValidatedAt: now,
41488
41511
  lastCustomerSnapshotId: null,
@@ -41513,7 +41536,7 @@ async function googleMarketingRoutes(app, opts) {
41513
41536
  selectedContainerPublicId: null,
41514
41537
  selectedWorkspaceId: null,
41515
41538
  selectedWorkspaceName: null,
41516
- selectionGeneration: sql14`${gtmConnections.selectionGeneration} + 1`,
41539
+ selectionGeneration: sql15`${gtmConnections.selectionGeneration} + 1`,
41517
41540
  scopes: tokens.scopes,
41518
41541
  lastValidatedAt: now,
41519
41542
  lastSnapshotAt: null,
@@ -41643,7 +41666,7 @@ async function googleMarketingRoutes(app, opts) {
41643
41666
  selectedCustomerStatus: customerChanged ? null : existing.selectedCustomerStatus,
41644
41667
  // A same-value write still starts a new selection generation. Do not
41645
41668
  // let timestamp equality reuse append-only evidence from before it.
41646
- selectionGeneration: sql14`${googleAdsConnections.selectionGeneration} + 1`,
41669
+ selectionGeneration: sql15`${googleAdsConnections.selectionGeneration} + 1`,
41647
41670
  lastValidatedAt: now,
41648
41671
  lastCustomerSnapshotId: null,
41649
41672
  lastInventorySnapshotAt: null,
@@ -41686,7 +41709,7 @@ async function googleMarketingRoutes(app, opts) {
41686
41709
  selectedContainerPublicId: containerChanged ? null : existing.selectedContainerPublicId,
41687
41710
  selectedWorkspaceId,
41688
41711
  selectedWorkspaceName: workspaceChanged ? null : existing.selectedWorkspaceName,
41689
- selectionGeneration: sql14`${gtmConnections.selectionGeneration} + 1`,
41712
+ selectionGeneration: sql15`${gtmConnections.selectionGeneration} + 1`,
41690
41713
  lastValidatedAt: now,
41691
41714
  // Every selection write starts a new evidence generation, including a
41692
41715
  // same-value reselection. The timestamp alone cannot order a prior
@@ -41720,7 +41743,7 @@ async function googleMarketingRoutes(app, opts) {
41720
41743
  let run = candidateRun;
41721
41744
  let queued = false;
41722
41745
  app.db.transaction((tx) => {
41723
- const existing = tx.select().from(runs).where(and31(
41746
+ const existing = tx.select().from(runs).where(and32(
41724
41747
  eq40(runs.projectId, project.id),
41725
41748
  eq40(runs.kind, RunKinds["google-ads-sync"]),
41726
41749
  or8(eq40(runs.status, RunStatuses.queued), eq40(runs.status, RunStatuses.running))
@@ -41756,7 +41779,7 @@ async function googleMarketingRoutes(app, opts) {
41756
41779
  let run = candidateRun;
41757
41780
  let queued = false;
41758
41781
  app.db.transaction((tx) => {
41759
- const existing = tx.select().from(runs).where(and31(
41782
+ const existing = tx.select().from(runs).where(and32(
41760
41783
  eq40(runs.projectId, project.id),
41761
41784
  eq40(runs.kind, RunKinds["gtm-sync"]),
41762
41785
  or8(eq40(runs.status, RunStatuses.queued), eq40(runs.status, RunStatuses.running))
@@ -41786,13 +41809,13 @@ async function googleMarketingRoutes(app, opts) {
41786
41809
  if (cursor) {
41787
41810
  conditions.push(or8(
41788
41811
  lt6(googleAdsRawSnapshots.capturedAt, cursor.capturedAt),
41789
- and31(eq40(googleAdsRawSnapshots.capturedAt, cursor.capturedAt), lt6(googleAdsRawSnapshots.id, cursor.id))
41812
+ and32(eq40(googleAdsRawSnapshots.capturedAt, cursor.capturedAt), lt6(googleAdsRawSnapshots.id, cursor.id))
41790
41813
  ));
41791
41814
  }
41792
41815
  const limit = query.limit ?? 50;
41793
- const rows = app.db.select().from(googleAdsRawSnapshots).where(and31(...conditions)).orderBy(desc18(googleAdsRawSnapshots.capturedAt), desc18(googleAdsRawSnapshots.id)).limit(limit + 1).all();
41816
+ const rows = app.db.select().from(googleAdsRawSnapshots).where(and32(...conditions)).orderBy(desc18(googleAdsRawSnapshots.capturedAt), desc18(googleAdsRawSnapshots.id)).limit(limit + 1).all();
41794
41817
  const page = rows.slice(0, limit);
41795
- const total = app.db.select({ total: sql14`COUNT(*)`.mapWith(Number).as("total") }).from(googleAdsRawSnapshots).where(eq40(googleAdsRawSnapshots.projectId, project.id)).get();
41818
+ const total = app.db.select({ total: sql15`COUNT(*)`.mapWith(Number).as("total") }).from(googleAdsRawSnapshots).where(eq40(googleAdsRawSnapshots.projectId, project.id)).get();
41796
41819
  return {
41797
41820
  snapshots: page.map(toGoogleAdsSnapshotMetadata),
41798
41821
  nextCursor: rows.length > limit && page.length > 0 ? encodeSnapshotCursor({ capturedAt: page.at(-1).capturedAt, id: page.at(-1).id }) : null,
@@ -41801,7 +41824,7 @@ async function googleMarketingRoutes(app, opts) {
41801
41824
  });
41802
41825
  app.get("/projects/:name/google-ads/snapshots/:snapshotId", async (request) => {
41803
41826
  const project = resolveProject(app.db, request.params.name);
41804
- const row = app.db.select().from(googleAdsRawSnapshots).where(and31(
41827
+ const row = app.db.select().from(googleAdsRawSnapshots).where(and32(
41805
41828
  eq40(googleAdsRawSnapshots.projectId, project.id),
41806
41829
  eq40(googleAdsRawSnapshots.id, request.params.snapshotId)
41807
41830
  )).get();
@@ -41818,13 +41841,13 @@ async function googleMarketingRoutes(app, opts) {
41818
41841
  if (cursor) {
41819
41842
  conditions.push(or8(
41820
41843
  lt6(gtmRawSnapshots.capturedAt, cursor.capturedAt),
41821
- and31(eq40(gtmRawSnapshots.capturedAt, cursor.capturedAt), lt6(gtmRawSnapshots.id, cursor.id))
41844
+ and32(eq40(gtmRawSnapshots.capturedAt, cursor.capturedAt), lt6(gtmRawSnapshots.id, cursor.id))
41822
41845
  ));
41823
41846
  }
41824
41847
  const limit = query.limit ?? 50;
41825
- const rows = app.db.select().from(gtmRawSnapshots).where(and31(...conditions)).orderBy(desc18(gtmRawSnapshots.capturedAt), desc18(gtmRawSnapshots.id)).limit(limit + 1).all();
41848
+ const rows = app.db.select().from(gtmRawSnapshots).where(and32(...conditions)).orderBy(desc18(gtmRawSnapshots.capturedAt), desc18(gtmRawSnapshots.id)).limit(limit + 1).all();
41826
41849
  const page = rows.slice(0, limit);
41827
- const total = app.db.select({ total: sql14`COUNT(*)`.mapWith(Number).as("total") }).from(gtmRawSnapshots).where(eq40(gtmRawSnapshots.projectId, project.id)).get();
41850
+ const total = app.db.select({ total: sql15`COUNT(*)`.mapWith(Number).as("total") }).from(gtmRawSnapshots).where(eq40(gtmRawSnapshots.projectId, project.id)).get();
41828
41851
  return {
41829
41852
  snapshots: page.map(toGtmSnapshotMetadata),
41830
41853
  nextCursor: rows.length > limit && page.length > 0 ? encodeSnapshotCursor({ capturedAt: page.at(-1).capturedAt, id: page.at(-1).id }) : null,
@@ -41833,7 +41856,7 @@ async function googleMarketingRoutes(app, opts) {
41833
41856
  });
41834
41857
  app.get("/projects/:name/gtm/snapshots/:snapshotId", async (request) => {
41835
41858
  const project = resolveProject(app.db, request.params.name);
41836
- const row = app.db.select().from(gtmRawSnapshots).where(and31(
41859
+ const row = app.db.select().from(gtmRawSnapshots).where(and32(
41837
41860
  eq40(gtmRawSnapshots.projectId, project.id),
41838
41861
  eq40(gtmRawSnapshots.id, request.params.snapshotId)
41839
41862
  )).get();
@@ -41859,7 +41882,7 @@ async function googleMarketingRoutes(app, opts) {
41859
41882
  selectedCustomerCurrencyCode: null,
41860
41883
  selectedCustomerTimeZone: null,
41861
41884
  selectedCustomerStatus: null,
41862
- selectionGeneration: sql14`${googleAdsConnections.selectionGeneration} + 1`,
41885
+ selectionGeneration: sql15`${googleAdsConnections.selectionGeneration} + 1`,
41863
41886
  scopes: [],
41864
41887
  lastValidatedAt: null,
41865
41888
  lastCustomerSnapshotId: null,
@@ -41898,7 +41921,7 @@ async function googleMarketingRoutes(app, opts) {
41898
41921
  selectedContainerPublicId: null,
41899
41922
  selectedWorkspaceId: null,
41900
41923
  selectedWorkspaceName: null,
41901
- selectionGeneration: sql14`${gtmConnections.selectionGeneration} + 1`,
41924
+ selectionGeneration: sql15`${gtmConnections.selectionGeneration} + 1`,
41902
41925
  scopes: [],
41903
41926
  lastValidatedAt: null,
41904
41927
  lastSnapshotAt: null,
@@ -41926,7 +41949,7 @@ async function googleMarketingRoutes(app, opts) {
41926
41949
  parseBody2(conversionTrackingContractWriteRequestSchema, request.body, "conversion tracking contract")
41927
41950
  );
41928
41951
  const project = resolveProject(app.db, request.params.name);
41929
- const duplicate = app.db.select({ id: conversionTrackingContracts.id }).from(conversionTrackingContracts).where(and31(eq40(conversionTrackingContracts.projectId, project.id), eq40(conversionTrackingContracts.name, body.name))).get();
41952
+ const duplicate = app.db.select({ id: conversionTrackingContracts.id }).from(conversionTrackingContracts).where(and32(eq40(conversionTrackingContracts.projectId, project.id), eq40(conversionTrackingContracts.name, body.name))).get();
41930
41953
  if (duplicate) throw alreadyExists("Conversion tracking contract", body.name);
41931
41954
  const now = (/* @__PURE__ */ new Date()).toISOString();
41932
41955
  const contract = {
@@ -41951,7 +41974,7 @@ async function googleMarketingRoutes(app, opts) {
41951
41974
  });
41952
41975
  app.get("/projects/:name/conversion-tracking/contracts/:contractId", async (request) => {
41953
41976
  const project = resolveProject(app.db, request.params.name);
41954
- const row = app.db.select().from(conversionTrackingContracts).where(and31(
41977
+ const row = app.db.select().from(conversionTrackingContracts).where(and32(
41955
41978
  eq40(conversionTrackingContracts.projectId, project.id),
41956
41979
  eq40(conversionTrackingContracts.id, request.params.contractId)
41957
41980
  )).get();
@@ -41964,12 +41987,12 @@ async function googleMarketingRoutes(app, opts) {
41964
41987
  parseBody2(conversionTrackingContractWriteRequestSchema, request.body, "conversion tracking contract")
41965
41988
  );
41966
41989
  const project = resolveProject(app.db, request.params.name);
41967
- const existing = app.db.select().from(conversionTrackingContracts).where(and31(
41990
+ const existing = app.db.select().from(conversionTrackingContracts).where(and32(
41968
41991
  eq40(conversionTrackingContracts.projectId, project.id),
41969
41992
  eq40(conversionTrackingContracts.id, request.params.contractId)
41970
41993
  )).get();
41971
41994
  if (!existing) throw notFound("Conversion tracking contract", request.params.contractId);
41972
- const duplicate = app.db.select({ id: conversionTrackingContracts.id }).from(conversionTrackingContracts).where(and31(
41995
+ const duplicate = app.db.select({ id: conversionTrackingContracts.id }).from(conversionTrackingContracts).where(and32(
41973
41996
  eq40(conversionTrackingContracts.projectId, project.id),
41974
41997
  eq40(conversionTrackingContracts.name, body.name),
41975
41998
  ne4(conversionTrackingContracts.id, existing.id)
@@ -42006,7 +42029,7 @@ async function googleMarketingRoutes(app, opts) {
42006
42029
  app.delete("/projects/:name/conversion-tracking/contracts/:contractId", async (request, reply) => {
42007
42030
  requireWrite(request);
42008
42031
  const project = resolveProject(app.db, request.params.name);
42009
- const existing = app.db.select().from(conversionTrackingContracts).where(and31(
42032
+ const existing = app.db.select().from(conversionTrackingContracts).where(and32(
42010
42033
  eq40(conversionTrackingContracts.projectId, project.id),
42011
42034
  eq40(conversionTrackingContracts.id, request.params.contractId)
42012
42035
  )).get();
@@ -42026,7 +42049,7 @@ async function googleMarketingRoutes(app, opts) {
42026
42049
  });
42027
42050
  app.get("/projects/:name/conversion-tracking/contracts/:contractId/integrity", async (request) => {
42028
42051
  const project = resolveProject(app.db, request.params.name);
42029
- const row = app.db.select().from(conversionTrackingContracts).where(and31(
42052
+ const row = app.db.select().from(conversionTrackingContracts).where(and32(
42030
42053
  eq40(conversionTrackingContracts.projectId, project.id),
42031
42054
  eq40(conversionTrackingContracts.id, request.params.contractId)
42032
42055
  )).get();
@@ -42061,11 +42084,11 @@ async function googleMarketingRoutes(app, opts) {
42061
42084
 
42062
42085
  // ../api-routes/src/ads.ts
42063
42086
  import crypto34 from "crypto";
42064
- import { eq as eq42, and as and33, asc as asc8, desc as desc19, gt as gt2, gte as gte9, lt as lt7, lte as lte8, ne as ne5, inArray as inArray17, or as or10, isNull as isNull4, isNotNull as isNotNull2, sql as sql16 } from "drizzle-orm";
42087
+ import { eq as eq42, and as and34, asc as asc8, desc as desc19, gt as gt2, gte as gte9, lt as lt7, lte as lte8, ne as ne5, inArray as inArray17, or as or10, isNull as isNull4, isNotNull as isNotNull2, sql as sql17 } from "drizzle-orm";
42065
42088
 
42066
42089
  // ../api-routes/src/ads-activation-routes.ts
42067
42090
  import crypto33 from "crypto";
42068
- import { and as and32, asc as asc7, eq as eq41, gt, isNotNull, isNull as isNull3, lte as lte7, or as or9, sql as sql15 } from "drizzle-orm";
42091
+ import { and as and33, asc as asc7, eq as eq41, gt, isNotNull, isNull as isNull3, lte as lte7, or as or9, sql as sql16 } from "drizzle-orm";
42069
42092
 
42070
42093
  // ../api-routes/src/ads-activation.ts
42071
42094
  import crypto32 from "crypto";
@@ -43498,7 +43521,7 @@ function createActivationStore(app, request) {
43498
43521
  const bindingRejection = validateGrantBinding(grantRow, input);
43499
43522
  if (bindingRejection) return bindingRejection;
43500
43523
  const grant = grantRow;
43501
- const existing = tx.select().from(adsOperations).where(and32(
43524
+ const existing = tx.select().from(adsOperations).where(and33(
43502
43525
  eq41(adsOperations.projectId, input.projectId),
43503
43526
  eq41(adsOperations.operationKey, input.operationKey)
43504
43527
  )).get();
@@ -43523,7 +43546,7 @@ function createActivationStore(app, request) {
43523
43546
  leaseOwner: input.leaseOwner,
43524
43547
  leaseExpiresAt: input.leaseExpiresAt,
43525
43548
  updatedAt: input.now
43526
- }).where(and32(
43549
+ }).where(and33(
43527
43550
  eq41(adsOperations.id, existing.id),
43528
43551
  eq41(adsOperations.state, AdsOperationStates.pending),
43529
43552
  or9(
@@ -43545,7 +43568,7 @@ function createActivationStore(app, request) {
43545
43568
  state: AdsActivationGrantStates.expired,
43546
43569
  expiredAt: input.now,
43547
43570
  updatedAt: input.now
43548
- }).where(and32(
43571
+ }).where(and33(
43549
43572
  eq41(adsActivationGrants.id, grant.id),
43550
43573
  eq41(adsActivationGrants.state, AdsActivationGrantStates.approved)
43551
43574
  )).run();
@@ -43581,7 +43604,7 @@ function createActivationStore(app, request) {
43581
43604
  operationId: input.operationId,
43582
43605
  executionStartedAt: input.now,
43583
43606
  updatedAt: input.now
43584
- }).where(and32(
43607
+ }).where(and33(
43585
43608
  eq41(adsActivationGrants.id, grant.id),
43586
43609
  eq41(adsActivationGrants.projectId, input.projectId),
43587
43610
  eq41(adsActivationGrants.adAccountId, input.adAccountId),
@@ -43617,7 +43640,7 @@ function createActivationStore(app, request) {
43617
43640
  const changed = tx.update(adsOperations).set({
43618
43641
  leaseExpiresAt: input.leaseExpiresAt,
43619
43642
  updatedAt: input.now
43620
- }).where(and32(
43643
+ }).where(and33(
43621
43644
  eq41(adsOperations.id, input.operationId),
43622
43645
  eq41(adsOperations.state, AdsOperationStates.pending),
43623
43646
  eq41(adsOperations.leaseOwner, input.leaseOwner),
@@ -43632,7 +43655,7 @@ function createActivationStore(app, request) {
43632
43655
  leaseOwner: null,
43633
43656
  leaseExpiresAt: null,
43634
43657
  updatedAt: input.now
43635
- }).where(and32(
43658
+ }).where(and33(
43636
43659
  eq41(adsOperations.id, input.operationId),
43637
43660
  eq41(adsOperations.state, AdsOperationStates.pending),
43638
43661
  eq41(adsOperations.leaseOwner, input.leaseOwner)
@@ -43645,7 +43668,7 @@ function createActivationStore(app, request) {
43645
43668
  if (input.fromState !== AdsOperationStepStates.pending || input.next.state !== AdsOperationStepStates.executing) {
43646
43669
  throw internalError("Ads activation forward authorization transition is invalid");
43647
43670
  }
43648
- const grant = tx.select().from(adsActivationGrants).where(and32(
43671
+ const grant = tx.select().from(adsActivationGrants).where(and33(
43649
43672
  eq41(adsActivationGrants.id, input.grantId),
43650
43673
  eq41(adsActivationGrants.operationId, input.operationId)
43651
43674
  )).get();
@@ -43661,7 +43684,7 @@ function createActivationStore(app, request) {
43661
43684
  if (!Number.isFinite(expiresAt) || expiresAt <= Date.parse(input.now)) {
43662
43685
  return { applied: false, operation, rejection: "expired" };
43663
43686
  }
43664
- const existing = tx.select().from(adsOperationSteps).where(and32(
43687
+ const existing = tx.select().from(adsOperationSteps).where(and33(
43665
43688
  eq41(adsOperationSteps.id, input.next.id),
43666
43689
  eq41(adsOperationSteps.operationId, input.operationId)
43667
43690
  )).get();
@@ -43673,7 +43696,7 @@ function createActivationStore(app, request) {
43673
43696
  const lease = tx.update(adsOperations).set({
43674
43697
  leaseExpiresAt: input.leaseExpiresAt,
43675
43698
  updatedAt: input.next.updatedAt
43676
- }).where(and32(
43699
+ }).where(and33(
43677
43700
  eq41(adsOperations.id, input.operationId),
43678
43701
  eq41(adsOperations.state, AdsOperationStates.pending),
43679
43702
  eq41(adsOperations.leaseOwner, input.leaseOwner),
@@ -43693,7 +43716,7 @@ function createActivationStore(app, request) {
43693
43716
  startedAt: input.next.startedAt,
43694
43717
  finishedAt: input.next.finishedAt,
43695
43718
  updatedAt: input.next.updatedAt
43696
- }).where(and32(
43719
+ }).where(and33(
43697
43720
  eq41(adsOperationSteps.id, input.next.id),
43698
43721
  eq41(adsOperationSteps.operationId, input.operationId),
43699
43722
  eq41(adsOperationSteps.state, input.fromState)
@@ -43703,7 +43726,7 @@ function createActivationStore(app, request) {
43703
43726
  return { applied: changed.changes === 1, operation: current };
43704
43727
  }, { behavior: "immediate" }),
43705
43728
  transitionStep: async (input) => app.db.transaction((tx) => {
43706
- const existing = tx.select().from(adsOperationSteps).where(and32(
43729
+ const existing = tx.select().from(adsOperationSteps).where(and33(
43707
43730
  eq41(adsOperationSteps.id, input.next.id),
43708
43731
  eq41(adsOperationSteps.operationId, input.operationId)
43709
43732
  )).get();
@@ -43715,7 +43738,7 @@ function createActivationStore(app, request) {
43715
43738
  const lease = tx.update(adsOperations).set({
43716
43739
  leaseExpiresAt: input.leaseExpiresAt,
43717
43740
  updatedAt: input.next.updatedAt
43718
- }).where(and32(
43741
+ }).where(and33(
43719
43742
  eq41(adsOperations.id, input.operationId),
43720
43743
  eq41(adsOperations.state, AdsOperationStates.pending),
43721
43744
  eq41(adsOperations.leaseOwner, input.leaseOwner),
@@ -43735,7 +43758,7 @@ function createActivationStore(app, request) {
43735
43758
  startedAt: input.next.startedAt,
43736
43759
  finishedAt: input.next.finishedAt,
43737
43760
  updatedAt: input.next.updatedAt
43738
- }).where(and32(
43761
+ }).where(and33(
43739
43762
  eq41(adsOperationSteps.id, input.next.id),
43740
43763
  eq41(adsOperationSteps.operationId, input.operationId),
43741
43764
  eq41(adsOperationSteps.state, input.fromState)
@@ -43745,7 +43768,7 @@ function createActivationStore(app, request) {
43745
43768
  return { applied: changed.changes === 1, operation };
43746
43769
  }, { behavior: "immediate" }),
43747
43770
  finishOperation: async (input) => app.db.transaction((tx) => {
43748
- const currentGrant = tx.select().from(adsActivationGrants).where(and32(
43771
+ const currentGrant = tx.select().from(adsActivationGrants).where(and33(
43749
43772
  eq41(adsActivationGrants.id, input.grantId),
43750
43773
  eq41(adsActivationGrants.operationId, input.operationId)
43751
43774
  )).get();
@@ -43766,7 +43789,7 @@ function createActivationStore(app, request) {
43766
43789
  );
43767
43790
  }
43768
43791
  const effectiveGrantState = input.operationState === AdsOperationStates.unknown ? AdsActivationGrantStates.unknown : input.grantState;
43769
- const campaignStep = tx.select().from(adsOperationSteps).where(and32(
43792
+ const campaignStep = tx.select().from(adsOperationSteps).where(and33(
43770
43793
  eq41(adsOperationSteps.operationId, input.operationId),
43771
43794
  eq41(adsOperationSteps.entityType, AdsActivationEntityTypes.campaign)
43772
43795
  )).get();
@@ -43778,7 +43801,7 @@ function createActivationStore(app, request) {
43778
43801
  leaseOwner: null,
43779
43802
  leaseExpiresAt: null,
43780
43803
  updatedAt: input.now
43781
- }).where(and32(
43804
+ }).where(and33(
43782
43805
  eq41(adsOperations.id, input.operationId),
43783
43806
  eq41(adsOperations.state, AdsOperationStates.pending),
43784
43807
  eq41(adsOperations.leaseOwner, input.leaseOwner),
@@ -43789,7 +43812,7 @@ function createActivationStore(app, request) {
43789
43812
  state: effectiveGrantState,
43790
43813
  consumedAt: effectiveGrantState === AdsActivationGrantStates.consumed ? input.now : null,
43791
43814
  updatedAt: input.now
43792
- }).where(and32(
43815
+ }).where(and33(
43793
43816
  eq41(adsActivationGrants.id, input.grantId),
43794
43817
  eq41(adsActivationGrants.operationId, input.operationId),
43795
43818
  eq41(adsActivationGrants.state, AdsActivationGrantStates.executing)
@@ -43924,21 +43947,21 @@ function selectWatchdogOperations(app, nowIso, batchSize, allowLiveRevocationLea
43924
43947
  );
43925
43948
  const eligibleState = allowLiveRevocationLease ? or9(
43926
43949
  eq41(adsOperations.state, AdsOperationStates.unknown),
43927
- and32(
43950
+ and33(
43928
43951
  eq41(adsOperations.state, AdsOperationStates.pending),
43929
43952
  or9(
43930
43953
  isNotNull(adsActivationGrants.revocationRequestedAt),
43931
- and32(leaseAvailable, campaignHasMutationEvidence)
43954
+ and33(leaseAvailable, campaignHasMutationEvidence)
43932
43955
  )
43933
43956
  )
43934
- ) : and32(
43957
+ ) : and33(
43935
43958
  or9(
43936
43959
  eq41(adsOperations.state, AdsOperationStates.unknown),
43937
43960
  eq41(adsOperations.state, AdsOperationStates.pending)
43938
43961
  ),
43939
43962
  leaseAvailable
43940
43963
  );
43941
- const freshRevocationPriority = sql15`CASE
43964
+ const freshRevocationPriority = sql16`CASE
43942
43965
  WHEN ${adsActivationGrants.revocationRequestedAt} IS NOT NULL
43943
43966
  AND (
43944
43967
  ${adsOperations.lastReconciledAt} IS NULL
@@ -43953,11 +43976,11 @@ function selectWatchdogOperations(app, nowIso, batchSize, allowLiveRevocationLea
43953
43976
  eq41(adsActivationGrants.operationId, adsOperations.id)
43954
43977
  ).leftJoin(
43955
43978
  adsOperationSteps,
43956
- and32(
43979
+ and33(
43957
43980
  eq41(adsOperationSteps.operationId, adsOperations.id),
43958
43981
  eq41(adsOperationSteps.entityType, AdsActivationEntityTypes.campaign)
43959
43982
  )
43960
- ).where(and32(
43983
+ ).where(and33(
43961
43984
  eq41(adsOperations.kind, AdsOperationKinds.campaign_tree_activate),
43962
43985
  eligibleState
43963
43986
  )).orderBy(
@@ -43984,7 +44007,7 @@ function finalizeContainedRevokedUnknownActivation(app, operation, grant) {
43984
44007
  leaseExpiresAt: null,
43985
44008
  lastReconciledAt: nowIso,
43986
44009
  updatedAt: nowIso
43987
- }).where(and32(
44010
+ }).where(and33(
43988
44011
  eq41(adsOperations.id, operation.id),
43989
44012
  eq41(adsOperations.state, AdsOperationStates.unknown)
43990
44013
  )).run();
@@ -43993,7 +44016,7 @@ function finalizeContainedRevokedUnknownActivation(app, operation, grant) {
43993
44016
  state: AdsActivationGrantStates.consumed,
43994
44017
  consumedAt: nowIso,
43995
44018
  updatedAt: nowIso
43996
- }).where(and32(
44019
+ }).where(and33(
43997
44020
  eq41(adsActivationGrants.id, grant.id),
43998
44021
  eq41(adsActivationGrants.operationId, operation.id),
43999
44022
  eq41(adsActivationGrants.state, AdsActivationGrantStates.unknown),
@@ -44074,7 +44097,7 @@ async function containUrgentAdsActivationCampaignsOnce(app, opts) {
44074
44097
  }
44075
44098
  app.db.update(adsOperations).set({
44076
44099
  lastReconciledAt: (/* @__PURE__ */ new Date()).toISOString()
44077
- }).where(and32(
44100
+ }).where(and33(
44078
44101
  eq41(adsOperations.id, operation.id),
44079
44102
  or9(
44080
44103
  eq41(adsOperations.state, AdsOperationStates.unknown),
@@ -44100,11 +44123,11 @@ async function sweepStaleAdsActivationsOnce(app, opts) {
44100
44123
  leaseOwner: null,
44101
44124
  leaseExpiresAt: null,
44102
44125
  updatedAt: nowIso
44103
- }).where(and32(
44126
+ }).where(and33(
44104
44127
  eq41(adsOperations.id, operation.id),
44105
44128
  or9(
44106
44129
  eq41(adsOperations.state, AdsOperationStates.unknown),
44107
- and32(
44130
+ and33(
44108
44131
  eq41(adsOperations.state, AdsOperationStates.pending),
44109
44132
  or9(
44110
44133
  isNull3(adsOperations.leaseOwner),
@@ -44118,7 +44141,7 @@ async function sweepStaleAdsActivationsOnce(app, opts) {
44118
44141
  tx.update(adsActivationGrants).set({
44119
44142
  state: AdsActivationGrantStates.unknown,
44120
44143
  updatedAt: nowIso
44121
- }).where(and32(
44144
+ }).where(and33(
44122
44145
  eq41(adsActivationGrants.id, grant.id),
44123
44146
  eq41(adsActivationGrants.operationId, operation.id),
44124
44147
  eq41(adsActivationGrants.state, AdsActivationGrantStates.executing)
@@ -44137,11 +44160,11 @@ async function sweepStaleAdsActivationsOnce(app, opts) {
44137
44160
  }));
44138
44161
  const markRecoveryIncomplete = (operation) => {
44139
44162
  const failedAt = (/* @__PURE__ */ new Date()).toISOString();
44140
- app.db.update(adsOperations).set({ updatedAt: failedAt }).where(and32(
44163
+ app.db.update(adsOperations).set({ updatedAt: failedAt }).where(and33(
44141
44164
  eq41(adsOperations.id, operation.id),
44142
44165
  or9(
44143
44166
  eq41(adsOperations.state, AdsOperationStates.unknown),
44144
- and32(
44167
+ and33(
44145
44168
  eq41(adsOperations.state, AdsOperationStates.pending),
44146
44169
  or9(
44147
44170
  isNull3(adsOperations.leaseOwner),
@@ -44180,7 +44203,7 @@ async function sweepStaleAdsActivationsOnce(app, opts) {
44180
44203
  lastReconciledAt: (/* @__PURE__ */ new Date()).toISOString(),
44181
44204
  errorMessage: safety.fullyVerified ? "Unknown activation was safety-paused; manual remediation is still required" : "Unknown activation safety pause could not be fully verified",
44182
44205
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
44183
- }).where(and32(
44206
+ }).where(and33(
44184
44207
  eq41(adsOperations.id, operation.id),
44185
44208
  eq41(adsOperations.state, AdsOperationStates.unknown)
44186
44209
  )).run();
@@ -44342,13 +44365,13 @@ function registerAdsActivationRoutes(app, opts) {
44342
44365
  adsActivationGrantRevokeRequestSchema,
44343
44366
  request.body === void 0 ? {} : request.body
44344
44367
  );
44345
- const existing = app.db.select().from(adsActivationGrants).where(and32(
44368
+ const existing = app.db.select().from(adsActivationGrants).where(and33(
44346
44369
  eq41(adsActivationGrants.id, request.params.grantId),
44347
44370
  eq41(adsActivationGrants.projectId, project.id)
44348
44371
  )).get();
44349
44372
  if (!existing) throw notFound("Ads activation grant", request.params.grantId);
44350
44373
  const grant = app.db.transaction((tx) => {
44351
- const current = tx.select().from(adsActivationGrants).where(and32(
44374
+ const current = tx.select().from(adsActivationGrants).where(and33(
44352
44375
  eq41(adsActivationGrants.id, request.params.grantId),
44353
44376
  eq41(adsActivationGrants.projectId, project.id)
44354
44377
  )).get();
@@ -44369,7 +44392,7 @@ function registerAdsActivationRoutes(app, opts) {
44369
44392
  tx.update(adsActivationGrants).set({
44370
44393
  revocationRequestedAt: nowIso,
44371
44394
  updatedAt: nowIso
44372
- }).where(and32(
44395
+ }).where(and33(
44373
44396
  eq41(adsActivationGrants.id, current.id),
44374
44397
  eq41(adsActivationGrants.state, current.state),
44375
44398
  isNull3(adsActivationGrants.revocationRequestedAt)
@@ -44380,7 +44403,7 @@ function registerAdsActivationRoutes(app, opts) {
44380
44403
  revokedAt: expired ? null : nowIso,
44381
44404
  expiredAt: expired ? nowIso : null,
44382
44405
  updatedAt: nowIso
44383
- }).where(and32(
44406
+ }).where(and33(
44384
44407
  eq41(adsActivationGrants.id, current.id),
44385
44408
  eq41(adsActivationGrants.state, AdsActivationGrantStates.approved)
44386
44409
  )).run();
@@ -44410,7 +44433,7 @@ function registerAdsActivationRoutes(app, opts) {
44410
44433
  const executor = requireAuthenticatedKey(request);
44411
44434
  const project = resolveProject(app.db, request.params.name);
44412
44435
  const body = parseBody3(adsActivateTreeRequestSchema, request.body);
44413
- const grant = app.db.select().from(adsActivationGrants).where(and32(
44436
+ const grant = app.db.select().from(adsActivationGrants).where(and33(
44414
44437
  eq41(adsActivationGrants.id, body.grantId),
44415
44438
  eq41(adsActivationGrants.projectId, project.id)
44416
44439
  )).get();
@@ -44454,14 +44477,14 @@ function registerAdsActivationRoutes(app, opts) {
44454
44477
  if (request.body !== void 0) {
44455
44478
  throw validationError("Ads activation recovery does not accept a request body");
44456
44479
  }
44457
- const operation = app.db.select().from(adsOperations).where(and32(
44480
+ const operation = app.db.select().from(adsOperations).where(and33(
44458
44481
  eq41(adsOperations.projectId, project.id),
44459
44482
  eq41(adsOperations.operationKey, request.params.operationKey)
44460
44483
  )).get();
44461
44484
  if (!operation || operation.kind !== AdsOperationKinds.campaign_tree_activate) {
44462
44485
  throw notFound("Ads activation operation", request.params.operationKey);
44463
44486
  }
44464
- const grant = app.db.select().from(adsActivationGrants).where(and32(
44487
+ const grant = app.db.select().from(adsActivationGrants).where(and33(
44465
44488
  eq41(adsActivationGrants.projectId, project.id),
44466
44489
  eq41(adsActivationGrants.operationId, operation.id)
44467
44490
  )).get();
@@ -45004,7 +45027,7 @@ function semanticallyMatchesMaterializedEntity(app, input) {
45004
45027
  return AdsOperationKinds.ad_update;
45005
45028
  }
45006
45029
  })();
45007
- const rows = app.db.select().from(adsOperations).where(and33(
45030
+ const rows = app.db.select().from(adsOperations).where(and34(
45008
45031
  eq42(adsOperations.projectId, input.projectId),
45009
45032
  eq42(adsOperations.entityType, input.entityType),
45010
45033
  eq42(adsOperations.entityId, input.entityId),
@@ -45193,7 +45216,7 @@ async function executeAdsOperation(app, request, input) {
45193
45216
  }).onConflictDoNothing({
45194
45217
  target: [adsOperations.projectId, adsOperations.operationKey]
45195
45218
  }).returning({ id: adsOperations.id }).all();
45196
- const canonical = app.db.select().from(adsOperations).where(and33(
45219
+ const canonical = app.db.select().from(adsOperations).where(and34(
45197
45220
  eq42(adsOperations.projectId, input.projectId),
45198
45221
  eq42(adsOperations.operationKey, input.operationKey)
45199
45222
  )).get();
@@ -45213,7 +45236,7 @@ async function executeAdsOperation(app, request, input) {
45213
45236
  entityId: result.id,
45214
45237
  upstreamUpdatedAt: result.updatedAt ?? null,
45215
45238
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
45216
- }).where(and33(
45239
+ }).where(and34(
45217
45240
  eq42(adsOperations.id, id),
45218
45241
  eq42(adsOperations.state, AdsOperationStates.pending),
45219
45242
  isNull4(adsOperations.leaseOwner)
@@ -45234,7 +45257,7 @@ async function executeAdsOperation(app, request, input) {
45234
45257
  errorCode: null,
45235
45258
  errorMessage: null,
45236
45259
  updatedAt
45237
- }).where(and33(
45260
+ }).where(and34(
45238
45261
  eq42(adsOperations.id, id),
45239
45262
  eq42(adsOperations.state, AdsOperationStates.pending),
45240
45263
  isNull4(adsOperations.leaseOwner)
@@ -45263,7 +45286,7 @@ async function executeAdsOperation(app, request, input) {
45263
45286
  errorCode: failure.code,
45264
45287
  errorMessage: failure.message,
45265
45288
  updatedAt
45266
- }).where(and33(
45289
+ }).where(and34(
45267
45290
  eq42(adsOperations.id, id),
45268
45291
  eq42(adsOperations.state, AdsOperationStates.pending),
45269
45292
  isNull4(adsOperations.leaseOwner)
@@ -45281,7 +45304,7 @@ async function executeAdsOperation(app, request, input) {
45281
45304
  return update.changes > 0;
45282
45305
  });
45283
45306
  if (!finalized) {
45284
- const canonical2 = app.db.select().from(adsOperations).where(and33(
45307
+ const canonical2 = app.db.select().from(adsOperations).where(and34(
45285
45308
  eq42(adsOperations.id, id),
45286
45309
  eq42(adsOperations.projectId, input.projectId)
45287
45310
  )).get();
@@ -45298,7 +45321,7 @@ async function executeAdsOperation(app, request, input) {
45298
45321
  }
45299
45322
  }
45300
45323
  function readOperationByKey(app, projectId, operationKey) {
45301
- return app.db.select().from(adsOperations).where(and33(
45324
+ return app.db.select().from(adsOperations).where(and34(
45302
45325
  eq42(adsOperations.projectId, projectId),
45303
45326
  eq42(adsOperations.operationKey, operationKey)
45304
45327
  )).get();
@@ -45316,13 +45339,13 @@ function claimOperationForReconciliation(app, row, leaseOwner, now, leaseMs, pol
45316
45339
  const pendingCutoff = new Date(now.getTime() - policy.pendingMinIdleMs).toISOString();
45317
45340
  const backoffMs = policy.backoffBaseMs * 2 ** Math.max(0, row.reconcileAttempts - 1);
45318
45341
  const unknownCutoff = new Date(now.getTime() - backoffMs).toISOString();
45319
- const claimableState = row.state === AdsOperationStates.pending ? and33(
45342
+ const claimableState = row.state === AdsOperationStates.pending ? and34(
45320
45343
  eq42(adsOperations.state, AdsOperationStates.pending),
45321
45344
  lte8(adsOperations.updatedAt, pendingCutoff)
45322
- ) : row.state === AdsOperationStates.unknown ? and33(
45345
+ ) : row.state === AdsOperationStates.unknown ? and34(
45323
45346
  eq42(adsOperations.state, AdsOperationStates.unknown),
45324
45347
  enforceBackoff ? lte8(adsOperations.updatedAt, unknownCutoff) : void 0
45325
- ) : and33(
45348
+ ) : and34(
45326
45349
  eq42(adsOperations.state, AdsOperationStates.reconciling),
45327
45350
  or10(isNull4(adsOperations.leaseExpiresAt), lte8(adsOperations.leaseExpiresAt, nowIso))
45328
45351
  );
@@ -45330,9 +45353,9 @@ function claimOperationForReconciliation(app, row, leaseOwner, now, leaseMs, pol
45330
45353
  state: AdsOperationStates.reconciling,
45331
45354
  leaseOwner,
45332
45355
  leaseExpiresAt: leaseExpiresAt2,
45333
- reconcileAttempts: sql16`${adsOperations.reconcileAttempts} + 1`,
45356
+ reconcileAttempts: sql17`${adsOperations.reconcileAttempts} + 1`,
45334
45357
  updatedAt: nowIso
45335
- }).where(and33(
45358
+ }).where(and34(
45336
45359
  eq42(adsOperations.id, row.id),
45337
45360
  eq42(adsOperations.projectId, row.projectId),
45338
45361
  eq42(adsOperations.reconcileAttempts, row.reconcileAttempts),
@@ -45386,7 +45409,7 @@ function finishReconciliation(app, row, leaseOwner, context, outcome, maxAttempt
45386
45409
  leaseOwner: null,
45387
45410
  leaseExpiresAt: null,
45388
45411
  updatedAt: now
45389
- }).where(and33(
45412
+ }).where(and34(
45390
45413
  eq42(adsOperations.id, row.id),
45391
45414
  eq42(adsOperations.projectId, row.projectId),
45392
45415
  eq42(adsOperations.leaseOwner, leaseOwner),
@@ -45399,7 +45422,7 @@ function finishReconciliation(app, row, leaseOwner, context, outcome, maxAttempt
45399
45422
  }));
45400
45423
  }
45401
45424
  });
45402
- const canonical = app.db.select().from(adsOperations).where(and33(
45425
+ const canonical = app.db.select().from(adsOperations).where(and34(
45403
45426
  eq42(adsOperations.id, row.id),
45404
45427
  eq42(adsOperations.projectId, row.projectId)
45405
45428
  )).get();
@@ -45441,7 +45464,7 @@ function quarantineExhaustedReconciliation(app, row, now, policy, context) {
45441
45464
  leaseOwner: null,
45442
45465
  leaseExpiresAt: null,
45443
45466
  updatedAt: nowIso
45444
- }).where(and33(
45467
+ }).where(and34(
45445
45468
  eq42(adsOperations.id, row.id),
45446
45469
  eq42(adsOperations.projectId, row.projectId),
45447
45470
  gte9(adsOperations.reconcileAttempts, policy.maxAttempts),
@@ -45640,32 +45663,32 @@ async function sweepAdsOperationsOnce(app, opts, config) {
45640
45663
  { length: config.policy.maxAttempts },
45641
45664
  (_, reconcileAttempts) => {
45642
45665
  const backoffMs = config.policy.backoffBaseMs * 2 ** Math.max(0, reconcileAttempts - 1);
45643
- return and33(
45666
+ return and34(
45644
45667
  eq42(adsOperations.reconcileAttempts, reconcileAttempts),
45645
45668
  lte8(adsOperations.updatedAt, new Date(now.getTime() - backoffMs).toISOString())
45646
45669
  );
45647
45670
  }
45648
45671
  );
45649
45672
  const retryableStateWhere = or10(
45650
- and33(
45673
+ and34(
45651
45674
  eq42(adsOperations.state, AdsOperationStates.pending),
45652
45675
  lte8(adsOperations.updatedAt, pendingCutoff)
45653
45676
  ),
45654
- and33(
45677
+ and34(
45655
45678
  eq42(adsOperations.state, AdsOperationStates.unknown),
45656
45679
  or10(...unknownRetryWindows)
45657
45680
  ),
45658
- and33(
45681
+ and34(
45659
45682
  eq42(adsOperations.state, AdsOperationStates.reconciling),
45660
45683
  or10(isNull4(adsOperations.leaseExpiresAt), lte8(adsOperations.leaseExpiresAt, nowIso))
45661
45684
  )
45662
45685
  );
45663
- const staleReconcileWhere = and33(
45686
+ const staleReconcileWhere = and34(
45664
45687
  lt7(adsOperations.reconcileAttempts, config.policy.maxAttempts),
45665
45688
  ne5(adsOperations.kind, AdsOperationKinds.campaign_tree_activate),
45666
45689
  or10(
45667
45690
  eq42(adsOperations.reconcileStrategy, AdsReconcileStrategies.known_entity),
45668
- and33(
45691
+ and34(
45669
45692
  eq42(adsOperations.reconcileStrategy, AdsReconcileStrategies.create_fingerprint),
45670
45693
  or10(
45671
45694
  isNotNull2(adsOperations.entityId),
@@ -45678,16 +45701,16 @@ async function sweepAdsOperationsOnce(app, opts, config) {
45678
45701
  ),
45679
45702
  retryableStateWhere
45680
45703
  );
45681
- const exhaustedRows = app.db.select().from(adsOperations).where(and33(
45704
+ const exhaustedRows = app.db.select().from(adsOperations).where(and34(
45682
45705
  ne5(adsOperations.kind, AdsOperationKinds.campaign_tree_activate),
45683
45706
  gte9(adsOperations.reconcileAttempts, config.policy.maxAttempts),
45684
45707
  or10(
45685
- and33(
45708
+ and34(
45686
45709
  eq42(adsOperations.state, AdsOperationStates.pending),
45687
45710
  lte8(adsOperations.updatedAt, pendingCutoff)
45688
45711
  ),
45689
45712
  eq42(adsOperations.state, AdsOperationStates.unknown),
45690
- and33(
45713
+ and34(
45691
45714
  eq42(adsOperations.state, AdsOperationStates.reconciling),
45692
45715
  or10(isNull4(adsOperations.leaseExpiresAt), lte8(adsOperations.leaseExpiresAt, nowIso))
45693
45716
  )
@@ -45716,7 +45739,7 @@ async function sweepAdsOperationsOnce(app, opts, config) {
45716
45739
  }
45717
45740
  const eligibleProjectIds = [...credentialsByProjectId.keys()];
45718
45741
  if (eligibleProjectIds.length === 0) return;
45719
- const rows = app.db.select().from(adsOperations).where(and33(
45742
+ const rows = app.db.select().from(adsOperations).where(and34(
45720
45743
  inArray17(adsOperations.projectId, eligibleProjectIds),
45721
45744
  staleReconcileWhere
45722
45745
  )).orderBy(asc8(adsOperations.updatedAt)).limit(config.batchSize).all();
@@ -46043,12 +46066,12 @@ async function adsRoutes(app, opts) {
46043
46066
  throw validationError("Invalid ads operation list query", { issues: parsed.error.issues });
46044
46067
  }
46045
46068
  const cursor = parsed.data.cursor ? decodeAdsOperationCursor(parsed.data.cursor, project.id, parsed.data.state) : void 0;
46046
- const rows = app.db.select().from(adsOperations).where(and33(
46069
+ const rows = app.db.select().from(adsOperations).where(and34(
46047
46070
  eq42(adsOperations.projectId, project.id),
46048
46071
  inArray17(adsOperations.state, parsed.data.state),
46049
46072
  cursor ? or10(
46050
46073
  gt2(adsOperations.createdAt, cursor.createdAt),
46051
- and33(
46074
+ and34(
46052
46075
  eq42(adsOperations.createdAt, cursor.createdAt),
46053
46076
  gt2(adsOperations.id, cursor.id)
46054
46077
  )
@@ -46092,7 +46115,7 @@ async function adsRoutes(app, opts) {
46092
46115
  "/projects/:name/ads/operations/:operationKey",
46093
46116
  async (request) => {
46094
46117
  const project = resolveProject(app.db, request.params.name);
46095
- const row = app.db.select().from(adsOperations).where(and33(
46118
+ const row = app.db.select().from(adsOperations).where(and34(
46096
46119
  eq42(adsOperations.projectId, project.id),
46097
46120
  eq42(adsOperations.operationKey, request.params.operationKey)
46098
46121
  )).get();
@@ -46389,7 +46412,7 @@ async function adsRoutes(app, opts) {
46389
46412
  if (!row) {
46390
46413
  throw validationError('No ads connection for this project. Run "canonry ads connect" first.');
46391
46414
  }
46392
- const inFlight = app.db.select({ id: runs.id, status: runs.status }).from(runs).where(and33(
46415
+ const inFlight = app.db.select({ id: runs.id, status: runs.status }).from(runs).where(and34(
46393
46416
  eq42(runs.projectId, project.id),
46394
46417
  eq42(runs.kind, RunKinds["ads-sync"]),
46395
46418
  inArray17(runs.status, [RunStatuses.queued, RunStatuses.running])
@@ -46486,7 +46509,7 @@ async function adsRoutes(app, opts) {
46486
46509
  if (entityId) conditions.push(eq42(adsInsightsDaily.entityId, entityId));
46487
46510
  if (from) conditions.push(gte9(adsInsightsDaily.date, from));
46488
46511
  if (to) conditions.push(lte8(adsInsightsDaily.date, to));
46489
- const rows = app.db.select().from(adsInsightsDaily).where(and33(...conditions)).orderBy(asc8(adsInsightsDaily.date)).all();
46512
+ const rows = app.db.select().from(adsInsightsDaily).where(and34(...conditions)).orderBy(asc8(adsInsightsDaily.date)).all();
46490
46513
  const conn = app.db.select().from(adsConnections).where(eq42(adsConnections.projectId, project.id)).get();
46491
46514
  const accountToday = adsAccountToday(conn?.timezone, (/* @__PURE__ */ new Date()).toISOString());
46492
46515
  const dtoRows = rows.map((row) => ({
@@ -46513,11 +46536,11 @@ async function adsRoutes(app, opts) {
46513
46536
  const entityRows = [...campaignRows, ...adGroupRows, ...adRows];
46514
46537
  const hasEntityWithoutSyncRunId = entityRows.some((row) => row.syncRunId === null);
46515
46538
  const entitySyncRunIds = new Set(entityRows.flatMap((row) => row.syncRunId === null ? [] : [row.syncRunId]));
46516
- const sourceSync = entitySyncRunIds.size === 1 ? app.db.select({ id: runs.id, kind: runs.kind, status: runs.status }).from(runs).where(and33(
46539
+ const sourceSync = entitySyncRunIds.size === 1 ? app.db.select({ id: runs.id, kind: runs.kind, status: runs.status }).from(runs).where(and34(
46517
46540
  eq42(runs.id, [...entitySyncRunIds][0]),
46518
46541
  eq42(runs.projectId, project.id)
46519
46542
  )).get() : void 0;
46520
- const latestAdsSync = app.db.select({ id: runs.id, kind: runs.kind, status: runs.status }).from(runs).where(and33(
46543
+ const latestAdsSync = app.db.select({ id: runs.id, kind: runs.kind, status: runs.status }).from(runs).where(and34(
46521
46544
  eq42(runs.projectId, project.id),
46522
46545
  eq42(runs.kind, RunKinds["ads-sync"])
46523
46546
  )).orderBy(desc19(runs.createdAt)).get();
@@ -46536,7 +46559,7 @@ async function adsRoutes(app, opts) {
46536
46559
  clicks: adsInsightsDaily.clicks,
46537
46560
  spendMicros: adsInsightsDaily.spendMicros,
46538
46561
  conversions: adsInsightsDaily.conversions
46539
- }).from(adsInsightsDaily).where(and33(
46562
+ }).from(adsInsightsDaily).where(and34(
46540
46563
  eq42(adsInsightsDaily.projectId, project.id),
46541
46564
  eq42(adsInsightsDaily.level, AdsInsightLevels.campaign)
46542
46565
  )).all();
@@ -46689,11 +46712,11 @@ async function adsRoutes(app, opts) {
46689
46712
  const scopedCampaigns = campaignId === void 0 ? liveCampaigns : liveCampaigns.filter((campaign) => campaign.id === campaignId);
46690
46713
  if (scopedCampaigns.length > ADS_LIVE_MAX_CAMPAIGNS) truncated = true;
46691
46714
  const walkedCampaigns = scopedCampaigns.slice(0, ADS_LIVE_MAX_CAMPAIGNS);
46692
- const storedCampaignRows = app.db.select().from(adsCampaigns).where(and33(
46715
+ const storedCampaignRows = app.db.select().from(adsCampaigns).where(and34(
46693
46716
  eq42(adsCampaigns.projectId, project.id),
46694
46717
  campaignId === void 0 ? void 0 : eq42(adsCampaigns.id, campaignId)
46695
46718
  )).all();
46696
- const storedAdGroupRows = app.db.select().from(adsAdGroups).where(and33(
46719
+ const storedAdGroupRows = app.db.select().from(adsAdGroups).where(and34(
46697
46720
  eq42(adsAdGroups.projectId, project.id),
46698
46721
  campaignId === void 0 ? void 0 : eq42(adsAdGroups.campaignId, campaignId)
46699
46722
  )).all();
@@ -46875,7 +46898,7 @@ async function adsRoutes(app, opts) {
46875
46898
  const campaignCount = app.db.select().from(adsCampaigns).where(eq42(adsCampaigns.projectId, project.id)).all().length;
46876
46899
  const adGroupCount = app.db.select().from(adsAdGroups).where(eq42(adsAdGroups.projectId, project.id)).all().length;
46877
46900
  const adCount = app.db.select().from(adsAds).where(eq42(adsAds.projectId, project.id)).all().length;
46878
- const campaignInsights = app.db.select().from(adsInsightsDaily).where(and33(
46901
+ const campaignInsights = app.db.select().from(adsInsightsDaily).where(and34(
46879
46902
  eq42(adsInsightsDaily.projectId, project.id),
46880
46903
  eq42(adsInsightsDaily.level, "campaign")
46881
46904
  )).all();
@@ -46924,7 +46947,7 @@ async function adsRoutes(app, opts) {
46924
46947
 
46925
46948
  // ../api-routes/src/bing.ts
46926
46949
  import crypto36 from "crypto";
46927
- import { eq as eq43, and as and34, desc as desc20 } from "drizzle-orm";
46950
+ import { eq as eq43, and as and35, desc as desc20 } from "drizzle-orm";
46928
46951
 
46929
46952
  // ../integration-bing/src/bing-client.ts
46930
46953
  import crypto35 from "crypto";
@@ -47444,7 +47467,7 @@ async function bingRoutes(app, opts) {
47444
47467
  requireConnectionStore();
47445
47468
  const project = resolveProject(app.db, request.params.name);
47446
47469
  const { url, limit } = request.query;
47447
- const whereClause = url ? and34(eq43(bingUrlInspections.projectId, project.id), eq43(bingUrlInspections.url, url)) : eq43(bingUrlInspections.projectId, project.id);
47470
+ const whereClause = url ? and35(eq43(bingUrlInspections.projectId, project.id), eq43(bingUrlInspections.url, url)) : eq43(bingUrlInspections.projectId, project.id);
47448
47471
  const filtered = app.db.select().from(bingUrlInspections).where(whereClause).orderBy(desc20(bingUrlInspections.inspectedAt)).limit(Math.max(1, Math.min(parseInt(limit ?? "100", 10) || 100, 1e3))).all();
47449
47472
  return filtered.map((r) => ({
47450
47473
  id: r.id,
@@ -47676,7 +47699,7 @@ async function bingRoutes(app, opts) {
47676
47699
  import fs from "fs";
47677
47700
  import path from "path";
47678
47701
  import os from "os";
47679
- import { eq as eq44, and as and35 } from "drizzle-orm";
47702
+ import { eq as eq44, and as and36 } from "drizzle-orm";
47680
47703
  function getScreenshotDir() {
47681
47704
  return path.join(os.homedir(), ".canonry", "screenshots");
47682
47705
  }
@@ -47751,7 +47774,7 @@ async function cdpRoutes(app, opts) {
47751
47774
  async (request, reply) => {
47752
47775
  const project = resolveProject(app.db, request.params.name);
47753
47776
  const { runId } = request.params;
47754
- const run = app.db.select().from(runs).where(and35(eq44(runs.id, runId), eq44(runs.projectId, project.id))).get();
47777
+ const run = app.db.select().from(runs).where(and36(eq44(runs.id, runId), eq44(runs.projectId, project.id))).get();
47755
47778
  if (!run) {
47756
47779
  const err = notFound("Run", runId);
47757
47780
  return reply.code(err.statusCode).send(err.toJSON());
@@ -47848,7 +47871,7 @@ async function cdpRoutes(app, opts) {
47848
47871
 
47849
47872
  // ../api-routes/src/ga.ts
47850
47873
  import crypto37 from "crypto";
47851
- import { eq as eq45, desc as desc21, and as and36, sql as sql17 } from "drizzle-orm";
47874
+ import { eq as eq45, desc as desc21, and as and37, sql as sql18 } from "drizzle-orm";
47852
47875
 
47853
47876
  // ../api-routes/src/ga-session-history.ts
47854
47877
  function buildSessionHistory(landingPageDays, dailyTotals) {
@@ -47993,8 +48016,8 @@ function formatSharePct(numerator, total) {
47993
48016
  }
47994
48017
  function dateRangeConditions(column, range) {
47995
48018
  const conditions = [];
47996
- if (range.startDate) conditions.push(sql17`${column} >= ${range.startDate}`);
47997
- if (range.endDate) conditions.push(sql17`${column} <= ${range.endDate}`);
48019
+ if (range.startDate) conditions.push(sql18`${column} >= ${range.startDate}`);
48020
+ if (range.endDate) conditions.push(sql18`${column} <= ${range.endDate}`);
47998
48021
  return conditions;
47999
48022
  }
48000
48023
  var SOCIAL_CHANNEL_GROUPS2 = /* @__PURE__ */ new Set(["Organic Social", "Paid Social"]);
@@ -48042,10 +48065,10 @@ function pickWinningDimension(rows, tupleKey) {
48042
48065
  function persistAcquisitionMeasurement(db, input) {
48043
48066
  const { startDate, endDate } = input.report;
48044
48067
  db.transaction((tx) => {
48045
- tx.delete(gaAcquisitionDaily).where(and36(
48068
+ tx.delete(gaAcquisitionDaily).where(and37(
48046
48069
  eq45(gaAcquisitionDaily.projectId, input.projectId),
48047
- sql17`${gaAcquisitionDaily.date} >= ${startDate}`,
48048
- sql17`${gaAcquisitionDaily.date} <= ${endDate}`
48070
+ sql18`${gaAcquisitionDaily.date} >= ${startDate}`,
48071
+ sql18`${gaAcquisitionDaily.date} <= ${endDate}`
48049
48072
  )).run();
48050
48073
  for (const row of input.report.rows) {
48051
48074
  tx.insert(gaAcquisitionDaily).values({
@@ -48084,10 +48107,10 @@ function persistAcquisitionMeasurement(db, input) {
48084
48107
  function persistLeadMeasurement(db, input) {
48085
48108
  const { startDate, endDate } = input.report;
48086
48109
  db.transaction((tx) => {
48087
- tx.delete(gaLeadEventsDaily).where(and36(
48110
+ tx.delete(gaLeadEventsDaily).where(and37(
48088
48111
  eq45(gaLeadEventsDaily.projectId, input.projectId),
48089
- sql17`${gaLeadEventsDaily.date} >= ${startDate}`,
48090
- sql17`${gaLeadEventsDaily.date} <= ${endDate}`
48112
+ sql18`${gaLeadEventsDaily.date} >= ${startDate}`,
48113
+ sql18`${gaLeadEventsDaily.date} <= ${endDate}`
48091
48114
  )).run();
48092
48115
  for (const row of input.report.rows) {
48093
48116
  tx.insert(gaLeadEventsDaily).values({
@@ -48460,10 +48483,10 @@ async function ga4Routes(app, opts) {
48460
48483
  app.db.transaction((tx) => {
48461
48484
  if (syncTraffic) {
48462
48485
  tx.delete(gaTrafficSnapshots).where(
48463
- and36(
48486
+ and37(
48464
48487
  eq45(gaTrafficSnapshots.projectId, project.id),
48465
- sql17`${gaTrafficSnapshots.date} >= ${summary.periodStart}`,
48466
- sql17`${gaTrafficSnapshots.date} <= ${summary.periodEnd}`
48488
+ sql18`${gaTrafficSnapshots.date} >= ${summary.periodStart}`,
48489
+ sql18`${gaTrafficSnapshots.date} <= ${summary.periodEnd}`
48467
48490
  )
48468
48491
  ).run();
48469
48492
  for (const row of rows) {
@@ -48483,10 +48506,10 @@ async function ga4Routes(app, opts) {
48483
48506
  }
48484
48507
  }
48485
48508
  tx.delete(gaDailyTotals).where(
48486
- and36(
48509
+ and37(
48487
48510
  eq45(gaDailyTotals.projectId, project.id),
48488
- sql17`${gaDailyTotals.date} >= ${summary.periodStart}`,
48489
- sql17`${gaDailyTotals.date} <= ${summary.periodEnd}`
48511
+ sql18`${gaDailyTotals.date} >= ${summary.periodStart}`,
48512
+ sql18`${gaDailyTotals.date} <= ${summary.periodEnd}`
48490
48513
  )
48491
48514
  ).run();
48492
48515
  for (const row of dailyTotals) {
@@ -48509,10 +48532,10 @@ async function ga4Routes(app, opts) {
48509
48532
  }
48510
48533
  if (syncAi) {
48511
48534
  tx.delete(gaAiReferrals).where(
48512
- and36(
48535
+ and37(
48513
48536
  eq45(gaAiReferrals.projectId, project.id),
48514
- sql17`${gaAiReferrals.date} >= ${summary.periodStart}`,
48515
- sql17`${gaAiReferrals.date} <= ${summary.periodEnd}`
48537
+ sql18`${gaAiReferrals.date} >= ${summary.periodStart}`,
48538
+ sql18`${gaAiReferrals.date} <= ${summary.periodEnd}`
48516
48539
  )
48517
48540
  ).run();
48518
48541
  for (const row of aiReferrals) {
@@ -48541,10 +48564,10 @@ async function ga4Routes(app, opts) {
48541
48564
  }
48542
48565
  if (syncSocial) {
48543
48566
  tx.delete(gaSocialReferrals).where(
48544
- and36(
48567
+ and37(
48545
48568
  eq45(gaSocialReferrals.projectId, project.id),
48546
- sql17`${gaSocialReferrals.date} >= ${summary.periodStart}`,
48547
- sql17`${gaSocialReferrals.date} <= ${summary.periodEnd}`
48569
+ sql18`${gaSocialReferrals.date} >= ${summary.periodStart}`,
48570
+ sql18`${gaSocialReferrals.date} <= ${summary.periodEnd}`
48548
48571
  )
48549
48572
  ).run();
48550
48573
  for (const row of socialReferrals) {
@@ -48713,7 +48736,7 @@ async function ga4Routes(app, opts) {
48713
48736
  totalDirectSessions: gaTrafficWindowSummaries.totalDirectSessions,
48714
48737
  totalUsers: gaTrafficWindowSummaries.totalUsers
48715
48738
  }).from(gaTrafficWindowSummaries).where(
48716
- and36(
48739
+ and37(
48717
48740
  eq45(gaTrafficWindowSummaries.projectId, project.id),
48718
48741
  eq45(gaTrafficWindowSummaries.windowKey, range.window)
48719
48742
  )
@@ -48726,9 +48749,9 @@ async function ga4Routes(app, opts) {
48726
48749
  totalUsers: gaTrafficSummaries.totalUsers
48727
48750
  }).from(gaTrafficSummaries).where(eq45(gaTrafficSummaries.projectId, project.id)).get();
48728
48751
  const retainedBounds = [
48729
- app.db.select({ min: sql17`MIN(${gaTrafficSnapshots.date})`, max: sql17`MAX(${gaTrafficSnapshots.date})` }).from(gaTrafficSnapshots).where(eq45(gaTrafficSnapshots.projectId, project.id)).get(),
48730
- app.db.select({ min: sql17`MIN(${gaAiReferrals.date})`, max: sql17`MAX(${gaAiReferrals.date})` }).from(gaAiReferrals).where(eq45(gaAiReferrals.projectId, project.id)).get(),
48731
- app.db.select({ min: sql17`MIN(${gaSocialReferrals.date})`, max: sql17`MAX(${gaSocialReferrals.date})` }).from(gaSocialReferrals).where(eq45(gaSocialReferrals.projectId, project.id)).get()
48752
+ app.db.select({ min: sql18`MIN(${gaTrafficSnapshots.date})`, max: sql18`MAX(${gaTrafficSnapshots.date})` }).from(gaTrafficSnapshots).where(eq45(gaTrafficSnapshots.projectId, project.id)).get(),
48753
+ app.db.select({ min: sql18`MIN(${gaAiReferrals.date})`, max: sql18`MAX(${gaAiReferrals.date})` }).from(gaAiReferrals).where(eq45(gaAiReferrals.projectId, project.id)).get(),
48754
+ app.db.select({ min: sql18`MIN(${gaSocialReferrals.date})`, max: sql18`MAX(${gaSocialReferrals.date})` }).from(gaSocialReferrals).where(eq45(gaSocialReferrals.projectId, project.id)).get()
48732
48755
  ];
48733
48756
  const retainedDates = retainedBounds.flatMap((bound) => [bound?.min, bound?.max]).filter((date) => Boolean(date));
48734
48757
  const projectSummaryCoversAll = Boolean(
@@ -48742,10 +48765,10 @@ async function ga4Routes(app, opts) {
48742
48765
  const socialConditions = [eq45(gaSocialReferrals.projectId, project.id), ...dateRangeConditions(gaSocialReferrals.date, measuredRange)];
48743
48766
  const snapshotTotalsRow = !denominatorRow ? (() => {
48744
48767
  const summed = app.db.select({
48745
- totalSessions: sql17`COALESCE(SUM(${gaTrafficSnapshots.sessions}), 0)`,
48746
- totalOrganicSessions: sql17`COALESCE(SUM(${gaTrafficSnapshots.organicSessions}), 0)`,
48747
- totalUsers: sql17`COALESCE(SUM(${gaTrafficSnapshots.users}), 0)`
48748
- }).from(gaTrafficSnapshots).where(and36(...snapshotConditions)).get();
48768
+ totalSessions: sql18`COALESCE(SUM(${gaTrafficSnapshots.sessions}), 0)`,
48769
+ totalOrganicSessions: sql18`COALESCE(SUM(${gaTrafficSnapshots.organicSessions}), 0)`,
48770
+ totalUsers: sql18`COALESCE(SUM(${gaTrafficSnapshots.users}), 0)`
48771
+ }).from(gaTrafficSnapshots).where(and37(...snapshotConditions)).get();
48749
48772
  return {
48750
48773
  totalSessions: summed?.totalSessions ?? 0,
48751
48774
  totalOrganicSessions: summed?.totalOrganicSessions ?? 0,
@@ -48757,35 +48780,35 @@ async function ga4Routes(app, opts) {
48757
48780
  })() : null;
48758
48781
  const summaryRow = denominatorRow ?? snapshotTotalsRow;
48759
48782
  const directTotalRow = windowSummaryRow ? { totalDirectSessions: windowSummaryRow.totalDirectSessions } : app.db.select({
48760
- totalDirectSessions: sql17`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)`
48761
- }).from(gaTrafficSnapshots).where(and36(...snapshotConditions)).get();
48783
+ totalDirectSessions: sql18`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)`
48784
+ }).from(gaTrafficSnapshots).where(and37(...snapshotConditions)).get();
48762
48785
  const rows = app.db.select({
48763
- landingPage: sql17`COALESCE(${gaTrafficSnapshots.landingPageNormalized}, ${gaTrafficSnapshots.landingPage})`,
48764
- sessions: sql17`SUM(${gaTrafficSnapshots.sessions})`,
48765
- organicSessions: sql17`SUM(${gaTrafficSnapshots.organicSessions})`,
48766
- directSessions: sql17`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)`,
48767
- users: sql17`SUM(${gaTrafficSnapshots.users})`
48768
- }).from(gaTrafficSnapshots).where(and36(...snapshotConditions)).groupBy(sql17`COALESCE(${gaTrafficSnapshots.landingPageNormalized}, ${gaTrafficSnapshots.landingPage})`).orderBy(sql17`SUM(${gaTrafficSnapshots.sessions}) DESC`).limit(limit).all();
48786
+ landingPage: sql18`COALESCE(${gaTrafficSnapshots.landingPageNormalized}, ${gaTrafficSnapshots.landingPage})`,
48787
+ sessions: sql18`SUM(${gaTrafficSnapshots.sessions})`,
48788
+ organicSessions: sql18`SUM(${gaTrafficSnapshots.organicSessions})`,
48789
+ directSessions: sql18`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)`,
48790
+ users: sql18`SUM(${gaTrafficSnapshots.users})`
48791
+ }).from(gaTrafficSnapshots).where(and37(...snapshotConditions)).groupBy(sql18`COALESCE(${gaTrafficSnapshots.landingPageNormalized}, ${gaTrafficSnapshots.landingPage})`).orderBy(sql18`SUM(${gaTrafficSnapshots.sessions}) DESC`).limit(limit).all();
48769
48792
  const aiReferralRows = app.db.select({
48770
48793
  source: gaAiReferrals.source,
48771
48794
  medium: gaAiReferrals.medium,
48772
48795
  trafficClass: gaAiReferrals.trafficClass,
48773
48796
  sourceDimension: gaAiReferrals.sourceDimension,
48774
- sessions: sql17`SUM(${gaAiReferrals.sessions})`
48775
- }).from(gaAiReferrals).where(and36(...aiConditions)).groupBy(gaAiReferrals.source, gaAiReferrals.medium, gaAiReferrals.trafficClass, gaAiReferrals.sourceDimension).all();
48797
+ sessions: sql18`SUM(${gaAiReferrals.sessions})`
48798
+ }).from(gaAiReferrals).where(and37(...aiConditions)).groupBy(gaAiReferrals.source, gaAiReferrals.medium, gaAiReferrals.trafficClass, gaAiReferrals.sourceDimension).all();
48776
48799
  const aiReferralLandingPageRows = app.db.select({
48777
48800
  source: gaAiReferrals.source,
48778
48801
  medium: gaAiReferrals.medium,
48779
48802
  trafficClass: gaAiReferrals.trafficClass,
48780
48803
  sourceDimension: gaAiReferrals.sourceDimension,
48781
- landingPage: sql17`COALESCE(${gaAiReferrals.landingPageNormalized}, ${gaAiReferrals.landingPage})`,
48782
- sessions: sql17`SUM(${gaAiReferrals.sessions})`
48783
- }).from(gaAiReferrals).where(and36(...aiConditions)).groupBy(
48804
+ landingPage: sql18`COALESCE(${gaAiReferrals.landingPageNormalized}, ${gaAiReferrals.landingPage})`,
48805
+ sessions: sql18`SUM(${gaAiReferrals.sessions})`
48806
+ }).from(gaAiReferrals).where(and37(...aiConditions)).groupBy(
48784
48807
  gaAiReferrals.source,
48785
48808
  gaAiReferrals.medium,
48786
48809
  gaAiReferrals.trafficClass,
48787
48810
  gaAiReferrals.sourceDimension,
48788
- sql17`COALESCE(${gaAiReferrals.landingPageNormalized}, ${gaAiReferrals.landingPage})`
48811
+ sql18`COALESCE(${gaAiReferrals.landingPageNormalized}, ${gaAiReferrals.landingPage})`
48789
48812
  ).all();
48790
48813
  const aiRowsForTotals = app.db.select({
48791
48814
  date: gaAiReferrals.date,
@@ -48795,7 +48818,7 @@ async function ga4Routes(app, opts) {
48795
48818
  sourceDimension: gaAiReferrals.sourceDimension,
48796
48819
  channelGroup: gaAiReferrals.channelGroup,
48797
48820
  sessions: gaAiReferrals.sessions
48798
- }).from(gaAiReferrals).where(and36(...aiConditions)).all();
48821
+ }).from(gaAiReferrals).where(and37(...aiConditions)).all();
48799
48822
  const aiReferrals = pickWinningDimension(
48800
48823
  aiReferralRows,
48801
48824
  (r) => `${r.source}\0${r.medium}\0${r.trafficClass}`
@@ -48809,13 +48832,13 @@ async function ga4Routes(app, opts) {
48809
48832
  source: gaSocialReferrals.source,
48810
48833
  medium: gaSocialReferrals.medium,
48811
48834
  channelGroup: gaSocialReferrals.channelGroup,
48812
- sessions: sql17`SUM(${gaSocialReferrals.sessions})`,
48813
- users: sql17`SUM(${gaSocialReferrals.users})`
48814
- }).from(gaSocialReferrals).where(and36(...socialConditions)).groupBy(gaSocialReferrals.source, gaSocialReferrals.medium, gaSocialReferrals.channelGroup).orderBy(sql17`SUM(${gaSocialReferrals.sessions}) DESC`).all();
48835
+ sessions: sql18`SUM(${gaSocialReferrals.sessions})`,
48836
+ users: sql18`SUM(${gaSocialReferrals.users})`
48837
+ }).from(gaSocialReferrals).where(and37(...socialConditions)).groupBy(gaSocialReferrals.source, gaSocialReferrals.medium, gaSocialReferrals.channelGroup).orderBy(sql18`SUM(${gaSocialReferrals.sessions}) DESC`).all();
48815
48838
  const socialTotals = app.db.select({
48816
- sessions: sql17`SUM(${gaSocialReferrals.sessions})`,
48817
- users: sql17`SUM(${gaSocialReferrals.users})`
48818
- }).from(gaSocialReferrals).where(and36(...socialConditions)).get();
48839
+ sessions: sql18`SUM(${gaSocialReferrals.sessions})`,
48840
+ users: sql18`SUM(${gaSocialReferrals.users})`
48841
+ }).from(gaSocialReferrals).where(and37(...socialConditions)).get();
48819
48842
  const latestSync = app.db.select({ syncedAt: gaTrafficSummaries.syncedAt }).from(gaTrafficSummaries).where(eq45(gaTrafficSummaries.projectId, project.id)).orderBy(desc21(gaTrafficSummaries.syncedAt)).limit(1).get();
48820
48843
  const total = summaryRow?.totalSessions ?? 0;
48821
48844
  const totalDirectSessions = directTotalRow?.totalDirectSessions ?? 0;
@@ -48931,17 +48954,17 @@ async function ga4Routes(app, opts) {
48931
48954
  source: gaAiReferrals.source,
48932
48955
  medium: gaAiReferrals.medium,
48933
48956
  trafficClass: gaAiReferrals.trafficClass,
48934
- landingPage: sql17`COALESCE(${gaAiReferrals.landingPageNormalized}, ${gaAiReferrals.landingPage})`,
48957
+ landingPage: sql18`COALESCE(${gaAiReferrals.landingPageNormalized}, ${gaAiReferrals.landingPage})`,
48935
48958
  sourceDimension: gaAiReferrals.sourceDimension,
48936
- sessions: sql17`SUM(${gaAiReferrals.sessions})`,
48937
- users: sql17`SUM(${gaAiReferrals.users})`
48938
- }).from(gaAiReferrals).where(and36(...conditions)).groupBy(
48959
+ sessions: sql18`SUM(${gaAiReferrals.sessions})`,
48960
+ users: sql18`SUM(${gaAiReferrals.users})`
48961
+ }).from(gaAiReferrals).where(and37(...conditions)).groupBy(
48939
48962
  gaAiReferrals.date,
48940
48963
  gaAiReferrals.source,
48941
48964
  gaAiReferrals.medium,
48942
48965
  gaAiReferrals.trafficClass,
48943
48966
  gaAiReferrals.sourceDimension,
48944
- sql17`COALESCE(${gaAiReferrals.landingPageNormalized}, ${gaAiReferrals.landingPage})`
48967
+ sql18`COALESCE(${gaAiReferrals.landingPageNormalized}, ${gaAiReferrals.landingPage})`
48945
48968
  ).orderBy(gaAiReferrals.date).all();
48946
48969
  return rows;
48947
48970
  });
@@ -48958,7 +48981,7 @@ async function ga4Routes(app, opts) {
48958
48981
  sourceDimension: gaAiReferrals.sourceDimension,
48959
48982
  channelGroup: gaAiReferrals.channelGroup,
48960
48983
  sessions: gaAiReferrals.sessions
48961
- }).from(gaAiReferrals).where(and36(...conditions)).all();
48984
+ }).from(gaAiReferrals).where(and37(...conditions)).all();
48962
48985
  return buildAiReferralDailySeries(rows);
48963
48986
  });
48964
48987
  app.get("/projects/:name/ga/social-referral-history", async (request, _reply) => {
@@ -48973,7 +48996,7 @@ async function ga4Routes(app, opts) {
48973
48996
  channelGroup: gaSocialReferrals.channelGroup,
48974
48997
  sessions: gaSocialReferrals.sessions,
48975
48998
  users: gaSocialReferrals.users
48976
- }).from(gaSocialReferrals).where(and36(...conditions)).orderBy(gaSocialReferrals.date).all();
48999
+ }).from(gaSocialReferrals).where(and37(...conditions)).orderBy(gaSocialReferrals.date).all();
48977
49000
  return rows;
48978
49001
  });
48979
49002
  app.get("/projects/:name/ga/social-referral-trend", async (request, _reply) => {
@@ -48986,10 +49009,10 @@ async function ga4Routes(app, opts) {
48986
49009
  d.setDate(d.getDate() - n);
48987
49010
  return fmt(d);
48988
49011
  };
48989
- const sumSocial = (from, to) => app.db.select({ sessions: sql17`COALESCE(SUM(${gaSocialReferrals.sessions}), 0)` }).from(gaSocialReferrals).where(and36(
49012
+ const sumSocial = (from, to) => app.db.select({ sessions: sql18`COALESCE(SUM(${gaSocialReferrals.sessions}), 0)` }).from(gaSocialReferrals).where(and37(
48990
49013
  eq45(gaSocialReferrals.projectId, project.id),
48991
- sql17`${gaSocialReferrals.date} >= ${from}`,
48992
- sql17`${gaSocialReferrals.date} < ${to}`
49014
+ sql18`${gaSocialReferrals.date} >= ${from}`,
49015
+ sql18`${gaSocialReferrals.date} < ${to}`
48993
49016
  )).get();
48994
49017
  const current7d = sumSocial(daysAgo(7), fmt(today));
48995
49018
  const prev7d = sumSocial(daysAgo(14), daysAgo(7));
@@ -48997,19 +49020,19 @@ async function ga4Routes(app, opts) {
48997
49020
  const prev30d = sumSocial(daysAgo(60), daysAgo(30));
48998
49021
  const sourceCurrent = app.db.select({
48999
49022
  source: gaSocialReferrals.source,
49000
- sessions: sql17`SUM(${gaSocialReferrals.sessions})`
49001
- }).from(gaSocialReferrals).where(and36(
49023
+ sessions: sql18`SUM(${gaSocialReferrals.sessions})`
49024
+ }).from(gaSocialReferrals).where(and37(
49002
49025
  eq45(gaSocialReferrals.projectId, project.id),
49003
- sql17`${gaSocialReferrals.date} >= ${daysAgo(7)}`,
49004
- sql17`${gaSocialReferrals.date} < ${fmt(today)}`
49026
+ sql18`${gaSocialReferrals.date} >= ${daysAgo(7)}`,
49027
+ sql18`${gaSocialReferrals.date} < ${fmt(today)}`
49005
49028
  )).groupBy(gaSocialReferrals.source).all();
49006
49029
  const sourcePrev = app.db.select({
49007
49030
  source: gaSocialReferrals.source,
49008
- sessions: sql17`SUM(${gaSocialReferrals.sessions})`
49009
- }).from(gaSocialReferrals).where(and36(
49031
+ sessions: sql18`SUM(${gaSocialReferrals.sessions})`
49032
+ }).from(gaSocialReferrals).where(and37(
49010
49033
  eq45(gaSocialReferrals.projectId, project.id),
49011
- sql17`${gaSocialReferrals.date} >= ${daysAgo(14)}`,
49012
- sql17`${gaSocialReferrals.date} < ${daysAgo(7)}`
49034
+ sql18`${gaSocialReferrals.date} >= ${daysAgo(14)}`,
49035
+ sql18`${gaSocialReferrals.date} < ${daysAgo(7)}`
49013
49036
  )).groupBy(gaSocialReferrals.source).all();
49014
49037
  const prevMap = new Map(sourcePrev.map((r) => [r.source, r.sessions]));
49015
49038
  let biggestMover = null;
@@ -49047,16 +49070,16 @@ async function ga4Routes(app, opts) {
49047
49070
  d.setDate(d.getDate() - n);
49048
49071
  return fmt(d);
49049
49072
  };
49050
- const sumTotal = (from, to) => app.db.select({ sessions: sql17`COALESCE(SUM(${gaTrafficSnapshots.sessions}), 0)` }).from(gaTrafficSnapshots).where(and36(eq45(gaTrafficSnapshots.projectId, project.id), sql17`${gaTrafficSnapshots.date} >= ${from}`, sql17`${gaTrafficSnapshots.date} < ${to}`)).get();
49051
- const sumOrganic = (from, to) => app.db.select({ sessions: sql17`COALESCE(SUM(${gaTrafficSnapshots.organicSessions}), 0)` }).from(gaTrafficSnapshots).where(and36(eq45(gaTrafficSnapshots.projectId, project.id), sql17`${gaTrafficSnapshots.date} >= ${from}`, sql17`${gaTrafficSnapshots.date} < ${to}`)).get();
49052
- const sumDirect = (from, to) => app.db.select({ sessions: sql17`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)` }).from(gaTrafficSnapshots).where(and36(eq45(gaTrafficSnapshots.projectId, project.id), sql17`${gaTrafficSnapshots.date} >= ${from}`, sql17`${gaTrafficSnapshots.date} < ${to}`)).get();
49053
- const sumAi = (from, to) => app.db.select({ sessions: sql17`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and36(
49073
+ const sumTotal = (from, to) => app.db.select({ sessions: sql18`COALESCE(SUM(${gaTrafficSnapshots.sessions}), 0)` }).from(gaTrafficSnapshots).where(and37(eq45(gaTrafficSnapshots.projectId, project.id), sql18`${gaTrafficSnapshots.date} >= ${from}`, sql18`${gaTrafficSnapshots.date} < ${to}`)).get();
49074
+ const sumOrganic = (from, to) => app.db.select({ sessions: sql18`COALESCE(SUM(${gaTrafficSnapshots.organicSessions}), 0)` }).from(gaTrafficSnapshots).where(and37(eq45(gaTrafficSnapshots.projectId, project.id), sql18`${gaTrafficSnapshots.date} >= ${from}`, sql18`${gaTrafficSnapshots.date} < ${to}`)).get();
49075
+ const sumDirect = (from, to) => app.db.select({ sessions: sql18`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)` }).from(gaTrafficSnapshots).where(and37(eq45(gaTrafficSnapshots.projectId, project.id), sql18`${gaTrafficSnapshots.date} >= ${from}`, sql18`${gaTrafficSnapshots.date} < ${to}`)).get();
49076
+ const sumAi = (from, to) => app.db.select({ sessions: sql18`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and37(
49054
49077
  eq45(gaAiReferrals.projectId, project.id),
49055
- sql17`${gaAiReferrals.date} >= ${from}`,
49056
- sql17`${gaAiReferrals.date} < ${to}`,
49078
+ sql18`${gaAiReferrals.date} >= ${from}`,
49079
+ sql18`${gaAiReferrals.date} < ${to}`,
49057
49080
  eq45(gaAiReferrals.sourceDimension, "session")
49058
49081
  )).get();
49059
- const sumSocial = (from, to) => app.db.select({ sessions: sql17`COALESCE(SUM(${gaSocialReferrals.sessions}), 0)` }).from(gaSocialReferrals).where(and36(eq45(gaSocialReferrals.projectId, project.id), sql17`${gaSocialReferrals.date} >= ${from}`, sql17`${gaSocialReferrals.date} < ${to}`)).get();
49082
+ const sumSocial = (from, to) => app.db.select({ sessions: sql18`COALESCE(SUM(${gaSocialReferrals.sessions}), 0)` }).from(gaSocialReferrals).where(and37(eq45(gaSocialReferrals.projectId, project.id), sql18`${gaSocialReferrals.date} >= ${from}`, sql18`${gaSocialReferrals.date} < ${to}`)).get();
49060
49083
  const todayStr = fmt(today);
49061
49084
  const buildTrend = (sum) => {
49062
49085
  const c7 = sum(daysAgo(7), todayStr)?.sessions ?? 0;
@@ -49065,16 +49088,16 @@ async function ga4Routes(app, opts) {
49065
49088
  const p30 = sum(daysAgo(60), daysAgo(30))?.sessions ?? 0;
49066
49089
  return { sessions7d: c7, sessionsPrev7d: p7, trend7dPct: deltaPercent(c7, p7), sessions30d: c30, sessionsPrev30d: p30, trend30dPct: deltaPercent(c30, p30) };
49067
49090
  };
49068
- const aiSourceCurrent = app.db.select({ source: gaAiReferrals.source, sessions: sql17`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and36(
49091
+ const aiSourceCurrent = app.db.select({ source: gaAiReferrals.source, sessions: sql18`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and37(
49069
49092
  eq45(gaAiReferrals.projectId, project.id),
49070
- sql17`${gaAiReferrals.date} >= ${daysAgo(7)}`,
49071
- sql17`${gaAiReferrals.date} < ${todayStr}`,
49093
+ sql18`${gaAiReferrals.date} >= ${daysAgo(7)}`,
49094
+ sql18`${gaAiReferrals.date} < ${todayStr}`,
49072
49095
  eq45(gaAiReferrals.sourceDimension, "session")
49073
49096
  )).groupBy(gaAiReferrals.source).all();
49074
- const aiSourcePrev = app.db.select({ source: gaAiReferrals.source, sessions: sql17`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and36(
49097
+ const aiSourcePrev = app.db.select({ source: gaAiReferrals.source, sessions: sql18`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and37(
49075
49098
  eq45(gaAiReferrals.projectId, project.id),
49076
- sql17`${gaAiReferrals.date} >= ${daysAgo(14)}`,
49077
- sql17`${gaAiReferrals.date} < ${daysAgo(7)}`,
49099
+ sql18`${gaAiReferrals.date} >= ${daysAgo(14)}`,
49100
+ sql18`${gaAiReferrals.date} < ${daysAgo(7)}`,
49078
49101
  eq45(gaAiReferrals.sourceDimension, "session")
49079
49102
  )).groupBy(gaAiReferrals.source).all();
49080
49103
  const findBiggestMover = (current, prev) => {
@@ -49091,8 +49114,8 @@ async function ga4Routes(app, opts) {
49091
49114
  }
49092
49115
  return mover;
49093
49116
  };
49094
- const socialSourceCurrent = app.db.select({ source: gaSocialReferrals.source, sessions: sql17`SUM(${gaSocialReferrals.sessions})` }).from(gaSocialReferrals).where(and36(eq45(gaSocialReferrals.projectId, project.id), sql17`${gaSocialReferrals.date} >= ${daysAgo(7)}`, sql17`${gaSocialReferrals.date} < ${todayStr}`)).groupBy(gaSocialReferrals.source).all();
49095
- const socialSourcePrev = app.db.select({ source: gaSocialReferrals.source, sessions: sql17`SUM(${gaSocialReferrals.sessions})` }).from(gaSocialReferrals).where(and36(eq45(gaSocialReferrals.projectId, project.id), sql17`${gaSocialReferrals.date} >= ${daysAgo(14)}`, sql17`${gaSocialReferrals.date} < ${daysAgo(7)}`)).groupBy(gaSocialReferrals.source).all();
49117
+ const socialSourceCurrent = app.db.select({ source: gaSocialReferrals.source, sessions: sql18`SUM(${gaSocialReferrals.sessions})` }).from(gaSocialReferrals).where(and37(eq45(gaSocialReferrals.projectId, project.id), sql18`${gaSocialReferrals.date} >= ${daysAgo(7)}`, sql18`${gaSocialReferrals.date} < ${todayStr}`)).groupBy(gaSocialReferrals.source).all();
49118
+ const socialSourcePrev = app.db.select({ source: gaSocialReferrals.source, sessions: sql18`SUM(${gaSocialReferrals.sessions})` }).from(gaSocialReferrals).where(and37(eq45(gaSocialReferrals.projectId, project.id), sql18`${gaSocialReferrals.date} >= ${daysAgo(14)}`, sql18`${gaSocialReferrals.date} < ${daysAgo(7)}`)).groupBy(gaSocialReferrals.source).all();
49096
49119
  return {
49097
49120
  total: buildTrend(sumTotal),
49098
49121
  organic: buildTrend(sumOrganic),
@@ -49110,12 +49133,12 @@ async function ga4Routes(app, opts) {
49110
49133
  const conditions = [eq45(gaTrafficSnapshots.projectId, project.id), ...dateRangeConditions(gaTrafficSnapshots.date, range)];
49111
49134
  const rows = app.db.select({
49112
49135
  date: gaTrafficSnapshots.date,
49113
- sessions: sql17`SUM(${gaTrafficSnapshots.sessions})`,
49114
- organicSessions: sql17`SUM(${gaTrafficSnapshots.organicSessions})`,
49115
- users: sql17`SUM(${gaTrafficSnapshots.users})`
49116
- }).from(gaTrafficSnapshots).where(and36(...conditions)).groupBy(gaTrafficSnapshots.date).orderBy(gaTrafficSnapshots.date).all();
49136
+ sessions: sql18`SUM(${gaTrafficSnapshots.sessions})`,
49137
+ organicSessions: sql18`SUM(${gaTrafficSnapshots.organicSessions})`,
49138
+ users: sql18`SUM(${gaTrafficSnapshots.users})`
49139
+ }).from(gaTrafficSnapshots).where(and37(...conditions)).groupBy(gaTrafficSnapshots.date).orderBy(gaTrafficSnapshots.date).all();
49117
49140
  const totalConditions = [eq45(gaDailyTotals.projectId, project.id), ...dateRangeConditions(gaDailyTotals.date, range)];
49118
- const totals = app.db.select({ date: gaDailyTotals.date, users: gaDailyTotals.users }).from(gaDailyTotals).where(and36(...totalConditions)).all();
49141
+ const totals = app.db.select({ date: gaDailyTotals.date, users: gaDailyTotals.users }).from(gaDailyTotals).where(and37(...totalConditions)).all();
49119
49142
  return buildSessionHistory(
49120
49143
  rows.map((r) => ({
49121
49144
  date: r.date,
@@ -49130,11 +49153,11 @@ async function ga4Routes(app, opts) {
49130
49153
  const project = resolveProject(app.db, request.params.name);
49131
49154
  requireGa4Connection(opts, project.name, project.canonicalDomain);
49132
49155
  const trafficPages = app.db.select({
49133
- landingPage: sql17`COALESCE(${gaTrafficSnapshots.landingPageNormalized}, ${gaTrafficSnapshots.landingPage})`,
49134
- sessions: sql17`SUM(${gaTrafficSnapshots.sessions})`,
49135
- organicSessions: sql17`SUM(${gaTrafficSnapshots.organicSessions})`,
49136
- users: sql17`SUM(${gaTrafficSnapshots.users})`
49137
- }).from(gaTrafficSnapshots).where(eq45(gaTrafficSnapshots.projectId, project.id)).groupBy(sql17`COALESCE(${gaTrafficSnapshots.landingPageNormalized}, ${gaTrafficSnapshots.landingPage})`).orderBy(sql17`SUM(${gaTrafficSnapshots.sessions}) DESC`).all();
49156
+ landingPage: sql18`COALESCE(${gaTrafficSnapshots.landingPageNormalized}, ${gaTrafficSnapshots.landingPage})`,
49157
+ sessions: sql18`SUM(${gaTrafficSnapshots.sessions})`,
49158
+ organicSessions: sql18`SUM(${gaTrafficSnapshots.organicSessions})`,
49159
+ users: sql18`SUM(${gaTrafficSnapshots.users})`
49160
+ }).from(gaTrafficSnapshots).where(eq45(gaTrafficSnapshots.projectId, project.id)).groupBy(sql18`COALESCE(${gaTrafficSnapshots.landingPageNormalized}, ${gaTrafficSnapshots.landingPage})`).orderBy(sql18`SUM(${gaTrafficSnapshots.sessions}) DESC`).all();
49138
49161
  return {
49139
49162
  pages: trafficPages.map((r) => ({
49140
49163
  landingPage: r.landingPage,
@@ -50789,7 +50812,7 @@ async function wordpressRoutes(app, opts) {
50789
50812
 
50790
50813
  // ../api-routes/src/backlinks.ts
50791
50814
  import crypto39 from "crypto";
50792
- import { and as and38, asc as asc9, desc as desc22, eq as eq46, sql as sql18 } from "drizzle-orm";
50815
+ import { and as and39, asc as asc9, desc as desc22, eq as eq46, sql as sql19 } from "drizzle-orm";
50793
50816
 
50794
50817
  // ../integration-commoncrawl/src/constants.ts
50795
50818
  import os2 from "os";
@@ -51079,7 +51102,7 @@ async function queryBacklinks(opts) {
51079
51102
  const reversed = opts.targets.map(reverseDomain);
51080
51103
  const targetList = reversed.map(quote).join(", ");
51081
51104
  const limitClause = opts.limitPerTarget ? `QUALIFY row_number() OVER (PARTITION BY t.target_rev_domain ORDER BY v.num_hosts DESC) <= ${Math.floor(opts.limitPerTarget)}` : "";
51082
- const sql24 = `
51105
+ const sql25 = `
51083
51106
  WITH vertices AS (
51084
51107
  SELECT * FROM read_csv(
51085
51108
  ${quote(opts.vertexPath)},
@@ -51115,7 +51138,7 @@ async function queryBacklinks(opts) {
51115
51138
  const conn = await instance.connect();
51116
51139
  let rows;
51117
51140
  try {
51118
- const reader = await conn.runAndReadAll(sql24);
51141
+ const reader = await conn.runAndReadAll(sql25);
51119
51142
  rows = reader.getRowObjects();
51120
51143
  } finally {
51121
51144
  conn.disconnectSync?.();
@@ -51192,7 +51215,7 @@ function pruneCachedRelease(release, opts = {}) {
51192
51215
  }
51193
51216
 
51194
51217
  // ../api-routes/src/backlinks-filter.ts
51195
- import { and as and37, ne as ne6, notLike } from "drizzle-orm";
51218
+ import { and as and38, ne as ne6, notLike } from "drizzle-orm";
51196
51219
  var BACKLINK_FILTER_PATTERNS = [
51197
51220
  "*.google.com",
51198
51221
  "*.googleusercontent.com",
@@ -51215,7 +51238,7 @@ function backlinkCrawlerExclusionClause() {
51215
51238
  conditions.push(ne6(backlinkDomains.linkingDomain, pattern));
51216
51239
  }
51217
51240
  }
51218
- const combined = and37(...conditions);
51241
+ const combined = and38(...conditions);
51219
51242
  if (!combined) throw new Error("BACKLINK_FILTER_PATTERNS is unexpectedly empty");
51220
51243
  return combined;
51221
51244
  }
@@ -51290,7 +51313,7 @@ function latestSummaryForProject(db, projectId, source, release) {
51290
51313
  eq46(backlinkSummaries.source, source)
51291
51314
  ];
51292
51315
  if (release) conditions.push(eq46(backlinkSummaries.release, release));
51293
- return db.select().from(backlinkSummaries).where(and38(...conditions)).orderBy(desc22(backlinkSummaries.queriedAt)).limit(1).get();
51316
+ return db.select().from(backlinkSummaries).where(and39(...conditions)).orderBy(desc22(backlinkSummaries.queriedAt)).limit(1).get();
51294
51317
  }
51295
51318
  function parseExcludeCrawlers(value) {
51296
51319
  if (!value) return false;
@@ -51298,19 +51321,19 @@ function parseExcludeCrawlers(value) {
51298
51321
  return lower === "1" || lower === "true" || lower === "yes";
51299
51322
  }
51300
51323
  function computeFilteredSummary(db, base) {
51301
- const baseDomainCondition = and38(
51324
+ const baseDomainCondition = and39(
51302
51325
  eq46(backlinkDomains.projectId, base.projectId),
51303
51326
  eq46(backlinkDomains.source, base.source),
51304
51327
  eq46(backlinkDomains.release, base.release)
51305
51328
  );
51306
- const filteredCondition = and38(baseDomainCondition, backlinkCrawlerExclusionClause());
51329
+ const filteredCondition = and39(baseDomainCondition, backlinkCrawlerExclusionClause());
51307
51330
  const unfilteredAgg = db.select({
51308
- count: sql18`count(*)`,
51309
- total: sql18`coalesce(sum(${backlinkDomains.numHosts}), 0)`
51331
+ count: sql19`count(*)`,
51332
+ total: sql19`coalesce(sum(${backlinkDomains.numHosts}), 0)`
51310
51333
  }).from(backlinkDomains).where(baseDomainCondition).get();
51311
51334
  const filteredAgg = db.select({
51312
- count: sql18`count(*)`,
51313
- total: sql18`coalesce(sum(${backlinkDomains.numHosts}), 0)`
51335
+ count: sql19`count(*)`,
51336
+ total: sql19`coalesce(sum(${backlinkDomains.numHosts}), 0)`
51314
51337
  }).from(backlinkDomains).where(filteredCondition).get();
51315
51338
  const top10Rows = db.select({ numHosts: backlinkDomains.numHosts }).from(backlinkDomains).where(filteredCondition).orderBy(desc22(backlinkDomains.numHosts)).limit(10).all();
51316
51339
  const totalLinkingDomains = Number(filteredAgg?.count ?? 0);
@@ -51333,10 +51356,10 @@ function computeFilteredSummary(db, base) {
51333
51356
  };
51334
51357
  }
51335
51358
  function buildSourceAvailability(db, projectId, source, connected, excludeCrawlers) {
51336
- const summary = db.select().from(backlinkSummaries).where(and38(eq46(backlinkSummaries.projectId, projectId), eq46(backlinkSummaries.source, source))).orderBy(desc22(backlinkSummaries.queriedAt)).limit(1).get();
51359
+ const summary = db.select().from(backlinkSummaries).where(and39(eq46(backlinkSummaries.projectId, projectId), eq46(backlinkSummaries.source, source))).orderBy(desc22(backlinkSummaries.queriedAt)).limit(1).get();
51337
51360
  let totalLinkingDomains = summary?.totalLinkingDomains ?? 0;
51338
51361
  if (summary && excludeCrawlers) {
51339
- const filtered = db.select({ count: sql18`count(*)` }).from(backlinkDomains).where(and38(
51362
+ const filtered = db.select({ count: sql19`count(*)` }).from(backlinkDomains).where(and39(
51340
51363
  eq46(backlinkDomains.projectId, projectId),
51341
51364
  eq46(backlinkDomains.source, source),
51342
51365
  eq46(backlinkDomains.release, summary.release),
@@ -51518,13 +51541,13 @@ async function backlinksRoutes(app, opts) {
51518
51541
  const limit = Math.min(Math.max(parseInt(request.query.limit ?? "50", 10) || 50, 1), 500);
51519
51542
  const offset = Math.max(parseInt(request.query.offset ?? "0", 10) || 0, 0);
51520
51543
  const excludeCrawlers = parseExcludeCrawlers(request.query.excludeCrawlers);
51521
- const baseDomainCondition = and38(
51544
+ const baseDomainCondition = and39(
51522
51545
  eq46(backlinkDomains.projectId, project.id),
51523
51546
  eq46(backlinkDomains.source, source),
51524
51547
  eq46(backlinkDomains.release, targetRelease)
51525
51548
  );
51526
- const domainCondition = excludeCrawlers ? and38(baseDomainCondition, backlinkCrawlerExclusionClause()) : baseDomainCondition;
51527
- const totalRow = app.db.select({ count: sql18`count(*)` }).from(backlinkDomains).where(domainCondition).get();
51549
+ const domainCondition = excludeCrawlers ? and39(baseDomainCondition, backlinkCrawlerExclusionClause()) : baseDomainCondition;
51550
+ const totalRow = app.db.select({ count: sql19`count(*)` }).from(backlinkDomains).where(domainCondition).get();
51528
51551
  const rows = app.db.select({
51529
51552
  linkingDomain: backlinkDomains.linkingDomain,
51530
51553
  numHosts: backlinkDomains.numHosts,
@@ -51547,7 +51570,7 @@ async function backlinksRoutes(app, opts) {
51547
51570
  async (request, reply) => {
51548
51571
  const project = resolveProject(app.db, request.params.name);
51549
51572
  const source = parseSourceParam(request.query.source);
51550
- const rows = app.db.select().from(backlinkSummaries).where(and38(eq46(backlinkSummaries.projectId, project.id), eq46(backlinkSummaries.source, source))).orderBy(asc9(backlinkSummaries.queriedAt)).all();
51573
+ const rows = app.db.select().from(backlinkSummaries).where(and39(eq46(backlinkSummaries.projectId, project.id), eq46(backlinkSummaries.source, source))).orderBy(asc9(backlinkSummaries.queriedAt)).all();
51551
51574
  const response = rows.map((r) => ({
51552
51575
  release: r.release,
51553
51576
  totalLinkingDomains: r.totalLinkingDomains,
@@ -51575,7 +51598,7 @@ import crypto42 from "crypto";
51575
51598
  import { isIP } from "net";
51576
51599
  import { isDeepStrictEqual } from "util";
51577
51600
  import { Agent as UndiciAgent } from "undici";
51578
- import { and as and42, desc as desc23, eq as eq50, gte as gte11, lte as lte11, sql as sql21 } from "drizzle-orm";
51601
+ import { and as and43, desc as desc23, eq as eq50, gte as gte11, lte as lte11, sql as sql22 } from "drizzle-orm";
51579
51602
 
51580
51603
  // ../api-routes/src/cloudflare-worker-version.ts
51581
51604
  var CURRENT_CLOUDFLARE_WORKER_VERSION = "1.0.1";
@@ -68098,10 +68121,10 @@ async function ackCloudflareQueueMessages(client, options) {
68098
68121
 
68099
68122
  // ../api-routes/src/traffic-event-ingest.ts
68100
68123
  import crypto41 from "crypto";
68101
- import { and as and40, eq as eq48, gte as gte10, lt as lt9, lte as lte9, sql as sql20 } from "drizzle-orm";
68124
+ import { and as and41, eq as eq48, gte as gte10, lt as lt9, lte as lte9, sql as sql21 } from "drizzle-orm";
68102
68125
 
68103
68126
  // ../api-routes/src/raw-event-sample-retention.ts
68104
- import { and as and39, eq as eq47, lt as lt8, sql as sql19 } from "drizzle-orm";
68127
+ import { and as and40, eq as eq47, lt as lt8, sql as sql20 } from "drizzle-orm";
68105
68128
  var RAW_EVENT_SAMPLE_RETENTION_MS = 30 * 24 * 60 * 6e4;
68106
68129
  var RAW_EVENT_SAMPLE_RETENTION_SWEEP_INTERVAL_MS = 24 * 60 * 6e4;
68107
68130
  var CANONICAL_UTC_TIMESTAMP_GLOB = "[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9]Z";
@@ -68112,16 +68135,16 @@ function rawEventSampleRetentionCutoff(referenceAt) {
68112
68135
  }
68113
68136
  function deleteExpiredRawEventSamples(db, cutoff, sourceId) {
68114
68137
  const sourceScope = sourceId === void 0 ? void 0 : eq47(rawEventSamples.sourceId, sourceId);
68115
- db.delete(rawEventSamples).where(and39(sourceScope, sql19`julianday(${rawEventSamples.ts}) IS NULL`)).run();
68116
- db.delete(rawEventSamples).where(and39(
68138
+ db.delete(rawEventSamples).where(and40(sourceScope, sql20`julianday(${rawEventSamples.ts}) IS NULL`)).run();
68139
+ db.delete(rawEventSamples).where(and40(
68117
68140
  sourceScope,
68118
- sql19`${rawEventSamples.ts} GLOB ${CANONICAL_UTC_TIMESTAMP_GLOB}`,
68141
+ sql20`${rawEventSamples.ts} GLOB ${CANONICAL_UTC_TIMESTAMP_GLOB}`,
68119
68142
  lt8(rawEventSamples.ts, cutoff)
68120
68143
  )).run();
68121
- db.delete(rawEventSamples).where(and39(
68144
+ db.delete(rawEventSamples).where(and40(
68122
68145
  sourceScope,
68123
- sql19`${rawEventSamples.ts} NOT GLOB ${CANONICAL_UTC_TIMESTAMP_GLOB}`,
68124
- sql19`julianday(${rawEventSamples.ts}) < julianday(${cutoff})`
68146
+ sql20`${rawEventSamples.ts} NOT GLOB ${CANONICAL_UTC_TIMESTAMP_GLOB}`,
68147
+ sql20`julianday(${rawEventSamples.ts}) < julianday(${cutoff})`
68125
68148
  )).run();
68126
68149
  }
68127
68150
  function enforceRawEventSampleRetention(db, sourceId, referenceAt) {
@@ -68167,7 +68190,7 @@ function writeTrafficEventBatch(opts) {
68167
68190
  let aiReferralHits = 0;
68168
68191
  let unknownHits = 0;
68169
68192
  opts.db.transaction((tx) => {
68170
- tx.update(trafficSources).set({ updatedAt: sql20`${trafficSources.updatedAt}` }).where(eq48(trafficSources.id, opts.sourceId)).run();
68193
+ tx.update(trafficSources).set({ updatedAt: sql21`${trafficSources.updatedAt}` }).where(eq48(trafficSources.id, opts.sourceId)).run();
68171
68194
  const source = tx.select().from(trafficSources).where(eq48(trafficSources.id, opts.sourceId)).get();
68172
68195
  opts.validateSource(source);
68173
68196
  const rawSampleCutoff = enforceRawEventSampleRetention(
@@ -68175,7 +68198,7 @@ function writeTrafficEventBatch(opts) {
68175
68198
  opts.sourceId,
68176
68199
  opts.receivedAt
68177
68200
  );
68178
- tx.delete(trafficEventReceipts).where(and40(
68201
+ tx.delete(trafficEventReceipts).where(and41(
68179
68202
  eq48(trafficEventReceipts.sourceId, opts.sourceId),
68180
68203
  lte9(trafficEventReceipts.expiresAt, opts.receivedAt)
68181
68204
  )).run();
@@ -68224,7 +68247,7 @@ function writeTrafficEventBatch(opts) {
68224
68247
  crawlerEventsHourly.status
68225
68248
  ],
68226
68249
  set: {
68227
- hits: sql20`${crawlerEventsHourly.hits} + ${bucket.hits}`,
68250
+ hits: sql21`${crawlerEventsHourly.hits} + ${bucket.hits}`,
68228
68251
  sampledUserAgent: bucket.sampledUserAgent,
68229
68252
  updatedAt: opts.receivedAt
68230
68253
  }
@@ -68255,7 +68278,7 @@ function writeTrafficEventBatch(opts) {
68255
68278
  crawlerVerificationManifestsHourly.manifestId
68256
68279
  ],
68257
68280
  set: {
68258
- hits: sql20`${crawlerVerificationManifestsHourly.hits} + ${bucket.hits}`,
68281
+ hits: sql21`${crawlerVerificationManifestsHourly.hits} + ${bucket.hits}`,
68259
68282
  manifestJson: bucket.verificationManifest,
68260
68283
  updatedAt: opts.receivedAt
68261
68284
  }
@@ -68289,7 +68312,7 @@ function writeTrafficEventBatch(opts) {
68289
68312
  aiUserFetchEventsHourly.status
68290
68313
  ],
68291
68314
  set: {
68292
- hits: sql20`${aiUserFetchEventsHourly.hits} + ${bucket.hits}`,
68315
+ hits: sql21`${aiUserFetchEventsHourly.hits} + ${bucket.hits}`,
68293
68316
  sampledUserAgent: bucket.sampledUserAgent,
68294
68317
  updatedAt: opts.receivedAt
68295
68318
  }
@@ -68320,7 +68343,7 @@ function writeTrafficEventBatch(opts) {
68320
68343
  aiUserFetchVerificationManifestsHourly.manifestId
68321
68344
  ],
68322
68345
  set: {
68323
- hits: sql20`${aiUserFetchVerificationManifestsHourly.hits} + ${bucket.hits}`,
68346
+ hits: sql21`${aiUserFetchVerificationManifestsHourly.hits} + ${bucket.hits}`,
68324
68347
  manifestJson: bucket.verificationManifest,
68325
68348
  updatedAt: opts.receivedAt
68326
68349
  }
@@ -68358,9 +68381,9 @@ function writeTrafficEventBatch(opts) {
68358
68381
  aiReferralEventsHourly.status
68359
68382
  ],
68360
68383
  set: {
68361
- sessionsOrHits: sql20`${aiReferralEventsHourly.sessionsOrHits} + ${bucket.hits}`,
68362
- paidSessionsOrHits: sql20`${aiReferralEventsHourly.paidSessionsOrHits} + ${bucket.paidHits}`,
68363
- organicSessionsOrHits: sql20`${aiReferralEventsHourly.organicSessionsOrHits} + ${bucket.organicHits}`,
68384
+ sessionsOrHits: sql21`${aiReferralEventsHourly.sessionsOrHits} + ${bucket.hits}`,
68385
+ paidSessionsOrHits: sql21`${aiReferralEventsHourly.paidSessionsOrHits} + ${bucket.paidHits}`,
68386
+ organicSessionsOrHits: sql21`${aiReferralEventsHourly.organicSessionsOrHits} + ${bucket.organicHits}`,
68364
68387
  updatedAt: opts.receivedAt
68365
68388
  }
68366
68389
  }).run();
@@ -68375,7 +68398,7 @@ function writeTrafficEventBatch(opts) {
68375
68398
  if (!hour || hourlySampleLimit === 0) continue;
68376
68399
  let remaining = remainingSamplesByHour.get(hour.start);
68377
68400
  if (remaining === void 0) {
68378
- const existing = tx.select({ total: sql20`COUNT(*)` }).from(rawEventSamples).where(and40(
68401
+ const existing = tx.select({ total: sql21`COUNT(*)` }).from(rawEventSamples).where(and41(
68379
68402
  eq48(rawEventSamples.sourceId, opts.sourceId),
68380
68403
  gte10(rawEventSamples.ts, hour.start),
68381
68404
  lt9(rawEventSamples.ts, hour.end)
@@ -68435,7 +68458,7 @@ function writeTrafficEventBatch(opts) {
68435
68458
  }
68436
68459
 
68437
68460
  // ../api-routes/src/traffic-sync-lease.ts
68438
- import { and as and41, eq as eq49, isNull as isNull5, lte as lte10, or as or11 } from "drizzle-orm";
68461
+ import { and as and42, eq as eq49, isNull as isNull5, lte as lte10, or as or11 } from "drizzle-orm";
68439
68462
  function leaseExpiresAt(now, ttlMs) {
68440
68463
  const nowMs = Date.parse(now);
68441
68464
  if (!Number.isFinite(nowMs)) throw new RangeError("Traffic sync lease now must be an ISO instant");
@@ -68449,7 +68472,7 @@ function tryClaimTrafficSyncLease(input) {
68449
68472
  syncLeaseOwner: input.owner,
68450
68473
  syncLeaseExpiresAt: expiresAt,
68451
68474
  updatedAt: input.now
68452
- }).where(and41(
68475
+ }).where(and42(
68453
68476
  eq49(trafficSources.id, input.sourceId),
68454
68477
  or11(
68455
68478
  isNull5(trafficSources.syncLeaseOwner),
@@ -68466,7 +68489,7 @@ function releaseTrafficSyncLease(input) {
68466
68489
  syncLeaseOwner: null,
68467
68490
  syncLeaseExpiresAt: null,
68468
68491
  updatedAt: input.now
68469
- }).where(and41(
68492
+ }).where(and42(
68470
68493
  eq49(trafficSources.id, input.sourceId),
68471
68494
  eq49(trafficSources.syncLeaseOwner, input.owner)
68472
68495
  )).run();
@@ -68617,7 +68640,7 @@ function assertCloudflareIngestUrlOutsideWorkerRoute(ingestUrl, workerRouteHost)
68617
68640
  }
68618
68641
  }
68619
68642
  function emptyTrafficSeriesPoint(bucket) {
68620
- return { bucket, crawlerHits: 0, aiUserFetchHits: 0, aiReferralHits: 0 };
68643
+ return { bucket, crawlerHits: 0, aiUserFetchHits: 0, aiReferralHits: 0, aiReferralLandedHits: 0 };
68621
68644
  }
68622
68645
  function completeTrafficSeries(windowStart, windowEnd, granularity, pointsByBucket) {
68623
68646
  const cursor = new Date(windowStart);
@@ -68701,7 +68724,7 @@ function crawlerVerificationProvenance(db, projectId, events) {
68701
68724
  manifestId: crawlerVerificationManifestsHourly.manifestId,
68702
68725
  manifest: crawlerVerificationManifestsHourly.manifestJson,
68703
68726
  hits: crawlerVerificationManifestsHourly.hits
68704
- }).from(crawlerVerificationManifestsHourly).where(sql21`(
68727
+ }).from(crawlerVerificationManifestsHourly).where(sql22`(
68705
68728
  ${crawlerVerificationManifestsHourly.projectId},
68706
68729
  ${crawlerVerificationManifestsHourly.sourceId},
68707
68730
  ${crawlerVerificationManifestsHourly.tsHour},
@@ -68735,7 +68758,7 @@ function aiUserFetchVerificationProvenance(db, projectId, events) {
68735
68758
  manifestId: aiUserFetchVerificationManifestsHourly.manifestId,
68736
68759
  manifest: aiUserFetchVerificationManifestsHourly.manifestJson,
68737
68760
  hits: aiUserFetchVerificationManifestsHourly.hits
68738
- }).from(aiUserFetchVerificationManifestsHourly).where(sql21`(
68761
+ }).from(aiUserFetchVerificationManifestsHourly).where(sql22`(
68739
68762
  ${aiUserFetchVerificationManifestsHourly.projectId},
68740
68763
  ${aiUserFetchVerificationManifestsHourly.sourceId},
68741
68764
  ${aiUserFetchVerificationManifestsHourly.tsHour},
@@ -68802,7 +68825,7 @@ function isSameTrafficSourceGeneration(current, started) {
68802
68825
  return isDeepStrictEqual(current.configJson, started.configJson) && current.updatedAt === started.updatedAt && current.lastSyncedAt === started.lastSyncedAt;
68803
68826
  }
68804
68827
  function bindTrafficSyncSchedule(tx, projectId, sourceId, now, createIfMissing = true) {
68805
- const schedule = tx.select().from(schedules).where(and42(
68828
+ const schedule = tx.select().from(schedules).where(and43(
68806
68829
  eq50(schedules.projectId, projectId),
68807
68830
  eq50(schedules.kind, SchedulableRunKinds["traffic-sync"])
68808
68831
  )).get();
@@ -68913,28 +68936,28 @@ async function runBackfillTask(options) {
68913
68936
  finishedAt
68914
68937
  );
68915
68938
  tx.delete(crawlerEventsHourly).where(
68916
- and42(
68939
+ and43(
68917
68940
  eq50(crawlerEventsHourly.sourceId, sourceRow2.id),
68918
68941
  gte11(crawlerEventsHourly.tsHour, windowStartIso),
68919
68942
  lte11(crawlerEventsHourly.tsHour, windowEndIso)
68920
68943
  )
68921
68944
  ).run();
68922
68945
  tx.delete(aiUserFetchEventsHourly).where(
68923
- and42(
68946
+ and43(
68924
68947
  eq50(aiUserFetchEventsHourly.sourceId, sourceRow2.id),
68925
68948
  gte11(aiUserFetchEventsHourly.tsHour, windowStartIso),
68926
68949
  lte11(aiUserFetchEventsHourly.tsHour, windowEndIso)
68927
68950
  )
68928
68951
  ).run();
68929
68952
  tx.delete(aiReferralEventsHourly).where(
68930
- and42(
68953
+ and43(
68931
68954
  eq50(aiReferralEventsHourly.sourceId, sourceRow2.id),
68932
68955
  gte11(aiReferralEventsHourly.tsHour, windowStartIso),
68933
68956
  lte11(aiReferralEventsHourly.tsHour, windowEndIso)
68934
68957
  )
68935
68958
  ).run();
68936
68959
  tx.delete(rawEventSamples).where(
68937
- and42(
68960
+ and43(
68938
68961
  eq50(rawEventSamples.sourceId, sourceRow2.id),
68939
68962
  gte11(rawEventSamples.ts, windowStartIso),
68940
68963
  lte11(rawEventSamples.ts, windowEndIso)
@@ -68966,7 +68989,7 @@ async function runBackfillTask(options) {
68966
68989
  crawlerEventsHourly.status
68967
68990
  ],
68968
68991
  set: {
68969
- hits: sql21`${crawlerEventsHourly.hits} + ${bucket.hits}`,
68992
+ hits: sql22`${crawlerEventsHourly.hits} + ${bucket.hits}`,
68970
68993
  sampledUserAgent: bucket.sampledUserAgent,
68971
68994
  updatedAt: finishedAt
68972
68995
  }
@@ -68997,7 +69020,7 @@ async function runBackfillTask(options) {
68997
69020
  crawlerVerificationManifestsHourly.manifestId
68998
69021
  ],
68999
69022
  set: {
69000
- hits: sql21`${crawlerVerificationManifestsHourly.hits} + ${bucket.hits}`,
69023
+ hits: sql22`${crawlerVerificationManifestsHourly.hits} + ${bucket.hits}`,
69001
69024
  manifestJson: bucket.verificationManifest,
69002
69025
  updatedAt: finishedAt
69003
69026
  }
@@ -69030,7 +69053,7 @@ async function runBackfillTask(options) {
69030
69053
  aiUserFetchEventsHourly.status
69031
69054
  ],
69032
69055
  set: {
69033
- hits: sql21`${aiUserFetchEventsHourly.hits} + ${bucket.hits}`,
69056
+ hits: sql22`${aiUserFetchEventsHourly.hits} + ${bucket.hits}`,
69034
69057
  sampledUserAgent: bucket.sampledUserAgent,
69035
69058
  updatedAt: finishedAt
69036
69059
  }
@@ -69061,7 +69084,7 @@ async function runBackfillTask(options) {
69061
69084
  aiUserFetchVerificationManifestsHourly.manifestId
69062
69085
  ],
69063
69086
  set: {
69064
- hits: sql21`${aiUserFetchVerificationManifestsHourly.hits} + ${bucket.hits}`,
69087
+ hits: sql22`${aiUserFetchVerificationManifestsHourly.hits} + ${bucket.hits}`,
69065
69088
  manifestJson: bucket.verificationManifest,
69066
69089
  updatedAt: finishedAt
69067
69090
  }
@@ -69788,7 +69811,7 @@ async function trafficRoutes(app, opts) {
69788
69811
  }
69789
69812
  let removed = false;
69790
69813
  if (row.status === TrafficSourceStatuses.connected) {
69791
- const schedule = tx.select().from(schedules).where(and42(
69814
+ const schedule = tx.select().from(schedules).where(and43(
69792
69815
  eq50(schedules.projectId, project.id),
69793
69816
  eq50(schedules.kind, SchedulableRunKinds["traffic-sync"])
69794
69817
  )).get();
@@ -69874,7 +69897,7 @@ async function trafficRoutes(app, opts) {
69874
69897
  bindTrafficSyncSchedule(tx, project.id, target.id, now);
69875
69898
  scheduleAction = "upsert";
69876
69899
  } else {
69877
- const schedule = tx.select().from(schedules).where(and42(
69900
+ const schedule = tx.select().from(schedules).where(and43(
69878
69901
  eq50(schedules.projectId, project.id),
69879
69902
  eq50(schedules.kind, SchedulableRunKinds["traffic-sync"])
69880
69903
  )).get();
@@ -70222,7 +70245,7 @@ async function trafficRoutes(app, opts) {
70222
70245
  tx.update(runs).set({ status: RunStatuses.failed, error: safeError, finishedAt: failedAt }).where(eq50(runs.id, runId2)).run();
70223
70246
  const latestSource = tx.select().from(trafficSources).where(eq50(trafficSources.id, sourceRow2.id)).get();
70224
70247
  if (latestSource && latestSource.status === TrafficSourceStatuses.connected && latestSource.syncLeaseOwner === leaseOwner && isDeepStrictEqual(latestSource.configJson, sourceRow2.configJson)) {
70225
- tx.update(trafficSources).set({ lastError: safeError, updatedAt: failedAt }).where(and42(
70248
+ tx.update(trafficSources).set({ lastError: safeError, updatedAt: failedAt }).where(and43(
70226
70249
  eq50(trafficSources.id, sourceRow2.id),
70227
70250
  eq50(trafficSources.status, TrafficSourceStatuses.connected),
70228
70251
  eq50(trafficSources.syncLeaseOwner, leaseOwner)
@@ -70570,7 +70593,7 @@ async function trafficRoutes(app, opts) {
70570
70593
  crawlerEventsHourly.status
70571
70594
  ],
70572
70595
  set: {
70573
- hits: sql21`${crawlerEventsHourly.hits} + ${bucket.hits}`,
70596
+ hits: sql22`${crawlerEventsHourly.hits} + ${bucket.hits}`,
70574
70597
  sampledUserAgent: bucket.sampledUserAgent,
70575
70598
  updatedAt: finishedAt
70576
70599
  }
@@ -70601,7 +70624,7 @@ async function trafficRoutes(app, opts) {
70601
70624
  crawlerVerificationManifestsHourly.manifestId
70602
70625
  ],
70603
70626
  set: {
70604
- hits: sql21`${crawlerVerificationManifestsHourly.hits} + ${bucket.hits}`,
70627
+ hits: sql22`${crawlerVerificationManifestsHourly.hits} + ${bucket.hits}`,
70605
70628
  manifestJson: bucket.verificationManifest,
70606
70629
  updatedAt: finishedAt
70607
70630
  }
@@ -70635,7 +70658,7 @@ async function trafficRoutes(app, opts) {
70635
70658
  aiUserFetchEventsHourly.status
70636
70659
  ],
70637
70660
  set: {
70638
- hits: sql21`${aiUserFetchEventsHourly.hits} + ${bucket.hits}`,
70661
+ hits: sql22`${aiUserFetchEventsHourly.hits} + ${bucket.hits}`,
70639
70662
  sampledUserAgent: bucket.sampledUserAgent,
70640
70663
  updatedAt: finishedAt
70641
70664
  }
@@ -70666,7 +70689,7 @@ async function trafficRoutes(app, opts) {
70666
70689
  aiUserFetchVerificationManifestsHourly.manifestId
70667
70690
  ],
70668
70691
  set: {
70669
- hits: sql21`${aiUserFetchVerificationManifestsHourly.hits} + ${bucket.hits}`,
70692
+ hits: sql22`${aiUserFetchVerificationManifestsHourly.hits} + ${bucket.hits}`,
70670
70693
  manifestJson: bucket.verificationManifest,
70671
70694
  updatedAt: finishedAt
70672
70695
  }
@@ -70707,9 +70730,9 @@ async function trafficRoutes(app, opts) {
70707
70730
  // colliding bucket adds its paid and organic arrivals to the ones
70708
70731
  // already there rather than overwriting a single label.
70709
70732
  set: {
70710
- sessionsOrHits: sql21`${aiReferralEventsHourly.sessionsOrHits} + ${bucket.hits}`,
70711
- paidSessionsOrHits: sql21`${aiReferralEventsHourly.paidSessionsOrHits} + ${bucket.paidHits}`,
70712
- organicSessionsOrHits: sql21`${aiReferralEventsHourly.organicSessionsOrHits} + ${bucket.organicHits}`,
70733
+ sessionsOrHits: sql22`${aiReferralEventsHourly.sessionsOrHits} + ${bucket.hits}`,
70734
+ paidSessionsOrHits: sql22`${aiReferralEventsHourly.paidSessionsOrHits} + ${bucket.paidHits}`,
70735
+ organicSessionsOrHits: sql22`${aiReferralEventsHourly.organicSessionsOrHits} + ${bucket.organicHits}`,
70713
70736
  updatedAt: finishedAt
70714
70737
  }
70715
70738
  }).run();
@@ -71028,9 +71051,9 @@ async function trafficRoutes(app, opts) {
71028
71051
  function buildSourceDetail(projectId, row, since) {
71029
71052
  const crawlerPathRows = app.db.select({
71030
71053
  pathNormalized: crawlerEventsHourly.pathNormalized,
71031
- hits: sql21`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
71054
+ hits: sql22`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
71032
71055
  }).from(crawlerEventsHourly).where(
71033
- and42(
71056
+ and43(
71034
71057
  eq50(crawlerEventsHourly.sourceId, row.id),
71035
71058
  gte11(crawlerEventsHourly.tsHour, since)
71036
71059
  )
@@ -71039,26 +71062,30 @@ async function trafficRoutes(app, opts) {
71039
71062
  crawlerPathRows.map((r) => ({ pathNormalized: r.pathNormalized, hits: Number(r.hits) }))
71040
71063
  );
71041
71064
  const crawlerTotal = crawlerSegments.content + crawlerSegments.sitemap + crawlerSegments.robots + crawlerSegments.asset + crawlerSegments.other;
71042
- const aiUserFetchTotals = app.db.select({ total: sql21`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
71043
- and42(
71065
+ const aiUserFetchTotals = app.db.select({ total: sql22`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
71066
+ and43(
71044
71067
  eq50(aiUserFetchEventsHourly.sourceId, row.id),
71045
71068
  gte11(aiUserFetchEventsHourly.tsHour, since)
71046
71069
  )
71047
71070
  ).get();
71048
- const aiTotals = app.db.select({ total: sql21`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
71049
- and42(
71071
+ const aiTotals = app.db.select({
71072
+ total: sql22`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`,
71073
+ nonhop: sql22`COALESCE(SUM(CASE WHEN ${referralLandedCondition()} THEN ${aiReferralEventsHourly.sessionsOrHits} ELSE 0 END), 0)`,
71074
+ landed: sql22`COALESCE(SUM(CASE WHEN ${countableReferralCondition()} THEN ${aiReferralEventsHourly.sessionsOrHits} ELSE 0 END), 0)`
71075
+ }).from(aiReferralEventsHourly).where(
71076
+ and43(
71050
71077
  eq50(aiReferralEventsHourly.sourceId, row.id),
71051
71078
  gte11(aiReferralEventsHourly.tsHour, since)
71052
71079
  )
71053
71080
  ).get();
71054
- const sampleTotals = app.db.select({ total: sql21`COUNT(*)` }).from(rawEventSamples).where(
71055
- and42(
71081
+ const sampleTotals = app.db.select({ total: sql22`COUNT(*)` }).from(rawEventSamples).where(
71082
+ and43(
71056
71083
  eq50(rawEventSamples.sourceId, row.id),
71057
71084
  gte11(rawEventSamples.ts, since)
71058
71085
  )
71059
71086
  ).get();
71060
71087
  const latestRun = app.db.select().from(runs).where(
71061
- and42(
71088
+ and43(
71062
71089
  eq50(runs.projectId, projectId),
71063
71090
  eq50(runs.kind, RunKinds["traffic-sync"]),
71064
71091
  eq50(runs.sourceId, row.id)
@@ -71073,6 +71100,8 @@ async function trafficRoutes(app, opts) {
71073
71100
  crawlerSegments,
71074
71101
  aiUserFetchHits: Number(aiUserFetchTotals?.total ?? 0),
71075
71102
  aiReferralHits: Number(aiTotals?.total ?? 0),
71103
+ aiReferralLandedHits: Number(aiTotals?.landed ?? 0),
71104
+ aiReferralRedirectedHits: Number(aiTotals?.total ?? 0) - Number(aiTotals?.nonhop ?? 0),
71076
71105
  sampleCount: Number(sampleTotals?.total ?? 0)
71077
71106
  },
71078
71107
  latestRun: latestRun ? {
@@ -71095,7 +71124,7 @@ async function trafficRoutes(app, opts) {
71095
71124
  const now = (/* @__PURE__ */ new Date()).toISOString();
71096
71125
  let updatedRow;
71097
71126
  app.db.transaction((tx) => {
71098
- const sourceRow2 = tx.select().from(trafficSources).where(and42(eq50(trafficSources.projectId, project.id), eq50(trafficSources.id, request.params.id))).get();
71127
+ const sourceRow2 = tx.select().from(trafficSources).where(and43(eq50(trafficSources.projectId, project.id), eq50(trafficSources.id, request.params.id))).get();
71099
71128
  if (!sourceRow2) {
71100
71129
  throw notFound("traffic source", request.params.id);
71101
71130
  }
@@ -71213,6 +71242,9 @@ async function trafficRoutes(app, opts) {
71213
71242
  let crawlerSegments = { content: 0, sitemap: 0, robots: 0, asset: 0, other: 0 };
71214
71243
  let aiUserFetchTotal = 0;
71215
71244
  let aiReferralCounts = aiReferralClassCounts(0, 0, 0);
71245
+ let aiReferralTotalHits = 0;
71246
+ let aiReferralNonHopHits = 0;
71247
+ let aiReferralLandedHits = 0;
71216
71248
  let totalEventRows = 0;
71217
71249
  const seriesByBucket = /* @__PURE__ */ new Map();
71218
71250
  if (kind === "all" || kind === TrafficEventKinds.crawler) {
@@ -71222,21 +71254,21 @@ async function trafficRoutes(app, opts) {
71222
71254
  lte11(crawlerEventsHourly.tsHour, untilIso)
71223
71255
  ];
71224
71256
  if (sourceIdParam) crawlerFilters.push(eq50(crawlerEventsHourly.sourceId, sourceIdParam));
71225
- const crawlerWhere = and42(...crawlerFilters);
71257
+ const crawlerWhere = and43(...crawlerFilters);
71226
71258
  const pathTotals = app.db.select({
71227
71259
  pathNormalized: crawlerEventsHourly.pathNormalized,
71228
- hits: sql21`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`,
71229
- rows: sql21`COUNT(*)`
71260
+ hits: sql22`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`,
71261
+ rows: sql22`COUNT(*)`
71230
71262
  }).from(crawlerEventsHourly).where(crawlerWhere).groupBy(crawlerEventsHourly.pathNormalized).all();
71231
71263
  crawlerSegments = segmentCrawlerHits(
71232
71264
  pathTotals.map((r) => ({ pathNormalized: r.pathNormalized, hits: Number(r.hits) }))
71233
71265
  );
71234
71266
  crawlerTotal = crawlerSegments.content + crawlerSegments.sitemap + crawlerSegments.robots + crawlerSegments.asset + crawlerSegments.other;
71235
71267
  totalEventRows += pathTotals.reduce((sum, row) => sum + Number(row.rows), 0);
71236
- const crawlerSeriesBucket = granularity === TrafficSeriesGranularities.day ? sql21`substr(${crawlerEventsHourly.tsHour}, 1, 10)` : crawlerEventsHourly.tsHour;
71268
+ const crawlerSeriesBucket = granularity === TrafficSeriesGranularities.day ? sql22`substr(${crawlerEventsHourly.tsHour}, 1, 10)` : crawlerEventsHourly.tsHour;
71237
71269
  const crawlerSeries = app.db.select({
71238
71270
  bucket: crawlerSeriesBucket,
71239
- hits: sql21`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
71271
+ hits: sql22`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
71240
71272
  }).from(crawlerEventsHourly).where(crawlerWhere).groupBy(crawlerSeriesBucket).all();
71241
71273
  for (const row of crawlerSeries) {
71242
71274
  trafficSeriesPoint(seriesByBucket, row.bucket).crawlerHits = Number(row.hits);
@@ -71266,17 +71298,17 @@ async function trafficRoutes(app, opts) {
71266
71298
  lte11(aiUserFetchEventsHourly.tsHour, untilIso)
71267
71299
  ];
71268
71300
  if (sourceIdParam) userFetchFilters.push(eq50(aiUserFetchEventsHourly.sourceId, sourceIdParam));
71269
- const userFetchWhere = and42(...userFetchFilters);
71301
+ const userFetchWhere = and43(...userFetchFilters);
71270
71302
  const total = app.db.select({
71271
- total: sql21`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)`,
71272
- rows: sql21`COUNT(*)`
71303
+ total: sql22`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)`,
71304
+ rows: sql22`COUNT(*)`
71273
71305
  }).from(aiUserFetchEventsHourly).where(userFetchWhere).get();
71274
71306
  aiUserFetchTotal = Number(total?.total ?? 0);
71275
71307
  totalEventRows += Number(total?.rows ?? 0);
71276
- const userFetchSeriesBucket = granularity === TrafficSeriesGranularities.day ? sql21`substr(${aiUserFetchEventsHourly.tsHour}, 1, 10)` : aiUserFetchEventsHourly.tsHour;
71308
+ const userFetchSeriesBucket = granularity === TrafficSeriesGranularities.day ? sql22`substr(${aiUserFetchEventsHourly.tsHour}, 1, 10)` : aiUserFetchEventsHourly.tsHour;
71277
71309
  const userFetchSeries = app.db.select({
71278
71310
  bucket: userFetchSeriesBucket,
71279
- hits: sql21`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)`
71311
+ hits: sql22`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)`
71280
71312
  }).from(aiUserFetchEventsHourly).where(userFetchWhere).groupBy(userFetchSeriesBucket).all();
71281
71313
  for (const row of userFetchSeries) {
71282
71314
  trafficSeriesPoint(seriesByBucket, row.bucket).aiUserFetchHits = Number(row.hits);
@@ -71305,26 +71337,34 @@ async function trafficRoutes(app, opts) {
71305
71337
  lte11(aiReferralEventsHourly.tsHour, untilIso)
71306
71338
  ];
71307
71339
  if (sourceIdParam) aiFilters.push(eq50(aiReferralEventsHourly.sourceId, sourceIdParam));
71308
- const aiWhere = and42(...aiFilters);
71340
+ const aiWhere = and43(...aiFilters);
71309
71341
  const total = app.db.select({
71310
- total: sql21`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`,
71311
- paid: sql21`COALESCE(SUM(${aiReferralEventsHourly.paidSessionsOrHits}), 0)`,
71312
- organic: sql21`COALESCE(SUM(${aiReferralEventsHourly.organicSessionsOrHits}), 0)`,
71313
- rows: sql21`COUNT(*)`
71342
+ total: sql22`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`,
71343
+ nonhop: sql22`COALESCE(SUM(CASE WHEN ${referralLandedCondition()} THEN ${aiReferralEventsHourly.sessionsOrHits} ELSE 0 END), 0)`,
71344
+ landed: sql22`COALESCE(SUM(CASE WHEN ${countableReferralCondition()} THEN ${aiReferralEventsHourly.sessionsOrHits} ELSE 0 END), 0)`,
71345
+ paid: sql22`COALESCE(SUM(CASE WHEN ${countableReferralCondition()} THEN ${aiReferralEventsHourly.paidSessionsOrHits} ELSE 0 END), 0)`,
71346
+ organic: sql22`COALESCE(SUM(CASE WHEN ${countableReferralCondition()} THEN ${aiReferralEventsHourly.organicSessionsOrHits} ELSE 0 END), 0)`,
71347
+ rows: sql22`COUNT(*)`
71314
71348
  }).from(aiReferralEventsHourly).where(aiWhere).get();
71349
+ aiReferralTotalHits = Number(total?.total ?? 0);
71350
+ aiReferralNonHopHits = Number(total?.nonhop ?? 0);
71351
+ aiReferralLandedHits = Number(total?.landed ?? 0);
71315
71352
  aiReferralCounts = aiReferralClassCounts(
71316
- Number(total?.total ?? 0),
71353
+ aiReferralLandedHits,
71317
71354
  Number(total?.paid ?? 0),
71318
71355
  Number(total?.organic ?? 0)
71319
71356
  );
71320
71357
  totalEventRows += Number(total?.rows ?? 0);
71321
- const referralSeriesBucket = granularity === TrafficSeriesGranularities.day ? sql21`substr(${aiReferralEventsHourly.tsHour}, 1, 10)` : aiReferralEventsHourly.tsHour;
71358
+ const referralSeriesBucket = granularity === TrafficSeriesGranularities.day ? sql22`substr(${aiReferralEventsHourly.tsHour}, 1, 10)` : aiReferralEventsHourly.tsHour;
71322
71359
  const referralSeries = app.db.select({
71323
71360
  bucket: referralSeriesBucket,
71324
- hits: sql21`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`
71361
+ hits: sql22`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`,
71362
+ landed: sql22`COALESCE(SUM(CASE WHEN ${countableReferralCondition()} THEN ${aiReferralEventsHourly.sessionsOrHits} ELSE 0 END), 0)`
71325
71363
  }).from(aiReferralEventsHourly).where(aiWhere).groupBy(referralSeriesBucket).all();
71326
71364
  for (const row of referralSeries) {
71327
- trafficSeriesPoint(seriesByBucket, row.bucket).aiReferralHits = Number(row.hits);
71365
+ const point = trafficSeriesPoint(seriesByBucket, row.bucket);
71366
+ point.aiReferralHits = Number(row.hits);
71367
+ point.aiReferralLandedHits = Number(row.landed);
71328
71368
  }
71329
71369
  const rows = app.db.select().from(aiReferralEventsHourly).where(aiWhere).orderBy(desc23(aiReferralEventsHourly.tsHour)).limit(limit).all();
71330
71370
  for (const r of rows) {
@@ -71380,7 +71420,9 @@ async function trafficRoutes(app, opts) {
71380
71420
  crawlerInfraHits: sumInfraHits(crawlerSegments),
71381
71421
  crawlerSegments,
71382
71422
  aiUserFetchHits: aiUserFetchTotal,
71383
- aiReferralHits: aiReferralCounts.total,
71423
+ aiReferralHits: aiReferralTotalHits,
71424
+ aiReferralLandedHits,
71425
+ aiReferralRedirectedHits: aiReferralTotalHits - aiReferralNonHopHits,
71384
71426
  aiReferralPaidHits: aiReferralCounts.paid,
71385
71427
  aiReferralOrganicHits: aiReferralCounts.organic,
71386
71428
  aiReferralUnknownHits: aiReferralCounts.unknown
@@ -71721,7 +71763,7 @@ var skillsTriggerSurfaceCheck = {
71721
71763
  var AGENT_CHECKS = [skillsInstalledCheck, skillsCurrentCheck, skillsTriggerSurfaceCheck];
71722
71764
 
71723
71765
  // ../api-routes/src/doctor/checks/backlinks.ts
71724
- import { and as and43, eq as eq51 } from "drizzle-orm";
71766
+ import { and as and44, eq as eq51 } from "drizzle-orm";
71725
71767
  function skippedNoProject() {
71726
71768
  return {
71727
71769
  status: CheckStatuses.skipped,
@@ -71751,7 +71793,7 @@ var BACKLINKS_CHECKS = [
71751
71793
  details: { commoncrawl: ccConnected }
71752
71794
  };
71753
71795
  }
71754
- const ccHasData = ccConnected ? !!ctx.db.select({ id: backlinkSummaries.id }).from(backlinkSummaries).where(and43(
71796
+ const ccHasData = ccConnected ? !!ctx.db.select({ id: backlinkSummaries.id }).from(backlinkSummaries).where(and44(
71755
71797
  eq51(backlinkSummaries.projectId, ctx.project.id),
71756
71798
  eq51(backlinkSummaries.source, BacklinkSources.commoncrawl)
71757
71799
  )).limit(1).get() : false;
@@ -72276,7 +72318,7 @@ var ga4ConnectionCheck = {
72276
72318
  var GA_AUTH_CHECKS = [ga4ConnectionCheck];
72277
72319
 
72278
72320
  // ../api-routes/src/doctor/checks/gbp-auth.ts
72279
- import { and as and44, eq as eq54 } from "drizzle-orm";
72321
+ import { and as and45, eq as eq54 } from "drizzle-orm";
72280
72322
  var RECENT_SYNC_WARN_DAYS2 = 7;
72281
72323
  var RECENT_SYNC_FAIL_DAYS2 = 30;
72282
72324
  function skippedNoProject3() {
@@ -72509,7 +72551,7 @@ var recentSyncCheck = {
72509
72551
  title: "GBP recent sync",
72510
72552
  run: (ctx) => {
72511
72553
  if (!ctx.project) return skippedNoProject3();
72512
- const selected = ctx.db.select({ locationName: gbpLocations.locationName, syncedAt: gbpLocations.syncedAt }).from(gbpLocations).where(and44(eq54(gbpLocations.projectId, ctx.project.id), eq54(gbpLocations.selected, true))).all();
72554
+ const selected = ctx.db.select({ locationName: gbpLocations.locationName, syncedAt: gbpLocations.syncedAt }).from(gbpLocations).where(and45(eq54(gbpLocations.projectId, ctx.project.id), eq54(gbpLocations.selected, true))).all();
72513
72555
  if (selected.length === 0) {
72514
72556
  return {
72515
72557
  status: CheckStatuses.skipped,
@@ -73129,7 +73171,7 @@ var RUNTIME_STATE_CHECKS = [
73129
73171
  ];
73130
73172
 
73131
73173
  // ../api-routes/src/doctor/checks/traffic-source.ts
73132
- import { and as and45, eq as eq56, gte as gte12, inArray as inArray18, ne as ne7, sql as sql22 } from "drizzle-orm";
73174
+ import { and as and46, eq as eq56, gte as gte12, inArray as inArray18, ne as ne7, sql as sql23 } from "drizzle-orm";
73133
73175
  var RECENT_DATA_WARN_DAYS = 7;
73134
73176
  var RECENT_DATA_FAIL_DAYS = 30;
73135
73177
  function isCloudflareDirectPush(source) {
@@ -73168,7 +73210,7 @@ function skippedNoProject5() {
73168
73210
  function loadProbes(ctx) {
73169
73211
  if (!ctx.project) return [];
73170
73212
  const rows = ctx.db.select().from(trafficSources).where(
73171
- and45(
73213
+ and46(
73172
73214
  eq56(trafficSources.projectId, ctx.project.id),
73173
73215
  ne7(trafficSources.status, TrafficSourceStatuses.archived)
73174
73216
  )
@@ -73274,8 +73316,8 @@ var recentDataCheck = {
73274
73316
  const warnCutoff = new Date(now.getTime() - RECENT_DATA_WARN_DAYS * 24 * 60 * 6e4).toISOString();
73275
73317
  const failCutoff = new Date(now.getTime() - RECENT_DATA_FAIL_DAYS * 24 * 60 * 6e4).toISOString();
73276
73318
  const recentCrawlers = Number(
73277
- ctx.db.select({ total: sql22`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
73278
- and45(
73319
+ ctx.db.select({ total: sql23`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
73320
+ and46(
73279
73321
  eq56(crawlerEventsHourly.projectId, ctx.project.id),
73280
73322
  inArray18(crawlerEventsHourly.sourceId, activeSourceIds),
73281
73323
  gte12(crawlerEventsHourly.tsHour, warnCutoff)
@@ -73283,8 +73325,8 @@ var recentDataCheck = {
73283
73325
  ).get()?.total ?? 0
73284
73326
  );
73285
73327
  const recentReferrals = Number(
73286
- ctx.db.select({ total: sql22`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
73287
- and45(
73328
+ ctx.db.select({ total: sql23`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
73329
+ and46(
73288
73330
  eq56(aiReferralEventsHourly.projectId, ctx.project.id),
73289
73331
  inArray18(aiReferralEventsHourly.sourceId, activeSourceIds),
73290
73332
  gte12(aiReferralEventsHourly.tsHour, warnCutoff)
@@ -73292,8 +73334,8 @@ var recentDataCheck = {
73292
73334
  ).get()?.total ?? 0
73293
73335
  );
73294
73336
  const recentUserFetches = Number(
73295
- ctx.db.select({ total: sql22`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
73296
- and45(
73337
+ ctx.db.select({ total: sql23`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
73338
+ and46(
73297
73339
  eq56(aiUserFetchEventsHourly.projectId, ctx.project.id),
73298
73340
  inArray18(aiUserFetchEventsHourly.sourceId, activeSourceIds),
73299
73341
  gte12(aiUserFetchEventsHourly.tsHour, warnCutoff)
@@ -73304,18 +73346,22 @@ var recentDataCheck = {
73304
73346
  return {
73305
73347
  status: CheckStatuses.ok,
73306
73348
  code: "traffic.recent-data.fresh",
73307
- summary: `${recentCrawlers} crawler hit(s), ${recentUserFetches} AI user-fetch hit(s), and ${recentReferrals} AI-referral arrival(s) in the last ${RECENT_DATA_WARN_DAYS} days.`,
73349
+ summary: `${recentCrawlers} crawler hit(s), ${recentUserFetches} AI user-fetch hit(s), and ${recentReferrals} AI-referral hit(s) in the last ${RECENT_DATA_WARN_DAYS} days.`,
73308
73350
  details: {
73309
73351
  crawlerHits: recentCrawlers,
73310
73352
  aiUserFetchHits: recentUserFetches,
73311
- referralArrivals: recentReferrals,
73353
+ // Full hit count on purpose: for freshness, a redirect hop is still
73354
+ // proof the pipeline works. Named hits, not arrivals — the report's
73355
+ // referralArrivals is redirect-excluded and must not share a name
73356
+ // with a figure that is not.
73357
+ referralHits: recentReferrals,
73312
73358
  windowDays: RECENT_DATA_WARN_DAYS
73313
73359
  }
73314
73360
  };
73315
73361
  }
73316
73362
  const olderCrawlers = Number(
73317
- ctx.db.select({ total: sql22`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
73318
- and45(
73363
+ ctx.db.select({ total: sql23`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
73364
+ and46(
73319
73365
  eq56(crawlerEventsHourly.projectId, ctx.project.id),
73320
73366
  inArray18(crawlerEventsHourly.sourceId, activeSourceIds),
73321
73367
  gte12(crawlerEventsHourly.tsHour, failCutoff)
@@ -73323,8 +73369,8 @@ var recentDataCheck = {
73323
73369
  ).get()?.total ?? 0
73324
73370
  );
73325
73371
  const olderReferrals = Number(
73326
- ctx.db.select({ total: sql22`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
73327
- and45(
73372
+ ctx.db.select({ total: sql23`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
73373
+ and46(
73328
73374
  eq56(aiReferralEventsHourly.projectId, ctx.project.id),
73329
73375
  inArray18(aiReferralEventsHourly.sourceId, activeSourceIds),
73330
73376
  gte12(aiReferralEventsHourly.tsHour, failCutoff)
@@ -73332,8 +73378,8 @@ var recentDataCheck = {
73332
73378
  ).get()?.total ?? 0
73333
73379
  );
73334
73380
  const olderUserFetches = Number(
73335
- ctx.db.select({ total: sql22`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
73336
- and45(
73381
+ ctx.db.select({ total: sql23`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
73382
+ and46(
73337
73383
  eq56(aiUserFetchEventsHourly.projectId, ctx.project.id),
73338
73384
  inArray18(aiUserFetchEventsHourly.sourceId, activeSourceIds),
73339
73385
  gte12(aiUserFetchEventsHourly.tsHour, failCutoff)
@@ -74245,7 +74291,7 @@ async function doctorRoutes(app, opts) {
74245
74291
 
74246
74292
  // ../api-routes/src/discovery/routes.ts
74247
74293
  import crypto44 from "crypto";
74248
- import { and as and46, desc as desc24, eq as eq57, gte as gte13, inArray as inArray19, isNull as isNull6, or as or12 } from "drizzle-orm";
74294
+ import { and as and47, desc as desc24, eq as eq57, gte as gte13, inArray as inArray19, isNull as isNull6, or as or12 } from "drizzle-orm";
74249
74295
  var MAX_INFLIGHT_DISCOVERY_AGE_MS = 2 * 60 * 60 * 1e3;
74250
74296
  async function discoveryRoutes(app, opts) {
74251
74297
  app.post("/projects/:name/discover/run", async (request, reply) => {
@@ -74279,7 +74325,7 @@ async function discoveryRoutes(app, opts) {
74279
74325
  const now = (/* @__PURE__ */ new Date()).toISOString();
74280
74326
  const ageFloorIso = new Date(Date.now() - MAX_INFLIGHT_DISCOVERY_AGE_MS).toISOString();
74281
74327
  const decision = app.db.transaction((tx) => {
74282
- const existing = tx.select({ id: discoverySessions.id, runId: discoverySessions.runId }).from(discoverySessions).where(and46(
74328
+ const existing = tx.select({ id: discoverySessions.id, runId: discoverySessions.runId }).from(discoverySessions).where(and47(
74283
74329
  eq57(discoverySessions.projectId, project.id),
74284
74330
  eq57(discoverySessions.icpDescription, icpDescription),
74285
74331
  // Buyer is part of session identity: it changes the seed prompt's
@@ -74925,7 +74971,7 @@ function dedupeStrings(input) {
74925
74971
 
74926
74972
  // ../api-routes/src/technical-aeo.ts
74927
74973
  import crypto46 from "crypto";
74928
- import { and as and47, asc as asc10, count, desc as desc25, eq as eq59, inArray as inArray20, isNotNull as isNotNull3, isNull as isNull7, lt as lt10, or as or13, sql as sql23 } from "drizzle-orm";
74974
+ import { and as and48, asc as asc10, count, desc as desc25, eq as eq59, inArray as inArray20, isNotNull as isNotNull3, isNull as isNull7, lt as lt10, or as or13, sql as sql24 } from "drizzle-orm";
74929
74975
  import { alias } from "drizzle-orm/sqlite-core";
74930
74976
  var FETCHED_SITE_CRAWL_STATES = /* @__PURE__ */ new Set([
74931
74977
  ...SiteCrawlFetchedStates,
@@ -75144,7 +75190,7 @@ function linkKindFilter(linkKind) {
75144
75190
  }
75145
75191
  var graphSourceNode = alias(siteCrawlGraphNodes, "site_crawl_graph_source_node");
75146
75192
  var graphTargetNode = alias(siteCrawlGraphNodes, "site_crawl_graph_target_node");
75147
- var PAGE_CHANGE_PREDICATE = sql23`(
75193
+ var PAGE_CHANGE_PREDICATE = sql24`(
75148
75194
  current.url IS NOT previous.url
75149
75195
  OR current.final_url IS NOT previous.final_url
75150
75196
  OR current.path IS NOT previous.path
@@ -75166,7 +75212,7 @@ var PAGE_CHANGE_PREDICATE = sql23`(
75166
75212
  OR current.link_score_raw IS NOT previous.link_score_raw
75167
75213
  OR current.link_score_normalized IS NOT previous.link_score_normalized
75168
75214
  )`;
75169
- var LINK_CHANGE_PREDICATE = sql23`(
75215
+ var LINK_CHANGE_PREDICATE = sql24`(
75170
75216
  current.source_node_key IS NOT previous.source_node_key
75171
75217
  OR current.source_url IS NOT previous.source_url
75172
75218
  OR current.target_node_key IS NOT previous.target_node_key
@@ -75255,25 +75301,25 @@ async function technicalAeoRoutes(app, opts) {
75255
75301
  } else {
75256
75302
  filters.push(eq59(siteCrawlSnapshots.complete, true), eq59(runs.status, RunStatuses.completed));
75257
75303
  }
75258
- return app.db.select({ snapshot: siteCrawlSnapshots, runStatus: runs.status }).from(siteCrawlSnapshots).innerJoin(runs, eq59(siteCrawlSnapshots.runId, runs.id)).where(and47(...filters)).orderBy(desc25(siteCrawlSnapshots.createdAt), desc25(siteCrawlSnapshots.runId)).limit(1).get();
75304
+ return app.db.select({ snapshot: siteCrawlSnapshots, runStatus: runs.status }).from(siteCrawlSnapshots).innerJoin(runs, eq59(siteCrawlSnapshots.runId, runs.id)).where(and48(...filters)).orderBy(desc25(siteCrawlSnapshots.createdAt), desc25(siteCrawlSnapshots.runId)).limit(1).get();
75259
75305
  };
75260
75306
  const detailScopeFor = (projectId, snapshot) => snapshot.detailsAvailable && snapshot.attemptId ? { projectId, runId: snapshot.runId, attemptId: snapshot.attemptId } : null;
75261
75307
  const pageInScope = (scope, selector) => {
75262
75308
  if (!selector.nodeKey && !selector.url) return null;
75263
- return app.db.select().from(siteCrawlPages).where(and47(
75309
+ return app.db.select().from(siteCrawlPages).where(and48(
75264
75310
  eq59(siteCrawlPages.projectId, scope.projectId),
75265
75311
  eq59(siteCrawlPages.runId, scope.runId),
75266
75312
  eq59(siteCrawlPages.attemptId, scope.attemptId),
75267
75313
  selector.nodeKey ? eq59(siteCrawlPages.nodeKey, selector.nodeKey) : eq59(siteCrawlPages.url, selector.url)
75268
75314
  )).orderBy(asc10(siteCrawlPages.nodeKey)).limit(1).get() ?? null;
75269
75315
  };
75270
- const rootPageInScope = (scope, rootUrl) => pageInScope(scope, { url: rootUrl }) ?? app.db.select().from(siteCrawlPages).where(and47(
75316
+ const rootPageInScope = (scope, rootUrl) => pageInScope(scope, { url: rootUrl }) ?? app.db.select().from(siteCrawlPages).where(and48(
75271
75317
  eq59(siteCrawlPages.projectId, scope.projectId),
75272
75318
  eq59(siteCrawlPages.runId, scope.runId),
75273
75319
  eq59(siteCrawlPages.attemptId, scope.attemptId),
75274
75320
  eq59(siteCrawlPages.depth, 0)
75275
75321
  )).orderBy(asc10(siteCrawlPages.nodeKey)).limit(1).get() ?? null;
75276
- const isSurfaceableAuditRun = (projectId, runId) => Boolean(app.db.select({ id: runs.id }).from(runs).where(and47(
75322
+ const isSurfaceableAuditRun = (projectId, runId) => Boolean(app.db.select({ id: runs.id }).from(runs).where(and48(
75277
75323
  eq59(runs.id, runId),
75278
75324
  eq59(runs.projectId, projectId),
75279
75325
  eq59(runs.kind, RunKinds["site-audit"]),
@@ -75283,7 +75329,7 @@ async function technicalAeoRoutes(app, opts) {
75283
75329
  const assertKnownAuditRun = (projectId, runId) => {
75284
75330
  if (runId && !isSurfaceableAuditRun(projectId, runId)) throw notFound("Site crawl run", runId);
75285
75331
  };
75286
- const hasLegacyAudit = (projectId) => Boolean(app.db.select({ runId: siteAuditSnapshots.runId }).from(siteAuditSnapshots).innerJoin(runs, eq59(siteAuditSnapshots.runId, runs.id)).where(and47(
75332
+ const hasLegacyAudit = (projectId) => Boolean(app.db.select({ runId: siteAuditSnapshots.runId }).from(siteAuditSnapshots).innerJoin(runs, eq59(siteAuditSnapshots.runId, runs.id)).where(and48(
75287
75333
  eq59(siteAuditSnapshots.projectId, projectId),
75288
75334
  eq59(runs.projectId, projectId),
75289
75335
  eq59(runs.kind, RunKinds["site-audit"]),
@@ -75315,13 +75361,13 @@ async function technicalAeoRoutes(app, opts) {
75315
75361
  notProbeRun()
75316
75362
  ];
75317
75363
  const targetFilters = request.query.runId ? [...baseFilters, eq59(siteAuditSnapshots.runId, request.query.runId)] : baseFilters;
75318
- const latest = app.db.select({ snap: siteAuditSnapshots, runStatus: runs.status }).from(siteAuditSnapshots).innerJoin(runs, eq59(siteAuditSnapshots.runId, runs.id)).where(and47(...targetFilters)).orderBy(desc25(siteAuditSnapshots.createdAt)).limit(1).get();
75364
+ const latest = app.db.select({ snap: siteAuditSnapshots, runStatus: runs.status }).from(siteAuditSnapshots).innerJoin(runs, eq59(siteAuditSnapshots.runId, runs.id)).where(and48(...targetFilters)).orderBy(desc25(siteAuditSnapshots.createdAt)).limit(1).get();
75319
75365
  if (!latest) {
75320
75366
  if (request.query.runId) throw notFound("Site audit run", request.query.runId);
75321
75367
  return emptyScore(project.name);
75322
75368
  }
75323
75369
  const snap = latest.snap;
75324
- const previous = app.db.select({ snap: siteAuditSnapshots }).from(siteAuditSnapshots).innerJoin(runs, eq59(siteAuditSnapshots.runId, runs.id)).where(and47(...baseFilters, lt10(siteAuditSnapshots.createdAt, snap.createdAt))).orderBy(desc25(siteAuditSnapshots.createdAt)).limit(1).get()?.snap ?? null;
75370
+ const previous = app.db.select({ snap: siteAuditSnapshots }).from(siteAuditSnapshots).innerJoin(runs, eq59(siteAuditSnapshots.runId, runs.id)).where(and48(...baseFilters, lt10(siteAuditSnapshots.createdAt, snap.createdAt))).orderBy(desc25(siteAuditSnapshots.createdAt)).limit(1).get()?.snap ?? null;
75325
75371
  const deltaScore = previous ? snap.aggregateScore - previous.aggregateScore : null;
75326
75372
  const trend = deltaScore == null ? null : deltaScore > 0 ? SiteAuditTrendDirections.up : deltaScore < 0 ? SiteAuditTrendDirections.down : SiteAuditTrendDirections.flat;
75327
75373
  return {
@@ -75355,7 +75401,7 @@ async function technicalAeoRoutes(app, opts) {
75355
75401
  notProbeRun()
75356
75402
  ];
75357
75403
  if (request.query.runId) targetFilters.push(eq59(siteAuditSnapshots.runId, request.query.runId));
75358
- const latest = app.db.select({ runId: siteAuditSnapshots.runId, auditedAt: siteAuditSnapshots.auditedAt }).from(siteAuditSnapshots).innerJoin(runs, eq59(siteAuditSnapshots.runId, runs.id)).where(and47(...targetFilters)).orderBy(desc25(siteAuditSnapshots.createdAt)).limit(1).get();
75404
+ const latest = app.db.select({ runId: siteAuditSnapshots.runId, auditedAt: siteAuditSnapshots.auditedAt }).from(siteAuditSnapshots).innerJoin(runs, eq59(siteAuditSnapshots.runId, runs.id)).where(and48(...targetFilters)).orderBy(desc25(siteAuditSnapshots.createdAt)).limit(1).get();
75359
75405
  if (!latest && request.query.runId) {
75360
75406
  throw notFound("Site audit run", request.query.runId);
75361
75407
  }
@@ -75365,7 +75411,7 @@ async function technicalAeoRoutes(app, opts) {
75365
75411
  const statusFilter = request.query.status === "success" || request.query.status === "error" ? request.query.status : null;
75366
75412
  const conds = [eq59(siteAuditPages.projectId, project.id), eq59(siteAuditPages.runId, latest.runId)];
75367
75413
  if (statusFilter) conds.push(eq59(siteAuditPages.status, statusFilter));
75368
- const where = and47(...conds);
75414
+ const where = and48(...conds);
75369
75415
  const totalRow = app.db.select({ value: count() }).from(siteAuditPages).where(where).get();
75370
75416
  const total = totalRow?.value ?? 0;
75371
75417
  const limit = parsePositiveInt(request.query.limit, 100, 500);
@@ -75389,7 +75435,7 @@ async function technicalAeoRoutes(app, opts) {
75389
75435
  auditedAt: siteAuditSnapshots.auditedAt,
75390
75436
  aggregateScore: siteAuditSnapshots.aggregateScore,
75391
75437
  pagesAudited: siteAuditSnapshots.pagesAudited
75392
- }).from(siteAuditSnapshots).innerJoin(runs, eq59(siteAuditSnapshots.runId, runs.id)).where(and47(
75438
+ }).from(siteAuditSnapshots).innerJoin(runs, eq59(siteAuditSnapshots.runId, runs.id)).where(and48(
75393
75439
  eq59(siteAuditSnapshots.projectId, project.id),
75394
75440
  eq59(runs.projectId, project.id),
75395
75441
  eq59(runs.kind, RunKinds["site-audit"]),
@@ -75487,7 +75533,7 @@ async function technicalAeoRoutes(app, opts) {
75487
75533
  { projectId: project.id, runId: snapshot.runId, attemptId: snapshot.attemptId },
75488
75534
  snapshot.rootUrl
75489
75535
  )?.nodeKey ?? null;
75490
- const persistedLayout = app.db.select().from(siteCrawlGraphLayouts).where(and47(
75536
+ const persistedLayout = app.db.select().from(siteCrawlGraphLayouts).where(and48(
75491
75537
  eq59(siteCrawlGraphLayouts.projectId, project.id),
75492
75538
  eq59(siteCrawlGraphLayouts.runId, snapshot.runId),
75493
75539
  eq59(siteCrawlGraphLayouts.attemptId, snapshot.attemptId)
@@ -75562,12 +75608,12 @@ async function technicalAeoRoutes(app, opts) {
75562
75608
  linkScoreNormalized: siteCrawlPages.linkScoreNormalized,
75563
75609
  x: siteCrawlGraphNodes.x,
75564
75610
  y: siteCrawlGraphNodes.y
75565
- }).from(siteCrawlGraphNodes).innerJoin(siteCrawlPages, and47(
75611
+ }).from(siteCrawlGraphNodes).innerJoin(siteCrawlPages, and48(
75566
75612
  eq59(siteCrawlPages.projectId, siteCrawlGraphNodes.projectId),
75567
75613
  eq59(siteCrawlPages.runId, siteCrawlGraphNodes.runId),
75568
75614
  eq59(siteCrawlPages.attemptId, siteCrawlGraphNodes.attemptId),
75569
75615
  eq59(siteCrawlPages.nodeKey, siteCrawlGraphNodes.nodeKey)
75570
- )).where(and47(...graphScope, lt10(siteCrawlGraphNodes.sampleRank, maxNodes))).orderBy(asc10(siteCrawlGraphNodes.sampleRank)).all();
75616
+ )).where(and48(...graphScope, lt10(siteCrawlGraphNodes.sampleRank, maxNodes))).orderBy(asc10(siteCrawlGraphNodes.sampleRank)).all();
75571
75617
  const nodes = nodeRows.map(({ indexabilityReasons, canonicalNodeKey, ...row }) => ({
75572
75618
  ...row,
75573
75619
  healthState: deriveSiteHealthState({ ...row, indexabilityReasons, canonicalNodeKey })
@@ -75580,19 +75626,19 @@ async function technicalAeoRoutes(app, opts) {
75580
75626
  followable: siteCrawlGraphEdges.followable,
75581
75627
  occurrences: siteCrawlGraphEdges.occurrences,
75582
75628
  isTemplate: siteCrawlGraphEdges.isTemplate
75583
- }).from(siteCrawlGraphEdges).innerJoin(graphSourceNode, and47(
75629
+ }).from(siteCrawlGraphEdges).innerJoin(graphSourceNode, and48(
75584
75630
  eq59(graphSourceNode.projectId, siteCrawlGraphEdges.projectId),
75585
75631
  eq59(graphSourceNode.runId, siteCrawlGraphEdges.runId),
75586
75632
  eq59(graphSourceNode.attemptId, siteCrawlGraphEdges.attemptId),
75587
75633
  eq59(graphSourceNode.nodeKey, siteCrawlGraphEdges.sourceNodeKey),
75588
75634
  lt10(graphSourceNode.sampleRank, maxNodes)
75589
- )).innerJoin(graphTargetNode, and47(
75635
+ )).innerJoin(graphTargetNode, and48(
75590
75636
  eq59(graphTargetNode.projectId, siteCrawlGraphEdges.projectId),
75591
75637
  eq59(graphTargetNode.runId, siteCrawlGraphEdges.runId),
75592
75638
  eq59(graphTargetNode.attemptId, siteCrawlGraphEdges.attemptId),
75593
75639
  eq59(graphTargetNode.nodeKey, siteCrawlGraphEdges.targetNodeKey),
75594
75640
  lt10(graphTargetNode.sampleRank, maxNodes)
75595
- )).where(and47(
75641
+ )).where(and48(
75596
75642
  eq59(siteCrawlGraphEdges.projectId, project.id),
75597
75643
  eq59(siteCrawlGraphEdges.runId, snapshot.runId),
75598
75644
  eq59(siteCrawlGraphEdges.attemptId, snapshot.attemptId),
@@ -75689,7 +75735,7 @@ async function technicalAeoRoutes(app, opts) {
75689
75735
  let frontier = [focus.nodeKey];
75690
75736
  let queryTruncated = false;
75691
75737
  for (let distance = 0; distance < hops && frontier.length > 0; distance += 1) {
75692
- const candidates = app.db.select().from(siteCrawlEdges).where(and47(
75738
+ const candidates = app.db.select().from(siteCrawlEdges).where(and48(
75693
75739
  eq59(siteCrawlEdges.projectId, scope.projectId),
75694
75740
  eq59(siteCrawlEdges.runId, scope.runId),
75695
75741
  eq59(siteCrawlEdges.attemptId, scope.attemptId),
@@ -75730,7 +75776,7 @@ async function technicalAeoRoutes(app, opts) {
75730
75776
  frontier = [...next].sort();
75731
75777
  }
75732
75778
  const nodeKeys = [...distances.keys()];
75733
- const pageRows = nodeKeys.length === 0 ? [] : app.db.select().from(siteCrawlPages).where(and47(
75779
+ const pageRows = nodeKeys.length === 0 ? [] : app.db.select().from(siteCrawlPages).where(and48(
75734
75780
  eq59(siteCrawlPages.projectId, scope.projectId),
75735
75781
  eq59(siteCrawlPages.runId, scope.runId),
75736
75782
  eq59(siteCrawlPages.attemptId, scope.attemptId),
@@ -75738,7 +75784,7 @@ async function technicalAeoRoutes(app, opts) {
75738
75784
  )).all();
75739
75785
  const persistedNodeKeys = new Set(pageRows.map((row) => row.nodeKey));
75740
75786
  const outermostNodeKeys = pageRows.filter((row) => distances.get(row.nodeKey) === hops).map((row) => row.nodeKey);
75741
- const omittedOutermostEdge = outermostNodeKeys.length === 0 ? void 0 : app.db.select({ edgeKey: siteCrawlEdges.edgeKey }).from(siteCrawlEdges).where(and47(
75787
+ const omittedOutermostEdge = outermostNodeKeys.length === 0 ? void 0 : app.db.select({ edgeKey: siteCrawlEdges.edgeKey }).from(siteCrawlEdges).where(and48(
75742
75788
  eq59(siteCrawlEdges.projectId, scope.projectId),
75743
75789
  eq59(siteCrawlEdges.runId, scope.runId),
75744
75790
  eq59(siteCrawlEdges.attemptId, scope.attemptId),
@@ -75840,7 +75886,7 @@ async function technicalAeoRoutes(app, opts) {
75840
75886
  let found = fromPage.nodeKey === toPage.nodeKey;
75841
75887
  let truncated = false;
75842
75888
  for (let depth = 0; depth < maxDepth && frontier.length > 0 && !found; depth += 1) {
75843
- const candidates = app.db.select().from(siteCrawlEdges).where(and47(
75889
+ const candidates = app.db.select().from(siteCrawlEdges).where(and48(
75844
75890
  eq59(siteCrawlEdges.projectId, scope.projectId),
75845
75891
  eq59(siteCrawlEdges.runId, scope.runId),
75846
75892
  eq59(siteCrawlEdges.attemptId, scope.attemptId),
@@ -75852,7 +75898,7 @@ async function technicalAeoRoutes(app, opts) {
75852
75898
  )).orderBy(asc10(siteCrawlEdges.edgeKey)).limit(SITE_HEALTH_PATH_MAX_VISITED_NODES + 1).all();
75853
75899
  if (candidates.length > SITE_HEALTH_PATH_MAX_VISITED_NODES) truncated = true;
75854
75900
  const candidateTargetKeys = [...new Set(candidates.map((edge) => edge.targetNodeKey).filter((nodeKey) => nodeKey != null))];
75855
- const persistedTargetKeys = new Set(candidateTargetKeys.length === 0 ? [] : app.db.select({ nodeKey: siteCrawlPages.nodeKey }).from(siteCrawlPages).where(and47(
75901
+ const persistedTargetKeys = new Set(candidateTargetKeys.length === 0 ? [] : app.db.select({ nodeKey: siteCrawlPages.nodeKey }).from(siteCrawlPages).where(and48(
75856
75902
  eq59(siteCrawlPages.projectId, scope.projectId),
75857
75903
  eq59(siteCrawlPages.runId, scope.runId),
75858
75904
  eq59(siteCrawlPages.attemptId, scope.attemptId),
@@ -75898,7 +75944,7 @@ async function technicalAeoRoutes(app, opts) {
75898
75944
  pathEdges.unshift(step.edge);
75899
75945
  pathKeys.unshift(step.nodeKey);
75900
75946
  }
75901
- const pathRows = app.db.select().from(siteCrawlPages).where(and47(
75947
+ const pathRows = app.db.select().from(siteCrawlPages).where(and48(
75902
75948
  eq59(siteCrawlPages.projectId, scope.projectId),
75903
75949
  eq59(siteCrawlPages.runId, scope.runId),
75904
75950
  eq59(siteCrawlPages.attemptId, scope.attemptId),
@@ -75938,13 +75984,13 @@ async function technicalAeoRoutes(app, opts) {
75938
75984
  eq59(siteCrawlSnapshots.complete, true),
75939
75985
  notProbeRun()
75940
75986
  ];
75941
- const afterTarget = request.query.toRunId ? resolveCrawl(project.id, request.query.toRunId) : app.db.select({ snapshot: siteCrawlSnapshots, runStatus: runs.status }).from(siteCrawlSnapshots).innerJoin(runs, eq59(siteCrawlSnapshots.runId, runs.id)).where(and47(...completeSnapshotFilters)).orderBy(desc25(siteCrawlSnapshots.createdAt), desc25(siteCrawlSnapshots.runId)).limit(1).get();
75987
+ const afterTarget = request.query.toRunId ? resolveCrawl(project.id, request.query.toRunId) : app.db.select({ snapshot: siteCrawlSnapshots, runStatus: runs.status }).from(siteCrawlSnapshots).innerJoin(runs, eq59(siteCrawlSnapshots.runId, runs.id)).where(and48(...completeSnapshotFilters)).orderBy(desc25(siteCrawlSnapshots.createdAt), desc25(siteCrawlSnapshots.runId)).limit(1).get();
75942
75988
  if (request.query.toRunId && !afterTarget) throw notFound("Site crawl run", request.query.toRunId);
75943
- const beforeTarget = request.query.fromRunId ? resolveCrawl(project.id, request.query.fromRunId) : afterTarget ? app.db.select({ snapshot: siteCrawlSnapshots, runStatus: runs.status }).from(siteCrawlSnapshots).innerJoin(runs, eq59(siteCrawlSnapshots.runId, runs.id)).where(and47(
75989
+ const beforeTarget = request.query.fromRunId ? resolveCrawl(project.id, request.query.fromRunId) : afterTarget ? app.db.select({ snapshot: siteCrawlSnapshots, runStatus: runs.status }).from(siteCrawlSnapshots).innerJoin(runs, eq59(siteCrawlSnapshots.runId, runs.id)).where(and48(
75944
75990
  ...completeSnapshotFilters,
75945
75991
  or13(
75946
75992
  lt10(siteCrawlSnapshots.createdAt, afterTarget.snapshot.createdAt),
75947
- and47(
75993
+ and48(
75948
75994
  eq59(siteCrawlSnapshots.createdAt, afterTarget.snapshot.createdAt),
75949
75995
  lt10(siteCrawlSnapshots.runId, afterTarget.snapshot.runId)
75950
75996
  )
@@ -76023,9 +76069,9 @@ async function technicalAeoRoutes(app, opts) {
76023
76069
  const summary2 = { pages: zero2(), links: zero2() };
76024
76070
  if (scopeFilter !== "links") {
76025
76071
  if (includeAdded || includeChanged) {
76026
- const addedExpression = includeAdded ? sql23`COALESCE(SUM(CASE WHEN previous.id IS NULL THEN 1 ELSE 0 END), 0)` : sql23`0`;
76027
- const changedExpression = includeChanged ? sql23`COALESCE(SUM(CASE WHEN previous.id IS NOT NULL AND ${PAGE_CHANGE_PREDICATE} THEN 1 ELSE 0 END), 0)` : sql23`0`;
76028
- const [counts2 = { added: 0, changed: 0 }] = app.db.all(sql23`
76072
+ const addedExpression = includeAdded ? sql24`COALESCE(SUM(CASE WHEN previous.id IS NULL THEN 1 ELSE 0 END), 0)` : sql24`0`;
76073
+ const changedExpression = includeChanged ? sql24`COALESCE(SUM(CASE WHEN previous.id IS NOT NULL AND ${PAGE_CHANGE_PREDICATE} THEN 1 ELSE 0 END), 0)` : sql24`0`;
76074
+ const [counts2 = { added: 0, changed: 0 }] = app.db.all(sql24`
76029
76075
  SELECT ${addedExpression} AS added, ${changedExpression} AS changed
76030
76076
  FROM site_crawl_pages AS current
76031
76077
  LEFT JOIN site_crawl_pages AS previous
@@ -76041,7 +76087,7 @@ async function technicalAeoRoutes(app, opts) {
76041
76087
  summary2.pages.changed = Number(counts2.changed);
76042
76088
  }
76043
76089
  if (includeRemoved) {
76044
- const [counts2 = { removed: 0 }] = app.db.all(sql23`
76090
+ const [counts2 = { removed: 0 }] = app.db.all(sql24`
76045
76091
  SELECT COUNT(*) AS removed
76046
76092
  FROM site_crawl_pages AS previous
76047
76093
  LEFT JOIN site_crawl_pages AS current
@@ -76059,9 +76105,9 @@ async function technicalAeoRoutes(app, opts) {
76059
76105
  }
76060
76106
  if (scopeFilter !== "pages") {
76061
76107
  if (includeAdded || includeChanged) {
76062
- const addedExpression = includeAdded ? sql23`COALESCE(SUM(CASE WHEN previous.id IS NULL THEN 1 ELSE 0 END), 0)` : sql23`0`;
76063
- const changedExpression = includeChanged ? sql23`COALESCE(SUM(CASE WHEN previous.id IS NOT NULL AND ${LINK_CHANGE_PREDICATE} THEN 1 ELSE 0 END), 0)` : sql23`0`;
76064
- const [counts2 = { added: 0, changed: 0 }] = app.db.all(sql23`
76108
+ const addedExpression = includeAdded ? sql24`COALESCE(SUM(CASE WHEN previous.id IS NULL THEN 1 ELSE 0 END), 0)` : sql24`0`;
76109
+ const changedExpression = includeChanged ? sql24`COALESCE(SUM(CASE WHEN previous.id IS NOT NULL AND ${LINK_CHANGE_PREDICATE} THEN 1 ELSE 0 END), 0)` : sql24`0`;
76110
+ const [counts2 = { added: 0, changed: 0 }] = app.db.all(sql24`
76065
76111
  SELECT ${addedExpression} AS added, ${changedExpression} AS changed
76066
76112
  FROM site_crawl_edges AS current
76067
76113
  LEFT JOIN site_crawl_edges AS previous
@@ -76079,7 +76125,7 @@ async function technicalAeoRoutes(app, opts) {
76079
76125
  summary2.links.changed = Number(counts2.changed);
76080
76126
  }
76081
76127
  if (includeRemoved) {
76082
- const [counts2 = { removed: 0 }] = app.db.all(sql23`
76128
+ const [counts2 = { removed: 0 }] = app.db.all(sql24`
76083
76129
  SELECT COUNT(*) AS removed
76084
76130
  FROM site_crawl_edges AS previous
76085
76131
  LEFT JOIN site_crawl_edges AS current
@@ -76109,48 +76155,48 @@ async function technicalAeoRoutes(app, opts) {
76109
76155
  const includeRemoved = changeFilter === "all" || changeFilter === "removed";
76110
76156
  const table = entity === "page" ? "site_crawl_pages" : "site_crawl_edges";
76111
76157
  const keyColumn = entity === "page" ? "node_key" : "edge_key";
76112
- const internalCurrent = entity === "link" ? sql23`AND current.internal = 1` : sql23``;
76113
- const internalPreviousJoin = entity === "link" ? sql23`AND previous.internal = 1` : sql23``;
76114
- const internalPrevious = entity === "link" ? sql23`AND previous.internal = 1` : sql23``;
76115
- const internalCurrentJoin = entity === "link" ? sql23`AND current.internal = 1` : sql23``;
76158
+ const internalCurrent = entity === "link" ? sql24`AND current.internal = 1` : sql24``;
76159
+ const internalPreviousJoin = entity === "link" ? sql24`AND previous.internal = 1` : sql24``;
76160
+ const internalPrevious = entity === "link" ? sql24`AND previous.internal = 1` : sql24``;
76161
+ const internalCurrentJoin = entity === "link" ? sql24`AND current.internal = 1` : sql24``;
76116
76162
  const difference2 = entity === "page" ? PAGE_CHANGE_PREDICATE : LINK_CHANGE_PREDICATE;
76117
- const afterKind = changeFilter === "added" ? sql23`previous.id IS NULL` : changeFilter === "changed" ? sql23`previous.id IS NOT NULL AND ${difference2}` : sql23`previous.id IS NULL OR (previous.id IS NOT NULL AND ${difference2})`;
76118
- const afterRows = includeAfter ? app.db.all(sql23`
76163
+ const afterKind = changeFilter === "added" ? sql24`previous.id IS NULL` : changeFilter === "changed" ? sql24`previous.id IS NOT NULL AND ${difference2}` : sql24`previous.id IS NULL OR (previous.id IS NOT NULL AND ${difference2})`;
76164
+ const afterRows = includeAfter ? app.db.all(sql24`
76119
76165
  SELECT ${entity} AS entity,
76120
76166
  CASE WHEN previous.id IS NULL THEN 'added' ELSE 'changed' END AS change,
76121
- current.${sql23.raw(keyColumn)} AS key
76122
- FROM ${sql23.raw(table)} AS current
76123
- LEFT JOIN ${sql23.raw(table)} AS previous
76167
+ current.${sql24.raw(keyColumn)} AS key
76168
+ FROM ${sql24.raw(table)} AS current
76169
+ LEFT JOIN ${sql24.raw(table)} AS previous
76124
76170
  ON previous.project_id = ${beforeScope.projectId}
76125
76171
  AND previous.run_id = ${beforeScope.runId}
76126
76172
  AND previous.attempt_id = ${beforeScope.attemptId}
76127
76173
  ${internalPreviousJoin}
76128
- AND previous.${sql23.raw(keyColumn)} = current.${sql23.raw(keyColumn)}
76174
+ AND previous.${sql24.raw(keyColumn)} = current.${sql24.raw(keyColumn)}
76129
76175
  WHERE current.project_id = ${afterScope.projectId}
76130
76176
  AND current.run_id = ${afterScope.runId}
76131
76177
  AND current.attempt_id = ${afterScope.attemptId}
76132
76178
  ${internalCurrent}
76133
- AND current.${sql23.raw(keyColumn)} > ${afterKey}
76179
+ AND current.${sql24.raw(keyColumn)} > ${afterKey}
76134
76180
  AND (${afterKind})
76135
- ORDER BY current.${sql23.raw(keyColumn)} ASC
76181
+ ORDER BY current.${sql24.raw(keyColumn)} ASC
76136
76182
  LIMIT ${wanted2}
76137
76183
  `) : [];
76138
- const removedRows = includeRemoved ? app.db.all(sql23`
76139
- SELECT ${entity} AS entity, 'removed' AS change, previous.${sql23.raw(keyColumn)} AS key
76140
- FROM ${sql23.raw(table)} AS previous
76141
- LEFT JOIN ${sql23.raw(table)} AS current
76184
+ const removedRows = includeRemoved ? app.db.all(sql24`
76185
+ SELECT ${entity} AS entity, 'removed' AS change, previous.${sql24.raw(keyColumn)} AS key
76186
+ FROM ${sql24.raw(table)} AS previous
76187
+ LEFT JOIN ${sql24.raw(table)} AS current
76142
76188
  ON current.project_id = ${afterScope.projectId}
76143
76189
  AND current.run_id = ${afterScope.runId}
76144
76190
  AND current.attempt_id = ${afterScope.attemptId}
76145
76191
  ${internalCurrentJoin}
76146
- AND current.${sql23.raw(keyColumn)} = previous.${sql23.raw(keyColumn)}
76192
+ AND current.${sql24.raw(keyColumn)} = previous.${sql24.raw(keyColumn)}
76147
76193
  WHERE previous.project_id = ${beforeScope.projectId}
76148
76194
  AND previous.run_id = ${beforeScope.runId}
76149
76195
  AND previous.attempt_id = ${beforeScope.attemptId}
76150
76196
  ${internalPrevious}
76151
- AND previous.${sql23.raw(keyColumn)} > ${afterKey}
76197
+ AND previous.${sql24.raw(keyColumn)} > ${afterKey}
76152
76198
  AND current.id IS NULL
76153
- ORDER BY previous.${sql23.raw(keyColumn)} ASC
76199
+ ORDER BY previous.${sql24.raw(keyColumn)} ASC
76154
76200
  LIMIT ${wanted2}
76155
76201
  `) : [];
76156
76202
  const merged = [];
@@ -76180,13 +76226,13 @@ async function technicalAeoRoutes(app, opts) {
76180
76226
  const visibleKeys = keyRows.slice(0, limit);
76181
76227
  const pageKeys = visibleKeys.filter((row) => row.entity === "page").map((row) => row.key);
76182
76228
  const linkKeys = visibleKeys.filter((row) => row.entity === "link").map((row) => row.key);
76183
- const pageRowsFor = (scope) => pageKeys.length === 0 ? [] : app.db.select().from(siteCrawlPages).where(and47(
76229
+ const pageRowsFor = (scope) => pageKeys.length === 0 ? [] : app.db.select().from(siteCrawlPages).where(and48(
76184
76230
  eq59(siteCrawlPages.projectId, scope.projectId),
76185
76231
  eq59(siteCrawlPages.runId, scope.runId),
76186
76232
  eq59(siteCrawlPages.attemptId, scope.attemptId),
76187
76233
  inArray20(siteCrawlPages.nodeKey, pageKeys)
76188
76234
  )).all();
76189
- const edgeRowsFor = (scope) => linkKeys.length === 0 ? [] : app.db.select().from(siteCrawlEdges).where(and47(
76235
+ const edgeRowsFor = (scope) => linkKeys.length === 0 ? [] : app.db.select().from(siteCrawlEdges).where(and48(
76190
76236
  eq59(siteCrawlEdges.projectId, scope.projectId),
76191
76237
  eq59(siteCrawlEdges.runId, scope.runId),
76192
76238
  eq59(siteCrawlEdges.attemptId, scope.attemptId),
@@ -76332,7 +76378,7 @@ async function technicalAeoRoutes(app, opts) {
76332
76378
  const orderBy = request.query.sort === "score-desc" ? [desc25(siteCrawlPages.auditScore), asc10(siteCrawlPages.nodeKey)] : request.query.sort === "score-asc" ? [asc10(siteCrawlPages.auditScore), asc10(siteCrawlPages.nodeKey)] : request.query.sort === "path" ? [asc10(siteCrawlPages.path), asc10(siteCrawlPages.nodeKey)] : [asc10(siteCrawlPages.url), asc10(siteCrawlPages.nodeKey)];
76333
76379
  let healthStateFilter = null;
76334
76380
  if (healthState) {
76335
- const legacyRow = app.db.select({ id: siteCrawlPages.id }).from(siteCrawlPages).where(and47(
76381
+ const legacyRow = app.db.select({ id: siteCrawlPages.id }).from(siteCrawlPages).where(and48(
76336
76382
  eq59(siteCrawlPages.projectId, project.id),
76337
76383
  eq59(siteCrawlPages.runId, snapshot.runId),
76338
76384
  eq59(siteCrawlPages.attemptId, snapshot.attemptId),
@@ -76352,7 +76398,7 @@ async function technicalAeoRoutes(app, opts) {
76352
76398
  pages: []
76353
76399
  };
76354
76400
  }
76355
- const where = and47(...filters);
76401
+ const where = and48(...filters);
76356
76402
  const total = app.db.select({ value: count() }).from(siteCrawlPages).where(where).get()?.value ?? 0;
76357
76403
  const rows = app.db.select().from(siteCrawlPages).where(where).orderBy(...orderBy).limit(limit).offset(offset).all();
76358
76404
  const nextOffset = offset + rows.length;
@@ -76383,7 +76429,7 @@ async function technicalAeoRoutes(app, opts) {
76383
76429
  url: siteCrawlPages.url,
76384
76430
  inventoryEligible: siteCrawlPages.inventoryEligible,
76385
76431
  fetchState: siteCrawlPages.fetchState
76386
- }).from(siteCrawlPages).where(and47(
76432
+ }).from(siteCrawlPages).where(and48(
76387
76433
  eq59(siteCrawlPages.projectId, project.id),
76388
76434
  eq59(siteCrawlPages.runId, snapshot.runId),
76389
76435
  eq59(siteCrawlPages.attemptId, snapshot.attemptId)
@@ -76475,7 +76521,7 @@ async function technicalAeoRoutes(app, opts) {
76475
76521
  if (request.query.targetUrl) filters.push(eq59(siteCrawlEdges.targetUrl, request.query.targetUrl));
76476
76522
  const followable = parseBoolean2(request.query.followable);
76477
76523
  if (followable != null) filters.push(eq59(siteCrawlEdges.followable, followable));
76478
- const where = and47(...filters);
76524
+ const where = and48(...filters);
76479
76525
  const total = app.db.select({ value: count() }).from(siteCrawlEdges).where(where).get()?.value ?? 0;
76480
76526
  const limit = parseBoundedLimit(request.query.limit, 100, 200);
76481
76527
  const offset = decodeCursor(request.query.cursor);
@@ -76542,8 +76588,8 @@ async function technicalAeoRoutes(app, opts) {
76542
76588
  const inboundMatch = request.query.nodeKey && request.query.url ? or13(eq59(siteCrawlEdges.targetNodeKey, request.query.nodeKey), eq59(siteCrawlEdges.targetUrl, request.query.url)) : request.query.nodeKey ? eq59(siteCrawlEdges.targetNodeKey, request.query.nodeKey) : eq59(siteCrawlEdges.targetUrl, request.query.url);
76543
76589
  const outboundMatch = request.query.nodeKey && request.query.url ? or13(eq59(siteCrawlEdges.sourceNodeKey, request.query.nodeKey), eq59(siteCrawlEdges.sourceUrl, request.query.url)) : request.query.nodeKey ? eq59(siteCrawlEdges.sourceNodeKey, request.query.nodeKey) : eq59(siteCrawlEdges.sourceUrl, request.query.url);
76544
76590
  const limit = parseBoundedLimit(request.query.limit, 50, 100);
76545
- const inboundRows = app.db.select().from(siteCrawlEdges).where(and47(...scope, inboundMatch)).orderBy(asc10(siteCrawlEdges.edgeKey)).limit(limit + 1).all();
76546
- const outboundRows = app.db.select().from(siteCrawlEdges).where(and47(...scope, outboundMatch)).orderBy(asc10(siteCrawlEdges.edgeKey)).limit(limit + 1).all();
76591
+ const inboundRows = app.db.select().from(siteCrawlEdges).where(and48(...scope, inboundMatch)).orderBy(asc10(siteCrawlEdges.edgeKey)).limit(limit + 1).all();
76592
+ const outboundRows = app.db.select().from(siteCrawlEdges).where(and48(...scope, outboundMatch)).orderBy(asc10(siteCrawlEdges.edgeKey)).limit(limit + 1).all();
76547
76593
  return {
76548
76594
  project: project.name,
76549
76595
  hasCrawlData: true,
@@ -76576,7 +76622,7 @@ async function technicalAeoRoutes(app, opts) {
76576
76622
  if (!snapshot.attemptId) {
76577
76623
  return { project: project.name, runId: snapshot.runId, state: "partial", checkDeadLinks: true, checked: snapshot.deadLinksChecked, found: snapshot.deadLinksFound, unverified: snapshot.deadLinksUnverified, total: 0, nextCursor: null, deadLinks: [] };
76578
76624
  }
76579
- const where = and47(
76625
+ const where = and48(
76580
76626
  eq59(siteCrawlFindings.projectId, project.id),
76581
76627
  eq59(siteCrawlFindings.runId, snapshot.runId),
76582
76628
  eq59(siteCrawlFindings.attemptId, snapshot.attemptId),
@@ -76590,7 +76636,7 @@ async function technicalAeoRoutes(app, opts) {
76590
76636
  // a fabricated broken link shown to a client is not worth the saved
76591
76637
  // predicate. Applied to `total` as well as the rows, or the count would
76592
76638
  // promise a page the list cannot fill.
76593
- isNotNull3(sql23`json_extract(${siteCrawlFindings.evidence}, '$.statusCode')`)
76639
+ isNotNull3(sql24`json_extract(${siteCrawlFindings.evidence}, '$.statusCode')`)
76594
76640
  );
76595
76641
  const total = app.db.select({ value: count() }).from(siteCrawlFindings).where(where).get()?.value ?? 0;
76596
76642
  const limit = parseBoundedLimit(request.query.limit, 100, 200);
@@ -76629,13 +76675,13 @@ async function technicalAeoRoutes(app, opts) {
76629
76675
  createdAt: runs.createdAt,
76630
76676
  startedAt: runs.startedAt,
76631
76677
  finishedAt: runs.finishedAt
76632
- }).from(runs).where(and47(
76678
+ }).from(runs).where(and48(
76633
76679
  eq59(runs.projectId, project.id),
76634
76680
  eq59(runs.kind, RunKinds["site-audit"]),
76635
76681
  notProbeRun()
76636
76682
  )).orderBy(desc25(runs.createdAt), desc25(runs.id)).limit(limit).all();
76637
76683
  const runIds = rows.map((row) => row.runId);
76638
- const crawlRunIds = new Set(runIds.length === 0 ? [] : app.db.select({ runId: siteCrawlSnapshots.runId }).from(siteCrawlSnapshots).innerJoin(runs, eq59(siteCrawlSnapshots.runId, runs.id)).where(and47(
76684
+ const crawlRunIds = new Set(runIds.length === 0 ? [] : app.db.select({ runId: siteCrawlSnapshots.runId }).from(siteCrawlSnapshots).innerJoin(runs, eq59(siteCrawlSnapshots.runId, runs.id)).where(and48(
76639
76685
  eq59(siteCrawlSnapshots.projectId, project.id),
76640
76686
  eq59(runs.projectId, project.id),
76641
76687
  eq59(runs.kind, RunKinds["site-audit"]),
@@ -76654,18 +76700,18 @@ async function technicalAeoRoutes(app, opts) {
76654
76700
  });
76655
76701
  app.get("/projects/:name/technical-aeo/runs/:runId/progress", async (request) => {
76656
76702
  const project = resolveProject(app.db, request.params.name);
76657
- const run = app.db.select().from(runs).where(and47(
76703
+ const run = app.db.select().from(runs).where(and48(
76658
76704
  eq59(runs.id, request.params.runId),
76659
76705
  eq59(runs.projectId, project.id),
76660
76706
  eq59(runs.kind, RunKinds["site-audit"]),
76661
76707
  notProbeRun()
76662
76708
  )).get();
76663
76709
  if (!run) throw notFound("Site audit run", request.params.runId);
76664
- const attempt = app.db.select().from(siteCrawlAttempts).where(and47(
76710
+ const attempt = app.db.select().from(siteCrawlAttempts).where(and48(
76665
76711
  eq59(siteCrawlAttempts.projectId, project.id),
76666
76712
  eq59(siteCrawlAttempts.runId, run.id)
76667
76713
  )).orderBy(desc25(siteCrawlAttempts.attemptNumber), desc25(siteCrawlAttempts.updatedAt)).limit(1).get();
76668
- const persistedLayout = attempt ? app.db.select().from(siteCrawlGraphLayouts).where(and47(
76714
+ const persistedLayout = attempt ? app.db.select().from(siteCrawlGraphLayouts).where(and48(
76669
76715
  eq59(siteCrawlGraphLayouts.projectId, project.id),
76670
76716
  eq59(siteCrawlGraphLayouts.runId, run.id),
76671
76717
  eq59(siteCrawlGraphLayouts.attemptId, attempt.id)
@@ -76701,14 +76747,14 @@ async function technicalAeoRoutes(app, opts) {
76701
76747
  app.get("/projects/:name/technical-aeo/runs/:runId/page-health-preview", async (request) => app.db.transaction((tx) => {
76702
76748
  const project = tx.select().from(projects).where(eq59(projects.name, request.params.name)).get();
76703
76749
  if (!project) throw notFound("Project", request.params.name);
76704
- const run = tx.select().from(runs).where(and47(
76750
+ const run = tx.select().from(runs).where(and48(
76705
76751
  eq59(runs.id, request.params.runId),
76706
76752
  eq59(runs.projectId, project.id),
76707
76753
  eq59(runs.kind, RunKinds["site-audit"]),
76708
76754
  notProbeRun()
76709
76755
  )).get();
76710
76756
  if (!run) throw notFound("Site audit run", request.params.runId);
76711
- const attempt = tx.select().from(siteCrawlAttempts).where(and47(
76757
+ const attempt = tx.select().from(siteCrawlAttempts).where(and48(
76712
76758
  eq59(siteCrawlAttempts.projectId, project.id),
76713
76759
  eq59(siteCrawlAttempts.runId, run.id)
76714
76760
  )).orderBy(desc25(siteCrawlAttempts.attemptNumber), desc25(siteCrawlAttempts.updatedAt)).limit(1).get();
@@ -76724,7 +76770,7 @@ async function technicalAeoRoutes(app, opts) {
76724
76770
  if (!attempt) {
76725
76771
  return { ...base, pagesAudited: 0, examples: [] };
76726
76772
  }
76727
- const auditedWhere = and47(
76773
+ const auditedWhere = and48(
76728
76774
  eq59(siteCrawlPages.projectId, project.id),
76729
76775
  eq59(siteCrawlPages.runId, run.id),
76730
76776
  eq59(siteCrawlPages.attemptId, attempt.id),
@@ -76739,7 +76785,7 @@ async function technicalAeoRoutes(app, opts) {
76739
76785
  url: siteCrawlPages.url,
76740
76786
  auditScore: siteCrawlPages.auditScore,
76741
76787
  auditFields: siteCrawlPages.auditFields
76742
- }).from(siteCrawlPages).where(and47(
76788
+ }).from(siteCrawlPages).where(and48(
76743
76789
  auditedWhere,
76744
76790
  isNotNull3(siteCrawlPages.auditScore),
76745
76791
  lt10(siteCrawlPages.auditScore, 70)
@@ -76775,10 +76821,10 @@ async function technicalAeoRoutes(app, opts) {
76775
76821
  status: runs.status,
76776
76822
  identityKey: siteCrawlRunRequests.identityKey,
76777
76823
  effectiveOptions: siteCrawlRunRequests.effectiveOptions
76778
- }).from(runs).leftJoin(siteCrawlRunRequests, and47(
76824
+ }).from(runs).leftJoin(siteCrawlRunRequests, and48(
76779
76825
  eq59(siteCrawlRunRequests.projectId, runs.projectId),
76780
76826
  eq59(siteCrawlRunRequests.runId, runs.id)
76781
- )).where(and47(
76827
+ )).where(and48(
76782
76828
  eq59(runs.projectId, project.id),
76783
76829
  eq59(runs.kind, RunKinds["site-audit"]),
76784
76830
  inArray20(runs.status, [RunStatuses.queued, RunStatuses.running])
@@ -76832,7 +76878,7 @@ async function technicalAeoRoutes(app, opts) {
76832
76878
 
76833
76879
  // ../api-routes/src/research.ts
76834
76880
  import crypto47 from "crypto";
76835
- import { and as and48, desc as desc26, eq as eq60 } from "drizzle-orm";
76881
+ import { and as and49, desc as desc26, eq as eq60 } from "drizzle-orm";
76836
76882
  var sameLocation = (a, b) => a.label === b.label && a.city === b.city && a.region === b.region && a.country === b.country && a.timezone === b.timezone;
76837
76883
  async function researchRoutes(app, opts) {
76838
76884
  app.post("/projects/:name/research/runs", async (request, reply) => {
@@ -76862,7 +76908,7 @@ async function researchRoutes(app, opts) {
76862
76908
  const now = (/* @__PURE__ */ new Date()).toISOString();
76863
76909
  const decision = app.db.transaction((tx) => {
76864
76910
  if (input.idempotencyKey) {
76865
- const existing = tx.select().from(researchRuns).where(and48(eq60(researchRuns.projectId, project.id), eq60(researchRuns.idempotencyKey, input.idempotencyKey))).get();
76911
+ const existing = tx.select().from(researchRuns).where(and49(eq60(researchRuns.projectId, project.id), eq60(researchRuns.idempotencyKey, input.idempotencyKey))).get();
76866
76912
  if (existing) {
76867
76913
  if (existing.requestHash !== requestHash2) throw alreadyExists("Research idempotency key", input.idempotencyKey);
76868
76914
  return { reused: true, id: existing.id, shouldDispatch: existing.status === ResearchRunStatuses.queued };
@@ -76892,7 +76938,7 @@ async function researchRoutes(app, opts) {
76892
76938
  });
76893
76939
  }
76894
76940
  function getDetail(app, projectId, id) {
76895
- const row = app.db.select().from(researchRuns).where(and48(eq60(researchRuns.id, id), eq60(researchRuns.projectId, projectId))).get();
76941
+ const row = app.db.select().from(researchRuns).where(and49(eq60(researchRuns.id, id), eq60(researchRuns.projectId, projectId))).get();
76896
76942
  if (!row) throw notFound("Research run", id);
76897
76943
  const queries2 = app.db.select().from(researchRunQueries).where(eq60(researchRunQueries.researchRunId, id)).orderBy(researchRunQueries.position).all().map(serializeQuery);
76898
76944
  return { ...serializeRun(row), queries: queries2 };
@@ -77610,7 +77656,7 @@ var IntelligenceService = class {
77610
77656
  */
77611
77657
  analyzeAndPersist(runId, projectId) {
77612
77658
  const recentRuns = this.db.select().from(runs).where(
77613
- and49(
77659
+ and50(
77614
77660
  eq61(runs.projectId, projectId),
77615
77661
  or14(eq61(runs.status, "completed"), eq61(runs.status, "partial")),
77616
77662
  // Defensive: RunCoordinator already skips probes before this is
@@ -77710,7 +77756,7 @@ var IntelligenceService = class {
77710
77756
  }
77711
77757
  const windowStart = runRow.startedAt ?? runRow.createdAt;
77712
77758
  const windowEnd = runRow.finishedAt ?? (/* @__PURE__ */ new Date()).toISOString();
77713
- const selected = this.db.select().from(gbpLocations).where(and49(
77759
+ const selected = this.db.select().from(gbpLocations).where(and50(
77714
77760
  eq61(gbpLocations.projectId, projectId),
77715
77761
  eq61(gbpLocations.selected, true),
77716
77762
  gte14(gbpLocations.syncedAt, windowStart),
@@ -77747,12 +77793,12 @@ var IntelligenceService = class {
77747
77793
  }
77748
77794
  /** Build the per-location signal bundle the GBP analyzer consumes. */
77749
77795
  buildGbpLocationSignals(projectId, locationName, displayName, fallbackDate) {
77750
- const metricRows = this.db.select({ metric: gbpDailyMetrics.metric, date: gbpDailyMetrics.date, value: gbpDailyMetrics.value }).from(gbpDailyMetrics).where(and49(eq61(gbpDailyMetrics.projectId, projectId), eq61(gbpDailyMetrics.locationName, locationName))).all();
77751
- const placeActionRows = this.db.select({ placeActionType: gbpPlaceActions.placeActionType, providerType: gbpPlaceActions.providerType }).from(gbpPlaceActions).where(and49(eq61(gbpPlaceActions.projectId, projectId), eq61(gbpPlaceActions.locationName, locationName))).all();
77752
- const lodgingRow = this.db.select({ populatedGroupCount: gbpLodgingSnapshots.populatedGroupCount }).from(gbpLodgingSnapshots).where(and49(eq61(gbpLodgingSnapshots.projectId, projectId), eq61(gbpLodgingSnapshots.locationName, locationName))).orderBy(desc27(gbpLodgingSnapshots.syncedAt)).limit(1).get();
77753
- const ownerRow = this.db.select({ description: gbpLocations.description }).from(gbpLocations).where(and49(eq61(gbpLocations.projectId, projectId), eq61(gbpLocations.locationName, locationName))).get();
77796
+ const metricRows = this.db.select({ metric: gbpDailyMetrics.metric, date: gbpDailyMetrics.date, value: gbpDailyMetrics.value }).from(gbpDailyMetrics).where(and50(eq61(gbpDailyMetrics.projectId, projectId), eq61(gbpDailyMetrics.locationName, locationName))).all();
77797
+ const placeActionRows = this.db.select({ placeActionType: gbpPlaceActions.placeActionType, providerType: gbpPlaceActions.providerType }).from(gbpPlaceActions).where(and50(eq61(gbpPlaceActions.projectId, projectId), eq61(gbpPlaceActions.locationName, locationName))).all();
77798
+ const lodgingRow = this.db.select({ populatedGroupCount: gbpLodgingSnapshots.populatedGroupCount }).from(gbpLodgingSnapshots).where(and50(eq61(gbpLodgingSnapshots.projectId, projectId), eq61(gbpLodgingSnapshots.locationName, locationName))).orderBy(desc27(gbpLodgingSnapshots.syncedAt)).limit(1).get();
77799
+ const ownerRow = this.db.select({ description: gbpLocations.description }).from(gbpLocations).where(and50(eq61(gbpLocations.projectId, projectId), eq61(gbpLocations.locationName, locationName))).get();
77754
77800
  const descriptionMissing = !(ownerRow?.description ?? "").trim();
77755
- const placeRow = this.db.select({ attributes: gbpPlaceDetails.attributes }).from(gbpPlaceDetails).where(and49(eq61(gbpPlaceDetails.projectId, projectId), eq61(gbpPlaceDetails.locationName, locationName))).orderBy(desc27(gbpPlaceDetails.syncedAt)).limit(1).get();
77801
+ const placeRow = this.db.select({ attributes: gbpPlaceDetails.attributes }).from(gbpPlaceDetails).where(and50(eq61(gbpPlaceDetails.projectId, projectId), eq61(gbpPlaceDetails.locationName, locationName))).orderBy(desc27(gbpPlaceDetails.syncedAt)).limit(1).get();
77756
77802
  const placesAmenities = placeRow ? extractPlaceAmenities(placeRow.attributes) : [];
77757
77803
  const summary = buildGbpSummary({
77758
77804
  locationName,
@@ -77788,7 +77834,7 @@ var IntelligenceService = class {
77788
77834
  /** Build the month-over-month keyword series for a location from the
77789
77835
  * accumulating gbp_keyword_monthly table (latest complete month vs prior). */
77790
77836
  buildGbpKeywordTrend(projectId, locationName) {
77791
- const rows = this.db.select({ month: gbpKeywordMonthly.month, keyword: gbpKeywordMonthly.keyword, valueCount: gbpKeywordMonthly.valueCount }).from(gbpKeywordMonthly).where(and49(eq61(gbpKeywordMonthly.projectId, projectId), eq61(gbpKeywordMonthly.locationName, locationName))).all();
77837
+ const rows = this.db.select({ month: gbpKeywordMonthly.month, keyword: gbpKeywordMonthly.keyword, valueCount: gbpKeywordMonthly.valueCount }).from(gbpKeywordMonthly).where(and50(eq61(gbpKeywordMonthly.projectId, projectId), eq61(gbpKeywordMonthly.locationName, locationName))).all();
77792
77838
  if (rows.length === 0) return { recentMonth: null, priorMonth: null, points: [] };
77793
77839
  const months = [...new Set(rows.map((r) => r.month))].sort().reverse();
77794
77840
  const recentMonth = months[0] ?? null;
@@ -77819,7 +77865,7 @@ var IntelligenceService = class {
77819
77865
  */
77820
77866
  persistGbpInsights(runId, projectId, gbpInsights, coveredLocationNames) {
77821
77867
  const covered = new Set(coveredLocationNames);
77822
- const existing = this.db.select({ id: insights.id, dismissed: insights.dismissed }).from(insights).where(and49(eq61(insights.projectId, projectId), eq61(insights.provider, GBP_INSIGHT_PROVIDER))).all();
77868
+ const existing = this.db.select({ id: insights.id, dismissed: insights.dismissed }).from(insights).where(and50(eq61(insights.projectId, projectId), eq61(insights.provider, GBP_INSIGHT_PROVIDER))).all();
77823
77869
  const staleIds = [];
77824
77870
  const dismissedSlots = /* @__PURE__ */ new Set();
77825
77871
  for (const row of existing) {
@@ -77929,7 +77975,7 @@ var IntelligenceService = class {
77929
77975
  sinceTimestamp = parsed;
77930
77976
  }
77931
77977
  const allRuns = this.db.select().from(runs).where(
77932
- and49(
77978
+ and50(
77933
77979
  eq61(runs.projectId, project.id),
77934
77980
  or14(eq61(runs.status, "completed"), eq61(runs.status, "partial")),
77935
77981
  // Backfill must not replay probe runs as if they were real sweeps.
@@ -78106,7 +78152,7 @@ var IntelligenceService = class {
78106
78152
  );
78107
78153
  const ROWS_PER_GROUP_BUDGET = Math.max(2, locationCount);
78108
78154
  const recentRunRows = this.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(
78109
- and49(
78155
+ and50(
78110
78156
  eq61(runs.projectId, projectId),
78111
78157
  eq61(runs.kind, RunKinds["answer-visibility"]),
78112
78158
  or14(eq61(runs.status, "completed"), eq61(runs.status, "partial")),
@@ -78129,7 +78175,7 @@ var IntelligenceService = class {
78129
78175
  const haveHistory = recentRunIds.length > 0;
78130
78176
  const priorRegressionsByPair = /* @__PURE__ */ new Map();
78131
78177
  if (haveHistory) {
78132
- const priorRows = this.db.select({ query: insights.query, provider: insights.provider, runId: insights.runId }).from(insights).where(and49(eq61(insights.type, "regression"), inArray21(insights.runId, recentRunIds))).all();
78178
+ const priorRows = this.db.select({ query: insights.query, provider: insights.provider, runId: insights.runId }).from(insights).where(and50(eq61(insights.type, "regression"), inArray21(insights.runId, recentRunIds))).all();
78133
78179
  const regressionGroups = /* @__PURE__ */ new Map();
78134
78180
  for (const row of priorRows) {
78135
78181
  if (!row.runId) continue;