@ncukondo/reference-manager 0.24.1 → 0.26.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 (80) hide show
  1. package/README.md +53 -1
  2. package/dist/chunks/{SearchableMultiSelect-CKRfbnka.js → SearchableMultiSelect-D2IzthN4.js} +2 -2
  3. package/dist/chunks/{SearchableMultiSelect-CKRfbnka.js.map → SearchableMultiSelect-D2IzthN4.js.map} +1 -1
  4. package/dist/chunks/{action-menu-BCgv1m3v.js → action-menu-DWdoHTFh.js} +3 -3
  5. package/dist/chunks/{action-menu-BCgv1m3v.js.map → action-menu-DWdoHTFh.js.map} +1 -1
  6. package/dist/chunks/checker-CKfdG8Ia.js +170 -0
  7. package/dist/chunks/checker-CKfdG8Ia.js.map +1 -0
  8. package/dist/chunks/crossref-client-Gs75LMVf.js +94 -0
  9. package/dist/chunks/crossref-client-Gs75LMVf.js.map +1 -0
  10. package/dist/chunks/fix-interaction-DNXbmlPr.js +262 -0
  11. package/dist/chunks/fix-interaction-DNXbmlPr.js.map +1 -0
  12. package/dist/chunks/{index-JA964gjc.js → index-BEQ4YIXx.js} +356 -27
  13. package/dist/chunks/index-BEQ4YIXx.js.map +1 -0
  14. package/dist/chunks/{index-zafRwZEZ.js → index-k67fQbe4.js} +3 -3
  15. package/dist/chunks/index-k67fQbe4.js.map +1 -0
  16. package/dist/chunks/{index-DWAtvFtp.js → index-of6eJn8N.js} +209 -21
  17. package/dist/chunks/index-of6eJn8N.js.map +1 -0
  18. package/dist/chunks/{index-C36Us_zC.js → index-tdmbNN9b.js} +4 -4
  19. package/dist/chunks/{index-C36Us_zC.js.map → index-tdmbNN9b.js.map} +1 -1
  20. package/dist/chunks/{loader-CV71qNY2.js → loader-B-fte1uv.js} +19 -8
  21. package/dist/chunks/loader-B-fte1uv.js.map +1 -0
  22. package/dist/chunks/metadata-comparator-C5zfoYdK.js +137 -0
  23. package/dist/chunks/metadata-comparator-C5zfoYdK.js.map +1 -0
  24. package/dist/chunks/pubmed-client-CGReJIOz.js +51 -0
  25. package/dist/chunks/pubmed-client-CGReJIOz.js.map +1 -0
  26. package/dist/chunks/{reference-select-Bbl-roAS.js → reference-select-i1Cnmc16.js} +3 -3
  27. package/dist/chunks/{reference-select-Bbl-roAS.js.map → reference-select-i1Cnmc16.js.map} +1 -1
  28. package/dist/chunks/{style-select-BeAktUts.js → style-select-COnY01qb.js} +3 -3
  29. package/dist/chunks/{style-select-BeAktUts.js.map → style-select-COnY01qb.js.map} +1 -1
  30. package/dist/cli/commands/check.d.ts +43 -0
  31. package/dist/cli/commands/check.d.ts.map +1 -0
  32. package/dist/cli/commands/index.d.ts +2 -0
  33. package/dist/cli/commands/index.d.ts.map +1 -1
  34. package/dist/cli/index.d.ts.map +1 -1
  35. package/dist/cli/server-client.d.ts +2 -1
  36. package/dist/cli/server-client.d.ts.map +1 -1
  37. package/dist/cli.js +1 -1
  38. package/dist/config/defaults.d.ts.map +1 -1
  39. package/dist/config/env-override.d.ts.map +1 -1
  40. package/dist/config/key-parser.d.ts.map +1 -1
  41. package/dist/config/loader.d.ts.map +1 -1
  42. package/dist/config/schema.d.ts +3 -0
  43. package/dist/config/schema.d.ts.map +1 -1
  44. package/dist/features/check/checker.d.ts +19 -0
  45. package/dist/features/check/checker.d.ts.map +1 -0
  46. package/dist/features/check/crossref-client.d.ts +40 -0
  47. package/dist/features/check/crossref-client.d.ts.map +1 -0
  48. package/dist/features/check/fix-actions.d.ts +16 -0
  49. package/dist/features/check/fix-actions.d.ts.map +1 -0
  50. package/dist/features/check/fix-interaction.d.ts +11 -0
  51. package/dist/features/check/fix-interaction.d.ts.map +1 -0
  52. package/dist/features/check/metadata-comparator.d.ts +37 -0
  53. package/dist/features/check/metadata-comparator.d.ts.map +1 -0
  54. package/dist/features/check/metadata-similarity.d.ts +22 -0
  55. package/dist/features/check/metadata-similarity.d.ts.map +1 -0
  56. package/dist/features/check/pubmed-client.d.ts +20 -0
  57. package/dist/features/check/pubmed-client.d.ts.map +1 -0
  58. package/dist/features/check/types.d.ts +28 -0
  59. package/dist/features/check/types.d.ts.map +1 -0
  60. package/dist/features/operations/check.d.ts +29 -0
  61. package/dist/features/operations/check.d.ts.map +1 -0
  62. package/dist/features/operations/index.d.ts +1 -0
  63. package/dist/features/operations/index.d.ts.map +1 -1
  64. package/dist/features/operations/library-operations.d.ts +8 -0
  65. package/dist/features/operations/library-operations.d.ts.map +1 -1
  66. package/dist/features/operations/operations-library.d.ts +2 -0
  67. package/dist/features/operations/operations-library.d.ts.map +1 -1
  68. package/dist/index.js +1 -1
  69. package/dist/mcp/tools/check.d.ts +11 -0
  70. package/dist/mcp/tools/check.d.ts.map +1 -0
  71. package/dist/mcp/tools/index.d.ts.map +1 -1
  72. package/dist/server/index.d.ts.map +1 -1
  73. package/dist/server/routes/check.d.ts +4 -0
  74. package/dist/server/routes/check.d.ts.map +1 -0
  75. package/dist/server.js +3 -3
  76. package/package.json +1 -1
  77. package/dist/chunks/index-DWAtvFtp.js.map +0 -1
  78. package/dist/chunks/index-JA964gjc.js.map +0 -1
  79. package/dist/chunks/index-zafRwZEZ.js.map +0 -1
  80. package/dist/chunks/loader-CV71qNY2.js.map +0 -1
