@digital-science-dsl/dimensions-analytics-mcp 0.5.3

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 (722) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/README.md +152 -0
  3. package/bin/dimensions-analytics-mcp-http.js +2 -0
  4. package/bin/dimensions-analytics-mcp.js +2 -0
  5. package/dist/client/auth/config-loaders.d.ts +22 -0
  6. package/dist/client/auth/config-loaders.d.ts.map +1 -0
  7. package/dist/client/auth/config-loaders.js +68 -0
  8. package/dist/client/auth/config-loaders.js.map +1 -0
  9. package/dist/client/auth/decorators/index.d.ts +7 -0
  10. package/dist/client/auth/decorators/index.d.ts.map +1 -0
  11. package/dist/client/auth/decorators/index.js +6 -0
  12. package/dist/client/auth/decorators/index.js.map +1 -0
  13. package/dist/client/auth/decorators/with-caching.d.ts +81 -0
  14. package/dist/client/auth/decorators/with-caching.d.ts.map +1 -0
  15. package/dist/client/auth/decorators/with-caching.js +168 -0
  16. package/dist/client/auth/decorators/with-caching.js.map +1 -0
  17. package/dist/client/auth/factory.d.ts +13 -0
  18. package/dist/client/auth/factory.d.ts.map +1 -0
  19. package/dist/client/auth/factory.js +29 -0
  20. package/dist/client/auth/factory.js.map +1 -0
  21. package/dist/client/auth/index.d.ts +7 -0
  22. package/dist/client/auth/index.d.ts.map +1 -0
  23. package/dist/client/auth/index.js +6 -0
  24. package/dist/client/auth/index.js.map +1 -0
  25. package/dist/client/auth/jwt-utils.d.ts +17 -0
  26. package/dist/client/auth/jwt-utils.d.ts.map +1 -0
  27. package/dist/client/auth/jwt-utils.js +33 -0
  28. package/dist/client/auth/jwt-utils.js.map +1 -0
  29. package/dist/client/auth/node.d.ts +16 -0
  30. package/dist/client/auth/node.d.ts.map +1 -0
  31. package/dist/client/auth/node.js +15 -0
  32. package/dist/client/auth/node.js.map +1 -0
  33. package/dist/client/auth/providers/index.d.ts +2 -0
  34. package/dist/client/auth/providers/index.d.ts.map +1 -0
  35. package/dist/client/auth/providers/index.js +2 -0
  36. package/dist/client/auth/providers/index.js.map +1 -0
  37. package/dist/client/auth/providers/jwt-auth-provider.d.ts +70 -0
  38. package/dist/client/auth/providers/jwt-auth-provider.d.ts.map +1 -0
  39. package/dist/client/auth/providers/jwt-auth-provider.js +134 -0
  40. package/dist/client/auth/providers/jwt-auth-provider.js.map +1 -0
  41. package/dist/client/auth/schemas.d.ts +19 -0
  42. package/dist/client/auth/schemas.d.ts.map +1 -0
  43. package/dist/client/auth/schemas.js +23 -0
  44. package/dist/client/auth/schemas.js.map +1 -0
  45. package/dist/client/auth/types.d.ts +25 -0
  46. package/dist/client/auth/types.d.ts.map +1 -0
  47. package/dist/client/auth/types.js +9 -0
  48. package/dist/client/auth/types.js.map +1 -0
  49. package/dist/client/command.d.ts +44 -0
  50. package/dist/client/command.d.ts.map +1 -0
  51. package/dist/client/command.js +23 -0
  52. package/dist/client/command.js.map +1 -0
  53. package/dist/client/config/index.d.ts +11 -0
  54. package/dist/client/config/index.d.ts.map +1 -0
  55. package/dist/client/config/index.js +8 -0
  56. package/dist/client/config/index.js.map +1 -0
  57. package/dist/client/config/loader.d.ts +27 -0
  58. package/dist/client/config/loader.d.ts.map +1 -0
  59. package/dist/client/config/loader.js +128 -0
  60. package/dist/client/config/loader.js.map +1 -0
  61. package/dist/client/config/node.d.ts +18 -0
  62. package/dist/client/config/node.d.ts.map +1 -0
  63. package/dist/client/config/node.js +17 -0
  64. package/dist/client/config/node.js.map +1 -0
  65. package/dist/client/config/schemas.d.ts +23 -0
  66. package/dist/client/config/schemas.d.ts.map +1 -0
  67. package/dist/client/config/schemas.js +24 -0
  68. package/dist/client/config/schemas.js.map +1 -0
  69. package/dist/client/config/types.d.ts +37 -0
  70. package/dist/client/config/types.d.ts.map +1 -0
  71. package/dist/client/config/types.js +6 -0
  72. package/dist/client/config/types.js.map +1 -0
  73. package/dist/client/config/unified-loader.d.ts +41 -0
  74. package/dist/client/config/unified-loader.d.ts.map +1 -0
  75. package/dist/client/config/unified-loader.js +86 -0
  76. package/dist/client/config/unified-loader.js.map +1 -0
  77. package/dist/client/config.d.ts +43 -0
  78. package/dist/client/config.d.ts.map +1 -0
  79. package/dist/client/config.js +56 -0
  80. package/dist/client/config.js.map +1 -0
  81. package/dist/client/deployment-config.d.ts +36 -0
  82. package/dist/client/deployment-config.d.ts.map +1 -0
  83. package/dist/client/deployment-config.js +79 -0
  84. package/dist/client/deployment-config.js.map +1 -0
  85. package/dist/client/errors.d.ts +180 -0
  86. package/dist/client/errors.d.ts.map +1 -0
  87. package/dist/client/errors.js +253 -0
  88. package/dist/client/errors.js.map +1 -0
  89. package/dist/client/http-client.d.ts +215 -0
  90. package/dist/client/http-client.d.ts.map +1 -0
  91. package/dist/client/http-client.js +419 -0
  92. package/dist/client/http-client.js.map +1 -0
  93. package/dist/client/index.d.ts +28 -0
  94. package/dist/client/index.d.ts.map +1 -0
  95. package/dist/client/index.js +18 -0
  96. package/dist/client/index.js.map +1 -0
  97. package/dist/client/internal-dsl-client.d.ts +30 -0
  98. package/dist/client/internal-dsl-client.d.ts.map +1 -0
  99. package/dist/client/internal-dsl-client.js +101 -0
  100. package/dist/client/internal-dsl-client.js.map +1 -0
  101. package/dist/client/rate-limiter.d.ts +79 -0
  102. package/dist/client/rate-limiter.d.ts.map +1 -0
  103. package/dist/client/rate-limiter.js +118 -0
  104. package/dist/client/rate-limiter.js.map +1 -0
  105. package/dist/client/resolve-api-key-user.d.ts +24 -0
  106. package/dist/client/resolve-api-key-user.d.ts.map +1 -0
  107. package/dist/client/resolve-api-key-user.js +80 -0
  108. package/dist/client/resolve-api-key-user.js.map +1 -0
  109. package/dist/client/types.d.ts +44 -0
  110. package/dist/client/types.d.ts.map +1 -0
  111. package/dist/client/types.js +10 -0
  112. package/dist/client/types.js.map +1 -0
  113. package/dist/dsl/client.d.ts +330 -0
  114. package/dist/dsl/client.d.ts.map +1 -0
  115. package/dist/dsl/client.js +433 -0
  116. package/dist/dsl/client.js.map +1 -0
  117. package/dist/dsl/commands/apply-filters.d.ts +15 -0
  118. package/dist/dsl/commands/apply-filters.d.ts.map +1 -0
  119. package/dist/dsl/commands/apply-filters.js +29 -0
  120. package/dist/dsl/commands/apply-filters.js.map +1 -0
  121. package/dist/dsl/commands/facet/index.d.ts +6 -0
  122. package/dist/dsl/commands/facet/index.d.ts.map +1 -0
  123. package/dist/dsl/commands/facet/index.js +6 -0
  124. package/dist/dsl/commands/facet/index.js.map +1 -0
  125. package/dist/dsl/commands/facet/schemas.d.ts +71 -0
  126. package/dist/dsl/commands/facet/schemas.d.ts.map +1 -0
  127. package/dist/dsl/commands/facet/schemas.js +84 -0
  128. package/dist/dsl/commands/facet/schemas.js.map +1 -0
  129. package/dist/dsl/commands/functions/ClassifyCommand.d.ts +96 -0
  130. package/dist/dsl/commands/functions/ClassifyCommand.d.ts.map +1 -0
  131. package/dist/dsl/commands/functions/ClassifyCommand.js +95 -0
  132. package/dist/dsl/commands/functions/ClassifyCommand.js.map +1 -0
  133. package/dist/dsl/commands/functions/ExtractAffiliationsCommand.d.ts +86 -0
  134. package/dist/dsl/commands/functions/ExtractAffiliationsCommand.d.ts.map +1 -0
  135. package/dist/dsl/commands/functions/ExtractAffiliationsCommand.js +131 -0
  136. package/dist/dsl/commands/functions/ExtractAffiliationsCommand.js.map +1 -0
  137. package/dist/dsl/commands/functions/ExtractConceptsCommand.d.ts +73 -0
  138. package/dist/dsl/commands/functions/ExtractConceptsCommand.d.ts.map +1 -0
  139. package/dist/dsl/commands/functions/ExtractConceptsCommand.js +110 -0
  140. package/dist/dsl/commands/functions/ExtractConceptsCommand.js.map +1 -0
  141. package/dist/dsl/commands/functions/ExtractGrantsCommand.d.ts +66 -0
  142. package/dist/dsl/commands/functions/ExtractGrantsCommand.d.ts.map +1 -0
  143. package/dist/dsl/commands/functions/ExtractGrantsCommand.js +87 -0
  144. package/dist/dsl/commands/functions/ExtractGrantsCommand.js.map +1 -0
  145. package/dist/dsl/commands/functions/index.d.ts +10 -0
  146. package/dist/dsl/commands/functions/index.d.ts.map +1 -0
  147. package/dist/dsl/commands/functions/index.js +10 -0
  148. package/dist/dsl/commands/functions/index.js.map +1 -0
  149. package/dist/dsl/commands/index.d.ts +8 -0
  150. package/dist/dsl/commands/index.d.ts.map +1 -0
  151. package/dist/dsl/commands/index.js +7 -0
  152. package/dist/dsl/commands/index.js.map +1 -0
  153. package/dist/dsl/commands/validate-input.d.ts +18 -0
  154. package/dist/dsl/commands/validate-input.d.ts.map +1 -0
  155. package/dist/dsl/commands/validate-input.js +27 -0
  156. package/dist/dsl/commands/validate-input.js.map +1 -0
  157. package/dist/dsl/create-client.d.ts +32 -0
  158. package/dist/dsl/create-client.d.ts.map +1 -0
  159. package/dist/dsl/create-client.js +58 -0
  160. package/dist/dsl/create-client.js.map +1 -0
  161. package/dist/dsl/fluent-query-builder.d.ts +439 -0
  162. package/dist/dsl/fluent-query-builder.d.ts.map +1 -0
  163. package/dist/dsl/fluent-query-builder.js +534 -0
  164. package/dist/dsl/fluent-query-builder.js.map +1 -0
  165. package/dist/dsl/index.d.ts +32 -0
  166. package/dist/dsl/index.d.ts.map +1 -0
  167. package/dist/dsl/index.js +31 -0
  168. package/dist/dsl/index.js.map +1 -0
  169. package/dist/dsl/pagination.d.ts +82 -0
  170. package/dist/dsl/pagination.d.ts.map +1 -0
  171. package/dist/dsl/pagination.js +135 -0
  172. package/dist/dsl/pagination.js.map +1 -0
  173. package/dist/dsl/query-builder.d.ts +456 -0
  174. package/dist/dsl/query-builder.d.ts.map +1 -0
  175. package/dist/dsl/query-builder.js +994 -0
  176. package/dist/dsl/query-builder.js.map +1 -0
  177. package/dist/dsl/response-parser.d.ts +111 -0
  178. package/dist/dsl/response-parser.d.ts.map +1 -0
  179. package/dist/dsl/response-parser.js +210 -0
  180. package/dist/dsl/response-parser.js.map +1 -0
  181. package/dist/dsl/schema/cache.d.ts +52 -0
  182. package/dist/dsl/schema/cache.d.ts.map +1 -0
  183. package/dist/dsl/schema/cache.js +97 -0
  184. package/dist/dsl/schema/cache.js.map +1 -0
  185. package/dist/dsl/schema/extract.d.ts +18 -0
  186. package/dist/dsl/schema/extract.d.ts.map +1 -0
  187. package/dist/dsl/schema/extract.js +41 -0
  188. package/dist/dsl/schema/extract.js.map +1 -0
  189. package/dist/dsl/schema/index.d.ts +13 -0
  190. package/dist/dsl/schema/index.d.ts.map +1 -0
  191. package/dist/dsl/schema/index.js +12 -0
  192. package/dist/dsl/schema/index.js.map +1 -0
  193. package/dist/dsl/schema/load.d.ts +41 -0
  194. package/dist/dsl/schema/load.d.ts.map +1 -0
  195. package/dist/dsl/schema/load.js +119 -0
  196. package/dist/dsl/schema/load.js.map +1 -0
  197. package/dist/dsl/schema/store.d.ts +137 -0
  198. package/dist/dsl/schema/store.d.ts.map +1 -0
  199. package/dist/dsl/schema/store.js +204 -0
  200. package/dist/dsl/schema/store.js.map +1 -0
  201. package/dist/dsl/schema/structured-entities.d.ts +21 -0
  202. package/dist/dsl/schema/structured-entities.d.ts.map +1 -0
  203. package/dist/dsl/schema/structured-entities.js +39 -0
  204. package/dist/dsl/schema/structured-entities.js.map +1 -0
  205. package/dist/dsl/schema/summary.d.ts +51 -0
  206. package/dist/dsl/schema/summary.d.ts.map +1 -0
  207. package/dist/dsl/schema/summary.js +61 -0
  208. package/dist/dsl/schema/summary.js.map +1 -0
  209. package/dist/dsl/schema/types.d.ts +36 -0
  210. package/dist/dsl/schema/types.d.ts.map +1 -0
  211. package/dist/dsl/schema/types.js +6 -0
  212. package/dist/dsl/schema/types.js.map +1 -0
  213. package/dist/dsl/schema/validation.d.ts +21 -0
  214. package/dist/dsl/schema/validation.d.ts.map +1 -0
  215. package/dist/dsl/schema/validation.js +44 -0
  216. package/dist/dsl/schema/validation.js.map +1 -0
  217. package/dist/dsl/types/buckets.d.ts +18 -0
  218. package/dist/dsl/types/buckets.d.ts.map +1 -0
  219. package/dist/dsl/types/buckets.js +6 -0
  220. package/dist/dsl/types/buckets.js.map +1 -0
  221. package/dist/dsl/types/common.d.ts +91 -0
  222. package/dist/dsl/types/common.d.ts.map +1 -0
  223. package/dist/dsl/types/common.js +6 -0
  224. package/dist/dsl/types/common.js.map +1 -0
  225. package/dist/dsl/types/entities.d.ts +35 -0
  226. package/dist/dsl/types/entities.d.ts.map +1 -0
  227. package/dist/dsl/types/entities.js +11 -0
  228. package/dist/dsl/types/entities.js.map +1 -0
  229. package/dist/dsl/types/index.d.ts +12 -0
  230. package/dist/dsl/types/index.d.ts.map +1 -0
  231. package/dist/dsl/types/index.js +7 -0
  232. package/dist/dsl/types/index.js.map +1 -0
  233. package/dist/dsl/types/return-clauses.d.ts +107 -0
  234. package/dist/dsl/types/return-clauses.d.ts.map +1 -0
  235. package/dist/dsl/types/return-clauses.js +22 -0
  236. package/dist/dsl/types/return-clauses.js.map +1 -0
  237. package/dist/dsl/types/special-functions.d.ts +175 -0
  238. package/dist/dsl/types/special-functions.d.ts.map +1 -0
  239. package/dist/dsl/types/special-functions.js +25 -0
  240. package/dist/dsl/types/special-functions.js.map +1 -0
  241. package/dist/dsl/types/vocabulary.d.ts +21 -0
  242. package/dist/dsl/types/vocabulary.d.ts.map +1 -0
  243. package/dist/dsl/types/vocabulary.js +44 -0
  244. package/dist/dsl/types/vocabulary.js.map +1 -0
  245. package/dist/dsl/usage-policy.d.ts +87 -0
  246. package/dist/dsl/usage-policy.d.ts.map +1 -0
  247. package/dist/dsl/usage-policy.js +133 -0
  248. package/dist/dsl/usage-policy.js.map +1 -0
  249. package/dist/dsl/utils/escape.d.ts +24 -0
  250. package/dist/dsl/utils/escape.d.ts.map +1 -0
  251. package/dist/dsl/utils/escape.js +124 -0
  252. package/dist/dsl/utils/escape.js.map +1 -0
  253. package/dist/dsl/utils/sanitize.d.ts +13 -0
  254. package/dist/dsl/utils/sanitize.d.ts.map +1 -0
  255. package/dist/dsl/utils/sanitize.js +19 -0
  256. package/dist/dsl/utils/sanitize.js.map +1 -0
  257. package/dist/dsl/utils/string-utils.d.ts +35 -0
  258. package/dist/dsl/utils/string-utils.d.ts.map +1 -0
  259. package/dist/dsl/utils/string-utils.js +145 -0
  260. package/dist/dsl/utils/string-utils.js.map +1 -0
  261. package/dist/dsl/utils/validate-field-name.d.ts +11 -0
  262. package/dist/dsl/utils/validate-field-name.d.ts.map +1 -0
  263. package/dist/dsl/utils/validate-field-name.js +18 -0
  264. package/dist/dsl/utils/validate-field-name.js.map +1 -0
  265. package/dist/examples/dsl-examples.d.ts +11 -0
  266. package/dist/examples/dsl-examples.d.ts.map +1 -0
  267. package/dist/examples/dsl-examples.js +49 -0
  268. package/dist/examples/dsl-examples.js.map +1 -0
  269. package/dist/examples/usage-scenarios.d.ts +22 -0
  270. package/dist/examples/usage-scenarios.d.ts.map +1 -0
  271. package/dist/examples/usage-scenarios.js +173 -0
  272. package/dist/examples/usage-scenarios.js.map +1 -0
  273. package/dist/funder-org-names.d.ts +12 -0
  274. package/dist/funder-org-names.d.ts.map +1 -0
  275. package/dist/funder-org-names.js +30 -0
  276. package/dist/funder-org-names.js.map +1 -0
  277. package/dist/http-main.d.ts +7 -0
  278. package/dist/http-main.d.ts.map +1 -0
  279. package/dist/http-main.js +36 -0
  280. package/dist/http-main.js.map +1 -0
  281. package/dist/http.d.ts +29 -0
  282. package/dist/http.d.ts.map +1 -0
  283. package/dist/http.js +173 -0
  284. package/dist/http.js.map +1 -0
  285. package/dist/index.d.ts +9 -0
  286. package/dist/index.d.ts.map +1 -0
  287. package/dist/index.js +7 -0
  288. package/dist/index.js.map +1 -0
  289. package/dist/kwq/build-query.d.ts +26 -0
  290. package/dist/kwq/build-query.d.ts.map +1 -0
  291. package/dist/kwq/build-query.js +37 -0
  292. package/dist/kwq/build-query.js.map +1 -0
  293. package/dist/kwq/concept-groups.d.ts +49 -0
  294. package/dist/kwq/concept-groups.d.ts.map +1 -0
  295. package/dist/kwq/concept-groups.js +55 -0
  296. package/dist/kwq/concept-groups.js.map +1 -0
  297. package/dist/kwq/dsl-assembler.d.ts +28 -0
  298. package/dist/kwq/dsl-assembler.d.ts.map +1 -0
  299. package/dist/kwq/dsl-assembler.js +124 -0
  300. package/dist/kwq/dsl-assembler.js.map +1 -0
  301. package/dist/kwq/ensemble.d.ts +38 -0
  302. package/dist/kwq/ensemble.d.ts.map +1 -0
  303. package/dist/kwq/ensemble.js +107 -0
  304. package/dist/kwq/ensemble.js.map +1 -0
  305. package/dist/kwq/index.d.ts +16 -0
  306. package/dist/kwq/index.d.ts.map +1 -0
  307. package/dist/kwq/index.js +14 -0
  308. package/dist/kwq/index.js.map +1 -0
  309. package/dist/kwq/types.d.ts +120 -0
  310. package/dist/kwq/types.d.ts.map +1 -0
  311. package/dist/kwq/types.js +11 -0
  312. package/dist/kwq/types.js.map +1 -0
  313. package/dist/lambda.d.ts +10 -0
  314. package/dist/lambda.d.ts.map +1 -0
  315. package/dist/lambda.js +4 -0
  316. package/dist/lambda.js.map +1 -0
  317. package/dist/main.d.ts +8 -0
  318. package/dist/main.d.ts.map +1 -0
  319. package/dist/main.js +33 -0
  320. package/dist/main.js.map +1 -0
  321. package/dist/mcp/batch-fetch.d.ts +89 -0
  322. package/dist/mcp/batch-fetch.d.ts.map +1 -0
  323. package/dist/mcp/batch-fetch.js +178 -0
  324. package/dist/mcp/batch-fetch.js.map +1 -0
  325. package/dist/mcp/examples/dsl-examples.d.ts +21 -0
  326. package/dist/mcp/examples/dsl-examples.d.ts.map +1 -0
  327. package/dist/mcp/examples/dsl-examples.js +61 -0
  328. package/dist/mcp/examples/dsl-examples.js.map +1 -0
  329. package/dist/mcp/examples/usage-scenarios.d.ts +20 -0
  330. package/dist/mcp/examples/usage-scenarios.d.ts.map +1 -0
  331. package/dist/mcp/examples/usage-scenarios.js +169 -0
  332. package/dist/mcp/examples/usage-scenarios.js.map +1 -0
  333. package/dist/mcp/export-format.d.ts +43 -0
  334. package/dist/mcp/export-format.d.ts.map +1 -0
  335. package/dist/mcp/export-format.js +92 -0
  336. package/dist/mcp/export-format.js.map +1 -0
  337. package/dist/mcp/funder-org-names.d.ts +12 -0
  338. package/dist/mcp/funder-org-names.d.ts.map +1 -0
  339. package/dist/mcp/funder-org-names.js +30 -0
  340. package/dist/mcp/funder-org-names.js.map +1 -0
  341. package/dist/mcp/http-server.d.ts +20 -0
  342. package/dist/mcp/http-server.d.ts.map +1 -0
  343. package/dist/mcp/http-server.js +118 -0
  344. package/dist/mcp/http-server.js.map +1 -0
  345. package/dist/mcp/middleware/field-aliases.d.ts +97 -0
  346. package/dist/mcp/middleware/field-aliases.d.ts.map +1 -0
  347. package/dist/mcp/middleware/field-aliases.js +208 -0
  348. package/dist/mcp/middleware/field-aliases.js.map +1 -0
  349. package/dist/mcp/resources/schema.d.ts +13 -0
  350. package/dist/mcp/resources/schema.d.ts.map +1 -0
  351. package/dist/mcp/resources/schema.js +262 -0
  352. package/dist/mcp/resources/schema.js.map +1 -0
  353. package/dist/mcp/schema/context.d.ts +10 -0
  354. package/dist/mcp/schema/context.d.ts.map +1 -0
  355. package/dist/mcp/schema/context.js +6 -0
  356. package/dist/mcp/schema/context.js.map +1 -0
  357. package/dist/mcp/schema/index.d.ts +8 -0
  358. package/dist/mcp/schema/index.d.ts.map +1 -0
  359. package/dist/mcp/schema/index.js +6 -0
  360. package/dist/mcp/schema/index.js.map +1 -0
  361. package/dist/mcp/server.d.ts +56 -0
  362. package/dist/mcp/server.d.ts.map +1 -0
  363. package/dist/mcp/server.js +168 -0
  364. package/dist/mcp/server.js.map +1 -0
  365. package/dist/mcp/shared-schema.d.ts +13 -0
  366. package/dist/mcp/shared-schema.d.ts.map +1 -0
  367. package/dist/mcp/shared-schema.js +28 -0
  368. package/dist/mcp/shared-schema.js.map +1 -0
  369. package/dist/mcp/tools/analytics-filters.d.ts +18 -0
  370. package/dist/mcp/tools/analytics-filters.d.ts.map +1 -0
  371. package/dist/mcp/tools/analytics-filters.js +35 -0
  372. package/dist/mcp/tools/analytics-filters.js.map +1 -0
  373. package/dist/mcp/tools/analytics.d.ts +16 -0
  374. package/dist/mcp/tools/analytics.d.ts.map +1 -0
  375. package/dist/mcp/tools/analytics.js +381 -0
  376. package/dist/mcp/tools/analytics.js.map +1 -0
  377. package/dist/mcp/tools/concept-profile.d.ts +14 -0
  378. package/dist/mcp/tools/concept-profile.d.ts.map +1 -0
  379. package/dist/mcp/tools/concept-profile.js +130 -0
  380. package/dist/mcp/tools/concept-profile.js.map +1 -0
  381. package/dist/mcp/tools/dataset-profile.d.ts +15 -0
  382. package/dist/mcp/tools/dataset-profile.d.ts.map +1 -0
  383. package/dist/mcp/tools/dataset-profile.js +194 -0
  384. package/dist/mcp/tools/dataset-profile.js.map +1 -0
  385. package/dist/mcp/tools/fetch-search-pages.d.ts +15 -0
  386. package/dist/mcp/tools/fetch-search-pages.d.ts.map +1 -0
  387. package/dist/mcp/tools/fetch-search-pages.js +237 -0
  388. package/dist/mcp/tools/fetch-search-pages.js.map +1 -0
  389. package/dist/mcp/tools/functions.d.ts +14 -0
  390. package/dist/mcp/tools/functions.d.ts.map +1 -0
  391. package/dist/mcp/tools/functions.js +87 -0
  392. package/dist/mcp/tools/functions.js.map +1 -0
  393. package/dist/mcp/tools/impact-chain.d.ts +15 -0
  394. package/dist/mcp/tools/impact-chain.d.ts.map +1 -0
  395. package/dist/mcp/tools/impact-chain.js +96 -0
  396. package/dist/mcp/tools/impact-chain.js.map +1 -0
  397. package/dist/mcp/tools/kwq.d.ts +19 -0
  398. package/dist/mcp/tools/kwq.d.ts.map +1 -0
  399. package/dist/mcp/tools/kwq.js +156 -0
  400. package/dist/mcp/tools/kwq.js.map +1 -0
  401. package/dist/mcp/tools/lookup.d.ts +14 -0
  402. package/dist/mcp/tools/lookup.d.ts.map +1 -0
  403. package/dist/mcp/tools/lookup.js +146 -0
  404. package/dist/mcp/tools/lookup.js.map +1 -0
  405. package/dist/mcp/tools/policy-profile.d.ts +15 -0
  406. package/dist/mcp/tools/policy-profile.d.ts.map +1 -0
  407. package/dist/mcp/tools/policy-profile.js +174 -0
  408. package/dist/mcp/tools/policy-profile.js.map +1 -0
  409. package/dist/mcp/tools/profile.d.ts +14 -0
  410. package/dist/mcp/tools/profile.d.ts.map +1 -0
  411. package/dist/mcp/tools/profile.js +349 -0
  412. package/dist/mcp/tools/profile.js.map +1 -0
  413. package/dist/mcp/tools/query.d.ts +16 -0
  414. package/dist/mcp/tools/query.d.ts.map +1 -0
  415. package/dist/mcp/tools/query.js +75 -0
  416. package/dist/mcp/tools/query.js.map +1 -0
  417. package/dist/mcp/tools/schema.d.ts +23 -0
  418. package/dist/mcp/tools/schema.d.ts.map +1 -0
  419. package/dist/mcp/tools/schema.js +124 -0
  420. package/dist/mcp/tools/schema.js.map +1 -0
  421. package/dist/mcp/tools/search-entity-metadata.d.ts +18 -0
  422. package/dist/mcp/tools/search-entity-metadata.d.ts.map +1 -0
  423. package/dist/mcp/tools/search-entity-metadata.js +221 -0
  424. package/dist/mcp/tools/search-entity-metadata.js.map +1 -0
  425. package/dist/mcp/tools/search-input.d.ts +58 -0
  426. package/dist/mcp/tools/search-input.d.ts.map +1 -0
  427. package/dist/mcp/tools/search-input.js +76 -0
  428. package/dist/mcp/tools/search-input.js.map +1 -0
  429. package/dist/mcp/tools/search.d.ts +24 -0
  430. package/dist/mcp/tools/search.d.ts.map +1 -0
  431. package/dist/mcp/tools/search.js +115 -0
  432. package/dist/mcp/tools/search.js.map +1 -0
  433. package/dist/mcp/utils.d.ts +82 -0
  434. package/dist/mcp/utils.d.ts.map +1 -0
  435. package/dist/mcp/utils.js +126 -0
  436. package/dist/mcp/utils.js.map +1 -0
  437. package/dist/middleware/field-aliases.d.ts +97 -0
  438. package/dist/middleware/field-aliases.d.ts.map +1 -0
  439. package/dist/middleware/field-aliases.js +208 -0
  440. package/dist/middleware/field-aliases.js.map +1 -0
  441. package/dist/resources/schema.d.ts +13 -0
  442. package/dist/resources/schema.d.ts.map +1 -0
  443. package/dist/resources/schema.js +204 -0
  444. package/dist/resources/schema.js.map +1 -0
  445. package/dist/schema/context.d.ts +10 -0
  446. package/dist/schema/context.d.ts.map +1 -0
  447. package/dist/schema/context.js +6 -0
  448. package/dist/schema/context.js.map +1 -0
  449. package/dist/schema/index.d.ts +9 -0
  450. package/dist/schema/index.d.ts.map +1 -0
  451. package/dist/schema/index.js +6 -0
  452. package/dist/schema/index.js.map +1 -0
  453. package/dist/schema/load.d.ts +43 -0
  454. package/dist/schema/load.d.ts.map +1 -0
  455. package/dist/schema/load.js +139 -0
  456. package/dist/schema/load.js.map +1 -0
  457. package/dist/schema/store.d.ts +112 -0
  458. package/dist/schema/store.d.ts.map +1 -0
  459. package/dist/schema/store.js +173 -0
  460. package/dist/schema/store.js.map +1 -0
  461. package/dist/schema/structured-entities.d.ts +21 -0
  462. package/dist/schema/structured-entities.d.ts.map +1 -0
  463. package/dist/schema/structured-entities.js +39 -0
  464. package/dist/schema/structured-entities.js.map +1 -0
  465. package/dist/schema/types.d.ts +36 -0
  466. package/dist/schema/types.d.ts.map +1 -0
  467. package/dist/schema/types.js +6 -0
  468. package/dist/schema/types.js.map +1 -0
  469. package/dist/server.d.ts +57 -0
  470. package/dist/server.d.ts.map +1 -0
  471. package/dist/server.js +144 -0
  472. package/dist/server.js.map +1 -0
  473. package/dist/telemetry.d.ts +172 -0
  474. package/dist/telemetry.d.ts.map +1 -0
  475. package/dist/telemetry.js +233 -0
  476. package/dist/telemetry.js.map +1 -0
  477. package/dist/tools/analytics-filters.d.ts +18 -0
  478. package/dist/tools/analytics-filters.d.ts.map +1 -0
  479. package/dist/tools/analytics-filters.js +35 -0
  480. package/dist/tools/analytics-filters.js.map +1 -0
  481. package/dist/tools/analytics.d.ts +16 -0
  482. package/dist/tools/analytics.d.ts.map +1 -0
  483. package/dist/tools/analytics.js +381 -0
  484. package/dist/tools/analytics.js.map +1 -0
  485. package/dist/tools/concept-profile.d.ts +14 -0
  486. package/dist/tools/concept-profile.d.ts.map +1 -0
  487. package/dist/tools/concept-profile.js +130 -0
  488. package/dist/tools/concept-profile.js.map +1 -0
  489. package/dist/tools/dataset-profile.d.ts +15 -0
  490. package/dist/tools/dataset-profile.d.ts.map +1 -0
  491. package/dist/tools/dataset-profile.js +194 -0
  492. package/dist/tools/dataset-profile.js.map +1 -0
  493. package/dist/tools/functions.d.ts +14 -0
  494. package/dist/tools/functions.d.ts.map +1 -0
  495. package/dist/tools/functions.js +294 -0
  496. package/dist/tools/functions.js.map +1 -0
  497. package/dist/tools/impact-chain.d.ts +15 -0
  498. package/dist/tools/impact-chain.d.ts.map +1 -0
  499. package/dist/tools/impact-chain.js +96 -0
  500. package/dist/tools/impact-chain.js.map +1 -0
  501. package/dist/tools/kwq.d.ts +19 -0
  502. package/dist/tools/kwq.d.ts.map +1 -0
  503. package/dist/tools/kwq.js +156 -0
  504. package/dist/tools/kwq.js.map +1 -0
  505. package/dist/tools/lookup.d.ts +14 -0
  506. package/dist/tools/lookup.d.ts.map +1 -0
  507. package/dist/tools/lookup.js +213 -0
  508. package/dist/tools/lookup.js.map +1 -0
  509. package/dist/tools/policy-profile.d.ts +15 -0
  510. package/dist/tools/policy-profile.d.ts.map +1 -0
  511. package/dist/tools/policy-profile.js +174 -0
  512. package/dist/tools/policy-profile.js.map +1 -0
  513. package/dist/tools/profile.d.ts +14 -0
  514. package/dist/tools/profile.d.ts.map +1 -0
  515. package/dist/tools/profile.js +349 -0
  516. package/dist/tools/profile.js.map +1 -0
  517. package/dist/tools/query.d.ts +16 -0
  518. package/dist/tools/query.d.ts.map +1 -0
  519. package/dist/tools/query.js +53 -0
  520. package/dist/tools/query.js.map +1 -0
  521. package/dist/tools/schema.d.ts +23 -0
  522. package/dist/tools/schema.d.ts.map +1 -0
  523. package/dist/tools/schema.js +124 -0
  524. package/dist/tools/schema.js.map +1 -0
  525. package/dist/tools/search-entity-metadata.d.ts +18 -0
  526. package/dist/tools/search-entity-metadata.d.ts.map +1 -0
  527. package/dist/tools/search-entity-metadata.js +221 -0
  528. package/dist/tools/search-entity-metadata.js.map +1 -0
  529. package/dist/tools/search.d.ts +23 -0
  530. package/dist/tools/search.d.ts.map +1 -0
  531. package/dist/tools/search.js +110 -0
  532. package/dist/tools/search.js.map +1 -0
  533. package/dist/tools/solr-fields.d.ts +39 -0
  534. package/dist/tools/solr-fields.d.ts.map +1 -0
  535. package/dist/tools/solr-fields.js +40 -0
  536. package/dist/tools/solr-fields.js.map +1 -0
  537. package/dist/utils.d.ts +70 -0
  538. package/dist/utils.d.ts.map +1 -0
  539. package/dist/utils.js +104 -0
  540. package/dist/utils.js.map +1 -0
  541. package/package.json +41 -0
  542. package/src/client/auth/config-loaders.ts +81 -0
  543. package/src/client/auth/decorators/index.ts +7 -0
  544. package/src/client/auth/decorators/with-caching.ts +237 -0
  545. package/src/client/auth/factory.ts +34 -0
  546. package/src/client/auth/index.ts +6 -0
  547. package/src/client/auth/jwt-utils.ts +36 -0
  548. package/src/client/auth/node.ts +16 -0
  549. package/src/client/auth/providers/index.ts +1 -0
  550. package/src/client/auth/providers/jwt-auth-provider.ts +153 -0
  551. package/src/client/auth/schemas.ts +25 -0
  552. package/src/client/auth/types.ts +30 -0
  553. package/src/client/command.ts +54 -0
  554. package/src/client/config/index.ts +15 -0
  555. package/src/client/config/loader.ts +155 -0
  556. package/src/client/config/node.ts +22 -0
  557. package/src/client/config/schemas.ts +28 -0
  558. package/src/client/config/types.ts +39 -0
  559. package/src/client/config/unified-loader.ts +118 -0
  560. package/src/client/config.ts +69 -0
  561. package/src/client/deployment-config.ts +98 -0
  562. package/src/client/errors.ts +295 -0
  563. package/src/client/http-client.ts +577 -0
  564. package/src/client/index.ts +68 -0
  565. package/src/client/internal-dsl-client.ts +128 -0
  566. package/src/client/rate-limiter.ts +139 -0
  567. package/src/client/resolve-api-key-user.ts +99 -0
  568. package/src/client/types.ts +44 -0
  569. package/src/dsl/client.ts +538 -0
  570. package/src/dsl/commands/apply-filters.ts +35 -0
  571. package/src/dsl/commands/facet/index.ts +12 -0
  572. package/src/dsl/commands/facet/schemas.ts +101 -0
  573. package/src/dsl/commands/functions/ClassifyCommand.ts +129 -0
  574. package/src/dsl/commands/functions/ExtractAffiliationsCommand.ts +163 -0
  575. package/src/dsl/commands/functions/ExtractConceptsCommand.ts +141 -0
  576. package/src/dsl/commands/functions/ExtractGrantsCommand.ts +112 -0
  577. package/src/dsl/commands/functions/index.ts +31 -0
  578. package/src/dsl/commands/index.ts +29 -0
  579. package/src/dsl/commands/validate-input.ts +29 -0
  580. package/src/dsl/create-client.ts +80 -0
  581. package/src/dsl/fluent-query-builder.ts +684 -0
  582. package/src/dsl/index.ts +206 -0
  583. package/src/dsl/pagination.ts +202 -0
  584. package/src/dsl/query-builder.ts +1120 -0
  585. package/src/dsl/response-parser.ts +299 -0
  586. package/src/dsl/schema/cache.ts +124 -0
  587. package/src/dsl/schema/extract.ts +44 -0
  588. package/src/dsl/schema/index.ts +50 -0
  589. package/src/dsl/schema/load.ts +160 -0
  590. package/src/dsl/schema/store.ts +253 -0
  591. package/src/dsl/schema/structured-entities.ts +44 -0
  592. package/src/dsl/schema/summary.ts +94 -0
  593. package/src/dsl/schema/types.ts +40 -0
  594. package/src/dsl/schema/validation.ts +56 -0
  595. package/src/dsl/types/buckets.ts +22 -0
  596. package/src/dsl/types/common.ts +99 -0
  597. package/src/dsl/types/entities.ts +43 -0
  598. package/src/dsl/types/index.ts +63 -0
  599. package/src/dsl/types/return-clauses.ts +147 -0
  600. package/src/dsl/types/special-functions.ts +220 -0
  601. package/src/dsl/types/vocabulary.ts +82 -0
  602. package/src/dsl/usage-policy.ts +219 -0
  603. package/src/dsl/utils/escape.ts +123 -0
  604. package/src/dsl/utils/sanitize.ts +21 -0
  605. package/src/dsl/utils/string-utils.ts +147 -0
  606. package/src/dsl/utils/validate-field-name.ts +19 -0
  607. package/src/http-main.ts +41 -0
  608. package/src/index.ts +14 -0
  609. package/src/main.ts +40 -0
  610. package/src/mcp/batch-fetch.ts +255 -0
  611. package/src/mcp/examples/dsl-examples.ts +66 -0
  612. package/src/mcp/examples/usage-scenarios.ts +185 -0
  613. package/src/mcp/export-format.ts +113 -0
  614. package/src/mcp/funder-org-names.ts +30 -0
  615. package/src/mcp/http-server.ts +148 -0
  616. package/src/mcp/middleware/field-aliases.ts +274 -0
  617. package/src/mcp/resources/schema.ts +364 -0
  618. package/src/mcp/schema/context.ts +11 -0
  619. package/src/mcp/schema/index.ts +38 -0
  620. package/src/mcp/server.ts +247 -0
  621. package/src/mcp/shared-schema.ts +34 -0
  622. package/src/mcp/tools/analytics-filters.ts +46 -0
  623. package/src/mcp/tools/analytics.ts +453 -0
  624. package/src/mcp/tools/fetch-search-pages.ts +329 -0
  625. package/src/mcp/tools/functions.ts +105 -0
  626. package/src/mcp/tools/lookup.ts +182 -0
  627. package/src/mcp/tools/query.ts +91 -0
  628. package/src/mcp/tools/schema.ts +147 -0
  629. package/src/mcp/tools/search-entity-metadata.ts +253 -0
  630. package/src/mcp/tools/search-input.ts +87 -0
  631. package/src/mcp/tools/search.ts +168 -0
  632. package/src/mcp/utils.ts +199 -0
  633. package/test/client/auth/config-loaders.test.ts +92 -0
  634. package/test/client/auth/decorators/with-caching.test.ts +482 -0
  635. package/test/client/auth/factory.test.ts +68 -0
  636. package/test/client/auth/providers/jwt-auth-provider.test.ts +398 -0
  637. package/test/client/auth/types.test.ts +18 -0
  638. package/test/client/command.test.ts +163 -0
  639. package/test/client/config/loader.test.ts +377 -0
  640. package/test/client/config/unified-loader.test.ts +136 -0
  641. package/test/client/deployment-config.test.ts +69 -0
  642. package/test/client/errors/index.test.ts +408 -0
  643. package/test/client/helpers/mock-fetch.ts +42 -0
  644. package/test/client/http-client.test.ts +1148 -0
  645. package/test/client/integration/auth-providers.integration.test.ts +186 -0
  646. package/test/client/internal-dsl-client.test.ts +76 -0
  647. package/test/client/rate-limiter.test.ts +204 -0
  648. package/test/client/resolve-api-key-user.test.ts +87 -0
  649. package/test/dsl/client.special-functions.test.ts +387 -0
  650. package/test/dsl/client.test.ts +457 -0
  651. package/test/dsl/commands/apply-filters.test.ts +147 -0
  652. package/test/dsl/commands/functions/ClassifyCommand.test.ts +170 -0
  653. package/test/dsl/commands/functions/ExtractAffiliationsCommand.test.ts +306 -0
  654. package/test/dsl/commands/functions/ExtractConceptsCommand.test.ts +136 -0
  655. package/test/dsl/commands/functions/ExtractGrantsCommand.test.ts +202 -0
  656. package/test/dsl/commands/search/filters.test.ts +42 -0
  657. package/test/dsl/fluent-query-builder.test.ts +865 -0
  658. package/test/dsl/integration/client.integration.test.ts +294 -0
  659. package/test/dsl/integration/facet-api.integration.test.ts +276 -0
  660. package/test/dsl/integration/field-existence.integration.test.ts +148 -0
  661. package/test/dsl/integration/fluent-api-docs-examples.integration.test.ts +988 -0
  662. package/test/dsl/integration/fluent-api.integration.test.ts +615 -0
  663. package/test/dsl/integration/search-helpers.ts +27 -0
  664. package/test/dsl/integration/special-functions.integration.test.ts +224 -0
  665. package/test/dsl/integration/test-config.ts +52 -0
  666. package/test/dsl/pagination.test.ts +86 -0
  667. package/test/dsl/query-builder.test.ts +1775 -0
  668. package/test/dsl/response-parser.test.ts +520 -0
  669. package/test/dsl/schema/cache.test.ts +53 -0
  670. package/test/dsl/schema/load.test.ts +165 -0
  671. package/test/dsl/schema/summary.test.ts +61 -0
  672. package/test/dsl/schema/validation.test.ts +46 -0
  673. package/test/dsl/time-series.test.ts +135 -0
  674. package/test/dsl/unnest.test.ts +151 -0
  675. package/test/dsl/usage-policy.test.ts +100 -0
  676. package/test/dsl/utils/escape.property.test.ts +109 -0
  677. package/test/dsl/utils/escape.test.ts +140 -0
  678. package/test/dsl/utils/validate-field-name.property.test.ts +99 -0
  679. package/test/dsl/utils/validate-field-name.test.ts +55 -0
  680. package/test/examples/dsl-examples.test.ts +29 -0
  681. package/test/examples/usage-scenarios.test.ts +90 -0
  682. package/test/fixtures/describe-schema.json +4000 -0
  683. package/test/funder-org-names.test.ts +20 -0
  684. package/test/helpers/schema-fixture.ts +18 -0
  685. package/test/helpers/tool-test-harness.ts +114 -0
  686. package/test/integration/assertions.ts +263 -0
  687. package/test/integration/env.ts +108 -0
  688. package/test/integration/harness.ts +307 -0
  689. package/test/integration/hosted-client.ts +56 -0
  690. package/test/integration/hosted-mocks.ts +81 -0
  691. package/test/integration/hosted-run.ts +86 -0
  692. package/test/integration/hosted.e2e.test.ts +101 -0
  693. package/test/integration/reporter.ts +100 -0
  694. package/test/integration/run.ts +74 -0
  695. package/test/integration/suites/analytics.integration.ts +72 -0
  696. package/test/integration/suites/functions.integration.ts +37 -0
  697. package/test/integration/suites/hosted-smoke.integration.ts +38 -0
  698. package/test/integration/suites/index.ts +22 -0
  699. package/test/integration/suites/lookup.integration.ts +57 -0
  700. package/test/integration/suites/query.integration.ts +49 -0
  701. package/test/integration/suites/resources.integration.ts +68 -0
  702. package/test/integration/suites/search.integration.ts +80 -0
  703. package/test/integration/types.ts +92 -0
  704. package/test/integration/verify-usage-scenarios.ts +162 -0
  705. package/test/mcp/export-format.test.ts +67 -0
  706. package/test/mcp/http-server.test.ts +80 -0
  707. package/test/middleware/field-aliases.test.ts +287 -0
  708. package/test/resources/schema.test.ts +28 -0
  709. package/test/schema/describe-contract.test.ts +24 -0
  710. package/test/schema/store.test.ts +45 -0
  711. package/test/server.test.ts +170 -0
  712. package/test/tools/analytics-filters.test.ts +35 -0
  713. package/test/tools/analytics.test.ts +419 -0
  714. package/test/tools/fetch-search-pages.test.ts +200 -0
  715. package/test/tools/functions.test.ts +153 -0
  716. package/test/tools/lookup.test.ts +296 -0
  717. package/test/tools/query.test.ts +100 -0
  718. package/test/tools/schema.test.ts +37 -0
  719. package/test/tools/search.test.ts +415 -0
  720. package/test/utils.test.ts +45 -0
  721. package/tsconfig.json +9 -0
  722. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,988 @@
