@cyanheads/openalex-mcp-server 0.8.0 → 0.10.0

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.
Files changed (67) hide show
  1. package/AGENTS.md +25 -7
  2. package/CLAUDE.md +25 -7
  3. package/Dockerfile +17 -8
  4. package/README.md +28 -19
  5. package/changelog/0.10.x/0.10.0.md +30 -0
  6. package/changelog/0.9.x/0.9.0.md +48 -0
  7. package/dist/config/server-config.d.ts +2 -0
  8. package/dist/config/server-config.d.ts.map +1 -1
  9. package/dist/config/server-config.js +10 -0
  10. package/dist/config/server-config.js.map +1 -1
  11. package/dist/index.js +1 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/mcp-server/prompts/definitions/literature-review.prompt.js +1 -1
  14. package/dist/mcp-server/prompts/definitions/research-landscape.prompt.js +1 -1
  15. package/dist/mcp-server/tools/definitions/analyze-trends.tool.d.ts +35 -4
  16. package/dist/mcp-server/tools/definitions/analyze-trends.tool.d.ts.map +1 -1
  17. package/dist/mcp-server/tools/definitions/analyze-trends.tool.js +86 -41
  18. package/dist/mcp-server/tools/definitions/analyze-trends.tool.js.map +1 -1
  19. package/dist/mcp-server/tools/definitions/citation-graph.tool.d.ts +48 -5
  20. package/dist/mcp-server/tools/definitions/citation-graph.tool.d.ts.map +1 -1
  21. package/dist/mcp-server/tools/definitions/citation-graph.tool.js +77 -24
  22. package/dist/mcp-server/tools/definitions/citation-graph.tool.js.map +1 -1
  23. package/dist/mcp-server/tools/definitions/describe-fields.tool.d.ts.map +1 -1
  24. package/dist/mcp-server/tools/definitions/describe-fields.tool.js +34 -4
  25. package/dist/mcp-server/tools/definitions/describe-fields.tool.js.map +1 -1
  26. package/dist/mcp-server/tools/definitions/resolve-name.tool.d.ts +43 -1
  27. package/dist/mcp-server/tools/definitions/resolve-name.tool.d.ts.map +1 -1
  28. package/dist/mcp-server/tools/definitions/resolve-name.tool.js +182 -40
  29. package/dist/mcp-server/tools/definitions/resolve-name.tool.js.map +1 -1
  30. package/dist/mcp-server/tools/definitions/search-entities.tool.d.ts +64 -6
  31. package/dist/mcp-server/tools/definitions/search-entities.tool.d.ts.map +1 -1
  32. package/dist/mcp-server/tools/definitions/search-entities.tool.js +138 -35
  33. package/dist/mcp-server/tools/definitions/search-entities.tool.js.map +1 -1
  34. package/dist/mcp-server/tools/page-size.d.ts +18 -0
  35. package/dist/mcp-server/tools/page-size.d.ts.map +1 -0
  36. package/dist/mcp-server/tools/page-size.js +28 -0
  37. package/dist/mcp-server/tools/page-size.js.map +1 -0
  38. package/dist/mcp-server/tools/render-budget.d.ts +4 -2
  39. package/dist/mcp-server/tools/render-budget.d.ts.map +1 -1
  40. package/dist/mcp-server/tools/render-budget.js +4 -2
  41. package/dist/mcp-server/tools/render-budget.js.map +1 -1
  42. package/dist/mcp-server/tools/response-budget.d.ts +3 -3
  43. package/dist/mcp-server/tools/response-budget.d.ts.map +1 -1
  44. package/dist/mcp-server/tools/response-budget.js +64 -35
  45. package/dist/mcp-server/tools/response-budget.js.map +1 -1
  46. package/dist/services/openalex/budget.d.ts +3 -1
  47. package/dist/services/openalex/budget.d.ts.map +1 -1
  48. package/dist/services/openalex/budget.js +3 -1
  49. package/dist/services/openalex/budget.js.map +1 -1
  50. package/dist/services/openalex/field-catalog.json +50 -1
  51. package/dist/services/openalex/filter-values.d.ts +48 -0
  52. package/dist/services/openalex/filter-values.d.ts.map +1 -0
  53. package/dist/services/openalex/filter-values.js +350 -0
  54. package/dist/services/openalex/filter-values.js.map +1 -0
  55. package/dist/services/openalex/iso-codes.json +1565 -0
  56. package/dist/services/openalex/openalex-service.d.ts +176 -20
  57. package/dist/services/openalex/openalex-service.d.ts.map +1 -1
  58. package/dist/services/openalex/openalex-service.js +573 -127
  59. package/dist/services/openalex/openalex-service.js.map +1 -1
  60. package/dist/services/openalex/provider-text.d.ts +7 -6
  61. package/dist/services/openalex/provider-text.d.ts.map +1 -1
  62. package/dist/services/openalex/provider-text.js +485 -61
  63. package/dist/services/openalex/provider-text.js.map +1 -1
  64. package/dist/services/openalex/types.d.ts +5 -2
  65. package/dist/services/openalex/types.d.ts.map +1 -1
  66. package/package.json +14 -12
  67. package/server.json +35 -21