@@ -1,5 +1,5 @@
1
- import { a } from "./index-DWAtvFtp.js";
2
- import { d, g, l, o, s } from "./index-JA964gjc.js";
1
+ import { a } from "./index-of6eJn8N.js";
2
+ import { d, g, l, o, s } from "./index-BEQ4YIXx.js";
3
3
  export {
4
4
  a as addAttachment,
5
5
  d as detachAttachment,
@@ -8,4 +8,4 @@ export {
8
8
  o as openAttachment,
9
9
  s as syncAttachments
10
10
  };
11
- //# sourceMappingURL=index-zafRwZEZ.js.map
11
+ //# sourceMappingURL=index-k67fQbe4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-k67fQbe4.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
@@ -11342,6 +11342,12 @@ async function fetchIsbn(isbn) {
11342
11342
  };
11343
11343
  }
11344
11344
  }
11345
+ const fetcher = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
11346
+ __proto__: null,
11347
+ fetchDoi,
11348
+ fetchIsbn,
11349
+ fetchPmids
11350
+ }, Symbol.toStringTag, { value: "Module" }));
11345
11351
  function parseBibtex(content) {
11346
11352
  return parseWithCitationJs(content, "bibtex");
11347
11353
  }
@@ -12064,6 +12070,183 @@ function createAddRoute(library, config) {
12064
12070
  });
12065
12071
  return route;
12066
12072
  }
