@mantra-ai/core 0.4.0 → 0.4.2
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/discovery/ranking.d.ts +2 -0
- package/dist/discovery/ranking.d.ts.map +1 -1
- package/dist/discovery/ranking.js +19 -1
- package/dist/discovery/ranking.js.map +1 -1
- package/dist/discovery/types.d.ts +4 -4
- package/dist/discovery/types.d.ts.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -3
- package/dist/index.js.map +1 -1
- package/dist/sources/crossref/client.d.ts +70 -0
- package/dist/sources/crossref/client.d.ts.map +1 -1
- package/dist/sources/crossref/client.js +190 -3
- package/dist/sources/crossref/client.js.map +1 -1
- package/dist/sources/crossref/provider.d.ts +20 -0
- package/dist/sources/crossref/provider.d.ts.map +1 -0
- package/dist/sources/crossref/provider.js +39 -0
- package/dist/sources/crossref/provider.js.map +1 -0
- package/dist/sources/opencitations/citation-graph-provider.d.ts +18 -0
- package/dist/sources/opencitations/citation-graph-provider.d.ts.map +1 -0
- package/dist/sources/opencitations/citation-graph-provider.js +119 -0
- package/dist/sources/opencitations/citation-graph-provider.js.map +1 -0
- package/dist/sources/opencitations/client.d.ts +29 -0
- package/dist/sources/opencitations/client.d.ts.map +1 -0
- package/dist/sources/opencitations/client.js +108 -0
- package/dist/sources/opencitations/client.js.map +1 -0
- package/package.json +1 -1
|
@@ -6,10 +6,12 @@ import type { DiscoverCandidateCore, DiscoverSourceKind } from "./types";
|
|
|
6
6
|
* - Mantra FTS: BM25 rank (negative float, lower = better match)
|
|
7
7
|
* - Zotero: match-location score (negative int, e.g. -15 for title match)
|
|
8
8
|
* - Semantic Scholar: position in relevance-ordered results (0-based index)
|
|
9
|
+
* - Crossref: raw relevance score (positive float, higher = better match)
|
|
9
10
|
* - null score: treated as 0.5 (neutral)
|
|
10
11
|
*/
|
|
11
12
|
export declare function normalizeScore(raw: number | null, sourceKind: DiscoverSourceKind, opts?: {
|
|
12
13
|
resultCount?: number;
|
|
14
|
+
maxRawScore?: number;
|
|
13
15
|
}): number;
|
|
14
16
|
/**
|
|
15
17
|
* Merge candidates from multiple sources.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ranking.d.ts","sourceRoot":"","sources":["../../src/discovery/ranking.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAkBzE
|
|
1
|
+
{"version":3,"file":"ranking.d.ts","sourceRoot":"","sources":["../../src/discovery/ranking.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAkBzE;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,GAAG,IAAI,EAClB,UAAU,EAAE,kBAAkB,EAC9B,IAAI,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GACpD,MAAM,CAuCR;AAiGD;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,qBAAqB,EAAE,GAClC,qBAAqB,EAAE,CAiDzB;AAID,MAAM,WAAW,QAAQ;IACvB,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,qBAAqB,EAAE,EACnC,IAAI,CAAC,EAAE,QAAQ,GACd,qBAAqB,EAAE,CAoCzB"}
|
|
@@ -15,6 +15,7 @@ const CITATION_SATURATION = 10_000;
|
|
|
15
15
|
* - Mantra FTS: BM25 rank (negative float, lower = better match)
|
|
16
16
|
* - Zotero: match-location score (negative int, e.g. -15 for title match)
|
|
17
17
|
* - Semantic Scholar: position in relevance-ordered results (0-based index)
|
|
18
|
+
* - Crossref: raw relevance score (positive float, higher = better match)
|
|
18
19
|
* - null score: treated as 0.5 (neutral)
|
|
19
20
|
*/
|
|
20
21
|
export function normalizeScore(raw, sourceKind, opts) {
|
|
@@ -39,6 +40,14 @@ export function normalizeScore(raw, sourceKind, opts) {
|
|
|
39
40
|
const count = opts?.resultCount ?? 20;
|
|
40
41
|
return Math.min(1, raw / Math.max(1, count));
|
|
41
42
|
}
|
|
43
|
+
case "crossref": {
|
|
44
|
+
// Crossref returns a positive relevance score (higher = better).
|
|
45
|
+
// Normalize as 1 - (score / maxScoreInBatch) so top result → ~0.
|
|
46
|
+
const max = opts?.maxRawScore;
|
|
47
|
+
if (max == null || max <= 0)
|
|
48
|
+
return 0.5;
|
|
49
|
+
return Math.max(0, Math.min(1, 1 - raw / max));
|
|
50
|
+
}
|
|
42
51
|
default: {
|
|
43
52
|
// Unknown source: assume raw is already roughly 0–1 or treat as neutral.
|
|
44
53
|
if (raw >= 0 && raw <= 1)
|
|
@@ -189,10 +198,19 @@ export function mergeCandidates(candidates) {
|
|
|
189
198
|
* 3. Sort ascending (lower = better). Deterministic tiebreak by title.
|
|
190
199
|
*/
|
|
191
200
|
export function rankCandidates(candidates, opts) {
|
|
201
|
+
// Pre-compute max raw score for Crossref candidates (Option B normalization)
|
|
202
|
+
const crossrefScores = candidates
|
|
203
|
+
.filter((c) => c.sources[0] === "crossref" && c.score != null)
|
|
204
|
+
.map((c) => c.score);
|
|
205
|
+
const crossrefMaxScore = crossrefScores.length > 0
|
|
206
|
+
? Math.max(...crossrefScores)
|
|
207
|
+
: undefined;
|
|
192
208
|
const scored = candidates.map((c) => {
|
|
193
209
|
// Use the first source for normalization context
|
|
194
210
|
const primarySource = c.sources[0] ?? "unknown";
|
|
195
|
-
const normalized = normalizeScore(c.score, primarySource
|
|
211
|
+
const normalized = normalizeScore(c.score, primarySource, {
|
|
212
|
+
maxRawScore: crossrefMaxScore,
|
|
213
|
+
});
|
|
196
214
|
// Boosts are subtracted (lower = better)
|
|
197
215
|
const finalScore = normalized -
|
|
198
216
|
localBoost(c) -
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ranking.js","sourceRoot":"","sources":["../../src/discovery/ranking.ts"],"names":[],"mappings":"AAEA,wEAAwE;AAExE,6DAA6D;AAC7D,MAAM,WAAW,GAAG,IAAI,CAAC;AAEzB,sDAAsD;AACtD,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAEhC,mDAAmD;AACnD,MAAM,iBAAiB,GAAG,IAAI,CAAC;AAE/B,4DAA4D;AAC5D,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAEnC,wEAAwE;AAExE
|
|
1
|
+
{"version":3,"file":"ranking.js","sourceRoot":"","sources":["../../src/discovery/ranking.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,7 +10,7 @@ export type DiscoverCapability = "search" | "augment";
|
|
|
10
10
|
* Extensible source identifier.
|
|
11
11
|
* Built-in kinds are listed here; providers may add new ones.
|
|
12
12
|
*/
|
|
13
|
-
export type DiscoverSourceKind = "mantra" | "zotero" | "pdf-index" | "semantic-scholar" | "semantic-scholar-citation-graph" | (string & {});
|
|
13
|
+
export type DiscoverSourceKind = "mantra" | "zotero" | "pdf-index" | "semantic-scholar" | "semantic-scholar-citation-graph" | "crossref" | "opencitations-citation-graph" | (string & {});
|
|
14
14
|
/**
|
|
15
15
|
* Tracks which seed paper(s) led to a candidate during citation-graph expansion.
|
|
16
16
|
*/
|
|
@@ -41,11 +41,11 @@ export interface DiscoverCandidateCore {
|
|
|
41
41
|
zoteroKey?: string | null;
|
|
42
42
|
/** Resolved local PDF path — set by PDF index augmenter or Zotero. */
|
|
43
43
|
pdfPath?: string | null;
|
|
44
|
-
/** Semantic Scholar paper ID. */
|
|
44
|
+
/** Semantic Scholar paper ID (legacy, kept for backward compat). */
|
|
45
45
|
semanticScholarId?: string | null;
|
|
46
|
-
/** Total citation count. */
|
|
46
|
+
/** Total citation count (from Crossref is-referenced-by-count or S2). */
|
|
47
47
|
citationCount?: number | null;
|
|
48
|
-
/** Influential citation count (Semantic Scholar). */
|
|
48
|
+
/** Influential citation count (Semantic Scholar only, legacy). */
|
|
49
49
|
influentialCitationCount?: number | null;
|
|
50
50
|
/** Short abstract or snippet. */
|
|
51
51
|
abstractSnippet?: string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/discovery/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,8BAA8B;AAC9B,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,SAAS,CAAC;AAItD;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAC1B,QAAQ,GACR,QAAQ,GACR,WAAW,GACX,kBAAkB,GAClB,iCAAiC,GACjC,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAIlB;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,kEAAkE;IAClE,GAAG,EAAE,MAAM,CAAC;IACZ,8CAA8C;IAC9C,QAAQ,EAAE,YAAY,GAAG,UAAU,CAAC;CACrC;AAID;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAEpB,mDAAmD;IACnD,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAE9B,mEAAmE;IACnE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAIrB,wFAAwF;IACxF,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAIxB,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/discovery/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,8BAA8B;AAC9B,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,SAAS,CAAC;AAItD;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAC1B,QAAQ,GACR,QAAQ,GACR,WAAW,GACX,kBAAkB,GAClB,iCAAiC,GACjC,UAAU,GACV,8BAA8B,GAC9B,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAIlB;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,kEAAkE;IAClE,GAAG,EAAE,MAAM,CAAC;IACZ,8CAA8C;IAC9C,QAAQ,EAAE,YAAY,GAAG,UAAU,CAAC;CACrC;AAID;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAEpB,mDAAmD;IACnD,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAE9B,mEAAmE;IACnE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAIrB,wFAAwF;IACxF,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAIxB,oEAAoE;IACpE,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,yEAAyE;IACzE,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,kEAAkE;IAClE,wBAAwB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,iCAAiC;IACjC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,kCAAkC;IAClC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAIpB,mFAAmF;IACnF,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;CAC5B;AAID,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,qDAAqD;IACrD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,0CAA0C;IAC1C,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC;IAExC,iCAAiC;IACjC,QAAQ,CAAC,YAAY,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAErD,uEAAuE;IACvE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAE1B;;;OAGG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAAC;IAEnF;;;;OAIG;IACH,OAAO,CAAC,CAAC,UAAU,EAAE,qBAAqB,EAAE,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAAC;CACjF;AAID,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAID,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,qBAAqB,EAAE,CAAC;IAC/B,MAAM,EAAE,qBAAqB,EAAE,CAAC;IAChC,MAAM,EAAE,aAAa,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,kBAAkB,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC;CACf"}
|
package/dist/index.d.ts
CHANGED
|
@@ -22,8 +22,12 @@ export type { DiscoverCapability, DiscoverSourceKind, DiscoverCandidateCore, Dis
|
|
|
22
22
|
export { ProviderRegistry } from "./discovery/registry";
|
|
23
23
|
export { normalizeScore, mergeCandidates, rankCandidates, } from "./discovery/ranking";
|
|
24
24
|
export type { RankOpts } from "./discovery/ranking";
|
|
25
|
-
export {
|
|
26
|
-
export {
|
|
25
|
+
export { CrossrefProvider } from "./sources/crossref/provider";
|
|
26
|
+
export { crossrefWorkToCandidate } from "./sources/crossref/provider";
|
|
27
|
+
export { searchWorks as crossrefSearchWorks, getWorkByDoi as crossrefGetWorkByDoi, batchHydrateByDois as crossrefBatchHydrate, } from "./sources/crossref/client";
|
|
28
|
+
export type { CrossrefWork, CrossrefAuthor, CrossrefSearchResponse, } from "./sources/crossref/client";
|
|
29
|
+
export { OpenCitationsCitationGraphProvider } from "./sources/opencitations/citation-graph-provider";
|
|
30
|
+
export { getReferences as cociGetReferences, getCitations as cociGetCitations, } from "./sources/opencitations/client";
|
|
27
31
|
export { searchPapers as s2SearchPapers, getPaperDetails as s2GetPaperDetails, getPaperReferences as s2GetPaperReferences, getPaperCitations as s2GetPaperCitations, } from "./sources/semantic-scholar/client";
|
|
28
32
|
export type { S2Paper, S2Author, S2ExternalIds, S2SearchResponse, S2CitationEdge, S2CitationResponse, S2ClientOpts, } from "./sources/semantic-scholar/client";
|
|
29
33
|
export type { PaperDigest, HypothesisSet, Hypothesis } from "./analysis/schemas";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AAGjC,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACrE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGxD,YAAY,EACV,aAAa,EACb,mBAAmB,EACnB,aAAa,EACb,WAAW,EACX,YAAY,EACZ,UAAU,EACV,cAAc,EACd,aAAa,EACb,aAAa,EACb,cAAc,EACd,WAAW,EACX,gBAAgB,EAChB,WAAW,EACX,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,UAAU,EACV,iBAAiB,EACjB,YAAY,EACZ,UAAU,EACV,IAAI,EACJ,eAAe,EACf,YAAY,EACZ,eAAe,EACf,WAAW,EACX,eAAe,EACf,gBAAgB,EAChB,WAAW,GACZ,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC,YAAY,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC3E,OAAO,EACL,YAAY,EACZ,SAAS,EACT,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,6BAA6B,EAAE,MAAM,0BAA0B,CAAC;AACzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,YAAY,EAAE,MAAM,EAAE,MAAM,kCAAkC,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,YAAY,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAGvE,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC3E,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,4BAA4B,GAC7B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGpD,OAAO,EACL,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,uCAAuC,CAAC;AAC/C,YAAY,EAAE,aAAa,EAAE,MAAM,uCAAuC,CAAC;AAG3E,YAAY,EACV,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,EACpB,aAAa,EACb,UAAU,GACX,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EACL,cAAc,EACd,eAAe,EACf,cAAc,GACf,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAGpD,OAAO,EAAE,uBAAuB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -20,9 +20,14 @@ export { createWorkId } from "./works/util/work-id";
|
|
|
20
20
|
export { NormalizedDocSchema, SectionCategoryEnum, } from "./normalization/normalized-doc-schema";
|
|
21
21
|
export { ProviderRegistry } from "./discovery/registry";
|
|
22
22
|
export { normalizeScore, mergeCandidates, rankCandidates, } from "./discovery/ranking";
|
|
23
|
-
// ── Sources:
|
|
24
|
-
export {
|
|
25
|
-
export {
|
|
23
|
+
// ── Sources: Crossref (discovery) ────────────────────────────────
|
|
24
|
+
export { CrossrefProvider } from "./sources/crossref/provider";
|
|
25
|
+
export { crossrefWorkToCandidate } from "./sources/crossref/provider";
|
|
26
|
+
export { searchWorks as crossrefSearchWorks, getWorkByDoi as crossrefGetWorkByDoi, batchHydrateByDois as crossrefBatchHydrate, } from "./sources/crossref/client";
|
|
27
|
+
// ── Sources: OpenCitations (citation graph) ─────────────────────
|
|
28
|
+
export { OpenCitationsCitationGraphProvider } from "./sources/opencitations/citation-graph-provider";
|
|
29
|
+
export { getReferences as cociGetReferences, getCitations as cociGetCitations, } from "./sources/opencitations/client";
|
|
30
|
+
// ── Sources: Semantic Scholar (legacy, retained for ingest paths) ──
|
|
26
31
|
export { searchPapers as s2SearchPapers, getPaperDetails as s2GetPaperDetails, getPaperReferences as s2GetPaperReferences, getPaperCitations as s2GetPaperCitations, } from "./sources/semantic-scholar/client";
|
|
27
32
|
export { PaperDigestSchema, HypothesisSetSchema } from "./analysis/schemas";
|
|
28
33
|
export { extractFindings } from "./analysis/extract-findings";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iCAAiC;AAEjC,sEAAsE;AACtE,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AAEjC,sEAAsE;AACtE,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAsCrE,sEAAsE;AACtE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAIzC,OAAO,EACL,YAAY,EACZ,SAAS,EACT,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,6BAA6B,EAAE,MAAM,0BAA0B,CAAC;AACzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAEvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAGhE,sEAAsE;AACtE,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC3E,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,4BAA4B,GAC7B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEpD,sEAAsE;AACtE,OAAO,EACL,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,uCAAuC,CAAC;AAe/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EACL,cAAc,EACd,eAAe,EACf,cAAc,GACf,MAAM,qBAAqB,CAAC;AAG7B,oEAAoE;AACpE,OAAO,EAAE,uBAAuB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iCAAiC;AAEjC,sEAAsE;AACtE,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AAEjC,sEAAsE;AACtE,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAsCrE,sEAAsE;AACtE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAIzC,OAAO,EACL,YAAY,EACZ,SAAS,EACT,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,6BAA6B,EAAE,MAAM,0BAA0B,CAAC;AACzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAEvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAGhE,sEAAsE;AACtE,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC3E,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,4BAA4B,GAC7B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEpD,sEAAsE;AACtE,OAAO,EACL,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,uCAAuC,CAAC;AAe/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EACL,cAAc,EACd,eAAe,EACf,cAAc,GACf,MAAM,qBAAqB,CAAC;AAG7B,oEAAoE;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,EACL,WAAW,IAAI,mBAAmB,EAClC,YAAY,IAAI,oBAAoB,EACpC,kBAAkB,IAAI,oBAAoB,GAC3C,MAAM,2BAA2B,CAAC;AAOnC,mEAAmE;AACnE,OAAO,EAAE,kCAAkC,EAAE,MAAM,iDAAiD,CAAC;AACrG,OAAO,EACL,aAAa,IAAI,iBAAiB,EAClC,YAAY,IAAI,gBAAgB,GACjC,MAAM,gCAAgC,CAAC;AAExC,sEAAsE;AACtE,OAAO,EACL,YAAY,IAAI,cAAc,EAC9B,eAAe,IAAI,iBAAiB,EACpC,kBAAkB,IAAI,oBAAoB,EAC1C,iBAAiB,IAAI,mBAAmB,GACzC,MAAM,mCAAmC,CAAC;AAa3C,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC"}
|
|
@@ -1,3 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed client for the Crossref REST API.
|
|
3
|
+
*
|
|
4
|
+
* Free, no API key required. Uses the polite pool via `mailto` parameter
|
|
5
|
+
* for better rate limits.
|
|
6
|
+
*
|
|
7
|
+
* @see https://api.crossref.org/swagger-ui/index.html
|
|
8
|
+
*/
|
|
1
9
|
import type { AdapterResult } from "../../works/types";
|
|
10
|
+
export interface CrossrefWork {
|
|
11
|
+
DOI: string;
|
|
12
|
+
title?: string[];
|
|
13
|
+
author?: CrossrefAuthor[];
|
|
14
|
+
"published-print"?: CrossrefDate;
|
|
15
|
+
"published-online"?: CrossrefDate;
|
|
16
|
+
published?: CrossrefDate;
|
|
17
|
+
"container-title"?: string[];
|
|
18
|
+
score?: number;
|
|
19
|
+
"is-referenced-by-count"?: number;
|
|
20
|
+
"references-count"?: number;
|
|
21
|
+
abstract?: string;
|
|
22
|
+
URL?: string;
|
|
23
|
+
"reference"?: CrossrefReference[];
|
|
24
|
+
}
|
|
25
|
+
export interface CrossrefAuthor {
|
|
26
|
+
given?: string;
|
|
27
|
+
family?: string;
|
|
28
|
+
name?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface CrossrefDate {
|
|
31
|
+
"date-parts"?: number[][];
|
|
32
|
+
}
|
|
33
|
+
export interface CrossrefReference {
|
|
34
|
+
DOI?: string;
|
|
35
|
+
key?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface CrossrefSearchResponse {
|
|
38
|
+
total: number;
|
|
39
|
+
items: CrossrefWork[];
|
|
40
|
+
}
|
|
41
|
+
/** Extract the best publication year from a Crossref work. */
|
|
42
|
+
export declare function extractYear(work: CrossrefWork): number | null;
|
|
43
|
+
/** Format authors into a single string. */
|
|
44
|
+
export declare function formatAuthors(authors?: CrossrefAuthor[]): string | null;
|
|
45
|
+
/** Extract first title from the title array. */
|
|
46
|
+
export declare function extractTitle(work: CrossrefWork): string | null;
|
|
47
|
+
/** Extract venue/journal name. */
|
|
48
|
+
export declare function extractVenue(work: CrossrefWork): string | null;
|
|
49
|
+
/** Truncate abstract to a snippet. */
|
|
50
|
+
export declare function extractAbstract(work: CrossrefWork): string | null;
|
|
51
|
+
/**
|
|
52
|
+
* Fetch a single Crossref work by DOI (existing ingest pathway).
|
|
53
|
+
*/
|
|
2
54
|
export declare function fetchCrossrefWorkByDoi(doi: string): Promise<AdapterResult<any>>;
|
|
55
|
+
/**
|
|
56
|
+
* Search for works by keyword query.
|
|
57
|
+
* Results are sorted by Crossref relevance score (descending).
|
|
58
|
+
*/
|
|
59
|
+
export declare function searchWorks(query: string, opts?: {
|
|
60
|
+
limit?: number;
|
|
61
|
+
offset?: number;
|
|
62
|
+
mailto?: string;
|
|
63
|
+
}): Promise<AdapterResult<CrossrefSearchResponse>>;
|
|
64
|
+
/**
|
|
65
|
+
* Fetch a single Crossref work by DOI as a typed CrossrefWork.
|
|
66
|
+
*/
|
|
67
|
+
export declare function getWorkByDoi(doi: string): Promise<AdapterResult<CrossrefWork>>;
|
|
68
|
+
/**
|
|
69
|
+
* Fetch metadata for multiple DOIs in batches with bounded concurrency.
|
|
70
|
+
* Returns a DOI-keyed map. Missing/failed DOIs are silently omitted.
|
|
71
|
+
*/
|
|
72
|
+
export declare function batchHydrateByDois(dois: string[]): Promise<Map<string, CrossrefWork>>;
|
|
3
73
|
//# sourceMappingURL=client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/sources/crossref/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/sources/crossref/client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAkBvD,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,CAAC,EAAE,cAAc,EAAE,CAAC;IAC1B,iBAAiB,CAAC,EAAE,YAAY,CAAC;IACjC,kBAAkB,CAAC,EAAE,YAAY,CAAC;IAClC,SAAS,CAAC,EAAE,YAAY,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,iBAAiB,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,YAAY,EAAE,CAAC;CACvB;AAwCD,8DAA8D;AAC9D,wBAAgB,WAAW,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,GAAG,IAAI,CAO7D;AAED,2CAA2C;AAC3C,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE,cAAc,EAAE,GAAG,MAAM,GAAG,IAAI,CAUvE;AAED,gDAAgD;AAChD,wBAAgB,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,GAAG,IAAI,CAE9D;AAED,kCAAkC;AAClC,wBAAgB,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,GAAG,IAAI,CAE9D;AAED,sCAAsC;AACtC,wBAAgB,eAAe,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,GAAG,IAAI,CAMjE;AAID;;GAEG;AACH,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAiB7B;AAID;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1D,OAAO,CAAC,aAAa,CAAC,sBAAsB,CAAC,CAAC,CAuChD;AAID;;GAEG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAiBtC;AAID;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EAAE,GACb,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAyBpC"}
|
|
@@ -1,8 +1,98 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Typed client for the Crossref REST API.
|
|
3
|
+
*
|
|
4
|
+
* Free, no API key required. Uses the polite pool via `mailto` parameter
|
|
5
|
+
* for better rate limits.
|
|
6
|
+
*
|
|
7
|
+
* @see https://api.crossref.org/swagger-ui/index.html
|
|
8
|
+
*/
|
|
9
|
+
const BASE_URL = "https://api.crossref.org";
|
|
10
|
+
/** Max retries on 429 / 5xx before giving up. */
|
|
11
|
+
const MAX_RETRIES = 2;
|
|
12
|
+
/** Request timeout in ms. */
|
|
13
|
+
const REQUEST_TIMEOUT_MS = 15_000;
|
|
14
|
+
/** Max concurrent requests for batch operations. */
|
|
15
|
+
const BATCH_CONCURRENCY = 5;
|
|
16
|
+
/** Chunk size for batch DOI lookups. */
|
|
17
|
+
const BATCH_CHUNK_SIZE = 20;
|
|
18
|
+
// ── Helpers ──────────────────────────────────────────────────────────
|
|
19
|
+
const HEADERS = {
|
|
20
|
+
Accept: "application/json",
|
|
21
|
+
};
|
|
22
|
+
async function fetchWithRetry(url) {
|
|
23
|
+
let lastError;
|
|
24
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
25
|
+
try {
|
|
26
|
+
const res = await fetch(url, {
|
|
27
|
+
headers: HEADERS,
|
|
28
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
29
|
+
});
|
|
30
|
+
if ((res.status === 429 || res.status >= 500) && attempt < MAX_RETRIES) {
|
|
31
|
+
await new Promise((r) => setTimeout(r, 1000 * (attempt + 1)));
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
return res;
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
lastError = e;
|
|
38
|
+
if (attempt < MAX_RETRIES) {
|
|
39
|
+
await new Promise((r) => setTimeout(r, 1000 * (attempt + 1)));
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
throw lastError ?? new Error("fetchWithRetry exhausted");
|
|
45
|
+
}
|
|
46
|
+
// ── Parsing helpers ──────────────────────────────────────────────────
|
|
47
|
+
/** Extract the best publication year from a Crossref work. */
|
|
48
|
+
export function extractYear(work) {
|
|
49
|
+
const dateParts = work.published?.["date-parts"]?.[0] ??
|
|
50
|
+
work["published-online"]?.["date-parts"]?.[0] ??
|
|
51
|
+
work["published-print"]?.["date-parts"]?.[0];
|
|
52
|
+
const year = dateParts?.[0];
|
|
53
|
+
return typeof year === "number" && year > 0 ? year : null;
|
|
54
|
+
}
|
|
55
|
+
/** Format authors into a single string. */
|
|
56
|
+
export function formatAuthors(authors) {
|
|
57
|
+
if (!authors || authors.length === 0)
|
|
58
|
+
return null;
|
|
59
|
+
return authors
|
|
60
|
+
.map((a) => {
|
|
61
|
+
if (a.name)
|
|
62
|
+
return a.name;
|
|
63
|
+
if (a.family && a.given)
|
|
64
|
+
return `${a.given} ${a.family}`;
|
|
65
|
+
return a.family ?? a.given ?? null;
|
|
66
|
+
})
|
|
67
|
+
.filter(Boolean)
|
|
68
|
+
.join(", ") || null;
|
|
69
|
+
}
|
|
70
|
+
/** Extract first title from the title array. */
|
|
71
|
+
export function extractTitle(work) {
|
|
72
|
+
return work.title?.[0] ?? null;
|
|
73
|
+
}
|
|
74
|
+
/** Extract venue/journal name. */
|
|
75
|
+
export function extractVenue(work) {
|
|
76
|
+
return work["container-title"]?.[0] ?? null;
|
|
77
|
+
}
|
|
78
|
+
/** Truncate abstract to a snippet. */
|
|
79
|
+
export function extractAbstract(work) {
|
|
80
|
+
if (!work.abstract)
|
|
81
|
+
return null;
|
|
82
|
+
// Crossref abstracts may contain JATS XML tags — strip them
|
|
83
|
+
const plain = work.abstract.replace(/<[^>]+>/g, "").trim();
|
|
84
|
+
if (!plain)
|
|
85
|
+
return null;
|
|
86
|
+
return plain.length > 200 ? plain.slice(0, 197) + "..." : plain;
|
|
87
|
+
}
|
|
88
|
+
// ── Public API: existing ingest adapter ──────────────────────────────
|
|
89
|
+
/**
|
|
90
|
+
* Fetch a single Crossref work by DOI (existing ingest pathway).
|
|
91
|
+
*/
|
|
2
92
|
export async function fetchCrossrefWorkByDoi(doi) {
|
|
3
|
-
const url =
|
|
93
|
+
const url = `${BASE_URL}/works/${encodeURIComponent(doi)}`;
|
|
4
94
|
try {
|
|
5
|
-
const res = await
|
|
95
|
+
const res = await fetchWithRetry(url);
|
|
6
96
|
if (!res.ok) {
|
|
7
97
|
const status = res.status;
|
|
8
98
|
if (status === 404)
|
|
@@ -21,4 +111,101 @@ export async function fetchCrossrefWorkByDoi(doi) {
|
|
|
21
111
|
return { ok: false, reason: "network_error" };
|
|
22
112
|
}
|
|
23
113
|
}
|
|
114
|
+
// ── Public API: discovery search ─────────────────────────────────────
|
|
115
|
+
/**
|
|
116
|
+
* Search for works by keyword query.
|
|
117
|
+
* Results are sorted by Crossref relevance score (descending).
|
|
118
|
+
*/
|
|
119
|
+
export async function searchWorks(query, opts) {
|
|
120
|
+
const rows = Math.min(opts?.limit ?? 20, 100);
|
|
121
|
+
const offset = opts?.offset ?? 0;
|
|
122
|
+
const params = new URLSearchParams({
|
|
123
|
+
query,
|
|
124
|
+
rows: String(rows),
|
|
125
|
+
offset: String(offset),
|
|
126
|
+
sort: "relevance",
|
|
127
|
+
order: "desc",
|
|
128
|
+
});
|
|
129
|
+
if (opts?.mailto)
|
|
130
|
+
params.set("mailto", opts.mailto);
|
|
131
|
+
const url = `${BASE_URL}/works?${params}`;
|
|
132
|
+
try {
|
|
133
|
+
const res = await fetchWithRetry(url);
|
|
134
|
+
if (!res.ok) {
|
|
135
|
+
const status = res.status;
|
|
136
|
+
if (status === 400)
|
|
137
|
+
return { ok: false, status, reason: "not_found" };
|
|
138
|
+
if (status === 429)
|
|
139
|
+
return { ok: false, status, reason: "rate_limited" };
|
|
140
|
+
return { ok: false, status, reason: "upstream_error" };
|
|
141
|
+
}
|
|
142
|
+
const data = await res.json();
|
|
143
|
+
const message = data?.message;
|
|
144
|
+
if (!message)
|
|
145
|
+
return { ok: false, reason: "upstream_error" };
|
|
146
|
+
return {
|
|
147
|
+
ok: true,
|
|
148
|
+
data: {
|
|
149
|
+
total: message["total-results"] ?? 0,
|
|
150
|
+
items: (message.items ?? []),
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
return { ok: false, reason: "network_error" };
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// ── Public API: typed single-work fetch ──────────────────────────────
|
|
159
|
+
/**
|
|
160
|
+
* Fetch a single Crossref work by DOI as a typed CrossrefWork.
|
|
161
|
+
*/
|
|
162
|
+
export async function getWorkByDoi(doi) {
|
|
163
|
+
const url = `${BASE_URL}/works/${encodeURIComponent(doi)}`;
|
|
164
|
+
try {
|
|
165
|
+
const res = await fetchWithRetry(url);
|
|
166
|
+
if (!res.ok) {
|
|
167
|
+
const status = res.status;
|
|
168
|
+
if (status === 404)
|
|
169
|
+
return { ok: false, status, reason: "not_found" };
|
|
170
|
+
if (status === 429)
|
|
171
|
+
return { ok: false, status, reason: "rate_limited" };
|
|
172
|
+
return { ok: false, status, reason: "upstream_error" };
|
|
173
|
+
}
|
|
174
|
+
const data = await res.json();
|
|
175
|
+
const work = data?.message;
|
|
176
|
+
if (!work?.DOI)
|
|
177
|
+
return { ok: false, reason: "not_found" };
|
|
178
|
+
return { ok: true, data: work };
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
return { ok: false, reason: "network_error" };
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// ── Public API: batch DOI hydration ──────────────────────────────────
|
|
185
|
+
/**
|
|
186
|
+
* Fetch metadata for multiple DOIs in batches with bounded concurrency.
|
|
187
|
+
* Returns a DOI-keyed map. Missing/failed DOIs are silently omitted.
|
|
188
|
+
*/
|
|
189
|
+
export async function batchHydrateByDois(dois) {
|
|
190
|
+
const results = new Map();
|
|
191
|
+
if (dois.length === 0)
|
|
192
|
+
return results;
|
|
193
|
+
// Deduplicate and normalize
|
|
194
|
+
const uniqueDois = [...new Set(dois.map((d) => d.toLowerCase()))];
|
|
195
|
+
// Process in chunks with bounded concurrency
|
|
196
|
+
for (let i = 0; i < uniqueDois.length; i += BATCH_CHUNK_SIZE) {
|
|
197
|
+
const chunk = uniqueDois.slice(i, i + BATCH_CHUNK_SIZE);
|
|
198
|
+
const promises = chunk.map(async (doi) => {
|
|
199
|
+
const result = await getWorkByDoi(doi);
|
|
200
|
+
if (result.ok) {
|
|
201
|
+
results.set(doi.toLowerCase(), result.data);
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
// Run chunk with bounded concurrency
|
|
205
|
+
for (let j = 0; j < promises.length; j += BATCH_CONCURRENCY) {
|
|
206
|
+
await Promise.allSettled(promises.slice(j, j + BATCH_CONCURRENCY));
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return results;
|
|
210
|
+
}
|
|
24
211
|
//# sourceMappingURL=client.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/sources/crossref/client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/sources/crossref/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Crossref discovery provider.
|
|
3
|
+
*
|
|
4
|
+
* Adapts the Crossref API client to the DiscoverProvider interface.
|
|
5
|
+
*/
|
|
6
|
+
import type { DiscoverCandidateCore, DiscoverProvider, DiscoverSearchOpts } from "../../discovery/types";
|
|
7
|
+
import { type CrossrefWork } from "./client";
|
|
8
|
+
/**
|
|
9
|
+
* Map a CrossrefWork to a DiscoverCandidateCore.
|
|
10
|
+
* Preserves the raw Crossref relevance score for ranking normalization.
|
|
11
|
+
*/
|
|
12
|
+
export declare function crossrefWorkToCandidate(work: CrossrefWork): DiscoverCandidateCore;
|
|
13
|
+
export declare class CrossrefProvider implements DiscoverProvider {
|
|
14
|
+
readonly name = "Crossref";
|
|
15
|
+
readonly sourceKind: "crossref";
|
|
16
|
+
readonly capabilities: readonly ["search"];
|
|
17
|
+
readonly isLocal = false;
|
|
18
|
+
search(query: string, opts?: DiscoverSearchOpts): Promise<DiscoverCandidateCore[]>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../../src/sources/crossref/provider.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,qBAAqB,EACrB,gBAAgB,EAChB,kBAAkB,EACnB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAOL,KAAK,YAAY,EAClB,MAAM,UAAU,CAAC;AAElB;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,YAAY,GACjB,qBAAqB,CAavB;AAED,qBAAa,gBAAiB,YAAW,gBAAgB;IACvD,QAAQ,CAAC,IAAI,cAAc;IAC3B,QAAQ,CAAC,UAAU,EAAG,UAAU,CAAU;IAC1C,QAAQ,CAAC,YAAY,sBAAuB;IAC5C,QAAQ,CAAC,OAAO,SAAS;IAEnB,MAAM,CACV,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,kBAAkB,GACxB,OAAO,CAAC,qBAAqB,EAAE,CAAC;CAapC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Crossref discovery provider.
|
|
3
|
+
*
|
|
4
|
+
* Adapts the Crossref API client to the DiscoverProvider interface.
|
|
5
|
+
*/
|
|
6
|
+
import { searchWorks, extractTitle, extractYear, formatAuthors, extractVenue, extractAbstract, } from "./client";
|
|
7
|
+
/**
|
|
8
|
+
* Map a CrossrefWork to a DiscoverCandidateCore.
|
|
9
|
+
* Preserves the raw Crossref relevance score for ranking normalization.
|
|
10
|
+
*/
|
|
11
|
+
export function crossrefWorkToCandidate(work) {
|
|
12
|
+
return {
|
|
13
|
+
doi: work.DOI ?? null,
|
|
14
|
+
title: extractTitle(work),
|
|
15
|
+
authors: formatAuthors(work.author),
|
|
16
|
+
year: extractYear(work),
|
|
17
|
+
sources: ["crossref"],
|
|
18
|
+
score: work.score ?? null,
|
|
19
|
+
citationCount: work["is-referenced-by-count"] ?? null,
|
|
20
|
+
abstractSnippet: extractAbstract(work),
|
|
21
|
+
venue: extractVenue(work),
|
|
22
|
+
url: work.URL ?? null,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export class CrossrefProvider {
|
|
26
|
+
name = "Crossref";
|
|
27
|
+
sourceKind = "crossref";
|
|
28
|
+
capabilities = ["search"];
|
|
29
|
+
isLocal = false;
|
|
30
|
+
async search(query, opts) {
|
|
31
|
+
const limit = opts?.limit ?? 20;
|
|
32
|
+
const result = await searchWorks(query, { limit });
|
|
33
|
+
if (!result.ok) {
|
|
34
|
+
throw new Error(`Crossref search failed: ${result.reason}${result.status ? ` (${result.status})` : ""}`);
|
|
35
|
+
}
|
|
36
|
+
return result.data.items.map((work) => crossrefWorkToCandidate(work));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../../src/sources/crossref/provider.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,EACL,WAAW,EACX,YAAY,EACZ,WAAW,EACX,aAAa,EACb,YAAY,EACZ,eAAe,GAEhB,MAAM,UAAU,CAAC;AAElB;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CACrC,IAAkB;IAElB,OAAO;QACL,GAAG,EAAE,IAAI,CAAC,GAAG,IAAI,IAAI;QACrB,KAAK,EAAE,YAAY,CAAC,IAAI,CAAC;QACzB,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC;QACnC,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC;QACvB,OAAO,EAAE,CAAC,UAAU,CAAC;QACrB,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,IAAI;QACzB,aAAa,EAAE,IAAI,CAAC,wBAAwB,CAAC,IAAI,IAAI;QACrD,eAAe,EAAE,eAAe,CAAC,IAAI,CAAC;QACtC,KAAK,EAAE,YAAY,CAAC,IAAI,CAAC;QACzB,GAAG,EAAE,IAAI,CAAC,GAAG,IAAI,IAAI;KACtB,CAAC;AACJ,CAAC;AAED,MAAM,OAAO,gBAAgB;IAClB,IAAI,GAAG,UAAU,CAAC;IAClB,UAAU,GAAG,UAAmB,CAAC;IACjC,YAAY,GAAG,CAAC,QAAQ,CAAU,CAAC;IACnC,OAAO,GAAG,KAAK,CAAC;IAEzB,KAAK,CAAC,MAAM,CACV,KAAa,EACb,IAAyB;QAEzB,MAAM,KAAK,GAAG,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;QAEhC,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QAEnD,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CACb,2BAA2B,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACxF,CAAC;QACJ,CAAC;QAED,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,uBAAuB,CAAC,IAAI,CAAC,CAAC,CAAC;IACxE,CAAC;CACF"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCitations COCI citation-graph discovery provider.
|
|
3
|
+
*
|
|
4
|
+
* Expands from a set of seed DOIs by fetching their references (bibliography)
|
|
5
|
+
* and citations (downstream work) via OpenCitations, then hydrates metadata
|
|
6
|
+
* from Crossref before returning deduplicated candidates.
|
|
7
|
+
*/
|
|
8
|
+
import type { DiscoverCandidateCore, DiscoverProvider, DiscoverSearchOpts } from "../../discovery/types";
|
|
9
|
+
export declare class OpenCitationsCitationGraphProvider implements DiscoverProvider {
|
|
10
|
+
readonly name = "OpenCitations Citation Graph";
|
|
11
|
+
readonly sourceKind: "opencitations-citation-graph";
|
|
12
|
+
readonly capabilities: readonly ["search"];
|
|
13
|
+
readonly isLocal = false;
|
|
14
|
+
private seedDois;
|
|
15
|
+
constructor(seedDois: string[]);
|
|
16
|
+
search(_query: string, opts?: DiscoverSearchOpts): Promise<DiscoverCandidateCore[]>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=citation-graph-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"citation-graph-provider.d.ts","sourceRoot":"","sources":["../../../src/sources/opencitations/citation-graph-provider.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EACV,qBAAqB,EACrB,gBAAgB,EAChB,kBAAkB,EAEnB,MAAM,uBAAuB,CAAC;AAyB/B,qBAAa,kCAAmC,YAAW,gBAAgB;IACzE,QAAQ,CAAC,IAAI,kCAAkC;IAC/C,QAAQ,CAAC,UAAU,EAAG,8BAA8B,CAAU;IAC9D,QAAQ,CAAC,YAAY,sBAAuB;IAC5C,QAAQ,CAAC,OAAO,SAAS;IAEzB,OAAO,CAAC,QAAQ,CAAW;gBAEf,QAAQ,EAAE,MAAM,EAAE;IAIxB,MAAM,CACV,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,kBAAkB,GACxB,OAAO,CAAC,qBAAqB,EAAE,CAAC;CAyFpC"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCitations COCI citation-graph discovery provider.
|
|
3
|
+
*
|
|
4
|
+
* Expands from a set of seed DOIs by fetching their references (bibliography)
|
|
5
|
+
* and citations (downstream work) via OpenCitations, then hydrates metadata
|
|
6
|
+
* from Crossref before returning deduplicated candidates.
|
|
7
|
+
*/
|
|
8
|
+
import { getReferences, getCitations } from "./client";
|
|
9
|
+
import { batchHydrateByDois, extractTitle, extractYear, formatAuthors, extractVenue, extractAbstract, } from "../crossref/client";
|
|
10
|
+
/** Max concurrent seed expansions to avoid burst traffic. */
|
|
11
|
+
const MAX_CONCURRENCY = 3;
|
|
12
|
+
/** Max results per direction per seed. */
|
|
13
|
+
const PER_SEED_LIMIT = 50;
|
|
14
|
+
export class OpenCitationsCitationGraphProvider {
|
|
15
|
+
name = "OpenCitations Citation Graph";
|
|
16
|
+
sourceKind = "opencitations-citation-graph";
|
|
17
|
+
capabilities = ["search"];
|
|
18
|
+
isLocal = false;
|
|
19
|
+
seedDois;
|
|
20
|
+
constructor(seedDois) {
|
|
21
|
+
this.seedDois = seedDois;
|
|
22
|
+
}
|
|
23
|
+
async search(_query, opts) {
|
|
24
|
+
if (this.seedDois.length === 0)
|
|
25
|
+
return [];
|
|
26
|
+
const limit = opts?.limit ?? 20;
|
|
27
|
+
// Fan out across seeds with bounded concurrency
|
|
28
|
+
const allTagged = [];
|
|
29
|
+
const seedDoiSet = new Set(this.seedDois.map((d) => d.toLowerCase()));
|
|
30
|
+
for (let i = 0; i < this.seedDois.length; i += MAX_CONCURRENCY) {
|
|
31
|
+
const batch = this.seedDois.slice(i, i + MAX_CONCURRENCY);
|
|
32
|
+
const requests = [];
|
|
33
|
+
for (const doi of batch) {
|
|
34
|
+
requests.push({
|
|
35
|
+
doi,
|
|
36
|
+
relation: "references",
|
|
37
|
+
promise: getReferences(doi),
|
|
38
|
+
});
|
|
39
|
+
requests.push({
|
|
40
|
+
doi,
|
|
41
|
+
relation: "cited-by",
|
|
42
|
+
promise: getCitations(doi),
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
const results = await Promise.allSettled(requests.map((r) => r.promise));
|
|
46
|
+
for (let j = 0; j < results.length; j++) {
|
|
47
|
+
const result = results[j];
|
|
48
|
+
const req = requests[j];
|
|
49
|
+
if (result.status === "fulfilled" && result.value.ok) {
|
|
50
|
+
const dois = result.value.data;
|
|
51
|
+
for (const doi of dois.slice(0, PER_SEED_LIMIT)) {
|
|
52
|
+
allTagged.push({ doi, seedDoi: req.doi, relation: req.relation });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Deduplicate by DOI, collecting seed origins per paper
|
|
58
|
+
const doiMap = new Map();
|
|
59
|
+
for (const { doi, seedDoi, relation } of allTagged) {
|
|
60
|
+
const key = doi.toLowerCase();
|
|
61
|
+
// Exclude seed papers from results
|
|
62
|
+
if (seedDoiSet.has(key))
|
|
63
|
+
continue;
|
|
64
|
+
const existing = doiMap.get(key);
|
|
65
|
+
if (existing) {
|
|
66
|
+
const originKey = `${seedDoi.toLowerCase()}:${relation}`;
|
|
67
|
+
if (!existing.origins.some((o) => `${o.doi.toLowerCase()}:${o.relation}` === originKey)) {
|
|
68
|
+
existing.origins.push({ doi: seedDoi, relation });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
doiMap.set(key, {
|
|
73
|
+
doi,
|
|
74
|
+
origins: [{ doi: seedDoi, relation }],
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// Limit before expensive hydration
|
|
79
|
+
const entries = [...doiMap.values()].slice(0, limit);
|
|
80
|
+
if (entries.length === 0)
|
|
81
|
+
return [];
|
|
82
|
+
// Hydrate metadata from Crossref
|
|
83
|
+
const doisToHydrate = entries.map((e) => e.doi);
|
|
84
|
+
const hydrated = await batchHydrateByDois(doisToHydrate);
|
|
85
|
+
// Map to candidates
|
|
86
|
+
return entries.map(({ doi, origins }, i) => {
|
|
87
|
+
const work = hydrated.get(doi.toLowerCase());
|
|
88
|
+
return workToCandidate(doi, work, origins, i);
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function workToCandidate(doi, work, origins, position) {
|
|
93
|
+
if (!work) {
|
|
94
|
+
// Minimal candidate when Crossref hydration missed
|
|
95
|
+
return {
|
|
96
|
+
doi,
|
|
97
|
+
title: null,
|
|
98
|
+
authors: null,
|
|
99
|
+
year: null,
|
|
100
|
+
sources: ["opencitations-citation-graph"],
|
|
101
|
+
score: position,
|
|
102
|
+
seedOrigins: origins,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
doi: work.DOI ?? doi,
|
|
107
|
+
title: extractTitle(work),
|
|
108
|
+
authors: formatAuthors(work.author),
|
|
109
|
+
year: extractYear(work),
|
|
110
|
+
sources: ["opencitations-citation-graph"],
|
|
111
|
+
score: position,
|
|
112
|
+
citationCount: work["is-referenced-by-count"] ?? null,
|
|
113
|
+
abstractSnippet: extractAbstract(work),
|
|
114
|
+
venue: extractVenue(work),
|
|
115
|
+
url: work.URL ?? null,
|
|
116
|
+
seedOrigins: origins,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=citation-graph-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"citation-graph-provider.js","sourceRoot":"","sources":["../../../src/sources/opencitations/citation-graph-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed client for the OpenCitations COCI REST API.
|
|
3
|
+
*
|
|
4
|
+
* Free, no API key required, no rate limits documented.
|
|
5
|
+
* Returns citation edges by DOI in both directions.
|
|
6
|
+
*
|
|
7
|
+
* @see https://opencitations.net/index/coci/api/v1
|
|
8
|
+
*/
|
|
9
|
+
import type { AdapterResult } from "../../works/types";
|
|
10
|
+
/** A single citation edge from COCI. */
|
|
11
|
+
export interface CociCitation {
|
|
12
|
+
/** DOI of the citing paper. */
|
|
13
|
+
citing: string;
|
|
14
|
+
/** DOI of the cited paper. */
|
|
15
|
+
cited: string;
|
|
16
|
+
/** Creation date of the citation record (YYYY-MM-DD). */
|
|
17
|
+
creation?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Get papers referenced by a given paper (its bibliography).
|
|
21
|
+
* Returns deduplicated, normalized DOIs of cited papers.
|
|
22
|
+
*/
|
|
23
|
+
export declare function getReferences(doi: string): Promise<AdapterResult<string[]>>;
|
|
24
|
+
/**
|
|
25
|
+
* Get papers that cite a given paper.
|
|
26
|
+
* Returns deduplicated, normalized DOIs of citing papers.
|
|
27
|
+
*/
|
|
28
|
+
export declare function getCitations(doi: string): Promise<AdapterResult<string[]>>;
|
|
29
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/sources/opencitations/client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAYvD,wCAAwC;AACxC,MAAM,WAAW,YAAY;IAC3B,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,yDAAyD;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA2DD;;;GAGG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC,CAmBlC;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC,CAmBlC"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed client for the OpenCitations COCI REST API.
|
|
3
|
+
*
|
|
4
|
+
* Free, no API key required, no rate limits documented.
|
|
5
|
+
* Returns citation edges by DOI in both directions.
|
|
6
|
+
*
|
|
7
|
+
* @see https://opencitations.net/index/coci/api/v1
|
|
8
|
+
*/
|
|
9
|
+
const BASE_URL = "https://opencitations.net/index/coci/api/v1";
|
|
10
|
+
/** Max retries on 5xx before giving up. */
|
|
11
|
+
const MAX_RETRIES = 2;
|
|
12
|
+
/** Request timeout in ms. */
|
|
13
|
+
const REQUEST_TIMEOUT_MS = 15_000;
|
|
14
|
+
// ── Helpers ──────────────────────────────────────────────────────────
|
|
15
|
+
async function fetchWithRetry(url) {
|
|
16
|
+
let lastError;
|
|
17
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
18
|
+
try {
|
|
19
|
+
const res = await fetch(url, {
|
|
20
|
+
headers: { Accept: "application/json" },
|
|
21
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
22
|
+
});
|
|
23
|
+
if (res.status >= 500 && attempt < MAX_RETRIES) {
|
|
24
|
+
await new Promise((r) => setTimeout(r, 1000 * (attempt + 1)));
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
return res;
|
|
28
|
+
}
|
|
29
|
+
catch (e) {
|
|
30
|
+
lastError = e;
|
|
31
|
+
if (attempt < MAX_RETRIES) {
|
|
32
|
+
await new Promise((r) => setTimeout(r, 1000 * (attempt + 1)));
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
throw lastError ?? new Error("fetchWithRetry exhausted");
|
|
38
|
+
}
|
|
39
|
+
/** Normalize a DOI to lowercase, trimmed. */
|
|
40
|
+
function normalizeDoi(doi) {
|
|
41
|
+
return doi.trim().toLowerCase();
|
|
42
|
+
}
|
|
43
|
+
/** Extract DOIs from COCI edges, filtering out empty/invalid values. */
|
|
44
|
+
function extractDois(edges, field) {
|
|
45
|
+
const seen = new Set();
|
|
46
|
+
const result = [];
|
|
47
|
+
for (const edge of edges) {
|
|
48
|
+
const raw = edge[field];
|
|
49
|
+
if (!raw)
|
|
50
|
+
continue;
|
|
51
|
+
const doi = normalizeDoi(raw);
|
|
52
|
+
if (!doi || seen.has(doi))
|
|
53
|
+
continue;
|
|
54
|
+
seen.add(doi);
|
|
55
|
+
result.push(doi);
|
|
56
|
+
}
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
// ── Public API ───────────────────────────────────────────────────────
|
|
60
|
+
/**
|
|
61
|
+
* Get papers referenced by a given paper (its bibliography).
|
|
62
|
+
* Returns deduplicated, normalized DOIs of cited papers.
|
|
63
|
+
*/
|
|
64
|
+
export async function getReferences(doi) {
|
|
65
|
+
const url = `${BASE_URL}/references/${encodeURIComponent(doi)}`;
|
|
66
|
+
try {
|
|
67
|
+
const res = await fetchWithRetry(url);
|
|
68
|
+
if (!res.ok) {
|
|
69
|
+
const status = res.status;
|
|
70
|
+
if (status === 404)
|
|
71
|
+
return { ok: false, status, reason: "not_found" };
|
|
72
|
+
if (status === 429)
|
|
73
|
+
return { ok: false, status, reason: "rate_limited" };
|
|
74
|
+
return { ok: false, status, reason: "upstream_error" };
|
|
75
|
+
}
|
|
76
|
+
const edges = (await res.json());
|
|
77
|
+
// References: papers cited by the query DOI → extract "cited" field
|
|
78
|
+
return { ok: true, data: extractDois(edges, "cited") };
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return { ok: false, reason: "network_error" };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Get papers that cite a given paper.
|
|
86
|
+
* Returns deduplicated, normalized DOIs of citing papers.
|
|
87
|
+
*/
|
|
88
|
+
export async function getCitations(doi) {
|
|
89
|
+
const url = `${BASE_URL}/citations/${encodeURIComponent(doi)}`;
|
|
90
|
+
try {
|
|
91
|
+
const res = await fetchWithRetry(url);
|
|
92
|
+
if (!res.ok) {
|
|
93
|
+
const status = res.status;
|
|
94
|
+
if (status === 404)
|
|
95
|
+
return { ok: false, status, reason: "not_found" };
|
|
96
|
+
if (status === 429)
|
|
97
|
+
return { ok: false, status, reason: "rate_limited" };
|
|
98
|
+
return { ok: false, status, reason: "upstream_error" };
|
|
99
|
+
}
|
|
100
|
+
const edges = (await res.json());
|
|
101
|
+
// Citations: papers that cite the query DOI → extract "citing" field
|
|
102
|
+
return { ok: true, data: extractDois(edges, "citing") };
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return { ok: false, reason: "network_error" };
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/sources/opencitations/client.ts"],"names":[],"mappings":"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"}
|