@canonry/canonry 7.16.0 → 7.17.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.
Files changed (30) hide show
  1. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +22 -6
  2. package/assets/assets/{AuditHistoryPanel-Cl9tUvSZ.js → AuditHistoryPanel-CzjskfMX.js} +1 -1
  3. package/assets/assets/{BacklinksPage-CTeTJ9dh.js → BacklinksPage-ToENGBdp.js} +1 -1
  4. package/assets/assets/{HistoryPage-DpOoXr2P.js → HistoryPage-BZgVoYGm.js} +1 -1
  5. package/assets/assets/{MeasurementPropertyPage-DxXsgM25.js → MeasurementPropertyPage-EBI5sn-D.js} +1 -1
  6. package/assets/assets/ProjectPage-lGGjM_qj.js +8 -0
  7. package/assets/assets/{RunsPage-CfDi7I1z.js → RunsPage-CuHi8241.js} +1 -1
  8. package/assets/assets/{SettingsPage-BHDb1apK.js → SettingsPage-D0fgAoVu.js} +1 -1
  9. package/assets/assets/{SiteHealthSection-DQZyy4P_.js → SiteHealthSection-DhLxldgs.js} +3 -3
  10. package/assets/assets/{TrafficPage-DX_vN2RL.js → TrafficPage-DD65RqeR.js} +2 -2
  11. package/assets/assets/{TrafficSourceDetailPage-Cg92zrtZ.js → TrafficSourceDetailPage-CFVCj13J.js} +1 -1
  12. package/assets/assets/{extract-error-message-BKxVCbov.js → extract-error-message-D118msoE.js} +1 -1
  13. package/assets/assets/{index-DoQJETc6.js → index-DxFd1t4G.js} +26 -26
  14. package/assets/assets/{react-sigma_core.esm.min-BhqZcSgh.js → react-sigma_core.esm.min-DdlHLMEz.js} +1 -1
  15. package/assets/assets/{v2-overview-adapter-DZ5YsE_G.js → v2-overview-adapter-CoCb2aB0.js} +1 -1
  16. package/assets/index.html +1 -1
  17. package/dist/{chunk-2S7U2YHI.js → chunk-C6GWKYGE.js} +2 -2
  18. package/dist/{chunk-KDWTNI4Z.js → chunk-FK7AWV57.js} +23 -1
  19. package/dist/{chunk-6LS2R477.js → chunk-MHB23E3N.js} +103 -2
  20. package/dist/{chunk-O6XPXEN6.js → chunk-OPJCFDNR.js} +3 -3
  21. package/dist/{chunk-VWSUFTW5.js → chunk-ORA5R7QM.js} +6 -6
  22. package/dist/{chunk-3ZGBSHZ2.js → chunk-PLS4EM2Y.js} +30 -3
  23. package/dist/{chunk-SPZRSKCF.js → chunk-ZQ7C6IFA.js} +1381 -797
  24. package/dist/cli.js +124 -12
  25. package/dist/{demo-server-6OE3H2KL.js → demo-server-WQDHQG6P.js} +68 -15
  26. package/dist/index.js +6 -6
  27. package/dist/{intelligence-service-USSTKAKC.js → intelligence-service-JWZRZ6JZ.js} +2 -2
  28. package/dist/mcp.js +4 -4
  29. package/package.json +12 -12
  30. 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-VWSUFTW5.js";
36
+ } from "./chunk-ORA5R7QM.js";
37
37
  import {
38
38
  autoSyncSkills,
39
39
  formatAutoSyncNotice
40
- } from "./chunk-O6XPXEN6.js";
40
+ } from "./chunk-OPJCFDNR.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-3ZGBSHZ2.js";
57
+ } from "./chunk-PLS4EM2Y.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-2S7U2YHI.js";
63
+ import "./chunk-C6GWKYGE.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-KDWTNI4Z.js";
75
+ } from "./chunk-FK7AWV57.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-SPZRSKCF.js";
107
+ } from "./chunk-ZQ7C6IFA.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,8 @@ import {
181
182
  formatRunErrorOneLine,
182
183
  formatSignedPointDelta,
183
184
  formatSiteAuditPageBudget,
