From 8900de6c6fe8cc9892dd3be97194463214effd76 Mon Sep 17 00:00:00 2001 From: Tim Hostetler <6970899+thostetler@users.noreply.github.com> Date: Wed, 1 Apr 2026 15:38:50 -0400 Subject: [PATCH 1/3] feat(config): expose search and highlight tuning params as env vars Timeout values declared in .env.local.sample were never wired up; hl.maxAnalyzedChars was hardcoded at 150k with no override path. - Wire NEXT_PUBLIC_SEARCH_API_TIMEOUT_MS and NEXT_PUBLIC_SEARCH_SSR_API_TIMEOUT_MS into APP_DEFAULTS - Add NEXT_PUBLIC_SOLR_HL_MAX_ANALYZED_CHARS with 1M default, used in getHighlightParams - Update .env.local.sample with new var --- .env.local.sample | 1 + src/api/search/models.ts | 4 ++-- src/config.ts | 6 ++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.env.local.sample b/.env.local.sample index fb3277abb..d2d2479c3 100644 --- a/.env.local.sample +++ b/.env.local.sample @@ -27,6 +27,7 @@ REDIS_PREFIX=scix_ # SEARCH NEXT_PUBLIC_SEARCH_API_TIMEOUT_MS=30000 NEXT_PUBLIC_SEARCH_SSR_API_TIMEOUT_MS=30000 +NEXT_PUBLIC_SOLR_HL_MAX_ANALYZED_CHARS=1000000 # CRAWLERS VERIFIED_BOTS_ACCESS_TOKEN= diff --git a/src/api/search/models.ts b/src/api/search/models.ts index 1dbe1dabe..6fa867f3b 100644 --- a/src/api/search/models.ts +++ b/src/api/search/models.ts @@ -1,4 +1,4 @@ -import { APP_DEFAULTS } from '@/config'; +import { APP_DEFAULTS, HL_MAX_ANALYZED_CHARS } from '@/config'; import { IADSApiSearchParams, IDocsEntity } from '@/api/search/types'; export const defaultFields: IADSApiSearchParams['fl'] = [ @@ -225,7 +225,7 @@ export const getHighlightParams = (params: IADSApiSearchParams): IADSApiSearchPa fl: ['id'], hl: true, 'hl.fl': 'title,abstract,body,ack,keyword,author', - 'hl.maxAnalyzedChars': 150000, + 'hl.maxAnalyzedChars': HL_MAX_ANALYZED_CHARS, 'hl.requireFieldMatch': true, 'hl.usePhraseHighlighter': true, }); diff --git a/src/config.ts b/src/config.ts index e50885ef3..60ce2ebda 100644 --- a/src/config.ts +++ b/src/config.ts @@ -23,14 +23,16 @@ export const APP_DEFAULTS = { BIBTEX_DEFAULT_AUTHOR_CUTOFF: 10, RESULT_ITEM_PUB_CUTOFF: 50, EMPTY_QUERY: '*:*', - API_TIMEOUT: 30000, - SSR_API_TIMEOUT: 30000, + API_TIMEOUT: parseInt(process.env.NEXT_PUBLIC_SEARCH_API_TIMEOUT_MS ?? '30000', 10), + SSR_API_TIMEOUT: parseInt(process.env.NEXT_PUBLIC_SEARCH_SSR_API_TIMEOUT_MS ?? '30000', 10), PREFERRED_SEARCH_SORT: 'score', PREFERRED_LIB_SORT: 'time', } as const; export const GOOGLE_RECAPTCHA_KEY = '6Lex_aQUAAAAAMwJFbdGFeigshN7mRQdbXoGQ7-N'; +export const HL_MAX_ANALYZED_CHARS = parseInt(process.env.NEXT_PUBLIC_SOLR_HL_MAX_ANALYZED_CHARS ?? '1000000', 10); + export const sessionConfig: IronSessionOptions = { password: process.env.COOKIE_SECRET, cookieName: process.env.SCIX_SESSION_COOKIE_NAME, From d2fb55d2d20423e92d8944391a488d3b54e11b55 Mon Sep 17 00:00:00 2001 From: Tim Hostetler <6970899+thostetler@users.noreply.github.com> Date: Wed, 1 Apr 2026 15:40:59 -0400 Subject: [PATCH 2/3] feat(config): expose Solr facet limit as runtime env var - Add NEXT_PUBLIC_SOLR_FACET_LIMIT with default 2000 - Use it in getSearchFacetYearsParams, getSearchFacetCitationsParams, getSearchFacetReadsParams --- .env.local.sample | 1 + src/api/search/models.ts | 8 ++++---- src/config.ts | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.env.local.sample b/.env.local.sample index d2d2479c3..d8f25d3e1 100644 --- a/.env.local.sample +++ b/.env.local.sample @@ -28,6 +28,7 @@ REDIS_PREFIX=scix_ NEXT_PUBLIC_SEARCH_API_TIMEOUT_MS=30000 NEXT_PUBLIC_SEARCH_SSR_API_TIMEOUT_MS=30000 NEXT_PUBLIC_SOLR_HL_MAX_ANALYZED_CHARS=1000000 +NEXT_PUBLIC_SOLR_FACET_LIMIT=2000 # CRAWLERS VERIFIED_BOTS_ACCESS_TOKEN= diff --git a/src/api/search/models.ts b/src/api/search/models.ts index 6fa867f3b..822bb4d58 100644 --- a/src/api/search/models.ts +++ b/src/api/search/models.ts @@ -1,4 +1,4 @@ -import { APP_DEFAULTS, HL_MAX_ANALYZED_CHARS } from '@/config'; +import { APP_DEFAULTS, HL_MAX_ANALYZED_CHARS, SOLR_FACET_LIMIT } from '@/config'; import { IADSApiSearchParams, IDocsEntity } from '@/api/search/types'; export const defaultFields: IADSApiSearchParams['fl'] = [ @@ -194,7 +194,7 @@ export const getSearchFacetYearsParams = (params: IADSApiSearchParams): IADSApiS 'facet.pivot': 'property,year', facet: true, 'facet.mincount': 1, - 'facet.limit': 2000, + 'facet.limit': SOLR_FACET_LIMIT, }); export const getSearchFacetCitationsParams = (params: IADSApiSearchParams): IADSApiSearchParams => ({ @@ -202,7 +202,7 @@ export const getSearchFacetCitationsParams = (params: IADSApiSearchParams): IADS fl: ['id'], stats: true, 'stats.field': 'citation_count', - 'json.facet': `{"citation_count":{"type":"terms","field":"citation_count","sort":{"index":"desc"},"limit":2000}}`, + 'json.facet': `{"citation_count":{"type":"terms","field":"citation_count","sort":{"index":"desc"},"limit":${SOLR_FACET_LIMIT}}}`, }); export const getSearchFacetReadsParams = (params: IADSApiSearchParams): IADSApiSearchParams => ({ @@ -210,7 +210,7 @@ export const getSearchFacetReadsParams = (params: IADSApiSearchParams): IADSApiS fl: ['id'], stats: true, 'stats.field': 'read_count', - 'json.facet': `{"read_count":{"type":"terms","field":"read_count","sort":{"index":"desc"},"limit":2000}}`, + 'json.facet': `{"read_count":{"type":"terms","field":"read_count","sort":{"index":"desc"},"limit":${SOLR_FACET_LIMIT}}}`, }); export const getSearchStatsParams = (params: IADSApiSearchParams, field: string): IADSApiSearchParams => ({ diff --git a/src/config.ts b/src/config.ts index 60ce2ebda..39c6b3aed 100644 --- a/src/config.ts +++ b/src/config.ts @@ -32,6 +32,7 @@ export const APP_DEFAULTS = { export const GOOGLE_RECAPTCHA_KEY = '6Lex_aQUAAAAAMwJFbdGFeigshN7mRQdbXoGQ7-N'; export const HL_MAX_ANALYZED_CHARS = parseInt(process.env.NEXT_PUBLIC_SOLR_HL_MAX_ANALYZED_CHARS ?? '1000000', 10); +export const SOLR_FACET_LIMIT = parseInt(process.env.NEXT_PUBLIC_SOLR_FACET_LIMIT ?? '2000', 10); export const sessionConfig: IronSessionOptions = { password: process.env.COOKIE_SECRET, From f1908ca9179cdbf60107f53a67b091f035ac013d Mon Sep 17 00:00:00 2001 From: Tim Hostetler <6970899+thostetler@users.noreply.github.com> Date: Wed, 1 Apr 2026 15:44:43 -0400 Subject: [PATCH 3/3] feat(config): expose results graph row limit as runtime env var - Add NEXT_PUBLIC_VIS_RESULTS_GRAPH_ROWS with default 1500 - Use it in defaultResultsGraphParams --- .env.local.sample | 1 + src/api/vis/models.ts | 3 ++- src/config.ts | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.env.local.sample b/.env.local.sample index d8f25d3e1..b962bfd01 100644 --- a/.env.local.sample +++ b/.env.local.sample @@ -29,6 +29,7 @@ NEXT_PUBLIC_SEARCH_API_TIMEOUT_MS=30000 NEXT_PUBLIC_SEARCH_SSR_API_TIMEOUT_MS=30000 NEXT_PUBLIC_SOLR_HL_MAX_ANALYZED_CHARS=1000000 NEXT_PUBLIC_SOLR_FACET_LIMIT=2000 +NEXT_PUBLIC_VIS_RESULTS_GRAPH_ROWS=1500 # CRAWLERS VERIFIED_BOTS_ACCESS_TOKEN= diff --git a/src/api/vis/models.ts b/src/api/vis/models.ts index 016af8aec..f96cf334f 100644 --- a/src/api/vis/models.ts +++ b/src/api/vis/models.ts @@ -1,13 +1,14 @@ import { mapObjIndexed } from 'ramda'; import { IADSApiVisParams, IADSApiWordCloudParams } from './types'; import { IADSApiSearchParams } from '@/api/search/types'; +import { VIS_RESULTS_GRAPH_ROWS } from '@/config'; export const defaultResultsGraphParams: IADSApiSearchParams = { q: '*:*', sort: ['date desc', 'bibcode desc'], fl: ['title', 'bibcode', 'citation_count', 'read_count', 'pubdate'], start: 0, - rows: 1500, + rows: VIS_RESULTS_GRAPH_ROWS, }; type ParamValueType = IADSApiSearchParams[keyof IADSApiSearchParams]; diff --git a/src/config.ts b/src/config.ts index 39c6b3aed..f645637ec 100644 --- a/src/config.ts +++ b/src/config.ts @@ -33,6 +33,7 @@ export const GOOGLE_RECAPTCHA_KEY = '6Lex_aQUAAAAAMwJFbdGFeigshN7mRQdbXoGQ7-N'; export const HL_MAX_ANALYZED_CHARS = parseInt(process.env.NEXT_PUBLIC_SOLR_HL_MAX_ANALYZED_CHARS ?? '1000000', 10); export const SOLR_FACET_LIMIT = parseInt(process.env.NEXT_PUBLIC_SOLR_FACET_LIMIT ?? '2000', 10); +export const VIS_RESULTS_GRAPH_ROWS = parseInt(process.env.NEXT_PUBLIC_VIS_RESULTS_GRAPH_ROWS ?? '1500', 10); export const sessionConfig: IronSessionOptions = { password: process.env.COOKIE_SECRET,