Insurgently

API reference

Every declaration in Library Hub's API for other plugins, generated from the code.

For people building on Library Hub. Coding agents get the same knowledge as Markdown in the Agent docs.

For tools and coding agentslibrary-hub-api.d.tsapi.json

LibraryHubApi

version

readonly version: string

Semantic version of this API. Check it with isCompatible (or use getLibraryHub).

listBooks

listBooks(which: BookRef[] | {
    shelf: string;
} | {
    ids: BookRef[];
} | "all"): Promise<BookSummary[]>

Books (in the order asked), or a shelf's books. Works from the Content Server, or read-only from the library file when the server is off and a library folder is set. Rejects with book-missing naming any id Calibre doesn't have. { ids } works as the list does. Any BookRef that names a Calibre book; one that names another book rejects with not-calibre. 'all': every book in Calibre, by id.

bookFile

bookFile(book: BookRef, format: BookFormat, opts?: BookFileOptions): Promise<ArrayBuffer | null>

A book file's bytes, from the Content Server, else read-only from the library folder when the server is off. With { convert: true }, an EPUB the book lacks is made from its AZW3 or MOBI after the user agrees (null if they decline); that needs the server, and rejects with server-off without it. the book is any BookRef: a book file in the vault, or one another provider holds, is served as it is.

pdfText

pdfText(book: BookRef, pages?: PageRange): Promise<string>

A PDF's text, page by page (pages separated by a blank line), through Obsidian's PDF.js. With pages, only those pages, so a long book can be read a part at a time. the book is any BookRef, and the text is laid out: a line of the page on a line of its own, a wider gap a blank line, a word broken at a line's end joined. chars a-b locations and bookText count in this text.

shelfMembers

shelfMembers(shelf: string): Promise<number[]>