@@ -4,6 +4,41 @@
4
4
  */
5
5
  import type { Context } from '@cyanheads/mcp-ts-core';
6
6
  import { type AnalyzeParams, type AnalyzeResult, type AutocompleteParams, type AutocompleteRecord, type AutocompleteResult, type EntityRecord, type EntityType, type SearchParams, type SearchResult } from './types.js';
7
+ /** Whether this aggregation keeps count order, ignoring the native unknown-bucket suffix. */
8
+ export declare function isBooleanGroupBy(groupBy: string): boolean;
9
+ /** One upstream filter clause: the canonical key and the value it constrains. */
10
+ type FilterClause = [key: string, value: string];
11
+ /**
12
+ * Build an OpenAlex filter string from ordered key-value clauses.
13
+ * Input: [["cited_by_count", ">100"], ["is_oa", "true"]]
14
+ * Output: "cited_by_count:>100,is_oa:true"
15
+ *
16
+ * Clauses, not a record: OpenAlex ANDs a repeated key (`publication_year:2020,publication_year:2024`
17
+ * matches works in both years, which is nothing), and two caller filters can resolve to one
18
+ * canonical key. A record would hold only the last of them.
19
+ *
20
+ * Comma handling (commas collide with OpenAlex's filter clause separator):
21
+ * - Free-text search keys (`title.search`, `abstract.search.exact`, `semantic.search`, …) and
22
+ * keys matched as whole text (`raw_affiliation_strings`, `display_name`, `geo.city`, …): the
23
+ * value goes out double-quoted as `quotedCommaValue()` writes it, so the comma stays part of the
24
+ * phrase. The quoted value is sent as written, `+` included.
25
+ * - All other keys: throw a pre-flight validation error — OpenAlex OR-lists use `|`, not commas.
26
+ *
27
+ * Every other value goes out as `upstreamFilterValue()` writes it: country and `language` values
28
+ * converted to the codes OpenAlex stores (a country segment that cannot be a code throws
29
+ * `invalid_country_code`), a multi-word value on a key matched as whole text (`geo.city`,
30
+ * `awards.funder_display_name`, …) double-quoted so OpenAlex reads it as one phrase, and the AND
31
+ * operator — a `+`, or a space on a key where words mean AND — sent as the AND it spells. A value
32
+ * that puts that operator beside a `|` throws `mixed_and_or_in_filter_value`, since OpenAlex drops
33
+ * every `|` alternative that ANDs more than one value; a value sent double-quoted that carries a
34
+ * `"` of its own throws `quote_in_filter_value`. A value left unquoted with an unmatched `"`
35
+ * throws `unmatched_quote_in_filter_value`. Every throw runs before any request.
36
+ * `autocomplete()` sends its filters without `translateFilters()`, so the conversion lives here
37
+ * rather than there.
38
+ *
39
+ * Exported for the timing suite, which runs it on caller-sized keys and values.
40
+ */
41
+ export declare function buildFilterString(filters: FilterClause[]): string;
7
42
  /**
8
43
  * Recovery for a PMCID that reached OpenAlex and came back with nothing. OpenAlex indexes no
9
44
  * PMCIDs — `has_pmcid:true` matches zero works and a work's `ids` object never carries the key —
@@ -12,6 +47,11 @@ import { type AnalyzeParams, type AnalyzeResult, type AutocompleteParams, type A
12
47
  * mapping here and the `openalex_resolve_name` miss notice so both say the same thing.
13
48
  */
