@canonry/canonry 7.72.2 → 7.74.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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-L64W5J35.js} +3 -3
- package/dist/{agent-LCD2VG7C.js → agent-CMQ34CFD.js} +7 -7
- package/dist/{agent-ask-OBHTCYFR.js → agent-ask-3KEYJSZV.js} +3 -3
- package/dist/{agent-conversations-VMZ4NFIX.js → agent-conversations-4KKPOTCP.js} +3 -3
- package/dist/{agent-memory-UPFJFNWC.js → agent-memory-VOSRZ57W.js} +3 -3
- package/dist/{agent-providers-4GOWLBZK.js → agent-providers-SLXTYMDS.js} +3 -3
- package/dist/{agent-transcript-RGXIVZUP.js → agent-transcript-Q6OEZROG.js} +3 -3
- package/dist/{analytics-FBK4XV5P.js → analytics-LSF6NYII.js} +3 -3
- package/dist/{apply-Y2DVE3YB.js → apply-7O3RES7N.js} +3 -3
- package/dist/{backfill-NE55YL6X.js → backfill-7ARSKYDG.js} +9 -9
- package/dist/{backlinks-YWHFC7DZ.js → backlinks-4YAC374B.js} +3 -3
- package/dist/{bing-7BP3DWPK.js → bing-SHAYDXAA.js} +3 -3
- package/dist/{bootstrap-Z7QSKVPL.js → bootstrap-BHLBGQKJ.js} +10 -10
- package/dist/{cdp-OL6RENO3.js → cdp-QWJE6SFY.js} +7 -7
- package/dist/{chunk-J523Y7X2.js → chunk-2Y6MSB4J.js} +1 -1
- package/dist/{chunk-GA2EHZTI.js → chunk-3WPTMLQI.js} +22 -6
- package/dist/{chunk-QDN3FL2A.js → chunk-3YIKSZHN.js} +2 -1
- 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-QKDKVPMR.js → chunk-AJMDETJA.js} +4 -4
- package/dist/{chunk-HZSE3WSG.js → chunk-AZQNJX3T.js} +2 -2
- package/dist/{chunk-ATT3ZCSS.js → chunk-BICUWFV4.js} +38 -16
- package/dist/{chunk-MJYO6UK2.js → chunk-DL3LTSBV.js} +2 -2
- package/dist/{chunk-6MYHGP46.js → chunk-DLVGMRM5.js} +1 -1
- package/dist/{chunk-TOX6HAQJ.js → chunk-EXGETCJR.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-NZZWJCKS.js → chunk-HJHFW455.js} +3 -3
- package/dist/{chunk-DRGCVTYH.js → chunk-JPM3VC6A.js} +1 -1
- package/dist/{chunk-H4HNXCDF.js → chunk-KOWOQ3JZ.js} +2 -2
- package/dist/{chunk-UWBJWKDQ.js → chunk-L5GIL45X.js} +2 -2
- package/dist/{chunk-P3UGNR2Y.js → chunk-LS47ZAX2.js} +5 -5
- package/dist/{chunk-IV6VZ63E.js → chunk-MB3IUJ6Z.js} +18 -14
- package/dist/{chunk-3AG3LPZX.js → chunk-MRSNLKSM.js} +1 -1
- package/dist/{chunk-JE5QURTR.js → chunk-NXFNXXYM.js} +184 -92
- package/dist/{chunk-Q25JQANW.js → chunk-O4D66XPL.js} +17 -2
- package/dist/{chunk-O7WOCTBD.js → chunk-PAIYFNNY.js} +71 -3
- package/dist/{chunk-JEBY6MS6.js → chunk-QS6RIP37.js} +1 -1
- package/dist/{chunk-4LTL5RNY.js → chunk-SCRPC2PQ.js} +4 -4
- package/dist/{chunk-YXAKL5HM.js → chunk-SF5JLMLG.js} +6791 -6777
- package/dist/{chunk-UZKNS5PL.js → chunk-TXUNPPWD.js} +254 -92
- package/dist/{chunk-NZLK3KHQ.js → chunk-WLNYLQTX.js} +6 -6
- package/dist/{chunk-7KOAP47B.js → chunk-WLWOGBLJ.js} +363 -248
- package/dist/{chunk-CF6BUJRK.js → chunk-WY2C6FFA.js} +8 -8
- package/dist/{chunk-BZZDFIY2.js → chunk-XDQJOZKJ.js} +1 -1
- package/dist/{chunk-TEDY3MHN.js → chunk-YTSE2EZP.js} +3 -3
- package/dist/{chunk-G7SGQUW4.js → chunk-ZMDIARSG.js} +345 -337
- package/dist/{citations-RVSC67GE.js → citations-EENLZULG.js} +3 -3
- package/dist/{cli-catalog-NEZE5QU5.js → cli-catalog-BXHG544D.js} +3 -3
- package/dist/{cli-commands-ARJWPTFW.js → cli-commands-7BG5M2KF.js} +7 -7
- package/dist/cli.js +13 -13
- package/dist/{competitor-BX3M3OYS.js → competitor-CW5LMXJ6.js} +3 -3
- package/dist/{content-PKJMVMHJ.js → content-BX6UGRRU.js} +3 -3
- package/dist/{dashboard-SVHZBVM6.js → dashboard-M2TKT2LW.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-2EZUZFNR.js} +3 -3
- package/dist/{discover-eval-6ORCVYYR.js → discover-eval-IS2GRYVV.js} +3 -3
- package/dist/{doctor-TVZRMBSS.js → doctor-DPEIBV3E.js} +3 -3
- package/dist/{evidence-FNIAFBBG.js → evidence-UGC4ZWNA.js} +3 -3
- package/dist/{export-cmd-HQNF2SSD.js → export-cmd-7OVM23C4.js} +3 -3
- package/dist/{ga-PIO5OXMK.js → ga-FUADE4K4.js} +3 -3
- package/dist/{gbp-3R5FME43.js → gbp-R4M663R5.js} +3 -3
- package/dist/{google-BYZREX2O.js → google-WTOTC5SL.js} +4 -4
- package/dist/{google-marketing-SPQ2GW6X.js → google-marketing-IXPMUBXZ.js} +1 -1
- package/dist/{health-cmd-HH5RYMSV.js → health-cmd-QKDO6VIT.js} +3 -3
- package/dist/{history-Q35NLLMJ.js → history-LEBTYXVW.js} +3 -3
- package/dist/index.d.ts +249 -72
- package/dist/index.js +25 -25
- package/dist/{init-Q33HEJJN.js → init-BKOT4UY2.js} +12 -11
- package/dist/{insights-SH73B4PD.js → insights-OBHQ5GHV.js} +3 -3
- package/dist/intelligence-service-EJQQNO65.js +16 -0
- package/dist/{journeys-SIV7HPW7.js → journeys-PTMCJHOL.js} +3 -3
- package/dist/{keys-O656YWSW.js → keys-W2FZNFOR.js} +3 -3
- package/dist/{keyword-FZ2N4EW7.js → keyword-Y6WABJPU.js} +3 -3
- package/dist/{logs-2NPN7HBI.js → logs-KRSH53GN.js} +3 -3
- package/dist/mcp-6LJW6LEJ.js +19 -0
- package/dist/mcp.js +20 -14
- package/dist/{measurement-plan-JQKVSJRL.js → measurement-plan-RHLKXNYG.js} +5 -5
- package/dist/{notify-VTAYBHC6.js → notify-HRK2HQTU.js} +3 -3
- package/dist/{organic-evidence-HPXXEPOW.js → organic-evidence-EX2VL5CE.js} +3 -3
- package/dist/{overview-FSBNDYZJ.js → overview-254QNXAC.js} +4 -4
- package/dist/{project-MAPPXURS.js → project-UOYX7T4J.js} +3 -3
- package/dist/{query-R6DLPIPJ.js → query-JMVOMNRS.js} +3 -3
- package/dist/{research-FXKOEUQB.js → research-PAPX7KO5.js} +3 -3
- package/dist/{results-export-X2PUM63S.js → results-export-3BXIIDP2.js} +3 -3
- package/dist/{run-6ENTG4IO.js → run-WQXLV4MS.js} +4 -4
- package/dist/{schedule-DMMVRT7P.js → schedule-3WJ5F3BF.js} +3 -3
- package/dist/{search-FHI6APT7.js → search-RVGFOZAT.js} +3 -3
- package/dist/{serve-SJTQQQQE.js → serve-BPM2P3GY.js} +26 -26
- package/dist/{session-VHCKM3AI.js → session-76DT5W6D.js} +13 -13
- package/dist/{settings-FMB4QED4.js → settings-MRJ566D6.js} +3 -3
- package/dist/{skills-HBIMHSOI.js → skills-F6AXQHTO.js} +2 -2
- package/dist/{snapshot-RBA2EL7R.js → snapshot-7GBDFFVB.js} +3 -3
- package/dist/{src-BXXGJOQB.js → src-52USCS7O.js} +4 -2
- package/dist/{status-ATFDFAVG.js → status-S6CZV2LU.js} +4 -4
- package/dist/{technical-aeo-JWQTGCTB.js → technical-aeo-Q73ZF2FD.js} +3 -3
- package/dist/{telemetry-6QFGJL2I.js → telemetry-BT4OOPN6.js} +4 -4
- package/dist/{tools-4VRHKUBE.js → tools-HYOV77FY.js} +11 -11
- package/dist/{traffic-5R7M4CK5.js → traffic-EFLF62IZ.js} +5 -5
- package/dist/{users-24TIUYJY.js → users-MYXGNUIZ.js} +3 -3
- package/dist/{visibility-stats-YLQPPBJJ.js → visibility-stats-QENASZW6.js} +3 -3
- package/dist/{wordpress-7VDPHMUZ.js → wordpress-CYLQHE5L.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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
answerServiceAdapters,
|
|
3
3
|
answerServiceDescriptors
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-6W5AR4IW.js";
|
|
5
5
|
import {
|
|
6
6
|
AeroLlmUsageFeatures,
|
|
7
7
|
aeroTurnStatus,
|
|
@@ -27,14 +27,14 @@ import {
|
|
|
27
27
|
resolveConfiguredAgentProvider,
|
|
28
28
|
resolveSessionProviderAndModel,
|
|
29
29
|
setAeroSystemPrompt
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-WLNYLQTX.js";
|
|
31
31
|
import {
|
|
32
32
|
AeroToolProfiles,
|
|
33
33
|
AeroToolScopes,
|
|
34
34
|
buildAeroStateTools,
|
|
35
35
|
isAeroToolProfile,
|
|
36
36
|
truncateToolResult
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-LS47ZAX2.js";
|
|
38
38
|
import {
|
|
39
39
|
getGoogleAuthConfig,
|
|
40
40
|
getGoogleConnection,
|
|
@@ -53,7 +53,7 @@ import {
|
|
|
53
53
|
removeCloudflareTrafficConnection,
|
|
54
54
|
removeCloudflareTrafficConnectionBySourceId,
|
|
55
55
|
upsertCloudflareTrafficConnection
|
|
56
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-XDQJOZKJ.js";
|
|
57
57
|
import {
|
|
58
58
|
claudeAdapter,
|
|
59
59
|
embedQueries,
|
|
@@ -64,7 +64,7 @@ import {
|
|
|
64
64
|
openaiAdapter,
|
|
65
65
|
openrouterAdapter,
|
|
66
66
|
perplexityAdapter
|
|
67
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-6ATKY252.js";
|
|
68
68
|
import {
|
|
69
69
|
classifyUsageSurface,
|
|
70
70
|
createApiUsageTelemetry,
|
|
@@ -76,7 +76,7 @@ import {
|
|
|
76
76
|
startOutcomeTimer,
|
|
77
77
|
trackFeatureCompleted,
|
|
78
78
|
trackInstallState
|
|
79
|
-
} from "./chunk-
|
|
79
|
+
} from "./chunk-SCRPC2PQ.js";
|
|
80
80
|
import {
|
|
81
81
|
isLoopbackBindHost
|
|
82
82
|
} from "./chunk-TSENU4GG.js";
|
|
@@ -84,7 +84,7 @@ import {
|
|
|
84
84
|
isApiProviderRegistrable,
|
|
85
85
|
isCdpProviderRegistrable,
|
|
86
86
|
registeredProviderNames
|
|
87
|
-
} from "./chunk-
|
|
87
|
+
} from "./chunk-DLVGMRM5.js";
|
|
88
88
|
import {
|
|
89
89
|
checkLatestVersionForServer,
|
|
90
90
|
getOrCreateAnonymousId,
|
|
@@ -95,17 +95,17 @@ import {
|
|
|
95
95
|
recordDashboardEvent,
|
|
96
96
|
setTelemetryPreference,
|
|
97
97
|
trackEvent
|
|
98
|
-
} from "./chunk-
|
|
98
|
+
} from "./chunk-DL3LTSBV.js";
|
|
99
99
|
import {
|
|
100
100
|
createCanonryMcpServer
|
|
101
|
-
} from "./chunk-
|
|
101
|
+
} from "./chunk-MB3IUJ6Z.js";
|
|
102
102
|
import {
|
|
103
103
|
CANONRY_MCP_TIERS,
|
|
104
104
|
CANONRY_MCP_TOOLKIT_NAMES
|
|
105
105
|
} from "./chunk-NDTU7FGL.js";
|
|
106
106
|
import {
|
|
107
107
|
ApiClient
|
|
108
|
-
} from "./chunk-
|
|
108
|
+
} from "./chunk-BICUWFV4.js";
|
|
109
109
|
import {
|
|
110
110
|
AGENT_PROVIDERS,
|
|
111
111
|
adapterSupportsBatch,
|
|
@@ -136,21 +136,21 @@ import {
|
|
|
136
136
|
saveConfigPatch,
|
|
137
137
|
sentimentInstallReadiness,
|
|
138
138
|
updateSharedProviderExecutionGate
|
|
139
|
-
} from "./chunk-
|
|
139
|
+
} from "./chunk-NXFNXXYM.js";
|
|
140
140
|
import {
|
|
141
141
|
getBundledSkillSnapshots
|
|
142
|
-
} from "./chunk-
|
|
142
|
+
} from "./chunk-HEL6DKDN.js";
|
|
143
143
|
import {
|
|
144
144
|
computeFactorAverages,
|
|
145
145
|
deleteSiteCrawlGraphLayout,
|
|
146
146
|
persistSiteCrawlGraphLayout,
|
|
147
147
|
prepareSiteCrawlGraphLayout,
|
|
148
148
|
recordedSharePct
|
|
149
|
-
} from "./chunk-
|
|
149
|
+
} from "./chunk-6YW24AUN.js";
|
|
150
150
|
import {
|
|
151
151
|
CanonryMcpToolNames,
|
|
152
152
|
canonryMcpTools
|
|
153
|
-
} from "./chunk-
|
|
153
|
+
} from "./chunk-3WPTMLQI.js";
|
|
154
154
|
import {
|
|
155
155
|
PACKAGE_VERSION
|
|
156
156
|
} from "./chunk-AOJU5LKX.js";
|
|
@@ -159,16 +159,16 @@ import {
|
|
|
159
159
|
} from "./chunk-HGMYEDAQ.js";
|
|
160
160
|
import {
|
|
161
161
|
IntelligenceService
|
|
162
|
-
} from "./chunk-
|
|
162
|
+
} from "./chunk-5PA7SJ2M.js";
|
|
163
163
|
import {
|
|
164
164
|
addLogListener,
|
|
165
165
|
createFastifyLogger,
|
|
166
166
|
createLogger
|
|
167
|
-
} from "./chunk-
|
|
167
|
+
} from "./chunk-AZQNJX3T.js";
|
|
168
168
|
import {
|
|
169
169
|
computeCitedCompetitorDomains,
|
|
170
170
|
determineCitationState
|
|
171
|
-
} from "./chunk-
|
|
171
|
+
} from "./chunk-JPM3VC6A.js";
|
|
172
172
|
import {
|
|
173
173
|
BingApiError,
|
|
174
174
|
CC_CACHE_DIR,
|
|
@@ -181,6 +181,7 @@ import {
|
|
|
181
181
|
GbpApiError,
|
|
182
182
|
GoogleApiError,
|
|
183
183
|
GoogleAuthError,
|
|
184
|
+
MCP_DELEGATED_KEY_MAX_AGE_MS,
|
|
184
185
|
PLUGIN_DIR,
|
|
185
186
|
SITE_REACHABILITY_CHECKS,
|
|
186
187
|
SITE_REACHABILITY_CHECK_ID,
|
|
@@ -288,7 +289,7 @@ import {
|
|
|
288
289
|
webhookResponseReason,
|
|
289
290
|
webhookTargetRefusalReason,
|
|
290
291
|
writeAuditLog
|
|
291
|
-
} from "./chunk-
|
|
292
|
+
} from "./chunk-WLWOGBLJ.js";
|
|
292
293
|
import {
|
|
293
294
|
OperationalLogStore,
|
|
294
295
|
SentimentIdempotencyConflict,
|
|
@@ -374,7 +375,7 @@ import {
|
|
|
374
375
|
siteLivenessState,
|
|
375
376
|
trafficSources,
|
|
376
377
|
usageCounters
|
|
377
|
-
} from "./chunk-
|
|
378
|
+
} from "./chunk-PAIYFNNY.js";
|
|
378
379
|
import {
|
|
379
380
|
AGENT_MEMORY_VALUE_MAX_BYTES,
|
|
380
381
|
AI_ENGINE_DOMAINS,
|
|
@@ -626,7 +627,7 @@ import {
|
|
|
626
627
|
winnabilityClassLabel,
|
|
627
628
|
withRetry,
|
|
628
629
|
withSkippedProviders
|
|
629
|
-
} from "./chunk-
|
|
630
|
+
} from "./chunk-SF5JLMLG.js";
|
|
630
631
|
|
|
631
632
|
// src/google-marketing-runtime.ts
|
|
632
633
|
import crypto2 from "crypto";
|
|
@@ -3316,7 +3317,7 @@ import path5 from "path";
|
|
|
3316
3317
|
import { isIP as isIP2 } from "net";
|
|
3317
3318
|
import { fileURLToPath } from "url";
|
|
3318
3319
|
import { setImmediate as yieldToEventLoop4 } from "timers/promises";
|
|
3319
|
-
import { and as
|
|
3320
|
+
import { and as and27, eq as eq33, isNotNull as isNotNull5, isNull as isNull8, lte as lte3, max, ne as ne4, or as or4, sql as sql13 } from "drizzle-orm";
|
|
3320
3321
|
|
|
3321
3322
|
// src/seo-runtime.ts
|
|
3322
3323
|
import { eq, inArray } from "drizzle-orm";
|
|
@@ -5809,7 +5810,7 @@ function nonBlank(value) {
|
|
|
5809
5810
|
return trimmed ? trimmed : void 0;
|
|
5810
5811
|
}
|
|
5811
5812
|
function resolveBuildCommit(env = process.env) {
|
|
5812
|
-
const embedded = true ? "
|
|
5813
|
+
const embedded = true ? "4bcaf7411fada38e4780290ce3ebccdea236a5c5" : void 0;
|
|
5813
5814
|
return nonBlank(embedded) ?? nonBlank(env.CANONRY_COMMIT);
|
|
5814
5815
|
}
|
|
5815
5816
|
function resolveInstanceIdentity(env = process.env) {
|
|
@@ -15638,8 +15639,7 @@ import { eq as eq27 } from "drizzle-orm";
|
|
|
15638
15639
|
|
|
15639
15640
|
// src/agent/remote-mcp.ts
|
|
15640
15641
|
import { Type } from "@earendil-works/pi-ai";
|
|
15641
|
-
import { Client } from "@modelcontextprotocol/
|
|
15642
|
-
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
15642
|
+
import { Client, StreamableHTTPClientTransport } from "@modelcontextprotocol/client";
|
|
15643
15643
|
var log24 = createLogger("RemoteMcp");
|
|
15644
15644
|
var AERO_EXCLUDED_MCP_TOOLS = /* @__PURE__ */ new Set([]);
|
|
15645
15645
|
async function connectStreamableHttp(server) {
|
|
@@ -15650,7 +15650,7 @@ async function connectStreamableHttp(server) {
|
|
|
15650
15650
|
});
|
|
15651
15651
|
const client = new Client(
|
|
15652
15652
|
{ name: "canonry-aero", version: "1.0.0" },
|
|
15653
|
-
{ capabilities: {} }
|
|
15653
|
+
{ capabilities: {}, versionNegotiation: { mode: "auto" } }
|
|
15654
15654
|
);
|
|
15655
15655
|
await client.connect(transport);
|
|
15656
15656
|
return client;
|
|
@@ -16971,12 +16971,15 @@ var ViewerAeroSessions = class {
|
|
|
16971
16971
|
// src/mcp-http.ts
|
|
16972
16972
|
import crypto25 from "crypto";
|
|
16973
16973
|
import { isIP } from "net";
|
|
16974
|
-
import { eq as eq29 } from "drizzle-orm";
|
|
16975
|
-
import {
|
|
16976
|
-
import { isInitializeRequest } from "@modelcontextprotocol/
|
|
16974
|
+
import { and as and24, eq as eq29, isNull as isNull6 } from "drizzle-orm";
|
|
16975
|
+
import { NodeStreamableHTTPServerTransport, toNodeHandler, toWebRequest } from "@modelcontextprotocol/node";
|
|
16976
|
+
import { McpServer, createMcpHandler, isInitializeRequest, isLegacyRequest } from "@modelcontextprotocol/server";
|
|
16977
16977
|
var SESSION_IDLE_MS = 10 * 60 * 1e3;
|
|
16978
16978
|
var SWEEP_INTERVAL_MS = 60 * 1e3;
|
|
16979
|
-
|
|
16979
|
+
var MAX_CLEANUP_RETRIES_PER_SWEEP = 8;
|
|
16980
|
+
var MAX_PENDING_KEY_RETIREMENTS = 256;
|
|
16981
|
+
var MAX_CLEANUP_BACKOFF_MS = 10 * 60 * 1e3;
|
|
16982
|
+
function mintSessionKey(db, scopes, userId, oauthGrantId, createdAt) {
|
|
16980
16983
|
const raw = `cnry_${crypto25.randomBytes(24).toString("hex")}`;
|
|
16981
16984
|
const id = crypto25.randomUUID();
|
|
16982
16985
|
db.insert(apiKeys).values({
|
|
@@ -16986,18 +16989,10 @@ function mintSessionKey(db, scopes, userId) {
|
|
|
16986
16989
|
keyPrefix: raw.slice(0, 9),
|
|
16987
16990
|
scopes: [...scopes],
|
|
16988
16991
|
delegatedUserId: userId,
|
|
16989
|
-
|
|
16992
|
+
delegatedOAuthGrantId: oauthGrantId,
|
|
16993
|
+
createdAt: new Date(createdAt).toISOString()
|
|
16990
16994
|
}).run();
|
|
16991
|
-
return { id, raw };
|
|
16992
|
-
}
|
|
16993
|
-
function revokeSessionKey(db, id) {
|
|
16994
|
-
try {
|
|
16995
|
-
db.transaction((tx) => {
|
|
16996
|
-
tx.delete(dashboardSessions).where(eq29(dashboardSessions.apiKeyId, id)).run();
|
|
16997
|
-
tx.update(apiKeys).set({ revokedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(eq29(apiKeys.id, id)).run();
|
|
16998
|
-
});
|
|
16999
|
-
} catch {
|
|
17000
|
-
}
|
|
16995
|
+
return { id, raw, expiresAt: createdAt + MCP_DELEGATED_KEY_MAX_AGE_MS };
|
|
17001
16996
|
}
|
|
17002
16997
|
function mcpTransportPaths() {
|
|
17003
16998
|
const paths = ["/mcp", "/mcp/readonly"];
|
|
@@ -17052,18 +17047,95 @@ function mcpHttpHealth(app, apiPrefix, hosted) {
|
|
|
17052
17047
|
}
|
|
17053
17048
|
function registerMcpHttpRoutes(scope, opts) {
|
|
17054
17049
|
const sessions = /* @__PURE__ */ new Map();
|
|
17050
|
+
const legacyServers = /* @__PURE__ */ new Set();
|
|
17051
|
+
const modernExchanges = /* @__PURE__ */ new Set();
|
|
17055
17052
|
const now = opts.now ?? (() => Date.now());
|
|
17053
|
+
const pendingKeyRetirements = /* @__PURE__ */ new Map();
|
|
17054
|
+
let shuttingDown = false;
|
|
17055
|
+
function withoutLockWait(work) {
|
|
17056
|
+
const timeout = opts.db.$client.pragma("busy_timeout", { simple: true });
|
|
17057
|
+
try {
|
|
17058
|
+
opts.db.$client.pragma("busy_timeout = 0");
|
|
17059
|
+
return work();
|
|
17060
|
+
} finally {
|
|
17061
|
+
opts.db.$client.pragma(`busy_timeout = ${timeout}`);
|
|
17062
|
+
}
|
|
17063
|
+
}
|
|
17064
|
+
function attemptKeyRetirement(id, remove) {
|
|
17065
|
+
try {
|
|
17066
|
+
withoutLockWait(() => {
|
|
17067
|
+
opts.db.transaction((tx) => {
|
|
17068
|
+
tx.delete(dashboardSessions).where(eq29(dashboardSessions.apiKeyId, id)).run();
|
|
17069
|
+
tx.update(apiKeys).set({ revokedAt: new Date(now()).toISOString() }).where(and24(eq29(apiKeys.id, id), isNull6(apiKeys.revokedAt))).run();
|
|
17070
|
+
});
|
|
17071
|
+
if (remove) {
|
|
17072
|
+
try {
|
|
17073
|
+
opts.db.delete(apiKeys).where(eq29(apiKeys.id, id)).run();
|
|
17074
|
+
} catch (error) {
|
|
17075
|
+
scope.log.warn({ err: error, keyId: id }, "Retained revoked MCP request key after deletion failed");
|
|
17076
|
+
}
|
|
17077
|
+
}
|
|
17078
|
+
});
|
|
17079
|
+
return true;
|
|
17080
|
+
} catch (error) {
|
|
17081
|
+
scope.log.error({ err: error, keyId: id }, "Failed to retire MCP key; cleanup remains bounded by its expiry");
|
|
17082
|
+
return false;
|
|
17083
|
+
}
|
|
17084
|
+
}
|
|
17085
|
+
function retireSessionKey(key, remove = false) {
|
|
17086
|
+
const queued = pendingKeyRetirements.get(key.id);
|
|
17087
|
+
if (queued) {
|
|
17088
|
+
queued.remove ||= remove;
|
|
17089
|
+
return;
|
|
17090
|
+
}
|
|
17091
|
+
if (attemptKeyRetirement(key.id, remove)) return;
|
|
17092
|
+
if (pendingKeyRetirements.size >= MAX_PENDING_KEY_RETIREMENTS) {
|
|
17093
|
+
const oldest = pendingKeyRetirements.keys().next().value;
|
|
17094
|
+
if (oldest !== void 0) pendingKeyRetirements.delete(oldest);
|
|
17095
|
+
scope.log.warn("MCP cleanup queue is full; oldest credential remains bounded by its expiry");
|
|
17096
|
+
}
|
|
17097
|
+
pendingKeyRetirements.set(key.id, { remove, expiresAt: key.expiresAt, nextAttemptAt: now() + SWEEP_INTERVAL_MS, attempts: 1 });
|
|
17098
|
+
}
|
|
17099
|
+
function retryKeyRetirements() {
|
|
17100
|
+
let attempted = 0;
|
|
17101
|
+
for (const [id, queued] of pendingKeyRetirements) {
|
|
17102
|
+
if (queued.expiresAt <= now()) {
|
|
17103
|
+
pendingKeyRetirements.delete(id);
|
|
17104
|
+
continue;
|
|
17105
|
+
}
|
|
17106
|
+
if (queued.nextAttemptAt > now()) continue;
|
|
17107
|
+
if (attempted++ >= MAX_CLEANUP_RETRIES_PER_SWEEP) break;
|
|
17108
|
+
if (attemptKeyRetirement(id, queued.remove)) pendingKeyRetirements.delete(id);
|
|
17109
|
+
else {
|
|
17110
|
+
queued.nextAttemptAt = now() + Math.min(SWEEP_INTERVAL_MS * 2 ** queued.attempts, MAX_CLEANUP_BACKOFF_MS);
|
|
17111
|
+
queued.attempts++;
|
|
17112
|
+
}
|
|
17113
|
+
}
|
|
17114
|
+
}
|
|
17056
17115
|
async function dropSession(id) {
|
|
17057
|
-
|
|
17058
|
-
if (!session) return;
|
|
17059
|
-
sessions.delete(id);
|
|
17060
|
-
await session.close().catch(() => {
|
|
17061
|
-
});
|
|
17116
|
+
await sessions.get(id)?.close().catch((error) => scope.log.error({ err: error }, "Failed to close legacy MCP session"));
|
|
17062
17117
|
}
|
|
17063
17118
|
const sweep = setInterval(() => {
|
|
17064
|
-
|
|
17065
|
-
|
|
17066
|
-
|
|
17119
|
+
try {
|
|
17120
|
+
retryKeyRetirements();
|
|
17121
|
+
withoutLockWait(() => {
|
|
17122
|
+
const cutoff = now() - SESSION_IDLE_MS;
|
|
17123
|
+
for (const session of legacyServers) {
|
|
17124
|
+
const key = session.sessionKeyId ? opts.db.select({ revokedAt: apiKeys.revokedAt }).from(apiKeys).where(eq29(apiKeys.id, session.sessionKeyId)).get() : void 0;
|
|
17125
|
+
if (session.lastSeenAt < cutoff || session.expiresAt !== void 0 && session.expiresAt <= now() || session.sessionKeyId && (!key || key.revokedAt)) {
|
|
17126
|
+
void session.close().catch((error) => scope.log.error({ err: error }, "Failed to close expired MCP session"));
|
|
17127
|
+
}
|
|
17128
|
+
}
|
|
17129
|
+
for (const exchange of modernExchanges) {
|
|
17130
|
+
if (!exchange.sessionKey) continue;
|
|
17131
|
+
const key = opts.db.select({ revokedAt: apiKeys.revokedAt }).from(apiKeys).where(eq29(apiKeys.id, exchange.sessionKey.id)).get();
|
|
17132
|
+
if (!key || key.revokedAt || exchange.sessionKey.expiresAt <= now()) {
|
|
17133
|
+
void exchange.close().catch((error) => scope.log.error({ err: error }, "Failed to close expired MCP request"));
|
|
17134
|
+
}
|
|
17135
|
+
}
|
|
17136
|
+
});
|
|
17137
|
+
} catch (error) {
|
|
17138
|
+
scope.log.error({ err: error }, "MCP lifecycle sweep failed; will retry on the next interval");
|
|
17067
17139
|
}
|
|
17068
17140
|
}, SWEEP_INTERVAL_MS);
|
|
17069
17141
|
sweep.unref();
|
|
@@ -17077,9 +17149,15 @@ function registerMcpHttpRoutes(scope, opts) {
|
|
|
17077
17149
|
return payload;
|
|
17078
17150
|
});
|
|
17079
17151
|
}
|
|
17080
|
-
scope.addHook("
|
|
17152
|
+
scope.addHook("preClose", async () => {
|
|
17153
|
+
shuttingDown = true;
|
|
17081
17154
|
clearInterval(sweep);
|
|
17082
|
-
await Promise.all([...
|
|
17155
|
+
await Promise.all([...legacyServers].map((session) => session.close().catch((error) => scope.log.error({ err: error }, "Failed to close MCP session during shutdown"))));
|
|
17156
|
+
await Promise.all([...modernExchanges].map((exchange) => exchange.close().catch((error) => scope.log.error({ err: error }, "Failed to close MCP request during shutdown"))));
|
|
17157
|
+
retryKeyRetirements();
|
|
17158
|
+
if (pendingKeyRetirements.size > 0) {
|
|
17159
|
+
scope.log.warn({ count: pendingKeyRetirements.size }, "MCP credential cleanup remains pending at shutdown; credentials remain bounded by expiry");
|
|
17160
|
+
}
|
|
17083
17161
|
});
|
|
17084
17162
|
function callerBearer(request) {
|
|
17085
17163
|
const header = request.headers.authorization;
|
|
@@ -17090,53 +17168,74 @@ function registerMcpHttpRoutes(scope, opts) {
|
|
|
17090
17168
|
if (trimmed.slice(0, prefix.length).toLowerCase() !== prefix) return null;
|
|
17091
17169
|
return trimmed.slice(prefix.length).trim() || null;
|
|
17092
17170
|
}
|
|
17093
|
-
|
|
17094
|
-
|
|
17095
|
-
if (!bearer) return null;
|
|
17171
|
+
function createAuthorizedServer(request, segment, bearer, signal, modern = false, needsApiCredential = true) {
|
|
17172
|
+
if (shuttingDown) throw new Error("MCP server is shutting down");
|
|
17096
17173
|
const scopes = request.principal?.scopes ?? request.apiKey?.scopes ?? [];
|
|
17097
17174
|
let sessionKey = null;
|
|
17098
|
-
if (!request.apiKey && request.principal?.kind === "user") {
|
|
17099
|
-
|
|
17175
|
+
if (needsApiCredential && !request.apiKey && request.principal?.kind === "user") {
|
|
17176
|
+
if (!request.principal.oauthGrantId) throw forbidden("MCP OAuth credentials require an active authorization grant.");
|
|
17177
|
+
sessionKey = mintSessionKey(opts.db, segment.readOnly ? ["read"] : scopes, request.principal.id, request.principal.oauthGrantId, now());
|
|
17100
17178
|
}
|
|
17101
17179
|
const client = new ApiClient(opts.selfApiUrl, sessionKey?.raw ?? bearer, {
|
|
17102
17180
|
skipProbe: true,
|
|
17181
|
+
storedOnly: segment.readOnly,
|
|
17182
|
+
signal,
|
|
17103
17183
|
clientName: `canonry-mcp/${PACKAGE_VERSION}`,
|
|
17104
17184
|
surface: "mcp-http",
|
|
17105
17185
|
// Correlation only: this is never accepted as caller identity or authority.
|
|
17106
|
-
actorSession: crypto25.randomUUID()
|
|
17186
|
+
...modern ? {} : { actorSession: crypto25.randomUUID() }
|
|
17107
17187
|
});
|
|
17108
17188
|
let server;
|
|
17109
17189
|
try {
|
|
17110
17190
|
server = createCanonryMcpServer({
|
|
17111
|
-
scope: segment.readOnly
|
|
17191
|
+
scope: segment.readOnly ? "stored-only" : isReadOnlyKey(scopes) ? "read-only" : "all",
|
|
17112
17192
|
credentialScopes: scopes,
|
|
17113
17193
|
operator: request.operatorAccess === true,
|
|
17194
|
+
connectionProfile: Boolean(opts.issuer && !request.principal?.projectId && (request.principal?.kind === "user" || request.principal?.delegatedUser) && scopes.some((scope2) => scope2 === "read" || scope2 === "*")),
|
|
17114
17195
|
tiers: segment.tiers,
|
|
17115
17196
|
clientFactory: () => client,
|
|
17116
17197
|
updateAvailable: opts.getUpdateAvailable
|
|
17117
17198
|
});
|
|
17199
|
+
server.server.registerCapabilities({ tools: { listChanged: false }, resources: { listChanged: false, subscribe: false } });
|
|
17118
17200
|
} catch (error) {
|
|
17119
|
-
if (sessionKey)
|
|
17201
|
+
if (sessionKey) retireSessionKey(sessionKey, modern);
|
|
17120
17202
|
throw error;
|
|
17121
17203
|
}
|
|
17122
|
-
|
|
17204
|
+
return { server, sessionKey };
|
|
17205
|
+
}
|
|
17206
|
+
async function openSession(request, authorizationId, segment) {
|
|
17207
|
+
const bearer = callerBearer(request);
|
|
17208
|
+
if (!bearer) return null;
|
|
17209
|
+
const { server, sessionKey } = createAuthorizedServer(request, segment, bearer);
|
|
17210
|
+
const transport = new NodeStreamableHTTPServerTransport({
|
|
17123
17211
|
sessionIdGenerator: () => crypto25.randomUUID(),
|
|
17124
17212
|
onsessioninitialized: (id) => {
|
|
17125
|
-
|
|
17213
|
+
if (!shuttingDown && !closing) sessions.set(id, session);
|
|
17126
17214
|
}
|
|
17127
17215
|
});
|
|
17128
|
-
|
|
17129
|
-
|
|
17130
|
-
|
|
17131
|
-
|
|
17132
|
-
|
|
17133
|
-
|
|
17134
|
-
|
|
17216
|
+
let closing;
|
|
17217
|
+
const session = { transport, close, authorizationId, segmentId: segment.id, sessionKeyId: sessionKey?.id, expiresAt: sessionKey?.expiresAt, lastSeenAt: now() };
|
|
17218
|
+
legacyServers.add(session);
|
|
17219
|
+
function close() {
|
|
17220
|
+
if (closing) return closing;
|
|
17221
|
+
closing = Promise.resolve().then(async () => {
|
|
17222
|
+
if (sessionKey) retireSessionKey(sessionKey);
|
|
17223
|
+
const id = transport.sessionId;
|
|
17224
|
+
if (id) sessions.delete(id);
|
|
17225
|
+
try {
|
|
17226
|
+
await transport.close();
|
|
17227
|
+
} finally {
|
|
17228
|
+
try {
|
|
17229
|
+
await server.close();
|
|
17230
|
+
} finally {
|
|
17231
|
+
legacyServers.delete(session);
|
|
17232
|
+
}
|
|
17233
|
+
}
|
|
17234
|
+
});
|
|
17235
|
+
return closing;
|
|
17135
17236
|
}
|
|
17136
17237
|
transport.onclose = () => {
|
|
17137
|
-
|
|
17138
|
-
if (id) sessions.delete(id);
|
|
17139
|
-
if (sessionKey) revokeSessionKey(opts.db, sessionKey.id);
|
|
17238
|
+
void close().catch((error) => scope.log.error({ err: error }, "Failed to close legacy MCP transport"));
|
|
17140
17239
|
};
|
|
17141
17240
|
try {
|
|
17142
17241
|
await server.connect(transport);
|
|
@@ -17145,15 +17244,68 @@ function registerMcpHttpRoutes(scope, opts) {
|
|
|
17145
17244
|
});
|
|
17146
17245
|
throw error;
|
|
17147
17246
|
}
|
|
17148
|
-
return
|
|
17247
|
+
return session;
|
|
17248
|
+
}
|
|
17249
|
+
async function handleModern(request, reply, segment, bearer) {
|
|
17250
|
+
const abort = new AbortController();
|
|
17251
|
+
let closing;
|
|
17252
|
+
const exchange = {
|
|
17253
|
+
close: () => {
|
|
17254
|
+
if (closing) return closing;
|
|
17255
|
+
abort.abort();
|
|
17256
|
+
if (exchange.sessionKey) retireSessionKey(exchange.sessionKey, true);
|
|
17257
|
+
modernExchanges.delete(exchange);
|
|
17258
|
+
closing = handler.close().catch((error) => {
|
|
17259
|
+
scope.log.error({ err: error }, "Failed to close MCP request transport");
|
|
17260
|
+
throw error;
|
|
17261
|
+
});
|
|
17262
|
+
return closing;
|
|
17263
|
+
}
|
|
17264
|
+
};
|
|
17265
|
+
const reportError = (error) => scope.log.error({ err: error }, "Modern MCP request failed");
|
|
17266
|
+
const handler = createMcpHandler(({ requestInfo }) => {
|
|
17267
|
+
if (shuttingDown) throw new Error("MCP server is shutting down");
|
|
17268
|
+
const body = request.body;
|
|
17269
|
+
const method = body && typeof body === "object" ? body.method : void 0;
|
|
17270
|
+
if (method === "subscriptions/listen") {
|
|
17271
|
+
return new McpServer({ name: "canonry", version: PACKAGE_VERSION });
|
|
17272
|
+
}
|
|
17273
|
+
const signal = requestInfo ? AbortSignal.any([abort.signal, requestInfo.signal]) : abort.signal;
|
|
17274
|
+
const opened = createAuthorizedServer(request, segment, bearer, signal, true, method === "tools/call");
|
|
17275
|
+
exchange.sessionKey = opened.sessionKey ?? void 0;
|
|
17276
|
+
return opened.server;
|
|
17277
|
+
}, { legacy: "reject", onerror: reportError });
|
|
17278
|
+
modernExchanges.add(exchange);
|
|
17279
|
+
try {
|
|
17280
|
+
await toNodeHandler(handler, { onerror: reportError })(request.raw, reply.raw, request.body);
|
|
17281
|
+
} finally {
|
|
17282
|
+
await exchange.close();
|
|
17283
|
+
}
|
|
17149
17284
|
}
|
|
17150
17285
|
async function handle(request, reply, segment) {
|
|
17286
|
+
if (shuttingDown) {
|
|
17287
|
+
await reply.status(503).send({ jsonrpc: "2.0", id: null, error: { code: -32e3, message: "MCP server is shutting down." } });
|
|
17288
|
+
return;
|
|
17289
|
+
}
|
|
17151
17290
|
const principal = request.principal ?? request.apiKey;
|
|
17152
17291
|
const bearer = callerBearer(request);
|
|
17153
17292
|
if (!principal || !bearer) {
|
|
17154
17293
|
await reply.status(401).send({ error: { code: "AUTH_REQUIRED", message: "Authentication required." } });
|
|
17155
17294
|
return;
|
|
17156
17295
|
}
|
|
17296
|
+
if (segment.readOnly && !request.apiKey && request.principal?.kind === "user" && !principal.scopes.some((scope2) => scope2 === "read" || scope2 === "*")) {
|
|
17297
|
+
throw forbidden('The hosted read-only MCP endpoint requires the "read" scope.');
|
|
17298
|
+
}
|
|
17299
|
+
const webRequest = await toWebRequest(request.raw, request.body);
|
|
17300
|
+
const legacy = await isLegacyRequest(webRequest, request.body);
|
|
17301
|
+
if (shuttingDown) {
|
|
17302
|
+
await reply.status(503).send({ jsonrpc: "2.0", id: null, error: { code: -32e3, message: "MCP server is shutting down." } });
|
|
17303
|
+
return;
|
|
17304
|
+
}
|
|
17305
|
+
if (!legacy) {
|
|
17306
|
+
await handleModern(request, reply, segment, bearer);
|
|
17307
|
+
return;
|
|
17308
|
+
}
|
|
17157
17309
|
const authorizationId = hashApiKey(JSON.stringify({
|
|
17158
17310
|
bearerHash: hashApiKey(bearer),
|
|
17159
17311
|
kind: request.principal?.kind ?? "api-key",
|
|
@@ -17165,6 +17317,11 @@ function registerMcpHttpRoutes(scope, opts) {
|
|
|
17165
17317
|
const sessionId = request.headers["mcp-session-id"];
|
|
17166
17318
|
const existing = typeof sessionId === "string" ? sessions.get(sessionId) : void 0;
|
|
17167
17319
|
if (existing) {
|
|
17320
|
+
if (existing.expiresAt !== void 0 && existing.expiresAt <= now() && typeof sessionId === "string") {
|
|
17321
|
+
await dropSession(sessionId);
|
|
17322
|
+
await reply.status(404).send({ error: { code: "NOT_FOUND", message: "Unknown MCP session." } });
|
|
17323
|
+
return;
|
|
17324
|
+
}
|
|
17168
17325
|
if (existing.authorizationId !== authorizationId || existing.segmentId !== segment.id) {
|
|
17169
17326
|
await reply.status(404).send({ error: { code: "NOT_FOUND", message: "Unknown MCP session." } });
|
|
17170
17327
|
return;
|
|
@@ -17186,6 +17343,11 @@ function registerMcpHttpRoutes(scope, opts) {
|
|
|
17186
17343
|
await reply.status(401).send({ error: { code: "AUTH_REQUIRED", message: "Authentication required." } });
|
|
17187
17344
|
return;
|
|
17188
17345
|
}
|
|
17346
|
+
if (shuttingDown) {
|
|
17347
|
+
await opened.close();
|
|
17348
|
+
await reply.status(503).send({ jsonrpc: "2.0", id: null, error: { code: -32e3, message: "MCP server is shutting down." } });
|
|
17349
|
+
return;
|
|
17350
|
+
}
|
|
17189
17351
|
let handled = false;
|
|
17190
17352
|
try {
|
|
17191
17353
|
await opened.transport.handleRequest(request.raw, reply.raw, request.body);
|
|
@@ -18401,7 +18563,7 @@ function clipText(value, length) {
|
|
|
18401
18563
|
}
|
|
18402
18564
|
|
|
18403
18565
|
// src/research-runner.ts
|
|
18404
|
-
import { and as
|
|
18566
|
+
import { and as and25, eq as eq31, inArray as inArray13, sql as sql11 } from "drizzle-orm";
|
|
18405
18567
|
var unfinishedResearchQueryStatuses = [ResearchQueryStatuses.queued, ResearchQueryStatuses.running];
|
|
18406
18568
|
function finalResearchRunStatus(completed, failed, waiting) {
|
|
18407
18569
|
if (waiting > 0) return ResearchRunStatuses["waiting-upstream"];
|
|
@@ -18409,13 +18571,13 @@ function finalResearchRunStatus(completed, failed, waiting) {
|
|
|
18409
18571
|
return completed > 0 ? ResearchRunStatuses.partial : ResearchRunStatuses.failed;
|
|
18410
18572
|
}
|
|
18411
18573
|
async function executeResearchRun(db, registry, runId, projectId, options = {}) {
|
|
18412
|
-
const run = db.select().from(researchRuns).where(
|
|
18574
|
+
const run = db.select().from(researchRuns).where(and25(eq31(researchRuns.id, runId), eq31(researchRuns.projectId, projectId))).get();
|
|
18413
18575
|
if (!run || run.status !== ResearchRunStatuses.queued) return;
|
|
18414
18576
|
const project = db.select().from(projects).where(eq31(projects.id, projectId)).get();
|
|
18415
18577
|
if (!project) return;
|
|
18416
18578
|
const provider = registry.get(run.provider);
|
|
18417
18579
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
18418
|
-
const claim = db.update(researchRuns).set({ status: ResearchRunStatuses.running, startedAt: now }).where(
|
|
18580
|
+
const claim = db.update(researchRuns).set({ status: ResearchRunStatuses.running, startedAt: now }).where(and25(eq31(researchRuns.id, runId), eq31(researchRuns.status, ResearchRunStatuses.queued))).run();
|
|
18419
18581
|
if (claim.changes !== 1) return;
|
|
18420
18582
|
const elapsed = startOutcomeTimer();
|
|
18421
18583
|
const requested = currentOutcomeOrigin();
|
|
@@ -18460,7 +18622,7 @@ async function executeResearchRun(db, registry, runId, projectId, options = {})
|
|
|
18460
18622
|
await mapWithConcurrency(rows, Math.max(1, provider.config.quotaPolicy.maxConcurrency), async (row) => {
|
|
18461
18623
|
try {
|
|
18462
18624
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
18463
|
-
db.update(researchRunQueries).set({ status: ResearchQueryStatuses.running, startedAt }).where(
|
|
18625
|
+
db.update(researchRunQueries).set({ status: ResearchQueryStatuses.running, startedAt }).where(and25(eq31(researchRunQueries.id, row.id), eq31(researchRunQueries.status, ResearchQueryStatuses.queued))).run();
|
|
18464
18626
|
const raw = await gate.run(async () => {
|
|
18465
18627
|
dispatched++;
|
|
18466
18628
|
return provider.adapter.executeTrackedQuery({ query: row.queryText, canonicalDomains: domains, competitorDomains, ...run.location ? { location: run.location } : {} }, config);
|
|
@@ -18491,7 +18653,7 @@ async function executeResearchRun(db, registry, runId, projectId, options = {})
|
|
|
18491
18653
|
rawResponse: raw.rawResponse,
|
|
18492
18654
|
answerEvidence: raw.evidence ?? null,
|
|
18493
18655
|
finishedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
18494
|
-
}).where(
|
|
18656
|
+
}).where(and25(eq31(researchRunQueries.id, row.id), eq31(researchRunQueries.status, ResearchQueryStatuses.running))).run();
|
|
18495
18657
|
if (completed.changes === 1) incrementResearchProgress(db, runId, "completedQueries");
|
|
18496
18658
|
} catch (error) {
|
|
18497
18659
|
if (!(error instanceof IncompleteAnswerError && error.resumable)) queryFailure ??= error;
|
|
@@ -18546,7 +18708,7 @@ function incrementResearchProgress(db, runId, column) {
|
|
|
18546
18708
|
}
|
|
18547
18709
|
function markResearchQueryFailed(db, runId, queryId, error) {
|
|
18548
18710
|
const message = describeError(error);
|
|
18549
|
-
const unfinished =
|
|
18711
|
+
const unfinished = and25(eq31(researchRunQueries.id, queryId), inArray13(researchRunQueries.status, unfinishedResearchQueryStatuses));
|
|
18550
18712
|
if (error instanceof IncompleteAnswerError && error.resumable) {
|
|
18551
18713
|
db.update(researchRunQueries).set({
|
|
18552
18714
|
status: ResearchQueryStatuses["waiting-upstream"],
|
|
@@ -18562,7 +18724,7 @@ function markResearchQueryFailed(db, runId, queryId, error) {
|
|
|
18562
18724
|
if (failed.changes === 1) incrementResearchProgress(db, runId, "failedQueries");
|
|
18563
18725
|
}
|
|
18564
18726
|
function markUnfinishedResearchQueriesFailed(db, runId, error) {
|
|
18565
|
-
db.update(researchRunQueries).set({ status: ResearchQueryStatuses.failed, error, finishedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(
|
|
18727
|
+
db.update(researchRunQueries).set({ status: ResearchQueryStatuses.failed, error, finishedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(and25(eq31(researchRunQueries.researchRunId, runId), inArray13(researchRunQueries.status, unfinishedResearchQueryStatuses))).run();
|
|
18566
18728
|
}
|
|
18567
18729
|
function finalizeResearchRun(db, runId, fatalError) {
|
|
18568
18730
|
const rows = db.select({ status: researchRunQueries.status }).from(researchRunQueries).where(eq31(researchRunQueries.researchRunId, runId)).all();
|
|
@@ -18582,7 +18744,7 @@ function finalizeResearchRun(db, runId, fatalError) {
|
|
|
18582
18744
|
}
|
|
18583
18745
|
|
|
18584
18746
|
// src/google-marketing-sync.ts
|
|
18585
|
-
import { and as
|
|
18747
|
+
import { and as and26, eq as eq32, isNull as isNull7, sql as sql12 } from "drizzle-orm";
|
|
18586
18748
|
var RUNTIME_FAILURE_REASONS = {
|
|
18587
18749
|
INVALID_INPUT: OutcomeReasonCodes.VALIDATION,
|
|
18588
18750
|
NOT_CONFIGURED: OutcomeReasonCodes.NOT_CONNECTED,
|
|
@@ -18619,7 +18781,7 @@ function assertSnapshotContext(metadata, expected) {
|
|
|
18619
18781
|
}
|
|
18620
18782
|
}
|
|
18621
18783
|
function requireSyncRun(db, runId, projectId, kind) {
|
|
18622
|
-
const run = db.select().from(runs).where(
|
|
18784
|
+
const run = db.select().from(runs).where(and26(
|
|
18623
18785
|
eq32(runs.id, runId),
|
|
18624
18786
|
eq32(runs.projectId, projectId),
|
|
18625
18787
|
eq32(runs.kind, kind)
|
|
@@ -18638,7 +18800,7 @@ function markFailed(db, runId, projectId, kind, expectedStatus, error) {
|
|
|
18638
18800
|
status: RunStatuses.failed,
|
|
18639
18801
|
error: serializeRunError({ message: safeErrorMessage(error) }),
|
|
18640
18802
|
finishedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
18641
|
-
}).where(
|
|
18803
|
+
}).where(and26(
|
|
18642
18804
|
eq32(runs.id, runId),
|
|
18643
18805
|
eq32(runs.projectId, projectId),
|
|
18644
18806
|
eq32(runs.kind, kind),
|
|
@@ -18646,7 +18808,7 @@ function markFailed(db, runId, projectId, kind, expectedStatus, error) {
|
|
|
18646
18808
|
)).run();
|
|
18647
18809
|
}
|
|
18648
18810
|
function claimSyncRun(db, runId, projectId, kind, startedAt) {
|
|
18649
|
-
const claim = db.update(runs).set({ status: RunStatuses.running, startedAt, error: null }).where(
|
|
18811
|
+
const claim = db.update(runs).set({ status: RunStatuses.running, startedAt, error: null }).where(and26(
|
|
18650
18812
|
eq32(runs.id, runId),
|
|
18651
18813
|
eq32(runs.projectId, projectId),
|
|
18652
18814
|
eq32(runs.kind, kind),
|
|
@@ -18714,7 +18876,7 @@ async function executeGoogleAdsMarketingSync(db, runtime, runId, projectId) {
|
|
|
18714
18876
|
status: RunStatuses.completed,
|
|
18715
18877
|
finishedAt,
|
|
18716
18878
|
error: null
|
|
18717
|
-
}).where(
|
|
18879
|
+
}).where(and26(
|
|
18718
18880
|
eq32(runs.id, runId),
|
|
18719
18881
|
eq32(runs.projectId, projectId),
|
|
18720
18882
|
eq32(runs.kind, RunKinds["google-ads-sync"]),
|
|
@@ -18738,11 +18900,11 @@ async function executeGoogleAdsMarketingSync(db, runtime, runId, projectId) {
|
|
|
18738
18900
|
lastMetricsSnapshotAt: result.metrics?.metadata.capturedAt ?? connection.lastMetricsSnapshotAt,
|
|
18739
18901
|
lastMetricsSnapshotId: result.metrics?.metadata.id ?? connection.lastMetricsSnapshotId,
|
|
18740
18902
|
updatedAt: finishedAt
|
|
18741
|
-
}).where(
|
|
18903
|
+
}).where(and26(
|
|
18742
18904
|
eq32(googleAdsConnections.id, connection.id),
|
|
18743
18905
|
eq32(googleAdsConnections.projectId, projectId),
|
|
18744
18906
|
eq32(googleAdsConnections.selectedCustomerId, connection.selectedCustomerId),
|
|
18745
|
-
connection.selectedLoginCustomerId === null ?
|
|
18907
|
+
connection.selectedLoginCustomerId === null ? isNull7(googleAdsConnections.selectedLoginCustomerId) : eq32(googleAdsConnections.selectedLoginCustomerId, connection.selectedLoginCustomerId),
|
|
18746
18908
|
eq32(googleAdsConnections.selectionGeneration, connection.selectionGeneration)
|
|
18747
18909
|
)).run();
|
|
18748
18910
|
if (connectionClaim.changes !== 1) {
|
|
@@ -18823,7 +18985,7 @@ async function executeGtmMarketingSync(db, runtime, runId, projectId) {
|
|
|
18823
18985
|
status: RunStatuses.completed,
|
|
18824
18986
|
finishedAt,
|
|
18825
18987
|
error: null
|
|
18826
|
-
}).where(
|
|
18988
|
+
}).where(and26(
|
|
18827
18989
|
eq32(runs.id, runId),
|
|
18828
18990
|
eq32(runs.projectId, projectId),
|
|
18829
18991
|
eq32(runs.kind, RunKinds["gtm-sync"]),
|
|
@@ -18848,12 +19010,12 @@ async function executeGtmMarketingSync(db, runtime, runId, projectId) {
|
|
|
18848
19010
|
lastSnapshotAt: snapshot.metadata.capturedAt,
|
|
18849
19011
|
lastSnapshotId: snapshot.metadata.id,
|
|
18850
19012
|
updatedAt: finishedAt
|
|
18851
|
-
}).where(
|
|
19013
|
+
}).where(and26(
|
|
18852
19014
|
eq32(gtmConnections.id, connection.id),
|
|
18853
19015
|
eq32(gtmConnections.projectId, projectId),
|
|
18854
19016
|
eq32(gtmConnections.selectedAccountId, connection.selectedAccountId),
|
|
18855
19017
|
eq32(gtmConnections.selectedContainerId, connection.selectedContainerId),
|
|
18856
|
-
connection.selectedWorkspaceId === null ?
|
|
19018
|
+
connection.selectedWorkspaceId === null ? isNull7(gtmConnections.selectedWorkspaceId) : eq32(gtmConnections.selectedWorkspaceId, connection.selectedWorkspaceId),
|
|
18857
19019
|
eq32(gtmConnections.selectionGeneration, connection.selectionGeneration)
|
|
18858
19020
|
)).run();
|
|
18859
19021
|
if (connectionClaim.changes !== 1) {
|
|
@@ -20262,13 +20424,13 @@ async function createServer(opts) {
|
|
|
20262
20424
|
const currentPasswordFingerprint = () => hashSessionToken(opts.config.dashboardPasswordHash ?? "");
|
|
20263
20425
|
opts.db.delete(dashboardSessions).where(or4(
|
|
20264
20426
|
eq33(dashboardSessions.apiKeyHash, ""),
|
|
20265
|
-
|
|
20427
|
+
and27(
|
|
20266
20428
|
isNotNull5(dashboardSessions.passwordFingerprint),
|
|
20267
20429
|
ne4(dashboardSessions.passwordFingerprint, currentPasswordFingerprint())
|
|
20268
20430
|
)
|
|
20269
20431
|
)).run();
|
|
20270
20432
|
if (!opts.config.dashboardPasswordHash) {
|
|
20271
|
-
const lastPasswordEventAt = (action) => opts.db.select({ at: max(auditLog.createdAt) }).from(auditLog).where(
|
|
20433
|
+
const lastPasswordEventAt = (action) => opts.db.select({ at: max(auditLog.createdAt) }).from(auditLog).where(and27(eq33(auditLog.entityType, "dashboard-password"), eq33(auditLog.action, action))).get()?.at ?? null;
|
|
20272
20434
|
const createdAt = lastPasswordEventAt("dashboard-password.created");
|
|
20273
20435
|
const clearedAt = lastPasswordEventAt("dashboard-password.cleared");
|
|
20274
20436
|
if (createdAt !== null && (clearedAt === null || clearedAt < createdAt)) {
|
|
@@ -20302,7 +20464,7 @@ async function createServer(opts) {
|
|
|
20302
20464
|
currentApiKeyHash: apiKeys.keyHash,
|
|
20303
20465
|
passwordFingerprint: dashboardSessions.passwordFingerprint,
|
|
20304
20466
|
expiresAt: dashboardSessions.expiresAt
|
|
20305
|
-
}).from(dashboardSessions).innerJoin(apiKeys, eq33(apiKeys.id, dashboardSessions.apiKeyId)).where(
|
|
20467
|
+
}).from(dashboardSessions).innerJoin(apiKeys, eq33(apiKeys.id, dashboardSessions.apiKeyId)).where(and27(eq33(dashboardSessions.tokenHash, tokenHash), isNull8(apiKeys.revokedAt))).get();
|
|
20306
20468
|
if (!session) return null;
|
|
20307
20469
|
const expiresAt = Date.parse(session.expiresAt);
|
|
20308
20470
|
if (!Number.isFinite(expiresAt) || expiresAt <= Date.now() || session.apiKeyHash !== session.currentApiKeyHash || session.passwordFingerprint !== null && session.passwordFingerprint !== currentPasswordFingerprint()) {
|
|
@@ -20581,7 +20743,7 @@ async function createServer(opts) {
|
|
|
20581
20743
|
opts.db.update(projects).set({ answerFieldsRecompute: null }).where(eq33(projects.id, projectId)).run();
|
|
20582
20744
|
if (recomputeDebts.get(projectId) === debt) recomputeDebts.delete(projectId);
|
|
20583
20745
|
} else if (debt.latestFull === 0) {
|
|
20584
|
-
opts.db.update(projects).set({ answerFieldsRecompute: "competitors" }).where(
|
|
20746
|
+
opts.db.update(projects).set({ answerFieldsRecompute: "competitors" }).where(and27(eq33(projects.id, projectId), eq33(projects.answerFieldsRecompute, "full"))).run();
|
|
20585
20747
|
}
|
|
20586
20748
|
} catch (err) {
|
|
20587
20749
|
app.log.error({ err, projectId }, "could not clear the owed answer field recompute");
|