@canonry/canonry 7.72.2 → 7.74.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 (131) hide show
  1. package/assets/assets/{AgentSetupPage-D39M9CRK.js → AgentSetupPage-D7YVdPWO.js} +1 -1
  2. package/assets/assets/{AuditHistoryPanel-BS-iFyHX.js → AuditHistoryPanel-yrgfS5B_.js} +1 -1
  3. package/assets/assets/{BacklinksPage-BW2bEGF4.js → BacklinksPage-DJM6z03g.js} +1 -1
  4. package/assets/assets/{HistoryPage-Dh6o2iVd.js → HistoryPage-CNvAVJ1S.js} +1 -1
  5. package/assets/assets/{MeasurementPropertyPage-DL9cbtVz.js → MeasurementPropertyPage-BVVYhOxR.js} +1 -1
  6. package/assets/assets/{ProjectPage-DXh97uDN.js → ProjectPage-CPRD8kR9.js} +1 -1
  7. package/assets/assets/{RunsPage-BM4ETLsm.js → RunsPage-Ck33dcjz.js} +1 -1
  8. package/assets/assets/{SettingsPage-DpJTB2-Q.js → SettingsPage-CS_t4Dai.js} +1 -1
  9. package/assets/assets/{SiteHealthSection-CmlMQ17V.js → SiteHealthSection-BurKnHpn.js} +2 -2
  10. package/assets/assets/ToneBadge-Df8oiKsQ.js +60 -0
  11. package/assets/assets/{TrafficPage-ClH3Dxnm.js → TrafficPage-DAiY698E.js} +1 -1
  12. package/assets/assets/{TrafficSourceDetailPage-DE-NyNGz.js → TrafficSourceDetailPage-clJSX2rr.js} +1 -1
  13. package/assets/assets/{account-context-BwV6ox8O.js → account-context-DDEhuoP2.js} +1 -1
  14. package/assets/assets/{card-DhkoBNyY.js → card-DbR-lBY3.js} +1 -1
  15. package/assets/assets/{extract-error-message-dNDtiSBo.js → extract-error-message-7_Vm2DQF.js} +1 -1
  16. package/assets/assets/{format-helpers-Bt4tx-f3.js → format-helpers-vtahpXTQ.js} +1 -1
  17. package/assets/assets/{index-MbApCekj.js → index-BIhCeXvc.js} +4 -4
  18. package/assets/assets/{query-client-D-zMw63p.js → query-client-TlFXYJ9o.js} +1 -1
  19. package/assets/assets/{react-query-EdiRRB2q.js → react-query-C5Mv8xfD.js} +1 -1
  20. package/assets/assets/{react-sigma_core.esm.min-Bidr1Gxk.js → react-sigma_core.esm.min-DmggJ7YC.js} +1 -1
  21. package/assets/assets/{service-BUi8JgGI.js → service-CLFURPuM.js} +1 -1
  22. package/assets/index.html +7 -7
  23. package/dist/{ads-FFUUMS4J.js → ads-L64W5J35.js} +3 -3
  24. package/dist/{agent-LCD2VG7C.js → agent-CMQ34CFD.js} +7 -7
  25. package/dist/{agent-ask-OBHTCYFR.js → agent-ask-3KEYJSZV.js} +3 -3
  26. package/dist/{agent-conversations-VMZ4NFIX.js → agent-conversations-4KKPOTCP.js} +3 -3
  27. package/dist/{agent-memory-UPFJFNWC.js → agent-memory-VOSRZ57W.js} +3 -3
  28. package/dist/{agent-providers-4GOWLBZK.js → agent-providers-SLXTYMDS.js} +3 -3
  29. package/dist/{agent-transcript-RGXIVZUP.js → agent-transcript-Q6OEZROG.js} +3 -3
  30. package/dist/{analytics-FBK4XV5P.js → analytics-LSF6NYII.js} +3 -3
  31. package/dist/{apply-Y2DVE3YB.js → apply-7O3RES7N.js} +3 -3
  32. package/dist/{backfill-NE55YL6X.js → backfill-7ARSKYDG.js} +9 -9
  33. package/dist/{backlinks-YWHFC7DZ.js → backlinks-4YAC374B.js} +3 -3
  34. package/dist/{bing-7BP3DWPK.js → bing-SHAYDXAA.js} +3 -3
  35. package/dist/{bootstrap-Z7QSKVPL.js → bootstrap-BHLBGQKJ.js} +10 -10
  36. package/dist/{cdp-OL6RENO3.js → cdp-QWJE6SFY.js} +7 -7
  37. package/dist/{chunk-J523Y7X2.js → chunk-2Y6MSB4J.js} +1 -1
  38. package/dist/{chunk-GA2EHZTI.js → chunk-3WPTMLQI.js} +22 -6
  39. package/dist/{chunk-QDN3FL2A.js → chunk-3YIKSZHN.js} +2 -1
  40. package/dist/{chunk-IY4AJ6DN.js → chunk-5PA7SJ2M.js} +5 -5
  41. package/dist/{chunk-JO73L677.js → chunk-6ATKY252.js} +2 -2
  42. package/dist/{chunk-XR6ZVMYK.js → chunk-6W5AR4IW.js} +1 -1
  43. package/dist/{chunk-IZMT4WLZ.js → chunk-6YW24AUN.js} +2 -2
  44. package/dist/{chunk-QKDKVPMR.js → chunk-AJMDETJA.js} +4 -4
  45. package/dist/{chunk-HZSE3WSG.js → chunk-AZQNJX3T.js} +2 -2
  46. package/dist/{chunk-ATT3ZCSS.js → chunk-BICUWFV4.js} +38 -16
  47. package/dist/{chunk-MJYO6UK2.js → chunk-DL3LTSBV.js} +2 -2
  48. package/dist/{chunk-6MYHGP46.js → chunk-DLVGMRM5.js} +1 -1
  49. package/dist/{chunk-TOX6HAQJ.js → chunk-EXGETCJR.js} +3 -3
  50. package/dist/{chunk-BADJCT6U.js → chunk-GWDMWKM6.js} +1 -1
  51. package/dist/{chunk-PPM6Z7CM.js → chunk-HEL6DKDN.js} +1 -1
  52. package/dist/{chunk-NZZWJCKS.js → chunk-HJHFW455.js} +3 -3
  53. package/dist/{chunk-DRGCVTYH.js → chunk-JPM3VC6A.js} +1 -1
  54. package/dist/{chunk-H4HNXCDF.js → chunk-KOWOQ3JZ.js} +2 -2
  55. package/dist/{chunk-UWBJWKDQ.js → chunk-L5GIL45X.js} +2 -2
  56. package/dist/{chunk-P3UGNR2Y.js → chunk-LS47ZAX2.js} +5 -5
  57. package/dist/{chunk-IV6VZ63E.js → chunk-MB3IUJ6Z.js} +18 -14
  58. package/dist/{chunk-3AG3LPZX.js → chunk-MRSNLKSM.js} +1 -1
  59. package/dist/{chunk-JE5QURTR.js → chunk-NXFNXXYM.js} +184 -92
  60. package/dist/{chunk-Q25JQANW.js → chunk-O4D66XPL.js} +17 -2
  61. package/dist/{chunk-O7WOCTBD.js → chunk-PAIYFNNY.js} +71 -3
  62. package/dist/{chunk-JEBY6MS6.js → chunk-QS6RIP37.js} +1 -1
  63. package/dist/{chunk-4LTL5RNY.js → chunk-SCRPC2PQ.js} +4 -4
  64. package/dist/{chunk-YXAKL5HM.js → chunk-SF5JLMLG.js} +6791 -6777
  65. package/dist/{chunk-UZKNS5PL.js → chunk-TXUNPPWD.js} +254 -92
  66. package/dist/{chunk-NZLK3KHQ.js → chunk-WLNYLQTX.js} +6 -6
  67. package/dist/{chunk-7KOAP47B.js → chunk-WLWOGBLJ.js} +363 -248
  68. package/dist/{chunk-CF6BUJRK.js → chunk-WY2C6FFA.js} +8 -8
  69. package/dist/{chunk-BZZDFIY2.js → chunk-XDQJOZKJ.js} +1 -1
  70. package/dist/{chunk-TEDY3MHN.js → chunk-YTSE2EZP.js} +3 -3
  71. package/dist/{chunk-G7SGQUW4.js → chunk-ZMDIARSG.js} +345 -337
  72. package/dist/{citations-RVSC67GE.js → citations-EENLZULG.js} +3 -3
  73. package/dist/{cli-catalog-NEZE5QU5.js → cli-catalog-BXHG544D.js} +3 -3
  74. package/dist/{cli-commands-ARJWPTFW.js → cli-commands-7BG5M2KF.js} +7 -7
  75. package/dist/cli.js +13 -13
  76. package/dist/{competitor-BX3M3OYS.js → competitor-CW5LMXJ6.js} +3 -3
  77. package/dist/{content-PKJMVMHJ.js → content-BX6UGRRU.js} +3 -3
  78. package/dist/{dashboard-SVHZBVM6.js → dashboard-M2TKT2LW.js} +6 -6
  79. package/dist/{demo-GLV22DPY.js → demo-GKSMSKOY.js} +1 -1
  80. package/dist/{demo-server-GPM4C4Q2.js → demo-server-UQO4XKHN.js} +12 -12
  81. package/dist/{discover-JDP44ZHX.js → discover-2EZUZFNR.js} +3 -3
  82. package/dist/{discover-eval-6ORCVYYR.js → discover-eval-IS2GRYVV.js} +3 -3
  83. package/dist/{doctor-TVZRMBSS.js → doctor-DPEIBV3E.js} +3 -3
  84. package/dist/{evidence-FNIAFBBG.js → evidence-UGC4ZWNA.js} +3 -3
  85. package/dist/{export-cmd-HQNF2SSD.js → export-cmd-7OVM23C4.js} +3 -3
  86. package/dist/{ga-PIO5OXMK.js → ga-FUADE4K4.js} +3 -3
  87. package/dist/{gbp-3R5FME43.js → gbp-R4M663R5.js} +3 -3
  88. package/dist/{google-BYZREX2O.js → google-WTOTC5SL.js} +4 -4
  89. package/dist/{google-marketing-SPQ2GW6X.js → google-marketing-IXPMUBXZ.js} +1 -1
  90. package/dist/{health-cmd-HH5RYMSV.js → health-cmd-QKDO6VIT.js} +3 -3
  91. package/dist/{history-Q35NLLMJ.js → history-LEBTYXVW.js} +3 -3
  92. package/dist/index.d.ts +249 -72
  93. package/dist/index.js +25 -25
  94. package/dist/{init-Q33HEJJN.js → init-BKOT4UY2.js} +12 -11
  95. package/dist/{insights-SH73B4PD.js → insights-OBHQ5GHV.js} +3 -3
  96. package/dist/intelligence-service-EJQQNO65.js +16 -0
  97. package/dist/{journeys-SIV7HPW7.js → journeys-PTMCJHOL.js} +3 -3
  98. package/dist/{keys-O656YWSW.js → keys-W2FZNFOR.js} +3 -3
  99. package/dist/{keyword-FZ2N4EW7.js → keyword-Y6WABJPU.js} +3 -3
  100. package/dist/{logs-2NPN7HBI.js → logs-KRSH53GN.js} +3 -3
  101. package/dist/mcp-6LJW6LEJ.js +19 -0
  102. package/dist/mcp.js +20 -14
  103. package/dist/{measurement-plan-JQKVSJRL.js → measurement-plan-RHLKXNYG.js} +5 -5
  104. package/dist/{notify-VTAYBHC6.js → notify-HRK2HQTU.js} +3 -3
  105. package/dist/{organic-evidence-HPXXEPOW.js → organic-evidence-EX2VL5CE.js} +3 -3
  106. package/dist/{overview-FSBNDYZJ.js → overview-254QNXAC.js} +4 -4
  107. package/dist/{project-MAPPXURS.js → project-UOYX7T4J.js} +3 -3
  108. package/dist/{query-R6DLPIPJ.js → query-JMVOMNRS.js} +3 -3
  109. package/dist/{research-FXKOEUQB.js → research-PAPX7KO5.js} +3 -3
  110. package/dist/{results-export-X2PUM63S.js → results-export-3BXIIDP2.js} +3 -3
  111. package/dist/{run-6ENTG4IO.js → run-WQXLV4MS.js} +4 -4
  112. package/dist/{schedule-DMMVRT7P.js → schedule-3WJ5F3BF.js} +3 -3
  113. package/dist/{search-FHI6APT7.js → search-RVGFOZAT.js} +3 -3
  114. package/dist/{serve-SJTQQQQE.js → serve-BPM2P3GY.js} +26 -26
  115. package/dist/{session-VHCKM3AI.js → session-76DT5W6D.js} +13 -13
  116. package/dist/{settings-FMB4QED4.js → settings-MRJ566D6.js} +3 -3
  117. package/dist/{skills-HBIMHSOI.js → skills-F6AXQHTO.js} +2 -2
  118. package/dist/{snapshot-RBA2EL7R.js → snapshot-7GBDFFVB.js} +3 -3
  119. package/dist/{src-BXXGJOQB.js → src-52USCS7O.js} +4 -2
  120. package/dist/{status-ATFDFAVG.js → status-S6CZV2LU.js} +4 -4
  121. package/dist/{technical-aeo-JWQTGCTB.js → technical-aeo-Q73ZF2FD.js} +3 -3
  122. package/dist/{telemetry-6QFGJL2I.js → telemetry-BT4OOPN6.js} +4 -4
  123. package/dist/{tools-4VRHKUBE.js → tools-HYOV77FY.js} +11 -11
  124. package/dist/{traffic-5R7M4CK5.js → traffic-EFLF62IZ.js} +5 -5
  125. package/dist/{users-24TIUYJY.js → users-MYXGNUIZ.js} +3 -3
  126. package/dist/{visibility-stats-YLQPPBJJ.js → visibility-stats-QENASZW6.js} +3 -3
  127. package/dist/{wordpress-7VDPHMUZ.js → wordpress-CYLQHE5L.js} +3 -3
  128. package/package.json +10 -6
  129. package/assets/assets/ToneBadge-CmvL5mFG.js +0 -60
  130. package/dist/intelligence-service-LVRH4RJG.js +0 -16
  131. package/dist/mcp-RHQY3DV6.js +0 -14
