@canonry/canonry 7.72.2 → 7.73.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.
- package/assets/assets/{AgentSetupPage-D39M9CRK.js → AgentSetupPage-D7YVdPWO.js} +1 -1
- package/assets/assets/{AuditHistoryPanel-BS-iFyHX.js → AuditHistoryPanel-yrgfS5B_.js} +1 -1
- package/assets/assets/{BacklinksPage-BW2bEGF4.js → BacklinksPage-DJM6z03g.js} +1 -1
- package/assets/assets/{HistoryPage-Dh6o2iVd.js → HistoryPage-CNvAVJ1S.js} +1 -1
- package/assets/assets/{MeasurementPropertyPage-DL9cbtVz.js → MeasurementPropertyPage-BVVYhOxR.js} +1 -1
- package/assets/assets/{ProjectPage-DXh97uDN.js → ProjectPage-CPRD8kR9.js} +1 -1
- package/assets/assets/{RunsPage-BM4ETLsm.js → RunsPage-Ck33dcjz.js} +1 -1
- package/assets/assets/{SettingsPage-DpJTB2-Q.js → SettingsPage-CS_t4Dai.js} +1 -1
- package/assets/assets/{SiteHealthSection-CmlMQ17V.js → SiteHealthSection-BurKnHpn.js} +2 -2
- package/assets/assets/ToneBadge-Df8oiKsQ.js +60 -0
- package/assets/assets/{TrafficPage-ClH3Dxnm.js → TrafficPage-DAiY698E.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-DE-NyNGz.js → TrafficSourceDetailPage-clJSX2rr.js} +1 -1
- package/assets/assets/{account-context-BwV6ox8O.js → account-context-DDEhuoP2.js} +1 -1
- package/assets/assets/{card-DhkoBNyY.js → card-DbR-lBY3.js} +1 -1
- package/assets/assets/{extract-error-message-dNDtiSBo.js → extract-error-message-7_Vm2DQF.js} +1 -1
- package/assets/assets/{format-helpers-Bt4tx-f3.js → format-helpers-vtahpXTQ.js} +1 -1
- package/assets/assets/{index-MbApCekj.js → index-BIhCeXvc.js} +4 -4
- package/assets/assets/{query-client-D-zMw63p.js → query-client-TlFXYJ9o.js} +1 -1
- package/assets/assets/{react-query-EdiRRB2q.js → react-query-C5Mv8xfD.js} +1 -1
- package/assets/assets/{react-sigma_core.esm.min-Bidr1Gxk.js → react-sigma_core.esm.min-DmggJ7YC.js} +1 -1
- package/assets/assets/{service-BUi8JgGI.js → service-CLFURPuM.js} +1 -1
- package/assets/index.html +7 -7
- package/dist/{ads-FFUUMS4J.js → ads-TX5622SS.js} +3 -3
- package/dist/{agent-LCD2VG7C.js → agent-AIOQL66U.js} +7 -7
- package/dist/{agent-ask-OBHTCYFR.js → agent-ask-A6GIJTBX.js} +3 -3
- package/dist/{agent-conversations-VMZ4NFIX.js → agent-conversations-LHWLKOPQ.js} +3 -3
- package/dist/{agent-memory-UPFJFNWC.js → agent-memory-F54BPEYN.js} +3 -3
- package/dist/{agent-providers-4GOWLBZK.js → agent-providers-L74KZOSG.js} +3 -3
- package/dist/{agent-transcript-RGXIVZUP.js → agent-transcript-IH65H755.js} +3 -3
- package/dist/{analytics-FBK4XV5P.js → analytics-YWCY2KSY.js} +3 -3
- package/dist/{apply-Y2DVE3YB.js → apply-BLUUYG2N.js} +3 -3
- package/dist/{backfill-NE55YL6X.js → backfill-6WO5CH6Z.js} +9 -9
- package/dist/{backlinks-YWHFC7DZ.js → backlinks-NC7AUGTK.js} +3 -3
- package/dist/{bing-7BP3DWPK.js → bing-WQUEYHVC.js} +3 -3
- package/dist/{bootstrap-Z7QSKVPL.js → bootstrap-AXZV4BBC.js} +10 -10
- package/dist/{cdp-OL6RENO3.js → cdp-DUG5PMUD.js} +7 -7
- package/dist/{chunk-J523Y7X2.js → chunk-2Y6MSB4J.js} +1 -1
- package/dist/{chunk-G7SGQUW4.js → chunk-3ANSG6YT.js} +345 -337
- package/dist/{chunk-GA2EHZTI.js → chunk-3WPTMLQI.js} +22 -6
- package/dist/{chunk-QDN3FL2A.js → chunk-3YIKSZHN.js} +2 -1
- package/dist/{chunk-H4HNXCDF.js → chunk-4B6DE7BB.js} +2 -2
- package/dist/{chunk-UWBJWKDQ.js → chunk-4JMTDLFV.js} +2 -2
- package/dist/{chunk-IY4AJ6DN.js → chunk-5PA7SJ2M.js} +5 -5
- package/dist/{chunk-JO73L677.js → chunk-6ATKY252.js} +2 -2
- package/dist/{chunk-XR6ZVMYK.js → chunk-6W5AR4IW.js} +1 -1
- package/dist/{chunk-IZMT4WLZ.js → chunk-6YW24AUN.js} +2 -2
- package/dist/{chunk-HZSE3WSG.js → chunk-AZQNJX3T.js} +2 -2
- package/dist/{chunk-CF6BUJRK.js → chunk-B6R223HQ.js} +8 -8
- package/dist/{chunk-6MYHGP46.js → chunk-DLVGMRM5.js} +1 -1
- package/dist/{chunk-P3UGNR2Y.js → chunk-ETVM3T7K.js} +5 -5
- package/dist/{chunk-IV6VZ63E.js → chunk-F5D4GPZQ.js} +18 -14
- package/dist/{chunk-NZLK3KHQ.js → chunk-GNBATQS3.js} +6 -6
- package/dist/{chunk-TEDY3MHN.js → chunk-GUFKUPKZ.js} +3 -3
- package/dist/{chunk-BADJCT6U.js → chunk-GWDMWKM6.js} +1 -1
- package/dist/{chunk-PPM6Z7CM.js → chunk-HEL6DKDN.js} +1 -1
- package/dist/{chunk-QKDKVPMR.js → chunk-HGMTGC34.js} +4 -4
- package/dist/{chunk-UZKNS5PL.js → chunk-HIGBV77K.js} +254 -92
- package/dist/{chunk-NZZWJCKS.js → chunk-HJHFW455.js} +3 -3
- package/dist/{chunk-JE5QURTR.js → chunk-HKV4UWG5.js} +1 -1
- package/dist/{chunk-DRGCVTYH.js → chunk-JPM3VC6A.js} +1 -1
- package/dist/{chunk-TOX6HAQJ.js → chunk-JQNVNB63.js} +3 -3
- package/dist/{chunk-3AG3LPZX.js → chunk-MRSNLKSM.js} +1 -1
- package/dist/{chunk-O7WOCTBD.js → chunk-PAIYFNNY.js} +71 -3
- package/dist/{chunk-MJYO6UK2.js → chunk-PRSQ4R47.js} +2 -2
- package/dist/{chunk-JEBY6MS6.js → chunk-QS6RIP37.js} +1 -1
- package/dist/{chunk-4LTL5RNY.js → chunk-S77W2XSI.js} +4 -4
- package/dist/{chunk-YXAKL5HM.js → chunk-SF5JLMLG.js} +6791 -6777
- package/dist/{chunk-Q25JQANW.js → chunk-T5PWWDMJ.js} +17 -2
- package/dist/{chunk-ATT3ZCSS.js → chunk-WH2M2MQF.js} +38 -16
- package/dist/{chunk-7KOAP47B.js → chunk-WLWOGBLJ.js} +363 -248
- package/dist/{chunk-BZZDFIY2.js → chunk-XDQJOZKJ.js} +1 -1
- package/dist/{citations-RVSC67GE.js → citations-FUZ6DGP5.js} +3 -3
- package/dist/{cli-catalog-NEZE5QU5.js → cli-catalog-BXHG544D.js} +3 -3
- package/dist/{cli-commands-ARJWPTFW.js → cli-commands-GMOR67F5.js} +7 -7
- package/dist/cli.js +13 -13
- package/dist/{competitor-BX3M3OYS.js → competitor-QDCH7PLT.js} +3 -3
- package/dist/{content-PKJMVMHJ.js → content-JX2CPIPR.js} +3 -3
- package/dist/{dashboard-SVHZBVM6.js → dashboard-OOWMLMKV.js} +6 -6
- package/dist/{demo-GLV22DPY.js → demo-GKSMSKOY.js} +1 -1
- package/dist/{demo-server-GPM4C4Q2.js → demo-server-UQO4XKHN.js} +12 -12
- package/dist/{discover-JDP44ZHX.js → discover-YQSVQRUV.js} +3 -3
- package/dist/{discover-eval-6ORCVYYR.js → discover-eval-FN5RL6QI.js} +3 -3
- package/dist/{doctor-TVZRMBSS.js → doctor-YHJLAEJJ.js} +3 -3
- package/dist/{evidence-FNIAFBBG.js → evidence-KUPZMBIK.js} +3 -3
- package/dist/{export-cmd-HQNF2SSD.js → export-cmd-YSEPTUUF.js} +3 -3
- package/dist/{ga-PIO5OXMK.js → ga-WNS7Q7TF.js} +3 -3
- package/dist/{gbp-3R5FME43.js → gbp-5NYFK4TW.js} +3 -3
- package/dist/{google-BYZREX2O.js → google-T4CF4WCI.js} +4 -4
- package/dist/{google-marketing-SPQ2GW6X.js → google-marketing-IXPMUBXZ.js} +1 -1
- package/dist/{health-cmd-HH5RYMSV.js → health-cmd-2W37CF6J.js} +3 -3
- package/dist/{history-Q35NLLMJ.js → history-PA3O6ZHX.js} +3 -3
- package/dist/index.d.ts +188 -11
- package/dist/index.js +25 -25
- package/dist/{init-Q33HEJJN.js → init-I3P7FINF.js} +12 -11
- package/dist/{insights-SH73B4PD.js → insights-O5PUVHTW.js} +3 -3
- package/dist/intelligence-service-EJQQNO65.js +16 -0
- package/dist/{journeys-SIV7HPW7.js → journeys-GU34O3HE.js} +3 -3
- package/dist/{keys-O656YWSW.js → keys-RXBFRNUS.js} +3 -3
- package/dist/{keyword-FZ2N4EW7.js → keyword-MASR36DK.js} +3 -3
- package/dist/{logs-2NPN7HBI.js → logs-OTA7MV4P.js} +3 -3
- package/dist/mcp-ZQYN2NET.js +19 -0
- package/dist/mcp.js +20 -14
- package/dist/{measurement-plan-JQKVSJRL.js → measurement-plan-ZGVO36TN.js} +5 -5
- package/dist/{notify-VTAYBHC6.js → notify-KS5CR3S2.js} +3 -3
- package/dist/{organic-evidence-HPXXEPOW.js → organic-evidence-CTH52AC5.js} +3 -3
- package/dist/{overview-FSBNDYZJ.js → overview-IRCIDE5H.js} +4 -4
- package/dist/{project-MAPPXURS.js → project-H5XPI5CT.js} +3 -3
- package/dist/{query-R6DLPIPJ.js → query-2R6EZG5T.js} +3 -3
- package/dist/{research-FXKOEUQB.js → research-OA3UQAV3.js} +3 -3
- package/dist/{results-export-X2PUM63S.js → results-export-XUXU3WMX.js} +3 -3
- package/dist/{run-6ENTG4IO.js → run-7IIOB6AS.js} +4 -4
- package/dist/{schedule-DMMVRT7P.js → schedule-DUTPZB5C.js} +3 -3
- package/dist/{search-FHI6APT7.js → search-TWUJD7KH.js} +3 -3
- package/dist/{serve-SJTQQQQE.js → serve-BYHHULUU.js} +26 -26
- package/dist/{session-VHCKM3AI.js → session-M5XSTGPI.js} +13 -13
- package/dist/{settings-FMB4QED4.js → settings-GQXU5M3H.js} +3 -3
- package/dist/{skills-HBIMHSOI.js → skills-F6AXQHTO.js} +2 -2
- package/dist/{snapshot-RBA2EL7R.js → snapshot-QFKUO4QK.js} +3 -3
- package/dist/{src-BXXGJOQB.js → src-52USCS7O.js} +4 -2
- package/dist/{status-ATFDFAVG.js → status-42LPR7YH.js} +4 -4
- package/dist/{technical-aeo-JWQTGCTB.js → technical-aeo-SUILL4MY.js} +3 -3
- package/dist/{telemetry-6QFGJL2I.js → telemetry-RITB7YZH.js} +4 -4
- package/dist/{tools-4VRHKUBE.js → tools-DGWJOLNS.js} +11 -11
- package/dist/{traffic-5R7M4CK5.js → traffic-3YC3HUNT.js} +5 -5
- package/dist/{users-24TIUYJY.js → users-BST5DQ5R.js} +3 -3
- package/dist/{visibility-stats-YLQPPBJJ.js → visibility-stats-NCNP4AL2.js} +3 -3
- package/dist/{wordpress-7VDPHMUZ.js → wordpress-4HQDLQVE.js} +3 -3
- package/package.json +10 -6
- package/assets/assets/ToneBadge-CmvL5mFG.js +0 -60
- package/dist/intelligence-service-LVRH4RJG.js +0 -16
- package/dist/mcp-RHQY3DV6.js +0 -14
|
@@ -9,14 +9,14 @@ import {
|
|
|
9
9
|
normalizeCloudflareWorkerEvent,
|
|
10
10
|
sessionizeJourneyRequests,
|
|
11
11
|
verifyRequestSignature
|
|
12
|
-
} from "./chunk-
|
|
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-
|
|
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-
|
|
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-
|
|
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 =
|
|
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
|
|
6382
|
-
const
|
|
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 (
|
|
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
|
|
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
|
|
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
|
-
|
|
8238
|
-
db.insert(oauthTokens).values({
|
|
8267
|
+
]) {
|
|
8268
|
+
tx.insert(oauthTokens).values({
|
|
8239
8269
|
tokenHash: sha256(row.token),
|
|
8240
8270
|
kind: row.kind,
|
|
8241
|
-
|
|
8242
|
-
|
|
8243
|
-
|
|
8244
|
-
|
|
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
|
-
//
|
|
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
|
|
8264
|
-
|
|
8265
|
-
|
|
8266
|
-
|
|
8267
|
-
|
|
8268
|
-
|
|
8269
|
-
|
|
8270
|
-
|
|
8271
|
-
|
|
8272
|
-
|
|
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
|
|
8277
|
-
const
|
|
8278
|
-
|
|
8279
|
-
|
|
8280
|
-
|
|
8281
|
-
|
|
8282
|
-
|
|
8283
|
-
|
|
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
|
-
|
|
8290
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
8333
|
-
|
|
8334
|
-
|
|
8335
|
-
|
|
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
|
|
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
|
|
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) :
|
|
10681
|
+
opts.exactVersion ? eq17(runs.measurementPlanVersionId, versionId) : inArray8(runs.measurementPlanVersionId, comparableMeasurementVersionIds(db, projectId, versionId)),
|
|
10583
10682
|
eq17(runs.kind, RunKinds["answer-visibility"]),
|
|
10584
|
-
|
|
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) :
|
|
10695
|
+
opts.exactVersion ? eq17(runs.measurementPlanVersionId, versionId) : inArray8(runs.measurementPlanVersionId, comparableMeasurementVersionIds(db, projectId, versionId)),
|
|
10597
10696
|
eq17(runs.kind, RunKinds["answer-visibility"]),
|
|
10598
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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"),
|
|
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
|
|
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),
|
|
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),
|
|
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
|
|
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
|
|
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),
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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
|
-
|
|
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(
|
|
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
|
|
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
|
|
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 ?
|
|
13718
|
-
latestRunIds ?
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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),
|
|
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
|
|
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
|
|
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
|
-
|
|
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),
|
|
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
|
-
|
|
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
|
|
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(
|
|
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 ?
|
|
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),
|
|
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),
|
|
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
|
|
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
|
-
|
|
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(
|
|
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
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
23179
|
+
inArray21(runs.measurementPlanVersionId, comparableMeasurementVersionIds(db, current.projectId, active.version.id)),
|
|
23081
23180
|
eq39(runs.kind, RunKinds["answer-visibility"]),
|
|
23082
|
-
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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
|
|
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"]),
|
|
27393
|
-
const activeResearch = tx.select({ id: researchRuns.id }).from(researchRuns).where(and36(eq45(researchRuns.projectId, project.id),
|
|
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),
|
|
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),
|
|
27398
|
-
const selectedResearch = tx.select({ id: researchRuns.id }).from(researchRuns).where(and36(eq45(researchRuns.projectId, project.id),
|
|
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(
|
|
27406
|
-
researchQueries: tx.select({ value: count2() }).from(researchRunQueries).where(
|
|
27407
|
-
insights: tx.select({ value: count2() }).from(insights).where(
|
|
27408
|
-
healthSnapshots: tx.select({ value: count2() }).from(healthSnapshots).where(
|
|
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),
|
|
27412
|
-
tx.delete(runs).where(and36(eq45(runs.projectId, project.id),
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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 ?
|
|
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(
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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]) :
|
|
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
|
|
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),
|
|
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),
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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),
|
|
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),
|
|
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(
|
|
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
|
|
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 ?
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
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
|
-
|
|
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(
|
|
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
|
|
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),
|
|
48760
|
-
const keywordRows = app.db.select().from(gbpKeywordImpressions).where(and54(eq66(gbpKeywordImpressions.projectId, project.id),
|
|
48761
|
-
const placeActionRows = app.db.select().from(gbpPlaceActions).where(and54(eq66(gbpPlaceActions.projectId, project.id),
|
|
48762
|
-
const lodgingRows = app.db.select().from(gbpLodgingSnapshots).where(and54(eq66(gbpLodgingSnapshots.projectId, project.id),
|
|
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),
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 ${
|
|
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
|
|
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"]),
|
|
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
|
|
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
|
-
|
|
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
|
|
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),
|
|
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
|
|
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(
|
|
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),
|
|
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
|
|
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,
|
|
68232
|
-
const lastSuccess = db.select({ createdAt: runs.createdAt, finishedAt: runs.finishedAt }).from(runs).where(and76(graded,
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
73087
|
-
|
|
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
|
-
|
|
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
|
-
|
|
73135
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
74231
|
+
inArray45(runs.status, SURFACEABLE_STATUSES),
|
|
74119
74232
|
notProbeRun(),
|
|
74120
|
-
|
|
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
|
-
|
|
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,
|