@ankinize/sdk 0.0.0-stage → 0.1.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.
Files changed (42) hide show
  1. package/README.md +78 -2
  2. package/dist/batch.d.ts +157 -0
  3. package/dist/batch.js +263 -0
  4. package/dist/gen/client/client.gen.d.ts +2 -0
  5. package/dist/gen/client/client.gen.js +216 -0
  6. package/dist/gen/client/index.d.ts +10 -0
  7. package/dist/gen/client/index.js +6 -0
  8. package/dist/gen/client/types.gen.d.ts +120 -0
  9. package/dist/gen/client/types.gen.js +2 -0
  10. package/dist/gen/client/utils.gen.d.ts +37 -0
  11. package/dist/gen/client/utils.gen.js +228 -0
  12. package/dist/gen/client.gen.d.ts +12 -0
  13. package/dist/gen/client.gen.js +4 -0
  14. package/dist/gen/core/auth.gen.d.ts +25 -0
  15. package/dist/gen/core/auth.gen.js +14 -0
  16. package/dist/gen/core/bodySerializer.gen.d.ts +25 -0
  17. package/dist/gen/core/bodySerializer.gen.js +57 -0
  18. package/dist/gen/core/params.gen.d.ts +43 -0
  19. package/dist/gen/core/params.gen.js +109 -0
  20. package/dist/gen/core/pathSerializer.gen.d.ts +33 -0
  21. package/dist/gen/core/pathSerializer.gen.js +106 -0
  22. package/dist/gen/core/queryKeySerializer.gen.d.ts +18 -0
  23. package/dist/gen/core/queryKeySerializer.gen.js +92 -0
  24. package/dist/gen/core/serverSentEvents.gen.d.ts +71 -0
  25. package/dist/gen/core/serverSentEvents.gen.js +132 -0
  26. package/dist/gen/core/types.gen.d.ts +83 -0
  27. package/dist/gen/core/types.gen.js +2 -0
  28. package/dist/gen/core/utils.gen.d.ts +19 -0
  29. package/dist/gen/core/utils.gen.js +87 -0
  30. package/dist/gen/public.gen.d.ts +1 -0
  31. package/dist/gen/public.gen.js +2 -0
  32. package/dist/gen/sdk.gen.d.ts +504 -0
  33. package/dist/gen/sdk.gen.js +880 -0
  34. package/dist/gen/types.gen.d.ts +3452 -0
  35. package/dist/gen/types.gen.js +2 -0
  36. package/dist/index.d.ts +6 -0
  37. package/dist/index.js +5 -0
  38. package/dist/runtime.d.ts +19 -0
  39. package/dist/runtime.js +57 -0
  40. package/dist/typed.d.ts +90 -0
  41. package/dist/typed.js +51 -0
  42. package/package.json +38 -5