185
+ gaSearchLandingHasSearchData,
186
+ gaSearchLandingPageLabel,
184
187
  gbpNegativeReviewMaxStarsSchema,
185
188
  googleAdsMetricsWindowSchema,
186
189
  isRetiredAgentProviderId,
@@ -234,7 +237,7 @@ import {
234
237
  visibilityCompareSelectionSchema,
235
238
  visibilityReportRequestSchema,
236
239
  winnabilityClassSchema
237
- } from "./chunk-6LS2R477.js";
240
+ } from "./chunk-MHB23E3N.js";
238
241
 
239
242
  // src/cli.ts
240
243
  import { pathToFileURL } from "url";
@@ -784,7 +787,7 @@ function parseDemoTrustedProxies(values) {
784
787
  async function demoCommand(options) {
785
788
  const { host, port } = parseDemoListenOptions(options);
786
789
  const trustProxy = parseDemoTrustedProxies(options.trustProxy);
787
- const { createDemoServer } = await import("./demo-server-6OE3H2KL.js");
790
+ const { createDemoServer } = await import("./demo-server-WQDHQG6P.js");
788
791
  const app = await createDemoServer({ trustProxy });
789
792
  let stopping = false;
790
793
  const stop = () => {
@@ -1198,7 +1201,7 @@ No DB writes performed. Re-run without --dry-run to apply.`);
1198
1201
  }
1199
1202
  }
1200
1203
  async function backfillInsightsCommand(project2, opts) {
1201
- const { IntelligenceService } = await import("./intelligence-service-USSTKAKC.js");
1204
+ const { IntelligenceService } = await import("./intelligence-service-JWZRZ6JZ.js");
1202
1205
  const config = loadConfig();
1203
1206
  const db = createClient(config.database);
1204
1207
  migrate(db);
@@ -5437,8 +5440,99 @@ async function gaSync(project2, opts) {
5437
5440
  console.log(` AI rows: ${result.aiReferralCount}`);
5438
5441
  console.log(` Social rows: ${result.socialReferralCount}`);
5439
5442
  console.log(` Period: ${result.days} days${result.clamped ? ` (requested ${result.requestedDays})` : ""}`);
5443
+ const searchLanding = result.measurement.searchLandingPages;
5444
+ if (searchLanding) {
5445
+ console.log(` Search Console landing pages: ${searchLanding.status} (${searchLanding.rowCount} rows)`);
5446
+ if (searchLanding.error) console.log(` Error: ${searchLanding.error}`);
5447
+ }
5440
5448
  console.log(` Synced at: ${result.syncedAt}`);
5441
5449
  }
5450
+ var SEARCH_LANDING_NOT_AVAILABLE = "n/a";
5451
+ function searchLandingCells(metrics) {
5452
+ return [
5453
+ metrics.organicGoogleSearchClicks.toLocaleString("en-US"),
5454
+ metrics.organicGoogleSearchImpressions.toLocaleString("en-US"),
5455
+ metrics.organicGoogleSearchClickThroughRate === null ? SEARCH_LANDING_NOT_AVAILABLE : formatPercent(metrics.organicGoogleSearchClickThroughRate),
5456
+ metrics.organicGoogleSearchAveragePosition === null ? SEARCH_LANDING_NOT_AVAILABLE : metrics.organicGoogleSearchAveragePosition.toFixed(1),
5457
+ metrics.activeUsers.toLocaleString("en-US")
5458
+ ];
5459
+ }
5460
+ async function gaSearchLandingPages(project2, opts) {
5461
+ const client = getClient7();
5462
+ const params = {};
5463
+ if (opts?.window) params.window = opts.window;
5464
+ if (opts?.limit) params.limit = opts.limit;
5465
+ if (opts?.offset) params.offset = opts.offset;
5466
+ const result = await client.gaSearchLandingPages(
5467
+ project2,
5468
+ Object.keys(params).length > 0 ? params : void 0
5469
+ );
5470
+ if (opts?.format === "json") {
5471
+ console.log(JSON.stringify(result, null, 2));
5472
+ return;
5473
+ } else if (opts?.format === "jsonl") {
5474
+ emitJsonl(result.rows.map((row) => ({
5475
+ project: project2,
5476
+ window: result.window,
5477
+ windowStart: result.windowStart,
5478
+ windowEnd: result.windowEnd,
5479
+ ...row
5480
+ })));
5481
+ return;
5482
+ }
5483
+ if (result.status === "never-synced") {
5484
+ console.log(`No GA4 Search Console landing-page data for "${project2}" yet. Run "canonry ga sync ${project2}".`);
5485
+ return;
5486
+ }
5487
+ console.log(`Google organic search traffic: landing page + query string (GA4 Search Console link) for "${project2}"`);
5488
+ if (result.windowStart && result.windowEnd) {
5489
+ console.log(`Last ${result.windowDays ?? GA_SEARCH_LANDING_WINDOW_DAYS[result.window]} days: ${result.windowStart} to ${result.windowEnd}${result.timeZone ? ` (${result.timeZone})` : ""}`);
5490
+ }
5491
+ if (result.status === "unavailable") {
5492
+ console.log(`Status: unavailable. GA4 did not return Search Console data: ${result.error ?? "no reason given"}`);
5493
+ console.log(`Link Search Console to this GA4 property (GA4 Admin, Product links, Search Console links), then run "canonry ga sync ${project2}".`);
5494
+ } else if (result.status === "error") {
5495
+ console.log(`Status: the last refresh failed${result.attemptedAt ? ` (${result.attemptedAt})` : ""}: ${result.error ?? "unknown error"}`);
5496
+ }
5497
+ if (result.status !== "ready" && result.total) {
5498
+ console.log(`Showing the snapshot synced ${result.syncedAt ?? "earlier"}.`);
5499
+ }
5500
+ if (!result.total) {
5501
+ console.log("No stored snapshot.");
5502
+ return;
5503
+ }
5504
+ const headers = ["LANDING PAGE", "CLICKS", "IMPRESSIONS", "CTR", "AVG POSITION", "ACTIVE USERS"];
5505
+ const table = [
5506
+ ["Total", ...searchLandingCells(result.total)],
5507
+ ...result.rows.map((row) => [gaSearchLandingPageLabel(row.landingPage), ...searchLandingCells(row)])
5508
+ ];
5509
+ const pageWidth = Math.min(60, Math.max(headers[0].length, ...table.map((row) => row[0].length)));
5510
+ const widths = headers.map((header, index) => index === 0 ? pageWidth : Math.max(header.length, ...table.map((row) => row[index].length)));
5511
+ 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(" ")}`;
5512
+ console.log();
5513
+ console.log(line(headers));
5514
+ console.log(` ${widths.map((width) => "\u2500".repeat(width)).join(" ")}`);
5515
+ for (const row of table) console.log(line(row));
5516
+ console.log();
5517
+ if (result.rows.length > 0) {
5518
+ console.log(` Showing ${result.offset + 1}-${result.offset + result.rows.length} of ${result.totalRows} pages.`);
5519
+ } else if (result.totalRows > 0) {
5520
+ console.log(` No landing-page rows at offset ${result.offset} (${result.totalRows} stored).`);
5521
+ }
5522
+ if (!gaSearchLandingHasSearchData(result.total)) {
5523
+ console.log(" No landing pages had Google organic search traffic in this window.");
5524
+ console.log(" If the property should have some, check its Search Console link in GA4 (Admin, Product links, Search Console links).");
5525
+ }
5526
+ if (result.rowsCapped && result.reportRowCount !== null) {
5527
+ console.log(` GA4 reported ${result.reportRowCount} rows; the ${result.totalRows} with the most clicks are stored.`);
5528
+ }
5529
+ if (result.subjectToThresholding) {
5530
+ console.log(" GA4 applied thresholding to this report, so some rows may be withheld.");
5531
+ }
5532
+ if (result.status === "ready" && result.syncedAt) {
5533
+ console.log(` Synced at: ${result.syncedAt}`);
5534
+ }
5535
+ }
5442
5536
  async function gaTraffic(project2, opts) {
5443
5537
  const client = getClient7();
5444
5538
  const params = rangeParams(opts, opts?.limit ? { limit: String(opts.limit) } : void 0);
@@ -6094,13 +6188,13 @@ var GA_CLI_COMMANDS = [
6094
6188
  },
6095
6189
  {
6096
6190
  path: ["ga", "sync"],
6097
- usage: "canonry ga sync <project> [--days 30] [--only traffic|ai|social] [--format json]",
6191
+ usage: "canonry ga sync <project> [--days 30] [--only traffic|ai|social|search-landing] [--format json]",
6098
6192
  options: {
6099
6193
  days: stringOption(),
6100
6194
  only: stringOption()
6101
6195
  },
6102
6196
  run: async (input) => {
6103
- const project2 = requireProject(input, "ga.sync", "canonry ga sync <project> [--days 30] [--only traffic|ai|social] [--format json]");
6197
+ const project2 = requireProject(input, "ga.sync", "canonry ga sync <project> [--days 30] [--only traffic|ai|social|search-landing] [--format json]");
6104
6198
  const daysStr = getString(input.values, "days");
6105
6199
  const days = daysStr ? parseInt(daysStr, 10) : void 0;
6106
6200
  const only = getString(input.values, "only");
@@ -6132,6 +6226,24 @@ var GA_CLI_COMMANDS = [
6132
6226
  });
6133
6227
  }
6134
6228
  },
6229
+ {
6230
+ path: ["ga", "search-landing-pages"],
6231
+ usage: "canonry ga search-landing-pages <project> [--window 7d|28d|90d] [--limit 50] [--offset 0] [--format json|jsonl]",
6232
+ options: {
6233
+ window: stringOption(),
6234
+ limit: stringOption(),
6235
+ offset: stringOption()
6236
+ },
6237
+ run: async (input) => {
6238
+ 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]");
6239
+ await gaSearchLandingPages(project2, {
6240
+ window: getString(input.values, "window"),
6241
+ limit: getString(input.values, "limit"),
6242
+ offset: getString(input.values, "offset"),
6243
+ format: input.format
6244
+ });
6245
+ }
6246
+ },
6135
6247
  {
6136
6248
  path: ["ga", "traffic"],
6137
6249
  usage: `canonry ga traffic <project> [--limit 50] ${RANGE_USAGE} [--format json]`,
@@ -6241,7 +6353,7 @@ var GA_CLI_COMMANDS = [
6241
6353
  unknownSubcommand(input.positionals[0], {
6242
6354
  command: "ga",
6243
6355
  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"]
6356
+ 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
6357
  });
6246
6358
  }
6247
6359
  }
@@ -5,11 +5,11 @@ import {
5
5
  computeFactorAverages,
6
6
  layoutSiteCrawlGraphInput,
7
7
  persistSiteCrawlGraphLayout
8
- } from "./chunk-2S7U2YHI.js";
8
+ } from "./chunk-C6GWKYGE.js";
9
9
  import {
10
10
  PACKAGE_VERSION,
11
11
  canonryMcpTools
12
- } from "./chunk-KDWTNI4Z.js";
12
+ } from "./chunk-FK7AWV57.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-SPZRSKCF.js";
88
+ } from "./chunk-ZQ7C6IFA.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-6LS2R477.js";
117
+ } from "./chunk-MHB23E3N.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: "demo-property", clientEmail: "sample@analytics.example", privateKey: "", createdAt: context.now.toISOString(), updatedAt: context.now.toISOString() } : void 0;
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-VWSUFTW5.js";
6
+ } from "./chunk-ORA5R7QM.js";
7
7
  import {
8
8
  loadConfig
9
- } from "./chunk-3ZGBSHZ2.js";
10
- import "./chunk-2S7U2YHI.js";
11
- import "./chunk-KDWTNI4Z.js";
12
- import "./chunk-SPZRSKCF.js";
13
- import "./chunk-6LS2R477.js";
9
+ } from "./chunk-PLS4EM2Y.js";
10
+ import "./chunk-C6GWKYGE.js";
11
+ import "./chunk-FK7AWV57.js";
12
+ import "./chunk-ZQ7C6IFA.js";
13
+ import "./chunk-MHB23E3N.js";
14
14
  export {
15
15
  GoogleMarketingRuntimeError,
16
16
  createGoogleMarketingCredentialStore,
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  HISTORY_WINDOW_RUNS,
3
3
  IntelligenceService
4
- } from "./chunk-SPZRSKCF.js";
5
- import "./chunk-6LS2R477.js";
4
+ } from "./chunk-ZQ7C6IFA.js";
5
+ import "./chunk-MHB23E3N.js";
6
6
  export {
7
7
  HISTORY_WINDOW_RUNS,
8
8
  IntelligenceService
package/dist/mcp.js CHANGED
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  autoSyncSkills
3
- } from "./chunk-O6XPXEN6.js";
3
+ } from "./chunk-OPJCFDNR.js";
4
4
  import {
5
5
  createApiClient,
6
6
  createCanonryMcpServer
7
- } from "./chunk-3ZGBSHZ2.js";
8
- import "./chunk-KDWTNI4Z.js";
7
+ } from "./chunk-PLS4EM2Y.js";
8
+ import "./chunk-FK7AWV57.js";
9
9
  import {
10
10
  isReadOnlyKey,
11
11
  updateCheckEnvOptOut
12
- } from "./chunk-6LS2R477.js";
12
+ } from "./chunk-MHB23E3N.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.16.0",
3
+ "version": "7.17.1",
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": [
@@ -87,32 +87,32 @@
87
87
  "tsx": "^4.19.0",
