@canonry/canonry 4.148.3 → 4.148.4

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.
@@ -289,6 +289,7 @@ import {
289
289
  internalError,
290
290
  isBrowserProvider,
291
291
  isReadOnlyKey,
292
+ isRetryableHttpError,
292
293
  isVertexGroundingRedirect,
293
294
  isoDateDaysBeforeInTimeZone,
294
295
  keywordDtoSchema,
@@ -449,6 +450,7 @@ import {
449
450
  resolveMeasurementRunScope,
450
451
  resolveSnapshotRequestQueries,
451
452
  resultsExportDtoSchema,
453
+ retryAfterDelayMs,
452
454
  runDetailDtoSchema,
453
455
  runDtoSchema,
454
456
  runInProgress,
@@ -517,7 +519,7 @@ import {
517
519
  wordpressSchemaDeployResultDtoSchema,
518
520
  wordpressSchemaStatusResultDtoSchema,
519
521
  wordpressStatusDtoSchema
520
- } from "./chunk-3VMKOSTQ.js";
522
+ } from "./chunk-UOYZDJOE.js";
521
523
 
522
524
  // src/intelligence-service.ts
523
525
  import { eq as eq57, desc as desc26, asc as asc11, and as and45, ne as ne7, or as or11, inArray as inArray19, gte as gte13, lte as lte10 } from "drizzle-orm";
@@ -41685,14 +41687,28 @@ var BING_WMT_API_BASE = "https://ssl.bing.com/webmaster/api.svc/json";
41685
41687
  var BING_SUBMIT_URL_BATCH_LIMIT = 500;
41686
41688
  var BING_SUBMIT_URL_DAILY_LIMIT = 1e4;
41687
41689
  var BING_REQUEST_TIMEOUT_MS = 3e4;
41690
+ var BING_MAX_RETRIES = 4;
41691
+ var BING_RETRY_BASE_DELAY_MS = 2e3;
41692
+ var BING_RETRY_MAX_DELAY_MS = 3e4;
41688
41693
 
41689
41694
  // ../integration-bing/src/types.ts
41695
+ var BING_THROTTLE_ERROR_CODES = /* @__PURE__ */ new Set([4, 5]);
41690
41696
  var BingApiError = class extends Error {
41691
41697
  status;
41692
- constructor(message, status) {
41698
+ /** Bing's own `ErrorCode` from the response body, when it sent one. */
41699
+ bingErrorCode;
41700
+ /**
41701
+ * True when Bing was throttling. Kept as a field rather than re-derived from
41702
+ * the message so `isRetryableHttpError` sees the condition structurally and
41703
+ * callers do not have to parse prose.
41704
+ */
41705
+ isThrottle;
41706
+ constructor(message, status, bingErrorCode = null) {
41693
41707
  super(message);
41694
41708
  this.name = "BingApiError";
41695
41709
  this.status = status;
41710
+ this.bingErrorCode = bingErrorCode;
41711
+ this.isThrottle = status === 429 || bingErrorCode != null && BING_THROTTLE_ERROR_CODES.has(bingErrorCode);
41696
41712
  }
41697
41713
  };
41698
41714
 
@@ -41752,7 +41768,19 @@ function bingClientLog(level, action, ctx) {
41752
41768
  function escapeRegExp4(str) {
41753
41769
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
41754
41770
  }
41755
- async function bingFetch(apiKey, endpoint, opts) {
41771
+ function parseBingErrorCode(body) {
41772
+ try {
41773
+ const parsed = JSON.parse(body);
41774
+ const root = parsed != null && typeof parsed === "object" && "d" in parsed ? parsed.d : parsed;
41775
+ if (root != null && typeof root === "object" && "ErrorCode" in root) {
41776
+ const code = root.ErrorCode;
41777
+ if (typeof code === "number") return code;
41778
+ }
41779
+ } catch {
41780
+ }
41781
+ return null;
41782
+ }
41783
+ async function bingFetchOnce(apiKey, endpoint, opts) {
41756
41784
  const method = opts?.method ?? "GET";
41757
41785
  const separator = endpoint.includes("?") ? "&" : "?";
41758
41786
  const url = `${BING_WMT_API_BASE}/${endpoint}${separator}apikey=${encodeURIComponent(apiKey)}`;
@@ -41775,10 +41803,17 @@ async function bingFetch(apiKey, endpoint, opts) {
41775
41803
  }
41776
41804
  if (!res.ok) {
41777
41805
  const body = await res.text();
41778
- bingClientLog("error", "http.error", { endpoint, method, httpStatus: res.status });
41779
41806
  let detail = body.length <= 500 ? body : `${body.slice(0, 500)}... [truncated]`;
41780
41807
  detail = detail.replace(new RegExp(escapeRegExp4(apiKey), "g"), "***");
41781
- throw new BingApiError(`Bing API error (${res.status}): ${detail}`, res.status);
41808
+ const bingErrorCode = parseBingErrorCode(body);
41809
+ const err = new BingApiError(`Bing API error (${res.status}): ${detail}`, res.status, bingErrorCode);
41810
+ bingClientLog("error", err.isThrottle ? "http.throttled" : "http.error", {
41811
+ endpoint,
41812
+ method,
41813
+ httpStatus: res.status,
41814
+ bingErrorCode
41815
+ });
41816
+ throw err;
41782
41817
  }
41783
41818
  const text2 = await res.text();
41784
41819
  if (!text2 || text2.trim() === "") {
@@ -41794,6 +41829,27 @@ async function bingFetch(apiKey, endpoint, opts) {
41794
41829
  throw new BingApiError("Bing API returned invalid JSON", 502);
41795
41830
  }
41796
41831
  }
41832
+ async function bingFetch(apiKey, endpoint, opts) {
41833
+ const isIdempotent = (opts?.method ?? "GET") === "GET";
41834
+ return withRetry(() => bingFetchOnce(apiKey, endpoint, opts), {
41835
+ maxRetries: BING_MAX_RETRIES,
41836
+ baseDelayMs: BING_RETRY_BASE_DELAY_MS,
41837
+ maxDelayMs: BING_RETRY_MAX_DELAY_MS,
41838
+ isRetryable: (err) => {
41839
+ if (err instanceof BingApiError && err.isThrottle) return true;
41840
+ return isIdempotent && isRetryableHttpError(err);
41841
+ },
41842
+ computeDelayMs: (_attempt, err, defaultMs) => retryAfterDelayMs(err) ?? defaultMs,
41843
+ onRetry: ({ attempt, err, delayMs }) => {
41844
+ bingClientLog("warn", "http.retry", {
41845
+ endpoint,
41846
+ attempt,
41847
+ delayMs: Math.round(delayMs),
41848
+ throttled: err instanceof BingApiError ? err.isThrottle : false
41849
+ });
41850
+ }
41851
+ });
41852
+ }
41797
41853
  async function getSites(apiKey) {
41798
41854
  validateApiKey(apiKey);
41799
41855
  const data = await bingFetch(apiKey, "GetUserSites");
@@ -10,7 +10,7 @@ import {
10
10
  loadConfig,
11
11
  loadConfigRaw,
12
12
  saveConfigPatch
13
- } from "./chunk-NIKDPQOF.js";
13
+ } from "./chunk-IGPUEHUD.js";
14
14
  import {
15
15
  CC_CACHE_DIR,
16
16
  DUCKDB_SPEC,
@@ -126,7 +126,7 @@ import {
126
126
  siteAuditSnapshots,
127
127
  toAlertView,
128
128
  usageCounters
129
- } from "./chunk-ILUVQDXM.js";
129
+ } from "./chunk-AJOOL3D3.js";
130
130
  import {
131
131
  AGENT_MEMORY_VALUE_MAX_BYTES,
132
132
  AGENT_PROVIDER_IDS,
@@ -217,7 +217,7 @@ import {
217
217
  validationError,
218
218
  winnabilityClassLabel,
219
219
  withRetry
220
- } from "./chunk-3VMKOSTQ.js";
220
+ } from "./chunk-UOYZDJOE.js";
221
221
 
222
222
  // src/telemetry.ts
223
223
  import crypto from "crypto";
@@ -7420,7 +7420,7 @@ function readStoredGroundingSources(rawResponse) {
7420
7420
  return result;
7421
7421
  }
7422
7422
  async function backfillInsightsCommand(project, opts) {
7423
- const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-CEYWNR6W.js");
7423
+ const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-S5PQT5GP.js");
7424
7424
  const config = loadConfig();
7425
7425
  const db = createClient(config.database);
7426
7426
  migrate(db);
@@ -81,7 +81,7 @@ import {
81
81
  trafficConnectWordpressRequestSchema,
82
82
  trafficEventKindSchema,
83
83
  trafficSeriesGranularitySchema
84
- } from "./chunk-3VMKOSTQ.js";
84
+ } from "./chunk-UOYZDJOE.js";
85
85
 
86
86
  // src/config.ts
87
87
  import fs from "fs";
@@ -7893,6 +7893,19 @@ async function withRetry(fn, opts = {}) {
7893
7893
  }
7894
7894
  throw lastErr;
7895
7895
  }
7896
+ function retryAfterDelayMs(err, now = Date.now()) {
7897
+ if (err == null || typeof err !== "object") return null;
7898
+ const record = err;
7899
+ const raw = record.retryAfter ?? record["retry-after"];
7900
+ if (typeof raw === "number") return Number.isFinite(raw) ? Math.max(0, raw * 1e3) : null;
7901
+ if (typeof raw !== "string") return null;
7902
+ const trimmed = raw.trim();
7903
+ if (trimmed === "") return null;
7904
+ if (/^\d+$/.test(trimmed)) return Number(trimmed) * 1e3;
7905
+ const at = Date.parse(trimmed);
7906
+ if (Number.isNaN(at)) return null;
7907
+ return Math.max(0, at - now);
7908
+ }
7896
7909
  var RATE_LIMIT_MARKERS = [
7897
7910
  "throttle",
7898
7911
  // Bing Webmaster Tools: ThrottleHost / ThrottleUser
@@ -13982,6 +13995,7 @@ export {
13982
13995
  gbpSummaryDtoSchema,
13983
13996
  formatGbpMetricLabel,
13984
13997
  withRetry,
13998
+ retryAfterDelayMs,
13985
13999
  isRetryableHttpError,
13986
14000
  mapWithConcurrency,
13987
14001
  bingUrlInspectionDtoSchema,
package/dist/cli.js CHANGED
@@ -30,7 +30,7 @@ import {
30
30
  showFirstRunNotice,
31
31
  trackCliCommandFinished,
32
32
  trackEvent
33
- } from "./chunk-GUKRQT22.js";
33
+ } from "./chunk-CQBXLHT4.js";
34
34
  import {
35
35
  CliError,
36
36
  EXIT_SYSTEM_ERROR,
@@ -50,7 +50,7 @@ import {
50
50
  saveConfigPatch,
51
51
  systemError,
52
52
  usageError
53
- } from "./chunk-NIKDPQOF.js";
53
+ } from "./chunk-IGPUEHUD.js";
54
54
  import {
55
55
  apiKeys,
56
56
  createClient,
@@ -58,7 +58,7 @@ import {
58
58
  projects,
59
59
  queries,
60
60
  renderReportHtml
61
- } from "./chunk-ILUVQDXM.js";
61
+ } from "./chunk-AJOOL3D3.js";
62
62
  import {
63
63
  AdsDeliverySnapshotStatuses,
64
64
  AdsHistoricalCampaignRollupStatuses,
@@ -122,7 +122,7 @@ import {
122
122
  providerQuotaPolicySchema,
123
123
  resolveProviderInput,
124
124
  winnabilityClassSchema
125
- } from "./chunk-3VMKOSTQ.js";
125
+ } from "./chunk-UOYZDJOE.js";
126
126
 
127
127
  // src/cli.ts
128
128
  import { pathToFileURL } from "url";
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  createServer
3
- } from "./chunk-GUKRQT22.js";
3
+ } from "./chunk-CQBXLHT4.js";
4
4
  import {
5
5
  loadConfig
6
- } from "./chunk-NIKDPQOF.js";
7
- import "./chunk-ILUVQDXM.js";
8
- import "./chunk-3VMKOSTQ.js";
6
+ } from "./chunk-IGPUEHUD.js";
7
+ import "./chunk-AJOOL3D3.js";
8
+ import "./chunk-UOYZDJOE.js";
9
9
  export {
10
10
  createServer,
11
11
  loadConfig
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  IntelligenceService
3
- } from "./chunk-ILUVQDXM.js";
4
- import "./chunk-3VMKOSTQ.js";
3
+ } from "./chunk-AJOOL3D3.js";
4
+ import "./chunk-UOYZDJOE.js";
5
5
  export {
6
6
  IntelligenceService
7
7
  };
package/dist/mcp.js CHANGED
@@ -3,10 +3,10 @@ import {
3
3
  PACKAGE_VERSION,
4
4
  canonryMcpTools,
5
5
  createApiClient
6
- } from "./chunk-NIKDPQOF.js";
6
+ } from "./chunk-IGPUEHUD.js";
7
7
  import {
8
8
  isReadOnlyKey
9
- } from "./chunk-3VMKOSTQ.js";
9
+ } from "./chunk-UOYZDJOE.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": "@canonry/canonry",
3
- "version": "4.148.3",
3
+ "version": "4.148.4",
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",
@@ -69,8 +69,8 @@
69
69
  "@ainyc/canonry-api-client": "0.0.0",