The Calibre ids of the books on a shelf, ascending: in shelves, not in shelves_exclude (the same test as the shelf's Base). A shelf is named by its shelf_id, or its note's name or path. Book notes without a calibre_id aren't included.

calibreChecks

calibreChecks(): Promise<CalibreChecks>

The Calibre settings Library Hub depends on, checked against the Content Server now: that it answers, that any login works, that the library exists, and that it allows changes (needed to convert a book or write to it). Each check that fails says how to set it right in Calibre. Never rejects: a server that doesn't answer is a failed check.

listShelves

listShelves(): Promise<ShelfInfo[]>

Every shelf, by name, with how many Calibre books are on it.

shelfBaseQuery

shelfBaseQuery(shelf: string): Promise<ShelfBaseQuery>

A shelf's membership as Bases reads it, with the shelf's values filled in: a one-line filter for your own Base or formula, and a whole .base file.

addToShelf

addToShelf(shelf: string, books: BookRef[]): Promise<ShelfChange>

Puts books on a shelf: each book's note gets the shelf in shelves and any exclusion is lifted. Books already on it are unchanged; books without a note are noNote. Logged as one run (run) you can pass to undoRun; nothing is logged when nothing changed.

removeFromShelf

removeFromShelf(shelf: string, books: BookRef[]): Promise<ShelfChange>

Takes books off a shelf: each book's note drops it from shelves and excludes it (shelves_exclude), so nothing puts the book back by itself. Books not on it are unchanged. Logged as one run; nothing when nothing changed.

createShelf

createShelf(spec: NewShelf): Promise<CreatedShelf>

Makes a shelf: a shelf note in the shelves folder (with Shelf Members.base beside it the first time) and the given books pinned to it, in one run. A shelf whose shelf_id exists already is returned as it is, with the books added, so asking twice makes one shelf.

renameShelf

renameShelf(shelf: string, name: string): Promise<RenamedShelf>

Renames a shelf's note and heading; its shelf_id stays, so nothing that names the shelf breaks. Undoable.

deleteShelf

deleteShelf(shelf: string): Promise<DeletedShelf>

Deletes a shelf: the note goes to the trash and its id comes out of every book note. undoRun brings it all back.

mergeShelves

mergeShelves(shelves: string[]): Promise<MergedShelves>

Merges shelves into the first one named: every book on the others is pinned to it, then the others are deleted, in one run. Needs two or more different shelves.

suggestShelves

suggestShelves(book: BookRef, limit?: number): Promise<ShelfSuggestion[]>

The shelves that suit a book, best first: every shelf it isn't on, ranked by Topic Map by what the book and each shelf's books are about. No model is asked. limit is 5 unless given (1–50).

Topic Map serves this: without it, or with one that doesn't rank shelves yet, it rejects with needs-topic-map; when Topic Map hasn't indexed the book, with no-vectors.

undoRun

undoRun(run: string): Promise<UndoReport>

Undoes a run a write operation returned: fields go back unless they changed since (those are named in kept), files the run made go to the trash. A run already undone restores nothing, so undoing twice is safe.

openBook

openBook(book: BookRef, at?: BookPlace): Promise<OpenedBook>

Opens a book in Library Hub's reader, in a new tab, at a place. The book is any BookRef (A Calibre id). Rejects book-missing (nothing matches, or the book has no note) and format-missing (no EPUB, AZW3, MOBI or PDF to read; an AZW3 or MOBI, opened when the book has no EPUB, before its PDF).

findBook

findBook(book: BookRef): Promise<FoundBook>

The book a reference names (see BookRef), without opening it. Rejects book-missing, saying what it tried.

onBooksChanged

onBooksChanged(cb: (change: BooksChanged) => void): () => void

Calls cb each time books arrive, change or go (see BooksChanged); the same news as the library-hub:books-changed workspace event. Returns the function that stops it: pass it to your plugin's register().

shelvesOf

shelvesOf(books: BookRef[]): Promise<BookShelves[]>

Which shelves each book is on, in the order asked: in shelves, not excluded (the same test as shelfMembers). A book without a note is on none.

findBooks

findBooks(query: string, limit?: number): Promise<BookSummary[]>

Books whose title and authors hold every word of query (case and accents ignored), titles that start with it first. limit is 10 unless given (1–50).

estimateShelfFromDescription

estimateShelfFromDescription(spec: DescribedShelf): Promise<ShelfEstimate>

What making a shelf from a description would read and cost: how many books the model would read and in how many calls through library-hub.shelf-keep. No model is asked. Rejects with no-hub without Model Hub.; the books are those that share the description's words (no vectors needed).

shelfFromDescription

shelfFromDescription(spec: DescribedShelf): Promise<DescribedShelfResult>

Makes a shelf from a description: the books that best match its words (title, authors and context, by a keyword ranking), and any naming a term, are read by library-hub.shelf-keep, which keeps those that belong; the shelf is made with them pinned, in one logged run that undoRun takes back. A shelf of that name already there gets the books added. By words (before, the books nearest it by meaning).

estimateSummary

estimateSummary(book: BookRef, kind?: SummaryKind): Promise<SummaryEstimate>

What summarizing a book would read and cost. Reads the book's text; no model is asked. kind is summary unless given.

summarizeBook

summarizeBook(book: BookRef, kind?: SummaryKind): Promise<StartedJob>

Summarizes a book in the background, as the plugin's own commands do (the job shows in the Library panel), and resolves at once with the job and its run. summary writes a one-page ## Summary in the book's note; chapters writes one note per chapter (quotes checked word for word) and a ## Chapters list. Follow it with jobStatus; undoRun takes it back.

jobStatus

jobStatus(job: number): Promise<JobInfo>

A background job's progress, cost and outcome. Rejects with job-missing for an id it doesn't know.

bookText

bookText(book: BookRef, opts?: BookTextOptions): Promise<BookText>

A book's text as chapters, read from its file: the EPUB, else the AZW3 or MOBI as it is, else the PDF, laid out, with its outline's chapters. An AZW3 or MOBI that can't be read as it is (DRM, a damaged file) is read from an EPUB Calibre makes from it, with convert. Each chapter has a location openBook lands on, its offsets in the whole text and its text; hash changes only when the text does. A Calibre book is read from the Content Server, else from the library folder, where nothing can be converted: an unreadable AZW3 or MOBI with a PDF rejects with needs-conversion (with convert, its PDF is read, with a warning), and one without rejects with server-off. A book file in the vault, or one another provider serves, is read as it is. Rejects with book-missing, format-missing (no EPUB, AZW3, MOBI or PDF), needs-conversion, declined, conversion-failed and no-text (a scan, a book of images, a file that can't be read).

bookChapters

bookChapters(book: BookRef, opts?: BookTextOptions): Promise<BookChapters>

The same as bookText without the chapters' text: a book's chapters, their locations and offsets, and the text's hash. It reads the whole file all the same.

status

status(): Promise<LibraryStatus>

Whether Calibre's Content Server and the providers turned on can be reached now, and what the library holds. Never rejects: something that doesn't answer is reported as such. Asks Calibre once and each provider's checks (each given a few seconds).

Functions

