@ainyc/canonry 4.71.0 → 4.72.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. package/assets/agent-workspace/skills/aero/references/regression-playbook.md +1 -1
  2. package/assets/agent-workspace/skills/canonry/references/aeo-analysis.md +7 -0
  3. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +20 -2
  4. package/assets/assets/{BacklinksPage-CQNPYiDA.js → BacklinksPage-CjfpwZEH.js} +1 -1
  5. package/assets/assets/{ChartPrimitives-BShpLrpS.js → ChartPrimitives-Ckf2FrUy.js} +1 -1
  6. package/assets/assets/{ProjectPage-CJLw1m4O.js → ProjectPage-DZeplYeC.js} +6 -6
  7. package/assets/assets/{RunRow-Dq1vs1hA.js → RunRow-BuFyG0V_.js} +1 -1
  8. package/assets/assets/{RunsPage-CBMa2xWh.js → RunsPage-D-pr000K.js} +1 -1
  9. package/assets/assets/{SettingsPage-B_XeJDdg.js → SettingsPage-CiaapCYn.js} +1 -1
  10. package/assets/assets/{TrafficPage-vJv_Mf6f.js → TrafficPage-B40xytJD.js} +1 -1
  11. package/assets/assets/{TrafficSourceDetailPage-C3yFwVmQ.js → TrafficSourceDetailPage-7hHem-gM.js} +1 -1
  12. package/assets/assets/{extract-error-message-CIpeBFLl.js → extract-error-message-3GkDsu1h.js} +1 -1
  13. package/assets/assets/{index-BXLM3-cs.js → index-BVdH2O9w.js} +77 -77
  14. package/assets/assets/{server-traffic-Yt3jIi3g.js → server-traffic-CsgPsudZ.js} +1 -1
  15. package/assets/assets/{trash-2-xGvNHhEj.js → trash-2-B8Ipf9rI.js} +1 -1
  16. package/assets/index.html +1 -1
  17. package/dist/{chunk-ZNWMVYYU.js → chunk-NYZSY5QJ.js} +126 -7
  18. package/dist/{chunk-5FM7QRYD.js → chunk-SJI6JGPN.js} +1249 -1005
  19. package/dist/{chunk-XYBBC5CH.js → chunk-XYX447L2.js} +670 -99
  20. package/dist/{chunk-B32J3DSZ.js → chunk-ZISXWFQA.js} +92 -4
  21. package/dist/cli.js +306 -84
  22. package/dist/index.js +4 -4
  23. package/dist/{intelligence-service-GV57RTPO.js → intelligence-service-YOZOOYUI.js} +2 -2
  24. package/dist/mcp.js +2 -2
  25. package/package.json +9 -9
