@ainyc/canonry 4.112.6 → 4.113.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/assets/BacklinksPage-AYTE7he1.js +1 -0
- package/assets/assets/{ChartPrimitives-CFWAHPcS.js → ChartPrimitives-J0xH87kk.js} +1 -1
- package/assets/assets/ProjectPage-BcqfsS5X.js +7 -0
- package/assets/assets/{RunRow-Qyzm30FW.js → RunRow-Duz6GoZ0.js} +1 -1
- package/assets/assets/RunsPage-DpocjSZ-.js +1 -0
- package/assets/assets/{SettingsPage-DwpJMAmo.js → SettingsPage-CboDfSRx.js} +1 -1
- package/assets/assets/TrafficPage-B5c8opWF.js +1 -0
- package/assets/assets/TrafficSourceDetailPage-D9JPwzH-.js +1 -0
- package/assets/assets/{arrow-left-uUn3V6mX.js → arrow-left-DMukIffh.js} +1 -1
- package/assets/assets/{extract-error-message-DnaGve8f.js → extract-error-message-CVln-Uf_.js} +1 -1
- package/assets/assets/{index-Du2NS1zP.js → index-DNoISJxr.js} +53 -53
- package/assets/assets/{trash-2-Cn2KSurM.js → trash-2-BbhOWhnf.js} +1 -1
- package/assets/index.html +1 -1
- package/dist/{chunk-FVELOZTK.js → chunk-B3B3HJPH.js} +3 -3
- package/dist/{chunk-D5PEINWZ.js → chunk-XYSEBOHP.js} +221 -183
- package/dist/cli.js +3 -3
- package/dist/index.js +3 -3
- package/dist/{intelligence-service-ZPY7NIKR.js → intelligence-service-RRWOGVVE.js} +1 -1
- package/dist/mcp.js +1 -1
- package/package.json +7 -7
- package/assets/assets/BacklinksPage-D71EWLVy.js +0 -1
- package/assets/assets/ProjectPage-zNZMtXRD.js +0 -7
- package/assets/assets/RunsPage-BmwjeZUx.js +0 -1
- package/assets/assets/TrafficPage-DQERHZoJ.js +0 -1
- package/assets/assets/TrafficSourceDetailPage-C-5sFG6L.js +0 -1
- /package/dist/{chunk-K2XOEBSH.js → chunk-RMTNF2ES.js} +0 -0
|
@@ -274,7 +274,7 @@ import {
|
|
|
274
274
|
} from "./chunk-DBZLOLYT.js";
|
|
275
275
|
|
|
276
276
|
// src/intelligence-service.ts
|
|
277
|
-
import { eq as eq38, desc as desc18, asc as asc6, and as
|
|
277
|
+
import { eq as eq38, desc as desc18, asc as asc6, and as and29, ne as ne5, or as or6, inArray as inArray14, gte as gte7, lte as lte4 } from "drizzle-orm";
|
|
278
278
|
|
|
279
279
|
// ../db/src/client.ts
|
|
280
280
|
import { mkdirSync } from "fs";
|
|
@@ -6291,7 +6291,7 @@ function aliasArraysEqual(a, b) {
|
|
|
6291
6291
|
|
|
6292
6292
|
// ../api-routes/src/queries.ts
|
|
6293
6293
|
import crypto5 from "crypto";
|
|
6294
|
-
import { eq as eq4, inArray, sql as sql4 } from "drizzle-orm";
|
|
6294
|
+
import { and, eq as eq4, inArray, sql as sql4 } from "drizzle-orm";
|
|
6295
6295
|
function preserveSnapshotQueryText(tx, projectId, queryIds) {
|
|
6296
6296
|
const candidates = queryIds && queryIds.length > 0 ? tx.select({ id: queries.id, text: queries.query }).from(queries).where(inArray(queries.id, queryIds)).all() : tx.select({ id: queries.id, text: queries.query }).from(queries).where(eq4(queries.projectId, projectId)).all();
|
|
6297
6297
|
for (const q of candidates) {
|
|
@@ -6391,6 +6391,26 @@ async function queryRoutes(app, opts) {
|
|
|
6391
6391
|
const rows = app.db.select().from(queries).where(eq4(queries.projectId, project.id)).all();
|
|
6392
6392
|
return reply.send(rows.map((r) => ({ id: r.id, query: r.query, createdAt: r.createdAt })));
|
|
6393
6393
|
});
|
|
6394
|
+
app.delete("/projects/:name/queries/:id", async (request, reply) => {
|
|
6395
|
+
const project = resolveProject(app.db, request.params.name);
|
|
6396
|
+
const query = app.db.select().from(queries).where(and(eq4(queries.projectId, project.id), eq4(queries.id, request.params.id))).get();
|
|
6397
|
+
if (!query) {
|
|
6398
|
+
throw notFound("Query", request.params.id);
|
|
6399
|
+
}
|
|
6400
|
+
app.db.transaction((tx) => {
|
|
6401
|
+
preserveSnapshotQueryText(tx, project.id, [query.id]);
|
|
6402
|
+
tx.delete(queries).where(eq4(queries.id, query.id)).run();
|
|
6403
|
+
writeAuditLog(tx, auditFromRequest(request, {
|
|
6404
|
+
projectId: project.id,
|
|
6405
|
+
actor: "api",
|
|
6406
|
+
action: "queries.deleted",
|
|
6407
|
+
entityType: "query",
|
|
6408
|
+
entityId: query.id,
|
|
6409
|
+
diff: { deleted: [query.query] }
|
|
6410
|
+
}));
|
|
6411
|
+
});
|
|
6412
|
+
return reply.status(204).send();
|
|
6413
|
+
});
|
|
6394
6414
|
app.post("/projects/:name/queries", async (request, reply) => {
|
|
6395
6415
|
const project = resolveProject(app.db, request.params.name);
|
|
6396
6416
|
const body = request.body;
|
|
@@ -6730,12 +6750,12 @@ function parseCompetitorBatch(value) {
|
|
|
6730
6750
|
|
|
6731
6751
|
// ../api-routes/src/runs.ts
|
|
6732
6752
|
import crypto8 from "crypto";
|
|
6733
|
-
import { and as
|
|
6753
|
+
import { and as and3, eq as eq7, asc, desc, or as or2, sql as sql5 } from "drizzle-orm";
|
|
6734
6754
|
import { gte } from "drizzle-orm";
|
|
6735
6755
|
|
|
6736
6756
|
// ../api-routes/src/run-queue.ts
|
|
6737
6757
|
import crypto7 from "crypto";
|
|
6738
|
-
import { and, eq as eq6, or } from "drizzle-orm";
|
|
6758
|
+
import { and as and2, eq as eq6, or } from "drizzle-orm";
|
|
6739
6759
|
function queueRunIfProjectIdle(db, params) {
|
|
6740
6760
|
const createdAt = params.createdAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
6741
6761
|
const kind = params.kind ?? "answer-visibility";
|
|
@@ -6743,7 +6763,7 @@ function queueRunIfProjectIdle(db, params) {
|
|
|
6743
6763
|
const runId = crypto7.randomUUID();
|
|
6744
6764
|
return db.transaction((tx) => {
|
|
6745
6765
|
const activeRun = tx.select().from(runs).where(
|
|
6746
|
-
|
|
6766
|
+
and2(
|
|
6747
6767
|
eq6(runs.projectId, params.projectId),
|
|
6748
6768
|
or(eq6(runs.status, "queued"), eq6(runs.status, "running"))
|
|
6749
6769
|
)
|
|
@@ -6826,7 +6846,7 @@ async function runRoutes(app, opts) {
|
|
|
6826
6846
|
throw validationError("No locations configured for this project");
|
|
6827
6847
|
}
|
|
6828
6848
|
const result = app.db.transaction((tx) => {
|
|
6829
|
-
const activeRun = tx.select({ id: runs.id }).from(runs).where(
|
|
6849
|
+
const activeRun = tx.select({ id: runs.id }).from(runs).where(and3(
|
|
6830
6850
|
eq7(runs.projectId, project.id),
|
|
6831
6851
|
or2(eq7(runs.status, "queued"), eq7(runs.status, "running"))
|
|
6832
6852
|
)).get();
|
|
@@ -6899,15 +6919,15 @@ async function runRoutes(app, opts) {
|
|
|
6899
6919
|
const parsedLimit = parseInt(request.query.limit ?? "", 10);
|
|
6900
6920
|
const limit = Number.isNaN(parsedLimit) || parsedLimit <= 0 ? void 0 : parsedLimit;
|
|
6901
6921
|
const kind = parseListKind(request.query.kind);
|
|
6902
|
-
const where = kind ?
|
|
6922
|
+
const where = kind ? and3(eq7(runs.projectId, project.id), eq7(runs.kind, kind)) : eq7(runs.projectId, project.id);
|
|
6903
6923
|
const rows = limit == null ? app.db.select().from(runs).where(where).orderBy(asc(runs.createdAt)).all() : app.db.select().from(runs).where(where).orderBy(desc(runs.createdAt)).limit(limit).all().reverse();
|
|
6904
6924
|
return reply.send(rows.map(formatRun));
|
|
6905
6925
|
});
|
|
6906
6926
|
app.get("/projects/:name/runs/latest", async (request, reply) => {
|
|
6907
6927
|
const project = resolveProject(app.db, request.params.name);
|
|
6908
|
-
const countRow = app.db.select({ count: sql5`count(*)` }).from(runs).where(
|
|
6928
|
+
const countRow = app.db.select({ count: sql5`count(*)` }).from(runs).where(and3(eq7(runs.projectId, project.id), notProbeRun())).get();
|
|
6909
6929
|
const totalRuns = countRow?.count ?? 0;
|
|
6910
|
-
const latestRun = app.db.select().from(runs).where(
|
|
6930
|
+
const latestRun = app.db.select().from(runs).where(and3(eq7(runs.projectId, project.id), notProbeRun())).orderBy(desc(runs.createdAt), desc(runs.id)).limit(1).get();
|
|
6911
6931
|
if (!latestRun) {
|
|
6912
6932
|
return reply.send({ totalRuns: 0, run: null });
|
|
6913
6933
|
}
|
|
@@ -6926,7 +6946,7 @@ async function runRoutes(app, opts) {
|
|
|
6926
6946
|
if (kind) filters.push(eq7(runs.kind, kind));
|
|
6927
6947
|
const scopedProjectId = request.apiKey?.projectId;
|
|
6928
6948
|
if (scopedProjectId) filters.push(eq7(runs.projectId, scopedProjectId));
|
|
6929
|
-
const rows = app.db.select().from(runs).where(
|
|
6949
|
+
const rows = app.db.select().from(runs).where(and3(...filters)).orderBy(desc(runs.createdAt), desc(runs.id)).limit(limit).all();
|
|
6930
6950
|
return reply.send(rows.map(formatRun));
|
|
6931
6951
|
});
|
|
6932
6952
|
app.post("/runs", async (request, reply) => {
|
|
@@ -7137,7 +7157,7 @@ function loadRunDetail(app, run) {
|
|
|
7137
7157
|
|
|
7138
7158
|
// ../api-routes/src/apply.ts
|
|
7139
7159
|
import crypto10 from "crypto";
|
|
7140
|
-
import { and as
|
|
7160
|
+
import { and as and4, eq as eq8 } from "drizzle-orm";
|
|
7141
7161
|
|
|
7142
7162
|
// ../api-routes/src/schedule-utils.ts
|
|
7143
7163
|
import { CronExpressionParser } from "cron-parser";
|
|
@@ -7580,7 +7600,7 @@ async function applyRoutes(app, opts) {
|
|
|
7580
7600
|
});
|
|
7581
7601
|
const AV_KIND = SchedulableRunKinds["answer-visibility"];
|
|
7582
7602
|
if (resolvedSchedule) {
|
|
7583
|
-
const existingSched = tx.select().from(schedules).where(
|
|
7603
|
+
const existingSched = tx.select().from(schedules).where(and4(eq8(schedules.projectId, projectId), eq8(schedules.kind, AV_KIND))).get();
|
|
7584
7604
|
if (existingSched) {
|
|
7585
7605
|
tx.update(schedules).set({
|
|
7586
7606
|
cronExpr: resolvedSchedule.cronExpr,
|
|
@@ -7606,9 +7626,9 @@ async function applyRoutes(app, opts) {
|
|
|
7606
7626
|
}
|
|
7607
7627
|
scheduleAction = "upsert";
|
|
7608
7628
|
} else if (deleteSchedule) {
|
|
7609
|
-
const existingSched = tx.select().from(schedules).where(
|
|
7629
|
+
const existingSched = tx.select().from(schedules).where(and4(eq8(schedules.projectId, projectId), eq8(schedules.kind, AV_KIND))).get();
|
|
7610
7630
|
if (existingSched) {
|
|
7611
|
-
tx.delete(schedules).where(
|
|
7631
|
+
tx.delete(schedules).where(and4(eq8(schedules.projectId, projectId), eq8(schedules.kind, AV_KIND))).run();
|
|
7612
7632
|
scheduleAction = "delete";
|
|
7613
7633
|
}
|
|
7614
7634
|
}
|
|
@@ -7692,7 +7712,7 @@ function normalizeCompetitorList2(domains) {
|
|
|
7692
7712
|
}
|
|
7693
7713
|
|
|
7694
7714
|
// ../api-routes/src/history.ts
|
|
7695
|
-
import { and as
|
|
7715
|
+
import { and as and5, eq as eq9, desc as desc2, inArray as inArray2 } from "drizzle-orm";
|
|
7696
7716
|
|
|
7697
7717
|
// ../api-routes/src/notification-redaction.ts
|
|
7698
7718
|
var REDACTED_URL = {
|
|
@@ -7750,7 +7770,7 @@ async function historyRoutes(app) {
|
|
|
7750
7770
|
const project = resolveProject(app.db, request.params.name);
|
|
7751
7771
|
const limit = parseInt(request.query.limit ?? "50", 10);
|
|
7752
7772
|
const offset = parseInt(request.query.offset ?? "0", 10);
|
|
7753
|
-
const projectRuns = app.db.select({ id: runs.id }).from(runs).where(
|
|
7773
|
+
const projectRuns = app.db.select({ id: runs.id }).from(runs).where(and5(eq9(runs.projectId, project.id), notProbeRun())).all();
|
|
7754
7774
|
if (projectRuns.length === 0) {
|
|
7755
7775
|
return reply.send({ snapshots: [], total: 0 });
|
|
7756
7776
|
}
|
|
@@ -7799,7 +7819,7 @@ async function historyRoutes(app) {
|
|
|
7799
7819
|
app.get("/projects/:name/timeline", async (request, reply) => {
|
|
7800
7820
|
const project = resolveProject(app.db, request.params.name);
|
|
7801
7821
|
const projectQueries = app.db.select().from(queries).where(eq9(queries.projectId, project.id)).all();
|
|
7802
|
-
const projectRuns = app.db.select().from(runs).where(
|
|
7822
|
+
const projectRuns = app.db.select().from(runs).where(and5(eq9(runs.projectId, project.id), notProbeRun())).orderBy(runs.createdAt).all();
|
|
7803
7823
|
if (projectRuns.length === 0 || projectQueries.length === 0) {
|
|
7804
7824
|
return reply.send([]);
|
|
7805
7825
|
}
|
|
@@ -8010,13 +8030,13 @@ function formatAuditEntry(row) {
|
|
|
8010
8030
|
}
|
|
8011
8031
|
|
|
8012
8032
|
// ../api-routes/src/analytics.ts
|
|
8013
|
-
import { and as
|
|
8033
|
+
import { and as and6, eq as eq10, desc as desc3, inArray as inArray3 } from "drizzle-orm";
|
|
8014
8034
|
async function analyticsRoutes(app) {
|
|
8015
8035
|
app.get("/projects/:name/analytics/metrics", async (request, reply) => {
|
|
8016
8036
|
const project = resolveProject(app.db, request.params.name);
|
|
8017
8037
|
const window = parseWindow(request.query.window);
|
|
8018
8038
|
const cutoff = windowCutoff(window);
|
|
8019
|
-
const projectRuns = app.db.select().from(runs).where(
|
|
8039
|
+
const projectRuns = app.db.select().from(runs).where(and6(eq10(runs.projectId, project.id), notProbeRun())).orderBy(runs.createdAt).all().filter((r) => r.status === "completed" || r.status === "partial").filter((r) => !cutoff || r.createdAt >= cutoff);
|
|
8020
8040
|
if (projectRuns.length === 0) {
|
|
8021
8041
|
return reply.send({
|
|
8022
8042
|
window,
|
|
@@ -8068,14 +8088,14 @@ async function analyticsRoutes(app) {
|
|
|
8068
8088
|
const project = resolveProject(app.db, request.params.name);
|
|
8069
8089
|
const window = parseWindow(request.query.window);
|
|
8070
8090
|
const cutoff = windowCutoff(window);
|
|
8071
|
-
const completedRuns = app.db.select().from(runs).where(
|
|
8091
|
+
const completedRuns = app.db.select().from(runs).where(and6(eq10(runs.projectId, project.id), notProbeRun())).orderBy(desc3(runs.createdAt), desc3(runs.id)).all().filter((r) => r.status === "completed" || r.status === "partial");
|
|
8072
8092
|
const latestGroup = groupRunsByCreatedAt(completedRuns)[0] ?? [];
|
|
8073
8093
|
const latestGroupRunIds = latestGroup.map((r) => r.id);
|
|
8074
8094
|
const latestRun = pickGroupRepresentative(latestGroup);
|
|
8075
8095
|
if (!latestRun) {
|
|
8076
8096
|
return reply.send({ cited: [], gap: [], uncited: [], mentionedQueries: [], mentionGap: [], notMentioned: [], runId: "", window });
|
|
8077
8097
|
}
|
|
8078
|
-
const windowRuns = app.db.select().from(runs).where(
|
|
8098
|
+
const windowRuns = app.db.select().from(runs).where(and6(eq10(runs.projectId, project.id), notProbeRun())).orderBy(runs.createdAt).all().filter((r) => r.status === "completed" || r.status === "partial").filter((r) => !cutoff || r.createdAt >= cutoff);
|
|
8079
8099
|
const windowRunIds = windowRuns.map((r) => r.id);
|
|
8080
8100
|
const runIdToCreatedAt = new Map(windowRuns.map((r) => [r.id, r.createdAt]));
|
|
8081
8101
|
const consistencyMap = /* @__PURE__ */ new Map();
|
|
@@ -8206,7 +8226,7 @@ async function analyticsRoutes(app) {
|
|
|
8206
8226
|
const mapped = surfaceClassFromCompetitorType(row.competitorType);
|
|
8207
8227
|
if (mapped) storedSurfaceClasses.set(normalizeProjectDomain(row.domain), mapped);
|
|
8208
8228
|
}
|
|
8209
|
-
const windowRuns = app.db.select().from(runs).where(
|
|
8229
|
+
const windowRuns = app.db.select().from(runs).where(and6(eq10(runs.projectId, project.id), notProbeRun())).orderBy(desc3(runs.createdAt), desc3(runs.id)).all().filter((r) => r.status === "completed" || r.status === "partial").filter((r) => !cutoff || r.createdAt >= cutoff);
|
|
8210
8230
|
if (windowRuns.length === 0) {
|
|
8211
8231
|
return reply.send({
|
|
8212
8232
|
overall: [],
|
|
@@ -8471,7 +8491,7 @@ function buildCategoryCounts(counts2) {
|
|
|
8471
8491
|
}
|
|
8472
8492
|
|
|
8473
8493
|
// ../api-routes/src/intelligence.ts
|
|
8474
|
-
import { eq as eq11, desc as desc4, and as
|
|
8494
|
+
import { eq as eq11, desc as desc4, and as and7, inArray as inArray4, like } from "drizzle-orm";
|
|
8475
8495
|
var SEVERITY_RANK = { low: 0, medium: 1, high: 2, critical: 3 };
|
|
8476
8496
|
function severitiesAtOrAbove(min) {
|
|
8477
8497
|
const floor = SEVERITY_RANK[min];
|
|
@@ -8611,7 +8631,7 @@ async function intelligenceRoutes(app) {
|
|
|
8611
8631
|
}
|
|
8612
8632
|
limit = parsed;
|
|
8613
8633
|
}
|
|
8614
|
-
const rows = app.db.select().from(insights).where(conditions.length === 1 ? conditions[0] :
|
|
8634
|
+
const rows = app.db.select().from(insights).where(conditions.length === 1 ? conditions[0] : and7(...conditions)).orderBy(desc4(insights.createdAt)).all();
|
|
8615
8635
|
const showDismissed = request.query.dismissed === "true";
|
|
8616
8636
|
let result = rows.filter((r) => showDismissed || !r.dismissed).map(mapInsightRow);
|
|
8617
8637
|
if (limit !== void 0) result = result.slice(0, limit);
|
|
@@ -8636,7 +8656,7 @@ async function intelligenceRoutes(app) {
|
|
|
8636
8656
|
});
|
|
8637
8657
|
app.get("/projects/:name/health/latest", async (request, reply) => {
|
|
8638
8658
|
const project = resolveProject(app.db, request.params.name);
|
|
8639
|
-
const projectVisRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(
|
|
8659
|
+
const projectVisRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(and7(
|
|
8640
8660
|
eq11(runs.projectId, project.id),
|
|
8641
8661
|
eq11(runs.kind, RunKinds["answer-visibility"]),
|
|
8642
8662
|
inArray4(runs.status, [RunStatuses.completed, RunStatuses.partial]),
|
|
@@ -8647,7 +8667,7 @@ async function intelligenceRoutes(app) {
|
|
|
8647
8667
|
const latestGroup = groupRunsByCreatedAt(projectVisRuns)[0] ?? [];
|
|
8648
8668
|
const latestGroupRunIds = latestGroup.map((r) => r.id);
|
|
8649
8669
|
if (latestGroupRunIds.length > 0) {
|
|
8650
|
-
const groupRows = app.db.select().from(healthSnapshots).where(
|
|
8670
|
+
const groupRows = app.db.select().from(healthSnapshots).where(and7(
|
|
8651
8671
|
eq11(healthSnapshots.projectId, project.id),
|
|
8652
8672
|
inArray4(healthSnapshots.runId, latestGroupRunIds)
|
|
8653
8673
|
)).all();
|
|
@@ -8671,14 +8691,14 @@ async function intelligenceRoutes(app) {
|
|
|
8671
8691
|
}
|
|
8672
8692
|
|
|
8673
8693
|
// ../api-routes/src/report.ts
|
|
8674
|
-
import { and as
|
|
8694
|
+
import { and as and11, desc as desc7, eq as eq15, gte as gte2, inArray as inArray6, lt, lte, ne as ne2, or as or3, sql as sql7 } from "drizzle-orm";
|
|
8675
8695
|
|
|
8676
8696
|
// ../api-routes/src/content.ts
|
|
8677
8697
|
import crypto11 from "crypto";
|
|
8678
|
-
import { and as
|
|
8698
|
+
import { and as and9, desc as desc6, eq as eq13 } from "drizzle-orm";
|
|
8679
8699
|
|
|
8680
8700
|
// ../api-routes/src/content-data.ts
|
|
8681
|
-
import { and as
|
|
8701
|
+
import { and as and8, eq as eq12, desc as desc5, inArray as inArray5 } from "drizzle-orm";
|
|
8682
8702
|
var RECENT_RUNS_WINDOW = 5;
|
|
8683
8703
|
function loadOrchestratorInput(db, project, locationFilter = void 0) {
|
|
8684
8704
|
const projectId = project.id;
|
|
@@ -8808,7 +8828,7 @@ function listCompetitorDomains(db, projectId) {
|
|
|
8808
8828
|
}
|
|
8809
8829
|
function listRecentAnswerVisibilityRunIds(db, projectId, limit, locationFilter) {
|
|
8810
8830
|
const rows = db.select({ id: runs.id, location: runs.location }).from(runs).where(
|
|
8811
|
-
|
|
8831
|
+
and8(
|
|
8812
8832
|
eq12(runs.projectId, projectId),
|
|
8813
8833
|
eq12(runs.kind, RunKinds["answer-visibility"]),
|
|
8814
8834
|
// Queued/running/failed/cancelled runs may have partial or no
|
|
@@ -9179,7 +9199,7 @@ async function contentRoutes(app, opts = {}) {
|
|
|
9179
9199
|
dismissedAt: now
|
|
9180
9200
|
}
|
|
9181
9201
|
}).run();
|
|
9182
|
-
const row = app.db.select().from(contentTargetDismissals).where(
|
|
9202
|
+
const row = app.db.select().from(contentTargetDismissals).where(and9(
|
|
9183
9203
|
eq13(contentTargetDismissals.projectId, project.id),
|
|
9184
9204
|
eq13(contentTargetDismissals.targetRef, targetRef)
|
|
9185
9205
|
)).get();
|
|
@@ -9189,7 +9209,7 @@ async function contentRoutes(app, opts = {}) {
|
|
|
9189
9209
|
app.delete("/projects/:name/content/dismissals/:targetRef", async (request, reply) => {
|
|
9190
9210
|
const project = resolveProject(app.db, request.params.name);
|
|
9191
9211
|
const { targetRef } = request.params;
|
|
9192
|
-
const result = app.db.delete(contentTargetDismissals).where(
|
|
9212
|
+
const result = app.db.delete(contentTargetDismissals).where(and9(
|
|
9193
9213
|
eq13(contentTargetDismissals.projectId, project.id),
|
|
9194
9214
|
eq13(contentTargetDismissals.targetRef, targetRef)
|
|
9195
9215
|
)).run();
|
|
@@ -9200,7 +9220,7 @@ async function contentRoutes(app, opts = {}) {
|
|
|
9200
9220
|
});
|
|
9201
9221
|
app.get("/projects/:name/content/recommendations/:targetRef/analysis", async (request, reply) => {
|
|
9202
9222
|
const project = resolveProject(app.db, request.params.name);
|
|
9203
|
-
const row = app.db.select().from(recommendationExplanations).where(
|
|
9223
|
+
const row = app.db.select().from(recommendationExplanations).where(and9(
|
|
9204
9224
|
eq13(recommendationExplanations.projectId, project.id),
|
|
9205
9225
|
eq13(recommendationExplanations.targetRef, request.params.targetRef)
|
|
9206
9226
|
)).orderBy(desc6(recommendationExplanations.generatedAt)).limit(1).get();
|
|
@@ -9228,7 +9248,7 @@ async function contentRoutes(app, opts = {}) {
|
|
|
9228
9248
|
throw notFound("contentRecommendation", targetRef);
|
|
9229
9249
|
}
|
|
9230
9250
|
if (!body.forceRefresh) {
|
|
9231
|
-
const cached = app.db.select().from(recommendationExplanations).where(
|
|
9251
|
+
const cached = app.db.select().from(recommendationExplanations).where(and9(
|
|
9232
9252
|
eq13(recommendationExplanations.projectId, project.id),
|
|
9233
9253
|
eq13(recommendationExplanations.targetRef, targetRef)
|
|
9234
9254
|
)).orderBy(desc6(recommendationExplanations.generatedAt)).limit(1).get();
|
|
@@ -9267,7 +9287,7 @@ async function contentRoutes(app, opts = {}) {
|
|
|
9267
9287
|
generatedAt: now
|
|
9268
9288
|
}
|
|
9269
9289
|
}).run();
|
|
9270
|
-
const row = app.db.select().from(recommendationExplanations).where(
|
|
9290
|
+
const row = app.db.select().from(recommendationExplanations).where(and9(
|
|
9271
9291
|
eq13(recommendationExplanations.projectId, project.id),
|
|
9272
9292
|
eq13(recommendationExplanations.targetRef, targetRef),
|
|
9273
9293
|
eq13(recommendationExplanations.promptVersion, result.promptVersion)
|
|
@@ -9351,7 +9371,7 @@ async function contentRoutes(app, opts = {}) {
|
|
|
9351
9371
|
generatedAt: now
|
|
9352
9372
|
}
|
|
9353
9373
|
}).run();
|
|
9354
|
-
const row = app.db.select().from(recommendationBriefs).where(
|
|
9374
|
+
const row = app.db.select().from(recommendationBriefs).where(and9(
|
|
9355
9375
|
eq13(recommendationBriefs.projectId, project.id),
|
|
9356
9376
|
eq13(recommendationBriefs.targetRef, targetRef),
|
|
9357
9377
|
eq13(recommendationBriefs.promptVersion, result.promptVersion)
|
|
@@ -9381,7 +9401,7 @@ function lookupCachedBrief(db, projectId, targetRef, promptVersion) {
|
|
|
9381
9401
|
if (promptVersion !== void 0) {
|
|
9382
9402
|
conditions.push(eq13(recommendationBriefs.promptVersion, promptVersion));
|
|
9383
9403
|
}
|
|
9384
|
-
return db.select().from(recommendationBriefs).where(
|
|
9404
|
+
return db.select().from(recommendationBriefs).where(and9(...conditions)).orderBy(desc6(recommendationBriefs.generatedAt)).limit(1).get();
|
|
9385
9405
|
}
|
|
9386
9406
|
function parseLimitParam(raw) {
|
|
9387
9407
|
if (raw === void 0) return void 0;
|
|
@@ -9407,7 +9427,7 @@ function winnabilityClassRank(winnabilityClass) {
|
|
|
9407
9427
|
}
|
|
9408
9428
|
|
|
9409
9429
|
// ../api-routes/src/gsc-totals.ts
|
|
9410
|
-
import { and as
|
|
9430
|
+
import { and as and10, asc as asc2, eq as eq14, sql as sql6 } from "drizzle-orm";
|
|
9411
9431
|
function readGscDailyTotals(db, projectId, startDate, endDate) {
|
|
9412
9432
|
const rows = db.select({
|
|
9413
9433
|
date: gscDailyTotals.date,
|
|
@@ -9415,7 +9435,7 @@ function readGscDailyTotals(db, projectId, startDate, endDate) {
|
|
|
9415
9435
|
impressions: gscDailyTotals.impressions,
|
|
9416
9436
|
position: gscDailyTotals.position
|
|
9417
9437
|
}).from(gscDailyTotals).where(
|
|
9418
|
-
|
|
9438
|
+
and10(
|
|
9419
9439
|
eq14(gscDailyTotals.projectId, projectId),
|
|
9420
9440
|
sql6`${gscDailyTotals.date} >= ${startDate}`,
|
|
9421
9441
|
sql6`${gscDailyTotals.date} <= ${endDate}`
|
|
@@ -11846,7 +11866,7 @@ function buildGscSection(db, projectId, projectBrandNames, canonicalDomain, trac
|
|
|
11846
11866
|
function buildGaSection(db, projectId, windowDays) {
|
|
11847
11867
|
const gaWindowKey = GA_WINDOW_SUMMARY_KEYS[windowDays];
|
|
11848
11868
|
const windowSummary = gaWindowKey ? db.select().from(gaTrafficWindowSummaries).where(
|
|
11849
|
-
|
|
11869
|
+
and11(
|
|
11850
11870
|
eq15(gaTrafficWindowSummaries.projectId, projectId),
|
|
11851
11871
|
eq15(gaTrafficWindowSummaries.windowKey, gaWindowKey)
|
|
11852
11872
|
)
|
|
@@ -12024,7 +12044,7 @@ function nonSubresourceReferralPathCondition() {
|
|
|
12024
12044
|
}
|
|
12025
12045
|
function buildServerActivity(db, projectId, windowDays) {
|
|
12026
12046
|
const sourceRows = db.select({ id: trafficSources.id }).from(trafficSources).where(
|
|
12027
|
-
|
|
12047
|
+
and11(
|
|
12028
12048
|
eq15(trafficSources.projectId, projectId),
|
|
12029
12049
|
ne2(trafficSources.status, TrafficSourceStatuses.archived)
|
|
12030
12050
|
)
|
|
@@ -12040,7 +12060,7 @@ function buildServerActivity(db, projectId, windowDays) {
|
|
|
12040
12060
|
const trendStart = new Date(trendStartMs).toISOString();
|
|
12041
12061
|
const sumVerifiedCrawlers = (windowStartIso, windowEndIso, exclusiveEnd = false) => Number(
|
|
12042
12062
|
db.select({ total: sql7`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
|
|
12043
|
-
|
|
12063
|
+
and11(
|
|
12044
12064
|
eq15(crawlerEventsHourly.projectId, projectId),
|
|
12045
12065
|
eq15(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
|
|
12046
12066
|
gte2(crawlerEventsHourly.tsHour, windowStartIso),
|
|
@@ -12050,7 +12070,7 @@ function buildServerActivity(db, projectId, windowDays) {
|
|
|
12050
12070
|
);
|
|
12051
12071
|
const sumUnverifiedCrawlers = (windowStartIso, windowEndIso, exclusiveEnd = false) => Number(
|
|
12052
12072
|
db.select({ total: sql7`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
|
|
12053
|
-
|
|
12073
|
+
and11(
|
|
12054
12074
|
eq15(crawlerEventsHourly.projectId, projectId),
|
|
12055
12075
|
ne2(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
|
|
12056
12076
|
gte2(crawlerEventsHourly.tsHour, windowStartIso),
|
|
@@ -12060,7 +12080,7 @@ function buildServerActivity(db, projectId, windowDays) {
|
|
|
12060
12080
|
);
|
|
12061
12081
|
const sumReferrals = (windowStartIso, windowEndIso, exclusiveEnd = false) => Number(
|
|
12062
12082
|
db.select({ total: sql7`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
|
|
12063
|
-
|
|
12083
|
+
and11(
|
|
12064
12084
|
eq15(aiReferralEventsHourly.projectId, projectId),
|
|
12065
12085
|
nonSubresourceReferralPathCondition(),
|
|
12066
12086
|
gte2(aiReferralEventsHourly.tsHour, windowStartIso),
|
|
@@ -12070,7 +12090,7 @@ function buildServerActivity(db, projectId, windowDays) {
|
|
|
12070
12090
|
);
|
|
12071
12091
|
const sumUserFetches = (windowStartIso, windowEndIso, exclusiveEnd = false) => Number(
|
|
12072
12092
|
db.select({ total: sql7`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
|
|
12073
|
-
|
|
12093
|
+
and11(
|
|
12074
12094
|
eq15(aiUserFetchEventsHourly.projectId, projectId),
|
|
12075
12095
|
gte2(aiUserFetchEventsHourly.tsHour, windowStartIso),
|
|
12076
12096
|
exclusiveEnd ? lt(aiUserFetchEventsHourly.tsHour, windowEndIso) : lte(aiUserFetchEventsHourly.tsHour, windowEndIso)
|
|
@@ -12090,7 +12110,7 @@ function buildServerActivity(db, projectId, windowDays) {
|
|
|
12090
12110
|
verificationStatus: crawlerEventsHourly.verificationStatus,
|
|
12091
12111
|
hits: sql7`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
|
|
12092
12112
|
}).from(crawlerEventsHourly).where(
|
|
12093
|
-
|
|
12113
|
+
and11(
|
|
12094
12114
|
eq15(crawlerEventsHourly.projectId, projectId),
|
|
12095
12115
|
gte2(crawlerEventsHourly.tsHour, headlineStart),
|
|
12096
12116
|
lte(crawlerEventsHourly.tsHour, headlineEnd)
|
|
@@ -12100,7 +12120,7 @@ function buildServerActivity(db, projectId, windowDays) {
|
|
|
12100
12120
|
operator: crawlerEventsHourly.operator,
|
|
12101
12121
|
hits: sql7`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
|
|
12102
12122
|
}).from(crawlerEventsHourly).where(
|
|
12103
|
-
|
|
12123
|
+
and11(
|
|
12104
12124
|
eq15(crawlerEventsHourly.projectId, projectId),
|
|
12105
12125
|
eq15(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
|
|
12106
12126
|
gte2(crawlerEventsHourly.tsHour, priorStart),
|
|
@@ -12111,7 +12131,7 @@ function buildServerActivity(db, projectId, windowDays) {
|
|
|
12111
12131
|
operator: aiReferralEventsHourly.operator,
|
|
12112
12132
|
hits: sql7`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`
|
|
12113
12133
|
}).from(aiReferralEventsHourly).where(
|
|
12114
|
-
|
|
12134
|
+
and11(
|
|
12115
12135
|
eq15(aiReferralEventsHourly.projectId, projectId),
|
|
12116
12136
|
nonSubresourceReferralPathCondition(),
|
|
12117
12137
|
gte2(aiReferralEventsHourly.tsHour, headlineStart),
|
|
@@ -12122,7 +12142,7 @@ function buildServerActivity(db, projectId, windowDays) {
|
|
|
12122
12142
|
operator: aiUserFetchEventsHourly.operator,
|
|
12123
12143
|
hits: sql7`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)`
|
|
12124
12144
|
}).from(aiUserFetchEventsHourly).where(
|
|
12125
|
-
|
|
12145
|
+
and11(
|
|
12126
12146
|
eq15(aiUserFetchEventsHourly.projectId, projectId),
|
|
12127
12147
|
gte2(aiUserFetchEventsHourly.tsHour, headlineStart),
|
|
12128
12148
|
lte(aiUserFetchEventsHourly.tsHour, headlineEnd)
|
|
@@ -12166,7 +12186,7 @@ function buildServerActivity(db, projectId, windowDays) {
|
|
|
12166
12186
|
hits: sql7`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`,
|
|
12167
12187
|
operators: sql7`COUNT(DISTINCT ${crawlerEventsHourly.operator})`
|
|
12168
12188
|
}).from(crawlerEventsHourly).where(
|
|
12169
|
-
|
|
12189
|
+
and11(
|
|
12170
12190
|
eq15(crawlerEventsHourly.projectId, projectId),
|
|
12171
12191
|
eq15(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
|
|
12172
12192
|
gte2(crawlerEventsHourly.tsHour, headlineStart),
|
|
@@ -12183,7 +12203,7 @@ function buildServerActivity(db, projectId, windowDays) {
|
|
|
12183
12203
|
arrivals: sql7`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`,
|
|
12184
12204
|
landingPaths: sql7`COUNT(DISTINCT ${aiReferralEventsHourly.landingPathNormalized})`
|
|
12185
12205
|
}).from(aiReferralEventsHourly).where(
|
|
12186
|
-
|
|
12206
|
+
and11(
|
|
12187
12207
|
eq15(aiReferralEventsHourly.projectId, projectId),
|
|
12188
12208
|
nonSubresourceReferralPathCondition(),
|
|
12189
12209
|
gte2(aiReferralEventsHourly.tsHour, headlineStart),
|
|
@@ -12200,7 +12220,7 @@ function buildServerActivity(db, projectId, windowDays) {
|
|
|
12200
12220
|
arrivals: sql7`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`,
|
|
12201
12221
|
products: sql7`COUNT(DISTINCT ${aiReferralEventsHourly.product})`
|
|
12202
12222
|
}).from(aiReferralEventsHourly).where(
|
|
12203
|
-
|
|
12223
|
+
and11(
|
|
12204
12224
|
eq15(aiReferralEventsHourly.projectId, projectId),
|
|
12205
12225
|
nonSubresourceReferralPathCondition(),
|
|
12206
12226
|
gte2(aiReferralEventsHourly.tsHour, headlineStart),
|
|
@@ -12216,7 +12236,7 @@ function buildServerActivity(db, projectId, windowDays) {
|
|
|
12216
12236
|
date: sql7`SUBSTR(${crawlerEventsHourly.tsHour}, 1, 10)`,
|
|
12217
12237
|
hits: sql7`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
|
|
12218
12238
|
}).from(crawlerEventsHourly).where(
|
|
12219
|
-
|
|
12239
|
+
and11(
|
|
12220
12240
|
eq15(crawlerEventsHourly.projectId, projectId),
|
|
12221
12241
|
eq15(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
|
|
12222
12242
|
gte2(crawlerEventsHourly.tsHour, trendStart),
|
|
@@ -12227,7 +12247,7 @@ function buildServerActivity(db, projectId, windowDays) {
|
|
|
12227
12247
|
date: sql7`SUBSTR(${aiReferralEventsHourly.tsHour}, 1, 10)`,
|
|
12228
12248
|
hits: sql7`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`
|
|
12229
12249
|
}).from(aiReferralEventsHourly).where(
|
|
12230
|
-
|
|
12250
|
+
and11(
|
|
12231
12251
|
eq15(aiReferralEventsHourly.projectId, projectId),
|
|
12232
12252
|
nonSubresourceReferralPathCondition(),
|
|
12233
12253
|
gte2(aiReferralEventsHourly.tsHour, trendStart),
|
|
@@ -12238,7 +12258,7 @@ function buildServerActivity(db, projectId, windowDays) {
|
|
|
12238
12258
|
date: sql7`SUBSTR(${aiUserFetchEventsHourly.tsHour}, 1, 10)`,
|
|
12239
12259
|
hits: sql7`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)`
|
|
12240
12260
|
}).from(aiUserFetchEventsHourly).where(
|
|
12241
|
-
|
|
12261
|
+
and11(
|
|
12242
12262
|
eq15(aiUserFetchEventsHourly.projectId, projectId),
|
|
12243
12263
|
gte2(aiUserFetchEventsHourly.tsHour, trendStart),
|
|
12244
12264
|
lte(aiUserFetchEventsHourly.tsHour, headlineEnd)
|
|
@@ -12323,7 +12343,7 @@ function buildIndexingHealth(db, projectId) {
|
|
|
12323
12343
|
return null;
|
|
12324
12344
|
}
|
|
12325
12345
|
function buildCitationsTrend(db, projectId, queryLookup, locationFilter) {
|
|
12326
|
-
const visibilityRuns = db.select().from(runs).where(
|
|
12346
|
+
const visibilityRuns = db.select().from(runs).where(and11(eq15(runs.projectId, projectId), eq15(runs.kind, RunKinds["answer-visibility"]), notProbeRun())).all().filter((r) => locationFilter === void 0 || (r.location ?? null) === locationFilter);
|
|
12327
12347
|
const totalQueries = queryLookup.byId.size;
|
|
12328
12348
|
const points = [];
|
|
12329
12349
|
for (const run of visibilityRuns) {
|
|
@@ -12371,7 +12391,7 @@ function buildCitationsTrend(db, projectId, queryLookup, locationFilter) {
|
|
|
12371
12391
|
}
|
|
12372
12392
|
function buildInsightList(db, projectId, locationFilter) {
|
|
12373
12393
|
const recentRunIds = db.select({ id: runs.id, location: runs.location }).from(runs).where(
|
|
12374
|
-
|
|
12394
|
+
and11(
|
|
12375
12395
|
eq15(runs.projectId, projectId),
|
|
12376
12396
|
eq15(runs.kind, RunKinds["answer-visibility"]),
|
|
12377
12397
|
or3(eq15(runs.status, RunStatuses.completed), eq15(runs.status, RunStatuses.partial)),
|
|
@@ -12379,7 +12399,7 @@ function buildInsightList(db, projectId, locationFilter) {
|
|
|
12379
12399
|
)
|
|
12380
12400
|
).orderBy(desc7(runs.createdAt)).all().filter((r) => locationFilter === void 0 || (r.location ?? null) === locationFilter).slice(0, INSIGHT_LOOKBACK_RUNS).map((r) => r.id);
|
|
12381
12401
|
if (recentRunIds.length === 0) return [];
|
|
12382
|
-
const rows = db.select().from(insights).where(
|
|
12402
|
+
const rows = db.select().from(insights).where(and11(eq15(insights.projectId, projectId), inArray6(insights.runId, recentRunIds))).orderBy(desc7(insights.createdAt)).all();
|
|
12383
12403
|
const severityRank = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
12384
12404
|
const flat = rows.filter((r) => !r.dismissed).map((r) => {
|
|
12385
12405
|
const recommendation = r.recommendation;
|
|
@@ -12931,7 +12951,7 @@ function buildProjectReport(db, projectName, periodDays) {
|
|
|
12931
12951
|
const project = resolveProject(db, projectName);
|
|
12932
12952
|
const queryLookup = loadQueryLookup(db, project.id);
|
|
12933
12953
|
const comparisonWindowDays = reportComparisonWindowDays(periodDays);
|
|
12934
|
-
const allRuns = db.select().from(runs).where(
|
|
12954
|
+
const allRuns = db.select().from(runs).where(and11(eq15(runs.projectId, project.id), notProbeRun())).orderBy(desc7(runs.createdAt), desc7(runs.id)).all();
|
|
12935
12955
|
const visibilityRuns = allRuns.filter((r) => r.kind === RunKinds["answer-visibility"]);
|
|
12936
12956
|
const completedVisRunGroups = groupRunsByCreatedAt(
|
|
12937
12957
|
visibilityRuns.filter((r) => r.status === RunStatuses.completed || r.status === RunStatuses.partial)
|
|
@@ -13167,7 +13187,7 @@ async function reportRoutes(app) {
|
|
|
13167
13187
|
}
|
|
13168
13188
|
|
|
13169
13189
|
// ../api-routes/src/citations.ts
|
|
13170
|
-
import { and as
|
|
13190
|
+
import { and as and12, eq as eq16, inArray as inArray7 } from "drizzle-orm";
|
|
13171
13191
|
async function citationRoutes(app) {
|
|
13172
13192
|
app.get("/projects/:name/citations/visibility", async (request, reply) => {
|
|
13173
13193
|
const project = resolveProject(app.db, request.params.name);
|
|
@@ -13176,7 +13196,7 @@ async function citationRoutes(app) {
|
|
|
13176
13196
|
if (projectQueries.length === 0) {
|
|
13177
13197
|
return reply.send(emptyCitationVisibility("no-queries"));
|
|
13178
13198
|
}
|
|
13179
|
-
const projectRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(
|
|
13199
|
+
const projectRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(and12(eq16(runs.projectId, project.id), notProbeRun())).all();
|
|
13180
13200
|
if (projectRuns.length === 0) {
|
|
13181
13201
|
return reply.send(emptyCitationVisibility("no-runs-yet"));
|
|
13182
13202
|
}
|
|
@@ -13332,7 +13352,7 @@ function normalizeDomain2(domain) {
|
|
|
13332
13352
|
}
|
|
13333
13353
|
|
|
13334
13354
|
// ../api-routes/src/visibility-stats.ts
|
|
13335
|
-
import { and as
|
|
13355
|
+
import { and as and13, desc as desc8, eq as eq17, inArray as inArray8 } from "drizzle-orm";
|
|
13336
13356
|
function round42(value) {
|
|
13337
13357
|
return Math.round(value * 1e4) / 1e4;
|
|
13338
13358
|
}
|
|
@@ -13484,7 +13504,7 @@ async function visibilityStatsRoutes(app) {
|
|
|
13484
13504
|
lastRuns = n;
|
|
13485
13505
|
}
|
|
13486
13506
|
const projectQueries = app.db.select({ id: queries.id, query: queries.query }).from(queries).where(eq17(queries.projectId, project.id)).all();
|
|
13487
|
-
let projectRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt, status: runs.status }).from(runs).where(
|
|
13507
|
+
let projectRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt, status: runs.status }).from(runs).where(and13(eq17(runs.projectId, project.id), eq17(runs.kind, RunKinds["answer-visibility"]), notProbeRun())).orderBy(desc8(runs.createdAt)).all().filter((r) => r.status === RunStatuses.completed || r.status === RunStatuses.partial);
|
|
13488
13508
|
if (sinceMs !== null) projectRuns = projectRuns.filter((r) => Date.parse(r.createdAt) >= sinceMs);
|
|
13489
13509
|
if (untilMs !== null) projectRuns = projectRuns.filter((r) => Date.parse(r.createdAt) <= untilMs);
|
|
13490
13510
|
if (lastRuns !== null) projectRuns = projectRuns.slice(0, lastRuns);
|
|
@@ -13554,7 +13574,7 @@ async function visibilityStatsRoutes(app) {
|
|
|
13554
13574
|
}
|
|
13555
13575
|
|
|
13556
13576
|
// ../api-routes/src/composites.ts
|
|
13557
|
-
import { eq as eq18, and as
|
|
13577
|
+
import { eq as eq18, and as and14, desc as desc9, sql as sql8, like as like2, or as or4, inArray as inArray9 } from "drizzle-orm";
|
|
13558
13578
|
var TOP_INSIGHT_LIMIT = 5;
|
|
13559
13579
|
var SEARCH_HIT_HARD_LIMIT = 50;
|
|
13560
13580
|
var SEARCH_SNIPPET_RADIUS = 80;
|
|
@@ -13572,7 +13592,7 @@ async function compositeRoutes(app) {
|
|
|
13572
13592
|
const project = resolveProject(app.db, request.params.name);
|
|
13573
13593
|
const filterLocation = (request.query.location ?? "").trim() || null;
|
|
13574
13594
|
const sinceIso = parseSinceFilter(request.query.since);
|
|
13575
|
-
const allRunsRaw = app.db.select().from(runs).where(
|
|
13595
|
+
const allRunsRaw = app.db.select().from(runs).where(and14(eq18(runs.projectId, project.id), notProbeRun())).orderBy(desc9(runs.createdAt), desc9(runs.id)).all();
|
|
13576
13596
|
const allRuns = allRunsRaw.filter((r) => runMatchesFilters(r, filterLocation, sinceIso));
|
|
13577
13597
|
const totalRuns = allRuns.length;
|
|
13578
13598
|
const visibilityRuns = allRuns.filter((r) => r.kind === RunKinds["answer-visibility"]);
|
|
@@ -13728,7 +13748,7 @@ async function compositeRoutes(app) {
|
|
|
13728
13748
|
rawResponse: querySnapshots.rawResponse,
|
|
13729
13749
|
createdAt: querySnapshots.createdAt
|
|
13730
13750
|
}).from(querySnapshots).innerJoin(queries, eq18(querySnapshots.queryId, queries.id)).where(
|
|
13731
|
-
|
|
13751
|
+
and14(
|
|
13732
13752
|
eq18(queries.projectId, project.id),
|
|
13733
13753
|
or4(
|
|
13734
13754
|
sql8`${querySnapshots.answerText} LIKE ${pattern} ESCAPE '\\'`,
|
|
@@ -13739,7 +13759,7 @@ async function compositeRoutes(app) {
|
|
|
13739
13759
|
)
|
|
13740
13760
|
).orderBy(desc9(querySnapshots.createdAt)).limit(limit + 1).all());
|
|
13741
13761
|
const insightMatches = app.db.select().from(insights).where(
|
|
13742
|
-
|
|
13762
|
+
and14(
|
|
13743
13763
|
eq18(insights.projectId, project.id),
|
|
13744
13764
|
or4(
|
|
13745
13765
|
like2(insights.title, pattern),
|
|
@@ -13956,7 +13976,7 @@ function buildSuggestedQueriesFromGsc(app, projectId, trackedQueries) {
|
|
|
13956
13976
|
// NULLIF guards the degenerate impressions=0 case (SQLite returns NULL,
|
|
13957
13977
|
// which the JS coerces to 0 — caught by the impression floor anyway).
|
|
13958
13978
|
avgPosition: sql8`COALESCE(SUM(${gscSearchData.position} * ${gscSearchData.impressions}) * 1.0 / NULLIF(SUM(${gscSearchData.impressions}), 0), 0)`
|
|
13959
|
-
}).from(gscSearchData).where(
|
|
13979
|
+
}).from(gscSearchData).where(and14(
|
|
13960
13980
|
eq18(gscSearchData.projectId, projectId),
|
|
13961
13981
|
sql8`${gscSearchData.date} >= ${cutoff}`,
|
|
13962
13982
|
sql8`${gscSearchData.impressions} > 0`
|
|
@@ -14464,6 +14484,13 @@ var runIdParameter = {
|
|
|
14464
14484
|
description: "Run ID.",
|
|
14465
14485
|
schema: stringSchema
|
|
14466
14486
|
};
|
|
14487
|
+
var queryIdParameter = {
|
|
14488
|
+
name: "id",
|
|
14489
|
+
in: "path",
|
|
14490
|
+
required: true,
|
|
14491
|
+
description: "Query ID.",
|
|
14492
|
+
schema: stringSchema
|
|
14493
|
+
};
|
|
14467
14494
|
var notificationIdParameter = {
|
|
14468
14495
|
name: "id",
|
|
14469
14496
|
in: "path",
|
|
@@ -14870,6 +14897,17 @@ var routeCatalog = [
|
|
|
14870
14897
|
400: errorResponse("Invalid query delete request.")
|
|
14871
14898
|
}
|
|
14872
14899
|
},
|
|
14900
|
+
{
|
|
14901
|
+
method: "delete",
|
|
14902
|
+
path: "/api/v1/projects/{name}/queries/{id}",
|
|
14903
|
+
summary: "Delete one query by ID",
|
|
14904
|
+
tags: ["queries"],
|
|
14905
|
+
parameters: [nameParameter, queryIdParameter],
|
|
14906
|
+
responses: {
|
|
14907
|
+
204: { description: "Query deleted." },
|
|
14908
|
+
404: errorResponse("Project or query not found.")
|
|
14909
|
+
}
|
|
14910
|
+
},
|
|
14873
14911
|
{
|
|
14874
14912
|
method: "post",
|
|
14875
14913
|
path: "/api/v1/projects/{name}/queries",
|
|
@@ -18862,7 +18900,7 @@ async function telemetryRoutes(app, opts) {
|
|
|
18862
18900
|
|
|
18863
18901
|
// ../api-routes/src/schedules.ts
|
|
18864
18902
|
import crypto13 from "crypto";
|
|
18865
|
-
import { and as
|
|
18903
|
+
import { and as and15, eq as eq20 } from "drizzle-orm";
|
|
18866
18904
|
function parseKindParam(raw) {
|
|
18867
18905
|
if (raw === void 0 || raw === null || raw === "") return SchedulableRunKinds["answer-visibility"];
|
|
18868
18906
|
const parsed = schedulableRunKindSchema.safeParse(raw);
|
|
@@ -18934,7 +18972,7 @@ async function scheduleRoutes(app, opts) {
|
|
|
18934
18972
|
}
|
|
18935
18973
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
18936
18974
|
const enabledBool = enabled !== false;
|
|
18937
|
-
const existing = app.db.select().from(schedules).where(
|
|
18975
|
+
const existing = app.db.select().from(schedules).where(and15(eq20(schedules.projectId, project.id), eq20(schedules.kind, kind))).get();
|
|
18938
18976
|
if (existing) {
|
|
18939
18977
|
app.db.update(schedules).set({
|
|
18940
18978
|
cronExpr,
|
|
@@ -18968,13 +19006,13 @@ async function scheduleRoutes(app, opts) {
|
|
|
18968
19006
|
diff: { kind, cronExpr, preset, timezone, providers, sourceId }
|
|
18969
19007
|
});
|
|
18970
19008
|
opts.onScheduleUpdated?.("upsert", project.id, kind);
|
|
18971
|
-
const schedule = app.db.select().from(schedules).where(
|
|
19009
|
+
const schedule = app.db.select().from(schedules).where(and15(eq20(schedules.projectId, project.id), eq20(schedules.kind, kind))).get();
|
|
18972
19010
|
return reply.status(existing ? 200 : 201).send(formatSchedule(schedule));
|
|
18973
19011
|
});
|
|
18974
19012
|
app.get("/projects/:name/schedule", async (request, reply) => {
|
|
18975
19013
|
const project = resolveProject(app.db, request.params.name);
|
|
18976
19014
|
const kind = parseKindParam(request.query?.kind);
|
|
18977
|
-
const schedule = app.db.select().from(schedules).where(
|
|
19015
|
+
const schedule = app.db.select().from(schedules).where(and15(eq20(schedules.projectId, project.id), eq20(schedules.kind, kind))).get();
|
|
18978
19016
|
if (!schedule) {
|
|
18979
19017
|
throw notFound("Schedule", `${request.params.name} (kind=${kind})`);
|
|
18980
19018
|
}
|
|
@@ -18983,7 +19021,7 @@ async function scheduleRoutes(app, opts) {
|
|
|
18983
19021
|
app.delete("/projects/:name/schedule", async (request, reply) => {
|
|
18984
19022
|
const project = resolveProject(app.db, request.params.name);
|
|
18985
19023
|
const kind = parseKindParam(request.query?.kind);
|
|
18986
|
-
const schedule = app.db.select().from(schedules).where(
|
|
19024
|
+
const schedule = app.db.select().from(schedules).where(and15(eq20(schedules.projectId, project.id), eq20(schedules.kind, kind))).get();
|
|
18987
19025
|
if (!schedule) {
|
|
18988
19026
|
throw notFound("Schedule", `${request.params.name} (kind=${kind})`);
|
|
18989
19027
|
}
|
|
@@ -19140,7 +19178,7 @@ function formatNotification(row) {
|
|
|
19140
19178
|
|
|
19141
19179
|
// ../api-routes/src/google.ts
|
|
19142
19180
|
import crypto18 from "crypto";
|
|
19143
|
-
import { eq as eq22, and as
|
|
19181
|
+
import { eq as eq22, and as and16, desc as desc11, sql as sql9, inArray as inArray10 } from "drizzle-orm";
|
|
19144
19182
|
|
|
19145
19183
|
// ../api-routes/src/gbp-summary.ts
|
|
19146
19184
|
function computeMetricTotals(rows) {
|
|
@@ -21120,7 +21158,7 @@ async function googleRoutes(app, opts) {
|
|
|
21120
21158
|
if (page) conditions.push(sql9`${gscSearchData.page} LIKE ${"%" + escapeLikePattern(page) + "%"} ESCAPE '\\'`);
|
|
21121
21159
|
const limitVal = Math.max(parseInt(limit ?? "500", 10) || 0, 1);
|
|
21122
21160
|
const offsetVal = Math.max(parseInt(offset ?? "0", 10) || 0, 0);
|
|
21123
|
-
const rows = app.db.select().from(gscSearchData).where(
|
|
21161
|
+
const rows = app.db.select().from(gscSearchData).where(and16(...conditions)).orderBy(desc11(gscSearchData.date)).limit(limitVal).offset(offsetVal).all();
|
|
21124
21162
|
return rows.map((r) => ({
|
|
21125
21163
|
date: r.date,
|
|
21126
21164
|
query: r.query,
|
|
@@ -21148,7 +21186,7 @@ async function googleRoutes(app, opts) {
|
|
|
21148
21186
|
date: gscSearchData.date,
|
|
21149
21187
|
clicks: sql9`COALESCE(SUM(${gscSearchData.clicks}), 0)`,
|
|
21150
21188
|
impressions: sql9`COALESCE(SUM(${gscSearchData.impressions}), 0)`
|
|
21151
|
-
}).from(gscSearchData).where(
|
|
21189
|
+
}).from(gscSearchData).where(and16(...conditions)).groupBy(gscSearchData.date).orderBy(gscSearchData.date).all();
|
|
21152
21190
|
const daily = mergeGscDailyTotalsWithFallback(
|
|
21153
21191
|
dailyTotals,
|
|
21154
21192
|
dimensionedRows.map((r) => ({
|
|
@@ -21241,7 +21279,7 @@ async function googleRoutes(app, opts) {
|
|
|
21241
21279
|
const { url, limit } = request.query;
|
|
21242
21280
|
const conditions = [eq22(gscUrlInspections.projectId, project.id)];
|
|
21243
21281
|
if (url) conditions.push(eq22(gscUrlInspections.url, url));
|
|
21244
|
-
const rows = app.db.select().from(gscUrlInspections).where(
|
|
21282
|
+
const rows = app.db.select().from(gscUrlInspections).where(and16(...conditions)).orderBy(desc11(gscUrlInspections.inspectedAt)).limit(parseInt(limit ?? "100", 10)).all();
|
|
21245
21283
|
return rows.map((r) => ({
|
|
21246
21284
|
id: r.id,
|
|
21247
21285
|
url: r.url,
|
|
@@ -21736,7 +21774,7 @@ async function googleRoutes(app, opts) {
|
|
|
21736
21774
|
app.db.transaction((tx) => {
|
|
21737
21775
|
if (switching) clearGbpProjectData(tx, project.id);
|
|
21738
21776
|
for (const remote of remoteLocations) {
|
|
21739
|
-
const existing = tx.select().from(gbpLocations).where(
|
|
21777
|
+
const existing = tx.select().from(gbpLocations).where(and16(eq22(gbpLocations.projectId, project.id), eq22(gbpLocations.locationName, remote.name))).get();
|
|
21740
21778
|
const profile = buildLocationProfileFields(remote);
|
|
21741
21779
|
if (existing) {
|
|
21742
21780
|
tx.update(gbpLocations).set({
|
|
@@ -21833,7 +21871,7 @@ async function googleRoutes(app, opts) {
|
|
|
21833
21871
|
throw validationError(parsed.error.issues[0]?.message ?? "Invalid selection request");
|
|
21834
21872
|
}
|
|
21835
21873
|
const { selected } = parsed.data;
|
|
21836
|
-
const existing = app.db.select().from(gbpLocations).where(
|
|
21874
|
+
const existing = app.db.select().from(gbpLocations).where(and16(eq22(gbpLocations.projectId, project.id), eq22(gbpLocations.locationName, locationName))).get();
|
|
21837
21875
|
if (!existing) throw notFound("GBP location", locationName);
|
|
21838
21876
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
21839
21877
|
app.db.transaction((tx) => {
|
|
@@ -21893,7 +21931,7 @@ async function googleRoutes(app, opts) {
|
|
|
21893
21931
|
const conditions = [eq22(gbpDailyMetrics.projectId, project.id)];
|
|
21894
21932
|
if (request.query.locationName) conditions.push(eq22(gbpDailyMetrics.locationName, request.query.locationName));
|
|
21895
21933
|
if (request.query.metric) conditions.push(eq22(gbpDailyMetrics.metric, request.query.metric));
|
|
21896
|
-
const rows = app.db.select().from(gbpDailyMetrics).where(
|
|
21934
|
+
const rows = app.db.select().from(gbpDailyMetrics).where(and16(...conditions)).orderBy(desc11(gbpDailyMetrics.date)).all();
|
|
21897
21935
|
return {
|
|
21898
21936
|
metrics: rows.map((r) => ({ locationName: r.locationName, date: r.date, metric: r.metric, value: r.value })),
|
|
21899
21937
|
total: rows.length
|
|
@@ -21903,7 +21941,7 @@ async function googleRoutes(app, opts) {
|
|
|
21903
21941
|
const project = resolveProject(app.db, request.params.name);
|
|
21904
21942
|
const conditions = [eq22(gbpKeywordImpressions.projectId, project.id)];
|
|
21905
21943
|
if (request.query.locationName) conditions.push(eq22(gbpKeywordImpressions.locationName, request.query.locationName));
|
|
21906
|
-
const rows = app.db.select().from(gbpKeywordImpressions).where(
|
|
21944
|
+
const rows = app.db.select().from(gbpKeywordImpressions).where(and16(...conditions)).all();
|
|
21907
21945
|
rows.sort((a, b) => (b.valueCount ?? -1) - (a.valueCount ?? -1));
|
|
21908
21946
|
const thresholded = rows.filter((r) => r.valueThreshold !== null).length;
|
|
21909
21947
|
return {
|
|
@@ -21923,7 +21961,7 @@ async function googleRoutes(app, opts) {
|
|
|
21923
21961
|
const project = resolveProject(app.db, request.params.name);
|
|
21924
21962
|
const conditions = [eq22(gbpPlaceActions.projectId, project.id)];
|
|
21925
21963
|
if (request.query.locationName) conditions.push(eq22(gbpPlaceActions.locationName, request.query.locationName));
|
|
21926
|
-
const rows = app.db.select().from(gbpPlaceActions).where(
|
|
21964
|
+
const rows = app.db.select().from(gbpPlaceActions).where(and16(...conditions)).all();
|
|
21927
21965
|
return {
|
|
21928
21966
|
placeActions: rows.map((r) => ({
|
|
21929
21967
|
locationName: r.locationName,
|
|
@@ -21940,7 +21978,7 @@ async function googleRoutes(app, opts) {
|
|
|
21940
21978
|
const project = resolveProject(app.db, request.params.name);
|
|
21941
21979
|
const conditions = [eq22(gbpLodgingSnapshots.projectId, project.id)];
|
|
21942
21980
|
if (request.query.locationName) conditions.push(eq22(gbpLodgingSnapshots.locationName, request.query.locationName));
|
|
21943
|
-
const rows = app.db.select().from(gbpLodgingSnapshots).where(
|
|
21981
|
+
const rows = app.db.select().from(gbpLodgingSnapshots).where(and16(...conditions)).orderBy(desc11(gbpLodgingSnapshots.syncedAt)).all();
|
|
21944
21982
|
const latestByLocation = /* @__PURE__ */ new Map();
|
|
21945
21983
|
for (const row of rows) {
|
|
21946
21984
|
if (!latestByLocation.has(row.locationName)) latestByLocation.set(row.locationName, row);
|
|
@@ -21957,7 +21995,7 @@ async function googleRoutes(app, opts) {
|
|
|
21957
21995
|
const project = resolveProject(app.db, request.params.name);
|
|
21958
21996
|
const conditions = [eq22(gbpAttributesSnapshots.projectId, project.id)];
|
|
21959
21997
|
if (request.query.locationName) conditions.push(eq22(gbpAttributesSnapshots.locationName, request.query.locationName));
|
|
21960
|
-
const rows = app.db.select().from(gbpAttributesSnapshots).where(
|
|
21998
|
+
const rows = app.db.select().from(gbpAttributesSnapshots).where(and16(...conditions)).orderBy(desc11(gbpAttributesSnapshots.syncedAt)).all();
|
|
21961
21999
|
const latestByLocation = /* @__PURE__ */ new Map();
|
|
21962
22000
|
for (const row of rows) {
|
|
21963
22001
|
if (!latestByLocation.has(row.locationName)) latestByLocation.set(row.locationName, row);
|
|
@@ -21977,7 +22015,7 @@ async function googleRoutes(app, opts) {
|
|
|
21977
22015
|
const project = resolveProject(app.db, request.params.name);
|
|
21978
22016
|
const conditions = [eq22(gbpPlaceDetails.projectId, project.id)];
|
|
21979
22017
|
if (request.query.locationName) conditions.push(eq22(gbpPlaceDetails.locationName, request.query.locationName));
|
|
21980
|
-
const rows = app.db.select().from(gbpPlaceDetails).where(
|
|
22018
|
+
const rows = app.db.select().from(gbpPlaceDetails).where(and16(...conditions)).orderBy(desc11(gbpPlaceDetails.syncedAt)).all();
|
|
21981
22019
|
const latestByLocation = /* @__PURE__ */ new Map();
|
|
21982
22020
|
for (const row of rows) {
|
|
21983
22021
|
if (!latestByLocation.has(row.locationName)) latestByLocation.set(row.locationName, row);
|
|
@@ -21996,7 +22034,7 @@ async function googleRoutes(app, opts) {
|
|
|
21996
22034
|
app.get("/projects/:name/gbp/summary", async (request) => {
|
|
21997
22035
|
const project = resolveProject(app.db, request.params.name);
|
|
21998
22036
|
const locationName = request.query.locationName ?? null;
|
|
21999
|
-
const locationNames = locationName ? [locationName] : app.db.select({ n: gbpLocations.locationName }).from(gbpLocations).where(
|
|
22037
|
+
const locationNames = locationName ? [locationName] : app.db.select({ n: gbpLocations.locationName }).from(gbpLocations).where(and16(eq22(gbpLocations.projectId, project.id), eq22(gbpLocations.selected, true))).all().map((r) => r.n);
|
|
22000
22038
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
22001
22039
|
if (locationNames.length === 0) {
|
|
22002
22040
|
return buildGbpSummary({
|
|
@@ -22010,10 +22048,10 @@ async function googleRoutes(app, opts) {
|
|
|
22010
22048
|
locationProfiles: []
|
|
22011
22049
|
});
|
|
22012
22050
|
}
|
|
22013
|
-
const metricRows = app.db.select().from(gbpDailyMetrics).where(
|
|
22014
|
-
const keywordRows = app.db.select().from(gbpKeywordImpressions).where(
|
|
22015
|
-
const placeActionRows = app.db.select().from(gbpPlaceActions).where(
|
|
22016
|
-
const lodgingRows = app.db.select().from(gbpLodgingSnapshots).where(
|
|
22051
|
+
const metricRows = app.db.select().from(gbpDailyMetrics).where(and16(eq22(gbpDailyMetrics.projectId, project.id), inArray10(gbpDailyMetrics.locationName, locationNames))).all();
|
|
22052
|
+
const keywordRows = app.db.select().from(gbpKeywordImpressions).where(and16(eq22(gbpKeywordImpressions.projectId, project.id), inArray10(gbpKeywordImpressions.locationName, locationNames))).all();
|
|
22053
|
+
const placeActionRows = app.db.select().from(gbpPlaceActions).where(and16(eq22(gbpPlaceActions.projectId, project.id), inArray10(gbpPlaceActions.locationName, locationNames))).all();
|
|
22054
|
+
const lodgingRows = app.db.select().from(gbpLodgingSnapshots).where(and16(eq22(gbpLodgingSnapshots.projectId, project.id), inArray10(gbpLodgingSnapshots.locationName, locationNames))).orderBy(desc11(gbpLodgingSnapshots.syncedAt)).all();
|
|
22017
22055
|
const latestLodgingByLocation = /* @__PURE__ */ new Map();
|
|
22018
22056
|
for (const row of lodgingRows) {
|
|
22019
22057
|
if (!latestLodgingByLocation.has(row.locationName)) {
|
|
@@ -22027,7 +22065,7 @@ async function googleRoutes(app, opts) {
|
|
|
22027
22065
|
regularHours: gbpLocations.regularHours,
|
|
22028
22066
|
primaryPhone: gbpLocations.primaryPhone,
|
|
22029
22067
|
openStatus: gbpLocations.openStatus
|
|
22030
|
-
}).from(gbpLocations).where(
|
|
22068
|
+
}).from(gbpLocations).where(and16(eq22(gbpLocations.projectId, project.id), inArray10(gbpLocations.locationName, locationNames))).all();
|
|
22031
22069
|
return buildGbpSummary({
|
|
22032
22070
|
locationName,
|
|
22033
22071
|
locationCount: locationNames.length,
|
|
@@ -22043,7 +22081,7 @@ async function googleRoutes(app, opts) {
|
|
|
22043
22081
|
|
|
22044
22082
|
// ../api-routes/src/ads.ts
|
|
22045
22083
|
import crypto19 from "crypto";
|
|
22046
|
-
import { eq as eq23, and as
|
|
22084
|
+
import { eq as eq23, and as and17, asc as asc3, gte as gte3, lte as lte2, inArray as inArray11 } from "drizzle-orm";
|
|
22047
22085
|
function statusDto(row) {
|
|
22048
22086
|
if (!row) return { connected: false };
|
|
22049
22087
|
return {
|
|
@@ -22159,7 +22197,7 @@ async function adsRoutes(app, opts) {
|
|
|
22159
22197
|
if (!row) {
|
|
22160
22198
|
throw validationError('No ads connection for this project. Run "canonry ads connect" first.');
|
|
22161
22199
|
}
|
|
22162
|
-
const inFlight = app.db.select({ id: runs.id, status: runs.status }).from(runs).where(
|
|
22200
|
+
const inFlight = app.db.select({ id: runs.id, status: runs.status }).from(runs).where(and17(
|
|
22163
22201
|
eq23(runs.projectId, project.id),
|
|
22164
22202
|
eq23(runs.kind, RunKinds["ads-sync"]),
|
|
22165
22203
|
inArray11(runs.status, [RunStatuses.queued, RunStatuses.running])
|
|
@@ -22244,7 +22282,7 @@ async function adsRoutes(app, opts) {
|
|
|
22244
22282
|
if (entityId) conditions.push(eq23(adsInsightsDaily.entityId, entityId));
|
|
22245
22283
|
if (from) conditions.push(gte3(adsInsightsDaily.date, from));
|
|
22246
22284
|
if (to) conditions.push(lte2(adsInsightsDaily.date, to));
|
|
22247
|
-
const rows = app.db.select().from(adsInsightsDaily).where(
|
|
22285
|
+
const rows = app.db.select().from(adsInsightsDaily).where(and17(...conditions)).orderBy(asc3(adsInsightsDaily.date)).all();
|
|
22248
22286
|
const dtoRows = rows.map((row) => ({
|
|
22249
22287
|
level: row.level,
|
|
22250
22288
|
entityId: row.entityId,
|
|
@@ -22266,7 +22304,7 @@ async function adsRoutes(app, opts) {
|
|
|
22266
22304
|
const campaignCount = app.db.select().from(adsCampaigns).where(eq23(adsCampaigns.projectId, project.id)).all().length;
|
|
22267
22305
|
const adGroupCount = app.db.select().from(adsAdGroups).where(eq23(adsAdGroups.projectId, project.id)).all().length;
|
|
22268
22306
|
const adCount = app.db.select().from(adsAds).where(eq23(adsAds.projectId, project.id)).all().length;
|
|
22269
|
-
const campaignInsights = app.db.select().from(adsInsightsDaily).where(
|
|
22307
|
+
const campaignInsights = app.db.select().from(adsInsightsDaily).where(and17(
|
|
22270
22308
|
eq23(adsInsightsDaily.projectId, project.id),
|
|
22271
22309
|
eq23(adsInsightsDaily.level, "campaign")
|
|
22272
22310
|
)).all();
|
|
@@ -22308,7 +22346,7 @@ async function adsRoutes(app, opts) {
|
|
|
22308
22346
|
|
|
22309
22347
|
// ../api-routes/src/bing.ts
|
|
22310
22348
|
import crypto20 from "crypto";
|
|
22311
|
-
import { eq as eq24, and as
|
|
22349
|
+
import { eq as eq24, and as and18, desc as desc12 } from "drizzle-orm";
|
|
22312
22350
|
|
|
22313
22351
|
// ../integration-bing/src/constants.ts
|
|
22314
22352
|
var BING_WMT_API_BASE = "https://ssl.bing.com/webmaster/api.svc/json";
|
|
@@ -22783,7 +22821,7 @@ async function bingRoutes(app, opts) {
|
|
|
22783
22821
|
requireConnectionStore();
|
|
22784
22822
|
const project = resolveProject(app.db, request.params.name);
|
|
22785
22823
|
const { url, limit } = request.query;
|
|
22786
|
-
const whereClause = url ?
|
|
22824
|
+
const whereClause = url ? and18(eq24(bingUrlInspections.projectId, project.id), eq24(bingUrlInspections.url, url)) : eq24(bingUrlInspections.projectId, project.id);
|
|
22787
22825
|
const filtered = app.db.select().from(bingUrlInspections).where(whereClause).orderBy(desc12(bingUrlInspections.inspectedAt)).limit(Math.max(1, Math.min(parseInt(limit ?? "100", 10) || 100, 1e3))).all();
|
|
22788
22826
|
return filtered.map((r) => ({
|
|
22789
22827
|
id: r.id,
|
|
@@ -23015,7 +23053,7 @@ async function bingRoutes(app, opts) {
|
|
|
23015
23053
|
import fs from "fs";
|
|
23016
23054
|
import path from "path";
|
|
23017
23055
|
import os from "os";
|
|
23018
|
-
import { eq as eq25, and as
|
|
23056
|
+
import { eq as eq25, and as and19 } from "drizzle-orm";
|
|
23019
23057
|
function getScreenshotDir() {
|
|
23020
23058
|
return path.join(os.homedir(), ".canonry", "screenshots");
|
|
23021
23059
|
}
|
|
@@ -23090,7 +23128,7 @@ async function cdpRoutes(app, opts) {
|
|
|
23090
23128
|
async (request, reply) => {
|
|
23091
23129
|
const project = resolveProject(app.db, request.params.name);
|
|
23092
23130
|
const { runId } = request.params;
|
|
23093
|
-
const run = app.db.select().from(runs).where(
|
|
23131
|
+
const run = app.db.select().from(runs).where(and19(eq25(runs.id, runId), eq25(runs.projectId, project.id))).get();
|
|
23094
23132
|
if (!run) {
|
|
23095
23133
|
const err = notFound("Run", runId);
|
|
23096
23134
|
return reply.code(err.statusCode).send(err.toJSON());
|
|
@@ -23187,7 +23225,7 @@ async function cdpRoutes(app, opts) {
|
|
|
23187
23225
|
|
|
23188
23226
|
// ../api-routes/src/ga.ts
|
|
23189
23227
|
import crypto21 from "crypto";
|
|
23190
|
-
import { eq as eq26, desc as desc13, and as
|
|
23228
|
+
import { eq as eq26, desc as desc13, and as and20, sql as sql10 } from "drizzle-orm";
|
|
23191
23229
|
function gaLog(level, action, ctx) {
|
|
23192
23230
|
const entry = { ts: (/* @__PURE__ */ new Date()).toISOString(), level, module: "GA4Routes", action, ...ctx };
|
|
23193
23231
|
const stream = level === "error" ? process.stderr : process.stdout;
|
|
@@ -23482,7 +23520,7 @@ async function ga4Routes(app, opts) {
|
|
|
23482
23520
|
app.db.transaction((tx) => {
|
|
23483
23521
|
if (syncTraffic) {
|
|
23484
23522
|
tx.delete(gaTrafficSnapshots).where(
|
|
23485
|
-
|
|
23523
|
+
and20(
|
|
23486
23524
|
eq26(gaTrafficSnapshots.projectId, project.id),
|
|
23487
23525
|
sql10`${gaTrafficSnapshots.date} >= ${summary.periodStart}`,
|
|
23488
23526
|
sql10`${gaTrafficSnapshots.date} <= ${summary.periodEnd}`
|
|
@@ -23506,7 +23544,7 @@ async function ga4Routes(app, opts) {
|
|
|
23506
23544
|
}
|
|
23507
23545
|
if (syncAi) {
|
|
23508
23546
|
tx.delete(gaAiReferrals).where(
|
|
23509
|
-
|
|
23547
|
+
and20(
|
|
23510
23548
|
eq26(gaAiReferrals.projectId, project.id),
|
|
23511
23549
|
sql10`${gaAiReferrals.date} >= ${summary.periodStart}`,
|
|
23512
23550
|
sql10`${gaAiReferrals.date} <= ${summary.periodEnd}`
|
|
@@ -23532,7 +23570,7 @@ async function ga4Routes(app, opts) {
|
|
|
23532
23570
|
}
|
|
23533
23571
|
if (syncSocial) {
|
|
23534
23572
|
tx.delete(gaSocialReferrals).where(
|
|
23535
|
-
|
|
23573
|
+
and20(
|
|
23536
23574
|
eq26(gaSocialReferrals.projectId, project.id),
|
|
23537
23575
|
sql10`${gaSocialReferrals.date} >= ${summary.periodStart}`,
|
|
23538
23576
|
sql10`${gaSocialReferrals.date} <= ${summary.periodEnd}`
|
|
@@ -23636,7 +23674,7 @@ async function ga4Routes(app, opts) {
|
|
|
23636
23674
|
totalDirectSessions: gaTrafficWindowSummaries.totalDirectSessions,
|
|
23637
23675
|
totalUsers: gaTrafficWindowSummaries.totalUsers
|
|
23638
23676
|
}).from(gaTrafficWindowSummaries).where(
|
|
23639
|
-
|
|
23677
|
+
and20(
|
|
23640
23678
|
eq26(gaTrafficWindowSummaries.projectId, project.id),
|
|
23641
23679
|
eq26(gaTrafficWindowSummaries.windowKey, window)
|
|
23642
23680
|
)
|
|
@@ -23645,7 +23683,7 @@ async function ga4Routes(app, opts) {
|
|
|
23645
23683
|
totalSessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.sessions}), 0)`,
|
|
23646
23684
|
totalOrganicSessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.organicSessions}), 0)`,
|
|
23647
23685
|
totalUsers: sql10`COALESCE(SUM(${gaTrafficSnapshots.users}), 0)`
|
|
23648
|
-
}).from(gaTrafficSnapshots).where(
|
|
23686
|
+
}).from(gaTrafficSnapshots).where(and20(...snapshotConditions)).get() : null;
|
|
23649
23687
|
const summaryRow = cutoffDate ? windowSummaryRow ?? snapshotTotalsRow : app.db.select({
|
|
23650
23688
|
totalSessions: gaTrafficSummaries.totalSessions,
|
|
23651
23689
|
totalOrganicSessions: gaTrafficSummaries.totalOrganicSessions,
|
|
@@ -23653,7 +23691,7 @@ async function ga4Routes(app, opts) {
|
|
|
23653
23691
|
}).from(gaTrafficSummaries).where(eq26(gaTrafficSummaries.projectId, project.id)).get();
|
|
23654
23692
|
const directTotalRow = windowSummaryRow ? { totalDirectSessions: windowSummaryRow.totalDirectSessions } : app.db.select({
|
|
23655
23693
|
totalDirectSessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)`
|
|
23656
|
-
}).from(gaTrafficSnapshots).where(
|
|
23694
|
+
}).from(gaTrafficSnapshots).where(and20(...snapshotConditions)).get();
|
|
23657
23695
|
const summaryMeta = app.db.select({
|
|
23658
23696
|
periodStart: gaTrafficSummaries.periodStart,
|
|
23659
23697
|
periodEnd: gaTrafficSummaries.periodEnd
|
|
@@ -23664,14 +23702,14 @@ async function ga4Routes(app, opts) {
|
|
|
23664
23702
|
organicSessions: sql10`SUM(${gaTrafficSnapshots.organicSessions})`,
|
|
23665
23703
|
directSessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)`,
|
|
23666
23704
|
users: sql10`SUM(${gaTrafficSnapshots.users})`
|
|
23667
|
-
}).from(gaTrafficSnapshots).where(
|
|
23705
|
+
}).from(gaTrafficSnapshots).where(and20(...snapshotConditions)).groupBy(sql10`COALESCE(${gaTrafficSnapshots.landingPageNormalized}, ${gaTrafficSnapshots.landingPage})`).orderBy(sql10`SUM(${gaTrafficSnapshots.sessions}) DESC`).limit(limit).all();
|
|
23668
23706
|
const aiReferralRows = app.db.select({
|
|
23669
23707
|
source: gaAiReferrals.source,
|
|
23670
23708
|
medium: gaAiReferrals.medium,
|
|
23671
23709
|
sourceDimension: gaAiReferrals.sourceDimension,
|
|
23672
23710
|
sessions: sql10`SUM(${gaAiReferrals.sessions})`,
|
|
23673
23711
|
users: sql10`SUM(${gaAiReferrals.users})`
|
|
23674
|
-
}).from(gaAiReferrals).where(
|
|
23712
|
+
}).from(gaAiReferrals).where(and20(...aiConditions)).groupBy(gaAiReferrals.source, gaAiReferrals.medium, gaAiReferrals.sourceDimension).all();
|
|
23675
23713
|
const aiReferralLandingPageRows = app.db.select({
|
|
23676
23714
|
source: gaAiReferrals.source,
|
|
23677
23715
|
medium: gaAiReferrals.medium,
|
|
@@ -23679,7 +23717,7 @@ async function ga4Routes(app, opts) {
|
|
|
23679
23717
|
landingPage: sql10`COALESCE(${gaAiReferrals.landingPageNormalized}, ${gaAiReferrals.landingPage})`,
|
|
23680
23718
|
sessions: sql10`SUM(${gaAiReferrals.sessions})`,
|
|
23681
23719
|
users: sql10`SUM(${gaAiReferrals.users})`
|
|
23682
|
-
}).from(gaAiReferrals).where(
|
|
23720
|
+
}).from(gaAiReferrals).where(and20(...aiConditions)).groupBy(
|
|
23683
23721
|
gaAiReferrals.source,
|
|
23684
23722
|
gaAiReferrals.medium,
|
|
23685
23723
|
gaAiReferrals.sourceDimension,
|
|
@@ -23716,7 +23754,7 @@ async function ga4Routes(app, opts) {
|
|
|
23716
23754
|
channelGroup: gaAiReferrals.channelGroup,
|
|
23717
23755
|
sessions: sql10`COALESCE(SUM(${gaAiReferrals.sessions}), 0)`,
|
|
23718
23756
|
users: sql10`COALESCE(SUM(${gaAiReferrals.users}), 0)`
|
|
23719
|
-
}).from(gaAiReferrals).where(
|
|
23757
|
+
}).from(gaAiReferrals).where(and20(...aiConditions, eq26(gaAiReferrals.sourceDimension, "session"))).groupBy(gaAiReferrals.channelGroup).all();
|
|
23720
23758
|
const aiSessionsByChannelGroup = /* @__PURE__ */ new Map();
|
|
23721
23759
|
let aiBySessionUsers = 0;
|
|
23722
23760
|
for (const row of aiBySessionRows) {
|
|
@@ -23730,11 +23768,11 @@ async function ga4Routes(app, opts) {
|
|
|
23730
23768
|
channelGroup: gaSocialReferrals.channelGroup,
|
|
23731
23769
|
sessions: sql10`SUM(${gaSocialReferrals.sessions})`,
|
|
23732
23770
|
users: sql10`SUM(${gaSocialReferrals.users})`
|
|
23733
|
-
}).from(gaSocialReferrals).where(
|
|
23771
|
+
}).from(gaSocialReferrals).where(and20(...socialConditions)).groupBy(gaSocialReferrals.source, gaSocialReferrals.medium, gaSocialReferrals.channelGroup).orderBy(sql10`SUM(${gaSocialReferrals.sessions}) DESC`).all();
|
|
23734
23772
|
const socialTotals = app.db.select({
|
|
23735
23773
|
sessions: sql10`SUM(${gaSocialReferrals.sessions})`,
|
|
23736
23774
|
users: sql10`SUM(${gaSocialReferrals.users})`
|
|
23737
|
-
}).from(gaSocialReferrals).where(
|
|
23775
|
+
}).from(gaSocialReferrals).where(and20(...socialConditions)).get();
|
|
23738
23776
|
const latestSync = app.db.select({ syncedAt: gaTrafficSummaries.syncedAt }).from(gaTrafficSummaries).where(eq26(gaTrafficSummaries.projectId, project.id)).orderBy(desc13(gaTrafficSummaries.syncedAt)).limit(1).get();
|
|
23739
23777
|
const total = summaryRow?.totalSessions ?? 0;
|
|
23740
23778
|
const totalDirectSessions = directTotalRow?.totalDirectSessions ?? 0;
|
|
@@ -23825,7 +23863,7 @@ async function ga4Routes(app, opts) {
|
|
|
23825
23863
|
sourceDimension: gaAiReferrals.sourceDimension,
|
|
23826
23864
|
sessions: sql10`SUM(${gaAiReferrals.sessions})`,
|
|
23827
23865
|
users: sql10`SUM(${gaAiReferrals.users})`
|
|
23828
|
-
}).from(gaAiReferrals).where(
|
|
23866
|
+
}).from(gaAiReferrals).where(and20(...conditions)).groupBy(
|
|
23829
23867
|
gaAiReferrals.date,
|
|
23830
23868
|
gaAiReferrals.source,
|
|
23831
23869
|
gaAiReferrals.medium,
|
|
@@ -23847,7 +23885,7 @@ async function ga4Routes(app, opts) {
|
|
|
23847
23885
|
channelGroup: gaSocialReferrals.channelGroup,
|
|
23848
23886
|
sessions: gaSocialReferrals.sessions,
|
|
23849
23887
|
users: gaSocialReferrals.users
|
|
23850
|
-
}).from(gaSocialReferrals).where(
|
|
23888
|
+
}).from(gaSocialReferrals).where(and20(...conditions)).orderBy(gaSocialReferrals.date).all();
|
|
23851
23889
|
return rows;
|
|
23852
23890
|
});
|
|
23853
23891
|
app.get("/projects/:name/ga/social-referral-trend", async (request, _reply) => {
|
|
@@ -23860,7 +23898,7 @@ async function ga4Routes(app, opts) {
|
|
|
23860
23898
|
d.setDate(d.getDate() - n);
|
|
23861
23899
|
return fmt(d);
|
|
23862
23900
|
};
|
|
23863
|
-
const sumSocial = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaSocialReferrals.sessions}), 0)` }).from(gaSocialReferrals).where(
|
|
23901
|
+
const sumSocial = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaSocialReferrals.sessions}), 0)` }).from(gaSocialReferrals).where(and20(
|
|
23864
23902
|
eq26(gaSocialReferrals.projectId, project.id),
|
|
23865
23903
|
sql10`${gaSocialReferrals.date} >= ${from}`,
|
|
23866
23904
|
sql10`${gaSocialReferrals.date} < ${to}`
|
|
@@ -23873,7 +23911,7 @@ async function ga4Routes(app, opts) {
|
|
|
23873
23911
|
const sourceCurrent = app.db.select({
|
|
23874
23912
|
source: gaSocialReferrals.source,
|
|
23875
23913
|
sessions: sql10`SUM(${gaSocialReferrals.sessions})`
|
|
23876
|
-
}).from(gaSocialReferrals).where(
|
|
23914
|
+
}).from(gaSocialReferrals).where(and20(
|
|
23877
23915
|
eq26(gaSocialReferrals.projectId, project.id),
|
|
23878
23916
|
sql10`${gaSocialReferrals.date} >= ${daysAgo(7)}`,
|
|
23879
23917
|
sql10`${gaSocialReferrals.date} < ${fmt(today)}`
|
|
@@ -23881,7 +23919,7 @@ async function ga4Routes(app, opts) {
|
|
|
23881
23919
|
const sourcePrev = app.db.select({
|
|
23882
23920
|
source: gaSocialReferrals.source,
|
|
23883
23921
|
sessions: sql10`SUM(${gaSocialReferrals.sessions})`
|
|
23884
|
-
}).from(gaSocialReferrals).where(
|
|
23922
|
+
}).from(gaSocialReferrals).where(and20(
|
|
23885
23923
|
eq26(gaSocialReferrals.projectId, project.id),
|
|
23886
23924
|
sql10`${gaSocialReferrals.date} >= ${daysAgo(14)}`,
|
|
23887
23925
|
sql10`${gaSocialReferrals.date} < ${daysAgo(7)}`
|
|
@@ -23923,16 +23961,16 @@ async function ga4Routes(app, opts) {
|
|
|
23923
23961
|
return fmt(d);
|
|
23924
23962
|
};
|
|
23925
23963
|
const pct = (cur, prev) => prev === 0 ? null : Math.round((cur - prev) / prev * 100);
|
|
23926
|
-
const sumTotal = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.sessions}), 0)` }).from(gaTrafficSnapshots).where(
|
|
23927
|
-
const sumOrganic = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.organicSessions}), 0)` }).from(gaTrafficSnapshots).where(
|
|
23928
|
-
const sumDirect = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)` }).from(gaTrafficSnapshots).where(
|
|
23929
|
-
const sumAi = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(
|
|
23964
|
+
const sumTotal = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.sessions}), 0)` }).from(gaTrafficSnapshots).where(and20(eq26(gaTrafficSnapshots.projectId, project.id), sql10`${gaTrafficSnapshots.date} >= ${from}`, sql10`${gaTrafficSnapshots.date} < ${to}`)).get();
|
|
23965
|
+
const sumOrganic = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.organicSessions}), 0)` }).from(gaTrafficSnapshots).where(and20(eq26(gaTrafficSnapshots.projectId, project.id), sql10`${gaTrafficSnapshots.date} >= ${from}`, sql10`${gaTrafficSnapshots.date} < ${to}`)).get();
|
|
23966
|
+
const sumDirect = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)` }).from(gaTrafficSnapshots).where(and20(eq26(gaTrafficSnapshots.projectId, project.id), sql10`${gaTrafficSnapshots.date} >= ${from}`, sql10`${gaTrafficSnapshots.date} < ${to}`)).get();
|
|
23967
|
+
const sumAi = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and20(
|
|
23930
23968
|
eq26(gaAiReferrals.projectId, project.id),
|
|
23931
23969
|
sql10`${gaAiReferrals.date} >= ${from}`,
|
|
23932
23970
|
sql10`${gaAiReferrals.date} < ${to}`,
|
|
23933
23971
|
eq26(gaAiReferrals.sourceDimension, "session")
|
|
23934
23972
|
)).get();
|
|
23935
|
-
const sumSocial = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaSocialReferrals.sessions}), 0)` }).from(gaSocialReferrals).where(
|
|
23973
|
+
const sumSocial = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaSocialReferrals.sessions}), 0)` }).from(gaSocialReferrals).where(and20(eq26(gaSocialReferrals.projectId, project.id), sql10`${gaSocialReferrals.date} >= ${from}`, sql10`${gaSocialReferrals.date} < ${to}`)).get();
|
|
23936
23974
|
const todayStr = fmt(today);
|
|
23937
23975
|
const buildTrend = (sum) => {
|
|
23938
23976
|
const c7 = sum(daysAgo(7), todayStr)?.sessions ?? 0;
|
|
@@ -23941,13 +23979,13 @@ async function ga4Routes(app, opts) {
|
|
|
23941
23979
|
const p30 = sum(daysAgo(60), daysAgo(30))?.sessions ?? 0;
|
|
23942
23980
|
return { sessions7d: c7, sessionsPrev7d: p7, trend7dPct: pct(c7, p7), sessions30d: c30, sessionsPrev30d: p30, trend30dPct: pct(c30, p30) };
|
|
23943
23981
|
};
|
|
23944
|
-
const aiSourceCurrent = app.db.select({ source: gaAiReferrals.source, sessions: sql10`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(
|
|
23982
|
+
const aiSourceCurrent = app.db.select({ source: gaAiReferrals.source, sessions: sql10`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and20(
|
|
23945
23983
|
eq26(gaAiReferrals.projectId, project.id),
|
|
23946
23984
|
sql10`${gaAiReferrals.date} >= ${daysAgo(7)}`,
|
|
23947
23985
|
sql10`${gaAiReferrals.date} < ${todayStr}`,
|
|
23948
23986
|
eq26(gaAiReferrals.sourceDimension, "session")
|
|
23949
23987
|
)).groupBy(gaAiReferrals.source).all();
|
|
23950
|
-
const aiSourcePrev = app.db.select({ source: gaAiReferrals.source, sessions: sql10`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(
|
|
23988
|
+
const aiSourcePrev = app.db.select({ source: gaAiReferrals.source, sessions: sql10`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and20(
|
|
23951
23989
|
eq26(gaAiReferrals.projectId, project.id),
|
|
23952
23990
|
sql10`${gaAiReferrals.date} >= ${daysAgo(14)}`,
|
|
23953
23991
|
sql10`${gaAiReferrals.date} < ${daysAgo(7)}`,
|
|
@@ -23967,8 +24005,8 @@ async function ga4Routes(app, opts) {
|
|
|
23967
24005
|
}
|
|
23968
24006
|
return mover;
|
|
23969
24007
|
};
|
|
23970
|
-
const socialSourceCurrent = app.db.select({ source: gaSocialReferrals.source, sessions: sql10`SUM(${gaSocialReferrals.sessions})` }).from(gaSocialReferrals).where(
|
|
23971
|
-
const socialSourcePrev = app.db.select({ source: gaSocialReferrals.source, sessions: sql10`SUM(${gaSocialReferrals.sessions})` }).from(gaSocialReferrals).where(
|
|
24008
|
+
const socialSourceCurrent = app.db.select({ source: gaSocialReferrals.source, sessions: sql10`SUM(${gaSocialReferrals.sessions})` }).from(gaSocialReferrals).where(and20(eq26(gaSocialReferrals.projectId, project.id), sql10`${gaSocialReferrals.date} >= ${daysAgo(7)}`, sql10`${gaSocialReferrals.date} < ${todayStr}`)).groupBy(gaSocialReferrals.source).all();
|
|
24009
|
+
const socialSourcePrev = app.db.select({ source: gaSocialReferrals.source, sessions: sql10`SUM(${gaSocialReferrals.sessions})` }).from(gaSocialReferrals).where(and20(eq26(gaSocialReferrals.projectId, project.id), sql10`${gaSocialReferrals.date} >= ${daysAgo(14)}`, sql10`${gaSocialReferrals.date} < ${daysAgo(7)}`)).groupBy(gaSocialReferrals.source).all();
|
|
23972
24010
|
return {
|
|
23973
24011
|
total: buildTrend(sumTotal),
|
|
23974
24012
|
organic: buildTrend(sumOrganic),
|
|
@@ -23990,7 +24028,7 @@ async function ga4Routes(app, opts) {
|
|
|
23990
24028
|
sessions: sql10`SUM(${gaTrafficSnapshots.sessions})`,
|
|
23991
24029
|
organicSessions: sql10`SUM(${gaTrafficSnapshots.organicSessions})`,
|
|
23992
24030
|
users: sql10`SUM(${gaTrafficSnapshots.users})`
|
|
23993
|
-
}).from(gaTrafficSnapshots).where(
|
|
24031
|
+
}).from(gaTrafficSnapshots).where(and20(...conditions)).groupBy(gaTrafficSnapshots.date).orderBy(gaTrafficSnapshots.date).all();
|
|
23994
24032
|
return rows.map((r) => ({
|
|
23995
24033
|
date: r.date,
|
|
23996
24034
|
sessions: r.sessions ?? 0,
|
|
@@ -25654,7 +25692,7 @@ async function wordpressRoutes(app, opts) {
|
|
|
25654
25692
|
|
|
25655
25693
|
// ../api-routes/src/backlinks.ts
|
|
25656
25694
|
import crypto23 from "crypto";
|
|
25657
|
-
import { and as
|
|
25695
|
+
import { and as and22, asc as asc4, desc as desc14, eq as eq27, sql as sql11 } from "drizzle-orm";
|
|
25658
25696
|
|
|
25659
25697
|
// ../integration-commoncrawl/src/constants.ts
|
|
25660
25698
|
import os2 from "os";
|
|
@@ -26057,7 +26095,7 @@ function pruneCachedRelease(release, opts = {}) {
|
|
|
26057
26095
|
}
|
|
26058
26096
|
|
|
26059
26097
|
// ../api-routes/src/backlinks-filter.ts
|
|
26060
|
-
import { and as
|
|
26098
|
+
import { and as and21, ne as ne3, notLike } from "drizzle-orm";
|
|
26061
26099
|
var BACKLINK_FILTER_PATTERNS = [
|
|
26062
26100
|
"*.google.com",
|
|
26063
26101
|
"*.googleusercontent.com",
|
|
@@ -26080,7 +26118,7 @@ function backlinkCrawlerExclusionClause() {
|
|
|
26080
26118
|
conditions.push(ne3(backlinkDomains.linkingDomain, pattern));
|
|
26081
26119
|
}
|
|
26082
26120
|
}
|
|
26083
|
-
const combined =
|
|
26121
|
+
const combined = and21(...conditions);
|
|
26084
26122
|
if (!combined) throw new Error("BACKLINK_FILTER_PATTERNS is unexpectedly empty");
|
|
26085
26123
|
return combined;
|
|
26086
26124
|
}
|
|
@@ -26155,7 +26193,7 @@ function latestSummaryForProject(db, projectId, source, release) {
|
|
|
26155
26193
|
eq27(backlinkSummaries.source, source)
|
|
26156
26194
|
];
|
|
26157
26195
|
if (release) conditions.push(eq27(backlinkSummaries.release, release));
|
|
26158
|
-
return db.select().from(backlinkSummaries).where(
|
|
26196
|
+
return db.select().from(backlinkSummaries).where(and22(...conditions)).orderBy(desc14(backlinkSummaries.queriedAt)).limit(1).get();
|
|
26159
26197
|
}
|
|
26160
26198
|
function parseExcludeCrawlers(value) {
|
|
26161
26199
|
if (!value) return false;
|
|
@@ -26163,12 +26201,12 @@ function parseExcludeCrawlers(value) {
|
|
|
26163
26201
|
return lower === "1" || lower === "true" || lower === "yes";
|
|
26164
26202
|
}
|
|
26165
26203
|
function computeFilteredSummary(db, base) {
|
|
26166
|
-
const baseDomainCondition =
|
|
26204
|
+
const baseDomainCondition = and22(
|
|
26167
26205
|
eq27(backlinkDomains.projectId, base.projectId),
|
|
26168
26206
|
eq27(backlinkDomains.source, base.source),
|
|
26169
26207
|
eq27(backlinkDomains.release, base.release)
|
|
26170
26208
|
);
|
|
26171
|
-
const filteredCondition =
|
|
26209
|
+
const filteredCondition = and22(baseDomainCondition, backlinkCrawlerExclusionClause());
|
|
26172
26210
|
const unfilteredAgg = db.select({
|
|
26173
26211
|
count: sql11`count(*)`,
|
|
26174
26212
|
total: sql11`coalesce(sum(${backlinkDomains.numHosts}), 0)`
|
|
@@ -26198,10 +26236,10 @@ function computeFilteredSummary(db, base) {
|
|
|
26198
26236
|
};
|
|
26199
26237
|
}
|
|
26200
26238
|
function buildSourceAvailability(db, projectId, source, connected, excludeCrawlers) {
|
|
26201
|
-
const summary = db.select().from(backlinkSummaries).where(
|
|
26239
|
+
const summary = db.select().from(backlinkSummaries).where(and22(eq27(backlinkSummaries.projectId, projectId), eq27(backlinkSummaries.source, source))).orderBy(desc14(backlinkSummaries.queriedAt)).limit(1).get();
|
|
26202
26240
|
let totalLinkingDomains = summary?.totalLinkingDomains ?? 0;
|
|
26203
26241
|
if (summary && excludeCrawlers) {
|
|
26204
|
-
const filtered = db.select({ count: sql11`count(*)` }).from(backlinkDomains).where(
|
|
26242
|
+
const filtered = db.select({ count: sql11`count(*)` }).from(backlinkDomains).where(and22(
|
|
26205
26243
|
eq27(backlinkDomains.projectId, projectId),
|
|
26206
26244
|
eq27(backlinkDomains.source, source),
|
|
26207
26245
|
eq27(backlinkDomains.release, summary.release),
|
|
@@ -26384,12 +26422,12 @@ async function backlinksRoutes(app, opts) {
|
|
|
26384
26422
|
const limit = Math.min(Math.max(parseInt(request.query.limit ?? "50", 10) || 50, 1), 500);
|
|
26385
26423
|
const offset = Math.max(parseInt(request.query.offset ?? "0", 10) || 0, 0);
|
|
26386
26424
|
const excludeCrawlers = parseExcludeCrawlers(request.query.excludeCrawlers);
|
|
26387
|
-
const baseDomainCondition =
|
|
26425
|
+
const baseDomainCondition = and22(
|
|
26388
26426
|
eq27(backlinkDomains.projectId, project.id),
|
|
26389
26427
|
eq27(backlinkDomains.source, source),
|
|
26390
26428
|
eq27(backlinkDomains.release, targetRelease)
|
|
26391
26429
|
);
|
|
26392
|
-
const domainCondition = excludeCrawlers ?
|
|
26430
|
+
const domainCondition = excludeCrawlers ? and22(baseDomainCondition, backlinkCrawlerExclusionClause()) : baseDomainCondition;
|
|
26393
26431
|
const totalRow = app.db.select({ count: sql11`count(*)` }).from(backlinkDomains).where(domainCondition).get();
|
|
26394
26432
|
const rows = app.db.select({
|
|
26395
26433
|
linkingDomain: backlinkDomains.linkingDomain,
|
|
@@ -26413,7 +26451,7 @@ async function backlinksRoutes(app, opts) {
|
|
|
26413
26451
|
async (request, reply) => {
|
|
26414
26452
|
const project = resolveProject(app.db, request.params.name);
|
|
26415
26453
|
const source = parseSourceParam(request.query.source);
|
|
26416
|
-
const rows = app.db.select().from(backlinkSummaries).where(
|
|
26454
|
+
const rows = app.db.select().from(backlinkSummaries).where(and22(eq27(backlinkSummaries.projectId, project.id), eq27(backlinkSummaries.source, source))).orderBy(asc4(backlinkSummaries.queriedAt)).all();
|
|
26417
26455
|
const response = rows.map((r) => ({
|
|
26418
26456
|
release: r.release,
|
|
26419
26457
|
totalLinkingDomains: r.totalLinkingDomains,
|
|
@@ -26469,7 +26507,7 @@ async function backlinksRoutes(app, opts) {
|
|
|
26469
26507
|
// ../api-routes/src/traffic.ts
|
|
26470
26508
|
import crypto25 from "crypto";
|
|
26471
26509
|
import { Agent as UndiciAgent } from "undici";
|
|
26472
|
-
import { and as
|
|
26510
|
+
import { and as and23, desc as desc15, eq as eq28, gte as gte4, lte as lte3, sql as sql12 } from "drizzle-orm";
|
|
26473
26511
|
|
|
26474
26512
|
// ../integration-cloud-run/src/auth.ts
|
|
26475
26513
|
import crypto24 from "crypto";
|
|
@@ -30328,28 +30366,28 @@ async function runBackfillTask(options) {
|
|
|
30328
30366
|
try {
|
|
30329
30367
|
app.db.transaction((tx) => {
|
|
30330
30368
|
tx.delete(crawlerEventsHourly).where(
|
|
30331
|
-
|
|
30369
|
+
and23(
|
|
30332
30370
|
eq28(crawlerEventsHourly.sourceId, sourceRow.id),
|
|
30333
30371
|
gte4(crawlerEventsHourly.tsHour, windowStartIso),
|
|
30334
30372
|
lte3(crawlerEventsHourly.tsHour, windowEndIso)
|
|
30335
30373
|
)
|
|
30336
30374
|
).run();
|
|
30337
30375
|
tx.delete(aiUserFetchEventsHourly).where(
|
|
30338
|
-
|
|
30376
|
+
and23(
|
|
30339
30377
|
eq28(aiUserFetchEventsHourly.sourceId, sourceRow.id),
|
|
30340
30378
|
gte4(aiUserFetchEventsHourly.tsHour, windowStartIso),
|
|
30341
30379
|
lte3(aiUserFetchEventsHourly.tsHour, windowEndIso)
|
|
30342
30380
|
)
|
|
30343
30381
|
).run();
|
|
30344
30382
|
tx.delete(aiReferralEventsHourly).where(
|
|
30345
|
-
|
|
30383
|
+
and23(
|
|
30346
30384
|
eq28(aiReferralEventsHourly.sourceId, sourceRow.id),
|
|
30347
30385
|
gte4(aiReferralEventsHourly.tsHour, windowStartIso),
|
|
30348
30386
|
lte3(aiReferralEventsHourly.tsHour, windowEndIso)
|
|
30349
30387
|
)
|
|
30350
30388
|
).run();
|
|
30351
30389
|
tx.delete(rawEventSamples).where(
|
|
30352
|
-
|
|
30390
|
+
and23(
|
|
30353
30391
|
eq28(rawEventSamples.sourceId, sourceRow.id),
|
|
30354
30392
|
gte4(rawEventSamples.ts, windowStartIso),
|
|
30355
30393
|
lte3(rawEventSamples.ts, windowEndIso)
|
|
@@ -30732,7 +30770,7 @@ async function trafficRoutes(app, opts) {
|
|
|
30732
30770
|
row = tx.select().from(trafficSources).where(eq28(trafficSources.id, newId)).get();
|
|
30733
30771
|
}
|
|
30734
30772
|
const existingSchedule = tx.select().from(schedules).where(
|
|
30735
|
-
|
|
30773
|
+
and23(
|
|
30736
30774
|
eq28(schedules.projectId, project.id),
|
|
30737
30775
|
eq28(schedules.kind, SchedulableRunKinds["traffic-sync"])
|
|
30738
30776
|
)
|
|
@@ -31454,7 +31492,7 @@ async function trafficRoutes(app, opts) {
|
|
|
31454
31492
|
pathNormalized: crawlerEventsHourly.pathNormalized,
|
|
31455
31493
|
hits: sql12`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
|
|
31456
31494
|
}).from(crawlerEventsHourly).where(
|
|
31457
|
-
|
|
31495
|
+
and23(
|
|
31458
31496
|
eq28(crawlerEventsHourly.sourceId, row.id),
|
|
31459
31497
|
gte4(crawlerEventsHourly.tsHour, since)
|
|
31460
31498
|
)
|
|
@@ -31464,25 +31502,25 @@ async function trafficRoutes(app, opts) {
|
|
|
31464
31502
|
);
|
|
31465
31503
|
const crawlerTotal = crawlerSegments.content + crawlerSegments.sitemap + crawlerSegments.robots + crawlerSegments.asset + crawlerSegments.other;
|
|
31466
31504
|
const aiUserFetchTotals = app.db.select({ total: sql12`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
|
|
31467
|
-
|
|
31505
|
+
and23(
|
|
31468
31506
|
eq28(aiUserFetchEventsHourly.sourceId, row.id),
|
|
31469
31507
|
gte4(aiUserFetchEventsHourly.tsHour, since)
|
|
31470
31508
|
)
|
|
31471
31509
|
).get();
|
|
31472
31510
|
const aiTotals = app.db.select({ total: sql12`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
|
|
31473
|
-
|
|
31511
|
+
and23(
|
|
31474
31512
|
eq28(aiReferralEventsHourly.sourceId, row.id),
|
|
31475
31513
|
gte4(aiReferralEventsHourly.tsHour, since)
|
|
31476
31514
|
)
|
|
31477
31515
|
).get();
|
|
31478
31516
|
const sampleTotals = app.db.select({ total: sql12`COUNT(*)` }).from(rawEventSamples).where(
|
|
31479
|
-
|
|
31517
|
+
and23(
|
|
31480
31518
|
eq28(rawEventSamples.sourceId, row.id),
|
|
31481
31519
|
gte4(rawEventSamples.ts, since)
|
|
31482
31520
|
)
|
|
31483
31521
|
).get();
|
|
31484
31522
|
const latestRun = app.db.select().from(runs).where(
|
|
31485
|
-
|
|
31523
|
+
and23(
|
|
31486
31524
|
eq28(runs.projectId, projectId),
|
|
31487
31525
|
eq28(runs.kind, RunKinds["traffic-sync"]),
|
|
31488
31526
|
eq28(runs.sourceId, row.id)
|
|
@@ -31516,7 +31554,7 @@ async function trafficRoutes(app, opts) {
|
|
|
31516
31554
|
"`advanceToNow` must be `true`. There is no implicit reset."
|
|
31517
31555
|
);
|
|
31518
31556
|
}
|
|
31519
|
-
const sourceRow = app.db.select().from(trafficSources).where(
|
|
31557
|
+
const sourceRow = app.db.select().from(trafficSources).where(and23(eq28(trafficSources.projectId, project.id), eq28(trafficSources.id, request.params.id))).get();
|
|
31520
31558
|
if (!sourceRow) {
|
|
31521
31559
|
throw notFound("traffic source", request.params.id);
|
|
31522
31560
|
}
|
|
@@ -31621,7 +31659,7 @@ async function trafficRoutes(app, opts) {
|
|
|
31621
31659
|
lte3(crawlerEventsHourly.tsHour, untilIso)
|
|
31622
31660
|
];
|
|
31623
31661
|
if (sourceIdParam) crawlerFilters.push(eq28(crawlerEventsHourly.sourceId, sourceIdParam));
|
|
31624
|
-
const crawlerWhere =
|
|
31662
|
+
const crawlerWhere = and23(...crawlerFilters);
|
|
31625
31663
|
const pathTotals = app.db.select({
|
|
31626
31664
|
pathNormalized: crawlerEventsHourly.pathNormalized,
|
|
31627
31665
|
hits: sql12`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
|
|
@@ -31653,7 +31691,7 @@ async function trafficRoutes(app, opts) {
|
|
|
31653
31691
|
lte3(aiUserFetchEventsHourly.tsHour, untilIso)
|
|
31654
31692
|
];
|
|
31655
31693
|
if (sourceIdParam) userFetchFilters.push(eq28(aiUserFetchEventsHourly.sourceId, sourceIdParam));
|
|
31656
|
-
const userFetchWhere =
|
|
31694
|
+
const userFetchWhere = and23(...userFetchFilters);
|
|
31657
31695
|
const total = app.db.select({ total: sql12`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(userFetchWhere).get();
|
|
31658
31696
|
aiUserFetchTotal = Number(total?.total ?? 0);
|
|
31659
31697
|
const rows = app.db.select().from(aiUserFetchEventsHourly).where(userFetchWhere).orderBy(desc15(aiUserFetchEventsHourly.tsHour)).limit(limit).all();
|
|
@@ -31678,7 +31716,7 @@ async function trafficRoutes(app, opts) {
|
|
|
31678
31716
|
lte3(aiReferralEventsHourly.tsHour, untilIso)
|
|
31679
31717
|
];
|
|
31680
31718
|
if (sourceIdParam) aiFilters.push(eq28(aiReferralEventsHourly.sourceId, sourceIdParam));
|
|
31681
|
-
const aiWhere =
|
|
31719
|
+
const aiWhere = and23(...aiFilters);
|
|
31682
31720
|
const total = app.db.select({ total: sql12`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(aiWhere).get();
|
|
31683
31721
|
aiReferralTotal = Number(total?.total ?? 0);
|
|
31684
31722
|
const rows = app.db.select().from(aiReferralEventsHourly).where(aiWhere).orderBy(desc15(aiReferralEventsHourly.tsHour)).limit(limit).all();
|
|
@@ -31885,7 +31923,7 @@ function readInstalledManifest(skillDir) {
|
|
|
31885
31923
|
var AGENT_CHECKS = [skillsInstalledCheck, skillsCurrentCheck];
|
|
31886
31924
|
|
|
31887
31925
|
// ../api-routes/src/doctor/checks/backlinks.ts
|
|
31888
|
-
import { and as
|
|
31926
|
+
import { and as and24, eq as eq29 } from "drizzle-orm";
|
|
31889
31927
|
function skippedNoProject() {
|
|
31890
31928
|
return {
|
|
31891
31929
|
status: CheckStatuses.skipped,
|
|
@@ -31917,7 +31955,7 @@ var BACKLINKS_CHECKS = [
|
|
|
31917
31955
|
details: { commoncrawl: ccConnected, bingWebmaster: bingConnected }
|
|
31918
31956
|
};
|
|
31919
31957
|
}
|
|
31920
|
-
const ccHasData = ccConnected ? !!ctx.db.select({ id: backlinkSummaries.id }).from(backlinkSummaries).where(
|
|
31958
|
+
const ccHasData = ccConnected ? !!ctx.db.select({ id: backlinkSummaries.id }).from(backlinkSummaries).where(and24(
|
|
31921
31959
|
eq29(backlinkSummaries.projectId, ctx.project.id),
|
|
31922
31960
|
eq29(backlinkSummaries.source, BacklinkSources.commoncrawl)
|
|
31923
31961
|
)).limit(1).get() : false;
|
|
@@ -32442,7 +32480,7 @@ var ga4ConnectionCheck = {
|
|
|
32442
32480
|
var GA_AUTH_CHECKS = [ga4ConnectionCheck];
|
|
32443
32481
|
|
|
32444
32482
|
// ../api-routes/src/doctor/checks/gbp-auth.ts
|
|
32445
|
-
import { and as
|
|
32483
|
+
import { and as and25, eq as eq32 } from "drizzle-orm";
|
|
32446
32484
|
var RECENT_SYNC_WARN_DAYS2 = 7;
|
|
32447
32485
|
var RECENT_SYNC_FAIL_DAYS2 = 30;
|
|
32448
32486
|
function skippedNoProject3() {
|
|
@@ -32675,7 +32713,7 @@ var recentSyncCheck = {
|
|
|
32675
32713
|
title: "GBP recent sync",
|
|
32676
32714
|
run: (ctx) => {
|
|
32677
32715
|
if (!ctx.project) return skippedNoProject3();
|
|
32678
|
-
const selected = ctx.db.select({ locationName: gbpLocations.locationName, syncedAt: gbpLocations.syncedAt }).from(gbpLocations).where(
|
|
32716
|
+
const selected = ctx.db.select({ locationName: gbpLocations.locationName, syncedAt: gbpLocations.syncedAt }).from(gbpLocations).where(and25(eq32(gbpLocations.projectId, ctx.project.id), eq32(gbpLocations.selected, true))).all();
|
|
32679
32717
|
if (selected.length === 0) {
|
|
32680
32718
|
return {
|
|
32681
32719
|
status: CheckStatuses.skipped,
|
|
@@ -33277,7 +33315,7 @@ var RUNTIME_STATE_CHECKS = [
|
|
|
33277
33315
|
];
|
|
33278
33316
|
|
|
33279
33317
|
// ../api-routes/src/doctor/checks/traffic-source.ts
|
|
33280
|
-
import { and as
|
|
33318
|
+
import { and as and26, eq as eq34, gte as gte5, ne as ne4, sql as sql13 } from "drizzle-orm";
|
|
33281
33319
|
var RECENT_DATA_WARN_DAYS = 7;
|
|
33282
33320
|
var RECENT_DATA_FAIL_DAYS = 30;
|
|
33283
33321
|
function skippedNoProject5() {
|
|
@@ -33291,7 +33329,7 @@ function skippedNoProject5() {
|
|
|
33291
33329
|
function loadProbes(ctx) {
|
|
33292
33330
|
if (!ctx.project) return [];
|
|
33293
33331
|
const rows = ctx.db.select().from(trafficSources).where(
|
|
33294
|
-
|
|
33332
|
+
and26(
|
|
33295
33333
|
eq34(trafficSources.projectId, ctx.project.id),
|
|
33296
33334
|
ne4(trafficSources.status, TrafficSourceStatuses.archived)
|
|
33297
33335
|
)
|
|
@@ -33372,7 +33410,7 @@ var recentDataCheck = {
|
|
|
33372
33410
|
const failCutoff = new Date(now.getTime() - RECENT_DATA_FAIL_DAYS * 24 * 60 * 6e4).toISOString();
|
|
33373
33411
|
const recentCrawlers = Number(
|
|
33374
33412
|
ctx.db.select({ total: sql13`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
|
|
33375
|
-
|
|
33413
|
+
and26(
|
|
33376
33414
|
eq34(crawlerEventsHourly.projectId, ctx.project.id),
|
|
33377
33415
|
gte5(crawlerEventsHourly.tsHour, warnCutoff)
|
|
33378
33416
|
)
|
|
@@ -33380,7 +33418,7 @@ var recentDataCheck = {
|
|
|
33380
33418
|
);
|
|
33381
33419
|
const recentReferrals = Number(
|
|
33382
33420
|
ctx.db.select({ total: sql13`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
|
|
33383
|
-
|
|
33421
|
+
and26(
|
|
33384
33422
|
eq34(aiReferralEventsHourly.projectId, ctx.project.id),
|
|
33385
33423
|
gte5(aiReferralEventsHourly.tsHour, warnCutoff)
|
|
33386
33424
|
)
|
|
@@ -33396,7 +33434,7 @@ var recentDataCheck = {
|
|
|
33396
33434
|
}
|
|
33397
33435
|
const olderCrawlers = Number(
|
|
33398
33436
|
ctx.db.select({ total: sql13`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
|
|
33399
|
-
|
|
33437
|
+
and26(
|
|
33400
33438
|
eq34(crawlerEventsHourly.projectId, ctx.project.id),
|
|
33401
33439
|
gte5(crawlerEventsHourly.tsHour, failCutoff)
|
|
33402
33440
|
)
|
|
@@ -33404,7 +33442,7 @@ var recentDataCheck = {
|
|
|
33404
33442
|
);
|
|
33405
33443
|
const olderReferrals = Number(
|
|
33406
33444
|
ctx.db.select({ total: sql13`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
|
|
33407
|
-
|
|
33445
|
+
and26(
|
|
33408
33446
|
eq34(aiReferralEventsHourly.projectId, ctx.project.id),
|
|
33409
33447
|
gte5(aiReferralEventsHourly.tsHour, failCutoff)
|
|
33410
33448
|
)
|
|
@@ -33821,7 +33859,7 @@ async function doctorRoutes(app, opts) {
|
|
|
33821
33859
|
|
|
33822
33860
|
// ../api-routes/src/discovery/routes.ts
|
|
33823
33861
|
import crypto27 from "crypto";
|
|
33824
|
-
import { and as
|
|
33862
|
+
import { and as and27, desc as desc16, eq as eq35, gte as gte6, inArray as inArray12, isNull, or as or5 } from "drizzle-orm";
|
|
33825
33863
|
var MAX_INFLIGHT_DISCOVERY_AGE_MS = 2 * 60 * 60 * 1e3;
|
|
33826
33864
|
async function discoveryRoutes(app, opts) {
|
|
33827
33865
|
app.post("/projects/:name/discover/run", async (request, reply) => {
|
|
@@ -33855,7 +33893,7 @@ async function discoveryRoutes(app, opts) {
|
|
|
33855
33893
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
33856
33894
|
const ageFloorIso = new Date(Date.now() - MAX_INFLIGHT_DISCOVERY_AGE_MS).toISOString();
|
|
33857
33895
|
const decision = app.db.transaction((tx) => {
|
|
33858
|
-
const existing = tx.select({ id: discoverySessions.id, runId: discoverySessions.runId }).from(discoverySessions).where(
|
|
33896
|
+
const existing = tx.select({ id: discoverySessions.id, runId: discoverySessions.runId }).from(discoverySessions).where(and27(
|
|
33859
33897
|
eq35(discoverySessions.projectId, project.id),
|
|
33860
33898
|
eq35(discoverySessions.icpDescription, icpDescription),
|
|
33861
33899
|
// Buyer is part of session identity: it changes the seed prompt's
|
|
@@ -34501,7 +34539,7 @@ function dedupeStrings(input) {
|
|
|
34501
34539
|
|
|
34502
34540
|
// ../api-routes/src/technical-aeo.ts
|
|
34503
34541
|
import crypto29 from "crypto";
|
|
34504
|
-
import { and as
|
|
34542
|
+
import { and as and28, asc as asc5, count, desc as desc17, eq as eq37, inArray as inArray13 } from "drizzle-orm";
|
|
34505
34543
|
var SURFACEABLE_STATUSES = [RunStatuses.completed, RunStatuses.partial];
|
|
34506
34544
|
function emptyScore(projectName) {
|
|
34507
34545
|
return {
|
|
@@ -34533,7 +34571,7 @@ function parsePositiveInt(value, fallback, max) {
|
|
|
34533
34571
|
async function technicalAeoRoutes(app, opts) {
|
|
34534
34572
|
app.get("/projects/:name/technical-aeo", async (request) => {
|
|
34535
34573
|
const project = resolveProject(app.db, request.params.name);
|
|
34536
|
-
const rows = app.db.select({ snap: siteAuditSnapshots, runStatus: runs.status }).from(siteAuditSnapshots).innerJoin(runs, eq37(siteAuditSnapshots.runId, runs.id)).where(
|
|
34574
|
+
const rows = app.db.select({ snap: siteAuditSnapshots, runStatus: runs.status }).from(siteAuditSnapshots).innerJoin(runs, eq37(siteAuditSnapshots.runId, runs.id)).where(and28(
|
|
34537
34575
|
eq37(siteAuditSnapshots.projectId, project.id),
|
|
34538
34576
|
eq37(runs.kind, RunKinds["site-audit"]),
|
|
34539
34577
|
inArray13(runs.status, SURFACEABLE_STATUSES),
|
|
@@ -34568,7 +34606,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
34568
34606
|
});
|
|
34569
34607
|
app.get("/projects/:name/technical-aeo/pages", async (request) => {
|
|
34570
34608
|
const project = resolveProject(app.db, request.params.name);
|
|
34571
|
-
const latest = app.db.select({ runId: siteAuditSnapshots.runId, auditedAt: siteAuditSnapshots.auditedAt }).from(siteAuditSnapshots).innerJoin(runs, eq37(siteAuditSnapshots.runId, runs.id)).where(
|
|
34609
|
+
const latest = app.db.select({ runId: siteAuditSnapshots.runId, auditedAt: siteAuditSnapshots.auditedAt }).from(siteAuditSnapshots).innerJoin(runs, eq37(siteAuditSnapshots.runId, runs.id)).where(and28(
|
|
34572
34610
|
eq37(siteAuditSnapshots.projectId, project.id),
|
|
34573
34611
|
eq37(runs.kind, RunKinds["site-audit"]),
|
|
34574
34612
|
inArray13(runs.status, SURFACEABLE_STATUSES),
|
|
@@ -34580,7 +34618,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
34580
34618
|
const statusFilter = request.query.status === "success" || request.query.status === "error" ? request.query.status : null;
|
|
34581
34619
|
const conds = [eq37(siteAuditPages.runId, latest.runId)];
|
|
34582
34620
|
if (statusFilter) conds.push(eq37(siteAuditPages.status, statusFilter));
|
|
34583
|
-
const where =
|
|
34621
|
+
const where = and28(...conds);
|
|
34584
34622
|
const totalRow = app.db.select({ value: count() }).from(siteAuditPages).where(where).get();
|
|
34585
34623
|
const total = totalRow?.value ?? 0;
|
|
34586
34624
|
const limit = parsePositiveInt(request.query.limit, 100, 500);
|
|
@@ -34604,7 +34642,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
34604
34642
|
auditedAt: siteAuditSnapshots.auditedAt,
|
|
34605
34643
|
aggregateScore: siteAuditSnapshots.aggregateScore,
|
|
34606
34644
|
pagesAudited: siteAuditSnapshots.pagesAudited
|
|
34607
|
-
}).from(siteAuditSnapshots).innerJoin(runs, eq37(siteAuditSnapshots.runId, runs.id)).where(
|
|
34645
|
+
}).from(siteAuditSnapshots).innerJoin(runs, eq37(siteAuditSnapshots.runId, runs.id)).where(and28(
|
|
34608
34646
|
eq37(siteAuditSnapshots.projectId, project.id),
|
|
34609
34647
|
eq37(runs.kind, RunKinds["site-audit"]),
|
|
34610
34648
|
inArray13(runs.status, SURFACEABLE_STATUSES),
|
|
@@ -34618,7 +34656,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
34618
34656
|
if (!parsed.success) {
|
|
34619
34657
|
throw validationError(parsed.error.issues[0]?.message ?? "Invalid site-audit request");
|
|
34620
34658
|
}
|
|
34621
|
-
const existing = app.db.select({ id: runs.id, status: runs.status }).from(runs).where(
|
|
34659
|
+
const existing = app.db.select({ id: runs.id, status: runs.status }).from(runs).where(and28(
|
|
34622
34660
|
eq37(runs.projectId, project.id),
|
|
34623
34661
|
eq37(runs.kind, RunKinds["site-audit"]),
|
|
34624
34662
|
inArray13(runs.status, [RunStatuses.queued, RunStatuses.running])
|
|
@@ -35211,7 +35249,7 @@ var IntelligenceService = class {
|
|
|
35211
35249
|
*/
|
|
35212
35250
|
analyzeAndPersist(runId, projectId) {
|
|
35213
35251
|
const recentRuns = this.db.select().from(runs).where(
|
|
35214
|
-
|
|
35252
|
+
and29(
|
|
35215
35253
|
eq38(runs.projectId, projectId),
|
|
35216
35254
|
or6(eq38(runs.status, "completed"), eq38(runs.status, "partial")),
|
|
35217
35255
|
// Defensive: RunCoordinator already skips probes before this is
|
|
@@ -35303,7 +35341,7 @@ var IntelligenceService = class {
|
|
|
35303
35341
|
}
|
|
35304
35342
|
const windowStart = runRow.startedAt ?? runRow.createdAt;
|
|
35305
35343
|
const windowEnd = runRow.finishedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
35306
|
-
const selected = this.db.select().from(gbpLocations).where(
|
|
35344
|
+
const selected = this.db.select().from(gbpLocations).where(and29(
|
|
35307
35345
|
eq38(gbpLocations.projectId, projectId),
|
|
35308
35346
|
eq38(gbpLocations.selected, true),
|
|
35309
35347
|
gte7(gbpLocations.syncedAt, windowStart),
|
|
@@ -35340,12 +35378,12 @@ var IntelligenceService = class {
|
|
|
35340
35378
|
}
|
|
35341
35379
|
/** Build the per-location signal bundle the GBP analyzer consumes. */
|
|
35342
35380
|
buildGbpLocationSignals(projectId, locationName, displayName, fallbackDate) {
|
|
35343
|
-
const metricRows = this.db.select({ metric: gbpDailyMetrics.metric, date: gbpDailyMetrics.date, value: gbpDailyMetrics.value }).from(gbpDailyMetrics).where(
|
|
35344
|
-
const placeActionRows = this.db.select({ placeActionType: gbpPlaceActions.placeActionType, providerType: gbpPlaceActions.providerType }).from(gbpPlaceActions).where(
|
|
35345
|
-
const lodgingRow = this.db.select({ populatedGroupCount: gbpLodgingSnapshots.populatedGroupCount }).from(gbpLodgingSnapshots).where(
|
|
35346
|
-
const ownerRow = this.db.select({ description: gbpLocations.description }).from(gbpLocations).where(
|
|
35381
|
+
const metricRows = this.db.select({ metric: gbpDailyMetrics.metric, date: gbpDailyMetrics.date, value: gbpDailyMetrics.value }).from(gbpDailyMetrics).where(and29(eq38(gbpDailyMetrics.projectId, projectId), eq38(gbpDailyMetrics.locationName, locationName))).all();
|
|
35382
|
+
const placeActionRows = this.db.select({ placeActionType: gbpPlaceActions.placeActionType, providerType: gbpPlaceActions.providerType }).from(gbpPlaceActions).where(and29(eq38(gbpPlaceActions.projectId, projectId), eq38(gbpPlaceActions.locationName, locationName))).all();
|
|
35383
|
+
const lodgingRow = this.db.select({ populatedGroupCount: gbpLodgingSnapshots.populatedGroupCount }).from(gbpLodgingSnapshots).where(and29(eq38(gbpLodgingSnapshots.projectId, projectId), eq38(gbpLodgingSnapshots.locationName, locationName))).orderBy(desc18(gbpLodgingSnapshots.syncedAt)).limit(1).get();
|
|
35384
|
+
const ownerRow = this.db.select({ description: gbpLocations.description }).from(gbpLocations).where(and29(eq38(gbpLocations.projectId, projectId), eq38(gbpLocations.locationName, locationName))).get();
|
|
35347
35385
|
const descriptionMissing = !(ownerRow?.description ?? "").trim();
|
|
35348
|
-
const placeRow = this.db.select({ attributes: gbpPlaceDetails.attributes }).from(gbpPlaceDetails).where(
|
|
35386
|
+
const placeRow = this.db.select({ attributes: gbpPlaceDetails.attributes }).from(gbpPlaceDetails).where(and29(eq38(gbpPlaceDetails.projectId, projectId), eq38(gbpPlaceDetails.locationName, locationName))).orderBy(desc18(gbpPlaceDetails.syncedAt)).limit(1).get();
|
|
35349
35387
|
const placesAmenities = placeRow ? extractPlaceAmenities(placeRow.attributes) : [];
|
|
35350
35388
|
const summary = buildGbpSummary({
|
|
35351
35389
|
locationName,
|
|
@@ -35381,7 +35419,7 @@ var IntelligenceService = class {
|
|
|
35381
35419
|
/** Build the month-over-month keyword series for a location from the
|
|
35382
35420
|
* accumulating gbp_keyword_monthly table (latest complete month vs prior). */
|
|
35383
35421
|
buildGbpKeywordTrend(projectId, locationName) {
|
|
35384
|
-
const rows = this.db.select({ month: gbpKeywordMonthly.month, keyword: gbpKeywordMonthly.keyword, valueCount: gbpKeywordMonthly.valueCount }).from(gbpKeywordMonthly).where(
|
|
35422
|
+
const rows = this.db.select({ month: gbpKeywordMonthly.month, keyword: gbpKeywordMonthly.keyword, valueCount: gbpKeywordMonthly.valueCount }).from(gbpKeywordMonthly).where(and29(eq38(gbpKeywordMonthly.projectId, projectId), eq38(gbpKeywordMonthly.locationName, locationName))).all();
|
|
35385
35423
|
if (rows.length === 0) return { recentMonth: null, priorMonth: null, points: [] };
|
|
35386
35424
|
const months = [...new Set(rows.map((r) => r.month))].sort().reverse();
|
|
35387
35425
|
const recentMonth = months[0] ?? null;
|
|
@@ -35412,7 +35450,7 @@ var IntelligenceService = class {
|
|
|
35412
35450
|
*/
|
|
35413
35451
|
persistGbpInsights(runId, projectId, gbpInsights, coveredLocationNames) {
|
|
35414
35452
|
const covered = new Set(coveredLocationNames);
|
|
35415
|
-
const existing = this.db.select({ id: insights.id, dismissed: insights.dismissed }).from(insights).where(
|
|
35453
|
+
const existing = this.db.select({ id: insights.id, dismissed: insights.dismissed }).from(insights).where(and29(eq38(insights.projectId, projectId), eq38(insights.provider, GBP_INSIGHT_PROVIDER))).all();
|
|
35416
35454
|
const staleIds = [];
|
|
35417
35455
|
const dismissedSlots = /* @__PURE__ */ new Set();
|
|
35418
35456
|
for (const row of existing) {
|
|
@@ -35514,7 +35552,7 @@ var IntelligenceService = class {
|
|
|
35514
35552
|
sinceTimestamp = parsed;
|
|
35515
35553
|
}
|
|
35516
35554
|
const allRuns = this.db.select().from(runs).where(
|
|
35517
|
-
|
|
35555
|
+
and29(
|
|
35518
35556
|
eq38(runs.projectId, project.id),
|
|
35519
35557
|
or6(eq38(runs.status, "completed"), eq38(runs.status, "partial")),
|
|
35520
35558
|
// Backfill must not replay probe runs as if they were real sweeps.
|
|
@@ -35691,7 +35729,7 @@ var IntelligenceService = class {
|
|
|
35691
35729
|
);
|
|
35692
35730
|
const ROWS_PER_GROUP_BUDGET = Math.max(2, locationCount);
|
|
35693
35731
|
const recentRunRows = this.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(
|
|
35694
|
-
|
|
35732
|
+
and29(
|
|
35695
35733
|
eq38(runs.projectId, projectId),
|
|
35696
35734
|
eq38(runs.kind, RunKinds["answer-visibility"]),
|
|
35697
35735
|
or6(eq38(runs.status, "completed"), eq38(runs.status, "partial")),
|
|
@@ -35714,7 +35752,7 @@ var IntelligenceService = class {
|
|
|
35714
35752
|
const haveHistory = recentRunIds.length > 0;
|
|
35715
35753
|
const priorRegressionsByPair = /* @__PURE__ */ new Map();
|
|
35716
35754
|
if (haveHistory) {
|
|
35717
|
-
const priorRows = this.db.select({ query: insights.query, provider: insights.provider, runId: insights.runId }).from(insights).where(
|
|
35755
|
+
const priorRows = this.db.select({ query: insights.query, provider: insights.provider, runId: insights.runId }).from(insights).where(and29(eq38(insights.type, "regression"), inArray14(insights.runId, recentRunIds))).all();
|
|
35718
35756
|
const regressionGroups = /* @__PURE__ */ new Map();
|
|
35719
35757
|
for (const row of priorRows) {
|
|
35720
35758
|
if (!row.runId) continue;
|