@canonry/canonry 4.136.2 → 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 (30) hide show
  1. package/README.md +2 -1
  2. package/assets/assets/{AuditHistoryPanel-DtUGiN21.js → AuditHistoryPanel-CIdoSKjP.js} +1 -1
  3. package/assets/assets/{BacklinksPage-BGwtmwfz.js → BacklinksPage-BYnzQLFq.js} +1 -1
  4. package/assets/assets/{ChartPrimitives-Df2UC1g3.js → ChartPrimitives-bx4p5MDx.js} +1 -1
  5. package/assets/assets/{HistoryPage-AtaMVEUx.js → HistoryPage-CjLb8TKY.js} +1 -1
  6. package/assets/assets/ProjectPage-C_bSGiLs.js +8 -0
  7. package/assets/assets/{RunRow-Cmf-5xVo.js → RunRow-D6W6D1BX.js} +1 -1
  8. package/assets/assets/{RunsPage-BAPy9Yri.js → RunsPage-CQT4lXFp.js} +1 -1
  9. package/assets/assets/{SettingsPage-BXO7WpTo.js → SettingsPage-DVQKzz6s.js} +1 -1
  10. package/assets/assets/{TrafficPage-IH-wiPu2.js → TrafficPage-BdocLgWw.js} +1 -1
  11. package/assets/assets/{TrafficSourceDetailPage-CTTN-P52.js → TrafficSourceDetailPage-CTZF_R9C.js} +1 -1
  12. package/assets/assets/{arrow-left-BwzAIeJ_.js → arrow-left-ClC65OiR.js} +1 -1
  13. package/assets/assets/extract-error-message-CsgTjzyj.js +1 -0
  14. package/assets/assets/index-BZgknVrZ.js +213 -0
  15. package/assets/assets/{index-CglduHCN.css → index-DY7GziwY.css} +1 -1
  16. package/assets/assets/{trash-2-C50OeBAV.js → trash-2-nr8RRH47.js} +1 -1
  17. package/assets/index.html +2 -2
  18. package/dist/{chunk-MXR3GI5L.js → chunk-3KGJ7BXW.js} +234 -16
  19. package/dist/{chunk-YVMQWVNY.js → chunk-GO24URVP.js} +187 -15
  20. package/dist/{chunk-SMFUCXHI.js → chunk-R3GAWKHM.js} +1 -1
  21. package/dist/{chunk-GGIRLRAY.js → chunk-RJ7OW6W6.js} +3076 -2904
  22. package/dist/cli.js +147 -33
  23. package/dist/index.d.ts +2 -0
  24. package/dist/index.js +4 -4
  25. package/dist/{intelligence-service-BD6BHTEJ.js → intelligence-service-5RJHJLYA.js} +2 -2
  26. package/dist/mcp.js +2 -2
  27. package/package.json +11 -11
  28. package/assets/assets/ProjectPage-OlBjxXNx.js +0 -8
  29. package/assets/assets/extract-error-message-BIcIoJLN.js +0 -1
  30. package/assets/assets/index-BPpSrJY0.js +0 -210
