@canonry/canonry 7.58.4 → 7.58.5

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.
@@ -918,16 +918,24 @@ Cloudflare to redeliver after the visibility timeout.
918
918
 
919
919
  The source lease rejects concurrent scheduler and operator drains. A stale
920
920
  lease can be recovered after its expiry, and only its owner can release it.
921
- Receipts remain for Cloudflare's current 14-day platform maximum plus a replay
922
- margin. This stays safe even when the locally recorded retention is stale or
923
- lower than the Queue's actual setting.
924
-
925
- Each default Queue sync drains at most 10 batches of 100 messages: **1,000
926
- messages per tick**. Doctor reports a residual of 1–1,000 messages as within
927
- that budget. If no new messages arrive, the next scheduled sync can clear it.
928
- Doctor warns when more than 1,000 messages remain because one default tick
929
- cannot drain the residual. Run a manual sync to accelerate the drain. If the
930
- backlog remains above 1,000, shorten the `traffic-sync` schedule interval.
921
+ Each sync reads the Queue's live message retention from Cloudflare and keeps
922
+ receipts for that long plus a 10-minute replay margin, since a message can only
923
+ be redelivered while it is retained. When the retention goes up, live receipts
924
+ are extended to it; when it goes down, new receipts never expire before the
925
+ newest receipt from the longer retention. If the read fails or returns no
926
+ usable value, receipts keep Cloudflare's 14-day maximum plus the margin.
927
+
928
+ Each Queue sync drains in batches of up to 100 messages for as long as
929
+ Cloudflare reports a backlog, up to a 4-minute time limit per sync
930
+ (`CANONRY_CLOUDFLARE_QUEUE_SYNC_DEADLINE_MS`, 30 seconds to 15 minutes) and a
931
+ 300-pull safety cap. Cloudflare can return a partial or briefly empty batch
932
+ while a backlog waits, so a sync stops only when Cloudflare reports no backlog,
933
+ two pulls in a row come back empty, or the limit is reached. If a pull fails
934
+ after earlier batches were saved, the run ends `partial` and keeps them.
935
+ Doctor treats a residual of up to 1,000 messages as normal (they arrived during
936
+ the drain) and warns above that: the drain hit its limit before the Queue was
937
+ empty. Shorten the `traffic-sync` interval or raise the time limit, or messages
938
+ will pass the Queue's retention and be dropped.
931
939
 
932
940
  ## Syncing data
933
941
 
@@ -1074,9 +1082,9 @@ schedule. Recurring syncs are safe because of the adapter's overlap ring or
1074
1082
  durable Queue receipts.
1075
1083
 
1076
1084
  Keep the auto-created 30-minute schedule for Queue pull. The Worker sends one
1077
- selected event in each Queue message. At its 1,000-message limit, this cadence
1078
- drains about 0.56 selected events per second. If the Queue backlog remains
1079
- above 1,000, run a manual sync. Then shorten the interval:
1085
+ selected event in each Queue message, and each sync drains for up to 4 minutes.
1086
+ If doctor reports more than 1,000 messages remaining after syncs, shorten the
1087
+ interval:
1080
1088
 
