@ainyc/canonry 4.15.0 → 4.15.2

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.
@@ -2251,6 +2251,65 @@ var trafficSyncResponseSchema = z20.object({
2251
2251
  windowStart: z20.string(),
2252
2252
  windowEnd: z20.string()
2253
2253
  });
2254
+ var trafficSourceTotalsSchema = z20.object({
2255
+ crawlerHits: z20.number().int().nonnegative(),
2256
+ aiReferralHits: z20.number().int().nonnegative(),
2257
+ sampleCount: z20.number().int().nonnegative()
2258
+ });
2259
+ var trafficSourceListResponseSchema = z20.object({
2260
+ sources: z20.array(trafficSourceDtoSchema)
2261
+ });
2262
+ var trafficSourceDetailDtoSchema = trafficSourceDtoSchema.extend({
2263
+ totals24h: trafficSourceTotalsSchema,
2264
+ latestRun: z20.object({
2265
+ runId: z20.string(),
2266
+ status: runStatusSchema,
2267
+ startedAt: z20.string().nullable(),
2268
+ finishedAt: z20.string().nullable(),
2269
+ error: z20.string().nullable()
2270
+ }).nullable()
2271
+ });
2272
+ var trafficStatusResponseSchema = z20.object({
2273
+ sources: z20.array(trafficSourceDetailDtoSchema)
2274
+ });
2275
+ var trafficEventKindSchema = z20.enum(["crawler", "ai-referral"]);
2276
+ var TrafficEventKinds = trafficEventKindSchema.enum;
2277
+ var trafficCrawlerEventEntrySchema = z20.object({
2278
+ kind: z20.literal(TrafficEventKinds.crawler),
2279
+ sourceId: z20.string(),
2280
+ tsHour: z20.string(),
2281
+ botId: z20.string(),
2282
+ operator: z20.string(),
2283
+ verificationStatus: z20.string(),
2284
+ pathNormalized: z20.string(),
2285
+ status: z20.number().int(),
2286
+ hits: z20.number().int().nonnegative()
2287
+ });
2288
+ var trafficAiReferralEventEntrySchema = z20.object({
2289
+ kind: z20.literal(TrafficEventKinds["ai-referral"]),
2290
+ sourceId: z20.string(),
2291
+ tsHour: z20.string(),
2292
+ product: z20.string(),
2293
+ operator: z20.string(),
2294
+ sourceDomain: z20.string(),
2295
+ evidenceType: z20.string(),
2296
+ landingPathNormalized: z20.string(),
2297
+ status: z20.number().int(),
2298
+ hits: z20.number().int().nonnegative()
2299
+ });
2300
+ var trafficEventEntrySchema = z20.discriminatedUnion("kind", [
2301
+ trafficCrawlerEventEntrySchema,
2302
+ trafficAiReferralEventEntrySchema
2303
+ ]);
2304
+ var trafficEventsResponseSchema = z20.object({
2305
+ windowStart: z20.string(),
2306
+ windowEnd: z20.string(),
2307
+ totals: z20.object({
2308
+ crawlerHits: z20.number().int().nonnegative(),
2309
+ aiReferralHits: z20.number().int().nonnegative()
2310
+ }),
2311
+ events: z20.array(trafficEventEntrySchema)
2312
+ });
2254
2313
 
2255
2314
  // ../contracts/src/formatting.ts
