@canonry/canonry 7.58.3 → 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.
Files changed (35) hide show
  1. package/assets/agent-workspace/skills/canonry/references/server-side-traffic.md +21 -13
  2. package/assets/assets/{AgentSetupPage-CRvCLiCD.js → AgentSetupPage-CoD9a386.js} +1 -1
  3. package/assets/assets/{MeasurementPropertyPage-B3qnQtNg.js → MeasurementPropertyPage-BZmvjMiS.js} +1 -1
  4. package/assets/assets/{ProjectPage-j9V9UFfY.js → ProjectPage-DMIoYBCF.js} +2 -2
  5. package/assets/assets/{RunsPage-CvqCrsiH.js → RunsPage-DtvesLu2.js} +1 -1
  6. package/assets/assets/{SettingsPage-CX5Rzsm3.js → SettingsPage-BjE3d5Ae.js} +1 -1
  7. package/assets/assets/{SiteHealthSection-CYKyJBaJ.js → SiteHealthSection-D6RLbM2o.js} +2 -2
  8. package/assets/assets/{TrafficPage-DNC0DP-U.js → TrafficPage-CHZlfMgd.js} +1 -1
  9. package/assets/assets/{index-CQwjYVPD.js → index-CgAMnZFS.js} +5 -5
  10. package/assets/assets/index-DElT2Fss.css +1 -0
  11. package/assets/assets/{react-sigma_core.esm.min-BNkIcXRz.js → react-sigma_core.esm.min-TGwpCHs4.js} +1 -1
  12. package/assets/assets/{service-CWdIU_mf.js → service-CUJkePNp.js} +1 -1
  13. package/assets/index.html +2 -2
  14. package/dist/{backfill-JAHDHVXJ.js → backfill-SINDWLD3.js} +2 -2
  15. package/dist/{chunk-2DZYA62C.js → chunk-5D4RL23M.js} +1 -1
  16. package/dist/{chunk-NMLVLFF7.js → chunk-65YQFVJM.js} +1 -1
  17. package/dist/{chunk-QFO7JHX2.js → chunk-A5F5E4DL.js} +1 -1
  18. package/dist/{chunk-BDUHO7KK.js → chunk-AP7YSOFC.js} +14 -14
  19. package/dist/{chunk-SXGLLWS4.js → chunk-CYVQW32W.js} +7 -5
  20. package/dist/{chunk-JDRKZOUP.js → chunk-NWYNTYPD.js} +1 -1
  21. package/dist/{chunk-RXMGU7AF.js → chunk-O6TF6TPM.js} +2 -2
  22. package/dist/{chunk-NWQQYLZV.js → chunk-QEJBAPDP.js} +195 -100
  23. package/dist/{cli-commands-3HTHHRXT.js → cli-commands-ZPW3OST3.js} +1 -1
  24. package/dist/cli.js +2 -2
  25. package/dist/{dashboard-2P3TEH6S.js → dashboard-VT3GQRW4.js} +1 -1
  26. package/dist/{demo-TPOKI7ZM.js → demo-ZBNVULOO.js} +1 -1
  27. package/dist/{demo-server-ZBNKYYM2.js → demo-server-QUW4TDJL.js} +153 -7
  28. package/dist/index.js +5 -5
  29. package/dist/{init-4IKMMWAD.js → init-C2DLDK6T.js} +1 -1
  30. package/dist/{intelligence-service-4PHEK5F4.js → intelligence-service-R5BRSQKI.js} +2 -2
  31. package/dist/{serve-2AOLGG3F.js → serve-ME2KJ6BG.js} +6 -6
  32. package/dist/{session-VTFLD3C5.js → session-R3PRJ3RB.js} +3 -3
  33. package/dist/{tools-LRHO7QOT.js → tools-VZVQ2CTU.js} +2 -2
  34. package/package.json +1 -1
  35. package/assets/assets/index-B662I7kR.css +0 -1
@@ -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-BDUHO7KK.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-BDUHO7KK.js";
4
+ } from "./chunk-AP7YSOFC.js";
5
5
  import "./chunk-6GO5VVAC.js";
6
6
  import {
7
7
  buildSetupState,
8
8
  runPendingServeHandoff
9
- } from "./chunk-JDRKZOUP.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-ZBNKYYM2.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 = () => {