@canonry/canonry 4.134.0 → 4.134.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/agent-workspace/skills/canonry/references/aeo-analysis.md +3 -2
- package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +14 -3
- package/assets/assets/{AuditHistoryPanel-DBUWbfNk.js → AuditHistoryPanel-BW7LVMSZ.js} +1 -1
- package/assets/assets/{BacklinksPage-BFm0VdUO.js → BacklinksPage-DU65axM1.js} +1 -1
- package/assets/assets/{ChartPrimitives-oV_nduTH.js → ChartPrimitives-CUZJ7nUb.js} +1 -1
- package/assets/assets/{HistoryPage-IF2FMem3.js → HistoryPage-BswdEXC5.js} +1 -1
- package/assets/assets/ProjectPage-CttTuKKo.js +8 -0
- package/assets/assets/{RunRow-De5zdch5.js → RunRow-CBxbfubI.js} +1 -1
- package/assets/assets/{RunsPage-xtRF78r8.js → RunsPage-BQxA05ua.js} +1 -1
- package/assets/assets/{SettingsPage-B_GAxaWu.js → SettingsPage-krEusjc9.js} +1 -1
- package/assets/assets/{TrafficPage-E8I5ineJ.js → TrafficPage-DMhcA9lg.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-DGk2MqSp.js → TrafficSourceDetailPage-Dm0Gj0HS.js} +1 -1
- package/assets/assets/{arrow-left-D-4QMxi9.js → arrow-left-_1YaUPbl.js} +1 -1
- package/assets/assets/{extract-error-message-DuqIFU8Z.js → extract-error-message-D4XKG37U.js} +1 -1
- package/assets/assets/{index-De1MKbc7.js → index-V1C3c7nO.js} +68 -68
- package/assets/assets/{trash-2-BVh__r6G.js → trash-2-D3LWIGDJ.js} +1 -1
- package/assets/index.html +1 -1
- package/dist/{chunk-ZUQPHGEN.js → chunk-BSU2MI3Y.js} +35 -3
- package/dist/{chunk-PC7AYXND.js → chunk-CF5WTWXI.js} +24 -0
- package/dist/{chunk-LIXWDIDR.js → chunk-DVJGFY3J.js} +189 -72
- package/dist/{chunk-TKXWTDV6.js → chunk-NWVPRV7A.js} +4 -4
- package/dist/cli.js +49 -5
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-4XOFUN5E.js → intelligence-service-NO4FJUYD.js} +2 -2
- package/dist/mcp.js +2 -2
- package/package.json +7 -7
- package/assets/assets/ProjectPage-ClwxX9Ga.js +0 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
import{c as a}from"./index-
|
|
1
|
+
import{c as a}from"./index-V1C3c7nO.js";const c=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],d=a("circle-check",c);const e=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3",key:"1u773s"}],["path",{d:"M12 17h.01",key:"p32p05"}]],k=a("circle-question-mark",e);const t=[["path",{d:"M12 15V3",key:"m9g1x1"}],["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["path",{d:"m7 10 5 5 5-5",key:"brsn70"}]],s=a("download",t);const o=[["path",{d:"M15 3h6v6",key:"1q9fwt"}],["path",{d:"M10 14 21 3",key:"gplh6r"}],["path",{d:"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",key:"a6xqqp"}]],r=a("external-link",o);const n=[["path",{d:"M10 11v6",key:"nco0om"}],["path",{d:"M14 11v6",key:"outv1u"}],["path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6",key:"miytrc"}],["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2",key:"e791ji"}]],y=a("trash-2",n);export{d as C,s as D,r as E,y as T,k as a};
|
package/assets/index.html
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
<link rel="icon" type="image/png" sizes="32x32" href="./favicon-32.png" />
|
|
13
13
|
<link rel="apple-touch-icon" href="./apple-touch-icon.png" />
|
|
14
14
|
<title>Canonry</title>
|
|
15
|
-
<script type="module" crossorigin src="./assets/index-
|
|
15
|
+
<script type="module" crossorigin src="./assets/index-V1C3c7nO.js"></script>
|
|
16
16
|
<link rel="modulepreload" crossorigin href="./assets/vendor-tanstack-Be8JdV5M.js">
|
|
17
17
|
<link rel="modulepreload" crossorigin href="./assets/vendor-radix-CQ77EO2y.js">
|
|
18
18
|
<link rel="modulepreload" crossorigin href="./assets/vendor-recharts-DSxTZhaH.js">
|
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
trafficConnectWordpressRequestSchema,
|
|
43
43
|
trafficEventKindSchema,
|
|
44
44
|
trafficSeriesGranularitySchema
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-CF5WTWXI.js";
|
|
46
46
|
|
|
47
47
|
// src/config.ts
|
|
48
48
|
import fs from "fs";
|
|
@@ -3283,6 +3283,18 @@ var getApiV1ProjectsByNameGaAiReferralHistory = (options) => {
|
|
|
3283
3283
|
...options
|
|
3284
3284
|
});
|
|
3285
3285
|
};
|
|
3286
|
+
var getApiV1ProjectsByNameGaAiReferralDaily = (options) => {
|
|
3287
|
+
return (options.client ?? client).get({
|
|
3288
|
+
security: [
|
|
3289
|
+
{
|
|
3290
|
+
scheme: "bearer",
|
|
3291
|
+
type: "http"
|
|
3292
|
+
}
|
|
3293
|
+
],
|
|
3294
|
+
url: "/api/v1/projects/{name}/ga/ai-referral-daily",
|
|
3295
|
+
...options
|
|
3296
|
+
});
|
|
3297
|
+
};
|
|
3286
3298
|
var getApiV1ProjectsByNameGaSocialReferralHistory = (options) => {
|
|
3287
3299
|
return (options.client ?? client).get({
|
|
3288
3300
|
security: [
|
|
@@ -5352,6 +5364,15 @@ var ApiClient = class {
|
|
|
5352
5364
|
})
|
|
5353
5365
|
);
|
|
5354
5366
|
}
|
|
5367
|
+
async gaAiReferralDaily(project, params) {
|
|
5368
|
+
return this.invoke(
|
|
5369
|
+
() => getApiV1ProjectsByNameGaAiReferralDaily({
|
|
5370
|
+
client: this.heyClient,
|
|
5371
|
+
path: { name: project },
|
|
5372
|
+
query: params
|
|
5373
|
+
})
|
|
5374
|
+
);
|
|
5375
|
+
}
|
|
5355
5376
|
async gaSocialReferralHistory(project, params) {
|
|
5356
5377
|
return this.invoke(
|
|
5357
5378
|
() => getApiV1ProjectsByNameGaSocialReferralHistory({
|
|
@@ -7081,8 +7102,8 @@ var canonryMcpTools = [
|
|
|
7081
7102
|
}),
|
|
7082
7103
|
defineTool({
|
|
7083
7104
|
name: "canonry_ga_ai_referral_history",
|
|
7084
|
-
title: "Get GA AI referral
|
|
7085
|
-
description: "Get AI referral
|
|
7105
|
+
title: "Get GA AI referral detail rows",
|
|
7106
|
+
description: "Get raw AI referral rows per day, landing page, and attribution dimension. Detail, not totals: use canonry_ga_ai_referral_daily for session counts.",
|
|
7086
7107
|
access: "read",
|
|
7087
7108
|
tier: "ga",
|
|
7088
7109
|
inputSchema: gaWindowInputSchema,
|
|
@@ -7090,6 +7111,17 @@ var canonryMcpTools = [
|
|
|
7090
7111
|
openApiOperations: ["GET /api/v1/projects/{name}/ga/ai-referral-history"],
|
|
7091
7112
|
handler: (client2, input) => client2.gaAiReferralHistory(input.project, compactStringParams(input, ["window"]))
|
|
7092
7113
|
}),
|
|
7114
|
+
defineTool({
|
|
7115
|
+
name: "canonry_ga_ai_referral_daily",
|
|
7116
|
+
title: "Get GA AI referral sessions per day",
|
|
7117
|
+
description: "Get AI referral sessions per day and per source, deduplicated across attribution dimensions. Totals match the AI sessions reported by canonry_ga_traffic.",
|
|
7118
|
+
access: "read",
|
|
7119
|
+
tier: "ga",
|
|
7120
|
+
inputSchema: gaWindowInputSchema,
|
|
7121
|
+
annotations: readAnnotations(),
|
|
7122
|
+
openApiOperations: ["GET /api/v1/projects/{name}/ga/ai-referral-daily"],
|
|
7123
|
+
handler: (client2, input) => client2.gaAiReferralDaily(input.project, compactStringParams(input, ["window"]))
|
|
7124
|
+
}),
|
|
7093
7125
|
defineTool({
|
|
7094
7126
|
name: "canonry_ga_social_referral_history",
|
|
7095
7127
|
title: "Get GA social referral history",
|
|
@@ -4148,6 +4148,29 @@ var ga4AiReferralHistoryEntrySchema = z25.object({
|
|
|
4148
4148
|
/** Which GA4 dimension this row came from: session (sessionSource), first_user (firstUserSource), or manual_utm (utm_source parameter) */
|
|
4149
4149
|
sourceDimension: ga4SourceDimensionSchema
|
|
4150
4150
|
});
|
|
4151
|
+
var ga4AiReferralDailySourceSchema = z25.object({
|
|
4152
|
+
source: z25.string(),
|
|
4153
|
+
sessions: z25.number(),
|
|
4154
|
+
paidSessions: z25.number(),
|
|
4155
|
+
organicSessions: z25.number()
|
|
4156
|
+
});
|
|
4157
|
+
var ga4AiReferralDailyEntrySchema = z25.object({
|
|
4158
|
+
date: z25.string(),
|
|
4159
|
+
sessions: z25.number(),
|
|
4160
|
+
paidSessions: z25.number(),
|
|
4161
|
+
organicSessions: z25.number(),
|
|
4162
|
+
/** Per-source split of the day. `sessions` is the sum of these. */
|
|
4163
|
+
bySource: z25.array(ga4AiReferralDailySourceSchema)
|
|
4164
|
+
});
|
|
4165
|
+
var ga4AiReferralDailyDtoSchema = z25.object({
|
|
4166
|
+
/** Ascending by date. Dates with no AI referrals are absent, not zero-filled. */
|
|
4167
|
+
days: z25.array(ga4AiReferralDailyEntrySchema),
|
|
4168
|
+
/** Sources present in the window, ordered by total sessions descending. */
|
|
4169
|
+
sources: z25.array(z25.string()),
|
|
4170
|
+
totalSessions: z25.number(),
|
|
4171
|
+
totalPaidSessions: z25.number(),
|
|
4172
|
+
totalOrganicSessions: z25.number()
|
|
4173
|
+
});
|
|
4151
4174
|
var ga4SocialReferralHistoryEntrySchema = z25.object({
|
|
4152
4175
|
date: z25.string(),
|
|
4153
4176
|
source: z25.string(),
|
|
@@ -7965,6 +7988,7 @@ export {
|
|
|
7965
7988
|
ga4StatusDtoSchema,
|
|
7966
7989
|
ga4SyncResponseDtoSchema,
|
|
7967
7990
|
ga4AiReferralHistoryEntrySchema,
|
|
7991
|
+
ga4AiReferralDailyDtoSchema,
|
|
7968
7992
|
ga4SocialReferralHistoryEntrySchema,
|
|
7969
7993
|
ga4SessionHistoryEntrySchema,
|
|
7970
7994
|
extractAnswerMentions,
|
|
@@ -209,6 +209,7 @@ import {
|
|
|
209
209
|
formatNumber,
|
|
210
210
|
formatRatio,
|
|
211
211
|
formatWindowCountDelta,
|
|
212
|
+
ga4AiReferralDailyDtoSchema,
|
|
212
213
|
ga4AiReferralHistoryEntrySchema,
|
|
213
214
|
ga4SessionHistoryEntrySchema,
|
|
214
215
|
ga4SocialReferralHistoryEntrySchema,
|
|
@@ -364,7 +365,7 @@ import {
|
|
|
364
365
|
wordpressSchemaDeployResultDtoSchema,
|
|
365
366
|
wordpressSchemaStatusResultDtoSchema,
|
|
366
367
|
wordpressStatusDtoSchema
|
|
367
|
-
} from "./chunk-
|
|
368
|
+
} from "./chunk-CF5WTWXI.js";
|
|
368
369
|
|
|
369
370
|
// src/intelligence-service.ts
|
|
370
371
|
import { eq as eq44, desc as desc21, asc as asc9, and as and35, ne as ne6, or as or10, inArray as inArray15, gte as gte12, lte as lte8 } from "drizzle-orm";
|
|
@@ -17462,6 +17463,7 @@ var SCHEMA_TABLE = {
|
|
|
17462
17463
|
ResearchRunDetailDto: researchRunDetailSchema,
|
|
17463
17464
|
ResearchRunListDto: researchRunListSchema,
|
|
17464
17465
|
DoctorReportDto: doctorReportSchema,
|
|
17466
|
+
GA4AiReferralDailyDto: ga4AiReferralDailyDtoSchema,
|
|
17465
17467
|
GA4AiReferralHistoryEntry: ga4AiReferralHistoryEntrySchema,
|
|
17466
17468
|
GA4MeasurementAnalysisDto: gaMeasurementAnalysisDtoSchema,
|
|
17467
17469
|
GA4SessionHistoryEntry: ga4SessionHistoryEntrySchema,
|
|
@@ -21205,7 +21207,8 @@ var routeCatalog = [
|
|
|
21205
21207
|
{
|
|
21206
21208
|
method: "get",
|
|
21207
21209
|
path: "/api/v1/projects/{name}/ga/ai-referral-history",
|
|
21208
|
-
summary: "Get AI referral
|
|
21210
|
+
summary: "Get raw AI referral detail rows per day, landing page, and attribution dimension",
|
|
21211
|
+
description: "Detail rows, not totals. One row per landing page per attribution dimension, so a single day of one source is many rows and each is commonly worth one session. Use /ga/ai-referral-daily for per-date or per-source session counts.",
|
|
21209
21212
|
tags: ["ga4"],
|
|
21210
21213
|
parameters: [nameParameter, analyticsWindowParameter],
|
|
21211
21214
|
responses: {
|
|
@@ -21214,6 +21217,19 @@ var routeCatalog = [
|
|
|
21214
21217
|
404: errorResponse("Project not found.")
|
|
21215
21218
|
}
|
|
21216
21219
|
},
|
|
21220
|
+
{
|
|
21221
|
+
method: "get",
|
|
21222
|
+
path: "/api/v1/projects/{name}/ga/ai-referral-daily",
|
|
21223
|
+
summary: "Get AI referral sessions per day and per source",
|
|
21224
|
+
description: "Sums landing pages within one attribution dimension and never across dimensions, so totalSessions equals the aiSessionsDeduped reported by /ga/traffic for the same window. Sessions only: GA counts users as a distinct count at the grain requested, so an AI-referral user total cannot be summed from these rows and no un-dimensioned AI-referral fetch exists to supply one.",
|
|
21225
|
+
tags: ["ga4"],
|
|
21226
|
+
parameters: [nameParameter, analyticsWindowParameter],
|
|
21227
|
+
responses: {
|
|
21228
|
+
200: jsonResponse("AI referral daily series returned.", "GA4AiReferralDailyDto"),
|
|
21229
|
+
400: errorResponse("GA4 is not connected."),
|
|
21230
|
+
404: errorResponse("Project not found.")
|
|
21231
|
+
}
|
|
21232
|
+
},
|
|
21217
21233
|
{
|
|
21218
21234
|
method: "get",
|
|
21219
21235
|
path: "/api/v1/projects/{name}/ga/social-referral-history",
|
|
@@ -31802,6 +31818,160 @@ function buildSessionHistory(landingPageDays, dailyTotals) {
|
|
|
31802
31818
|
});
|
|
31803
31819
|
}
|
|
31804
31820
|
|
|
31821
|
+
// ../api-routes/src/ga-ai-referral-aggregation.ts
|
|
31822
|
+
function normalizeAiTrafficClass(value) {
|
|
31823
|
+
return value === AiReferralTrafficClasses.paid ? AiReferralTrafficClasses.paid : AiReferralTrafficClasses.organic;
|
|
31824
|
+
}
|
|
31825
|
+
function emptyAiCounts() {
|
|
31826
|
+
return { sessions: 0, users: 0 };
|
|
31827
|
+
}
|
|
31828
|
+
function resolveWinningDimensions(rows) {
|
|
31829
|
+
const groups = /* @__PURE__ */ new Map();
|
|
31830
|
+
for (const row of rows) {
|
|
31831
|
+
const key = `${row.date}\0${row.source}\0${row.medium}`;
|
|
31832
|
+
let group = groups.get(key);
|
|
31833
|
+
if (!group) {
|
|
31834
|
+
group = { date: row.date, source: row.source, medium: row.medium, byDimension: /* @__PURE__ */ new Map() };
|
|
31835
|
+
groups.set(key, group);
|
|
31836
|
+
}
|
|
31837
|
+
let dim = group.byDimension.get(row.sourceDimension);
|
|
31838
|
+
if (!dim) {
|
|
31839
|
+
dim = { paidSessions: 0, organicSessions: 0 };
|
|
31840
|
+
group.byDimension.set(row.sourceDimension, dim);
|
|
31841
|
+
}
|
|
31842
|
+
const sessions = row.sessions ?? 0;
|
|
31843
|
+
if (normalizeAiTrafficClass(row.trafficClass) === AiReferralTrafficClasses.paid) {
|
|
31844
|
+
dim.paidSessions += sessions;
|
|
31845
|
+
} else {
|
|
31846
|
+
dim.organicSessions += sessions;
|
|
31847
|
+
}
|
|
31848
|
+
}
|
|
31849
|
+
const winners = [];
|
|
31850
|
+
for (const group of groups.values()) {
|
|
31851
|
+
const dims = [...group.byDimension.values()];
|
|
31852
|
+
const bestSessions = dims.reduce((best, d) => d.paidSessions + d.organicSessions > best.paidSessions + best.organicSessions ? d : best);
|
|
31853
|
+
winners.push({
|
|
31854
|
+
date: group.date,
|
|
31855
|
+
source: group.source,
|
|
31856
|
+
medium: group.medium,
|
|
31857
|
+
paidSessions: bestSessions.paidSessions,
|
|
31858
|
+
organicSessions: bestSessions.organicSessions
|
|
31859
|
+
});
|
|
31860
|
+
}
|
|
31861
|
+
return winners;
|
|
31862
|
+
}
|
|
31863
|
+
function resolveLegacyWinningUsers(rows) {
|
|
31864
|
+
const groups = /* @__PURE__ */ new Map();
|
|
31865
|
+
for (const row of rows) {
|
|
31866
|
+
const key = `${row.date}\0${row.source}\0${row.medium}`;
|
|
31867
|
+
let byDimension = groups.get(key);
|
|
31868
|
+
if (!byDimension) {
|
|
31869
|
+
byDimension = /* @__PURE__ */ new Map();
|
|
31870
|
+
groups.set(key, byDimension);
|
|
31871
|
+
}
|
|
31872
|
+
let dim = byDimension.get(row.sourceDimension);
|
|
31873
|
+
if (!dim) {
|
|
31874
|
+
dim = { paidUsers: 0, organicUsers: 0 };
|
|
31875
|
+
byDimension.set(row.sourceDimension, dim);
|
|
31876
|
+
}
|
|
31877
|
+
const users = row.users ?? 0;
|
|
31878
|
+
if (normalizeAiTrafficClass(row.trafficClass) === AiReferralTrafficClasses.paid) {
|
|
31879
|
+
dim.paidUsers += users;
|
|
31880
|
+
} else {
|
|
31881
|
+
dim.organicUsers += users;
|
|
31882
|
+
}
|
|
31883
|
+
}
|
|
31884
|
+
let paidUsers = 0;
|
|
31885
|
+
let organicUsers = 0;
|
|
31886
|
+
for (const byDimension of groups.values()) {
|
|
31887
|
+
const dims = [...byDimension.values()];
|
|
31888
|
+
const best = dims.reduce((winner, d) => d.paidUsers + d.organicUsers > winner.paidUsers + winner.organicUsers ? d : winner);
|
|
31889
|
+
paidUsers += best.paidUsers;
|
|
31890
|
+
organicUsers += best.organicUsers;
|
|
31891
|
+
}
|
|
31892
|
+
return { paidUsers, organicUsers };
|
|
31893
|
+
}
|
|
31894
|
+
function summarizeAiReferralCounts(rows) {
|
|
31895
|
+
const paidDeduped = emptyAiCounts();
|
|
31896
|
+
const organicDeduped = emptyAiCounts();
|
|
31897
|
+
const paidBySession = emptyAiCounts();
|
|
31898
|
+
const organicBySession = emptyAiCounts();
|
|
31899
|
+
const bySessionChannelGroup = /* @__PURE__ */ new Map();
|
|
31900
|
+
for (const winner of resolveWinningDimensions(rows)) {
|
|
31901
|
+
paidDeduped.sessions += winner.paidSessions;
|
|
31902
|
+
organicDeduped.sessions += winner.organicSessions;
|
|
31903
|
+
}
|
|
31904
|
+
const legacyUsers = resolveLegacyWinningUsers(rows);
|
|
31905
|
+
paidDeduped.users = legacyUsers.paidUsers;
|
|
31906
|
+
organicDeduped.users = legacyUsers.organicUsers;
|
|
31907
|
+
for (const row of rows) {
|
|
31908
|
+
if (row.sourceDimension !== "session") continue;
|
|
31909
|
+
const sessions = row.sessions ?? 0;
|
|
31910
|
+
const users = row.users ?? 0;
|
|
31911
|
+
bySessionChannelGroup.set(
|
|
31912
|
+
row.channelGroup,
|
|
31913
|
+
(bySessionChannelGroup.get(row.channelGroup) ?? 0) + sessions
|
|
31914
|
+
);
|
|
31915
|
+
const bucket = normalizeAiTrafficClass(row.trafficClass) === AiReferralTrafficClasses.paid ? paidBySession : organicBySession;
|
|
31916
|
+
bucket.sessions += sessions;
|
|
31917
|
+
bucket.users += users;
|
|
31918
|
+
}
|
|
31919
|
+
return {
|
|
31920
|
+
paidDeduped,
|
|
31921
|
+
organicDeduped,
|
|
31922
|
+
paidBySession,
|
|
31923
|
+
organicBySession,
|
|
31924
|
+
bySessionChannelGroup,
|
|
31925
|
+
deduped: {
|
|
31926
|
+
sessions: paidDeduped.sessions + organicDeduped.sessions,
|
|
31927
|
+
users: paidDeduped.users + organicDeduped.users
|
|
31928
|
+
},
|
|
31929
|
+
bySession: {
|
|
31930
|
+
sessions: paidBySession.sessions + organicBySession.sessions,
|
|
31931
|
+
users: paidBySession.users + organicBySession.users
|
|
31932
|
+
}
|
|
31933
|
+
};
|
|
31934
|
+
}
|
|
31935
|
+
function buildAiReferralDailySeries(rows) {
|
|
31936
|
+
const byDate = /* @__PURE__ */ new Map();
|
|
31937
|
+
const sourceTotals = /* @__PURE__ */ new Map();
|
|
31938
|
+
let totalSessions = 0;
|
|
31939
|
+
let totalPaidSessions = 0;
|
|
31940
|
+
let totalOrganicSessions = 0;
|
|
31941
|
+
for (const winner of resolveWinningDimensions(rows)) {
|
|
31942
|
+
const sessions = winner.paidSessions + winner.organicSessions;
|
|
31943
|
+
let bySource = byDate.get(winner.date);
|
|
31944
|
+
if (!bySource) {
|
|
31945
|
+
bySource = /* @__PURE__ */ new Map();
|
|
31946
|
+
byDate.set(winner.date, bySource);
|
|
31947
|
+
}
|
|
31948
|
+
let bucket = bySource.get(winner.source);
|
|
31949
|
+
if (!bucket) {
|
|
31950
|
+
bucket = { source: winner.source, sessions: 0, paidSessions: 0, organicSessions: 0 };
|
|
31951
|
+
bySource.set(winner.source, bucket);
|
|
31952
|
+
}
|
|
31953
|
+
bucket.sessions += sessions;
|
|
31954
|
+
bucket.paidSessions += winner.paidSessions;
|
|
31955
|
+
bucket.organicSessions += winner.organicSessions;
|
|
31956
|
+
sourceTotals.set(winner.source, (sourceTotals.get(winner.source) ?? 0) + sessions);
|
|
31957
|
+
totalSessions += sessions;
|
|
31958
|
+
totalPaidSessions += winner.paidSessions;
|
|
31959
|
+
totalOrganicSessions += winner.organicSessions;
|
|
31960
|
+
}
|
|
31961
|
+
const days = [...byDate.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([date, bySource]) => {
|
|
31962
|
+
const sources2 = [...bySource.values()].sort((a, b) => b.sessions - a.sessions || a.source.localeCompare(b.source));
|
|
31963
|
+
return {
|
|
31964
|
+
date,
|
|
31965
|
+
sessions: sources2.reduce((sum, s) => sum + s.sessions, 0),
|
|
31966
|
+
paidSessions: sources2.reduce((sum, s) => sum + s.paidSessions, 0),
|
|
31967
|
+
organicSessions: sources2.reduce((sum, s) => sum + s.organicSessions, 0),
|
|
31968
|
+
bySource: sources2
|
|
31969
|
+
};
|
|
31970
|
+
});
|
|
31971
|
+
const sources = [...sourceTotals.entries()].sort(([aSource, aSessions], [bSource, bSessions]) => bSessions - aSessions || aSource.localeCompare(bSource)).map(([source]) => source);
|
|
31972
|
+
return { days, sources, totalSessions, totalPaidSessions, totalOrganicSessions };
|
|
31973
|
+
}
|
|
31974
|
+
|
|
31805
31975
|
// ../api-routes/src/ga.ts
|
|
31806
31976
|
function gaLog(level, action, ctx) {
|
|
31807
31977
|
const entry = { ts: (/* @__PURE__ */ new Date()).toISOString(), level, module: "GA4Routes", action, ...ctx };
|
|
@@ -31858,12 +32028,6 @@ function pickWinningDimension(rows, tupleKey) {
|
|
|
31858
32028
|
}
|
|
31859
32029
|
return [...winners.values()].sort((a, b) => (b.sessions ?? 0) - (a.sessions ?? 0));
|
|
31860
32030
|
}
|
|
31861
|
-
function normalizeAiTrafficClass(value) {
|
|
31862
|
-
return value === AiReferralTrafficClasses.paid ? AiReferralTrafficClasses.paid : AiReferralTrafficClasses.organic;
|
|
31863
|
-
}
|
|
31864
|
-
function emptyAiCounts() {
|
|
31865
|
-
return { sessions: 0, users: 0 };
|
|
31866
|
-
}
|
|
31867
32031
|
function persistAcquisitionMeasurement(db, input) {
|
|
31868
32032
|
const { startDate, endDate } = input.report;
|
|
31869
32033
|
db.transaction((tx) => {
|
|
@@ -31992,70 +32156,6 @@ function persistMeasurementError(db, projectId, component, message, updatedAt) {
|
|
|
31992
32156
|
}
|
|
31993
32157
|
}).run();
|
|
31994
32158
|
}
|
|
31995
|
-
function summarizeAiReferralCounts(rows) {
|
|
31996
|
-
const dedupeGroups = /* @__PURE__ */ new Map();
|
|
31997
|
-
const bySessionChannelGroup = /* @__PURE__ */ new Map();
|
|
31998
|
-
const paidDeduped = emptyAiCounts();
|
|
31999
|
-
const organicDeduped = emptyAiCounts();
|
|
32000
|
-
const paidBySession = emptyAiCounts();
|
|
32001
|
-
const organicBySession = emptyAiCounts();
|
|
32002
|
-
for (const row of rows) {
|
|
32003
|
-
const isPaid = normalizeAiTrafficClass(row.trafficClass) === AiReferralTrafficClasses.paid;
|
|
32004
|
-
const sessions = row.sessions ?? 0;
|
|
32005
|
-
const users = row.users ?? 0;
|
|
32006
|
-
const key = `${row.date}\0${row.source}\0${row.medium}`;
|
|
32007
|
-
let byDimension = dedupeGroups.get(key);
|
|
32008
|
-
if (!byDimension) {
|
|
32009
|
-
byDimension = /* @__PURE__ */ new Map();
|
|
32010
|
-
dedupeGroups.set(key, byDimension);
|
|
32011
|
-
}
|
|
32012
|
-
let dim = byDimension.get(row.sourceDimension);
|
|
32013
|
-
if (!dim) {
|
|
32014
|
-
dim = { paidSessions: 0, organicSessions: 0, paidUsers: 0, organicUsers: 0 };
|
|
32015
|
-
byDimension.set(row.sourceDimension, dim);
|
|
32016
|
-
}
|
|
32017
|
-
if (isPaid) {
|
|
32018
|
-
dim.paidSessions += sessions;
|
|
32019
|
-
dim.paidUsers += users;
|
|
32020
|
-
} else {
|
|
32021
|
-
dim.organicSessions += sessions;
|
|
32022
|
-
dim.organicUsers += users;
|
|
32023
|
-
}
|
|
32024
|
-
if (row.sourceDimension === "session") {
|
|
32025
|
-
bySessionChannelGroup.set(
|
|
32026
|
-
row.channelGroup,
|
|
32027
|
-
(bySessionChannelGroup.get(row.channelGroup) ?? 0) + sessions
|
|
32028
|
-
);
|
|
32029
|
-
const sessionBucket = isPaid ? paidBySession : organicBySession;
|
|
32030
|
-
sessionBucket.sessions += sessions;
|
|
32031
|
-
sessionBucket.users += users;
|
|
32032
|
-
}
|
|
32033
|
-
}
|
|
32034
|
-
for (const byDimension of dedupeGroups.values()) {
|
|
32035
|
-
const dims = [...byDimension.values()];
|
|
32036
|
-
const bestSessions = dims.reduce((best, d) => d.paidSessions + d.organicSessions > best.paidSessions + best.organicSessions ? d : best);
|
|
32037
|
-
const bestUsers = dims.reduce((best, d) => d.paidUsers + d.organicUsers > best.paidUsers + best.organicUsers ? d : best);
|
|
32038
|
-
paidDeduped.sessions += bestSessions.paidSessions;
|
|
32039
|
-
organicDeduped.sessions += bestSessions.organicSessions;
|
|
32040
|
-
paidDeduped.users += bestUsers.paidUsers;
|
|
32041
|
-
organicDeduped.users += bestUsers.organicUsers;
|
|
32042
|
-
}
|
|
32043
|
-
return {
|
|
32044
|
-
paidDeduped,
|
|
32045
|
-
organicDeduped,
|
|
32046
|
-
paidBySession,
|
|
32047
|
-
organicBySession,
|
|
32048
|
-
bySessionChannelGroup,
|
|
32049
|
-
deduped: {
|
|
32050
|
-
sessions: paidDeduped.sessions + organicDeduped.sessions,
|
|
32051
|
-
users: paidDeduped.users + organicDeduped.users
|
|
32052
|
-
},
|
|
32053
|
-
bySession: {
|
|
32054
|
-
sessions: paidBySession.sessions + organicBySession.sessions,
|
|
32055
|
-
users: paidBySession.users + organicBySession.users
|
|
32056
|
-
}
|
|
32057
|
-
};
|
|
32058
|
-
}
|
|
32059
32159
|
async function refreshOAuthTokenIfNeeded(googleStore, authConfig, canonicalDomain, oauthConn) {
|
|
32060
32160
|
const expiresAt = oauthConn.tokenExpiresAt ? new Date(oauthConn.tokenExpiresAt).getTime() : 0;
|
|
32061
32161
|
const fiveMinutes = 5 * 60 * 1e3;
|
|
@@ -32757,6 +32857,23 @@ async function ga4Routes(app, opts) {
|
|
|
32757
32857
|
).orderBy(gaAiReferrals.date).all();
|
|
32758
32858
|
return rows;
|
|
32759
32859
|
});
|
|
32860
|
+
app.get("/projects/:name/ga/ai-referral-daily", async (request, _reply) => {
|
|
32861
|
+
const project = resolveProject(app.db, request.params.name);
|
|
32862
|
+
requireGa4Connection(opts, project.name, project.canonicalDomain);
|
|
32863
|
+
const cutoffDate = windowCutoff(parseWindow(request.query.window))?.slice(0, 10) ?? null;
|
|
32864
|
+
const conditions = [eq31(gaAiReferrals.projectId, project.id)];
|
|
32865
|
+
if (cutoffDate) conditions.push(sql15`${gaAiReferrals.date} >= ${cutoffDate}`);
|
|
32866
|
+
const rows = app.db.select({
|
|
32867
|
+
date: gaAiReferrals.date,
|
|
32868
|
+
source: gaAiReferrals.source,
|
|
32869
|
+
medium: gaAiReferrals.medium,
|
|
32870
|
+
trafficClass: gaAiReferrals.trafficClass,
|
|
32871
|
+
sourceDimension: gaAiReferrals.sourceDimension,
|
|
32872
|
+
channelGroup: gaAiReferrals.channelGroup,
|
|
32873
|
+
sessions: gaAiReferrals.sessions
|
|
32874
|
+
}).from(gaAiReferrals).where(and25(...conditions)).all();
|
|
32875
|
+
return buildAiReferralDailySeries(rows);
|
|
32876
|
+
});
|
|
32760
32877
|
app.get("/projects/:name/ga/social-referral-history", async (request, _reply) => {
|
|
32761
32878
|
const project = resolveProject(app.db, request.params.name);
|
|
32762
32879
|
requireGa4Connection(opts, project.name, project.canonicalDomain);
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
loadConfig,
|
|
11
11
|
loadConfigRaw,
|
|
12
12
|
saveConfigPatch
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-BSU2MI3Y.js";
|
|
14
14
|
import {
|
|
15
15
|
CC_CACHE_DIR,
|
|
16
16
|
DUCKDB_SPEC,
|
|
@@ -119,7 +119,7 @@ import {
|
|
|
119
119
|
siteAuditPages,
|
|
120
120
|
siteAuditSnapshots,
|
|
121
121
|
usageCounters
|
|
122
|
-
} from "./chunk-
|
|
122
|
+
} from "./chunk-DVJGFY3J.js";
|
|
123
123
|
import {
|
|
124
124
|
AGENT_MEMORY_VALUE_MAX_BYTES,
|
|
125
125
|
AGENT_PROVIDER_IDS,
|
|
@@ -193,7 +193,7 @@ import {
|
|
|
193
193
|
validationError,
|
|
194
194
|
winnabilityClassLabel,
|
|
195
195
|
withRetry
|
|
196
|
-
} from "./chunk-
|
|
196
|
+
} from "./chunk-CF5WTWXI.js";
|
|
197
197
|
|
|
198
198
|
// src/telemetry.ts
|
|
199
199
|
import crypto from "crypto";
|
|
@@ -7010,7 +7010,7 @@ function readStoredGroundingSources(rawResponse) {
|
|
|
7010
7010
|
return result;
|
|
7011
7011
|
}
|
|
7012
7012
|
async function backfillInsightsCommand(project, opts) {
|
|
7013
|
-
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-
|
|
7013
|
+
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-NO4FJUYD.js");
|
|
7014
7014
|
const config = loadConfig();
|
|
7015
7015
|
const db = createClient(config.database);
|
|
7016
7016
|
migrate(db);
|
package/dist/cli.js
CHANGED
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
setTelemetrySource,
|
|
30
30
|
showFirstRunNotice,
|
|
31
31
|
trackEvent
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-NWVPRV7A.js";
|
|
33
33
|
import {
|
|
34
34
|
CliError,
|
|
35
35
|
EXIT_SYSTEM_ERROR,
|
|
@@ -46,7 +46,7 @@ import {
|
|
|
46
46
|
saveConfig,
|
|
47
47
|
saveConfigPatch,
|
|
48
48
|
usageError
|
|
49
|
-
} from "./chunk-
|
|
49
|
+
} from "./chunk-BSU2MI3Y.js";
|
|
50
50
|
import {
|
|
51
51
|
apiKeys,
|
|
52
52
|
createClient,
|
|
@@ -54,7 +54,7 @@ import {
|
|
|
54
54
|
projects,
|
|
55
55
|
queries,
|
|
56
56
|
renderReportHtml
|
|
57
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-DVJGFY3J.js";
|
|
58
58
|
import {
|
|
59
59
|
AdsDeliverySnapshotStatuses,
|
|
60
60
|
AdsHistoricalCampaignRollupStatuses,
|
|
@@ -100,7 +100,7 @@ import {
|
|
|
100
100
|
providerQuotaPolicySchema,
|
|
101
101
|
resolveProviderInput,
|
|
102
102
|
winnabilityClassSchema
|
|
103
|
-
} from "./chunk-
|
|
103
|
+
} from "./chunk-CF5WTWXI.js";
|
|
104
104
|
|
|
105
105
|
// src/cli.ts
|
|
106
106
|
import { pathToFileURL } from "url";
|
|
@@ -4111,6 +4111,36 @@ async function gaAiReferralHistory(project, opts) {
|
|
|
4111
4111
|
);
|
|
4112
4112
|
}
|
|
4113
4113
|
}
|
|
4114
|
+
async function gaAiReferralDaily(project, opts) {
|
|
4115
|
+
const client = getClient7();
|
|
4116
|
+
const result = await client.gaAiReferralDaily(project, opts?.window ? { window: opts.window } : void 0);
|
|
4117
|
+
if (opts?.format === "json") {
|
|
4118
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4119
|
+
return;
|
|
4120
|
+
} else if (opts?.format === "jsonl") {
|
|
4121
|
+
emitJsonl(result.days.map((day) => ({ project, window: opts?.window, ...day })));
|
|
4122
|
+
return;
|
|
4123
|
+
}
|
|
4124
|
+
if (result.days.length === 0) {
|
|
4125
|
+
console.log(`No AI referral sessions.${opts?.window ? " Try a wider window or omit --window." : ' Run "canonry ga sync <project>" first.'}`);
|
|
4126
|
+
return;
|
|
4127
|
+
}
|
|
4128
|
+
const dateWidth = 12;
|
|
4129
|
+
const sourceWidth = Math.min(30, Math.max(10, ...result.sources.map((s) => s.length)));
|
|
4130
|
+
console.log(`GA4 AI Referral Sessions per Day for "${project}":
|
|
4131
|
+
`);
|
|
4132
|
+
console.log(` ${"DATE".padEnd(dateWidth)} ${"SOURCE".padEnd(sourceWidth)} ${"SESSIONS".padEnd(10)}${"PAID".padEnd(8)}${"ORGANIC".padEnd(9)}`);
|
|
4133
|
+
console.log(` ${"\u2500".repeat(dateWidth)} ${"\u2500".repeat(sourceWidth)} ${"\u2500".repeat(10)}${"\u2500".repeat(8)}${"\u2500".repeat(9)}`);
|
|
4134
|
+
for (const day of result.days) {
|
|
4135
|
+
for (const entry of day.bySource) {
|
|
4136
|
+
console.log(
|
|
4137
|
+
` ${day.date.padEnd(dateWidth)} ${entry.source.padEnd(sourceWidth)} ${String(entry.sessions).padEnd(10)}${String(entry.paidSessions).padEnd(8)}${String(entry.organicSessions).padEnd(9)}`
|
|
4138
|
+
);
|
|
4139
|
+
}
|
|
4140
|
+
}
|
|
4141
|
+
console.log(`
|
|
4142
|
+
Total: ${result.totalSessions} sessions (${result.totalPaidSessions} paid, ${result.totalOrganicSessions} organic)`);
|
|
4143
|
+
}
|
|
4114
4144
|
async function gaSocialReferralHistory(project, opts) {
|
|
4115
4145
|
const client = getClient7();
|
|
4116
4146
|
const result = await client.gaSocialReferralHistory(project, opts?.window ? { window: opts.window } : void 0);
|
|
@@ -4575,6 +4605,20 @@ var GA_CLI_COMMANDS = [
|
|
|
4575
4605
|
});
|
|
4576
4606
|
}
|
|
4577
4607
|
},
|
|
4608
|
+
{
|
|
4609
|
+
path: ["ga", "ai-referral-daily"],
|
|
4610
|
+
usage: "canonry ga ai-referral-daily <project> [--window 30d] [--format json]",
|
|
4611
|
+
options: {
|
|
4612
|
+
window: stringOption()
|
|
4613
|
+
},
|
|
4614
|
+
run: async (input) => {
|
|
4615
|
+
const project = requireProject(input, "ga.ai-referral-daily", "canonry ga ai-referral-daily <project> [--window 30d] [--format json]");
|
|
4616
|
+
await gaAiReferralDaily(project, {
|
|
4617
|
+
window: getString(input.values, "window"),
|
|
4618
|
+
format: input.format
|
|
4619
|
+
});
|
|
4620
|
+
}
|
|
4621
|
+
},
|
|
4578
4622
|
{
|
|
4579
4623
|
path: ["ga", "social-referral-history"],
|
|
4580
4624
|
usage: "canonry ga social-referral-history <project> [--window 30d] [--format json]",
|
|
@@ -4638,7 +4682,7 @@ var GA_CLI_COMMANDS = [
|
|
|
4638
4682
|
unknownSubcommand(input.positionals[0], {
|
|
4639
4683
|
command: "ga",
|
|
4640
4684
|
usage: "canonry ga <subcommand> <project> [args]",
|
|
4641
|
-
available: ["connect", "disconnect", "status", "sync", "measurement-analysis", "traffic", "coverage", "ai-referral-history", "social-referral-history", "session-history", "social-referral-summary", "attribution"]
|
|
4685
|
+
available: ["connect", "disconnect", "status", "sync", "measurement-analysis", "traffic", "coverage", "ai-referral-history", "ai-referral-daily", "social-referral-history", "session-history", "social-referral-summary", "attribution"]
|
|
4642
4686
|
});
|
|
4643
4687
|
}
|
|
4644
4688
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createServer
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-NWVPRV7A.js";
|
|
4
4
|
import {
|
|
5
5
|
loadConfig
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-BSU2MI3Y.js";
|
|
7
|
+
import "./chunk-DVJGFY3J.js";
|
|
8
|
+
import "./chunk-CF5WTWXI.js";
|
|
9
9
|
export {
|
|
10
10
|
createServer,
|
|
11
11
|
loadConfig
|
package/dist/mcp.js
CHANGED
|
@@ -3,10 +3,10 @@ import {
|
|
|
3
3
|
PACKAGE_VERSION,
|
|
4
4
|
canonryMcpTools,
|
|
5
5
|
createApiClient
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-BSU2MI3Y.js";
|
|
7
7
|
import {
|
|
8
8
|
isReadOnlyKey
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-CF5WTWXI.js";
|
|
10
10
|
|
|
11
11
|
// src/mcp/cli.ts
|
|
12
12
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canonry/canonry",
|
|
3
|
-
"version": "4.134.
|
|
3
|
+
"version": "4.134.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Agent-first open-source AEO operating platform - track how answer engines cite your domain",
|
|
6
6
|
"license": "FSL-1.1-ALv2",
|
|
@@ -71,20 +71,20 @@
|
|
|
71
71
|
"@ainyc/canonry-db": "0.0.0",
|
|
72
72
|
"@ainyc/canonry-contracts": "0.0.0",
|
|
73
73
|
"@ainyc/canonry-integration-bing": "0.0.0",
|
|
74
|
+
"@ainyc/canonry-integration-commoncrawl": "0.0.0",
|
|
74
75
|
"@ainyc/canonry-integration-openai-ads": "0.0.0",
|
|
76
|
+
"@ainyc/canonry-integration-google-places": "0.0.0",
|
|
75
77
|
"@ainyc/canonry-integration-cloud-run": "0.0.0",
|
|
76
78
|
"@ainyc/canonry-integration-google": "0.0.0",
|
|
77
|
-
"@ainyc/canonry-integration-google-places": "0.0.0",
|
|
78
79
|
"@ainyc/canonry-integration-google-business-profile": "0.0.0",
|
|
79
80
|
"@ainyc/canonry-integration-traffic": "0.0.0",
|
|
80
|
-
"@ainyc/canonry-
|
|
81
|
-
"@ainyc/canonry-integration-commoncrawl": "0.0.0",
|
|
81
|
+
"@ainyc/canonry-intelligence": "0.0.0",
|
|
82
82
|
"@ainyc/canonry-provider-cdp": "0.0.0",
|
|
83
|
-
"@ainyc/canonry-provider-claude": "0.0.0",
|
|
84
|
-
"@ainyc/canonry-provider-local": "0.0.0",
|
|
85
83
|
"@ainyc/canonry-provider-gemini": "0.0.0",
|
|
86
|
-
"@ainyc/canonry-
|
|
84
|
+
"@ainyc/canonry-provider-claude": "0.0.0",
|
|
85
|
+
"@ainyc/canonry-integration-wordpress": "0.0.0",
|
|
87
86
|
"@ainyc/canonry-provider-openai": "0.0.0",
|
|
87
|
+
"@ainyc/canonry-provider-local": "0.0.0",
|
|
88
88
|
"@ainyc/canonry-provider-perplexity": "0.0.0"
|
|
89
89
|
},
|
|
90
90
|
"scripts": {
|