@canonry/canonry 4.148.12 → 4.150.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 (32) hide show
  1. package/assets/assets/{AuditHistoryPanel-B382FYpJ.js → AuditHistoryPanel-CXjIBlWZ.js} +1 -1
  2. package/assets/assets/{BacklinksPage-uO5NWBJo.js → BacklinksPage-oVeQiyZ9.js} +1 -1
  3. package/assets/assets/ChartPrimitives-DXVLCdBi.js +1 -0
  4. package/assets/assets/{HistoryPage-DDxC66Rh.js → HistoryPage-B6mWz25S.js} +1 -1
  5. package/assets/assets/MeasurementPropertyPage-Wa-JWWlY.js +1 -0
  6. package/assets/assets/ProjectPage-s2Sp2gWd.js +12 -0
  7. package/assets/assets/{RunRow-BI6h4uOF.js → RunRow-ag3MckGi.js} +1 -1
  8. package/assets/assets/{RunsPage-uKBpgmHl.js → RunsPage-CQhfk-U6.js} +1 -1
  9. package/assets/assets/{SettingsPage-BhLkW7Pm.js → SettingsPage-C4LOqjjm.js} +1 -1
  10. package/assets/assets/{TrafficPage-BxElvCdW.js → TrafficPage-BrQ6ByXb.js} +1 -1
  11. package/assets/assets/TrafficSourceDetailPage-CAiCsj3u.js +1 -0
  12. package/assets/assets/{arrow-left-DF8Fd34I.js → arrow-left-CPOYDEc0.js} +1 -1
  13. package/assets/assets/{extract-error-message-Dzq_DLpk.js → extract-error-message-gHKEV_z-.js} +1 -1
  14. package/assets/assets/index-CC5bfdzz.css +1 -0
  15. package/assets/assets/{index-D2xFeORc.js → index-XkpXQYKF.js} +81 -81
  16. package/assets/assets/refresh-cw-BEX_iTPE.js +1 -0
  17. package/assets/assets/{trash-2-BEYteUBN.js → trash-2-NEiQsVBH.js} +1 -1
  18. package/assets/index.html +2 -2
  19. package/dist/{chunk-R6UQYXLG.js → chunk-BUAVO37B.js} +23 -1
  20. package/dist/{chunk-U2ETSHDL.js → chunk-CETLBKTX.js} +79 -58
  21. package/dist/{chunk-HWK2JSV3.js → chunk-GJOACSPY.js} +52 -9
  22. package/dist/{chunk-B4JACCYB.js → chunk-TS3AHKZG.js} +2 -2
  23. package/dist/cli.js +4 -4
  24. package/dist/index.js +4 -4
  25. package/dist/{intelligence-service-M6QKJWT7.js → intelligence-service-CEEBCERV.js} +2 -2
  26. package/dist/mcp.js +2 -2
  27. package/package.json +6 -6
  28. package/assets/assets/ChartPrimitives-Ca6KRJrN.js +0 -1
  29. package/assets/assets/MeasurementPropertyPage-oWfYibAk.js +0 -1
  30. package/assets/assets/ProjectPage-D9xsYkED.js +0 -12
  31. package/assets/assets/TrafficSourceDetailPage-Fh4-7TUe.js +0 -1
  32. package/assets/assets/index-D5NO3NEG.css +0 -1
@@ -0,0 +1 @@
1
+ import{c as e}from"./index-XkpXQYKF.js";const o=[["path",{d:"m15 18-6-6 6-6",key:"1wnfg3"}]],a=e("chevron-left",o);const t=[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]],h=e("refresh-cw",t);export{a as C,h as R};
@@ -1 +1 @@
1
- import{c as a}from"./index-D2xFeORc.js";const t=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3",key:"1u773s"}],["path",{d:"M12 17h.01",key:"p32p05"}]],h=a("circle-question-mark",t);const e=[["path",{d:"M12 15V3",key:"m9g1x1"}],["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["path",{d:"m7 10 5 5 5-5",key:"brsn70"}]],d=a("download",e);const o=[["path",{d:"M15 3h6v6",key:"1q9fwt"}],["path",{d:"M10 14 21 3",key:"gplh6r"}],["path",{d:"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",key:"a6xqqp"}]],p=a("external-link",o);const c=[["path",{d:"M10 11v6",key:"nco0om"}],["path",{d:"M14 11v6",key:"outv1u"}],["path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6",key:"miytrc"}],["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2",key:"e791ji"}]],s=a("trash-2",c);export{h as C,d as D,p as E,s as T};
1
+ import{c as a}from"./index-XkpXQYKF.js";const t=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3",key:"1u773s"}],["path",{d:"M12 17h.01",key:"p32p05"}]],h=a("circle-question-mark",t);const e=[["path",{d:"M12 15V3",key:"m9g1x1"}],["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["path",{d:"m7 10 5 5 5-5",key:"brsn70"}]],d=a("download",e);const o=[["path",{d:"M15 3h6v6",key:"1q9fwt"}],["path",{d:"M10 14 21 3",key:"gplh6r"}],["path",{d:"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",key:"a6xqqp"}]],p=a("external-link",o);const c=[["path",{d:"M10 11v6",key:"nco0om"}],["path",{d:"M14 11v6",key:"outv1u"}],["path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6",key:"miytrc"}],["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2",key:"e791ji"}]],s=a("trash-2",c);export{h as C,d as D,p as E,s as T};
package/assets/index.html CHANGED
@@ -12,12 +12,12 @@
12
12
  <link rel="icon" type="image/png" sizes="32x32" href="./favicon-32.png" />
13
13
  <link rel="apple-touch-icon" href="./apple-touch-icon.png" />
14
14
  <title>Canonry</title>
15
- <script type="module" crossorigin src="./assets/index-D2xFeORc.js"></script>
15
+ <script type="module" crossorigin src="./assets/index-XkpXQYKF.js"></script>
16
16
  <link rel="modulepreload" crossorigin href="./assets/vendor-tanstack-BjS7iY3g.js">
17
17
  <link rel="modulepreload" crossorigin href="./assets/vendor-radix-DnzzbllM.js">
18
18
  <link rel="modulepreload" crossorigin href="./assets/vendor-recharts-33ACLxsD.js">
19
19
  <link rel="modulepreload" crossorigin href="./assets/vendor-markdown-CpDJch4G.js">
20
- <link rel="stylesheet" crossorigin href="./assets/index-D5NO3NEG.css">
20
+ <link rel="stylesheet" crossorigin href="./assets/index-CC5bfdzz.css">
21
21
  </head>
