@ncukondo/reference-manager 0.13.3 → 0.13.5
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/dist/chunks/{action-menu-Dc3wCGod.js → action-menu-svBJmZdi.js} +3 -3
- package/dist/chunks/{action-menu-Dc3wCGod.js.map → action-menu-svBJmZdi.js.map} +1 -1
- package/dist/chunks/{index-C0TB_ha0.js → index-4KSTJ3rp.js} +26 -15
- package/dist/chunks/{index-C0TB_ha0.js.map → index-4KSTJ3rp.js.map} +1 -1
- package/dist/chunks/{index-CU6eBQaB.js → index-CaAOawzv.js} +22 -14
- package/dist/chunks/{index-CU6eBQaB.js.map → index-CaAOawzv.js.map} +1 -1
- package/dist/chunks/{search-prompt-RtHDJFgL.js → search-prompt-Bg9usf8f.js} +32 -8
- package/dist/chunks/search-prompt-Bg9usf8f.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/features/interactive/search-prompt.d.ts +11 -0
- package/dist/features/interactive/search-prompt.d.ts.map +1 -1
- package/dist/features/operations/add.d.ts +2 -2
- package/dist/features/operations/add.d.ts.map +1 -1
- package/dist/features/operations/cite.d.ts +4 -0
- package/dist/features/operations/cite.d.ts.map +1 -1
- package/dist/features/operations/operations-library.d.ts +3 -1
- package/dist/features/operations/operations-library.d.ts.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +1 -1
- package/dist/chunks/search-prompt-RtHDJFgL.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-C0TB_ha0.js","sources":["../../src/features/operations/update.ts","../../src/features/format/citation-fallback.ts","../../src/features/format/citation-csl.ts","../../src/features/pagination/sorter.ts","../../src/features/pagination/paginate.ts","../../src/config/csl-styles.ts","../../src/features/operations/remove.ts","../../src/features/import/cache.ts","../../src/features/import/normalizer.ts","../../src/features/import/detector.ts","../../src/features/import/rate-limiter.ts","../../src/features/import/fetcher.ts","../../src/features/import/parser.ts","../../src/features/import/importer.ts","../../src/features/operations/add.ts","../../src/server/routes/add.ts","../../src/features/operations/cite.ts","../../src/server/routes/cite.ts","../../src/server/routes/health.ts","../../src/features/operations/list.ts","../../src/server/routes/list.ts","../../src/server/routes/references.ts","../../src/features/operations/search.ts","../../src/server/routes/search.ts","../../src/server/index.ts"],"sourcesContent":["import type { CslItem } from \"../../core/csl-json/types.js\";\nimport type { ILibrary, IdentifierType } from \"../../core/library-interface.js\";\n\n/**\n * Options for updateReference operation\n */\nexport interface UpdateOperationOptions {\n /** Reference ID or UUID */\n identifier: string;\n /** Identifier type: 'id' (default), 'uuid', 'doi', 'pmid', or 'isbn' */\n idType?: IdentifierType;\n /** Partial updates to apply to the reference */\n updates: Partial<CslItem>;\n /** How to handle ID collision: 'fail' (default) or 'suffix' */\n onIdCollision?: \"fail\" | \"suffix\";\n}\n\n/**\n * Result of updateReference operation\n */\nexport interface UpdateOperationResult {\n /** Whether the update was successful */\n updated: boolean;\n /** The updated item (if successful) */\n item?: CslItem;\n /** True if ID collision occurred (only when updated=false and onIdCollision='fail') */\n idCollision?: boolean;\n /** True if the ID was changed due to collision resolution */\n idChanged?: boolean;\n /** The new ID after collision resolution (only when idChanged=true) */\n newId?: string;\n}\n\n/**\n * Update a reference in the library.\n *\n * @param library - The library to update\n * @param options - Update options including identifier, updates, and collision handling\n * @returns Result indicating success and the updated item\n */\nexport async function updateReference(\n library: ILibrary,\n options: UpdateOperationOptions\n): Promise<UpdateOperationResult> {\n const { identifier, idType = \"id\", updates, onIdCollision = \"fail\" } = options;\n\n // Update the reference using unified update() method\n const updateResult = await library.update(identifier, updates, { idType, onIdCollision });\n\n if (!updateResult.updated) {\n const result: UpdateOperationResult = { updated: false };\n if (updateResult.idCollision) {\n result.idCollision = true;\n }\n return result;\n }\n\n // Save the library\n await library.save();\n\n // Build result from UpdateResult (item is now included)\n const result: UpdateOperationResult = { updated: true };\n\n if (updateResult.item) {\n result.item = updateResult.item;\n }\n\n if (updateResult.idChanged && updateResult.newId) {\n result.idChanged = true;\n result.newId = updateResult.newId;\n }\n\n return result;\n}\n","import type { CslItem } from \"../../core/csl-json/types.js\";\n\n/**\n * Extract first author name with initial\n * Returns \"Family G\" or \"Family\" if no given name\n */\nfunction formatFirstAuthor(item: CslItem): string {\n if (!item.author || item.author.length === 0) {\n return \"Unknown\";\n }\n\n const firstAuthor = item.author[0];\n if (!firstAuthor) {\n return \"Unknown\";\n }\n\n const family = firstAuthor.family || \"Unknown\";\n const givenInitial = firstAuthor.given ? firstAuthor.given[0] : \"\";\n\n if (givenInitial) {\n return `${family} ${givenInitial}`;\n }\n return family;\n}\n\n/**\n * Check if item has multiple authors\n */\nfunction hasMultipleAuthors(item: CslItem): boolean {\n return (item.author?.length || 0) > 1;\n}\n\n/**\n * Extract year from CSL-JSON issued field\n */\nfunction extractYear(item: CslItem): string {\n if (item.issued?.[\"date-parts\"]?.[0]?.[0]) {\n return String(item.issued[\"date-parts\"][0][0]);\n }\n return \"n.d.\";\n}\n\n/**\n * Get journal abbreviation (prefer short title)\n */\nfunction getJournalAbbrev(item: CslItem): string {\n const containerTitleShort = (item as Record<string, unknown>)[\"container-title-short\"];\n if (typeof containerTitleShort === \"string\") {\n return containerTitleShort;\n }\n return item[\"container-title\"] || \"\";\n}\n\n/**\n * Format volume/issue/pages section\n * Returns formats like: \"10(2):123-145\", \"10:123-145\", \"10(2)\", \"10\", or \"\"\n */\nfunction formatVolumeIssuePage(item: CslItem): string {\n const volume = item.volume;\n const issue = item.issue;\n const page = item.page;\n\n if (!volume && !issue && !page) {\n return \"\";\n }\n\n let result = \"\";\n\n if (volume) {\n result += volume;\n if (issue) {\n result += `(${issue})`;\n }\n if (page) {\n result += `:${page}`;\n }\n } else if (page) {\n result += page;\n }\n\n return result;\n}\n\n/**\n * Get identifier (PMID > DOI > URL priority)\n */\nfunction getIdentifier(item: CslItem): string {\n if (item.PMID) {\n return `PMID:${item.PMID}`;\n }\n if (item.DOI) {\n return `DOI:${item.DOI}`;\n }\n if (item.URL) {\n return item.URL;\n }\n return \"\";\n}\n\n/**\n * Format a single bibliography entry\n */\nfunction formatBibliographyEntry(item: CslItem): string {\n const parts: string[] = [];\n\n // Author\n const author = formatFirstAuthor(item);\n const etAl = hasMultipleAuthors(item) ? \" et al\" : \"\";\n parts.push(`${author}${etAl}.`);\n\n // Journal\n const journal = getJournalAbbrev(item);\n if (journal) {\n parts.push(`${journal}.`);\n }\n\n // Year and volume/issue/pages\n const year = extractYear(item);\n const volumeIssuePage = formatVolumeIssuePage(item);\n\n if (volumeIssuePage) {\n parts.push(`${year};${volumeIssuePage}.`);\n } else {\n parts.push(`${year}.`);\n }\n\n // Identifier\n const identifier = getIdentifier(item);\n if (identifier) {\n parts.push(`${identifier}.`);\n }\n\n // Title\n if (item.title) {\n parts.push(`${item.title}.`);\n }\n\n return parts.join(\" \");\n}\n\n/**\n * Get first author family name only (for in-text citations)\n */\nfunction getFirstAuthorFamilyName(item: CslItem): string {\n if (!item.author || item.author.length === 0) {\n return \"Unknown\";\n }\n\n const firstAuthor = item.author[0];\n if (!firstAuthor) {\n return \"Unknown\";\n }\n\n return firstAuthor.family || \"Unknown\";\n}\n\n/**\n * Format a single in-text citation (without parentheses)\n * Returns \"Family et al, YYYY\" or \"Family, YYYY\"\n */\nfunction formatInTextEntry(item: CslItem): string {\n const author = getFirstAuthorFamilyName(item);\n const etAl = hasMultipleAuthors(item) ? \" et al\" : \"\";\n const year = extractYear(item);\n\n return `${author}${etAl}, ${year}`;\n}\n\n/**\n * Format CSL-JSON items as simplified AMA-like bibliography entries.\n *\n * Format: FirstAuthor [et al]. JournalAbbrev. YYYY;volume(issue):pages. PMID:xxxxx [or DOI:xxxxx]. Title.\n *\n * Multiple items are separated by double newlines.\n *\n * @param items - Array of CSL-JSON items\n * @returns Formatted bibliography entries separated by double newlines\n */\nexport function formatBibliography(items: CslItem[]): string {\n if (items.length === 0) {\n return \"\";\n }\n\n return items.map(formatBibliographyEntry).join(\"\\n\\n\");\n}\n\n/**\n * Format CSL-JSON items as simplified in-text citations.\n *\n * Format: (FirstAuthor et al, YYYY)\n *\n * Multiple items are separated by semicolons and enclosed in parentheses.\n *\n * @param items - Array of CSL-JSON items\n * @returns Formatted in-text citation(s) enclosed in parentheses\n */\nexport function formatInText(items: CslItem[]): string {\n if (items.length === 0) {\n return \"\";\n }\n\n const citations = items.map(formatInTextEntry).join(\"; \");\n return `(${citations})`;\n}\n","import { Cite, plugins } from \"@citation-js/core\";\nimport \"@citation-js/plugin-csl\";\nimport type { CslItem } from \"../../core/csl-json/types.js\";\nimport { formatBibliography, formatInText } from \"./citation-fallback.js\";\n\n/**\n * Options for CSL citation formatting\n */\nexport type CitationFormatOptions = {\n /**\n * CSL style name (e.g., 'apa', 'vancouver', 'chicago')\n * @default 'apa'\n */\n style?: string;\n\n /**\n * Custom CSL style XML content.\n * When provided, this XML is registered and used instead of built-in styles.\n */\n styleXml?: string;\n\n /**\n * Output format: text, html, or rtf\n * @default 'text'\n */\n format?: \"text\" | \"html\" | \"rtf\";\n\n /**\n * Locale code (e.g., 'en-US', 'en-GB')\n * @default 'en-US'\n */\n locale?: string;\n};\n\n/**\n * Register a custom CSL style with citation-js.\n * Returns the style name to use for formatting.\n * @throws Error if CSL XML is invalid or malformed\n */\nfunction registerCustomStyle(styleName: string, styleXml: string): string {\n // Basic XML validation\n if (!styleXml.includes(\"<style\") || !styleXml.includes(\"</style>\")) {\n throw new Error(\n \"Invalid CSL file: Missing <style> element. The file may be malformed or not a valid CSL style.\"\n );\n }\n\n // Check for required CSL sections\n const hasCitation = styleXml.includes(\"<citation\") || styleXml.includes(\"<citation>\");\n const hasBibliography = styleXml.includes(\"<bibliography\") || styleXml.includes(\"<bibliography>\");\n if (!hasCitation && !hasBibliography) {\n throw new Error(\n \"Invalid CSL file: Missing <citation> or <bibliography> section. \" +\n \"A valid CSL style must define at least one of these sections.\"\n );\n }\n\n try {\n const config = plugins.config.get(\"@csl\");\n config.templates.add(styleName, styleXml);\n return styleName;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to register CSL style '${styleName}': ${message}`);\n }\n}\n\n/**\n * Format CSL-JSON items as bibliography using CSL processor.\n * Falls back to simplified format if CSL processing fails.\n *\n * @param items - Array of CSL-JSON items\n * @param options - Formatting options\n * @returns Formatted bibliography entries\n */\nexport function formatBibliographyCSL(items: CslItem[], options: CitationFormatOptions): string {\n // Handle empty array\n if (items.length === 0) {\n return \"\";\n }\n\n // Set defaults\n let style = options.style || \"apa\";\n const format = options.format || \"text\";\n const locale = options.locale || \"en-US\";\n\n // Register custom style if XML is provided\n if (options.styleXml) {\n style = registerCustomStyle(style, options.styleXml);\n }\n\n try {\n // Create Cite instance with CSL-JSON data\n const cite = new Cite(items);\n\n // Format as bibliography\n const result = cite.format(\"bibliography\", {\n format,\n template: style,\n lang: locale,\n });\n\n return result;\n } catch (error) {\n // Fall back to simplified format on any error\n const errorMessage = error instanceof Error ? error.message : String(error);\n process.stderr.write(\n `Warning: CSL processing failed (style: ${style}), falling back to simplified format: ${errorMessage}\\n`\n );\n return formatBibliography(items);\n }\n}\n\n/**\n * Format CSL-JSON items as in-text citations using CSL processor.\n * Falls back to simplified format if CSL processing fails.\n *\n * @param items - Array of CSL-JSON items\n * @param options - Formatting options\n * @returns Formatted in-text citation(s)\n */\nexport function formatInTextCSL(items: CslItem[], options: CitationFormatOptions): string {\n // Handle empty array\n if (items.length === 0) {\n return \"\";\n }\n\n // Set defaults\n let style = options.style || \"apa\";\n const format = options.format || \"text\";\n const locale = options.locale || \"en-US\";\n\n // Register custom style if XML is provided\n if (options.styleXml) {\n style = registerCustomStyle(style, options.styleXml);\n }\n\n try {\n // Create Cite instance with CSL-JSON data\n const cite = new Cite(items);\n\n // Format as in-text citation\n const result = cite.format(\"citation\", {\n format,\n template: style,\n lang: locale,\n });\n\n return result;\n } catch (error) {\n // Fall back to simplified format on any error\n const errorMessage = error instanceof Error ? error.message : String(error);\n process.stderr.write(\n `Warning: CSL processing failed (style: ${style}), falling back to simplified format: ${errorMessage}\\n`\n );\n return formatInText(items);\n }\n}\n","/**\n * Reference sorter\n */\n\nimport type { CslItem } from \"../../core/csl-json/types.js\";\nimport type { SortField, SortOrder } from \"./types.js\";\n\n/**\n * Extract created_at timestamp from item, returns epoch (0) if missing\n */\nfunction getCreatedAt(item: CslItem): number {\n const createdAt = item.custom?.created_at;\n if (!createdAt) return 0;\n return new Date(createdAt).getTime();\n}\n\n/**\n * Extract updated timestamp from item, falls back to created_at\n */\nfunction getUpdatedAt(item: CslItem): number {\n const timestamp = item.custom?.timestamp;\n if (timestamp) return new Date(timestamp).getTime();\n return getCreatedAt(item);\n}\n\n/**\n * Extract published date as comparable number\n * Returns 0 (epoch) if missing\n */\nfunction getPublishedDate(item: CslItem): number {\n const dateParts = item.issued?.[\"date-parts\"]?.[0];\n if (!dateParts || dateParts.length === 0) return 0;\n\n const year = dateParts[0] ?? 0;\n const month = dateParts[1] ?? 1;\n const day = dateParts[2] ?? 1;\n\n return new Date(year, month - 1, day).getTime();\n}\n\n/**\n * Extract first author's sortable name\n * Returns \"Anonymous\" if no author\n */\nfunction getAuthorName(item: CslItem): string {\n const firstAuthor = item.author?.[0];\n if (!firstAuthor) return \"Anonymous\";\n\n return firstAuthor.family ?? firstAuthor.literal ?? \"Anonymous\";\n}\n\n/**\n * Extract title, returns empty string if missing\n */\nfunction getTitle(item: CslItem): string {\n return item.title ?? \"\";\n}\n\n/**\n * Get sort value for a given field\n */\nfunction getSortValue(item: CslItem, field: SortField): number | string {\n switch (field) {\n case \"created\":\n return getCreatedAt(item);\n case \"updated\":\n return getUpdatedAt(item);\n case \"published\":\n return getPublishedDate(item);\n case \"author\":\n return getAuthorName(item).toLowerCase();\n case \"title\":\n return getTitle(item).toLowerCase();\n }\n}\n\n/**\n * Compare function for sorting\n */\nfunction compareValues(a: number | string, b: number | string, order: SortOrder): number {\n const multiplier = order === \"desc\" ? -1 : 1;\n\n if (typeof a === \"number\" && typeof b === \"number\") {\n return (a - b) * multiplier;\n }\n\n const strA = String(a);\n const strB = String(b);\n return strA.localeCompare(strB) * multiplier;\n}\n\n/**\n * Sort references by the specified field and order.\n * Uses secondary sort: created (desc), then id (asc) for stability.\n *\n * @param items - References to sort\n * @param sort - Sort field\n * @param order - Sort order\n * @returns Sorted references (new array, does not mutate input)\n */\nexport function sortReferences(items: CslItem[], sort: SortField, order: SortOrder): CslItem[] {\n return [...items].sort((a, b) => {\n // Primary sort\n const aValue = getSortValue(a, sort);\n const bValue = getSortValue(b, sort);\n const primaryCompare = compareValues(aValue, bValue, order);\n\n if (primaryCompare !== 0) return primaryCompare;\n\n // Secondary sort: created (desc)\n const aCreated = getCreatedAt(a);\n const bCreated = getCreatedAt(b);\n const createdCompare = bCreated - aCreated; // desc\n\n if (createdCompare !== 0) return createdCompare;\n\n // Tertiary sort: id (asc) for stability\n return a.id.localeCompare(b.id);\n });\n}\n","/**\n * Pagination applier\n */\n\nexport interface PaginateOptions {\n limit?: number;\n offset?: number;\n}\n\nexport interface PaginateResult<T> {\n items: T[];\n nextOffset: number | null;\n}\n\n/**\n * Apply pagination to an array of items.\n *\n * @param items - Items to paginate\n * @param options - Pagination options (limit=0 or undefined means unlimited)\n * @returns Paginated items with nextOffset (null if no more items)\n */\nexport function paginate<T>(items: T[], options: PaginateOptions): PaginateResult<T> {\n const offset = options.offset ?? 0;\n const limit = options.limit ?? 0;\n\n // Validate inputs\n if (limit < 0) {\n throw new Error(\"limit must be non-negative\");\n }\n if (offset < 0) {\n throw new Error(\"offset must be non-negative\");\n }\n\n const isUnlimited = limit === 0;\n\n // Apply offset\n const afterOffset = items.slice(offset);\n\n // Apply limit (0 means unlimited)\n const paginatedItems = isUnlimited ? afterOffset : afterOffset.slice(0, limit);\n\n // Calculate nextOffset\n let nextOffset: number | null = null;\n if (!isUnlimited && paginatedItems.length > 0) {\n const nextPosition = offset + paginatedItems.length;\n if (nextPosition < items.length) {\n nextOffset = nextPosition;\n }\n }\n\n return {\n items: paginatedItems,\n nextOffset,\n };\n}\n","/**\n * CSL Style Management\n *\n * Handles resolution and loading of CSL (Citation Style Language) style files.\n *\n * Style Resolution Order:\n * 1. --csl-file <path> (exact file path)\n * 2. Built-in style matching --style <name>\n * 3. Search in csl_directory paths (in array order)\n * 4. Default style from config (default_style)\n * 5. \"apa\" (hardcoded default)\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n\n/**\n * Built-in styles available in @citation-js/plugin-csl\n * These can be used directly without loading external files\n */\nexport const BUILTIN_STYLES = [\"apa\", \"vancouver\", \"harvard\"] as const;\n\nexport type BuiltinStyleName = (typeof BUILTIN_STYLES)[number];\n\n/**\n * Check if a style name is a built-in style\n */\nexport function isBuiltinStyle(styleName: string): styleName is BuiltinStyleName {\n return BUILTIN_STYLES.includes(styleName as BuiltinStyleName);\n}\n\nexport interface StyleResolutionOptions {\n /**\n * Exact path to CSL file (from --csl-file option)\n * Takes highest priority\n */\n cslFile?: string;\n\n /**\n * Style name to resolve (from --style option)\n */\n style?: string;\n\n /**\n * Directory or directories to search for custom CSL files\n * (from csl_directory config)\n * Can be a single string or array of strings\n */\n cslDirectory?: string | string[];\n\n /**\n * Default style to use if specified style not found\n * (from default_style config)\n */\n defaultStyle?: string;\n}\n\nexport interface StyleResolution {\n /**\n * Type of resolution: \"builtin\" for citation-js built-in styles,\n * \"custom\" for external CSL files\n */\n type: \"builtin\" | \"custom\";\n\n /**\n * The resolved style name (for built-in) or identifier (for custom)\n */\n styleName: string;\n\n /**\n * CSL XML content (only for custom styles)\n */\n styleXml?: string;\n}\n\n/**\n * Expand tilde (~) in path to home directory\n */\nfunction expandTilde(filePath: string): string {\n if (filePath.startsWith(\"~/\")) {\n const home = process.env.HOME || process.env.USERPROFILE || \"\";\n return path.join(home, filePath.slice(2));\n }\n return filePath;\n}\n\n/**\n * Load CSL style file content from the given path\n *\n * @param stylePath - Path to the CSL style file\n * @returns Content of the CSL style file (XML string)\n * @throws Error if file cannot be read\n */\nexport function loadCSLStyleFile(stylePath: string): string {\n return fs.readFileSync(stylePath, \"utf-8\");\n}\n\n/**\n * Resolve the style based on resolution options\n *\n * Resolution order:\n * 1. cslFile (exact path) - throws if doesn't exist\n * 2. Built-in style matching style name\n * 3. Search in csl_directory paths (in order)\n * 4. Default style (defaultStyle) - if built-in\n * 5. \"apa\" (hardcoded fallback)\n *\n * @param options - Style resolution options\n * @returns StyleResolution with type, styleName, and optional styleXml\n * @throws Error if cslFile is specified but doesn't exist\n */\nexport function resolveStyle(options: StyleResolutionOptions): StyleResolution {\n const { cslFile, style, cslDirectory, defaultStyle } = options;\n\n // 1. If cslFile is specified, use it (highest priority)\n if (cslFile) {\n if (!fs.existsSync(cslFile)) {\n throw new Error(`CSL file '${cslFile}' not found`);\n }\n const styleXml = loadCSLStyleFile(cslFile);\n const styleName = path.basename(cslFile, \".csl\");\n return {\n type: \"custom\",\n styleName,\n styleXml,\n };\n }\n\n // Determine which style name to try\n const styleToResolve = style || defaultStyle || \"apa\";\n\n // 2. Check if it's a built-in style\n if (isBuiltinStyle(styleToResolve)) {\n return {\n type: \"builtin\",\n styleName: styleToResolve,\n };\n }\n\n // 3. Search in csl_directory paths\n if (cslDirectory) {\n const directories = Array.isArray(cslDirectory) ? cslDirectory : [cslDirectory];\n\n for (const dir of directories) {\n const expandedDir = expandTilde(dir);\n const stylePath = path.join(expandedDir, `${styleToResolve}.csl`);\n\n if (fs.existsSync(stylePath)) {\n const styleXml = loadCSLStyleFile(stylePath);\n return {\n type: \"custom\",\n styleName: styleToResolve,\n styleXml,\n };\n }\n }\n }\n\n // 4. Fall back to default style if it's built-in\n if (defaultStyle && isBuiltinStyle(defaultStyle)) {\n return {\n type: \"builtin\",\n styleName: defaultStyle,\n };\n }\n\n // 5. Fall back to apa (hardcoded default)\n return {\n type: \"builtin\",\n styleName: \"apa\",\n };\n}\n","import { unlink } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { CslItem } from \"../../core/csl-json/types.js\";\nimport type { ILibrary, IdentifierType } from \"../../core/library-interface.js\";\nimport type { FulltextType } from \"../fulltext/index.js\";\n\n/**\n * Options for removeReference operation\n */\nexport interface RemoveOperationOptions {\n /** Reference ID or UUID */\n identifier: string;\n /** Identifier type: 'id' (default), 'uuid', 'doi', 'pmid', or 'isbn' */\n idType?: IdentifierType;\n /** Directory containing fulltext files (required if deleteFulltext is true) */\n fulltextDirectory?: string;\n /** Whether to delete associated fulltext files */\n deleteFulltext?: boolean;\n}\n\n/**\n * Result of removeReference operation\n */\nexport interface RemoveResult {\n /** Whether the reference was removed */\n removed: boolean;\n /** The removed item (if found and removal succeeded) */\n removedItem?: CslItem;\n /** Fulltext types that were deleted (only when deleteFulltext=true) */\n deletedFulltextTypes?: FulltextType[];\n}\n\n/**\n * Get fulltext attachment types from a CSL item.\n */\nexport function getFulltextAttachmentTypes(item: CslItem): FulltextType[] {\n const types: FulltextType[] = [];\n const fulltext = item.custom?.fulltext;\n\n if (fulltext?.pdf) {\n types.push(\"pdf\");\n }\n if (fulltext?.markdown) {\n types.push(\"markdown\");\n }\n\n return types;\n}\n\n/**\n * Delete fulltext files associated with an item.\n */\nasync function deleteFulltextFiles(item: CslItem, fulltextDirectory: string): Promise<void> {\n const fulltext = item.custom?.fulltext;\n if (!fulltext) {\n return;\n }\n\n const filesToDelete: string[] = [];\n\n if (fulltext.pdf) {\n filesToDelete.push(join(fulltextDirectory, fulltext.pdf));\n }\n if (fulltext.markdown) {\n filesToDelete.push(join(fulltextDirectory, fulltext.markdown));\n }\n\n for (const filePath of filesToDelete) {\n try {\n await unlink(filePath);\n } catch {\n // Ignore errors (file might not exist)\n }\n }\n}\n\n/**\n * Remove a reference from the library.\n *\n * @param library - The library to remove from\n * @param options - Remove options including identifier and lookup method\n * @returns Result indicating success and the removed item\n */\nexport async function removeReference(\n library: ILibrary,\n options: RemoveOperationOptions\n): Promise<RemoveResult> {\n const { identifier, idType = \"id\", fulltextDirectory, deleteFulltext = false } = options;\n\n const result = await library.remove(identifier, { idType });\n\n if (!result.removed || !result.removedItem) {\n return { removed: false };\n }\n\n // Delete fulltext files if requested\n let deletedFulltextTypes: FulltextType[] | undefined;\n if (deleteFulltext && fulltextDirectory) {\n deletedFulltextTypes = getFulltextAttachmentTypes(result.removedItem);\n if (deletedFulltextTypes.length > 0) {\n await deleteFulltextFiles(result.removedItem, fulltextDirectory);\n }\n }\n\n await library.save();\n\n return {\n removed: true,\n removedItem: result.removedItem,\n ...(deletedFulltextTypes && deletedFulltextTypes.length > 0 && { deletedFulltextTypes }),\n };\n}\n","/**\n * Response cache for PMID and DOI metadata\n *\n * In-memory cache with TTL to avoid redundant API calls.\n * - Per ADR-001: No persistent cache files on disk\n * - Cache is warm during interactive sessions (server mode)\n * - CLI invocations start fresh\n */\n\nimport type { CslItem } from \"../../core/csl-json/types.js\";\n\n/** Default TTL: 1 hour */\nconst DEFAULT_TTL_MS = 60 * 60 * 1000;\n\n/**\n * Cache configuration\n */\nexport interface CacheConfig {\n /** Time-to-live in milliseconds (default: 1 hour) */\n ttlMs?: number;\n}\n\n/**\n * Cache entry with timestamp and TTL\n */\ninterface CacheEntry {\n item: CslItem;\n cachedAt: number;\n ttlMs: number;\n}\n\n/** PMID cache: Map<pmid, CacheEntry> */\nconst pmidCache = new Map<string, CacheEntry>();\n\n/** DOI cache: Map<doi, CacheEntry> */\nconst doiCache = new Map<string, CacheEntry>();\n\n/** ISBN cache: Map<isbn, CacheEntry> */\nconst isbnCache = new Map<string, CacheEntry>();\n\n/**\n * Check if a cache entry is still valid\n */\nfunction isEntryValid(entry: CacheEntry): boolean {\n const now = Date.now();\n return now - entry.cachedAt < entry.ttlMs;\n}\n\n/**\n * Get item from cache if valid\n */\nfunction getFromCache(cache: Map<string, CacheEntry>, key: string): CslItem | undefined {\n const entry = cache.get(key);\n if (!entry) {\n return undefined;\n }\n if (!isEntryValid(entry)) {\n cache.delete(key);\n return undefined;\n }\n return entry.item;\n}\n\n/**\n * Store item in cache\n */\nfunction storeInCache(\n cache: Map<string, CacheEntry>,\n key: string,\n item: CslItem,\n config?: CacheConfig\n): void {\n const ttlMs = config?.ttlMs ?? DEFAULT_TTL_MS;\n cache.set(key, {\n item,\n cachedAt: Date.now(),\n ttlMs,\n });\n}\n\n/**\n * Get cached PMID result\n */\nexport function getPmidFromCache(pmid: string): CslItem | undefined {\n return getFromCache(pmidCache, pmid);\n}\n\n/**\n * Cache PMID result\n */\nexport function cachePmidResult(pmid: string, item: CslItem, config?: CacheConfig): void {\n storeInCache(pmidCache, pmid, item, config);\n}\n\n/**\n * Get cached DOI result\n */\nexport function getDoiFromCache(doi: string): CslItem | undefined {\n return getFromCache(doiCache, doi);\n}\n\n/**\n * Cache DOI result\n */\nexport function cacheDoiResult(doi: string, item: CslItem, config?: CacheConfig): void {\n storeInCache(doiCache, doi, item, config);\n}\n\n/**\n * Get cached ISBN result\n */\nexport function getIsbnFromCache(isbn: string): CslItem | undefined {\n return getFromCache(isbnCache, isbn);\n}\n\n/**\n * Cache ISBN result\n */\nexport function cacheIsbnResult(isbn: string, item: CslItem, config?: CacheConfig): void {\n storeInCache(isbnCache, isbn, item, config);\n}\n\n/**\n * Reset all caches (for test isolation)\n */\nexport function resetCache(): void {\n pmidCache.clear();\n doiCache.clear();\n isbnCache.clear();\n}\n","/**\n * DOI normalizer module\n *\n * Normalizes DOI identifiers by:\n * - Removing URL prefixes (doi.org, dx.doi.org)\n * - Trimming whitespace\n */\n\n/**\n * URL prefixes to remove from DOI\n */\nconst DOI_URL_PREFIXES = [\n \"https://doi.org/\",\n \"http://doi.org/\",\n \"https://dx.doi.org/\",\n \"http://dx.doi.org/\",\n];\n\n/**\n * Normalize a DOI identifier\n *\n * @param doi - DOI string, possibly with URL prefix\n * @returns Normalized DOI (10.xxx/xxx format)\n */\nexport function normalizeDoi(doi: string): string {\n // Trim whitespace\n const trimmed = doi.trim();\n\n if (!trimmed) {\n return \"\";\n }\n\n // Check for URL prefixes (case-insensitive)\n const lowerInput = trimmed.toLowerCase();\n\n for (const prefix of DOI_URL_PREFIXES) {\n if (lowerInput.startsWith(prefix.toLowerCase())) {\n // Remove the prefix while preserving the original case of the DOI\n return trimmed.slice(prefix.length);\n }\n }\n\n // No prefix found, return as-is\n return trimmed;\n}\n\n/**\n * Normalizes a PMID by removing the optional \"PMID:\" prefix and trimming whitespace.\n *\n * Supported formats:\n * - \"12345678\" -> \"12345678\"\n * - \"PMID:12345678\" -> \"12345678\"\n * - \"pmid:12345678\" -> \"12345678\"\n * - \"PMID: 12345678\" -> \"12345678\" (space after colon)\n *\n * @param pmid - The PMID string to normalize\n * @returns The normalized PMID (digits only) or empty string if invalid\n */\nexport function normalizePmid(pmid: string): string {\n // Trim whitespace\n const trimmed = pmid.trim();\n\n if (!trimmed) {\n return \"\";\n }\n\n // Remove \"PMID:\" prefix (case-insensitive, optional whitespace after colon)\n const normalized = trimmed.replace(/^pmid:\\s*/i, \"\");\n\n return normalized.trim();\n}\n\n/**\n * Normalizes an ISBN by removing the \"ISBN:\" prefix, hyphens, spaces, and uppercasing X.\n *\n * Supported formats:\n * - \"ISBN:978-4-00-000000-0\" -> \"9784000000000\"\n * - \"isbn:4-00-000000-0\" -> \"4000000000\"\n * - \"ISBN: 978 4 00 000000 0\" -> \"9784000000000\"\n * - \"ISBN:400000000x\" -> \"400000000X\" (uppercase X)\n *\n * @param isbn - The ISBN string to normalize\n * @returns The normalized ISBN (digits only, X uppercase at end for ISBN-10) or empty string if invalid\n */\nexport function normalizeIsbn(isbn: string): string {\n // Trim whitespace\n const trimmed = isbn.trim();\n\n if (!trimmed) {\n return \"\";\n }\n\n // Check for ISBN: prefix (case-insensitive)\n if (!/^isbn:/i.test(trimmed)) {\n return \"\";\n }\n\n // Remove \"ISBN:\" prefix (case-insensitive, optional whitespace after colon)\n let normalized = trimmed.replace(/^isbn:\\s*/i, \"\");\n\n // Remove hyphens and spaces\n normalized = normalized.replace(/[-\\s]/g, \"\");\n\n // Uppercase X (for ISBN-10 check digit)\n normalized = normalized.toUpperCase();\n\n return normalized;\n}\n","/**\n * Format detection module for multi-format import\n *\n * Detects input format based on:\n * - File extension (.json, .bib, .ris)\n * - Content patterns (JSON, BibTeX, RIS)\n * - Identifier patterns (PMID, DOI)\n * - Multiple whitespace-separated identifiers\n */\n\nimport { normalizeIsbn, normalizePmid } from \"./normalizer.js\";\n\n/**\n * Supported input formats\n */\nexport type InputFormat =\n | \"json\"\n | \"bibtex\"\n | \"ris\"\n | \"nbib\"\n | \"pmid\"\n | \"doi\"\n | \"isbn\"\n | \"identifiers\"\n | \"unknown\";\n\n/**\n * Extension to format mapping\n */\nconst EXTENSION_MAP: Record<string, InputFormat> = {\n \".json\": \"json\",\n \".bib\": \"bibtex\",\n \".ris\": \"ris\",\n \".nbib\": \"nbib\",\n};\n\n/**\n * DOI URL prefixes to strip\n */\nconst DOI_URL_PREFIXES = [\n \"https://doi.org/\",\n \"http://doi.org/\",\n \"https://dx.doi.org/\",\n \"http://dx.doi.org/\",\n];\n\n/**\n * Detect the format of the given input\n *\n * @param input - File path, identifier, or empty string for stdin\n * @param content - Optional content to analyze (for stdin or unknown extension)\n * @returns Detected format\n */\nexport function detectFormat(input: string, content?: string): InputFormat {\n // 1. Try extension-based detection first\n const extFormat = detectByExtension(input);\n if (extFormat !== \"unknown\") {\n return extFormat;\n }\n\n // 2. If content provided, try content-based detection\n if (content !== undefined) {\n const contentFormat = detectByContent(content);\n if (contentFormat !== \"unknown\") {\n return contentFormat;\n }\n }\n\n // 3. Try identifier detection on input string\n if (input.length > 0) {\n const identifierFormat = detectIdentifier(input);\n if (identifierFormat !== \"unknown\") {\n return identifierFormat;\n }\n }\n\n return \"unknown\";\n}\n\n/**\n * Detect format based on file extension\n */\nexport function detectByExtension(input: string): InputFormat {\n if (!input) return \"unknown\";\n\n // Extract extension (last dot and onwards)\n const dotIndex = input.lastIndexOf(\".\");\n if (dotIndex === -1 || dotIndex === input.length - 1) {\n return \"unknown\";\n }\n\n const ext = input.slice(dotIndex).toLowerCase();\n return EXTENSION_MAP[ext] ?? \"unknown\";\n}\n\n/**\n * Detect format based on content patterns\n */\nexport function detectByContent(content: string): InputFormat {\n const trimmed = content.trim();\n if (!trimmed) return \"unknown\";\n\n // JSON: starts with [ or {\n if (trimmed.startsWith(\"[\") || trimmed.startsWith(\"{\")) {\n return \"json\";\n }\n\n // BibTeX: starts with @\n if (trimmed.startsWith(\"@\")) {\n return \"bibtex\";\n }\n\n // RIS: starts with TY - (tag format)\n if (trimmed.startsWith(\"TY -\")) {\n return \"ris\";\n }\n\n // NBIB (PubMed MEDLINE): starts with PMID-\n if (trimmed.startsWith(\"PMID-\")) {\n return \"nbib\";\n }\n\n // Check if content is multiple identifiers\n return detectIdentifier(trimmed);\n}\n\n/**\n * Detect if input is an identifier (PMID, DOI, ISBN) or multiple identifiers\n */\nfunction detectIdentifier(input: string): InputFormat {\n // Split by whitespace\n const parts = input.split(/\\s+/).filter((p) => p.length > 0);\n\n if (parts.length === 0) {\n return \"unknown\";\n }\n\n // Check each part\n const formats: (\"pmid\" | \"doi\" | \"isbn\")[] = [];\n for (const part of parts) {\n const format = detectSingleIdentifier(part);\n if (format === \"unknown\") {\n // If any part is not a valid identifier, return unknown\n return \"unknown\";\n }\n formats.push(format);\n }\n\n // Single identifier returns its specific format\n if (formats.length === 1) {\n // formats[0] is guaranteed to exist when length === 1\n return formats[0] as \"pmid\" | \"doi\" | \"isbn\";\n }\n\n // Multiple valid identifiers\n return \"identifiers\";\n}\n\n/**\n * Detect if a single string is a PMID, DOI, or ISBN\n */\nexport function detectSingleIdentifier(input: string): \"pmid\" | \"doi\" | \"isbn\" | \"unknown\" {\n // DOI: starts with 10. or is a DOI URL\n if (isDoi(input)) {\n return \"doi\";\n }\n\n // ISBN: requires ISBN: prefix\n if (isIsbn(input)) {\n return \"isbn\";\n }\n\n // PMID: numeric only (must be after ISBN check to avoid conflicts)\n if (isPmid(input)) {\n return \"pmid\";\n }\n\n return \"unknown\";\n}\n\n/**\n * Check if string is a valid DOI\n */\nexport function isDoi(input: string): boolean {\n // Check DOI URL formats\n for (const prefix of DOI_URL_PREFIXES) {\n if (input.toLowerCase().startsWith(prefix.toLowerCase())) {\n const remainder = input.slice(prefix.length);\n return isDoiFormat(remainder);\n }\n }\n\n // Check standard DOI format (10.xxx/xxx)\n return isDoiFormat(input);\n}\n\n/**\n * Check if string is a valid DOI format (10.xxx/xxx)\n */\nfunction isDoiFormat(input: string): boolean {\n // DOI starts with 10. followed by registrant code and suffix\n // Pattern: 10.{registrant}/{suffix}\n if (!input.startsWith(\"10.\")) {\n return false;\n }\n\n // Must have content after 10.\n if (input.length <= 3) {\n return false;\n }\n\n // Must have a slash after registrant code\n const slashIndex = input.indexOf(\"/\");\n if (slashIndex === -1 || slashIndex <= 3) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Check if string is a valid PMID (numeric only)\n */\nexport function isPmid(input: string): boolean {\n if (!input || input.length === 0) {\n return false;\n }\n\n // Normalize input (removes PMID: prefix if present)\n const normalized = normalizePmid(input);\n\n if (!normalized) {\n return false;\n }\n\n // PMID is all digits\n return /^\\d+$/.test(normalized);\n}\n\n/**\n * Check if string is a valid ISBN (requires ISBN: prefix)\n *\n * ISBN must have ISBN: prefix and be either:\n * - ISBN-13: 13 digits\n * - ISBN-10: 10 digits (last may be X)\n */\nexport function isIsbn(input: string): boolean {\n if (!input || input.length === 0) {\n return false;\n }\n\n // Normalize input (removes ISBN: prefix if present, hyphens, spaces)\n const normalized = normalizeIsbn(input);\n\n if (!normalized) {\n return false;\n }\n\n // Check length: ISBN-10 (10 chars) or ISBN-13 (13 chars)\n if (normalized.length !== 10 && normalized.length !== 13) {\n return false;\n }\n\n // ISBN-10: 9 digits + (digit or X)\n if (normalized.length === 10) {\n // First 9 must be digits, last can be digit or X\n if (!/^\\d{9}[\\dX]$/.test(normalized)) {\n return false;\n }\n return true;\n }\n\n // ISBN-13: all digits\n if (!/^\\d{13}$/.test(normalized)) {\n return false;\n }\n\n return true;\n}\n","/**\n * Rate limiter module for API calls\n *\n * Uses factory + lazy initialization singleton pattern:\n * - RateLimiter class: Delay-based rate limiting with configurable requests/second\n * - getRateLimiter(api, config): Returns singleton per API type\n * - resetRateLimiters(): Clears singletons for test isolation\n */\n\n/**\n * API types supported by the rate limiter\n */\nexport type ApiType = \"pubmed\" | \"crossref\" | \"isbn\";\n\n/**\n * Configuration for rate limiter\n */\nexport interface RateLimiterConfig {\n pubmedApiKey?: string;\n}\n\n/**\n * Rate limiter interface\n */\nexport interface RateLimiter {\n readonly requestsPerSecond: number;\n readonly intervalMs: number;\n readonly lastRequestTime: number;\n acquire(): Promise<void>;\n}\n\n/**\n * Rate limit settings per API type\n */\nconst RATE_LIMITS = {\n pubmed: {\n withoutApiKey: 3, // 3 req/sec\n withApiKey: 10, // 10 req/sec\n },\n crossref: 50, // 50 req/sec\n isbn: 10, // 10 req/sec (conservative for Google Books API daily limit)\n} as const;\n\n/**\n * Internal rate limiter implementation\n */\nclass RateLimiterImpl implements RateLimiter {\n readonly requestsPerSecond: number;\n readonly intervalMs: number;\n private _lastRequestTime = 0;\n private _pending: Promise<void> = Promise.resolve();\n\n constructor(requestsPerSecond: number) {\n this.requestsPerSecond = requestsPerSecond;\n this.intervalMs = 1000 / requestsPerSecond;\n }\n\n get lastRequestTime(): number {\n return this._lastRequestTime;\n }\n\n async acquire(): Promise<void> {\n // Chain onto pending promise to ensure sequential processing\n this._pending = this._pending.then(() => this._acquireInternal());\n return this._pending;\n }\n\n private async _acquireInternal(): Promise<void> {\n const now = Date.now();\n const elapsed = now - this._lastRequestTime;\n const waitTime = Math.max(0, this.intervalMs - elapsed);\n\n if (waitTime > 0 && this._lastRequestTime > 0) {\n await this._delay(waitTime);\n }\n\n this._lastRequestTime = Date.now();\n }\n\n private _delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n\n/**\n * Singleton storage for rate limiters by API type\n */\nconst limiters = new Map<ApiType, RateLimiter>();\n\n/**\n * Create a new rate limiter instance\n */\nexport function createRateLimiter(options: {\n requestsPerSecond: number;\n}): RateLimiter {\n return new RateLimiterImpl(options.requestsPerSecond);\n}\n\n/**\n * Get singleton rate limiter for the specified API type\n *\n * Note: Configuration is only used on first call. Subsequent calls\n * return the existing singleton regardless of config changes.\n */\nexport function getRateLimiter(api: ApiType, config: RateLimiterConfig): RateLimiter {\n const existing = limiters.get(api);\n if (existing) {\n return existing;\n }\n\n const requestsPerSecond = getRequestsPerSecond(api, config);\n const limiter = createRateLimiter({ requestsPerSecond });\n limiters.set(api, limiter);\n\n return limiter;\n}\n\n/**\n * Determine requests per second based on API type and configuration\n */\nfunction getRequestsPerSecond(api: ApiType, config: RateLimiterConfig): number {\n switch (api) {\n case \"pubmed\":\n return config.pubmedApiKey ? RATE_LIMITS.pubmed.withApiKey : RATE_LIMITS.pubmed.withoutApiKey;\n case \"crossref\":\n return RATE_LIMITS.crossref;\n case \"isbn\":\n return RATE_LIMITS.isbn;\n }\n}\n\n/**\n * Reset all rate limiter singletons (for test isolation)\n */\nexport function resetRateLimiters(): void {\n limiters.clear();\n}\n","/**\n * Fetcher module for PMID and DOI metadata retrieval\n *\n * - PMID: Uses PMC Citation Exporter API (returns CSL-JSON directly)\n * - DOI: Uses citation-js plugin-doi (Cite.async)\n */\n\nimport { Cite } from \"@citation-js/core\";\nimport \"@citation-js/plugin-doi\";\nimport \"@citation-js/plugin-isbn\";\nimport { type CslItem, CslItemSchema } from \"../../core/csl-json/types.js\";\nimport { getRateLimiter } from \"./rate-limiter.js\";\n\n/** PMC Citation Exporter API base URL */\nconst PMC_API_BASE = \"https://pmc.ncbi.nlm.nih.gov/api/ctxp/v1/pubmed/\";\n\n/** Default timeout for API requests (10 seconds) */\nconst DEFAULT_TIMEOUT_MS = 10000;\n\n/** DOI pattern for validation */\nconst DOI_PATTERN = /^10\\.\\d{4,}(?:\\.\\d+)*\\/\\S+$/;\n\n/**\n * PubMed configuration for API requests\n */\nexport interface PubmedConfig {\n email?: string;\n apiKey?: string;\n}\n\n/**\n * Categorized failure reasons for JSON output\n */\nexport type FailureReason =\n | \"not_found\"\n | \"fetch_error\"\n | \"parse_error\"\n | \"validation_error\"\n | \"unknown\";\n\n/**\n * Result of fetching a single identifier\n */\nexport type FetchResult =\n | { success: true; item: CslItem }\n | { success: false; error: string; reason: FailureReason };\n\n/**\n * Result of fetching a PMID (includes pmid for tracking)\n */\nexport type PmidFetchResult =\n | { pmid: string; success: true; item: CslItem }\n | { pmid: string; success: false; error: string; reason: FailureReason };\n\n/**\n * Results of fetching multiple PMIDs\n */\nexport type FetchResults = PmidFetchResult[];\n\n/**\n * Build PMC API URL with query parameters\n */\nfunction buildPmcUrl(pmids: string[], config: PubmedConfig): string {\n const url = new URL(PMC_API_BASE);\n url.searchParams.set(\"format\", \"csl\");\n\n // Add each PMID as separate id parameter\n for (const pmid of pmids) {\n url.searchParams.append(\"id\", pmid);\n }\n\n if (config.email) {\n url.searchParams.set(\"email\", config.email);\n }\n if (config.apiKey) {\n url.searchParams.set(\"api_key\", config.apiKey);\n }\n\n return url.toString();\n}\n\n/**\n * Extract PMID from CSL-JSON item id field\n * PMC API returns id like \"pmid:12345678\"\n */\nfunction extractPmidFromId(id: string | undefined): string | undefined {\n if (!id) return undefined;\n const match = id.match(/^pmid:(\\d+)$/);\n return match?.[1];\n}\n\n/**\n * Fetch metadata for multiple PMIDs from PMC Citation Exporter API\n *\n * Uses batch API endpoint: /api/ctxp/v1/pubmed/?format=csl&id=1&id=2\n */\n\n/**\n * Parse raw API items and build maps of found items and validation errors\n */\nfunction parseRawItems(rawItems: unknown[]): {\n foundItems: Map<string, CslItem>;\n validationErrors: Map<string, string>;\n} {\n const foundItems = new Map<string, CslItem>();\n const validationErrors = new Map<string, string>();\n\n for (const rawItem of rawItems) {\n const parseResult = CslItemSchema.safeParse(rawItem);\n if (parseResult.success) {\n const pmid = extractPmidFromId(parseResult.data.id);\n if (pmid) {\n foundItems.set(pmid, parseResult.data);\n }\n } else {\n // Try to extract pmid even from invalid data for error reporting\n const maybeId = (rawItem as { id?: string })?.id;\n const pmid = extractPmidFromId(maybeId);\n if (pmid) {\n validationErrors.set(pmid, parseResult.error.message);\n }\n }\n }\n\n return { foundItems, validationErrors };\n}\n\n/**\n * Build fetch result for a single PMID\n */\nfunction buildPmidResult(\n pmid: string,\n foundItems: Map<string, CslItem>,\n validationErrors: Map<string, string>\n): PmidFetchResult {\n const item = foundItems.get(pmid);\n if (item) {\n return { pmid, success: true as const, item };\n }\n const validationError = validationErrors.get(pmid);\n if (validationError) {\n return {\n pmid,\n success: false as const,\n error: `Invalid CSL-JSON data: ${validationError}`,\n reason: \"validation_error\",\n };\n }\n return {\n pmid,\n success: false as const,\n error: `PMID ${pmid} not found`,\n reason: \"not_found\",\n };\n}\n\nexport async function fetchPmids(pmids: string[], config: PubmedConfig): Promise<FetchResults> {\n // Return empty array for empty input\n if (pmids.length === 0) {\n return [];\n }\n\n // Apply rate limiting\n const rateLimiterConfig = config.apiKey ? { pubmedApiKey: config.apiKey } : {};\n const rateLimiter = getRateLimiter(\"pubmed\", rateLimiterConfig);\n await rateLimiter.acquire();\n\n const url = buildPmcUrl(pmids, config);\n\n try {\n const response = await fetch(url, {\n method: \"GET\",\n signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS),\n });\n\n if (!response.ok) {\n // Return error for all PMIDs\n const errorMsg = `HTTP ${response.status}: ${response.statusText}`;\n return pmids.map((pmid) => ({\n pmid,\n success: false as const,\n error: errorMsg,\n reason: \"fetch_error\",\n }));\n }\n\n const data = await response.json();\n\n // Normalize response to array\n const rawItems: unknown[] = Array.isArray(data) ? data : [data];\n\n // Parse raw items and build results\n const { foundItems, validationErrors } = parseRawItems(rawItems);\n\n // Build results for each requested PMID\n return pmids.map((pmid) => buildPmidResult(pmid, foundItems, validationErrors));\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n return pmids.map((pmid) => ({\n pmid,\n success: false as const,\n error: errorMsg,\n reason: \"fetch_error\",\n }));\n }\n}\n\n/**\n * Fetch metadata for a DOI using citation-js\n *\n * Uses @citation-js/plugin-doi for content negotiation\n */\nexport async function fetchDoi(doi: string): Promise<FetchResult> {\n // Validate DOI format\n if (!DOI_PATTERN.test(doi)) {\n return {\n success: false,\n error: `Invalid DOI format: ${doi}`,\n reason: \"validation_error\",\n };\n }\n\n // Apply rate limiting (crossref)\n const rateLimiter = getRateLimiter(\"crossref\", {});\n await rateLimiter.acquire();\n\n try {\n // Use citation-js Cite.async for DOI resolution\n const cite = await Cite.async(doi);\n const rawItems = cite.get({ format: \"real\", type: \"json\" });\n\n if (!rawItems || !Array.isArray(rawItems) || rawItems.length === 0) {\n return {\n success: false,\n error: `No data returned for DOI ${doi}`,\n reason: \"not_found\",\n };\n }\n\n // Validate using zod schema\n const parseResult = CslItemSchema.safeParse(rawItems[0]);\n if (!parseResult.success) {\n return {\n success: false,\n error: `Invalid CSL-JSON data for DOI ${doi}: ${parseResult.error.message}`,\n reason: \"validation_error\",\n };\n }\n\n return { success: true, item: parseResult.data };\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n return {\n success: false,\n error: errorMsg,\n reason: \"fetch_error\",\n };\n }\n}\n\n/** ISBN-10 pattern: 9 digits + (digit or X) */\nconst ISBN10_PATTERN = /^\\d{9}[\\dX]$/;\n\n/** ISBN-13 pattern: 13 digits */\nconst ISBN13_PATTERN = /^\\d{13}$/;\n\n/**\n * Fetch metadata for an ISBN using Google Books API via citation-js\n *\n * @param isbn - Normalized ISBN (10 or 13 digits, no hyphens)\n * @returns FetchResult with CSL-JSON item or error\n */\nexport async function fetchIsbn(isbn: string): Promise<FetchResult> {\n // Validate ISBN format\n if (!ISBN10_PATTERN.test(isbn) && !ISBN13_PATTERN.test(isbn)) {\n return {\n success: false,\n error: `Invalid ISBN format: ${isbn}`,\n reason: \"validation_error\",\n };\n }\n\n // Apply rate limiting (google books - daily limit so we use a generic limiter)\n const rateLimiter = getRateLimiter(\"isbn\", {});\n await rateLimiter.acquire();\n\n try {\n // Use citation-js Cite.async for ISBN resolution\n const cite = await Cite.async(isbn);\n const rawItems = cite.get({ format: \"real\", type: \"json\" });\n\n if (!rawItems || !Array.isArray(rawItems) || rawItems.length === 0) {\n return {\n success: false,\n error: `No data returned for ISBN ${isbn}`,\n reason: \"not_found\",\n };\n }\n\n // Validate using zod schema\n const parseResult = CslItemSchema.safeParse(rawItems[0]);\n if (!parseResult.success) {\n return {\n success: false,\n error: `Invalid CSL-JSON data for ISBN ${isbn}: ${parseResult.error.message}`,\n reason: \"validation_error\",\n };\n }\n\n return { success: true, item: parseResult.data };\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n return {\n success: false,\n error: errorMsg,\n reason: \"fetch_error\",\n };\n }\n}\n","/**\n * Parser module for BibTeX and RIS formats\n *\n * Uses citation-js plugins for parsing:\n * - @citation-js/plugin-bibtex for BibTeX\n * - @citation-js/plugin-ris for RIS\n */\n\nimport { Cite } from \"@citation-js/core\";\nimport \"@citation-js/plugin-bibtex\";\nimport \"@citation-js/plugin-ris\";\nimport type { CslItem } from \"../../core/csl-json/types.js\";\n\n/**\n * Result of a parse operation\n */\nexport type ParseResult = {\n success: boolean;\n items: CslItem[];\n error?: string;\n};\n\n/**\n * Parse BibTeX content to CSL-JSON\n *\n * @param content - BibTeX content string\n * @returns Parse result with CSL-JSON items\n */\nexport function parseBibtex(content: string): ParseResult {\n return parseWithCitationJs(content, \"bibtex\");\n}\n\n/**\n * Parse RIS content to CSL-JSON\n *\n * @param content - RIS content string\n * @returns Parse result with CSL-JSON items\n */\nexport function parseRis(content: string): ParseResult {\n return parseWithCitationJs(content, \"ris\");\n}\n\n/**\n * NBIB to RIS tag mapping\n *\n * Maps PubMed MEDLINE tags to RIS equivalents\n */\nconst NBIB_TO_RIS_TAG_MAP: Record<string, string> = {\n PMID: \"AN\", // PubMed ID -> Accession Number\n TI: \"TI\", // Title -> Title\n FAU: \"AU\", // Full Author -> Author\n AU: \"AU\", // Author -> Author (short form, use FAU when available)\n JT: \"JO\", // Journal Title -> Journal Name\n TA: \"JA\", // Title Abbreviation -> Journal Abbreviation\n AB: \"AB\", // Abstract -> Abstract\n VI: \"VL\", // Volume -> Volume\n IP: \"IS\", // Issue/Part -> Issue Number\n PG: \"SP\", // Pagination -> Start Page (includes range)\n DP: \"PY\", // Date of Publication -> Publication Year\n LA: \"LA\", // Language -> Language\n MH: \"KW\", // MeSH Headings -> Keywords\n OT: \"KW\", // Other Terms -> Keywords\n AD: \"AD\", // Affiliation/Address -> Author Address\n IS: \"SN\", // ISSN -> Serial Number\n PT: \"TY\", // Publication Type -> Type of Reference\n};\n\n/**\n * Publication type mapping from NBIB to RIS\n */\nconst NBIB_PUBLICATION_TYPE_MAP: Record<string, string> = {\n \"Journal Article\": \"JOUR\",\n Review: \"JOUR\",\n Book: \"BOOK\",\n \"Book Chapter\": \"CHAP\",\n \"Conference Paper\": \"CPAPER\",\n Thesis: \"THES\",\n Report: \"RPRT\",\n};\n\n/**\n * Parse a single NBIB entry into tag-value pairs\n */\nfunction parseNbibEntry(entry: string): Array<{ tag: string; value: string }> {\n const result: Array<{ tag: string; value: string }> = [];\n const lines = entry.split(\"\\n\");\n\n let currentTag = \"\";\n let currentValue = \"\";\n\n for (const line of lines) {\n // Check if line starts with a tag (2-4 uppercase letters followed by space(s) and dash)\n const tagMatch = line.match(/^([A-Z]{2,4})\\s*-\\s*(.*)$/);\n\n if (tagMatch) {\n // Save previous tag-value pair\n if (currentTag) {\n result.push({ tag: currentTag, value: currentValue.trim() });\n }\n currentTag = tagMatch[1] ?? \"\";\n currentValue = tagMatch[2] ?? \"\";\n } else if (currentTag && line.match(/^\\s+/)) {\n // Continuation line (starts with whitespace)\n currentValue += ` ${line.trim()}`;\n }\n }\n\n // Save the last tag-value pair\n if (currentTag) {\n result.push({ tag: currentTag, value: currentValue.trim() });\n }\n\n return result;\n}\n\n/**\n * Convert a single NBIB tag-value pair to RIS line\n * @returns RIS line or null if tag should be skipped\n */\nfunction convertNbibTagToRisLine(\n tag: string,\n value: string\n): { line: string; isType?: boolean } | null {\n // Handle DOI specially (AID tag with [doi] suffix)\n if (tag === \"AID\" && value.includes(\"[doi]\")) {\n const doi = value.replace(/\\s*\\[doi\\].*$/, \"\").trim();\n return { line: `DO - ${doi}` };\n }\n\n // Handle PII specially (AID tag with [pii] suffix)\n if (tag === \"AID\" && value.includes(\"[pii]\")) {\n const pii = value.replace(/\\s*\\[pii\\].*$/, \"\").trim();\n return { line: `C1 - ${pii}` }; // C1 = Custom Field 1\n }\n\n // Get mapped RIS tag\n const risTag = NBIB_TO_RIS_TAG_MAP[tag];\n if (!risTag) {\n return null; // Skip unmapped tags\n }\n\n // Handle publication year (extract year only)\n if (risTag === \"PY\") {\n const yearMatch = value.match(/^(\\d{4})/);\n return yearMatch ? { line: `PY - ${yearMatch[1]}` } : null;\n }\n\n // Handle publication type\n if (risTag === \"TY\") {\n const risType = NBIB_PUBLICATION_TYPE_MAP[value] || \"JOUR\";\n return { line: `TY - ${risType}`, isType: true };\n }\n\n return { line: `${risTag} - ${value}` };\n}\n\n/**\n * Convert a single NBIB entry to RIS format\n */\nfunction convertSingleNbibEntryToRis(entry: string): string {\n const parsed = parseNbibEntry(entry);\n\n if (parsed.length === 0) {\n return \"\";\n }\n\n const risLines: string[] = [];\n let hasType = false;\n\n for (const { tag, value } of parsed) {\n const converted = convertNbibTagToRisLine(tag, value);\n if (!converted) {\n continue;\n }\n\n if (converted.isType) {\n risLines.unshift(converted.line); // TY must be first\n hasType = true;\n } else {\n risLines.push(converted.line);\n }\n }\n\n // Add default type if not present\n if (!hasType) {\n risLines.unshift(\"TY - JOUR\");\n }\n\n // Add end record tag\n risLines.push(\"ER -\");\n\n return risLines.join(\"\\n\");\n}\n\n/**\n * Convert NBIB (PubMed MEDLINE) format to RIS format\n *\n * @param content - NBIB content string\n * @returns RIS format string\n */\nexport function convertNbibToRis(content: string): string {\n const trimmed = content.trim();\n\n if (!trimmed) {\n return \"\";\n }\n\n // Split into entries by blank lines (PMID- starts each entry)\n const entries = trimmed.split(/\\n\\s*\\n/).filter((e) => e.trim());\n\n const risEntries = entries.map((entry) => convertSingleNbibEntryToRis(entry)).filter(Boolean);\n\n return risEntries.join(\"\\n\\n\");\n}\n\n/**\n * Parse NBIB (PubMed MEDLINE) content to CSL-JSON\n *\n * Converts NBIB to RIS format first, then parses with citation-js\n *\n * @param content - NBIB content string\n * @returns Parse result with CSL-JSON items\n */\nexport function parseNbib(content: string): ParseResult {\n const trimmed = content.trim();\n\n // Handle empty input\n if (!trimmed) {\n return { success: true, items: [] };\n }\n\n // Convert NBIB to RIS\n const risContent = convertNbibToRis(trimmed);\n\n if (!risContent) {\n return {\n success: false,\n items: [],\n error: \"Failed to convert NBIB to RIS: No valid entries found\",\n };\n }\n\n // Parse the RIS content\n return parseRis(risContent);\n}\n\n/**\n * Parse content using citation-js\n */\nfunction parseWithCitationJs(content: string, format: string): ParseResult {\n const trimmed = content.trim();\n\n // Handle empty input\n if (!trimmed) {\n return { success: true, items: [] };\n }\n\n try {\n // Parse with citation-js (auto-detection works well for bibtex/ris)\n const cite = new Cite(trimmed);\n\n // Get CSL-JSON output\n const items = cite.get({ format: \"real\", type: \"json\" }) as CslItem[];\n\n // Handle case where parsing produces no results\n if (!items || items.length === 0) {\n // Check if input looks like valid format but has no entries\n if (isEmptyFormat(trimmed, format)) {\n return { success: true, items: [] };\n }\n\n return {\n success: false,\n items: [],\n error: `No valid ${format.toUpperCase()} entries found`,\n };\n }\n\n return { success: true, items };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n // Check if this is truly empty content (comments only for bibtex)\n if (isEmptyFormat(trimmed, format)) {\n return { success: true, items: [] };\n }\n\n return {\n success: false,\n items: [],\n error: `Failed to parse ${format.toUpperCase()}: ${errorMessage}`,\n };\n }\n}\n\n/**\n * Check if content is \"empty\" for the given format\n * (e.g., only comments for BibTeX)\n */\nfunction isEmptyFormat(content: string, format: string): boolean {\n if (format === \"bibtex\") {\n // BibTeX comments start with %\n const lines = content.split(\"\\n\");\n return lines.every((line) => {\n const trimmed = line.trim();\n return trimmed === \"\" || trimmed.startsWith(\"%\");\n });\n }\n\n return false;\n}\n","/**\n * Importer orchestration module\n *\n * Coordinates format detection, parsing, and fetching to import references\n * from various input formats.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport type { CslItem } from \"../../core/csl-json/types.js\";\nimport { CslItemSchema } from \"../../core/csl-json/types.js\";\nimport {\n cacheDoiResult,\n cacheIsbnResult,\n cachePmidResult,\n getDoiFromCache,\n getIsbnFromCache,\n getPmidFromCache,\n} from \"./cache.js\";\nimport { detectByContent, detectByExtension, isDoi, isIsbn, isPmid } from \"./detector.js\";\nimport type { InputFormat } from \"./detector.js\";\nimport { fetchDoi, fetchIsbn, fetchPmids } from \"./fetcher.js\";\nimport type { FailureReason, PubmedConfig } from \"./fetcher.js\";\nimport { normalizeDoi, normalizeIsbn, normalizePmid } from \"./normalizer.js\";\nimport { parseBibtex, parseNbib, parseRis } from \"./parser.js\";\n\n// Re-export FailureReason for external use\nexport type { FailureReason } from \"./fetcher.js\";\n\n/**\n * Result of importing a single item\n */\nexport type ImportItemResult =\n | { success: true; item: CslItem; source: string }\n | { success: false; error: string; source: string; reason: FailureReason };\n\n/**\n * Result of an import operation\n */\nexport interface ImportResult {\n results: ImportItemResult[];\n}\n\n/**\n * Options for import operations\n */\nexport interface ImportOptions {\n pubmedConfig?: PubmedConfig;\n}\n\n/**\n * Classified identifiers\n */\ninterface ClassifiedIdentifiers {\n pmids: string[];\n dois: string[];\n isbns: string[];\n unknowns: string[];\n}\n\n/**\n * Classify identifiers into PMIDs, DOIs, and unknowns\n */\nfunction classifyIdentifiers(identifiers: string[]): ClassifiedIdentifiers {\n const pmids: string[] = [];\n const dois: string[] = [];\n const isbns: string[] = [];\n const unknowns: string[] = [];\n\n for (const id of identifiers) {\n if (isPmid(id)) {\n pmids.push(normalizePmid(id));\n } else if (isDoi(id)) {\n dois.push(normalizeDoi(id));\n } else if (isIsbn(id)) {\n isbns.push(normalizeIsbn(id));\n } else {\n unknowns.push(id);\n }\n }\n\n return { pmids, dois, isbns, unknowns };\n}\n\n/**\n * Build error results for unknown identifiers\n */\nfunction buildUnknownResults(unknowns: string[]): ImportItemResult[] {\n return unknowns.map((unknown) => ({\n success: false as const,\n error: `Cannot interpret '${unknown}' as identifier (not a valid PMID or DOI)`,\n source: unknown,\n reason: \"validation_error\" as const,\n }));\n}\n\n/**\n * Fetch PMIDs with cache support\n */\nasync function fetchPmidsWithCache(\n pmids: string[],\n pubmedConfig: PubmedConfig\n): Promise<ImportItemResult[]> {\n const results: ImportItemResult[] = [];\n const pmidsToFetch: string[] = [];\n\n // Check cache first\n for (const pmid of pmids) {\n const cached = getPmidFromCache(pmid);\n if (cached) {\n results.push({ success: true, item: cached, source: pmid });\n } else {\n pmidsToFetch.push(pmid);\n }\n }\n\n // Fetch uncached PMIDs\n if (pmidsToFetch.length > 0) {\n const fetchResults = await fetchPmids(pmidsToFetch, pubmedConfig);\n for (const fetchResult of fetchResults) {\n if (fetchResult.success) {\n cachePmidResult(fetchResult.pmid, fetchResult.item);\n results.push({\n success: true,\n item: fetchResult.item,\n source: fetchResult.pmid,\n });\n } else {\n results.push({\n success: false,\n error: fetchResult.error,\n source: fetchResult.pmid,\n reason: fetchResult.reason,\n });\n }\n }\n }\n\n return results;\n}\n\n/**\n * Fetch DOIs with cache support\n */\nasync function fetchDoisWithCache(dois: string[]): Promise<ImportItemResult[]> {\n const results: ImportItemResult[] = [];\n\n for (const doi of dois) {\n const cached = getDoiFromCache(doi);\n if (cached) {\n results.push({ success: true, item: cached, source: doi });\n continue;\n }\n\n const fetchResult = await fetchDoi(doi);\n if (fetchResult.success) {\n cacheDoiResult(doi, fetchResult.item);\n results.push({ success: true, item: fetchResult.item, source: doi });\n } else {\n results.push({\n success: false,\n error: fetchResult.error,\n source: doi,\n reason: fetchResult.reason,\n });\n }\n }\n\n return results;\n}\n\n/**\n * Fetch ISBNs with caching\n */\nasync function fetchIsbnsWithCache(isbns: string[]): Promise<ImportItemResult[]> {\n const results: ImportItemResult[] = [];\n\n for (const isbn of isbns) {\n const cached = getIsbnFromCache(isbn);\n if (cached) {\n results.push({ success: true, item: cached, source: isbn });\n continue;\n }\n\n const fetchResult = await fetchIsbn(isbn);\n if (fetchResult.success) {\n cacheIsbnResult(isbn, fetchResult.item);\n results.push({ success: true, item: fetchResult.item, source: isbn });\n } else {\n results.push({\n success: false,\n error: fetchResult.error,\n source: isbn,\n reason: fetchResult.reason,\n });\n }\n }\n\n return results;\n}\n\n/**\n * Parse JSON content and return import result\n */\nfunction parseJsonContent(content: string): ImportResult {\n try {\n const parsed = JSON.parse(content);\n const items: unknown[] = Array.isArray(parsed) ? parsed : [parsed];\n\n if (items.length === 0) {\n return { results: [] };\n }\n\n const results: ImportItemResult[] = [];\n for (const item of items) {\n const parseResult = CslItemSchema.safeParse(item);\n if (parseResult.success) {\n results.push({ success: true, item: parseResult.data, source: \"json\" });\n } else {\n results.push({\n success: false,\n error: `Invalid CSL-JSON: ${parseResult.error.message}`,\n source: \"json\",\n reason: \"validation_error\",\n });\n }\n }\n return { results };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n results: [\n {\n success: false,\n error: `Failed to parse JSON: ${message}`,\n source: \"json\",\n reason: \"parse_error\",\n },\n ],\n };\n }\n}\n\n/**\n * Parse BibTeX content and return import result\n */\nfunction parseBibtexContent(content: string): ImportResult {\n const parseResult = parseBibtex(content);\n\n if (!parseResult.success) {\n return {\n results: [\n {\n success: false,\n error: parseResult.error ?? \"Failed to parse BibTeX\",\n source: \"bibtex\",\n reason: \"parse_error\",\n },\n ],\n };\n }\n\n if (parseResult.items.length === 0) {\n return { results: [] };\n }\n\n return {\n results: parseResult.items.map((item) => ({\n success: true as const,\n item,\n source: \"bibtex\",\n })),\n };\n}\n\n/**\n * Parse RIS content and return import result\n */\nfunction parseRisContent(content: string): ImportResult {\n const parseResult = parseRis(content);\n\n if (!parseResult.success) {\n return {\n results: [\n {\n success: false,\n error: parseResult.error ?? \"Failed to parse RIS\",\n source: \"ris\",\n reason: \"parse_error\",\n },\n ],\n };\n }\n\n if (parseResult.items.length === 0) {\n return { results: [] };\n }\n\n return {\n results: parseResult.items.map((item) => ({\n success: true as const,\n item,\n source: \"ris\",\n })),\n };\n}\n\n/**\n * Parse NBIB content and return import result\n */\nfunction parseNbibContent(content: string): ImportResult {\n const parseResult = parseNbib(content);\n\n if (!parseResult.success) {\n return {\n results: [\n {\n success: false,\n error: parseResult.error ?? \"Failed to parse NBIB\",\n source: \"nbib\",\n reason: \"parse_error\",\n },\n ],\n };\n }\n\n if (parseResult.items.length === 0) {\n return { results: [] };\n }\n\n return {\n results: parseResult.items.map((item) => ({\n success: true as const,\n item,\n source: \"nbib\",\n })),\n };\n}\n\n/**\n * Import references from content string\n *\n * @param content - The content to parse\n * @param format - The format of the content (or \"auto\" for detection)\n * @param options - Import options\n * @returns Import result with parsed items\n */\nexport async function importFromContent(\n content: string,\n format: InputFormat | \"auto\",\n _options: ImportOptions\n): Promise<ImportResult> {\n // Determine the actual format\n let actualFormat: InputFormat;\n if (format === \"auto\") {\n actualFormat = detectByContent(content);\n if (actualFormat === \"unknown\") {\n return {\n results: [\n {\n success: false,\n error: \"Cannot detect input format. Use --format to specify explicitly.\",\n source: \"content\",\n reason: \"validation_error\",\n },\n ],\n };\n }\n } else {\n actualFormat = format;\n }\n\n // Parse based on format\n switch (actualFormat) {\n case \"json\":\n return parseJsonContent(content);\n case \"bibtex\":\n return parseBibtexContent(content);\n case \"ris\":\n return parseRisContent(content);\n case \"nbib\":\n return parseNbibContent(content);\n default:\n return {\n results: [\n {\n success: false,\n error: `Unsupported format for content parsing: ${actualFormat}`,\n source: \"content\",\n reason: \"validation_error\",\n },\n ],\n };\n }\n}\n\n/**\n * Import references from identifier strings (PMID or DOI)\n *\n * @param identifiers - Array of identifier strings\n * @param options - Import options (requires pubmedConfig for PMID fetching)\n * @returns Import result with fetched items\n */\nexport async function importFromIdentifiers(\n identifiers: string[],\n options: ImportOptions\n): Promise<ImportResult> {\n if (identifiers.length === 0) {\n return { results: [] };\n }\n\n // Classify identifiers\n const { pmids, dois, isbns, unknowns } = classifyIdentifiers(identifiers);\n\n // Collect results\n const results: ImportItemResult[] = [];\n\n // Add errors for unknown identifiers\n results.push(...buildUnknownResults(unknowns));\n\n // Fetch PMIDs with cache\n const pmidResults = await fetchPmidsWithCache(pmids, options.pubmedConfig ?? {});\n results.push(...pmidResults);\n\n // Fetch DOIs with cache\n const doiResults = await fetchDoisWithCache(dois);\n results.push(...doiResults);\n\n // Fetch ISBNs with cache\n const isbnResults = await fetchIsbnsWithCache(isbns);\n results.push(...isbnResults);\n\n return { results };\n}\n\n/**\n * Options for importFromInputs\n */\nexport interface ImportInputsOptions extends ImportOptions {\n /** Explicit format specification (default: auto) */\n format?: InputFormat | \"auto\";\n /** Content from stdin (if provided, processed before file/identifier inputs) */\n stdinContent?: string;\n}\n\n/**\n * Unified entry point for importing references from file paths or identifiers\n *\n * Classifies inputs as files or identifiers:\n * - If path exists as file → read and parse\n * - If path does not exist → interpret as identifier (PMID/DOI)\n *\n * @param inputs - Array of file paths or identifier strings\n * @param options - Import options including format specification\n * @returns Import result with all parsed/fetched items\n */\n\n/**\n * Check if input looks like a file path (has file-like extension)\n */\nfunction looksLikeFilePath(input: string): boolean {\n const fileExtensions = [\".json\", \".bib\", \".ris\", \".txt\", \".xml\", \".yaml\", \".yml\"];\n const lowerInput = input.toLowerCase();\n return fileExtensions.some((ext) => lowerInput.endsWith(ext));\n}\n\n/**\n * Process a single file input\n */\nasync function processFile(\n filePath: string,\n options: ImportInputsOptions\n): Promise<ImportItemResult[]> {\n try {\n const content = readFileSync(filePath, \"utf-8\");\n\n // Determine format\n let format: InputFormat | \"auto\";\n if (options.format && options.format !== \"auto\") {\n format = options.format;\n } else {\n // Try extension first\n const extFormat = detectByExtension(filePath);\n format = extFormat !== \"unknown\" ? extFormat : \"auto\";\n }\n\n const result = await importFromContent(content, format, options);\n\n // Update source to be the file path\n return result.results.map((r) => ({\n ...r,\n source: filePath,\n }));\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return [\n {\n success: false,\n error: `Failed to read file: ${message}`,\n source: filePath,\n reason: \"fetch_error\",\n },\n ];\n }\n}\n\n/**\n * Process identifier inputs (PMID/DOI)\n */\nasync function processIdentifiers(\n inputs: string[],\n options: ImportInputsOptions\n): Promise<ImportItemResult[]> {\n const results: ImportItemResult[] = [];\n const validIdentifiers: string[] = [];\n\n // Separate valid identifiers from invalid inputs\n for (const input of inputs) {\n // Check if it's a valid identifier\n const isValidPmid = isPmid(input);\n const isValidDoi = isDoi(input);\n const isValidIsbn = isIsbn(input);\n\n if (isValidPmid || isValidDoi || isValidIsbn) {\n validIdentifiers.push(input);\n } else {\n // Not a valid identifier\n const hint = looksLikeFilePath(input)\n ? \" Hint: If this is a file path, check that the file exists.\"\n : \"\";\n results.push({\n success: false,\n error: `Cannot interpret '${input}' as identifier (not a valid PMID, DOI, or ISBN).${hint}`,\n source: input,\n reason: \"validation_error\",\n });\n }\n }\n\n // Fetch valid identifiers\n if (validIdentifiers.length > 0) {\n const fetchResult = await importFromIdentifiers(validIdentifiers, options);\n results.push(...fetchResult.results);\n }\n\n return results;\n}\n\nexport async function importFromInputs(\n inputs: string[],\n options: ImportInputsOptions\n): Promise<ImportResult> {\n const allResults: ImportItemResult[] = [];\n\n // Process stdinContent if provided\n if (options.stdinContent?.trim()) {\n const stdinResults = await processStdinContent(options.stdinContent, options);\n allResults.push(...stdinResults);\n }\n\n // Process file/identifier inputs\n if (inputs.length > 0) {\n const identifiersToFetch: string[] = [];\n\n // Process each input\n for (const input of inputs) {\n if (existsSync(input)) {\n // Input is an existing file\n const fileResults = await processFile(input, options);\n allResults.push(...fileResults);\n } else {\n // Input does not exist as file - treat as potential identifier\n identifiersToFetch.push(input);\n }\n }\n\n // Process identifiers\n if (identifiersToFetch.length > 0) {\n const identifierResults = await processIdentifiers(identifiersToFetch, options);\n allResults.push(...identifierResults);\n }\n }\n\n return { results: allResults };\n}\n\n/**\n * Process stdin content based on format detection\n * - For file formats (json/bibtex/ris): parse directly\n * - For identifier formats (pmid/doi) or auto with identifiers: split and process\n */\nasync function processStdinContent(\n content: string,\n options: ImportInputsOptions\n): Promise<ImportItemResult[]> {\n const format = options.format || \"auto\";\n\n // If explicit file format specified, parse as content\n if (format === \"json\" || format === \"bibtex\" || format === \"ris\" || format === \"nbib\") {\n const result = await importFromContent(content, format, options);\n return result.results.map((r) => ({\n ...r,\n source: r.source === \"content\" ? \"stdin\" : r.source,\n }));\n }\n\n // If explicit identifier format, split and process\n if (format === \"pmid\" || format === \"doi\" || format === \"isbn\") {\n const identifiers = content.split(/\\s+/).filter((s) => s.length > 0);\n return processIdentifiers(identifiers, options);\n }\n\n // Auto-detect format from content\n const detectedFormat = detectByContent(content);\n\n if (\n detectedFormat === \"json\" ||\n detectedFormat === \"bibtex\" ||\n detectedFormat === \"ris\" ||\n detectedFormat === \"nbib\"\n ) {\n // File format detected - parse as content\n const result = await importFromContent(content, detectedFormat, options);\n return result.results.map((r) => ({\n ...r,\n source: r.source === \"content\" ? \"stdin\" : r.source,\n }));\n }\n\n // Not a file format - treat as whitespace-separated identifiers\n const identifiers = content.split(/\\s+/).filter((s) => s.length > 0);\n if (identifiers.length === 0) {\n return [];\n }\n\n return processIdentifiers(identifiers, options);\n}\n","import type { CslItem } from \"../../core/csl-json/types.js\";\nimport { generateId } from \"../../core/identifier/generator.js\";\nimport type { ILibrary } from \"../../core/library-interface.js\";\nimport { detectDuplicate } from \"../duplicate/detector.js\";\nimport type { InputFormat } from \"../import/detector.js\";\nimport type { PubmedConfig } from \"../import/fetcher.js\";\nimport {\n type ImportInputsOptions,\n type ImportItemResult,\n importFromInputs,\n} from \"../import/importer.js\";\n\n// Re-export FailureReason for external use\nexport type { FailureReason } from \"../import/importer.js\";\n\n/**\n * Options for adding references\n */\nexport interface AddReferencesOptions {\n /** Skip duplicate detection */\n force?: boolean;\n /** Explicit input format (default: auto) */\n format?: InputFormat | \"auto\";\n /** PubMed API configuration */\n pubmedConfig?: PubmedConfig;\n /** Content from stdin (if provided, processed before file/identifier inputs) */\n stdinContent?: string;\n}\n\n/**\n * Information about a successfully added reference\n */\nexport interface AddedItem {\n source: string;\n id: string;\n uuid: string;\n title: string;\n /** True if the ID was changed due to collision */\n idChanged?: boolean;\n /** Original ID before collision resolution */\n originalId?: string;\n}\n\n/**\n * Information about a failed import\n */\nexport interface FailedItem {\n source: string;\n error: string;\n reason: import(\"../import/importer.js\").FailureReason;\n}\n\n/**\n * Information about a skipped duplicate\n */\nexport interface SkippedItem {\n source: string;\n existingId: string;\n duplicateType: import(\"../duplicate/types.js\").DuplicateType;\n}\n\n/**\n * Result of addReferences operation\n */\nexport interface AddReferencesResult {\n added: AddedItem[];\n failed: FailedItem[];\n skipped: SkippedItem[];\n}\n\n/**\n * Add references to a library from various input sources.\n *\n * This function orchestrates:\n * 1. Import from inputs (files or identifiers)\n * 2. Duplicate detection (unless force=true)\n * 3. ID collision resolution\n * 4. Library save\n *\n * @param inputs - File paths or identifiers (PMID, DOI)\n * @param library - Target library\n * @param options - Add options\n * @returns Result with added, failed, and skipped items\n */\nexport async function addReferences(\n inputs: string[],\n library: ILibrary,\n options: AddReferencesOptions\n): Promise<AddReferencesResult> {\n const added: AddedItem[] = [];\n const failed: FailedItem[] = [];\n const skipped: SkippedItem[] = [];\n\n // 1. Import from inputs\n const importOptions = buildImportOptions(options);\n const importResult = await importFromInputs(inputs, importOptions);\n\n // Get existing items for duplicate/collision checks (getAll now returns CslItem[] directly)\n const existingItems = await library.getAll();\n\n // Track IDs we've added in this batch (for collision detection within batch)\n const addedIds = new Set<string>();\n\n // 2. Process each import result\n for (const result of importResult.results) {\n const processed = await processImportResult(\n result,\n existingItems,\n addedIds,\n options.force ?? false,\n library\n );\n\n if (processed.type === \"failed\") {\n failed.push(processed.item);\n } else if (processed.type === \"skipped\") {\n skipped.push(processed.item);\n } else {\n added.push(processed.item);\n }\n }\n\n // 3. Save library if any items were added\n if (added.length > 0) {\n await library.save();\n }\n\n return { added, failed, skipped };\n}\n\n/**\n * Build import options from add options\n */\nfunction buildImportOptions(options: AddReferencesOptions): ImportInputsOptions {\n const importOptions: ImportInputsOptions = {};\n if (options.format !== undefined) {\n importOptions.format = options.format;\n }\n if (options.pubmedConfig !== undefined) {\n importOptions.pubmedConfig = options.pubmedConfig;\n }\n if (options.stdinContent !== undefined) {\n importOptions.stdinContent = options.stdinContent;\n }\n return importOptions;\n}\n\ntype ProcessResult =\n | { type: \"added\"; item: AddedItem }\n | { type: \"failed\"; item: FailedItem }\n | { type: \"skipped\"; item: SkippedItem };\n\n/**\n * Process a single import result\n */\nasync function processImportResult(\n result: ImportItemResult,\n existingItems: CslItem[],\n addedIds: Set<string>,\n force: boolean,\n library: ILibrary\n): Promise<ProcessResult> {\n if (!result.success) {\n return {\n type: \"failed\",\n item: { source: result.source, error: result.error, reason: result.reason },\n };\n }\n\n const item = result.item;\n\n // Check for duplicates (unless force=true)\n if (!force) {\n const duplicateResult = detectDuplicate(item, existingItems);\n const existingMatch = duplicateResult.matches[0];\n if (existingMatch) {\n return {\n type: \"skipped\",\n item: {\n source: result.source,\n existingId: existingMatch.existing.id ?? \"\",\n duplicateType: existingMatch.type,\n },\n };\n }\n }\n\n // Resolve ID collision\n const allExistingIds = new Set([...existingItems.map((i) => i.id), ...addedIds]);\n const generatedId = generateId(item);\n const { id, changed } = resolveIdCollision(generatedId, allExistingIds);\n\n const finalItem: CslItem = { ...item, id };\n\n // Add to library\n const addedToLibrary = await library.add(finalItem);\n addedIds.add(id);\n\n // Build result (uuid comes from the library-added item which has ensured UUID)\n const uuid = addedToLibrary.custom?.uuid ?? \"\";\n const addedItem: AddedItem = {\n source: result.source,\n id,\n uuid,\n title: typeof finalItem.title === \"string\" ? finalItem.title : \"\",\n };\n\n if (changed) {\n addedItem.idChanged = true;\n addedItem.originalId = generatedId;\n }\n\n return { type: \"added\", item: addedItem };\n}\n\n/**\n * Generate an alphabetic suffix for ID collision resolution.\n * 0 -> 'a', 1 -> 'b', ..., 25 -> 'z', 26 -> 'aa', etc.\n */\nfunction generateSuffix(index: number): string {\n const alphabet = \"abcdefghijklmnopqrstuvwxyz\";\n let suffix = \"\";\n let n = index;\n\n do {\n suffix = alphabet[n % 26] + suffix;\n n = Math.floor(n / 26) - 1;\n } while (n >= 0);\n\n return suffix;\n}\n\n/**\n * Resolve ID collision by appending alphabetic suffix.\n */\nfunction resolveIdCollision(\n baseId: string,\n existingIds: Set<string>\n): { id: string; changed: boolean } {\n if (!existingIds.has(baseId)) {\n return { id: baseId, changed: false };\n }\n\n // Find next available suffix\n let index = 0;\n let newId: string;\n\n do {\n const suffix = generateSuffix(index);\n newId = `${baseId}${suffix}`;\n index++;\n } while (existingIds.has(newId));\n\n return { id: newId, changed: true };\n}\n","import { Hono } from \"hono\";\nimport type { Config } from \"../../config/schema.js\";\nimport type { Library } from \"../../core/library.js\";\nimport type { InputFormat } from \"../../features/import/detector.js\";\nimport type { PubmedConfig } from \"../../features/import/fetcher.js\";\nimport { type AddReferencesOptions, addReferences } from \"../../features/operations/add.js\";\n\n/**\n * Build PubmedConfig from config, filtering out undefined values\n * to satisfy exactOptionalPropertyTypes requirements.\n */\nfunction buildPubmedConfig(config: Config): PubmedConfig {\n const pubmedConfig: PubmedConfig = {};\n if (config.pubmed.email !== undefined) {\n pubmedConfig.email = config.pubmed.email;\n }\n if (config.pubmed.apiKey !== undefined) {\n pubmedConfig.apiKey = config.pubmed.apiKey;\n }\n return pubmedConfig;\n}\n\n/**\n * Create add route for importing references.\n * @param library - Library instance to use for operations\n * @param config - Configuration with PubMed settings\n * @returns Hono app with add route\n */\nexport function createAddRoute(library: Library, config: Config) {\n const route = new Hono();\n\n // POST / - Add references from inputs\n route.post(\"/\", async (c) => {\n // Parse request body\n let body: unknown;\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: \"Invalid JSON\" }, 400);\n }\n\n // Validate inputs\n if (!body || typeof body !== \"object\") {\n return c.json({ error: \"Request body must be an object\" }, 400);\n }\n\n const { inputs, options } = body as {\n inputs?: unknown;\n options?: { force?: boolean; format?: string };\n };\n\n if (!inputs || !Array.isArray(inputs) || inputs.length === 0) {\n return c.json({ error: \"inputs must be a non-empty array of strings\" }, 400);\n }\n\n // Ensure all inputs are strings\n if (!inputs.every((input) => typeof input === \"string\")) {\n return c.json({ error: \"All inputs must be strings\" }, 400);\n }\n\n // Build options\n const addOptions: AddReferencesOptions = {\n force: options?.force ?? false,\n pubmedConfig: buildPubmedConfig(config),\n };\n\n if (options?.format) {\n addOptions.format = options.format as InputFormat | \"auto\";\n }\n\n // Call addReferences\n const result = await addReferences(inputs as string[], library, addOptions);\n\n return c.json(result);\n });\n\n return route;\n}\n","import { isBuiltinStyle, resolveStyle } from \"../../config/csl-styles.js\";\nimport type { CslItem } from \"../../core/csl-json/types.js\";\nimport type { ILibrary, IdentifierType } from \"../../core/library-interface.js\";\nimport {\n formatBibliography,\n formatBibliographyCSL,\n formatInText,\n formatInTextCSL,\n} from \"../format/index.js\";\n\n/**\n * Options for citeReferences operation\n */\nexport interface CiteOperationOptions {\n /** Reference IDs or UUIDs to cite */\n identifiers: string[];\n /** Identifier type: 'id' (default), 'uuid', 'doi', 'pmid', or 'isbn' */\n idType?: IdentifierType;\n /** CSL style name or path to CSL file */\n style?: string;\n /** Path to custom CSL file */\n cslFile?: string;\n /** Locale for citation formatting (default: \"en-US\") */\n locale?: string;\n /** Output format (default: \"text\") */\n format?: \"text\" | \"html\" | \"rtf\";\n /** If true, generate in-text citation instead of bibliography */\n inText?: boolean;\n}\n\n/**\n * Result for a single citation\n */\nexport type CiteItemResult =\n | { success: true; identifier: string; citation: string }\n | { success: false; identifier: string; error: string };\n\n/**\n * Result of citeReferences operation\n */\nexport interface CiteResult {\n /** Results for each identifier */\n results: CiteItemResult[];\n}\n\ninterface FormatOptions {\n style?: string | undefined;\n styleXml?: string | undefined;\n locale?: string | undefined;\n format?: \"text\" | \"html\" | \"rtf\" | undefined;\n}\n\n/**\n * Check if fallback formatter should be used.\n */\nfunction shouldUseFallback(style: string | undefined, hasCustomXml: boolean): boolean {\n if (hasCustomXml) {\n return false;\n }\n if (style && !isBuiltinStyle(style)) {\n return true;\n }\n return false;\n}\n\n/**\n * Format a single item as citation.\n */\nfunction formatCitation(item: CslItem, inText: boolean, options: FormatOptions): string {\n const useFallback = shouldUseFallback(options.style, !!options.styleXml);\n const style = options.style ?? \"apa\";\n const locale = options.locale ?? \"en-US\";\n const format = options.format ?? \"text\";\n const styleXml = options.styleXml;\n\n if (useFallback) {\n return inText ? formatInText([item]) : formatBibliography([item]);\n }\n\n const formatOptions = { style, locale, format, ...(styleXml && { styleXml }) };\n return inText\n ? formatInTextCSL([item], formatOptions)\n : formatBibliographyCSL([item], formatOptions);\n}\n\n/**\n * Generate citation for a single identifier.\n */\nasync function generateCitationForIdentifier(\n library: ILibrary,\n identifier: string,\n idType: IdentifierType,\n inText: boolean,\n options: FormatOptions\n): Promise<CiteItemResult> {\n const item = await library.find(identifier, { idType });\n\n if (!item) {\n const lookupType = idType === \"uuid\" ? \"UUID\" : idType.toUpperCase();\n return {\n success: false,\n identifier,\n error: `Reference with ${lookupType} '${identifier}' not found`,\n };\n }\n\n const citation = formatCitation(item, inText, options);\n\n return {\n success: true,\n identifier,\n citation,\n };\n}\n\n/**\n * Generate citations for references.\n *\n * @param library - The library to cite from\n * @param options - Citation options including identifiers and style settings\n * @returns Results array with citation or error for each identifier\n */\nexport async function citeReferences(\n library: ILibrary,\n options: CiteOperationOptions\n): Promise<CiteResult> {\n const { identifiers, idType = \"id\", inText = false, style, cslFile, locale, format } = options;\n const results: CiteItemResult[] = [];\n\n // Resolve style: load custom CSL file if specified\n let resolvedStyle = style;\n let styleXml: string | undefined;\n\n if (cslFile) {\n const resolution = resolveStyle({ cslFile });\n resolvedStyle = resolution.styleName;\n styleXml = resolution.styleXml;\n }\n\n for (const identifier of identifiers) {\n const result = await generateCitationForIdentifier(library, identifier, idType, inText, {\n style: resolvedStyle,\n styleXml,\n locale,\n format,\n });\n results.push(result);\n }\n\n return { results };\n}\n","import { Hono } from \"hono\";\nimport { z } from \"zod\";\nimport type { Library } from \"../../core/library.js\";\nimport {\n type CiteOperationOptions,\n type CiteResult,\n citeReferences,\n} from \"../../features/operations/cite.js\";\n\n/**\n * Zod schema for cite request body\n */\nconst CiteRequestSchema = z.object({\n identifiers: z.array(z.string()).min(1, \"identifiers must be a non-empty array\"),\n idType: z.enum([\"id\", \"uuid\", \"doi\", \"pmid\", \"isbn\"]).optional(),\n inText: z.boolean().optional(),\n style: z.string().optional(),\n cslFile: z.string().optional(),\n locale: z.string().optional(),\n format: z.enum([\"text\", \"html\"]).optional(),\n});\n\ntype CiteRequestBody = z.infer<typeof CiteRequestSchema>;\n\n/**\n * Build cite operation options from validated request body.\n */\nfunction buildCiteOptions(body: CiteRequestBody): CiteOperationOptions {\n return {\n identifiers: body.identifiers,\n ...(body.idType !== undefined && { idType: body.idType }),\n ...(body.inText !== undefined && { inText: body.inText }),\n ...(body.style !== undefined && { style: body.style }),\n ...(body.cslFile !== undefined && { cslFile: body.cslFile }),\n ...(body.locale !== undefined && { locale: body.locale }),\n ...(body.format !== undefined && { format: body.format }),\n };\n}\n\n/**\n * Create cite route for generating citations.\n * @param library - Library instance to use for operations\n * @returns Hono app with cite route\n */\nexport function createCiteRoute(library: Library) {\n const route = new Hono();\n\n // POST / - Generate citations for identifiers\n route.post(\"/\", async (c) => {\n // Parse request body\n let rawBody: unknown;\n try {\n rawBody = await c.req.json();\n } catch {\n return c.json({ error: \"Invalid JSON\" }, 400);\n }\n\n // Validate with zod schema\n const parseResult = CiteRequestSchema.safeParse(rawBody);\n if (!parseResult.success) {\n const errorMessage = parseResult.error.issues[0]?.message ?? \"Invalid request body\";\n return c.json({ error: errorMessage }, 400);\n }\n\n // Call citeReferences operation\n const result: CiteResult = await citeReferences(library, buildCiteOptions(parseResult.data));\n\n return c.json(result);\n });\n\n return route;\n}\n","import { Hono } from \"hono\";\n\n/**\n * Health check route.\n * Returns a simple status to verify the server is running.\n */\nexport const healthRoute = new Hono();\n\nhealthRoute.get(\"/\", (c) => {\n return c.json({ status: \"ok\" });\n});\n","import type { CslItem } from \"../../core/csl-json/types.js\";\nimport type { ILibrary } from \"../../core/library-interface.js\";\nimport {\n type PaginationOptions,\n type SortField,\n type SortOptions,\n type SortOrder,\n paginate,\n sortReferences,\n} from \"../pagination/index.js\";\n\n/**\n * Options for listReferences operation\n */\nexport interface ListOptions extends PaginationOptions, SortOptions {}\n\n/**\n * Result of listReferences operation\n */\nexport interface ListResult {\n /** Raw CslItem array */\n items: CslItem[];\n /** Total count before pagination */\n total: number;\n /** Applied limit (0 if unlimited) */\n limit: number;\n /** Applied offset */\n offset: number;\n /** Next page offset, null if no more results */\n nextOffset: number | null;\n}\n\n/**\n * List all references from the library.\n *\n * @param library - The library to list references from\n * @param options - Pagination and sorting options\n * @returns Raw CslItem[] with pagination metadata\n */\nexport async function listReferences(library: ILibrary, options: ListOptions): Promise<ListResult> {\n const sort: SortField = options.sort ?? \"updated\";\n const order: SortOrder = options.order ?? \"desc\";\n const limit = options.limit ?? 0;\n const offset = options.offset ?? 0;\n\n // Get all items\n const allItems = await library.getAll();\n const total = allItems.length;\n\n // Sort\n const sorted = sortReferences(allItems, sort, order);\n\n // Paginate\n const { items: paginatedItems, nextOffset } = paginate(sorted, { limit, offset });\n\n return {\n items: paginatedItems,\n total,\n limit,\n offset,\n nextOffset,\n };\n}\n","import { Hono } from \"hono\";\nimport { z } from \"zod\";\nimport type { Library } from \"../../core/library.js\";\nimport { type ListOptions, listReferences } from \"../../features/operations/list.js\";\nimport { sortFieldSchema, sortOrderSchema } from \"../../features/pagination/index.js\";\nimport { pickDefined } from \"../../utils/object.js\";\n\n/**\n * Request body schema for list endpoint\n */\nconst listRequestBodySchema = z.object({\n sort: sortFieldSchema.optional(),\n order: sortOrderSchema.optional(),\n limit: z.number().int().min(0).optional(),\n offset: z.number().int().min(0).optional(),\n});\n\n/**\n * Request body type for list endpoint\n */\nexport type ListRequestBody = z.infer<typeof listRequestBodySchema>;\n\n/**\n * Creates list route for HTTP server\n */\nexport function createListRoute(library: Library) {\n const route = new Hono();\n\n // POST / - List all references\n route.post(\"/\", async (c) => {\n // Parse request body\n let body: unknown;\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: \"Invalid JSON\" }, 400);\n }\n\n // Validate body with zod\n const parseResult = listRequestBodySchema.safeParse(body);\n if (!parseResult.success) {\n const errorMessage = parseResult.error.issues[0]?.message ?? \"Invalid request body\";\n return c.json({ error: errorMessage }, 400);\n }\n\n const requestBody = parseResult.data;\n\n // Build options for listReferences\n const options: ListOptions = pickDefined(requestBody, [\n \"sort\",\n \"order\",\n \"limit\",\n \"offset\",\n ] as const);\n\n // Call listReferences operation - always returns raw CslItem[]\n const result = await listReferences(library, options);\n\n return c.json(result);\n });\n\n return route;\n}\n","import { Hono } from \"hono\";\nimport type { Library } from \"../../core/library.js\";\nimport { removeReference } from \"../../features/operations/remove.js\";\nimport { updateReference } from \"../../features/operations/update.js\";\n\n/**\n * Create references CRUD route with the given library.\n * @param library - Library instance to use for operations\n * @returns Hono app with references routes\n */\nexport function createReferencesRoute(library: Library) {\n const route = new Hono();\n\n // GET / - Get all references (getAll now returns Promise<CslItem[]>)\n route.get(\"/\", async (c) => {\n const items = await library.getAll();\n return c.json(items);\n });\n\n // GET /uuid/:uuid - Get reference by UUID\n route.get(\"/uuid/:uuid\", async (c) => {\n const uuid = c.req.param(\"uuid\");\n const item = await library.find(uuid, { idType: \"uuid\" });\n\n if (!item) {\n return c.json({ error: \"Reference not found\" }, 404);\n }\n\n return c.json(item);\n });\n\n // GET /id/:id - Get reference by citation ID\n route.get(\"/id/:id\", async (c) => {\n const id = c.req.param(\"id\");\n const item = await library.find(id);\n\n if (!item) {\n return c.json({ error: \"Reference not found\" }, 404);\n }\n\n return c.json(item);\n });\n\n // POST / - Create new reference\n route.post(\"/\", async (c) => {\n try {\n const body = await c.req.json();\n\n // Create and add reference (library.add handles validation and returns the added item)\n const addedItem = await library.add(body);\n\n return c.json(addedItem, 201);\n } catch (error) {\n return c.json(\n {\n error: \"Invalid request body\",\n details: error instanceof Error ? error.message : String(error),\n },\n 400\n );\n }\n });\n\n // PUT /uuid/:uuid - Update reference by UUID\n // Request body: { updates: Partial<CslItem>, onIdCollision?: \"fail\" | \"suffix\" }\n route.put(\"/uuid/:uuid\", async (c) => {\n const uuid = c.req.param(\"uuid\");\n\n let body: unknown;\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: \"Invalid JSON\" }, 400);\n }\n\n if (!body || typeof body !== \"object\") {\n return c.json({ error: \"Request body must be an object\" }, 400);\n }\n\n const { updates, onIdCollision } = body as {\n updates?: Partial<import(\"../../core/csl-json/types.js\").CslItem>;\n onIdCollision?: \"fail\" | \"suffix\";\n };\n\n if (!updates || typeof updates !== \"object\") {\n return c.json({ error: \"Request body must contain 'updates' object\" }, 400);\n }\n\n // Use updateReference operation\n const result = await updateReference(library, {\n identifier: uuid,\n idType: \"uuid\",\n updates,\n onIdCollision: onIdCollision ?? \"suffix\",\n });\n\n // Return operation result with appropriate status code\n if (!result.updated) {\n const status = result.idCollision ? 409 : 404;\n return c.json(result, status);\n }\n\n return c.json(result);\n });\n\n // PUT /id/:id - Update reference by citation ID\n // Request body: { updates: Partial<CslItem>, onIdCollision?: \"fail\" | \"suffix\" }\n route.put(\"/id/:id\", async (c) => {\n const id = c.req.param(\"id\");\n\n let body: unknown;\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: \"Invalid JSON\" }, 400);\n }\n\n if (!body || typeof body !== \"object\") {\n return c.json({ error: \"Request body must be an object\" }, 400);\n }\n\n const { updates, onIdCollision } = body as {\n updates?: Partial<import(\"../../core/csl-json/types.js\").CslItem>;\n onIdCollision?: \"fail\" | \"suffix\";\n };\n\n if (!updates || typeof updates !== \"object\") {\n return c.json({ error: \"Request body must contain 'updates' object\" }, 400);\n }\n\n // Use updateReference operation with idType: 'id'\n const result = await updateReference(library, {\n identifier: id,\n updates,\n onIdCollision: onIdCollision ?? \"suffix\",\n });\n\n // Return operation result with appropriate status code\n if (!result.updated) {\n const status = result.idCollision ? 409 : 404;\n return c.json(result, status);\n }\n\n return c.json(result);\n });\n\n // DELETE /uuid/:uuid - Delete reference by UUID\n route.delete(\"/uuid/:uuid\", async (c) => {\n const uuid = c.req.param(\"uuid\");\n\n // Use removeReference operation\n const result = await removeReference(library, {\n identifier: uuid,\n idType: \"uuid\",\n });\n\n // Return operation result with appropriate status code\n if (!result.removed) {\n return c.json(result, 404);\n }\n\n return c.json(result);\n });\n\n // DELETE /id/:id - Delete reference by citation ID\n route.delete(\"/id/:id\", async (c) => {\n const id = c.req.param(\"id\");\n\n // Use removeReference operation\n const result = await removeReference(library, {\n identifier: id,\n });\n\n // Return operation result with appropriate status code\n if (!result.removed) {\n return c.json(result, 404);\n }\n\n return c.json(result);\n });\n\n return route;\n}\n","import type { CslItem } from \"../../core/csl-json/types.js\";\nimport type { ILibrary } from \"../../core/library-interface.js\";\nimport {\n type PaginationOptions,\n type SearchSortField,\n type SortField,\n type SortOrder,\n paginate,\n sortReferences,\n} from \"../pagination/index.js\";\nimport { search } from \"../search/matcher.js\";\nimport { sortResults as sortByRelevance } from \"../search/sorter.js\";\nimport { tokenize } from \"../search/tokenizer.js\";\n\n/**\n * Sort options for search (includes relevance)\n */\nexport interface SearchSortOptions {\n sort?: SearchSortField;\n order?: SortOrder;\n}\n\n/**\n * Options for searchReferences operation\n */\nexport interface SearchOperationOptions extends PaginationOptions, SearchSortOptions {\n /** Search query string */\n query: string;\n}\n\n/**\n * Result of searchReferences operation\n */\nexport interface SearchResult {\n /** Raw CslItem array */\n items: CslItem[];\n /** Total count before pagination */\n total: number;\n /** Applied limit (0 if unlimited) */\n limit: number;\n /** Applied offset */\n offset: number;\n /** Next page offset, null if no more results */\n nextOffset: number | null;\n}\n\n/**\n * Search references in the library and return raw CslItem[] results.\n *\n * @param library - The library to search in\n * @param options - Search query and pagination options\n * @returns Raw CslItem[] with pagination metadata\n */\nexport async function searchReferences(\n library: ILibrary,\n options: SearchOperationOptions\n): Promise<SearchResult> {\n const query = options.query;\n const sort: SearchSortField = options.sort ?? \"updated\";\n const order: SortOrder = options.order ?? \"desc\";\n const limit = options.limit ?? 0;\n const offset = options.offset ?? 0;\n\n // Get all references\n const allItems = await library.getAll();\n\n // Search and get matched items\n let matchedItems: CslItem[];\n if (!query.trim()) {\n matchedItems = allItems;\n } else {\n // Tokenize and search\n const tokens = tokenize(query).tokens;\n const results = search(allItems, tokens);\n\n // If sorting by relevance, use the search sorter\n if (sort === \"relevance\") {\n const sorted = sortByRelevance(results);\n matchedItems =\n order === \"desc\"\n ? sorted.map((r) => r.reference)\n : sorted.map((r) => r.reference).reverse();\n } else {\n matchedItems = results.map((r) => r.reference);\n }\n }\n\n const total = matchedItems.length;\n\n // Sort (unless already sorted by relevance)\n let sorted: CslItem[];\n if (sort === \"relevance\") {\n sorted = matchedItems;\n } else {\n sorted = sortReferences(matchedItems, sort as SortField, order);\n }\n\n // Paginate\n const { items: paginatedItems, nextOffset } = paginate(sorted, { limit, offset });\n\n return {\n items: paginatedItems,\n total,\n limit,\n offset,\n nextOffset,\n };\n}\n","import { Hono } from \"hono\";\nimport { z } from \"zod\";\nimport type { Library } from \"../../core/library.js\";\nimport { type SearchOperationOptions, searchReferences } from \"../../features/operations/search.js\";\nimport { searchSortFieldSchema, sortOrderSchema } from \"../../features/pagination/index.js\";\nimport { pickDefined } from \"../../utils/object.js\";\n\n/**\n * Request body schema for search endpoint\n */\nconst searchRequestBodySchema = z.object({\n query: z.string(),\n sort: searchSortFieldSchema.optional(),\n order: sortOrderSchema.optional(),\n limit: z.number().int().min(0).optional(),\n offset: z.number().int().min(0).optional(),\n});\n\n/**\n * Request body type for search endpoint\n */\nexport type SearchRequestBody = z.infer<typeof searchRequestBodySchema>;\n\n/**\n * Creates search route for HTTP server\n */\nexport function createSearchRoute(library: Library) {\n const route = new Hono();\n\n // POST / - Search references\n route.post(\"/\", async (c) => {\n // Parse request body\n let body: unknown;\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: \"Invalid JSON\" }, 400);\n }\n\n // Validate body with zod\n const parseResult = searchRequestBodySchema.safeParse(body);\n if (!parseResult.success) {\n const errorMessage = parseResult.error.issues[0]?.message ?? \"Invalid request body\";\n return c.json({ error: errorMessage }, 400);\n }\n\n const requestBody = parseResult.data;\n\n // Build options for searchReferences\n const options: SearchOperationOptions = {\n query: requestBody.query,\n ...pickDefined(requestBody, [\"sort\", \"order\", \"limit\", \"offset\"] as const),\n };\n\n // Call searchReferences operation - always returns raw CslItem[]\n const result = await searchReferences(library, options);\n\n return c.json(result);\n });\n\n return route;\n}\n","import { Hono } from \"hono\";\nimport type { Config } from \"../config/schema.js\";\nimport { Library } from \"../core/library.js\";\nimport { FileWatcher } from \"../features/file-watcher/file-watcher.js\";\nimport { createAddRoute } from \"./routes/add.js\";\nimport { createCiteRoute } from \"./routes/cite.js\";\nimport { healthRoute } from \"./routes/health.js\";\nimport { createListRoute } from \"./routes/list.js\";\nimport { createReferencesRoute } from \"./routes/references.js\";\nimport { createSearchRoute } from \"./routes/search.js\";\n\n/**\n * Result of starting a server with file watcher.\n */\nexport interface ServerWithFileWatcherResult {\n /** The Hono application */\n app: Hono;\n /** The library instance */\n library: Library;\n /** The file watcher instance */\n fileWatcher: FileWatcher;\n /** Dispose function to clean up resources */\n dispose: () => Promise<void>;\n}\n\n/**\n * Create the main Hono server application.\n * @param library - Library instance for the references API\n * @param config - Configuration for the server\n * @returns Hono application\n */\nexport function createServer(library: Library, config: Config) {\n const app = new Hono();\n\n // Health check route\n app.route(\"/health\", healthRoute);\n\n // References API routes\n const referencesRoute = createReferencesRoute(library);\n app.route(\"/api/references\", referencesRoute);\n\n // Add references route\n const addRoute = createAddRoute(library, config);\n app.route(\"/api/add\", addRoute);\n\n // Cite route\n const citeRoute = createCiteRoute(library);\n app.route(\"/api/cite\", citeRoute);\n\n // List route\n const listRoute = createListRoute(library);\n app.route(\"/api/list\", listRoute);\n\n // Search route\n const searchRoute = createSearchRoute(library);\n app.route(\"/api/search\", searchRoute);\n\n return app;\n}\n\n/**\n * Start a server with file watcher for automatic library reload.\n * Uses the same pattern as MCP server file monitoring.\n * @param libraryPath - Path to the library file\n * @param config - Configuration for the server\n * @returns Server with file watcher result\n */\nexport async function startServerWithFileWatcher(\n libraryPath: string,\n config: Config\n): Promise<ServerWithFileWatcherResult> {\n // Load library\n const library = await Library.load(libraryPath);\n\n // Create the Hono app\n const app = createServer(library, config);\n\n // Create and start file watcher\n const fileWatcher = new FileWatcher(libraryPath, {\n debounceMs: config.watch.debounceMs,\n maxRetries: config.watch.maxRetries,\n retryDelayMs: config.watch.retryIntervalMs,\n pollIntervalMs: config.watch.pollIntervalMs,\n });\n\n // Listen for file changes\n // Library.reload() handles self-write detection via hash comparison\n fileWatcher.on(\"change\", () => {\n library.reload().catch((error) => {\n // Log error but don't crash - library continues with previous state\n console.error(\"Failed to reload library:\", error);\n });\n });\n\n await fileWatcher.start();\n\n // Create dispose function\n const dispose = async (): Promise<void> => {\n fileWatcher.close();\n };\n\n return {\n app,\n library,\n fileWatcher,\n dispose,\n };\n}\n"],"names":["result","cite","DOI_URL_PREFIXES","identifiers","search","sorted","sortByRelevance"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index-4KSTJ3rp.js","sources":["../../src/features/operations/update.ts","../../src/features/format/citation-fallback.ts","../../src/features/format/citation-csl.ts","../../src/features/pagination/sorter.ts","../../src/features/pagination/paginate.ts","../../src/config/csl-styles.ts","../../src/features/operations/remove.ts","../../src/features/import/cache.ts","../../src/features/import/normalizer.ts","../../src/features/import/detector.ts","../../src/features/import/rate-limiter.ts","../../src/features/import/fetcher.ts","../../src/features/import/parser.ts","../../src/features/import/importer.ts","../../src/features/operations/add.ts","../../src/server/routes/add.ts","../../src/features/operations/cite.ts","../../src/server/routes/cite.ts","../../src/server/routes/health.ts","../../src/features/operations/list.ts","../../src/server/routes/list.ts","../../src/server/routes/references.ts","../../src/features/operations/search.ts","../../src/server/routes/search.ts","../../src/server/index.ts"],"sourcesContent":["import type { CslItem } from \"../../core/csl-json/types.js\";\nimport type { ILibrary, IdentifierType } from \"../../core/library-interface.js\";\n\n/**\n * Options for updateReference operation\n */\nexport interface UpdateOperationOptions {\n /** Reference ID or UUID */\n identifier: string;\n /** Identifier type: 'id' (default), 'uuid', 'doi', 'pmid', or 'isbn' */\n idType?: IdentifierType;\n /** Partial updates to apply to the reference */\n updates: Partial<CslItem>;\n /** How to handle ID collision: 'fail' (default) or 'suffix' */\n onIdCollision?: \"fail\" | \"suffix\";\n}\n\n/**\n * Result of updateReference operation\n */\nexport interface UpdateOperationResult {\n /** Whether the update was successful */\n updated: boolean;\n /** The updated item (if successful) */\n item?: CslItem;\n /** True if ID collision occurred (only when updated=false and onIdCollision='fail') */\n idCollision?: boolean;\n /** True if the ID was changed due to collision resolution */\n idChanged?: boolean;\n /** The new ID after collision resolution (only when idChanged=true) */\n newId?: string;\n}\n\n/**\n * Update a reference in the library.\n *\n * @param library - The library to update\n * @param options - Update options including identifier, updates, and collision handling\n * @returns Result indicating success and the updated item\n */\nexport async function updateReference(\n library: ILibrary,\n options: UpdateOperationOptions\n): Promise<UpdateOperationResult> {\n const { identifier, idType = \"id\", updates, onIdCollision = \"fail\" } = options;\n\n // Update the reference using unified update() method\n const updateResult = await library.update(identifier, updates, { idType, onIdCollision });\n\n if (!updateResult.updated) {\n const result: UpdateOperationResult = { updated: false };\n if (updateResult.idCollision) {\n result.idCollision = true;\n }\n return result;\n }\n\n // Save the library\n await library.save();\n\n // Build result from UpdateResult (item is now included)\n const result: UpdateOperationResult = { updated: true };\n\n if (updateResult.item) {\n result.item = updateResult.item;\n }\n\n if (updateResult.idChanged && updateResult.newId) {\n result.idChanged = true;\n result.newId = updateResult.newId;\n }\n\n return result;\n}\n","import type { CslItem } from \"../../core/csl-json/types.js\";\n\n/**\n * Extract first author name with initial\n * Returns \"Family G\" or \"Family\" if no given name\n */\nfunction formatFirstAuthor(item: CslItem): string {\n if (!item.author || item.author.length === 0) {\n return \"Unknown\";\n }\n\n const firstAuthor = item.author[0];\n if (!firstAuthor) {\n return \"Unknown\";\n }\n\n const family = firstAuthor.family || \"Unknown\";\n const givenInitial = firstAuthor.given ? firstAuthor.given[0] : \"\";\n\n if (givenInitial) {\n return `${family} ${givenInitial}`;\n }\n return family;\n}\n\n/**\n * Check if item has multiple authors\n */\nfunction hasMultipleAuthors(item: CslItem): boolean {\n return (item.author?.length || 0) > 1;\n}\n\n/**\n * Extract year from CSL-JSON issued field\n */\nfunction extractYear(item: CslItem): string {\n if (item.issued?.[\"date-parts\"]?.[0]?.[0]) {\n return String(item.issued[\"date-parts\"][0][0]);\n }\n return \"n.d.\";\n}\n\n/**\n * Get journal abbreviation (prefer short title)\n */\nfunction getJournalAbbrev(item: CslItem): string {\n const containerTitleShort = (item as Record<string, unknown>)[\"container-title-short\"];\n if (typeof containerTitleShort === \"string\") {\n return containerTitleShort;\n }\n return item[\"container-title\"] || \"\";\n}\n\n/**\n * Format volume/issue/pages section\n * Returns formats like: \"10(2):123-145\", \"10:123-145\", \"10(2)\", \"10\", or \"\"\n */\nfunction formatVolumeIssuePage(item: CslItem): string {\n const volume = item.volume;\n const issue = item.issue;\n const page = item.page;\n\n if (!volume && !issue && !page) {\n return \"\";\n }\n\n let result = \"\";\n\n if (volume) {\n result += volume;\n if (issue) {\n result += `(${issue})`;\n }\n if (page) {\n result += `:${page}`;\n }\n } else if (page) {\n result += page;\n }\n\n return result;\n}\n\n/**\n * Get identifier (PMID > DOI > URL priority)\n */\nfunction getIdentifier(item: CslItem): string {\n if (item.PMID) {\n return `PMID:${item.PMID}`;\n }\n if (item.DOI) {\n return `DOI:${item.DOI}`;\n }\n if (item.URL) {\n return item.URL;\n }\n return \"\";\n}\n\n/**\n * Format a single bibliography entry\n */\nfunction formatBibliographyEntry(item: CslItem): string {\n const parts: string[] = [];\n\n // Author\n const author = formatFirstAuthor(item);\n const etAl = hasMultipleAuthors(item) ? \" et al\" : \"\";\n parts.push(`${author}${etAl}.`);\n\n // Journal\n const journal = getJournalAbbrev(item);\n if (journal) {\n parts.push(`${journal}.`);\n }\n\n // Year and volume/issue/pages\n const year = extractYear(item);\n const volumeIssuePage = formatVolumeIssuePage(item);\n\n if (volumeIssuePage) {\n parts.push(`${year};${volumeIssuePage}.`);\n } else {\n parts.push(`${year}.`);\n }\n\n // Identifier\n const identifier = getIdentifier(item);\n if (identifier) {\n parts.push(`${identifier}.`);\n }\n\n // Title\n if (item.title) {\n parts.push(`${item.title}.`);\n }\n\n return parts.join(\" \");\n}\n\n/**\n * Get first author family name only (for in-text citations)\n */\nfunction getFirstAuthorFamilyName(item: CslItem): string {\n if (!item.author || item.author.length === 0) {\n return \"Unknown\";\n }\n\n const firstAuthor = item.author[0];\n if (!firstAuthor) {\n return \"Unknown\";\n }\n\n return firstAuthor.family || \"Unknown\";\n}\n\n/**\n * Format a single in-text citation (without parentheses)\n * Returns \"Family et al, YYYY\" or \"Family, YYYY\"\n */\nfunction formatInTextEntry(item: CslItem): string {\n const author = getFirstAuthorFamilyName(item);\n const etAl = hasMultipleAuthors(item) ? \" et al\" : \"\";\n const year = extractYear(item);\n\n return `${author}${etAl}, ${year}`;\n}\n\n/**\n * Format CSL-JSON items as simplified AMA-like bibliography entries.\n *\n * Format: FirstAuthor [et al]. JournalAbbrev. YYYY;volume(issue):pages. PMID:xxxxx [or DOI:xxxxx]. Title.\n *\n * Multiple items are separated by double newlines.\n *\n * @param items - Array of CSL-JSON items\n * @returns Formatted bibliography entries separated by double newlines\n */\nexport function formatBibliography(items: CslItem[]): string {\n if (items.length === 0) {\n return \"\";\n }\n\n return items.map(formatBibliographyEntry).join(\"\\n\\n\");\n}\n\n/**\n * Format CSL-JSON items as simplified in-text citations.\n *\n * Format: (FirstAuthor et al, YYYY)\n *\n * Multiple items are separated by semicolons and enclosed in parentheses.\n *\n * @param items - Array of CSL-JSON items\n * @returns Formatted in-text citation(s) enclosed in parentheses\n */\nexport function formatInText(items: CslItem[]): string {\n if (items.length === 0) {\n return \"\";\n }\n\n const citations = items.map(formatInTextEntry).join(\"; \");\n return `(${citations})`;\n}\n","import { Cite, plugins } from \"@citation-js/core\";\nimport \"@citation-js/plugin-csl\";\nimport type { CslItem } from \"../../core/csl-json/types.js\";\nimport { formatBibliography, formatInText } from \"./citation-fallback.js\";\n\n/**\n * Options for CSL citation formatting\n */\nexport type CitationFormatOptions = {\n /**\n * CSL style name (e.g., 'apa', 'vancouver', 'chicago')\n * @default 'apa'\n */\n style?: string;\n\n /**\n * Custom CSL style XML content.\n * When provided, this XML is registered and used instead of built-in styles.\n */\n styleXml?: string;\n\n /**\n * Output format: text, html, or rtf\n * @default 'text'\n */\n format?: \"text\" | \"html\" | \"rtf\";\n\n /**\n * Locale code (e.g., 'en-US', 'en-GB')\n * @default 'en-US'\n */\n locale?: string;\n};\n\n/**\n * Register a custom CSL style with citation-js.\n * Returns the style name to use for formatting.\n * @throws Error if CSL XML is invalid or malformed\n */\nfunction registerCustomStyle(styleName: string, styleXml: string): string {\n // Basic XML validation\n if (!styleXml.includes(\"<style\") || !styleXml.includes(\"</style>\")) {\n throw new Error(\n \"Invalid CSL file: Missing <style> element. The file may be malformed or not a valid CSL style.\"\n );\n }\n\n // Check for required CSL sections\n const hasCitation = styleXml.includes(\"<citation\") || styleXml.includes(\"<citation>\");\n const hasBibliography = styleXml.includes(\"<bibliography\") || styleXml.includes(\"<bibliography>\");\n if (!hasCitation && !hasBibliography) {\n throw new Error(\n \"Invalid CSL file: Missing <citation> or <bibliography> section. \" +\n \"A valid CSL style must define at least one of these sections.\"\n );\n }\n\n try {\n const config = plugins.config.get(\"@csl\");\n config.templates.add(styleName, styleXml);\n return styleName;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to register CSL style '${styleName}': ${message}`);\n }\n}\n\n/**\n * Format CSL-JSON items as bibliography using CSL processor.\n * Falls back to simplified format if CSL processing fails.\n *\n * @param items - Array of CSL-JSON items\n * @param options - Formatting options\n * @returns Formatted bibliography entries\n */\nexport function formatBibliographyCSL(items: CslItem[], options: CitationFormatOptions): string {\n // Handle empty array\n if (items.length === 0) {\n return \"\";\n }\n\n // Set defaults\n let style = options.style || \"apa\";\n const format = options.format || \"text\";\n const locale = options.locale || \"en-US\";\n\n // Register custom style if XML is provided\n if (options.styleXml) {\n style = registerCustomStyle(style, options.styleXml);\n }\n\n try {\n // Create Cite instance with CSL-JSON data\n const cite = new Cite(items);\n\n // Format as bibliography\n const result = cite.format(\"bibliography\", {\n format,\n template: style,\n lang: locale,\n });\n\n return result;\n } catch (error) {\n // Fall back to simplified format on any error\n const errorMessage = error instanceof Error ? error.message : String(error);\n process.stderr.write(\n `Warning: CSL processing failed (style: ${style}), falling back to simplified format: ${errorMessage}\\n`\n );\n return formatBibliography(items);\n }\n}\n\n/**\n * Format CSL-JSON items as in-text citations using CSL processor.\n * Falls back to simplified format if CSL processing fails.\n *\n * @param items - Array of CSL-JSON items\n * @param options - Formatting options\n * @returns Formatted in-text citation(s)\n */\nexport function formatInTextCSL(items: CslItem[], options: CitationFormatOptions): string {\n // Handle empty array\n if (items.length === 0) {\n return \"\";\n }\n\n // Set defaults\n let style = options.style || \"apa\";\n const format = options.format || \"text\";\n const locale = options.locale || \"en-US\";\n\n // Register custom style if XML is provided\n if (options.styleXml) {\n style = registerCustomStyle(style, options.styleXml);\n }\n\n try {\n // Create Cite instance with CSL-JSON data\n const cite = new Cite(items);\n\n // Format as in-text citation\n const result = cite.format(\"citation\", {\n format,\n template: style,\n lang: locale,\n });\n\n return result;\n } catch (error) {\n // Fall back to simplified format on any error\n const errorMessage = error instanceof Error ? error.message : String(error);\n process.stderr.write(\n `Warning: CSL processing failed (style: ${style}), falling back to simplified format: ${errorMessage}\\n`\n );\n return formatInText(items);\n }\n}\n","/**\n * Reference sorter\n */\n\nimport type { CslItem } from \"../../core/csl-json/types.js\";\nimport type { SortField, SortOrder } from \"./types.js\";\n\n/**\n * Extract created_at timestamp from item, returns epoch (0) if missing\n */\nfunction getCreatedAt(item: CslItem): number {\n const createdAt = item.custom?.created_at;\n if (!createdAt) return 0;\n return new Date(createdAt).getTime();\n}\n\n/**\n * Extract updated timestamp from item, falls back to created_at\n */\nfunction getUpdatedAt(item: CslItem): number {\n const timestamp = item.custom?.timestamp;\n if (timestamp) return new Date(timestamp).getTime();\n return getCreatedAt(item);\n}\n\n/**\n * Extract published date as comparable number\n * Returns 0 (epoch) if missing\n */\nfunction getPublishedDate(item: CslItem): number {\n const dateParts = item.issued?.[\"date-parts\"]?.[0];\n if (!dateParts || dateParts.length === 0) return 0;\n\n const year = dateParts[0] ?? 0;\n const month = dateParts[1] ?? 1;\n const day = dateParts[2] ?? 1;\n\n return new Date(year, month - 1, day).getTime();\n}\n\n/**\n * Extract first author's sortable name\n * Returns \"Anonymous\" if no author\n */\nfunction getAuthorName(item: CslItem): string {\n const firstAuthor = item.author?.[0];\n if (!firstAuthor) return \"Anonymous\";\n\n return firstAuthor.family ?? firstAuthor.literal ?? \"Anonymous\";\n}\n\n/**\n * Extract title, returns empty string if missing\n */\nfunction getTitle(item: CslItem): string {\n return item.title ?? \"\";\n}\n\n/**\n * Get sort value for a given field\n */\nfunction getSortValue(item: CslItem, field: SortField): number | string {\n switch (field) {\n case \"created\":\n return getCreatedAt(item);\n case \"updated\":\n return getUpdatedAt(item);\n case \"published\":\n return getPublishedDate(item);\n case \"author\":\n return getAuthorName(item).toLowerCase();\n case \"title\":\n return getTitle(item).toLowerCase();\n }\n}\n\n/**\n * Compare function for sorting\n */\nfunction compareValues(a: number | string, b: number | string, order: SortOrder): number {\n const multiplier = order === \"desc\" ? -1 : 1;\n\n if (typeof a === \"number\" && typeof b === \"number\") {\n return (a - b) * multiplier;\n }\n\n const strA = String(a);\n const strB = String(b);\n return strA.localeCompare(strB) * multiplier;\n}\n\n/**\n * Sort references by the specified field and order.\n * Uses secondary sort: created (desc), then id (asc) for stability.\n *\n * @param items - References to sort\n * @param sort - Sort field\n * @param order - Sort order\n * @returns Sorted references (new array, does not mutate input)\n */\nexport function sortReferences(items: CslItem[], sort: SortField, order: SortOrder): CslItem[] {\n return [...items].sort((a, b) => {\n // Primary sort\n const aValue = getSortValue(a, sort);\n const bValue = getSortValue(b, sort);\n const primaryCompare = compareValues(aValue, bValue, order);\n\n if (primaryCompare !== 0) return primaryCompare;\n\n // Secondary sort: created (desc)\n const aCreated = getCreatedAt(a);\n const bCreated = getCreatedAt(b);\n const createdCompare = bCreated - aCreated; // desc\n\n if (createdCompare !== 0) return createdCompare;\n\n // Tertiary sort: id (asc) for stability\n return a.id.localeCompare(b.id);\n });\n}\n","/**\n * Pagination applier\n */\n\nexport interface PaginateOptions {\n limit?: number;\n offset?: number;\n}\n\nexport interface PaginateResult<T> {\n items: T[];\n nextOffset: number | null;\n}\n\n/**\n * Apply pagination to an array of items.\n *\n * @param items - Items to paginate\n * @param options - Pagination options (limit=0 or undefined means unlimited)\n * @returns Paginated items with nextOffset (null if no more items)\n */\nexport function paginate<T>(items: T[], options: PaginateOptions): PaginateResult<T> {\n const offset = options.offset ?? 0;\n const limit = options.limit ?? 0;\n\n // Validate inputs\n if (limit < 0) {\n throw new Error(\"limit must be non-negative\");\n }\n if (offset < 0) {\n throw new Error(\"offset must be non-negative\");\n }\n\n const isUnlimited = limit === 0;\n\n // Apply offset\n const afterOffset = items.slice(offset);\n\n // Apply limit (0 means unlimited)\n const paginatedItems = isUnlimited ? afterOffset : afterOffset.slice(0, limit);\n\n // Calculate nextOffset\n let nextOffset: number | null = null;\n if (!isUnlimited && paginatedItems.length > 0) {\n const nextPosition = offset + paginatedItems.length;\n if (nextPosition < items.length) {\n nextOffset = nextPosition;\n }\n }\n\n return {\n items: paginatedItems,\n nextOffset,\n };\n}\n","/**\n * CSL Style Management\n *\n * Handles resolution and loading of CSL (Citation Style Language) style files.\n *\n * Style Resolution Order:\n * 1. --csl-file <path> (exact file path)\n * 2. Built-in style matching --style <name>\n * 3. Search in csl_directory paths (in array order)\n * 4. Default style from config (default_style)\n * 5. \"apa\" (hardcoded default)\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n\n/**\n * Built-in styles available in @citation-js/plugin-csl\n * These can be used directly without loading external files\n */\nexport const BUILTIN_STYLES = [\"apa\", \"vancouver\", \"harvard\"] as const;\n\nexport type BuiltinStyleName = (typeof BUILTIN_STYLES)[number];\n\n/**\n * Check if a style name is a built-in style\n */\nexport function isBuiltinStyle(styleName: string): styleName is BuiltinStyleName {\n return BUILTIN_STYLES.includes(styleName as BuiltinStyleName);\n}\n\nexport interface StyleResolutionOptions {\n /**\n * Exact path to CSL file (from --csl-file option)\n * Takes highest priority\n */\n cslFile?: string;\n\n /**\n * Style name to resolve (from --style option)\n */\n style?: string;\n\n /**\n * Directory or directories to search for custom CSL files\n * (from csl_directory config)\n * Can be a single string or array of strings\n */\n cslDirectory?: string | string[];\n\n /**\n * Default style to use if specified style not found\n * (from default_style config)\n */\n defaultStyle?: string;\n}\n\nexport interface StyleResolution {\n /**\n * Type of resolution: \"builtin\" for citation-js built-in styles,\n * \"custom\" for external CSL files\n */\n type: \"builtin\" | \"custom\";\n\n /**\n * The resolved style name (for built-in) or identifier (for custom)\n */\n styleName: string;\n\n /**\n * CSL XML content (only for custom styles)\n */\n styleXml?: string;\n}\n\n/**\n * Expand tilde (~) in path to home directory\n */\nfunction expandTilde(filePath: string): string {\n if (filePath.startsWith(\"~/\")) {\n const home = process.env.HOME || process.env.USERPROFILE || \"\";\n return path.join(home, filePath.slice(2));\n }\n return filePath;\n}\n\n/**\n * Load CSL style file content from the given path\n *\n * @param stylePath - Path to the CSL style file\n * @returns Content of the CSL style file (XML string)\n * @throws Error if file cannot be read\n */\nexport function loadCSLStyleFile(stylePath: string): string {\n return fs.readFileSync(stylePath, \"utf-8\");\n}\n\n/**\n * Resolve the style based on resolution options\n *\n * Resolution order:\n * 1. cslFile (exact path) - throws if doesn't exist\n * 2. Built-in style matching style name\n * 3. Search in csl_directory paths (in order)\n * 4. Default style (defaultStyle) - if built-in\n * 5. \"apa\" (hardcoded fallback)\n *\n * @param options - Style resolution options\n * @returns StyleResolution with type, styleName, and optional styleXml\n * @throws Error if cslFile is specified but doesn't exist\n */\nexport function resolveStyle(options: StyleResolutionOptions): StyleResolution {\n const { cslFile, style, cslDirectory, defaultStyle } = options;\n\n // 1. If cslFile is specified, use it (highest priority)\n if (cslFile) {\n if (!fs.existsSync(cslFile)) {\n throw new Error(`CSL file '${cslFile}' not found`);\n }\n const styleXml = loadCSLStyleFile(cslFile);\n const styleName = path.basename(cslFile, \".csl\");\n return {\n type: \"custom\",\n styleName,\n styleXml,\n };\n }\n\n // Determine which style name to try\n const styleToResolve = style || defaultStyle || \"apa\";\n\n // 2. Check if it's a built-in style\n if (isBuiltinStyle(styleToResolve)) {\n return {\n type: \"builtin\",\n styleName: styleToResolve,\n };\n }\n\n // 3. Search in csl_directory paths\n if (cslDirectory) {\n const directories = Array.isArray(cslDirectory) ? cslDirectory : [cslDirectory];\n\n for (const dir of directories) {\n const expandedDir = expandTilde(dir);\n const stylePath = path.join(expandedDir, `${styleToResolve}.csl`);\n\n if (fs.existsSync(stylePath)) {\n const styleXml = loadCSLStyleFile(stylePath);\n return {\n type: \"custom\",\n styleName: styleToResolve,\n styleXml,\n };\n }\n }\n }\n\n // 4. Fall back to default style if it's built-in\n if (defaultStyle && isBuiltinStyle(defaultStyle)) {\n return {\n type: \"builtin\",\n styleName: defaultStyle,\n };\n }\n\n // 5. Fall back to apa (hardcoded default)\n return {\n type: \"builtin\",\n styleName: \"apa\",\n };\n}\n","import { unlink } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { CslItem } from \"../../core/csl-json/types.js\";\nimport type { ILibrary, IdentifierType } from \"../../core/library-interface.js\";\nimport type { FulltextType } from \"../fulltext/index.js\";\n\n/**\n * Options for removeReference operation\n */\nexport interface RemoveOperationOptions {\n /** Reference ID or UUID */\n identifier: string;\n /** Identifier type: 'id' (default), 'uuid', 'doi', 'pmid', or 'isbn' */\n idType?: IdentifierType;\n /** Directory containing fulltext files (required if deleteFulltext is true) */\n fulltextDirectory?: string;\n /** Whether to delete associated fulltext files */\n deleteFulltext?: boolean;\n}\n\n/**\n * Result of removeReference operation\n */\nexport interface RemoveResult {\n /** Whether the reference was removed */\n removed: boolean;\n /** The removed item (if found and removal succeeded) */\n removedItem?: CslItem;\n /** Fulltext types that were deleted (only when deleteFulltext=true) */\n deletedFulltextTypes?: FulltextType[];\n}\n\n/**\n * Get fulltext attachment types from a CSL item.\n */\nexport function getFulltextAttachmentTypes(item: CslItem): FulltextType[] {\n const types: FulltextType[] = [];\n const fulltext = item.custom?.fulltext;\n\n if (fulltext?.pdf) {\n types.push(\"pdf\");\n }\n if (fulltext?.markdown) {\n types.push(\"markdown\");\n }\n\n return types;\n}\n\n/**\n * Delete fulltext files associated with an item.\n */\nasync function deleteFulltextFiles(item: CslItem, fulltextDirectory: string): Promise<void> {\n const fulltext = item.custom?.fulltext;\n if (!fulltext) {\n return;\n }\n\n const filesToDelete: string[] = [];\n\n if (fulltext.pdf) {\n filesToDelete.push(join(fulltextDirectory, fulltext.pdf));\n }\n if (fulltext.markdown) {\n filesToDelete.push(join(fulltextDirectory, fulltext.markdown));\n }\n\n for (const filePath of filesToDelete) {\n try {\n await unlink(filePath);\n } catch {\n // Ignore errors (file might not exist)\n }\n }\n}\n\n/**\n * Remove a reference from the library.\n *\n * @param library - The library to remove from\n * @param options - Remove options including identifier and lookup method\n * @returns Result indicating success and the removed item\n */\nexport async function removeReference(\n library: ILibrary,\n options: RemoveOperationOptions\n): Promise<RemoveResult> {\n const { identifier, idType = \"id\", fulltextDirectory, deleteFulltext = false } = options;\n\n const result = await library.remove(identifier, { idType });\n\n if (!result.removed || !result.removedItem) {\n return { removed: false };\n }\n\n // Delete fulltext files if requested\n let deletedFulltextTypes: FulltextType[] | undefined;\n if (deleteFulltext && fulltextDirectory) {\n deletedFulltextTypes = getFulltextAttachmentTypes(result.removedItem);\n if (deletedFulltextTypes.length > 0) {\n await deleteFulltextFiles(result.removedItem, fulltextDirectory);\n }\n }\n\n await library.save();\n\n return {\n removed: true,\n removedItem: result.removedItem,\n ...(deletedFulltextTypes && deletedFulltextTypes.length > 0 && { deletedFulltextTypes }),\n };\n}\n","/**\n * Response cache for PMID and DOI metadata\n *\n * In-memory cache with TTL to avoid redundant API calls.\n * - Per ADR-001: No persistent cache files on disk\n * - Cache is warm during interactive sessions (server mode)\n * - CLI invocations start fresh\n */\n\nimport type { CslItem } from \"../../core/csl-json/types.js\";\n\n/** Default TTL: 1 hour */\nconst DEFAULT_TTL_MS = 60 * 60 * 1000;\n\n/**\n * Cache configuration\n */\nexport interface CacheConfig {\n /** Time-to-live in milliseconds (default: 1 hour) */\n ttlMs?: number;\n}\n\n/**\n * Cache entry with timestamp and TTL\n */\ninterface CacheEntry {\n item: CslItem;\n cachedAt: number;\n ttlMs: number;\n}\n\n/** PMID cache: Map<pmid, CacheEntry> */\nconst pmidCache = new Map<string, CacheEntry>();\n\n/** DOI cache: Map<doi, CacheEntry> */\nconst doiCache = new Map<string, CacheEntry>();\n\n/** ISBN cache: Map<isbn, CacheEntry> */\nconst isbnCache = new Map<string, CacheEntry>();\n\n/**\n * Check if a cache entry is still valid\n */\nfunction isEntryValid(entry: CacheEntry): boolean {\n const now = Date.now();\n return now - entry.cachedAt < entry.ttlMs;\n}\n\n/**\n * Get item from cache if valid\n */\nfunction getFromCache(cache: Map<string, CacheEntry>, key: string): CslItem | undefined {\n const entry = cache.get(key);\n if (!entry) {\n return undefined;\n }\n if (!isEntryValid(entry)) {\n cache.delete(key);\n return undefined;\n }\n return entry.item;\n}\n\n/**\n * Store item in cache\n */\nfunction storeInCache(\n cache: Map<string, CacheEntry>,\n key: string,\n item: CslItem,\n config?: CacheConfig\n): void {\n const ttlMs = config?.ttlMs ?? DEFAULT_TTL_MS;\n cache.set(key, {\n item,\n cachedAt: Date.now(),\n ttlMs,\n });\n}\n\n/**\n * Get cached PMID result\n */\nexport function getPmidFromCache(pmid: string): CslItem | undefined {\n return getFromCache(pmidCache, pmid);\n}\n\n/**\n * Cache PMID result\n */\nexport function cachePmidResult(pmid: string, item: CslItem, config?: CacheConfig): void {\n storeInCache(pmidCache, pmid, item, config);\n}\n\n/**\n * Get cached DOI result\n */\nexport function getDoiFromCache(doi: string): CslItem | undefined {\n return getFromCache(doiCache, doi);\n}\n\n/**\n * Cache DOI result\n */\nexport function cacheDoiResult(doi: string, item: CslItem, config?: CacheConfig): void {\n storeInCache(doiCache, doi, item, config);\n}\n\n/**\n * Get cached ISBN result\n */\nexport function getIsbnFromCache(isbn: string): CslItem | undefined {\n return getFromCache(isbnCache, isbn);\n}\n\n/**\n * Cache ISBN result\n */\nexport function cacheIsbnResult(isbn: string, item: CslItem, config?: CacheConfig): void {\n storeInCache(isbnCache, isbn, item, config);\n}\n\n/**\n * Reset all caches (for test isolation)\n */\nexport function resetCache(): void {\n pmidCache.clear();\n doiCache.clear();\n isbnCache.clear();\n}\n","/**\n * DOI normalizer module\n *\n * Normalizes DOI identifiers by:\n * - Removing URL prefixes (doi.org, dx.doi.org)\n * - Trimming whitespace\n */\n\n/**\n * URL prefixes to remove from DOI\n */\nconst DOI_URL_PREFIXES = [\n \"https://doi.org/\",\n \"http://doi.org/\",\n \"https://dx.doi.org/\",\n \"http://dx.doi.org/\",\n];\n\n/**\n * Normalize a DOI identifier\n *\n * @param doi - DOI string, possibly with URL prefix\n * @returns Normalized DOI (10.xxx/xxx format)\n */\nexport function normalizeDoi(doi: string): string {\n // Trim whitespace\n const trimmed = doi.trim();\n\n if (!trimmed) {\n return \"\";\n }\n\n // Check for URL prefixes (case-insensitive)\n const lowerInput = trimmed.toLowerCase();\n\n for (const prefix of DOI_URL_PREFIXES) {\n if (lowerInput.startsWith(prefix.toLowerCase())) {\n // Remove the prefix while preserving the original case of the DOI\n return trimmed.slice(prefix.length);\n }\n }\n\n // No prefix found, return as-is\n return trimmed;\n}\n\n/**\n * Normalizes a PMID by removing the optional \"PMID:\" prefix and trimming whitespace.\n *\n * Supported formats:\n * - \"12345678\" -> \"12345678\"\n * - \"PMID:12345678\" -> \"12345678\"\n * - \"pmid:12345678\" -> \"12345678\"\n * - \"PMID: 12345678\" -> \"12345678\" (space after colon)\n *\n * @param pmid - The PMID string to normalize\n * @returns The normalized PMID (digits only) or empty string if invalid\n */\nexport function normalizePmid(pmid: string): string {\n // Trim whitespace\n const trimmed = pmid.trim();\n\n if (!trimmed) {\n return \"\";\n }\n\n // Remove \"PMID:\" prefix (case-insensitive, optional whitespace after colon)\n const normalized = trimmed.replace(/^pmid:\\s*/i, \"\");\n\n return normalized.trim();\n}\n\n/**\n * Normalizes an ISBN by removing the \"ISBN:\" prefix, hyphens, spaces, and uppercasing X.\n *\n * Supported formats:\n * - \"ISBN:978-4-00-000000-0\" -> \"9784000000000\"\n * - \"isbn:4-00-000000-0\" -> \"4000000000\"\n * - \"ISBN: 978 4 00 000000 0\" -> \"9784000000000\"\n * - \"ISBN:400000000x\" -> \"400000000X\" (uppercase X)\n *\n * @param isbn - The ISBN string to normalize\n * @returns The normalized ISBN (digits only, X uppercase at end for ISBN-10) or empty string if invalid\n */\nexport function normalizeIsbn(isbn: string): string {\n // Trim whitespace\n const trimmed = isbn.trim();\n\n if (!trimmed) {\n return \"\";\n }\n\n // Check for ISBN: prefix (case-insensitive)\n if (!/^isbn:/i.test(trimmed)) {\n return \"\";\n }\n\n // Remove \"ISBN:\" prefix (case-insensitive, optional whitespace after colon)\n let normalized = trimmed.replace(/^isbn:\\s*/i, \"\");\n\n // Remove hyphens and spaces\n normalized = normalized.replace(/[-\\s]/g, \"\");\n\n // Uppercase X (for ISBN-10 check digit)\n normalized = normalized.toUpperCase();\n\n return normalized;\n}\n","/**\n * Format detection module for multi-format import\n *\n * Detects input format based on:\n * - File extension (.json, .bib, .ris)\n * - Content patterns (JSON, BibTeX, RIS)\n * - Identifier patterns (PMID, DOI)\n * - Multiple whitespace-separated identifiers\n */\n\nimport { normalizeIsbn, normalizePmid } from \"./normalizer.js\";\n\n/**\n * Supported input formats\n */\nexport type InputFormat =\n | \"json\"\n | \"bibtex\"\n | \"ris\"\n | \"nbib\"\n | \"pmid\"\n | \"doi\"\n | \"isbn\"\n | \"identifiers\"\n | \"unknown\";\n\n/**\n * Extension to format mapping\n */\nconst EXTENSION_MAP: Record<string, InputFormat> = {\n \".json\": \"json\",\n \".bib\": \"bibtex\",\n \".ris\": \"ris\",\n \".nbib\": \"nbib\",\n};\n\n/**\n * DOI URL prefixes to strip\n */\nconst DOI_URL_PREFIXES = [\n \"https://doi.org/\",\n \"http://doi.org/\",\n \"https://dx.doi.org/\",\n \"http://dx.doi.org/\",\n];\n\n/**\n * Detect the format of the given input\n *\n * @param input - File path, identifier, or empty string for stdin\n * @param content - Optional content to analyze (for stdin or unknown extension)\n * @returns Detected format\n */\nexport function detectFormat(input: string, content?: string): InputFormat {\n // 1. Try extension-based detection first\n const extFormat = detectByExtension(input);\n if (extFormat !== \"unknown\") {\n return extFormat;\n }\n\n // 2. If content provided, try content-based detection\n if (content !== undefined) {\n const contentFormat = detectByContent(content);\n if (contentFormat !== \"unknown\") {\n return contentFormat;\n }\n }\n\n // 3. Try identifier detection on input string\n if (input.length > 0) {\n const identifierFormat = detectIdentifier(input);\n if (identifierFormat !== \"unknown\") {\n return identifierFormat;\n }\n }\n\n return \"unknown\";\n}\n\n/**\n * Detect format based on file extension\n */\nexport function detectByExtension(input: string): InputFormat {\n if (!input) return \"unknown\";\n\n // Extract extension (last dot and onwards)\n const dotIndex = input.lastIndexOf(\".\");\n if (dotIndex === -1 || dotIndex === input.length - 1) {\n return \"unknown\";\n }\n\n const ext = input.slice(dotIndex).toLowerCase();\n return EXTENSION_MAP[ext] ?? \"unknown\";\n}\n\n/**\n * Detect format based on content patterns\n */\nexport function detectByContent(content: string): InputFormat {\n const trimmed = content.trim();\n if (!trimmed) return \"unknown\";\n\n // JSON: starts with [ or {\n if (trimmed.startsWith(\"[\") || trimmed.startsWith(\"{\")) {\n return \"json\";\n }\n\n // BibTeX: starts with @\n if (trimmed.startsWith(\"@\")) {\n return \"bibtex\";\n }\n\n // RIS: starts with TY - (tag format)\n if (trimmed.startsWith(\"TY -\")) {\n return \"ris\";\n }\n\n // NBIB (PubMed MEDLINE): starts with PMID-\n if (trimmed.startsWith(\"PMID-\")) {\n return \"nbib\";\n }\n\n // Check if content is multiple identifiers\n return detectIdentifier(trimmed);\n}\n\n/**\n * Detect if input is an identifier (PMID, DOI, ISBN) or multiple identifiers\n */\nfunction detectIdentifier(input: string): InputFormat {\n // Split by whitespace\n const parts = input.split(/\\s+/).filter((p) => p.length > 0);\n\n if (parts.length === 0) {\n return \"unknown\";\n }\n\n // Check each part\n const formats: (\"pmid\" | \"doi\" | \"isbn\")[] = [];\n for (const part of parts) {\n const format = detectSingleIdentifier(part);\n if (format === \"unknown\") {\n // If any part is not a valid identifier, return unknown\n return \"unknown\";\n }\n formats.push(format);\n }\n\n // Single identifier returns its specific format\n if (formats.length === 1) {\n // formats[0] is guaranteed to exist when length === 1\n return formats[0] as \"pmid\" | \"doi\" | \"isbn\";\n }\n\n // Multiple valid identifiers\n return \"identifiers\";\n}\n\n/**\n * Detect if a single string is a PMID, DOI, or ISBN\n */\nexport function detectSingleIdentifier(input: string): \"pmid\" | \"doi\" | \"isbn\" | \"unknown\" {\n // DOI: starts with 10. or is a DOI URL\n if (isDoi(input)) {\n return \"doi\";\n }\n\n // ISBN: requires ISBN: prefix\n if (isIsbn(input)) {\n return \"isbn\";\n }\n\n // PMID: numeric only (must be after ISBN check to avoid conflicts)\n if (isPmid(input)) {\n return \"pmid\";\n }\n\n return \"unknown\";\n}\n\n/**\n * Check if string is a valid DOI\n */\nexport function isDoi(input: string): boolean {\n // Check DOI URL formats\n for (const prefix of DOI_URL_PREFIXES) {\n if (input.toLowerCase().startsWith(prefix.toLowerCase())) {\n const remainder = input.slice(prefix.length);\n return isDoiFormat(remainder);\n }\n }\n\n // Check standard DOI format (10.xxx/xxx)\n return isDoiFormat(input);\n}\n\n/**\n * Check if string is a valid DOI format (10.xxx/xxx)\n */\nfunction isDoiFormat(input: string): boolean {\n // DOI starts with 10. followed by registrant code and suffix\n // Pattern: 10.{registrant}/{suffix}\n if (!input.startsWith(\"10.\")) {\n return false;\n }\n\n // Must have content after 10.\n if (input.length <= 3) {\n return false;\n }\n\n // Must have a slash after registrant code\n const slashIndex = input.indexOf(\"/\");\n if (slashIndex === -1 || slashIndex <= 3) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Check if string is a valid PMID (numeric only)\n */\nexport function isPmid(input: string): boolean {\n if (!input || input.length === 0) {\n return false;\n }\n\n // Normalize input (removes PMID: prefix if present)\n const normalized = normalizePmid(input);\n\n if (!normalized) {\n return false;\n }\n\n // PMID is all digits\n return /^\\d+$/.test(normalized);\n}\n\n/**\n * Check if string is a valid ISBN (requires ISBN: prefix)\n *\n * ISBN must have ISBN: prefix and be either:\n * - ISBN-13: 13 digits\n * - ISBN-10: 10 digits (last may be X)\n */\nexport function isIsbn(input: string): boolean {\n if (!input || input.length === 0) {\n return false;\n }\n\n // Normalize input (removes ISBN: prefix if present, hyphens, spaces)\n const normalized = normalizeIsbn(input);\n\n if (!normalized) {\n return false;\n }\n\n // Check length: ISBN-10 (10 chars) or ISBN-13 (13 chars)\n if (normalized.length !== 10 && normalized.length !== 13) {\n return false;\n }\n\n // ISBN-10: 9 digits + (digit or X)\n if (normalized.length === 10) {\n // First 9 must be digits, last can be digit or X\n if (!/^\\d{9}[\\dX]$/.test(normalized)) {\n return false;\n }\n return true;\n }\n\n // ISBN-13: all digits\n if (!/^\\d{13}$/.test(normalized)) {\n return false;\n }\n\n return true;\n}\n","/**\n * Rate limiter module for API calls\n *\n * Uses factory + lazy initialization singleton pattern:\n * - RateLimiter class: Delay-based rate limiting with configurable requests/second\n * - getRateLimiter(api, config): Returns singleton per API type\n * - resetRateLimiters(): Clears singletons for test isolation\n */\n\n/**\n * API types supported by the rate limiter\n */\nexport type ApiType = \"pubmed\" | \"crossref\" | \"isbn\";\n\n/**\n * Configuration for rate limiter\n */\nexport interface RateLimiterConfig {\n pubmedApiKey?: string;\n}\n\n/**\n * Rate limiter interface\n */\nexport interface RateLimiter {\n readonly requestsPerSecond: number;\n readonly intervalMs: number;\n readonly lastRequestTime: number;\n acquire(): Promise<void>;\n}\n\n/**\n * Rate limit settings per API type\n */\nconst RATE_LIMITS = {\n pubmed: {\n withoutApiKey: 3, // 3 req/sec\n withApiKey: 10, // 10 req/sec\n },\n crossref: 50, // 50 req/sec\n isbn: 10, // 10 req/sec (conservative for Google Books API daily limit)\n} as const;\n\n/**\n * Internal rate limiter implementation\n */\nclass RateLimiterImpl implements RateLimiter {\n readonly requestsPerSecond: number;\n readonly intervalMs: number;\n private _lastRequestTime = 0;\n private _pending: Promise<void> = Promise.resolve();\n\n constructor(requestsPerSecond: number) {\n this.requestsPerSecond = requestsPerSecond;\n this.intervalMs = 1000 / requestsPerSecond;\n }\n\n get lastRequestTime(): number {\n return this._lastRequestTime;\n }\n\n async acquire(): Promise<void> {\n // Chain onto pending promise to ensure sequential processing\n this._pending = this._pending.then(() => this._acquireInternal());\n return this._pending;\n }\n\n private async _acquireInternal(): Promise<void> {\n const now = Date.now();\n const elapsed = now - this._lastRequestTime;\n const waitTime = Math.max(0, this.intervalMs - elapsed);\n\n if (waitTime > 0 && this._lastRequestTime > 0) {\n await this._delay(waitTime);\n }\n\n this._lastRequestTime = Date.now();\n }\n\n private _delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n\n/**\n * Singleton storage for rate limiters by API type\n */\nconst limiters = new Map<ApiType, RateLimiter>();\n\n/**\n * Create a new rate limiter instance\n */\nexport function createRateLimiter(options: {\n requestsPerSecond: number;\n}): RateLimiter {\n return new RateLimiterImpl(options.requestsPerSecond);\n}\n\n/**\n * Get singleton rate limiter for the specified API type\n *\n * Note: Configuration is only used on first call. Subsequent calls\n * return the existing singleton regardless of config changes.\n */\nexport function getRateLimiter(api: ApiType, config: RateLimiterConfig): RateLimiter {\n const existing = limiters.get(api);\n if (existing) {\n return existing;\n }\n\n const requestsPerSecond = getRequestsPerSecond(api, config);\n const limiter = createRateLimiter({ requestsPerSecond });\n limiters.set(api, limiter);\n\n return limiter;\n}\n\n/**\n * Determine requests per second based on API type and configuration\n */\nfunction getRequestsPerSecond(api: ApiType, config: RateLimiterConfig): number {\n switch (api) {\n case \"pubmed\":\n return config.pubmedApiKey ? RATE_LIMITS.pubmed.withApiKey : RATE_LIMITS.pubmed.withoutApiKey;\n case \"crossref\":\n return RATE_LIMITS.crossref;\n case \"isbn\":\n return RATE_LIMITS.isbn;\n }\n}\n\n/**\n * Reset all rate limiter singletons (for test isolation)\n */\nexport function resetRateLimiters(): void {\n limiters.clear();\n}\n","/**\n * Fetcher module for PMID and DOI metadata retrieval\n *\n * - PMID: Uses PMC Citation Exporter API (returns CSL-JSON directly)\n * - DOI: Uses citation-js plugin-doi (Cite.async)\n */\n\nimport { Cite } from \"@citation-js/core\";\nimport \"@citation-js/plugin-doi\";\nimport \"@citation-js/plugin-isbn\";\nimport { type CslItem, CslItemSchema } from \"../../core/csl-json/types.js\";\nimport { getRateLimiter } from \"./rate-limiter.js\";\n\n/** PMC Citation Exporter API base URL */\nconst PMC_API_BASE = \"https://pmc.ncbi.nlm.nih.gov/api/ctxp/v1/pubmed/\";\n\n/** Default timeout for API requests (10 seconds) */\nconst DEFAULT_TIMEOUT_MS = 10000;\n\n/** DOI pattern for validation */\nconst DOI_PATTERN = /^10\\.\\d{4,}(?:\\.\\d+)*\\/\\S+$/;\n\n/**\n * PubMed configuration for API requests\n */\nexport interface PubmedConfig {\n email?: string;\n apiKey?: string;\n}\n\n/**\n * Categorized failure reasons for JSON output\n */\nexport type FailureReason =\n | \"not_found\"\n | \"fetch_error\"\n | \"parse_error\"\n | \"validation_error\"\n | \"unknown\";\n\n/**\n * Result of fetching a single identifier\n */\nexport type FetchResult =\n | { success: true; item: CslItem }\n | { success: false; error: string; reason: FailureReason };\n\n/**\n * Result of fetching a PMID (includes pmid for tracking)\n */\nexport type PmidFetchResult =\n | { pmid: string; success: true; item: CslItem }\n | { pmid: string; success: false; error: string; reason: FailureReason };\n\n/**\n * Results of fetching multiple PMIDs\n */\nexport type FetchResults = PmidFetchResult[];\n\n/**\n * Build PMC API URL with query parameters\n */\nfunction buildPmcUrl(pmids: string[], config: PubmedConfig): string {\n const url = new URL(PMC_API_BASE);\n url.searchParams.set(\"format\", \"csl\");\n\n // Add each PMID as separate id parameter\n for (const pmid of pmids) {\n url.searchParams.append(\"id\", pmid);\n }\n\n if (config.email) {\n url.searchParams.set(\"email\", config.email);\n }\n if (config.apiKey) {\n url.searchParams.set(\"api_key\", config.apiKey);\n }\n\n return url.toString();\n}\n\n/**\n * Extract PMID from CSL-JSON item id field\n * PMC API returns id like \"pmid:12345678\"\n */\nfunction extractPmidFromId(id: string | undefined): string | undefined {\n if (!id) return undefined;\n const match = id.match(/^pmid:(\\d+)$/);\n return match?.[1];\n}\n\n/**\n * Fetch metadata for multiple PMIDs from PMC Citation Exporter API\n *\n * Uses batch API endpoint: /api/ctxp/v1/pubmed/?format=csl&id=1&id=2\n */\n\n/**\n * Parse raw API items and build maps of found items and validation errors\n */\nfunction parseRawItems(rawItems: unknown[]): {\n foundItems: Map<string, CslItem>;\n validationErrors: Map<string, string>;\n} {\n const foundItems = new Map<string, CslItem>();\n const validationErrors = new Map<string, string>();\n\n for (const rawItem of rawItems) {\n const parseResult = CslItemSchema.safeParse(rawItem);\n if (parseResult.success) {\n const pmid = extractPmidFromId(parseResult.data.id);\n if (pmid) {\n foundItems.set(pmid, parseResult.data);\n }\n } else {\n // Try to extract pmid even from invalid data for error reporting\n const maybeId = (rawItem as { id?: string })?.id;\n const pmid = extractPmidFromId(maybeId);\n if (pmid) {\n validationErrors.set(pmid, parseResult.error.message);\n }\n }\n }\n\n return { foundItems, validationErrors };\n}\n\n/**\n * Build fetch result for a single PMID\n */\nfunction buildPmidResult(\n pmid: string,\n foundItems: Map<string, CslItem>,\n validationErrors: Map<string, string>\n): PmidFetchResult {\n const item = foundItems.get(pmid);\n if (item) {\n return { pmid, success: true as const, item };\n }\n const validationError = validationErrors.get(pmid);\n if (validationError) {\n return {\n pmid,\n success: false as const,\n error: `Invalid CSL-JSON data: ${validationError}`,\n reason: \"validation_error\",\n };\n }\n return {\n pmid,\n success: false as const,\n error: `PMID ${pmid} not found`,\n reason: \"not_found\",\n };\n}\n\nexport async function fetchPmids(pmids: string[], config: PubmedConfig): Promise<FetchResults> {\n // Return empty array for empty input\n if (pmids.length === 0) {\n return [];\n }\n\n // Apply rate limiting\n const rateLimiterConfig = config.apiKey ? { pubmedApiKey: config.apiKey } : {};\n const rateLimiter = getRateLimiter(\"pubmed\", rateLimiterConfig);\n await rateLimiter.acquire();\n\n const url = buildPmcUrl(pmids, config);\n\n try {\n const response = await fetch(url, {\n method: \"GET\",\n signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS),\n });\n\n if (!response.ok) {\n // Return error for all PMIDs\n const errorMsg = `HTTP ${response.status}: ${response.statusText}`;\n return pmids.map((pmid) => ({\n pmid,\n success: false as const,\n error: errorMsg,\n reason: \"fetch_error\",\n }));\n }\n\n const data = await response.json();\n\n // Normalize response to array\n const rawItems: unknown[] = Array.isArray(data) ? data : [data];\n\n // Parse raw items and build results\n const { foundItems, validationErrors } = parseRawItems(rawItems);\n\n // Build results for each requested PMID\n return pmids.map((pmid) => buildPmidResult(pmid, foundItems, validationErrors));\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n return pmids.map((pmid) => ({\n pmid,\n success: false as const,\n error: errorMsg,\n reason: \"fetch_error\",\n }));\n }\n}\n\n/**\n * Fetch metadata for a DOI using citation-js\n *\n * Uses @citation-js/plugin-doi for content negotiation\n */\nexport async function fetchDoi(doi: string): Promise<FetchResult> {\n // Validate DOI format\n if (!DOI_PATTERN.test(doi)) {\n return {\n success: false,\n error: `Invalid DOI format: ${doi}`,\n reason: \"validation_error\",\n };\n }\n\n // Apply rate limiting (crossref)\n const rateLimiter = getRateLimiter(\"crossref\", {});\n await rateLimiter.acquire();\n\n try {\n // Use citation-js Cite.async for DOI resolution\n const cite = await Cite.async(doi);\n const rawItems = cite.get({ format: \"real\", type: \"json\" });\n\n if (!rawItems || !Array.isArray(rawItems) || rawItems.length === 0) {\n return {\n success: false,\n error: `No data returned for DOI ${doi}`,\n reason: \"not_found\",\n };\n }\n\n // Validate using zod schema\n const parseResult = CslItemSchema.safeParse(rawItems[0]);\n if (!parseResult.success) {\n return {\n success: false,\n error: `Invalid CSL-JSON data for DOI ${doi}: ${parseResult.error.message}`,\n reason: \"validation_error\",\n };\n }\n\n return { success: true, item: parseResult.data };\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n return {\n success: false,\n error: errorMsg,\n reason: \"fetch_error\",\n };\n }\n}\n\n/** ISBN-10 pattern: 9 digits + (digit or X) */\nconst ISBN10_PATTERN = /^\\d{9}[\\dX]$/;\n\n/** ISBN-13 pattern: 13 digits */\nconst ISBN13_PATTERN = /^\\d{13}$/;\n\n/**\n * Fetch metadata for an ISBN using Google Books API via citation-js\n *\n * @param isbn - Normalized ISBN (10 or 13 digits, no hyphens)\n * @returns FetchResult with CSL-JSON item or error\n */\nexport async function fetchIsbn(isbn: string): Promise<FetchResult> {\n // Validate ISBN format\n if (!ISBN10_PATTERN.test(isbn) && !ISBN13_PATTERN.test(isbn)) {\n return {\n success: false,\n error: `Invalid ISBN format: ${isbn}`,\n reason: \"validation_error\",\n };\n }\n\n // Apply rate limiting (google books - daily limit so we use a generic limiter)\n const rateLimiter = getRateLimiter(\"isbn\", {});\n await rateLimiter.acquire();\n\n try {\n // Use citation-js Cite.async for ISBN resolution\n const cite = await Cite.async(isbn);\n const rawItems = cite.get({ format: \"real\", type: \"json\" });\n\n if (!rawItems || !Array.isArray(rawItems) || rawItems.length === 0) {\n return {\n success: false,\n error: `No data returned for ISBN ${isbn}`,\n reason: \"not_found\",\n };\n }\n\n // Validate using zod schema\n const parseResult = CslItemSchema.safeParse(rawItems[0]);\n if (!parseResult.success) {\n return {\n success: false,\n error: `Invalid CSL-JSON data for ISBN ${isbn}: ${parseResult.error.message}`,\n reason: \"validation_error\",\n };\n }\n\n return { success: true, item: parseResult.data };\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n return {\n success: false,\n error: errorMsg,\n reason: \"fetch_error\",\n };\n }\n}\n","/**\n * Parser module for BibTeX and RIS formats\n *\n * Uses citation-js plugins for parsing:\n * - @citation-js/plugin-bibtex for BibTeX\n * - @citation-js/plugin-ris for RIS\n */\n\nimport { Cite } from \"@citation-js/core\";\nimport \"@citation-js/plugin-bibtex\";\nimport \"@citation-js/plugin-ris\";\nimport type { CslItem } from \"../../core/csl-json/types.js\";\n\n/**\n * Result of a parse operation\n */\nexport type ParseResult = {\n success: boolean;\n items: CslItem[];\n error?: string;\n};\n\n/**\n * Parse BibTeX content to CSL-JSON\n *\n * @param content - BibTeX content string\n * @returns Parse result with CSL-JSON items\n */\nexport function parseBibtex(content: string): ParseResult {\n return parseWithCitationJs(content, \"bibtex\");\n}\n\n/**\n * Parse RIS content to CSL-JSON\n *\n * @param content - RIS content string\n * @returns Parse result with CSL-JSON items\n */\nexport function parseRis(content: string): ParseResult {\n return parseWithCitationJs(content, \"ris\");\n}\n\n/**\n * NBIB to RIS tag mapping\n *\n * Maps PubMed MEDLINE tags to RIS equivalents\n */\nconst NBIB_TO_RIS_TAG_MAP: Record<string, string> = {\n PMID: \"AN\", // PubMed ID -> Accession Number\n TI: \"TI\", // Title -> Title\n FAU: \"AU\", // Full Author -> Author\n AU: \"AU\", // Author -> Author (short form, use FAU when available)\n JT: \"JO\", // Journal Title -> Journal Name\n TA: \"JA\", // Title Abbreviation -> Journal Abbreviation\n AB: \"AB\", // Abstract -> Abstract\n VI: \"VL\", // Volume -> Volume\n IP: \"IS\", // Issue/Part -> Issue Number\n PG: \"SP\", // Pagination -> Start Page (includes range)\n DP: \"PY\", // Date of Publication -> Publication Year\n LA: \"LA\", // Language -> Language\n MH: \"KW\", // MeSH Headings -> Keywords\n OT: \"KW\", // Other Terms -> Keywords\n AD: \"AD\", // Affiliation/Address -> Author Address\n IS: \"SN\", // ISSN -> Serial Number\n PT: \"TY\", // Publication Type -> Type of Reference\n};\n\n/**\n * Publication type mapping from NBIB to RIS\n */\nconst NBIB_PUBLICATION_TYPE_MAP: Record<string, string> = {\n \"Journal Article\": \"JOUR\",\n Review: \"JOUR\",\n Book: \"BOOK\",\n \"Book Chapter\": \"CHAP\",\n \"Conference Paper\": \"CPAPER\",\n Thesis: \"THES\",\n Report: \"RPRT\",\n};\n\n/**\n * Parse a single NBIB entry into tag-value pairs\n */\nfunction parseNbibEntry(entry: string): Array<{ tag: string; value: string }> {\n const result: Array<{ tag: string; value: string }> = [];\n const lines = entry.split(\"\\n\");\n\n let currentTag = \"\";\n let currentValue = \"\";\n\n for (const line of lines) {\n // Check if line starts with a tag (2-4 uppercase letters followed by space(s) and dash)\n const tagMatch = line.match(/^([A-Z]{2,4})\\s*-\\s*(.*)$/);\n\n if (tagMatch) {\n // Save previous tag-value pair\n if (currentTag) {\n result.push({ tag: currentTag, value: currentValue.trim() });\n }\n currentTag = tagMatch[1] ?? \"\";\n currentValue = tagMatch[2] ?? \"\";\n } else if (currentTag && line.match(/^\\s+/)) {\n // Continuation line (starts with whitespace)\n currentValue += ` ${line.trim()}`;\n }\n }\n\n // Save the last tag-value pair\n if (currentTag) {\n result.push({ tag: currentTag, value: currentValue.trim() });\n }\n\n return result;\n}\n\n/**\n * Convert a single NBIB tag-value pair to RIS line\n * @returns RIS line or null if tag should be skipped\n */\nfunction convertNbibTagToRisLine(\n tag: string,\n value: string\n): { line: string; isType?: boolean } | null {\n // Handle DOI specially (AID tag with [doi] suffix)\n if (tag === \"AID\" && value.includes(\"[doi]\")) {\n const doi = value.replace(/\\s*\\[doi\\].*$/, \"\").trim();\n return { line: `DO - ${doi}` };\n }\n\n // Handle PII specially (AID tag with [pii] suffix)\n if (tag === \"AID\" && value.includes(\"[pii]\")) {\n const pii = value.replace(/\\s*\\[pii\\].*$/, \"\").trim();\n return { line: `C1 - ${pii}` }; // C1 = Custom Field 1\n }\n\n // Get mapped RIS tag\n const risTag = NBIB_TO_RIS_TAG_MAP[tag];\n if (!risTag) {\n return null; // Skip unmapped tags\n }\n\n // Handle publication year (extract year only)\n if (risTag === \"PY\") {\n const yearMatch = value.match(/^(\\d{4})/);\n return yearMatch ? { line: `PY - ${yearMatch[1]}` } : null;\n }\n\n // Handle publication type\n if (risTag === \"TY\") {\n const risType = NBIB_PUBLICATION_TYPE_MAP[value] || \"JOUR\";\n return { line: `TY - ${risType}`, isType: true };\n }\n\n return { line: `${risTag} - ${value}` };\n}\n\n/**\n * Convert a single NBIB entry to RIS format\n */\nfunction convertSingleNbibEntryToRis(entry: string): string {\n const parsed = parseNbibEntry(entry);\n\n if (parsed.length === 0) {\n return \"\";\n }\n\n const risLines: string[] = [];\n let hasType = false;\n\n for (const { tag, value } of parsed) {\n const converted = convertNbibTagToRisLine(tag, value);\n if (!converted) {\n continue;\n }\n\n if (converted.isType) {\n risLines.unshift(converted.line); // TY must be first\n hasType = true;\n } else {\n risLines.push(converted.line);\n }\n }\n\n // Add default type if not present\n if (!hasType) {\n risLines.unshift(\"TY - JOUR\");\n }\n\n // Add end record tag\n risLines.push(\"ER -\");\n\n return risLines.join(\"\\n\");\n}\n\n/**\n * Convert NBIB (PubMed MEDLINE) format to RIS format\n *\n * @param content - NBIB content string\n * @returns RIS format string\n */\nexport function convertNbibToRis(content: string): string {\n const trimmed = content.trim();\n\n if (!trimmed) {\n return \"\";\n }\n\n // Split into entries by blank lines (PMID- starts each entry)\n const entries = trimmed.split(/\\n\\s*\\n/).filter((e) => e.trim());\n\n const risEntries = entries.map((entry) => convertSingleNbibEntryToRis(entry)).filter(Boolean);\n\n return risEntries.join(\"\\n\\n\");\n}\n\n/**\n * Parse NBIB (PubMed MEDLINE) content to CSL-JSON\n *\n * Converts NBIB to RIS format first, then parses with citation-js\n *\n * @param content - NBIB content string\n * @returns Parse result with CSL-JSON items\n */\nexport function parseNbib(content: string): ParseResult {\n const trimmed = content.trim();\n\n // Handle empty input\n if (!trimmed) {\n return { success: true, items: [] };\n }\n\n // Convert NBIB to RIS\n const risContent = convertNbibToRis(trimmed);\n\n if (!risContent) {\n return {\n success: false,\n items: [],\n error: \"Failed to convert NBIB to RIS: No valid entries found\",\n };\n }\n\n // Parse the RIS content\n return parseRis(risContent);\n}\n\n/**\n * Parse content using citation-js\n */\nfunction parseWithCitationJs(content: string, format: string): ParseResult {\n const trimmed = content.trim();\n\n // Handle empty input\n if (!trimmed) {\n return { success: true, items: [] };\n }\n\n try {\n // Parse with citation-js (auto-detection works well for bibtex/ris)\n const cite = new Cite(trimmed);\n\n // Get CSL-JSON output\n const items = cite.get({ format: \"real\", type: \"json\" }) as CslItem[];\n\n // Handle case where parsing produces no results\n if (!items || items.length === 0) {\n // Check if input looks like valid format but has no entries\n if (isEmptyFormat(trimmed, format)) {\n return { success: true, items: [] };\n }\n\n return {\n success: false,\n items: [],\n error: `No valid ${format.toUpperCase()} entries found`,\n };\n }\n\n return { success: true, items };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n // Check if this is truly empty content (comments only for bibtex)\n if (isEmptyFormat(trimmed, format)) {\n return { success: true, items: [] };\n }\n\n return {\n success: false,\n items: [],\n error: `Failed to parse ${format.toUpperCase()}: ${errorMessage}`,\n };\n }\n}\n\n/**\n * Check if content is \"empty\" for the given format\n * (e.g., only comments for BibTeX)\n */\nfunction isEmptyFormat(content: string, format: string): boolean {\n if (format === \"bibtex\") {\n // BibTeX comments start with %\n const lines = content.split(\"\\n\");\n return lines.every((line) => {\n const trimmed = line.trim();\n return trimmed === \"\" || trimmed.startsWith(\"%\");\n });\n }\n\n return false;\n}\n","/**\n * Importer orchestration module\n *\n * Coordinates format detection, parsing, and fetching to import references\n * from various input formats.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport type { CslItem } from \"../../core/csl-json/types.js\";\nimport { CslItemSchema } from \"../../core/csl-json/types.js\";\nimport {\n cacheDoiResult,\n cacheIsbnResult,\n cachePmidResult,\n getDoiFromCache,\n getIsbnFromCache,\n getPmidFromCache,\n} from \"./cache.js\";\nimport { detectByContent, detectByExtension, isDoi, isIsbn, isPmid } from \"./detector.js\";\nimport type { InputFormat } from \"./detector.js\";\nimport { fetchDoi, fetchIsbn, fetchPmids } from \"./fetcher.js\";\nimport type { FailureReason, PubmedConfig } from \"./fetcher.js\";\nimport { normalizeDoi, normalizeIsbn, normalizePmid } from \"./normalizer.js\";\nimport { parseBibtex, parseNbib, parseRis } from \"./parser.js\";\n\n// Re-export FailureReason for external use\nexport type { FailureReason } from \"./fetcher.js\";\n\n/**\n * Result of importing a single item\n */\nexport type ImportItemResult =\n | { success: true; item: CslItem; source: string }\n | { success: false; error: string; source: string; reason: FailureReason };\n\n/**\n * Result of an import operation\n */\nexport interface ImportResult {\n results: ImportItemResult[];\n}\n\n/**\n * Options for import operations\n */\nexport interface ImportOptions {\n pubmedConfig?: PubmedConfig;\n}\n\n/**\n * Classified identifiers\n */\ninterface ClassifiedIdentifiers {\n pmids: string[];\n dois: string[];\n isbns: string[];\n unknowns: string[];\n}\n\n/**\n * Classify identifiers into PMIDs, DOIs, and unknowns\n */\nfunction classifyIdentifiers(identifiers: string[]): ClassifiedIdentifiers {\n const pmids: string[] = [];\n const dois: string[] = [];\n const isbns: string[] = [];\n const unknowns: string[] = [];\n\n for (const id of identifiers) {\n if (isPmid(id)) {\n pmids.push(normalizePmid(id));\n } else if (isDoi(id)) {\n dois.push(normalizeDoi(id));\n } else if (isIsbn(id)) {\n isbns.push(normalizeIsbn(id));\n } else {\n unknowns.push(id);\n }\n }\n\n return { pmids, dois, isbns, unknowns };\n}\n\n/**\n * Build error results for unknown identifiers\n */\nfunction buildUnknownResults(unknowns: string[]): ImportItemResult[] {\n return unknowns.map((unknown) => ({\n success: false as const,\n error: `Cannot interpret '${unknown}' as identifier (not a valid PMID or DOI)`,\n source: unknown,\n reason: \"validation_error\" as const,\n }));\n}\n\n/**\n * Fetch PMIDs with cache support\n */\nasync function fetchPmidsWithCache(\n pmids: string[],\n pubmedConfig: PubmedConfig\n): Promise<ImportItemResult[]> {\n const results: ImportItemResult[] = [];\n const pmidsToFetch: string[] = [];\n\n // Check cache first\n for (const pmid of pmids) {\n const cached = getPmidFromCache(pmid);\n if (cached) {\n results.push({ success: true, item: cached, source: pmid });\n } else {\n pmidsToFetch.push(pmid);\n }\n }\n\n // Fetch uncached PMIDs\n if (pmidsToFetch.length > 0) {\n const fetchResults = await fetchPmids(pmidsToFetch, pubmedConfig);\n for (const fetchResult of fetchResults) {\n if (fetchResult.success) {\n cachePmidResult(fetchResult.pmid, fetchResult.item);\n results.push({\n success: true,\n item: fetchResult.item,\n source: fetchResult.pmid,\n });\n } else {\n results.push({\n success: false,\n error: fetchResult.error,\n source: fetchResult.pmid,\n reason: fetchResult.reason,\n });\n }\n }\n }\n\n return results;\n}\n\n/**\n * Fetch DOIs with cache support\n */\nasync function fetchDoisWithCache(dois: string[]): Promise<ImportItemResult[]> {\n const results: ImportItemResult[] = [];\n\n for (const doi of dois) {\n const cached = getDoiFromCache(doi);\n if (cached) {\n results.push({ success: true, item: cached, source: doi });\n continue;\n }\n\n const fetchResult = await fetchDoi(doi);\n if (fetchResult.success) {\n cacheDoiResult(doi, fetchResult.item);\n results.push({ success: true, item: fetchResult.item, source: doi });\n } else {\n results.push({\n success: false,\n error: fetchResult.error,\n source: doi,\n reason: fetchResult.reason,\n });\n }\n }\n\n return results;\n}\n\n/**\n * Fetch ISBNs with caching\n */\nasync function fetchIsbnsWithCache(isbns: string[]): Promise<ImportItemResult[]> {\n const results: ImportItemResult[] = [];\n\n for (const isbn of isbns) {\n const cached = getIsbnFromCache(isbn);\n if (cached) {\n results.push({ success: true, item: cached, source: isbn });\n continue;\n }\n\n const fetchResult = await fetchIsbn(isbn);\n if (fetchResult.success) {\n cacheIsbnResult(isbn, fetchResult.item);\n results.push({ success: true, item: fetchResult.item, source: isbn });\n } else {\n results.push({\n success: false,\n error: fetchResult.error,\n source: isbn,\n reason: fetchResult.reason,\n });\n }\n }\n\n return results;\n}\n\n/**\n * Parse JSON content and return import result\n */\nfunction parseJsonContent(content: string): ImportResult {\n try {\n const parsed = JSON.parse(content);\n const items: unknown[] = Array.isArray(parsed) ? parsed : [parsed];\n\n if (items.length === 0) {\n return { results: [] };\n }\n\n const results: ImportItemResult[] = [];\n for (const item of items) {\n const parseResult = CslItemSchema.safeParse(item);\n if (parseResult.success) {\n results.push({ success: true, item: parseResult.data, source: \"json\" });\n } else {\n results.push({\n success: false,\n error: `Invalid CSL-JSON: ${parseResult.error.message}`,\n source: \"json\",\n reason: \"validation_error\",\n });\n }\n }\n return { results };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n results: [\n {\n success: false,\n error: `Failed to parse JSON: ${message}`,\n source: \"json\",\n reason: \"parse_error\",\n },\n ],\n };\n }\n}\n\n/**\n * Parse BibTeX content and return import result\n */\nfunction parseBibtexContent(content: string): ImportResult {\n const parseResult = parseBibtex(content);\n\n if (!parseResult.success) {\n return {\n results: [\n {\n success: false,\n error: parseResult.error ?? \"Failed to parse BibTeX\",\n source: \"bibtex\",\n reason: \"parse_error\",\n },\n ],\n };\n }\n\n if (parseResult.items.length === 0) {\n return { results: [] };\n }\n\n return {\n results: parseResult.items.map((item) => ({\n success: true as const,\n item,\n source: \"bibtex\",\n })),\n };\n}\n\n/**\n * Parse RIS content and return import result\n */\nfunction parseRisContent(content: string): ImportResult {\n const parseResult = parseRis(content);\n\n if (!parseResult.success) {\n return {\n results: [\n {\n success: false,\n error: parseResult.error ?? \"Failed to parse RIS\",\n source: \"ris\",\n reason: \"parse_error\",\n },\n ],\n };\n }\n\n if (parseResult.items.length === 0) {\n return { results: [] };\n }\n\n return {\n results: parseResult.items.map((item) => ({\n success: true as const,\n item,\n source: \"ris\",\n })),\n };\n}\n\n/**\n * Parse NBIB content and return import result\n */\nfunction parseNbibContent(content: string): ImportResult {\n const parseResult = parseNbib(content);\n\n if (!parseResult.success) {\n return {\n results: [\n {\n success: false,\n error: parseResult.error ?? \"Failed to parse NBIB\",\n source: \"nbib\",\n reason: \"parse_error\",\n },\n ],\n };\n }\n\n if (parseResult.items.length === 0) {\n return { results: [] };\n }\n\n return {\n results: parseResult.items.map((item) => ({\n success: true as const,\n item,\n source: \"nbib\",\n })),\n };\n}\n\n/**\n * Import references from content string\n *\n * @param content - The content to parse\n * @param format - The format of the content (or \"auto\" for detection)\n * @param options - Import options\n * @returns Import result with parsed items\n */\nexport async function importFromContent(\n content: string,\n format: InputFormat | \"auto\",\n _options: ImportOptions\n): Promise<ImportResult> {\n // Determine the actual format\n let actualFormat: InputFormat;\n if (format === \"auto\") {\n actualFormat = detectByContent(content);\n if (actualFormat === \"unknown\") {\n return {\n results: [\n {\n success: false,\n error: \"Cannot detect input format. Use --format to specify explicitly.\",\n source: \"content\",\n reason: \"validation_error\",\n },\n ],\n };\n }\n } else {\n actualFormat = format;\n }\n\n // Parse based on format\n switch (actualFormat) {\n case \"json\":\n return parseJsonContent(content);\n case \"bibtex\":\n return parseBibtexContent(content);\n case \"ris\":\n return parseRisContent(content);\n case \"nbib\":\n return parseNbibContent(content);\n default:\n return {\n results: [\n {\n success: false,\n error: `Unsupported format for content parsing: ${actualFormat}`,\n source: \"content\",\n reason: \"validation_error\",\n },\n ],\n };\n }\n}\n\n/**\n * Import references from identifier strings (PMID or DOI)\n *\n * @param identifiers - Array of identifier strings\n * @param options - Import options (requires pubmedConfig for PMID fetching)\n * @returns Import result with fetched items\n */\nexport async function importFromIdentifiers(\n identifiers: string[],\n options: ImportOptions\n): Promise<ImportResult> {\n if (identifiers.length === 0) {\n return { results: [] };\n }\n\n // Classify identifiers\n const { pmids, dois, isbns, unknowns } = classifyIdentifiers(identifiers);\n\n // Collect results\n const results: ImportItemResult[] = [];\n\n // Add errors for unknown identifiers\n results.push(...buildUnknownResults(unknowns));\n\n // Fetch PMIDs with cache\n const pmidResults = await fetchPmidsWithCache(pmids, options.pubmedConfig ?? {});\n results.push(...pmidResults);\n\n // Fetch DOIs with cache\n const doiResults = await fetchDoisWithCache(dois);\n results.push(...doiResults);\n\n // Fetch ISBNs with cache\n const isbnResults = await fetchIsbnsWithCache(isbns);\n results.push(...isbnResults);\n\n return { results };\n}\n\n/**\n * Options for importFromInputs\n */\nexport interface ImportInputsOptions extends ImportOptions {\n /** Explicit format specification (default: auto) */\n format?: InputFormat | \"auto\";\n /** Content from stdin (if provided, processed before file/identifier inputs) */\n stdinContent?: string;\n}\n\n/**\n * Unified entry point for importing references from file paths or identifiers\n *\n * Classifies inputs as files or identifiers:\n * - If path exists as file → read and parse\n * - If path does not exist → interpret as identifier (PMID/DOI)\n *\n * @param inputs - Array of file paths or identifier strings\n * @param options - Import options including format specification\n * @returns Import result with all parsed/fetched items\n */\n\n/**\n * Check if input looks like a file path (has file-like extension)\n */\nfunction looksLikeFilePath(input: string): boolean {\n const fileExtensions = [\".json\", \".bib\", \".ris\", \".txt\", \".xml\", \".yaml\", \".yml\"];\n const lowerInput = input.toLowerCase();\n return fileExtensions.some((ext) => lowerInput.endsWith(ext));\n}\n\n/**\n * Process a single file input\n */\nasync function processFile(\n filePath: string,\n options: ImportInputsOptions\n): Promise<ImportItemResult[]> {\n try {\n const content = readFileSync(filePath, \"utf-8\");\n\n // Determine format\n let format: InputFormat | \"auto\";\n if (options.format && options.format !== \"auto\") {\n format = options.format;\n } else {\n // Try extension first\n const extFormat = detectByExtension(filePath);\n format = extFormat !== \"unknown\" ? extFormat : \"auto\";\n }\n\n const result = await importFromContent(content, format, options);\n\n // Update source to be the file path\n return result.results.map((r) => ({\n ...r,\n source: filePath,\n }));\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return [\n {\n success: false,\n error: `Failed to read file: ${message}`,\n source: filePath,\n reason: \"fetch_error\",\n },\n ];\n }\n}\n\n/**\n * Process identifier inputs (PMID/DOI)\n */\nasync function processIdentifiers(\n inputs: string[],\n options: ImportInputsOptions\n): Promise<ImportItemResult[]> {\n const results: ImportItemResult[] = [];\n const validIdentifiers: string[] = [];\n\n // Separate valid identifiers from invalid inputs\n for (const input of inputs) {\n // Check if it's a valid identifier\n const isValidPmid = isPmid(input);\n const isValidDoi = isDoi(input);\n const isValidIsbn = isIsbn(input);\n\n if (isValidPmid || isValidDoi || isValidIsbn) {\n validIdentifiers.push(input);\n } else {\n // Not a valid identifier\n const hint = looksLikeFilePath(input)\n ? \" Hint: If this is a file path, check that the file exists.\"\n : \"\";\n results.push({\n success: false,\n error: `Cannot interpret '${input}' as identifier (not a valid PMID, DOI, or ISBN).${hint}`,\n source: input,\n reason: \"validation_error\",\n });\n }\n }\n\n // Fetch valid identifiers\n if (validIdentifiers.length > 0) {\n const fetchResult = await importFromIdentifiers(validIdentifiers, options);\n results.push(...fetchResult.results);\n }\n\n return results;\n}\n\nexport async function importFromInputs(\n inputs: string[],\n options: ImportInputsOptions\n): Promise<ImportResult> {\n const allResults: ImportItemResult[] = [];\n\n // Process stdinContent if provided\n if (options.stdinContent?.trim()) {\n const stdinResults = await processStdinContent(options.stdinContent, options);\n allResults.push(...stdinResults);\n }\n\n // Process file/identifier inputs\n if (inputs.length > 0) {\n const identifiersToFetch: string[] = [];\n\n // Process each input\n for (const input of inputs) {\n if (existsSync(input)) {\n // Input is an existing file\n const fileResults = await processFile(input, options);\n allResults.push(...fileResults);\n } else {\n // Input does not exist as file - treat as potential identifier\n identifiersToFetch.push(input);\n }\n }\n\n // Process identifiers\n if (identifiersToFetch.length > 0) {\n const identifierResults = await processIdentifiers(identifiersToFetch, options);\n allResults.push(...identifierResults);\n }\n }\n\n return { results: allResults };\n}\n\n/**\n * Process stdin content based on format detection\n * - For file formats (json/bibtex/ris): parse directly\n * - For identifier formats (pmid/doi) or auto with identifiers: split and process\n */\nasync function processStdinContent(\n content: string,\n options: ImportInputsOptions\n): Promise<ImportItemResult[]> {\n const format = options.format || \"auto\";\n\n // If explicit file format specified, parse as content\n if (format === \"json\" || format === \"bibtex\" || format === \"ris\" || format === \"nbib\") {\n const result = await importFromContent(content, format, options);\n return result.results.map((r) => ({\n ...r,\n source: r.source === \"content\" ? \"stdin\" : r.source,\n }));\n }\n\n // If explicit identifier format, split and process\n if (format === \"pmid\" || format === \"doi\" || format === \"isbn\") {\n const identifiers = content.split(/\\s+/).filter((s) => s.length > 0);\n return processIdentifiers(identifiers, options);\n }\n\n // Auto-detect format from content\n const detectedFormat = detectByContent(content);\n\n if (\n detectedFormat === \"json\" ||\n detectedFormat === \"bibtex\" ||\n detectedFormat === \"ris\" ||\n detectedFormat === \"nbib\"\n ) {\n // File format detected - parse as content\n const result = await importFromContent(content, detectedFormat, options);\n return result.results.map((r) => ({\n ...r,\n source: r.source === \"content\" ? \"stdin\" : r.source,\n }));\n }\n\n // Not a file format - treat as whitespace-separated identifiers\n const identifiers = content.split(/\\s+/).filter((s) => s.length > 0);\n if (identifiers.length === 0) {\n return [];\n }\n\n return processIdentifiers(identifiers, options);\n}\n","import type { CslItem } from \"../../core/csl-json/types.js\";\nimport { generateId } from \"../../core/identifier/generator.js\";\nimport type { ILibrary } from \"../../core/library-interface.js\";\nimport { detectDuplicate } from \"../duplicate/detector.js\";\nimport type { InputFormat } from \"../import/detector.js\";\nimport type { PubmedConfig } from \"../import/fetcher.js\";\nimport {\n type ImportInputsOptions,\n type ImportItemResult,\n importFromInputs,\n} from \"../import/importer.js\";\n\n// Re-export FailureReason for external use\nexport type { FailureReason } from \"../import/importer.js\";\n\n/**\n * Options for adding references\n */\nexport interface AddReferencesOptions {\n /** Skip duplicate detection */\n force?: boolean;\n /** Explicit input format (default: auto) */\n format?: InputFormat | \"auto\";\n /** PubMed API configuration */\n pubmedConfig?: PubmedConfig;\n /** Content from stdin (if provided, processed before file/identifier inputs) */\n stdinContent?: string;\n}\n\n/**\n * Information about a successfully added reference\n */\nexport interface AddedItem {\n source: string;\n id: string;\n uuid: string;\n title: string;\n /** True if the original ID from source file was changed due to collision */\n idChanged?: boolean;\n /** Original ID from source file before collision resolution */\n originalId?: string;\n}\n\n/**\n * Information about a failed import\n */\nexport interface FailedItem {\n source: string;\n error: string;\n reason: import(\"../import/importer.js\").FailureReason;\n}\n\n/**\n * Information about a skipped duplicate\n */\nexport interface SkippedItem {\n source: string;\n existingId: string;\n duplicateType: import(\"../duplicate/types.js\").DuplicateType;\n}\n\n/**\n * Result of addReferences operation\n */\nexport interface AddReferencesResult {\n added: AddedItem[];\n failed: FailedItem[];\n skipped: SkippedItem[];\n}\n\n/**\n * Add references to a library from various input sources.\n *\n * This function orchestrates:\n * 1. Import from inputs (files or identifiers)\n * 2. Duplicate detection (unless force=true)\n * 3. ID collision resolution\n * 4. Library save\n *\n * @param inputs - File paths or identifiers (PMID, DOI)\n * @param library - Target library\n * @param options - Add options\n * @returns Result with added, failed, and skipped items\n */\nexport async function addReferences(\n inputs: string[],\n library: ILibrary,\n options: AddReferencesOptions\n): Promise<AddReferencesResult> {\n const added: AddedItem[] = [];\n const failed: FailedItem[] = [];\n const skipped: SkippedItem[] = [];\n\n // 1. Import from inputs\n const importOptions = buildImportOptions(options);\n const importResult = await importFromInputs(inputs, importOptions);\n\n // Get existing items for duplicate/collision checks (getAll now returns CslItem[] directly)\n const existingItems = await library.getAll();\n\n // Track IDs we've added in this batch (for collision detection within batch)\n const addedIds = new Set<string>();\n\n // 2. Process each import result\n for (const result of importResult.results) {\n const processed = await processImportResult(\n result,\n existingItems,\n addedIds,\n options.force ?? false,\n library\n );\n\n if (processed.type === \"failed\") {\n failed.push(processed.item);\n } else if (processed.type === \"skipped\") {\n skipped.push(processed.item);\n } else {\n added.push(processed.item);\n }\n }\n\n // 3. Save library if any items were added\n if (added.length > 0) {\n await library.save();\n }\n\n return { added, failed, skipped };\n}\n\n/**\n * Build import options from add options\n */\nfunction buildImportOptions(options: AddReferencesOptions): ImportInputsOptions {\n const importOptions: ImportInputsOptions = {};\n if (options.format !== undefined) {\n importOptions.format = options.format;\n }\n if (options.pubmedConfig !== undefined) {\n importOptions.pubmedConfig = options.pubmedConfig;\n }\n if (options.stdinContent !== undefined) {\n importOptions.stdinContent = options.stdinContent;\n }\n return importOptions;\n}\n\ntype ProcessResult =\n | { type: \"added\"; item: AddedItem }\n | { type: \"failed\"; item: FailedItem }\n | { type: \"skipped\"; item: SkippedItem };\n\n/**\n * Process a single import result\n */\nasync function processImportResult(\n result: ImportItemResult,\n existingItems: CslItem[],\n addedIds: Set<string>,\n force: boolean,\n library: ILibrary\n): Promise<ProcessResult> {\n if (!result.success) {\n return {\n type: \"failed\",\n item: { source: result.source, error: result.error, reason: result.reason },\n };\n }\n\n const item = result.item;\n\n // Check for duplicates (unless force=true)\n if (!force) {\n const duplicateResult = detectDuplicate(item, existingItems);\n const existingMatch = duplicateResult.matches[0];\n if (existingMatch) {\n return {\n type: \"skipped\",\n item: {\n source: result.source,\n existingId: existingMatch.existing.id ?? \"\",\n duplicateType: existingMatch.type,\n },\n };\n }\n }\n\n // Resolve ID collision\n // Prioritize original ID from source file; generate ID only if not present\n const allExistingIds = new Set([...existingItems.map((i) => i.id), ...addedIds]);\n const originalId = item.id?.trim() || \"\";\n const hasOriginalId = originalId.length > 0;\n const baseId = hasOriginalId ? originalId : generateId(item);\n const { id, changed } = resolveIdCollision(baseId, allExistingIds);\n\n const finalItem: CslItem = { ...item, id };\n\n // Add to library\n const addedToLibrary = await library.add(finalItem);\n addedIds.add(id);\n\n // Build result (uuid comes from the library-added item which has ensured UUID)\n const uuid = addedToLibrary.custom?.uuid ?? \"\";\n const addedItem: AddedItem = {\n source: result.source,\n id,\n uuid,\n title: typeof finalItem.title === \"string\" ? finalItem.title : \"\",\n };\n\n // Report idChanged only when original ID from source was changed due to collision\n // Generated ID collisions are internal and not reported\n if (hasOriginalId && changed) {\n addedItem.idChanged = true;\n addedItem.originalId = originalId;\n }\n\n return { type: \"added\", item: addedItem };\n}\n\n/**\n * Generate an alphabetic suffix for ID collision resolution.\n * 0 -> 'a', 1 -> 'b', ..., 25 -> 'z', 26 -> 'aa', etc.\n */\nfunction generateSuffix(index: number): string {\n const alphabet = \"abcdefghijklmnopqrstuvwxyz\";\n let suffix = \"\";\n let n = index;\n\n do {\n suffix = alphabet[n % 26] + suffix;\n n = Math.floor(n / 26) - 1;\n } while (n >= 0);\n\n return suffix;\n}\n\n/**\n * Resolve ID collision by appending alphabetic suffix.\n */\nfunction resolveIdCollision(\n baseId: string,\n existingIds: Set<string>\n): { id: string; changed: boolean } {\n if (!existingIds.has(baseId)) {\n return { id: baseId, changed: false };\n }\n\n // Find next available suffix\n let index = 0;\n let newId: string;\n\n do {\n const suffix = generateSuffix(index);\n newId = `${baseId}${suffix}`;\n index++;\n } while (existingIds.has(newId));\n\n return { id: newId, changed: true };\n}\n","import { Hono } from \"hono\";\nimport type { Config } from \"../../config/schema.js\";\nimport type { Library } from \"../../core/library.js\";\nimport type { InputFormat } from \"../../features/import/detector.js\";\nimport type { PubmedConfig } from \"../../features/import/fetcher.js\";\nimport { type AddReferencesOptions, addReferences } from \"../../features/operations/add.js\";\n\n/**\n * Build PubmedConfig from config, filtering out undefined values\n * to satisfy exactOptionalPropertyTypes requirements.\n */\nfunction buildPubmedConfig(config: Config): PubmedConfig {\n const pubmedConfig: PubmedConfig = {};\n if (config.pubmed.email !== undefined) {\n pubmedConfig.email = config.pubmed.email;\n }\n if (config.pubmed.apiKey !== undefined) {\n pubmedConfig.apiKey = config.pubmed.apiKey;\n }\n return pubmedConfig;\n}\n\n/**\n * Create add route for importing references.\n * @param library - Library instance to use for operations\n * @param config - Configuration with PubMed settings\n * @returns Hono app with add route\n */\nexport function createAddRoute(library: Library, config: Config) {\n const route = new Hono();\n\n // POST / - Add references from inputs\n route.post(\"/\", async (c) => {\n // Parse request body\n let body: unknown;\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: \"Invalid JSON\" }, 400);\n }\n\n // Validate inputs\n if (!body || typeof body !== \"object\") {\n return c.json({ error: \"Request body must be an object\" }, 400);\n }\n\n const { inputs, options } = body as {\n inputs?: unknown;\n options?: { force?: boolean; format?: string };\n };\n\n if (!inputs || !Array.isArray(inputs) || inputs.length === 0) {\n return c.json({ error: \"inputs must be a non-empty array of strings\" }, 400);\n }\n\n // Ensure all inputs are strings\n if (!inputs.every((input) => typeof input === \"string\")) {\n return c.json({ error: \"All inputs must be strings\" }, 400);\n }\n\n // Build options\n const addOptions: AddReferencesOptions = {\n force: options?.force ?? false,\n pubmedConfig: buildPubmedConfig(config),\n };\n\n if (options?.format) {\n addOptions.format = options.format as InputFormat | \"auto\";\n }\n\n // Call addReferences\n const result = await addReferences(inputs as string[], library, addOptions);\n\n return c.json(result);\n });\n\n return route;\n}\n","import { isBuiltinStyle, resolveStyle } from \"../../config/csl-styles.js\";\nimport type { CslItem } from \"../../core/csl-json/types.js\";\nimport type { ILibrary, IdentifierType } from \"../../core/library-interface.js\";\nimport {\n formatBibliography,\n formatBibliographyCSL,\n formatInText,\n formatInTextCSL,\n} from \"../format/index.js\";\n\n/**\n * Options for citeReferences operation\n */\nexport interface CiteOperationOptions {\n /** Reference IDs or UUIDs to cite */\n identifiers: string[];\n /** Identifier type: 'id' (default), 'uuid', 'doi', 'pmid', or 'isbn' */\n idType?: IdentifierType;\n /** CSL style name or path to CSL file */\n style?: string;\n /** Path to custom CSL file */\n cslFile?: string;\n /** Default style from config (used when style is not specified) */\n defaultStyle?: string;\n /** Directory or directories to search for custom CSL files */\n cslDirectory?: string | string[];\n /** Locale for citation formatting (default: \"en-US\") */\n locale?: string;\n /** Output format (default: \"text\") */\n format?: \"text\" | \"html\" | \"rtf\";\n /** If true, generate in-text citation instead of bibliography */\n inText?: boolean;\n}\n\n/**\n * Result for a single citation\n */\nexport type CiteItemResult =\n | { success: true; identifier: string; citation: string }\n | { success: false; identifier: string; error: string };\n\n/**\n * Result of citeReferences operation\n */\nexport interface CiteResult {\n /** Results for each identifier */\n results: CiteItemResult[];\n}\n\ninterface FormatOptions {\n style?: string | undefined;\n styleXml?: string | undefined;\n locale?: string | undefined;\n format?: \"text\" | \"html\" | \"rtf\" | undefined;\n}\n\n/**\n * Check if fallback formatter should be used.\n */\nfunction shouldUseFallback(style: string | undefined, hasCustomXml: boolean): boolean {\n if (hasCustomXml) {\n return false;\n }\n if (style && !isBuiltinStyle(style)) {\n return true;\n }\n return false;\n}\n\n/**\n * Format a single item as citation.\n */\nfunction formatCitation(item: CslItem, inText: boolean, options: FormatOptions): string {\n const useFallback = shouldUseFallback(options.style, !!options.styleXml);\n const style = options.style ?? \"apa\";\n const locale = options.locale ?? \"en-US\";\n const format = options.format ?? \"text\";\n const styleXml = options.styleXml;\n\n if (useFallback) {\n return inText ? formatInText([item]) : formatBibliography([item]);\n }\n\n const formatOptions = { style, locale, format, ...(styleXml && { styleXml }) };\n return inText\n ? formatInTextCSL([item], formatOptions)\n : formatBibliographyCSL([item], formatOptions);\n}\n\n/**\n * Generate citation for a single identifier.\n */\nasync function generateCitationForIdentifier(\n library: ILibrary,\n identifier: string,\n idType: IdentifierType,\n inText: boolean,\n options: FormatOptions\n): Promise<CiteItemResult> {\n const item = await library.find(identifier, { idType });\n\n if (!item) {\n const lookupType = idType === \"uuid\" ? \"UUID\" : idType.toUpperCase();\n return {\n success: false,\n identifier,\n error: `Reference with ${lookupType} '${identifier}' not found`,\n };\n }\n\n const citation = formatCitation(item, inText, options);\n\n return {\n success: true,\n identifier,\n citation,\n };\n}\n\n/**\n * Generate citations for references.\n *\n * @param library - The library to cite from\n * @param options - Citation options including identifiers and style settings\n * @returns Results array with citation or error for each identifier\n */\nexport async function citeReferences(\n library: ILibrary,\n options: CiteOperationOptions\n): Promise<CiteResult> {\n const {\n identifiers,\n idType = \"id\",\n inText = false,\n style,\n cslFile,\n defaultStyle,\n cslDirectory,\n locale,\n format,\n } = options;\n const results: CiteItemResult[] = [];\n\n // Resolve style using the full resolution chain:\n // 1. cslFile (exact path)\n // 2. style (if built-in)\n // 3. Search in cslDirectory\n // 4. defaultStyle (if built-in or found in cslDirectory)\n // 5. Fallback to 'apa'\n const resolution = resolveStyle({\n ...(cslFile !== undefined && { cslFile }),\n ...(style !== undefined && { style }),\n ...(defaultStyle !== undefined && { defaultStyle }),\n ...(cslDirectory !== undefined && { cslDirectory }),\n });\n\n for (const identifier of identifiers) {\n const result = await generateCitationForIdentifier(library, identifier, idType, inText, {\n style: resolution.styleName,\n styleXml: resolution.styleXml,\n locale,\n format,\n });\n results.push(result);\n }\n\n return { results };\n}\n","import { Hono } from \"hono\";\nimport { z } from \"zod\";\nimport type { Library } from \"../../core/library.js\";\nimport {\n type CiteOperationOptions,\n type CiteResult,\n citeReferences,\n} from \"../../features/operations/cite.js\";\n\n/**\n * Zod schema for cite request body\n */\nconst CiteRequestSchema = z.object({\n identifiers: z.array(z.string()).min(1, \"identifiers must be a non-empty array\"),\n idType: z.enum([\"id\", \"uuid\", \"doi\", \"pmid\", \"isbn\"]).optional(),\n inText: z.boolean().optional(),\n style: z.string().optional(),\n cslFile: z.string().optional(),\n locale: z.string().optional(),\n format: z.enum([\"text\", \"html\"]).optional(),\n});\n\ntype CiteRequestBody = z.infer<typeof CiteRequestSchema>;\n\n/**\n * Build cite operation options from validated request body.\n */\nfunction buildCiteOptions(body: CiteRequestBody): CiteOperationOptions {\n return {\n identifiers: body.identifiers,\n ...(body.idType !== undefined && { idType: body.idType }),\n ...(body.inText !== undefined && { inText: body.inText }),\n ...(body.style !== undefined && { style: body.style }),\n ...(body.cslFile !== undefined && { cslFile: body.cslFile }),\n ...(body.locale !== undefined && { locale: body.locale }),\n ...(body.format !== undefined && { format: body.format }),\n };\n}\n\n/**\n * Create cite route for generating citations.\n * @param library - Library instance to use for operations\n * @returns Hono app with cite route\n */\nexport function createCiteRoute(library: Library) {\n const route = new Hono();\n\n // POST / - Generate citations for identifiers\n route.post(\"/\", async (c) => {\n // Parse request body\n let rawBody: unknown;\n try {\n rawBody = await c.req.json();\n } catch {\n return c.json({ error: \"Invalid JSON\" }, 400);\n }\n\n // Validate with zod schema\n const parseResult = CiteRequestSchema.safeParse(rawBody);\n if (!parseResult.success) {\n const errorMessage = parseResult.error.issues[0]?.message ?? \"Invalid request body\";\n return c.json({ error: errorMessage }, 400);\n }\n\n // Call citeReferences operation\n const result: CiteResult = await citeReferences(library, buildCiteOptions(parseResult.data));\n\n return c.json(result);\n });\n\n return route;\n}\n","import { Hono } from \"hono\";\n\n/**\n * Health check route.\n * Returns a simple status to verify the server is running.\n */\nexport const healthRoute = new Hono();\n\nhealthRoute.get(\"/\", (c) => {\n return c.json({ status: \"ok\" });\n});\n","import type { CslItem } from \"../../core/csl-json/types.js\";\nimport type { ILibrary } from \"../../core/library-interface.js\";\nimport {\n type PaginationOptions,\n type SortField,\n type SortOptions,\n type SortOrder,\n paginate,\n sortReferences,\n} from \"../pagination/index.js\";\n\n/**\n * Options for listReferences operation\n */\nexport interface ListOptions extends PaginationOptions, SortOptions {}\n\n/**\n * Result of listReferences operation\n */\nexport interface ListResult {\n /** Raw CslItem array */\n items: CslItem[];\n /** Total count before pagination */\n total: number;\n /** Applied limit (0 if unlimited) */\n limit: number;\n /** Applied offset */\n offset: number;\n /** Next page offset, null if no more results */\n nextOffset: number | null;\n}\n\n/**\n * List all references from the library.\n *\n * @param library - The library to list references from\n * @param options - Pagination and sorting options\n * @returns Raw CslItem[] with pagination metadata\n */\nexport async function listReferences(library: ILibrary, options: ListOptions): Promise<ListResult> {\n const sort: SortField = options.sort ?? \"updated\";\n const order: SortOrder = options.order ?? \"desc\";\n const limit = options.limit ?? 0;\n const offset = options.offset ?? 0;\n\n // Get all items\n const allItems = await library.getAll();\n const total = allItems.length;\n\n // Sort\n const sorted = sortReferences(allItems, sort, order);\n\n // Paginate\n const { items: paginatedItems, nextOffset } = paginate(sorted, { limit, offset });\n\n return {\n items: paginatedItems,\n total,\n limit,\n offset,\n nextOffset,\n };\n}\n","import { Hono } from \"hono\";\nimport { z } from \"zod\";\nimport type { Library } from \"../../core/library.js\";\nimport { type ListOptions, listReferences } from \"../../features/operations/list.js\";\nimport { sortFieldSchema, sortOrderSchema } from \"../../features/pagination/index.js\";\nimport { pickDefined } from \"../../utils/object.js\";\n\n/**\n * Request body schema for list endpoint\n */\nconst listRequestBodySchema = z.object({\n sort: sortFieldSchema.optional(),\n order: sortOrderSchema.optional(),\n limit: z.number().int().min(0).optional(),\n offset: z.number().int().min(0).optional(),\n});\n\n/**\n * Request body type for list endpoint\n */\nexport type ListRequestBody = z.infer<typeof listRequestBodySchema>;\n\n/**\n * Creates list route for HTTP server\n */\nexport function createListRoute(library: Library) {\n const route = new Hono();\n\n // POST / - List all references\n route.post(\"/\", async (c) => {\n // Parse request body\n let body: unknown;\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: \"Invalid JSON\" }, 400);\n }\n\n // Validate body with zod\n const parseResult = listRequestBodySchema.safeParse(body);\n if (!parseResult.success) {\n const errorMessage = parseResult.error.issues[0]?.message ?? \"Invalid request body\";\n return c.json({ error: errorMessage }, 400);\n }\n\n const requestBody = parseResult.data;\n\n // Build options for listReferences\n const options: ListOptions = pickDefined(requestBody, [\n \"sort\",\n \"order\",\n \"limit\",\n \"offset\",\n ] as const);\n\n // Call listReferences operation - always returns raw CslItem[]\n const result = await listReferences(library, options);\n\n return c.json(result);\n });\n\n return route;\n}\n","import { Hono } from \"hono\";\nimport type { Library } from \"../../core/library.js\";\nimport { removeReference } from \"../../features/operations/remove.js\";\nimport { updateReference } from \"../../features/operations/update.js\";\n\n/**\n * Create references CRUD route with the given library.\n * @param library - Library instance to use for operations\n * @returns Hono app with references routes\n */\nexport function createReferencesRoute(library: Library) {\n const route = new Hono();\n\n // GET / - Get all references (getAll now returns Promise<CslItem[]>)\n route.get(\"/\", async (c) => {\n const items = await library.getAll();\n return c.json(items);\n });\n\n // GET /uuid/:uuid - Get reference by UUID\n route.get(\"/uuid/:uuid\", async (c) => {\n const uuid = c.req.param(\"uuid\");\n const item = await library.find(uuid, { idType: \"uuid\" });\n\n if (!item) {\n return c.json({ error: \"Reference not found\" }, 404);\n }\n\n return c.json(item);\n });\n\n // GET /id/:id - Get reference by citation ID\n route.get(\"/id/:id\", async (c) => {\n const id = c.req.param(\"id\");\n const item = await library.find(id);\n\n if (!item) {\n return c.json({ error: \"Reference not found\" }, 404);\n }\n\n return c.json(item);\n });\n\n // POST / - Create new reference\n route.post(\"/\", async (c) => {\n try {\n const body = await c.req.json();\n\n // Create and add reference (library.add handles validation and returns the added item)\n const addedItem = await library.add(body);\n\n return c.json(addedItem, 201);\n } catch (error) {\n return c.json(\n {\n error: \"Invalid request body\",\n details: error instanceof Error ? error.message : String(error),\n },\n 400\n );\n }\n });\n\n // PUT /uuid/:uuid - Update reference by UUID\n // Request body: { updates: Partial<CslItem>, onIdCollision?: \"fail\" | \"suffix\" }\n route.put(\"/uuid/:uuid\", async (c) => {\n const uuid = c.req.param(\"uuid\");\n\n let body: unknown;\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: \"Invalid JSON\" }, 400);\n }\n\n if (!body || typeof body !== \"object\") {\n return c.json({ error: \"Request body must be an object\" }, 400);\n }\n\n const { updates, onIdCollision } = body as {\n updates?: Partial<import(\"../../core/csl-json/types.js\").CslItem>;\n onIdCollision?: \"fail\" | \"suffix\";\n };\n\n if (!updates || typeof updates !== \"object\") {\n return c.json({ error: \"Request body must contain 'updates' object\" }, 400);\n }\n\n // Use updateReference operation\n const result = await updateReference(library, {\n identifier: uuid,\n idType: \"uuid\",\n updates,\n onIdCollision: onIdCollision ?? \"suffix\",\n });\n\n // Return operation result with appropriate status code\n if (!result.updated) {\n const status = result.idCollision ? 409 : 404;\n return c.json(result, status);\n }\n\n return c.json(result);\n });\n\n // PUT /id/:id - Update reference by citation ID\n // Request body: { updates: Partial<CslItem>, onIdCollision?: \"fail\" | \"suffix\" }\n route.put(\"/id/:id\", async (c) => {\n const id = c.req.param(\"id\");\n\n let body: unknown;\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: \"Invalid JSON\" }, 400);\n }\n\n if (!body || typeof body !== \"object\") {\n return c.json({ error: \"Request body must be an object\" }, 400);\n }\n\n const { updates, onIdCollision } = body as {\n updates?: Partial<import(\"../../core/csl-json/types.js\").CslItem>;\n onIdCollision?: \"fail\" | \"suffix\";\n };\n\n if (!updates || typeof updates !== \"object\") {\n return c.json({ error: \"Request body must contain 'updates' object\" }, 400);\n }\n\n // Use updateReference operation with idType: 'id'\n const result = await updateReference(library, {\n identifier: id,\n updates,\n onIdCollision: onIdCollision ?? \"suffix\",\n });\n\n // Return operation result with appropriate status code\n if (!result.updated) {\n const status = result.idCollision ? 409 : 404;\n return c.json(result, status);\n }\n\n return c.json(result);\n });\n\n // DELETE /uuid/:uuid - Delete reference by UUID\n route.delete(\"/uuid/:uuid\", async (c) => {\n const uuid = c.req.param(\"uuid\");\n\n // Use removeReference operation\n const result = await removeReference(library, {\n identifier: uuid,\n idType: \"uuid\",\n });\n\n // Return operation result with appropriate status code\n if (!result.removed) {\n return c.json(result, 404);\n }\n\n return c.json(result);\n });\n\n // DELETE /id/:id - Delete reference by citation ID\n route.delete(\"/id/:id\", async (c) => {\n const id = c.req.param(\"id\");\n\n // Use removeReference operation\n const result = await removeReference(library, {\n identifier: id,\n });\n\n // Return operation result with appropriate status code\n if (!result.removed) {\n return c.json(result, 404);\n }\n\n return c.json(result);\n });\n\n return route;\n}\n","import type { CslItem } from \"../../core/csl-json/types.js\";\nimport type { ILibrary } from \"../../core/library-interface.js\";\nimport {\n type PaginationOptions,\n type SearchSortField,\n type SortField,\n type SortOrder,\n paginate,\n sortReferences,\n} from \"../pagination/index.js\";\nimport { search } from \"../search/matcher.js\";\nimport { sortResults as sortByRelevance } from \"../search/sorter.js\";\nimport { tokenize } from \"../search/tokenizer.js\";\n\n/**\n * Sort options for search (includes relevance)\n */\nexport interface SearchSortOptions {\n sort?: SearchSortField;\n order?: SortOrder;\n}\n\n/**\n * Options for searchReferences operation\n */\nexport interface SearchOperationOptions extends PaginationOptions, SearchSortOptions {\n /** Search query string */\n query: string;\n}\n\n/**\n * Result of searchReferences operation\n */\nexport interface SearchResult {\n /** Raw CslItem array */\n items: CslItem[];\n /** Total count before pagination */\n total: number;\n /** Applied limit (0 if unlimited) */\n limit: number;\n /** Applied offset */\n offset: number;\n /** Next page offset, null if no more results */\n nextOffset: number | null;\n}\n\n/**\n * Search references in the library and return raw CslItem[] results.\n *\n * @param library - The library to search in\n * @param options - Search query and pagination options\n * @returns Raw CslItem[] with pagination metadata\n */\nexport async function searchReferences(\n library: ILibrary,\n options: SearchOperationOptions\n): Promise<SearchResult> {\n const query = options.query;\n const sort: SearchSortField = options.sort ?? \"updated\";\n const order: SortOrder = options.order ?? \"desc\";\n const limit = options.limit ?? 0;\n const offset = options.offset ?? 0;\n\n // Get all references\n const allItems = await library.getAll();\n\n // Search and get matched items\n let matchedItems: CslItem[];\n if (!query.trim()) {\n matchedItems = allItems;\n } else {\n // Tokenize and search\n const tokens = tokenize(query).tokens;\n const results = search(allItems, tokens);\n\n // If sorting by relevance, use the search sorter\n if (sort === \"relevance\") {\n const sorted = sortByRelevance(results);\n matchedItems =\n order === \"desc\"\n ? sorted.map((r) => r.reference)\n : sorted.map((r) => r.reference).reverse();\n } else {\n matchedItems = results.map((r) => r.reference);\n }\n }\n\n const total = matchedItems.length;\n\n // Sort (unless already sorted by relevance)\n let sorted: CslItem[];\n if (sort === \"relevance\") {\n sorted = matchedItems;\n } else {\n sorted = sortReferences(matchedItems, sort as SortField, order);\n }\n\n // Paginate\n const { items: paginatedItems, nextOffset } = paginate(sorted, { limit, offset });\n\n return {\n items: paginatedItems,\n total,\n limit,\n offset,\n nextOffset,\n };\n}\n","import { Hono } from \"hono\";\nimport { z } from \"zod\";\nimport type { Library } from \"../../core/library.js\";\nimport { type SearchOperationOptions, searchReferences } from \"../../features/operations/search.js\";\nimport { searchSortFieldSchema, sortOrderSchema } from \"../../features/pagination/index.js\";\nimport { pickDefined } from \"../../utils/object.js\";\n\n/**\n * Request body schema for search endpoint\n */\nconst searchRequestBodySchema = z.object({\n query: z.string(),\n sort: searchSortFieldSchema.optional(),\n order: sortOrderSchema.optional(),\n limit: z.number().int().min(0).optional(),\n offset: z.number().int().min(0).optional(),\n});\n\n/**\n * Request body type for search endpoint\n */\nexport type SearchRequestBody = z.infer<typeof searchRequestBodySchema>;\n\n/**\n * Creates search route for HTTP server\n */\nexport function createSearchRoute(library: Library) {\n const route = new Hono();\n\n // POST / - Search references\n route.post(\"/\", async (c) => {\n // Parse request body\n let body: unknown;\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: \"Invalid JSON\" }, 400);\n }\n\n // Validate body with zod\n const parseResult = searchRequestBodySchema.safeParse(body);\n if (!parseResult.success) {\n const errorMessage = parseResult.error.issues[0]?.message ?? \"Invalid request body\";\n return c.json({ error: errorMessage }, 400);\n }\n\n const requestBody = parseResult.data;\n\n // Build options for searchReferences\n const options: SearchOperationOptions = {\n query: requestBody.query,\n ...pickDefined(requestBody, [\"sort\", \"order\", \"limit\", \"offset\"] as const),\n };\n\n // Call searchReferences operation - always returns raw CslItem[]\n const result = await searchReferences(library, options);\n\n return c.json(result);\n });\n\n return route;\n}\n","import { Hono } from \"hono\";\nimport type { Config } from \"../config/schema.js\";\nimport { Library } from \"../core/library.js\";\nimport { FileWatcher } from \"../features/file-watcher/file-watcher.js\";\nimport { createAddRoute } from \"./routes/add.js\";\nimport { createCiteRoute } from \"./routes/cite.js\";\nimport { healthRoute } from \"./routes/health.js\";\nimport { createListRoute } from \"./routes/list.js\";\nimport { createReferencesRoute } from \"./routes/references.js\";\nimport { createSearchRoute } from \"./routes/search.js\";\n\n/**\n * Result of starting a server with file watcher.\n */\nexport interface ServerWithFileWatcherResult {\n /** The Hono application */\n app: Hono;\n /** The library instance */\n library: Library;\n /** The file watcher instance */\n fileWatcher: FileWatcher;\n /** Dispose function to clean up resources */\n dispose: () => Promise<void>;\n}\n\n/**\n * Create the main Hono server application.\n * @param library - Library instance for the references API\n * @param config - Configuration for the server\n * @returns Hono application\n */\nexport function createServer(library: Library, config: Config) {\n const app = new Hono();\n\n // Health check route\n app.route(\"/health\", healthRoute);\n\n // References API routes\n const referencesRoute = createReferencesRoute(library);\n app.route(\"/api/references\", referencesRoute);\n\n // Add references route\n const addRoute = createAddRoute(library, config);\n app.route(\"/api/add\", addRoute);\n\n // Cite route\n const citeRoute = createCiteRoute(library);\n app.route(\"/api/cite\", citeRoute);\n\n // List route\n const listRoute = createListRoute(library);\n app.route(\"/api/list\", listRoute);\n\n // Search route\n const searchRoute = createSearchRoute(library);\n app.route(\"/api/search\", searchRoute);\n\n return app;\n}\n\n/**\n * Start a server with file watcher for automatic library reload.\n * Uses the same pattern as MCP server file monitoring.\n * @param libraryPath - Path to the library file\n * @param config - Configuration for the server\n * @returns Server with file watcher result\n */\nexport async function startServerWithFileWatcher(\n libraryPath: string,\n config: Config\n): Promise<ServerWithFileWatcherResult> {\n // Load library\n const library = await Library.load(libraryPath);\n\n // Create the Hono app\n const app = createServer(library, config);\n\n // Create and start file watcher\n const fileWatcher = new FileWatcher(libraryPath, {\n debounceMs: config.watch.debounceMs,\n maxRetries: config.watch.maxRetries,\n retryDelayMs: config.watch.retryIntervalMs,\n pollIntervalMs: config.watch.pollIntervalMs,\n });\n\n // Listen for file changes\n // Library.reload() handles self-write detection via hash comparison\n fileWatcher.on(\"change\", () => {\n library.reload().catch((error) => {\n // Log error but don't crash - library continues with previous state\n console.error(\"Failed to reload library:\", error);\n });\n });\n\n await fileWatcher.start();\n\n // Create dispose function\n const dispose = async (): Promise<void> => {\n fileWatcher.close();\n };\n\n return {\n app,\n library,\n fileWatcher,\n dispose,\n };\n}\n"],"names":["result","cite","DOI_URL_PREFIXES","identifiers","search","sorted","sortByRelevance"],"mappings":"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"}
|