@@ -0,0 +1,880 @@
1
+ // This file is auto-generated by @hey-api/openapi-ts
2
+ import { client } from './client.gen.js';
3
+ import { buildClientParams } from './client/index.js';
4
+ /**
5
+ * List all decks
6
+ *
7
+ * Returns every deck in the collection, including the built-in `Default` deck and nested decks. A nested deck's name is its full path, such as `Languages::German`.
8
+ */
9
+ export const listDecks = (options) => (options?.client ?? client).get({
10
+ responseStyle: 'data',
11
+ security: [{ scheme: 'bearer', type: 'http' }],
12
+ url: '/api/v1/decks',
13
+ ...options
14
+ });
15
+ /**
16
+ * Create a deck
17
+ *
18
+ * Creates a deck and returns it. Use `::` in the name to nest it under a parent, for example `Languages::German`.
19
+ */
20
+ export const createDeck = (parameters, options) => {
21
+ const params = buildClientParams([parameters], [{ args: [{ in: 'headers', key: 'idempotencyKey', map: 'Idempotency-Key' }, { in: 'body', key: 'name' }] }]);
22
+ return (options?.client ?? client).post({
23
+ responseStyle: 'data',
24
+ security: [{ scheme: 'bearer', type: 'http' }],
25
+ url: '/api/v1/decks',
26
+ ...options,
27
+ ...params,
28
+ headers: {
29
+ 'Content-Type': 'application/json',
30
+ ...options?.headers,
31
+ ...params.headers
32
+ }
33
+ });
34
+ };
35
+ /**
36
+ * Delete a deck and its subdecks
37
+ *
38
+ * Deletes the deck, all of its subdecks and every card in them. Notes left with no cards are removed too.
39
+ *
40
+ * This cannot be undone. The response lists exactly which decks and cards were removed. Deleting is still allowed while the account is over its storage quota.
41
+ */
42
+ export const deleteDeck = (parameters, options) => {
43
+ const params = buildClientParams([parameters], [{ args: [{ in: 'headers', key: 'idempotencyKey', map: 'Idempotency-Key' }, { in: 'path', key: 'id' }] }]);
44
+ return (options?.client ?? client).delete({
45
+ responseStyle: 'data',
46
+ security: [{ scheme: 'bearer', type: 'http' }],
47
+ url: '/api/v1/decks/{id}',
48
+ ...options,
49
+ ...params
50
+ });
51
+ };
52
+ /**
53
+ * Get a deck by ID
54
+ *
55
+ * Returns one deck by its numeric id.
56
+ */
57
+ export const getDeck = (parameters, options) => {
58
+ const params = buildClientParams([parameters], [{ args: [{ in: 'path', key: 'id' }] }]);
59
+ return (options?.client ?? client).get({
60
+ responseStyle: 'data',
61
+ security: [{ scheme: 'bearer', type: 'http' }],
62
+ url: '/api/v1/decks/{id}',
63
+ ...options,
64
+ ...params
65
+ });
66
+ };
67
+ /**
68
+ * Rename a deck
69
+ *
70
+ * Changes a deck's name. The deck keeps its id and its cards, and its subdecks are renamed with it.
71
+ */
72
+ export const renameDeck = (parameters, options) => {
73
+ const params = buildClientParams([parameters], [{ args: [
74
+ { in: 'headers', key: 'idempotencyKey', map: 'Idempotency-Key' },
75
+ { in: 'path', key: 'id' },
76
+ { in: 'body', key: 'name' }
77
+ ] }]);
78
+ return (options?.client ?? client).patch({
79
+ responseStyle: 'data',
80
+ security: [{ scheme: 'bearer', type: 'http' }],
81
+ url: '/api/v1/decks/{id}',
82
+ ...options,
83
+ ...params,
84
+ headers: {
85
+ 'Content-Type': 'application/json',
86
+ ...options?.headers,
87
+ ...params.headers
88
+ }
89
+ });
90
+ };
91
+ /**
92
+ * List notes with pagination and filters
93
+ *
94
+ * Returns notes in ascending id order, one page at a time. Filters combine with AND.
95
+ *
96
+ * To read the next page, send the previous response's `nextCursor` as `cursor`. `nextCursor` is `null` on the last page.
97
+ */
98
+ export const listNotes = (parameters, options) => {
99
+ const params = buildClientParams([parameters], [{ args: [
100
+ { in: 'query', key: 'deckId' },
101
+ { in: 'query', key: 'notetypeId' },
102
+ { in: 'query', key: 'tag' },
103
+ { in: 'query', key: 'cursor' },
104
+ { in: 'query', key: 'limit' }
105
+ ] }]);
106
+ return (options?.client ?? client).get({
107
+ responseStyle: 'data',
108
+ security: [{ scheme: 'bearer', type: 'http' }],
109
+ url: '/api/v1/notes',
110
+ ...options,
111
+ ...params
112
+ });
113
+ };
114
+ /**
115
+ * Create a note and generate its cards
116
+ *
117
+ * Creates a note and generates its cards from the note type's templates.
118
+ *
119
+ * Name the note type with `notetypeName` and the deck with `deckName` (compared ignoring case; a nested deck is `Languages::German`), or send `notetypeId` and `deckId` instead. Exactly one of `notetypeName` and `notetypeId` is needed; without a deck the note goes to the `Default` deck. A name that matches nothing is `404`.
120
+ *
121
+ * `fields` is an object with one entry per field of the note type, keyed by the field's name in camelCase: `Back Extra` is `backExtra`. Each field of a note type shows its `key` in [Get a note type](#getNoteType). The field's exact name works as a key too. A field you leave out is empty; a key that names no field is `400 invalid_input` and lists the valid keys.
122
+ *
123
+ * Send a `guid` only when you import notes from somewhere else and need to keep a stable identity; otherwise one is generated. All fields together may not exceed 5 MiB.
124
+ */
125
+ export const createNote = (parameters, options) => {
126
+ const params = buildClientParams([parameters], [{ args: [
127
+ { in: 'headers', key: 'idempotencyKey', map: 'Idempotency-Key' },
128
+ { in: 'body', key: 'notetypeName' },
129
+ { in: 'body', key: 'notetypeId' },
130
+ { in: 'body', key: 'deckName' },
131
+ { in: 'body', key: 'deckId' },
132
+ { in: 'body', key: 'fields' },
133
+ { in: 'body', key: 'tags' },
134
+ { in: 'body', key: 'guid' }
135
+ ] }]);
136
+ return (options?.client ?? client).post({
137
+ responseStyle: 'data',
138
+ security: [{ scheme: 'bearer', type: 'http' }],
139
+ url: '/api/v1/notes',
140
+ ...options,
141
+ ...params,
142
+ headers: {
143
+ 'Content-Type': 'application/json',
144
+ ...options?.headers,
145
+ ...params.headers
146
+ }
147
+ });
148
+ };
149
+ /**
150
+ * Create many notes in one call
151
+ *
152
+ * Creates up to 200 notes in one call. It does what [Create a note](#createNote) does for each entry (also naming note types and decks by name), but in one transaction and with the note types, decks and tags looked up once, so importing is far faster than one request per note.
153
+ *
154
+ * The answer is `200` with one entry in `results` per note you sent, in the same order (`index`). An entry the collection refuses, such as an unknown deck or a key that names no field, is reported as `ok: false` with an `error`, and the others are still written. Send `atomic: true` to write all or nothing: if any entry is refused, nothing is written and the answer is `422` with the same body.
155
+ *
156
+ * A batch counts as one request per 10 notes (at least one) against your plan's rate limit. At most 2 batches run at once on the server; when it is busy the answer is `503` with `Retry-After`, and nothing was changed.
157
+ */
158
+ export const createNotesBatch = (parameters, options) => {
159
+ const params = buildClientParams([parameters], [{ args: [
160
+ { in: 'headers', key: 'idempotencyKey', map: 'Idempotency-Key' },
161
+ { in: 'body', key: 'notes' },
162
+ { in: 'body', key: 'atomic' }
163
+ ] }]);
164
+ return (options?.client ?? client).post({
165
+ responseStyle: 'data',
166
+ security: [{ scheme: 'bearer', type: 'http' }],
167
+ url: '/api/v1/notes/batch-create',
168
+ ...options,
169
+ ...params,
170
+ headers: {
171
+ 'Content-Type': 'application/json',
172
+ ...options?.headers,
173
+ ...params.headers
174
+ }
175
+ });
176
+ };
177
+ /**
178
+ * Edit many notes in one call
179
+ *
180
+ * Edits up to 200 notes in one call. It does what [Edit a note](#updateNote) does for each entry, but in one transaction with note types, decks and tags looked up once. Each entry names a note by `id` and may send `fields`, `tags`, or the tag edits `addTags` and `removeTags`; what it leaves out stays as it was. `tags` replaces all tags and can not be sent with `addTags` or `removeTags`. `removeTags` works as in Anki: a tag is matched ignoring case, and removing `lang` also removes `lang::de` and the other tags below it (`*` is not a wildcard). A note may appear once per call.
181
+ *
182
+ * The answer is `200` with one entry in `results` per entry you sent, in the same order (`index`). An entry the collection refuses, such as an unknown note or the wrong number of fields, is reported as `ok: false` with an `error`, and the others are still written. Send `atomic: true` to write all or nothing: if any entry is refused, nothing is written and the answer is `422` with the same body. `changed` counts notes that differed from what was stored.
183
+ *
184
+ * A batch counts as one request per 10 entries (at least one) against your plan's rate limit.
185
+ */
186
+ export const updateNotesBatch = (parameters, options) => {
187
+ const params = buildClientParams([parameters], [{ args: [
188
+ { in: 'headers', key: 'idempotencyKey', map: 'Idempotency-Key' },
189
+ { in: 'body', key: 'updates' },
190
+ { in: 'body', key: 'atomic' }
191
+ ] }]);
192
+ return (options?.client ?? client).post({
193
+ responseStyle: 'data',
194
+ security: [{ scheme: 'bearer', type: 'http' }],
195
+ url: '/api/v1/notes/batch-update',
196
+ ...options,
197
+ ...params,
198
+ headers: {
199
+ 'Content-Type': 'application/json',
200
+ ...options?.headers,
201
+ ...params.headers
202
+ }
203
+ });
204
+ };
205
+ /**
206
+ * Delete many notes in one call
207
+ *
208
+ * Deletes up to 1000 notes and every card made from them, in one transaction. Ids that do not exist are not an error; they are listed in `missingNoteIds`. This cannot be undone. Deleting is still allowed while the account is over its storage quota.
209
+ *
210
+ * A batch counts as one request per 10 ids (at least one) against your plan's rate limit.
211
+ */
212
+ export const deleteNotesBatch = (parameters, options) => {
213
+ const params = buildClientParams([parameters], [{ args: [{ in: 'headers', key: 'idempotencyKey', map: 'Idempotency-Key' }, { in: 'body', key: 'ids' }] }]);
214
+ return (options?.client ?? client).post({
215
+ responseStyle: 'data',
216
+ security: [{ scheme: 'bearer', type: 'http' }],
217
+ url: '/api/v1/notes/batch-delete',
218
+ ...options,
219
+ ...params,
220
+ headers: {
221
+ 'Content-Type': 'application/json',
222
+ ...options?.headers,
223
+ ...params.headers
224
+ }
225
+ });
226
+ };
227
+ /**
228
+ * Delete a note and its cards
229
+ *
230
+ * Deletes a note and every card made from it. This cannot be undone. Deleting is still allowed while the account is over its storage quota.
231
+ */
232
+ export const deleteNote = (parameters, options) => {
233
+ const params = buildClientParams([parameters], [{ args: [{ in: 'headers', key: 'idempotencyKey', map: 'Idempotency-Key' }, { in: 'path', key: 'id' }] }]);
234
+ return (options?.client ?? client).delete({
235
+ responseStyle: 'data',
236
+ security: [{ scheme: 'bearer', type: 'http' }],
237
+ url: '/api/v1/notes/{id}',
238
+ ...options,
239
+ ...params
240
+ });
241
+ };
242
+ /**
243
+ * Get note by ID with cards
244
+ *
245
+ * Returns one note, including the cards it produced.
246
+ */
247
+ export const getNote = (parameters, options) => {
248
+ const params = buildClientParams([parameters], [{ args: [{ in: 'path', key: 'id' }] }]);
249
+ return (options?.client ?? client).get({
250
+ responseStyle: 'data',
251
+ security: [{ scheme: 'bearer', type: 'http' }],
252
+ url: '/api/v1/notes/{id}',
253
+ ...options,
254
+ ...params
255
+ });
256
+ };
257
+ /**
258
+ * Update note fields or tags
259
+ *
260
+ * Changes a note's fields, its tags, or both. Anything you leave out stays as it was, including each field missing from `fields`: send only the fields that change. If the new field content makes a template produce a card it did not before, the new cards are returned in `newCards`.
261
+ *
262
+ * `changed` is `false` when the request matched what was already stored, and nothing is written.
263
+ */
264
+ export const updateNote = (parameters, options) => {
265
+ const params = buildClientParams([parameters], [{ args: [
266
+ { in: 'headers', key: 'idempotencyKey', map: 'Idempotency-Key' },
267
+ { in: 'path', key: 'id' },
268
+ { in: 'body', key: 'fields' },
269
+ { in: 'body', key: 'tags' }
270
+ ] }]);
271
+ return (options?.client ?? client).patch({
272
+ responseStyle: 'data',
273
+ security: [{ scheme: 'bearer', type: 'http' }],
274
+ url: '/api/v1/notes/{id}',
275
+ ...options,
276
+ ...params,
277
+ headers: {
278
+ 'Content-Type': 'application/json',
279
+ ...options?.headers,
280
+ ...params.headers
281
+ }
282
+ });
283
+ };
284
+ /**
285
+ * List all note types
286
+ *
287
+ * Returns the id and name of every note type. Use [Get a note type](#getNoteType) for its fields and templates.
288
+ */
289
+ export const listNoteTypes = (options) => (options?.client ?? client).get({
290
+ responseStyle: 'data',
291
+ security: [{ scheme: 'bearer', type: 'http' }],
292
+ url: '/api/v1/note-types',
293
+ ...options
294
+ });
295
+ /**
296
+ * Create note type (stock or custom)
297
+ *
298
+ * Creates a note type, either from one of Anki's stock designs or from your own fields and templates.
299
+ *
300
+ * Send `stock` (`basic`, `basic-and-reversed`, `basic-optional-reversed`, `basic-type-in-answer`, `cloze` or `image-occlusion`) to start from a stock design, and optionally `name` to rename it. Or send `fields` and `templates` to define it yourself.
301
+ */
302
+ export const createNoteType = (parameters, options) => {
303
+ const params = buildClientParams([parameters], [{ args: [
304
+ { in: 'headers', key: 'idempotencyKey', map: 'Idempotency-Key' },
305
+ { in: 'body', key: 'stock' },
306
+ { in: 'body', key: 'name' },
307
+ { in: 'body', key: 'kind' },
308
+ { in: 'body', key: 'fields' },
309
+ { in: 'body', key: 'templates' },
310
+ { in: 'body', key: 'css' },
311
+ { in: 'body', key: 'sortFieldIdx' }
312
+ ] }]);
313
+ return (options?.client ?? client).post({
314
+ responseStyle: 'data',
315
+ security: [{ scheme: 'bearer', type: 'http' }],
316
+ url: '/api/v1/note-types',
317
+ ...options,
318
+ ...params,
319
+ headers: {
320
+ 'Content-Type': 'application/json',
321
+ ...options?.headers,
322
+ ...params.headers
323
+ }
324
+ });
325
+ };
326
+ /**
327
+ * Delete a note type
328
+ *
329
+ * Deletes a note type and every note that uses it.
330
+ *
331
+ * This changes the collection's schema, so it needs `?acceptFullSync=true` (otherwise `409 full_sync_required`) and *Allow destructive schema changes via API* turned on under Settings → Developer (otherwise `403 destructive_change_disabled`).
332
+ */
333
+ export const deleteNoteType = (parameters, options) => {
334
+ const params = buildClientParams([parameters], [{ args: [
335
+ { in: 'headers', key: 'idempotencyKey', map: 'Idempotency-Key' },
336
+ { in: 'path', key: 'id' },
337
+ { in: 'query', key: 'acceptFullSync' }
338
+ ] }]);
339
+ return (options?.client ?? client).delete({
340
+ responseStyle: 'data',
341
+ security: [{ scheme: 'bearer', type: 'http' }],
342
+ url: '/api/v1/note-types/{id}',
343
+ ...options,
344
+ ...params
345
+ });
346
+ };
347
+ /**
348
+ * Get note type details with fields and templates
349
+ *
350
+ * Returns a note type with its fields and card templates, its CSS and its sort field.
351
+ */
352
+ export const getNoteType = (parameters, options) => {
353
+ const params = buildClientParams([parameters], [{ args: [{ in: 'path', key: 'id' }] }]);
354
+ return (options?.client ?? client).get({
355
+ responseStyle: 'data',
356
+ security: [{ scheme: 'bearer', type: 'http' }],
357
+ url: '/api/v1/note-types/{id}',
358
+ ...options,
359
+ ...params
360
+ });
361
+ };
362
+ /**
363
+ * Update note type fields, templates, or styling
364
+ *
365
+ * Changes a note type's name, CSS, sort field, fields or templates.
366
+ *
367
+ * Adding, reordering or renaming fields and templates is safe. Removing a field or template, or changing which fields a template needs, changes the collection's schema, so every device has to download the whole collection again on its next sync (a *full sync*). The request is refused with `409 full_sync_required` until you add `?acceptFullSync=true`.
368
+ *
369
+ * Removing a field or template also needs *Allow destructive schema changes via API* turned on under Settings → Developer, or the answer is `403 destructive_change_disabled`.
370
+ */
371
+ export const updateNoteType = (parameters, options) => {
372
+ const params = buildClientParams([parameters], [{ args: [
373
+ { in: 'headers', key: 'idempotencyKey', map: 'Idempotency-Key' },
374
+ { in: 'path', key: 'id' },
375
+ { in: 'query', key: 'acceptFullSync' },
376
+ { in: 'body', key: 'name' },
377
+ { in: 'body', key: 'css' },
378
+ { in: 'body', key: 'sortFieldIdx' },
379
+ { in: 'body', key: 'fields' },
380
+ { in: 'body', key: 'templates' }
381
+ ] }]);
382
+ return (options?.client ?? client).patch({
383
+ responseStyle: 'data',
384
+ security: [{ scheme: 'bearer', type: 'http' }],
385
+ url: '/api/v1/note-types/{id}',
386
+ ...options,
387
+ ...params,
388
+ headers: {
389
+ 'Content-Type': 'application/json',
390
+ ...options?.headers,
391
+ ...params.headers
392
+ }
393
+ });
394
+ };
395
+ /**
396
+ * Get the study queue of a deck
397
+ *
398
+ * Returns the cards Anki would show next in a deck, in the order it would show them: the deck (and its subdecks) is searched for learning cards due now, then reviews and day-learning cards, then new cards, under the daily limits of every deck preset and deck (including *New cards ignore review limit* and *Apply all parent limits*), with new-card gather and sort order, review order, FSRS orders, burying of siblings and the mixes of new cards and day-learning cards with reviews. The result matches the desktop client's queue for the same collection and moment.
399
+ *
400
+ * `counts` is what Anki shows above the buttons (new, learning, review). `cards` holds the first `limit` cards, each with a `kind` of `new`, `learning` or `review`; `total` is the length of the whole queue. Learning cards that are due within the preset's learn-ahead limit are listed at the end. Nothing is written, so asking again before you answer gives the same queue; after `POST /api/v1/cards/{id}/answer` ask again.
401
+ *
402
+ * Without `deckId` the collection's current deck is used. Only the v3 scheduler is supported (`409 card_state_error` otherwise). A filtered deck is queued with unlimited counts, in the order it was built in Anki (its cards keep that position).
403
+ */
404
+ export const getStudyQueue = (parameters, options) => {
405
+ const params = buildClientParams([parameters], [{ args: [{ in: 'query', key: 'deckId' }, { in: 'query', key: 'limit' }] }]);
406
+ return (options?.client ?? client).get({
407
+ responseStyle: 'data',
408
+ security: [{ scheme: 'bearer', type: 'http' }],
409
+ url: '/api/v1/queue',
410
+ ...options,
411
+ ...params
412
+ });
413
+ };
414
+ /**
415
+ * List all tags
416
+ *
417
+ * Returns every tag in the collection, sorted by name. A nested tag keeps Anki's `::` separator, such as `Languages::German`; searching `tag:Languages` also finds the notes tagged with the nested ones.
418
+ */
419
+ export const listTags = (options) => (options?.client ?? client).get({
420
+ responseStyle: 'data',
421
+ security: [{ scheme: 'bearer', type: 'http' }],
422
+ url: '/api/v1/tags',
423
+ ...options
424
+ });
425
+ /**
426
+ * Create a tag
427
+ *
428
+ * Creates a tag without putting it on a note, as Anki registers a tag when a note brings it. A name that is already used (ignoring case) answers `200` with `created: false` and the spelling that is stored, so sending it twice is safe. A nested name keeps the spelling of a parent that exists, as in Anki.
429
+ *
430
+ * A tag no note carries is removed by Anki's *Check Database* and *Clear Unused Tags*.
431
+ */
432
+ export const createTag = (parameters, options) => {
433
+ const params = buildClientParams([parameters], [{ args: [{ in: 'headers', key: 'idempotencyKey', map: 'Idempotency-Key' }, { in: 'body', key: 'name' }] }]);
434
+ return (options?.client ?? client).post({
435
+ responseStyle: 'data',
436
+ security: [{ scheme: 'bearer', type: 'http' }],
437
+ url: '/api/v1/tags',
438
+ ...options,
439
+ ...params,
440
+ headers: {
441
+ 'Content-Type': 'application/json',
442
+ ...options?.headers,
443
+ ...params.headers
444
+ }
445
+ });
446
+ };
447
+ /**
448
+ * Delete a tag
449
+ *
450
+ * Removes a tag and the tags nested under it from every note and from the list. The notes keep everything else. This cannot be undone. Deleting is still allowed while the account is over its storage quota.
451
+ */
452
+ export const deleteTag = (parameters, options) => {
453
+ const params = buildClientParams([parameters], [{ args: [{ in: 'headers', key: 'idempotencyKey', map: 'Idempotency-Key' }, { in: 'path', key: 'name' }] }]);
454
+ return (options?.client ?? client).delete({
455
+ responseStyle: 'data',
456
+ security: [{ scheme: 'bearer', type: 'http' }],
457
+ url: '/api/v1/tags/{name}',
458
+ ...options,
459
+ ...params
460
+ });
461
+ };
462
+ /**
463
+ * Get a tag by name
464
+ *
465
+ * Returns a tag and `noteCount`, the notes that carry it or one of its nested tags (the notes `tag:name` finds). A tag exists when it is in the list, when a nested tag is, or when a note carries it. The `name` in the path is the tag, percent-encoded, and is compared ignoring case.
466
+ */
467
+ export const getTag = (parameters, options) => {
468
+ const params = buildClientParams([parameters], [{ args: [{ in: 'path', key: 'name' }] }]);
469
+ return (options?.client ?? client).get({
470
+ responseStyle: 'data',
471
+ security: [{ scheme: 'bearer', type: 'http' }],
472
+ url: '/api/v1/tags/{name}',
473
+ ...options,
474
+ ...params
475
+ });
476
+ };
477
+ /**
478
+ * Rename a tag
479
+ *
480
+ * Renames a tag and every tag nested under it on all notes: renaming `Languages` to `Lang` makes `Languages::German` into `Lang::German`. The notes that change get a new modification time, so they sync. If the new name is already a tag, the two are merged, and a note that ends up with the tag twice keeps it once. Renaming a tag that no note carries renames it in the list.
481
+ *
482
+ * `notes` is how many notes were looked at and changed.
483
+ */
484
+ export const renameTag = (parameters, options) => {
485
+ const params = buildClientParams([parameters], [{ args: [
486
+ { in: 'headers', key: 'idempotencyKey', map: 'Idempotency-Key' },
487
+ { in: 'path', key: 'name' },
488
+ { in: 'body', key: 'newName' }
489
+ ] }]);
490
+ return (options?.client ?? client).patch({
491
+ responseStyle: 'data',
492
+ security: [{ scheme: 'bearer', type: 'http' }],
493
+ url: '/api/v1/tags/{name}',
494
+ ...options,
495
+ ...params,
496
+ headers: {
497
+ 'Content-Type': 'application/json',
498
+ ...options?.headers,
499
+ ...params.headers
500
+ }
501
+ });
502
+ };
503
+ /**
504
+ * Create many tags in one call
505
+ *
506
+ * Creates up to 200 tags in one call, in one transaction. It does what [Create a tag](#createTag) does for each name. The answer is `200` with one entry in `results` per name, in order; a name that is refused (such as one with a space) is `ok: false` with an `error` and the others are still created. Send `atomic: true` to write all or nothing: then the answer is `422` with the same body.
507
+ *
508
+ * A batch counts as one request per 10 names against your plan's rate limit.
509
+ */
510
+ export const createTagsBatch = (parameters, options) => {
511
+ const params = buildClientParams([parameters], [{ args: [
512
+ { in: 'headers', key: 'idempotencyKey', map: 'Idempotency-Key' },
513
+ { in: 'body', key: 'names' },
514
+ { in: 'body', key: 'atomic' }
515
+ ] }]);
516
+ return (options?.client ?? client).post({
517
+ responseStyle: 'data',
518
+ security: [{ scheme: 'bearer', type: 'http' }],
519
+ url: '/api/v1/tags/batch-create',
520
+ ...options,
521
+ ...params,
522
+ headers: {
523
+ 'Content-Type': 'application/json',
524
+ ...options?.headers,
525
+ ...params.headers
526
+ }
527
+ });
528
+ };
529
+ /**
530
+ * Rename many tags in one call
531
+ *
532
+ * Renames up to 200 tags in one call, in one pass over the notes. Each entry names a tag by `name` and gives its `newName`, as [Rename a tag](#renameTag) does. Two entries may use the same `newName` (that merges the tags), but an entry that touches another one (a `name` that is, contains or lies inside another entry's `name` or `newName`) is refused with `invalid_input`, because the result would depend on the order. Entries are reported in `results` as in [Create many notes](#createNotesBatch); `atomic: true` writes all or nothing.
533
+ */
534
+ export const updateTagsBatch = (parameters, options) => {
535
+ const params = buildClientParams([parameters], [{ args: [
536
+ { in: 'headers', key: 'idempotencyKey', map: 'Idempotency-Key' },
537
+ { in: 'body', key: 'updates' },
538
+ { in: 'body', key: 'atomic' }
539
+ ] }]);
540
+ return (options?.client ?? client).post({
541
+ responseStyle: 'data',
542
+ security: [{ scheme: 'bearer', type: 'http' }],
543
+ url: '/api/v1/tags/batch-update',
544
+ ...options,
545
+ ...params,
546
+ headers: {
547
+ 'Content-Type': 'application/json',
548
+ ...options?.headers,
549
+ ...params.headers
550
+ }
551
+ });
552
+ };
553
+ /**
554
+ * Delete many tags in one call
555
+ *
556
+ * Deletes up to 1000 tags, with the tags nested under them, from every note and from the list, in one transaction. Names that do not exist are not an error; they are listed in `missingNames`. This cannot be undone. Deleting is still allowed while the account is over its storage quota.
557
+ */
558
+ export const deleteTagsBatch = (parameters, options) => {
559
+ const params = buildClientParams([parameters], [{ args: [{ in: 'headers', key: 'idempotencyKey', map: 'Idempotency-Key' }, { in: 'body', key: 'names' }] }]);
560
+ return (options?.client ?? client).post({
561
+ responseStyle: 'data',
562
+ security: [{ scheme: 'bearer', type: 'http' }],
563
+ url: '/api/v1/tags/batch-delete',
564
+ ...options,
565
+ ...params,
566
+ headers: {
567
+ 'Content-Type': 'application/json',
568
+ ...options?.headers,
569
+ ...params.headers
570
+ }
571
+ });
572
+ };
573
+ /**
574
+ * Get the statistics of a search
575
+ *
576
+ * Returns the graphs of Anki's statistics screen for the cards a search matches (`q`, default every card) and the last `days` days of review history (`0`, the default, is all of it). The numbers are Anki's: the same counts, buckets and averages the desktop client draws, computed from the review log and the cards in place. Nothing is copied into another database. A request reads the review log once, so a big collection takes a moment; one that takes longer than 20 seconds is refused with `400 invalid_input` (narrow the search or the days). The server keeps the graphs of a search in memory for up to five minutes, and never past the end of the day, while the collection is unchanged, so a repeat request is answered without reading the collection again; any change to the collection ends that.
577
+ *
578
+ * Days are counted from the end of the current day, so `0` is today, `-1` yesterday and `1` tomorrow; a day starts at the collection's `rollover` hour and is read in its `localOffset` (UTC when unset), as `timing` says. `buttons`, `hours` and `trueRetention` count answers over a month, three months, a year and all time. `cardCounts` counts cards by kind, with suspended and buried cards counted separately or together. `eases` (SM-2) and `difficulty`, `stability` and `retrievability` (FSRS) cover the cards that have the data; `fsrs` says whether the collection has FSRS turned on. `retrievability` is the chance of recalling each card now, from its memory state and the time since its last review. Keys of the count objects are numbers: a day, a percent bin or an interval in days.
579
+ */
580
+ export const getStats = (parameters, options) => {
581
+ const params = buildClientParams([parameters], [{ args: [{ in: 'query', key: 'q' }, { in: 'query', key: 'days' }] }]);
582
+ return (options?.client ?? client).get({
583
+ responseStyle: 'data',
584
+ security: [{ scheme: 'bearer', type: 'http' }],
585
+ url: '/api/v1/stats',
586
+ ...options,
587
+ ...params
588
+ });
589
+ };
590
+ /**
591
+ * List media files
592
+ *
593
+ * Lists the collection's media files by name, 100 at a time (`limit` up to 1000). `prefix` keeps only the names that start with it. When `nextCursor` is not null, pass it as `cursor` to get the next page. Each item has the file's `size`, its `sha1` and `sha256`, the `contentType` it is served as, and the `usn` of its last change, which is the number the Anki media sync uses.
594
+ */
595
+ export const listMedia = (parameters, options) => {
596
+ const params = buildClientParams([parameters], [{ args: [
597
+ { in: 'query', key: 'prefix' },
598
+ { in: 'query', key: 'limit' },
599
+ { in: 'query', key: 'cursor' }
600
+ ] }]);
601
+ return (options?.client ?? client).get({
602
+ responseStyle: 'data',
603
+ security: [{ scheme: 'bearer', type: 'http' }],
604
+ url: '/api/v1/media',
605
+ ...options,
606
+ ...params
607
+ });
608
+ };
609
+ /**
610
+ * Delete a media file
611
+ *
612
+ * Deletes the file. Your devices are told on their next media sync, as when a file is deleted in Anki. The storage it used is freed once no other name uses the same bytes. A name that is not there is `404`.
613
+ */
614
+ export const deleteMedia = (parameters, options) => {
615
+ const params = buildClientParams([parameters], [{ args: [{ in: 'path', key: 'name' }] }]);
616
+ return (options?.client ?? client).delete({
617
+ responseStyle: 'data',
618
+ security: [{ scheme: 'bearer', type: 'http' }],
619
+ url: '/api/v1/media/{name}',
620
+ ...options,
621
+ ...params
622
+ });
623
+ };
624
+ /**
625
+ * Download a media file
626
+ *
627
+ * Returns the file's bytes. The type comes from the file name's extension only, never from the bytes, and every response says `X-Content-Type-Options: nosniff` and a `Content-Security-Policy` with `sandbox`, so a file from your collection cannot run script on this origin. Images, audio, video and fonts are shown inline; SVG, PDF and any other type are offered as downloads (`Content-Disposition: attachment`).
628
+ *
629
+ * The `ETag` is the file's SHA-256, so `If-None-Match` answers `304`. `Range: bytes=...` (one range) answers `206`, which lets a browser seek in audio and video; a range past the end is `416`.
630
+ *
631
+ * Instead of a key, the request may carry the `u`, `exp` and `sig` query parameters of a signed link. A signed link opens that one file for reading until it expires, which is how a card shown in a sandboxed frame loads its pictures: `GET /api/v1/cards/{id}/render` puts such links into the card unless you pass `mediaBaseUrl`. The links last an hour.
632
+ */
633
+ export const getMedia = (parameters, options) => {
634
+ const params = buildClientParams([parameters], [{ args: [{ in: 'headers', key: 'Range' }, { in: 'path', key: 'name' }] }]);
635
+ return (options?.client ?? client).get({
636
+ responseStyle: 'data',
637
+ security: [{ scheme: 'bearer', type: 'http' }],
638
+ url: '/api/v1/media/{name}',
639
+ ...options,
640
+ ...params
641
+ });
642
+ };
643
+ /**
644
+ * Store a media file
645
+ *
646
+ * Stores the request body as the file, creating it or replacing it. Send the bytes as they are (any `Content-Type`) with a `Content-Length` header; chunked uploads are refused with `411`. A file is at most 100 MiB and not empty.
647
+ *
648
+ * The name must be one Anki clients would keep as it is: at most 120 bytes of UTF-8, in Unicode NFC, with none of `[ ] < > : " / ? * ^ \ |` or control characters, no Windows device name (`CON`, `NUL`, `LPT1`...), and not ending in a space or a dot. A client rewrites any other name when it syncs, so the file would never settle between devices; the `422 invalid_media_name` says the name to use. `Thumbs.db` and `.DS_Store` are never synced and are refused as well.
649
+ *
650
+ * `201` means the file is new; `200` means it replaced a file (`created` is false) or the bytes were the same (`unchanged` is true, and the `usn` stays). A new or changed file gets the next `usn`, so the media sync sends it to your devices. A file that would take the storage over the quota is `403 over_quota`, and a collection already holding the most file names it may (deleted names count) is `403 media_entry_limit`; replacing a name never adds one.
651
+ */
652
+ export const putMedia = (parameters, options) => {
653
+ const params = buildClientParams([parameters], [{ args: [{ in: 'path', key: 'name' }, { key: 'body', map: 'body' }] }]);
654
+ return (options?.client ?? client).put({
655
+ bodySerializer: null,
656
+ responseStyle: 'data',
657
+ security: [{ scheme: 'bearer', type: 'http' }],
658
+ url: '/api/v1/media/{name}',
659
+ ...options,
660
+ ...params,
661
+ headers: {
662
+ 'Content-Type': 'application/octet-stream',
663
+ ...options?.headers,
664
+ ...params.headers
665
+ }
666
+ });
667
+ };
668
+ /**
669
+ * List cards with pagination and filters
670
+ *
671
+ * Returns the cards that match a search (`q`; every card when it is empty), in ascending id order, one page at a time. You can also filter by deck or by note. Paginate with `nextCursor` as for notes, with one difference: a search that has to look at every card, such as a regular expression or `prop:s`, stops after about 10,000 cards and returns what it found so far together with a `nextCursor`. A page can therefore hold fewer than `limit` cards, or none, while `nextCursor` is not `null`; keep following it until it is.
672
+ */
673
+ export const listCards = (parameters, options) => {
674
+ const params = buildClientParams([parameters], [{ args: [
675
+ { in: 'query', key: 'q' },
676
+ { in: 'query', key: 'deckId' },
677
+ { in: 'query', key: 'noteId' },
678
+ { in: 'query', key: 'cursor' },
679
+ { in: 'query', key: 'limit' }
680
+ ] }]);
681
+ return (options?.client ?? client).get({
682
+ responseStyle: 'data',
683
+ security: [{ scheme: 'bearer', type: 'http' }],
684
+ url: '/api/v1/cards',
685
+ ...options,
686
+ ...params
687
+ });
688
+ };
689
+ /**
690
+ * Edit many cards in one call
691
+ *
692
+ * Applies one change to up to 1000 cards, in one transaction: set a flag, move them to a deck, suspend or bury them. It does what [Edit a card](#updateCard) does for each id, with the same rules for `patch`.
693
+ *
694
+ * The answer is `200` with one entry in `results` per distinct id. A card that does not exist, or that sits in a filtered deck and so can not be moved, is reported as `ok: false`, and the others are still changed. Send `atomic: true` to write all or nothing: if any card is refused, nothing is written and the answer is `422` with the same body. `changed` counts the cards that differed from what was stored.
695
+ *
696
+ * A batch counts as one request per 10 ids (at least one) against your plan's rate limit.
697
+ */
698
+ export const updateCardsBatch = (parameters, options) => {
699
+ const params = buildClientParams([parameters], [{ args: [
700
+ { in: 'headers', key: 'idempotencyKey', map: 'Idempotency-Key' },
701
+ { in: 'body', key: 'ids' },
702
+ { in: 'body', key: 'patch' },
703
+ { in: 'body', key: 'atomic' }
704
+ ] }]);
705
+ return (options?.client ?? client).post({
706
+ responseStyle: 'data',
707
+ security: [{ scheme: 'bearer', type: 'http' }],
708
+ url: '/api/v1/cards/batch-update',
709
+ ...options,
710
+ ...params,
711
+ headers: {
712
+ 'Content-Type': 'application/json',
713
+ ...options?.headers,
714
+ ...params.headers
715
+ }
716
+ });
717
+ };
718
+ /**
719
+ * Delete many cards in one call
720
+ *
721
+ * Deletes up to 1000 cards in one transaction. A note whose last card is deleted is deleted with it. Ids that do not exist are not an error; they are listed in `missingCardIds`. This cannot be undone. Deleting is still allowed while the account is over its storage quota.
722
+ *
723
+ * A batch counts as one request per 10 ids (at least one) against your plan's rate limit.
724
+ */
725
+ export const deleteCardsBatch = (parameters, options) => {
726
+ const params = buildClientParams([parameters], [{ args: [{ in: 'headers', key: 'idempotencyKey', map: 'Idempotency-Key' }, { in: 'body', key: 'ids' }] }]);
727
+ return (options?.client ?? client).post({
728
+ responseStyle: 'data',
729
+ security: [{ scheme: 'bearer', type: 'http' }],
730
+ url: '/api/v1/cards/batch-delete',
731
+ ...options,
732
+ ...params,
733
+ headers: {
734
+ 'Content-Type': 'application/json',
735
+ ...options?.headers,
736
+ ...params.headers
737
+ }
738
+ });
739
+ };
740
+ /**
741
+ * Delete a card
742
+ *
743
+ * Deletes one card. If it was the last card of its note, the note is removed too. This cannot be undone. Deleting is still allowed while the account is over its storage quota.
744
+ */
745
+ export const deleteCard = (parameters, options) => {
746
+ const params = buildClientParams([parameters], [{ args: [{ in: 'headers', key: 'idempotencyKey', map: 'Idempotency-Key' }, { in: 'path', key: 'id' }] }]);
747
+ return (options?.client ?? client).delete({
748
+ responseStyle: 'data',
749
+ security: [{ scheme: 'bearer', type: 'http' }],
750
+ url: '/api/v1/cards/{id}',
751
+ ...options,
752
+ ...params
753
+ });
754
+ };
755
+ /**
756
+ * Get card details by ID
757
+ *
758
+ * Returns one card with its scheduling state: queue, due, interval, ease factor, repetitions and lapses.
759
+ */
760
+ export const getCard = (parameters, options) => {
761
+ const params = buildClientParams([parameters], [{ args: [{ in: 'path', key: 'id' }] }]);
762
+ return (options?.client ?? client).get({
763
+ responseStyle: 'data',
764
+ security: [{ scheme: 'bearer', type: 'http' }],
765
+ url: '/api/v1/cards/{id}',
766
+ ...options,
767
+ ...params
768
+ });
769
+ };
770
+ /**
771
+ * Edit a card
772
+ *
773
+ * Changes a card's flag, moves it to another deck, or suspends or buries it. Anything you leave out stays as it was.
774
+ *
775
+ * `flag` is 0 (none) to 7. `suspended` and `buried` cannot both be sent. Suspending keeps a card out of review until you send `suspended: false`; burying hides it only until the next day or until you unbury it. A suspended card is never buried. Moving a card clears its FSRS memory state; it is replayed from the review history with the new deck's parameters the next time the card is shown or answered. Cards in a filtered deck can neither be moved nor moved into one (`409 card_state_error`).
776
+ *
777
+ * `changed` is `false` when the request matched what was already stored.
778
+ */
779
+ export const updateCard = (parameters, options) => {
780
+ const params = buildClientParams([parameters], [{ args: [
781
+ { in: 'headers', key: 'idempotencyKey', map: 'Idempotency-Key' },
782
+ { in: 'path', key: 'id' },
783
+ { in: 'body', key: 'deckId' },
784
+ { in: 'body', key: 'flag' },
785
+ { in: 'body', key: 'suspended' },
786
+ { in: 'body', key: 'buried' }
787
+ ] }]);
788
+ return (options?.client ?? client).patch({
789
+ responseStyle: 'data',
790
+ security: [{ scheme: 'bearer', type: 'http' }],
791
+ url: '/api/v1/cards/{id}',
792
+ ...options,
793
+ ...params,
794
+ headers: {
795
+ 'Content-Type': 'application/json',
796
+ ...options?.headers,
797
+ ...params.headers
798
+ }
799
+ });
800
+ };
801
+ /**
802
+ * Render a card's front and back
803
+ *
804
+ * Renders the card as Anki shows it: the note's fields are put into the card template, so the question and the answer are ready to display. The answer includes the question above a divider, as in Anki.
805
+ *
806
+ * Everything is sanitized on the server before it is returned: scripts, event handlers, iframes, forms, `javascript:` links and remote styles are removed, and CSS is limited to a safe subset. The result is still *content from your collection*, so display it in a sandboxed `<iframe sandbox>` or `srcdoc` and not straight into your page.
807
+ *
808
+ * With `format=json` (the default) you get `question`, `answer` and `css`. With `format=html` you get one complete HTML document, with a `Content-Security-Policy` that allows no script and the `sandbox` directive, which is meant for `<iframe sandbox srcdoc>`: fetch it with your key and put the text in `srcdoc` (an iframe's `src` cannot send the key, and this server refuses to be framed). Media in a card is referred to by file name and listed in `media`. The file names in the question and answer are turned into signed links to `GET /api/v1/media/{name}` that last an hour, so the card shows its pictures and plays its audio from a sandboxed frame; or pass `mediaBaseUrl` (an `http(s)` URL ending in `/`) to have them point at files you host instead.
809
+ *
810
+ * **Typing the answer.** For `{{type:Field}}`, `{{type:nc:Field}}` (accents ignored) and `{{type:cloze:Field}}` the question holds `<div class="typeans" data-field="Field"></div>`, where your own input goes. Pass what the learner typed as `typedAnswer` (up to 1000 characters) and the answer shows the comparison Anki shows, computed the same way: a `<code id="typeans">` with the typed text and the expected text as `typeGood`, `typeBad` and `typeMissed` spans around an arrow, in the font and size of the field. The classes carry no colors, so style them in your page. Without `typedAnswer` the answer shows the expected text. A text too long to compare is shown as one change.
811
+ *
812
+ * **Formulas.** `\(...\)` and `\[...\]` are returned as written. Anki's `[$]...[/$]` and `[$$]...[/$$]` tags are rewritten to them, and `[latex]...[/latex]` becomes display math; images are not generated, because that needs a TeX installation. `math` is true when the question or the answer holds a formula. Typeset it in your page with MathJax 3 after inserting the HTML (`format=html` allows no script, so a formula stays as text there). TeX that is not math, such as packages or TikZ, is not supported.
813
+ *
814
+ * A template that cannot be rendered is `422 render_error`.
815
+ */
816
+ export const renderCard = (parameters, options) => {
817
+ const params = buildClientParams([parameters], [{ args: [
818
+ { in: 'path', key: 'id' },
819
+ { in: 'query', key: 'format' },
820
+ { in: 'query', key: 'typedAnswer' },
821
+ { in: 'query', key: 'mediaBaseUrl' }
822
+ ] }]);
823
+ return (options?.client ?? client).get({
824
+ responseStyle: 'data',
825
+ security: [{ scheme: 'bearer', type: 'http' }],
826
+ url: '/api/v1/cards/{id}/render',
827
+ ...options,
828
+ ...params
829
+ });
830
+ };
831
+ /**
832
+ * Preview the four answer buttons
833
+ *
834
+ * Shows what each answer button would do, without answering: the time until the card would next be due after Again, Hard, Good and Easy. This is the preview Anki shows above its buttons.
835
+ *
836
+ * Only the v3 scheduler is supported. The card must be answerable: not suspended or buried (`409 card_state_error`). A card in a filtered deck is previewed as Anki does: in a deck that reschedules, the buttons are the home deck preset's, and a review that comes before it was due is scheduled from the days it was early; in a deck that does not reschedule, the buttons are the preview delays (Again, Hard and Good come back after the deck's delays, a delay of 0 ends the preview, and Easy always ends it) and show `0` seconds when they end it.
837
+ *
838
+ * Review intervals are fuzzed and load balanced like Anki's: the day is drawn within the fuzz range, weighted towards days with fewer cards of the same preset due, the preset's Easy Days and (if it buries siblings) days away from the card's siblings. The draw is fixed by the card and its review count, so the preview, the answer and a repeat of either agree.
839
+ */
840
+ export const getCardScheduling = (parameters, options) => {
841
+ const params = buildClientParams([parameters], [{ args: [{ in: 'path', key: 'id' }] }]);
842
+ return (options?.client ?? client).get({
843
+ responseStyle: 'data',
844
+ security: [{ scheme: 'bearer', type: 'http' }],
845
+ url: '/api/v1/cards/{id}/scheduling',
846
+ ...options,
847
+ ...params
848
+ });
849
+ };
850
+ /**
851
+ * Answer (review) a card
852
+ *
853
+ * Answers a card, the same as pressing a button in Anki's reviewer. The card is rescheduled with the deck preset's v3 scheduler (or FSRS when the preset turns it on), a review-log entry is written, the deck's daily counts go up, and siblings are buried if the preset says so. A card that reaches the leech threshold gets the `leech` tag and, if the preset says so, is suspended.
854
+ *
855
+ * `rating` is `again`, `hard`, `good` or `easy` (or 1 to 4). `timeTakenMs` is how long the learner looked at the card, capped by the preset. Send an `Idempotency-Key` so a retry does not answer twice.
856
+ *
857
+ * The card must not be suspended or buried, and the collection must use the v3 scheduler; otherwise the answer is `409 card_state_error`. A card in a filtered deck is answered as Anki does. The preset, the answer-time cap and burying come from the card's home deck, the daily counts go to the filtered deck and its parents, and the review log records an answer given before the card was due (or in a deck that does not reschedule) with type 3 (*filtered*). In a deck that reschedules, a review card that is passed returns to its home deck, and a learning card stays in the filtered deck until it graduates; in a deck that does not reschedule, nothing is rescheduled: Again, Hard and Good bring the card back after the deck's preview delay, and the card returns to its home deck in its old state when the preview ends. The legacy schedulers are not supported. A card that has no FSRS memory state yet (for example one that was just moved into an FSRS deck) gets one replayed from its review history, as Anki does, and from its SM-2 ease and interval when the history is too short.
858
+ *
859
+ * The load balancer is applied to review intervals as in Anki (see `GET /api/v1/cards/{id}/scheduling`). It reads the cards due in the next 99 days when the card is answered (Anki reads them once when it builds a queue), and the weekday used for Easy Days is taken in the collection's `localOffset` (UTC when unset).
860
+ */
861
+ export const answerCard = (parameters, options) => {
862
+ const params = buildClientParams([parameters], [{ args: [
863
+ { in: 'headers', key: 'idempotencyKey', map: 'Idempotency-Key' },
864
+ { in: 'path', key: 'id' },
865
+ { in: 'body', key: 'rating' },
866
+ { in: 'body', key: 'timeTakenMs' }
867
+ ] }]);
868
+ return (options?.client ?? client).post({
869
+ responseStyle: 'data',
870
+ security: [{ scheme: 'bearer', type: 'http' }],
871
+ url: '/api/v1/cards/{id}/answer',
872
+ ...options,
873
+ ...params,
874
+ headers: {
875
+ 'Content-Type': 'application/json',
876
+ ...options?.headers,
877
+ ...params.headers
878
+ }
879
+ });
880
+ };