isCompatible

declare function isCompatible(actual: string, wanted: string): boolean;

True when a consumer built against wanted can use an API at actual: same major and a minor at least as new. Before 1.0, minors break by default, so a 0.x API serves only the minors it promises (0.1 and up). The same rule, word for word, as Model Hub's (@insurgently/model-hub-api), used for both directions.

getLibraryHub

declare function getLibraryHub(app: unknown, wanted: string, opts?: {
    by?: string;
    for?: string;
}): GetLibraryHubResult;

Finds Library Hub in this vault and checks its API version against the one you built for (isCompatible). opts.by names your plugin and opts.for what it needs books for, in the message: getLibraryHub(app, '0.8.0', { by: 'My Plugin', for: 'for book collections' }).

hasMethod

declare function hasMethod<K extends keyof LibraryHubApi>(api: LibraryHubApi, name: K): api is LibraryHubApi & Required<Pick<LibraryHubApi, K>>;

Whether this Library Hub has a method newer than the version you gate on: if (hasMethod(libraryHub, 'bookText')) …. Methods tagged @since a later version than your gate may be missing on an older Library Hub.

onLibraryHubReady

declare function onLibraryHubReady(app: unknown, plugin: {
    registerEvent(ref: unknown): void;
}, wanted: string, cb: (libraryHub: LibraryHubApi) => void): void;

Runs cb with the API now if Library Hub is loaded (and compatible with wanted), and again each time it loads: it fires library-hub:ready on the workspace at the end of its onload. The listener is registered through plugin.registerEvent, so it stops when your plugin unloads.

onLibraryHubReady(this.app, this, '0.8.0', (libraryHub) => (this.libraryHub = libraryHub));

getBooks

declare function getBooks(app: unknown, wanted: string): GetBooksResult;

onBooksReady

declare function onBooksReady(app: unknown, plugin: {
    registerEvent(ref: unknown): void;
}, wanted: string, cb: (books: LibraryHubApi) => void): void;

Constants

BOOKS_API_VERSION

declare const BOOKS_API_VERSION: string;

BOOKS_PLUGIN_ID

declare const BOOKS_PLUGIN_ID = "library-hub";

BOOKS_READY_EVENT

declare const BOOKS_READY_EVENT = "library-hub:ready";

BOOKS_TOOLS

declare const BOOKS_TOOLS: LibraryHubTool[];

LIBRARY_HUB_API_VERSION

declare const LIBRARY_HUB_API_VERSION: string;

Semantic version of Library Hub's public API. Consumers check it before calling anything else.

LIBRARY_HUB_BOOKS_CHANGED_EVENT

declare const LIBRARY_HUB_BOOKS_CHANGED_EVENT = "library-hub:books-changed";

The workspace event Library Hub fires when books arrive, change or go, with a BooksChanged. onBooksChanged in the API hears the same thing.

this.registerEvent(this.app.workspace.on(LIBRARY_HUB_BOOKS_CHANGED_EVENT, (c: BooksChanged) => reindex(c.added)));

LIBRARY_HUB_PLUGIN_ID

declare const LIBRARY_HUB_PLUGIN_ID = "library-hub";

LIBRARY_HUB_READY_EVENT

declare const LIBRARY_HUB_READY_EVENT = "library-hub:ready";

The workspace event Library Hub fires each time it loads, with its API: at startup, and when the user disables and enables it again. onLibraryHubReady listens for it.

LIBRARY_HUB_TOOLS

declare const LIBRARY_HUB_TOOLS: LibraryHubTool[];

Every operation as a tool (see LibraryHubTool).

Types

Open a type to see its members.

BookChapter interface

One chapter of a book, as bookChapters lists it. An EPUB's, AZW3's or MOBI's chapters are its contents entries (an EPUB's nav or NCX), every one (front and back matter left out; never merged, however many), a file split at its entries' anchors when several point into it, and a file no entry claims a chapter of its own. A PDF's chapters are its outline's entries, or 12 even parts when it has no outline.