1081
1089
  ```bash
1082
1090
  cnry schedule set <project> --kind traffic-sync \
@@ -10,7 +10,7 @@ import {
10
10
  backfillSnapshotAttributionCommand,
11
11
  backfillTrafficClassificationCommand,
12
12
  replayQueryAuditLog
13
- } from "./chunk-RXMGU7AF.js";
13
+ } from "./chunk-O6TF6TPM.js";
14
14
  import "./chunk-BP5OKJIC.js";
15
15
  import "./chunk-TVANRUBO.js";
16
16
  import "./chunk-HGMYEDAQ.js";
@@ -18,7 +18,7 @@ import "./chunk-L7TKNHEX.js";
18
18
  import {
19
19
  backfillProjectAnswerMentions,
20
20
  backfillProjectAnswerMentionsInChunks
21
- } from "./chunk-NWQQYLZV.js";
21
+ } from "./chunk-QEJBAPDP.js";
22
22
  import "./chunk-Q4J3XSWE.js";
23
23
  import "./chunk-27SGL3DF.js";
24
24
  import "./chunk-SCS7R2ND.js";
@@ -5,7 +5,7 @@ import {
5
5
  isStoredPageReadTool,
6
6
  isStoredReadTool,
7
7
  truncateToolResult
8
- } from "./chunk-QFO7JHX2.js";
8
+ } from "./chunk-A5F5E4DL.js";
9
9
  import {
10
10
  CANONRY_MCP_TOOLKITS
11
11
  } from "./chunk-NCIPNVD6.js";
@@ -14,7 +14,7 @@ import {
14
14
  mergeGscQueryTotalsWithFallback,
15
15
  readGscQueryDailyRows,
16
16
  readLatestGscDataDate
17
- } from "./chunk-NWQQYLZV.js";
17
+ } from "./chunk-QEJBAPDP.js";
18
18
  import {
19
19
  getRequestContext
20
20
  } from "./chunk-27SGL3DF.js";
@@ -10,7 +10,7 @@ import {
10
10
  } from "./chunk-HGMYEDAQ.js";
11
11
  import {
12
12
  buildOpenApiDocument
13
- } from "./chunk-NWQQYLZV.js";
13
+ } from "./chunk-QEJBAPDP.js";
14
14
  import {
15
15
  DEFAULT_COMPETITOR_AUTO_ALIAS_MODE,
16
16
  MeasurementPortfolioLists,
@@ -599,7 +599,7 @@ var DEMO_CLI_COMMANDS = [{
599
599
  options: { host: stringOption(), port: stringOption(), "trust-proxy": multiStringOption() },
600
600
  allowPositionals: false,
601
601
  run: async (input) => {
602
- const { demoCommand } = await import("./demo-F5TRWB6V.js");
602
+ const { demoCommand } = await import("./demo-ZBNVULOO.js");
603
603
  await demoCommand({
604
604
  host: getString(input.values, "host"),
605
605
  port: getString(input.values, "port"),
@@ -620,7 +620,7 @@ var BACKFILL_CLI_COMMANDS = [
620
620
  allowPositionals: false,
621
621
  supportsDryRun: true,
622
622
  run: async (input) => {
623
- const { backfillAnswerVisibilityCommand } = await import("./backfill-JAHDHVXJ.js");
623
+ const { backfillAnswerVisibilityCommand } = await import("./backfill-SINDWLD3.js");
624
624
  await backfillAnswerVisibilityCommand({
625
625
  project: getString(input.values, "project"),
626
626
  dryRun: input.dryRun,
@@ -637,7 +637,7 @@ var BACKFILL_CLI_COMMANDS = [
637
637
  allowPositionals: false,
638
638
  supportsDryRun: true,
639
639
  run: async (input) => {
640
- const { backfillAnswerMentionsCommand } = await import("./backfill-JAHDHVXJ.js");
640
+ const { backfillAnswerMentionsCommand } = await import("./backfill-SINDWLD3.js");
641
641
  await backfillAnswerMentionsCommand({
642
642
  project: getString(input.values, "project"),
643
643
  dryRun: input.dryRun,
@@ -655,7 +655,7 @@ var BACKFILL_CLI_COMMANDS = [
655
655
  },
656
656
  supportsDryRun: true,
657
657
  run: async (input) => {
658
- const { backfillInsightsCommand } = await import("./backfill-JAHDHVXJ.js");
658
+ const { backfillInsightsCommand } = await import("./backfill-SINDWLD3.js");
659
659
  const usage = "canonry backfill insights <project> [--from-run <id>] [--to-run <id>] [--since <date>] [--dry-run] [--format json]";
660
660
  const project3 = requireProject(input, "backfill insights", usage);
661
661
  await backfillInsightsCommand(project3, {
@@ -675,7 +675,7 @@ var BACKFILL_CLI_COMMANDS = [
675
675
  },
676
676
  allowPositionals: false,
677
677
  run: async (input) => {
678
- const { backfillNormalizedPathsCommand } = await import("./backfill-JAHDHVXJ.js");
678
+ const { backfillNormalizedPathsCommand } = await import("./backfill-SINDWLD3.js");
679
679
  await backfillNormalizedPathsCommand({
680
680
  project: getString(input.values, "project"),
681
681
  format: input.format
@@ -690,7 +690,7 @@ var BACKFILL_CLI_COMMANDS = [
690
690
  },
691
691
  allowPositionals: false,
692
692
  run: async (input) => {
693
- const { backfillAiReferralPathsCommand } = await import("./backfill-JAHDHVXJ.js");
693
+ const { backfillAiReferralPathsCommand } = await import("./backfill-SINDWLD3.js");
694
694
  await backfillAiReferralPathsCommand({
695
695
  project: getString(input.values, "project"),
696
696
  format: input.format
@@ -702,7 +702,7 @@ var BACKFILL_CLI_COMMANDS = [
702
702
  usage: "canonry backfill snapshot-attribution <project> [--dry-run] [--format json]",
703
703
  supportsDryRun: true,
704
704
  run: async (input) => {
705
- const { backfillSnapshotAttributionCommand } = await import("./backfill-JAHDHVXJ.js");
705
+ const { backfillSnapshotAttributionCommand } = await import("./backfill-SINDWLD3.js");
706
706
  const usage = "canonry backfill snapshot-attribution <project> [--dry-run] [--format json]";
707
707
  const project3 = requireProject(input, "backfill snapshot-attribution", usage);
708
708
  await backfillSnapshotAttributionCommand({
@@ -721,7 +721,7 @@ var BACKFILL_CLI_COMMANDS = [
721
721
  allowPositionals: false,
722
722
  supportsDryRun: true,
723
723
  run: async (input) => {
724
- const { backfillTrafficClassificationCommand } = await import("./backfill-JAHDHVXJ.js");
724
+ const { backfillTrafficClassificationCommand } = await import("./backfill-SINDWLD3.js");
725
725
  await backfillTrafficClassificationCommand({
726
726
  project: getString(input.values, "project"),
727
727
  dryRun: input.dryRun,
@@ -1163,7 +1163,7 @@ var DASHBOARD_CLI_COMMANDS = [
1163
1163
  usage: "canonry dashboard reset-password [--format json]",
1164
1164
  help: "Clears the dashboard password from config.yaml, so the dashboard asks for a new one after a restart.\nLocal only: it edits the config file under CANONRY_CONFIG_DIR and does not call the server.",
1165
1165
  run: async (input) => {
1166
- const { resetDashboardPassword } = await import("./dashboard-2P3TEH6S.js");
1166
+ const { resetDashboardPassword } = await import("./dashboard-VT3GQRW4.js");
1167
1167
  await resetDashboardPassword({ format: input.format });
1168
1168
  }
1169
1169
  },
@@ -6615,7 +6615,7 @@ var SYSTEM_CLI_COMMANDS = [
6615
6615
  options: { access: stringOption() },
6616
6616
  run: async (input) => {
6617
6617
  if (input.positionals.length > 1) throw usageError("Expected at most one command group");
6618
- const [{ printCliCatalog }, { REGISTERED_CLI_COMMANDS: REGISTERED_CLI_COMMANDS2 }] = await Promise.all([import("./cli-catalog-PJYR3JHX.js"), import("./cli-commands-JBLV55EA.js")]);
6618
+ const [{ printCliCatalog }, { REGISTERED_CLI_COMMANDS: REGISTERED_CLI_COMMANDS2 }] = await Promise.all([import("./cli-catalog-PJYR3JHX.js"), import("./cli-commands-ZPW3OST3.js")]);
6619
6619
  printCliCatalog(REGISTERED_CLI_COMMANDS2, input.format, input.positionals[0], getString(input.values, "access"));
6620
6620
  }
6621
6621
  },
@@ -6664,7 +6664,7 @@ var SYSTEM_CLI_COMMANDS = [
6664
6664
  },
6665
6665
  allowPositionals: false,
6666
6666
  run: async (input) => {
6667
- const { initCommand } = await import("./init-LABWY7HI.js");
6667
+ const { initCommand } = await import("./init-C2DLDK6T.js");
6668
6668
  await initCommand({
6669
6669
  force: getBoolean(input.values, "force"),
6670
6670
  ref: getString(input.values, "ref"),
@@ -6719,7 +6719,7 @@ var SYSTEM_CLI_COMMANDS = [
6719
6719
  allowPositionals: false,
6720
6720
  run: async (input) => {
6721
6721
  applyServerEnv(input.values);
6722
- const { serveCommand } = await import("./serve-3WJL5N2Z.js");
6722
+ const { serveCommand } = await import("./serve-ME2KJ6BG.js");
6723
6723
  await serveCommand(input.format);
6724
6724
  }
6725
6725
  },
@@ -8027,8 +8027,8 @@ var AGENT_CLI_COMMANDS = [
8027
8027
  "timeout-ms": stringOption()
8028
8028
  },
8029
8029
  run: async (input) => {
8030
- const { coerceAgentProvider } = await import("./session-VTFLD3C5.js");
8031
- const { AERO_TOOL_PROFILES, isAeroToolProfile } = await import("./tools-LRHO7QOT.js");
8030
+ const { coerceAgentProvider } = await import("./session-R3PRJ3RB.js");
8031
+ const { AERO_TOOL_PROFILES, isAeroToolProfile } = await import("./tools-VZVQ2CTU.js");
8032
8032
  const { agentAsk } = await import("./agent-ask-XG7WQBX6.js");
8033
8033
  const usage = `canonry agent ask <project> "<prompt>" [--provider ${AGENT_PROVIDER_IDS.join("|")}] [--model <id>] [--scope all|read-only] [--profile default|ads-operator] [--context <json>] [--conversation <id>] [--max-tool-calls <n>] [--timeout-ms <ms>] [--format json]`;
8034
8034
  const project3 = requireProject(input, "agent.ask", usage);
@@ -27,14 +27,14 @@ import {
27
27
  resolveConfiguredAgentProvider,
28
28
  resolveSessionProviderAndModel,
29
29
  setAeroSystemPrompt
30
- } from "./chunk-2DZYA62C.js";
30
+ } from "./chunk-5D4RL23M.js";
31
31
  import {
32
32
  AeroToolProfiles,
33
33
  AeroToolScopes,
34
34
  buildAeroStateTools,
35
35
  isAeroToolProfile,
36
36
  truncateToolResult
37
- } from "./chunk-QFO7JHX2.js";
37
+ } from "./chunk-A5F5E4DL.js";
38
38
  import {
39
39
  getGoogleAuthConfig,
40
40
  getGoogleConnection,
@@ -162,7 +162,7 @@ import {
162
162
  addLogListener,
163
163
  createFastifyLogger,
164
164
  createLogger
165
- } from "./chunk-NMLVLFF7.js";
165
+ } from "./chunk-65YQFVJM.js";
166
166
  import {
167
167
  computeCitedCompetitorDomains,
168
168
  determineCitationState
@@ -265,6 +265,7 @@ import {
265
265
  registerOAuthAdminRoutes,
266
266
  registerOAuthRoutes,
267
267
  requireInstanceAdministrator,
268
+ resolveCloudflareQueueSyncDeadlineMs,
268
269
  resolveDestination,
269
270
  resolveMeasurementSitemapTarget,
270
271
  resolveTrustProxy,
@@ -284,7 +285,7 @@ import {
284
285
  webhookResponseReason,
285
286
  webhookTargetRefusalReason,
286
287
  writeAuditLog
287
- } from "./chunk-NWQQYLZV.js";
288
+ } from "./chunk-QEJBAPDP.js";
288
289
  import {
289
290
  OperationalLogStore,
290
291
  SentimentIdempotencyConflict,
@@ -5656,7 +5657,7 @@ function nonBlank(value) {
5656
5657
  return trimmed ? trimmed : void 0;
5657
5658
  }
5658
5659
  function resolveBuildCommit(env = process.env) {
5659
- const embedded = true ? "defc4dd5f82b7402ab8fc0b78cd5ac850deb3e35" : void 0;
5660
+ const embedded = true ? "9a896bfe2e40ca556ac3d4d8e35a39ad0f9060f5" : void 0;
5660
5661
  return nonBlank(embedded) ?? nonBlank(env.CANONRY_COMMIT);
5661
5662
  }
5662
5663
  function resolveInstanceIdentity(env = process.env) {
@@ -20519,6 +20520,7 @@ async function createServer(opts) {
20519
20520
  // was previously reachable only from tests, so a source losing ground could
20520
20521
  // not be rescued without shipping code. Unset keeps the built-in default.
20521
20522
  vercelSyncDeadlineMs: resolveVercelSyncDeadlineMs(process.env),
20523
+ cloudflareQueueSyncDeadlineMs: resolveCloudflareQueueSyncDeadlineMs(process.env),
20522
20524
  researchAllowViewers,
20523
20525
  researchViewerDailyRunLimit,
20524
20526
  // Local-only Aero agent routes. Registered here so they inherit api-routes'
@@ -47,7 +47,7 @@ function queueServeHandoff() {
47
47
  async function runPendingServeHandoff(format) {
48
48
  if (!pendingServeHandoff) return;
49
49
  pendingServeHandoff = false;
50
- const { serveCommand } = await import("./serve-3WJL5N2Z.js");
50
+ const { serveCommand } = await import("./serve-ME2KJ6BG.js");
51
51
  await serveCommand(format);
52
52
  }
53
53
 
@@ -23,7 +23,7 @@ import {
23
23
  createRunCompetitorResolver,
24
24
  readMarketCompetitorNames,
25
25
  refreshSnapshotMentionIdentity
26
- } from "./chunk-NWQQYLZV.js";
26
+ } from "./chunk-QEJBAPDP.js";
27
27
  import {
28
28
  classifyAiUserFetch,
29
29
  classifyCrawler
@@ -437,7 +437,7 @@ No DB writes performed. Re-run without --dry-run to apply.`);
437
437
  }
438
438
  }