14
49
  export declare const PMCID_NOT_INDEXED_HINT = "OpenAlex indexes no PMCIDs, so a PMCID resolves nothing however it is written. Convert it to a PMID or DOI \u2014 the NCBI ID Converter (https://www.ncbi.nlm.nih.gov/pmc/tools/idconv/) does this \u2014 and retry with that identifier.";
50
+ /**
51
+ * The filter clause that matches a funder by its bare DOI, or undefined for a value that clause
52
+ * would read as more than one literal DOI — it could only match some other funder, or every one.
53
+ */
54
+ export declare function funderDoiFilter(doi: string): string | undefined;
15
55
  /**
16
56
  * Detect ID format and return the API path segment.
17
57
  * "10.1038/nature12373" → "doi:10.1038/nature12373"
@@ -25,18 +65,51 @@ export declare const PMCID_NOT_INDEXED_HINT = "OpenAlex indexes no PMCIDs, so a
25
65
  * "https://www.ncbi.nlm.nih.gov/pmc/articles/PMC1234567/" → "pmcid:PMC1234567"
26
66
  * "https://pubmed.ncbi.nlm.nih.gov/21491125" → "pmid:21491125"
27
67
  * "PMID:21491125" → "pmid:21491125"
28
- * "https://openalex.org/keywords/groundwater" → "groundwater"
68
+ * "https://openalex.org/works/W2741809807" → "W2741809807"
69
+ * "https://api.openalex.org/keywords/groundwater" → "groundwater"
29
70
  * "W2741809807" → "W2741809807"
30
71
  */
31
72
  export declare function normalizeId(id: string): string;
73
+ /**
74
+ * The by-ID request path for `id`: `/<entityType>/<id>`, with every character a URL parse would
75
+ * read as structure percent-encoded so it stays part of the ID. OpenAlex decodes them back, so a
76
+ * DOI that holds a `#` or `?` reaches the record it names instead of a truncated one.
77
+ *
78
+ * A `.` or `..` segment, plain or percent-encoded, is refused before any request, since encoding
79
+ * cannot keep it inside the path. `/` is left as written, since DOIs carry it, and an encoded
80
+ * `%2F` is one segment to both the parse and OpenAlex. The refusal quotes `callerId`, the
81
+ * identifier as the caller wrote it, rather than the normalized `id` (`doi:…` for a DOI URL).
82
+ */
83
+ export declare function byIdPath(entityType: EntityType, id: string, callerId?: string): string;
32
84
  /** An identifier the deterministic by-ID path can resolve, with the scheme it was read as. */
