@chronicle.app/zotero 0.3.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.
@@ -0,0 +1,175 @@
1
+ /**
2
+ * The raw-record contract between ZoteroExtractor and ZoteroTransformer.
3
+ *
4
+ * The extractor walks the `items` spine of `zotero.sqlite` (Zotero 7 schema)
5
+ * and emits four record types, each a self-contained denormalization of the
6
+ * joins the transformer needs — the transformer never touches the database.
7
+ *
8
+ * All `dateAdded`/`dateModified` values are Zotero's UTC `YYYY-MM-DD HH:MM:SS`
9
+ * strings, passed through verbatim.
10
+ */
11
+ /** One creator row from `itemCreators` → `creators` → `creatorTypes`. */
12
+ export interface ZoteroCreator {
13
+ firstName: string | null;
14
+ lastName: string | null;
15
+ /** 0 = two-field (person), 1 = single-field (institution; name in lastName). */
16
+ fieldMode: number;
17
+ /** Zotero role: author, editor, translator, contributor, seriesEditor, … */
18
+ creatorType: string;
19
+ orderIndex: number;
20
+ }
21
+ /** A collection with its ancestor chain resolved (root has no parent). */
22
+ export interface ZoteroCollection {
23
+ /** 8-char collection key — the collection's sourceId. */
24
+ key: string;
25
+ name: string;
26
+ parent?: ZoteroCollection;
27
+ }
28
+ export interface ZoteroTag {
29
+ name: string;
30
+ /** 0 = manual, 1 = automatic. */
31
+ type: number;
32
+ }
33
+ /** An attachment row (child of a work, or standalone when orphaned). */
34
+ export interface ZoteroAttachment {
35
+ /** 8-char item key — the attachment's sourceId and its storage folder name. */
36
+ key: string;
37
+ /** 0 imported file, 1 imported url snapshot, 2 linked file, 3 linked url. */
38
+ linkMode: number;
39
+ contentType: string | null;
40
+ /** Raw `itemAttachments.path` (e.g. `storage:Paper.pdf`), if any. */
41
+ path: string | null;
42
+ /**
43
+ * Absolute path to the file on disk, resolved by the extractor:
44
+ * `storage:` paths resolve to `{dataDir}/storage/{key}/{filename}`; linked
45
+ * files (linkMode 2) pass through their absolute path. Unresolvable
46
+ * (linked-url, relative linked) attachments leave this unset.
47
+ */
48
+ resolvedPath?: string;
49
+ /** The attachment item's own `title` field, when set. */
50
+ title?: string;
51
+ /** The attachment item's own `url` field (linked-url and snapshot sources). */
52
+ url?: string;
53
+ /** Unix seconds of the last open in the Zotero reader, when recorded. */
54
+ lastRead?: number;
55
+ /**
56
+ * Set when this attachment's carrier (its resolved path, or its file's
57
+ * content hash) also appears under a DIFFERENT parent work — e.g. one
58
+ * anthology PDF attached to several chapter items. A shared carrier cannot
59
+ * witness a single work, so the transformer withholds its carrier merge
60
+ * edges (filesystem `sameAs`, `contentPath`) to keep distinct works from
61
+ * welding through the shared file. Orphans never set this.
62
+ */
63
+ sharedCarrier?: boolean;
64
+ dateAdded: string;
65
+ }
66
+ /**
67
+ * `work` record — a top-level reference item (journalArticle, book, …) with
68
+ * its EAV fields reconstructed and creators/collections/tags/attachments
69
+ * joined in.
70
+ */
71
+ export interface ZoteroWorkRecord {
72
+ /** 8-char item key — the work's sourceId. */
73
+ key: string;
74
+ /** Zotero item type name: journalArticle, book, bookSection, preprint, … */
75
+ itemType: string;
76
+ dateAdded: string;
77
+ dateModified: string;
78
+ /**
79
+ * The work's fields from the `itemData` EAV join, keyed by Zotero field
80
+ * name (title, abstractNote, date, publisher, numPages, url, DOI, ISBN,
81
+ * ISSN, publicationTitle, series, …), values verbatim.
82
+ */
83
+ fields: {
84
+ [fieldName: string]: string;
85
+ };
86
+ creators: ZoteroCreator[];
87
+ collections: ZoteroCollection[];
88
+ tags: ZoteroTag[];
89
+ attachments: ZoteroAttachment[];
90
+ }
91
+ /** Slim parent-work context carried on annotation records. */
92
+ export interface ZoteroWorkRef {
93
+ key: string;
94
+ itemType: string;
95
+ title?: string;
96
+ }
97
+ /**
98
+ * `annotation` record — one row of `itemAnnotations` (a highlight, underline,
99
+ * or note made in the Zotero reader) with its attachment and work context.
100
+ */
101
+ export interface ZoteroAnnotationRecord {
102
+ /** 8-char item key of the annotation — its sourceId. */
103
+ key: string;
104
+ /** Zotero annotation type: 1 highlight, 2 note, 3 image, 4 ink, 5 underline, 6 text. */
105
+ type: number;
106
+ /** The highlighted passage, if any. */
107
+ text: string | null;
108
+ /** The user's note on the annotation, if any. */
109
+ comment: string | null;
110
+ /** Highlight color as hex, e.g. `#ffd400`. */
111
+ color: string | null;
112
+ /** Human page label, e.g. `1412` (PDF only). */
113
+ pageLabel: string | null;
114
+ sortIndex: string;
115
+ /**
116
+ * Raw `position` JSON. PDF: `{"pageIndex":0,"rects":[…]}`. EPUB:
117
+ * `{"type":"FragmentSelector","value":"epubcfi(…)"}`.
118
+ */
119
+ position: string;
120
+ /** 1 when the annotation was embedded in the file rather than made in Zotero. */
121
+ isExternal: number;
122
+ /** Author of the annotation in group contexts; null for the local user. */
123
+ authorName: string | null;
124
+ dateAdded: string;
125
+ dateModified: string;
126
+ /** The attachment the annotation lives in. */
127
+ attachment: ZoteroAttachment;
128
+ /** The attachment's parent work; absent for annotations on orphan attachments. */
129
+ work?: ZoteroWorkRef;
130
+ }
131
+ /**
132
+ * `attachment` record — an orphan attachment (no parent work): a standalone
133
+ * file saved directly to the library.
134
+ */
135
+ export interface ZoteroOrphanAttachmentRecord extends ZoteroAttachment {
136
+ dateModified: string;
137
+ tags: ZoteroTag[];
138
+ collections: ZoteroCollection[];
139
+ }
140
+ /**
141
+ * `note` record — a Zotero note item: an HTML note written on a work (child
142
+ * note) or standing alone in the library.
143
+ */
144
+ export interface ZoteroNoteRecord {
145
+ /** 8-char item key of the note — its sourceId. */
146
+ key: string;
147
+ /** Zotero's derived display title (the note's first line). */
148
+ title: string | null;
149
+ /** The note body, verbatim Zotero HTML. */
150
+ note: string;
151
+ dateAdded: string;
152
+ dateModified: string;
153
+ /** The parent work; absent for standalone notes. */
154
+ work?: ZoteroWorkRef;
155
+ }
156
+ /** Per-record context: the library's identity, its owner, and this machine. */
157
+ export interface ZoteroContext {
158
+ recordType: 'works' | 'annotations' | 'attachments' | 'notes';
159
+ /** `settings.account.localUserKey` — present even without a zotero.org account. */
160
+ localUserKey: string;
161
+ /**
162
+ * The library's scope handle — the `inRealm` disambiguator for item-keyed
163
+ * entities, since Zotero item keys are only per-library unique. The
164
+ * zotero.org `userID` when the library has synced (globally stable, the same
165
+ * on every machine), else the `localUserKey`.
166
+ */
167
+ library: string;
168
+ /**
169
+ * The normalized short name of the machine this library lives on
170
+ * (`SystemInfo.getMachineName()`) — the `inRealm` scope for
171
+ * filesystem-keyed file identities, matching the timing/shell realm.
172
+ */
173
+ machine: string;
174
+ }
175
+ //# sourceMappingURL=records.d.ts.map
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The raw-record contract between ZoteroExtractor and ZoteroTransformer.
3
+ *
4
+ * The extractor walks the `items` spine of `zotero.sqlite` (Zotero 7 schema)
5
+ * and emits four record types, each a self-contained denormalization of the
6
+ * joins the transformer needs — the transformer never touches the database.
7
+ *
8
+ * All `dateAdded`/`dateModified` values are Zotero's UTC `YYYY-MM-DD HH:MM:SS`
9
+ * strings, passed through verbatim.
10
+ */
11
+ export {};
@@ -0,0 +1,3 @@
1
+ export { ZoteroExtractor } from './connectors/ZoteroExtractor.js';
2
+ export { default as ZoteroTransformer } from './connectors/ZoteroTransformer.js';
3
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { ZoteroExtractor } from './connectors/ZoteroExtractor.js';
2
+ export { default as ZoteroTransformer } from './connectors/ZoteroTransformer.js';
package/package.json ADDED
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "@chronicle.app/zotero",
3
+ "version": "0.3.0",
4
+ "main": "./dist/index.js",
5
+ "types": "./dist/index.d.ts",
6
+ "files": [
7
+ "dist/**/*.js",
8
+ "dist/**/*.d.ts"
9
+ ],
10
+ "scripts": {
11
+ "build": "tsc -b tsconfig.lib.json",
12
+ "typecheck": "tsc -p tsconfig.json",
13
+ "lint": "eslint src --ext .ts,.js",
14
+ "test": "node --test src/*.test.js"
15
+ },
16
+ "keywords": [
17
+ "chronicle",
18
+ "zotero"
19
+ ],
20
+ "author": "Andrew Louis",
21
+ "license": "MIT",
22
+ "type": "module",
23
+ "description": "Chronicle plugin for a local Zotero library: works, highlights, notes, and reading events",
24
+ "devDependencies": {
25
+ "@chronicle.app/etl": "0.3.0",
26
+ "@chronicle.app/schema": "0.3.0",
27
+ "@chronicle.app/tsconfig": "0.3.0",
28
+ "@types/node": "^22.10.1",
29
+ "typescript": "^5.7.2"
30
+ },
31
+ "homepage": "https://chronicle.app",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "https://github.com/chronicle-app/chronicle.git",
35
+ "directory": "plugins/zotero"
36
+ },
37
+ "publishConfig": {
38
+ "access": "public",
39
+ "registry": "https://registry.npmjs.org/"
40
+ },
41
+ "dependencies": {
42
+ "@chronicle.app/etl-sqlite": "0.3.0",
43
+ "zod": "^3.24.1"
44
+ },
45
+ "peerDependencies": {
46
+ "@chronicle.app/etl": ">=0.1.0 <1.0.0",
47
+ "@chronicle.app/schema": ">=0.1.0 <1.0.0"
48
+ },
49
+ "engines": {
50
+ "node": ">=22.13.0"
51
+ },
52
+ "exports": {
53
+ ".": {
54
+ "types": "./dist/index.d.ts",
55
+ "import": "./dist/index.js"
56
+ }
57
+ },
58
+ "chronicle": {
59
+ "plugin": true,
60
+ "sources": {
61
+ "zotero": {
62
+ "strategies": {
63
+ "app-db": {
64
+ "delivery": "local",
65
+ "recordTypes": [
66
+ "works",
67
+ "annotations",
68
+ "attachments",
69
+ "notes"
70
+ ],
71
+ "default": true
72
+ }
73
+ }
74
+ }
75
+ }
76
+ }
77
+ }