@canonry/canonry 4.180.3 → 4.180.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +1 -1
- package/assets/assets/{AuditHistoryPanel-CRtw07lK.js → AuditHistoryPanel-CdM_9qX1.js} +1 -1
- package/assets/assets/{BacklinksPage-DURChJhG.js → BacklinksPage-DWWMPSPn.js} +1 -1
- package/assets/assets/{HistoryPage-DsSSJmOs.js → HistoryPage-m7TtGFBQ.js} +1 -1
- package/assets/assets/{MeasurementPropertyPage-DalkH9IT.js → MeasurementPropertyPage-CYBfBtEz.js} +1 -1
- package/assets/assets/{ProjectPage-CXLK_E8n.js → ProjectPage-CNPcNrIR.js} +1 -1
- package/assets/assets/{RunRow-DDwwyIxg.js → RunRow-O4u505Fc.js} +1 -1
- package/assets/assets/{RunsPage-DCgaTijO.js → RunsPage-CCzFT4X0.js} +1 -1
- package/assets/assets/{SettingsPage-DwQqOC3_.js → SettingsPage-DOmE3JbU.js} +1 -1
- package/assets/assets/{SiteHealthSection-Fg2-UL0h.js → SiteHealthSection-BZFVE2h9.js} +3 -3
- package/assets/assets/{TrafficPage-CefISwhk.js → TrafficPage-DYxOEVbW.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-Rotzu2tN.js → TrafficSourceDetailPage-Qd5Zpx_8.js} +1 -1
- package/assets/assets/{extract-error-message-D6lzT2hr.js → extract-error-message-B0bdIDVc.js} +1 -1
- package/assets/assets/{index-BuZ_xmnc.js → index-HmdbSL4h.js} +2 -2
- package/assets/assets/{react-sigma_core.esm.min-D-IM5qRE.js → react-sigma_core.esm.min-DXCrX1Ie.js} +1 -1
- package/assets/index.html +1 -1
- package/dist/{chunk-W3YSGMYK.js → chunk-2J65ALIR.js} +4 -4
- package/dist/{chunk-CKGWOYPO.js → chunk-DK23XZ6C.js} +2 -2
- package/dist/{chunk-YPDKZ73I.js → chunk-JJIESVNL.js} +1 -1
- package/dist/{chunk-JWPN6RU7.js → chunk-UESVOQRS.js} +1 -1
- package/dist/{chunk-OJDH2F6I.js → chunk-V4QGOJNH.js} +518 -441
- package/dist/cli.js +17 -6
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-DSYYBDR2.js → intelligence-service-XNAKDGDQ.js} +2 -2
- package/dist/mcp.js +3 -3
- package/package.json +9 -9
|
@@ -643,10 +643,10 @@ import {
|
|
|
643
643
|
wordpressSchemaDeployResultDtoSchema,
|
|
644
644
|
wordpressSchemaStatusResultDtoSchema,
|
|
645
645
|
wordpressStatusDtoSchema
|
|
646
|
-
} from "./chunk-
|
|
646
|
+
} from "./chunk-UESVOQRS.js";
|
|
647
647
|
|
|
648
648
|
// src/intelligence-service.ts
|
|
649
|
-
import { eq as eq62, desc as desc27, asc as asc11, and as and51, ne as ne8, or as or14, inArray as inArray22, gte as
|
|
649
|
+
import { eq as eq62, desc as desc27, asc as asc11, and as and51, ne as ne8, or as or14, inArray as inArray22, gte as gte15, lte as lte13, isNull as isNull9, sql as sql25, exists } from "drizzle-orm";
|
|
650
650
|
|
|
651
651
|
// ../db/src/client.ts
|
|
652
652
|
import { mkdirSync } from "fs";
|
|
@@ -22588,16 +22588,153 @@ function nonSubresourceReferralPathCondition() {
|
|
|
22588
22588
|
}
|
|
22589
22589
|
|
|
22590
22590
|
// ../api-routes/src/report.ts
|
|
22591
|
-
import { and as and24, desc as desc12, eq as eq29, gte as
|
|
22591
|
+
import { and as and24, desc as desc12, eq as eq29, gte as gte6, inArray as inArray12, lt as lt6, lte as lte4, ne as ne3, or as or4, sql as sql10 } from "drizzle-orm";
|
|
22592
22592
|
|
|
22593
22593
|
// ../api-routes/src/content.ts
|
|
22594
22594
|
import crypto22 from "crypto";
|
|
22595
|
-
import { and as
|
|
22595
|
+
import { and as and23, desc as desc11, eq as eq28 } from "drizzle-orm";
|
|
22596
|
+
|
|
22597
|
+
// ../api-routes/src/content-data.ts
|
|
22598
|
+
import { and as and22, eq as eq27, desc as desc10, gte as gte5, inArray as inArray11, lte as lte3 } from "drizzle-orm";
|
|
22599
|
+
|
|
22600
|
+
// ../api-routes/src/gsc-totals.ts
|
|
22601
|
+
import { and as and21, asc as asc4, eq as eq26, sql as sql9, max, min } from "drizzle-orm";
|
|
22602
|
+
var WINDOW_DAYS = { "7d": 7, "30d": 30, "90d": 90 };
|
|
22603
|
+
function resolveGscWindowRange(window, latestDataDate, today) {
|
|
22604
|
+
if (window === "all") {
|
|
22605
|
+
return {
|
|
22606
|
+
startDate: null,
|
|
22607
|
+
endDate: latestDataDate,
|
|
22608
|
+
latestDataDate,
|
|
22609
|
+
daysSinceLatestData: gscDaysSinceLatestData(latestDataDate, today)
|
|
22610
|
+
};
|
|
22611
|
+
}
|
|
22612
|
+
return resolveGscWindowDays(WINDOW_DAYS[window], latestDataDate, today);
|
|
22613
|
+
}
|
|
22614
|
+
function resolveGscWindowDays(days, latestDataDate, today) {
|
|
22615
|
+
if (latestDataDate === null) {
|
|
22616
|
+
return {
|
|
22617
|
+
startDate: shiftIsoCalendarDate(today, -days),
|
|
22618
|
+
endDate: null,
|
|
22619
|
+
latestDataDate: null,
|
|
22620
|
+
daysSinceLatestData: null
|
|
22621
|
+
};
|
|
22622
|
+
}
|
|
22623
|
+
return {
|
|
22624
|
+
startDate: shiftIsoCalendarDate(latestDataDate, -(days - 1)),
|
|
22625
|
+
endDate: latestDataDate,
|
|
22626
|
+
latestDataDate,
|
|
22627
|
+
daysSinceLatestData: gscDaysSinceLatestData(latestDataDate, today)
|
|
22628
|
+
};
|
|
22629
|
+
}
|
|
22630
|
+
function gscDaysSinceLatestData(latestDataDate, today) {
|
|
22631
|
+
if (latestDataDate === null) return null;
|
|
22632
|
+
return Math.max(0, Math.round(
|
|
22633
|
+
(Date.parse(`${today}T00:00:00Z`) - Date.parse(`${latestDataDate}T00:00:00Z`)) / 864e5
|
|
22634
|
+
));
|
|
22635
|
+
}
|
|
22636
|
+
function readLatestGscDataDate(db, projectId) {
|
|
22637
|
+
const watermark = db.select({ through: gscDataWatermarks.dataThroughDate }).from(gscDataWatermarks).where(eq26(gscDataWatermarks.projectId, projectId)).get()?.through ?? null;
|
|
22638
|
+
const property = db.select({ latest: max(gscDailyTotals.date) }).from(gscDailyTotals).where(eq26(gscDailyTotals.projectId, projectId)).get()?.latest ?? null;
|
|
22639
|
+
const dimensioned = db.select({ latest: max(gscSearchData.date) }).from(gscSearchData).where(eq26(gscSearchData.projectId, projectId)).get()?.latest ?? null;
|
|
22640
|
+
return [watermark, property, dimensioned].filter((d) => d !== null).reduce((maxDate, d) => maxDate === null || d > maxDate ? d : maxDate, null);
|
|
22641
|
+
}
|
|
22642
|
+
function readEarliestGscDataDate(db, projectId) {
|
|
22643
|
+
const property = db.select({ earliest: min(gscDailyTotals.date) }).from(gscDailyTotals).where(eq26(gscDailyTotals.projectId, projectId)).get()?.earliest ?? null;
|
|
22644
|
+
const dimensioned = db.select({ earliest: min(gscSearchData.date) }).from(gscSearchData).where(eq26(gscSearchData.projectId, projectId)).get()?.earliest ?? null;
|
|
22645
|
+
return [property, dimensioned].filter((d) => d !== null).reduce((earliest, d) => earliest === null || d < earliest ? d : earliest, null);
|
|
22646
|
+
}
|
|
22647
|
+
function readGscDailyTotals(db, projectId, startDate, endDate) {
|
|
22648
|
+
const rows = db.select({
|
|
22649
|
+
date: gscDailyTotals.date,
|
|
22650
|
+
clicks: gscDailyTotals.clicks,
|
|
22651
|
+
impressions: gscDailyTotals.impressions,
|
|
22652
|
+
position: gscDailyTotals.position
|
|
22653
|
+
}).from(gscDailyTotals).where(
|
|
22654
|
+
and21(
|
|
22655
|
+
eq26(gscDailyTotals.projectId, projectId),
|
|
22656
|
+
sql9`${gscDailyTotals.date} >= ${startDate}`,
|
|
22657
|
+
sql9`${gscDailyTotals.date} <= ${endDate}`
|
|
22658
|
+
)
|
|
22659
|
+
).orderBy(asc4(gscDailyTotals.date)).all();
|
|
22660
|
+
return rows.map((r) => {
|
|
22661
|
+
const position = Number(r.position);
|
|
22662
|
+
return {
|
|
22663
|
+
date: r.date,
|
|
22664
|
+
clicks: r.clicks,
|
|
22665
|
+
impressions: r.impressions,
|
|
22666
|
+
position: Number.isFinite(position) ? position : 0
|
|
22667
|
+
};
|
|
22668
|
+
});
|
|
22669
|
+
}
|
|
22670
|
+
function mergeGscDailyTotalsWithFallback(propertyTotals, dimensionedFallback) {
|
|
22671
|
+
const byDate = /* @__PURE__ */ new Map();
|
|
22672
|
+
for (const row of dimensionedFallback) byDate.set(row.date, row);
|
|
22673
|
+
for (const row of propertyTotals) byDate.set(row.date, row);
|
|
22674
|
+
return [...byDate.values()].sort((a, b) => a.date.localeCompare(b.date));
|
|
22675
|
+
}
|
|
22676
|
+
function readGscQueryDailyRows(db, projectId, startDate, endDate) {
|
|
22677
|
+
const rows = db.select({
|
|
22678
|
+
date: gscQueryDailyTotals.date,
|
|
22679
|
+
query: gscQueryDailyTotals.query,
|
|
22680
|
+
clicks: gscQueryDailyTotals.clicks,
|
|
22681
|
+
impressions: gscQueryDailyTotals.impressions,
|
|
22682
|
+
position: gscQueryDailyTotals.position
|
|
22683
|
+
}).from(gscQueryDailyTotals).where(
|
|
22684
|
+
and21(
|
|
22685
|
+
eq26(gscQueryDailyTotals.projectId, projectId),
|
|
22686
|
+
sql9`${gscQueryDailyTotals.date} >= ${startDate}`,
|
|
22687
|
+
sql9`${gscQueryDailyTotals.date} <= ${endDate}`
|
|
22688
|
+
)
|
|
22689
|
+
).all();
|
|
22690
|
+
return rows.map((r) => {
|
|
22691
|
+
const position = Number(r.position);
|
|
22692
|
+
return {
|
|
22693
|
+
date: r.date,
|
|
22694
|
+
query: r.query,
|
|
22695
|
+
clicks: r.clicks,
|
|
22696
|
+
impressions: r.impressions,
|
|
22697
|
+
position: Number.isFinite(position) ? position : 0
|
|
22698
|
+
};
|
|
22699
|
+
});
|
|
22700
|
+
}
|
|
22701
|
+
function mergeGscQueryTotalsWithFallback(accurateDays, fallbackDays) {
|
|
22702
|
+
const dayKey = (r) => `${r.date}\0${r.query}`;
|
|
22703
|
+
const byDay = /* @__PURE__ */ new Map();
|
|
22704
|
+
for (const row of fallbackDays) byDay.set(dayKey(row), { row, accurate: false });
|
|
22705
|
+
for (const row of accurateDays) byDay.set(dayKey(row), { row, accurate: true });
|
|
22706
|
+
const byQuery = /* @__PURE__ */ new Map();
|
|
22707
|
+
for (const { row, accurate } of byDay.values()) {
|
|
22708
|
+
const acc = byQuery.get(row.query) ?? {
|
|
22709
|
+
clicks: 0,
|
|
22710
|
+
impressions: 0,
|
|
22711
|
+
weightedPositionSum: 0,
|
|
22712
|
+
positionSum: 0,
|
|
22713
|
+
positionDays: 0,
|
|
22714
|
+
sawAccurate: false,
|
|
22715
|
+
sawLegacy: false
|
|
22716
|
+
};
|
|
22717
|
+
acc.clicks += row.clicks;
|
|
22718
|
+
acc.impressions += row.impressions;
|
|
22719
|
+
acc.weightedPositionSum += row.position * row.impressions;
|
|
22720
|
+
acc.positionSum += row.position;
|
|
22721
|
+
acc.positionDays += 1;
|
|
22722
|
+
if (accurate) acc.sawAccurate = true;
|
|
22723
|
+
else acc.sawLegacy = true;
|
|
22724
|
+
byQuery.set(row.query, acc);
|
|
22725
|
+
}
|
|
22726
|
+
return [...byQuery.entries()].map(([query, acc]) => ({
|
|
22727
|
+
query,
|
|
22728
|
+
clicks: acc.clicks,
|
|
22729
|
+
impressions: acc.impressions,
|
|
22730
|
+
position: acc.impressions > 0 ? acc.weightedPositionSum / acc.impressions : acc.positionDays > 0 ? acc.positionSum / acc.positionDays : 0,
|
|
22731
|
+
source: acc.sawAccurate && acc.sawLegacy ? "mixed" : acc.sawAccurate ? "google" : "page-summed"
|
|
22732
|
+
}));
|
|
22733
|
+
}
|
|
22596
22734
|
|
|
22597
22735
|
// ../api-routes/src/content-data.ts
|
|
22598
|
-
import { and as and21, eq as eq26, desc as desc10, inArray as inArray11 } from "drizzle-orm";
|
|
22599
22736
|
var RECENT_RUNS_WINDOW = 5;
|
|
22600
|
-
function loadOrchestratorInput(db, project, locationFilter = void 0) {
|
|
22737
|
+
function loadOrchestratorInput(db, project, locationFilter = void 0, gscWindowDays = DEFAULT_CONTENT_GSC_WINDOW_DAYS) {
|
|
22601
22738
|
const projectId = project.id;
|
|
22602
22739
|
const ownDomain = hostOf(project.canonicalDomain) ?? "";
|
|
22603
22740
|
const ownedDomains = project.ownedDomains ?? [];
|
|
@@ -22616,7 +22753,8 @@ function loadOrchestratorInput(db, project, locationFilter = void 0) {
|
|
|
22616
22753
|
recentRunIds,
|
|
22617
22754
|
latestRunId,
|
|
22618
22755
|
ourDomains,
|
|
22619
|
-
competitorSet
|
|
22756
|
+
competitorSet,
|
|
22757
|
+
gscWindowDays
|
|
22620
22758
|
});
|
|
22621
22759
|
const inventory = buildInventory({
|
|
22622
22760
|
gscPages: listGscPagesForProject(db, projectId),
|
|
@@ -22644,7 +22782,7 @@ function loadOrchestratorInput(db, project, locationFilter = void 0) {
|
|
|
22644
22782
|
};
|
|
22645
22783
|
}
|
|
22646
22784
|
function loadDomainClasses(db, projectId) {
|
|
22647
|
-
const rows = db.select({ domain: domainClassifications.domain, competitorType: domainClassifications.competitorType }).from(domainClassifications).where(
|
|
22785
|
+
const rows = db.select({ domain: domainClassifications.domain, competitorType: domainClassifications.competitorType }).from(domainClassifications).where(eq27(domainClassifications.projectId, projectId)).all();
|
|
22648
22786
|
return new Map(rows.map((r) => [hostOf(r.domain) ?? "", r.competitorType]));
|
|
22649
22787
|
}
|
|
22650
22788
|
function buildQueryIntentModifiers(project, locationFilter) {
|
|
@@ -22716,18 +22854,18 @@ var US_REGION_ABBREVIATIONS = {
|
|
|
22716
22854
|
wyoming: "wy"
|
|
22717
22855
|
};
|
|
22718
22856
|
function listQueries(db, projectId) {
|
|
22719
|
-
const rows = db.select({ text: queries.query }).from(queries).where(
|
|
22857
|
+
const rows = db.select({ text: queries.query }).from(queries).where(eq27(queries.projectId, projectId)).all();
|
|
22720
22858
|
return rows.map((r) => r.text);
|
|
22721
22859
|
}
|
|
22722
22860
|
function listCompetitorDomains(db, projectId) {
|
|
22723
|
-
const rows = db.select({ domain: competitors.domain }).from(competitors).where(
|
|
22861
|
+
const rows = db.select({ domain: competitors.domain }).from(competitors).where(eq27(competitors.projectId, projectId)).all();
|
|
22724
22862
|
return rows.map((r) => r.domain);
|
|
22725
22863
|
}
|
|
22726
22864
|
function listRecentAnswerVisibilityRunIds(db, projectId, limit, locationFilter) {
|
|
22727
22865
|
const rows = db.select({ id: runs.id, location: runs.location }).from(runs).where(
|
|
22728
|
-
|
|
22729
|
-
|
|
22730
|
-
|
|
22866
|
+
and22(
|
|
22867
|
+
eq27(runs.projectId, projectId),
|
|
22868
|
+
eq27(runs.kind, RunKinds["answer-visibility"]),
|
|
22731
22869
|
// Queued/running/failed/cancelled runs may have partial or no
|
|
22732
22870
|
// snapshots; including them risks pointing latestRunId at a run with
|
|
22733
22871
|
// no usable evidence.
|
|
@@ -22741,22 +22879,22 @@ function listRecentAnswerVisibilityRunIds(db, projectId, limit, locationFilter)
|
|
|
22741
22879
|
return filtered.slice(0, limit).map((r) => r.id);
|
|
22742
22880
|
}
|
|
22743
22881
|
function lookupRunTimestamp(db, runId) {
|
|
22744
|
-
const row = db.select({ createdAt: runs.createdAt }).from(runs).where(
|
|
22882
|
+
const row = db.select({ createdAt: runs.createdAt }).from(runs).where(eq27(runs.id, runId)).get();
|
|
22745
22883
|
return row?.createdAt ?? "";
|
|
22746
22884
|
}
|
|
22747
22885
|
function listGscPagesForProject(db, projectId) {
|
|
22748
|
-
const rows = db.selectDistinct({ page: gscSearchData.page }).from(gscSearchData).where(
|
|
22886
|
+
const rows = db.selectDistinct({ page: gscSearchData.page }).from(gscSearchData).where(eq27(gscSearchData.projectId, projectId)).all();
|
|
22749
22887
|
return rows.map((r) => r.page);
|
|
22750
22888
|
}
|
|
22751
22889
|
function listGa4LandingPagesForProject(db, projectId) {
|
|
22752
|
-
const rows = db.selectDistinct({ landingPage: gaTrafficSnapshots.landingPage }).from(gaTrafficSnapshots).where(
|
|
22890
|
+
const rows = db.selectDistinct({ landingPage: gaTrafficSnapshots.landingPage }).from(gaTrafficSnapshots).where(eq27(gaTrafficSnapshots.projectId, projectId)).all();
|
|
22753
22891
|
return rows.map((r) => r.landingPage);
|
|
22754
22892
|
}
|
|
22755
22893
|
function buildGaTrafficByPage(db, projectId) {
|
|
22756
22894
|
const rows = db.select({
|
|
22757
22895
|
landingPage: gaTrafficSnapshots.landingPage,
|
|
22758
22896
|
sessions: gaTrafficSnapshots.sessions
|
|
22759
|
-
}).from(gaTrafficSnapshots).where(
|
|
22897
|
+
}).from(gaTrafficSnapshots).where(eq27(gaTrafficSnapshots.projectId, projectId)).all();
|
|
22760
22898
|
const map = /* @__PURE__ */ new Map();
|
|
22761
22899
|
for (const row of rows) {
|
|
22762
22900
|
const path8 = extractPath2(row.landingPage);
|
|
@@ -22767,9 +22905,9 @@ function buildGaTrafficByPage(db, projectId) {
|
|
|
22767
22905
|
}
|
|
22768
22906
|
function sumAiReferralSessions(db, projectId) {
|
|
22769
22907
|
const rows = db.select({ sessions: gaAiReferrals.sessions }).from(gaAiReferrals).where(
|
|
22770
|
-
|
|
22771
|
-
|
|
22772
|
-
|
|
22908
|
+
and22(
|
|
22909
|
+
eq27(gaAiReferrals.projectId, projectId),
|
|
22910
|
+
eq27(gaAiReferrals.sourceDimension, "session")
|
|
22773
22911
|
)
|
|
22774
22912
|
).all();
|
|
22775
22913
|
return rows.reduce((acc, r) => acc + (r.sessions ?? 0), 0);
|
|
@@ -22778,7 +22916,7 @@ function buildCandidateQueries(opts) {
|
|
|
22778
22916
|
if (opts.candidateQueryStrings.length === 0 || opts.recentRunIds.length === 0) {
|
|
22779
22917
|
return opts.candidateQueryStrings.map((query) => emptyCandidate(query));
|
|
22780
22918
|
}
|
|
22781
|
-
const queryRows = opts.db.select({ id: queries.id, text: queries.query }).from(queries).where(
|
|
22919
|
+
const queryRows = opts.db.select({ id: queries.id, text: queries.query }).from(queries).where(eq27(queries.projectId, opts.projectId)).all();
|
|
22782
22920
|
const queryIdByText = new Map(queryRows.map((r) => [r.text, r.id]));
|
|
22783
22921
|
const candidateQueryIds = opts.candidateQueryStrings.map((q) => queryIdByText.get(q)).filter((id) => Boolean(id));
|
|
22784
22922
|
const snapshotRows = filterTrackedSnapshots(opts.db.select().from(querySnapshots).where(inArray11(querySnapshots.runId, opts.recentRunIds)).all()).filter((r) => candidateQueryIds.includes(r.queryId));
|
|
@@ -22788,8 +22926,19 @@ function buildCandidateQueries(opts) {
|
|
|
22788
22926
|
list.push(row);
|
|
22789
22927
|
snapshotsByQuery.set(row.queryId, list);
|
|
22790
22928
|
}
|
|
22791
|
-
const
|
|
22792
|
-
const
|
|
22929
|
+
const gscWindow = resolveContentGscWindow(opts.db, opts.projectId, opts.gscWindowDays);
|
|
22930
|
+
const pageRows = gscWindow ? opts.db.select().from(gscSearchData).where(and22(
|
|
22931
|
+
eq27(gscSearchData.projectId, opts.projectId),
|
|
22932
|
+
gte5(gscSearchData.date, gscWindow.startDate),
|
|
22933
|
+
lte3(gscSearchData.date, gscWindow.endDate)
|
|
22934
|
+
)).all() : [];
|
|
22935
|
+
const gscByQuery = aggregateGscByQuery(
|
|
22936
|
+
pageRows,
|
|
22937
|
+
gscWindow ? mergeGscQueryTotalsWithFallback(
|
|
22938
|
+
readGscQueryDailyRows(opts.db, opts.projectId, gscWindow.startDate, gscWindow.endDate),
|
|
22939
|
+
pageDayFallback(pageRows)
|
|
22940
|
+
) : []
|
|
22941
|
+
);
|
|
22793
22942
|
return opts.candidateQueryStrings.map((query) => {
|
|
22794
22943
|
const queryId = queryIdByText.get(query);
|
|
22795
22944
|
const snaps = queryId ? snapshotsByQuery.get(queryId) ?? [] : [];
|
|
@@ -22804,7 +22953,35 @@ function buildCandidateQueries(opts) {
|
|
|
22804
22953
|
});
|
|
22805
22954
|
});
|
|
22806
22955
|
}
|
|
22807
|
-
|
|
22956
|
+
var DEFAULT_CONTENT_GSC_WINDOW_DAYS = 30;
|
|
22957
|
+
function resolveContentGscWindow(db, projectId, windowDays2) {
|
|
22958
|
+
const endDate = readLatestGscDataDate(db, projectId);
|
|
22959
|
+
if (!endDate) return null;
|
|
22960
|
+
const end = /* @__PURE__ */ new Date(`${endDate}T00:00:00Z`);
|
|
22961
|
+
end.setUTCDate(end.getUTCDate() - (Math.max(1, windowDays2) - 1));
|
|
22962
|
+
return { startDate: end.toISOString().slice(0, 10), endDate };
|
|
22963
|
+
}
|
|
22964
|
+
function pageDayFallback(rows) {
|
|
22965
|
+
const byDay = /* @__PURE__ */ new Map();
|
|
22966
|
+
for (const r of rows) {
|
|
22967
|
+
if (!r.query) continue;
|
|
22968
|
+
const key = `${r.date}\0${r.query}`;
|
|
22969
|
+
const acc = byDay.get(key) ?? { date: r.date, query: r.query, clicks: 0, impressions: 0, weighted: 0 };
|
|
22970
|
+
acc.clicks += r.clicks;
|
|
22971
|
+
acc.impressions += r.impressions;
|
|
22972
|
+
acc.weighted += (Number(r.position) || 0) * r.impressions;
|
|
22973
|
+
byDay.set(key, acc);
|
|
22974
|
+
}
|
|
22975
|
+
return [...byDay.values()].map((a) => ({
|
|
22976
|
+
date: a.date,
|
|
22977
|
+
query: a.query,
|
|
22978
|
+
clicks: a.clicks,
|
|
22979
|
+
impressions: a.impressions,
|
|
22980
|
+
position: a.impressions > 0 ? a.weighted / a.impressions : 0
|
|
22981
|
+
}));
|
|
22982
|
+
}
|
|
22983
|
+
function aggregateGscByQuery(rows, queryTotals = []) {
|
|
22984
|
+
const accurateByQuery = new Map(queryTotals.map((t) => [t.query, t]));
|
|
22808
22985
|
const accumulators = /* @__PURE__ */ new Map();
|
|
22809
22986
|
for (const r of rows) {
|
|
22810
22987
|
const page2 = extractPath2(r.page);
|
|
@@ -22830,12 +23007,16 @@ function aggregateGscByQuery(rows) {
|
|
|
22830
23007
|
}
|
|
22831
23008
|
const byQuery = /* @__PURE__ */ new Map();
|
|
22832
23009
|
for (const [query, acc] of accumulators) {
|
|
23010
|
+
const accurate = accurateByQuery.get(query);
|
|
23011
|
+
const impressions = accurate ? accurate.impressions : acc.totalImpressions;
|
|
23012
|
+
const clicks = accurate ? accurate.clicks : acc.totalClicks;
|
|
23013
|
+
const position = accurate ? accurate.position : acc.totalImpressions > 0 ? acc.weightedPositionSum / acc.totalImpressions : 0;
|
|
22833
23014
|
byQuery.set(query, {
|
|
22834
23015
|
page: acc.bestPage,
|
|
22835
|
-
position
|
|
22836
|
-
impressions
|
|
22837
|
-
clicks
|
|
22838
|
-
ctr:
|
|
23016
|
+
position,
|
|
23017
|
+
impressions,
|
|
23018
|
+
clicks,
|
|
23019
|
+
ctr: impressions > 0 ? clicks / impressions : 0
|
|
22839
23020
|
});
|
|
22840
23021
|
}
|
|
22841
23022
|
return byQuery;
|
|
@@ -22987,7 +23168,7 @@ function extractPath2(url) {
|
|
|
22987
23168
|
|
|
22988
23169
|
// ../api-routes/src/content.ts
|
|
22989
23170
|
function loadDismissedTargetRefs(db, projectId) {
|
|
22990
|
-
const rows = db.select({ targetRef: contentTargetDismissals.targetRef }).from(contentTargetDismissals).where(
|
|
23171
|
+
const rows = db.select({ targetRef: contentTargetDismissals.targetRef }).from(contentTargetDismissals).where(eq28(contentTargetDismissals.projectId, projectId)).all();
|
|
22991
23172
|
return new Set(rows.map((r) => r.targetRef));
|
|
22992
23173
|
}
|
|
22993
23174
|
function formatDismissalRow(row) {
|
|
@@ -23082,7 +23263,7 @@ async function contentRoutes(app, opts = {}) {
|
|
|
23082
23263
|
});
|
|
23083
23264
|
app.get("/projects/:name/content/dismissals", async (request) => {
|
|
23084
23265
|
const project = resolveProject(app.db, request.params.name);
|
|
23085
|
-
const rows = app.db.select().from(contentTargetDismissals).where(
|
|
23266
|
+
const rows = app.db.select().from(contentTargetDismissals).where(eq28(contentTargetDismissals.projectId, project.id)).orderBy(contentTargetDismissals.dismissedAt).all();
|
|
23086
23267
|
const response = {
|
|
23087
23268
|
dismissals: rows.map(formatDismissalRow)
|
|
23088
23269
|
};
|
|
@@ -23111,9 +23292,9 @@ async function contentRoutes(app, opts = {}) {
|
|
|
23111
23292
|
dismissedAt: now
|
|
23112
23293
|
}
|
|
23113
23294
|
}).run();
|
|
23114
|
-
const row = app.db.select().from(contentTargetDismissals).where(
|
|
23115
|
-
|
|
23116
|
-
|
|
23295
|
+
const row = app.db.select().from(contentTargetDismissals).where(and23(
|
|
23296
|
+
eq28(contentTargetDismissals.projectId, project.id),
|
|
23297
|
+
eq28(contentTargetDismissals.targetRef, targetRef)
|
|
23117
23298
|
)).get();
|
|
23118
23299
|
if (!row) throw notFound("contentTargetDismissal", targetRef);
|
|
23119
23300
|
return formatDismissalRow(row);
|
|
@@ -23121,9 +23302,9 @@ async function contentRoutes(app, opts = {}) {
|
|
|
23121
23302
|
app.delete("/projects/:name/content/dismissals/:targetRef", async (request, reply) => {
|
|
23122
23303
|
const project = resolveProject(app.db, request.params.name);
|
|
23123
23304
|
const { targetRef } = request.params;
|
|
23124
|
-
const result = app.db.delete(contentTargetDismissals).where(
|
|
23125
|
-
|
|
23126
|
-
|
|
23305
|
+
const result = app.db.delete(contentTargetDismissals).where(and23(
|
|
23306
|
+
eq28(contentTargetDismissals.projectId, project.id),
|
|
23307
|
+
eq28(contentTargetDismissals.targetRef, targetRef)
|
|
23127
23308
|
)).run();
|
|
23128
23309
|
if (result.changes === 0) {
|
|
23129
23310
|
throw notFound("contentTargetDismissal", targetRef);
|
|
@@ -23132,9 +23313,9 @@ async function contentRoutes(app, opts = {}) {
|
|
|
23132
23313
|
});
|
|
23133
23314
|
app.get("/projects/:name/content/recommendations/:targetRef/analysis", async (request, reply) => {
|
|
23134
23315
|
const project = resolveProject(app.db, request.params.name);
|
|
23135
|
-
const row = app.db.select().from(recommendationExplanations).where(
|
|
23136
|
-
|
|
23137
|
-
|
|
23316
|
+
const row = app.db.select().from(recommendationExplanations).where(and23(
|
|
23317
|
+
eq28(recommendationExplanations.projectId, project.id),
|
|
23318
|
+
eq28(recommendationExplanations.targetRef, request.params.targetRef)
|
|
23138
23319
|
)).orderBy(desc11(recommendationExplanations.generatedAt)).limit(1).get();
|
|
23139
23320
|
if (!row) {
|
|
23140
23321
|
return reply.status(404).send({ error: { code: "NOT_FOUND", message: "No cached explanation for this targetRef." } });
|
|
@@ -23160,9 +23341,9 @@ async function contentRoutes(app, opts = {}) {
|
|
|
23160
23341
|
throw notFound("contentRecommendation", targetRef);
|
|
23161
23342
|
}
|
|
23162
23343
|
if (!body.forceRefresh) {
|
|
23163
|
-
const cached = app.db.select().from(recommendationExplanations).where(
|
|
23164
|
-
|
|
23165
|
-
|
|
23344
|
+
const cached = app.db.select().from(recommendationExplanations).where(and23(
|
|
23345
|
+
eq28(recommendationExplanations.projectId, project.id),
|
|
23346
|
+
eq28(recommendationExplanations.targetRef, targetRef)
|
|
23166
23347
|
)).orderBy(desc11(recommendationExplanations.generatedAt)).limit(1).get();
|
|
23167
23348
|
if (cached) return reply.send(formatExplanationRow(cached));
|
|
23168
23349
|
}
|
|
@@ -23199,10 +23380,10 @@ async function contentRoutes(app, opts = {}) {
|
|
|
23199
23380
|
generatedAt: now
|
|
23200
23381
|
}
|
|
23201
23382
|
}).run();
|
|
23202
|
-
const row = app.db.select().from(recommendationExplanations).where(
|
|
23203
|
-
|
|
23204
|
-
|
|
23205
|
-
|
|
23383
|
+
const row = app.db.select().from(recommendationExplanations).where(and23(
|
|
23384
|
+
eq28(recommendationExplanations.projectId, project.id),
|
|
23385
|
+
eq28(recommendationExplanations.targetRef, targetRef),
|
|
23386
|
+
eq28(recommendationExplanations.promptVersion, result.promptVersion)
|
|
23206
23387
|
)).get();
|
|
23207
23388
|
if (!row) throw notFound("recommendationExplanation", targetRef);
|
|
23208
23389
|
return reply.send(formatExplanationRow(row));
|
|
@@ -23283,17 +23464,17 @@ async function contentRoutes(app, opts = {}) {
|
|
|
23283
23464
|
generatedAt: now
|
|
23284
23465
|
}
|
|
23285
23466
|
}).run();
|
|
23286
|
-
const row = app.db.select().from(recommendationBriefs).where(
|
|
23287
|
-
|
|
23288
|
-
|
|
23289
|
-
|
|
23467
|
+
const row = app.db.select().from(recommendationBriefs).where(and23(
|
|
23468
|
+
eq28(recommendationBriefs.projectId, project.id),
|
|
23469
|
+
eq28(recommendationBriefs.targetRef, targetRef),
|
|
23470
|
+
eq28(recommendationBriefs.promptVersion, result.promptVersion)
|
|
23290
23471
|
)).get();
|
|
23291
23472
|
if (!row) throw notFound("recommendationBrief", targetRef);
|
|
23292
23473
|
return reply.send(formatBriefRow(row));
|
|
23293
23474
|
});
|
|
23294
23475
|
app.get("/projects/:name/content/domain-classifications", async (request) => {
|
|
23295
23476
|
const project = resolveProject(app.db, request.params.name);
|
|
23296
|
-
const rows = app.db.select().from(domainClassifications).where(
|
|
23477
|
+
const rows = app.db.select().from(domainClassifications).where(eq28(domainClassifications.projectId, project.id)).orderBy(desc11(domainClassifications.hits)).all();
|
|
23297
23478
|
const response = {
|
|
23298
23479
|
classifications: rows.map((r) => ({
|
|
23299
23480
|
domain: r.domain,
|
|
@@ -23307,13 +23488,13 @@ async function contentRoutes(app, opts = {}) {
|
|
|
23307
23488
|
}
|
|
23308
23489
|
function lookupCachedBrief(db, projectId, targetRef, promptVersion) {
|
|
23309
23490
|
const conditions = [
|
|
23310
|
-
|
|
23311
|
-
|
|
23491
|
+
eq28(recommendationBriefs.projectId, projectId),
|
|
23492
|
+
eq28(recommendationBriefs.targetRef, targetRef)
|
|
23312
23493
|
];
|
|
23313
23494
|
if (promptVersion !== void 0) {
|
|
23314
|
-
conditions.push(
|
|
23495
|
+
conditions.push(eq28(recommendationBriefs.promptVersion, promptVersion));
|
|
23315
23496
|
}
|
|
23316
|
-
return db.select().from(recommendationBriefs).where(
|
|
23497
|
+
return db.select().from(recommendationBriefs).where(and23(...conditions)).orderBy(desc11(recommendationBriefs.generatedAt)).limit(1).get();
|
|
23317
23498
|
}
|
|
23318
23499
|
function parseLimitParam(raw) {
|
|
23319
23500
|
if (raw === void 0) return void 0;
|
|
@@ -23338,141 +23519,6 @@ function winnabilityClassRank(winnabilityClass) {
|
|
|
23338
23519
|
return winnabilityClass === WinnabilityClasses.ownable ? 0 : 1;
|
|
23339
23520
|
}
|
|
23340
23521
|
|
|
23341
|
-
// ../api-routes/src/gsc-totals.ts
|
|
23342
|
-
import { and as and23, asc as asc4, eq as eq28, sql as sql9, max, min } from "drizzle-orm";
|
|
23343
|
-
var WINDOW_DAYS = { "7d": 7, "30d": 30, "90d": 90 };
|
|
23344
|
-
function resolveGscWindowRange(window, latestDataDate, today) {
|
|
23345
|
-
if (window === "all") {
|
|
23346
|
-
return {
|
|
23347
|
-
startDate: null,
|
|
23348
|
-
endDate: latestDataDate,
|
|
23349
|
-
latestDataDate,
|
|
23350
|
-
daysSinceLatestData: gscDaysSinceLatestData(latestDataDate, today)
|
|
23351
|
-
};
|
|
23352
|
-
}
|
|
23353
|
-
return resolveGscWindowDays(WINDOW_DAYS[window], latestDataDate, today);
|
|
23354
|
-
}
|
|
23355
|
-
function resolveGscWindowDays(days, latestDataDate, today) {
|
|
23356
|
-
if (latestDataDate === null) {
|
|
23357
|
-
return {
|
|
23358
|
-
startDate: shiftIsoCalendarDate(today, -days),
|
|
23359
|
-
endDate: null,
|
|
23360
|
-
latestDataDate: null,
|
|
23361
|
-
daysSinceLatestData: null
|
|
23362
|
-
};
|
|
23363
|
-
}
|
|
23364
|
-
return {
|
|
23365
|
-
startDate: shiftIsoCalendarDate(latestDataDate, -(days - 1)),
|
|
23366
|
-
endDate: latestDataDate,
|
|
23367
|
-
latestDataDate,
|
|
23368
|
-
daysSinceLatestData: gscDaysSinceLatestData(latestDataDate, today)
|
|
23369
|
-
};
|
|
23370
|
-
}
|
|
23371
|
-
function gscDaysSinceLatestData(latestDataDate, today) {
|
|
23372
|
-
if (latestDataDate === null) return null;
|
|
23373
|
-
return Math.max(0, Math.round(
|
|
23374
|
-
(Date.parse(`${today}T00:00:00Z`) - Date.parse(`${latestDataDate}T00:00:00Z`)) / 864e5
|
|
23375
|
-
));
|
|
23376
|
-
}
|
|
23377
|
-
function readLatestGscDataDate(db, projectId) {
|
|
23378
|
-
const watermark = db.select({ through: gscDataWatermarks.dataThroughDate }).from(gscDataWatermarks).where(eq28(gscDataWatermarks.projectId, projectId)).get()?.through ?? null;
|
|
23379
|
-
const property = db.select({ latest: max(gscDailyTotals.date) }).from(gscDailyTotals).where(eq28(gscDailyTotals.projectId, projectId)).get()?.latest ?? null;
|
|
23380
|
-
const dimensioned = db.select({ latest: max(gscSearchData.date) }).from(gscSearchData).where(eq28(gscSearchData.projectId, projectId)).get()?.latest ?? null;
|
|
23381
|
-
return [watermark, property, dimensioned].filter((d) => d !== null).reduce((maxDate, d) => maxDate === null || d > maxDate ? d : maxDate, null);
|
|
23382
|
-
}
|
|
23383
|
-
function readEarliestGscDataDate(db, projectId) {
|
|
23384
|
-
const property = db.select({ earliest: min(gscDailyTotals.date) }).from(gscDailyTotals).where(eq28(gscDailyTotals.projectId, projectId)).get()?.earliest ?? null;
|
|
23385
|
-
const dimensioned = db.select({ earliest: min(gscSearchData.date) }).from(gscSearchData).where(eq28(gscSearchData.projectId, projectId)).get()?.earliest ?? null;
|
|
23386
|
-
return [property, dimensioned].filter((d) => d !== null).reduce((earliest, d) => earliest === null || d < earliest ? d : earliest, null);
|
|
23387
|
-
}
|
|
23388
|
-
function readGscDailyTotals(db, projectId, startDate, endDate) {
|
|
23389
|
-
const rows = db.select({
|
|
23390
|
-
date: gscDailyTotals.date,
|
|
23391
|
-
clicks: gscDailyTotals.clicks,
|
|
23392
|
-
impressions: gscDailyTotals.impressions,
|
|
23393
|
-
position: gscDailyTotals.position
|
|
23394
|
-
}).from(gscDailyTotals).where(
|
|
23395
|
-
and23(
|
|
23396
|
-
eq28(gscDailyTotals.projectId, projectId),
|
|
23397
|
-
sql9`${gscDailyTotals.date} >= ${startDate}`,
|
|
23398
|
-
sql9`${gscDailyTotals.date} <= ${endDate}`
|
|
23399
|
-
)
|
|
23400
|
-
).orderBy(asc4(gscDailyTotals.date)).all();
|
|
23401
|
-
return rows.map((r) => {
|
|
23402
|
-
const position = Number(r.position);
|
|
23403
|
-
return {
|
|
23404
|
-
date: r.date,
|
|
23405
|
-
clicks: r.clicks,
|
|
23406
|
-
impressions: r.impressions,
|
|
23407
|
-
position: Number.isFinite(position) ? position : 0
|
|
23408
|
-
};
|
|
23409
|
-
});
|
|
23410
|
-
}
|
|
23411
|
-
function mergeGscDailyTotalsWithFallback(propertyTotals, dimensionedFallback) {
|
|
23412
|
-
const byDate = /* @__PURE__ */ new Map();
|
|
23413
|
-
for (const row of dimensionedFallback) byDate.set(row.date, row);
|
|
23414
|
-
for (const row of propertyTotals) byDate.set(row.date, row);
|
|
23415
|
-
return [...byDate.values()].sort((a, b) => a.date.localeCompare(b.date));
|
|
23416
|
-
}
|
|
23417
|
-
function readGscQueryDailyRows(db, projectId, startDate, endDate) {
|
|
23418
|
-
const rows = db.select({
|
|
23419
|
-
date: gscQueryDailyTotals.date,
|
|
23420
|
-
query: gscQueryDailyTotals.query,
|
|
23421
|
-
clicks: gscQueryDailyTotals.clicks,
|
|
23422
|
-
impressions: gscQueryDailyTotals.impressions,
|
|
23423
|
-
position: gscQueryDailyTotals.position
|
|
23424
|
-
}).from(gscQueryDailyTotals).where(
|
|
23425
|
-
and23(
|
|
23426
|
-
eq28(gscQueryDailyTotals.projectId, projectId),
|
|
23427
|
-
sql9`${gscQueryDailyTotals.date} >= ${startDate}`,
|
|
23428
|
-
sql9`${gscQueryDailyTotals.date} <= ${endDate}`
|
|
23429
|
-
)
|
|
23430
|
-
).all();
|
|
23431
|
-
return rows.map((r) => {
|
|
23432
|
-
const position = Number(r.position);
|
|
23433
|
-
return {
|
|
23434
|
-
date: r.date,
|
|
23435
|
-
query: r.query,
|
|
23436
|
-
clicks: r.clicks,
|
|
23437
|
-
impressions: r.impressions,
|
|
23438
|
-
position: Number.isFinite(position) ? position : 0
|
|
23439
|
-
};
|
|
23440
|
-
});
|
|
23441
|
-
}
|
|
23442
|
-
function mergeGscQueryTotalsWithFallback(accurateDays, fallbackDays) {
|
|
23443
|
-
const dayKey = (r) => `${r.date}\0${r.query}`;
|
|
23444
|
-
const byDay = /* @__PURE__ */ new Map();
|
|
23445
|
-
for (const row of fallbackDays) byDay.set(dayKey(row), { row, accurate: false });
|
|
23446
|
-
for (const row of accurateDays) byDay.set(dayKey(row), { row, accurate: true });
|
|
23447
|
-
const byQuery = /* @__PURE__ */ new Map();
|
|
23448
|
-
for (const { row, accurate } of byDay.values()) {
|
|
23449
|
-
const acc = byQuery.get(row.query) ?? {
|
|
23450
|
-
clicks: 0,
|
|
23451
|
-
impressions: 0,
|
|
23452
|
-
weightedPositionSum: 0,
|
|
23453
|
-
positionSum: 0,
|
|
23454
|
-
positionDays: 0,
|
|
23455
|
-
sawAccurate: false,
|
|
23456
|
-
sawLegacy: false
|
|
23457
|
-
};
|
|
23458
|
-
acc.clicks += row.clicks;
|
|
23459
|
-
acc.impressions += row.impressions;
|
|
23460
|
-
acc.weightedPositionSum += row.position * row.impressions;
|
|
23461
|
-
acc.positionSum += row.position;
|
|
23462
|
-
acc.positionDays += 1;
|
|
23463
|
-
if (accurate) acc.sawAccurate = true;
|
|
23464
|
-
else acc.sawLegacy = true;
|
|
23465
|
-
byQuery.set(row.query, acc);
|
|
23466
|
-
}
|
|
23467
|
-
return [...byQuery.entries()].map(([query, acc]) => ({
|
|
23468
|
-
query,
|
|
23469
|
-
clicks: acc.clicks,
|
|
23470
|
-
impressions: acc.impressions,
|
|
23471
|
-
position: acc.impressions > 0 ? acc.weightedPositionSum / acc.impressions : acc.positionDays > 0 ? acc.positionSum / acc.positionDays : 0,
|
|
23472
|
-
source: acc.sawAccurate && acc.sawLegacy ? "mixed" : acc.sawAccurate ? "google" : "page-summed"
|
|
23473
|
-
}));
|
|
23474
|
-
}
|
|
23475
|
-
|
|
23476
23522
|
// ../api-routes/src/report-renderer.ts
|
|
23477
23523
|
var COLORS = {
|
|
23478
23524
|
bg: "#09090b",
|
|
@@ -25764,6 +25810,149 @@ function renderReportHtml(report, opts = {}) {
|
|
|
25764
25810
|
</html>`;
|
|
25765
25811
|
}
|
|
25766
25812
|
|
|
25813
|
+
// ../api-routes/src/ga-ai-referral-aggregation.ts
|
|
25814
|
+
function normalizeAiTrafficClass(value) {
|
|
25815
|
+
return value === AiReferralTrafficClasses.paid ? AiReferralTrafficClasses.paid : AiReferralTrafficClasses.organic;
|
|
25816
|
+
}
|
|
25817
|
+
function emptyAiCounts() {
|
|
25818
|
+
return { sessions: 0 };
|
|
25819
|
+
}
|
|
25820
|
+
var AI_ATTRIBUTION_PREFERRED_DIMENSION = "session";
|
|
25821
|
+
function pickWinningAttributionDimension(sessionsByDimension) {
|
|
25822
|
+
let winner;
|
|
25823
|
+
let winnerSessions = -1;
|
|
25824
|
+
for (const [dimension, sessions] of sessionsByDimension) {
|
|
25825
|
+
const beatsOnCount = sessions > winnerSessions;
|
|
25826
|
+
const winsTie = sessions === winnerSessions && dimension === AI_ATTRIBUTION_PREFERRED_DIMENSION;
|
|
25827
|
+
if (beatsOnCount || winsTie) {
|
|
25828
|
+
winnerSessions = sessions;
|
|
25829
|
+
winner = dimension;
|
|
25830
|
+
}
|
|
25831
|
+
}
|
|
25832
|
+
return winner;
|
|
25833
|
+
}
|
|
25834
|
+
function resolveWinningDimensions(rows) {
|
|
25835
|
+
const groups = /* @__PURE__ */ new Map();
|
|
25836
|
+
for (const row of rows) {
|
|
25837
|
+
const key = `${row.date}\0${row.source}`;
|
|
25838
|
+
let group = groups.get(key);
|
|
25839
|
+
if (!group) {
|
|
25840
|
+
group = { date: row.date, source: row.source, byDimension: /* @__PURE__ */ new Map(), mediumSessions: /* @__PURE__ */ new Map() };
|
|
25841
|
+
groups.set(key, group);
|
|
25842
|
+
}
|
|
25843
|
+
let dim = group.byDimension.get(row.sourceDimension);
|
|
25844
|
+
if (!dim) {
|
|
25845
|
+
dim = { paidSessions: 0, organicSessions: 0 };
|
|
25846
|
+
group.byDimension.set(row.sourceDimension, dim);
|
|
25847
|
+
}
|
|
25848
|
+
const sessions = row.sessions ?? 0;
|
|
25849
|
+
if (normalizeAiTrafficClass(row.trafficClass) === AiReferralTrafficClasses.paid) {
|
|
25850
|
+
dim.paidSessions += sessions;
|
|
25851
|
+
} else {
|
|
25852
|
+
dim.organicSessions += sessions;
|
|
25853
|
+
}
|
|
25854
|
+
let mediums = group.mediumSessions.get(row.sourceDimension);
|
|
25855
|
+
if (!mediums) {
|
|
25856
|
+
mediums = /* @__PURE__ */ new Map();
|
|
25857
|
+
group.mediumSessions.set(row.sourceDimension, mediums);
|
|
25858
|
+
}
|
|
25859
|
+
mediums.set(row.medium, (mediums.get(row.medium) ?? 0) + sessions);
|
|
25860
|
+
}
|
|
25861
|
+
const winners = [];
|
|
25862
|
+
for (const group of groups.values()) {
|
|
25863
|
+
const winningDimension = pickWinningAttributionDimension(
|
|
25864
|
+
new Map([...group.byDimension].map(([d, c]) => [d, c.paidSessions + c.organicSessions]))
|
|
25865
|
+
);
|
|
25866
|
+
if (winningDimension === void 0) continue;
|
|
25867
|
+
const best = group.byDimension.get(winningDimension);
|
|
25868
|
+
let medium = "";
|
|
25869
|
+
let mediumBest = -1;
|
|
25870
|
+
for (const [candidate, sessions] of group.mediumSessions.get(winningDimension) ?? []) {
|
|
25871
|
+
if (sessions > mediumBest) {
|
|
25872
|
+
mediumBest = sessions;
|
|
25873
|
+
medium = candidate;
|
|
25874
|
+
}
|
|
25875
|
+
}
|
|
25876
|
+
winners.push({
|
|
25877
|
+
date: group.date,
|
|
25878
|
+
source: group.source,
|
|
25879
|
+
medium,
|
|
25880
|
+
paidSessions: best.paidSessions,
|
|
25881
|
+
organicSessions: best.organicSessions
|
|
25882
|
+
});
|
|
25883
|
+
}
|
|
25884
|
+
return winners;
|
|
25885
|
+
}
|
|
25886
|
+
function summarizeAiReferralCounts(rows) {
|
|
25887
|
+
const paidDeduped = emptyAiCounts();
|
|
25888
|
+
const organicDeduped = emptyAiCounts();
|
|
25889
|
+
const paidBySession = emptyAiCounts();
|
|
25890
|
+
const organicBySession = emptyAiCounts();
|
|
25891
|
+
const bySessionChannelGroup = /* @__PURE__ */ new Map();
|
|
25892
|
+
for (const winner of resolveWinningDimensions(rows)) {
|
|
25893
|
+
paidDeduped.sessions += winner.paidSessions;
|
|
25894
|
+
organicDeduped.sessions += winner.organicSessions;
|
|
25895
|
+
}
|
|
25896
|
+
for (const row of rows) {
|
|
25897
|
+
if (row.sourceDimension !== "session") continue;
|
|
25898
|
+
const sessions = row.sessions ?? 0;
|
|
25899
|
+
bySessionChannelGroup.set(
|
|
25900
|
+
row.channelGroup,
|
|
25901
|
+
(bySessionChannelGroup.get(row.channelGroup) ?? 0) + sessions
|
|
25902
|
+
);
|
|
25903
|
+
const bucket = normalizeAiTrafficClass(row.trafficClass) === AiReferralTrafficClasses.paid ? paidBySession : organicBySession;
|
|
25904
|
+
bucket.sessions += sessions;
|
|
25905
|
+
}
|
|
25906
|
+
return {
|
|
25907
|
+
paidDeduped,
|
|
25908
|
+
organicDeduped,
|
|
25909
|
+
paidBySession,
|
|
25910
|
+
organicBySession,
|
|
25911
|
+
bySessionChannelGroup,
|
|
25912
|
+
deduped: { sessions: paidDeduped.sessions + organicDeduped.sessions },
|
|
25913
|
+
bySession: { sessions: paidBySession.sessions + organicBySession.sessions }
|
|
25914
|
+
};
|
|
25915
|
+
}
|
|
25916
|
+
function buildAiReferralDailySeries(rows) {
|
|
25917
|
+
const byDate = /* @__PURE__ */ new Map();
|
|
25918
|
+
const sourceTotals = /* @__PURE__ */ new Map();
|
|
25919
|
+
let totalSessions = 0;
|
|
25920
|
+
let totalPaidSessions = 0;
|
|
25921
|
+
let totalOrganicSessions = 0;
|
|
25922
|
+
for (const winner of resolveWinningDimensions(rows)) {
|
|
25923
|
+
const sessions = winner.paidSessions + winner.organicSessions;
|
|
25924
|
+
let bySource = byDate.get(winner.date);
|
|
25925
|
+
if (!bySource) {
|
|
25926
|
+
bySource = /* @__PURE__ */ new Map();
|
|
25927
|
+
byDate.set(winner.date, bySource);
|
|
25928
|
+
}
|
|
25929
|
+
let bucket = bySource.get(winner.source);
|
|
25930
|
+
if (!bucket) {
|
|
25931
|
+
bucket = { source: winner.source, sessions: 0, paidSessions: 0, organicSessions: 0 };
|
|
25932
|
+
bySource.set(winner.source, bucket);
|
|
25933
|
+
}
|
|
25934
|
+
bucket.sessions += sessions;
|
|
25935
|
+
bucket.paidSessions += winner.paidSessions;
|
|
25936
|
+
bucket.organicSessions += winner.organicSessions;
|
|
25937
|
+
sourceTotals.set(winner.source, (sourceTotals.get(winner.source) ?? 0) + sessions);
|
|
25938
|
+
totalSessions += sessions;
|
|
25939
|
+
totalPaidSessions += winner.paidSessions;
|
|
25940
|
+
totalOrganicSessions += winner.organicSessions;
|
|
25941
|
+
}
|
|
25942
|
+
const days = [...byDate.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([date, bySource]) => {
|
|
25943
|
+
const sources2 = [...bySource.values()].sort((a, b) => b.sessions - a.sessions || a.source.localeCompare(b.source));
|
|
25944
|
+
return {
|
|
25945
|
+
date,
|
|
25946
|
+
sessions: sources2.reduce((sum, s) => sum + s.sessions, 0),
|
|
25947
|
+
paidSessions: sources2.reduce((sum, s) => sum + s.paidSessions, 0),
|
|
25948
|
+
organicSessions: sources2.reduce((sum, s) => sum + s.organicSessions, 0),
|
|
25949
|
+
bySource: sources2
|
|
25950
|
+
};
|
|
25951
|
+
});
|
|
25952
|
+
const sources = [...sourceTotals.entries()].sort(([aSource, aSessions], [bSource, bSessions]) => bSessions - aSessions || aSource.localeCompare(bSource)).map(([source]) => source);
|
|
25953
|
+
return { days, sources, totalSessions, totalPaidSessions, totalOrganicSessions };
|
|
25954
|
+
}
|
|
25955
|
+
|
|
25767
25956
|
// ../api-routes/src/report.ts
|
|
25768
25957
|
var TOP_QUERIES_LIMIT = 20;
|
|
25769
25958
|
var TOP_LANDING_PAGES_LIMIT = 20;
|
|
@@ -25829,8 +26018,8 @@ function buildGscSection(db, projectId, projectBrandNames, canonicalDomain, trac
|
|
|
25829
26018
|
const rows = db.select().from(gscSearchData).where(
|
|
25830
26019
|
and24(
|
|
25831
26020
|
eq29(gscSearchData.projectId, projectId),
|
|
25832
|
-
|
|
25833
|
-
|
|
26021
|
+
gte6(gscSearchData.date, startDate),
|
|
26022
|
+
lte4(gscSearchData.date, maxDate)
|
|
25834
26023
|
)
|
|
25835
26024
|
).all();
|
|
25836
26025
|
const dailyTotals = readGscDailyTotals(db, projectId, startDate, maxDate);
|
|
@@ -25942,8 +26131,8 @@ function buildGaSection(db, projectId, windowDays2) {
|
|
|
25942
26131
|
const snapshotRows = snapshotStartDate ? db.select().from(gaTrafficSnapshots).where(
|
|
25943
26132
|
and24(
|
|
25944
26133
|
eq29(gaTrafficSnapshots.projectId, projectId),
|
|
25945
|
-
|
|
25946
|
-
|
|
26134
|
+
gte6(gaTrafficSnapshots.date, snapshotStartDate),
|
|
26135
|
+
lte4(gaTrafficSnapshots.date, snapshotMaxInWindow)
|
|
25947
26136
|
)
|
|
25948
26137
|
).all() : db.select().from(gaTrafficSnapshots).where(eq29(gaTrafficSnapshots.projectId, projectId)).all();
|
|
25949
26138
|
const totalSessions = windowSummary?.totalSessions ?? matchingFallbackSummary?.totalSessions ?? snapshotRows.reduce((s, r) => s + r.sessions, 0);
|
|
@@ -25971,8 +26160,8 @@ function buildGaSection(db, projectId, windowDays2) {
|
|
|
25971
26160
|
eq29(gaAiReferrals.sourceDimension, "session")
|
|
25972
26161
|
];
|
|
25973
26162
|
if (snapshotStartDate && snapshotMaxInWindow) {
|
|
25974
|
-
aiConditions.push(
|
|
25975
|
-
aiConditions.push(
|
|
26163
|
+
aiConditions.push(gte6(gaAiReferrals.date, snapshotStartDate));
|
|
26164
|
+
aiConditions.push(lte4(gaAiReferrals.date, snapshotMaxInWindow));
|
|
25976
26165
|
}
|
|
25977
26166
|
const aiSessionRows = db.select({
|
|
25978
26167
|
trafficClass: gaAiReferrals.trafficClass,
|
|
@@ -26077,7 +26266,7 @@ function buildAiReferrals(db, projectId, windowDays2) {
|
|
|
26077
26266
|
if (rows.length === 0) return null;
|
|
26078
26267
|
const dimSessionsByTuple = /* @__PURE__ */ new Map();
|
|
26079
26268
|
for (const r of rows) {
|
|
26080
|
-
const tupleKey = `${r.date}::${r.source}
|
|
26269
|
+
const tupleKey = `${r.date}::${r.source}`;
|
|
26081
26270
|
let dimMap = dimSessionsByTuple.get(tupleKey);
|
|
26082
26271
|
if (!dimMap) {
|
|
26083
26272
|
dimMap = /* @__PURE__ */ new Map();
|
|
@@ -26087,18 +26276,11 @@ function buildAiReferrals(db, projectId, windowDays2) {
|
|
|
26087
26276
|
}
|
|
26088
26277
|
const winningDimension = /* @__PURE__ */ new Map();
|
|
26089
26278
|
for (const [tupleKey, dimMap] of dimSessionsByTuple) {
|
|
26090
|
-
|
|
26091
|
-
let bestSessions = -1;
|
|
26092
|
-
for (const [dim, sessions] of dimMap) {
|
|
26093
|
-
if (sessions > bestSessions) {
|
|
26094
|
-
bestSessions = sessions;
|
|
26095
|
-
bestDim = dim;
|
|
26096
|
-
}
|
|
26097
|
-
}
|
|
26279
|
+
const bestDim = pickWinningAttributionDimension(dimMap);
|
|
26098
26280
|
if (bestDim) winningDimension.set(tupleKey, bestDim);
|
|
26099
26281
|
}
|
|
26100
26282
|
const dedupedRows = rows.filter(
|
|
26101
|
-
(r) => winningDimension.get(`${r.date}::${r.source}
|
|
26283
|
+
(r) => winningDimension.get(`${r.date}::${r.source}`) === r.sourceDimension
|
|
26102
26284
|
);
|
|
26103
26285
|
let total = 0;
|
|
26104
26286
|
let paidSessions = 0;
|
|
@@ -26168,8 +26350,8 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26168
26350
|
and24(
|
|
26169
26351
|
eq29(crawlerEventsHourly.projectId, projectId),
|
|
26170
26352
|
eq29(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
|
|
26171
|
-
|
|
26172
|
-
exclusiveEnd ? lt6(crawlerEventsHourly.tsHour, windowEndIso) :
|
|
26353
|
+
gte6(crawlerEventsHourly.tsHour, windowStartIso),
|
|
26354
|
+
exclusiveEnd ? lt6(crawlerEventsHourly.tsHour, windowEndIso) : lte4(crawlerEventsHourly.tsHour, windowEndIso)
|
|
26173
26355
|
)
|
|
26174
26356
|
).get()?.total ?? 0
|
|
26175
26357
|
);
|
|
@@ -26178,8 +26360,8 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26178
26360
|
and24(
|
|
26179
26361
|
eq29(crawlerEventsHourly.projectId, projectId),
|
|
26180
26362
|
ne3(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
|
|
26181
|
-
|
|
26182
|
-
exclusiveEnd ? lt6(crawlerEventsHourly.tsHour, windowEndIso) :
|
|
26363
|
+
gte6(crawlerEventsHourly.tsHour, windowStartIso),
|
|
26364
|
+
exclusiveEnd ? lt6(crawlerEventsHourly.tsHour, windowEndIso) : lte4(crawlerEventsHourly.tsHour, windowEndIso)
|
|
26183
26365
|
)
|
|
26184
26366
|
).get()?.total ?? 0
|
|
26185
26367
|
);
|
|
@@ -26192,8 +26374,8 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26192
26374
|
and24(
|
|
26193
26375
|
eq29(aiReferralEventsHourly.projectId, projectId),
|
|
26194
26376
|
countableReferralCondition(),
|
|
26195
|
-
|
|
26196
|
-
exclusiveEnd ? lt6(aiReferralEventsHourly.tsHour, windowEndIso) :
|
|
26377
|
+
gte6(aiReferralEventsHourly.tsHour, windowStartIso),
|
|
26378
|
+
exclusiveEnd ? lt6(aiReferralEventsHourly.tsHour, windowEndIso) : lte4(aiReferralEventsHourly.tsHour, windowEndIso)
|
|
26197
26379
|
)
|
|
26198
26380
|
).get();
|
|
26199
26381
|
return aiReferralClassCounts(Number(row?.total ?? 0), Number(row?.paid ?? 0), Number(row?.organic ?? 0));
|
|
@@ -26202,8 +26384,8 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26202
26384
|
db.select({ total: sql10`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
|
|
26203
26385
|
and24(
|
|
26204
26386
|
eq29(aiUserFetchEventsHourly.projectId, projectId),
|
|
26205
|
-
|
|
26206
|
-
exclusiveEnd ? lt6(aiUserFetchEventsHourly.tsHour, windowEndIso) :
|
|
26387
|
+
gte6(aiUserFetchEventsHourly.tsHour, windowStartIso),
|
|
26388
|
+
exclusiveEnd ? lt6(aiUserFetchEventsHourly.tsHour, windowEndIso) : lte4(aiUserFetchEventsHourly.tsHour, windowEndIso)
|
|
26207
26389
|
)
|
|
26208
26390
|
).get()?.total ?? 0
|
|
26209
26391
|
);
|
|
@@ -26219,8 +26401,8 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26219
26401
|
and24(
|
|
26220
26402
|
eq29(aiReferralEventsHourly.projectId, projectId),
|
|
26221
26403
|
nonSubresourceReferralPathCondition(),
|
|
26222
|
-
|
|
26223
|
-
|
|
26404
|
+
gte6(aiReferralEventsHourly.tsHour, headlineStart),
|
|
26405
|
+
lte4(aiReferralEventsHourly.tsHour, headlineEnd)
|
|
26224
26406
|
)
|
|
26225
26407
|
).get()?.total ?? 0
|
|
26226
26408
|
);
|
|
@@ -26233,8 +26415,8 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26233
26415
|
}).from(crawlerEventsHourly).where(
|
|
26234
26416
|
and24(
|
|
26235
26417
|
eq29(crawlerEventsHourly.projectId, projectId),
|
|
26236
|
-
|
|
26237
|
-
|
|
26418
|
+
gte6(crawlerEventsHourly.tsHour, headlineStart),
|
|
26419
|
+
lte4(crawlerEventsHourly.tsHour, headlineEnd)
|
|
26238
26420
|
)
|
|
26239
26421
|
).groupBy(crawlerEventsHourly.operator, crawlerEventsHourly.verificationStatus).all();
|
|
26240
26422
|
const crawlerByOperatorPriorRows = db.select({
|
|
@@ -26244,7 +26426,7 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26244
26426
|
and24(
|
|
26245
26427
|
eq29(crawlerEventsHourly.projectId, projectId),
|
|
26246
26428
|
eq29(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
|
|
26247
|
-
|
|
26429
|
+
gte6(crawlerEventsHourly.tsHour, priorStart),
|
|
26248
26430
|
lt6(crawlerEventsHourly.tsHour, headlineStart)
|
|
26249
26431
|
)
|
|
26250
26432
|
).groupBy(crawlerEventsHourly.operator).all();
|
|
@@ -26255,8 +26437,8 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26255
26437
|
and24(
|
|
26256
26438
|
eq29(aiReferralEventsHourly.projectId, projectId),
|
|
26257
26439
|
countableReferralCondition(),
|
|
26258
|
-
|
|
26259
|
-
|
|
26440
|
+
gte6(aiReferralEventsHourly.tsHour, headlineStart),
|
|
26441
|
+
lte4(aiReferralEventsHourly.tsHour, headlineEnd)
|
|
26260
26442
|
)
|
|
26261
26443
|
).groupBy(aiReferralEventsHourly.operator).all();
|
|
26262
26444
|
const userFetchByOperatorRows = db.select({
|
|
@@ -26265,8 +26447,8 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26265
26447
|
}).from(aiUserFetchEventsHourly).where(
|
|
26266
26448
|
and24(
|
|
26267
26449
|
eq29(aiUserFetchEventsHourly.projectId, projectId),
|
|
26268
|
-
|
|
26269
|
-
|
|
26450
|
+
gte6(aiUserFetchEventsHourly.tsHour, headlineStart),
|
|
26451
|
+
lte4(aiUserFetchEventsHourly.tsHour, headlineEnd)
|
|
26270
26452
|
)
|
|
26271
26453
|
).groupBy(aiUserFetchEventsHourly.operator).all();
|
|
26272
26454
|
const operatorAgg = /* @__PURE__ */ new Map();
|
|
@@ -26310,8 +26492,8 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26310
26492
|
and24(
|
|
26311
26493
|
eq29(crawlerEventsHourly.projectId, projectId),
|
|
26312
26494
|
eq29(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
|
|
26313
|
-
|
|
26314
|
-
|
|
26495
|
+
gte6(crawlerEventsHourly.tsHour, headlineStart),
|
|
26496
|
+
lte4(crawlerEventsHourly.tsHour, headlineEnd)
|
|
26315
26497
|
)
|
|
26316
26498
|
).groupBy(crawlerEventsHourly.pathNormalized).orderBy(desc12(sql10`SUM(${crawlerEventsHourly.hits})`)).limit(SERVER_ACTIVITY_TOP_PATHS_LIMIT).all();
|
|
26317
26499
|
const topCrawledPaths = topPathsRows.map((r) => ({
|
|
@@ -26327,8 +26509,8 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26327
26509
|
and24(
|
|
26328
26510
|
eq29(aiReferralEventsHourly.projectId, projectId),
|
|
26329
26511
|
countableReferralCondition(),
|
|
26330
|
-
|
|
26331
|
-
|
|
26512
|
+
gte6(aiReferralEventsHourly.tsHour, headlineStart),
|
|
26513
|
+
lte4(aiReferralEventsHourly.tsHour, headlineEnd)
|
|
26332
26514
|
)
|
|
26333
26515
|
).groupBy(aiReferralEventsHourly.product).orderBy(desc12(sql10`SUM(${aiReferralEventsHourly.sessionsOrHits})`)).all();
|
|
26334
26516
|
const referralProducts = referralProductsRows.map((r) => ({
|
|
@@ -26344,8 +26526,8 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26344
26526
|
and24(
|
|
26345
26527
|
eq29(aiReferralEventsHourly.projectId, projectId),
|
|
26346
26528
|
countableReferralCondition(),
|
|
26347
|
-
|
|
26348
|
-
|
|
26529
|
+
gte6(aiReferralEventsHourly.tsHour, headlineStart),
|
|
26530
|
+
lte4(aiReferralEventsHourly.tsHour, headlineEnd)
|
|
26349
26531
|
)
|
|
26350
26532
|
).groupBy(aiReferralEventsHourly.landingPathNormalized).orderBy(desc12(sql10`SUM(${aiReferralEventsHourly.sessionsOrHits})`)).limit(SERVER_ACTIVITY_TOP_PATHS_LIMIT).all();
|
|
26351
26533
|
const topReferralLandingPaths = topReferralRows.map((r) => ({
|
|
@@ -26360,8 +26542,8 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26360
26542
|
and24(
|
|
26361
26543
|
eq29(crawlerEventsHourly.projectId, projectId),
|
|
26362
26544
|
eq29(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
|
|
26363
|
-
|
|
26364
|
-
|
|
26545
|
+
gte6(crawlerEventsHourly.tsHour, trendStart),
|
|
26546
|
+
lte4(crawlerEventsHourly.tsHour, headlineEnd)
|
|
26365
26547
|
)
|
|
26366
26548
|
).groupBy(sql10`SUBSTR(${crawlerEventsHourly.tsHour}, 1, 10)`).all();
|
|
26367
26549
|
const referralTrendRows = db.select({
|
|
@@ -26371,8 +26553,8 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26371
26553
|
and24(
|
|
26372
26554
|
eq29(aiReferralEventsHourly.projectId, projectId),
|
|
26373
26555
|
countableReferralCondition(),
|
|
26374
|
-
|
|
26375
|
-
|
|
26556
|
+
gte6(aiReferralEventsHourly.tsHour, trendStart),
|
|
26557
|
+
lte4(aiReferralEventsHourly.tsHour, headlineEnd)
|
|
26376
26558
|
)
|
|
26377
26559
|
).groupBy(sql10`SUBSTR(${aiReferralEventsHourly.tsHour}, 1, 10)`).all();
|
|
26378
26560
|
const userFetchTrendRows = db.select({
|
|
@@ -26381,8 +26563,8 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26381
26563
|
}).from(aiUserFetchEventsHourly).where(
|
|
26382
26564
|
and24(
|
|
26383
26565
|
eq29(aiUserFetchEventsHourly.projectId, projectId),
|
|
26384
|
-
|
|
26385
|
-
|
|
26566
|
+
gte6(aiUserFetchEventsHourly.tsHour, trendStart),
|
|
26567
|
+
lte4(aiUserFetchEventsHourly.tsHour, headlineEnd)
|
|
26386
26568
|
)
|
|
26387
26569
|
).groupBy(sql10`SUBSTR(${aiUserFetchEventsHourly.tsHour}, 1, 10)`).all();
|
|
26388
26570
|
const emptyTrendEntry = () => ({ verifiedCrawlerHits: 0, userFetchHits: 0, referralArrivals: 0 });
|
|
@@ -27145,7 +27327,7 @@ function buildProjectReport(db, projectName, periodDays) {
|
|
|
27145
27327
|
const indexingHealthSection = buildIndexingHealth(db, project.id);
|
|
27146
27328
|
const citationsTrend = buildCitationsTrend(db, project.id, queryLookup, latestRunLocation);
|
|
27147
27329
|
const insightList = buildInsightList(db, project.id, latestRunLocation);
|
|
27148
|
-
const orchestratorInput = loadOrchestratorInput(db, project, latestRunLocation);
|
|
27330
|
+
const orchestratorInput = loadOrchestratorInput(db, project, latestRunLocation, periodDays);
|
|
27149
27331
|
const dismissedTargetRefs = loadDismissedTargetRefs(db, project.id);
|
|
27150
27332
|
const rawContentOpportunities = buildContentTargetRows(orchestratorInput);
|
|
27151
27333
|
const contentOpportunities = dismissedTargetRefs.size > 0 ? rawContentOpportunities.filter((r) => !dismissedTargetRefs.has(r.targetRef)) : rawContentOpportunities;
|
|
@@ -27332,10 +27514,10 @@ async function reportRoutes(app) {
|
|
|
27332
27514
|
}
|
|
27333
27515
|
|
|
27334
27516
|
// ../api-routes/src/organic-evidence.ts
|
|
27335
|
-
import { and as and26, desc as desc13, eq as eq31, gte as
|
|
27517
|
+
import { and as and26, desc as desc13, eq as eq31, gte as gte8, lte as lte6, or as or6, sql as sql12 } from "drizzle-orm";
|
|
27336
27518
|
|
|
27337
27519
|
// ../api-routes/src/ga-measurement-analysis.ts
|
|
27338
|
-
import { and as and25, eq as eq30, gte as
|
|
27520
|
+
import { and as and25, eq as eq30, gte as gte7, lte as lte5, or as or5, sql as sql11 } from "drizzle-orm";
|
|
27339
27521
|
var UNKNOWN_LANDING_PAGE = "(not set)";
|
|
27340
27522
|
function addDays(date, offset) {
|
|
27341
27523
|
const value = /* @__PURE__ */ new Date(`${date}T00:00:00.000Z`);
|
|
@@ -27531,15 +27713,15 @@ function buildGaMeasurementAnalysis(db, projectName, options = {}) {
|
|
|
27531
27713
|
const gaAnchor = [acquisitionAnchor, leadAnchor].filter((date) => date !== null).sort().at(-1) ?? null;
|
|
27532
27714
|
const gaPeriods = gaAnchor ? buildPeriods(gaAnchor, days) : [];
|
|
27533
27715
|
const gaStartDate = gaPeriods[0]?.startDate;
|
|
27534
|
-
const acquisitionRows = gaStartDate ? db.select().from(gaAcquisitionDaily).where(and25(eq30(gaAcquisitionDaily.projectId, project.id),
|
|
27535
|
-
const leadRows = gaStartDate ? db.select().from(gaLeadEventsDaily).where(and25(eq30(gaLeadEventsDaily.projectId, project.id),
|
|
27716
|
+
const acquisitionRows = gaStartDate ? db.select().from(gaAcquisitionDaily).where(and25(eq30(gaAcquisitionDaily.projectId, project.id), gte7(gaAcquisitionDaily.date, gaStartDate), lte5(gaAcquisitionDaily.date, gaAnchor))).all() : [];
|
|
27717
|
+
const leadRows = gaStartDate ? db.select().from(gaLeadEventsDaily).where(and25(eq30(gaLeadEventsDaily.projectId, project.id), gte7(gaLeadEventsDaily.date, gaStartDate), lte5(gaLeadEventsDaily.date, gaAnchor))).all() : [];
|
|
27536
27718
|
const engagementAnchor = db.select({ date: sql11`max(${gaDailyTotals.date})` }).from(gaDailyTotals).where(eq30(gaDailyTotals.projectId, project.id)).get()?.date ?? null;
|
|
27537
27719
|
const engagementPeriodWindow = engagementAnchor ? buildPeriods(engagementAnchor, days) : [];
|
|
27538
27720
|
const engagementStartDate = engagementPeriodWindow[0]?.startDate;
|
|
27539
27721
|
const engagementRows = engagementStartDate ? db.select().from(gaDailyTotals).where(and25(
|
|
27540
27722
|
eq30(gaDailyTotals.projectId, project.id),
|
|
27541
|
-
|
|
27542
|
-
|
|
27723
|
+
gte7(gaDailyTotals.date, engagementStartDate),
|
|
27724
|
+
lte5(gaDailyTotals.date, engagementAnchor)
|
|
27543
27725
|
)).all() : [];
|
|
27544
27726
|
const engagementAvailableFrom = db.select({
|
|
27545
27727
|
date: sql11`min(${gaDailyTotals.date})`
|
|
@@ -27553,9 +27735,9 @@ function buildGaMeasurementAnalysis(db, projectName, options = {}) {
|
|
|
27553
27735
|
const gscAnchor = db.select({ date: sql11`max(${gscDailyTotals.date})` }).from(gscDailyTotals).where(eq30(gscDailyTotals.projectId, project.id)).get()?.date ?? null;
|
|
27554
27736
|
const gscPeriods = gscAnchor ? buildPeriods(gscAnchor, days) : [];
|
|
27555
27737
|
const gscStartDate = gscPeriods[0]?.startDate;
|
|
27556
|
-
const propertyRows = gscStartDate ? db.select().from(gscDailyTotals).where(and25(eq30(gscDailyTotals.projectId, project.id),
|
|
27557
|
-
const queryRows = gscStartDate ? db.select().from(gscQueryDailyTotals).where(and25(eq30(gscQueryDailyTotals.projectId, project.id),
|
|
27558
|
-
const rawPageRows = gscStartDate ? db.select().from(gscSearchData).where(and25(eq30(gscSearchData.projectId, project.id),
|
|
27738
|
+
const propertyRows = gscStartDate ? db.select().from(gscDailyTotals).where(and25(eq30(gscDailyTotals.projectId, project.id), gte7(gscDailyTotals.date, gscStartDate), lte5(gscDailyTotals.date, gscAnchor))).all() : [];
|
|
27739
|
+
const queryRows = gscStartDate ? db.select().from(gscQueryDailyTotals).where(and25(eq30(gscQueryDailyTotals.projectId, project.id), gte7(gscQueryDailyTotals.date, gscStartDate), lte5(gscQueryDailyTotals.date, gscAnchor))).all() : [];
|
|
27740
|
+
const rawPageRows = gscStartDate ? db.select().from(gscSearchData).where(and25(eq30(gscSearchData.projectId, project.id), gte7(gscSearchData.date, gscStartDate), lte5(gscSearchData.date, gscAnchor))).all() : [];
|
|
27559
27741
|
const state = db.select().from(gaMeasurementSyncStates).where(eq30(gaMeasurementSyncStates.projectId, project.id)).get();
|
|
27560
27742
|
const acquisition = acquisitionRows.filter((row) => {
|
|
27561
27743
|
const landingPage = normalizeLandingPage(row.landingPageNormalized ?? row.landingPage);
|
|
@@ -27907,18 +28089,18 @@ function buildOrganicEvidence(db, projectName, periodDays) {
|
|
|
27907
28089
|
const isInWindow = (date) => inRange(date, startDate, endDate);
|
|
27908
28090
|
const gscRows = gscStartDate && gscEndDate ? db.select().from(gscDailyTotals).where(and26(
|
|
27909
28091
|
eq31(gscDailyTotals.projectId, project.id),
|
|
27910
|
-
|
|
27911
|
-
|
|
28092
|
+
gte8(gscDailyTotals.date, gscStartDate),
|
|
28093
|
+
lte6(gscDailyTotals.date, gscEndDate)
|
|
27912
28094
|
)).all() : [];
|
|
27913
28095
|
const gaRows = gaStartDate && gaEndDate ? db.select().from(gaTrafficSnapshots).where(and26(
|
|
27914
28096
|
eq31(gaTrafficSnapshots.projectId, project.id),
|
|
27915
|
-
|
|
27916
|
-
|
|
28097
|
+
gte8(gaTrafficSnapshots.date, gaStartDate),
|
|
28098
|
+
lte6(gaTrafficSnapshots.date, gaEndDate)
|
|
27917
28099
|
)).all() : [];
|
|
27918
28100
|
const nativeAcquisitionRows = nativeAcquisitionActive && nativeStartDate && nativeEndDate ? db.select().from(gaAcquisitionDaily).where(and26(
|
|
27919
28101
|
eq31(gaAcquisitionDaily.projectId, project.id),
|
|
27920
|
-
|
|
27921
|
-
|
|
28102
|
+
gte8(gaAcquisitionDaily.date, nativeStartDate),
|
|
28103
|
+
lte6(gaAcquisitionDaily.date, nativeEndDate)
|
|
27922
28104
|
)).all().filter((row) => matchesMarketingHost(row.hostName, marketingHosts)) : [];
|
|
27923
28105
|
const nativeOrganicRows = nativeAcquisitionRows.filter((row) => row.channelGroup === "Organic Search");
|
|
27924
28106
|
const nativeWindowOrganicRows = nativeOrganicRows;
|
|
@@ -27956,8 +28138,8 @@ function buildOrganicEvidence(db, projectName, periodDays) {
|
|
|
27956
28138
|
);
|
|
27957
28139
|
const namedRows = db.select().from(gscQueryDailyTotals).where(and26(
|
|
27958
28140
|
eq31(gscQueryDailyTotals.projectId, project.id),
|
|
27959
|
-
|
|
27960
|
-
|
|
28141
|
+
gte8(gscQueryDailyTotals.date, startDate),
|
|
28142
|
+
lte6(gscQueryDailyTotals.date, endDate)
|
|
27961
28143
|
)).all();
|
|
27962
28144
|
for (const row of namedRows) {
|
|
27963
28145
|
const isBrand = categorizeQueryByIntent(row.query, brandTokens) === "brand";
|
|
@@ -27983,7 +28165,7 @@ function buildOrganicEvidence(db, projectName, periodDays) {
|
|
|
27983
28165
|
totals: sumSearchRows(gscRows.filter((row) => inRange(row.date, cohort.startDate, cohort.endDate)))
|
|
27984
28166
|
}))
|
|
27985
28167
|
} : null;
|
|
27986
|
-
const pageSearchRows = db.select().from(gscSearchData).where(and26(eq31(gscSearchData.projectId, project.id),
|
|
28168
|
+
const pageSearchRows = db.select().from(gscSearchData).where(and26(eq31(gscSearchData.projectId, project.id), gte8(gscSearchData.date, startDate), lte6(gscSearchData.date, endDate))).all().filter((row) => pageMatchesMarketingHost(row.page, marketingHosts));
|
|
27987
28169
|
const gaWindow = gaStartDate && gaEndDate ? gaRows.filter((row) => inRange(row.date, gaStartDate, gaEndDate)) : [];
|
|
27988
28170
|
const legacyGaCohorts = gaCohorts.map((cohort) => ({
|
|
27989
28171
|
...cohort,
|
|
@@ -28010,7 +28192,7 @@ function buildOrganicEvidence(db, projectName, periodDays) {
|
|
|
28010
28192
|
}))
|
|
28011
28193
|
};
|
|
28012
28194
|
}
|
|
28013
|
-
const allGaAiRows = db.select().from(gaAiReferrals).where(and26(eq31(gaAiReferrals.projectId, project.id),
|
|
28195
|
+
const allGaAiRows = db.select().from(gaAiReferrals).where(and26(eq31(gaAiReferrals.projectId, project.id), gte8(gaAiReferrals.date, gaStartDate ?? startDate), lte6(gaAiReferrals.date, gaEndDate ?? endDate))).all().filter((row) => row.sourceDimension === "session");
|
|
28014
28196
|
const aiRows = gaStartDate && gaEndDate ? allGaAiRows.filter((row) => inRange(row.date, gaStartDate, gaEndDate)) : [];
|
|
28015
28197
|
const gaAiReferralSummary = allGaAiRows.length ? {
|
|
28016
28198
|
paidSessions: aiRows.filter((row) => row.trafficClass === AiReferralTrafficClasses.paid).reduce((count2, row) => count2 + row.sessions, 0),
|
|
@@ -28019,9 +28201,9 @@ function buildOrganicEvidence(db, projectName, periodDays) {
|
|
|
28019
28201
|
const serverSources = db.select().from(trafficSources).where(eq31(trafficSources.projectId, project.id)).all();
|
|
28020
28202
|
const serverStart = `${startDate}T00:00:00`;
|
|
28021
28203
|
const serverEnd = `${endDate}T23:59:59.999Z`;
|
|
28022
|
-
const allCrawlers = db.select().from(crawlerEventsHourly).where(and26(eq31(crawlerEventsHourly.projectId, project.id),
|
|
28023
|
-
const allFetches = db.select().from(aiUserFetchEventsHourly).where(and26(eq31(aiUserFetchEventsHourly.projectId, project.id),
|
|
28024
|
-
const allReferrals = db.select().from(aiReferralEventsHourly).where(and26(eq31(aiReferralEventsHourly.projectId, project.id), countableReferralCondition(),
|
|
28204
|
+
const allCrawlers = db.select().from(crawlerEventsHourly).where(and26(eq31(crawlerEventsHourly.projectId, project.id), gte8(crawlerEventsHourly.tsHour, serverStart), lte6(crawlerEventsHourly.tsHour, serverEnd))).all();
|
|
28205
|
+
const allFetches = db.select().from(aiUserFetchEventsHourly).where(and26(eq31(aiUserFetchEventsHourly.projectId, project.id), gte8(aiUserFetchEventsHourly.tsHour, serverStart), lte6(aiUserFetchEventsHourly.tsHour, serverEnd))).all();
|
|
28206
|
+
const allReferrals = db.select().from(aiReferralEventsHourly).where(and26(eq31(aiReferralEventsHourly.projectId, project.id), countableReferralCondition(), gte8(aiReferralEventsHourly.tsHour, serverStart), lte6(aiReferralEventsHourly.tsHour, serverEnd))).all();
|
|
28025
28207
|
const [serverCoverageRow] = db.all(sql12`
|
|
28026
28208
|
select
|
|
28027
28209
|
min(day) as startDate,
|
|
@@ -29015,7 +29197,7 @@ async function visibilityStatsRoutes(app) {
|
|
|
29015
29197
|
}
|
|
29016
29198
|
|
|
29017
29199
|
// ../api-routes/src/results-export.ts
|
|
29018
|
-
import { and as and29, asc as asc5, eq as eq34, gte as
|
|
29200
|
+
import { and as and29, asc as asc5, eq as eq34, gte as gte9, lte as lte7 } from "drizzle-orm";
|
|
29019
29201
|
var CSV_COLUMNS = [
|
|
29020
29202
|
"export_schema_version",
|
|
29021
29203
|
"project_id",
|
|
@@ -29155,8 +29337,8 @@ async function resultsExportRoutes(app) {
|
|
|
29155
29337
|
eq34(runs.projectId, project.id),
|
|
29156
29338
|
eq34(runs.kind, RunKinds["answer-visibility"]),
|
|
29157
29339
|
...includeProbes ? [] : [notProbeRun()],
|
|
29158
|
-
...sinceIso ? [
|
|
29159
|
-
...untilIso ? [
|
|
29340
|
+
...sinceIso ? [gte9(runs.createdAt, sinceIso)] : [],
|
|
29341
|
+
...untilIso ? [lte7(runs.createdAt, untilIso)] : []
|
|
29160
29342
|
];
|
|
29161
29343
|
const rows = app.db.select({
|
|
29162
29344
|
runId: runs.id,
|
|
@@ -43267,7 +43449,7 @@ async function googleMarketingRoutes(app, opts) {
|
|
|
43267
43449
|
|
|
43268
43450
|
// ../api-routes/src/ads.ts
|
|
43269
43451
|
import crypto35 from "crypto";
|
|
43270
|
-
import { eq as eq43, and as and35, asc as asc8, desc as desc19, gt as gt2, gte as
|
|
43452
|
+
import { eq as eq43, and as and35, asc as asc8, desc as desc19, gt as gt2, gte as gte10, lt as lt8, lte as lte9, ne as ne5, inArray as inArray17, or as or10, isNull as isNull5, isNotNull as isNotNull2, sql as sql17 } from "drizzle-orm";
|
|
43271
43453
|
|
|
43272
43454
|
// ../api-routes/src/ads-activation.ts
|
|
43273
43455
|
import crypto33 from "crypto";
|
|
@@ -44653,7 +44835,7 @@ async function executeApprovedAdsActivation(dependencies, request) {
|
|
|
44653
44835
|
|
|
44654
44836
|
// ../api-routes/src/ads-activation-routes.ts
|
|
44655
44837
|
import crypto34 from "crypto";
|
|
44656
|
-
import { and as and34, asc as asc7, eq as eq42, gt, isNotNull, isNull as isNull4, lte as
|
|
44838
|
+
import { and as and34, asc as asc7, eq as eq42, gt, isNotNull, isNull as isNull4, lte as lte8, or as or9, sql as sql16 } from "drizzle-orm";
|
|
44657
44839
|
var MAX_ACTIVATION_GRANT_LIFETIME_MS = 24 * 60 * 60 * 1e3;
|
|
44658
44840
|
var ACTIVATION_LEASE_MS = 5 * 6e4;
|
|
44659
44841
|
var ACTIVATION_REVOCATION_SETTLEMENT_MS = ACTIVATION_LEASE_MS;
|
|
@@ -44783,7 +44965,7 @@ function createActivationStore(app, request) {
|
|
|
44783
44965
|
isNull4(adsOperations.leaseOwner),
|
|
44784
44966
|
eq42(adsOperations.leaseOwner, input.leaseOwner),
|
|
44785
44967
|
isNull4(adsOperations.leaseExpiresAt),
|
|
44786
|
-
|
|
44968
|
+
lte8(adsOperations.leaseExpiresAt, input.now)
|
|
44787
44969
|
)
|
|
44788
44970
|
)).run();
|
|
44789
44971
|
const resumed = loadCanonicalActivation(tx, grant.id, existing.id);
|
|
@@ -45200,7 +45382,7 @@ function selectWatchdogOperations(app, nowIso, batchSize, allowLiveRevocationLea
|
|
|
45200
45382
|
const leaseAvailable = or9(
|
|
45201
45383
|
isNull4(adsOperations.leaseOwner),
|
|
45202
45384
|
isNull4(adsOperations.leaseExpiresAt),
|
|
45203
|
-
|
|
45385
|
+
lte8(adsOperations.leaseExpiresAt, nowIso)
|
|
45204
45386
|
);
|
|
45205
45387
|
const campaignHasMutationEvidence = or9(
|
|
45206
45388
|
eq42(adsOperationSteps.state, AdsOperationStepStates.executing),
|
|
@@ -45396,7 +45578,7 @@ async function sweepStaleAdsActivationsOnce(app, opts) {
|
|
|
45396
45578
|
or9(
|
|
45397
45579
|
isNull4(adsOperations.leaseOwner),
|
|
45398
45580
|
isNull4(adsOperations.leaseExpiresAt),
|
|
45399
|
-
|
|
45581
|
+
lte8(adsOperations.leaseExpiresAt, nowIso)
|
|
45400
45582
|
)
|
|
45401
45583
|
)
|
|
45402
45584
|
)
|
|
@@ -45433,7 +45615,7 @@ async function sweepStaleAdsActivationsOnce(app, opts) {
|
|
|
45433
45615
|
or9(
|
|
45434
45616
|
isNull4(adsOperations.leaseOwner),
|
|
45435
45617
|
isNull4(adsOperations.leaseExpiresAt),
|
|
45436
|
-
|
|
45618
|
+
lte8(adsOperations.leaseExpiresAt, failedAt)
|
|
45437
45619
|
)
|
|
45438
45620
|
)
|
|
45439
45621
|
)
|
|
@@ -46610,13 +46792,13 @@ function claimOperationForReconciliation(app, row, leaseOwner, now, leaseMs, pol
|
|
|
46610
46792
|
const unknownCutoff = new Date(now.getTime() - backoffMs).toISOString();
|
|
46611
46793
|
const claimableState = row.state === AdsOperationStates.pending ? and35(
|
|
46612
46794
|
eq43(adsOperations.state, AdsOperationStates.pending),
|
|
46613
|
-
|
|
46795
|
+
lte9(adsOperations.updatedAt, pendingCutoff)
|
|
46614
46796
|
) : row.state === AdsOperationStates.unknown ? and35(
|
|
46615
46797
|
eq43(adsOperations.state, AdsOperationStates.unknown),
|
|
46616
|
-
enforceBackoff ?
|
|
46798
|
+
enforceBackoff ? lte9(adsOperations.updatedAt, unknownCutoff) : void 0
|
|
46617
46799
|
) : and35(
|
|
46618
46800
|
eq43(adsOperations.state, AdsOperationStates.reconciling),
|
|
46619
|
-
or10(isNull5(adsOperations.leaseExpiresAt),
|
|
46801
|
+
or10(isNull5(adsOperations.leaseExpiresAt), lte9(adsOperations.leaseExpiresAt, nowIso))
|
|
46620
46802
|
);
|
|
46621
46803
|
const claimed = app.db.update(adsOperations).set({
|
|
46622
46804
|
state: AdsOperationStates.reconciling,
|
|
@@ -46736,7 +46918,7 @@ function quarantineExhaustedReconciliation(app, row, now, policy, context) {
|
|
|
46736
46918
|
}).where(and35(
|
|
46737
46919
|
eq43(adsOperations.id, row.id),
|
|
46738
46920
|
eq43(adsOperations.projectId, row.projectId),
|
|
46739
|
-
|
|
46921
|
+
gte10(adsOperations.reconcileAttempts, policy.maxAttempts),
|
|
46740
46922
|
inArray17(adsOperations.state, [
|
|
46741
46923
|
AdsOperationStates.pending,
|
|
46742
46924
|
AdsOperationStates.unknown,
|
|
@@ -46934,14 +47116,14 @@ async function sweepAdsOperationsOnce(app, opts, config) {
|
|
|
46934
47116
|
const backoffMs = config.policy.backoffBaseMs * 2 ** Math.max(0, reconcileAttempts - 1);
|
|
46935
47117
|
return and35(
|
|
46936
47118
|
eq43(adsOperations.reconcileAttempts, reconcileAttempts),
|
|
46937
|
-
|
|
47119
|
+
lte9(adsOperations.updatedAt, new Date(now.getTime() - backoffMs).toISOString())
|
|
46938
47120
|
);
|
|
46939
47121
|
}
|
|
46940
47122
|
);
|
|
46941
47123
|
const retryableStateWhere = or10(
|
|
46942
47124
|
and35(
|
|
46943
47125
|
eq43(adsOperations.state, AdsOperationStates.pending),
|
|
46944
|
-
|
|
47126
|
+
lte9(adsOperations.updatedAt, pendingCutoff)
|
|
46945
47127
|
),
|
|
46946
47128
|
and35(
|
|
46947
47129
|
eq43(adsOperations.state, AdsOperationStates.unknown),
|
|
@@ -46949,7 +47131,7 @@ async function sweepAdsOperationsOnce(app, opts, config) {
|
|
|
46949
47131
|
),
|
|
46950
47132
|
and35(
|
|
46951
47133
|
eq43(adsOperations.state, AdsOperationStates.reconciling),
|
|
46952
|
-
or10(isNull5(adsOperations.leaseExpiresAt),
|
|
47134
|
+
or10(isNull5(adsOperations.leaseExpiresAt), lte9(adsOperations.leaseExpiresAt, nowIso))
|
|
46953
47135
|
)
|
|
46954
47136
|
);
|
|
46955
47137
|
const staleReconcileWhere = and35(
|
|
@@ -46972,16 +47154,16 @@ async function sweepAdsOperationsOnce(app, opts, config) {
|
|
|
46972
47154
|
);
|
|
46973
47155
|
const exhaustedRows = app.db.select().from(adsOperations).where(and35(
|
|
46974
47156
|
ne5(adsOperations.kind, AdsOperationKinds.campaign_tree_activate),
|
|
46975
|
-
|
|
47157
|
+
gte10(adsOperations.reconcileAttempts, config.policy.maxAttempts),
|
|
46976
47158
|
or10(
|
|
46977
47159
|
and35(
|
|
46978
47160
|
eq43(adsOperations.state, AdsOperationStates.pending),
|
|
46979
|
-
|
|
47161
|
+
lte9(adsOperations.updatedAt, pendingCutoff)
|
|
46980
47162
|
),
|
|
46981
47163
|
eq43(adsOperations.state, AdsOperationStates.unknown),
|
|
46982
47164
|
and35(
|
|
46983
47165
|
eq43(adsOperations.state, AdsOperationStates.reconciling),
|
|
46984
|
-
or10(isNull5(adsOperations.leaseExpiresAt),
|
|
47166
|
+
or10(isNull5(adsOperations.leaseExpiresAt), lte9(adsOperations.leaseExpiresAt, nowIso))
|
|
46985
47167
|
)
|
|
46986
47168
|
),
|
|
46987
47169
|
or10(
|
|
@@ -47857,8 +48039,8 @@ async function adsRoutes(app, opts) {
|
|
|
47857
48039
|
const conditions = [eq43(adsInsightsDaily.projectId, project.id)];
|
|
47858
48040
|
if (parsedLevel) conditions.push(eq43(adsInsightsDaily.level, parsedLevel));
|
|
47859
48041
|
if (entityId) conditions.push(eq43(adsInsightsDaily.entityId, entityId));
|
|
47860
|
-
if (from) conditions.push(
|
|
47861
|
-
if (to) conditions.push(
|
|
48042
|
+
if (from) conditions.push(gte10(adsInsightsDaily.date, from));
|
|
48043
|
+
if (to) conditions.push(lte9(adsInsightsDaily.date, to));
|
|
47862
48044
|
const rows = app.db.select().from(adsInsightsDaily).where(and35(...conditions)).orderBy(asc8(adsInsightsDaily.date)).all();
|
|
47863
48045
|
const conn = app.db.select().from(adsConnections).where(eq43(adsConnections.projectId, project.id)).get();
|
|
47864
48046
|
const accountToday = adsAccountToday(conn?.timezone, (/* @__PURE__ */ new Date()).toISOString());
|
|
@@ -49238,118 +49420,6 @@ function buildSessionHistory(landingPageDays, dailyTotals) {
|
|
|
49238
49420
|
});
|
|
49239
49421
|
}
|
|
49240
49422
|
|
|
49241
|
-
// ../api-routes/src/ga-ai-referral-aggregation.ts
|
|
49242
|
-
function normalizeAiTrafficClass(value) {
|
|
49243
|
-
return value === AiReferralTrafficClasses.paid ? AiReferralTrafficClasses.paid : AiReferralTrafficClasses.organic;
|
|
49244
|
-
}
|
|
49245
|
-
function emptyAiCounts() {
|
|
49246
|
-
return { sessions: 0 };
|
|
49247
|
-
}
|
|
49248
|
-
function resolveWinningDimensions(rows) {
|
|
49249
|
-
const groups = /* @__PURE__ */ new Map();
|
|
49250
|
-
for (const row of rows) {
|
|
49251
|
-
const key = `${row.date}\0${row.source}\0${row.medium}`;
|
|
49252
|
-
let group = groups.get(key);
|
|
49253
|
-
if (!group) {
|
|
49254
|
-
group = { date: row.date, source: row.source, medium: row.medium, byDimension: /* @__PURE__ */ new Map() };
|
|
49255
|
-
groups.set(key, group);
|
|
49256
|
-
}
|
|
49257
|
-
let dim = group.byDimension.get(row.sourceDimension);
|
|
49258
|
-
if (!dim) {
|
|
49259
|
-
dim = { paidSessions: 0, organicSessions: 0 };
|
|
49260
|
-
group.byDimension.set(row.sourceDimension, dim);
|
|
49261
|
-
}
|
|
49262
|
-
const sessions = row.sessions ?? 0;
|
|
49263
|
-
if (normalizeAiTrafficClass(row.trafficClass) === AiReferralTrafficClasses.paid) {
|
|
49264
|
-
dim.paidSessions += sessions;
|
|
49265
|
-
} else {
|
|
49266
|
-
dim.organicSessions += sessions;
|
|
49267
|
-
}
|
|
49268
|
-
}
|
|
49269
|
-
const winners = [];
|
|
49270
|
-
for (const group of groups.values()) {
|
|
49271
|
-
const dims = [...group.byDimension.values()];
|
|
49272
|
-
const bestSessions = dims.reduce((best, d) => d.paidSessions + d.organicSessions > best.paidSessions + best.organicSessions ? d : best);
|
|
49273
|
-
winners.push({
|
|
49274
|
-
date: group.date,
|
|
49275
|
-
source: group.source,
|
|
49276
|
-
medium: group.medium,
|
|
49277
|
-
paidSessions: bestSessions.paidSessions,
|
|
49278
|
-
organicSessions: bestSessions.organicSessions
|
|
49279
|
-
});
|
|
49280
|
-
}
|
|
49281
|
-
return winners;
|
|
49282
|
-
}
|
|
49283
|
-
function summarizeAiReferralCounts(rows) {
|
|
49284
|
-
const paidDeduped = emptyAiCounts();
|
|
49285
|
-
const organicDeduped = emptyAiCounts();
|
|
49286
|
-
const paidBySession = emptyAiCounts();
|
|
49287
|
-
const organicBySession = emptyAiCounts();
|
|
49288
|
-
const bySessionChannelGroup = /* @__PURE__ */ new Map();
|
|
49289
|
-
for (const winner of resolveWinningDimensions(rows)) {
|
|
49290
|
-
paidDeduped.sessions += winner.paidSessions;
|
|
49291
|
-
organicDeduped.sessions += winner.organicSessions;
|
|
49292
|
-
}
|
|
49293
|
-
for (const row of rows) {
|
|
49294
|
-
if (row.sourceDimension !== "session") continue;
|
|
49295
|
-
const sessions = row.sessions ?? 0;
|
|
49296
|
-
bySessionChannelGroup.set(
|
|
49297
|
-
row.channelGroup,
|
|
49298
|
-
(bySessionChannelGroup.get(row.channelGroup) ?? 0) + sessions
|
|
49299
|
-
);
|
|
49300
|
-
const bucket = normalizeAiTrafficClass(row.trafficClass) === AiReferralTrafficClasses.paid ? paidBySession : organicBySession;
|
|
49301
|
-
bucket.sessions += sessions;
|
|
49302
|
-
}
|
|
49303
|
-
return {
|
|
49304
|
-
paidDeduped,
|
|
49305
|
-
organicDeduped,
|
|
49306
|
-
paidBySession,
|
|
49307
|
-
organicBySession,
|
|
49308
|
-
bySessionChannelGroup,
|
|
49309
|
-
deduped: { sessions: paidDeduped.sessions + organicDeduped.sessions },
|
|
49310
|
-
bySession: { sessions: paidBySession.sessions + organicBySession.sessions }
|
|
49311
|
-
};
|
|
49312
|
-
}
|
|
49313
|
-
function buildAiReferralDailySeries(rows) {
|
|
49314
|
-
const byDate = /* @__PURE__ */ new Map();
|
|
49315
|
-
const sourceTotals = /* @__PURE__ */ new Map();
|
|
49316
|
-
let totalSessions = 0;
|
|
49317
|
-
let totalPaidSessions = 0;
|
|
49318
|
-
let totalOrganicSessions = 0;
|
|
49319
|
-
for (const winner of resolveWinningDimensions(rows)) {
|
|
49320
|
-
const sessions = winner.paidSessions + winner.organicSessions;
|
|
49321
|
-
let bySource = byDate.get(winner.date);
|
|
49322
|
-
if (!bySource) {
|
|
49323
|
-
bySource = /* @__PURE__ */ new Map();
|
|
49324
|
-
byDate.set(winner.date, bySource);
|
|
49325
|
-
}
|
|
49326
|
-
let bucket = bySource.get(winner.source);
|
|
49327
|
-
if (!bucket) {
|
|
49328
|
-
bucket = { source: winner.source, sessions: 0, paidSessions: 0, organicSessions: 0 };
|
|
49329
|
-
bySource.set(winner.source, bucket);
|
|
49330
|
-
}
|
|
49331
|
-
bucket.sessions += sessions;
|
|
49332
|
-
bucket.paidSessions += winner.paidSessions;
|
|
49333
|
-
bucket.organicSessions += winner.organicSessions;
|
|
49334
|
-
sourceTotals.set(winner.source, (sourceTotals.get(winner.source) ?? 0) + sessions);
|
|
49335
|
-
totalSessions += sessions;
|
|
49336
|
-
totalPaidSessions += winner.paidSessions;
|
|
49337
|
-
totalOrganicSessions += winner.organicSessions;
|
|
49338
|
-
}
|
|
49339
|
-
const days = [...byDate.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([date, bySource]) => {
|
|
49340
|
-
const sources2 = [...bySource.values()].sort((a, b) => b.sessions - a.sessions || a.source.localeCompare(b.source));
|
|
49341
|
-
return {
|
|
49342
|
-
date,
|
|
49343
|
-
sessions: sources2.reduce((sum, s) => sum + s.sessions, 0),
|
|
49344
|
-
paidSessions: sources2.reduce((sum, s) => sum + s.paidSessions, 0),
|
|
49345
|
-
organicSessions: sources2.reduce((sum, s) => sum + s.organicSessions, 0),
|
|
49346
|
-
bySource: sources2
|
|
49347
|
-
};
|
|
49348
|
-
});
|
|
49349
|
-
const sources = [...sourceTotals.entries()].sort(([aSource, aSessions], [bSource, bSessions]) => bSessions - aSessions || aSource.localeCompare(bSource)).map(([source]) => source);
|
|
49350
|
-
return { days, sources, totalSessions, totalPaidSessions, totalOrganicSessions };
|
|
49351
|
-
}
|
|
49352
|
-
|
|
49353
49423
|
// ../api-routes/src/ga.ts
|
|
49354
49424
|
function gaLog(level, action, ctx) {
|
|
49355
49425
|
const entry = { ts: (/* @__PURE__ */ new Date()).toISOString(), level, module: "GA4Routes", action, ...ctx };
|
|
@@ -49401,16 +49471,26 @@ function buildChannelBreakdown(input) {
|
|
|
49401
49471
|
}
|
|
49402
49472
|
};
|
|
49403
49473
|
}
|
|
49404
|
-
function
|
|
49405
|
-
const
|
|
49474
|
+
function keepWinningDimensionRows(rows, groupKey) {
|
|
49475
|
+
const sessionsByGroupAndDimension = /* @__PURE__ */ new Map();
|
|
49406
49476
|
for (const row of rows) {
|
|
49407
|
-
const key =
|
|
49408
|
-
|
|
49409
|
-
if (!
|
|
49410
|
-
|
|
49411
|
-
|
|
49477
|
+
const key = groupKey(row);
|
|
49478
|
+
let byDimension = sessionsByGroupAndDimension.get(key);
|
|
49479
|
+
if (!byDimension) {
|
|
49480
|
+
byDimension = /* @__PURE__ */ new Map();
|
|
49481
|
+
sessionsByGroupAndDimension.set(key, byDimension);
|
|
49482
|
+
}
|
|
49483
|
+
byDimension.set(
|
|
49484
|
+
row.sourceDimension,
|
|
49485
|
+
(byDimension.get(row.sourceDimension) ?? 0) + (row.sessions ?? 0)
|
|
49486
|
+
);
|
|
49412
49487
|
}
|
|
49413
|
-
|
|
49488
|
+
const winningDimension = /* @__PURE__ */ new Map();
|
|
49489
|
+
for (const [key, byDimension] of sessionsByGroupAndDimension) {
|
|
49490
|
+
const winner = pickWinningAttributionDimension(byDimension);
|
|
49491
|
+
if (winner) winningDimension.set(key, winner);
|
|
49492
|
+
}
|
|
49493
|
+
return rows.filter((row) => winningDimension.get(groupKey(row)) === row.sourceDimension).sort((a, b) => (b.sessions ?? 0) - (a.sessions ?? 0));
|
|
49414
49494
|
}
|
|
49415
49495
|
function persistAcquisitionMeasurement(db, input) {
|
|
49416
49496
|
const { startDate, endDate } = input.report;
|
|
@@ -50169,13 +50249,10 @@ async function ga4Routes(app, opts) {
|
|
|
50169
50249
|
channelGroup: gaAiReferrals.channelGroup,
|
|
50170
50250
|
sessions: gaAiReferrals.sessions
|
|
50171
50251
|
}).from(gaAiReferrals).where(and38(...aiConditions)).all();
|
|
50172
|
-
const aiReferrals =
|
|
50173
|
-
|
|
50174
|
-
(r) => `${r.source}\0${r.medium}\0${r.trafficClass}`
|
|
50175
|
-
);
|
|
50176
|
-
const aiReferralLandingPages = pickWinningDimension(
|
|
50252
|
+
const aiReferrals = keepWinningDimensionRows(aiReferralRows, (r) => r.source);
|
|
50253
|
+
const aiReferralLandingPages = keepWinningDimensionRows(
|
|
50177
50254
|
aiReferralLandingPageRows,
|
|
50178
|
-
(r) => `${r.source}\0${r.
|
|
50255
|
+
(r) => `${r.source}\0${r.landingPage}`
|
|
50179
50256
|
);
|
|
50180
50257
|
const aiSummary = summarizeAiReferralCounts(aiRowsForTotals);
|
|
50181
50258
|
const socialReferrals = app.db.select({
|
|
@@ -52948,7 +53025,7 @@ import crypto43 from "crypto";
|
|
|
52948
53025
|
import { isIP } from "net";
|
|
52949
53026
|
import { isDeepStrictEqual } from "util";
|
|
52950
53027
|
import { Agent as UndiciAgent } from "undici";
|
|
52951
|
-
import { and as and44, desc as desc23, eq as eq51, gte as
|
|
53028
|
+
import { and as and44, desc as desc23, eq as eq51, gte as gte12, inArray as inArray18, lte as lte12, sql as sql22 } from "drizzle-orm";
|
|
52952
53029
|
|
|
52953
53030
|
// ../api-routes/src/cloudflare-worker-version.ts
|
|
52954
53031
|
var CURRENT_CLOUDFLARE_WORKER_VERSION = "1.0.1";
|
|
@@ -69559,7 +69636,7 @@ async function ackCloudflareQueueMessages(client, options) {
|
|
|
69559
69636
|
|
|
69560
69637
|
// ../api-routes/src/traffic-event-ingest.ts
|
|
69561
69638
|
import crypto42 from "crypto";
|
|
69562
|
-
import { and as and42, eq as eq49, gte as
|
|
69639
|
+
import { and as and42, eq as eq49, gte as gte11, lt as lt10, lte as lte10, sql as sql21 } from "drizzle-orm";
|
|
69563
69640
|
|
|
69564
69641
|
// ../api-routes/src/raw-event-sample-retention.ts
|
|
69565
69642
|
import { and as and41, eq as eq48, lt as lt9, sql as sql20 } from "drizzle-orm";
|
|
@@ -69638,7 +69715,7 @@ function writeTrafficEventBatch(opts) {
|
|
|
69638
69715
|
);
|
|
69639
69716
|
tx.delete(trafficEventReceipts).where(and42(
|
|
69640
69717
|
eq49(trafficEventReceipts.sourceId, opts.sourceId),
|
|
69641
|
-
|
|
69718
|
+
lte10(trafficEventReceipts.expiresAt, opts.receivedAt)
|
|
69642
69719
|
)).run();
|
|
69643
69720
|
const claimedEvents = [];
|
|
69644
69721
|
for (const event of opts.events) {
|
|
@@ -69838,7 +69915,7 @@ function writeTrafficEventBatch(opts) {
|
|
|
69838
69915
|
if (remaining === void 0) {
|
|
69839
69916
|
const existing = tx.select({ total: sql21`COUNT(*)` }).from(rawEventSamples).where(and42(
|
|
69840
69917
|
eq49(rawEventSamples.sourceId, opts.sourceId),
|
|
69841
|
-
|
|
69918
|
+
gte11(rawEventSamples.ts, hour.start),
|
|
69842
69919
|
lt10(rawEventSamples.ts, hour.end)
|
|
69843
69920
|
)).get();
|
|
69844
69921
|
remaining = Math.max(0, hourlySampleLimit - Number(existing?.total ?? 0));
|
|
@@ -69896,7 +69973,7 @@ function writeTrafficEventBatch(opts) {
|
|
|
69896
69973
|
}
|
|
69897
69974
|
|
|
69898
69975
|
// ../api-routes/src/traffic-sync-lease.ts
|
|
69899
|
-
import { and as and43, eq as eq50, isNull as isNull6, lte as
|
|
69976
|
+
import { and as and43, eq as eq50, isNull as isNull6, lte as lte11, or as or11 } from "drizzle-orm";
|
|
69900
69977
|
function leaseExpiresAt(now, ttlMs) {
|
|
69901
69978
|
const nowMs = Date.parse(now);
|
|
69902
69979
|
if (!Number.isFinite(nowMs)) throw new RangeError("Traffic sync lease now must be an ISO instant");
|
|
@@ -69913,7 +69990,7 @@ function tryClaimTrafficSyncLease(input) {
|
|
|
69913
69990
|
eq50(trafficSources.id, input.sourceId),
|
|
69914
69991
|
or11(
|
|
69915
69992
|
isNull6(trafficSources.syncLeaseOwner),
|
|
69916
|
-
|
|
69993
|
+
lte11(trafficSources.syncLeaseExpiresAt, input.now),
|
|
69917
69994
|
eq50(trafficSources.syncLeaseOwner, input.owner)
|
|
69918
69995
|
)
|
|
69919
69996
|
)).run();
|
|
@@ -70409,29 +70486,29 @@ async function runBackfillTask(options) {
|
|
|
70409
70486
|
tx.delete(crawlerEventsHourly).where(
|
|
70410
70487
|
and44(
|
|
70411
70488
|
eq51(crawlerEventsHourly.sourceId, sourceRow2.id),
|
|
70412
|
-
|
|
70413
|
-
|
|
70489
|
+
gte12(crawlerEventsHourly.tsHour, windowStartIso),
|
|
70490
|
+
lte12(crawlerEventsHourly.tsHour, windowEndIso)
|
|
70414
70491
|
)
|
|
70415
70492
|
).run();
|
|
70416
70493
|
tx.delete(aiUserFetchEventsHourly).where(
|
|
70417
70494
|
and44(
|
|
70418
70495
|
eq51(aiUserFetchEventsHourly.sourceId, sourceRow2.id),
|
|
70419
|
-
|
|
70420
|
-
|
|
70496
|
+
gte12(aiUserFetchEventsHourly.tsHour, windowStartIso),
|
|
70497
|
+
lte12(aiUserFetchEventsHourly.tsHour, windowEndIso)
|
|
70421
70498
|
)
|
|
70422
70499
|
).run();
|
|
70423
70500
|
tx.delete(aiReferralEventsHourly).where(
|
|
70424
70501
|
and44(
|
|
70425
70502
|
eq51(aiReferralEventsHourly.sourceId, sourceRow2.id),
|
|
70426
|
-
|
|
70427
|
-
|
|
70503
|
+
gte12(aiReferralEventsHourly.tsHour, windowStartIso),
|
|
70504
|
+
lte12(aiReferralEventsHourly.tsHour, windowEndIso)
|
|
70428
70505
|
)
|
|
70429
70506
|
).run();
|
|
70430
70507
|
tx.delete(rawEventSamples).where(
|
|
70431
70508
|
and44(
|
|
70432
70509
|
eq51(rawEventSamples.sourceId, sourceRow2.id),
|
|
70433
|
-
|
|
70434
|
-
|
|
70510
|
+
gte12(rawEventSamples.ts, windowStartIso),
|
|
70511
|
+
lte12(rawEventSamples.ts, windowEndIso)
|
|
70435
70512
|
)
|
|
70436
70513
|
).run();
|
|
70437
70514
|
for (const bucket of report.crawlerEventsHourly) {
|
|
@@ -72595,7 +72672,7 @@ async function trafficRoutes(app, opts) {
|
|
|
72595
72672
|
}).from(crawlerEventsHourly).where(
|
|
72596
72673
|
and44(
|
|
72597
72674
|
eq51(crawlerEventsHourly.sourceId, row.id),
|
|
72598
|
-
|
|
72675
|
+
gte12(crawlerEventsHourly.tsHour, since)
|
|
72599
72676
|
)
|
|
72600
72677
|
).groupBy(crawlerEventsHourly.pathNormalized).all();
|
|
72601
72678
|
const crawlerSegments = segmentCrawlerHits(
|
|
@@ -72605,7 +72682,7 @@ async function trafficRoutes(app, opts) {
|
|
|
72605
72682
|
const aiUserFetchTotals = app.db.select({ total: sql22`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
|
|
72606
72683
|
and44(
|
|
72607
72684
|
eq51(aiUserFetchEventsHourly.sourceId, row.id),
|
|
72608
|
-
|
|
72685
|
+
gte12(aiUserFetchEventsHourly.tsHour, since)
|
|
72609
72686
|
)
|
|
72610
72687
|
).get();
|
|
72611
72688
|
const aiTotals = app.db.select({
|
|
@@ -72615,13 +72692,13 @@ async function trafficRoutes(app, opts) {
|
|
|
72615
72692
|
}).from(aiReferralEventsHourly).where(
|
|
72616
72693
|
and44(
|
|
72617
72694
|
eq51(aiReferralEventsHourly.sourceId, row.id),
|
|
72618
|
-
|
|
72695
|
+
gte12(aiReferralEventsHourly.tsHour, since)
|
|
72619
72696
|
)
|
|
72620
72697
|
).get();
|
|
72621
72698
|
const sampleTotals = app.db.select({ total: sql22`COUNT(*)` }).from(rawEventSamples).where(
|
|
72622
72699
|
and44(
|
|
72623
72700
|
eq51(rawEventSamples.sourceId, row.id),
|
|
72624
|
-
|
|
72701
|
+
gte12(rawEventSamples.ts, since)
|
|
72625
72702
|
)
|
|
72626
72703
|
).get();
|
|
72627
72704
|
const latestRun = app.db.select().from(runs).where(
|
|
@@ -72800,8 +72877,8 @@ async function trafficRoutes(app, opts) {
|
|
|
72800
72877
|
if (kind === "all" || kind === TrafficEventKinds.crawler) {
|
|
72801
72878
|
const crawlerFilters = [
|
|
72802
72879
|
eq51(crawlerEventsHourly.projectId, project.id),
|
|
72803
|
-
|
|
72804
|
-
|
|
72880
|
+
gte12(crawlerEventsHourly.tsHour, sinceIso),
|
|
72881
|
+
lte12(crawlerEventsHourly.tsHour, untilIso)
|
|
72805
72882
|
];
|
|
72806
72883
|
if (sourceIdParam) crawlerFilters.push(eq51(crawlerEventsHourly.sourceId, sourceIdParam));
|
|
72807
72884
|
const crawlerWhere = and44(...crawlerFilters);
|
|
@@ -72875,8 +72952,8 @@ async function trafficRoutes(app, opts) {
|
|
|
72875
72952
|
if (kind === "all" || kind === TrafficEventKinds["ai-user-fetch"]) {
|
|
72876
72953
|
const userFetchFilters = [
|
|
72877
72954
|
eq51(aiUserFetchEventsHourly.projectId, project.id),
|
|
72878
|
-
|
|
72879
|
-
|
|
72955
|
+
gte12(aiUserFetchEventsHourly.tsHour, sinceIso),
|
|
72956
|
+
lte12(aiUserFetchEventsHourly.tsHour, untilIso)
|
|
72880
72957
|
];
|
|
72881
72958
|
if (sourceIdParam) userFetchFilters.push(eq51(aiUserFetchEventsHourly.sourceId, sourceIdParam));
|
|
72882
72959
|
const userFetchWhere = and44(...userFetchFilters);
|
|
@@ -72914,8 +72991,8 @@ async function trafficRoutes(app, opts) {
|
|
|
72914
72991
|
if (kind === "all" || kind === TrafficEventKinds["ai-referral"]) {
|
|
72915
72992
|
const aiFilters = [
|
|
72916
72993
|
eq51(aiReferralEventsHourly.projectId, project.id),
|
|
72917
|
-
|
|
72918
|
-
|
|
72994
|
+
gte12(aiReferralEventsHourly.tsHour, sinceIso),
|
|
72995
|
+
lte12(aiReferralEventsHourly.tsHour, untilIso)
|
|
72919
72996
|
];
|
|
72920
72997
|
if (sourceIdParam) aiFilters.push(eq51(aiReferralEventsHourly.sourceId, sourceIdParam));
|
|
72921
72998
|
const aiWhere = and44(...aiFilters);
|
|
@@ -74803,7 +74880,7 @@ var RUNTIME_STATE_CHECKS = [
|
|
|
74803
74880
|
];
|
|
74804
74881
|
|
|
74805
74882
|
// ../api-routes/src/doctor/checks/traffic-source.ts
|
|
74806
|
-
import { and as and47, eq as eq57, gte as
|
|
74883
|
+
import { and as and47, eq as eq57, gte as gte13, inArray as inArray19, ne as ne7, sql as sql23 } from "drizzle-orm";
|
|
74807
74884
|
var RECENT_DATA_WARN_DAYS = 7;
|
|
74808
74885
|
var RECENT_DATA_FAIL_DAYS = 30;
|
|
74809
74886
|
function isCloudflareDirectPush(source) {
|
|
@@ -74952,7 +75029,7 @@ var recentDataCheck = {
|
|
|
74952
75029
|
and47(
|
|
74953
75030
|
eq57(crawlerEventsHourly.projectId, ctx.project.id),
|
|
74954
75031
|
inArray19(crawlerEventsHourly.sourceId, activeSourceIds),
|
|
74955
|
-
|
|
75032
|
+
gte13(crawlerEventsHourly.tsHour, warnCutoff)
|
|
74956
75033
|
)
|
|
74957
75034
|
).get()?.total ?? 0
|
|
74958
75035
|
);
|
|
@@ -74961,7 +75038,7 @@ var recentDataCheck = {
|
|
|
74961
75038
|
and47(
|
|
74962
75039
|
eq57(aiReferralEventsHourly.projectId, ctx.project.id),
|
|
74963
75040
|
inArray19(aiReferralEventsHourly.sourceId, activeSourceIds),
|
|
74964
|
-
|
|
75041
|
+
gte13(aiReferralEventsHourly.tsHour, warnCutoff)
|
|
74965
75042
|
)
|
|
74966
75043
|
).get()?.total ?? 0
|
|
74967
75044
|
);
|
|
@@ -74970,7 +75047,7 @@ var recentDataCheck = {
|
|
|
74970
75047
|
and47(
|
|
74971
75048
|
eq57(aiUserFetchEventsHourly.projectId, ctx.project.id),
|
|
74972
75049
|
inArray19(aiUserFetchEventsHourly.sourceId, activeSourceIds),
|
|
74973
|
-
|
|
75050
|
+
gte13(aiUserFetchEventsHourly.tsHour, warnCutoff)
|
|
74974
75051
|
)
|
|
74975
75052
|
).get()?.total ?? 0
|
|
74976
75053
|
);
|
|
@@ -74996,7 +75073,7 @@ var recentDataCheck = {
|
|
|
74996
75073
|
and47(
|
|
74997
75074
|
eq57(crawlerEventsHourly.projectId, ctx.project.id),
|
|
74998
75075
|
inArray19(crawlerEventsHourly.sourceId, activeSourceIds),
|
|
74999
|
-
|
|
75076
|
+
gte13(crawlerEventsHourly.tsHour, failCutoff)
|
|
75000
75077
|
)
|
|
75001
75078
|
).get()?.total ?? 0
|
|
75002
75079
|
);
|
|
@@ -75005,7 +75082,7 @@ var recentDataCheck = {
|
|
|
75005
75082
|
and47(
|
|
75006
75083
|
eq57(aiReferralEventsHourly.projectId, ctx.project.id),
|
|
75007
75084
|
inArray19(aiReferralEventsHourly.sourceId, activeSourceIds),
|
|
75008
|
-
|
|
75085
|
+
gte13(aiReferralEventsHourly.tsHour, failCutoff)
|
|
75009
75086
|
)
|
|
75010
75087
|
).get()?.total ?? 0
|
|
75011
75088
|
);
|
|
@@ -75014,7 +75091,7 @@ var recentDataCheck = {
|
|
|
75014
75091
|
and47(
|
|
75015
75092
|
eq57(aiUserFetchEventsHourly.projectId, ctx.project.id),
|
|
75016
75093
|
inArray19(aiUserFetchEventsHourly.sourceId, activeSourceIds),
|
|
75017
|
-
|
|
75094
|
+
gte13(aiUserFetchEventsHourly.tsHour, failCutoff)
|
|
75018
75095
|
)
|
|
75019
75096
|
).get()?.total ?? 0
|
|
75020
75097
|
);
|
|
@@ -75929,7 +76006,7 @@ async function doctorRoutes(app, opts) {
|
|
|
75929
76006
|
|
|
75930
76007
|
// ../api-routes/src/discovery/routes.ts
|
|
75931
76008
|
import crypto45 from "crypto";
|
|
75932
|
-
import { and as and48, desc as desc24, eq as eq58, gte as
|
|
76009
|
+
import { and as and48, desc as desc24, eq as eq58, gte as gte14, inArray as inArray20, isNull as isNull7, or as or12 } from "drizzle-orm";
|
|
75933
76010
|
var MAX_INFLIGHT_DISCOVERY_AGE_MS = 2 * 60 * 60 * 1e3;
|
|
75934
76011
|
async function discoveryRoutes(app, opts) {
|
|
75935
76012
|
app.post("/projects/:name/discover/run", async (request, reply) => {
|
|
@@ -75989,7 +76066,7 @@ async function discoveryRoutes(app, opts) {
|
|
|
75989
76066
|
DiscoverySessionStatuses.seeding,
|
|
75990
76067
|
DiscoverySessionStatuses.probing
|
|
75991
76068
|
]),
|
|
75992
|
-
|
|
76069
|
+
gte14(discoverySessions.createdAt, ageFloorIso)
|
|
75993
76070
|
)).orderBy(desc24(discoverySessions.createdAt)).get();
|
|
75994
76071
|
if (existing && existing.runId) {
|
|
75995
76072
|
return { reused: true, sessionId: existing.id, runId: existing.runId };
|
|
@@ -79333,7 +79410,7 @@ var IntelligenceService = class {
|
|
|
79333
79410
|
// Never look forward. The window is this run's own past, so
|
|
79334
79411
|
// re-analyzing a historical run compares it against its true
|
|
79335
79412
|
// predecessor rather than against sweeps that came after it.
|
|
79336
|
-
|
|
79413
|
+
lte13(runChronologyKey, currentRunRecord.finishedAt ?? currentRunRecord.createdAt),
|
|
79337
79414
|
// MEASUREMENT: only runs that actually wrote snapshots — see above.
|
|
79338
79415
|
// Index seek on idx_snapshots_run, short-circuited on the first row.
|
|
79339
79416
|
exists(
|
|
@@ -79423,8 +79500,8 @@ var IntelligenceService = class {
|
|
|
79423
79500
|
const selected = this.db.select().from(gbpLocations).where(and51(
|
|
79424
79501
|
eq62(gbpLocations.projectId, projectId),
|
|
79425
79502
|
eq62(gbpLocations.selected, true),
|
|
79426
|
-
|
|
79427
|
-
|
|
79503
|
+
gte15(gbpLocations.syncedAt, windowStart),
|
|
79504
|
+
lte13(gbpLocations.syncedAt, windowEnd)
|
|
79428
79505
|
)).all();
|
|
79429
79506
|
if (selected.length === 0) {
|
|
79430
79507
|
log.info("gbp-intelligence.skip", { runId, reason: "no locations synced during run" });
|