33
85
  export interface ResolvedIdentifier {
34
- entityType: EntityType;
86
+ /** The entity types to look the identifier up as, in the order their records are returned. */
87
+ entityTypes: readonly EntityType[];
35
88
  /** The value in the form the OpenAlex path segment expects (`doi:10.1038/…`, `W2741809807`). */
36
89
  id: string;
90
+ /**
91
+ * Set on a bare native-ID shape, which short names share — keyword `p53` reads as publisher
92
+ * `P53`, and `F1`, `S1`, and `A1` are keywords too — so a lookup that finds no record is no
93
+ * sign the caller meant an ID, and the query is worth searching as a name next. A URL form
94
+ * names its record outright and never carries it.
95
+ */
96
+ mayBeName?: true;
37
97
  /** Identifier scheme, for caller-facing messages: `doi`, `orcid`, `openalex`, … */
38
98
  scheme: string;
39
99
  }
100
+ /** What `resolveIdentifier()` found. */
101
+ export interface IdentifierResolution extends AutocompleteResult {
102
+ /** Entity types whose lookup failed upstream while another type returned a record. */
103
+ failedEntityTypes?: EntityType[];
104
+ /**
105
+ * Set when every lookup found nothing and the query ran as a name search instead: `results`
106
+ * then hold that search's matches. `failedReason` names the upstream failure that stopped the
107
+ * search, with `results` empty.
108
+ */
109
+ nameFallback?: {
110
+ failedReason?: string;
111
+ };
112
+ }
40
113
  /**
41
114
  * Classify a query as an identifier, or return `undefined` for a name.
42
115
  *
@@ -45,12 +118,17 @@ export interface ResolvedIdentifier {
45
118
  * it produced. Names never survive that: a name with a colon in it yields a prefix that is in no
46
119
  * scheme table, and anything else fails the native-ID pattern.
47
120
  *
48
- * Keywords are the exception, and are read from the raw query instead: their IDs are slugs, so
49
- * `normalizeId()` reduces the URL to a bare word that no longer names an entity type. The URL
50
- * form is the only keyword spelling that identifies itself — a bare slug is indistinguishable
51
- * from any other name, and autocomplete is the right answer for it.
121
+ * Keywords are the exception, and are read from the URL before it is reduced: their IDs are
122
+ * slugs, so `normalizeId()` turns the URL into a bare word that no longer names an entity type.
123
+ * The URL form is the only keyword spelling that identifies itself — a bare slug is
124
+ * indistinguishable from any other name, and autocomplete is the right answer for it.
125
+ *
126
+ * `requested` (the caller's `entity_type`) narrows an identifier only among the types it can
127
+ * address: a ROR to one of institutions, funders, and publishers, and a Funder Registry DOI to
128
+ * works. Any other type leaves the identifier's own types in place — except `keywords`, under
129
+ * which a bare native-ID shape is a name: keyword IDs are slugs, and `P53` is a keyword.
52
130
  */
53
- export declare function inferIdentifier(query: string): ResolvedIdentifier | undefined;
131
+ export declare function inferIdentifier(query: string, requested?: EntityType): ResolvedIdentifier | undefined;
54
132
  /**
55
133
  * Shape a singleton entity record like an autocomplete match, so both resolution paths of
56
134
  * `openalex_resolve_name` return one result type. `entity_type` is singularized to match what
@@ -59,11 +137,27 @@ export declare function inferIdentifier(query: string): ResolvedIdentifier | und
59
137
  */
60
138
  export declare function toAutocompleteRecord(entityType: EntityType, record: EntityRecord): AutocompleteRecord;
61
139
  /**
62
- * The upstream field one caller-supplied `select` name projects to — `authors` → `authorships`
63
- * on works, `h_index` → `summary_stats` where that object exists; any other name unchanged.
64
- * Exported so a tool can find the record key a one-field projection lands under.
140
+ * The works `select` field the server derives rather than projects: each authorship's author as
141
+ * `{id, display_name, orcid}`, from the `authorships` it requests in its place. Not an upstream
142
+ * field, so it is never forwarded, and neither the default projection nor `*` includes it.
65
143
  */
