@ainyc/canonry 4.35.0 → 4.36.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/{index-u7ZXZ5mA.js → index-CAmKaZIt.js} +72 -72
- package/assets/assets/index-CTrHzgs-.css +1 -0
- package/assets/index.html +2 -2
- package/dist/{chunk-NLV4MZZF.js → chunk-F2G67CIU.js} +359 -236
- package/dist/{chunk-MLS5KJWK.js → chunk-JQQXMCQ7.js} +132 -16
- package/dist/{chunk-B3FBOECD.js → chunk-O7S623DL.js} +15 -1
- package/dist/{chunk-EM5GVF3C.js → chunk-XJVYVURK.js} +3 -1
- package/dist/cli.js +61 -27
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-WAJOEOJV.js → intelligence-service-7AWRUNI2.js} +2 -2
- package/dist/mcp.js +2 -2
- package/package.json +4 -4
- package/assets/assets/index-Cfv0_lwq.css +0 -1
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
loadConfig,
|
|
6
6
|
loadConfigRaw,
|
|
7
7
|
saveConfigPatch
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-O7S623DL.js";
|
|
9
9
|
import {
|
|
10
10
|
DEFAULT_RUN_HISTORY_LIMIT,
|
|
11
11
|
IntelligenceService,
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
buildContentTargetRows,
|
|
30
30
|
buildGapQueryScore,
|
|
31
31
|
buildInventory,
|
|
32
|
+
buildMentionCoverage,
|
|
32
33
|
buildMentionLandscape,
|
|
33
34
|
buildMovementSummary,
|
|
34
35
|
buildOverviewCompetitors,
|
|
@@ -73,7 +74,7 @@ import {
|
|
|
73
74
|
schedules,
|
|
74
75
|
trafficSources,
|
|
75
76
|
usageCounters
|
|
76
|
-
} from "./chunk-
|
|
77
|
+
} from "./chunk-JQQXMCQ7.js";
|
|
77
78
|
import {
|
|
78
79
|
AGENT_MEMORY_VALUE_MAX_BYTES,
|
|
79
80
|
AGENT_PROVIDER_IDS,
|
|
@@ -186,7 +187,7 @@ import {
|
|
|
186
187
|
visibilityStateFromAnswerMentioned,
|
|
187
188
|
windowCutoff,
|
|
188
189
|
wordpressEnvSchema
|
|
189
|
-
} from "./chunk-
|
|
190
|
+
} from "./chunk-XJVYVURK.js";
|
|
190
191
|
|
|
191
192
|
// src/telemetry.ts
|
|
192
193
|
import crypto from "crypto";
|
|
@@ -475,8 +476,8 @@ function checkLatestVersionForServer(opts) {
|
|
|
475
476
|
// src/server.ts
|
|
476
477
|
import { createRequire as createRequire4 } from "module";
|
|
477
478
|
import crypto34 from "crypto";
|
|
478
|
-
import
|
|
479
|
-
import
|
|
479
|
+
import fs13 from "fs";
|
|
480
|
+
import path15 from "path";
|
|
480
481
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
481
482
|
import { eq as eq41 } from "drizzle-orm";
|
|
482
483
|
import Fastify from "fastify";
|
|
@@ -548,7 +549,7 @@ async function authPlugin(app, opts = {}) {
|
|
|
548
549
|
|
|
549
550
|
// ../api-routes/src/projects.ts
|
|
550
551
|
import crypto4 from "crypto";
|
|
551
|
-
import { eq as eq3 } from "drizzle-orm";
|
|
552
|
+
import { eq as eq3, sql as sql2 } from "drizzle-orm";
|
|
552
553
|
|
|
553
554
|
// ../api-routes/src/helpers.ts
|
|
554
555
|
import crypto3 from "crypto";
|
|
@@ -726,6 +727,30 @@ async function projectRoutes(app, opts) {
|
|
|
726
727
|
const project = resolveProject(app.db, request.params.name);
|
|
727
728
|
return reply.send(formatProject(project));
|
|
728
729
|
});
|
|
730
|
+
app.get("/projects/:name/delete-preview", async (request, reply) => {
|
|
731
|
+
const project = resolveProject(app.db, request.params.name);
|
|
732
|
+
const pid = project.id;
|
|
733
|
+
const count = (n) => n ?? 0;
|
|
734
|
+
const queryCount = app.db.select({ n: sql2`count(*)` }).from(queries).where(eq3(queries.projectId, pid)).get();
|
|
735
|
+
const competitorCount = app.db.select({ n: sql2`count(*)` }).from(competitors).where(eq3(competitors.projectId, pid)).get();
|
|
736
|
+
const runCount = app.db.select({ n: sql2`count(*)` }).from(runs).where(eq3(runs.projectId, pid)).get();
|
|
737
|
+
const snapshotCount = app.db.select({ n: sql2`count(*)` }).from(querySnapshots).innerJoin(runs, eq3(querySnapshots.runId, runs.id)).where(eq3(runs.projectId, pid)).get();
|
|
738
|
+
const insightCount = app.db.select({ n: sql2`count(*)` }).from(insights).where(eq3(insights.projectId, pid)).get();
|
|
739
|
+
const auditLogCount = app.db.select({ n: sql2`count(*)` }).from(auditLog).where(eq3(auditLog.projectId, pid)).get();
|
|
740
|
+
return reply.send({
|
|
741
|
+
project: { id: project.id, name: project.name },
|
|
742
|
+
cascadeRows: {
|
|
743
|
+
queries: count(queryCount?.n),
|
|
744
|
+
competitors: count(competitorCount?.n),
|
|
745
|
+
runs: count(runCount?.n),
|
|
746
|
+
snapshots: count(snapshotCount?.n),
|
|
747
|
+
insights: count(insightCount?.n)
|
|
748
|
+
},
|
|
749
|
+
detachedRows: {
|
|
750
|
+
auditLog: count(auditLogCount?.n)
|
|
751
|
+
}
|
|
752
|
+
});
|
|
753
|
+
});
|
|
729
754
|
app.delete("/projects/:name", async (request, reply) => {
|
|
730
755
|
const project = resolveProject(app.db, request.params.name);
|
|
731
756
|
writeAuditLog(app.db, {
|
|
@@ -1300,7 +1325,7 @@ function parseCompetitorBatch(value) {
|
|
|
1300
1325
|
|
|
1301
1326
|
// ../api-routes/src/runs.ts
|
|
1302
1327
|
import crypto8 from "crypto";
|
|
1303
|
-
import { and as and2, eq as eq7, asc, desc, or as or2, sql as
|
|
1328
|
+
import { and as and2, eq as eq7, asc, desc, or as or2, sql as sql3 } from "drizzle-orm";
|
|
1304
1329
|
|
|
1305
1330
|
// ../api-routes/src/run-queue.ts
|
|
1306
1331
|
import crypto7 from "crypto";
|
|
@@ -1472,7 +1497,7 @@ async function runRoutes(app, opts) {
|
|
|
1472
1497
|
});
|
|
1473
1498
|
app.get("/projects/:name/runs/latest", async (request, reply) => {
|
|
1474
1499
|
const project = resolveProject(app.db, request.params.name);
|
|
1475
|
-
const countRow = app.db.select({ count:
|
|
1500
|
+
const countRow = app.db.select({ count: sql3`count(*)` }).from(runs).where(eq7(runs.projectId, project.id)).get();
|
|
1476
1501
|
const totalRuns = countRow?.count ?? 0;
|
|
1477
1502
|
const latestRun = app.db.select().from(runs).where(eq7(runs.projectId, project.id)).orderBy(desc(runs.createdAt), desc(runs.id)).limit(1).get();
|
|
1478
1503
|
if (!latestRun) {
|
|
@@ -1800,7 +1825,7 @@ async function deliverWebhook(target, payload, webhookSecret) {
|
|
|
1800
1825
|
const body = JSON.stringify(payload);
|
|
1801
1826
|
const isHttps = target.url.protocol === "https:";
|
|
1802
1827
|
const port = target.url.port ? Number(target.url.port) : isHttps ? 443 : 80;
|
|
1803
|
-
const
|
|
1828
|
+
const path16 = `${target.url.pathname}${target.url.search}`;
|
|
1804
1829
|
const headers = {
|
|
1805
1830
|
"Content-Length": String(Buffer.byteLength(body)),
|
|
1806
1831
|
"Content-Type": "application/json",
|
|
@@ -1816,7 +1841,7 @@ async function deliverWebhook(target, payload, webhookSecret) {
|
|
|
1816
1841
|
headers,
|
|
1817
1842
|
hostname: target.address,
|
|
1818
1843
|
method: "POST",
|
|
1819
|
-
path:
|
|
1844
|
+
path: path16,
|
|
1820
1845
|
port,
|
|
1821
1846
|
timeout: REQUEST_TIMEOUT_MS
|
|
1822
1847
|
};
|
|
@@ -2984,7 +3009,7 @@ async function intelligenceRoutes(app) {
|
|
|
2984
3009
|
}
|
|
2985
3010
|
|
|
2986
3011
|
// ../api-routes/src/report.ts
|
|
2987
|
-
import { and as and6, desc as desc6, eq as eq13, gte, inArray as inArray5, lt, lte, ne, or as or3, sql as
|
|
3012
|
+
import { and as and6, desc as desc6, eq as eq13, gte, inArray as inArray5, lt, lte, ne, or as or3, sql as sql4 } from "drizzle-orm";
|
|
2988
3013
|
|
|
2989
3014
|
// ../api-routes/src/report-renderer.ts
|
|
2990
3015
|
var COLORS = {
|
|
@@ -3033,9 +3058,9 @@ function inferAdSource(params) {
|
|
|
3033
3058
|
function formatLandingPageHtml(raw) {
|
|
3034
3059
|
const value = raw ?? "";
|
|
3035
3060
|
const queryIdx = value.indexOf("?");
|
|
3036
|
-
const
|
|
3061
|
+
const path16 = queryIdx === -1 ? value : value.slice(0, queryIdx);
|
|
3037
3062
|
const query = queryIdx === -1 ? "" : value.slice(queryIdx + 1);
|
|
3038
|
-
const pathHtml = `<span class="page-path">${escapeHtml(
|
|
3063
|
+
const pathHtml = `<span class="page-path">${escapeHtml(path16 || "/")}</span>`;
|
|
3039
3064
|
if (!query) return pathHtml;
|
|
3040
3065
|
let summary = "";
|
|
3041
3066
|
try {
|
|
@@ -4389,7 +4414,7 @@ function renderLineChart(points, color, title, height = 200) {
|
|
|
4389
4414
|
y: padY + usableH - p.y / max * usableH,
|
|
4390
4415
|
raw: p
|
|
4391
4416
|
}));
|
|
4392
|
-
const
|
|
4417
|
+
const path16 = xy.map((p, i) => `${i === 0 ? "M" : "L"} ${p.x.toFixed(1)} ${p.y.toFixed(1)}`).join(" ");
|
|
4393
4418
|
const dots = xy.map((p) => `<circle cx="${p.x.toFixed(1)}" cy="${p.y.toFixed(1)}" r="3" fill="${color}" />`).join("");
|
|
4394
4419
|
const xLabels = xy.map((p, i) => {
|
|
4395
4420
|
if (points.length > 8 && i % Math.ceil(points.length / 6) !== 0 && i !== points.length - 1) return "";
|
|
@@ -4401,7 +4426,7 @@ function renderLineChart(points, color, title, height = 200) {
|
|
|
4401
4426
|
<line x1="${padX}" y1="${padY + usableH}" x2="${padX + usableW}" y2="${padY + usableH}" stroke="${COLORS.border}" stroke-width="1" />
|
|
4402
4427
|
<text x="${padX - 6}" y="${(padY + 4).toFixed(1)}" fill="${COLORS.textFaint}" font-size="9" text-anchor="end">${formatNumber(max)}</text>
|
|
4403
4428
|
<text x="${padX - 6}" y="${(padY + usableH).toFixed(1)}" fill="${COLORS.textFaint}" font-size="9" text-anchor="end">0</text>
|
|
4404
|
-
<path d="${
|
|
4429
|
+
<path d="${path16}" stroke="${color}" stroke-width="2" fill="none" />
|
|
4405
4430
|
${dots}
|
|
4406
4431
|
${xLabels}
|
|
4407
4432
|
</svg>
|
|
@@ -5375,9 +5400,9 @@ function buildGaTrafficByPage(db, projectId) {
|
|
|
5375
5400
|
}).from(gaTrafficSnapshots).where(eq12(gaTrafficSnapshots.projectId, projectId)).all();
|
|
5376
5401
|
const map = /* @__PURE__ */ new Map();
|
|
5377
5402
|
for (const row of rows) {
|
|
5378
|
-
const
|
|
5379
|
-
if (!
|
|
5380
|
-
map.set(
|
|
5403
|
+
const path16 = extractPath(row.landingPage);
|
|
5404
|
+
if (!path16) continue;
|
|
5405
|
+
map.set(path16, (map.get(path16) ?? 0) + (row.sessions ?? 0));
|
|
5381
5406
|
}
|
|
5382
5407
|
return map;
|
|
5383
5408
|
}
|
|
@@ -5572,8 +5597,8 @@ function normalizeDomain(domain) {
|
|
|
5572
5597
|
function extractPath(url) {
|
|
5573
5598
|
if (!url) return "";
|
|
5574
5599
|
const match = /^https?:\/\/[^/]+(.*)$/.exec(url.trim());
|
|
5575
|
-
const
|
|
5576
|
-
const stripped =
|
|
5600
|
+
const path16 = match ? match[1] : url.trim();
|
|
5601
|
+
const stripped = path16.replace(/\/+$/, "");
|
|
5577
5602
|
return stripped || "/";
|
|
5578
5603
|
}
|
|
5579
5604
|
|
|
@@ -5860,7 +5885,7 @@ function buildAiReferrals(db, projectId) {
|
|
|
5860
5885
|
return { totalSessions: total, totalUsers, bySource, trend, topLandingPages };
|
|
5861
5886
|
}
|
|
5862
5887
|
function nonSubresourceReferralPathCondition() {
|
|
5863
|
-
return
|
|
5888
|
+
return sql4`
|
|
5864
5889
|
LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '/_next/static/%'
|
|
5865
5890
|
AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '/assets/%'
|
|
5866
5891
|
AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '/static/%'
|
|
@@ -5899,7 +5924,7 @@ function buildServerActivity(db, projectId) {
|
|
|
5899
5924
|
const priorStart = new Date(priorStartMs).toISOString();
|
|
5900
5925
|
const trendStart = new Date(trendStartMs).toISOString();
|
|
5901
5926
|
const sumVerifiedCrawlers = (windowStartIso, windowEndIso, exclusiveEnd = false) => Number(
|
|
5902
|
-
db.select({ total:
|
|
5927
|
+
db.select({ total: sql4`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
|
|
5903
5928
|
and6(
|
|
5904
5929
|
eq13(crawlerEventsHourly.projectId, projectId),
|
|
5905
5930
|
eq13(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
|
|
@@ -5909,7 +5934,7 @@ function buildServerActivity(db, projectId) {
|
|
|
5909
5934
|
).get()?.total ?? 0
|
|
5910
5935
|
);
|
|
5911
5936
|
const sumUnverifiedCrawlers = (windowStartIso, windowEndIso, exclusiveEnd = false) => Number(
|
|
5912
|
-
db.select({ total:
|
|
5937
|
+
db.select({ total: sql4`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
|
|
5913
5938
|
and6(
|
|
5914
5939
|
eq13(crawlerEventsHourly.projectId, projectId),
|
|
5915
5940
|
ne(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
|
|
@@ -5919,7 +5944,7 @@ function buildServerActivity(db, projectId) {
|
|
|
5919
5944
|
).get()?.total ?? 0
|
|
5920
5945
|
);
|
|
5921
5946
|
const sumReferrals = (windowStartIso, windowEndIso, exclusiveEnd = false) => Number(
|
|
5922
|
-
db.select({ total:
|
|
5947
|
+
db.select({ total: sql4`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
|
|
5923
5948
|
and6(
|
|
5924
5949
|
eq13(aiReferralEventsHourly.projectId, projectId),
|
|
5925
5950
|
nonSubresourceReferralPathCondition(),
|
|
@@ -5937,7 +5962,7 @@ function buildServerActivity(db, projectId) {
|
|
|
5937
5962
|
const crawlerByOperatorRows = db.select({
|
|
5938
5963
|
operator: crawlerEventsHourly.operator,
|
|
5939
5964
|
verificationStatus: crawlerEventsHourly.verificationStatus,
|
|
5940
|
-
hits:
|
|
5965
|
+
hits: sql4`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
|
|
5941
5966
|
}).from(crawlerEventsHourly).where(
|
|
5942
5967
|
and6(
|
|
5943
5968
|
eq13(crawlerEventsHourly.projectId, projectId),
|
|
@@ -5947,7 +5972,7 @@ function buildServerActivity(db, projectId) {
|
|
|
5947
5972
|
).groupBy(crawlerEventsHourly.operator, crawlerEventsHourly.verificationStatus).all();
|
|
5948
5973
|
const crawlerByOperatorPriorRows = db.select({
|
|
5949
5974
|
operator: crawlerEventsHourly.operator,
|
|
5950
|
-
hits:
|
|
5975
|
+
hits: sql4`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
|
|
5951
5976
|
}).from(crawlerEventsHourly).where(
|
|
5952
5977
|
and6(
|
|
5953
5978
|
eq13(crawlerEventsHourly.projectId, projectId),
|
|
@@ -5958,7 +5983,7 @@ function buildServerActivity(db, projectId) {
|
|
|
5958
5983
|
).groupBy(crawlerEventsHourly.operator).all();
|
|
5959
5984
|
const referralByOperatorRows = db.select({
|
|
5960
5985
|
operator: aiReferralEventsHourly.operator,
|
|
5961
|
-
hits:
|
|
5986
|
+
hits: sql4`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`
|
|
5962
5987
|
}).from(aiReferralEventsHourly).where(
|
|
5963
5988
|
and6(
|
|
5964
5989
|
eq13(aiReferralEventsHourly.projectId, projectId),
|
|
@@ -5998,8 +6023,8 @@ function buildServerActivity(db, projectId) {
|
|
|
5998
6023
|
);
|
|
5999
6024
|
const topPathsRows = db.select({
|
|
6000
6025
|
path: crawlerEventsHourly.pathNormalized,
|
|
6001
|
-
hits:
|
|
6002
|
-
operators:
|
|
6026
|
+
hits: sql4`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`,
|
|
6027
|
+
operators: sql4`COUNT(DISTINCT ${crawlerEventsHourly.operator})`
|
|
6003
6028
|
}).from(crawlerEventsHourly).where(
|
|
6004
6029
|
and6(
|
|
6005
6030
|
eq13(crawlerEventsHourly.projectId, projectId),
|
|
@@ -6007,7 +6032,7 @@ function buildServerActivity(db, projectId) {
|
|
|
6007
6032
|
gte(crawlerEventsHourly.tsHour, headlineStart),
|
|
6008
6033
|
lte(crawlerEventsHourly.tsHour, headlineEnd)
|
|
6009
6034
|
)
|
|
6010
|
-
).groupBy(crawlerEventsHourly.pathNormalized).orderBy(desc6(
|
|
6035
|
+
).groupBy(crawlerEventsHourly.pathNormalized).orderBy(desc6(sql4`SUM(${crawlerEventsHourly.hits})`)).limit(SERVER_ACTIVITY_TOP_PATHS_LIMIT).all();
|
|
6011
6036
|
const topCrawledPaths = topPathsRows.map((r) => ({
|
|
6012
6037
|
path: r.path,
|
|
6013
6038
|
verifiedHits: Number(r.hits),
|
|
@@ -6015,8 +6040,8 @@ function buildServerActivity(db, projectId) {
|
|
|
6015
6040
|
}));
|
|
6016
6041
|
const referralProductsRows = db.select({
|
|
6017
6042
|
product: aiReferralEventsHourly.product,
|
|
6018
|
-
arrivals:
|
|
6019
|
-
landingPaths:
|
|
6043
|
+
arrivals: sql4`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`,
|
|
6044
|
+
landingPaths: sql4`COUNT(DISTINCT ${aiReferralEventsHourly.landingPathNormalized})`
|
|
6020
6045
|
}).from(aiReferralEventsHourly).where(
|
|
6021
6046
|
and6(
|
|
6022
6047
|
eq13(aiReferralEventsHourly.projectId, projectId),
|
|
@@ -6024,7 +6049,7 @@ function buildServerActivity(db, projectId) {
|
|
|
6024
6049
|
gte(aiReferralEventsHourly.tsHour, headlineStart),
|
|
6025
6050
|
lte(aiReferralEventsHourly.tsHour, headlineEnd)
|
|
6026
6051
|
)
|
|
6027
|
-
).groupBy(aiReferralEventsHourly.product).orderBy(desc6(
|
|
6052
|
+
).groupBy(aiReferralEventsHourly.product).orderBy(desc6(sql4`SUM(${aiReferralEventsHourly.sessionsOrHits})`)).all();
|
|
6028
6053
|
const referralProducts = referralProductsRows.map((r) => ({
|
|
6029
6054
|
product: r.product,
|
|
6030
6055
|
arrivals: Number(r.arrivals),
|
|
@@ -6032,8 +6057,8 @@ function buildServerActivity(db, projectId) {
|
|
|
6032
6057
|
}));
|
|
6033
6058
|
const topReferralRows = db.select({
|
|
6034
6059
|
path: aiReferralEventsHourly.landingPathNormalized,
|
|
6035
|
-
arrivals:
|
|
6036
|
-
products:
|
|
6060
|
+
arrivals: sql4`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`,
|
|
6061
|
+
products: sql4`COUNT(DISTINCT ${aiReferralEventsHourly.product})`
|
|
6037
6062
|
}).from(aiReferralEventsHourly).where(
|
|
6038
6063
|
and6(
|
|
6039
6064
|
eq13(aiReferralEventsHourly.projectId, projectId),
|
|
@@ -6041,15 +6066,15 @@ function buildServerActivity(db, projectId) {
|
|
|
6041
6066
|
gte(aiReferralEventsHourly.tsHour, headlineStart),
|
|
6042
6067
|
lte(aiReferralEventsHourly.tsHour, headlineEnd)
|
|
6043
6068
|
)
|
|
6044
|
-
).groupBy(aiReferralEventsHourly.landingPathNormalized).orderBy(desc6(
|
|
6069
|
+
).groupBy(aiReferralEventsHourly.landingPathNormalized).orderBy(desc6(sql4`SUM(${aiReferralEventsHourly.sessionsOrHits})`)).limit(SERVER_ACTIVITY_TOP_PATHS_LIMIT).all();
|
|
6045
6070
|
const topReferralLandingPaths = topReferralRows.map((r) => ({
|
|
6046
6071
|
path: r.path,
|
|
6047
6072
|
arrivals: Number(r.arrivals),
|
|
6048
6073
|
distinctProducts: Number(r.products)
|
|
6049
6074
|
}));
|
|
6050
6075
|
const crawlerTrendRows = db.select({
|
|
6051
|
-
date:
|
|
6052
|
-
hits:
|
|
6076
|
+
date: sql4`SUBSTR(${crawlerEventsHourly.tsHour}, 1, 10)`,
|
|
6077
|
+
hits: sql4`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
|
|
6053
6078
|
}).from(crawlerEventsHourly).where(
|
|
6054
6079
|
and6(
|
|
6055
6080
|
eq13(crawlerEventsHourly.projectId, projectId),
|
|
@@ -6057,10 +6082,10 @@ function buildServerActivity(db, projectId) {
|
|
|
6057
6082
|
gte(crawlerEventsHourly.tsHour, trendStart),
|
|
6058
6083
|
lte(crawlerEventsHourly.tsHour, headlineEnd)
|
|
6059
6084
|
)
|
|
6060
|
-
).groupBy(
|
|
6085
|
+
).groupBy(sql4`SUBSTR(${crawlerEventsHourly.tsHour}, 1, 10)`).all();
|
|
6061
6086
|
const referralTrendRows = db.select({
|
|
6062
|
-
date:
|
|
6063
|
-
hits:
|
|
6087
|
+
date: sql4`SUBSTR(${aiReferralEventsHourly.tsHour}, 1, 10)`,
|
|
6088
|
+
hits: sql4`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`
|
|
6064
6089
|
}).from(aiReferralEventsHourly).where(
|
|
6065
6090
|
and6(
|
|
6066
6091
|
eq13(aiReferralEventsHourly.projectId, projectId),
|
|
@@ -6068,7 +6093,7 @@ function buildServerActivity(db, projectId) {
|
|
|
6068
6093
|
gte(aiReferralEventsHourly.tsHour, trendStart),
|
|
6069
6094
|
lte(aiReferralEventsHourly.tsHour, headlineEnd)
|
|
6070
6095
|
)
|
|
6071
|
-
).groupBy(
|
|
6096
|
+
).groupBy(sql4`SUBSTR(${aiReferralEventsHourly.tsHour}, 1, 10)`).all();
|
|
6072
6097
|
const dailyTrendMap = /* @__PURE__ */ new Map();
|
|
6073
6098
|
for (const r of crawlerTrendRows) {
|
|
6074
6099
|
const e = dailyTrendMap.get(r.date) ?? { verifiedCrawlerHits: 0, referralArrivals: 0 };
|
|
@@ -7128,7 +7153,7 @@ function normalizeDomain2(domain) {
|
|
|
7128
7153
|
}
|
|
7129
7154
|
|
|
7130
7155
|
// ../api-routes/src/composites.ts
|
|
7131
|
-
import { eq as eq15, and as and7, desc as desc7, sql as
|
|
7156
|
+
import { eq as eq15, and as and7, desc as desc7, sql as sql5, like, or as or4, inArray as inArray7 } from "drizzle-orm";
|
|
7132
7157
|
var TOP_INSIGHT_LIMIT = 5;
|
|
7133
7158
|
var SEARCH_HIT_HARD_LIMIT = 50;
|
|
7134
7159
|
var SEARCH_SNIPPET_RADIUS = 80;
|
|
@@ -7181,6 +7206,7 @@ async function compositeRoutes(app) {
|
|
|
7181
7206
|
const queryLookup = { byId: new Map(projectQueries.map((q) => [q.id, q.query])) };
|
|
7182
7207
|
const configuredApiProviders = parseJsonColumn(project.providers, []).filter((p) => !p.startsWith("cdp:"));
|
|
7183
7208
|
const scores = {
|
|
7209
|
+
mention: buildMentionCoverage(latestSnapshots, { configuredApiProviders }),
|
|
7184
7210
|
visibility: buildVisibilityScore(latestSnapshots, { configuredApiProviders }),
|
|
7185
7211
|
gapQueries: buildGapQueryScore(latestSnapshots),
|
|
7186
7212
|
indexCoverage: buildIndexCoverageScore(app, project.id),
|
|
@@ -7245,9 +7271,9 @@ async function compositeRoutes(app) {
|
|
|
7245
7271
|
and7(
|
|
7246
7272
|
eq15(queries.projectId, project.id),
|
|
7247
7273
|
or4(
|
|
7248
|
-
|
|
7249
|
-
|
|
7250
|
-
|
|
7274
|
+
sql5`${querySnapshots.answerText} LIKE ${pattern} ESCAPE '\\'`,
|
|
7275
|
+
sql5`${querySnapshots.citedDomains} LIKE ${pattern} ESCAPE '\\'`,
|
|
7276
|
+
sql5`${querySnapshots.rawResponse} LIKE ${pattern} ESCAPE '\\'`,
|
|
7251
7277
|
like(queries.query, pattern)
|
|
7252
7278
|
)
|
|
7253
7279
|
)
|
|
@@ -7258,8 +7284,8 @@ async function compositeRoutes(app) {
|
|
|
7258
7284
|
or4(
|
|
7259
7285
|
like(insights.title, pattern),
|
|
7260
7286
|
like(insights.query, pattern),
|
|
7261
|
-
|
|
7262
|
-
|
|
7287
|
+
sql5`${insights.recommendation} LIKE ${pattern} ESCAPE '\\'`,
|
|
7288
|
+
sql5`${insights.cause} LIKE ${pattern} ESCAPE '\\'`
|
|
7263
7289
|
)
|
|
7264
7290
|
)
|
|
7265
7291
|
).orderBy(desc7(insights.createdAt)).limit(limit + 1).all();
|
|
@@ -7331,6 +7357,7 @@ function loadSnapshotsByRunIds(app, runIds) {
|
|
|
7331
7357
|
provider: querySnapshots.provider,
|
|
7332
7358
|
model: querySnapshots.model,
|
|
7333
7359
|
citationState: querySnapshots.citationState,
|
|
7360
|
+
answerMentioned: querySnapshots.answerMentioned,
|
|
7334
7361
|
competitorOverlap: querySnapshots.competitorOverlap,
|
|
7335
7362
|
citedDomains: querySnapshots.citedDomains
|
|
7336
7363
|
}).from(querySnapshots).where(inArray7(querySnapshots.runId, [...runIds])).all());
|
|
@@ -7341,6 +7368,7 @@ function loadSnapshotsByRunIds(app, runIds) {
|
|
|
7341
7368
|
provider: row.provider,
|
|
7342
7369
|
model: row.model,
|
|
7343
7370
|
citationState: row.citationState,
|
|
7371
|
+
answerMentioned: row.answerMentioned,
|
|
7344
7372
|
competitorOverlap: parseJsonColumn(row.competitorOverlap, []),
|
|
7345
7373
|
citedDomains: parseJsonColumn(row.citedDomains, [])
|
|
7346
7374
|
});
|
|
@@ -7936,6 +7964,18 @@ var routeCatalog = [
|
|
|
7936
7964
|
404: { description: "Project not found." }
|
|
7937
7965
|
}
|
|
7938
7966
|
},
|
|
7967
|
+
{
|
|
7968
|
+
method: "get",
|
|
7969
|
+
path: "/api/v1/projects/{name}/delete-preview",
|
|
7970
|
+
summary: "Preview the cascade impact of deleting a project",
|
|
7971
|
+
description: "Read-only impact summary backing `canonry project delete --dry-run`. Returns counts of rows that would cascade-delete (queries, competitors, runs, snapshots, insights) and rows that would be detached (audit_log \u2014 `project_id` set to NULL).",
|
|
7972
|
+
tags: ["projects"],
|
|
7973
|
+
parameters: [nameParameter],
|
|
7974
|
+
responses: {
|
|
7975
|
+
200: { description: "Preview of cascade impact." },
|
|
7976
|
+
404: { description: "Project not found." }
|
|
7977
|
+
}
|
|
7978
|
+
},
|
|
7939
7979
|
{
|
|
7940
7980
|
method: "post",
|
|
7941
7981
|
path: "/api/v1/projects/{name}/locations",
|
|
@@ -10941,8 +10981,8 @@ async function openApiRoutes(app, opts = {}) {
|
|
|
10941
10981
|
return reply.type("application/json").send(buildOpenApiDocument(opts));
|
|
10942
10982
|
});
|
|
10943
10983
|
}
|
|
10944
|
-
function buildOperationId(method,
|
|
10945
|
-
const parts =
|
|
10984
|
+
function buildOperationId(method, path16) {
|
|
10985
|
+
const parts = path16.split("/").filter(Boolean).map((part) => {
|
|
10946
10986
|
if (part.startsWith("{") && part.endsWith("}")) {
|
|
10947
10987
|
return `by-${part.slice(1, -1)}`;
|
|
10948
10988
|
}
|
|
@@ -11378,7 +11418,7 @@ function formatNotification(row) {
|
|
|
11378
11418
|
|
|
11379
11419
|
// ../api-routes/src/google.ts
|
|
11380
11420
|
import crypto14 from "crypto";
|
|
11381
|
-
import { eq as eq18, and as and9, desc as desc8, sql as
|
|
11421
|
+
import { eq as eq18, and as and9, desc as desc8, sql as sql6 } from "drizzle-orm";
|
|
11382
11422
|
|
|
11383
11423
|
// ../integration-google/src/constants.ts
|
|
11384
11424
|
var GOOGLE_AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
|
|
@@ -12604,11 +12644,11 @@ async function googleRoutes(app, opts) {
|
|
|
12604
12644
|
const { startDate, endDate, query, page, limit, offset } = request.query;
|
|
12605
12645
|
const cutoffDate = !startDate ? windowCutoff(parseWindow(request.query.window))?.slice(0, 10) ?? null : null;
|
|
12606
12646
|
const conditions = [eq18(gscSearchData.projectId, project.id)];
|
|
12607
|
-
if (startDate) conditions.push(
|
|
12608
|
-
else if (cutoffDate) conditions.push(
|
|
12609
|
-
if (endDate) conditions.push(
|
|
12610
|
-
if (query) conditions.push(
|
|
12611
|
-
if (page) conditions.push(
|
|
12647
|
+
if (startDate) conditions.push(sql6`${gscSearchData.date} >= ${startDate}`);
|
|
12648
|
+
else if (cutoffDate) conditions.push(sql6`${gscSearchData.date} >= ${cutoffDate}`);
|
|
12649
|
+
if (endDate) conditions.push(sql6`${gscSearchData.date} <= ${endDate}`);
|
|
12650
|
+
if (query) conditions.push(sql6`${gscSearchData.query} LIKE ${"%" + query + "%"}`);
|
|
12651
|
+
if (page) conditions.push(sql6`${gscSearchData.page} LIKE ${"%" + page + "%"}`);
|
|
12612
12652
|
const limitVal = Math.max(parseInt(limit ?? "500", 10) || 0, 1);
|
|
12613
12653
|
const offsetVal = Math.max(parseInt(offset ?? "0", 10) || 0, 0);
|
|
12614
12654
|
const rows = app.db.select().from(gscSearchData).where(and9(...conditions)).orderBy(desc8(gscSearchData.date)).limit(limitVal).offset(offsetVal).all();
|
|
@@ -13853,7 +13893,7 @@ async function cdpRoutes(app, opts) {
|
|
|
13853
13893
|
|
|
13854
13894
|
// ../api-routes/src/ga.ts
|
|
13855
13895
|
import crypto16 from "crypto";
|
|
13856
|
-
import { eq as eq21, desc as desc10, and as and12, sql as
|
|
13896
|
+
import { eq as eq21, desc as desc10, and as and12, sql as sql7 } from "drizzle-orm";
|
|
13857
13897
|
function gaLog(level, action, ctx) {
|
|
13858
13898
|
const entry = { ts: (/* @__PURE__ */ new Date()).toISOString(), level, module: "GA4Routes", action, ...ctx };
|
|
13859
13899
|
const stream = level === "error" ? process.stderr : process.stdout;
|
|
@@ -14150,8 +14190,8 @@ async function ga4Routes(app, opts) {
|
|
|
14150
14190
|
tx.delete(gaTrafficSnapshots).where(
|
|
14151
14191
|
and12(
|
|
14152
14192
|
eq21(gaTrafficSnapshots.projectId, project.id),
|
|
14153
|
-
|
|
14154
|
-
|
|
14193
|
+
sql7`${gaTrafficSnapshots.date} >= ${summary.periodStart}`,
|
|
14194
|
+
sql7`${gaTrafficSnapshots.date} <= ${summary.periodEnd}`
|
|
14155
14195
|
)
|
|
14156
14196
|
).run();
|
|
14157
14197
|
for (const row of rows) {
|
|
@@ -14174,8 +14214,8 @@ async function ga4Routes(app, opts) {
|
|
|
14174
14214
|
tx.delete(gaAiReferrals).where(
|
|
14175
14215
|
and12(
|
|
14176
14216
|
eq21(gaAiReferrals.projectId, project.id),
|
|
14177
|
-
|
|
14178
|
-
|
|
14217
|
+
sql7`${gaAiReferrals.date} >= ${summary.periodStart}`,
|
|
14218
|
+
sql7`${gaAiReferrals.date} <= ${summary.periodEnd}`
|
|
14179
14219
|
)
|
|
14180
14220
|
).run();
|
|
14181
14221
|
for (const row of aiReferrals) {
|
|
@@ -14200,8 +14240,8 @@ async function ga4Routes(app, opts) {
|
|
|
14200
14240
|
tx.delete(gaSocialReferrals).where(
|
|
14201
14241
|
and12(
|
|
14202
14242
|
eq21(gaSocialReferrals.projectId, project.id),
|
|
14203
|
-
|
|
14204
|
-
|
|
14243
|
+
sql7`${gaSocialReferrals.date} >= ${summary.periodStart}`,
|
|
14244
|
+
sql7`${gaSocialReferrals.date} <= ${summary.periodEnd}`
|
|
14205
14245
|
)
|
|
14206
14246
|
).run();
|
|
14207
14247
|
for (const row of socialReferrals) {
|
|
@@ -14291,11 +14331,11 @@ async function ga4Routes(app, opts) {
|
|
|
14291
14331
|
const cutoff = windowCutoff(window);
|
|
14292
14332
|
const cutoffDate = cutoff?.slice(0, 10) ?? null;
|
|
14293
14333
|
const snapshotConditions = [eq21(gaTrafficSnapshots.projectId, project.id)];
|
|
14294
|
-
if (cutoffDate) snapshotConditions.push(
|
|
14334
|
+
if (cutoffDate) snapshotConditions.push(sql7`${gaTrafficSnapshots.date} >= ${cutoffDate}`);
|
|
14295
14335
|
const aiConditions = [eq21(gaAiReferrals.projectId, project.id)];
|
|
14296
|
-
if (cutoffDate) aiConditions.push(
|
|
14336
|
+
if (cutoffDate) aiConditions.push(sql7`${gaAiReferrals.date} >= ${cutoffDate}`);
|
|
14297
14337
|
const socialConditions = [eq21(gaSocialReferrals.projectId, project.id)];
|
|
14298
|
-
if (cutoffDate) socialConditions.push(
|
|
14338
|
+
if (cutoffDate) socialConditions.push(sql7`${gaSocialReferrals.date} >= ${cutoffDate}`);
|
|
14299
14339
|
const windowSummaryRow = cutoffDate ? app.db.select({
|
|
14300
14340
|
totalSessions: gaTrafficWindowSummaries.totalSessions,
|
|
14301
14341
|
totalOrganicSessions: gaTrafficWindowSummaries.totalOrganicSessions,
|
|
@@ -14308,9 +14348,9 @@ async function ga4Routes(app, opts) {
|
|
|
14308
14348
|
)
|
|
14309
14349
|
).get() : null;
|
|
14310
14350
|
const snapshotTotalsRow = cutoffDate && !windowSummaryRow ? app.db.select({
|
|
14311
|
-
totalSessions:
|
|
14312
|
-
totalOrganicSessions:
|
|
14313
|
-
totalUsers:
|
|
14351
|
+
totalSessions: sql7`COALESCE(SUM(${gaTrafficSnapshots.sessions}), 0)`,
|
|
14352
|
+
totalOrganicSessions: sql7`COALESCE(SUM(${gaTrafficSnapshots.organicSessions}), 0)`,
|
|
14353
|
+
totalUsers: sql7`COALESCE(SUM(${gaTrafficSnapshots.users}), 0)`
|
|
14314
14354
|
}).from(gaTrafficSnapshots).where(and12(...snapshotConditions)).get() : null;
|
|
14315
14355
|
const summaryRow = cutoffDate ? windowSummaryRow ?? snapshotTotalsRow : app.db.select({
|
|
14316
14356
|
totalSessions: gaTrafficSummaries.totalSessions,
|
|
@@ -14318,38 +14358,38 @@ async function ga4Routes(app, opts) {
|
|
|
14318
14358
|
totalUsers: gaTrafficSummaries.totalUsers
|
|
14319
14359
|
}).from(gaTrafficSummaries).where(eq21(gaTrafficSummaries.projectId, project.id)).get();
|
|
14320
14360
|
const directTotalRow = windowSummaryRow ? { totalDirectSessions: windowSummaryRow.totalDirectSessions } : app.db.select({
|
|
14321
|
-
totalDirectSessions:
|
|
14361
|
+
totalDirectSessions: sql7`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)`
|
|
14322
14362
|
}).from(gaTrafficSnapshots).where(and12(...snapshotConditions)).get();
|
|
14323
14363
|
const summaryMeta = app.db.select({
|
|
14324
14364
|
periodStart: gaTrafficSummaries.periodStart,
|
|
14325
14365
|
periodEnd: gaTrafficSummaries.periodEnd
|
|
14326
14366
|
}).from(gaTrafficSummaries).where(eq21(gaTrafficSummaries.projectId, project.id)).get();
|
|
14327
14367
|
const rows = app.db.select({
|
|
14328
|
-
landingPage:
|
|
14329
|
-
sessions:
|
|
14330
|
-
organicSessions:
|
|
14331
|
-
directSessions:
|
|
14332
|
-
users:
|
|
14333
|
-
}).from(gaTrafficSnapshots).where(and12(...snapshotConditions)).groupBy(
|
|
14368
|
+
landingPage: sql7`COALESCE(${gaTrafficSnapshots.landingPageNormalized}, ${gaTrafficSnapshots.landingPage})`,
|
|
14369
|
+
sessions: sql7`SUM(${gaTrafficSnapshots.sessions})`,
|
|
14370
|
+
organicSessions: sql7`SUM(${gaTrafficSnapshots.organicSessions})`,
|
|
14371
|
+
directSessions: sql7`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)`,
|
|
14372
|
+
users: sql7`SUM(${gaTrafficSnapshots.users})`
|
|
14373
|
+
}).from(gaTrafficSnapshots).where(and12(...snapshotConditions)).groupBy(sql7`COALESCE(${gaTrafficSnapshots.landingPageNormalized}, ${gaTrafficSnapshots.landingPage})`).orderBy(sql7`SUM(${gaTrafficSnapshots.sessions}) DESC`).limit(limit).all();
|
|
14334
14374
|
const aiReferralRows = app.db.select({
|
|
14335
14375
|
source: gaAiReferrals.source,
|
|
14336
14376
|
medium: gaAiReferrals.medium,
|
|
14337
14377
|
sourceDimension: gaAiReferrals.sourceDimension,
|
|
14338
|
-
sessions:
|
|
14339
|
-
users:
|
|
14378
|
+
sessions: sql7`SUM(${gaAiReferrals.sessions})`,
|
|
14379
|
+
users: sql7`SUM(${gaAiReferrals.users})`
|
|
14340
14380
|
}).from(gaAiReferrals).where(and12(...aiConditions)).groupBy(gaAiReferrals.source, gaAiReferrals.medium, gaAiReferrals.sourceDimension).all();
|
|
14341
14381
|
const aiReferralLandingPageRows = app.db.select({
|
|
14342
14382
|
source: gaAiReferrals.source,
|
|
14343
14383
|
medium: gaAiReferrals.medium,
|
|
14344
14384
|
sourceDimension: gaAiReferrals.sourceDimension,
|
|
14345
|
-
landingPage:
|
|
14346
|
-
sessions:
|
|
14347
|
-
users:
|
|
14385
|
+
landingPage: sql7`COALESCE(${gaAiReferrals.landingPageNormalized}, ${gaAiReferrals.landingPage})`,
|
|
14386
|
+
sessions: sql7`SUM(${gaAiReferrals.sessions})`,
|
|
14387
|
+
users: sql7`SUM(${gaAiReferrals.users})`
|
|
14348
14388
|
}).from(gaAiReferrals).where(and12(...aiConditions)).groupBy(
|
|
14349
14389
|
gaAiReferrals.source,
|
|
14350
14390
|
gaAiReferrals.medium,
|
|
14351
14391
|
gaAiReferrals.sourceDimension,
|
|
14352
|
-
|
|
14392
|
+
sql7`COALESCE(${gaAiReferrals.landingPageNormalized}, ${gaAiReferrals.landingPage})`
|
|
14353
14393
|
).all();
|
|
14354
14394
|
const aiReferrals = pickWinningDimension(
|
|
14355
14395
|
aiReferralRows,
|
|
@@ -14360,10 +14400,10 @@ async function ga4Routes(app, opts) {
|
|
|
14360
14400
|
(r) => `${r.source}\0${r.medium}\0${r.landingPage}`
|
|
14361
14401
|
);
|
|
14362
14402
|
const aiDeduped = app.db.select({
|
|
14363
|
-
sessions:
|
|
14364
|
-
users:
|
|
14403
|
+
sessions: sql7`COALESCE(SUM(max_sessions), 0)`,
|
|
14404
|
+
users: sql7`COALESCE(SUM(max_users), 0)`
|
|
14365
14405
|
}).from(
|
|
14366
|
-
|
|
14406
|
+
sql7`(
|
|
14367
14407
|
SELECT date, source, medium,
|
|
14368
14408
|
MAX(dimension_sessions) AS max_sessions,
|
|
14369
14409
|
MAX(dimension_users) AS max_users
|
|
@@ -14372,7 +14412,7 @@ async function ga4Routes(app, opts) {
|
|
|
14372
14412
|
SUM(sessions) AS dimension_sessions,
|
|
14373
14413
|
SUM(users) AS dimension_users
|
|
14374
14414
|
FROM ga_ai_referrals
|
|
14375
|
-
WHERE project_id = ${project.id}${cutoffDate ?
|
|
14415
|
+
WHERE project_id = ${project.id}${cutoffDate ? sql7` AND date >= ${cutoffDate}` : sql7``}
|
|
14376
14416
|
GROUP BY date, source, medium, source_dimension
|
|
14377
14417
|
)
|
|
14378
14418
|
GROUP BY date, source, medium
|
|
@@ -14380,8 +14420,8 @@ async function ga4Routes(app, opts) {
|
|
|
14380
14420
|
).get();
|
|
14381
14421
|
const aiBySessionRows = app.db.select({
|
|
14382
14422
|
channelGroup: gaAiReferrals.channelGroup,
|
|
14383
|
-
sessions:
|
|
14384
|
-
users:
|
|
14423
|
+
sessions: sql7`COALESCE(SUM(${gaAiReferrals.sessions}), 0)`,
|
|
14424
|
+
users: sql7`COALESCE(SUM(${gaAiReferrals.users}), 0)`
|
|
14385
14425
|
}).from(gaAiReferrals).where(and12(...aiConditions, eq21(gaAiReferrals.sourceDimension, "session"))).groupBy(gaAiReferrals.channelGroup).all();
|
|
14386
14426
|
const aiSessionsByChannelGroup = /* @__PURE__ */ new Map();
|
|
14387
14427
|
let aiBySessionUsers = 0;
|
|
@@ -14394,12 +14434,12 @@ async function ga4Routes(app, opts) {
|
|
|
14394
14434
|
source: gaSocialReferrals.source,
|
|
14395
14435
|
medium: gaSocialReferrals.medium,
|
|
14396
14436
|
channelGroup: gaSocialReferrals.channelGroup,
|
|
14397
|
-
sessions:
|
|
14398
|
-
users:
|
|
14399
|
-
}).from(gaSocialReferrals).where(and12(...socialConditions)).groupBy(gaSocialReferrals.source, gaSocialReferrals.medium, gaSocialReferrals.channelGroup).orderBy(
|
|
14437
|
+
sessions: sql7`SUM(${gaSocialReferrals.sessions})`,
|
|
14438
|
+
users: sql7`SUM(${gaSocialReferrals.users})`
|
|
14439
|
+
}).from(gaSocialReferrals).where(and12(...socialConditions)).groupBy(gaSocialReferrals.source, gaSocialReferrals.medium, gaSocialReferrals.channelGroup).orderBy(sql7`SUM(${gaSocialReferrals.sessions}) DESC`).all();
|
|
14400
14440
|
const socialTotals = app.db.select({
|
|
14401
|
-
sessions:
|
|
14402
|
-
users:
|
|
14441
|
+
sessions: sql7`SUM(${gaSocialReferrals.sessions})`,
|
|
14442
|
+
users: sql7`SUM(${gaSocialReferrals.users})`
|
|
14403
14443
|
}).from(gaSocialReferrals).where(and12(...socialConditions)).get();
|
|
14404
14444
|
const latestSync = app.db.select({ syncedAt: gaTrafficSummaries.syncedAt }).from(gaTrafficSummaries).where(eq21(gaTrafficSummaries.projectId, project.id)).orderBy(desc10(gaTrafficSummaries.syncedAt)).limit(1).get();
|
|
14405
14445
|
const total = summaryRow?.totalSessions ?? 0;
|
|
@@ -14482,21 +14522,21 @@ async function ga4Routes(app, opts) {
|
|
|
14482
14522
|
requireGa4Connection(opts, project.name, project.canonicalDomain);
|
|
14483
14523
|
const cutoffDate = windowCutoff(parseWindow(request.query.window))?.slice(0, 10) ?? null;
|
|
14484
14524
|
const conditions = [eq21(gaAiReferrals.projectId, project.id)];
|
|
14485
|
-
if (cutoffDate) conditions.push(
|
|
14525
|
+
if (cutoffDate) conditions.push(sql7`${gaAiReferrals.date} >= ${cutoffDate}`);
|
|
14486
14526
|
const rows = app.db.select({
|
|
14487
14527
|
date: gaAiReferrals.date,
|
|
14488
14528
|
source: gaAiReferrals.source,
|
|
14489
14529
|
medium: gaAiReferrals.medium,
|
|
14490
|
-
landingPage:
|
|
14530
|
+
landingPage: sql7`COALESCE(${gaAiReferrals.landingPageNormalized}, ${gaAiReferrals.landingPage})`,
|
|
14491
14531
|
sourceDimension: gaAiReferrals.sourceDimension,
|
|
14492
|
-
sessions:
|
|
14493
|
-
users:
|
|
14532
|
+
sessions: sql7`SUM(${gaAiReferrals.sessions})`,
|
|
14533
|
+
users: sql7`SUM(${gaAiReferrals.users})`
|
|
14494
14534
|
}).from(gaAiReferrals).where(and12(...conditions)).groupBy(
|
|
14495
14535
|
gaAiReferrals.date,
|
|
14496
14536
|
gaAiReferrals.source,
|
|
14497
14537
|
gaAiReferrals.medium,
|
|
14498
14538
|
gaAiReferrals.sourceDimension,
|
|
14499
|
-
|
|
14539
|
+
sql7`COALESCE(${gaAiReferrals.landingPageNormalized}, ${gaAiReferrals.landingPage})`
|
|
14500
14540
|
).orderBy(gaAiReferrals.date).all();
|
|
14501
14541
|
return rows;
|
|
14502
14542
|
});
|
|
@@ -14505,7 +14545,7 @@ async function ga4Routes(app, opts) {
|
|
|
14505
14545
|
requireGa4Connection(opts, project.name, project.canonicalDomain);
|
|
14506
14546
|
const cutoffDate = windowCutoff(parseWindow(request.query.window))?.slice(0, 10) ?? null;
|
|
14507
14547
|
const conditions = [eq21(gaSocialReferrals.projectId, project.id)];
|
|
14508
|
-
if (cutoffDate) conditions.push(
|
|
14548
|
+
if (cutoffDate) conditions.push(sql7`${gaSocialReferrals.date} >= ${cutoffDate}`);
|
|
14509
14549
|
const rows = app.db.select({
|
|
14510
14550
|
date: gaSocialReferrals.date,
|
|
14511
14551
|
source: gaSocialReferrals.source,
|
|
@@ -14526,10 +14566,10 @@ async function ga4Routes(app, opts) {
|
|
|
14526
14566
|
d.setDate(d.getDate() - n);
|
|
14527
14567
|
return fmt(d);
|
|
14528
14568
|
};
|
|
14529
|
-
const sumSocial = (from, to) => app.db.select({ sessions:
|
|
14569
|
+
const sumSocial = (from, to) => app.db.select({ sessions: sql7`COALESCE(SUM(${gaSocialReferrals.sessions}), 0)` }).from(gaSocialReferrals).where(and12(
|
|
14530
14570
|
eq21(gaSocialReferrals.projectId, project.id),
|
|
14531
|
-
|
|
14532
|
-
|
|
14571
|
+
sql7`${gaSocialReferrals.date} >= ${from}`,
|
|
14572
|
+
sql7`${gaSocialReferrals.date} < ${to}`
|
|
14533
14573
|
)).get();
|
|
14534
14574
|
const current7d = sumSocial(daysAgo2(7), fmt(today));
|
|
14535
14575
|
const prev7d = sumSocial(daysAgo2(14), daysAgo2(7));
|
|
@@ -14538,19 +14578,19 @@ async function ga4Routes(app, opts) {
|
|
|
14538
14578
|
const pct = (cur, prev) => prev === 0 ? null : Math.round((cur - prev) / prev * 100);
|
|
14539
14579
|
const sourceCurrent = app.db.select({
|
|
14540
14580
|
source: gaSocialReferrals.source,
|
|
14541
|
-
sessions:
|
|
14581
|
+
sessions: sql7`SUM(${gaSocialReferrals.sessions})`
|
|
14542
14582
|
}).from(gaSocialReferrals).where(and12(
|
|
14543
14583
|
eq21(gaSocialReferrals.projectId, project.id),
|
|
14544
|
-
|
|
14545
|
-
|
|
14584
|
+
sql7`${gaSocialReferrals.date} >= ${daysAgo2(7)}`,
|
|
14585
|
+
sql7`${gaSocialReferrals.date} < ${fmt(today)}`
|
|
14546
14586
|
)).groupBy(gaSocialReferrals.source).all();
|
|
14547
14587
|
const sourcePrev = app.db.select({
|
|
14548
14588
|
source: gaSocialReferrals.source,
|
|
14549
|
-
sessions:
|
|
14589
|
+
sessions: sql7`SUM(${gaSocialReferrals.sessions})`
|
|
14550
14590
|
}).from(gaSocialReferrals).where(and12(
|
|
14551
14591
|
eq21(gaSocialReferrals.projectId, project.id),
|
|
14552
|
-
|
|
14553
|
-
|
|
14592
|
+
sql7`${gaSocialReferrals.date} >= ${daysAgo2(14)}`,
|
|
14593
|
+
sql7`${gaSocialReferrals.date} < ${daysAgo2(7)}`
|
|
14554
14594
|
)).groupBy(gaSocialReferrals.source).all();
|
|
14555
14595
|
const prevMap = new Map(sourcePrev.map((r) => [r.source, r.sessions]));
|
|
14556
14596
|
let biggestMover = null;
|
|
@@ -14589,16 +14629,16 @@ async function ga4Routes(app, opts) {
|
|
|
14589
14629
|
return fmt(d);
|
|
14590
14630
|
};
|
|
14591
14631
|
const pct = (cur, prev) => prev === 0 ? null : Math.round((cur - prev) / prev * 100);
|
|
14592
|
-
const sumTotal = (from, to) => app.db.select({ sessions:
|
|
14593
|
-
const sumOrganic = (from, to) => app.db.select({ sessions:
|
|
14594
|
-
const sumDirect = (from, to) => app.db.select({ sessions:
|
|
14595
|
-
const sumAi = (from, to) => app.db.select({ sessions:
|
|
14632
|
+
const sumTotal = (from, to) => app.db.select({ sessions: sql7`COALESCE(SUM(${gaTrafficSnapshots.sessions}), 0)` }).from(gaTrafficSnapshots).where(and12(eq21(gaTrafficSnapshots.projectId, project.id), sql7`${gaTrafficSnapshots.date} >= ${from}`, sql7`${gaTrafficSnapshots.date} < ${to}`)).get();
|
|
14633
|
+
const sumOrganic = (from, to) => app.db.select({ sessions: sql7`COALESCE(SUM(${gaTrafficSnapshots.organicSessions}), 0)` }).from(gaTrafficSnapshots).where(and12(eq21(gaTrafficSnapshots.projectId, project.id), sql7`${gaTrafficSnapshots.date} >= ${from}`, sql7`${gaTrafficSnapshots.date} < ${to}`)).get();
|
|
14634
|
+
const sumDirect = (from, to) => app.db.select({ sessions: sql7`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)` }).from(gaTrafficSnapshots).where(and12(eq21(gaTrafficSnapshots.projectId, project.id), sql7`${gaTrafficSnapshots.date} >= ${from}`, sql7`${gaTrafficSnapshots.date} < ${to}`)).get();
|
|
14635
|
+
const sumAi = (from, to) => app.db.select({ sessions: sql7`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and12(
|
|
14596
14636
|
eq21(gaAiReferrals.projectId, project.id),
|
|
14597
|
-
|
|
14598
|
-
|
|
14637
|
+
sql7`${gaAiReferrals.date} >= ${from}`,
|
|
14638
|
+
sql7`${gaAiReferrals.date} < ${to}`,
|
|
14599
14639
|
eq21(gaAiReferrals.sourceDimension, "session")
|
|
14600
14640
|
)).get();
|
|
14601
|
-
const sumSocial = (from, to) => app.db.select({ sessions:
|
|
14641
|
+
const sumSocial = (from, to) => app.db.select({ sessions: sql7`COALESCE(SUM(${gaSocialReferrals.sessions}), 0)` }).from(gaSocialReferrals).where(and12(eq21(gaSocialReferrals.projectId, project.id), sql7`${gaSocialReferrals.date} >= ${from}`, sql7`${gaSocialReferrals.date} < ${to}`)).get();
|
|
14602
14642
|
const todayStr = fmt(today);
|
|
14603
14643
|
const buildTrend = (sum) => {
|
|
14604
14644
|
const c7 = sum(daysAgo2(7), todayStr)?.sessions ?? 0;
|
|
@@ -14607,16 +14647,16 @@ async function ga4Routes(app, opts) {
|
|
|
14607
14647
|
const p30 = sum(daysAgo2(60), daysAgo2(30))?.sessions ?? 0;
|
|
14608
14648
|
return { sessions7d: c7, sessionsPrev7d: p7, trend7dPct: pct(c7, p7), sessions30d: c30, sessionsPrev30d: p30, trend30dPct: pct(c30, p30) };
|
|
14609
14649
|
};
|
|
14610
|
-
const aiSourceCurrent = app.db.select({ source: gaAiReferrals.source, sessions:
|
|
14650
|
+
const aiSourceCurrent = app.db.select({ source: gaAiReferrals.source, sessions: sql7`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and12(
|
|
14611
14651
|
eq21(gaAiReferrals.projectId, project.id),
|
|
14612
|
-
|
|
14613
|
-
|
|
14652
|
+
sql7`${gaAiReferrals.date} >= ${daysAgo2(7)}`,
|
|
14653
|
+
sql7`${gaAiReferrals.date} < ${todayStr}`,
|
|
14614
14654
|
eq21(gaAiReferrals.sourceDimension, "session")
|
|
14615
14655
|
)).groupBy(gaAiReferrals.source).all();
|
|
14616
|
-
const aiSourcePrev = app.db.select({ source: gaAiReferrals.source, sessions:
|
|
14656
|
+
const aiSourcePrev = app.db.select({ source: gaAiReferrals.source, sessions: sql7`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and12(
|
|
14617
14657
|
eq21(gaAiReferrals.projectId, project.id),
|
|
14618
|
-
|
|
14619
|
-
|
|
14658
|
+
sql7`${gaAiReferrals.date} >= ${daysAgo2(14)}`,
|
|
14659
|
+
sql7`${gaAiReferrals.date} < ${daysAgo2(7)}`,
|
|
14620
14660
|
eq21(gaAiReferrals.sourceDimension, "session")
|
|
14621
14661
|
)).groupBy(gaAiReferrals.source).all();
|
|
14622
14662
|
const findBiggestMover = (current, prev) => {
|
|
@@ -14633,8 +14673,8 @@ async function ga4Routes(app, opts) {
|
|
|
14633
14673
|
}
|
|
14634
14674
|
return mover;
|
|
14635
14675
|
};
|
|
14636
|
-
const socialSourceCurrent = app.db.select({ source: gaSocialReferrals.source, sessions:
|
|
14637
|
-
const socialSourcePrev = app.db.select({ source: gaSocialReferrals.source, sessions:
|
|
14676
|
+
const socialSourceCurrent = app.db.select({ source: gaSocialReferrals.source, sessions: sql7`SUM(${gaSocialReferrals.sessions})` }).from(gaSocialReferrals).where(and12(eq21(gaSocialReferrals.projectId, project.id), sql7`${gaSocialReferrals.date} >= ${daysAgo2(7)}`, sql7`${gaSocialReferrals.date} < ${todayStr}`)).groupBy(gaSocialReferrals.source).all();
|
|
14677
|
+
const socialSourcePrev = app.db.select({ source: gaSocialReferrals.source, sessions: sql7`SUM(${gaSocialReferrals.sessions})` }).from(gaSocialReferrals).where(and12(eq21(gaSocialReferrals.projectId, project.id), sql7`${gaSocialReferrals.date} >= ${daysAgo2(14)}`, sql7`${gaSocialReferrals.date} < ${daysAgo2(7)}`)).groupBy(gaSocialReferrals.source).all();
|
|
14638
14678
|
return {
|
|
14639
14679
|
total: buildTrend(sumTotal),
|
|
14640
14680
|
organic: buildTrend(sumOrganic),
|
|
@@ -14650,12 +14690,12 @@ async function ga4Routes(app, opts) {
|
|
|
14650
14690
|
requireGa4Connection(opts, project.name, project.canonicalDomain);
|
|
14651
14691
|
const cutoffDate = windowCutoff(parseWindow(request.query.window))?.slice(0, 10) ?? null;
|
|
14652
14692
|
const conditions = [eq21(gaTrafficSnapshots.projectId, project.id)];
|
|
14653
|
-
if (cutoffDate) conditions.push(
|
|
14693
|
+
if (cutoffDate) conditions.push(sql7`${gaTrafficSnapshots.date} >= ${cutoffDate}`);
|
|
14654
14694
|
const rows = app.db.select({
|
|
14655
14695
|
date: gaTrafficSnapshots.date,
|
|
14656
|
-
sessions:
|
|
14657
|
-
organicSessions:
|
|
14658
|
-
users:
|
|
14696
|
+
sessions: sql7`SUM(${gaTrafficSnapshots.sessions})`,
|
|
14697
|
+
organicSessions: sql7`SUM(${gaTrafficSnapshots.organicSessions})`,
|
|
14698
|
+
users: sql7`SUM(${gaTrafficSnapshots.users})`
|
|
14659
14699
|
}).from(gaTrafficSnapshots).where(and12(...conditions)).groupBy(gaTrafficSnapshots.date).orderBy(gaTrafficSnapshots.date).all();
|
|
14660
14700
|
return rows.map((r) => ({
|
|
14661
14701
|
date: r.date,
|
|
@@ -14668,11 +14708,11 @@ async function ga4Routes(app, opts) {
|
|
|
14668
14708
|
const project = resolveProject(app.db, request.params.name);
|
|
14669
14709
|
requireGa4Connection(opts, project.name, project.canonicalDomain);
|
|
14670
14710
|
const trafficPages = app.db.select({
|
|
14671
|
-
landingPage:
|
|
14672
|
-
sessions:
|
|
14673
|
-
organicSessions:
|
|
14674
|
-
users:
|
|
14675
|
-
}).from(gaTrafficSnapshots).where(eq21(gaTrafficSnapshots.projectId, project.id)).groupBy(
|
|
14711
|
+
landingPage: sql7`COALESCE(${gaTrafficSnapshots.landingPageNormalized}, ${gaTrafficSnapshots.landingPage})`,
|
|
14712
|
+
sessions: sql7`SUM(${gaTrafficSnapshots.sessions})`,
|
|
14713
|
+
organicSessions: sql7`SUM(${gaTrafficSnapshots.organicSessions})`,
|
|
14714
|
+
users: sql7`SUM(${gaTrafficSnapshots.users})`
|
|
14715
|
+
}).from(gaTrafficSnapshots).where(eq21(gaTrafficSnapshots.projectId, project.id)).groupBy(sql7`COALESCE(${gaTrafficSnapshots.landingPageNormalized}, ${gaTrafficSnapshots.landingPage})`).orderBy(sql7`SUM(${gaTrafficSnapshots.sessions}) DESC`).all();
|
|
14676
14716
|
return {
|
|
14677
14717
|
pages: trafficPages.map((r) => ({
|
|
14678
14718
|
landingPage: r.landingPage,
|
|
@@ -14888,10 +14928,10 @@ function buildAuthErrorMessage(res, responseText) {
|
|
|
14888
14928
|
}
|
|
14889
14929
|
return "WordPress credentials are invalid or lack permission for this action";
|
|
14890
14930
|
}
|
|
14891
|
-
async function fetchJson(connection, siteUrl,
|
|
14931
|
+
async function fetchJson(connection, siteUrl, path16, init) {
|
|
14892
14932
|
if (siteUrl.startsWith("http:")) {
|
|
14893
14933
|
}
|
|
14894
|
-
const res = await fetch(`${normalizeSiteUrl(siteUrl)}${
|
|
14934
|
+
const res = await fetch(`${normalizeSiteUrl(siteUrl)}${path16}`, {
|
|
14895
14935
|
...init,
|
|
14896
14936
|
headers: {
|
|
14897
14937
|
"Authorization": `Basic ${encodeBasicAuth(connection.username, connection.appPassword)}`,
|
|
@@ -16309,7 +16349,7 @@ async function wordpressRoutes(app, opts) {
|
|
|
16309
16349
|
|
|
16310
16350
|
// ../api-routes/src/backlinks.ts
|
|
16311
16351
|
import crypto18 from "crypto";
|
|
16312
|
-
import { and as and14, asc as asc2, desc as desc11, eq as eq22, sql as
|
|
16352
|
+
import { and as and14, asc as asc2, desc as desc11, eq as eq22, sql as sql8 } from "drizzle-orm";
|
|
16313
16353
|
|
|
16314
16354
|
// ../integration-commoncrawl/src/constants.ts
|
|
16315
16355
|
import os3 from "os";
|
|
@@ -16593,7 +16633,7 @@ async function queryBacklinks(opts) {
|
|
|
16593
16633
|
const reversed = opts.targets.map(reverseDomain);
|
|
16594
16634
|
const targetList = reversed.map(quote).join(", ");
|
|
16595
16635
|
const limitClause = opts.limitPerTarget ? `QUALIFY row_number() OVER (PARTITION BY t.target_rev_domain ORDER BY v.num_hosts DESC) <= ${Math.floor(opts.limitPerTarget)}` : "";
|
|
16596
|
-
const
|
|
16636
|
+
const sql15 = `
|
|
16597
16637
|
WITH vertices AS (
|
|
16598
16638
|
SELECT * FROM read_csv(
|
|
16599
16639
|
${quote(opts.vertexPath)},
|
|
@@ -16629,7 +16669,7 @@ async function queryBacklinks(opts) {
|
|
|
16629
16669
|
const conn = await instance.connect();
|
|
16630
16670
|
let rows;
|
|
16631
16671
|
try {
|
|
16632
|
-
const reader = await conn.runAndReadAll(
|
|
16672
|
+
const reader = await conn.runAndReadAll(sql15);
|
|
16633
16673
|
rows = reader.getRowObjects();
|
|
16634
16674
|
} finally {
|
|
16635
16675
|
conn.disconnectSync?.();
|
|
@@ -16805,12 +16845,12 @@ function computeFilteredSummary(db, base) {
|
|
|
16805
16845
|
);
|
|
16806
16846
|
const filteredCondition = and14(baseDomainCondition, backlinkCrawlerExclusionClause());
|
|
16807
16847
|
const unfilteredAgg = db.select({
|
|
16808
|
-
count:
|
|
16809
|
-
total:
|
|
16848
|
+
count: sql8`count(*)`,
|
|
16849
|
+
total: sql8`coalesce(sum(${backlinkDomains.numHosts}), 0)`
|
|
16810
16850
|
}).from(backlinkDomains).where(baseDomainCondition).get();
|
|
16811
16851
|
const filteredAgg = db.select({
|
|
16812
|
-
count:
|
|
16813
|
-
total:
|
|
16852
|
+
count: sql8`count(*)`,
|
|
16853
|
+
total: sql8`coalesce(sum(${backlinkDomains.numHosts}), 0)`
|
|
16814
16854
|
}).from(backlinkDomains).where(filteredCondition).get();
|
|
16815
16855
|
const top10Rows = db.select({ numHosts: backlinkDomains.numHosts }).from(backlinkDomains).where(filteredCondition).orderBy(desc11(backlinkDomains.numHosts)).limit(10).all();
|
|
16816
16856
|
const totalLinkingDomains = Number(filteredAgg?.count ?? 0);
|
|
@@ -16984,7 +17024,7 @@ async function backlinksRoutes(app, opts) {
|
|
|
16984
17024
|
eq22(backlinkDomains.release, targetRelease)
|
|
16985
17025
|
);
|
|
16986
17026
|
const domainCondition = excludeCrawlers ? and14(baseDomainCondition, backlinkCrawlerExclusionClause()) : baseDomainCondition;
|
|
16987
|
-
const totalRow = app.db.select({ count:
|
|
17027
|
+
const totalRow = app.db.select({ count: sql8`count(*)` }).from(backlinkDomains).where(domainCondition).get();
|
|
16988
17028
|
const rows = app.db.select({
|
|
16989
17029
|
linkingDomain: backlinkDomains.linkingDomain,
|
|
16990
17030
|
numHosts: backlinkDomains.numHosts
|
|
@@ -17019,7 +17059,7 @@ async function backlinksRoutes(app, opts) {
|
|
|
17019
17059
|
|
|
17020
17060
|
// ../api-routes/src/traffic.ts
|
|
17021
17061
|
import crypto20 from "crypto";
|
|
17022
|
-
import { and as and15, desc as desc12, eq as eq23, gte as gte2, lte as lte2, sql as
|
|
17062
|
+
import { and as and15, desc as desc12, eq as eq23, gte as gte2, lte as lte2, sql as sql9 } from "drizzle-orm";
|
|
17023
17063
|
|
|
17024
17064
|
// ../integration-cloud-run/src/auth.ts
|
|
17025
17065
|
import crypto19 from "crypto";
|
|
@@ -17518,8 +17558,8 @@ var ASSET_PATH_PREFIXES = [
|
|
|
17518
17558
|
"/img/",
|
|
17519
17559
|
"/static/"
|
|
17520
17560
|
];
|
|
17521
|
-
function normalizeTrafficPathPattern(
|
|
17522
|
-
const cleanPath =
|
|
17561
|
+
function normalizeTrafficPathPattern(path16) {
|
|
17562
|
+
const cleanPath = path16.trim() || "/";
|
|
17523
17563
|
const pathOnly = cleanPath.split("?")[0] || "/";
|
|
17524
17564
|
const segments = pathOnly.split("/").map((segment) => {
|
|
17525
17565
|
if (!segment) return segment;
|
|
@@ -17568,8 +17608,8 @@ function resolveAiReferralLandingPath(event, evidenceType) {
|
|
|
17568
17608
|
}
|
|
17569
17609
|
return normalizeTrafficPathPattern(event.path);
|
|
17570
17610
|
}
|
|
17571
|
-
function isLikelySubresourcePath(
|
|
17572
|
-
const cleanPath =
|
|
17611
|
+
function isLikelySubresourcePath(path16) {
|
|
17612
|
+
const cleanPath = path16.split("?")[0] || "/";
|
|
17573
17613
|
return ASSET_PATH_PREFIXES.some((prefix) => cleanPath.startsWith(prefix)) || ASSET_EXTENSION_PATTERN.test(cleanPath);
|
|
17574
17614
|
}
|
|
17575
17615
|
function actorKey(event) {
|
|
@@ -17755,11 +17795,11 @@ function buildEventId2(event) {
|
|
|
17755
17795
|
function normalizeWordpressTrafficEvent(event) {
|
|
17756
17796
|
if (!event.observed_at) return null;
|
|
17757
17797
|
if (typeof event.id !== "number" || !Number.isFinite(event.id)) return null;
|
|
17758
|
-
const
|
|
17759
|
-
if (!
|
|
17798
|
+
const path16 = event.path?.trim();
|
|
17799
|
+
if (!path16) return null;
|
|
17760
17800
|
const queryString = trimOrNull(event.query_string);
|
|
17761
17801
|
const host = trimOrNull(event.host);
|
|
17762
|
-
const requestUrl = host ? `https://${host}${
|
|
17802
|
+
const requestUrl = host ? `https://${host}${path16}${queryString ? `?${queryString}` : ""}` : `${path16}${queryString ? `?${queryString}` : ""}`;
|
|
17763
17803
|
return {
|
|
17764
17804
|
sourceType: TrafficSourceTypes.wordpress,
|
|
17765
17805
|
evidenceKind: TrafficEvidenceKinds["raw-request"],
|
|
@@ -17769,7 +17809,7 @@ function normalizeWordpressTrafficEvent(event) {
|
|
|
17769
17809
|
method: trimOrNull(event.method),
|
|
17770
17810
|
requestUrl,
|
|
17771
17811
|
host,
|
|
17772
|
-
path:
|
|
17812
|
+
path: path16,
|
|
17773
17813
|
queryString,
|
|
17774
17814
|
status: typeof event.status === "number" && Number.isFinite(event.status) ? event.status : null,
|
|
17775
17815
|
userAgent: trimOrNull(event.user_agent),
|
|
@@ -17933,15 +17973,15 @@ function stringLabels(input) {
|
|
|
17933
17973
|
);
|
|
17934
17974
|
}
|
|
17935
17975
|
function normalizeVercelLogRow(row) {
|
|
17936
|
-
const
|
|
17937
|
-
if (!
|
|
17976
|
+
const path16 = row.requestPath;
|
|
17977
|
+
if (!path16) return null;
|
|
17938
17978
|
const observedAt = row.timestamp;
|
|
17939
17979
|
if (!observedAt) return null;
|
|
17940
17980
|
const requestId = row.requestId;
|
|
17941
17981
|
if (!requestId) return null;
|
|
17942
17982
|
const host = emptyToNull(row.domain);
|
|
17943
17983
|
const queryString = serializeSearchParams(row.requestSearchParams);
|
|
17944
|
-
const requestUrl = host ? `https://${host}${
|
|
17984
|
+
const requestUrl = host ? `https://${host}${path16}${queryString ? `?${queryString}` : ""}` : null;
|
|
17945
17985
|
return {
|
|
17946
17986
|
sourceType: TrafficSourceTypes.vercel,
|
|
17947
17987
|
evidenceKind: TrafficEvidenceKinds["raw-request"],
|
|
@@ -17951,7 +17991,7 @@ function normalizeVercelLogRow(row) {
|
|
|
17951
17991
|
method: row.requestMethod ?? null,
|
|
17952
17992
|
requestUrl,
|
|
17953
17993
|
host,
|
|
17954
|
-
path:
|
|
17994
|
+
path: path16,
|
|
17955
17995
|
queryString,
|
|
17956
17996
|
status: resolveStatus(row),
|
|
17957
17997
|
userAgent: emptyToNull(row.clientUserAgent),
|
|
@@ -18757,7 +18797,7 @@ async function trafficRoutes(app, opts) {
|
|
|
18757
18797
|
crawlerEventsHourly.status
|
|
18758
18798
|
],
|
|
18759
18799
|
set: {
|
|
18760
|
-
hits:
|
|
18800
|
+
hits: sql9`${crawlerEventsHourly.hits} + ${bucket.hits}`,
|
|
18761
18801
|
sampledUserAgent: bucket.sampledUserAgent,
|
|
18762
18802
|
updatedAt: finishedAt
|
|
18763
18803
|
}
|
|
@@ -18792,7 +18832,7 @@ async function trafficRoutes(app, opts) {
|
|
|
18792
18832
|
aiReferralEventsHourly.status
|
|
18793
18833
|
],
|
|
18794
18834
|
set: {
|
|
18795
|
-
sessionsOrHits:
|
|
18835
|
+
sessionsOrHits: sql9`${aiReferralEventsHourly.sessionsOrHits} + ${bucket.hits}`,
|
|
18796
18836
|
updatedAt: finishedAt
|
|
18797
18837
|
}
|
|
18798
18838
|
}).run();
|
|
@@ -19044,19 +19084,19 @@ async function trafficRoutes(app, opts) {
|
|
|
19044
19084
|
return response;
|
|
19045
19085
|
});
|
|
19046
19086
|
function buildSourceDetail(projectId, row, since) {
|
|
19047
|
-
const crawlerTotals = app.db.select({ total:
|
|
19087
|
+
const crawlerTotals = app.db.select({ total: sql9`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
|
|
19048
19088
|
and15(
|
|
19049
19089
|
eq23(crawlerEventsHourly.sourceId, row.id),
|
|
19050
19090
|
gte2(crawlerEventsHourly.tsHour, since)
|
|
19051
19091
|
)
|
|
19052
19092
|
).get();
|
|
19053
|
-
const aiTotals = app.db.select({ total:
|
|
19093
|
+
const aiTotals = app.db.select({ total: sql9`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
|
|
19054
19094
|
and15(
|
|
19055
19095
|
eq23(aiReferralEventsHourly.sourceId, row.id),
|
|
19056
19096
|
gte2(aiReferralEventsHourly.tsHour, since)
|
|
19057
19097
|
)
|
|
19058
19098
|
).get();
|
|
19059
|
-
const sampleTotals = app.db.select({ total:
|
|
19099
|
+
const sampleTotals = app.db.select({ total: sql9`COUNT(*)` }).from(rawEventSamples).where(
|
|
19060
19100
|
and15(
|
|
19061
19101
|
eq23(rawEventSamples.sourceId, row.id),
|
|
19062
19102
|
gte2(rawEventSamples.ts, since)
|
|
@@ -19158,7 +19198,7 @@ async function trafficRoutes(app, opts) {
|
|
|
19158
19198
|
];
|
|
19159
19199
|
if (sourceIdParam) crawlerFilters.push(eq23(crawlerEventsHourly.sourceId, sourceIdParam));
|
|
19160
19200
|
const crawlerWhere = and15(...crawlerFilters);
|
|
19161
|
-
const total = app.db.select({ total:
|
|
19201
|
+
const total = app.db.select({ total: sql9`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(crawlerWhere).get();
|
|
19162
19202
|
crawlerTotal = Number(total?.total ?? 0);
|
|
19163
19203
|
const rows = app.db.select().from(crawlerEventsHourly).where(crawlerWhere).orderBy(desc12(crawlerEventsHourly.tsHour)).limit(limit).all();
|
|
19164
19204
|
for (const r of rows) {
|
|
@@ -19183,7 +19223,7 @@ async function trafficRoutes(app, opts) {
|
|
|
19183
19223
|
];
|
|
19184
19224
|
if (sourceIdParam) aiFilters.push(eq23(aiReferralEventsHourly.sourceId, sourceIdParam));
|
|
19185
19225
|
const aiWhere = and15(...aiFilters);
|
|
19186
|
-
const total = app.db.select({ total:
|
|
19226
|
+
const total = app.db.select({ total: sql9`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(aiWhere).get();
|
|
19187
19227
|
aiReferralTotal = Number(total?.total ?? 0);
|
|
19188
19228
|
const rows = app.db.select().from(aiReferralEventsHourly).where(aiWhere).orderBy(desc12(aiReferralEventsHourly.tsHour)).limit(limit).all();
|
|
19189
19229
|
for (const r of rows) {
|
|
@@ -19216,6 +19256,75 @@ async function trafficRoutes(app, opts) {
|
|
|
19216
19256
|
});
|
|
19217
19257
|
}
|
|
19218
19258
|
|
|
19259
|
+
// ../api-routes/src/doctor/checks/agent.ts
|
|
19260
|
+
import fs6 from "fs";
|
|
19261
|
+
import path7 from "path";
|
|
19262
|
+
var REQUIRED_SKILLS = ["canonry", "aero"];
|
|
19263
|
+
var skillsInstalledCheck = {
|
|
19264
|
+
id: "agent.skills.installed",
|
|
19265
|
+
category: CheckCategories.agent,
|
|
19266
|
+
scope: CheckScopes.global,
|
|
19267
|
+
title: "Agent skills installed (~/.claude/skills/)",
|
|
19268
|
+
run: () => {
|
|
19269
|
+
const home = process.env.HOME;
|
|
19270
|
+
if (!home) {
|
|
19271
|
+
return {
|
|
19272
|
+
status: CheckStatuses.skipped,
|
|
19273
|
+
code: "agent.skills.no-home",
|
|
19274
|
+
summary: "Cannot determine $HOME \u2014 skip skills filesystem check.",
|
|
19275
|
+
remediation: null
|
|
19276
|
+
};
|
|
19277
|
+
}
|
|
19278
|
+
const skillsBase = path7.join(home, ".claude", "skills");
|
|
19279
|
+
const installed = [];
|
|
19280
|
+
const missing = [];
|
|
19281
|
+
for (const name of REQUIRED_SKILLS) {
|
|
19282
|
+
const dir = path7.join(skillsBase, name);
|
|
19283
|
+
if (isInstalled(dir)) installed.push(name);
|
|
19284
|
+
else missing.push(name);
|
|
19285
|
+
}
|
|
19286
|
+
const details = {
|
|
19287
|
+
checkedPath: skillsBase,
|
|
19288
|
+
installed,
|
|
19289
|
+
missing
|
|
19290
|
+
};
|
|
19291
|
+
if (missing.length === 0) {
|
|
19292
|
+
return {
|
|
19293
|
+
status: CheckStatuses.ok,
|
|
19294
|
+
code: "agent.skills.installed",
|
|
19295
|
+
summary: `Both canonry and aero skills are installed in ${skillsBase}.`,
|
|
19296
|
+
remediation: null,
|
|
19297
|
+
details
|
|
19298
|
+
};
|
|
19299
|
+
}
|
|
19300
|
+
if (installed.length === 0) {
|
|
19301
|
+
return {
|
|
19302
|
+
status: CheckStatuses.warn,
|
|
19303
|
+
code: "agent.skills.not-installed",
|
|
19304
|
+
summary: "Agent skills are not installed for Claude Code on this machine. Claude sessions on this host will not auto-load canonry/aero reference docs.",
|
|
19305
|
+
remediation: "Run `canonry skills install --dir ~` (or `canonry skills install --user`) to install both skills to ~/.claude/skills/ and ~/.codex/skills/.",
|
|
19306
|
+
details
|
|
19307
|
+
};
|
|
19308
|
+
}
|
|
19309
|
+
return {
|
|
19310
|
+
status: CheckStatuses.warn,
|
|
19311
|
+
code: "agent.skills.partial",
|
|
19312
|
+
summary: `Only ${installed.length} of ${REQUIRED_SKILLS.length} agent skills are installed (${installed.join(", ")}); ${missing.join(", ")} missing.`,
|
|
19313
|
+
remediation: `Run \`canonry skills install ${missing.join(" ")} --dir ~\` to fill the gap.`,
|
|
19314
|
+
details
|
|
19315
|
+
};
|
|
19316
|
+
}
|
|
19317
|
+
};
|
|
19318
|
+
function isInstalled(dir) {
|
|
19319
|
+
try {
|
|
19320
|
+
if (!fs6.existsSync(dir)) return false;
|
|
19321
|
+
return fs6.existsSync(path7.join(dir, "SKILL.md"));
|
|
19322
|
+
} catch {
|
|
19323
|
+
return false;
|
|
19324
|
+
}
|
|
19325
|
+
}
|
|
19326
|
+
var AGENT_CHECKS = [skillsInstalledCheck];
|
|
19327
|
+
|
|
19219
19328
|
// ../api-routes/src/doctor/checks/bing-auth.ts
|
|
19220
19329
|
var BING_AUTH_CHECKS = [
|
|
19221
19330
|
{
|
|
@@ -19837,7 +19946,7 @@ var providersConfiguredCheck = {
|
|
|
19837
19946
|
var PROVIDERS_CHECKS = [providersConfiguredCheck];
|
|
19838
19947
|
|
|
19839
19948
|
// ../api-routes/src/doctor/checks/traffic-source.ts
|
|
19840
|
-
import { and as and16, eq as eq24, gte as gte3, ne as ne3, sql as
|
|
19949
|
+
import { and as and16, eq as eq24, gte as gte3, ne as ne3, sql as sql10 } from "drizzle-orm";
|
|
19841
19950
|
var RECENT_DATA_WARN_DAYS = 7;
|
|
19842
19951
|
var RECENT_DATA_FAIL_DAYS = 30;
|
|
19843
19952
|
function skippedNoProject2() {
|
|
@@ -19931,7 +20040,7 @@ var recentDataCheck = {
|
|
|
19931
20040
|
const warnCutoff = new Date(now.getTime() - RECENT_DATA_WARN_DAYS * 24 * 60 * 6e4).toISOString();
|
|
19932
20041
|
const failCutoff = new Date(now.getTime() - RECENT_DATA_FAIL_DAYS * 24 * 60 * 6e4).toISOString();
|
|
19933
20042
|
const recentCrawlers = Number(
|
|
19934
|
-
ctx.db.select({ total:
|
|
20043
|
+
ctx.db.select({ total: sql10`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
|
|
19935
20044
|
and16(
|
|
19936
20045
|
eq24(crawlerEventsHourly.projectId, ctx.project.id),
|
|
19937
20046
|
gte3(crawlerEventsHourly.tsHour, warnCutoff)
|
|
@@ -19939,7 +20048,7 @@ var recentDataCheck = {
|
|
|
19939
20048
|
).get()?.total ?? 0
|
|
19940
20049
|
);
|
|
19941
20050
|
const recentReferrals = Number(
|
|
19942
|
-
ctx.db.select({ total:
|
|
20051
|
+
ctx.db.select({ total: sql10`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
|
|
19943
20052
|
and16(
|
|
19944
20053
|
eq24(aiReferralEventsHourly.projectId, ctx.project.id),
|
|
19945
20054
|
gte3(aiReferralEventsHourly.tsHour, warnCutoff)
|
|
@@ -19955,7 +20064,7 @@ var recentDataCheck = {
|
|
|
19955
20064
|
};
|
|
19956
20065
|
}
|
|
19957
20066
|
const olderCrawlers = Number(
|
|
19958
|
-
ctx.db.select({ total:
|
|
20067
|
+
ctx.db.select({ total: sql10`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
|
|
19959
20068
|
and16(
|
|
19960
20069
|
eq24(crawlerEventsHourly.projectId, ctx.project.id),
|
|
19961
20070
|
gte3(crawlerEventsHourly.tsHour, failCutoff)
|
|
@@ -19963,7 +20072,7 @@ var recentDataCheck = {
|
|
|
19963
20072
|
).get()?.total ?? 0
|
|
19964
20073
|
);
|
|
19965
20074
|
const olderReferrals = Number(
|
|
19966
|
-
ctx.db.select({ total:
|
|
20075
|
+
ctx.db.select({ total: sql10`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
|
|
19967
20076
|
and16(
|
|
19968
20077
|
eq24(aiReferralEventsHourly.projectId, ctx.project.id),
|
|
19969
20078
|
gte3(aiReferralEventsHourly.tsHour, failCutoff)
|
|
@@ -20145,7 +20254,8 @@ var ALL_CHECKS = [
|
|
|
20145
20254
|
...BING_AUTH_CHECKS,
|
|
20146
20255
|
...GA_AUTH_CHECKS,
|
|
20147
20256
|
...PROVIDERS_CHECKS,
|
|
20148
|
-
...TRAFFIC_SOURCE_CHECKS
|
|
20257
|
+
...TRAFFIC_SOURCE_CHECKS,
|
|
20258
|
+
...AGENT_CHECKS
|
|
20149
20259
|
];
|
|
20150
20260
|
var CHECK_BY_ID = Object.fromEntries(
|
|
20151
20261
|
ALL_CHECKS.map((check) => [check.id, check])
|
|
@@ -22450,7 +22560,7 @@ var localAdapter = {
|
|
|
22450
22560
|
};
|
|
22451
22561
|
|
|
22452
22562
|
// ../provider-cdp/src/adapter.ts
|
|
22453
|
-
import
|
|
22563
|
+
import path9 from "path";
|
|
22454
22564
|
import os4 from "os";
|
|
22455
22565
|
|
|
22456
22566
|
// ../provider-cdp/src/connection.ts
|
|
@@ -22815,12 +22925,12 @@ function sleep2(ms) {
|
|
|
22815
22925
|
}
|
|
22816
22926
|
|
|
22817
22927
|
// ../provider-cdp/src/screenshot.ts
|
|
22818
|
-
import
|
|
22819
|
-
import
|
|
22928
|
+
import fs7 from "fs";
|
|
22929
|
+
import path8 from "path";
|
|
22820
22930
|
async function captureElementScreenshot(client, selector, outputPath) {
|
|
22821
|
-
const dir =
|
|
22822
|
-
if (!
|
|
22823
|
-
|
|
22931
|
+
const dir = path8.dirname(outputPath);
|
|
22932
|
+
if (!fs7.existsSync(dir)) {
|
|
22933
|
+
fs7.mkdirSync(dir, { recursive: true });
|
|
22824
22934
|
}
|
|
22825
22935
|
let clip;
|
|
22826
22936
|
try {
|
|
@@ -22854,7 +22964,7 @@ async function captureElementScreenshot(client, selector, outputPath) {
|
|
|
22854
22964
|
}
|
|
22855
22965
|
const { data } = await client.Page.captureScreenshot(screenshotParams);
|
|
22856
22966
|
const buffer = Buffer.from(data, "base64");
|
|
22857
|
-
|
|
22967
|
+
fs7.writeFileSync(outputPath, buffer);
|
|
22858
22968
|
return outputPath;
|
|
22859
22969
|
}
|
|
22860
22970
|
|
|
@@ -22915,7 +23025,7 @@ function getConnection(config) {
|
|
|
22915
23025
|
return conn;
|
|
22916
23026
|
}
|
|
22917
23027
|
function getScreenshotDir2() {
|
|
22918
|
-
return
|
|
23028
|
+
return path9.join(os4.homedir(), ".canonry", "screenshots");
|
|
22919
23029
|
}
|
|
22920
23030
|
var cdpChatgptAdapter = {
|
|
22921
23031
|
name: "cdp:chatgpt",
|
|
@@ -22979,7 +23089,7 @@ var cdpChatgptAdapter = {
|
|
|
22979
23089
|
const answerText = await target.extractAnswer(client);
|
|
22980
23090
|
const groundingSources = await target.extractCitations(client);
|
|
22981
23091
|
const screenshotId = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
22982
|
-
const screenshotPath =
|
|
23092
|
+
const screenshotPath = path9.join(getScreenshotDir2(), `${screenshotId}.png`);
|
|
22983
23093
|
let capturedScreenshotPath;
|
|
22984
23094
|
try {
|
|
22985
23095
|
capturedScreenshotPath = await captureElementScreenshot(
|
|
@@ -23612,10 +23722,10 @@ function removeWordpressConnection(config, projectName) {
|
|
|
23612
23722
|
|
|
23613
23723
|
// src/job-runner.ts
|
|
23614
23724
|
import crypto24 from "crypto";
|
|
23615
|
-
import
|
|
23616
|
-
import
|
|
23725
|
+
import fs8 from "fs";
|
|
23726
|
+
import path10 from "path";
|
|
23617
23727
|
import os5 from "os";
|
|
23618
|
-
import { and as and18, eq as eq27, inArray as inArray9, sql as
|
|
23728
|
+
import { and as and18, eq as eq27, inArray as inArray9, sql as sql11 } from "drizzle-orm";
|
|
23619
23729
|
|
|
23620
23730
|
// src/run-telemetry.ts
|
|
23621
23731
|
import crypto23 from "crypto";
|
|
@@ -24106,12 +24216,12 @@ var JobRunner = class {
|
|
|
24106
24216
|
allBrandNames
|
|
24107
24217
|
);
|
|
24108
24218
|
let screenshotRelPath = null;
|
|
24109
|
-
if (raw.screenshotPath &&
|
|
24219
|
+
if (raw.screenshotPath && fs8.existsSync(raw.screenshotPath)) {
|
|
24110
24220
|
const snapshotId = crypto24.randomUUID();
|
|
24111
|
-
const screenshotDir =
|
|
24112
|
-
if (!
|
|
24113
|
-
const destPath =
|
|
24114
|
-
|
|
24221
|
+
const screenshotDir = path10.join(os5.homedir(), ".canonry", "screenshots", runId);
|
|
24222
|
+
if (!fs8.existsSync(screenshotDir)) fs8.mkdirSync(screenshotDir, { recursive: true });
|
|
24223
|
+
const destPath = path10.join(screenshotDir, `${snapshotId}.png`);
|
|
24224
|
+
fs8.renameSync(raw.screenshotPath, destPath);
|
|
24115
24225
|
screenshotRelPath = `${runId}/${snapshotId}.png`;
|
|
24116
24226
|
this.db.insert(querySnapshots).values({
|
|
24117
24227
|
id: snapshotId,
|
|
@@ -24296,7 +24406,7 @@ var JobRunner = class {
|
|
|
24296
24406
|
updatedAt: now
|
|
24297
24407
|
}).onConflictDoUpdate({
|
|
24298
24408
|
target: [usageCounters.scope, usageCounters.period, usageCounters.metric],
|
|
24299
|
-
set: { count:
|
|
24409
|
+
set: { count: sql11`${usageCounters.count} + ${count}`, updatedAt: now }
|
|
24300
24410
|
}).run();
|
|
24301
24411
|
}
|
|
24302
24412
|
flushProviderUsage(projectId, providerDispatchCounts) {
|
|
@@ -24366,7 +24476,7 @@ function buildPhases(input) {
|
|
|
24366
24476
|
|
|
24367
24477
|
// src/gsc-sync.ts
|
|
24368
24478
|
import crypto25 from "crypto";
|
|
24369
|
-
import { eq as eq28, and as and19, sql as
|
|
24479
|
+
import { eq as eq28, and as and19, sql as sql12 } from "drizzle-orm";
|
|
24370
24480
|
var log2 = createLogger("GscSync");
|
|
24371
24481
|
function formatDate3(d) {
|
|
24372
24482
|
return d.toISOString().split("T")[0];
|
|
@@ -24420,8 +24530,8 @@ async function executeGscSync(db, runId, projectId, opts) {
|
|
|
24420
24530
|
db.delete(gscSearchData).where(
|
|
24421
24531
|
and19(
|
|
24422
24532
|
eq28(gscSearchData.projectId, projectId),
|
|
24423
|
-
|
|
24424
|
-
|
|
24533
|
+
sql12`${gscSearchData.date} >= ${startDate}`,
|
|
24534
|
+
sql12`${gscSearchData.date} <= ${endDate}`
|
|
24425
24535
|
)
|
|
24426
24536
|
).run();
|
|
24427
24537
|
const batchSize = 500;
|
|
@@ -24956,8 +25066,8 @@ async function executeBingInspectSitemap(db, runId, projectId, opts) {
|
|
|
24956
25066
|
|
|
24957
25067
|
// src/commoncrawl-sync.ts
|
|
24958
25068
|
import crypto28 from "crypto";
|
|
24959
|
-
import
|
|
24960
|
-
import { and as and21, eq as eq31, sql as
|
|
25069
|
+
import path11 from "path";
|
|
25070
|
+
import { and as and21, eq as eq31, sql as sql13 } from "drizzle-orm";
|
|
24961
25071
|
var log6 = createLogger("CommonCrawlSync");
|
|
24962
25072
|
var INSERT_CHUNK_SIZE = 1e4;
|
|
24963
25073
|
function defaultDeps() {
|
|
@@ -24985,9 +25095,9 @@ async function executeReleaseSync(db, syncId, opts) {
|
|
|
24985
25095
|
error: null
|
|
24986
25096
|
}).where(eq31(ccReleaseSyncs.id, syncId)).run();
|
|
24987
25097
|
const paths = ccReleasePaths(release);
|
|
24988
|
-
const releaseCacheDir =
|
|
24989
|
-
const vertexPath =
|
|
24990
|
-
const edgesPath =
|
|
25098
|
+
const releaseCacheDir = path11.join(deps.cacheDir, release);
|
|
25099
|
+
const vertexPath = path11.join(releaseCacheDir, paths.vertexFilename);
|
|
25100
|
+
const edgesPath = path11.join(releaseCacheDir, paths.edgesFilename);
|
|
24991
25101
|
const [vertex, edges] = await Promise.all([
|
|
24992
25102
|
deps.downloadFile({ url: paths.vertexUrl, destPath: vertexPath }),
|
|
24993
25103
|
deps.downloadFile({ url: paths.edgesUrl, destPath: edgesPath })
|
|
@@ -25147,7 +25257,7 @@ function computeSummary(rows) {
|
|
|
25147
25257
|
|
|
25148
25258
|
// src/backlink-extract.ts
|
|
25149
25259
|
import crypto29 from "crypto";
|
|
25150
|
-
import
|
|
25260
|
+
import fs9 from "fs";
|
|
25151
25261
|
import { and as and22, desc as desc15, eq as eq32 } from "drizzle-orm";
|
|
25152
25262
|
var log7 = createLogger("BacklinkExtract");
|
|
25153
25263
|
function defaultDeps2() {
|
|
@@ -25176,7 +25286,7 @@ async function executeBacklinkExtract(db, runId, projectId, opts = {}) {
|
|
|
25176
25286
|
if (!sync.vertexPath || !sync.edgesPath) {
|
|
25177
25287
|
throw new Error(`Release ${sync.release} is missing cached file paths`);
|
|
25178
25288
|
}
|
|
25179
|
-
if (!
|
|
25289
|
+
if (!fs9.existsSync(sync.vertexPath) || !fs9.existsSync(sync.edgesPath)) {
|
|
25180
25290
|
throw new Error(
|
|
25181
25291
|
`Cache for release ${sync.release} is missing from disk (expected at ${sync.vertexPath}). The sync record exists in the database, but the ~16 GB dump was deleted or never present on this machine. Re-sync this release from the Backlinks admin page to restore the cache.`
|
|
25182
25292
|
);
|
|
@@ -25991,19 +26101,24 @@ function readStoredGroundingSources(rawResponse) {
|
|
|
25991
26101
|
return result;
|
|
25992
26102
|
}
|
|
25993
26103
|
async function backfillInsightsCommand(project, opts) {
|
|
25994
|
-
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-
|
|
26104
|
+
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-7AWRUNI2.js");
|
|
25995
26105
|
const config = loadConfig();
|
|
25996
26106
|
const db = createClient(config.database);
|
|
25997
26107
|
migrate(db);
|
|
25998
26108
|
const service = new IntelligenceService2(db);
|
|
25999
26109
|
const isJson = opts?.format === "json";
|
|
26110
|
+
const isDryRun = opts?.dryRun === true;
|
|
26000
26111
|
if (!isJson) {
|
|
26001
|
-
|
|
26112
|
+
const scope = opts?.since ? ` (since ${opts.since})` : "";
|
|
26113
|
+
const mode = isDryRun ? " [DRY RUN \u2014 no writes]" : "";
|
|
26114
|
+
process.stderr.write(`Backfilling insights for "${project}"${scope}${mode}...
|
|
26002
26115
|
`);
|
|
26003
26116
|
}
|
|
26004
26117
|
const result = service.backfill(project, {
|
|
26005
26118
|
fromRunId: opts?.fromRun,
|
|
26006
|
-
toRunId: opts?.toRun
|
|
26119
|
+
toRunId: opts?.toRun,
|
|
26120
|
+
since: opts?.since,
|
|
26121
|
+
dryRun: isDryRun
|
|
26007
26122
|
}, (info) => {
|
|
26008
26123
|
if (!isJson) {
|
|
26009
26124
|
process.stderr.write(` [${info.index}/${info.total}] ${info.runId} \u2014 ${info.insights} insights
|
|
@@ -26016,15 +26131,23 @@ async function backfillInsightsCommand(project, opts) {
|
|
|
26016
26131
|
skipped: result.skipped,
|
|
26017
26132
|
totalInsights: result.totalInsights
|
|
26018
26133
|
};
|
|
26134
|
+
if (result.dryRun) {
|
|
26135
|
+
output.dryRun = true;
|
|
26136
|
+
output.delta = result.delta;
|
|
26137
|
+
}
|
|
26019
26138
|
if (isJson) {
|
|
26020
26139
|
console.log(JSON.stringify(output, null, 2));
|
|
26021
26140
|
return;
|
|
26022
26141
|
}
|
|
26023
26142
|
console.log(`
|
|
26024
|
-
Backfill complete.`);
|
|
26143
|
+
Backfill ${isDryRun ? "preview" : "complete"}.`);
|
|
26025
26144
|
console.log(` Processed: ${result.processed}`);
|
|
26026
26145
|
console.log(` Skipped: ${result.skipped}`);
|
|
26027
26146
|
console.log(` Insights: ${result.totalInsights}`);
|
|
26147
|
+
if (result.delta) {
|
|
26148
|
+
console.log(` Delta: -${result.delta.wouldDelete} existing +${result.delta.wouldCreate} new (net ${result.delta.netChange >= 0 ? "+" : ""}${result.delta.netChange})`);
|
|
26149
|
+
console.log(` No DB writes performed. Re-run without --dry-run to apply.`);
|
|
26150
|
+
}
|
|
26028
26151
|
}
|
|
26029
26152
|
function reparseProviderSnapshot(provider, rawResponse) {
|
|
26030
26153
|
const envelope = parseJsonColumn(rawResponse, {});
|
|
@@ -26621,8 +26744,8 @@ import crypto33 from "crypto";
|
|
|
26621
26744
|
import { eq as eq39 } from "drizzle-orm";
|
|
26622
26745
|
|
|
26623
26746
|
// src/agent/session.ts
|
|
26624
|
-
import
|
|
26625
|
-
import
|
|
26747
|
+
import fs12 from "fs";
|
|
26748
|
+
import path14 from "path";
|
|
26626
26749
|
import { Agent } from "@mariozechner/pi-agent-core";
|
|
26627
26750
|
import { registerBuiltInApiProviders } from "@mariozechner/pi-ai";
|
|
26628
26751
|
|
|
@@ -26723,26 +26846,26 @@ function buildAgentProvidersResponse(config) {
|
|
|
26723
26846
|
}
|
|
26724
26847
|
|
|
26725
26848
|
// src/agent/skill-paths.ts
|
|
26726
|
-
import
|
|
26727
|
-
import
|
|
26849
|
+
import fs10 from "fs";
|
|
26850
|
+
import path12 from "path";
|
|
26728
26851
|
import { fileURLToPath } from "url";
|
|
26729
26852
|
function resolveAeroSkillDir(pkgDir) {
|
|
26730
|
-
const here = pkgDir ??
|
|
26853
|
+
const here = pkgDir ?? path12.dirname(fileURLToPath(import.meta.url));
|
|
26731
26854
|
const candidates = [
|
|
26732
|
-
|
|
26733
|
-
|
|
26734
|
-
|
|
26855
|
+
path12.join(here, "../assets/agent-workspace/skills/aero"),
|
|
26856
|
+
path12.join(here, "../../assets/agent-workspace/skills/aero"),
|
|
26857
|
+
path12.join(here, "../../../../skills/aero")
|
|
26735
26858
|
];
|
|
26736
26859
|
for (const candidate of candidates) {
|
|
26737
|
-
if (
|
|
26860
|
+
if (fs10.existsSync(path12.join(candidate, "SKILL.md"))) return candidate;
|
|
26738
26861
|
}
|
|
26739
26862
|
throw new Error(`Aero skill not found. Searched:
|
|
26740
26863
|
${candidates.join("\n ")}`);
|
|
26741
26864
|
}
|
|
26742
26865
|
|
|
26743
26866
|
// src/agent/skill-tools.ts
|
|
26744
|
-
import
|
|
26745
|
-
import
|
|
26867
|
+
import fs11 from "fs";
|
|
26868
|
+
import path13 from "path";
|
|
26746
26869
|
import { Type } from "@sinclair/typebox";
|
|
26747
26870
|
var MAX_DOC_CHARS = 2e4;
|
|
26748
26871
|
function textResult(details) {
|
|
@@ -26763,13 +26886,13 @@ function parseDescription(body) {
|
|
|
26763
26886
|
return "(no description)";
|
|
26764
26887
|
}
|
|
26765
26888
|
function scanSkillDocs(skillDir) {
|
|
26766
|
-
const refsDir =
|
|
26767
|
-
if (!
|
|
26889
|
+
const refsDir = path13.join(skillDir ?? resolveAeroSkillDir(), "references");
|
|
26890
|
+
if (!fs11.existsSync(refsDir)) return [];
|
|
26768
26891
|
const entries = [];
|
|
26769
|
-
for (const file of
|
|
26892
|
+
for (const file of fs11.readdirSync(refsDir)) {
|
|
26770
26893
|
if (!file.endsWith(".md")) continue;
|
|
26771
|
-
const filePath =
|
|
26772
|
-
const body =
|
|
26894
|
+
const filePath = path13.join(refsDir, file);
|
|
26895
|
+
const body = fs11.readFileSync(filePath, "utf-8");
|
|
26773
26896
|
entries.push({
|
|
26774
26897
|
slug: file.replace(/\.md$/, ""),
|
|
26775
26898
|
description: parseDescription(body),
|
|
@@ -26812,8 +26935,8 @@ function buildReadSkillDocTool() {
|
|
|
26812
26935
|
availableSlugs: docs.map((d) => d.slug)
|
|
26813
26936
|
});
|
|
26814
26937
|
}
|
|
26815
|
-
const filePath =
|
|
26816
|
-
const content =
|
|
26938
|
+
const filePath = path13.join(skillDir, "references", `${match.slug}.md`);
|
|
26939
|
+
const content = fs11.readFileSync(filePath, "utf-8");
|
|
26817
26940
|
if (content.length > MAX_DOC_CHARS) {
|
|
26818
26941
|
return textResult({
|
|
26819
26942
|
slug: match.slug,
|
|
@@ -26907,10 +27030,10 @@ function ensureBuiltinsRegistered() {
|
|
|
26907
27030
|
}
|
|
26908
27031
|
function loadAeroSystemPrompt(pkgDir) {
|
|
26909
27032
|
const skillDir = resolveAeroSkillDir(pkgDir);
|
|
26910
|
-
const skillBody =
|
|
26911
|
-
const soulPath =
|
|
26912
|
-
if (!
|
|
26913
|
-
const soulBody =
|
|
27033
|
+
const skillBody = fs12.readFileSync(path14.join(skillDir, "SKILL.md"), "utf-8");
|
|
27034
|
+
const soulPath = path14.join(skillDir, "soul.md");
|
|
27035
|
+
if (!fs12.existsSync(soulPath)) return skillBody;
|
|
27036
|
+
const soulBody = fs12.readFileSync(soulPath, "utf-8");
|
|
26914
27037
|
return `${soulBody.trimEnd()}
|
|
26915
27038
|
|
|
26916
27039
|
---
|
|
@@ -26968,7 +27091,7 @@ function resolveSessionProviderAndModel(config, opts) {
|
|
|
26968
27091
|
|
|
26969
27092
|
// src/agent/memory-store.ts
|
|
26970
27093
|
import crypto32 from "crypto";
|
|
26971
|
-
import { and as and27, desc as desc17, eq as eq38, like as like2, sql as
|
|
27094
|
+
import { and as and27, desc as desc17, eq as eq38, like as like2, sql as sql14 } from "drizzle-orm";
|
|
26972
27095
|
var COMPACTION_KEY_PREFIX = "compaction:";
|
|
26973
27096
|
var COMPACTION_NOTES_PER_SESSION = 3;
|
|
26974
27097
|
function rowToDto2(row) {
|
|
@@ -27054,7 +27177,7 @@ function writeCompactionNote(db, args) {
|
|
|
27054
27177
|
).orderBy(desc17(agentMemory.updatedAt)).all();
|
|
27055
27178
|
const stale = existing.slice(COMPACTION_NOTES_PER_SESSION).map((r) => r.id);
|
|
27056
27179
|
if (stale.length > 0) {
|
|
27057
|
-
tx.delete(agentMemory).where(
|
|
27180
|
+
tx.delete(agentMemory).where(sql14`${agentMemory.id} IN (${sql14.join(stale.map((s) => sql14`${s}`), sql14`, `)})`).run();
|
|
27058
27181
|
}
|
|
27059
27182
|
const row = tx.select().from(agentMemory).where(and27(eq38(agentMemory.projectId, args.projectId), eq38(agentMemory.key, key))).get();
|
|
27060
27183
|
if (row) inserted = rowToDto2(row);
|
|
@@ -27812,13 +27935,13 @@ function extractHostname(domain) {
|
|
|
27812
27935
|
function fetchWithPinnedAddress(target) {
|
|
27813
27936
|
return new Promise((resolve) => {
|
|
27814
27937
|
const port = target.url.port ? Number(target.url.port) : 443;
|
|
27815
|
-
const
|
|
27938
|
+
const path16 = target.url.pathname + target.url.search;
|
|
27816
27939
|
const req = https2.request(
|
|
27817
27940
|
{
|
|
27818
27941
|
hostname: target.address,
|
|
27819
27942
|
family: target.family,
|
|
27820
27943
|
port,
|
|
27821
|
-
path:
|
|
27944
|
+
path: path16,
|
|
27822
27945
|
method: "GET",
|
|
27823
27946
|
timeout: FETCH_TIMEOUT_MS2,
|
|
27824
27947
|
servername: target.url.hostname,
|
|
@@ -28723,8 +28846,8 @@ async function createServer(opts) {
|
|
|
28723
28846
|
);
|
|
28724
28847
|
jobRunner.onRunCompleted = (runId, projectId) => runCoordinator.onRunCompleted(runId, projectId);
|
|
28725
28848
|
const snapshotService = new SnapshotService(registry);
|
|
28726
|
-
const orphanedOpenClawDir =
|
|
28727
|
-
if (
|
|
28849
|
+
const orphanedOpenClawDir = path15.join(os6.homedir(), ".openclaw-aero");
|
|
28850
|
+
if (fs13.existsSync(orphanedOpenClawDir)) {
|
|
28728
28851
|
app.log.warn(
|
|
28729
28852
|
{ path: orphanedOpenClawDir },
|
|
28730
28853
|
"OpenClaw gateway is no longer used. Remove ~/.openclaw-aero/ manually to reclaim the directory."
|
|
@@ -29439,10 +29562,10 @@ async function createServer(opts) {
|
|
|
29439
29562
|
return snapshotService.createReport(input);
|
|
29440
29563
|
}
|
|
29441
29564
|
});
|
|
29442
|
-
const dirname =
|
|
29443
|
-
const assetsDir =
|
|
29444
|
-
if (
|
|
29445
|
-
const indexPath =
|
|
29565
|
+
const dirname = path15.dirname(fileURLToPath2(import.meta.url));
|
|
29566
|
+
const assetsDir = path15.join(dirname, "..", "assets");
|
|
29567
|
+
if (fs13.existsSync(assetsDir)) {
|
|
29568
|
+
const indexPath = path15.join(assetsDir, "index.html");
|
|
29446
29569
|
const injectConfig = (html) => {
|
|
29447
29570
|
const clientConfig = {};
|
|
29448
29571
|
if (basePath) clientConfig.basePath = basePath;
|
|
@@ -29460,8 +29583,8 @@ async function createServer(opts) {
|
|
|
29460
29583
|
index: false
|
|
29461
29584
|
});
|
|
29462
29585
|
const serveIndex = (_request, reply) => {
|
|
29463
|
-
if (
|
|
29464
|
-
const html =
|
|
29586
|
+
if (fs13.existsSync(indexPath)) {
|
|
29587
|
+
const html = fs13.readFileSync(indexPath, "utf-8");
|
|
29465
29588
|
return reply.type("text/html").send(injectConfig(html));
|
|
29466
29589
|
}
|
|
29467
29590
|
return reply.status(404).send({ error: "Dashboard not built" });
|
|
@@ -29481,8 +29604,8 @@ async function createServer(opts) {
|
|
|
29481
29604
|
if (basePath && !url.startsWith(basePath)) {
|
|
29482
29605
|
return reply.status(404).send({ error: "Not found", path: request.url });
|
|
29483
29606
|
}
|
|
29484
|
-
if (
|
|
29485
|
-
const html =
|
|
29607
|
+
if (fs13.existsSync(indexPath)) {
|
|
29608
|
+
const html = fs13.readFileSync(indexPath, "utf-8");
|
|
29486
29609
|
return reply.type("text/html").send(injectConfig(html));
|
|
29487
29610
|
}
|
|
29488
29611
|
return reply.status(404).send({ error: "Not found" });
|