@@ -9,14 +9,14 @@ import {
9
9
  normalizeCloudflareWorkerEvent,
10
10
  sessionizeJourneyRequests,
11
11
  verifyRequestSignature
12
- } from "./chunk-JEBY6MS6.js";
12
+ } from "./chunk-QS6RIP37.js";
13
13
  import {
14
14
  currentOutcomeAttribution,
15
15
  getRequestContext,
16
16
  registerRequestContext,
17
17
  requestAuditIdentity,
18
18
  sanitizeRequestContext
19
- } from "./chunk-BADJCT6U.js";
19
+ } from "./chunk-GWDMWKM6.js";
20
20
  import {
21
21
  SentimentIdempotencyConflict,
22
22
  SentimentRepository,
@@ -109,6 +109,7 @@ import {
109
109
  notifications,
110
110
  oauthAuthorizationCodes,
111
111
  oauthClients,
112
+ oauthGrants,
112
113
  oauthTokens,
113
114
  parseJsonColumn,
114
115
  pickGroupRepresentative,
@@ -156,7 +157,7 @@ import {
156
157
  userSessions,
157
158
  users,
158
159
  writeNegativeReviewMaxStars
159
- } from "./chunk-O7WOCTBD.js";
160
+ } from "./chunk-PAIYFNNY.js";
160
161
  import {
161
162
  ADS_ACTIVATE_SCOPE,
162
163
  ADS_ACTIVATION_ABSOLUTE_MAX_ENTITIES,
@@ -788,6 +789,7 @@ import {
788
789
  matchesMarketRankingFilter,
789
790
  matchesMarketRankingText,
790
791
  matchesMeasurementTargetUrl,
792
+ mcpProfileDtoSchema,
791
793
  measurementChangesQuerySchema,
792
794
  measurementChangesResponseSchema,
793
795
  measurementCompiledChecksumConflict,
@@ -1194,7 +1196,7 @@ import {
1194
1196
  wordpressSchemaDeployResultDtoSchema,
1195
1197
  wordpressSchemaStatusResultDtoSchema,
1196
1198
  wordpressStatusDtoSchema
1197
- } from "./chunk-YXAKL5HM.js";
1199
+ } from "./chunk-SF5JLMLG.js";
1198
1200
 
1199
1201
  // ../api-routes/src/user-session.ts
1200
1202
  import crypto2 from "crypto";
@@ -6076,9 +6078,6 @@ function readStoredGroundingSources(rawResponse) {
6076
6078
  return result;
6077
6079
  }
6078
6080
 
6079
- // ../api-routes/src/agent-conversations.ts
6080
- import { and as and7, desc as desc2, eq as eq12, like } from "drizzle-orm";
6081
-
6082
6081
  // ../api-routes/src/auth.ts
6083
6082
  import crypto8 from "crypto";
6084
6083
  import { eq as eq10 } from "drizzle-orm";
@@ -6107,6 +6106,9 @@ function isPaidReadRoute(request) {
6107
6106
  function isTransportEnvelopeRoute(request) {
6108
6107
  return request.routeOptions.config.transportEnvelope === true;
6109
6108
  }
6109
+ function isMcpAuthorizationRoute(request) {
6110
+ return isTransportEnvelopeRoute(request) || (request.method === "GET" || request.method === "HEAD") && matchOperationTemplate("GET", request.routeOptions.url ?? request.url) === "GET /api/v1/mcp/profile";
6111
+ }
6110
6112
  function requireScope(request, scope) {
6111
6113
  if (request.readSemanticGrant) return;
6112
6114
  const scopes = principalScopes(request);
@@ -6216,11 +6218,17 @@ function shouldSkipAuth(url) {
6216
6218
  if (url.endsWith("/traffic/cloudflare/ingest")) return true;
6217
6219
  return false;
6218
6220
  }
6221
+ var MCP_DELEGATED_KEY_MAX_AGE_MS = 60 * 60 * 1e3;
6219
6222
  var USERS_READ_SCOPE = "users.read";
6220
6223
  var USERS_WRITE_SCOPE = "users.write";
6221
6224
  function scopesForRole(role, researchAllowViewers = false) {
6222
6225
  return role === UserRoles.admin ? [WILDCARD_SCOPE] : researchAllowViewers ? [READ_ONLY_SCOPE, RESEARCH_RUN_SCOPE] : [READ_ONLY_SCOPE];
6223
6226
  }
6227
+ function delegatedScopesForRole(role, requested, researchAllowViewers = false) {
6228
+ const effective = intersectScopes(scopesForRole(role, researchAllowViewers), requested).filter((scope) => requested.includes(WILDCARD_SCOPE) || requested.includes(scope));
6229
+ if (effective.length === 0) throw forbidden("This credential no longer has any authorized scopes.");
6230
+ return effective;
6231
+ }
6224
6232
  function queryValue(request, key) {
6225
6233
  const raw = request.query?.[key];
6226
6234
  if (typeof raw === "string") return raw;
@@ -6374,15 +6382,15 @@ async function authPlugin(app, opts = {}) {
6374
6382
  const hash3 = hashApiKey(token);
6375
6383
  key = app.db.select().from(apiKeys).where(eq10(apiKeys.keyHash, hash3)).get();
6376
6384
  if (!key || key.revokedAt) {
6377
- const granted = isTransportEnvelopeRoute(request) ? opts.resolveOAuthToken?.(token) ?? null : null;
6385
+ const granted = isMcpAuthorizationRoute(request) ? opts.resolveOAuthToken?.(token) ?? null : null;
6378
6386
  if (granted) {
6379
6387
  const account = app.db.select().from(users).where(eq10(users.id, granted.userId)).get();
6380
6388
  if (!account) throw authInvalid();
6381
- const roleScopes = scopesForRole(account.role, opts.researchAllowViewers);
6382
- const requested = (granted.scope ?? "").split(/\s+/).filter((part) => part.length > 0 && part !== "offline_access");
6383
- const effective = intersectScopes(roleScopes, requested);
6389
+ const requested = (granted.scope ?? READ_ONLY_SCOPE).split(/\s+/).filter((part) => part.length > 0 && part !== "offline_access");
6390
+ const effective = delegatedScopesForRole(account.role, requested, opts.researchAllowViewers);
6384
6391
  request.principal = {
6385
6392
  kind: "user",
6393
+ oauthGrantId: granted.grantId,
6386
6394
  id: account.id,
6387
6395
  name: account.name,
6388
6396
  scopes: effective,
@@ -6423,10 +6431,17 @@ async function authPlugin(app, opts = {}) {
6423
6431
  let scopes = Array.isArray(key.scopes) ? key.scopes : [];
6424
6432
  const delegatedUser = key.delegatedUserId ? app.db.select().from(users).where(eq10(users.id, key.delegatedUserId)).get() : void 0;
6425
6433
  if (key.delegatedUserId && !delegatedUser) throw authInvalid();
6426
- if (delegatedUser) scopes = intersectScopes(scopesForRole(delegatedUser.role, opts.researchAllowViewers), scopes);
6434
+ if (key.delegatedOAuthGrantId) {
6435
+ const age = Date.now() - Date.parse(key.createdAt);
6436
+ if (!Number.isFinite(age) || age < 0 || age >= MCP_DELEGATED_KEY_MAX_AGE_MS) throw authInvalid();
6437
+ const grant = app.db.select().from(oauthGrants).where(eq10(oauthGrants.id, key.delegatedOAuthGrantId)).get();
6438
+ if (!grant || grant.revokedAt || grant.userId !== key.delegatedUserId) throw authInvalid();
6439
+ }
6440
+ if (delegatedUser) scopes = delegatedScopesForRole(delegatedUser.role, scopes, opts.researchAllowViewers);
6427
6441
  request.apiKey = { id: key.id, name: key.name, scopes, projectId: key.projectId ?? null };
6428
6442
  request.principal = {
6429
6443
  kind: "api-key",
6444
+ oauthGrantId: key.delegatedOAuthGrantId,
6430
6445
  id: key.id,
6431
6446
  name: key.name,
6432
6447
  scopes,
@@ -6455,6 +6470,34 @@ async function authPlugin(app, opts = {}) {
6455
6470
  });
6456
6471
  }
6457
6472
 
6473
+ // ../api-routes/src/mcp-profile.ts
6474
+ async function mcpProfileRoutes(app, opts) {
6475
+ app.get("/mcp/profile", async (request, reply) => {
6476
+ requireScope(request, READ_ONLY_SCOPE);
6477
+ const principal = request.principal;
6478
+ const user = principal?.kind === "user" ? principal : principal?.delegatedUser;
6479
+ if (!user || principal?.projectId) {
6480
+ throw forbidden("MCP connection profiles require an instance-wide named account.");
6481
+ }
6482
+ if (!opts.oauthResourceUrl) {
6483
+ throw notImplemented("This instance has no configured MCP OAuth resource.");
6484
+ }
6485
+ reply.header("Cache-Control", "no-store");
6486
+ return {
6487
+ userId: user.id,
6488
+ displayName: user.name,
6489
+ instance: {
6490
+ issuer: new URL(opts.oauthResourceUrl).origin,
6491
+ resource: opts.oauthResourceUrl
6492
+ },
6493
+ scopes: [READ_ONLY_SCOPE]
6494
+ };
6495
+ });
6496
+ }
6497
+
6498
+ // ../api-routes/src/agent-conversations.ts
6499
+ import { and as and7, desc as desc2, eq as eq12, like } from "drizzle-orm";
6500
+
6458
6501
  // ../api-routes/src/helpers.ts
6459
6502
  import crypto9 from "crypto";
6460
6503
  import { eq as eq11, ne as ne3, sql as sql2 } from "drizzle-orm";
@@ -7866,7 +7909,7 @@ function createOutcomeEmitter(sink) {
7866
7909
 
7867
7910
  // ../api-routes/src/oauth.ts
7868
7911
  import crypto10 from "crypto";
7869
- import { and as and10, eq as eq16, isNull as isNull2, lt as lt2 } from "drizzle-orm";
7912
+ import { and as and10, eq as eq16, inArray as inArray7, isNull as isNull2, lt as lt2 } from "drizzle-orm";
7870
7913
  var CODE_TTL_MS = 6e4;
7871
7914
  var ACCESS_TTL_MS = 60 * 60 * 1e3;
7872
7915
  var REFRESH_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
@@ -8021,6 +8064,7 @@ function registerOAuthRoutesIn(app, opts) {
8021
8064
  // S256 only. Advertising `plain` would invite a downgrade attempt.
8022
8065
  code_challenge_methods_supported: ["S256"],
8023
8066
  token_endpoint_auth_methods_supported: ["client_secret_post", "none"],
8067
+ revocation_endpoint_auth_methods_supported: ["client_secret_post", "none"],
8024
8068
  scopes_supported: [...SUPPORTED_SCOPES]
8025
8069
  };
8026
8070
  }
@@ -8210,38 +8254,25 @@ function registerOAuthRoutesIn(app, opts) {
8210
8254
  return reply.redirect(request.url);
8211
8255
  });
8212
8256
  app.post("/oauth/token", async (request, reply) => {
8257
+ reply.header("cache-control", "no-store").header("pragma", "no-cache");
8213
8258
  const body = request.body ?? {};
8214
8259
  const now = /* @__PURE__ */ new Date();
8215
8260
  db.delete(oauthAuthorizationCodes).where(lt2(oauthAuthorizationCodes.expiresAt, now.toISOString())).run();
8216
- function checkClient(clientId) {
8217
- const client = db.select().from(oauthClients).where(eq16(oauthClients.id, clientId)).get();
8218
- if (!client || client.revokedAt) return "invalid_client";
8219
- if (client.secretHash) {
8220
- const presented = body.client_secret;
8221
- if (!presented) return "invalid_secret";
8222
- const expected = Buffer.from(client.secretHash);
8223
- const actual = Buffer.from(sha256(presented));
8224
- if (expected.length !== actual.length || !crypto10.timingSafeEqual(expected, actual)) {
8225
- return "invalid_secret";
8226
- }
8227
- }
8228
- return "ok";
8229
- }
8230
- function issue(clientId, userId, resource, scope) {
8261
+ function issue(tx, grant) {
8231
8262
  const accessToken = newToken();
8232
8263
  const refreshToken = newToken();
8233
- const rows = [
8264
+ for (const row of [
8234
8265
  { token: accessToken, kind: "access", ttl: ACCESS_TTL_MS },
8235
8266
  { token: refreshToken, kind: "refresh", ttl: REFRESH_TTL_MS }
8236
- ];
8237
- for (const row of rows) {
8238
- db.insert(oauthTokens).values({
8267
+ ]) {
8268
+ tx.insert(oauthTokens).values({
8239
8269
  tokenHash: sha256(row.token),
8240
8270
  kind: row.kind,
8241
- clientId,
8242
- userId,
8243
- resource,
8244
- scope,
8271
+ grantId: grant.id,
8272
+ clientId: grant.clientId,
8273
+ userId: grant.userId,
8274
+ resource: grant.resource,
8275
+ scope: grant.scope,
8245
8276
  expiresAt: new Date(now.getTime() + row.ttl).toISOString(),
8246
8277
  createdAt: now.toISOString()
8247
8278
  }).run();
@@ -8250,54 +8281,119 @@ function registerOAuthRoutesIn(app, opts) {
8250
8281
  access_token: accessToken,
8251
8282
  token_type: "Bearer",
8252
8283
  expires_in: Math.floor(ACCESS_TTL_MS / 1e3),
8253
- // Without a refresh token the client silently loses access at the
8254
- // first expiry, which reads to a user as the connector breaking.
8284
+ // Preserve refresh issuance for existing clients that omit offline_access.
8255
8285
  refresh_token: refreshToken,
8256
- scope: scope ?? "read"
8286
+ scope: grant.scope ?? "read"
8257
8287
  };
8258
8288
  }
8259
8289
  if (body.grant_type === "authorization_code") {
8260
8290
  const code = body.code;
8261
8291
  const verifier = body.code_verifier;
8262
8292
  if (!code || !verifier) return badRequest(reply, "invalid_request", "code and code_verifier are required.");
8263
- const row = db.select().from(oauthAuthorizationCodes).where(eq16(oauthAuthorizationCodes.codeHash, sha256(code))).get();
8264
- if (!row) return badRequest(reply, "invalid_grant", "Unknown or already-redeemed code.");
8265
- db.delete(oauthAuthorizationCodes).where(eq16(oauthAuthorizationCodes.codeHash, row.codeHash)).run();
8266
- if (Date.parse(row.expiresAt) <= now.getTime()) return badRequest(reply, "invalid_grant", "Code has expired.");
8267
- if (body.client_id !== row.clientId) return badRequest(reply, "invalid_grant", "Code was issued to a different client.");
8268
- const clientState = checkClient(row.clientId);
8269
- if (clientState !== "ok") return badRequest(reply, "invalid_client", "Client is unknown, revoked, or failed authentication.");
8270
- if (body.redirect_uri !== row.redirectUri) return badRequest(reply, "invalid_grant", "redirect_uri does not match the authorization request.");
8271
- if (!verifyPkce(verifier, row.codeChallenge)) return badRequest(reply, "invalid_grant", "PKCE verification failed.");
8272
- return issue(row.clientId, row.userId, row.resource, row.scope);
8293
+ const result = db.transaction((tx) => {
8294
+ const row = tx.delete(oauthAuthorizationCodes).where(eq16(oauthAuthorizationCodes.codeHash, sha256(code))).returning().get();
8295
+ if (!row) return { error: "invalid_grant", description: "Unknown or already-redeemed code." };
8296
+ if (Date.parse(row.expiresAt) <= now.getTime()) return { error: "invalid_grant", description: "Code has expired." };
8297
+ if (body.client_id !== row.clientId) return { error: "invalid_grant", description: "Code was issued to a different client." };
8298
+ if (!authenticateClient(tx, row.clientId, body.client_secret)) return { error: "invalid_client", description: "Client is unknown, revoked, or failed authentication." };
8299
+ if (body.redirect_uri !== row.redirectUri) return { error: "invalid_grant", description: "redirect_uri does not match the authorization request." };
8300
+ if (!verifyPkce(verifier, row.codeChallenge)) return { error: "invalid_grant", description: "PKCE verification failed." };
8301
+ if (body.resource && body.resource !== row.resource) return { error: "invalid_target", description: "resource does not match the authorization grant." };
8302
+ const grant = { id: crypto10.randomUUID(), clientId: row.clientId, userId: row.userId, resource: row.resource, scope: row.scope };
8303
+ tx.insert(oauthGrants).values({ ...grant, createdAt: now.toISOString() }).run();
8304
+ return { tokens: issue(tx, grant) };
8305
+ }, { behavior: "immediate" });
8306
+ return result.tokens ?? badRequest(reply, result.error, result.description);
8273
8307
  }
8274
8308
  if (body.grant_type === "refresh_token") {
8275
8309
  const presented = body.refresh_token;
8276
- if (!presented) return badRequest(reply, "invalid_request", "refresh_token is required.");
8277
- const row = db.select().from(oauthTokens).where(and10(eq16(oauthTokens.tokenHash, sha256(presented)), eq16(oauthTokens.kind, "refresh"))).get();
8278
- if (!row || row.revokedAt) return badRequest(reply, "invalid_grant", "Unknown or revoked refresh token.");
8279
- if (Date.parse(row.expiresAt) <= now.getTime()) return badRequest(reply, "invalid_grant", "Refresh token has expired.");
8280
- const refreshClientState = checkClient(row.clientId);
8281
- if (refreshClientState !== "ok") return badRequest(reply, "invalid_client", "Client is unknown, revoked, or failed authentication.");
8282
- db.update(oauthTokens).set({ revokedAt: now.toISOString() }).where(eq16(oauthTokens.tokenHash, row.tokenHash)).run();
8283
- return issue(row.clientId, row.userId, row.resource, row.scope);
8310
+ if (!presented || !body.client_id) return badRequest(reply, "invalid_request", "refresh_token and client_id are required.");
8311
+ const result = db.transaction((tx) => {
8312
+ const row = tx.select().from(oauthTokens).where(and10(eq16(oauthTokens.tokenHash, sha256(presented)), eq16(oauthTokens.kind, "refresh"))).get();
8313
+ if (!row) return { error: "invalid_grant", description: "Unknown refresh token." };
8314
+ if (body.client_id !== row.clientId) return { error: "invalid_grant", description: "Refresh token was issued to a different client." };
8315
+ if (!authenticateClient(tx, row.clientId, body.client_secret)) return { error: "invalid_client", description: "Client is unknown, revoked, or failed authentication." };
8316
+ if (body.resource && body.resource !== row.resource) return { error: "invalid_target", description: "resource does not match the authorization grant." };
8317
+ if (row.revokedAt) {
8318
+ const grantId2 = row.grantId ?? adoptLegacyGrant(tx, row, now.toISOString());
8319
+ if (grantId2) revokeGrant(tx, grantId2, now.toISOString());
8320
+ return { error: "invalid_grant", description: "Refresh token was already used or revoked. Reconnect this authorization." };
8321
+ }
8322
+ if (Date.parse(row.expiresAt) <= now.getTime()) return { error: "invalid_grant", description: "Refresh token has expired." };
8323
+ const grant = row.grantId ? tx.select().from(oauthGrants).where(eq16(oauthGrants.id, row.grantId)).get() : void 0;
8324
+ if (row.grantId && (!grant || grant.revokedAt)) return { error: "invalid_grant", description: "Authorization has been revoked." };
8325
+ const grantId = row.grantId ?? adoptLegacyGrant(tx, row, now.toISOString());
8326
+ if (!grantId) return { error: "invalid_grant", description: "Authorization no longer has an existing account and client." };
8327
+ const consumed = tx.update(oauthTokens).set({ revokedAt: now.toISOString() }).where(and10(eq16(oauthTokens.tokenHash, row.tokenHash), isNull2(oauthTokens.revokedAt))).run();
8328
+ if (consumed.changes !== 1) return { error: "invalid_grant", description: "Refresh token was already used." };
8329
+ return { tokens: issue(tx, { ...row, id: grantId }) };
8330
+ }, { behavior: "immediate" });
8331
+ return result.tokens ?? badRequest(reply, result.error, result.description);
8284
8332
  }
8285
8333
  return badRequest(reply, "unsupported_grant_type", "Supported grants: authorization_code, refresh_token.");
8286
8334
  });
8287
8335
  app.post("/oauth/revoke", async (request, reply) => {
8288
8336
  const body = request.body ?? {};
8289
- if (body.token) {
8290
- db.update(oauthTokens).set({ revokedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(eq16(oauthTokens.tokenHash, sha256(body.token))).run();
8291
- }
8337
+ const now = (/* @__PURE__ */ new Date()).toISOString();
8338
+ const result = db.transaction((tx) => {
8339
+ if (body.client_id && !authenticateClient(tx, body.client_id, body.client_secret)) return "invalid_client";
8340
+ const row = body.token ? tx.select().from(oauthTokens).where(eq16(oauthTokens.tokenHash, sha256(body.token))).get() : void 0;
8341
+ if (!row || row.revokedAt || !Number.isFinite(Date.parse(row.expiresAt)) || Date.parse(row.expiresAt) <= Date.parse(now)) return;
8342
+ if (body.client_id && body.client_id !== row.clientId) return;
8343
+ if (!body.client_id && !authenticateClient(tx, row.clientId, body.client_secret)) return;
8344
+ const grantId = row.grantId ?? adoptLegacyGrant(tx, row, now);
8345
+ if (grantId) revokeGrant(tx, grantId, now);
8346
+ }, { behavior: "immediate" });
8347
+ if (result) return badRequest(reply, result, "Client is unknown, revoked, or failed authentication.");
8292
8348
  return reply.status(200).send({});
8293
8349
  });
8294
8350
  }
8351
+ function authenticateClient(db, clientId, secret) {
8352
+ const client = db.select().from(oauthClients).where(eq16(oauthClients.id, clientId)).get();
8353
+ if (!client || client.revokedAt) return false;
8354
+ if (!client.secretHash) return true;
8355
+ if (!secret) return false;
8356
+ const expected = Buffer.from(client.secretHash);
8357
+ const actual = Buffer.from(sha256(secret));
8358
+ return expected.length === actual.length && crypto10.timingSafeEqual(expected, actual);
8359
+ }
8360
+ function adoptLegacyGrant(db, row, now) {
8361
+ if (!db.select({ id: users.id }).from(users).where(eq16(users.id, row.userId)).get() || !db.select({ id: oauthClients.id }).from(oauthClients).where(eq16(oauthClients.id, row.clientId)).get()) return null;
8362
+ const identity = and10(
8363
+ eq16(oauthTokens.clientId, row.clientId),
8364
+ eq16(oauthTokens.userId, row.userId),
8365
+ row.resource === null ? isNull2(oauthTokens.resource) : eq16(oauthTokens.resource, row.resource),
8366
+ row.scope === null ? isNull2(oauthTokens.scope) : eq16(oauthTokens.scope, row.scope),
8367
+ isNull2(oauthTokens.grantId)
8368
+ );
8369
+ const id = crypto10.randomUUID();
8370
+ db.insert(oauthGrants).values({ id, clientId: row.clientId, userId: row.userId, resource: row.resource, scope: row.scope, createdAt: now }).run();
8371
+ db.update(oauthTokens).set({ grantId: id }).where(identity).run();
8372
+ return id;
8373
+ }
8374
+ function revokeGrant(db, grantId, now) {
8375
+ db.update(oauthGrants).set({ revokedAt: now }).where(and10(eq16(oauthGrants.id, grantId), isNull2(oauthGrants.revokedAt))).run();
8376
+ db.update(oauthTokens).set({ revokedAt: now }).where(and10(eq16(oauthTokens.grantId, grantId), isNull2(oauthTokens.revokedAt))).run();
8377
+ const delegatedKeys = db.select({ id: apiKeys.id }).from(apiKeys).where(eq16(apiKeys.delegatedOAuthGrantId, grantId));
8378
+ db.delete(dashboardSessions).where(inArray7(dashboardSessions.apiKeyId, delegatedKeys)).run();
8379
+ db.update(apiKeys).set({ revokedAt: now }).where(and10(eq16(apiKeys.delegatedOAuthGrantId, grantId), isNull2(apiKeys.revokedAt))).run();
8380
+ }
8295
8381
  function resolveOAuthAccessToken(db, token, expectedResource, now = /* @__PURE__ */ new Date()) {
8296
8382
  const row = db.select().from(oauthTokens).where(and10(eq16(oauthTokens.tokenHash, sha256(token)), eq16(oauthTokens.kind, "access"))).get();
8297
8383
  if (!row || row.revokedAt) return null;
8298
8384
  if (Date.parse(row.expiresAt) <= now.getTime()) return null;
8299
8385
  if (row.resource && row.resource !== expectedResource) return null;
8300
- return { userId: row.userId, clientId: row.clientId, scope: row.scope };
8386
+ const client = db.select().from(oauthClients).where(eq16(oauthClients.id, row.clientId)).get();
8387
+ if (!client || client.revokedAt) return null;
8388
+ const grantId = row.grantId ?? db.transaction((tx) => {
8389
+ const current = tx.select().from(oauthTokens).where(eq16(oauthTokens.tokenHash, row.tokenHash)).get();
8390
+ if (!current || current.revokedAt) return null;
8391
+ return current.grantId ?? adoptLegacyGrant(tx, current, now.toISOString());
8392
+ }, { behavior: "immediate" });
8393
+ if (!grantId) return null;
8394
+ const grant = db.select().from(oauthGrants).where(eq16(oauthGrants.id, grantId)).get();
8395
+ if (!grant || grant.revokedAt) return null;
8396
+ return { userId: row.userId, clientId: row.clientId, grantId, scope: row.scope };
8301
8397
  }
8302
8398
  function registerOAuthAdminRoutes(app, opts) {
8303
8399
  const { db } = opts;
@@ -8320,19 +8416,22 @@ function registerOAuthAdminRoutes(app, opts) {
8320
8416
  }))
8321
8417
  };
8322
8418
  });
8323
- app.delete("/oauth/clients/:id", async (request, reply) => {
8419
+ app.delete("/oauth/clients/:id", async (request) => {
8324
8420
  requireAdminSession(request);
8325
8421
  const { id } = request.params;
8326
- const client = db.select().from(oauthClients).where(eq16(oauthClients.id, id)).get();
8327
- if (!client) {
8328
- const error = notFound("OAuth client", id);
8329
- return reply.status(error.statusCode).send(error.toJSON());
8330
- }
8331
8422
  const now = (/* @__PURE__ */ new Date()).toISOString();
8332
- db.update(oauthClients).set({ revokedAt: now }).where(eq16(oauthClients.id, id)).run();
8333
- db.update(oauthTokens).set({ revokedAt: now }).where(and10(eq16(oauthTokens.clientId, id), isNull2(oauthTokens.revokedAt))).run();
8334
- db.delete(oauthAuthorizationCodes).where(eq16(oauthAuthorizationCodes.clientId, id)).run();
8335
- return { id, revokedAt: now };
8423
+ const revokedAt = db.transaction((tx) => {
8424
+ const client = tx.select().from(oauthClients).where(eq16(oauthClients.id, id)).get();
8425
+ if (!client) throw notFound("OAuth client", id);
8426
+ tx.update(oauthClients).set({ revokedAt: now }).where(and10(eq16(oauthClients.id, id), isNull2(oauthClients.revokedAt))).run();
8427
+ for (const grant of tx.select().from(oauthGrants).where(eq16(oauthGrants.clientId, id)).all()) {
8428
+ revokeGrant(tx, grant.id, now);
8429
+ }
8430
+ tx.update(oauthTokens).set({ revokedAt: now }).where(and10(eq16(oauthTokens.clientId, id), isNull2(oauthTokens.revokedAt))).run();
8431
+ tx.delete(oauthAuthorizationCodes).where(eq16(oauthAuthorizationCodes.clientId, id)).run();
8432
+ return client.revokedAt ?? now;
8433
+ }, { behavior: "immediate" });
8434
+ return { id, revokedAt };
8336
8435
  });
8337
8436
  }
8338
8437
 
@@ -9393,10 +9492,10 @@ async function settingsRoutes(app, opts) {
9393
9492
 
9394
9493
  // ../api-routes/src/run-queue.ts
9395
9494
  import crypto12 from "crypto";
9396
- import { and as and13, desc as desc7, eq as eq19, gt as gt2, inArray as inArray8, like as like2, or as or3 } from "drizzle-orm";
9495
+ import { and as and13, desc as desc7, eq as eq19, gt as gt2, inArray as inArray9, like as like2, or as or3 } from "drizzle-orm";
9397
9496
 
9398
9497
  // ../api-routes/src/measurement-report-adapter.ts
9399
- import { and as and11, desc as desc5, eq as eq17, gte as gte2, inArray as inArray7, isNull as isNull3, lt as lt3, lte as lte4, ne as ne5 } from "drizzle-orm";
9498
+ import { and as and11, desc as desc5, eq as eq17, gte as gte2, inArray as inArray8, isNull as isNull3, lt as lt3, lte as lte4, ne as ne5 } from "drizzle-orm";
9400
9499
 
9401
9500
  // ../api-routes/src/measurement-report.ts
9402
9501
  function normalizedHost(value) {
@@ -10579,9 +10678,9 @@ function latestMeasurementRun(db, projectId, versionId, statuses, window2 = {},
10579
10678
  // must never borrow a predecessor's run through the comparable chain; the
10580
10679
  // active-dashboard surfaces want the chain so a label-only republish does
10581
10680
  // not blank them. exactVersion selects the contract.
10582
- opts.exactVersion ? eq17(runs.measurementPlanVersionId, versionId) : inArray7(runs.measurementPlanVersionId, comparableMeasurementVersionIds(db, projectId, versionId)),
10681
+ opts.exactVersion ? eq17(runs.measurementPlanVersionId, versionId) : inArray8(runs.measurementPlanVersionId, comparableMeasurementVersionIds(db, projectId, versionId)),
10583
10682
  eq17(runs.kind, RunKinds["answer-visibility"]),
10584
- inArray7(runs.status, [...statuses]),
10683
+ inArray8(runs.status, [...statuses]),
10585
10684
  ne5(runs.trigger, RunTriggers.probe),
10586
10685
  isNull3(runs.measurementScope)
10587
10686
  ];
@@ -10593,9 +10692,9 @@ function pinnedMeasurementRun(db, projectId, versionId, runId, opts = {}) {
10593
10692
  return db.select().from(runs).where(and11(
10594
10693
  eq17(runs.id, runId),
10595
10694
  eq17(runs.projectId, projectId),
10596
- opts.exactVersion ? eq17(runs.measurementPlanVersionId, versionId) : inArray7(runs.measurementPlanVersionId, comparableMeasurementVersionIds(db, projectId, versionId)),
10695
+ opts.exactVersion ? eq17(runs.measurementPlanVersionId, versionId) : inArray8(runs.measurementPlanVersionId, comparableMeasurementVersionIds(db, projectId, versionId)),
10597
10696
  eq17(runs.kind, RunKinds["answer-visibility"]),
10598
- inArray7(runs.status, [RunStatuses.completed, RunStatuses.partial]),
10697
+ inArray8(runs.status, [RunStatuses.completed, RunStatuses.partial]),
10599
10698
  ne5(runs.trigger, RunTriggers.probe),
10600
10699
  isNull3(runs.measurementScope)
10601
10700
  )).get();
@@ -10655,7 +10754,7 @@ function buildStoredMeasurementReport(db, projectId, revision, runId, queryClass
10655
10754
  eq17(runs.projectId, projectId),
10656
10755
  eq17(runs.measurementPlanVersionId, version.id),
10657
10756
  eq17(runs.kind, RunKinds["answer-visibility"]),
10658
- inArray7(runs.status, [RunStatuses.completed, RunStatuses.partial]),
10757
+ inArray8(runs.status, [RunStatuses.completed, RunStatuses.partial]),
10659
10758
  ne5(runs.trigger, RunTriggers.probe)
10660
10759
  )).orderBy(desc5(runs.createdAt), desc5(runs.id)).get();
10661
10760
  let selectedRun = run;
@@ -11139,7 +11238,7 @@ function heldProviderAccounts(db, params) {
11139
11238
  }).from(runs).where(and13(
11140
11239
  eq19(runs.projectId, params.projectId),
11141
11240
  eq19(runs.kind, RunKinds["answer-visibility"]),
11142
- inArray8(runs.status, [RunStatuses.completed, RunStatuses.partial, RunStatuses.failed, RunStatuses.cancelled])
11241
+ inArray9(runs.status, [RunStatuses.completed, RunStatuses.partial, RunStatuses.failed, RunStatuses.cancelled])
11143
11242
  )).orderBy(desc7(runs.createdAt), desc7(runs.id)).limit(PROVIDER_ACCOUNT_LOOKBACK).all().map((run) => ({ ...run, providers: parseRunError(run.error)?.providers ?? {} }));
11144
11243
  const entries = recent.flatMap((run) => Object.values(run.providers));
11145
11244
  const withAccountFailure = recent.filter((run) => Object.values(run.providers).some((entry) => !entry.skipped && isProviderAccountFailure(entry.code)));
@@ -11201,7 +11300,7 @@ function heldProviderAccounts(db, params) {
11201
11300
  }
11202
11301
  if (held.size === 0) return held;
11203
11302
  const since = [...held.values()].map((streak) => streak.since).sort()[0];
11204
- const settingsChanges = db.select({ entityId: auditLog.entityId, action: auditLog.action, diff: auditLog.diff, createdAt: auditLog.createdAt }).from(auditLog).where(and13(eq19(auditLog.entityType, "provider"), inArray8(auditLog.entityId, [...held.keys()]), gt2(auditLog.createdAt, since))).all();
11303
+ const settingsChanges = db.select({ entityId: auditLog.entityId, action: auditLog.action, diff: auditLog.diff, createdAt: auditLog.createdAt }).from(auditLog).where(and13(eq19(auditLog.entityType, "provider"), inArray9(auditLog.entityId, [...held.keys()]), gt2(auditLog.createdAt, since))).all();
11205
11304
  for (const change of settingsChanges) {
11206
11305
  const streak = held.get(change.entityId ?? "");
11207
11306
  if (streak && change.createdAt > streak.since && providerSettingsChangeCouldFix(change.action, change.diff)) {
@@ -11358,7 +11457,7 @@ function queueRunIfProjectIdle(db, params) {
11358
11457
  }
11359
11458
 
11360
11459
  // ../api-routes/src/provider-batches.ts
11361
- import { and as and14, asc as asc4, eq as eq20, inArray as inArray9 } from "drizzle-orm";
11460
+ import { and as and14, asc as asc4, eq as eq20, inArray as inArray10 } from "drizzle-orm";
11362
11461
  function formatProviderBatchSummary(row) {
11363
11462
  return {
11364
11463
  id: row.id,
@@ -11381,10 +11480,10 @@ function runHadProviderBatch(db, runId) {
11381
11480
  return db.select({ id: providerBatches.id }).from(providerBatches).where(eq20(providerBatches.runId, runId)).limit(1).get() !== void 0;
11382
11481
  }
11383
11482
  function hasOutstandingProviderBatch(db, runId) {
11384
- return db.select({ id: providerBatches.id }).from(providerBatches).where(and14(eq20(providerBatches.runId, runId), inArray9(providerBatches.status, [...OUTSTANDING_PROVIDER_BATCH_STATUSES]))).limit(1).get() !== void 0;
11483
+ return db.select({ id: providerBatches.id }).from(providerBatches).where(and14(eq20(providerBatches.runId, runId), inArray10(providerBatches.status, [...OUTSTANDING_PROVIDER_BATCH_STATUSES]))).limit(1).get() !== void 0;
11385
11484
  }
11386
11485
  function readProjectRunsWithOutstandingProviderBatch(db, projectId) {
11387
- return db.selectDistinct({ runId: providerBatches.runId }).from(providerBatches).where(and14(eq20(providerBatches.projectId, projectId), inArray9(providerBatches.status, [...OUTSTANDING_PROVIDER_BATCH_STATUSES]))).orderBy(asc4(providerBatches.runId)).all().map((row) => row.runId);
11486
+ return db.selectDistinct({ runId: providerBatches.runId }).from(providerBatches).where(and14(eq20(providerBatches.projectId, projectId), inArray10(providerBatches.status, [...OUTSTANDING_PROVIDER_BATCH_STATUSES]))).orderBy(asc4(providerBatches.runId)).all().map((row) => row.runId);
11388
11487
  }
11389
11488
 
11390
11489
  // ../api-routes/src/notification-redaction.ts
@@ -12098,7 +12197,7 @@ function aliasArraysEqual(a, b) {
12098
12197
 
12099
12198
  // ../api-routes/src/queries.ts
12100
12199
  import crypto15 from "crypto";
12101
- import { and as and17, eq as eq23, inArray as inArray11, sql as sql5 } from "drizzle-orm";
12200
+ import { and as and17, eq as eq23, inArray as inArray12, sql as sql5 } from "drizzle-orm";
12102
12201
 
12103
12202
  // ../api-routes/src/query-class-read.ts
12104
12203
  function storedQueryClasses(db, projectId) {
@@ -12130,9 +12229,9 @@ function readQueryClasses(db, project, rows) {
12130
12229
 
12131
12230
  // ../api-routes/src/query-replace.ts
12132
12231
  import crypto14 from "crypto";
12133
- import { and as and16, eq as eq22, inArray as inArray10, isNull as isNull4 } from "drizzle-orm";
12232
+ import { and as and16, eq as eq22, inArray as inArray11, isNull as isNull4 } from "drizzle-orm";
12134
12233
  function preserveSnapshotQueryText(tx, projectId, queryIds) {
12135
- const candidates = queryIds && queryIds.length > 0 ? tx.select({ id: queries.id, text: queries.query }).from(queries).where(and16(eq22(queries.projectId, projectId), inArray10(queries.id, queryIds))).all() : tx.select({ id: queries.id, text: queries.query }).from(queries).where(eq22(queries.projectId, projectId)).all();
12234
+ const candidates = queryIds && queryIds.length > 0 ? tx.select({ id: queries.id, text: queries.query }).from(queries).where(and16(eq22(queries.projectId, projectId), inArray11(queries.id, queryIds))).all() : tx.select({ id: queries.id, text: queries.query }).from(queries).where(eq22(queries.projectId, projectId)).all();
12136
12235
  for (const q of candidates) {
12137
12236
  tx.update(querySnapshots).set({ queryText: q.text }).where(and16(eq22(querySnapshots.queryId, q.id), isNull4(querySnapshots.queryText))).run();
12138
12237
  }
@@ -12195,7 +12294,7 @@ function assertNoActivePlanlessSweep(tx, scope) {
12195
12294
  const activeRun = tx.select({ id: runs.id }).from(runs).where(and16(
12196
12295
  eq22(runs.projectId, scope.projectId),
12197
12296
  eq22(runs.kind, RunKinds["answer-visibility"]),
12198
- inArray10(runs.status, [RunStatuses.queued, RunStatuses.running]),
12297
+ inArray11(runs.status, [RunStatuses.queued, RunStatuses.running]),
12199
12298
  isNull4(runs.measurementPlanVersionId)
12200
12299
  )).get();
12201
12300
  if (activeRun) throw runInProgress(scope.projectName, RunKinds["answer-visibility"], activeRun.id);
@@ -12248,11 +12347,11 @@ function replaceProjectQueries(tx, projectId, incomingTexts, now) {
12248
12347
  for (const dup of diff.duplicates) {
12249
12348
  tx.update(querySnapshots).set({ queryId: dup.keptId }).where(eq22(querySnapshots.queryId, dup.id)).run();
12250
12349
  }
12251
- tx.delete(queries).where(inArray10(queries.id, diff.duplicates.map((d) => d.id))).run();
12350
+ tx.delete(queries).where(inArray11(queries.id, diff.duplicates.map((d) => d.id))).run();
12252
12351
  }
12253
12352
  if (diff.removed.length > 0) {
12254
12353
  const removedIds = diff.removed.map((r) => r.id);
12255
- tx.delete(queries).where(inArray10(queries.id, removedIds)).run();
12354
+ tx.delete(queries).where(inArray11(queries.id, removedIds)).run();
12256
12355
  }
12257
12356
  for (const keptRow of diff.kept) {
12258
12357
  if (keptRow.currentText !== keptRow.incomingText) {
@@ -12350,9 +12449,9 @@ async function queryRoutes(app, opts) {
12350
12449
  let snapshotsDetached = 0;
12351
12450
  let affectedQueries = 0;
12352
12451
  if (removedIds.length > 0) {
12353
- const snapshotCount = app.db.select({ n: sql5`count(*)` }).from(querySnapshots).where(inArray11(querySnapshots.queryId, removedIds)).get();
12452
+ const snapshotCount = app.db.select({ n: sql5`count(*)` }).from(querySnapshots).where(inArray12(querySnapshots.queryId, removedIds)).get();
12354
12453
  snapshotsDetached = snapshotCount?.n ?? 0;
12355
- const distinctAffected = app.db.select({ n: sql5`count(distinct ${querySnapshots.queryId})` }).from(querySnapshots).where(inArray11(querySnapshots.queryId, removedIds)).get();
12454
+ const distinctAffected = app.db.select({ n: sql5`count(distinct ${querySnapshots.queryId})` }).from(querySnapshots).where(inArray12(querySnapshots.queryId, removedIds)).get();
12356
12455
  affectedQueries = distinctAffected?.n ?? 0;
12357
12456
  }
12358
12457
  return reply.send({
@@ -12633,7 +12732,7 @@ import { and as and22, eq as eq29 } from "drizzle-orm";
12633
12732
 
12634
12733
  // ../api-routes/src/competitor-auto-aliases.ts
12635
12734
  import { setImmediate as yieldToEventLoop2 } from "timers/promises";
12636
- import { and as and18, asc as asc5, desc as desc8, eq as eq24, inArray as inArray12 } from "drizzle-orm";
12735
+ import { and as and18, asc as asc5, desc as desc8, eq as eq24, inArray as inArray13 } from "drizzle-orm";
12637
12736
  var SCAN_PAGE_SIZE = 200;
12638
12737
  async function scanCompetitorAutoAliasEvidence(db, project, opts = {}) {
12639
12738
  const tracked = readStoredCompetitors(db, project.id);
@@ -12652,7 +12751,7 @@ async function scanCompetitorAutoAliasEvidence(db, project, opts = {}) {
12652
12751
  const runRows = tracked.length === 0 && market.length === 0 ? [] : db.select({ id: runs.id, createdAt: runs.createdAt, planVersionId: runs.measurementPlanVersionId }).from(runs).where(and18(
12653
12752
  eq24(runs.projectId, project.id),
12654
12753
  eq24(runs.kind, RunKinds["answer-visibility"]),
12655
- inArray12(runs.status, [RunStatuses.completed, RunStatuses.partial]),
12754
+ inArray13(runs.status, [RunStatuses.completed, RunStatuses.partial]),
12656
12755
  notProbeRun()
12657
12756
  )).orderBy(desc8(runs.createdAt), desc8(runs.id)).limit(AUTO_ALIAS_SCAN_MAX_RUNS).all();
12658
12757
  const pause = () => opts.yieldToEventLoop === false ? Promise.resolve() : yieldToEventLoop2();
@@ -12674,7 +12773,7 @@ async function scanCompetitorAutoAliasEvidence(db, project, opts = {}) {
12674
12773
  rawResponse: querySnapshots.rawResponse,
12675
12774
  executionId: querySnapshots.measurementExecutionId,
12676
12775
  createdAt: querySnapshots.createdAt
12677
- }).from(querySnapshots).where(inArray12(querySnapshots.id, ids.slice(offset, offset + SCAN_PAGE_SIZE))).all();
12776
+ }).from(querySnapshots).where(inArray13(querySnapshots.id, ids.slice(offset, offset + SCAN_PAGE_SIZE))).all();
12678
12777
  scannedSnapshots += rows.length;
12679
12778
  for (const row of rows) {
12680
12779
  accumulator.add({
@@ -12850,10 +12949,10 @@ function createProjectPassQueue(run, opts = {}) {
12850
12949
  }
12851
12950
 
12852
12951
  // ../api-routes/src/competitor-change-preview.ts
12853
- import { and as and21, eq as eq28, inArray as inArray14 } from "drizzle-orm";
12952
+ import { and as and21, eq as eq28, inArray as inArray15 } from "drizzle-orm";
12854
12953
 
12855
12954
  // ../api-routes/src/competitor-landscape.ts
12856
- import { and as and20, desc as desc9, eq as eq27, gte as gte3, inArray as inArray13, isNull as isNull5, or as or4, sql as sql6 } from "drizzle-orm";
12955
+ import { and as and20, desc as desc9, eq as eq27, gte as gte3, inArray as inArray14, isNull as isNull5, or as or4, sql as sql6 } from "drizzle-orm";
12857
12956
 
12858
12957
  // ../api-routes/src/mention-share-inputs.ts
12859
12958
  import { eq as eq25 } from "drizzle-orm";
@@ -13714,8 +13813,8 @@ function selectLandscapePopulation(app, projectName, filters, selection) {
13714
13813
  const candidateRuns = app.db.select().from(runs).where(and20(
13715
13814
  eq27(runs.projectId, project.id),
13716
13815
  eq27(runs.kind, RunKinds["answer-visibility"]),
13717
- selection?.runIds ? inArray13(runs.id, [...selection.runIds]) : void 0,
13718
- latestRunIds ? inArray13(runs.id, latestRunIds) : filters.runId ? eq27(runs.id, filters.runId) : void 0,
13816
+ selection?.runIds ? inArray14(runs.id, [...selection.runIds]) : void 0,
13817
+ latestRunIds ? inArray14(runs.id, latestRunIds) : filters.runId ? eq27(runs.id, filters.runId) : void 0,
13719
13818
  cutoff ? gte3(runs.createdAt, cutoff) : void 0
13720
13819
  )).all();
13721
13820
  const advanced = filters.groupKey || filters.scope === "all-markets" ? resolveAdvancedScope(app, project.id, filters.groupKey ? "group" : "all-markets", filters.groupKey, candidateRuns) : null;
@@ -13746,7 +13845,7 @@ function selectLandscapePopulation(app, projectName, filters, selection) {
13746
13845
  location: querySnapshots.location,
13747
13846
  measurementExecutionId: querySnapshots.measurementExecutionId,
13748
13847
  createdAt: querySnapshots.createdAt
13749
- }).from(querySnapshots).where(inArray13(querySnapshots.runId, candidateRuns.map((run) => run.id))).all();
13848
+ }).from(querySnapshots).where(inArray14(querySnapshots.runId, candidateRuns.map((run) => run.id))).all();
13750
13849
  const runById = new Map(candidateRuns.map((run) => [run.id, run]));
13751
13850
  const selectedIds = selection?.snapshotIds ? new Set(selection.snapshotIds) : null;
13752
13851
  const inScope = allSnapshots.filter((snapshot) => (!selectedIds || selectedIds.has(snapshot.id)) && snapshotMatchesFilters({
@@ -13773,7 +13872,7 @@ function selectLandscapePopulation(app, projectName, filters, selection) {
13773
13872
  );
13774
13873
  }
13775
13874
  const hydratedInScope = selection?.answerTextCap === void 0 || eligibleSnapshots.length === 0 ? inScope : (() => {
13776
- const answerTextById = new Map(app.db.select({ id: querySnapshots.id, answerText: querySnapshots.answerText }).from(querySnapshots).where(inArray13(querySnapshots.id, eligibleSnapshots.map((snapshot) => snapshot.id))).all().map((row) => [row.id, row.answerText]));
13875
+ const answerTextById = new Map(app.db.select({ id: querySnapshots.id, answerText: querySnapshots.answerText }).from(querySnapshots).where(inArray14(querySnapshots.id, eligibleSnapshots.map((snapshot) => snapshot.id))).all().map((row) => [row.id, row.answerText]));
13777
13876
  return inScope.map((snapshot) => eligibleRuns.has(snapshot.runId) ? { ...snapshot, answerText: answerTextById.get(snapshot.id) ?? null } : snapshot);
13778
13877
  })();
13779
13878
  return {
@@ -13810,7 +13909,7 @@ function latestSweepRuns(db, projectId) {
13810
13909
  const candidates = db.select().from(runs).where(and20(
13811
13910
  eq27(runs.projectId, projectId),
13812
13911
  eq27(runs.kind, RunKinds["answer-visibility"]),
13813
- inArray13(runs.status, [RunStatuses.completed, RunStatuses.partial]),
13912
+ inArray14(runs.status, [RunStatuses.completed, RunStatuses.partial]),
13814
13913
  notProbeRun(),
13815
13914
  // A scoped spot check is never the latest sweep.
13816
13915
  isNull5(runs.measurementScope)
@@ -13863,7 +13962,7 @@ function readCompetitorIdentityChangedAt(db, projectId) {
13863
13962
  const row = db.select({ at: sql6`max(${auditLog.createdAt})` }).from(auditLog).where(and20(
13864
13963
  eq27(auditLog.projectId, projectId),
13865
13964
  or4(
13866
- inArray13(auditLog.action, COMPETITOR_NAME_CHANGE_ACTIONS),
13965
+ inArray14(auditLog.action, COMPETITOR_NAME_CHANGE_ACTIONS),
13867
13966
  sql6`(json_valid(${diff}) AND (
13868
13967
  json_type(${diff}, '$.aliasChanges') = 'array'
13869
13968
  OR json_type(${diff}, '$.autoAliasChanges') = 'array'
@@ -14114,7 +14213,7 @@ function frozenRunScopes(db, projectId, kind, groupKey, candidateRuns) {
14114
14213
  const planVersionIds = [...new Set(candidateRuns.map((run) => run.measurementPlanVersionId).filter((id) => typeof id === "string" && id.length > 0))];
14115
14214
  const historicalVersions = planVersionIds.length === 0 ? [] : db.select().from(measurementPlanVersions).where(and20(
14116
14215
  eq27(measurementPlanVersions.projectId, projectId),
14117
- inArray13(measurementPlanVersions.id, planVersionIds)
14216
+ inArray14(measurementPlanVersions.id, planVersionIds)
14118
14217
  )).all();
14119
14218
  const frozenByVersionId = new Map(historicalVersions.map((version) => [
14120
14219
  version.id,
@@ -14288,7 +14387,7 @@ function previewCompetitorShareImpact(app, projectName, after, options = {}) {
14288
14387
  const before = shareOfVoiceFromLandscape(beforeLandscape, queryClass);
14289
14388
  const afterShare = shareOfVoiceFromLandscape(afterLandscape, queryClass);
14290
14389
  const runIds = beforeLandscape.runIds ?? [];
14291
- const sweepAt = runIds.length === 0 ? null : app.db.select({ createdAt: runs.createdAt }).from(runs).where(and21(eq28(runs.projectId, project.id), inArray14(runs.id, runIds))).all().map((row) => row.createdAt).sort().at(-1) ?? null;
14390
+ const sweepAt = runIds.length === 0 ? null : app.db.select({ createdAt: runs.createdAt }).from(runs).where(and21(eq28(runs.projectId, project.id), inArray15(runs.id, runIds))).all().map((row) => row.createdAt).sort().at(-1) ?? null;
14292
14391
  const caveats = [];
14293
14392
  if (queryClass === "pooled") caveats.push(CompetitorShareImpactCaveats["pooled"]);
14294
14393
  if (runIds.length === 0) caveats.push(CompetitorShareImpactCaveats["no-latest-sweep"]);
@@ -14938,13 +15037,13 @@ async function competitorSuggestionRoutes(app) {
14938
15037
 
14939
15038
  // ../api-routes/src/runs.ts
14940
15039
  import crypto18 from "crypto";
14941
- import { and as and25, eq as eq33, ne as ne7, asc as asc7, desc as desc12, inArray as inArray17, notInArray, or as or6, sql as sql9 } from "drizzle-orm";
15040
+ import { and as and25, eq as eq33, ne as ne7, asc as asc7, desc as desc12, inArray as inArray18, notInArray, or as or6, sql as sql9 } from "drizzle-orm";
14942
15041
  import { z as z3 } from "zod";
14943
15042
  import { gte as gte4 } from "drizzle-orm";
14944
15043
 
14945
15044
  // ../api-routes/src/run-fill.ts
14946
15045
  import crypto16 from "crypto";
14947
- import { and as and23, desc as desc10, eq as eq31, gt as gt3, inArray as inArray15, isNull as isNull6, ne as ne6, or as or5, sql as sql7 } from "drizzle-orm";
15046
+ import { and as and23, desc as desc10, eq as eq31, gt as gt3, inArray as inArray16, isNull as isNull6, ne as ne6, or as or5, sql as sql7 } from "drizzle-orm";
14948
15047
  var ACTIVE_STATUSES = ["queued", "running"];
14949
15048
  function normalizeProvider(value) {
14950
15049
  return value.trim().toLocaleLowerCase("en");
@@ -14974,7 +15073,7 @@ function newerFullSweep(db, run) {
14974
15073
  isNull6(runs.queries),
14975
15074
  gt3(runs.createdAt, run.createdAt),
14976
15075
  or5(
14977
- inArray15(runs.status, ["queued", "running", "completed", "partial"]),
15076
+ inArray16(runs.status, ["queued", "running", "completed", "partial"]),
14978
15077
  sql7`EXISTS (SELECT 1 FROM ${querySnapshots} WHERE ${querySnapshots.runId} = ${runs.id})`
14979
15078
  )
14980
15079
  )).orderBy(desc10(runs.createdAt)).get();
@@ -15120,13 +15219,13 @@ function latestFillFor(db, runId) {
15120
15219
  return db.select().from(runFills).where(eq31(runFills.runId, runId)).orderBy(desc10(runFills.createdAt), desc10(runFills.id)).get();
15121
15220
  }
15122
15221
  function activeFillFor(db, projectId) {
15123
- return db.select().from(runFills).where(and23(eq31(runFills.projectId, projectId), inArray15(runFills.status, [...ACTIVE_STATUSES]))).get();
15222
+ return db.select().from(runFills).where(and23(eq31(runFills.projectId, projectId), inArray16(runFills.status, [...ACTIVE_STATUSES]))).get();
15124
15223
  }
15125
15224
  function activeSweepFor(db, projectId) {
15126
15225
  return db.select({ id: runs.id }).from(runs).where(and23(
15127
15226
  eq31(runs.projectId, projectId),
15128
15227
  eq31(runs.kind, RunKinds["answer-visibility"]),
15129
- inArray15(runs.status, [...ACTIVE_STATUSES])
15228
+ inArray16(runs.status, [...ACTIVE_STATUSES])
15130
15229
  )).get();
15131
15230
  }
15132
15231
  function readRunCompleteness(db, run, input = {}) {
@@ -15190,7 +15289,7 @@ function queueRunFill(db, runId, input = {}) {
15190
15289
 
15191
15290
  // ../api-routes/src/seo.ts
15192
15291
  import crypto17 from "crypto";
15193
- import { and as and24, asc as asc6, desc as desc11, eq as eq32, inArray as inArray16, isNotNull as isNotNull3, sql as sql8 } from "drizzle-orm";
15292
+ import { and as and24, asc as asc6, desc as desc11, eq as eq32, inArray as inArray17, isNotNull as isNotNull3, sql as sql8 } from "drizzle-orm";
15194
15293
 
15195
15294
  // ../api-routes/src/measurement-scope-options.ts
15196
15295
  function marketLinks(keys, settings) {
@@ -15571,7 +15670,7 @@ async function seoRoutes(app, opts) {
15571
15670
  return profileDto(row);
15572
15671
  };
15573
15672
  const tasks = (id) => currentSeoTasks(app.db.select().from(seoTasks).where(eq32(seoTasks.jobId, id)).orderBy(asc6(seoTasks.id)).all());
15574
- const taskCounts = (ids) => ids.length ? app.db.select({ jobId: seoTasks.jobId, status: seoTasks.status, count: sql8`count(*)` }).from(seoTasks).where(and24(inArray16(seoTasks.jobId, ids), currentSeoTaskCondition())).groupBy(seoTasks.jobId, seoTasks.status).all() : [];
15673
+ const taskCounts = (ids) => ids.length ? app.db.select({ jobId: seoTasks.jobId, status: seoTasks.status, count: sql8`count(*)` }).from(seoTasks).where(and24(inArray17(seoTasks.jobId, ids), currentSeoTaskCondition())).groupBy(seoTasks.jobId, seoTasks.status).all() : [];
15575
15674
  const runSummary = (row) => runDto(row, taskCounts([row.id]));
15576
15675
  const job = (projectId, id) => {
15577
15676
  const row = app.db.select().from(seoJobs).where(and24(eq32(seoJobs.projectId, projectId), isNotNull3(seoJobs.runId), eq32(seoJobs.id, id))).get();
@@ -15586,7 +15685,7 @@ async function seoRoutes(app, opts) {
15586
15685
  if (query.profileId && row.profileId !== query.profileId) throw validationError("The SEO run does not belong to this profile.");
15587
15686
  return row;
15588
15687
  }
15589
- return app.db.select().from(seoJobs).where(and24(eq32(seoJobs.projectId, projectId), isNotNull3(seoJobs.runId), query.profileId ? eq32(seoJobs.profileId, query.profileId) : void 0, evidenceOnly ? inArray16(seoJobs.status, [SeoRunStatuses.completed, SeoRunStatuses.partial]) : void 0)).orderBy(desc11(seoJobs.createdAt), sql8`seo_jobs.rowid DESC`).get() ?? null;
15688
+ return app.db.select().from(seoJobs).where(and24(eq32(seoJobs.projectId, projectId), isNotNull3(seoJobs.runId), query.profileId ? eq32(seoJobs.profileId, query.profileId) : void 0, evidenceOnly ? inArray17(seoJobs.status, [SeoRunStatuses.completed, SeoRunStatuses.partial]) : void 0)).orderBy(desc11(seoJobs.createdAt), sql8`seo_jobs.rowid DESC`).get() ?? null;
15590
15689
  };
15591
15690
  const queryInput = (value) => {
15592
15691
  const raw = value ?? {};
@@ -15597,7 +15696,7 @@ async function seoRoutes(app, opts) {
15597
15696
  const status = (projectId) => {
15598
15697
  const runtime = getRuntime();
15599
15698
  const latest = app.db.select().from(seoJobs).where(and24(eq32(seoJobs.projectId, projectId), isNotNull3(seoJobs.runId))).orderBy(desc11(seoJobs.createdAt)).get();
15600
- const last = app.db.select().from(seoJobs).where(and24(eq32(seoJobs.projectId, projectId), isNotNull3(seoJobs.runId), inArray16(seoJobs.status, [SeoRunStatuses.completed, SeoRunStatuses.partial]))).orderBy(desc11(seoJobs.finishedAt)).get();
15699
+ const last = app.db.select().from(seoJobs).where(and24(eq32(seoJobs.projectId, projectId), isNotNull3(seoJobs.runId), inArray17(seoJobs.status, [SeoRunStatuses.completed, SeoRunStatuses.partial]))).orderBy(desc11(seoJobs.finishedAt)).get();
15601
15700
  const available = !!runtime?.connections.length && !!opts.onSeoRunRequested;
15602
15701
  return { available, reason: available ? null : "SEO execution is not configured on this host.", capabilities: [...new Set(runtime?.connections.flatMap((connection) => [...connection.adapter.capabilities]) ?? [])], profileCount: profiles(projectId).length, latestRunId: latest?.id ?? null, latestRunStatus: latest?.status ?? null, lastCompletedAt: last?.finishedAt ?? null };
15603
15702
  };
@@ -16219,7 +16318,7 @@ async function runRoutes(app, opts) {
16219
16318
  const terminalStatuses = /* @__PURE__ */ new Set(["completed", "partial", "failed", "cancelled"]);
16220
16319
  if (terminalStatuses.has(run.status)) throw runNotCancellable(run.id, run.status);
16221
16320
  const now = (/* @__PURE__ */ new Date()).toISOString();
16222
- const cancelled = app.db.update(runs).set({ status: "cancelled", finishedAt: now, error: serializeRunError({ message: "Cancelled by user" }) }).where(and25(eq33(runs.id, run.id), inArray17(runs.status, ["queued", "running"]))).run();
16321
+ const cancelled = app.db.update(runs).set({ status: "cancelled", finishedAt: now, error: serializeRunError({ message: "Cancelled by user" }) }).where(and25(eq33(runs.id, run.id), inArray18(runs.status, ["queued", "running"]))).run();
16223
16322
  if (cancelled.changes === 0) {
16224
16323
  const current = app.db.select().from(runs).where(eq33(runs.id, run.id)).get();
16225
16324
  if (!current) throw notFound("Run", run.id);
@@ -17556,7 +17655,7 @@ async function measurementServiceRoutes(app, opts) {
17556
17655
 
17557
17656
  // ../api-routes/src/measurement-draft.ts
17558
17657
  import crypto22 from "crypto";
17559
- import { and as and27, asc as asc8, desc as desc14, eq as eq35, inArray as inArray18 } from "drizzle-orm";
17658
+ import { and as and27, asc as asc8, desc as desc14, eq as eq35, inArray as inArray19 } from "drizzle-orm";
17560
17659
 
17561
17660
  // ../api-routes/src/measurement-draft-compile.ts
17562
17661
  var MEASUREMENT_DRAFT_MAX_TARGETS = 1e3;
@@ -20148,7 +20247,7 @@ async function measurementDraftRoutes(app, opts = {}) {
20148
20247
  // The comparable chain, not the bare active id: a label-only
20149
20248
  // republish must not flip setup back to awaiting_first_run while
20150
20249
  // the overview keeps serving the prior run.
20151
- inArray18(runs.measurementPlanVersionId, comparableMeasurementVersionIds(app.db, project.id, active.id)),
20250
+ inArray19(runs.measurementPlanVersionId, comparableMeasurementVersionIds(app.db, project.id, active.id)),
20152
20251
  eq35(runs.status, RunStatuses.completed)
20153
20252
  )).get() : void 0;
20154
20253
  const state = activeSchemaVersion === 1 ? "republish_required" : draft ? "setup_in_progress" : active ? completedRun ? "operational" : "awaiting_first_run" : "simple";
@@ -20848,7 +20947,7 @@ async function measurementDraftRoutes(app, opts = {}) {
20848
20947
  const sets = app.db.select().from(measurementQuerySets).where(eq35(measurementQuerySets.projectId, project.id)).orderBy(asc8(measurementQuerySets.name)).all();
20849
20948
  const counts2 = /* @__PURE__ */ new Map();
20850
20949
  if (sets.length) {
20851
- for (const item2 of app.db.select({ querySetId: measurementQuerySetItems.querySetId }).from(measurementQuerySetItems).where(inArray18(measurementQuerySetItems.querySetId, sets.map((set) => set.id))).all()) {
20950
+ for (const item2 of app.db.select({ querySetId: measurementQuerySetItems.querySetId }).from(measurementQuerySetItems).where(inArray19(measurementQuerySetItems.querySetId, sets.map((set) => set.id))).all()) {
20852
20951
  counts2.set(item2.querySetId, (counts2.get(item2.querySetId) ?? 0) + 1);
20853
20952
  }
20854
20953
  }
@@ -21783,10 +21882,10 @@ async function measurementPropertyEvidenceRoutes(app) {
21783
21882
 
21784
21883
  // ../api-routes/src/measurement-portfolio-reads.ts
21785
21884
  import { createHash as createHash5 } from "crypto";
21786
- import { and as and31, desc as desc15, eq as eq39, inArray as inArray20, lt as lt4, or as or7 } from "drizzle-orm";
21885
+ import { and as and31, desc as desc15, eq as eq39, inArray as inArray21, lt as lt4, or as or7 } from "drizzle-orm";
21787
21886
 
21788
21887
  // ../api-routes/src/measurement-question-reads.ts
21789
- import { and as and30, eq as eq38, getTableColumns, inArray as inArray19, sql as sql10 } from "drizzle-orm";
21888
+ import { and as and30, eq as eq38, getTableColumns, inArray as inArray20, sql as sql10 } from "drizzle-orm";
21790
21889
  var DEFAULT_LIMIT2 = 50;
21791
21890
  var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
21792
21891
  RunStatuses.completed,
@@ -21896,7 +21995,7 @@ function selectedQuestionSnapshots(db, runId, manifest, scope) {
21896
21995
  if (scope !== void 0) {
21897
21996
  const executionIds = [...new Set(manifest.expectedSlots.map((slot) => slot.executionId))];
21898
21997
  if (executionIds.length === 0) return [];
21899
- conditions.push(inArray19(querySnapshots.measurementExecutionId, executionIds));
21998
+ conditions.push(inArray20(querySnapshots.measurementExecutionId, executionIds));
21900
21999
  }
21901
22000
  if (scope?.provider !== void 0) {
21902
22001
  conditions.push(sql10`lower(trim(${querySnapshots.provider})) = ${normalizeIdentityText(scope.provider)}`);
@@ -21911,7 +22010,7 @@ function rawResponsesForLegacyQuestionSnapshots(db, runId, snapshots) {
21911
22010
  rawResponse: querySnapshots.rawResponse
21912
22011
  }).from(querySnapshots).where(and30(
21913
22012
  eq38(querySnapshots.runId, runId),
21914
- inArray19(querySnapshots.id, legacyIds)
22013
+ inArray20(querySnapshots.id, legacyIds)
21915
22014
  )).all().map((snapshot) => [snapshot.id, snapshot.rawResponse]));
21916
22015
  }
21917
22016
  function withLegacyRawEvidence(db, runId, snapshots) {
@@ -23077,9 +23176,9 @@ function previousComparableRun(db, active, current) {
23077
23176
  // republish: a run pinned to a comparable prior revision measured exactly
23078
23177
  // the questions the active revision asks. The execution-identity and scope
23079
23178
  // checks below still gate what actually compares.
23080
- inArray20(runs.measurementPlanVersionId, comparableMeasurementVersionIds(db, current.projectId, active.version.id)),
23179
+ inArray21(runs.measurementPlanVersionId, comparableMeasurementVersionIds(db, current.projectId, active.version.id)),
23081
23180
  eq39(runs.kind, RunKinds["answer-visibility"]),
23082
- inArray20(runs.status, [RunStatuses.completed, RunStatuses.partial]),
23181
+ inArray21(runs.status, [RunStatuses.completed, RunStatuses.partial]),
23083
23182
  or7(
23084
23183
  lt4(runs.createdAt, current.createdAt),
23085
23184
  and31(eq39(runs.createdAt, current.createdAt), lt4(runs.id, current.id))
@@ -23490,7 +23589,7 @@ async function measurementPortfolioReadRoutes(app) {
23490
23589
 
23491
23590
  // ../api-routes/src/visibility-report.ts
23492
23591
  import { createHash as createHash7 } from "crypto";
23493
- import { and as and32, desc as desc16, eq as eq40, gte as gte5, inArray as inArray21, isNotNull as isNotNull4, isNull as isNull7, lt as lt5, lte as lte5, or as or8 } from "drizzle-orm";
23592
+ import { and as and32, desc as desc16, eq as eq40, gte as gte5, inArray as inArray22, isNotNull as isNotNull4, isNull as isNull7, lt as lt5, lte as lte5, or as or8 } from "drizzle-orm";
23494
23593
 
23495
23594
  // ../api-routes/src/visibility-report-reader.ts
23496
23595
  import { createHash as createHash6 } from "crypto";
@@ -24275,7 +24374,7 @@ function loadVisibilitySnapshots(db, runIds) {
24275
24374
  requestedContext: querySnapshots.requestedContext,
24276
24375
  supportedContext: querySnapshots.supportedContext,
24277
24376
  createdAt: querySnapshots.createdAt
24278
- }).from(querySnapshots).where(inArray21(querySnapshots.runId, [...runIds])).all();
24377
+ }).from(querySnapshots).where(inArray22(querySnapshots.runId, [...runIds])).all();
24279
24378
  for (const row of rows) {
24280
24379
  const snapshots = byRun.get(row.runId) ?? [];
24281
24380
  snapshots.push(row);
@@ -24696,7 +24795,7 @@ function completedVisibilityRuns(db, projectId, planless, query) {
24696
24795
  return db.select().from(runs).where(and32(
24697
24796
  eq40(runs.projectId, projectId),
24698
24797
  eq40(runs.kind, RunKinds["answer-visibility"]),
24699
- inArray21(runs.status, [RunStatuses.completed, RunStatuses.partial]),
24798
+ inArray22(runs.status, [RunStatuses.completed, RunStatuses.partial]),
24700
24799
  notProbeRun(),
24701
24800
  planless ? isNull7(runs.measurementPlanVersionId) : isNotNull4(runs.measurementPlanVersionId),
24702
24801
  // A scoped spot check is never a whole-project sweep. It can be inspected
@@ -24711,7 +24810,7 @@ function previousEligibleVisibilityRun(db, projectId, planless, selected) {
24711
24810
  return db.select().from(runs).where(and32(
24712
24811
  eq40(runs.projectId, projectId),
24713
24812
  eq40(runs.kind, RunKinds["answer-visibility"]),
24714
- inArray21(runs.status, [RunStatuses.completed, RunStatuses.partial]),
24813
+ inArray22(runs.status, [RunStatuses.completed, RunStatuses.partial]),
24715
24814
  notProbeRun(),
24716
24815
  planless ? isNull7(runs.measurementPlanVersionId) : isNotNull4(runs.measurementPlanVersionId),
24717
24816
  isNull7(runs.measurementScope),
@@ -24850,7 +24949,7 @@ function frozenSimpleDefinitions(db, projectId, runIds) {
24850
24949
  if (runIds.length === 0) return /* @__PURE__ */ new Map();
24851
24950
  return new Map(db.select().from(simpleMeasurementDefinitions).where(and32(
24852
24951
  eq40(simpleMeasurementDefinitions.projectId, projectId),
24853
- inArray21(simpleMeasurementDefinitions.runId, [...runIds])
24952
+ inArray22(simpleMeasurementDefinitions.runId, [...runIds])
24854
24953
  )).all().map((row) => [row.runId, row.definition]));
24855
24954
  }
24856
24955
  function simpleRunInput(db, project, run, definition2, includeEvidence) {
@@ -24919,7 +25018,7 @@ function readVisibilityComparisonRuns(db, projectId, since, until, includeEviden
24919
25018
  const sourceRuns = db.select().from(runs).where(and32(
24920
25019
  eq40(runs.projectId, projectId),
24921
25020
  eq40(runs.kind, RunKinds["answer-visibility"]),
24922
- inArray21(runs.status, [RunStatuses.completed, RunStatuses.partial]),
25021
+ inArray22(runs.status, [RunStatuses.completed, RunStatuses.partial]),
24923
25022
  notProbeRun(),
24924
25023
  isNotNull4(runs.measurementPlanVersionId),
24925
25024
  isNull7(runs.measurementScope),
@@ -24949,7 +25048,7 @@ function readVisibilityComparisonRuns(db, projectId, since, until, includeEviden
24949
25048
 
24950
25049
  // ../api-routes/src/query-tracking.ts
24951
25050
  import crypto24 from "crypto";
24952
- import { and as and33, desc as desc17, eq as eq41, inArray as inArray22, isNotNull as isNotNull5, isNull as isNull8, ne as ne8 } from "drizzle-orm";
25051
+ import { and as and33, desc as desc17, eq as eq41, inArray as inArray23, isNotNull as isNotNull5, isNull as isNull8, ne as ne8 } from "drizzle-orm";
24953
25052
 
24954
25053
  // ../api-routes/src/embed-queries.ts
24955
25054
  function embedQueryWriteLimit(request) {
@@ -25156,7 +25255,7 @@ function simpleMeasuredAtByQuery(db, project, queryRows2, opts) {
25156
25255
  }).from(runs).where(and33(
25157
25256
  eq41(runs.projectId, project.id),
25158
25257
  eq41(runs.kind, RunKinds["answer-visibility"]),
25159
- inArray22(runs.status, [RunStatuses.completed, RunStatuses.partial]),
25258
+ inArray23(runs.status, [RunStatuses.completed, RunStatuses.partial]),
25160
25259
  ne8(runs.trigger, RunTriggers.probe),
25161
25260
  isNull8(runs.measurementScope),
25162
25261
  isNull8(runs.measurementPlanVersionId)
@@ -25168,7 +25267,7 @@ function simpleMeasuredAtByQuery(db, project, queryRows2, opts) {
25168
25267
  definition: simpleMeasurementDefinitions.definition
25169
25268
  }).from(simpleMeasurementDefinitions).where(and33(
25170
25269
  eq41(simpleMeasurementDefinitions.projectId, project.id),
25171
- inArray22(simpleMeasurementDefinitions.runId, eligibleRuns.map((run) => run.id))
25270
+ inArray23(simpleMeasurementDefinitions.runId, eligibleRuns.map((run) => run.id))
25172
25271
  )).all()) {
25173
25272
  const parsed = simpleMeasurementDefinitionSchema.safeParse(row.definition);
25174
25273
  if (parsed.success) frozenByRun.set(row.runId, parsed.data);
@@ -25180,7 +25279,7 @@ function simpleMeasuredAtByQuery(db, project, queryRows2, opts) {
25180
25279
  queryId: querySnapshots.queryId,
25181
25280
  queryText: querySnapshots.queryText,
25182
25281
  provider: querySnapshots.provider
25183
- }).from(querySnapshots).where(inArray22(querySnapshots.runId, [...frozenByRun.keys()])).all()) {
25282
+ }).from(querySnapshots).where(inArray23(querySnapshots.runId, [...frozenByRun.keys()])).all()) {
25184
25283
  if (!snapshot.queryId) continue;
25185
25284
  const byQuery = snapshotsByRunQuery.get(snapshot.runId) ?? /* @__PURE__ */ new Map();
25186
25285
  const rows = byQuery.get(snapshot.queryId) ?? [];
@@ -25278,7 +25377,7 @@ function measuredAtByQuery(db, state, opts) {
25278
25377
  const eligibleRuns = db.select().from(runs).where(and33(
25279
25378
  eq41(runs.projectId, project.id),
25280
25379
  eq41(runs.kind, RunKinds["answer-visibility"]),
25281
- inArray22(runs.status, [RunStatuses.completed, RunStatuses.partial]),
25380
+ inArray23(runs.status, [RunStatuses.completed, RunStatuses.partial]),
25282
25381
  ne8(runs.trigger, RunTriggers.probe),
25283
25382
  isNull8(runs.measurementScope),
25284
25383
  isNotNull5(runs.measurementPlanVersionId)
@@ -25291,7 +25390,7 @@ function measuredAtByQuery(db, state, opts) {
25291
25390
  canonicalJson: measurementPlanVersions.canonicalJson
25292
25391
  }).from(measurementPlanVersions).where(and33(
25293
25392
  eq41(measurementPlanVersions.projectId, project.id),
25294
- inArray22(measurementPlanVersions.id, versionIds)
25393
+ inArray23(measurementPlanVersions.id, versionIds)
25295
25394
  )).all().flatMap((row) => {
25296
25395
  const parsed = parseStoredMeasurementPlanAnyVersion(row.canonicalJson);
25297
25396
  return parsed.schemaVersion === 2 ? [[row.id, { revision: row.revision, plan: parsed }]] : [];
@@ -25323,7 +25422,7 @@ function measuredAtByQuery(db, state, opts) {
25323
25422
  measurementExecutionId: querySnapshots.measurementExecutionId,
25324
25423
  requestedContext: querySnapshots.requestedContext,
25325
25424
  supportedContext: querySnapshots.supportedContext
25326
- }).from(querySnapshots).where(inArray22(querySnapshots.runId, eligibleRuns.map((run) => run.id))).all();
25425
+ }).from(querySnapshots).where(inArray23(querySnapshots.runId, eligibleRuns.map((run) => run.id))).all();
25327
25426
  for (const snapshot of snapshotRows) {
25328
25427
  const snapshots = snapshotsByRun.get(snapshot.runId) ?? [];
25329
25428
  snapshots.push(snapshot);
@@ -26332,7 +26431,7 @@ function writeAdvancedCandidate(tx, candidate, request, now) {
26332
26431
  const removed = current.filter((row) => !candidate.queryRows.has(row.id));
26333
26432
  if (removed.length > 0) {
26334
26433
  preserveSnapshotQueryText(tx, candidate.state.project.id, removed.map((row) => row.id));
26335
- tx.delete(queries).where(inArray22(queries.id, removed.map((row) => row.id))).run();
26434
+ tx.delete(queries).where(inArray23(queries.id, removed.map((row) => row.id))).run();
26336
26435
  }
26337
26436
  for (const row of candidate.queryRows.values()) {
26338
26437
  const previous = currentById.get(row.id);
@@ -27379,7 +27478,7 @@ async function applyRoutes(app, opts) {
27379
27478
  }
27380
27479
 
27381
27480
  // ../api-routes/src/history.ts
27382
- import { and as and36, asc as asc9, count as count2, getTableColumns as getTableColumns2, desc as desc18, eq as eq45, gte as gte6, inArray as inArray23, like as like3, lte as lte6, ne as ne9, notInArray as notInArray2, or as or9, sql as sql11 } from "drizzle-orm";
27481
+ import { and as and36, asc as asc9, count as count2, getTableColumns as getTableColumns2, desc as desc18, eq as eq45, gte as gte6, inArray as inArray24, like as like3, lte as lte6, ne as ne9, notInArray as notInArray2, or as or9, sql as sql11 } from "drizzle-orm";
27383
27482
  async function historyRoutes(app) {
27384
27483
  app.post("/projects/:name/results/clear", async (request) => {
27385
27484
  requireAdminSession(request);
@@ -27389,27 +27488,27 @@ async function historyRoutes(app) {
27389
27488
  if (!parsed.success) throw validationError("Invalid history cleanup request", { issues: parsed.error.issues });
27390
27489
  const input = parsed.data;
27391
27490
  return app.db.transaction((tx) => {
27392
- const active = tx.select({ id: runs.id }).from(runs).where(and36(eq45(runs.projectId, project.id), eq45(runs.kind, RunKinds["answer-visibility"]), inArray23(runs.status, ["queued", "running"]))).get();
27393
- const activeResearch = tx.select({ id: researchRuns.id }).from(researchRuns).where(and36(eq45(researchRuns.projectId, project.id), inArray23(researchRuns.status, ["queued", "running"]))).get();
27491
+ const active = tx.select({ id: runs.id }).from(runs).where(and36(eq45(runs.projectId, project.id), eq45(runs.kind, RunKinds["answer-visibility"]), inArray24(runs.status, ["queued", "running"]))).get();
27492
+ const activeResearch = tx.select({ id: researchRuns.id }).from(researchRuns).where(and36(eq45(researchRuns.projectId, project.id), inArray24(researchRuns.status, ["queued", "running"]))).get();
27394
27493
  if (active || activeResearch) throw runInProgress(project.name, active ? "answer-visibility" : "research", (active ?? activeResearch).id);
27395
- const activeFill = tx.select({ id: runFills.id, runId: runFills.runId }).from(runFills).where(and36(eq45(runFills.projectId, project.id), inArray23(runFills.status, ["queued", "running"]))).get();
27494
+ const activeFill = tx.select({ id: runFills.id, runId: runFills.runId }).from(runFills).where(and36(eq45(runFills.projectId, project.id), inArray24(runFills.status, ["queued", "running"]))).get();
27396
27495
  if (activeFill) throw runFillInProgress(activeFill.runId, activeFill.id);
27397
- const selectedRuns = tx.select({ id: runs.id, kind: runs.kind }).from(runs).where(and36(eq45(runs.projectId, project.id), inArray23(runs.id, input.runIds))).all();
27398
- const selectedResearch = tx.select({ id: researchRuns.id }).from(researchRuns).where(and36(eq45(researchRuns.projectId, project.id), inArray23(researchRuns.id, input.researchRunIds))).all();
27496
+ const selectedRuns = tx.select({ id: runs.id, kind: runs.kind }).from(runs).where(and36(eq45(runs.projectId, project.id), inArray24(runs.id, input.runIds))).all();
27497
+ const selectedResearch = tx.select({ id: researchRuns.id }).from(researchRuns).where(and36(eq45(researchRuns.projectId, project.id), inArray24(researchRuns.id, input.researchRunIds))).all();
27399
27498
  if (selectedRuns.length !== input.runIds.length || selectedResearch.length !== input.researchRunIds.length) throw notFound("Selected saved run in project", project.name);
27400
27499
  if (selectedRuns.some((run) => run.kind !== RunKinds["answer-visibility"])) throw validationError("Only answer-visibility runs and research batches can be cleared. Site Health and integration runs are preserved.");
27401
27500
  const result = {
27402
27501
  dryRun: !input.confirm,
27403
27502
  runIds: input.runIds,
27404
27503
  researchRunIds: input.researchRunIds,
27405
- querySnapshots: tx.select({ value: count2() }).from(querySnapshots).where(inArray23(querySnapshots.runId, input.runIds)).get().value,
27406
- researchQueries: tx.select({ value: count2() }).from(researchRunQueries).where(inArray23(researchRunQueries.researchRunId, input.researchRunIds)).get().value,
27407
- insights: tx.select({ value: count2() }).from(insights).where(inArray23(insights.runId, input.runIds)).get().value,
27408
- healthSnapshots: tx.select({ value: count2() }).from(healthSnapshots).where(inArray23(healthSnapshots.runId, input.runIds)).get().value
27504
+ querySnapshots: tx.select({ value: count2() }).from(querySnapshots).where(inArray24(querySnapshots.runId, input.runIds)).get().value,
27505
+ researchQueries: tx.select({ value: count2() }).from(researchRunQueries).where(inArray24(researchRunQueries.researchRunId, input.researchRunIds)).get().value,
27506
+ insights: tx.select({ value: count2() }).from(insights).where(inArray24(insights.runId, input.runIds)).get().value,
27507
+ healthSnapshots: tx.select({ value: count2() }).from(healthSnapshots).where(inArray24(healthSnapshots.runId, input.runIds)).get().value
27409
27508
  };
27410
27509
  if (input.confirm) {
27411
- tx.delete(researchRuns).where(and36(eq45(researchRuns.projectId, project.id), inArray23(researchRuns.id, input.researchRunIds))).run();
27412
- tx.delete(runs).where(and36(eq45(runs.projectId, project.id), inArray23(runs.id, input.runIds))).run();
27510
+ tx.delete(researchRuns).where(and36(eq45(researchRuns.projectId, project.id), inArray24(researchRuns.id, input.researchRunIds))).run();
27511
+ tx.delete(runs).where(and36(eq45(runs.projectId, project.id), inArray24(runs.id, input.runIds))).run();
27413
27512
  writeAuditLog(tx, { projectId: project.id, actor: "api", action: "results.cleared", entityType: "project", entityId: project.id, diff: result });
27414
27513
  }
27415
27514
  return result;
@@ -27462,7 +27561,7 @@ async function historyRoutes(app) {
27462
27561
  location: querySnapshots.location,
27463
27562
  rawResponse: querySnapshots.rawResponse,
27464
27563
  createdAt: querySnapshots.createdAt
27465
- }).from(querySnapshots).leftJoin(queries, eq45(querySnapshots.queryId, queries.id)).where(inArray23(querySnapshots.runId, projectRuns.map((r) => r.id))).orderBy(desc18(querySnapshots.createdAt)).all();
27564
+ }).from(querySnapshots).leftJoin(queries, eq45(querySnapshots.queryId, queries.id)).where(inArray24(querySnapshots.runId, projectRuns.map((r) => r.id))).orderBy(desc18(querySnapshots.createdAt)).all();
27466
27565
  const locationFilter = request.query.location;
27467
27566
  const filtered = locationFilter !== void 0 ? allSnapshots.filter((s) => s.location === (locationFilter || null)) : allSnapshots;
27468
27567
  const total = filtered.length;
@@ -27523,7 +27622,7 @@ async function historyRoutes(app) {
27523
27622
  return reply.send([]);
27524
27623
  }
27525
27624
  const runIds = new Set(projectRuns.map((r) => r.id));
27526
- const rawSnapshots = app.db.select().from(querySnapshots).where(inArray23(querySnapshots.runId, [...runIds])).all();
27625
+ const rawSnapshots = app.db.select().from(querySnapshots).where(inArray24(querySnapshots.runId, [...runIds])).all();
27527
27626
  const timelineLocationFilter = request.query.location;
27528
27627
  const filteredSnapshots = timelineLocationFilter !== void 0 ? rawSnapshots.filter((s) => s.location === (timelineLocationFilter || null)) : rawSnapshots;
27529
27628
  const allSnapshots = filteredSnapshots.map((snapshot) => ({
@@ -27644,7 +27743,7 @@ async function historyRoutes(app) {
27644
27743
  throw validationError("Both run1 and run2 query params are required");
27645
27744
  }
27646
27745
  const requestedRunIds = [.../* @__PURE__ */ new Set([run1, run2])];
27647
- const runRows = app.db.select({ id: runs.id, projectId: runs.projectId }).from(runs).where(inArray23(runs.id, requestedRunIds)).all();
27746
+ const runRows = app.db.select({ id: runs.id, projectId: runs.projectId }).from(runs).where(inArray24(runs.id, requestedRunIds)).all();
27648
27747
  const runsById = new Map(runRows.map((row) => [row.id, row]));
27649
27748
  for (const runId of requestedRunIds) {
27650
27749
  const run = runsById.get(runId);
@@ -27761,7 +27860,7 @@ function parseOptionalPositiveInt(value, max2) {
27761
27860
  }
27762
27861
 
27763
27862
  // ../api-routes/src/analytics.ts
27764
- import { and as and37, desc as desc19, eq as eq46, gte as gte7, inArray as inArray24, lt as lt6 } from "drizzle-orm";
27863
+ import { and as and37, desc as desc19, eq as eq46, gte as gte7, inArray as inArray25, lt as lt6 } from "drizzle-orm";
27765
27864
 
27766
27865
  // ../api-routes/src/analytics-model-attribution.ts
27767
27866
  function logicalSweeps(observations) {
@@ -27873,7 +27972,7 @@ async function analyticsRoutes(app) {
27873
27972
  const projectRuns = app.db.select().from(runs).where(and37(
27874
27973
  eq46(runs.projectId, project.id),
27875
27974
  eq46(runs.kind, RunKinds["answer-visibility"]),
27876
- inArray24(runs.status, [RunStatuses.completed, RunStatuses.partial]),
27975
+ inArray25(runs.status, [RunStatuses.completed, RunStatuses.partial]),
27877
27976
  notProbeRun(),
27878
27977
  cutoff ? gte7(runs.createdAt, cutoff) : void 0
27879
27978
  )).orderBy(desc19(runs.createdAt)).all().filter((r) => measuredWhole(app.db, r)).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
@@ -27922,7 +28021,7 @@ async function analyticsRoutes(app) {
27922
28021
  answerMentioned: querySnapshots.answerMentioned,
27923
28022
  mentionIdentity: querySnapshots.mentionIdentity,
27924
28023
  answerText: querySnapshots.answerText
27925
- }).from(querySnapshots).where(inArray24(querySnapshots.runId, runIds)).all();
28024
+ }).from(querySnapshots).where(inArray25(querySnapshots.runId, runIds)).all();
27926
28025
  const rawSnapshots = referenceBasket ? loadedSnapshots.filter(
27927
28026
  (s) => s.queryId !== null || s.queryText !== null && referenceBasket.has(normalizeQueryText(s.queryText))
27928
28027
  ) : filterTrackedSnapshots(loadedSnapshots);
@@ -27972,7 +28071,7 @@ async function analyticsRoutes(app) {
27972
28071
  const anchorRunPredicate = and37(
27973
28072
  eq46(runs.projectId, project.id),
27974
28073
  eq46(runs.kind, RunKinds["answer-visibility"]),
27975
- inArray24(runs.status, [RunStatuses.completed, RunStatuses.partial]),
28074
+ inArray25(runs.status, [RunStatuses.completed, RunStatuses.partial]),
27976
28075
  notProbeRun(),
27977
28076
  lt6(runs.createdAt, cutoff)
27978
28077
  );
@@ -28002,7 +28101,7 @@ async function analyticsRoutes(app) {
28002
28101
  provider: querySnapshots.provider,
28003
28102
  model: querySnapshots.model,
28004
28103
  servedModel: querySnapshots.servedModel
28005
- }).from(querySnapshots).where(inArray24(querySnapshots.runId, runIds2)).all())) {
28104
+ }).from(querySnapshots).where(inArray25(querySnapshots.runId, runIds2)).all())) {
28006
28105
  if (pending.has(snapshot.provider)) {
28007
28106
  const models = modelsByProvider.get(snapshot.provider) ?? [];
28008
28107
  models.push(snapshot.model);
@@ -28155,7 +28254,7 @@ async function analyticsRoutes(app) {
28155
28254
  answerMentioned: querySnapshots.answerMentioned,
28156
28255
  mentionIdentity: querySnapshots.mentionIdentity,
28157
28256
  answerText: querySnapshots.answerText
28158
- }).from(querySnapshots).where(inArray24(querySnapshots.runId, windowRunIds)).all());
28257
+ }).from(querySnapshots).where(inArray25(querySnapshots.runId, windowRunIds)).all());
28159
28258
  for (const s of allWindowSnaps) {
28160
28259
  const timePoint = runIdToCreatedAt.get(s.runId) ?? s.runId;
28161
28260
  let entry = consistencyMap.get(s.queryId);
@@ -28177,7 +28276,7 @@ async function analyticsRoutes(app) {
28177
28276
  mentionIdentity: querySnapshots.mentionIdentity,
28178
28277
  answerText: querySnapshots.answerText,
28179
28278
  citedDomains: querySnapshots.citedDomains
28180
- }).from(querySnapshots).leftJoin(queries, eq46(querySnapshots.queryId, queries.id)).where(inArray24(querySnapshots.runId, latestGroupRunIds)).all());
28279
+ }).from(querySnapshots).leftJoin(queries, eq46(querySnapshots.queryId, queries.id)).where(inArray25(querySnapshots.runId, latestGroupRunIds)).all());
28181
28280
  const snapshots = rawSnapshots.map((s) => ({
28182
28281
  ...s,
28183
28282
  resolvedMentioned: resolveSnapshotAnswerMentioned(s, project)
@@ -28344,7 +28443,7 @@ async function analyticsRoutes(app) {
28344
28443
  eq46(runs.projectId, project.id),
28345
28444
  eq46(runs.kind, RunKinds["answer-visibility"]),
28346
28445
  notProbeRun(),
28347
- latestRuns ? inArray24(runs.id, latestRuns.map((run) => run.id)) : requestedRunId ? eq46(runs.id, requestedRunId) : void 0
28446
+ latestRuns ? inArray25(runs.id, latestRuns.map((run) => run.id)) : requestedRunId ? eq46(runs.id, requestedRunId) : void 0
28348
28447
  )).orderBy(desc19(runs.createdAt), desc19(runs.id)).all().filter((r) => r.status === "completed" || r.status === "partial").filter((r) => measuredWhole(app.db, r)).filter((r) => !cutoff || r.createdAt >= cutoff);
28349
28448
  if (windowRuns.length === 0) {
28350
28449
  return reply.send({
@@ -28377,7 +28476,7 @@ async function analyticsRoutes(app) {
28377
28476
  citedDomains: querySnapshots.citedDomains,
28378
28477
  citedUrls: querySnapshots.citedUrls,
28379
28478
  measurementExecutionId: querySnapshots.measurementExecutionId
28380
- }).from(querySnapshots).leftJoin(queries, eq46(querySnapshots.queryId, queries.id)).where(inArray24(querySnapshots.runId, windowRunIds)).all();
28479
+ }).from(querySnapshots).leftJoin(queries, eq46(querySnapshots.queryId, queries.id)).where(inArray25(querySnapshots.runId, windowRunIds)).all();
28381
28480
  let unclassifiedAnswers = 0;
28382
28481
  let snapshots = loadedSnapshots;
28383
28482
  if (splitByClass) {
@@ -28730,7 +28829,7 @@ function buildCategoryCounts(counts2) {
28730
28829
  }
28731
28830
 
28732
28831
  // ../api-routes/src/intelligence.ts
28733
- import { eq as eq47, desc as desc20, and as and38, inArray as inArray25, like as like4 } from "drizzle-orm";
28832
+ import { eq as eq47, desc as desc20, and as and38, inArray as inArray26, like as like4 } from "drizzle-orm";
28734
28833
  var SEVERITY_RANK = { low: 0, medium: 1, high: 2, critical: 3 };
28735
28834
  function severitiesAtOrAbove(min2) {
28736
28835
  const floor = SEVERITY_RANK[min2];
@@ -28866,7 +28965,7 @@ async function intelligenceRoutes(app) {
28866
28965
  }
28867
28966
  const severityFilter = request.query.severity?.trim();
28868
28967
  if (severityFilter) {
28869
- conditions.push(inArray25(insights.severity, severitiesAtOrAbove(severityFilter)));
28968
+ conditions.push(inArray26(insights.severity, severitiesAtOrAbove(severityFilter)));
28870
28969
  }
28871
28970
  let limit;
28872
28971
  if (request.query.limit !== void 0) {
@@ -28904,7 +29003,7 @@ async function intelligenceRoutes(app) {
28904
29003
  const projectVisRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(and38(
28905
29004
  eq47(runs.projectId, project.id),
28906
29005
  eq47(runs.kind, RunKinds["answer-visibility"]),
28907
- inArray25(runs.status, [RunStatuses.completed, RunStatuses.partial]),
29006
+ inArray26(runs.status, [RunStatuses.completed, RunStatuses.partial]),
28908
29007
  // Health-latest is the dashboard headline; probe runs must not
28909
29008
  // displace the most recent real visibility sweep.
28910
29009
  notProbeRun()
@@ -28914,7 +29013,7 @@ async function intelligenceRoutes(app) {
28914
29013
  if (latestGroupRunIds.length > 0) {
28915
29014
  const groupRows = app.db.select().from(healthSnapshots).where(and38(
28916
29015
  eq47(healthSnapshots.projectId, project.id),
28917
- inArray25(healthSnapshots.runId, latestGroupRunIds)
29016
+ inArray26(healthSnapshots.runId, latestGroupRunIds)
28918
29017
  )).all();
28919
29018
  if (groupRows.length > 0) {
28920
29019
  return reply.send(aggregateHealthSnapshots(project.id, groupRows));
@@ -29300,7 +29399,7 @@ async function trafficAnalyticsRoutes(app) {
29300
29399
  }
29301
29400
 
29302
29401
  // ../api-routes/src/traffic-samples.ts
29303
- import { and as and41, count as count3, desc as desc22, eq as eq49, gte as gte9, inArray as inArray26, lte as lte8, sql as sql14 } from "drizzle-orm";
29402
+ import { and as and41, count as count3, desc as desc22, eq as eq49, gte as gte9, inArray as inArray27, lte as lte8, sql as sql14 } from "drizzle-orm";
29304
29403
  var storedKind = {
29305
29404
  [TrafficSampleKinds.crawler]: "crawler",
29306
29405
  [TrafficSampleKinds["ai-user-fetch"]]: "ai_user_fetch",
@@ -29323,7 +29422,7 @@ async function trafficSamplesRoutes(app) {
29323
29422
  const limit = query.limit ?? 100;
29324
29423
  const offset = query.offset ?? 0;
29325
29424
  const filters = [eq49(rawEventSamples.projectId, project.id), gte9(rawEventSamples.ts, windowStart), lte8(rawEventSamples.ts, windowEnd)];
29326
- filters.push(query.kind && query.kind !== "all" ? eq49(rawEventSamples.eventType, storedKind[query.kind]) : inArray26(rawEventSamples.eventType, [storedKind[TrafficSampleKinds.crawler], storedKind[TrafficSampleKinds["ai-user-fetch"]], storedKind[TrafficSampleKinds["ai-referral"]]]));
29425
+ filters.push(query.kind && query.kind !== "all" ? eq49(rawEventSamples.eventType, storedKind[query.kind]) : inArray27(rawEventSamples.eventType, [storedKind[TrafficSampleKinds.crawler], storedKind[TrafficSampleKinds["ai-user-fetch"]], storedKind[TrafficSampleKinds["ai-referral"]]]));
29327
29426
  if (query.sourceId) filters.push(eq49(rawEventSamples.sourceId, query.sourceId));
29328
29427
  if (query.path !== void 0) filters.push(sql14`${rawEventSamples.pathNormalized} LIKE ${escapeLikePattern(query.path) + "%"} ESCAPE '\\'`);
29329
29428
  const where = and41(...filters);
@@ -29346,7 +29445,7 @@ async function trafficSamplesRoutes(app) {
29346
29445
 
29347
29446
  // ../api-routes/src/journeys.ts
29348
29447
  import crypto28 from "crypto";
29349
- import { and as and42, asc as asc10, count as count4, desc as desc23, eq as eq50, gt as gt4, gte as gte10, inArray as inArray27, lt as lt8, lte as lte9, sql as sql15 } from "drizzle-orm";
29448
+ import { and as and42, asc as asc10, count as count4, desc as desc23, eq as eq50, gt as gt4, gte as gte10, inArray as inArray28, lt as lt8, lte as lte9, sql as sql15 } from "drizzle-orm";
29350
29449
  import "zod";
29351
29450
 
29352
29451
  // ../api-routes/src/cloudflare-worker-version.ts
@@ -29380,7 +29479,7 @@ function persistJourneyBatch(tx, input) {
29380
29479
  if (extracted.length === 0) return { visitsWritten: 0, eventsStored: 0 };
29381
29480
  const stored = /* @__PURE__ */ new Set();
29382
29481
  for (const ids of chunks([...new Set(extracted.map((r) => r.eventId))])) {
29383
- const rows = tx.select({ id: journeyEvents.sourceEventId }).from(journeyEvents).where(and42(eq50(journeyEvents.projectId, input.projectId), eq50(journeyEvents.sourceId, input.sourceId), inArray27(journeyEvents.sourceEventId, ids))).all();
29482
+ const rows = tx.select({ id: journeyEvents.sourceEventId }).from(journeyEvents).where(and42(eq50(journeyEvents.projectId, input.projectId), eq50(journeyEvents.sourceId, input.sourceId), inArray28(journeyEvents.sourceEventId, ids))).all();
29384
29483
  for (const row of rows) stored.add(row.id);
29385
29484
  }
29386
29485
  const basisByKey = /* @__PURE__ */ new Map();
@@ -29418,13 +29517,13 @@ function persistJourneyBatch(tx, input) {
29418
29517
  };
29419
29518
  const storedCappedDays = /* @__PURE__ */ new Map();
29420
29519
  for (const keys of chunks([...basisByKey.keys()])) {
29421
- for (const row of tx.select().from(journeyVisitors).where(and42(eq50(journeyVisitors.projectId, input.projectId), inArray27(journeyVisitors.visitorKey, keys))).all()) {
29520
+ for (const row of tx.select().from(journeyVisitors).where(and42(eq50(journeyVisitors.projectId, input.projectId), inArray28(journeyVisitors.visitorKey, keys))).all()) {
29422
29521
  Object.assign(stateFor(row.visitorKey), { firstAiAt: row.firstAiAt, firstAiEngine: row.firstAiEngine, lastAiAt: row.lastAiAt });
29423
29522
  storedCappedDays.set(row.visitorKey, row.cappedDays);
29424
29523
  }
29425
29524
  for (const row of tx.select({ visitorKey: journeyVisits.visitorKey, ts: journeyEvents.ts }).from(journeyEvents).innerJoin(journeyVisits, eq50(journeyVisits.id, journeyEvents.visitId)).where(and42(
29426
29525
  eq50(journeyVisits.projectId, input.projectId),
29427
- inArray27(journeyVisits.visitorKey, keys),
29526
+ inArray28(journeyVisits.visitorKey, keys),
29428
29527
  eq50(journeyEvents.aiTouch, true),
29429
29528
  gte10(journeyEvents.ts, lookbackStart),
29430
29529
  lte9(journeyEvents.ts, latestIso)
@@ -29434,7 +29533,7 @@ function persistJourneyBatch(tx, input) {
29434
29533
  const day = sql15`substr(${journeyEvents.ts}, 1, 10)`;
29435
29534
  for (const row of tx.select({ visitorKey: journeyVisits.visitorKey, day, total: count4() }).from(journeyEvents).innerJoin(journeyVisits, eq50(journeyVisits.id, journeyEvents.visitId)).where(and42(
29436
29535
  eq50(journeyVisits.projectId, input.projectId),
29437
- inArray27(journeyVisits.visitorKey, keys),
29536
+ inArray28(journeyVisits.visitorKey, keys),
29438
29537
  gte10(journeyEvents.ts, `${firstDay}T00:00:00.000Z`),
29439
29538
  lt8(journeyEvents.ts, dayAfterLast)
29440
29539
  )).groupBy(journeyVisits.visitorKey, day).all()) {
@@ -29442,7 +29541,7 @@ function persistJourneyBatch(tx, input) {
29442
29541
  }
29443
29542
  for (const row of tx.select().from(journeyVisits).where(and42(
29444
29543
  eq50(journeyVisits.projectId, input.projectId),
29445
- inArray27(journeyVisits.visitorKey, keys),
29544
+ inArray28(journeyVisits.visitorKey, keys),
29446
29545
  lte9(journeyVisits.startedAt, windowEnd),
29447
29546
  gte10(journeyVisits.endedAt, windowStart)
29448
29547
  )).all()) {
@@ -29561,7 +29660,7 @@ function recomputeVisitTotals(tx, visitIds) {
29561
29660
  endedAt: sql15`coalesce(${of(sql15`max(${journeyEvents.ts})`)}, ${journeyVisits.endedAt})`,
29562
29661
  requestCount: of(sql15`count(*)`),
29563
29662
  pageCount: of(sql15`count(*) FILTER (WHERE ${journeyEvents.kind} = 'page')`)
29564
- }).where(inArray27(journeyVisits.id, [...visitIds])).run();
29663
+ }).where(inArray28(journeyVisits.id, [...visitIds])).run();
29565
29664
  }
29566
29665
  function recordJourneyBatch(tx, input, handlers) {
29567
29666
  if (!input.secret || input.events.length === 0) return { visitsWritten: 0, eventsStored: 0 };
@@ -29636,7 +29735,7 @@ function visitorDto(visitor, visits) {
29636
29735
  function visitsByVisitor(db, projectId, keys) {
29637
29736
  const out = /* @__PURE__ */ new Map();
29638
29737
  for (const part of chunks(keys)) {
29639
- for (const row of db.select().from(journeyVisits).where(and42(eq50(journeyVisits.projectId, projectId), inArray27(journeyVisits.visitorKey, part))).orderBy(asc10(journeyVisits.startedAt)).all()) {
29738
+ for (const row of db.select().from(journeyVisits).where(and42(eq50(journeyVisits.projectId, projectId), inArray28(journeyVisits.visitorKey, part))).orderBy(asc10(journeyVisits.startedAt)).all()) {
29640
29739
  const list = out.get(row.visitorKey);
29641
29740
  if (list) list.push(row);
29642
29741
  else out.set(row.visitorKey, [row]);
@@ -29652,7 +29751,7 @@ function partialSources(db, projectId) {
29652
29751
  status: trafficSources.status,
29653
29752
  configJson: trafficSources.configJson,
29654
29753
  lastWorkerVersion: trafficSources.lastWorkerVersion
29655
- }).from(trafficSources).where(and42(eq50(trafficSources.projectId, projectId), inArray27(trafficSources.sourceType, types))).orderBy(asc10(trafficSources.id)).all();
29754
+ }).from(trafficSources).where(and42(eq50(trafficSources.projectId, projectId), inArray28(trafficSources.sourceType, types))).orderBy(asc10(trafficSources.id)).all();
29656
29755
  const out = [];
29657
29756
  for (const row of rows) {
29658
29757
  if (row.status === TrafficSourceStatuses.archived) continue;
@@ -29762,7 +29861,7 @@ async function journeyRoutes(app) {
29762
29861
  const page3 = visits.slice(offset, offset + limit);
29763
29862
  const events = /* @__PURE__ */ new Map();
29764
29863
  for (const part of chunks(page3.map((v) => v.id))) {
29765
- for (const row of app.db.select().from(journeyEvents).where(inArray27(journeyEvents.visitId, part)).orderBy(asc10(journeyEvents.ts)).all()) {
29864
+ for (const row of app.db.select().from(journeyEvents).where(inArray28(journeyEvents.visitId, part)).orderBy(asc10(journeyEvents.ts)).all()) {
29766
29865
  const list = events.get(row.visitId);
29767
29866
  if (list) list.push(row);
29768
29867
  else events.set(row.visitId, [row]);
@@ -30165,7 +30264,7 @@ function literalPathPrefixCondition(path8, prefix) {
30165
30264
  }
30166
30265
 
30167
30266
  // ../api-routes/src/ga-measurement-analysis.ts
30168
- import { and as and44, eq as eq52, gte as gte12, inArray as inArray28, lte as lte11, or as or11, sql as sql18 } from "drizzle-orm";
30267
+ import { and as and44, eq as eq52, gte as gte12, inArray as inArray29, lte as lte11, or as or11, sql as sql18 } from "drizzle-orm";
30169
30268
  var UNKNOWN_LANDING_PAGE = "(not set)";
30170
30269
  function addDays(date, offset) {
30171
30270
  const value = /* @__PURE__ */ new Date(`${date}T00:00:00.000Z`);
@@ -30473,7 +30572,7 @@ function buildGaMeasurementAnalysis(db, projectName, options = {}) {
30473
30572
  const countedEventNames = countedLeadEventNames(configuredLeadEvents, keyEventNames ?? []);
30474
30573
  const measuredEventSet = new Set(state?.leadEventNames ?? configuredLeadEvents);
30475
30574
  const reportedEventNames = countedEventNames.filter((name) => measuredEventSet.has(name));
30476
- const leadEventCondition = reportedEventNames.length > 0 ? inArray28(gaLeadEventsDaily.eventName, reportedEventNames) : null;
30575
+ const leadEventCondition = reportedEventNames.length > 0 ? inArray29(gaLeadEventsDaily.eventName, reportedEventNames) : null;
30477
30576
  const acquisitionAnchor = db.select({ date: sql18`max(${gaAcquisitionDaily.date})` }).from(gaAcquisitionDaily).where(and44(eq52(gaAcquisitionDaily.projectId, project.id), ...acquisitionScope)).get()?.date ?? null;
30478
30577
  const leadAnchor = leadEventCondition === null ? null : db.select({ date: sql18`max(${gaLeadEventsDaily.date})` }).from(gaLeadEventsDaily).where(and44(eq52(gaLeadEventsDaily.projectId, project.id), leadEventCondition, or11(
30479
30578
  eq52(gaLeadEventsDaily.attributionScope, "channel"),
@@ -31297,7 +31396,7 @@ async function organicEvidenceRoutes(app) {
31297
31396
  }
31298
31397
 
31299
31398
  // ../api-routes/src/citations.ts
31300
- import { and as and46, eq as eq54, inArray as inArray29 } from "drizzle-orm";
31399
+ import { and as and46, eq as eq54, inArray as inArray30 } from "drizzle-orm";
31301
31400
  async function citationRoutes(app) {
31302
31401
  app.get("/projects/:name/citations/visibility", async (request, reply) => {
31303
31402
  const project = resolveProject(app.db, request.params.name);
@@ -31321,7 +31420,7 @@ async function citationRoutes(app) {
31321
31420
  competitorOverlap: querySnapshots.competitorOverlap,
31322
31421
  answerMentioned: querySnapshots.answerMentioned,
31323
31422
  createdAt: querySnapshots.createdAt
31324
- }).from(querySnapshots).where(inArray29(querySnapshots.runId, projectRuns.map((r) => r.id))).all();
31423
+ }).from(querySnapshots).where(inArray30(querySnapshots.runId, projectRuns.map((r) => r.id))).all();
31325
31424
  if (rawSnapshots.length === 0) {
31326
31425
  return reply.send(emptyCitationVisibility("no-runs-yet"));
31327
31426
  }
@@ -31458,7 +31557,7 @@ function computeCitationVisibility(input) {
31458
31557
  }
31459
31558
 
31460
31559
  // ../api-routes/src/visibility-stats.ts
31461
- import { and as and47, desc as desc26, eq as eq55, inArray as inArray30 } from "drizzle-orm";
31560
+ import { and as and47, desc as desc26, eq as eq55, inArray as inArray31 } from "drizzle-orm";
31462
31561
 
31463
31562
  // ../api-routes/src/visibility-compare.ts
31464
31563
  var VISIBILITY_COMPARE_MIN_RUNS = 5;
@@ -31945,7 +32044,7 @@ async function visibilityStatsRoutes(app) {
31945
32044
  citationState: querySnapshots.citationState,
31946
32045
  answerMentioned: querySnapshots.answerMentioned,
31947
32046
  createdAt: querySnapshots.createdAt
31948
- }).from(querySnapshots).where(inArray30(querySnapshots.runId, runIds)).all() : [];
32047
+ }).from(querySnapshots).where(inArray31(querySnapshots.runId, runIds)).all() : [];
31949
32048
  const stats = computeVisibilityStats({ queries: projectQueries, snapshots, groupBy });
31950
32049
  const queryAttribution = buildQueryAttribution(projectQueries);
31951
32050
  let shareOfVoice;
@@ -31956,7 +32055,7 @@ async function visibilityStatsRoutes(app) {
31956
32055
  queryText: querySnapshots.queryText,
31957
32056
  answerMentioned: querySnapshots.answerMentioned,
31958
32057
  answerText: querySnapshots.answerText
31959
- }).from(querySnapshots).where(inArray30(querySnapshots.runId, runIds)).all() : [];
32058
+ }).from(querySnapshots).where(inArray31(querySnapshots.runId, runIds)).all() : [];
31960
32059
  const attributedSovSnapshots = sovSnapshots.filter((s) => resolveCurrentQuery(queryAttribution, s) !== void 0);
31961
32060
  const advanced = activeMeasurementPlan(app.db, project.id)?.plan.schemaVersion === 2;
31962
32061
  const queryClass = advanced || projectQueryClassifier(project) ? requestedQueryClass : "all";
@@ -32054,7 +32153,7 @@ function readVisibilityCompare(db, projectName, query) {
32054
32153
  answerText: querySnapshots.answerText,
32055
32154
  citedDomains: querySnapshots.citedDomains,
32056
32155
  location: querySnapshots.location
32057
- }).from(querySnapshots).where(inArray30(querySnapshots.runId, runIds)).all() : [];
32156
+ }).from(querySnapshots).where(inArray31(querySnapshots.runId, runIds)).all() : [];
32058
32157
  return {
32059
32158
  runCount: runIds.length,
32060
32159
  snapshots: snapshots.filter((snapshot) => (providerKey2 === void 0 || normalizeIdentityText(snapshot.provider) === providerKey2) && (locationKey2 === void 0 || (locationKey2 === "none" ? snapshot.location === null : snapshot.location !== null && normalizeIdentityText(snapshot.location) === locationKey2)))
@@ -32173,7 +32272,7 @@ function readVisibilityContinuity(db, projectName, months) {
32173
32272
  const trackedQueries = db.select({ id: queries.id, query: queries.query }).from(queries).where(eq55(queries.projectId, project.id)).all();
32174
32273
  const loadProjectMonth = (bounds) => {
32175
32274
  const runIds = legacyCompareRunIds(db, project.id, bounds);
32176
- const rows = runIds.length > 0 && trackedQueries.length > 0 ? db.select({ queryId: querySnapshots.queryId, queryText: querySnapshots.queryText, provider: querySnapshots.provider, model: querySnapshots.model }).from(querySnapshots).where(inArray30(querySnapshots.runId, runIds)).all() : [];
32275
+ const rows = runIds.length > 0 && trackedQueries.length > 0 ? db.select({ queryId: querySnapshots.queryId, queryText: querySnapshots.queryText, provider: querySnapshots.provider, model: querySnapshots.model }).from(querySnapshots).where(inArray31(querySnapshots.runId, runIds)).all() : [];
32177
32276
  return { runCount: runIds.length, snapshots: rows.map(bare) };
32178
32277
  };
32179
32278
  const frames = [{ frame: "project", continuity: gate(trackedQueries, loadProjectMonth(fromBounds), loadProjectMonth(toBounds)) }];
@@ -32433,7 +32532,7 @@ async function resultsExportRoutes(app) {
32433
32532
  }
32434
32533
 
32435
32534
  // ../api-routes/src/composites.ts
32436
- import { eq as eq57, and as and49, desc as desc27, sql as sql20, like as like5, or as or13, inArray as inArray31 } from "drizzle-orm";
32535
+ import { eq as eq57, and as and49, desc as desc27, sql as sql20, like as like5, or as or13, inArray as inArray32 } from "drizzle-orm";
32437
32536
  var TOP_INSIGHT_LIMIT = 5;
32438
32537
  var SEARCH_HIT_HARD_LIMIT = 50;
32439
32538
  var SEARCH_SNIPPET_RADIUS = 80;
@@ -32734,7 +32833,7 @@ function loadSnapshotsByRunIds(app, runIds, queryIdByText) {
32734
32833
  rawResponse: querySnapshots.rawResponse,
32735
32834
  competitorOverlap: querySnapshots.competitorOverlap,
32736
32835
  citedDomains: querySnapshots.citedDomains
32737
- }).from(querySnapshots).where(inArray31(querySnapshots.runId, [...runIds])).all();
32836
+ }).from(querySnapshots).where(inArray32(querySnapshots.runId, [...runIds])).all();
32738
32837
  for (const row of rows) {
32739
32838
  const queryText = row.queryText?.trim() || null;
32740
32839
  let queryId;
@@ -33174,7 +33273,7 @@ import crypto29 from "crypto";
33174
33273
  import { and as and51, desc as desc29, eq as eq59 } from "drizzle-orm";
33175
33274
 
33176
33275
  // ../api-routes/src/content-data.ts
33177
- import { and as and50, eq as eq58, desc as desc28, gte as gte15, inArray as inArray32, lte as lte14 } from "drizzle-orm";
33276
+ import { and as and50, eq as eq58, desc as desc28, gte as gte15, inArray as inArray33, lte as lte14 } from "drizzle-orm";
33178
33277
  var RECENT_RUNS_WINDOW = 5;
33179
33278
  function loadOrchestratorInput(db, project, locationFilter = void 0, gscWindowDays = DEFAULT_CONTENT_GSC_WINDOW_DAYS) {
33180
33279
  const projectId = project.id;
@@ -33314,7 +33413,7 @@ function listRecentAnswerVisibilityRunIds(db, projectId, limit, locationFilter)
33314
33413
  // Queued/running/failed/cancelled runs may have partial or no
33315
33414
  // snapshots; including them risks pointing latestRunId at a run with
33316
33415
  // no usable evidence.
33317
- inArray32(runs.status, [RunStatuses.completed, RunStatuses.partial]),
33416
+ inArray33(runs.status, [RunStatuses.completed, RunStatuses.partial]),
33318
33417
  // Probe runs are operator/agent test runs; they must not poison the
33319
33418
  // recent-runs window the content engine uses to recommend actions.
33320
33419
  notProbeRun()
@@ -33382,7 +33481,7 @@ function buildCandidateQueries(opts) {
33382
33481
  const queryRows2 = opts.db.select({ id: queries.id, text: queries.query }).from(queries).where(eq58(queries.projectId, opts.projectId)).all();
33383
33482
  const queryIdByText = new Map(queryRows2.map((r) => [r.text, r.id]));
33384
33483
  const candidateQueryIds = opts.candidateQueryStrings.map((q) => queryIdByText.get(q)).filter((id) => Boolean(id));
33385
- const snapshotRows = filterTrackedSnapshots(opts.db.select().from(querySnapshots).where(inArray32(querySnapshots.runId, opts.recentRunIds)).all()).filter((r) => candidateQueryIds.includes(r.queryId));
33484
+ const snapshotRows = filterTrackedSnapshots(opts.db.select().from(querySnapshots).where(inArray33(querySnapshots.runId, opts.recentRunIds)).all()).filter((r) => candidateQueryIds.includes(r.queryId));
33386
33485
  const snapshotsByQuery = /* @__PURE__ */ new Map();
33387
33486
  for (const row of snapshotRows) {
33388
33487
  const list = snapshotsByQuery.get(row.queryId) ?? [];
@@ -34127,6 +34226,7 @@ var SCHEMA_TABLE = {
34127
34226
  ResultsClearResponse: resultsClearResponseSchema,
34128
34227
  DoctorReportDto: doctorReportSchema,
34129
34228
  InstanceStatusDto: instanceStatusDtoSchema,
34229
+ McpProfileDto: mcpProfileDtoSchema,
34130
34230
  GA4AiReferralDailyDto: ga4AiReferralDailyDtoSchema,
34131
34231
  GA4AiReferralHistoryEntry: ga4AiReferralHistoryEntrySchema,
34132
34232
  GA4MeasurementAnalysisDto: gaMeasurementAnalysisDtoSchema,
@@ -41287,6 +41387,19 @@ var routeCatalog = [
41287
41387
  400: errorResponse("Invalid report month.")
41288
41388
  }
41289
41389
  },
41390
+ {
41391
+ method: "get",
41392
+ path: "/api/v1/mcp/profile",
41393
+ summary: "Read the authenticated MCP connection profile",
41394
+ description: "Identifies the named account within this configured MCP resource and its effective instance-wide read scope. Accepts MCP-audience OAuth tokens without granting access to other REST routes. Direct API keys without a named account are refused.",
41395
+ tags: ["mcp"],
41396
+ responses: {
41397
+ 200: jsonResponse("Authenticated MCP connection profile.", "McpProfileDto"),
41398
+ 401: errorResponse("Authentication required or invalid."),
41399
+ 403: errorResponse("An instance-wide named account with read scope is required."),
41400
+ 501: errorResponse("MCP OAuth resource is not configured.")
41401
+ }
41402
+ },
41290
41403
  {
41291
41404
  method: "get",
41292
41405
  path: "/api/v1/status",
@@ -45500,7 +45613,7 @@ async function gbpLocalPostsRoutes(app, options) {
45500
45613
  }
45501
45614
 
45502
45615
  // ../api-routes/src/google.ts
45503
- import { eq as eq66, and as and54, desc as desc31, sql as sql21, inArray as inArray33 } from "drizzle-orm";
45616
+ import { eq as eq66, and as and54, desc as desc31, sql as sql21, inArray as inArray34 } from "drizzle-orm";
45504
45617
 
45505
45618
  // ../api-routes/src/gsc-period-comparison.ts
45506
45619
  var DAY_MS2 = 864e5;
@@ -48756,10 +48869,10 @@ async function googleRoutes(app, opts) {
48756
48869
  locationProfiles: []
48757
48870
  });
48758
48871
  }
48759
- const metricRows = app.db.select().from(gbpDailyMetrics).where(and54(eq66(gbpDailyMetrics.projectId, project.id), inArray33(gbpDailyMetrics.locationName, locationNames))).all();
48760
- const keywordRows = app.db.select().from(gbpKeywordImpressions).where(and54(eq66(gbpKeywordImpressions.projectId, project.id), inArray33(gbpKeywordImpressions.locationName, locationNames))).all();
48761
- const placeActionRows = app.db.select().from(gbpPlaceActions).where(and54(eq66(gbpPlaceActions.projectId, project.id), inArray33(gbpPlaceActions.locationName, locationNames))).all();
48762
- const lodgingRows = app.db.select().from(gbpLodgingSnapshots).where(and54(eq66(gbpLodgingSnapshots.projectId, project.id), inArray33(gbpLodgingSnapshots.locationName, locationNames))).orderBy(desc31(gbpLodgingSnapshots.syncedAt)).all();
48872
+ const metricRows = app.db.select().from(gbpDailyMetrics).where(and54(eq66(gbpDailyMetrics.projectId, project.id), inArray34(gbpDailyMetrics.locationName, locationNames))).all();
48873
+ const keywordRows = app.db.select().from(gbpKeywordImpressions).where(and54(eq66(gbpKeywordImpressions.projectId, project.id), inArray34(gbpKeywordImpressions.locationName, locationNames))).all();
48874
+ const placeActionRows = app.db.select().from(gbpPlaceActions).where(and54(eq66(gbpPlaceActions.projectId, project.id), inArray34(gbpPlaceActions.locationName, locationNames))).all();
48875
+ const lodgingRows = app.db.select().from(gbpLodgingSnapshots).where(and54(eq66(gbpLodgingSnapshots.projectId, project.id), inArray34(gbpLodgingSnapshots.locationName, locationNames))).orderBy(desc31(gbpLodgingSnapshots.syncedAt)).all();
48763
48876
  const latestLodgingByLocation = /* @__PURE__ */ new Map();
48764
48877
  for (const row of lodgingRows) {
48765
48878
  if (!latestLodgingByLocation.has(row.locationName)) {
@@ -48773,7 +48886,7 @@ async function googleRoutes(app, opts) {
48773
48886
  regularHours: gbpLocations.regularHours,
48774
48887
  primaryPhone: gbpLocations.primaryPhone,
48775
48888
  openStatus: gbpLocations.openStatus
48776
- }).from(gbpLocations).where(and54(eq66(gbpLocations.projectId, project.id), inArray33(gbpLocations.locationName, locationNames))).all();
48889
+ }).from(gbpLocations).where(and54(eq66(gbpLocations.projectId, project.id), inArray34(gbpLocations.locationName, locationNames))).all();
48777
48890
  return buildGbpSummary({
48778
48891
  locationName,
48779
48892
  locationCount: locationNames.length,
@@ -50443,7 +50556,7 @@ async function googleMarketingRoutes(app, opts) {
50443
50556
 
50444
50557
  // ../api-routes/src/ads.ts
50445
50558
  import crypto42 from "crypto";
50446
- import { eq as eq69, and as and57, asc as asc15, desc as desc33, gt as gt6, gte as gte16, lt as lt10, lte as lte16, ne as ne13, inArray as inArray34, or as or16, isNull as isNull12, isNotNull as isNotNull7, sql as sql24 } from "drizzle-orm";
50559
+ import { eq as eq69, and as and57, asc as asc15, desc as desc33, gt as gt6, gte as gte16, lt as lt10, lte as lte16, ne as ne13, inArray as inArray35, or as or16, isNull as isNull12, isNotNull as isNotNull7, sql as sql24 } from "drizzle-orm";
50447
50560
 
50448
50561
  // ../api-routes/src/ads-activation.ts
50449
50562
  import crypto40 from "crypto";
@@ -53541,7 +53654,7 @@ function semanticallyMatchesMaterializedEntity(app, input) {
53541
53654
  eq69(adsOperations.projectId, input.projectId),
53542
53655
  eq69(adsOperations.entityType, input.entityType),
53543
53656
  eq69(adsOperations.entityId, input.entityId),
53544
- inArray34(adsOperations.kind, [createKind, updateKind])
53657
+ inArray35(adsOperations.kind, [createKind, updateKind])
53545
53658
  )).orderBy(asc15(adsOperations.createdAt), asc15(adsOperations.id)).all();
53546
53659
  if (rows.some((row) => row.state === AdsOperationStates.pending || row.state === AdsOperationStates.reconciling || row.state === AdsOperationStates.unknown || row.kind === updateKind && row.state === AdsOperationStates.succeeded)) {
53547
53660
  return false;
@@ -53989,7 +54102,7 @@ function quarantineExhaustedReconciliation(app, row, now, policy, context) {
53989
54102
  eq69(adsOperations.id, row.id),
53990
54103
  eq69(adsOperations.projectId, row.projectId),
53991
54104
  gte16(adsOperations.reconcileAttempts, policy.maxAttempts),
53992
- inArray34(adsOperations.state, [
54105
+ inArray35(adsOperations.state, [
53993
54106
  AdsOperationStates.pending,
53994
54107
  AdsOperationStates.unknown,
53995
54108
  AdsOperationStates.reconciling
@@ -54233,7 +54346,7 @@ async function sweepAdsOperationsOnce(app, opts, config) {
54233
54346
  eq69(adsOperations.reconcileStrategy, AdsReconcileStrategies.create_fingerprint),
54234
54347
  or16(
54235
54348
  isNotNull7(adsOperations.entityId),
54236
- inArray34(adsOperations.state, [
54349
+ inArray35(adsOperations.state, [
54237
54350
  AdsOperationStates.pending,
54238
54351
  AdsOperationStates.reconciling
54239
54352
  ])
@@ -54284,7 +54397,7 @@ async function sweepAdsOperationsOnce(app, opts, config) {
54284
54397
  const eligibleProjectIds = [...credentialsByProjectId.keys()];
54285
54398
  if (eligibleProjectIds.length === 0) return;
54286
54399
  const rows = app.db.select().from(adsOperations).where(and57(
54287
- inArray34(adsOperations.projectId, eligibleProjectIds),
54400
+ inArray35(adsOperations.projectId, eligibleProjectIds),
54288
54401
  staleReconcileWhere
54289
54402
  )).orderBy(asc15(adsOperations.updatedAt)).limit(config.batchSize).all();
54290
54403
  for (const row of rows) {
@@ -54610,7 +54723,7 @@ async function adsRoutes(app, opts) {
54610
54723
  const cursor = parsed.data.cursor ? decodeAdsOperationCursor(parsed.data.cursor, project.id, parsed.data.state) : void 0;
54611
54724
  const rows = app.db.select().from(adsOperations).where(and57(
54612
54725
  eq69(adsOperations.projectId, project.id),
54613
- inArray34(adsOperations.state, parsed.data.state),
54726
+ inArray35(adsOperations.state, parsed.data.state),
54614
54727
  cursor ? or16(
54615
54728
  gt6(adsOperations.createdAt, cursor.createdAt),
54616
54729
  and57(
@@ -55044,7 +55157,7 @@ async function adsRoutes(app, opts) {
55044
55157
  const inFlight2 = app.db.select({ id: runs.id, status: runs.status }).from(runs).where(and57(
55045
55158
  eq69(runs.projectId, project.id),
55046
55159
  eq69(runs.kind, RunKinds["ads-sync"]),
55047
- inArray34(runs.status, [RunStatuses.queued, RunStatuses.running])
55160
+ inArray35(runs.status, [RunStatuses.queued, RunStatuses.running])
55048
55161
  )).get();
55049
55162
  if (inFlight2) {
55050
55163
  const existing = { runId: inFlight2.id, status: inFlight2.status };
@@ -60934,7 +61047,7 @@ async function backlinksRoutes(app, opts) {
60934
61047
  import crypto52 from "crypto";
60935
61048
  import { isIP } from "net";
60936
61049
  import { isDeepStrictEqual } from "util";
60937
- import { and as and69, desc as desc39, eq as eq80, gt as gt7, gte as gte20, inArray as inArray35, lt as lt13, lte as lte21, sql as sql31 } from "drizzle-orm";
61050
+ import { and as and69, desc as desc39, eq as eq80, gt as gt7, gte as gte20, inArray as inArray36, lt as lt13, lte as lte21, sql as sql31 } from "drizzle-orm";
60938
61051
 
60939
61052
  // ../api-routes/src/traffic-limits.ts
60940
61053
  var VERCEL_MAX_SYNC_WINDOW_MS = 24 * 60 * 6e4;
@@ -65884,7 +65997,7 @@ async function trafficRoutes(app, opts) {
65884
65997
  const listed = useContentList ? contentPaths : infraPaths;
65885
65998
  const IN_LIST_CAP = 2e4;
65886
65999
  const listFitsInSql = listed.length <= IN_LIST_CAP;
65887
- const contentExpr = listed.length === 0 ? useContentList ? sql31`0` : sql31`${crawlerEventsHourly.hits}` : useContentList ? sql31`CASE WHEN ${inArray35(crawlerEventsHourly.pathNormalized, listed)} THEN ${crawlerEventsHourly.hits} ELSE 0 END` : sql31`CASE WHEN ${inArray35(crawlerEventsHourly.pathNormalized, listed)} THEN 0 ELSE ${crawlerEventsHourly.hits} END`;
66000
+ const contentExpr = listed.length === 0 ? useContentList ? sql31`0` : sql31`${crawlerEventsHourly.hits}` : useContentList ? sql31`CASE WHEN ${inArray36(crawlerEventsHourly.pathNormalized, listed)} THEN ${crawlerEventsHourly.hits} ELSE 0 END` : sql31`CASE WHEN ${inArray36(crawlerEventsHourly.pathNormalized, listed)} THEN 0 ELSE ${crawlerEventsHourly.hits} END`;
65888
66001
  if (listFitsInSql) {
65889
66002
  const crawlerSeries = app.db.select({
65890
66003
  bucket: crawlerSeriesBucket,
@@ -66273,7 +66386,7 @@ var reportSweepsCheck = {
66273
66386
  };
66274
66387
 
66275
66388
  // ../api-routes/src/doctor/checks/report-models.ts
66276
- import { and as and71, eq as eq82, gte as gte22, inArray as inArray36, lte as lte23 } from "drizzle-orm";
66389
+ import { and as and71, eq as eq82, gte as gte22, inArray as inArray37, lte as lte23 } from "drizzle-orm";
66277
66390
  var reportModelsCheck = {
66278
66391
  id: "report.models",
66279
66392
  category: CheckCategories.providers,
@@ -66288,7 +66401,7 @@ var reportModelsCheck = {
66288
66401
  const months = reportMonths.flatMap((month) => {
66289
66402
  const bounds = calendarMonthBounds(month);
66290
66403
  const previous = new Date(Date.parse(bounds.since) - 1).toISOString().slice(0, 7);
66291
- const observations = ctx.db.select({ provider: querySnapshots.provider, model: querySnapshots.model, at: runs.createdAt }).from(querySnapshots).innerJoin(runs, eq82(runs.id, querySnapshots.runId)).where(and71(eq82(runs.projectId, ctx.project.id), eq82(runs.kind, RunKinds["answer-visibility"]), inArray36(runs.status, [RunStatuses.completed, RunStatuses.partial]), notProbeRun(), gte22(runs.createdAt, bounds.since), lte23(runs.createdAt, bounds.until))).all();
66404
+ const observations = ctx.db.select({ provider: querySnapshots.provider, model: querySnapshots.model, at: runs.createdAt }).from(querySnapshots).innerJoin(runs, eq82(runs.id, querySnapshots.runId)).where(and71(eq82(runs.projectId, ctx.project.id), eq82(runs.kind, RunKinds["answer-visibility"]), inArray37(runs.status, [RunStatuses.completed, RunStatuses.partial]), notProbeRun(), gte22(runs.createdAt, bounds.since), lte23(runs.createdAt, bounds.until))).all();
66292
66405
  return readVisibilityContinuity(ctx.db, ctx.project.name, { from: previous, to: month }).map(({ frame, continuity: continuity2 }) => ({
66293
66406
  month,
66294
66407
  previousMonth: previous,
@@ -66865,7 +66978,7 @@ var BACKLINKS_CHECKS = [
66865
66978
  ];
66866
66979
 
66867
66980
  // ../api-routes/src/doctor/checks/bing-auth.ts
66868
- import { and as and73, desc as desc40, eq as eq85, inArray as inArray37 } from "drizzle-orm";
66981
+ import { and as and73, desc as desc40, eq as eq85, inArray as inArray38 } from "drizzle-orm";
66869
66982
  var BING_CONNECTION_ENTITY = "bing_connection";
66870
66983
  var BING_CONNECTED_ACTION = "bing.connected";
66871
66984
  var BING_DISCONNECTED_ACTION = "bing.disconnected";
@@ -66876,7 +66989,7 @@ function lostBingConnection(ctx, project) {
66876
66989
  const lastChange = ctx.db.select({ action: auditLog.action }).from(auditLog).where(and73(
66877
66990
  eq85(auditLog.entityType, BING_CONNECTION_ENTITY),
66878
66991
  eq85(auditLog.entityId, project.canonicalDomain),
66879
- inArray37(auditLog.action, [BING_CONNECTED_ACTION, BING_DISCONNECTED_ACTION])
66992
+ inArray38(auditLog.action, [BING_CONNECTED_ACTION, BING_DISCONNECTED_ACTION])
66880
66993
  )).orderBy(desc40(auditLog.createdAt)).limit(1).get();
66881
66994
  return lastChange?.action !== BING_DISCONNECTED_ACTION;
66882
66995
  }
@@ -67422,7 +67535,7 @@ var ga4ConnectionCheck = {
67422
67535
  var GA_AUTH_CHECKS = [ga4ConnectionCheck];
67423
67536
 
67424
67537
  // ../api-routes/src/doctor/checks/data-freshness.ts
67425
- import { and as and74, desc as desc41, eq as eq88, inArray as inArray38 } from "drizzle-orm";
67538
+ import { and as and74, desc as desc41, eq as eq88, inArray as inArray39 } from "drizzle-orm";
67426
67539
  var GA_DATA_AGING_DAYS = 3;
67427
67540
  var GA_DATA_STALE_DAYS = 5;
67428
67541
  var GSC_DATA_AGING_DAYS = 5;
@@ -67451,7 +67564,7 @@ function skipped(code, summary3) {
67451
67564
  return { status: CheckStatuses.skipped, code, summary: summary3, remediation: null };
67452
67565
  }
67453
67566
  function lastSyncAgeDays(ctx, kinds) {
67454
- const row = ctx.db.select({ createdAt: runs.createdAt }).from(runs).where(and74(eq88(runs.projectId, ctx.project.id), inArray38(runs.kind, kinds), eq88(runs.status, "completed"))).orderBy(desc41(runs.createdAt)).limit(1).get();
67567
+ const row = ctx.db.select({ createdAt: runs.createdAt }).from(runs).where(and74(eq88(runs.projectId, ctx.project.id), inArray39(runs.kind, kinds), eq88(runs.status, "completed"))).orderBy(desc41(runs.createdAt)).limit(1).get();
67455
67568
  if (!row?.createdAt) return null;
67456
67569
  const age = Math.floor((Date.now() - Date.parse(row.createdAt)) / DAY_MS4);
67457
67570
  return Number.isFinite(age) ? age : null;
@@ -67577,7 +67690,7 @@ var gscRecentDataCheck = {
67577
67690
  var DATA_FRESHNESS_CHECKS = [gaRecentDataCheck, gscRecentDataCheck];
67578
67691
 
67579
67692
  // ../api-routes/src/doctor/checks/seo-refresh.ts
67580
- import { and as and75, asc as asc20, desc as desc42, eq as eq89, gt as gt8, inArray as inArray39, sql as sql32 } from "drizzle-orm";
67693
+ import { and as and75, asc as asc20, desc as desc42, eq as eq89, gt as gt8, inArray as inArray40, sql as sql32 } from "drizzle-orm";
67581
67694
  var GRACE_DAYS = 2;
67582
67695
  var DAY_MS5 = 24 * 60 * 60 * 1e3;
67583
67696
  var FIRING_SPAN_MS = 6e4;
@@ -67609,7 +67722,7 @@ function isIncomplete(run) {
67609
67722
  return run.status === RunStatuses.failed || run.status === RunStatuses.partial;
67610
67723
  }
67611
67724
  function runProfiles(ctx, firing) {
67612
- const jobs = firing.length === 0 ? [] : ctx.db.select({ runId: seoJobs.runId, profileId: seoJobs.profileId }).from(seoJobs).where(inArray39(seoJobs.runId, firing.map((run) => run.id))).all();
67725
+ const jobs = firing.length === 0 ? [] : ctx.db.select({ runId: seoJobs.runId, profileId: seoJobs.profileId }).from(seoJobs).where(inArray40(seoJobs.runId, firing.map((run) => run.id))).all();
67613
67726
  const byRun = new Map(jobs.flatMap((job) => job.runId ? [[job.runId, job.profileId]] : []));
67614
67727
  return new Map(firing.map((run) => [run.id, byRun.get(run.id) ?? skippedRefreshProfile(run.error)]));
67615
67728
  }
@@ -67719,7 +67832,7 @@ function gradeSeoRefresh(ctx, project) {
67719
67832
  };
67720
67833
  }
67721
67834
  if (now >= Date.parse(deadlineAt)) {
67722
- const active = ctx.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(and75(seoSyncRuns(project.id), inArray39(runs.status, [RunStatuses.queued, RunStatuses.running]))).orderBy(asc20(runs.createdAt)).limit(1).get();
67835
+ const active = ctx.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(and75(seoSyncRuns(project.id), inArray40(runs.status, [RunStatuses.queued, RunStatuses.running]))).orderBy(asc20(runs.createdAt)).limit(1).get();
67723
67836
  const since = last ? `No SEO refresh has completed since ${day(last.at)}.` : "No SEO refresh has completed since the schedule was enabled.";
67724
67837
  const missed = last ? `The scheduled refresh due ${day(dueAt)} did not complete within ${GRACE_DAYS} days.` : `Its first refresh, due ${day(dueAt)}, did not complete within ${GRACE_DAYS} days.`;
67725
67838
  return {
@@ -68135,7 +68248,7 @@ async function probeApiHost(host, options = {}) {
68135
68248
  }
68136
68249
 
68137
68250
  // ../api-routes/src/doctor/checks/integration-sync.ts
68138
- import { and as and76, count as count7, desc as desc43, eq as eq90, gte as gte23, gt as gt9, inArray as inArray40, isNull as isNull14, notInArray as notInArray3, or as or19 } from "drizzle-orm";
68251
+ import { and as and76, count as count7, desc as desc43, eq as eq90, gte as gte23, gt as gt9, inArray as inArray41, isNull as isNull14, notInArray as notInArray3, or as or19 } from "drizzle-orm";
68139
68252
  var SYNC_FAILURE_WINDOW = 3;
68140
68253
  var SUMMARY_ERROR_LIMIT = 300;
68141
68254
  var FINISHED_STATUSES = [RunStatuses.completed, RunStatuses.partial, RunStatuses.failed];
@@ -68228,8 +68341,8 @@ function readSyncRunState(db, projectId, kind, options = {}) {
68228
68341
  ...options.nothingToSyncErrors?.length ? [or19(isNull14(runs.error), notInArray3(runs.error, [...options.nothingToSyncErrors]))] : []
68229
68342
  );
68230
68343
  const graded = options.since ? and76(scope, gte23(runs.createdAt, options.since)) : scope;
68231
- const recent = db.select({ id: runs.id, status: runs.status, trigger: runs.trigger, error: runs.error, createdAt: runs.createdAt }).from(runs).where(and76(graded, inArray40(runs.status, FINISHED_STATUSES))).orderBy(desc43(runs.createdAt)).limit(SYNC_FAILURE_WINDOW).all();
68232
- const lastSuccess = db.select({ createdAt: runs.createdAt, finishedAt: runs.finishedAt }).from(runs).where(and76(graded, inArray40(runs.status, SUCCESS_STATUSES))).orderBy(desc43(runs.createdAt)).limit(1).get();
68344
+ const recent = db.select({ id: runs.id, status: runs.status, trigger: runs.trigger, error: runs.error, createdAt: runs.createdAt }).from(runs).where(and76(graded, inArray41(runs.status, FINISHED_STATUSES))).orderBy(desc43(runs.createdAt)).limit(SYNC_FAILURE_WINDOW).all();
68345
+ const lastSuccess = db.select({ createdAt: runs.createdAt, finishedAt: runs.finishedAt }).from(runs).where(and76(graded, inArray41(runs.status, SUCCESS_STATUSES))).orderBy(desc43(runs.createdAt)).limit(1).get();
68233
68346
  const failureCount = db.select({ count: count7() }).from(runs).where(and76(lastSuccess ? and76(graded, gt9(runs.createdAt, lastSuccess.createdAt)) : graded, eq90(runs.status, RunStatuses.failed))).get();
68234
68347
  const failuresSinceSuccess = Number(failureCount?.count ?? 0);
68235
68348
  const latest = recent[0];
@@ -68790,7 +68903,7 @@ var PLACES_CHECK_BY_ID = Object.fromEntries(
68790
68903
  );
68791
68904
 
68792
68905
  // ../api-routes/src/doctor/checks/gbp-reviews.ts
68793
- import { and as and78, desc as desc44, eq as eq94, gte as gte24, inArray as inArray41, sql as sql33 } from "drizzle-orm";
68906
+ import { and as and78, desc as desc44, eq as eq94, gte as gte24, inArray as inArray42, sql as sql33 } from "drizzle-orm";
68794
68907
  var REVIEW_EVENTS = /* @__PURE__ */ new Set(["review.negative", "review.rating-dropped"]);
68795
68908
  var V4_ACCESS_REMEDIATION = "Business Profile reviews use the legacy My Business API (mybusiness.googleapis.com), which Google enables per Cloud project only on request; the API Library and `gcloud services enable` cannot turn it on. Open the enable link in the API access approval email as the approved account, or reply to the access-request thread asking Google to enable mybusiness.googleapis.com for your project number, then run `canonry gbp sync`.";
68796
68909
  var reviewsAccessCheck = {
@@ -68913,7 +69026,7 @@ var reviewDeliveryCheck = {
68913
69026
  payload: reviewWebhookDeliveries.payload
68914
69027
  }).from(reviewWebhookDeliveries).where(and78(
68915
69028
  eq94(reviewWebhookDeliveries.projectId, ctx.project.id),
68916
- inArray41(reviewWebhookDeliveries.state, [ReviewDeliveryStates.Uncertain, ReviewDeliveryStates.Failed]),
69029
+ inArray42(reviewWebhookDeliveries.state, [ReviewDeliveryStates.Uncertain, ReviewDeliveryStates.Failed]),
68917
69030
  gte24(lastTouched, since)
68918
69031
  )).orderBy(desc44(lastTouched)).all();
68919
69032
  if (rows.length === 0) {
@@ -69498,7 +69611,7 @@ var RUNTIME_STATE_CHECKS = [
69498
69611
  ];
69499
69612
 
69500
69613
  // ../api-routes/src/doctor/checks/traffic-source.ts
69501
- import { and as and79, desc as desc45, eq as eq95, gte as gte25, inArray as inArray42, isNotNull as isNotNull9, ne as ne16, sql as sql34 } from "drizzle-orm";
69614
+ import { and as and79, desc as desc45, eq as eq95, gte as gte25, inArray as inArray43, isNotNull as isNotNull9, ne as ne16, sql as sql34 } from "drizzle-orm";
69502
69615
  var RECENT_DATA_WARN_DAYS = 7;
69503
69616
  var RECENT_DATA_FAIL_DAYS = 30;
69504
69617
  function isCloudflareDirectPush(source) {
@@ -69678,7 +69791,7 @@ var recentDataCheck = {
69678
69791
  ctx.db.select({ total: sql34`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
69679
69792
  and79(
69680
69793
  eq95(crawlerEventsHourly.projectId, ctx.project.id),
69681
- inArray42(crawlerEventsHourly.sourceId, activeSourceIds),
69794
+ inArray43(crawlerEventsHourly.sourceId, activeSourceIds),
69682
69795
  gte25(crawlerEventsHourly.tsHour, warnCutoff)
69683
69796
  )
69684
69797
  ).get()?.total ?? 0
@@ -69687,7 +69800,7 @@ var recentDataCheck = {
69687
69800
  ctx.db.select({ total: sql34`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
69688
69801
  and79(
69689
69802
  eq95(aiReferralEventsHourly.projectId, ctx.project.id),
69690
- inArray42(aiReferralEventsHourly.sourceId, activeSourceIds),
69803
+ inArray43(aiReferralEventsHourly.sourceId, activeSourceIds),
69691
69804
  gte25(aiReferralEventsHourly.tsHour, warnCutoff)
69692
69805
  )
69693
69806
  ).get()?.total ?? 0
@@ -69696,7 +69809,7 @@ var recentDataCheck = {
69696
69809
  ctx.db.select({ total: sql34`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
69697
69810
  and79(
69698
69811
  eq95(aiUserFetchEventsHourly.projectId, ctx.project.id),
69699
- inArray42(aiUserFetchEventsHourly.sourceId, activeSourceIds),
69812
+ inArray43(aiUserFetchEventsHourly.sourceId, activeSourceIds),
69700
69813
  gte25(aiUserFetchEventsHourly.tsHour, warnCutoff)
69701
69814
  )
69702
69815
  ).get()?.total ?? 0
@@ -69722,7 +69835,7 @@ var recentDataCheck = {
69722
69835
  ctx.db.select({ total: sql34`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
69723
69836
  and79(
69724
69837
  eq95(crawlerEventsHourly.projectId, ctx.project.id),
69725
- inArray42(crawlerEventsHourly.sourceId, activeSourceIds),
69838
+ inArray43(crawlerEventsHourly.sourceId, activeSourceIds),
69726
69839
  gte25(crawlerEventsHourly.tsHour, failCutoff)
69727
69840
  )
69728
69841
  ).get()?.total ?? 0
@@ -69731,7 +69844,7 @@ var recentDataCheck = {
69731
69844
  ctx.db.select({ total: sql34`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
69732
69845
  and79(
69733
69846
  eq95(aiReferralEventsHourly.projectId, ctx.project.id),
69734
- inArray42(aiReferralEventsHourly.sourceId, activeSourceIds),
69847
+ inArray43(aiReferralEventsHourly.sourceId, activeSourceIds),
69735
69848
  gte25(aiReferralEventsHourly.tsHour, failCutoff)
69736
69849
  )
69737
69850
  ).get()?.total ?? 0
@@ -69740,7 +69853,7 @@ var recentDataCheck = {
69740
69853
  ctx.db.select({ total: sql34`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
69741
69854
  and79(
69742
69855
  eq95(aiUserFetchEventsHourly.projectId, ctx.project.id),
69743
- inArray42(aiUserFetchEventsHourly.sourceId, activeSourceIds),
69856
+ inArray43(aiUserFetchEventsHourly.sourceId, activeSourceIds),
69744
69857
  gte25(aiUserFetchEventsHourly.tsHour, failCutoff)
69745
69858
  )
69746
69859
  ).get()?.total ?? 0
@@ -70997,7 +71110,7 @@ async function statusRoutes(app, opts) {
70997
71110
 
70998
71111
  // ../api-routes/src/discovery/routes.ts
70999
71112
  import crypto54 from "crypto";
71000
- import { and as and81, desc as desc47, eq as eq97, gte as gte26, inArray as inArray43, isNull as isNull16, or as or20 } from "drizzle-orm";
71113
+ import { and as and81, desc as desc47, eq as eq97, gte as gte26, inArray as inArray44, isNull as isNull16, or as or20 } from "drizzle-orm";
71001
71114
  var MAX_INFLIGHT_DISCOVERY_AGE_MS = 2 * 60 * 60 * 1e3;
71002
71115
  async function discoveryRoutes(app, opts) {
71003
71116
  app.post("/projects/:name/discover/run", async (request, reply) => {
@@ -71052,7 +71165,7 @@ async function discoveryRoutes(app, opts) {
71052
71165
  // must never reuse another set's session. Null (= Gemini-only
71053
71166
  // default, including explicit ['gemini']) matches legacy rows.
71054
71167
  seedProviders == null ? isNull16(discoverySessions.seedProviders) : eq97(discoverySessions.seedProviders, seedProviders),
71055
- inArray43(discoverySessions.status, [
71168
+ inArray44(discoverySessions.status, [
71056
71169
  DiscoverySessionStatuses.queued,
71057
71170
  DiscoverySessionStatuses.seeding,
71058
71171
  DiscoverySessionStatuses.probing
@@ -71760,7 +71873,7 @@ function dedupeStrings(input) {
71760
71873
 
71761
71874
  // ../api-routes/src/technical-aeo.ts
71762
71875
  import crypto56 from "crypto";
71763
- import { and as and83, asc as asc22, count as count8, desc as desc48, eq as eq100, gte as gte27, inArray as inArray44, isNotNull as isNotNull10, isNull as isNull17, lt as lt14, or as or21, sql as sql36 } from "drizzle-orm";
71876
+ import { and as and83, asc as asc22, count as count8, desc as desc48, eq as eq100, gte as gte27, inArray as inArray45, isNotNull as isNotNull10, isNull as isNull17, lt as lt14, or as or21, sql as sql36 } from "drizzle-orm";
71764
71877
  import { alias } from "drizzle-orm/sqlite-core";
71765
71878
 
71766
71879
  // ../api-routes/src/technical-aeo-issues.ts
@@ -72405,7 +72518,7 @@ async function technicalAeoRoutes(app, opts) {
72405
72518
  eq100(siteCrawlSnapshots.projectId, projectId),
72406
72519
  eq100(runs.projectId, projectId),
72407
72520
  eq100(runs.kind, RunKinds["site-audit"]),
72408
- inArray44(runs.status, SURFACEABLE_STATUSES),
72521
+ inArray45(runs.status, SURFACEABLE_STATUSES),
72409
72522
  notProbeRun()
72410
72523
  ];
72411
72524
  const availableScanDatesFor = (projectId, requestedDate) => {
@@ -72475,7 +72588,7 @@ async function technicalAeoRoutes(app, opts) {
72475
72588
  eq100(siteAuditSnapshots.projectId, projectId),
72476
72589
  eq100(runs.projectId, projectId),
72477
72590
  eq100(runs.kind, RunKinds["site-audit"]),
72478
- inArray44(runs.status, SURFACEABLE_STATUSES),
72591
+ inArray45(runs.status, SURFACEABLE_STATUSES),
72479
72592
  notProbeRun(),
72480
72593
  ...recordedBefore ? [lt14(siteAuditSnapshots.createdAt, recordedBefore)] : []
72481
72594
  ];
@@ -72627,7 +72740,7 @@ async function technicalAeoRoutes(app, opts) {
72627
72740
  eq100(runs.id, runId),
72628
72741
  eq100(runs.projectId, projectId),
72629
72742
  eq100(runs.kind, RunKinds["site-audit"]),
72630
- inArray44(runs.status, SURFACEABLE_STATUSES),
72743
+ inArray45(runs.status, SURFACEABLE_STATUSES),
72631
72744
  notProbeRun()
72632
72745
  )).limit(1).get());
72633
72746
  const assertKnownAuditRun = (projectId, runId) => {
@@ -72637,7 +72750,7 @@ async function technicalAeoRoutes(app, opts) {
72637
72750
  eq100(siteAuditSnapshots.projectId, projectId),
72638
72751
  eq100(runs.projectId, projectId),
72639
72752
  eq100(runs.kind, RunKinds["site-audit"]),
72640
- inArray44(runs.status, SURFACEABLE_STATUSES),
72753
+ inArray45(runs.status, SURFACEABLE_STATUSES),
72641
72754
  notProbeRun()
72642
72755
  )).limit(1).get());
72643
72756
  const emptyCrawlSummary = (projectName, legacyAuditAvailable) => ({
@@ -72768,7 +72881,7 @@ async function technicalAeoRoutes(app, opts) {
72768
72881
  eq100(siteAuditSnapshots.projectId, project.id),
72769
72882
  eq100(runs.projectId, project.id),
72770
72883
  eq100(runs.kind, RunKinds["site-audit"]),
72771
- inArray44(runs.status, SURFACEABLE_STATUSES),
72884
+ inArray45(runs.status, SURFACEABLE_STATUSES),
72772
72885
  notProbeRun()
72773
72886
  )).orderBy(desc48(siteAuditSnapshots.createdAt)).limit(limit).all();
72774
72887
  return { project: project.name, points: rows.reverse() };
@@ -73083,8 +73196,8 @@ async function technicalAeoRoutes(app, opts) {
73083
73196
  eq100(siteCrawlEdges.internal, true),
73084
73197
  isNotNull10(siteCrawlEdges.targetNodeKey),
73085
73198
  or21(
73086
- inArray44(siteCrawlEdges.sourceNodeKey, frontier),
73087
- inArray44(siteCrawlEdges.targetNodeKey, frontier)
73199
+ inArray45(siteCrawlEdges.sourceNodeKey, frontier),
73200
+ inArray45(siteCrawlEdges.targetNodeKey, frontier)
73088
73201
  )
73089
73202
  )).orderBy(asc22(siteCrawlEdges.edgeKey)).limit(maxEdges + maxNodes + 1).all();
73090
73203
  if (candidates.length > maxEdges + maxNodes) queryTruncated = true;
@@ -73121,7 +73234,7 @@ async function technicalAeoRoutes(app, opts) {
73121
73234
  eq100(siteCrawlPages.projectId, scope.projectId),
73122
73235
  eq100(siteCrawlPages.runId, scope.runId),
73123
73236
  eq100(siteCrawlPages.attemptId, scope.attemptId),
73124
- inArray44(siteCrawlPages.nodeKey, nodeKeys)
73237
+ inArray45(siteCrawlPages.nodeKey, nodeKeys)
73125
73238
  )).all();
73126
73239
  const persistedNodeKeys = new Set(pageRows.map((row) => row.nodeKey));
73127
73240
  const outermostNodeKeys = pageRows.filter((row) => distances.get(row.nodeKey) === hops).map((row) => row.nodeKey);
@@ -73131,8 +73244,8 @@ async function technicalAeoRoutes(app, opts) {
73131
73244
  eq100(siteCrawlEdges.attemptId, scope.attemptId),
73132
73245
  eq100(siteCrawlEdges.internal, true),
73133
73246
  isNotNull10(siteCrawlEdges.targetNodeKey),
73134
- inArray44(siteCrawlEdges.sourceNodeKey, outermostNodeKeys),
73135
- inArray44(siteCrawlEdges.targetNodeKey, outermostNodeKeys)
73247
+ inArray45(siteCrawlEdges.sourceNodeKey, outermostNodeKeys),
73248
+ inArray45(siteCrawlEdges.targetNodeKey, outermostNodeKeys)
73136
73249
  )).limit(1).get();
73137
73250
  if (omittedOutermostEdge && !seenEdgeKeys.has(omittedOutermostEdge.edgeKey)) {
73138
73251
  omittedEdgeKeys.add(omittedOutermostEdge.edgeKey);
@@ -73233,7 +73346,7 @@ async function technicalAeoRoutes(app, opts) {
73233
73346
  eq100(siteCrawlEdges.followable, true),
73234
73347
  eq100(siteCrawlEdges.relation, "anchor"),
73235
73348
  isNotNull10(siteCrawlEdges.targetNodeKey),
73236
- inArray44(siteCrawlEdges.sourceNodeKey, frontier)
73349
+ inArray45(siteCrawlEdges.sourceNodeKey, frontier)
73237
73350
  )).orderBy(asc22(siteCrawlEdges.edgeKey)).limit(SITE_HEALTH_PATH_MAX_VISITED_NODES + 1).all();
73238
73351
  if (candidates.length > SITE_HEALTH_PATH_MAX_VISITED_NODES) truncated = true;
73239
73352
  const candidateTargetKeys = [...new Set(candidates.map((edge) => edge.targetNodeKey).filter((nodeKey) => nodeKey != null))];
@@ -73241,7 +73354,7 @@ async function technicalAeoRoutes(app, opts) {
73241
73354
  eq100(siteCrawlPages.projectId, scope.projectId),
73242
73355
  eq100(siteCrawlPages.runId, scope.runId),
73243
73356
  eq100(siteCrawlPages.attemptId, scope.attemptId),
73244
- inArray44(siteCrawlPages.nodeKey, candidateTargetKeys)
73357
+ inArray45(siteCrawlPages.nodeKey, candidateTargetKeys)
73245
73358
  )).all().map((row) => row.nodeKey));
73246
73359
  const next = /* @__PURE__ */ new Set();
73247
73360
  for (const edge of candidates.slice(0, SITE_HEALTH_PATH_MAX_VISITED_NODES)) {
@@ -73286,7 +73399,7 @@ async function technicalAeoRoutes(app, opts) {
73286
73399
  eq100(siteCrawlPages.projectId, scope.projectId),
73287
73400
  eq100(siteCrawlPages.runId, scope.runId),
73288
73401
  eq100(siteCrawlPages.attemptId, scope.attemptId),
73289
- inArray44(siteCrawlPages.nodeKey, pathKeys)
73402
+ inArray45(siteCrawlPages.nodeKey, pathKeys)
73290
73403
  )).all();
73291
73404
  const pageByKey = new Map(pathRows.map((row) => [row.nodeKey, row]));
73292
73405
  const pathDetection = templateDetectionOf(snapshot.templateDetection);
@@ -73577,14 +73690,14 @@ async function technicalAeoRoutes(app, opts) {
73577
73690
  eq100(siteCrawlPages.projectId, scope.projectId),
73578
73691
  eq100(siteCrawlPages.runId, scope.runId),
73579
73692
  eq100(siteCrawlPages.attemptId, scope.attemptId),
73580
- inArray44(siteCrawlPages.nodeKey, pageKeys)
73693
+ inArray45(siteCrawlPages.nodeKey, pageKeys)
73581
73694
  )).all();
73582
73695
  const edgeRowsFor = (scope) => linkKeys.length === 0 ? [] : app.db.select().from(siteCrawlEdges).where(and83(
73583
73696
  eq100(siteCrawlEdges.projectId, scope.projectId),
73584
73697
  eq100(siteCrawlEdges.runId, scope.runId),
73585
73698
  eq100(siteCrawlEdges.attemptId, scope.attemptId),
73586
73699
  eq100(siteCrawlEdges.internal, true),
73587
- inArray44(siteCrawlEdges.edgeKey, linkKeys)
73700
+ inArray45(siteCrawlEdges.edgeKey, linkKeys)
73588
73701
  )).all();
73589
73702
  const beforePages = new Map(pageRowsFor(beforeScope).map((row) => [row.nodeKey, mapCrawlPage(row)]));
73590
73703
  const afterPages = new Map(pageRowsFor(afterScope).map((row) => [row.nodeKey, mapCrawlPage(row)]));
@@ -74115,9 +74228,9 @@ async function technicalAeoRoutes(app, opts) {
74115
74228
  eq100(siteCrawlSnapshots.projectId, project.id),
74116
74229
  eq100(runs.projectId, project.id),
74117
74230
  eq100(runs.kind, RunKinds["site-audit"]),
74118
- inArray44(runs.status, SURFACEABLE_STATUSES),
74231
+ inArray45(runs.status, SURFACEABLE_STATUSES),
74119
74232
  notProbeRun(),
74120
- inArray44(siteCrawlSnapshots.runId, runIds)
74233
+ inArray45(siteCrawlSnapshots.runId, runIds)
74121
74234
  )).all().map((row) => row.runId));
74122
74235
  return {
74123
74236
  project: project.name,
@@ -74258,7 +74371,7 @@ async function technicalAeoRoutes(app, opts) {
74258
74371
  )).where(and83(
74259
74372
  eq100(runs.projectId, project.id),
74260
74373
  eq100(runs.kind, RunKinds["site-audit"]),
74261
- inArray44(runs.status, [RunStatuses.queued, RunStatuses.running])
74374
+ inArray45(runs.status, [RunStatuses.queued, RunStatuses.running])
74262
74375
  )).get();
74263
74376
  if (existing) {
74264
74377
  if (existing.identityKey === identityKey) {
@@ -75184,6 +75297,7 @@ async function apiRoutes(app, opts) {
75184
75297
  getGoogleMarketingDoctorInput: opts.getGoogleMarketingDoctorInput,
75185
75298
  probeApiHost: opts.probeApiHost
75186
75299
  });
75300
+ await api.register(mcpProfileRoutes, { oauthResourceUrl: opts.oauthResourceUrl });
75187
75301
  await api.register(statusRoutes, {
75188
75302
  db: opts.db,
75189
75303
  getMcpHealth: opts.getMcpHealth,
@@ -75433,6 +75547,7 @@ export {
75433
75547
  createCredentialChecker,
75434
75548
  requireInstanceAdministrator,
75435
75549
  hashApiKey,
75550
+ MCP_DELEGATED_KEY_MAX_AGE_MS,
75436
75551
  notProbeRun,
75437
75552
  syncRunClaimKey,
75438
75553
  writeAuditLog,