12073
+ const CHECK_CONCURRENCY = 5;
12074
+ async function checkReferences(library, options) {
12075
+ const { checkReference } = await import("./checker-CKfdG8Ia.js");
12076
+ const save = options.save !== false;
12077
+ const skipDays = options.skipDays ?? 7;
12078
+ const items = await resolveItems(library, options);
12079
+ const tasks = items.map((item, index) => ({
12080
+ index,
12081
+ item,
12082
+ skip: shouldSkipRecentCheck(item, skipDays)
12083
+ }));
12084
+ const results = new Array(items.length);
12085
+ fillSkippedResults(tasks, results);
12086
+ const toCheck = tasks.filter((t) => !t.skip);
12087
+ const checkConfig = {
12088
+ ...options.config,
12089
+ ...options.metadata !== void 0 ? { metadata: options.metadata } : {}
12090
+ };
12091
+ await checkInParallel(toCheck, results, checkReference, checkConfig);
12092
+ if (save) {
12093
+ await saveAllResults(library, toCheck, results);
12094
+ }
12095
+ return { results, summary: computeSummary(results) };
12096
+ }
12097
+ function fillSkippedResults(tasks, results) {
12098
+ for (const task of tasks) {
12099
+ if (task.skip) {
12100
+ results[task.index] = {
12101
+ id: task.item.id,
12102
+ uuid: task.item.custom?.uuid ?? "",
12103
+ status: "skipped",
12104
+ findings: [],
12105
+ checkedAt: task.item.custom?.check?.checked_at,
12106
+ checkedSources: []
12107
+ };
12108
+ }
12109
+ }
12110
+ }
12111
+ async function checkInParallel(tasks, results, checkFn, config) {
12112
+ for (let i = 0; i < tasks.length; i += CHECK_CONCURRENCY) {
12113
+ const chunk = tasks.slice(i, i + CHECK_CONCURRENCY);
12114
+ const settled = await Promise.allSettled(chunk.map((task) => checkFn(task.item, config)));
12115
+ for (const [j, task] of chunk.entries()) {
12116
+ const outcome = settled[j];
12117
+ results[task.index] = outcome?.status === "fulfilled" ? outcome.value : buildFallbackResult(task.item);
12118
+ }
12119
+ }
12120
+ }
12121
+ function buildFallbackResult(item) {
12122
+ return {
12123
+ id: item.id,
12124
+ uuid: item.custom?.uuid ?? "",
12125
+ status: "ok",
12126
+ findings: [],
12127
+ checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
12128
+ checkedSources: []
12129
+ };
12130
+ }
12131
+ async function saveAllResults(library, tasks, results) {
12132
+ for (const task of tasks) {
12133
+ const result = results[task.index];
12134
+ if (result.status !== "skipped") {
12135
+ await saveCheckResult(library, task.item, result);
12136
+ }
12137
+ }
12138
+ if (results.some((r) => r.status !== "skipped")) {
12139
+ await library.save();
12140
+ }
12141
+ }
12142
+ async function resolveItems(library, options) {
12143
+ if (options.all) {
12144
+ return library.getAll();
12145
+ }
12146
+ if (options.searchQuery) {
12147
+ const { searchReferences: searchReferences2 } = await Promise.resolve().then(() => search);
12148
+ const result = await searchReferences2(library, { query: options.searchQuery });
12149
+ return result.items;
12150
+ }
12151
+ if (options.identifiers && options.identifiers.length > 0) {
12152
+ const idType = options.idType ?? "id";
12153
+ const items = [];
12154
+ for (const identifier of options.identifiers) {
12155
+ const item = await library.find(identifier, { idType });
12156
+ if (!item) {
12157
+ throw new Error(`Reference not found: ${identifier}`);
12158
+ }
12159
+ items.push(item);
12160
+ }
12161
+ return items;
12162
+ }
12163
+ return [];
12164
+ }
12165
+ function shouldSkipRecentCheck(item, skipDays) {
12166
+ if (skipDays <= 0) return false;
12167
+ const check2 = item.custom?.check;
12168
+ if (!check2?.checked_at) return false;
12169
+ const checkedAt = new Date(check2.checked_at);
12170
+ const now = /* @__PURE__ */ new Date();
12171
+ const daysSince = (now.getTime() - checkedAt.getTime()) / (1e3 * 60 * 60 * 24);
12172
+ return daysSince < skipDays;
12173
+ }
12174
+ async function saveCheckResult(library, item, result) {
12175
+ const checkData = {
12176
+ checked_at: result.checkedAt,
12177
+ status: result.status === "warning" ? result.findings[0]?.type ?? "warning" : result.status,
12178
+ findings: result.findings.map((f) => ({
12179
+ type: f.type,
12180
+ message: f.message,
12181
+ ...f.details ? { details: snakeCaseKeys(f.details) } : {}
12182
+ }))
12183
+ };
12184
+ const existingCustom = item.custom ?? {};
12185
+ await library.update(item.id, {
12186
+ custom: { ...existingCustom, check: checkData }
12187
+ });
12188
+ }
12189
+ function snakeCaseKeys(obj) {
12190
+ const result = {};
12191
+ for (const [key, value] of Object.entries(obj)) {
12192
+ const snakeKey = key.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
12193
+ result[snakeKey] = value;
12194
+ }
12195
+ return result;
12196
+ }
12197
+ function computeSummary(results) {
12198
+ return {
12199
+ total: results.length,
12200
+ ok: results.filter((r) => r.status === "ok").length,
12201
+ warnings: results.filter((r) => r.status === "warning").length,
12202
+ skipped: results.filter((r) => r.status === "skipped").length
12203
+ };
12204
+ }
12205
+ const check = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
12206
+ __proto__: null,
12207
+ checkReferences
12208
+ }, Symbol.toStringTag, { value: "Module" }));
12209
+ const CheckRequestSchema = z.object({
12210
+ identifiers: z.array(z.string()).optional(),
12211
+ idType: z.enum(["id", "uuid"]).optional(),
12212
+ all: z.boolean().optional(),
12213
+ searchQuery: z.string().optional(),
12214
+ skipDays: z.number().optional(),
12215
+ save: z.boolean().optional(),
12216
+ metadata: z.boolean().optional()
12217
+ }).refine((data) => data.identifiers?.length || data.all || data.searchQuery, {
12218
+ message: "Must provide identifiers, all, or searchQuery"
12219
+ });
12220
+ function buildCheckOptions(data) {
12221
+ const options = {};
12222
+ if (data.identifiers?.length) options.identifiers = data.identifiers;
12223
+ if (data.idType) options.idType = data.idType;
12224
+ if (data.all) options.all = true;
12225
+ if (data.searchQuery) options.searchQuery = data.searchQuery;
12226
+ if (data.skipDays !== void 0) options.skipDays = data.skipDays;
12227
+ if (data.save !== void 0) options.save = data.save;
12228
+ if (data.metadata !== void 0) options.metadata = data.metadata;
12229
+ return options;
12230
+ }
12231
+ function createCheckRoute(library) {
12232
+ const route = new Hono();
12233
+ route.post("/", async (c) => {
12234
+ let rawBody;
12235
+ try {
12236
+ rawBody = await c.req.json();
12237
+ } catch {
12238
+ return c.json({ error: "Invalid JSON" }, 400);
12239
+ }
12240
+ const parseResult = CheckRequestSchema.safeParse(rawBody);
12241
+ if (!parseResult.success) {
12242
+ const errorMessage = parseResult.error.issues[0]?.message ?? "Invalid request body";
12243
+ return c.json({ error: errorMessage }, 400);
12244
+ }
12245
+ const result = await checkReferences(library, buildCheckOptions(parseResult.data));
12246
+ return c.json(result);
12247
+ });
12248
+ return route;
12249
+ }
12067
12250
  function shouldUseFallback(style, hasCustomXml) {
12068
12251
  if (hasCustomXml) {
12069
12252
  return false;
@@ -12506,6 +12689,8 @@ function createServer(library, config) {
12506
12689
  app.route("/api/list", listRoute);
12507
12690
  const searchRoute = createSearchRoute(library);
12508
12691
  app.route("/api/search", searchRoute);
12692
+ const checkRoute = createCheckRoute(library);
12693
+ app.route("/api/check", checkRoute);
12509
12694
  return app;
12510
12695
  }
12511
12696
  async function startServerWithFileWatcher(libraryPath, config) {
@@ -12534,34 +12719,37 @@ async function startServerWithFileWatcher(libraryPath, config) {
12534
12719
  };
12535
12720
  }
12536
12721
  export {
12537
- search as A,
12722
+ check as A,
12538
12723
  BUILTIN_STYLES as B,
12724
+ cite as C,
12725
+ list as D,
12726
+ search as E,
12539
12727
  RESERVED_ROLES as R,
12540
12728
  addAttachment as a,
12541
- findFulltextFiles as b,
12542
- findFulltextFile as c,
12729
+ generateFilename as b,
12730
+ findFulltextFiles as c,
12543
12731
  deleteDirectoryIfEmpty as d,
12544
12732
  ensureDirectory as e,
12545
12733
  formatBibliographyCSL as f,
12546
- generateFilename as g,
12547
- extensionToFormat as h,
12734
+ getRateLimiter as g,
12735
+ findFulltextFile as h,
12548
12736
  isReservedRole as i,
12549
- fulltextAttach as j,
12550
- fulltextGet as k,
12551
- fulltextDiscover as l,
12552
- fulltextFetch as m,
12737
+ extensionToFormat as j,
12738
+ fulltextAttach as k,
12739
+ fulltextGet as l,
12740
+ fulltextDiscover as m,
12553
12741
  normalizePathForOutput as n,
12554
- fulltextConvert as o,
12742
+ fulltextFetch as o,
12555
12743
  parseFilename as p,
12556
- getExtension as q,
12557
- getDefaultExportFromCjs as r,
12558
- getFulltextAttachmentTypes as s,
12559
- startServerWithFileWatcher as t,
12560
- createServer as u,
12561
- fetch$1 as v,
12562
- remove as w,
12563
- add as x,
12564
- cite as y,
12565
- list as z
12744
+ fulltextConvert as q,
12745
+ getExtension as r,
12746
+ getDefaultExportFromCjs as s,
12747
+ getFulltextAttachmentTypes as t,
12748
+ startServerWithFileWatcher as u,
12749
+ createServer as v,
12750
+ fetch$1 as w,
12751
+ remove as x,
12752
+ fetcher as y,
12753
+ add as z
12566
12754
  };
12567
- //# sourceMappingURL=index-DWAtvFtp.js.map
12755
+ //# sourceMappingURL=index-of6eJn8N.js.map