@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.
- package/LICENSE +21 -0
- package/README.md +118 -0
- package/dist/connectors/ZoteroExtractor.d.ts +73 -0
- package/dist/connectors/ZoteroExtractor.js +551 -0
- package/dist/connectors/ZoteroTransformer.d.ts +139 -0
- package/dist/connectors/ZoteroTransformer.js +941 -0
- package/dist/connectors/records.d.ts +175 -0
- package/dist/connectors/records.js +11 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/package.json +77 -0
|
@@ -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 {};
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
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
|
+
}
|