Skip to content

Repo sync #39868

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 18 additions & 9 deletions src/content-render/scripts/add-content-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,7 @@ function processFile(filePath: string, options: ScriptOptions) {
// Remove the legacy type property if option is passed
const removeLegacyType = Boolean(options.removeType && data.type)

// Skip if contentType already exists and we're not removing legacy type
if (data.contentType && !removeLegacyType) {
console.log(`contentType already set on ${relativePath}`)
return { processed: true, updated: false }
}

const newContentType = data.contentType || determineContentType(relativePath, data.type || '')
const newContentType = determineContentType(relativePath, data.type || '')

if (options.dryRun) {
console.log(`\n${relativePath}`)
Expand All @@ -121,9 +115,24 @@ function processFile(filePath: string, options: ScriptOptions) {
return { processed: true, updated: false }
}

// Set the contentType property if it doesn't exist
if (!data.contentType) {
// Check if we're actually changing an existing contentType
const isChangingContentType = data.contentType && data.contentType !== newContentType
const isAddingContentType = !data.contentType

if (isChangingContentType) {
console.log(
`Changing contentType from '${data.contentType}' to '${newContentType}' on ${relativePath}`,
)
} else if (isAddingContentType) {
console.log(`Adding contentType '${newContentType}' on ${relativePath}`)
}

// Only update if there's actually a change needed
if (isChangingContentType || isAddingContentType) {
data.contentType = newContentType
} else {
console.log(`contentType is already set to '${data.contentType}' on ${relativePath}`)
return { processed: true, updated: false }
}

let legacyTypeValue
Expand Down
10 changes: 10 additions & 0 deletions src/events/lib/hydro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import { isNil } from 'lodash-es'
import statsd from '@/observability/lib/statsd'
import { report } from '@/observability/lib/failbot'
import { MAX_REQUEST_TIMEOUT } from '@/frame/lib/constants'
import { createLogger } from '@/observability/logger'

const logger = createLogger(import.meta.url)

const TIME_OUT_TEXT = 'ms has passed since batch creation'
const SERVER_DISCONNECT_TEXT = 'The server disconnected before a response was received'
Expand Down Expand Up @@ -70,6 +73,13 @@ async function _publish(
) {
const error = new Error(`Failed to send event to Hydro (${statusCode})`)
if (inProd) {
logger.error('Failed to send event to Hydro', {
error,
statusCode,
body,
requestBody,
})
// Report the error to Failbot
report(error, { statusCode, body, requestBody })
} else {
throw error
Expand Down
21 changes: 9 additions & 12 deletions src/search/lib/helpers/external-search-analytics.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ExtendedRequest } from '@/types'
import { publish } from '@/events/lib/hydro'
import { hydroNames } from '@/events/lib/schema'
import { createLogger } from '@/observability/logger'
Expand All @@ -9,7 +10,7 @@ const logger = createLogger(import.meta.url)
* Returns null if the request should continue, or an error response object if validation failed
*/
export async function handleExternalSearchAnalytics(
req: any,
req: ExtendedRequest,
searchContext: string,
): Promise<{ error: string; status: number } | null> {
const host = req.headers['x-host'] || req.headers.host
Expand Down Expand Up @@ -73,12 +74,12 @@ export async function handleExternalSearchAnalytics(
version: '1.0.0',
created: new Date().toISOString(),
hostname: normalizedHost,
path: '',
search: '',
path: req?.context?.path || '',
search: 'REDACTED',
hash: '',
path_language: 'en',
path_version: '',
path_product: '',
path_language: req?.context?.language || 'en',
path_version: req?.context?.version || '',
path_product: req?.context?.product || '',
path_article: '',
},
search_query: 'REDACTED',
Expand All @@ -90,7 +91,7 @@ export async function handleExternalSearchAnalytics(
await publish(analyticsPayload)
} catch (error) {
// Don't fail the request if analytics fails
console.error('Failed to send search analytics:', error)
logger.error('Failed to send search analytics:', { error })
}

return null
Expand Down Expand Up @@ -146,16 +147,12 @@ function stripPort(host: string): string {
return hostname
}

interface ExternalAPIRequestLike {
headers: Record<string, string | undefined>
}

/**
* Determines if a request is likely from an external API client rather than a browser
* Uses multiple heuristics to detect programmatic vs browser requests
*/
const userAgentRegex = /^(curl|wget|python-requests|axios|node-fetch|Go-http-client|okhttp)/i
function isExternalAPIRequest(req: ExternalAPIRequestLike): boolean {
function isExternalAPIRequest(req: ExtendedRequest): boolean {
const headers = req.headers

// Browser security headers that APIs typically don't send
Expand Down
Loading