@ainyc/canonry 2.14.1 → 2.14.2
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-BwFUCV6e.js → index-D1v6Q-fS.js} +36 -36
- package/assets/index.html +1 -1
- package/dist/{chunk-QTS7VZXN.js → chunk-7VWSR5F6.js} +6 -0
- package/dist/{chunk-3T64Y7GR.js → chunk-CILBPOHB.js} +42 -2
- package/dist/{chunk-FV6PY5UE.js → chunk-NEDRCOOL.js} +14 -1
- package/dist/cli.js +4 -4
- package/dist/index.js +3 -3
- package/dist/{intelligence-service-AEI46KC5.js → intelligence-service-6S5YKANX.js} +1 -1
- package/dist/mcp.js +1 -1
- package/package.json +7 -7
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-D1v6Q-fS.js"></script>
|
|
16
16
|
<link rel="stylesheet" crossorigin href="./assets/index-U2SLimrz.css">
|
|
17
17
|
</head>
|
|
18
18
|
<body>
|
|
@@ -1298,11 +1298,15 @@ var ga4SocialReferralDtoSchema = z12.object({
|
|
|
1298
1298
|
var ga4TrafficSummaryDtoSchema = z12.object({
|
|
1299
1299
|
totalSessions: z12.number(),
|
|
1300
1300
|
totalOrganicSessions: z12.number(),
|
|
1301
|
+
/** Direct-channel sessions (sessions with no source — bookmarks, typed URLs, AI-driven traffic with stripped referrer). 0 for legacy rows from before the column was added. */
|
|
1302
|
+
totalDirectSessions: z12.number(),
|
|
1301
1303
|
totalUsers: z12.number(),
|
|
1302
1304
|
topPages: z12.array(z12.object({
|
|
1303
1305
|
landingPage: z12.string(),
|
|
1304
1306
|
sessions: z12.number(),
|
|
1305
1307
|
organicSessions: z12.number(),
|
|
1308
|
+
/** Per-page Direct-channel sessions. 0 for legacy rows. */
|
|
1309
|
+
directSessions: z12.number(),
|
|
1306
1310
|
users: z12.number()
|
|
1307
1311
|
})),
|
|
1308
1312
|
aiReferrals: z12.array(ga4AiReferralDtoSchema),
|
|
@@ -1319,6 +1323,8 @@ var ga4TrafficSummaryDtoSchema = z12.object({
|
|
|
1319
1323
|
organicSharePct: z12.number(),
|
|
1320
1324
|
/** Deduped AI sessions as a percentage of total sessions (0–100, rounded). */
|
|
1321
1325
|
aiSharePct: z12.number(),
|
|
1326
|
+
/** Direct-channel sessions as a percentage of total sessions (0–100, rounded). */
|
|
1327
|
+
directSharePct: z12.number(),
|
|
1322
1328
|
/** Social sessions as a percentage of total sessions (0–100, rounded). */
|
|
1323
1329
|
socialSharePct: z12.number(),
|
|
1324
1330
|
lastSyncedAt: z12.string().nullable()
|
|
@@ -60,7 +60,7 @@ import {
|
|
|
60
60
|
visibilityStateFromAnswerMentioned,
|
|
61
61
|
windowCutoff,
|
|
62
62
|
wordpressEnvSchema
|
|
63
|
-
} from "./chunk-
|
|
63
|
+
} from "./chunk-7VWSR5F6.js";
|
|
64
64
|
import {
|
|
65
65
|
IntelligenceService,
|
|
66
66
|
agentMemory,
|
|
@@ -98,7 +98,7 @@ import {
|
|
|
98
98
|
runs,
|
|
99
99
|
schedules,
|
|
100
100
|
usageCounters
|
|
101
|
-
} from "./chunk-
|
|
101
|
+
} from "./chunk-NEDRCOOL.js";
|
|
102
102
|
|
|
103
103
|
// src/telemetry.ts
|
|
104
104
|
import crypto from "crypto";
|
|
@@ -6662,6 +6662,8 @@ async function fetchTrafficByLandingPage(accessToken, propertyId, days) {
|
|
|
6662
6662
|
sessions: parseInt(row.metricValues[0].value, 10) || 0,
|
|
6663
6663
|
organicSessions: 0,
|
|
6664
6664
|
// populated by organic-only pass below
|
|
6665
|
+
directSessions: 0,
|
|
6666
|
+
// populated by direct-only pass below
|
|
6665
6667
|
users: parseInt(row.metricValues[1].value, 10) || 0
|
|
6666
6668
|
}));
|
|
6667
6669
|
rows.push(...pageRows);
|
|
@@ -6697,9 +6699,38 @@ async function fetchTrafficByLandingPage(accessToken, propertyId, days) {
|
|
|
6697
6699
|
organicOffset += (organicResponse.rows ?? []).length;
|
|
6698
6700
|
if ((organicResponse.rows ?? []).length < 1e4 || organicOffset >= total) break;
|
|
6699
6701
|
}
|
|
6702
|
+
const directMap = /* @__PURE__ */ new Map();
|
|
6703
|
+
let directOffset = 0;
|
|
6704
|
+
let directPageCount = 0;
|
|
6705
|
+
while (directPageCount < GA4_MAX_PAGES) {
|
|
6706
|
+
directPageCount++;
|
|
6707
|
+
const directRequest = {
|
|
6708
|
+
dateRanges: [{ startDate: formatDate(startDate), endDate: formatDate(endDate) }],
|
|
6709
|
+
dimensions: [{ name: "date" }, { name: "landingPagePlusQueryString" }],
|
|
6710
|
+
metrics: [{ name: "sessions" }],
|
|
6711
|
+
dimensionFilter: {
|
|
6712
|
+
filter: {
|
|
6713
|
+
fieldName: "sessionDefaultChannelGrouping",
|
|
6714
|
+
stringFilter: { matchType: "EXACT", value: "Direct" }
|
|
6715
|
+
}
|
|
6716
|
+
},
|
|
6717
|
+
limit: 1e4,
|
|
6718
|
+
offset: directOffset
|
|
6719
|
+
};
|
|
6720
|
+
const directResponse = await runReport(accessToken, propertyId, directRequest);
|
|
6721
|
+
if (!directResponse) break;
|
|
6722
|
+
for (const row of directResponse.rows ?? []) {
|
|
6723
|
+
const key = `${row.dimensionValues[0].value}::${row.dimensionValues[1].value}`;
|
|
6724
|
+
directMap.set(key, parseInt(row.metricValues[0].value, 10) || 0);
|
|
6725
|
+
}
|
|
6726
|
+
const total = directResponse.rowCount ?? 0;
|
|
6727
|
+
directOffset += (directResponse.rows ?? []).length;
|
|
6728
|
+
if ((directResponse.rows ?? []).length < 1e4 || directOffset >= total) break;
|
|
6729
|
+
}
|
|
6700
6730
|
for (const row of rows) {
|
|
6701
6731
|
const key = `${row.date}::${row.landingPage}`;
|
|
6702
6732
|
row.organicSessions = organicMap.get(key) ?? 0;
|
|
6733
|
+
row.directSessions = directMap.get(key) ?? 0;
|
|
6703
6734
|
}
|
|
6704
6735
|
for (const row of rows) {
|
|
6705
6736
|
if (row.date.length === 8 && !row.date.includes("-")) {
|
|
@@ -8665,6 +8696,7 @@ async function ga4Routes(app, opts) {
|
|
|
8665
8696
|
landingPageNormalized: normalizeUrlPath(row.landingPage),
|
|
8666
8697
|
sessions: row.sessions,
|
|
8667
8698
|
organicSessions: row.organicSessions,
|
|
8699
|
+
directSessions: row.directSessions,
|
|
8668
8700
|
users: row.users,
|
|
8669
8701
|
syncedAt: now,
|
|
8670
8702
|
syncRunId: runId
|
|
@@ -8782,6 +8814,9 @@ async function ga4Routes(app, opts) {
|
|
|
8782
8814
|
totalOrganicSessions: gaTrafficSummaries.totalOrganicSessions,
|
|
8783
8815
|
totalUsers: gaTrafficSummaries.totalUsers
|
|
8784
8816
|
}).from(gaTrafficSummaries).where(eq19(gaTrafficSummaries.projectId, project.id)).get();
|
|
8817
|
+
const directTotalRow = app.db.select({
|
|
8818
|
+
totalDirectSessions: sql5`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)`
|
|
8819
|
+
}).from(gaTrafficSnapshots).where(and8(...snapshotConditions)).get();
|
|
8785
8820
|
const summaryMeta = app.db.select({
|
|
8786
8821
|
periodStart: gaTrafficSummaries.periodStart,
|
|
8787
8822
|
periodEnd: gaTrafficSummaries.periodEnd
|
|
@@ -8790,6 +8825,7 @@ async function ga4Routes(app, opts) {
|
|
|
8790
8825
|
landingPage: sql5`COALESCE(${gaTrafficSnapshots.landingPageNormalized}, ${gaTrafficSnapshots.landingPage})`,
|
|
8791
8826
|
sessions: sql5`SUM(${gaTrafficSnapshots.sessions})`,
|
|
8792
8827
|
organicSessions: sql5`SUM(${gaTrafficSnapshots.organicSessions})`,
|
|
8828
|
+
directSessions: sql5`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)`,
|
|
8793
8829
|
users: sql5`SUM(${gaTrafficSnapshots.users})`
|
|
8794
8830
|
}).from(gaTrafficSnapshots).where(and8(...snapshotConditions)).groupBy(sql5`COALESCE(${gaTrafficSnapshots.landingPageNormalized}, ${gaTrafficSnapshots.landingPage})`).orderBy(sql5`SUM(${gaTrafficSnapshots.sessions}) DESC`).limit(limit).all();
|
|
8795
8831
|
const aiReferrals = app.db.select({
|
|
@@ -8825,14 +8861,17 @@ async function ga4Routes(app, opts) {
|
|
|
8825
8861
|
}).from(gaSocialReferrals).where(and8(...socialConditions)).get();
|
|
8826
8862
|
const latestSync = app.db.select({ syncedAt: gaTrafficSummaries.syncedAt }).from(gaTrafficSummaries).where(eq19(gaTrafficSummaries.projectId, project.id)).orderBy(desc9(gaTrafficSummaries.syncedAt)).limit(1).get();
|
|
8827
8863
|
const total = summaryRow?.totalSessions ?? 0;
|
|
8864
|
+
const totalDirectSessions = directTotalRow?.totalDirectSessions ?? 0;
|
|
8828
8865
|
return {
|
|
8829
8866
|
totalSessions: total,
|
|
8830
8867
|
totalOrganicSessions: summaryRow?.totalOrganicSessions ?? 0,
|
|
8868
|
+
totalDirectSessions,
|
|
8831
8869
|
totalUsers: summaryRow?.totalUsers ?? 0,
|
|
8832
8870
|
topPages: rows.map((r) => ({
|
|
8833
8871
|
landingPage: r.landingPage,
|
|
8834
8872
|
sessions: r.sessions ?? 0,
|
|
8835
8873
|
organicSessions: r.organicSessions ?? 0,
|
|
8874
|
+
directSessions: r.directSessions ?? 0,
|
|
8836
8875
|
users: r.users ?? 0
|
|
8837
8876
|
})),
|
|
8838
8877
|
aiReferrals: aiReferrals.map((r) => ({
|
|
@@ -8855,6 +8894,7 @@ async function ga4Routes(app, opts) {
|
|
|
8855
8894
|
socialUsers: socialTotals?.users ?? 0,
|
|
8856
8895
|
organicSharePct: total > 0 ? Math.round((summaryRow?.totalOrganicSessions ?? 0) / total * 100) : 0,
|
|
8857
8896
|
aiSharePct: total > 0 ? Math.round((aiDeduped?.sessions ?? 0) / total * 100) : 0,
|
|
8897
|
+
directSharePct: total > 0 ? Math.round(totalDirectSessions / total * 100) : 0,
|
|
8858
8898
|
socialSharePct: total > 0 ? Math.round((socialTotals?.sessions ?? 0) / total * 100) : 0,
|
|
8859
8899
|
lastSyncedAt: latestSync?.syncedAt ?? null,
|
|
8860
8900
|
periodStart: (() => {
|
|
@@ -320,6 +320,13 @@ var gaTrafficSnapshots = sqliteTable("ga_traffic_snapshots", {
|
|
|
320
320
|
landingPageNormalized: text("landing_page_normalized"),
|
|
321
321
|
sessions: integer("sessions").notNull().default(0),
|
|
322
322
|
organicSessions: integer("organic_sessions").notNull().default(0),
|
|
323
|
+
/**
|
|
324
|
+
* Per-page Direct channel sessions. Nullable so existing rows survive
|
|
325
|
+
* the migration; new GA4 sync writes populate it. Distinct from
|
|
326
|
+
* `sessions - organicSessions` because that residual lumps Direct
|
|
327
|
+
* together with social, referral, paid, and email.
|
|
328
|
+
*/
|
|
329
|
+
directSessions: integer("direct_sessions"),
|
|
323
330
|
users: integer("users").notNull().default(0),
|
|
324
331
|
syncedAt: text("synced_at").notNull(),
|
|
325
332
|
syncRunId: text("sync_run_id").references(() => runs.id, { onDelete: "cascade" })
|
|
@@ -1068,7 +1075,13 @@ var MIGRATIONS = [
|
|
|
1068
1075
|
// See plans/ai-attribution-research.md "Step 1 — data hygiene".
|
|
1069
1076
|
`ALTER TABLE ga_traffic_snapshots ADD COLUMN landing_page_normalized TEXT`,
|
|
1070
1077
|
`CREATE INDEX IF NOT EXISTS idx_ga_traffic_page_normalized
|
|
1071
|
-
ON ga_traffic_snapshots(project_id, date, landing_page_normalized)
|
|
1078
|
+
ON ga_traffic_snapshots(project_id, date, landing_page_normalized)`,
|
|
1079
|
+
// v45: Per-page Direct channel sessions on ga_traffic_snapshots. Nullable
|
|
1080
|
+
// so existing rows survive; populated by the GA4 sync writer in a
|
|
1081
|
+
// separate commit. Unblocks an honest channel breakdown for the project
|
|
1082
|
+
// dashboard (organic / social / direct / known-AI) — see
|
|
1083
|
+
// plans/ai-attribution-research.md scope A.
|
|
1084
|
+
`ALTER TABLE ga_traffic_snapshots ADD COLUMN direct_sessions INTEGER`
|
|
1072
1085
|
];
|
|
1073
1086
|
function isDuplicateColumnError(err) {
|
|
1074
1087
|
if (!(err instanceof Error)) return false;
|
package/dist/cli.js
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
setGoogleAuthConfig,
|
|
18
18
|
showFirstRunNotice,
|
|
19
19
|
trackEvent
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-CILBPOHB.js";
|
|
21
21
|
import {
|
|
22
22
|
CcReleaseSyncStatuses,
|
|
23
23
|
CheckScopes,
|
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
saveConfig,
|
|
46
46
|
saveConfigPatch,
|
|
47
47
|
usageError
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-7VWSR5F6.js";
|
|
49
49
|
import {
|
|
50
50
|
apiKeys,
|
|
51
51
|
competitors,
|
|
@@ -56,7 +56,7 @@ import {
|
|
|
56
56
|
projects,
|
|
57
57
|
querySnapshots,
|
|
58
58
|
runs
|
|
59
|
-
} from "./chunk-
|
|
59
|
+
} from "./chunk-NEDRCOOL.js";
|
|
60
60
|
import "./chunk-MLKGABMK.js";
|
|
61
61
|
|
|
62
62
|
// src/cli.ts
|
|
@@ -371,7 +371,7 @@ async function backfillNormalizedPathsCommand(opts) {
|
|
|
371
371
|
console.log(` Unchanged: ${unchanged}`);
|
|
372
372
|
}
|
|
373
373
|
async function backfillInsightsCommand(project, opts) {
|
|
374
|
-
const { IntelligenceService } = await import("./intelligence-service-
|
|
374
|
+
const { IntelligenceService } = await import("./intelligence-service-6S5YKANX.js");
|
|
375
375
|
const config = loadConfig();
|
|
376
376
|
const db = createClient(config.database);
|
|
377
377
|
migrate(db);
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createServer
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-CILBPOHB.js";
|
|
4
4
|
import {
|
|
5
5
|
loadConfig
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-7VWSR5F6.js";
|
|
7
|
+
import "./chunk-NEDRCOOL.js";
|
|
8
8
|
import "./chunk-MLKGABMK.js";
|
|
9
9
|
export {
|
|
10
10
|
createServer,
|
package/dist/mcp.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ainyc/canonry",
|
|
3
|
-
"version": "2.14.
|
|
3
|
+
"version": "2.14.2",
|
|
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",
|
|
@@ -60,20 +60,20 @@
|
|
|
60
60
|
"tsup": "^8.5.1",
|
|
61
61
|
"tsx": "^4.19.0",
|
|
62
62
|
"@ainyc/canonry-config": "0.0.0",
|
|
63
|
-
"@ainyc/canonry-api-routes": "0.0.0",
|
|
64
63
|
"@ainyc/canonry-contracts": "0.0.0",
|
|
65
64
|
"@ainyc/canonry-db": "0.0.0",
|
|
66
|
-
"@ainyc/canonry-
|
|
67
|
-
"@ainyc/canonry-integration-commoncrawl": "0.0.0",
|
|
65
|
+
"@ainyc/canonry-api-routes": "0.0.0",
|
|
68
66
|
"@ainyc/canonry-intelligence": "0.0.0",
|
|
67
|
+
"@ainyc/canonry-integration-commoncrawl": "0.0.0",
|
|
69
68
|
"@ainyc/canonry-integration-google": "0.0.0",
|
|
69
|
+
"@ainyc/canonry-integration-bing": "0.0.0",
|
|
70
70
|
"@ainyc/canonry-provider-cdp": "0.0.0",
|
|
71
|
-
"@ainyc/canonry-provider-claude": "0.0.0",
|
|
72
|
-
"@ainyc/canonry-provider-gemini": "0.0.0",
|
|
73
71
|
"@ainyc/canonry-integration-wordpress": "0.0.0",
|
|
74
72
|
"@ainyc/canonry-provider-local": "0.0.0",
|
|
73
|
+
"@ainyc/canonry-provider-perplexity": "0.0.0",
|
|
74
|
+
"@ainyc/canonry-provider-gemini": "0.0.0",
|
|
75
75
|
"@ainyc/canonry-provider-openai": "0.0.0",
|
|
76
|
-
"@ainyc/canonry-provider-
|
|
76
|
+
"@ainyc/canonry-provider-claude": "0.0.0"
|
|
77
77
|
},
|
|
78
78
|
"scripts": {
|
|
79
79
|
"build": "tsx scripts/copy-agent-assets.ts && tsup && tsx build-web.ts",
|