@ainyc/canonry 4.99.0 → 4.99.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.
Files changed (25) hide show
  1. package/assets/assets/{BacklinksPage-CuWs7I1D.js → BacklinksPage-v2RC8wlg.js} +1 -1
  2. package/assets/assets/{ChartPrimitives-bm37tprp.js → ChartPrimitives-B74e5pqn.js} +1 -1
  3. package/assets/assets/ProjectPage-BCzS7TQn.js +6 -0
  4. package/assets/assets/{RunRow-DzhQl87g.js → RunRow-BmVPjO-m.js} +1 -1
  5. package/assets/assets/{RunsPage-wOaewhbF.js → RunsPage-CK5atXvL.js} +1 -1
  6. package/assets/assets/{SettingsPage-CJdhhkkE.js → SettingsPage-DarPFUPl.js} +1 -1
  7. package/assets/assets/{TrafficPage-BJBeN5Ph.js → TrafficPage-Ddnn_WqU.js} +1 -1
  8. package/assets/assets/{TrafficSourceDetailPage-D3PmH0B1.js → TrafficSourceDetailPage-g08SKnwZ.js} +1 -1
  9. package/assets/assets/{arrow-left-BmITMI6O.js → arrow-left-D39Vxasb.js} +1 -1
  10. package/assets/assets/{extract-error-message-BGwnyAfP.js → extract-error-message-BiNWqBeh.js} +1 -1
  11. package/assets/assets/{index-BsZNCwg8.css → index-BCuWbxUj.css} +1 -1
  12. package/assets/assets/index-Dd4J1VhB.js +210 -0
  13. package/assets/assets/{trash-2-Bd2mkP_w.js → trash-2-xh6gsnap.js} +1 -1
  14. package/assets/index.html +2 -2
  15. package/dist/{chunk-CEHD33NQ.js → chunk-4Q3LBD7A.js} +251 -111
  16. package/dist/{chunk-VQN74WWA.js → chunk-IDI6LMYL.js} +1 -1
  17. package/dist/{chunk-CWFTMFEU.js → chunk-JF7EXHGA.js} +12 -3
  18. package/dist/{chunk-DJVUNURL.js → chunk-YBIT5O62.js} +36 -29
  19. package/dist/cli.js +4 -4
  20. package/dist/index.js +4 -4
  21. package/dist/{intelligence-service-QHBXW4KI.js → intelligence-service-TWCEKVKZ.js} +2 -2
  22. package/dist/mcp.js +2 -2
  23. package/package.json +8 -8
  24. package/assets/assets/ProjectPage-BksYe8FP.js +0 -6
  25. package/assets/assets/index-BSX6r6ju.js +0 -210
@@ -9,7 +9,7 @@ import {
9
9
  loadConfig,
10
10
  loadConfigRaw,
11
11
  saveConfigPatch
12
- } from "./chunk-VQN74WWA.js";
12
+ } from "./chunk-IDI6LMYL.js";
13
13
  import {
14
14
  CC_CACHE_DIR,
15
15
  DUCKDB_SPEC,
@@ -111,7 +111,7 @@ import {
111
111
  siteAuditPages,
112
112
  siteAuditSnapshots,
113
113
  usageCounters
114
- } from "./chunk-DJVUNURL.js";
114
+ } from "./chunk-YBIT5O62.js";
115
115
  import {
116
116
  AGENT_MEMORY_VALUE_MAX_BYTES,
117
117
  AGENT_PROVIDER_IDS,
@@ -171,7 +171,7 @@ import {
171
171
  validationError,
172
172
  winnabilityClassLabel,
173
173
  withRetry
174
- } from "./chunk-CWFTMFEU.js";
174
+ } from "./chunk-JF7EXHGA.js";
175
175
 
176
176
  // src/telemetry.ts
177
177
  import crypto from "crypto";
