@canonry/canonry 4.176.0 → 4.177.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/assets/agent-workspace/skills/canonry/SKILL.md +7 -0
- package/assets/agent-workspace/skills/canonry/references/server-side-traffic.md +55 -9
- package/assets/assets/{AuditHistoryPanel-aEUCJheK.js → AuditHistoryPanel-YZvGU1la.js} +1 -1
- package/assets/assets/{BacklinksPage-BcWequGL.js → BacklinksPage-CB2uJWWy.js} +1 -1
- package/assets/assets/{HistoryPage-D0BWQK0c.js → HistoryPage-D9IxxbQ9.js} +1 -1
- package/assets/assets/{MeasurementPropertyPage-D96eQnYJ.js → MeasurementPropertyPage-CxgnnPdp.js} +1 -1
- package/assets/assets/{ProjectPage-CoRkwGec.js → ProjectPage-CPmaXzhL.js} +8 -8
- package/assets/assets/{RunRow--3y-0dSr.js → RunRow-2KxOta8F.js} +1 -1
- package/assets/assets/{RunsPage-7wdCl_J3.js → RunsPage-ya8vTkyd.js} +1 -1
- package/assets/assets/{SettingsPage-D37dV5-m.js → SettingsPage-lTy3o2bo.js} +1 -1
- package/assets/assets/{SiteHealthSection-B9WF97sJ.js → SiteHealthSection-Cyu7MIv2.js} +3 -3
- package/assets/assets/TrafficPage-DjhKfw57.js +1 -0
- package/assets/assets/TrafficSourceDetailPage-Pwi-Dl9Q.js +1 -0
- package/assets/assets/{extract-error-message-DlPqK0mV.js → extract-error-message-I1FVWHLH.js} +1 -1
- package/assets/assets/{index-CiQNKNMG.js → index-BeLVKN3H.js} +3 -3
- package/assets/assets/{react-sigma_core.esm.min-Dc7_SFjo.js → react-sigma_core.esm.min-BX6mOEq5.js} +1 -1
- package/assets/index.html +1 -1
- package/dist/{chunk-TIEHKR6K.js → chunk-6XUWDSLN.js} +10 -10
- package/dist/{chunk-J3RVQCCQ.js → chunk-GJE334DA.js} +1495 -1239
- package/dist/{chunk-OSMUOPBR.js → chunk-PQT3ECM3.js} +75 -10
- package/dist/{chunk-HYKZOCBT.js → chunk-QRE3DAAU.js} +2 -2
- package/dist/{chunk-DSGX2IAI.js → chunk-XFAPF2YX.js} +4 -4
- package/dist/cli.js +11 -8
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-RSZTVVX2.js → intelligence-service-C57RIB37.js} +2 -2
- package/dist/mcp.js +3 -3
- package/package.json +8 -8
- package/assets/assets/TrafficPage-Bn1yDSRr.js +0 -1
- package/assets/assets/TrafficSourceDetailPage-CURlB_yO.js +0 -1
|
@@ -13655,8 +13655,22 @@ var serverActivitySectionSchema = z47.object({
|
|
|
13655
13655
|
* not "is this a confirmed bot identity?"
|
|
13656
13656
|
*/
|
|
13657
13657
|
aiUserFetchHits: z47.object({ current: z47.number(), prior: z47.number(), deltaPct: z47.number().nullable() }),
|
|
13658
|
-
/**
|
|
13658
|
+
/**
|
|
13659
|
+
* Last-7d AI-referral sessions (sessionized from server-side request
|
|
13660
|
+
* evidence). Paid + organic + unclassified. Excludes subresource fetches and
|
|
13661
|
+
* requests answered with a Location redirect (301/302/303/307/308): a hop is
|
|
13662
|
+
* not an arrival, and its destination raises its own row. Redirect-answered
|
|
13663
|
+
* requests are reported separately in `referralRedirects`.
|
|
13664
|
+
*/
|
|
13659
13665
|
referralArrivals: z47.object({ current: z47.number(), prior: z47.number(), deltaPct: z47.number().nullable() }),
|
|
13666
|
+
/**
|
|
13667
|
+
* AI-referred requests in the current window that were answered with a
|
|
13668
|
+
* Location redirect instead of a page. Not arrivals — but a site where this
|
|
13669
|
+
* dominates has its AI traffic bouncing off a redirect before landing, which
|
|
13670
|
+
* is exactly the thing to fix, so the report must be able to say it rather
|
|
13671
|
+
* than render an empty section.
|
|
13672
|
+
*/
|
|
13673
|
+
referralRedirects: z47.number().int().nonnegative(),
|
|
13660
13674
|
/**
|
|
13661
13675
|
* `referralArrivals` split by traffic class. The three buckets sum to it.
|
|
13662
13676
|
*
|
|
@@ -14349,9 +14363,10 @@ var trafficSourceDtoSchema = z50.object({
|
|
|
14349
14363
|
/**
|
|
14350
14364
|
* Newest instant a sync clamped past instead of ingesting, or null when no
|
|
14351
14365
|
* skip is outstanding. Non-null means this source has a known gap in its
|
|
14352
|
-
* history that only a
|
|
14353
|
-
* clear when the watermark catches up, because catching up is exactly
|
|
14354
|
-
* the skipping sync did.
|
|
14366
|
+
* history that only a repair with proven source coverage can close — it does
|
|
14367
|
+
* not clear when the watermark catches up, because catching up is exactly
|
|
14368
|
+
* what the skipping sync did. WordPress generic replace-mode backfill is
|
|
14369
|
+
* deliberately unavailable because the retained feed cannot prove coverage.
|
|
14355
14370
|
*/
|
|
14356
14371
|
skippedThroughAt: z50.string().nullable(),
|
|
14357
14372
|
/** Residual Cloudflare Queue depth reported by the most recent bounded pull. */
|
|
@@ -14537,7 +14552,7 @@ var trafficSyncResponseSchema = z50.object({
|
|
|
14537
14552
|
windowEnd: z50.string()
|
|
14538
14553
|
});
|
|
14539
14554
|
var trafficBackfillRequestSchema = z50.object({
|
|
14540
|
-
/** Lookback window in days.
|
|
14555
|
+
/** Lookback window in days. Default: 30; capped server-side at the adapter ceiling. WordPress always requires a retention-aware repair, not this generic replace operation. */
|
|
14541
14556
|
days: z50.number().int().positive().optional()
|
|
14542
14557
|
});
|
|
14543
14558
|
var trafficResetRequestSchema = z50.object({
|
|
@@ -14567,7 +14582,31 @@ var trafficSourceTotalsSchema = z50.object({
|
|
|
14567
14582
|
/** Full per-class crawler-hit breakdown; the five buckets sum to `crawlerHits`. */
|
|
14568
14583
|
crawlerSegments: trafficCrawlerSegmentsSchema,
|
|
14569
14584
|
aiUserFetchHits: z50.number().int().nonnegative(),
|
|
14585
|
+
/**
|
|
14586
|
+
* Every request carrying AI-origin evidence. UNCHANGED contract — still the
|
|
14587
|
+
* full count across every status. Use `aiReferralLandedHits` for the
|
|
14588
|
+
* "someone actually arrived" signal.
|
|
14589
|
+
*/
|
|
14570
14590
|
aiReferralHits: z50.number().int().nonnegative(),
|
|
14591
|
+
/**
|
|
14592
|
+
* Countable referral SESSIONS: excludes requests answered with a proven
|
|
14593
|
+
* Location redirect (301/302/303/307/308) AND static subresource fetches,
|
|
14594
|
+
* matching the report's predicate exactly. This is the figure to present as
|
|
14595
|
+
* visits, visitors, sessions or arrivals. "Not proven" on the redirect half:
|
|
14596
|
+
* a source that never observed a status stores 0, and an unobserved status
|
|
14597
|
+
* is not a hop, so those rows count — the benefit-of-the-doubt default.
|
|
14598
|
+
* `landed + redirected <= total`; the gap is subresource noise, which is
|
|
14599
|
+
* neither a session nor a hop.
|
|
14600
|
+
*/
|
|
14601
|
+
aiReferralLandedHits: z50.number().int().nonnegative(),
|
|
14602
|
+
/**
|
|
14603
|
+
* Referral hits answered with a Location redirect. The visitor got no
|
|
14604
|
+
* content here; the destination raises its own row when it carries the same
|
|
14605
|
+
* evidence, so counting these as arrivals double-counts one person. A site
|
|
14606
|
+
* where this is most of the total is a finding in itself: its AI arrivals
|
|
14607
|
+
* all bounce off a redirect.
|
|
14608
|
+
*/
|
|
14609
|
+
aiReferralRedirectedHits: z50.number().int().nonnegative(),
|
|
14571
14610
|
sampleCount: z50.number().int().nonnegative()
|
|
14572
14611
|
});
|
|
14573
14612
|
var trafficSourceListResponseSchema = z50.object({
|
|
@@ -14598,7 +14637,12 @@ var trafficSeriesPointSchema = z50.object({
|
|
|
14598
14637
|
bucket: z50.string(),
|
|
14599
14638
|
crawlerHits: z50.number().int().nonnegative(),
|
|
14600
14639
|
aiUserFetchHits: z50.number().int().nonnegative(),
|
|
14601
|
-
aiReferralHits: z50.number().int().nonnegative()
|
|
14640
|
+
aiReferralHits: z50.number().int().nonnegative(),
|
|
14641
|
+
/**
|
|
14642
|
+
* The part of `aiReferralHits` not answered with a Location redirect — the
|
|
14643
|
+
* series to chart under any label that says sessions or visits.
|
|
14644
|
+
*/
|
|
14645
|
+
aiReferralLandedHits: z50.number().int().nonnegative()
|
|
14602
14646
|
});
|
|
14603
14647
|
var trafficCrawlerEventEntrySchema = z50.object({
|
|
14604
14648
|
kind: z50.literal(TrafficEventKinds.crawler),
|
|
@@ -14677,13 +14721,26 @@ var trafficEventsResponseSchema = z50.object({
|
|
|
14677
14721
|
/** Full per-class crawler-hit breakdown; the five buckets sum to `crawlerHits`. */
|
|
14678
14722
|
crawlerSegments: trafficCrawlerSegmentsSchema,
|
|
14679
14723
|
aiUserFetchHits: z50.number().int().nonnegative(),
|
|
14680
|
-
/**
|
|
14724
|
+
/**
|
|
14725
|
+
* Every AI-referral request in the window, whatever the server answered.
|
|
14726
|
+
* NOT a session count: use `aiReferralLandedHits` for anything presented
|
|
14727
|
+
* as sessions or visits. The three class buckets sum to the LANDED figure,
|
|
14728
|
+
* because a redirect hop's paid tags are not a paid session.
|
|
14729
|
+
*/
|
|
14681
14730
|
aiReferralHits: z50.number().int().nonnegative(),
|
|
14682
|
-
/**
|
|
14731
|
+
/**
|
|
14732
|
+
* Countable referral SESSIONS: no redirect hops, no static subresource
|
|
14733
|
+
* fetches — the same predicate the report uses, so windowed totals here
|
|
14734
|
+
* and report arrivals cannot disagree.
|
|
14735
|
+
*/
|
|
14736
|
+
aiReferralLandedHits: z50.number().int().nonnegative(),
|
|
14737
|
+
/** Referral hits answered with a Location redirect — hops, not arrivals. */
|
|
14738
|
+
aiReferralRedirectedHits: z50.number().int().nonnegative(),
|
|
14739
|
+
/** LANDED sessions carrying paid-attribution UTM evidence. */
|
|
14683
14740
|
aiReferralPaidHits: z50.number().int().nonnegative(),
|
|
14684
|
-
/**
|
|
14741
|
+
/** LANDED sessions with no paid-attribution evidence. */
|
|
14685
14742
|
aiReferralOrganicHits: z50.number().int().nonnegative(),
|
|
14686
|
-
/**
|
|
14743
|
+
/** LANDED sessions ingested before the classifier shipped; unresolvable, never organic. */
|
|
14687
14744
|
aiReferralUnknownHits: z50.number().int().nonnegative()
|
|
14688
14745
|
}),
|
|
14689
14746
|
eventRows: z50.object({
|
|
@@ -15822,6 +15879,12 @@ function formatMicros(micros, currencyCode = "USD") {
|
|
|
15822
15879
|
}).format(micros / MICROS_PER_UNIT);
|
|
15823
15880
|
}
|
|
15824
15881
|
|
|
15882
|
+
// ../contracts/src/http-status.ts
|
|
15883
|
+
var LOCATION_REDIRECT_STATUSES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
|
|
15884
|
+
function isLocationRedirectStatus(status) {
|
|
15885
|
+
return LOCATION_REDIRECT_STATUSES.has(status);
|
|
15886
|
+
}
|
|
15887
|
+
|
|
15825
15888
|
// ../contracts/src/sql-like.ts
|
|
15826
15889
|
function escapeLikePattern(value) {
|
|
15827
15890
|
return value.replace(/[\\%_]/g, (match) => `\\${match}`);
|
|
@@ -16759,6 +16822,8 @@ export {
|
|
|
16759
16822
|
adsCpcMicros,
|
|
16760
16823
|
dollarsToMicros,
|
|
16761
16824
|
formatMicros,
|
|
16825
|
+
LOCATION_REDIRECT_STATUSES,
|
|
16826
|
+
isLocationRedirectStatus,
|
|
16762
16827
|
escapeLikePattern,
|
|
16763
16828
|
READ_ONLY_SCOPE,
|
|
16764
16829
|
WILDCARD_SCOPE,
|
|
@@ -5,11 +5,11 @@ import {
|
|
|
5
5
|
installSkills,
|
|
6
6
|
loadConfigRaw,
|
|
7
7
|
saveConfigPatch
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-6XUWDSLN.js";
|
|
9
9
|
import {
|
|
10
10
|
SKILL_MANIFEST_FILENAME,
|
|
11
11
|
SkillsClients
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-PQT3ECM3.js";
|
|
13
13
|
|
|
14
14
|
// src/skills-autosync.ts
|
|
15
15
|
import fs from "fs";
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
loadConfig,
|
|
10
10
|
loadConfigRaw,
|
|
11
11
|
saveConfigPatch
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-6XUWDSLN.js";
|
|
13
13
|
import {
|
|
14
14
|
CC_CACHE_DIR,
|
|
15
15
|
DUCKDB_SPEC,
|
|
@@ -145,7 +145,7 @@ import {
|
|
|
145
145
|
siteCrawlSnapshots,
|
|
146
146
|
toAlertView,
|
|
147
147
|
usageCounters
|
|
148
|
-
} from "./chunk-
|
|
148
|
+
} from "./chunk-GJE334DA.js";
|
|
149
149
|
import {
|
|
150
150
|
AGENT_MEMORY_VALUE_MAX_BYTES,
|
|
151
151
|
AGENT_PROVIDER_IDS,
|
|
@@ -282,7 +282,7 @@ import {
|
|
|
282
282
|
validationError,
|
|
283
283
|
winnabilityClassLabel,
|
|
284
284
|
withRetry
|
|
285
|
-
} from "./chunk-
|
|
285
|
+
} from "./chunk-PQT3ECM3.js";
|
|
286
286
|
|
|
287
287
|
// src/telemetry.ts
|
|
288
288
|
import crypto from "crypto";
|
|
@@ -11839,7 +11839,7 @@ function readStoredGroundingSources(rawResponse) {
|
|
|
11839
11839
|
return result;
|
|
11840
11840
|
}
|
|
11841
11841
|
async function backfillInsightsCommand(project, opts) {
|
|
11842
|
-
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-
|
|
11842
|
+
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-C57RIB37.js");
|
|
11843
11843
|
const config = loadConfig();
|
|
11844
11844
|
const db = createClient(config.database);
|
|
11845
11845
|
migrate(db);
|
package/dist/cli.js
CHANGED
|
@@ -26,11 +26,11 @@ import {
|
|
|
26
26
|
showFirstRunNotice,
|
|
27
27
|
trackCliCommandFinished,
|
|
28
28
|
trackEvent
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-XFAPF2YX.js";
|
|
30
30
|
import {
|
|
31
31
|
autoSyncSkills,
|
|
32
32
|
formatAutoSyncNotice
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-QRE3DAAU.js";
|
|
34
34
|
import {
|
|
35
35
|
CliError,
|
|
36
36
|
EXIT_SYSTEM_ERROR,
|
|
@@ -55,7 +55,7 @@ import {
|
|
|
55
55
|
saveConfigPatch,
|
|
56
56
|
systemError,
|
|
57
57
|
usageError
|
|
58
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-6XUWDSLN.js";
|
|
59
59
|
import {
|
|
60
60
|
CLOUDFLARE_WORKER_BINDINGS,
|
|
61
61
|
CLOUDFLARE_WORKER_GENERATED_MARKER,
|
|
@@ -69,7 +69,7 @@ import {
|
|
|
69
69
|
projects,
|
|
70
70
|
queries,
|
|
71
71
|
renderReportHtml
|
|
72
|
-
} from "./chunk-
|
|
72
|
+
} from "./chunk-GJE334DA.js";
|
|
73
73
|
import {
|
|
74
74
|
AdsDeliverySnapshotStatuses,
|
|
75
75
|
AdsHistoricalCampaignRollupStatuses,
|
|
@@ -137,7 +137,7 @@ import {
|
|
|
137
137
|
providerQuotaPolicySchema,
|
|
138
138
|
resolveProviderInput,
|
|
139
139
|
winnabilityClassSchema
|
|
140
|
-
} from "./chunk-
|
|
140
|
+
} from "./chunk-PQT3ECM3.js";
|
|
141
141
|
|
|
142
142
|
// src/cli.ts
|
|
143
143
|
import { pathToFileURL } from "url";
|
|
@@ -6884,7 +6884,7 @@ async function trafficReset(project, opts) {
|
|
|
6884
6884
|
throw new CliError({
|
|
6885
6885
|
code: "TRAFFIC_RESET_REQUIRES_FLAG",
|
|
6886
6886
|
message: "--advance-to-now is required",
|
|
6887
|
-
displayMessage: "Error: --advance-to-now is required. This skips
|
|
6887
|
+
displayMessage: "Error: --advance-to-now is required. This skips history between the source's current lastSyncedAt and now. For WordPress, generic replace-mode backfill is unavailable; use a retention-aware repair that declares any unrecoverable span.",
|
|
6888
6888
|
details: { project, source: opts.source }
|
|
6889
6889
|
});
|
|
6890
6890
|
}
|
|
@@ -6898,6 +6898,9 @@ async function trafficReset(project, opts) {
|
|
|
6898
6898
|
console.log(` Status: ${updated.status}`);
|
|
6899
6899
|
console.log(` Last synced: ${updated.lastSyncedAt ?? "never"} (advanced to NOW)`);
|
|
6900
6900
|
console.log(` Last error: ${updated.lastError ?? "none"}`);
|
|
6901
|
+
if (updated.skippedThroughAt) {
|
|
6902
|
+
console.log(" Historical repair: generic WordPress replace-mode backfill is unavailable until a retention-aware repair proves coverage.");
|
|
6903
|
+
}
|
|
6901
6904
|
console.log("");
|
|
6902
6905
|
console.log("Next scheduled sync will resume from this timestamp.");
|
|
6903
6906
|
}
|
|
@@ -6958,7 +6961,7 @@ async function trafficStatus(project, opts) {
|
|
|
6958
6961
|
console.log(` 24h infra: ${d.totals24h.crawlerInfraHits} sitemap/robots/asset fetches`);
|
|
6959
6962
|
console.log(` 24h other: ${d.totals24h.crawlerSegments.other} fetches`);
|
|
6960
6963
|
console.log(` 24h crawler: ${d.totals24h.crawlerHits} hits total`);
|
|
6961
|
-
console.log(` 24h AI referral: ${d.totals24h.
|
|
6964
|
+
console.log(` 24h AI referral: ${d.totals24h.aiReferralLandedHits} sessions (+${d.totals24h.aiReferralRedirectedHits} redirect hops excluded)`);
|
|
6962
6965
|
console.log(` 24h samples: ${d.totals24h.sampleCount}`);
|
|
6963
6966
|
if (d.latestRun) {
|
|
6964
6967
|
console.log(` Latest run: ${d.latestRun.runId} (${d.latestRun.status})`);
|
|
@@ -7067,7 +7070,7 @@ async function trafficEvents(project, opts) {
|
|
|
7067
7070
|
console.log(` Other fetches (window): ${result.totals.crawlerSegments.other}`);
|
|
7068
7071
|
console.log(` Crawler hits total (window): ${result.totals.crawlerHits}`);
|
|
7069
7072
|
console.log(` AI user-fetch hits (window): ${result.totals.aiUserFetchHits}`);
|
|
7070
|
-
console.log(` AI referral sessions (window): ${result.totals.
|
|
7073
|
+
console.log(` AI referral sessions (window): ${result.totals.aiReferralLandedHits} (+${result.totals.aiReferralRedirectedHits} redirect hops excluded)`);
|
|
7071
7074
|
console.log(` paid: ${result.totals.aiReferralPaidHits}`);
|
|
7072
7075
|
console.log(` organic: ${result.totals.aiReferralOrganicHits}`);
|
|
7073
7076
|
console.log(` unclassified: ${result.totals.aiReferralUnknownHits} (ingested before paid/organic classification)`);
|
package/dist/index.js
CHANGED
|
@@ -3,12 +3,12 @@ import {
|
|
|
3
3
|
createGoogleMarketingCredentialStore,
|
|
4
4
|
createGoogleMarketingRuntime,
|
|
5
5
|
createServer
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-XFAPF2YX.js";
|
|
7
7
|
import {
|
|
8
8
|
loadConfig
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-6XUWDSLN.js";
|
|
10
|
+
import "./chunk-GJE334DA.js";
|
|
11
|
+
import "./chunk-PQT3ECM3.js";
|
|
12
12
|
export {
|
|
13
13
|
GoogleMarketingRuntimeError,
|
|
14
14
|
createGoogleMarketingCredentialStore,
|
package/dist/mcp.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
autoSyncSkills
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-QRE3DAAU.js";
|
|
4
4
|
import {
|
|
5
5
|
CliError,
|
|
6
6
|
PACKAGE_VERSION,
|
|
7
7
|
canonryMcpTools,
|
|
8
8
|
createApiClient
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-6XUWDSLN.js";
|
|
10
10
|
import {
|
|
11
11
|
isReadOnlyKey
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-PQT3ECM3.js";
|
|
13
13
|
|
|
14
14
|
// src/mcp/cli.ts
|
|
15
15
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canonry/canonry",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.177.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Self-hosted AI visibility (AEO) platform: track how ChatGPT, Claude, Gemini, and Perplexity cite your domain, join it with Search Console, GA4, server-side traffic, and paid media, and fix what you find through agent tools (CLI, REST, MCP). Local SQLite.",
|
|
6
6
|
"license": "FSL-1.1-ALv2",
|
|
@@ -70,30 +70,30 @@
|
|
|
70
70
|
"@types/node-cron": "^3.0.11",
|
|
71
71
|
"tsup": "^8.5.1",
|
|
72
72
|
"tsx": "^4.19.0",
|
|
73
|
-
"@ainyc/canonry-api-client": "0.0.0",
|
|
74
73
|
"@ainyc/canonry-api-routes": "0.0.0",
|
|
75
|
-
"@ainyc/canonry-config": "0.0.0",
|
|
76
74
|
"@ainyc/canonry-contracts": "0.0.0",
|
|
75
|
+
"@ainyc/canonry-config": "0.0.0",
|
|
76
|
+
"@ainyc/canonry-api-client": "0.0.0",
|
|
77
77
|
"@ainyc/canonry-db": "0.0.0",
|
|
78
78
|
"@ainyc/canonry-integration-bing": "0.0.0",
|
|
79
79
|
"@ainyc/canonry-integration-cloud-run": "0.0.0",
|
|
80
80
|
"@ainyc/canonry-integration-cloudflare-queue": "0.0.0",
|
|
81
81
|
"@ainyc/canonry-integration-cloudflare-worker": "0.0.0",
|
|
82
|
-
"@ainyc/canonry-integration-google-ads": "0.0.0",
|
|
83
|
-
"@ainyc/canonry-integration-google": "0.0.0",
|
|
84
82
|
"@ainyc/canonry-integration-commoncrawl": "0.0.0",
|
|
85
|
-
"@ainyc/canonry-integration-google
|
|
83
|
+
"@ainyc/canonry-integration-google": "0.0.0",
|
|
84
|
+
"@ainyc/canonry-integration-google-ads": "0.0.0",
|
|
86
85
|
"@ainyc/canonry-integration-google-places": "0.0.0",
|
|
86
|
+
"@ainyc/canonry-integration-google-business-profile": "0.0.0",
|
|
87
87
|
"@ainyc/canonry-integration-google-tag-manager": "0.0.0",
|
|
88
|
-
"@ainyc/canonry-integration-traffic": "0.0.0",
|
|
89
88
|
"@ainyc/canonry-integration-wordpress": "0.0.0",
|
|
90
89
|
"@ainyc/canonry-integration-openai-ads": "0.0.0",
|
|
90
|
+
"@ainyc/canonry-integration-traffic": "0.0.0",
|
|
91
91
|
"@ainyc/canonry-intelligence": "0.0.0",
|
|
92
92
|
"@ainyc/canonry-provider-cdp": "0.0.0",
|
|
93
93
|
"@ainyc/canonry-provider-gemini": "0.0.0",
|
|
94
|
-
"@ainyc/canonry-provider-claude": "0.0.0",
|
|
95
94
|
"@ainyc/canonry-provider-local": "0.0.0",
|
|
96
95
|
"@ainyc/canonry-provider-openai": "0.0.0",
|
|
96
|
+
"@ainyc/canonry-provider-claude": "0.0.0",
|
|
97
97
|
"@ainyc/canonry-provider-perplexity": "0.0.0"
|
|
98
98
|
},
|
|
99
99
|
"scripts": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as c,j as e,h as V,u as U,f as E,L}from"./vendor-tanstack-Dock0eH1.js";import{cT as O,cU as z,cV as I,cW as F,cX as A,B as N,f as B,cY as W,bU as $,k as D,i as w,d as S,cZ as H,T as G}from"./index-CiQNKNMG.js";import{b as J,c as M,d as Q,a as T,f as _,t as K}from"./extract-error-message-DlPqK0mV.js";import{G as Y,w as X,x as Z,y as ee,p as q,A as te}from"./vendor-lucide-nYKv-BB7.js";import"./vendor-radix-4UOaVWza.js";import"./vendor-recharts-D8rt5lKn.js";import"./vendor-markdown-Bn7fRwrx.js";import"./vendor-yaml-GWJz5H2G.js";function re({open:t,onOpenChange:a,projectName:n}){const[r,s]=c.useState("pick");c.useEffect(()=>{t&&s("pick")},[t]);const o=()=>{a(!1),s("pick")};return e.jsx(O,{open:t,onOpenChange:i=>{i?a(!0):o()},children:e.jsx(z,{children:r==="pick"?e.jsx(ne,{onPick:s}):r==="wordpress"?e.jsx(ie,{projectName:n,onBack:()=>s("pick"),onClose:o}):r==="vercel"?e.jsx(ce,{projectName:n,onBack:()=>s("pick"),onClose:o}):e.jsx(le,{projectName:n,onBack:()=>s("pick"),onClose:o})})})}const se=[{type:"wordpress",name:"WordPress",action:"Install the traffic plugin",icon:Y},{type:"cloud-run",name:"Google Cloud Run",action:"Read request logs",icon:X},{type:"vercel",name:"Vercel",action:"Read request logs",icon:Z}];function ne({onPick:t}){return e.jsxs(e.Fragment,{children:[e.jsxs(I,{children:[e.jsx(F,{children:"Connect a traffic source"}),e.jsx(A,{children:"Choose where Canonry should read traffic logs."})]}),e.jsx("div",{className:"mt-6 flex flex-col gap-3",children:se.map(({type:a,name:n,action:r,icon:s})=>e.jsxs("button",{type:"button",onClick:()=>t(a),className:"group flex items-center gap-3 rounded-md border border-base bg-bg-elevated/30 px-3 py-3 text-left transition-colors hover:border-mono-600 hover:bg-bg-elevated/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-mono-400",children:[e.jsx("span",{className:"mt-0.5 inline-flex size-9 shrink-0 items-center justify-center rounded-md border border-base bg-bg text-neutral group-hover:text-heading",children:e.jsx(s,{className:"size-4"})}),e.jsxs("span",{className:"flex min-w-0 flex-1 items-baseline justify-between gap-3",children:[e.jsx("span",{className:"text-sm font-medium text-heading",children:n}),e.jsx("span",{className:"text-sm text-secondary",children:r})]})]},a))})]})}function oe({title:t,description:a,onBack:n}){return e.jsxs(I,{children:[e.jsxs("button",{type:"button",onClick:n,className:"mb-1 inline-flex w-fit items-center gap-1 rounded text-sm text-secondary transition-colors hover:text-strong focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-mono-400",children:[e.jsx(ee,{className:"size-3"}),"Choose a different source"]}),e.jsx(F,{children:t}),e.jsx(A,{children:a})]})}function ae(t,a){const n=V();return async(r,s)=>{await W(t,r),s?.(),a(),n({to:"/traffic/$projectName/$sourceId",params:{projectName:t,sourceId:r}})}}function k(t,a){const[n,r]=c.useState(null),s=ae(t,a);return{error:n,runConnect:async i=>{r(null);const d=i.validate();if(d){r(d);return}let u;try{u=await i.mutate()}catch(l){r(T(l));return}try{await s(u.id,i.onConnected)}catch(l){r(`Source connected, but starting the initial backfill failed: ${T(l)}`)}}}}function P({title:t,description:a,projectName:n,onBack:r,onClose:s,onSubmit:o,isPending:i,error:d,children:u}){return e.jsxs(e.Fragment,{children:[e.jsx(oe,{title:t,description:a,onBack:r}),e.jsxs("form",{onSubmit:B(async l=>{l.preventDefault(),await o()}),className:"mt-6 flex flex-col gap-5 overflow-y-auto pr-1",children:[e.jsx(p,{label:"Project",description:"Canonry project this source attaches to.",children:e.jsx("input",{type:"text",value:n,disabled:!0,className:"w-full rounded border border-strong bg-bg-elevated/50 px-2 py-1.5 text-sm text-neutral"})}),u,d?e.jsx("p",{className:"rounded-md border border-negative-800/50 bg-negative-950/30 px-3 py-2 text-xs text-negative-200",children:d}):null,e.jsxs("div",{className:"mt-2 flex items-center justify-end gap-2 border-t border-default pt-4",children:[e.jsx(N,{type:"button",variant:"ghost",size:"sm",onClick:s,children:"Close"}),e.jsx(N,{type:"submit",disabled:i,size:"sm",children:i?"Connecting…":"Connect"})]})]})]})}function ie({projectName:t,onBack:a,onClose:n}){const[r,s]=c.useState(""),[o,i]=c.useState(""),[d,u]=c.useState(""),[l,j]=c.useState(""),f=J(t||null),{error:g,runConnect:b}=k(t,n),y=()=>b({validate:()=>r.trim()?o.trim()?d.trim()?null:"Application Password is required.":"Username is required.":"WordPress site URL is required.",mutate:()=>f.mutateAsync({baseUrl:r.trim(),username:o.trim(),applicationPassword:d.trim(),displayName:l.trim()||void 0}),onConnected:()=>u("")});return e.jsxs(P,{title:"Connect a WordPress site",description:e.jsxs(e.Fragment,{children:["Pulls request events from the Canonry Traffic Logger plugin. The Application Password is stored in ",e.jsx("code",{children:"~/.canonry/config.yaml"})," on the server and never echoed back to the dashboard."]}),projectName:t,onBack:a,onClose:n,onSubmit:y,isPending:f.isPending,error:g,children:[e.jsx(p,{label:"WordPress site URL",description:"Base URL of the site running the Canonry Traffic Logger plugin.",required:!0,children:e.jsx("input",{type:"url",value:r,onChange:x=>s(x.target.value),required:!0,autoComplete:"url",placeholder:"https://example.com",className:"w-full rounded border border-strong bg-transparent px-2 py-1.5 text-sm text-strong placeholder-mono-600 focus:border-mono-500 focus:outline-none"})}),e.jsx(p,{label:"Username",description:"WordPress user that owns the Application Password.",required:!0,children:e.jsx("input",{type:"text",value:o,onChange:x=>i(x.target.value),required:!0,autoComplete:"username",className:"w-full rounded border border-strong bg-transparent px-2 py-1.5 text-sm text-strong placeholder-mono-600 focus:border-mono-500 focus:outline-none"})}),e.jsx(p,{label:"Application Password",description:"Create one in wp-admin under Users -> Profile -> Application Passwords.",required:!0,children:e.jsx("input",{type:"password",value:d,onChange:x=>u(x.target.value),required:!0,autoComplete:"new-password",className:"w-full rounded border border-strong bg-transparent px-2 py-1.5 text-sm text-strong placeholder-mono-600 focus:border-mono-500 focus:outline-none"})}),e.jsx(p,{label:"Display name (optional)",description:"Friendly label shown in the dashboard. Defaults to the WordPress host.",children:e.jsx("input",{type:"text",value:l,onChange:x=>j(x.target.value),autoComplete:"off",className:"w-full rounded border border-strong bg-transparent px-2 py-1.5 text-sm text-strong placeholder-mono-600 focus:border-mono-500 focus:outline-none"})})]})}function le({projectName:t,onBack:a,onClose:n}){const[r,s]=c.useState(""),[o,i]=c.useState(""),[d,u]=c.useState(""),[l,j]=c.useState(""),[f,g]=c.useState(""),b=Q(t||null),{error:y,runConnect:x}=k(t,n),C=()=>x({validate:()=>r.trim()?f.trim()?null:"Service-account JSON content is required.":"GCP project ID is required.",mutate:()=>b.mutateAsync({gcpProjectId:r.trim(),serviceName:o.trim()||void 0,location:d.trim()||void 0,displayName:l.trim()||void 0,keyJson:f.trim()}),onConnected:()=>g("")}),h=async m=>{if(!m)return;const R=await m.text();g(R)};return e.jsxs(P,{title:"Connect a Cloud Run service",description:e.jsxs(e.Fragment,{children:["v1 supports service-account JSON only. The private key is stored in"," ",e.jsx("code",{children:"~/.canonry/config.yaml"})," on the server and never echoed back to the dashboard."]}),projectName:t,onBack:a,onClose:n,onSubmit:C,isPending:b.isPending,error:y,children:[e.jsx(p,{label:"GCP project ID",description:"The Google Cloud project hosting the Cloud Run service (e.g. my-prod-foo).",required:!0,children:e.jsx("input",{type:"text",value:r,onChange:m=>s(m.target.value),required:!0,autoComplete:"off",className:"w-full rounded border border-strong bg-transparent px-2 py-1.5 text-sm text-strong placeholder-mono-600 focus:border-mono-500 focus:outline-none"})}),e.jsx(p,{label:"Service name (optional)",description:"Restrict log pulls to a specific Cloud Run service. Omit to pull all services in the project.",children:e.jsx("input",{type:"text",value:o,onChange:m=>i(m.target.value),autoComplete:"off",className:"w-full rounded border border-strong bg-transparent px-2 py-1.5 text-sm text-strong placeholder-mono-600 focus:border-mono-500 focus:outline-none"})}),e.jsx(p,{label:"Location (optional)",description:"Region of the Cloud Run service (e.g. us-central1). Helpful when multiple regions emit logs.",children:e.jsx("input",{type:"text",value:d,onChange:m=>u(m.target.value),autoComplete:"off",className:"w-full rounded border border-strong bg-transparent px-2 py-1.5 text-sm text-strong placeholder-mono-600 focus:border-mono-500 focus:outline-none"})}),e.jsx(p,{label:"Display name (optional)",description:"Friendly label shown in the dashboard. Defaults to the project + service combo.",children:e.jsx("input",{type:"text",value:l,onChange:m=>j(m.target.value),autoComplete:"off",className:"w-full rounded border border-strong bg-transparent px-2 py-1.5 text-sm text-strong placeholder-mono-600 focus:border-mono-500 focus:outline-none"})}),e.jsxs(p,{label:"Service-account JSON",description:"Paste the contents of the SA key (JSON). The SA needs roles/logging.viewer (or any role granting logging.logEntries.list).",required:!0,children:[e.jsx("textarea",{value:f,onChange:m=>g(m.target.value),rows:6,spellCheck:!1,autoComplete:"off",className:"w-full rounded border border-strong bg-transparent px-2 py-1.5 font-mono text-sm text-strong placeholder-mono-600 focus:border-mono-500 focus:outline-none",placeholder:'{"type":"service_account","project_id":"…","private_key":"…"}',required:!0}),e.jsxs("label",{className:"mt-2 inline-flex cursor-pointer items-center gap-2 text-sm text-secondary hover:text-strong",children:[e.jsx("input",{type:"file",accept:"application/json,.json",className:"hidden",onChange:m=>{h(m.target.files?.[0]??null)}}),e.jsx("span",{className:"rounded-md border border-base px-2 py-1",children:"Or upload a key file"})]})]})]})}function ce({projectName:t,onBack:a,onClose:n}){const[r,s]=c.useState(""),[o,i]=c.useState(""),[d,u]=c.useState(""),[l,j]=c.useState("production"),[f,g]=c.useState(""),b=M(t||null),{error:y,runConnect:x}=k(t,n),C=()=>x({validate:()=>r.trim()?o.trim()?d.trim()?null:"Vercel personal access token is required.":"Vercel team / account ID is required.":"Vercel project ID is required.",mutate:()=>b.mutateAsync({projectId:r.trim(),teamId:o.trim(),token:d.trim(),environment:l,displayName:f.trim()||void 0}),onConnected:()=>u("")});return e.jsxs(P,{title:"Connect a Vercel project",description:e.jsxs(e.Fragment,{children:["Pulls request logs straight from Vercel, no in-app instrumentation needed. The personal access token is stored in ",e.jsx("code",{children:"~/.canonry/config.yaml"})," on the server and never echoed back to the dashboard."]}),projectName:t,onBack:a,onClose:n,onSubmit:C,isPending:b.isPending,error:y,children:[e.jsx(p,{label:"Vercel project ID",description:"The prj_… id from the Vercel dashboard or .vercel/project.json.",required:!0,children:e.jsx("input",{type:"text",value:r,onChange:h=>s(h.target.value),required:!0,autoComplete:"off",placeholder:"prj_…",className:"w-full rounded border border-strong bg-transparent px-2 py-1.5 text-sm text-strong placeholder-mono-600 focus:border-mono-500 focus:outline-none"})}),e.jsx(p,{label:"Vercel team / account ID",description:"The Vercel team or personal account that owns the project. Find it as orgId in your .vercel/project.json.",required:!0,children:e.jsx("input",{type:"text",value:o,onChange:h=>i(h.target.value),required:!0,autoComplete:"off",className:"w-full rounded border border-strong bg-transparent px-2 py-1.5 text-sm text-strong placeholder-mono-600 focus:border-mono-500 focus:outline-none"})}),e.jsx(p,{label:"Personal access token",description:"Create a Vercel personal access token under Account Settings → Tokens. Tokens can expire, so use a long-lived one.",required:!0,children:e.jsx("input",{type:"password",value:d,onChange:h=>u(h.target.value),required:!0,autoComplete:"new-password",className:"w-full rounded border border-strong bg-transparent px-2 py-1.5 text-sm text-strong placeholder-mono-600 focus:border-mono-500 focus:outline-none"})}),e.jsx(p,{label:"Environment",description:"Which deployment environment's request logs to pull.",children:e.jsxs("select",{value:l,onChange:h=>j(h.target.value),className:"w-full rounded border border-strong bg-transparent px-2 py-1.5 text-sm text-strong focus:border-mono-500 focus:outline-none",children:[e.jsx("option",{value:"production",children:"production"}),e.jsx("option",{value:"preview",children:"preview"})]})}),e.jsx(p,{label:"Display name (optional)",description:"Friendly label shown in the dashboard. Defaults to the Vercel project ID.",children:e.jsx("input",{type:"text",value:f,onChange:h=>g(h.target.value),autoComplete:"off",className:"w-full rounded border border-strong bg-transparent px-2 py-1.5 text-sm text-strong placeholder-mono-600 focus:border-mono-500 focus:outline-none"})})]})}function p({label:t,description:a,required:n,children:r}){return e.jsxs("label",{className:"flex flex-col gap-1",children:[e.jsxs("span",{className:"text-sm font-medium text-strong",children:[t,n?e.jsx("span",{className:"ml-1 text-negative-400",children:"*"}):null]}),r,e.jsx("span",{className:"text-[13px] leading-5 text-secondary",children:a})]})}function de(t){if(!t)return"never";const a=Date.now()-new Date(t).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 v(t){return t>=1e6?`${(t/1e6).toFixed(1)}M`:t>=1e3?`${(t/1e3).toFixed(1)}K`:t.toLocaleString()}function ye(){const[t,a]=c.useState(""),[n,r]=c.useState(!1),o=U($({client:D})).data??[],i=c.useMemo(()=>t||(o[0]?.name??""),[t,o]),d=_(i||null),u=d.data?.sources??[];return e.jsxs("div",{className:"page-container",children:[e.jsxs("div",{className:"page-header",children:[e.jsxs("div",{className:"page-header-left",children:[e.jsx("h1",{className:"page-title",children:"Traffic sources"}),e.jsx("p",{className:"page-subtitle",children:"AI crawler hits and referral sessions from your server logs."})]}),!w()&&e.jsx("div",{className:"flex flex-wrap items-center justify-end gap-2",children:e.jsxs(N,{type:"button",variant:"outline",size:"sm",onClick:()=>r(!0),disabled:!i,children:[e.jsx(q,{className:"size-3.5"}),"Connect a source"]})})]}),e.jsxs("section",{children:[o.length>1&&e.jsxs("label",{className:"mb-4 flex w-fit items-center gap-2 text-sm font-medium text-secondary",htmlFor:"traffic-project",children:["Project",e.jsx("select",{id:"traffic-project",className:"h-8 min-w-44 rounded-md border border-base bg-bg px-2 text-sm text-heading outline-none transition focus:border-mono-500 focus:ring-1 focus:ring-mono-500",value:i,onChange:l=>a(l.target.value),children:o.map(l=>e.jsx("option",{value:l.name,children:l.displayName??l.name},l.id))})]}),i?d.isLoading?e.jsx(S,{className:"p-6 text-center text-sm text-muted",children:"Loading sources…"}):u.length===0?e.jsxs(S,{className:"p-8 text-center",children:[e.jsxs("p",{className:"text-sm text-neutral",children:["No traffic sources connected for ",i,"."]}),!w()&&e.jsxs(e.Fragment,{children:[e.jsx("p",{className:"mt-1 text-sm text-secondary",children:"Connect a source to start collecting traffic."}),e.jsx("div",{className:"mt-4 flex flex-wrap items-center justify-center gap-2",children:e.jsxs(N,{type:"button",variant:"outline",size:"sm",onClick:()=>r(!0),children:[e.jsx(q,{className:"size-3.5"}),"Connect a source"]})})]})]}):e.jsx(ue,{projectName:i,sources:u}):e.jsx(S,{className:"p-6 text-center text-sm text-muted",children:"No projects yet."})]}),!w()&&e.jsx(re,{open:n,onOpenChange:r,projectName:i})]})}function ue({projectName:t,sources:a}){const n=E({queries:a.map(s=>({...H({client:D,path:{name:t,id:s.id}}),staleTime:3e4}))}),r=a.map((s,o)=>({source:s,detail:n[o]?.data,isLoading:n[o]?.isLoading??!1}));return e.jsx("div",{className:"rounded-xl border border-default bg-surface overflow-hidden",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"bg-bg-elevated/50 text-[10px] font-semibold uppercase tracking-wider text-muted",children:e.jsxs("tr",{children:[e.jsx("th",{className:"px-4 py-2 text-left",children:"Source"}),e.jsx("th",{className:"px-4 py-2 text-left",children:"Status"}),e.jsx("th",{className:"px-4 py-2 text-left",children:"Last sync"}),e.jsx("th",{className:"px-4 py-2 text-right",children:"Content crawls"}),e.jsx("th",{className:"px-4 py-2 text-right",children:"Infra crawls"}),e.jsx("th",{className:"px-4 py-2 text-right",children:"AI fetches"}),e.jsx("th",{className:"px-4 py-2 text-right",children:"AI referrals"}),e.jsx("th",{className:"px-4 py-2 text-right"})]})}),e.jsx("tbody",{className:"divide-y divide-mono-800/60",children:r.map(({source:s,detail:o,isLoading:i})=>e.jsxs("tr",{className:"hover:bg-bg-elevated/40 transition-colors",children:[e.jsx("td",{className:"px-4 py-3",children:e.jsx("div",{className:"font-medium text-heading",children:s.displayName})}),e.jsxs("td",{className:"px-4 py-3",children:[e.jsx(G,{tone:K(s.status),children:s.status}),s.lastError?e.jsx("p",{className:"mt-1 max-w-[18rem] truncate text-sm text-negative-400",title:s.lastError,children:s.lastError}):null]}),e.jsx("td",{className:"px-4 py-3 text-neutral",children:de(s.lastSyncedAt)}),e.jsx("td",{className:"px-4 py-3 text-right tabular-nums text-heading",title:o?`${o.totals24h.crawlerHits.toLocaleString("en-US")} total crawler hits`:void 0,children:i?"—":v(o?.totals24h.crawlerContentHits??0)}),e.jsx("td",{className:"px-4 py-3 text-right tabular-nums text-muted",children:i?"—":v(o?.totals24h.crawlerInfraHits??0)}),e.jsx("td",{className:"px-4 py-3 text-right tabular-nums text-heading",children:i?"—":v(o?.totals24h.aiUserFetchHits??0)}),e.jsx("td",{className:"px-4 py-3 text-right tabular-nums text-heading",children:i?"—":v(o?.totals24h.aiReferralHits??0)}),e.jsx("td",{className:"px-4 py-3 text-right",children:e.jsxs(L,{to:"/traffic/$projectName/$sourceId",params:{projectName:t,sourceId:s.id},className:"inline-flex items-center gap-1 text-sm text-secondary hover:text-heading",children:["View",e.jsx(te,{className:"size-3.5"})]})})]},s.id))})]})})}export{ye as TrafficPage};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{j as e,C as Ee,E as $e,r as i,L as Fe}from"./vendor-tanstack-Dock0eH1.js";import{c_ as W,c$ as o,d as H,I as P,T as He,i as ae,B as Pe,d0 as Ue}from"./index-CiQNKNMG.js";import{g as Oe,h as Me,i as _e,t as De,a as Be}from"./extract-error-message-DlPqK0mV.js";import{e as Y,h as Ke,C as re,a as ne,c as ze}from"./ChartPrimitives-BoYe2M-i.js";import{q as Ge,z as We,e as Ve,y as le,X as qe}from"./vendor-lucide-nYKv-BB7.js";import{R as Xe,B as Qe,a as Ye,X as Ze,Y as Je,T as et,f as V,g as q}from"./vendor-recharts-D8rt5lKn.js";import"./vendor-radix-4UOaVWza.js";import"./vendor-markdown-Bn7fRwrx.js";import"./vendor-yaml-GWJz5H2G.js";const tt=[{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"}],me=[{value:"all",label:"All claims"},{value:W.verified,label:"Verified"},{value:W.claimed_unverified,label:"Claimed unverified"},{value:W.unknown_ai_like,label:"Unknown AI-like"}];function st(s){return s==="all"?null:Number.parseInt(s[0],10)}function fe(s){switch(s.kind){case o.crawler:case o["ai-user-fetch"]:return s.botId;case o["ai-referral"]:return s.product}}function pe(s){switch(s.kind){case o.crawler:case o["ai-user-fetch"]:return s.pathNormalized;case o["ai-referral"]:return s.landingPathNormalized}}function at(s){switch(s.kind){case o.crawler:case o["ai-user-fetch"]:return s.verificationStatus;case o["ai-referral"]:return null}}function rt(s,a){if(a==="hour")return s;const r=new Date(s),n=r.getFullYear(),u=String(r.getMonth()+1).padStart(2,"0"),f=String(r.getDate()).padStart(2,"0");return`${n}-${u}-${f}`}function nt(s,a,r){const n=a.pathQuery.trim().toLowerCase(),u=st(a.statusClass);return s.filter(f=>!(a.selectedBucket&&rt(f.tsHour,r)!==a.selectedBucket||a.identity&&fe(f)!==a.identity||a.operator&&f.operator!==a.operator||n&&!pe(f).toLowerCase().includes(n)||u!==null&&Math.floor(f.status/100)!==u||a.verification!=="all"&&at(f)!==a.verification))}function lt(s,a){if(!s||typeof s!="object")return null;const r=s.activeTooltipIndex;let n;if(typeof r=="number")n=r;else if(typeof r=="string"&&r!=="")n=Number(r);else return null;return!Number.isInteger(n)||n<0||n>=a.length?null:a[n]?.bucket??null}const U=[{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}],ie=U.find(s=>s.label==="24h")??U[2],I=50,oe=Y[0],ce=Y[2],de=Y[1],ue=Ue();function be(s){const a=new Date(s);return`${a.getMonth()+1}/${a.getDate()} ${String(a.getHours()).padStart(2,"0")}:00`}function it(s){const a=new Date(`${s}T00:00:00`);return`${a.getMonth()+1}/${a.getDate()}`}function xe(s){if(!s)return"never";const a=Date.now()-new Date(s).getTime(),r=Math.floor(a/6e4);if(r<1)return"just now";if(r<60)return`${r}m ago`;const n=Math.floor(r/60);return n<24?`${n}h ago`:`${Math.floor(n/24)}d ago`}function ot(s){return s.size===1?[...s][0]:"all"}function he({canGoBack:s,className:a}){const r="inline-flex items-center gap-1";if(s){const n=()=>{window.history.back()};return e.jsxs("button",{type:"button",onClick:n,className:`${r} ${a??""}`,children:[e.jsx(le,{className:"size-3"})," Back"]})}return e.jsxs(Fe,{to:"/traffic",className:`${r} ${a??""}`,children:[e.jsx(le,{className:"size-3"})," All sources"]})}function wt(){const s=Ee({strict:!1}),a=s.projectName??"",r=$e(),n=s.sourceId??"",[u,f]=i.useState(ie.value),[x,ye]=i.useState(()=>new Set(["crawler","ai-user-fetch","ai-referral"])),[c,A]=i.useState(null),[p,O]=i.useState(""),[b,M]=i.useState(""),[v,_]=i.useState(""),[N,D]=i.useState("all"),[S,B]=i.useState("all"),[je,K]=i.useState(1),[Z,J]=i.useState(null),[ee,te]=i.useState(null),h=i.useMemo(()=>U.find(t=>t.value===u)??ie,[u]),ve=i.useMemo(()=>ot(x),[x]),z=Oe(a||null,n||null),g=Me(a||null,{kind:ve,sourceId:n||void 0,sinceMinutes:u,limit:h.fetchLimit,granularity:h.granularity}),R=_e(a||null,n||null),l=z.data,w=g.data?.events??[],y=g.data?.totals,T=g.data?.eventRows,E=i.useMemo(()=>w.filter(t=>{switch(t.kind){case o.crawler:return x.has("crawler");case o["ai-user-fetch"]:return x.has("ai-user-fetch");case o["ai-referral"]:return x.has("ai-referral")}}),[w,x]),Ne=i.useMemo(()=>{const t=new Set;for(const d of w)t.add(fe(d));return p&&t.add(p),[...t].sort((d,m)=>d.localeCompare(m))},[w,p]),Se=i.useMemo(()=>{const t=new Set;for(const d of w)t.add(d.operator);return b&&t.add(b),[...t].sort((d,m)=>d.localeCompare(m))},[w,b]),j=i.useMemo(()=>nt(E,{selectedBucket:c,identity:p,operator:b,pathQuery:v,statusClass:N,verification:S},h.granularity),[E,c,p,b,v,N,S,h.granularity]);i.useEffect(()=>{K(1)},[E,c,p,b,v,N,S]);const $=Math.max(1,Math.ceil(j.length/I)),F=Math.min(Math.max(1,je),$),L=(F-1)*I,we=i.useMemo(()=>j.slice(L,L+I),[j,L]),Ce=j.length>I,ke=j.length===0?0:L+1,Te=Math.min(L+I,j.length),se=i.useMemo(()=>c?ge(c,h.granularity):null,[c,h.granularity]),C=i.useMemo(()=>ct(g.data?.series.points??[],h.granularity),[g.data?.series.points,h.granularity]),G=t=>{ye(d=>{const m=new Set(d);return m.has(t)?m.size>1&&m.delete(t):m.add(t),m})},Le=t=>{const d=lt(t,C);d&&A(m=>m===d?null:d)},Ie=()=>{A(null),O(""),M(""),_(""),D("all"),B("all")},Ae=!!(c||p||b||v.trim()||N!=="all"||S!=="all"),Re=async()=>{J(null),te(null);try{const t=await R.mutateAsync({sinceMinutes:60});te(`Pulled ${t.pulledEvents} entries · ${t.crawlerHits} crawler · ${t.aiUserFetchHits} AI user fetch · ${t.aiReferralHits} AI referral · ${t.unknownHits} unknown`)}catch(t){J(Be(t))}};return!a||!n?e.jsx("div",{className:"page-container",children:e.jsx("p",{className:"text-sm text-muted",children:"Missing project name or source id in URL."})}):z.isLoading?e.jsx("div",{className:"page-container",children:e.jsx("p",{className:"text-sm text-muted",children:"Loading source…"})}):z.isError||!l?e.jsxs("div",{className:"page-container",children:[e.jsx("p",{className:"text-sm text-negative",children:"Could not load this source."}),e.jsx(he,{canGoBack:r,className:"mt-2 text-xs text-secondary hover:text-strong"})]}):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(he,{canGoBack:r,className:"text-xs text-muted hover:text-strong"}),e.jsx("h1",{className:"page-title mt-2",children:l.displayName}),e.jsxs("p",{className:"page-subtitle",children:[l.sourceType," source for ",a]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(He,{tone:De(l.status),children:l.status}),!ae()&&e.jsxs(Pe,{type:"button",variant:"outline",size:"sm",disabled:R.isPending,onClick:()=>{Re()},children:[e.jsx(Ge,{className:`size-3.5 ${R.isPending?"animate-spin":""}`}),R.isPending?"Syncing…":"Sync now"]})]})]}),Z?e.jsx("div",{className:"rounded-md border border-negative-800/50 bg-negative-950/30 px-3 py-2 text-sm text-negative-200",children:Z}):null,ee?e.jsx("div",{className:"rounded-md border border-positive-800/50 bg-positive-950/30 px-3 py-2 text-sm text-positive-200",children:ee}):null,e.jsxs("section",{"aria-labelledby":"traffic-24h-heading",children:[e.jsx("h2",{id:"traffic-24h-heading",className:"mb-3 text-sm font-medium text-heading",children:"Last 24 hours"}),e.jsxs("div",{className:"grid grid-cols-1 divide-y divide-default border-y border-default sm:grid-cols-3 sm:divide-x sm:divide-y-0",children:[e.jsx(Q,{label:"Content crawls",value:l.totals24h.crawlerContentHits,tooltip:`Content and document paths only. Excludes sitemap ${l.totals24h.crawlerSegments.sitemap.toLocaleString("en-US")}, robots ${l.totals24h.crawlerSegments.robots.toLocaleString("en-US")}, assets ${l.totals24h.crawlerSegments.asset.toLocaleString("en-US")}, and ${l.totals24h.crawlerSegments.other.toLocaleString("en-US")} other requests such as feeds, API paths, or downloads. Total crawler hits: ${l.totals24h.crawlerHits.toLocaleString("en-US")}.`}),e.jsx(Q,{label:"AI user fetches",value:l.totals24h.aiUserFetchHits,tooltip:"ChatGPT-User/Perplexity-User fetches initiated by a real user in an AI surface."}),e.jsx(Q,{label:"AI referral sessions",value:l.totals24h.aiReferralHits,tooltip:"Browser click-throughs from AI surfaces, identified by Referer or UTM evidence."})]})]}),e.jsxs("section",{children:[e.jsx("p",{className:"eyebrow mb-4",children:"Latest sync run"}),l.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-heading",children:["Status: ",e.jsx("span",{className:"font-medium",children:l.latestRun.status})]}),e.jsxs("span",{className:"text-muted",children:["Started: ",xe(l.latestRun.startedAt)]}),l.latestRun.finishedAt?e.jsxs("span",{className:"text-muted",children:["Finished: ",xe(l.latestRun.finishedAt)]}):null]}),e.jsxs("details",{className:"mt-3",children:[e.jsx("summary",{className:"cursor-pointer text-sm text-secondary hover:text-strong",children:"Run details"}),e.jsx("code",{className:"mt-2 block text-xs text-muted",children:l.latestRun.runId})]}),l.latestRun.error?e.jsx("p",{className:"mt-2 rounded border border-negative-900/40 bg-negative-950/30 px-3 py-2 text-xs text-negative",children:l.latestRun.error}):null]}):e.jsx(H,{className:"px-4 py-3 text-sm text-muted",children:ae()?"No traffic-sync runs recorded yet.":'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-muted",children:"Events"}),e.jsx("h2",{className:"mt-1 text-base font-semibold text-primary",children:h.granularity==="day"?"Daily rollups":"Hourly rollups"}),y?e.jsxs("p",{className:"mt-1.5 text-xs text-muted",children:[y.crawlerContentHits.toLocaleString("en-US")," content crawls ·"," ",y.crawlerInfraHits.toLocaleString("en-US")," infra (sitemap/robots/assets) ·"," ",y.aiUserFetchHits.toLocaleString("en-US")," AI user fetches ·"," ",y.aiReferralHits.toLocaleString("en-US")," AI referral sessions · last ",h.label," · ",ue]}):null]}),e.jsx("div",{className:"inline-flex rounded-md border border-base p-0.5",role:"toolbar","aria-label":"Window",children:U.map(t=>e.jsx("button",{type:"button",className:`rounded px-2.5 py-1 text-xs ${u===t.value?"bg-bg-elevated text-heading":"text-secondary hover:text-strong"}`,"aria-pressed":u===t.value,onClick:()=>{f(t.value),A(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(X,{label:"Crawler",color:oe,count:y?.crawlerHits??0,active:x.has("crawler"),onToggle:()=>G("crawler")}),e.jsx(X,{label:"AI user fetches",color:ce,count:y?.aiUserFetchHits??0,active:x.has("ai-user-fetch"),onToggle:()=>G("ai-user-fetch")}),e.jsx(X,{label:"AI referral sessions",color:de,count:y?.aiReferralHits??0,active:x.has("ai-referral"),onToggle:()=>G("ai-referral")})]}),g.isError?e.jsxs("p",{className:"py-12 text-center text-xs text-negative-400",children:["Failed to load events: ",g.error instanceof Error?g.error.message:"Unknown error"]}):g.isLoading?e.jsx("p",{className:"py-12 text-center text-xs text-muted",children:"Loading events…"}):C.length===0?e.jsx("p",{className:"py-12 text-center text-xs text-muted",children:"No events in this window."}):e.jsx("div",{className:"h-72",children:e.jsx(Xe,{children:e.jsxs(Qe,{data:C,margin:{top:4,right:4,bottom:0,left:0},onClick:Le,style:{cursor:"pointer"},children:[e.jsx(Ye,{stroke:Ke,strokeDasharray:"3 3"}),e.jsx(Ze,{dataKey:"label",tick:ne,stroke:re,interval:"preserveStartEnd",minTickGap:h.granularity==="day"?24:32}),e.jsx(Je,{tick:ne,stroke:re,allowDecimals:!1}),e.jsx(et,{...ze}),x.has("crawler")?e.jsx(V,{dataKey:"crawler",name:"Crawler",fill:oe,stackId:"a",children:C.map(t=>e.jsx(q,{fillOpacity:c&&c!==t.bucket?.25:1},t.bucket))}):null,x.has("ai-user-fetch")?e.jsx(V,{dataKey:"aiUserFetch",name:"AI user fetch",fill:ce,stackId:"a",children:C.map(t=>e.jsx(q,{fillOpacity:c&&c!==t.bucket?.25:1},t.bucket))}):null,x.has("ai-referral")?e.jsx(V,{dataKey:"aiReferral",name:"AI referral",fill:de,stackId:"a",children:C.map(t=>e.jsx(q,{fillOpacity:c&&c!==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-muted",children:"Event rows"}),e.jsxs("p",{className:"mt-1 text-xs text-muted",children:["Showing ",e.jsx("span",{className:"tabular-nums text-neutral",children:j.length.toLocaleString("en-US")})," of"," ",e.jsx("span",{className:"tabular-nums text-muted",children:E.length.toLocaleString("en-US")})," ",T?.truncated?"loaded events":"events",T?.truncated?e.jsxs(e.Fragment,{children:[" ","· loaded ",e.jsx("span",{className:"tabular-nums text-neutral",children:T.returned.toLocaleString("en-US")})," of"," ",e.jsx("span",{className:"tabular-nums text-muted",children:T.total.toLocaleString("en-US")})," rows"]}):null," ","· ",ue]})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsxs("span",{className:"inline-flex items-center text-secondary",children:[e.jsxs("select",{"aria-label":"Filter by identity",value:p,onChange:t=>O(t.target.value),className:"rounded-md border border-base bg-bg px-2.5 py-1.5 text-xs text-strong focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-600",children:[e.jsx("option",{value:"",children:"All identities"}),Ne.map(t=>e.jsx("option",{value:t,children:t},t))]}),e.jsx(P,{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-secondary",children:[e.jsxs("select",{"aria-label":"Filter by operator",value:b,onChange:t=>M(t.target.value),className:"rounded-md border border-base bg-bg px-2.5 py-1.5 text-xs text-strong focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-600",children:[e.jsx("option",{value:"",children:"All operators"}),Se.map(t=>e.jsx("option",{value:t,children:t},t))]}),e.jsx(P,{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:N,onChange:t=>D(t.target.value),className:"rounded-md border border-base bg-bg px-2.5 py-1.5 text-xs text-strong focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-600",children:tt.map(t=>e.jsx("option",{value:t.value,children:t.label},t.value))}),e.jsx("select",{"aria-label":"Filter by verification claim",value:S,onChange:t=>B(t.target.value),className:"rounded-md border border-base bg-bg px-2.5 py-1.5 text-xs text-strong focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-600",children:me.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:v,onChange:t=>_(t.target.value),className:"w-44 rounded-md border border-base bg-bg px-2.5 py-1.5 text-xs text-strong placeholder:text-faint focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-600"})]})]}),Ae?e.jsxs("div",{className:"mb-3 flex flex-wrap items-center gap-2",children:[se?e.jsx(k,{label:`Bucket: ${se}`,onClear:()=>A(null)}):null,p?e.jsx(k,{label:`Identity: ${p}`,onClear:()=>O("")}):null,b?e.jsx(k,{label:`Operator: ${b}`,onClear:()=>M("")}):null,v.trim()?e.jsx(k,{label:`Path: ${v.trim()}`,onClear:()=>_("")}):null,N!=="all"?e.jsx(k,{label:`Status: ${N}`,onClear:()=>D("all")}):null,S!=="all"?e.jsx(k,{label:`Claim: ${dt(S)}`,onClear:()=>B("all")}):null,e.jsx("button",{type:"button",onClick:Ie,className:"text-xs text-muted underline-offset-4 hover:text-strong hover:underline",children:"Clear all"})]}):null,e.jsx(mt,{events:we,truncated:T?.truncated??!1}),Ce?e.jsxs("div",{className:"mt-3 flex flex-wrap items-center justify-between gap-x-4 gap-y-2 text-xs text-secondary",children:[e.jsxs("p",{className:"tabular-nums",children:["Showing ",e.jsx("span",{className:"text-neutral",children:ke.toLocaleString("en-US")}),"–",e.jsx("span",{className:"text-neutral",children:Te.toLocaleString("en-US")})," of"," ",e.jsx("span",{className:"text-neutral",children:j.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:F<=1,"aria-label":"Previous page",className:"inline-flex items-center gap-1 rounded-md border border-base bg-bg px-2.5 py-1.5 text-strong transition hover:border-strong hover:text-primary disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:border-base disabled:hover:text-strong",children:[e.jsx(We,{className:"size-3.5"}),"Prev"]}),e.jsxs("span",{className:"tabular-nums",children:["Page ",e.jsx("span",{className:"text-strong",children:F})," of"," ",e.jsx("span",{className:"text-strong",children:$})]}),e.jsxs("button",{type:"button",onClick:()=>K(t=>Math.min($,t+1)),disabled:F>=$,"aria-label":"Next page",className:"inline-flex items-center gap-1 rounded-md border border-base bg-bg px-2.5 py-1.5 text-strong transition hover:border-strong hover:text-primary disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:border-base disabled:hover:text-strong",children:["Next",e.jsx(Ve,{className:"size-3.5"})]})]})]}):null]}),e.jsxs("details",{className:"border-t border-default pt-4",children:[e.jsx("summary",{className:"cursor-pointer text-sm text-secondary hover:text-strong",children:"How traffic is classified"}),e.jsx("p",{className:"mt-2 max-w-3xl text-sm text-secondary",children:"Crawler requests, AI user fetches, and referrals are recorded separately. Filters expose the underlying evidence."})]})]})}function ge(s,a){return a==="day"?it(s):be(s)}function ct(s,a){return s.map(r=>({bucket:r.bucket,label:ge(r.bucket,a),crawler:r.crawlerHits,aiUserFetch:r.aiUserFetchHits,aiReferral:r.aiReferralHits}))}function dt(s){return me.find(a=>a.value===s)?.label??s}function k({label:s,onClear:a}){return e.jsxs("span",{className:"inline-flex items-center gap-1.5 rounded border border-strong bg-surface-inset px-2.5 py-1 text-sm text-strong",children:[s,e.jsx("button",{type:"button",onClick:a,"aria-label":`Clear ${s}`,className:"rounded p-0.5 text-secondary hover:bg-mono-700/60 hover:text-heading",children:e.jsx(qe,{className:"size-3"})})]})}function X({label:s,color:a,count:r,active:n,onToggle:u}){return e.jsxs("button",{type:"button",onClick:u,"aria-pressed":n,className:`inline-flex items-center gap-2 rounded border px-3 py-1.5 text-xs font-medium transition ${n?"border-strong bg-surface-inset text-heading":"border-base bg-transparent text-muted hover:text-neutral"}`,children:[e.jsx("span",{"aria-hidden":"true",className:`flex size-3 items-center justify-center rounded-sm border transition-opacity ${n?"border-transparent opacity-100":"border-strong opacity-60"}`,style:n?{backgroundColor:a}:void 0,children:n?"✓":""}),e.jsx("span",{children:s}),e.jsx("span",{className:`tabular-nums ${n?"text-secondary":"text-faint"}`,children:r.toLocaleString("en-US")})]})}function Q({label:s,value:a,tooltip:r}){return e.jsxs("div",{className:"px-4 py-3",children:[e.jsxs("p",{className:"flex items-center gap-1 text-sm text-secondary",children:[s,r?e.jsx(P,{text:r}):null]}),e.jsx("p",{className:"mt-1 text-2xl font-semibold tabular-nums text-heading",children:a.toLocaleString("en-US")})]})}function ut(s){switch(s){case o.crawler:return"Crawler";case o["ai-user-fetch"]:return"AI hit";case o["ai-referral"]:return"AI referral"}}function xt(s){switch(s.kind){case o.crawler:case o["ai-user-fetch"]:return s.botId;case o["ai-referral"]:return s.product}}function ht(s){switch(s.kind){case o.crawler:case o["ai-user-fetch"]:return`${s.verificationStatus} · HTTP ${s.status}`;case o["ai-referral"]:return`${s.evidenceType} · ${s.sourceDomain}`}}function mt({events:s,truncated:a=!1}){return s.length===0?e.jsx(H,{className:"p-6 text-center text-sm text-muted",children:a?"No matches in the rows loaded so far. More rows exist beyond the load limit, so narrow the time window to search them.":"No event rows match the current filters."}):e.jsx("div",{className:"rounded-xl border border-default bg-surface overflow-hidden",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"bg-bg-elevated/50 text-[10px] font-semibold uppercase tracking-wider text-muted",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(P,{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-mono-800/60",children:s.map((r,n)=>e.jsxs("tr",{className:"hover:bg-bg-elevated/40 transition-colors",children:[e.jsx("td",{className:"px-4 py-2 font-mono text-xs text-neutral",children:be(r.tsHour)}),e.jsx("td",{className:"px-4 py-2 text-neutral",children:ut(r.kind)}),e.jsxs("td",{className:"px-4 py-2 text-heading",children:[xt(r),e.jsx("span",{className:"ml-2 text-[11px] text-muted",children:r.operator})]}),e.jsx("td",{className:"px-4 py-2 text-neutral",children:ht(r)}),e.jsx("td",{className:"px-4 py-2 truncate font-mono text-xs text-neutral",children:pe(r)}),e.jsx("td",{className:"px-4 py-2 text-right tabular-nums text-heading",children:r.hits})]},`${r.kind}:${r.tsHour}:${n}`))})]})})}export{mt as EventsTable,Q as TrafficKpi,wt as TrafficSourceDetailPage,ot as trafficFetchKind};
|