@ainyc/canonry 4.137.0 → 4.138.0

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 (25) hide show
  1. package/assets/assets/{AuditHistoryPanel-B6GEmlVM.js → AuditHistoryPanel-CIdoSKjP.js} +1 -1
  2. package/assets/assets/{BacklinksPage-Cr3QegNo.js → BacklinksPage-BYnzQLFq.js} +1 -1
  3. package/assets/assets/{ChartPrimitives-rhsGzU1A.js → ChartPrimitives-bx4p5MDx.js} +1 -1
  4. package/assets/assets/{HistoryPage-B3HrxyPP.js → HistoryPage-CjLb8TKY.js} +1 -1
  5. package/assets/assets/{ProjectPage-D3WiL3RI.js → ProjectPage-C_bSGiLs.js} +6 -6
  6. package/assets/assets/{RunRow-MsV1RLPm.js → RunRow-D6W6D1BX.js} +1 -1
  7. package/assets/assets/{RunsPage-BVlv0j3Y.js → RunsPage-CQT4lXFp.js} +1 -1
  8. package/assets/assets/{SettingsPage-Dfd-T4o9.js → SettingsPage-DVQKzz6s.js} +1 -1
  9. package/assets/assets/{TrafficPage-Bl1jj73m.js → TrafficPage-BdocLgWw.js} +1 -1
  10. package/assets/assets/{TrafficSourceDetailPage-CinQcKmY.js → TrafficSourceDetailPage-CTZF_R9C.js} +1 -1
  11. package/assets/assets/{arrow-left-CHU6s_Xn.js → arrow-left-ClC65OiR.js} +1 -1
  12. package/assets/assets/{extract-error-message-BDdyZgyf.js → extract-error-message-CsgTjzyj.js} +1 -1
  13. package/assets/assets/{index-BNulljlk.js → index-BZgknVrZ.js} +62 -62
  14. package/assets/assets/{index-CglduHCN.css → index-DY7GziwY.css} +1 -1
  15. package/assets/assets/{trash-2-BE5oH1Tj.js → trash-2-nr8RRH47.js} +1 -1
  16. package/assets/index.html +2 -2
  17. package/dist/{chunk-XEX5CLQW.js → chunk-3KGJ7BXW.js} +125 -5
  18. package/dist/{chunk-PBTB3FCN.js → chunk-GO24URVP.js} +71 -4
  19. package/dist/{chunk-UVWI6VPP.js → chunk-R3GAWKHM.js} +1 -1
  20. package/dist/{chunk-7RF5EDUO.js → chunk-RJ7OW6W6.js} +3000 -2924
  21. package/dist/cli.js +4 -4
  22. package/dist/index.js +4 -4
  23. package/dist/{intelligence-service-JEFHUGVX.js → intelligence-service-5RJHJLYA.js} +2 -2
  24. package/dist/mcp.js +2 -2
  25. package/package.json +6 -6