70
70
  "@ainyc/canonry-api-routes": "0.0.0",
71
71
  "@ainyc/canonry-config": "0.0.0",
72
- "@ainyc/canonry-db": "0.0.0",
73
72
  "@ainyc/canonry-contracts": "0.0.0",
73
+ "@ainyc/canonry-db": "0.0.0",
74
74
  "@ainyc/canonry-integration-openai-ads": "0.0.0",
75
75
  "@ainyc/canonry-integration-bing": "0.0.0",
76
76
  "@ainyc/canonry-integration-cloud-run": "0.0.0",
@@ -78,15 +78,15 @@
78
78
  "@ainyc/canonry-integration-google": "0.0.0",
79
79
  "@ainyc/canonry-integration-google-business-profile": "0.0.0",
80
80
  "@ainyc/canonry-integration-google-places": "0.0.0",
81
- "@ainyc/canonry-integration-wordpress": "0.0.0",
82
81
  "@ainyc/canonry-integration-traffic": "0.0.0",
82
+ "@ainyc/canonry-integration-wordpress": "0.0.0",
83
83
  "@ainyc/canonry-intelligence": "0.0.0",
84
- "@ainyc/canonry-provider-cdp": "0.0.0",
85
- "@ainyc/canonry-provider-claude": "0.0.0",
86
84
  "@ainyc/canonry-provider-gemini": "0.0.0",
85
+ "@ainyc/canonry-provider-claude": "0.0.0",
87
86
  "@ainyc/canonry-provider-openai": "0.0.0",
87
+ "@ainyc/canonry-provider-perplexity": "0.0.0",
88
88
  "@ainyc/canonry-provider-local": "0.0.0",
89
- "@ainyc/canonry-provider-perplexity": "0.0.0"
89
+ "@ainyc/canonry-provider-cdp": "0.0.0"
90
90
  },
91
91
  "scripts": {
92
92
  "build": "tsx scripts/copy-agent-assets.ts && tsup && tsx build-web.ts",