@canonry/canonry 7.4.0 → 7.5.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 (31) hide show
  1. package/assets/assets/{AuditHistoryPanel-DIL5oTHF.js → AuditHistoryPanel-B5aLMnWE.js} +1 -1
  2. package/assets/assets/{BacklinksPage-BpCURZh8.js → BacklinksPage-Biq1jrqe.js} +1 -1
  3. package/assets/assets/{HistoryPage-TPbexxzA.js → HistoryPage-CGGkAgnz.js} +1 -1
  4. package/assets/assets/MeasurementPropertyPage-BwyWGGBg.js +1 -0
  5. package/assets/assets/ProjectPage-DEnKyD3e.js +8 -0
  6. package/assets/assets/{RunsPage-Dhu7Qe7B.js → RunsPage-DNBn0Rau.js} +1 -1
  7. package/assets/assets/{SettingsPage-BCG1QJ07.js → SettingsPage-D3m-BLuf.js} +1 -1
  8. package/assets/assets/{SiteHealthSection-BXueYSiu.js → SiteHealthSection-CPMu1l-l.js} +3 -3
  9. package/assets/assets/{TrafficPage-ua9wsccA.js → TrafficPage-BCK_V__i.js} +2 -2
  10. package/assets/assets/{TrafficSourceDetailPage-pwATnkp8.js → TrafficSourceDetailPage-DaCehUm8.js} +1 -1
  11. package/assets/assets/{extract-error-message-DJfNdKqh.js → extract-error-message-CqBLzzuR.js} +1 -1
  12. package/assets/assets/{index-DvWWyhGp.js → index-C2X_UARl.js} +15 -15
  13. package/assets/assets/{react-sigma_core.esm.min-DnbWY5j_.js → react-sigma_core.esm.min-BvO4SZKT.js} +1 -1
  14. package/assets/assets/v2-overview-adapter-CgDChBa5.js +1 -0
  15. package/assets/index.html +1 -1
  16. package/dist/{chunk-TNLOOXUP.js → chunk-56YOI7QX.js} +2 -2
  17. package/dist/{chunk-GEKMHZS2.js → chunk-HAWCV4SU.js} +10 -10
  18. package/dist/{chunk-SWSWCUHS.js → chunk-JTQ4KFIR.js} +64 -31
  19. package/dist/{chunk-ZP6GF32R.js → chunk-KJIXDPYH.js} +3 -3
  20. package/dist/{chunk-PXRUWG75.js → chunk-RVM6QJQT.js} +75 -8
  21. package/dist/{chunk-JU6TPMCJ.js → chunk-VVEMJCC6.js} +2 -2
  22. package/dist/{chunk-XFVJ6QVE.js → chunk-Y7K5NMNV.js} +2 -2
  23. package/dist/cli.js +26 -15
  24. package/dist/{demo-server-INMOE4BA.js → demo-server-V3DDLXND.js} +4 -4
  25. package/dist/index.js +6 -6
  26. package/dist/{intelligence-service-IBUS2IND.js → intelligence-service-MZVPWIXL.js} +2 -2
  27. package/dist/mcp.js +4 -4
  28. package/package.json +12 -12
  29. package/assets/assets/MeasurementPropertyPage-H991GW9h.js +0 -1
  30. package/assets/assets/ProjectPage-l1NAl-9k.js +0 -8
  31. package/assets/assets/v2-overview-adapter-BIOvZAlo.js +0 -1