22
22
  <body>
23
23
  <div id="root"></div>
@@ -5995,6 +5995,14 @@ var measurementPortfolioWeakestPropertySchema = measurementDemoPropertySchema.ex
5995
5995
  ctx.addIssue({ code: z13.ZodIssueCode.custom, path: ["recommendedInsteadTruncated"], message: "Truncation must agree with the replacement total" });
5996
5996
  }
5997
5997
  });
5998
+ var measurementPortfolioMarketSchema = z13.object({
5999
+ groupKey: measurementV2StableKeySchema,
6000
+ label: measurementDemoLabelSchema,
6001
+ propertyCount: measurementDemoCountSchema,
6002
+ propertiesMentioned: measurementMetricValueSchema,
6003
+ mentionCoverage: measurementMetricValueSchema,
6004
+ citationCoverage: measurementMetricValueSchema
6005
+ }).strict();
5998
6006
  var measurementPortfolioSummaryResponseSchema = z13.object({
5999
6007
  /** A null group key means no named reporting group; spot checks may still narrow the effective Property set. */
6000
6008
  portfolio: z13.object({
@@ -6010,6 +6018,12 @@ var measurementPortfolioSummaryResponseSchema = z13.object({
6010
6018
  citationCoverage: measurementMetricValueSchema
6011
6019
  }).strict(),
6012
6020
  weakestProperties: z13.array(measurementPortfolioWeakestPropertySchema),
6021
+ /**
6022
+ * Every named market, worst-first. Empty when the request already narrowed to
6023
+ * one group (a roll-up would only restate the scope) and when the plan defines
6024
+ * no groups. Additive field.
6025
+ */
6026
+ markets: z13.array(measurementPortfolioMarketSchema),
6013
6027
  totalProperties: measurementDemoCountSchema,
6014
6028
  truncated: z13.boolean()
6015
6029
  }).strict();
@@ -13793,6 +13807,12 @@ function isGhostTelemetryEvent(eventName, properties) {
13793
13807
  return GHOST_TELEMETRY_TEST_LOCATIONS.has(location);
13794
13808
  }
13795
13809
 
13810
+ // ../contracts/src/trend-stability.ts
13811
+ var MIN_TREND_POINTS = 4;
13812
+ function isTrendBaseline(points) {
13813
+ return points.length < MIN_TREND_POINTS;
13814
+ }
13815
+
13796
13816
  export {
13797
13817
  __export,
13798
13818
  apiKeyDtoSchema,
@@ -14368,5 +14388,7 @@ export {
14368
14388
  bucketOnboardingCount,
14369
14389
  onboardingTelemetryEventSchema,
14370
14390
  telemetryEventAcceptedDtoSchema,
14371
- isGhostTelemetryEvent
14391
+ isGhostTelemetryEvent,
14392
+ MIN_TREND_POINTS,
14393
+ isTrendBaseline
14372
14394
  };
@@ -10,7 +10,7 @@ import {
10
10
  loadConfig,
11
11
  loadConfigRaw,
12
12
  saveConfigPatch
13
- } from "./chunk-B4JACCYB.js";
13
+ } from "./chunk-TS3AHKZG.js";
14
14
  import {
15
15
  CC_CACHE_DIR,
16
16
  DUCKDB_SPEC,
@@ -126,7 +126,7 @@ import {
126
126
  siteAuditSnapshots,
127
127
  toAlertView,
128
128
  usageCounters
129
- } from "./chunk-HWK2JSV3.js";
129
+ } from "./chunk-GJOACSPY.js";
130
130
  import {
131
131
  AGENT_MEMORY_VALUE_MAX_BYTES,
132
132
  AGENT_PROVIDER_IDS,
@@ -218,7 +218,7 @@ import {
218
218
  validationError,
219
219
  winnabilityClassLabel,
220
220
  withRetry
221
- } from "./chunk-R6UQYXLG.js";
221
+ } from "./chunk-BUAVO37B.js";
222
222
 
223
223
  // src/telemetry.ts
224
224
  import crypto from "crypto";
@@ -5674,6 +5674,7 @@ async function inspectUrlsPaced(urls, cb, deps = {}) {
5674
5674
  const sleep3 = deps.sleep ?? defaultSleep;
5675
5675
  const jitter = deps.jitter ?? Math.random;
5676
5676
  const concurrency = Math.max(1, Math.min(deps.concurrency ?? INSPECT_MAX_CONCURRENCY, urls.length || 1));
5677
+ const isRetryable = deps.isRetryable ?? isRetryableGscInspectError;
5677
5678
  let inspected = 0;
5678
5679
  let errors = 0;
5679
5680
  let consecutiveRetryableFailures = 0;
@@ -5699,7 +5700,7 @@ async function inspectUrlsPaced(urls, cb, deps = {}) {
5699
5700
  maxRetries: INSPECT_MAX_RETRIES,
5700
5701
  baseDelayMs: INSPECT_BASE_DELAY_MS,
5701
5702
  maxDelayMs: INSPECT_MAX_BACKOFF_MS,
5702
- isRetryable: isRetryableGscInspectError,
5703
+ isRetryable,
5703
5704
  sleep: sleep3,
5704
5705
  onRetry: ({ attempt, delayMs, err }) => deps.log?.info("inspect.retry", {
5705
5706
  url,
@@ -5714,7 +5715,7 @@ async function inspectUrlsPaced(urls, cb, deps = {}) {
5714
5715
  } catch (err) {
5715
5716
  errors++;
5716
5717
  cb.onError(url, err, index);
5717
- if (isRetryableGscInspectError(err)) {
5718
+ if (isRetryable(err)) {
5718
5719
  consecutiveRetryableFailures++;
5719
5720
  if (consecutiveRetryableFailures >= INSPECT_FAILFAST_THRESHOLD) {
5720
5721
  deps.log?.error("inspect.circuit-break", {
@@ -5918,61 +5919,81 @@ async function executeBingInspectSitemap(db, runId, projectId, opts) {
5918
5919
  });
5919
5920
  blockedUrls = /* @__PURE__ */ new Set();
5920
5921
  }
5922
+ const skipped = Math.max(0, sitemapUrls.length - INSPECT_SWEEP_MAX_URLS);
5923
+ const targetUrls = skipped > 0 ? sitemapUrls.slice(0, INSPECT_SWEEP_MAX_URLS) : sitemapUrls;
5924
+ if (skipped > 0) {
5925
+ log7.warn("sitemap.over-budget", {
5926
+ runId,
5927
+ projectId,
5928
+ sitemapUrls: sitemapUrls.length,
5929
+ inspecting: targetUrls.length,
5930
+ skipped,
5931
+ dailyQuota: INSPECT_DAILY_QUOTA,
5932
+ note: `Sitemap has ${sitemapUrls.length} pages; inspecting the first ${targetUrls.length}. ${skipped} pages will not have a verdict from this run.`
5933
+ });
5934
+ }
5935
+ const siteUrl = conn.siteUrl;
5921
5936
  let inspected = 0;
5922
5937
  let errors = 0;
5923
- for (const pageUrl of sitemapUrls) {
5924
- try {
5925
- const result = await getUrlInfo(conn.apiKey, conn.siteUrl, pageUrl);
5926
- const inspectedAt = (/* @__PURE__ */ new Date()).toISOString();
5927
- const httpCode = result.HttpStatus ?? result.HttpCode ?? null;
5928
- const lastCrawledDate = parseBingDate(result.LastCrawledDate);
5929
- const inIndexDate = parseBingDate(result.InIndexDate);
5930
- const discoveryDate = parseBingDate(result.DiscoveryDate);
5931
- let derivedInIndex = null;
5932
- if (result.DocumentSize != null && result.DocumentSize > 0) {
5933
- derivedInIndex = true;
5934
- } else if (lastCrawledDate != null) {
5935
- derivedInIndex = httpCode != null && httpCode >= 400 ? false : true;
5936
- } else if (discoveryDate != null) {
5937
- derivedInIndex = false;
5938
- }
5939
- if (derivedInIndex === true && blockedUrls.has(pageUrl)) {
5940
- derivedInIndex = false;
5938
+ const outcome = await inspectUrlsPaced(
5939
+ targetUrls,
5940
+ {
5941
+ inspectOne: (pageUrl) => getUrlInfo(conn.apiKey, siteUrl, pageUrl),
5942
+ onResult: (pageUrl, result) => {
5943
+ const inspectedAt = (/* @__PURE__ */ new Date()).toISOString();
5944
+ const httpCode = result.HttpStatus ?? result.HttpCode ?? null;
5945
+ const lastCrawledDate = parseBingDate(result.LastCrawledDate);
5946
+ const inIndexDate = parseBingDate(result.InIndexDate);
5947
+ const discoveryDate = parseBingDate(result.DiscoveryDate);
5948
+ let derivedInIndex = null;
5949
+ if (result.DocumentSize != null && result.DocumentSize > 0) {
5950
+ derivedInIndex = true;
5951
+ } else if (lastCrawledDate != null) {
5952
+ derivedInIndex = httpCode != null && httpCode >= 400 ? false : true;
5953
+ } else if (discoveryDate != null) {
5954
+ derivedInIndex = false;
5955
+ }
5956
+ if (derivedInIndex === true && blockedUrls.has(pageUrl)) {
5957
+ derivedInIndex = false;
5958
+ }
5959
+ db.insert(bingUrlInspections).values({
5960
+ id: crypto10.randomUUID(),
5961
+ projectId,
5962
+ url: pageUrl,
5963
+ httpCode,
5964
+ inIndex: derivedInIndex,
5965
+ lastCrawledDate,
5966
+ inIndexDate,
5967
+ inspectedAt,
5968
+ syncRunId: runId,
5969
+ createdAt: inspectedAt,
5970
+ documentSize: result.DocumentSize ?? null,
5971
+ anchorCount: result.AnchorCount ?? null,
5972
+ discoveryDate
5973
+ }).run();
5974
+ inspected++;
5975
+ log7.info("inspect.url-done", { runId, projectId, url: pageUrl, progress: `${inspected}/${targetUrls.length}` });
5976
+ },
5977
+ onError: (pageUrl, err) => {
5978
+ errors++;
5979
+ log7.error("inspect.url-failed", {
5980
+ runId,
5981
+ projectId,
5982
+ url: pageUrl,
5983
+ error: err instanceof Error ? err.message : String(err)
5984
+ });
5941
5985
  }
5942
- db.insert(bingUrlInspections).values({
5943
- id: crypto10.randomUUID(),
5944
- projectId,
5945
- url: pageUrl,
5946
- httpCode,
5947
- inIndex: derivedInIndex,
5948
- lastCrawledDate,
5949
- inIndexDate,
5950
- inspectedAt,
5951
- syncRunId: runId,
5952
- createdAt: inspectedAt,
5953
- documentSize: result.DocumentSize ?? null,
5954
- anchorCount: result.AnchorCount ?? null,
5955
- discoveryDate
5956
- }).run();
5957
- inspected++;
5958
- log7.info("inspect.url-done", {
5959
- runId,
5960
- projectId,
5961
- url: pageUrl,
5962
- progress: `${inspected}/${sitemapUrls.length}`
5963
- });
5964
- } catch (err) {
5965
- errors++;
5966
- log7.error("inspect.url-failed", {
5967
- runId,
5968
- projectId,
5969
- url: pageUrl,
5970
- error: err instanceof Error ? err.message : String(err)
5971
- });
5972
- }
5973
- if (inspected + errors < sitemapUrls.length) {
5974
- await new Promise((r) => setTimeout(r, 1e3));
5975
- }
5986
+ },
5987
+ { isRetryable: isRetryableHttpError, concurrency: 1, log: log7, ...opts.pacedDeps }
5988
+ );
5989
+ if (outcome.aborted) {
5990
+ log7.error("inspect.circuit-break", {
5991
+ runId,
5992
+ projectId,
5993
+ inspected,
5994
+ errors,
5995
+ note: "Bing inspection stopped early after sustained failures; the remaining pages were not attempted."
5996
+ });
5976
5997
  }
5977
5998
  const allInspections = db.select().from(bingUrlInspections).where(eq8(bingUrlInspections.projectId, projectId)).orderBy(desc3(bingUrlInspections.inspectedAt)).all();
5978
5999
  const latestByUrl = /* @__PURE__ */ new Map();
@@ -7411,7 +7432,7 @@ function readStoredGroundingSources(rawResponse) {
7411
7432
  return result;
7412
7433
  }
7413
7434
  async function backfillInsightsCommand(project, opts) {
7414
- const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-M6QKJWT7.js");
7435
+ const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-CEEBCERV.js");
7415
7436
  const config = loadConfig();
7416
7437
  const db = createClient(config.database);
7417
7438
  migrate(db);
@@ -61,6 +61,7 @@ import {
61
61
  MEASUREMENT_PAGE_MAX_LIMIT,
62
62
  MEASUREMENT_PLAN_V2_SCHEMA_VERSION,
63
63
  MIN_DOMAIN_BRAND_KEY_LENGTH,
64
+ MIN_TREND_POINTS,
64
65
  MODEL_ATTRIBUTION_EVENT_LIMIT,
65
66
  MeasurementEvidenceShapes,
66
67
  MeasurementPlanValidationError,
@@ -290,6 +291,7 @@ import {
290
291
  isBrowserProvider,
291
292
  isReadOnlyKey,
292
293
  isRetryableHttpError,
294
+ isTrendBaseline,
293
295
  isVertexGroundingRedirect,
294
296
  isoDateDaysBeforeInTimeZone,
295
297
  keywordDtoSchema,
@@ -519,7 +521,7 @@ import {
519
521
  wordpressSchemaDeployResultDtoSchema,
520
522
  wordpressSchemaStatusResultDtoSchema,
521
523
  wordpressStatusDtoSchema
522
- } from "./chunk-R6UQYXLG.js";
524
+ } from "./chunk-BUAVO37B.js";
523
525
 
524
526
  // src/intelligence-service.ts
525
527
  import { eq as eq57, desc as desc26, asc as asc11, and as and45, ne as ne7, or as or11, inArray as inArray19, gte as gte13, lte as lte10 } from "drizzle-orm";
@@ -6326,12 +6328,6 @@ function categorizeQueryByIntent(query, brandTokens) {
6326
6328
  return "other";
6327
6329
  }
6328
6330
 
6329
- // ../intelligence/src/trend-stability.ts
6330
- var MIN_TREND_POINTS = 4;
6331
- function isTrendBaseline(points) {
6332
- return points.length < MIN_TREND_POINTS;
6333
- }
6334
-
6335
6331
  // ../intelligence/src/citation-scorecard.ts
6336
6332
  function buildCitationScorecard(snapshots, queryLookup) {
6337
6333
  if (snapshots.length === 0) {
@@ -16687,6 +16683,8 @@ function filteredOverviewWithDb(db, active, plan, run, filters, targetKeys) {
16687
16683
  const usageEdges = materialized.input.usageEdges.filter((edge) => filters.queryClass === "all" || materialized.edgeQueryClass.get(edge.id) === filters.queryClass);
16688
16684
  return {
16689
16685
  materialized,
16686
+ expectedSlots,
16687
+ usageEdges,
16690
16688
  overview: buildMeasurementOverview({
16691
16689
  ...materialized.input,
16692
16690
  expectedSlots,
@@ -16812,6 +16810,39 @@ function targetKeysForRun(plan, run, requested, requireEntireScope) {
16812
16810
  }
16813
16811
  return selected;
16814
16812
  }
16813
+ function marketRollup(plan, run, materialized, expectedSlots, usageEdges, scopedToOneGroup) {
16814
+ if (scopedToOneGroup) return [];
16815
+ return plan.groups.map((group) => {
16816
+ const targetKeys = targetKeysForRun(plan, run, group.targetKeys, false);
16817
+ const overview = buildMeasurementOverview({
16818
+ ...materialized.input,
16819
+ expectedSlots,
16820
+ usageEdges,
16821
+ scopeTargetIds: targetKeys
16822
+ });
16823
+ return {
16824
+ groupKey: group.stableKey,
16825
+ label: group.label,
16826
+ propertyCount: targetKeys.length,
16827
+ propertiesMentioned: countMetric2(overview.propertiesMentioned),
16828
+ mentionCoverage: coverageMetric2(overview.mentionCoverage),
16829
+ citationCoverage: coverageMetric2(overview.citationCoverage)
16830
+ };
16831
+ }).sort(compareWeakestMarket);
16832
+ }
16833
+ function compareWeakestMarket(a, b) {
16834
+ const aUnavailable = a.mentionCoverage.state === "unavailable" || a.citationCoverage.state === "unavailable";
16835
+ const bUnavailable = b.mentionCoverage.state === "unavailable" || b.citationCoverage.state === "unavailable";
16836
+ if (aUnavailable !== bUnavailable) return aUnavailable ? 1 : -1;
16837
+ if (aUnavailable || bUnavailable) return compareText13(a.label, b.label) || compareText13(a.groupKey, b.groupKey);
16838
+ if (a.mentionCoverage.state === "available" && b.mentionCoverage.state === "available" && a.mentionCoverage.value !== b.mentionCoverage.value) {
16839
+ return a.mentionCoverage.value - b.mentionCoverage.value;
16840
+ }
16841
+ if (a.citationCoverage.state === "available" && b.citationCoverage.state === "available" && a.citationCoverage.value !== b.citationCoverage.value) {
16842
+ return a.citationCoverage.value - b.citationCoverage.value;
16843
+ }
16844
+ return compareText13(a.label, b.label) || compareText13(a.groupKey, b.groupKey);
16845
+ }
16815
16846
  function portfolioResponse(db, active, plan, query) {
16816
16847
  const group = query.groupKey === void 0 ? void 0 : requireGroup2(plan, query.groupKey);
16817
16848
  const run = selectMeasurementQuestionRun(db, active.version.projectId, active, query.runId);
@@ -16845,11 +16876,22 @@ function portfolioResponse(db, active, plan, query) {
16845
16876
  citationCoverage: unavailable3("no_completed_run")
16846
16877
  },
16847
16878
  weakestProperties: rows2.slice(0, limit2),
16879
+ // Sorted through the same comparator as the measured branch. Plan order
16880
+ // is `stableKey`, so emitting it raw put markets in an order the schema
16881
+ // documents as worst-first and that changes the moment a run lands.
16882
+ markets: group !== void 0 ? [] : plan.groups.map((g) => ({
16883
+ groupKey: g.stableKey,
16884
+ label: g.label,
16885
+ propertyCount: g.targetKeys.length,
16886
+ propertiesMentioned: unavailable3("no_completed_run"),
16887
+ mentionCoverage: unavailable3("no_completed_run"),
16888
+ citationCoverage: unavailable3("no_completed_run")
16889
+ })).sort(compareWeakestMarket),
16848
16890
  totalProperties: rows2.length,
16849
16891
  truncated: rows2.length > limit2
16850
16892
  });
16851
16893
  }
16852
- const { materialized, overview } = filteredOverviewWithDb(db, active, plan, run, filters, targetKeys);
16894
+ const { materialized, overview, expectedSlots: filteredSlots, usageEdges: filteredEdges } = filteredOverviewWithDb(db, active, plan, run, filters, targetKeys);
16853
16895
  const measured = new Map(overview.properties.map((row) => [row.targetId, row]));
16854
16896
  const rows = targets.map((target) => {
16855
16897
  const row = measured.get(target.stableKey);
@@ -16879,6 +16921,7 @@ function portfolioResponse(db, active, plan, query) {
16879
16921
  citationCoverage: coverageMetric2(overview.citationCoverage)
16880
16922
  },
16881
16923
  weakestProperties: rows.slice(0, limit),
16924
+ markets: marketRollup(plan, run, materialized, filteredSlots, filteredEdges, group !== void 0),
16882
16925
  totalProperties: rows.length,
16883
16926
  truncated: rows.length > limit
16884
16927
  });
@@ -27671,7 +27714,7 @@ var routeCatalog = [
27671
27714
  method: "get",
27672
27715
  path: "/api/v1/projects/{name}/measurement-portfolio-summary",
27673
27716
  summary: "Get the weakest measured Properties",
27674
- description: "Returns a compact, revision-pinned portfolio ranking from stored results. It defaults to Non-brand questions, ranks measured mention coverage before citation coverage, and keeps unavailable rows separate from measured weakness. Replacement names come only from stored answer extraction. It never starts provider work.",
27717
+ description: "Returns a compact, revision-pinned portfolio ranking from stored results, plus a worst-first roll-up of every named market. It defaults to Non-brand questions, ranks measured mention coverage before citation coverage, and keeps unavailable rows separate from measured weakness. Every market is scoped to the displayed run, so a market row matches that market read with groupKey; markets may share Properties and never sum to the portfolio totals. The markets array is empty when the request already narrowed to one group. Replacement names come only from stored answer extraction. It never starts provider work.",
27675
27718
  tags: ["measurement-plans"],
27676
27719
  parameters: [
27677
27720
  nameParameter,
@@ -81,7 +81,7 @@ import {
81
81
  trafficConnectWordpressRequestSchema,
82
82
  trafficEventKindSchema,
83
83
  trafficSeriesGranularitySchema
84
- } from "./chunk-R6UQYXLG.js";
84
+ } from "./chunk-BUAVO37B.js";
85
85
 
86
86
  // src/config.ts
87
87
  import fs from "fs";
@@ -9431,7 +9431,7 @@ var canonryMcpTools = [
9431
9431
  defineTool({
9432
9432
  name: "canonry_measurement_portfolio_summary",
9433
9433
  title: "Summarize measured Properties",
9434
- description: "Start here to rank the weakest measured Properties and their stored replacement names. Reads stored data only; it never starts provider work.",
9434
+ description: "Start here to rank the weakest measured Properties and their stored replacement names, and to compare every named market worst-first. Each market is scoped to the displayed run; markets may share Properties, so they never sum to the portfolio totals. Reads stored data only; it never starts provider work.",
9435
9435
  access: "read",
9436
9436
  tier: "monitoring",
9437
9437
  inputSchema: measurementPortfolioSummaryInputSchema,
package/dist/cli.js CHANGED
@@ -30,7 +30,7 @@ import {
30
30
  showFirstRunNotice,
31
31
  trackCliCommandFinished,
32
32
  trackEvent
33
- } from "./chunk-U2ETSHDL.js";
33
+ } from "./chunk-CETLBKTX.js";
34
34
  import {
35
35
  CliError,
36
36
  EXIT_SYSTEM_ERROR,
@@ -50,7 +50,7 @@ import {
50
50
  saveConfigPatch,
51
51
  systemError,
52
52
  usageError
53
- } from "./chunk-B4JACCYB.js";
53
+ } from "./chunk-TS3AHKZG.js";
54
54
  import {
55
55
  apiKeys,
56
56
  createClient,
@@ -58,7 +58,7 @@ import {
58
58
  projects,
59
59
  queries,
60
60
  renderReportHtml
61
- } from "./chunk-HWK2JSV3.js";
61
+ } from "./chunk-GJOACSPY.js";
62
62
  import {
63
63
  AdsDeliverySnapshotStatuses,
64
64
  AdsHistoricalCampaignRollupStatuses,
@@ -122,7 +122,7 @@ import {
122
122
  providerQuotaPolicySchema,
123
123
  resolveProviderInput,
124
124
  winnabilityClassSchema
125
- } from "./chunk-R6UQYXLG.js";
125
+ } from "./chunk-BUAVO37B.js";
126
126
 
127
127
  // src/cli.ts
128
128
  import { pathToFileURL } from "url";
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  createServer
3
- } from "./chunk-U2ETSHDL.js";
3
+ } from "./chunk-CETLBKTX.js";
4
4
  import {
5
5
  loadConfig
6
- } from "./chunk-B4JACCYB.js";
7
- import "./chunk-HWK2JSV3.js";
8
- import "./chunk-R6UQYXLG.js";
6
+ } from "./chunk-TS3AHKZG.js";
7
+ import "./chunk-GJOACSPY.js";
8
+ import "./chunk-BUAVO37B.js";
9
9
  export {
10
10
  createServer,
11
11
  loadConfig
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  IntelligenceService
3
- } from "./chunk-HWK2JSV3.js";
4
- import "./chunk-R6UQYXLG.js";
3
+ } from "./chunk-GJOACSPY.js";
4
+ import "./chunk-BUAVO37B.js";
5
5
  export {
6
6
  IntelligenceService
7
7
  };
package/dist/mcp.js CHANGED
@@ -3,10 +3,10 @@ import {
3
3
  PACKAGE_VERSION,
4
4
  canonryMcpTools,
5
5
  createApiClient
6
- } from "./chunk-B4JACCYB.js";
6
+ } from "./chunk-TS3AHKZG.js";
7
7
  import {
8
8
  isReadOnlyKey
9
- } from "./chunk-R6UQYXLG.js";
9
+ } from "./chunk-BUAVO37B.js";
10
10
 
11
11
  // src/mcp/cli.ts
12
12
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canonry/canonry",
3
- "version": "4.148.12",
3
+ "version": "4.150.1",
4
4
  "type": "module",
5
5
  "description": "Agent-first open-source AEO operating platform - track how answer engines cite your domain",
6
6
  "license": "FSL-1.1-ALv2",
@@ -72,20 +72,20 @@
72
72
  "@ainyc/canonry-contracts": "0.0.0",
73
73
  "@ainyc/canonry-db": "0.0.0",
74
74
  "@ainyc/canonry-integration-bing": "0.0.0",
75
- "@ainyc/canonry-integration-openai-ads": "0.0.0",
76
75
  "@ainyc/canonry-integration-cloud-run": "0.0.0",
76
+ "@ainyc/canonry-integration-commoncrawl": "0.0.0",
77
77
  "@ainyc/canonry-integration-google": "0.0.0",
78
- "@ainyc/canonry-integration-google-places": "0.0.0",
78
+ "@ainyc/canonry-integration-openai-ads": "0.0.0",
79
79
  "@ainyc/canonry-integration-google-business-profile": "0.0.0",
80
+ "@ainyc/canonry-integration-google-places": "0.0.0",
80
81
  "@ainyc/canonry-integration-traffic": "0.0.0",
81
- "@ainyc/canonry-integration-commoncrawl": "0.0.0",
82
82
  "@ainyc/canonry-integration-wordpress": "0.0.0",
83
- "@ainyc/canonry-provider-claude": "0.0.0",
84
83
  "@ainyc/canonry-intelligence": "0.0.0",
85
84
  "@ainyc/canonry-provider-cdp": "0.0.0",
85
+ "@ainyc/canonry-provider-claude": "0.0.0",
86
86
  "@ainyc/canonry-provider-gemini": "0.0.0",
87
- "@ainyc/canonry-provider-openai": "0.0.0",
88
87
  "@ainyc/canonry-provider-local": "0.0.0",
88
+ "@ainyc/canonry-provider-openai": "0.0.0",
89
89
  "@ainyc/canonry-provider-perplexity": "0.0.0"
90
90
  },
91
91
  "scripts": {
@@ -1 +0,0 @@
1
- import{c as n}from"./index-D2xFeORc.js";const c=[["path",{d:"m15 18-6-6 6-6",key:"1wnfg3"}]],d=n("chevron-left",c);const i=[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]],v=n("refresh-cw",i),f={contentStyle:{backgroundColor:"var(--chart-tooltip-bg, #18181b)",border:"1px solid var(--chart-tooltip-border, #3f3f46)",borderRadius:8,fontSize:12},labelStyle:{color:"var(--chart-tooltip-label, #e4e4e7)"},itemStyle:{color:"var(--chart-tooltip-item, #a1a1aa)"}},u={fill:"var(--chart-neutral-text-dim, #71717a)",fontSize:11},l="var(--chart-grid, #27272a)",b="var(--chart-axis, #27272a)",r=["var(--chart-series-1, #34d399)","var(--chart-series-2, #60a5fa)","var(--chart-series-3, #f472b6)","var(--chart-series-4, #facc15)","var(--chart-series-5, #a78bfa)","var(--chart-series-6, #fb923c)","var(--chart-series-7, #22d3ee)","var(--chart-series-8, #f87171)"],s={gemini:"#60a5fa",openai:"#34d399",claude:"#fb923c",perplexity:"#22d3ee",local:"#a78bfa"};function m(a,t=0){return s[a]??r[t%r.length]}const p={text:"var(--chart-neutral-text, #a1a1aa)",textDim:"var(--chart-neutral-text-dim, #71717a)",textFaint:"var(--chart-neutral-text-faint, #52525b)",surface:"var(--chart-neutral-surface, #27272a)",trackSubtle:"var(--chart-neutral-track-subtle, rgb(255 255 255 / 0.04))",gridLine:"var(--chart-neutral-grid-line, rgb(255 255 255 / 0.06))"},S={positive:"var(--chart-tone-positive, #34d399)",positiveDeep:"var(--chart-tone-positive-deep, #10b981)",caution:"var(--chart-tone-caution, #fbbf24)",negative:"var(--chart-tone-negative, #fb7185)"};function g(a){return a}function o(a){const t=/^(\d{4})-(\d{2})-(\d{2})/.exec(a);return t?{year:Number(t[1]),month:Number(t[2]),day:Number(t[3])}:null}function R(a){const t=String(a),e=o(t);return e?new Date(Date.UTC(e.year,e.month-1,e.day)).toLocaleDateString(void 0,{timeZone:"UTC",month:"short",day:"numeric",year:"numeric"}):t}function C(a){const t=o(String(a));return t?`${t.month}/${t.day}`:String(a)}function T(a){return new Date(a).toLocaleDateString(void 0,{month:"short",day:"numeric",year:"numeric"})}function y(a){const t=new Date(a);return`${t.getMonth()+1}/${t.getDate()}`}export{d as C,v as R,b as a,u as b,R as c,f as d,p as e,C as f,r as g,S as h,l as i,y as j,T as k,g as o,m as p};
@@ -1 +0,0 @@
1
- import{C as te,r as v,u as T,D as ne,j as e,L as q}from"./vendor-tanstack-BjS7iY3g.js";import{bL as ae,bS as re,d2 as ie,d3 as oe,bY as le,bM as de,B as b,T as g,I as C,d4 as ce,m as B}from"./index-D2xFeORc.js";import{m as he}from"./v2-overview-adapter-BHmxTmCf.js";import{A as xe}from"./arrow-left-DF8Fd34I.js";import"./vendor-radix-DnzzbllM.js";import"./vendor-recharts-33ACLxsD.js";import"./vendor-markdown-CpDJch4G.js";const F=50,l={branded:{headline:"When they know your name",technical:"Branded questions"},"non-brand":{headline:"When they don't",technical:"Non-brand questions"}},me={plan_v1:"Setup update required",no_completed_run:"No completed measurement yet",no_population:"No questions of this type are assigned",evidence_incomplete:"Source evidence is incomplete",not_applicable:"Not applicable for this Property"},O={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"}},V={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 pe(s){return[...s].sort((n,a)=>+(a.classification==="assigned")-+(n.classification==="assigned"))}function ue(s){return`${s.expectedSlotId}:${s.usageEdgeId}`}function je({row:s}){return s.mentioned===null?e.jsxs("span",{className:"inline-flex flex-col items-start gap-0.5",children:[e.jsx(g,{tone:"neutral",children:"Not measured"}),e.jsx("span",{className:"text-xs text-muted",children:"No mention signal for this Property"})]}):e.jsx(g,{tone:s.mentioned?"positive":"neutral",children:s.mentioned?"Mentioned":"Not mentioned"})}const ye="—";function be({row:s}){return s.cited===null?e.jsxs("span",{className:"inline-flex flex-col items-start gap-0.5",children:[e.jsx(g,{tone:"neutral",children:"Not measured"}),e.jsx("span",{className:"text-xs text-muted",children:"Sources were not fully captured"})]}):e.jsx(g,{tone:s.cited?"positive":"neutral",children:s.cited?"Cited":"Not cited"})}function ge({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.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:pe(s.sources).map(n=>e.jsxs("tr",{children:[e.jsx("td",{children:e.jsx(g,{tone:V[n.classification].tone,children:V[n.classification].label})}),e.jsx("td",{className:"break-all text-secondary",children:n.sourceUrl})]},n.sourceUrl))})]})})}function K(s){return me[s.reason]??"Not measured"}function L({metric:s,emphasis:n=!1}){if(s.state==="unavailable")return e.jsxs("span",{className:"inline-flex flex-col gap-0.5",children:[e.jsx("span",{className:n?"text-lg font-semibold text-secondary":"text-sm font-medium text-secondary",children:"Not measured"}),e.jsx("span",{className:"text-sm text-secondary",children:K(s)})]});const a=`${Math.round(s.value*100)}%`,c=s.numerator===void 0||s.denominator===void 0?null:`${s.numerator} of ${s.denominator}`;return e.jsxs("span",{className:"inline-flex flex-col gap-0.5 tabular-nums",children:[e.jsx("span",{className:n?"text-lg font-semibold text-heading":"text-sm font-medium text-primary",children:a}),c?e.jsx("span",{className:"text-xs text-muted",children:c}):null]})}function z(s,n,a){return ce({client:B,path:{name:s},query:{scope:"property",targetKey:n,queryClass:a}})}function D(s){return s?.properties.items.at(0)}function fe({branded:s,nonBrand:n,brandedError:a,nonBrandError:c,onRetry:w}){const S=[{queryClass:"branded",row:s,isError:a},{queryClass:"non-brand",row:n,isError:c}];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(C,{text:"Branded questions already contain your name, so an answer engine has an easy path back to you. Non-brand questions describe the need instead, and that is the demand you have to earn. Each row is measured only over the questions assigned to this Property in that class; a class with no assigned question 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 question class"}),e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Question type"}),e.jsx("th",{children:"Mentioned in the answer"}),e.jsx("th",{children:"Cited as a source"})]})}),e.jsx("tbody",{children:S.map(({queryClass:r,row:d,isError:x})=>e.jsxs("tr",{children:[e.jsxs("td",{children:[e.jsx("span",{className:"block font-medium text-heading",children:l[r].headline}),e.jsx("span",{className:"mt-0.5 block text-xs text-muted",children:l[r].technical}),d&&x?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(b,{type:"button",size:"sm",variant:"ghost",className:"h-11 px-3 text-sm md:h-11",onClick:()=>w(r),children:["Retry ",l[r].technical.toLocaleLowerCase()]})]}):null]}),d?e.jsxs(e.Fragment,{children:[e.jsx("td",{children:e.jsx(L,{metric:d.mentionCoverage,emphasis:!0})}),e.jsx("td",{children:e.jsx(L,{metric:d.citationCoverage,emphasis:!0})})]}):x?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 ",l[r].technical.toLocaleLowerCase(),"."]}),e.jsxs(b,{type:"button",size:"sm",variant:"outline",className:"h-11 px-4 text-sm md:h-11",onClick:()=>w(r),children:["Retry ",l[r].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…"})})]})]},r))})]})})]})}function ve({row:s,queryClass:n,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.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"By answer engine"}),e.jsxs("h2",{id:"property-providers",className:"text-base font-semibold text-heading",children:["Which engines answer for this Property",e.jsx(C,{text:"Each row is measured over the questions 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 ",l[n].technical.toLocaleLowerCase()," are unavailable. Retry that question 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 ",l[n].technical.toLocaleLowerCase()," for this Property.",s.mentionCoverage.state==="unavailable"?` ${K(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(c=>e.jsxs("tr",{children:[e.jsx("td",{className:"font-medium text-heading",children:c.provider}),e.jsx("td",{children:e.jsx(L,{metric:c.mentionCoverage})}),e.jsx("td",{children:e.jsx(L,{metric:c.citationCoverage})})]},c.provider))})]})})]})}function Ne({questions:s,queryClass:n}){return e.jsxs("section",{"aria-labelledby":"property-questions",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:"Questions"}),e.jsxs("h2",{id:"property-questions",className:"text-base font-semibold text-heading",children:[l[n].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 ",l[n].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:"Questions assigned to this Property"}),e.jsx("thead",{children:e.jsx("tr",{children:e.jsx("th",{children:"Question"})})}),e.jsx("tbody",{children:s.map(a=>e.jsx("tr",{children:e.jsx("td",{className:"text-secondary",children:a})},a))})]})})]})}function we({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.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"Pages"}),e.jsxs("h2",{id:"property-urls",className:"text-base font-semibold text-heading",children:["URLs that count as this Property",e.jsx(C,{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(n=>e.jsx("tr",{children:e.jsx("td",{className:"break-all text-secondary",children:n})},n))})]})})]})}function ke(){const{projectName:s,targetKey:n}=te({strict:!1}),[a,c]=v.useState("non-brand"),[w,S]=v.useState(new Set),r=s??"",d=n??"",x=!!r&&!!d,{canWrite:M}=ae(),f=T({...re({client:B,path:{name:r}}),enabled:x}),m=T({...z(r,d,"branded"),enabled:x}),p=T({...z(r,d,"non-brand"),enabled:x}),U=D(m.data),I=D(p.data),u=a==="branded"?m.data:p.data,N=a==="branded"?U:I,_=(a==="branded"?m.isError:p.isError)&&N===void 0,Q=u?.measurement.displayedRunId,P={client:B,path:{name:r},query:{targetKey:d,queryClass:a,shape:ie.answers,limit:F,...Q?{runId:Q}:{}}},i=ne({...oe(P),enabled:x&&u!==void 0,initialPageParam:P,getNextPageParam:t=>t.answers?.nextCursor?{path:P.path,query:{...P.query,cursor:t.answers.nextCursor}}:void 0}),R=f.data?.active??null,j=R?.plan.schemaVersion===2?R.plan:null,W=R!==null&&j===null,E=j?.targets.find(t=>t.stableKey===d)??null,H=v.useMemo(()=>{if(!j)return[];const t=new Map(j.querySnapshots.map(o=>[o.queryId,o.queryText]));return[...new Set(j.assignments.filter(o=>o.targetKey===d&&o.queryClass===a).flatMap(o=>{const h=t.get(o.queryId);return h===void 0?[]:[h]}))].sort((o,h)=>o.localeCompare(h))},[j,d,a]),G=v.useMemo(()=>E?.urlMatchers.map(he)??[],[E]),y=v.useMemo(()=>(i.data?.pages??[]).flatMap(h=>h.answers?.items??[]),[i.data]),$=i.data?.pages[0]?.answers?.totalEstimate??y.length,Y=(i.data?.pages??[]).length>0&&(i.data?.pages??[]).every(t=>t.answers===void 0),Z=i.data?.pages[0]?.measurement.state,A=e.jsxs(q,{to:"/projects/$projectName",params:{projectName:r},className:"inline-flex items-center gap-1 text-xs text-muted hover:text-strong",children:[e.jsx(xe,{className:"size-3.5","aria-hidden":"true"}),"Back to measurement overview"]});if(!x)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(!le("portfolio",de()?.projectTabs))return e.jsx("div",{className:"page-container",children:e.jsx("p",{className:"text-sm text-muted",children:"This view is not available here."})});if(f.isPending&&!f.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 J=f.isError&&f.data===void 0,X=m.isError&&m.data===void 0,ee=p.isError&&p.data===void 0;return J||X&&ee?e.jsxs("div",{className:"page-container space-y-3",children:[A,e.jsx("p",{role:"alert",className:"text-sm text-negative",children:"Could not load this Property."}),e.jsx(b,{type:"button",size:"sm",variant:"outline",className:"h-11 px-4 text-sm md:h-11",onClick:()=>{f.refetch(),m.refetch(),p.refetch()},children:"Try again"})]}):!j||!E?e.jsxs("div",{className:"page-container space-y-3",children:[A,e.jsx("p",{role:"status",className:"text-sm text-secondary",children:j?"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(b,{asChild:!0,type:"button",variant:"outline",className:"h-11 px-4 text-sm md:h-11",children:e.jsx(q,{to:"/projects/$projectName/portfolio",params:{projectName:r},children:M?W?"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:[A,e.jsx("h1",{className:"page-title mt-2",children:E.label}),e.jsxs("p",{className:"page-subtitle",children:["Property in ",r]})]}),e.jsxs("div",{className:"page-header-right",children:[u?e.jsx(g,{tone:O[u.measurement.state].tone,children:O[u.measurement.state].label}):null,N&&N.flags>0?e.jsxs(g,{tone:"caution",children:[N.flags," flagged"]}):null]})]}),e.jsx(fe,{branded:U,nonBrand:I,brandedError:m.isError,nonBrandError:p.isError,onRetry:t=>{t==="branded"?m.refetch():p.refetch()}}),u&&(u.measurement.state==="not_measured"||u.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:M?"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(b,{asChild:!0,type:"button",className:"h-11 px-4 text-sm md:h-11",children:e.jsx(q,{to:"/projects/$projectName",params:{projectName:r},children:M?"Go to measurement overview":"View measurement overview"})})]}):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:"Question type"}),e.jsxs("select",{id:"property-query-class",value:a,onChange:t=>c(t.target.value==="branded"?"branded":"non-brand"),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:l["non-brand"].technical}),e.jsx("option",{value:"branded",children:l.branded.technical})]})]}),e.jsxs("p",{className:"supporting-copy",children:["Everything below is measured over ",l[a].technical.toLocaleLowerCase()," only."]})]}),e.jsx(ve,{row:N,queryClass:a,isError:_}),e.jsx(Ne,{questions:H,queryClass:a}),e.jsx(we,{urls:G}),e.jsxs("section",{"aria-labelledby":"property-evidence",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:"Evidence"}),e.jsxs("h2",{id:"property-evidence",className:"text-base font-semibold text-heading",children:["Answers the engines gave",e.jsx(C,{text:"One row per answer an engine gave for the questions 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. Expand a row for the source URLs the engine returned, this Property's own first."})]})]}),y.length>0?e.jsxs("p",{className:"supporting-copy",children:[y.length," of ",$]}):null]}),_?e.jsxs("p",{className:"text-sm text-secondary",children:["Evidence for ",l[a].technical.toLocaleLowerCase()," is unavailable. Retry that question type above."]}):i.isPending&&y.length===0?e.jsx("p",{className:"text-sm text-secondary",children:"Loading evidence…"}):i.isError&&y.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(b,{type:"button",size:"sm",variant:"outline",className:"h-11 px-4 text-sm md:h-11",onClick:()=>{i.refetch()},children:"Retry evidence"})]}):Z==="not_measured"?e.jsx("p",{className:"text-sm text-secondary",children:"Not measured yet. Run a measurement to collect the answers for this Property."}):Y?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."}):y.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:"overflow-x-auto rounded-md border border-default",children:e.jsxs("table",{className:"evidence-table min-w-[720px]",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:"Question"}),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:y.map(t=>{const o=ue(t),h=w.has(o);return e.jsxs(v.Fragment,{children:[e.jsxs("tr",{children:[e.jsxs("td",{className:"text-secondary",children:[e.jsx("span",{className:"block",children:t.queryText}),e.jsx("span",{className:"mt-1 block text-xs text-muted",children:[t.provider,t.location].filter(Boolean).join(" · ")}),t.historical||t.bridged?e.jsx("span",{className:"mt-1 flex",children:e.jsx(g,{tone:"caution",children:"Historical"})}):null]}),e.jsx("td",{children:e.jsx(je,{row:t})}),e.jsx("td",{children:e.jsx(be,{row:t})}),e.jsx("td",{className:"tabular-nums text-secondary",children:t.cited===null?ye:t.sources.length}),e.jsx("td",{className:"text-right",children:e.jsx(b,{type:"button",size:"sm",variant:"ghost","aria-expanded":h,onClick:()=>S(se=>{const k=new Set(se);return k.delete(o)||k.add(o),k}),children:h?`Hide sources for ${t.queryText}`:`Show sources for ${t.queryText}`})})]}),h?e.jsx("tr",{children:e.jsx("td",{colSpan:5,className:"bg-surface-subtle px-4",children:e.jsx(ge,{row:t})})}):null]},o)})})]})}),i.hasNextPage?e.jsxs("div",{className:"mt-2 flex flex-wrap items-center gap-3 text-sm text-secondary",children:[e.jsxs("span",{children:["Showing ",y.length," of ",$]}),i.isFetchNextPageError?e.jsx("span",{role:"alert",children:"Could not load more evidence."}):null,e.jsx(b,{size:"sm",variant:"outline",className:"h-11 px-4 text-sm md:h-11",disabled:i.isFetchingNextPage,onClick:()=>{i.fetchNextPage()},children:i.isFetchingNextPage?"Loading…":i.isFetchNextPageError?"Retry more evidence":`Show ${F} more`})]}):null]})]})]})}export{ke as MeasurementPropertyPage};