@@ -1 +1 @@
1
- import{c as a}from"./index-BNulljlk.js";const c=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],d=a("circle-check",c);const e=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3",key:"1u773s"}],["path",{d:"M12 17h.01",key:"p32p05"}]],k=a("circle-question-mark",e);const t=[["path",{d:"M12 15V3",key:"m9g1x1"}],["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["path",{d:"m7 10 5 5 5-5",key:"brsn70"}]],s=a("download",t);const o=[["path",{d:"M15 3h6v6",key:"1q9fwt"}],["path",{d:"M10 14 21 3",key:"gplh6r"}],["path",{d:"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",key:"a6xqqp"}]],r=a("external-link",o);const n=[["path",{d:"M10 11v6",key:"nco0om"}],["path",{d:"M14 11v6",key:"outv1u"}],["path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6",key:"miytrc"}],["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2",key:"e791ji"}]],y=a("trash-2",n);export{d as C,s as D,r as E,y as T,k as a};
1
+ import{c as a}from"./index-BZgknVrZ.js";const c=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],d=a("circle-check",c);const e=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3",key:"1u773s"}],["path",{d:"M12 17h.01",key:"p32p05"}]],k=a("circle-question-mark",e);const t=[["path",{d:"M12 15V3",key:"m9g1x1"}],["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["path",{d:"m7 10 5 5 5-5",key:"brsn70"}]],s=a("download",t);const o=[["path",{d:"M15 3h6v6",key:"1q9fwt"}],["path",{d:"M10 14 21 3",key:"gplh6r"}],["path",{d:"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",key:"a6xqqp"}]],r=a("external-link",o);const n=[["path",{d:"M10 11v6",key:"nco0om"}],["path",{d:"M14 11v6",key:"outv1u"}],["path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6",key:"miytrc"}],["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2",key:"e791ji"}]],y=a("trash-2",n);export{d as C,s as D,r as E,y as T,k as a};
package/assets/index.html CHANGED
@@ -12,12 +12,12 @@
12
12
  <link rel="icon" type="image/png" sizes="32x32" href="./favicon-32.png" />
13
13
  <link rel="apple-touch-icon" href="./apple-touch-icon.png" />
14
14
  <title>Canonry</title>
15
- <script type="module" crossorigin src="./assets/index-BNulljlk.js"></script>
15
+ <script type="module" crossorigin src="./assets/index-BZgknVrZ.js"></script>
16
16
  <link rel="modulepreload" crossorigin href="./assets/vendor-tanstack-Be8JdV5M.js">
17
17
  <link rel="modulepreload" crossorigin href="./assets/vendor-radix-CQ77EO2y.js">
18
18
  <link rel="modulepreload" crossorigin href="./assets/vendor-recharts-DSxTZhaH.js">
19
19
  <link rel="modulepreload" crossorigin href="./assets/vendor-markdown-6dwjPOKK.js">
20
- <link rel="stylesheet" crossorigin href="./assets/index-CglduHCN.css">
20
+ <link rel="stylesheet" crossorigin href="./assets/index-DY7GziwY.css">
21
21
  </head>
22
22
  <body>
23
23
  <div id="root"></div>