439
439
  async function backfillInsightsCommand(project, opts) {
440
- const { IntelligenceService } = await import("./intelligence-service-4PHEK5F4.js");
440
+ const { IntelligenceService } = await import("./intelligence-service-R5BRSQKI.js");
441
441
  const config = loadConfig();
442
442
  const db = createClient(config.database);
443
443
  migrate(db);
@@ -59714,7 +59714,7 @@ async function backlinksRoutes(app, opts) {
59714
59714
  import crypto51 from "crypto";
59715
59715
  import { isIP } from "net";
59716
59716
  import { isDeepStrictEqual } from "util";
59717
- import { and as and68, desc as desc38, eq as eq79, gte as gte18, inArray as inArray33, lte as lte19, sql as sql29 } from "drizzle-orm";
59717
+ import { and as and68, desc as desc38, eq as eq79, gt as gt6, gte as gte18, inArray as inArray33, lt as lt12, lte as lte19, sql as sql29 } from "drizzle-orm";
59718
59718
 
59719
59719
  // ../api-routes/src/cloudflare-worker-version.ts
59720
59720
  var CURRENT_CLOUDFLARE_WORKER_VERSION = "1.0.1";
@@ -59723,8 +59723,9 @@ var CURRENT_CLOUDFLARE_WORKER_VERSION = "1.0.1";
59723
59723
  var VERCEL_MAX_SYNC_WINDOW_MS = 24 * 60 * 6e4;
59724
59724
  var DEFAULT_VERCEL_SYNC_DEADLINE_MS = 4 * 6e4;
59725
59725
  var CLOUDFLARE_QUEUE_BATCH_SIZE = 100;
59726
- var DEFAULT_CLOUDFLARE_QUEUE_MAX_BATCHES = 10;
59727
- var DEFAULT_CLOUDFLARE_QUEUE_DRAIN_BUDGET = CLOUDFLARE_QUEUE_BATCH_SIZE * DEFAULT_CLOUDFLARE_QUEUE_MAX_BATCHES;
59726
+ var DEFAULT_CLOUDFLARE_QUEUE_SYNC_DEADLINE_MS = 4 * 6e4;
59727
+ var DEFAULT_CLOUDFLARE_QUEUE_MAX_BATCHES = 300;
59728
+ var CLOUDFLARE_QUEUE_RESIDUAL_WARN_COUNT = 1e3;
59728
59729
  var MIN_VERCEL_SYNC_DEADLINE_MS = 3e4;
59729
59730
  var MAX_VERCEL_SYNC_DEADLINE_MS = 15 * 6e4;
59730
59731
  var TRAFFIC_SOURCE_MAX_CATCHUP_MS = {
@@ -59737,6 +59738,13 @@ function resolveVercelSyncDeadlineMs(env = process.env) {
59737
59738
  if (!Number.isFinite(parsed) || parsed <= 0) return void 0;
59738
59739
  return Math.min(MAX_VERCEL_SYNC_DEADLINE_MS, Math.max(MIN_VERCEL_SYNC_DEADLINE_MS, Math.trunc(parsed)));
59739
59740
  }
59741
+ function resolveCloudflareQueueSyncDeadlineMs(env = process.env) {
59742
+ const raw = env.CANONRY_CLOUDFLARE_QUEUE_SYNC_DEADLINE_MS;
59743
+ if (raw === void 0 || raw.trim() === "") return void 0;
59744
+ const parsed = Number(raw);
59745
+ if (!Number.isFinite(parsed) || parsed <= 0) return void 0;
59746
+ return Math.min(MAX_VERCEL_SYNC_DEADLINE_MS, Math.max(MIN_VERCEL_SYNC_DEADLINE_MS, Math.trunc(parsed)));
59747
+ }
59740
59748
 
59741
59749
  // ../integration-cloud-run/src/auth.ts
59742
59750
  import crypto49 from "crypto";
@@ -60723,8 +60731,11 @@ function resolveOptions(options) {
60723
60731
  sleep: options.sleep
60724
60732
  };
60725
60733
  }
60734
+ function queueUrl(options) {
60735
+ return `${options.apiBaseUrl}/accounts/${encodeURIComponent(options.accountId)}/queues/${encodeURIComponent(options.queueId)}`;
60736
+ }
60726
60737
  function queueMessagesUrl(options, action) {
60727
- return `${options.apiBaseUrl}/accounts/${encodeURIComponent(options.accountId)}/queues/${encodeURIComponent(options.queueId)}/messages/${action}`;
60738
+ return `${queueUrl(options)}/messages/${action}`;
60728
60739
  }
60729
60740
  function requestSignal(timeoutMs, signal) {
60730
60741
  const timeout = AbortSignal.timeout(timeoutMs);
@@ -60768,16 +60779,20 @@ async function withQueueRetry(attempt, options) {
60768
60779
  throw lastError;
60769
60780
  }
60770
60781
  async function postJson(options, action, body, signal) {
60782
+ return requestJson(options, { method: "POST", url: queueMessagesUrl(options, action), label: action, body }, signal);
60783
+ }
60784
+ async function requestJson(options, request, signal) {
60785
+ const { label: action } = request;
60771
60786
  return withQueueRetry(async () => {
60772
60787
  let response;
60773
60788
  try {
60774
- response = await options.fetchImpl(queueMessagesUrl(options, action), {
60775
- method: "POST",
60789
+ response = await options.fetchImpl(request.url, {
60790
+ method: request.method,
60776
60791
  headers: {
60777
60792
  Authorization: `Bearer ${options.apiToken}`,
60778
- "Content-Type": "application/json"
60793
+ ...request.body ? { "Content-Type": "application/json" } : {}
60779
60794
  },
60780
- body: JSON.stringify(body),
60795
+ ...request.body ? { body: JSON.stringify(request.body) } : {},
60781
60796
  signal: requestSignal(options.timeoutMs, signal)
60782
60797
  });
60783
60798
  } catch (error) {
@@ -60795,7 +60810,10 @@ async function postJson(options, action, body, signal) {
60795
60810
  }
60796
60811
  try {
60797
60812
  return await response.json();
60798
- } catch {
60813
+ } catch (error) {
60814
+ if (isAbortError(error)) {
60815
+ throw new CloudflareQueueApiError("Cloudflare Queue request timed out or was aborted", 408);
60816
+ }
60799
60817
  throw new CloudflareQueueApiError(`Cloudflare Queue ${action} returned invalid JSON`, 502);
60800
60818
  }
60801
60819
  }, {
@@ -60996,6 +61014,19 @@ function normalizeRetries(retries) {
60996
61014
  return { leaseId, ...retry.delaySeconds === void 0 ? {} : { delaySeconds: retry.delaySeconds } };
60997
61015
  });
60998
61016
  }
61017
+ var CLOUDFLARE_QUEUE_MAX_RETENTION_SECONDS = 14 * 24 * 60 * 60;
61018
+ var MIN_RETENTION_SECONDS = 60;
61019
+ var SANITY_MAX_RETENTION_SECONDS = 10 * 365 * 24 * 60 * 60;
61020
+ function recordOrNull(value) {
61021
+ return value != null && typeof value === "object" && !Array.isArray(value) ? value : null;
61022
+ }
61023
+ async function getCloudflareQueueRetentionSeconds(client, signal) {
61024
+ const resolved = resolveOptions(client);
61025
+ const envelope = recordOrNull(await requestJson(resolved, { method: "GET", url: queueUrl(resolved), label: "read" }, signal));
61026
+ if (envelope?.success !== true) return null;
61027
+ const seconds = recordOrNull(recordOrNull(envelope.result)?.settings)?.message_retention_period;
61028
+ return typeof seconds === "number" && Number.isInteger(seconds) && seconds >= MIN_RETENTION_SECONDS && seconds <= SANITY_MAX_RETENTION_SECONDS ? seconds : null;
61029
+ }
60999
61030
  async function pullCloudflareQueueMessages(client, options = {}) {
61000
61031
  const resolved = resolveOptions(client);
61001
61032
  const body = {};
@@ -61421,7 +61452,10 @@ var MAX_BACKFILL_DAYS = 90;
61421
61452
  var BACKFILL_MAX_PAGES = 1e3;
61422
61453
  var BACKFILL_SAMPLE_LIMIT = 500;
61423
61454
  var CLOUDFLARE_INGEST_BODY_LIMIT = 256 * 1024;
61424
- var CLOUDFLARE_QUEUE_RECEIPT_TTL_MS = 14 * 24 * 60 * 6e4 + 10 * 6e4;
61455
+ var CLOUDFLARE_QUEUE_RECEIPT_REPLAY_MARGIN_MS = 10 * 6e4;
61456
+ var CLOUDFLARE_QUEUE_RECEIPT_TTL_MS = CLOUDFLARE_QUEUE_MAX_RETENTION_SECONDS * 1e3 + CLOUDFLARE_QUEUE_RECEIPT_REPLAY_MARGIN_MS;
61457
+ var DAY_MS2 = 24 * 60 * 6e4;
61458
+ var CLOUDFLARE_QUEUE_RETENTION_READ_TIMEOUT_MS = 1e4;
61425
61459
  var CLOUDFLARE_QUEUE_VISIBILITY_TIMEOUT_MS = 5 * 6e4;
61426
61460
  var CLOUDFLARE_QUEUE_SYNC_LEASE_TTL_MS = 5 * 6e4;
61427
61461
  var WORDPRESS_SYNC_LEASE_TTL_MS = 5 * 6e4;
@@ -61440,6 +61474,35 @@ function timingSafeEqualHex(a, b) {
61440
61474
  const right = Buffer.from(b, "hex");
61441
61475
  return left.length === right.length && crypto51.timingSafeEqual(left, right);
61442
61476
  }
61477
+ async function loadQueueReceiptPolicy(db, sourceId, readRetentionSeconds, warn2) {
61478
+ let liveTtlMs = null;
61479
+ try {
61480
+ const seconds = await readRetentionSeconds();
61481
+ if (seconds === null) {
61482
+ warn2({}, "Cloudflare reported no usable Queue retention; keeping dedupe receipts for the maximum retention");
61483
+ } else {
61484
+ liveTtlMs = seconds * 1e3 + CLOUDFLARE_QUEUE_RECEIPT_REPLAY_MARGIN_MS;
61485
+ }
61486
+ } catch (error) {
61487
+ warn2(
61488
+ error instanceof CloudflareQueueApiError ? { status: error.status, error: error.message } : { error: "unexpected error" },
61489
+ "Could not read Cloudflare Queue retention; keeping dedupe receipts for the maximum retention"
61490
+ );
61491
+ }
61492
+ if (liveTtlMs === null) return { ttlMsAt: () => CLOUDFLARE_QUEUE_RECEIPT_TTL_MS };
61493
+ const ttlMs = liveTtlMs;
61494
+ const now = (/* @__PURE__ */ new Date()).toISOString();
61495
+ const alive = and68(eq79(trafficEventReceipts.sourceId, sourceId), gt6(trafficEventReceipts.expiresAt, now));
61496
+ const lifetimeMs = sql29`(julianday(${trafficEventReceipts.expiresAt}) - julianday(${trafficEventReceipts.receivedAt})) * ${DAY_MS2}`;
61497
+ const shortest = db.select({ ms: sql29`min(${lifetimeMs})` }).from(trafficEventReceipts).where(alive).get()?.ms ?? null;
61498
+ if (shortest !== null && shortest < ttlMs - 1e3) {
61499
+ const extended = sql29`strftime('%Y-%m-%dT%H:%M:%fZ', julianday(${trafficEventReceipts.receivedAt}) + ${ttlMs / DAY_MS2})`;
61500
+ db.update(trafficEventReceipts).set({ expiresAt: extended }).where(and68(alive, lt12(trafficEventReceipts.expiresAt, extended))).run();
61501
+ }
61502
+ const floorExpiry = db.select({ at: sql29`max(${trafficEventReceipts.expiresAt})` }).from(trafficEventReceipts).where(and68(alive, sql29`${lifetimeMs} < ${CLOUDFLARE_QUEUE_RECEIPT_TTL_MS - 1e3}`)).get()?.at ?? null;
61503
+ const floorMs = floorExpiry ? Date.parse(floorExpiry) : 0;
61504
+ return { ttlMsAt: (receivedAt) => Math.max(ttlMs, floorMs - Date.parse(receivedAt)) };
61505
+ }
61443
61506
  function parseDirectPushCloudflareSourceConfig(config) {
61444
61507
  const parsed = cloudflareTrafficSourceConfigSchema.safeParse(config);
61445
61508
  return parsed.success && parsed.data.deliveryMode === CloudflareTrafficDeliveryModes["direct-push"] ? parsed.data : null;
@@ -62139,9 +62202,11 @@ async function trafficRoutes(app, opts) {
62139
62202
  const pullVercelEvents = opts.pullVercelTrafficEvents ?? listVercelTrafficEvents;
62140
62203
  const pullQueueMessages = opts.pullCloudflareQueueMessages ?? pullCloudflareQueueMessages;
62141
62204
  const ackQueueMessages = opts.ackCloudflareQueueMessages ?? ackCloudflareQueueMessages;
62205
+ const readQueueRetentionSeconds = opts.getCloudflareQueueRetentionSeconds ?? getCloudflareQueueRetentionSeconds;
62142
62206
  const cloudflareQueueMaxBatches = opts.cloudflareQueueMaxBatches ?? DEFAULT_CLOUDFLARE_QUEUE_MAX_BATCHES;
62143
- if (!Number.isInteger(cloudflareQueueMaxBatches) || cloudflareQueueMaxBatches < 1 || cloudflareQueueMaxBatches > 50) {
62144
- throw new RangeError("cloudflareQueueMaxBatches must be an integer from 1 to 50");
62207
+ const cloudflareQueueSyncDeadlineMs = opts.cloudflareQueueSyncDeadlineMs ?? DEFAULT_CLOUDFLARE_QUEUE_SYNC_DEADLINE_MS;
62208
+ if (!Number.isInteger(cloudflareQueueMaxBatches) || cloudflareQueueMaxBatches < 1 || cloudflareQueueMaxBatches > 1e3) {
62209
+ throw new RangeError("cloudflareQueueMaxBatches must be an integer from 1 to 1000");
62145
62210
  }
62146
62211
  const allowLoopback = opts.allowLoopbackWebhooks === true;
62147
62212
  let rawSampleRetentionTimer;
@@ -63054,6 +63119,61 @@ async function trafficRoutes(app, opts) {
63054
63119
  const runId = crypto51.randomUUID();
63055
63120
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
63056
63121
  const startedMs = Date.now();
63122
+ let acceptedEvents = 0;
63123
+ let selfTrafficExcluded = 0;
63124
+ let crawlerHits = 0;
63125
+ let aiUserFetchHits = 0;
63126
+ let aiReferralHits = 0;
63127
+ let unknownHits = 0;
63128
+ let crawlerBucketRows = 0;
63129
+ let aiUserFetchBucketRows = 0;
63130
+ let aiReferralBucketRows = 0;
63131
+ let sampleRows = 0;
63132
+ let committedAt = startedAt;
63133
+ let remainingBacklogCount = 0;
63134
+ let completedBatches = 0;
63135
+ const finishSync = (status, error) => {
63136
+ app.db.update(runs).set({ status, finishedAt: committedAt, ...error ? { error } : {} }).where(eq79(runs.id, runId)).run();
63137
+ writeAuditLog(app.db, {
63138
+ projectId: project.id,
63139
+ actor: "api",
63140
+ action: "traffic.cloudflare.queue-synced",
63141
+ entityType: "traffic_source",
63142
+ entityId: sourceRow2.id
63143
+ });
63144
+ try {
63145
+ opts.onTrafficSynced?.({
63146
+ status: "completed",
63147
+ sourceType: sourceRow2.sourceType,
63148
+ sourceId: sourceRow2.id,
63149
+ pulledEvents: acceptedEvents,
63150
+ selfTrafficExcluded,
63151
+ crawlerHits,
63152
+ aiUserFetchHits,
63153
+ aiReferralHits,
63154
+ durationMs: Date.now() - startedMs
63155
+ });
63156
+ } catch {
63157
+ }
63158
+ return {
63159
+ sourceId: sourceRow2.id,
63160
+ runId,
63161
+ syncedAt: committedAt,
63162
+ pulledEvents: acceptedEvents,
63163
+ selfTrafficExcluded,
63164
+ crawlerHits,
63165
+ aiUserFetchHits,
63166
+ aiReferralHits,
63167
+ unknownHits,
63168
+ crawlerBucketRows,
63169
+ aiUserFetchBucketRows,
63170
+ aiReferralBucketRows,
63171
+ sampleRows,
63172
+ remainingBacklogCount,
63173
+ windowStart: startedAt,
63174
+ windowEnd: committedAt
63175
+ };
63176
+ };
63057
63177
  try {
63058
63178
  app.db.insert(runs).values({
63059
63179
  id: runId,
@@ -63065,20 +63185,17 @@ async function trafficRoutes(app, opts) {
63065
63185
  startedAt,
63066
63186
  createdAt: startedAt
63067
63187
  }).run();
63068
- let acceptedEvents = 0;
63069
- let selfTrafficExcluded = 0;
63070
- let crawlerHits = 0;
63071
- let aiUserFetchHits = 0;
63072
- let aiReferralHits = 0;
63073
- let unknownHits = 0;
63074
- let crawlerBucketRows = 0;
63075
- let aiUserFetchBucketRows = 0;
63076
- let aiReferralBucketRows = 0;
63077
- let sampleRows = 0;
63078
- let committedAt = startedAt;
63079
- let remainingBacklogCount = 0;
63080
63188
  const canonicalHost = resolveCloudflareWorkerRouteHost(project.canonicalDomain);
63081
- for (let batch = 0; batch < cloudflareQueueMaxBatches; batch += 1) {
63189
+ const drainDeadlineMs = startedMs + cloudflareQueueSyncDeadlineMs;
63190
+ let consecutiveEmptyPulls = 0;
63191
+ let receiptPolicy = null;
63192
+ const resolveReceiptPolicy = () => receiptPolicy ??= loadQueueReceiptPolicy(
63193
+ app.db,
63194
+ sourceRow2.id,
63195
+ () => readQueueRetentionSeconds({ ...queueClient, maxRetries: 0, timeoutMs: CLOUDFLARE_QUEUE_RETENTION_READ_TIMEOUT_MS }),
63196
+ (fields, message) => request.log.warn({ sourceId: sourceRow2.id, ...fields }, message)
63197
+ );
63198
+ for (let batch = 0; batch < cloudflareQueueMaxBatches && (batch === 0 || Date.now() < drainDeadlineMs); batch += 1) {
63082
63199
  if (!tryClaimTrafficSyncLease({
63083
63200
  db: app.db,
63084
63201
  sourceId: sourceRow2.id,
@@ -63144,6 +63261,7 @@ async function trafficRoutes(app, opts) {
63144
63261
  }
63145
63262
  validLeases.push(message.leaseId);
63146
63263
  }
63264
+ const policy = normalized.length > 0 ? await resolveReceiptPolicy() : null;
63147
63265
  committedAt = (/* @__PURE__ */ new Date()).toISOString();
63148
63266
  const writeResult = writeTrafficEventBatch({
63149
63267
  db: app.db,
@@ -63151,7 +63269,7 @@ async function trafficRoutes(app, opts) {
63151
63269
  sourceId: sourceRow2.id,
63152
63270
  events: normalized,
63153
63271
  receivedAt: committedAt,
63154
- receiptTtlMs: CLOUDFLARE_QUEUE_RECEIPT_TTL_MS,
63272
+ receiptTtlMs: policy ? policy.ttlMsAt(committedAt) : CLOUDFLARE_QUEUE_RECEIPT_TTL_MS,
63155
63273
  sampleLimit,
63156
63274
  validateSource: (latest) => {
63157
63275
  if (!latest || latest.projectId !== project.id || latest.status !== TrafficSourceStatuses.connected || latest.syncLeaseOwner !== leaseOwner || !isDeepStrictEqual(latest.configJson, sourceRow2.configJson)) {
@@ -63198,53 +63316,27 @@ async function trafficRoutes(app, opts) {
63198
63316
  aiUserFetchBucketRows += writeResult.aiUserFetchBucketRows;
63199
63317
  aiReferralBucketRows += writeResult.aiReferralBucketRows;
63200
63318
  sampleRows += writeResult.sampleRows;
63201
- const pulledEnvelopeCount = pulled.messages.length + pulled.skippedUnleasedMessageCount;
63202
- if (pulledEnvelopeCount < CLOUDFLARE_QUEUE_BATCH_SIZE || remainingBacklogCount === 0) break;
63203
- }
63204
- app.db.update(runs).set({ status: RunStatuses.completed, finishedAt: committedAt }).where(eq79(runs.id, runId)).run();
63205
- writeAuditLog(app.db, {
63206
- projectId: project.id,
63207
- actor: "api",
63208
- action: "traffic.cloudflare.queue-synced",
63209
- entityType: "traffic_source",
63210
- entityId: sourceRow2.id
63211
- });
63212
- try {
63213
- opts.onTrafficSynced?.({
63214
- status: "completed",
63215
- sourceType: sourceRow2.sourceType,
63216
- sourceId: sourceRow2.id,
63217
- pulledEvents: acceptedEvents,
63218
- selfTrafficExcluded,
63219
- crawlerHits,
63220
- aiUserFetchHits,
63221
- aiReferralHits,
63222
- durationMs: Date.now() - startedMs
63223
- });
63224
- } catch {
63319
+ completedBatches += 1;
63320
+ if (remainingBacklogCount === 0) break;
63321
+ if (pulled.messages.length === 0) {
63322
+ if (pulled.skippedUnleasedMessageCount > 0 && pulled.skippedUnleasedMessageCount < CLOUDFLARE_QUEUE_BATCH_SIZE) break;
63323
+ consecutiveEmptyPulls = pulled.skippedUnleasedMessageCount === 0 ? consecutiveEmptyPulls + 1 : 0;
63324
+ if (consecutiveEmptyPulls >= 2) break;
63325
+ } else {
63326
+ consecutiveEmptyPulls = 0;
63327
+ }
63225
63328
  }
63226
- const response = {
63227
- sourceId: sourceRow2.id,
63228
- runId,
63229
- syncedAt: committedAt,
63230
- pulledEvents: acceptedEvents,
63231
- selfTrafficExcluded,
63232
- crawlerHits,
63233
- aiUserFetchHits,
63234
- aiReferralHits,
63235
- unknownHits,
63236
- crawlerBucketRows,
63237
- aiUserFetchBucketRows,
63238
- aiReferralBucketRows,
63239
- sampleRows,
63240
- remainingBacklogCount,
63241
- windowStart: startedAt,
63242
- windowEnd: committedAt
63243
- };
63244
- return response;
63329
+ return finishSync(RunStatuses.completed, null);
63245
63330
  } catch (error) {
63246
63331
  const failedAt = (/* @__PURE__ */ new Date()).toISOString();
63247
63332
  const safeError = error instanceof CloudflareQueueApiError ? error.message : "Cloudflare Queue sync failed; retry the active source.";
63333
+ if (completedBatches > 0) {
63334
+ request.log.warn(
63335
+ { sourceId: sourceRow2.id, completedBatches, error: safeError },
63336
+ "Cloudflare Queue sync stopped after saving some batches"
63337
+ );
63338
+ return finishSync(RunStatuses.partial, safeError);
63339
+ }
63248
63340
  try {
63249
63341
  opts.onTrafficSynced?.({
63250
63342
  status: "failed",
@@ -65907,7 +65999,7 @@ var GSC_DATA_STALE_DAYS = 7;
65907
65999
  var SYNC_IDLE_DAYS = 3;
65908
66000
  var NOT_SYNCING_URGENT_DAYS = 8;
65909
66001
  var GSC_REPORTING_TIME_ZONE2 = "America/Los_Angeles";
65910
- var DAY_MS2 = 24 * 60 * 60 * 1e3;
66002
+ var DAY_MS3 = 24 * 60 * 60 * 1e3;
65911
66003
  var ISO_DATE = /^(\d{4})-(\d{2})-(\d{2})$/;
65912
66004
  function utcFromIsoDate(date) {
65913
66005
  const match = ISO_DATE.exec(date);
@@ -65918,7 +66010,7 @@ function daysBetweenIsoDates(from, to) {
65918
66010
  const start = utcFromIsoDate(from);
65919
66011
  const end = utcFromIsoDate(to);
65920
66012
  if (start === null || end === null) return null;
65921
- return Math.floor((end - start) / DAY_MS2);
66013
+ return Math.floor((end - start) / DAY_MS3);
65922
66014
  }
65923
66015
  function daysSinceDate(date, now = /* @__PURE__ */ new Date(), timeZone) {
65924
66016
  const today = timeZone ? formatIsoDateInTimeZone(now.toISOString(), timeZone) : `${now.getUTCFullYear()}-${String(now.getUTCMonth() + 1).padStart(2, "0")}-${String(now.getUTCDate()).padStart(2, "0")}`;
@@ -65930,7 +66022,7 @@ function skipped(code, summary3) {
65930
66022
  function lastSyncAgeDays(ctx, kinds) {
65931
66023
  const row = ctx.db.select({ createdAt: runs.createdAt }).from(runs).where(and73(eq87(runs.projectId, ctx.project.id), inArray36(runs.kind, kinds), eq87(runs.status, "completed"))).orderBy(desc40(runs.createdAt)).limit(1).get();
65932
66024
  if (!row?.createdAt) return null;
65933
- const age = Math.floor((Date.now() - Date.parse(row.createdAt)) / DAY_MS2);
66025
+ const age = Math.floor((Date.now() - Date.parse(row.createdAt)) / DAY_MS3);
65934
66026
  return Number.isFinite(age) ? age : null;
65935
66027
  }
65936
66028
  function grade(ctx, spec, newestDate) {
@@ -66423,7 +66515,7 @@ async function probeApiHost(host, options = {}) {
66423
66515
  }
66424
66516
 
66425
66517
  // ../api-routes/src/doctor/checks/integration-sync.ts
66426
- import { and as and74, count as count6, desc as desc41, eq as eq88, gte as gte21, gt as gt6, inArray as inArray37, isNull as isNull14, notInArray as notInArray3, or as or19 } from "drizzle-orm";
66518
+ import { and as and74, count as count6, desc as desc41, eq as eq88, gte as gte21, gt as gt7, inArray as inArray37, isNull as isNull14, notInArray as notInArray3, or as or19 } from "drizzle-orm";
66427
66519
  var SYNC_FAILURE_WINDOW = 3;
66428
66520
  var SUMMARY_ERROR_LIMIT = 300;
66429
66521
  var FINISHED_STATUSES = [RunStatuses.completed, RunStatuses.partial, RunStatuses.failed];
@@ -66518,7 +66610,7 @@ function readSyncRunState(db, projectId, kind, options = {}) {
66518
66610
  const graded = options.since ? and74(scope, gte21(runs.createdAt, options.since)) : scope;
66519
66611
  const recent = db.select({ id: runs.id, status: runs.status, trigger: runs.trigger, error: runs.error, createdAt: runs.createdAt }).from(runs).where(and74(graded, inArray37(runs.status, FINISHED_STATUSES))).orderBy(desc41(runs.createdAt)).limit(SYNC_FAILURE_WINDOW).all();
66520
66612
  const lastSuccess = db.select({ createdAt: runs.createdAt, finishedAt: runs.finishedAt }).from(runs).where(and74(graded, inArray37(runs.status, SUCCESS_STATUSES))).orderBy(desc41(runs.createdAt)).limit(1).get();
66521
- const failureCount = db.select({ count: count6() }).from(runs).where(and74(lastSuccess ? and74(graded, gt6(runs.createdAt, lastSuccess.createdAt)) : graded, eq88(runs.status, RunStatuses.failed))).get();
66613
+ const failureCount = db.select({ count: count6() }).from(runs).where(and74(lastSuccess ? and74(graded, gt7(runs.createdAt, lastSuccess.createdAt)) : graded, eq88(runs.status, RunStatuses.failed))).get();
66522
66614
  const failuresSinceSuccess = Number(failureCount?.count ?? 0);
66523
66615
  const latest = recent[0];
66524
66616
  return {
@@ -68353,12 +68445,12 @@ var queueBacklogCheck = {
68353
68445
  }
68354
68446
  const remaining = measured.filter((source) => (source.queueBacklogCount ?? 0) > 0);
68355
68447
  const total = remaining.reduce((sum, source) => sum + source.queueBacklogCount, 0);
68356
- if (total > DEFAULT_CLOUDFLARE_QUEUE_DRAIN_BUDGET) {
68448
+ if (total > CLOUDFLARE_QUEUE_RESIDUAL_WARN_COUNT) {
68357
68449
  return {
68358
68450
  status: CheckStatuses.warn,
68359
68451
  code: "traffic.queue-backlog.remaining",
68360
- summary: `${total.toLocaleString("en-US")} message(s) remained across ${remaining.length} Cloudflare Queue source(s) after the last bounded sync, exceeding the default ${DEFAULT_CLOUDFLARE_QUEUE_DRAIN_BUDGET.toLocaleString("en-US")}-message drain budget.`,
68361
- remediation: "Run `canonry traffic sync <project> --source <id>` again. If the backlog stays above 1,000 messages, shorten the traffic-sync schedule interval.",
68452
+ summary: `${total.toLocaleString("en-US")} message(s) remained across ${remaining.length} Cloudflare Queue source(s) after the last sync, more than the ${CLOUDFLARE_QUEUE_RESIDUAL_WARN_COUNT.toLocaleString("en-US")} that can arrive while a drain runs. The drain stopped at its time limit or pull cap before the Queue was empty.`,
68453
+ remediation: "If the backlog keeps growing, messages will pass the Queue's retention and be dropped. Shorten the traffic-sync schedule interval, or raise `CANONRY_CLOUDFLARE_QUEUE_SYNC_DEADLINE_MS` (default 4 minutes per sync).",
68362
68454
  details
68363
68455
  };
68364
68456
  }
@@ -68366,8 +68458,8 @@ var queueBacklogCheck = {
68366
68458
  return {
68367
68459
  status: CheckStatuses.ok,
68368
68460
  code: "traffic.queue-backlog.within-drain-budget",
68369
- summary: `${total.toLocaleString("en-US")} message(s) remained after the last bounded sync, within the default ${DEFAULT_CLOUDFLARE_QUEUE_DRAIN_BUDGET.toLocaleString("en-US")}-message drain budget.`,
68370
- remediation: "If no new messages arrive, the next scheduled sync can drain this residual backlog. Run `canonry traffic sync <project> --source <id>` to accelerate it.",
68461
+ summary: `${total.toLocaleString("en-US")} message(s) remained after the last sync, within the ${CLOUDFLARE_QUEUE_RESIDUAL_WARN_COUNT.toLocaleString("en-US")} that can arrive while a drain runs.`,
68462
+ remediation: "The next scheduled sync drains these. Run `canonry traffic sync <project> --source <id>` to drain them sooner.",
68371
68463
  details
68372
68464
  };
68373
68465
  }
@@ -68529,7 +68621,7 @@ var GTM_REQUIRED_OAUTH_SCOPES = [
68529
68621
  ];
68530
68622
  var FRESH_SNAPSHOT_WARN_DAYS = 7;
68531
68623
  var FRESH_SNAPSHOT_FAIL_DAYS = 30;
68532
- var DAY_MS3 = 24 * 60 * 60 * 1e3;
68624
+ var DAY_MS4 = 24 * 60 * 60 * 1e3;
68533
68625
  function unavailableStatus() {
68534
68626
  return {
68535
68627
  status: CheckStatuses.skipped,
@@ -68616,7 +68708,7 @@ function snapshotOutput(provider, latestSnapshotAt, now) {
68616
68708
  details: { latestSnapshotAt }
68617
68709
  };
68618
68710
  }
68619
- const ageDays2 = (now.getTime() - snapshotMs) / DAY_MS3;
68711
+ const ageDays2 = (now.getTime() - snapshotMs) / DAY_MS4;
68620
68712
  const details = { latestSnapshotAt, ageDays: Math.max(0, Math.round(ageDays2)) };
68621
68713
  if (ageDays2 < 0) {
68622
68714
  return {
@@ -69925,12 +70017,12 @@ function dedupeStrings(input) {
69925
70017
 
69926
70018
  // ../api-routes/src/technical-aeo.ts
69927
70019
  import crypto55 from "crypto";
69928
- import { and as and81, asc as asc20, count as count7, desc as desc45, eq as eq98, gte as gte25, inArray as inArray41, isNotNull as isNotNull9, isNull as isNull17, lt as lt12, or as or21, sql as sql33 } from "drizzle-orm";
70020
+ import { and as and81, asc as asc20, count as count7, desc as desc45, eq as eq98, gte as gte25, inArray as inArray41, isNotNull as isNotNull9, isNull as isNull17, lt as lt13, or as or21, sql as sql33 } from "drizzle-orm";
69929
70021
  import { alias } from "drizzle-orm/sqlite-core";
69930
70022
 
69931
70023
  // ../api-routes/src/technical-aeo-issues.ts
69932
70024
  import { createHash as createHash10 } from "crypto";
69933
- import { and as and80, asc as asc19, eq as eq97, gt as gt7, sql as sql32 } from "drizzle-orm";
70025
+ import { and as and80, asc as asc19, eq as eq97, gt as gt8, sql as sql32 } from "drizzle-orm";
69934
70026
  var ADVISORY_CODES = /* @__PURE__ */ new Set([
69935
70027
  "entity-consistency.title.short",
69936
70028
  "site.duplicate-title",
@@ -70091,7 +70183,7 @@ function readSiteAuditIssues(input) {
70091
70183
  url: siteCrawlPages.url,
70092
70184
  auditScore: siteCrawlPages.auditScore,
70093
70185
  auditFields: siteCrawlPages.auditFields
70094
- }).from(siteCrawlPages).where(and80(scope, after === void 0 ? void 0 : gt7(siteCrawlPages.nodeKey, after))).orderBy(asc19(siteCrawlPages.nodeKey)).limit(200).all();
70186
+ }).from(siteCrawlPages).where(and80(scope, after === void 0 ? void 0 : gt8(siteCrawlPages.nodeKey, after))).orderBy(asc19(siteCrawlPages.nodeKey)).limit(200).all();
70095
70187
  for (const page3 of pages) {
70096
70188
  evidenceHash.update(JSON.stringify(page3));
70097
70189
  const fields = record(page3.auditFields);
@@ -70581,11 +70673,11 @@ async function technicalAeoRoutes(app, opts) {
70581
70673
  };
70582
70674
  const resolveCrawl = (projectId, runId, requestedDate, scope = {}) => {
70583
70675
  const filters = visibleCrawlFilters(projectId);
70584
- if (scope.recordedBefore) filters.push(lt12(siteCrawlSnapshots.createdAt, scope.recordedBefore));
70676
+ if (scope.recordedBefore) filters.push(lt13(siteCrawlSnapshots.createdAt, scope.recordedBefore));
70585
70677
  if (requestedDate) {
70586
70678
  const nextDate2 = /* @__PURE__ */ new Date(`${requestedDate}T00:00:00.000Z`);
70587
70679
  nextDate2.setUTCDate(nextDate2.getUTCDate() + 1);
70588
- filters.push(gte25(siteCrawlSnapshots.createdAt, requestedDate), lt12(siteCrawlSnapshots.createdAt, nextDate2.toISOString()));
70680
+ filters.push(gte25(siteCrawlSnapshots.createdAt, requestedDate), lt13(siteCrawlSnapshots.createdAt, nextDate2.toISOString()));
70589
70681
  }
70590
70682
  const selectionFilters = scope.scoredOnly ? [...filters, sql33`exists (select 1 from ${siteAuditSnapshots} where ${siteAuditSnapshots.projectId} = ${siteCrawlSnapshots.projectId} and ${siteAuditSnapshots.runId} = ${siteCrawlSnapshots.runId})`] : filters;
70591
70683
  const selected = app.db.select({ snapshot: siteCrawlSnapshots, runStatus: runs.status }).from(siteCrawlSnapshots).innerJoin(runs, eq98(siteCrawlSnapshots.runId, runs.id)).where(and81(...selectionFilters, runId ? eq98(siteCrawlSnapshots.runId, runId) : void 0)).orderBy(
@@ -70602,7 +70694,7 @@ async function technicalAeoRoutes(app, opts) {
70602
70694
  const sameDate = and81(
70603
70695
  ...filters,
70604
70696
  gte25(siteCrawlSnapshots.createdAt, date),
70605
- lt12(siteCrawlSnapshots.createdAt, nextDate.toISOString())
70697
+ lt13(siteCrawlSnapshots.createdAt, nextDate.toISOString())
70606
70698
  );
70607
70699
  const sameDateRunCount = app.db.select({ value: count7() }).from(siteCrawlSnapshots).innerJoin(runs, eq98(siteCrawlSnapshots.runId, runs.id)).where(sameDate).get()?.value ?? 0;
70608
70700
  const candidates = app.db.select({
@@ -70633,7 +70725,7 @@ async function technicalAeoRoutes(app, opts) {
70633
70725
  eq98(runs.kind, RunKinds["site-audit"]),
70634
70726
  inArray41(runs.status, SURFACEABLE_STATUSES),
70635
70727
  notProbeRun(),
70636
- ...recordedBefore ? [lt12(siteAuditSnapshots.createdAt, recordedBefore)] : []
70728
+ ...recordedBefore ? [lt13(siteAuditSnapshots.createdAt, recordedBefore)] : []
70637
70729
  ];
70638
70730
  const complete = sql33`case when ${runs.status} = ${RunStatuses.completed} then 1 else 0 end`;
70639
70731
  const selectAudit = (pinnedRunId) => app.db.select({ snap: siteAuditSnapshots, runStatus: runs.status }).from(siteAuditSnapshots).innerJoin(runs, eq98(siteAuditSnapshots.runId, runs.id)).where(and81(...filters, pinnedRunId ? eq98(siteAuditSnapshots.runId, pinnedRunId) : void 0)).orderBy(
@@ -70660,7 +70752,7 @@ async function technicalAeoRoutes(app, opts) {
70660
70752
  const sameDate = and81(
70661
70753
  ...filters,
70662
70754
  gte25(siteAuditSnapshots.createdAt, date),
70663
- lt12(siteAuditSnapshots.createdAt, nextDate.toISOString())
70755
+ lt13(siteAuditSnapshots.createdAt, nextDate.toISOString())
70664
70756
  );
70665
70757
  const sameDateRunCount = app.db.select({ value: count7() }).from(siteAuditSnapshots).innerJoin(runs, eq98(siteAuditSnapshots.runId, runs.id)).where(sameDate).get()?.value ?? 0;
70666
70758
  const candidates = app.db.select({
@@ -71099,7 +71191,7 @@ async function technicalAeoRoutes(app, opts) {
71099
71191
  eq98(siteCrawlPages.runId, siteCrawlGraphNodes.runId),
71100
71192
  eq98(siteCrawlPages.attemptId, siteCrawlGraphNodes.attemptId),
71101
71193
  eq98(siteCrawlPages.nodeKey, siteCrawlGraphNodes.nodeKey)
71102
- )).where(and81(...graphScope, lt12(siteCrawlGraphNodes.sampleRank, maxNodes))).orderBy(asc20(siteCrawlGraphNodes.sampleRank)).all();
71194
+ )).where(and81(...graphScope, lt13(siteCrawlGraphNodes.sampleRank, maxNodes))).orderBy(asc20(siteCrawlGraphNodes.sampleRank)).all();
71103
71195
  const nodes = nodeRows.map(({ indexabilityReasons, canonicalNodeKey, ...row }) => ({
71104
71196
  ...row,
71105
71197
  healthState: deriveSiteHealthState({ ...row, indexabilityReasons, canonicalNodeKey }),
@@ -71118,18 +71210,18 @@ async function technicalAeoRoutes(app, opts) {
71118
71210
  eq98(graphSourceNode.runId, siteCrawlGraphEdges.runId),
71119
71211
  eq98(graphSourceNode.attemptId, siteCrawlGraphEdges.attemptId),
71120
71212
  eq98(graphSourceNode.nodeKey, siteCrawlGraphEdges.sourceNodeKey),
71121
- lt12(graphSourceNode.sampleRank, maxNodes)
71213
+ lt13(graphSourceNode.sampleRank, maxNodes)
71122
71214
  )).innerJoin(graphTargetNode, and81(
71123
71215
  eq98(graphTargetNode.projectId, siteCrawlGraphEdges.projectId),
71124
71216
  eq98(graphTargetNode.runId, siteCrawlGraphEdges.runId),
71125
71217
  eq98(graphTargetNode.attemptId, siteCrawlGraphEdges.attemptId),
71126
71218
  eq98(graphTargetNode.nodeKey, siteCrawlGraphEdges.targetNodeKey),
71127
- lt12(graphTargetNode.sampleRank, maxNodes)
71219
+ lt13(graphTargetNode.sampleRank, maxNodes)
71128
71220
  )).where(and81(
71129
71221
  eq98(siteCrawlGraphEdges.projectId, project.id),
71130
71222
  eq98(siteCrawlGraphEdges.runId, snapshot.runId),
71131
71223
  eq98(siteCrawlGraphEdges.attemptId, snapshot.attemptId),
71132
- lt12(siteCrawlGraphEdges.sampleRank, maxEdges),
71224
+ lt13(siteCrawlGraphEdges.sampleRank, maxEdges),
71133
71225
  graphLinkKindFilter
71134
71226
  )).orderBy(asc20(siteCrawlGraphEdges.sampleRank)).all();
71135
71227
  const totalNodes = persistedLayout.totalNodes;
@@ -71473,10 +71565,10 @@ async function technicalAeoRoutes(app, opts) {
71473
71565
  const beforeTarget = request.query.fromRunId ? resolveCrawl(project.id, request.query.fromRunId) : afterTarget ? app.db.select({ snapshot: siteCrawlSnapshots, runStatus: runs.status }).from(siteCrawlSnapshots).innerJoin(runs, eq98(siteCrawlSnapshots.runId, runs.id)).where(and81(
71474
71566
  ...completeSnapshotFilters,
71475
71567
  or21(
71476
- lt12(siteCrawlSnapshots.createdAt, afterTarget.snapshot.createdAt),
71568
+ lt13(siteCrawlSnapshots.createdAt, afterTarget.snapshot.createdAt),
71477
71569
  and81(
71478
71570
  eq98(siteCrawlSnapshots.createdAt, afterTarget.snapshot.createdAt),
71479
- lt12(siteCrawlSnapshots.runId, afterTarget.snapshot.runId)
71571
+ lt13(siteCrawlSnapshots.runId, afterTarget.snapshot.runId)
71480
71572
  )
71481
71573
  )
71482
71574
  )).orderBy(desc45(siteCrawlSnapshots.createdAt), desc45(siteCrawlSnapshots.runId)).limit(1).get() : void 0;
@@ -72361,7 +72453,7 @@ async function technicalAeoRoutes(app, opts) {
72361
72453
  }).from(siteCrawlPages).where(and81(
72362
72454
  auditedWhere,
72363
72455
  isNotNull9(siteCrawlPages.auditScore),
72364
- lt12(siteCrawlPages.auditScore, 70)
72456
+ lt13(siteCrawlPages.auditScore, 70)
72365
72457
  )).orderBy(asc20(siteCrawlPages.auditScore), asc20(siteCrawlPages.nodeKey)).limit(LIVE_PAGE_HEALTH_CANDIDATE_LIMIT).all();
72366
72458
  const examples = candidates.flatMap((candidate) => {
72367
72459
  if (candidate.auditScore == null) return [];
@@ -72456,7 +72548,7 @@ async function technicalAeoRoutes(app, opts) {
72456
72548
  // ../api-routes/src/research.ts
72457
72549
  import crypto56 from "crypto";
72458
72550
  import { z as z6 } from "zod";
72459
- import { and as and82, count as count8, desc as desc46, eq as eq99, gte as gte26, lt as lt13, or as or22, sql as sql34 } from "drizzle-orm";
72551
+ import { and as and82, count as count8, desc as desc46, eq as eq99, gte as gte26, lt as lt14, or as or22, sql as sql34 } from "drizzle-orm";
72460
72552
  var sameLocation = (a, b) => a.label === b.label && a.city === b.city && a.region === b.region && a.country === b.country && a.timezone === b.timezone;
72461
72553
  var BATCH_RECEIPT_PREFIX = "__canonry_research_batch__:";
72462
72554
  async function researchRoutes(app, opts) {
@@ -72521,7 +72613,7 @@ async function researchRoutes(app, opts) {
72521
72613
  const used = tx.select({ value: count8() }).from(researchRuns).where(and82(
72522
72614
  eq99(researchRuns.projectId, project.id),
72523
72615
  gte26(researchRuns.createdAt, start),
72524
- lt13(researchRuns.createdAt, end),
72616
+ lt14(researchRuns.createdAt, end),
72525
72617
  sql34`(json_extract(${researchRuns.initiatedBy}, '$.role') = ${UserRoles.viewer} OR json_extract(${researchRuns.initiatedBy}, '$.limited') = 1)`
72526
72618
  )).get()?.value ?? 0;
72527
72619
  if (used >= viewerDailyRunLimit) {
@@ -72577,7 +72669,7 @@ async function researchRoutes(app, opts) {
72577
72669
  const used = tx.select({ value: count8() }).from(researchRuns).where(and82(
72578
72670
  eq99(researchRuns.projectId, project.id),
72579
72671
  gte26(researchRuns.createdAt, start),
72580
- lt13(researchRuns.createdAt, end),
72672
+ lt14(researchRuns.createdAt, end),
72581
72673
  sql34`(json_extract(${researchRuns.initiatedBy}, '$.role') = ${UserRoles.viewer} OR json_extract(${researchRuns.initiatedBy}, '$.limited') = 1)`
72582
72674
  )).get()?.value ?? 0;
72583
72675
  if (used + prepared.length > viewerDailyRunLimit) throw researchDailyLimitExceeded(project.name, viewerDailyRunLimit, date);
@@ -72631,7 +72723,7 @@ async function researchRoutes(app, opts) {
72631
72723
  const cursor = request.query.cursor ? parseResearchCursor(request.query.cursor, project.id) : null;
72632
72724
  const rows = app.db.select().from(researchRuns).where(and82(
72633
72725
  eq99(researchRuns.projectId, project.id),
72634
- cursor ? or22(lt13(researchRuns.createdAt, cursor.createdAt), and82(eq99(researchRuns.createdAt, cursor.createdAt), lt13(researchRuns.id, cursor.id))) : void 0
72726
+ cursor ? or22(lt14(researchRuns.createdAt, cursor.createdAt), and82(eq99(researchRuns.createdAt, cursor.createdAt), lt14(researchRuns.id, cursor.id))) : void 0
72635
72727
  )).orderBy(desc46(researchRuns.createdAt), desc46(researchRuns.id)).limit(limit + 1).all();
72636
72728
  const runs2 = rows.slice(0, limit).map(serializeRun);
72637
72729
  const last = runs2.at(-1);
@@ -73260,7 +73352,9 @@ async function apiRoutes(app, opts) {
73260
73352
  cloudflareTrafficCredentialStore: opts.cloudflareTrafficCredentialStore,
73261
73353
  pullCloudflareQueueMessages: opts.pullCloudflareQueueMessages,
73262
73354
  ackCloudflareQueueMessages: opts.ackCloudflareQueueMessages,
73355
+ getCloudflareQueueRetentionSeconds: opts.getCloudflareQueueRetentionSeconds,
73263
73356
  cloudflareQueueMaxBatches: opts.cloudflareQueueMaxBatches,
73357
+ cloudflareQueueSyncDeadlineMs: opts.cloudflareQueueSyncDeadlineMs,
73264
73358
  cloudflareTrafficIngestUrl: opts.cloudflareTrafficIngestUrl,
73265
73359
  cloudflareIngestRateLimitMax: opts.cloudflareIngestRateLimitMax,
73266
73360
  cloudflareIngestIpRateLimitMax: opts.cloudflareIngestIpRateLimitMax,
@@ -73676,6 +73770,7 @@ export {
73676
73770
  listCachedReleases,
73677
73771
  pruneCachedRelease,
73678
73772
  resolveVercelSyncDeadlineMs,
73773
+ resolveCloudflareQueueSyncDeadlineMs,
73679
73774
  SITE_REACHABILITY_CHECK_ID,
73680
73775
  SITE_REACHABILITY_CHECKS,
73681
73776
  scheduledHealthCheckIds,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  REGISTERED_CLI_COMMANDS
3
- } from "./chunk-CFGA6OAK.js";
3
+ } from "./chunk-AP7YSOFC.js";
4
4
  import "./chunk-6GO5VVAC.js";
5
5
  import "./chunk-WLIGKWVB.js";
6
6
  import "./chunk-VJWDBFSL.js";
package/dist/cli.js CHANGED
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node --import tsx
2
2
  import {
3
3
  REGISTERED_CLI_COMMANDS
4
- } from "./chunk-CFGA6OAK.js";
4
+ } from "./chunk-AP7YSOFC.js";
5
5
  import "./chunk-6GO5VVAC.js";
6
6
  import {
7
7
  buildSetupState,
8
8
  runPendingServeHandoff
9
- } from "./chunk-BNGGUL7F.js";
9
+ } from "./chunk-NWYNTYPD.js";
10
10
  import "./chunk-WLIGKWVB.js";
11
11
  import "./chunk-VJWDBFSL.js";
12
12
  import "./chunk-TSENU4GG.js";
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-HGMYEDAQ.js";
8
8
  import {
9
9
  anyUsersExist
10
- } from "./chunk-NWQQYLZV.js";
10
+ } from "./chunk-QEJBAPDP.js";
11
11
  import "./chunk-Q4J3XSWE.js";
12
12
  import "./chunk-27SGL3DF.js";
13
13
  import {
@@ -40,7 +40,7 @@ function parseDemoTrustedProxies(values) {
40
40
  async function demoCommand(options) {
41
41
  const { host, port } = parseDemoListenOptions(options);
42
42
  const trustProxy = parseDemoTrustedProxies(options.trustProxy);
43
- const { createDemoServer } = await import("./demo-server-WIVTG6GH.js");
43
+ const { createDemoServer } = await import("./demo-server-QUW4TDJL.js");
44
44
  const app = await createDemoServer({ trustProxy });
45
45
  let stopping = false;
46
46
  const stop = () => {
@@ -18,14 +18,14 @@ import "./chunk-HGMYEDAQ.js";
18
18
  import {
19
19
  HISTORY_WINDOW_RUNS,
20
20
  IntelligenceService
21
- } from "./chunk-NMLVLFF7.js";
21
+ } from "./chunk-65YQFVJM.js";
22
22
  import {
23
23
  determineCitationState
24
24
  } from "./chunk-L7TKNHEX.js";
25
25
  import {
26
26
  apiRoutes,
27
27
  assessConversionTrackingIntegrity
28
- } from "./chunk-NWQQYLZV.js";
28
+ } from "./chunk-QEJBAPDP.js";
29
29
  import "./chunk-Q4J3XSWE.js";
30
30
  import "./chunk-27SGL3DF.js";
31
31
  import {
package/dist/index.js CHANGED
@@ -3,10 +3,10 @@ import {
3
3
  createGoogleMarketingCredentialStore,
4
4
  createGoogleMarketingRuntime,
5
5
  createServer
6
- } from "./chunk-6A6BD5KS.js";
6
+ } from "./chunk-CYVQW32W.js";
7
7
  import "./chunk-52NCZIAC.js";
8
- import "./chunk-2DZYA62C.js";
9
- import "./chunk-QFO7JHX2.js";
8
+ import "./chunk-5D4RL23M.js";
9
+ import "./chunk-A5F5E4DL.js";
10
10
  import "./chunk-ELCLGWUT.js";
11
11
  import "./chunk-XEBKF4N5.js";
12
12
  import "./chunk-6IBLGQVZ.js";
@@ -28,9 +28,9 @@ import "./chunk-QSPLYPVA.js";
28
28
  import "./chunk-N2HCXIQ3.js";
29
29
  import "./chunk-AOJU5LKX.js";
30
30
  import "./chunk-HGMYEDAQ.js";
31
- import "./chunk-NMLVLFF7.js";
31
+ import "./chunk-65YQFVJM.js";
32
32
  import "./chunk-L7TKNHEX.js";
33
- import "./chunk-NWQQYLZV.js";
33
+ import "./chunk-QEJBAPDP.js";
34
34
  import "./chunk-Q4J3XSWE.js";
35
35
  import "./chunk-27SGL3DF.js";
36
36
  import "./chunk-SCS7R2ND.js";
@@ -7,7 +7,7 @@ import {
7
7
  import {
8
8
  buildSetupState,
9
9
  queueServeHandoff
10
- } from "./chunk-BNGGUL7F.js";
10
+ } from "./chunk-NWYNTYPD.js";
11
11
  import "./chunk-VJWDBFSL.js";
12
12
  import "./chunk-YDSY5YJE.js";
13
13
  import "./chunk-3U7LL3JM.js";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  HISTORY_WINDOW_RUNS,
3
3
  IntelligenceService
4
- } from "./chunk-NMLVLFF7.js";
4
+ } from "./chunk-65YQFVJM.js";
5
5
  import "./chunk-L7TKNHEX.js";
6
- import "./chunk-NWQQYLZV.js";
6
+ import "./chunk-QEJBAPDP.js";
7
7
  import "./chunk-Q4J3XSWE.js";
8
8
  import "./chunk-27SGL3DF.js";
9
9
  import "./chunk-SCS7R2ND.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  backfillAiReferralPaths,
3
3
  backfillNormalizedPaths
4
- } from "./chunk-RXMGU7AF.js";
4
+ } from "./chunk-O6TF6TPM.js";
5
5
  import {
6
6
  operatorHttpUrl
7
7
  } from "./chunk-6GO5VVAC.js";
@@ -9,10 +9,10 @@ import {
9
9
  allowsKeylessFirstRunSetup,
10
10
  createServer,
11
11
  waitForServerRuntimeStartup
12
- } from "./chunk-6A6BD5KS.js";
12
+ } from "./chunk-CYVQW32W.js";
13
13
  import "./chunk-52NCZIAC.js";
14
- import "./chunk-2DZYA62C.js";
15
- import "./chunk-QFO7JHX2.js";
14
+ import "./chunk-5D4RL23M.js";
15
+ import "./chunk-A5F5E4DL.js";
16
16
  import "./chunk-ELCLGWUT.js";
17
17
  import "./chunk-XEBKF4N5.js";
18
18
  import "./chunk-6IBLGQVZ.js";
@@ -55,12 +55,12 @@ import {
55
55
  CliError,
56
56
  isMachineFormat
57
57
  } from "./chunk-HGMYEDAQ.js";
58
- import "./chunk-NMLVLFF7.js";
58
+ import "./chunk-65YQFVJM.js";
59
59
  import "./chunk-L7TKNHEX.js";
60
60
  import {
61
61
  refreshSnapshotMentionIdentity,
62
62
  snapshotsWithSentimentResults
63
- } from "./chunk-NWQQYLZV.js";
63
+ } from "./chunk-QEJBAPDP.js";
64
64
  import "./chunk-Q4J3XSWE.js";
65
65
  import "./chunk-27SGL3DF.js";
66
66
  import {
@@ -10,8 +10,8 @@ import {
10
10
  resolveAeroSkillDir,
11
11
  resolveConfiguredAgentProvider,
12
12
  resolveSessionProviderAndModel
13
- } from "./chunk-2DZYA62C.js";
14
- import "./chunk-QFO7JHX2.js";
13
+ } from "./chunk-5D4RL23M.js";
14
+ import "./chunk-A5F5E4DL.js";
15
15
  import "./chunk-NCIPNVD6.js";
16
16
  import "./chunk-F6W7FCS2.js";
17
17
  import {
@@ -24,7 +24,7 @@ import "./chunk-QSPLYPVA.js";
24
24
  import "./chunk-N2HCXIQ3.js";
25
25
  import "./chunk-AOJU5LKX.js";
26
26
  import "./chunk-HGMYEDAQ.js";
27
- import "./chunk-NWQQYLZV.js";
27
+ import "./chunk-QEJBAPDP.js";
28
28
  import "./chunk-Q4J3XSWE.js";
29
29
  import "./chunk-27SGL3DF.js";
30
30
  import "./chunk-SCS7R2ND.js";
@@ -11,7 +11,7 @@ import {
11
11
  buildAllTools,
12
12
  buildReadTools,
13
13
  isAeroToolProfile
14
- } from "./chunk-QFO7JHX2.js";
14
+ } from "./chunk-A5F5E4DL.js";
15
15
  import "./chunk-F6W7FCS2.js";
16
16
  import "./chunk-TVANRUBO.js";
17
17
  import "./chunk-YJPQBJZO.js";
@@ -19,7 +19,7 @@ import "./chunk-QSPLYPVA.js";
19
19
  import "./chunk-N2HCXIQ3.js";
20
20
  import "./chunk-AOJU5LKX.js";
21
21
  import "./chunk-HGMYEDAQ.js";
22
- import "./chunk-NWQQYLZV.js";
22
+ import "./chunk-QEJBAPDP.js";
23
23
  import "./chunk-Q4J3XSWE.js";
24
24
  import "./chunk-27SGL3DF.js";
25
25
  import "./chunk-SCS7R2ND.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canonry/canonry",
3
- "version": "7.58.4",
3
+ "version": "7.58.5",
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
  "keywords": [