88
88
  "@ainyc/canonry-web": "0.0.0",
89
89
  "@ainyc/canonry-api-routes": "0.0.0",
90
- "@ainyc/canonry-api-client": "0.0.0",
91
90
  "@ainyc/canonry-config": "0.0.0",
92
- "@ainyc/canonry-db": "0.0.0",
93
91
  "@ainyc/canonry-contracts": "0.0.0",
92
+ "@ainyc/canonry-api-client": "0.0.0",
93
+ "@ainyc/canonry-db": "0.0.0",
94
94
  "@ainyc/canonry-integration-bing": "0.0.0",
95
95
  "@ainyc/canonry-integration-cloud-run": "0.0.0",
96
- "@ainyc/canonry-integration-cloudflare-queue": "0.0.0",
96
+ "@ainyc/canonry-integration-commoncrawl": "0.0.0",
97
97
  "@ainyc/canonry-integration-cloudflare-worker": "0.0.0",
98
98
  "@ainyc/canonry-integration-google": "0.0.0",
99
- "@ainyc/canonry-integration-google-business-profile": "0.0.0",
99
+ "@ainyc/canonry-integration-google-ads": "0.0.0",
100
+ "@ainyc/canonry-integration-cloudflare-queue": "0.0.0",
100
101
  "@ainyc/canonry-integration-google-places": "0.0.0",
