/** * Crossref Provider Adapter — science search + get via the works JSON * API. * * Credential model (DESIGN D2 supplier table): keyless — no credential * model exists for Crossref at all. `credentialEnvVars` is `[]` * (Crossref's `mailto` is politeness, not a credential), and the cache * fingerprint is ALWAYS `""` (DESIGN D4b note: keyless responses are * user-independent; no keyed partition exists to re-partition into). * The env flows through `create({ env })`, never the transport seam. * * Politeness (DESIGN D2 politeness bullet): the house * `scoutline/${VERSION}` User-Agent rides every request WITH a * `mailto:` contact embedded in the UA itself — the Crossref * polite-pool convention (UA-carried mailto), unlike OpenAlex's * query-param convention. Unconditional: there is no keyed tier. * * Controls (DESIGN D7 table crossref column): `author`, `year`, * `venue`, and `type` are ALL wire-consumed together on ONE works call * (`query.author=`, `filter=from-pub-date`/`until-pub-date`, * `query.container-title=`, `filter=type:`). Crossref is the only v1 * supplier consuming venue. The `type` VALUE is rewritten per the D7 * round-2 translation table; Crossref consumes ALL seven union values * — no rejection row. * * Junk filter (PRD AC-4 + AC-8): `type: "component"` records (figure * /table components riding a real DOI) NEVER surface; the default * filter is EXACTLY the component drop — nothing more, so every * non-component record still surfaces. * * Parsing (DESIGN D2/D3, PRD AC-7c/AC-7d): deterministic JSON field * mapping. `title` and `container-title` arrive as ARRAYS (ScienceWork * carries strings); `author` given+family join into display strings; * `is-referenced-by-count` → `citationCount` (verbatim pin). Absent * supplier fields stay absent, never undefined-valued and never * fabricated. Crossref carries no abstracts — `summary` is honestly * absent (AC-7c). * * Identifiers (DESIGN D10 ruling 3): bare DOI → the `works/` * entity route (message-type "work" single-record response). PMID and * arXiv ids do NOT route to Crossref — rejected at validate with * `UnsupportedOptionError`. */ import type { ScienceCacheIdentity, ScienceGetRequest, ScienceSearchRequest, ScienceWork } from "../../capabilities/science.js"; import type { ProviderCapability, ProviderContext } from "../types.js"; import { type CrossrefTransportDeps } from "./client.js"; import { createCrossrefDiagnosticsCapability } from "./diagnostics.js"; /** Local science search contract — see the module header. */ interface CrossrefScienceSearchCapability { validate(request: ScienceSearchRequest): void; cacheIdentity(request: ScienceSearchRequest): ScienceCacheIdentity; invoke(request: ScienceSearchRequest, signal?: AbortSignal): Promise; } /** Local science get contract — see the module header. */ interface CrossrefScienceGetCapability { validate(request: ScienceGetRequest): void; cacheIdentity(request: ScienceGetRequest): ScienceCacheIdentity; invoke(request: ScienceGetRequest, signal?: AbortSignal): Promise; } /** Local ScienceCapability surface. */ interface CrossrefScienceCapability { readonly search: CrossrefScienceSearchCapability; readonly get: CrossrefScienceGetCapability; } /** * Dependencies the Crossref Adapter accepts. The unified `transport` * seam carries `fetch` and timer injection (house spider/arXiv/OpenAlex * pattern); credentials do not exist for Crossref, so nothing flows * through `create({ env })` beyond the context itself. */ export interface CrossrefAdapterDependencies { readonly transport?: CrossrefTransportDeps; } /** Local Adapter contract — see the module header. */ interface CrossrefAdapter { readonly id: "crossref"; readonly science: CrossrefScienceCapability; readonly diagnostics: ReturnType; } /** Local Descriptor contract — see the module header. */ interface CrossrefDescriptor { readonly id: "crossref"; isConfigured(env: NodeJS.ProcessEnv, capabilityId?: ProviderCapability): boolean; capabilities(): ReadonlySet; create(context: ProviderContext): CrossrefAdapter; readonly credentialEnvVars: readonly string[]; } /** * Build the Crossref Provider Descriptor. Keyless — no credential model * exists — so `isConfigured` is true for the no-capability form * (doctor) and the science duo + diagnostics — never `quota` or * non-science capabilities. `create()` is side-effect-free; transport * runs per capability call. */ export declare function createCrossrefDescriptor(dependencies?: CrossrefAdapterDependencies): CrossrefDescriptor; export {}; //# sourceMappingURL=adapter.d.ts.map