@@ -10,7 +10,7 @@ import {
10
10
  loadConfig,
11
11
  loadConfigRaw,
12
12
  saveConfigPatch
13
- } from "./chunk-UVWI6VPP.js";
13
+ } from "./chunk-R3GAWKHM.js";
14
14
  import {
15
15
  CC_CACHE_DIR,
16
16
  DUCKDB_SPEC,
@@ -119,7 +119,7 @@ import {
119
119
  siteAuditPages,
120
120
  siteAuditSnapshots,
121
121
  usageCounters
122
- } from "./chunk-PBTB3FCN.js";
122
+ } from "./chunk-GO24URVP.js";
123
123
  import {
124
124
  AGENT_MEMORY_VALUE_MAX_BYTES,
125
125
  AGENT_PROVIDER_IDS,
@@ -129,6 +129,7 @@ import {
129
129
  AdsCampaignBiddingTypes,
130
130
  AgentProviderIds,
131
131
  BacklinkSources,
132
+ CITED_URL_CAPTURE_VERSION,
132
133
  CcReleaseSyncStatuses,
133
134
  CodingAgents,
134
135
  DiscoveryCompetitorTypes,
@@ -137,6 +138,7 @@ import {
137
138
  MemorySources,
138
139
  ONBOARDING_FLOW_VERSION,
139
140
  ProviderNames,
141
+ ROUTE_CAPABLE_CITED_URL_PROVIDERS,
140
142
  ResearchQueryStatuses,
141
143
  ResearchRunStatuses,
142
144
  RunKinds,
@@ -167,12 +169,14 @@ import {
167
169
  computeBacklinkSummaryMetrics,
168
170
  contentActionLabel,
169
171
  contentBriefDtoSchema,
172
+ deriveCitedUrlCandidates,
170
173
  determineAnswerMentioned,
171
174
  dollarsToMicros,
172
175
  effectiveBrandNames,
173
176
  effectiveDomains,
174
177
  embedClientConfigForRequest,
175
178
  factorStatusFromScore,
179
+ filterCapturedCitedUrls,
176
180
  formatIsoDateInTimeZone,
177
181
  frameAncestorsHeaderValue,
178
182
  hostMatchesAnyDomain,
@@ -182,6 +186,7 @@ import {
182
186
  isBrowserProvider,
183
187
  isGhostTelemetryEvent,
184
188
  isRetryableHttpError,
189
+ isVertexGroundingRedirect,
185
190
  mapWithConcurrency,
186
191
  normalizeIdTokens,
187
192
  normalizeServedModel,
@@ -201,7 +206,7 @@ import {
201
206
  validationError,
202
207
  winnabilityClassLabel,
203
208
  withRetry
204
- } from "./chunk-7RF5EDUO.js";
209
+ } from "./chunk-RJ7OW6W6.js";
205
210
 
206
211
  // src/telemetry.ts
207
212
  import crypto from "crypto";
@@ -3246,6 +3251,87 @@ function releaseDailyQueryQuota(db, input) {
3246
3251
  db.update(usageCounters).set({ count: sql`MAX(0, ${usageCounters.count} - ${input.count})`, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(and(eq(usageCounters.scope, input.scope), eq(usageCounters.period, input.period), eq(usageCounters.metric, "queries"))).run();
3247
3252
  }
3248
3253
 
3254
+ // src/cited-url-capture.ts
3255
+ var RESOLUTION_CONCURRENCY = 5;
3256
+ var RESOLUTION_TIMEOUT_MS = 5e3;
3257
+ var MAX_VERTEX_PROXY_HOPS = 3;
3258
+ var REDIRECT_STATUSES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
3259
+ function isRouteCapableProvider(provider) {
3260
+ return ROUTE_CAPABLE_CITED_URL_PROVIDERS.includes(provider);
3261
+ }
3262
+ function parseHttpUrl(value, base) {
3263
+ try {
3264
+ const url = new URL(value, base);
3265
+ if (url.protocol !== "http:" && url.protocol !== "https:") return void 0;
3266
+ url.hash = "";
3267
+ return url;
3268
+ } catch {
3269
+ return void 0;
3270
+ }
3271
+ }
3272
+ async function resolveVertexGroundingRedirect(value, opts = {}) {
3273
+ const initial = parseHttpUrl(value);
3274
+ if (!initial || !isVertexGroundingRedirect(initial)) return void 0;
3275
+ const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
3276
+ const timeoutMs = opts.timeoutMs ?? RESOLUTION_TIMEOUT_MS;
3277
+ let current = initial;
3278
+ for (let hop = 0; hop <= MAX_VERTEX_PROXY_HOPS; hop++) {
3279
+ const controller = new AbortController();
3280
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
3281
+ let response;
3282
+ try {
3283
+ response = await fetchImpl(current, { redirect: "manual", signal: controller.signal });
3284
+ } catch {
3285
+ return void 0;
3286
+ } finally {
3287
+ clearTimeout(timer);
3288
+ }
3289
+ if (!REDIRECT_STATUSES.has(response.status)) return void 0;
3290
+ const location = response.headers.get("location");
3291
+ if (!location) return void 0;
3292
+ const next = parseHttpUrl(location, current.toString());
3293
+ if (!next) return void 0;
3294
+ if (!isVertexGroundingRedirect(next)) return next.toString();
3295
+ current = next;
3296
+ }
3297
+ return void 0;
3298
+ }
3299
+ async function captureCitedUrls(provider, sources, opts = {}) {
3300
+ const sourceCount = sources.length;
3301
+ if (!isRouteCapableProvider(provider)) {
3302
+ return {
3303
+ citedUrls: null,
3304
+ captureStatus: "unsupported",
3305
+ sourceCount,
3306
+ resolvedCount: 0,
3307
+ captureVersion: CITED_URL_CAPTURE_VERSION
3308
+ };
3309
+ }
3310
+ const candidates = deriveCitedUrlCandidates(sources);
3311
+ const candidateCount = candidates.length;
3312
+ let resolved;
3313
+ try {
3314
+ resolved = await mapWithConcurrency(candidates, RESOLUTION_CONCURRENCY, async (candidate) => {
3315
+ const parsed = parseHttpUrl(candidate);
3316
+ if (!parsed) return void 0;
3317
+ if (!isVertexGroundingRedirect(parsed)) return candidate;
3318
+ return resolveVertexGroundingRedirect(candidate, opts);
3319
+ });
3320
+ } catch {
3321
+ resolved = candidates.map(() => void 0);
3322
+ }
3323
+ const acceptedPerSource = resolved.map((value) => filterCapturedCitedUrls([value]).at(0));
3324
+ const resolvedCount = acceptedPerSource.filter((value) => value !== void 0).length;
3325
+ const captureStatus = resolvedCount === candidateCount ? "complete" : resolvedCount > 0 ? "partial" : "failed";
3326
+ return {
3327
+ citedUrls: filterCapturedCitedUrls(acceptedPerSource),
3328
+ captureStatus,
3329
+ sourceCount,
3330
+ resolvedCount,
3331
+ captureVersion: CITED_URL_CAPTURE_VERSION
3332
+ };
3333
+ }
3334
+
3249
3335
  // src/job-runner.ts
3250
3336
  var log = createLogger("JobRunner");
3251
3337
  var RunCancelledError = class extends Error {
@@ -3469,7 +3555,31 @@ var JobRunner = class {
3469
3555
  config
3470
3556
  );
3471
3557
  this.throwIfRunCancelled(runId);
3472
- const normalized = adapter.normalizeResult(raw);
3558
+ const providerResult = adapter.normalizeResult(raw);
3559
+ const rawGroundingSources = providerResult.groundingSources;
3560
+ const normalized = {
3561
+ ...providerResult,
3562
+ groundingSources: Array.isArray(rawGroundingSources) ? rawGroundingSources : []
3563
+ };
3564
+ let citedUrlCapture;
3565
+ try {
3566
+ citedUrlCapture = await captureCitedUrls(providerName, rawGroundingSources);
3567
+ } catch (err) {
3568
+ citedUrlCapture = {
3569
+ citedUrls: [],
3570
+ captureStatus: "failed",
3571
+ sourceCount: normalized.groundingSources.length,
3572
+ resolvedCount: 0,
3573
+ captureVersion: CITED_URL_CAPTURE_VERSION
3574
+ };
3575
+ log.warn("query.cited-url-capture-failed", {
3576
+ runId,
3577
+ provider: providerName,
3578
+ query: q.query,
3579
+ error: err instanceof Error ? err.message : String(err)
3580
+ });
3581
+ }
3582
+ this.throwIfRunCancelled(runId);
3473
3583
  log.info("query.result", { runId, provider: providerName, query: q.query, citedDomains: normalized.citedDomains, groundingSources: normalized.groundingSources.map((s) => s.uri), matchDomains: allDomains });
3474
3584
  const citationState = determineCitationState(normalized, allDomains);
3475
3585
  const answerMentioned = determineAnswerMentioned(
@@ -3505,6 +3615,11 @@ var JobRunner = class {
3505
3615
  answerMentioned,
3506
3616
  answerText: normalized.answerText,
3507
3617
  citedDomains: normalized.citedDomains,
3618
+ citedUrls: citedUrlCapture.citedUrls,
3619
+ captureStatus: citedUrlCapture.captureStatus,
3620
+ sourceCount: citedUrlCapture.sourceCount,
3621
+ resolvedCount: citedUrlCapture.resolvedCount,
3622
+ captureVersion: citedUrlCapture.captureVersion,
3508
3623
  competitorOverlap: overlap,
3509
3624
  recommendedCompetitors: extractedCompetitors,
3510
3625
  location: runLocation?.label ?? null,
@@ -3531,6 +3646,11 @@ var JobRunner = class {
3531
3646
  answerMentioned,
3532
3647
  answerText: normalized.answerText,
3533
3648
  citedDomains: normalized.citedDomains,
3649
+ citedUrls: citedUrlCapture.citedUrls,
3650
+ captureStatus: citedUrlCapture.captureStatus,
3651
+ sourceCount: citedUrlCapture.sourceCount,
3652
+ resolvedCount: citedUrlCapture.resolvedCount,
3653
+ captureVersion: citedUrlCapture.captureVersion,
3534
3654
  competitorOverlap: overlap,
3535
3655
  recommendedCompetitors: extractedCompetitors,
3536
3656
  location: runLocation?.label ?? null,
@@ -7119,7 +7239,7 @@ function readStoredGroundingSources(rawResponse) {
7119
7239
  return result;
7120
7240
  }
7121
7241
  async function backfillInsightsCommand(project, opts) {
7122
- const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-JEFHUGVX.js");
7242
+ const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-5RJHJLYA.js");
7123
7243
  const config = loadConfig();
7124
7244
  const db = createClient(config.database);
7125
7245
  migrate(db);
@@ -289,6 +289,7 @@ import {
289
289
  projectDtoSchema,
290
290
  projectOverviewDtoSchema,
291
291
  projectReportDtoSchema,
292
+ projectSearchResponseSchema,
292
293
  projectUpsertRequestSchema,
293
294
  providerError,
294
295
  queryDtoSchema,
@@ -377,7 +378,7 @@ import {
377
378
  wordpressSchemaDeployResultDtoSchema,
378
379
  wordpressSchemaStatusResultDtoSchema,
379
380
  wordpressStatusDtoSchema
380
- } from "./chunk-7RF5EDUO.js";
381
+ } from "./chunk-RJ7OW6W6.js";
381
382
 
382
383
  // src/intelligence-service.ts
383
384
  import { eq as eq44, desc as desc21, asc as asc9, and as and35, ne as ne6, or as or10, inArray as inArray15, gte as gte12, lte as lte8 } from "drizzle-orm";
@@ -553,6 +554,13 @@ var querySnapshots = sqliteTable("query_snapshots", {
553
554
  answerMentioned: integer("answer_mentioned", { mode: "boolean" }),
554
555
  answerText: text("answer_text"),
555
556
  citedDomains: text("cited_domains", { mode: "json" }).$type().notNull().default([]),
557
+ // Flat capture fields are deliberately nullable: historical rows are not
558
+ // backfilled, so all-null means this observation predates URL capture.
559
+ citedUrls: text("cited_urls", { mode: "json" }).$type(),
560
+ captureStatus: text("capture_status").$type(),
561
+ sourceCount: integer("source_count"),
562
+ resolvedCount: integer("resolved_count"),
563
+ captureVersion: integer("capture_version"),
556
564
  competitorOverlap: text("competitor_overlap", { mode: "json" }).$type().notNull().default([]),
557
565
  recommendedCompetitors: text("recommended_competitors", { mode: "json" }).$type().notNull().default([]),
558
566
  location: text("location"),
@@ -4299,6 +4307,19 @@ var MIGRATION_VERSIONS = [
4299
4307
  `ALTER TABLE research_run_queries ADD COLUMN named_competitors TEXT NOT NULL DEFAULT '[]'`,
4300
4308
  `ALTER TABLE research_run_queries ADD COLUMN cited_competitor_domains TEXT NOT NULL DEFAULT '[]'`
4301
4309
  ]
4310
+ },
4311
+ {
4312
+ // New live rows capture source URLs; historical snapshots intentionally
4313
+ // stay NULL so readers can distinguish absent capture from zero sources.
4314
+ version: 111,
4315
+ name: "query-snapshot-cited-url-capture",
4316
+ statements: [
4317
+ `ALTER TABLE query_snapshots ADD COLUMN cited_urls TEXT`,
4318
+ `ALTER TABLE query_snapshots ADD COLUMN capture_status TEXT`,
4319
+ `ALTER TABLE query_snapshots ADD COLUMN source_count INTEGER`,
4320
+ `ALTER TABLE query_snapshots ADD COLUMN resolved_count INTEGER`,
4321
+ `ALTER TABLE query_snapshots ADD COLUMN capture_version INTEGER`
4322
+ ]
4302
4323
  }
4303
4324
  ];
4304
4325
  function rebuildBacklinkTableWithSource(tx, table) {
@@ -8334,6 +8355,11 @@ function loadRunDetail(app, run) {
8334
8355
  answerMentioned: querySnapshots.answerMentioned,
8335
8356
  answerText: querySnapshots.answerText,
8336
8357
  citedDomains: querySnapshots.citedDomains,
8358
+ citedUrls: querySnapshots.citedUrls,
8359
+ captureStatus: querySnapshots.captureStatus,
8360
+ sourceCount: querySnapshots.sourceCount,
8361
+ resolvedCount: querySnapshots.resolvedCount,
8362
+ captureVersion: querySnapshots.captureVersion,
8337
8363
  competitorOverlap: querySnapshots.competitorOverlap,
8338
8364
  recommendedCompetitors: querySnapshots.recommendedCompetitors,
8339
8365
  location: querySnapshots.location,
@@ -8359,6 +8385,11 @@ function loadRunDetail(app, run) {
8359
8385
  mentionState: project ? resolveSnapshotMentionState(s, project) : answerMentioned ? "mentioned" : "not-mentioned",
8360
8386
  answerText: s.answerText,
8361
8387
  citedDomains: s.citedDomains,
8388
+ citedUrls: s.citedUrls,
8389
+ captureStatus: s.captureStatus,
8390
+ sourceCount: s.sourceCount,
8391
+ resolvedCount: s.resolvedCount,
8392
+ captureVersion: s.captureVersion,
8362
8393
  competitorOverlap: s.competitorOverlap,
8363
8394
  recommendedCompetitors: s.recommendedCompetitors,
8364
8395
  matchedTerms: project ? resolveSnapshotMatchedTerms(s, project) : [],
@@ -9013,6 +9044,11 @@ async function historyRoutes(app) {
9013
9044
  answerMentioned: querySnapshots.answerMentioned,
9014
9045
  answerText: querySnapshots.answerText,
9015
9046
  citedDomains: querySnapshots.citedDomains,
9047
+ citedUrls: querySnapshots.citedUrls,
9048
+ captureStatus: querySnapshots.captureStatus,
9049
+ sourceCount: querySnapshots.sourceCount,
9050
+ resolvedCount: querySnapshots.resolvedCount,
9051
+ captureVersion: querySnapshots.captureVersion,
9016
9052
  competitorOverlap: querySnapshots.competitorOverlap,
9017
9053
  recommendedCompetitors: querySnapshots.recommendedCompetitors,
9018
9054
  location: querySnapshots.location,
@@ -9036,6 +9072,11 @@ async function historyRoutes(app) {
9036
9072
  mentionState: resolveSnapshotMentionState(s, project),
9037
9073
  answerText: s.answerText,
9038
9074
  citedDomains: s.citedDomains,
9075
+ citedUrls: s.citedUrls,
9076
+ captureStatus: s.captureStatus,
9077
+ sourceCount: s.sourceCount,
9078
+ resolvedCount: s.resolvedCount,
9079
+ captureVersion: s.captureVersion,
9039
9080
  competitorOverlap: s.competitorOverlap,
9040
9081
  recommendedCompetitors: s.recommendedCompetitors,
9041
9082
  location: s.location,
@@ -16509,6 +16550,11 @@ var CSV_COLUMNS = [
16509
16550
  "answer_mentioned",
16510
16551
  "mention_state",
16511
16552
  "cited_domains_json",
16553
+ "cited_urls_json",
16554
+ "capture_status",
16555
+ "source_count",
16556
+ "resolved_count",
16557
+ "capture_version",
16512
16558
  "competitor_overlap_json",
16513
16559
  "recommended_competitors_json",
16514
16560
  "answer_text",
@@ -16590,6 +16636,11 @@ function renderResultsExportCsv(report) {
16590
16636
  record.answerMentioned,
16591
16637
  record.mentionState,
16592
16638
  JSON.stringify(record.citedDomains),
16639
+ JSON.stringify(record.citedUrls),
16640
+ record.captureStatus,
16641
+ record.sourceCount,
16642
+ record.resolvedCount,
16643
+ record.captureVersion,
16593
16644
  JSON.stringify(record.competitorOverlap),
16594
16645
  JSON.stringify(record.recommendedCompetitors),
16595
16646
  record.answerText,
@@ -16634,6 +16685,11 @@ async function resultsExportRoutes(app) {
16634
16685
  citationState: querySnapshots.citationState,
16635
16686
  answerMentioned: querySnapshots.answerMentioned,
16636
16687
  citedDomains: querySnapshots.citedDomains,
16688
+ citedUrls: querySnapshots.citedUrls,
16689
+ captureStatus: querySnapshots.captureStatus,
16690
+ sourceCount: querySnapshots.sourceCount,
16691
+ resolvedCount: querySnapshots.resolvedCount,
16692
+ captureVersion: querySnapshots.captureVersion,
16637
16693
  competitorOverlap: querySnapshots.competitorOverlap,
16638
16694
  recommendedCompetitors: querySnapshots.recommendedCompetitors,
16639
16695
  answerText: querySnapshots.answerText,
@@ -16662,6 +16718,11 @@ async function resultsExportRoutes(app) {
16662
16718
  answerMentioned: row.answerMentioned,
16663
16719
  mentionState: recordMentionState(row.answerMentioned),
16664
16720
  citedDomains: row.citedDomains,
16721
+ citedUrls: row.citedUrls,
16722
+ captureStatus: row.captureStatus,
16723
+ sourceCount: row.sourceCount,
16724
+ resolvedCount: row.resolvedCount,
16725
+ captureVersion: row.captureVersion,
16665
16726
  competitorOverlap: row.competitorOverlap,
16666
16727
  recommendedCompetitors: row.recommendedCompetitors,
16667
16728
  answerText: row.answerText,
@@ -16872,6 +16933,7 @@ async function compositeRoutes(app) {
16872
16933
  citationState: querySnapshots.citationState,
16873
16934
  answerText: querySnapshots.answerText,
16874
16935
  citedDomains: querySnapshots.citedDomains,
16936
+ citedUrls: querySnapshots.citedUrls,
16875
16937
  rawResponse: querySnapshots.rawResponse,
16876
16938
  createdAt: querySnapshots.createdAt
16877
16939
  }).from(querySnapshots).innerJoin(queries, eq22(querySnapshots.queryId, queries.id)).where(
@@ -16880,6 +16942,7 @@ async function compositeRoutes(app) {
16880
16942
  or6(
16881
16943
  sql11`${querySnapshots.answerText} LIKE ${pattern} ESCAPE '\\'`,
16882
16944
  sql11`${querySnapshots.citedDomains} LIKE ${pattern} ESCAPE '\\'`,
16945
+ sql11`${querySnapshots.citedUrls} LIKE ${pattern} ESCAPE '\\'`,
16883
16946
  sql11`${querySnapshots.rawResponse} LIKE ${pattern} ESCAPE '\\'`,
16884
16947
  like2(queries.query, pattern)
16885
16948
  )
@@ -17334,6 +17397,7 @@ function buildSnapshotHit(row, searchTerm) {
17334
17397
  const query = row.queryText ?? "";
17335
17398
  const answer = row.answerText ?? "";
17336
17399
  const citedJoined = row.citedDomains.join(",");
17400
+ const citedUrlsJoined = row.citedUrls?.join(",") ?? "";
17337
17401
  const raw = row.rawResponse ?? "";
17338
17402
  let matchedField;
17339
17403
  let snippet;
@@ -17343,6 +17407,9 @@ function buildSnapshotHit(row, searchTerm) {
17343
17407
  } else if (citedJoined.toLowerCase().includes(lower)) {
17344
17408
  matchedField = "citedDomains";
17345
17409
  snippet = makeSnippet(citedJoined, searchTerm);
17410
+ } else if (citedUrlsJoined.toLowerCase().includes(lower)) {
17411
+ matchedField = "citedUrls";
17412
+ snippet = makeSnippet(citedUrlsJoined, searchTerm);
17346
17413
  } else if (raw.toLowerCase().includes(lower)) {
17347
17414
  matchedField = "searchQueries";
17348
17415
  snippet = makeSnippet(raw, searchTerm);
@@ -17519,6 +17586,7 @@ var SCHEMA_TABLE = {
17519
17586
  ProjectConfig: projectConfigSchema,
17520
17587
  ProjectOverviewDto: projectOverviewDtoSchema,
17521
17588
  ProjectReportDto: projectReportDtoSchema,
17589
+ ProjectSearchResponseDto: projectSearchResponseSchema,
17522
17590
  QueryDto: queryDtoSchema,
17523
17591
  ResultsExportDto: resultsExportDtoSchema,
17524
17592
  RunDetailDto: runDetailDtoSchema,
@@ -21713,7 +21781,7 @@ var routeCatalog = [
21713
21781
  method: "get",
21714
21782
  path: "/api/v1/projects/{name}/search",
21715
21783
  summary: "Search query snapshots and insights for text",
21716
- description: "Returns the most recent snapshots and insights whose answer text, cited domains, raw response, or insight title/query/recommendation/cause matches the query. Use to find anything mentioning a competitor, term, or URL without paginating snapshots.",
21784
+ description: "Returns the most recent snapshots and insights whose answer text, cited domains, captured cited URLs, raw response, or insight title/query/recommendation/cause matches the query. Use to find anything mentioning a competitor, term, or URL without paginating snapshots.",
21717
21785
  tags: ["intelligence"],
21718
21786
  parameters: [
21719
21787
  nameParameter,
@@ -21721,8 +21789,7 @@ var routeCatalog = [
21721
21789
  { name: "limit", in: "query", description: "Max combined hits (1-50, default 25).", schema: stringSchema }
21722
21790
  ],
21723
21791
  responses: {
21724
- // TODO: Add `ProjectSearchResponseDto` Zod schema in contracts (projectSearchResponseSchema exists).
21725
- 200: rawJsonResponse("Search hits returned.", looseObjectSchema),
21792
+ 200: jsonResponse("Search hits returned.", "ProjectSearchResponseDto"),
21726
21793
  400: errorResponse("Query string missing or too short."),
21727
21794
  404: errorResponse("Project not found.")
21728
21795
  }
@@ -42,7 +42,7 @@ import {
42
42
  trafficConnectWordpressRequestSchema,
43
43
  trafficEventKindSchema,
44
44
  trafficSeriesGranularitySchema
45
- } from "./chunk-7RF5EDUO.js";
45
+ } from "./chunk-RJ7OW6W6.js";
46
46
 
47
47
  // src/config.ts
48
48
  import fs from "fs";