1
+ /**
2
+ * Integration tests to validate the code examples in docs/FLUENT_API_GUIDE.md.
3
+ * Ensures documentation examples work correctly against the real Dimensions API.
4
+ * @module test/integration/fluent-api-docs-examples.integration
5
+ */
6
+
7
+ import { beforeAll, describe, expect, it } from "vitest";
8
+ import { DimensionsClient } from "../../../../src/dsl/index.js";
9
+
10
+ import { loadTestConfig } from "./test-config.js";
11
+
12
+ const config = loadTestConfig(); // was: process.env.DIMENSIONS_API_KEY
13
+ const TIMEOUT = 30_000;
14
+ const RATE_LIMIT_TIMEOUT = 90_000;
15
+ const EXTENDED_TIMEOUT = 120_000;
16
+
17
+ /**
18
+ * These tests validate that the code examples in the FLUENT_API_GUIDE.md
19
+ * documentation work correctly against the real Dimensions API.
20
+ */
21
+ describe.skipIf(!config)("FLUENT_API_GUIDE.md Examples Validation", () => {
22
+ let client: DimensionsClient;
23
+
24
+ beforeAll(() => {
25
+ client = new DimensionsClient({
26
+ apiKey: config!.apiKey,
27
+ ...(config!.baseUrl && { baseUrl: config!.baseUrl }),
28
+ rateLimitPerMinute: 30,
29
+ });
30
+ });
31
+
32
+ describe("Real-World Examples (Examples 1-6)", () => {
33
+ /**
34
+ * Example 1: Find Highly-Cited Recent Research
35
+ * From docs/FLUENT_API_GUIDE.md lines 532-554
36
+ */
37
+ it(
38
+ "Example 1: Find Highly-Cited Recent Research",
39
+ async () => {
40
+ const result = await client
41
+ .publications()
42
+ .for("deep learning")
43
+ .whereRange("year", 2021, 2024)
44
+ .where("times_cited", ">=", 100)
45
+ .openGroup()
46
+ .where("type", "=", "article")
47
+ .or()
48
+ .where("type", "=", "review")
49
+ .closeGroup()
50
+ .fields(["id", "title", "year", "times_cited", "doi"])
51
+ .sort("times_cited", "desc")
52
+ .limit(50)
53
+ .execute();
54
+
55
+ // Verify result structure
56
+ expect(result).toHaveProperty("data");
57
+ expect(result).toHaveProperty("totalCount");
58
+ expect(Array.isArray(result.data)).toBe(true);
59
+ expect(result.data.length).toBeGreaterThan(0);
60
+
61
+ // Verify each returned publication has the expected fields and values
62
+ for (const pub of result.data) {
63
+ // Check expected fields exist
64
+ expect(pub.id).toBeDefined();
65
+ expect(pub.title).toBeDefined();
66
+
67
+ // Verify year is in range (if present)
68
+ if (pub.year) {
69
+ expect(pub.year).toBeGreaterThanOrEqual(2021);
70
+ expect(pub.year).toBeLessThanOrEqual(2024);
71
+ }
72
+
73
+ // Verify citations >= 100 (if present)
74
+ if (pub.times_cited !== undefined) {
75
+ expect(pub.times_cited).toBeGreaterThanOrEqual(100);
76
+ }
77
+
78
+ // Verify type is article or review (if present)
79
+ if (pub.type) {
80
+ expect(["article", "review"]).toContain(pub.type);
81
+ }
82
+ }
83
+
84
+ // Verify sorting (times_cited should be descending)
85
+ for (let i = 1; i < result.data.length; i++) {
86
+ const prev = result.data[i - 1]?.times_cited ?? 0;
87
+ const curr = result.data[i]?.times_cited ?? 0;
88
+ expect(prev).toBeGreaterThanOrEqual(curr);
89
+ }
90
+ },
91
+ EXTENDED_TIMEOUT,
92
+ );
93
+
94
+ /**
95
+ * Example 2: Find Collaborative Open Science
96
+ * From docs/FLUENT_API_GUIDE.md lines 557-573
97
+ */
98
+ it(
99
+ "Example 2: Find Collaborative Open Science",
100
+ async () => {
101
+ const result = await client
102
+ .publications()
103
+ .for("genomics")
104
+ .whereRange("year", 2020, 2024)
105
+ .whereCount("authors", ">=", 5)
106
+ .whereNotEmpty("doi")
107
+ .where("open_access", "!=", "closed")
108
+ .fields(["id", "title", "authors_count", "doi", "open_access"])
109
+ .limit(20)
110
+ .execute();
111
+
112
+ // Verify result structure
113
+ expect(result).toHaveProperty("data");
114
+ expect(result).toHaveProperty("totalCount");
115
+ expect(result.data.length).toBeGreaterThan(0);
116
+
117
+ // Verify each publication meets the criteria
118
+ for (const pub of result.data) {
119
+ expect(pub.id).toBeDefined();
120
+ expect(pub.title).toBeDefined();
121
+
122
+ // Verify DOI is present (not empty)
123
+ expect(pub.doi).toBeDefined();
124
+ expect(pub.doi).not.toBe("");
125
+
126
+ // Verify open access is not closed (if present)
127
+ if (pub.open_access) {
128
+ expect(pub.open_access).not.toBe("closed");
129
+ }
130
+
131
+ // Note: authors_count validation depends on API returning this field
132
+ // The whereCount filter ensures >= 5 authors, but authors_count field
133
+ // may not always be returned even if requested
134
+ }
135
+ },
136
+ RATE_LIMIT_TIMEOUT,
137
+ );
138
+
139
+ /**
140
+ * Example 3: Track Funding by Topic and Year
141
+ * From docs/FLUENT_API_GUIDE.md lines 575-597
142
+ */
143
+ it(
144
+ "Example 3: Track Funding by Topic and Year",
145
+ async () => {
146
+ const result = await client
147
+ .grants()
148
+ .for("renewable energy")
149
+ .whereRange("start_year", 2020, 2024)
150
+ .whereNotEmpty("funder_org_name")
151
+ .whereNotEmpty("funding_usd")
152
+ .fields(["id", "title", "start_year", "funder_org_name", "funding_usd"])
153
+ .sort("funding_usd", "desc")
154
+ .limit(100)
155
+ .execute();
156
+
157
+ // Verify result structure
158
+ expect(result).toHaveProperty("data");
159
+ expect(result).toHaveProperty("totalCount");
160
+ expect(result.data.length).toBeGreaterThan(0);
161
+
162
+ // Verify each grant meets the criteria
163
+ for (const grant of result.data) {
164
+ expect(grant.id).toBeDefined();
165
+ expect(grant.title).toBeDefined();
166
+
167
+ // Verify start_year is in range (if present)
168
+ if (grant.start_year) {
169
+ expect(grant.start_year).toBeGreaterThanOrEqual(2020);
170
+ expect(grant.start_year).toBeLessThanOrEqual(2024);
171
+ }
172
+
173
+ // Verify funder_org_name is not empty (if present)
174
+ if (grant.funder_org_name) {
175
+ expect(grant.funder_org_name).not.toBe("");
176
+ }
177
+ }
178
+
179
+ // Test the calculation pattern from the documentation
180
+ const totalFunding = result.data.reduce((sum, grant) => sum + (grant.funding_usd ?? 0), 0);
181
+ expect(totalFunding).toBeGreaterThan(0);
182
+ },
183
+ RATE_LIMIT_TIMEOUT,
184
+ );
185
+
186
+ /**
187
+ * Example 4: Find Active Clinical Trials
188
+ * From docs/FLUENT_API_GUIDE.md lines 599-616
189
+ */
190
+ it(
191
+ "Example 4: Find Active Clinical Trials",
192
+ async () => {
193
+ const result = await client
194
+ .clinicalTrials()
195
+ .for("cancer immunotherapy")
196
+ .whereIn("phase", ["Phase 2", "Phase 3", "Phase 4"])
197
+ .where("overall_status", "=", "Recruiting")
198
+ .fields(["id", "title", "phase", "overall_status", "conditions", "start_date"])
199
+ .sort("start_date", "desc")
200
+ .limit(50)
201
+ .execute();
202
+
203
+ // Verify result structure
204
+ expect(result).toHaveProperty("data");
205
+ expect(result).toHaveProperty("totalCount");
206
+ // Note: We may get 0 results if no recruiting trials match
207
+ expect(Array.isArray(result.data)).toBe(true);
208
+
209
+ // Verify each trial meets the criteria (if any results)
210
+ for (const trial of result.data) {
211
+ expect(trial.id).toBeDefined();
212
+
213
+ // Verify phase is in the expected list (if present)
214
+ if (trial.phase) {
215
+ expect(["Phase 2", "Phase 3", "Phase 4"]).toContain(trial.phase);
216
+ }
217
+
218
+ // Verify status is Recruiting (if present)
219
+ if (trial.overall_status) {
220
+ expect(trial.overall_status).toBe("Recruiting");
221
+ }
222
+ }
223
+ },
224
+ RATE_LIMIT_TIMEOUT,
225
+ );
226
+
227
+ /**
228
+ * Example 5: Patent Analysis by Company
229
+ * From docs/FLUENT_API_GUIDE.md lines 618-650
230
+ */
231
+ it(
232
+ "Example 5: Patent Analysis by Company",
233
+ async () => {
234
+ const result = await client
235
+ .patents()
236
+ .for("electric vehicle battery")
237
+ .where("year", ">=", 2020)
238
+ .whereNotEmpty("assignees")
239
+ .fields(["id", "title", "year", "assignees", "filing_date"])
240
+ .sort("filing_date", "desc")
241
+ .limit(200)
242
+ .execute();
243
+
244
+ // Verify result structure
245
+ expect(result).toHaveProperty("data");
246
+ expect(result).toHaveProperty("totalCount");
247
+ expect(result.data.length).toBeGreaterThan(0);
248
+
249
+ // Verify each patent meets the criteria
250
+ for (const patent of result.data) {
251
+ expect(patent.id).toBeDefined();
252
+ expect(patent.title).toBeDefined();
253
+
254
+ // Verify year >= 2020 (if present)
255
+ if (patent.year) {
256
+ expect(patent.year).toBeGreaterThanOrEqual(2020);
257
+ }
258
+ }
259
+
260
+ // Test the grouping pattern from the documentation
261
+ const byAssignee = new Map<string, number>();
262
+ for (const patent of result.data) {
263
+ if (patent.assignees) {
264
+ for (const assignee of patent.assignees) {
265
+ byAssignee.set(assignee.name, (byAssignee.get(assignee.name) ?? 0) + 1);
266
+ }
267
+ }
268
+ }
269
+
270
+ // Should have at least some assignees grouped
271
+ expect(byAssignee.size).toBeGreaterThan(0);
272
+ },
273
+ RATE_LIMIT_TIMEOUT,
274
+ );
275
+
276
+ /**
277
+ * Example 6: Researcher Profile with Publications
278
+ * From docs/FLUENT_API_GUIDE.md lines 652-685
279
+ *
280
+ * NOTE: The documentation example wraps the name in extra quotes like:
281
+ * .for(`"${researcher.first_name} ${researcher.last_name}"`)
282
+ * This is INCORRECT because .for() already adds quotes around the search term.
283
+ * The correct usage is:
284
+ * .for(`${researcher.first_name} ${researcher.last_name}`)
285
+ * This test uses the corrected version.
286
+ */
287
+ it(
288
+ "Example 6: Researcher Profile with Publications",
289
+ async () => {
290
+ // First part: Find researchers
291
+ const researchers = await client
292
+ .researchers()
293
+ .for("Jennifer Doudna")
294
+ .whereNotEmpty("orcid_id")
295
+ .limit(5)
296
+ .execute();
297
+
298
+ // Verify researcher search works
299
+ expect(researchers).toHaveProperty("data");
300
+ expect(researchers).toHaveProperty("totalCount");
301
+ expect(Array.isArray(researchers.data)).toBe(true);
302
+
303
+ // If researchers found, try to get their publications
304
+ if (researchers.data.length > 0) {
305
+ const researcher = researchers.data[0];
306
+
307
+ // Verify researcher structure
308
+ expect(researcher).toHaveProperty("id");
309
+
310
+ // Second part: Search for publications by researcher name
311
+ // Note: Do NOT add extra quotes - for() already quotes the search term
312
+ if (researcher.first_name && researcher.last_name) {
313
+ const publications = await client
314
+ .publications()
315
+ .for(`${researcher.first_name} ${researcher.last_name}`)
316
+ .in("authors")
317
+ .whereRange("year", 2020, 2024)
318
+ .fields(["id", "title", "year", "times_cited"])
319
+ .sort("times_cited", "desc")
320
+ .limit(20)
321
+ .execute();
322
+
323
+ // Verify publications result
324
+ expect(publications).toHaveProperty("data");
325
+ expect(publications).toHaveProperty("totalCount");
326
+ expect(Array.isArray(publications.data)).toBe(true);
327
+
328
+ // Verify year range if publications exist
329
+ for (const pub of publications.data) {
330
+ if (pub.year) {
331
+ expect(pub.year).toBeGreaterThanOrEqual(2020);
332
+ expect(pub.year).toBeLessThanOrEqual(2024);
333
+ }
334
+ }
335
+ }
336
+ }
337
+ },
338
+ EXTENDED_TIMEOUT,
339
+ );
340
+ });
341
+
342
+ describe("Basic Query Examples", () => {
343
+ /**
344
+ * Basic query with where clauses
345
+ * From docs/FLUENT_API_GUIDE.md lines 255-263
346
+ */
347
+ it(
348
+ "basic filters with where clause",
349
+ async () => {
350
+ const result = await client
351
+ .publications()
352
+ .for("AI")
353
+ .where("year", ">=", 2020)
354
+ .where("times_cited", ">", 100)
355
+ .where("type", "=", "article")
356
+ .limit(10)
357
+ .execute();
358
+
359
+ expect(result).toHaveProperty("data");
360
+ expect(result).toHaveProperty("totalCount");
361
+
362
+ for (const pub of result.data) {
363
+ if (pub.year) {
364
+ expect(pub.year).toBeGreaterThanOrEqual(2020);
365
+ }
366
+ if (pub.times_cited !== undefined) {
367
+ expect(pub.times_cited).toBeGreaterThan(100);
368
+ }
369
+ if (pub.type) {
370
+ expect(pub.type).toBe("article");
371
+ }
372
+ }
373
+ },
374
+ RATE_LIMIT_TIMEOUT,
375
+ );
376
+
377
+ /**
378
+ * whereEmpty and whereNotEmpty usage
379
+ * From docs/FLUENT_API_GUIDE.md lines 279-286
380
+ */
381
+ it(
382
+ "whereEmpty and whereNotEmpty filters",
383
+ async () => {
384
+ const result = await client
385
+ .publications()
386
+ .for("research")
387
+ .whereNotEmpty("doi")
388
+ .fields(["id", "title", "doi"])
389
+ .limit(10)
390
+ .execute();
391
+
392
+ expect(result.data.length).toBeGreaterThan(0);
393
+
394
+ for (const pub of result.data) {
395
+ expect(pub.doi).toBeDefined();
396
+ expect(pub.doi).not.toBe("");
397
+ }
398
+ },
399
+ RATE_LIMIT_TIMEOUT,
400
+ );
401
+ });
402
+
403
+ describe("whereIn Examples", () => {
404
+ /**
405
+ * List filters with whereIn
406
+ * From docs/FLUENT_API_GUIDE.md lines 290-299
407
+ */
408
+ it(
409
+ "whereIn for type filtering",
410
+ async () => {
411
+ const result = await client
412
+ .publications()
413
+ .for("science")
414
+ .whereIn("type", ["article", "review", "preprint"])
415
+ .whereIn("year", [2022, 2023, 2024])
416
+ .fields(["id", "title", "type", "year"])
417
+ .limit(20)
418
+ .execute();
419
+
420
+ expect(result.data.length).toBeGreaterThan(0);
421
+
422
+ for (const pub of result.data) {
423
+ if (pub.type) {
424
+ expect(["article", "review", "preprint"]).toContain(pub.type);
425
+ }
426
+ if (pub.year) {
427
+ expect([2022, 2023, 2024]).toContain(pub.year);
428
+ }
429
+ }
430
+ },
431
+ RATE_LIMIT_TIMEOUT,
432
+ );
433
+ });
434
+
435
+ describe("whereRange Examples", () => {
436
+ /**
437
+ * Range filters with whereRange
438
+ * From docs/FLUENT_API_GUIDE.md lines 303-312
439
+ */
440
+ it(
441
+ "whereRange for year and citations",
442
+ async () => {
443
+ const result = await client
444
+ .publications()
445
+ .for("genomics")
446
+ .whereRange("year", 2020, 2024)
447
+ .whereRange("times_cited", 10, 100)
448
+ .fields(["id", "title", "year", "times_cited"])
449
+ .limit(20)
450
+ .execute();
451
+
452
+ expect(result).toHaveProperty("data");
453
+
454
+ for (const pub of result.data) {
455
+ if (pub.year) {
456
+ expect(pub.year).toBeGreaterThanOrEqual(2020);
457
+ expect(pub.year).toBeLessThanOrEqual(2024);
458
+ }
459
+ if (pub.times_cited !== undefined) {
460
+ expect(pub.times_cited).toBeGreaterThanOrEqual(10);
461
+ expect(pub.times_cited).toBeLessThanOrEqual(100);
462
+ }
463
+ }
464
+ },
465
+ RATE_LIMIT_TIMEOUT,
466
+ );
467
+ });
468
+
469
+ describe("whereCount Examples", () => {
470
+ /**
471
+ * Count filters with whereCount
472
+ * From docs/FLUENT_API_GUIDE.md lines 316-332
473
+ */
474
+ it(
475
+ "whereCount for collaborative research (5+ authors)",
476
+ async () => {
477
+ const result = await client
478
+ .publications()
479
+ .for("research")
480
+ .whereCount("authors", ">=", 5)
481
+ .fields(["id", "title", "authors"])
482
+ .limit(10)
483
+ .execute();
484
+
485
+ expect(result.data.length).toBeGreaterThan(0);
486
+
487
+ for (const pub of result.data) {
488
+ if (pub.authors) {
489
+ expect(pub.authors.length).toBeGreaterThanOrEqual(5);
490
+ }
491
+ }
492
+ },
493
+ RATE_LIMIT_TIMEOUT,
494
+ );
495
+
496
+ /**
497
+ * whereCount for single-author publications
498
+ * From docs/FLUENT_API_GUIDE.md lines 328-332
499
+ */
500
+ it(
501
+ "whereCount for single-author publications",
502
+ async () => {
503
+ const result = await client
504
+ .publications()
505
+ .for("research")
506
+ .whereCount("authors", "=", 1)
507
+ .fields(["id", "title", "authors"])
508
+ .limit(10)
509
+ .execute();
510
+
511
+ expect(result.data.length).toBeGreaterThan(0);
512
+
513
+ for (const pub of result.data) {
514
+ if (pub.authors) {
515
+ expect(pub.authors.length).toBe(1);
516
+ }
517
+ }
518
+ },
519
+ RATE_LIMIT_TIMEOUT,
520
+ );
521
+ });
522
+
523
+ describe("Boolean Logic Examples", () => {
524
+ /**
525
+ * AND logic (default behavior)
526
+ * From docs/FLUENT_API_GUIDE.md lines 340-352
527
+ */
528
+ it(
529
+ "AND logic - multiple conditions combined",
530
+ async () => {
531
+ const result = await client
532
+ .publications()
533
+ .for("AI")
534
+ .where("year", ">=", 2020)
535
+ .where("type", "=", "article")
536
+ .fields(["id", "year", "type"])
537
+ .limit(10)
538
+ .execute();
539
+
540
+ expect(result.data.length).toBeGreaterThan(0);
541
+
542
+ for (const pub of result.data) {
543
+ if (pub.year) {
544
+ expect(pub.year).toBeGreaterThanOrEqual(2020);
545
+ }
546
+ if (pub.type) {
547
+ expect(pub.type).toBe("article");
548
+ }
549
+ }
550
+ },
551
+ RATE_LIMIT_TIMEOUT,
552
+ );
553
+
554
+ /**
555
+ * OR logic
556
+ * From docs/FLUENT_API_GUIDE.md lines 354-368
557
+ */
558
+ it(
559
+ "OR logic - alternative conditions",
560
+ async () => {
561
+ const result = await client
562
+ .publications()
563
+ .for("research")
564
+ .where("type", "=", "article")
565
+ .or()
566
+ .where("type", "=", "review")
567
+ .fields(["id", "type"])
568
+ .limit(10)
569
+ .execute();
570
+
571
+ expect(result.data.length).toBeGreaterThan(0);
572
+
573
+ for (const pub of result.data) {
574
+ if (pub.type) {
575
+ expect(["article", "review"]).toContain(pub.type);
576
+ }
577
+ }
578
+ },
579
+ RATE_LIMIT_TIMEOUT,
580
+ );
581
+
582
+ /**
583
+ * NOT logic
584
+ * From docs/FLUENT_API_GUIDE.md lines 370-383
585
+ */
586
+ it(
587
+ "NOT logic - negation",
588
+ async () => {
589
+ const result = await client
590
+ .publications()
591
+ .for("research")
592
+ .where("type", "=", "article")
593
+ .not()
594
+ .where("open_access", "=", "closed")
595
+ .fields(["id", "type", "open_access"])
596
+ .limit(10)
597
+ .execute();
598
+
599
+ expect(result.data.length).toBeGreaterThan(0);
600
+
601
+ for (const pub of result.data) {
602
+ if (pub.type) {
603
+ expect(pub.type).toBe("article");
604
+ }
605
+ // open_access should not be "closed"
606
+ if (pub.open_access) {
607
+ expect(pub.open_access).not.toBe("closed");
608
+ }
609
+ }
610
+ },
611
+ RATE_LIMIT_TIMEOUT,
612
+ );
613
+
614
+ /**
615
+ * Explicit AND
616
+ * From docs/FLUENT_API_GUIDE.md lines 385-398
617
+ */
618
+ it(
619
+ "explicit AND - same as default",
620
+ async () => {
621
+ const result = await client
622
+ .publications()
623
+ .for("AI")
624
+ .where("year", ">=", 2020)
625
+ .and()
626
+ .where("type", "=", "article")
627
+ .fields(["id", "year", "type"])
628
+ .limit(10)
629
+ .execute();
630
+
631
+ expect(result.data.length).toBeGreaterThan(0);
632
+
633
+ for (const pub of result.data) {
634
+ if (pub.year) {
635
+ expect(pub.year).toBeGreaterThanOrEqual(2020);
636
+ }
637
+ if (pub.type) {
638
+ expect(pub.type).toBe("article");
639
+ }
640
+ }
641
+ },
642
+ RATE_LIMIT_TIMEOUT,
643
+ );
644
+ });
645
+
646
+ describe("Grouping Examples", () => {
647
+ /**
648
+ * Basic grouping with openGroup/closeGroup
649
+ * From docs/FLUENT_API_GUIDE.md lines 400-418
650
+ */
651
+ it(
652
+ "grouping with parentheses",
653
+ async () => {
654
+ const result = await client
655
+ .publications()
656
+ .for("research")
657
+ .openGroup()
658
+ .where("type", "=", "article")
659
+ .or()
660
+ .where("type", "=", "review")
661
+ .closeGroup()
662
+ .and()
663
+ .where("year", ">=", 2020)
664
+ .fields(["id", "type", "year"])
665
+ .limit(10)
666
+ .execute();
667
+
668
+ expect(result.data.length).toBeGreaterThan(0);
669
+
670
+ for (const pub of result.data) {
671
+ if (pub.type) {
672
+ expect(["article", "review"]).toContain(pub.type);
673
+ }
674
+ if (pub.year) {
675
+ expect(pub.year).toBeGreaterThanOrEqual(2020);
676
+ }
677
+ }
678
+ },
679
+ RATE_LIMIT_TIMEOUT,
680
+ );
681
+
682
+ /**
683
+ * Nested groups
684
+ * From docs/FLUENT_API_GUIDE.md lines 420-442
685
+ */
686
+ it(
687
+ "nested groups for complex logic",
688
+ async () => {
689
+ const result = await client
690
+ .publications()
691
+ .for("science")
692
+ .openGroup()
693
+ .openGroup()
694
+ .where("type", "=", "article")
695
+ .or()
696
+ .where("type", "=", "review")
697
+ .closeGroup()
698
+ .and()
699
+ .where("year", ">=", 2020)
700
+ .closeGroup()
701
+ .and()
702
+ .whereNotEmpty("doi")
703
+ .fields(["id", "type", "year", "doi"])
704
+ .limit(10)
705
+ .execute();
706
+
707
+ expect(result.data.length).toBeGreaterThan(0);
708
+
709
+ for (const pub of result.data) {
710
+ if (pub.type) {
711
+ expect(["article", "review"]).toContain(pub.type);
712
+ }
713
+ if (pub.year) {
714
+ expect(pub.year).toBeGreaterThanOrEqual(2020);
715
+ }
716
+ expect(pub.doi).toBeDefined();
717
+ expect(pub.doi).not.toBe("");
718
+ }
719
+ },
720
+ RATE_LIMIT_TIMEOUT,
721
+ );
722
+ });
723
+
724
+ describe("Search Index Examples", () => {
725
+ /**
726
+ * Search index with in()
727
+ * From docs/FLUENT_API_GUIDE.md lines 213-222
728
+ */
729
+ it(
730
+ "search index - title_abstract_only",
731
+ async () => {
732
+ const result = await client
733
+ .publications()
734
+ .in("title_abstract_only")
735
+ .for("CRISPR gene editing")
736
+ .fields(["id", "title", "abstract"])
737
+ .limit(10)
738
+ .execute();
739
+
740
+ expect(result.data.length).toBeGreaterThan(0);
741
+
742
+ // Results should have CRISPR in title or abstract
743
+ for (const pub of result.data) {
744
+ const searchableText = `${pub.title ?? ""} ${pub.abstract ?? ""}`.toLowerCase();
745
+ const hasCrispr = searchableText.includes("crispr");
746
+ const hasGene = searchableText.includes("gene");
747
+ const hasEditing = searchableText.includes("editing");
748
+ // At least one of the search terms should appear
749
+ expect(hasCrispr || hasGene || hasEditing).toBe(true);
750
+ }
751
+ },
752
+ RATE_LIMIT_TIMEOUT,
753
+ );
754
+ });
755
+
756
+ describe("getDsl() Validation", () => {
757
+ /**
758
+ * getDsl() should match documented output
759
+ * From docs/FLUENT_API_GUIDE.md lines 449-462
760
+ */
761
+ it("getDsl generates expected DSL query", () => {
762
+ const dsl = client
763
+ .publications()
764
+ .for("machine learning")
765
+ .where("year", ">=", 2020)
766
+ .where("type", "=", "article")
767
+ .fields(["id", "title"])
768
+ .getDsl();
769
+
770
+ // Verify the DSL contains expected parts
771
+ expect(dsl).toContain("search publications");
772
+ expect(dsl).toContain('for "machine learning"');
773
+ expect(dsl).toContain("year >= 2020");
774
+ expect(dsl).toContain('type = "article"');
775
+ expect(dsl).toContain("return publications[id+title]");
776
+ });
777
+
778
+ /**
779
+ * Complex getDsl example
780
+ */
781
+ it("getDsl for complex query with all features", () => {
782
+ const dsl = client
783
+ .publications()
784
+ .in("title_abstract_only")
785
+ .for("artificial intelligence")
786
+ .where("year", ">=", 2020)
787
+ .openGroup()
788
+ .where("type", "=", "article")
789
+ .or()
790
+ .where("type", "=", "review")
791
+ .closeGroup()
792
+ .whereNotEmpty("doi")
793
+ .fields(["id", "title", "year", "doi"])
794
+ .sort("times_cited", "desc")
795
+ .limit(50)
796
+ .skip(10)
797
+ .getDsl();
798
+
799
+ expect(dsl).toContain("search publications");
800
+ expect(dsl).toContain("in title_abstract_only");
801
+ expect(dsl).toContain('for "artificial intelligence"');
802
+ expect(dsl).toContain("year >= 2020");
803
+ expect(dsl).toContain('type = "article"');
804
+ expect(dsl).toContain("or");
805
+ expect(dsl).toContain('type = "review"');
806
+ expect(dsl).toContain("doi is not empty");
807
+ expect(dsl).toContain("return publications[id+title+year+doi]");
808
+ expect(dsl).toContain("sort by times_cited desc");
809
+ expect(dsl).toContain("limit 50 skip 10");
810
+ });
811
+ });
812
+
813
+ describe("Field Validation", () => {
814
+ /**
815
+ * Verify all fields used in documentation examples are valid
816
+ */
817
+ it(
818
+ "publication fields from examples are valid",
819
+ async () => {
820
+ const result = await client
821
+ .publications()
822
+ .for("test")
823
+ .fields([
824
+ "id",
825
+ "title",
826
+ "doi",
827
+ "year",
828
+ "times_cited",
829
+ "type",
830
+ "open_access",
831
+ "authors",
832
+ "authors_count",
833
+ "abstract",
834
+ ])
835
+ .limit(1)
836
+ .execute();
837
+
838
+ // If we get here without error, the fields are valid
839
+ expect(result).toHaveProperty("data");
840
+ },
841
+ TIMEOUT,
842
+ );
843
+
844
+ it(
845
+ "grant fields from examples are valid",
846
+ async () => {
847
+ const result = await client
848
+ .grants()
849
+ .for("test")
850
+ .fields(["id", "title", "start_year", "funder_org_name", "funding_usd"])
851
+ .limit(1)
852
+ .execute();
853
+
854
+ expect(result).toHaveProperty("data");
855
+ },
856
+ TIMEOUT,
857
+ );
858
+
859
+ it(
860
+ "clinical trial fields from examples are valid",
861
+ async () => {
862
+ const result = await client
863
+ .clinicalTrials()
864
+ .for("test")
865
+ .fields(["id", "title", "phase", "overall_status", "conditions", "start_date"])
866
+ .limit(1)
867
+ .execute();
868
+
869
+ expect(result).toHaveProperty("data");
870
+ },
871
+ TIMEOUT,
872
+ );
873
+
874
+ it(
875
+ "patent fields from examples are valid",
876
+ async () => {
877
+ const result = await client
878
+ .patents()
879
+ .for("test")
880
+ .fields(["id", "title", "year", "assignees", "filing_date"])
881
+ .limit(1)
882
+ .execute();
883
+
884
+ expect(result).toHaveProperty("data");
885
+ },
886
+ TIMEOUT,
887
+ );
888
+
889
+ it(
890
+ "researcher fields from examples are valid",
891
+ async () => {
892
+ const result = await client.researchers().for("*").limit(1).execute();
893
+
894
+ expect(result).toHaveProperty("data");
895
+ if (result.data.length > 0) {
896
+ // Check that researcher has expected structure
897
+ const researcher = result.data[0];
898
+ expect(researcher).toHaveProperty("id");
899
+ }
900
+ },
901
+ TIMEOUT,
902
+ );
903
+ });
904
+
905
+ describe("Pagination Examples", () => {
906
+ /**
907
+ * Pagination with limit and skip
908
+ * From docs/FLUENT_API_GUIDE.md lines 177-196
909
+ */
910
+ it(
911
+ "pagination works correctly",
912
+ async () => {
913
+ // Get first page
914
+ const page1 = await client
915
+ .publications()
916
+ .for("climate change")
917
+ .fields(["id", "title"])
918
+ .sort("id", "asc")
919
+ .limit(5)
920
+ .execute();
921
+
922
+ expect(page1.data.length).toBe(5);
923
+
924
+ // Get second page
925
+ const page2 = await client
926
+ .publications()
927
+ .for("climate change")
928
+ .fields(["id", "title"])
929
+ .sort("id", "asc")
930
+ .skip(5)
931
+ .limit(5)
932
+ .execute();
933
+
934
+ expect(page2.data.length).toBeGreaterThan(0);
935
+
936
+ // Ensure no overlap
937
+ const page1Ids = new Set(page1.data.map((p) => p.id));
938
+ for (const pub of page2.data) {
939
+ expect(page1Ids.has(pub.id)).toBe(false);
940
+ }
941
+ },
942
+ EXTENDED_TIMEOUT,
943
+ );
944
+ });
945
+
946
+ describe("Type Safety Validation", () => {
947
+ /**
948
+ * Verify returned data has correct types as documented
949
+ * From docs/FLUENT_API_GUIDE.md lines 43-53
950
+ */
951
+ it(
952
+ "result.data is correctly typed array",
953
+ async () => {
954
+ const result = await client
955
+ .publications()
956
+ .for("CRISPR")
957
+ .fields(["id", "title", "doi"])
958
+ .limit(5)
959
+ .execute();
960
+
961
+ // result.data should be an array
962
+ expect(Array.isArray(result.data)).toBe(true);
963
+
964
+ // Each item should have the structure of a Publication
965
+ for (const pub of result.data) {
966
+ expect(typeof pub.id).toBe("string");
967
+ expect(typeof pub.title).toBe("string");
968
+ // doi is optional, but if present should be string
969
+ if (pub.doi !== undefined) {
970
+ expect(typeof pub.doi).toBe("string");
971
+ }
972
+ }
973
+ },
974
+ TIMEOUT,
975
+ );
976
+
977
+ it(
978
+ "result.totalCount is a number",
979
+ async () => {
980
+ const result = await client.publications().for("genomics").limit(1).execute();
981
+
982
+ expect(typeof result.totalCount).toBe("number");
983
+ expect(result.totalCount).toBeGreaterThanOrEqual(0);
984
+ },
985
+ TIMEOUT,
986
+ );
987
+ });
988
+ });