$ show aidenlx/zotlit
ZotLit is a dual-plugin system (Obsidian plugin + Zotero addon) that bridges Zotero's reference management with Obsidian's note-taking environment. It enables users to create literature notes from Zotero items, insert formatted citations, import annotations, and export documents via Pandoc — all within Obsidian. The system is a monorepo with three main applications: an Obsidian plugin (apps/obsidian) that provides views (annotation sidebar, references panel, citation popover, template data explorer), services (citation indexing, live updates from Zotero, Pandoc integration, note creation/update), and a settings tab; a Zotero addon (apps/zotero) that extends Zotero's menus, database status, and freshness signaling; and a documentation site (apps/docs) built with TanStack Router and Fumadocs on Cloudflare Workers. The architecture is service-oriented on the Obsidian side, with approximately 20 services wired in a service container (build.ts) using AsyncDisposableStack for lifecycle management. Shared packages (@zotlit/db, @zotlit/templates, @zotlit/protocol, @zotlit/obsidian-i18n, @zotlit/item-lookup) provide database queries over Zotero's SQLite via Drizzle ORM, template rendering with Eta/Liquid engines, a versioned HTTP wire protocol between Zotero and Obsidian, i18n Language Pack compilation, and a search index for item lookup. The codebase is well-tested with Vitest, employs modern TypeScript patterns, and maintains a comprehensive typed contract system for template data. Key workflows include: bidirectional citation linking (pandoc-style and wikilink), live preview of citations in reading view, annotation import from PDF/EPUB/snapshots with turndown HTML-to-Markdown conversion, Pandoc export with a bundled Lua filter and pinned WASM engine, batch note creation from collection selections, and a template workbench CLI for debugging and authoring templates. The system relies on Zotero's local SQLite database as the authoritative source, with a freshness detection mechanism (WAL checkpoint polling) to trigger updates in Obsidian.
The LLM identified 3 files worth highlighting for reuse:
An eval-free runtime interpreter for compiled Language Pack JSON (created by the same package's compiler). It supports plural forms, select/ordinal, and custom formatter injection without eval. The runtime is self-contained, has no internal monorepo dependencies beyond standard libraries, and could be extracted as a standalone i18n runtime for any app that wants to ship pre-compiled message catalogs without risk of code injection.
A minimal typed event emitter (3 KB) providing `on`, `once`, `off`, and `emit` with TypeScript generics for event maps. It is fully self-contained with no dependencies. The implementation is idiomatic and demonstrates non-trivial generic constraint usage. It could be extracted into any TypeScript project requiring a lightweight pub/sub utility with `once` support.
A bounded cache implementing stale-while-revalidate semantics with `AsyncDisposable` read leases. Readers acquire a lease that serves the last fresh result while allowing a background refresh. The cache enforces a maximum entry count and TTL, and handles concurrent refresh deduplication. It is self-contained (imports only from @/lib/constants and @/lib/log) and demonstrates a robust pattern for serving cached data with freshness guarantees. Could be extracted into any async TypeScript project needing similar caching.