@ainyc/canonry 4.87.0 → 4.88.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 (24) hide show
  1. package/assets/agent-workspace/skills/canonry/references/server-side-traffic.md +19 -0
  2. package/assets/assets/{BacklinksPage-BPvsw_Bi.js → BacklinksPage-Dpx6ylmU.js} +1 -1
  3. package/assets/assets/{ChartPrimitives-BdlKCq7y.js → ChartPrimitives-CG5EGu62.js} +1 -1
  4. package/assets/assets/{ProjectPage-1Q8YC9Vd.js → ProjectPage-B_xnYE7W.js} +1 -1
  5. package/assets/assets/{RunRow-DcSsnE5c.js → RunRow-C0V4vf-u.js} +1 -1
  6. package/assets/assets/{RunsPage-DKoIMkQL.js → RunsPage-9gWTjteG.js} +1 -1
  7. package/assets/assets/{SettingsPage-bH3PdNKb.js → SettingsPage-kBwz4Glg.js} +1 -1
  8. package/assets/assets/{TrafficPage-IW_DX-0V.js → TrafficPage-D4adjs8S.js} +1 -1
  9. package/assets/assets/TrafficSourceDetailPage-CmURRHaU.js +1 -0
  10. package/assets/assets/{arrow-left-B5Du72nk.js → arrow-left-DJ0-oFbd.js} +1 -1
  11. package/assets/assets/{extract-error-message-C7Vhd5zH.js → extract-error-message-DfBzETgi.js} +1 -1
  12. package/assets/assets/{index-C_ZzKZfM.js → index-BeuGfMy8.js} +53 -53
  13. package/assets/assets/{trash-2-DWcofmpv.js → trash-2-Bjf6mCqw.js} +1 -1
  14. package/assets/index.html +1 -1
  15. package/dist/{chunk-DUDFNP5Y.js → chunk-2VEFNAQ3.js} +4 -4
  16. package/dist/{chunk-MDRDX5R2.js → chunk-JZ67YCHT.js} +168 -0
  17. package/dist/{chunk-6XMXBAEW.js → chunk-RH3QYFX3.js} +1 -1
  18. package/dist/{chunk-5LW7CJAO.js → chunk-WMZJO56S.js} +30 -6
  19. package/dist/cli.js +13 -7
  20. package/dist/index.js +4 -4
  21. package/dist/{intelligence-service-XUKYOHKL.js → intelligence-service-WTEEV46F.js} +2 -2
  22. package/dist/mcp.js +2 -2
  23. package/package.json +9 -9
  24. package/assets/assets/TrafficSourceDetailPage-DRHOGn9B.js +0 -1
@@ -1 +1 @@
1
- import{c}from"./index-C_ZzKZfM.js";const a=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],h=c("circle-check",a);const e=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3",key:"1u773s"}],["path",{d:"M12 17h.01",key:"p32p05"}]],n=c("circle-question-mark",e);const o=[["path",{d:"M12 15V3",key:"m9g1x1"}],["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["path",{d:"m7 10 5 5 5-5",key:"brsn70"}]],s=c("download",o);const t=[["path",{d:"M10 11v6",key:"nco0om"}],["path",{d:"M14 11v6",key:"outv1u"}],["path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6",key:"miytrc"}],["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2",key:"e791ji"}]],r=c("trash-2",t);export{h as C,s as D,r as T,n as a};
1
+ import{c}from"./index-BeuGfMy8.js";const a=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],h=c("circle-check",a);const e=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3",key:"1u773s"}],["path",{d:"M12 17h.01",key:"p32p05"}]],n=c("circle-question-mark",e);const o=[["path",{d:"M12 15V3",key:"m9g1x1"}],["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["path",{d:"m7 10 5 5 5-5",key:"brsn70"}]],s=c("download",o);const t=[["path",{d:"M10 11v6",key:"nco0om"}],["path",{d:"M14 11v6",key:"outv1u"}],["path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6",key:"miytrc"}],["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2",key:"e791ji"}]],r=c("trash-2",t);export{h as C,s as D,r as T,n as a};
package/assets/index.html CHANGED
@@ -12,7 +12,7 @@
12
12
  <link rel="icon" type="image/png" sizes="32x32" href="./favicon-32.png" />
13
13
  <link rel="apple-touch-icon" href="./apple-touch-icon.png" />
14
14
  <title>Canonry</title>
15
- <script type="module" crossorigin src="./assets/index-C_ZzKZfM.js"></script>
15
+ <script type="module" crossorigin src="./assets/index-BeuGfMy8.js"></script>
16
16
  <link rel="modulepreload" crossorigin href="./assets/vendor-tanstack-Dq7p98wZ.js">
17
17
  <link rel="modulepreload" crossorigin href="./assets/vendor-radix-B57xfQbP.js">
18
18
  <link rel="modulepreload" crossorigin href="./assets/vendor-recharts-ClRVR6aX.js">
@@ -9,7 +9,7 @@ import {
9
9
  loadConfig,
10
10
  loadConfigRaw,
11
11
  saveConfigPatch
12
- } from "./chunk-6XMXBAEW.js";
12
+ } from "./chunk-RH3QYFX3.js";
13
13
  import {
14
14
  CC_CACHE_DIR,
15
15
  DUCKDB_SPEC,
@@ -104,7 +104,7 @@ import {
104
104
  siteAuditPages,
105
105
  siteAuditSnapshots,
106
106
  usageCounters
107
- } from "./chunk-5LW7CJAO.js";
107
+ } from "./chunk-WMZJO56S.js";
108
108
  import {
109
109
  AGENT_MEMORY_VALUE_MAX_BYTES,
110
110
  AGENT_PROVIDER_IDS,
@@ -160,7 +160,7 @@ import {
160
160
  validationError,
161
161
  winnabilityClassLabel,
162
162
  withRetry
163
- } from "./chunk-MDRDX5R2.js";
163
+ } from "./chunk-JZ67YCHT.js";
164
164
 
165
165
  // src/telemetry.ts
166
166
  import crypto from "crypto";
@@ -6289,7 +6289,7 @@ function readStoredGroundingSources(rawResponse) {
6289
6289
  return result;
6290
6290
  }
