@canonry/canonry 4.180.3 → 4.180.5
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-6LSP7ODK.js} +4 -4
- package/dist/{chunk-CKGWOYPO.js → chunk-DK23XZ6C.js} +2 -2
- package/dist/{chunk-OJDH2F6I.js → chunk-EC2O3LHD.js} +519 -440
- package/dist/{chunk-YPDKZ73I.js → chunk-JJIESVNL.js} +1 -1
- package/dist/{chunk-JWPN6RU7.js → chunk-UESVOQRS.js} +1 -1
- package/dist/cli.js +17 -6
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-DSYYBDR2.js → intelligence-service-NJUFIWAO.js} +2 -2
- package/dist/mcp.js +3 -3
- package/package.json +8 -8
|
@@ -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,37 @@ function buildCandidateQueries(opts) {
|
|
|
22804
22953
|
});
|
|
22805
22954
|
});
|
|
22806
22955
|
}
|
|
22807
|
-
|
|
22956
|
+
var DEFAULT_CONTENT_GSC_WINDOW_DAYS = 30;
|
|
22957
|
+
function windowEndingOn(endDate, windowDays2) {
|
|
22958
|
+
const end = /* @__PURE__ */ new Date(`${endDate}T00:00:00Z`);
|
|
22959
|
+
end.setUTCDate(end.getUTCDate() - (Math.max(1, windowDays2) - 1));
|
|
22960
|
+
return { startDate: end.toISOString().slice(0, 10), endDate };
|
|
22961
|
+
}
|
|
22962
|
+
function resolveContentGscWindow(db, projectId, windowDays2) {
|
|
22963
|
+
const endDate = readLatestGscDataDate(db, projectId);
|
|
22964
|
+
return endDate ? windowEndingOn(endDate, windowDays2) : null;
|
|
22965
|
+
}
|
|
22966
|
+
function pageDayFallback(rows) {
|
|
22967
|
+
const byDay = /* @__PURE__ */ new Map();
|
|
22968
|
+
for (const r of rows) {
|
|
22969
|
+
if (!r.query) continue;
|
|
22970
|
+
const key = `${r.date}\0${r.query}`;
|
|
22971
|
+
const acc = byDay.get(key) ?? { date: r.date, query: r.query, clicks: 0, impressions: 0, weighted: 0 };
|
|
22972
|
+
acc.clicks += r.clicks;
|
|
22973
|
+
acc.impressions += r.impressions;
|
|
22974
|
+
acc.weighted += (Number(r.position) || 0) * r.impressions;
|
|
22975
|
+
byDay.set(key, acc);
|
|
22976
|
+
}
|
|
22977
|
+
return [...byDay.values()].map((a) => ({
|
|
22978
|
+
date: a.date,
|
|
22979
|
+
query: a.query,
|
|
22980
|
+
clicks: a.clicks,
|
|
22981
|
+
impressions: a.impressions,
|
|
22982
|
+
position: a.impressions > 0 ? a.weighted / a.impressions : 0
|
|
22983
|
+
}));
|
|
22984
|
+
}
|
|
22985
|
+
function aggregateGscByQuery(rows, queryTotals = []) {
|
|
22986
|
+
const accurateByQuery = new Map(queryTotals.map((t) => [t.query, t]));
|
|
22808
22987
|
const accumulators = /* @__PURE__ */ new Map();
|
|
22809
22988
|
for (const r of rows) {
|
|
22810
22989
|
const page2 = extractPath2(r.page);
|
|
@@ -22830,12 +23009,16 @@ function aggregateGscByQuery(rows) {
|
|
|
22830
23009
|
}
|
|
22831
23010
|
const byQuery = /* @__PURE__ */ new Map();
|
|
22832
23011
|
for (const [query, acc] of accumulators) {
|
|
23012
|
+
const accurate = accurateByQuery.get(query);
|
|
23013
|
+
const impressions = accurate ? accurate.impressions : acc.totalImpressions;
|
|
23014
|
+
const clicks = accurate ? accurate.clicks : acc.totalClicks;
|
|
23015
|
+
const position = accurate ? accurate.position : acc.totalImpressions > 0 ? acc.weightedPositionSum / acc.totalImpressions : 0;
|
|
22833
23016
|
byQuery.set(query, {
|
|
22834
23017
|
page: acc.bestPage,
|
|
22835
|
-
position
|
|
22836
|
-
impressions
|
|
22837
|
-
clicks
|
|
22838
|
-
ctr:
|
|
23018
|
+
position,
|
|
23019
|
+
impressions,
|
|
23020
|
+
clicks,
|
|
23021
|
+
ctr: impressions > 0 ? clicks / impressions : 0
|
|
22839
23022
|
});
|
|
22840
23023
|
}
|
|
22841
23024
|
return byQuery;
|
|
@@ -22987,7 +23170,7 @@ function extractPath2(url) {
|
|
|
22987
23170
|
|
|
22988
23171
|
// ../api-routes/src/content.ts
|
|
22989
23172
|
function loadDismissedTargetRefs(db, projectId) {
|
|
22990
|
-
const rows = db.select({ targetRef: contentTargetDismissals.targetRef }).from(contentTargetDismissals).where(
|
|
23173
|
+
const rows = db.select({ targetRef: contentTargetDismissals.targetRef }).from(contentTargetDismissals).where(eq28(contentTargetDismissals.projectId, projectId)).all();
|
|
22991
23174
|
return new Set(rows.map((r) => r.targetRef));
|
|
22992
23175
|
}
|
|
22993
23176
|
function formatDismissalRow(row) {
|
|
@@ -23082,7 +23265,7 @@ async function contentRoutes(app, opts = {}) {
|
|
|
23082
23265
|
});
|
|
23083
23266
|
app.get("/projects/:name/content/dismissals", async (request) => {
|
|
23084
23267
|
const project = resolveProject(app.db, request.params.name);
|
|
23085
|
-
const rows = app.db.select().from(contentTargetDismissals).where(
|
|
23268
|
+
const rows = app.db.select().from(contentTargetDismissals).where(eq28(contentTargetDismissals.projectId, project.id)).orderBy(contentTargetDismissals.dismissedAt).all();
|
|
23086
23269
|
const response = {
|
|
23087
23270
|
dismissals: rows.map(formatDismissalRow)
|
|
23088
23271
|
};
|
|
@@ -23111,9 +23294,9 @@ async function contentRoutes(app, opts = {}) {
|
|
|
23111
23294
|
dismissedAt: now
|
|
23112
23295
|
}
|
|
23113
23296
|
}).run();
|
|
23114
|
-
const row = app.db.select().from(contentTargetDismissals).where(
|
|
23115
|
-
|
|
23116
|
-
|
|
23297
|
+
const row = app.db.select().from(contentTargetDismissals).where(and23(
|
|
23298
|
+
eq28(contentTargetDismissals.projectId, project.id),
|
|
23299
|
+
eq28(contentTargetDismissals.targetRef, targetRef)
|
|
23117
23300
|
)).get();
|
|
23118
23301
|
if (!row) throw notFound("contentTargetDismissal", targetRef);
|
|
23119
23302
|
return formatDismissalRow(row);
|
|
@@ -23121,9 +23304,9 @@ async function contentRoutes(app, opts = {}) {
|
|
|
23121
23304
|
app.delete("/projects/:name/content/dismissals/:targetRef", async (request, reply) => {
|
|
23122
23305
|
const project = resolveProject(app.db, request.params.name);
|
|
23123
23306
|
const { targetRef } = request.params;
|
|
23124
|
-
const result = app.db.delete(contentTargetDismissals).where(
|
|
23125
|
-
|
|
23126
|
-
|
|
23307
|
+
const result = app.db.delete(contentTargetDismissals).where(and23(
|
|
23308
|
+
eq28(contentTargetDismissals.projectId, project.id),
|
|
23309
|
+
eq28(contentTargetDismissals.targetRef, targetRef)
|
|
23127
23310
|
)).run();
|
|
23128
23311
|
if (result.changes === 0) {
|
|
23129
23312
|
throw notFound("contentTargetDismissal", targetRef);
|
|
@@ -23132,9 +23315,9 @@ async function contentRoutes(app, opts = {}) {
|
|
|
23132
23315
|
});
|
|
23133
23316
|
app.get("/projects/:name/content/recommendations/:targetRef/analysis", async (request, reply) => {
|
|
23134
23317
|
const project = resolveProject(app.db, request.params.name);
|
|
23135
|
-
const row = app.db.select().from(recommendationExplanations).where(
|
|
23136
|
-
|
|
23137
|
-
|
|
23318
|
+
const row = app.db.select().from(recommendationExplanations).where(and23(
|
|
23319
|
+
eq28(recommendationExplanations.projectId, project.id),
|
|
23320
|
+
eq28(recommendationExplanations.targetRef, request.params.targetRef)
|
|
23138
23321
|
)).orderBy(desc11(recommendationExplanations.generatedAt)).limit(1).get();
|
|
23139
23322
|
if (!row) {
|
|
23140
23323
|
return reply.status(404).send({ error: { code: "NOT_FOUND", message: "No cached explanation for this targetRef." } });
|
|
@@ -23160,9 +23343,9 @@ async function contentRoutes(app, opts = {}) {
|
|
|
23160
23343
|
throw notFound("contentRecommendation", targetRef);
|
|
23161
23344
|
}
|
|
23162
23345
|
if (!body.forceRefresh) {
|
|
23163
|
-
const cached = app.db.select().from(recommendationExplanations).where(
|
|
23164
|
-
|
|
23165
|
-
|
|
23346
|
+
const cached = app.db.select().from(recommendationExplanations).where(and23(
|
|
23347
|
+
eq28(recommendationExplanations.projectId, project.id),
|
|
23348
|
+
eq28(recommendationExplanations.targetRef, targetRef)
|
|
23166
23349
|
)).orderBy(desc11(recommendationExplanations.generatedAt)).limit(1).get();
|
|
23167
23350
|
if (cached) return reply.send(formatExplanationRow(cached));
|
|
23168
23351
|
}
|
|
@@ -23199,10 +23382,10 @@ async function contentRoutes(app, opts = {}) {
|
|
|
23199
23382
|
generatedAt: now
|
|
23200
23383
|
}
|
|
23201
23384
|
}).run();
|
|
23202
|
-
const row = app.db.select().from(recommendationExplanations).where(
|
|
23203
|
-
|
|
23204
|
-
|
|
23205
|
-
|
|
23385
|
+
const row = app.db.select().from(recommendationExplanations).where(and23(
|
|
23386
|
+
eq28(recommendationExplanations.projectId, project.id),
|
|
23387
|
+
eq28(recommendationExplanations.targetRef, targetRef),
|
|
23388
|
+
eq28(recommendationExplanations.promptVersion, result.promptVersion)
|
|
23206
23389
|
)).get();
|
|
23207
23390
|
if (!row) throw notFound("recommendationExplanation", targetRef);
|
|
23208
23391
|
return reply.send(formatExplanationRow(row));
|
|
@@ -23283,17 +23466,17 @@ async function contentRoutes(app, opts = {}) {
|
|
|
23283
23466
|
generatedAt: now
|
|
23284
23467
|
}
|
|
23285
23468
|
}).run();
|
|
23286
|
-
const row = app.db.select().from(recommendationBriefs).where(
|
|
23287
|
-
|
|
23288
|
-
|
|
23289
|
-
|
|
23469
|
+
const row = app.db.select().from(recommendationBriefs).where(and23(
|
|
23470
|
+
eq28(recommendationBriefs.projectId, project.id),
|
|
23471
|
+
eq28(recommendationBriefs.targetRef, targetRef),
|
|
23472
|
+
eq28(recommendationBriefs.promptVersion, result.promptVersion)
|
|
23290
23473
|
)).get();
|
|
23291
23474
|
if (!row) throw notFound("recommendationBrief", targetRef);
|
|
23292
23475
|
return reply.send(formatBriefRow(row));
|
|
23293
23476
|
});
|
|
23294
23477
|
app.get("/projects/:name/content/domain-classifications", async (request) => {
|
|
23295
23478
|
const project = resolveProject(app.db, request.params.name);
|
|
23296
|
-
const rows = app.db.select().from(domainClassifications).where(
|
|
23479
|
+
const rows = app.db.select().from(domainClassifications).where(eq28(domainClassifications.projectId, project.id)).orderBy(desc11(domainClassifications.hits)).all();
|
|
23297
23480
|
const response = {
|
|
23298
23481
|
classifications: rows.map((r) => ({
|
|
23299
23482
|
domain: r.domain,
|
|
@@ -23307,13 +23490,13 @@ async function contentRoutes(app, opts = {}) {
|
|
|
23307
23490
|
}
|
|
23308
23491
|
function lookupCachedBrief(db, projectId, targetRef, promptVersion) {
|
|
23309
23492
|
const conditions = [
|
|
23310
|
-
|
|
23311
|
-
|
|
23493
|
+
eq28(recommendationBriefs.projectId, projectId),
|
|
23494
|
+
eq28(recommendationBriefs.targetRef, targetRef)
|
|
23312
23495
|
];
|
|
23313
23496
|
if (promptVersion !== void 0) {
|
|
23314
|
-
conditions.push(
|
|
23497
|
+
conditions.push(eq28(recommendationBriefs.promptVersion, promptVersion));
|
|
23315
23498
|
}
|
|
23316
|
-
return db.select().from(recommendationBriefs).where(
|
|
23499
|
+
return db.select().from(recommendationBriefs).where(and23(...conditions)).orderBy(desc11(recommendationBriefs.generatedAt)).limit(1).get();
|
|
23317
23500
|
}
|
|
23318
23501
|
function parseLimitParam(raw) {
|
|
23319
23502
|
if (raw === void 0) return void 0;
|
|
@@ -23338,141 +23521,6 @@ function winnabilityClassRank(winnabilityClass) {
|
|
|
23338
23521
|
return winnabilityClass === WinnabilityClasses.ownable ? 0 : 1;
|
|
23339
23522
|
}
|
|
23340
23523
|
|
|
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
23524
|
// ../api-routes/src/report-renderer.ts
|
|
23477
23525
|
var COLORS = {
|
|
23478
23526
|
bg: "#09090b",
|
|
@@ -25764,6 +25812,149 @@ function renderReportHtml(report, opts = {}) {
|
|
|
25764
25812
|
</html>`;
|
|
25765
25813
|
}
|
|
25766
25814
|
|
|
25815
|
+
// ../api-routes/src/ga-ai-referral-aggregation.ts
|
|
25816
|
+
function normalizeAiTrafficClass(value) {
|
|
25817
|
+
return value === AiReferralTrafficClasses.paid ? AiReferralTrafficClasses.paid : AiReferralTrafficClasses.organic;
|
|
25818
|
+
}
|
|
25819
|
+
function emptyAiCounts() {
|
|
25820
|
+
return { sessions: 0 };
|
|
25821
|
+
}
|
|
25822
|
+
var AI_ATTRIBUTION_PREFERRED_DIMENSION = "session";
|
|
25823
|
+
function pickWinningAttributionDimension(sessionsByDimension) {
|
|
25824
|
+
let winner;
|
|
25825
|
+
let winnerSessions = -1;
|
|
25826
|
+
for (const [dimension, sessions] of sessionsByDimension) {
|
|
25827
|
+
const beatsOnCount = sessions > winnerSessions;
|
|
25828
|
+
const winsTie = sessions === winnerSessions && dimension === AI_ATTRIBUTION_PREFERRED_DIMENSION;
|
|
25829
|
+
if (beatsOnCount || winsTie) {
|
|
25830
|
+
winnerSessions = sessions;
|
|
25831
|
+
winner = dimension;
|
|
25832
|
+
}
|
|
25833
|
+
}
|
|
25834
|
+
return winner;
|
|
25835
|
+
}
|
|
25836
|
+
function resolveWinningDimensions(rows) {
|
|
25837
|
+
const groups = /* @__PURE__ */ new Map();
|
|
25838
|
+
for (const row of rows) {
|
|
25839
|
+
const key = `${row.date}\0${row.source}`;
|
|
25840
|
+
let group = groups.get(key);
|
|
25841
|
+
if (!group) {
|
|
25842
|
+
group = { date: row.date, source: row.source, byDimension: /* @__PURE__ */ new Map(), mediumSessions: /* @__PURE__ */ new Map() };
|
|
25843
|
+
groups.set(key, group);
|
|
25844
|
+
}
|
|
25845
|
+
let dim = group.byDimension.get(row.sourceDimension);
|
|
25846
|
+
if (!dim) {
|
|
25847
|
+
dim = { paidSessions: 0, organicSessions: 0 };
|
|
25848
|
+
group.byDimension.set(row.sourceDimension, dim);
|
|
25849
|
+
}
|
|
25850
|
+
const sessions = row.sessions ?? 0;
|
|
25851
|
+
if (normalizeAiTrafficClass(row.trafficClass) === AiReferralTrafficClasses.paid) {
|
|
25852
|
+
dim.paidSessions += sessions;
|
|
25853
|
+
} else {
|
|
25854
|
+
dim.organicSessions += sessions;
|
|
25855
|
+
}
|
|
25856
|
+
let mediums = group.mediumSessions.get(row.sourceDimension);
|
|
25857
|
+
if (!mediums) {
|
|
25858
|
+
mediums = /* @__PURE__ */ new Map();
|
|
25859
|
+
group.mediumSessions.set(row.sourceDimension, mediums);
|
|
25860
|
+
}
|
|
25861
|
+
mediums.set(row.medium, (mediums.get(row.medium) ?? 0) + sessions);
|
|
25862
|
+
}
|
|
25863
|
+
const winners = [];
|
|
25864
|
+
for (const group of groups.values()) {
|
|
25865
|
+
const winningDimension = pickWinningAttributionDimension(
|
|
25866
|
+
new Map([...group.byDimension].map(([d, c]) => [d, c.paidSessions + c.organicSessions]))
|
|
25867
|
+
);
|
|
25868
|
+
if (winningDimension === void 0) continue;
|
|
25869
|
+
const best = group.byDimension.get(winningDimension);
|
|
25870
|
+
let medium = "";
|
|
25871
|
+
let mediumBest = -1;
|
|
25872
|
+
for (const [candidate, sessions] of group.mediumSessions.get(winningDimension) ?? []) {
|
|
25873
|
+
if (sessions > mediumBest) {
|
|
25874
|
+
mediumBest = sessions;
|
|
25875
|
+
medium = candidate;
|
|
25876
|
+
}
|
|
25877
|
+
}
|
|
25878
|
+
winners.push({
|
|
25879
|
+
date: group.date,
|
|
25880
|
+
source: group.source,
|
|
25881
|
+
medium,
|
|
25882
|
+
paidSessions: best.paidSessions,
|
|
25883
|
+
organicSessions: best.organicSessions
|
|
25884
|
+
});
|
|
25885
|
+
}
|
|
25886
|
+
return winners;
|
|
25887
|
+
}
|
|
25888
|
+
function summarizeAiReferralCounts(rows) {
|
|
25889
|
+
const paidDeduped = emptyAiCounts();
|
|
25890
|
+
const organicDeduped = emptyAiCounts();
|
|
25891
|
+
const paidBySession = emptyAiCounts();
|
|
25892
|
+
const organicBySession = emptyAiCounts();
|
|
25893
|
+
const bySessionChannelGroup = /* @__PURE__ */ new Map();
|
|
25894
|
+
for (const winner of resolveWinningDimensions(rows)) {
|
|
25895
|
+
paidDeduped.sessions += winner.paidSessions;
|
|
25896
|
+
organicDeduped.sessions += winner.organicSessions;
|
|
25897
|
+
}
|
|
25898
|
+
for (const row of rows) {
|
|
25899
|
+
if (row.sourceDimension !== "session") continue;
|
|
25900
|
+
const sessions = row.sessions ?? 0;
|
|
25901
|
+
bySessionChannelGroup.set(
|
|
25902
|
+
row.channelGroup,
|
|
25903
|
+
(bySessionChannelGroup.get(row.channelGroup) ?? 0) + sessions
|
|
25904
|
+
);
|
|
25905
|
+
const bucket = normalizeAiTrafficClass(row.trafficClass) === AiReferralTrafficClasses.paid ? paidBySession : organicBySession;
|
|
25906
|
+
bucket.sessions += sessions;
|
|
25907
|
+
}
|
|
25908
|
+
return {
|
|
25909
|
+
paidDeduped,
|
|
25910
|
+
organicDeduped,
|
|
25911
|
+
paidBySession,
|
|
25912
|
+
organicBySession,
|
|
25913
|
+
bySessionChannelGroup,
|
|
25914
|
+
deduped: { sessions: paidDeduped.sessions + organicDeduped.sessions },
|
|
25915
|
+
bySession: { sessions: paidBySession.sessions + organicBySession.sessions }
|
|
25916
|
+
};
|
|
25917
|
+
}
|
|
25918
|
+
function buildAiReferralDailySeries(rows) {
|
|
25919
|
+
const byDate = /* @__PURE__ */ new Map();
|
|
25920
|
+
const sourceTotals = /* @__PURE__ */ new Map();
|
|
25921
|
+
let totalSessions = 0;
|
|
25922
|
+
let totalPaidSessions = 0;
|
|
25923
|
+
let totalOrganicSessions = 0;
|
|
25924
|
+
for (const winner of resolveWinningDimensions(rows)) {
|
|
25925
|
+
const sessions = winner.paidSessions + winner.organicSessions;
|
|
25926
|
+
let bySource = byDate.get(winner.date);
|
|
25927
|
+
if (!bySource) {
|
|
25928
|
+
bySource = /* @__PURE__ */ new Map();
|
|
25929
|
+
byDate.set(winner.date, bySource);
|
|
25930
|
+
}
|
|
25931
|
+
let bucket = bySource.get(winner.source);
|
|
25932
|
+
if (!bucket) {
|
|
25933
|
+
bucket = { source: winner.source, sessions: 0, paidSessions: 0, organicSessions: 0 };
|
|
25934
|
+
bySource.set(winner.source, bucket);
|
|
25935
|
+
}
|
|
25936
|
+
bucket.sessions += sessions;
|
|
25937
|
+
bucket.paidSessions += winner.paidSessions;
|
|
25938
|
+
bucket.organicSessions += winner.organicSessions;
|
|
25939
|
+
sourceTotals.set(winner.source, (sourceTotals.get(winner.source) ?? 0) + sessions);
|
|
25940
|
+
totalSessions += sessions;
|
|
25941
|
+
totalPaidSessions += winner.paidSessions;
|
|
25942
|
+
totalOrganicSessions += winner.organicSessions;
|
|
25943
|
+
}
|
|
25944
|
+
const days = [...byDate.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([date, bySource]) => {
|
|
25945
|
+
const sources2 = [...bySource.values()].sort((a, b) => b.sessions - a.sessions || a.source.localeCompare(b.source));
|
|
25946
|
+
return {
|
|
25947
|
+
date,
|
|
25948
|
+
sessions: sources2.reduce((sum, s) => sum + s.sessions, 0),
|
|
25949
|
+
paidSessions: sources2.reduce((sum, s) => sum + s.paidSessions, 0),
|
|
25950
|
+
organicSessions: sources2.reduce((sum, s) => sum + s.organicSessions, 0),
|
|
25951
|
+
bySource: sources2
|
|
25952
|
+
};
|
|
25953
|
+
});
|
|
25954
|
+
const sources = [...sourceTotals.entries()].sort(([aSource, aSessions], [bSource, bSessions]) => bSessions - aSessions || aSource.localeCompare(bSource)).map(([source]) => source);
|
|
25955
|
+
return { days, sources, totalSessions, totalPaidSessions, totalOrganicSessions };
|
|
25956
|
+
}
|
|
25957
|
+
|
|
25767
25958
|
// ../api-routes/src/report.ts
|
|
25768
25959
|
var TOP_QUERIES_LIMIT = 20;
|
|
25769
25960
|
var TOP_LANDING_PAGES_LIMIT = 20;
|
|
@@ -25829,8 +26020,8 @@ function buildGscSection(db, projectId, projectBrandNames, canonicalDomain, trac
|
|
|
25829
26020
|
const rows = db.select().from(gscSearchData).where(
|
|
25830
26021
|
and24(
|
|
25831
26022
|
eq29(gscSearchData.projectId, projectId),
|
|
25832
|
-
|
|
25833
|
-
|
|
26023
|
+
gte6(gscSearchData.date, startDate),
|
|
26024
|
+
lte4(gscSearchData.date, maxDate)
|
|
25834
26025
|
)
|
|
25835
26026
|
).all();
|
|
25836
26027
|
const dailyTotals = readGscDailyTotals(db, projectId, startDate, maxDate);
|
|
@@ -25942,8 +26133,8 @@ function buildGaSection(db, projectId, windowDays2) {
|
|
|
25942
26133
|
const snapshotRows = snapshotStartDate ? db.select().from(gaTrafficSnapshots).where(
|
|
25943
26134
|
and24(
|
|
25944
26135
|
eq29(gaTrafficSnapshots.projectId, projectId),
|
|
25945
|
-
|
|
25946
|
-
|
|
26136
|
+
gte6(gaTrafficSnapshots.date, snapshotStartDate),
|
|
26137
|
+
lte4(gaTrafficSnapshots.date, snapshotMaxInWindow)
|
|
25947
26138
|
)
|
|
25948
26139
|
).all() : db.select().from(gaTrafficSnapshots).where(eq29(gaTrafficSnapshots.projectId, projectId)).all();
|
|
25949
26140
|
const totalSessions = windowSummary?.totalSessions ?? matchingFallbackSummary?.totalSessions ?? snapshotRows.reduce((s, r) => s + r.sessions, 0);
|
|
@@ -25971,8 +26162,8 @@ function buildGaSection(db, projectId, windowDays2) {
|
|
|
25971
26162
|
eq29(gaAiReferrals.sourceDimension, "session")
|
|
25972
26163
|
];
|
|
25973
26164
|
if (snapshotStartDate && snapshotMaxInWindow) {
|
|
25974
|
-
aiConditions.push(
|
|
25975
|
-
aiConditions.push(
|
|
26165
|
+
aiConditions.push(gte6(gaAiReferrals.date, snapshotStartDate));
|
|
26166
|
+
aiConditions.push(lte4(gaAiReferrals.date, snapshotMaxInWindow));
|
|
25976
26167
|
}
|
|
25977
26168
|
const aiSessionRows = db.select({
|
|
25978
26169
|
trafficClass: gaAiReferrals.trafficClass,
|
|
@@ -26077,7 +26268,7 @@ function buildAiReferrals(db, projectId, windowDays2) {
|
|
|
26077
26268
|
if (rows.length === 0) return null;
|
|
26078
26269
|
const dimSessionsByTuple = /* @__PURE__ */ new Map();
|
|
26079
26270
|
for (const r of rows) {
|
|
26080
|
-
const tupleKey = `${r.date}::${r.source}
|
|
26271
|
+
const tupleKey = `${r.date}::${r.source}`;
|
|
26081
26272
|
let dimMap = dimSessionsByTuple.get(tupleKey);
|
|
26082
26273
|
if (!dimMap) {
|
|
26083
26274
|
dimMap = /* @__PURE__ */ new Map();
|
|
@@ -26087,18 +26278,11 @@ function buildAiReferrals(db, projectId, windowDays2) {
|
|
|
26087
26278
|
}
|
|
26088
26279
|
const winningDimension = /* @__PURE__ */ new Map();
|
|
26089
26280
|
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
|
-
}
|
|
26281
|
+
const bestDim = pickWinningAttributionDimension(dimMap);
|
|
26098
26282
|
if (bestDim) winningDimension.set(tupleKey, bestDim);
|
|
26099
26283
|
}
|
|
26100
26284
|
const dedupedRows = rows.filter(
|
|
26101
|
-
(r) => winningDimension.get(`${r.date}::${r.source}
|
|
26285
|
+
(r) => winningDimension.get(`${r.date}::${r.source}`) === r.sourceDimension
|
|
26102
26286
|
);
|
|
26103
26287
|
let total = 0;
|
|
26104
26288
|
let paidSessions = 0;
|
|
@@ -26168,8 +26352,8 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26168
26352
|
and24(
|
|
26169
26353
|
eq29(crawlerEventsHourly.projectId, projectId),
|
|
26170
26354
|
eq29(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
|
|
26171
|
-
|
|
26172
|
-
exclusiveEnd ? lt6(crawlerEventsHourly.tsHour, windowEndIso) :
|
|
26355
|
+
gte6(crawlerEventsHourly.tsHour, windowStartIso),
|
|
26356
|
+
exclusiveEnd ? lt6(crawlerEventsHourly.tsHour, windowEndIso) : lte4(crawlerEventsHourly.tsHour, windowEndIso)
|
|
26173
26357
|
)
|
|
26174
26358
|
).get()?.total ?? 0
|
|
26175
26359
|
);
|
|
@@ -26178,8 +26362,8 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26178
26362
|
and24(
|
|
26179
26363
|
eq29(crawlerEventsHourly.projectId, projectId),
|
|
26180
26364
|
ne3(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
|
|
26181
|
-
|
|
26182
|
-
exclusiveEnd ? lt6(crawlerEventsHourly.tsHour, windowEndIso) :
|
|
26365
|
+
gte6(crawlerEventsHourly.tsHour, windowStartIso),
|
|
26366
|
+
exclusiveEnd ? lt6(crawlerEventsHourly.tsHour, windowEndIso) : lte4(crawlerEventsHourly.tsHour, windowEndIso)
|
|
26183
26367
|
)
|
|
26184
26368
|
).get()?.total ?? 0
|
|
26185
26369
|
);
|
|
@@ -26192,8 +26376,8 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26192
26376
|
and24(
|
|
26193
26377
|
eq29(aiReferralEventsHourly.projectId, projectId),
|
|
26194
26378
|
countableReferralCondition(),
|
|
26195
|
-
|
|
26196
|
-
exclusiveEnd ? lt6(aiReferralEventsHourly.tsHour, windowEndIso) :
|
|
26379
|
+
gte6(aiReferralEventsHourly.tsHour, windowStartIso),
|
|
26380
|
+
exclusiveEnd ? lt6(aiReferralEventsHourly.tsHour, windowEndIso) : lte4(aiReferralEventsHourly.tsHour, windowEndIso)
|
|
26197
26381
|
)
|
|
26198
26382
|
).get();
|
|
26199
26383
|
return aiReferralClassCounts(Number(row?.total ?? 0), Number(row?.paid ?? 0), Number(row?.organic ?? 0));
|
|
@@ -26202,8 +26386,8 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26202
26386
|
db.select({ total: sql10`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
|
|
26203
26387
|
and24(
|
|
26204
26388
|
eq29(aiUserFetchEventsHourly.projectId, projectId),
|
|
26205
|
-
|
|
26206
|
-
exclusiveEnd ? lt6(aiUserFetchEventsHourly.tsHour, windowEndIso) :
|
|
26389
|
+
gte6(aiUserFetchEventsHourly.tsHour, windowStartIso),
|
|
26390
|
+
exclusiveEnd ? lt6(aiUserFetchEventsHourly.tsHour, windowEndIso) : lte4(aiUserFetchEventsHourly.tsHour, windowEndIso)
|
|
26207
26391
|
)
|
|
26208
26392
|
).get()?.total ?? 0
|
|
26209
26393
|
);
|
|
@@ -26219,8 +26403,8 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26219
26403
|
and24(
|
|
26220
26404
|
eq29(aiReferralEventsHourly.projectId, projectId),
|
|
26221
26405
|
nonSubresourceReferralPathCondition(),
|
|
26222
|
-
|
|
26223
|
-
|
|
26406
|
+
gte6(aiReferralEventsHourly.tsHour, headlineStart),
|
|
26407
|
+
lte4(aiReferralEventsHourly.tsHour, headlineEnd)
|
|
26224
26408
|
)
|
|
26225
26409
|
).get()?.total ?? 0
|
|
26226
26410
|
);
|
|
@@ -26233,8 +26417,8 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26233
26417
|
}).from(crawlerEventsHourly).where(
|
|
26234
26418
|
and24(
|
|
26235
26419
|
eq29(crawlerEventsHourly.projectId, projectId),
|
|
26236
|
-
|
|
26237
|
-
|
|
26420
|
+
gte6(crawlerEventsHourly.tsHour, headlineStart),
|
|
26421
|
+
lte4(crawlerEventsHourly.tsHour, headlineEnd)
|
|
26238
26422
|
)
|
|
26239
26423
|
).groupBy(crawlerEventsHourly.operator, crawlerEventsHourly.verificationStatus).all();
|
|
26240
26424
|
const crawlerByOperatorPriorRows = db.select({
|
|
@@ -26244,7 +26428,7 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26244
26428
|
and24(
|
|
26245
26429
|
eq29(crawlerEventsHourly.projectId, projectId),
|
|
26246
26430
|
eq29(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
|
|
26247
|
-
|
|
26431
|
+
gte6(crawlerEventsHourly.tsHour, priorStart),
|
|
26248
26432
|
lt6(crawlerEventsHourly.tsHour, headlineStart)
|
|
26249
26433
|
)
|
|
26250
26434
|
).groupBy(crawlerEventsHourly.operator).all();
|
|
@@ -26255,8 +26439,8 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26255
26439
|
and24(
|
|
26256
26440
|
eq29(aiReferralEventsHourly.projectId, projectId),
|
|
26257
26441
|
countableReferralCondition(),
|
|
26258
|
-
|
|
26259
|
-
|
|
26442
|
+
gte6(aiReferralEventsHourly.tsHour, headlineStart),
|
|
26443
|
+
lte4(aiReferralEventsHourly.tsHour, headlineEnd)
|
|
26260
26444
|
)
|
|
26261
26445
|
).groupBy(aiReferralEventsHourly.operator).all();
|
|
26262
26446
|
const userFetchByOperatorRows = db.select({
|
|
@@ -26265,8 +26449,8 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26265
26449
|
}).from(aiUserFetchEventsHourly).where(
|
|
26266
26450
|
and24(
|
|
26267
26451
|
eq29(aiUserFetchEventsHourly.projectId, projectId),
|
|
26268
|
-
|
|
26269
|
-
|
|
26452
|
+
gte6(aiUserFetchEventsHourly.tsHour, headlineStart),
|
|
26453
|
+
lte4(aiUserFetchEventsHourly.tsHour, headlineEnd)
|
|
26270
26454
|
)
|
|
26271
26455
|
).groupBy(aiUserFetchEventsHourly.operator).all();
|
|
26272
26456
|
const operatorAgg = /* @__PURE__ */ new Map();
|
|
@@ -26310,8 +26494,8 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26310
26494
|
and24(
|
|
26311
26495
|
eq29(crawlerEventsHourly.projectId, projectId),
|
|
26312
26496
|
eq29(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
|
|
26313
|
-
|
|
26314
|
-
|
|
26497
|
+
gte6(crawlerEventsHourly.tsHour, headlineStart),
|
|
26498
|
+
lte4(crawlerEventsHourly.tsHour, headlineEnd)
|
|
26315
26499
|
)
|
|
26316
26500
|
).groupBy(crawlerEventsHourly.pathNormalized).orderBy(desc12(sql10`SUM(${crawlerEventsHourly.hits})`)).limit(SERVER_ACTIVITY_TOP_PATHS_LIMIT).all();
|
|
26317
26501
|
const topCrawledPaths = topPathsRows.map((r) => ({
|
|
@@ -26327,8 +26511,8 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26327
26511
|
and24(
|
|
26328
26512
|
eq29(aiReferralEventsHourly.projectId, projectId),
|
|
26329
26513
|
countableReferralCondition(),
|
|
26330
|
-
|
|
26331
|
-
|
|
26514
|
+
gte6(aiReferralEventsHourly.tsHour, headlineStart),
|
|
26515
|
+
lte4(aiReferralEventsHourly.tsHour, headlineEnd)
|
|
26332
26516
|
)
|
|
26333
26517
|
).groupBy(aiReferralEventsHourly.product).orderBy(desc12(sql10`SUM(${aiReferralEventsHourly.sessionsOrHits})`)).all();
|
|
26334
26518
|
const referralProducts = referralProductsRows.map((r) => ({
|
|
@@ -26344,8 +26528,8 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26344
26528
|
and24(
|
|
26345
26529
|
eq29(aiReferralEventsHourly.projectId, projectId),
|
|
26346
26530
|
countableReferralCondition(),
|
|
26347
|
-
|
|
26348
|
-
|
|
26531
|
+
gte6(aiReferralEventsHourly.tsHour, headlineStart),
|
|
26532
|
+
lte4(aiReferralEventsHourly.tsHour, headlineEnd)
|
|
26349
26533
|
)
|
|
26350
26534
|
).groupBy(aiReferralEventsHourly.landingPathNormalized).orderBy(desc12(sql10`SUM(${aiReferralEventsHourly.sessionsOrHits})`)).limit(SERVER_ACTIVITY_TOP_PATHS_LIMIT).all();
|
|
26351
26535
|
const topReferralLandingPaths = topReferralRows.map((r) => ({
|
|
@@ -26360,8 +26544,8 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26360
26544
|
and24(
|
|
26361
26545
|
eq29(crawlerEventsHourly.projectId, projectId),
|
|
26362
26546
|
eq29(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
|
|
26363
|
-
|
|
26364
|
-
|
|
26547
|
+
gte6(crawlerEventsHourly.tsHour, trendStart),
|
|
26548
|
+
lte4(crawlerEventsHourly.tsHour, headlineEnd)
|
|
26365
26549
|
)
|
|
26366
26550
|
).groupBy(sql10`SUBSTR(${crawlerEventsHourly.tsHour}, 1, 10)`).all();
|
|
26367
26551
|
const referralTrendRows = db.select({
|
|
@@ -26371,8 +26555,8 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26371
26555
|
and24(
|
|
26372
26556
|
eq29(aiReferralEventsHourly.projectId, projectId),
|
|
26373
26557
|
countableReferralCondition(),
|
|
26374
|
-
|
|
26375
|
-
|
|
26558
|
+
gte6(aiReferralEventsHourly.tsHour, trendStart),
|
|
26559
|
+
lte4(aiReferralEventsHourly.tsHour, headlineEnd)
|
|
26376
26560
|
)
|
|
26377
26561
|
).groupBy(sql10`SUBSTR(${aiReferralEventsHourly.tsHour}, 1, 10)`).all();
|
|
26378
26562
|
const userFetchTrendRows = db.select({
|
|
@@ -26381,8 +26565,8 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
26381
26565
|
}).from(aiUserFetchEventsHourly).where(
|
|
26382
26566
|
and24(
|
|
26383
26567
|
eq29(aiUserFetchEventsHourly.projectId, projectId),
|
|
26384
|
-
|
|
26385
|
-
|
|
26568
|
+
gte6(aiUserFetchEventsHourly.tsHour, trendStart),
|
|
26569
|
+
lte4(aiUserFetchEventsHourly.tsHour, headlineEnd)
|
|
26386
26570
|
)
|
|
26387
26571
|
).groupBy(sql10`SUBSTR(${aiUserFetchEventsHourly.tsHour}, 1, 10)`).all();
|
|
26388
26572
|
const emptyTrendEntry = () => ({ verifiedCrawlerHits: 0, userFetchHits: 0, referralArrivals: 0 });
|
|
@@ -27332,10 +27516,10 @@ async function reportRoutes(app) {
|
|
|
27332
27516
|
}
|
|
27333
27517
|
|
|
27334
27518
|
// ../api-routes/src/organic-evidence.ts
|
|
27335
|
-
import { and as and26, desc as desc13, eq as eq31, gte as
|
|
27519
|
+
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
27520
|
|
|
27337
27521
|
// ../api-routes/src/ga-measurement-analysis.ts
|
|
27338
|
-
import { and as and25, eq as eq30, gte as
|
|
27522
|
+
import { and as and25, eq as eq30, gte as gte7, lte as lte5, or as or5, sql as sql11 } from "drizzle-orm";
|
|
27339
27523
|
var UNKNOWN_LANDING_PAGE = "(not set)";
|
|
27340
27524
|
function addDays(date, offset) {
|
|
27341
27525
|
const value = /* @__PURE__ */ new Date(`${date}T00:00:00.000Z`);
|
|
@@ -27531,15 +27715,15 @@ function buildGaMeasurementAnalysis(db, projectName, options = {}) {
|
|
|
27531
27715
|
const gaAnchor = [acquisitionAnchor, leadAnchor].filter((date) => date !== null).sort().at(-1) ?? null;
|
|
27532
27716
|
const gaPeriods = gaAnchor ? buildPeriods(gaAnchor, days) : [];
|
|
27533
27717
|
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),
|
|
27718
|
+
const acquisitionRows = gaStartDate ? db.select().from(gaAcquisitionDaily).where(and25(eq30(gaAcquisitionDaily.projectId, project.id), gte7(gaAcquisitionDaily.date, gaStartDate), lte5(gaAcquisitionDaily.date, gaAnchor))).all() : [];
|
|
27719
|
+
const leadRows = gaStartDate ? db.select().from(gaLeadEventsDaily).where(and25(eq30(gaLeadEventsDaily.projectId, project.id), gte7(gaLeadEventsDaily.date, gaStartDate), lte5(gaLeadEventsDaily.date, gaAnchor))).all() : [];
|
|
27536
27720
|
const engagementAnchor = db.select({ date: sql11`max(${gaDailyTotals.date})` }).from(gaDailyTotals).where(eq30(gaDailyTotals.projectId, project.id)).get()?.date ?? null;
|
|
27537
27721
|
const engagementPeriodWindow = engagementAnchor ? buildPeriods(engagementAnchor, days) : [];
|
|
27538
27722
|
const engagementStartDate = engagementPeriodWindow[0]?.startDate;
|
|
27539
27723
|
const engagementRows = engagementStartDate ? db.select().from(gaDailyTotals).where(and25(
|
|
27540
27724
|
eq30(gaDailyTotals.projectId, project.id),
|
|
27541
|
-
|
|
27542
|
-
|
|
27725
|
+
gte7(gaDailyTotals.date, engagementStartDate),
|
|
27726
|
+
lte5(gaDailyTotals.date, engagementAnchor)
|
|
27543
27727
|
)).all() : [];
|
|
27544
27728
|
const engagementAvailableFrom = db.select({
|
|
27545
27729
|
date: sql11`min(${gaDailyTotals.date})`
|
|
@@ -27553,9 +27737,9 @@ function buildGaMeasurementAnalysis(db, projectName, options = {}) {
|
|
|
27553
27737
|
const gscAnchor = db.select({ date: sql11`max(${gscDailyTotals.date})` }).from(gscDailyTotals).where(eq30(gscDailyTotals.projectId, project.id)).get()?.date ?? null;
|
|
27554
27738
|
const gscPeriods = gscAnchor ? buildPeriods(gscAnchor, days) : [];
|
|
27555
27739
|
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),
|
|
27740
|
+
const propertyRows = gscStartDate ? db.select().from(gscDailyTotals).where(and25(eq30(gscDailyTotals.projectId, project.id), gte7(gscDailyTotals.date, gscStartDate), lte5(gscDailyTotals.date, gscAnchor))).all() : [];
|
|
27741
|
+
const queryRows = gscStartDate ? db.select().from(gscQueryDailyTotals).where(and25(eq30(gscQueryDailyTotals.projectId, project.id), gte7(gscQueryDailyTotals.date, gscStartDate), lte5(gscQueryDailyTotals.date, gscAnchor))).all() : [];
|
|
27742
|
+
const rawPageRows = gscStartDate ? db.select().from(gscSearchData).where(and25(eq30(gscSearchData.projectId, project.id), gte7(gscSearchData.date, gscStartDate), lte5(gscSearchData.date, gscAnchor))).all() : [];
|
|
27559
27743
|
const state = db.select().from(gaMeasurementSyncStates).where(eq30(gaMeasurementSyncStates.projectId, project.id)).get();
|
|
27560
27744
|
const acquisition = acquisitionRows.filter((row) => {
|
|
27561
27745
|
const landingPage = normalizeLandingPage(row.landingPageNormalized ?? row.landingPage);
|
|
@@ -27907,18 +28091,18 @@ function buildOrganicEvidence(db, projectName, periodDays) {
|
|
|
27907
28091
|
const isInWindow = (date) => inRange(date, startDate, endDate);
|
|
27908
28092
|
const gscRows = gscStartDate && gscEndDate ? db.select().from(gscDailyTotals).where(and26(
|
|
27909
28093
|
eq31(gscDailyTotals.projectId, project.id),
|
|
27910
|
-
|
|
27911
|
-
|
|
28094
|
+
gte8(gscDailyTotals.date, gscStartDate),
|
|
28095
|
+
lte6(gscDailyTotals.date, gscEndDate)
|
|
27912
28096
|
)).all() : [];
|
|
27913
28097
|
const gaRows = gaStartDate && gaEndDate ? db.select().from(gaTrafficSnapshots).where(and26(
|
|
27914
28098
|
eq31(gaTrafficSnapshots.projectId, project.id),
|
|
27915
|
-
|
|
27916
|
-
|
|
28099
|
+
gte8(gaTrafficSnapshots.date, gaStartDate),
|
|
28100
|
+
lte6(gaTrafficSnapshots.date, gaEndDate)
|
|
27917
28101
|
)).all() : [];
|
|
27918
28102
|
const nativeAcquisitionRows = nativeAcquisitionActive && nativeStartDate && nativeEndDate ? db.select().from(gaAcquisitionDaily).where(and26(
|
|
27919
28103
|
eq31(gaAcquisitionDaily.projectId, project.id),
|
|
27920
|
-
|
|
27921
|
-
|
|
28104
|
+
gte8(gaAcquisitionDaily.date, nativeStartDate),
|
|
28105
|
+
lte6(gaAcquisitionDaily.date, nativeEndDate)
|
|
27922
28106
|
)).all().filter((row) => matchesMarketingHost(row.hostName, marketingHosts)) : [];
|
|
27923
28107
|
const nativeOrganicRows = nativeAcquisitionRows.filter((row) => row.channelGroup === "Organic Search");
|
|
27924
28108
|
const nativeWindowOrganicRows = nativeOrganicRows;
|
|
@@ -27956,8 +28140,8 @@ function buildOrganicEvidence(db, projectName, periodDays) {
|
|
|
27956
28140
|
);
|
|
27957
28141
|
const namedRows = db.select().from(gscQueryDailyTotals).where(and26(
|
|
27958
28142
|
eq31(gscQueryDailyTotals.projectId, project.id),
|
|
27959
|
-
|
|
27960
|
-
|
|
28143
|
+
gte8(gscQueryDailyTotals.date, startDate),
|
|
28144
|
+
lte6(gscQueryDailyTotals.date, endDate)
|
|
27961
28145
|
)).all();
|
|
27962
28146
|
for (const row of namedRows) {
|
|
27963
28147
|
const isBrand = categorizeQueryByIntent(row.query, brandTokens) === "brand";
|
|
@@ -27983,7 +28167,7 @@ function buildOrganicEvidence(db, projectName, periodDays) {
|
|
|
27983
28167
|
totals: sumSearchRows(gscRows.filter((row) => inRange(row.date, cohort.startDate, cohort.endDate)))
|
|
27984
28168
|
}))
|
|
27985
28169
|
} : null;
|
|
27986
|
-
const pageSearchRows = db.select().from(gscSearchData).where(and26(eq31(gscSearchData.projectId, project.id),
|
|
28170
|
+
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
28171
|
const gaWindow = gaStartDate && gaEndDate ? gaRows.filter((row) => inRange(row.date, gaStartDate, gaEndDate)) : [];
|
|
27988
28172
|
const legacyGaCohorts = gaCohorts.map((cohort) => ({
|
|
27989
28173
|
...cohort,
|
|
@@ -28010,7 +28194,7 @@ function buildOrganicEvidence(db, projectName, periodDays) {
|
|
|
28010
28194
|
}))
|
|
28011
28195
|
};
|
|
28012
28196
|
}
|
|
28013
|
-
const allGaAiRows = db.select().from(gaAiReferrals).where(and26(eq31(gaAiReferrals.projectId, project.id),
|
|
28197
|
+
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
28198
|
const aiRows = gaStartDate && gaEndDate ? allGaAiRows.filter((row) => inRange(row.date, gaStartDate, gaEndDate)) : [];
|
|
28015
28199
|
const gaAiReferralSummary = allGaAiRows.length ? {
|
|
28016
28200
|
paidSessions: aiRows.filter((row) => row.trafficClass === AiReferralTrafficClasses.paid).reduce((count2, row) => count2 + row.sessions, 0),
|
|
@@ -28019,9 +28203,9 @@ function buildOrganicEvidence(db, projectName, periodDays) {
|
|
|
28019
28203
|
const serverSources = db.select().from(trafficSources).where(eq31(trafficSources.projectId, project.id)).all();
|
|
28020
28204
|
const serverStart = `${startDate}T00:00:00`;
|
|
28021
28205
|
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(),
|
|
28206
|
+
const allCrawlers = db.select().from(crawlerEventsHourly).where(and26(eq31(crawlerEventsHourly.projectId, project.id), gte8(crawlerEventsHourly.tsHour, serverStart), lte6(crawlerEventsHourly.tsHour, serverEnd))).all();
|
|
28207
|
+
const allFetches = db.select().from(aiUserFetchEventsHourly).where(and26(eq31(aiUserFetchEventsHourly.projectId, project.id), gte8(aiUserFetchEventsHourly.tsHour, serverStart), lte6(aiUserFetchEventsHourly.tsHour, serverEnd))).all();
|
|
28208
|
+
const allReferrals = db.select().from(aiReferralEventsHourly).where(and26(eq31(aiReferralEventsHourly.projectId, project.id), countableReferralCondition(), gte8(aiReferralEventsHourly.tsHour, serverStart), lte6(aiReferralEventsHourly.tsHour, serverEnd))).all();
|
|
28025
28209
|
const [serverCoverageRow] = db.all(sql12`
|
|
28026
28210
|
select
|
|
28027
28211
|
min(day) as startDate,
|
|
@@ -29015,7 +29199,7 @@ async function visibilityStatsRoutes(app) {
|
|
|
29015
29199
|
}
|
|
29016
29200
|
|
|
29017
29201
|
// ../api-routes/src/results-export.ts
|
|
29018
|
-
import { and as and29, asc as asc5, eq as eq34, gte as
|
|
29202
|
+
import { and as and29, asc as asc5, eq as eq34, gte as gte9, lte as lte7 } from "drizzle-orm";
|
|
29019
29203
|
var CSV_COLUMNS = [
|
|
29020
29204
|
"export_schema_version",
|
|
29021
29205
|
"project_id",
|
|
@@ -29155,8 +29339,8 @@ async function resultsExportRoutes(app) {
|
|
|
29155
29339
|
eq34(runs.projectId, project.id),
|
|
29156
29340
|
eq34(runs.kind, RunKinds["answer-visibility"]),
|
|
29157
29341
|
...includeProbes ? [] : [notProbeRun()],
|
|
29158
|
-
...sinceIso ? [
|
|
29159
|
-
...untilIso ? [
|
|
29342
|
+
...sinceIso ? [gte9(runs.createdAt, sinceIso)] : [],
|
|
29343
|
+
...untilIso ? [lte7(runs.createdAt, untilIso)] : []
|
|
29160
29344
|
];
|
|
29161
29345
|
const rows = app.db.select({
|
|
29162
29346
|
runId: runs.id,
|
|
@@ -43267,7 +43451,7 @@ async function googleMarketingRoutes(app, opts) {
|
|
|
43267
43451
|
|
|
43268
43452
|
// ../api-routes/src/ads.ts
|
|
43269
43453
|
import crypto35 from "crypto";
|
|
43270
|
-
import { eq as eq43, and as and35, asc as asc8, desc as desc19, gt as gt2, gte as
|
|
43454
|
+
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
43455
|
|
|
43272
43456
|
// ../api-routes/src/ads-activation.ts
|
|
43273
43457
|
import crypto33 from "crypto";
|
|
@@ -44653,7 +44837,7 @@ async function executeApprovedAdsActivation(dependencies, request) {
|
|
|
44653
44837
|
|
|
44654
44838
|
// ../api-routes/src/ads-activation-routes.ts
|
|
44655
44839
|
import crypto34 from "crypto";
|
|
44656
|
-
import { and as and34, asc as asc7, eq as eq42, gt, isNotNull, isNull as isNull4, lte as
|
|
44840
|
+
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
44841
|
var MAX_ACTIVATION_GRANT_LIFETIME_MS = 24 * 60 * 60 * 1e3;
|
|
44658
44842
|
var ACTIVATION_LEASE_MS = 5 * 6e4;
|
|
44659
44843
|
var ACTIVATION_REVOCATION_SETTLEMENT_MS = ACTIVATION_LEASE_MS;
|
|
@@ -44783,7 +44967,7 @@ function createActivationStore(app, request) {
|
|
|
44783
44967
|
isNull4(adsOperations.leaseOwner),
|
|
44784
44968
|
eq42(adsOperations.leaseOwner, input.leaseOwner),
|
|
44785
44969
|
isNull4(adsOperations.leaseExpiresAt),
|
|
44786
|
-
|
|
44970
|
+
lte8(adsOperations.leaseExpiresAt, input.now)
|
|
44787
44971
|
)
|
|
44788
44972
|
)).run();
|
|
44789
44973
|
const resumed = loadCanonicalActivation(tx, grant.id, existing.id);
|
|
@@ -45200,7 +45384,7 @@ function selectWatchdogOperations(app, nowIso, batchSize, allowLiveRevocationLea
|
|
|
45200
45384
|
const leaseAvailable = or9(
|
|
45201
45385
|
isNull4(adsOperations.leaseOwner),
|
|
45202
45386
|
isNull4(adsOperations.leaseExpiresAt),
|
|
45203
|
-
|
|
45387
|
+
lte8(adsOperations.leaseExpiresAt, nowIso)
|
|
45204
45388
|
);
|
|
45205
45389
|
const campaignHasMutationEvidence = or9(
|
|
45206
45390
|
eq42(adsOperationSteps.state, AdsOperationStepStates.executing),
|
|
@@ -45396,7 +45580,7 @@ async function sweepStaleAdsActivationsOnce(app, opts) {
|
|
|
45396
45580
|
or9(
|
|
45397
45581
|
isNull4(adsOperations.leaseOwner),
|
|
45398
45582
|
isNull4(adsOperations.leaseExpiresAt),
|
|
45399
|
-
|
|
45583
|
+
lte8(adsOperations.leaseExpiresAt, nowIso)
|
|
45400
45584
|
)
|
|
45401
45585
|
)
|
|
45402
45586
|
)
|
|
@@ -45433,7 +45617,7 @@ async function sweepStaleAdsActivationsOnce(app, opts) {
|
|
|
45433
45617
|
or9(
|
|
45434
45618
|
isNull4(adsOperations.leaseOwner),
|
|
45435
45619
|
isNull4(adsOperations.leaseExpiresAt),
|
|
45436
|
-
|
|
45620
|
+
lte8(adsOperations.leaseExpiresAt, failedAt)
|
|
45437
45621
|
)
|
|
45438
45622
|
)
|
|
45439
45623
|
)
|
|
@@ -46610,13 +46794,13 @@ function claimOperationForReconciliation(app, row, leaseOwner, now, leaseMs, pol
|
|
|
46610
46794
|
const unknownCutoff = new Date(now.getTime() - backoffMs).toISOString();
|
|
46611
46795
|
const claimableState = row.state === AdsOperationStates.pending ? and35(
|
|
46612
46796
|
eq43(adsOperations.state, AdsOperationStates.pending),
|
|
46613
|
-
|
|
46797
|
+
lte9(adsOperations.updatedAt, pendingCutoff)
|
|
46614
46798
|
) : row.state === AdsOperationStates.unknown ? and35(
|
|
46615
46799
|
eq43(adsOperations.state, AdsOperationStates.unknown),
|
|
46616
|
-
enforceBackoff ?
|
|
46800
|
+
enforceBackoff ? lte9(adsOperations.updatedAt, unknownCutoff) : void 0
|
|
46617
46801
|
) : and35(
|
|
46618
46802
|
eq43(adsOperations.state, AdsOperationStates.reconciling),
|
|
46619
|
-
or10(isNull5(adsOperations.leaseExpiresAt),
|
|
46803
|
+
or10(isNull5(adsOperations.leaseExpiresAt), lte9(adsOperations.leaseExpiresAt, nowIso))
|
|
46620
46804
|
);
|
|
46621
46805
|
const claimed = app.db.update(adsOperations).set({
|
|
46622
46806
|
state: AdsOperationStates.reconciling,
|
|
@@ -46736,7 +46920,7 @@ function quarantineExhaustedReconciliation(app, row, now, policy, context) {
|
|
|
46736
46920
|
}).where(and35(
|
|
46737
46921
|
eq43(adsOperations.id, row.id),
|
|
46738
46922
|
eq43(adsOperations.projectId, row.projectId),
|
|
46739
|
-
|
|
46923
|
+
gte10(adsOperations.reconcileAttempts, policy.maxAttempts),
|
|
46740
46924
|
inArray17(adsOperations.state, [
|
|
46741
46925
|
AdsOperationStates.pending,
|
|
46742
46926
|
AdsOperationStates.unknown,
|
|
@@ -46934,14 +47118,14 @@ async function sweepAdsOperationsOnce(app, opts, config) {
|
|
|
46934
47118
|
const backoffMs = config.policy.backoffBaseMs * 2 ** Math.max(0, reconcileAttempts - 1);
|
|
46935
47119
|
return and35(
|
|
46936
47120
|
eq43(adsOperations.reconcileAttempts, reconcileAttempts),
|
|
46937
|
-
|
|
47121
|
+
lte9(adsOperations.updatedAt, new Date(now.getTime() - backoffMs).toISOString())
|
|
46938
47122
|
);
|
|
46939
47123
|
}
|
|
46940
47124
|
);
|
|
46941
47125
|
const retryableStateWhere = or10(
|
|
46942
47126
|
and35(
|
|
46943
47127
|
eq43(adsOperations.state, AdsOperationStates.pending),
|
|
46944
|
-
|
|
47128
|
+
lte9(adsOperations.updatedAt, pendingCutoff)
|
|
46945
47129
|
),
|
|
46946
47130
|
and35(
|
|
46947
47131
|
eq43(adsOperations.state, AdsOperationStates.unknown),
|
|
@@ -46949,7 +47133,7 @@ async function sweepAdsOperationsOnce(app, opts, config) {
|
|
|
46949
47133
|
),
|
|
46950
47134
|
and35(
|
|
46951
47135
|
eq43(adsOperations.state, AdsOperationStates.reconciling),
|
|
46952
|
-
or10(isNull5(adsOperations.leaseExpiresAt),
|
|
47136
|
+
or10(isNull5(adsOperations.leaseExpiresAt), lte9(adsOperations.leaseExpiresAt, nowIso))
|
|
46953
47137
|
)
|
|
46954
47138
|
);
|
|
46955
47139
|
const staleReconcileWhere = and35(
|
|
@@ -46972,16 +47156,16 @@ async function sweepAdsOperationsOnce(app, opts, config) {
|
|
|
46972
47156
|
);
|
|
46973
47157
|
const exhaustedRows = app.db.select().from(adsOperations).where(and35(
|
|
46974
47158
|
ne5(adsOperations.kind, AdsOperationKinds.campaign_tree_activate),
|
|
46975
|
-
|
|
47159
|
+
gte10(adsOperations.reconcileAttempts, config.policy.maxAttempts),
|
|
46976
47160
|
or10(
|
|
46977
47161
|
and35(
|
|
46978
47162
|
eq43(adsOperations.state, AdsOperationStates.pending),
|
|
46979
|
-
|
|
47163
|
+
lte9(adsOperations.updatedAt, pendingCutoff)
|
|
46980
47164
|
),
|
|
46981
47165
|
eq43(adsOperations.state, AdsOperationStates.unknown),
|
|
46982
47166
|
and35(
|
|
46983
47167
|
eq43(adsOperations.state, AdsOperationStates.reconciling),
|
|
46984
|
-
or10(isNull5(adsOperations.leaseExpiresAt),
|
|
47168
|
+
or10(isNull5(adsOperations.leaseExpiresAt), lte9(adsOperations.leaseExpiresAt, nowIso))
|
|
46985
47169
|
)
|
|
46986
47170
|
),
|
|
46987
47171
|
or10(
|
|
@@ -47857,8 +48041,8 @@ async function adsRoutes(app, opts) {
|
|
|
47857
48041
|
const conditions = [eq43(adsInsightsDaily.projectId, project.id)];
|
|
47858
48042
|
if (parsedLevel) conditions.push(eq43(adsInsightsDaily.level, parsedLevel));
|
|
47859
48043
|
if (entityId) conditions.push(eq43(adsInsightsDaily.entityId, entityId));
|
|
47860
|
-
if (from) conditions.push(
|
|
47861
|
-
if (to) conditions.push(
|
|
48044
|
+
if (from) conditions.push(gte10(adsInsightsDaily.date, from));
|
|
48045
|
+
if (to) conditions.push(lte9(adsInsightsDaily.date, to));
|
|
47862
48046
|
const rows = app.db.select().from(adsInsightsDaily).where(and35(...conditions)).orderBy(asc8(adsInsightsDaily.date)).all();
|
|
47863
48047
|
const conn = app.db.select().from(adsConnections).where(eq43(adsConnections.projectId, project.id)).get();
|
|
47864
48048
|
const accountToday = adsAccountToday(conn?.timezone, (/* @__PURE__ */ new Date()).toISOString());
|
|
@@ -49238,118 +49422,6 @@ function buildSessionHistory(landingPageDays, dailyTotals) {
|
|
|
49238
49422
|
});
|
|
49239
49423
|
}
|
|
49240
49424
|
|
|
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
49425
|
// ../api-routes/src/ga.ts
|
|
49354
49426
|
function gaLog(level, action, ctx) {
|
|
49355
49427
|
const entry = { ts: (/* @__PURE__ */ new Date()).toISOString(), level, module: "GA4Routes", action, ...ctx };
|
|
@@ -49401,16 +49473,26 @@ function buildChannelBreakdown(input) {
|
|
|
49401
49473
|
}
|
|
49402
49474
|
};
|
|
49403
49475
|
}
|
|
49404
|
-
function
|
|
49405
|
-
const
|
|
49476
|
+
function keepWinningDimensionRows(rows, groupKey) {
|
|
49477
|
+
const sessionsByGroupAndDimension = /* @__PURE__ */ new Map();
|
|
49406
49478
|
for (const row of rows) {
|
|
49407
|
-
const key =
|
|
49408
|
-
|
|
49409
|
-
if (!
|
|
49410
|
-
|
|
49411
|
-
|
|
49479
|
+
const key = groupKey(row);
|
|
49480
|
+
let byDimension = sessionsByGroupAndDimension.get(key);
|
|
49481
|
+
if (!byDimension) {
|
|
49482
|
+
byDimension = /* @__PURE__ */ new Map();
|
|
49483
|
+
sessionsByGroupAndDimension.set(key, byDimension);
|
|
49484
|
+
}
|
|
49485
|
+
byDimension.set(
|
|
49486
|
+
row.sourceDimension,
|
|
49487
|
+
(byDimension.get(row.sourceDimension) ?? 0) + (row.sessions ?? 0)
|
|
49488
|
+
);
|
|
49412
49489
|
}
|
|
49413
|
-
|
|
49490
|
+
const winningDimension = /* @__PURE__ */ new Map();
|
|
49491
|
+
for (const [key, byDimension] of sessionsByGroupAndDimension) {
|
|
49492
|
+
const winner = pickWinningAttributionDimension(byDimension);
|
|
49493
|
+
if (winner) winningDimension.set(key, winner);
|
|
49494
|
+
}
|
|
49495
|
+
return rows.filter((row) => winningDimension.get(groupKey(row)) === row.sourceDimension).sort((a, b) => (b.sessions ?? 0) - (a.sessions ?? 0));
|
|
49414
49496
|
}
|
|
49415
49497
|
function persistAcquisitionMeasurement(db, input) {
|
|
49416
49498
|
const { startDate, endDate } = input.report;
|
|
@@ -50169,13 +50251,10 @@ async function ga4Routes(app, opts) {
|
|
|
50169
50251
|
channelGroup: gaAiReferrals.channelGroup,
|
|
50170
50252
|
sessions: gaAiReferrals.sessions
|
|
50171
50253
|
}).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(
|
|
50254
|
+
const aiReferrals = keepWinningDimensionRows(aiReferralRows, (r) => r.source);
|
|
50255
|
+
const aiReferralLandingPages = keepWinningDimensionRows(
|
|
50177
50256
|
aiReferralLandingPageRows,
|
|
50178
|
-
(r) => `${r.source}\0${r.
|
|
50257
|
+
(r) => `${r.source}\0${r.landingPage}`
|
|
50179
50258
|
);
|
|
50180
50259
|
const aiSummary = summarizeAiReferralCounts(aiRowsForTotals);
|
|
50181
50260
|
const socialReferrals = app.db.select({
|
|
@@ -52948,7 +53027,7 @@ import crypto43 from "crypto";
|
|
|
52948
53027
|
import { isIP } from "net";
|
|
52949
53028
|
import { isDeepStrictEqual } from "util";
|
|
52950
53029
|
import { Agent as UndiciAgent } from "undici";
|
|
52951
|
-
import { and as and44, desc as desc23, eq as eq51, gte as
|
|
53030
|
+
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
53031
|
|
|
52953
53032
|
// ../api-routes/src/cloudflare-worker-version.ts
|
|
52954
53033
|
var CURRENT_CLOUDFLARE_WORKER_VERSION = "1.0.1";
|
|
@@ -69559,7 +69638,7 @@ async function ackCloudflareQueueMessages(client, options) {
|
|
|
69559
69638
|
|
|
69560
69639
|
// ../api-routes/src/traffic-event-ingest.ts
|
|
69561
69640
|
import crypto42 from "crypto";
|
|
69562
|
-
import { and as and42, eq as eq49, gte as
|
|
69641
|
+
import { and as and42, eq as eq49, gte as gte11, lt as lt10, lte as lte10, sql as sql21 } from "drizzle-orm";
|
|
69563
69642
|
|
|
69564
69643
|
// ../api-routes/src/raw-event-sample-retention.ts
|
|
69565
69644
|
import { and as and41, eq as eq48, lt as lt9, sql as sql20 } from "drizzle-orm";
|
|
@@ -69638,7 +69717,7 @@ function writeTrafficEventBatch(opts) {
|
|
|
69638
69717
|
);
|
|
69639
69718
|
tx.delete(trafficEventReceipts).where(and42(
|
|
69640
69719
|
eq49(trafficEventReceipts.sourceId, opts.sourceId),
|
|
69641
|
-
|
|
69720
|
+
lte10(trafficEventReceipts.expiresAt, opts.receivedAt)
|
|
69642
69721
|
)).run();
|
|
69643
69722
|
const claimedEvents = [];
|
|
69644
69723
|
for (const event of opts.events) {
|
|
@@ -69838,7 +69917,7 @@ function writeTrafficEventBatch(opts) {
|
|
|
69838
69917
|
if (remaining === void 0) {
|
|
69839
69918
|
const existing = tx.select({ total: sql21`COUNT(*)` }).from(rawEventSamples).where(and42(
|
|
69840
69919
|
eq49(rawEventSamples.sourceId, opts.sourceId),
|
|
69841
|
-
|
|
69920
|
+
gte11(rawEventSamples.ts, hour.start),
|
|
69842
69921
|
lt10(rawEventSamples.ts, hour.end)
|
|
69843
69922
|
)).get();
|
|
69844
69923
|
remaining = Math.max(0, hourlySampleLimit - Number(existing?.total ?? 0));
|
|
@@ -69896,7 +69975,7 @@ function writeTrafficEventBatch(opts) {
|
|
|
69896
69975
|
}
|
|
69897
69976
|
|
|
69898
69977
|
// ../api-routes/src/traffic-sync-lease.ts
|
|
69899
|
-
import { and as and43, eq as eq50, isNull as isNull6, lte as
|
|
69978
|
+
import { and as and43, eq as eq50, isNull as isNull6, lte as lte11, or as or11 } from "drizzle-orm";
|
|
69900
69979
|
function leaseExpiresAt(now, ttlMs) {
|
|
69901
69980
|
const nowMs = Date.parse(now);
|
|
69902
69981
|
if (!Number.isFinite(nowMs)) throw new RangeError("Traffic sync lease now must be an ISO instant");
|
|
@@ -69913,7 +69992,7 @@ function tryClaimTrafficSyncLease(input) {
|
|
|
69913
69992
|
eq50(trafficSources.id, input.sourceId),
|
|
69914
69993
|
or11(
|
|
69915
69994
|
isNull6(trafficSources.syncLeaseOwner),
|
|
69916
|
-
|
|
69995
|
+
lte11(trafficSources.syncLeaseExpiresAt, input.now),
|
|
69917
69996
|
eq50(trafficSources.syncLeaseOwner, input.owner)
|
|
69918
69997
|
)
|
|
69919
69998
|
)).run();
|
|
@@ -70409,29 +70488,29 @@ async function runBackfillTask(options) {
|
|
|
70409
70488
|
tx.delete(crawlerEventsHourly).where(
|
|
70410
70489
|
and44(
|
|
70411
70490
|
eq51(crawlerEventsHourly.sourceId, sourceRow2.id),
|
|
70412
|
-
|
|
70413
|
-
|
|
70491
|
+
gte12(crawlerEventsHourly.tsHour, windowStartIso),
|
|
70492
|
+
lte12(crawlerEventsHourly.tsHour, windowEndIso)
|
|
70414
70493
|
)
|
|
70415
70494
|
).run();
|
|
70416
70495
|
tx.delete(aiUserFetchEventsHourly).where(
|
|
70417
70496
|
and44(
|
|
70418
70497
|
eq51(aiUserFetchEventsHourly.sourceId, sourceRow2.id),
|
|
70419
|
-
|
|
70420
|
-
|
|
70498
|
+
gte12(aiUserFetchEventsHourly.tsHour, windowStartIso),
|
|
70499
|
+
lte12(aiUserFetchEventsHourly.tsHour, windowEndIso)
|
|
70421
70500
|
)
|
|
70422
70501
|
).run();
|
|
70423
70502
|
tx.delete(aiReferralEventsHourly).where(
|
|
70424
70503
|
and44(
|
|
70425
70504
|
eq51(aiReferralEventsHourly.sourceId, sourceRow2.id),
|
|
70426
|
-
|
|
70427
|
-
|
|
70505
|
+
gte12(aiReferralEventsHourly.tsHour, windowStartIso),
|
|
70506
|
+
lte12(aiReferralEventsHourly.tsHour, windowEndIso)
|
|
70428
70507
|
)
|
|
70429
70508
|
).run();
|
|
70430
70509
|
tx.delete(rawEventSamples).where(
|
|
70431
70510
|
and44(
|
|
70432
70511
|
eq51(rawEventSamples.sourceId, sourceRow2.id),
|
|
70433
|
-
|
|
70434
|
-
|
|
70512
|
+
gte12(rawEventSamples.ts, windowStartIso),
|
|
70513
|
+
lte12(rawEventSamples.ts, windowEndIso)
|
|
70435
70514
|
)
|
|
70436
70515
|
).run();
|
|
70437
70516
|
for (const bucket of report.crawlerEventsHourly) {
|
|
@@ -72595,7 +72674,7 @@ async function trafficRoutes(app, opts) {
|
|
|
72595
72674
|
}).from(crawlerEventsHourly).where(
|
|
72596
72675
|
and44(
|
|
72597
72676
|
eq51(crawlerEventsHourly.sourceId, row.id),
|
|
72598
|
-
|
|
72677
|
+
gte12(crawlerEventsHourly.tsHour, since)
|
|
72599
72678
|
)
|
|
72600
72679
|
).groupBy(crawlerEventsHourly.pathNormalized).all();
|
|
72601
72680
|
const crawlerSegments = segmentCrawlerHits(
|
|
@@ -72605,7 +72684,7 @@ async function trafficRoutes(app, opts) {
|
|
|
72605
72684
|
const aiUserFetchTotals = app.db.select({ total: sql22`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
|
|
72606
72685
|
and44(
|
|
72607
72686
|
eq51(aiUserFetchEventsHourly.sourceId, row.id),
|
|
72608
|
-
|
|
72687
|
+
gte12(aiUserFetchEventsHourly.tsHour, since)
|
|
72609
72688
|
)
|
|
72610
72689
|
).get();
|
|
72611
72690
|
const aiTotals = app.db.select({
|
|
@@ -72615,13 +72694,13 @@ async function trafficRoutes(app, opts) {
|
|
|
72615
72694
|
}).from(aiReferralEventsHourly).where(
|
|
72616
72695
|
and44(
|
|
72617
72696
|
eq51(aiReferralEventsHourly.sourceId, row.id),
|
|
72618
|
-
|
|
72697
|
+
gte12(aiReferralEventsHourly.tsHour, since)
|
|
72619
72698
|
)
|
|
72620
72699
|
).get();
|
|
72621
72700
|
const sampleTotals = app.db.select({ total: sql22`COUNT(*)` }).from(rawEventSamples).where(
|
|
72622
72701
|
and44(
|
|
72623
72702
|
eq51(rawEventSamples.sourceId, row.id),
|
|
72624
|
-
|
|
72703
|
+
gte12(rawEventSamples.ts, since)
|
|
72625
72704
|
)
|
|
72626
72705
|
).get();
|
|
72627
72706
|
const latestRun = app.db.select().from(runs).where(
|
|
@@ -72800,8 +72879,8 @@ async function trafficRoutes(app, opts) {
|
|
|
72800
72879
|
if (kind === "all" || kind === TrafficEventKinds.crawler) {
|
|
72801
72880
|
const crawlerFilters = [
|
|
72802
72881
|
eq51(crawlerEventsHourly.projectId, project.id),
|
|
72803
|
-
|
|
72804
|
-
|
|
72882
|
+
gte12(crawlerEventsHourly.tsHour, sinceIso),
|
|
72883
|
+
lte12(crawlerEventsHourly.tsHour, untilIso)
|
|
72805
72884
|
];
|
|
72806
72885
|
if (sourceIdParam) crawlerFilters.push(eq51(crawlerEventsHourly.sourceId, sourceIdParam));
|
|
72807
72886
|
const crawlerWhere = and44(...crawlerFilters);
|
|
@@ -72875,8 +72954,8 @@ async function trafficRoutes(app, opts) {
|
|
|
72875
72954
|
if (kind === "all" || kind === TrafficEventKinds["ai-user-fetch"]) {
|
|
72876
72955
|
const userFetchFilters = [
|
|
72877
72956
|
eq51(aiUserFetchEventsHourly.projectId, project.id),
|
|
72878
|
-
|
|
72879
|
-
|
|
72957
|
+
gte12(aiUserFetchEventsHourly.tsHour, sinceIso),
|
|
72958
|
+
lte12(aiUserFetchEventsHourly.tsHour, untilIso)
|
|
72880
72959
|
];
|
|
72881
72960
|
if (sourceIdParam) userFetchFilters.push(eq51(aiUserFetchEventsHourly.sourceId, sourceIdParam));
|
|
72882
72961
|
const userFetchWhere = and44(...userFetchFilters);
|
|
@@ -72914,8 +72993,8 @@ async function trafficRoutes(app, opts) {
|
|
|
72914
72993
|
if (kind === "all" || kind === TrafficEventKinds["ai-referral"]) {
|
|
72915
72994
|
const aiFilters = [
|
|
72916
72995
|
eq51(aiReferralEventsHourly.projectId, project.id),
|
|
72917
|
-
|
|
72918
|
-
|
|
72996
|
+
gte12(aiReferralEventsHourly.tsHour, sinceIso),
|
|
72997
|
+
lte12(aiReferralEventsHourly.tsHour, untilIso)
|
|
72919
72998
|
];
|
|
72920
72999
|
if (sourceIdParam) aiFilters.push(eq51(aiReferralEventsHourly.sourceId, sourceIdParam));
|
|
72921
73000
|
const aiWhere = and44(...aiFilters);
|
|
@@ -74803,7 +74882,7 @@ var RUNTIME_STATE_CHECKS = [
|
|
|
74803
74882
|
];
|
|
74804
74883
|
|
|
74805
74884
|
// ../api-routes/src/doctor/checks/traffic-source.ts
|
|
74806
|
-
import { and as and47, eq as eq57, gte as
|
|
74885
|
+
import { and as and47, eq as eq57, gte as gte13, inArray as inArray19, ne as ne7, sql as sql23 } from "drizzle-orm";
|
|
74807
74886
|
var RECENT_DATA_WARN_DAYS = 7;
|
|
74808
74887
|
var RECENT_DATA_FAIL_DAYS = 30;
|
|
74809
74888
|
function isCloudflareDirectPush(source) {
|
|
@@ -74952,7 +75031,7 @@ var recentDataCheck = {
|
|
|
74952
75031
|
and47(
|
|
74953
75032
|
eq57(crawlerEventsHourly.projectId, ctx.project.id),
|
|
74954
75033
|
inArray19(crawlerEventsHourly.sourceId, activeSourceIds),
|
|
74955
|
-
|
|
75034
|
+
gte13(crawlerEventsHourly.tsHour, warnCutoff)
|
|
74956
75035
|
)
|
|
74957
75036
|
).get()?.total ?? 0
|
|
74958
75037
|
);
|
|
@@ -74961,7 +75040,7 @@ var recentDataCheck = {
|
|
|
74961
75040
|
and47(
|
|
74962
75041
|
eq57(aiReferralEventsHourly.projectId, ctx.project.id),
|
|
74963
75042
|
inArray19(aiReferralEventsHourly.sourceId, activeSourceIds),
|
|
74964
|
-
|
|
75043
|
+
gte13(aiReferralEventsHourly.tsHour, warnCutoff)
|
|
74965
75044
|
)
|
|
74966
75045
|
).get()?.total ?? 0
|
|
74967
75046
|
);
|
|
@@ -74970,7 +75049,7 @@ var recentDataCheck = {
|
|
|
74970
75049
|
and47(
|
|
74971
75050
|
eq57(aiUserFetchEventsHourly.projectId, ctx.project.id),
|
|
74972
75051
|
inArray19(aiUserFetchEventsHourly.sourceId, activeSourceIds),
|
|
74973
|
-
|
|
75052
|
+
gte13(aiUserFetchEventsHourly.tsHour, warnCutoff)
|
|
74974
75053
|
)
|
|
74975
75054
|
).get()?.total ?? 0
|
|
74976
75055
|
);
|
|
@@ -74996,7 +75075,7 @@ var recentDataCheck = {
|
|
|
74996
75075
|
and47(
|
|
74997
75076
|
eq57(crawlerEventsHourly.projectId, ctx.project.id),
|
|
74998
75077
|
inArray19(crawlerEventsHourly.sourceId, activeSourceIds),
|
|
74999
|
-
|
|
75078
|
+
gte13(crawlerEventsHourly.tsHour, failCutoff)
|
|
75000
75079
|
)
|
|
75001
75080
|
).get()?.total ?? 0
|
|
75002
75081
|
);
|
|
@@ -75005,7 +75084,7 @@ var recentDataCheck = {
|
|
|
75005
75084
|
and47(
|
|
75006
75085
|
eq57(aiReferralEventsHourly.projectId, ctx.project.id),
|
|
75007
75086
|
inArray19(aiReferralEventsHourly.sourceId, activeSourceIds),
|
|
75008
|
-
|
|
75087
|
+
gte13(aiReferralEventsHourly.tsHour, failCutoff)
|
|
75009
75088
|
)
|
|
75010
75089
|
).get()?.total ?? 0
|
|
75011
75090
|
);
|
|
@@ -75014,7 +75093,7 @@ var recentDataCheck = {
|
|
|
75014
75093
|
and47(
|
|
75015
75094
|
eq57(aiUserFetchEventsHourly.projectId, ctx.project.id),
|
|
75016
75095
|
inArray19(aiUserFetchEventsHourly.sourceId, activeSourceIds),
|
|
75017
|
-
|
|
75096
|
+
gte13(aiUserFetchEventsHourly.tsHour, failCutoff)
|
|
75018
75097
|
)
|
|
75019
75098
|
).get()?.total ?? 0
|
|
75020
75099
|
);
|
|
@@ -75929,7 +76008,7 @@ async function doctorRoutes(app, opts) {
|
|
|
75929
76008
|
|
|
75930
76009
|
// ../api-routes/src/discovery/routes.ts
|
|
75931
76010
|
import crypto45 from "crypto";
|
|
75932
|
-
import { and as and48, desc as desc24, eq as eq58, gte as
|
|
76011
|
+
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
76012
|
var MAX_INFLIGHT_DISCOVERY_AGE_MS = 2 * 60 * 60 * 1e3;
|
|
75934
76013
|
async function discoveryRoutes(app, opts) {
|
|
75935
76014
|
app.post("/projects/:name/discover/run", async (request, reply) => {
|
|
@@ -75989,7 +76068,7 @@ async function discoveryRoutes(app, opts) {
|
|
|
75989
76068
|
DiscoverySessionStatuses.seeding,
|
|
75990
76069
|
DiscoverySessionStatuses.probing
|
|
75991
76070
|
]),
|
|
75992
|
-
|
|
76071
|
+
gte14(discoverySessions.createdAt, ageFloorIso)
|
|
75993
76072
|
)).orderBy(desc24(discoverySessions.createdAt)).get();
|
|
75994
76073
|
if (existing && existing.runId) {
|
|
75995
76074
|
return { reused: true, sessionId: existing.id, runId: existing.runId };
|
|
@@ -79333,7 +79412,7 @@ var IntelligenceService = class {
|
|
|
79333
79412
|
// Never look forward. The window is this run's own past, so
|
|
79334
79413
|
// re-analyzing a historical run compares it against its true
|
|
79335
79414
|
// predecessor rather than against sweeps that came after it.
|
|
79336
|
-
|
|
79415
|
+
lte13(runChronologyKey, currentRunRecord.finishedAt ?? currentRunRecord.createdAt),
|
|
79337
79416
|
// MEASUREMENT: only runs that actually wrote snapshots — see above.
|
|
79338
79417
|
// Index seek on idx_snapshots_run, short-circuited on the first row.
|
|
79339
79418
|
exists(
|
|
@@ -79423,8 +79502,8 @@ var IntelligenceService = class {
|
|
|
79423
79502
|
const selected = this.db.select().from(gbpLocations).where(and51(
|
|
79424
79503
|
eq62(gbpLocations.projectId, projectId),
|
|
79425
79504
|
eq62(gbpLocations.selected, true),
|
|
79426
|
-
|
|
79427
|
-
|
|
79505
|
+
gte15(gbpLocations.syncedAt, windowStart),
|
|
79506
|
+
lte13(gbpLocations.syncedAt, windowEnd)
|
|
79428
79507
|
)).all();
|
|
79429
79508
|
if (selected.length === 0) {
|
|
79430
79509
|
log.info("gbp-intelligence.skip", { runId, reason: "no locations synced during run" });
|