interface BookChapter
  • n: number

    1-based, in reading order. For a book of 30 chapters or fewer, openBook(book, { chapter: n }) opens at it; past 30 the chapter notes (and so openBook's chapter number) count merged parts, so open at location.

  • title: string
  • location: string

    Where it starts, as openBook's BookPlace.location takes it: an EPUB's file inside the book (OEBPS/c3.xhtml, or OEBPS/all.xhtml#ch3 for a chapter that starts inside a file); an AZW3's or MOBI's contents entry (kindle:pos:fid:0001:off:0000000000, filepos:0000001234), or the start of its section as a CFI (epubcfi(/6/4!/4)) when no entry points there; or chars a-b for a PDF (code points into its text, which give the page). A passage inside the chapter keeps the chapter's location (EPUB, AZW3, MOBI) or adds its own offset to start (PDF).

  • start: number

    Where it starts and ends in the book's whole text, in code points (as a corpus counts them).

  • end: number
BookChapters interface

A book's chapters, as bookChapters gives them.

interface BookChapters
  • book: FoundBook

    The book the reference named.

  • format: BookFormat | "AZW3" | "MOBI"

    The file the text was read from. AZW3 and MOBI: such a file is read as it is, with no conversion.

  • convertedFrom?: "AZW3" | "MOBI"

    When the EPUB was just made from the book's AZW3 or MOBI (convert, for one that can't be read as it is), which.

  • hash: string

    SHA-256 of the book's whole text (UTF-8), in hex. It changes only when the text does, so a corpus can keep its passages while it matches. The whole text is an EPUB's spine files' text in reading order (an AZW3's or MOBI's sections; front and back matter included), or a PDF's pages as pdfText gives them, joined by blank lines. A page's paragraphs and blocks are separated by a blank line, its line breaks by a line break. an EPUB is read with foliate-js, the reader's own parser, so every EPUB's text, and hash, changed once in 0.9.

  • length: number

    The whole text's length, in code points.

  • chapters: BookChapter[]
  • warnings: string[]

    What a reader of the text should know, in plain words: a PDF with no outline cut into even parts, a conversion declined.

  • outline: boolean

    Whether the chapters follow the book's own structure: an EPUB's contents, or a PDF's outline. False for a PDF with no outline, cut into even parts (or one part when short).

BookFileOptions interface
interface BookFileOptions
  • convert?: boolean

    For an EPUB the book doesn't have: when it has an AZW3 or MOBI, ask the user to convert it in Calibre. The conversion adds an EPUB to the book in their Calibre library, so the user is always asked first; bookFile resolves null when they decline. Without this, a missing EPUB rejects with format-missing. Converting needs Calibre's Content Server: with only the library folder, it rejects with server-off.

BookFormat type

The formats bookFile returns. Other formats (AZW3, MOBI…) are listed in formats but not served.

type BookFormat = "EPUB" | "PDF";
BookPlace interface

Where in a book to open it. Tried in order: highlight, quote, location, chapter, href, then page; the first that lands wins.; chapter, highlight and location.

interface BookPlace
  • href?: string

    A contents entry's file#anchor (an EPUB section), as in the book's table of contents or spine.

  • quote?: string

    A short verbatim passage from the book (a sentence or so); the reader finds it and shows it, highlighted if it can. Whitespace and quote-mark differences are ignored.

  • page?: number

    A 1-based page number (PDFs).

  • chapter?: string | number

    A chapter: its title (as the contents has it; case and spacing don't matter), or its number counted the way Library Hub's chapter notes count them (front and back matter left out).

  • highlight?: string

    A highlight's id (h_…) in the book's highlights note: the reader goes to it, checking its text first.

  • location?: string

    A passage's location exactly as a corpus records it (Topic Map's location): an EPUB contents entry (text/c3.xhtml#s2), an AZW3 or MOBI one as bookChapters gives it (kindle:pos:…, filepos:…, a section's epubcfi(…);), or chars a-b, code-point offsets into pdfText's text, which gives the PDF page. What a split adds after it (§2, w3) is ignored. Pass the passage's quote with it to land on the passage itself.

BookRef type

Which book: one thing another plugin, a link or a corpus knows about it. (0.5 took a Calibre id only).

- a number, or a string of digits: a Calibre id (ten or thirteen digits that check out as an ISBN are an ISBN); - a book note's path or name, or a link to it ([[Name]]); - a book file's path: a file in the vault (opened as it is, with or without a note), or a path inside a Calibre library, whose book folder Title (42) names the Calibre id; - an ISBN (10 or 13 digits, hyphens allowed), a Calibre uuid, an Audiobookshelf id or an OPDS id.

A string can say which with a prefix: calibre:42, note:Books/Library/Salt Roads.md, file:…, isbn:…, uuid:…, audiobookshelf:…, opds:…. The object form names one: { isbn: '978…' }.

type BookRef = number | string | BookRefParts;
BookRefParts interface

A book reference that names what it is (see BookRef): exactly one of these.

interface BookRefParts
  • calibre?: number
  • note?: string
  • file?: string
  • isbn?: string
  • uuid?: string
  • audiobookshelf?: string
  • opds?: string
BooksApi type
type BooksApi = LibraryHubApi;
BooksChanged interface

Books that arrived, changed or went. Changes close together come as one: a sync of two hundred books is one event.

interface BooksChanged
  • added: ChangedBook[]

    New book notes: from a notes sync, a resync or Bring in new books.

  • changed: ChangedBook[]

    Book notes a sync changed, and notes renamed or moved (with previousPath).

  • removed: ChangedBook[]

    Book notes deleted (or moved out of the library folder).

  • source: "sync" | "intake" | "vault"

    What did it: a notes sync or resync (sync), Bring in new books (intake), or an edit in the vault (vault).

BooksErrorCode type
type BooksErrorCode = LibraryHubErrorCode;
BookShelves interface

Which shelves a book is on, as shelvesOf gives it.

interface BookShelves
  • id: number

    The Calibre id asked about.

  • notePath: string | null

    The book's note, or null when it has none: membership lives in the note, so such a book is on no shelf.

  • shelves: string[]

    The shelf_ids of the shelves it is on (in shelves, not excluded), ascending.

BooksTool type
type BooksTool = LibraryHubTool;
BookSummary interface

One Calibre book, as listBooks gives it.

interface BookSummary
  • id: number

    The Calibre id.

  • title: string
  • authors: string[]
  • formats: string[]

    Calibre's formats for the book, upper case: EPUB, PDF, AZW3…

  • notePath: string | null

    The book's note in the library folder (by its calibre_id or calibre_ids), or null when it has none.

  • context?: string

    What the book is about, as plain text: the note's context field, else Calibre's comments with their HTML taken out. Absent when neither has any.

BookText interface

A book's text, as bookText gives it: bookChapters with each chapter's text.

interface BookText extends BookChapters
  • chapters: BookTextChapter[]
BookTextChapter interface

A chapter with its text: exactly the book's whole text from start to end.

interface BookTextChapter extends BookChapter
  • text: string
BookTextOptions interface

What bookText and bookChapters take.

interface BookTextOptions
  • convert?: boolean

    For a book whose only text is an AZW3 or MOBI that can't be read as it is (DRM, a damaged file): ask the user to convert it to an EPUB in Calibre (it adds a file to their library, so they are always asked). Without it, such a book rejects with needs-conversion, naming the cause. If they decline, or the conversion fails, a PDF is read instead when the book has one (with a warning); else the call rejects with declined or conversion-failed. an AZW3 or MOBI that can be read is read as it is, so this only matters when it can't.

CalibreCheck interface

One Calibre setting as checked.

interface CalibreCheck
  • id: "server" | "login" | "library" | "changes"
  • name: string

    The setting in a word or two: "Content Server", "Login", "Library", "Changes".

  • state: CalibreCheckState

    off: not checked, because an earlier check failed.

  • text: string

    What was found.

  • fix?: string

    Where to set it right in Calibre, when state is bad.

CalibreChecks interface
interface CalibreChecks
  • ok: boolean

    Every check passed.

  • reads: boolean

    The server answers and the library exists: books can be read.

  • writes: boolean

    The server allows changes.

  • checks: CalibreCheck[]
CalibreCheckState type
type CalibreCheckState = "ok" | "bad" | "off";
CalibreStatus interface

Calibre, as status finds it.

interface CalibreStatus
  • state: "server" | "file" | "off"

    server: the Content Server answers, so books, their files and text can be read. file: the server is off and the library folder is read instead, read-only (books, and their files and text; no conversion). off: neither (not set up, or not answering).

  • files: boolean

    Book files can be read now: bookFile, pdfText and bookText of a Calibre book.

  • text: string

    What was found, in plain words.

ChangedBook interface

One book in a BooksChanged.

interface ChangedBook
  • notePath: string

    The book's note in the vault (for a removed book, where it was).

  • id: number | null

    The Calibre id, when the book has one (an audiobook only another provider holds has none).

  • title: string

    The title, from the note's name.

  • authors: string[]

    The author on the note, when it names one.

  • previousPath?: string

    For a note that was renamed or moved: where it was before.

CreatedShelf interface

What createShelf did.

interface CreatedShelf extends ShelfChange
  • shelf: ShelfInfo
  • created: boolean

    False when a shelf with that shelf_id existed already: it is returned as is, with the books added.

DeletedShelf interface

What deleteShelf did.

interface DeletedShelf
  • deleted: string

    The shelf_id of the shelf that was deleted.

  • unpinned: number

    How many book notes had the shelf taken out of them.

  • run: string | null

    The logged run, to pass to undoRun, which brings the shelf note and every pin back.

DescribedShelf interface

What estimateShelfFromDescription and shelfFromDescription take.

interface DescribedShelf
  • name: string

    The shelf's name: its note's name and the source of its shelf_id.

  • description: string

    What belongs on it, in a sentence or two. The books are chosen by this; it also becomes the note's summary.

  • terms?: string[]

    Names or places a member's title or description would mention: books naming one are considered too.

  • group?: string

    A group folder under the shelves folder; without it, the packs choose.

DescribedShelfResult interface

What shelfFromDescription did.

interface DescribedShelfResult extends CreatedShelf
  • considered: number

    How many books the model read.

  • costUsd: number

    What the calls cost, in US dollars.

Estimate interface

What a run that asks a model would read and cost, before it runs.

interface Estimate
  • role: string

    The role the calls go through: library-hub.shelf-keep, library-hub.summarize, library-hub.chapters.

  • calls: number

    How many model calls, at most.

  • tokens: number

    About how many input tokens, in all.

  • usd: number | null

    About what it costs, in US dollars. With Model Hub 0.13 or later, the high end of Model Hub's estimate of the calls (each with a full reply), so a budget set from it holds; null when Model Hub can't price them (text says why). With an older Model Hub, the input at the role's first model's listed price; null when that model has no price.

  • text: string

    The same in one plain sentence, as the approval dialog shows it: with Model Hub 0.13 or later, a range ("about $0.02–$0.09").

FoundBook interface

The book a reference named, as findBook gives it.

interface FoundBook
  • notePath: string | null

    The book's note, or null for a book file in the vault that has none (or, a Calibre book named by its id that has no note yet).

  • calibreId: number | null

    Its Calibre id, or null when it isn't a Calibre book (or the file was named directly).

  • file: string | null

    The book file in the vault, when the reference named one; null for a book read through its providers.

  • via: "calibre" | "note" | "file" | "isbn" | "uuid" | "audiobookshelf" | "opds"

    What matched: calibre, note, file, isbn, uuid, audiobookshelf or opds.

GetBooksResult type

What the deprecated getBooks answers: { books }, as before 0.6. getLibraryHub answers GetLibraryHubResult.

type GetBooksResult = {
    books: LibraryHubApi;
} | {
    books: null;
    reason: "missing" | "incompatible";
    message: string;
    version?: string;
};
GetLibraryHubResult type

What getLibraryHub answers: the API, or why not, in a message to show as it is.

type GetLibraryHubResult = {
    libraryHub: LibraryHubApi;
} | {
    libraryHub: null;
    reason: "missing" | "incompatible";
    message: string;
    version?: string;
};
JobInfo interface

A background job as jobStatus gives it.

interface JobInfo
  • job: number
  • name: string
  • status: "waiting" | "running" | "done" | "failed" | "cancelled"
  • label: string

    What it is doing now, or did last.

  • done: number

    Steps done and in all (chapters, say), when it counts them; 0 when it doesn't.

  • total: number
  • spentUsd: number

    What it has spent so far, in US dollars.

  • error?: string

    Why it failed, in plain words.

  • run?: string

    Its logged run, when it has one.

JsonSchema interface

A JSON schema for a tool's input, as Model Hub's tool registry and MCP servers take it.

interface JsonSchema
  • type: "object" | "string" | "number" | "integer" | "boolean" | "array"
  • description?: string
  • properties?: Record<string, JsonSchema>
  • required?: string[]
  • items?: JsonSchema
  • enum?: string[]
  • minimum?: number
LibraryHubErrorCode type

Why a call failed: - server-off: Calibre's Content Server isn't set or doesn't answer, and no library folder is set to read the library instead. With a library folder, books and their files are read from it, and only what changes Calibre needs the server: converting a book to EPUB rejects with server-off, saying so. - server-error: the server answered with an error (a login it asks for, a refused change, a failure). With the server off: a book file in the library folder that couldn't be read, such as one in a cloud-synced folder that isn't downloaded on this computer, or took too long to download; the message names the file. - book-missing: Calibre has no book with that id (for openBook and findBook: nothing matches the reference, or the book has no note; the message says what was tried). - format-missing: the book has no file in that format (and none to convert from, or convert wasn't asked); for openBook, no EPUB, AZW3, MOBI or PDF to read (AZW3 and MOBI). - shelf-missing: no shelf note has that id or name. - conversion-failed: Calibre tried to convert the book and couldn't. - no-text: the PDF has no text layer (a scan). - invalid-request: the arguments are malformed (an id that isn't a number, an unknown format). - no-vectors: the library has no book vectors yet, or this book has none. the vectors are Topic Map's: given when Topic Map hasn't indexed the library, or this book, yet. - no-hub: Model Hub isn't installed, enabled or new enough, and the call asks a model. - job-missing: no job has that id (finished jobs are kept for a while, the 30 most recent). - needs-conversion: bookText or bookChapters of a book whose only text is an AZW3 or MOBI that can't be read as it is (DRM, a damaged file; the message names the cause), without { convert: true }: making an EPUB adds a file to the user's Calibre library, so it is only done when asked. An AZW3 or MOBI that can be read is read as it is, with no conversion. - declined: the user declined that conversion, and the book has no PDF to read instead. - not-calibre: the call works on Calibre books, and the reference names a book Calibre doesn't hold (a book file in the vault, a book only another provider has). - busy: Obsidian is still updating links in the vault, so a change that moves a note (renameShelf) was not made. Nothing was changed; try again in a moment. also: with the server off, Calibre's library file was being written each time it was read (Calibre adding books); try again when it's done. - needs-topic-map: the call works from what books are about (their vectors), which Library Hub alone doesn't keep: it needs the Topic Map plugin, which serves it, or a newer Topic Map that offers the call. Also a Topic Map refusal with no code of its own here, its words in the message. Library Hub's own matching is by words.