66
- export declare function translateSelectField(entityType: SearchParams['entityType'], field: string): string;
144
+ export declare const AUTHOR_LIST_FIELD = "author_list";
145
+ /**
146
+ * The record key one caller-supplied `select` name lands under: `author_list` keeps its own
147
+ * name; any other name lands under the upstream field it projects (`authors` → `authorships`).
148
+ * Exported so a tool can find the array a one-field projection returns.
149
+ */
150
+ export declare function selectRecordKey(entityType: SearchParams['entityType'], field: string): string;
151
+ /**
152
+ * Detect a value the `id:` filter would carry — OpenAlex IDs, bare or in any URL spelling
153
+ * `parseOpenAlexUrl()` reads, optionally pipe-joined for OR semantics. When matched, `id` is
154
+ * rewritten to `openalex` (the canonical filter key) and the value is forwarded as written:
155
+ * upstream accepts every one of those spellings, and the space around a `|`. Stricter than any
156
+ * value so a future generic upstream `id:` filter wouldn't be shadowed — only values that read
157
+ * as OpenAlex IDs get redirected. Exported for the timing suite, which runs it on caller-sized
158
+ * values.
159
+ */
160
+ export declare function isOpenAlexFilterValue(value: string): boolean;
67
161
  /**
68
162
  * Rewrite one caller-supplied filter key to the upstream OpenAlex name, before the
69
163
  * value-dependent `id` rewrite. Exported so the citation-graph tool can check a caller's key
@@ -74,6 +168,21 @@ export declare function translateSelectField(entityType: SearchParams['entityTyp
74
168
  * typos no map can preempt.
75
169
  */
76
170
  export declare function translateFilterKey(entityType: SearchParams['entityType'], key: string): string;
171
+ /**
172
+ * The `filter` parameter a search or group_by over `filters` sends: keys translated, then each
173
+ * clause built by `buildFilterString()`, whose pre-flight throws (`comma_in_filter_value`,
174
+ * `invalid_country_code`, `mixed_and_or_in_filter_value`, `quote_in_filter_value`,
175
+ * `unmatched_quote_in_filter_value`) it shares.
176
+ * Exported so a tool that spends a request before its search — the citation graph's seed lookup —
177
+ * can run those checks first and fail without one.
178
+ */
179
+ export declare function buildSearchFilter(entityType: SearchParams['entityType'], filters: Record<string, string>): string;
180
+ /**
181
+ * Recovery for every `upstream_unavailable` failure of a semantic search — a relabelled embedding
182
+ * failure, the 503 OpenAlex sends when the embedding timed out, or any other outage — since a
183
+ * keyword search does not depend on the embedding service and can answer while it is down.
184
+ */
185
+ export declare const SEMANTIC_UNAVAILABLE_HINT = "OpenAlex semantic search is failing upstream. Retry in a minute, or rerun with search_mode \"keyword\", which does not depend on it.";
77
186
  /**
78
187
  * Recovery for a spent daily budget on a server that sends no API key. It runs on the smaller
79
188
  * anonymous budget, so a key is the one fix besides waiting. A keyed server's budget is already
@@ -81,21 +190,40 @@ export declare function translateFilterKey(entityType: SearchParams['entityType'
81
190
  * case keeps the key-neutral recovery each tool's contract declares.
82
191
  */
83
192
  export declare const BUDGET_EXHAUSTED_KEYLESS_HINT = "This server's daily OpenAlex budget is spent and refills at midnight UTC \u2014 retrying before then will not succeed. The server sends no OpenAlex API key, so it runs on the smaller anonymous budget; setting OPENALEX_API_KEY to a free key (https://openalex.org/settings/api) raises it.";
