paper-manager 0.3.1 → 0.4.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 (44) hide show
  1. package/dist/ai/embed.test.d.ts +1 -0
  2. package/dist/ai/embed.test.js +93 -0
  3. package/dist/ai/embed.test.js.map +1 -0
  4. package/dist/commands/knowledge-base.js +10 -7
  5. package/dist/commands/knowledge-base.js.map +1 -1
  6. package/dist/commands/literature.js +25 -20
  7. package/dist/commands/literature.js.map +1 -1
  8. package/dist/config/index.d.ts +1 -1
  9. package/dist/config/index.js +2 -2
  10. package/dist/config/index.js.map +1 -1
  11. package/dist/config/index.test.d.ts +1 -0
  12. package/dist/config/index.test.js +143 -0
  13. package/dist/config/index.test.js.map +1 -0
  14. package/dist/config/init.d.ts +1 -1
  15. package/dist/config/init.js +24 -7
  16. package/dist/config/init.js.map +1 -1
  17. package/dist/config/init.test.d.ts +1 -0
  18. package/dist/config/init.test.js +61 -0
  19. package/dist/config/init.test.js.map +1 -0
  20. package/dist/db/index.test.d.ts +1 -0
  21. package/dist/db/index.test.js +79 -0
  22. package/dist/db/index.test.js.map +1 -0
  23. package/dist/db/operations/knowledge-bases.test.d.ts +1 -0
  24. package/dist/db/operations/knowledge-bases.test.js +73 -0
  25. package/dist/db/operations/knowledge-bases.test.js.map +1 -0
  26. package/dist/db/operations/literatures.test.d.ts +1 -0
  27. package/dist/db/operations/literatures.test.js +159 -0
  28. package/dist/db/operations/literatures.test.js.map +1 -0
  29. package/dist/db/test-utils.d.ts +6 -0
  30. package/dist/db/test-utils.js +14 -0
  31. package/dist/db/test-utils.js.map +1 -0
  32. package/dist/extractor/index.d.ts +5 -0
  33. package/dist/extractor/index.js +23 -0
  34. package/dist/extractor/index.js.map +1 -0
  35. package/dist/extractor/pdf.d.ts +2 -0
  36. package/dist/extractor/pdf.js +18 -0
  37. package/dist/extractor/pdf.js.map +1 -0
  38. package/dist/extractor/text.d.ts +2 -0
  39. package/dist/extractor/text.js +17 -0
  40. package/dist/extractor/text.js.map +1 -0
  41. package/dist/types/index.test.d.ts +1 -0
  42. package/dist/types/index.test.js +157 -0
  43. package/dist/types/index.test.js.map +1 -0
  44. package/package.json +7 -3
