@canonry/canonry 4.133.1 → 4.133.3

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/canonry-cli.md +7 -0
  2. package/assets/assets/{AuditHistoryPanel-BKJ_bJO3.js → AuditHistoryPanel-DTHQGvkW.js} +1 -1
  3. package/assets/assets/{BacklinksPage-Dlp78T7O.js → BacklinksPage-DuPI3wt9.js} +1 -1
  4. package/assets/assets/{ChartPrimitives-BnqLVaHC.js → ChartPrimitives-T8mxOObc.js} +1 -1
  5. package/assets/assets/{HistoryPage-dEjboZIm.js → HistoryPage-T1W40xKG.js} +1 -1
  6. package/assets/assets/ProjectPage-DYwM8-Rp.js +8 -0
  7. package/assets/assets/{RunRow-C0PeLbDh.js → RunRow-nHr4wW9B.js} +1 -1
  8. package/assets/assets/{RunsPage-8cmHsMEV.js → RunsPage-Cbusy_84.js} +1 -1
  9. package/assets/assets/{SettingsPage-FzWCV54A.js → SettingsPage-BVcbl4gn.js} +1 -1
  10. package/assets/assets/{TrafficPage-BrEuU4K9.js → TrafficPage-CZ4NTWI6.js} +1 -1
  11. package/assets/assets/{TrafficSourceDetailPage-yqyQGzqQ.js → TrafficSourceDetailPage-xW-KvZY1.js} +1 -1
  12. package/assets/assets/{arrow-left-DJbzrqwz.js → arrow-left-flskyFPK.js} +1 -1
  13. package/assets/assets/{extract-error-message-7lcxZroQ.js → extract-error-message-BHfCTm0H.js} +1 -1
  14. package/assets/assets/{index-DtOyJ_1v.js → index-CQzGDGMB.js} +64 -64
  15. package/assets/assets/index-JhX-wfQO.css +1 -0
  16. package/assets/assets/{trash-2-DFJYR1Fq.js → trash-2-LGfqtSzZ.js} +1 -1
  17. package/assets/index.html +2 -2
  18. package/dist/{chunk-42P7POVS.js → chunk-6ON6GUAL.js} +9 -5
  19. package/dist/{chunk-P4MIG7V5.js → chunk-A6BYMSZL.js} +30 -2
  20. package/dist/{chunk-VPY3PZXV.js → chunk-HENMGNLT.js} +344 -59
  21. package/dist/{chunk-ZPQX5ZQ2.js → chunk-YRRQFOAH.js} +92 -0
  22. package/dist/cli.js +45 -4
  23. package/dist/index.js +4 -4
  24. package/dist/{intelligence-service-2K7GVEQM.js → intelligence-service-OSLFG5S2.js} +2 -2
  25. package/dist/mcp.js +2 -2
  26. package/package.json +8 -8
  27. package/assets/assets/ProjectPage-CV1zK5No.js +0 -8
  28. package/assets/assets/index-BKoAGOtU.css +0 -1
@@ -8,10 +8,16 @@ import {
8
8
  AdsActivationEntityTypes,
9
9
  AdsActivationGrantStates,
10
10
  AdsActivationVersionPolicies,
11
+ AdsActivityAssessmentStates,
11
12
  AdsAdGroupBillingEventTypes,
12
13
  AdsCampaignBiddingTypes,
14
+ AdsDeliveryConfigurationBases,
15
+ AdsDeliverySnapshotIssues,
16
+ AdsDeliverySnapshotStatuses,
13
17
  AdsEntityStatuses,
14
18
  AdsEntityTypes,
19
+ AdsHistoricalCampaignRollupStatuses,
20
+ AdsInsightLevels,
15
21
  AdsIntegrityDecisions,
16
22
  AdsOperationKinds,
17
23
  AdsOperationStates,
@@ -83,6 +89,7 @@ import {
83
89
  adsConversionPixelListResponseSchema,
84
90
  adsCpcMicros,
85
91
  adsCtr,
92
+ adsDeliveryDiagnosticsDtoSchema,
86
93
  adsDisconnectResponseSchema,
87
94
  adsGeoSearchQuerySchema,
88
95
  adsGeoSearchResponseSchema,
@@ -349,10 +356,10 @@ import {
349
356
  wordpressSchemaDeployResultDtoSchema,
350
357
  wordpressSchemaStatusResultDtoSchema,
351
358
  wordpressStatusDtoSchema
352
- } from "./chunk-ZPQX5ZQ2.js";
359
+ } from "./chunk-YRRQFOAH.js";
353
360
 
354
361
  // src/intelligence-service.ts
355
- import { eq as eq44, desc as desc20, asc as asc9, and as and35, ne as ne6, or as or10, inArray as inArray15, gte as gte12, lte as lte8 } from "drizzle-orm";
362
+ import { eq as eq44, desc as desc21, asc as asc9, and as and35, ne as ne6, or as or10, inArray as inArray15, gte as gte12, lte as lte8 } from "drizzle-orm";
356
363
 
357
364
  // ../db/src/client.ts
358
365
  import { mkdirSync } from "fs";
@@ -15267,22 +15274,48 @@ function sumSearchRows(rows) {
15267
15274
  zero()
15268
15275
  );
15269
15276
  }