193
+ /**
194
+ * The server's own message for a plan-gated filter, naming the filter when the upstream message
195
+ * opens with it. The name is read as a field-name run only, so caller text the upstream clause
196
+ * echoes cannot carry markdown or a line break into the message.
197
+ */
198
+ export declare function planGatedFilterMessage(upstreamMessage: string | undefined): string;
84
199
  declare class OpenAlexService {
85
200
  private readonly baseUrl;
86
201
  private readonly apiKey;
87
202
  private readonly mailto;
88
203
  constructor();
89
- /** Execute an HTTP request against the OpenAlex API with retry on transient failures. */
204
+ /**
205
+ * Execute an HTTP request against the OpenAlex API with retry on transient failures. With
206
+ * `deadlineMs`, every attempt and backoff settles within that many milliseconds, after which
207
+ * the request fails as a `Timeout`.
208
+ */
90
209
  private request;
91
210
  private throwNormalizedRequestError;
92
211
  private parseResponse;
93
212
  /** Search/filter/sort entities, or retrieve a single entity by ID. */
94
213
  search(params: SearchParams, ctx: Context): Promise<SearchResult>;
214
+ /**
215
+ * Look a funder up by its Crossref Funder Registry DOI. OpenAlex's `/funders/doi:` path
216
+ * resolves nothing, so this is a one-result list request on the `ids.doi` filter, which OpenAlex
217
+ * bills like any list request. A value the filter would read as more than one literal DOI fails
218
+ * as not found without a request (see `funderDoiFilter`).
219
+ */
220
+ private funderByDoi;
95
221
  /** Group-by aggregation. */
96
222
  analyze(params: AnalyzeParams, ctx: Context): Promise<AnalyzeResult>;
97
223
  /**
98
- * Resolve an identifier to the single entity it addresses, shaped as an autocomplete match.
224
+ * Resolve an identifier to the entities it addresses, shaped as autocomplete matches — one
225
+ * lookup per entity type in `identifier.entityTypes`, run in parallel, with the records found
226
+ * returned in that order.
99
227
  *
100
228
  * Autocomplete matches on `display_name` and the external-ID URL, so whether an identifier
101
229
  * resolves through it depends on scheme, bare-vs-URL form, and entity type — a bare ORCID or
@@ -106,22 +234,50 @@ declare class OpenAlexService {
106
234
  * A miss returns no results rather than throwing. Autocomplete answers an unmatched query with
107
235
  * an empty list, and routing identifiers through here is meant to make them behave *more* like
108
236
  * the front door, not to hand one class of query a hard failure the rest never sees.
237
+ *
238
+ * A lookup that fails for any other reason drops only its own type, named in
239
+ * `failedEntityTypes`, while another type returned a record. With no record to return, or once
240
+ * the caller has cancelled, the failure is thrown instead — an empty or partial answer there
241
+ * would claim records do not exist when the lookup for them never finished.
242
+ *
243
+ * `nameSearch` is the autocomplete to run when every lookup finds nothing — for a query that
244
+ * may be a name rather than an ID (`ResolvedIdentifier.mayBeName`). It runs only on that miss,
245
+ * so an ID that resolves still costs its one request, and only within what is left of
246
+ * `NAME_FALLBACK_DEADLINE_MS` from the start of this call (see `nameSearchAfterMiss`).
247
+ *
248
+ * `query` is the text `identifier` was read from, as the caller wrote it. The lookups are sent
249
+ * that spelling, which `search()` normalizes back to `identifier.id`, so a lookup that refuses
250
+ * the identifier quotes what the caller sent.
251
+ */
252
+ resolveIdentifier(identifier: ResolvedIdentifier, ctx: Context, nameSearch?: AutocompleteParams, query?: string): Promise<IdentifierResolution>;
253
+ /**
254
+ * The name search an identifier lookup falls back to after finding nothing, bounded by the
255
+ * `remainingMs` the lookup left of the call's deadline. It is a best-effort second reading of
256
+ * the query, so a transient upstream failure — a timeout, the deadline running out, an outage,
257
+ * a burst throttle — comes back as `nameFallback.failedReason` for the caller to see, beside
258
+ * the lookup's own true miss. A caller cancellation, a request upstream rejected, a spent
259
+ * budget, and anything unclassified are thrown: none of them is cured by calling again, and an
260
+ * answer in their place would hide the error the caller needs to act on.
109
261
  */
110
- resolveIdentifier(identifier: ResolvedIdentifier, ctx: Context): Promise<AutocompleteResult>;
111
- /** Autocomplete name resolution. */
112
- autocomplete(params: AutocompleteParams, ctx: Context): Promise<AutocompleteResult>;
262
+ private nameSearchAfterMiss;
263
+ /**
264
+ * Autocomplete name resolution. `deadlineMs` bounds the whole request, retries included (see
265
+ * `request`).
266
+ */
267
+ autocomplete(params: AutocompleteParams, ctx: Context, deadlineMs?: number): Promise<AutocompleteResult>;
113
268
  }
