UNPKG

@bachman-dev/wanikani-api-types

Version:

Regularly updated type definitions for the WaniKani API

1,321 lines (1,320 loc) 45.1 kB
import * as v from "valibot"; //#region src/v20170710/lang/_internal.ts /* @__NO_SIDE_EFFECTS__ */ function getLocale(issue) { if (typeof issue.lang === "string") { if (issue.lang === "en" || issue.lang.startsWith("en-")) return "en"; } return "en"; } //#endregion //#region src/v20170710/lang/date-union.ts const en$2 = "Expected either a valid ISO-8601 timestamp string or a JavaScript Date"; const dateUnion = /* @__NO_SIDE_EFFECTS__ */ (issue) => { switch (/* @__PURE__ */ getLocale(issue)) { default: return en$2; } }; //#endregion //#region src/v20170710/lang/review-payload-intersect.ts const en$1 = "Failed to intersect Review Payload objects; this is usually caused when trying to merge a base object with key/value type conflicts."; const reviewPayloadIntersect = /* @__NO_SIDE_EFFECTS__ */ (issue) => { switch (/* @__PURE__ */ getLocale(issue)) { default: return en$1; } }; //#endregion //#region src/v20170710/lang/review-payload-union.ts const en = "Review Payload must have one and only one of either an assignment_id or subject_id positive integer"; const reviewPayloadUnion = /* @__NO_SIDE_EFFECTS__ */ (issue) => { switch (/* @__PURE__ */ getLocale(issue)) { default: return en; } }; //#endregion //#region src/v20170710/base.ts const ApiRevision = v.literal("20170710"); /** * A constant representing the WaniKani API revision. This will match the revision module being imported from, or the * latest revision when importing from the root module. * * @see {@link https://docs.api.wanikani.com/20170710/#revisions-aka-versioning} * @category Base */ const API_REVISION = "20170710"; /** * A type guard that checks if the given value matches the type predicate. * * @category Base * @category Type Guards */ /* @__NO_SIDE_EFFECTS__ */ function isApiRevision(value) { return v.is(ApiRevision, value); } const SafeInteger = v.pipe(v.number(), v.safeInteger(), v.minValue(0)); const DatableString = v.pipe(v.string(), v.trim(), v.isoTimestamp(), v.brand("DatableString")); /** * A type guard that checks if the given value matches the type predicate. * * @category Base * @category Type Guards */ /* @__NO_SIDE_EFFECTS__ */ function isDatableString(value) { return v.is(DatableString, value); } /** * The minimum level provided by WaniKani; exported for use in lieu of a Magic Number. * * @category Base */ const MIN_LEVEL = 1; /** * The maximum level provided by WaniKani; exported for use in lieu of a Magic Number. * * @category Base */ const MAX_LEVEL = 60; const Level = v.pipe(SafeInteger, v.minValue(1), v.maxValue(60)); /** * A type guard that checks if the given value matches the type predicate. * * @category Base * @category Type Guards */ /* @__NO_SIDE_EFFECTS__ */ function isLevel(value) { return v.is(Level, value); } const BaseResource = v.object({ data_updated_at: DatableString, url: v.string() }); const BaseCollection = v.object({ data_updated_at: v.union([DatableString, v.null()]), object: v.literal("collection"), pages: v.object({ next_url: v.union([v.string(), v.null()]), per_page: v.number(), previous_url: v.union([v.string(), v.null()]) }), total_count: v.number(), url: v.string() }); const CollectionParameters = v.object({ ids: v.optional(v.array(SafeInteger)), page_after_id: v.optional(SafeInteger), page_before_id: v.optional(SafeInteger), updated_after: v.optional(v.union([DatableString, v.date()], dateUnion)) }); /** * Parses a parameter object, for use with the WaniKani API. * * @param params -- An object containing the query string parameters to parse. * @returns A query string of all the parameters, which can be added to a base URL. * @throws A `TypeError` if a non-object is passed to the function. * @category Base */ function stringifyParameters(params) { v.assert(CollectionParameters, params); if (Object.keys(params).length === 0) return ""; let isFirstItem = true; let queryString = ""; const emptyQueryParams = [ "immediately_available_for_lessons", "immediately_available_for_review", "in_review" ]; for (const [key, value] of Object.entries(params)) { if (emptyQueryParams.includes(key) && typeof value === "boolean") { if (value) { queryString += isFirstItem ? "?" : "&"; queryString += key; } } else { queryString += isFirstItem ? "?" : "&"; if (typeof value === "boolean") queryString += value ? `${key}=true` : `${key}=false`; else if (value instanceof Date && Object.prototype.toString.call(value) === "[object Date]") queryString += `${key}=${value.toISOString()}`; else if (Array.isArray(value) || typeof value === "number" || typeof value === "string") queryString += `${key}=${value.toString()}`; } isFirstItem = false; } return queryString; } const BaseReport = v.object({ data_updated_at: DatableString, object: v.literal("report"), url: v.string() }); const ApiError = v.object({ code: v.number(), error: v.string() }); /** * A type guard that checks if the given value matches the type predicate. * * @category Base * @category Type Guards */ /* @__NO_SIDE_EFFECTS__ */ function isApiError(value) { return v.is(ApiError, value); } //#endregion //#region src/v20170710/subjects.ts const SubjectType = v.picklist([ "kana_vocabulary", "kanji", "radical", "vocabulary" ]); /** * A type guard that checks if the given value matches the type predicate. * * @category Subjects * @category Type Guards */ /* @__NO_SIDE_EFFECTS__ */ function isSubjectType(value) { return v.is(SubjectType, value); } const SubjectTuple = v.pipe(v.tupleWithRest([SubjectType], SubjectType), v.nonEmpty(), v.checkItems((item, index, array) => array.indexOf(item) === index, "Duplicate Subject Type detected in Subject Tuple")); /** * A type guard that checks if the given value matches the type predicate. * * @category Subjects * @category Type Guards */ /* @__NO_SIDE_EFFECTS__ */ function isSubjectTuple(value) { return v.is(SubjectTuple, value); } const SubjectAuxiliaryMeaning = v.object({ meaning: v.string(), type: v.picklist(["blacklist", "whitelist"]) }); const SubjectMeaning = v.object({ accepted_answer: v.boolean(), meaning: v.string(), primary: v.boolean() }); const SubjectBaseData = v.object({ auxiliary_meanings: v.array(SubjectAuxiliaryMeaning), created_at: DatableString, document_url: v.string(), hidden_at: v.union([DatableString, v.null()]), lesson_position: v.number(), level: Level, meaning_mnemonic: v.string(), meanings: v.array(SubjectMeaning), slug: v.string(), spaced_repetition_system_id: v.number() }); const RadicalCharacterImage = v.intersect([v.object({ url: v.string() }), v.variant("content_type", [v.object({ content_type: v.literal("image/svg+xml"), metadata: v.object({ inline_styles: v.boolean() }) }), v.object({ content_type: v.literal("image/png"), metadata: v.object({ color: v.string(), dimensions: v.string(), style_name: v.string() }) })])]); const RadicalData = v.object(v.entriesFromObjects([SubjectBaseData, v.object({ amalgamation_subject_ids: v.array(v.number()), character_images: v.array(RadicalCharacterImage), characters: v.union([v.string(), v.null()]) })])); const KanjiReading = v.object({ accepted_answer: v.boolean(), primary: v.boolean(), reading: v.string(), type: v.picklist([ "kunyomi", "nanori", "onyomi" ]) }); const KanjiData = v.object(v.entriesFromObjects([SubjectBaseData, v.object({ amalgamation_subject_ids: v.array(v.number()), characters: v.string(), component_subject_ids: v.array(v.number()), meaning_hint: v.union([v.string(), v.null()]), reading_hint: v.union([v.string(), v.null()]), reading_mnemonic: v.string(), readings: v.array(KanjiReading), visually_similar_subject_ids: v.array(v.number()) })])); const VocabularyContextSentence = v.object({ en: v.string(), ja: v.string() }); const VocabularyPronunciationAudio = v.object({ content_type: v.picklist([ "audio/mpeg", "audio/ogg", "audio/webm" ]), metadata: v.object({ gender: v.picklist(["female", "male"]), pronunciation: v.string(), source_id: v.number(), voice_actor_id: v.number(), voice_actor_name: v.string(), voice_description: v.string() }), url: v.string() }); const VocabularyReading = v.object({ accepted_answer: v.boolean(), primary: v.boolean(), reading: v.string() }); const VocabularyData = v.object(v.entriesFromObjects([SubjectBaseData, v.object({ characters: v.string(), component_subject_ids: v.array(v.number()), context_sentences: v.array(VocabularyContextSentence), parts_of_speech: v.array(v.string()), pronunciation_audios: v.array(VocabularyPronunciationAudio), reading_mnemonic: v.string(), readings: v.array(VocabularyReading) })])); const KanaVocabularyData = v.object(v.entriesFromObjects([SubjectBaseData, v.object({ characters: v.string(), context_sentences: v.array(VocabularyContextSentence), parts_of_speech: v.array(v.string()), pronunciation_audios: v.array(VocabularyPronunciationAudio) })])); const Subject = v.intersect([ BaseResource, v.object({ id: v.number() }), v.variant("object", [ v.object({ data: KanaVocabularyData, object: v.literal("kana_vocabulary") }), v.object({ data: KanjiData, object: v.literal("kanji") }), v.object({ data: RadicalData, object: v.literal("radical") }), v.object({ data: VocabularyData, object: v.literal("vocabulary") }) ]) ]); /** * A type guard that checks if the given value matches the type predicate. * * @category Subjects * @category Type Guards */ /* @__NO_SIDE_EFFECTS__ */ function isSubject(value) { return v.is(Subject, value); } const SubjectCollection = v.object(v.entriesFromObjects([BaseCollection, v.object({ data: v.array(Subject) })])); /** * A type guard that checks if the given value matches the type predicate. * * @category Subjects * @category Type Guards */ /* @__NO_SIDE_EFFECTS__ */ function isSubjectCollection(value) { return v.is(SubjectCollection, value); } /** * A regular expression that matches the markup found in WaniKani's subject mnemonics and hints. Both the tag and inner * text are captured for each match. * * @category Subjects */ const SUBJECT_MARKUP_MATCHER = /<(?<tag>ja|kanji|meaning|radical|reading|vocabulary)>(?<innerText>.*?)<\/\1>/dgu; /** * Parses WaniKani subject markup (mnemonics, hints, etc) for easier display/formatting. * * @param text The subject markup to parse * @returns A structured array of objects that can be traversed and displayed * @category Subjects */ function parseSubjectMarkup(text) { if (!text) return []; const markupArray = []; let lastIdx = 0; for (const match of text.matchAll(SUBJECT_MARKUP_MATCHER)) if (typeof match.indices?.[0] !== "undefined") { const beforeText = text.substring(lastIdx, match.indices[0][0]); if (beforeText) markupArray.push({ text: beforeText }); if (typeof match.groups?.innerText === "string" && (match.groups.tag === "ja" || match.groups.tag === "kanji" || match.groups.tag === "meaning" || match.groups.tag === "radical" || match.groups.tag === "reading" || match.groups.tag === "vocabulary")) { const tagNode = { tag: match.groups.tag, children: parseSubjectMarkup(match.groups.innerText) }; markupArray.push(tagNode); } lastIdx = match.indices[0][1]; } const afterText = text.substring(lastIdx, text.length); if (afterText) markupArray.push({ text: afterText }); return markupArray; } const SubjectParameters = v.object(v.entriesFromObjects([CollectionParameters, v.object({ hidden: v.optional(v.boolean()), levels: v.optional(v.array(Level)), slugs: v.optional(v.array(v.string())), types: v.optional(SubjectTuple) })])); //#endregion //#region src/v20170710/spaced-repetition-systems.ts /** * The minimum SRS Stage Number used in WaniKani's SRS; exported for use in lieu of a Magic Number. * * @category Spaced Repetition Systems */ const MIN_SRS_STAGE = 0; /** * The maximum SRS Stage Number used in WaniKani's reviews; exported for use in lieu of a Magic Number. * * @category Spaced Repetition Systems */ const MAX_SRS_REVIEW_STAGE = 8; /** * The maximum SRS Stage Number used in WaniKani's SRS; exported for use in lieu of a Magic Number. * * @category Spaced Repetition Systems */ const MAX_SRS_STAGE = 9; const SpacedRepetitionSystemStageNumber = v.pipe(SafeInteger, v.minValue(0), v.maxValue(9)); /** * A type guard that checks if the given value matches the type predicate. * * @category Spaced Repetition Systems * @category Type Guards */ /* @__NO_SIDE_EFFECTS__ */ function isSpacedRepetitionSystemStageNumber(value) { return v.is(SpacedRepetitionSystemStageNumber, value); } const SpacedRepetitionSystemStage = v.object({ interval: v.union([v.number(), v.null()]), interval_unit: v.union([v.picklist([ "days", "hours", "milliseconds", "minutes", "seconds", "weeks" ]), v.null()]), position: SpacedRepetitionSystemStageNumber }); const SpacedRepetitionSystem = v.object(v.entriesFromObjects([BaseResource, v.object({ data: v.object({ burning_stage_position: SpacedRepetitionSystemStageNumber, created_at: DatableString, description: v.string(), name: v.string(), passing_stage_position: SpacedRepetitionSystemStageNumber, stages: v.array(SpacedRepetitionSystemStage), starting_stage_position: SpacedRepetitionSystemStageNumber, unlocking_stage_position: SpacedRepetitionSystemStageNumber }), id: v.number(), object: v.literal("spaced_repetition_system") })])); /** * A type guard that checks if the given value matches the type predicate. * * @category Spaced Repetition Systems * @category Type Guards */ /* @__NO_SIDE_EFFECTS__ */ function isSpacedRepetitionSystem(value) { return v.is(SpacedRepetitionSystem, value); } const SpacedRepetitionSystemCollection = v.object(v.entriesFromObjects([BaseCollection, v.object({ data: v.array(SpacedRepetitionSystem) })])); /** * A type guard that checks if the given value matches the type predicate. * * @category Spaced Repetition Systems * @category Type Guards */ /* @__NO_SIDE_EFFECTS__ */ function isSpacedRepetitionSystemCollection(value) { return v.is(SpacedRepetitionSystemCollection, value); } const SpacedRepetitionSystemParameters = CollectionParameters; //#endregion //#region src/v20170710/assignments.ts const Assignment = v.object(v.entriesFromObjects([BaseResource, v.object({ data: v.object({ available_at: v.union([DatableString, v.null()]), burned_at: v.union([DatableString, v.null()]), created_at: DatableString, hidden: v.boolean(), passed_at: v.union([DatableString, v.null()]), resurrected_at: v.union([DatableString, v.null()]), srs_stage: SpacedRepetitionSystemStageNumber, started_at: v.union([DatableString, v.null()]), subject_id: v.number(), subject_type: SubjectType, unlocked_at: v.union([DatableString, v.null()]) }), id: v.number(), object: v.literal("assignment") })])); /** * A type guard that checks if the given value matches the type predicate. * * @category Assignments * @category Type Guards */ /* @__NO_SIDE_EFFECTS__ */ function isAssignment(value) { return v.is(Assignment, value); } const AssignmentCollection = v.object(v.entriesFromObjects([BaseCollection, v.object({ data: v.array(Assignment) })])); /** * A type guard that checks if the given value matches the type predicate. * * @category Assignments * @category Type Guards */ /* @__NO_SIDE_EFFECTS__ */ function isAssignmentCollection(value) { return v.is(AssignmentCollection, value); } const AssignmentParameters = v.object(v.entriesFromObjects([CollectionParameters, v.object({ available_after: v.optional(v.union([DatableString, v.date()], dateUnion)), available_before: v.optional(v.union([DatableString, v.date()], dateUnion)), burned: v.optional(v.boolean()), hidden: v.optional(v.boolean()), immediately_available_for_lessons: v.optional(v.boolean()), immediately_available_for_review: v.optional(v.boolean()), in_review: v.optional(v.boolean()), levels: v.optional(v.array(Level)), srs_stages: v.optional(v.array(SpacedRepetitionSystemStageNumber)), started: v.optional(v.boolean()), subject_ids: v.optional(v.array(SafeInteger)), subject_types: v.optional(SubjectTuple), unlocked: v.optional(v.boolean()) })])); const AssignmentPayload = v.object({ assignment: v.object({ started_at: v.optional(v.union([DatableString, v.date()], dateUnion)) }) }); //#endregion //#region src/v20170710/level-progressions.ts const LevelProgression = v.object(v.entriesFromObjects([BaseResource, v.object({ data: v.object({ abandoned_at: v.union([DatableString, v.null()]), completed_at: v.union([DatableString, v.null()]), created_at: DatableString, level: Level, passed_at: v.union([DatableString, v.null()]), started_at: v.union([DatableString, v.null()]), unlocked_at: v.union([DatableString, v.null()]) }), id: v.number(), object: v.literal("level_progression") })])); /** * A type guard that checks if the given value matches the type predicate. * * @category Level Progressions * @category Type Guards */ /* @__NO_SIDE_EFFECTS__ */ function isLevelProgression(value) { return v.is(LevelProgression, value); } const LevelProgressionCollection = v.object(v.entriesFromObjects([BaseCollection, v.object({ data: v.array(LevelProgression) })])); /** * A type guard that checks if the given value matches the type predicate. * * @category Level Progressions * @category Type Guards */ /* @__NO_SIDE_EFFECTS__ */ function isLevelProgressionCollection(value) { return v.is(LevelProgressionCollection, value); } const LevelProgressionParameters = CollectionParameters; //#endregion //#region src/v20170710/review-statistics.ts const ReviewStatistic = v.object(v.entriesFromObjects([BaseResource, v.object({ data: v.object({ created_at: DatableString, hidden: v.boolean(), meaning_correct: v.number(), meaning_current_streak: v.number(), meaning_incorrect: v.number(), meaning_max_streak: v.number(), percentage_correct: v.number(), reading_correct: v.number(), reading_current_streak: v.number(), reading_incorrect: v.number(), reading_max_streak: v.number(), subject_id: v.number(), subject_type: SubjectType }), id: v.number(), object: v.literal("review_statistic") })])); /** * A type guard that checks if the given value matches the type predicate. * * @category Review Statistics * @category Type Guards */ /* @__NO_SIDE_EFFECTS__ */ function isReviewStatistic(value) { return v.is(ReviewStatistic, value); } const ReviewStatisticCollection = v.object(v.entriesFromObjects([BaseCollection, v.object({ data: v.array(ReviewStatistic) })])); /** * A type guard that checks if the given value matches the type predicate. * * @category Review Statistics * @category Type Guards */ /* @__NO_SIDE_EFFECTS__ */ function isReviewStatisticCollection(value) { return v.is(ReviewStatisticCollection, value); } const ReviewStatisticParameters = v.object(v.entriesFromObjects([CollectionParameters, v.object({ hidden: v.optional(v.boolean()), percentages_greater_than: v.optional(v.number()), percentages_less_than: v.optional(v.number()), subject_ids: v.optional(v.array(SafeInteger)), subject_types: v.optional(SubjectTuple) })])); //#endregion //#region src/v20170710/reviews.ts const Review = v.object(v.entriesFromObjects([BaseResource, v.object({ data: v.object({ assignment_id: v.number(), created_at: DatableString, ending_srs_stage: SpacedRepetitionSystemStageNumber, incorrect_meaning_answers: v.number(), incorrect_reading_answers: v.number(), spaced_repetition_system_id: v.number(), starting_srs_stage: SpacedRepetitionSystemStageNumber, subject_id: v.number() }), id: v.number(), object: v.literal("review") })])); /** * A type guard that checks if the given value matches the type predicate. * * @category Reviews * @category Type Guards */ /* @__NO_SIDE_EFFECTS__ */ function isReview(value) { return v.is(Review, value); } const ReviewCollection = v.object(v.entriesFromObjects([BaseCollection, v.object({ data: v.array(Review) })])); /** * A type guard that checks if the given value matches the type predicate. * * @category Reviews * @category Type Guards */ /* @__NO_SIDE_EFFECTS__ */ function isReviewCollection(value) { return v.is(ReviewCollection, value); } const ReviewParameters = v.object(v.entriesFromObjects([CollectionParameters, v.object({ assignment_ids: v.optional(v.array(SafeInteger)), subject_ids: v.optional(v.array(SafeInteger)) })])); const ReviewPayload = v.object({ review: v.intersect([v.object({ incorrect_meaning_answers: SafeInteger, incorrect_reading_answers: SafeInteger, created_at: v.optional(v.union([DatableString, v.date()], dateUnion)) }), v.union([v.object({ assignment_id: SafeInteger, subject_id: v.optional(v.never()) }), v.object({ subject_id: SafeInteger, assignment_id: v.optional(v.never()) })], reviewPayloadUnion)], reviewPayloadIntersect) }); const CreatedReview = v.object(v.entriesFromObjects([Review, v.object({ resources_updated: v.object({ assignment: Assignment, review_statistic: ReviewStatistic }) })])); /** * A type guard that checks if the given value matches the type predicate. * * @category Reviews * @category Type Guards */ /* @__NO_SIDE_EFFECTS__ */ function isCreatedReview(value) { return v.is(CreatedReview, value); } //#endregion //#region src/v20170710/study-materials.ts const StudyMaterialBaseData = v.object({ meaning_note: v.string(), meaning_synonyms: v.array(v.string()), reading_note: v.string() }); const StudyMaterial = v.object(v.entriesFromObjects([BaseResource, v.object({ data: v.intersect([StudyMaterialBaseData, v.object({ created_at: DatableString, hidden: v.boolean(), subject_id: v.number(), subject_type: SubjectType })]), id: v.number(), object: v.literal("study_material") })])); /** * A type guard that checks if the given value matches the type predicate. * * @category Study Materials * @category Type Guards */ /* @__NO_SIDE_EFFECTS__ */ function isStudyMaterial(value) { return v.is(StudyMaterial, value); } const StudyMaterialCollection = v.object(v.entriesFromObjects([BaseCollection, v.object({ data: v.array(StudyMaterial) })])); /** * A type guard that checks if the given value matches the type predicate. * * @category Study Materials * @category Type Guards */ /* @__NO_SIDE_EFFECTS__ */ function isStudyMaterialCollection(value) { return v.is(StudyMaterialCollection, value); } const StudyMaterialParameters = v.object(v.entriesFromObjects([CollectionParameters, v.object({ hidden: v.optional(v.boolean()), subject_ids: v.optional(v.array(SafeInteger)), subject_types: v.optional(SubjectTuple) })])); const StudyMaterialUpdatePayload = v.partial(StudyMaterialBaseData); const StudyMaterialCreatePayload = v.object(v.entriesFromObjects([StudyMaterialUpdatePayload, v.object({ subject_id: SafeInteger })])); //#endregion //#region src/v20170710/resets.ts const Reset = v.object(v.entriesFromObjects([BaseResource, v.object({ data: v.object({ confirmed_at: v.union([DatableString, v.null()]), created_at: DatableString, original_level: Level, target_level: Level }), id: v.number(), object: v.literal("reset") })])); /** * A type guard that checks if the given value matches the type predicate. * * @category Resets * @category Type Guards */ /* @__NO_SIDE_EFFECTS__ */ function isReset(value) { return v.is(Reset, value); } const ResetCollection = v.object(v.entriesFromObjects([BaseCollection, v.object({ data: v.array(Reset) })])); /** * A type guard that checks if the given value matches the type predicate. * * @category Resets * @category Type Guards */ /* @__NO_SIDE_EFFECTS__ */ function isResetCollection(value) { return v.is(ResetCollection, value); } const ResetParameters = CollectionParameters; //#endregion //#region src/v20170710/user.ts /** * The minimum batch size for lessons in the WaniKani app; exported for use in lieu of a Magic Number. * * @category User */ const MIN_LESSON_BATCH_SIZE = 3; /** * The maximum batch size for lessons in the WaniKani app; exported for use in lieu of a Magic Number. * * @category User */ const MAX_LESSON_BATCH_SIZE = 10; const LessonBatchSizeNumber = v.pipe(SafeInteger, v.minValue(3), v.maxValue(10)); /** * A type guard that checks if the given value matches the type predicate. * * @category User * @category Type Guards */ /* @__NO_SIDE_EFFECTS__ */ function isLessonBatchSizeNumber(value) { return v.is(LessonBatchSizeNumber, value); } const UserPreferences = v.object({ default_voice_actor_id: SafeInteger, extra_study_autoplay_audio: v.boolean(), lessons_autoplay_audio: v.boolean(), lessons_batch_size: LessonBatchSizeNumber, lessons_presentation_order: v.picklist([ "ascending_level_then_shuffled", "ascending_level_then_subject", "shuffled" ]), reviews_autoplay_audio: v.boolean(), reviews_display_srs_indicator: v.boolean(), reviews_presentation_order: v.picklist(["lower_levels_first", "shuffled"]) }); const User = v.object(v.entriesFromObjects([BaseResource, v.object({ data: v.object({ current_vacation_started_at: v.union([DatableString, v.null()]), id: v.string(), level: Level, preferences: UserPreferences, profile_url: v.string(), started_at: DatableString, subscription: v.object({ active: v.boolean(), max_level_granted: Level, period_ends_at: v.union([DatableString, v.null()]), type: v.picklist([ "free", "lifetime", "recurring", "unknown" ]) }), username: v.string() }), object: v.literal("user") })])); /** * A type guard that checks if the given value matches the type predicate. * * @category User * @category Type Guards */ /* @__NO_SIDE_EFFECTS__ */ function isUser(value) { return v.is(User, value); } const UserPreferencesPayload = v.object({ user: v.object({ preferences: v.partial(UserPreferences) }) }); //#endregion //#region src/v20170710/voice-actors.ts const VoiceActor = v.object(v.entriesFromObjects([BaseResource, v.object({ data: v.object({ created_at: DatableString, description: v.string(), gender: v.picklist(["female", "male"]), name: v.string() }), id: v.number(), object: v.literal("voice_actor") })])); /** * A type guard that checks if the given value matches the type predicate. * * @category Voice Actors * @category Type Guards */ /* @__NO_SIDE_EFFECTS__ */ function isVoiceActor(value) { return v.is(VoiceActor, value); } const VoiceActorCollection = v.object(v.entriesFromObjects([BaseCollection, v.object({ data: v.array(VoiceActor) })])); /** * A type guard that checks if the given value matches the type predicate. * * @category Voice Actors * @category Type Guards */ /* @__NO_SIDE_EFFECTS__ */ function isVoiceActorCollection(value) { return v.is(VoiceActorCollection, value); } const VoiceActorParameters = CollectionParameters; //#endregion //#region src/v20170710/requests.ts /** * A factory for preparing requests to the WaniKani API, with methods that return an {@link ApiRequest} that can be used * in any HTTP library/package to make the request. * * @category Requests */ var ApiRequestFactory = class ApiRequestFactory { /** * Types of Assignment Requests available in the WaniKani API. */ assignments = { get: (idOrParams, options) => { const headers = { ...this._getHeaders }; if (typeof options?.customHeaders !== "undefined") for (const [key, value] of Object.entries(options.customHeaders)) { ApiRequestFactory._validateHeader(key, value); headers[key] = value; } const request = { body: null, headers, method: "GET", url: `${this.baseUrl}/assignments` }; if (typeof idOrParams === "number") { v.assert(SafeInteger, idOrParams); request.url += `/${idOrParams}`; } else if (typeof idOrParams !== "undefined") { v.assert(AssignmentParameters, idOrParams); request.url += stringifyParameters(idOrParams); } return request; }, start: (assignmentId, payload, options) => { v.assert(SafeInteger, assignmentId); v.assert(AssignmentPayload, payload); const headers = { ...this._postPutHeaders }; if (typeof options?.customHeaders !== "undefined") for (const [key, value] of Object.entries(options.customHeaders)) { ApiRequestFactory._validateHeader(key, value); headers[key] = value; } return { body: JSON.stringify(payload), headers, method: "PUT", url: `${this.baseUrl}/assignments/${assignmentId}/start` }; } }; /** The base URL of the WaniKani API */ baseUrl = "https://api.wanikani.com/v2"; /** * Types of Level Progression Requests available in the WaniKani API. */ levelProgressions = { get: (idOrParams, options) => { const headers = { ...this._getHeaders }; if (typeof options?.customHeaders !== "undefined") for (const [key, value] of Object.entries(options.customHeaders)) { ApiRequestFactory._validateHeader(key, value); headers[key] = value; } const request = { body: null, headers, method: "GET", url: `${this.baseUrl}/level_progressions` }; if (typeof idOrParams === "number") { v.assert(SafeInteger, idOrParams); request.url += `/${idOrParams}`; } else if (typeof idOrParams !== "undefined") { v.assert(LevelProgressionParameters, idOrParams); request.url += stringifyParameters(idOrParams); } return request; } }; /** * Types of Reset Requests available in the WaniKani API. */ resets = { get: (idOrParams, options) => { const headers = { ...this._getHeaders }; if (typeof options?.customHeaders !== "undefined") for (const [key, value] of Object.entries(options.customHeaders)) { ApiRequestFactory._validateHeader(key, value); headers[key] = value; } const request = { body: null, headers, method: "GET", url: `${this.baseUrl}/resets` }; if (typeof idOrParams === "number") { v.assert(SafeInteger, idOrParams); request.url += `/${idOrParams}`; } else if (typeof idOrParams !== "undefined") { v.assert(ResetParameters, idOrParams); request.url += stringifyParameters(idOrParams); } return request; } }; /** * Types of Review Statistic Requests available in the WaniKani API. */ reviewStatistics = { get: (idOrParams, options) => { const headers = { ...this._getHeaders }; if (typeof options?.customHeaders !== "undefined") for (const [key, value] of Object.entries(options.customHeaders)) { ApiRequestFactory._validateHeader(key, value); headers[key] = value; } const request = { body: null, headers, method: "GET", url: `${this.baseUrl}/review_statistics` }; if (typeof idOrParams === "number") { v.assert(SafeInteger, idOrParams); request.url += `/${idOrParams}`; } else if (typeof idOrParams !== "undefined") { v.assert(ReviewStatisticParameters, idOrParams); request.url += stringifyParameters(idOrParams); } return request; } }; /** * Types of Review Requests available in the WaniKani API. */ reviews = { create: (payload, options) => { v.assert(ReviewPayload, payload); const headers = { ...this._postPutHeaders }; if (typeof options !== "undefined") { if (typeof options.customHeaders !== "undefined") for (const [key, value] of Object.entries(options.customHeaders)) { ApiRequestFactory._validateHeader(key, value); headers[key] = value; } } return { body: JSON.stringify(payload), headers, method: "POST", url: `${this.baseUrl}/reviews` }; }, get: (idOrParams, options) => { const headers = { ...this._getHeaders }; if (typeof options?.customHeaders !== "undefined") for (const [key, value] of Object.entries(options.customHeaders)) { ApiRequestFactory._validateHeader(key, value); headers[key] = value; } const request = { body: null, headers, method: "GET", url: `${this.baseUrl}/reviews` }; if (typeof idOrParams === "number") { v.assert(SafeInteger, idOrParams); request.url += `/${idOrParams}`; } else if (typeof idOrParams !== "undefined") { v.assert(ReviewParameters, idOrParams); request.url += stringifyParameters(idOrParams); } return request; } }; /** * Types of Spaced Repetition System (SRS) Requests available in the WaniKani API. */ spacedRepetitionSystems = { get: (idOrParams, options) => { const headers = { ...this._getHeaders }; if (typeof options?.customHeaders !== "undefined") for (const [key, value] of Object.entries(options.customHeaders)) { ApiRequestFactory._validateHeader(key, value); headers[key] = value; } const request = { body: null, headers, method: "GET", url: `${this.baseUrl}/spaced_repetition_systems` }; if (typeof idOrParams === "number") { v.assert(SafeInteger, idOrParams); request.url += `/${idOrParams}`; } else if (typeof idOrParams !== "undefined") { v.assert(SpacedRepetitionSystemParameters, idOrParams); request.url += stringifyParameters(idOrParams); } return request; } }; /** * An alias for Spaced Repetition System requests. */ srs = this.spacedRepetitionSystems; /** * Types of Study Material Requests available in the WaniKani API. */ studyMaterials = { get: (idOrParams, options) => { const headers = { ...this._getHeaders }; if (typeof options?.customHeaders !== "undefined") for (const [key, value] of Object.entries(options.customHeaders)) { ApiRequestFactory._validateHeader(key, value); headers[key] = value; } const request = { body: null, headers, method: "GET", url: `${this.baseUrl}/study_materials` }; if (typeof idOrParams === "number") { v.assert(SafeInteger, idOrParams); request.url += `/${idOrParams}`; } else if (typeof idOrParams !== "undefined") { v.assert(StudyMaterialParameters, idOrParams); request.url += stringifyParameters(idOrParams); } return request; }, create: (payload, options) => { v.assert(StudyMaterialCreatePayload, payload); const headers = { ...this._postPutHeaders }; if (typeof options !== "undefined") { if (typeof options.customHeaders !== "undefined") for (const [key, value] of Object.entries(options.customHeaders)) { ApiRequestFactory._validateHeader(key, value); headers[key] = value; } } return { body: JSON.stringify(payload), headers, method: "POST", url: `${this.baseUrl}/study_materials` }; }, update: (studyMaterialId, payload, options) => { v.assert(SafeInteger, studyMaterialId); v.assert(StudyMaterialUpdatePayload, payload); const headers = { ...this._postPutHeaders }; if (typeof options !== "undefined") { if (typeof options.customHeaders !== "undefined") for (const [key, value] of Object.entries(options.customHeaders)) { ApiRequestFactory._validateHeader(key, value); headers[key] = value; } } return { body: JSON.stringify(payload), headers, method: "PUT", url: `${this.baseUrl}/study_materials/${studyMaterialId}` }; } }; /** * Types of Subject Requests available in the WaniKani API. */ subjects = { get: (idOrParams, options) => { const headers = { ...this._getHeaders }; if (typeof options?.customHeaders !== "undefined") for (const [key, value] of Object.entries(options.customHeaders)) { ApiRequestFactory._validateHeader(key, value); headers[key] = value; } const request = { body: null, headers, method: "GET", url: `${this.baseUrl}/subjects` }; if (typeof idOrParams === "number") { v.assert(SafeInteger, idOrParams); request.url += `/${idOrParams}`; } else if (typeof idOrParams !== "undefined") { v.assert(SubjectParameters, idOrParams); request.url += stringifyParameters(idOrParams); } return request; } }; /** * Types of Summary Requests available in the WaniKani API. */ summary = { get: (options) => { const headers = { ...this._getHeaders }; if (typeof options?.customHeaders !== "undefined") for (const [key, value] of Object.entries(options.customHeaders)) { ApiRequestFactory._validateHeader(key, value); headers[key] = value; } return { body: null, headers, method: "GET", url: `${this.baseUrl}/summary` }; } }; /** * Types of User Requests available in the WaniKani API. */ user = { get: (options) => { const headers = { ...this._getHeaders }; if (typeof options?.customHeaders !== "undefined") for (const [key, value] of Object.entries(options.customHeaders)) { ApiRequestFactory._validateHeader(key, value); headers[key] = value; } return { body: null, headers, method: "GET", url: `${this.baseUrl}/user` }; }, updatePreferences: (payload, options) => { v.assert(UserPreferencesPayload, payload); const headers = { ...this._postPutHeaders }; if (typeof options !== "undefined") { if (typeof options.customHeaders !== "undefined") for (const [key, value] of Object.entries(options.customHeaders)) { ApiRequestFactory._validateHeader(key, value); headers[key] = value; } } return { body: JSON.stringify(payload), headers, method: "PUT", url: `${this.baseUrl}/user` }; } }; /** * Types of Voice Actor Requests available in the WaniKani API. */ voiceActors = { get: (idOrParams, options) => { const headers = { ...this._getHeaders }; if (typeof options?.customHeaders !== "undefined") for (const [key, value] of Object.entries(options.customHeaders)) { ApiRequestFactory._validateHeader(key, value); headers[key] = value; } const request = { body: null, headers, method: "GET", url: `${this.baseUrl}/voice_actors` }; if (typeof idOrParams === "number") { v.assert(SafeInteger, idOrParams); request.url += `/${idOrParams}`; } else if (typeof idOrParams !== "undefined") { v.assert(VoiceActorParameters, idOrParams); request.url += stringifyParameters(idOrParams); } return request; } }; /** * The headers set on factory initialization, excluding anything in the `customHeaders` property in * {@link ApiRequestFactoryInit}. */ _initHeaders; /** * The headers that will be added to any GET requests returned by the factory. */ _getHeaders; /** * The headers that will be added to any POST and PUT requests returned by the factory. */ _postPutHeaders; /** * Initialize the Request Factory. * @param init Initialization options for the factory. * @throws A `TypeError` if trying to set type-checked request headers. */ constructor(init) { this._initHeaders = { authorization: `Bearer ${init.apiToken}`, "wanikani-revision": init.revision ?? "20170710" }; this._getHeaders = { ...this._initHeaders }; this._postPutHeaders = { ...this._initHeaders }; if (typeof init.customHeaders !== "undefined") for (const [key, value] of Object.entries(init.customHeaders)) { ApiRequestFactory._validateHeader(key, value); this._getHeaders[key] = value; this._postPutHeaders[key] = value; } this._postPutHeaders["content-type"] = "application/json"; } /** * Validates custom-set headers to make sure type checking isn't circumvented. * @param key The header key, e.g. `Accpet` or `X-Forwarded-For` * @param value The header value, e.g. `application/json` or `192.168.1.1` * @throws A `TypeError` if trying to set type-checked request headers. * @internal */ static _validateHeader(key, value) { if (key.toLowerCase() === "authorization") throw new TypeError("WaniKani API Token should be set via setApiToken() method."); else if (key.toLowerCase() === "wanikani-revision") throw new TypeError("WaniKani API Revision should be set via setApiRevision() method."); else if ((key.toLowerCase() === "accept" || key.toLowerCase() === "content-type") && value !== "application/json") throw new TypeError(`The "${key}" header must be set to "application/json" .`); } /** * Add additional custom headers to be used in all requests generated by the factory. * @param headers An object containing HTTP headers and their values. * @returns The factory, with the added custom headers. * @throws A `TypeError` if trying to set type-checked request headers. */ addCustomHeaders(headers) { for (const [key, value] of Object.entries(headers)) { ApiRequestFactory._validateHeader(key, value); this._getHeaders[key] = value; this._postPutHeaders[key] = value; } return this; } /** * Sets a new WaniKani API Revision to use in requests returned by the factory. * @param revision The WaniKani API Revision to use. * @returns The factory, with the newly set WaniKani API Revision. * @throws A {@link valibot!ValiError} if the WaniKani API Revision is invalid. */ setApiRevision(revision) { const validRevision = v.parse(ApiRevision, revision); this._initHeaders["wanikani-revision"] = validRevision; this._getHeaders["wanikani-revision"] = validRevision; this._postPutHeaders["wanikani-revision"] = validRevision; return this; } /** * Sets a new WaniKani API Token to use in requests returned by the factory. * @param token The new WaniKani API Token to use. * @returns The factory, with the newly set WaniKani API Token. */ setApiToken(token) { this._initHeaders.authorization = `Bearer ${token}`; this._getHeaders.authorization = `Bearer ${token}`; this._postPutHeaders.authorization = `Bearer ${token}`; return this; } /** * Sets the custom headers for all requests gerated by the factory to those passed to this function, removing any * previously set custom headers, and keeping API Revision and Token settings. * @param headers An object containing HTTP headers and their values. * @returns The factory, with the only custom headers being those passed to this function. * @throws A `TypeError` if trying to set type-checked request headers. */ setCustomHeaders(headers) { this._getHeaders = { ...this._initHeaders }; this._postPutHeaders = { ...this._initHeaders }; for (const [key, value] of Object.entries(headers)) { ApiRequestFactory._validateHeader(key, value); this._getHeaders[key] = value; this._postPutHeaders[key] = value; } this._postPutHeaders["content-type"] = "application/json"; return this; } }; //#endregion //#region src/v20170710/summary.ts const SummaryInterval = v.object({ available_at: DatableString, subject_ids: v.array(v.number()) }); const Summary = v.object(v.entriesFromObjects([BaseReport, v.object({ data: v.object({ lessons: v.array(SummaryInterval), next_reviews_at: v.union([DatableString, v.null()]), reviews: v.array(SummaryInterval) }) })])); /** * A type guard that checks if the given value matches the type predicate. * * @category Summary * @category Type Guards */ /* @__NO_SIDE_EFFECTS__ */ function isSummary(value) { return v.is(Summary, value); } //#endregion export { isAssignment as $, isStudyMaterialCollection as A, isSubject as At, ReviewStatisticCollection as B, BaseResource as Bt, StudyMaterial as C, SubjectParameters as Ct, StudyMaterialParameters as D, VocabularyData as Dt, StudyMaterialCreatePayload as E, VocabularyContextSentence as Et, ReviewPayload as F, API_REVISION as Ft, LevelProgressionCollection as G, MIN_LEVEL as Gt, isReviewStatistic as H, DatableString as Ht, isCreatedReview as I, ApiError as It, isLevelProgressionCollection as J, isApiRevision as Jt, LevelProgressionParameters as K, SafeInteger as Kt, isReview as L, ApiRevision as Lt, Review as M, isSubjectTuple as Mt, ReviewCollection as N, isSubjectType as Nt, StudyMaterialUpdatePayload as O, VocabularyPronunciationAudio as Ot, ReviewParameters as P, parseSubjectMarkup as Pt, AssignmentPayload as Q, isReviewCollection as R, BaseCollection as Rt, isResetCollection as S, SubjectMeaning as St, StudyMaterialCollection as T, SubjectType as Tt, isReviewStatisticCollection as U, Level as Ut, ReviewStatisticParameters as V, CollectionParameters as Vt, LevelProgression as W, MAX_LEVEL as Wt, AssignmentCollection as X, isLevel as Xt, Assignment as Y, isDatableString as Yt, AssignmentParameters as Z, stringifyParameters as Zt, isUser as _, SUBJECT_MARKUP_MATCHER as _t, VoiceActor as a, SpacedRepetitionSystemCollection as at, ResetParameters as b, SubjectBaseData as bt, isVoiceActor as c, SpacedRepetitionSystemStageNumber as ct, MAX_LESSON_BATCH_SIZE as d, isSpacedRepetitionSystemStageNumber as dt, isAssignmentCollection as et, MIN_LESSON_BATCH_SIZE as f, KanaVocabularyData as ft, isLessonBatchSizeNumber as g, RadicalData as gt, UserPreferencesPayload as h, RadicalCharacterImage as ht, ApiRequestFactory as i, SpacedRepetitionSystem as it, CreatedReview as j, isSubjectCollection as jt, isStudyMaterial as k, VocabularyReading as kt, isVoiceActorCollection as l, isSpacedRepetitionSystem as lt, UserPreferences as m, KanjiReading as mt, SummaryInterval as n, MAX_SRS_STAGE as nt, VoiceActorCollection as o, SpacedRepetitionSystemParameters as ot, User as p, KanjiData as pt, isLevelProgression as q, isApiError as qt, isSummary as r, MIN_SRS_STAGE as rt, VoiceActorParameters as s, SpacedRepetitionSystemStage as st, Summary as t, MAX_SRS_REVIEW_STAGE as tt, LessonBatchSizeNumber as u, isSpacedRepetitionSystemCollection as ut, Reset as v, Subject as vt, StudyMaterialBaseData as w, SubjectTuple as wt, isReset as x, SubjectCollection as xt, ResetCollection as y, SubjectAuxiliaryMeaning as yt, ReviewStatistic as z, BaseReport as zt };