102
+ "@ainyc/canonry-integration-google-business-profile": "0.0.0",
101
103
  "@ainyc/canonry-integration-google-tag-manager": "0.0.0",
102
- "@ainyc/canonry-integration-commoncrawl": "0.0.0",
103
104
  "@ainyc/canonry-integration-openai-ads": "0.0.0",
104
105
  "@ainyc/canonry-integration-traffic": "0.0.0",
105
- "@ainyc/canonry-integration-wordpress": "0.0.0",
106
106
  "@ainyc/canonry-intelligence": "0.0.0",
107
107
  "@ainyc/canonry-provider-cdp": "0.0.0",
108
- "@ainyc/canonry-provider-gemini": "0.0.0",
109
- "@ainyc/canonry-integration-google-ads": "0.0.0",
108
+ "@ainyc/canonry-integration-wordpress": "0.0.0",
110
109
  "@ainyc/canonry-provider-claude": "0.0.0",
111
110
  "@ainyc/canonry-provider-muse": "0.0.0",
112
- "@ainyc/canonry-provider-local": "0.0.0",
111
+ "@ainyc/canonry-provider-gemini": "0.0.0",
113
112
  "@ainyc/canonry-provider-openai": "0.0.0",
114
- "@ainyc/canonry-integration-typesafe": "0.0.0",
115
- "@ainyc/canonry-provider-perplexity": "0.0.0"
113
+ "@ainyc/canonry-provider-local": "0.0.0",
114
+ "@ainyc/canonry-provider-perplexity": "0.0.0",
115
+ "@ainyc/canonry-integration-typesafe": "0.0.0"
116
116
  },
117
117
  "scripts": {
118
118
  "build": "pnpm run build:cli && pnpm run build:web",