UNPKG

yanki-connect

Version:
1,725 lines 81.2 kB
//#region src/types/deck.d.ts type DeckStats = { deck_id: number; learn_count: number; name: string; new_count: number; review_count: number; total_in_deck: number; }; type DeckConfig = { autoplay: boolean; dyn: 1 | false; id: number; lapse: { delays: number[]; leechAction: number; leechFails: number; minInt: number; mult: number; }; maxTaken: number; mod: number; name: string; new: { bury: boolean; delays: number[]; initialFactor: number; ints: number[]; order: number; perDay: number; separate: boolean; }; replayq: boolean; rev: { bury: boolean; ease4: number; fuzz: number; ivlFct: number; maxIvl: number; minSpace: number; perDay: number; }; timer: number; usn: number; }; type DeckRequests = Request<'changeDeck', 6, { cards: number[]; deck: string; }> | Request<'cloneDeckConfigId', 6, { cloneFrom: number; name: string; }, false | number> | Request<'createDeck', 6, { deck: string; }, number> | Request<'deckNames', 6, never, string[]> | Request<'deckNamesAndIds', 6, never, Record<string, number>> | Request<'deleteDecks', 6, { cardsToo: true; decks: string[]; }> | Request<'getDeckConfig', 6, { deck: string; }, DeckConfig> | Request<'getDecks', 6, Record<'cards', number[]>, Record<string, number[]>> | Request<'getDeckStats', 6, { decks: string[]; }, Record<string, DeckStats>> | Request<'removeDeckConfigId', 6, { configId: number; }, boolean> | Request<'saveDeckConfig', 6, { config: DeckConfig; }, boolean> | Request<'setDeckConfigId', 6, { configId: number; decks: string[]; }, boolean>; //#endregion //#region src/types/note.d.ts type NoteModel = 'Basic' | 'Basic (and reversed card)' | 'Basic (type in the answer)' | 'Cloze' | (string & {}); type NoteMedia = { data?: string; fields?: string[]; filename: string; path?: string; skipHash?: string; url?: string; }; type Note = { audio?: NoteMedia[]; deckName: string; fields: Record<string, string>; modelName: NoteModel; picture?: NoteMedia[]; tags?: string[]; video?: NoteMedia[]; }; type NoteWithCreationOptions = Note & { options?: { allowDuplicate?: boolean; duplicateScope?: 'deck' | (string & {}); duplicateScopeOptions?: { checkAllModels?: boolean; checkChildren?: boolean; deckName?: null | string; }; }; }; type NoteRequests = Request<'addNote', 6, { note: NoteWithCreationOptions; }, null | number> | Request<'addNotes', 6, { notes: NoteWithCreationOptions[]; }, Array<null | string> | null> | Request<'addTags', 6, { notes: number[]; tags: string; }> | Request<'canAddNotes', 6, { notes: NoteWithCreationOptions[]; }, boolean[]> | Request<'canAddNotesWithErrorDetail', 6, { notes: NoteWithCreationOptions[]; }, Array<{ canAdd: false; error: string; } | { canAdd: true; }>> | Request<'clearUnusedTags', 6, never, string[]> | Request<'deleteNotes', 6, { notes: number[]; }> | Request<'findNotes', 6, { query: string; }, number[]> | Request<'getNoteTags', 6, { note: number; }, string[]> | Request<'getTags', 6, never, string[]> | Request<'notesInfo', 6, { notes: number[]; }, Array<{ cards: number[]; fields: Record<string, { order: number; value: string; }>; mod: number; modelName: string; noteId: number; profile: string; tags: string[]; }>> | Request<'notesModTime', 6, { notes: number[]; }, Array<{ mod: number; noteId: number; }>> | Request<'removeEmptyNotes', 6> | Request<'removeTags', 6, { notes: number[]; tags: string; }> | Request<'replaceTags', 6, { notes: number[]; replace_with_tag: string; tag_to_replace: string; }> | Request<'replaceTagsInAllNotes', 6, { replace_with_tag: string; tag_to_replace: string; }> | Request<'updateNote', 6, { note: { audio?: NoteMedia[]; fields: Record<string, string>; id: number; picture?: NoteMedia[]; tags?: string[]; video?: NoteMedia[]; } | { fields?: Record<string, string>; id: number; tags: string[]; }; }> | Request<'updateNoteFields', 6, { note: { audio?: NoteMedia[]; fields: Record<string, string>; id: number; picture?: NoteMedia[]; video?: NoteMedia[]; }; }> | Request<'updateNoteModel', 6, { note: { fields: Record<string, string>; id: number; modelName: string; tags: string[]; }; }> | Request<'updateNoteTags', 6, { note: number; tags: string[]; }>; //#endregion //#region src/types/graphical.d.ts type GraphicalRequests = Request<'guiAddCards', 6, { note: Note; }, number> | Request<'guiAnswerCard', 6, { ease: number; }, boolean> | Request<'guiBrowse', 6, { query: string; reorderCards?: { columnId: CardBrowserColumns; order: 'ascending' | 'descending'; }; }, number[]> | Request<'guiCheckDatabase', 6, never, true> | Request<'guiCurrentCard', 6, never, CardInfo | null> | Request<'guiDeckBrowser', 6> | Request<'guiDeckOverview', 6, { name: string; }, boolean> | Request<'guiDeckReview', 6, { name: string; }, boolean> | Request<'guiEditNote', 6, { note: number; }> | Request<'guiExitAnki', 6> | Request<'guiImportFile', 6, { path: string; }> | Request<'guiPlayAudio', 6, never, true> | Request<'guiSelectCard', 6, { card: number; }, boolean> | Request<'guiSelectedNotes', 6, never, number[]> | Request<'guiSelectNote', 6, { note: number; }, boolean> | Request<'guiShowAnswer', 6, never, boolean> | Request<'guiShowQuestion', 6, never, boolean> | Request<'guiStartCardTimer', 6, never, true> | Request<'guiUndo', 6, never, boolean>; //#endregion //#region src/types/media.d.ts type MediaRequests = Request<'deleteMediaFile', 6, { filename: string; }> | Request<'getMediaDirPath', 6, never, string> | Request<'getMediaFilesNames', 6, { pattern: string; }, string[]> | Request<'retrieveMediaFile', 6, { filename: string; }, false | string> | Request<'storeMediaFile', 6, { data?: string; deleteExisting?: boolean; filename: string; path?: string; url?: string; }, string>; //#endregion //#region src/types/miscellaneous.d.ts type MiscellaneousRequests = Request<'apiReflect', 6, { actions: null | string[]; scopes: Array<'actions'>; }, { actions: string[]; scopes: string[]; }> | Request<'exportPackage', 6, { deck: string; includeSched?: boolean; path: string; }, boolean> | Request<'getActiveProfile', 6, never, string> | Request<'getProfiles', 6, never, string[]> | Request<'importPackage', 6, { path: string; }, boolean> | Request<'loadProfile', 6, { name: string; }, true> | Request<'multi', 6, // Crazy, have to call this experimental { actions: Array<{ action: Requests['action']; params?: Requests['params']; version?: number; }>; }, Array<Requests['response'] | { error: null | string; result: Requests['response']; }>> | Request<'reloadCollection', 6> | Request<'requestPermission', 6, never, { permission: 'denied'; } | { permission: 'granted'; requireApiKey: boolean; version: boolean; }> | Request<'sync', 6> | Request<'version', 6, never, number>; //#endregion //#region src/types/model.d.ts type ModelField = { collapsed: boolean; description: string; excludeFromSearch: boolean; font: string; id: number; name: string; ord: number; plainText: boolean; preventDeletion: boolean; rtl: boolean; size: number; sticky: boolean; tag: null; }; type ModelTemplate = { afmt: string; bafmt: string; bfont: string; bqfmt: string; bsize: number; did: null; id: number; name: string; ord: number; qfmt: string; }; type Model = { css: string; did: null; flds: ModelField[]; id: number; latexPost: string; latexPre: string; latexsvg: boolean; mod: number; name: string; originalStockKind: number; req: Array<[number, string, number[]]>; sortf: number; tmpls: ModelTemplate[]; type: number; usn: number; }; type ModelToCreate = { cardTemplates: Array<{ [key: string]: string; Back: string; Front: string; }>; css?: string; inOrderFields: string[]; isCloze?: boolean; modelName: string; }; type ModelRequests = Request<'createModel', 6, ModelToCreate, Model> | Request<'findAndReplaceInModels', 6, { model: { back: boolean; css: boolean; fieldText: string; front: boolean; modelName: string; replaceText: string; }; }, number> | Request<'findModelsById', 6, { modelIds: number[]; }, Model[]> | Request<'findModelsByName', 6, { modelNames: string[]; }, Model[]> | Request<'modelFieldAdd', 6, { fieldName: string; index: number; modelName: string; }> | Request<'modelFieldDescriptions', 6, { description: string; fieldName: string; modelName: string; }, boolean> | Request<'modelFieldFonts', 6, { modelName: string; }, Record<string, { font: string; size: number; }>> | Request<'modelFieldNames', 6, { modelName: string; }, string[]> | Request<'modelFieldRemove', 6, { fieldName: string; modelName: string; }> | Request<'modelFieldRename', 6, { modelName: string; newFieldName: string; oldFieldName: string; }> | Request<'modelFieldReposition', 6, { fieldName: string; index: number; modelName: string; }> | Request<'modelFieldSetDescription', 6, { fieldName: string; index: number; modelName: string; }> | Request<'modelFieldSetFont', 6, { fieldName: string; font: string; modelName: string; }> | Request<'modelFieldSetFontSize', 6, { fieldName: string; fontSize: number; modelName: string; }> | Request<'modelFieldsOnTemplates', 6, { modelName: string; }, Record<string, [string[], string[]]>> | Request<'modelNames', 6, never, string[]> | Request<'modelNamesAndIds', 6, never, Record<string, number>> | Request<'modelStyling', 6, { modelName: string; }, { css: string; }> | Request<'modelTemplateAdd', 6, { modelName: string; template: { [key: string]: string; Back: string; Front: string; }; }> | Request<'modelTemplateRemove', 6, { modelName: string; templateName: string; }> | Request<'modelTemplateRename', 6, { modelName: string; newTemplateName: string; oldTemplateName: string; }> | Request<'modelTemplateReposition', 6, { index: number; modelName: string; templateName: string; }> | Request<'modelTemplates', 6, { modelName: string; }, Record<string, { [key: string]: string; Back: string; Front: string; }>> | Request<'updateModelStyling', 6, { model: { css: string; name: string; }; }> | Request<'updateModelTemplates', 6, { model: { name: string; templates: Record<string, { Back?: string; Front?: string; }>; }; }>; //#endregion //#region src/types/statistic.d.ts type ReviewStatisticTuple = [reviewTime: number, cardID: number, usn: number, buttonPressed: number, newInterval: number, previousInterval: number, newFactor: number, reviewDuration: number, reviewType: number]; type StatisticRequests = Request<'cardReviews', 6, { deck: string; startID: number; }, ReviewStatisticTuple[]> | Request<'getCollectionStatsHTML', 6, { wholeCollection: boolean; }, string> | Request<'getLatestReviewID', 6, { deck: string; }, number> | Request<'getNumCardsReviewedByDay', 6, never, Array<[string, number]>> | Request<'getNumCardsReviewedToday', 6, never, number> | Request<'getReviewsOfCards', 6, { cards: string[]; }, Record<string, Array<{ /** ButtonPressed */ ease: number; /** NewFactor */ factor: number; /** ReviewTime */ id: number; /** NewInterval */ ivl: number; /** PreviousInterval */ lastIvl: number; /** ReviewDuration */ time: number; /** ReviewType */ type: number; /** Usn */ usn: number; }>>> | Request<'insertReviews', 6, { reviews: ReviewStatisticTuple[]; }>; //#endregion //#region src/types/shared.d.ts /** * Abstract wrapper over an Anki Connect action / response */ type Request<Action extends string, Version extends AnkiConnectVersion, Params = never, Result = null> = { action: Action; params: Params; response: { error: null | string; result: Result; }; version: Version; }; /** * Requests */ type Requests = CardRequests | DeckRequests | GraphicalRequests | MediaRequests | MiscellaneousRequests | ModelRequests | NoteRequests | StatisticRequests; type AnkiConnectVersion = 6; type Actions = Requests['action']; type ActionsWithParams = { [K in Actions]: ParamsForAction<K> extends never ? never : K }[Actions]; type ActionsWithoutParams = { [K in Actions]: ParamsForAction<K> extends never ? K : never }[Actions]; type ParamsForAction<T extends Requests['action']> = Extract<Requests, { action: T; }>['params']; type ResponseForAction<T extends Requests['action']> = Extract<Requests, { action: T; }>['response']; //#endregion //#region src/types/card.d.ts type CardBrowserColumns = 'answer' | 'cardDue' | 'cardEase' | 'cardIvl' | 'cardLapses' | 'cardMod' | 'cardReps' | 'deck' | 'note' | 'noteCrt' | 'noteFld' | 'noteMod' | 'noteTags' | 'question' | 'template' | (string & {}); type CardValueKeys = 'data' | 'did' | 'due' | 'factor' | 'flags' | 'id' | 'ivl' | 'lapses' | 'left' | 'mod' | 'odid' | 'odue' | 'ord' | 'queue' | 'reps' | 'type' | 'usn'; type CardInfo = { answer: string; buttons?: number[]; cardId: number; css: string; deckName: string; due: number; fieldOrder: number; fields: Record<string, { order: number; value: string; }>; interval: number; lapses: number; left: number; mod: number; modelName: string; nextReviews: string[]; note: number; ord: number; question: string; queue: number; reps: number; template: string; type: number; }; type CardRequests = Request<'answerCards', 6, { answers: Array<{ cardId: number; ease: number; }>; }, boolean[]> | Request<'areDue', 6, { cards: number[]; }, boolean[]> | Request<'areSuspended', 6, { cards: number[]; }, Array<boolean | null>> | Request<'cardsInfo', 6, { cards: number[]; }, CardInfo[]> | Request<'cardsModTime', 6, { cards: number[]; }, { cardId: number; mod: number; }> | Request<'cardsToNotes', 6, { cards: number[]; }, number[]> | Request<'findCards', 6, { query: string; }, number[]> | Request<'forgetCards', 6, { cards: number[]; }> | Request<'getEaseFactors', 6, { cards: number[]; }, number[]> | Request<'getIntervals', 6, { cards: number[]; complete?: boolean; }, number[] | number[][]> | Request<'relearnCards', 6, { cards: number[]; }> | Request<'setDueDate', 6, { cards: number[]; days: string; }, boolean> | Request<'setEaseFactors', 6, { cards: number[]; easeFactors: number[]; }, boolean[]> | Request<'setSpecificValueOfCard', 6, { card: number; keys: CardValueKeys[]; newValues: string[]; }, boolean[]> | Request<'suspend', 6, { cards: number[]; }, boolean> | Request<'suspended', 6, { card: number; }, boolean> | Request<'unsuspend', 6, { cards: number[]; }, boolean>; //#endregion //#region src/client.d.ts /** * Subset of built-in Fetch interface that's actually used by Anki, for ease of * external re-implementation when passing a custom fetch function to * YankiClient. */ type YankiFetchAdapter = (input: string, init?: { body?: string; headers?: Record<string, string>; method?: string; mode?: RequestMode; }) => Promise<undefined | { headers: Headers | Record<string, string>; json(): Promise<any>; status: number; }>; /** Optional options to pass when instantiating a new YankiConnect instance. */ type YankiConnectOptions = { /** * Attempt to open the desktop Anki.app if it's not already running. * * - `true` will always attempt to open Anki _when a request is made_. This * might introduce significant latency on the first launch. * - `false` will never attempt to open Anki. Requests will fail until * something or someone else opens the Anki app. * - `immediately` is a special option that will open Anki when the client is * instantiated. * * The Anki desktop app must be running for the client and the underlying * Anki-Connect service to work. * * Currently supported on macOS only. * * The client does not attempt to close the app. * @default false */ autoLaunch: 'immediately' | boolean; /** * Advanced option to customize the resource fetch implementation used to make requests to Anki-Connect. * * Note that the signature reflects the subset of the built-in Fetch interface that's actually used by yanki-connect. * * The exact signature of this option is subject to change in the future. * @default fetch */ fetchAdapter: undefined | YankiFetchAdapter; /** * Host where the Anki-Connect service is running. * @default 'http://127.0.0.1' */ host: string; /** * Anki-Connect security key (optional) * @default undefined */ key: string | undefined; /** * Port where the Anki-Connect service is running. * @default 8765 */ port: number; /** * Anki-Connect API version. * * Only API version 6 is supported for now. * @default 6 */ version: AnkiConnectVersion; }; declare const defaultYankiConnectOptions: YankiConnectOptions; /** * __YankiConnect is a client for the [Anki-Connect * API](https://git.sr.ht/~foosoft/anki-connect/tree/25.11.9.0/item/README.md)__. * * It implements every endpoint from Anki-Connect version 25.11.9.0, released 2025-11-09. * * Inline documentation is by the Anki-Connect authors, generated from [the * readme.md](https://git.sr.ht/~foosoft/anki-connect/tree/25.11.9.0/item/README.md) */ declare class YankiConnect { /** * __Card Actions__ * * [Documentation](https://git.sr.ht/~foosoft/anki-connect/tree/25.11.9.0/item/README.md#card-actions) */ readonly card: { /** * Answer cards. Ease is between 1 (Again) and 4 (Easy). Will start the * timer immediately before answering. Returns true if card exists, `false` * otherwise. */ answerCards: (params: { answers: Array<{ cardId: number; ease: number; }>; }) => Promise<boolean[]>; /** * Returns an array indicating whether each of the given cards is due (in * the same order). Note: cards in the learning queue with a large interval * (over 20 minutes) are treated as not due until the time of their interval * has passed, to match the way Anki treats them when reviewing. */ areDue: (params: { cards: number[]; }) => Promise<boolean[]>; /** * Returns an array indicating whether each of the given cards is suspended * (in the same order). If card doesn’t exist returns `null`. */ areSuspended: (params: { cards: number[]; }) => Promise<(boolean | null)[]>; /** * Returns a list of objects containing for each card ID the card fields, * front and back sides including CSS, note type, the note that the card * belongs to, and deck name, last modification timestamp as well as ease * and interval. */ cardsInfo: (params: { cards: number[]; }) => Promise<CardInfo[]>; /** * Returns a list of objects containing for each card ID the modification * time. This function is about 15 times faster than executing `cardsInfo`. */ cardsModTime: (params: { cards: number[]; }) => Promise<{ cardId: number; mod: number; }>; /** * Returns an unordered array of note IDs for the given card IDs. For cards * with the same note, the ID is only given once in the array. */ cardsToNotes: (params: { cards: number[]; }) => Promise<number[]>; /** * Returns an array of card IDs for a given query. Functionally identical to * `guiBrowse` but doesn’t use the GUI for better performance. */ findCards: (params: { query: string; }) => Promise<number[]>; /** * Forget cards, making the cards new again. */ forgetCards: (params: { cards: number[]; }) => Promise<null>; /** * Returns an array with the ease factor for each of the given cards (in the * same order). */ getEaseFactors: (params: { cards: number[]; }) => Promise<number[]>; /** * Returns an array of the most recent intervals for each given card ID, or * a 2-dimensional array of all the intervals for each given card ID when * complete is `true`. Negative intervals are in seconds and positive * intervals in days. */ getIntervals: (params: { cards: number[]; complete?: boolean; }) => Promise<number[] | number[][]>; /** * Make cards be “relearning”. */ relearnCards: (params: { cards: number[]; }) => Promise<null>; /** * Set Due Date. Turns cards into review cards if they are new, and makes * them due on a certain date. * * - 0 = today * - 1! = tomorrow + change interval to 1 * - 3-7 = random choice of 3-7 days */ setDueDate: (params: { cards: number[]; days: string; }) => Promise<boolean>; /** * Sets ease factor of cards by card ID; returns `true` if successful (all * cards existed) or `false` otherwise. */ setEaseFactors: (params: { cards: number[]; easeFactors: number[]; }) => Promise<boolean[]>; /** * Sets specific value of a single card. Given the risk of wreaking havoc in * the database when changing some of the values of a card, some of the keys * require the argument “warning_check” set to True. This can be used to set * a card’s flag, change it’s ease factor, change the review order in a * filtered deck and change the column “data” (not currently used by anki * apparently), and many other values. A list of values and explanation of * their respective utility can be found at [AnkiDroid’s * wiki](https://github.com/ankidroid/Anki-Android/wiki/Database-Structure). */ setSpecificValueOfCard: (params: { card: number; keys: ("data" | "did" | "due" | "factor" | "flags" | "id" | "ivl" | "lapses" | "left" | "mod" | "odid" | "odue" | "ord" | "queue" | "reps" | "type" | "usn")[]; newValues: string[]; }) => Promise<boolean[]>; /** * Suspend cards by card ID; returns `true` if successful (at least one card * wasn’t already suspended) or `false` otherwise. */ suspend: (params: { cards: number[]; }) => Promise<boolean>; /** * Check if card is suspended by its ID. Returns `true` if suspended, * `false` otherwise. */ suspended: (params: { card: number; }) => Promise<boolean>; /** * Unsuspend cards by card ID; returns `true` if successful (at least one * card was previously suspended) or `false` otherwise. */ unsuspend: (params: { cards: number[]; }) => Promise<boolean>; }; /** * __Deck Actions__ * * [Documentation](https://git.sr.ht/~foosoft/anki-connect/tree/25.11.9.0/item/README.md#deck-actions) */ readonly deck: { /** * Moves cards with the given IDs to a different deck, creating the deck if * it doesn’t exist yet. */ changeDeck: (params: { cards: number[]; deck: string; }) => Promise<null>; /** * Creates a new configuration group with the given name, cloning from the * group with the given ID, or from the default group if this is * unspecified. Returns the ID of the new configuration group, or `false` if * the specified group to clone from does not exist. */ cloneDeckConfigId: (params: { cloneFrom: number; name: string; }) => Promise<number | false>; /** * Create a new empty deck. Will not overwrite a deck that exists with the * same name. */ createDeck: (params: { deck: string; }) => Promise<number>; /** * Gets the complete list of deck names for the current user. */ deckNames: () => Promise<string[]>; /** * Gets the complete list of deck names and their respective IDs for the * current user. */ deckNamesAndIds: () => Promise<Record<string, number>>; /** * Deletes decks with the given names. The argument `cardsToo` must be * specified and set to `true`. */ deleteDecks: (params: { cardsToo: true; decks: string[]; }) => Promise<null>; /** * Gets the configuration group object for the given deck. */ getDeckConfig: (params: { deck: string; }) => Promise<{ autoplay: boolean; dyn: 1 | false; id: number; lapse: { delays: number[]; leechAction: number; leechFails: number; minInt: number; mult: number; }; maxTaken: number; mod: number; name: string; new: { bury: boolean; delays: number[]; initialFactor: number; ints: number[]; order: number; perDay: number; separate: boolean; }; replayq: boolean; rev: { bury: boolean; ease4: number; fuzz: number; ivlFct: number; maxIvl: number; minSpace: number; perDay: number; }; timer: number; usn: number; }>; /** * Accepts an array of card IDs and returns an object with each deck name as * a key, and its value an array of the given cards which belong to it. */ getDecks: (params: Record<"cards", number[]>) => Promise<Record<string, number[]>>; /** Gets statistics such as total cards and cards due for the given decks. */ getDeckStats: (params: { decks: string[]; }) => Promise<Record<string, { deck_id: number; learn_count: number; name: string; new_count: number; review_count: number; total_in_deck: number; }>>; /** * Removes the configuration group with the given ID, returning `true` if * successful, or `false` if attempting to remove either the default * configuration group (ID = 1) or a configuration group that does not * exist. */ removeDeckConfigId: (params: { configId: number; }) => Promise<boolean>; /** * Saves the given configuration group, returning `true` on success or * `false` if the ID of the configuration group is invalid (such as when it * does not exist). */ saveDeckConfig: (params: { config: { autoplay: boolean; dyn: 1 | false; id: number; lapse: { delays: number[]; leechAction: number; leechFails: number; minInt: number; mult: number; }; maxTaken: number; mod: number; name: string; new: { bury: boolean; delays: number[]; initialFactor: number; ints: number[]; order: number; perDay: number; separate: boolean; }; replayq: boolean; rev: { bury: boolean; ease4: number; fuzz: number; ivlFct: number; maxIvl: number; minSpace: number; perDay: number; }; timer: number; usn: number; }; }) => Promise<boolean>; /** * Changes the configuration group for the given decks to the one with the * given ID. Returns `true` on success or `false` if the given configuration * group or any of the given decks do not exist. */ setDeckConfigId: (params: { configId: number; decks: string[]; }) => Promise<boolean>; }; /** * __Graphical Actions__ * * [Documentation](https://git.sr.ht/~foosoft/anki-connect/tree/25.11.9.0/item/README.md#graphical-actions) */ readonly graphical: { /** * Invokes the _Add Cards_ dialog, presets the note using the given deck and * model, with the provided field values and tags. Invoking it multiple * times closes the old window and _reopen the window_ with the new provided * values. * * Audio, video, and picture files can be embedded into the fields via the * `audio`, `video`, and `picture` keys, respectively. Refer to the * documentation of `addNote` and `storeMediaFile` for an explanation of * these fields. * * The result is the ID of the note which would be added, if the user chose * to confirm the _Add Cards_ dialogue. */ guiAddCards: (params: { note: Note; }) => Promise<number>; /** * Answers the current card; returns `true` if succeeded or `false` * otherwise. Note that the answer for the current card must be displayed * before before any answer can be accepted by Anki. */ guiAnswerCard: (params: { ease: number; }) => Promise<boolean>; /** * Invokes the _Card Browser_ dialog and searches for a given query. Returns * an array of identifiers of the cards that were found. Query syntax is * [documented here](https://docs.ankiweb.net/searching.html). * * Optionally, the `reorderCards` property can be provided to reorder the * cards shown in the _Card Browser_. This is an array including the `order` * and `columnId` objects. `order` can be either `ascending` or `descending` * while `columnId` can be one of several column identifiers (as documented * in the [Anki source * code](https://github.com/ankitects/anki/blob/main/rslib/src/browser_table.rs)). * The specified column needs to be visible in the _Card Browser_. */ guiBrowse: (params: { query: string; reorderCards?: { columnId: CardBrowserColumns; order: "ascending" | "descending"; }; }) => Promise<number[]>; /** * Requests a database check, but returns immediately without waiting for * the check to complete. Therefore, the action will always return `true` * even if errors are detected during the database check. */ guiCheckDatabase: () => Promise<true>; /** * Returns information about the current card or `null` if not in review * mode. */ guiCurrentCard: () => Promise<CardInfo | null>; /** * Opens the _Deck Browser_ dialog. */ guiDeckBrowser: () => Promise<null>; /** * Opens the _Deck Overview_ dialog for the deck with the given name; * returns `true` if succeeded or `false` otherwise. */ guiDeckOverview: (params: { name: string; }) => Promise<boolean>; /** * Starts review for the deck with the given name; returns `true` if * succeeded or `false` otherwise. */ guiDeckReview: (params: { name: string; }) => Promise<boolean>; /** * Opens the _Edit_ dialog with a note corresponding to given note ID. The * dialog is similar to the _Edit Current_ dialog, but: * * - has a Preview button to preview the cards for the note * - has a Browse button to open the browser with these cards * - has Previous/Back buttons to navigate the history of the dialog * - has no bar with the Close button */ guiEditNote: (params: { note: number; }) => Promise<null>; /** * Schedules a request to gracefully close Anki. This operation is * asynchronous, so it will return immediately and won’t wait until the Anki * process actually terminates. */ guiExitAnki: () => Promise<null>; /** * Invokes the _Import… (Ctrl+Shift+I)_ dialog with an optional file path. * Brings up the dialog for user to review the import. Supports all file * types that Anki supports. Brings open file dialog if no path is provided. * Forward slashes must be used in the path on Windows. Only supported for * Anki 2.1.52+. */ guiImportFile: (params: { path: string; }) => Promise<null>; /** * Plays any Audio for the current side of the current card; returns true if * succeeded or false otherwise. */ guiPlayAudio: () => Promise<true>; /** * Finds the open instance of the Card Browser dialog and selects a card * given a card identifier. Returns true if the Card Browser is open, false * otherwise. */ guiSelectCard: (params: { card: number; }) => Promise<boolean>; /** * Finds the open instance of the _Card Browser_ dialog and returns an array * of identifiers of the notes that are selected. Returns an empty list if * the browser is not open. */ guiSelectedNotes: () => Promise<number[]>; /** * @deprecated Actually selects card IDs. Use `guiSelectCard` instead.' */ guiSelectNote: (params: { note: number; }) => Promise<boolean>; /** * Shows answer text for the current card; returns `true` if in review mode * or `false` otherwise. */ guiShowAnswer: () => Promise<boolean>; /** * Shows question text for the current card; returns `true` if in review * mode or `false` otherwise. */ guiShowQuestion: () => Promise<boolean>; /** * Starts or resets the `timerStarted` value for the current card. This is * useful for deferring the start time to when it is displayed via the API, * allowing the recorded time taken to answer the card to be more accurate * when calling `guiAnswerCard`. */ guiStartCardTimer: () => Promise<true>; /** * Undo the last action / card; returns `true` if succeeded or `false` * otherwise. */ guiUndo: () => Promise<boolean>; }; /** * __Media Actions__ * * [Documentation](https://git.sr.ht/~foosoft/anki-connect/tree/25.11.9.0/item/README.md#media-actions) */ readonly media: { /** * Deletes the specified file inside the media folder. */ deleteMediaFile: (params: { filename: string; }) => Promise<null>; /** * Gets the full path to the `collection.media` folder of the currently * opened profile. */ getMediaDirPath: () => Promise<string>; /** * Gets the names of media files matched the pattern. Returning all names by * default. */ getMediaFilesNames: (params: { pattern: string; }) => Promise<string[]>; /** * Retrieves the base64-encoded contents of the specified file, returning * `false` if the file does not exist. */ retrieveMediaFile: (params: { filename: string; }) => Promise<string | false>; /** * Stores a file with the specified base64-encoded contents inside the media * folder. Alternatively you can specify a absolute file path, or a url from * where the file shell be downloaded. If more than one of `data`, `path` * and `url` are provided, the `data` field will be used first, then `path`, * and finally `url`. To prevent Anki from removing files not used by any * cards (e.g. for configuration files), prefix the filename with an * underscore. These files are still synchronized to AnkiWeb. Any existing * file with the same name is deleted by default. Set `deleteExisting` to * `false` to prevent that by [letting Anki give the new file a * non-conflicting * name](https://github.com/ankitects/anki/blob/aeba725d3ea9628c73300648f748140db3fdd5ed/rslib/src/media/files.rs#L194). */ storeMediaFile: (params: { data?: string; deleteExisting?: boolean; filename: string; path?: string; url?: string; }) => Promise<string>; }; /** * __Miscellaneous Actions__ * * [Documentation](https://git.sr.ht/~foosoft/anki-connect/tree/25.11.9.0/item/README.md#miscellaneous-actions) */ readonly miscellaneous: { /** * Gets information about the AnkiConnect APIs available. The request * supports the following params: * * - `scopes` - An array of scopes to get reflection information about. The * only currently supported value is `"actions"`. * - `actions` - Either `null` or an array of API method names to check for. * If the value is `null`, the result will list all of the available API * actions. If the value is an array of strings, the result will only * contain actions which were in this array. */ apiReflect: (params: { actions: null | string[]; scopes: Array<"actions">; }) => Promise<{ actions: string[]; scopes: string[]; }>; /** * Exports a given deck in `.apkg` format. Returns `true` if successful or * `false` otherwise. The optional property `includeSched` (default is * `false`) can be specified to include the cards’ scheduling data. */ exportPackage: (params: { deck: string; includeSched?: boolean; path: string; }) => Promise<boolean>; /** * Retrieve the active profile. */ getActiveProfile: () => Promise<string>; /** * Retrieve the list of profiles. */ getProfiles: () => Promise<string[]>; /** * Imports a file in `.apkg` format into the collection. Returns `true` if * successful or `false` otherwise. Note that the file path is relative to * Anki’s collection.media folder, not to the client. */ importPackage: (params: { path: string; }) => Promise<boolean>; /** * Selects the profile specified in request. */ loadProfile: (params: { name: string; }) => Promise<true>; /** * Performs multiple actions in one request, returning an array with the * response of each action (in the given order). */ multi: (params: { actions: Array<{ action: Requests["action"]; params?: Requests["params"]; version?: number; }>; }) => Promise<({ error: null | string; result: boolean[]; } | { error: null | string; result: (boolean | null)[]; } | { error: null | string; result: CardInfo[]; } | { error: null | string; result: { cardId: number; mod: number; }; } | { error: null | string; result: number[]; } | { error: null | string; result: null; } | { error: null | string; result: number[] | number[][]; } | { error: null | string; result: boolean; } | { error: null | string; result: number | false; } | { error: null | string; result: number; } | { error: null | string; result: string[]; } | { error: null | string; result: Record<string, number>; } | { error: null | string; result: { autoplay: boolean; dyn: 1 | false; id: number; lapse: { delays: number[]; leechAction: number; leechFails: number; minInt: number; mult: number; }; maxTaken: number; mod: number; name: string; new: { bury: boolean; delays: number[]; initialFactor: number; ints: number[]; order: number; perDay: number; separate: boolean; }; replayq: boolean; rev: { bury: boolean; ease4: number; fuzz: number; ivlFct: number; maxIvl: number; minSpace: number; perDay: number; }; timer: number; usn: number; }; } | { error: null | string; result: Record<string, number[]>; } | { error: null | string; result: Record<string, { deck_id: number; learn_count: number; name: string; new_count: number; review_count: number; total_in_deck: number; }>; } | { error: null | string; result: true; } | { error: null | string; result: CardInfo | null; } | { error: null | string; result: string; } | { error: null | string; result: string | false; } | { error: null | string; result: { actions: string[]; scopes: string[]; }; } | { error: null | string; result: ({ error: null | string; result: boolean[]; } | { error: null | string; result: (boolean | null)[]; } | { error: null | string; result: CardInfo[]; } | { error: null | string; result: { cardId: number; mod: number; }; } | { error: null | string; result: number[]; } | { error: null | string; result: null; } | { error: null | string; result: number[] | number[][]; } | { error: null | string; result: boolean; } | { error: null | string; result: number | false; } | { error: null | string; result: number; } | { error: null | string; result: string[]; } | { error: null | string; result: Record<string, number>; } | { error: null | string; result: { autoplay: boolean; dyn: 1 | false; id: number; lapse: { delays: number[]; leechAction: number; leechFails: number; minInt: number; mult: number; }; maxTaken: number; mod: number; name: string; new: { bury: boolean; delays: number[]; initialFactor: number; ints: number[]; order: number; perDay: number; separate: boolean; }; replayq: boolean; rev: { bury: boolean; ease4: number; fuzz: number; ivlFct: number; maxIvl: number; minSpace: number; perDay: number; }; timer: number; usn: number; }; } | { error: null | string; result: Record<string, number[]>; } | { error: null | string; result: Record<string, { deck_id: number; learn_count: number; name: string; new_count: number; review_count: number; total_in_deck: number; }>; } | { error: null | string; result: true; } | { error: null | string; result: CardInfo | null; } | { error: null | string; result: string; } | { error: null | string; result: string | false; } | { error: null | string; result: { actions: string[]; scopes: string[]; }; } | /*elided*/any | { error: null | string; result: { permission: "denied"; } | { permission: "granted"; requireApiKey: boolean; version: boolean; }; } | { error: null | string; result: { css: string; did: null; flds: { collapsed: boolean; description: string; excludeFromSearch: boolean; font: string; id: number; name: string; ord: number; plainText: boolean; preventDeletion: boolean; rtl: boolean; size: number; sticky: boolean; tag: null; }[]; id: number; latexPost: string; latexPre: string; latexsvg: boolean; mod: number; name: string; originalStockKind: number; req: Array<[number, string, number[]]>; sortf: number; tmpls: { afmt: string; bafmt: string; bfont: string; bqfmt: string; bsize: number; did: null; id: number; name: string; ord: number; qfmt: string; }[]; type: number; usn: number; }; } | { error: null | string; result: { css: string; did: null; flds: { collapsed: boolean; description: string; excludeFromSearch: boolean; font: string; id: number; name: string; ord: number; plainText: boolean; preventDeletion: boolean; rtl: boolean; size: number; sticky: boolean; tag: null; }[]; id: number; latexPost: string; latexPre: string; latexsvg: boolean; mod: number; name: string; originalStockKind: number; req: Array<[number, string, number[]]>; sortf: number; tmpls: { afmt: string; bafmt: string; bfont: string; bqfmt: string; bsize: number; did: null; id: number; name: string; ord: number; qfmt: string; }[]; type: number; usn: number; }[]; } | { error: null | string; result: { css: string; did: null; flds: { collapsed: boolean; description: string; excludeFromSearch: boolean; font: string; id: number; name: string; ord: number; plainText: boolean; preventDeletion: boolean; rtl: boolean; size: number; sticky: boolean; tag: null; }[]; id: number; latexPost: string; latexPre: string; latexsvg: boolean; mod: number; name: string; originalStockKind: number; req: Array<[number, string, number[]]>; sortf: number; tmpls: { afmt: string; bafmt: string; bfont: string; bqfmt: string; bsize: number; did: null; id: number; name: string; ord: number; qfmt: string; }[]; type: number; usn: number; }[]; } | { error: null | string; result: Record<string, { font: string; size: number; }>; } | { error: null | string; result: Record<string, [string[], string[]]>; } | { error: null | string; result: { css: string; }; } | { error: null | string; result: Record<string, { [key: string]: string; Back: string; Front: string; }>; } | { error: null | string; result: number | null; } | { error: null | string; result: (string | null)[] | null; } | { error: null | string; result: ({ canAdd: false; error: string; } | { canAdd: true; })[]; } | { error: null | string; result: { cards: number[]; fields: Record<string, { order: number; value: string; }>; mod: number; modelName: string; noteId: number; profile: string; tags: string[]; }[]; } | { error: null | string; result: { mod: number; noteId: number; }[]; } | { error: null | string; result: [reviewTime: number, cardID: number, usn: number, buttonPressed: number, newInterval: number, previousInterval: number, newFactor: number, reviewDuration: number, reviewType: number][]; } | { error: null | string; result: [string, number][]; } | { error: null | string; result: Record<string, { ease: number; factor: number; id: number; ivl: number; lastIvl: number; time: number; type: number; usn: number; }[]>; } | { error: null | string; result: Requests["response"]; })[]; } | { error: null | string; result: { permission: "denied"; } | { permission: "granted"; requireApiKey: boolean; version: boolean; }; } | { error: null | string; result: { css: string; did: null; flds: { collapsed: boolean; description: string; excludeFromSearch: boolean; font: string; id: number; name: string; ord: number; plainText: boolean; preventDeletion: boolean; rtl: boolean; size: number; sticky: boolean; tag: null; }[]; id: number; latexPost: string; latexPre: string; latexsvg: boolean; mod: number; name: string; originalStockKind: number; req: Array<[number, string, number[]]>; sortf: number; tmpls: { afmt: string; bafmt: string; bfont: string; bqfmt: string; bsize: number; did: null; id: number; name: string; ord: number; qfmt: string; }[]; type: number; usn: number; }; } | { error: null | string; result: { css: string; did: null; flds: { collapsed: boolean; description: string; excludeFromSearch: boolean; font: string; id: number; name: string; ord: number; plainText: boolean; preventDeletion: boolean; rtl: boolean; size: numbe