15277
+ var classifyVerificationStatus = (status) => {
15278
+ if (status === VerificationStatuses.verified) return "verified";
15279
+ if (status === VerificationStatuses.claimed_unverified) return "claimedUnverified";
15280
+ if (status === VerificationStatuses.unknown_ai_like) return "unknownAiLike";
15281
+ return null;
15282
+ };
15283
+ var emptyVerificationCounts = () => ({
15284
+ verified: 0,
15285
+ claimedUnverified: 0,
15286
+ unknownAiLike: 0
15287
+ });
15288
+ function summarizeVerificationHits(rows) {
15289
+ const counts2 = emptyVerificationCounts();
15290
+ let unsupportedRows = 0;
15291
+ let unsupportedHits = 0;
15292
+ for (const row of rows) {
15293
+ const tier = classifyVerificationStatus(row.verificationStatus);
15294
+ if (!tier) {
15295
+ unsupportedRows += 1;
15296
+ unsupportedHits += row.hits;
15297
+ continue;
15298
+ }
15299
+ counts2[tier] += row.hits;
15300
+ }
15301
+ return { counts: counts2, unsupportedRows, unsupportedHits };
15302
+ }
15270
15303
  function summarizeServer(crawlers, fetches, referrals) {
15271
15304
  const total = referrals.reduce((count2, row) => count2 + row.sessionsOrHits, 0);
15272
15305
  const paid = referrals.reduce((count2, row) => count2 + row.paidSessionsOrHits, 0);
15273
15306
  const organic = referrals.reduce((count2, row) => count2 + row.organicSessionsOrHits, 0);
15307
+ const crawlerHits = summarizeVerificationHits(crawlers);
15308
+ const userFetchHits = summarizeVerificationHits(fetches);
15274
15309
  return {
15275
- crawlerHits: {
15276
- verified: crawlers.filter((row) => row.verificationStatus === VerificationStatuses.verified).reduce((count2, row) => count2 + row.hits, 0),
15277
- claimedUnverified: crawlers.filter((row) => row.verificationStatus === VerificationStatuses.claimed_unverified).reduce((count2, row) => count2 + row.hits, 0),
15278
- unknownAiLike: crawlers.filter((row) => row.verificationStatus === VerificationStatuses.unknown_ai_like).reduce((count2, row) => count2 + row.hits, 0)
15279
- },
15280
- userFetchHits: {
15281
- verified: fetches.filter((row) => row.verificationStatus === VerificationStatuses.verified).reduce((count2, row) => count2 + row.hits, 0),
15282
- claimedUnverified: fetches.filter((row) => row.verificationStatus === VerificationStatuses.claimed_unverified).reduce((count2, row) => count2 + row.hits, 0),
15283
- unknownAiLike: fetches.filter((row) => row.verificationStatus === VerificationStatuses.unknown_ai_like).reduce((count2, row) => count2 + row.hits, 0)
15310
+ summary: {
15311
+ crawlerHits: crawlerHits.counts,
15312
+ userFetchHits: userFetchHits.counts,
15313
+ referralSessions: { total, paid, organic, unknown: Math.max(0, total - paid - organic) }
15284
15314
  },
15285
- referralSessions: { total, paid, organic, unknown: Math.max(0, total - paid - organic) }
15315
+ unsupportedVerification: {
15316
+ rows: crawlerHits.unsupportedRows + userFetchHits.unsupportedRows,
15317
+ hits: crawlerHits.unsupportedHits + userFetchHits.unsupportedHits
15318
+ }
15286
15319
  };
15287
15320
  }
15288
15321
  function comparisonDetail(latest, prior) {
@@ -15476,7 +15509,8 @@ function buildOrganicEvidence(db, projectName, periodDays) {
15476
15509
  const crawlers = allCrawlers.filter((row) => serverInWindow(row.tsHour));
15477
15510
  const fetches = allFetches.filter((row) => serverInWindow(row.tsHour));
15478
15511
  const referrals = allReferrals.filter((row) => serverInWindow(row.tsHour));
15479
- const server = serverSources.length ? summarizeServer(crawlers, fetches, referrals) : null;
15512
+ const serverSummary = summarizeServer(crawlers, fetches, referrals);
15513
+ const server = serverSources.length ? serverSummary.summary : null;
15480
15514
  const latest = db.select().from(runs).where(and14(
15481
15515
  eq18(runs.projectId, project.id),
15482
15516
  eq18(runs.kind, RunKinds["answer-visibility"]),
@@ -15523,16 +15557,16 @@ function buildOrganicEvidence(db, projectName, periodDays) {
15523
15557
  ensurePage(row.landingPageNormalized ?? row.landingPage).ga4OrganicSessions += row.sessions;
15524
15558
  }
15525
15559
  for (const row of crawlers) {
15560
+ const tier = classifyVerificationStatus(row.verificationStatus);
15561
+ if (!tier) continue;
15526
15562
  const counts2 = ensurePage(row.pathNormalized).server.crawlerHits;
15527
- if (row.verificationStatus === VerificationStatuses.verified) counts2.verified += row.hits;
15528
- else if (row.verificationStatus === VerificationStatuses.claimed_unverified) counts2.claimedUnverified += row.hits;
15529
- else counts2.unknownAiLike += row.hits;
15563
+ counts2[tier] += row.hits;
15530
15564
  }
15531
15565
  for (const row of fetches) {
15566
+ const tier = classifyVerificationStatus(row.verificationStatus);
15567
+ if (!tier) continue;
15532
15568
  const counts2 = ensurePage(row.pathNormalized).server.userFetchHits;
15533
- if (row.verificationStatus === VerificationStatuses.verified) counts2.verified += row.hits;
15534
- else if (row.verificationStatus === VerificationStatuses.claimed_unverified) counts2.claimedUnverified += row.hits;
15535
- else counts2.unknownAiLike += row.hits;
15569
+ counts2[tier] += row.hits;
15536
15570
  }
15537
15571
  for (const row of referrals) {
15538
15572
  const counts2 = ensurePage(row.landingPathNormalized).server.referralSessions;
@@ -15567,10 +15601,10 @@ function buildOrganicEvidence(db, projectName, periodDays) {
15567
15601
  }
15568
15602
  const latestGa = ga4?.cohorts.at(-1);
15569
15603
  const priorGa = ga4?.cohorts.at(-2);
15570
- if (ga4 && latestGa && priorGa) {
15604
+ if (ga4 && latestGa && priorGa && latestGa.organicSessions !== priorGa.organicSessions) {
15571
15605
  findings.push({
15572
15606
  tone: "neutral",
15573
- title: "Organic sessions remain a separate outcome",
15607
+ title: "Organic sessions changed",
15574
15608
  detail: `GA4 organic sessions were ${comparisonDetail(latestGa.organicSessions, priorGa.organicSessions)}; visibility alone does not establish lead impact.`
15575
15609
  });
15576
15610
  }
@@ -15674,6 +15708,12 @@ function buildOrganicEvidence(db, projectName, periodDays) {
15674
15708
  detail: "Claimed-unverified and heuristic AI requests are user-agent evidence without operator IP verification and are reported separately from verified requests."
15675
15709
  });
15676
15710
  }
15711
+ if (serverSummary.unsupportedVerification.rows > 0) {
15712
+ limitations.push({
15713
+ code: "unsupported-server-verification-status",
15714
+ detail: `Skipped ${serverSummary.unsupportedVerification.hits} server hits across ${serverSummary.unsupportedVerification.rows} rows with unsupported verification statuses; they are excluded from all verification tiers.`
15715
+ });
15716
+ }
15677
15717
  if (visibility && visibility.ageDays > 30) {
15678
15718
  limitations.push({
15679
15719
  code: "stale-visibility-sweep",
@@ -17346,6 +17386,7 @@ var SCHEMA_TABLE = {
17346
17386
  AdsActivationGrantResponse: adsActivationGrantResponseSchema,
17347
17387
  AdsCampaignListResponse: adsCampaignListResponseSchema,
17348
17388
  AdsConnectionStatusDto: adsConnectionStatusDtoSchema,
17389
+ AdsDeliveryDiagnosticsDto: adsDeliveryDiagnosticsDtoSchema,
17349
17390
  AdsConversionEventSettingListResponse: adsConversionEventSettingListResponseSchema,
17350
17391
  AdsConversionPixelListResponse: adsConversionPixelListResponseSchema,
17351
17392
  AdsDisconnectResponse: adsDisconnectResponseSchema,
@@ -20342,6 +20383,18 @@ var routeCatalog = [
20342
20383
  404: errorResponse("Project not found.")
20343
20384
  }
20344
20385
  },
20386
+ {
20387
+ method: "get",
20388
+ path: "/api/v1/projects/{name}/ads/delivery-diagnostics",
20389
+ summary: "Stored ads snapshot provenance, configuration facts, and historical campaign activity",
20390
+ description: "Read-only local evidence. It does not call OpenAI and never determines provider eligibility or serving.",
20391
+ tags: ["ads"],
20392
+ parameters: [nameParameter],
20393
+ responses: {
20394
+ 200: jsonResponse("Stored diagnostics returned.", "AdsDeliveryDiagnosticsDto"),
20395
+ 404: errorResponse("Project not found.")
20396
+ }
20397
+ },
20345
20398
  {
20346
20399
  method: "post",
20347
20400
  path: "/api/v1/projects/{name}/bing/connect",
@@ -25975,7 +26028,7 @@ async function googleRoutes(app, opts) {
25975
26028
 
25976
26029
  // ../api-routes/src/ads.ts
25977
26030
  import crypto22 from "crypto";
25978
- import { eq as eq28, and as and22, asc as asc6, gt as gt2, gte as gte8, lt as lt3, lte as lte6, ne as ne3, inArray as inArray12, or as or8, isNull as isNull2, isNotNull as isNotNull2, sql as sql14 } from "drizzle-orm";
26031
+ import { eq as eq28, and as and22, asc as asc6, desc as desc13, gt as gt2, gte as gte8, lt as lt3, lte as lte6, ne as ne3, inArray as inArray12, or as or8, isNull as isNull2, isNotNull as isNotNull2, sql as sql14 } from "drizzle-orm";
25979
26032
 
25980
26033
  // ../api-routes/src/ads-activation-routes.ts
25981
26034
  import crypto21 from "crypto";
@@ -28413,6 +28466,139 @@ function registerAdsActivationRoutes(app, opts) {
28413
28466
  }
28414
28467
 
28415
28468
  // ../api-routes/src/ads.ts
28469
+ function runSourceDto(row) {
28470
+ const parsed = runStatusSchema.safeParse(row.status);
28471
+ return parsed.success ? { runId: row.id, status: parsed.data } : null;
28472
+ }
28473
+ function storedSnapshotProvenance(input) {
28474
+ if (!input.connected) {
28475
+ return {
28476
+ status: AdsDeliverySnapshotStatuses.unavailable,
28477
+ issue: AdsDeliverySnapshotIssues.no_ads_connection,
28478
+ sourceSync: null
28479
+ };
28480
+ }
28481
+ if (input.connectionLastSyncedAt === null) {
28482
+ return {
28483
+ status: input.hasEntityRows ? AdsDeliverySnapshotStatuses.partial : AdsDeliverySnapshotStatuses.unavailable,
28484
+ issue: AdsDeliverySnapshotIssues.connection_not_synced,
28485
+ sourceSync: null
28486
+ };
28487
+ }
28488
+ if (!input.hasEntityRows) {
28489
+ if (!input.latestAdsSync) {
28490
+ return {
28491
+ status: AdsDeliverySnapshotStatuses.unavailable,
28492
+ issue: AdsDeliverySnapshotIssues.no_ads_sync,
28493
+ sourceSync: null
28494
+ };
28495
+ }
28496
+ const sourceSync2 = runSourceDto(input.latestAdsSync);
28497
+ if (!sourceSync2 || sourceSync2.status !== RunStatuses.completed) {
28498
+ return {
28499
+ status: AdsDeliverySnapshotStatuses.partial,
28500
+ issue: AdsDeliverySnapshotIssues.source_sync_not_completed,
28501
+ sourceSync: sourceSync2
28502
+ };
28503
+ }
28504
+ return {
28505
+ status: AdsDeliverySnapshotStatuses.complete,
28506
+ issue: null,
28507
+ sourceSync: sourceSync2
28508
+ };
28509
+ }
28510
+ if (input.hasEntityWithoutSyncRunId) {
28511
+ return {
28512
+ status: AdsDeliverySnapshotStatuses.partial,
28513
+ issue: AdsDeliverySnapshotIssues.entity_rows_missing_sync_run_id,
28514
+ sourceSync: null
28515
+ };
28516
+ }
28517
+ if (input.entitySyncRunIds.size !== 1) {
28518
+ return {
28519
+ status: AdsDeliverySnapshotStatuses.partial,
28520
+ issue: AdsDeliverySnapshotIssues.entity_rows_span_multiple_sync_runs,
28521
+ sourceSync: null
28522
+ };
28523
+ }
28524
+ if (!input.sourceSync) {
28525
+ return {
28526
+ status: AdsDeliverySnapshotStatuses.partial,
28527
+ issue: AdsDeliverySnapshotIssues.source_sync_missing,
28528
+ sourceSync: null
28529
+ };
28530
+ }
28531
+ const sourceSync = runSourceDto(input.sourceSync);
28532
+ if (input.sourceSync.kind !== RunKinds["ads-sync"]) {
28533
+ return {
28534
+ status: AdsDeliverySnapshotStatuses.partial,
28535
+ issue: AdsDeliverySnapshotIssues.source_sync_not_ads_sync,
28536
+ sourceSync
28537
+ };
28538
+ }
28539
+ if (!sourceSync || sourceSync.status !== RunStatuses.completed) {
28540
+ return {
28541
+ status: AdsDeliverySnapshotStatuses.partial,
28542
+ issue: AdsDeliverySnapshotIssues.source_sync_not_completed,
28543
+ sourceSync
28544
+ };
28545
+ }
28546
+ return {
28547
+ status: AdsDeliverySnapshotStatuses.complete,
28548
+ issue: null,
28549
+ sourceSync
28550
+ };
28551
+ }
28552
+ function historicalCampaignRollups(rows) {
28553
+ if (rows.length === 0) {
28554
+ return {
28555
+ status: AdsHistoricalCampaignRollupStatuses.unavailable,
28556
+ window: { from: null, to: null },
28557
+ totals: null
28558
+ };
28559
+ }
28560
+ let impressions = 0;
28561
+ let clicks = 0;
28562
+ let spendMicros = 0;
28563
+ let conversions = 0;
28564
+ let fromDate = null;
28565
+ let toDate = null;
28566
+ for (const row of rows) {
28567
+ impressions += row.impressions;
28568
+ clicks += row.clicks;
28569
+ spendMicros += row.spendMicros;
28570
+ conversions += row.conversions;
28571
+ if (fromDate === null || row.date < fromDate) fromDate = row.date;
28572
+ if (toDate === null || row.date > toDate) toDate = row.date;
28573
+ }
28574
+ return {
28575
+ status: AdsHistoricalCampaignRollupStatuses.reported,
28576
+ window: { from: fromDate, to: toDate },
28577
+ totals: {
28578
+ impressions,
28579
+ clicks,
28580
+ spendMicros,
28581
+ conversions,
28582
+ ctr: adsCtr(clicks, impressions),
28583
+ cpcMicros: adsCpcMicros(spendMicros, clicks)
28584
+ }
28585
+ };
28586
+ }
28587
+ function storedActivityAssessment(snapshotStatus, rollupStatus, rollupImpressions) {
28588
+ switch (snapshotStatus) {
28589
+ case AdsDeliverySnapshotStatuses.unavailable:
28590
+ return AdsActivityAssessmentStates.unavailable;
28591
+ case AdsDeliverySnapshotStatuses.partial:
28592
+ return AdsActivityAssessmentStates.partial_snapshot;
28593
+ case AdsDeliverySnapshotStatuses.complete:
28594
+ switch (rollupStatus) {
28595
+ case AdsHistoricalCampaignRollupStatuses.unavailable:
28596
+ return AdsActivityAssessmentStates.metrics_unavailable;
28597
+ case AdsHistoricalCampaignRollupStatuses.reported:
28598
+ return (rollupImpressions ?? 0) > 0 ? AdsActivityAssessmentStates.observed_activity : AdsActivityAssessmentStates.no_observed_activity;
28599
+ }
28600
+ }
28601
+ }
28416
28602
  var DEFAULT_RECONCILE_SWEEP_INTERVAL_MS = 6e4;
28417
28603
  var DEFAULT_RECONCILE_PENDING_STALE_MS = 5 * 6e4;
28418
28604
  var DEFAULT_RECONCILE_BACKOFF_BASE_MS = 5 * 6e4;
@@ -29538,6 +29724,10 @@ async function adsRoutes(app, opts) {
29538
29724
  reviewStatus: account.reviewStatus,
29539
29725
  integrityReviewStatus: account.integrityReviewStatus,
29540
29726
  integrityDecision: account.integrityDecision,
29727
+ // A credential rotation for the same account preserves its
29728
+ // snapshot watermark. A different account invalidates all stored
29729
+ // entity/insight provenance until the new binding is synced.
29730
+ lastSyncedAt: existingRow.adAccountId === account.id ? existingRow.lastSyncedAt : null,
29541
29731
  updatedAt: now
29542
29732
  }).where(eq28(adsConnections.id, existingRow.id)).run();
29543
29733
  } else {
@@ -30093,6 +30283,101 @@ async function adsRoutes(app, opts) {
30093
30283
  const response = { rows: dtoRows, currencyCode: conn?.currencyCode ?? null };
30094
30284
  return response;
30095
30285
  });
30286
+ app.get("/projects/:name/ads/delivery-diagnostics", async (request) => {
30287
+ const project = resolveProject(app.db, request.params.name);
30288
+ const connection = app.db.select().from(adsConnections).where(eq28(adsConnections.projectId, project.id)).get();
30289
+ const campaignRows = app.db.select().from(adsCampaigns).where(eq28(adsCampaigns.projectId, project.id)).all();
30290
+ const adGroupRows = app.db.select().from(adsAdGroups).where(eq28(adsAdGroups.projectId, project.id)).all();
30291
+ const adRows = app.db.select().from(adsAds).where(eq28(adsAds.projectId, project.id)).all();
30292
+ const entityRows = [...campaignRows, ...adGroupRows, ...adRows];
30293
+ const hasEntityWithoutSyncRunId = entityRows.some((row) => row.syncRunId === null);
30294
+ const entitySyncRunIds = new Set(entityRows.flatMap((row) => row.syncRunId === null ? [] : [row.syncRunId]));
30295
+ const sourceSync = entitySyncRunIds.size === 1 ? app.db.select({ id: runs.id, kind: runs.kind, status: runs.status }).from(runs).where(and22(
30296
+ eq28(runs.id, [...entitySyncRunIds][0]),
30297
+ eq28(runs.projectId, project.id)
30298
+ )).get() : void 0;
30299
+ const latestAdsSync = app.db.select({ id: runs.id, kind: runs.kind, status: runs.status }).from(runs).where(and22(
30300
+ eq28(runs.projectId, project.id),
30301
+ eq28(runs.kind, RunKinds["ads-sync"])
30302
+ )).orderBy(desc13(runs.createdAt)).get();
30303
+ const snapshot = storedSnapshotProvenance({
30304
+ connected: Boolean(connection),
30305
+ connectionLastSyncedAt: connection?.lastSyncedAt ?? null,
30306
+ hasEntityRows: entityRows.length > 0,
30307
+ hasEntityWithoutSyncRunId,
30308
+ entitySyncRunIds,
30309
+ sourceSync,
30310
+ latestAdsSync
30311
+ });
30312
+ const rollups = historicalCampaignRollups(app.db.select({
30313
+ date: adsInsightsDaily.date,
30314
+ impressions: adsInsightsDaily.impressions,
30315
+ clicks: adsInsightsDaily.clicks,
30316
+ spendMicros: adsInsightsDaily.spendMicros,
30317
+ conversions: adsInsightsDaily.conversions
30318
+ }).from(adsInsightsDaily).where(and22(
30319
+ eq28(adsInsightsDaily.projectId, project.id),
30320
+ eq28(adsInsightsDaily.level, AdsInsightLevels.campaign)
30321
+ )).all());
30322
+ const adsByGroup = /* @__PURE__ */ new Map();
30323
+ for (const ad of adRows) {
30324
+ const list = adsByGroup.get(ad.adGroupId) ?? [];
30325
+ list.push({ id: ad.id, name: ad.name, status: ad.status, reviewStatus: ad.reviewStatus });
30326
+ adsByGroup.set(ad.adGroupId, list);
30327
+ }
30328
+ const groupsByCampaign = /* @__PURE__ */ new Map();
30329
+ for (const adGroup of adGroupRows) {
30330
+ const list = groupsByCampaign.get(adGroup.campaignId) ?? [];
30331
+ list.push({
30332
+ id: adGroup.id,
30333
+ name: adGroup.name,
30334
+ status: adGroup.status,
30335
+ billingEventType: adGroupBillingEventTypeDto(adGroup.billingEventType),
30336
+ maxBidMicros: adGroup.maxBidMicros,
30337
+ contextHints: adGroup.contextHints,
30338
+ ads: adsByGroup.get(adGroup.id) ?? []
30339
+ });
30340
+ groupsByCampaign.set(adGroup.campaignId, list);
30341
+ }
30342
+ const response = {
30343
+ snapshot: {
30344
+ ...snapshot,
30345
+ lastSyncedAt: connection?.lastSyncedAt ?? null,
30346
+ campaignCount: campaignRows.length,
30347
+ adGroupCount: adGroupRows.length,
30348
+ adCount: adRows.length
30349
+ },
30350
+ historicalCampaignRollups: rollups,
30351
+ storedConfiguration: {
30352
+ basis: AdsDeliveryConfigurationBases.storedSnapshot,
30353
+ connection: connection === void 0 ? null : {
30354
+ status: connection.status,
30355
+ reviewStatus: connection.reviewStatus,
30356
+ integrityReviewStatus: connection.integrityReviewStatus,
30357
+ integrityDecision: connection.integrityDecision,
30358
+ conversionTrackingConfigured: connection.conversionTrackingConfigured
30359
+ },
30360
+ campaigns: campaignRows.map((campaign) => ({
30361
+ id: campaign.id,
30362
+ name: campaign.name,
30363
+ status: campaign.status,
30364
+ biddingType: campaignBiddingTypeDto(campaign.biddingType),
30365
+ dailySpendLimitMicros: campaign.dailySpendLimitMicros,
30366
+ lifetimeSpendLimitMicros: campaign.lifetimeSpendLimitMicros,
30367
+ conversionEventSettingIds: campaign.conversionEventSettingIds,
30368
+ adGroups: groupsByCampaign.get(campaign.id) ?? []
30369
+ }))
30370
+ },
30371
+ assessment: {
30372
+ state: storedActivityAssessment(
30373
+ snapshot.status,
30374
+ rollups.status,
30375
+ rollups.totals === null ? null : rollups.totals.impressions
30376
+ )
30377
+ }
30378
+ };
30379
+ return response;
30380
+ });
30096
30381
  app.get("/projects/:name/ads/summary", async (request) => {
30097
30382
  const project = resolveProject(app.db, request.params.name);
30098
30383
  const row = app.db.select().from(adsConnections).where(eq28(adsConnections.projectId, project.id)).get();
@@ -30141,7 +30426,7 @@ async function adsRoutes(app, opts) {
30141
30426
 
30142
30427
  // ../api-routes/src/bing.ts
30143
30428
  import crypto23 from "crypto";
30144
- import { eq as eq29, and as and23, desc as desc13 } from "drizzle-orm";
30429
+ import { eq as eq29, and as and23, desc as desc14 } from "drizzle-orm";
30145
30430
 
30146
30431
  // ../integration-bing/src/constants.ts
30147
30432
  var BING_WMT_API_BASE = "https://ssl.bing.com/webmaster/api.svc/json";
@@ -30515,7 +30800,7 @@ async function bingRoutes(app, opts) {
30515
30800
  const store = requireConnectionStore();
30516
30801
  const project = resolveProject(app.db, request.params.name);
30517
30802
  requireConnection(store, project.canonicalDomain);
30518
- const allInspections = app.db.select().from(bingUrlInspections).where(eq29(bingUrlInspections.projectId, project.id)).orderBy(desc13(bingUrlInspections.inspectedAt)).all();
30803
+ const allInspections = app.db.select().from(bingUrlInspections).where(eq29(bingUrlInspections.projectId, project.id)).orderBy(desc14(bingUrlInspections.inspectedAt)).all();
30519
30804
  const latestByUrl = /* @__PURE__ */ new Map();
30520
30805
  const definitiveByUrl = /* @__PURE__ */ new Map();
30521
30806
  for (const row of allInspections) {
@@ -30604,7 +30889,7 @@ async function bingRoutes(app, opts) {
30604
30889
  const project = resolveProject(app.db, request.params.name);
30605
30890
  const parsed = parseInt(request.query.limit ?? "90", 10);
30606
30891
  const limit = Number.isNaN(parsed) || parsed <= 0 ? 90 : parsed;
30607
- const rows = app.db.select().from(bingCoverageSnapshots).where(eq29(bingCoverageSnapshots.projectId, project.id)).orderBy(desc13(bingCoverageSnapshots.date)).limit(limit).all();
30892
+ const rows = app.db.select().from(bingCoverageSnapshots).where(eq29(bingCoverageSnapshots.projectId, project.id)).orderBy(desc14(bingCoverageSnapshots.date)).limit(limit).all();
30608
30893
  return rows.map((r) => ({
30609
30894
  date: r.date,
30610
30895
  indexed: r.indexed,
@@ -30617,7 +30902,7 @@ async function bingRoutes(app, opts) {
30617
30902
  const project = resolveProject(app.db, request.params.name);
30618
30903
  const { url, limit } = request.query;
30619
30904
  const whereClause = url ? and23(eq29(bingUrlInspections.projectId, project.id), eq29(bingUrlInspections.url, url)) : eq29(bingUrlInspections.projectId, project.id);
30620
- const filtered = app.db.select().from(bingUrlInspections).where(whereClause).orderBy(desc13(bingUrlInspections.inspectedAt)).limit(Math.max(1, Math.min(parseInt(limit ?? "100", 10) || 100, 1e3))).all();
30905
+ const filtered = app.db.select().from(bingUrlInspections).where(whereClause).orderBy(desc14(bingUrlInspections.inspectedAt)).limit(Math.max(1, Math.min(parseInt(limit ?? "100", 10) || 100, 1e3))).all();
30621
30906
  return filtered.map((r) => ({
30622
30907
  id: r.id,
30623
30908
  url: r.url,
@@ -30761,7 +31046,7 @@ async function bingRoutes(app, opts) {
30761
31046
  }
30762
31047
  let urlsToSubmit = request.body?.urls ?? [];
30763
31048
  if (request.body?.allUnindexed) {
30764
- const allInspections = app.db.select().from(bingUrlInspections).where(eq29(bingUrlInspections.projectId, project.id)).orderBy(desc13(bingUrlInspections.inspectedAt)).all();
31049
+ const allInspections = app.db.select().from(bingUrlInspections).where(eq29(bingUrlInspections.projectId, project.id)).orderBy(desc14(bingUrlInspections.inspectedAt)).all();
30765
31050
  const latestByUrl = /* @__PURE__ */ new Map();
30766
31051
  for (const row of allInspections) {
30767
31052
  if (!latestByUrl.has(row.url)) {
@@ -31020,7 +31305,7 @@ async function cdpRoutes(app, opts) {
31020
31305
 
31021
31306
  // ../api-routes/src/ga.ts
31022
31307
  import crypto24 from "crypto";
31023
- import { eq as eq31, desc as desc14, and as and25, sql as sql15 } from "drizzle-orm";
31308
+ import { eq as eq31, desc as desc15, and as and25, sql as sql15 } from "drizzle-orm";
31024
31309
 
31025
31310
  // ../api-routes/src/ga-session-history.ts
31026
31311
  function buildSessionHistory(landingPageDays, dailyTotals) {
@@ -31467,7 +31752,7 @@ async function ga4Routes(app, opts) {
31467
31752
  if (!connected) {
31468
31753
  return { connected: false, propertyId: null, clientEmail: null, authMethod: null, lastSyncedAt: null };
31469
31754
  }
31470
- const latestSync = app.db.select({ syncedAt: gaTrafficSummaries.syncedAt }).from(gaTrafficSummaries).where(eq31(gaTrafficSummaries.projectId, project.id)).orderBy(desc14(gaTrafficSummaries.syncedAt)).limit(1).get();
31755
+ const latestSync = app.db.select({ syncedAt: gaTrafficSummaries.syncedAt }).from(gaTrafficSummaries).where(eq31(gaTrafficSummaries.projectId, project.id)).orderBy(desc15(gaTrafficSummaries.syncedAt)).limit(1).get();
31471
31756
  return {
31472
31757
  connected: true,
31473
31758
  propertyId: saConn?.propertyId ?? oauthConn?.propertyId ?? null,
@@ -31873,7 +32158,7 @@ async function ga4Routes(app, opts) {
31873
32158
  sessions: sql15`SUM(${gaSocialReferrals.sessions})`,
31874
32159
  users: sql15`SUM(${gaSocialReferrals.users})`
31875
32160
  }).from(gaSocialReferrals).where(and25(...socialConditions)).get();
31876
- const latestSync = app.db.select({ syncedAt: gaTrafficSummaries.syncedAt }).from(gaTrafficSummaries).where(eq31(gaTrafficSummaries.projectId, project.id)).orderBy(desc14(gaTrafficSummaries.syncedAt)).limit(1).get();
32161
+ const latestSync = app.db.select({ syncedAt: gaTrafficSummaries.syncedAt }).from(gaTrafficSummaries).where(eq31(gaTrafficSummaries.projectId, project.id)).orderBy(desc15(gaTrafficSummaries.syncedAt)).limit(1).get();
31877
32162
  const total = summaryRow?.totalSessions ?? 0;
31878
32163
  const totalDirectSessions = directTotalRow?.totalDirectSessions ?? 0;
31879
32164
  const totalOrganicSessions = summaryRow?.totalOrganicSessions ?? 0;
@@ -33818,7 +34103,7 @@ async function wordpressRoutes(app, opts) {
33818
34103
 
33819
34104
  // ../api-routes/src/backlinks.ts
33820
34105
  import crypto26 from "crypto";
33821
- import { and as and27, asc as asc7, desc as desc15, eq as eq32, sql as sql16 } from "drizzle-orm";
34106
+ import { and as and27, asc as asc7, desc as desc16, eq as eq32, sql as sql16 } from "drizzle-orm";
33822
34107
 
33823
34108
  // ../integration-commoncrawl/src/constants.ts
33824
34109
  import os2 from "os";
@@ -34319,7 +34604,7 @@ function latestSummaryForProject(db, projectId, source, release) {
34319
34604
  eq32(backlinkSummaries.source, source)
34320
34605
  ];
34321
34606
  if (release) conditions.push(eq32(backlinkSummaries.release, release));
34322
- return db.select().from(backlinkSummaries).where(and27(...conditions)).orderBy(desc15(backlinkSummaries.queriedAt)).limit(1).get();
34607
+ return db.select().from(backlinkSummaries).where(and27(...conditions)).orderBy(desc16(backlinkSummaries.queriedAt)).limit(1).get();
34323
34608
  }
34324
34609
  function parseExcludeCrawlers(value) {
34325
34610
  if (!value) return false;
@@ -34341,7 +34626,7 @@ function computeFilteredSummary(db, base) {
34341
34626
  count: sql16`count(*)`,
34342
34627
  total: sql16`coalesce(sum(${backlinkDomains.numHosts}), 0)`
34343
34628
  }).from(backlinkDomains).where(filteredCondition).get();
34344
- const top10Rows = db.select({ numHosts: backlinkDomains.numHosts }).from(backlinkDomains).where(filteredCondition).orderBy(desc15(backlinkDomains.numHosts)).limit(10).all();
34629
+ const top10Rows = db.select({ numHosts: backlinkDomains.numHosts }).from(backlinkDomains).where(filteredCondition).orderBy(desc16(backlinkDomains.numHosts)).limit(10).all();
34345
34630
  const totalLinkingDomains = Number(filteredAgg?.count ?? 0);
34346
34631
  const totalHosts = Number(filteredAgg?.total ?? 0);
34347
34632
  const unfilteredLinkingDomains = Number(unfilteredAgg?.count ?? 0);
@@ -34362,7 +34647,7 @@ function computeFilteredSummary(db, base) {
34362
34647
  };
34363
34648
  }
34364
34649
  function buildSourceAvailability(db, projectId, source, connected, excludeCrawlers) {
34365
- const summary = db.select().from(backlinkSummaries).where(and27(eq32(backlinkSummaries.projectId, projectId), eq32(backlinkSummaries.source, source))).orderBy(desc15(backlinkSummaries.queriedAt)).limit(1).get();
34650
+ const summary = db.select().from(backlinkSummaries).where(and27(eq32(backlinkSummaries.projectId, projectId), eq32(backlinkSummaries.source, source))).orderBy(desc16(backlinkSummaries.queriedAt)).limit(1).get();
34366
34651
  let totalLinkingDomains = summary?.totalLinkingDomains ?? 0;
34367
34652
  if (summary && excludeCrawlers) {
34368
34653
  const filtered = db.select({ count: sql16`count(*)` }).from(backlinkDomains).where(and27(
@@ -34468,11 +34753,11 @@ async function backlinksRoutes(app, opts) {
34468
34753
  return reply.status(201).send(mapSyncRow(inserted));
34469
34754
  });
34470
34755
  app.get("/backlinks/syncs/latest", async (_request, reply) => {
34471
- const row = app.db.select().from(ccReleaseSyncs).orderBy(desc15(ccReleaseSyncs.updatedAt)).limit(1).get();
34756
+ const row = app.db.select().from(ccReleaseSyncs).orderBy(desc16(ccReleaseSyncs.updatedAt)).limit(1).get();
34472
34757
  return reply.send(row ? mapSyncRow(row) : null);
34473
34758
  });
34474
34759
  app.get("/backlinks/syncs", async (_request, reply) => {
34475
- const rows = app.db.select().from(ccReleaseSyncs).orderBy(desc15(ccReleaseSyncs.updatedAt)).all();
34760
+ const rows = app.db.select().from(ccReleaseSyncs).orderBy(desc16(ccReleaseSyncs.updatedAt)).all();
34476
34761
  return reply.send(rows.map(mapSyncRow));
34477
34762
  });
34478
34763
  app.get("/backlinks/releases", async (_request, reply) => {
@@ -34559,7 +34844,7 @@ async function backlinksRoutes(app, opts) {
34559
34844
  linkingDomain: backlinkDomains.linkingDomain,
34560
34845
  numHosts: backlinkDomains.numHosts,
34561
34846
  source: backlinkDomains.source
34562
- }).from(backlinkDomains).where(domainCondition).orderBy(desc15(backlinkDomains.numHosts)).limit(limit).offset(offset).all();
34847
+ }).from(backlinkDomains).where(domainCondition).orderBy(desc16(backlinkDomains.numHosts)).limit(limit).offset(offset).all();
34563
34848
  let summary = null;
34564
34849
  if (summaryRow) {
34565
34850
  summary = excludeCrawlers ? computeFilteredSummary(app.db, summaryRow) : mapSummaryRow(summaryRow);
@@ -34633,7 +34918,7 @@ async function backlinksRoutes(app, opts) {
34633
34918
  // ../api-routes/src/traffic.ts
34634
34919
  import crypto28 from "crypto";
34635
34920
  import { Agent as UndiciAgent } from "undici";
34636
- import { and as and28, desc as desc16, eq as eq33, gte as gte9, lte as lte7, sql as sql17 } from "drizzle-orm";
34921
+ import { and as and28, desc as desc17, eq as eq33, gte as gte9, lte as lte7, sql as sql17 } from "drizzle-orm";
34637
34922
 
34638
34923
  // ../integration-cloud-run/src/auth.ts
34639
34924
  import crypto27 from "crypto";
@@ -39735,7 +40020,7 @@ async function trafficRoutes(app, opts) {
39735
40020
  eq33(runs.kind, RunKinds["traffic-sync"]),
39736
40021
  eq33(runs.sourceId, row.id)
39737
40022
  )
39738
- ).orderBy(desc16(runs.startedAt)).limit(1).get();
40023
+ ).orderBy(desc17(runs.startedAt)).limit(1).get();
39739
40024
  return {
39740
40025
  ...rowToDto(row),
39741
40026
  totals24h: {
@@ -39795,14 +40080,14 @@ async function trafficRoutes(app, opts) {
39795
40080
  });
39796
40081
  app.get("/projects/:name/traffic/sources", async (request) => {
39797
40082
  const project = resolveProject(app.db, request.params.name);
39798
- const rows = app.db.select().from(trafficSources).where(eq33(trafficSources.projectId, project.id)).orderBy(desc16(trafficSources.createdAt)).all();
40083
+ const rows = app.db.select().from(trafficSources).where(eq33(trafficSources.projectId, project.id)).orderBy(desc17(trafficSources.createdAt)).all();
39799
40084
  const sources = rows.filter((row) => row.status !== TrafficSourceStatuses.archived).map(rowToDto);
39800
40085
  const response = { sources };
39801
40086
  return response;
39802
40087
  });
39803
40088
  app.get("/projects/:name/traffic/status", async (request) => {
39804
40089
  const project = resolveProject(app.db, request.params.name);
39805
- const rows = app.db.select().from(trafficSources).where(eq33(trafficSources.projectId, project.id)).orderBy(desc16(trafficSources.createdAt)).all();
40090
+ const rows = app.db.select().from(trafficSources).where(eq33(trafficSources.projectId, project.id)).orderBy(desc17(trafficSources.createdAt)).all();
39806
40091
  const since = new Date(Date.now() - 24 * 60 * 6e4).toISOString();
39807
40092
  const sources = rows.filter((row) => row.status !== TrafficSourceStatuses.archived).map((row) => buildSourceDetail(project.id, row, since));
39808
40093
  const response = { sources };
@@ -39901,7 +40186,7 @@ async function trafficRoutes(app, opts) {
39901
40186
  for (const row of crawlerSeries) {
39902
40187
  trafficSeriesPoint(seriesByBucket, row.bucket).crawlerHits = Number(row.hits);
39903
40188
  }
39904
- const rows = app.db.select().from(crawlerEventsHourly).where(crawlerWhere).orderBy(desc16(crawlerEventsHourly.tsHour)).limit(limit).all();
40189
+ const rows = app.db.select().from(crawlerEventsHourly).where(crawlerWhere).orderBy(desc17(crawlerEventsHourly.tsHour)).limit(limit).all();
39905
40190
  for (const r of rows) {
39906
40191
  events.push({
39907
40192
  kind: TrafficEventKinds.crawler,
@@ -39939,7 +40224,7 @@ async function trafficRoutes(app, opts) {
39939
40224
  for (const row of userFetchSeries) {
39940
40225
  trafficSeriesPoint(seriesByBucket, row.bucket).aiUserFetchHits = Number(row.hits);
39941
40226
  }
39942
- const rows = app.db.select().from(aiUserFetchEventsHourly).where(userFetchWhere).orderBy(desc16(aiUserFetchEventsHourly.tsHour)).limit(limit).all();
40227
+ const rows = app.db.select().from(aiUserFetchEventsHourly).where(userFetchWhere).orderBy(desc17(aiUserFetchEventsHourly.tsHour)).limit(limit).all();
39943
40228
  for (const r of rows) {
39944
40229
  events.push({
39945
40230
  kind: TrafficEventKinds["ai-user-fetch"],
@@ -39982,7 +40267,7 @@ async function trafficRoutes(app, opts) {
39982
40267
  for (const row of referralSeries) {
39983
40268
  trafficSeriesPoint(seriesByBucket, row.bucket).aiReferralHits = Number(row.hits);
39984
40269
  }
39985
- const rows = app.db.select().from(aiReferralEventsHourly).where(aiWhere).orderBy(desc16(aiReferralEventsHourly.tsHour)).limit(limit).all();
40270
+ const rows = app.db.select().from(aiReferralEventsHourly).where(aiWhere).orderBy(desc17(aiReferralEventsHourly.tsHour)).limit(limit).all();
39986
40271
  for (const r of rows) {
39987
40272
  const counts2 = aiReferralClassCounts(r.sessionsOrHits, r.paidSessionsOrHits, r.organicSessionsOrHits);
39988
40273
  events.push({
@@ -42218,7 +42503,7 @@ async function doctorRoutes(app, opts) {
42218
42503
 
42219
42504
  // ../api-routes/src/discovery/routes.ts
42220
42505
  import crypto30 from "crypto";
42221
- import { and as and32, desc as desc17, eq as eq40, gte as gte11, inArray as inArray13, isNull as isNull3, or as or9 } from "drizzle-orm";
42506
+ import { and as and32, desc as desc18, eq as eq40, gte as gte11, inArray as inArray13, isNull as isNull3, or as or9 } from "drizzle-orm";
42222
42507
  var MAX_INFLIGHT_DISCOVERY_AGE_MS = 2 * 60 * 60 * 1e3;
42223
42508
  async function discoveryRoutes(app, opts) {
42224
42509
  app.post("/projects/:name/discover/run", async (request, reply) => {
@@ -42279,7 +42564,7 @@ async function discoveryRoutes(app, opts) {
42279
42564
  DiscoverySessionStatuses.probing
42280
42565
  ]),
42281
42566
  gte11(discoverySessions.createdAt, ageFloorIso)
42282
- )).orderBy(desc17(discoverySessions.createdAt)).get();
42567
+ )).orderBy(desc18(discoverySessions.createdAt)).get();
42283
42568
  if (existing && existing.runId) {
42284
42569
  return { reused: true, sessionId: existing.id, runId: existing.runId };
42285
42570
  }
@@ -42348,7 +42633,7 @@ async function discoveryRoutes(app, opts) {
42348
42633
  const project = resolveProject(app.db, request.params.name);
42349
42634
  const parsedLimit = parseInt(request.query.limit ?? "", 10);
42350
42635
  const limit = Number.isNaN(parsedLimit) || parsedLimit <= 0 ? 50 : parsedLimit;
42351
- const rows = app.db.select().from(discoverySessions).where(eq40(discoverySessions.projectId, project.id)).orderBy(desc17(discoverySessions.createdAt)).limit(limit).all();
42636
+ const rows = app.db.select().from(discoverySessions).where(eq40(discoverySessions.projectId, project.id)).orderBy(desc18(discoverySessions.createdAt)).limit(limit).all();
42352
42637
  return reply.send(rows.map(serializeSession));
42353
42638
  }
42354
42639
  );
@@ -42898,7 +43183,7 @@ function dedupeStrings(input) {
42898
43183
 
42899
43184
  // ../api-routes/src/technical-aeo.ts
42900
43185
  import crypto32 from "crypto";
42901
- import { and as and33, asc as asc8, count, desc as desc18, eq as eq42, inArray as inArray14, lt as lt4 } from "drizzle-orm";
43186
+ import { and as and33, asc as asc8, count, desc as desc19, eq as eq42, inArray as inArray14, lt as lt4 } from "drizzle-orm";
42902
43187
  var SURFACEABLE_STATUSES = [RunStatuses.completed, RunStatuses.partial];
42903
43188
  function emptyScore(projectName) {
42904
43189
  return {
@@ -42937,13 +43222,13 @@ async function technicalAeoRoutes(app, opts) {
42937
43222
  notProbeRun()
42938
43223
  ];
42939
43224
  const targetFilters = request.query.runId ? [...baseFilters, eq42(siteAuditSnapshots.runId, request.query.runId)] : baseFilters;
42940
- const latest = app.db.select({ snap: siteAuditSnapshots, runStatus: runs.status }).from(siteAuditSnapshots).innerJoin(runs, eq42(siteAuditSnapshots.runId, runs.id)).where(and33(...targetFilters)).orderBy(desc18(siteAuditSnapshots.createdAt)).limit(1).get();
43225
+ const latest = app.db.select({ snap: siteAuditSnapshots, runStatus: runs.status }).from(siteAuditSnapshots).innerJoin(runs, eq42(siteAuditSnapshots.runId, runs.id)).where(and33(...targetFilters)).orderBy(desc19(siteAuditSnapshots.createdAt)).limit(1).get();
42941
43226
  if (!latest) {
42942
43227
  if (request.query.runId) throw notFound("Site audit run", request.query.runId);
42943
43228
  return emptyScore(project.name);
42944
43229
  }
42945
43230
  const snap = latest.snap;
42946
- const previous = app.db.select({ snap: siteAuditSnapshots }).from(siteAuditSnapshots).innerJoin(runs, eq42(siteAuditSnapshots.runId, runs.id)).where(and33(...baseFilters, lt4(siteAuditSnapshots.createdAt, snap.createdAt))).orderBy(desc18(siteAuditSnapshots.createdAt)).limit(1).get()?.snap ?? null;
43231
+ const previous = app.db.select({ snap: siteAuditSnapshots }).from(siteAuditSnapshots).innerJoin(runs, eq42(siteAuditSnapshots.runId, runs.id)).where(and33(...baseFilters, lt4(siteAuditSnapshots.createdAt, snap.createdAt))).orderBy(desc19(siteAuditSnapshots.createdAt)).limit(1).get()?.snap ?? null;
42947
43232
  const deltaScore = previous ? snap.aggregateScore - previous.aggregateScore : null;
42948
43233
  const trend = deltaScore == null ? null : deltaScore > 0 ? SiteAuditTrendDirections.up : deltaScore < 0 ? SiteAuditTrendDirections.down : SiteAuditTrendDirections.flat;
42949
43234
  return {
@@ -42976,7 +43261,7 @@ async function technicalAeoRoutes(app, opts) {
42976
43261
  notProbeRun()
42977
43262
  ];
42978
43263
  if (request.query.runId) targetFilters.push(eq42(siteAuditSnapshots.runId, request.query.runId));
42979
- const latest = app.db.select({ runId: siteAuditSnapshots.runId, auditedAt: siteAuditSnapshots.auditedAt }).from(siteAuditSnapshots).innerJoin(runs, eq42(siteAuditSnapshots.runId, runs.id)).where(and33(...targetFilters)).orderBy(desc18(siteAuditSnapshots.createdAt)).limit(1).get();
43264
+ const latest = app.db.select({ runId: siteAuditSnapshots.runId, auditedAt: siteAuditSnapshots.auditedAt }).from(siteAuditSnapshots).innerJoin(runs, eq42(siteAuditSnapshots.runId, runs.id)).where(and33(...targetFilters)).orderBy(desc19(siteAuditSnapshots.createdAt)).limit(1).get();
42980
43265
  if (!latest && request.query.runId) {
42981
43266
  throw notFound("Site audit run", request.query.runId);
42982
43267
  }
@@ -42991,7 +43276,7 @@ async function technicalAeoRoutes(app, opts) {
42991
43276
  const total = totalRow?.value ?? 0;
42992
43277
  const limit = parsePositiveInt(request.query.limit, 100, 500);
42993
43278
  const offset = parsePositiveInt(request.query.offset, 0, Number.MAX_SAFE_INTEGER);
42994
- const orderBy = request.query.sort === "score-desc" ? desc18(siteAuditPages.overallScore) : request.query.sort === "url" ? asc8(siteAuditPages.url) : asc8(siteAuditPages.overallScore);
43279
+ const orderBy = request.query.sort === "score-desc" ? desc19(siteAuditPages.overallScore) : request.query.sort === "url" ? asc8(siteAuditPages.url) : asc8(siteAuditPages.overallScore);
42995
43280
  const rows = app.db.select().from(siteAuditPages).where(where).orderBy(orderBy).limit(limit).offset(offset).all();
42996
43281
  const pages = rows.map((row) => ({
42997
43282
  url: row.url,
@@ -43015,7 +43300,7 @@ async function technicalAeoRoutes(app, opts) {
43015
43300
  eq42(runs.kind, RunKinds["site-audit"]),
43016
43301
  inArray14(runs.status, SURFACEABLE_STATUSES),
43017
43302
  notProbeRun()
43018
- )).orderBy(desc18(siteAuditSnapshots.createdAt)).limit(limit).all();
43303
+ )).orderBy(desc19(siteAuditSnapshots.createdAt)).limit(limit).all();
43019
43304
  return { project: project.name, points: rows.reverse() };
43020
43305
  });
43021
43306
  app.post("/projects/:name/technical-aeo/runs", async (request) => {
@@ -43052,7 +43337,7 @@ async function technicalAeoRoutes(app, opts) {
43052
43337
 
43053
43338
  // ../api-routes/src/research.ts
43054
43339
  import crypto33 from "crypto";
43055
- import { and as and34, desc as desc19, eq as eq43 } from "drizzle-orm";
43340
+ import { and as and34, desc as desc20, eq as eq43 } from "drizzle-orm";
43056
43341
  var sameLocation = (a, b) => a.label === b.label && a.city === b.city && a.region === b.region && a.country === b.country && a.timezone === b.timezone;
43057
43342
  async function researchRoutes(app, opts) {
43058
43343
  app.post("/projects/:name/research/runs", async (request, reply) => {
@@ -43103,7 +43388,7 @@ async function researchRoutes(app, opts) {
43103
43388
  const project = resolveProject(app.db, request.params.name);
43104
43389
  const requested = Number.parseInt(request.query.limit ?? "", 10);
43105
43390
  const limit = Number.isInteger(requested) && requested > 0 ? Math.min(requested, 100) : 20;
43106
- const runs2 = app.db.select().from(researchRuns).where(eq43(researchRuns.projectId, project.id)).orderBy(desc19(researchRuns.createdAt)).limit(limit).all().map(serializeRun);
43391
+ const runs2 = app.db.select().from(researchRuns).where(eq43(researchRuns.projectId, project.id)).orderBy(desc20(researchRuns.createdAt)).limit(limit).all().map(serializeRun);
43107
43392
  return { runs: runs2 };
43108
43393
  });
43109
43394
  app.get("/projects/:name/research/runs/:runId", async (request) => {
@@ -43719,7 +44004,7 @@ var IntelligenceService = class {
43719
44004
  // intelligence window.
43720
44005
  ne6(runs.trigger, RunTriggers.probe)
43721
44006
  )
43722
- ).orderBy(desc20(runs.finishedAt), desc20(runs.createdAt)).limit(HISTORY_WINDOW_RUNS).all();
44007
+ ).orderBy(desc21(runs.finishedAt), desc21(runs.createdAt)).limit(HISTORY_WINDOW_RUNS).all();
43723
44008
  if (recentRuns.length === 0) {
43724
44009
  log.info("intelligence.skip", { runId, reason: "no completed runs" });
43725
44010
  return null;
@@ -43841,10 +44126,10 @@ var IntelligenceService = class {
43841
44126
  buildGbpLocationSignals(projectId, locationName, displayName, fallbackDate) {
43842
44127
  const metricRows = this.db.select({ metric: gbpDailyMetrics.metric, date: gbpDailyMetrics.date, value: gbpDailyMetrics.value }).from(gbpDailyMetrics).where(and35(eq44(gbpDailyMetrics.projectId, projectId), eq44(gbpDailyMetrics.locationName, locationName))).all();
43843
44128
  const placeActionRows = this.db.select({ placeActionType: gbpPlaceActions.placeActionType, providerType: gbpPlaceActions.providerType }).from(gbpPlaceActions).where(and35(eq44(gbpPlaceActions.projectId, projectId), eq44(gbpPlaceActions.locationName, locationName))).all();
43844
- const lodgingRow = this.db.select({ populatedGroupCount: gbpLodgingSnapshots.populatedGroupCount }).from(gbpLodgingSnapshots).where(and35(eq44(gbpLodgingSnapshots.projectId, projectId), eq44(gbpLodgingSnapshots.locationName, locationName))).orderBy(desc20(gbpLodgingSnapshots.syncedAt)).limit(1).get();
44129
+ const lodgingRow = this.db.select({ populatedGroupCount: gbpLodgingSnapshots.populatedGroupCount }).from(gbpLodgingSnapshots).where(and35(eq44(gbpLodgingSnapshots.projectId, projectId), eq44(gbpLodgingSnapshots.locationName, locationName))).orderBy(desc21(gbpLodgingSnapshots.syncedAt)).limit(1).get();
43845
44130
  const ownerRow = this.db.select({ description: gbpLocations.description }).from(gbpLocations).where(and35(eq44(gbpLocations.projectId, projectId), eq44(gbpLocations.locationName, locationName))).get();
43846
44131
  const descriptionMissing = !(ownerRow?.description ?? "").trim();
43847
- const placeRow = this.db.select({ attributes: gbpPlaceDetails.attributes }).from(gbpPlaceDetails).where(and35(eq44(gbpPlaceDetails.projectId, projectId), eq44(gbpPlaceDetails.locationName, locationName))).orderBy(desc20(gbpPlaceDetails.syncedAt)).limit(1).get();
44132
+ const placeRow = this.db.select({ attributes: gbpPlaceDetails.attributes }).from(gbpPlaceDetails).where(and35(eq44(gbpPlaceDetails.projectId, projectId), eq44(gbpPlaceDetails.locationName, locationName))).orderBy(desc21(gbpPlaceDetails.syncedAt)).limit(1).get();
43848
44133
  const placesAmenities = placeRow ? extractPlaceAmenities(placeRow.attributes) : [];
43849
44134
  const summary = buildGbpSummary({
43850
44135
  locationName,
@@ -44197,7 +44482,7 @@ var IntelligenceService = class {
44197
44482
  // Defensive — see top of file.
44198
44483
  ne6(runs.trigger, RunTriggers.probe)
44199
44484
  )
44200
- ).orderBy(desc20(runs.createdAt), desc20(runs.id)).limit((RECURRENCE_LOOKBACK_RUNS + 1) * ROWS_PER_GROUP_BUDGET).all();
44485
+ ).orderBy(desc21(runs.createdAt), desc21(runs.id)).limit((RECURRENCE_LOOKBACK_RUNS + 1) * ROWS_PER_GROUP_BUDGET).all();
44201
44486
  const recentGroups = groupRunsByCreatedAt(recentRunRows);
44202
44487
  const recentRunIds = [];
44203
44488
  const recentRunIdToCreatedAt = /* @__PURE__ */ new Map();