no-text also covers an EPUB, AZW3 or MOBI with no readable text (a book of images), and a book file that can't be read at all (DRM, a damaged file), the message naming the cause.

type LibraryHubErrorCode = "server-off" | "server-error" | "book-missing" | "format-missing" | "shelf-missing" | "conversion-failed" | "no-text" | "invalid-request" | "no-vectors" | "no-hub" | "job-missing" | "needs-conversion" | "declined" | "not-calibre" | "busy" | "needs-topic-map";
LibraryHubTool interface

One operation as a tool a model can call. Library Hub registers these with Model Hub's tool registry when both load, so they run from the Hub's panel and its MCP server under the user's tool settings; anything else (a command palette, say) can map them the same way. method is the LibraryHubApi method to call; args names the input properties in the order the method takes them (a missing optional one is passed as undefined), or is the one entry $input for a method that takes the input object whole.

interface LibraryHubTool
  • name: string

    Dotted and unique: library-hub.list_shelves.

  • description: string

    For the model: what it does and when to use it.

  • input: JsonSchema
  • method: keyof LibraryHubApi
  • args: string[]

    Input properties in the method's argument order; the one entry $input passes the whole input object.

  • effect: "read" | "write"

    Whether it changes anything. Model Hub runs reads freely and asks before a write, unless the user says otherwise.

  • estimate?: keyof LibraryHubApi

    A method that takes the same arguments and resolves to an Estimate: what the call would read and cost, shown to the user before they approve it.