2256
2315
  function formatRatio(value) {
@@ -2389,6 +2448,9 @@ export {
2389
2448
  TrafficEventConfidences,
2390
2449
  TrafficSourceStatuses,
2391
2450
  TrafficSourceAuthModes,
2451
+ trafficConnectCloudRunRequestSchema,
2452
+ trafficEventKindSchema,
2453
+ TrafficEventKinds,
2392
2454
  formatRatio,
2393
2455
  formatNumber,
2394
2456
  formatDate,
package/dist/cli.js CHANGED
@@ -20,7 +20,7 @@ import {
20
20
  setTelemetrySource,
21
21
  showFirstRunNotice,
22
22
  trackEvent
23
- } from "./chunk-DLSQXNUN.js";
23
+ } from "./chunk-IVNWS2YU.js";
24
24
  import {
25
25
  CliError,
26
26
  EXIT_SYSTEM_ERROR,
@@ -36,7 +36,7 @@ import {
36
36
  saveConfig,
37
37
  saveConfigPatch,
38
38
  usageError
39
- } from "./chunk-C32VL5BB.js";
39
+ } from "./chunk-7SRKUAZO.js";
40
40
  import {
41
41
  apiKeys,
42
42
  competitors,
@@ -49,7 +49,7 @@ import {
49
49
  queries,
50
50
  querySnapshots,
51
51
  runs
52
- } from "./chunk-7HBZCGRL.js";
52
+ } from "./chunk-MI33SQL6.js";
53
53
  import {
54
54
  CcReleaseSyncStatuses,
55
55
  CheckScopes,
@@ -60,6 +60,7 @@ import {
60
60
  RunKinds,
61
61
  RunStatuses,
62
62
  SkillsClients,
63
+ TrafficEventKinds,
63
64
  determineAnswerMentioned,
64
65
  effectiveDomains,
65
66
  formatRunErrorOneLine,
@@ -68,7 +69,7 @@ import {
68
69
  providerQuotaPolicySchema,
69
70
  resolveProviderInput,
70
71
  skillsClientSchema
71
- } from "./chunk-6QTH5NS5.js";
72
+ } from "./chunk-ONI3TX2A.js";
72
73
 
73
74
  // src/cli.ts
74
75
  import { pathToFileURL } from "url";
@@ -620,7 +621,7 @@ function readStoredGroundingSources(rawResponse) {
620
621
  return result;
621
622
  }
622
623
  async function backfillInsightsCommand(project, opts) {
623
- const { IntelligenceService } = await import("./intelligence-service-BCKXIKIL.js");
624
+ const { IntelligenceService } = await import("./intelligence-service-JYV3CO4H.js");
624
625
  const config = loadConfig();
625
626
  const db = createClient(config.database);
626
627
  migrate(db);
@@ -2801,6 +2802,128 @@ async function trafficSync(project, opts) {
2801
2802
  console.log(` Sample rows: ${result.sampleRows}`);
2802
2803
  console.log(` Synced at: ${result.syncedAt}`);
2803
2804
  }
2805
+ function formatSourceLine(source) {
2806
+ const parts = [
2807
+ source.id,
2808
+ source.sourceType,
2809
+ source.status,
2810
+ source.lastSyncedAt ?? "never synced",
2811
+ source.displayName
2812
+ ];
2813
+ return parts.join(" ");
2814
+ }
2815
+ async function trafficSources(project, opts) {
2816
+ const client = createApiClient();
2817
+ const result = await client.trafficListSources(project);
2818
+ if (opts.format === "json") {
2819
+ console.log(JSON.stringify(result, null, 2));
2820
+ return;
2821
+ }
2822
+ if (result.sources.length === 0) {
2823
+ console.log(`No traffic sources connected for project "${project}".`);
2824
+ console.log("Run: canonry traffic connect cloud-run <project> --gcp-project <id> --service-account-key <path>");
2825
+ return;
2826
+ }
2827
+ console.log(`Traffic sources for "${project}":`);
2828
+ console.log(" ID TYPE STATUS LAST_SYNCED DISPLAY_NAME");
2829
+ for (const source of result.sources) {
2830
+ console.log(` ${formatSourceLine(source)}`);
2831
+ }
2832
+ }
2833
+ async function trafficStatus(project, opts) {
2834
+ const client = createApiClient();
2835
+ const result = await client.trafficStatus(project);
2836
+ const details = result.sources;
2837
+ if (opts.format === "json") {
2838
+ console.log(JSON.stringify(result, null, 2));
2839
+ return;
2840
+ }
2841
+ if (details.length === 0) {
2842
+ console.log(`No traffic sources connected for project "${project}".`);
2843
+ console.log("Run: canonry traffic connect cloud-run <project> --gcp-project <id> --service-account-key <path>");
2844
+ return;
2845
+ }
2846
+ for (const d of details) {
2847
+ console.log(`Source ${d.id} (${d.sourceType})`);
2848
+ console.log(` Display name: ${d.displayName}`);
2849
+ console.log(` Status: ${d.status}`);
2850
+ console.log(` Last synced: ${d.lastSyncedAt ?? "never"}`);
2851
+ if (d.lastError) console.log(` Last error: ${d.lastError}`);
2852
+ console.log(` 24h crawler: ${d.totals24h.crawlerHits} hits`);
2853
+ console.log(` 24h AI referral: ${d.totals24h.aiReferralHits} hits`);
2854
+ console.log(` 24h samples: ${d.totals24h.sampleCount}`);
2855
+ if (d.latestRun) {
2856
+ console.log(` Latest run: ${d.latestRun.runId} (${d.latestRun.status})`);
2857
+ console.log(` Started: ${d.latestRun.startedAt}`);
2858
+ if (d.latestRun.finishedAt) console.log(` Finished: ${d.latestRun.finishedAt}`);
2859
+ if (d.latestRun.error) console.log(` Error: ${d.latestRun.error}`);
2860
+ } else {
2861
+ console.log(` Latest run: (none)`);
2862
+ }
2863
+ console.log("");
2864
+ }
2865
+ }
2866
+ function formatEventLine(event) {
2867
+ if (event.kind === TrafficEventKinds.crawler) {
2868
+ return [
2869
+ event.tsHour,
2870
+ "crawler",
2871
+ event.botId,
2872
+ event.verificationStatus,
2873
+ String(event.status),
2874
+ event.pathNormalized,
2875
+ `${event.hits} hits`
2876
+ ].join(" ");
2877
+ }
2878
+ return [
2879
+ event.tsHour,
2880
+ "ai-referral",
2881
+ event.product,
2882
+ event.evidenceType,
2883
+ event.sourceDomain,
2884
+ event.landingPathNormalized,
2885
+ `${event.hits} hits`
2886
+ ].join(" ");
2887
+ }
2888
+ async function trafficEvents(project, opts) {
2889
+ if (opts.kind && opts.kind !== "all" && opts.kind !== TrafficEventKinds.crawler && opts.kind !== TrafficEventKinds["ai-referral"]) {
2890
+ throw new CliError({
2891
+ code: "TRAFFIC_INVALID_KIND",
2892
+ message: `--kind must be one of: all, ${TrafficEventKinds.crawler}, ${TrafficEventKinds["ai-referral"]}`,
2893
+ displayMessage: `Error: --kind must be "all", "${TrafficEventKinds.crawler}", or "${TrafficEventKinds["ai-referral"]}"`,
2894
+ details: { project, kind: opts.kind }
2895
+ });
2896
+ }
2897
+ const params = {};
2898
+ if (opts.kind && opts.kind !== "all") params.kind = opts.kind;
2899
+ if (opts.source) params.sourceId = opts.source;
2900
+ if (opts.limit !== void 0) params.limit = opts.limit;
2901
+ if (opts.sinceMinutes !== void 0) {
2902
+ const since = new Date(Date.now() - opts.sinceMinutes * 6e4).toISOString();
2903
+ params.since = since;
2904
+ } else if (opts.since) {
2905
+ params.since = opts.since;
2906
+ }
2907
+ if (opts.until) params.until = opts.until;
2908
+ const client = createApiClient();
2909
+ const result = await client.trafficListEvents(project, params);
2910
+ if (opts.format === "json") {
2911
+ console.log(JSON.stringify(result, null, 2));
2912
+ return;
2913
+ }
2914
+ console.log(`Traffic events for "${project}" ${result.windowStart} \u2192 ${result.windowEnd}`);
2915
+ console.log(` Crawler hits (window): ${result.totals.crawlerHits}`);
2916
+ console.log(` AI referral hits (window): ${result.totals.aiReferralHits}`);
2917
+ console.log("");
2918
+ if (result.events.length === 0) {
2919
+ console.log("No events in this window.");
2920
+ return;
2921
+ }
2922
+ console.log(" TS_HOUR KIND IDENTITY EVIDENCE/STATUS PATH HITS");
2923
+ for (const event of result.events) {
2924
+ console.log(` ${formatEventLine(event)}`);
2925
+ }
2926
+ }
2804
2927
 
2805
2928
  // src/cli-commands/traffic.ts
2806
2929
  var TRAFFIC_CLI_COMMANDS = [
@@ -2847,7 +2970,7 @@ var TRAFFIC_CLI_COMMANDS = [
2847
2970
  },
2848
2971
  {
2849
2972
  path: ["traffic", "sync"],
2850
- usage: "canonry traffic sync <project> --source <id> [--since-minutes 60] [--format json]",
2973
+ usage: "canonry traffic sync <project> --source <id> [--since-minutes 43200] [--format json]",
2851
2974
  options: {
2852
2975
  source: stringOption(),
2853
2976
  "since-minutes": stringOption()
@@ -2856,12 +2979,15 @@ var TRAFFIC_CLI_COMMANDS = [
2856
2979
  const project = requireProject(
2857
2980
  input,
2858
2981
  "traffic.sync",
2859
- "canonry traffic sync <project> --source <id> [--since-minutes 60]"
2982
+ "canonry traffic sync <project> --source <id> [--since-minutes 43200]"
2860
2983
  );
2861
2984
  const source = getString(input.values, "source");
2862
2985
  if (!source) throw new Error("--source <id> is required");
2863
- const sinceStr = getString(input.values, "since-minutes");
2864
- const sinceMinutes = sinceStr ? parseInt(sinceStr, 10) : void 0;
2986
+ const sinceMinutes = parseIntegerOption(input, "since-minutes", {
2987
+ command: "traffic.sync",
2988
+ usage: "canonry traffic sync <project> --source <id> [--since-minutes 43200]",
2989
+ message: "--since-minutes must be an integer"
2990
+ });
2865
2991
  await trafficSync(project, {
2866
2992
  source,
2867
2993
  sinceMinutes,
@@ -2869,6 +2995,68 @@ var TRAFFIC_CLI_COMMANDS = [
2869
2995
  });
2870
2996
  }
2871
2997
  },
2998
+ {
2999
+ path: ["traffic", "sources"],
3000
+ usage: "canonry traffic sources <project> [--format json]",
3001
+ run: async (input) => {
3002
+ const project = requireProject(
3003
+ input,
3004
+ "traffic.sources",
3005
+ "canonry traffic sources <project>"
3006
+ );
3007
+ await trafficSources(project, { format: input.format });
3008
+ }
3009
+ },
3010
+ {
3011
+ path: ["traffic", "status"],
3012
+ usage: "canonry traffic status <project> [--format json]",
3013
+ run: async (input) => {
3014
+ const project = requireProject(
3015
+ input,
3016
+ "traffic.status",
3017
+ "canonry traffic status <project>"
3018
+ );
3019
+ await trafficStatus(project, { format: input.format });
3020
+ }
3021
+ },
3022
+ {
3023
+ path: ["traffic", "events"],
3024
+ usage: "canonry traffic events <project> [--kind crawler|ai-referral|all] [--source <id>] [--since-minutes 1440] [--since <iso>] [--until <iso>] [--limit 500] [--format json]",
3025
+ options: {
3026
+ kind: stringOption(),
3027
+ source: stringOption(),
3028
+ "since-minutes": stringOption(),
3029
+ since: stringOption(),
3030
+ until: stringOption(),
3031
+ limit: stringOption()
3032
+ },
3033
+ run: async (input) => {
3034
+ const project = requireProject(
3035
+ input,
3036
+ "traffic.events",
3037
+ "canonry traffic events <project>"
3038
+ );
3039
+ const sinceMinutes = parseIntegerOption(input, "since-minutes", {
3040
+ command: "traffic.events",
3041
+ usage: "canonry traffic events <project> [--since-minutes 1440]",
3042
+ message: "--since-minutes must be an integer"
3043
+ });
3044
+ const limit = parseIntegerOption(input, "limit", {
3045
+ command: "traffic.events",
3046
+ usage: "canonry traffic events <project> [--limit 500]",
3047
+ message: "--limit must be an integer"
3048
+ });
3049
+ await trafficEvents(project, {
3050
+ kind: getString(input.values, "kind"),
3051
+ source: getString(input.values, "source"),
3052
+ sinceMinutes,
3053
+ since: getString(input.values, "since"),
3054
+ until: getString(input.values, "until"),
3055
+ limit,
3056
+ format: input.format
3057
+ });
3058
+ }
3059
+ },
2872
3060
  {
2873
3061
  path: ["traffic"],
2874
3062
  usage: "canonry traffic <subcommand> <project> [args]",
@@ -2876,7 +3064,7 @@ var TRAFFIC_CLI_COMMANDS = [
2876
3064
  unknownSubcommand(input.positionals[0], {
2877
3065
  command: "traffic",
2878
3066
  usage: "canonry traffic <subcommand> <project> [args]",
2879
- available: ["connect", "sync"]
3067
+ available: ["connect", "sync", "status", "sources", "events"]
2880
3068
  });
2881
3069
  }
2882
3070
  }
@@ -10451,6 +10639,7 @@ Integrations:
10451
10639
  google Google Search Console / Analytics
10452
10640
  bing Bing Webmaster Tools
10453
10641
  wordpress WordPress REST API
10642
+ traffic Server-side traffic ingestion (Cloud Run)
10454
10643
 
10455
10644
  Automation:
10456
10645
  schedule Manage scheduled runs
@@ -10492,7 +10681,7 @@ async function runCli(args = process.argv.slice(2)) {
10492
10681
  showFirstRunNotice();
10493
10682
  getOrCreateAnonymousId();
10494
10683
  }
10495
- const SUBCOMMAND_COMMANDS = /* @__PURE__ */ new Set(["backfill", "project", "query", "keyword", "competitor", "schedule", "notify", "settings", "telemetry", "google", "bing", "wordpress", "cdp"]);
10684
+ const SUBCOMMAND_COMMANDS = /* @__PURE__ */ new Set(["backfill", "project", "query", "keyword", "competitor", "schedule", "notify", "settings", "telemetry", "google", "bing", "wordpress", "cdp", "traffic"]);
10496
10685
  const MIXED_SUBCOMMANDS = {
10497
10686
  insights: /* @__PURE__ */ new Set(["dismiss"]),
10498
10687
  run: /* @__PURE__ */ new Set(["show", "cancel"])
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  createServer
3
- } from "./chunk-DLSQXNUN.js";
3
+ } from "./chunk-IVNWS2YU.js";
4
4
  import {
5
5
  loadConfig
6
- } from "./chunk-C32VL5BB.js";
7
- import "./chunk-7HBZCGRL.js";
8
- import "./chunk-6QTH5NS5.js";
6
+ } from "./chunk-7SRKUAZO.js";
7
+ import "./chunk-MI33SQL6.js";
8
+ import "./chunk-ONI3TX2A.js";
9
9
  export {
10
10
  createServer,
11
11
  loadConfig
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  IntelligenceService
3
- } from "./chunk-7HBZCGRL.js";
4
- import "./chunk-6QTH5NS5.js";
3
+ } from "./chunk-MI33SQL6.js";
4
+ import "./chunk-ONI3TX2A.js";
5
5
  export {
6
6
  IntelligenceService
7
7
  };
package/dist/mcp.js CHANGED
@@ -2,8 +2,8 @@ import {
2
2
  CliError,
3
3
  canonryMcpTools,
4
4
  createApiClient
5
- } from "./chunk-C32VL5BB.js";
6
- import "./chunk-6QTH5NS5.js";
5
+ } from "./chunk-7SRKUAZO.js";
6
+ import "./chunk-ONI3TX2A.js";
7
7
 
8
8
  // src/mcp/cli.ts
9
9
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
@@ -107,7 +107,7 @@ function zodErrorMessage(error) {
107
107
  }
108
108
 
109
109
  // src/mcp/toolkits.ts
110
- var CANONRY_MCP_TOOLKIT_NAMES = ["monitoring", "setup", "gsc", "ga", "agent"];
110
+ var CANONRY_MCP_TOOLKIT_NAMES = ["monitoring", "setup", "gsc", "ga", "traffic", "agent"];
111
111
  var CANONRY_MCP_TOOLKITS = [
112
112
  {
113
113
  name: "monitoring",
@@ -133,6 +133,12 @@ var CANONRY_MCP_TOOLKITS = [
133
133
  description: "Read GA traffic, AI/social referral history, attribution trend, and session history.",
134
134
  whenToLoad: "Load when you need traffic, referral, or attribution data from Google Analytics 4."
135
135
  },
136
+ {
137
+ name: "traffic",
138
+ title: "Server-side traffic ingestion",
139
+ description: "Connect Cloud Run traffic sources, trigger syncs, and read crawler / AI-referral hourly rollups straight from server logs (no GA dependency).",
140
+ whenToLoad: "Load when you need server-log evidence of crawler hits or AI-referral arrivals (e.g. confirming GPTBot or ChatGPT-User on a page), or when wiring up / syncing a Cloud Run traffic source."
141
+ },
136
142
  {
137
143
  name: "agent",
138
144
  title: "Aero agent lifecycle and memory",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ainyc/canonry",
3
- "version": "4.15.0",
3
+ "version": "4.15.2",
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",
@@ -61,20 +61,20 @@
61
61
  "tsx": "^4.19.0",
62
62
  "@ainyc/canonry-api-routes": "0.0.0",
63
63
  "@ainyc/canonry-config": "0.0.0",
64
- "@ainyc/canonry-db": "0.0.0",
65
- "@ainyc/canonry-integration-bing": "0.0.0",
66
64
  "@ainyc/canonry-intelligence": "0.0.0",
67
- "@ainyc/canonry-integration-cloud-run": "0.0.0",
65
+ "@ainyc/canonry-db": "0.0.0",
68
66
  "@ainyc/canonry-contracts": "0.0.0",
67
+ "@ainyc/canonry-integration-cloud-run": "0.0.0",
69
68
  "@ainyc/canonry-integration-commoncrawl": "0.0.0",
70
69
  "@ainyc/canonry-integration-google": "0.0.0",
71
- "@ainyc/canonry-integration-traffic": "0.0.0",
72
70
  "@ainyc/canonry-integration-wordpress": "0.0.0",
73
71
  "@ainyc/canonry-provider-cdp": "0.0.0",
72
+ "@ainyc/canonry-integration-traffic": "0.0.0",
74
73
  "@ainyc/canonry-provider-claude": "0.0.0",
75
- "@ainyc/canonry-provider-gemini": "0.0.0",
76
- "@ainyc/canonry-provider-local": "0.0.0",
74
+ "@ainyc/canonry-integration-bing": "0.0.0",
77
75
  "@ainyc/canonry-provider-openai": "0.0.0",
76
+ "@ainyc/canonry-provider-local": "0.0.0",
77
+ "@ainyc/canonry-provider-gemini": "0.0.0",
78
78
  "@ainyc/canonry-provider-perplexity": "0.0.0"
79
79
  },
80
80
  "scripts": {