@@ -1561,56 +1561,24 @@ var scheduleUpsertRequestSchema = z14.object({
1561
1561
  );
1562
1562
 
1563
1563
  // ../contracts/src/analytics.ts
1564
- import { z as z15 } from "zod";
1565
- var metricsWindowSchema = z15.enum(["7d", "30d", "90d", "all"]);
1566
- var trendDirectionSchema = z15.enum(["improving", "declining", "stable"]);
1567
- var visibilityMetricModeSchema = z15.enum(["mentioned", "cited"]);
1568
- var VisibilityMetricModes = visibilityMetricModeSchema.enum;
1569
- var providerMetricSchema = z15.object({
1570
- citationRate: z15.number(),
1571
- cited: z15.number().int(),
1572
- total: z15.number().int(),
1573
- mentionRate: z15.number(),
1574
- mentionedCount: z15.number().int()
1575
- });
1576
- var timeBucketSchema = z15.object({
1577
- startDate: z15.string(),
1578
- endDate: z15.string(),
1579
- citationRate: z15.number(),
1580
- cited: z15.number().int(),
1581
- total: z15.number().int(),
1582
- queryCount: z15.number().int(),
1583
- mentionRate: z15.number(),
1584
- mentionedCount: z15.number().int(),
1585
- byProvider: z15.record(z15.string(), providerMetricSchema)
1586
- });
1587
- var queryChangeEventSchema = z15.object({
1588
- date: z15.string(),
1589
- delta: z15.number().int(),
1590
- label: z15.string()
1591
- });
1592
- var brandMetricsDtoSchema = z15.object({
1593
- window: metricsWindowSchema,
1594
- buckets: z15.array(timeBucketSchema),
1595
- overall: providerMetricSchema,
1596
- byProvider: z15.record(z15.string(), providerMetricSchema),
1597
- trend: trendDirectionSchema,
1598
- mentionTrend: trendDirectionSchema,
1599
- queryChanges: z15.array(queryChangeEventSchema)
1600
- });
1601
- function parseWindow(value) {
1602
- if (value === "7d" || value === "30d" || value === "90d" || value === "all") return value;
1603
- return "all";
1604
- }
1605
- function windowCutoff(window) {
1606
- if (window === "all") return null;
1607
- const days = window === "7d" ? 7 : window === "30d" ? 30 : 90;
1608
- const d = /* @__PURE__ */ new Date();
1609
- d.setDate(d.getDate() - days);
1610
- return d.toISOString();
1611
- }
1564
+ import { z as z18 } from "zod";
1612
1565
 
1613
1566
  // ../contracts/src/source-categories.ts
1567
+ import { z as z15 } from "zod";
1568
+ var sourceCategorySchema = z15.enum([
1569
+ "competitor",
1570
+ "directory",
1571
+ "social",
1572
+ "forum",
1573
+ "news",
1574
+ "reference",
1575
+ "blog",
1576
+ "ecommerce",
1577
+ "video",
1578
+ "academic",
1579
+ "other"
1580
+ ]);
1581
+ var SourceCategories = sourceCategorySchema.enum;
1614
1582
  var SOURCE_CATEGORY_RULES = [
1615
1583
  // Directories, marketplaces & review platforms — generic across industries.
1616
1584
  // Industry-specific directories (NRCA, GAF, etc.) intentionally omitted;
@@ -1635,6 +1603,21 @@ var SOURCE_CATEGORY_RULES = [
1635
1603
  { pattern: "producthunt.com", category: "directory", label: "Product Hunt" },
1636
1604
  { pattern: "glassdoor.com", category: "directory", label: "Glassdoor" },
1637
1605
  { pattern: "indeed.com", category: "directory", label: "Indeed" },
1606
+ // Major GLOBAL travel / lodging / dining aggregators (OTAs). Included
1607
+ // because — unlike niche per-vertical directories (NRCA, GAF) which are
1608
+ // deliberately omitted — these are top-tier cross-business marketplaces in
1609
+ // the same class as Yelp/Angi, and AEO for hospitality routinely competes
1610
+ // against them. They classify as `ota-aggregator` surfaces (see #675).
1611
+ { pattern: "tripadvisor.com", category: "directory", label: "Tripadvisor" },
1612
+ { pattern: "booking.com", category: "directory", label: "Booking.com" },
1613
+ { pattern: "expedia.com", category: "directory", label: "Expedia" },
1614
+ { pattern: "hotels.com", category: "directory", label: "Hotels.com" },
1615
+ { pattern: "agoda.com", category: "directory", label: "Agoda" },
1616
+ { pattern: "kayak.com", category: "directory", label: "Kayak" },
1617
+ { pattern: "trivago.com", category: "directory", label: "Trivago" },
1618
+ { pattern: "airbnb.com", category: "directory", label: "Airbnb" },
1619
+ { pattern: "vrbo.com", category: "directory", label: "Vrbo" },
1620
+ { pattern: "opentable.com", category: "directory", label: "OpenTable" },
1638
1621
  // Forums
1639
1622
  { pattern: "reddit.com", category: "forum", label: "Reddit" },
1640
1623
  { pattern: "quora.com", category: "forum", label: "Quora" },
@@ -1734,30 +1717,312 @@ function categoryLabel(category) {
1734
1717
  return CATEGORY_LABELS[category];
1735
1718
  }
1736
1719
 
1737
- // ../contracts/src/ga.ts
1720
+ // ../contracts/src/surface-class.ts
1721
+ import { z as z17 } from "zod";
1722
+
1723
+ // ../contracts/src/discovery.ts
1738
1724
  import { z as z16 } from "zod";
1739
- var ga4ConnectionDtoSchema = z16.object({
1725
+ var discoveryBucketSchema = z16.enum(["cited", "aspirational", "wasted-surface"]);
1726
+ var DiscoveryBuckets = discoveryBucketSchema.enum;
1727
+ var DEFAULT_DISCOVERY_PROMOTE_BUCKETS = [
1728
+ DiscoveryBuckets.cited,
1729
+ DiscoveryBuckets.aspirational
1730
+ ];
1731
+ var DISCOVERY_PROMOTE_COMPETITOR_CAP = 20;
1732
+ var DISCOVERY_PROMOTE_COMPETITOR_MIN_HITS = 2;
1733
+ var discoveryCompetitorTypeSchema = z16.enum([
1734
+ "direct-competitor",
1735
+ "ota-aggregator",
1736
+ "editorial-media",
1737
+ "other",
1738
+ "unknown"
1739
+ ]);
1740
+ var DiscoveryCompetitorTypes = discoveryCompetitorTypeSchema.enum;
1741
+ var DEFAULT_DISCOVERY_PROMOTE_COMPETITOR_TYPES = [
1742
+ DiscoveryCompetitorTypes["direct-competitor"]
1743
+ ];
1744
+ var discoverySessionStatusSchema = z16.enum(["queued", "seeding", "probing", "completed", "failed"]);
1745
+ var DiscoverySessionStatuses = discoverySessionStatusSchema.enum;
1746
+ var discoveryCompetitorMapEntrySchema = z16.object({
1747
+ domain: z16.string().min(1),
1748
+ hits: z16.number().int().positive(),
1749
+ /**
1750
+ * Domain classification from the session's post-probe AI classification
1751
+ * pass. Defaults to `unknown` so competitor maps persisted before
1752
+ * classification existed (or by a session whose classification call failed)
1753
+ * still parse — those entries are excluded from the default promote filter.
1754
+ */
1755
+ competitorType: discoveryCompetitorTypeSchema.default("unknown")
1756
+ });
1757
+ var discoveryProbeDtoSchema = z16.object({
1740
1758
  id: z16.string(),
1759
+ sessionId: z16.string(),
1741
1760
  projectId: z16.string(),
1742
- propertyId: z16.string(),
1743
- clientEmail: z16.string(),
1744
- connected: z16.boolean(),
1745
- createdAt: z16.string(),
1746
- updatedAt: z16.string()
1747
- });
1748
- var ga4TrafficSnapshotDtoSchema = z16.object({
1749
- date: z16.string(),
1750
- landingPage: z16.string(),
1751
- sessions: z16.number(),
1752
- organicSessions: z16.number(),
1753
- users: z16.number()
1754
- });
1755
- var ga4SourceDimensionSchema = z16.enum(["session", "first_user", "manual_utm"]);
1756
- var ga4AiReferralDtoSchema = z16.object({
1757
- source: z16.string(),
1758
- medium: z16.string(),
1759
- sessions: z16.number(),
1760
- users: z16.number(),
1761
+ query: z16.string(),
1762
+ bucket: discoveryBucketSchema.nullable().default(null),
1763
+ citationState: citationStateSchema,
1764
+ citedDomains: z16.array(z16.string()).default([]),
1765
+ createdAt: z16.string()
1766
+ });
1767
+ var discoverySessionDtoSchema = z16.object({
1768
+ id: z16.string(),
1769
+ projectId: z16.string(),
1770
+ status: discoverySessionStatusSchema,
1771
+ icpDescription: z16.string().nullable().optional(),
1772
+ seedProvider: z16.string().nullable().optional(),
1773
+ seedCountRaw: z16.number().int().nullable().optional(),
1774
+ seedCount: z16.number().int().nullable().optional(),
1775
+ dedupThreshold: z16.number().nullable().optional(),
1776
+ probeCount: z16.number().int().nullable().optional(),
1777
+ citedCount: z16.number().int().nullable().default(null),
1778
+ aspirationalCount: z16.number().int().nullable().default(null),
1779
+ wastedCount: z16.number().int().nullable().default(null),
1780
+ competitorMap: z16.array(discoveryCompetitorMapEntrySchema).default([]),
1781
+ error: z16.string().nullable().optional(),
1782
+ startedAt: z16.string().nullable().optional(),
1783
+ finishedAt: z16.string().nullable().optional(),
1784
+ createdAt: z16.string()
1785
+ });
1786
+ var discoverySessionDetailDtoSchema = discoverySessionDtoSchema.extend({
1787
+ probes: z16.array(discoveryProbeDtoSchema).default([])
1788
+ });
1789
+ var DISCOVERY_MAX_PROBES_CAP = 500;
1790
+ var discoveryRunRequestSchema = z16.object({
1791
+ icpDescription: z16.string().min(1).optional(),
1792
+ dedupThreshold: z16.number().min(0).max(1).optional(),
1793
+ maxProbes: z16.number().int().positive().max(DISCOVERY_MAX_PROBES_CAP).optional(),
1794
+ /**
1795
+ * Optional override of the project's location labels, constraining seed
1796
+ * generation to a subset of the configured service areas. Each label must
1797
+ * match a configured project location (resolved server-side via
1798
+ * `resolveLocations`). Omitted means "use every project location" — a
1799
+ * project with no locations is unaffected.
1800
+ */
1801
+ locations: z16.array(z16.string().min(1)).optional()
1802
+ });
1803
+ var discoveryPromoteRequestSchema = z16.object({
1804
+ buckets: z16.array(discoveryBucketSchema).min(1).optional(),
1805
+ includeCompetitors: z16.boolean().optional(),
1806
+ competitorTypes: z16.array(discoveryCompetitorTypeSchema).min(1).optional()
1807
+ });
1808
+ var discoveryPromotePreviewSchema = z16.object({
1809
+ sessionId: z16.string(),
1810
+ projectId: z16.string(),
1811
+ status: discoverySessionStatusSchema,
1812
+ queriesByBucket: z16.object({
1813
+ cited: z16.array(z16.string()),
1814
+ aspirational: z16.array(z16.string()),
1815
+ "wasted-surface": z16.array(z16.string())
1816
+ }),
1817
+ suggestedCompetitors: z16.array(discoveryCompetitorMapEntrySchema)
1818
+ });
1819
+ var discoveryPromoteResultSchema = z16.object({
1820
+ sessionId: z16.string(),
1821
+ projectId: z16.string(),
1822
+ promoted: z16.object({
1823
+ queries: z16.array(z16.string()),
1824
+ competitors: z16.array(z16.string())
1825
+ }),
1826
+ skipped: z16.object({
1827
+ queries: z16.array(z16.string()),
1828
+ competitors: z16.array(z16.string())
1829
+ })
1830
+ });
1831
+ var queryProvenanceSchema = z16.union([
1832
+ z16.literal("cli"),
1833
+ z16.string().regex(/^discovery:.+$/)
1834
+ ]);
1835
+
1836
+ // ../contracts/src/surface-class.ts
1837
+ var surfaceClassSchema = z17.enum([
1838
+ "own",
1839
+ "direct-competitor",
1840
+ "ota-aggregator",
1841
+ "editorial-media",
1842
+ "other"
1843
+ ]);
1844
+ var SurfaceClasses = surfaceClassSchema.enum;
1845
+ var SURFACE_CLASS_LABELS = {
1846
+ own: "Your domains",
1847
+ "direct-competitor": "Direct competitors",
1848
+ "ota-aggregator": "Aggregators & marketplaces",
1849
+ "editorial-media": "Editorial & media",
1850
+ other: "Other sources"
1851
+ };
1852
+ function surfaceClassLabel(surfaceClass) {
1853
+ return SURFACE_CLASS_LABELS[surfaceClass];
1854
+ }
1855
+ function surfaceClassFromCompetitorType(type) {
1856
+ switch (type) {
1857
+ case DiscoveryCompetitorTypes["direct-competitor"]:
1858
+ return SurfaceClasses["direct-competitor"];
1859
+ case DiscoveryCompetitorTypes["ota-aggregator"]:
1860
+ return SurfaceClasses["ota-aggregator"];
1861
+ case DiscoveryCompetitorTypes["editorial-media"]:
1862
+ return SurfaceClasses["editorial-media"];
1863
+ case DiscoveryCompetitorTypes.other:
1864
+ return SurfaceClasses.other;
1865
+ case DiscoveryCompetitorTypes.unknown:
1866
+ return void 0;
1867
+ }
1868
+ }
1869
+ function matchesAnyDomain(candidate, domains) {
1870
+ if (!candidate) return false;
1871
+ for (const domain of domains) {
1872
+ const normalized = normalizeProjectDomain(domain);
1873
+ if (!normalized) continue;
1874
+ if (candidate === normalized || candidate.endsWith(`.${normalized}`)) return true;
1875
+ }
1876
+ return false;
1877
+ }
1878
+ function classifySurfaceFromCategory(domain, category, context, storedClass) {
1879
+ const candidate = normalizeProjectDomain(domain);
1880
+ if (matchesAnyDomain(candidate, context.projectDomains)) return SurfaceClasses.own;
1881
+ if (matchesAnyDomain(candidate, context.competitorDomains)) return SurfaceClasses["direct-competitor"];
1882
+ if (storedClass) return storedClass;
1883
+ switch (category) {
1884
+ case "directory":
1885
+ case "ecommerce":
1886
+ return SurfaceClasses["ota-aggregator"];
1887
+ case "news":
1888
+ case "blog":
1889
+ case "reference":
1890
+ return SurfaceClasses["editorial-media"];
1891
+ case "competitor":
1892
+ return SurfaceClasses["direct-competitor"];
1893
+ case "social":
1894
+ case "forum":
1895
+ case "video":
1896
+ case "academic":
1897
+ case "other":
1898
+ return SurfaceClasses.other;
1899
+ }
1900
+ }
1901
+
1902
+ // ../contracts/src/analytics.ts
1903
+ var metricsWindowSchema = z18.enum(["7d", "30d", "90d", "all"]);
1904
+ var trendDirectionSchema = z18.enum(["improving", "declining", "stable"]);
1905
+ var visibilityMetricModeSchema = z18.enum(["mentioned", "cited"]);
1906
+ var VisibilityMetricModes = visibilityMetricModeSchema.enum;
1907
+ var providerMetricSchema = z18.object({
1908
+ citationRate: z18.number(),
1909
+ cited: z18.number().int(),
1910
+ total: z18.number().int(),
1911
+ mentionRate: z18.number(),
1912
+ mentionedCount: z18.number().int()
1913
+ });
1914
+ var timeBucketSchema = z18.object({
1915
+ startDate: z18.string(),
1916
+ endDate: z18.string(),
1917
+ citationRate: z18.number(),
1918
+ cited: z18.number().int(),
1919
+ total: z18.number().int(),
1920
+ queryCount: z18.number().int(),
1921
+ mentionRate: z18.number(),
1922
+ mentionedCount: z18.number().int(),
1923
+ byProvider: z18.record(z18.string(), providerMetricSchema)
1924
+ });
1925
+ var queryChangeEventSchema = z18.object({
1926
+ date: z18.string(),
1927
+ delta: z18.number().int(),
1928
+ label: z18.string()
1929
+ });
1930
+ var brandMetricsDtoSchema = z18.object({
1931
+ window: metricsWindowSchema,
1932
+ buckets: z18.array(timeBucketSchema),
1933
+ overall: providerMetricSchema,
1934
+ byProvider: z18.record(z18.string(), providerMetricSchema),
1935
+ trend: trendDirectionSchema,
1936
+ mentionTrend: trendDirectionSchema,
1937
+ queryChanges: z18.array(queryChangeEventSchema)
1938
+ });
1939
+ var sourceCategoryCountSchema = z18.object({
1940
+ category: sourceCategorySchema,
1941
+ label: z18.string(),
1942
+ count: z18.number().int(),
1943
+ /** Share of all cited slots in scope, 0..1 (4dp). */
1944
+ percentage: z18.number(),
1945
+ topDomains: z18.array(z18.object({ domain: z18.string(), count: z18.number().int() }))
1946
+ });
1947
+ var sourceRankEntrySchema = z18.object({
1948
+ domain: z18.string(),
1949
+ count: z18.number().int(),
1950
+ /** Share of the list's `totalCitedSlots`, 0..1 (4dp). */
1951
+ percentage: z18.number(),
1952
+ category: sourceCategorySchema,
1953
+ label: z18.string(),
1954
+ surfaceClass: surfaceClassSchema
1955
+ });
1956
+ var surfaceClassCountSchema = z18.object({
1957
+ surfaceClass: surfaceClassSchema,
1958
+ label: z18.string(),
1959
+ count: z18.number().int(),
1960
+ /** Share of the list's `totalCitedSlots`, 0..1 (4dp). */
1961
+ percentage: z18.number(),
1962
+ domainCount: z18.number().int()
1963
+ });
1964
+ var rankedSourceListSchema = z18.object({
1965
+ /** Total cited slots (grounding citations) counted in this scope. */
1966
+ totalCitedSlots: z18.number().int(),
1967
+ /** Distinct domains in this scope. */
1968
+ domainTotal: z18.number().int(),
1969
+ /** Ranked domains, desc by count; truncated to the applied limit if any. */
1970
+ entries: z18.array(sourceRankEntrySchema),
1971
+ /** Distinct domains beyond the limit (0 when full). */
1972
+ truncatedDomainCount: z18.number().int(),
1973
+ /** Cited slots beyond the limit (0 when full). */
1974
+ truncatedCitedSlots: z18.number().int(),
1975
+ /** Surface-class roll-up over the FULL scope (not just `entries`). */
1976
+ bySurfaceClass: z18.array(surfaceClassCountSchema)
1977
+ });
1978
+ var sourceBreakdownDtoSchema = z18.object({
1979
+ overall: z18.array(sourceCategoryCountSchema),
1980
+ byQuery: z18.record(z18.string(), z18.array(sourceCategoryCountSchema)),
1981
+ /** Full ranked + classified cited-domain list across all providers (#675). */
1982
+ ranked: rankedSourceListSchema,
1983
+ /** Per-provider ranked + classified breakdown, keyed by provider name (#675). */
1984
+ byProvider: z18.record(z18.string(), rankedSourceListSchema),
1985
+ runId: z18.string(),
1986
+ window: metricsWindowSchema,
1987
+ /** Applied ranked-list limit; null when the full list is returned. */
1988
+ limit: z18.number().int().nullable()
1989
+ });
1990
+ function parseWindow(value) {
1991
+ if (value === "7d" || value === "30d" || value === "90d" || value === "all") return value;
1992
+ return "all";
1993
+ }
1994
+ function windowCutoff(window) {
1995
+ if (window === "all") return null;
1996
+ const days = window === "7d" ? 7 : window === "30d" ? 30 : 90;
1997
+ const d = /* @__PURE__ */ new Date();
1998
+ d.setDate(d.getDate() - days);
1999
+ return d.toISOString();
2000
+ }
2001
+
2002
+ // ../contracts/src/ga.ts
2003
+ import { z as z19 } from "zod";
2004
+ var ga4ConnectionDtoSchema = z19.object({
2005
+ id: z19.string(),
2006
+ projectId: z19.string(),
2007
+ propertyId: z19.string(),
2008
+ clientEmail: z19.string(),
2009
+ connected: z19.boolean(),
2010
+ createdAt: z19.string(),
2011
+ updatedAt: z19.string()
2012
+ });
2013
+ var ga4TrafficSnapshotDtoSchema = z19.object({
2014
+ date: z19.string(),
2015
+ landingPage: z19.string(),
2016
+ sessions: z19.number(),
2017
+ organicSessions: z19.number(),
2018
+ users: z19.number()
2019
+ });
2020
+ var ga4SourceDimensionSchema = z19.enum(["session", "first_user", "manual_utm"]);
2021
+ var ga4AiReferralDtoSchema = z19.object({
2022
+ source: z19.string(),
2023
+ medium: z19.string(),
2024
+ sessions: z19.number(),
2025
+ users: z19.number(),
1761
2026
  /**
1762
2027
  * The winning attribution dimension for this (source, medium) tuple — the
1763
2028
  * one with the highest session count. GA4 emits one row per dimension
@@ -1767,144 +2032,144 @@ var ga4AiReferralDtoSchema = z16.object({
1767
2032
  */
1768
2033
  sourceDimension: ga4SourceDimensionSchema
1769
2034
  });
1770
- var ga4AiReferralLandingPageDtoSchema = z16.object({
1771
- source: z16.string(),
1772
- medium: z16.string(),
2035
+ var ga4AiReferralLandingPageDtoSchema = z19.object({
2036
+ source: z19.string(),
2037
+ medium: z19.string(),
1773
2038
  /**
1774
2039
  * The winning attribution dimension for this (source, medium, landingPage)
1775
2040
  * tuple — the one with the highest session count.
1776
2041
  */
1777
2042
  sourceDimension: ga4SourceDimensionSchema,
1778
- landingPage: z16.string(),
1779
- sessions: z16.number(),
1780
- users: z16.number()
1781
- });
1782
- var ga4SocialReferralDtoSchema = z16.object({
1783
- source: z16.string(),
1784
- medium: z16.string(),
1785
- sessions: z16.number(),
1786
- users: z16.number(),
2043
+ landingPage: z19.string(),
2044
+ sessions: z19.number(),
2045
+ users: z19.number()
2046
+ });
2047
+ var ga4SocialReferralDtoSchema = z19.object({
2048
+ source: z19.string(),
2049
+ medium: z19.string(),
2050
+ sessions: z19.number(),
2051
+ users: z19.number(),
1787
2052
  /** GA4 default channel group (e.g. 'Organic Social', 'Paid Social') */
1788
- channelGroup: z16.string()
2053
+ channelGroup: z19.string()
1789
2054
  });
1790
- var ga4ChannelBucketDtoSchema = z16.object({
1791
- sessions: z16.number(),
1792
- sharePct: z16.number(),
1793
- sharePctDisplay: z16.string()
2055
+ var ga4ChannelBucketDtoSchema = z19.object({
2056
+ sessions: z19.number(),
2057
+ sharePct: z19.number(),
2058
+ sharePctDisplay: z19.string()
1794
2059
  });
1795
- var ga4ChannelBreakdownDtoSchema = z16.object({
2060
+ var ga4ChannelBreakdownDtoSchema = z19.object({
1796
2061
  organic: ga4ChannelBucketDtoSchema,
1797
2062
  social: ga4ChannelBucketDtoSchema,
1798
2063
  direct: ga4ChannelBucketDtoSchema,
1799
2064
  ai: ga4ChannelBucketDtoSchema,
1800
2065
  other: ga4ChannelBucketDtoSchema
1801
2066
  });
1802
- var ga4TrafficSummaryDtoSchema = z16.object({
1803
- totalSessions: z16.number(),
1804
- totalOrganicSessions: z16.number(),
2067
+ var ga4TrafficSummaryDtoSchema = z19.object({
2068
+ totalSessions: z19.number(),
2069
+ totalOrganicSessions: z19.number(),
1805
2070
  /** Direct-channel sessions (sessions with no source — bookmarks, typed URLs, AI-driven traffic with stripped referrer). 0 for legacy rows from before the column was added. */
1806
- totalDirectSessions: z16.number(),
1807
- totalUsers: z16.number(),
1808
- topPages: z16.array(z16.object({
1809
- landingPage: z16.string(),
1810
- sessions: z16.number(),
1811
- organicSessions: z16.number(),
2071
+ totalDirectSessions: z19.number(),
2072
+ totalUsers: z19.number(),
2073
+ topPages: z19.array(z19.object({
2074
+ landingPage: z19.string(),
2075
+ sessions: z19.number(),
2076
+ organicSessions: z19.number(),
1812
2077
  /** Per-page Direct-channel sessions. 0 for legacy rows. */
1813
- directSessions: z16.number(),
1814
- users: z16.number()
2078
+ directSessions: z19.number(),
2079
+ users: z19.number()
1815
2080
  })),
1816
- aiReferrals: z16.array(ga4AiReferralDtoSchema),
1817
- aiReferralLandingPages: z16.array(ga4AiReferralLandingPageDtoSchema),
2081
+ aiReferrals: z19.array(ga4AiReferralDtoSchema),
2082
+ aiReferralLandingPages: z19.array(ga4AiReferralLandingPageDtoSchema),
1818
2083
  /** Deduped AI session total: MAX(sessions) per date+source+medium across attribution dimensions, then summed. Cross-cutting: can overlap with Direct/Organic/Social via firstUserSource. */
1819
- aiSessionsDeduped: z16.number(),
2084
+ aiSessionsDeduped: z19.number(),
1820
2085
  /** Deduped AI user total: MAX(users) per date+source+medium across attribution dimensions, then summed. */
1821
- aiUsersDeduped: z16.number(),
2086
+ aiUsersDeduped: z19.number(),
1822
2087
  /** AI sessions whose CURRENT sessionSource matched an AI engine. Can overlap with raw Organic/Social/Direct totals; `channelBreakdown` removes those overlaps for display. */
1823
- aiSessionsBySession: z16.number(),
2088
+ aiSessionsBySession: z19.number(),
1824
2089
  /** AI users whose CURRENT sessionSource matched an AI engine. Can overlap with raw Organic/Social/Direct totals. */
1825
- aiUsersBySession: z16.number(),
1826
- socialReferrals: z16.array(ga4SocialReferralDtoSchema),
2090
+ aiUsersBySession: z19.number(),
2091
+ socialReferrals: z19.array(ga4SocialReferralDtoSchema),
1827
2092
  /** Total social sessions (session-scoped, no cross-dimension dedup needed). */
1828
- socialSessions: z16.number(),
2093
+ socialSessions: z19.number(),
1829
2094
  /** Total social users (session-scoped, no cross-dimension dedup needed). */
1830
- socialUsers: z16.number(),
2095
+ socialUsers: z19.number(),
1831
2096
  /** Five disjoint buckets used for the channel breakdown. Known AI session-source matches are removed from their native GA4 bucket before shares are computed. */
1832
2097
  channelBreakdown: ga4ChannelBreakdownDtoSchema,
1833
2098
  /** Organic sessions as a percentage of total sessions (0–100, rounded). */
1834
- organicSharePct: z16.number(),
2099
+ organicSharePct: z19.number(),
1835
2100
  /** Deduped AI sessions as a percentage of total sessions (0–100, rounded). Cross-cutting: can overlap with Direct/Organic/Social. */
1836
- aiSharePct: z16.number(),
2101
+ aiSharePct: z19.number(),
1837
2102
  /** Session-source-only AI sessions as a percentage of total sessions (0–100, rounded). Can overlap with raw Organic/Social/Direct totals. */
1838
- aiSharePctBySession: z16.number(),
2103
+ aiSharePctBySession: z19.number(),
1839
2104
  /** Direct-channel sessions as a percentage of total sessions (0–100, rounded). */
1840
- directSharePct: z16.number(),
2105
+ directSharePct: z19.number(),
1841
2106
  /** Social sessions as a percentage of total sessions (0–100, rounded). */
1842
- socialSharePct: z16.number(),
2107
+ socialSharePct: z19.number(),
1843
2108
  /** Display string for organicSharePct: 'X%', '<1%' for non-zero shares that round below 1, or '—' when sessions exist but total is unknown (partial sync). */
1844
- organicSharePctDisplay: z16.string(),
2109
+ organicSharePctDisplay: z19.string(),
1845
2110
  /** Display string for aiSharePct: 'X%', '<1%' for non-zero shares that round below 1, or '—' when sessions exist but total is unknown (partial sync). */
1846
- aiSharePctDisplay: z16.string(),
2111
+ aiSharePctDisplay: z19.string(),
1847
2112
  /** Display string for aiSharePctBySession: 'X%', '<1%' for non-zero shares that round below 1, or '—' when sessions exist but total is unknown (partial sync). */
1848
- aiSharePctBySessionDisplay: z16.string(),
2113
+ aiSharePctBySessionDisplay: z19.string(),
1849
2114
  /** Display string for directSharePct: 'X%', '<1%' for non-zero shares that round below 1, or '—' when sessions exist but total is unknown (partial sync). */
1850
- directSharePctDisplay: z16.string(),
2115
+ directSharePctDisplay: z19.string(),
1851
2116
  /** Display string for socialSharePct: 'X%', '<1%' for non-zero shares that round below 1, or '—' when sessions exist but total is unknown (partial sync). */
1852
- socialSharePctDisplay: z16.string(),
2117
+ socialSharePctDisplay: z19.string(),
1853
2118
  /** Sessions not covered by Organic, Social, Direct, or AI (session) channels — e.g. Referral, Email, Paid Search, Display. Always non-negative; clamped to 0 when the four disjoint channels sum above total (rounding edge). */
1854
- otherSessions: z16.number(),
2119
+ otherSessions: z19.number(),
1855
2120
  /** Other sessions as a percentage of total sessions (0–100, rounded). */
1856
- otherSharePct: z16.number(),
2121
+ otherSharePct: z19.number(),
1857
2122
  /** Display string for otherSharePct: 'X%', '<1%' for non-zero shares that round below 1, or '—' when sessions exist but total is unknown (partial sync). */
1858
- otherSharePctDisplay: z16.string(),
1859
- lastSyncedAt: z16.string().nullable()
1860
- });
1861
- var ga4StatusDtoSchema = z16.object({
1862
- connected: z16.boolean(),
1863
- propertyId: z16.string().nullable(),
1864
- clientEmail: z16.string().nullable(),
1865
- authMethod: z16.enum(["service-account", "oauth"]).nullable(),
1866
- lastSyncedAt: z16.string().nullable(),
1867
- createdAt: z16.string().nullable().optional(),
1868
- updatedAt: z16.string().nullable().optional()
1869
- });
1870
- var ga4SyncResponseDtoSchema = z16.object({
1871
- synced: z16.boolean(),
1872
- rowCount: z16.number().int().nonnegative(),
1873
- aiReferralCount: z16.number().int().nonnegative(),
1874
- socialReferralCount: z16.number().int().nonnegative(),
1875
- days: z16.number().int().nonnegative(),
1876
- syncedAt: z16.string(),
2123
+ otherSharePctDisplay: z19.string(),
2124
+ lastSyncedAt: z19.string().nullable()
2125
+ });
2126
+ var ga4StatusDtoSchema = z19.object({
2127
+ connected: z19.boolean(),
2128
+ propertyId: z19.string().nullable(),
2129
+ clientEmail: z19.string().nullable(),
2130
+ authMethod: z19.enum(["service-account", "oauth"]).nullable(),
2131
+ lastSyncedAt: z19.string().nullable(),
2132
+ createdAt: z19.string().nullable().optional(),
2133
+ updatedAt: z19.string().nullable().optional()
2134
+ });
2135
+ var ga4SyncResponseDtoSchema = z19.object({
2136
+ synced: z19.boolean(),
2137
+ rowCount: z19.number().int().nonnegative(),
2138
+ aiReferralCount: z19.number().int().nonnegative(),
2139
+ socialReferralCount: z19.number().int().nonnegative(),
2140
+ days: z19.number().int().nonnegative(),
2141
+ syncedAt: z19.string(),
1877
2142
  /**
1878
2143
  * Components that were written this run. Present when `only` is set.
1879
2144
  * Always includes `traffic` and `summary` (the share denominator) plus
1880
2145
  * the requested channel breakdown — `ai` and/or `social`.
1881
2146
  */
1882
- syncedComponents: z16.array(z16.string()).optional()
1883
- });
1884
- var ga4AiReferralHistoryEntrySchema = z16.object({
1885
- date: z16.string(),
1886
- source: z16.string(),
1887
- medium: z16.string(),
1888
- landingPage: z16.string(),
1889
- sessions: z16.number(),
1890
- users: z16.number(),
2147
+ syncedComponents: z19.array(z19.string()).optional()
2148
+ });
2149
+ var ga4AiReferralHistoryEntrySchema = z19.object({
2150
+ date: z19.string(),
2151
+ source: z19.string(),
2152
+ medium: z19.string(),
2153
+ landingPage: z19.string(),
2154
+ sessions: z19.number(),
2155
+ users: z19.number(),
1891
2156
  /** Which GA4 dimension this row came from: session (sessionSource), first_user (firstUserSource), or manual_utm (utm_source parameter) */
1892
2157
  sourceDimension: ga4SourceDimensionSchema
1893
2158
  });
1894
- var ga4SocialReferralHistoryEntrySchema = z16.object({
1895
- date: z16.string(),
1896
- source: z16.string(),
1897
- medium: z16.string(),
1898
- sessions: z16.number(),
1899
- users: z16.number(),
2159
+ var ga4SocialReferralHistoryEntrySchema = z19.object({
2160
+ date: z19.string(),
2161
+ source: z19.string(),
2162
+ medium: z19.string(),
2163
+ sessions: z19.number(),
2164
+ users: z19.number(),
1900
2165
  /** GA4 default channel group (e.g. 'Organic Social', 'Paid Social') */
1901
- channelGroup: z16.string()
2166
+ channelGroup: z19.string()
1902
2167
  });
1903
- var ga4SessionHistoryEntrySchema = z16.object({
1904
- date: z16.string(),
1905
- sessions: z16.number(),
1906
- organicSessions: z16.number(),
1907
- users: z16.number()
2168
+ var ga4SessionHistoryEntrySchema = z19.object({
2169
+ date: z19.string(),
2170
+ sessions: z19.number(),
2171
+ organicSessions: z19.number(),
2172
+ users: z19.number()
1908
2173
  });
1909
2174
 
1910
2175
  // ../contracts/src/answer-visibility.ts
@@ -2072,149 +2337,149 @@ function escapeRegExp(value) {
2072
2337
  }
2073
2338
 
2074
2339
  // ../contracts/src/agent.ts
2075
- import { z as z17 } from "zod";
2076
- var agentProviderIdSchema = z17.enum(["claude", "openai", "gemini", "zai"]);
2077
- var agentProviderOptionDtoSchema = z17.object({
2340
+ import { z as z20 } from "zod";
2341
+ var agentProviderIdSchema = z20.enum(["claude", "openai", "gemini", "zai"]);
2342
+ var agentProviderOptionDtoSchema = z20.object({
2078
2343
  /** Stable identifier — what clients pass back as `provider` on the prompt endpoint. */
2079
2344
  id: agentProviderIdSchema,
2080
2345
  /** Human-readable label for UI pickers, e.g. "Anthropic (Claude)". */
2081
- label: z17.string(),
2346
+ label: z20.string(),
2082
2347
  /** Default model if the caller doesn't pick one. */
2083
- defaultModel: z17.string(),
2348
+ defaultModel: z20.string(),
2084
2349
  /** Whether a usable API key was found (config.yaml or provider env var). */
2085
- configured: z17.boolean(),
2350
+ configured: z20.boolean(),
2086
2351
  /**
2087
2352
  * Where the key resolved from, if any. `null` when `configured === false`.
2088
2353
  * Surfaced so the UI can nudge users toward their preferred source of truth.
2089
2354
  */
2090
- keySource: z17.enum(["config", "env"]).nullable()
2355
+ keySource: z20.enum(["config", "env"]).nullable()
2091
2356
  });
2092
- var agentProvidersResponseDtoSchema = z17.object({
2357
+ var agentProvidersResponseDtoSchema = z20.object({
2093
2358
  /**
2094
2359
  * Every provider Aero knows about. `configured === false` entries are
2095
2360
  * included so the UI can render them disabled with an onboarding hint.
2096
2361
  */
2097
- providers: z17.array(agentProviderOptionDtoSchema).default([]),
2362
+ providers: z20.array(agentProviderOptionDtoSchema).default([]),
2098
2363
  /**
2099
2364
  * Provider Aero auto-picks when no explicit override is passed. Null if
2100
2365
  * nothing is configured (install never exchanged a key).
2101
2366
  */
2102
2367
  defaultProvider: agentProviderIdSchema.nullable()
2103
2368
  });
2104
- var memorySourceSchema = z17.enum(["aero", "user", "compaction"]);
2369
+ var memorySourceSchema = z20.enum(["aero", "user", "compaction"]);
2105
2370
  var MemorySources = memorySourceSchema.enum;
2106
2371
  var AGENT_MEMORY_VALUE_MAX_BYTES = 2 * 1024;
2107
2372
  var AGENT_MEMORY_KEY_MAX_LENGTH = 128;
2108
- var agentMemoryUpsertRequestSchema = z17.object({
2109
- key: z17.string().min(1).max(AGENT_MEMORY_KEY_MAX_LENGTH),
2110
- value: z17.string().min(1)
2373
+ var agentMemoryUpsertRequestSchema = z20.object({
2374
+ key: z20.string().min(1).max(AGENT_MEMORY_KEY_MAX_LENGTH),
2375
+ value: z20.string().min(1)
2111
2376
  });
2112
- var agentMemoryDeleteRequestSchema = z17.object({
2113
- key: z17.string().min(1).max(AGENT_MEMORY_KEY_MAX_LENGTH)
2377
+ var agentMemoryDeleteRequestSchema = z20.object({
2378
+ key: z20.string().min(1).max(AGENT_MEMORY_KEY_MAX_LENGTH)
2114
2379
  });
2115
2380
 
2116
2381
  // ../contracts/src/backlinks.ts
2117
- import { z as z18 } from "zod";
2118
- var ccReleaseSyncStatusSchema = z18.enum(["queued", "downloading", "querying", "ready", "failed"]);
2382
+ import { z as z21 } from "zod";
2383
+ var ccReleaseSyncStatusSchema = z21.enum(["queued", "downloading", "querying", "ready", "failed"]);
2119
2384
  var CcReleaseSyncStatuses = ccReleaseSyncStatusSchema.enum;
2120
- var ccReleaseSyncDtoSchema = z18.object({
2121
- id: z18.string(),
2122
- release: z18.string(),
2385
+ var ccReleaseSyncDtoSchema = z21.object({
2386
+ id: z21.string(),
2387
+ release: z21.string(),
2123
2388
  status: ccReleaseSyncStatusSchema,
2124
- phaseDetail: z18.string().nullable().optional(),
2125
- vertexPath: z18.string().nullable().optional(),
2126
- edgesPath: z18.string().nullable().optional(),
2127
- vertexSha256: z18.string().nullable().optional(),
2128
- edgesSha256: z18.string().nullable().optional(),
2129
- vertexBytes: z18.number().int().nullable().optional(),
2130
- edgesBytes: z18.number().int().nullable().optional(),
2131
- projectsProcessed: z18.number().int().nullable().optional(),
2132
- domainsDiscovered: z18.number().int().nullable().optional(),
2133
- downloadStartedAt: z18.string().nullable().optional(),
2134
- downloadFinishedAt: z18.string().nullable().optional(),
2135
- queryStartedAt: z18.string().nullable().optional(),
2136
- queryFinishedAt: z18.string().nullable().optional(),
2137
- error: z18.string().nullable().optional(),
2138
- createdAt: z18.string(),
2139
- updatedAt: z18.string()
2140
- });
2141
- var backlinkDomainDtoSchema = z18.object({
2142
- linkingDomain: z18.string(),
2143
- numHosts: z18.number().int()
2144
- });
2145
- var backlinkSummaryDtoSchema = z18.object({
2146
- projectId: z18.string(),
2147
- release: z18.string(),
2148
- targetDomain: z18.string(),
2149
- totalLinkingDomains: z18.number().int(),
2150
- totalHosts: z18.number().int(),
2151
- top10HostsShare: z18.string(),
2152
- queriedAt: z18.string(),
2389
+ phaseDetail: z21.string().nullable().optional(),
2390
+ vertexPath: z21.string().nullable().optional(),
2391
+ edgesPath: z21.string().nullable().optional(),
2392
+ vertexSha256: z21.string().nullable().optional(),
2393
+ edgesSha256: z21.string().nullable().optional(),
2394
+ vertexBytes: z21.number().int().nullable().optional(),
2395
+ edgesBytes: z21.number().int().nullable().optional(),
2396
+ projectsProcessed: z21.number().int().nullable().optional(),
2397
+ domainsDiscovered: z21.number().int().nullable().optional(),
2398
+ downloadStartedAt: z21.string().nullable().optional(),
2399
+ downloadFinishedAt: z21.string().nullable().optional(),
2400
+ queryStartedAt: z21.string().nullable().optional(),
2401
+ queryFinishedAt: z21.string().nullable().optional(),
2402
+ error: z21.string().nullable().optional(),
2403
+ createdAt: z21.string(),
2404
+ updatedAt: z21.string()
2405
+ });
2406
+ var backlinkDomainDtoSchema = z21.object({
2407
+ linkingDomain: z21.string(),
2408
+ numHosts: z21.number().int()
2409
+ });
2410
+ var backlinkSummaryDtoSchema = z21.object({
2411
+ projectId: z21.string(),
2412
+ release: z21.string(),
2413
+ targetDomain: z21.string(),
2414
+ totalLinkingDomains: z21.number().int(),
2415
+ totalHosts: z21.number().int(),
2416
+ top10HostsShare: z21.string(),
2417
+ queriedAt: z21.string(),
2153
2418
  // Populated when the response is filtered (e.g. ?excludeCrawlers=1).
2154
2419
  // Counts the rows omitted from totalLinkingDomains/totalHosts so callers
2155
2420
  // can show "N hidden" hints without re-deriving them.
2156
- excludedLinkingDomains: z18.number().int().optional(),
2157
- excludedHosts: z18.number().int().optional()
2421
+ excludedLinkingDomains: z21.number().int().optional(),
2422
+ excludedHosts: z21.number().int().optional()
2158
2423
  });
2159
- var backlinkListResponseSchema = z18.object({
2424
+ var backlinkListResponseSchema = z21.object({
2160
2425
  summary: backlinkSummaryDtoSchema.nullable(),
2161
- total: z18.number().int(),
2162
- rows: z18.array(backlinkDomainDtoSchema)
2163
- });
2164
- var backlinkHistoryEntrySchema = z18.object({
2165
- release: z18.string(),
2166
- totalLinkingDomains: z18.number().int(),
2167
- totalHosts: z18.number().int(),
2168
- top10HostsShare: z18.string(),
2169
- queriedAt: z18.string()
2170
- });
2171
- var backlinksInstallStatusDtoSchema = z18.object({
2172
- duckdbInstalled: z18.boolean(),
2173
- duckdbVersion: z18.string().nullable().optional(),
2174
- duckdbSpec: z18.string(),
2175
- pluginDir: z18.string()
2176
- });
2177
- var backlinksInstallResultDtoSchema = z18.object({
2178
- installed: z18.boolean(),
2179
- version: z18.string(),
2180
- path: z18.string(),
2181
- alreadyPresent: z18.boolean()
2182
- });
2183
- var ccAvailableReleaseSchema = z18.object({
2184
- release: z18.string(),
2185
- vertexUrl: z18.string(),
2186
- edgesUrl: z18.string(),
2187
- vertexBytes: z18.number().int().nullable(),
2188
- edgesBytes: z18.number().int().nullable(),
2189
- lastModified: z18.string().nullable()
2190
- });
2191
- var ccCachedReleaseSchema = z18.object({
2192
- release: z18.string(),
2426
+ total: z21.number().int(),
2427
+ rows: z21.array(backlinkDomainDtoSchema)
2428
+ });
2429
+ var backlinkHistoryEntrySchema = z21.object({
2430
+ release: z21.string(),
2431
+ totalLinkingDomains: z21.number().int(),
2432
+ totalHosts: z21.number().int(),
2433
+ top10HostsShare: z21.string(),
2434
+ queriedAt: z21.string()
2435
+ });
2436
+ var backlinksInstallStatusDtoSchema = z21.object({
2437
+ duckdbInstalled: z21.boolean(),
2438
+ duckdbVersion: z21.string().nullable().optional(),
2439
+ duckdbSpec: z21.string(),
2440
+ pluginDir: z21.string()
2441
+ });
2442
+ var backlinksInstallResultDtoSchema = z21.object({
2443
+ installed: z21.boolean(),
2444
+ version: z21.string(),
2445
+ path: z21.string(),
2446
+ alreadyPresent: z21.boolean()
2447
+ });
2448
+ var ccAvailableReleaseSchema = z21.object({
2449
+ release: z21.string(),
2450
+ vertexUrl: z21.string(),
2451
+ edgesUrl: z21.string(),
2452
+ vertexBytes: z21.number().int().nullable(),
2453
+ edgesBytes: z21.number().int().nullable(),
2454
+ lastModified: z21.string().nullable()
2455
+ });
2456
+ var ccCachedReleaseSchema = z21.object({
2457
+ release: z21.string(),
2193
2458
  syncStatus: ccReleaseSyncStatusSchema.nullable(),
2194
- bytes: z18.number().int(),
2195
- lastUsedAt: z18.string().nullable()
2459
+ bytes: z21.number().int(),
2460
+ lastUsedAt: z21.string().nullable()
2196
2461
  });
2197
2462
 
2198
2463
  // ../contracts/src/composites.ts
2199
- import { z as z19 } from "zod";
2200
- var searchHitKindSchema = z19.enum(["snapshot", "insight"]);
2201
- var projectSearchSnapshotHitSchema = z19.object({
2202
- kind: z19.literal("snapshot"),
2203
- id: z19.string(),
2204
- runId: z19.string(),
2205
- query: z19.string(),
2206
- provider: z19.string(),
2207
- model: z19.string().nullable(),
2464
+ import { z as z22 } from "zod";
2465
+ var searchHitKindSchema = z22.enum(["snapshot", "insight"]);
2466
+ var projectSearchSnapshotHitSchema = z22.object({
2467
+ kind: z22.literal("snapshot"),
2468
+ id: z22.string(),
2469
+ runId: z22.string(),
2470
+ query: z22.string(),
2471
+ provider: z22.string(),
2472
+ model: z22.string().nullable(),
2208
2473
  citationState: citationStateSchema,
2209
- matchedField: z19.enum(["answerText", "citedDomains", "searchQueries", "query"]),
2210
- snippet: z19.string(),
2211
- createdAt: z19.string()
2212
- });
2213
- var projectSearchInsightHitSchema = z19.object({
2214
- kind: z19.literal("insight"),
2215
- id: z19.string(),
2216
- runId: z19.string().nullable(),
2217
- type: z19.enum([
2474
+ matchedField: z22.enum(["answerText", "citedDomains", "searchQueries", "query"]),
2475
+ snippet: z22.string(),
2476
+ createdAt: z22.string()
2477
+ });
2478
+ var projectSearchInsightHitSchema = z22.object({
2479
+ kind: z22.literal("insight"),
2480
+ id: z22.string(),
2481
+ runId: z22.string().nullable(),
2482
+ type: z22.enum([
2218
2483
  "regression",
2219
2484
  "gain",
2220
2485
  "opportunity",
@@ -2230,29 +2495,29 @@ var projectSearchInsightHitSchema = z19.object({
2230
2495
  "gbp-metric-drop",
2231
2496
  "gbp-keyword-drop"
2232
2497
  ]),
2233
- severity: z19.enum(["critical", "high", "medium", "low"]),
2234
- title: z19.string(),
2235
- query: z19.string(),
2236
- provider: z19.string(),
2237
- matchedField: z19.enum(["title", "query", "recommendation", "cause"]),
2238
- snippet: z19.string(),
2239
- dismissed: z19.boolean(),
2240
- createdAt: z19.string()
2241
- });
2242
- var projectSearchHitSchema = z19.discriminatedUnion("kind", [
2498
+ severity: z22.enum(["critical", "high", "medium", "low"]),
2499
+ title: z22.string(),
2500
+ query: z22.string(),
2501
+ provider: z22.string(),
2502
+ matchedField: z22.enum(["title", "query", "recommendation", "cause"]),
2503
+ snippet: z22.string(),
2504
+ dismissed: z22.boolean(),
2505
+ createdAt: z22.string()
2506
+ });
2507
+ var projectSearchHitSchema = z22.discriminatedUnion("kind", [
2243
2508
  projectSearchSnapshotHitSchema,
2244
2509
  projectSearchInsightHitSchema
2245
2510
  ]);
2246
- var projectSearchResponseSchema = z19.object({
2247
- query: z19.string(),
2248
- totalHits: z19.number().int().nonnegative(),
2249
- truncated: z19.boolean(),
2250
- hits: z19.array(projectSearchHitSchema)
2511
+ var projectSearchResponseSchema = z22.object({
2512
+ query: z22.string(),
2513
+ totalHits: z22.number().int().nonnegative(),
2514
+ truncated: z22.boolean(),
2515
+ hits: z22.array(projectSearchHitSchema)
2251
2516
  });
2252
2517
 
2253
2518
  // ../contracts/src/content.ts
2254
- import { z as z20 } from "zod";
2255
- var contentActionSchema = z20.enum(["create", "expand", "refresh", "add-schema"]);
2519
+ import { z as z23 } from "zod";
2520
+ var contentActionSchema = z23.enum(["create", "expand", "refresh", "add-schema"]);
2256
2521
  var ContentActions = contentActionSchema.enum;
2257
2522
  function contentActionLabel(action) {
2258
2523
  switch (action) {
@@ -2266,9 +2531,9 @@ function contentActionLabel(action) {
2266
2531
  return "Add schema";
2267
2532
  }
2268
2533
  }
2269
- var demandSourceSchema = z20.enum(["gsc", "competitor-evidence", "both"]);
2534
+ var demandSourceSchema = z23.enum(["gsc", "competitor-evidence", "both"]);
2270
2535
  var DemandSources = demandSourceSchema.enum;
2271
- var actionConfidenceSchema = z20.enum(["high", "medium", "low"]);
2536
+ var actionConfidenceSchema = z23.enum(["high", "medium", "low"]);
2272
2537
  var ActionConfidences = actionConfidenceSchema.enum;
2273
2538
  function actionConfidenceLabel(confidence) {
2274
2539
  switch (confidence) {
@@ -2280,7 +2545,7 @@ function actionConfidenceLabel(confidence) {
2280
2545
  return "Low";
2281
2546
  }
2282
2547
  }
2283
- var pageTypeSchema = z20.enum([
2548
+ var pageTypeSchema = z23.enum([
2284
2549
  "blog-post",
2285
2550
  "comparison",
2286
2551
  "listicle",
@@ -2289,7 +2554,7 @@ var pageTypeSchema = z20.enum([
2289
2554
  "glossary"
2290
2555
  ]);
2291
2556
  var PageTypes = pageTypeSchema.enum;
2292
- var contentActionStateSchema = z20.enum([
2557
+ var contentActionStateSchema = z23.enum([
2293
2558
  "proposed",
2294
2559
  "briefed",
2295
2560
  "payload-generated",
@@ -2299,136 +2564,217 @@ var contentActionStateSchema = z20.enum([
2299
2564
  "dismissed"
2300
2565
  ]);
2301
2566
  var ContentActionStates = contentActionStateSchema.enum;
2302
- var ourBestPageSchema = z20.object({
2303
- url: z20.string(),
2304
- gscImpressions: z20.number().nonnegative(),
2305
- gscClicks: z20.number().nonnegative(),
2567
+ var winnabilityClassSchema = z23.enum(["ownable", "ceded"]);
2568
+ var WinnabilityClasses = winnabilityClassSchema.enum;
2569
+ function winnabilityClassLabel(winnabilityClass) {
2570
+ switch (winnabilityClass) {
2571
+ case "ownable":
2572
+ return "Ownable";
2573
+ case "ceded":
2574
+ return "Ceded";
2575
+ }
2576
+ }
2577
+ var CEDED_SURFACE_THRESHOLD = 0.6;
2578
+ function deriveWinnabilityClass(citedSurfaceDomains, domainClasses, threshold = CEDED_SURFACE_THRESHOLD) {
2579
+ const hasCoverage = citedSurfaceDomains.some((d) => domainClasses.has(d.domain));
2580
+ if (citedSurfaceDomains.length === 0 || domainClasses.size === 0 || !hasCoverage) {
2581
+ return { winnabilityClass: WinnabilityClasses.ownable, winnability: null };
2582
+ }
2583
+ let total = 0;
2584
+ let ceded = 0;
2585
+ for (const { domain, citationCount } of citedSurfaceDomains) {
2586
+ total += citationCount;
2587
+ const cls = domainClasses.get(domain);
2588
+ if (cls === DiscoveryCompetitorTypes["ota-aggregator"] || cls === DiscoveryCompetitorTypes["editorial-media"]) {
2589
+ ceded += citationCount;
2590
+ }
2591
+ }
2592
+ if (total === 0) {
2593
+ return { winnabilityClass: WinnabilityClasses.ownable, winnability: null };
2594
+ }
2595
+ const cededShare = ceded / total;
2596
+ const winnability = Math.min(1, Math.max(0, 1 - cededShare));
2597
+ return {
2598
+ winnabilityClass: cededShare >= threshold ? WinnabilityClasses.ceded : WinnabilityClasses.ownable,
2599
+ winnability
2600
+ };
2601
+ }
2602
+ var ourBestPageSchema = z23.object({
2603
+ url: z23.string(),
2604
+ gscImpressions: z23.number().nonnegative(),
2605
+ gscClicks: z23.number().nonnegative(),
2306
2606
  // Null when the page came from the inventory fallback (no GSC ranking data).
2307
- gscAvgPosition: z20.number().nonnegative().nullable(),
2308
- organicSessions: z20.number().nonnegative()
2309
- });
2310
- var winningCompetitorSchema = z20.object({
2311
- domain: z20.string(),
2312
- url: z20.string(),
2313
- title: z20.string(),
2314
- citationCount: z20.number().int().nonnegative()
2315
- });
2316
- var scoreBreakdownSchema = z20.object({
2317
- demand: z20.number(),
2318
- competitor: z20.number(),
2319
- absence: z20.number(),
2320
- gapSeverity: z20.number()
2321
- });
2322
- var existingActionRefSchema = z20.object({
2323
- actionId: z20.string(),
2607
+ gscAvgPosition: z23.number().nonnegative().nullable(),
2608
+ organicSessions: z23.number().nonnegative()
2609
+ });
2610
+ var winningCompetitorSchema = z23.object({
2611
+ domain: z23.string(),
2612
+ url: z23.string(),
2613
+ title: z23.string(),
2614
+ citationCount: z23.number().int().nonnegative()
2615
+ });
2616
+ var scoreBreakdownSchema = z23.object({
2617
+ demand: z23.number(),
2618
+ competitor: z23.number(),
2619
+ absence: z23.number(),
2620
+ gapSeverity: z23.number()
2621
+ });
2622
+ var existingActionRefSchema = z23.object({
2623
+ actionId: z23.string(),
2324
2624
  state: contentActionStateSchema,
2325
- lastUpdated: z20.string()
2625
+ lastUpdated: z23.string()
2326
2626
  });
2327
- var contentTargetRowDtoSchema = z20.object({
2328
- targetRef: z20.string(),
2329
- query: z20.string(),
2627
+ var contentTargetRowDtoSchema = z23.object({
2628
+ targetRef: z23.string(),
2629
+ query: z23.string(),
2330
2630
  action: contentActionSchema,
2331
2631
  ourBestPage: ourBestPageSchema.nullable(),
2332
2632
  winningCompetitor: winningCompetitorSchema.nullable(),
2333
- score: z20.number(),
2633
+ score: z23.number(),
2334
2634
  scoreBreakdown: scoreBreakdownSchema,
2335
- drivers: z20.array(z20.string()),
2635
+ drivers: z23.array(z23.string()),
2336
2636
  demandSource: demandSourceSchema,
2337
2637
  actionConfidence: actionConfidenceSchema,
2338
- existingAction: existingActionRefSchema.nullable()
2339
- });
2340
- var contentTargetsResponseDtoSchema = z20.object({
2341
- targets: z20.array(contentTargetRowDtoSchema),
2342
- contextMetrics: z20.object({
2343
- totalAiReferralSessions: z20.number().int().nonnegative(),
2344
- latestRunId: z20.string(),
2345
- runTimestamp: z20.string()
2638
+ existingAction: existingActionRefSchema.nullable(),
2639
+ /**
2640
+ * Deterministic winnability gate. `ceded` ⇒ the cited surface is dominated by
2641
+ * aggregators/editorial and not worth chasing; `ownable` ⇒ worth a brief.
2642
+ * Derived (no LLM) from the discovery domain classifier.
2643
+ */
2644
+ winnabilityClass: winnabilityClassSchema,
2645
+ /**
2646
+ * Citation-weighted complement of the ceded share (`1 - cededShare`), in
2647
+ * `[0, 1]`. `null` when the gate failed open (no classification coverage for
2648
+ * the cited surface) — distinct from a computed `1.0`.
2649
+ */
2650
+ winnability: z23.number().min(0).max(1).nullable()
2651
+ });
2652
+ var contentTargetsResponseDtoSchema = z23.object({
2653
+ targets: z23.array(contentTargetRowDtoSchema),
2654
+ contextMetrics: z23.object({
2655
+ totalAiReferralSessions: z23.number().int().nonnegative(),
2656
+ latestRunId: z23.string(),
2657
+ runTimestamp: z23.string()
2346
2658
  })
2347
2659
  });
2348
- var contentTargetDismissalDtoSchema = z20.object({
2349
- targetRef: z20.string(),
2350
- addressedUrl: z20.string().nullable(),
2351
- note: z20.string().nullable(),
2352
- dismissedAt: z20.string()
2660
+ var contentTargetDismissalDtoSchema = z23.object({
2661
+ targetRef: z23.string(),
2662
+ addressedUrl: z23.string().nullable(),
2663
+ note: z23.string().nullable(),
2664
+ dismissedAt: z23.string()
2353
2665
  });
2354
- var contentTargetDismissalsResponseDtoSchema = z20.object({
2355
- dismissals: z20.array(contentTargetDismissalDtoSchema)
2666
+ var contentTargetDismissalsResponseDtoSchema = z23.object({
2667
+ dismissals: z23.array(contentTargetDismissalDtoSchema)
2356
2668
  });
2357
- var contentTargetDismissRequestSchema = z20.object({
2358
- targetRef: z20.string().min(1),
2669
+ var contentTargetDismissRequestSchema = z23.object({
2670
+ targetRef: z23.string().min(1),
2359
2671
  /** URL of the page the user wrote that addresses this recommendation. Stored verbatim for the audit trail; not currently used to suppress the slug-token matcher. */
2360
- addressedUrl: z20.string().url().optional(),
2672
+ addressedUrl: z23.string().url().optional(),
2361
2673
  /** Free-form note (e.g. "covered in our Q1 content sprint"). 500 char cap is the API surface limit; the DB column is unbounded. */
2362
- note: z20.string().max(500).optional()
2674
+ note: z23.string().max(500).optional()
2363
2675
  });
2364
- var recommendationExplanationDtoSchema = z20.object({
2365
- targetRef: z20.string(),
2676
+ var recommendationExplanationDtoSchema = z23.object({
2677
+ targetRef: z23.string(),
2366
2678
  /** Version of the prompt template used. Bumping the version invalidates the cache forward without touching the table. */
2367
- promptVersion: z20.string(),
2679
+ promptVersion: z23.string(),
2368
2680
  /** Provider that produced the explanation (e.g. "claude", "gemini"). */
2369
- provider: z20.string(),
2681
+ provider: z23.string(),
2370
2682
  /** Model id within that provider (e.g. "claude-sonnet-4-6"). */
2371
- model: z20.string(),
2683
+ model: z23.string(),
2372
2684
  /** Markdown-formatted rationale + recommended next steps. */
2373
- responseText: z20.string(),
2685
+ responseText: z23.string(),
2374
2686
  /** Estimated cost in millicents (1/100 of a cent). 0 when unknown. */
2375
- costMillicents: z20.number().int().nonnegative(),
2376
- generatedAt: z20.string()
2687
+ costMillicents: z23.number().int().nonnegative(),
2688
+ generatedAt: z23.string()
2377
2689
  });
2378
- var recommendationExplainRequestSchema = z20.object({
2690
+ var recommendationExplainRequestSchema = z23.object({
2379
2691
  /**
2380
2692
  * Optional provider override (e.g. "claude" to force Claude even if
2381
2693
  * the project's default is Gemini). Falls through to project default
2382
2694
  * → auto-detect when omitted.
2383
2695
  */
2384
- provider: z20.string().optional(),
2696
+ provider: z23.string().optional(),
2385
2697
  /**
2386
2698
  * Optional model override within the chosen provider. Falls through to
2387
2699
  * the `analyze`-tier default model when omitted.
2388
2700
  */
2389
- model: z20.string().optional(),
2701
+ model: z23.string().optional(),
2390
2702
  /**
2391
2703
  * Force a fresh LLM call even if a cached explanation exists for the
2392
2704
  * current prompt version. Use sparingly — defeats the cache.
2393
2705
  */
2394
- forceRefresh: z20.boolean().optional()
2395
- });
2396
- var contentGroundingSourceSchema = z20.object({
2397
- uri: z20.string(),
2398
- title: z20.string(),
2399
- domain: z20.string(),
2400
- isOurDomain: z20.boolean(),
2401
- isCompetitor: z20.boolean(),
2402
- citationCount: z20.number().int().nonnegative(),
2403
- providers: z20.array(providerNameSchema)
2404
- });
2405
- var contentSourceRowDtoSchema = z20.object({
2406
- query: z20.string(),
2407
- groundingSources: z20.array(contentGroundingSourceSchema)
2408
- });
2409
- var contentSourcesResponseDtoSchema = z20.object({
2410
- sources: z20.array(contentSourceRowDtoSchema),
2411
- latestRunId: z20.string()
2412
- });
2413
- var contentGapRowDtoSchema = z20.object({
2414
- query: z20.string(),
2415
- competitorDomains: z20.array(z20.string()),
2416
- competitorCount: z20.number().int().nonnegative(),
2417
- missRate: z20.number().min(0).max(1),
2418
- lastSeenInRunId: z20.string()
2419
- });
2420
- var contentGapsResponseDtoSchema = z20.object({
2421
- gaps: z20.array(contentGapRowDtoSchema),
2422
- latestRunId: z20.string()
2706
+ forceRefresh: z23.boolean().optional()
2707
+ });
2708
+ var contentBriefDtoSchema = z23.object({
2709
+ /** The query the brief is for (echoed from the recommendation). */
2710
+ targetQuery: z23.string().trim().min(1),
2711
+ /** Always `ownable` in practice — the gate rejects `ceded` before synthesis. */
2712
+ winnabilityClass: winnabilityClassSchema,
2713
+ /** The differentiated content angle to take. */
2714
+ angle: z23.string().trim().min(1),
2715
+ /** Why this query is winnable, citing the cited-surface signal. */
2716
+ whyWinnable: z23.string().trim().min(1),
2717
+ /** The schema.org type or markup to add or extend. */
2718
+ schemaHookup: z23.string().trim().min(1),
2719
+ /** Why the cited surface is controllable (the ownable-vs-ceded reasoning). */
2720
+ controllableSurfaceRationale: z23.string().trim().min(1)
2721
+ });
2722
+ var recommendationBriefDtoSchema = z23.object({
2723
+ targetRef: z23.string(),
2724
+ /** Version of the brief prompt template; bumping invalidates the cache forward. */
2725
+ promptVersion: z23.string(),
2726
+ provider: z23.string(),
2727
+ model: z23.string(),
2728
+ brief: contentBriefDtoSchema,
2729
+ /** Estimated cost in millicents (1/100 of a cent). 0 when unknown. */
2730
+ costMillicents: z23.number().int().nonnegative(),
2731
+ generatedAt: z23.string()
2732
+ });
2733
+ var domainClassificationDtoSchema = z23.object({
2734
+ domain: z23.string(),
2735
+ competitorType: discoveryCompetitorTypeSchema,
2736
+ hits: z23.number().int().nonnegative(),
2737
+ updatedAt: z23.string()
2738
+ });
2739
+ var domainClassificationsResponseDtoSchema = z23.object({
2740
+ classifications: z23.array(domainClassificationDtoSchema)
2741
+ });
2742
+ var contentGroundingSourceSchema = z23.object({
2743
+ uri: z23.string(),
2744
+ title: z23.string(),
2745
+ domain: z23.string(),
2746
+ isOurDomain: z23.boolean(),
2747
+ isCompetitor: z23.boolean(),
2748
+ citationCount: z23.number().int().nonnegative(),
2749
+ providers: z23.array(providerNameSchema)
2750
+ });
2751
+ var contentSourceRowDtoSchema = z23.object({
2752
+ query: z23.string(),
2753
+ groundingSources: z23.array(contentGroundingSourceSchema)
2754
+ });
2755
+ var contentSourcesResponseDtoSchema = z23.object({
2756
+ sources: z23.array(contentSourceRowDtoSchema),
2757
+ latestRunId: z23.string()
2758
+ });
2759
+ var contentGapRowDtoSchema = z23.object({
2760
+ query: z23.string(),
2761
+ competitorDomains: z23.array(z23.string()),
2762
+ competitorCount: z23.number().int().nonnegative(),
2763
+ missRate: z23.number().min(0).max(1),
2764
+ lastSeenInRunId: z23.string()
2765
+ });
2766
+ var contentGapsResponseDtoSchema = z23.object({
2767
+ gaps: z23.array(contentGapRowDtoSchema),
2768
+ latestRunId: z23.string()
2423
2769
  });
2424
2770
 
2425
2771
  // ../contracts/src/doctor.ts
2426
- import { z as z21 } from "zod";
2427
- var checkStatusSchema = z21.enum(["ok", "warn", "fail", "skipped"]);
2772
+ import { z as z24 } from "zod";
2773
+ var checkStatusSchema = z24.enum(["ok", "warn", "fail", "skipped"]);
2428
2774
  var CheckStatuses = checkStatusSchema.enum;
2429
- var checkScopeSchema = z21.enum(["global", "project"]);
2775
+ var checkScopeSchema = z24.enum(["global", "project"]);
2430
2776
  var CheckScopes = checkScopeSchema.enum;
2431
- var checkCategorySchema = z21.enum([
2777
+ var checkCategorySchema = z24.enum([
2432
2778
  "auth",
2433
2779
  "config",
2434
2780
  "providers",
@@ -2439,31 +2785,31 @@ var checkCategorySchema = z21.enum([
2439
2785
  "agent"
2440
2786
  ]);
2441
2787
  var CheckCategories = checkCategorySchema.enum;
2442
- var checkResultSchema = z21.object({
2443
- id: z21.string(),
2788
+ var checkResultSchema = z24.object({
2789
+ id: z24.string(),
2444
2790
  category: checkCategorySchema,
2445
2791
  scope: checkScopeSchema,
2446
- title: z21.string(),
2792
+ title: z24.string(),
2447
2793
  status: checkStatusSchema,
2448
- code: z21.string().describe('Stable machine-readable code (e.g. "google.token.refresh-failed"). Use this for filtering and remediation logic.'),
2449
- summary: z21.string(),
2450
- remediation: z21.string().nullable().optional().describe('Operator-facing next step. Null when status is "ok" or no specific remediation applies.'),
2451
- details: z21.record(z21.string(), z21.unknown()).optional().describe("Structured context \u2014 principal email, redirect URI, missing scopes, etc. Stable per check id."),
2452
- durationMs: z21.number().int().nonnegative().describe("How long the check took to execute.")
2794
+ code: z24.string().describe('Stable machine-readable code (e.g. "google.token.refresh-failed"). Use this for filtering and remediation logic.'),
2795
+ summary: z24.string(),
2796
+ remediation: z24.string().nullable().optional().describe('Operator-facing next step. Null when status is "ok" or no specific remediation applies.'),
2797
+ details: z24.record(z24.string(), z24.unknown()).optional().describe("Structured context \u2014 principal email, redirect URI, missing scopes, etc. Stable per check id."),
2798
+ durationMs: z24.number().int().nonnegative().describe("How long the check took to execute.")
2453
2799
  });
2454
- var doctorReportSchema = z21.object({
2800
+ var doctorReportSchema = z24.object({
2455
2801
  scope: checkScopeSchema,
2456
- project: z21.string().nullable().describe('Project name when scope is "project", null otherwise.'),
2457
- generatedAt: z21.string().describe("ISO-8601 timestamp when this doctor run started."),
2458
- durationMs: z21.number().int().nonnegative(),
2459
- summary: z21.object({
2460
- total: z21.number().int().nonnegative(),
2461
- ok: z21.number().int().nonnegative(),
2462
- warn: z21.number().int().nonnegative(),
2463
- fail: z21.number().int().nonnegative(),
2464
- skipped: z21.number().int().nonnegative()
2802
+ project: z24.string().nullable().describe('Project name when scope is "project", null otherwise.'),
2803
+ generatedAt: z24.string().describe("ISO-8601 timestamp when this doctor run started."),
2804
+ durationMs: z24.number().int().nonnegative(),
2805
+ summary: z24.object({
2806
+ total: z24.number().int().nonnegative(),
2807
+ ok: z24.number().int().nonnegative(),
2808
+ warn: z24.number().int().nonnegative(),
2809
+ fail: z24.number().int().nonnegative(),
2810
+ skipped: z24.number().int().nonnegative()
2465
2811
  }),
2466
- checks: z21.array(checkResultSchema)
2812
+ checks: z24.array(checkResultSchema)
2467
2813
  });
2468
2814
  function summarizeCheckResults(results) {
2469
2815
  const summary = { total: results.length, ok: 0, warn: 0, fail: 0, skipped: 0 };
@@ -2609,52 +2955,52 @@ function normalizeUrlPath(input) {
2609
2955
  }
2610
2956
 
2611
2957
  // ../contracts/src/citations.ts
2612
- import { z as z22 } from "zod";
2613
- var citationCoverageProviderSchema = z22.object({
2614
- provider: z22.string(),
2958
+ import { z as z25 } from "zod";
2959
+ var citationCoverageProviderSchema = z25.object({
2960
+ provider: z25.string(),
2615
2961
  citationState: citationStateSchema,
2616
- cited: z22.boolean(),
2617
- mentioned: z22.boolean(),
2618
- runId: z22.string(),
2619
- runCreatedAt: z22.string()
2620
- });
2621
- var citationCoverageRowSchema = z22.object({
2622
- queryId: z22.string(),
2623
- query: z22.string(),
2624
- providers: z22.array(citationCoverageProviderSchema),
2625
- citedCount: z22.number().int().nonnegative(),
2626
- mentionedCount: z22.number().int().nonnegative(),
2627
- totalProviders: z22.number().int().nonnegative()
2628
- });
2629
- var competitorGapRowSchema = z22.object({
2630
- queryId: z22.string(),
2631
- query: z22.string(),
2632
- provider: z22.string(),
2633
- citingCompetitors: z22.array(z22.string()),
2634
- runId: z22.string(),
2635
- runCreatedAt: z22.string()
2962
+ cited: z25.boolean(),
2963
+ mentioned: z25.boolean(),
2964
+ runId: z25.string(),
2965
+ runCreatedAt: z25.string()
2966
+ });
2967
+ var citationCoverageRowSchema = z25.object({
2968
+ queryId: z25.string(),
2969
+ query: z25.string(),
2970
+ providers: z25.array(citationCoverageProviderSchema),
2971
+ citedCount: z25.number().int().nonnegative(),
2972
+ mentionedCount: z25.number().int().nonnegative(),
2973
+ totalProviders: z25.number().int().nonnegative()
2974
+ });
2975
+ var competitorGapRowSchema = z25.object({
2976
+ queryId: z25.string(),
2977
+ query: z25.string(),
2978
+ provider: z25.string(),
2979
+ citingCompetitors: z25.array(z25.string()),
2980
+ runId: z25.string(),
2981
+ runCreatedAt: z25.string()
2636
2982
  });
2637
- var citationVisibilitySummarySchema = z22.object({
2638
- providersConfigured: z22.number().int().nonnegative(),
2639
- providersCiting: z22.number().int().nonnegative(),
2640
- providersMentioning: z22.number().int().nonnegative(),
2641
- totalQueries: z22.number().int().nonnegative(),
2983
+ var citationVisibilitySummarySchema = z25.object({
2984
+ providersConfigured: z25.number().int().nonnegative(),
2985
+ providersCiting: z25.number().int().nonnegative(),
2986
+ providersMentioning: z25.number().int().nonnegative(),
2987
+ totalQueries: z25.number().int().nonnegative(),
2642
2988
  // Cross-tab buckets — each tracked query with at least one snapshot lands
2643
2989
  // in exactly one of these. Queries with zero snapshots are not counted in
2644
2990
  // any bucket; (sum of buckets) ≤ totalQueries.
2645
- queriesCitedAndMentioned: z22.number().int().nonnegative(),
2646
- queriesCitedOnly: z22.number().int().nonnegative(),
2647
- queriesMentionedOnly: z22.number().int().nonnegative(),
2648
- queriesInvisible: z22.number().int().nonnegative(),
2649
- latestRunId: z22.string().nullable(),
2650
- latestRunAt: z22.string().nullable()
2651
- });
2652
- var citationVisibilityResponseSchema = z22.object({
2991
+ queriesCitedAndMentioned: z25.number().int().nonnegative(),
2992
+ queriesCitedOnly: z25.number().int().nonnegative(),
2993
+ queriesMentionedOnly: z25.number().int().nonnegative(),
2994
+ queriesInvisible: z25.number().int().nonnegative(),
2995
+ latestRunId: z25.string().nullable(),
2996
+ latestRunAt: z25.string().nullable()
2997
+ });
2998
+ var citationVisibilityResponseSchema = z25.object({
2653
2999
  summary: citationVisibilitySummarySchema,
2654
- byQuery: z22.array(citationCoverageRowSchema),
2655
- competitorGaps: z22.array(competitorGapRowSchema),
2656
- status: z22.enum(["ready", "no-data"]),
2657
- reason: z22.enum(["no-runs-yet", "no-queries"]).optional()
3000
+ byQuery: z25.array(citationCoverageRowSchema),
3001
+ competitorGaps: z25.array(competitorGapRowSchema),
3002
+ status: z25.enum(["ready", "no-data"]),
3003
+ reason: z25.enum(["no-runs-yet", "no-queries"]).optional()
2658
3004
  });
2659
3005
  function emptyCitationVisibility(reason) {
2660
3006
  return {
@@ -2681,46 +3027,46 @@ function citationStateToCited(state) {
2681
3027
  }
2682
3028
 
2683
3029
  // ../contracts/src/report.ts
2684
- import { z as z23 } from "zod";
2685
- var providerLocationTreatmentSchema = z23.enum([
3030
+ import { z as z26 } from "zod";
3031
+ var providerLocationTreatmentSchema = z26.enum([
2686
3032
  "prompt",
2687
3033
  "request-param",
2688
3034
  "browser-geo",
2689
3035
  "ignored"
2690
3036
  ]);
2691
- var reportMetaLocationSchema = z23.object({
3037
+ var reportMetaLocationSchema = z26.object({
2692
3038
  /** Human-readable label as configured on the project (e.g. "michigan"). */
2693
- label: z23.string(),
3039
+ label: z26.string(),
2694
3040
  /** Resolved city/region/country from the project's `LocationContext`. */
2695
- city: z23.string(),
2696
- region: z23.string(),
2697
- country: z23.string(),
3041
+ city: z26.string(),
3042
+ region: z26.string(),
3043
+ country: z26.string(),
2698
3044
  /**
2699
3045
  * Other locations configured on the project that did NOT power this report.
2700
3046
  * When non-empty, callers should make clear that the report is location-scoped:
2701
3047
  * a separate sweep is needed to see how AI engines respond from each one.
2702
3048
  */
2703
- otherConfiguredLabels: z23.array(z23.string())
3049
+ otherConfiguredLabels: z26.array(z26.string())
2704
3050
  });
2705
- var reportProviderLocationHandlingSchema = z23.object({
3051
+ var reportProviderLocationHandlingSchema = z26.object({
2706
3052
  /** Provider name (matches `query_snapshots.provider`). */
2707
- provider: z23.string(),
3053
+ provider: z26.string(),
2708
3054
  /** How this provider applied the configured location during this run. */
2709
3055
  treatment: providerLocationTreatmentSchema,
2710
3056
  /** One-sentence explanation suitable for the report. */
2711
- description: z23.string()
3057
+ description: z26.string()
2712
3058
  });
2713
- var reportMetaSchema = z23.object({
3059
+ var reportMetaSchema = z26.object({
2714
3060
  /** ISO timestamp the report was generated (server clock). */
2715
- generatedAt: z23.string(),
3061
+ generatedAt: z26.string(),
2716
3062
  /** Project the report covers. */
2717
- project: z23.object({
2718
- id: z23.string(),
2719
- name: z23.string(),
2720
- displayName: z23.string(),
2721
- canonicalDomain: z23.string(),
2722
- country: z23.string(),
2723
- language: z23.string()
3063
+ project: z26.object({
3064
+ id: z26.string(),
3065
+ name: z26.string(),
3066
+ displayName: z26.string(),
3067
+ canonicalDomain: z26.string(),
3068
+ country: z26.string(),
3069
+ language: z26.string()
2724
3070
  }),
2725
3071
  /**
2726
3072
  * The location that powered the latest visibility run, when one was set.
@@ -2735,24 +3081,24 @@ var reportMetaSchema = z23.object({
2735
3081
  * each provider's answer — some providers append it to the prompt, some
2736
3082
  * pass it as a structured request field, and some (CDP) ignore it.
2737
3083
  */
2738
- providerLocationHandling: z23.array(reportProviderLocationHandlingSchema),
3084
+ providerLocationHandling: z26.array(reportProviderLocationHandlingSchema),
2739
3085
  /** Earliest data point referenced by the report (ISO date). */
2740
- periodStart: z23.string().nullable(),
3086
+ periodStart: z26.string().nullable(),
2741
3087
  /** Latest data point referenced by the report (ISO date). */
2742
- periodEnd: z23.string().nullable()
3088
+ periodEnd: z26.string().nullable()
2743
3089
  });
2744
- var reportExecutiveSummarySchema = z23.object({
3090
+ var reportExecutiveSummarySchema = z26.object({
2745
3091
  /**
2746
3092
  * 0..100 — share of tracked queries that were cited by at least one
2747
3093
  * provider in the latest run. "Cited" means the project's domain appeared
2748
3094
  * in the source list / grounding the AI used to answer. Computed per-query
2749
3095
  * (not per-(query × provider)) so the rate is invariant to provider count.
2750
3096
  */
2751
- citationRate: z23.number(),
3097
+ citationRate: z26.number(),
2752
3098
  /** Numerator of `citationRate` — distinct tracked queries cited by ≥1 provider in the latest run. */
2753
- citedQueryCount: z23.number(),
3099
+ citedQueryCount: z26.number(),
2754
3100
  /** Denominator of `citationRate` — total tracked queries. */
2755
- totalQueryCount: z23.number(),
3101
+ totalQueryCount: z26.number(),
2756
3102
  /**
2757
3103
  * 0..100 — share of tracked queries where the project's brand or domain
2758
3104
  * appeared in at least one provider's answer text in the latest run.
@@ -2760,68 +3106,68 @@ var reportExecutiveSummarySchema = z23.object({
2760
3106
  * the prose without citing your domain in its sources, and vice versa.
2761
3107
  * Same per-query denominator as `citationRate` for consistency.
2762
3108
  */
2763
- mentionRate: z23.number(),
3109
+ mentionRate: z26.number(),
2764
3110
  /** Numerator of `mentionRate` — distinct tracked queries mentioned in ≥1 provider's answer text. */
2765
- mentionedQueryCount: z23.number(),
3111
+ mentionedQueryCount: z26.number(),
2766
3112
  /** Compared to the previous run: 'up' | 'down' | 'flat' | 'unknown' (no prior run). */
2767
- trend: z23.enum(["up", "down", "flat", "unknown"]),
3113
+ trend: z26.enum(["up", "down", "flat", "unknown"]),
2768
3114
  /** Total tracked queries. */
2769
- queryCount: z23.number(),
3115
+ queryCount: z26.number(),
2770
3116
  /** Total tracked competitors. */
2771
- competitorCount: z23.number(),
3117
+ competitorCount: z26.number(),
2772
3118
  /** Number of providers in the latest run. */
2773
- providerCount: z23.number(),
3119
+ providerCount: z26.number(),
2774
3120
  /** GSC totals across the most-recent sync window. Null when GSC is not connected. */
2775
- gsc: z23.object({
2776
- clicks: z23.number(),
2777
- impressions: z23.number(),
2778
- ctr: z23.number(),
2779
- avgPosition: z23.number(),
2780
- periodStart: z23.string(),
2781
- periodEnd: z23.string()
3121
+ gsc: z26.object({
3122
+ clicks: z26.number(),
3123
+ impressions: z26.number(),
3124
+ ctr: z26.number(),
3125
+ avgPosition: z26.number(),
3126
+ periodStart: z26.string(),
3127
+ periodEnd: z26.string()
2782
3128
  }).nullable(),
2783
3129
  /** GA4 totals across the most-recent sync period. Null when GA4 is not connected. */
2784
- ga: z23.object({
2785
- sessions: z23.number(),
2786
- users: z23.number(),
2787
- periodStart: z23.string(),
2788
- periodEnd: z23.string()
3130
+ ga: z26.object({
3131
+ sessions: z26.number(),
3132
+ users: z26.number(),
3133
+ periodStart: z26.string(),
3134
+ periodEnd: z26.string()
2789
3135
  }).nullable(),
2790
3136
  /** Top 3-5 findings, each rendered as a single-sentence narrative. */
2791
- findings: z23.array(z23.object({
2792
- title: z23.string(),
2793
- detail: z23.string(),
2794
- tone: z23.enum(["positive", "caution", "negative", "neutral"])
3137
+ findings: z26.array(z26.object({
3138
+ title: z26.string(),
3139
+ detail: z26.string(),
3140
+ tone: z26.enum(["positive", "caution", "negative", "neutral"])
2795
3141
  }))
2796
3142
  });
2797
- var citationCellSchema = z23.object({
2798
- citationState: z23.enum(["cited", "not-cited", "pending"]),
2799
- answerMentioned: z23.boolean().nullable(),
2800
- model: z23.string().nullable()
3143
+ var citationCellSchema = z26.object({
3144
+ citationState: z26.enum(["cited", "not-cited", "pending"]),
3145
+ answerMentioned: z26.boolean().nullable(),
3146
+ model: z26.string().nullable()
2801
3147
  });
2802
- var citationScorecardSchema = z23.object({
2803
- queries: z23.array(z23.string()),
2804
- providers: z23.array(z23.string()),
3148
+ var citationScorecardSchema = z26.object({
3149
+ queries: z26.array(z26.string()),
3150
+ providers: z26.array(z26.string()),
2805
3151
  /** matrix[queryIndex][providerIndex] — null when no snapshot exists for the pair. */
2806
- matrix: z23.array(z23.array(citationCellSchema.nullable())),
3152
+ matrix: z26.array(z26.array(citationCellSchema.nullable())),
2807
3153
  /** Per-provider citation rate (0..100). */
2808
- providerRates: z23.array(z23.object({
2809
- provider: z23.string(),
2810
- citedCount: z23.number(),
2811
- totalCount: z23.number(),
2812
- citationRate: z23.number()
3154
+ providerRates: z26.array(z26.object({
3155
+ provider: z26.string(),
3156
+ citedCount: z26.number(),
3157
+ totalCount: z26.number(),
3158
+ citationRate: z26.number()
2813
3159
  }))
2814
3160
  });
2815
- var competitorRowSchema = z23.object({
2816
- domain: z23.string(),
3161
+ var competitorRowSchema = z26.object({
3162
+ domain: z26.string(),
2817
3163
  /** Number of (query × provider) pairs that cited this competitor. */
2818
- citationCount: z23.number(),
3164
+ citationCount: z26.number(),
2819
3165
  /** Out-of count for the same denominator. */
2820
- totalCount: z23.number(),
3166
+ totalCount: z26.number(),
2821
3167
  /** 'High' | 'Moderate' | 'Low' | 'None' — from buildPortfolioProject pressure logic. */
2822
- pressureLabel: z23.enum(["High", "Moderate", "Low", "None"]),
3168
+ pressureLabel: z26.enum(["High", "Moderate", "Low", "None"]),
2823
3169
  /** Distinct queries on which this competitor was cited. */
2824
- citedQueries: z23.array(z23.string()),
3170
+ citedQueries: z26.array(z26.string()),
2825
3171
  /**
2826
3172
  * Citation share 0..100. Numerator = this competitor's `citationCount`.
2827
3173
  * Denominator = sum of `citationCount` across all competitors plus the
@@ -2829,30 +3175,30 @@ var competitorRowSchema = z23.object({
2829
3175
  * slots in the snapshot. Distinct from the project-level Mention Share
2830
3176
  * gauge — that one is brand-in-answer-text, this one is domain-in-source-list.
2831
3177
  */
2832
- sharePct: z23.number(),
3178
+ sharePct: z26.number(),
2833
3179
  /**
2834
3180
  * URLs from the latest run's grounding sources whose host matches this
2835
3181
  * competitor's domain, with the queries each URL was cited for. Empty
2836
3182
  * when no grounding-source data is available (e.g. no `rawResponse` JSON
2837
3183
  * stored for the snapshots).
2838
3184
  */
2839
- theirCitedPages: z23.array(z23.object({ url: z23.string(), citedFor: z23.array(z23.string()) }))
3185
+ theirCitedPages: z26.array(z26.object({ url: z26.string(), citedFor: z26.array(z26.string()) }))
2840
3186
  });
2841
- var competitorLandscapeSchema = z23.object({
3187
+ var competitorLandscapeSchema = z26.object({
2842
3188
  /** Project's own citation count (for the bar chart comparing project vs competitors). */
2843
- projectCitationCount: z23.number(),
2844
- competitors: z23.array(competitorRowSchema)
3189
+ projectCitationCount: z26.number(),
3190
+ competitors: z26.array(competitorRowSchema)
2845
3191
  });
2846
- var mentionRowSchema = z23.object({
2847
- domain: z23.string(),
3192
+ var mentionRowSchema = z26.object({
3193
+ domain: z26.string(),
2848
3194
  /** Number of (query × provider) pairs whose answer text mentioned this competitor's brand or domain. */
2849
- mentionCount: z23.number(),
3195
+ mentionCount: z26.number(),
2850
3196
  /** Out-of count for the same denominator (snapshots that had answer text). */
2851
- totalCount: z23.number(),
3197
+ totalCount: z26.number(),
2852
3198
  /** 'High' | 'Moderate' | 'Low' | 'None' — mention frequency tier (mirrors CompetitorRow.pressureLabel). */
2853
- pressureLabel: z23.enum(["High", "Moderate", "Low", "None"]),
3199
+ pressureLabel: z26.enum(["High", "Moderate", "Low", "None"]),
2854
3200
  /** Distinct queries on which this competitor was mentioned. */
2855
- mentionedQueries: z23.array(z23.string()),
3201
+ mentionedQueries: z26.array(z26.string()),
2856
3202
  /**
2857
3203
  * Mention share 0..100. Numerator = this competitor's `mentionCount`.
2858
3204
  * Denominator = sum of `mentionCount` across all competitors plus the
@@ -2860,129 +3206,129 @@ var mentionRowSchema = z23.object({
2860
3206
  * mention. Per-competitor split of the same head-to-head measure the
2861
3207
  * project's hero `MentionShareDto` gauge headlines.
2862
3208
  */
2863
- sharePct: z23.number()
3209
+ sharePct: z26.number()
2864
3210
  });
2865
- var mentionLandscapeSchema = z23.object({
3211
+ var mentionLandscapeSchema = z26.object({
2866
3212
  /** Project's own mention count (for the bar chart comparing project vs competitors). */
2867
- projectMentionCount: z23.number(),
3213
+ projectMentionCount: z26.number(),
2868
3214
  /** Snapshots considered — those with non-empty answerText. Drives the totalCount denominator. */
2869
- totalAnswerSnapshots: z23.number(),
2870
- competitors: z23.array(mentionRowSchema)
3215
+ totalAnswerSnapshots: z26.number(),
3216
+ competitors: z26.array(mentionRowSchema)
2871
3217
  });
2872
- var aiSourceCategoryBucketSchema = z23.object({
3218
+ var aiSourceCategoryBucketSchema = z26.object({
2873
3219
  /** Category slug from packages/contracts/src/source-categories. */
2874
- category: z23.string(),
3220
+ category: z26.string(),
2875
3221
  /** Display label. */
2876
- label: z23.string(),
3222
+ label: z26.string(),
2877
3223
  /** Number of citations falling in this category. */
2878
- count: z23.number(),
3224
+ count: z26.number(),
2879
3225
  /** 0..100 share of total citations. */
2880
- sharePct: z23.number()
3226
+ sharePct: z26.number()
2881
3227
  });
2882
- var aiSourceOriginSchema = z23.object({
2883
- categories: z23.array(aiSourceCategoryBucketSchema),
3228
+ var aiSourceOriginSchema = z26.object({
3229
+ categories: z26.array(aiSourceCategoryBucketSchema),
2884
3230
  /** Top 20 source domains by citation count (excluding the project's own domain). */
2885
- topDomains: z23.array(z23.object({
2886
- domain: z23.string(),
2887
- count: z23.number(),
3231
+ topDomains: z26.array(z26.object({
3232
+ domain: z26.string(),
3233
+ count: z26.number(),
2888
3234
  /** True when the domain is one of the project's tracked competitors. */
2889
- isCompetitor: z23.boolean()
3235
+ isCompetitor: z26.boolean()
2890
3236
  }))
2891
3237
  });
2892
- var gscQueryRowSchema = z23.object({
2893
- query: z23.string(),
2894
- clicks: z23.number(),
2895
- impressions: z23.number(),
2896
- ctr: z23.number(),
2897
- avgPosition: z23.number(),
3238
+ var gscQueryRowSchema = z26.object({
3239
+ query: z26.string(),
3240
+ clicks: z26.number(),
3241
+ impressions: z26.number(),
3242
+ ctr: z26.number(),
3243
+ avgPosition: z26.number(),
2898
3244
  /** Heuristic categorization: 'brand' | 'lead-gen' | 'industry' | 'other'. */
2899
- category: z23.enum(["brand", "lead-gen", "industry", "other"])
2900
- });
2901
- var gscSectionSchema = z23.object({
2902
- periodStart: z23.string(),
2903
- periodEnd: z23.string(),
2904
- totalClicks: z23.number(),
2905
- totalImpressions: z23.number(),
2906
- ctr: z23.number(),
2907
- avgPosition: z23.number(),
2908
- topQueries: z23.array(gscQueryRowSchema),
2909
- categoryBreakdown: z23.array(z23.object({
2910
- category: z23.enum(["brand", "lead-gen", "industry", "other"]),
2911
- clicks: z23.number(),
2912
- impressions: z23.number(),
2913
- sharePct: z23.number()
3245
+ category: z26.enum(["brand", "lead-gen", "industry", "other"])
3246
+ });
3247
+ var gscSectionSchema = z26.object({
3248
+ periodStart: z26.string(),
3249
+ periodEnd: z26.string(),
3250
+ totalClicks: z26.number(),
3251
+ totalImpressions: z26.number(),
3252
+ ctr: z26.number(),
3253
+ avgPosition: z26.number(),
3254
+ topQueries: z26.array(gscQueryRowSchema),
3255
+ categoryBreakdown: z26.array(z26.object({
3256
+ category: z26.enum(["brand", "lead-gen", "industry", "other"]),
3257
+ clicks: z26.number(),
3258
+ impressions: z26.number(),
3259
+ sharePct: z26.number()
2914
3260
  })),
2915
- trend: z23.array(z23.object({ date: z23.string(), clicks: z23.number(), impressions: z23.number() })),
3261
+ trend: z26.array(z26.object({ date: z26.string(), clicks: z26.number(), impressions: z26.number() })),
2916
3262
  /**
2917
3263
  * Tracked AEO queries that have no GSC impressions in the report window.
2918
3264
  * Surfaces queries that may not represent real search demand.
2919
3265
  */
2920
- trackedButNoGsc: z23.array(z23.string()),
3266
+ trackedButNoGsc: z26.array(z26.string()),
2921
3267
  /**
2922
3268
  * GSC top queries (sorted by impressions desc) that are not tracked as
2923
3269
  * AEO queries — the candidate set for adding to the AEO project.
2924
3270
  */
2925
- gscButNotTracked: z23.array(z23.string())
2926
- });
2927
- var gaTrafficSectionSchema = z23.object({
2928
- totalSessions: z23.number(),
2929
- totalUsers: z23.number(),
2930
- totalOrganicSessions: z23.number(),
2931
- periodStart: z23.string(),
2932
- periodEnd: z23.string(),
2933
- topLandingPages: z23.array(z23.object({
2934
- page: z23.string(),
2935
- sessions: z23.number(),
2936
- users: z23.number(),
2937
- organicSessions: z23.number()
3271
+ gscButNotTracked: z26.array(z26.string())
3272
+ });
3273
+ var gaTrafficSectionSchema = z26.object({
3274
+ totalSessions: z26.number(),
3275
+ totalUsers: z26.number(),
3276
+ totalOrganicSessions: z26.number(),
3277
+ periodStart: z26.string(),
3278
+ periodEnd: z26.string(),
3279
+ topLandingPages: z26.array(z26.object({
3280
+ page: z26.string(),
3281
+ sessions: z26.number(),
3282
+ users: z26.number(),
3283
+ organicSessions: z26.number()
2938
3284
  })),
2939
- channelBreakdown: z23.array(z23.object({
2940
- channel: z23.string(),
2941
- sessions: z23.number(),
2942
- sharePct: z23.number()
3285
+ channelBreakdown: z26.array(z26.object({
3286
+ channel: z26.string(),
3287
+ sessions: z26.number(),
3288
+ sharePct: z26.number()
2943
3289
  }))
2944
3290
  });
2945
- var socialReferralSectionSchema = z23.object({
2946
- totalSessions: z23.number(),
2947
- organicSessions: z23.number(),
2948
- paidSessions: z23.number(),
2949
- channels: z23.array(z23.object({
2950
- channelGroup: z23.string(),
2951
- sessions: z23.number(),
2952
- sharePct: z23.number()
3291
+ var socialReferralSectionSchema = z26.object({
3292
+ totalSessions: z26.number(),
3293
+ organicSessions: z26.number(),
3294
+ paidSessions: z26.number(),
3295
+ channels: z26.array(z26.object({
3296
+ channelGroup: z26.string(),
3297
+ sessions: z26.number(),
3298
+ sharePct: z26.number()
2953
3299
  })),
2954
- topCampaigns: z23.array(z23.object({
2955
- source: z23.string(),
2956
- medium: z23.string(),
2957
- sessions: z23.number()
3300
+ topCampaigns: z26.array(z26.object({
3301
+ source: z26.string(),
3302
+ medium: z26.string(),
3303
+ sessions: z26.number()
2958
3304
  }))
2959
3305
  });
2960
- var aiReferralSectionSchema = z23.object({
2961
- totalSessions: z23.number(),
2962
- totalUsers: z23.number(),
2963
- bySource: z23.array(z23.object({
2964
- source: z23.string(),
2965
- sessions: z23.number(),
2966
- users: z23.number(),
2967
- sharePct: z23.number()
3306
+ var aiReferralSectionSchema = z26.object({
3307
+ totalSessions: z26.number(),
3308
+ totalUsers: z26.number(),
3309
+ bySource: z26.array(z26.object({
3310
+ source: z26.string(),
3311
+ sessions: z26.number(),
3312
+ users: z26.number(),
3313
+ sharePct: z26.number()
2968
3314
  })),
2969
- trend: z23.array(z23.object({ date: z23.string(), sessions: z23.number() })),
2970
- topLandingPages: z23.array(z23.object({
2971
- page: z23.string(),
2972
- sessions: z23.number(),
2973
- users: z23.number()
3315
+ trend: z26.array(z26.object({ date: z26.string(), sessions: z26.number() })),
3316
+ topLandingPages: z26.array(z26.object({
3317
+ page: z26.string(),
3318
+ sessions: z26.number(),
3319
+ users: z26.number()
2974
3320
  }))
2975
3321
  });
2976
- var serverActivitySectionSchema = z23.object({
3322
+ var serverActivitySectionSchema = z26.object({
2977
3323
  /** ISO8601 inclusive lower bound of the report window (default: 7 days). */
2978
- windowStart: z23.string(),
3324
+ windowStart: z26.string(),
2979
3325
  /** ISO8601 inclusive upper bound. */
2980
- windowEnd: z23.string(),
2981
- hasData: z23.boolean(),
3326
+ windowEnd: z26.string(),
3327
+ hasData: z26.boolean(),
2982
3328
  /** Last-7d total verified crawler hits, with prior 7d for delta. */
2983
- verifiedCrawlerHits: z23.object({ current: z23.number(), prior: z23.number(), deltaPct: z23.number().nullable() }),
3329
+ verifiedCrawlerHits: z26.object({ current: z26.number(), prior: z26.number(), deltaPct: z26.number().nullable() }),
2984
3330
  /** Last-7d total unverified crawler hits, separated from verified trust metrics. */
2985
- unverifiedCrawlerHits: z23.object({ current: z23.number(), prior: z23.number(), deltaPct: z23.number().nullable() }),
3331
+ unverifiedCrawlerHits: z26.object({ current: z26.number(), prior: z26.number(), deltaPct: z26.number().nullable() }),
2986
3332
  /**
2987
3333
  * Last-7d on-demand per-user fetches from AI surfaces (ChatGPT-User,
2988
3334
  * Perplexity-User, MistralAI-User). Disjoint from `verifiedCrawlerHits` /
@@ -2991,19 +3337,19 @@ var serverActivitySectionSchema = z23.object({
2991
3337
  * because the operational question for user-fetch is "is this happening?"
2992
3338
  * not "is this a confirmed bot identity?"
2993
3339
  */
2994
- aiUserFetchHits: z23.object({ current: z23.number(), prior: z23.number(), deltaPct: z23.number().nullable() }),
3340
+ aiUserFetchHits: z26.object({ current: z26.number(), prior: z26.number(), deltaPct: z26.number().nullable() }),
2995
3341
  /** Last-7d AI-referral sessions (sessionized from server-side request evidence). */
2996
- referralArrivals: z23.object({ current: z23.number(), prior: z23.number(), deltaPct: z23.number().nullable() }),
3342
+ referralArrivals: z26.object({ current: z26.number(), prior: z26.number(), deltaPct: z26.number().nullable() }),
2997
3343
  /** Per-AI-operator breakdown (OpenAI, Anthropic, Google AI, Perplexity, …). */
2998
- byOperator: z23.array(z23.object({
2999
- operator: z23.string(),
3000
- verifiedHits: z23.number(),
3344
+ byOperator: z26.array(z26.object({
3345
+ operator: z26.string(),
3346
+ verifiedHits: z26.number(),
3001
3347
  /** Shown to agency audience only: claimed-bot UA, source IP not in a published range. */
3002
- unverifiedHits: z23.number(),
3348
+ unverifiedHits: z26.number(),
3003
3349
  /** Per-user fetches from this operator's AI surface (ChatGPT-User, …). */
3004
- userFetchHits: z23.number(),
3005
- referralArrivals: z23.number(),
3006
- deltaPct: z23.number().nullable()
3350
+ userFetchHits: z26.number(),
3351
+ referralArrivals: z26.number(),
3352
+ deltaPct: z26.number().nullable()
3007
3353
  })),
3008
3354
  /**
3009
3355
  * Top crawled paths (verified only, last-7d). Path-level citation cross-reference
@@ -3013,84 +3359,84 @@ var serverActivitySectionSchema = z23.object({
3013
3359
  * citation evidence can extend this entry with a `citationState` field without
3014
3360
  * breaking the contract.
3015
3361
  */
3016
- topCrawledPaths: z23.array(z23.object({
3017
- path: z23.string(),
3018
- verifiedHits: z23.number(),
3362
+ topCrawledPaths: z26.array(z26.object({
3363
+ path: z26.string(),
3364
+ verifiedHits: z26.number(),
3019
3365
  /** How many distinct AI operators crawled this path in the window. */
3020
- distinctOperators: z23.number()
3366
+ distinctOperators: z26.number()
3021
3367
  })),
3022
3368
  /** AI products that sent ≥1 session in the window (referral by destination). */
3023
- referralProducts: z23.array(z23.object({
3024
- product: z23.string(),
3025
- arrivals: z23.number(),
3026
- distinctLandingPaths: z23.number()
3369
+ referralProducts: z26.array(z26.object({
3370
+ product: z26.string(),
3371
+ arrivals: z26.number(),
3372
+ distinctLandingPaths: z26.number()
3027
3373
  })),
3028
3374
  /** Daily trend, last 14d for sparkline / chart rendering. */
3029
- dailyTrend: z23.array(z23.object({
3030
- date: z23.string(),
3031
- verifiedCrawlerHits: z23.number(),
3032
- userFetchHits: z23.number(),
3033
- referralArrivals: z23.number()
3375
+ dailyTrend: z26.array(z26.object({
3376
+ date: z26.string(),
3377
+ verifiedCrawlerHits: z26.number(),
3378
+ userFetchHits: z26.number(),
3379
+ referralArrivals: z26.number()
3034
3380
  })),
3035
3381
  /**
3036
3382
  * Top landing paths for AI-referral sessions (last-7d).
3037
3383
  * Complements `topCrawledPaths` (what bots fetch) with what humans actually land on.
3038
3384
  */
3039
- topReferralLandingPaths: z23.array(z23.object({
3040
- path: z23.string(),
3041
- arrivals: z23.number(),
3042
- distinctProducts: z23.number()
3385
+ topReferralLandingPaths: z26.array(z26.object({
3386
+ path: z26.string(),
3387
+ arrivals: z26.number(),
3388
+ distinctProducts: z26.number()
3043
3389
  }))
3044
3390
  });
3045
- var indexingHealthSectionSchema = z23.object({
3391
+ var indexingHealthSectionSchema = z26.object({
3046
3392
  /** Source: 'google' | 'bing' | null when neither is connected. */
3047
- provider: z23.enum(["google", "bing"]).nullable(),
3048
- total: z23.number(),
3049
- indexed: z23.number(),
3050
- notIndexed: z23.number(),
3393
+ provider: z26.enum(["google", "bing"]).nullable(),
3394
+ total: z26.number(),
3395
+ indexed: z26.number(),
3396
+ notIndexed: z26.number(),
3051
3397
  /** Google-only — pages explicitly marked as deindexed. Bing reports 'unknown' instead. */
3052
- deindexed: z23.number(),
3398
+ deindexed: z26.number(),
3053
3399
  /** Bing-only — pages with no inspection data yet. */
3054
- unknown: z23.number(),
3400
+ unknown: z26.number(),
3055
3401
  /** 0..100. */
3056
- indexedPct: z23.number()
3402
+ indexedPct: z26.number()
3057
3403
  });
3058
- var citationsTrendPointSchema = z23.object({
3404
+ var citationsTrendPointSchema = z26.object({
3059
3405
  /** Run ID — anchor for cross-section linking. */
3060
- runId: z23.string(),
3406
+ runId: z26.string(),
3061
3407
  /** ISO timestamp when the run finished (or createdAt fallback). */
3062
- date: z23.string(),
3408
+ date: z26.string(),
3063
3409
  /**
3064
3410
  * 0..100 — same per-query unique-cited definition as
3065
3411
  * `ReportExecutiveSummary.citationRate`. Stable across runs with different
3066
3412
  * provider counts so the trend line measures real movement rather than
3067
3413
  * provider-count variance.
3068
3414
  */
3069
- citationRate: z23.number(),
3415
+ citationRate: z26.number(),
3070
3416
  /** Numerator of `citationRate` for this run. */
3071
- citedQueryCount: z23.number(),
3417
+ citedQueryCount: z26.number(),
3072
3418
  /** Denominator of `citationRate` for this run. */
3073
- totalQueryCount: z23.number(),
3419
+ totalQueryCount: z26.number(),
3074
3420
  /** 0..100 — same per-query unique-mentioned definition as `ReportExecutiveSummary.mentionRate`. */
3075
- mentionRate: z23.number(),
3421
+ mentionRate: z26.number(),
3076
3422
  /** Numerator of `mentionRate` for this run. */
3077
- mentionedQueryCount: z23.number(),
3423
+ mentionedQueryCount: z26.number(),
3078
3424
  /**
3079
3425
  * Per-provider rates for the same run. Each provider's rate is per-pair
3080
3426
  * within that provider (`cited / scanned`), so it remains comparable
3081
3427
  * between providers in the same run.
3082
3428
  */
3083
- providerRates: z23.array(z23.object({ provider: z23.string(), citationRate: z23.number() }))
3429
+ providerRates: z26.array(z26.object({ provider: z26.string(), citationRate: z26.number() }))
3084
3430
  });
3085
- var reportInsightSchema = z23.object({
3086
- id: z23.string(),
3087
- type: z23.enum(["regression", "gain", "opportunity"]),
3088
- severity: z23.enum(["critical", "high", "medium", "low"]),
3089
- title: z23.string(),
3090
- query: z23.string(),
3091
- provider: z23.string(),
3092
- recommendation: z23.string().nullable(),
3093
- createdAt: z23.string(),
3431
+ var reportInsightSchema = z26.object({
3432
+ id: z26.string(),
3433
+ type: z26.enum(["regression", "gain", "opportunity"]),
3434
+ severity: z26.enum(["critical", "high", "medium", "low"]),
3435
+ title: z26.string(),
3436
+ query: z26.string(),
3437
+ provider: z26.string(),
3438
+ recommendation: z26.string().nullable(),
3439
+ createdAt: z26.string(),
3094
3440
  /**
3095
3441
  * How many times this insight fired across recent runs for the same
3096
3442
  * `(query, provider, type)` tuple. Always ≥ 1. Insights returned by the
@@ -3098,57 +3444,57 @@ var reportInsightSchema = z23.object({
3098
3444
  * surfacing the multiplicity. Use it directly instead of grouping again
3099
3445
  * client-side — counts derived from raw insight rows will overcount.
3100
3446
  */
3101
- instanceCount: z23.number()
3447
+ instanceCount: z26.number()
3102
3448
  });
3103
- var recommendedNextStepSchema = z23.object({
3449
+ var recommendedNextStepSchema = z26.object({
3104
3450
  /** 'immediate' | 'short-term' | 'medium-term' — bucketed by severity heuristic. */
3105
- horizon: z23.enum(["immediate", "short-term", "medium-term"]),
3106
- title: z23.string(),
3107
- rationale: z23.string()
3451
+ horizon: z26.enum(["immediate", "short-term", "medium-term"]),
3452
+ title: z26.string(),
3453
+ rationale: z26.string()
3108
3454
  });
3109
- var reportRateDeltaSchema = z23.object({
3455
+ var reportRateDeltaSchema = z26.object({
3110
3456
  /** Current value (0..100 for rates, raw count otherwise). When `window`
3111
3457
  * is present this is the average over the last `window` checks. */
3112
- current: z23.number(),
3458
+ current: z26.number(),
3113
3459
  /** Prior value compared against. When `window` is present this is the
3114
3460
  * average over the prior `window` checks before that. */
3115
- prior: z23.number(),
3461
+ prior: z26.number(),
3116
3462
  /** Absolute delta (current − prior). Negative = decrease. */
3117
- deltaAbs: z23.number(),
3463
+ deltaAbs: z26.number(),
3118
3464
  /**
3119
3465
  * Direction tag for tone mapping. Threshold is metric-specific (3pp for
3120
3466
  * rates, 0.5 for counts) so small noise lands as 'flat' rather than
3121
3467
  * flipping up/down each run.
3122
3468
  */
3123
- direction: z23.enum(["up", "down", "flat"]),
3469
+ direction: z26.enum(["up", "down", "flat"]),
3124
3470
  /**
3125
3471
  * How many points went into each side of the average. Omitted (or 1)
3126
3472
  * means point-to-point (legacy "since last check"). Higher values mean
3127
3473
  * a rolling-average comparison — renderers should label it as
3128
3474
  * "vs prior N checks" when this is ≥ 2.
3129
3475
  */
3130
- window: z23.number().optional()
3476
+ window: z26.number().optional()
3131
3477
  });
3132
- var reportProviderMovementSchema = z23.object({
3133
- provider: z23.string(),
3134
- current: z23.number(),
3135
- prior: z23.number(),
3136
- deltaAbs: z23.number(),
3137
- direction: z23.enum(["up", "down", "flat"])
3478
+ var reportProviderMovementSchema = z26.object({
3479
+ provider: z26.string(),
3480
+ current: z26.number(),
3481
+ prior: z26.number(),
3482
+ deltaAbs: z26.number(),
3483
+ direction: z26.enum(["up", "down", "flat"])
3138
3484
  });
3139
- var whatsChangedSectionSchema = z23.object({
3485
+ var whatsChangedSectionSchema = z26.object({
3140
3486
  /**
3141
3487
  * False when there's no prior run (or fewer than the trend baseline),
3142
3488
  * meaning all per-metric deltas will be null. Renderers use this to swap
3143
3489
  * in a "establishing baseline" fallback rather than rendering empty
3144
3490
  * delta tiles.
3145
3491
  */
3146
- enoughHistory: z23.boolean(),
3492
+ enoughHistory: z26.boolean(),
3147
3493
  /**
3148
3494
  * One-sentence narrative summary suitable as a section subtitle.
3149
3495
  * Always present — even on baseline, narrates whatever signal exists.
3150
3496
  */
3151
- headline: z23.string(),
3497
+ headline: z26.string(),
3152
3498
  /** Citation rate delta vs the prior completed run. Null when no prior run. */
3153
3499
  citationRate: reportRateDeltaSchema.nullable(),
3154
3500
  /** Mention rate delta vs the prior completed run. Null when no prior run. */
@@ -3171,24 +3517,24 @@ var whatsChangedSectionSchema = z23.object({
3171
3517
  * when no prior run. Sorted by |deltaAbs| desc — providers with the
3172
3518
  * biggest swing first.
3173
3519
  */
3174
- providerMovements: z23.array(reportProviderMovementSchema),
3520
+ providerMovements: z26.array(reportProviderMovementSchema),
3175
3521
  /**
3176
3522
  * Top wins this period — gains surfaced by the intelligence engine.
3177
3523
  * Capped at 5; sourced from `insights` filtered to `type: 'gain'`.
3178
3524
  */
3179
- wins: z23.array(reportInsightSchema),
3525
+ wins: z26.array(reportInsightSchema),
3180
3526
  /**
3181
3527
  * Top regressions this period — citations or mentions lost. Capped at 5;
3182
3528
  * sourced from `insights` filtered to `type: 'regression'`.
3183
3529
  */
3184
- regressions: z23.array(reportInsightSchema)
3185
- });
3186
- var reportAudienceSchema = z23.enum(["agency", "client"]);
3187
- var reportActionAudienceSchema = z23.enum(["agency", "client", "both"]);
3188
- var reportActionHorizonSchema = z23.enum(["immediate", "short-term", "medium-term"]);
3189
- var reportActionConfidenceSchema = z23.enum(["high", "medium", "low"]);
3190
- var reportToneSchema = z23.enum(["positive", "caution", "negative", "neutral"]);
3191
- var reportActionCategorySchema = z23.enum([
3530
+ regressions: z26.array(reportInsightSchema)
3531
+ });
3532
+ var reportAudienceSchema = z26.enum(["agency", "client"]);
3533
+ var reportActionAudienceSchema = z26.enum(["agency", "client", "both"]);
3534
+ var reportActionHorizonSchema = z26.enum(["immediate", "short-term", "medium-term"]);
3535
+ var reportActionConfidenceSchema = z26.enum(["high", "medium", "low"]);
3536
+ var reportToneSchema = z26.enum(["positive", "caution", "negative", "neutral"]);
3537
+ var reportActionCategorySchema = z26.enum([
3192
3538
  "content",
3193
3539
  "competitors",
3194
3540
  "provider",
@@ -3197,23 +3543,23 @@ var reportActionCategorySchema = z23.enum([
3197
3543
  "location",
3198
3544
  "monitoring"
3199
3545
  ]);
3200
- var reportActionPlanItemSchema = z23.object({
3546
+ var reportActionPlanItemSchema = z26.object({
3201
3547
  /** Which report audience should see this action. `both` renders in both modes. */
3202
3548
  audience: reportActionAudienceSchema,
3203
3549
  /** Stable sort priority. Lower numbers render earlier. */
3204
- priority: z23.number(),
3550
+ priority: z26.number(),
3205
3551
  /** When this should be tackled. */
3206
3552
  horizon: reportActionHorizonSchema,
3207
3553
  category: reportActionCategorySchema,
3208
- title: z23.string(),
3554
+ title: z26.string(),
3209
3555
  /** Direct next step written as an operator/client-friendly imperative. */
3210
- action: z23.string(),
3556
+ action: z26.string(),
3211
3557
  /** Why this matters. Keep each entry concise and evidence-backed. */
3212
- why: z23.array(z23.string()),
3558
+ why: z26.array(z26.string()),
3213
3559
  /** Specific observations that justify the action. */
3214
- evidence: z23.array(z23.string()),
3560
+ evidence: z26.array(z26.string()),
3215
3561
  /** What should move if the action worked. */
3216
- successMetric: z23.string(),
3562
+ successMetric: z26.string(),
3217
3563
  /** Confidence in the recommendation based on the available evidence. */
3218
3564
  confidence: reportActionConfidenceSchema,
3219
3565
  /**
@@ -3225,23 +3571,23 @@ var reportActionPlanItemSchema = z23.object({
3225
3571
  * load. Actions sourced from other signals (competitor gaps, indexing
3226
3572
  * issues, etc.) omit this and use their own dismiss flows.
3227
3573
  */
3228
- targetRef: z23.string().optional()
3574
+ targetRef: z26.string().optional()
3229
3575
  });
3230
- var reportClientSummarySchema = z23.object({
3231
- headline: z23.string(),
3232
- overview: z23.string(),
3233
- actionItems: z23.array(reportActionPlanItemSchema),
3234
- confidenceNotes: z23.array(z23.string())
3576
+ var reportClientSummarySchema = z26.object({
3577
+ headline: z26.string(),
3578
+ overview: z26.string(),
3579
+ actionItems: z26.array(reportActionPlanItemSchema),
3580
+ confidenceNotes: z26.array(z26.string())
3235
3581
  });
3236
- var reportAgencyDiagnosticSchema = z23.object({
3237
- title: z23.string(),
3238
- detail: z23.string(),
3239
- severity: z23.enum(["positive", "caution", "negative", "neutral"]),
3240
- evidence: z23.array(z23.string())
3582
+ var reportAgencyDiagnosticSchema = z26.object({
3583
+ title: z26.string(),
3584
+ detail: z26.string(),
3585
+ severity: z26.enum(["positive", "caution", "negative", "neutral"]),
3586
+ evidence: z26.array(z26.string())
3241
3587
  });
3242
- var reportAgencyDiagnosticsSchema = z23.object({
3243
- priorities: z23.array(reportActionPlanItemSchema),
3244
- diagnostics: z23.array(reportAgencyDiagnosticSchema)
3588
+ var reportAgencyDiagnosticsSchema = z26.object({
3589
+ priorities: z26.array(reportActionPlanItemSchema),
3590
+ diagnostics: z26.array(reportAgencyDiagnosticSchema)
3245
3591
  });
3246
3592
  function reportActionTone(action) {
3247
3593
  if (action.horizon === "immediate") return "negative";
@@ -3299,7 +3645,7 @@ function reportConfidenceLabel(confidence) {
3299
3645
  return "Low";
3300
3646
  }
3301
3647
  }
3302
- var projectReportDtoSchema = z23.object({
3648
+ var projectReportDtoSchema = z26.object({
3303
3649
  meta: reportMetaSchema,
3304
3650
  executiveSummary: reportExecutiveSummarySchema,
3305
3651
  citationScorecard: citationScorecardSchema,
@@ -3313,16 +3659,16 @@ var projectReportDtoSchema = z23.object({
3313
3659
  /** Server-side log-evidence visibility (crawls + click-through sessions). Null when no traffic source connected. */
3314
3660
  serverActivity: serverActivitySectionSchema.nullable(),
3315
3661
  indexingHealth: indexingHealthSectionSchema.nullable(),
3316
- citationsTrend: z23.array(citationsTrendPointSchema),
3662
+ citationsTrend: z26.array(citationsTrendPointSchema),
3317
3663
  /**
3318
3664
  * Trend-focused "what's changed" summary for the report's act 2. Always
3319
3665
  * present; renderers gate empty/baseline states via `enoughHistory`.
3320
3666
  */
3321
3667
  whatsChanged: whatsChangedSectionSchema,
3322
- insights: z23.array(reportInsightSchema),
3323
- recommendedNextSteps: z23.array(recommendedNextStepSchema),
3668
+ insights: z26.array(reportInsightSchema),
3669
+ recommendedNextSteps: z26.array(recommendedNextStepSchema),
3324
3670
  /** Canonical structured actions shared by the client and agency render modes. */
3325
- actionPlan: z23.array(reportActionPlanItemSchema),
3671
+ actionPlan: z26.array(reportActionPlanItemSchema),
3326
3672
  /** Polished client-facing summary and action shortlist. */
3327
3673
  clientSummary: reportClientSummarySchema,
3328
3674
  /** Technical, evidence-oriented operator diagnostics for agency mode. */
@@ -3332,17 +3678,17 @@ var projectReportDtoSchema = z23.object({
3332
3678
  * intelligence layer (`buildContentTargetRows`). Empty when no run has
3333
3679
  * produced candidate queries with demand or competitor signal.
3334
3680
  */
3335
- contentOpportunities: z23.array(contentTargetRowDtoSchema),
3681
+ contentOpportunities: z26.array(contentTargetRowDtoSchema),
3336
3682
  /**
3337
3683
  * Queries where competitors were cited but the project was not. Sourced
3338
3684
  * from `buildContentGapRows`. Empty until the first answer-visibility run.
3339
3685
  */
3340
- contentGaps: z23.array(contentGapRowDtoSchema),
3686
+ contentGaps: z26.array(contentGapRowDtoSchema),
3341
3687
  /**
3342
3688
  * Per-query grounding source map (own + competitor cited URLs). Sourced
3343
3689
  * from `buildContentSourceRows`. Empty until the first answer-visibility run.
3344
3690
  */
3345
- groundingSources: z23.array(contentSourceRowDtoSchema)
3691
+ groundingSources: z26.array(contentSourceRowDtoSchema)
3346
3692
  });
3347
3693
 
3348
3694
  // ../contracts/src/report-dedup.ts
@@ -3413,10 +3759,10 @@ function dedupeReportOpportunities(report) {
3413
3759
  }
3414
3760
 
3415
3761
  // ../contracts/src/skills.ts
3416
- import { z as z24 } from "zod";
3417
- var codingAgentSchema = z24.enum(["claude", "codex"]);
3762
+ import { z as z27 } from "zod";
3763
+ var codingAgentSchema = z27.enum(["claude", "codex"]);
3418
3764
  var CodingAgents = codingAgentSchema.enum;
3419
- var skillsClientSchema = z24.enum(["claude", "codex", "all"]);
3765
+ var skillsClientSchema = z27.enum(["claude", "codex", "all"]);
3420
3766
  var SkillsClients = skillsClientSchema.enum;
3421
3767
  var SKILL_MANIFEST_FILENAME = ".canonry-skill-manifest.json";
3422
3768
  function classifySkillFile(params) {
@@ -3434,8 +3780,8 @@ function coerceSkillManifest(parsed) {
3434
3780
  }
3435
3781
 
3436
3782
  // ../contracts/src/traffic.ts
3437
- import { z as z25 } from "zod";
3438
- var trafficSourceTypeSchema = z25.enum([
3783
+ import { z as z28 } from "zod";
3784
+ var trafficSourceTypeSchema = z28.enum([
3439
3785
  "cloud-run",
3440
3786
  "wordpress",
3441
3787
  "cloudflare",
@@ -3443,7 +3789,7 @@ var trafficSourceTypeSchema = z25.enum([
3443
3789
  "generic-log"
3444
3790
  ]);
3445
3791
  var TrafficSourceTypes = trafficSourceTypeSchema.enum;
3446
- var trafficAdapterCapabilitySchema = z25.enum([
3792
+ var trafficAdapterCapabilitySchema = z28.enum([
3447
3793
  "raw-request-events",
3448
3794
  "aggregate-request-metrics",
3449
3795
  "request-url",
@@ -3454,328 +3800,215 @@ var trafficAdapterCapabilitySchema = z25.enum([
3454
3800
  "cursor-pull"
3455
3801
  ]);
3456
3802
  var TrafficAdapterCapabilities = trafficAdapterCapabilitySchema.enum;
3457
- var trafficEvidenceKindSchema = z25.enum(["raw-request", "aggregate-bucket"]);
3803
+ var trafficEvidenceKindSchema = z28.enum(["raw-request", "aggregate-bucket"]);
3458
3804
  var TrafficEvidenceKinds = trafficEvidenceKindSchema.enum;
3459
- var trafficEventConfidenceSchema = z25.enum(["observed", "provider-aggregated", "inferred"]);
3805
+ var trafficEventConfidenceSchema = z28.enum(["observed", "provider-aggregated", "inferred"]);
3460
3806
  var TrafficEventConfidences = trafficEventConfidenceSchema.enum;
3461
- var trafficProviderResourceSchema = z25.object({
3462
- type: z25.string().nullable(),
3463
- labels: z25.record(z25.string(), z25.string())
3807
+ var trafficProviderResourceSchema = z28.object({
3808
+ type: z28.string().nullable(),
3809
+ labels: z28.record(z28.string(), z28.string())
3464
3810
  });
3465
- var normalizedTrafficRequestSchema = z25.object({
3811
+ var normalizedTrafficRequestSchema = z28.object({
3466
3812
  sourceType: trafficSourceTypeSchema,
3467
- evidenceKind: z25.literal(TrafficEvidenceKinds["raw-request"]),
3468
- confidence: z25.literal(TrafficEventConfidences.observed),
3469
- eventId: z25.string().min(1),
3470
- observedAt: z25.string().min(1),
3471
- method: z25.string().nullable(),
3472
- requestUrl: z25.string().nullable(),
3473
- host: z25.string().nullable(),
3474
- path: z25.string().min(1),
3475
- queryString: z25.string().nullable(),
3476
- status: z25.number().int().nullable(),
3477
- userAgent: z25.string().nullable(),
3478
- remoteIp: z25.string().nullable(),
3479
- referer: z25.string().nullable(),
3480
- latencyMs: z25.number().nullable(),
3481
- requestSizeBytes: z25.number().int().nullable(),
3482
- responseSizeBytes: z25.number().int().nullable(),
3813
+ evidenceKind: z28.literal(TrafficEvidenceKinds["raw-request"]),
3814
+ confidence: z28.literal(TrafficEventConfidences.observed),
3815
+ eventId: z28.string().min(1),
3816
+ observedAt: z28.string().min(1),
3817
+ method: z28.string().nullable(),
3818
+ requestUrl: z28.string().nullable(),
3819
+ host: z28.string().nullable(),
3820
+ path: z28.string().min(1),
3821
+ queryString: z28.string().nullable(),
3822
+ status: z28.number().int().nullable(),
3823
+ userAgent: z28.string().nullable(),
3824
+ remoteIp: z28.string().nullable(),
3825
+ referer: z28.string().nullable(),
3826
+ latencyMs: z28.number().nullable(),
3827
+ requestSizeBytes: z28.number().int().nullable(),
3828
+ responseSizeBytes: z28.number().int().nullable(),
3483
3829
  providerResource: trafficProviderResourceSchema,
3484
- providerLabels: z25.record(z25.string(), z25.string())
3830
+ providerLabels: z28.record(z28.string(), z28.string())
3485
3831
  });
3486
- var normalizedTrafficPullPageSchema = z25.object({
3487
- events: z25.array(normalizedTrafficRequestSchema),
3488
- rawEntryCount: z25.number().int().nonnegative(),
3489
- skippedEntryCount: z25.number().int().nonnegative(),
3490
- nextPageToken: z25.string().optional(),
3491
- filter: z25.string()
3832
+ var normalizedTrafficPullPageSchema = z28.object({
3833
+ events: z28.array(normalizedTrafficRequestSchema),
3834
+ rawEntryCount: z28.number().int().nonnegative(),
3835
+ skippedEntryCount: z28.number().int().nonnegative(),
3836
+ nextPageToken: z28.string().optional(),
3837
+ filter: z28.string()
3492
3838
  });
3493
- var trafficSourceStatusSchema = z25.enum(["connected", "paused", "error", "archived"]);
3839
+ var trafficSourceStatusSchema = z28.enum(["connected", "paused", "error", "archived"]);
3494
3840
  var TrafficSourceStatuses = trafficSourceStatusSchema.enum;
3495
- var trafficSourceAuthModeSchema = z25.enum(["oauth", "service-account"]);
3841
+ var trafficSourceAuthModeSchema = z28.enum(["oauth", "service-account"]);
3496
3842
  var TrafficSourceAuthModes = trafficSourceAuthModeSchema.enum;
3497
- var verificationStatusSchema = z25.enum(["verified", "claimed_unverified", "unknown_ai_like"]);
3843
+ var verificationStatusSchema = z28.enum(["verified", "claimed_unverified", "unknown_ai_like"]);
3498
3844
  var VerificationStatuses = verificationStatusSchema.enum;
3499
- var cloudRunSourceConfigSchema = z25.object({
3500
- gcpProjectId: z25.string().min(1),
3501
- serviceName: z25.string().nullable().optional(),
3502
- location: z25.string().nullable().optional(),
3845
+ var cloudRunSourceConfigSchema = z28.object({
3846
+ gcpProjectId: z28.string().min(1),
3847
+ serviceName: z28.string().nullable().optional(),
3848
+ location: z28.string().nullable().optional(),
3503
3849
  authMode: trafficSourceAuthModeSchema
3504
3850
  });
3505
- var wordpressTrafficSourceConfigSchema = z25.object({
3506
- baseUrl: z25.string().url(),
3507
- username: z25.string().min(1)
3851
+ var wordpressTrafficSourceConfigSchema = z28.object({
3852
+ baseUrl: z28.string().url(),
3853
+ username: z28.string().min(1)
3508
3854
  });
3509
- var vercelTrafficEnvironmentSchema = z25.enum(["production", "preview"]);
3855
+ var vercelTrafficEnvironmentSchema = z28.enum(["production", "preview"]);
3510
3856
  var VercelTrafficEnvironments = vercelTrafficEnvironmentSchema.enum;
3511
- var vercelTrafficSourceConfigSchema = z25.object({
3857
+ var vercelTrafficSourceConfigSchema = z28.object({
3512
3858
  /** Vercel project id (e.g. `prj_...`). */
3513
- projectId: z25.string().min(1),
3859
+ projectId: z28.string().min(1),
3514
3860
  /** Vercel team or account id: the org that owns the project. */
3515
- teamId: z25.string().min(1),
3861
+ teamId: z28.string().min(1),
3516
3862
  environment: vercelTrafficEnvironmentSchema
3517
3863
  });
3518
- var trafficSourceDtoSchema = z25.object({
3519
- id: z25.string(),
3520
- projectId: z25.string(),
3864
+ var trafficSourceDtoSchema = z28.object({
3865
+ id: z28.string(),
3866
+ projectId: z28.string(),
3521
3867
  sourceType: trafficSourceTypeSchema,
3522
- displayName: z25.string(),
3868
+ displayName: z28.string(),
3523
3869
  status: trafficSourceStatusSchema,
3524
- lastSyncedAt: z25.string().nullable(),
3525
- lastCursor: z25.string().nullable(),
3526
- lastError: z25.string().nullable(),
3527
- archivedAt: z25.string().nullable(),
3528
- config: z25.record(z25.string(), z25.unknown()),
3529
- createdAt: z25.string(),
3530
- updatedAt: z25.string()
3531
- });
3532
- var trafficConnectCloudRunRequestSchema = z25.object({
3533
- gcpProjectId: z25.string().min(1),
3534
- serviceName: z25.string().min(1).optional(),
3535
- location: z25.string().min(1).optional(),
3536
- displayName: z25.string().min(1).optional(),
3870
+ lastSyncedAt: z28.string().nullable(),
3871
+ lastCursor: z28.string().nullable(),
3872
+ lastError: z28.string().nullable(),
3873
+ archivedAt: z28.string().nullable(),
3874
+ config: z28.record(z28.string(), z28.unknown()),
3875
+ createdAt: z28.string(),
3876
+ updatedAt: z28.string()
3877
+ });
3878
+ var trafficConnectCloudRunRequestSchema = z28.object({
3879
+ gcpProjectId: z28.string().min(1),
3880
+ serviceName: z28.string().min(1).optional(),
3881
+ location: z28.string().min(1).optional(),
3882
+ displayName: z28.string().min(1).optional(),
3537
3883
  /** Service-account JSON content (string). When omitted, defaults to OAuth via `canonry google connect <project> --type ga4` flow. */
3538
- keyJson: z25.string().optional()
3884
+ keyJson: z28.string().optional()
3539
3885
  });
3540
- var trafficConnectWordpressRequestSchema = z25.object({
3541
- baseUrl: z25.string().url(),
3542
- username: z25.string().min(1),
3886
+ var trafficConnectWordpressRequestSchema = z28.object({
3887
+ baseUrl: z28.string().url(),
3888
+ username: z28.string().min(1),
3543
3889
  /** WordPress Application Password (the same auth used by the content client). */
3544
- applicationPassword: z25.string().min(1),
3545
- displayName: z25.string().min(1).optional()
3890
+ applicationPassword: z28.string().min(1),
3891
+ displayName: z28.string().min(1).optional()
3546
3892
  });
3547
- var trafficConnectVercelRequestSchema = z25.object({
3893
+ var trafficConnectVercelRequestSchema = z28.object({
3548
3894
  /** Vercel project id (e.g. `prj_...`) — from the Vercel dashboard or `.vercel/project.json`. */
3549
- projectId: z25.string().min(1),
3895
+ projectId: z28.string().min(1),
3550
3896
  /** Vercel team or account id: the org that owns the project ("orgId" in .vercel/project.json). */
3551
- teamId: z25.string().min(1),
3897
+ teamId: z28.string().min(1),
3552
3898
  /** Vercel personal access token. Stored in `~/.canonry/config.yaml`, never the DB. */
3553
- token: z25.string().min(1),
3899
+ token: z28.string().min(1),
3554
3900
  /** Which deployment environment's request logs to pull. Default: `production`. */
3555
3901
  environment: vercelTrafficEnvironmentSchema.optional(),
3556
- displayName: z25.string().min(1).optional()
3902
+ displayName: z28.string().min(1).optional()
3557
3903
  });
3558
- var trafficSyncResponseSchema = z25.object({
3559
- sourceId: z25.string(),
3560
- runId: z25.string(),
3561
- syncedAt: z25.string(),
3562
- pulledEvents: z25.number().int().nonnegative(),
3904
+ var trafficSyncResponseSchema = z28.object({
3905
+ sourceId: z28.string(),
3906
+ runId: z28.string(),
3907
+ syncedAt: z28.string(),
3908
+ pulledEvents: z28.number().int().nonnegative(),
3563
3909
  /** Self-traffic events (Canonry's own tooling) dropped before rollup. */
3564
- selfTrafficExcluded: z25.number().int().nonnegative(),
3565
- crawlerHits: z25.number().int().nonnegative(),
3566
- aiUserFetchHits: z25.number().int().nonnegative(),
3567
- aiReferralHits: z25.number().int().nonnegative(),
3568
- unknownHits: z25.number().int().nonnegative(),
3569
- crawlerBucketRows: z25.number().int().nonnegative(),
3570
- aiUserFetchBucketRows: z25.number().int().nonnegative(),
3571
- aiReferralBucketRows: z25.number().int().nonnegative(),
3572
- sampleRows: z25.number().int().nonnegative(),
3573
- windowStart: z25.string(),
3574
- windowEnd: z25.string()
3575
- });
3576
- var trafficBackfillRequestSchema = z25.object({
3910
+ selfTrafficExcluded: z28.number().int().nonnegative(),
3911
+ crawlerHits: z28.number().int().nonnegative(),
3912
+ aiUserFetchHits: z28.number().int().nonnegative(),
3913
+ aiReferralHits: z28.number().int().nonnegative(),
3914
+ unknownHits: z28.number().int().nonnegative(),
3915
+ crawlerBucketRows: z28.number().int().nonnegative(),
3916
+ aiUserFetchBucketRows: z28.number().int().nonnegative(),
3917
+ aiReferralBucketRows: z28.number().int().nonnegative(),
3918
+ sampleRows: z28.number().int().nonnegative(),
3919
+ windowStart: z28.string(),
3920
+ windowEnd: z28.string()
3921
+ });
3922
+ var trafficBackfillRequestSchema = z28.object({
3577
3923
  /** Lookback window in days. Capped server-side at the upstream log retention ceiling (Cloud Logging _Default = 30d). Default: 30. */
3578
- days: z25.number().int().positive().optional()
3924
+ days: z28.number().int().positive().optional()
3579
3925
  });
3580
- var trafficResetRequestSchema = z25.object({
3581
- advanceToNow: z25.literal(true)
3926
+ var trafficResetRequestSchema = z28.object({
3927
+ advanceToNow: z28.literal(true)
3582
3928
  });
3583
- var trafficBackfillResponseSchema = z25.object({
3584
- sourceId: z25.string(),
3585
- runId: z25.string(),
3929
+ var trafficBackfillResponseSchema = z28.object({
3930
+ sourceId: z28.string(),
3931
+ runId: z28.string(),
3586
3932
  status: runStatusSchema,
3587
- windowStart: z25.string(),
3588
- windowEnd: z25.string(),
3933
+ windowStart: z28.string(),
3934
+ windowEnd: z28.string(),
3589
3935
  /** Days actually used after server-side clamping (≤ requested). */
3590
- daysRequested: z25.number().int().positive(),
3591
- daysApplied: z25.number().int().positive()
3936
+ daysRequested: z28.number().int().positive(),
3937
+ daysApplied: z28.number().int().positive()
3592
3938
  });
3593
- var trafficSourceTotalsSchema = z25.object({
3594
- crawlerHits: z25.number().int().nonnegative(),
3595
- aiUserFetchHits: z25.number().int().nonnegative(),
3596
- aiReferralHits: z25.number().int().nonnegative(),
3597
- sampleCount: z25.number().int().nonnegative()
3939
+ var trafficSourceTotalsSchema = z28.object({
3940
+ crawlerHits: z28.number().int().nonnegative(),
3941
+ aiUserFetchHits: z28.number().int().nonnegative(),
3942
+ aiReferralHits: z28.number().int().nonnegative(),
3943
+ sampleCount: z28.number().int().nonnegative()
3598
3944
  });
3599
- var trafficSourceListResponseSchema = z25.object({
3600
- sources: z25.array(trafficSourceDtoSchema)
3945
+ var trafficSourceListResponseSchema = z28.object({
3946
+ sources: z28.array(trafficSourceDtoSchema)
3601
3947
  });
3602
3948
  var trafficSourceDetailDtoSchema = trafficSourceDtoSchema.extend({
3603
3949
  totals24h: trafficSourceTotalsSchema,
3604
- latestRun: z25.object({
3605
- runId: z25.string(),
3950
+ latestRun: z28.object({
3951
+ runId: z28.string(),
3606
3952
  status: runStatusSchema,
3607
- startedAt: z25.string().nullable(),
3608
- finishedAt: z25.string().nullable(),
3609
- error: z25.string().nullable()
3953
+ startedAt: z28.string().nullable(),
3954
+ finishedAt: z28.string().nullable(),
3955
+ error: z28.string().nullable()
3610
3956
  }).nullable()
3611
3957
  });
3612
- var trafficStatusResponseSchema = z25.object({
3613
- sources: z25.array(trafficSourceDetailDtoSchema)
3958
+ var trafficStatusResponseSchema = z28.object({
3959
+ sources: z28.array(trafficSourceDetailDtoSchema)
3614
3960
  });
3615
- var trafficEventKindSchema = z25.enum(["crawler", "ai-user-fetch", "ai-referral"]);
3961
+ var trafficEventKindSchema = z28.enum(["crawler", "ai-user-fetch", "ai-referral"]);
3616
3962
  var TrafficEventKinds = trafficEventKindSchema.enum;
3617
- var trafficCrawlerEventEntrySchema = z25.object({
3618
- kind: z25.literal(TrafficEventKinds.crawler),
3619
- sourceId: z25.string(),
3620
- tsHour: z25.string(),
3621
- botId: z25.string(),
3622
- operator: z25.string(),
3623
- verificationStatus: z25.string(),
3624
- pathNormalized: z25.string(),
3625
- status: z25.number().int(),
3626
- hits: z25.number().int().nonnegative()
3627
- });
3628
- var trafficAiUserFetchEventEntrySchema = z25.object({
3629
- kind: z25.literal(TrafficEventKinds["ai-user-fetch"]),
3630
- sourceId: z25.string(),
3631
- tsHour: z25.string(),
3632
- botId: z25.string(),
3633
- operator: z25.string(),
3634
- verificationStatus: z25.string(),
3635
- pathNormalized: z25.string(),
3636
- status: z25.number().int(),
3637
- hits: z25.number().int().nonnegative()
3638
- });
3639
- var trafficAiReferralEventEntrySchema = z25.object({
3640
- kind: z25.literal(TrafficEventKinds["ai-referral"]),
3641
- sourceId: z25.string(),
3642
- tsHour: z25.string(),
3643
- product: z25.string(),
3644
- operator: z25.string(),
3645
- sourceDomain: z25.string(),
3646
- evidenceType: z25.string(),
3647
- landingPathNormalized: z25.string(),
3648
- status: z25.number().int(),
3649
- hits: z25.number().int().nonnegative()
3650
- });
3651
- var trafficEventEntrySchema = z25.discriminatedUnion("kind", [
3963
+ var trafficCrawlerEventEntrySchema = z28.object({
3964
+ kind: z28.literal(TrafficEventKinds.crawler),
3965
+ sourceId: z28.string(),
3966
+ tsHour: z28.string(),
3967
+ botId: z28.string(),
3968
+ operator: z28.string(),
3969
+ verificationStatus: z28.string(),
3970
+ pathNormalized: z28.string(),
3971
+ status: z28.number().int(),
3972
+ hits: z28.number().int().nonnegative()
3973
+ });
3974
+ var trafficAiUserFetchEventEntrySchema = z28.object({
3975
+ kind: z28.literal(TrafficEventKinds["ai-user-fetch"]),
3976
+ sourceId: z28.string(),
3977
+ tsHour: z28.string(),
3978
+ botId: z28.string(),
3979
+ operator: z28.string(),
3980
+ verificationStatus: z28.string(),
3981
+ pathNormalized: z28.string(),
3982
+ status: z28.number().int(),
3983
+ hits: z28.number().int().nonnegative()
3984
+ });
3985
+ var trafficAiReferralEventEntrySchema = z28.object({
3986
+ kind: z28.literal(TrafficEventKinds["ai-referral"]),
3987
+ sourceId: z28.string(),
3988
+ tsHour: z28.string(),
3989
+ product: z28.string(),
3990
+ operator: z28.string(),
3991
+ sourceDomain: z28.string(),
3992
+ evidenceType: z28.string(),
3993
+ landingPathNormalized: z28.string(),
3994
+ status: z28.number().int(),
3995
+ hits: z28.number().int().nonnegative()
3996
+ });
3997
+ var trafficEventEntrySchema = z28.discriminatedUnion("kind", [
3652
3998
  trafficCrawlerEventEntrySchema,
3653
3999
  trafficAiUserFetchEventEntrySchema,
3654
4000
  trafficAiReferralEventEntrySchema
3655
4001
  ]);
3656
- var trafficEventsResponseSchema = z25.object({
3657
- windowStart: z25.string(),
3658
- windowEnd: z25.string(),
3659
- totals: z25.object({
3660
- crawlerHits: z25.number().int().nonnegative(),
3661
- aiUserFetchHits: z25.number().int().nonnegative(),
3662
- aiReferralHits: z25.number().int().nonnegative()
3663
- }),
3664
- events: z25.array(trafficEventEntrySchema)
3665
- });
3666
-
3667
- // ../contracts/src/discovery.ts
3668
- import { z as z26 } from "zod";
3669
- var discoveryBucketSchema = z26.enum(["cited", "aspirational", "wasted-surface"]);
3670
- var DiscoveryBuckets = discoveryBucketSchema.enum;
3671
- var DEFAULT_DISCOVERY_PROMOTE_BUCKETS = [
3672
- DiscoveryBuckets.cited,
3673
- DiscoveryBuckets.aspirational
3674
- ];
3675
- var DISCOVERY_PROMOTE_COMPETITOR_CAP = 20;
3676
- var DISCOVERY_PROMOTE_COMPETITOR_MIN_HITS = 2;
3677
- var discoveryCompetitorTypeSchema = z26.enum([
3678
- "direct-competitor",
3679
- "ota-aggregator",
3680
- "editorial-media",
3681
- "other",
3682
- "unknown"
3683
- ]);
3684
- var DiscoveryCompetitorTypes = discoveryCompetitorTypeSchema.enum;
3685
- var DEFAULT_DISCOVERY_PROMOTE_COMPETITOR_TYPES = [
3686
- DiscoveryCompetitorTypes["direct-competitor"]
3687
- ];
3688
- var discoverySessionStatusSchema = z26.enum(["queued", "seeding", "probing", "completed", "failed"]);
3689
- var DiscoverySessionStatuses = discoverySessionStatusSchema.enum;
3690
- var discoveryCompetitorMapEntrySchema = z26.object({
3691
- domain: z26.string().min(1),
3692
- hits: z26.number().int().positive(),
3693
- /**
3694
- * Domain classification from the session's post-probe AI classification
3695
- * pass. Defaults to `unknown` so competitor maps persisted before
3696
- * classification existed (or by a session whose classification call failed)
3697
- * still parse — those entries are excluded from the default promote filter.
3698
- */
3699
- competitorType: discoveryCompetitorTypeSchema.default("unknown")
3700
- });
3701
- var discoveryProbeDtoSchema = z26.object({
3702
- id: z26.string(),
3703
- sessionId: z26.string(),
3704
- projectId: z26.string(),
3705
- query: z26.string(),
3706
- bucket: discoveryBucketSchema.nullable().default(null),
3707
- citationState: citationStateSchema,
3708
- citedDomains: z26.array(z26.string()).default([]),
3709
- createdAt: z26.string()
3710
- });
3711
- var discoverySessionDtoSchema = z26.object({
3712
- id: z26.string(),
3713
- projectId: z26.string(),
3714
- status: discoverySessionStatusSchema,
3715
- icpDescription: z26.string().nullable().optional(),
3716
- seedProvider: z26.string().nullable().optional(),
3717
- seedCountRaw: z26.number().int().nullable().optional(),
3718
- seedCount: z26.number().int().nullable().optional(),
3719
- dedupThreshold: z26.number().nullable().optional(),
3720
- probeCount: z26.number().int().nullable().optional(),
3721
- citedCount: z26.number().int().nullable().default(null),
3722
- aspirationalCount: z26.number().int().nullable().default(null),
3723
- wastedCount: z26.number().int().nullable().default(null),
3724
- competitorMap: z26.array(discoveryCompetitorMapEntrySchema).default([]),
3725
- error: z26.string().nullable().optional(),
3726
- startedAt: z26.string().nullable().optional(),
3727
- finishedAt: z26.string().nullable().optional(),
3728
- createdAt: z26.string()
3729
- });
3730
- var discoverySessionDetailDtoSchema = discoverySessionDtoSchema.extend({
3731
- probes: z26.array(discoveryProbeDtoSchema).default([])
3732
- });
3733
- var DISCOVERY_MAX_PROBES_CAP = 500;
3734
- var discoveryRunRequestSchema = z26.object({
3735
- icpDescription: z26.string().min(1).optional(),
3736
- dedupThreshold: z26.number().min(0).max(1).optional(),
3737
- maxProbes: z26.number().int().positive().max(DISCOVERY_MAX_PROBES_CAP).optional(),
3738
- /**
3739
- * Optional override of the project's location labels, constraining seed
3740
- * generation to a subset of the configured service areas. Each label must
3741
- * match a configured project location (resolved server-side via
3742
- * `resolveLocations`). Omitted means "use every project location" — a
3743
- * project with no locations is unaffected.
3744
- */
3745
- locations: z26.array(z26.string().min(1)).optional()
3746
- });
3747
- var discoveryPromoteRequestSchema = z26.object({
3748
- buckets: z26.array(discoveryBucketSchema).min(1).optional(),
3749
- includeCompetitors: z26.boolean().optional(),
3750
- competitorTypes: z26.array(discoveryCompetitorTypeSchema).min(1).optional()
3751
- });
3752
- var discoveryPromotePreviewSchema = z26.object({
3753
- sessionId: z26.string(),
3754
- projectId: z26.string(),
3755
- status: discoverySessionStatusSchema,
3756
- queriesByBucket: z26.object({
3757
- cited: z26.array(z26.string()),
3758
- aspirational: z26.array(z26.string()),
3759
- "wasted-surface": z26.array(z26.string())
3760
- }),
3761
- suggestedCompetitors: z26.array(discoveryCompetitorMapEntrySchema)
3762
- });
3763
- var discoveryPromoteResultSchema = z26.object({
3764
- sessionId: z26.string(),
3765
- projectId: z26.string(),
3766
- promoted: z26.object({
3767
- queries: z26.array(z26.string()),
3768
- competitors: z26.array(z26.string())
4002
+ var trafficEventsResponseSchema = z28.object({
4003
+ windowStart: z28.string(),
4004
+ windowEnd: z28.string(),
4005
+ totals: z28.object({
4006
+ crawlerHits: z28.number().int().nonnegative(),
4007
+ aiUserFetchHits: z28.number().int().nonnegative(),
4008
+ aiReferralHits: z28.number().int().nonnegative()
3769
4009
  }),
3770
- skipped: z26.object({
3771
- queries: z26.array(z26.string()),
3772
- competitors: z26.array(z26.string())
3773
- })
4010
+ events: z28.array(trafficEventEntrySchema)
3774
4011
  });
3775
- var queryProvenanceSchema = z26.union([
3776
- z26.literal("cli"),
3777
- z26.string().regex(/^discovery:.+$/)
3778
- ]);
3779
4012
 
3780
4013
  // ../contracts/src/embeddings.ts
3781
4014
  function cosineSimilarity(a, b) {
@@ -4076,12 +4309,32 @@ export {
4076
4309
  SchedulableRunKinds,
4077
4310
  scheduleDtoSchema,
4078
4311
  scheduleUpsertRequestSchema,
4079
- brandMetricsDtoSchema,
4080
- parseWindow,
4081
- windowCutoff,
4082
4312
  categorizeSource,
4083
4313
  categorizeSourceWithCompetitors,
4084
4314
  categoryLabel,
4315
+ discoveryBucketSchema,
4316
+ DiscoveryBuckets,
4317
+ DEFAULT_DISCOVERY_PROMOTE_BUCKETS,
4318
+ DISCOVERY_PROMOTE_COMPETITOR_CAP,
4319
+ DISCOVERY_PROMOTE_COMPETITOR_MIN_HITS,
4320
+ discoveryCompetitorTypeSchema,
4321
+ DiscoveryCompetitorTypes,
4322
+ DEFAULT_DISCOVERY_PROMOTE_COMPETITOR_TYPES,
4323
+ DiscoverySessionStatuses,
4324
+ discoverySessionDtoSchema,
4325
+ discoverySessionDetailDtoSchema,
4326
+ DISCOVERY_MAX_PROBES_CAP,
4327
+ discoveryRunRequestSchema,
4328
+ discoveryPromoteRequestSchema,
4329
+ discoveryPromotePreviewSchema,
4330
+ discoveryPromoteResultSchema,
4331
+ surfaceClassLabel,
4332
+ surfaceClassFromCompetitorType,
4333
+ classifySurfaceFromCategory,
4334
+ brandMetricsDtoSchema,
4335
+ sourceBreakdownDtoSchema,
4336
+ parseWindow,
4337
+ windowCutoff,
4085
4338
  ga4StatusDtoSchema,
4086
4339
  ga4SyncResponseDtoSchema,
4087
4340
  ga4AiReferralHistoryEntrySchema,
@@ -4110,12 +4363,19 @@ export {
4110
4363
  ContentActions,
4111
4364
  contentActionLabel,
4112
4365
  actionConfidenceLabel,
4366
+ winnabilityClassSchema,
4367
+ WinnabilityClasses,
4368
+ winnabilityClassLabel,
4369
+ deriveWinnabilityClass,
4113
4370
  contentTargetsResponseDtoSchema,
4114
4371
  contentTargetDismissalDtoSchema,
4115
4372
  contentTargetDismissalsResponseDtoSchema,
4116
4373
  contentTargetDismissRequestSchema,
4117
4374
  recommendationExplanationDtoSchema,
4118
4375
  recommendationExplainRequestSchema,
4376
+ contentBriefDtoSchema,
4377
+ recommendationBriefDtoSchema,
4378
+ domainClassificationsResponseDtoSchema,
4119
4379
  contentSourcesResponseDtoSchema,
4120
4380
  contentGapsResponseDtoSchema,
4121
4381
  CheckStatuses,
@@ -4161,22 +4421,6 @@ export {
4161
4421
  trafficEventKindSchema,
4162
4422
  TrafficEventKinds,
4163
4423
  trafficEventsResponseSchema,
4164
- discoveryBucketSchema,
4165
- DiscoveryBuckets,
4166
- DEFAULT_DISCOVERY_PROMOTE_BUCKETS,
4167
- DISCOVERY_PROMOTE_COMPETITOR_CAP,
4168
- DISCOVERY_PROMOTE_COMPETITOR_MIN_HITS,
4169
- discoveryCompetitorTypeSchema,
4170
- DiscoveryCompetitorTypes,
4171
- DEFAULT_DISCOVERY_PROMOTE_COMPETITOR_TYPES,
4172
- DiscoverySessionStatuses,
4173
- discoverySessionDtoSchema,
4174
- discoverySessionDetailDtoSchema,
4175
- DISCOVERY_MAX_PROBES_CAP,
4176
- discoveryRunRequestSchema,
4177
- discoveryPromoteRequestSchema,
4178
- discoveryPromotePreviewSchema,
4179
- discoveryPromoteResultSchema,
4180
4424
  clusterByCosine,
4181
4425
  pickClusterRepresentative,
4182
4426
  formatRatio,