LibraryStatus interface

What Library Hub can reach and what the library holds, as status gives it.

interface LibraryStatus
  • version: string

    The API version (the same as version on the API).

  • calibre: CalibreStatus
  • providers: ProviderStatus[]

    The providers turned on, other than Calibre, each checked.

  • library: { notes: number; calibreBooks: number | null; formats: Record<string, number>; shelves: number; }
MergedShelves interface

What mergeShelves did.

interface MergedShelves
  • shelf: ShelfInfo

    The shelf that was kept, with its new member count.

  • merged: string[]

    The shelf_ids of the shelves merged into it and deleted.

  • changed: number[]

    Calibre ids whose notes now pin the kept shelf.

  • noNote: number[]

    Calibre ids with no book note, which could not be moved.

  • run: string | null
NewShelf interface

What createShelf takes.

interface NewShelf
  • name: string

    The shelf's name: its note's name, and the source of its shelf_id ("Field Guides" → field-guides).

  • description?: string

    A sentence for the note's summary.

  • books?: BookRef[]

    Books to pin to it now: Calibre ids, or any BookRef that names a Calibre book.

  • rule?: string

    A cluster id whose books belong to it by rule.

  • group?: string

    A group folder under the shelves folder. Without it, the first pack group whose pattern matches the name.

