@canonry/canonry 7.3.0 → 7.5.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.
Files changed (34) hide show
  1. package/assets/agent-workspace/skills/aero/references/orchestration.md +1 -1
  2. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +2 -1
  3. package/assets/assets/{AuditHistoryPanel-DP92khTY.js → AuditHistoryPanel-B5aLMnWE.js} +1 -1
  4. package/assets/assets/{BacklinksPage-BI_9t1iI.js → BacklinksPage-Biq1jrqe.js} +1 -1
  5. package/assets/assets/{HistoryPage-tDE6Nv0J.js → HistoryPage-CGGkAgnz.js} +1 -1
  6. package/assets/assets/MeasurementPropertyPage-BwyWGGBg.js +1 -0
  7. package/assets/assets/ProjectPage-DEnKyD3e.js +8 -0
  8. package/assets/assets/{RunsPage-Bl_c9-vA.js → RunsPage-DNBn0Rau.js} +1 -1
  9. package/assets/assets/{SettingsPage-DQ5_Q2rc.js → SettingsPage-D3m-BLuf.js} +1 -1
  10. package/assets/assets/SiteHealthSection-CPMu1l-l.js +4 -0
  11. package/assets/assets/{TrafficPage-CROectSE.js → TrafficPage-BCK_V__i.js} +3 -3
  12. package/assets/assets/{TrafficSourceDetailPage-Bthvvwg5.js → TrafficSourceDetailPage-DaCehUm8.js} +1 -1
  13. package/assets/assets/{extract-error-message-DOLCGQMa.js → extract-error-message-CqBLzzuR.js} +1 -1
  14. package/assets/assets/{index-CCOcEGdz.js → index-C2X_UARl.js} +20 -20
  15. package/assets/assets/{react-sigma_core.esm.min-TWiq-VWU.js → react-sigma_core.esm.min-BvO4SZKT.js} +1 -1
  16. package/assets/assets/v2-overview-adapter-CgDChBa5.js +1 -0
  17. package/assets/index.html +1 -1
  18. package/dist/{chunk-YQXQBFHT.js → chunk-3L7QPB37.js} +9850 -9767
  19. package/dist/{chunk-RVELNJAW.js → chunk-6Z5MRX24.js} +2 -2
  20. package/dist/{chunk-3JEUZ2K5.js → chunk-E7EWAAH3.js} +3 -3
  21. package/dist/{chunk-FWV6IIYY.js → chunk-JURAGZOO.js} +7 -6
  22. package/dist/{chunk-QND5LEAC.js → chunk-KS66E5H6.js} +2 -2
  23. package/dist/{chunk-MQPBOQUH.js → chunk-OY5QVO34.js} +7 -7
  24. package/dist/{chunk-XODXE6PT.js → chunk-ZHI2MCMD.js} +83 -32
  25. package/dist/cli.js +64 -24
  26. package/dist/{demo-server-BXABH765.js → demo-server-55M7DF3U.js} +4 -4
  27. package/dist/index.js +6 -6
  28. package/dist/{intelligence-service-EIWYQYVG.js → intelligence-service-HZSRDMFP.js} +2 -2
  29. package/dist/mcp.js +4 -4
  30. package/package.json +14 -14
  31. package/assets/assets/MeasurementPropertyPage-Y2F334Qs.js +0 -1
  32. package/assets/assets/ProjectPage-DW581TNr.js +0 -8
  33. package/assets/assets/SiteHealthSection-DdZruU72.js +0 -4
  34. package/assets/assets/v2-overview-adapter-CxmV639A.js +0 -1
package/dist/cli.js CHANGED
@@ -32,11 +32,11 @@ import {
32
32
  trackCliCommandFinished,
33
33
  trackEvent,
34
34
  waitForServerRuntimeStartup
35
- } from "./chunk-MQPBOQUH.js";
35
+ } from "./chunk-OY5QVO34.js";
36
36
  import {
37
37
  autoSyncSkills,
38
38
  formatAutoSyncNotice
39
- } from "./chunk-3JEUZ2K5.js";
39
+ } from "./chunk-E7EWAAH3.js";
40
40
  import {
41
41
  configExists,
42
42
  createApiClient,
@@ -53,13 +53,13 @@ import {
53
53
  saveConfig,
54
54
  saveConfigPatch,
55
55
  shouldPrintServeSkillsNudge
56
- } from "./chunk-RVELNJAW.js";
56
+ } from "./chunk-6Z5MRX24.js";
57
57
  import {
58
58
  DEFAULT_DEMO_TRUSTED_PROXIES,
59
59
  trustedProxiesProblem,
60
60
  trustedProxyProblem
61
61
  } from "./chunk-RB2F4D3Z.js";