114
269
  export declare function initOpenAlexService(): void;
115
270
  export declare function getOpenAlexService(): OpenAlexService;
271
+ type FieldCatalog = Record<EntityType, {
272
+ filter: string[];
273
+ select: string[];
274
+ }>;
116
275
  /**
117
276
  * Return the typed field catalog keyed by entity type → context → field list.
118
277
  * Only `filter` and `select` arrays are stored. `group_by` resolves to the `filter` key here;
119
278
  * the describe-fields handler then prunes the fields group_by cannot target (raw dates,
120
279
  * `*.search` operators, `from_*`/`to_*` range modifiers, and a per-type set from a live sweep).
121
280
  */
122
- export declare function getFieldCatalog(): Record<EntityType, {
123
- filter: string[];
124
- select: string[];
125
- }>;
281
+ export declare function getFieldCatalog(): FieldCatalog;
126
282
  export {};
127
283
  //# sourceMappingURL=openalex-service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"openalex-service.d.ts","sourceRoot":"","sources":["../../../src/services/openalex/openalex-service.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAuBtD,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EAGvB,KAAK,YAAY,EACjB,KAAK,UAAU,EAEf,KAAK,YAAY,EACjB,KAAK,YAAY,EAClB,MAAM,YAAY,CAAC;AAoFpB;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,8OACgM,CAAC;AA0BpO;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAuF9C;AAuBD,8FAA8F;AAC9F,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,UAAU,CAAC;IACvB,gGAAgG;IAChG,EAAE,EAAE,MAAM,CAAC;IACX,mFAAmF;IACnF,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS,CAkB7E;AA4HD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,YAAY,GACnB,kBAAkB,CAUpB;AA2ED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,YAAY,CAAC,YAAY,CAAC,EACtC,KAAK,EAAE,MAAM,GACZ,MAAM,CAQR;AA+CD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,YAAY,CAAC,YAAY,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAE9F;AAqSD;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,mSACmP,CAAC;AAsJ9R,cAAM,eAAe;IACnB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAEhC,cAKC;IAED,yFAAyF;IACzF,OAAO,CAAC,OAAO;IAgDf,OAAO,CAAC,2BAA2B;IAgGnC,OAAO,CAAC,aAAa;IAqCrB,sEAAsE;IAChE,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC,CA6FtE;IAED,4BAA4B;IACtB,OAAO,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC,CA2DzE;IAED;;;;;;;;;;;;OAYG;IACG,iBAAiB,CACrB,UAAU,EAAE,kBAAkB,EAC9B,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,kBAAkB,CAAC,CAkB7B;IAED,oCAAoC;IAC9B,YAAY,CAAC,MAAM,EAAE,kBAAkB,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAsBxF;CACF;AAID,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED,wBAAgB,kBAAkB,IAAI,eAAe,CAIpD;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAAC,UAAU,EAAE;IAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAE5F"}
1
+ {"version":3,"file":"openalex-service.d.ts","sourceRoot":"","sources":["../../../src/services/openalex/openalex-service.ts"],"names":[],"mappings":"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"}