@@ -264,6 +264,8 @@ import {
264
264
  mentionStateFromAnswerMentioned,
265
265
  missingDependency,
266
266
  modelIdsEquivalent,
267
+ noProvider,
268
+ noQueries,
267
269
  normalizeIdTokens,
268
270
  normalizeModelId,
269
271
  normalizeProjectAliases,
@@ -273,6 +275,7 @@ import {
273
275
  notFound,
274
276
  notImplemented,
275
277
  notificationDtoSchema,
278
+ onboardingTelemetryEventSchema,
276
279
  operationInProgress,
277
280
  orderLocationsDefaultFirst,
278
281
  organicEvidenceDtoSchema,
@@ -286,6 +289,7 @@ import {
286
289
  projectDtoSchema,
287
290
  projectOverviewDtoSchema,
288
291
  projectReportDtoSchema,
292
+ projectSearchResponseSchema,
289
293
  projectUpsertRequestSchema,
290
294
  providerError,
291
295
  queryDtoSchema,
@@ -338,6 +342,7 @@ import {
338
342
  summarizeCheckResults,
339
343
  surfaceClassFromCompetitorType,
340
344
  surfaceClassLabel,
345
+ telemetryEventAcceptedDtoSchema,
341
346
  textContainsAnyBrandAlias,
342
347
  textContainsBrandAlias,
343
348
  textContainsDomain,
@@ -373,7 +378,7 @@ import {
373
378
  wordpressSchemaDeployResultDtoSchema,
374
379
  wordpressSchemaStatusResultDtoSchema,
375
380
  wordpressStatusDtoSchema
376
- } from "./chunk-GGIRLRAY.js";
381
+ } from "./chunk-RJ7OW6W6.js";
377
382
 
378
383
  // src/intelligence-service.ts
379
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";
@@ -549,6 +554,13 @@ var querySnapshots = sqliteTable("query_snapshots", {
549
554
  answerMentioned: integer("answer_mentioned", { mode: "boolean" }),
550
555
  answerText: text("answer_text"),
551
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"),
552
564
  competitorOverlap: text("competitor_overlap", { mode: "json" }).$type().notNull().default([]),
553
565
  recommendedCompetitors: text("recommended_competitors", { mode: "json" }).$type().notNull().default([]),
554
566
  location: text("location"),
@@ -4295,6 +4307,19 @@ var MIGRATION_VERSIONS = [
4295
4307
  `ALTER TABLE research_run_queries ADD COLUMN named_competitors TEXT NOT NULL DEFAULT '[]'`,
4296
4308
  `ALTER TABLE research_run_queries ADD COLUMN cited_competitor_domains TEXT NOT NULL DEFAULT '[]'`
4297
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
+ ]
4298
4323
  }
4299
4324
  ];
4300
4325
  function rebuildBacklinkTableWithSource(tx, table) {
@@ -7969,9 +7994,20 @@ async function runRoutes(app, opts) {
7969
7994
  rawProviders.splice(0, rawProviders.length, ...normalized);
7970
7995
  }
7971
7996
  const providers = rawProviders?.length ? rawProviders : void 0;
7997
+ const shouldPreflight = trigger !== RunTriggers.probe && opts.getRunnableProviderNames !== void 0;
7998
+ const trackedRows = body.queries?.length || shouldPreflight ? app.db.select({ query: queries.query }).from(queries).where(eq8(queries.projectId, project.id)).all() : [];
7999
+ if (shouldPreflight) {
8000
+ const preflightError = answerVisibilityPreflightError({
8001
+ projectName: project.name,
8002
+ projectProviders: project.providers,
8003
+ requestedProviders: providers,
8004
+ runnableProviderNames: opts.getRunnableProviderNames(),
8005
+ trackedQueryCount: trackedRows.length
8006
+ });
8007
+ if (preflightError) throw preflightError;
8008
+ }
7972
8009
  let scopedQueries = null;
7973
8010
  if (body.queries?.length) {
7974
- const trackedRows = app.db.select({ query: queries.query }).from(queries).where(eq8(queries.projectId, project.id)).all();
7975
8011
  const tracked = new Set(trackedRows.map((r) => r.query));
7976
8012
  const missing = body.queries.filter((q) => !tracked.has(q));
7977
8013
  if (missing.length) {
@@ -8135,7 +8171,28 @@ async function runRoutes(app, opts) {
8135
8171
  const providers = rawProviders?.length ? rawProviders : void 0;
8136
8172
  const now = (/* @__PURE__ */ new Date()).toISOString();
8137
8173
  const results = [];
8174
+ const runnableProviderNames = opts.getRunnableProviderNames?.();
8138
8175
  for (const project of allProjects) {
8176
+ if (runnableProviderNames) {
8177
+ const trackedQuery = app.db.select({ id: queries.id }).from(queries).where(eq8(queries.projectId, project.id)).limit(1).get();
8178
+ const preflightError = answerVisibilityPreflightError({
8179
+ projectName: project.name,
8180
+ projectProviders: project.providers,
8181
+ requestedProviders: providers,
8182
+ runnableProviderNames,
8183
+ trackedQueryCount: trackedQuery ? 1 : 0
8184
+ });
8185
+ if (preflightError) {
8186
+ results.push({
8187
+ projectName: project.name,
8188
+ projectId: project.id,
8189
+ status: "error",
8190
+ error: preflightError.message,
8191
+ errorCode: preflightError.code
8192
+ });
8193
+ continue;
8194
+ }
8195
+ }
8139
8196
  const projectLocations = project.locations;
8140
8197
  let resolvedLocation;
8141
8198
  if (project.defaultLocation) {
@@ -8199,6 +8256,26 @@ async function runRoutes(app, opts) {
8199
8256
  return reply.send(loadRunDetail(app, run));
8200
8257
  });
8201
8258
  }
8259
+ function answerVisibilityPreflightError(input) {
8260
+ if (input.trackedQueryCount === 0) {
8261
+ return noQueries(input.projectName);
8262
+ }
8263
+ const availableProviders = normalizeProviderNames(input.runnableProviderNames);
8264
+ const requestedProviders = normalizeProviderNames(input.requestedProviders ?? []);
8265
+ const projectProviders = normalizeProviderNames(input.projectProviders);
8266
+ const selectedProviders = requestedProviders.length > 0 ? requestedProviders : projectProviders.length > 0 ? projectProviders : availableProviders;
8267
+ const available = new Set(availableProviders);
8268
+ const runnableProviders = selectedProviders.filter((provider) => available.has(provider));
8269
+ if (runnableProviders.length > 0) return null;
8270
+ return noProvider(input.projectName, {
8271
+ availableProviders,
8272
+ selectedProviders,
8273
+ selectionSource: requestedProviders.length > 0 ? "request" : projectProviders.length > 0 ? "project" : "instance"
8274
+ });
8275
+ }
8276
+ function normalizeProviderNames(providerNames) {
8277
+ return [...new Set(providerNames.map((name) => name.trim().toLowerCase()).filter(Boolean))];
8278
+ }
8202
8279
  function parseRunTriggerRequest(value) {
8203
8280
  const result = runTriggerRequestSchema.safeParse(value);
8204
8281
  if (result.success) return result.data;
@@ -8278,6 +8355,11 @@ function loadRunDetail(app, run) {
8278
8355
  answerMentioned: querySnapshots.answerMentioned,
8279
8356
  answerText: querySnapshots.answerText,
8280
8357
  citedDomains: querySnapshots.citedDomains,
8358
+ citedUrls: querySnapshots.citedUrls,
8359
+ captureStatus: querySnapshots.captureStatus,
8360
+ sourceCount: querySnapshots.sourceCount,
8361
+ resolvedCount: querySnapshots.resolvedCount,
8362
+ captureVersion: querySnapshots.captureVersion,
8281
8363
  competitorOverlap: querySnapshots.competitorOverlap,
8282
8364
  recommendedCompetitors: querySnapshots.recommendedCompetitors,
8283
8365
  location: querySnapshots.location,
@@ -8303,6 +8385,11 @@ function loadRunDetail(app, run) {
8303
8385
  mentionState: project ? resolveSnapshotMentionState(s, project) : answerMentioned ? "mentioned" : "not-mentioned",
8304
8386
  answerText: s.answerText,
8305
8387
  citedDomains: s.citedDomains,
8388
+ citedUrls: s.citedUrls,
8389
+ captureStatus: s.captureStatus,
8390
+ sourceCount: s.sourceCount,
8391
+ resolvedCount: s.resolvedCount,
8392
+ captureVersion: s.captureVersion,
8306
8393
  competitorOverlap: s.competitorOverlap,
8307
8394
  recommendedCompetitors: s.recommendedCompetitors,
8308
8395
  matchedTerms: project ? resolveSnapshotMatchedTerms(s, project) : [],
@@ -8957,6 +9044,11 @@ async function historyRoutes(app) {
8957
9044
  answerMentioned: querySnapshots.answerMentioned,
8958
9045
  answerText: querySnapshots.answerText,
8959
9046
  citedDomains: querySnapshots.citedDomains,
9047
+ citedUrls: querySnapshots.citedUrls,
9048
+ captureStatus: querySnapshots.captureStatus,
9049
+ sourceCount: querySnapshots.sourceCount,
9050
+ resolvedCount: querySnapshots.resolvedCount,
9051
+ captureVersion: querySnapshots.captureVersion,
8960
9052
  competitorOverlap: querySnapshots.competitorOverlap,
8961
9053
  recommendedCompetitors: querySnapshots.recommendedCompetitors,
8962
9054
  location: querySnapshots.location,
@@ -8980,6 +9072,11 @@ async function historyRoutes(app) {
8980
9072
  mentionState: resolveSnapshotMentionState(s, project),
8981
9073
  answerText: s.answerText,
8982
9074
  citedDomains: s.citedDomains,
9075
+ citedUrls: s.citedUrls,
9076
+ captureStatus: s.captureStatus,
9077
+ sourceCount: s.sourceCount,
9078
+ resolvedCount: s.resolvedCount,
9079
+ captureVersion: s.captureVersion,
8983
9080
  competitorOverlap: s.competitorOverlap,
8984
9081
  recommendedCompetitors: s.recommendedCompetitors,
8985
9082
  location: s.location,
@@ -16453,6 +16550,11 @@ var CSV_COLUMNS = [
16453
16550
  "answer_mentioned",
16454
16551
  "mention_state",
16455
16552
  "cited_domains_json",
16553
+ "cited_urls_json",
16554
+ "capture_status",
16555
+ "source_count",
16556
+ "resolved_count",
16557
+ "capture_version",
16456
16558
  "competitor_overlap_json",
16457
16559
  "recommended_competitors_json",
16458
16560
  "answer_text",
@@ -16534,6 +16636,11 @@ function renderResultsExportCsv(report) {
16534
16636
  record.answerMentioned,
16535
16637
  record.mentionState,
16536
16638
  JSON.stringify(record.citedDomains),
16639
+ JSON.stringify(record.citedUrls),
16640
+ record.captureStatus,
16641
+ record.sourceCount,
16642
+ record.resolvedCount,
16643
+ record.captureVersion,
16537
16644
  JSON.stringify(record.competitorOverlap),
16538
16645
  JSON.stringify(record.recommendedCompetitors),
16539
16646
  record.answerText,
@@ -16578,6 +16685,11 @@ async function resultsExportRoutes(app) {
16578
16685
  citationState: querySnapshots.citationState,
16579
16686
  answerMentioned: querySnapshots.answerMentioned,
16580
16687
  citedDomains: querySnapshots.citedDomains,
16688
+ citedUrls: querySnapshots.citedUrls,
16689
+ captureStatus: querySnapshots.captureStatus,
16690
+ sourceCount: querySnapshots.sourceCount,
16691
+ resolvedCount: querySnapshots.resolvedCount,
16692
+ captureVersion: querySnapshots.captureVersion,
16581
16693
  competitorOverlap: querySnapshots.competitorOverlap,
16582
16694
  recommendedCompetitors: querySnapshots.recommendedCompetitors,
16583
16695
  answerText: querySnapshots.answerText,
@@ -16606,6 +16718,11 @@ async function resultsExportRoutes(app) {
16606
16718
  answerMentioned: row.answerMentioned,
16607
16719
  mentionState: recordMentionState(row.answerMentioned),
16608
16720
  citedDomains: row.citedDomains,
16721
+ citedUrls: row.citedUrls,
16722
+ captureStatus: row.captureStatus,
16723
+ sourceCount: row.sourceCount,
16724
+ resolvedCount: row.resolvedCount,
16725
+ captureVersion: row.captureVersion,
16609
16726
  competitorOverlap: row.competitorOverlap,
16610
16727
  recommendedCompetitors: row.recommendedCompetitors,
16611
16728
  answerText: row.answerText,
@@ -16816,6 +16933,7 @@ async function compositeRoutes(app) {
16816
16933
  citationState: querySnapshots.citationState,
16817
16934
  answerText: querySnapshots.answerText,
16818
16935
  citedDomains: querySnapshots.citedDomains,
16936
+ citedUrls: querySnapshots.citedUrls,
16819
16937
  rawResponse: querySnapshots.rawResponse,
16820
16938
  createdAt: querySnapshots.createdAt
16821
16939
  }).from(querySnapshots).innerJoin(queries, eq22(querySnapshots.queryId, queries.id)).where(
@@ -16824,6 +16942,7 @@ async function compositeRoutes(app) {
16824
16942
  or6(
16825
16943
  sql11`${querySnapshots.answerText} LIKE ${pattern} ESCAPE '\\'`,
16826
16944
  sql11`${querySnapshots.citedDomains} LIKE ${pattern} ESCAPE '\\'`,
16945
+ sql11`${querySnapshots.citedUrls} LIKE ${pattern} ESCAPE '\\'`,
16827
16946
  sql11`${querySnapshots.rawResponse} LIKE ${pattern} ESCAPE '\\'`,
16828
16947
  like2(queries.query, pattern)
16829
16948
  )
@@ -17278,6 +17397,7 @@ function buildSnapshotHit(row, searchTerm) {
17278
17397
  const query = row.queryText ?? "";
17279
17398
  const answer = row.answerText ?? "";
17280
17399
  const citedJoined = row.citedDomains.join(",");
17400
+ const citedUrlsJoined = row.citedUrls?.join(",") ?? "";
17281
17401
  const raw = row.rawResponse ?? "";
17282
17402
  let matchedField;
17283
17403
  let snippet;
@@ -17287,6 +17407,9 @@ function buildSnapshotHit(row, searchTerm) {
17287
17407
  } else if (citedJoined.toLowerCase().includes(lower)) {
17288
17408
  matchedField = "citedDomains";
17289
17409
  snippet = makeSnippet(citedJoined, searchTerm);
17410
+ } else if (citedUrlsJoined.toLowerCase().includes(lower)) {
17411
+ matchedField = "citedUrls";
17412
+ snippet = makeSnippet(citedUrlsJoined, searchTerm);
17290
17413
  } else if (raw.toLowerCase().includes(lower)) {
17291
17414
  matchedField = "searchQueries";
17292
17415
  snippet = makeSnippet(raw, searchTerm);
@@ -17456,12 +17579,14 @@ var SCHEMA_TABLE = {
17456
17579
  LatestProjectRunDto: latestProjectRunDtoSchema,
17457
17580
  LocationContext: locationContextSchema,
17458
17581
  NotificationDto: notificationDtoSchema,
17582
+ OnboardingTelemetryEvent: onboardingTelemetryEventSchema,
17459
17583
  OrganicEvidenceDto: organicEvidenceDtoSchema,
17460
17584
  ProjectDto: projectDtoSchema,
17461
17585
  ProjectUpsertRequest: projectUpsertRequestSchema,
17462
17586
  ProjectConfig: projectConfigSchema,
17463
17587
  ProjectOverviewDto: projectOverviewDtoSchema,
17464
17588
  ProjectReportDto: projectReportDtoSchema,
17589
+ ProjectSearchResponseDto: projectSearchResponseSchema,
17465
17590
  QueryDto: queryDtoSchema,
17466
17591
  ResultsExportDto: resultsExportDtoSchema,
17467
17592
  RunDetailDto: runDetailDtoSchema,
@@ -17477,6 +17602,7 @@ var SCHEMA_TABLE = {
17477
17602
  SnapshotListResponse: snapshotListResponseSchema,
17478
17603
  SnapshotReportDto: snapshotReportSchema,
17479
17604
  SourceBreakdownDto: sourceBreakdownDtoSchema,
17605
+ TelemetryEventAcceptedDto: telemetryEventAcceptedDtoSchema,
17480
17606
  TrafficBackfillResponse: trafficBackfillResponseSchema,
17481
17607
  TrafficEventsResponse: trafficEventsResponseSchema,
17482
17608
  TrafficSourceDetailDto: trafficSourceDetailDtoSchema,
@@ -18502,7 +18628,9 @@ var routeCatalog = [
18502
18628
  },
18503
18629
  responses: {
18504
18630
  201: jsonResponse("Run queued.", "RunDto"),
18505
- 409: errorResponse("Run already in progress.")
18631
+ 422: errorResponse("Project has no tracked queries."),
18632
+ 409: errorResponse("Run already in progress."),
18633
+ 503: errorResponse("No runnable answer provider is configured.")
18506
18634
  }
18507
18635
  },
18508
18636
  {
@@ -19127,6 +19255,24 @@ var routeCatalog = [
19127
19255
  501: errorResponse("Telemetry configuration is not available.")
19128
19256
  }
19129
19257
  },
19258
+ {
19259
+ method: "post",
19260
+ path: "/api/v1/telemetry/onboarding",
19261
+ summary: "Record a privacy-safe onboarding milestone",
19262
+ tags: ["telemetry"],
19263
+ requestBody: {
19264
+ required: true,
19265
+ content: {
19266
+ "application/json": {
19267
+ schema: { $ref: "#/components/schemas/OnboardingTelemetryEvent" }
19268
+ }
19269
+ }
19270
+ },
19271
+ responses: {
19272
+ 202: jsonResponse("Onboarding milestone accepted.", "TelemetryEventAcceptedDto"),
19273
+ 400: errorResponse("Invalid onboarding telemetry event.")
19274
+ }
19275
+ },
19130
19276
  {
19131
19277
  method: "get",
19132
19278
  path: "/api/v1/screenshots/{snapshotId}",
@@ -21635,7 +21781,7 @@ var routeCatalog = [
21635
21781
  method: "get",
21636
21782
  path: "/api/v1/projects/{name}/search",
21637
21783
  summary: "Search query snapshots and insights for text",
21638
- 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.",
21639
21785
  tags: ["intelligence"],
21640
21786
  parameters: [
21641
21787
  nameParameter,
@@ -21643,8 +21789,7 @@ var routeCatalog = [
21643
21789
  { name: "limit", in: "query", description: "Max combined hits (1-50, default 25).", schema: stringSchema }
21644
21790
  ],
21645
21791
  responses: {
21646
- // TODO: Add `ProjectSearchResponseDto` Zod schema in contracts (projectSearchResponseSchema exists).
21647
- 200: rawJsonResponse("Search hits returned.", looseObjectSchema),
21792
+ 200: jsonResponse("Search hits returned.", "ProjectSearchResponseDto"),
21648
21793
  400: errorResponse("Query string missing or too short."),
21649
21794
  404: errorResponse("Project not found.")
21650
21795
  }
@@ -22777,6 +22922,19 @@ async function telemetryRoutes(app, opts) {
22777
22922
  anonymousId: status?.anonymousId ? status.anonymousId.slice(0, 8) + "..." : void 0
22778
22923
  };
22779
22924
  });
22925
+ app.post("/telemetry/onboarding", async (request, reply) => {
22926
+ const parsed = onboardingTelemetryEventSchema.safeParse(request.body);
22927
+ if (!parsed.success) {
22928
+ throw validationError("Invalid onboarding telemetry event", {
22929
+ issues: parsed.error.issues.map((issue) => ({
22930
+ code: issue.code,
22931
+ path: issue.path.join(".")
22932
+ }))
22933
+ });
22934
+ }
22935
+ opts.recordOnboardingEvent?.(parsed.data);
22936
+ return reply.status(202).send({ accepted: Boolean(opts.recordOnboardingEvent) });
22937
+ });
22780
22938
  }
22781
22939
 
22782
22940
  // ../api-routes/src/schedules.ts
@@ -24798,6 +24956,24 @@ function stableStringify3(value) {
24798
24956
  }
24799
24957
 
24800
24958
  // ../api-routes/src/google.ts
24959
+ var GOOGLE_OAUTH_COMPLETE_MESSAGE = "canonry:google-oauth-complete";
24960
+ function googleOAuthSuccessHtml(type) {
24961
+ const message = JSON.stringify({
24962
+ type: GOOGLE_OAUTH_COMPLETE_MESSAGE,
24963
+ connectionType: type
24964
+ });
24965
+ return `<html><body style="font-family:system-ui;text-align:center;padding:60px">
24966
+ <h2>Connected successfully!</h2>
24967
+ <p>Google ${type.toUpperCase()} has been linked to your domain.</p>
24968
+ <p style="color:#888">This window closes automatically.</p>
24969
+ <script>
24970
+ if (window.opener && !window.opener.closed) {
24971
+ window.opener.postMessage(${message}, '*')
24972
+ window.close()
24973
+ }
24974
+ </script>
24975
+ </body></html>`;
24976
+ }
24801
24977
  function isOnProjectDomain(url, projectDomain) {
24802
24978
  const urlHost = hostOf(url);
24803
24979
  const projectHost = hostOf(projectDomain);
@@ -25123,13 +25299,7 @@ async function googleRoutes(app, opts) {
25123
25299
  entityId: type,
25124
25300
  diff: { domain, type, propertyId }
25125
25301
  });
25126
- return reply.type("text/html").send(
25127
- `<html><body style="font-family:system-ui;text-align:center;padding:60px">
25128
- <h2>Connected successfully!</h2>
25129
- <p>Google ${type.toUpperCase()} has been linked to your domain.</p>
25130
- <p style="color:#888">You can close this tab.</p>
25131
- </body></html>`
25132
- );
25302
+ return reply.type("text/html").send(googleOAuthSuccessHtml(type));
25133
25303
  }
25134
25304
  app.get("/google/callback", async (request, reply) => {
25135
25305
  return handleOAuthCallback(request, reply);
@@ -44159,7 +44329,8 @@ async function apiRoutes(app, opts) {
44159
44329
  await api.register(competitorRoutes);
44160
44330
  await api.register(runRoutes, {
44161
44331
  onRunCreated: opts.onRunCreated,
44162
- validProviderNames: opts.providerAdapters?.map((a) => a.name)
44332
+ validProviderNames: opts.providerAdapters?.map((a) => a.name),
44333
+ getRunnableProviderNames: opts.getRunnableProviderNames
44163
44334
  });
44164
44335
  await api.register(applyRoutes, {
44165
44336
  onScheduleUpdated: opts.onScheduleUpdated,
@@ -44210,7 +44381,8 @@ async function apiRoutes(app, opts) {
44210
44381
  });
44211
44382
  await api.register(telemetryRoutes, {
44212
44383
  getTelemetryStatus: opts.getTelemetryStatus,
44213
- setTelemetryEnabled: opts.setTelemetryEnabled
44384
+ setTelemetryEnabled: opts.setTelemetryEnabled,
44385
+ recordOnboardingEvent: opts.recordOnboardingEvent
44214
44386
  });
44215
44387
  await api.register(adsRoutes, {
44216
44388
  adsCredentialStore: opts.adsCredentialStore,
@@ -42,7 +42,7 @@ import {
42
42
  trafficConnectWordpressRequestSchema,
43
43
  trafficEventKindSchema,
44
44
  trafficSeriesGranularitySchema
45
- } from "./chunk-GGIRLRAY.js";
45
+ } from "./chunk-RJ7OW6W6.js";
46
46
 
47
47
  // src/config.ts
48
48
  import fs from "fs";