@ainyc/canonry 4.87.0 → 4.89.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.
- package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +16 -0
- package/assets/agent-workspace/skills/canonry/references/server-side-traffic.md +19 -0
- package/assets/assets/{BacklinksPage-BPvsw_Bi.js → BacklinksPage-Cl3V55iK.js} +1 -1
- package/assets/assets/{ChartPrimitives-BdlKCq7y.js → ChartPrimitives-D4D_lSIp.js} +1 -1
- package/assets/assets/{ProjectPage-1Q8YC9Vd.js → ProjectPage-Dwwcddk2.js} +1 -1
- package/assets/assets/{RunRow-DcSsnE5c.js → RunRow-CNjwUkqj.js} +1 -1
- package/assets/assets/{RunsPage-DKoIMkQL.js → RunsPage-owFYxiRU.js} +1 -1
- package/assets/assets/{SettingsPage-bH3PdNKb.js → SettingsPage-D3rc2Hze.js} +1 -1
- package/assets/assets/{TrafficPage-IW_DX-0V.js → TrafficPage-BDkhe0Iz.js} +1 -1
- package/assets/assets/TrafficSourceDetailPage-CUw6Odt1.js +1 -0
- package/assets/assets/{arrow-left-B5Du72nk.js → arrow-left-BAOMqvGW.js} +1 -1
- package/assets/assets/{extract-error-message-C7Vhd5zH.js → extract-error-message-BO0DeR7V.js} +1 -1
- package/assets/assets/{index-C_ZzKZfM.js → index-BbnglhBg.js} +79 -79
- package/assets/assets/index-fLUYE9Z5.css +1 -0
- package/assets/assets/{trash-2-DWcofmpv.js → trash-2-RQK6oqQJ.js} +1 -1
- package/assets/index.html +2 -2
- package/dist/{chunk-MDRDX5R2.js → chunk-LRO4CLPL.js} +230 -1
- package/dist/{chunk-DUDFNP5Y.js → chunk-MUPIPQBB.js} +50 -7
- package/dist/{chunk-6XMXBAEW.js → chunk-PRKBJNAG.js} +1 -1
- package/dist/{chunk-5LW7CJAO.js → chunk-WEV4RH25.js} +30 -6
- package/dist/cli.js +44 -14
- package/dist/index.d.ts +9 -1
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-XUKYOHKL.js → intelligence-service-SO46DMGR.js} +2 -2
- package/dist/mcp.js +2 -2
- package/package.json +8 -8
- package/assets/assets/TrafficSourceDetailPage-DRHOGn9B.js +0 -1
- package/assets/assets/index-ClkRAeHL.css +0 -1
package/dist/cli.js
CHANGED
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
setTelemetrySource,
|
|
28
28
|
showFirstRunNotice,
|
|
29
29
|
trackEvent
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-MUPIPQBB.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-
|
|
47
|
+
} from "./chunk-PRKBJNAG.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-
|
|
55
|
+
} from "./chunk-WEV4RH25.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-
|
|
80
|
+
} from "./chunk-LRO4CLPL.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
|
|
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(`
|
|
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("");
|
|
@@ -10293,6 +10299,18 @@ async function waitForReady(host, port, maxMs = 1e4) {
|
|
|
10293
10299
|
}
|
|
10294
10300
|
return false;
|
|
10295
10301
|
}
|
|
10302
|
+
function buildServeForwardArgs(opts) {
|
|
10303
|
+
const args = [];
|
|
10304
|
+
if (opts.port) args.push("--port", opts.port);
|
|
10305
|
+
if (opts.host) args.push("--host", opts.host);
|
|
10306
|
+
if (opts.basePath) args.push("--base-path", opts.basePath);
|
|
10307
|
+
if (opts.embed) {
|
|
10308
|
+
args.push("--embed");
|
|
10309
|
+
for (const origin of opts.embedAllowOrigins ?? []) args.push("--embed-allow-origin", origin);
|
|
10310
|
+
for (const view of opts.embedViews ?? []) args.push("--embed-view", view);
|
|
10311
|
+
}
|
|
10312
|
+
return args;
|
|
10313
|
+
}
|
|
10296
10314
|
async function startDaemon(opts) {
|
|
10297
10315
|
const pidPath = getPidPath();
|
|
10298
10316
|
const format = opts.format ?? "text";
|
|
@@ -10313,9 +10331,7 @@ async function startDaemon(opts) {
|
|
|
10313
10331
|
const cliPath = path7.resolve(new URL(import.meta.url).pathname);
|
|
10314
10332
|
const inSourceMode = new URL(import.meta.url).pathname.endsWith(".ts");
|
|
10315
10333
|
const args = inSourceMode ? ["--import", "tsx", cliPath, "serve"] : [cliPath, "serve"];
|
|
10316
|
-
|
|
10317
|
-
if (opts.host) args.push("--host", opts.host);
|
|
10318
|
-
if (opts.basePath) args.push("--base-path", opts.basePath);
|
|
10334
|
+
args.push(...buildServeForwardArgs(opts));
|
|
10319
10335
|
const child = spawn(process.execPath, args, {
|
|
10320
10336
|
detached: true,
|
|
10321
10337
|
stdio: "ignore"
|
|
@@ -10996,6 +11012,11 @@ function applyServerEnv(values) {
|
|
|
10996
11012
|
if (port) process.env.CANONRY_PORT = port;
|
|
10997
11013
|
if (host) process.env.CANONRY_HOST = host;
|
|
10998
11014
|
if (basePath) process.env.CANONRY_BASE_PATH = basePath;
|
|
11015
|
+
const embedOrigins = getStringArray(values, "embed-allow-origin");
|
|
11016
|
+
const embedViews = getStringArray(values, "embed-view");
|
|
11017
|
+
if (getBoolean(values, "embed")) process.env.CANONRY_EMBED = "1";
|
|
11018
|
+
if (embedOrigins && embedOrigins.length > 0) process.env.CANONRY_EMBED_ORIGINS = embedOrigins.join(",");
|
|
11019
|
+
if (embedViews && embedViews.length > 0) process.env.CANONRY_EMBED_VIEWS = embedViews.join(",");
|
|
10999
11020
|
}
|
|
11000
11021
|
var SYSTEM_CLI_COMMANDS = [
|
|
11001
11022
|
{
|
|
@@ -11052,11 +11073,14 @@ var SYSTEM_CLI_COMMANDS = [
|
|
|
11052
11073
|
},
|
|
11053
11074
|
{
|
|
11054
11075
|
path: ["serve"],
|
|
11055
|
-
usage: "canonry serve [--port <port>] [--host <host>] [--base-path <path>] [--format json]",
|
|
11076
|
+
usage: "canonry serve [--port <port>] [--host <host>] [--base-path <path>] [--embed] [--embed-allow-origin <origin>...] [--embed-view <view>...] [--format json]",
|
|
11056
11077
|
options: {
|
|
11057
11078
|
port: stringOption(),
|
|
11058
11079
|
host: stringOption(),
|
|
11059
|
-
"base-path": stringOption()
|
|
11080
|
+
"base-path": stringOption(),
|
|
11081
|
+
embed: { type: "boolean", default: false },
|
|
11082
|
+
"embed-allow-origin": multiStringOption(),
|
|
11083
|
+
"embed-view": multiStringOption()
|
|
11060
11084
|
},
|
|
11061
11085
|
allowPositionals: false,
|
|
11062
11086
|
run: async (input) => {
|
|
@@ -11066,11 +11090,14 @@ var SYSTEM_CLI_COMMANDS = [
|
|
|
11066
11090
|
},
|
|
11067
11091
|
{
|
|
11068
11092
|
path: ["start"],
|
|
11069
|
-
usage: "canonry start [--port <port>] [--host <host>] [--base-path <path>] [--format json]",
|
|
11093
|
+
usage: "canonry start [--port <port>] [--host <host>] [--base-path <path>] [--embed] [--embed-allow-origin <origin>...] [--embed-view <view>...] [--format json]",
|
|
11070
11094
|
options: {
|
|
11071
11095
|
port: stringOption(),
|
|
11072
11096
|
host: stringOption(),
|
|
11073
|
-
"base-path": stringOption()
|
|
11097
|
+
"base-path": stringOption(),
|
|
11098
|
+
embed: { type: "boolean", default: false },
|
|
11099
|
+
"embed-allow-origin": multiStringOption(),
|
|
11100
|
+
"embed-view": multiStringOption()
|
|
11074
11101
|
},
|
|
11075
11102
|
allowPositionals: false,
|
|
11076
11103
|
run: async (input) => {
|
|
@@ -11078,6 +11105,9 @@ var SYSTEM_CLI_COMMANDS = [
|
|
|
11078
11105
|
port: getString(input.values, "port"),
|
|
11079
11106
|
host: getString(input.values, "host"),
|
|
11080
11107
|
basePath: getString(input.values, "base-path"),
|
|
11108
|
+
embed: getBoolean(input.values, "embed"),
|
|
11109
|
+
embedAllowOrigins: getStringArray(input.values, "embed-allow-origin"),
|
|
11110
|
+
embedViews: getStringArray(input.values, "embed-view"),
|
|
11081
11111
|
format: input.format
|
|
11082
11112
|
});
|
|
11083
11113
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { FastifyInstance } from 'fastify';
|
|
2
2
|
import { DatabaseClient } from '@ainyc/canonry-db';
|
|
3
|
-
import { ProviderQuotaPolicy } from '@ainyc/canonry-contracts';
|
|
3
|
+
import { ProviderQuotaPolicy, EmbedConfigEntry } from '@ainyc/canonry-contracts';
|
|
4
4
|
|
|
5
5
|
type GoogleConnectionType = 'gsc' | 'ga4' | 'gbp';
|
|
6
6
|
interface ProviderConfigEntry {
|
|
@@ -205,6 +205,7 @@ interface CanonryConfig {
|
|
|
205
205
|
lastKnownLatestVersion?: string;
|
|
206
206
|
agent?: AgentConfigEntry;
|
|
207
207
|
places?: PlacesConfigEntry;
|
|
208
|
+
embed?: EmbedConfigEntry;
|
|
208
209
|
}
|
|
209
210
|
declare function loadConfig(): CanonryConfig;
|
|
210
211
|
|
|
@@ -223,6 +224,13 @@ declare function createServer(opts: {
|
|
|
223
224
|
* Defaults to loopback when unset (programmatic/test callers).
|
|
224
225
|
*/
|
|
225
226
|
host?: string;
|
|
227
|
+
/**
|
|
228
|
+
* Override for the directory the pre-built SPA is served from. Defaults to
|
|
229
|
+
* the package's bundled `assets/` (resolved from `import.meta.url`). Exposed
|
|
230
|
+
* so tests can point at a temp dir containing a fixture `index.html` and
|
|
231
|
+
* assert the injected config + framing header on the served document.
|
|
232
|
+
*/
|
|
233
|
+
assetsDir?: string;
|
|
226
234
|
}): Promise<FastifyInstance>;
|
|
227
235
|
|
|
228
236
|
export { type CanonryConfig, createServer, loadConfig };
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createServer
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-MUPIPQBB.js";
|
|
4
4
|
import {
|
|
5
5
|
loadConfig
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-PRKBJNAG.js";
|
|
7
|
+
import "./chunk-WEV4RH25.js";
|
|
8
|
+
import "./chunk-LRO4CLPL.js";
|
|
9
9
|
export {
|
|
10
10
|
createServer,
|
|
11
11
|
loadConfig
|
package/dist/mcp.js
CHANGED
|
@@ -3,10 +3,10 @@ import {
|
|
|
3
3
|
PACKAGE_VERSION,
|
|
4
4
|
canonryMcpTools,
|
|
5
5
|
createApiClient
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-PRKBJNAG.js";
|
|
7
7
|
import {
|
|
8
8
|
isReadOnlyKey
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-LRO4CLPL.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.
|
|
3
|
+
"version": "4.89.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",
|
|
@@ -64,23 +64,23 @@
|
|
|
64
64
|
"tsx": "^4.19.0",
|
|
65
65
|
"@ainyc/canonry-api-routes": "0.0.0",
|
|
66
66
|
"@ainyc/canonry-config": "0.0.0",
|
|
67
|
-
"@ainyc/canonry-api-client": "0.0.0",
|
|
68
67
|
"@ainyc/canonry-contracts": "0.0.0",
|
|
69
68
|
"@ainyc/canonry-db": "0.0.0",
|
|
70
|
-
"@ainyc/canonry-integration-openai-ads": "0.0.0",
|
|
71
69
|
"@ainyc/canonry-integration-cloud-run": "0.0.0",
|
|
72
|
-
"@ainyc/canonry-integration-commoncrawl": "0.0.0",
|
|
73
70
|
"@ainyc/canonry-integration-bing": "0.0.0",
|
|
74
|
-
"@ainyc/canonry-
|
|
71
|
+
"@ainyc/canonry-api-client": "0.0.0",
|
|
72
|
+
"@ainyc/canonry-integration-openai-ads": "0.0.0",
|
|
73
|
+
"@ainyc/canonry-integration-commoncrawl": "0.0.0",
|
|
75
74
|
"@ainyc/canonry-integration-google": "0.0.0",
|
|
76
75
|
"@ainyc/canonry-integration-google-places": "0.0.0",
|
|
76
|
+
"@ainyc/canonry-integration-google-business-profile": "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-
|
|
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",
|
|
83
81
|
"@ainyc/canonry-provider-claude": "0.0.0",
|
|
82
|
+
"@ainyc/canonry-provider-gemini": "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};
|