@@ -0,0 +1,61 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
4
+ import { getFilesDir, getProjectDataDir, getVectorStoreDir } from "./index.js";
5
+ import { initScope } from "./init.js";
6
+ // initScope() uses getProjectDataDir() which is a module-level constant resolved at import time.
7
+ // This means process.chdir() cannot redirect it. We must clean up the actual project data dir
8
+ // between tests to ensure isolation.
9
+ let origCwd;
10
+ beforeEach(() => {
11
+ origCwd = process.cwd();
12
+ const projectDir = getProjectDataDir();
13
+ if (fs.existsSync(projectDir)) {
14
+ fs.rmSync(projectDir, { recursive: true, force: true });
15
+ }
16
+ });
17
+ afterEach(() => {
18
+ process.chdir(origCwd);
19
+ const projectDir = getProjectDataDir();
20
+ if (fs.existsSync(projectDir)) {
21
+ fs.rmSync(projectDir, { recursive: true, force: true });
22
+ }
23
+ });
24
+ describe("initScope (project scope)", () => {
25
+ it("creates all expected files and directories on first run", () => {
26
+ const result = initScope();
27
+ const baseDir = result.baseDir;
28
+ // All items should be "created"
29
+ expect(result.items.every((item) => item.status === "created")).toBe(true);
30
+ expect(result.items).toHaveLength(5);
31
+ // Verify filesystem
32
+ expect(fs.existsSync(baseDir)).toBe(true);
33
+ expect(fs.existsSync(path.join(baseDir, "config.json"))).toBe(true);
34
+ expect(fs.existsSync(path.join(baseDir, "papers.db"))).toBe(true);
35
+ expect(fs.existsSync(getFilesDir(baseDir))).toBe(true);
36
+ expect(fs.existsSync(getVectorStoreDir(baseDir))).toBe(true);
37
+ });
38
+ it("config.json contains $schema field", () => {
39
+ const result = initScope();
40
+ const configContent = fs.readFileSync(path.join(result.baseDir, "config.json"), "utf-8");
41
+ const config = JSON.parse(configContent);
42
+ expect(config["$schema"]).toContain("config.schema.json");
43
+ });
44
+ it("is idempotent — second run reports all items as exists", () => {
45
+ initScope();
46
+ const result = initScope();
47
+ expect(result.items.every((item) => item.status === "exists")).toBe(true);
48
+ expect(result.items).toHaveLength(5);
49
+ });
50
+ it("preserves existing config.json content on second run", () => {
51
+ const result = initScope();
52
+ const configPath = path.join(result.baseDir, "config.json");
53
+ // Write custom content
54
+ fs.writeFileSync(configPath, JSON.stringify({ custom: "data" }));
55
+ // Second init should not overwrite
56
+ initScope();
57
+ const content = JSON.parse(fs.readFileSync(configPath, "utf-8"));
58
+ expect(content["custom"]).toBe("data");
59
+ });
60
+ });
61
+ //# sourceMappingURL=init.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.test.js","sourceRoot":"","sources":["../../src/config/init.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,79 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { dbRowToKnowledgeBase, dbRowToLiterature, isRecord } from "./index.js";
3
+ // ─── isRecord ────────────────────────────────────────────────
4
+ describe("isRecord", () => {
5
+ it("returns true for plain objects", () => {
6
+ expect(isRecord({})).toBe(true);
7
+ expect(isRecord({ a: 1 })).toBe(true);
8
+ });
9
+ it("returns false for arrays", () => {
10
+ expect(isRecord([])).toBe(false);
11
+ expect(isRecord([1, 2])).toBe(false);
12
+ });
13
+ it("returns false for primitives and null", () => {
14
+ expect(isRecord(null)).toBe(false);
15
+ expect(isRecord(undefined)).toBe(false);
16
+ expect(isRecord(42)).toBe(false);
17
+ expect(isRecord("string")).toBe(false);
18
+ expect(isRecord(true)).toBe(false);
19
+ });
20
+ });
21
+ // ─── dbRowToKnowledgeBase ────────────────────────────────────
22
+ describe("dbRowToKnowledgeBase", () => {
23
+ const validRow = {
24
+ id: "550e8400-e29b-41d4-a716-446655440000",
25
+ name: "Test KB",
26
+ description: "A description",
27
+ embedding_model_id: "model-1",
28
+ created_at: 1700000000000,
29
+ updated_at: 1700000000000,
30
+ };
31
+ it("converts a valid DB row to KnowledgeBaseMetadata", () => {
32
+ const result = dbRowToKnowledgeBase(validRow);
33
+ expect(result.id).toBe(validRow.id);
34
+ expect(result.name).toBe("Test KB");
35
+ expect(result.embeddingModelId).toBe("model-1");
36
+ expect(result.createdAt).toBeInstanceOf(Date);
37
+ expect(result.createdAt.getTime()).toBe(1700000000000);
38
+ });
39
+ it("throws on non-object input", () => {
40
+ expect(() => dbRowToKnowledgeBase(null)).toThrow("Invalid database row");
41
+ expect(() => dbRowToKnowledgeBase("string")).toThrow("Invalid database row");
42
+ expect(() => dbRowToKnowledgeBase([])).toThrow("Invalid database row");
43
+ });
44
+ });
45
+ // ─── dbRowToLiterature ───────────────────────────────────────
46
+ describe("dbRowToLiterature", () => {
47
+ const validRow = {
48
+ id: "550e8400-e29b-41d4-a716-446655440000",
49
+ title: "A Paper",
50
+ title_translation: null,
51
+ author: "Alice",
52
+ abstract: "This paper...",
53
+ summary: null,
54
+ keywords: '["ai","ml"]',
55
+ url: null,
56
+ notes: '{"read":"yes"}',
57
+ knowledge_base_id: "550e8400-e29b-41d4-a716-446655440000",
58
+ created_at: 1700000000000,
59
+ updated_at: 1700000000000,
60
+ };
61
+ it("converts a valid DB row with JSON fields", () => {
62
+ const result = dbRowToLiterature(validRow);
63
+ expect(result.title).toBe("A Paper");
64
+ expect(result.author).toBe("Alice");
65
+ expect(result.keywords).toEqual(["ai", "ml"]);
66
+ expect(result.notes).toEqual({ read: "yes" });
67
+ expect(result.knowledgeBaseId).toBe(validRow.knowledge_base_id);
68
+ });
69
+ it("handles missing keywords/notes with defaults", () => {
70
+ const row = { ...validRow, keywords: undefined, notes: undefined };
71
+ const result = dbRowToLiterature(row);
72
+ expect(result.keywords).toEqual([]);
73
+ expect(result.notes).toEqual({});
74
+ });
75
+ it("throws on non-object input", () => {
76
+ expect(() => dbRowToLiterature(42)).toThrow("Invalid database row");
77
+ });
78
+ });
79
+ //# sourceMappingURL=index.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../src/db/index.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,73 @@
1
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
2
+ import { createTestDb } from "../test-utils.js";
3
+ import { createKnowledgeBase, deleteKnowledgeBase, getKnowledgeBase, listKnowledgeBases, } from "./knowledge-bases.js";
4
+ let db;
5
+ beforeEach(() => {
6
+ db = createTestDb();
7
+ });
8
+ afterEach(() => {
9
+ db.close();
10
+ });
11
+ const input = {
12
+ name: "Test KB",
13
+ description: "A test knowledge base",
14
+ embeddingModelId: "model-1",
15
+ };
16
+ // ─── createKnowledgeBase ─────────────────────────────────────
17
+ describe("createKnowledgeBase", () => {
18
+ it("creates and returns a knowledge base with generated id and timestamps", () => {
19
+ const kb = createKnowledgeBase(db, input);
20
+ expect(kb.id).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/);
21
+ expect(kb.name).toBe("Test KB");
22
+ expect(kb.description).toBe("A test knowledge base");
23
+ expect(kb.embeddingModelId).toBe("model-1");
24
+ expect(kb.createdAt).toBeInstanceOf(Date);
25
+ expect(kb.updatedAt).toBeInstanceOf(Date);
26
+ });
27
+ it("rejects duplicate names due to UNIQUE constraint", () => {
28
+ createKnowledgeBase(db, input);
29
+ expect(() => createKnowledgeBase(db, input)).toThrow();
30
+ });
31
+ });
32
+ // ─── getKnowledgeBase ────────────────────────────────────────
33
+ describe("getKnowledgeBase", () => {
34
+ it("returns the knowledge base by id", () => {
35
+ const created = createKnowledgeBase(db, input);
36
+ const found = getKnowledgeBase(db, created.id);
37
+ expect(found).not.toBeNull();
38
+ expect(found.id).toBe(created.id);
39
+ expect(found.name).toBe("Test KB");
40
+ });
41
+ it("returns null for non-existent id", () => {
42
+ expect(getKnowledgeBase(db, "non-existent")).toBeNull();
43
+ });
44
+ });
45
+ // ─── listKnowledgeBases ──────────────────────────────────────
46
+ describe("listKnowledgeBases", () => {
47
+ it("returns an empty array when no knowledge bases exist", () => {
48
+ expect(listKnowledgeBases(db)).toEqual([]);
49
+ });
50
+ it("returns knowledge bases ordered by created_at DESC", () => {
51
+ const kb1 = createKnowledgeBase(db, { ...input, name: "First" });
52
+ // Manually backdate kb1 so ordering is deterministic
53
+ db.prepare("UPDATE knowledge_bases SET created_at = created_at - 1000 WHERE id = ?").run(kb1.id);
54
+ const kb2 = createKnowledgeBase(db, { ...input, name: "Second" });
55
+ const list = listKnowledgeBases(db);
56
+ expect(list).toHaveLength(2);
57
+ // Second was created after First, so it should come first in DESC order
58
+ expect(list[0].id).toBe(kb2.id);
59
+ expect(list[1].id).toBe(kb1.id);
60
+ });
61
+ });
62
+ // ─── deleteKnowledgeBase ─────────────────────────────────────
63
+ describe("deleteKnowledgeBase", () => {
64
+ it("deletes an existing knowledge base and returns true", () => {
65
+ const kb = createKnowledgeBase(db, input);
66
+ expect(deleteKnowledgeBase(db, kb.id)).toBe(true);
67
+ expect(getKnowledgeBase(db, kb.id)).toBeNull();
68
+ });
69
+ it("returns false for non-existent id", () => {
70
+ expect(deleteKnowledgeBase(db, "non-existent")).toBe(false);
71
+ });
72
+ });
73
+ //# sourceMappingURL=knowledge-bases.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"knowledge-bases.test.js","sourceRoot":"","sources":["../../../src/db/operations/knowledge-bases.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,159 @@
1
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
2
+ import { createTestDb } from "../test-utils.js";
3
+ import { createKnowledgeBase } from "./knowledge-bases.js";
4
+ import { createLiterature, deleteLiterature, deleteLiteraturesByKnowledgeBaseId, getLiterature, listLiteratures, updateLiterature, } from "./literatures.js";
5
+ let db;
6
+ let kbId;
7
+ beforeEach(() => {
8
+ db = createTestDb();
9
+ // Every literature needs a knowledge base
10
+ const kb = createKnowledgeBase(db, {
11
+ name: "Test KB",
12
+ description: "test",
13
+ embeddingModelId: "model-1",
14
+ });
15
+ kbId = kb.id;
16
+ });
17
+ afterEach(() => {
18
+ db.close();
19
+ });
20
+ function makeInput(overrides) {
21
+ return {
22
+ title: "A Paper",
23
+ titleTranslation: null,
24
+ author: "Alice",
25
+ abstract: "This paper explores...",
26
+ summary: null,
27
+ keywords: ["ai", "ml"],
28
+ url: null,
29
+ notes: { read: "yes" },
30
+ knowledgeBaseId: kbId,
31
+ ...overrides,
32
+ };
33
+ }
34
+ // ─── createLiterature ────────────────────────────────────────
35
+ describe("createLiterature", () => {
36
+ it("creates a literature with generated id and timestamps", () => {
37
+ const lit = createLiterature(db, makeInput());
38
+ expect(lit.id).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/);
39
+ expect(lit.title).toBe("A Paper");
40
+ expect(lit.author).toBe("Alice");
41
+ expect(lit.knowledgeBaseId).toBe(kbId);
42
+ });
43
+ it("round-trips JSON fields (keywords and notes)", () => {
44
+ const lit = createLiterature(db, makeInput({
45
+ keywords: ["deep learning", "transformer"],
46
+ notes: { chapter1: "interesting", chapter2: "review" },
47
+ }));
48
+ expect(lit.keywords).toEqual(["deep learning", "transformer"]);
49
+ expect(lit.notes).toEqual({ chapter1: "interesting", chapter2: "review" });
50
+ });
51
+ it("handles empty keywords and notes", () => {
52
+ const lit = createLiterature(db, makeInput({ keywords: [], notes: {} }));
53
+ expect(lit.keywords).toEqual([]);
54
+ expect(lit.notes).toEqual({});
55
+ });
56
+ });
57
+ // ─── getLiterature ───────────────────────────────────────────
58
+ describe("getLiterature", () => {
59
+ it("returns the literature by id", () => {
60
+ const created = createLiterature(db, makeInput());
61
+ const found = getLiterature(db, created.id);
62
+ expect(found).not.toBeNull();
63
+ expect(found.title).toBe("A Paper");
64
+ });
65
+ it("returns null for non-existent id", () => {
66
+ expect(getLiterature(db, "non-existent")).toBeNull();
67
+ });
68
+ });
69
+ // ─── listLiteratures ─────────────────────────────────────────
70
+ describe("listLiteratures", () => {
71
+ it("returns only literatures belonging to the given KB", () => {
72
+ const kb2 = createKnowledgeBase(db, {
73
+ name: "Other KB",
74
+ description: "other",
75
+ embeddingModelId: "model-1",
76
+ });
77
+ createLiterature(db, makeInput({ title: "Paper A" }));
78
+ createLiterature(db, makeInput({ title: "Paper B", knowledgeBaseId: kb2.id }));
79
+ const list = listLiteratures(db, kbId);
80
+ expect(list).toHaveLength(1);
81
+ expect(list[0].title).toBe("Paper A");
82
+ });
83
+ it("returns an empty array for a KB with no literatures", () => {
84
+ expect(listLiteratures(db, kbId)).toEqual([]);
85
+ });
86
+ });
87
+ // ─── updateLiterature ────────────────────────────────────────
88
+ describe("updateLiterature", () => {
89
+ it("updates only the specified fields", () => {
90
+ const lit = createLiterature(db, makeInput());
91
+ const updated = updateLiterature(db, lit.id, { title: "New Title" });
92
+ expect(updated).not.toBeNull();
93
+ expect(updated.title).toBe("New Title");
94
+ // Other fields stay unchanged
95
+ expect(updated.author).toBe("Alice");
96
+ expect(updated.keywords).toEqual(["ai", "ml"]);
97
+ });
98
+ it("updates JSON fields correctly", () => {
99
+ const lit = createLiterature(db, makeInput());
100
+ const updated = updateLiterature(db, lit.id, {
101
+ keywords: ["new-tag"],
102
+ notes: { updated: "true" },
103
+ });
104
+ expect(updated.keywords).toEqual(["new-tag"]);
105
+ expect(updated.notes).toEqual({ updated: "true" });
106
+ });
107
+ it("advances updatedAt on update", () => {
108
+ const lit = createLiterature(db, makeInput());
109
+ const updated = updateLiterature(db, lit.id, { title: "Changed" });
110
+ expect(updated.updatedAt.getTime()).toBeGreaterThanOrEqual(lit.updatedAt.getTime());
111
+ });
112
+ it("returns the original when input is empty (no fields to update)", () => {
113
+ const lit = createLiterature(db, makeInput());
114
+ const unchanged = updateLiterature(db, lit.id, {});
115
+ expect(unchanged).not.toBeNull();
116
+ expect(unchanged.title).toBe(lit.title);
117
+ expect(unchanged.updatedAt.getTime()).toBe(lit.updatedAt.getTime());
118
+ });
119
+ it("returns null for non-existent id", () => {
120
+ expect(updateLiterature(db, "non-existent", { title: "X" })).toBeNull();
121
+ });
122
+ });
123
+ // ─── deleteLiterature ────────────────────────────────────────
124
+ describe("deleteLiterature", () => {
125
+ it("deletes an existing literature and returns true", () => {
126
+ const lit = createLiterature(db, makeInput());
127
+ expect(deleteLiterature(db, lit.id)).toBe(true);
128
+ expect(getLiterature(db, lit.id)).toBeNull();
129
+ });
130
+ it("returns false for non-existent id", () => {
131
+ expect(deleteLiterature(db, "non-existent")).toBe(false);
132
+ });
133
+ });
134
+ // ─── deleteLiteraturesByKnowledgeBaseId ──────────────────────
135
+ describe("deleteLiteraturesByKnowledgeBaseId", () => {
136
+ it("deletes all literatures in a KB and returns the count", () => {
137
+ createLiterature(db, makeInput({ title: "Paper 1" }));
138
+ createLiterature(db, makeInput({ title: "Paper 2" }));
139
+ expect(deleteLiteraturesByKnowledgeBaseId(db, kbId)).toBe(2);
140
+ expect(listLiteratures(db, kbId)).toEqual([]);
141
+ });
142
+ it("returns 0 when the KB has no literatures", () => {
143
+ expect(deleteLiteraturesByKnowledgeBaseId(db, kbId)).toBe(0);
144
+ });
145
+ });
146
+ // ─── Foreign Key Behavior ────────────────────────────────────
147
+ describe("foreign key: ON DELETE SET NULL", () => {
148
+ it("sets knowledge_base_id to null when KB is deleted", () => {
149
+ const lit = createLiterature(db, makeInput());
150
+ // Delete the KB directly via SQL to trigger FK cascade
151
+ db.prepare("DELETE FROM knowledge_bases WHERE id = ?").run(kbId);
152
+ // getLiterature() will throw because Zod schema requires knowledgeBaseId to be a UUID,
153
+ // but FK cascade sets it to NULL. Check the raw row instead.
154
+ const raw = db.prepare("SELECT knowledge_base_id FROM literatures WHERE id = ?").get(lit.id);
155
+ expect(raw).toBeDefined();
156
+ expect(raw["knowledge_base_id"]).toBeNull();
157
+ });
158
+ });
159
+ //# sourceMappingURL=literatures.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"literatures.test.js","sourceRoot":"","sources":["../../../src/db/operations/literatures.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type BetterSqlite3 from "better-sqlite3";
2
+ /**
3
+ * Creates an in-memory SQLite database with the schema initialized.
4
+ * Each call returns a fresh, isolated database instance.
5
+ */
6
+ export declare function createTestDb(): BetterSqlite3.Database;
@@ -0,0 +1,14 @@
1
+ import Database from "better-sqlite3";
2
+ import { initializeDatabase } from "./index.js";
3
+ /**
4
+ * Creates an in-memory SQLite database with the schema initialized.
5
+ * Each call returns a fresh, isolated database instance.
6
+ */
7
+ export function createTestDb() {
8
+ const db = new Database(":memory:");
9
+ db.pragma("journal_mode = WAL");
10
+ db.pragma("foreign_keys = ON");
11
+ initializeDatabase(db);
12
+ return db;
13
+ }
14
+ //# sourceMappingURL=test-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-utils.js","sourceRoot":"","sources":["../../src/db/test-utils.ts"],"names":[],"mappings":"AACA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAEtC,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEhD;;;GAGG;AACH,MAAM,UAAU,YAAY;IAC1B,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,UAAU,CAAC,CAAC;IACpC,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAChC,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAC/B,kBAAkB,CAAC,EAAE,CAAC,CAAC;IACvB,OAAO,EAAE,CAAC;AACZ,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { Document } from "@langchain/core/documents";
2
+ import { extractPdfContent } from "./pdf.js";
3
+ import { extractTextContent } from "./text.js";
4
+ export { extractPdfContent, extractTextContent };
5
+ export declare function extractContent(filePath: string): Promise<Document[]>;
@@ -0,0 +1,23 @@
1
+ import mime from "mime-types";
2
+ import { extractPdfContent } from "./pdf.js";
3
+ import { extractTextContent } from "./text.js";
4
+ export { extractPdfContent, extractTextContent };
5
+ const TEXT_LIKE_MIME_TYPES = new Set([
6
+ "application/x-tex",
7
+ "application/x-latex",
8
+ ]);
9
+ function isTextLike(mimeType) {
10
+ return mimeType.startsWith("text/") || TEXT_LIKE_MIME_TYPES.has(mimeType);
11
+ }
12
+ export async function extractContent(filePath) {
13
+ const mimeType = mime.lookup(filePath);
14
+ if (mimeType === "application/pdf") {
15
+ return extractPdfContent(filePath);
16
+ }
17
+ if (typeof mimeType === "string" && isTextLike(mimeType)) {
18
+ return extractTextContent(filePath);
19
+ }
20
+ const ext = filePath.split(".").pop() ?? "unknown";
21
+ throw new Error(`Unsupported file type: .${ext} (${String(mimeType)})`);
22
+ }
23
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/extractor/index.ts"],"names":[],"mappings":"AACA,OAAO,IAAI,MAAM,YAAY,CAAC;AAE9B,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAE/C,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,CAAC;AAEjD,MAAM,oBAAoB,GAAwB,IAAI,GAAG,CAAC;IACxD,mBAAmB;IACnB,qBAAqB;CACtB,CAAC,CAAC;AAEH,SAAS,UAAU,CAAC,QAAgB;IAClC,OAAO,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,QAAgB;IACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAEvC,IAAI,QAAQ,KAAK,iBAAiB,EAAE,CAAC;QACnC,OAAO,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IACrC,CAAC;IAED,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzD,OAAO,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IACtC,CAAC;IAED,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,SAAS,CAAC;IACnD,MAAM,IAAI,KAAK,CAAC,2BAA2B,GAAG,KAAK,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AAC1E,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Document } from "@langchain/core/documents";
2
+ export declare function extractPdfContent(pdfPath: string): Promise<Document[]>;
@@ -0,0 +1,18 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { Document } from "@langchain/core/documents";
3
+ import { PDFParse } from "pdf-parse";
4
+ export async function extractPdfContent(pdfPath) {
5
+ const data = await readFile(pdfPath);
6
+ const parser = new PDFParse({ data });
7
+ const result = await parser.getText();
8
+ await parser.destroy();
9
+ return result.pages.map((page) => new Document({
10
+ pageContent: page.text,
11
+ metadata: {
12
+ source: pdfPath,
13
+ pdf: { totalPages: result.total },
14
+ loc: { pageNumber: page.num },
15
+ },
16
+ }));
17
+ }
18
+ //# sourceMappingURL=pdf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdf.js","sourceRoot":"","sources":["../../src/extractor/pdf.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,OAAe;IACrD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,CAAC;IACrC,MAAM,MAAM,GAAG,IAAI,QAAQ,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;IACtC,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;IAEvB,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,CACrB,CAAC,IAAI,EAAE,EAAE,CACP,IAAI,QAAQ,CAAC;QACX,WAAW,EAAE,IAAI,CAAC,IAAI;QACtB,QAAQ,EAAE;YACR,MAAM,EAAE,OAAO;YACf,GAAG,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,KAAK,EAAE;YACjC,GAAG,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE;SAC9B;KACF,CAAC,CACL,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Document } from "@langchain/core/documents";
2
+ export declare function extractTextContent(filePath: string): Promise<Document[]>;
@@ -0,0 +1,17 @@
1
+ import { readFile, stat } from "node:fs/promises";
2
+ import { Document } from "@langchain/core/documents";
3
+ const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10 MB
4
+ export async function extractTextContent(filePath) {
5
+ const fileStats = await stat(filePath);
6
+ if (fileStats.size > MAX_FILE_SIZE) {
7
+ throw new Error(`File too large: ${String(Math.round(fileStats.size / 1024 / 1024))} MB exceeds the 10 MB limit`);
8
+ }
9
+ const content = await readFile(filePath, "utf-8");
10
+ return [
11
+ new Document({
12
+ pageContent: content,
13
+ metadata: { source: filePath },
14
+ }),
15
+ ];
16
+ }
17
+ //# sourceMappingURL=text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/extractor/text.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAErD,MAAM,aAAa,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,QAAQ;AAEhD,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,QAAgB;IACvD,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC;IACvC,IAAI,SAAS,CAAC,IAAI,GAAG,aAAa,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CACb,mBAAmB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,6BAA6B,CACjG,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAClD,OAAO;QACL,IAAI,QAAQ,CAAC;YACX,WAAW,EAAE,OAAO;YACpB,QAAQ,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;SAC/B,CAAC;KACH,CAAC;AACJ,CAAC"}
@@ -0,0 +1 @@
1
+ export {};