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