6291
6291
  async function backfillInsightsCommand(project, opts) {
6292
- const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-XUKYOHKL.js");
6292
+ const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-WTEEV46F.js");
6293
6293
  const config = loadConfig();
6294
6294
  const db = createClient(config.database);
6295
6295
  migrate(db);
@@ -4555,6 +4555,20 @@ function coerceSkillManifest(parsed) {
4555
4555
 
4556
4556
  // ../contracts/src/traffic.ts
4557
4557
  import { z as z30 } from "zod";
4558
+ var trafficCrawlerSegmentsSchema = z30.object({
4559
+ content: z30.number().int().nonnegative(),
4560
+ sitemap: z30.number().int().nonnegative(),
4561
+ robots: z30.number().int().nonnegative(),
4562
+ asset: z30.number().int().nonnegative(),
4563
+ other: z30.number().int().nonnegative()
4564
+ });
4565
+ var trafficPathClassSchema = z30.enum([
4566
+ "content",
4567
+ "sitemap",
4568
+ "robots",
4569
+ "asset",
4570
+ "other"
4571
+ ]);
4558
4572
  var trafficSourceTypeSchema = z30.enum([
4559
4573
  "cloud-run",
4560
4574
  "wordpress",
@@ -4711,7 +4725,18 @@ var trafficBackfillResponseSchema = z30.object({
4711
4725
  daysApplied: z30.number().int().positive()
4712
4726
  });
4713
4727
  var trafficSourceTotalsSchema = z30.object({
4728
+ /**
4729
+ * Total classified-crawler hits in the window. UNCHANGED contract — still the
4730
+ * full count across every path class. Use `crawlerContentHits` for the
4731
+ * "content was actually crawled" signal.
4732
+ */
4714
4733
  crawlerHits: z30.number().int().nonnegative(),
4734
+ /** Crawler hits against content/document paths only (= `crawlerSegments.content`). */
4735
+ crawlerContentHits: z30.number().int().nonnegative(),
4736
+ /** Infrastructure crawler hits — sitemap + robots + asset fetches (`crawlerSegments.{sitemap,robots,asset}`). */
4737
+ crawlerInfraHits: z30.number().int().nonnegative(),
4738
+ /** Full per-class crawler-hit breakdown; the five buckets sum to `crawlerHits`. */
4739
+ crawlerSegments: trafficCrawlerSegmentsSchema,
4715
4740
  aiUserFetchHits: z30.number().int().nonnegative(),
4716
4741
  aiReferralHits: z30.number().int().nonnegative(),
4717
4742
  sampleCount: z30.number().int().nonnegative()
@@ -4742,6 +4767,8 @@ var trafficCrawlerEventEntrySchema = z30.object({
4742
4767
  operator: z30.string(),
4743
4768
  verificationStatus: z30.string(),
4744
4769
  pathNormalized: z30.string(),
4770
+ /** Coarse class of the fetched path — lets the UI split content crawls from sitemap/robots/asset polling. */
4771
+ pathClass: trafficPathClassSchema,
4745
4772
  status: z30.number().int(),
4746
4773
  hits: z30.number().int().nonnegative()
4747
4774
  });
@@ -4777,13 +4804,151 @@ var trafficEventsResponseSchema = z30.object({
4777
4804
  windowStart: z30.string(),
4778
4805
  windowEnd: z30.string(),
4779
4806
  totals: z30.object({
4807
+ /** Total classified-crawler hits across the window. UNCHANGED contract. */
4780
4808
  crawlerHits: z30.number().int().nonnegative(),
4809
+ /** Crawler hits against content/document paths only (= `crawlerSegments.content`). */
4810
+ crawlerContentHits: z30.number().int().nonnegative(),
4811
+ /** Infrastructure crawler hits — sitemap + robots + asset fetches. */
4812
+ crawlerInfraHits: z30.number().int().nonnegative(),
4813
+ /** Full per-class crawler-hit breakdown; the five buckets sum to `crawlerHits`. */
4814
+ crawlerSegments: trafficCrawlerSegmentsSchema,
4781
4815
  aiUserFetchHits: z30.number().int().nonnegative(),
4782
4816
  aiReferralHits: z30.number().int().nonnegative()
4783
4817
  }),
4784
4818
  events: z30.array(trafficEventEntrySchema)
4785
4819
  });
4786
4820
 
4821
+ // ../contracts/src/traffic-path.ts
4822
+ var TrafficPathClasses = {
4823
+ content: "content",
4824
+ sitemap: "sitemap",
4825
+ robots: "robots",
4826
+ asset: "asset",
4827
+ other: "other"
4828
+ };
4829
+ var ROBOTS_BASENAMES = /* @__PURE__ */ new Set(["robots.txt", "llms.txt", "llms-full.txt"]);
4830
+ var ASSET_EXTENSIONS = /* @__PURE__ */ new Set([
4831
+ "css",
4832
+ "js",
4833
+ "mjs",
4834
+ "cjs",
4835
+ "map",
4836
+ "json",
4837
+ "png",
4838
+ "jpg",
4839
+ "jpeg",
4840
+ "webp",
4841
+ "avif",
4842
+ "gif",
4843
+ "svg",
4844
+ "ico",
4845
+ "bmp",
4846
+ "tif",
4847
+ "tiff",
4848
+ "woff",
4849
+ "woff2",
4850
+ "ttf",
4851
+ "otf",
4852
+ "eot",
4853
+ "mp4",
4854
+ "webm",
4855
+ "mov",
4856
+ "m4v",
4857
+ "mp3",
4858
+ "wav",
4859
+ "ogg",
4860
+ "flac",
4861
+ "m4a",
4862
+ "wasm"
4863
+ ]);
4864
+ var DOCUMENT_EXTENSIONS = /* @__PURE__ */ new Set([
4865
+ "html",
4866
+ "htm",
4867
+ "xhtml",
4868
+ "shtml",
4869
+ "php",
4870
+ "php5",
4871
+ "php7",
4872
+ "asp",
4873
+ "aspx",
4874
+ "jsp",
4875
+ "jspx",
4876
+ "cfm",
4877
+ "md"
4878
+ ]);
4879
+ var DOWNLOAD_EXTENSIONS = /* @__PURE__ */ new Set([
4880
+ "pdf",
4881
+ "csv",
4882
+ "tsv",
4883
+ "txt",
4884
+ "doc",
4885
+ "docx",
4886
+ "xls",
4887
+ "xlsx",
4888
+ "ppt",
4889
+ "pptx",
4890
+ "odt",
4891
+ "ods",
4892
+ "odp",
4893
+ "rtf",
4894
+ "zip",
4895
+ "gz",
4896
+ "tgz",
4897
+ "tar",
4898
+ "rar",
4899
+ "7z",
4900
+ "bz2",
4901
+ "xz",
4902
+ "rss",
4903
+ "atom",
4904
+ "ics",
4905
+ "vcf",
4906
+ "epub",
4907
+ "mobi",
4908
+ "apk",
4909
+ "dmg",
4910
+ "exe",
4911
+ "bin",
4912
+ "iso",
4913
+ "sql"
4914
+ ]);
4915
+ var SITEMAP_BASENAME = /^sitemap(?:[-_]index)?$/;
4916
+ function classifyTrafficPath(pathNormalized) {
4917
+ const raw = (pathNormalized ?? "").trim();
4918
+ if (!raw) return TrafficPathClasses.other;
4919
+ const rawPath = raw.split(/[?#]/)[0] ?? "";
4920
+ const pathOnly = rawPath.length > 1 ? rawPath.replace(/\/+$/, "") || "/" : rawPath;
4921
+ if (!pathOnly) return TrafficPathClasses.other;
4922
+ const lower = pathOnly.toLowerCase();
4923
+ const segments = lower.split("/");
4924
+ const basename = segments[segments.length - 1] ?? "";
4925
+ if (ROBOTS_BASENAMES.has(basename)) return TrafficPathClasses.robots;
4926
+ if (lower.endsWith(".xml") || lower.endsWith(".xml.gz")) return TrafficPathClasses.sitemap;
4927
+ if (SITEMAP_BASENAME.test(basename)) return TrafficPathClasses.sitemap;
4928
+ const dot = basename.lastIndexOf(".");
4929
+ const ext = dot > 0 ? basename.slice(dot + 1) : "";
4930
+ if (ext) {
4931
+ if (ASSET_EXTENSIONS.has(ext)) return TrafficPathClasses.asset;
4932
+ if (DOCUMENT_EXTENSIONS.has(ext)) return TrafficPathClasses.content;
4933
+ if (DOWNLOAD_EXTENSIONS.has(ext)) return TrafficPathClasses.other;
4934
+ return TrafficPathClasses.content;
4935
+ }
4936
+ return TrafficPathClasses.content;
4937
+ }
4938
+ function emptyCrawlerSegments() {
4939
+ return { content: 0, sitemap: 0, robots: 0, asset: 0, other: 0 };
4940
+ }
4941
+ function segmentCrawlerHits(rows) {
4942
+ const segments = emptyCrawlerSegments();
4943
+ for (const row of rows) {
4944
+ segments[classifyTrafficPath(row.pathNormalized)] += row.hits;
4945
+ }
4946
+ return segments;
4947
+ }
4948
+ function sumInfraHits(segments) {
4949
+ return segments.sitemap + segments.robots + segments.asset;
4950
+ }
4951
+
4787
4952
  // ../contracts/src/formatting.ts
4788
4953
  function formatRatio(value) {
4789
4954
  if (!Number.isFinite(value) || value === 0) return "0%";
@@ -5285,6 +5450,9 @@ export {
5285
5450
  trafficEventKindSchema,
5286
5451
  TrafficEventKinds,
5287
5452
  trafficEventsResponseSchema,
5453
+ classifyTrafficPath,
5454
+ segmentCrawlerHits,
5455
+ sumInfraHits,
5288
5456
  formatRatio,
5289
5457
  formatNumber,
5290
5458
  formatDate,
@@ -23,7 +23,7 @@ import {
23
23
  trafficConnectVercelRequestSchema,
24
24
  trafficConnectWordpressRequestSchema,
25
25
  trafficEventKindSchema
26
- } from "./chunk-MDRDX5R2.js";
26
+ } from "./chunk-JZ67YCHT.js";
27
27
 
28
28
  // src/config.ts
29
29
  import fs from "fs";
@@ -86,6 +86,7 @@ import {
86
86
  classifyCitedSurface,
87
87
  classifySkillFile,
88
88
  classifySurfaceFromCategory,
89
+ classifyTrafficPath,
89
90
  clusterByCosine,
90
91
  coerceSkillManifest,
91
92
  competitorBatchRequestSchema,
@@ -210,6 +211,7 @@ import {
210
211
  scheduleDtoSchema,
211
212
  scheduleUpsertRequestSchema,
212
213
  seedCollapseWarning,
214
+ segmentCrawlerHits,
213
215
  serializeRunError,
214
216
  settingsDtoSchema,
215
217
  siteAuditPagesResponseSchema,
@@ -222,6 +224,7 @@ import {
222
224
  snapshotReportSchema,
223
225
  snapshotRequestSchema,
224
226
  sourceBreakdownDtoSchema,
227
+ sumInfraHits,
225
228
  summarizeCheckResults,
226
229
  surfaceClassFromCompetitorType,
227
230
  surfaceClassLabel,
@@ -255,7 +258,7 @@ import {
255
258
  wordpressSchemaDeployResultDtoSchema,
256
259
  wordpressSchemaStatusResultDtoSchema,
257
260
  wordpressStatusDtoSchema
258
- } from "./chunk-MDRDX5R2.js";
261
+ } from "./chunk-JZ67YCHT.js";
259
262
 
260
263
  // src/intelligence-service.ts
261
264
  import { eq as eq37, desc as desc18, asc as asc5, and as and27, ne as ne5, or as or5, inArray as inArray14, gte as gte7, lte as lte4 } from "drizzle-orm";
@@ -30625,12 +30628,19 @@ async function trafficRoutes(app, opts) {
30625
30628
  return response;
30626
30629
  });
30627
30630
  function buildSourceDetail(projectId, row, since) {
30628
- const crawlerTotals = app.db.select({ total: sql11`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
30631
+ const crawlerPathRows = app.db.select({
30632
+ pathNormalized: crawlerEventsHourly.pathNormalized,
30633
+ hits: sql11`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
30634
+ }).from(crawlerEventsHourly).where(
30629
30635
  and21(
30630
30636
  eq27(crawlerEventsHourly.sourceId, row.id),
30631
30637
  gte4(crawlerEventsHourly.tsHour, since)
30632
30638
  )
30633
- ).get();
30639
+ ).groupBy(crawlerEventsHourly.pathNormalized).all();
30640
+ const crawlerSegments = segmentCrawlerHits(
30641
+ crawlerPathRows.map((r) => ({ pathNormalized: r.pathNormalized, hits: Number(r.hits) }))
30642
+ );
30643
+ const crawlerTotal = crawlerSegments.content + crawlerSegments.sitemap + crawlerSegments.robots + crawlerSegments.asset + crawlerSegments.other;
30634
30644
  const aiUserFetchTotals = app.db.select({ total: sql11`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
30635
30645
  and21(
30636
30646
  eq27(aiUserFetchEventsHourly.sourceId, row.id),
@@ -30659,7 +30669,10 @@ async function trafficRoutes(app, opts) {
30659
30669
  return {
30660
30670
  ...rowToDto(row),
30661
30671
  totals24h: {
30662
- crawlerHits: Number(crawlerTotals?.total ?? 0),
30672
+ crawlerHits: crawlerTotal,
30673
+ crawlerContentHits: crawlerSegments.content,
30674
+ crawlerInfraHits: sumInfraHits(crawlerSegments),
30675
+ crawlerSegments,
30663
30676
  aiUserFetchHits: Number(aiUserFetchTotals?.total ?? 0),
30664
30677
  aiReferralHits: Number(aiTotals?.total ?? 0),
30665
30678
  sampleCount: Number(sampleTotals?.total ?? 0)
@@ -30776,6 +30789,7 @@ async function trafficRoutes(app, opts) {
30776
30789
  const untilIso = until.toISOString();
30777
30790
  const events = [];
30778
30791
  let crawlerTotal = 0;
30792
+ let crawlerSegments = { content: 0, sitemap: 0, robots: 0, asset: 0, other: 0 };
30779
30793
  let aiUserFetchTotal = 0;
30780
30794
  let aiReferralTotal = 0;
30781
30795
  if (kind === "all" || kind === TrafficEventKinds.crawler) {
@@ -30786,8 +30800,14 @@ async function trafficRoutes(app, opts) {
30786
30800
  ];
30787
30801
  if (sourceIdParam) crawlerFilters.push(eq27(crawlerEventsHourly.sourceId, sourceIdParam));
30788
30802
  const crawlerWhere = and21(...crawlerFilters);
30789
- const total = app.db.select({ total: sql11`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(crawlerWhere).get();
30790
- crawlerTotal = Number(total?.total ?? 0);
30803
+ const pathTotals = app.db.select({
30804
+ pathNormalized: crawlerEventsHourly.pathNormalized,
30805
+ hits: sql11`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
30806
+ }).from(crawlerEventsHourly).where(crawlerWhere).groupBy(crawlerEventsHourly.pathNormalized).all();
30807
+ crawlerSegments = segmentCrawlerHits(
30808
+ pathTotals.map((r) => ({ pathNormalized: r.pathNormalized, hits: Number(r.hits) }))
30809
+ );
30810
+ crawlerTotal = crawlerSegments.content + crawlerSegments.sitemap + crawlerSegments.robots + crawlerSegments.asset + crawlerSegments.other;
30791
30811
  const rows = app.db.select().from(crawlerEventsHourly).where(crawlerWhere).orderBy(desc15(crawlerEventsHourly.tsHour)).limit(limit).all();
30792
30812
  for (const r of rows) {
30793
30813
  events.push({
@@ -30798,6 +30818,7 @@ async function trafficRoutes(app, opts) {
30798
30818
  operator: r.operator,
30799
30819
  verificationStatus: r.verificationStatus,
30800
30820
  pathNormalized: r.pathNormalized,
30821
+ pathClass: classifyTrafficPath(r.pathNormalized),
30801
30822
  status: r.status,
30802
30823
  hits: r.hits
30803
30824
  });
@@ -30861,6 +30882,9 @@ async function trafficRoutes(app, opts) {
30861
30882
  windowEnd: untilIso,
30862
30883
  totals: {
30863
30884
  crawlerHits: crawlerTotal,
30885
+ crawlerContentHits: crawlerSegments.content,
30886
+ crawlerInfraHits: sumInfraHits(crawlerSegments),
30887
+ crawlerSegments,
30864
30888
  aiUserFetchHits: aiUserFetchTotal,
30865
30889
  aiReferralHits: aiReferralTotal
30866
30890
  },
package/dist/cli.js CHANGED
@@ -27,7 +27,7 @@ import {
27
27
  setTelemetrySource,
28
28
  showFirstRunNotice,
29
29
  trackEvent
30
- } from "./chunk-DUDFNP5Y.js";
30
+ } from "./chunk-2VEFNAQ3.js";
31
31
  import {
32
32
  CliError,
33
33
  EXIT_SYSTEM_ERROR,
@@ -44,7 +44,7 @@ import {
44
44
  saveConfig,
45
45
  saveConfigPatch,
46
46
  usageError
47
- } from "./chunk-6XMXBAEW.js";
47
+ } from "./chunk-RH3QYFX3.js";
48
48
  import {
49
49
  apiKeys,
50
50
  createClient,
@@ -52,7 +52,7 @@ import {
52
52
  projects,
53
53
  queries,
54
54
  renderReportHtml
55
- } from "./chunk-5LW7CJAO.js";
55
+ } from "./chunk-WMZJO56S.js";
56
56
  import {
57
57
  BacklinkSources,
58
58
  CcReleaseSyncStatuses,
@@ -77,7 +77,7 @@ import {
77
77
  providerQuotaPolicySchema,
78
78
  resolveProviderInput,
79
79
  winnabilityClassSchema
80
- } from "./chunk-MDRDX5R2.js";
80
+ } from "./chunk-JZ67YCHT.js";
81
81
 
82
82
  // src/cli.ts
83
83
  import { pathToFileURL } from "url";
@@ -4245,7 +4245,10 @@ async function trafficStatus(project, opts) {
4245
4245
  console.log(` Status: ${d.status}`);
4246
4246
  console.log(` Last synced: ${d.lastSyncedAt ?? "never"}`);
4247
4247
  if (d.lastError) console.log(` Last error: ${d.lastError}`);
4248
- console.log(` 24h crawler: ${d.totals24h.crawlerHits} hits`);
4248
+ console.log(` 24h content: ${d.totals24h.crawlerContentHits} crawls`);
4249
+ console.log(` 24h infra: ${d.totals24h.crawlerInfraHits} sitemap/robots/asset fetches`);
4250
+ console.log(` 24h other: ${d.totals24h.crawlerSegments.other} fetches`);
4251
+ console.log(` 24h crawler: ${d.totals24h.crawlerHits} hits total`);
4249
4252
  console.log(` 24h AI referral: ${d.totals24h.aiReferralHits} sessions`);
4250
4253
  console.log(` 24h samples: ${d.totals24h.sampleCount}`);
4251
4254
  if (d.latestRun) {
@@ -4268,7 +4271,7 @@ function formatEventLine(event) {
4268
4271
  event.botId,
4269
4272
  event.verificationStatus,
4270
4273
  String(event.status),
4271
- event.pathNormalized,
4274
+ `${event.pathNormalized} [${event.pathClass}]`,
4272
4275
  `${event.hits} hits`
4273
4276
  ].join(" ");
4274
4277
  case TrafficEventKinds["ai-user-fetch"]:
@@ -4328,7 +4331,10 @@ async function trafficEvents(project, opts) {
4328
4331
  return;
4329
4332
  }
4330
4333
  console.log(`Traffic events for "${project}" ${result.windowStart} \u2192 ${result.windowEnd}`);
4331
- console.log(` Crawler hits (window): ${result.totals.crawlerHits}`);
4334
+ console.log(` Content crawls (window): ${result.totals.crawlerContentHits}`);
4335
+ console.log(` Infra fetches (window): ${result.totals.crawlerInfraHits} (sitemap ${result.totals.crawlerSegments.sitemap} \xB7 robots ${result.totals.crawlerSegments.robots} \xB7 asset ${result.totals.crawlerSegments.asset})`);
4336
+ console.log(` Other fetches (window): ${result.totals.crawlerSegments.other}`);
4337
+ console.log(` Crawler hits total (window): ${result.totals.crawlerHits}`);
4332
4338
  console.log(` AI user-fetch hits (window): ${result.totals.aiUserFetchHits}`);
4333
4339
  console.log(` AI referral sessions (window): ${result.totals.aiReferralHits}`);
4334
4340
  console.log("");
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  createServer
3
- } from "./chunk-DUDFNP5Y.js";
3
+ } from "./chunk-2VEFNAQ3.js";
4
4
  import {
5
5
  loadConfig
6
- } from "./chunk-6XMXBAEW.js";
7
- import "./chunk-5LW7CJAO.js";
8
- import "./chunk-MDRDX5R2.js";
6
+ } from "./chunk-RH3QYFX3.js";
7
+ import "./chunk-WMZJO56S.js";
8
+ import "./chunk-JZ67YCHT.js";
9
9
  export {
10
10
  createServer,
11
11
  loadConfig
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  IntelligenceService
3
- } from "./chunk-5LW7CJAO.js";
4
- import "./chunk-MDRDX5R2.js";
3
+ } from "./chunk-WMZJO56S.js";
4
+ import "./chunk-JZ67YCHT.js";
5
5
  export {
6
6
  IntelligenceService
7
7
  };
package/dist/mcp.js CHANGED
@@ -3,10 +3,10 @@ import {
3
3
  PACKAGE_VERSION,
4
4
  canonryMcpTools,
5
5
  createApiClient
6
- } from "./chunk-6XMXBAEW.js";
6
+ } from "./chunk-RH3QYFX3.js";
7
7
  import {
8
8
  isReadOnlyKey
9
- } from "./chunk-MDRDX5R2.js";
9
+ } from "./chunk-JZ67YCHT.js";
10
10
 
11
11
  // src/mcp/cli.ts
12
12
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ainyc/canonry",
3
- "version": "4.87.0",
3
+ "version": "4.88.0",
4
4
  "type": "module",
5
5
  "description": "Agent-first open-source AEO operating platform - track how answer engines cite your domain",
6
6
  "license": "FSL-1.1-ALv2",
@@ -62,25 +62,25 @@
62
62
  "@types/node-cron": "^3.0.11",
63
63
  "tsup": "^8.5.1",
64
64
  "tsx": "^4.19.0",
65
- "@ainyc/canonry-api-routes": "0.0.0",
66
- "@ainyc/canonry-config": "0.0.0",
67
65
  "@ainyc/canonry-api-client": "0.0.0",
66
+ "@ainyc/canonry-config": "0.0.0",
67
+ "@ainyc/canonry-api-routes": "0.0.0",
68
68
  "@ainyc/canonry-contracts": "0.0.0",
69
69
  "@ainyc/canonry-db": "0.0.0",
70
- "@ainyc/canonry-integration-openai-ads": "0.0.0",
70
+ "@ainyc/canonry-integration-bing": "0.0.0",
71
71
  "@ainyc/canonry-integration-cloud-run": "0.0.0",
72
72
  "@ainyc/canonry-integration-commoncrawl": "0.0.0",
73
- "@ainyc/canonry-integration-bing": "0.0.0",
74
- "@ainyc/canonry-integration-google-business-profile": "0.0.0",
75
73
  "@ainyc/canonry-integration-google": "0.0.0",
74
+ "@ainyc/canonry-integration-openai-ads": "0.0.0",
75
+ "@ainyc/canonry-integration-google-business-profile": "0.0.0",
76
76
  "@ainyc/canonry-integration-google-places": "0.0.0",
77
77
  "@ainyc/canonry-integration-traffic": "0.0.0",
78
- "@ainyc/canonry-integration-wordpress": "0.0.0",
79
78
  "@ainyc/canonry-intelligence": "0.0.0",
80
- "@ainyc/canonry-provider-gemini": "0.0.0",
81
- "@ainyc/canonry-provider-local": "0.0.0",
79
+ "@ainyc/canonry-integration-wordpress": "0.0.0",
82
80
  "@ainyc/canonry-provider-cdp": "0.0.0",
81
+ "@ainyc/canonry-provider-gemini": "0.0.0",
83
82
  "@ainyc/canonry-provider-claude": "0.0.0",
83
+ "@ainyc/canonry-provider-local": "0.0.0",
84
84
  "@ainyc/canonry-provider-openai": "0.0.0",
85
85
  "@ainyc/canonry-provider-perplexity": "0.0.0"
86
86
  },
@@ -1 +0,0 @@
1
- import{j as e,A as Re,B as Le,r as h,L as $e}from"./vendor-tanstack-Dq7p98wZ.js";import{I as O,c2 as Y,c3 as u,T as Ee,B as Ue,g as H,b as Fe,c4 as Me,c5 as He}from"./index-C_ZzKZfM.js";import{g as Pe,h as Oe,i as De,t as Be,R as _e,d as Ge}from"./extract-error-message-C7Vhd5zH.js";import{e as ee,i as Ke,C as ie,a as le,c as We,h as Ve}from"./ChartPrimitives-BdlKCq7y.js";import{R as Ye,B as Xe,a as Qe,X as qe,Y as Ze,T as Je,e as X,f as Q}from"./vendor-recharts-ClRVR6aX.js";import{A as ce}from"./arrow-left-B5Du72nk.js";import"./vendor-radix-B57xfQbP.js";import"./vendor-markdown-DK7fbRNb.js";function q({value:s,label:a,delta:n,tone:r,description:x,tooltip:l,isNumeric:c=!0,progress:o,providerCoverage:d}){const v=2*Math.PI*48,m=Number.parseInt(s,10),I=typeof o=="number"&&Number.isFinite(o)?Math.min(Math.max(o,0),100)/100:c&&!Number.isNaN(m)?Math.min(m/100,1):.5,y=v*(1-I);return e.jsxs("div",{className:"score-gauge",children:[e.jsxs("div",{className:"gauge-ring-wrapper",children:[e.jsxs("svg",{className:"gauge-ring",viewBox:"0 0 120 120","aria-hidden":"true",children:[e.jsx("circle",{className:"gauge-bg",cx:"60",cy:"60",r:48,strokeWidth:6}),e.jsx("circle",{className:`gauge-fill gauge-fill-${r}`,cx:"60",cy:"60",r:48,strokeWidth:6,strokeDasharray:v,strokeDashoffset:y,transform:"rotate(-90 60 60)"})]}),e.jsx("div",{className:"gauge-center",children:e.jsx("span",{className:c?"gauge-value":"gauge-value-text",children:s.split(" / ")[0]})})]}),e.jsxs("p",{className:"gauge-label",children:[a,l&&e.jsx(O,{text:l})]}),e.jsx("p",{className:"gauge-delta",children:n}),d&&e.jsx("p",{className:"gauge-provider-coverage",children:d}),e.jsx("p",{className:"gauge-description",children:x})]})}const et=[{value:"all",label:"All status"},{value:"2xx",label:"2xx success"},{value:"3xx",label:"3xx redirect"},{value:"4xx",label:"4xx client error"},{value:"5xx",label:"5xx server error"}],fe=[{value:"all",label:"All claims"},{value:Y.verified,label:"Verified"},{value:Y.claimed_unverified,label:"Claimed unverified"},{value:Y.unknown_ai_like,label:"Unknown AI-like"}];function tt(s){return s==="all"?null:Number.parseInt(s[0],10)}function pe(s){switch(s.kind){case u.crawler:case u["ai-user-fetch"]:return s.botId;case u["ai-referral"]:return s.product}}function ge(s){switch(s.kind){case u.crawler:case u["ai-user-fetch"]:return s.pathNormalized;case u["ai-referral"]:return s.landingPathNormalized}}function st(s){switch(s.kind){case u.crawler:case u["ai-user-fetch"]:return s.verificationStatus;case u["ai-referral"]:return null}}function be(s,a){if(a==="hour")return s;const n=new Date(s),r=n.getFullYear(),x=String(n.getMonth()+1).padStart(2,"0"),l=String(n.getDate()).padStart(2,"0");return`${r}-${x}-${l}`}function at(s,a,n){const r=a.pathQuery.trim().toLowerCase(),x=tt(a.statusClass);return s.filter(l=>!(a.selectedBucket&&be(l.tsHour,n)!==a.selectedBucket||a.identity&&pe(l)!==a.identity||a.operator&&l.operator!==a.operator||r&&!ge(l).toLowerCase().includes(r)||x!==null&&Math.floor(l.status/100)!==x||a.verification!=="all"&&st(l)!==a.verification))}function rt(s,a){if(!s||typeof s!="object")return null;const n=s.activeTooltipIndex;let r;if(typeof n=="number")r=n;else if(typeof n=="string"&&n!=="")r=Number(n);else return null;return!Number.isInteger(r)||r<0||r>=a.length?null:a[r]?.bucket??null}const D=[{value:60,label:"1h",granularity:"hour",fetchLimit:500},{value:360,label:"6h",granularity:"hour",fetchLimit:500},{value:1440,label:"24h",granularity:"hour",fetchLimit:500},{value:10080,label:"7d",granularity:"hour",fetchLimit:1e3},{value:720*60,label:"30d",granularity:"day",fetchLimit:2e3},{value:2160*60,label:"90d",granularity:"day",fetchLimit:5e3}],oe=D.find(s=>s.label==="24h")??D[2],L=50,ue=ee[0],de=ee[2],xe=ee[1],he=Me();function je(s){const a=new Date(s);return`${a.getMonth()+1}/${a.getDate()} ${String(a.getHours()).padStart(2,"0")}:00`}function nt(s){const a=new Date(`${s}T00:00:00`);return`${a.getMonth()+1}/${a.getDate()}`}function $(s){if(!s)return"never";const a=Date.now()-new Date(s).getTime(),n=Math.floor(a/6e4);if(n<1)return"just now";if(n<60)return`${n}m ago`;const r=Math.floor(n/60);return r<24?`${r}h ago`:`${Math.floor(r/24)}d ago`}function me({canGoBack:s,className:a}){const n="inline-flex items-center gap-1";if(s){const r=()=>{window.history.back()};return e.jsxs("button",{type:"button",onClick:r,className:`${n} ${a??""}`,children:[e.jsx(ce,{className:"size-3"})," Back"]})}return e.jsxs($e,{to:"/traffic",className:`${n} ${a??""}`,children:[e.jsx(ce,{className:"size-3"})," All sources"]})}function yt(){const s=Re({strict:!1}),a=s.projectName??"",n=Le(),r=s.sourceId??"",[x,l]=h.useState(oe.value),[c,o]=h.useState(()=>new Set(["crawler","ai-user-fetch","ai-referral"])),[d,z]=h.useState(null),[f,v]=h.useState(""),[m,I]=h.useState(""),[y,B]=h.useState(""),[S,_]=h.useState("all"),[k,G]=h.useState("all"),[ye,K]=h.useState(1),[te,se]=h.useState(null),[ae,re]=h.useState(null),b=h.useMemo(()=>D.find(t=>t.value===x)??oe,[x]),W=Pe(a||null,r||null),j=Oe(a||null,{kind:"all",sourceId:r||void 0,sinceMinutes:x,limit:b.fetchLimit}),E=De(a||null,r||null),i=W.data,N=j.data?.events??[],C=j.data?.totals,U=h.useMemo(()=>N.filter(t=>{switch(t.kind){case u.crawler:return c.has("crawler");case u["ai-user-fetch"]:return c.has("ai-user-fetch");case u["ai-referral"]:return c.has("ai-referral")}}),[N,c]),ve=h.useMemo(()=>{const t=new Set;for(const p of N)t.add(pe(p));return f&&t.add(f),[...t].sort((p,g)=>p.localeCompare(g))},[N,f]),Ne=h.useMemo(()=>{const t=new Set;for(const p of N)t.add(p.operator);return m&&t.add(m),[...t].sort((p,g)=>p.localeCompare(g))},[N,m]),w=h.useMemo(()=>at(U,{selectedBucket:d,identity:f,operator:m,pathQuery:y,statusClass:S,verification:k},b.granularity),[U,d,f,m,y,S,k,b.granularity]);h.useEffect(()=>{K(1)},[U,d,f,m,y,S,k]);const F=Math.max(1,Math.ceil(w.length/L)),M=Math.min(Math.max(1,ye),F),R=(M-1)*L,we=h.useMemo(()=>w.slice(R,R+L),[w,R]),ze=w.length>L,Se=w.length===0?0:R+1,ke=Math.min(R+L,w.length),ne=h.useMemo(()=>d?P(d,b.granularity):null,[d,b.granularity]),T=h.useMemo(()=>it(N,b.granularity,j.data?.windowStart,j.data?.windowEnd),[N,b.granularity,j.data?.windowStart,j.data?.windowEnd]),V=t=>{o(p=>{const g=new Set(p);return g.has(t)?g.size>1&&g.delete(t):g.add(t),g})},Ce=t=>{const p=rt(t,T);p&&z(g=>g===p?null:p)},Te=()=>{z(null),v(""),I(""),B(""),_("all"),G("all")},Ae=!!(d||f||m||y.trim()||S!=="all"||k!=="all"),Ie=async()=>{se(null),re(null);try{const t=await E.mutateAsync({sinceMinutes:60});re(`Pulled ${t.pulledEvents} entries · ${t.crawlerHits} crawler · ${t.aiUserFetchHits} AI user fetch · ${t.aiReferralHits} AI referral · ${t.unknownHits} unknown`)}catch(t){se(Ge(t))}};return!a||!r?e.jsx("div",{className:"page-container",children:e.jsx("p",{className:"text-sm text-zinc-500",children:"Missing project name or source id in URL."})}):W.isLoading?e.jsx("div",{className:"page-container",children:e.jsx("p",{className:"text-sm text-zinc-500",children:"Loading source…"})}):W.isError||!i?e.jsxs("div",{className:"page-container",children:[e.jsx("p",{className:"text-sm text-rose-300",children:"Could not load this source."}),e.jsx(me,{canGoBack:n,className:"mt-2 text-xs text-zinc-400 hover:text-zinc-200"})]}):e.jsxs("div",{className:"page-container space-y-8",children:[e.jsxs("div",{className:"page-header",children:[e.jsxs("div",{className:"page-header-left",children:[e.jsx(me,{canGoBack:n,className:"text-xs text-zinc-500 hover:text-zinc-200"}),e.jsx("h1",{className:"page-title mt-2",children:i.displayName}),e.jsxs("p",{className:"page-subtitle",children:[i.sourceType," · project ",e.jsx("span",{className:"text-zinc-300",children:a})," ·",e.jsx("span",{className:"ml-1 font-mono text-zinc-400",children:i.id})]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(Ee,{tone:Be(i.status),children:i.status}),e.jsxs(Ue,{type:"button",variant:"outline",size:"sm",disabled:E.isPending,onClick:()=>{Ie()},children:[e.jsx(_e,{className:`size-3.5 ${E.isPending?"animate-spin":""}`}),E.isPending?"Syncing…":"Sync now"]})]})]}),te?e.jsx("div",{className:"rounded-md border border-rose-800/50 bg-rose-950/30 px-3 py-2 text-xs text-rose-200",children:te}):null,ae?e.jsx("div",{className:"rounded-md border border-emerald-800/50 bg-emerald-950/30 px-3 py-2 text-xs text-emerald-200",children:ae}):null,e.jsxs("section",{className:"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3",children:[e.jsx(q,{label:"24h crawler hits",value:String(i.totals24h.crawlerHits),delta:i.lastSyncedAt?`last sync ${$(i.lastSyncedAt)}`:"never synced",tone:i.totals24h.crawlerHits>0?"positive":"neutral",description:"Bulk machine crawl — GPTBot, OAI-SearchBot, PerplexityBot, Googlebot, etc.",isNumeric:!0,progress:Math.min(100,Math.round(i.totals24h.crawlerHits/1e3*100))}),e.jsx(q,{label:"24h AI user fetches",value:String(i.totals24h.aiUserFetchHits),delta:i.lastSyncedAt?`last sync ${$(i.lastSyncedAt)}`:"never synced",tone:i.totals24h.aiUserFetchHits>0?"positive":"neutral",description:"ChatGPT-User, Perplexity-User — fetches initiated by a real user inside an AI surface (citation click, URL read).",isNumeric:!0,progress:Math.min(100,Math.round(i.totals24h.aiUserFetchHits/1e3*100))}),e.jsx(q,{label:"24h AI referral sessions",value:String(i.totals24h.aiReferralHits),delta:i.lastSyncedAt?`last sync ${$(i.lastSyncedAt)}`:"never synced",tone:i.totals24h.aiReferralHits>0?"positive":"neutral",description:"Browser click-throughs from chatgpt.com, perplexity.ai, etc. (Referer / UTM evidence).",isNumeric:!0,progress:Math.min(100,Math.round(i.totals24h.aiReferralHits/1e3*100))})]}),e.jsxs("section",{children:[e.jsx("p",{className:"mb-4 text-[10px] font-semibold uppercase tracking-wider text-zinc-500",children:"Latest sync run"}),i.latestRun?e.jsxs(H,{className:"p-4 text-sm",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-x-6 gap-y-1.5",children:[e.jsxs("span",{className:"text-zinc-100",children:["Status: ",e.jsx("span",{className:"font-medium",children:i.latestRun.status})]}),e.jsxs("span",{className:"text-zinc-500",children:["Started: ",$(i.latestRun.startedAt)]}),i.latestRun.finishedAt?e.jsxs("span",{className:"text-zinc-500",children:["Finished: ",$(i.latestRun.finishedAt)]}):null,e.jsx("span",{className:"font-mono text-[11px] text-zinc-600",children:i.latestRun.runId})]}),i.latestRun.error?e.jsx("p",{className:"mt-2 rounded border border-rose-900/40 bg-rose-950/30 px-3 py-2 text-xs text-rose-300",children:i.latestRun.error}):null]}):e.jsx(H,{className:"px-4 py-3 text-sm text-zinc-500",children:'No traffic-sync runs recorded yet. Hit "Sync now" above to create one.'})]}),e.jsxs("section",{children:[e.jsxs("div",{className:"mb-4 flex flex-wrap items-end justify-between gap-x-4 gap-y-3",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-[10px] font-semibold uppercase tracking-wider text-zinc-500",children:"Events"}),e.jsx("h2",{className:"mt-1 text-base font-semibold text-zinc-50",children:b.granularity==="day"?"Daily rollups":"Hourly rollups"}),C?e.jsxs("p",{className:"mt-1.5 text-xs text-zinc-500",children:[C.crawlerHits.toLocaleString("en-US")," crawler ·"," ",C.aiUserFetchHits.toLocaleString("en-US")," AI user fetches ·"," ",C.aiReferralHits.toLocaleString("en-US")," AI referral sessions · last ",b.label," · ",he]}):null]}),e.jsx("div",{className:"filter-row mb-0",role:"toolbar","aria-label":"Window",children:D.map(t=>e.jsx("button",{type:"button",className:`filter-chip ${x===t.value?"filter-chip-active":""}`,"aria-pressed":x===t.value,onClick:()=>{l(t.value),z(null)},children:t.label},t.value))})]}),e.jsxs(H,{className:"p-4",children:[e.jsxs("div",{className:"mb-3 flex flex-wrap items-center gap-2",role:"toolbar","aria-label":"Series",children:[e.jsx(J,{label:"Crawler",color:ue,count:C?.crawlerHits??0,active:c.has("crawler"),onToggle:()=>V("crawler")}),e.jsx(J,{label:"AI user fetches",color:de,count:C?.aiUserFetchHits??0,active:c.has("ai-user-fetch"),onToggle:()=>V("ai-user-fetch")}),e.jsx(J,{label:"AI referral sessions",color:xe,count:C?.aiReferralHits??0,active:c.has("ai-referral"),onToggle:()=>V("ai-referral")})]}),j.isError?e.jsxs("p",{className:"py-12 text-center text-xs text-rose-400",children:["Failed to load events: ",j.error instanceof Error?j.error.message:"Unknown error"]}):j.isLoading?e.jsx("p",{className:"py-12 text-center text-xs text-zinc-500",children:"Loading events…"}):T.length===0?e.jsx("p",{className:"py-12 text-center text-xs text-zinc-500",children:"No events in this window."}):e.jsx("div",{className:"h-72",children:e.jsx(Ye,{children:e.jsxs(Xe,{data:T,margin:{top:4,right:4,bottom:0,left:0},onClick:Ce,style:{cursor:"pointer"},children:[e.jsx(Qe,{stroke:Ke,strokeDasharray:"3 3"}),e.jsx(qe,{dataKey:"label",tick:le,stroke:ie,interval:"preserveStartEnd",minTickGap:b.granularity==="day"?24:32}),e.jsx(Ze,{tick:le,stroke:ie,allowDecimals:!1}),e.jsx(Je,{...We}),c.has("crawler")?e.jsx(X,{dataKey:"crawler",name:"Crawler",fill:ue,stackId:"a",children:T.map(t=>e.jsx(Q,{fillOpacity:d&&d!==t.bucket?.25:1},t.bucket))}):null,c.has("ai-user-fetch")?e.jsx(X,{dataKey:"aiUserFetch",name:"AI user fetch",fill:de,stackId:"a",children:T.map(t=>e.jsx(Q,{fillOpacity:d&&d!==t.bucket?.25:1},t.bucket))}):null,c.has("ai-referral")?e.jsx(X,{dataKey:"aiReferral",name:"AI referral",fill:xe,stackId:"a",children:T.map(t=>e.jsx(Q,{fillOpacity:d&&d!==t.bucket?.25:1},t.bucket))}):null]})})})]})]}),e.jsxs("section",{children:[e.jsxs("div",{className:"mb-4 flex flex-wrap items-end justify-between gap-x-4 gap-y-2",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-[10px] font-semibold uppercase tracking-wider text-zinc-500",children:"Event rows"}),e.jsxs("p",{className:"mt-1 text-xs text-zinc-500",children:["Showing ",e.jsx("span",{className:"tabular-nums text-zinc-300",children:w.length.toLocaleString("en-US")})," of"," ",e.jsx("span",{className:"tabular-nums text-zinc-500",children:U.length.toLocaleString("en-US")})," events · ",he]})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsxs("span",{className:"inline-flex items-center text-zinc-400",children:[e.jsxs("select",{"aria-label":"Filter by identity",value:f,onChange:t=>v(t.target.value),className:"rounded-md border border-zinc-800 bg-zinc-950 px-2.5 py-1.5 text-xs text-zinc-200 focus:outline-none focus-visible:ring-1 focus-visible:ring-zinc-600",children:[e.jsx("option",{value:"",children:"All identities"}),ve.map(t=>e.jsx("option",{value:t,children:t},t))]}),e.jsx(O,{text:"The specific bot or AI product making the request (e.g., GPTBot, ChatGPT-User, Perplexity). One operator usually runs several identities."})]}),e.jsxs("span",{className:"inline-flex items-center text-zinc-400",children:[e.jsxs("select",{"aria-label":"Filter by operator",value:m,onChange:t=>I(t.target.value),className:"rounded-md border border-zinc-800 bg-zinc-950 px-2.5 py-1.5 text-xs text-zinc-200 focus:outline-none focus-visible:ring-1 focus-visible:ring-zinc-600",children:[e.jsx("option",{value:"",children:"All operators"}),Ne.map(t=>e.jsx("option",{value:t,children:t},t))]}),e.jsx(O,{text:"The company that runs the bot or product (e.g., OpenAI, Anthropic, Perplexity). Filtering by operator includes every identity under that company."})]}),e.jsx("select",{"aria-label":"Filter by HTTP status class",value:S,onChange:t=>_(t.target.value),className:"rounded-md border border-zinc-800 bg-zinc-950 px-2.5 py-1.5 text-xs text-zinc-200 focus:outline-none focus-visible:ring-1 focus-visible:ring-zinc-600",children:et.map(t=>e.jsx("option",{value:t.value,children:t.label},t.value))}),e.jsx("select",{"aria-label":"Filter by verification claim",value:k,onChange:t=>G(t.target.value),className:"rounded-md border border-zinc-800 bg-zinc-950 px-2.5 py-1.5 text-xs text-zinc-200 focus:outline-none focus-visible:ring-1 focus-visible:ring-zinc-600",children:fe.map(t=>e.jsx("option",{value:t.value,children:t.label},t.value))}),e.jsx("input",{type:"search","aria-label":"Filter by path",placeholder:"path contains…",value:y,onChange:t=>B(t.target.value),className:"w-44 rounded-md border border-zinc-800 bg-zinc-950 px-2.5 py-1.5 text-xs text-zinc-200 placeholder:text-zinc-600 focus:outline-none focus-visible:ring-1 focus-visible:ring-zinc-600"})]})]}),Ae?e.jsxs("div",{className:"mb-3 flex flex-wrap items-center gap-2",children:[ne?e.jsx(A,{label:`Bucket: ${ne}`,onClear:()=>z(null)}):null,f?e.jsx(A,{label:`Identity: ${f}`,onClear:()=>v("")}):null,m?e.jsx(A,{label:`Operator: ${m}`,onClear:()=>I("")}):null,y.trim()?e.jsx(A,{label:`Path: ${y.trim()}`,onClear:()=>B("")}):null,S!=="all"?e.jsx(A,{label:`Status: ${S}`,onClear:()=>_("all")}):null,k!=="all"?e.jsx(A,{label:`Claim: ${lt(k)}`,onClear:()=>G("all")}):null,e.jsx("button",{type:"button",onClick:Te,className:"text-xs text-zinc-500 underline-offset-4 hover:text-zinc-200 hover:underline",children:"Clear all"})]}):null,e.jsx(dt,{events:we}),ze?e.jsxs("div",{className:"mt-3 flex flex-wrap items-center justify-between gap-x-4 gap-y-2 text-xs text-zinc-400",children:[e.jsxs("p",{className:"tabular-nums",children:["Showing ",e.jsx("span",{className:"text-zinc-300",children:Se.toLocaleString("en-US")}),"–",e.jsx("span",{className:"text-zinc-300",children:ke.toLocaleString("en-US")})," of"," ",e.jsx("span",{className:"text-zinc-300",children:w.length.toLocaleString("en-US")})," events"]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("button",{type:"button",onClick:()=>K(t=>Math.max(1,t-1)),disabled:M<=1,"aria-label":"Previous page",className:"inline-flex items-center gap-1 rounded-md border border-zinc-800 bg-zinc-950 px-2.5 py-1.5 text-zinc-200 transition hover:border-zinc-700 hover:text-zinc-50 disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:border-zinc-800 disabled:hover:text-zinc-200",children:[e.jsx(Ve,{className:"size-3.5"}),"Prev"]}),e.jsxs("span",{className:"tabular-nums",children:["Page ",e.jsx("span",{className:"text-zinc-200",children:M})," of"," ",e.jsx("span",{className:"text-zinc-200",children:F})]}),e.jsxs("button",{type:"button",onClick:()=>K(t=>Math.min(F,t+1)),disabled:M>=F,"aria-label":"Next page",className:"inline-flex items-center gap-1 rounded-md border border-zinc-800 bg-zinc-950 px-2.5 py-1.5 text-zinc-200 transition hover:border-zinc-700 hover:text-zinc-50 disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:border-zinc-800 disabled:hover:text-zinc-200",children:["Next",e.jsx(Fe,{className:"size-3.5"})]})]})]}):null]})]})}function Z(s,a){return{bucket:s,label:a,crawler:0,aiUserFetch:0,aiReferral:0}}function P(s,a){return a==="day"?nt(s):je(s)}function it(s,a,n,r){const x=new Map;for(const l of s){const c=be(l.tsHour,a);let o=x.get(c);switch(o||(o=Z(c,P(c,a)),x.set(c,o)),l.kind){case u.crawler:o.crawler+=l.hits;break;case u["ai-user-fetch"]:o.aiUserFetch+=l.hits;break;case u["ai-referral"]:o.aiReferral+=l.hits;break}}if(n&&r){const l=new Date(n),c=new Date(r);if(a==="day"){const o=new Date(Date.UTC(l.getUTCFullYear(),l.getUTCMonth(),l.getUTCDate())),d=new Date(Date.UTC(c.getUTCFullYear(),c.getUTCMonth(),c.getUTCDate()));for(;o<=d;){const z=o.getUTCFullYear(),f=String(o.getUTCMonth()+1).padStart(2,"0"),v=String(o.getUTCDate()).padStart(2,"0"),m=`${z}-${f}-${v}`;x.has(m)||x.set(m,Z(m,P(m,a))),o.setUTCDate(o.getUTCDate()+1)}}else{const o=new Date(l);for(o.setUTCMinutes(0,0,0);o<=c;){const d=o.toISOString();x.has(d)||x.set(d,Z(d,P(d,a))),o.setUTCHours(o.getUTCHours()+1)}}}return[...x.values()].sort((l,c)=>l.bucket<c.bucket?-1:l.bucket>c.bucket?1:0)}function lt(s){return fe.find(a=>a.value===s)?.label??s}function A({label:s,onClear:a}){return e.jsxs("span",{className:"inline-flex items-center gap-1.5 rounded-full border border-zinc-700 bg-zinc-800/60 px-2.5 py-1 text-[11px] text-zinc-200",children:[s,e.jsx("button",{type:"button",onClick:a,"aria-label":`Clear ${s}`,className:"rounded-full p-0.5 text-zinc-400 hover:bg-zinc-700/60 hover:text-zinc-100",children:e.jsx(He,{className:"size-3"})})]})}function J({label:s,color:a,count:n,active:r,onToggle:x}){return e.jsxs("button",{type:"button",onClick:x,"aria-pressed":r,className:`inline-flex items-center gap-2 rounded-full border px-3 py-1 text-xs font-medium transition ${r?"border-zinc-700 bg-zinc-800/60 text-zinc-100":"border-zinc-800 bg-transparent text-zinc-500 hover:text-zinc-300"}`,children:[e.jsx("span",{"aria-hidden":"true",className:`size-2 rounded-full transition-opacity ${r?"opacity-100":"opacity-30"}`,style:{backgroundColor:a}}),e.jsx("span",{children:s}),e.jsx("span",{className:`tabular-nums ${r?"text-zinc-400":"text-zinc-600"}`,children:n.toLocaleString("en-US")})]})}function ct(s){switch(s){case u.crawler:return"Crawler";case u["ai-user-fetch"]:return"AI hit";case u["ai-referral"]:return"AI referral"}}function ot(s){switch(s.kind){case u.crawler:case u["ai-user-fetch"]:return s.botId;case u["ai-referral"]:return s.product}}function ut(s){switch(s.kind){case u.crawler:case u["ai-user-fetch"]:return`${s.verificationStatus} · HTTP ${s.status}`;case u["ai-referral"]:return`${s.evidenceType} · ${s.sourceDomain}`}}function dt({events:s}){return s.length===0?e.jsx(H,{className:"p-6 text-center text-sm text-zinc-500",children:"No event rows match the current filters."}):e.jsx("div",{className:"rounded-xl border border-zinc-800/60 bg-zinc-900/30 overflow-hidden",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"bg-zinc-900/50 text-[10px] font-semibold uppercase tracking-wider text-zinc-500",children:e.jsxs("tr",{children:[e.jsx("th",{className:"px-4 py-2 text-left",children:"Hour"}),e.jsx("th",{className:"px-4 py-2 text-left",children:"Kind"}),e.jsx("th",{className:"px-4 py-2 text-left",children:"Identity"}),e.jsx("th",{className:"px-4 py-2 text-left",children:"Evidence / status"}),e.jsx("th",{className:"px-4 py-2 text-left",children:"Path"}),e.jsx("th",{className:"px-4 py-2 text-right",children:e.jsxs("span",{className:"inline-flex items-center",children:["Hits",e.jsx(O,{text:"Each row is one hour-bucket, not one request. Hits is the number of requests in that hour that shared the same identity, path, HTTP status, and verification claim."})]})})]})}),e.jsx("tbody",{className:"divide-y divide-zinc-800/60",children:s.map((a,n)=>e.jsxs("tr",{className:"hover:bg-zinc-900/40 transition-colors",children:[e.jsx("td",{className:"px-4 py-2 font-mono text-xs text-zinc-300",children:je(a.tsHour)}),e.jsx("td",{className:"px-4 py-2 text-zinc-300",children:ct(a.kind)}),e.jsxs("td",{className:"px-4 py-2 text-zinc-100",children:[ot(a),e.jsx("span",{className:"ml-2 text-[11px] text-zinc-500",children:a.operator})]}),e.jsx("td",{className:"px-4 py-2 text-zinc-300",children:ut(a)}),e.jsx("td",{className:"px-4 py-2 truncate font-mono text-xs text-zinc-300",children:ge(a)}),e.jsx("td",{className:"px-4 py-2 text-right tabular-nums text-zinc-100",children:a.hits})]},`${a.kind}:${a.tsHour}:${n}`))})]})})}export{yt as TrafficSourceDetailPage};