OpenedBook interface

What openBook did.

interface OpenedBook
  • placed: "highlight" | "quote" | "href" | "chapter" | "page" | "start"

    Which part of the place it landed on; 'start' when none matched (the book opens where the reader would by default). A location lands as 'href' (its contents entry) or 'page' (its PDF page). 'chapter' and 'highlight' .

PageRange interface

A pages range for pdfText, 1-based and inclusive; either end may be left out.

interface PageRange
  • from?: number
  • to?: number
ProviderStatus interface

Another book provider (Audiobookshelf, OPDS, Readwise…) the user has turned on, as status finds it.

interface ProviderStatus
  • id: string
  • name: string
  • state: "ok" | "bad"

    ok: its checks pass; bad: one failed, or it didn't answer in time.

  • files: boolean

    Whether it can serve book files (so bookText can read a book only it has).

  • text: string

    What was found, in plain words.

RenamedShelf interface

What renameShelf did.

interface RenamedShelf
  • shelf: ShelfInfo

    The shelf under its new name; its id is the same, so pins and Bases that name it still work.

  • run: string | null

    The logged run, to pass to undoRun; null when the shelf already had that name.

ShelfBaseQuery interface

A shelf's membership as a Bases filter.

interface ShelfBaseQuery
  • filter: string

    One line for a Base's filters or a formula: the shelf's shelves and shelves_exclude test with its id filled in.

  • base: string

    A whole .base file: the same filter and the plugin's three views (Shelf, Cards, Shelf table).