@@ -3637,8 +3637,18 @@ var measurementMetricValueSchema = z6.discriminatedUnion("state", [
3637
3637
  * Mention coverage only: answers left out of numerator and denominator
3638
3638
  * because they could not be tied to one Property. Absent means none.
3639
3639
  */
3640
- unattributed: z6.number().int().positive().optional()
3641
- }).strict(),
3640
+ unattributed: z6.number().int().positive().optional(),
3641
+ /**
3642
+ * Citation coverage only: saved answers left out of numerator and
3643
+ * denominator because their source-link capture was incomplete. A link
3644
+ * such an answer did capture is not counted either. Absent means none.
3645
+ */
3646
+ unchecked: z6.number().int().positive().optional()
3647
+ }).strict().superRefine((value, ctx) => {
3648
+ if (value.unattributed !== void 0 && value.unchecked !== void 0) {
3649
+ ctx.addIssue({ code: "custom", path: ["unchecked"], message: "A metric reads one signal: unattributed (mention) and unchecked (citation) cannot share it" });
3650
+ }
3651
+ }),
3642
3652
  z6.object({
3643
3653
  state: z6.literal("unavailable"),
3644
3654
  reason: measurementMetricUnavailableReasonSchema
@@ -8220,7 +8230,22 @@ var visibilityReportRateSchema = z20.object({
8220
8230
  * absent means none were. When every answer is unattributable the rate is
8221
8231
  * unavailable with reason `identity-ambiguous` instead.
8222
8232
  */
8223
- unattributed: z20.number().int().positive().optional()
8233
+ unattributed: z20.number().int().positive().optional(),
8234
+ /**
8235
+ * Saved answers left out of a citation rate because their source-link
8236
+ * capture was incomplete (`citationComplete: false`). They leave the
8237
+ * numerator AND the denominator: a link that was never read is not counted as
8238
+ * not cited, and a link that was read on such an answer is not counted as
8239
+ * cited either, since counting only those positives would bias the rate up.
8240
+ * Present only on an available rate that left at least one answer out;
8241
+ * absent means none were. When every answer is unchecked the rate is
8242
+ * unavailable with reason `evidence-incomplete`, and a missing answer (no
8243
+ * saved observation) still withholds the rate that way. Never beside
8244
+ * `unattributed`: one rate reads one signal. A Simple project's citation
8245
+ * state comes from stored cited domains, not URL capture, so its rates never
8246
+ * carry this field.
8247
+ */
8248
+ unchecked: z20.number().int().positive().optional()
8224
8249
  }).strict().superRefine((value, ctx) => {
8225
8250
  const unavailable = value.numerator === null || value.denominator === null || value.rate === null;
8226
8251
  if (unavailable) {
@@ -8230,11 +8255,17 @@ var visibilityReportRateSchema = z20.object({
8230
8255
  if (value.unattributed !== void 0) {
8231
8256
  ctx.addIssue({ code: z20.ZodIssueCode.custom, path: ["unattributed"], message: "Only an available rate can leave answers out" });
8232
8257
  }
8258
+ if (value.unchecked !== void 0) {
8259
+ ctx.addIssue({ code: z20.ZodIssueCode.custom, path: ["unchecked"], message: "Only an available rate can leave answers out" });
8260
+ }
8233
8261
  return;
8234
8262
  }
8235
8263
  if (value.reason !== void 0) {
8236
8264
  ctx.addIssue({ code: z20.ZodIssueCode.custom, message: "Available rates cannot carry a reason" });
8237
8265
  }
8266
+ if (value.unattributed !== void 0 && value.unchecked !== void 0) {
8267
+ ctx.addIssue({ code: z20.ZodIssueCode.custom, path: ["unchecked"], message: "A rate reads one signal: unattributed (mention) and unchecked (citation) cannot share it" });
8268
+ }
8238
8269
  const { numerator, denominator } = value;
8239
8270
  if (denominator === null || numerator === null) return;
8240
8271
  if (denominator === 0) {
@@ -8885,7 +8916,8 @@ var measurementRateSchema = z22.union([
8885
8916
  numerator: z22.number().int().nonnegative(),
8886
8917
  denominator: z22.number().int().positive(),
8887
8918
  rate: fraction(z22.number().min(0).max(1)),
8888
- unattributed: z22.number().int().positive().optional()
8919
+ unattributed: z22.number().int().positive().optional(),
8920
+ unchecked: z22.number().int().positive().optional()
8889
8921
  }).strict(),
8890
8922
  z22.object({
8891
8923
  numerator: z22.null(),
@@ -8897,6 +8929,9 @@ var measurementRateSchema = z22.union([
8897
8929
  if (value.numerator !== null && value.numerator > value.denominator) {
8898
8930
  ctx.addIssue({ code: "custom", path: ["numerator"], message: "Rate numerator cannot exceed denominator" });
8899
8931
  }
8932
+ if (value.numerator !== null && value.unattributed !== void 0 && value.unchecked !== void 0) {
8933
+ ctx.addIssue({ code: "custom", path: ["unchecked"], message: "A rate reads one signal: unattributed (mention) and unchecked (citation) cannot share it" });
8934
+ }
8900
8935
  });
8901
8936
  var normalizedMeasurementProviderSchema = z22.string().trim().min(1).overwrite((value) => value.toLocaleLowerCase("en"));
8902
8937
  var measurementExpectedSlotV1Schema = z22.object({
@@ -19316,6 +19351,7 @@ function serializeForInlineScript(value) {
19316
19351
  // ../contracts/src/provider-errors.ts
19317
19352
  var PROVIDER_ERROR_PRIORITY = [
19318
19353
  "PROVIDER_AUTH",
19354
+ "PROVIDER_BILLING",
19319
19355
  "RATE_LIMITED",
19320
19356
  "PROVIDER_UNAVAILABLE",
19321
19357
  "TIMEOUT",
@@ -19324,13 +19360,16 @@ var PROVIDER_ERROR_PRIORITY = [
19324
19360
  "UNKNOWN"
19325
19361
  ];
19326
19362
  function classifyProviderErrorMessage(message) {
19327
- if (/\b401\b|\b403\b|unauthorized|forbidden|invalid[_ -]?api[_ -]?key|missing[_ -]?api[_ -]?key|authentication/i.test(message)) {
19363
+ const status = extractProviderHttpStatus(message);
19364
+ if (status === 401 || status === 403 || /unauthorized|forbidden|invalid[_ -]?api[_ -]?key|missing[_ -]?api[_ -]?key|api[_ -]?key[_ -]?(?:is[_ -]?)?(?:not[_ -]?valid|invalid|expired)|authentication/i.test(message)) {
19328
19365
  return "PROVIDER_AUTH";
19329
19366
  }
19330
- if (/\b429\b|rate[_ -]?limit|too many requests|quota[_ -]?exceeded/i.test(message)) {
19367
+ if (status === 402 || /payment required|credit balance|insufficient[_ -]?(?:quota|credits?|balance|funds)/i.test(message) || /exceeded your current quota/i.test(message) && !/RESOURCE_EXHAUSTED/.test(message)) {
19368
+ return "PROVIDER_BILLING";
19369
+ }
19370
+ if (status === 429 || /rate[_ -]?limit|too many requests|quota[_ -]?exceeded/i.test(message)) {
19331
19371
  return "RATE_LIMITED";
19332
19372
  }
19333
- const status = extractProviderHttpStatus(message);
19334
19373
  if (status !== void 0 && status >= 500 || /overloaded|service unavailable|bad gateway|internal server error/i.test(message)) {
19335
19374
  return "PROVIDER_UNAVAILABLE";
19336
19375
  }
@@ -20420,6 +20459,32 @@ function unattributedAnswersLabel(value) {
20420
20459
  if (value.unattributed === void 0 || value.unattributed <= 0) return null;
20421
20460
  return `${value.unattributed} of ${value.denominator + value.unattributed} answers could not be tied to one property`;
20422
20461
  }
20462
+ function uncheckedSourcesLabel(value) {
20463
+ if (value.denominator === null || value.denominator === void 0) return null;
20464
+ if (value.unchecked === void 0 || value.unchecked <= 0) return null;
20465
+ const total = value.denominator + value.unchecked;
20466
+ return `${value.unchecked} of ${total} ${total === 1 ? "answer" : "answers"} had sources that could not be checked`;
20467
+ }
20468
+
20469
+ // ../contracts/src/coverage-rate.ts
20470
+ function assertCount(name, value) {
20471
+ if (!Number.isInteger(value) || value < 0) {
20472
+ throw new RangeError(`${name} must be a non-negative integer, got ${value}`);
20473
+ }
20474
+ }
20475
+ function rateOverChecked(numerator, answers, excluded, field) {
20476
+ assertCount("numerator", numerator);
20477
+ assertCount("answers", answers);
20478
+ assertCount("excluded", excluded);
20479
+ if (excluded > answers) throw new RangeError(`excluded (${excluded}) cannot exceed answers (${answers})`);
20480
+ const denominator = answers - excluded;
20481
+ if (numerator > denominator) {
20482
+ throw new RangeError(`numerator (${numerator}) cannot exceed the ${denominator} checked answers`);
20483
+ }
20484
+ if (denominator === 0) return null;
20485
+ const rate2 = { numerator, denominator, rate: numerator / denominator };
20486
+ return excluded === 0 ? rate2 : { ...rate2, [field]: excluded };
20487
+ }
20423
20488
 
20424
20489
  export {
20425
20490
  __export,
@@ -21374,5 +21439,7 @@ export {
21374
21439
  parseTrafficAnalyticsPeriod,
21375
21440
  trafficAnalyticsResponseSchema,
21376
21441
  UNATTRIBUTED_MENTION_REASON,
21377
- unattributedAnswersLabel
21442
+ unattributedAnswersLabel,
21443
+ uncheckedSourcesLabel,
21444
+ rateOverChecked
21378
21445
  };
@@ -135,7 +135,7 @@ import {
135
135
  trafficSeriesGranularitySchema,
136
136
  visibilityCompareSelectionSchema,
137
137
  visibilityReportRequestSchema
138
- } from "./chunk-PXRUWG75.js";
138
+ } from "./chunk-RVM6QJQT.js";
139
139
 
140
140
  // src/cli-error.ts
141
141
  function isMachineFormat(format) {
@@ -2911,7 +2911,7 @@ var canonryMcpTools = [
2911
2911
  defineTool({
2912
2912
  name: "canonry_measurement_portfolio_summary",
2913
2913
  title: "Summarize measured Properties",
2914
- description: "Start here for best and worst Properties. One call returns the weakest Properties, the names answers wrote instead of them, and the domains engines cited for them. Defaults to non-brand queries; state the returned queryClass and never pool branded with non-brand. Returns at most 4 Property rows per list, the most that fit one result; a larger limit is lowered and limitNote says so. For other rows pass groupKey (one metro's weakest), or page canonry_measurement_overview. Mention (answer text names the Property) and citation (a source URL on its page) are separate: report each as numerator/denominator, with any unattributed count beside mention. Denominators count answers, one per query per engine (queries x engines = answers). Group Properties only by each row's metro and submarkets, never by label. namedInsteadInAnswerText lists names written in the answer text of answers that neither named nor cited the Property, counted by answer: they are not citations, and namedInsteadInAnswerTextTotal counts distinct names, not answers. citedDomains and weakestAnswerSources count answers citing each domain, every engine included; weakestAnswerSources pools the weakest rows plus every tied Property, each answer once, and its domainTotal counts distinct domains, not citations. weakestAnswerSources.ownDomainAnswers counts those answers that cite any of your own domains. A Property's citationCoverage counts only answers citing that Property's own page, so 0% citation does not mean your domain went uncited; use ownDomainAnswers for that. When tiedAtWeakest is set, tiedAtWeakest.count Properties share the weakest rates and the rows are the first of them by name, not a rank: report the count, tiedAtWeakest.byMetro (tied Properties per metro over the whole tie; a Property in two metros counts in both) and tiedAtWeakest.namedInstead (names written instead across the whole tie, counted by distinct answer; namedInsteadTotal is distinct names), and call the rows examples. mentionRanking.strongest/.weakest rank every Property with an available mention rate; .excluded lists the rest with reasons. markets lists every market at one level, worst-first (every metro, or a groupKey's submarkets), whatever the limit. Markets may share Properties and never sum to portfolio totals. Reads stored data only; never starts provider work.",
2914
+ description: "Start here for best and worst Properties. One call returns the weakest Properties, the names answers wrote instead of them, and the domains engines cited for them. Defaults to non-brand queries; state the returned queryClass and never pool branded with non-brand. Returns at most 4 Property rows per list, the most that fit one result; a larger limit is lowered and limitNote says so. For other rows pass groupKey (one metro's weakest), or page canonry_measurement_overview. Mention (answer text names the Property) and citation (a source URL on its page) are separate: report each as numerator/denominator, with any unattributed count beside mention and any unchecked count beside citation (saved answers whose source capture was incomplete; they are in neither side). Denominators count answers, one per query per engine (queries x engines = answers, less any unattributed or unchecked). Group Properties only by each row's metro and submarkets, never by label. namedInsteadInAnswerText lists names written in the answer text of answers that neither named nor cited the Property, counted by answer: they are not citations, and namedInsteadInAnswerTextTotal counts distinct names, not answers. citedDomains and weakestAnswerSources count answers citing each domain, every engine included; weakestAnswerSources pools the weakest rows plus every tied Property, each answer once, and its domainTotal counts distinct domains, not citations. weakestAnswerSources.ownDomainAnswers counts those answers that cite any of your own domains. A Property's citationCoverage counts only answers citing that Property's own page, so 0% citation does not mean your domain went uncited; use ownDomainAnswers for that. When tiedAtWeakest is set, tiedAtWeakest.count Properties share the weakest rates and the rows are the first of them by name, not a rank: report the count, tiedAtWeakest.byMetro (tied Properties per metro over the whole tie; a Property in two metros counts in both) and tiedAtWeakest.namedInstead (names written instead across the whole tie, counted by distinct answer; namedInsteadTotal is distinct names), and call the rows examples. mentionRanking.strongest/.weakest rank every Property with an available mention rate; .excluded lists the rest with reasons. markets lists every market at one level, worst-first (every metro, or a groupKey's submarkets), whatever the limit. Markets may share Properties and never sum to portfolio totals. Reads stored data only; never starts provider work.",
2915
2915
  access: "read",
2916
2916
  tier: "monitoring",
2917
2917
  inputSchema: measurementPortfolioSummaryInputSchema,
@@ -5,7 +5,7 @@ import {
5
5
  siteCrawlGraphNodes,
6
6
  siteCrawlPages,
7
7
  siteCrawlSnapshots
8
- } from "./chunk-SWSWCUHS.js";
8
+ } from "./chunk-JTQ4KFIR.js";
9
9
  import {
10
10
  SITE_CRAWL_GRAPH_MAX_EDGES,
11
11
  SITE_CRAWL_GRAPH_MAX_NODES,
@@ -13,7 +13,7 @@ import {
13
13
  TEMPLATE_LINK_RATIO_THRESHOLD,
14
14
  factorStatusFromScore,
15
15
  roundPreservingTotal
16
- } from "./chunk-PXRUWG75.js";
16
+ } from "./chunk-RVM6QJQT.js";
17
17
 
18
18
  // src/site-audit-factors.ts
19
19
  function recordedSharePct(factor) {
package/dist/cli.js CHANGED
@@ -32,11 +32,11 @@ import {
32
32
  trackCliCommandFinished,
33
33
  trackEvent,
34
34
  waitForServerRuntimeStartup
35
- } from "./chunk-GEKMHZS2.js";
35
+ } from "./chunk-HAWCV4SU.js";
36
36
  import {
37
37
  autoSyncSkills,
38
38
  formatAutoSyncNotice
39
- } from "./chunk-ZP6GF32R.js";
39
+ } from "./chunk-KJIXDPYH.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-TNLOOXUP.js";
56
+ } from "./chunk-56YOI7QX.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-XFVJ6QVE.js";
62
+ import "./chunk-Y7K5NMNV.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-JU6TPMCJ.js";
74
+ } from "./chunk-VVEMJCC6.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-SWSWCUHS.js";
103
+ } from "./chunk-JTQ4KFIR.js";
104
104
  import {
105
105
  AdsDeliverySnapshotStatuses,
106
106
  AdsHistoricalCampaignRollupStatuses,
@@ -224,10 +224,11 @@ import {
224
224
  siteAuditPageBudgetSchema,
225
225
  snapshotProviderModeSchema,
226
226
  unattributedAnswersLabel,
227
+ uncheckedSourcesLabel,
227
228
  visibilityCompareSelectionSchema,
228
229
  visibilityReportRequestSchema,
229
230
  winnabilityClassSchema
230
- } from "./chunk-PXRUWG75.js";
231
+ } from "./chunk-RVM6QJQT.js";
231
232
 
232
233
  // src/cli.ts
233
234
  import { pathToFileURL } from "url";
@@ -777,7 +778,7 @@ function parseDemoTrustedProxies(values) {
777
778
  async function demoCommand(options) {
778
779
  const { host, port } = parseDemoListenOptions(options);
779
780
  const trustProxy = parseDemoTrustedProxies(options.trustProxy);
780
- const { createDemoServer } = await import("./demo-server-INMOE4BA.js");
781
+ const { createDemoServer } = await import("./demo-server-V3DDLXND.js");
781
782
  const app = await createDemoServer({ trustProxy });
782
783
  let stopping = false;
783
784
  const stop = () => {
@@ -1191,7 +1192,7 @@ No DB writes performed. Re-run without --dry-run to apply.`);
1191
1192
  }
1192
1193
  }
1193
1194
  async function backfillInsightsCommand(project2, opts) {
1194
- const { IntelligenceService } = await import("./intelligence-service-IBUS2IND.js");
1195
+ const { IntelligenceService } = await import("./intelligence-service-MZVPWIXL.js");
1195
1196
  const config = loadConfig();
1196
1197
  const db = createClient(config.database);
1197
1198
  migrate(db);
@@ -11988,6 +11989,12 @@ var METRIC_REASONS = {
11988
11989
  function unattributedText(metric) {
11989
11990
  return metric.state === "available" ? unattributedAnswersLabel(metric) : null;
11990
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
+ }
11991
11998
  function metricText(metric) {
11992
11999
  if (metric.state === "unavailable") return METRIC_REASONS[metric.reason] ?? `not measured (${metric.reason})`;
11993
12000
  const percent = formatPercent(metric.value);
@@ -12015,17 +12022,21 @@ function printMeasurementProperty(response) {
12015
12022
  lines.push(`Measurement: ${response.measurement.state}${response.measurement.displayedRunId ? ` \xB7 run ${response.measurement.displayedRunId}` : ""}`);
12016
12023
  lines.push("");
12017
12024
  const mention = row ? row.mentionCoverage : response.metrics.mentionCoverage;
12018
- const unattributed = unattributedText(mention);
12019
- lines.push(`Mentioned ${metricText(mention)}${unattributed ? ` \xB7 ${unattributed}` : ""}`);
12020
- 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))}`);
12021
12028
  if (row && row.flags > 0) lines.push(`Flagged ${row.flags} ${row.flags === 1 ? "result needs" : "results need"} review`);
12022
12029
  if (row && row.providers.length > 0) {
12030
+ const engineWidth = 14;
12031
+ const mentionWidth = 34;
12023
12032
  lines.push("");
12024
- lines.push(`${"Engine".padEnd(14)}${"Mentioned".padEnd(34)}Cited`);
12033
+ lines.push(`${"Engine".padEnd(engineWidth)}${"Mentioned".padEnd(mentionWidth)}Cited`);
12025
12034
  for (const provider of row.providers) {
12026
- 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)}`);
12027
12036
  const providerUnattributed = unattributedText(provider.mentionCoverage);
12028
- 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}`);
12029
12040
  }
12030
12041
  }
12031
12042
  console.log(lines.join("\n"));
@@ -5,11 +5,11 @@ import {
5
5
  computeFactorAverages,
6
6
  layoutSiteCrawlGraphInput,
7
7
  persistSiteCrawlGraphLayout
8
- } from "./chunk-XFVJ6QVE.js";
8
+ } from "./chunk-Y7K5NMNV.js";
9
9
  import {
10
10
  PACKAGE_VERSION,
11
11
  canonryMcpTools
12
- } from "./chunk-JU6TPMCJ.js";
12
+ } from "./chunk-VVEMJCC6.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-SWSWCUHS.js";
86
+ } from "./chunk-JTQ4KFIR.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-PXRUWG75.js";
115
+ } from "./chunk-RVM6QJQT.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-GEKMHZS2.js";
6
+ } from "./chunk-HAWCV4SU.js";
7
7
  import {
8
8
  loadConfig
9
- } from "./chunk-TNLOOXUP.js";
10
- import "./chunk-XFVJ6QVE.js";
11
- import "./chunk-JU6TPMCJ.js";
12
- import "./chunk-SWSWCUHS.js";
13
- import "./chunk-PXRUWG75.js";
9
+ } from "./chunk-56YOI7QX.js";
10
+ import "./chunk-Y7K5NMNV.js";
11
+ import "./chunk-VVEMJCC6.js";
12
+ import "./chunk-JTQ4KFIR.js";
13
+ import "./chunk-RVM6QJQT.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-SWSWCUHS.js";
5
- import "./chunk-PXRUWG75.js";
4
+ } from "./chunk-JTQ4KFIR.js";
5
+ import "./chunk-RVM6QJQT.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-ZP6GF32R.js";
3
+ } from "./chunk-KJIXDPYH.js";
4
4
  import {
5
5
  createApiClient,
6
6
  createCanonryMcpServer
7
- } from "./chunk-TNLOOXUP.js";
8
- import "./chunk-JU6TPMCJ.js";
7
+ } from "./chunk-56YOI7QX.js";
8
+ import "./chunk-VVEMJCC6.js";
9
9
  import {
10
10
  isReadOnlyKey,
11
11
  updateCheckEnvOptOut
12
- } from "./chunk-PXRUWG75.js";
12
+ } from "./chunk-RVM6QJQT.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.4.0",
3
+ "version": "7.5.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": [
@@ -86,33 +86,33 @@
86
86
  "tsup": "^8.5.1",
87
87
  "tsx": "^4.19.0",
88
88
  "@ainyc/canonry-web": "0.0.0",
89
- "@ainyc/canonry-api-client": "0.0.0",
90
89
  "@ainyc/canonry-config": "0.0.0",
91
- "@ainyc/canonry-api-routes": "0.0.0",
92
90
  "@ainyc/canonry-contracts": "0.0.0",
91
+ "@ainyc/canonry-api-routes": "0.0.0",
92
+ "@ainyc/canonry-api-client": "0.0.0",
93
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",
97
96
  "@ainyc/canonry-integration-cloudflare-worker": "0.0.0",
98
97
  "@ainyc/canonry-integration-commoncrawl": "0.0.0",
98
+ "@ainyc/canonry-integration-google": "0.0.0",
99
99
  "@ainyc/canonry-integration-google-ads": "0.0.0",
100
+ "@ainyc/canonry-integration-cloudflare-queue": "0.0.0",
100
101
  "@ainyc/canonry-integration-google-business-profile": "0.0.0",
101
- "@ainyc/canonry-integration-google": "0.0.0",
102
- "@ainyc/canonry-integration-google-tag-manager": "0.0.0",
103
102
  "@ainyc/canonry-integration-google-places": "0.0.0",
103
+ "@ainyc/canonry-integration-google-tag-manager": "0.0.0",
104
104
  "@ainyc/canonry-integration-openai-ads": "0.0.0",
105
- "@ainyc/canonry-integration-traffic": "0.0.0",
106
- "@ainyc/canonry-provider-claude": "0.0.0",
107
105
  "@ainyc/canonry-integration-wordpress": "0.0.0",
106
+ "@ainyc/canonry-intelligence": "0.0.0",
107
+ "@ainyc/canonry-integration-traffic": "0.0.0",
108
108
  "@ainyc/canonry-provider-cdp": "0.0.0",
109
+ "@ainyc/canonry-provider-claude": "0.0.0",
109
110
  "@ainyc/canonry-provider-gemini": "0.0.0",
110
- "@ainyc/canonry-provider-muse": "0.0.0",
111
- "@ainyc/canonry-intelligence": "0.0.0",
112
111
  "@ainyc/canonry-provider-local": "0.0.0",
112
+ "@ainyc/canonry-provider-muse": "0.0.0",
113
113
  "@ainyc/canonry-provider-openai": "0.0.0",
114
- "@ainyc/canonry-integration-typesafe": "0.0.0",
115
- "@ainyc/canonry-provider-perplexity": "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",
@@ -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{cE as Le,d0 as Me,cx as Se,cv as Ae,L as Re,cQ as Te,cL as z,e8 as ke,e9 as qe,x as M,ea as Ie,B as g,I as P,T as w,aK as ae,aL as ne,d6 as D,eb as Ue,ec as Be,ed as _e,j as $e,s as Oe,f as ce}from"./index-DvWWyhGp.js";import{m as Ve,a as he,U as Qe,M as Ke,A as Fe,u as me}from"./v2-overview-adapter-BIOvZAlo.js";import{j as ze,o as De}from"./ChartPrimitives-CYlrwLJs.js";import{Z as He}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:Qe,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(De(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(D(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 ${Ke.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??"",H=!!l&&!!c,W=b.useMemo(()=>Me("portfolio",Se(Ae())),[]),S=H&&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),Q=de(f.data),j=h==="branded"?v.data:f.data,E=h==="branded"?V:Q,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}),K=C.data?.active??null,p=K?.plan.schemaVersion===2?K.plan:null,pe=K!==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:D,className:"inline-flex items-center gap-1 text-xs text-muted hover:text-strong",children:[e.jsx(He,{className:"size-3.5","aria-hidden":"true"}),"Back to AI Visibility"]});if(!H)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:Q,brandedFailed:ee,nonBrandFailed:se}),e.jsx(rs,{branded:V,nonBrand:Q,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:D,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};