62
- import "./chunk-QND5LEAC.js";
62
+ import "./chunk-KS66E5H6.js";
63
63
  import {
64
64
  CliError,
65
65
  EXIT_SYSTEM_ERROR,
@@ -71,7 +71,7 @@ import {
71
71
  runMeasurementDraftAction,
72
72
  systemError,
73
73
  usageError
74
- } from "./chunk-FWV6IIYY.js";
74
+ } from "./chunk-JURAGZOO.js";
75
75
  import {
76
76
  CLOUDFLARE_WORKER_BINDINGS,
77
77
  CLOUDFLARE_WORKER_GENERATED_MARKER,
@@ -100,7 +100,7 @@ import {
100
100
  querySnapshots,
101
101
  rawEventSamples,
102
102
  runs
103
- } from "./chunk-XODXE6PT.js";
103
+ } from "./chunk-ZHI2MCMD.js";
104
104
  import {
105
105
  AdsDeliverySnapshotStatuses,
106
106
  AdsHistoricalCampaignRollupStatuses,
@@ -127,6 +127,7 @@ import {
127
127
  RunKinds,
128
128
  RunStatuses,
129
129
  RunTriggers,
130
+ SITE_AUDIT_MAX_PAGE_LIMIT,
130
131
  TrafficEventConfidences,
131
132
  TrafficEventKinds,
132
133
  TrafficEvidenceKinds,
@@ -173,6 +174,7 @@ import {
173
174
  formatPercent,
174
175
  formatRunErrorOneLine,
175
176
  formatSignedPointDelta,
177
+ formatSiteAuditPageBudget,
176
178
  gbpNegativeReviewMaxStarsSchema,
177
179
  googleAdsMetricsWindowSchema,
178
180
  isRetiredAgentProviderId,
@@ -219,12 +221,14 @@ import {
219
221
  sentimentSummaryRequestSchema,
220
222
  shareOfVoiceLabel,
221
223
  shareOfVoiceReason,
224
+ siteAuditPageBudgetSchema,
222
225
  snapshotProviderModeSchema,
223
226
  unattributedAnswersLabel,
227
+ uncheckedSourcesLabel,
224
228
  visibilityCompareSelectionSchema,
225
229
  visibilityReportRequestSchema,
226
230
  winnabilityClassSchema
227
- } from "./chunk-YQXQBFHT.js";
231
+ } from "./chunk-3L7QPB37.js";
228
232
 
229
233
  // src/cli.ts
230
234
  import { pathToFileURL } from "url";
@@ -774,7 +778,7 @@ function parseDemoTrustedProxies(values) {
774
778
  async function demoCommand(options) {
775
779
  const { host, port } = parseDemoListenOptions(options);
776
780
  const trustProxy = parseDemoTrustedProxies(options.trustProxy);
777
- const { createDemoServer } = await import("./demo-server-BXABH765.js");
781
+ const { createDemoServer } = await import("./demo-server-55M7DF3U.js");
778
782
  const app = await createDemoServer({ trustProxy });
779
783
  let stopping = false;
780
784
  const stop = () => {
@@ -1188,7 +1192,7 @@ No DB writes performed. Re-run without --dry-run to apply.`);
1188
1192
  }
1189
1193
  }
1190
1194
  async function backfillInsightsCommand(project2, opts) {
1191
- const { IntelligenceService } = await import("./intelligence-service-EIWYQYVG.js");
1195
+ const { IntelligenceService } = await import("./intelligence-service-HZSRDMFP.js");
1192
1196
  const config = loadConfig();
1193
1197
  const db = createClient(config.database);
1194
1198
  migrate(db);
@@ -11985,6 +11989,12 @@ var METRIC_REASONS = {
11985
11989
  function unattributedText(metric) {
11986
11990
  return metric.state === "available" ? unattributedAnswersLabel(metric) : null;
11987
11991
  }
11992
+ function uncheckedText(metric) {
11993
+ return metric.state === "available" ? uncheckedSourcesLabel(metric) : null;
11994
+ }
11995
+ function metricWithNote(metric, note) {
11996
+ return `${metricText(metric)}${note ? ` \xB7 ${note}` : ""}`;
11997
+ }
11988
11998
  function metricText(metric) {
11989
11999
  if (metric.state === "unavailable") return METRIC_REASONS[metric.reason] ?? `not measured (${metric.reason})`;
11990
12000
  const percent = formatPercent(metric.value);
@@ -12012,17 +12022,21 @@ function printMeasurementProperty(response) {
12012
12022
  lines.push(`Measurement: ${response.measurement.state}${response.measurement.displayedRunId ? ` \xB7 run ${response.measurement.displayedRunId}` : ""}`);
12013
12023
  lines.push("");
12014
12024
  const mention = row ? row.mentionCoverage : response.metrics.mentionCoverage;
12015
- const unattributed = unattributedText(mention);
12016
- lines.push(`Mentioned ${metricText(mention)}${unattributed ? ` \xB7 ${unattributed}` : ""}`);
12017
- lines.push(`Cited ${metricText(row ? row.citationCoverage : response.metrics.citationCoverage)}`);
12025
+ const citation = row ? row.citationCoverage : response.metrics.citationCoverage;
12026
+ lines.push(`Mentioned ${metricWithNote(mention, unattributedText(mention))}`);
12027
+ lines.push(`Cited ${metricWithNote(citation, uncheckedText(citation))}`);
12018
12028
  if (row && row.flags > 0) lines.push(`Flagged ${row.flags} ${row.flags === 1 ? "result needs" : "results need"} review`);
12019
12029
  if (row && row.providers.length > 0) {
12030
+ const engineWidth = 14;
12031
+ const mentionWidth = 34;
12020
12032
  lines.push("");
12021
- lines.push(`${"Engine".padEnd(14)}${"Mentioned".padEnd(34)}Cited`);
12033
+ lines.push(`${"Engine".padEnd(engineWidth)}${"Mentioned".padEnd(mentionWidth)}Cited`);
12022
12034
  for (const provider of row.providers) {
12023
- lines.push(`${provider.provider.padEnd(14)}${metricText(provider.mentionCoverage).padEnd(34)}${metricText(provider.citationCoverage)}`);
12035
+ lines.push(`${provider.provider.padEnd(engineWidth)}${metricText(provider.mentionCoverage).padEnd(mentionWidth)}${metricText(provider.citationCoverage)}`);
12024
12036
  const providerUnattributed = unattributedText(provider.mentionCoverage);
12025
- if (providerUnattributed) lines.push(`${"".padEnd(14)}${providerUnattributed}`);
12037
+ if (providerUnattributed) lines.push(`${"".padEnd(engineWidth)}${providerUnattributed}`);
12038
+ const providerUnchecked = uncheckedText(provider.citationCoverage);
12039
+ if (providerUnchecked) lines.push(`${"".padEnd(engineWidth + mentionWidth)}${providerUnchecked}`);
12026
12040
  }
12027
12041
  }
12028
12042
  console.log(lines.join("\n"));
@@ -13571,7 +13585,10 @@ async function createProject(name, opts) {
13571
13585
  language: opts.language,
13572
13586
  providers: opts.providers ?? [],
13573
13587
  providerModels: opts.providerModels ?? {},
13574
- ...opts.providerDispatchModes && Object.keys(opts.providerDispatchModes).length > 0 ? { providerDispatchModes: opts.providerDispatchModes } : {}
13588
+ ...opts.providerDispatchModes && Object.keys(opts.providerDispatchModes).length > 0 ? { providerDispatchModes: opts.providerDispatchModes } : {},
13589
+ // Sent only when given: this PUT also re-runs over an existing project,
13590
+ // and an omitted budget keeps the stored one.
13591
+ ...opts.siteAuditMaxPages !== void 0 ? { siteAuditMaxPages: opts.siteAuditMaxPages } : {}
13575
13592
  });
13576
13593
  warnDroppedDispatchModes(opts.providerDispatchModes ?? {}, result);
13577
13594
  if (isMachineFormat(opts.format)) {
@@ -13655,6 +13672,9 @@ async function showProject(name, format) {
13655
13672
  const dispatchModes = Object.entries(project2.providerDispatchModes ?? {}).sort(([left], [right]) => left.localeCompare(right));
13656
13673
  console.log(` Dispatch modes: ${dispatchModes.length > 0 ? `${dispatchModes.map(([provider, mode]) => `${provider}=${mode}`).join(", ")} (scheduled sweeps; others sync)` : "(none; every provider runs sync)"}`);
13657
13674
  console.log(` Negative reviews: ${resolveNegativeReviewMaxStars(project2.negativeReviewMaxStars)} stars or fewer${project2.negativeReviewMaxStars == null ? " (default)" : ""}`);
13675
+ if (project2.siteAuditMaxPages !== void 0) {
13676
+ console.log(` Site Health page budget: ${formatSiteAuditPageBudget(project2.siteAuditMaxPages)}`);
13677
+ }
13658
13678
  console.log(` Tags: ${project2.tags.length > 0 ? project2.tags.join(", ") : "(none)"}`);
13659
13679
  const labelEntries = Object.entries(project2.labels);
13660
13680
  console.log(` Labels: ${labelEntries.length > 0 ? labelEntries.map(([k, v]) => `${k}=${v}`).join(", ") : "(none)"}`);
@@ -13738,7 +13758,10 @@ async function updateProjectSettings(name, opts) {
13738
13758
  autoExtractBacklinks: project2.autoExtractBacklinks,
13739
13759
  // Sent only when asked for: the server keeps the stored threshold when the
13740
13760
  // field is absent, so a stale read cannot overwrite a newer setting.
13741
- ...opts.negativeReviewMaxStars !== void 0 ? { negativeReviewMaxStars: opts.negativeReviewMaxStars } : {}
13761
+ ...opts.negativeReviewMaxStars !== void 0 ? { negativeReviewMaxStars: opts.negativeReviewMaxStars } : {},
13762
+ // Same for the page budget: never echoed from the read above, so an edit
13763
+ // that does not touch it cannot overwrite a newer one or send a stray null.
13764
+ ...opts.siteAuditMaxPages !== void 0 ? { siteAuditMaxPages: opts.siteAuditMaxPages } : {}
13742
13765
  });
13743
13766
  warnDroppedDispatchModes(touchesDispatch ? providerDispatchModes : project2.providerDispatchModes ?? {}, result);
13744
13767
  if (isMachineFormat(opts.format)) {
@@ -13853,7 +13876,7 @@ async function setDefaultLocation(project2, label, format) {
13853
13876
  var PROJECT_CLI_COMMANDS = [
13854
13877
  {
13855
13878
  path: ["project", "create"],
13856
- usage: "canonry project create <name> [--domain <domain>] [--owned-domain <domain>...] [--alias <name>...] [--qualified-alias <name>...] [--country <code>] [--language <lang>] [--display-name <name>] [--provider <name>...] [--provider-model provider=model...] [--dispatch-mode provider=sync|batch...] [--format json]",
13879
+ usage: "canonry project create <name> [--domain <domain>] [--owned-domain <domain>...] [--alias <name>...] [--qualified-alias <name>...] [--country <code>] [--language <lang>] [--display-name <name>] [--provider <name>...] [--provider-model provider=model...] [--dispatch-mode provider=sync|batch...] [--site-audit-max-pages <1-50000|full>] [--format json]",
13857
13880
  help: "Create a project. Pass --domain for the public site to scan. Provider credentials are not required for Page Health.",
13858
13881
  options: {
13859
13882
  domain: { type: "string", short: "d" },
@@ -13865,13 +13888,14 @@ var PROJECT_CLI_COMMANDS = [
13865
13888
  "display-name": stringOption(),
13866
13889
  provider: multiStringOption(),
13867
13890
  "provider-model": multiStringOption(),
13868
- "dispatch-mode": multiStringOption()
13891
+ "dispatch-mode": multiStringOption(),
13892
+ "site-audit-max-pages": stringOption()
13869
13893
  },
13870
13894
  run: async (input) => {
13871
13895
  const name = requireProject(
13872
13896
  input,
13873
13897
  "project.create",
13874
- "canonry project create <name> [--domain <domain>] [--owned-domain <domain>...] [--alias <name>...] [--qualified-alias <name>...] [--country <code>] [--language <lang>] [--display-name <name>] [--provider <name>...] [--provider-model provider=model...] [--dispatch-mode provider=sync|batch...] [--format json]"
13898
+ "canonry project create <name> [--domain <domain>] [--owned-domain <domain>...] [--alias <name>...] [--qualified-alias <name>...] [--country <code>] [--language <lang>] [--display-name <name>] [--provider <name>...] [--provider-model provider=model...] [--dispatch-mode provider=sync|batch...] [--site-audit-max-pages <1-50000|full>] [--format json]"
13875
13899
  );
13876
13900
  await createProject(name, {
13877
13901
  domain: getString(input.values, "domain") ?? name,
@@ -13884,13 +13908,14 @@ var PROJECT_CLI_COMMANDS = [
13884
13908
  providers: getStringArray(input.values, "provider") ?? [],
13885
13909
  providerModels: parseProviderModelAssignments(getStringArray(input.values, "provider-model")),
13886
13910
  providerDispatchModes: parseDispatchModeAssignments(getStringArray(input.values, "dispatch-mode")),
13911
+ siteAuditMaxPages: parseSiteAuditMaxPages(getString(input.values, "site-audit-max-pages"), "project.create"),
13887
13912
  format: input.format
13888
13913
  });
13889
13914
  }
13890
13915
  },
13891
13916
  {
13892
13917
  path: ["project", "update"],
13893
- usage: "canonry project update <name> [--domain <domain>] [--owned-domain <domain>...] [--add-domain <domain>...] [--remove-domain <domain>...] [--alias <name>...] [--add-alias <name>...] [--remove-alias <name>...] [--add-qualified-alias <name>...] [--remove-qualified-alias <name>...] [--country <code>] [--language <lang>] [--display-name <name>] [--provider <name>...] [--all-providers] [--provider-model provider=model...] [--clear-provider-model <provider>...] [--dispatch-mode provider=sync|batch...] [--clear-dispatch-mode <provider>...] [--negative-review-max-stars <1-4|default>] [--format json]",
13918
+ usage: "canonry project update <name> [--domain <domain>] [--owned-domain <domain>...] [--add-domain <domain>...] [--remove-domain <domain>...] [--alias <name>...] [--add-alias <name>...] [--remove-alias <name>...] [--add-qualified-alias <name>...] [--remove-qualified-alias <name>...] [--country <code>] [--language <lang>] [--display-name <name>] [--provider <name>...] [--all-providers] [--provider-model provider=model...] [--clear-provider-model <provider>...] [--dispatch-mode provider=sync|batch...] [--clear-dispatch-mode <provider>...] [--negative-review-max-stars <1-4|default>] [--site-audit-max-pages <1-50000|full>] [--format json]",
13894
13919
  options: {
13895
13920
  domain: { type: "string", short: "d" },
13896
13921
  "owned-domain": multiStringOption(),
@@ -13910,13 +13935,14 @@ var PROJECT_CLI_COMMANDS = [
13910
13935
  "clear-provider-model": multiStringOption(),
13911
13936
  "dispatch-mode": multiStringOption(),
13912
13937
  "clear-dispatch-mode": multiStringOption(),
13913
- "negative-review-max-stars": stringOption()
13938
+ "negative-review-max-stars": stringOption(),
13939
+ "site-audit-max-pages": stringOption()
13914
13940
  },
13915
13941
  run: async (input) => {
13916
13942
  const name = requireProject(
13917
13943
  input,
13918
13944
  "project.update",
13919
- "canonry project update <name> [--domain <domain>] [--owned-domain <domain>...] [--add-domain <domain>...] [--remove-domain <domain>...] [--alias <name>...] [--add-alias <name>...] [--remove-alias <name>...] [--add-qualified-alias <name>...] [--remove-qualified-alias <name>...] [--country <code>] [--language <lang>] [--display-name <name>] [--provider <name>...] [--all-providers] [--provider-model provider=model...] [--clear-provider-model <provider>...] [--dispatch-mode provider=sync|batch...] [--clear-dispatch-mode <provider>...] [--negative-review-max-stars <1-4|default>] [--format json]"
13945
+ "canonry project update <name> [--domain <domain>] [--owned-domain <domain>...] [--add-domain <domain>...] [--remove-domain <domain>...] [--alias <name>...] [--add-alias <name>...] [--remove-alias <name>...] [--add-qualified-alias <name>...] [--remove-qualified-alias <name>...] [--country <code>] [--language <lang>] [--display-name <name>] [--provider <name>...] [--all-providers] [--provider-model provider=model...] [--clear-provider-model <provider>...] [--dispatch-mode provider=sync|batch...] [--clear-dispatch-mode <provider>...] [--negative-review-max-stars <1-4|default>] [--site-audit-max-pages <1-50000|full>] [--format json]"
13920
13946
  );
13921
13947
  const providers = getStringArray(input.values, "provider");
13922
13948
  const allProviders = getBoolean(input.values, "all-providers");
@@ -13950,6 +13976,7 @@ var PROJECT_CLI_COMMANDS = [
13950
13976
  dispatchModes,
13951
13977
  clearDispatchModes,
13952
13978
  negativeReviewMaxStars: parseNegativeReviewMaxStars(getString(input.values, "negative-review-max-stars")),
13979
+ siteAuditMaxPages: parseSiteAuditMaxPages(getString(input.values, "site-audit-max-pages"), "project.update"),
13953
13980
  format: input.format
13954
13981
  });
13955
13982
  }
@@ -14101,6 +14128,19 @@ function parseNegativeReviewMaxStars(raw) {
14101
14128
  }
14102
14129
  return parsed.data;
14103
14130
  }
14131
+ function parseSiteAuditMaxPages(raw, command) {
14132
+ if (raw === void 0) return void 0;
14133
+ const value = raw.trim();
14134
+ if (value.toLowerCase() === "full") return null;
14135
+ const parsed = /^\d+$/.test(value) ? siteAuditPageBudgetSchema.safeParse(Number(value)) : void 0;
14136
+ if (!parsed?.success) {
14137
+ throw usageError(`Error: --site-audit-max-pages must be a whole number of pages from 1 to ${SITE_AUDIT_MAX_PAGE_LIMIT}, or "full" for the full site`, {
14138
+ message: `--site-audit-max-pages must be 1-${SITE_AUDIT_MAX_PAGE_LIMIT} or "full"`,
14139
+ details: { command, option: "site-audit-max-pages", value: raw }
14140
+ });
14141
+ }
14142
+ return parsed.data;
14143
+ }
14104
14144
 
14105
14145
  // src/commands/organic-evidence.ts
14106
14146
  async function showOrganicEvidence(project2, opts) {
@@ -18909,7 +18949,7 @@ var TECHNICAL_AEO_CLI_COMMANDS_BASE = [
18909
18949
  {
18910
18950
  path: ["technical-aeo", "run"],
18911
18951
  usage: "canonry technical-aeo run <project> [--sitemap-url <url>] [--max-pages <n>] [--max-edges <n>] [--max-depth <n>] [--check-dead-links] [--wait] [--format json]",
18912
- help: "Start a Site Health crawl. No answer-engine provider is required. --wait polls for up to 15 minutes. Dead-link checking is off unless --check-dead-links is set.",
18952
+ help: "Start a Site Health crawl. No answer-engine provider is required. Without --max-pages the scan uses the project's saved page budget (canonry project update <project> --site-audit-max-pages <n|full>), else the full site, up to 50,000 pages. --wait polls for up to 15 minutes, so a large full-site scan can outlast it; follow it with canonry technical-aeo progress <project> --run-id <id>. Dead-link checking is off unless --check-dead-links is set.",
18913
18953
  options: {
18914
18954
  "sitemap-url": stringOption(),
18915
18955
  limit: stringOption(),
@@ -5,11 +5,11 @@ import {
5
5
  computeFactorAverages,
6
6
  layoutSiteCrawlGraphInput,
7
7
  persistSiteCrawlGraphLayout
8
- } from "./chunk-QND5LEAC.js";
8
+ } from "./chunk-KS66E5H6.js";
9
9
  import {
10
10
  PACKAGE_VERSION,
11
11
  canonryMcpTools
12
- } from "./chunk-FWV6IIYY.js";
12
+ } from "./chunk-JURAGZOO.js";
13
13
  import {
14
14
  HISTORY_WINDOW_RUNS,
15
15
  IntelligenceService,
@@ -83,7 +83,7 @@ import {
83
83
  siteCrawlPages,
84
84
  siteCrawlSnapshots,
85
85
  trafficSources
86
- } from "./chunk-XODXE6PT.js";
86
+ } from "./chunk-ZHI2MCMD.js";
87
87
  import {
88
88
  RunKinds,
89
89
  SiteCrawlFetchStates,
@@ -112,7 +112,7 @@ import {
112
112
  roundPreservingTotal,
113
113
  siteAuditPageFactorSchema,
114
114
  wilsonInterval
115
- } from "./chunk-YQXQBFHT.js";
115
+ } from "./chunk-3L7QPB37.js";
116
116
 
117
117
  // src/demo-server.ts
118
118
  import { dirname, join as join2 } from "path";
package/dist/index.js CHANGED
@@ -3,14 +3,14 @@ import {
3
3
  createGoogleMarketingCredentialStore,
4
4
  createGoogleMarketingRuntime,
5
5
  createServer
6
- } from "./chunk-MQPBOQUH.js";
6
+ } from "./chunk-OY5QVO34.js";
7
7
  import {
8
8
  loadConfig
9
- } from "./chunk-RVELNJAW.js";
10
- import "./chunk-QND5LEAC.js";
11
- import "./chunk-FWV6IIYY.js";
12
- import "./chunk-XODXE6PT.js";
13
- import "./chunk-YQXQBFHT.js";
9
+ } from "./chunk-6Z5MRX24.js";
10
+ import "./chunk-KS66E5H6.js";
11
+ import "./chunk-JURAGZOO.js";
12
+ import "./chunk-ZHI2MCMD.js";
13
+ import "./chunk-3L7QPB37.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-XODXE6PT.js";
5
- import "./chunk-YQXQBFHT.js";
4
+ } from "./chunk-ZHI2MCMD.js";
5
+ import "./chunk-3L7QPB37.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-3JEUZ2K5.js";
3
+ } from "./chunk-E7EWAAH3.js";
4
4
  import {
5
5
  createApiClient,
6
6
  createCanonryMcpServer
7
- } from "./chunk-RVELNJAW.js";
8
- import "./chunk-FWV6IIYY.js";
7
+ } from "./chunk-6Z5MRX24.js";
8
+ import "./chunk-JURAGZOO.js";
9
9
  import {
10
10
  isReadOnlyKey,
11
11
  updateCheckEnvOptOut
12
- } from "./chunk-YQXQBFHT.js";
12
+ } from "./chunk-3L7QPB37.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.0",
3
+ "version": "7.5.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": [
@@ -87,32 +87,32 @@
87
87
  "tsx": "^4.19.0",
88
88
  "@ainyc/canonry-web": "0.0.0",
89
89
  "@ainyc/canonry-api-client": "0.0.0",
90
- "@ainyc/canonry-config": "0.0.0",
91
90
  "@ainyc/canonry-api-routes": "0.0.0",
92
- "@ainyc/canonry-contracts": "0.0.0",
91
+ "@ainyc/canonry-config": "0.0.0",
93
92
  "@ainyc/canonry-db": "0.0.0",
94
- "@ainyc/canonry-integration-bing": "0.0.0",
95
- "@ainyc/canonry-integration-cloudflare-queue": "0.0.0",
93
+ "@ainyc/canonry-contracts": "0.0.0",
96
94
  "@ainyc/canonry-integration-cloud-run": "0.0.0",
95
+ "@ainyc/canonry-integration-cloudflare-worker": "0.0.0",
96
+ "@ainyc/canonry-integration-cloudflare-queue": "0.0.0",
97
+ "@ainyc/canonry-integration-commoncrawl": "0.0.0",
97
98
  "@ainyc/canonry-integration-google": "0.0.0",
98
99
  "@ainyc/canonry-integration-google-ads": "0.0.0",
99
- "@ainyc/canonry-integration-cloudflare-worker": "0.0.0",
100
100
  "@ainyc/canonry-integration-google-business-profile": "0.0.0",
101
- "@ainyc/canonry-integration-commoncrawl": "0.0.0",
102
- "@ainyc/canonry-integration-openai-ads": "0.0.0",
103
101
  "@ainyc/canonry-integration-google-places": "0.0.0",
102
+ "@ainyc/canonry-integration-bing": "0.0.0",
104
103
  "@ainyc/canonry-integration-google-tag-manager": "0.0.0",
105
- "@ainyc/canonry-integration-wordpress": "0.0.0",
104
+ "@ainyc/canonry-integration-openai-ads": "0.0.0",
106
105
  "@ainyc/canonry-integration-traffic": "0.0.0",
107
- "@ainyc/canonry-provider-cdp": "0.0.0",
108
106
  "@ainyc/canonry-intelligence": "0.0.0",
109
- "@ainyc/canonry-provider-local": "0.0.0",
107
+ "@ainyc/canonry-integration-wordpress": "0.0.0",
108
+ "@ainyc/canonry-provider-cdp": "0.0.0",
110
109
  "@ainyc/canonry-provider-claude": "0.0.0",
110
+ "@ainyc/canonry-provider-local": "0.0.0",
111
111
  "@ainyc/canonry-provider-gemini": "0.0.0",
112
- "@ainyc/canonry-provider-perplexity": "0.0.0",
113
- "@ainyc/canonry-integration-typesafe": "0.0.0",
114
112
  "@ainyc/canonry-provider-muse": "0.0.0",
115
- "@ainyc/canonry-provider-openai": "0.0.0"
113
+ "@ainyc/canonry-provider-openai": "0.0.0",
114
+ "@ainyc/canonry-integration-typesafe": "0.0.0",
115
+ "@ainyc/canonry-provider-perplexity": "0.0.0"
116
116
  },
117
117
  "scripts": {
118
118
  "build": "pnpm run build:cli && pnpm run build:web",
@@ -1 +0,0 @@
1
- import{D as we,k as Pe,l as Ce,r as b,u as L,C as Ee,j as e,L as I}from"./vendor-tanstack-ZXXkndVj.js";import{cA as Le,cY as Me,ct as Se,cr as Ae,L as Re,cM as Te,cH as z,e4 as ke,e5 as qe,x as M,e6 as Ie,B as g,I as P,T as w,aK as ae,aL as ne,d2 as H,e7 as Ue,e8 as Be,e9 as _e,j as $e,s as Oe,f as ce}from"./index-CCOcEGdz.js";import{m as Ve,a as he,U as Ke,M as Qe,A as Fe,u as me}from"./v2-overview-adapter-CxmV639A.js";import{j as ze,o as He}from"./ChartPrimitives-CYlrwLJs.js";import{Z as De}from"./vendor-lucide-N6vOpZmh.js";import"./vendor-radix-twS1M3FF.js";import"./vendor-recharts-D-cUuLZo.js";import"./vendor-markdown-B4giJcws.js";import"./vendor-yaml-GWJz5H2G.js";const re=50,u={branded:{headline:"When they know your name",technical:"Branded queries"},"non-brand":{headline:"When they don't",technical:"Non-brand queries"}},We={plan_v1:"Setup update required",no_completed_run:"No completed measurement yet",no_population:"No queries of this type are assigned",evidence_incomplete:"Source evidence is incomplete",identity_ambiguous:Ke,not_applicable:"Not applicable for this Property"},ie={complete:{label:"Measured",tone:"positive"},partial:{label:"Partly measured",tone:"caution"},running:{label:"Measuring now",tone:"neutral"},queued:{label:"Measurement queued",tone:"neutral"},failed:{label:"Measurement failed",tone:"negative"},not_measured:{label:"Not measured",tone:"neutral"}},oe={assigned:{label:"Matches this Property",tone:"positive"},sibling:{label:"Matches another Property",tone:"caution"},ownedUnmapped:{label:"Site URL not in a Property",tone:"caution"},external:{label:"External URL",tone:"neutral"},ambiguous:{label:"Matches multiple Properties",tone:"caution"},invalid:{label:"Invalid URL",tone:"negative"}};function Ge(s){return[...s].sort((t,a)=>+(a.classification==="assigned")-+(t.classification==="assigned"))}function Ye(s){return`${s.expectedSlotId}:${s.usageEdgeId}`}function Ze({row:s}){return s.mentioned===null?e.jsxs("span",{className:"inline-flex flex-col items-start gap-0.5",children:[e.jsx(w,{tone:"neutral",children:"Not measured"}),e.jsx("span",{className:"text-xs text-muted",children:"No mention signal for this Property"})]}):e.jsx(w,{tone:s.mentioned?"positive":"neutral",children:s.mentioned?"Mentioned":"Not mentioned"})}const Je="—";function Xe({row:s}){return s.cited===null?e.jsxs("span",{className:"inline-flex flex-col items-start gap-0.5",children:[e.jsx(w,{tone:"neutral",children:"Not measured"}),e.jsx("span",{className:"text-xs text-muted",children:"Sources were not fully captured"})]}):e.jsx(w,{tone:s.cited?"positive":"neutral",children:s.cited?"Cited":"Not cited"})}function es({row:s}){return s.cited===null&&s.sources.length===0?e.jsx("p",{className:"py-2 text-sm text-secondary",children:"The sources for this answer were not fully captured, so none can be shown."}):s.sources.length===0?e.jsx("p",{className:"py-2 text-sm text-secondary",children:"This answer returned no source URLs at all."}):e.jsxs("details",{className:"mt-2","data-answer-sources":!0,children:[e.jsxs("summary",{className:"min-h-11 cursor-pointer py-3 text-sm text-secondary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-mono-400",children:[he," (",s.sources.length,")"]}),e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"evidence-table min-w-[420px]",children:[e.jsxs("caption",{className:"sr-only",children:["Source URLs for ",s.queryText]}),e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Match"}),e.jsx("th",{children:"URL"})]})}),e.jsx("tbody",{children:Ge(s.sources).map(t=>e.jsxs("tr",{children:[e.jsx("td",{children:e.jsx(w,{tone:oe[t.classification].tone,children:oe[t.classification].label})}),e.jsx("td",{children:e.jsx($e,{url:t.sourceUrl})})]},t.sourceUrl))})]})})]})}function ss({project:s,targetKey:t,row:a}){const r=L({..._e({client:M,path:{name:s},query:{targetKey:t,resultId:a.observationId}})});if(r.isPending)return e.jsx("p",{className:"py-2 text-sm text-secondary",role:"status","aria-live":"polite",children:"Loading the answer…"});if(r.isError)return e.jsx("p",{className:"py-2 text-sm text-secondary",role:"alert",children:"Could not load this answer."});const i=r.data?.answer;return i==null||i.trim()===""?e.jsx("p",{className:"py-2 text-sm text-secondary",children:"This answer was measured, but its text was not stored."}):e.jsx("div",{className:"py-2",children:e.jsx(Fe,{headingLevel:4,copyable:!0,children:i})})}function B(s){return We[s.reason]??"Not measured"}function U({metric:s,emphasis:t=!1}){if(s.state==="unavailable")return e.jsxs("span",{className:"inline-flex flex-col gap-0.5",children:[e.jsx("span",{className:t?"text-lg font-semibold text-secondary":"text-sm font-medium text-secondary",children:"Not measured"}),e.jsx("span",{className:"text-sm text-secondary",children:B(s)})]});const a=ce(s.value),r=s.numerator===void 0||s.denominator===void 0?null:`${s.numerator} of ${s.denominator}`,i=me(s);return e.jsxs("span",{className:"inline-flex flex-col gap-0.5 tabular-nums",children:[e.jsx("span",{className:t?"text-lg font-semibold text-heading":"text-sm font-medium text-primary",children:a}),r?e.jsx("span",{className:"text-xs text-muted",children:r}):null,i?e.jsx("span",{className:"text-xs text-muted",children:i}):null]})}function le(s,t,a){return Ue({client:M,path:{name:s},query:{scope:"property",targetKey:t,queryClass:a}})}function de(s){return s?.properties.items.at(0)}function ts({measuredAt:s,unmeasuredReason:t,queryClass:a}){const r=s===void 0?null:s===null?"No completed sweep yet":`Measured ${ze(He(s))}`;return r===null&&t===void 0?null:e.jsxs("p",{className:"supporting-copy",children:[[r,t].filter(Boolean).join(" · "),r!==null&&t===void 0?` · ${u[a].technical.toLocaleLowerCase()} only`:""]})}function as({project:s,groups:t}){return t.length===0?null:e.jsxs("section",{"aria-labelledby":"property-market",className:"page-section-divider",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"Competitive comparison"}),e.jsxs("h2",{id:"property-market",className:"text-base font-semibold text-heading",children:["Measured at the market level",e.jsx(P,{text:"Competitors are attached to a market rather than to a single Property, because one building has nobody to be compared against. Share of voice and competitor pressure are reported for the market this Property sits in."})]})]}),e.jsx(g,{asChild:!0,type:"button",size:"sm",variant:"outline",children:e.jsx(I,{to:"/projects/$projectName",params:{projectName:s},search:a=>z(H(a),{measurementScope:"project"}),children:"Open measurement overview"})})]}),e.jsx("ul",{className:"flex flex-wrap gap-2",children:t.map(a=>e.jsxs("li",{className:"rounded-md border border-default px-3 py-1.5 text-sm text-strong",children:[a.label,e.jsxs("span",{className:"ml-2 text-xs text-muted",children:[a.competitors.length," ",a.competitors.length===1?"competitor":"competitors"]})]},a.stableKey))})]})}function q({label:s,metric:t,failed:a=!1}){if(t===void 0)return e.jsxs("div",{className:"aeo-hero-row",children:[e.jsx("p",{className:"aeo-hero-row-label",children:s}),e.jsx("p",{className:"aeo-hero-row-value text-base font-semibold text-secondary",children:a?"Unavailable":"…"}),a?e.jsx("div",{}):e.jsx("div",{className:"aeo-hero-row-bar","aria-hidden":"true"}),e.jsx("p",{className:"aeo-hero-row-detail",children:a?"Could not be loaded":"Loading"})]});if(t.state==="unavailable"){const l=B(t);return e.jsxs("div",{className:"aeo-hero-row",children:[e.jsx("p",{className:"aeo-hero-row-label",children:s}),e.jsx("p",{className:"aeo-hero-row-value text-base font-semibold text-secondary",children:"Not measured"}),e.jsx("div",{}),e.jsx("p",{className:"aeo-hero-row-detail",children:l==="Not measured"?"":l})]})}const{figure:r,sign:i}=Oe(ce(t.value)),y=t.numerator===void 0||t.denominator===void 0?null:`${t.numerator} of ${t.denominator}`,o=me(t);return e.jsxs("div",{className:"aeo-hero-row",children:[e.jsx("p",{className:"aeo-hero-row-label",children:s}),e.jsxs("p",{className:"aeo-hero-row-value text-heading",children:[r,i?e.jsx("span",{className:"text-faint",children:i}):null]}),e.jsx("div",{className:"aeo-hero-row-bar","aria-hidden":"true",children:e.jsx("div",{className:"metric-card-bar-fill progress-fill-neutral",style:{width:`${t.value*100}%`}})}),e.jsxs("p",{className:"aeo-hero-row-detail tabular-nums",children:[y??"",o?e.jsx("span",{className:"block",children:o}):null]})]})}function ns({branded:s,nonBrand:t,brandedFailed:a=!1,nonBrandFailed:r=!1}){return e.jsxs("section",{"aria-labelledby":"property-coverage-hero",children:[e.jsx("h2",{id:"property-coverage-hero",className:"sr-only",children:"Coverage for this Property"}),e.jsxs("div",{className:"space-y-5",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"Non-brand · the demand to earn"}),e.jsx(q,{label:"Mentioned",metric:t?.mentionCoverage,failed:r}),e.jsx(q,{label:"Cited",metric:t?.citationCoverage,failed:r})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"Branded · already named"}),e.jsx(q,{label:"Mentioned",metric:s?.mentionCoverage,failed:a}),e.jsx(q,{label:"Cited",metric:s?.citationCoverage,failed:a})]})]})]})}function rs({branded:s,nonBrand:t,brandedError:a,nonBrandError:r,onRetry:i}){const y=[{queryClass:"branded",row:s,isError:a},{queryClass:"non-brand",row:t,isError:r}];return e.jsxs("section",{"aria-labelledby":"property-brand-contrast",children:[e.jsx("div",{className:"section-head section-head-inline",children:e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"The gap"}),e.jsxs("h2",{id:"property-brand-contrast",className:"text-base font-semibold text-heading",children:["Named versus not named",e.jsx(P,{text:"Branded queries already contain your name, so an answer engine has an easy path back to you. Non-brand queries describe the need instead, and that is the demand you have to earn. Each row is measured only over the queries assigned to this Property in that class; a class with no assigned query reads Not measured rather than 0%."})]})]})}),e.jsx("div",{className:"overflow-x-auto rounded-md border border-default",children:e.jsxs("table",{className:"evidence-table min-w-[560px]",children:[e.jsx("caption",{className:"sr-only",children:"Mention and citation coverage for this Property, split by query class"}),e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Query type"}),e.jsx("th",{children:"Mentioned in the answer"}),e.jsx("th",{children:"Cited as a source"})]})}),e.jsx("tbody",{children:y.map(({queryClass:o,row:l,isError:c})=>e.jsxs("tr",{children:[e.jsxs("td",{children:[e.jsx("span",{className:"block font-medium text-heading",children:u[o].headline}),e.jsx("span",{className:"mt-0.5 block text-xs text-muted",children:u[o].technical}),l&&c?e.jsxs("span",{className:"mt-2 flex flex-wrap items-center gap-2 text-sm text-caution",children:[e.jsx("span",{role:"status",children:"Refresh failed."}),e.jsxs(g,{type:"button",size:"sm",variant:"ghost",className:"h-11 px-3 text-sm md:h-11",onClick:()=>i(o),children:["Retry ",u[o].technical.toLocaleLowerCase()]})]}):null]}),l?e.jsxs(e.Fragment,{children:[e.jsx("td",{children:e.jsx(U,{metric:l.mentionCoverage,emphasis:!0})}),e.jsx("td",{children:e.jsx(U,{metric:l.citationCoverage,emphasis:!0})})]}):c?e.jsx("td",{colSpan:2,children:e.jsxs("div",{className:"flex flex-wrap items-center gap-3 text-sm text-secondary",children:[e.jsxs("span",{role:"alert",children:["Could not load ",u[o].technical.toLocaleLowerCase(),"."]}),e.jsxs(g,{type:"button",size:"sm",variant:"outline",className:"h-11 px-4 text-sm md:h-11",onClick:()=>i(o),children:["Retry ",u[o].technical.toLocaleLowerCase()]})]})}):e.jsxs(e.Fragment,{children:[e.jsx("td",{children:e.jsx("span",{className:"text-sm text-secondary",children:"Loading…"})}),e.jsx("td",{children:e.jsx("span",{className:"text-sm text-secondary",children:"Loading…"})})]})]},o))})]})})]})}function is({row:s,queryClass:t,isError:a}){return e.jsxs("section",{"aria-labelledby":"property-providers",className:"page-section-divider",children:[e.jsx("div",{className:"section-head section-head-inline",children:e.jsx("div",{children:e.jsxs("h2",{id:"property-providers",className:"text-base font-semibold text-heading",children:["Which engines answer for this Property",e.jsx(P,{text:"Each row is measured over the queries that engine actually answered for this Property, so the rows are a split of the same population rather than parts that add up to the Property total. An engine that answered nothing for this Property is absent instead of shown at 0%."})]})})}),s===void 0&&a?e.jsxs("p",{className:"text-sm text-secondary",children:["Details for ",u[t].technical.toLocaleLowerCase()," are unavailable. Retry that query type above."]}):s===void 0?e.jsx("p",{className:"text-sm text-secondary",children:"Loading…"}):s.providers.length===0?e.jsxs("p",{className:"text-sm text-secondary",children:["No answer engine has measured ",u[t].technical.toLocaleLowerCase()," for this Property.",s.mentionCoverage.state==="unavailable"?` ${B(s.mentionCoverage)}.`:""]}):e.jsx("div",{className:"overflow-x-auto rounded-md border border-default",children:e.jsxs("table",{className:"evidence-table min-w-[520px]",children:[e.jsx("caption",{className:"sr-only",children:"Per-engine mention and citation coverage"}),e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Engine"}),e.jsx("th",{children:"Mentioned"}),e.jsx("th",{children:"Cited"})]})}),e.jsx("tbody",{children:s.providers.map(r=>e.jsxs("tr",{children:[e.jsx("td",{className:"font-medium text-heading",children:r.provider}),e.jsx("td",{children:e.jsx(U,{metric:r.mentionCoverage})}),e.jsx("td",{children:e.jsx(U,{metric:r.citationCoverage})})]},r.provider))})]})})]})}function os(s){const t=s.questions.join(" · ");return s.questionsTruncated?`${t} +${s.questionTotal-s.questions.length} more`:t}function ls({project:s,targetKey:t,queryClass:a}){const r=L({...Be({client:M,path:{name:s},query:{targetKey:t,queryClass:a}})});if(r.isPending||r.isError)return null;const i=r.data?.competitors??[],y=r.data?.basis;return e.jsxs("section",{"aria-labelledby":"property-named-instead",className:"page-section-divider",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsx("div",{children:e.jsxs("h2",{id:"property-named-instead",className:"text-base font-semibold text-heading",children:["Named instead of this Property",e.jsx(P,{text:"Counted from the answers that did not name this Property, so a name here is one an engine recommended in its place. Occurrences count answers, not positions: an engine naming the same rival in two answers counts twice, and one naming it twice in a single answer counts once."})]})}),i.length>0?e.jsxs("p",{className:"supporting-copy",children:[r.data?.total??i.length," named"]}):null]}),i.length===0?e.jsx("p",{className:"text-sm text-secondary",children:"No rival was named in the answers this Property missed. Nothing to compete with here yet."}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"overflow-x-auto rounded-md border border-default",children:e.jsxs("table",{className:"evidence-table min-w-[420px]",children:[e.jsx("caption",{className:"sr-only",children:"Names the engines gave instead of this Property"}),e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Named"}),e.jsx("th",{children:"Answers"}),e.jsx("th",{children:"Engines"}),e.jsx("th",{children:"Queries"})]})}),e.jsx("tbody",{children:i.map(o=>e.jsxs("tr",{children:[e.jsx("td",{className:"text-strong",children:o.name}),e.jsx("td",{className:"tabular-nums text-secondary",children:o.occurrences}),e.jsxs("td",{className:"text-secondary",children:[o.providers.join(", "),o.providersTruncated?` +${o.providerTotal-o.providers.length}`:""]}),e.jsx("td",{className:"text-right",children:e.jsxs("span",{className:"inline-flex items-center justify-end gap-1",children:[e.jsx("span",{className:"tabular-nums text-secondary",children:o.questionTotal}),e.jsx(P,{text:os(o)})]})})]},o.name))})]})}),y?.state==="available"?e.jsxs("p",{className:"supporting-copy mt-2",children:[y.targetMissResults," of ",y.answeredResults," answers to ",u[a].technical.toLocaleLowerCase()," did not name this Property."]}):null]})]})}function ds({questions:s,queryClass:t}){return e.jsxs("section",{"aria-labelledby":"property-questions",className:"page-section-divider",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsx("div",{children:e.jsxs("h2",{id:"property-questions",className:"text-base font-semibold text-heading",children:[u[t].technical," assigned to this Property"]})}),e.jsxs("p",{className:"supporting-copy",children:[s.length," assigned"]})]}),s.length===0?e.jsxs("p",{className:"text-sm text-secondary",children:["No ",u[t].technical.toLocaleLowerCase()," are assigned. Add one in advanced measurement setup to measure this class."]}):e.jsx("div",{className:"overflow-x-auto rounded-md border border-default",children:e.jsxs("table",{className:"evidence-table min-w-[420px]",children:[e.jsx("caption",{className:"sr-only",children:"Queries assigned to this Property"}),e.jsx("thead",{children:e.jsx("tr",{children:e.jsx("th",{children:"Query"})})}),e.jsx("tbody",{children:s.map(a=>e.jsx("tr",{children:e.jsx("td",{className:"text-secondary",children:a})},a))})]})})]})}function cs({urls:s}){return e.jsxs("section",{"aria-labelledby":"property-urls",className:"page-section-divider",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsx("div",{children:e.jsxs("h2",{id:"property-urls",className:"text-base font-semibold text-heading",children:["URLs that count as this Property",e.jsx(P,{text:"A cited source URL is credited to this Property when it matches one of these. The most specific matcher wins, so a URL covered by two Properties at the same specificity is flagged for review instead of being credited to either."})]})}),e.jsxs("p",{className:"supporting-copy",children:[s.length," configured"]})]}),s.length===0?e.jsx("p",{className:"text-sm text-secondary",children:"No URLs are configured for this Property."}):e.jsx("div",{className:"overflow-x-auto rounded-md border border-default",children:e.jsxs("table",{className:"evidence-table min-w-[420px]",children:[e.jsx("caption",{className:"sr-only",children:"URL matchers configured for this Property"}),e.jsx("thead",{children:e.jsx("tr",{children:e.jsx("th",{children:"URL"})})}),e.jsx("tbody",{children:s.map(t=>e.jsx("tr",{children:e.jsx("td",{className:"break-all text-secondary",children:t})},t))})]})})]})}function hs(s,t){const a=[s.marketKey?t??"the selected market":null,s.provider?`the ${s.provider} answer engine`:null,s.model?`the ${s.model} model`:null,s.location?`location ${s.location}`:null,s.from||s.to?"a date range":null,s.measurementRunId?"a saved sweep":null].filter(r=>r!==null);return a.length===0?null:`AI Visibility is filtered to ${a.join(", ")}. This page shows the latest measurement for ${Qe.allMarkets.toLocaleLowerCase()} and answer engines.`}function Ns(){const{projectName:s,targetKey:t}=we({strict:!1}),a=Pe(),r=Ce({strict:!1}),i=b.useMemo(()=>Le(r),[r]),[y,o]=b.useState(new Set),l=s??"",c=t??"",D=!!l&&!!c,W=b.useMemo(()=>Me("portfolio",Se(Ae())),[]),S=D&&W,{canWrite:_}=Re(),C=L({...Te({client:M,path:{name:l}}),enabled:S}),G=C.data?.active?.plan,$=G?.schemaVersion===2?G:null,O=i.queryClass==="branded"||i.queryClass==="non-brand"?i.queryClass:null,Y=n=>$?.assignments.some(d=>d.targetKey===c&&d.queryClass===n)??!1,h=O??(!Y("non-brand")&&Y("branded")?"branded":"non-brand");b.useEffect(()=>{!$||O||a({to:".",replace:!0,search:n=>z(n,{queryClass:h})})},[$,O,h,a]);const v=L({...le(l,c,"branded"),enabled:S}),f=L({...le(l,c,"non-brand"),enabled:S}),V=de(v.data),K=de(f.data),j=h==="branded"?v.data:f.data,E=h==="branded"?V:K,Z=(h==="branded"?v.isError:f.isError)&&E===void 0,A=j?.measurement.displayedRunId;ke(l,{view:"property",selection:{mode:"advanced",scope:"property",scopeKey:c,queryClass:h,limit:10,...A?{runId:A}:{}}});const xe=E?.mentionCoverage.state==="unavailable"?B(E.mentionCoverage):void 0,ue=j===void 0?void 0:j.measurement.completedAt??null,R={client:M,path:{name:l},query:{targetKey:c,queryClass:h,shape:qe.answers,limit:re,...A?{runId:A}:{}}},m=Ee({...Ie(R),enabled:S&&j!==void 0,initialPageParam:R,getNextPageParam:n=>n.answers?.nextCursor?{path:R.path,query:{...R.query,cursor:n.answers.nextCursor}}:void 0}),Q=C.data?.active??null,p=Q?.plan.schemaVersion===2?Q.plan:null,pe=Q!==null&&p===null,T=p?.targets.find(n=>n.stableKey===c)??null,J=hs(i,p?.reportingScopes?.find(n=>n.stableKey===i.marketKey)?.label),je=b.useMemo(()=>{if(!p)return[];const n=new Map(p.querySnapshots.map(d=>[d.queryId,d.queryText]));return[...new Set(p.assignments.filter(d=>d.targetKey===c&&d.queryClass===h).flatMap(d=>{const x=n.get(d.queryId);return x===void 0?[]:[x]}))].sort((d,x)=>d.localeCompare(x))},[p,c,h]),ye=b.useMemo(()=>T?.urlMatchers.map(Ve)??[],[T]),be=b.useMemo(()=>p?.groups.filter(n=>n.targetKeys.includes(c))??[],[p,c]),N=b.useMemo(()=>(m.data?.pages??[]).flatMap(x=>x.answers?.items??[]),[m.data]),X=m.data?.pages[0]?.answers?.totalEstimate??N.length,ge=(m.data?.pages??[]).length>0&&(m.data?.pages??[]).every(n=>n.answers===void 0),ve=m.data?.pages[0]?.measurement.state,k=e.jsxs(I,{to:"/projects/$projectName",params:{projectName:l},search:H,className:"inline-flex items-center gap-1 text-xs text-muted hover:text-strong",children:[e.jsx(De,{className:"size-3.5","aria-hidden":"true"}),"Back to AI Visibility"]});if(!D)return e.jsx("div",{className:"page-container",children:e.jsx("p",{className:"text-sm text-muted",children:"Missing project name or Property key in URL."})});if(!W)return e.jsxs("div",{className:"page-container space-y-3",children:[k,e.jsx("p",{className:"text-sm text-muted",children:"This view is not available here."})]});if(C.isPending&&!C.isError)return e.jsx("div",{className:"page-container",children:e.jsxs("div",{role:"status","aria-live":"polite",children:[e.jsx("span",{className:"sr-only",children:"Loading Property"}),e.jsx("div",{className:"h-32 animate-pulse rounded-md bg-surface-subtle","aria-hidden":"true"})]})});const fe=C.isError&&C.data===void 0,ee=v.isError&&v.data===void 0,se=f.isError&&f.data===void 0;return fe||ee&&se?e.jsxs("div",{className:"page-container space-y-3",children:[k,e.jsx("p",{role:"alert",className:"text-sm text-negative",children:"Could not load this Property."}),e.jsx(g,{type:"button",size:"sm",variant:"outline",className:"h-11 px-4 text-sm md:h-11",onClick:()=>{C.refetch(),v.refetch(),f.refetch()},children:"Try again"})]}):!p||!T?e.jsxs("div",{className:"page-container space-y-3",children:[k,e.jsx("p",{role:"status",className:"text-sm text-secondary",children:p?"This Property is not in the published setup. It may have been renamed or removed.":"A Property page needs a published advanced measurement setup. Republish setup from the project Portfolio tab."}),e.jsx(g,{asChild:!0,type:"button",variant:"outline",className:"h-11 px-4 text-sm md:h-11",children:e.jsx(I,{to:"/projects/$projectName/portfolio",params:{projectName:l},children:_?pe?"Republish setup":"Open measurement setup":"View measurement setup"})})]}):e.jsxs("div",{className:"page-container space-y-8",children:[e.jsxs("div",{className:"page-header",children:[e.jsxs("div",{className:"page-header-left",children:[k,e.jsx("h1",{className:"page-title mt-2",children:T.label}),e.jsxs("p",{className:"page-subtitle",children:["Property in ",l,J?e.jsxs(e.Fragment,{children:[" · Filters not applied ",e.jsx(P,{text:J})]}):null]})]}),e.jsxs("div",{className:"page-header-right",children:[j?e.jsx(w,{tone:ie[j.measurement.state].tone,children:ie[j.measurement.state].label}):null,E&&E.flags>0?e.jsxs(w,{tone:"caution",children:[E.flags," flagged"]}):null]})]}),e.jsx(ns,{branded:V,nonBrand:K,brandedFailed:ee,nonBrandFailed:se}),e.jsx(rs,{branded:V,nonBrand:K,brandedError:v.isError,nonBrandError:f.isError,onRetry:n=>{n==="branded"?v.refetch():f.refetch()}}),j&&(j.measurement.state==="not_measured"||j.nextAction.kind==="run_measurement")?e.jsxs("section",{className:"flex flex-wrap items-center justify-between gap-3 border-y border-default py-4","aria-label":"Measurement next step",children:[e.jsx("p",{className:"text-sm text-secondary",children:ne()?ae:_?"Run a measurement from the project overview to collect this Property’s coverage and source evidence.":"This Property needs a new measurement before coverage and source evidence are available."}),e.jsx(g,{asChild:!0,type:"button",className:"h-11 px-4 text-sm md:h-11",children:e.jsx(I,{to:"/projects/$projectName",params:{projectName:l},search:H,children:_?"Go to AI Visibility":"View AI Visibility"})})]}):null,e.jsxs("div",{className:"flex flex-wrap items-end gap-4 border-y border-default py-4",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx("label",{htmlFor:"property-query-class",className:"block text-sm font-medium text-heading",children:"Query type"}),e.jsxs("select",{id:"property-query-class",value:h,onChange:n=>{const d=n.target.value==="branded"?"branded":"non-brand";a({to:".",search:x=>z(x,{queryClass:d})})},className:"h-11 rounded-md border border-default bg-surface px-3 text-sm text-primary focus:outline-none focus:ring-2 focus:ring-mono-400",children:[e.jsx("option",{value:"non-brand",children:u["non-brand"].technical}),e.jsx("option",{value:"branded",children:u.branded.technical})]})]}),e.jsx(ts,{measuredAt:ue,unmeasuredReason:xe,queryClass:h})]}),e.jsx(is,{row:E,queryClass:h,isError:Z}),e.jsx(ls,{project:l,targetKey:c,queryClass:h}),e.jsx(ds,{questions:je,queryClass:h}),e.jsx(cs,{urls:ye}),e.jsx(as,{project:l,groups:be}),e.jsxs("section",{"aria-labelledby":"property-evidence",className:"page-section-divider",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsx("div",{children:e.jsxs("h2",{id:"property-evidence",className:"text-base font-semibold text-heading",children:["Answers the engines gave",e.jsx(P,{text:"One row per answer an engine gave for the queries assigned to this Property in the displayed measurement. Mentioned and cited are independent: an answer can name this Property without linking it, or link it without naming it. Answers that did neither are listed first, because those are what a gap is made of. Where the answer text was not stored the mention reads Not measured, never a zero. Open a row to read what the engine actually said, followed by the source URLs it returned, this Property's own first. The answer is where a miss becomes actionable: a query this Property was not named in may still have named a sibling building."})]})}),N.length>0?e.jsxs("p",{className:"supporting-copy",children:[N.length," of ",X]}):null]}),Z?e.jsxs("p",{className:"text-sm text-secondary",children:["Evidence for ",u[h].technical.toLocaleLowerCase()," is unavailable. Retry that query type above."]}):m.isPending&&N.length===0?e.jsx("p",{className:"text-sm text-secondary",children:"Loading evidence…"}):m.isError&&N.length===0?e.jsxs("div",{className:"flex flex-wrap items-center gap-3 text-sm text-secondary",children:[e.jsx("span",{role:"alert",children:"Evidence could not be loaded."}),e.jsx(g,{type:"button",size:"sm",variant:"outline",className:"h-11 px-4 text-sm md:h-11",onClick:()=>{m.refetch()},children:"Retry evidence"})]}):ve==="not_measured"?e.jsx("p",{className:"text-sm text-secondary",children:ne()?ae:"Not measured yet. Run a measurement to collect the answers for this Property."}):ge?e.jsx("p",{role:"alert",className:"text-sm text-caution",children:"This measurement was returned in an older format, so the answers cannot be shown here. The numbers above are unaffected."}):N.length===0?e.jsx("p",{className:"text-sm text-secondary",children:"No answers matched this Property in the displayed measurement."}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"property-answer-table-container overflow-x-auto rounded-md border border-default",children:e.jsxs("table",{className:"evidence-table property-evidence-table",children:[e.jsx("caption",{className:"sr-only",children:"Answers measured for this Property"}),e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Query"}),e.jsx("th",{children:"Mentioned in the answer"}),e.jsx("th",{children:"Cited as a source"}),e.jsx("th",{children:"Sources"}),e.jsx("th",{children:e.jsx("span",{className:"sr-only",children:"Sources detail"})})]})}),e.jsx("tbody",{children:N.map(n=>{const d=Ye(n),x=y.has(d),te=`property-answer-${encodeURIComponent(d)}`;return e.jsxs(b.Fragment,{children:[e.jsxs("tr",{className:"property-answer-summary",children:[e.jsxs("td",{className:"text-secondary",children:[e.jsx("h3",{className:"text-sm font-medium text-heading",children:n.queryText}),e.jsx("span",{className:"mt-1 block text-xs text-muted",children:[n.provider,n.location].filter(Boolean).join(" · ")}),n.historical||n.bridged?e.jsx("span",{className:"mt-1 flex",children:e.jsx(w,{tone:"caution",children:"Historical"})}):null]}),e.jsxs("td",{children:[e.jsx("span",{className:"property-evidence-mobile-label","aria-hidden":"true",children:"Mentioned"}),e.jsx(Ze,{row:n})]}),e.jsxs("td",{children:[e.jsx("span",{className:"property-evidence-mobile-label","aria-hidden":"true",children:"Cited"}),e.jsx(Xe,{row:n})]}),e.jsxs("td",{className:"tabular-nums text-secondary",children:[e.jsx("span",{className:"property-evidence-mobile-label","aria-hidden":"true",children:he}),n.cited===null?Je:n.sources.length]}),e.jsx("td",{className:"text-right",children:e.jsx(g,{type:"button",size:"sm",variant:"ghost",className:"h-auto min-h-11 max-w-full whitespace-normal py-2 text-left md:h-auto","aria-expanded":x,"aria-label":x?`Hide the answer for ${n.queryText}`:`Read the answer for ${n.queryText}`,"aria-controls":x?te:void 0,onClick:()=>o(Ne=>{const F=new Set(Ne);return F.delete(d)||F.add(d),F}),children:x?"Hide answer":"Read answer"})})]}),x?e.jsx("tr",{className:"property-answer-detail",children:e.jsxs("td",{id:te,colSpan:5,className:"bg-surface-subtle px-4",children:[e.jsx(ss,{project:l,targetKey:c,row:n}),e.jsx(es,{row:n})]})}):null]},d)})})]})}),m.hasNextPage?e.jsxs("div",{className:"mt-2 flex flex-wrap items-center gap-3 text-sm text-secondary",children:[e.jsxs("span",{children:["Showing ",N.length," of ",X]}),m.isFetchNextPageError?e.jsx("span",{role:"alert",children:"Could not load more evidence."}):null,e.jsx(g,{size:"sm",variant:"outline",className:"h-11 px-4 text-sm md:h-11",disabled:m.isFetchingNextPage,onClick:()=>{m.fetchNextPage()},children:m.isFetchingNextPage?"Loading…":m.isFetchNextPageError?"Retry more evidence":`Show ${re} more`})]}):null]})]})]})}export{oe as EVIDENCE_LABELS,Ns as MeasurementPropertyPage};