ShelfChange interface

What a write to shelf membership did.

interface ShelfChange
  • run: string | null

    The logged run, to pass to undoRun; null when nothing changed, so there was nothing to log.

  • changed: number[]

    Calibre ids whose notes changed.

  • unchanged: number[]

    Calibre ids already as asked (on the shelf for an add, off it for a remove).

  • noNote: number[]

    Calibre ids with no book note: membership lives in the note, so these can't be shelved until a sync makes one.

ShelfEstimate interface

What estimateShelfFromDescription gives.

interface ShelfEstimate extends Estimate
  • candidates: number

    How many books would be read by the model: those that best match the description's words, and those naming a term.

ShelfInfo interface

One shelf, as listShelves gives it.

interface ShelfInfo
  • id: string

    The shelf's shelf_id (collection_id before 0.8): how shelfMembers and the write operations name it.

  • name: string

    The shelf note's name.

  • path: string

    The shelf note's path in the vault.

  • rule?: string

    The cluster id whose books belonged to the shelf by rule.

  • group?: string

    The group folder the shelf sits in (Books/Collections/<group>/), when it has one.

  • members: number

    How many Calibre books are on it now (book notes without a calibre_id aren't counted).

ShelfSuggestion interface

A shelf that suits a book, as suggestShelves ranks it.

interface ShelfSuggestion
  • shelf: ShelfInfo
  • score: number

    How well the book suits the shelf by what they are about, as Topic Map's rankGroups scores it (higher is closer). Before 0.8, the cosine against the mean of the shelf's books' vectors.

  • match: number

    How well the shelf matches; suggestions are ordered by it. the same as score (Topic Map ranks by meaning and words together).

  • because: string

    Why, in plain words: how close the book is to the shelf's books, against the bar Topic Map judged it by, with the numbers after the words.

StartedJob interface

A background job summarizeBook started.

interface StartedJob
  • job: number

    For jobStatus.

  • run: string

    The logged run its writes go to, for undoRun; undoing it while the job runs stops the job first.

  • name: string

    The job's name, as the Library panel shows it.

SummaryEstimate interface

What estimateSummary gives.

interface SummaryEstimate extends Estimate
  • id: number
  • title: string
  • kind: SummaryKind
  • chapters: number

    How many chapters the book's text has.

  • exists: boolean

    The book's note already has a ## Summary (for summary) or ## Chapters (for chapters): a new run replaces it.

SummaryKind type

What summarizeBook writes: summary, a one-page summary in the book's note; chapters, one note per chapter.

type SummaryKind = "summary" | "chapters";
UndoReport interface

What undoing a run did.

interface UndoReport
  • restored: number

    Notes whose fields went back.

  • trashed: number

    Files the run made, moved to the trash.

  • kept: string[]

    What was left as it is, in plain words: a field or note changed after the run.

  • stopped?: string

    The run's job was still going and was stopped first (a summary, say), in plain words.

Package
@insurgently/library-hub-api
Plugin id
library-hub
Needs
Obsidian 1.13.1, desktop
License
MIT