@canonry/canonry 7.15.0 → 7.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +22 -6
- package/assets/assets/{AuditHistoryPanel-Cl9tUvSZ.js → AuditHistoryPanel-CUde9U_6.js} +1 -1
- package/assets/assets/{BacklinksPage-CTeTJ9dh.js → BacklinksPage-DMQPw8ks.js} +1 -1
- package/assets/assets/{HistoryPage-DpOoXr2P.js → HistoryPage-DZSa1gYf.js} +1 -1
- package/assets/assets/{MeasurementPropertyPage-DxXsgM25.js → MeasurementPropertyPage-DgW17Jpd.js} +1 -1
- package/assets/assets/ProjectPage-C8vdtqtA.js +8 -0
- package/assets/assets/{RunsPage-CfDi7I1z.js → RunsPage-DRfNd-Jp.js} +1 -1
- package/assets/assets/{SettingsPage-BHDb1apK.js → SettingsPage-D38Gl1Nv.js} +1 -1
- package/assets/assets/{SiteHealthSection-DQZyy4P_.js → SiteHealthSection-CR3zB84D.js} +3 -3
- package/assets/assets/{TrafficPage-DX_vN2RL.js → TrafficPage-DX3qRPgQ.js} +2 -2
- package/assets/assets/{TrafficSourceDetailPage-Cg92zrtZ.js → TrafficSourceDetailPage-CigB82vX.js} +1 -1
- package/assets/assets/{extract-error-message-BKxVCbov.js → extract-error-message-DsMnnkxT.js} +1 -1
- package/assets/assets/{index-DoQJETc6.js → index-DBr6ISbx.js} +25 -25
- package/assets/assets/{react-sigma_core.esm.min-BhqZcSgh.js → react-sigma_core.esm.min-CkYxzGpi.js} +1 -1
- package/assets/assets/{v2-overview-adapter-DZ5YsE_G.js → v2-overview-adapter-5x8UiA07.js} +1 -1
- package/assets/index.html +1 -1
- package/dist/{chunk-YFCKHEKM.js → chunk-2MBI5SYB.js} +3 -3
- package/dist/{chunk-7HJYGDRW.js → chunk-3NAZXITW.js} +1680 -840
- package/dist/{chunk-KOBK4I5N.js → chunk-PVWGKDY6.js} +156 -2
- package/dist/{chunk-SG6T3DEP.js → chunk-QPOXDS43.js} +2 -2
- package/dist/{chunk-LC7GMHOL.js → chunk-RBQUGZM4.js} +23 -1
- package/dist/{chunk-N2MRW2DH.js → chunk-WEKVQK3O.js} +43 -20
- package/dist/{chunk-SGQBPTWQ.js → chunk-WVBLFG7H.js} +30 -3
- package/dist/cli.js +123 -12
- package/dist/{demo-server-YWGUGZMI.js → demo-server-BVJFYR4V.js} +68 -15
- package/dist/index.js +6 -6
- package/dist/{intelligence-service-7RKUUR7O.js → intelligence-service-FK2W72X7.js} +2 -2
- package/dist/mcp.js +4 -4
- package/package.json +9 -9
- package/assets/assets/ProjectPage-By9arjLJ.js +0 -8
package/dist/cli.js
CHANGED
|
@@ -33,11 +33,11 @@ import {
|
|
|
33
33
|
trackCliCommandFinished,
|
|
34
34
|
trackEvent,
|
|
35
35
|
waitForServerRuntimeStartup
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-WEKVQK3O.js";
|
|
37
37
|
import {
|
|
38
38
|
autoSyncSkills,
|
|
39
39
|
formatAutoSyncNotice
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-2MBI5SYB.js";
|
|
41
41
|
import {
|
|
42
42
|
configExists,
|
|
43
43
|
createApiClient,
|
|
@@ -54,13 +54,13 @@ import {
|
|
|
54
54
|
saveConfig,
|
|
55
55
|
saveConfigPatch,
|
|
56
56
|
shouldPrintServeSkillsNudge
|
|
57
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-WVBLFG7H.js";
|
|
58
58
|
import {
|
|
59
59
|
DEFAULT_DEMO_TRUSTED_PROXIES,
|
|
60
60
|
trustedProxiesProblem,
|
|
61
61
|
trustedProxyProblem
|
|
62
62
|
} from "./chunk-RB2F4D3Z.js";
|
|
63
|
-
import "./chunk-
|
|
63
|
+
import "./chunk-QPOXDS43.js";
|
|
64
64
|
import {
|
|
65
65
|
CliError,
|
|
66
66
|
EXIT_SYSTEM_ERROR,
|
|
@@ -72,7 +72,7 @@ import {
|
|
|
72
72
|
runMeasurementDraftAction,
|
|
73
73
|
systemError,
|
|
74
74
|
usageError
|
|
75
|
-
} from "./chunk-
|
|
75
|
+
} from "./chunk-RBQUGZM4.js";
|
|
76
76
|
import {
|
|
77
77
|
CLOUDFLARE_WORKER_BINDINGS,
|
|
78
78
|
CLOUDFLARE_WORKER_GENERATED_MARKER,
|
|
@@ -104,7 +104,7 @@ import {
|
|
|
104
104
|
rawEventSamples,
|
|
105
105
|
readMarketCompetitorNames,
|
|
106
106
|
runs
|
|
107
|
-
} from "./chunk-
|
|
107
|
+
} from "./chunk-3NAZXITW.js";
|
|
108
108
|
import {
|
|
109
109
|
AdsDeliverySnapshotStatuses,
|
|
110
110
|
AdsHistoricalCampaignRollupStatuses,
|
|
@@ -119,6 +119,7 @@ import {
|
|
|
119
119
|
CitationStates,
|
|
120
120
|
DiscoveryPromoteCompetitorSkipReasons,
|
|
121
121
|
FEEDBACK_KINDS,
|
|
122
|
+
GA_SEARCH_LANDING_WINDOW_DAYS,
|
|
122
123
|
GaMoverChangeBases,
|
|
123
124
|
MeasurementEvidenceShapes,
|
|
124
125
|
OUTSTANDING_PROVIDER_BATCH_STATUSES,
|
|
@@ -181,6 +182,7 @@ import {
|
|
|
181
182
|
formatRunErrorOneLine,
|
|
182
183
|
formatSignedPointDelta,
|
|
183
184
|
formatSiteAuditPageBudget,
|
|
185
|
+
gaSearchLandingHasSearchData,
|
|
184
186
|
gbpNegativeReviewMaxStarsSchema,
|
|
185
187
|
googleAdsMetricsWindowSchema,
|
|
186
188
|
isRetiredAgentProviderId,
|
|
@@ -234,7 +236,7 @@ import {
|
|
|
234
236
|
visibilityCompareSelectionSchema,
|
|
235
237
|
visibilityReportRequestSchema,
|
|
236
238
|
winnabilityClassSchema
|
|
237
|
-
} from "./chunk-
|
|
239
|
+
} from "./chunk-PVWGKDY6.js";
|
|
238
240
|
|
|
239
241
|
// src/cli.ts
|
|
240
242
|
import { pathToFileURL } from "url";
|
|
@@ -784,7 +786,7 @@ function parseDemoTrustedProxies(values) {
|
|
|
784
786
|
async function demoCommand(options) {
|
|
785
787
|
const { host, port } = parseDemoListenOptions(options);
|
|
786
788
|
const trustProxy = parseDemoTrustedProxies(options.trustProxy);
|
|
787
|
-
const { createDemoServer } = await import("./demo-server-
|
|
789
|
+
const { createDemoServer } = await import("./demo-server-BVJFYR4V.js");
|
|
788
790
|
const app = await createDemoServer({ trustProxy });
|
|
789
791
|
let stopping = false;
|
|
790
792
|
const stop = () => {
|
|
@@ -1198,7 +1200,7 @@ No DB writes performed. Re-run without --dry-run to apply.`);
|
|
|
1198
1200
|
}
|
|
1199
1201
|
}
|
|
1200
1202
|
async function backfillInsightsCommand(project2, opts) {
|
|
1201
|
-
const { IntelligenceService } = await import("./intelligence-service-
|
|
1203
|
+
const { IntelligenceService } = await import("./intelligence-service-FK2W72X7.js");
|
|
1202
1204
|
const config = loadConfig();
|
|
1203
1205
|
const db = createClient(config.database);
|
|
1204
1206
|
migrate(db);
|
|
@@ -5437,8 +5439,99 @@ async function gaSync(project2, opts) {
|
|
|
5437
5439
|
console.log(` AI rows: ${result.aiReferralCount}`);
|
|
5438
5440
|
console.log(` Social rows: ${result.socialReferralCount}`);
|
|
5439
5441
|
console.log(` Period: ${result.days} days${result.clamped ? ` (requested ${result.requestedDays})` : ""}`);
|
|
5442
|
+
const searchLanding = result.measurement.searchLandingPages;
|
|
5443
|
+
if (searchLanding) {
|
|
5444
|
+
console.log(` Search Console landing pages: ${searchLanding.status} (${searchLanding.rowCount} rows)`);
|
|
5445
|
+
if (searchLanding.error) console.log(` Error: ${searchLanding.error}`);
|
|
5446
|
+
}
|
|
5440
5447
|
console.log(` Synced at: ${result.syncedAt}`);
|
|
5441
5448
|
}
|
|
5449
|
+
var SEARCH_LANDING_NOT_AVAILABLE = "n/a";
|
|
5450
|
+
function searchLandingCells(metrics) {
|
|
5451
|
+
return [
|
|
5452
|
+
metrics.organicGoogleSearchClicks.toLocaleString("en-US"),
|
|
5453
|
+
metrics.organicGoogleSearchImpressions.toLocaleString("en-US"),
|
|
5454
|
+
metrics.organicGoogleSearchClickThroughRate === null ? SEARCH_LANDING_NOT_AVAILABLE : formatPercent(metrics.organicGoogleSearchClickThroughRate),
|
|
5455
|
+
metrics.organicGoogleSearchAveragePosition === null ? SEARCH_LANDING_NOT_AVAILABLE : metrics.organicGoogleSearchAveragePosition.toFixed(1),
|
|
5456
|
+
metrics.activeUsers.toLocaleString("en-US")
|
|
5457
|
+
];
|
|
5458
|
+
}
|
|
5459
|
+
async function gaSearchLandingPages(project2, opts) {
|
|
5460
|
+
const client = getClient7();
|
|
5461
|
+
const params = {};
|
|
5462
|
+
if (opts?.window) params.window = opts.window;
|
|
5463
|
+
if (opts?.limit) params.limit = opts.limit;
|
|
5464
|
+
if (opts?.offset) params.offset = opts.offset;
|
|
5465
|
+
const result = await client.gaSearchLandingPages(
|
|
5466
|
+
project2,
|
|
5467
|
+
Object.keys(params).length > 0 ? params : void 0
|
|
5468
|
+
);
|
|
5469
|
+
if (opts?.format === "json") {
|
|
5470
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5471
|
+
return;
|
|
5472
|
+
} else if (opts?.format === "jsonl") {
|
|
5473
|
+
emitJsonl(result.rows.map((row) => ({
|
|
5474
|
+
project: project2,
|
|
5475
|
+
window: result.window,
|
|
5476
|
+
windowStart: result.windowStart,
|
|
5477
|
+
windowEnd: result.windowEnd,
|
|
5478
|
+
...row
|
|
5479
|
+
})));
|
|
5480
|
+
return;
|
|
5481
|
+
}
|
|
5482
|
+
if (result.status === "never-synced") {
|
|
5483
|
+
console.log(`No GA4 Search Console landing-page data for "${project2}" yet. Run "canonry ga sync ${project2}".`);
|
|
5484
|
+
return;
|
|
5485
|
+
}
|
|
5486
|
+
console.log(`Google organic search traffic: landing page + query string (GA4 Search Console link) for "${project2}"`);
|
|
5487
|
+
if (result.windowStart && result.windowEnd) {
|
|
5488
|
+
console.log(`Last ${result.windowDays ?? GA_SEARCH_LANDING_WINDOW_DAYS[result.window]} days: ${result.windowStart} to ${result.windowEnd}${result.timeZone ? ` (${result.timeZone})` : ""}`);
|
|
5489
|
+
}
|
|
5490
|
+
if (result.status === "unavailable") {
|
|
5491
|
+
console.log(`Status: unavailable. GA4 did not return Search Console data: ${result.error ?? "no reason given"}`);
|
|
5492
|
+
console.log(`Link Search Console to this GA4 property (GA4 Admin, Product links, Search Console links), then run "canonry ga sync ${project2}".`);
|
|
5493
|
+
} else if (result.status === "error") {
|
|
5494
|
+
console.log(`Status: the last refresh failed${result.attemptedAt ? ` (${result.attemptedAt})` : ""}: ${result.error ?? "unknown error"}`);
|
|
5495
|
+
}
|
|
5496
|
+
if (result.status !== "ready" && result.total) {
|
|
5497
|
+
console.log(`Showing the snapshot synced ${result.syncedAt ?? "earlier"}.`);
|
|
5498
|
+
}
|
|
5499
|
+
if (!result.total) {
|
|
5500
|
+
console.log("No stored snapshot.");
|
|
5501
|
+
return;
|
|
5502
|
+
}
|
|
5503
|
+
const headers = ["LANDING PAGE", "CLICKS", "IMPRESSIONS", "CTR", "AVG POSITION", "ACTIVE USERS"];
|
|
5504
|
+
const table = [
|
|
5505
|
+
["Total", ...searchLandingCells(result.total)],
|
|
5506
|
+
...result.rows.map((row) => [row.landingPage, ...searchLandingCells(row)])
|
|
5507
|
+
];
|
|
5508
|
+
const pageWidth = Math.min(60, Math.max(headers[0].length, ...table.map((row) => row[0].length)));
|
|
5509
|
+
const widths = headers.map((header, index) => index === 0 ? pageWidth : Math.max(header.length, ...table.map((row) => row[index].length)));
|
|
5510
|
+
const line = (cells) => ` ${cells.map((cell2, index) => index === 0 ? (cell2.length > pageWidth ? `${cell2.slice(0, pageWidth - 3)}...` : cell2).padEnd(pageWidth) : cell2.padStart(widths[index])).join(" ")}`;
|
|
5511
|
+
console.log();
|
|
5512
|
+
console.log(line(headers));
|
|
5513
|
+
console.log(` ${widths.map((width) => "\u2500".repeat(width)).join(" ")}`);
|
|
5514
|
+
for (const row of table) console.log(line(row));
|
|
5515
|
+
console.log();
|
|
5516
|
+
if (result.rows.length > 0) {
|
|
5517
|
+
console.log(` Showing ${result.offset + 1}-${result.offset + result.rows.length} of ${result.totalRows} pages.`);
|
|
5518
|
+
} else if (result.totalRows > 0) {
|
|
5519
|
+
console.log(` No landing-page rows at offset ${result.offset} (${result.totalRows} stored).`);
|
|
5520
|
+
}
|
|
5521
|
+
if (!gaSearchLandingHasSearchData(result.total)) {
|
|
5522
|
+
console.log(" No landing pages had Google organic search traffic in this window.");
|
|
5523
|
+
console.log(" If the property should have some, check its Search Console link in GA4 (Admin, Product links, Search Console links).");
|
|
5524
|
+
}
|
|
5525
|
+
if (result.rowsCapped && result.reportRowCount !== null) {
|
|
5526
|
+
console.log(` GA4 reported ${result.reportRowCount} rows; the ${result.totalRows} with the most clicks are stored.`);
|
|
5527
|
+
}
|
|
5528
|
+
if (result.subjectToThresholding) {
|
|
5529
|
+
console.log(" GA4 applied thresholding to this report, so some rows may be withheld.");
|
|
5530
|
+
}
|
|
5531
|
+
if (result.status === "ready" && result.syncedAt) {
|
|
5532
|
+
console.log(` Synced at: ${result.syncedAt}`);
|
|
5533
|
+
}
|
|
5534
|
+
}
|
|
5442
5535
|
async function gaTraffic(project2, opts) {
|
|
5443
5536
|
const client = getClient7();
|
|
5444
5537
|
const params = rangeParams(opts, opts?.limit ? { limit: String(opts.limit) } : void 0);
|
|
@@ -6094,13 +6187,13 @@ var GA_CLI_COMMANDS = [
|
|
|
6094
6187
|
},
|
|
6095
6188
|
{
|
|
6096
6189
|
path: ["ga", "sync"],
|
|
6097
|
-
usage: "canonry ga sync <project> [--days 30] [--only traffic|ai|social] [--format json]",
|
|
6190
|
+
usage: "canonry ga sync <project> [--days 30] [--only traffic|ai|social|search-landing] [--format json]",
|
|
6098
6191
|
options: {
|
|
6099
6192
|
days: stringOption(),
|
|
6100
6193
|
only: stringOption()
|
|
6101
6194
|
},
|
|
6102
6195
|
run: async (input) => {
|
|
6103
|
-
const project2 = requireProject(input, "ga.sync", "canonry ga sync <project> [--days 30] [--only traffic|ai|social] [--format json]");
|
|
6196
|
+
const project2 = requireProject(input, "ga.sync", "canonry ga sync <project> [--days 30] [--only traffic|ai|social|search-landing] [--format json]");
|
|
6104
6197
|
const daysStr = getString(input.values, "days");
|
|
6105
6198
|
const days = daysStr ? parseInt(daysStr, 10) : void 0;
|
|
6106
6199
|
const only = getString(input.values, "only");
|
|
@@ -6132,6 +6225,24 @@ var GA_CLI_COMMANDS = [
|
|
|
6132
6225
|
});
|
|
6133
6226
|
}
|
|
6134
6227
|
},
|
|
6228
|
+
{
|
|
6229
|
+
path: ["ga", "search-landing-pages"],
|
|
6230
|
+
usage: "canonry ga search-landing-pages <project> [--window 7d|28d|90d] [--limit 50] [--offset 0] [--format json|jsonl]",
|
|
6231
|
+
options: {
|
|
6232
|
+
window: stringOption(),
|
|
6233
|
+
limit: stringOption(),
|
|
6234
|
+
offset: stringOption()
|
|
6235
|
+
},
|
|
6236
|
+
run: async (input) => {
|
|
6237
|
+
const project2 = requireProject(input, "ga.search-landing-pages", "canonry ga search-landing-pages <project> [--window 7d|28d|90d] [--limit 50] [--offset 0] [--format json|jsonl]");
|
|
6238
|
+
await gaSearchLandingPages(project2, {
|
|
6239
|
+
window: getString(input.values, "window"),
|
|
6240
|
+
limit: getString(input.values, "limit"),
|
|
6241
|
+
offset: getString(input.values, "offset"),
|
|
6242
|
+
format: input.format
|
|
6243
|
+
});
|
|
6244
|
+
}
|
|
6245
|
+
},
|
|
6135
6246
|
{
|
|
6136
6247
|
path: ["ga", "traffic"],
|
|
6137
6248
|
usage: `canonry ga traffic <project> [--limit 50] ${RANGE_USAGE} [--format json]`,
|
|
@@ -6241,7 +6352,7 @@ var GA_CLI_COMMANDS = [
|
|
|
6241
6352
|
unknownSubcommand(input.positionals[0], {
|
|
6242
6353
|
command: "ga",
|
|
6243
6354
|
usage: "canonry ga <subcommand> <project> [args]",
|
|
6244
|
-
available: ["connect", "disconnect", "status", "properties", "sync", "measurement-analysis", "traffic", "coverage", "ai-referral-history", "ai-referral-daily", "social-referral-history", "session-history", "social-referral-summary", "attribution"]
|
|
6355
|
+
available: ["connect", "disconnect", "status", "properties", "sync", "measurement-analysis", "search-landing-pages", "traffic", "coverage", "ai-referral-history", "ai-referral-daily", "social-referral-history", "session-history", "social-referral-summary", "attribution"]
|
|
6245
6356
|
});
|
|
6246
6357
|
}
|
|
6247
6358
|
}
|
|
@@ -5,11 +5,11 @@ import {
|
|
|
5
5
|
computeFactorAverages,
|
|
6
6
|
layoutSiteCrawlGraphInput,
|
|
7
7
|
persistSiteCrawlGraphLayout
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-QPOXDS43.js";
|
|
9
9
|
import {
|
|
10
10
|
PACKAGE_VERSION,
|
|
11
11
|
canonryMcpTools
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-RBQUGZM4.js";
|
|
13
13
|
import {
|
|
14
14
|
HISTORY_WINDOW_RUNS,
|
|
15
15
|
IntelligenceService,
|
|
@@ -42,6 +42,8 @@ import {
|
|
|
42
42
|
gaDailyTotals,
|
|
43
43
|
gaLeadEventsDaily,
|
|
44
44
|
gaMeasurementSyncStates,
|
|
45
|
+
gaSearchLandingPages,
|
|
46
|
+
gaSearchLandingWindows,
|
|
45
47
|
gaTrafficSnapshots,
|
|
46
48
|
gaTrafficSummaries,
|
|
47
49
|
gaTrafficWindowSummaries,
|
|
@@ -83,7 +85,7 @@ import {
|
|
|
83
85
|
siteCrawlPages,
|
|
84
86
|
siteCrawlSnapshots,
|
|
85
87
|
trafficSources
|
|
86
|
-
} from "./chunk-
|
|
88
|
+
} from "./chunk-3NAZXITW.js";
|
|
87
89
|
import {
|
|
88
90
|
RunKinds,
|
|
89
91
|
SiteCrawlFetchStates,
|
|
@@ -112,7 +114,7 @@ import {
|
|
|
112
114
|
roundPreservingTotal,
|
|
113
115
|
siteAuditPageFactorSchema,
|
|
114
116
|
wilsonInterval
|
|
115
|
-
} from "./chunk-
|
|
117
|
+
} from "./chunk-PVWGKDY6.js";
|
|
116
118
|
|
|
117
119
|
// src/demo-server.ts
|
|
118
120
|
import { dirname, join as join2 } from "path";
|
|
@@ -1170,6 +1172,7 @@ var DEMO_READ_ROUTES = /* @__PURE__ */ new Set([
|
|
|
1170
1172
|
"/api/v1/projects/:name/ga/attribution-trend",
|
|
1171
1173
|
"/api/v1/projects/:name/ga/coverage",
|
|
1172
1174
|
"/api/v1/projects/:name/ga/measurement-analysis",
|
|
1175
|
+
"/api/v1/projects/:name/ga/search-landing-pages",
|
|
1173
1176
|
"/api/v1/projects/:name/ga/session-history",
|
|
1174
1177
|
"/api/v1/projects/:name/ga/social-referral-history",
|
|
1175
1178
|
"/api/v1/projects/:name/ga/social-referral-trend",
|
|
@@ -2082,6 +2085,16 @@ function seedDemoCore(db, context) {
|
|
|
2082
2085
|
seedDemoAnswerIntelligence(db, context.simple);
|
|
2083
2086
|
}
|
|
2084
2087
|
|
|
2088
|
+
// src/demo/types.ts
|
|
2089
|
+
var DEMO_GA4_PROPERTY_ID = "demo-property";
|
|
2090
|
+
function createDemoSeedContext(now = /* @__PURE__ */ new Date()) {
|
|
2091
|
+
return {
|
|
2092
|
+
now,
|
|
2093
|
+
simple: { id: "demo-project-summit", name: "summit-roofing", displayName: "Summit Roofing", domain: "summit-roofing.example" },
|
|
2094
|
+
portfolio: { id: "demo-project-harbor", name: "harbor-resorts", displayName: "Harbor Resorts", domain: "harbor-resorts.example" }
|
|
2095
|
+
};
|
|
2096
|
+
}
|
|
2097
|
+
|
|
2085
2098
|
// src/demo/seed-site-crawl.ts
|
|
2086
2099
|
var DEMO_AUDIT_FACTORS = [
|
|
2087
2100
|
{ id: "structured-data", name: "Structured Data (JSON-LD)", weight: 12, bias: 4, found: "JSON-LD markup describes this page.", missing: "JSON-LD markup is missing or incomplete.", recommendation: "Add JSON-LD that describes the business and this page." },
|
|
@@ -2794,6 +2807,54 @@ async function seedDemoSignals(db, context) {
|
|
|
2794
2807
|
await seedProjectSignals(db, project, context.now, index);
|
|
2795
2808
|
}
|
|
2796
2809
|
}
|
|
2810
|
+
function seedSearchLandingPages(db, input) {
|
|
2811
|
+
const windows = [["7d", 7, 1], ["28d", 28, 4], ["90d", 90, 12]];
|
|
2812
|
+
for (const [windowKey, days, scale] of windows) {
|
|
2813
|
+
const clicks = (140 + input.variant * 25) * scale;
|
|
2814
|
+
const impressions = (5200 + input.variant * 640) * scale;
|
|
2815
|
+
db.insert(gaSearchLandingWindows).values({
|
|
2816
|
+
id: `${input.prefix}-ga-search-window-${windowKey}`,
|
|
2817
|
+
projectId: input.projectId,
|
|
2818
|
+
propertyId: DEMO_GA4_PROPERTY_ID,
|
|
2819
|
+
windowKey,
|
|
2820
|
+
periodStart: day(input.now, -days),
|
|
2821
|
+
periodEnd: day(input.now, -1),
|
|
2822
|
+
timeZone: "UTC",
|
|
2823
|
+
totalClicks: clicks,
|
|
2824
|
+
totalImpressions: impressions,
|
|
2825
|
+
totalCtr: clicks / impressions,
|
|
2826
|
+
totalAveragePosition: 7.4 - input.variant * 0.6,
|
|
2827
|
+
totalActiveUsers: (170 + input.variant * 30) * scale,
|
|
2828
|
+
reportRowCount: 24,
|
|
2829
|
+
rowsCapped: true,
|
|
2830
|
+
syncedAt: input.nowIso,
|
|
2831
|
+
syncRunId: input.syncRunId,
|
|
2832
|
+
createdAt: input.nowIso
|
|
2833
|
+
}).run();
|
|
2834
|
+
const pages = [
|
|
2835
|
+
["/", 0.55, 0.32, 5.1],
|
|
2836
|
+
["/services/", 0.21, 0.27, 7.8]
|
|
2837
|
+
];
|
|
2838
|
+
for (const [landingPage, clickShare, impressionShare, position] of pages) {
|
|
2839
|
+
const pageClicks = Math.round(clicks * clickShare);
|
|
2840
|
+
const pageImpressions = Math.round(impressions * impressionShare);
|
|
2841
|
+
db.insert(gaSearchLandingPages).values({
|
|
2842
|
+
id: `${input.prefix}-ga-search-page-${windowKey}-${landingPage}`,
|
|
2843
|
+
projectId: input.projectId,
|
|
2844
|
+
windowKey,
|
|
2845
|
+
landingPage,
|
|
2846
|
+
clicks: pageClicks,
|
|
2847
|
+
impressions: pageImpressions,
|
|
2848
|
+
ctr: pageClicks / pageImpressions,
|
|
2849
|
+
averagePosition: position,
|
|
2850
|
+
activeUsers: Math.round(pageClicks * 1.2),
|
|
2851
|
+
syncedAt: input.nowIso,
|
|
2852
|
+
syncRunId: input.syncRunId,
|
|
2853
|
+
createdAt: input.nowIso
|
|
2854
|
+
}).run();
|
|
2855
|
+
}
|
|
2856
|
+
}
|
|
2857
|
+
}
|
|
2797
2858
|
async function seedProjectSignals(db, project, now, variant) {
|
|
2798
2859
|
const nowIso = now.toISOString();
|
|
2799
2860
|
const prefix = `demo-signals-${project.id}`;
|
|
@@ -2834,7 +2895,8 @@ async function seedProjectSignals(db, project, now, variant) {
|
|
|
2834
2895
|
db.insert(gscUrlInspections).values({ id: `${prefix}-gsc-inspection`, projectId: project.id, syncRunId, url: `${root}services/`, indexingState: "INDEXING_ALLOWED", verdict: "PASS", coverageState: "Submitted and indexed", pageFetchState: "SUCCESSFUL", robotsTxtState: "ALLOWED", crawlTime: nowIso, lastCrawlResult: "SUCCESSFUL", isMobileFriendly: true, richResults: ["Sample FAQ"], referringUrls: [root], inspectedAt: nowIso, createdAt: nowIso }).run();
|
|
2835
2896
|
db.insert(bingKeywordStats).values(searchTerms.map((query, i) => ({ id: `${prefix}-bing-keyword-${i}`, projectId: project.id, query, impressions: 310 - i * 70, clicks: 22 - i * 4, ctr: "0.071", averagePosition: String(6 + i), syncedAt: nowIso, createdAt: nowIso }))).run();
|
|
2836
2897
|
db.insert(bingUrlInspections).values({ id: `${prefix}-bing-inspection`, projectId: project.id, url: root, httpCode: 200, inIndex: true, lastCrawledDate: dates.at(-2), inIndexDate: dates.at(-8), inspectedAt: nowIso, syncRunId, createdAt: nowIso, documentSize: 24120, anchorCount: 18, discoveryDate: dates[0] }).run();
|
|
2837
|
-
db.insert(gaMeasurementSyncStates).values({ projectId: project.id, acquisitionStatus: "ready", acquisitionSyncedAt: nowIso, leadStatus: "ready", leadSyncedAt: nowIso, leadAttributionScope: "landing-page", updatedAt: nowIso }).run();
|
|
2898
|
+
db.insert(gaMeasurementSyncStates).values({ projectId: project.id, acquisitionStatus: "ready", acquisitionSyncedAt: nowIso, leadStatus: "ready", leadSyncedAt: nowIso, leadAttributionScope: "landing-page", searchLandingStatus: "ready", searchLandingSyncedAt: nowIso, searchLandingAttemptedAt: nowIso, updatedAt: nowIso }).run();
|
|
2899
|
+
seedSearchLandingPages(db, { projectId: project.id, prefix, syncRunId, nowIso, now, variant });
|
|
2838
2900
|
db.insert(gaTrafficSummaries).values({ id: `${prefix}-ga-summary`, projectId: project.id, periodStart: dates[0], periodEnd: dates.at(-1), totalSessions: 1610, totalOrganicSessions: 980, totalUsers: 1214, syncedAt: nowIso, syncRunId }).run();
|
|
2839
2901
|
db.insert(gaTrafficWindowSummaries).values({ id: `${prefix}-ga-window`, projectId: project.id, windowKey: "30d", periodStart: dates[0], periodEnd: dates.at(-1), totalSessions: 1610, totalOrganicSessions: 980, totalDirectSessions: 284, totalUsers: 1214, syncedAt: nowIso, syncRunId }).run();
|
|
2840
2902
|
const inventory = variant === 0 ? summitRoofingInventory() : harborResortsInventory();
|
|
@@ -2915,7 +2977,7 @@ function demoReadOptions(db, context) {
|
|
|
2915
2977
|
ga4CredentialStore: {
|
|
2916
2978
|
getConnection: (projectName) => {
|
|
2917
2979
|
const project = [context.simple, context.portfolio].find((item) => item.name === projectName);
|
|
2918
|
-
return project ? { projectName, propertyId:
|
|
2980
|
+
return project ? { projectName, propertyId: DEMO_GA4_PROPERTY_ID, clientEmail: "sample@analytics.example", privateKey: "", createdAt: context.now.toISOString(), updatedAt: context.now.toISOString() } : void 0;
|
|
2919
2981
|
},
|
|
2920
2982
|
upsertConnection: refuseMutation,
|
|
2921
2983
|
deleteConnection: refuseMutation
|
|
@@ -2953,15 +3015,6 @@ function demoReadOptions(db, context) {
|
|
|
2953
3015
|
};
|
|
2954
3016
|
}
|
|
2955
3017
|
|
|
2956
|
-
// src/demo/types.ts
|
|
2957
|
-
function createDemoSeedContext(now = /* @__PURE__ */ new Date()) {
|
|
2958
|
-
return {
|
|
2959
|
-
now,
|
|
2960
|
-
simple: { id: "demo-project-summit", name: "summit-roofing", displayName: "Summit Roofing", domain: "summit-roofing.example" },
|
|
2961
|
-
portfolio: { id: "demo-project-harbor", name: "harbor-resorts", displayName: "Harbor Resorts", domain: "harbor-resorts.example" }
|
|
2962
|
-
};
|
|
2963
|
-
}
|
|
2964
|
-
|
|
2965
3018
|
// src/demo-server.ts
|
|
2966
3019
|
async function createDemoServer(options = {}) {
|
|
2967
3020
|
const db = createClient(":memory:");
|
package/dist/index.js
CHANGED
|
@@ -3,14 +3,14 @@ import {
|
|
|
3
3
|
createGoogleMarketingCredentialStore,
|
|
4
4
|
createGoogleMarketingRuntime,
|
|
5
5
|
createServer
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-WEKVQK3O.js";
|
|
7
7
|
import {
|
|
8
8
|
loadConfig
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
12
|
-
import "./chunk-
|
|
13
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-WVBLFG7H.js";
|
|
10
|
+
import "./chunk-QPOXDS43.js";
|
|
11
|
+
import "./chunk-RBQUGZM4.js";
|
|
12
|
+
import "./chunk-3NAZXITW.js";
|
|
13
|
+
import "./chunk-PVWGKDY6.js";
|
|
14
14
|
export {
|
|
15
15
|
GoogleMarketingRuntimeError,
|
|
16
16
|
createGoogleMarketingCredentialStore,
|
package/dist/mcp.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
autoSyncSkills
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-2MBI5SYB.js";
|
|
4
4
|
import {
|
|
5
5
|
createApiClient,
|
|
6
6
|
createCanonryMcpServer
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-WVBLFG7H.js";
|
|
8
|
+
import "./chunk-RBQUGZM4.js";
|
|
9
9
|
import {
|
|
10
10
|
isReadOnlyKey,
|
|
11
11
|
updateCheckEnvOptOut
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-PVWGKDY6.js";
|
|
13
13
|
|
|
14
14
|
// src/mcp/cli.ts
|
|
15
15
|
import { randomUUID } from "crypto";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canonry/canonry",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.17.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Self-hosted AI visibility (AEO) platform: track how ChatGPT, Claude, Gemini, and Perplexity cite your domain, join it with Search Console, GA4, server-side traffic, and paid media, and fix what you find through agent tools (CLI, REST, MCP). Local SQLite.",
|
|
6
6
|
"keywords": [
|
|
@@ -86,28 +86,28 @@
|
|
|
86
86
|
"tsup": "^8.5.1",
|
|
87
87
|
"tsx": "^4.19.0",
|
|
88
88
|
"@ainyc/canonry-api-client": "0.0.0",
|
|
89
|
+
"@ainyc/canonry-web": "0.0.0",
|
|
89
90
|
"@ainyc/canonry-api-routes": "0.0.0",
|
|
90
91
|
"@ainyc/canonry-contracts": "0.0.0",
|
|
91
|
-
"@ainyc/canonry-web": "0.0.0",
|
|
92
|
-
"@ainyc/canonry-db": "0.0.0",
|
|
93
92
|
"@ainyc/canonry-config": "0.0.0",
|
|
93
|
+
"@ainyc/canonry-db": "0.0.0",
|
|
94
94
|
"@ainyc/canonry-integration-bing": "0.0.0",
|
|
95
|
-
"@ainyc/canonry-integration-cloudflare-queue": "0.0.0",
|
|
96
95
|
"@ainyc/canonry-integration-cloudflare-worker": "0.0.0",
|
|
97
96
|
"@ainyc/canonry-integration-commoncrawl": "0.0.0",
|
|
97
|
+
"@ainyc/canonry-integration-cloud-run": "0.0.0",
|
|
98
98
|
"@ainyc/canonry-integration-google": "0.0.0",
|
|
99
|
+
"@ainyc/canonry-integration-cloudflare-queue": "0.0.0",
|
|
99
100
|
"@ainyc/canonry-integration-google-ads": "0.0.0",
|
|
100
101
|
"@ainyc/canonry-integration-google-business-profile": "0.0.0",
|
|
101
|
-
"@ainyc/canonry-integration-cloud-run": "0.0.0",
|
|
102
|
-
"@ainyc/canonry-integration-google-places": "0.0.0",
|
|
103
|
-
"@ainyc/canonry-integration-openai-ads": "0.0.0",
|
|
104
102
|
"@ainyc/canonry-integration-google-tag-manager": "0.0.0",
|
|
103
|
+
"@ainyc/canonry-integration-google-places": "0.0.0",
|
|
105
104
|
"@ainyc/canonry-integration-traffic": "0.0.0",
|
|
106
|
-
"@ainyc/canonry-integration-
|
|
107
|
-
"@ainyc/canonry-provider-cdp": "0.0.0",
|
|
105
|
+
"@ainyc/canonry-integration-openai-ads": "0.0.0",
|
|
108
106
|
"@ainyc/canonry-intelligence": "0.0.0",
|
|
107
|
+
"@ainyc/canonry-provider-cdp": "0.0.0",
|
|
109
108
|
"@ainyc/canonry-provider-claude": "0.0.0",
|
|
110
109
|
"@ainyc/canonry-provider-gemini": "0.0.0",
|
|
110
|
+
"@ainyc/canonry-integration-wordpress": "0.0.0",
|
|
111
111
|
"@ainyc/canonry-provider-local": "0.0.0",
|
|
112
112
|
"@ainyc/canonry-provider-openai": "0.0.0",
|
|
113
113
|
"@ainyc/canonry-provider-muse": "0.0.0",
|