@@ -1473,7 +1473,8 @@ function extractWebSearchToolErrors(rawResponse) {
1473
1473
  if (!content) return [];
1474
1474
  for (const block of content) {
1475
1475
  if (block.type !== "web_search_tool_result") continue;
1476
- if (block.content === null || typeof block.content !== "object" || Array.isArray(block.content)) continue;
1476
+ if (block.content === null || typeof block.content !== "object" || Array.isArray(block.content))
1477
+ continue;
1477
1478
  const errorCode = block.content.error_code;
1478
1479
  if (typeof errorCode === "string" && errorCode.length > 0) {
1479
1480
  errors.add(errorCode);
@@ -6402,7 +6403,7 @@ function readStoredGroundingSources(rawResponse) {
6402
6403
  return result;
6403
6404
  }
6404
6405
  async function backfillInsightsCommand(project, opts) {
6405
- const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-QHBXW4KI.js");
6406
+ const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-TWCEKVKZ.js");
6406
6407
  const config = loadConfig();
6407
6408
  const db = createClient(config.database);
6408
6409
  migrate(db);
@@ -10425,9 +10426,7 @@ var API_ADAPTERS = [
10425
10426
  localAdapter,
10426
10427
  perplexityAdapter
10427
10428
  ];
10428
- var BROWSER_ADAPTERS = [
10429
- cdpChatgptAdapter
10430
- ];
10429
+ var BROWSER_ADAPTERS = [cdpChatgptAdapter];
10431
10430
  var adapterMap = Object.fromEntries(
10432
10431
  API_ADAPTERS.map((a) => [a.name, a])
10433
10432
  );
@@ -10477,13 +10476,18 @@ function verifyDashboardPassword(password, storedHash) {
10477
10476
  N: DASHBOARD_SCRYPT_COST,
10478
10477
  maxmem: DASHBOARD_SCRYPT_MAXMEM
10479
10478
  });
10480
- if (derived.length !== expected.length) return { ok: false, needsRehash: false };
10481
- return { ok: crypto20.timingSafeEqual(derived, expected), needsRehash: false };
10479
+ if (derived.length !== expected.length)
10480
+ return { ok: false, needsRehash: false };
10481
+ return {
10482
+ ok: crypto20.timingSafeEqual(derived, expected),
10483
+ needsRehash: false
10484
+ };
10482
10485
  }
10483
10486
  if (/^[a-f0-9]{64}$/i.test(storedHash)) {
10484
10487
  const candidate = Buffer.from(hashApiKey(password), "hex");
10485
10488
  const expected = Buffer.from(storedHash, "hex");
10486
- if (candidate.length !== expected.length) return { ok: false, needsRehash: false };
10489
+ if (candidate.length !== expected.length)
10490
+ return { ok: false, needsRehash: false };
10487
10491
  const ok = crypto20.timingSafeEqual(candidate, expected);
10488
10492
  return { ok, needsRehash: ok };
10489
10493
  }
@@ -10525,7 +10529,11 @@ function serializeSessionCookie(opts) {
10525
10529
  function applyLegacyCredentials(rows, config) {
10526
10530
  let migratedGoogle = 0;
10527
10531
  for (const row of rows.google) {
10528
- const existing = getGoogleConnection(config, row.domain, row.connectionType);
10532
+ const existing = getGoogleConnection(
10533
+ config,
10534
+ row.domain,
10535
+ row.connectionType
10536
+ );
10529
10537
  if (existing?.refreshToken) continue;
10530
10538
  upsertGoogleConnection(config, {
10531
10539
  domain: row.domain,
@@ -10604,10 +10612,12 @@ async function createServer(opts) {
10604
10612
  error: err instanceof Error ? err.message : String(err)
10605
10613
  });
10606
10614
  }
10607
- log21.info("providers.configured", { providers: Object.keys(providers).filter((k) => {
10608
- const p = providers[k];
10609
- return p?.apiKey || p?.baseUrl || p?.vertexProject;
10610
- }) });
10615
+ log21.info("providers.configured", {
10616
+ providers: Object.keys(providers).filter((k) => {
10617
+ const p = providers[k];
10618
+ return p?.apiKey || p?.baseUrl || p?.vertexProject;
10619
+ })
10620
+ });
10611
10621
  for (const adapter of API_ADAPTERS) {
10612
10622
  const entry = providers[adapter.name];
10613
10623
  if (!entry) continue;
@@ -10627,7 +10637,11 @@ async function createServer(opts) {
10627
10637
  }
10628
10638
  const cdpConfig = opts.config.cdp;
10629
10639
  if (cdpConfig?.host || cdpConfig?.port) {
10630
- const CDP_DEFAULT_QUOTA = { maxConcurrency: 1, maxRequestsPerMinute: 4, maxRequestsPerDay: 200 };
10640
+ const CDP_DEFAULT_QUOTA = {
10641
+ maxConcurrency: 1,
10642
+ maxRequestsPerMinute: 4,
10643
+ maxRequestsPerDay: 200
10644
+ };
10631
10645
  const cdpEndpoint = `ws://${cdpConfig.host ?? "localhost"}:${cdpConfig.port ?? 9222}`;
10632
10646
  registry.register(cdpChatgptAdapter, {
10633
10647
  provider: "cdp:chatgpt",
@@ -10641,7 +10655,9 @@ async function createServer(opts) {
10641
10655
  jobRunner.recoverStaleRuns();
10642
10656
  const notifier = new Notifier(opts.db, serverUrl);
10643
10657
  const intelligenceService = new IntelligenceService(opts.db);
10644
- const aeroClient = new ApiClient(opts.config.apiUrl, opts.config.apiKey, { skipProbe: true });
10658
+ const aeroClient = new ApiClient(opts.config.apiUrl, opts.config.apiKey, {
10659
+ skipProbe: true
10660
+ });
10645
10661
  const agentEnabled = resolveAgentEnabled(process.env, opts.config);
10646
10662
  const sessionRegistry = agentEnabled ? new SessionRegistry({
10647
10663
  db: opts.db,
@@ -10688,7 +10704,9 @@ async function createServer(opts) {
10688
10704
  const runGbpSync = (runId, projectId, syncOpts) => {
10689
10705
  const { clientId: googleClientId, clientSecret: googleClientSecret } = getGoogleAuthConfig(opts.config);
10690
10706
  if (!googleClientId || !googleClientSecret) {
10691
- app.log.error("GBP sync requested but Google OAuth credentials are not configured in the local config");
10707
+ app.log.error(
10708
+ "GBP sync requested but Google OAuth credentials are not configured in the local config"
10709
+ );
10692
10710
  return;
10693
10711
  }
10694
10712
  executeGbpSync(opts.db, runId, projectId, {
@@ -10741,7 +10759,14 @@ async function createServer(opts) {
10741
10759
  },
10742
10760
  onTrafficSyncRequested: (projectName, sourceId) => {
10743
10761
  aeroClient.trafficSync(projectName, sourceId).catch((err) => {
10744
- app.log.error({ projectName, sourceId, err: err instanceof Error ? err.message : String(err) }, "Scheduled traffic sync failed");
10762
+ app.log.error(
10763
+ {
10764
+ projectName,
10765
+ sourceId,
10766
+ err: err instanceof Error ? err.message : String(err)
10767
+ },
10768
+ "Scheduled traffic sync failed"
10769
+ );
10745
10770
  });
10746
10771
  },
10747
10772
  onGbpSyncRequested: (runId, projectId) => {
@@ -10756,21 +10781,33 @@ async function createServer(opts) {
10756
10781
  onBacklinksSyncRequested: (projectName) => {
10757
10782
  void (async () => {
10758
10783
  const probed = await probeLatestRelease().catch((err) => {
10759
- app.log.warn({ projectName, err }, "Scheduled backlinks sync: latest-release probe failed");
10784
+ app.log.warn(
10785
+ { projectName, err },
10786
+ "Scheduled backlinks sync: latest-release probe failed"
10787
+ );
10760
10788
  return null;
10761
10789
  });
10762
10790
  if (!probed) return;
10763
- const alreadySynced = opts.db.select().from(ccReleaseSyncs).where(and14(
10764
- eq20(ccReleaseSyncs.release, probed.release),
10765
- eq20(ccReleaseSyncs.status, CcReleaseSyncStatuses.ready)
10766
- )).limit(1).get();
10791
+ const alreadySynced = opts.db.select().from(ccReleaseSyncs).where(
10792
+ and14(
10793
+ eq20(ccReleaseSyncs.release, probed.release),
10794
+ eq20(ccReleaseSyncs.status, CcReleaseSyncStatuses.ready)
10795
+ )
10796
+ ).limit(1).get();
10767
10797
  if (alreadySynced) {
10768
- app.log.info({ projectName, release: probed.release }, "Scheduled backlinks sync: already up to date, skipping");
10798
+ app.log.info(
10799
+ { projectName, release: probed.release },
10800
+ "Scheduled backlinks sync: already up to date, skipping"
10801
+ );
10769
10802
  return;
10770
10803
  }
10771
10804
  aeroClient.backlinksTriggerSync(probed.release).catch((err) => {
10772
10805
  app.log.error(
10773
- { projectName, release: probed.release, err: err instanceof Error ? err.message : String(err) },
10806
+ {
10807
+ projectName,
10808
+ release: probed.release,
10809
+ err: err instanceof Error ? err.message : String(err)
10810
+ },
10774
10811
  "Scheduled backlinks sync failed"
10775
10812
  );
10776
10813
  });
@@ -10779,7 +10816,10 @@ async function createServer(opts) {
10779
10816
  if (project && bingConnectionStore.getConnection(project.canonicalDomain)) {
10780
10817
  aeroClient.backlinksBingSync(projectName).catch((err) => {
10781
10818
  app.log.error(
10782
- { projectName, err: err instanceof Error ? err.message : String(err) },
10819
+ {
10820
+ projectName,
10821
+ err: err instanceof Error ? err.message : String(err)
10822
+ },
10783
10823
  "Scheduled Bing backlinks sync failed"
10784
10824
  );
10785
10825
  });
@@ -10801,7 +10841,9 @@ async function createServer(opts) {
10801
10841
  vertexConfigured: adapter.name === "gemini" ? !!opts.config.providers?.gemini?.vertexProject : void 0
10802
10842
  }));
10803
10843
  const googleSettingsSummary = {
10804
- configured: Boolean(opts.config.google?.clientId && opts.config.google?.clientSecret)
10844
+ configured: Boolean(
10845
+ opts.config.google?.clientId && opts.config.google?.clientSecret
10846
+ )
10805
10847
  };
10806
10848
  const bingSettingsSummary = {
10807
10849
  // Treat Bing as configured if there is at least one connection with an API key,
@@ -10818,8 +10860,13 @@ async function createServer(opts) {
10818
10860
  upsertConnection: (connection) => {
10819
10861
  if (!opts.config.bing) opts.config.bing = {};
10820
10862
  if (!opts.config.bing.connections) opts.config.bing.connections = [];
10821
- const idx = opts.config.bing.connections.findIndex((c) => c.domain === connection.domain);
10822
- const normalized = { ...connection, createdByProjectId: connection.createdByProjectId ?? null };
10863
+ const idx = opts.config.bing.connections.findIndex(
10864
+ (c) => c.domain === connection.domain
10865
+ );
10866
+ const normalized = {
10867
+ ...connection,
10868
+ createdByProjectId: connection.createdByProjectId ?? null
10869
+ };
10823
10870
  if (idx >= 0) {
10824
10871
  opts.config.bing.connections[idx] = normalized;
10825
10872
  } else {
@@ -10829,7 +10876,9 @@ async function createServer(opts) {
10829
10876
  return normalized;
10830
10877
  },
10831
10878
  updateConnection: (domain, patch) => {
10832
- const conn = opts.config.bing?.connections?.find((c) => c.domain === domain);
10879
+ const conn = opts.config.bing?.connections?.find(
10880
+ (c) => c.domain === domain
10881
+ );
10833
10882
  if (!conn) return void 0;
10834
10883
  Object.assign(conn, patch);
10835
10884
  saveConfigPatch(opts.config);
@@ -10837,7 +10886,9 @@ async function createServer(opts) {
10837
10886
  },
10838
10887
  deleteConnection: (domain) => {
10839
10888
  if (!opts.config.bing?.connections) return false;
10840
- const idx = opts.config.bing.connections.findIndex((c) => c.domain === domain);
10889
+ const idx = opts.config.bing.connections.findIndex(
10890
+ (c) => c.domain === domain
10891
+ );
10841
10892
  if (idx < 0) return false;
10842
10893
  opts.config.bing.connections.splice(idx, 1);
10843
10894
  saveConfigPatch(opts.config);
@@ -10884,7 +10935,10 @@ async function createServer(opts) {
10884
10935
  return updated;
10885
10936
  },
10886
10937
  deleteConnection: (projectName) => {
10887
- const removed = removeWordpressTrafficConnection(opts.config, projectName);
10938
+ const removed = removeWordpressTrafficConnection(
10939
+ opts.config,
10940
+ projectName
10941
+ );
10888
10942
  if (removed) saveConfigPatch(opts.config);
10889
10943
  return removed;
10890
10944
  }
@@ -10914,12 +10968,21 @@ async function createServer(opts) {
10914
10968
  return updated;
10915
10969
  },
10916
10970
  updateConnection: (domain, connectionType, patch) => {
10917
- const updated = patchGoogleConnection(opts.config, domain, connectionType, patch);
10971
+ const updated = patchGoogleConnection(
10972
+ opts.config,
10973
+ domain,
10974
+ connectionType,
10975
+ patch
10976
+ );
10918
10977
  if (updated) saveConfigPatch(opts.config);
10919
10978
  return updated;
10920
10979
  },
10921
10980
  deleteConnection: (domain, connectionType) => {
10922
- const removed = removeGoogleConnection(opts.config, domain, connectionType);
10981
+ const removed = removeGoogleConnection(
10982
+ opts.config,
10983
+ domain,
10984
+ connectionType
10985
+ );
10923
10986
  if (removed) saveConfigPatch(opts.config);
10924
10987
  return removed;
10925
10988
  }
@@ -11010,13 +11073,16 @@ async function createServer(opts) {
11010
11073
  const key = getDefaultApiKey();
11011
11074
  if (!key || key.revokedAt) return false;
11012
11075
  const sessionId = createSession(key.id);
11013
- reply.header("set-cookie", serializeSessionCookie({
11014
- name: SESSION_COOKIE_NAME,
11015
- value: sessionId,
11016
- path: sessionCookiePath,
11017
- secure: sessionCookieSecure,
11018
- ttlMs: SESSION_TTL_MS
11019
- }));
11076
+ reply.header(
11077
+ "set-cookie",
11078
+ serializeSessionCookie({
11079
+ name: SESSION_COOKIE_NAME,
11080
+ value: sessionId,
11081
+ path: sessionCookiePath,
11082
+ secure: sessionCookieSecure,
11083
+ ttlMs: SESSION_TTL_MS
11084
+ })
11085
+ );
11020
11086
  return true;
11021
11087
  };
11022
11088
  const boundToLoopback = isLoopbackBindHost(opts.host);
@@ -11037,7 +11103,9 @@ async function createServer(opts) {
11037
11103
  });
11038
11104
  app.post(apiPrefix + "/session/setup", async (request, reply) => {
11039
11105
  if (!boundToLoopback && !requestHasValidApiKey(request)) {
11040
- const err = authRequired("This server is network-reachable; setting the dashboard password requires a valid API key.");
11106
+ const err = authRequired(
11107
+ "This server is network-reachable; setting the dashboard password requires a valid API key."
11108
+ );
11041
11109
  return reply.status(err.statusCode).send(err.toJSON());
11042
11110
  }
11043
11111
  if (opts.config.dashboardPasswordHash) {
@@ -11062,19 +11130,31 @@ async function createServer(opts) {
11062
11130
  const apiKey = request.body?.apiKey?.trim();
11063
11131
  if (password) {
11064
11132
  if (!opts.config.dashboardPasswordHash) {
11065
- const err2 = validationError("No dashboard password configured \u2014 use /session/setup first");
11133
+ const err2 = validationError(
11134
+ "No dashboard password configured \u2014 use /session/setup first"
11135
+ );
11066
11136
  return reply.status(err2.statusCode).send(err2.toJSON());
11067
11137
  }
11068
- const verification = verifyDashboardPassword(password, opts.config.dashboardPasswordHash);
11138
+ const verification = verifyDashboardPassword(
11139
+ password,
11140
+ opts.config.dashboardPasswordHash
11141
+ );
11069
11142
  if (!verification.ok) {
11070
- return reply.status(401).send({ error: { code: "AUTH_INVALID", message: "Incorrect password" } });
11143
+ return reply.status(401).send({
11144
+ error: { code: "AUTH_INVALID", message: "Incorrect password" }
11145
+ });
11071
11146
  }
11072
11147
  if (verification.needsRehash) {
11073
11148
  opts.config.dashboardPasswordHash = hashDashboardPassword(password);
11074
11149
  saveConfigPatch(opts.config);
11075
11150
  }
11076
11151
  if (!createPasswordSession(reply)) {
11077
- return reply.status(401).send({ error: { code: "AUTH_INVALID", message: "Server API key not found \u2014 re-run canonry init" } });
11152
+ return reply.status(401).send({
11153
+ error: {
11154
+ code: "AUTH_INVALID",
11155
+ message: "Server API key not found \u2014 re-run canonry init"
11156
+ }
11157
+ });
11078
11158
  }
11079
11159
  return reply.send({ authenticated: true });
11080
11160
  }
@@ -11086,13 +11166,16 @@ async function createServer(opts) {
11086
11166
  }
11087
11167
  opts.db.update(apiKeys).set({ lastUsedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(eq20(apiKeys.id, key.id)).run();
11088
11168
  const sessionId = createSession(key.id);
11089
- reply.header("set-cookie", serializeSessionCookie({
11090
- name: SESSION_COOKIE_NAME,
11091
- value: sessionId,
11092
- path: sessionCookiePath,
11093
- secure: sessionCookieSecure,
11094
- ttlMs: SESSION_TTL_MS
11095
- }));
11169
+ reply.header(
11170
+ "set-cookie",
11171
+ serializeSessionCookie({
11172
+ name: SESSION_COOKIE_NAME,
11173
+ value: sessionId,
11174
+ path: sessionCookiePath,
11175
+ secure: sessionCookieSecure,
11176
+ ttlMs: SESSION_TTL_MS
11177
+ })
11178
+ );
11096
11179
  return reply.send({ authenticated: true });
11097
11180
  }
11098
11181
  const err = validationError("Either password or apiKey is required");
@@ -11101,13 +11184,16 @@ async function createServer(opts) {
11101
11184
  app.delete(apiPrefix + "/session", async (request, reply) => {
11102
11185
  const sessionId = parseCookies(request.headers.cookie)[SESSION_COOKIE_NAME];
11103
11186
  clearSession(sessionId);
11104
- reply.header("set-cookie", serializeSessionCookie({
11105
- name: SESSION_COOKIE_NAME,
11106
- value: null,
11107
- path: sessionCookiePath,
11108
- secure: sessionCookieSecure,
11109
- ttlMs: SESSION_TTL_MS
11110
- }));
11187
+ reply.header(
11188
+ "set-cookie",
11189
+ serializeSessionCookie({
11190
+ name: SESSION_COOKIE_NAME,
11191
+ value: null,
11192
+ path: sessionCookiePath,
11193
+ secure: sessionCookieSecure,
11194
+ ttlMs: SESSION_TTL_MS
11195
+ })
11196
+ );
11111
11197
  return reply.status(204).send();
11112
11198
  });
11113
11199
  const LATEST_RELEASE_TTL_MS = 5 * 60 * 1e3;
@@ -11132,8 +11218,12 @@ async function createServer(opts) {
11132
11218
  latestReleaseCache = { value, expiresAt: now + LATEST_RELEASE_TTL_MS };
11133
11219
  return value;
11134
11220
  };
11135
- const explainContentRecommendation = createRecommendationExplainer({ config: opts.config });
11136
- const briefContentRecommendation = createRecommendationBriefSynthesizer({ config: opts.config });
11221
+ const explainContentRecommendation = createRecommendationExplainer({
11222
+ config: opts.config
11223
+ });
11224
+ const briefContentRecommendation = createRecommendationBriefSynthesizer({
11225
+ config: opts.config
11226
+ });
11137
11227
  await app.register(apiRoutes, {
11138
11228
  db: opts.db,
11139
11229
  routePrefix: apiPrefix,
@@ -11195,7 +11285,9 @@ async function createServer(opts) {
11195
11285
  onGscSyncRequested: (runId, projectId, syncOpts) => {
11196
11286
  const { clientId: googleClientId, clientSecret: googleClientSecret } = getGoogleAuthConfig(opts.config);
11197
11287
  if (!googleClientId || !googleClientSecret) {
11198
- app.log.error("GSC sync requested but Google OAuth credentials are not configured in the local config");
11288
+ app.log.error(
11289
+ "GSC sync requested but Google OAuth credentials are not configured in the local config"
11290
+ );
11199
11291
  return;
11200
11292
  }
11201
11293
  executeGscSync(opts.db, runId, projectId, {
@@ -11208,7 +11300,9 @@ async function createServer(opts) {
11208
11300
  onInspectSitemapRequested: (runId, projectId, inspectOpts) => {
11209
11301
  const { clientId: googleClientId, clientSecret: googleClientSecret } = getGoogleAuthConfig(opts.config);
11210
11302
  if (!googleClientId || !googleClientSecret) {
11211
- app.log.error("Inspect sitemap requested but Google OAuth credentials are not configured");
11303
+ app.log.error(
11304
+ "Inspect sitemap requested but Google OAuth credentials are not configured"
11305
+ );
11212
11306
  return;
11213
11307
  }
11214
11308
  executeInspectSitemap(opts.db, runId, projectId, {
@@ -11233,7 +11327,9 @@ async function createServer(opts) {
11233
11327
  pluginDir: PLUGIN_DIR
11234
11328
  }),
11235
11329
  onInstallBacklinks: async () => {
11236
- const result = await installDuckdb({ onLog: (line) => app.log.info({ line }, "duckdb install") });
11330
+ const result = await installDuckdb({
11331
+ onLog: (line) => app.log.info({ line }, "duckdb install")
11332
+ });
11237
11333
  return {
11238
11334
  installed: true,
11239
11335
  version: result.version,
@@ -11256,8 +11352,13 @@ async function createServer(opts) {
11256
11352
  trigger: RunTriggers.scheduled,
11257
11353
  createdAt: now
11258
11354
  }).run();
11259
- executeBacklinkExtract(opts.db, runId, projectId, { release: r }).catch((err) => {
11260
- app.log.error({ runId, projectId, err }, "Auto backlink extract failed");
11355
+ executeBacklinkExtract(opts.db, runId, projectId, {
11356
+ release: r
11357
+ }).catch((err) => {
11358
+ app.log.error(
11359
+ { runId, projectId, err },
11360
+ "Auto backlink extract failed"
11361
+ );
11261
11362
  });
11262
11363
  }
11263
11364
  }
@@ -11266,9 +11367,11 @@ async function createServer(opts) {
11266
11367
  });
11267
11368
  },
11268
11369
  onBacklinkExtractRequested: (runId, projectId, release) => {
11269
- executeBacklinkExtract(opts.db, runId, projectId, { release }).catch((err) => {
11270
- app.log.error({ runId, err }, "Backlink extract failed");
11271
- });
11370
+ executeBacklinkExtract(opts.db, runId, projectId, { release }).catch(
11371
+ (err) => {
11372
+ app.log.error({ runId, err }, "Backlink extract failed");
11373
+ }
11374
+ );
11272
11375
  },
11273
11376
  onBingBacklinkSyncRequested: (runId, projectId) => {
11274
11377
  executeBingBacklinkSync(opts.db, runId, projectId, {
@@ -11303,9 +11406,16 @@ async function createServer(opts) {
11303
11406
  embedQueries: (queriesToEmbed) => {
11304
11407
  const cfg = registry.get("gemini")?.config;
11305
11408
  if (!cfg?.apiKey) {
11306
- return Promise.reject(new Error("Gemini API key not configured; harvest semantic novelty unavailable"));
11409
+ return Promise.reject(
11410
+ new Error(
11411
+ "Gemini API key not configured; harvest semantic novelty unavailable"
11412
+ )
11413
+ );
11307
11414
  }
11308
- return embedQueries(queriesToEmbed, { apiKey: cfg.apiKey, baseUrl: cfg.baseUrl });
11415
+ return embedQueries(queriesToEmbed, {
11416
+ apiKey: cfg.apiKey,
11417
+ baseUrl: cfg.baseUrl
11418
+ });
11309
11419
  },
11310
11420
  onSiteAuditRequested: (runId, projectId, auditOpts) => {
11311
11421
  runSiteAudit(runId, projectId, auditOpts);
@@ -11321,7 +11431,10 @@ async function createServer(opts) {
11321
11431
  const cached = listCachedReleases();
11322
11432
  const syncByRelease = /* @__PURE__ */ new Map();
11323
11433
  for (const row of opts.db.select().from(ccReleaseSyncs).all()) {
11324
- syncByRelease.set(row.release, { status: row.status, updatedAt: row.updatedAt });
11434
+ syncByRelease.set(row.release, {
11435
+ status: row.status,
11436
+ updatedAt: row.updatedAt
11437
+ });
11325
11438
  }
11326
11439
  return cached.map((entry) => {
11327
11440
  const sync = syncByRelease.get(entry.release);
@@ -11370,16 +11483,20 @@ async function createServer(opts) {
11370
11483
  wordpressTrafficCredentialStore,
11371
11484
  vercelTrafficCredentialStore,
11372
11485
  onTrafficSynced: (event) => {
11373
- trackEvent("traffic.synced", {
11374
- status: event.status,
11375
- sourceType: event.sourceType,
11376
- sourceId: event.sourceId,
11377
- pulledEvents: event.pulledEvents,
11378
- selfTrafficExcluded: event.selfTrafficExcluded,
11379
- crawlerHits: event.crawlerHits,
11380
- aiReferralHits: event.aiReferralHits,
11381
- durationMs: event.durationMs
11382
- }, event.errorCode ? { errorCode: event.errorCode } : void 0);
11486
+ trackEvent(
11487
+ "traffic.synced",
11488
+ {
11489
+ status: event.status,
11490
+ sourceType: event.sourceType,
11491
+ sourceId: event.sourceId,
11492
+ pulledEvents: event.pulledEvents,
11493
+ selfTrafficExcluded: event.selfTrafficExcluded,
11494
+ crawlerHits: event.crawlerHits,
11495
+ aiReferralHits: event.aiReferralHits,
11496
+ durationMs: event.durationMs
11497
+ },
11498
+ event.errorCode ? { errorCode: event.errorCode } : void 0
11499
+ );
11383
11500
  },
11384
11501
  onRunCreated: (runId, projectId, providers2, location) => {
11385
11502
  jobRunner.executeRun(runId, projectId, providers2, location).catch((err) => {
@@ -11442,16 +11559,18 @@ async function createServer(opts) {
11442
11559
  }).map((project) => project.id);
11443
11560
  const targetProjectIds = affectedProjectIds.length > 0 ? affectedProjectIds : [null];
11444
11561
  const createdAt = (/* @__PURE__ */ new Date()).toISOString();
11445
- opts.db.insert(auditLog).values(targetProjectIds.map((projectId) => ({
11446
- id: crypto20.randomUUID(),
11447
- projectId,
11448
- actor: "api",
11449
- action: existing ? "provider.updated" : "provider.created",
11450
- entityType: "provider",
11451
- entityId: name,
11452
- diff,
11453
- createdAt
11454
- }))).run();
11562
+ opts.db.insert(auditLog).values(
11563
+ targetProjectIds.map((projectId) => ({
11564
+ id: crypto20.randomUUID(),
11565
+ projectId,
11566
+ actor: "api",
11567
+ action: existing ? "provider.updated" : "provider.created",
11568
+ entityType: "provider",
11569
+ entityId: name,
11570
+ diff,
11571
+ createdAt
11572
+ }))
11573
+ ).run();
11455
11574
  }
11456
11575
  return {
11457
11576
  name,
@@ -11499,7 +11618,10 @@ async function createServer(opts) {
11499
11618
  "aliases changed \u2014 recomputed mention fields on historical snapshots"
11500
11619
  );
11501
11620
  } catch (err) {
11502
- app.log.error({ err, projectId, projectName }, "alias-triggered backfill failed");
11621
+ app.log.error(
11622
+ { err, projectId, projectName },
11623
+ "alias-triggered backfill failed"
11624
+ );
11503
11625
  }
11504
11626
  });
11505
11627
  },
@@ -11528,7 +11650,11 @@ async function createServer(opts) {
11528
11650
  app.log.error({ err }, "Failed to save CDP config");
11529
11651
  throw err;
11530
11652
  }
11531
- const CDP_DEFAULT_QUOTA = { maxConcurrency: 1, maxRequestsPerMinute: 4, maxRequestsPerDay: 200 };
11653
+ const CDP_DEFAULT_QUOTA = {
11654
+ maxConcurrency: 1,
11655
+ maxRequestsPerMinute: 4,
11656
+ maxRequestsPerDay: 200
11657
+ };
11532
11658
  registry.register(cdpChatgptAdapter, {
11533
11659
  provider: "cdp:chatgpt",
11534
11660
  cdpEndpoint: `ws://${host}:${port2}`,
@@ -11560,16 +11686,19 @@ async function createServer(opts) {
11560
11686
  conn.config
11561
11687
  );
11562
11688
  const raw = result.rawResponse;
11563
- return [{
11564
- target: targets?.[0] ?? "chatgpt",
11565
- screenshotPath: result.screenshotPath ?? "",
11566
- answerText: raw.answerText ?? "",
11567
- citations: raw.groundingSources ?? []
11568
- }];
11689
+ return [
11690
+ {
11691
+ target: targets?.[0] ?? "chatgpt",
11692
+ screenshotPath: result.screenshotPath ?? "",
11693
+ answerText: raw.answerText ?? "",
11694
+ citations: raw.groundingSources ?? []
11695
+ }
11696
+ ];
11569
11697
  },
11570
11698
  onGenerateQueries: async (providerName, count, project) => {
11571
11699
  const provider = registry.get(providerName);
11572
- if (!provider) throw new Error(`Provider "${providerName}" is not configured`);
11700
+ if (!provider)
11701
+ throw new Error(`Provider "${providerName}" is not configured`);
11573
11702
  const siteText = await fetchSiteText(project.domain);
11574
11703
  const prompt = buildQueryGenerationPrompt({
11575
11704
  domain: project.domain,
@@ -11622,11 +11751,11 @@ async function createServer(opts) {
11622
11751
  // Without this, the browser hits the server for every JS chunk on
11623
11752
  // every page load, defeating most of the dashboard's first-paint
11624
11753
  // budget.
11625
- setHeaders: (reply, filePath) => {
11626
- if (filePath.endsWith(".html")) {
11627
- reply.setHeader("Cache-Control", "no-cache, must-revalidate");
11754
+ setHeaders: (res, path10) => {
11755
+ if (path10.endsWith(".html")) {
11756
+ res.setHeader("Cache-Control", "no-cache, must-revalidate");
11628
11757
  } else {
11629
- reply.setHeader("Cache-Control", "public, max-age=31536000, immutable");
11758
+ res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
11630
11759
  }
11631
11760
  }
11632
11761
  });
@@ -11690,10 +11819,18 @@ function buildQueryGenerationPrompt(ctx) {
11690
11819
  lines.push(`Country: ${ctx.country}`);
11691
11820
  lines.push(`Language: ${ctx.language}`);
11692
11821
  if (ctx.siteText) {
11693
- lines.push("", "--- Site Content ---", ctx.siteText, "--- End Site Content ---");
11822
+ lines.push(
11823
+ "",
11824
+ "--- Site Content ---",
11825
+ ctx.siteText,
11826
+ "--- End Site Content ---"
11827
+ );
11694
11828
  }
11695
11829
  if (ctx.existingQueries.length > 0) {
11696
- lines.push("", `Already tracking (do NOT duplicate): ${ctx.existingQueries.join(", ")}`);
11830
+ lines.push(
11831
+ "",
11832
+ `Already tracking (do NOT duplicate): ${ctx.existingQueries.join(", ")}`
11833
+ );
11697
11834
  }
11698
11835
  lines.push(
11699
11836
  "",
@@ -11715,7 +11852,10 @@ function parseQueryResponse(raw, count) {
11715
11852
  let cleaned = line.replace(/^\s*(?:\d+[.)]\s*|[-*•]\s*)/, "").trim();
11716
11853
  cleaned = cleaned.replace(/^["']|["']$/g, "").trim();
11717
11854
  if (!cleaned) continue;
11718
- if (/^(?:here are|sure|certainly|of course|i['’]ve|these are|below are)/i.test(cleaned)) continue;
11855
+ if (/^(?:here are|sure|certainly|of course|i['’]ve|these are|below are)/i.test(
11856
+ cleaned
11857
+ ))
11858
+ continue;
11719
11859
  if (cleaned.split(/\s+/).length > 8) continue;
11720
11860
  const key = cleaned.toLowerCase();
11721
11861
  if (seen.has(key)) continue;