@ainyc/canonry 4.71.0 → 4.71.1

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.
@@ -95,7 +95,7 @@ import {
95
95
  runs,
96
96
  schedules,
97
97
  usageCounters
98
- } from "./chunk-XYBBC5CH.js";
98
+ } from "./chunk-ETJDAMGA.js";
99
99
  import {
100
100
  AGENT_MEMORY_VALUE_MAX_BYTES,
101
101
  AGENT_PROVIDER_IDS,
@@ -5618,7 +5618,7 @@ function readStoredGroundingSources(rawResponse) {
5618
5618
  return result;
5619
5619
  }
5620
5620
  async function backfillInsightsCommand(project, opts) {
5621
- const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-GV57RTPO.js");
5621
+ const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-ISO4VGEC.js");
5622
5622
  const config = loadConfig();
5623
5623
  const db = createClient(config.database);
5624
5624
  migrate(db);
@@ -27326,10 +27326,11 @@ async function resolveRetainedStart(options, unservableStartMs, endMs) {
27326
27326
  async function drainVercelTrafficEvents(options) {
27327
27327
  const startMs = toMs(options.startDate);
27328
27328
  const endMs = toMs(options.endDate);
27329
+ const now = options.now ?? (() => Date.now());
27329
27330
  const events = [];
27330
27331
  const seenEventIds = /* @__PURE__ */ new Set();
27331
27332
  if (endMs <= startMs) {
27332
- return { events, subWindowCount: 0, effectiveStartMs: startMs, retentionClamped: false, truncatedSliceCount: 0, truncatedSliceStartsMs: [] };
27333
+ return { events, subWindowCount: 0, effectiveStartMs: startMs, retentionClamped: false, truncatedSliceCount: 0, truncatedSliceStartsMs: [], drainedThroughMs: startMs, deadlineReached: false };
27333
27334
  }
27334
27335
  let cursorMs = startMs;
27335
27336
  let spanMs = endMs - startMs;
@@ -27340,8 +27341,13 @@ async function drainVercelTrafficEvents(options) {
27340
27341
  let floorSpanProbeCountdown = 0;
27341
27342
  let floorPageBudgetCountdown = 0;
27342
27343
  let truncatedSliceCount = 0;
27344
+ let deadlineReached = false;
27343
27345
  const truncatedSliceStartsMs = [];
27344
27346
  while (cursorMs < endMs) {
27347
+ if (options.deadlineMs !== void 0 && now() >= options.deadlineMs) {
27348
+ deadlineReached = true;
27349
+ break;
27350
+ }
27345
27351
  if (subWindowCount >= options.maxSubWindows) {
27346
27352
  throw new Error(
27347
27353
  `Vercel window not drained within ${options.maxSubWindows} sub-windows \u2014 narrow the time range`
@@ -27428,7 +27434,7 @@ async function drainVercelTrafficEvents(options) {
27428
27434
  }
27429
27435
  }
27430
27436
  }
27431
- return { events, subWindowCount, effectiveStartMs, retentionClamped, truncatedSliceCount, truncatedSliceStartsMs };
27437
+ return { events, subWindowCount, effectiveStartMs, retentionClamped, truncatedSliceCount, truncatedSliceStartsMs, drainedThroughMs: cursorMs, deadlineReached };
27432
27438
  }
27433
27439
 
27434
27440
  // ../api-routes/src/traffic.ts
@@ -27440,6 +27446,8 @@ var DEFAULT_WP_PAGE_SIZE = 500;
27440
27446
  var DEFAULT_WP_MAX_PAGES = 20;
27441
27447
  var DEFAULT_VERCEL_MAX_PAGES = 50;
27442
27448
  var VERCEL_MAX_SUB_WINDOWS = 5e3;
27449
+ var VERCEL_MAX_SYNC_WINDOW_MS = 24 * 60 * 6e4;
27450
+ var DEFAULT_VERCEL_SYNC_DEADLINE_MS = 4 * 6e4;
27443
27451
  var VERCEL_BACKFILL_CHUNK_MS = 60 * 6e4;
27444
27452
  var MAX_TRACKED_EVENT_IDS = 1e3;
27445
27453
  var DEFAULT_BACKFILL_DAYS = 30;
@@ -27687,6 +27695,7 @@ async function trafficRoutes(app, opts) {
27687
27695
  }
27688
27696
  }
27689
27697
  const vercelMaxPages = opts.defaultVercelMaxPages ?? DEFAULT_VERCEL_MAX_PAGES;
27698
+ const vercelSyncDeadlineMs = opts.vercelSyncDeadlineMs ?? DEFAULT_VERCEL_SYNC_DEADLINE_MS;
27690
27699
  const syncWindowMinutes = opts.defaultSyncWindowMinutes ?? DEFAULT_SYNC_WINDOW_MINUTES;
27691
27700
  const pageSize = opts.defaultPageSize ?? DEFAULT_PAGE_SIZE3;
27692
27701
  const maxPages = opts.defaultMaxPages ?? DEFAULT_MAX_PAGES4;
@@ -28038,6 +28047,7 @@ async function trafficRoutes(app, opts) {
28038
28047
  let allEvents;
28039
28048
  let nextCursor;
28040
28049
  let auditAction;
28050
+ let effectiveWindowEnd = windowEnd;
28041
28051
  if (sourceRow.sourceType === TrafficSourceTypes["cloud-run"]) {
28042
28052
  auditAction = "traffic.cloud-run.synced";
28043
28053
  const credentialStore = opts.cloudRunCredentialStore;
@@ -28163,9 +28173,19 @@ async function trafficRoutes(app, opts) {
28163
28173
  const windowMinutes = Number.isFinite(requestedMinutes) && requestedMinutes && requestedMinutes > 0 ? Math.floor(requestedMinutes) : syncWindowMinutes;
28164
28174
  const requestedStartMs = windowEnd.getTime() - windowMinutes * 6e4;
28165
28175
  const lastSyncedMs = sourceRow.lastSyncedAt ? new Date(sourceRow.lastSyncedAt).getTime() : Number.NEGATIVE_INFINITY;
28166
- windowStart = new Date(
28167
- Math.min(windowEnd.getTime(), Math.max(requestedStartMs, lastSyncedMs))
28168
- );
28176
+ const clampedStartMs = Math.min(windowEnd.getTime(), Math.max(requestedStartMs, lastSyncedMs));
28177
+ const cappedStartMs = Math.max(clampedStartMs, windowEnd.getTime() - VERCEL_MAX_SYNC_WINDOW_MS);
28178
+ if (cappedStartMs > clampedStartMs) {
28179
+ request.log.warn(
28180
+ {
28181
+ sourceId: sourceRow.id,
28182
+ requestedStart: new Date(clampedStartMs).toISOString(),
28183
+ cappedStart: new Date(cappedStartMs).toISOString()
28184
+ },
28185
+ "Vercel sync window exceeded the max single-sync span; clamped the start forward (older traffic skipped \u2014 run a backfill to recover it)"
28186
+ );
28187
+ }
28188
+ windowStart = new Date(cappedStartMs);
28169
28189
  try {
28170
28190
  const drained = await drainVercelTrafficEvents({
28171
28191
  pull: pullVercelEvents,
@@ -28176,11 +28196,31 @@ async function trafficRoutes(app, opts) {
28176
28196
  startDate: windowStart.getTime(),
28177
28197
  endDate: windowEnd.getTime(),
28178
28198
  pagesPerSubWindow: vercelMaxPages,
28179
- maxSubWindows: VERCEL_MAX_SUB_WINDOWS
28199
+ maxSubWindows: VERCEL_MAX_SUB_WINDOWS,
28200
+ // Bound the drain's wall-clock so a dense/slow window can't run for
28201
+ // many minutes. On hit the drain stops and reports how far it got.
28202
+ deadlineMs: syncStartedAtMs + vercelSyncDeadlineMs
28180
28203
  });
28181
28204
  if (drained.retentionClamped) {
28182
28205
  throw vercelRetentionClampError(windowStart.getTime(), drained.effectiveStartMs);
28183
28206
  }
28207
+ if (drained.deadlineReached) {
28208
+ if (drained.drainedThroughMs <= windowStart.getTime()) {
28209
+ throw new Error(
28210
+ `sync exceeded its ${vercelSyncDeadlineMs}ms drain budget without completing any sub-window (request-logs slow or unavailable)`
28211
+ );
28212
+ }
28213
+ effectiveWindowEnd = new Date(drained.drainedThroughMs);
28214
+ request.log.warn(
28215
+ {
28216
+ sourceId: sourceRow.id,
28217
+ drainedThrough: effectiveWindowEnd.toISOString(),
28218
+ requestedEnd: windowEnd.toISOString(),
28219
+ subWindows: drained.subWindowCount
28220
+ },
28221
+ "Vercel drain hit its time budget; committing the partial window and advancing to it \u2014 next sync resumes from here"
28222
+ );
28223
+ }
28184
28224
  if (drained.truncatedSliceCount > 0) {
28185
28225
  request.log.warn(
28186
28226
  {
@@ -28364,11 +28404,13 @@ async function trafficRoutes(app, opts) {
28364
28404
  }
28365
28405
  const sourceUpdate = {
28366
28406
  status: TrafficSourceStatuses.connected,
28367
- // Advance to windowEnd, not finishedAt — events arriving at the
28368
- // source between windowEnd and finishedAt aren't in this pull's
28369
- // range. If we stored finishedAt, the next sync's clamp would skip
28370
- // past them and they'd be lost.
28371
- lastSyncedAt: windowEnd.toISOString(),
28407
+ // Advance to effectiveWindowEnd, not finishedAt — events arriving at the
28408
+ // source between the window end and finishedAt aren't in this pull's
28409
+ // range. If we stored finishedAt, the next sync's clamp would skip past
28410
+ // them and they'd be lost. effectiveWindowEnd equals windowEnd on a full
28411
+ // sync; for a Vercel drain that stopped at its deadline it is the partial
28412
+ // boundary, so the next sync resumes exactly where this one left off.
28413
+ lastSyncedAt: effectiveWindowEnd.toISOString(),
28372
28414
  lastError: null,
28373
28415
  lastEventIds: nextEventIds,
28374
28416
  updatedAt: finishedAt
@@ -28421,7 +28463,9 @@ async function trafficRoutes(app, opts) {
28421
28463
  aiReferralBucketRows,
28422
28464
  sampleRows,
28423
28465
  windowStart: windowStart.toISOString(),
28424
- windowEnd: windowEnd.toISOString()
28466
+ // The window actually synced: equals windowEnd on a full sync, or the
28467
+ // partial boundary when a Vercel drain stopped at its deadline.
28468
+ windowEnd: effectiveWindowEnd.toISOString()
28425
28469
  };
28426
28470
  return response;
28427
28471
  });
@@ -31208,6 +31252,7 @@ async function apiRoutes(app, opts) {
31208
31252
  pullWordpressTrafficEvents: opts.pullWordpressTrafficEvents,
31209
31253
  vercelTrafficCredentialStore: opts.vercelTrafficCredentialStore,
31210
31254
  pullVercelTrafficEvents: opts.pullVercelTrafficEvents,
31255
+ vercelSyncDeadlineMs: opts.vercelSyncDeadlineMs,
31211
31256
  onTrafficSynced: opts.onTrafficSynced,
31212
31257
  onScheduleUpdated: opts.onScheduleUpdated,
31213
31258
  allowLoopbackWebhooks: opts.allowLoopbackWebhooks
package/dist/cli.js CHANGED
@@ -27,7 +27,7 @@ import {
27
27
  setTelemetrySource,
28
28
  showFirstRunNotice,
29
29
  trackEvent
30
- } from "./chunk-B32J3DSZ.js";
30
+ } from "./chunk-CWEV3YMZ.js";
31
31
  import {
32
32
  CliError,
33
33
  EXIT_SYSTEM_ERROR,
@@ -52,7 +52,7 @@ import {
52
52
  projects,
53
53
  queries,
54
54
  renderReportHtml
55
- } from "./chunk-XYBBC5CH.js";
55
+ } from "./chunk-ETJDAMGA.js";
56
56
  import {
57
57
  CcReleaseSyncStatuses,
58
58
  CheckScopes,
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  createServer
3
- } from "./chunk-B32J3DSZ.js";
3
+ } from "./chunk-CWEV3YMZ.js";
4
4
  import {
5
5
  loadConfig
6
6
  } from "./chunk-ZNWMVYYU.js";
7
- import "./chunk-XYBBC5CH.js";
7
+ import "./chunk-ETJDAMGA.js";
8
8
  import "./chunk-5FM7QRYD.js";
9
9
  export {
10
10
  createServer,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  IntelligenceService
3
- } from "./chunk-XYBBC5CH.js";
3
+ } from "./chunk-ETJDAMGA.js";
4
4
  import "./chunk-5FM7QRYD.js";
5
5
  export {
6
6
  IntelligenceService
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ainyc/canonry",
3
- "version": "4.71.0",
3
+ "version": "4.71.1",
4
4
  "type": "module",
5
5
  "description": "Agent-first open-source AEO operating platform - track how answer engines cite your domain",
6
6
  "license": "FSL-1.1-ALv2",
@@ -66,22 +66,22 @@
66
66
  "@ainyc/canonry-api-routes": "0.0.0",
67
67
  "@ainyc/canonry-config": "0.0.0",
68
68
  "@ainyc/canonry-contracts": "0.0.0",
69
- "@ainyc/canonry-integration-bing": "0.0.0",
70
69
  "@ainyc/canonry-db": "0.0.0",
71
70
  "@ainyc/canonry-integration-cloud-run": "0.0.0",
71
+ "@ainyc/canonry-integration-commoncrawl": "0.0.0",
72
+ "@ainyc/canonry-integration-google": "0.0.0",
73
+ "@ainyc/canonry-integration-bing": "0.0.0",
72
74
  "@ainyc/canonry-integration-google-business-profile": "0.0.0",
73
75
  "@ainyc/canonry-integration-traffic": "0.0.0",
74
76
  "@ainyc/canonry-integration-google-places": "0.0.0",
75
- "@ainyc/canonry-integration-google": "0.0.0",
76
- "@ainyc/canonry-integration-commoncrawl": "0.0.0",
77
77
  "@ainyc/canonry-integration-wordpress": "0.0.0",
78
78
  "@ainyc/canonry-intelligence": "0.0.0",
79
79
  "@ainyc/canonry-provider-cdp": "0.0.0",
80
- "@ainyc/canonry-provider-claude": "0.0.0",
81
80
  "@ainyc/canonry-provider-gemini": "0.0.0",
82
81
  "@ainyc/canonry-provider-local": "0.0.0",
82
+ "@ainyc/canonry-provider-openai": "0.0.0",
83
83
  "@ainyc/canonry-provider-perplexity": "0.0.0",
84
- "@ainyc/canonry-provider-openai": "0.0.0"
84
+ "@ainyc/canonry-provider-claude": "0.0.0"
85
85
  },
86
86
  "scripts": {
87
87
  "build": "tsx scripts/copy-agent-assets.ts && tsup && tsx build-web.ts",