diff --git a/.changeset/config.json b/.changeset/config.json index 2be13d43..f14edd9d 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -7,5 +7,5 @@ "access": "public", "baseBranch": "main", "updateInternalDependencies": "patch", - "ignore": [] + "ignore": ["@blizzard-api/integration-tests"] } diff --git a/.changeset/fifty-mammals-raise.md b/.changeset/fifty-mammals-raise.md new file mode 100644 index 00000000..66a9dc3a --- /dev/null +++ b/.changeset/fifty-mammals-raise.md @@ -0,0 +1,5 @@ +--- +'@blizzard-api/d3': patch +--- + +Fix an issue when calling D3 profile APIs where the battletag wasn't encoded properly diff --git a/.changeset/funny-snakes-see.md b/.changeset/funny-snakes-see.md new file mode 100644 index 00000000..403a28d4 --- /dev/null +++ b/.changeset/funny-snakes-see.md @@ -0,0 +1,5 @@ +--- +'@blizzard-api/client': patch +--- + +Update ky to 1.14.3 diff --git a/.changeset/metal-zebras-type.md b/.changeset/metal-zebras-type.md new file mode 100644 index 00000000..1f8be657 --- /dev/null +++ b/.changeset/metal-zebras-type.md @@ -0,0 +1,7 @@ +--- +'@blizzard-api/classic-wow': minor +'@blizzard-api/core': minor +'@blizzard-api/wow': minor +--- + +Introduce new types for search results for various WoW APIs diff --git a/.changeset/moody-mirrors-push.md b/.changeset/moody-mirrors-push.md new file mode 100644 index 00000000..901fc3bb --- /dev/null +++ b/.changeset/moody-mirrors-push.md @@ -0,0 +1,5 @@ +--- +'@blizzard-api/client': patch +--- + +Update ky to 1.14.2 diff --git a/.changeset/new-pens-sit.md b/.changeset/new-pens-sit.md new file mode 100644 index 00000000..aa2bb24e --- /dev/null +++ b/.changeset/new-pens-sit.md @@ -0,0 +1,7 @@ +--- +'@blizzard-api/classic-wow': major +'@blizzard-api/core': major +'@blizzard-api/wow': major +--- + +Many types have had keys added, removed, made nullable or otherwise edited to better reflect the possible return values of the API. This update is the largest pass of all the response types since the library was first published. diff --git a/.changeset/old-eggs-clap.md b/.changeset/old-eggs-clap.md new file mode 100644 index 00000000..a33ea0e8 --- /dev/null +++ b/.changeset/old-eggs-clap.md @@ -0,0 +1,11 @@ +--- +'@blizzard-api/classic-wow': major +'@blizzard-api/client': major +'@blizzard-api/core': major +'@blizzard-api/sc2': major +'@blizzard-api/wow': major +'@blizzard-api/d3': major +'@blizzard-api/hs': major +--- + +Update minimum node version to ^20.19.0 || ^22.13.0 || >=24 diff --git a/.changeset/petite-walls-clean.md b/.changeset/petite-walls-clean.md new file mode 100644 index 00000000..a108e48a --- /dev/null +++ b/.changeset/petite-walls-clean.md @@ -0,0 +1,5 @@ +--- +'@blizzard-api/client': patch +--- + +Update ky to 1.14.1 diff --git a/.changeset/twelve-planes-grin.md b/.changeset/twelve-planes-grin.md new file mode 100644 index 00000000..1a553538 --- /dev/null +++ b/.changeset/twelve-planes-grin.md @@ -0,0 +1,5 @@ +--- +'@blizzard-api/client': major +--- + +Remove the axios compatability layer that resulted in response existing both directly in the response and in the data. If you face errors after this you likely just need to remove accessing data. diff --git a/.changeset/violet-bats-build.md b/.changeset/violet-bats-build.md new file mode 100644 index 00000000..132fc12e --- /dev/null +++ b/.changeset/violet-bats-build.md @@ -0,0 +1,9 @@ +--- +'@blizzard-api/classic-wow': major +'@blizzard-api/sc2': major +'@blizzard-api/wow': major +'@blizzard-api/d3': major +'@blizzard-api/hs': major +--- + +Moved a series of base parameters and generic types/interfaces into @blizzard-api/core to better share types between packages. If you can't access a type or interface anymore, it should now be available in @blizzard-api/core. diff --git a/.changeset/witty-bears-return.md b/.changeset/witty-bears-return.md new file mode 100644 index 00000000..e1c05bbc --- /dev/null +++ b/.changeset/witty-bears-return.md @@ -0,0 +1,5 @@ +--- +'@blizzard-api/core': minor +--- + +Add a series of base parameters that can be used when dealing with Blizzard API. These are used throughout the game packages. diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5884bb09..d3cf3ec5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,7 @@ name: CI permissions: contents: write + id-token: write pull-requests: write on: @@ -31,7 +32,7 @@ jobs: - uses: pnpm/action-setup@f2b2b233b538f500472c7274c7012f57857d8ce0 # https://github.com/pnpm/action-setup/commit/f2b2b233b538f500472c7274c7012f57857d8ce0 with: - version: 10.24.0 + version: 10.28.0 - name: Cache turbo build setup uses: actions/cache@v4 @@ -72,4 +73,5 @@ jobs: publish: pnpm release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_CONFIG_PROVENANCE: true NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index e747dedc..db1292f4 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -33,7 +33,7 @@ jobs: uses: actions/configure-pages@v5 - uses: pnpm/action-setup@f2b2b233b538f500472c7274c7012f57857d8ce0 # https://github.com/pnpm/action-setup/commit/f2b2b233b538f500472c7274c7012f57857d8ce0 with: - version: 10.24.0 + version: 10.28.0 - name: Setup Node.js 22.x uses: actions/setup-node@v4 with: diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 12e2f723..78348c4d 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,3 +1,3 @@ { - "recommendations": ["dbaeumer.vscode-eslint", "prettier.prettier-vscode", "yoavbls.pretty-ts-errors"] + "recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode", "yoavbls.pretty-ts-errors"] } diff --git a/eslint.config.js b/eslint.config.js index f4a36160..d75c0c68 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,8 +1,8 @@ import { configs as putstackConfigs } from '@putstack/eslint-config-typescript'; import jsdocEslint from 'eslint-plugin-jsdoc'; -import tseslint from 'typescript-eslint'; +import { defineConfig } from 'eslint/config'; -export default tseslint.config( +export default defineConfig( { ignores: ['**/coverage/**', '**/dist/**', '**/node_modules/**', '**/build/**', '**/docs/**', '!.prettierrc.js'], }, diff --git a/generated/schemas/classic-wow/auction-house.ts b/generated/schemas/classic-wow/auction-house.ts new file mode 100644 index 00000000..4225a2c5 --- /dev/null +++ b/generated/schemas/classic-wow/auction-house.ts @@ -0,0 +1,25 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { hrefSchema, nameIdKeySchema, nameIdSchema, responseBaseSchema } from '../core'; + +export const auctionHouseIndexResponseSchema = responseBaseSchema.extend({ + auctions: z.array(nameIdKeySchema), +}); + +const auctionSchema = z.strictObject({ + bid: z.number(), + buyout: z.number(), + id: z.number(), + item: z.strictObject({ + id: z.number(), + rand: z.number().optional(), + seed: z.number().optional(), + }), + quantity: z.number(), + time_left: z.union([z.literal('LONG'), z.literal('MEDIUM'), z.literal('SHORT'), z.literal('VERY_LONG')]), +}); + +export const auctionsResponseSchema = nameIdSchema.extend(responseBaseSchema.shape).extend({ + auctions: z.array(auctionSchema), + connected_realm: hrefSchema, +}); diff --git a/generated/schemas/classic-wow/character-achievements.ts b/generated/schemas/classic-wow/character-achievements.ts new file mode 100644 index 00000000..2100c975 --- /dev/null +++ b/generated/schemas/classic-wow/character-achievements.ts @@ -0,0 +1,83 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { characterSchema, nameIdKeySchema, responseBaseSchema } from '../core'; + +const categoryProgressSchema = z.strictObject({ + category: nameIdKeySchema, + points: z.number(), + quantity: z.number(), +}); + +const recentEventSchema = z.strictObject({ + achievement: nameIdKeySchema, + timestamp: z.number(), +}); + +const statisticSchema = z.strictObject({ + description: z.string().optional().nullable(), + id: z.number(), + last_updated_timestamp: z.number(), + name: z.string(), + quantity: z.number(), +}); + +const subCategorySchema = z.strictObject({ + id: z.number(), + name: z.string(), + statistics: z.array(statisticSchema), +}); + +const childCriterum3Schema = z.strictObject({ + amount: z.number().optional(), + id: z.number(), + is_completed: z.boolean(), +}); + +const categorySchema = z.strictObject({ + id: z.number(), + name: z.string(), + statistics: z.array(statisticSchema).optional(), + sub_categories: z.array(subCategorySchema).optional(), +}); + +const childCriterum2Schema = z.strictObject({ + amount: z.number().optional(), + child_criteria: z.array(childCriterum3Schema).optional(), + id: z.number(), + is_completed: z.boolean(), +}); + +const childCriterumSchema = z.strictObject({ + amount: z.number().optional(), + child_criteria: z.array(childCriterum2Schema).optional(), + id: z.number(), + is_completed: z.boolean(), +}); + +export const characterAchievementStatisticsResponseSchema = responseBaseSchema.extend({ + categories: z.array(categorySchema), + character: characterSchema, +}); + +const criteriaSchema = z.strictObject({ + amount: z.number().optional(), + child_criteria: z.array(childCriterumSchema).optional(), + id: z.number(), + is_completed: z.boolean(), +}); + +const achievementSchema = z.strictObject({ + achievement: nameIdKeySchema, + completed_timestamp: z.number().optional(), + criteria: criteriaSchema.optional(), + id: z.number(), +}); + +export const characterAchievementsSummaryResponseSchema = responseBaseSchema.extend({ + achievements: z.array(achievementSchema), + category_progress: z.array(categoryProgressSchema), + character: characterSchema, + recent_events: z.array(recentEventSchema), + total_points: z.number(), + total_quantity: z.number(), +}); diff --git a/generated/schemas/classic-wow/character-equipment.ts b/generated/schemas/classic-wow/character-equipment.ts new file mode 100644 index 00000000..43039fd3 --- /dev/null +++ b/generated/schemas/classic-wow/character-equipment.ts @@ -0,0 +1,179 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { characterSchema, colorSchema, keyBaseSchema, nameIdKeySchema, responseBaseSchema } from '../core'; + +const nameDescriptionSchema = z.strictObject({ + color: colorSchema, + display_string: z.string(), +}); + +const nameTypeSchema = z.strictObject({ + name: z.string(), + type: z.string(), +}); + +const displayStringsSchema = z.strictObject({ + copper: z.string(), + gold: z.string(), + header: z.string(), + silver: z.string(), +}); + +const displayStringValueSchema = z.strictObject({ + display_string: z.string(), + value: z.number(), +}); + +const effectSchema = z.strictObject({ + display_string: z.string(), + is_active: z.boolean(), + required_count: z.number(), +}); + +const enchantmentSlotSchema = z.strictObject({ + id: z.number(), + type: z.string().optional(), +}); + +const armorSchema = z.strictObject({ + display: nameDescriptionSchema, + value: z.number(), +}); + +const enchantmentSchema = z.strictObject({ + display_string: z.string().optional(), + enchantment_id: z.number(), + enchantment_slot: enchantmentSlotSchema, + source_item: nameIdKeySchema.optional(), + spell: z + .strictObject({ + description: z.string(), + spell: nameIdKeySchema, + }) + .optional(), +}); + +const modifiedCraftingStatSchema = z.strictObject({ + id: z.number(), + name: z.string(), + type: z.string(), +}); + +const sellPriceSchema = z.strictObject({ + display_strings: displayStringsSchema, + value: z.number(), +}); + +const socketSchema = z.strictObject({ + display_string: z.string(), + item: nameIdKeySchema, + media: keyBaseSchema.and( + z.strictObject({ + id: z.number(), + }), + ), + socket_type: nameTypeSchema, +}); + +const spellSchema = z.strictObject({ + description: z.string(), + spell: nameIdKeySchema, +}); + +const statSchema = z.strictObject({ + display: nameDescriptionSchema, + is_equip_bonus: z.boolean().optional(), + is_negated: z.boolean().optional(), + type: nameTypeSchema, + value: z.number(), +}); + +const transmogSchema = z.strictObject({ + display_string: z.string(), + item: nameIdKeySchema, + item_modified_appearance_id: z.number(), +}); + +const itemElementSchema = z.strictObject({ + is_equipped: z.boolean().optional(), + item: nameIdKeySchema, +}); + +const playableClassesSchema = z.strictObject({ + display_string: z.string(), + links: z.array(nameIdKeySchema), +}); + +const requirementsSchema = z.strictObject({ + level: displayStringValueSchema, + playable_classes: playableClassesSchema.optional(), +}); + +const setSchema = z.strictObject({ + display_string: z.string().optional(), + effects: z.array(effectSchema).optional(), + item_set: nameIdKeySchema.optional(), + items: z.array(itemElementSchema).optional(), +}); + +const damageSchema = z.strictObject({ + damage_class: nameTypeSchema, + display_string: z.string(), + max_value: z.number(), + min_value: z.number(), +}); + +const weaponSchema = z.strictObject({ + attack_speed: displayStringValueSchema, + damage: damageSchema, + dps: displayStringValueSchema, +}); + +const equippedItemSchema = z.strictObject({ + armor: armorSchema.optional(), + binding: nameTypeSchema, + bonus_list: z.array(z.number()).optional(), + context: z.number().optional(), + description: z.string().optional(), + durability: displayStringValueSchema.optional(), + enchantments: z.array(enchantmentSchema).optional(), + inventory_type: nameTypeSchema, + is_subclass_hidden: z.boolean().optional(), + item: keyBaseSchema.and( + z.strictObject({ + id: z.number(), + }), + ), + item_class: nameIdKeySchema, + item_subclass: nameIdKeySchema, + level: displayStringValueSchema.optional(), + limit_category: z.string().optional(), + media: keyBaseSchema.and( + z.strictObject({ + id: z.number(), + }), + ), + modified_appearance_id: z.number().optional(), + modified_crafting_stat: z.array(modifiedCraftingStatSchema).optional(), + name: z.string(), + name_description: nameDescriptionSchema.optional(), + quality: nameTypeSchema, + quantity: z.number(), + requirements: requirementsSchema.optional(), + sell_price: sellPriceSchema.optional(), + set: setSchema.optional(), + slot: nameTypeSchema, + sockets: z.array(socketSchema).optional(), + spells: z.array(spellSchema).optional(), + stats: z.array(statSchema).optional(), + transmog: transmogSchema.optional(), + unique_equipped: z.string().optional(), + upgrade_id: z.number().optional(), + weapon: weaponSchema.optional(), +}); + +export const characterEquipmentSummaryResponseSchema = responseBaseSchema.extend({ + character: characterSchema, + equipped_item_sets: z.array(setSchema), + equipped_items: z.array(equippedItemSchema), +}); diff --git a/generated/schemas/classic-wow/character-hunter-pets.ts b/generated/schemas/classic-wow/character-hunter-pets.ts new file mode 100644 index 00000000..a26a1288 --- /dev/null +++ b/generated/schemas/classic-wow/character-hunter-pets.ts @@ -0,0 +1,22 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { characterSchema, keyBaseSchema, nameIdKeySchema, responseBaseSchema } from '../core'; + +const hunterPetSchema = z.strictObject({ + creature: nameIdKeySchema, + creature_display: keyBaseSchema.and( + z.strictObject({ + id: z.number(), + }), + ), + is_active: z.boolean().optional(), + is_summoned: z.boolean().optional(), + level: z.number(), + name: z.string(), + slot: z.number(), +}); + +export const characterHunterPetsSummaryResponseSchema = responseBaseSchema.extend({ + character: characterSchema, + hunter_pets: z.array(hunterPetSchema), +}); diff --git a/generated/schemas/classic-wow/character-media.ts b/generated/schemas/classic-wow/character-media.ts new file mode 100644 index 00000000..6c95c98f --- /dev/null +++ b/generated/schemas/classic-wow/character-media.ts @@ -0,0 +1,13 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { characterSchema, responseBaseSchema } from '../core'; + +const assetSchema = z.strictObject({ + key: z.string(), + value: z.string(), +}); + +export const characterMediaSummaryResponseSchema = responseBaseSchema.extend({ + assets: z.array(assetSchema), + character: characterSchema, +}); diff --git a/generated/schemas/classic-wow/character-profile.ts b/generated/schemas/classic-wow/character-profile.ts new file mode 100644 index 00000000..0c617250 --- /dev/null +++ b/generated/schemas/classic-wow/character-profile.ts @@ -0,0 +1,42 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { factionSchema, genderSchema, hrefSchema, nameIdKeySchema, realmSchema, responseBaseSchema } from '../core'; + +const guildSchema = nameIdKeySchema.extend({ + faction: factionSchema, + realm: realmSchema, +}); + +export const characterProfileSummaryResponseSchema = responseBaseSchema.extend({ + achievement_points: z.number().optional(), + achievements: hrefSchema.optional(), + active_spec: nameIdKeySchema, + active_title: z + .strictObject({ + name: z.string(), + }) + .optional(), + appearance: hrefSchema, + average_item_level: z.number(), + character_class: nameIdKeySchema, + equipment: hrefSchema, + equipped_item_level: z.number(), + experience: z.number(), + faction: factionSchema, + gender: genderSchema, + guild: guildSchema, + hunter_pets: hrefSchema.optional(), + id: z.number(), + is_ghost: z.boolean().optional(), + is_self_found: z.boolean().optional(), + last_login_timestamp: z.number(), + level: z.number(), + media: hrefSchema, + name: z.string(), + pvp_summary: hrefSchema, + race: nameIdKeySchema, + realm: realmSchema, + specializations: hrefSchema, + statistics: hrefSchema, + titles: hrefSchema, +}); diff --git a/generated/schemas/classic-wow/character-specialization.ts b/generated/schemas/classic-wow/character-specialization.ts new file mode 100644 index 00000000..6957f9c0 --- /dev/null +++ b/generated/schemas/classic-wow/character-specialization.ts @@ -0,0 +1,48 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { characterSchema, nameIdKeySchema, nameIdSchema, responseBaseSchema } from '../core'; + +const spellTooltipSchema = z.strictObject({ + cast_time: z.union([z.literal('Channeled'), z.literal('Instant'), z.literal('Instant cast'), z.literal('Passive')]), + cooldown: z.string().optional(), + description: z.string(), + power_cost: z.string().optional().nullable(), + range: z.string().optional(), + spell: nameIdSchema, +}); + +const talentElementSchema = z.strictObject({ + spell_tooltip: spellTooltipSchema, + talent: z.union([ + nameIdSchema, + z.strictObject({ + id: z.number(), + }), + ]), + talent_rank: z.number().optional(), +}); + +const classicProgressionSpecializationSchema = z.strictObject({ + specialization: nameIdKeySchema, + specialization_name: z.string(), + talents: z.array(talentElementSchema).optional(), +}); + +const specializationGroupItemSchema = z.strictObject({ + specialization_name: z.string(), + spent_points: z.number(), + talents: z.array(talentElementSchema), +}); + +const specializationGroupSchema = z.strictObject({ + glyphs: z.array(nameIdSchema).optional(), + is_active: z.boolean(), + specializations: z.array(specializationGroupItemSchema).optional(), +}); + +export const characterSpecializationsSummaryResponseSchema = responseBaseSchema.extend({ + active_specialization: nameIdKeySchema.optional(), + character: characterSchema, + specialization_groups: z.array(specializationGroupSchema), + specializations: z.array(classicProgressionSpecializationSchema).optional(), +}); diff --git a/generated/schemas/classic-wow/character-statistics.ts b/generated/schemas/classic-wow/character-statistics.ts new file mode 100644 index 00000000..2533663c --- /dev/null +++ b/generated/schemas/classic-wow/character-statistics.ts @@ -0,0 +1,57 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { characterSchema, nameIdKeySchema, responseBaseSchema } from '../core'; + +const baseEffectiveStatSchema = z.strictObject({ + base: z.number(), + effective: z.number(), +}); + +const ratingWithValueSchema = z.strictObject({ + rating_bonus: z.number(), + rating_normalized: z.number(), + value: z.number(), +}); + +export const characterStatisticsSummaryResponseSchema = responseBaseSchema.extend({ + agility: baseEffectiveStatSchema, + arcane_resistance: baseEffectiveStatSchema.optional(), + armor: baseEffectiveStatSchema, + attack_power: z.number(), + block: ratingWithValueSchema, + bonus_armor: z.number().optional(), + character: characterSchema, + defense: baseEffectiveStatSchema.optional(), + dodge: ratingWithValueSchema, + fire_resistance: baseEffectiveStatSchema.optional(), + health: z.number(), + holy_resistance: baseEffectiveStatSchema.optional(), + intellect: baseEffectiveStatSchema, + main_hand_damage_max: z.number(), + main_hand_damage_min: z.number(), + main_hand_dps: z.number(), + main_hand_speed: z.number(), + mana_regen: z.number(), + mana_regen_combat: z.number(), + mastery: ratingWithValueSchema.optional(), + melee_crit: ratingWithValueSchema, + melee_haste: ratingWithValueSchema.optional(), + nature_resistance: baseEffectiveStatSchema.optional(), + off_hand_damage_max: z.number(), + off_hand_damage_min: z.number(), + off_hand_dps: z.number(), + off_hand_speed: z.number(), + parry: ratingWithValueSchema, + power: z.number(), + power_type: nameIdKeySchema, + ranged_crit: ratingWithValueSchema, + ranged_haste: ratingWithValueSchema.optional(), + shadow_resistance: baseEffectiveStatSchema.optional(), + spell_crit: ratingWithValueSchema, + spell_haste: ratingWithValueSchema.optional(), + spell_penetration: z.number(), + spell_power: z.number(), + spirit: baseEffectiveStatSchema, + stamina: baseEffectiveStatSchema, + strength: baseEffectiveStatSchema, +}); diff --git a/generated/schemas/classic-wow/connected-realm.ts b/generated/schemas/classic-wow/connected-realm.ts new file mode 100644 index 00000000..0c7fa49f --- /dev/null +++ b/generated/schemas/classic-wow/connected-realm.ts @@ -0,0 +1,121 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { + baseSearchParametersSchema, + hrefSchema, + keyBaseSchema, + localesSchema, + nameIdKeySchema, + responseBaseSchema, + searchResponseWithoutResultsSchema, +} from '../core'; + +export const connectedRealmIndexResponseSchema = responseBaseSchema.extend({ + connected_realms: z.array(hrefSchema), +}); + +const realmPopulationCapitalizedSchema = z.union([ + z.literal('FULL'), + z.literal('HIGH'), + z.literal('LOCKED'), + z.literal('LOW'), + z.literal('MEDIUM'), + z.literal('RECOMMENDED'), +]); + +const realmLockedStatusSchema = z.strictObject({ + is_locked_for_new_characters: z.boolean(), + is_locked_for_pct: z.boolean(), +}); + +const realmStatusSchema = z.union([z.literal('Down'), z.literal('Up')]); + +const realmStatusCapitalizedSchema = z.union([z.literal('DOWN'), z.literal('UP')]); + +const searchRealmPopulationSchema = z.strictObject({ + name: z.record(localesSchema, z.string()), + type: realmPopulationCapitalizedSchema, +}); + +const searchRealmStatusSchema = z.strictObject({ + name: z.record(localesSchema, z.string()), + type: realmStatusCapitalizedSchema, +}); + +const realmTimezoneSchema = z.any(); + +const realmCategorySchema = z.any(); + +const realmLocalesSchema = z.any(); + +const realmTypeCapitalizedSchema = z.any(); + +const realmSchema = z.strictObject({ + category: realmCategorySchema, + connected_realm: hrefSchema, + id: z.number(), + is_tournament: z.boolean(), + locale: realmLocalesSchema, + name: z.string(), + region: nameIdKeySchema, + slug: z.string(), + timezone: realmTimezoneSchema, + type: z.strictObject({ + name: z.string(), + type: realmTypeCapitalizedSchema, + }), +}); + +export const connectedRealmSearchParametersSchema = baseSearchParametersSchema.extend({ + 'realms.timezone': realmTimezoneSchema.optional(), + 'status.type': realmStatusCapitalizedSchema.optional(), +}); + +const searchRealmSchema = z.strictObject({ + category: z.record(localesSchema, z.string()), + id: z.number(), + is_tournament: z.boolean(), + locale: realmLocalesSchema, + name: z.record(localesSchema, z.union([z.string(), z.undefined()])), + region: z.strictObject({ + id: z.number(), + name: z.record(localesSchema, z.string()), + }), + slug: z.string(), + timezone: realmTimezoneSchema, + type: z.strictObject({ + name: z.record(localesSchema, z.string()), + type: realmTypeCapitalizedSchema, + }), +}); + +export const connectedRealmResponseSchema = responseBaseSchema.extend({ + auctions: hrefSchema, + has_queue: z.boolean(), + id: z.number(), + population: z.strictObject({ + name: z.string(), + type: realmPopulationCapitalizedSchema, + }), + pvp_season: hrefSchema.optional(), + realm_locked_status: realmLockedStatusSchema.optional(), + realms: z.array(realmSchema), + status: z.strictObject({ + name: realmStatusSchema, + type: realmStatusCapitalizedSchema, + }), +}); + +const connectedRealmSearchResponseItemSchema = keyBaseSchema.extend({ + data: z.strictObject({ + has_queue: z.boolean(), + id: z.number(), + population: searchRealmPopulationSchema, + realms: z.array(searchRealmSchema), + status: searchRealmStatusSchema, + }), +}); + +export const connectedRealmSearchResponseSchema = searchResponseWithoutResultsSchema.extend({ + results: z.array(connectedRealmSearchResponseItemSchema), +}); diff --git a/generated/schemas/classic-wow/creature.ts b/generated/schemas/classic-wow/creature.ts new file mode 100644 index 00000000..72b00b58 --- /dev/null +++ b/generated/schemas/classic-wow/creature.ts @@ -0,0 +1,95 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { + baseSearchParametersSchema, + keyBaseSchema, + localesSchema, + mediaAssetSchema, + nameIdKeySchema, + responseBaseSchema, + searchResponseWithoutResultsSchema, +} from '../core'; + +const displayMediaAssetSchema = z.strictObject({ + key: z.string(), + value: z.string(), +}); + +export const creatureFamilyIndexResponseSchema = responseBaseSchema.extend({ + creature_families: z.array(nameIdKeySchema), +}); + +export const creatureFamilyMediaResponseSchema = responseBaseSchema.extend({ + assets: z.array(mediaAssetSchema), + id: z.number(), +}); + +const mediaSchema = keyBaseSchema.extend({ + id: z.number(), +}); + +const creatureDisplaySchema = keyBaseSchema.extend({ + id: z.number(), +}); + +export const creatureSearchParametersSchema = baseSearchParametersSchema.extend({ + locale: localesSchema, + name: z.string(), +}); + +const creatureSearchResponseItemSchema = keyBaseSchema.extend({ + data: z.strictObject({ + creature_displays: z.array( + z.strictObject({ + id: z.number(), + }), + ), + family: z + .strictObject({ + id: z.number(), + name: z.record(localesSchema, z.string()), + }) + .optional(), + id: z.number(), + is_tameable: z.boolean(), + name: z.record(localesSchema, z.union([z.string(), z.undefined()])), + type: z.strictObject({ + id: z.number(), + name: z.record(localesSchema, z.string()), + }), + }), +}); + +export const creatureTypeIndexResponseSchema = responseBaseSchema.extend({ + creature_types: z.array(nameIdKeySchema), +}); + +export const creatureTypeResponseSchema = responseBaseSchema.extend({ + id: z.number(), + name: z.string(), +}); + +export const creatureDisplayMediaResponseSchema = responseBaseSchema.extend({ + assets: z.array(displayMediaAssetSchema), + id: z.number(), +}); + +export const creatureFamilyResponseSchema = responseBaseSchema.extend({ + id: z.number(), + media: mediaSchema.optional(), + name: z.string(), + specialization: nameIdKeySchema.optional(), +}); + +export const creatureResponseSchema = responseBaseSchema.extend({ + creature_displays: z.array(creatureDisplaySchema), + family: nameIdKeySchema, + id: z.number(), + is_tameable: z.boolean(), + name: z.string(), + type: nameIdKeySchema, +}); + +export const creatureSearchResponseSchema = searchResponseWithoutResultsSchema.extend({ + results: z.array(creatureSearchResponseItemSchema), +}); diff --git a/generated/schemas/classic-wow/guild-crest.ts b/generated/schemas/classic-wow/guild-crest.ts new file mode 100644 index 00000000..7d34143b --- /dev/null +++ b/generated/schemas/classic-wow/guild-crest.ts @@ -0,0 +1,39 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { colorSchema, keyBaseSchema, responseBaseSchema } from '../core'; + +const guildCrestAssetSchema = z.strictObject({ + key: z.string(), + value: z.string(), +}); + +const backgroundSchema = z.strictObject({ + id: z.number(), + rgba: colorSchema, +}); + +const mediaSchema = keyBaseSchema.extend({ + id: z.number(), +}); + +const colorsSchema = z.strictObject({ + backgrounds: z.array(backgroundSchema).optional(), + borders: z.array(backgroundSchema).optional(), + emblems: z.array(backgroundSchema).optional(), +}); + +export const guildCrestBorderEmblemResponseSchema = responseBaseSchema.extend({ + assets: z.array(guildCrestAssetSchema), + id: z.number(), +}); + +const borderSchema = z.strictObject({ + id: z.number(), + media: mediaSchema, +}); + +export const guildCrestComponentsIndexResponseSchema = responseBaseSchema.extend({ + borders: z.array(borderSchema), + colors: colorsSchema, + emblems: z.array(borderSchema), +}); diff --git a/generated/schemas/classic-wow/guild.ts b/generated/schemas/classic-wow/guild.ts new file mode 100644 index 00000000..2a677030 --- /dev/null +++ b/generated/schemas/classic-wow/guild.ts @@ -0,0 +1,137 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { + characterSchema, + colorSchema, + factionSchema, + hrefSchema, + keyBaseSchema, + nameIdKeySchema, + realmSchema, + responseBaseSchema, +} from '../core'; + +const guildSchema = nameIdKeySchema.extend({ + faction: factionSchema, + realm: realmSchema, +}); + +const categoryProgressSchema = z.strictObject({ + category: nameIdKeySchema, + points: z.number(), + quantity: z.number(), +}); + +const recentEventSchema = z.strictObject({ + achievement: nameIdKeySchema, + timestamp: z.number(), +}); + +const characterAchievementSchema = z.strictObject({ + achievement: nameIdKeySchema, + character: characterSchema, +}); + +const rgbWithIdSchema = z.strictObject({ + id: z.number(), + rgba: colorSchema, +}); + +const childCriterumSchema = z.strictObject({ + amount: z.number(), + id: z.number(), + is_completed: z.boolean(), +}); + +const borderSchema = z.strictObject({ + color: rgbWithIdSchema, + id: z.number(), + media: keyBaseSchema.and( + z.strictObject({ + id: z.number(), + }), + ), +}); + +const criteriaSchema = z.strictObject({ + amount: z.number().optional(), + child_criteria: z.array(childCriterumSchema).optional(), + id: z.number(), + is_completed: z.boolean(), +}); + +const playableSchema = keyBaseSchema.extend({ + id: z.number(), +}); + +const rosterMemberCharacterSchema = characterSchema.extend({ + level: z.number(), + playable_class: playableSchema, + playable_race: playableSchema, +}); + +export const guildAchievementsClassicEraResponseSchema = responseBaseSchema.extend({ + guild: guildSchema, +}); + +const achievementSchema = z.strictObject({ + achievement: nameIdKeySchema, + completed_timestamp: z.number().optional(), + criteria: criteriaSchema.optional(), + id: z.number(), +}); + +const activityElementSchema = z.strictObject({ + activity: z.strictObject({ + type: z.string(), + }), + character_achievement: characterAchievementSchema, + timestamp: z.number(), +}); + +const crestSchema = z.strictObject({ + background: z.strictObject({ + color: rgbWithIdSchema, + }), + border: borderSchema, + emblem: borderSchema, +}); + +const memberSchema = z.strictObject({ + character: rosterMemberCharacterSchema, + rank: z.number(), +}); + +export const guildAchievementsResponseSchema = responseBaseSchema.extend({ + achievements: z.array(achievementSchema), + category_progress: z.array(categoryProgressSchema), + guild: guildSchema, + recent_events: z.array(recentEventSchema), + total_points: z.number(), + total_quantity: z.number(), +}); + +export const guildActivityResponseSchema = responseBaseSchema.extend({ + activities: z.array(activityElementSchema).optional(), + guild: guildSchema, +}); + +export const guildResponseSchema = responseBaseSchema.extend({ + achievement_points: z.number(), + achievements: hrefSchema, + activity: hrefSchema, + created_timestamp: z.number(), + crest: crestSchema.optional(), + faction: factionSchema, + id: z.number(), + member_count: z.number(), + name: z.string(), + name_search: z.string(), + realm: realmSchema, + roster: hrefSchema, +}); + +export const guildRosterResponseSchema = responseBaseSchema.extend({ + guild: guildSchema, + members: z.array(memberSchema), +}); diff --git a/generated/schemas/classic-wow/index.ts b/generated/schemas/classic-wow/index.ts new file mode 100644 index 00000000..6ad9ae17 --- /dev/null +++ b/generated/schemas/classic-wow/index.ts @@ -0,0 +1,20 @@ +export * from './auction-house'; +export * from './character-achievements'; +export * from './character-equipment'; +export * from './character-hunter-pets'; +export * from './character-media'; +export * from './character-profile'; +export * from './character-specialization'; +export * from './character-statistics'; +export * from './connected-realm'; +export * from './creature'; +export * from './guild'; +export * from './guild-crest'; +export * from './item'; +export * from './media-search'; +export * from './playable-class'; +export * from './playable-race'; +export * from './power-type'; +export * from './pvp-season'; +export * from './realm'; +export * from './region'; diff --git a/generated/schemas/classic-wow/item.ts b/generated/schemas/classic-wow/item.ts new file mode 100644 index 00000000..0019ce98 --- /dev/null +++ b/generated/schemas/classic-wow/item.ts @@ -0,0 +1,280 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { + baseSearchParametersSchema, + colorSchema, + keyBaseSchema, + localesSchema, + mediaAssetSchema, + nameIdKeySchema, + nameIdSchema, + responseBaseSchema, + searchResponseWithoutResultsSchema, +} from '../core'; + +export const itemClassIndexResponseSchema = responseBaseSchema.extend({ + item_classes: z.array(nameIdKeySchema), +}); + +export const itemClassResponseSchema = responseBaseSchema.extend({ + class_id: z.number(), + item_subclasses: z.array(nameIdKeySchema), + name: z.string(), +}); + +export const itemMediaResponseSchema = responseBaseSchema.extend({ + assets: z.array(mediaAssetSchema), + id: z.number(), +}); + +const inventoryTypeSchema = z.strictObject({ + name: z.record(localesSchema, z.string()), + type: z.union([ + z.literal('BACK'), + z.literal('BAG'), + z.literal('CHEST'), + z.literal('FEET'), + z.literal('FINGER'), + z.literal('HANDS'), + z.literal('HEAD'), + z.literal('LEGS'), + z.literal('NECK'), + z.literal('NON_EQUIP'), + z.literal('SHIRT'), + z.literal('SHOULDER'), + z.literal('TABARD'), + z.literal('TRINKET'), + z.literal('TWOHWEAPON'), + z.literal('WAIST'), + z.literal('WRIST'), + ]), +}); + +const mediaSchema = keyBaseSchema.extend({ + id: z.number(), +}); + +const itemQualitySchema = z.strictObject({ + name: z.record(localesSchema, z.string()), + type: z.union([ + z.literal('ARTIFACT'), + z.literal('COMMON'), + z.literal('EPIC'), + z.literal('HEIRLOOM'), + z.literal('LEGENDARY'), + z.literal('POOR'), + z.literal('RARE'), + z.literal('UNCOMMON'), + ]), +}); + +export const itemSearchParametersSchema = baseSearchParametersSchema.extend({ + locale: localesSchema, + name: z.string(), +}); + +const itemSearchResponseItemSchema = keyBaseSchema.extend({ + data: z.strictObject({ + id: z.number(), + inventory_type: inventoryTypeSchema, + is_equippable: z.boolean(), + is_stackable: z.boolean(), + item_class: z.strictObject({ + id: z.number(), + name: z.record(localesSchema, z.string()), + }), + item_subclass: z.strictObject({ + id: z.number(), + name: z.record(localesSchema, z.string()), + }), + level: z.number(), + max_count: z.number(), + media: z.strictObject({ + id: z.number(), + }), + name: z.record(localesSchema, z.string()), + purchase_price: z.number(), + purchase_quantity: z.number(), + quality: itemQualitySchema, + required_level: z.number(), + sell_price: z.number(), + }), +}); + +export const itemSubClassResponseSchema = responseBaseSchema.extend({ + class_id: z.number(), + display_name: z.string(), + hide_subclass_in_tooltips: z.boolean(), + subclass_id: z.number(), + verbose_name: z.string(), +}); + +const displaySchema = z.strictObject({ + color: colorSchema, + display_string: z.string(), +}); + +const damageSchema = z.strictObject({ + damage_class: z.strictObject({ + name: z.string(), + type: z.string(), + }), + display_string: z.string(), + max_value: z.number(), + min_value: z.number(), +}); + +const durabilitySchema = z.strictObject({ + display_string: z.string(), + value: z.number(), +}); + +const armorSchema = z.strictObject({ + display: displaySchema, + value: z.number(), +}); + +const requirementsSchema = z.strictObject({ + level: durabilitySchema, +}); + +const spellSchema = z.strictObject({ + description: z.string(), + spell: nameIdKeySchema, +}); + +const weaponSchema = z.strictObject({ + attack_speed: durabilitySchema, + damage: damageSchema, + dps: durabilitySchema, +}); + +const recipeItemDisplayStringsSchema = z.strictObject({ + copper: z.string(), + gold: z.string(), + header: z.string(), + silver: z.string(), +}); + +const statTypeSchema = z.union([ + z.literal('Agility'), + z.literal('Critical Strike'), + z.literal('Haste'), + z.literal('Intellect'), + z.literal('Mastery'), + z.literal('Stamina'), + z.literal('Strength'), + z.literal('Versatility'), +]); + +const statTypeCapitalizedSchema = z.union([ + z.literal('AGILITY'), + z.literal('CRIT_RATING'), + z.literal('HASTE_RATING'), + z.literal('INTELLECT'), + z.literal('MASTERY'), + z.literal('STAMINA'), + z.literal('STRENGTH'), + z.literal('VERSATILITY'), +]); + +export const itemSearchResponseSchema = searchResponseWithoutResultsSchema.extend({ + results: z.array(itemSearchResponseItemSchema), +}); + +const statSchema = z.strictObject({ + display: displaySchema, + is_negated: z.boolean().optional(), + type: z.strictObject({ + name: statTypeSchema, + type: statTypeCapitalizedSchema, + }), + value: z.number(), +}); + +const recipeItemSchema = z.strictObject({ + armor: armorSchema.optional(), + binding: z.strictObject({ + name: z.string(), + type: z.string(), + }), + durability: durabilitySchema, + inventory_type: inventoryTypeSchema, + item: mediaSchema, + item_class: nameIdKeySchema, + item_subclass: nameIdKeySchema, + level: durabilitySchema, + media: mediaSchema, + name: z.string(), + quality: itemQualitySchema, + requirements: requirementsSchema, + sell_price: z.strictObject({ + display_strings: recipeItemDisplayStringsSchema, + value: z.number(), + }), + stats: z.array(statSchema), + weapon: weaponSchema.optional(), +}); + +const recipeSchema = z.strictObject({ + item: recipeItemSchema, + reagents: z.array( + nameIdKeySchema.and( + z.strictObject({ + quantity: z.number(), + }), + ), + ), + reagents_display_string: z.string(), +}); + +const previewItemSchema = z.strictObject({ + armor: armorSchema.optional(), + binding: z + .strictObject({ + name: z.string(), + type: z.string(), + }) + .optional(), + bonus_list: z.array(z.number()).optional(), + container_slots: durabilitySchema.optional(), + context: z.number().optional(), + crafting_reagent: z.string().optional(), + description: z.string().optional(), + durability: durabilitySchema.optional(), + inventory_type: inventoryTypeSchema, + is_subclass_hidden: z.boolean().optional(), + item: mediaSchema, + item_class: nameIdKeySchema, + item_subclass: nameIdKeySchema, + level: durabilitySchema.optional(), + media: mediaSchema, + name: z.string(), + quality: itemQualitySchema, + recipe: recipeSchema.optional(), + requirements: requirementsSchema.optional(), + sell_price: z.number().optional(), + shield_block: armorSchema.optional(), + spells: z.array(spellSchema).optional(), + stats: z.array(statSchema).optional(), + unique_equipped: z.literal('Unique').optional(), + weapon: weaponSchema.optional(), +}); + +export const itemResponseSchema = nameIdSchema.extend(responseBaseSchema.shape).extend({ + description: z.string().optional(), + inventory_type: inventoryTypeSchema, + is_equippable: z.boolean(), + is_stackable: z.boolean(), + item_class: nameIdKeySchema, + item_subclass: nameIdKeySchema, + level: z.number(), + max_count: z.number(), + media: mediaSchema, + preview_item: previewItemSchema, + purchase_price: z.number(), + purchase_quantity: z.number(), + quality: itemQualitySchema, + required_level: z.number(), + sell_price: z.number(), +}); diff --git a/generated/schemas/classic-wow/media-search.ts b/generated/schemas/classic-wow/media-search.ts new file mode 100644 index 00000000..60194dcf --- /dev/null +++ b/generated/schemas/classic-wow/media-search.ts @@ -0,0 +1,23 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { + baseSearchParametersSchema, + keyBaseSchema, + mediaAssetSchema, + searchResponseWithoutResultsSchema, +} from '../core'; + +export const mediaSearchParametersSchema = baseSearchParametersSchema.extend({ + tags: z.string().optional(), +}); + +const mediaSearchResponseItemSchema = keyBaseSchema.extend({ + data: z.strictObject({ + assets: z.array(mediaAssetSchema), + id: z.number(), + }), +}); + +export const mediaSearchResponseSchema = searchResponseWithoutResultsSchema.extend({ + results: z.array(mediaSearchResponseItemSchema), +}); diff --git a/generated/schemas/classic-wow/playable-class.ts b/generated/schemas/classic-wow/playable-class.ts new file mode 100644 index 00000000..8206a837 --- /dev/null +++ b/generated/schemas/classic-wow/playable-class.ts @@ -0,0 +1,34 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { + genderNameSchema, + hrefSchema, + keyBaseSchema, + mediaAssetSchema, + nameIdKeySchema, + nameIdSchema, + responseBaseSchema, +} from '../core'; + +export const playableClassIndexResponseSchema = responseBaseSchema.extend({ + classes: z.array(nameIdKeySchema), +}); + +export const playableClassMediaResponseSchema = responseBaseSchema.extend({ + assets: z.array(mediaAssetSchema), + id: z.number(), +}); + +const mediaSchema = keyBaseSchema.extend({ + id: z.number(), +}); + +export const playableClassResponseSchema = nameIdSchema.extend(responseBaseSchema.shape).extend({ + additional_power_types: z.array(nameIdKeySchema).optional(), + gender_name: genderNameSchema, + media: mediaSchema, + playable_races: z.array(nameIdKeySchema), + power_type: nameIdKeySchema, + pvp_talent_slots: hrefSchema, + specializations: z.array(nameIdKeySchema).optional(), +}); diff --git a/generated/schemas/classic-wow/playable-race.ts b/generated/schemas/classic-wow/playable-race.ts new file mode 100644 index 00000000..f356444e --- /dev/null +++ b/generated/schemas/classic-wow/playable-race.ts @@ -0,0 +1,16 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { factionSchema, genderNameSchema, nameIdKeySchema, nameIdSchema, responseBaseSchema } from '../core'; + +export const playableRaceIndexResponseSchema = responseBaseSchema.extend({ + races: z.array(nameIdKeySchema), +}); + +export const playableRaceResponseSchema = nameIdSchema.extend(responseBaseSchema.shape).extend({ + faction: factionSchema, + gender_name: genderNameSchema, + is_allied_race: z.boolean(), + is_selectable: z.boolean(), + playable_classes: z.array(nameIdKeySchema), + racial_spells: z.array(nameIdKeySchema), +}); diff --git a/generated/schemas/classic-wow/power-type.ts b/generated/schemas/classic-wow/power-type.ts new file mode 100644 index 00000000..4278ddab --- /dev/null +++ b/generated/schemas/classic-wow/power-type.ts @@ -0,0 +1,9 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { nameIdKeySchema, nameIdSchema, responseBaseSchema } from '../core'; + +export const powerTypeIndexResponseSchema = responseBaseSchema.extend({ + power_types: z.array(nameIdKeySchema), +}); + +export const powerTypeResponseSchema = nameIdSchema.extend(responseBaseSchema.shape); diff --git a/generated/schemas/classic-wow/pvp-season.ts b/generated/schemas/classic-wow/pvp-season.ts new file mode 100644 index 00000000..cdeb4986 --- /dev/null +++ b/generated/schemas/classic-wow/pvp-season.ts @@ -0,0 +1,20 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { hrefSchema, keyBaseSchema, responseBaseSchema } from '../core'; + +const seasonSchema = keyBaseSchema.extend({ + id: z.number(), +}); + +export const pvpSeasonResponseSchema = responseBaseSchema.extend({ + id: z.number(), + leaderboards: hrefSchema, + rewards: hrefSchema, + season_name: z.string().optional(), + season_start_timestamp: z.number(), +}); + +export const pvpSeasonIndexResponseSchema = responseBaseSchema.extend({ + current_season: seasonSchema, + seasons: z.array(seasonSchema), +}); diff --git a/generated/schemas/classic-wow/realm.ts b/generated/schemas/classic-wow/realm.ts new file mode 100644 index 00000000..e1941b6d --- /dev/null +++ b/generated/schemas/classic-wow/realm.ts @@ -0,0 +1,103 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { + baseSearchParametersSchema, + hrefSchema, + keyBaseSchema, + localesSchema, + nameIdKeySchema, + nameIdSchema, + realmSchema, + responseBaseSchema, + searchResponseWithoutResultsSchema, +} from '../core'; + +export const realmCategorySchema = z.union([ + z.literal('Brazil'), + z.literal('English'), + z.literal('French'), + z.literal('German'), + z.literal('Italian'), + z.literal('Latin America'), + z.literal('Oceanic'), + z.literal('PS'), + z.literal('Russian'), + z.literal('Spanish'), + z.literal('United States'), + z.literal('\uD55C\uAD6D'), +]); + +export const realmIndexResponseSchema = responseBaseSchema.extend({ + realms: z.array(realmSchema), +}); + +export const realmLocalesSchema = z.union([ + z.literal('deDE'), + z.literal('enGB'), + z.literal('enUS'), + z.literal('esES'), + z.literal('esMX'), + z.literal('frFR'), + z.literal('itIT'), + z.literal('koKR'), + z.literal('ptBR'), + z.literal('ptPT'), + z.literal('ruRU'), + z.literal('zhCN'), + z.literal('zhTW'), +]); + +export const realmTimezoneSchema = z.union([ + z.literal('America/Chicago'), + z.literal('America/Denver'), + z.literal('America/Los_Angeles'), + z.literal('America/New_York'), + z.literal('America/Sao_Paulo'), + z.literal('Asia/Seoul'), + z.literal('Australia/Melbourne'), + z.literal('Europe/Paris'), +]); + +export const realmTypeCapitalizedSchema = z.union([z.literal('NORMAL'), z.literal('RP')]); + +export const realmSearchParametersSchema = baseSearchParametersSchema.extend({ + timezone: realmTimezoneSchema.optional(), +}); + +const realmSearchResponseItemSchema = keyBaseSchema.extend({ + data: z.strictObject({ + category: z.record(localesSchema, z.string()), + id: z.number(), + is_tournament: z.boolean(), + locale: realmLocalesSchema, + name: z.record(localesSchema, z.string()), + region: z.strictObject({ + id: z.number(), + name: z.record(localesSchema, z.string()), + }), + slug: z.string(), + timezone: realmTimezoneSchema, + type: z.strictObject({ + name: z.string(), + type: realmTypeCapitalizedSchema, + }), + }), +}); + +export const realmResponseSchema = nameIdSchema.extend(responseBaseSchema.shape).extend({ + category: realmCategorySchema, + connected_realm: hrefSchema, + is_tournament: z.boolean(), + locale: realmLocalesSchema, + region: nameIdKeySchema, + slug: z.string(), + timezone: realmTimezoneSchema, + type: z.strictObject({ + name: z.string(), + type: realmTypeCapitalizedSchema, + }), +}); + +export const realmSearchResponseSchema = searchResponseWithoutResultsSchema.extend({ + results: z.array(realmSearchResponseItemSchema), +}); diff --git a/generated/schemas/classic-wow/region.ts b/generated/schemas/classic-wow/region.ts new file mode 100644 index 00000000..aff525ba --- /dev/null +++ b/generated/schemas/classic-wow/region.ts @@ -0,0 +1,12 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { hrefSchema, nameIdSchema, responseBaseSchema } from '../core'; + +export const regionIndexResponseSchema = responseBaseSchema.extend({ + regions: z.array(hrefSchema), +}); + +export const regionResponseSchema = nameIdSchema.extend(responseBaseSchema.shape).extend({ + patch_string: z.string(), + tag: z.string(), +}); diff --git a/generated/schemas/core/base.ts b/generated/schemas/core/base.ts new file mode 100644 index 00000000..08668e76 --- /dev/null +++ b/generated/schemas/core/base.ts @@ -0,0 +1,68 @@ +// Generated by ts-to-zod +import { z } from 'zod'; + +export const baseSearchParametersSchema = z.strictObject({ + _page: z.number().optional(), + orderby: z.union([z.array(z.string()), z.string()]).optional(), +}); + +export const colorSchema = z.strictObject({ + a: z.number(), + b: z.number(), + g: z.number(), + r: z.number(), +}); + +export const factionsSchema = z.union([z.literal('ALLIANCE'), z.literal('HORDE'), z.literal('NEUTRAL')]); + +export const genderSchema = z.strictObject({ + name: z.string(), + type: z.union([z.literal('FEMALE'), z.literal('MALE')]), +}); + +export const genderNameSchema = z.strictObject({ + female: z.string().nullable(), + male: z.string().nullable(), +}); + +export const hrefSchema = z.strictObject({ + href: z.string(), +}); + +export const keyBaseSchema = z.strictObject({ + key: hrefSchema, +}); + +export const mediaAssetSchema = z.strictObject({ + file_data_id: z.number().optional(), + key: z.string(), + value: z.string(), +}); + +export const nameIdSchema = z.strictObject({ + id: z.number(), + name: z.string(), +}); + +export const nameIdKeySchema = keyBaseSchema.extend(nameIdSchema.shape); + +export const realmSchema = keyBaseSchema.extend({ + id: z.number(), + name: z.string().optional(), + slug: z.string(), +}); + +export const responseBaseSchema = z.strictObject({ + _links: z.strictObject({ + self: hrefSchema, + }), +}); + +export const characterSchema = nameIdKeySchema.extend({ + realm: realmSchema, +}); + +export const factionSchema = z.strictObject({ + name: z.string(), + type: factionsSchema, +}); diff --git a/generated/schemas/core/index.ts b/generated/schemas/core/index.ts new file mode 100644 index 00000000..d0f236a5 --- /dev/null +++ b/generated/schemas/core/index.ts @@ -0,0 +1,4 @@ +export * from './base'; +export * from './locales'; +export * from './namespace'; +export * from './search'; diff --git a/generated/schemas/core/locales.ts b/generated/schemas/core/locales.ts new file mode 100644 index 00000000..764f5546 --- /dev/null +++ b/generated/schemas/core/locales.ts @@ -0,0 +1,25 @@ +// Generated by ts-to-zod +import { z } from 'zod'; + +export const localesSchema = z.union([ + z.literal('de_DE'), + z.literal('en_GB'), + z.literal('en_US'), + z.literal('es_ES'), + z.literal('es_MX'), + z.literal('fr_FR'), + z.literal('it_IT'), + z.literal('ko_KR'), + z.literal('pt_BR'), + z.literal('ru_RU'), + z.literal('zh_CN'), + z.literal('zh_TW'), +]); + +export const originsSchema = z.union([ + z.literal('cn'), + z.literal('eu'), + z.literal('kr'), + z.literal('tw'), + z.literal('us'), +]); diff --git a/generated/schemas/core/namespace.ts b/generated/schemas/core/namespace.ts new file mode 100644 index 00000000..763856ec --- /dev/null +++ b/generated/schemas/core/namespace.ts @@ -0,0 +1,14 @@ +// Generated by ts-to-zod +import { z } from 'zod'; + +export const blizzardNamespacesSchema = z.union([ + z.literal('dynamic'), + z.literal('dynamic-classic1x'), + z.literal('dynamic-classic'), + z.literal('profile'), + z.literal('profile-classic1x'), + z.literal('profile-classic'), + z.literal('static'), + z.literal('static-classic1x'), + z.literal('static-classic'), +]); diff --git a/generated/schemas/core/search.ts b/generated/schemas/core/search.ts new file mode 100644 index 00000000..03ab6aca --- /dev/null +++ b/generated/schemas/core/search.ts @@ -0,0 +1,10 @@ +// Generated by ts-to-zod +import { z } from 'zod'; + +export const searchResponseWithoutResultsSchema = z.strictObject({ + maxPageSize: z.number(), + page: z.number(), + pageCount: z.number(), + pageSize: z.number(), + resultCountCapped: z.boolean().optional(), +}); diff --git a/generated/schemas/d3/act.ts b/generated/schemas/d3/act.ts new file mode 100644 index 00000000..85589bf7 --- /dev/null +++ b/generated/schemas/d3/act.ts @@ -0,0 +1,26 @@ +// Generated by ts-to-zod +import { z } from 'zod'; + +const questSchema = z.strictObject({ + id: z.number(), + name: z.string(), + slug: z.string(), +}); + +const actSchema = z.strictObject({ + name: z.string(), + number: z.number(), + quests: z.array(questSchema), + slug: z.string(), +}); + +export const actIndexResponseSchema = z.strictObject({ + acts: z.array(actSchema), +}); + +export const actResponseSchema = z.strictObject({ + name: z.string(), + number: z.number(), + quests: z.array(questSchema), + slug: z.string(), +}); diff --git a/generated/schemas/d3/artisan-and-recipe.ts b/generated/schemas/d3/artisan-and-recipe.ts new file mode 100644 index 00000000..7b434210 --- /dev/null +++ b/generated/schemas/d3/artisan-and-recipe.ts @@ -0,0 +1,50 @@ +// Generated by ts-to-zod +import { z } from 'zod'; + +const itemSchema = z.strictObject({ + icon: z.string(), + id: z.string(), + name: z.string(), + path: z.string(), + slug: z.string(), +}); + +const reagentSchema = z.strictObject({ + item: itemSchema, + quantity: z.number(), +}); + +const recipeSchema = z.strictObject({ + cost: z.number(), + id: z.string(), + itemProduced: itemSchema, + name: z.string(), + reagents: z.array(reagentSchema), + slug: z.string(), +}); + +const tierSchema = z.strictObject({ + taughtRecipes: z.array(recipeSchema), + tier: z.number(), + trainedRecipes: z.array(recipeSchema), +}); + +const trainingSchema = z.strictObject({ + tiers: z.array(tierSchema), +}); + +export const artisanResponseSchema = z.strictObject({ + name: z.string(), + portrait: z.string(), + slug: z.string(), + training: trainingSchema, +}); + +export const recipeResponseSchema = z.strictObject({ + cost: z.number(), + id: z.string(), + itemProduced: itemSchema, + name: z.string(), + reagents: z.array(reagentSchema), + slug: z.string(), +}); diff --git a/generated/schemas/d3/character-class-and-skill.ts b/generated/schemas/d3/character-class-and-skill.ts new file mode 100644 index 00000000..2d2779cc --- /dev/null +++ b/generated/schemas/d3/character-class-and-skill.ts @@ -0,0 +1,42 @@ +// Generated by ts-to-zod +import { z } from 'zod'; + +const skillCategorySchema = z.strictObject({ + name: z.string(), + slug: z.string(), +}); + +const skillSchema = z.strictObject({ + description: z.string(), + descriptionHtml: z.string(), + flavorText: z.string().optional(), + icon: z.string(), + level: z.number(), + name: z.string(), + slug: z.string(), + tooltipUrl: z.string(), +}); + +const runeSchema = z.strictObject({ + description: z.string(), + descriptionHtml: z.string(), + level: z.number(), + name: z.string(), + slug: z.string(), + type: z.string(), +}); + +export const characterClassResponseSchema = z.strictObject({ + femaleName: z.string(), + icon: z.string(), + maleName: z.string(), + name: z.string(), + skillCategories: z.array(skillCategorySchema), + skills: z.record(z.union([z.literal('active'), z.literal('passive')]), z.array(skillSchema)), + slug: z.string(), +}); + +export const skillResponseSchema = z.strictObject({ + runes: z.array(runeSchema), + skill: skillSchema, +}); diff --git a/generated/schemas/d3/follower.ts b/generated/schemas/d3/follower.ts new file mode 100644 index 00000000..487df799 --- /dev/null +++ b/generated/schemas/d3/follower.ts @@ -0,0 +1,20 @@ +// Generated by ts-to-zod +import { z } from 'zod'; + +const skillSchema = z.strictObject({ + description: z.string(), + descriptionHtml: z.string(), + icon: z.string(), + level: z.number(), + name: z.string(), + slug: z.string(), + tooltipUrl: z.string(), +}); + +export const followerResponseSchema = z.strictObject({ + name: z.string(), + portrait: z.string(), + realName: z.string(), + skills: z.array(skillSchema), + slug: z.string(), +}); diff --git a/generated/schemas/d3/game-data.ts b/generated/schemas/d3/game-data.ts new file mode 100644 index 00000000..cd470489 --- /dev/null +++ b/generated/schemas/d3/game-data.ts @@ -0,0 +1,121 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { hrefSchema, responseBaseSchema } from '../core'; + +export const eraIndexResponseSchema = responseBaseSchema.extend({ + current_era: z.number(), + era: z.array(hrefSchema), + generated_by: z.string(), + last_update_time: z.string(), +}); + +export const seasonIndexResponseSchema = responseBaseSchema.extend({ + current_season: z.number(), + generated_by: z.string(), + last_update_time: z.string(), + season: z.array(hrefSchema), + service_current_season: z.number(), + service_season_state: z.string(), +}); + +const leaderboardSchema = z.strictObject({ + hardcore: z.boolean().optional(), + hero_class_string: z.string().optional(), + ladder: hrefSchema, + team_size: z.number().optional(), +}); + +const leaderboardIdSchema = z.union([ + z.literal('AchievementPoints'), + z.literal('BattleTag'), + z.literal('ClanName'), + z.literal('CompletedTime'), + z.literal('GameAccount'), + z.literal('HeroBattleTag'), + z.literal('HeroClanTag'), + z.literal('HeroClass'), + z.literal('HeroGender'), + z.literal('HeroId'), + z.literal('HeroLevel'), + z.literal('HeroVisualItems'), + z.literal('ParagonLevel'), + z.literal('Rank'), + z.literal('RiftLevel'), + z.literal('RiftTime'), +]); + +const selfSchema = z.strictObject({ + href: z.string(), +}); + +const rowDataSchema = z.strictObject({ + id: leaderboardIdSchema, + number: z.number().optional(), + string: z.string().optional(), + timestamp: z.number().optional(), +}); + +const playerSchema = z.strictObject({ + accountId: z.number(), + data: z.array(rowDataSchema), + key: z.string(), +}); + +const columnSchema = z.strictObject({ + hidden: z.boolean(), + id: leaderboardIdSchema, + label: z.string().nullable(), + order: z.number().optional(), + type: z.union([z.literal('DATETIME'), z.literal('NUMBER'), z.literal('STRING')]), +}); + +const rowSchema = z.strictObject({ + data: z.array(rowDataSchema), + order: z.number(), + player: z.array(playerSchema), +}); + +const eraLeaderboardSchema = z.strictObject({ + hardcore: z.boolean().optional(), + hero_class_string: z.string().optional(), + ladder: selfSchema, + team_size: z.number(), +}); + +export const seasonLeaderboardResponseSchema = responseBaseSchema.extend({ + achievement_points: z.boolean(), + column: z.array(columnSchema), + generated_by: z.string(), + key: z.string(), + last_update_time: z.string(), + row: z.array(rowSchema), + season: z.number(), + title: z.string(), +}); + +export const seasonResponseSchema = responseBaseSchema.extend({ + generated_by: z.string(), + last_update_time: z.string(), + leaderboard: z.array(leaderboardSchema), + season_id: z.number(), +}); + +export const eraLeaderboardResponseSchema = responseBaseSchema.extend({ + column: z.array(columnSchema), + era: z.number(), + generated_by: z.string(), + greater_rift: z.boolean(), + greater_rift_solo_class: z.string(), + key: z.string(), + last_update_time: z.string(), + row: z.array(rowSchema), + title: z.string(), +}); + +export const eraResponseSchema = responseBaseSchema.extend({ + era_id: z.number(), + era_start_date: z.number(), + generated_by: z.string(), + last_update_time: z.string(), + leaderboard: z.array(eraLeaderboardSchema), +}); diff --git a/generated/schemas/d3/index.ts b/generated/schemas/d3/index.ts new file mode 100644 index 00000000..45535ef0 --- /dev/null +++ b/generated/schemas/d3/index.ts @@ -0,0 +1,8 @@ +export * from './act'; +export * from './artisan-and-recipe'; +export * from './character-class-and-skill'; +export * from './follower'; +export * from './game-data'; +export * from './item'; +export * from './item-type'; +export * from './profile'; diff --git a/generated/schemas/d3/item-type.ts b/generated/schemas/d3/item-type.ts new file mode 100644 index 00000000..5ae25f8f --- /dev/null +++ b/generated/schemas/d3/item-type.ts @@ -0,0 +1,16 @@ +// Generated by ts-to-zod +import { z } from 'zod'; + +export const itemTypeIndexResponseSchema = z.strictObject({ + id: z.string(), + name: z.string(), + path: z.string(), +}); + +export const itemTypeResponseSchema = z.strictObject({ + icon: z.string(), + id: z.string(), + name: z.string(), + path: z.string(), + slug: z.string(), +}); diff --git a/generated/schemas/d3/item.ts b/generated/schemas/d3/item.ts new file mode 100644 index 00000000..af7e18cc --- /dev/null +++ b/generated/schemas/d3/item.ts @@ -0,0 +1,47 @@ +// Generated by ts-to-zod +import { z } from 'zod'; + +export const primarySchema = z.strictObject({ + text: z.string(), + textHtml: z.string(), +}); + +export const attributesSchema = z.strictObject({ + other: z.array(z.unknown()), + primary: z.array(primarySchema), + secondary: z.array(primarySchema), +}); + +export const randomAffixSchema = z.strictObject({ + oneOf: z.array(primarySchema), +}); + +export const typeSchema = z.strictObject({ + id: z.string(), + twoHanded: z.boolean(), +}); + +export const itemResponseSchema = z.strictObject({ + accountBound: z.boolean(), + attributes: attributesSchema, + color: z.string(), + damage: z.string(), + damageHtml: z.string(), + dps: z.string(), + flavorText: z.string(), + flavorTextHtml: z.string(), + icon: z.string(), + id: z.string(), + isSeasonRequiredToDrop: z.boolean(), + name: z.string(), + randomAffixes: z.array(randomAffixSchema), + requiredLevel: z.number(), + seasonRequiredToDrop: z.number(), + setItems: z.array(z.unknown()), + slots: z.array(z.string()), + slug: z.string(), + stackSizeMax: z.number(), + tooltipParams: z.string(), + type: typeSchema, + typeName: z.string(), +}); diff --git a/generated/schemas/d3/profile.ts b/generated/schemas/d3/profile.ts new file mode 100644 index 00000000..4224eafb --- /dev/null +++ b/generated/schemas/d3/profile.ts @@ -0,0 +1,358 @@ +// Generated by ts-to-zod +import { z } from 'zod'; + +const attributesSchema = z.strictObject({ + primary: z.array(z.string()), + secondary: z.array(z.string()).optional(), +}); + +const displayColorSchema = z.union([ + z.literal('blue'), + z.literal('green'), + z.literal('orange'), + z.literal('white'), + z.literal('yellow'), +]); + +const setSchema = z.strictObject({ + description: z.string(), + descriptionHtml: z.string(), + name: z.string(), + slug: z.string(), +}); + +const killsSchema = z.strictObject({ + elites: z.number(), +}); + +const artisanSchema = z.strictObject({ + level: z.number(), + slug: z.union([z.literal('blacksmith'), z.literal('jeweler'), z.literal('mystic')]), +}); + +const accountResponseKillsSchema = z.strictObject({ + elites: z.number(), + hardcoreMonsters: z.number(), + monsters: z.number(), +}); + +const progressionSchema = z.strictObject({ + act1: z.boolean(), + act2: z.boolean(), + act3: z.boolean(), + act4: z.boolean(), + act5: z.boolean(), +}); + +const timePlayedSchema = z.strictObject({ + barbarian: z.number(), + crusader: z.number(), + 'demon-hunter': z.number(), + monk: z.number(), + necromancer: z.number(), + 'witch-doctor': z.number(), + wizard: z.number(), +}); + +const accountHeroItemSchema = z.strictObject({ + icon: z.string(), + id: z.string(), + name: z.string(), + path: z.string(), + slug: z.string(), +}); + +const completedQuestSchema = z.strictObject({ + name: z.string(), + slug: z.string(), +}); + +const runeSchema = z.strictObject({ + description: z.string(), + descriptionHtml: z.string(), + level: z.number(), + name: z.string(), + slug: z.string(), + type: z.string(), +}); + +const skillSchema = z.strictObject({ + description: z.string(), + descriptionHtml: z.string(), + flavorText: z.string().optional(), + icon: z.string(), + level: z.number(), + name: z.string(), + slug: z.string(), + tooltipUrl: z.string(), +}); + +const itemProducedSchema = z.strictObject({ + id: z.string(), + path: z.string(), +}); + +const reagentSchema = z.strictObject({ + item: accountHeroItemSchema, + quantity: z.number(), +}); + +const dyeSchema = z.strictObject({ + icon: z.string(), + id: z.string(), + name: z.string(), + tooltipParams: z.string(), +}); + +const statsSchema = z.strictObject({ + experienceBonus: z.number(), + goldFind: z.number(), + magicFind: z.number(), +}); + +const itemSchema = z.strictObject({ + displayColor: displayColorSchema.optional(), + dyeColor: dyeSchema.optional(), + icon: z.string(), + id: z.string(), + name: z.string(), + tooltipParams: z.string(), +}); + +const craftedBySchema = z.strictObject({ + cost: z.number(), + id: z.string(), + itemProduced: itemProducedSchema, + name: z.string(), + reagents: z.array(reagentSchema), + slug: z.string(), +}); + +const scoundrelSchema = z.strictObject({ + items: z.record(z.string(), itemSchema), + level: z.number(), + skills: z.array(skillSchema), + slug: z.string(), + stats: statsSchema, +}); + +const gemSchema = z.strictObject({ + attributes: z.array(z.string()), + isGem: z.boolean(), + isJewel: z.boolean(), + item: accountHeroItemSchema, + jewelRank: z.number().optional(), + jewelSecondaryUnlockRank: z.number().optional(), +}); + +const heroKillsSchema = z.strictObject({ + elites: z.number(), +}); + +const actSchema = z.strictObject({ + completed: z.boolean(), + completedQuests: z.array(completedQuestSchema), +}); + +const passiveSchema = z.strictObject({ + skill: skillSchema, +}); + +const seasonSchema = z.strictObject({ + highestHardcoreLevel: z.number(), + kills: accountResponseKillsSchema, + paragonLevel: z.number(), + paragonLevelHardcore: z.number(), + seasonId: z.number(), + timePlayed: timePlayedSchema, +}); + +const activeSchema = z.strictObject({ + rune: runeSchema, + skill: skillSchema, +}); + +const templarItemsSchema = z.strictObject({ + bracers: itemSchema, + feet: itemSchema, + hands: itemSchema, + head: itemSchema, + mainHand: itemSchema, + offHand: itemSchema, + shoulders: itemSchema, + torso: itemSchema, + waist: itemSchema, +}); + +const followerItemSchema = z.strictObject({ + accountBound: z.boolean(), + armor: z.number(), + attacksPerSecond: z.number(), + attributes: attributesSchema.optional(), + attributesHtml: attributesSchema.optional(), + blockChance: z.string().optional(), + craftedBy: craftedBySchema.optional(), + damage: z.string().optional(), + displayColor: z.string(), + dps: z.string().optional(), + dye: dyeSchema.optional(), + flavorText: z.string().optional(), + icon: z.string(), + id: z.string(), + isSeasonRequiredToDrop: z.boolean(), + itemLevel: z.number(), + maxDamage: z.number(), + minDamage: z.number(), + name: z.string(), + openSockets: z.number(), + requiredLevel: z.number(), + seasonRequiredToDrop: z.number(), + set: setSchema.optional(), + slots: z.string(), + stackSizeMax: z.number(), + tooltipParams: z.string(), + type: z.record(z.string(), z.union([z.boolean(), z.string()])), + typeName: z.string(), +}); + +export const accountHeroItemsResponseSchema = z.strictObject({ + accountBound: z.boolean(), + armor: z.number(), + attacksPerSecond: z.number(), + attributes: attributesSchema, + attributesHtml: attributesSchema, + craftedBy: craftedBySchema.optional(), + damage: z.string().optional(), + displayColor: displayColorSchema, + dps: z.string().optional(), + elementalType: z.string().optional(), + flavorText: z.string(), + gems: z.array(gemSchema).optional(), + icon: z.string(), + id: z.string(), + isSeasonRequiredToDrop: z.boolean(), + itemLevel: z.number(), + maxDamage: z.number(), + minDamage: z.number(), + name: z.string(), + openSockets: z.number(), + requiredLevel: z.number(), + seasonRequiredToDrop: z.number(), + set: setSchema.optional(), + slots: z.string(), + stackSizeMax: z.number(), + tooltipParams: z.string(), + type: z.record(z.string(), z.union([z.boolean(), z.string()])), + typeName: z.string(), +}); + +const heroProgressionSchema = z.strictObject({ + act1: actSchema, + act2: actSchema, + act3: actSchema, + act4: actSchema, + act5: actSchema, +}); + +const skillsSchema = z.strictObject({ + active: z.array(activeSchema), + passive: z.array(passiveSchema), +}); + +const heroSchema = z.strictObject({ + class: z.string(), + classSlug: z.string(), + dead: z.boolean(), + gender: z.number(), + hardcore: z.boolean(), + id: z.number(), + kills: heroKillsSchema, + 'last-updated': z.number(), + level: z.number(), + name: z.string(), + paragonLevel: z.number(), + seasonal: z.boolean(), +}); + +const enchantressItemsSchema = z.strictObject({ + mainHand: itemSchema, +}); + +const enchantressSchema = z.strictObject({ + items: enchantressItemsSchema, + level: z.number(), + skills: z.array(z.unknown()), + slug: z.string(), + stats: statsSchema, +}); + +const templarSchema = z.strictObject({ + items: templarItemsSchema, + level: z.number(), + skills: z.array(skillSchema), + slug: z.string(), + stats: statsSchema, +}); + +export const accountHeroFollowerItemsResponseSchema = z.strictObject({ + enchantress: z.record(z.string(), followerItemSchema), + scoundrel: z.record(z.string(), followerItemSchema), + templar: z.record(z.string(), followerItemSchema), +}); + +const followersSchema = z.strictObject({ + enchantress: enchantressSchema, + scoundrel: scoundrelSchema, + templar: templarSchema, +}); + +export const accountResponseSchema = z.strictObject({ + battleTag: z.string(), + blacksmith: artisanSchema, + blacksmithHardcore: artisanSchema, + blacksmithSeason: artisanSchema, + blacksmithSeasonHardcore: artisanSchema, + guildName: z.string(), + heroes: z.array(heroSchema), + highestHardcoreLevel: z.number(), + jeweler: artisanSchema, + jewelerHardcore: artisanSchema, + jewelerSeason: artisanSchema, + jewelerSeasonHardcore: artisanSchema, + kills: accountResponseKillsSchema, + lastHeroPlayed: z.number(), + lastUpdated: z.number(), + mystic: artisanSchema, + mysticHardcore: artisanSchema, + mysticSeason: artisanSchema, + mysticSeasonHardcore: artisanSchema, + paragonLevel: z.number(), + paragonLevelHardcore: z.number(), + paragonLevelSeason: z.number(), + paragonLevelSeasonHardcore: z.number(), + progression: progressionSchema, + seasonalProfiles: z.record(z.string(), seasonSchema), + timePlayed: timePlayedSchema, +}); + +export const accountHeroResponseSchema = z.strictObject({ + alive: z.boolean(), + class: z.string(), + followers: followersSchema, + gender: z.number(), + hardcore: z.boolean(), + highestSoloRiftCompleted: z.number(), + id: z.number(), + items: z.record(z.string(), itemSchema), + kills: killsSchema, + lastUpdated: z.number(), + legendaryPowers: z.array(itemSchema), + level: z.number(), + name: z.string(), + paragonLevel: z.number(), + progression: heroProgressionSchema, + seasonal: z.boolean(), + seasonCreated: z.number(), + skills: skillsSchema, + stats: z.record(z.string(), z.number()), +}); diff --git a/generated/schemas/hs/card-backs.ts b/generated/schemas/hs/card-backs.ts new file mode 100644 index 00000000..f9cad0b4 --- /dev/null +++ b/generated/schemas/hs/card-backs.ts @@ -0,0 +1,73 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { localesSchema } from '../core'; + +export const cardBackSearchParametersSchema = z.strictObject({ + cardBackCategory: z + .union([ + z.literal('achieve'), + z.literal('base'), + z.literal('blizzard'), + z.literal('esports'), + z.literal('events'), + z.literal('fireside'), + z.literal('game_license'), + z.literal('golden'), + z.literal('heroes'), + z.literal('legend'), + z.literal('pre_purchase'), + z.literal('promotion'), + z.literal('season'), + ]) + .optional(), + locale: localesSchema.optional(), + page: z.number().optional(), + pageSize: z.number().optional(), + sort: z + .union([ + z.literal('attack:asc'), + z.literal('attack:desc'), + z.literal('class:asc'), + z.literal('class:desc'), + z.literal('dataAdded:asc'), + z.literal('dataAdded:desc'), + z.literal('groupByClass:asc'), + z.literal('groupByClass:desc'), + z.literal('health:asc'), + z.literal('health:desc'), + z.literal('manaCost:asc'), + z.literal('manaCost:desc'), + z.literal('name:asc'), + z.literal('name:desc'), + ]) + .optional(), + textFilter: z.string().optional(), +}); + +export const singleCardBackSearchResponseSchema = z.strictObject({ + id: z.number(), + image: z.string(), + name: z.union([z.record(localesSchema, z.string()), z.string()]), + slug: z.string(), + sortCategory: z.number(), + text: z.union([z.record(localesSchema, z.string()), z.string()]), +}); + +export const searchOptionsSchema = z.union([ + z.literal('attack'), + z.literal('class'), + z.literal('dataAdded'), + z.literal('groupByClass'), + z.literal('health'), + z.literal('manaCost'), + z.literal('name'), +]); + +export const sortOptionsSchema = z.union([z.literal('asc'), z.literal('desc')]); + +export const cardBackSearchResponseSchema = z.strictObject({ + cardBacks: z.array(singleCardBackSearchResponseSchema), + cardCount: z.number(), + page: z.number(), + pageCount: z.number(), +}); diff --git a/generated/schemas/hs/cards.ts b/generated/schemas/hs/cards.ts new file mode 100644 index 00000000..b3907066 --- /dev/null +++ b/generated/schemas/hs/cards.ts @@ -0,0 +1,125 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { localesSchema } from '../core'; + +export const fetchOneCardResponseSchema = z.strictObject({ + artistName: z.string(), + attack: z.number(), + cardSetId: z.number(), + cardTypeId: z.number(), + classId: z.number(), + collectible: z.number(), + cropImage: z.string(), + flavorText: z.union([z.record(localesSchema, z.string()), z.string()]), + health: z.number(), + id: z.number(), + image: z.union([z.record(localesSchema, z.string()), z.string()]), + imageGold: z.union([z.record(localesSchema, z.string()), z.string()]), + isZilliaxCosmeticModule: z.boolean(), + isZilliaxFunctionalModule: z.boolean(), + keywordIds: z.array(z.number()), + manaCost: z.number(), + multiClassIds: z.array(z.number()), + name: z.union([z.record(localesSchema, z.string()), z.string()]), + rarityId: z.number(), + slug: z.string(), + text: z.union([z.record(localesSchema, z.string()), z.string()]), +}); + +export const gameModeSchema = z.union([ + z.literal('arena'), + z.literal('battlegrounds'), + z.literal('classic'), + z.literal('constructed'), + z.literal('duels'), + z.literal('mercenaries'), + z.literal('standard'), +]); + +const baseSearchParametersSchema = z.strictObject({ + gameMode: gameModeSchema.optional(), + locale: localesSchema.optional(), + mercenaryRole: z.string().optional(), + minionType: z.string().optional(), + page: z.number().optional(), + pageSize: z.number().optional(), + sort: z + .union([ + z.literal('attack:asc'), + z.literal('attack:desc'), + z.literal('health:asc'), + z.literal('health:desc'), + z.literal('name:asc'), + z.literal('name:desc'), + z.literal('tier:asc'), + z.literal('tier:desc'), + ]) + .optional(), + textFilter: z.string().optional(), + tier: z + .union([z.literal(1), z.literal(2), z.literal(3), z.literal(4), z.literal(5), z.literal(6), z.literal('hero')]) + .optional(), +}); + +const statsByLevelSchema = z.strictObject({ + attack: z.number(), + health: z.number(), +}); + +export const blizzardCardSearchParametersSchema = baseSearchParametersSchema.extend({ + attack: z.string().optional(), + defaultMercenary: z.string().optional(), + health: z.string().optional(), + mercenaryId: z.string().optional(), +}); + +export const cardSearchParametersSchema = baseSearchParametersSchema.extend({ + attack: z.union([z.array(z.number()), z.number()]).optional(), + defaultMercenary: z.union([z.array(z.number()), z.number()]).optional(), + health: z.union([z.array(z.number()), z.number()]).optional(), + mercenaryId: z.union([z.array(z.number()), z.number()]).optional(), +}); + +const mercenaryHeroSchema = z.strictObject({ + collectible: z.number(), + craftingCost: z.number(), + default: z.number(), + faction: z.number().nullable(), + mercId: z.number(), + rarity: z.number(), + roleId: z.number(), + statsByLevel: z.record(z.string(), statsByLevelSchema), +}); + +const cardSchema = z.strictObject({ + artistName: z.string().nullable(), + attack: z.number(), + cardSetId: z.number(), + cardTypeId: z.number(), + classId: z.number().nullable(), + collectible: z.number(), + cropImage: z.string().nullable(), + flavorText: z.string(), + health: z.number(), + id: z.number(), + image: z.string(), + imageGold: z.string(), + isZilliaxCosmeticModule: z.boolean(), + isZilliaxFunctionalModule: z.boolean(), + manaCost: z.number(), + mercenaryHero: mercenaryHeroSchema, + minionTypeId: z.number(), + multiClassIds: z.array(z.number()), + multiTypeIds: z.array(z.number()).optional(), + name: z.string(), + rarityId: z.number(), + slug: z.string(), + text: z.string(), +}); + +export const cardSearchResponseSchema = z.strictObject({ + cardCount: z.number(), + cards: z.array(cardSchema), + page: z.number(), + pageCount: z.number(), +}); diff --git a/generated/schemas/hs/decks.ts b/generated/schemas/hs/decks.ts new file mode 100644 index 00000000..bac94b46 --- /dev/null +++ b/generated/schemas/hs/decks.ts @@ -0,0 +1,81 @@ +// Generated by ts-to-zod +import { z } from 'zod'; + +const cardSchema = z.strictObject({ + armor: z.number().optional(), + artistName: z.string(), + attack: z.number().optional(), + bannedFromSideboard: z.number().optional(), + cardSetId: z.number(), + cardTypeId: z.number(), + childIds: z.array(z.number()).optional(), + classId: z.number(), + collectible: z.number(), + cropImage: z.string(), + flavorText: z.string(), + health: z.number().optional(), + id: z.number(), + image: z.string(), + imageGold: z.string(), + isZilliaxCosmeticModule: z.boolean(), + isZilliaxFunctionalModule: z.boolean(), + keywordIds: z.array(z.number()).optional(), + manaCost: z.number(), + minionTypeId: z.number().optional(), + multiClassIds: z.array(z.number()), + name: z.string(), + rarityId: z.number(), + slug: z.string(), + spellSchoolId: z.number().optional(), + text: z.string(), +}); + +const classSchema = z.strictObject({ + id: z.number(), + name: z.string(), + slug: z.string(), +}); + +const heroSchema = z.strictObject({ + artistName: z.string().nullable(), + cardSetId: z.number(), + cardTypeId: z.number(), + classId: z.number(), + collectible: z.number(), + cropImage: z.null(), + flavorText: z.string(), + health: z.number().optional(), + id: z.number(), + image: z.string(), + imageGold: z.string(), + isZilliaxCosmeticModule: z.boolean(), + isZilliaxFunctionalModule: z.boolean(), + manaCost: z.number(), + multiClassIds: z.array(z.number()), + name: z.string(), + parentId: z.number(), + rarityId: z.number().nullable(), + slug: z.string(), + text: z.string(), +}); + +export const deckSearchParametersSchema = z.union([ + z.strictObject({ + code: z.string(), + }), + z.strictObject({ + hero: z.string().optional(), + ids: z.string(), + }), +]); + +export const deckResponseSchema = z.strictObject({ + cardCount: z.number(), + cards: z.array(cardSchema), + class: classSchema, + deckCode: z.string(), + format: z.string(), + hero: heroSchema, + heroPower: heroSchema, + version: z.number(), +}); diff --git a/generated/schemas/hs/index.ts b/generated/schemas/hs/index.ts new file mode 100644 index 00000000..5551c026 --- /dev/null +++ b/generated/schemas/hs/index.ts @@ -0,0 +1,4 @@ +export * from './card-backs'; +export * from './cards'; +export * from './decks'; +export * from './metadata'; diff --git a/generated/schemas/hs/metadata.ts b/generated/schemas/hs/metadata.ts new file mode 100644 index 00000000..c855cd2a --- /dev/null +++ b/generated/schemas/hs/metadata.ts @@ -0,0 +1,84 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { nameIdSchema } from '../core'; + +const gameModeSchema = nameIdSchema.extend({ + gameModes: z.array(z.number()).optional(), + slug: z.string(), +}); + +const classSchema = z.strictObject({ + alternateHeroCardIds: z.array(z.number()).optional(), + cardId: z.number().optional(), + heroPowerCardId: z.number().optional(), + id: z.number(), + name: z.string(), + slug: z.string(), +}); + +const keywordSchema = nameIdSchema.extend({ + gameModes: z.array(z.number()), + refText: z.string(), + slug: z.string(), + text: z.string(), +}); + +const raritySchema = nameIdSchema.extend({ + craftingCost: z.array(z.number().nullable()), + dustValue: z.array(z.number().nullable()), + slug: z.string(), +}); + +const setGroupSchema = z.strictObject({ + cardSets: z.array(z.string()), + icon: z.string().optional(), + name: z.string(), + slug: z.string(), + standard: z.boolean().optional(), + svg: z.string().optional().nullable(), + year: z.number().optional(), + yearRange: z.string().optional(), +}); + +const setTypeSchema = z.union([z.literal(''), z.literal('adventure'), z.literal('base'), z.literal('expansion')]); + +const setSchema = nameIdSchema.extend({ + aliasSetIds: z.array(z.number()).optional(), + collectibleCount: z.number(), + collectibleRevealedCount: z.number(), + hyped: z.boolean(), + nonCollectibleCount: z.number(), + nonCollectibleRevealedCount: z.number(), + slug: z.string(), + type: setTypeSchema, +}); + +export const allMetadataResponseSchema = z.strictObject({ + arenaIds: z.array(z.number()), + bgGameModes: z.array(gameModeSchema), + cardBackCategories: z.array(gameModeSchema), + classes: z.array(classSchema), + filterableFields: z.array(z.string()), + gameModes: z.array(gameModeSchema), + keywords: z.array(keywordSchema), + mercenaryFactions: z.array(gameModeSchema), + mercenaryRoles: z.array(gameModeSchema), + minionTypes: z.array(gameModeSchema), + numericFields: z.array(z.string()), + rarities: z.array(raritySchema), + setGroups: z.array(setGroupSchema), + sets: z.array(setSchema), + spellSchools: z.array(gameModeSchema), + types: z.array(gameModeSchema), +}); + +export const specificMetadataResponseSchema = nameIdSchema.extend({ + aliasSetIds: z.array(z.number()).optional(), + collectibleCount: z.number(), + collectibleRevealedCount: z.number(), + hyped: z.boolean(), + nonCollectibleCount: z.number(), + nonCollectibleRevealedCount: z.number(), + slug: z.string(), + type: setTypeSchema, +}); diff --git a/generated/schemas/sc2/index.ts b/generated/schemas/sc2/index.ts new file mode 100644 index 00000000..10cdd261 --- /dev/null +++ b/generated/schemas/sc2/index.ts @@ -0,0 +1,4 @@ +export * from './ladder'; +export * from './league'; +export * from './legacy'; +export * from './profile'; diff --git a/generated/schemas/sc2/ladder.ts b/generated/schemas/sc2/ladder.ts new file mode 100644 index 00000000..49b5282a --- /dev/null +++ b/generated/schemas/sc2/ladder.ts @@ -0,0 +1,33 @@ +// Generated by ts-to-zod +import { z } from 'zod'; + +export const seasonResponseSchema = z.strictObject({ + endDate: z.string(), + number: z.number(), + seasonId: z.number(), + startDate: z.string(), + year: z.number(), +}); + +const teamMemberSchema = z.strictObject({ + clanTag: z.string().optional(), + displayName: z.string(), + favoriteRace: z.union([z.literal('protoss'), z.literal('random'), z.literal('terran'), z.literal('zerg')]), + id: z.string(), + realm: z.number(), + region: z.number(), +}); + +const ladderTeamSchema = z.strictObject({ + joinTimestamp: z.number(), + losses: z.number(), + mmr: z.number(), + points: z.number(), + previousRank: z.number(), + teamMembers: z.array(teamMemberSchema), + wins: z.number(), +}); + +export const grandmasterLeaderboardResponseSchema = z.strictObject({ + ladderTeams: z.array(ladderTeamSchema), +}); diff --git a/generated/schemas/sc2/league.ts b/generated/schemas/sc2/league.ts new file mode 100644 index 00000000..9db63a51 --- /dev/null +++ b/generated/schemas/sc2/league.ts @@ -0,0 +1,54 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { responseBaseSchema } from '../core'; + +const keySchema = z.strictObject({ + league_id: z.number(), + queue_id: z.number(), + season_id: z.number(), + team_type: z.number(), +}); + +export const starcraftLeagueIdSchema = z.union([ + z.literal('bronze'), + z.literal('diamond'), + z.literal('gold'), + z.literal('grandmaster'), + z.literal('master'), + z.literal('platinum'), + z.literal('silver'), +]); + +export const starcraftLeagueQueueSchema = z.union([ + z.literal('hots-1v1'), + z.literal('hots-2v2'), + z.literal('hots-3v3'), + z.literal('hots-4v4'), + z.literal('lotv-1v1'), + z.literal('lotv-2v2'), + z.literal('lotv-3v3'), + z.literal('lotv-4v4'), + z.literal('lotv-archon'), + z.literal('wol-1v1'), + z.literal('wol-2v2'), + z.literal('wol-3v3'), + z.literal('wol-4v4'), +]); + +export const starcraftLeagueTeamTypeSchema = z.union([z.literal('arranged'), z.literal('random')]); + +const divisionSchema = z.strictObject({ + id: z.number(), + ladder_id: z.number(), + member_count: z.number(), +}); + +const tierSchema = z.strictObject({ + division: z.array(divisionSchema), + id: z.number(), +}); + +export const leagueDataResponseSchema = responseBaseSchema.extend({ + key: keySchema, + tier: z.array(tierSchema), +}); diff --git a/generated/schemas/sc2/legacy.ts b/generated/schemas/sc2/legacy.ts new file mode 100644 index 00000000..53d8363b --- /dev/null +++ b/generated/schemas/sc2/legacy.ts @@ -0,0 +1,153 @@ +// Generated by ts-to-zod +import { z } from 'zod'; + +export const legacyLaddersResponseSchema = z.strictObject({ + currentSeason: z.array(z.unknown()), + previousSeason: z.array(z.unknown()), + showcasePlacement: z.array(z.unknown()), +}); + +const matchSchema = z.strictObject({ + date: z.number(), + decision: z.union([z.literal('Left'), z.literal('Loss'), z.literal('Win')]), + map: z.string(), + speed: z.union([z.literal('Fast'), z.literal('Faster')]), + type: z.union([z.literal('2v2'), z.literal('3v3'), z.literal('Co-Op'), z.literal('Custom')]), +}); + +const campaignSchema = z.strictObject({ + hots: z.string(), + wol: z.string(), +}); + +const careerSchema = z.strictObject({ + careerTotalGames: z.number(), + highest1v1Rank: z.string(), + highestTeamRank: z.string(), + primaryRace: z.string(), + protossWins: z.number(), + seasonTotalGames: z.number(), + terranWins: z.number(), + zergWins: z.number(), +}); + +const iconSchema = z.strictObject({ + h: z.number(), + offset: z.number(), + url: z.string(), + w: z.number(), + x: z.number(), + y: z.number(), +}); + +const rewardsSchema = z.strictObject({ + earned: z.array(z.string()), + selected: z.array(z.string()), +}); + +const animationSchema = z.strictObject({ + achievementId: z.string(), + command: z.literal('/dance').optional(), + icon: iconSchema, + id: z.string(), + name: z.string().optional(), + title: z.string(), +}); + +const achievementSchema = z.strictObject({ + achievementId: z.string(), + categoryId: z.string(), + description: z.string(), + icon: iconSchema, + points: z.number(), + title: z.string(), +}); + +const pointsSchema = z.strictObject({ + categoryPoints: z.record(z.string(), z.number()), + totalPoints: z.number(), +}); + +const categoryChildSchema = z.strictObject({ + categoryId: z.string(), + featuredAchievementId: z.string(), + title: z.string(), +}); + +const statSchema = z.strictObject({ + games: z.number(), + type: z.string(), + wins: z.number(), +}); + +const swarmLevelsByRaceSchema = z.strictObject({ + currentLevelXP: z.number(), + level: z.number(), + totalLevelXP: z.number(), +}); + +const categorySchema = z.strictObject({ + categoryId: z.string(), + children: z.array(categoryChildSchema).optional(), + featuredAchievementId: z.string(), + title: z.string(), +}); + +export const legacyMatchHistoryResponseSchema = z.strictObject({ + matches: z.array(matchSchema), +}); + +const achievementsSchema = z.strictObject({ + achievements: z.array( + z.strictObject({ + achievementId: z.string(), + completionDate: z.number(), + }), + ), + points: pointsSchema, +}); + +const seasonSchema = z.strictObject({ + seasonId: z.number(), + seasonNumber: z.number(), + seasonYear: z.number(), + stats: z.array(statSchema), + totalGamesThisSeason: z.number(), +}); + +const swarmLevelsSchema = z.strictObject({ + level: z.number(), + protoss: swarmLevelsByRaceSchema, + terran: swarmLevelsByRaceSchema, + zerg: swarmLevelsByRaceSchema, +}); + +export const legacyRewardsResponseSchema = z.strictObject({ + animations: z.array(animationSchema), + portraits: z.array(animationSchema), + protossDecals: z.array(animationSchema), + skins: z.array(animationSchema), + terranDecals: z.array(animationSchema), + zergDecals: z.array(animationSchema), +}); + +export const legacyAchievementsResponseSchema = z.strictObject({ + achievements: z.array(achievementSchema), + categories: z.array(categorySchema), +}); + +export const legacyProfileResponseSchema = z.strictObject({ + achievements: achievementsSchema, + campaign: campaignSchema, + career: careerSchema, + clanName: z.string(), + clanTag: z.string(), + displayName: z.string(), + id: z.string(), + portrait: iconSchema, + profilePath: z.string(), + realm: z.number(), + rewards: rewardsSchema, + season: seasonSchema, + swarmLevels: swarmLevelsSchema, +}); diff --git a/generated/schemas/sc2/profile.ts b/generated/schemas/sc2/profile.ts new file mode 100644 index 00000000..31e63293 --- /dev/null +++ b/generated/schemas/sc2/profile.ts @@ -0,0 +1,84 @@ +// Generated by ts-to-zod +import { z } from 'zod'; + +export const ladderResponseSchema = z.strictObject({ + allLadderMemberships: z.array(z.unknown()), + ladderTeams: z.array(z.unknown()), + ranksAndPools: z.array(z.unknown()), +}); + +export const ladderSummaryResponseSchema = z.strictObject({ + allLadderMemberships: z.array(z.unknown()), + placementMatches: z.array(z.unknown()), + showCaseEntries: z.array(z.unknown()), +}); + +export const metadataResponseSchema = z.strictObject({ + avatarUrl: z.string(), + name: z.string(), + profileId: z.string(), + profileUrl: z.string(), + realmId: z.number(), + regionId: z.number(), +}); + +const achievementSchema = z.strictObject({ + categoryId: z.string(), + chainAchievementIds: z.array(z.string()), + chainRewardSize: z.number(), + criteriaIds: z.array(z.string()).optional(), + description: z.string(), + flags: z.number(), + id: z.string(), + imageUrl: z.string(), + isChained: z.boolean(), + points: z.number(), + title: z.string(), + uiOrderHint: z.number(), +}); + +const categorySchema = z.strictObject({ + childrenCategoryIds: z.array(z.string()), + featuredAchievementId: z.string(), + id: z.string(), + medalTiers: z.array(z.number()).optional(), + name: z.string(), + parentCategoryId: z.string().nullable(), + points: z.number(), + uiOrderHint: z.number(), +}); + +const criterionSchema = z.strictObject({ + achievementId: z.string(), + description: z.string(), + evaluationClass: z.union([ + z.literal('Achv'), + z.literal('Clnt'), + z.literal('S2Gm'), + z.literal('Sunk'), + z.literal('Trny'), + ]), + flags: z.number(), + id: z.string(), + necessaryQuantity: z.number(), + uiOrderHint: z.number(), +}); + +const rewardSchema = z.strictObject({ + achievementId: z.string().optional(), + command: z.literal('/dance').optional(), + flags: z.number(), + id: z.string(), + imageUrl: z.string(), + isSkin: z.boolean(), + name: z.string(), + uiOrderHint: z.number(), + unlockableType: z.string(), +}); + +export const staticProfileResponseSchema = z.strictObject({ + achievements: z.array(achievementSchema), + categories: z.array(categorySchema), + criteria: z.array(criterionSchema), + rewards: z.array(rewardSchema), +}); diff --git a/generated/schemas/wow/account-profile.ts b/generated/schemas/wow/account-profile.ts new file mode 100644 index 00000000..5da584d6 --- /dev/null +++ b/generated/schemas/wow/account-profile.ts @@ -0,0 +1,163 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { + factionSchema, + genderSchema, + hrefSchema, + keyBaseSchema, + nameIdKeySchema, + nameIdSchema, + realmSchema, +} from '../core'; + +const linksSchema = z.strictObject({ + profile: hrefSchema, + self: hrefSchema, + user: hrefSchema, +}); + +const heirloomSchema = z.strictObject({ + heirloom: nameIdKeySchema, + upgrade: z.strictObject({ + level: z.number(), + }), +}); + +const mountSchema = z.strictObject({ + is_favorite: z.boolean().optional(), + mount: nameIdKeySchema, +}); + +const toySchema = z.strictObject({ + is_favorite: z.boolean().optional(), + toy: nameIdKeySchema, +}); + +const slotSchema = z.strictObject({ + name: z.string(), + type: z.string(), +}); + +const positionSchema = z.strictObject({ + facing: z.number(), + map: nameIdSchema, + x: z.number(), + y: z.number(), + z: z.number(), + zone: nameIdSchema, +}); + +const protectedStatsSchema = z.strictObject({ + level_gold_gained: z.number(), + level_gold_lost: z.number(), + level_item_value_gained: z.number(), + level_number_deaths: z.number(), + total_gold_gained: z.number(), + total_gold_lost: z.number(), + total_item_value_gained: z.number(), + total_number_deaths: z.number(), +}); + +const characterSchema = z.strictObject({ + character: hrefSchema, + faction: factionSchema, + gender: genderSchema, + id: z.number(), + level: z.number(), + name: z.string(), + playable_class: nameIdKeySchema, + playable_race: nameIdKeySchema, + protected_character: hrefSchema, + realm: realmSchema, +}); + +const qualitySchema = z.strictObject({ + name: z.string(), + type: z.union([z.literal('COMMON'), z.literal('POOR'), z.literal('RARE'), z.literal('UNCOMMON')]), +}); + +const statsSchema = z.strictObject({ + breed_id: z.number(), + health: z.number(), + power: z.number(), + speed: z.number(), +}); + +const wowAccountSchema = z.strictObject({ + characters: z.array(characterSchema), + id: z.number(), +}); + +export const accountCollectionsIndexResponseSchema = z.strictObject({ + _links: linksSchema, + heirlooms: hrefSchema, + mounts: hrefSchema, + pets: hrefSchema, + toys: hrefSchema, + transmogs: hrefSchema, +}); + +export const accountHeirloomsCollectionSummaryResponseSchema = z.strictObject({ + _links: linksSchema, + heirlooms: z.array(heirloomSchema), +}); + +export const accountMountsCollectionSummaryResponseSchema = z.strictObject({ + _links: linksSchema, + mounts: z.array(mountSchema), +}); + +const petSchema = z.strictObject({ + active_slot: z.number().optional(), + creature_display: keyBaseSchema + .and( + z.strictObject({ + id: z.number(), + }), + ) + .optional(), + id: z.number(), + is_active: z.boolean().optional(), + is_favorite: z.boolean().optional(), + level: z.number(), + name: z.string().optional(), + quality: qualitySchema, + species: nameIdKeySchema, + stats: statsSchema, +}); + +export const accountProfileSummaryResponseSchema = z.strictObject({ + _links: linksSchema, + collections: hrefSchema, + id: z.number(), + wow_accounts: z.array(wowAccountSchema).optional(), +}); + +export const accountToysCollectionSummaryResponseSchema = z.strictObject({ + _links: linksSchema, + toys: z.array(toySchema), +}); + +export const accountTransmogsCollectionSummaryResponseSchema = z.strictObject({ + _links: linksSchema, + appearance_sets: z.array(nameIdKeySchema), + slots: z.array(slotSchema), +}); + +export const protectedCharacterProfileSummaryResponseSchema = z.strictObject({ + _links: linksSchema, + bind_position: positionSchema, + character: realmSchema, + id: z.number(), + money: z.number(), + name: z.string(), + position: positionSchema, + protected_stats: protectedStatsSchema, + wow_account: z.number(), +}); + +export const accountPetsCollectionSummaryResponseSchema = z.strictObject({ + _links: linksSchema, + pets: z.array(petSchema), + unlocked_battle_pet_slots: z.number(), +}); diff --git a/generated/schemas/wow/achievements.ts b/generated/schemas/wow/achievements.ts new file mode 100644 index 00000000..2e05a12a --- /dev/null +++ b/generated/schemas/wow/achievements.ts @@ -0,0 +1,117 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { + factionSchema, + keyBaseSchema, + mediaAssetSchema, + nameIdKeySchema, + nameIdSchema, + responseBaseSchema, +} from '../core'; + +export const achievementCategoryIndexResponseSchema = responseBaseSchema.extend({ + categories: z.array(nameIdKeySchema), + guild_categories: z.array(nameIdKeySchema), + root_categories: z.array(nameIdKeySchema), +}); + +export const achievementCategoryResponseSchema = nameIdSchema.extend(responseBaseSchema.shape).extend({ + achievements: z.array(nameIdKeySchema), + aggregates_by_faction: z.strictObject({ + alliance: z.strictObject({ + points: z.number(), + quantity: z.number(), + }), + horde: z.strictObject({ + points: z.number(), + quantity: z.number(), + }), + }), + display_order: z.number(), + is_guild_category: z.boolean(), + parent_category: nameIdKeySchema.optional(), + subcategories: z.array(nameIdKeySchema).optional(), +}); + +export const achievementIndexResponseSchema = responseBaseSchema.extend({ + achievements: z.array(nameIdKeySchema), +}); + +export const achievementMediaResponseSchema = responseBaseSchema.extend({ + assets: z.array(mediaAssetSchema), + id: z.number(), +}); + +const operatorSchema = z.strictObject({ + name: z.string(), + type: z.union([z.literal('AND'), z.literal('COMPLETE_AT_LEAST')]), +}); + +const childCriteria3Schema = z.strictObject({ + achievement: nameIdKeySchema.optional(), + amount: z.number(), + description: z.string().nullable(), + faction: factionSchema.optional(), + id: z.number(), + is_gold: z.boolean().optional(), + operator: operatorSchema.optional(), + show_progress_bar: z.boolean().optional(), +}); + +const childCriteria2Schema = z.strictObject({ + achievement: nameIdKeySchema.optional(), + amount: z.number(), + child_criteria: z.array(childCriteria3Schema).optional(), + description: z.string().nullable(), + faction: factionSchema.optional(), + id: z.number(), + is_gold: z.boolean().optional(), + operator: operatorSchema.optional(), + show_progress_bar: z.boolean().optional(), +}); + +const childCriteriaSchema = z.strictObject({ + achievement: nameIdKeySchema.optional(), + amount: z.number(), + child_criteria: z.array(childCriteria2Schema).optional(), + description: z.string().nullable(), + faction: factionSchema.optional(), + id: z.number(), + is_gold: z.boolean().optional(), + operator: operatorSchema.optional(), + show_progress_bar: z.boolean().optional(), +}); + +const criteriaSchema = z.strictObject({ + amount: z.number(), + child_criteria: z.array(childCriteriaSchema).optional(), + description: z.string().nullable(), + faction: factionSchema.optional(), + id: z.number(), + operator: operatorSchema.optional(), + show_progress_bar: z.boolean().optional(), +}); + +export const achievementResponseSchema = nameIdSchema.extend(responseBaseSchema.shape).extend({ + category: nameIdKeySchema, + criteria: criteriaSchema.optional(), + description: z.string(), + display_order: z.number(), + guild_reward_items: z.array(nameIdKeySchema).optional(), + is_account_wide: z.boolean(), + media: keyBaseSchema.and( + z.strictObject({ + id: z.number(), + }), + ), + next_achievement: nameIdKeySchema.optional(), + points: z.number(), + prerequisite_achievement: nameIdKeySchema.optional(), + requirements: z + .strictObject({ + faction: factionSchema, + }) + .optional(), + reward_description: z.string().optional(), + reward_item: nameIdKeySchema.optional(), +}); diff --git a/generated/schemas/wow/auction-house.ts b/generated/schemas/wow/auction-house.ts new file mode 100644 index 00000000..7ec503f5 --- /dev/null +++ b/generated/schemas/wow/auction-house.ts @@ -0,0 +1,59 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { responseBaseSchema } from '../core'; + +const auctionHouseTimeLeftSchema = z.union([ + z.literal('LONG'), + z.literal('MEDIUM'), + z.literal('SHORT'), + z.literal('VERY_LONG'), +]); + +const auctionHousePostingSchema = z.strictObject({ + bid: z.number().optional(), + buyout: z.number(), + id: z.number(), + item: z.strictObject({ + bonus_lists: z.array(z.number()).optional(), + context: z.number().optional(), + id: z.number(), + modifiers: z + .array( + z.strictObject({ + type: z.number(), + value: z.number(), + }), + ) + .optional(), + pet_breed_id: z.number().optional(), + pet_level: z.number().optional(), + pet_quality_id: z.number().optional(), + pet_species_id: z.number().optional(), + }), + quantity: z.number(), + time_left: auctionHouseTimeLeftSchema, +}); + +const auctionHouseCommoditySchema = z.strictObject({ + id: z.number(), + item: z.strictObject({ + id: z.number(), + }), + quantity: z.number(), + time_left: auctionHouseTimeLeftSchema, + unit_price: z.number(), +}); + +export const auctionHouseResponseSchema = responseBaseSchema.extend({ + auctions: z.array(auctionHousePostingSchema), + commodities: z.strictObject({ + href: z.string(), + }), + connected_realm: z.strictObject({ + href: z.string(), + }), +}); + +export const auctionHouseCommoditiesResponseSchema = responseBaseSchema.extend({ + auctions: z.array(auctionHouseCommoditySchema), +}); diff --git a/generated/schemas/wow/azerite-essence.ts b/generated/schemas/wow/azerite-essence.ts new file mode 100644 index 00000000..ee4afa62 --- /dev/null +++ b/generated/schemas/wow/azerite-essence.ts @@ -0,0 +1,58 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { + baseSearchParametersSchema, + keyBaseSchema, + localesSchema, + mediaAssetSchema, + nameIdKeySchema, + nameIdSchema, + responseBaseSchema, + searchResponseWithoutResultsSchema, +} from '../core'; + +export const azeriteEssenceIndexResponseSchema = responseBaseSchema.extend({ + azerite_essences: z.array(nameIdKeySchema), +}); + +export const azeriteEssenceMediaResponseSchema = responseBaseSchema.extend({ + assets: z.array(mediaAssetSchema), + id: z.number(), +}); + +const mediaSchema = keyBaseSchema.extend({ + id: z.number(), +}); + +const powerSchema = z.strictObject({ + id: z.number(), + main_power_spell: nameIdKeySchema, + passive_power_spell: nameIdKeySchema, + rank: z.number(), +}); + +export const azeriteEssenceSearchParametersSchema = baseSearchParametersSchema.extend({ + 'allowed_specializations.id': z.number().optional(), +}); + +const azeriteEssenceSearchResponseItemSchema = keyBaseSchema.extend({ + data: z.strictObject({ + allowed_specializations: z.array( + z.strictObject({ + id: z.number(), + name: z.record(localesSchema, z.string()), + }), + ), + name: z.record(localesSchema, z.string()), + }), +}); + +export const azeriteEssenceResponseSchema = nameIdSchema.extend(responseBaseSchema.shape).extend({ + allowed_specializations: z.array(nameIdKeySchema), + media: mediaSchema, + powers: z.array(powerSchema), +}); + +export const azeriteEssenceSearchResponseSchema = searchResponseWithoutResultsSchema.extend({ + results: z.array(azeriteEssenceSearchResponseItemSchema), +}); diff --git a/generated/schemas/wow/character-achievements.ts b/generated/schemas/wow/character-achievements.ts new file mode 100644 index 00000000..359acfe2 --- /dev/null +++ b/generated/schemas/wow/character-achievements.ts @@ -0,0 +1,84 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { characterSchema, hrefSchema, nameIdKeySchema, responseBaseSchema } from '../core'; + +const categoryProgressSchema = z.strictObject({ + category: nameIdKeySchema, + points: z.number(), + quantity: z.number(), +}); + +const recentEventSchema = z.strictObject({ + achievement: nameIdKeySchema, + timestamp: z.number(), +}); + +const statisticSchema = z.strictObject({ + description: z.string().optional().nullable(), + id: z.number(), + last_updated_timestamp: z.number(), + name: z.string(), + quantity: z.number(), +}); + +const subCategorySchema = z.strictObject({ + id: z.number(), + name: z.string(), + statistics: z.array(statisticSchema), +}); + +const childCriterum3Schema = z.strictObject({ + amount: z.number().optional(), + id: z.number(), + is_completed: z.boolean(), +}); + +const categorySchema = z.strictObject({ + id: z.number().optional(), + name: z.string(), + statistics: z.array(statisticSchema).optional(), + sub_categories: z.array(subCategorySchema).optional(), +}); + +const childCriterum2Schema = z.strictObject({ + amount: z.number().optional(), + child_criteria: z.array(childCriterum3Schema).optional(), + id: z.number(), + is_completed: z.boolean(), +}); + +const childCriterumSchema = z.strictObject({ + amount: z.number().optional(), + child_criteria: z.array(childCriterum2Schema).optional(), + id: z.number(), + is_completed: z.boolean(), +}); + +export const characterAchievementStatisticsResponseSchema = responseBaseSchema.extend({ + categories: z.array(categorySchema), + character: characterSchema, +}); + +const criteriaSchema = z.strictObject({ + amount: z.number().optional(), + child_criteria: z.array(childCriterumSchema).optional(), + id: z.number(), + is_completed: z.boolean(), +}); + +const achievementSchema = z.strictObject({ + achievement: nameIdKeySchema, + completed_timestamp: z.number().optional(), + criteria: criteriaSchema.optional(), + id: z.number(), +}); + +export const characterAchievementsSummaryResponseSchema = responseBaseSchema.extend({ + achievements: z.array(achievementSchema), + category_progress: z.array(categoryProgressSchema), + character: characterSchema, + recent_events: z.array(recentEventSchema), + statistics: hrefSchema, + total_points: z.number(), + total_quantity: z.number(), +}); diff --git a/generated/schemas/wow/character-appearance.ts b/generated/schemas/wow/character-appearance.ts new file mode 100644 index 00000000..08d20ad3 --- /dev/null +++ b/generated/schemas/wow/character-appearance.ts @@ -0,0 +1,73 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { + characterSchema, + colorSchema, + factionSchema, + genderSchema, + keyBaseSchema, + nameIdKeySchema, + nameIdSchema, + responseBaseSchema, +} from '../core'; + +const itemSchema = z.strictObject({ + enchant: z.number(), + id: z.number(), + internal_slot_id: z.number(), + item_appearance_modifier_id: z.number().optional(), + secondary_id: z.number().optional(), + secondary_item_appearance_modifier_id: z.number().optional(), + secondary_subclass: z.number().optional(), + slot: z.strictObject({ + name: z.string(), + type: z.string(), + }), + subclass: z.number().optional(), +}); + +const rgbWithIdSchema = z.strictObject({ + id: z.number(), + rgba: colorSchema, +}); + +const choiceSchema = z.strictObject({ + display_order: z.number(), + id: z.number(), + name: z.string().optional(), +}); + +const customizationSchema = z.strictObject({ + choice: choiceSchema, + option: nameIdSchema, +}); + +const borderEmblemSchema = z.strictObject({ + color: rgbWithIdSchema, + id: z.number(), + media: keyBaseSchema.and( + z.strictObject({ + id: z.number(), + }), + ), +}); + +const guildCrestSchema = z.strictObject({ + background: z.strictObject({ + color: rgbWithIdSchema, + }), + border: borderEmblemSchema, + emblem: borderEmblemSchema, +}); + +export const characterAppearanceResponseSchema = responseBaseSchema.extend({ + active_spec: nameIdKeySchema, + character: characterSchema, + customizations: z.array(customizationSchema), + faction: factionSchema, + gender: genderSchema, + guild_crest: guildCrestSchema, + items: z.array(itemSchema), + playable_class: nameIdKeySchema, + playable_race: nameIdKeySchema, +}); diff --git a/generated/schemas/wow/character-collections.ts b/generated/schemas/wow/character-collections.ts new file mode 100644 index 00000000..d3769854 --- /dev/null +++ b/generated/schemas/wow/character-collections.ts @@ -0,0 +1,101 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { characterSchema, hrefSchema, keyBaseSchema, nameIdKeySchema, responseBaseSchema } from '../core'; + +export const characterCollectionsIndexResponseSchema = responseBaseSchema.extend({ + character: characterSchema, + decors: hrefSchema, + heirlooms: hrefSchema, + mounts: hrefSchema, + pets: hrefSchema, + toys: hrefSchema, + transmogs: hrefSchema, +}); + +const heirloomSchema = z.strictObject({ + heirloom: nameIdKeySchema, + upgrade: z.strictObject({ + level: z.number(), + }), +}); + +const mountSchema = z.strictObject({ + is_character_specific: z.boolean().optional(), + is_favorite: z.boolean().optional(), + is_useable: z.boolean(), + mount: nameIdKeySchema, +}); + +const toySchema = z.strictObject({ + is_favorite: z.boolean().optional(), + toy: nameIdKeySchema, +}); + +const qualitySchema = z.strictObject({ + name: z.string(), + type: z.union([z.literal('COMMON'), z.literal('POOR'), z.literal('RARE'), z.literal('UNCOMMON')]), +}); + +const statsSchema = z.strictObject({ + breed_id: z.number(), + health: z.number(), + power: z.number(), + speed: z.number(), +}); + +const slotSlotSchema = z.strictObject({ + name: z.string(), + type: z.string(), +}); + +export const characterHeirloomsCollectionSummaryResponseSchema = responseBaseSchema.extend({ + heirlooms: z.array(heirloomSchema), +}); + +export const characterMountsCollectionSummaryResponseSchema = responseBaseSchema.extend({ + mounts: z.array(mountSchema), +}); + +const petSchema = z.strictObject({ + active_slot: z.number().optional(), + creature_display: keyBaseSchema + .and( + z.strictObject({ + id: z.number(), + }), + ) + .optional(), + id: z.number(), + is_active: z.boolean().optional(), + is_favorite: z.boolean().optional(), + level: z.number(), + name: z.string().optional(), + quality: qualitySchema, + species: nameIdKeySchema, + stats: statsSchema, +}); + +export const characterToysCollectionSummaryResponseSchema = responseBaseSchema.extend({ + toys: z.array(toySchema), +}); + +const slotSchema = z.strictObject({ + appearances: z.array( + keyBaseSchema.and( + z.strictObject({ + id: z.number(), + }), + ), + ), + slot: slotSlotSchema, +}); + +export const characterPetsCollectionSummaryResponseSchema = responseBaseSchema.extend({ + pets: z.array(petSchema), + unlocked_battle_pet_slots: z.number(), +}); + +export const characterTransmogCollectionSummaryResponseSchema = responseBaseSchema.extend({ + appearance_sets: z.array(nameIdKeySchema), + slots: z.array(slotSchema), +}); diff --git a/generated/schemas/wow/character-encounters.ts b/generated/schemas/wow/character-encounters.ts new file mode 100644 index 00000000..8599050f --- /dev/null +++ b/generated/schemas/wow/character-encounters.ts @@ -0,0 +1,88 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { characterSchema, hrefSchema, nameIdKeySchema, responseBaseSchema } from '../core'; + +export const characterEncountersSummaryResponseSchema = responseBaseSchema.extend({ + character: characterSchema, + dungeons: hrefSchema, + raids: hrefSchema, +}); + +const dungeonDifficultiesSchema = z.strictObject({ + name: z.string().optional(), + type: z + .union([z.literal('HEROIC'), z.literal('MYTHIC'), z.literal('MYTHIC_KEYSTONE'), z.literal('NORMAL')]) + .optional(), +}); + +const statusSchema = z.strictObject({ + name: z.string(), + type: z.union([z.literal('COMPLETE'), z.literal('IN_PROGRESS')]), +}); + +const encounterSchema = z.strictObject({ + completed_count: z.number(), + encounter: nameIdKeySchema, + last_kill_timestamp: z.number(), +}); + +const progressSchema = z.strictObject({ + completed_count: z.number(), + encounters: z.array(encounterSchema), + total_count: z.number(), +}); + +const raidDifficultiesSchema = z.strictObject({ + name: z.string(), + type: z.union([ + z.literal('HEROIC'), + z.literal('LEGACY_10_MAN'), + z.literal('LEGACY_10_MAN_HEROIC'), + z.literal('LEGACY_25_MAN'), + z.literal('LEGACY_25_MAN_HEROIC'), + z.literal('LFR'), + z.literal('MYTHIC'), + z.literal('NORMAL'), + ]), +}); + +const raidModeSchema = z.strictObject({ + difficulty: raidDifficultiesSchema, + progress: progressSchema, + status: statusSchema, +}); + +const dungeonModeSchema = z.strictObject({ + difficulty: dungeonDifficultiesSchema, + progress: progressSchema, + status: statusSchema, +}); + +const dungeonInstanceSchema = z.strictObject({ + instance: nameIdKeySchema, + modes: z.array(dungeonModeSchema), +}); + +const raidInstanceSchema = z.strictObject({ + instance: nameIdKeySchema, + modes: z.array(raidModeSchema), +}); + +const expansionWithDungeonInstancesSchema = z.strictObject({ + expansion: nameIdKeySchema, + instances: z.array(dungeonInstanceSchema), +}); + +const expansionWithRaidInstancesSchema = z.strictObject({ + expansion: nameIdKeySchema, + instances: z.array(raidInstanceSchema), +}); + +export const characterDungeonsResponseSchema = responseBaseSchema.extend({ + expansions: z.array(expansionWithDungeonInstancesSchema), +}); + +export const characterRaidsResponseSchema = responseBaseSchema.extend({ + character: characterSchema, + expansions: z.array(expansionWithRaidInstancesSchema), +}); diff --git a/generated/schemas/wow/character-equipment.ts b/generated/schemas/wow/character-equipment.ts new file mode 100644 index 00000000..781d4877 --- /dev/null +++ b/generated/schemas/wow/character-equipment.ts @@ -0,0 +1,174 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { characterSchema, colorSchema, keyBaseSchema, nameIdKeySchema, responseBaseSchema } from '../core'; + +const nameDescriptionSchema = z.strictObject({ + color: colorSchema, + display_string: z.string(), +}); + +const nameTypeSchema = z.strictObject({ + name: z.string(), + type: z.string(), +}); + +const displayStringsSchema = z.strictObject({ + copper: z.string(), + gold: z.string(), + header: z.string(), + silver: z.string(), +}); + +const displayStringValueSchema = z.strictObject({ + display_string: z.string(), + value: z.number(), +}); + +const effectSchema = z.strictObject({ + display_string: z.string(), + is_active: z.boolean(), + required_count: z.number(), +}); + +const enchantmentSlotSchema = z.strictObject({ + id: z.number(), + type: z.string(), +}); + +const armorSchema = z.strictObject({ + display: nameDescriptionSchema, + value: z.number(), +}); + +const enchantmentSchema = z.strictObject({ + display_string: z.string(), + enchantment_id: z.number(), + enchantment_slot: enchantmentSlotSchema, + source_item: nameIdKeySchema.optional(), +}); + +const modifiedCraftingStatSchema = z.strictObject({ + id: z.number(), + name: z.string(), + type: z.string(), +}); + +const sellPriceSchema = z.strictObject({ + display_strings: displayStringsSchema, + value: z.number(), +}); + +const socketSchema = z.strictObject({ + context: z.number().optional(), + display_color: colorSchema.optional(), + display_string: z.string(), + item: nameIdKeySchema, + media: keyBaseSchema.and( + z.strictObject({ + id: z.number(), + }), + ), + socket_type: nameTypeSchema, +}); + +const spellSchema = z.strictObject({ + description: z.string(), + spell: nameIdKeySchema, +}); + +const statSchema = z.strictObject({ + display: nameDescriptionSchema, + is_equip_bonus: z.boolean().optional(), + is_negated: z.boolean().optional(), + type: nameTypeSchema, + value: z.number(), +}); + +const transmogSchema = z.strictObject({ + display_string: z.string(), + item: nameIdKeySchema, + item_modified_appearance_id: z.number(), +}); + +const itemElementSchema = z.strictObject({ + is_equipped: z.boolean().optional(), + item: nameIdKeySchema, +}); + +const playableClassesSchema = z.strictObject({ + display_string: z.string(), + links: z.array(nameIdKeySchema), +}); + +const requirementsSchema = z.strictObject({ + level: displayStringValueSchema, + playable_classes: playableClassesSchema.optional(), +}); + +const setSchema = z.strictObject({ + display_string: z.string(), + effects: z.array(effectSchema), + item_set: nameIdKeySchema, + items: z.array(itemElementSchema), +}); + +const damageSchema = z.strictObject({ + damage_class: nameTypeSchema, + display_string: z.string(), + max_value: z.number(), + min_value: z.number(), +}); + +const weaponSchema = z.strictObject({ + attack_speed: displayStringValueSchema, + damage: damageSchema, + dps: displayStringValueSchema, +}); + +const equippedItemSchema = z.strictObject({ + armor: armorSchema.optional(), + binding: nameTypeSchema, + bonus_list: z.array(z.number()).optional(), + context: z.number(), + description: z.string().optional(), + durability: displayStringValueSchema.optional(), + enchantments: z.array(enchantmentSchema).optional(), + inventory_type: nameTypeSchema, + is_subclass_hidden: z.boolean().optional(), + item: keyBaseSchema.and( + z.strictObject({ + id: z.number(), + }), + ), + item_class: nameIdKeySchema, + item_subclass: nameIdKeySchema, + level: displayStringValueSchema, + limit_category: z.string().optional(), + media: keyBaseSchema.and( + z.strictObject({ + id: z.number(), + }), + ), + modified_appearance_id: z.number().optional(), + modified_crafting_stat: z.array(modifiedCraftingStatSchema).optional(), + name: z.string(), + name_description: nameDescriptionSchema.optional(), + quality: nameTypeSchema, + quantity: z.number(), + requirements: requirementsSchema.optional(), + sell_price: sellPriceSchema.optional(), + set: setSchema.optional(), + slot: nameTypeSchema, + sockets: z.array(socketSchema).optional(), + spells: z.array(spellSchema).optional(), + stats: z.array(statSchema).optional(), + transmog: transmogSchema.optional(), + unique_equipped: z.string().optional(), + weapon: weaponSchema.optional(), +}); + +export const characterEquipmentSummaryResponseSchema = responseBaseSchema.extend({ + character: characterSchema, + equipped_item_sets: z.array(setSchema), + equipped_items: z.array(equippedItemSchema), +}); diff --git a/generated/schemas/wow/character-hunter-pets.ts b/generated/schemas/wow/character-hunter-pets.ts new file mode 100644 index 00000000..a26a1288 --- /dev/null +++ b/generated/schemas/wow/character-hunter-pets.ts @@ -0,0 +1,22 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { characterSchema, keyBaseSchema, nameIdKeySchema, responseBaseSchema } from '../core'; + +const hunterPetSchema = z.strictObject({ + creature: nameIdKeySchema, + creature_display: keyBaseSchema.and( + z.strictObject({ + id: z.number(), + }), + ), + is_active: z.boolean().optional(), + is_summoned: z.boolean().optional(), + level: z.number(), + name: z.string(), + slot: z.number(), +}); + +export const characterHunterPetsSummaryResponseSchema = responseBaseSchema.extend({ + character: characterSchema, + hunter_pets: z.array(hunterPetSchema), +}); diff --git a/generated/schemas/wow/character-media.ts b/generated/schemas/wow/character-media.ts new file mode 100644 index 00000000..6c95c98f --- /dev/null +++ b/generated/schemas/wow/character-media.ts @@ -0,0 +1,13 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { characterSchema, responseBaseSchema } from '../core'; + +const assetSchema = z.strictObject({ + key: z.string(), + value: z.string(), +}); + +export const characterMediaSummaryResponseSchema = responseBaseSchema.extend({ + assets: z.array(assetSchema), + character: characterSchema, +}); diff --git a/generated/schemas/wow/character-mythic-keystone-profile.ts b/generated/schemas/wow/character-mythic-keystone-profile.ts new file mode 100644 index 00000000..4270bf91 --- /dev/null +++ b/generated/schemas/wow/character-mythic-keystone-profile.ts @@ -0,0 +1,69 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { + characterSchema, + colorSchema, + keyBaseSchema, + nameIdKeySchema, + nameIdSchema, + realmSchema, + responseBaseSchema, +} from '../core'; + +const currentPeriodSchema = z.strictObject({ + period: keyBaseSchema.and( + z.strictObject({ + id: z.number(), + }), + ), +}); + +const mythicRatingSchema = z.strictObject({ + color: colorSchema, + rating: z.number(), +}); + +const memberSchema = z.strictObject({ + character: nameIdSchema.and( + z.strictObject({ + realm: realmSchema, + }), + ), + equipped_item_level: z.number(), + race: nameIdKeySchema, + specialization: nameIdKeySchema, +}); + +export const characterMythicKeystoneProfileIndexResponseSchema = responseBaseSchema.extend({ + character: characterSchema, + current_period: currentPeriodSchema, + seasons: z.array( + keyBaseSchema.and( + z.strictObject({ + id: z.number(), + }), + ), + ), +}); + +const bestRunSchema = z.strictObject({ + completed_timestamp: z.number(), + dungeon: nameIdKeySchema, + duration: z.number(), + is_completed_within_time: z.boolean(), + keystone_affixes: z.array(nameIdKeySchema), + keystone_level: z.number(), + members: z.array(memberSchema), + mythic_rating: mythicRatingSchema, +}); + +export const characterMythicKeystoneSeasonDetailsResponseSchema = responseBaseSchema.extend({ + best_runs: z.array(bestRunSchema), + character: characterSchema, + mythic_rating: mythicRatingSchema, + season: keyBaseSchema.and( + z.strictObject({ + id: z.number(), + }), + ), +}); diff --git a/generated/schemas/wow/character-professions.ts b/generated/schemas/wow/character-professions.ts new file mode 100644 index 00000000..6fb24be5 --- /dev/null +++ b/generated/schemas/wow/character-professions.ts @@ -0,0 +1,28 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { characterSchema, nameIdKeySchema, nameIdSchema, responseBaseSchema } from '../core'; + +const tierSchema = z.strictObject({ + known_recipes: z.array(nameIdKeySchema).optional(), + max_skill_points: z.number(), + skill_points: z.number(), + tier: nameIdSchema, +}); + +const secondarySchema = z.strictObject({ + max_skill_points: z.number().optional(), + profession: nameIdKeySchema, + skill_points: z.number().optional(), + tiers: z.array(tierSchema).optional(), +}); + +const primarySchema = z.strictObject({ + profession: nameIdKeySchema, + tiers: z.array(tierSchema), +}); + +export const characterProfessionsSummaryResponseSchema = responseBaseSchema.extend({ + character: characterSchema, + primaries: z.array(primarySchema), + secondaries: z.array(secondarySchema), +}); diff --git a/generated/schemas/wow/character-profile.ts b/generated/schemas/wow/character-profile.ts new file mode 100644 index 00000000..8532b12e --- /dev/null +++ b/generated/schemas/wow/character-profile.ts @@ -0,0 +1,63 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { factionSchema, genderSchema, hrefSchema, nameIdKeySchema, realmSchema, responseBaseSchema } from '../core'; + +export const characterProfileStatusResponseSchema = responseBaseSchema.extend({ + id: z.number(), + is_valid: z.boolean(), +}); + +const covenantProgressSchema = z.strictObject({ + chosen_covenant: nameIdKeySchema, + renown_level: z.number(), + soulbinds: hrefSchema, +}); + +const guildSchema = nameIdKeySchema.extend({ + faction: factionSchema, + realm: realmSchema, +}); + +export const characterProfileSummaryResponseSchema = responseBaseSchema.extend({ + achievement_points: z.number(), + achievements: hrefSchema, + achievements_statistics: hrefSchema, + active_spec: nameIdKeySchema, + active_title: nameIdKeySchema + .and( + z.strictObject({ + display_string: z.string(), + }), + ) + .optional(), + appearance: hrefSchema, + average_item_level: z.number(), + character_class: nameIdKeySchema, + collections: hrefSchema, + covenant_progress: covenantProgressSchema, + encounters: hrefSchema, + equipment: hrefSchema, + equipped_item_level: z.number(), + experience: z.number(), + faction: factionSchema, + gender: genderSchema, + guild: guildSchema, + hunter_pets: hrefSchema, + id: z.number(), + is_remix: z.boolean(), + last_login_timestamp: z.number(), + level: z.number(), + media: hrefSchema, + mythic_keystone_profile: hrefSchema, + name: z.string(), + name_search: z.string(), + professions: hrefSchema, + pvp_summary: hrefSchema, + quests: hrefSchema, + race: nameIdKeySchema, + realm: realmSchema, + reputations: hrefSchema, + specializations: hrefSchema, + statistics: hrefSchema, + titles: hrefSchema, +}); diff --git a/generated/schemas/wow/character-pvp.ts b/generated/schemas/wow/character-pvp.ts new file mode 100644 index 00000000..48485d29 --- /dev/null +++ b/generated/schemas/wow/character-pvp.ts @@ -0,0 +1,45 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { characterSchema, factionSchema, keyBaseSchema, nameIdSchema, responseBaseSchema } from '../core'; + +const bracketSchema = z.strictObject({ + id: z.number(), + type: z.string(), +}); + +const matchStatisticsSchema = z.strictObject({ + lost: z.number(), + played: z.number(), + won: z.number(), +}); + +const pvpMapStatisticSchema = z.strictObject({ + match_statistics: matchStatisticsSchema, + world_map: nameIdSchema, +}); + +export const characterPvpBracketStatisticsResponseSchema = responseBaseSchema.extend({ + bracket: bracketSchema, + character: characterSchema, + faction: factionSchema, + rating: z.number(), + season: keyBaseSchema.and( + z.strictObject({ + id: z.number(), + }), + ), + season_match_statistics: matchStatisticsSchema, + tier: keyBaseSchema.and( + z.strictObject({ + id: z.number(), + }), + ), + weekly_match_statistics: matchStatisticsSchema, +}); + +export const characterPvpSummaryResponseSchema = responseBaseSchema.extend({ + character: characterSchema, + honor_level: z.number(), + honorable_kills: z.number(), + pvp_map_statistics: z.array(pvpMapStatisticSchema), +}); diff --git a/generated/schemas/wow/character-quests.ts b/generated/schemas/wow/character-quests.ts new file mode 100644 index 00000000..7881ddce --- /dev/null +++ b/generated/schemas/wow/character-quests.ts @@ -0,0 +1,14 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { characterSchema, hrefSchema, nameIdKeySchema, responseBaseSchema } from '../core'; + +export const characterCompletedQuestsResponseSchema = responseBaseSchema.extend({ + character: characterSchema, + quests: z.array(nameIdKeySchema), +}); + +export const characterQuestsResponseSchema = responseBaseSchema.extend({ + character: characterSchema, + completed: hrefSchema, + in_progress: z.array(nameIdKeySchema), +}); diff --git a/generated/schemas/wow/character-reputations.ts b/generated/schemas/wow/character-reputations.ts new file mode 100644 index 00000000..61feb122 --- /dev/null +++ b/generated/schemas/wow/character-reputations.ts @@ -0,0 +1,29 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { characterSchema, nameIdKeySchema, responseBaseSchema } from '../core'; + +const paragonSchema = z.strictObject({ + max: z.number(), + raw: z.number(), + value: z.number(), +}); + +const standingSchema = z.strictObject({ + max: z.number(), + name: z.string(), + raw: z.number(), + renown_level: z.number().optional(), + tier: z.number().optional(), + value: z.number(), +}); + +const reputationSchema = z.strictObject({ + faction: nameIdKeySchema, + paragon: paragonSchema.optional(), + standing: standingSchema, +}); + +export const characterReputationsSummaryResponseSchema = responseBaseSchema.extend({ + character: characterSchema, + reputations: z.array(reputationSchema), +}); diff --git a/generated/schemas/wow/character-soulbinds.ts b/generated/schemas/wow/character-soulbinds.ts new file mode 100644 index 00000000..2f57d7ec --- /dev/null +++ b/generated/schemas/wow/character-soulbinds.ts @@ -0,0 +1,42 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { characterSchema, nameIdKeySchema, responseBaseSchema } from '../core'; + +const socketSchema = z.strictObject({ + conduit: nameIdKeySchema, + rank: z.number(), +}); + +const typeClassSchema = z.strictObject({ + name: z.union([ + z.literal('Endurance Conduit Slot'), + z.literal('Finesse Conduit Slot'), + z.literal('Potency Conduit Slot'), + ]), + type: z.union([z.literal('ENDURANCE'), z.literal('FINESSE'), z.literal('POTENCY')]), +}); + +const conduitSocketSchema = z.strictObject({ + socket: socketSchema, + type: typeClassSchema, +}); + +const traitSchema = z.strictObject({ + conduit_socket: conduitSocketSchema.optional(), + display_order: z.number(), + tier: z.number(), + trait: nameIdKeySchema.optional(), +}); + +const soulbindSchema = z.strictObject({ + is_active: z.boolean().optional(), + soulbind: nameIdKeySchema, + traits: z.array(traitSchema), +}); + +export const characterSoulbindsResponseSchema = responseBaseSchema.extend({ + character: characterSchema, + chosen_covenant: nameIdKeySchema, + renown_level: z.number(), + soulbinds: z.array(soulbindSchema), +}); diff --git a/generated/schemas/wow/character-specializations.ts b/generated/schemas/wow/character-specializations.ts new file mode 100644 index 00000000..3b3c0f48 --- /dev/null +++ b/generated/schemas/wow/character-specializations.ts @@ -0,0 +1,92 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { characterSchema, keyBaseSchema, nameIdKeySchema, responseBaseSchema } from '../core'; + +const spellTooltipSchema = z.strictObject({ + cast_time: z + .union([ + z.literal('1.5 sec cast'), + z.literal('2.5 sec cast'), + z.literal('3 sec cast'), + z.literal('Channeled'), + z.literal('Instant'), + z.literal('Passive'), + ]) + .optional(), + cooldown: z.string().optional(), + description: z.string().optional(), + power_cost: z.string().optional(), + range: z + .union([ + z.literal('8-30 yd range'), + z.literal('15 yd range'), + z.literal('30 yd range'), + z.literal('40 yd range'), + z.literal('50 yd range'), + z.literal('55 yd range'), + z.literal('100 yd range'), + z.literal('Melee Range'), + ]) + .optional(), + spell: keyBaseSchema.and( + z.strictObject({ + id: z.number(), + name: z.string().optional(), + }), + ), +}); + +const selectedSchema = z.strictObject({ + spell_tooltip: spellTooltipSchema, + talent: keyBaseSchema.and( + z.strictObject({ + id: z.number(), + name: z.string().optional(), + }), + ), +}); + +const pvpTalentSlotSchema = z.strictObject({ + selected: selectedSchema, + slot_number: z.number(), +}); + +const selectedTalentSchema = z.strictObject({ + default_points: z.number().optional(), + id: z.number(), + rank: z.number(), + tooltip: selectedSchema.optional(), +}); + +const loadoutSchema = z.strictObject({ + is_active: z.boolean(), + selected_class_talent_tree: keyBaseSchema.and( + z.strictObject({ + name: z.string(), + }), + ), + selected_class_talents: z.array(selectedTalentSchema), + selected_hero_talent_tree: nameIdKeySchema, + selected_hero_talents: z.array(selectedTalentSchema), + selected_spec_talent_tree: keyBaseSchema.and( + z.strictObject({ + name: z.string(), + }), + ), + selected_spec_talents: z.array(selectedTalentSchema).optional(), + talent_loadout_code: z.string(), +}); + +const specializationSchema = z.strictObject({ + glyphs: z.array(nameIdKeySchema).optional(), + loadouts: z.array(loadoutSchema), + pvp_talent_slots: z.array(pvpTalentSlotSchema).optional(), + specialization: nameIdKeySchema, +}); + +export const characterSpecializationsSummaryResponseSchema = responseBaseSchema.extend({ + active_hero_talent_tree: nameIdKeySchema, + active_specialization: nameIdKeySchema, + character: characterSchema, + specializations: z.array(specializationSchema), +}); diff --git a/generated/schemas/wow/character-statistics.ts b/generated/schemas/wow/character-statistics.ts new file mode 100644 index 00000000..ec20e6d8 --- /dev/null +++ b/generated/schemas/wow/character-statistics.ts @@ -0,0 +1,62 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { characterSchema, nameIdKeySchema, responseBaseSchema } from '../core'; + +const baseEffectiveStatSchema = z.strictObject({ + base: z.number(), + effective: z.number(), +}); + +const ratingSchema = z.strictObject({ + rating_bonus: z.number(), + rating_normalized: z.number(), +}); + +const ratingWithValueSchema = z.strictObject({ + rating_bonus: z.number(), + rating_normalized: z.number(), + value: z.number(), +}); + +export const characterStatisticsSummaryResponseSchema = responseBaseSchema.extend({ + agility: baseEffectiveStatSchema, + armor: baseEffectiveStatSchema, + attack_power: z.number(), + avoidance: ratingSchema, + block: ratingWithValueSchema, + bonus_armor: z.number(), + character: characterSchema, + dodge: ratingWithValueSchema, + health: z.number(), + intellect: baseEffectiveStatSchema, + lifesteal: ratingWithValueSchema, + main_hand_damage_max: z.number(), + main_hand_damage_min: z.number(), + main_hand_dps: z.number(), + main_hand_speed: z.number(), + mana_regen: z.number(), + mana_regen_combat: z.number(), + mastery: ratingWithValueSchema, + melee_crit: ratingWithValueSchema, + melee_haste: ratingWithValueSchema, + off_hand_damage_max: z.number(), + off_hand_damage_min: z.number(), + off_hand_dps: z.number(), + off_hand_speed: z.number(), + parry: ratingWithValueSchema, + power: z.number(), + power_type: nameIdKeySchema, + ranged_crit: ratingWithValueSchema, + ranged_haste: ratingWithValueSchema, + speed: ratingSchema, + spell_crit: ratingWithValueSchema, + spell_haste: ratingWithValueSchema, + spell_penetration: z.number(), + spell_power: z.number(), + stamina: baseEffectiveStatSchema, + strength: baseEffectiveStatSchema, + versatility: z.number(), + versatility_damage_done_bonus: z.number(), + versatility_damage_taken_bonus: z.number(), + versatility_healing_done_bonus: z.number(), +}); diff --git a/generated/schemas/wow/character-titles.ts b/generated/schemas/wow/character-titles.ts new file mode 100644 index 00000000..37b3daa0 --- /dev/null +++ b/generated/schemas/wow/character-titles.ts @@ -0,0 +1,15 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { characterSchema, nameIdKeySchema, responseBaseSchema } from '../core'; + +export const characterTitlesSummaryResponseSchema = responseBaseSchema.extend({ + active_title: nameIdKeySchema + .and( + z.strictObject({ + display_string: z.string(), + }), + ) + .optional(), + character: characterSchema, + titles: z.array(nameIdKeySchema), +}); diff --git a/generated/schemas/wow/connected-realm.ts b/generated/schemas/wow/connected-realm.ts new file mode 100644 index 00000000..e183ec96 --- /dev/null +++ b/generated/schemas/wow/connected-realm.ts @@ -0,0 +1,120 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { + baseSearchParametersSchema, + hrefSchema, + keyBaseSchema, + localesSchema, + nameIdKeySchema, + responseBaseSchema, + searchResponseWithoutResultsSchema, +} from '../core'; + +export const connectedRealmIndexResponseSchema = responseBaseSchema.extend({ + connected_realms: z.array(hrefSchema), +}); + +const realmPopulationCapitalizedSchema = z.union([ + z.literal('FULL'), + z.literal('HIGH'), + z.literal('LOW'), + z.literal('MEDIUM'), + z.literal('RECOMMENDED'), +]); + +const realmLockedStatusSchema = z.strictObject({ + is_locked_for_new_characters: z.boolean(), + is_locked_for_pct: z.boolean(), +}); + +const realmStatusSchema = z.union([z.literal('Down'), z.literal('Up')]); + +const realmStatusCapitalizedSchema = z.union([z.literal('DOWN'), z.literal('UP')]); + +const searchRealmPopulationSchema = z.strictObject({ + name: z.record(localesSchema, z.string()), + type: realmPopulationCapitalizedSchema, +}); + +const searchRealmStatusSchema = z.strictObject({ + name: z.record(localesSchema, z.string()), + type: realmStatusCapitalizedSchema, +}); + +const realmTimezoneSchema = z.any(); + +const realmCategorySchema = z.any(); + +const realmLocalesSchema = z.any(); + +const realmTypeCapitalizedSchema = z.any(); + +const realmSchema = z.strictObject({ + category: realmCategorySchema, + connected_realm: hrefSchema, + id: z.number(), + is_tournament: z.boolean(), + locale: realmLocalesSchema, + name: z.string(), + region: nameIdKeySchema, + slug: z.string(), + timezone: realmTimezoneSchema, + type: z.strictObject({ + name: z.string(), + type: realmTypeCapitalizedSchema, + }), +}); + +export const connectedRealmSearchParametersSchema = baseSearchParametersSchema.extend({ + 'realms.timezone': realmTimezoneSchema.optional(), + 'status.type': realmStatusCapitalizedSchema.optional(), +}); + +const searchRealmSchema = z.strictObject({ + category: z.record(localesSchema, z.string()), + id: z.number(), + is_tournament: z.boolean(), + locale: realmLocalesSchema, + name: z.record(localesSchema, z.string()), + region: z.strictObject({ + id: z.number(), + name: z.record(localesSchema, z.string()), + }), + slug: z.string(), + timezone: realmTimezoneSchema, + type: z.strictObject({ + name: z.record(localesSchema, z.string()), + type: realmTypeCapitalizedSchema, + }), +}); + +export const connectedRealmResponseSchema = responseBaseSchema.extend({ + auctions: hrefSchema, + has_queue: z.boolean(), + id: z.number(), + mythic_leaderboards: hrefSchema, + population: z.strictObject({ + name: z.string(), + type: realmPopulationCapitalizedSchema, + }), + realm_locked_status: realmLockedStatusSchema.optional(), + realms: z.array(realmSchema), + status: z.strictObject({ + name: realmStatusSchema, + type: realmStatusCapitalizedSchema, + }), +}); + +const connectedRealmSearchResponseItemSchema = keyBaseSchema.extend({ + data: z.strictObject({ + has_queue: z.boolean(), + id: z.number(), + population: searchRealmPopulationSchema, + realms: z.array(searchRealmSchema), + status: searchRealmStatusSchema, + }), +}); + +export const connectedRealmSearchResponseSchema = searchResponseWithoutResultsSchema.extend({ + results: z.array(connectedRealmSearchResponseItemSchema), +}); diff --git a/generated/schemas/wow/covenant.ts b/generated/schemas/wow/covenant.ts new file mode 100644 index 00000000..f807ada8 --- /dev/null +++ b/generated/schemas/wow/covenant.ts @@ -0,0 +1,101 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { keyBaseSchema, mediaAssetSchema, nameIdKeySchema, nameIdSchema, responseBaseSchema } from '../core'; + +export const conduitIndexResponseSchema = responseBaseSchema.extend({ + conduits: z.array(nameIdKeySchema), +}); + +const socketTypeSchema = z.strictObject({ + name: z.string(), + type: z.string(), +}); + +export const covenantIndexResponseSchema = responseBaseSchema.extend({ + covenants: z.array(nameIdKeySchema), +}); + +export const covenantMediaResponseSchema = responseBaseSchema.extend({ + assets: z.array(mediaAssetSchema).optional(), +}); + +const mediaSchema = keyBaseSchema.extend({ + id: z.number(), +}); + +const renownRewardSchema = z.strictObject({ + level: z.number(), + reward: nameIdKeySchema, +}); + +export const soulbindIndexResponseSchema = responseBaseSchema.extend({ + soulbinds: z.array(nameIdKeySchema), +}); + +export const soulbindResponseSchema = responseBaseSchema.extend({ + covenant: nameIdKeySchema, + creature: nameIdKeySchema, + follower: nameIdSchema, + id: z.number(), + name: z.string(), + talent_tree: nameIdKeySchema, +}); + +const classAbilitySpellTooltipSchema = z.strictObject({ + cast_time: z.string(), + cooldown: z.string().optional(), + description: z.string(), + power_cost: z.string().optional().nullable(), + range: z.string().optional(), + spell: nameIdKeySchema, +}); + +const spellTooltipSchema = z.strictObject({ + cast_time: z.string(), + description: z.string(), + spell: nameIdKeySchema, +}); + +const signatureAbilitySpellTooltipSchema = z.strictObject({ + cast_time: z.string(), + cooldown: z.string().optional(), + description: z.string(), + range: z.string().optional(), + spell: nameIdKeySchema, +}); + +const rankSchema = z.strictObject({ + id: z.number(), + spell_tooltip: spellTooltipSchema, + tier: z.number(), +}); + +const classAbilitySchema = z.strictObject({ + id: z.number(), + playable_class: nameIdKeySchema, + spell_tooltip: classAbilitySpellTooltipSchema, +}); + +const signatureAbilitySchema = z.strictObject({ + id: z.number(), + spell_tooltip: signatureAbilitySpellTooltipSchema, +}); + +export const conduitResponseSchema = responseBaseSchema.extend({ + id: z.number(), + item: nameIdKeySchema, + name: z.string(), + ranks: z.array(rankSchema), + socket_type: socketTypeSchema, +}); + +export const covenantResponseSchema = responseBaseSchema.extend({ + class_abilities: z.array(classAbilitySchema).optional(), + description: z.string(), + id: z.number(), + media: mediaSchema.optional(), + name: z.string(), + renown_rewards: z.array(renownRewardSchema), + signature_ability: signatureAbilitySchema.optional(), + soulbinds: z.array(nameIdKeySchema).optional(), +}); diff --git a/generated/schemas/wow/creature.ts b/generated/schemas/wow/creature.ts new file mode 100644 index 00000000..9dcd136e --- /dev/null +++ b/generated/schemas/wow/creature.ts @@ -0,0 +1,95 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { + baseSearchParametersSchema, + keyBaseSchema, + localesSchema, + mediaAssetSchema, + nameIdKeySchema, + responseBaseSchema, + searchResponseWithoutResultsSchema, +} from '../core'; + +const displayMediaAssetSchema = z.strictObject({ + key: z.string(), + value: z.string(), +}); + +export const creatureFamilyIndexResponseSchema = responseBaseSchema.extend({ + creature_families: z.array(nameIdKeySchema), +}); + +export const creatureFamilyMediaResponseSchema = responseBaseSchema.extend({ + assets: z.array(mediaAssetSchema), + id: z.number(), +}); + +const mediaSchema = keyBaseSchema.extend({ + id: z.number(), +}); + +const creatureDisplaySchema = keyBaseSchema.extend({ + id: z.number(), +}); + +export const creatureSearchParametersSchema = baseSearchParametersSchema.extend({ + locale: localesSchema, + name: z.string(), +}); + +const creatureSearchResponseItemSchema = keyBaseSchema.extend({ + data: z.strictObject({ + creature_displays: z.array( + z.strictObject({ + id: z.number(), + }), + ), + family: z + .strictObject({ + id: z.number(), + name: z.record(localesSchema, z.string()), + }) + .optional(), + id: z.number(), + is_tameable: z.boolean(), + name: z.record(localesSchema, z.union([z.string(), z.undefined()])), + type: z.strictObject({ + id: z.number(), + name: z.record(localesSchema, z.string()), + }), + }), +}); + +export const creatureTypeIndexResponseSchema = responseBaseSchema.extend({ + creature_types: z.array(nameIdKeySchema), +}); + +export const creatureTypeResponseSchema = responseBaseSchema.extend({ + id: z.number(), + name: z.string(), +}); + +export const creatureDisplayMediaResponseSchema = responseBaseSchema.extend({ + assets: z.array(displayMediaAssetSchema), + id: z.number(), +}); + +export const creatureFamilyResponseSchema = responseBaseSchema.extend({ + id: z.number(), + media: mediaSchema, + name: z.string(), + specialization: nameIdKeySchema, +}); + +export const creatureResponseSchema = responseBaseSchema.extend({ + creature_displays: z.array(creatureDisplaySchema), + family: nameIdKeySchema, + id: z.number(), + is_tameable: z.boolean(), + name: z.string(), + type: nameIdKeySchema, +}); + +export const creatureSearchResponseSchema = searchResponseWithoutResultsSchema.extend({ + results: z.array(creatureSearchResponseItemSchema), +}); diff --git a/generated/schemas/wow/guild-crest.ts b/generated/schemas/wow/guild-crest.ts new file mode 100644 index 00000000..c8d44227 --- /dev/null +++ b/generated/schemas/wow/guild-crest.ts @@ -0,0 +1,39 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { colorSchema, keyBaseSchema, responseBaseSchema } from '../core'; + +const guildCrestAssetSchema = z.strictObject({ + key: z.string(), + value: z.string(), +}); + +const backgroundSchema = z.strictObject({ + id: z.number(), + rgba: colorSchema, +}); + +const mediaSchema = keyBaseSchema.extend({ + id: z.number(), +}); + +const colorsSchema = z.strictObject({ + backgrounds: z.array(backgroundSchema), + borders: z.array(backgroundSchema), + emblems: z.array(backgroundSchema), +}); + +export const guildCrestBorderEmblemResponseSchema = responseBaseSchema.extend({ + assets: z.array(guildCrestAssetSchema), + id: z.number(), +}); + +const borderSchema = z.strictObject({ + id: z.number(), + media: mediaSchema, +}); + +export const guildCrestComponentsIndexResponseSchema = responseBaseSchema.extend({ + borders: z.array(borderSchema), + colors: colorsSchema, + emblems: z.array(borderSchema), +}); diff --git a/generated/schemas/wow/guild.ts b/generated/schemas/wow/guild.ts new file mode 100644 index 00000000..63d6fd43 --- /dev/null +++ b/generated/schemas/wow/guild.ts @@ -0,0 +1,146 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { + characterSchema, + colorSchema, + factionSchema, + factionsSchema, + hrefSchema, + keyBaseSchema, + nameIdKeySchema, + realmSchema, + responseBaseSchema, +} from '../core'; + +const categoryProgressSchema = z.strictObject({ + category: nameIdKeySchema, + points: z.number(), + quantity: z.number(), +}); + +const guildSchema = nameIdKeySchema.extend({ + faction: factionSchema, + realm: realmSchema, +}); + +const recentEventSchema = z.strictObject({ + achievement: nameIdKeySchema, + timestamp: z.number(), +}); + +const characterAchievementSchema = z.strictObject({ + achievement: nameIdKeySchema, + character: characterSchema, +}); + +const encounterActivitySchema = z.strictObject({ + encounter: nameIdKeySchema, + mode: z.strictObject({ + name: z.string(), + type: z.literal('MYTHIC'), + }), +}); + +const rgbWithIdSchema = z.strictObject({ + id: z.number(), + rgba: colorSchema, +}); + +const childCriterumSchema = z.strictObject({ + amount: z.number(), + id: z.number(), + is_completed: z.boolean(), +}); + +const borderSchema = z.strictObject({ + color: rgbWithIdSchema, + id: z.number(), + media: keyBaseSchema.and( + z.strictObject({ + id: z.number(), + }), + ), +}); + +const criteriaSchema = z.strictObject({ + amount: z.number().optional(), + child_criteria: z.array(childCriterumSchema).optional(), + id: z.number(), + is_completed: z.boolean(), +}); + +const playableSchema = keyBaseSchema.extend({ + id: z.number(), +}); + +const rosterMemberCharacterSchema = characterSchema.extend({ + faction: z.strictObject({ + type: factionsSchema, + }), + level: z.number(), + playable_class: playableSchema, + playable_race: playableSchema, +}); + +const achievementSchema = z.strictObject({ + achievement: nameIdKeySchema, + completed_timestamp: z.number().optional(), + criteria: criteriaSchema.optional(), + id: z.number(), +}); + +const activityElementSchema = z.strictObject({ + activity: z.strictObject({ + type: z.string(), + }), + character_achievement: characterAchievementSchema.optional(), + encounter_completed: encounterActivitySchema.optional(), + timestamp: z.number(), +}); + +const crestSchema = z.strictObject({ + background: z.strictObject({ + color: rgbWithIdSchema, + }), + border: borderSchema, + emblem: borderSchema, +}); + +const memberSchema = z.strictObject({ + character: rosterMemberCharacterSchema, + rank: z.number(), +}); + +export const guildAchievementsResponseSchema = responseBaseSchema.extend({ + achievements: z.array(achievementSchema), + category_progress: z.array(categoryProgressSchema), + guild: guildSchema, + recent_events: z.array(recentEventSchema), + total_points: z.number(), + total_quantity: z.number(), +}); + +export const guildActivityResponseSchema = responseBaseSchema.extend({ + activities: z.array(activityElementSchema), + guild: guildSchema, +}); + +export const guildResponseSchema = responseBaseSchema.extend({ + achievement_points: z.number(), + achievements: hrefSchema, + activity: hrefSchema, + created_timestamp: z.number(), + crest: crestSchema, + faction: factionSchema, + id: z.number(), + member_count: z.number(), + name: z.string(), + name_search: z.string(), + realm: realmSchema, + roster: hrefSchema, +}); + +export const guildRosterResponseSchema = responseBaseSchema.extend({ + guild: guildSchema, + members: z.array(memberSchema), +}); diff --git a/generated/schemas/wow/heirloom.ts b/generated/schemas/wow/heirloom.ts new file mode 100644 index 00000000..3a31974c --- /dev/null +++ b/generated/schemas/wow/heirloom.ts @@ -0,0 +1,92 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { colorSchema, keyBaseSchema, nameIdKeySchema, responseBaseSchema } from '../core'; + +export const heirloomIndexResponseSchema = responseBaseSchema.extend({ + heirlooms: z.array(nameIdKeySchema), +}); + +const mediaSchema = keyBaseSchema.extend({ + id: z.number(), +}); + +const sourceSchema = z.strictObject({ + name: z.string(), + type: z.string(), +}); + +const attackSpeedClassSchema = z.strictObject({ + display_string: z.string(), + value: z.number(), +}); + +const damageSchema = z.strictObject({ + damage_class: sourceSchema, + display_string: z.string(), + max_value: z.number(), + min_value: z.number(), +}); + +const displaySchema = z.strictObject({ + color: colorSchema, + display_string: z.string(), +}); + +const requirementsLevelSchema = z.strictObject({ + display_string: z.string(), +}); + +const statSchema = z.strictObject({ + display: displaySchema, + is_equip_bonus: z.boolean().optional(), + type: sourceSchema, + value: z.number(), +}); + +const requirementsSchema = z.strictObject({ + level: requirementsLevelSchema, +}); + +const upgradesSchema = z.strictObject({ + display_string: z.string(), + max_value: z.number(), + value: z.number(), +}); + +const weaponSchema = z.strictObject({ + attack_speed: attackSpeedClassSchema, + damage: damageSchema, + dps: attackSpeedClassSchema, +}); + +const upgradeItemSchema = z.strictObject({ + binding: sourceSchema, + bonus_list: z.array(z.number()), + context: z.number(), + inventory_type: sourceSchema, + item: mediaSchema, + item_class: nameIdKeySchema, + item_subclass: nameIdKeySchema, + level: attackSpeedClassSchema, + media: mediaSchema, + name: z.string(), + quality: sourceSchema, + requirements: requirementsSchema, + stats: z.array(statSchema), + upgrades: upgradesSchema, + weapon: weaponSchema, +}); + +const upgradeSchema = z.strictObject({ + item: upgradeItemSchema, + level: z.number(), +}); + +export const heirloomResponseSchema = responseBaseSchema.extend({ + id: z.number(), + item: nameIdKeySchema, + media: mediaSchema, + source: sourceSchema, + source_description: z.string(), + upgrades: z.array(upgradeSchema), +}); diff --git a/generated/schemas/wow/index.ts b/generated/schemas/wow/index.ts new file mode 100644 index 00000000..4b5f923b --- /dev/null +++ b/generated/schemas/wow/index.ts @@ -0,0 +1,54 @@ +export * from './account-profile'; +export * from './achievements'; +export * from './auction-house'; +export * from './azerite-essence'; +export * from './character-achievements'; +export * from './character-appearance'; +export * from './character-collections'; +export * from './character-encounters'; +export * from './character-equipment'; +export * from './character-hunter-pets'; +export * from './character-media'; +export * from './character-mythic-keystone-profile'; +export * from './character-professions'; +export * from './character-profile'; +export * from './character-pvp'; +export * from './character-quests'; +export * from './character-reputations'; +export * from './character-soulbinds'; +export * from './character-specializations'; +export * from './character-statistics'; +export * from './character-titles'; +export * from './connected-realm'; +export * from './covenant'; +export * from './creature'; +export * from './guild'; +export * from './guild-crest'; +export * from './heirloom'; +export * from './item'; +export * from './journal'; +export * from './media-search'; +export * from './modified-crafting'; +export * from './mount'; +export * from './mythic-keystone-affix'; +export * from './mythic-keystone-dungeon'; +export * from './mythic-keystone-leaderboard'; +export * from './mythic-raid-leaderboard'; +export * from './pet'; +export * from './playable-class'; +export * from './playable-race'; +export * from './playable-specialization'; +export * from './power-type'; +export * from './profession'; +export * from './pvp-season'; +export * from './pvp-tier'; +export * from './quest'; +export * from './realm'; +export * from './region'; +export * from './reputations'; +export * from './spell'; +export * from './talent'; +export * from './tech-talent'; +export * from './title'; +export * from './toy'; +export * from './wow-token'; diff --git a/generated/schemas/wow/item.ts b/generated/schemas/wow/item.ts new file mode 100644 index 00000000..320bfbf2 --- /dev/null +++ b/generated/schemas/wow/item.ts @@ -0,0 +1,326 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { + baseSearchParametersSchema, + colorSchema, + keyBaseSchema, + localesSchema, + mediaAssetSchema, + nameIdKeySchema, + nameIdSchema, + responseBaseSchema, + searchResponseWithoutResultsSchema, +} from '../core'; + +export const itemClassIndexResponseSchema = responseBaseSchema.extend({ + item_classes: z.array(nameIdKeySchema), +}); + +export const itemClassResponseSchema = responseBaseSchema.extend({ + class_id: z.number(), + item_subclasses: z.array(nameIdKeySchema), + name: z.string(), +}); + +export const itemMediaResponseSchema = responseBaseSchema.extend({ + assets: z.array(mediaAssetSchema), + id: z.number(), +}); + +const mediaSchema = keyBaseSchema.extend({ + id: z.number(), +}); + +export const itemSearchParametersSchema = baseSearchParametersSchema.extend({ + locale: localesSchema, + name: z.string(), +}); + +export const itemSetIndexResponseSchema = responseBaseSchema.extend({ + item_sets: z.array(nameIdKeySchema), +}); + +const effectSchema = z.strictObject({ + display_string: z.string(), + required_count: z.number(), +}); + +export const itemSubClassResponseSchema = responseBaseSchema.extend({ + class_id: z.number(), + display_name: z.string(), + hide_subclass_in_tooltips: z.boolean().optional(), + subclass_id: z.number(), + verbose_name: z.string().optional(), +}); + +const displaySchema = z.strictObject({ + color: colorSchema, + display_string: z.string(), +}); + +const damageSchema = z.strictObject({ + damage_class: z.strictObject({ + name: z.string(), + type: z.string(), + }), + display_string: z.string(), + max_value: z.number(), + min_value: z.number(), +}); + +const durabilitySchema = z.strictObject({ + display_string: z.string(), + value: z.number(), +}); + +const inventoryTypeSchema = z.union([ + z.literal('BACK'), + z.literal('CHEST'), + z.literal('FEET'), + z.literal('FINGER'), + z.literal('HAND'), + z.literal('HANDS'), + z.literal('HEAD'), + z.literal('LEGS'), + z.literal('NECK'), + z.literal('SHOULDER'), + z.literal('THROWN'), + z.literal('TRINKET'), + z.literal('WAIST'), + z.literal('WRIST'), + z.literal('RANGED'), + z.literal('TWOHWEAPON'), + z.literal('WEAPON'), + z.literal('WEAPONMAINHAND'), + z.literal('WEAPONOFFHAND'), + z.literal('BAG'), + z.literal('NON_EQUIP'), + z.literal('SHIRT'), + z.literal('TABARD'), +]); + +const inventoryTypeNameSchema = z.strictObject({ + name: z.string(), + type: inventoryTypeSchema, +}); + +const inventoryTypeNameFromSearchSchema = z.strictObject({ + name: z.record(localesSchema, z.string()), + type: inventoryTypeSchema, +}); + +const itemQualityTypeSchema = z.union([ + z.literal('ARTIFACT'), + z.literal('COMMON'), + z.literal('EPIC'), + z.literal('HEIRLOOM'), + z.literal('LEGENDARY'), + z.literal('POOR'), + z.literal('RARE'), + z.literal('UNCOMMON'), +]); + +const itemQualityFromSearchSchema = z.strictObject({ + name: z.record(localesSchema, z.string()), + type: itemQualityTypeSchema, +}); + +const itemSearchResponseItemSchema = keyBaseSchema.extend({ + data: z.strictObject({ + appearances: z + .array( + z.strictObject({ + id: z.number(), + }), + ) + .optional(), + id: z.number(), + inventory_type: inventoryTypeNameFromSearchSchema, + is_equippable: z.boolean(), + is_stackable: z.boolean(), + item_class: z.strictObject({ + id: z.number(), + name: z.record(localesSchema, z.string()), + }), + item_subclass: z.strictObject({ + id: z.number(), + name: z.record(localesSchema, z.string()), + }), + level: z.number(), + max_count: z.number(), + media: z.strictObject({ + id: z.number(), + }), + name: z.record(localesSchema, z.union([z.string(), z.undefined()])), + purchase_price: z.number(), + purchase_quantity: z.number(), + quality: itemQualityFromSearchSchema, + required_level: z.number(), + sell_price: z.number(), + }), +}); + +const armorSchema = z.strictObject({ + display: displaySchema, + value: z.number(), +}); + +const itemQualitySchema = z.strictObject({ + name: z.string(), + type: itemQualityTypeSchema, +}); + +const requirementsSchema = z.strictObject({ + level: durabilitySchema, +}); + +const spellSchema = z.strictObject({ + description: z.string(), + spell: nameIdKeySchema, +}); + +const weaponSchema = z.strictObject({ + attack_speed: durabilitySchema, + damage: damageSchema, + dps: durabilitySchema, +}); + +const recipeItemDisplayStringsSchema = z.strictObject({ + copper: z.string(), + gold: z.string(), + header: z.string(), + silver: z.string(), +}); + +const statTypeCapitalizedSchema = z.union([ + z.literal('AGILITY'), + z.literal('ARCANE_RESISTANCE'), + z.literal('CRIT_RATING'), + z.literal('FIRE_RESISTANCE'), + z.literal('FROST_RESISTANCE'), + z.literal('HASTE_RATING'), + z.literal('INTELLECT'), + z.literal('MASTERY'), + z.literal('NATURE_RESISTANCE'), + z.literal('SHADOW_RESISTANCE'), + z.literal('STAMINA'), + z.literal('STRENGTH'), + z.literal('VERSATILITY'), +]); + +export const itemSearchResponseSchema = searchResponseWithoutResultsSchema.extend({ + results: z.array(itemSearchResponseItemSchema), +}); + +export const itemSetResponseSchema = responseBaseSchema.extend({ + effects: z.array(effectSchema), + id: z.number(), + items: z.array(nameIdKeySchema), + name: z.string(), +}); + +const statSchema = z.strictObject({ + display: displaySchema, + is_negated: z.boolean().optional(), + type: z.strictObject({ + name: z.string(), + type: statTypeCapitalizedSchema, + }), + value: z.number(), +}); + +const recipeItemSchema = z.strictObject({ + armor: armorSchema.optional(), + binding: z.strictObject({ + name: z.string(), + type: z.string(), + }), + durability: durabilitySchema, + inventory_type: inventoryTypeNameSchema, + item: mediaSchema, + item_class: nameIdKeySchema, + item_subclass: nameIdKeySchema, + level: durabilitySchema, + media: mediaSchema, + name: z.string(), + quality: itemQualitySchema, + requirements: requirementsSchema, + sell_price: z.strictObject({ + display_strings: recipeItemDisplayStringsSchema, + value: z.number(), + }), + stats: z.array(statSchema), + weapon: weaponSchema.optional(), +}); + +const recipeSchema = z.strictObject({ + item: recipeItemSchema, + reagents: z.array( + nameIdKeySchema.and( + z.strictObject({ + quantity: z.number(), + }), + ), + ), + reagents_display_string: z.string(), +}); + +const previewItemSchema = z.strictObject({ + armor: armorSchema.optional(), + binding: z + .strictObject({ + name: z.string(), + type: z.string(), + }) + .optional(), + bonus_list: z.array(z.number()).optional(), + container_slots: durabilitySchema.optional(), + context: z.number().optional(), + crafting_reagent: z.string().optional(), + description: z.string().optional(), + durability: durabilitySchema.optional(), + inventory_type: inventoryTypeNameSchema, + is_subclass_hidden: z.boolean().optional(), + item: mediaSchema, + item_class: nameIdKeySchema, + item_subclass: nameIdKeySchema, + level: durabilitySchema.optional(), + media: mediaSchema, + name: z.string(), + quality: itemQualitySchema, + recipe: recipeSchema.optional(), + requirements: requirementsSchema.optional(), + sell_price: z.number().optional(), + shield_block: armorSchema.optional(), + spells: z.array(spellSchema).optional(), + stats: z.array(statSchema).optional(), + unique_equipped: z.literal('Unique').optional(), + weapon: weaponSchema.optional(), +}); + +export const itemResponseSchema = nameIdSchema.extend(responseBaseSchema.shape).extend({ + appearances: z + .array( + keyBaseSchema.and( + z.strictObject({ + id: z.number(), + }), + ), + ) + .optional(), + description: z.string().optional(), + inventory_type: inventoryTypeNameSchema, + is_equippable: z.boolean(), + is_stackable: z.boolean(), + item_class: nameIdKeySchema, + item_subclass: nameIdKeySchema, + level: z.number(), + max_count: z.number(), + media: mediaSchema, + preview_item: previewItemSchema, + purchase_price: z.number(), + purchase_quantity: z.number(), + quality: itemQualitySchema, + required_level: z.number(), + sell_price: z.number(), +}); diff --git a/generated/schemas/wow/journal.ts b/generated/schemas/wow/journal.ts new file mode 100644 index 00000000..542478f1 --- /dev/null +++ b/generated/schemas/wow/journal.ts @@ -0,0 +1,295 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { + baseSearchParametersSchema, + factionSchema, + keyBaseSchema, + localesSchema, + nameIdKeySchema, + nameIdSchema, + responseBaseSchema, + searchResponseWithoutResultsSchema, +} from '../core'; + +export const journalEncounterIndexResponseSchema = responseBaseSchema.extend({ + encounters: z.array(nameIdKeySchema), +}); + +const itemSchema = z.strictObject({ + id: z.number(), + item: nameIdKeySchema, +}); + +export const journalEncounterSearchParametersSchema = baseSearchParametersSchema.extend({ + instanceName: z.string(), + locale: localesSchema, +}); + +export const journalExpansionIndexResponseSchema = responseBaseSchema.extend({ + tiers: z.array(nameIdKeySchema), +}); + +export const journalExpansionResponseSchema = nameIdSchema.extend(responseBaseSchema.shape).extend({ + dungeons: z.array(nameIdKeySchema), + raids: z.array(nameIdKeySchema), + world_bosses: z.array(nameIdKeySchema).optional(), +}); + +export const journalInstanceIndexResponseSchema = responseBaseSchema.extend({ + instances: z.array(nameIdKeySchema), +}); + +const assetSchema = z.strictObject({ + key: z.string(), + value: z.string(), +}); + +const mediaSchema = keyBaseSchema.extend({ + id: z.number(), +}); + +const encounterCategorySchema = z.union([ + z.literal('DUNGEON'), + z.literal('EVENT'), + z.literal('RAID'), + z.literal('WORLD_BOSS'), +]); + +const creatureDisplaySchema = keyBaseSchema.extend({ + id: z.number(), +}); + +const encounterModeSchema = z.union([z.literal('HEROIC'), z.literal('LFR'), z.literal('MYTHIC'), z.literal('NORMAL')]); + +const journalEncounterSearchCreatureSchema = z.strictObject({ + creature_display: z.strictObject({ + id: z.number(), + }), + id: z.number(), + name: z.record(localesSchema, z.string()), +}); + +const journalEncounterSearchItemSchema = z.strictObject({ + id: z.number(), + item: z.strictObject({ + id: z.number(), + name: z.record(localesSchema, z.string()), + }), +}); + +const categorySchema = z.strictObject({ + type: encounterCategorySchema.optional(), +}); + +const journalSubSection6Schema = z.strictObject({ + body_text: z.string().optional().nullable(), + creature_display: creatureDisplaySchema.optional(), + id: z.number(), + spell: keyBaseSchema + .and( + z.strictObject({ + id: z.number(), + name: z.string().optional(), + }), + ) + .optional(), + title: z.string().optional(), +}); + +const modeNameSchema = z.union([ + z.literal('10 Player'), + z.literal('10 Player (Heroic)'), + z.literal('25 Player'), + z.literal('25 Player (Heroic)'), + z.literal('Heroic'), + z.literal('Mythic'), + z.literal('Mythic+ Dungeons'), + z.literal('Normal'), + z.literal('Raid Finder'), +]); + +const modeTypeSchema = z.union([ + z.literal('HEROIC'), + z.literal('LEGACY_10_MAN'), + z.literal('LEGACY_10_MAN_HEROIC'), + z.literal('LEGACY_25_MAN'), + z.literal('LEGACY_25_MAN_HEROIC'), + z.literal('LFR'), + z.literal('MYTHIC'), + z.literal('MYTHIC_KEYSTONE'), + z.literal('NORMAL'), +]); + +const modeSchema = z.strictObject({ + name: modeNameSchema, + type: modeTypeSchema, +}); + +const creatureSchema = nameIdSchema.extend({ + creature_display: creatureDisplaySchema, + description: z.string().optional(), +}); + +export const journalInstanceMediaResponseSchema = responseBaseSchema.extend({ + assets: z.array(assetSchema), +}); + +const modeElementSchema = z.strictObject({ + is_timewalking: z.boolean().optional(), + is_tracked: z.boolean(), + mode: modeSchema, + players: z.number(), +}); + +const journalSubSection5Schema = z.strictObject({ + body_text: z.string().optional().nullable(), + creature_display: creatureDisplaySchema.optional(), + id: z.number(), + sections: z.array(journalSubSection6Schema).optional(), + spell: keyBaseSchema + .and( + z.strictObject({ + id: z.number(), + name: z.string().optional(), + }), + ) + .optional(), + title: z.string().optional(), +}); + +export const journalInstanceResponseSchema = nameIdSchema.extend(responseBaseSchema.shape).extend({ + area: nameIdSchema.optional(), + category: categorySchema, + description: z.string().optional(), + encounters: z.array(nameIdKeySchema), + expansion: nameIdKeySchema.optional(), + location: nameIdSchema.optional(), + map: nameIdSchema.optional(), + media: mediaSchema, + minimum_level: z.number().optional(), + modes: z.array(modeElementSchema).optional(), + order_index: z.number().optional(), +}); + +const journalSubSection4Schema = z.strictObject({ + body_text: z.string().optional().nullable(), + creature_display: creatureDisplaySchema.optional(), + id: z.number(), + sections: z.array(journalSubSection5Schema).optional(), + spell: keyBaseSchema + .and( + z.strictObject({ + id: z.number(), + name: z.string().optional(), + }), + ) + .optional(), + title: z.string().optional(), +}); + +const journalSubSection3Schema = z.strictObject({ + body_text: z.string().optional().nullable(), + creature_display: creatureDisplaySchema.optional(), + id: z.number(), + sections: z.array(journalSubSection4Schema).optional(), + spell: keyBaseSchema + .and( + z.strictObject({ + id: z.number(), + name: z.string().optional(), + }), + ) + .optional(), + title: z.string().optional(), +}); + +const journalSubSection2Schema = z.strictObject({ + body_text: z.string().optional().nullable(), + creature_display: creatureDisplaySchema.optional(), + id: z.number(), + sections: z.array(journalSubSection3Schema).optional(), + spell: keyBaseSchema + .and( + z.strictObject({ + id: z.number(), + name: z.string().optional(), + }), + ) + .optional(), + title: z.string().optional(), +}); + +const journalSubSectionSchema = z.strictObject({ + body_text: z.string().optional().nullable(), + creature_display: creatureDisplaySchema.optional(), + id: z.number(), + sections: z.array(journalSubSection2Schema).optional(), + spell: keyBaseSchema + .and( + z.strictObject({ + id: z.number(), + name: z.string().optional(), + }), + ) + .optional(), + title: z.string().optional(), +}); + +const journalSectionSchema = z.strictObject({ + body_text: z.string().optional().nullable(), + creature_display: creatureDisplaySchema.optional(), + id: z.number(), + sections: z.array(journalSubSectionSchema).optional(), + spell: keyBaseSchema + .and( + z.strictObject({ + id: z.number(), + name: z.string().optional(), + }), + ) + .optional(), + title: z.string().optional(), +}); + +const journalEncounterSearchResponseItemSchema = keyBaseSchema.extend({ + data: z.strictObject({ + category: categorySchema, + creatures: z.array(journalEncounterSearchCreatureSchema), + id: z.number(), + instance: z.strictObject({ + id: z.number(), + name: z.record(localesSchema, z.string()).optional(), + }), + items: z.array(journalEncounterSearchItemSchema).optional(), + modes: z + .array( + z.strictObject({ + name: z.record(localesSchema, z.string()), + type: encounterModeSchema, + }), + ) + .optional(), + name: z.record(localesSchema, z.string()), + sections: z.array(journalSectionSchema).optional(), + }), +}); + +export const journalEncounterResponseSchema = nameIdSchema.extend(responseBaseSchema.shape).extend({ + category: categorySchema, + creatures: z.array(creatureSchema).optional(), + description: z.string().optional(), + faction: factionSchema.optional(), + instance: keyBaseSchema.and( + z.strictObject({ + id: z.number(), + name: z.string().optional(), + }), + ), + items: z.array(itemSchema).optional(), + modes: z.array(modeSchema).optional(), + sections: z.array(journalSectionSchema).optional(), +}); + +export const journalEncounterSearchResponseSchema = searchResponseWithoutResultsSchema.extend({ + results: z.array(journalEncounterSearchResponseItemSchema), +}); diff --git a/generated/schemas/wow/media-search.ts b/generated/schemas/wow/media-search.ts new file mode 100644 index 00000000..2a0c88de --- /dev/null +++ b/generated/schemas/wow/media-search.ts @@ -0,0 +1,23 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { + baseSearchParametersSchema, + keyBaseSchema, + mediaAssetSchema, + searchResponseWithoutResultsSchema, +} from '../core'; + +export const mediaSearchParametersSchema = baseSearchParametersSchema.extend({ + tags: z.string().optional(), +}); + +const mediaSearchResponseItemSchema = keyBaseSchema.extend({ + data: z.strictObject({ + assets: z.array(mediaAssetSchema), + id: z.number().optional(), + }), +}); + +export const mediaSearchResponseSchema = searchResponseWithoutResultsSchema.extend({ + results: z.array(mediaSearchResponseItemSchema), +}); diff --git a/generated/schemas/wow/modified-crafting.ts b/generated/schemas/wow/modified-crafting.ts new file mode 100644 index 00000000..609b7421 --- /dev/null +++ b/generated/schemas/wow/modified-crafting.ts @@ -0,0 +1,39 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { hrefSchema, keyBaseSchema, nameIdKeySchema, responseBaseSchema } from '../core'; + +export const modifiedCraftingCategoryIndexResponseSchema = responseBaseSchema.extend({ + categories: z.array( + keyBaseSchema.and( + z.strictObject({ + id: z.number(), + name: z.string().optional(), + }), + ), + ), +}); + +export const modifiedCraftingCategoryResponseSchema = responseBaseSchema.extend({ + id: z.number(), + name: z.string().optional(), +}); + +export const modifiedCraftingIndexResponseSchema = responseBaseSchema.extend({ + categories: hrefSchema, + slot_types: hrefSchema, +}); + +const slotTypeSchema = keyBaseSchema.extend({ + id: z.number(), + name: z.string().optional(), +}); + +export const modifiedCraftingReagentSlotTypeResponseSchema = responseBaseSchema.extend({ + compatible_categories: z.array(nameIdKeySchema), + description: z.string(), + id: z.number(), +}); + +export const modifiedCraftingReagentSlotTypeIndexResponseSchema = responseBaseSchema.extend({ + slot_types: z.array(slotTypeSchema), +}); diff --git a/generated/schemas/wow/mount.ts b/generated/schemas/wow/mount.ts new file mode 100644 index 00000000..cd51d39d --- /dev/null +++ b/generated/schemas/wow/mount.ts @@ -0,0 +1,73 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { + baseSearchParametersSchema, + factionSchema, + factionsSchema, + keyBaseSchema, + localesSchema, + nameIdKeySchema, + responseBaseSchema, + searchResponseWithoutResultsSchema, +} from '../core'; + +export const mountIndexResponseSchema = responseBaseSchema.extend({ + mounts: z.array(nameIdKeySchema), +}); + +const creatureDisplaySchema = keyBaseSchema.extend({ + id: z.number(), +}); + +const sourceSchema = z.strictObject({ + name: z.string(), + type: z.string(), +}); + +export const mountSearchParametersSchema = baseSearchParametersSchema.extend({ + locale: localesSchema, + name: z.string(), +}); + +const mountSearchResponseItemSchema = keyBaseSchema.extend({ + data: z.strictObject({ + creature_displays: z.array( + z.strictObject({ + id: z.number(), + }), + ), + faction: z + .strictObject({ + name: z.record(localesSchema, z.string()), + type: factionsSchema, + }) + .optional(), + id: z.number(), + name: z.record(localesSchema, z.string()), + source: z.strictObject({ + name: z.record(localesSchema, z.string()), + type: z.string(), + }), + }), +}); + +export const mountResponseSchema = responseBaseSchema.extend({ + creature_displays: z.array(creatureDisplaySchema), + description: z.string().nullable(), + faction: factionSchema.optional(), + id: z.number(), + name: z.string(), + requirements: z + .strictObject({ + classes: z.array(nameIdKeySchema).optional(), + faction: factionSchema.optional(), + races: z.array(nameIdKeySchema).optional(), + }) + .optional(), + should_exclude_if_uncollected: z.boolean().optional(), + source: sourceSchema.optional(), +}); + +export const mountSearchResponseSchema = searchResponseWithoutResultsSchema.extend({ + results: z.array(mountSearchResponseItemSchema), +}); diff --git a/generated/schemas/wow/mythic-keystone-affix.ts b/generated/schemas/wow/mythic-keystone-affix.ts new file mode 100644 index 00000000..b54c0e64 --- /dev/null +++ b/generated/schemas/wow/mythic-keystone-affix.ts @@ -0,0 +1,30 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { keyBaseSchema, mediaAssetSchema, responseBaseSchema } from '../core'; + +export const mythicKeystoneAffixIndexResponseSchema = responseBaseSchema.extend({ + affixes: z.array( + keyBaseSchema.and( + z.strictObject({ + id: z.number(), + name: z.string().nullable(), + }), + ), + ), +}); + +export const mythicKeystoneAffixMediaResponseSchema = responseBaseSchema.extend({ + assets: z.array(mediaAssetSchema).optional(), + id: z.number(), +}); + +const mediaSchema = keyBaseSchema.extend({ + id: z.number(), +}); + +export const mythicKeystoneAffixResponseSchema = responseBaseSchema.extend({ + description: z.string().nullable(), + id: z.number(), + media: mediaSchema, + name: z.string().nullable(), +}); diff --git a/generated/schemas/wow/mythic-keystone-dungeon.ts b/generated/schemas/wow/mythic-keystone-dungeon.ts new file mode 100644 index 00000000..ba9e0937 --- /dev/null +++ b/generated/schemas/wow/mythic-keystone-dungeon.ts @@ -0,0 +1,57 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { hrefSchema, keyBaseSchema, nameIdKeySchema, nameIdSchema, responseBaseSchema } from '../core'; + +export const mythicKeystoneDungeonIndexResponseSchema = responseBaseSchema.extend({ + dungeons: z.array(nameIdKeySchema), +}); + +const keystoneUpgradeSchema = z.strictObject({ + qualifying_duration: z.number(), + upgrade_level: z.number(), +}); + +const zoneSchema = z.strictObject({ + slug: z.string(), +}); + +export const mythicKeystoneIndexResponseSchema = responseBaseSchema.extend({ + dungeons: hrefSchema, + seasons: hrefSchema, +}); + +const periodSchema = keyBaseSchema.extend({ + id: z.number(), +}); + +export const mythicKeystonePeriodResponseSchema = responseBaseSchema.extend({ + end_timestamp: z.number(), + id: z.number(), + start_timestamp: z.number(), +}); + +export const mythicKeystoneSeasonIndexResponseSchema = responseBaseSchema.extend({ + current_season: periodSchema, + seasons: z.array(periodSchema), +}); + +export const mythicKeystoneSeasonResponseSchema = responseBaseSchema.extend({ + end_timestamp: z.number(), + id: z.number(), + periods: z.array(periodSchema), + season_name: z.string().nullable(), + start_timestamp: z.number(), +}); + +export const mythicKeystoneDungeonResponseSchema = nameIdSchema.extend(responseBaseSchema.shape).extend({ + dungeon: nameIdKeySchema, + is_tracked: z.boolean(), + keystone_upgrades: z.array(keystoneUpgradeSchema), + map: nameIdSchema, + zone: zoneSchema, +}); + +export const mythicKeystonePeriodIndexResponseSchema = responseBaseSchema.extend({ + current_period: periodSchema, + periods: z.array(periodSchema), +}); diff --git a/generated/schemas/wow/mythic-keystone-leaderboard.ts b/generated/schemas/wow/mythic-keystone-leaderboard.ts new file mode 100644 index 00000000..995aeb58 --- /dev/null +++ b/generated/schemas/wow/mythic-keystone-leaderboard.ts @@ -0,0 +1,53 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { factionsSchema, hrefSchema, keyBaseSchema, nameIdKeySchema, nameIdSchema, responseBaseSchema } from '../core'; + +export const mythicKeystoneLeaderboardIndexResponseSchema = responseBaseSchema.extend({ + current_leaderboards: z.array(nameIdKeySchema), +}); + +const keystoneAffixElementSchema = z.strictObject({ + keystone_affix: nameIdKeySchema, + starting_level: z.number(), +}); + +const specializationSchema = keyBaseSchema.extend({ + id: z.number(), +}); + +const realmSchema = keyBaseSchema.extend({ + id: z.number(), + slug: z.string(), +}); + +const profileSchema = nameIdSchema.extend({ + realm: realmSchema, +}); + +const memberSchema = z.strictObject({ + faction: z.strictObject({ + type: factionsSchema, + }), + profile: profileSchema, + specialization: specializationSchema, +}); + +const leadingGroupSchema = z.strictObject({ + completed_timestamp: z.number(), + duration: z.number(), + keystone_level: z.number(), + members: z.array(memberSchema), + ranking: z.number(), +}); + +export const mythicKeystoneLeaderboardResponseSchema = responseBaseSchema.extend({ + connected_realm: hrefSchema, + keystone_affixes: z.array(keystoneAffixElementSchema), + leading_groups: z.array(leadingGroupSchema), + map: nameIdSchema, + map_challenge_mode_id: z.number(), + name: z.string(), + period: z.number(), + period_end_timestamp: z.number(), + period_start_timestamp: z.number(), +}); diff --git a/generated/schemas/wow/mythic-raid-leaderboard.ts b/generated/schemas/wow/mythic-raid-leaderboard.ts new file mode 100644 index 00000000..c12a9b15 --- /dev/null +++ b/generated/schemas/wow/mythic-raid-leaderboard.ts @@ -0,0 +1,35 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { factionsSchema, keyBaseSchema, nameIdSchema, originsSchema, responseBaseSchema } from '../core'; + +const journalInstanceSchema = keyBaseSchema.extend({ + id: z.number(), + name: z.null(), +}); + +const realmSchema = z.strictObject({ + id: z.number(), + name: z.null(), + slug: z.string(), +}); + +const guildSchema = nameIdSchema.extend({ + realm: realmSchema, +}); + +const entrySchema = z.strictObject({ + faction: z.strictObject({ + type: factionsSchema, + }), + guild: guildSchema, + rank: z.number(), + region: originsSchema, + timestamp: z.number(), +}); + +export const mythicRaidLeaderboardResponseSchema = responseBaseSchema.extend({ + criteria_type: z.string(), + entries: z.array(entrySchema), + journal_instance: journalInstanceSchema, + slug: z.string(), +}); diff --git a/generated/schemas/wow/pet.ts b/generated/schemas/wow/pet.ts new file mode 100644 index 00000000..b43f3f19 --- /dev/null +++ b/generated/schemas/wow/pet.ts @@ -0,0 +1,64 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { keyBaseSchema, mediaAssetSchema, nameIdKeySchema, nameIdSchema, responseBaseSchema } from '../core'; + +export const petAbilityIndexResponseSchema = responseBaseSchema.extend({ + abilities: z.array(nameIdKeySchema), +}); + +export const petAbilityMediaResponseSchema = responseBaseSchema.extend({ + assets: z.array(mediaAssetSchema), + id: z.number(), +}); + +const battlePetTypeSchema = nameIdSchema.extend({ + type: z.string(), +}); + +const mediaSchema = keyBaseSchema.extend({ + id: z.number(), +}); + +export const petIndexResponseSchema = responseBaseSchema.extend({ + pets: z.array(nameIdKeySchema), +}); + +export const petMediaResponseSchema = responseBaseSchema.extend({ + assets: z.array(mediaAssetSchema), + id: z.number(), +}); + +const abilitySchema = z.strictObject({ + ability: nameIdKeySchema, + required_level: z.number(), + slot: z.number(), +}); + +const sourceSchema = z.strictObject({ + name: z.string(), + type: z.string(), +}); + +export const petAbilityResponseSchema = nameIdSchema.extend(responseBaseSchema.shape).extend({ + battle_pet_type: battlePetTypeSchema, + cooldown: z.number().optional(), + media: mediaSchema, + rounds: z.number(), +}); + +export const petResponseSchema = nameIdSchema.extend(responseBaseSchema.shape).extend({ + abilities: z.array(abilitySchema).optional(), + battle_pet_type: battlePetTypeSchema, + creature: nameIdKeySchema, + description: z.string().nullable(), + icon: z.string(), + is_alliance_only: z.boolean(), + is_battlepet: z.boolean(), + is_capturable: z.boolean(), + is_horde_only: z.boolean(), + is_random_creature_display: z.boolean(), + is_tradable: z.boolean(), + media: mediaSchema, + should_exclude_if_uncollected: z.boolean().optional(), + source: sourceSchema.optional(), +}); diff --git a/generated/schemas/wow/playable-class.ts b/generated/schemas/wow/playable-class.ts new file mode 100644 index 00000000..59df8bad --- /dev/null +++ b/generated/schemas/wow/playable-class.ts @@ -0,0 +1,42 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { + genderNameSchema, + hrefSchema, + keyBaseSchema, + mediaAssetSchema, + nameIdKeySchema, + nameIdSchema, + responseBaseSchema, +} from '../core'; + +export const playableClassIndexResponseSchema = responseBaseSchema.extend({ + classes: z.array(nameIdKeySchema), +}); + +export const playableClassMediaResponseSchema = responseBaseSchema.extend({ + assets: z.array(mediaAssetSchema), + id: z.number(), +}); + +const mediaSchema = keyBaseSchema.extend({ + id: z.number(), +}); + +const talentSlotSchema = z.strictObject({ + slot_number: z.number(), + unlock_player_level: z.number(), +}); + +export const playableClassResponseSchema = nameIdSchema.extend(responseBaseSchema.shape).extend({ + gender_name: genderNameSchema, + media: mediaSchema, + playable_races: z.array(nameIdKeySchema), + power_type: nameIdKeySchema, + pvp_talent_slots: hrefSchema, + specializations: z.array(nameIdKeySchema), +}); + +export const pvpTalentSlotsResponseSchema = responseBaseSchema.extend({ + talent_slots: z.array(talentSlotSchema), +}); diff --git a/generated/schemas/wow/playable-race.ts b/generated/schemas/wow/playable-race.ts new file mode 100644 index 00000000..f356444e --- /dev/null +++ b/generated/schemas/wow/playable-race.ts @@ -0,0 +1,16 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { factionSchema, genderNameSchema, nameIdKeySchema, nameIdSchema, responseBaseSchema } from '../core'; + +export const playableRaceIndexResponseSchema = responseBaseSchema.extend({ + races: z.array(nameIdKeySchema), +}); + +export const playableRaceResponseSchema = nameIdSchema.extend(responseBaseSchema.shape).extend({ + faction: factionSchema, + gender_name: genderNameSchema, + is_allied_race: z.boolean(), + is_selectable: z.boolean(), + playable_classes: z.array(nameIdKeySchema), + racial_spells: z.array(nameIdKeySchema), +}); diff --git a/generated/schemas/wow/playable-specialization.ts b/generated/schemas/wow/playable-specialization.ts new file mode 100644 index 00000000..5b75d1a3 --- /dev/null +++ b/generated/schemas/wow/playable-specialization.ts @@ -0,0 +1,58 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { + genderNameSchema, + keyBaseSchema, + mediaAssetSchema, + nameIdKeySchema, + nameIdSchema, + responseBaseSchema, +} from '../core'; + +export const playableSpecializationIndexResponseSchema = responseBaseSchema.extend({ + character_specializations: z.array(nameIdKeySchema), + pet_specializations: z.array(nameIdKeySchema), +}); + +export const playableSpecializationMediaResponseSchema = responseBaseSchema.extend({ + assets: z.array(mediaAssetSchema), + id: z.number(), +}); + +const mediaSchema = keyBaseSchema.extend({ + id: z.number(), +}); + +const primaryStatTypeSchema = z.strictObject({ + name: z.string(), + type: z.string(), +}); + +const specTalentTreeSchema = keyBaseSchema.extend({ + name: z.string(), +}); + +const spellTooltipSchema = z.strictObject({ + cast_time: z.string(), + cooldown: z.string().optional(), + description: z.string(), + power_cost: z.string().optional().nullable(), + range: z.string().optional(), +}); + +const pvpTalentSchema = z.strictObject({ + spell_tooltip: spellTooltipSchema, + talent: nameIdKeySchema, +}); + +export const playableSpecializationResponseSchema = nameIdSchema.extend(responseBaseSchema.shape).extend({ + gender_description: genderNameSchema, + hero_talent_trees: z.array(nameIdKeySchema), + media: mediaSchema, + playable_class: nameIdKeySchema, + power_type: nameIdKeySchema, + primary_stat_type: primaryStatTypeSchema, + pvp_talents: z.array(pvpTalentSchema), + role: primaryStatTypeSchema, + spec_talent_tree: specTalentTreeSchema, +}); diff --git a/generated/schemas/wow/power-type.ts b/generated/schemas/wow/power-type.ts new file mode 100644 index 00000000..4278ddab --- /dev/null +++ b/generated/schemas/wow/power-type.ts @@ -0,0 +1,9 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { nameIdKeySchema, nameIdSchema, responseBaseSchema } from '../core'; + +export const powerTypeIndexResponseSchema = responseBaseSchema.extend({ + power_types: z.array(nameIdKeySchema), +}); + +export const powerTypeResponseSchema = nameIdSchema.extend(responseBaseSchema.shape); diff --git a/generated/schemas/wow/profession.ts b/generated/schemas/wow/profession.ts new file mode 100644 index 00000000..3f084bd0 --- /dev/null +++ b/generated/schemas/wow/profession.ts @@ -0,0 +1,72 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { keyBaseSchema, mediaAssetSchema, nameIdKeySchema, nameIdSchema, responseBaseSchema } from '../core'; + +export const professionIndexResponseSchema = responseBaseSchema.extend({ + professions: z.array(nameIdKeySchema), +}); + +export const professionMediaResponseSchema = responseBaseSchema.extend({ + assets: z.array(mediaAssetSchema), + id: z.number(), +}); + +const mediaSchema = keyBaseSchema.extend({ + id: z.number(), +}); + +const typeSchema = z.strictObject({ + name: z.string(), + type: z.string(), +}); + +const categorySchema = z.strictObject({ + name: z.string(), + recipes: z.array(nameIdKeySchema), +}); + +export const recipeMediaResponseSchema = responseBaseSchema.extend({ + assets: z.array(mediaAssetSchema), + id: z.number(), +}); + +const craftedQuantitySchema = z.strictObject({ + maximum: z.number().optional(), + minimum: z.number().optional(), + value: z.number().optional(), +}); + +const reagentSchema = z.strictObject({ + quantity: z.number(), + reagent: nameIdKeySchema, +}); + +export const professionResponseSchema = nameIdSchema.extend(responseBaseSchema.shape).extend({ + description: z.string(), + media: mediaSchema, + skill_tiers: z.array(nameIdKeySchema), + type: typeSchema, +}); + +export const professionSkillTierResponseSchema = nameIdSchema.extend(responseBaseSchema.shape).extend({ + categories: z.array(categorySchema), + maximum_skill_level: z.number(), + minimum_skill_level: z.number(), +}); + +export const recipeResponseSchema = nameIdSchema.extend(responseBaseSchema.shape).extend({ + crafted_item: nameIdKeySchema.optional(), + crafted_quantity: craftedQuantitySchema.optional(), + description: z.string().optional(), + media: mediaSchema, + modified_crafting_slots: z + .array( + z.strictObject({ + display_order: z.number(), + slot_type: nameIdKeySchema, + }), + ) + .optional(), + rank: z.number().optional(), + reagents: z.array(reagentSchema).optional(), +}); diff --git a/generated/schemas/wow/pvp-season.ts b/generated/schemas/wow/pvp-season.ts new file mode 100644 index 00000000..709a7bd3 --- /dev/null +++ b/generated/schemas/wow/pvp-season.ts @@ -0,0 +1,92 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { + factionSchema, + factionsSchema, + hrefSchema, + keyBaseSchema, + nameIdKeySchema, + nameIdSchema, + responseBaseSchema, +} from '../core'; + +const seasonSchema = keyBaseSchema.extend({ + id: z.number(), +}); + +const bracketSchema = z.strictObject({ + id: z.number(), + type: z.union([z.literal('ARENA_3v3'), z.literal('BATTLEGROUNDS'), z.literal('BLITZ'), z.literal('SHUFFLE')]), +}); + +const rewardSchema = z.strictObject({ + achievement: nameIdKeySchema, + bracket: bracketSchema, + faction: factionSchema.optional(), + rating_cutoff: z.number(), + specialization: nameIdKeySchema.optional(), +}); + +export const pvpSeasonIndexResponseSchema = responseBaseSchema.extend({ + current_season: seasonSchema, + seasons: z.array(seasonSchema), +}); + +export const pvpSeasonResponseSchema = responseBaseSchema.extend({ + id: z.number(), + leaderboards: hrefSchema, + rewards: hrefSchema, + season_end_timestamp: z.number().optional(), + season_name: z.string().optional().nullable(), + season_start_timestamp: z.number(), +}); + +const realmSchema = keyBaseSchema.extend({ + id: z.number(), + slug: z.string(), +}); + +const characterSchema = nameIdSchema.extend({ + realm: realmSchema, +}); + +const seasonMatchStatisticsSchema = z.strictObject({ + lost: z.number(), + played: z.number(), + won: z.number(), +}); + +export const pvpLeaderboardIndexResponseSchema = responseBaseSchema.extend({ + leaderboards: z.array( + keyBaseSchema.and( + z.strictObject({ + id: z.number().optional(), + name: z.string(), + }), + ), + ), + season: seasonSchema, +}); + +const entrySchema = z.strictObject({ + character: characterSchema, + faction: z.strictObject({ + type: factionsSchema, + }), + rank: z.number(), + rating: z.number(), + season_match_statistics: seasonMatchStatisticsSchema, + tier: seasonSchema, +}); + +export const pvpRewardsIndexResponseSchema = responseBaseSchema.extend({ + rewards: z.array(rewardSchema), + season: seasonSchema, +}); + +export const pvpLeaderboardResponseSchema = responseBaseSchema.extend({ + bracket: bracketSchema, + entries: z.array(entrySchema), + name: z.string(), + season: seasonSchema, +}); diff --git a/generated/schemas/wow/pvp-tier.ts b/generated/schemas/wow/pvp-tier.ts new file mode 100644 index 00000000..fb1343fc --- /dev/null +++ b/generated/schemas/wow/pvp-tier.ts @@ -0,0 +1,29 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { keyBaseSchema, mediaAssetSchema, nameIdKeySchema, nameIdSchema, responseBaseSchema } from '../core'; + +export const pvpTierIndexResponseSchema = responseBaseSchema.extend({ + tiers: z.array(nameIdKeySchema), +}); + +export const pvpTierMediaResponseSchema = responseBaseSchema.extend({ + assets: z.array(mediaAssetSchema), + id: z.number(), +}); + +const bracketSchema = z.strictObject({ + id: z.number(), + type: z.string(), +}); + +const mediaSchema = keyBaseSchema.extend({ + id: z.number(), +}); + +export const pvpTierResponseSchema = nameIdSchema.extend(responseBaseSchema.shape).extend({ + bracket: bracketSchema, + max_rating: z.number(), + media: mediaSchema, + min_rating: z.number(), + rating_type: z.number(), +}); diff --git a/generated/schemas/wow/quest.ts b/generated/schemas/wow/quest.ts new file mode 100644 index 00000000..c408d0bf --- /dev/null +++ b/generated/schemas/wow/quest.ts @@ -0,0 +1,83 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { factionSchema, hrefSchema, nameIdKeySchema, responseBaseSchema } from '../core'; + +export const questAreaIndexResponseSchema = responseBaseSchema.extend({ + areas: z.array(nameIdKeySchema), +}); + +export const questAreaResponseSchema = responseBaseSchema.extend({ + area: z.string(), + id: z.number(), + quests: z.array(nameIdKeySchema), +}); + +export const questCategoryIndexResponseSchema = responseBaseSchema.extend({ + categories: z.array(nameIdKeySchema), +}); + +export const questCategoryResponseSchema = responseBaseSchema.extend({ + category: z.string(), + id: z.number(), + quests: z.array(nameIdKeySchema), +}); + +export const questIndexResponseSchema = responseBaseSchema.extend({ + areas: hrefSchema, + categories: hrefSchema, + types: hrefSchema, +}); + +export const questTypeIndexResponseSchema = responseBaseSchema.extend({ + types: z.array(nameIdKeySchema), +}); + +export const questTypeResponseSchema = responseBaseSchema.extend({ + id: z.number(), + quests: z.array(nameIdKeySchema), + type: z.string(), +}); + +const unitsSchema = z.strictObject({ + copper: z.number(), + gold: z.number(), + silver: z.number(), +}); + +const reputationSchema = z.strictObject({ + reward: nameIdKeySchema, + value: z.number(), +}); + +const reputationRequirementSchema = z.strictObject({ + faction: nameIdKeySchema, + min_reputation: z.number(), +}); + +const requirementsSchema = z.strictObject({ + faction: factionSchema, + max_character_level: z.number(), + min_character_level: z.number(), + reputations: z.array(reputationRequirementSchema), +}); + +const moneySchema = z.strictObject({ + units: unitsSchema, + value: z.number(), +}); + +const rewardsSchema = z.strictObject({ + experience: z.number(), + money: moneySchema, + reputations: z.array(reputationSchema), +}); + +export const questResponseSchema = responseBaseSchema.extend({ + area: nameIdKeySchema.optional(), + category: nameIdKeySchema, + description: z.string(), + id: z.number(), + requirements: requirementsSchema, + rewards: rewardsSchema, + title: z.string(), +}); diff --git a/generated/schemas/wow/realm.ts b/generated/schemas/wow/realm.ts new file mode 100644 index 00000000..1008c883 --- /dev/null +++ b/generated/schemas/wow/realm.ts @@ -0,0 +1,103 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { + baseSearchParametersSchema, + hrefSchema, + keyBaseSchema, + localesSchema, + nameIdKeySchema, + nameIdSchema, + realmSchema, + responseBaseSchema, + searchResponseWithoutResultsSchema, +} from '../core'; + +export const realmCategorySchema = z.union([ + z.literal('Brazil'), + z.literal('English'), + z.literal('French'), + z.literal('German'), + z.literal('Italian'), + z.literal('Latin America'), + z.literal('Oceanic'), + z.literal('PS'), + z.literal('Russian'), + z.literal('Spanish'), + z.literal('United States'), + z.literal('\uD55C\uAD6D'), +]); + +export const realmIndexResponseSchema = responseBaseSchema.extend({ + realms: z.array(realmSchema), +}); + +export const realmLocalesSchema = z.union([ + z.literal('deDE'), + z.literal('enGB'), + z.literal('enUS'), + z.literal('esES'), + z.literal('esMX'), + z.literal('frFR'), + z.literal('itIT'), + z.literal('koKR'), + z.literal('ptBR'), + z.literal('ptPT'), + z.literal('ruRU'), + z.literal('zhCN'), + z.literal('zhTW'), +]); + +export const realmTimezoneSchema = z.union([ + z.literal('America/Chicago'), + z.literal('America/Denver'), + z.literal('America/Los_Angeles'), + z.literal('America/New_York'), + z.literal('America/Sao_Paulo'), + z.literal('Asia/Seoul'), + z.literal('Australia/Melbourne'), + z.literal('Europe/Paris'), +]); + +export const realmTypeCapitalizedSchema = z.union([z.literal('NORMAL'), z.literal('RP')]); + +export const realmSearchParametersSchema = baseSearchParametersSchema.extend({ + timezone: realmTimezoneSchema.optional(), +}); + +const realmSearchResponseItemSchema = keyBaseSchema.extend({ + data: z.strictObject({ + category: z.record(localesSchema, z.string()), + id: z.number(), + is_tournament: z.boolean(), + locale: realmLocalesSchema, + name: z.record(localesSchema, z.string()), + region: z.strictObject({ + id: z.number(), + name: z.record(localesSchema, z.string()), + }), + slug: z.string(), + timezone: realmTimezoneSchema, + type: z.strictObject({ + name: z.record(localesSchema, z.string()), + type: realmTypeCapitalizedSchema, + }), + }), +}); + +export const realmResponseSchema = nameIdSchema.extend(responseBaseSchema.shape).extend({ + category: realmCategorySchema, + connected_realm: hrefSchema, + is_tournament: z.boolean(), + locale: realmLocalesSchema, + region: nameIdKeySchema, + slug: z.string(), + timezone: realmTimezoneSchema, + type: z.strictObject({ + name: z.string(), + type: realmTypeCapitalizedSchema, + }), +}); + +export const realmSearchResponseSchema = searchResponseWithoutResultsSchema.extend({ + results: z.array(realmSearchResponseItemSchema), +}); diff --git a/generated/schemas/wow/region.ts b/generated/schemas/wow/region.ts new file mode 100644 index 00000000..aff525ba --- /dev/null +++ b/generated/schemas/wow/region.ts @@ -0,0 +1,12 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { hrefSchema, nameIdSchema, responseBaseSchema } from '../core'; + +export const regionIndexResponseSchema = responseBaseSchema.extend({ + regions: z.array(hrefSchema), +}); + +export const regionResponseSchema = nameIdSchema.extend(responseBaseSchema.shape).extend({ + patch_string: z.string(), + tag: z.string(), +}); diff --git a/generated/schemas/wow/reputations.ts b/generated/schemas/wow/reputations.ts new file mode 100644 index 00000000..65b09aef --- /dev/null +++ b/generated/schemas/wow/reputations.ts @@ -0,0 +1,50 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { factionSchema, keyBaseSchema, nameIdKeySchema, responseBaseSchema } from '../core'; + +export const reputationFactionIndexResponseSchema = responseBaseSchema.extend({ + factions: z.array(nameIdKeySchema), + root_factions: z.array(nameIdKeySchema), +}); + +const renownTierSchema = z.strictObject({ + level: z.number(), + name: z.string(), + rewards: z.array(nameIdKeySchema), +}); + +const reputationTierSchema = keyBaseSchema.extend({ + id: z.number(), + name: z.string().optional(), +}); + +export const reputationTiersIndexResponseSchema = responseBaseSchema.extend({ + reputation_tiers: z.array(reputationTierSchema), +}); + +const tierSchema = z.strictObject({ + id: z.number(), + max_value: z.number(), + min_value: z.number(), + name: z.string(), +}); + +export const reputationFactionResponseSchema = responseBaseSchema.extend({ + can_paragon: z.boolean().optional(), + description: z.string().optional(), + factions: z.array(nameIdKeySchema).optional(), + header_shows_bar: z.boolean().optional(), + id: z.number(), + is_header: z.boolean().optional(), + is_renown: z.boolean().optional(), + name: z.string(), + player_faction: factionSchema.optional(), + renown_tiers: z.array(renownTierSchema).optional(), + reputation_tiers: reputationTierSchema.optional(), +}); + +export const reputationTiersResponseSchema = responseBaseSchema.extend({ + faction: nameIdKeySchema.optional(), + id: z.number(), + tiers: z.array(tierSchema), +}); diff --git a/generated/schemas/wow/spell.ts b/generated/schemas/wow/spell.ts new file mode 100644 index 00000000..09ef89b3 --- /dev/null +++ b/generated/schemas/wow/spell.ts @@ -0,0 +1,44 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { + baseSearchParametersSchema, + keyBaseSchema, + localesSchema, + mediaAssetSchema, + nameIdSchema, + responseBaseSchema, + searchResponseWithoutResultsSchema, +} from '../core'; + +export const spellMediaResponseSchema = responseBaseSchema.extend({ + assets: z.array(mediaAssetSchema), + id: z.number(), +}); + +const mediaSchema = keyBaseSchema.extend({ + id: z.number(), +}); + +export const spellSearchParametersSchema = baseSearchParametersSchema.extend({ + locale: localesSchema, + name: z.string(), +}); + +const spellSearchResponseItemSchema = keyBaseSchema.extend({ + data: z.strictObject({ + id: z.number(), + media: z.strictObject({ + id: z.number(), + }), + name: z.record(localesSchema, z.string()), + }), +}); + +export const spellResponseSchema = nameIdSchema.extend(responseBaseSchema.shape).extend({ + description: z.string().nullable(), + media: mediaSchema, +}); + +export const spellSearchResponseSchema = searchResponseWithoutResultsSchema.extend({ + results: z.array(spellSearchResponseItemSchema), +}); diff --git a/generated/schemas/wow/talent.ts b/generated/schemas/wow/talent.ts new file mode 100644 index 00000000..50228630 --- /dev/null +++ b/generated/schemas/wow/talent.ts @@ -0,0 +1,190 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { keyBaseSchema, nameIdKeySchema, nameIdSchema, responseBaseSchema } from '../core'; + +export const pvpTalentIndexResponseSchema = responseBaseSchema.extend({ + pvp_talents: z.array(nameIdKeySchema), +}); + +export const pvpTalentResponseSchema = responseBaseSchema.extend({ + compatible_slots: z.array(z.number()), + description: z.string(), + id: z.number(), + overrides_spell: nameIdKeySchema.optional(), + playable_specialization: nameIdKeySchema, + spell: nameIdKeySchema, + unlock_player_level: z.number(), +}); + +export const talentIndexResponseSchema = responseBaseSchema.extend({ + talents: z.array(nameIdKeySchema), +}); + +const rankDescriptionSchema = z.strictObject({ + description: z.string().nullable(), + rank: z.number(), +}); + +const talentTreeSchema = keyBaseSchema.extend({ + name: z.string(), +}); + +const specTalentTreeSchema = keyBaseSchema.extend({ + name: z.string(), +}); + +const restrictionLineSchema = z.strictObject({ + is_for_class: z.boolean(), + required_points: z.number(), + restricted_row: z.number(), +}); + +const purpleSpellTooltipSchema = z.strictObject({ + cast_time: z.string(), + description: z.string(), + spell: nameIdKeySchema, +}); + +const nodeTypeSchema = z.strictObject({ + id: z.number(), + type: z.union([z.literal('ACTIVE'), z.literal('CHOICE'), z.literal('PASSIVE')]), +}); + +const choiceOfTooltipSchema = z.strictObject({ + spell_tooltip: purpleSpellTooltipSchema, + talent: nameIdKeySchema, +}); + +const tooltipSpellTooltipSchema = z.strictObject({ + cast_time: z.string(), + cooldown: z.string().optional(), + description: z.string(), + power_cost: z.string().optional(), + range: z.string().optional(), + spell: nameIdKeySchema, +}); + +export const talentResponseSchema = responseBaseSchema.extend({ + id: z.number(), + overrides_spell: nameIdKeySchema.optional(), + playable_class: keyBaseSchema + .and( + z.strictObject({ + id: z.number(), + name: z.string().optional(), + }), + ) + .optional(), + playable_specialization: nameIdKeySchema.optional(), + rank_descriptions: z.array(rankDescriptionSchema).optional(), + spell: nameIdKeySchema.optional(), +}); + +export const talentTreeIndexResponseSchema = responseBaseSchema.extend({ + class_talent_trees: z.array(talentTreeSchema), + hero_talent_trees: z.array(nameIdKeySchema), + spec_talent_trees: z.array(talentTreeSchema), +}); + +const tooltipSchema = z.strictObject({ + spell_tooltip: tooltipSpellTooltipSchema, + talent: nameIdKeySchema, +}); + +const rankSchema = z.strictObject({ + choice_of_tooltips: z.array(tooltipSchema).optional(), + default_points: z.number().optional(), + rank: z.number(), + tooltip: tooltipSchema.optional(), +}); + +const specTalentNodeRankSchema = z.strictObject({ + choice_of_tooltips: z.array(choiceOfTooltipSchema).optional(), + rank: z.number(), + tooltip: tooltipSchema.optional(), +}); + +const talentNodeSchema = z.strictObject({ + display_col: z.number(), + display_row: z.number(), + id: z.number(), + locked_by: z.array(z.number()).optional(), + node_type: nodeTypeSchema, + ranks: z.array(rankSchema), + raw_position_x: z.number(), + raw_position_y: z.number(), + unlocks: z.array(z.number()).optional(), +}); + +export const talentTreeNodesResponseSchema = responseBaseSchema.extend({ + id: z.number(), + spec_talent_trees: z.array(specTalentTreeSchema), + talent_nodes: z.array(talentNodeSchema), +}); + +const specTalentNodeSchema = z.strictObject({ + display_col: z.number(), + display_row: z.number(), + id: z.number(), + locked_by: z.array(z.number()).optional(), + node_type: nodeTypeSchema, + ranks: z.array(specTalentNodeRankSchema), + raw_position_x: z.number(), + raw_position_y: z.number(), + unlocks: z.array(z.number()).optional(), +}); + +const classTalentNodeRankSchema = z.strictObject({ + choice_of_tooltips: z.array(tooltipSchema).optional(), + default_points: z.number().optional(), + rank: z.number(), + tooltip: tooltipSchema.optional(), +}); + +const heroTalentTreeNodeSchema = z.strictObject({ + display_col: z.number(), + display_row: z.number(), + id: z.number(), + locked_by: z.array(z.number()).optional(), + node_type: z.strictObject({ + id: z.number(), + type: z.union([z.literal('ACTIVE'), z.literal('CHOICE'), z.literal('PASSIVE')]), + }), + ranks: z.array(rankSchema), + raw_position_x: z.number(), + raw_position_y: z.number(), + unlocks: z.array(z.number()).optional(), +}); + +const classTalentNodeSchema = z.strictObject({ + display_col: z.number(), + display_row: z.number(), + id: z.number(), + locked_by: z.array(z.number()).optional(), + node_type: nodeTypeSchema, + ranks: z.array(classTalentNodeRankSchema), + raw_position_x: z.number(), + raw_position_y: z.number(), + unlocks: z.array(z.number()).optional(), +}); + +const heroTalentTreeSchema = nameIdSchema.extend({ + hero_talent_nodes: z.array(heroTalentTreeNodeSchema), + media: keyBaseSchema.and( + z.strictObject({ + id: z.number(), + }), + ), + playable_class: nameIdKeySchema, + playable_specializations: z.array(nameIdKeySchema), +}); + +export const talentTreeResponseSchema = nameIdSchema.extend(responseBaseSchema.shape).extend({ + class_talent_nodes: z.array(classTalentNodeSchema), + hero_talent_trees: z.array(heroTalentTreeSchema), + media: keyBaseSchema, + playable_class: nameIdKeySchema, + playable_specialization: nameIdKeySchema, + restriction_lines: z.array(restrictionLineSchema), + spec_talent_nodes: z.array(specTalentNodeSchema), +}); diff --git a/generated/schemas/wow/tech-talent.ts b/generated/schemas/wow/tech-talent.ts new file mode 100644 index 00000000..202a7567 --- /dev/null +++ b/generated/schemas/wow/tech-talent.ts @@ -0,0 +1,61 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { keyBaseSchema, mediaAssetSchema, nameIdKeySchema, nameIdSchema, responseBaseSchema } from '../core'; + +export const techTalentIndexResponseSchema = responseBaseSchema.extend({ + talents: z.array(nameIdKeySchema), +}); + +export const techTalentMediaResponseSchema = responseBaseSchema.extend({ + assets: z.array(mediaAssetSchema), +}); + +const mediaSchema = keyBaseSchema.extend({ + id: z.number(), +}); + +const spellTooltipSchema = z.strictObject({ + cast_time: z.string(), + cooldown: z.string().optional(), + description: z.string().nullable(), + power_cost: z.string().optional().nullable(), + range: z.string().optional(), + spell: nameIdKeySchema, +}); + +const talentTreeSchema = keyBaseSchema.extend({ + id: z.number(), + name: z.string().optional(), +}); + +export const techTalentTreeResponseSchema = responseBaseSchema.extend({ + id: z.number(), + max_tiers: z.number(), + playable_class: nameIdKeySchema.optional(), + talents: z.array(nameIdKeySchema), +}); + +export const techTalentResponseSchema = nameIdSchema.extend(responseBaseSchema.shape).extend({ + description: z.string().optional(), + display_order: z.number(), + media: mediaSchema, + prerequisite_talent: nameIdKeySchema.optional(), + socket_type: z + .strictObject({ + name: z.string(), + type: z.union([z.literal('ENDURANCE'), z.literal('FINESSE'), z.literal('POTENCY')]), + }) + .optional(), + spell_tooltip: spellTooltipSchema.optional(), + talent_tree: keyBaseSchema.and( + z.strictObject({ + id: z.number(), + name: z.string().optional(), + }), + ), + tier: z.number(), +}); + +export const techTalentTreeIndexResponseSchema = responseBaseSchema.extend({ + talent_trees: z.array(talentTreeSchema), +}); diff --git a/generated/schemas/wow/title.ts b/generated/schemas/wow/title.ts new file mode 100644 index 00000000..e4af6d1c --- /dev/null +++ b/generated/schemas/wow/title.ts @@ -0,0 +1,27 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { genderNameSchema, nameIdKeySchema, nameIdSchema, responseBaseSchema } from '../core'; + +export const titleIndexResponseSchema = responseBaseSchema.extend({ + titles: z.array(nameIdKeySchema), +}); + +const titleSourceSchema = z.strictObject({ + achievements: z.array(nameIdKeySchema).optional(), + quests: z.array(nameIdKeySchema).optional(), + type: z.union([ + z.strictObject({ + name: z.literal('Achievement'), + type: z.literal('ACHIEVEMENT'), + }), + z.strictObject({ + name: z.literal('Quest'), + type: z.literal('QUEST'), + }), + ]), +}); + +export const titleResponseSchema = nameIdSchema.extend(responseBaseSchema.shape).extend({ + gender_name: genderNameSchema, + source: titleSourceSchema.optional(), +}); diff --git a/generated/schemas/wow/toy.ts b/generated/schemas/wow/toy.ts new file mode 100644 index 00000000..3431daf9 --- /dev/null +++ b/generated/schemas/wow/toy.ts @@ -0,0 +1,25 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { keyBaseSchema, nameIdKeySchema, responseBaseSchema } from '../core'; + +export const toyIndexResponseSchema = responseBaseSchema.extend({ + toys: z.array(nameIdKeySchema), +}); + +const mediaSchema = keyBaseSchema.extend({ + id: z.number(), +}); + +const sourceSchema = z.strictObject({ + name: z.string(), + type: z.string(), +}); + +export const toyResponseSchema = responseBaseSchema.extend({ + id: z.number(), + item: nameIdKeySchema, + media: mediaSchema, + should_exclude_if_uncollected: z.boolean().optional(), + source: sourceSchema, + source_description: z.string().optional(), +}); diff --git a/generated/schemas/wow/wow-token.ts b/generated/schemas/wow/wow-token.ts new file mode 100644 index 00000000..de7d514e --- /dev/null +++ b/generated/schemas/wow/wow-token.ts @@ -0,0 +1,8 @@ +// Generated by ts-to-zod +import { z } from 'zod'; +import { responseBaseSchema } from '../core'; + +export const wowTokenResponseSchema = responseBaseSchema.extend({ + last_updated_timestamp: z.number(), + price: z.number(), +}); diff --git a/package.json b/package.json index 6521a1ba..6a43c87a 100644 --- a/package.json +++ b/package.json @@ -7,9 +7,9 @@ "repository": "https://github.com/Pewtro/blizzard-api", "type": "module", "engines": { - "node": "^18.18 || >=20.9" + "node": "^20.19.0 || ^22.13.0 || >=24" }, - "packageManager": "pnpm@10.24.0", + "packageManager": "pnpm@10.28.0", "keywords": [ "blizzard", "battlenet", @@ -30,25 +30,27 @@ ], "devDependencies": { "@changesets/cli": "2.29.8", - "@putstack/eslint-config-typescript": "4.11.0", + "@putstack/eslint-config-typescript": "4.14.0", "@putstack/prettier-config": "2.0.0", - "@types/node": "24.10.1", - "@vitest/coverage-v8": "4.0.15", - "@vitest/ui": "4.0.15", - "eslint": "9.39.1", - "eslint-plugin-jsdoc": "61.4.1", + "@types/node": "24.10.10", + "@vitest/coverage-v8": "4.0.18", + "@vitest/ui": "4.0.18", + "eslint": "9.39.2", + "eslint-plugin-jsdoc": "62.5.0", "husky": "9.1.7", "lint-staged": "16.2.7", "npm-run-all2": "8.0.4", - "prettier": "3.7.4", - "tsdown": "0.17.0", - "turbo": "2.6.3", - "typedoc": "0.28.15", + "prettier": "3.8.1", + "ts-to-zod": "5.1.0", + "tsdown": "0.20.1", + "tsx": "4.21.0", + "turbo": "2.8.2", + "typedoc": "0.28.16", "typedoc-github-theme": "0.3.1", "typescript": "5.9.3", - "typescript-eslint": "8.48.1", - "vitest": "4.0.15", - "zod": "4.1.13" + "typescript-eslint": "8.54.0", + "vitest": "4.0.18", + "zod": "4.3.6" }, "pnpm": { "onlyBuiltDependencies": [ @@ -57,18 +59,21 @@ ] }, "scripts": { - "build": "turbo build", "build:docs": "typedoc", - "lint": "eslint --format stylish --max-warnings 0 --cache", + "build": "turbo build", + "generate:zod": "tsx ./scripts/generate-zod.ts", + "generate": "npm-run-all -l generate:zod \"prettier:write ./generated\" \"lint:fix ./generated\"", "lint:ci": "npm-run-all -p -l typecheck stylecheck \"lint .\"", "lint:fix": "pnpm lint --fix", + "lint": "eslint --format stylish --max-warnings 0 --cache", "prepare": "husky", + "prettier:write": "prettier --write", "release": "changeset publish", "stylecheck": "prettier --check .", - "test": "vitest run", "test:coverage": "pnpm run test --coverage", "test:ui": "vitest --ui --coverage", "test:watch": "vitest watch", + "test": "vitest run", "typecheck": "tsc" }, "lint-staged": { diff --git a/packages/classic-wow/package.json b/packages/classic-wow/package.json index c76862c0..1a0ea046 100644 --- a/packages/classic-wow/package.json +++ b/packages/classic-wow/package.json @@ -7,7 +7,7 @@ "repository": "https://github.com/Pewtro/blizzard-api/tree/main/packages/classic-wow", "type": "module", "engines": { - "node": "^18.18 || >=20.9" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "module": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/classic-wow/src/auction-house/auction-house.ts b/packages/classic-wow/src/auction-house/auction-house.ts index 9a712548..b6d5e309 100644 --- a/packages/classic-wow/src/auction-house/auction-house.ts +++ b/packages/classic-wow/src/auction-house/auction-house.ts @@ -1,5 +1,5 @@ +import { wowBasePath } from '@blizzard-api/core'; import type { BlizzardNamespaces, Resource } from '@blizzard-api/core'; -import { base } from '../../../wow/src/base'; import type { AuctionHouseIndexResponse, AuctionsResponse } from './types'; /** @@ -14,7 +14,7 @@ export function auctionHouseIndex( ): Resource { return { namespace, - path: `${base}/connected-realm/${connectedRealmId}/auctions/index`, + path: `${wowBasePath}/connected-realm/${connectedRealmId}/auctions/index`, }; } /** @@ -35,6 +35,6 @@ export function auctions( ): Resource { return { namespace, - path: `${base}/connected-realm/${connectedRealmId}/auctions/${auctionHouseId}`, + path: `${wowBasePath}/connected-realm/${connectedRealmId}/auctions/${auctionHouseId}`, }; } diff --git a/packages/classic-wow/src/auction-house/types.ts b/packages/classic-wow/src/auction-house/types.ts index 0db8c7d7..338e337e 100644 --- a/packages/classic-wow/src/auction-house/types.ts +++ b/packages/classic-wow/src/auction-house/types.ts @@ -1,4 +1,4 @@ -import type { NameId, NameIdKey, ResponseBase } from '../../../wow/src/base'; +import type { Href, NameId, NameIdKey, ResponseBase } from '@blizzard-api/core'; export interface AuctionHouseIndexResponse extends ResponseBase { auctions: Array; @@ -6,7 +6,7 @@ export interface AuctionHouseIndexResponse extends ResponseBase { export interface AuctionsResponse extends NameId, ResponseBase { auctions: Array; - connected_realm: { href: string }; + connected_realm: Href; } interface Auction { diff --git a/packages/classic-wow/src/base.ts b/packages/classic-wow/src/base.ts deleted file mode 100644 index b81e4d39..00000000 --- a/packages/classic-wow/src/base.ts +++ /dev/null @@ -1,4 +0,0 @@ -/** - * The base request path for the character API for Classic World of Warcraft. - */ -export const characterBase = 'profile/wow/character'; diff --git a/packages/classic-wow/src/character-achievements/character-achievements.test.ts b/packages/classic-wow/src/character-achievements/character-achievements.test.ts index 85e94bb7..91fecc77 100644 --- a/packages/classic-wow/src/character-achievements/character-achievements.test.ts +++ b/packages/classic-wow/src/character-achievements/character-achievements.test.ts @@ -1,6 +1,6 @@ +import { wowCharacterBasePath } from '@blizzard-api/core'; import type { BlizzardNamespaces } from '@blizzard-api/core'; import { describe, expect, it } from 'vitest'; -import { characterBase } from '../base'; import { characterAchievementsSummary, characterAchievementStatistics } from './character-achievements'; describe('characterAchievementsSummary', () => { @@ -12,7 +12,7 @@ describe('characterAchievementsSummary', () => { expect(result).toEqual({ namespace, - path: `${characterBase}/${realmSlug}/${characterName.toLowerCase()}/achievements`, + path: `${wowCharacterBasePath}/${realmSlug}/${characterName.toLowerCase()}/achievements`, }); }); }); @@ -26,7 +26,7 @@ describe('characterAchievementStatistics', () => { expect(result).toEqual({ namespace, - path: `${characterBase}/${realmSlug}/${characterName.toLowerCase()}/achievements/statistics`, + path: `${wowCharacterBasePath}/${realmSlug}/${characterName.toLowerCase()}/achievements/statistics`, }); }); }); diff --git a/packages/classic-wow/src/character-achievements/character-achievements.ts b/packages/classic-wow/src/character-achievements/character-achievements.ts index ed2fe9d1..ff675191 100644 --- a/packages/classic-wow/src/character-achievements/character-achievements.ts +++ b/packages/classic-wow/src/character-achievements/character-achievements.ts @@ -1,5 +1,5 @@ import type { BlizzardNamespaces, Resource } from '@blizzard-api/core'; -import { characterBase } from '../base'; +import { wowCharacterBasePath } from '@blizzard-api/core'; import type { CharacterAchievementsSummaryResponse, CharacterAchievementStatisticsResponse } from './types'; /** @@ -15,7 +15,7 @@ export function characterAchievementsSummary( ): Resource { return { namespace, - path: `${characterBase}/${realmSlug}/${characterName.toLowerCase()}/achievements`, + path: `${wowCharacterBasePath}/${realmSlug}/${characterName.toLowerCase()}/achievements`, }; } @@ -32,6 +32,6 @@ export function characterAchievementStatistics( ): Resource { return { namespace, - path: `${characterBase}/${realmSlug}/${characterName.toLowerCase()}/achievements/statistics`, + path: `${wowCharacterBasePath}/${realmSlug}/${characterName.toLowerCase()}/achievements/statistics`, }; } diff --git a/packages/classic-wow/src/character-achievements/types.ts b/packages/classic-wow/src/character-achievements/types.ts index 5308dccb..a7fd3035 100644 --- a/packages/classic-wow/src/character-achievements/types.ts +++ b/packages/classic-wow/src/character-achievements/types.ts @@ -1,5 +1,81 @@ -import type { CharacterAchievementsSummaryResponse as CharacterAchievementsSummaryRetailResponse } from '../../../wow/src/character-achievements/types'; +import type { Character, NameIdKey, ResponseBase } from '@blizzard-api/core'; -export type { CharacterAchievementStatisticsResponse } from '../../../wow/src/character-achievements/types'; +export interface CharacterAchievementsSummaryResponse extends ResponseBase { + achievements: Array; + category_progress: Array; + character: Character; + recent_events: Array; + total_points: number; + total_quantity: number; +} -export type CharacterAchievementsSummaryResponse = Omit; +export interface CharacterAchievementStatisticsResponse extends ResponseBase { + categories: Array; + character: Character; +} + +interface Achievement { + achievement: NameIdKey; + completed_timestamp?: number; + criteria?: Criteria; + id: number; +} + +interface Category { + id: number; + name: string; + statistics?: Array; + sub_categories?: Array; +} + +interface CategoryProgress { + category: NameIdKey; + points: number; + quantity: number; +} + +interface ChildCriterum { + amount?: number; + child_criteria?: Array; + id: number; + is_completed: boolean; +} + +interface ChildCriterum2 { + amount?: number; + child_criteria?: Array; + id: number; + is_completed: boolean; +} + +interface ChildCriterum3 { + amount?: number; + id: number; + is_completed: boolean; +} + +interface Criteria { + amount?: number; + child_criteria?: Array; + id: number; + is_completed: boolean; +} + +interface RecentEvent { + achievement: NameIdKey; + timestamp: number; +} + +interface Statistic { + description?: null | string; + id: number; + last_updated_timestamp: number; + name: string; + quantity: number; +} + +interface SubCategory { + id: number; + name: string; + statistics: Array; +} diff --git a/packages/classic-wow/src/character-equipment/character-equipment.test.ts b/packages/classic-wow/src/character-equipment/character-equipment.test.ts index 9b5477c6..2b614d5d 100644 --- a/packages/classic-wow/src/character-equipment/character-equipment.test.ts +++ b/packages/classic-wow/src/character-equipment/character-equipment.test.ts @@ -1,6 +1,6 @@ import type { BlizzardNamespaces } from '@blizzard-api/core'; +import { wowCharacterBasePath } from '@blizzard-api/core'; import { describe, expect, it } from 'vitest'; -import { characterBase } from '../base'; import { characterEquipmentSummary } from './character-equipment'; describe('characterEquipmentSummary', () => { @@ -13,7 +13,7 @@ describe('characterEquipmentSummary', () => { expect(result).toEqual({ namespace, - path: `${characterBase}/${realmSlug}/${characterName}/equipment`, + path: `${wowCharacterBasePath}/${realmSlug}/${characterName}/equipment`, }); }); @@ -26,7 +26,7 @@ describe('characterEquipmentSummary', () => { expect(result).toEqual({ namespace, - path: `${characterBase}/${realmSlug}/${characterName}/equipment`, + path: `${wowCharacterBasePath}/${realmSlug}/${characterName}/equipment`, }); }); }); diff --git a/packages/classic-wow/src/character-equipment/character-equipment.ts b/packages/classic-wow/src/character-equipment/character-equipment.ts index ced7384b..041a15fe 100644 --- a/packages/classic-wow/src/character-equipment/character-equipment.ts +++ b/packages/classic-wow/src/character-equipment/character-equipment.ts @@ -1,5 +1,5 @@ import type { BlizzardNamespaces, Resource } from '@blizzard-api/core'; -import { characterBase } from '../base'; +import { wowCharacterBasePath } from '@blizzard-api/core'; import type { CharacterEquipmentSummaryResponse } from './types'; /** @@ -16,6 +16,6 @@ export function characterEquipmentSummary( ): Resource { return { namespace, - path: `${characterBase}/${realmSlug}/${characterName}/equipment`, + path: `${wowCharacterBasePath}/${realmSlug}/${characterName}/equipment`, }; } diff --git a/packages/classic-wow/src/character-equipment/types.ts b/packages/classic-wow/src/character-equipment/types.ts index 1b65b96d..6fcb666d 100644 --- a/packages/classic-wow/src/character-equipment/types.ts +++ b/packages/classic-wow/src/character-equipment/types.ts @@ -1 +1,160 @@ -export type { CharacterEquipmentSummaryResponse } from '../../../wow/src/character-equipment/types'; +import type { Character, Color, KeyBase, NameIdKey, ResponseBase } from '@blizzard-api/core'; + +export interface CharacterEquipmentSummaryResponse extends ResponseBase { + character: Character; + equipped_item_sets: Array; + equipped_items: Array; +} + +interface Armor { + display: NameDescription; + value: number; +} + +interface Damage { + damage_class: NameType; + display_string: string; + max_value: number; + min_value: number; +} + +interface DisplayStrings { + copper: string; + gold: string; + header: string; + silver: string; +} + +interface DisplayStringValue { + display_string: string; + value: number; +} + +interface Effect { + display_string: string; + is_active: boolean; + required_count: number; +} + +interface Enchantment { + display_string?: string; + enchantment_id: number; + enchantment_slot: EnchantmentSlot; + source_item?: NameIdKey; + spell?: { description: string; spell: NameIdKey }; +} + +interface EnchantmentSlot { + id: number; + type?: string; +} + +interface EquippedItem { + armor?: Armor; + binding: NameType; + bonus_list?: Array; + context?: number; + description?: string; + durability?: DisplayStringValue; + enchantments?: Array; + inventory_type: NameType; + is_subclass_hidden?: boolean; + item: KeyBase & { id: number }; + item_class: NameIdKey; + item_subclass: NameIdKey; + level?: DisplayStringValue; + limit_category?: string; + media: KeyBase & { id: number }; + modified_appearance_id?: number; + modified_crafting_stat?: Array; + name: string; + name_description?: NameDescription; + quality: NameType; + quantity: number; + requirements?: Requirements; + sell_price?: SellPrice; + set?: Set; + slot: NameType; + sockets?: Array; + spells?: Array; + stats?: Array; + transmog?: Transmog; + unique_equipped?: string; + upgrade_id?: number; + weapon?: Weapon; +} + +interface ItemElement { + is_equipped?: boolean; + item: NameIdKey; +} + +interface ModifiedCraftingStat { + id: number; + name: string; + type: string; +} + +interface NameDescription { + color: Color; + display_string: string; +} + +interface NameType { + name: string; + type: string; +} + +interface PlayableClasses { + display_string: string; + links: Array; +} + +interface Requirements { + level: DisplayStringValue; + playable_classes?: PlayableClasses; +} + +interface SellPrice { + display_strings: DisplayStrings; + value: number; +} + +interface Set { + display_string?: string; + effects?: Array; + item_set?: NameIdKey; + items?: Array; +} + +interface Socket { + display_string: string; + item: NameIdKey; + media: KeyBase & { id: number }; + socket_type: NameType; +} + +interface Spell { + description: string; + spell: NameIdKey; +} + +interface Stat { + display: NameDescription; + is_equip_bonus?: boolean; + is_negated?: boolean; + type: NameType; + value: number; +} + +interface Transmog { + display_string: string; + item: NameIdKey; + item_modified_appearance_id: number; +} + +interface Weapon { + attack_speed: DisplayStringValue; + damage: Damage; + dps: DisplayStringValue; +} diff --git a/packages/classic-wow/src/character-hunter-pets/character-hunter-pets.test.ts b/packages/classic-wow/src/character-hunter-pets/character-hunter-pets.test.ts index 64d2c4a4..31ed76b8 100644 --- a/packages/classic-wow/src/character-hunter-pets/character-hunter-pets.test.ts +++ b/packages/classic-wow/src/character-hunter-pets/character-hunter-pets.test.ts @@ -1,6 +1,6 @@ import type { BlizzardNamespaces } from '@blizzard-api/core'; +import { wowCharacterBasePath } from '@blizzard-api/core'; import { describe, expect, it } from 'vitest'; -import { characterBase } from '../base'; import { characterHunterPetsSummary } from './character-hunter-pets'; describe('characterHunterPetsSummary', () => { @@ -12,7 +12,7 @@ describe('characterHunterPetsSummary', () => { expect(result).toEqual({ namespace, - path: `${characterBase}/${realmSlug}/${characterName}/hunter-pets`, + path: `${wowCharacterBasePath}/${realmSlug}/${characterName}/hunter-pets`, }); }); @@ -24,7 +24,7 @@ describe('characterHunterPetsSummary', () => { expect(result).toEqual({ namespace, - path: `${characterBase}/${realmSlug}/${characterName}/hunter-pets`, + path: `${wowCharacterBasePath}/${realmSlug}/${characterName}/hunter-pets`, }); }); }); diff --git a/packages/classic-wow/src/character-hunter-pets/character-hunter-pets.ts b/packages/classic-wow/src/character-hunter-pets/character-hunter-pets.ts index 385692bf..f192e764 100644 --- a/packages/classic-wow/src/character-hunter-pets/character-hunter-pets.ts +++ b/packages/classic-wow/src/character-hunter-pets/character-hunter-pets.ts @@ -1,5 +1,5 @@ import type { BlizzardNamespaces, Resource } from '@blizzard-api/core'; -import { characterBase } from '../base'; +import { wowCharacterBasePath } from '@blizzard-api/core'; import type { CharacterHunterPetsSummaryResponse } from './types'; /** @@ -16,6 +16,6 @@ export function characterHunterPetsSummary( ): Resource { return { namespace, - path: `${characterBase}/${realmSlug}/${characterName}/hunter-pets`, + path: `${wowCharacterBasePath}/${realmSlug}/${characterName}/hunter-pets`, }; } diff --git a/packages/classic-wow/src/character-hunter-pets/types.ts b/packages/classic-wow/src/character-hunter-pets/types.ts index 847c9c2b..77a6201d 100644 --- a/packages/classic-wow/src/character-hunter-pets/types.ts +++ b/packages/classic-wow/src/character-hunter-pets/types.ts @@ -1 +1,16 @@ -export type { CharacterHunterPetsSummaryResponse } from '../../../wow/src/character-hunter-pets/types'; +import type { Character, KeyBase, NameIdKey, ResponseBase } from '@blizzard-api/core'; + +export interface CharacterHunterPetsSummaryResponse extends ResponseBase { + character: Character; + hunter_pets: Array; +} + +interface HunterPet { + creature: NameIdKey; + creature_display: KeyBase & { id: number }; + is_active?: boolean; + is_summoned?: boolean; + level: number; + name: string; + slot: number; +} diff --git a/packages/classic-wow/src/character-media/character-media.test.ts b/packages/classic-wow/src/character-media/character-media.test.ts index cc4c4deb..517e4f73 100644 --- a/packages/classic-wow/src/character-media/character-media.test.ts +++ b/packages/classic-wow/src/character-media/character-media.test.ts @@ -1,6 +1,6 @@ import type { BlizzardNamespaces, Resource } from '@blizzard-api/core'; +import { wowCharacterBasePath } from '@blizzard-api/core'; import { describe, expect, it } from 'vitest'; -import { characterBase } from '../base'; import { characterMediaSummary } from './character-media'; import type { CharacterMediaSummaryResponse } from './types'; @@ -14,7 +14,7 @@ describe('characterMediaSummary', () => { expect(result).toEqual({ namespace, - path: `${characterBase}/${realmSlug}/${characterName}/character-media`, + path: `${wowCharacterBasePath}/${realmSlug}/${characterName}/character-media`, }); }); @@ -27,7 +27,7 @@ describe('characterMediaSummary', () => { expect(result).toEqual({ namespace, - path: `${characterBase}/${realmSlug}/${characterName}/character-media`, + path: `${wowCharacterBasePath}/${realmSlug}/${characterName}/character-media`, }); }); }); diff --git a/packages/classic-wow/src/character-media/character-media.ts b/packages/classic-wow/src/character-media/character-media.ts index 0163a028..184ee0f3 100644 --- a/packages/classic-wow/src/character-media/character-media.ts +++ b/packages/classic-wow/src/character-media/character-media.ts @@ -1,5 +1,5 @@ import type { BlizzardNamespaces, Resource } from '@blizzard-api/core'; -import { characterBase } from '../base'; +import { wowCharacterBasePath } from '@blizzard-api/core'; import type { CharacterMediaSummaryResponse } from './types'; /** @@ -15,6 +15,6 @@ export function characterMediaSummary( ): Resource { return { namespace, - path: `${characterBase}/${realmSlug}/${characterName}/character-media`, + path: `${wowCharacterBasePath}/${realmSlug}/${characterName}/character-media`, }; } diff --git a/packages/classic-wow/src/character-media/types.ts b/packages/classic-wow/src/character-media/types.ts index d656980d..f92742c4 100644 --- a/packages/classic-wow/src/character-media/types.ts +++ b/packages/classic-wow/src/character-media/types.ts @@ -1 +1,11 @@ -export type { CharacterMediaSummaryResponse } from '../../../wow/src/character-media/types'; +import type { Character, ResponseBase } from '@blizzard-api/core'; + +export interface CharacterMediaSummaryResponse extends ResponseBase { + assets: Array; + character: Character; +} + +interface Asset { + key: string; + value: string; +} diff --git a/packages/classic-wow/src/character-profile/character-profile.test.ts b/packages/classic-wow/src/character-profile/character-profile.test.ts index f4fce5b3..30cf38ed 100644 --- a/packages/classic-wow/src/character-profile/character-profile.test.ts +++ b/packages/classic-wow/src/character-profile/character-profile.test.ts @@ -1,6 +1,6 @@ import type { BlizzardNamespaces } from '@blizzard-api/core'; +import { wowCharacterBasePath } from '@blizzard-api/core'; import { describe, expect, it } from 'vitest'; -import { characterBase } from '../base'; import { characterProfileStatus, characterProfileSummary } from './character-profile'; describe('characterProfileStatus', () => { @@ -13,7 +13,7 @@ describe('characterProfileStatus', () => { expect(result).toEqual({ namespace, - path: `${characterBase}/${realmSlug}/${characterName.toLowerCase()}/status`, + path: `${wowCharacterBasePath}/${realmSlug}/${characterName.toLowerCase()}/status`, }); }); }); @@ -28,7 +28,7 @@ describe('characterProfileSummary', () => { expect(result).toEqual({ namespace, - path: `${characterBase}/${realmSlug}/${characterName.toLowerCase()}`, + path: `${wowCharacterBasePath}/${realmSlug}/${characterName.toLowerCase()}`, }); }); }); diff --git a/packages/classic-wow/src/character-profile/character-profile.ts b/packages/classic-wow/src/character-profile/character-profile.ts index b73f3c56..616808e9 100644 --- a/packages/classic-wow/src/character-profile/character-profile.ts +++ b/packages/classic-wow/src/character-profile/character-profile.ts @@ -1,5 +1,5 @@ import type { BlizzardNamespaces, Resource } from '@blizzard-api/core'; -import { characterBase } from '../base'; +import { wowCharacterBasePath } from '@blizzard-api/core'; import type { CharacterProfileStatusResponse, CharacterProfileSummaryResponse } from './types'; /** @@ -26,7 +26,7 @@ export function characterProfileStatus( ): Resource { return { namespace, - path: `${characterBase}/${realmSlug}/${characterName.toLowerCase()}/status`, + path: `${wowCharacterBasePath}/${realmSlug}/${characterName.toLowerCase()}/status`, }; } @@ -44,6 +44,6 @@ export function characterProfileSummary( ): Resource { return { namespace, - path: `${characterBase}/${realmSlug}/${characterName.toLowerCase()}`, + path: `${wowCharacterBasePath}/${realmSlug}/${characterName.toLowerCase()}`, }; } diff --git a/packages/classic-wow/src/character-profile/types.ts b/packages/classic-wow/src/character-profile/types.ts index 98af6c6f..6cdd1243 100644 --- a/packages/classic-wow/src/character-profile/types.ts +++ b/packages/classic-wow/src/character-profile/types.ts @@ -1,4 +1,5 @@ -import type { Faction, Gender, Href, NameIdKey, Realm, ResponseBase } from '../../../wow/src/base'; +import type { Faction, Gender, Href, NameIdKey, Realm, ResponseBase } from '@blizzard-api/core'; + export type { CharacterProfileStatusResponse } from '../../../wow/src/character-profile/types'; export interface CharacterProfileSummaryResponse extends ResponseBase { @@ -15,6 +16,7 @@ export interface CharacterProfileSummaryResponse extends ResponseBase { faction: Faction; gender: Gender; guild: Guild; + hunter_pets?: Href; id: number; //Hardcore only is_ghost?: boolean; diff --git a/packages/classic-wow/src/character-specialization/character-specialization.test.ts b/packages/classic-wow/src/character-specialization/character-specialization.test.ts index c65d07e7..1c383103 100644 --- a/packages/classic-wow/src/character-specialization/character-specialization.test.ts +++ b/packages/classic-wow/src/character-specialization/character-specialization.test.ts @@ -1,6 +1,6 @@ import type { BlizzardNamespaces, Resource } from '@blizzard-api/core'; +import { wowCharacterBasePath } from '@blizzard-api/core'; import { describe, expect, it } from 'vitest'; -import { characterBase } from '../base'; import { characterSpecializationsSummary } from './character-specialization'; import type { CharacterSpecializationsSummaryResponse } from './types'; @@ -18,7 +18,7 @@ describe('characterSpecializationsSummary', () => { expect(result).toEqual({ namespace, - path: `${characterBase}/${realmSlug}/${characterName}/specializations`, + path: `${wowCharacterBasePath}/${realmSlug}/${characterName}/specializations`, }); }); @@ -35,7 +35,7 @@ describe('characterSpecializationsSummary', () => { expect(result).toEqual({ namespace, - path: `${characterBase}/${realmSlug}/${characterName}/specializations`, + path: `${wowCharacterBasePath}/${realmSlug}/${characterName}/specializations`, }); }); }); diff --git a/packages/classic-wow/src/character-specialization/character-specialization.ts b/packages/classic-wow/src/character-specialization/character-specialization.ts index 0b7381d0..022ffac7 100644 --- a/packages/classic-wow/src/character-specialization/character-specialization.ts +++ b/packages/classic-wow/src/character-specialization/character-specialization.ts @@ -1,5 +1,5 @@ import type { BlizzardNamespaces, Resource } from '@blizzard-api/core'; -import { characterBase } from '../base'; +import { wowCharacterBasePath } from '@blizzard-api/core'; import type { CharacterSpecializationsSummaryResponse } from './types'; /** @@ -15,6 +15,6 @@ export function characterSpecializationsSummary( ): Resource { return { namespace, - path: `${characterBase}/${realmSlug}/${characterName}/specializations`, + path: `${wowCharacterBasePath}/${realmSlug}/${characterName}/specializations`, }; } diff --git a/packages/classic-wow/src/character-specialization/types.ts b/packages/classic-wow/src/character-specialization/types.ts index d0bda288..5b974922 100644 --- a/packages/classic-wow/src/character-specialization/types.ts +++ b/packages/classic-wow/src/character-specialization/types.ts @@ -1,20 +1,28 @@ -import type { Character, NameId, ResponseBase } from '../../../wow/src/base'; +import type { Character, NameId, NameIdKey, ResponseBase } from '@blizzard-api/core'; export interface CharacterSpecializationsSummaryResponse extends ResponseBase { + active_specialization?: NameIdKey; character: Character; specialization_groups: Array; + specializations?: Array; } -interface Specialization { +interface ClassicProgressionSpecialization { + specialization: NameIdKey; specialization_name: string; - spent_points: number; - talents: Array; + talents?: Array; } interface SpecializationGroup { glyphs?: Array; is_active: boolean; - specializations?: Array; + specializations?: Array; +} + +interface SpecializationGroupItem { + specialization_name: string; + spent_points: number; + talents: Array; } interface SpellTooltip { @@ -28,6 +36,6 @@ interface SpellTooltip { interface TalentElement { spell_tooltip: SpellTooltip; - talent: { id: number }; - talent_rank: number; + talent: NameId | { id: number }; + talent_rank?: number; } diff --git a/packages/classic-wow/src/character-statistics/character-statistics.test.ts b/packages/classic-wow/src/character-statistics/character-statistics.test.ts index 14b523d6..71e61913 100644 --- a/packages/classic-wow/src/character-statistics/character-statistics.test.ts +++ b/packages/classic-wow/src/character-statistics/character-statistics.test.ts @@ -1,6 +1,6 @@ import type { BlizzardNamespaces } from '@blizzard-api/core'; +import { wowCharacterBasePath } from '@blizzard-api/core'; import { describe, expect, it } from 'vitest'; -import { characterBase } from '../base'; import { characterStatisticsSummary } from './character-statistics'; describe('characterStatisticsSummary', () => { @@ -13,7 +13,7 @@ describe('characterStatisticsSummary', () => { expect(result).toEqual({ namespace, - path: `${characterBase}/${realmSlug}/${characterName}/statistics`, + path: `${wowCharacterBasePath}/${realmSlug}/${characterName}/statistics`, }); }); @@ -26,7 +26,7 @@ describe('characterStatisticsSummary', () => { expect(result).toEqual({ namespace, - path: `${characterBase}/${realmSlug}/${characterName}/statistics`, + path: `${wowCharacterBasePath}/${realmSlug}/${characterName}/statistics`, }); }); }); diff --git a/packages/classic-wow/src/character-statistics/character-statistics.ts b/packages/classic-wow/src/character-statistics/character-statistics.ts index fccb9bd2..7ccc850f 100644 --- a/packages/classic-wow/src/character-statistics/character-statistics.ts +++ b/packages/classic-wow/src/character-statistics/character-statistics.ts @@ -1,5 +1,5 @@ import type { BlizzardNamespaces, Resource } from '@blizzard-api/core'; -import { characterBase } from '../base'; +import { wowCharacterBasePath } from '@blizzard-api/core'; import type { CharacterStatisticsSummaryResponse } from './types'; /** @@ -15,6 +15,6 @@ export function characterStatisticsSummary( ): Resource { return { namespace, - path: `${characterBase}/${realmSlug}/${characterName}/statistics`, + path: `${wowCharacterBasePath}/${realmSlug}/${characterName}/statistics`, }; } diff --git a/packages/classic-wow/src/character-statistics/types.ts b/packages/classic-wow/src/character-statistics/types.ts index c8593a94..c8bba801 100644 --- a/packages/classic-wow/src/character-statistics/types.ts +++ b/packages/classic-wow/src/character-statistics/types.ts @@ -1,8 +1,8 @@ -import type { Character, ResponseBase } from '../../../wow/src/base'; +import type { Character, NameIdKey, ResponseBase } from '@blizzard-api/core'; export interface CharacterStatisticsSummaryResponse extends ResponseBase { agility: BaseEffectiveStat; - arcane_resistance: BaseEffectiveStat; + arcane_resistance?: BaseEffectiveStat; armor: BaseEffectiveStat; attack_power: number; block: RatingWithValue; @@ -10,9 +10,9 @@ export interface CharacterStatisticsSummaryResponse extends ResponseBase { character: Character; defense?: BaseEffectiveStat; dodge: RatingWithValue; - fire_resistance: BaseEffectiveStat; + fire_resistance?: BaseEffectiveStat; health: number; - holy_resistance: BaseEffectiveStat; + holy_resistance?: BaseEffectiveStat; intellect: BaseEffectiveStat; main_hand_damage_max: number; main_hand_damage_min: number; @@ -23,17 +23,17 @@ export interface CharacterStatisticsSummaryResponse extends ResponseBase { mastery?: RatingWithValue; melee_crit: RatingWithValue; melee_haste?: RatingWithValue; - nature_resistance: BaseEffectiveStat; + nature_resistance?: BaseEffectiveStat; off_hand_damage_max: number; off_hand_damage_min: number; off_hand_dps: number; off_hand_speed: number; parry: RatingWithValue; power: number; - power_type: Character; + power_type: NameIdKey; ranged_crit: RatingWithValue; ranged_haste?: RatingWithValue; - shadow_resistance: BaseEffectiveStat; + shadow_resistance?: BaseEffectiveStat; spell_crit: RatingWithValue; spell_haste?: RatingWithValue; spell_penetration: number; @@ -49,7 +49,7 @@ interface BaseEffectiveStat { } interface RatingWithValue { - rating: number; rating_bonus: number; + rating_normalized: number; value: number; } diff --git a/packages/classic-wow/src/connected-realm/connected-realm.ts b/packages/classic-wow/src/connected-realm/connected-realm.ts index c10b114d..587b1109 100644 --- a/packages/classic-wow/src/connected-realm/connected-realm.ts +++ b/packages/classic-wow/src/connected-realm/connected-realm.ts @@ -1,10 +1,10 @@ -import type { BlizzardNamespaces, Resource, SearchResponse } from '@blizzard-api/core'; -import { base } from '../../../wow/src/base'; +import { wowBasePath } from '@blizzard-api/core'; +import type { BlizzardNamespaces, Resource } from '@blizzard-api/core'; import type { ConnectedRealmIndexResponse, ConnectedRealmResponse, ConnectedRealmSearchParameters, - ConnectedRealmSearchResponseItem, + ConnectedRealmSearchResponse, } from './types'; /** @@ -19,7 +19,7 @@ export function connectedRealm( ): Resource { return { namespace, - path: `${base}/connected-realm/${connectedRealmId}`, + path: `${wowBasePath}/connected-realm/${connectedRealmId}`, }; } /** @@ -32,19 +32,19 @@ export function connectedRealmIndex( ): Resource { return { namespace, - path: `${base}/connected-realm/index`, + path: `${wowBasePath}/connected-realm/index`, }; } /** * Performs a search of connected realms. * @param namespace The namespace to use. See {@link BlizzardNamespaces}. * @param options The search parameters. See {@link ConnectedRealmSearchParameters}. - * @returns The search results. See {@link SearchResponse} & {@link ConnectedRealmSearchResponseItem}. + * @returns The search results. See {@link ConnectedRealmSearchResponse}. */ export function connectedRealmSearch( namespace: Extract, options: ConnectedRealmSearchParameters, -): Resource, ConnectedRealmSearchParameters> { +): Resource { return { namespace, parameters: { @@ -53,6 +53,6 @@ export function connectedRealmSearch( 'realms.timezone': options['realms.timezone'], 'status.type': options['status.type'], }, - path: `${base}/search/connected-realm`, + path: `${wowBasePath}/search/connected-realm`, }; } diff --git a/packages/classic-wow/src/connected-realm/types.ts b/packages/classic-wow/src/connected-realm/types.ts index 1c171c9b..f4d2a11b 100644 --- a/packages/classic-wow/src/connected-realm/types.ts +++ b/packages/classic-wow/src/connected-realm/types.ts @@ -1,2 +1,106 @@ -//The classic version of the connected realm types are the same as the retail version. -export type * from '../../../wow/src/connected-realm/types'; +import type { + BaseSearchParameters, + Href, + KeyBase, + Locales, + NameIdKey, + ResponseBase, + SearchResponseWithoutResults, +} from '@blizzard-api/core'; +import type { RealmCategory, RealmLocales, RealmTimezone, RealmTypeCapitalized } from '../realm/types'; + +/** + * Connected Realm Index API response. + * @see https://develop.battle.net/documentation/world-of-warcraft/game-data-apis + */ +export interface ConnectedRealmIndexResponse extends ResponseBase { + connected_realms: Array; +} +/** + * Connected Realm API response. + * @see https://develop.battle.net/documentation/world-of-warcraft/game-data-apis + */ +export interface ConnectedRealmResponse extends ResponseBase { + auctions: Href; + has_queue: boolean; + id: number; + population: { name: string; type: RealmPopulationCapitalized }; + pvp_season?: Href; + realm_locked_status?: RealmLockedStatus; + realms: Array; + status: { name: RealmStatus; type: RealmStatusCapitalized }; +} +/** + * Connected Realm Search API parameters. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/guides/search} + */ +export interface ConnectedRealmSearchParameters extends BaseSearchParameters { + 'realms.timezone'?: RealmTimezone; + 'status.type'?: RealmStatusCapitalized; +} + +/** + * Connected Realm Search API response item. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/guides/search} + */ +export interface ConnectedRealmSearchResponse extends SearchResponseWithoutResults { + results: Array; +} + +interface ConnectedRealmSearchResponseItem extends KeyBase { + data: { + has_queue: boolean; + id: number; + population: SearchRealmPopulation; + realms: Array; + status: SearchRealmStatus; + }; +} + +interface Realm { + category: RealmCategory; + connected_realm: Href; + id: number; + is_tournament: boolean; + locale: RealmLocales; + name: string; + region: NameIdKey; + slug: string; + timezone: RealmTimezone; + type: { name: string; type: RealmTypeCapitalized }; +} + +interface RealmLockedStatus { + is_locked_for_new_characters: boolean; + is_locked_for_pct: boolean; +} + +type RealmPopulationCapitalized = 'FULL' | 'HIGH' | 'LOCKED' | 'LOW' | 'MEDIUM' | 'RECOMMENDED'; + +type RealmStatus = 'Down' | 'Up'; + +type RealmStatusCapitalized = 'DOWN' | 'UP'; + +interface SearchRealm { + category: Record; + id: number; + is_tournament: boolean; + locale: RealmLocales; + name: Record; + region: { id: number; name: Record }; + slug: string; + timezone: RealmTimezone; + type: { name: Record; type: RealmTypeCapitalized }; +} + +interface SearchRealmPopulation { + name: Record; + type: RealmPopulationCapitalized; +} + +interface SearchRealmStatus { + name: Record; + type: RealmStatusCapitalized; +} diff --git a/packages/classic-wow/src/creature/creature.test.ts b/packages/classic-wow/src/creature/creature.test.ts index 339aec72..89d24873 100644 --- a/packages/classic-wow/src/creature/creature.test.ts +++ b/packages/classic-wow/src/creature/creature.test.ts @@ -1,5 +1,5 @@ +import { wowBasePath, wowMediaBasePath, wowSearchBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base, mediaBase, searchBase } from '../../../wow/src/base'; import { creature, creatureDisplayMedia, @@ -22,7 +22,7 @@ describe.concurrent('classicCreatureApi', () => { const resource = creature(namespace, creatureId); expect(resource).toEqual({ namespace, - path: `${base}/creature/123`, + path: `${wowBasePath}/creature/123`, }); }); @@ -30,7 +30,7 @@ describe.concurrent('classicCreatureApi', () => { const resource = creatureDisplayMedia(namespace, creatureDisplayId); expect(resource).toEqual({ namespace, - path: `${mediaBase}/creature-display/456`, + path: `${wowMediaBasePath}/creature-display/456`, }); }); @@ -38,7 +38,7 @@ describe.concurrent('classicCreatureApi', () => { const resource = creatureFamily(namespace, creatureFamilyId); expect(resource).toEqual({ namespace, - path: `${base}/creature-family/789`, + path: `${wowBasePath}/creature-family/789`, }); }); @@ -46,7 +46,7 @@ describe.concurrent('classicCreatureApi', () => { const resource = creatureFamilyIndex(namespace); expect(resource).toEqual({ namespace, - path: `${base}/creature-family/index`, + path: `${wowBasePath}/creature-family/index`, }); }); @@ -54,7 +54,7 @@ describe.concurrent('classicCreatureApi', () => { const resource = creatureFamilyMedia(namespace, creatureFamilyId); expect(resource).toEqual({ namespace, - path: `${mediaBase}/creature-family/789`, + path: `${wowMediaBasePath}/creature-family/789`, }); }); @@ -62,7 +62,7 @@ describe.concurrent('classicCreatureApi', () => { const resource = creatureType(namespace, creatureTypeId); expect(resource).toEqual({ namespace, - path: `${base}/creature-type/987`, + path: `${wowBasePath}/creature-type/987`, }); }); @@ -70,7 +70,7 @@ describe.concurrent('classicCreatureApi', () => { const resource = creatureTypeIndex(namespace); expect(resource).toEqual({ namespace, - path: `${base}/creature-type/index`, + path: `${wowBasePath}/creature-type/index`, }); }); @@ -88,7 +88,7 @@ describe.concurrent('classicCreatureApi', () => { 'name.en_US': 'creatureName', orderby: 'name', }, - path: `${searchBase}/creature`, + path: `${wowSearchBasePath}/creature`, }); }); @@ -106,7 +106,7 @@ describe.concurrent('classicCreatureApi', () => { 'name.en_US': 'creatureName', orderby: 'name,id', }, - path: `${searchBase}/creature`, + path: `${wowSearchBasePath}/creature`, }); }); }); diff --git a/packages/classic-wow/src/creature/creature.ts b/packages/classic-wow/src/creature/creature.ts index ac5b14a5..5b22b27d 100644 --- a/packages/classic-wow/src/creature/creature.ts +++ b/packages/classic-wow/src/creature/creature.ts @@ -1,5 +1,5 @@ -import type { BlizzardNamespaces, Resource, SearchResponse } from '@blizzard-api/core'; -import { base, mediaBase, searchBase } from '../../../wow/src/base'; +import { wowBasePath, wowMediaBasePath, wowSearchBasePath } from '@blizzard-api/core'; +import type { BlizzardNamespaces, Resource } from '@blizzard-api/core'; import type { CreatureDisplayMediaResponse, CreatureFamilyIndexResponse, @@ -7,7 +7,7 @@ import type { CreatureFamilyResponse, CreatureResponse, CreatureSearchParameters, - CreatureSearchResponseItem, + CreatureSearchResponse, CreatureTypeIndexResponse, CreatureTypeResponse, } from './types'; @@ -24,7 +24,7 @@ export function creature( ): Resource { return { namespace, - path: `${base}/creature/${creatureId}`, + path: `${wowBasePath}/creature/${creatureId}`, }; } /** @@ -39,7 +39,7 @@ export function creatureDisplayMedia( ): Resource { return { namespace, - path: `${mediaBase}/creature-display/${creatureDisplayId}`, + path: `${wowMediaBasePath}/creature-display/${creatureDisplayId}`, }; } /** @@ -54,7 +54,7 @@ export function creatureFamily( ): Resource { return { namespace, - path: `${base}/creature-family/${creatureFamilyId}`, + path: `${wowBasePath}/creature-family/${creatureFamilyId}`, }; } /** @@ -67,7 +67,7 @@ export function creatureFamilyIndex( ): Resource { return { namespace, - path: `${base}/creature-family/index`, + path: `${wowBasePath}/creature-family/index`, }; } /** @@ -82,19 +82,19 @@ export function creatureFamilyMedia( ): Resource { return { namespace, - path: `${mediaBase}/creature-family/${creatureFamilyId}`, + path: `${wowMediaBasePath}/creature-family/${creatureFamilyId}`, }; } /** * Performs a search of creatures. * @param namespace The namespace to use. See {@link BlizzardNamespaces}. * @param options The creature search parameters. See {@link CreatureSearchParameters}. - * @returns The creature search results. See {@link SearchResponse} & {@link CreatureSearchResponseItem}. + * @returns The creature search results. See {@link CreatureSearchResponse}. */ export function creatureSearch( namespace: Extract, options: CreatureSearchParameters, -): Resource, Omit> { +): Resource> { return { namespace, parameters: { @@ -102,7 +102,7 @@ export function creatureSearch( [`name.${options.locale}`]: options.name, orderby: Array.isArray(options.orderby) ? options.orderby.join(',') : options.orderby, }, - path: `${searchBase}/creature`, + path: `${wowSearchBasePath}/creature`, }; } /** @@ -117,7 +117,7 @@ export function creatureType( ): Resource { return { namespace, - path: `${base}/creature-type/${creatureTypeId}`, + path: `${wowBasePath}/creature-type/${creatureTypeId}`, }; } /** @@ -130,6 +130,6 @@ export function creatureTypeIndex( ): Resource { return { namespace, - path: `${base}/creature-type/index`, + path: `${wowBasePath}/creature-type/index`, }; } diff --git a/packages/classic-wow/src/creature/types.ts b/packages/classic-wow/src/creature/types.ts index 3d4ac5af..6b223581 100644 --- a/packages/classic-wow/src/creature/types.ts +++ b/packages/classic-wow/src/creature/types.ts @@ -1,2 +1,118 @@ -//The classic version of the creature types are the same as the retail version. -export type * from '../../../wow/src/creature/types'; +import type { + BaseSearchParameters, + KeyBase, + Locales, + MediaAsset, + NameIdKey, + ResponseBase, + SearchResponseWithoutResults, +} from '@blizzard-api/core'; + +/** + * The response for creature display media. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + */ +export interface CreatureDisplayMediaResponse extends ResponseBase { + assets: Array; + id: number; +} + +/** + * The response for a creature family index. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + */ +export interface CreatureFamilyIndexResponse extends ResponseBase { + creature_families: Array; +} + +/** + * The response for creature family media. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + */ +export interface CreatureFamilyMediaResponse extends ResponseBase { + assets: Array; + id: number; +} + +/** + * The response for a creature family. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + */ +export interface CreatureFamilyResponse extends ResponseBase { + id: number; + media?: Media; + name: string; + specialization?: NameIdKey; +} + +/** + * The response for a creature. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + */ +export interface CreatureResponse extends ResponseBase { + creature_displays: Array; + family: NameIdKey; + id: number; + is_tameable: boolean; + name: string; + type: NameIdKey; +} + +/** + * The search parameters for a creature. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/guides/search} + */ +export interface CreatureSearchParameters extends BaseSearchParameters { + locale: Locales; + name: string; +} + +/** + * The response for a creature search. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/guides/search} + */ +export interface CreatureSearchResponse extends SearchResponseWithoutResults { + results: Array; +} +/** + * The response for a creature type index. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + */ +export interface CreatureTypeIndexResponse extends ResponseBase { + creature_types: Array; +} + +/** + * The response for a creature type. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + */ +export interface CreatureTypeResponse extends ResponseBase { + id: number; + name: string; +} + +interface CreatureDisplay extends KeyBase { + id: number; +} + +interface CreatureSearchResponseItem extends KeyBase { + data: { + creature_displays: Array<{ id: number }>; + family?: { id: number; name: Record }; + id: number; + is_tameable: boolean; + name: Record; + type: { id: number; name: Record }; + }; +} + +interface DisplayMediaAsset { + key: string; + value: string; +} + +interface Media extends KeyBase { + id: number; +} diff --git a/packages/classic-wow/src/guild-crest/guild-crest.test.ts b/packages/classic-wow/src/guild-crest/guild-crest.test.ts index 0e8223ba..25d2d415 100644 --- a/packages/classic-wow/src/guild-crest/guild-crest.test.ts +++ b/packages/classic-wow/src/guild-crest/guild-crest.test.ts @@ -1,26 +1,26 @@ +import { wowBasePath, wowMediaBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base, mediaBase } from '../../../wow/src/base'; import { guildCrestBorder, guildCrestComponentsIndex, guildCrestEmblem } from './guild-crest'; const namespace = 'static-classic'; describe.concurrent('classicGuildCrestApi', () => { it('should return the guild crest components index resource', ({ expect }) => { const resource = guildCrestComponentsIndex(namespace); - expect(resource.path).toBe(`${base}/guild-crest/index`); + expect(resource.path).toBe(`${wowBasePath}/guild-crest/index`); expect(resource.namespace).toBe(namespace); }); it('should return the guild crest border resource for a given borderId', ({ expect }) => { const borderId = 123; const resource = guildCrestBorder(namespace, borderId); - expect(resource.path).toBe(`${mediaBase}/guild-crest/border/123`); + expect(resource.path).toBe(`${wowMediaBasePath}/guild-crest/border/123`); expect(resource.namespace).toBe(namespace); }); it('should return the guild crest emblem resource for a given emblemId', ({ expect }) => { const emblemId = 456; const resource = guildCrestEmblem(namespace, emblemId); - expect(resource.path).toBe(`${mediaBase}/guild-crest/emblem/456`); + expect(resource.path).toBe(`${wowMediaBasePath}/guild-crest/emblem/456`); expect(resource.namespace).toBe(namespace); }); }); diff --git a/packages/classic-wow/src/guild-crest/guild-crest.ts b/packages/classic-wow/src/guild-crest/guild-crest.ts index 7c259a76..8b2e2661 100644 --- a/packages/classic-wow/src/guild-crest/guild-crest.ts +++ b/packages/classic-wow/src/guild-crest/guild-crest.ts @@ -1,5 +1,5 @@ import type { BlizzardNamespaces, Resource } from '@blizzard-api/core'; -import { base, mediaBase } from '../../../wow/src/base'; +import { wowBasePath, wowMediaBasePath } from '@blizzard-api/core'; import type { GuildCrestBorderEmblemResponse, GuildCrestComponentsIndexResponse } from './types'; /** @@ -14,7 +14,7 @@ export function guildCrestBorder( ): Resource { return { namespace, - path: `${mediaBase}/guild-crest/border/${borderId}`, + path: `${wowMediaBasePath}/guild-crest/border/${borderId}`, }; } /** @@ -27,7 +27,7 @@ export function guildCrestComponentsIndex( ): Resource { return { namespace, - path: `${base}/guild-crest/index`, + path: `${wowBasePath}/guild-crest/index`, }; } /** @@ -42,6 +42,6 @@ export function guildCrestEmblem( ): Resource { return { namespace, - path: `${mediaBase}/guild-crest/emblem/${emblemId}`, + path: `${wowMediaBasePath}/guild-crest/emblem/${emblemId}`, }; } diff --git a/packages/classic-wow/src/guild-crest/types.ts b/packages/classic-wow/src/guild-crest/types.ts index 934a3f35..227598d7 100644 --- a/packages/classic-wow/src/guild-crest/types.ts +++ b/packages/classic-wow/src/guild-crest/types.ts @@ -1 +1,44 @@ -export type * from '../../../wow/src/guild-crest/types'; +import type { Color, KeyBase, ResponseBase } from '@blizzard-api/core'; + +/** + * The response for a guild crest border or emblem. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + */ +export interface GuildCrestBorderEmblemResponse extends ResponseBase { + assets: Array; + id: number; +} + +/** + * The response for the guild crest components index. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + */ +export interface GuildCrestComponentsIndexResponse extends ResponseBase { + borders: Array; + colors: Colors; + emblems: Array; +} + +interface Background { + id: number; + rgba: Color; +} + +interface Border { + id: number; + media: Media; +} + +interface Colors { + backgrounds?: Array; + borders?: Array; + emblems?: Array; +} + +interface GuildCrestAsset { + key: string; + value: string; +} +interface Media extends KeyBase { + id: number; +} diff --git a/packages/classic-wow/src/guild/types.ts b/packages/classic-wow/src/guild/types.ts index 37ce6e03..f01bb821 100644 --- a/packages/classic-wow/src/guild/types.ts +++ b/packages/classic-wow/src/guild/types.ts @@ -1,34 +1,91 @@ -import type { Character, Faction, KeyBase, NameIdKey, Realm, ResponseBase } from '../../../wow/src/base'; -import type { GuildResponse as GuildRetailResponse } from '../../../wow/src/guild/types'; -export type { GuildAchievementsResponse } from '../../../wow/src/guild/types'; +import type { Character, Color, Faction, Href, KeyBase, NameIdKey, Realm, ResponseBase } from '@blizzard-api/core'; export interface GuildAchievementsClassicEraResponse extends ResponseBase { guild: Guild; } +export interface GuildAchievementsResponse extends ResponseBase { + achievements: Array; + category_progress: Array; + guild: Guild; + recent_events: Array; + total_points: number; + total_quantity: number; +} + export interface GuildActivityResponse extends ResponseBase { activities?: Array; guild: Guild; } - -export type GuildResponse = Omit & { crest?: GuildRetailResponse['crest'] }; +export interface GuildResponse extends ResponseBase { + achievement_points: number; + achievements: Href; + activity: Href; + created_timestamp: number; + crest?: Crest; + faction: Faction; + id: number; + member_count: number; + name: string; + name_search: string; + realm: Realm; + roster: Href; +} export interface GuildRosterResponse extends ResponseBase { guild: Guild; members: Array; } +interface Achievement { + achievement: NameIdKey; + completed_timestamp?: number; + criteria?: Criteria; + id: number; +} + interface ActivityElement { activity: { type: string }; character_achievement: CharacterAchievement; timestamp: number; } +interface Border { + color: RgbWithId; + id: number; + media: KeyBase & { id: number }; +} + +interface CategoryProgress { + category: NameIdKey; + points: number; + quantity: number; +} + interface CharacterAchievement { achievement: NameIdKey; character: Character; } +interface ChildCriterum { + amount: number; + id: number; + is_completed: boolean; +} + +interface Crest { + background: { color: RgbWithId }; + border: Border; + emblem: Border; +} + +interface Criteria { + amount?: number; + child_criteria?: Array; + id: number; + is_completed: boolean; +} + interface Guild extends NameIdKey { faction: Faction; realm: Realm; @@ -43,6 +100,16 @@ interface Playable extends KeyBase { id: number; } +interface RecentEvent { + achievement: NameIdKey; + timestamp: number; +} + +interface RgbWithId { + id: number; + rgba: Color; +} + interface RosterMemberCharacter extends Character { level: number; playable_class: Playable; diff --git a/packages/classic-wow/src/item/item.test.ts b/packages/classic-wow/src/item/item.test.ts index 6cdde191..a9fdc995 100644 --- a/packages/classic-wow/src/item/item.test.ts +++ b/packages/classic-wow/src/item/item.test.ts @@ -1,5 +1,5 @@ +import { wowBasePath, wowMediaBasePath, wowSearchBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base, mediaBase, searchBase } from '../../../wow/src/base'; import { item, itemClass, itemClassIndex, itemMedia, itemSearch, itemSubClass } from './item'; import type { ItemSearchParameters } from './types'; @@ -8,14 +8,14 @@ const namespace = 'static-classic'; describe.concurrent('classicItemApi', () => { it('should return the item class index resource', ({ expect }) => { const resource = itemClassIndex(namespace); - expect(resource.path).toBe(`${base}/item-class/index`); + expect(resource.path).toBe(`${wowBasePath}/item-class/index`); expect(resource.namespace).toBe(namespace); }); it('should return the item class resource for a given itemClassId', ({ expect }) => { const itemClassId = 123; const resource = itemClass(namespace, itemClassId); - expect(resource.path).toBe(`${base}/item-class/${itemClassId}`); + expect(resource.path).toBe(`${wowBasePath}/item-class/${itemClassId}`); expect(resource.namespace).toBe(namespace); }); @@ -23,21 +23,21 @@ describe.concurrent('classicItemApi', () => { const itemClassId = 123; const itemSubClassId = 456; const resource = itemSubClass(namespace, itemClassId, itemSubClassId); - expect(resource.path).toBe(`${base}/item-class/${itemClassId}/item-subclass/${itemSubClassId}`); + expect(resource.path).toBe(`${wowBasePath}/item-class/${itemClassId}/item-subclass/${itemSubClassId}`); expect(resource.namespace).toBe(namespace); }); it('should return the item resource for a given itemId', ({ expect }) => { const itemId = 123; const resource = item(namespace, itemId); - expect(resource.path).toBe(`${base}/item/${itemId}`); + expect(resource.path).toBe(`${wowBasePath}/item/${itemId}`); expect(resource.namespace).toBe(namespace); }); it('should return the item media resource for a given itemId', ({ expect }) => { const itemId = 123; const resource = itemMedia(namespace, itemId); - expect(resource.path).toBe(`${mediaBase}/item/${itemId}`); + expect(resource.path).toBe(`${wowMediaBasePath}/item/${itemId}`); expect(resource.namespace).toBe(namespace); }); @@ -49,7 +49,7 @@ describe.concurrent('classicItemApi', () => { orderby: 'name', } satisfies ItemSearchParameters; const resource = itemSearch(namespace, options); - expect(resource.path).toBe(`${searchBase}/item`); + expect(resource.path).toBe(`${wowSearchBasePath}/item`); expect(resource.namespace).toBe(namespace); expect(resource.parameters).toEqual({ _page: 1, @@ -66,7 +66,7 @@ describe.concurrent('classicItemApi', () => { orderby: ['name', 'id'], } satisfies ItemSearchParameters; const resource = itemSearch(namespace, options); - expect(resource.path).toBe(`${searchBase}/item`); + expect(resource.path).toBe(`${wowSearchBasePath}/item`); expect(resource.namespace).toBe(namespace); expect(resource.parameters).toEqual({ _page: 1, diff --git a/packages/classic-wow/src/item/item.ts b/packages/classic-wow/src/item/item.ts index 13051151..6ef77498 100644 --- a/packages/classic-wow/src/item/item.ts +++ b/packages/classic-wow/src/item/item.ts @@ -1,12 +1,12 @@ -import type { BlizzardNamespaces, Resource, SearchResponse } from '@blizzard-api/core'; -import { base, mediaBase, searchBase } from '../../../wow/src/base'; +import { wowBasePath, wowMediaBasePath, wowSearchBasePath } from '@blizzard-api/core'; +import type { BlizzardNamespaces, Resource } from '@blizzard-api/core'; import type { ItemClassIndexResponse, ItemClassResponse, ItemMediaResponse, ItemResponse, ItemSearchParameters, - ItemSearchResponseItem, + ItemSearchResponse, ItemSubClassResponse, } from './types'; @@ -22,7 +22,7 @@ export function item( ): Resource { return { namespace, - path: `${base}/item/${itemId}`, + path: `${wowBasePath}/item/${itemId}`, }; } /** @@ -37,7 +37,7 @@ export function itemClass( ): Resource { return { namespace, - path: `${base}/item-class/${itemClassId}`, + path: `${wowBasePath}/item-class/${itemClassId}`, }; } /** @@ -50,7 +50,7 @@ export function itemClassIndex( ): Resource { return { namespace, - path: `${base}/item-class/index`, + path: `${wowBasePath}/item-class/index`, }; } /** @@ -65,19 +65,19 @@ export function itemMedia( ): Resource { return { namespace, - path: `${mediaBase}/item/${itemId}`, + path: `${wowMediaBasePath}/item/${itemId}`, }; } /** * Search for items. * @param namespace The namespace to use. See {@link BlizzardNamespaces}. * @param options The search parameters. See {@link ItemSearchParameters}. - * @returns The search results. See {@link SearchResponse}. + * @returns The search results. See {@link ItemSearchResponse}. */ export function itemSearch( namespace: Extract, options: ItemSearchParameters, -): Resource, Omit> { +): Resource> { return { namespace, parameters: { @@ -85,7 +85,7 @@ export function itemSearch( [`name.${options.locale}`]: options.name, orderby: Array.isArray(options.orderby) ? options.orderby.join(',') : options.orderby, }, - path: `${searchBase}/item`, + path: `${wowSearchBasePath}/item`, }; } /** @@ -102,6 +102,6 @@ export function itemSubClass( ): Resource { return { namespace, - path: `${base}/item-class/${itemClassId}/item-subclass/${itemSubclassId}`, + path: `${wowBasePath}/item-class/${itemClassId}/item-subclass/${itemSubclassId}`, }; } diff --git a/packages/classic-wow/src/item/types.ts b/packages/classic-wow/src/item/types.ts index f96783c6..b5e324fc 100644 --- a/packages/classic-wow/src/item/types.ts +++ b/packages/classic-wow/src/item/types.ts @@ -1,9 +1,276 @@ -export type { - ItemClassIndexResponse, - ItemClassResponse, - ItemMediaResponse, - ItemResponse, - ItemSearchParameters, - ItemSearchResponseItem, - ItemSubClassResponse, -} from '../../../wow/src/item/types.ts'; +import type { + BaseSearchParameters, + Color, + KeyBase, + Locales, + MediaAsset, + NameId, + NameIdKey, + ResponseBase, + SearchResponseWithoutResults, +} from '@blizzard-api/core'; + +/** + * The response for an item class index. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + */ +export interface ItemClassIndexResponse extends ResponseBase { + item_classes: Array; +} + +/** + * The response for an item class. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + */ +export interface ItemClassResponse extends ResponseBase { + class_id: number; + item_subclasses: Array; + name: string; +} + +/** + * The response for an item media. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + */ +export interface ItemMediaResponse extends ResponseBase { + assets: Array; + id: number; +} +/** + * The response for an item. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + */ +export interface ItemResponse extends NameId, ResponseBase { + description?: string; + inventory_type: InventoryType; + is_equippable: boolean; + is_stackable: boolean; + item_class: NameIdKey; + item_subclass: NameIdKey; + level: number; + max_count: number; + media: Media; + preview_item: PreviewItem; + purchase_price: number; + purchase_quantity: number; + quality: ItemQuality; + required_level: number; + sell_price: number; +} + +/** + * The parameters for an item search. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/guides/search} + */ +export interface ItemSearchParameters extends BaseSearchParameters { + locale: Locales; + name: string; +} + +/** + * The response for an item search. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/guides/search} + */ +export interface ItemSearchResponse extends SearchResponseWithoutResults { + results: Array; +} +/** + * The response for an item subclass. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + */ +export interface ItemSubClassResponse extends ResponseBase { + class_id: number; + display_name: string; + hide_subclass_in_tooltips: boolean; + subclass_id: number; + verbose_name: string; +} + +interface Armor { + display: Display; + value: number; +} + +interface Damage { + damage_class: { + name: string; + type: string; + }; + display_string: string; + max_value: number; + min_value: number; +} + +interface Display { + color: Color; + display_string: string; +} + +interface Durability { + display_string: string; + value: number; +} + +interface InventoryType { + name: Record; + type: //Armor + | 'BACK' + | 'BAG' + | 'CHEST' + | 'FEET' + | 'FINGER' + | 'HANDS' + | 'HEAD' + | 'LEGS' + | 'NECK' + | 'NON_EQUIP' + | 'SHIRT' + | 'SHOULDER' + | 'TABARD' + | 'TRINKET' + //Weapons + | 'TWOHWEAPON' + //Misc + | 'WAIST' + | 'WRIST'; +} + +interface ItemQuality { + name: Record; + type: 'ARTIFACT' | 'COMMON' | 'EPIC' | 'HEIRLOOM' | 'LEGENDARY' | 'POOR' | 'RARE' | 'UNCOMMON'; +} + +interface ItemSearchResponseItem extends KeyBase { + data: { + id: number; + inventory_type: InventoryType; + is_equippable: boolean; + is_stackable: boolean; + item_class: { id: number; name: Record }; + item_subclass: { id: number; name: Record }; + level: number; + max_count: number; + media: { id: number }; + name: Record; + purchase_price: number; + purchase_quantity: number; + quality: ItemQuality; + required_level: number; + sell_price: number; + }; +} + +interface Media extends KeyBase { + id: number; +} + +interface PreviewItem { + armor?: Armor; + binding?: { + name: string; + type: string; + }; + bonus_list?: Array; + container_slots?: Durability; + context?: number; + crafting_reagent?: string; + description?: string; + durability?: Durability; + inventory_type: InventoryType; + is_subclass_hidden?: boolean; + item: Media; + item_class: NameIdKey; + item_subclass: NameIdKey; + level?: Durability; + media: Media; + name: string; + quality: ItemQuality; + recipe?: Recipe; + requirements?: Requirements; + sell_price?: number; + shield_block?: Armor; + spells?: Array; + stats?: Array; + unique_equipped?: 'Unique'; + weapon?: Weapon; +} + +interface Recipe { + item: RecipeItem; + reagents: Array; + reagents_display_string: string; +} + +interface RecipeItem { + armor?: Armor; + binding: { + name: string; + type: string; + }; + durability: Durability; + inventory_type: InventoryType; + item: Media; + item_class: NameIdKey; + item_subclass: NameIdKey; + level: Durability; + media: Media; + name: string; + quality: ItemQuality; + requirements: Requirements; + sell_price: { display_strings: RecipeItemDisplayStrings; value: number }; + stats: Array; + weapon?: Weapon; +} + +interface RecipeItemDisplayStrings { + copper: string; + gold: string; + header: string; + silver: string; +} + +interface Requirements { + level: Durability; +} + +interface Spell { + description: string; + spell: NameIdKey; +} +interface Stat { + display: Display; + is_negated?: boolean; + type: { + name: StatType; + type: StatTypeCapitalized; + }; + value: number; +} + +type StatType = + | 'Agility' + | 'Critical Strike' + | 'Haste' + | 'Intellect' + | 'Mastery' + | 'Stamina' + | 'Strength' + | 'Versatility'; + +type StatTypeCapitalized = + | 'AGILITY' + | 'CRIT_RATING' + | 'HASTE_RATING' + | 'INTELLECT' + | 'MASTERY' + | 'STAMINA' + | 'STRENGTH' + | 'VERSATILITY'; + +interface Weapon { + attack_speed: Durability; + damage: Damage; + dps: Durability; +} diff --git a/packages/classic-wow/src/media-search/media-search.test.ts b/packages/classic-wow/src/media-search/media-search.test.ts index 38e51c08..e87d4c87 100644 --- a/packages/classic-wow/src/media-search/media-search.test.ts +++ b/packages/classic-wow/src/media-search/media-search.test.ts @@ -1,5 +1,5 @@ +import { wowSearchBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { searchBase } from '../../../wow/src/base'; import { mediaSearch } from './media-search'; const namespace = 'static-classic'; @@ -7,7 +7,7 @@ const namespace = 'static-classic'; describe.concurrent('mediaSearchApi', () => { it('should return the media search resource', ({ expect }) => { const resource = mediaSearch(namespace, {}); - expect(resource.path).toBe(`${searchBase}/media`); + expect(resource.path).toBe(`${wowSearchBasePath}/media`); expect(resource.namespace).toBe(namespace); expect(resource.parameters).toEqual({}); }); @@ -18,7 +18,7 @@ describe.concurrent('mediaSearchApi', () => { orderby: 'name', tags: 'tag', }); - expect(resource.path).toBe(`${searchBase}/media`); + expect(resource.path).toBe(`${wowSearchBasePath}/media`); expect(resource.namespace).toBe(namespace); expect(resource.parameters).toEqual({ _page: 1, @@ -33,7 +33,7 @@ describe.concurrent('mediaSearchApi', () => { orderby: ['name', 'id'], tags: 'tag', }); - expect(resource.path).toBe(`${searchBase}/media`); + expect(resource.path).toBe(`${wowSearchBasePath}/media`); expect(resource.namespace).toBe(namespace); expect(resource.parameters).toEqual({ _page: 1, diff --git a/packages/classic-wow/src/media-search/media-search.ts b/packages/classic-wow/src/media-search/media-search.ts index c1205fa7..b8423b11 100644 --- a/packages/classic-wow/src/media-search/media-search.ts +++ b/packages/classic-wow/src/media-search/media-search.ts @@ -1,17 +1,17 @@ -import type { BlizzardNamespaces, Resource, SearchResponse } from '@blizzard-api/core'; -import { searchBase } from '../../../wow/src/base'; -import type { MediaSearchParameters, MediaSearchResponseItem } from './types'; +import { wowSearchBasePath } from '@blizzard-api/core'; +import type { BlizzardNamespaces, Resource } from '@blizzard-api/core'; +import type { MediaSearchParameters, MediaSearchResponse } from './types'; /** * Search for media. * @param namespace The namespace to use. See {@link BlizzardNamespaces}. * @param options The search parameters. See {@link MediaSearchParameters}. - * @returns The search results. See {@link SearchResponse}. + * @returns The search results. See {@link MediaSearchResponse}. */ export function mediaSearch( namespace: Extract, options: MediaSearchParameters, -): Resource, MediaSearchParameters> { +): Resource { return { namespace, parameters: { @@ -19,6 +19,6 @@ export function mediaSearch( orderby: Array.isArray(options.orderby) ? options.orderby.join(',') : options.orderby, tags: options.tags, }, - path: `${searchBase}/media`, + path: `${wowSearchBasePath}/media`, }; } diff --git a/packages/classic-wow/src/media-search/types.ts b/packages/classic-wow/src/media-search/types.ts index b2f94df0..8e9a0f3c 100644 --- a/packages/classic-wow/src/media-search/types.ts +++ b/packages/classic-wow/src/media-search/types.ts @@ -1 +1,25 @@ -export type * from '../../../wow/src/media-search/types'; +import type { BaseSearchParameters, KeyBase, MediaAsset, SearchResponseWithoutResults } from '@blizzard-api/core'; + +/** + * The search parameters for media. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/guides/search} + */ +export interface MediaSearchParameters extends BaseSearchParameters { + tags?: string; +} + +/** + * The response for a media search. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/guides/search} + */ +export interface MediaSearchResponse extends SearchResponseWithoutResults { + results: Array; +} +interface MediaSearchResponseItem extends KeyBase { + data: { + assets: Array; + id: number; + }; +} diff --git a/packages/classic-wow/src/playable-class/playable-class.test.ts b/packages/classic-wow/src/playable-class/playable-class.test.ts index 2e960b2b..5d188e12 100644 --- a/packages/classic-wow/src/playable-class/playable-class.test.ts +++ b/packages/classic-wow/src/playable-class/playable-class.test.ts @@ -1,5 +1,5 @@ +import { wowBasePath, wowMediaBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base, mediaBase } from '../../../wow/src/base'; import { playableClass, playableClassIndex, playableClassMedia } from './playable-class'; const namespace = 'static-classic'; @@ -11,14 +11,14 @@ describe.concurrent('classicPlayableClassApi', () => { const resource = playableClass(namespace, playableClassId); expect(resource.namespace).toBe(namespace); - expect(resource.path).toBe(`${base}/playable-class/1`); + expect(resource.path).toBe(`${wowBasePath}/playable-class/1`); }); it('should return a playable class index resource', ({ expect }) => { const resource = playableClassIndex(namespace); expect(resource.namespace).toBe(namespace); - expect(resource.path).toBe(`${base}/playable-class/index`); + expect(resource.path).toBe(`${wowBasePath}/playable-class/index`); }); it('should return a playable class media resource', ({ expect }) => { @@ -27,6 +27,6 @@ describe.concurrent('classicPlayableClassApi', () => { const resource = playableClassMedia(namespace, playableClassId); expect(resource.namespace).toBe(namespace); - expect(resource.path).toBe(`${mediaBase}/playable-class/1`); + expect(resource.path).toBe(`${wowMediaBasePath}/playable-class/1`); }); }); diff --git a/packages/classic-wow/src/playable-class/playable-class.ts b/packages/classic-wow/src/playable-class/playable-class.ts index 73b79932..9861dc0b 100644 --- a/packages/classic-wow/src/playable-class/playable-class.ts +++ b/packages/classic-wow/src/playable-class/playable-class.ts @@ -1,5 +1,5 @@ +import { wowBasePath, wowMediaBasePath } from '@blizzard-api/core'; import type { BlizzardNamespaces, Resource } from '@blizzard-api/core'; -import { base, mediaBase } from '../../../wow/src/base'; import type { PlayableClassIndexResponse, PlayableClassMediaResponse, PlayableClassResponse } from './types'; /** @@ -14,7 +14,7 @@ export function playableClass( ): Resource { return { namespace, - path: `${base}/playable-class/${playableClassId}`, + path: `${wowBasePath}/playable-class/${playableClassId}`, }; } /** @@ -27,7 +27,7 @@ export function playableClassIndex( ): Resource { return { namespace, - path: `${base}/playable-class/index`, + path: `${wowBasePath}/playable-class/index`, }; } /** @@ -42,6 +42,6 @@ export function playableClassMedia( ): Resource { return { namespace, - path: `${mediaBase}/playable-class/${playableClassId}`, + path: `${wowMediaBasePath}/playable-class/${playableClassId}`, }; } diff --git a/packages/classic-wow/src/playable-class/types.ts b/packages/classic-wow/src/playable-class/types.ts index 5dc38bb0..f719fba9 100644 --- a/packages/classic-wow/src/playable-class/types.ts +++ b/packages/classic-wow/src/playable-class/types.ts @@ -1,17 +1,34 @@ -import type { GenderName, KeyBase, NameId, NameIdKey, ResponseBase } from '../../../wow/src/base'; +import type { GenderName, Href, KeyBase, MediaAsset, NameId, NameIdKey, ResponseBase } from '@blizzard-api/core'; -export type { PlayableClassIndexResponse, PlayableClassMediaResponse } from '../../../wow/src/playable-class/types'; +/** + * The response for a playable class index. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + */ +export interface PlayableClassIndexResponse extends ResponseBase { + classes: Array; +} + +/** + * The response for playable class media. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + */ +export interface PlayableClassMediaResponse extends ResponseBase { + assets: Array; + id: number; +} /** * The response for a playable class. * @see {@link https://develop.battle.net/documentation/world-of-warcraft-classic/game-data-apis} */ export interface PlayableClassResponse extends NameId, ResponseBase { + additional_power_types?: Array; gender_name: GenderName; media: Media; playable_races: Array; power_type: NameIdKey; - pvp_talent_slots: { href: string }; + pvp_talent_slots: Href; + specializations?: Array; } interface Media extends KeyBase { diff --git a/packages/classic-wow/src/playable-race/playable-race.test.ts b/packages/classic-wow/src/playable-race/playable-race.test.ts index ddac8cd5..2e43ed29 100644 --- a/packages/classic-wow/src/playable-race/playable-race.test.ts +++ b/packages/classic-wow/src/playable-race/playable-race.test.ts @@ -1,6 +1,6 @@ +import { wowBasePath } from '@blizzard-api/core'; import type { BlizzardNamespaces } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base } from '../../../wow/src/base'; import { playableRace, playableRaceIndex } from './playable-race'; const namespace: BlizzardNamespaces = 'static-classic1x'; @@ -9,14 +9,14 @@ describe.concurrent('playableRaceApi', () => { const playableRaceId = 456; const resource = playableRace(namespace, playableRaceId); - expect(resource.path).toBe(`${base}/playable-race/${playableRaceId}`); + expect(resource.path).toBe(`${wowBasePath}/playable-race/${playableRaceId}`); expect(resource.namespace).toBe(namespace); }); it('playableRaceIndex should return a resource object with the correct path and namespace', ({ expect }) => { const resource = playableRaceIndex(namespace); - expect(resource.path).toBe(`${base}/playable-race/index`); + expect(resource.path).toBe(`${wowBasePath}/playable-race/index`); expect(resource.namespace).toBe(namespace); }); }); diff --git a/packages/classic-wow/src/playable-race/playable-race.ts b/packages/classic-wow/src/playable-race/playable-race.ts index 251dea0a..a38af5f2 100644 --- a/packages/classic-wow/src/playable-race/playable-race.ts +++ b/packages/classic-wow/src/playable-race/playable-race.ts @@ -1,5 +1,5 @@ +import { wowBasePath } from '@blizzard-api/core'; import type { BlizzardNamespaces, Resource } from '@blizzard-api/core'; -import { base } from '../../../wow/src/base'; import type { PlayableRaceIndexResponse, PlayableRaceResponse } from './types'; /** @@ -14,7 +14,7 @@ export function playableRace( ): Resource { return { namespace, - path: `${base}/playable-race/${playableRaceId}`, + path: `${wowBasePath}/playable-race/${playableRaceId}`, }; } /** @@ -27,6 +27,6 @@ export function playableRaceIndex( ): Resource { return { namespace, - path: `${base}/playable-race/index`, + path: `${wowBasePath}/playable-race/index`, }; } diff --git a/packages/classic-wow/src/playable-race/types.ts b/packages/classic-wow/src/playable-race/types.ts index 14af7f6c..0d7bd8ca 100644 --- a/packages/classic-wow/src/playable-race/types.ts +++ b/packages/classic-wow/src/playable-race/types.ts @@ -1 +1,22 @@ -export type * from '../../../wow/src/playable-race/types'; +import type { Faction, GenderName, NameId, NameIdKey, ResponseBase } from '@blizzard-api/core'; + +/** + * The playable race index response. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + */ +export interface PlayableRaceIndexResponse extends ResponseBase { + races: Array; +} + +/** + * The playable race response. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + */ +export interface PlayableRaceResponse extends NameId, ResponseBase { + faction: Faction; + gender_name: GenderName; + is_allied_race: boolean; + is_selectable: boolean; + playable_classes: Array; + racial_spells: Array; +} diff --git a/packages/classic-wow/src/power-type/power-type.test.ts b/packages/classic-wow/src/power-type/power-type.test.ts index 3614d29d..94473acd 100644 --- a/packages/classic-wow/src/power-type/power-type.test.ts +++ b/packages/classic-wow/src/power-type/power-type.test.ts @@ -1,6 +1,6 @@ +import { wowBasePath } from '@blizzard-api/core'; import type { BlizzardNamespaces } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base } from '../../../wow/src/base'; import { powerType, powerTypeIndex } from './power-type'; const namespace: BlizzardNamespaces = 'static-classic1x'; @@ -10,14 +10,14 @@ describe.concurrent('powerTypeApi', () => { const powerTypeId = 123; const resource = powerType(namespace, powerTypeId); - expect(resource.path).toBe(`${base}/power-type/${powerTypeId}`); + expect(resource.path).toBe(`${wowBasePath}/power-type/${powerTypeId}`); expect(resource.namespace).toBe(namespace); }); it('powerTypeIndex should return a resource object with the correct path and namespace', ({ expect }) => { const resource = powerTypeIndex(namespace); - expect(resource.path).toBe(`${base}/power-type/index`); + expect(resource.path).toBe(`${wowBasePath}/power-type/index`); expect(resource.namespace).toBe(namespace); }); }); diff --git a/packages/classic-wow/src/power-type/power-type.ts b/packages/classic-wow/src/power-type/power-type.ts index 5a162db3..b36e9ed0 100644 --- a/packages/classic-wow/src/power-type/power-type.ts +++ b/packages/classic-wow/src/power-type/power-type.ts @@ -1,5 +1,5 @@ +import { wowBasePath } from '@blizzard-api/core'; import type { BlizzardNamespaces, Resource } from '@blizzard-api/core'; -import { base } from '../../../wow/src/base'; import type { PowerTypeIndexResponse, PowerTypeResponse } from './types'; /** @@ -14,7 +14,7 @@ export function powerType( ): Resource { return { namespace, - path: `${base}/power-type/${powerTypeId}`, + path: `${wowBasePath}/power-type/${powerTypeId}`, }; } /** @@ -27,6 +27,6 @@ export function powerTypeIndex( ): Resource { return { namespace, - path: `${base}/power-type/index`, + path: `${wowBasePath}/power-type/index`, }; } diff --git a/packages/classic-wow/src/power-type/types.ts b/packages/classic-wow/src/power-type/types.ts index bc627af7..ea0197ed 100644 --- a/packages/classic-wow/src/power-type/types.ts +++ b/packages/classic-wow/src/power-type/types.ts @@ -1 +1,15 @@ -export type * from '../../../wow/src/power-type/types'; +import type { NameId, NameIdKey, ResponseBase } from '@blizzard-api/core'; + +/** + * The response for a power type index. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + */ +export interface PowerTypeIndexResponse extends ResponseBase { + power_types: Array; +} + +/** + * The response for a power type. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + */ +export interface PowerTypeResponse extends NameId, ResponseBase {} diff --git a/packages/classic-wow/src/pvp-season/pvp-season.test.ts b/packages/classic-wow/src/pvp-season/pvp-season.test.ts index 5c433f69..b39c2029 100644 --- a/packages/classic-wow/src/pvp-season/pvp-season.test.ts +++ b/packages/classic-wow/src/pvp-season/pvp-season.test.ts @@ -1,6 +1,6 @@ +import { wowBasePath } from '@blizzard-api/core'; import type { BlizzardNamespaces } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base } from '../../../wow/src/base'; import { pvpLeaderboard, pvpLeaderboardIndex, @@ -18,27 +18,27 @@ describe('classicPvpSeasonApi', () => { it('should return the PvP season index', ({ expect }) => { const result = pvpSeasonIndex(namespace); expect(result.namespace).toBe(namespace); - expect(result.path).toBe(`${base}/pvp-season/index`); + expect(result.path).toBe(`${wowBasePath}/pvp-season/index`); }); it('should return the PvP season by ID', ({ expect }) => { const pvpSeasonId = 123; const result = pvpSeason(namespace, pvpSeasonId); expect(result.namespace).toBe(namespace); - expect(result.path).toBe(`${base}/pvp-season/${pvpSeasonId}`); + expect(result.path).toBe(`${wowBasePath}/pvp-season/${pvpSeasonId}`); }); it('should return the PvP region index', ({ expect }) => { const result = pvpRegionIndex(namespace); expect(result.namespace).toBe(namespace); - expect(result.path).toBe(`${base}/pvp-region/index`); + expect(result.path).toBe(`${wowBasePath}/pvp-region/index`); }); it('should return the PvP season index in a PvP region', ({ expect }) => { const pvpRegionId = 456; const result = pvpRegionalSeasonIndex(namespace, pvpRegionId); expect(result.namespace).toBe(namespace); - expect(result.path).toBe(`${base}/pvp-region/${pvpRegionId}/pvp-season/index`); + expect(result.path).toBe(`${wowBasePath}/pvp-region/${pvpRegionId}/pvp-season/index`); }); it('should return a PvP season by region ID and season ID', ({ expect }) => { @@ -46,7 +46,7 @@ describe('classicPvpSeasonApi', () => { const pvpSeasonId = 123; const result = pvpRegionalSeason(namespace, pvpRegionId, pvpSeasonId); expect(result.namespace).toBe(namespace); - expect(result.path).toBe(`${base}/pvp-region/${pvpRegionId}/pvp-season/${pvpSeasonId}`); + expect(result.path).toBe(`${wowBasePath}/pvp-region/${pvpRegionId}/pvp-season/${pvpSeasonId}`); }); it('should return the PvP leaderboards for a PvP season in a given PvP region', ({ expect }) => { @@ -54,7 +54,9 @@ describe('classicPvpSeasonApi', () => { const pvpSeasonId = 123; const result = pvpLeaderboardIndex(namespace, pvpRegionId, pvpSeasonId); expect(result.namespace).toBe(namespace); - expect(result.path).toBe(`${base}/pvp-region/${pvpRegionId}/pvp-season/${pvpSeasonId}/pvp-leaderboard/index`); + expect(result.path).toBe( + `${wowBasePath}/pvp-region/${pvpRegionId}/pvp-season/${pvpSeasonId}/pvp-leaderboard/index`, + ); }); it('should return a PvP leaderboard by PvP season ID and bracket', ({ expect }) => { @@ -64,7 +66,7 @@ describe('classicPvpSeasonApi', () => { const result = pvpLeaderboard(namespace, pvpRegionId, pvpSeasonId, pvpBracket); expect(result.namespace).toBe(namespace); expect(result.path).toBe( - `${base}/pvp-region/${pvpRegionId}/pvp-season/${pvpSeasonId}/pvp-leaderboard/${pvpBracket}`, + `${wowBasePath}/pvp-region/${pvpRegionId}/pvp-season/${pvpSeasonId}/pvp-leaderboard/${pvpBracket}`, ); }); @@ -73,6 +75,6 @@ describe('classicPvpSeasonApi', () => { const pvpSeasonId = 123; const result = pvpRewardsIndex(namespace, pvpRegionId, pvpSeasonId); expect(result.namespace).toBe(namespace); - expect(result.path).toBe(`${base}/pvp-region/${pvpRegionId}/pvp-season/${pvpSeasonId}/pvp-reward/index`); + expect(result.path).toBe(`${wowBasePath}/pvp-region/${pvpRegionId}/pvp-season/${pvpSeasonId}/pvp-reward/index`); }); }); diff --git a/packages/classic-wow/src/pvp-season/pvp-season.ts b/packages/classic-wow/src/pvp-season/pvp-season.ts index ee92d1b9..feda78d1 100644 --- a/packages/classic-wow/src/pvp-season/pvp-season.ts +++ b/packages/classic-wow/src/pvp-season/pvp-season.ts @@ -1,5 +1,5 @@ +import { wowBasePath } from '@blizzard-api/core'; import type { BlizzardNamespaces, Resource } from '@blizzard-api/core'; -import { base } from '../../../wow/src/base'; import type { PvpSeasonIndexResponse, PvpSeasonResponse } from './types'; /** @@ -18,7 +18,7 @@ export function pvpLeaderboard( ): Resource { return { namespace, - path: `${base}/pvp-region/${pvpRegionId}/pvp-season/${pvpSeasonId}/pvp-leaderboard/${pvpBracket}`, + path: `${wowBasePath}/pvp-region/${pvpRegionId}/pvp-season/${pvpSeasonId}/pvp-leaderboard/${pvpBracket}`, }; } /** @@ -35,7 +35,7 @@ export function pvpLeaderboardIndex( ): Resource { return { namespace, - path: `${base}/pvp-region/${pvpRegionId}/pvp-season/${pvpSeasonId}/pvp-leaderboard/index`, + path: `${wowBasePath}/pvp-region/${pvpRegionId}/pvp-season/${pvpSeasonId}/pvp-leaderboard/index`, }; } /** @@ -52,7 +52,7 @@ export function pvpRegionalSeason( ): Resource { return { namespace, - path: `${base}/pvp-region/${pvpRegionId}/pvp-season/${pvpSeasonId}`, + path: `${wowBasePath}/pvp-region/${pvpRegionId}/pvp-season/${pvpSeasonId}`, }; } /** @@ -67,7 +67,7 @@ export function pvpRegionalSeasonIndex( ): Resource { return { namespace, - path: `${base}/pvp-region/${pvpRegionId}/pvp-season/index`, + path: `${wowBasePath}/pvp-region/${pvpRegionId}/pvp-season/index`, }; } /** @@ -80,7 +80,7 @@ export function pvpRegionIndex( ): Resource { return { namespace, - path: `${base}/pvp-region/index`, + path: `${wowBasePath}/pvp-region/index`, }; } /** @@ -97,7 +97,7 @@ export function pvpRewardsIndex( ): Resource { return { namespace, - path: `${base}/pvp-region/${pvpRegionId}/pvp-season/${pvpSeasonId}/pvp-reward/index`, + path: `${wowBasePath}/pvp-region/${pvpRegionId}/pvp-season/${pvpSeasonId}/pvp-reward/index`, }; } /** @@ -112,7 +112,7 @@ export function pvpSeason( ): Resource { return { namespace, - path: `${base}/pvp-season/${pvpSeasonId}`, + path: `${wowBasePath}/pvp-season/${pvpSeasonId}`, }; } /** @@ -125,6 +125,6 @@ export function pvpSeasonIndex( ): Resource { return { namespace, - path: `${base}/pvp-season/index`, + path: `${wowBasePath}/pvp-season/index`, }; } diff --git a/packages/classic-wow/src/pvp-season/types.ts b/packages/classic-wow/src/pvp-season/types.ts index 5a831cc5..32c9ce7f 100644 --- a/packages/classic-wow/src/pvp-season/types.ts +++ b/packages/classic-wow/src/pvp-season/types.ts @@ -1 +1,26 @@ -export type { PvpSeasonIndexResponse, PvpSeasonResponse } from '../../../wow/src/pvp-season/types'; +import type { Href, KeyBase, ResponseBase } from '@blizzard-api/core'; + +/** + * The response for a PvP season index. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + */ +export interface PvpSeasonIndexResponse extends ResponseBase { + current_season: Season; + seasons: Array; +} + +/** + * The response for a PvP season. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + */ +export interface PvpSeasonResponse extends ResponseBase { + id: number; + leaderboards: Href; + rewards: Href; + season_name?: string; + season_start_timestamp: number; +} + +interface Season extends KeyBase { + id: number; +} diff --git a/packages/classic-wow/src/realm/realm.test.ts b/packages/classic-wow/src/realm/realm.test.ts index bb88ff48..29b2d1b4 100644 --- a/packages/classic-wow/src/realm/realm.test.ts +++ b/packages/classic-wow/src/realm/realm.test.ts @@ -1,5 +1,5 @@ +import { wowBasePath, wowSearchBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base, searchBase } from '../../../wow/src/base'; import { realm, realmIndex, realmSearch } from './realm'; import type { RealmSearchParameters } from './types'; @@ -13,7 +13,7 @@ describe.concurrent('classicRealmApi', () => { expect(result).toEqual({ namespace, - path: `${base}/realm/test-realm`, + path: `${wowBasePath}/realm/test-realm`, }); }); @@ -22,7 +22,7 @@ describe.concurrent('classicRealmApi', () => { expect(result).toEqual({ namespace, - path: `${base}/realm/index`, + path: `${wowBasePath}/realm/index`, }); }); @@ -42,7 +42,7 @@ describe.concurrent('classicRealmApi', () => { orderby: 'name', timezone: options.timezone, }, - path: `${searchBase}/realm`, + path: `${wowSearchBasePath}/realm`, }); }); @@ -62,7 +62,7 @@ describe.concurrent('classicRealmApi', () => { orderby: 'name,population', timezone: options.timezone, }, - path: `${searchBase}/realm`, + path: `${wowSearchBasePath}/realm`, }); }); }); diff --git a/packages/classic-wow/src/realm/realm.ts b/packages/classic-wow/src/realm/realm.ts index 868cb216..c5faf5e1 100644 --- a/packages/classic-wow/src/realm/realm.ts +++ b/packages/classic-wow/src/realm/realm.ts @@ -1,6 +1,6 @@ -import type { BlizzardNamespaces, Resource, SearchResponse } from '@blizzard-api/core'; -import { base, searchBase } from '../../../wow/src/base'; -import type { RealmIndexResponse, RealmResponse, RealmSearchParameters, RealmSearchResponseItem } from './types'; +import { wowBasePath, wowSearchBasePath } from '@blizzard-api/core'; +import type { BlizzardNamespaces, Resource } from '@blizzard-api/core'; +import type { RealmIndexResponse, RealmResponse, RealmSearchParameters, RealmSearchResponse } from './types'; /** * Get a realm by slug. @@ -14,7 +14,7 @@ export function realm( ): Resource { return { namespace, - path: `${base}/realm/${realmSlug}`, + path: `${wowBasePath}/realm/${realmSlug}`, }; } /** @@ -27,19 +27,19 @@ export function realmIndex( ): Resource { return { namespace, - path: `${base}/realm/index`, + path: `${wowBasePath}/realm/index`, }; } /** * Search for realms. * @param namespace The namespace to use. See {@link BlizzardNamespaces}. * @param options The search parameters. See {@link RealmSearchParameters}. - * @returns The search results. See {@link SearchResponse}. + * @returns The search results. See {@link RealmSearchResponse}. */ export function realmSearch( namespace: Extract, options: RealmSearchParameters, -): Resource, RealmSearchParameters> { +): Resource { return { namespace, parameters: { @@ -47,6 +47,6 @@ export function realmSearch( orderby: Array.isArray(options.orderby) ? options.orderby.join(',') : options.orderby, timezone: options.timezone, }, - path: `${searchBase}/realm`, + path: `${wowSearchBasePath}/realm`, }; } diff --git a/packages/classic-wow/src/realm/types.ts b/packages/classic-wow/src/realm/types.ts index 7b93dfce..1afbbe19 100644 --- a/packages/classic-wow/src/realm/types.ts +++ b/packages/classic-wow/src/realm/types.ts @@ -1 +1,118 @@ -export type * from '../../../wow/src/realm/types'; +import type { + BaseSearchParameters, + Href, + KeyBase, + Locales, + NameId, + NameIdKey, + Realm, + ResponseBase, + SearchResponseWithoutResults, +} from '@blizzard-api/core'; + +/** + * The category of a realm. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + */ +export type RealmCategory = + | 'Brazil' + | 'English' + | 'French' + | 'German' + | 'Italian' + | 'Latin America' + | 'Oceanic' + | 'PS' + | 'Russian' + | 'Spanish' + | 'United States' + | '한국'; + +/** + * The response for a realm index. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + */ +export interface RealmIndexResponse extends ResponseBase { + realms: Array; +} + +export type RealmLocales = + | 'deDE' + | 'enGB' + | 'enUS' + | 'esES' + | 'esMX' + | 'frFR' + | 'itIT' + | 'koKR' + | 'ptBR' + | 'ptPT' + | 'ruRU' + | 'zhCN' + | 'zhTW'; + +/** + * The response for a realm. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + */ +export interface RealmResponse extends NameId, ResponseBase { + category: RealmCategory; + connected_realm: Href; + is_tournament: boolean; + locale: RealmLocales; + region: NameIdKey; + slug: string; + timezone: RealmTimezone; + type: { name: string; type: RealmTypeCapitalized }; +} + +/** + * The search parameters for realms. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/guides/search} + */ +export interface RealmSearchParameters extends BaseSearchParameters { + timezone?: RealmTimezone; +} + +/** + * The response for a realm search. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/guides/search} + */ +export interface RealmSearchResponse extends SearchResponseWithoutResults { + results: Array; +} + +/** + * The timezone of a realm. + */ +export type RealmTimezone = + | 'America/Chicago' + | 'America/Denver' + | 'America/Los_Angeles' + | 'America/New_York' + | 'America/Sao_Paulo' + | 'Asia/Seoul' + | 'Australia/Melbourne' + | 'Europe/Paris'; + +export type RealmTypeCapitalized = 'NORMAL' | 'RP'; + +/** + * The type of a realm, capitalized and shortended). + */ + +interface RealmSearchResponseItem extends KeyBase { + data: { + category: Record; + id: number; + is_tournament: boolean; + locale: RealmLocales; + name: Record; + region: { id: number; name: Record }; + slug: string; + timezone: RealmTimezone; + type: { name: string; type: RealmTypeCapitalized }; + }; +} diff --git a/packages/classic-wow/src/region/region.test.ts b/packages/classic-wow/src/region/region.test.ts index 903b481d..5a6c3555 100644 --- a/packages/classic-wow/src/region/region.test.ts +++ b/packages/classic-wow/src/region/region.test.ts @@ -1,5 +1,5 @@ +import { wowBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base } from '../../../wow/src/base'; import { region, regionIndex } from './region'; describe.concurrent('classicRegionApi', () => { @@ -7,14 +7,14 @@ describe.concurrent('classicRegionApi', () => { const namespace = 'dynamic-classic'; const regionId = 1; const resource = region(namespace, regionId); - expect(resource.path).toBe(`${base}/region/1`); + expect(resource.path).toBe(`${wowBasePath}/region/1`); expect(resource.namespace).toBe(namespace); }); it('should return the region index resource', ({ expect }) => { const namespace = 'dynamic-classic'; const resource = regionIndex(namespace); - expect(resource.path).toBe(`${base}/region/index`); + expect(resource.path).toBe(`${wowBasePath}/region/index`); expect(resource.namespace).toBe(namespace); }); }); diff --git a/packages/classic-wow/src/region/region.ts b/packages/classic-wow/src/region/region.ts index f397bd76..5aee7a40 100644 --- a/packages/classic-wow/src/region/region.ts +++ b/packages/classic-wow/src/region/region.ts @@ -1,5 +1,5 @@ +import { wowBasePath } from '@blizzard-api/core'; import type { BlizzardNamespaces, Resource } from '@blizzard-api/core'; -import { base } from '../../../wow/src/base'; import type { RegionIndexResponse, RegionResponse } from './types'; /** @@ -14,7 +14,7 @@ export function region( ): Resource { return { namespace, - path: `${base}/region/${regionId}`, + path: `${wowBasePath}/region/${regionId}`, }; } /** @@ -27,6 +27,6 @@ export function regionIndex( ): Resource { return { namespace, - path: `${base}/region/index`, + path: `${wowBasePath}/region/index`, }; } diff --git a/packages/classic-wow/src/region/types.ts b/packages/classic-wow/src/region/types.ts index 7d5b6202..51abe9c5 100644 --- a/packages/classic-wow/src/region/types.ts +++ b/packages/classic-wow/src/region/types.ts @@ -1 +1,18 @@ -export type * from '../../../wow/src/region/types'; +import type { Href, NameId, ResponseBase } from '@blizzard-api/core'; + +/** + * The response for a region index. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + */ +export interface RegionIndexResponse extends ResponseBase { + regions: Array; +} + +/** + * The response for a region. + * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} + */ +export interface RegionResponse extends NameId, ResponseBase { + patch_string: string; + tag: string; +} diff --git a/packages/client/package.json b/packages/client/package.json index ee83d5d3..bbf0e1a0 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -7,7 +7,7 @@ "repository": "https://github.com/Pewtro/blizzard-api/tree/main/packages/client", "type": "module", "engines": { - "node": "^18.18 || >=20.9" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "module": "./dist/index.js", "types": "./dist/index.d.ts", @@ -40,7 +40,7 @@ "hearthstone" ], "dependencies": { - "ky": "1.14.0" + "ky": "1.14.3" }, "peerDependencies": { "@blizzard-api/core": "2.1.1" diff --git a/packages/client/src/client/client.ts b/packages/client/src/client/client.ts index bb1170be..b48937c4 100644 --- a/packages/client/src/client/client.ts +++ b/packages/client/src/client/client.ts @@ -5,7 +5,6 @@ import ky from 'ky'; import type { AccessToken, AccessTokenRequestArguments, - AxiosCompatability, ClientOptions, ValidateAccessTokenArguments, ValidateAccessTokenResponse, @@ -59,7 +58,7 @@ export class BlizzardApiClient { * // => 86399 * // => 'client-id' */ - public getAccessToken = async (options?: AccessTokenRequestArguments): Promise> => { + public getAccessToken = async (options?: AccessTokenRequestArguments): Promise => { const { key, origin, secret } = { ...this.defaults, ...options }; const basicAuth = Buffer.from(`${key}:${secret}`).toString('base64'); const response = await this.ky @@ -74,10 +73,7 @@ export class BlizzardApiClient { }) .json(); - return { - data: response, - ...response, - }; + return response; }; /** @@ -101,9 +97,7 @@ export class BlizzardApiClient { * // => 86399 * // => 'client-id' */ - public refreshAccessToken = async ( - options?: AccessTokenRequestArguments, - ): Promise> => { + public refreshAccessToken = async (options?: AccessTokenRequestArguments): Promise => { const response = await this.getAccessToken(options); this.setAccessToken(response.access_token); return response; @@ -118,9 +112,7 @@ export class BlizzardApiClient { * console.log(response.client_id); * // => 'client-id' */ - public validateAccessToken = async ( - options?: ValidateAccessTokenArguments, - ): Promise> => { + public validateAccessToken = async (options?: ValidateAccessTokenArguments): Promise => { const { origin, token } = { ...this.defaults, ...options }; if (!token) { @@ -136,10 +128,7 @@ export class BlizzardApiClient { }) .json(); - return { - data: response, - ...response, - }; + return response; }; /** @@ -220,7 +209,7 @@ export class BlizzardApiClient { resource: Resource, options?: Partial, headers?: Record, - ): ResourceResponse> { + ): ResourceResponse { const url = this.getRequestUrl(resource, options); const config = this.getRequestConfig(resource, options, headers); @@ -234,9 +223,6 @@ export class BlizzardApiClient { }); const data = await response.json(); - return { - data, - ...data, - }; + return data; } } diff --git a/packages/client/src/client/types.ts b/packages/client/src/client/types.ts index 8476daad..99c7f751 100644 --- a/packages/client/src/client/types.ts +++ b/packages/client/src/client/types.ts @@ -36,15 +36,6 @@ export interface AccessTokenRequestArguments { secret?: string; // The client secret. } -export type AxiosCompatability = T & { - /** - * @deprecated - * This property is only here for backward compatibility, it will be removed in the next major version. - * All data should be accessed directly from the response object instead of through this property. - */ - data: T; -}; - /** * A client configuration object. * @example diff --git a/packages/client/src/tests/client.test.ts b/packages/client/src/tests/client.test.ts index 76b8bb8f..61df1c1c 100644 --- a/packages/client/src/tests/client.test.ts +++ b/packages/client/src/tests/client.test.ts @@ -90,7 +90,6 @@ describe.concurrent('client', async () => { expect(config.searchParams.locale).toBeDefined(); }); - // eslint-disable-next-line sonarjs/assertions-in-tests it("validateAccessToken should throw an error if the access token isn't valid", async ({ expect }) => { await expect(() => client.validateAccessToken({ token: undefined })).rejects.toThrow(); }); @@ -105,12 +104,10 @@ describe.concurrent('client', async () => { expect(sub).length.greaterThan(0); }); - // eslint-disable-next-line sonarjs/assertions-in-tests it("the client will throw an error when requesting resources that don't exist", async ({ expect }) => { await expect(() => client.sendRequest(wow.connectedRealm(9_999_999_999))).rejects.toThrow(); }); - // eslint-disable-next-line sonarjs/assertions-in-tests it('the client cannot be created without a client id and secret', async ({ expect }) => { await expect(() => //@ts-expect-error expect error when key is missing diff --git a/packages/core/package.json b/packages/core/package.json index 4a1bb42d..0bd46b4b 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -7,7 +7,7 @@ "repository": "https://github.com/Pewtro/blizzard-api/tree/main/packages/core", "type": "module", "engines": { - "node": "^18.18 || >=20.9" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "module": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/wow/src/base.ts b/packages/core/src/base.ts similarity index 60% rename from packages/wow/src/base.ts rename to packages/core/src/base.ts index f6229405..e84e9d68 100644 --- a/packages/wow/src/base.ts +++ b/packages/core/src/base.ts @@ -1,129 +1,145 @@ -/** - * @file base.ts - * @module base - * @description Contains base constants and interfaces for the Blizzard API. - */ - -/** - * The base request path for the Blizzard API for world of warcraft. - */ -export const base = '/data/wow'; - -/** - * The base request path for media in the Blizzard API for world of warcraft. - */ -export const mediaBase = `${base}/media` as const; - -/** - * The base request path for search in the Blizzard API for world of warcraft. - */ -export const searchBase = `${base}/search` as const; - -/** - * - */ - -/** - * A record containing the RGBA values of a color. - */ -export interface Color { - a: number; - b: number; - g: number; - r: number; -} -/** - * The playable gender names/descriptions in World of Warcraft. - */ -export interface GenderName { - female: string; - male: string; -} - -export interface Href { - href: string; -} - -/** - * Base record interface containing key.href property that often appear in Blizzard API responses. - */ -export interface KeyBase { - key: Href; -} - -/** - * The media asset associated with a character or entity in World of Warcraft. - */ -export interface MediaAsset { - file_data_id: number; - key: string; - value: string; -} - -/** - * Base record interface containing name and id properties that often appear together in Blizzard API responses. - */ -export interface NameId { - id: number; - name: string; -} - -/** - * Base record containing both {@link KeyBase} and {@link NameId} interfaces. - */ -export interface NameIdKey extends KeyBase, NameId {} - -/** - * Base interface for Blizzard API responses. - */ -export interface ResponseBase { - _links: { - self: Href; - }; -} - -/** - * The playable genders in World of Warcraft. - */ -export const Genders = { - FEMALE: 'FEMALE', - MALE: 'MALE', -} as const; - -/** - * The gender associated with a character or entity in World of Warcraft. - */ -export interface Gender { - name: Capitalize>; - type: keyof typeof Genders; -} - -/** - * The playable factions in World of Warcraft. - */ -export const Factions = { - ALLIANCE: 'ALLIANCE', - HORDE: 'HORDE', -} as const; - -/** - * The standard structure to represent a World of Warcraft Character. - */ -export interface Character extends NameIdKey { - realm: Realm; -} - -/** - * The faction associated with a character or entity in World of Warcraft. - */ -export interface Faction { - name: Capitalize>; - type: keyof typeof Factions; -} - -/** - * The standard structure to represent a World of Warcraft Realm. - */ -export interface Realm extends NameIdKey { - slug: string; -} +/** + * The base request path for the D3 API in the Blizzard API. + */ +export const d3BasePath = 'd3/data'; + +/** + * The base request path for profile APIs in the D3 API. + */ +export const d3ProfileBasePath = `d3/profile`; + +/** + * The base request path for game data APIs in the D3 API. + */ +export const d3GameDataBasePath = `data/d3`; + +/** + * The base request path for the Blizzard API for world of warcraft. + */ +export const wowBasePath = '/data/wow'; + +/** + * The base request path for the character API for Classic World of Warcraft. + */ +export const wowCharacterBasePath = 'profile/wow/character'; + +/** + * The base request path for media in the Blizzard API for world of warcraft. + */ +export const wowMediaBasePath = `${wowBasePath}/media` as const; + +/** + * The base request path for search in the Blizzard API for world of warcraft. + */ +export const wowSearchBasePath = `${wowBasePath}/search` as const; + +/** + * Base search parameters + * orderby The field to order results by. + * _page The page number to return. + * @example + * const params: BaseSearchParameters = { + * orderby: 'name', + * _page: 1, + * }; + */ +export interface BaseSearchParameters { + _page?: number; + orderby?: Array | string; +} +/** + * The standard structure to represent a World of Warcraft Character. + */ +export interface Character extends NameIdKey { + realm: Realm; +} + +/** + * A record containing the RGBA values of a color. + */ +export interface Color { + a: number; + b: number; + g: number; + r: number; +} + +/** + * The faction associated with a character or entity in World of Warcraft. + */ +export interface Faction { + name: string; + type: Factions; +} + +/** + * The playable factions in World of Warcraft. + */ +export type Factions = 'ALLIANCE' | 'HORDE' | 'NEUTRAL'; + +/** + * The gender associated with a character or entity in World of Warcraft. + */ +export interface Gender { + name: string; + type: 'FEMALE' | 'MALE'; +} + +/** + * The playable gender names/descriptions in World of Warcraft. + */ +export interface GenderName { + female: null | string; + male: null | string; +} + +export interface Href { + href: string; +} + +/** + * Base record interface containing key.href property that often appear in Blizzard API responses. + */ +export interface KeyBase { + key: Href; +} + +/** + * The media asset associated with a character or entity in World of Warcraft. + */ +export interface MediaAsset { + file_data_id?: number; + key: string; + value: string; +} + +/** + * Base record interface containing name and id properties that often appear together in Blizzard API responses. + */ +export interface NameId { + id: number; + name: string; +} + +/** + * Base record containing both {@link KeyBase} and {@link NameId} interfaces. + */ +export interface NameIdKey extends KeyBase, NameId {} + +/** + * The standard structure to represent a World of Warcraft Realm. + */ +export interface Realm extends KeyBase { + id: number; + name?: string; + slug: string; +} + +/** + * Base interface for Blizzard API responses. + */ +export interface ResponseBase { + _links: { + self: Href; + }; +} diff --git a/packages/core/src/blizzard-api.test.ts b/packages/core/src/blizzard-api.test.ts index 66a586b1..3fd33d8a 100644 --- a/packages/core/src/blizzard-api.test.ts +++ b/packages/core/src/blizzard-api.test.ts @@ -1,6 +1,6 @@ import { describe, it } from 'vitest'; -import type { Locales, Origins } from './blizzard-api'; import { getBlizzardApi } from './blizzard-api'; +import type { Locales, Origins } from './locales'; describe.concurrent('getBlizzardApi', () => { it('should return the correct endpoint for the specified origin and locale', ({ expect }) => { diff --git a/packages/core/src/blizzard-api.ts b/packages/core/src/blizzard-api.ts index e54bbaed..fc133034 100644 --- a/packages/core/src/blizzard-api.ts +++ b/packages/core/src/blizzard-api.ts @@ -1,35 +1,14 @@ -/** - * Possible locales for use within the Blizzard API. - */ -export type Locales = - | 'de_DE' - | 'en_GB' - | 'en_US' - | 'es_ES' - | 'es_MX' - | 'fr_FR' - | 'it_IT' - | 'ko_KR' - | 'multi' - | 'pt_BR' - | 'pt_PT' - | 'ru_RU' - | 'zh_CN' - | 'zh_TW'; -/** - * Possible regions for use within the Blizzard API. - */ -export type Origins = 'cn' | 'eu' | 'kr' | 'tw' | 'us'; +import type { Locales, Origins } from './locales'; /** * A record of regions and their supported locales. */ const _regionLocaleMap = { cn: ['zh_CN'], - eu: ['en_GB', 'es_ES', 'fr_FR', 'ru_RU', 'de_DE', 'pt_PT', 'it_IT', 'multi'], - kr: ['ko_KR', 'en_GB', 'en_US', 'multi'], - tw: ['zh_TW', 'en_GB', 'en_US', 'multi'], - us: ['en_US', 'es_MX', 'pt_BR', 'multi'], + eu: ['en_GB', 'es_ES', 'fr_FR', 'ru_RU', 'de_DE', 'it_IT'], + kr: ['ko_KR', 'en_GB', 'en_US'], + tw: ['zh_TW', 'en_GB', 'en_US'], + us: ['en_US', 'es_MX', 'pt_BR'], } as const satisfies Record>; /** diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index d7e6ef29..1ac6bfc4 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,9 +1,15 @@ +//Base +export * from './base'; + //Blizzard API export * from './blizzard-api'; //Namespace export type * from './namespace'; +//Locales +export type * from './locales'; + //Resource export type * from './resource'; diff --git a/packages/core/src/locales.ts b/packages/core/src/locales.ts new file mode 100644 index 00000000..71c0d5f2 --- /dev/null +++ b/packages/core/src/locales.ts @@ -0,0 +1,20 @@ +/** + * Possible locales for use within the Blizzard API. + */ +export type Locales = + | 'de_DE' + | 'en_GB' + | 'en_US' + | 'es_ES' + | 'es_MX' + | 'fr_FR' + | 'it_IT' + | 'ko_KR' + | 'pt_BR' + | 'ru_RU' + | 'zh_CN' + | 'zh_TW'; +/** + * Possible regions for use within the Blizzard API. + */ +export type Origins = 'cn' | 'eu' | 'kr' | 'tw' | 'us'; diff --git a/packages/core/src/search.ts b/packages/core/src/search.ts index 9152e401..69a5485b 100644 --- a/packages/core/src/search.ts +++ b/packages/core/src/search.ts @@ -1,18 +1,3 @@ -/** - * Base search parameters - * orderby The field to order results by. - * _page The page number to return. - * @example - * const params: BaseSearchParameters = { - * orderby: 'name', - * _page: 1, - * }; - */ -export interface BaseSearchParameters { - _page?: number; - orderby?: Array | string; -} - /** * Search response * page The current page number. @@ -26,14 +11,12 @@ export interface BaseSearchParameters { * pageSize: 20, * maxPageSize: 100, * pageCount: 10, - * results: [], * }; */ -export interface SearchResponse { +export interface SearchResponseWithoutResults { maxPageSize: number; page: number; pageCount: number; pageSize: number; resultCountCapped?: boolean; - results: Array; } diff --git a/packages/d3/package.json b/packages/d3/package.json index 59f255a0..2b71068e 100644 --- a/packages/d3/package.json +++ b/packages/d3/package.json @@ -7,7 +7,7 @@ "repository": "https://github.com/Pewtro/blizzard-api/tree/main/packages/d3", "type": "module", "engines": { - "node": "^18.18 || >=20.9" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "module": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/d3/src/act/act.test.ts b/packages/d3/src/act/act.test.ts index d27a7782..321518e8 100644 --- a/packages/d3/src/act/act.test.ts +++ b/packages/d3/src/act/act.test.ts @@ -1,14 +1,14 @@ +import { d3BasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base } from '../base'; import { act, actIndex } from './act'; describe.concurrent('act', () => { it('should return the act resource', ({ expect }) => { const resource = act(1); - expect(resource.path).toBe(`${base}/act/1`); + expect(resource.path).toBe(`${d3BasePath}/act/1`); }); it('should return the act index resource', ({ expect }) => { const resource = actIndex(); - expect(resource.path).toBe(`${base}/act`); + expect(resource.path).toBe(`${d3BasePath}/act`); }); }); diff --git a/packages/d3/src/act/act.ts b/packages/d3/src/act/act.ts index 12f69604..d09540b4 100644 --- a/packages/d3/src/act/act.ts +++ b/packages/d3/src/act/act.ts @@ -1,5 +1,5 @@ import type { Resource } from '@blizzard-api/core'; -import { base } from '../base'; +import { d3BasePath } from '@blizzard-api/core'; import type { ActIndexResponse, ActResponse } from './types'; /** @@ -9,7 +9,7 @@ import type { ActIndexResponse, ActResponse } from './types'; */ export function act(actId: number): Resource { return { - path: `${base}/act/${actId}`, + path: `${d3BasePath}/act/${actId}`, }; } @@ -19,6 +19,6 @@ export function act(actId: number): Resource { */ export function actIndex(): Resource { return { - path: `${base}/act`, + path: `${d3BasePath}/act`, }; } diff --git a/packages/d3/src/artisan-and-recipe/artisan-and-recipe.test.ts b/packages/d3/src/artisan-and-recipe/artisan-and-recipe.test.ts index 1efc2345..f77bdf11 100644 --- a/packages/d3/src/artisan-and-recipe/artisan-and-recipe.test.ts +++ b/packages/d3/src/artisan-and-recipe/artisan-and-recipe.test.ts @@ -1,11 +1,11 @@ +import { d3BasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base } from '../base'; import { artisan, recipe } from './artisan-and-recipe'; describe.concurrent('artisan and recipe', () => { it('should return the correct resource path', ({ expect }) => { const artisanSlug = 'blacksmith'; - const expectedPath = `${base}/artisan/blacksmith`; + const expectedPath = `${d3BasePath}/artisan/blacksmith`; const resource = artisan(artisanSlug); @@ -15,7 +15,7 @@ describe.concurrent('artisan and recipe', () => { const artisanSlug = 'blacksmith'; const recipeSlug = 'sword'; - const expectedPath = `${base}/artisan/blacksmith/recipe/sword`; + const expectedPath = `${d3BasePath}/artisan/blacksmith/recipe/sword`; const resource = recipe(artisanSlug, recipeSlug); diff --git a/packages/d3/src/artisan-and-recipe/artisan-and-recipe.ts b/packages/d3/src/artisan-and-recipe/artisan-and-recipe.ts index d1c41659..9435d8c2 100644 --- a/packages/d3/src/artisan-and-recipe/artisan-and-recipe.ts +++ b/packages/d3/src/artisan-and-recipe/artisan-and-recipe.ts @@ -1,5 +1,5 @@ import type { Resource } from '@blizzard-api/core'; -import { base } from '../base'; +import { d3BasePath } from '@blizzard-api/core'; import type { ArtisanResponse, RecipeResponse } from './types'; /** @@ -9,7 +9,7 @@ import type { ArtisanResponse, RecipeResponse } from './types'; */ export function artisan(artisanSlug: string): Resource { return { - path: `${base}/artisan/${artisanSlug}`, + path: `${d3BasePath}/artisan/${artisanSlug}`, }; } @@ -21,6 +21,6 @@ export function artisan(artisanSlug: string): Resource { */ export function recipe(artisanSlug: string, recipeSlug: string): Resource { return { - path: `${base}/artisan/${artisanSlug}/recipe/${recipeSlug}`, + path: `${d3BasePath}/artisan/${artisanSlug}/recipe/${recipeSlug}`, }; } diff --git a/packages/d3/src/base.ts b/packages/d3/src/base.ts deleted file mode 100644 index 7cca90c1..00000000 --- a/packages/d3/src/base.ts +++ /dev/null @@ -1,17 +0,0 @@ -export const base = 'd3/data'; - -export const profileBase = `d3/profile`; - -//Why is the game data APIs base root the reverse of the regular base? -export const gameDataBase = `data/d3`; - -/** - * Base interface for Blizzard API responses. - */ -export interface ResponseBase { - _links: { - self: { - href: string; - }; - }; -} diff --git a/packages/d3/src/character-class-and-skill/character-class-and-skill.test.ts b/packages/d3/src/character-class-and-skill/character-class-and-skill.test.ts index ee9cf431..3df59b25 100644 --- a/packages/d3/src/character-class-and-skill/character-class-and-skill.test.ts +++ b/packages/d3/src/character-class-and-skill/character-class-and-skill.test.ts @@ -1,11 +1,11 @@ +import { d3BasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base } from '../base'; import { characterClass, skill } from './character-class-and-skill'; describe.concurrent('characterClass', () => { it('returns the correct resource path', ({ expect }) => { const characterClassSlug = 'warrior'; - const expectedPath = `${base}/character-class/warrior`; + const expectedPath = `${d3BasePath}/character-class/warrior`; const resource = characterClass(characterClassSlug); @@ -14,7 +14,7 @@ describe.concurrent('characterClass', () => { it('returns the correct resource path', ({ expect }) => { const characterClassSlug = 'warrior'; const skillSlug = 'charge'; - const expectedPath = `${base}/hero/warrior/skill/charge`; + const expectedPath = `${d3BasePath}/hero/warrior/skill/charge`; const resource = skill(characterClassSlug, skillSlug); diff --git a/packages/d3/src/character-class-and-skill/character-class-and-skill.ts b/packages/d3/src/character-class-and-skill/character-class-and-skill.ts index 4046dd38..98439774 100644 --- a/packages/d3/src/character-class-and-skill/character-class-and-skill.ts +++ b/packages/d3/src/character-class-and-skill/character-class-and-skill.ts @@ -1,5 +1,5 @@ import type { Resource } from '@blizzard-api/core'; -import { base } from '../base'; +import { d3BasePath } from '@blizzard-api/core'; import type { CharacterClassResponse, SkillResponse } from './types'; /** @@ -9,7 +9,7 @@ import type { CharacterClassResponse, SkillResponse } from './types'; */ export function characterClass(characterClassSlug: string): Resource { return { - path: `${base}/character-class/${characterClassSlug}`, + path: `${d3BasePath}/character-class/${characterClassSlug}`, }; } @@ -21,6 +21,6 @@ export function characterClass(characterClassSlug: string): Resource { return { - path: `${base}/hero/${characterClassSlug}/skill/${skillSlug}`, + path: `${d3BasePath}/hero/${characterClassSlug}/skill/${skillSlug}`, }; } diff --git a/packages/d3/src/follower/follower.test.ts b/packages/d3/src/follower/follower.test.ts index c7514563..5f7ac22a 100644 --- a/packages/d3/src/follower/follower.test.ts +++ b/packages/d3/src/follower/follower.test.ts @@ -1,11 +1,11 @@ +import { d3BasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base } from '../base'; import { follower } from './follower'; describe.concurrent('follower', () => { it('should return the correct resource path', ({ expect }) => { const followerSlug = 'some-follower-slug'; - const expectedPath = `${base}/follower/some-follower-slug`; + const expectedPath = `${d3BasePath}/follower/some-follower-slug`; const resource = follower(followerSlug); diff --git a/packages/d3/src/follower/follower.ts b/packages/d3/src/follower/follower.ts index 60609a8f..7a8aa143 100644 --- a/packages/d3/src/follower/follower.ts +++ b/packages/d3/src/follower/follower.ts @@ -1,5 +1,5 @@ import type { Resource } from '@blizzard-api/core'; -import { base } from '../base'; +import { d3BasePath } from '@blizzard-api/core'; import type { FollowerResponse } from './types'; /** @@ -9,6 +9,6 @@ import type { FollowerResponse } from './types'; */ export function follower(followerSlug: string): Resource { return { - path: `${base}/follower/${followerSlug}`, + path: `${d3BasePath}/follower/${followerSlug}`, }; } diff --git a/packages/d3/src/game-data/game-data.test.ts b/packages/d3/src/game-data/game-data.test.ts index 8028d715..0f9d95e3 100644 --- a/packages/d3/src/game-data/game-data.test.ts +++ b/packages/d3/src/game-data/game-data.test.ts @@ -1,41 +1,41 @@ +import { d3GameDataBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { gameDataBase } from '../base'; import { era, eraIndex, eraLeaderboard, season, seasonIndex, seasonLeaderboard } from '../game-data/game-data'; describe.concurrent('game-data', () => { it('seasonIndex should return the correct resource path', ({ expect }) => { const resource = seasonIndex(); - expect(resource.path).toBe(`${gameDataBase}/season`); + expect(resource.path).toBe(`${d3GameDataBasePath}/season`); }); it('season should return the correct resource path', ({ expect }) => { const id = 123; const resource = season(id); - expect(resource.path).toBe(`${gameDataBase}/season/${id}`); + expect(resource.path).toBe(`${d3GameDataBasePath}/season/${id}`); }); it('seasonLeaderboard should return the correct resource path', ({ expect }) => { const id = 123; const leaderboard = 'leaderboard1'; const resource = seasonLeaderboard(id, leaderboard); - expect(resource.path).toBe(`${gameDataBase}/season/${id}/leaderboard/${leaderboard}`); + expect(resource.path).toBe(`${d3GameDataBasePath}/season/${id}/leaderboard/${leaderboard}`); }); it('eraIndex should return the correct resource path', ({ expect }) => { const resource = eraIndex(); - expect(resource.path).toBe(`${gameDataBase}/era`); + expect(resource.path).toBe(`${d3GameDataBasePath}/era`); }); it('era should return the correct resource path', ({ expect }) => { const id = 123; const resource = era(id); - expect(resource.path).toBe(`${gameDataBase}/era/${id}`); + expect(resource.path).toBe(`${d3GameDataBasePath}/era/${id}`); }); it('eraLeaderboard should return the correct resource path', ({ expect }) => { const id = 123; const leaderboard = 'leaderboard1'; const resource = eraLeaderboard(id, leaderboard); - expect(resource.path).toBe(`${gameDataBase}/era/${id}/leaderboard/${leaderboard}`); + expect(resource.path).toBe(`${d3GameDataBasePath}/era/${id}/leaderboard/${leaderboard}`); }); }); diff --git a/packages/d3/src/game-data/game-data.ts b/packages/d3/src/game-data/game-data.ts index 7f9518cc..a4aa8d58 100644 --- a/packages/d3/src/game-data/game-data.ts +++ b/packages/d3/src/game-data/game-data.ts @@ -1,5 +1,5 @@ +import { d3GameDataBasePath } from '@blizzard-api/core'; import type { Resource } from '@blizzard-api/core'; -import { gameDataBase } from '../base'; import type { EraIndexResponse, EraLeaderboardResponse, @@ -16,7 +16,7 @@ import type { */ export function era(id: number): Resource { return { - path: `${gameDataBase}/era/${id}`, + path: `${d3GameDataBasePath}/era/${id}`, }; } @@ -26,7 +26,7 @@ export function era(id: number): Resource { */ export function eraIndex(): Resource { return { - path: `${gameDataBase}/era`, + path: `${d3GameDataBasePath}/era`, }; } @@ -38,7 +38,7 @@ export function eraIndex(): Resource { */ export function eraLeaderboard(id: number, leaderboard: string): Resource { return { - path: `${gameDataBase}/era/${id}/leaderboard/${leaderboard}`, + path: `${d3GameDataBasePath}/era/${id}/leaderboard/${leaderboard}`, }; } @@ -49,7 +49,7 @@ export function eraLeaderboard(id: number, leaderboard: string): Resource { return { - path: `${gameDataBase}/season/${id}`, + path: `${d3GameDataBasePath}/season/${id}`, }; } @@ -59,7 +59,7 @@ export function season(id: number): Resource { */ export function seasonIndex(): Resource { return { - path: `${gameDataBase}/season`, + path: `${d3GameDataBasePath}/season`, }; } @@ -71,6 +71,6 @@ export function seasonIndex(): Resource { */ export function seasonLeaderboard(id: number, leaderboard: string): Resource { return { - path: `${gameDataBase}/season/${id}/leaderboard/${leaderboard}`, + path: `${d3GameDataBasePath}/season/${id}/leaderboard/${leaderboard}`, }; } diff --git a/packages/d3/src/game-data/types.ts b/packages/d3/src/game-data/types.ts index e0fcf069..0e441e59 100644 --- a/packages/d3/src/game-data/types.ts +++ b/packages/d3/src/game-data/types.ts @@ -1,8 +1,8 @@ -import type { ResponseBase } from '../base'; +import type { Href, ResponseBase } from '@blizzard-api/core'; export interface EraIndexResponse extends ResponseBase { current_era: number; - era: Array<{ href: string }>; + era: Array; generated_by: string; last_update_time: string; } @@ -31,7 +31,7 @@ export interface SeasonIndexResponse extends ResponseBase { current_season: number; generated_by: string; last_update_time: string; - season: Array<{ href: string }>; + season: Array; service_current_season: number; service_season_state: string; } @@ -72,7 +72,7 @@ interface EraLeaderboard { interface Leaderboard { hardcore?: boolean; hero_class_string?: string; - ladder: { href: string }; + ladder: Href; team_size?: number; } diff --git a/packages/d3/src/item-type/item-type.test.ts b/packages/d3/src/item-type/item-type.test.ts index 1f235ff6..6adfad83 100644 --- a/packages/d3/src/item-type/item-type.test.ts +++ b/packages/d3/src/item-type/item-type.test.ts @@ -1,15 +1,15 @@ +import { d3BasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base } from '../base'; import { itemType, itemTypeIndex } from './item-type'; describe.concurrent('itemTypeIndex', () => { it('should return the correct resource path', ({ expect }) => { const resource = itemTypeIndex(); - expect(resource.path).toBe(`${base}/item-type`); + expect(resource.path).toBe(`${d3BasePath}/item-type`); }); it('should return the correct resource path', ({ expect }) => { const itemTypeSlug = 'some-item-type-slug'; const resource = itemType(itemTypeSlug); - expect(resource.path).toBe(`${base}/item-type/${itemTypeSlug}`); + expect(resource.path).toBe(`${d3BasePath}/item-type/${itemTypeSlug}`); }); }); diff --git a/packages/d3/src/item-type/item-type.ts b/packages/d3/src/item-type/item-type.ts index 03a62126..bbf24a16 100644 --- a/packages/d3/src/item-type/item-type.ts +++ b/packages/d3/src/item-type/item-type.ts @@ -1,5 +1,5 @@ import type { Resource } from '@blizzard-api/core'; -import { base } from '../base'; +import { d3BasePath } from '@blizzard-api/core'; import type { ItemTypeIndexResponse, ItemTypeResponse } from './types'; /** @@ -9,7 +9,7 @@ import type { ItemTypeIndexResponse, ItemTypeResponse } from './types'; */ export function itemType(itemTypeSlug: string): Resource> { return { - path: `${base}/item-type/${itemTypeSlug}`, + path: `${d3BasePath}/item-type/${itemTypeSlug}`, }; } @@ -19,6 +19,6 @@ export function itemType(itemTypeSlug: string): Resource */ export function itemTypeIndex(): Resource> { return { - path: `${base}/item-type`, + path: `${d3BasePath}/item-type`, }; } diff --git a/packages/d3/src/item/item.test.ts b/packages/d3/src/item/item.test.ts index 6ed7f471..df3e7d53 100644 --- a/packages/d3/src/item/item.test.ts +++ b/packages/d3/src/item/item.test.ts @@ -1,11 +1,11 @@ +import { d3BasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base } from '../base'; import { item } from './item'; describe.concurrent('item', () => { it('should return the correct resource path', ({ expect }) => { const itemSlugAndId = '12345'; - const expectedPath = `${base}/item/12345`; + const expectedPath = `${d3BasePath}/item/12345`; const resource = item(itemSlugAndId); diff --git a/packages/d3/src/item/item.ts b/packages/d3/src/item/item.ts index 9732f090..0403cd5d 100644 --- a/packages/d3/src/item/item.ts +++ b/packages/d3/src/item/item.ts @@ -1,5 +1,5 @@ import type { Resource } from '@blizzard-api/core'; -import { base } from '../base'; +import { d3BasePath } from '@blizzard-api/core'; import type { ItemResponse } from './types'; /** @@ -9,6 +9,6 @@ import type { ItemResponse } from './types'; */ export function item(itemSlugAndId: string): Resource { return { - path: `${base}/item/${itemSlugAndId}`, + path: `${d3BasePath}/item/${itemSlugAndId}`, }; } diff --git a/packages/d3/src/profile/profile.test.ts b/packages/d3/src/profile/profile.test.ts index 9a598f01..9b4eb7c3 100644 --- a/packages/d3/src/profile/profile.test.ts +++ b/packages/d3/src/profile/profile.test.ts @@ -1,5 +1,5 @@ +import { d3ProfileBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { profileBase } from '../base'; import { account, accountHero, accountHeroFollowerItems, accountHeroItems } from './profile'; const battleTag = 'example#1234'; @@ -7,7 +7,7 @@ const heroId = 42; describe.concurrent('profile', () => { it('account should return the correct resource', ({ expect }) => { - const expectedPath = `${profileBase}/example#1234`; + const expectedPath = `${d3ProfileBasePath}/example%231234`; const resource = account(battleTag); @@ -15,7 +15,7 @@ describe.concurrent('profile', () => { }); it('should return the correct resource path', ({ expect }) => { - const expectedPath = `${profileBase}/example#1234/hero/42`; + const expectedPath = `${d3ProfileBasePath}/example%231234/hero/42`; const resource = accountHero(battleTag, heroId); @@ -23,7 +23,7 @@ describe.concurrent('profile', () => { }); it('should return the correct resource path', ({ expect }) => { - const expectedPath = `${profileBase}/example#1234/hero/42/items`; + const expectedPath = `${d3ProfileBasePath}/example%231234/hero/42/items`; const resource = accountHeroItems(battleTag, heroId); @@ -31,7 +31,7 @@ describe.concurrent('profile', () => { }); it('accountHeroFollowerItems should return the correct resource', ({ expect }) => { - const expectedPath = `${profileBase}/example#1234/hero/42/follower-items`; + const expectedPath = `${d3ProfileBasePath}/example%231234/hero/42/follower-items`; const resource = accountHeroFollowerItems(battleTag, heroId); diff --git a/packages/d3/src/profile/profile.ts b/packages/d3/src/profile/profile.ts index b2fe83f4..72d237fc 100644 --- a/packages/d3/src/profile/profile.ts +++ b/packages/d3/src/profile/profile.ts @@ -1,5 +1,5 @@ +import { d3ProfileBasePath } from '@blizzard-api/core'; import type { Resource } from '@blizzard-api/core'; -import { profileBase } from '../base'; import type { AccountHeroFollowerItemsResponse, AccountHeroResponse, AccountResponse } from './types'; /** @@ -9,7 +9,7 @@ import type { AccountHeroFollowerItemsResponse, AccountHeroResponse, AccountResp */ export function account(battleTag: string): Resource { return { - path: `${profileBase}/${battleTag}`, + path: `${d3ProfileBasePath}/${encodeURIComponent(battleTag)}`, }; } @@ -21,7 +21,7 @@ export function account(battleTag: string): Resource { */ export function accountHero(battleTag: string, heroId: number): Resource { return { - path: `${profileBase}/${battleTag}/hero/${heroId}`, + path: `${d3ProfileBasePath}/${encodeURIComponent(battleTag)}/hero/${heroId}`, }; } @@ -36,7 +36,7 @@ export function accountHeroFollowerItems( heroId: number, ): Resource { return { - path: `${profileBase}/${battleTag}/hero/${heroId}/follower-items`, + path: `${d3ProfileBasePath}/${encodeURIComponent(battleTag)}/hero/${heroId}/follower-items`, }; } @@ -48,6 +48,6 @@ export function accountHeroFollowerItems( */ export function accountHeroItems(battleTag: string, heroId: number): Resource { return { - path: `${profileBase}/${battleTag}/hero/${heroId}/items`, + path: `${d3ProfileBasePath}/${encodeURIComponent(battleTag)}/hero/${heroId}/items`, }; } diff --git a/packages/d3/src/profile/types.ts b/packages/d3/src/profile/types.ts index 0acddb3d..9bb2c940 100644 --- a/packages/d3/src/profile/types.ts +++ b/packages/d3/src/profile/types.ts @@ -230,7 +230,7 @@ interface HeroProgression { interface Item { displayColor?: DisplayColor; - dyeColor?: Item; + dyeColor?: Dye; icon: string; id: string; name: string; diff --git a/packages/hs/package.json b/packages/hs/package.json index b65ec2e2..c44d7ed2 100644 --- a/packages/hs/package.json +++ b/packages/hs/package.json @@ -7,7 +7,7 @@ "repository": "https://github.com/Pewtro/blizzard-api/tree/main/packages/hs", "type": "module", "engines": { - "node": "^18.18 || >=20.9" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "module": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/hs/src/base.ts b/packages/hs/src/base.ts deleted file mode 100644 index accd862e..00000000 --- a/packages/hs/src/base.ts +++ /dev/null @@ -1,7 +0,0 @@ -export type GameMode = 'arena' | 'battlegrounds' | 'classic' | 'constructed' | 'duels' | 'mercenaries' | 'standard'; - -export type SearchSortOption = `${SortOptions}:${SortDirection}`; - -type SortDirection = 'asc' | 'desc'; - -type SortOptions = 'attack' | 'class' | 'dataAdded' | 'groupByClass' | 'health' | 'manaCost' | 'name'; diff --git a/packages/hs/src/card-backs/types.ts b/packages/hs/src/card-backs/types.ts index efe943a2..bc1b0acb 100644 --- a/packages/hs/src/card-backs/types.ts +++ b/packages/hs/src/card-backs/types.ts @@ -1,5 +1,4 @@ import type { Locales } from '@blizzard-api/core'; -import type { SearchSortOption } from '../base'; export interface CardBackSearchParameters { cardBackCategory?: @@ -19,7 +18,7 @@ export interface CardBackSearchParameters { locale?: Locales; page?: number; pageSize?: number; - sort?: SearchSortOption; + sort?: `${SearchOptions}:${SortOptions}`; textFilter?: string; } @@ -30,6 +29,8 @@ export interface CardBackSearchResponse { pageCount: number; } +export type SearchOptions = 'attack' | 'class' | 'dataAdded' | 'groupByClass' | 'health' | 'manaCost' | 'name'; + export interface SingleCardBackSearchResponse { id: number; image: string; @@ -38,3 +39,4 @@ export interface SingleCardBackSearchResponse { sortCategory: number; text: Record | string; } +export type SortOptions = 'asc' | 'desc'; diff --git a/packages/hs/src/cards/cards.test.ts b/packages/hs/src/cards/cards.test.ts index 1158c628..4062d941 100644 --- a/packages/hs/src/cards/cards.test.ts +++ b/packages/hs/src/cards/cards.test.ts @@ -1,6 +1,5 @@ import type { Locales } from '@blizzard-api/core'; import { describe, expect, it } from 'vitest'; -import type { GameMode } from '../base'; import { cardSearch, fetchOneCard } from './cards'; import type { CardSearchParameters } from './types'; @@ -69,8 +68,7 @@ describe('fetchOneCard', () => { it('should return correct parameters with specified gameMode', () => { const id = 'card123'; - const options = { gameMode: 'battlegrounds' as GameMode, locale: 'en_US' as Locales }; - const result = fetchOneCard(id, options); + const result = fetchOneCard(id, { gameMode: 'battlegrounds', locale: 'en_US' }); expect(result.parameters).toEqual({ gameMode: 'battlegrounds', locale: 'en_US', @@ -80,8 +78,7 @@ describe('fetchOneCard', () => { it('should handle undefined locale correctly', () => { const id = 'card123'; - const options = { gameMode: 'battlegrounds' as GameMode }; - const result = fetchOneCard(id, options); + const result = fetchOneCard(id, { gameMode: 'battlegrounds' }); expect(result.parameters).toEqual({ gameMode: 'battlegrounds', locale: undefined, diff --git a/packages/hs/src/cards/cards.ts b/packages/hs/src/cards/cards.ts index b2eada41..85985069 100644 --- a/packages/hs/src/cards/cards.ts +++ b/packages/hs/src/cards/cards.ts @@ -1,10 +1,10 @@ import type { Locales, Resource } from '@blizzard-api/core'; -import type { GameMode } from '../base'; import type { BlizzardCardSearchParameters, CardSearchParameters, CardSearchResponse, FetchOneCardResponse, + GameMode, } from './types'; /** diff --git a/packages/hs/src/cards/types.ts b/packages/hs/src/cards/types.ts index 90b1f732..0ca0c056 100644 --- a/packages/hs/src/cards/types.ts +++ b/packages/hs/src/cards/types.ts @@ -1,5 +1,4 @@ import type { Locales } from '@blizzard-api/core'; -import type { GameMode } from '../base'; export interface BlizzardCardSearchParameters extends BaseSearchParameters { attack?: string; @@ -46,6 +45,8 @@ export interface FetchOneCardResponse { text: Record | string; } +export type GameMode = 'arena' | 'battlegrounds' | 'classic' | 'constructed' | 'duels' | 'mercenaries' | 'standard'; + interface BaseSearchParameters { gameMode?: GameMode; locale?: Locales; diff --git a/packages/hs/src/metadata/types.ts b/packages/hs/src/metadata/types.ts index f72dbc2e..07c8bb01 100644 --- a/packages/hs/src/metadata/types.ts +++ b/packages/hs/src/metadata/types.ts @@ -1,4 +1,4 @@ -import type { NameId } from '../../../wow/src/base'; +import type { NameId } from '@blizzard-api/core'; export interface AllMetadataResponse { arenaIds: Array; diff --git a/packages/integration-tests/classic-wow/auction-house.integration.test.ts b/packages/integration-tests/classic-wow/auction-house.integration.test.ts new file mode 100644 index 00000000..9dece9ab --- /dev/null +++ b/packages/integration-tests/classic-wow/auction-house.integration.test.ts @@ -0,0 +1,64 @@ +import * as classicWow from '@blizzard-api/classic-wow'; +import { createBlizzardApiClient } from '@blizzard-api/client'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + auctionHouseIndexResponseSchema, + auctionsResponseSchema, + connectedRealmIndexResponseSchema, +} from '../../../generated/schemas/classic-wow'; + +//The auction house API is known to be flaky; skip by default. +describe.skip('classic-wow auction house integration', () => { + it('fetches index and validates responses with generated schemas', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'us', + secret: environment.blizzardClientSecret, + }); + + // 1) Get connected realm index and validate + const realmIndexResponse = await client.sendRequest(classicWow.connectedRealmIndex('dynamic-classic1x')); + const parsedRealmIndex = connectedRealmIndexResponseSchema.safeParse(realmIndexResponse); + if (!parsedRealmIndex.success) { + console.error('Connected realm index validation failed:', treeifyError(parsedRealmIndex.error)); + } + expect(parsedRealmIndex.success).toBe(true); + + const firstRealm = realmIndexResponse.connected_realms?.[0]; + expect(firstRealm).toBeDefined(); + + // Extract connected realm id from the href (e.g. /data/wow/connected-realm/123) + const href = firstRealm?.href; + const match = /connected-realm\/(\d+)/.exec(href ?? ''); + expect(match).toBeTruthy(); + const connectedRealmId = Number(match?.[1]); + + // 2) Fetch auction house index for that connected realm and validate + const auctionIndexResponse = await client.sendRequest( + classicWow.auctionHouseIndex('dynamic-classic1x', connectedRealmId), + ); + const parsedAuctionIndex = auctionHouseIndexResponseSchema.safeParse(auctionIndexResponse); + if (!parsedAuctionIndex.success) { + console.error('Auction house index validation failed:', treeifyError(parsedAuctionIndex.error)); + } + expect(parsedAuctionIndex.success).toBe(true); + + const firstAuctionHouse = auctionIndexResponse.auctions?.[0]; + expect(firstAuctionHouse).toBeDefined(); + + const auctionHouseId = firstAuctionHouse?.id; + expect(auctionHouseId).toBeGreaterThan(0); + + // 3) Fetch auctions for that auction house and validate (may be large) + const auctionsResponse = await client.sendRequest( + classicWow.auctions('dynamic-classic1x', connectedRealmId, auctionHouseId ?? 0), + ); + const parsedAuctions = auctionsResponseSchema.safeParse(auctionsResponse); + if (!parsedAuctions.success) { + console.error('Auctions validation failed:', treeifyError(parsedAuctions.error)); + } + expect(parsedAuctions.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/classic-wow/character-achievements.integration.test.ts b/packages/integration-tests/classic-wow/character-achievements.integration.test.ts new file mode 100644 index 00000000..3e810a79 --- /dev/null +++ b/packages/integration-tests/classic-wow/character-achievements.integration.test.ts @@ -0,0 +1,40 @@ +import * as classicWow from '@blizzard-api/classic-wow'; +import { createBlizzardApiClient } from '@blizzard-api/client'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + characterAchievementsSummaryResponseSchema, + characterAchievementStatisticsResponseSchema, +} from '../../../generated/schemas/classic-wow'; + +describe('classic-wow character achievements integration', () => { + it('fetches achievements summary and statistics for a character', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const realm = 'shekzeer'; + const character = 'putro'; + + const summary = await client.sendRequest( + classicWow.characterAchievementsSummary('profile-classic', realm, character), + ); + const parsedSummary = characterAchievementsSummaryResponseSchema.safeParse(summary); + if (!parsedSummary.success) { + console.error('Character achievements summary validation failed:', treeifyError(parsedSummary.error)); + } + expect(parsedSummary.success).toBe(true); + + const stats = await client.sendRequest( + classicWow.characterAchievementStatistics('profile-classic', realm, character), + ); + const parsedStats = characterAchievementStatisticsResponseSchema.safeParse(stats); + if (!parsedStats.success) { + console.error('Character achievement statistics validation failed:', treeifyError(parsedStats.error)); + } + expect(parsedStats.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/classic-wow/character-equipment.integration.test.ts b/packages/integration-tests/classic-wow/character-equipment.integration.test.ts new file mode 100644 index 00000000..e57a8db2 --- /dev/null +++ b/packages/integration-tests/classic-wow/character-equipment.integration.test.ts @@ -0,0 +1,26 @@ +import * as classicWow from '@blizzard-api/classic-wow'; +import { createBlizzardApiClient } from '@blizzard-api/client'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { characterEquipmentSummaryResponseSchema } from '../../../generated/schemas/classic-wow'; + +describe('classic-wow character equipment integration', () => { + it('fetches equipment summary for a character', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const realm = 'shekzeer'; + const character = 'putro'; + + const resp = await client.sendRequest(classicWow.characterEquipmentSummary('profile-classic', realm, character)); + const parsed = characterEquipmentSummaryResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Character equipment summary validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/classic-wow/character-hunter-pets.integration.test.ts b/packages/integration-tests/classic-wow/character-hunter-pets.integration.test.ts new file mode 100644 index 00000000..e9e0f36e --- /dev/null +++ b/packages/integration-tests/classic-wow/character-hunter-pets.integration.test.ts @@ -0,0 +1,26 @@ +import * as classicWow from '@blizzard-api/classic-wow'; +import { createBlizzardApiClient } from '@blizzard-api/client'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { characterHunterPetsSummaryResponseSchema } from '../../../generated/schemas/classic-wow'; + +describe('classic-wow character hunter pets integration', () => { + it('fetches hunter pets summary for a character', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const realm = 'shekzeer'; + const character = 'putro'; + + const resp = await client.sendRequest(classicWow.characterHunterPetsSummary('profile-classic', realm, character)); + const parsed = characterHunterPetsSummaryResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Character hunter pets summary validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/classic-wow/character-media.integration.test.ts b/packages/integration-tests/classic-wow/character-media.integration.test.ts new file mode 100644 index 00000000..b321bca3 --- /dev/null +++ b/packages/integration-tests/classic-wow/character-media.integration.test.ts @@ -0,0 +1,26 @@ +import * as classicWow from '@blizzard-api/classic-wow'; +import { createBlizzardApiClient } from '@blizzard-api/client'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { characterMediaSummaryResponseSchema } from '../../../generated/schemas/classic-wow'; + +describe('classic-wow character media integration', () => { + it('fetches media summary for a character', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const realm = 'shekzeer'; + const character = 'putro'; + + const resp = await client.sendRequest(classicWow.characterMediaSummary('profile-classic', realm, character)); + const parsed = characterMediaSummaryResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Character media summary validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/classic-wow/character-profile.integration.test.ts b/packages/integration-tests/classic-wow/character-profile.integration.test.ts new file mode 100644 index 00000000..ac18968f --- /dev/null +++ b/packages/integration-tests/classic-wow/character-profile.integration.test.ts @@ -0,0 +1,26 @@ +import * as classicWow from '@blizzard-api/classic-wow'; +import { createBlizzardApiClient } from '@blizzard-api/client'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { characterProfileSummaryResponseSchema } from '../../../generated/schemas/classic-wow'; + +describe('classic-wow character profile integration', () => { + it('fetches profile summary', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const realm = 'shekzeer'; + const character = 'putro'; + + const resp = await client.sendRequest(classicWow.characterProfileSummary('profile-classic', realm, character)); + const parsed = characterProfileSummaryResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Character profile summary validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/classic-wow/character-specialization.integration.test.ts b/packages/integration-tests/classic-wow/character-specialization.integration.test.ts new file mode 100644 index 00000000..cf91fd62 --- /dev/null +++ b/packages/integration-tests/classic-wow/character-specialization.integration.test.ts @@ -0,0 +1,47 @@ +import * as classicWow from '@blizzard-api/classic-wow'; +import { createBlizzardApiClient } from '@blizzard-api/client'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { characterSpecializationsSummaryResponseSchema } from '../../../generated/schemas/classic-wow'; + +describe('classic-wow character specialization integration', () => { + it('fetches specialization summary for a character on classic era', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const realm = 'soulseeker'; + const character = 'reonwar'; + + const resp = await client.sendRequest( + classicWow.characterSpecializationsSummary('profile-classic1x', realm, character), + ); + const parsed = characterSpecializationsSummaryResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Character specialization summary validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); + it('fetches specialization summary for a character on classic progression', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const realm = 'shekzeer'; + const character = 'putro'; + + const resp = await client.sendRequest( + classicWow.characterSpecializationsSummary('profile-classic', realm, character), + ); + const parsed = characterSpecializationsSummaryResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Character specialization summary validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/classic-wow/character-statistics.integration.test.ts b/packages/integration-tests/classic-wow/character-statistics.integration.test.ts new file mode 100644 index 00000000..b22a3a0e --- /dev/null +++ b/packages/integration-tests/classic-wow/character-statistics.integration.test.ts @@ -0,0 +1,26 @@ +import * as classicWow from '@blizzard-api/classic-wow'; +import { createBlizzardApiClient } from '@blizzard-api/client'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { characterStatisticsSummaryResponseSchema } from '../../../generated/schemas/classic-wow'; + +describe('classic-wow character statistics integration', () => { + it('fetches statistics summary for a character', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const realm = 'shekzeer'; + const character = 'putro'; + + const resp = await client.sendRequest(classicWow.characterStatisticsSummary('profile-classic', realm, character)); + const parsed = characterStatisticsSummaryResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Character statistics summary validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/classic-wow/connected-realm.integration.test.ts b/packages/integration-tests/classic-wow/connected-realm.integration.test.ts new file mode 100644 index 00000000..cc45d8b1 --- /dev/null +++ b/packages/integration-tests/classic-wow/connected-realm.integration.test.ts @@ -0,0 +1,43 @@ +import * as classicWow from '@blizzard-api/classic-wow'; +import { createBlizzardApiClient } from '@blizzard-api/client'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + connectedRealmIndexResponseSchema, + connectedRealmResponseSchema, + connectedRealmSearchResponseSchema, +} from '../../../generated/schemas/classic-wow'; + +describe('classic-wow connected realm integration', () => { + it('validates connected realm index', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'us', + secret: environment.blizzardClientSecret, + }); + + const resp = await client.sendRequest(classicWow.connectedRealmIndex('dynamic-classic1x')); + const parsed = connectedRealmIndexResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Connected realm index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + + const realm = await client.sendRequest(classicWow.connectedRealm('dynamic-classic1x', 5085)); + const parsedRealm = connectedRealmResponseSchema.safeParse(realm); + if (!parsedRealm.success) { + console.error('Connected realm detail validation failed:', treeifyError(parsedRealm.error)); + } + expect(parsedRealm.success).toBe(true); + + const search = await client.sendRequest(classicWow.connectedRealmSearch('dynamic-classic1x', { _page: 1 })); + const parsedSearch = connectedRealmSearchResponseSchema.safeParse(search); + if (!parsedSearch.success) { + console.error('Connected realm search validation failed:', treeifyError(parsedSearch.error)); + console.log('search', search); + console.log('parsedSearch.error', parsedSearch.error); + } + expect(parsedSearch.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/classic-wow/creature.integration.test.ts b/packages/integration-tests/classic-wow/creature.integration.test.ts new file mode 100644 index 00000000..b9168f13 --- /dev/null +++ b/packages/integration-tests/classic-wow/creature.integration.test.ts @@ -0,0 +1,186 @@ +import * as classicWow from '@blizzard-api/classic-wow'; +import { createBlizzardApiClient } from '@blizzard-api/client'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + creatureDisplayMediaResponseSchema, + creatureFamilyIndexResponseSchema, + creatureFamilyMediaResponseSchema, + creatureFamilyResponseSchema, + creatureResponseSchema, + creatureSearchResponseSchema, + creatureTypeIndexResponseSchema, + creatureTypeResponseSchema, +} from '../../../generated/schemas/classic-wow'; + +describe.concurrent('classic-wow creature integration for classic era', async () => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'us', + secret: environment.blizzardClientSecret, + }); + it('validates creature', async ({ expect }) => { + const resp = await client.sendRequest(classicWow.creature('static-classic1x', 30)); + const parsed = creatureResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Creature validation failed', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + + const respMedia = await client.sendRequest(classicWow.creatureDisplayMedia('static-classic1x', 30)); + const parsedMedia = creatureDisplayMediaResponseSchema.safeParse(respMedia); + if (!parsedMedia.success) { + console.error('Creature validation failed', treeifyError(parsedMedia.error)); + } + expect(parsedMedia.success).toBe(true); + }); + it('validates creature family index', async ({ expect }) => { + const resp = await client.sendRequest(classicWow.creatureFamilyIndex('static-classic1x')); + const parsed = creatureFamilyIndexResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Creature family index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + + // eslint-disable-next-line sonarjs/pseudo-random + const creatureFamilyIndex = Math.floor(Math.random() * resp.creature_families.length); + const creatureFamily = resp.creature_families[creatureFamilyIndex]; + expect(creatureFamily).toBeDefined(); + + const family = await client.sendRequest(classicWow.creatureFamily('static-classic1x', creatureFamily!.id)); + const parsedFamily = creatureFamilyResponseSchema.safeParse(family); + if (!parsedFamily.success) { + console.error( + 'Creature family detail validation failed for id', + creatureFamily!.id, + treeifyError(parsedFamily.error), + ); + console.log('family', family); + console.log('parsedFamily.error', parsedFamily.error); + } + expect(parsedFamily.success).toBe(true); + + const media = await client.sendRequest(classicWow.creatureFamilyMedia('static-classic1x', creatureFamily!.id)); + const parsedMedia = creatureFamilyMediaResponseSchema.safeParse(media); + if (!parsedMedia.success) { + console.error('Creature family media validation failed:', treeifyError(parsedMedia.error)); + } + expect(parsedMedia.success).toBe(true); + }); + + it('validates creature type index and details', async ({ expect }) => { + const resp = await client.sendRequest(classicWow.creatureTypeIndex('static-classic1x')); + const parsed = creatureTypeIndexResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Creature type index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + + // eslint-disable-next-line sonarjs/pseudo-random + const creatureTypeIndex = Math.floor(Math.random() * resp.creature_types.length); + const creatureType = resp.creature_types[creatureTypeIndex]; + expect(creatureType).toBeDefined(); + + const type = await client.sendRequest(classicWow.creatureType('static-classic1x', creatureType!.id)); + const parsedType = creatureTypeResponseSchema.safeParse(type); + if (!parsedType.success) { + console.error('Creature type detail validation failed:', treeifyError(parsedType.error)); + } + expect(parsedType.success).toBe(true); + }); + + it('validates creature search', async ({ expect }) => { + const search = await client.sendRequest( + classicWow.creatureSearch('static-classic1x', { _page: 1, locale: 'en_GB', name: 'wolf' }), + ); + const parsed = creatureSearchResponseSchema.safeParse(search); + if (!parsed.success) { + console.error('Creature search validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); +}); + +describe.concurrent('classic-wow creature integration for classic progression', async () => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'us', + secret: environment.blizzardClientSecret, + }); + it('validates creature', async ({ expect }) => { + const resp = await client.sendRequest(classicWow.creature('static-classic', 30)); + const parsed = creatureResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Creature validation failed', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); + it('validates creature family index', async ({ expect }) => { + const resp = await client.sendRequest(classicWow.creatureFamilyIndex('static-classic')); + const parsed = creatureFamilyIndexResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Creature family index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + + // eslint-disable-next-line sonarjs/pseudo-random + const creatureFamilyIndex = Math.floor(Math.random() * resp.creature_families.length); + const creatureFamily = resp.creature_families[creatureFamilyIndex]; + expect(creatureFamily).toBeDefined(); + + const family = await client.sendRequest(classicWow.creatureFamily('static-classic', creatureFamily!.id)); + const parsedFamily = creatureFamilyResponseSchema.safeParse(family); + if (!parsedFamily.success) { + console.error( + 'Creature family detail validation failed for id', + creatureFamily!.id, + treeifyError(parsedFamily.error), + ); + console.log('family', family); + console.log('parsedFamily.error', parsedFamily.error); + } + expect(parsedFamily.success).toBe(true); + + const media = await client.sendRequest(classicWow.creatureFamilyMedia('static-classic', 1)); + const parsedMedia = creatureFamilyMediaResponseSchema.safeParse(media); + if (!parsedMedia.success) { + console.error('Creature family media validation failed:', treeifyError(parsedMedia.error)); + } + expect(parsedMedia.success).toBe(true); + }); + + it('validates creature type index and details', async ({ expect }) => { + const resp = await client.sendRequest(classicWow.creatureTypeIndex('static-classic')); + const parsed = creatureTypeIndexResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Creature type index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + + // eslint-disable-next-line sonarjs/pseudo-random + const creatureTypeIndex = Math.floor(Math.random() * resp.creature_types.length); + const creatureType = resp.creature_types[creatureTypeIndex]; + expect(creatureType).toBeDefined(); + + const type = await client.sendRequest(classicWow.creatureType('static-classic', creatureType!.id)); + const parsedType = creatureTypeResponseSchema.safeParse(type); + if (!parsedType.success) { + console.error('Creature type detail validation failed:', treeifyError(parsedType.error)); + } + expect(parsedType.success).toBe(true); + }); + + it('validates creature search', async ({ expect }) => { + const search = await client.sendRequest( + classicWow.creatureSearch('static-classic', { _page: 1, locale: 'en_GB', name: 'wolf' }), + ); + const parsed = creatureSearchResponseSchema.safeParse(search); + if (!parsed.success) { + console.error('Creature search validation failed:', treeifyError(parsed.error)); + console.log('search', search); + console.log('parsed.error', parsed.error); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/classic-wow/guild-crest.integration.test.ts b/packages/integration-tests/classic-wow/guild-crest.integration.test.ts new file mode 100644 index 00000000..34837b5a --- /dev/null +++ b/packages/integration-tests/classic-wow/guild-crest.integration.test.ts @@ -0,0 +1,23 @@ +import * as classicWow from '@blizzard-api/classic-wow'; +import { createBlizzardApiClient } from '@blizzard-api/client'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { guildCrestComponentsIndexResponseSchema } from '../../../generated/schemas/classic-wow'; + +describe('classic-wow guild crest integration', () => { + it('validates guild crest components index', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'us', + secret: environment.blizzardClientSecret, + }); + + const resp = await client.sendRequest(classicWow.guildCrestComponentsIndex('static-classic1x')); + const parsed = guildCrestComponentsIndexResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Guild crest components index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/classic-wow/guild.integration.test.ts b/packages/integration-tests/classic-wow/guild.integration.test.ts new file mode 100644 index 00000000..4a3d6848 --- /dev/null +++ b/packages/integration-tests/classic-wow/guild.integration.test.ts @@ -0,0 +1,28 @@ +import * as classicWow from '@blizzard-api/classic-wow'; +import { createBlizzardApiClient } from '@blizzard-api/client'; +import { describe, it } from 'vitest'; +import { environment } from '../../../environment'; + +describe('classic-wow guild integration', () => { + it('fetches guild endpoints for raid-drømmen on shekzeer', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const realm = 'shekzeer'; + const guildSlug = 'raid-drømmen'; + + const guildResp = await client.sendRequest(classicWow.guild('profile-classic', realm, guildSlug)); + expect(guildResp).toBeDefined(); + + const achievementsResp = await client.sendRequest( + classicWow.guildAchievements('profile-classic', realm, guildSlug), + ); + expect(achievementsResp).toBeDefined(); + + const rosterResp = await client.sendRequest(classicWow.guildRoster('profile-classic', realm, guildSlug)); + expect(rosterResp).toBeDefined(); + }); +}); diff --git a/packages/integration-tests/classic-wow/item.integration.test.ts b/packages/integration-tests/classic-wow/item.integration.test.ts new file mode 100644 index 00000000..154f61f4 --- /dev/null +++ b/packages/integration-tests/classic-wow/item.integration.test.ts @@ -0,0 +1,23 @@ +import * as classicWow from '@blizzard-api/classic-wow'; +import { createBlizzardApiClient } from '@blizzard-api/client'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { itemClassIndexResponseSchema } from '../../../generated/schemas/classic-wow'; + +describe('classic-wow item integration', () => { + it('validates item class index', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'us', + secret: environment.blizzardClientSecret, + }); + + const resp = await client.sendRequest(classicWow.itemClassIndex('static-classic1x')); + const parsed = itemClassIndexResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Item class index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/classic-wow/media-search.integration.test.ts b/packages/integration-tests/classic-wow/media-search.integration.test.ts new file mode 100644 index 00000000..700d29ef --- /dev/null +++ b/packages/integration-tests/classic-wow/media-search.integration.test.ts @@ -0,0 +1,30 @@ +import * as classicWow from '@blizzard-api/classic-wow'; +import { createBlizzardApiClient } from '@blizzard-api/client'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { mediaSearchResponseSchema } from '../../../generated/schemas/classic-wow'; + +describe('classic-wow media search integration', () => { + it('performs a media search and validates items', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const search = await client.sendRequest(classicWow.mediaSearch('static-classic', { _page: 1 })); + const parsedSearch = mediaSearchResponseSchema.safeParse(search); + if (!parsedSearch.success) { + console.error('Media search validation failed:', treeifyError(parsedSearch.error)); + } + expect(parsedSearch.success).toBe(true); + + const eraSearch = await client.sendRequest(classicWow.mediaSearch('static-classic1x', { _page: 1 })); + const parsedEraSearch = mediaSearchResponseSchema.safeParse(eraSearch); + if (!parsedEraSearch.success) { + console.error('Media search validation failed:', treeifyError(parsedEraSearch.error)); + } + expect(parsedEraSearch.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/classic-wow/playable-class.integration.test.ts b/packages/integration-tests/classic-wow/playable-class.integration.test.ts new file mode 100644 index 00000000..1b2c3367 --- /dev/null +++ b/packages/integration-tests/classic-wow/playable-class.integration.test.ts @@ -0,0 +1,75 @@ +import * as classicWow from '@blizzard-api/classic-wow'; +import { createBlizzardApiClient } from '@blizzard-api/client'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { playableClassMediaResponseSchema, playableClassResponseSchema } from '../../../generated/schemas/classic-wow'; + +describe.concurrent('classic-wow playable class integration', () => { + it('fetches playable class and media by id for classic era', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'us', + secret: environment.blizzardClientSecret, + }); + + const indices = await client.sendRequest(classicWow.playableClassIndex('static-classic1x')); + + const classRequests = []; + const mediaRequests = []; + for (const playerClass of indices.classes) { + classRequests.push(client.sendRequest(classicWow.playableClass('static-classic1x', playerClass.id))); + mediaRequests.push(client.sendRequest(classicWow.playableClassMedia('static-classic1x', playerClass.id))); + } + const responses = await Promise.all(classRequests); + for (const resp of responses) { + const parsed = playableClassResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Playable class validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + } + const mediaResponses = await Promise.all(mediaRequests); + for (const mediaResp of mediaResponses) { + const mediaParsed = playableClassMediaResponseSchema.safeParse(mediaResp); + + if (!mediaParsed.success) { + console.error('Playable class media validation failed:', treeifyError(mediaParsed.error)); + } + expect(mediaParsed.success).toBe(true); + } + }); + it('fetches playable class and media by id for classic', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'us', + secret: environment.blizzardClientSecret, + }); + + const indices = await client.sendRequest(classicWow.playableClassIndex('static-classic')); + + const classRequests = []; + const mediaRequests = []; + for (const playerClass of indices.classes) { + classRequests.push(client.sendRequest(classicWow.playableClass('static-classic', playerClass.id))); + mediaRequests.push(client.sendRequest(classicWow.playableClassMedia('static-classic', playerClass.id))); + } + const responses = await Promise.all(classRequests); + for (const resp of responses) { + const parsed = playableClassResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Playable class validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + } + const mediaResponses = await Promise.all(mediaRequests); + for (const mediaResp of mediaResponses) { + const mediaParsed = playableClassMediaResponseSchema.safeParse(mediaResp); + + if (!mediaParsed.success) { + console.error('Playable class media validation failed:', treeifyError(mediaParsed.error)); + } + expect(mediaParsed.success).toBe(true); + } + }); +}); diff --git a/packages/integration-tests/classic-wow/playable-race.integration.test.ts b/packages/integration-tests/classic-wow/playable-race.integration.test.ts new file mode 100644 index 00000000..7a5f2374 --- /dev/null +++ b/packages/integration-tests/classic-wow/playable-race.integration.test.ts @@ -0,0 +1,71 @@ +import * as classicWow from '@blizzard-api/classic-wow'; +import { createBlizzardApiClient } from '@blizzard-api/client'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { playableRaceIndexResponseSchema, playableRaceResponseSchema } from '../../../generated/schemas/classic-wow'; + +describe.concurrent('classic-wow playable race integration', () => { + it('validates playable races for classic era', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'us', + secret: environment.blizzardClientSecret, + }); + + const resp = await client.sendRequest(classicWow.playableRaceIndex('static-classic1x')); + const parsed = playableRaceIndexResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Playable race index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + + const requests = []; + + for (const race of resp.races) { + requests.push(client.sendRequest(classicWow.playableRace('static-classic1x', race.id))); + } + + const results = await Promise.all(requests); + + for (const result of results) { + const parsedResult = playableRaceResponseSchema.safeParse(result); + if (!parsedResult.success) { + console.error('Race detail validation failed for id', result.id, treeifyError(parsedResult.error)); + } + expect(parsedResult.success).toBe(true); + } + }); + it('validates playable races for classic progression', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'us', + secret: environment.blizzardClientSecret, + }); + + const resp = await client.sendRequest(classicWow.playableRaceIndex('static-classic')); + const parsed = playableRaceIndexResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Playable race index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + + const requests = []; + + for (const race of resp.races) { + requests.push(client.sendRequest(classicWow.playableRace('static-classic', race.id))); + } + + const results = await Promise.all(requests); + + for (const result of results) { + const parsedResult = playableRaceResponseSchema.safeParse(result); + if (!parsedResult.success) { + console.error('Race detail validation failed for id', result.id, treeifyError(parsedResult.error)); + console.log('result', result); + console.log('parsedResult.error', parsedResult.error); + } + expect(parsedResult.success).toBe(true); + } + }); +}); diff --git a/packages/integration-tests/classic-wow/power-type.integration.test.ts b/packages/integration-tests/classic-wow/power-type.integration.test.ts new file mode 100644 index 00000000..b1aff596 --- /dev/null +++ b/packages/integration-tests/classic-wow/power-type.integration.test.ts @@ -0,0 +1,23 @@ +import * as classicWow from '@blizzard-api/classic-wow'; +import { createBlizzardApiClient } from '@blizzard-api/client'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { powerTypeIndexResponseSchema } from '../../../generated/schemas/classic-wow'; + +describe('classic-wow power type integration', () => { + it('validates power type index', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'us', + secret: environment.blizzardClientSecret, + }); + + const resp = await client.sendRequest(classicWow.powerTypeIndex('static-classic1x')); + const parsed = powerTypeIndexResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Power type index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/classic-wow/pvp-season.integration.test.ts b/packages/integration-tests/classic-wow/pvp-season.integration.test.ts new file mode 100644 index 00000000..68edb630 --- /dev/null +++ b/packages/integration-tests/classic-wow/pvp-season.integration.test.ts @@ -0,0 +1,23 @@ +import * as classicWow from '@blizzard-api/classic-wow'; +import { createBlizzardApiClient } from '@blizzard-api/client'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { pvpSeasonIndexResponseSchema } from '../../../generated/schemas/classic-wow'; + +describe('classic-wow pvp season integration', () => { + it('validates pvp season index', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'us', + secret: environment.blizzardClientSecret, + }); + + const resp = await client.sendRequest(classicWow.pvpSeasonIndex('dynamic-classic')); + const parsed = pvpSeasonIndexResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('PvP season index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/classic-wow/realm.integration.test.ts b/packages/integration-tests/classic-wow/realm.integration.test.ts new file mode 100644 index 00000000..eeb6e79a --- /dev/null +++ b/packages/integration-tests/classic-wow/realm.integration.test.ts @@ -0,0 +1,23 @@ +import * as classicWow from '@blizzard-api/classic-wow'; +import { createBlizzardApiClient } from '@blizzard-api/client'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { realmIndexResponseSchema } from '../../../generated/schemas/classic-wow'; + +describe('classic-wow realm integration', () => { + it('validates realm index', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'us', + secret: environment.blizzardClientSecret, + }); + + const resp = await client.sendRequest(classicWow.realmIndex('dynamic-classic1x')); + const parsed = realmIndexResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Realm index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/classic-wow/region.integration.test.ts b/packages/integration-tests/classic-wow/region.integration.test.ts new file mode 100644 index 00000000..2f26a1fa --- /dev/null +++ b/packages/integration-tests/classic-wow/region.integration.test.ts @@ -0,0 +1,23 @@ +import * as classicWow from '@blizzard-api/classic-wow'; +import { createBlizzardApiClient } from '@blizzard-api/client'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { regionIndexResponseSchema } from '../../../generated/schemas/classic-wow'; + +describe('classic-wow region integration', () => { + it('validates region index', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'us', + secret: environment.blizzardClientSecret, + }); + + const resp = await client.sendRequest(classicWow.regionIndex('dynamic-classic1x')); + const parsed = regionIndexResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Region index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/package.json b/packages/integration-tests/package.json new file mode 100644 index 00000000..3dd59539 --- /dev/null +++ b/packages/integration-tests/package.json @@ -0,0 +1,25 @@ +{ + "name": "@blizzard-api/integration-tests", + "version": "0.0.1", + "license": "MIT", + "author": "Putro", + "description": "Integration tests for the Blizzard Battle.net API client", + "repository": "https://github.com/Pewtro/blizzard-api/tree/main/packages/integration-tests", + "type": "module", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "devDependencies": { + "@blizzard-api/classic-wow": "workspace:*", + "@blizzard-api/client": "workspace:*", + "@blizzard-api/core": "workspace:*", + "@blizzard-api/d3": "workspace:*", + "@blizzard-api/hs": "workspace:*", + "@blizzard-api/sc2": "workspace:*", + "@blizzard-api/wow": "workspace:*" + }, + "scripts": { + "test": "vitest run", + "test:watch": "vitest watch" + } +} diff --git a/packages/integration-tests/wow/achievements.integration.test.ts b/packages/integration-tests/wow/achievements.integration.test.ts new file mode 100644 index 00000000..3894ed85 --- /dev/null +++ b/packages/integration-tests/wow/achievements.integration.test.ts @@ -0,0 +1,116 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + achievementCategoryIndexResponseSchema, + achievementCategoryResponseSchema, + achievementIndexResponseSchema, + achievementMediaResponseSchema, + achievementResponseSchema, +} from '../../../generated/schemas/wow/achievements'; + +describe('wow achievements integration', () => { + it('fetches achievement indices and media', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + const index = await client.sendRequest(wow.achievementIndex()); + const parsed = achievementIndexResponseSchema.safeParse(index); + if (!parsed.success) { + console.error('Achievement index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + + // Pick up to 5 achievements at random from the index to fetch details + const achievements = parsed.success ? parsed.data.achievements : []; + const sampleSize = Math.min(5, achievements.length); + const sampled = + achievements.length > sampleSize + ? // eslint-disable-next-line sonarjs/pseudo-random + achievements.toSorted(() => 0.5 - Math.random()).slice(0, sampleSize) + : achievements.slice(0, sampleSize); + + const requests = []; + for (const achievement of sampled) { + requests.push(client.sendRequest(wow.achievement(achievement.id))); + } + + const responses = await Promise.all(requests); + + for (const achievement of responses) { + const parsedAchievement = achievementResponseSchema.safeParse(achievement); + if (!parsedAchievement.success) { + console.error( + 'Achievement detail validation failed for id', + achievement.id, + treeifyError(parsedAchievement.error), + ); + } + expect(parsedAchievement.success).toBe(true); + } + }); + + it('validates achievement categories and media', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const catIndex = await client.sendRequest(wow.achievementCategoryIndex()); + const parsedCatIndex = achievementCategoryIndexResponseSchema.safeParse(catIndex); + if (!parsedCatIndex.success) { + console.error('Achievement category index validation failed:', treeifyError(parsedCatIndex.error)); + } + expect(parsedCatIndex.success).toBe(true); + + const categories = parsedCatIndex.success ? parsedCatIndex.data.categories : []; + const sampleSize = Math.min(50, categories.length); + const sampledCats = + categories.length > sampleSize + ? // eslint-disable-next-line sonarjs/pseudo-random + categories.toSorted(() => 0.5 - Math.random()).slice(0, sampleSize) + : categories.slice(0, sampleSize); + + const catRequests = []; + for (const c of sampledCats) { + catRequests.push(client.sendRequest(wow.achievementCategory(c.id))); + } + + const catResponses = await Promise.all(catRequests); + for (const cr of catResponses) { + const parsedCat = achievementCategoryResponseSchema.safeParse(cr); + if (!parsedCat.success) { + console.error('Achievement category validation failed for id', cr.id, treeifyError(parsedCat.error)); + } + expect(parsedCat.success).toBe(true); + } + + // Validate media for some achievements from the original index + const achievementsList = await client.sendRequest(wow.achievementIndex()); + const parsedIndexAgain = achievementIndexResponseSchema.safeParse(achievementsList); + if (!parsedIndexAgain.success) { + console.error('Achievement index revalidation failed:', treeifyError(parsedIndexAgain.error)); + } + expect(parsedIndexAgain.success).toBe(true); + + const achs = parsedIndexAgain.success ? parsedIndexAgain.data.achievements : []; + const mediaSample = achs.slice(0, Math.min(5, achs.length)); + const mediaRequests = []; + for (const a of mediaSample) { + mediaRequests.push(client.sendRequest(wow.achievementMedia(a.id))); + } + const mediaResponses = await Promise.all(mediaRequests); + for (const m of mediaResponses) { + const parsedMedia = achievementMediaResponseSchema.safeParse(m); + if (!parsedMedia.success) { + console.error('Achievement media validation failed for id', m.id, treeifyError(parsedMedia.error)); + } + expect(parsedMedia.success).toBe(true); + } + }); +}); diff --git a/packages/integration-tests/wow/auction-house.integration.test.ts b/packages/integration-tests/wow/auction-house.integration.test.ts new file mode 100644 index 00000000..c1c0170a --- /dev/null +++ b/packages/integration-tests/wow/auction-house.integration.test.ts @@ -0,0 +1,43 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + auctionHouseCommoditiesResponseSchema, + auctionHouseResponseSchema, +} from '../../../generated/schemas/wow/auction-house'; + +describe('wow auction-house integration', () => { + it('validates auctions and commodities responses', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const realms = await client.sendRequest(wow.connectedRealmIndex()); + const firstConnectedRealm = realms.connected_realms.find((cr) => cr.href); + if (!firstConnectedRealm) { + throw new Error('No connected realms found for testing auction house'); + } + const realmId = firstConnectedRealm.href.split('/').at(-1)?.split('?')[0]; + if (!realmId) { + throw new Error('No realm ID found for testing auction house'); + } + + const auctions = await client.sendRequest(wow.auctions(Number.parseInt(realmId))); + const parsedAuctions = auctionHouseResponseSchema.safeParse(auctions); + if (!parsedAuctions.success) { + console.error('Auctions validation failed:', treeifyError(parsedAuctions.error)); + } + expect(parsedAuctions.success).toBe(true); + + const commodities = await client.sendRequest(wow.commodities()); + const parsedCommodities = auctionHouseCommoditiesResponseSchema.safeParse(commodities); + if (!parsedCommodities.success) { + console.error('Commodities validation failed:', treeifyError(parsedCommodities.error)); + } + expect(parsedCommodities.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/azerite-essence.integration.test.ts b/packages/integration-tests/wow/azerite-essence.integration.test.ts new file mode 100644 index 00000000..fb2d4bad --- /dev/null +++ b/packages/integration-tests/wow/azerite-essence.integration.test.ts @@ -0,0 +1,69 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + azeriteEssenceIndexResponseSchema, + azeriteEssenceMediaResponseSchema, + azeriteEssenceResponseSchema, + azeriteEssenceSearchResponseSchema, +} from '../../../generated/schemas/wow/azerite-essence'; + +describe('wow azerite-essence integration', () => { + it('validates azerite essence index and search', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const index = await client.sendRequest(wow.azeriteEssenceIndex()); + const parsedIndex = azeriteEssenceIndexResponseSchema.safeParse(index); + if (!parsedIndex.success) { + console.error('Azerite essence index validation failed:', treeifyError(parsedIndex.error)); + } + expect(parsedIndex.success).toBe(true); + + const search = await client.sendRequest(wow.azeriteEssenceSearch({ _page: 1 })); + const parsedSearch = azeriteEssenceSearchResponseSchema.safeParse(search); + if (!parsedSearch.success) { + console.error('Azerite essence search validation failed:', treeifyError(parsedSearch.error)); + } + expect(parsedSearch.success).toBe(true); + + // Fetch some detail and media for a few essences from the index + const essences = parsedIndex.success ? parsedIndex.data.azerite_essences : []; + const sampleSize = Math.min(5, essences.length); + const sampled = + essences.length > sampleSize + ? // eslint-disable-next-line sonarjs/pseudo-random + essences.toSorted(() => 0.5 - Math.random()).slice(0, sampleSize) + : essences.slice(0, sampleSize); + + const detailRequests: Array> = []; + const mediaRequests: Array> = []; + for (const essence of sampled) { + detailRequests.push(client.sendRequest(wow.azeriteEssence(essence.id))); + mediaRequests.push(client.sendRequest(wow.azeriteEssenceMedia(essence.id))); + } + + const details = await Promise.all(detailRequests); + for (const d of details) { + const parsed = azeriteEssenceResponseSchema.safeParse(d); + if (!parsed.success) { + console.error('Azerite essence detail validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + } + + const medias = await Promise.all(mediaRequests); + for (const m of medias) { + const parsed = azeriteEssenceMediaResponseSchema.safeParse(m); + if (!parsed.success) { + console.error('Azerite essence media validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + } + }); +}); diff --git a/packages/integration-tests/wow/character-achievements.integration.test.ts b/packages/integration-tests/wow/character-achievements.integration.test.ts new file mode 100644 index 00000000..830b5236 --- /dev/null +++ b/packages/integration-tests/wow/character-achievements.integration.test.ts @@ -0,0 +1,35 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + characterAchievementsSummaryResponseSchema, + characterAchievementStatisticsResponseSchema, +} from '../../../generated/schemas/wow'; + +describe('wow character-achievements integration', () => { + it('validates character achievements summary and statistics', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + const realm = 'laughing-skull'; + const character = 'putro'; + + const summary = await client.sendRequest(wow.characterAchievementsSummary(realm, character)); + const parsedSummary = characterAchievementsSummaryResponseSchema.safeParse(summary); + if (!parsedSummary.success) { + console.error('Character achievements summary validation failed:', treeifyError(parsedSummary.error)); + } + expect(parsedSummary.success).toBe(true); + + const stats = await client.sendRequest(wow.characterAchievementStatistics(realm, character)); + const parsedStats = characterAchievementStatisticsResponseSchema.safeParse(stats); + if (!parsedStats.success) { + console.error('Character achievement statistics validation failed:', treeifyError(parsedStats.error)); + } + expect(parsedStats.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/character-appearance.integration.test.ts b/packages/integration-tests/wow/character-appearance.integration.test.ts new file mode 100644 index 00000000..a67736a5 --- /dev/null +++ b/packages/integration-tests/wow/character-appearance.integration.test.ts @@ -0,0 +1,24 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { characterAppearanceResponseSchema } from '../../../generated/schemas/wow'; + +describe('wow character-appearance integration', () => { + it('validates character appearance', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + const realm = 'laughing-skull'; + const character = 'putro'; + const resp = await client.sendRequest(wow.characterAppearanceSummary(realm, character)); + const parsed = characterAppearanceResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Character appearance validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/character-collections.integration.test.ts b/packages/integration-tests/wow/character-collections.integration.test.ts new file mode 100644 index 00000000..7a094541 --- /dev/null +++ b/packages/integration-tests/wow/character-collections.integration.test.ts @@ -0,0 +1,76 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + characterCollectionsIndexResponseSchema, + characterHeirloomsCollectionSummaryResponseSchema, + characterMountsCollectionSummaryResponseSchema, + characterPetsCollectionSummaryResponseSchema, + characterToysCollectionSummaryResponseSchema, + characterTransmogCollectionSummaryResponseSchema, +} from '../../../generated/schemas/wow'; + +describe.concurrent('wow character-collections integration', async () => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + const realm = 'laughing-skull'; + const character = 'putro'; + it('validates collections indices', async ({ expect }) => { + const index = await client.sendRequest(wow.characterCollectionsIndex(realm, character)); + const parsedIndex = characterCollectionsIndexResponseSchema.safeParse(index); + if (!parsedIndex.success) { + console.error('Character collections index validation failed:', treeifyError(parsedIndex.error)); + } + expect(parsedIndex.success).toBe(true); + }); + + it('validates heirlooms collection summary', async ({ expect }) => { + const heirlooms = await client.sendRequest(wow.characterHeirloomsCollectionSummary(realm, character)); + const parsedHeirlooms = characterHeirloomsCollectionSummaryResponseSchema.safeParse(heirlooms); + if (!parsedHeirlooms.success) { + console.error('Character heirlooms collection validation failed:', treeifyError(parsedHeirlooms.error)); + } + expect(parsedHeirlooms.success).toBe(true); + }); + + it('validates mounts collection summary', async ({ expect }) => { + const mounts = await client.sendRequest(wow.characterMountsCollectionSummary(realm, character)); + const parsedMounts = characterMountsCollectionSummaryResponseSchema.safeParse(mounts); + if (!parsedMounts.success) { + console.error('Character mounts collection validation failed:', treeifyError(parsedMounts.error)); + } + expect(parsedMounts.success).toBe(true); + }); + + it('validates pets collection summary', async ({ expect }) => { + const pets = await client.sendRequest(wow.characterPetsCollectionSummary(realm, character)); + const parsedPets = characterPetsCollectionSummaryResponseSchema.safeParse(pets); + if (!parsedPets.success) { + console.error('Character pets collection validation failed:', treeifyError(parsedPets.error)); + } + expect(parsedPets.success).toBe(true); + }); + + it('validates toys collection summary', async ({ expect }) => { + const toys = await client.sendRequest(wow.characterToysCollectionSummary(realm, character)); + const parsedToys = characterToysCollectionSummaryResponseSchema.safeParse(toys); + if (!parsedToys.success) { + console.error('Character toys collection validation failed:', treeifyError(parsedToys.error)); + } + expect(parsedToys.success).toBe(true); + }); + + it('validates transmog collection summary', async ({ expect }) => { + const transmog = await client.sendRequest(wow.characterTransmogCollectionSummary(realm, character)); + const parsedTransmog = characterTransmogCollectionSummaryResponseSchema.safeParse(transmog); + if (!parsedTransmog.success) { + console.error('Character transmog collection validation failed:', treeifyError(parsedTransmog.error)); + } + expect(parsedTransmog.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/character-encounters.integration.test.ts b/packages/integration-tests/wow/character-encounters.integration.test.ts new file mode 100644 index 00000000..9c7b5d57 --- /dev/null +++ b/packages/integration-tests/wow/character-encounters.integration.test.ts @@ -0,0 +1,43 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + characterDungeonsResponseSchema, + characterEncountersSummaryResponseSchema, + characterRaidsResponseSchema, +} from '../../../generated/schemas/wow'; + +describe('wow character-encounters integration', () => { + it('validates character encounters', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + const realm = 'laughing-skull'; + const character = 'putro'; + const encounters = await client.sendRequest(wow.characterEncountersSummary(realm, character)); + const parsed = characterEncountersSummaryResponseSchema.safeParse(encounters); + if (!parsed.success) { + console.error('Character encounters validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + + // Validate dungeons and raids endpoints referenced by the summary + const dungeons = await client.sendRequest(wow.characterDungeons(realm, character)); + const parsedDungeons = characterDungeonsResponseSchema.safeParse(dungeons); + if (!parsedDungeons.success) { + console.error('Character dungeons validation failed:', treeifyError(parsedDungeons.error)); + } + expect(parsedDungeons.success).toBe(true); + + const raids = await client.sendRequest(wow.characterRaids(realm, character)); + const parsedRaids = characterRaidsResponseSchema.safeParse(raids); + if (!parsedRaids.success) { + console.error('Character raids validation failed:', treeifyError(parsedRaids.error)); + } + expect(parsedRaids.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/character-equipment.integration.test.ts b/packages/integration-tests/wow/character-equipment.integration.test.ts new file mode 100644 index 00000000..dae75781 --- /dev/null +++ b/packages/integration-tests/wow/character-equipment.integration.test.ts @@ -0,0 +1,26 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { characterEquipmentSummaryResponseSchema } from '../../../generated/schemas/wow'; + +describe('wow character equipment integration', () => { + it('fetches equipment summary for a character', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const realm = 'laughing-skull'; + const character = 'putro'; + + const resp = await client.sendRequest(wow.characterEquipmentSummary(realm, character)); + const parsed = characterEquipmentSummaryResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Character equipment summary validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/character-hunter-pets.integration.test.ts b/packages/integration-tests/wow/character-hunter-pets.integration.test.ts new file mode 100644 index 00000000..e29dd7d3 --- /dev/null +++ b/packages/integration-tests/wow/character-hunter-pets.integration.test.ts @@ -0,0 +1,24 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { characterHunterPetsSummaryResponseSchema } from '../../../generated/schemas/wow'; + +describe('wow character-hunter-pets integration', () => { + it('validates character hunter pets', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + const realm = 'laughing-skull'; + const character = 'putro'; + const resp = await client.sendRequest(wow.characterHunterPetsSummary(realm, character)); + const parsed = characterHunterPetsSummaryResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Character hunter pets validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/character-media.integration.test.ts b/packages/integration-tests/wow/character-media.integration.test.ts new file mode 100644 index 00000000..0a667f66 --- /dev/null +++ b/packages/integration-tests/wow/character-media.integration.test.ts @@ -0,0 +1,26 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { characterMediaSummaryResponseSchema } from '../../../generated/schemas/wow'; + +describe('wow character media integration', () => { + it('fetches media summary for a character', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const realm = 'laughing-skull'; + const character = 'putro'; + + const resp = await client.sendRequest(wow.characterMediaSummary(realm, character)); + const parsed = characterMediaSummaryResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Character media summary validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/character-mythic-keystone-profile.integration.test.ts b/packages/integration-tests/wow/character-mythic-keystone-profile.integration.test.ts new file mode 100644 index 00000000..fff7e1d7 --- /dev/null +++ b/packages/integration-tests/wow/character-mythic-keystone-profile.integration.test.ts @@ -0,0 +1,54 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + characterMythicKeystoneProfileIndexResponseSchema, + characterMythicKeystoneSeasonDetailsResponseSchema, +} from '../../../generated/schemas/wow'; + +describe('wow character-mythic-keystone-profile integration', () => { + it('validates mythic keystone profile index', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + const realm = 'laughing-skull'; + const character = 'putro'; + const index = await client.sendRequest(wow.characterMythicKeystoneProfileIndex(realm, character)); + const parsed = characterMythicKeystoneProfileIndexResponseSchema.safeParse(index); + if (!parsed.success) { + console.error('Character mythic keystone profile index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); + + it('validates mythic keystone season details when available', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + const realm = 'laughing-skull'; + const character = 'putro'; + + const index = await client.sendRequest(wow.characterMythicKeystoneProfileIndex(realm, character)); + const parsedIndex = characterMythicKeystoneProfileIndexResponseSchema.safeParse(index); + if (!parsedIndex.success) { + console.error('Character mythic keystone profile index validation failed:', treeifyError(parsedIndex.error)); + } + expect(parsedIndex.success).toBe(true); + + const seasonId = index.seasons.at(0)?.id; + const details = await client.sendRequest(wow.characterMythicKeystoneSeasonDetails(realm, character, seasonId!)); + const parsedDetails = characterMythicKeystoneSeasonDetailsResponseSchema.safeParse(details); + if (!parsedDetails.success) { + console.error('Character mythic keystone season details validation failed:', treeifyError(parsedDetails.error)); + console.log('details', details); + console.log('parsedDetails', parsedDetails.error); + } + expect(parsedDetails.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/character-professions.integration.test.ts b/packages/integration-tests/wow/character-professions.integration.test.ts new file mode 100644 index 00000000..f31f0806 --- /dev/null +++ b/packages/integration-tests/wow/character-professions.integration.test.ts @@ -0,0 +1,24 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { characterProfessionsSummaryResponseSchema } from '../../../generated/schemas/wow'; + +describe('wow character-professions integration', () => { + it('validates character professions', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + const realm = 'laughing-skull'; + const character = 'putro'; + const resp = await client.sendRequest(wow.characterProfessionsSummary(realm, character)); + const parsed = characterProfessionsSummaryResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Character professions validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/character-profile.integration.test.ts b/packages/integration-tests/wow/character-profile.integration.test.ts new file mode 100644 index 00000000..cf534790 --- /dev/null +++ b/packages/integration-tests/wow/character-profile.integration.test.ts @@ -0,0 +1,35 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + characterProfileStatusResponseSchema, + characterProfileSummaryResponseSchema, +} from '../../../generated/schemas/wow'; + +describe('wow character-profile integration', () => { + it('validates character profile summary and status', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + const realm = 'laughing-skull'; + const character = 'putro'; + + const summary = await client.sendRequest(wow.characterProfileSummary(realm, character)); + const parsedSummary = characterProfileSummaryResponseSchema.safeParse(summary); + if (!parsedSummary.success) { + console.error('Character profile summary validation failed:', treeifyError(parsedSummary.error)); + } + expect(parsedSummary.success).toBe(true); + + const status = await client.sendRequest(wow.characterProfileStatus(realm, character)); + const parsedStatus = characterProfileStatusResponseSchema.safeParse(status); + if (!parsedStatus.success) { + console.error('Character profile status validation failed:', treeifyError(parsedStatus.error)); + } + expect(parsedStatus.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/character-pvp.integration.test.ts b/packages/integration-tests/wow/character-pvp.integration.test.ts new file mode 100644 index 00000000..2c39bb6b --- /dev/null +++ b/packages/integration-tests/wow/character-pvp.integration.test.ts @@ -0,0 +1,44 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + characterPvpBracketStatisticsResponseSchema, + characterPvpSummaryResponseSchema, +} from '../../../generated/schemas/wow'; + +describe('wow character-pvp integration', () => { + it('validates character pvp summary', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + const realm = 'laughing-skull'; + const character = 'putro'; + const resp = await client.sendRequest(wow.characterPvpSummary(realm, character)); + const parsed = characterPvpSummaryResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Character pvp summary validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); + + it('validates character pvp bracket statistics', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + const realm = 'laughing-skull'; + const character = 'voidshuffle'; + + const bracketResp = await client.sendRequest(wow.characterPvpBracketStatistics(realm, character, '2v2')); + const parsedBracket = characterPvpBracketStatisticsResponseSchema.safeParse(bracketResp); + if (!parsedBracket.success) { + console.error('Character pvp bracket validation failed:', treeifyError(parsedBracket.error)); + } + expect(parsedBracket.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/character-quests.integration.test.ts b/packages/integration-tests/wow/character-quests.integration.test.ts new file mode 100644 index 00000000..7946b7ad --- /dev/null +++ b/packages/integration-tests/wow/character-quests.integration.test.ts @@ -0,0 +1,41 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { characterCompletedQuestsResponseSchema, characterQuestsResponseSchema } from '../../../generated/schemas/wow'; + +describe('wow character-quests integration', () => { + it('validates character quests', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + const realm = 'laughing-skull'; + const character = 'putro'; + const resp = await client.sendRequest(wow.characterQuests(realm, character)); + const parsed = characterQuestsResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Character quests validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); + + it('validates completed quests', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + const realm = 'laughing-skull'; + const character = 'putro'; + + const completed = await client.sendRequest(wow.characterCompletedQuests(realm, character)); + const parsedCompleted = characterCompletedQuestsResponseSchema.safeParse(completed); + if (!parsedCompleted.success) { + console.error('Character completed quests validation failed:', treeifyError(parsedCompleted.error)); + } + expect(parsedCompleted.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/character-reputations.integration.test.ts b/packages/integration-tests/wow/character-reputations.integration.test.ts new file mode 100644 index 00000000..14d69550 --- /dev/null +++ b/packages/integration-tests/wow/character-reputations.integration.test.ts @@ -0,0 +1,24 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { characterReputationsSummaryResponseSchema } from '../../../generated/schemas/wow'; + +describe('wow character-reputations integration', () => { + it('validates character reputations', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + const realm = 'laughing-skull'; + const character = 'putro'; + const resp = await client.sendRequest(wow.characterReputationsSummary(realm, character)); + const parsed = characterReputationsSummaryResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Character reputations validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/character-soulbinds.integration.test.ts b/packages/integration-tests/wow/character-soulbinds.integration.test.ts new file mode 100644 index 00000000..99a1b087 --- /dev/null +++ b/packages/integration-tests/wow/character-soulbinds.integration.test.ts @@ -0,0 +1,24 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { characterSoulbindsResponseSchema } from '../../../generated/schemas/wow'; + +describe('wow character-soulbinds integration', () => { + it('validates character soulbinds', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + const realm = 'laughing-skull'; + const character = 'putro'; + const resp = await client.sendRequest(wow.characterSoulbinds(realm, character)); + const parsed = characterSoulbindsResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Character soulbinds validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/character-specializations.integration.test.ts b/packages/integration-tests/wow/character-specializations.integration.test.ts new file mode 100644 index 00000000..d1668051 --- /dev/null +++ b/packages/integration-tests/wow/character-specializations.integration.test.ts @@ -0,0 +1,24 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { characterSpecializationsSummaryResponseSchema } from '../../../generated/schemas/wow'; + +describe('wow character-specializations integration', () => { + it('validates character specializations', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + const realm = 'laughing-skull'; + const character = 'putro'; + const resp = await client.sendRequest(wow.characterSpecializationsSummary(realm, character)); + const parsed = characterSpecializationsSummaryResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Character specializations validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/character-statistics.integration.test.ts b/packages/integration-tests/wow/character-statistics.integration.test.ts new file mode 100644 index 00000000..8a6a2a52 --- /dev/null +++ b/packages/integration-tests/wow/character-statistics.integration.test.ts @@ -0,0 +1,26 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { characterStatisticsSummaryResponseSchema } from '../../../generated/schemas/wow'; + +describe('wow character statistics integration', () => { + it('fetches statistics summary for a character', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const realm = 'laughing-skull'; + const character = 'putro'; + + const resp = await client.sendRequest(wow.characterStatisticsSummary(realm, character)); + const parsed = characterStatisticsSummaryResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Character statistics summary validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/character-titles.integration.test.ts b/packages/integration-tests/wow/character-titles.integration.test.ts new file mode 100644 index 00000000..c64e6e0c --- /dev/null +++ b/packages/integration-tests/wow/character-titles.integration.test.ts @@ -0,0 +1,24 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { characterTitlesSummaryResponseSchema } from '../../../generated/schemas/wow'; + +describe('wow character-titles integration', () => { + it('validates character titles', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + const realm = 'laughing-skull'; + const character = 'putro'; + const resp = await client.sendRequest(wow.characterTitlesSummary(realm, character)); + const parsed = characterTitlesSummaryResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Character titles validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/connected-realm.integration.test.ts b/packages/integration-tests/wow/connected-realm.integration.test.ts new file mode 100644 index 00000000..e7b38a21 --- /dev/null +++ b/packages/integration-tests/wow/connected-realm.integration.test.ts @@ -0,0 +1,38 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { connectedRealmIndexResponseSchema, connectedRealmSearchResponseSchema } from '../../../generated/schemas/wow'; + +describe('wow connected realm integration', () => { + it('validates connected realm index', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const resp = await client.sendRequest(wow.connectedRealmIndex()); + const parsed = connectedRealmIndexResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Connected realm index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); + + it('validates connected realm search', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const search = await client.sendRequest(wow.connectedRealmSearch({ _page: 1 })); + const parsed = connectedRealmSearchResponseSchema.safeParse(search); + if (!parsed.success) { + console.error('Connected realm search validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/covenant.integration.test.ts b/packages/integration-tests/wow/covenant.integration.test.ts new file mode 100644 index 00000000..daaa4975 --- /dev/null +++ b/packages/integration-tests/wow/covenant.integration.test.ts @@ -0,0 +1,105 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + conduitIndexResponseSchema, + conduitResponseSchema, + covenantIndexResponseSchema, + covenantMediaResponseSchema, + covenantResponseSchema, + soulbindIndexResponseSchema, + soulbindResponseSchema, +} from '../../../generated/schemas/wow/covenant'; + +describe.concurrent('wow covenant integration', async () => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + it('validates covenant index and fetches details', async ({ expect }) => { + const covIndex = await client.sendRequest(wow.covenantIndex()); + const parsedCov = covenantIndexResponseSchema.safeParse(covIndex); + if (!parsedCov.success) { + console.error('Covenant index validation failed:', treeifyError(parsedCov.error)); + } + expect(parsedCov.success).toBe(true); + + const requests = []; + + for (const cov of covIndex.covenants) { + requests.push(client.sendRequest(wow.covenant(cov.id))); + } + const responses = await Promise.all(requests); + for (const covenant of responses) { + const parsedDetail = covenantResponseSchema.safeParse(covenant); + if (!parsedDetail.success) { + console.error('Covenant detail validation failed:', treeifyError(parsedDetail.error)); + } + expect(parsedDetail.success).toBe(true); + + const media = await client.sendRequest(wow.covenantMedia(covenant.id)); + const parsedMedia = covenantMediaResponseSchema.safeParse(media); + if (!parsedMedia.success) { + console.error('Covenant media validation failed:', treeifyError(parsedMedia.error)); + } + expect(parsedMedia.success).toBe(true); + } + }); + it('validates soulbind index and fetches details', async ({ expect }) => { + const soulIndex = await client.sendRequest(wow.soulbindIndex()); + const parsedSoul = soulbindIndexResponseSchema.safeParse(soulIndex); + if (!parsedSoul.success) { + console.error('Soulbind index validation failed:', treeifyError(parsedSoul.error)); + } + expect(parsedSoul.success).toBe(true); + + const requests = []; + for (const soul of parsedSoul.success ? parsedSoul.data.soulbinds : []) { + requests.push(client.sendRequest(wow.soulbind(soul.id))); + } + const responses = await Promise.all(requests); + + for (const soulbind of responses) { + const parsedDetail = soulbindResponseSchema.safeParse(soulbind); + if (!parsedDetail.success) { + console.error('Soulbind detail validation failed:', treeifyError(parsedDetail.error)); + } + expect(parsedDetail.success).toBe(true); + } + }); + + it('validates conduit index and fetches details', async ({ expect }) => { + const conduitIndex = await client.sendRequest(wow.conduitIndex()); + const parsedConduit = conduitIndexResponseSchema.safeParse(conduitIndex); + if (!parsedConduit.success) { + console.error('Conduit index validation failed:', treeifyError(parsedConduit.error)); + } + expect(parsedConduit.success).toBe(true); + + // Pick up to 5 conduits at random from the index to fetch details + const conduits = parsedConduit.success ? parsedConduit.data.conduits : []; + const sampleSize = Math.min(5, conduits.length); + const sampled = + conduits.length > sampleSize + ? // eslint-disable-next-line sonarjs/pseudo-random + conduits.toSorted(() => 0.5 - Math.random()).slice(0, sampleSize) + : conduits.slice(0, sampleSize); + + const requests = []; + for (const conduit of sampled) { + requests.push(client.sendRequest(wow.conduit(conduit.id))); + } + const responses = await Promise.all(requests); + + for (const conduit of responses) { + const parsedDetail = conduitResponseSchema.safeParse(conduit); + if (!parsedDetail.success) { + console.error('Conduit detail validation failed:', treeifyError(parsedDetail.error)); + } + expect(parsedDetail.success).toBe(true); + } + }); +}); diff --git a/packages/integration-tests/wow/creature.integration.test.ts b/packages/integration-tests/wow/creature.integration.test.ts new file mode 100644 index 00000000..c4bf3e11 --- /dev/null +++ b/packages/integration-tests/wow/creature.integration.test.ts @@ -0,0 +1,87 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + creatureFamilyIndexResponseSchema, + creatureFamilyMediaResponseSchema, + creatureFamilyResponseSchema, + creatureSearchResponseSchema, + creatureTypeIndexResponseSchema, + creatureTypeResponseSchema, +} from '../../../generated/schemas/wow/creature'; + +describe('wow creature integration', () => { + it('validates creature family index', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const resp = await client.sendRequest(wow.creatureFamilyIndex()); + const parsed = creatureFamilyIndexResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Creature family index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + + const first = parsed.success ? parsed.data.creature_families[0] : undefined; + if (first) { + const detail = await client.sendRequest(wow.creatureFamily(first.id)); + const parsedDetail = creatureFamilyResponseSchema.safeParse(detail); + if (!parsedDetail.success) { + console.error('Creature family detail validation failed:', treeifyError(parsedDetail.error)); + } + expect(parsedDetail.success).toBe(true); + + const media = await client.sendRequest(wow.creatureFamilyMedia(first.id)); + const parsedMedia = creatureFamilyMediaResponseSchema.safeParse(media); + if (!parsedMedia.success) { + console.error('Creature family media validation failed:', treeifyError(parsedMedia.error)); + } + expect(parsedMedia.success).toBe(true); + } + }); + + it('validates creature search', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const search = await client.sendRequest(wow.creatureSearch({ _page: 1, locale: 'en_GB', name: 'dragon' })); + const parsed = creatureSearchResponseSchema.safeParse(search); + if (!parsed.success) { + console.error('Creature search validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); + + it('validates creature type index', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const resp = await client.sendRequest(wow.creatureTypeIndex()); + const parsed = creatureTypeIndexResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Creature type index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + + const first = parsed.success ? parsed.data.creature_types[0] : undefined; + if (first) { + const detail = await client.sendRequest(wow.creatureType(first.id)); + const parsedDetail = creatureTypeResponseSchema.safeParse(detail); + if (!parsedDetail.success) { + console.error('Creature type detail validation failed:', treeifyError(parsedDetail.error)); + } + expect(parsedDetail.success).toBe(true); + } + }); +}); diff --git a/packages/integration-tests/wow/guild-crest.integration.test.ts b/packages/integration-tests/wow/guild-crest.integration.test.ts new file mode 100644 index 00000000..18cb578a --- /dev/null +++ b/packages/integration-tests/wow/guild-crest.integration.test.ts @@ -0,0 +1,23 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { guildCrestComponentsIndexResponseSchema } from '../../../generated/schemas/wow'; + +describe('wow guild crest integration', () => { + it('validates guild crest components index', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const resp = await client.sendRequest(wow.guildCrestComponentsIndex()); + const parsed = guildCrestComponentsIndexResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Guild crest components index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/guild.integration.test.ts b/packages/integration-tests/wow/guild.integration.test.ts new file mode 100644 index 00000000..e3727965 --- /dev/null +++ b/packages/integration-tests/wow/guild.integration.test.ts @@ -0,0 +1,52 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + guildAchievementsResponseSchema, + guildActivityResponseSchema, + guildResponseSchema, + guildRosterResponseSchema, +} from '../../../generated/schemas/wow/guild'; + +describe('wow guild integration', () => { + it('fetches guild endpoints for echoes on laughing-skull', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const realm = 'laughing-skull'; + const guildSlug = 'echoes'; + + const guildResp = await client.sendRequest(wow.guild(realm, guildSlug)); + const parsedGuild = guildResponseSchema.safeParse(guildResp); + if (!parsedGuild.success) { + console.error('Guild validation failed:', treeifyError(parsedGuild.error)); + } + expect(parsedGuild.success).toBe(true); + + const achievementsResp = await client.sendRequest(wow.guildAchievements(realm, guildSlug)); + const parsedAchievements = guildAchievementsResponseSchema.safeParse(achievementsResp); + if (!parsedAchievements.success) { + console.error('Guild achievements validation failed:', treeifyError(parsedAchievements.error)); + } + expect(parsedAchievements.success).toBe(true); + + const rosterResp = await client.sendRequest(wow.guildRoster(realm, guildSlug)); + const parsedRoster = guildRosterResponseSchema.safeParse(rosterResp); + if (!parsedRoster.success) { + console.error('Guild roster validation failed:', treeifyError(parsedRoster.error)); + } + expect(parsedRoster.success).toBe(true); + + const activityResp = await client.sendRequest(wow.guildActivity(realm, guildSlug)); + const parsedActivity = guildActivityResponseSchema.safeParse(activityResp); + if (!parsedActivity.success) { + console.error('Guild activity validation failed:', treeifyError(parsedActivity.error)); + } + expect(parsedActivity.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/heirloom.integration.test.ts b/packages/integration-tests/wow/heirloom.integration.test.ts new file mode 100644 index 00000000..f4850ab4 --- /dev/null +++ b/packages/integration-tests/wow/heirloom.integration.test.ts @@ -0,0 +1,32 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { heirloomIndexResponseSchema, heirloomResponseSchema } from '../../../generated/schemas/wow/heirloom'; + +describe('wow heirloom integration', () => { + it('validates heirloom index and fetches heirloom detail', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + const index = await client.sendRequest(wow.heirloomIndex()); + const parsed = heirloomIndexResponseSchema.safeParse(index); + if (!parsed.success) { + console.error('Heirloom index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + + const first = parsed.success ? parsed.data.heirlooms[0] : undefined; + if (first) { + const item = await client.sendRequest(wow.heirloom(first.id)); + const parsedItem = heirloomResponseSchema.safeParse(item); + if (!parsedItem.success) { + console.error('Heirloom detail validation failed:', treeifyError(parsedItem.error)); + } + expect(parsedItem.success).toBe(true); + } + }); +}); diff --git a/packages/integration-tests/wow/item.integration.test.ts b/packages/integration-tests/wow/item.integration.test.ts new file mode 100644 index 00000000..7c1d5492 --- /dev/null +++ b/packages/integration-tests/wow/item.integration.test.ts @@ -0,0 +1,97 @@ +/* eslint-disable sonarjs/pseudo-random */ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + itemClassIndexResponseSchema, + itemClassResponseSchema, + itemMediaResponseSchema, + itemResponseSchema, + itemSearchResponseSchema, + itemSetIndexResponseSchema, + itemSetResponseSchema, + itemSubClassResponseSchema, +} from '../../../generated/schemas/wow/item'; + +describe.concurrent('wow item integration', async () => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + it('validates item and item media', async ({ expect }) => { + const resp = await client.sendRequest(wow.item(19_019)); + const parsed = itemResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Item validation failed', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + + const respMedia = await client.sendRequest(wow.itemMedia(19_019)); + const parsedMedia = itemMediaResponseSchema.safeParse(respMedia); + if (!parsedMedia.success) { + console.error('Item media validation failed', treeifyError(parsedMedia.error)); + } + expect(parsedMedia.success).toBe(true); + }); + it('validates item class index', async ({ expect }) => { + const resp = await client.sendRequest(wow.itemClassIndex()); + const parsed = itemClassIndexResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Item class index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + + const itemClassIndex = Math.floor(Math.random() * resp.item_classes.length); + const itemClass = resp.item_classes[itemClassIndex]; + + expect(itemClass).toBeDefined(); + + const detail = await client.sendRequest(wow.itemClass(itemClass!.id)); + const parsedDetail = itemClassResponseSchema.safeParse(detail); + if (!parsedDetail.success) { + console.error('Item class detail validation failed:', treeifyError(parsedDetail.error)); + } + expect(parsedDetail.success).toBe(true); + + const subClassIndex = Math.floor(Math.random() * detail.item_subclasses.length); + const subClass = detail.item_subclasses[subClassIndex]; + + const subDetail = await client.sendRequest(wow.itemSubClass(itemClass!.id, subClass!.id)); + const parsedSubDetail = itemSubClassResponseSchema.safeParse(subDetail); + if (!parsedSubDetail.success) { + console.error('Item subclass detail validation failed:', treeifyError(parsedSubDetail.error)); + } + expect(parsedSubDetail.success).toBe(true); + }); + + it('validates item sets', async ({ expect }) => { + const setIndex = await client.sendRequest(wow.itemSetIndex()); + const parsedSetIndex = itemSetIndexResponseSchema.safeParse(setIndex); + if (!parsedSetIndex.success) { + console.error('Item set index validation failed:', treeifyError(parsedSetIndex.error)); + } + expect(parsedSetIndex.success).toBe(true); + + const first = parsedSetIndex.success ? parsedSetIndex.data.item_sets[0] : undefined; + if (first) { + const set = await client.sendRequest(wow.itemSet(first.id)); + const parsedSet = itemSetResponseSchema.safeParse(set); + if (!parsedSet.success) { + console.error('Item set detail validation failed:', treeifyError(parsedSet.error)); + } + expect(parsedSet.success).toBe(true); + } + }); + + it('validates item search', async ({ expect }) => { + const search = await client.sendRequest(wow.itemSearch({ _page: 1, locale: 'en_GB', name: 'Glaive' })); + const parsed = itemSearchResponseSchema.safeParse(search); + if (!parsed.success) { + console.error('Item search validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/journal.integration.test.ts b/packages/integration-tests/wow/journal.integration.test.ts new file mode 100644 index 00000000..88827fb7 --- /dev/null +++ b/packages/integration-tests/wow/journal.integration.test.ts @@ -0,0 +1,183 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + journalEncounterIndexResponseSchema, + journalEncounterResponseSchema, + journalEncounterSearchResponseSchema, + journalExpansionIndexResponseSchema, + journalExpansionResponseSchema, + journalInstanceIndexResponseSchema, + journalInstanceMediaResponseSchema, + journalInstanceResponseSchema, +} from '../../../generated/schemas/wow/journal'; + +describe.concurrent('wow journal integration', () => { + it('validates journal encounter index and details', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + const enc = await client.sendRequest(wow.journalEncounterIndex()); + const parsedEnc = journalEncounterIndexResponseSchema.safeParse(enc); + if (!parsedEnc.success) { + console.error('Journal encounter index validation failed:', treeifyError(parsedEnc.error)); + } + expect(parsedEnc.success).toBe(true); + + // Pick up to 5 encounters at random from the index to fetch details + const encounters = parsedEnc.success ? parsedEnc.data.encounters : []; + const sampleSize = Math.min(5, encounters.length); + const sampledEncounters = + encounters.length > sampleSize + ? // eslint-disable-next-line sonarjs/pseudo-random + encounters.toSorted(() => 0.5 - Math.random()).slice(0, sampleSize) + : encounters.slice(0, sampleSize); + + const encounterRequests = []; + + for (const encounter of sampledEncounters) { + encounterRequests.push(client.sendRequest(wow.journalEncounter(encounter.id))); + } + const encounterResponses = await Promise.all(encounterRequests); + for (const encounter of encounterResponses) { + const parsedEncounter = journalEncounterResponseSchema.safeParse(encounter); + if (!parsedEncounter.success) { + console.error( + 'Journal encounter detail validation failed for id', + encounter.id, + treeifyError(parsedEncounter.error), + ); + } + expect(parsedEncounter.success).toBe(true); + } + }); + it('validates journal expansion index and details', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const exp = await client.sendRequest(wow.journalExpansionIndex()); + const parsedExp = journalExpansionIndexResponseSchema.safeParse(exp); + if (!parsedExp.success) { + console.error('Journal expansion index validation failed:', treeifyError(parsedExp.error)); + } + expect(parsedExp.success).toBe(true); + + // Pick up to 5 expansions at random from the index to fetch details + const expansions = parsedExp.success ? parsedExp.data.tiers : []; + const sampleSize = Math.min(5, expansions.length); + const sampledExpansions = + expansions.length > sampleSize + ? // eslint-disable-next-line sonarjs/pseudo-random + expansions.toSorted(() => 0.5 - Math.random()).slice(0, sampleSize) + : expansions.slice(0, sampleSize); + + const expansionRequests = []; + + for (const expansion of sampledExpansions) { + expansionRequests.push(client.sendRequest(wow.journalExpansion(expansion.id))); + } + const expansionResponses = await Promise.all(expansionRequests); + for (const expansion of expansionResponses) { + const parsedExpansion = journalExpansionResponseSchema.safeParse(expansion); + if (!parsedExpansion.success) { + console.error( + 'Journal expansion detail validation failed for id', + expansion.id, + treeifyError(parsedExpansion.error), + ); + } + expect(parsedExpansion.success).toBe(true); + } + }); + + it('validates journal instance index and details', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const instanceResp = await client.sendRequest(wow.journalInstanceIndex()); + const parsedExp = journalInstanceIndexResponseSchema.safeParse(instanceResp); + if (!parsedExp.success) { + console.error('Journal instance index validation failed:', treeifyError(parsedExp.error)); + } + expect(parsedExp.success).toBe(true); + + // Pick up to 5 instances at random from the index to fetch details + const instances = parsedExp.success ? parsedExp.data.instances : []; + const sampleSize = Math.min(5, instances.length); + const sampledInstances = + instances.length > sampleSize + ? // eslint-disable-next-line sonarjs/pseudo-random + instances.toSorted(() => 0.5 - Math.random()).slice(0, sampleSize) + : instances.slice(0, sampleSize); + + const instanceRequests = []; + + for (const instance of sampledInstances) { + instanceRequests.push(client.sendRequest(wow.journalInstance(instance.id))); + } + const instanceResponses = await Promise.all(instanceRequests); + for (const instance of instanceResponses) { + const parsedInstance = journalInstanceResponseSchema.safeParse(instance); + if (!parsedInstance.success) { + console.error( + 'Journal instance detail validation failed for id', + instance.id, + treeifyError(parsedInstance.error), + ); + } + expect(parsedInstance.success).toBe(true); + } + }); + + it('validates journal encounter search', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const search = await client.sendRequest( + wow.journalEncounterSearch({ _page: 1, instanceName: 'raid', locale: 'en_GB' }), + ); + const parsed = journalEncounterSearchResponseSchema.safeParse(search); + if (!parsed.success) { + console.error('Journal encounter search validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); + + it('validates journal instance media', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const instanceResp = await client.sendRequest(wow.journalInstanceIndex()); + const parsedExp = journalInstanceIndexResponseSchema.safeParse(instanceResp); + if (!parsedExp.success) { + console.error('Journal instance index validation failed:', treeifyError(parsedExp.error)); + } + expect(parsedExp.success).toBe(true); + + const instances = parsedExp.success ? parsedExp.data.instances : []; + if (instances.length > 0) { + const media = await client.sendRequest(wow.journalInstanceMedia(instances[0]!.id)); + const parsedMedia = journalInstanceMediaResponseSchema.safeParse(media); + if (!parsedMedia.success) { + console.error('Journal instance media validation failed:', treeifyError(parsedMedia.error)); + } + expect(parsedMedia.success).toBe(true); + } + }); +}); diff --git a/packages/integration-tests/wow/media-search.integration.test.ts b/packages/integration-tests/wow/media-search.integration.test.ts new file mode 100644 index 00000000..6073f3bc --- /dev/null +++ b/packages/integration-tests/wow/media-search.integration.test.ts @@ -0,0 +1,23 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { mediaSearchResponseSchema } from '../../../generated/schemas/wow'; + +describe('wow media search integration', () => { + it('performs a media search and validates items', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const search = await client.sendRequest(wow.mediaSearch({ _page: 1 })); + const parsedSearch = mediaSearchResponseSchema.safeParse(search); + if (!parsedSearch.success) { + console.error('Media search validation failed:', treeifyError(parsedSearch.error)); + } + expect(parsedSearch.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/modified-crafting.integration.test.ts b/packages/integration-tests/wow/modified-crafting.integration.test.ts new file mode 100644 index 00000000..25ba46b1 --- /dev/null +++ b/packages/integration-tests/wow/modified-crafting.integration.test.ts @@ -0,0 +1,89 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + modifiedCraftingCategoryIndexResponseSchema, + modifiedCraftingCategoryResponseSchema, + modifiedCraftingIndexResponseSchema, + modifiedCraftingReagentSlotTypeIndexResponseSchema, + modifiedCraftingReagentSlotTypeResponseSchema, +} from '../../../generated/schemas/wow/modified-crafting'; + +describe('wow modified-crafting integration', () => { + it('validates modified crafting category index and fetches detail', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + const index = await client.sendRequest(wow.modifiedCraftingCategoryIndex()); + const parsed = modifiedCraftingCategoryIndexResponseSchema.safeParse(index); + if (!parsed.success) { + console.error('Modified crafting category index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + + // Pick up to 5 categories at random from the index to fetch details + const categories = parsed.success ? parsed.data.categories : []; + const sampleSize = Math.min(5, categories.length); + const sampled = + categories.length > sampleSize + ? // eslint-disable-next-line sonarjs/pseudo-random + categories.toSorted(() => 0.5 - Math.random()).slice(0, sampleSize) + : categories.slice(0, sampleSize); + + const requests = []; + + for (const c of sampled) { + requests.push(client.sendRequest(wow.modifiedCraftingCategory(c.id))); + } + const responses = await Promise.all(requests); + for (const category of responses) { + const parsedCategory = modifiedCraftingCategoryResponseSchema.safeParse(category); + if (!parsedCategory.success) { + console.error('Modified crafting category detail validation failed:', treeifyError(parsedCategory.error)); + } + expect(parsedCategory.success).toBe(true); + } + }); + + it('validates modified crafting index and reagent slot types', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const index = await client.sendRequest(wow.modifiedCraftingIndex()); + const parsed = modifiedCraftingIndexResponseSchema.safeParse(index); + if (!parsed.success) { + console.error('Modified crafting index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + + const slotTypeIndex = await client.sendRequest(wow.modifiedCraftingReagentSlotTypeIndex()); + const parsedSlotIndex = modifiedCraftingReagentSlotTypeIndexResponseSchema.safeParse(slotTypeIndex); + if (!parsedSlotIndex.success) { + console.error( + 'Modified crafting reagent slot type index validation failed:', + treeifyError(parsedSlotIndex.error), + ); + } + expect(parsedSlotIndex.success).toBe(true); + + const slotTypes = parsedSlotIndex.success ? parsedSlotIndex.data.slot_types : []; + if (slotTypes.length > 0) { + const slotType = await client.sendRequest(wow.modifiedCraftingReagentSlotType(slotTypes[0]!.id)); + const parsedSlotType = modifiedCraftingReagentSlotTypeResponseSchema.safeParse(slotType); + if (!parsedSlotType.success) { + console.error( + 'Modified crafting reagent slot type detail validation failed:', + treeifyError(parsedSlotType.error), + ); + } + expect(parsedSlotType.success).toBe(true); + } + }); +}); diff --git a/packages/integration-tests/wow/mount.integration.test.ts b/packages/integration-tests/wow/mount.integration.test.ts new file mode 100644 index 00000000..c25d7ef1 --- /dev/null +++ b/packages/integration-tests/wow/mount.integration.test.ts @@ -0,0 +1,66 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + mountIndexResponseSchema, + mountResponseSchema, + mountSearchResponseSchema, +} from '../../../generated/schemas/wow/mount'; + +describe('wow mount integration', () => { + it('validates mount index and fetches mount detail', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + const index = await client.sendRequest(wow.mountIndex()); + const parsed = mountIndexResponseSchema.safeParse(index); + if (!parsed.success) { + console.error('Mount index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + + // Pick up to 5 mounts at random from the index to fetch details + const mounts = parsed.success ? parsed.data.mounts : []; + const sampleSize = Math.min(5, mounts.length); + const sampled = + mounts.length > sampleSize + ? // eslint-disable-next-line sonarjs/pseudo-random + mounts.toSorted(() => 0.5 - Math.random()).slice(0, sampleSize) + : mounts.slice(0, sampleSize); + + const requests = []; + + for (const t of sampled) { + requests.push(client.sendRequest(wow.mount(t.id))); + } + const responses = await Promise.all(requests); + for (const mount of responses) { + const parsedmount = mountResponseSchema.safeParse(mount); + if (!parsedmount.success) { + console.error('mount detail validation failed for id', mount.id, treeifyError(parsedmount.error)); + } + expect(parsedmount.success).toBe(true); + } + }); + + it('validates mount search', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const search = await client.sendRequest(wow.mountSearch({ _page: 1, locale: 'en_GB', name: 'Horse' })); + const parsed = mountSearchResponseSchema.safeParse(search); + if (!parsed.success) { + console.error('Mount search validation failed:', treeifyError(parsed.error)); + console.log('search', search); + console.log('parsed.error', parsed.error); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/mythic-keystone-affix.integration.test.ts b/packages/integration-tests/wow/mythic-keystone-affix.integration.test.ts new file mode 100644 index 00000000..e5e37633 --- /dev/null +++ b/packages/integration-tests/wow/mythic-keystone-affix.integration.test.ts @@ -0,0 +1,61 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + mythicKeystoneAffixIndexResponseSchema, + mythicKeystoneAffixMediaResponseSchema, + mythicKeystoneAffixResponseSchema, +} from '../../../generated/schemas/wow/mythic-keystone-affix'; + +describe('wow mythic-keystone-affix integration', () => { + it('validates index, detail and media', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const index = await client.sendRequest(wow.mythicKeystoneAffixIndex()); + const parsedIndex = mythicKeystoneAffixIndexResponseSchema.safeParse(index); + if (!parsedIndex.success) { + console.error('Mythic keystone affix index validation failed:', treeifyError(parsedIndex.error)); + } + expect(parsedIndex.success).toBe(true); + + const affixes = parsedIndex.success ? parsedIndex.data.affixes : []; + const sampleSize = Math.min(5, affixes.length); + const sampled = + affixes.length > sampleSize + ? // eslint-disable-next-line sonarjs/pseudo-random + affixes.toSorted(() => 0.5 - Math.random()).slice(0, sampleSize) + : affixes.slice(0, sampleSize); + + const detailRequests = []; + const mediaRequests = []; + + for (const a of sampled) { + detailRequests.push(client.sendRequest(wow.mythicKeystoneAffix(a.id))); + mediaRequests.push(client.sendRequest(wow.mythicKeystoneAffixMedia(a.id))); + } + + const details = await Promise.all(detailRequests); + for (const d of details) { + const parsed = mythicKeystoneAffixResponseSchema.safeParse(d); + if (!parsed.success) { + console.error('Mythic keystone affix detail validation failed for id', d.id, treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + } + + const medias = await Promise.all(mediaRequests); + for (const m of medias) { + const parsed = mythicKeystoneAffixMediaResponseSchema.safeParse(m); + if (!parsed.success) { + console.error('Mythic keystone affix media validation failed for id', m.id, treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + } + }); +}); diff --git a/packages/integration-tests/wow/mythic-keystone-dungeon.integration.test.ts b/packages/integration-tests/wow/mythic-keystone-dungeon.integration.test.ts new file mode 100644 index 00000000..ac6e9684 --- /dev/null +++ b/packages/integration-tests/wow/mythic-keystone-dungeon.integration.test.ts @@ -0,0 +1,48 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + mythicKeystoneDungeonIndexResponseSchema, + mythicKeystoneDungeonResponseSchema, +} from '../../../generated/schemas/wow/mythic-keystone-dungeon'; + +describe('wow mythic-keystone-dungeon integration', () => { + it('validates dungeon index and details', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const index = await client.sendRequest(wow.mythicKeystoneDungeonIndex()); + const parsed = mythicKeystoneDungeonIndexResponseSchema.safeParse(index); + if (!parsed.success) { + console.error('Mythic keystone dungeon index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + + const dungeons = parsed.success ? parsed.data.dungeons : []; + const sampleSize = Math.min(5, dungeons.length); + const sampled = + dungeons.length > sampleSize + ? // eslint-disable-next-line sonarjs/pseudo-random + dungeons.toSorted(() => 0.5 - Math.random()).slice(0, sampleSize) + : dungeons.slice(0, sampleSize); + + const requests = []; + for (const d of sampled) { + requests.push(client.sendRequest(wow.mythicKeystoneDungeon(d.id))); + } + + const responses = await Promise.all(requests); + for (const r of responses) { + const parsedResp = mythicKeystoneDungeonResponseSchema.safeParse(r); + if (!parsedResp.success) { + console.error('Mythic keystone dungeon detail validation failed for id', r.id, treeifyError(parsedResp.error)); + } + expect(parsedResp.success).toBe(true); + } + }); +}); diff --git a/packages/integration-tests/wow/mythic-keystone-leaderboard.integration.test.ts b/packages/integration-tests/wow/mythic-keystone-leaderboard.integration.test.ts new file mode 100644 index 00000000..513234c0 --- /dev/null +++ b/packages/integration-tests/wow/mythic-keystone-leaderboard.integration.test.ts @@ -0,0 +1,33 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + mythicKeystoneLeaderboardIndexResponseSchema, + mythicKeystoneLeaderboardResponseSchema, +} from '../../../generated/schemas/wow/mythic-keystone-leaderboard'; + +describe('wow mythic-keystone-leaderboard integration', () => { + it('fetches leaderboard index and a leaderboard for a connected realm', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'us', + secret: environment.blizzardClientSecret, + }); + + const index = await client.sendRequest(wow.mythicKeystoneLeaderboardIndex(11)); + const parsedIndex = mythicKeystoneLeaderboardIndexResponseSchema.safeParse(index); + if (!parsedIndex.success) { + console.error('Mythic keystone leaderboard index validation failed:', treeifyError(parsedIndex.error)); + } + expect(parsedIndex.success).toBe(true); + + const leaderboard = await client.sendRequest(wow.mythicKeystoneLeaderboard(11, 197, 641)); + const parsedLeaderboard = mythicKeystoneLeaderboardResponseSchema.safeParse(leaderboard); + if (!parsedLeaderboard.success) { + console.error('Mythic keystone leaderboard validation failed:', treeifyError(parsedLeaderboard.error)); + } + expect(parsedLeaderboard.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/mythic-raid-leaderboard.integration.test.ts b/packages/integration-tests/wow/mythic-raid-leaderboard.integration.test.ts new file mode 100644 index 00000000..cea64c83 --- /dev/null +++ b/packages/integration-tests/wow/mythic-raid-leaderboard.integration.test.ts @@ -0,0 +1,23 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { mythicRaidLeaderboardResponseSchema } from '../../../generated/schemas/wow/mythic-raid-leaderboard'; + +describe('wow mythic-raid-leaderboard integration', () => { + it('fetches a raid leaderboard for a known instance slug', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const resp = await client.sendRequest(wow.mythicRaidLeaderboard('uldir', 'alliance')); + const parsedResp = mythicRaidLeaderboardResponseSchema.safeParse(resp); + if (!parsedResp.success) { + console.error('Mythic raid leaderboard validation failed for uldir', treeifyError(parsedResp.error)); + } + expect(parsedResp.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/pet.integration.test.ts b/packages/integration-tests/wow/pet.integration.test.ts new file mode 100644 index 00000000..9be0d303 --- /dev/null +++ b/packages/integration-tests/wow/pet.integration.test.ts @@ -0,0 +1,122 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + petAbilityIndexResponseSchema, + petAbilityMediaResponseSchema, + petAbilityResponseSchema, + petIndexResponseSchema, + petMediaResponseSchema, + petResponseSchema, +} from '../../../generated/schemas/wow/pet'; + +describe('wow pet integration', () => { + it('validates pet index and fetches pet detail', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + const index = await client.sendRequest(wow.petIndex()); + const parsed = petIndexResponseSchema.safeParse(index); + if (!parsed.success) { + console.error('Pet index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + + // Pick up to 5 pets at random from the index to fetch details + const pets = parsed.success ? parsed.data.pets : []; + const sampleSize = Math.min(5, pets.length); + const sampled = + pets.length > sampleSize + ? // eslint-disable-next-line sonarjs/pseudo-random + pets.toSorted(() => 0.5 - Math.random()).slice(0, sampleSize) + : pets.slice(0, sampleSize); + + const requests = []; + + for (const t of sampled) { + requests.push(client.sendRequest(wow.pet(t.id))); + } + const responses = await Promise.all(requests); + for (const pet of responses) { + const parsedPet = petResponseSchema.safeParse(pet); + if (!parsedPet.success) { + console.error('Pet detail validation failed for id', pet.id, treeifyError(parsedPet.error)); + } + expect(parsedPet.success).toBe(true); + } + }); + + it('validates pet abilities and media', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const abilityIndex = await client.sendRequest(wow.petAbilityIndex()); + const parsedAbilityIndex = petAbilityIndexResponseSchema.safeParse(abilityIndex); + if (!parsedAbilityIndex.success) { + console.error('Pet ability index validation failed:', treeifyError(parsedAbilityIndex.error)); + } + expect(parsedAbilityIndex.success).toBe(true); + + const abilities = parsedAbilityIndex.success ? parsedAbilityIndex.data.abilities : []; + const sampleSize = Math.min(5, abilities.length); + const sampled = + abilities.length > sampleSize + ? // eslint-disable-next-line sonarjs/pseudo-random + abilities.toSorted(() => 0.5 - Math.random()).slice(0, sampleSize) + : abilities.slice(0, sampleSize); + + for (const ability of sampled) { + const detail = await client.sendRequest(wow.petAbility(ability.id)); + const parsedDetail = petAbilityResponseSchema.safeParse(detail); + if (!parsedDetail.success) { + console.error('Pet ability detail validation failed for id', ability.id, treeifyError(parsedDetail.error)); + } + expect(parsedDetail.success).toBe(true); + + const media = await client.sendRequest(wow.petAbilityMedia(ability.id)); + const parsedMedia = petAbilityMediaResponseSchema.safeParse(media); + if (!parsedMedia.success) { + console.error('Pet ability media validation failed for id', ability.id, treeifyError(parsedMedia.error)); + } + expect(parsedMedia.success).toBe(true); + } + + const petIndex = await client.sendRequest(wow.petIndex()); + const parsedPetIndex = petIndexResponseSchema.safeParse(petIndex); + if (!parsedPetIndex.success) { + console.error('Pet index validation failed:', treeifyError(parsedPetIndex.error)); + } + expect(parsedPetIndex.success).toBe(true); + + // Pick up to 5 pets at random from the index to fetch details + const pets = petIndex.pets; + const petSampleSize = Math.min(5, pets.length); + const petSampled = + pets.length > petSampleSize + ? // eslint-disable-next-line sonarjs/pseudo-random + pets.toSorted(() => 0.5 - Math.random()).slice(0, petSampleSize) + : pets.slice(0, petSampleSize); + + const requests = []; + + for (const pet of petSampled) { + requests.push(client.sendRequest(wow.petMedia(pet.id))); + } + const responses = await Promise.all(requests); + + for (const pet of responses) { + const parsedPetMedia = petMediaResponseSchema.safeParse(pet); + if (!parsedPetMedia.success) { + console.error('Pet media validation failed for id', pet.id, treeifyError(parsedPetMedia.error)); + } + expect(parsedPetMedia.success).toBe(true); + } + }); +}); diff --git a/packages/integration-tests/wow/playable-class.integration.test.ts b/packages/integration-tests/wow/playable-class.integration.test.ts new file mode 100644 index 00000000..94f87ac5 --- /dev/null +++ b/packages/integration-tests/wow/playable-class.integration.test.ts @@ -0,0 +1,52 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + playableClassIndexResponseSchema, + playableClassMediaResponseSchema, + playableClassResponseSchema, + pvpTalentSlotsResponseSchema, +} from '../../../generated/schemas/wow/playable-class'; + +describe.concurrent('wow playable class integration', () => { + it('fetches playable class and media by id', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const index = await client.sendRequest(wow.playableClassIndex()); + const parsedIndex = playableClassIndexResponseSchema.safeParse(index); + if (!parsedIndex.success) { + console.error('Playable class index validation failed:', treeifyError(parsedIndex.error)); + } + expect(parsedIndex.success).toBe(true); + + const first = parsedIndex.success ? parsedIndex.data.classes[0] : undefined; + if (first) { + const resp = await client.sendRequest(wow.playableClass(first.id)); + const parsed = playableClassResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Playable class validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + + const media = await client.sendRequest(wow.playableClassMedia(first.id)); + const parsedMedia = playableClassMediaResponseSchema.safeParse(media); + if (!parsedMedia.success) { + console.error('Playable class media validation failed:', treeifyError(parsedMedia.error)); + } + expect(parsedMedia.success).toBe(true); + + const pvpSlots = await client.sendRequest(wow.pvpTalentSlots(first.id)); + const parsedPvpSlots = pvpTalentSlotsResponseSchema.safeParse(pvpSlots); + if (!parsedPvpSlots.success) { + console.error('Playable class PvP talent slots validation failed:', treeifyError(parsedPvpSlots.error)); + } + expect(parsedPvpSlots.success).toBe(true); + } + }); +}); diff --git a/packages/integration-tests/wow/playable-race.integration.test.ts b/packages/integration-tests/wow/playable-race.integration.test.ts new file mode 100644 index 00000000..31d71515 --- /dev/null +++ b/packages/integration-tests/wow/playable-race.integration.test.ts @@ -0,0 +1,39 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { playableRaceIndexResponseSchema, playableRaceResponseSchema } from '../../../generated/schemas/wow'; + +describe('wow playable race integration', () => { + it('validates playable races', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'us', + secret: environment.blizzardClientSecret, + }); + + const resp = await client.sendRequest(wow.playableRaceIndex()); + const parsed = playableRaceIndexResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Playable race index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + + const requests = []; + + for (const race of resp.races) { + requests.push(client.sendRequest(wow.playableRace(race.id))); + } + + const results = await Promise.all(requests); + + for (const result of results) { + const parsedResult = playableRaceResponseSchema.safeParse(result); + if (!parsedResult.success) { + console.error('Race detail validation failed for id', result.id, treeifyError(parsedResult.error)); + } + expect(parsedResult.success).toBe(true); + } + }); +}); diff --git a/packages/integration-tests/wow/playable-specialization.integration.test.ts b/packages/integration-tests/wow/playable-specialization.integration.test.ts new file mode 100644 index 00000000..328fa379 --- /dev/null +++ b/packages/integration-tests/wow/playable-specialization.integration.test.ts @@ -0,0 +1,47 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + playableSpecializationIndexResponseSchema, + playableSpecializationMediaResponseSchema, + playableSpecializationResponseSchema, +} from '../../../generated/schemas/wow/playable-specialization'; + +describe('wow playable-specialization integration', () => { + it('validates playable specialization index and fetches detail', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + const index = await client.sendRequest(wow.playableSpecializationIndex()); + const parsed = playableSpecializationIndexResponseSchema.safeParse(index); + if (!parsed.success) { + console.error('Playable specialization index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + + const requests = []; + for (const specialization of index.character_specializations) { + requests.push(client.sendRequest(wow.playableSpecialization(specialization.id))); + } + const responses = await Promise.all(requests); + for (const spec of responses) { + const parsedSpec = playableSpecializationResponseSchema.safeParse(spec); + if (!parsedSpec.success) { + console.error('Playable specialization detail validation failed:', treeifyError(parsedSpec.error)); + } + + expect(parsedSpec.success).toBe(true); + + const media = await client.sendRequest(wow.playableSpecializationMedia(spec.id)); + const parsedMedia = playableSpecializationMediaResponseSchema.safeParse(media); + if (!parsedMedia.success) { + console.error('Playable specialization media validation failed:', treeifyError(parsedMedia.error)); + } + expect(parsedMedia.success).toBe(true); + } + }, 10_000); +}); diff --git a/packages/integration-tests/wow/power-type.integration.test.ts b/packages/integration-tests/wow/power-type.integration.test.ts new file mode 100644 index 00000000..6e801718 --- /dev/null +++ b/packages/integration-tests/wow/power-type.integration.test.ts @@ -0,0 +1,33 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { powerTypeIndexResponseSchema, powerTypeResponseSchema } from '../../../generated/schemas/wow'; + +describe('wow power type integration', () => { + it('validates power type index', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'us', + secret: environment.blizzardClientSecret, + }); + + const resp = await client.sendRequest(wow.powerTypeIndex()); + const parsed = powerTypeIndexResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Power type index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + + const first = parsed.success ? parsed.data.power_types[0] : undefined; + if (first) { + const type = await client.sendRequest(wow.powerType(first.id)); + const parsedType = powerTypeResponseSchema.safeParse(type); + if (!parsedType.success) { + console.error('Power type detail validation failed:', treeifyError(parsedType.error)); + } + expect(parsedType.success).toBe(true); + } + }); +}); diff --git a/packages/integration-tests/wow/profession.integration.test.ts b/packages/integration-tests/wow/profession.integration.test.ts new file mode 100644 index 00000000..87cafbcd --- /dev/null +++ b/packages/integration-tests/wow/profession.integration.test.ts @@ -0,0 +1,82 @@ +/* eslint-disable sonarjs/pseudo-random */ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + professionIndexResponseSchema, + professionMediaResponseSchema, + professionResponseSchema, + professionSkillTierResponseSchema, + recipeMediaResponseSchema, + recipeResponseSchema, +} from '../../../generated/schemas/wow/profession'; + +describe('wow profession integration', () => { + it('validates profession index and fetches profession detail', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + const index = await client.sendRequest(wow.professionIndex()); + const parsedIndex = professionIndexResponseSchema.safeParse(index); + if (!parsedIndex.success) { + console.error('Profession index validation failed:', treeifyError(parsedIndex.error)); + } + expect(parsedIndex.success).toBe(true); + + const first = parsedIndex.data?.professions[0]; + + expect(first).toBeDefined(); + + const prof = await client.sendRequest(wow.profession(first!.id)); + const parsedProf = professionResponseSchema.safeParse(prof); + if (!parsedProf.success) { + console.error('Profession detail validation failed:', treeifyError(parsedProf.error)); + } + expect(parsedProf.success).toBe(true); + + const media = await client.sendRequest(wow.professionMedia(first!.id)); + const parsedMedia = professionMediaResponseSchema.safeParse(media); + if (!parsedMedia.success) { + console.error('Profession media validation failed:', treeifyError(parsedMedia.error)); + } + expect(parsedMedia.success).toBe(true); + + const skillTierId = + parsedProf.data?.skill_tiers[Math.floor(Math.random() * parsedProf.data?.skill_tiers.length)]?.id; + + expect(skillTierId).toBeDefined(); + const tier = await client.sendRequest(wow.professionSkillTier(first!.id, skillTierId!)); + const parsedTier = professionSkillTierResponseSchema.safeParse(tier); + if (!parsedTier.success) { + console.error('Profession skill tier detail validation failed:', treeifyError(parsedTier.error)); + } + expect(parsedTier.success).toBe(true); + + const categoryIndex = Math.floor(Math.random() * (parsedTier.data?.categories.length ?? 0)); + const recipeLength = parsedTier.data?.categories[categoryIndex]?.recipes.length; + const recipeIndex = Math.floor(Math.random() * (recipeLength ?? 0)); + const recipeId = parsedTier.data?.categories[categoryIndex]?.recipes[recipeIndex]?.id; + + expect(recipeId).toBeDefined(); + + const recipe = await client.sendRequest(wow.recipe(recipeId!)); + const parsedRecipe = recipeResponseSchema.safeParse(recipe); + if (!parsedRecipe.success) { + console.error('Recipe detail validation failed:', recipeId, treeifyError(parsedRecipe.error)); + console.log('recipe', recipe); + console.log('parsedrecipe.error', parsedRecipe.error); + } + expect(parsedRecipe.success).toBe(true); + + const recipeMedia = await client.sendRequest(wow.recipeMedia(recipeId!)); + const parsedRecipeMedia = recipeMediaResponseSchema.safeParse(recipeMedia); + if (!parsedRecipeMedia.success) { + console.error('Recipe media validation failed:', treeifyError(parsedRecipeMedia.error)); + } + expect(parsedRecipeMedia.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/pvp-season.integration.test.ts b/packages/integration-tests/wow/pvp-season.integration.test.ts new file mode 100644 index 00000000..0b39cf25 --- /dev/null +++ b/packages/integration-tests/wow/pvp-season.integration.test.ts @@ -0,0 +1,62 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + pvpLeaderboardIndexResponseSchema, + pvpLeaderboardResponseSchema, + pvpRewardsIndexResponseSchema, + pvpSeasonIndexResponseSchema, + pvpSeasonResponseSchema, +} from '../../../generated/schemas/wow/pvp-season'; + +describe('wow pvp integration', () => { + it('validates pvp leaderboard and season indices', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const season = await client.sendRequest(wow.pvpSeasonIndex()); + const parsedSeason = pvpSeasonIndexResponseSchema.safeParse(season); + if (!parsedSeason.success) { + console.error('PVP season index validation failed:', treeifyError(parsedSeason.error)); + } + expect(parsedSeason.success).toBe(true); + + const seasonId = parsedSeason.success ? parsedSeason.data.current_season.id : undefined; + if (seasonId) { + const seasonDetail = await client.sendRequest(wow.pvpSeason(seasonId)); + const parsedSeasonDetail = pvpSeasonResponseSchema.safeParse(seasonDetail); + if (!parsedSeasonDetail.success) { + console.error('PVP season detail validation failed:', treeifyError(parsedSeasonDetail.error)); + } + expect(parsedSeasonDetail.success).toBe(true); + + const rewards = await client.sendRequest(wow.pvpRewardsIndex(seasonId)); + const parsedRewards = pvpRewardsIndexResponseSchema.safeParse(rewards); + if (!parsedRewards.success) { + console.error('PVP rewards index validation failed:', treeifyError(parsedRewards.error)); + } + expect(parsedRewards.success).toBe(true); + } + + const leaderboardIndex = await client.sendRequest(wow.pvpLeaderboardIndex(season.current_season.id)); + const parsedLeaderboardIndex = pvpLeaderboardIndexResponseSchema.safeParse(leaderboardIndex); + if (!parsedLeaderboardIndex.success) { + console.error('PVP leaderboard index validation failed:', treeifyError(parsedLeaderboardIndex.error)); + } + expect(parsedLeaderboardIndex.success).toBe(true); + + const leaderboard = await client.sendRequest(wow.pvpLeaderboard(season.current_season.id, '3v3')); + const parsedLeaderboard = pvpLeaderboardResponseSchema.safeParse(leaderboard); + if (!parsedLeaderboard.success) { + console.error('PVP leaderboard detail validation failed:', treeifyError(parsedLeaderboard.error)); + console.log('leaderboard', leaderboard); + console.log('parsedLeaderboard.error', parsedLeaderboard.error); + } + expect(parsedLeaderboard.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/pvp-tier.integration.test.ts b/packages/integration-tests/wow/pvp-tier.integration.test.ts new file mode 100644 index 00000000..70f96bf3 --- /dev/null +++ b/packages/integration-tests/wow/pvp-tier.integration.test.ts @@ -0,0 +1,60 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + pvpTierIndexResponseSchema, + pvpTierMediaResponseSchema, + pvpTierResponseSchema, +} from '../../../generated/schemas/wow/pvp-tier'; + +describe('wow pvp-tier integration', () => { + it('validates pvp tier index, detail and media', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const index = await client.sendRequest(wow.pvpTierIndex()); + const parsedIndex = pvpTierIndexResponseSchema.safeParse(index); + if (!parsedIndex.success) { + console.error('PvP tier index validation failed:', treeifyError(parsedIndex.error)); + } + expect(parsedIndex.success).toBe(true); + + const tiers = parsedIndex.success ? parsedIndex.data.tiers : []; + const sampleSize = Math.min(5, tiers.length); + const sampled = + tiers.length > sampleSize + ? // eslint-disable-next-line sonarjs/pseudo-random + tiers.toSorted(() => 0.5 - Math.random()).slice(0, sampleSize) + : tiers.slice(0, sampleSize); + + const detailRequests = []; + const mediaRequests = []; + for (const t of sampled) { + detailRequests.push(client.sendRequest(wow.pvpTier(t.id))); + mediaRequests.push(client.sendRequest(wow.pvpTierMedia(t.id))); + } + + const details = await Promise.all(detailRequests); + for (const d of details) { + const parsed = pvpTierResponseSchema.safeParse(d); + if (!parsed.success) { + console.error('PvP tier detail validation failed for id', d.id, treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + } + + const medias = await Promise.all(mediaRequests); + for (const m of medias) { + const parsed = pvpTierMediaResponseSchema.safeParse(m); + if (!parsed.success) { + console.error('PvP tier media validation failed for id', m.id, treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + } + }); +}); diff --git a/packages/integration-tests/wow/quest.integration.test.ts b/packages/integration-tests/wow/quest.integration.test.ts new file mode 100644 index 00000000..2298e360 --- /dev/null +++ b/packages/integration-tests/wow/quest.integration.test.ts @@ -0,0 +1,97 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + questAreaIndexResponseSchema, + questAreaResponseSchema, + questCategoryIndexResponseSchema, + questCategoryResponseSchema, + questIndexResponseSchema, + questResponseSchema, + questTypeIndexResponseSchema, + questTypeResponseSchema, +} from '../../../generated/schemas/wow/quest'; + +describe('wow quest integration', () => { + it('validates quest index and fetches quest detail', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + const index = await client.sendRequest(wow.questIndex()); + const parsed = questIndexResponseSchema.safeParse(index); + if (!parsed.success) { + console.error('Quest index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + + const quest = await client.sendRequest(wow.quest(32_370)); + const parsedQuest = questResponseSchema.safeParse(quest); + if (!parsedQuest.success) { + console.error('Quest detail validation failed:', treeifyError(parsedQuest.error)); + } + expect(parsedQuest.success).toBe(true); + }); + + it('validates quest areas, categories, and types', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const areaIndex = await client.sendRequest(wow.questAreaIndex()); + const parsedAreaIndex = questAreaIndexResponseSchema.safeParse(areaIndex); + if (!parsedAreaIndex.success) { + console.error('Quest area index validation failed:', treeifyError(parsedAreaIndex.error)); + } + expect(parsedAreaIndex.success).toBe(true); + + const areas = parsedAreaIndex.success ? parsedAreaIndex.data.areas : []; + if (areas.length > 0) { + const area = await client.sendRequest(wow.questArea(areas[0]!.id)); + const parsedArea = questAreaResponseSchema.safeParse(area); + if (!parsedArea.success) { + console.error('Quest area detail validation failed:', treeifyError(parsedArea.error)); + } + expect(parsedArea.success).toBe(true); + } + + const categoryIndex = await client.sendRequest(wow.questCategoryIndex()); + const parsedCategoryIndex = questCategoryIndexResponseSchema.safeParse(categoryIndex); + if (!parsedCategoryIndex.success) { + console.error('Quest category index validation failed:', treeifyError(parsedCategoryIndex.error)); + } + expect(parsedCategoryIndex.success).toBe(true); + + const categories = parsedCategoryIndex.success ? parsedCategoryIndex.data.categories : []; + if (categories.length > 0) { + const category = await client.sendRequest(wow.questCategory(categories[0]!.id)); + const parsedCategory = questCategoryResponseSchema.safeParse(category); + if (!parsedCategory.success) { + console.error('Quest category detail validation failed:', treeifyError(parsedCategory.error)); + } + expect(parsedCategory.success).toBe(true); + } + + const typeIndex = await client.sendRequest(wow.questTypeIndex()); + const parsedTypeIndex = questTypeIndexResponseSchema.safeParse(typeIndex); + if (!parsedTypeIndex.success) { + console.error('Quest type index validation failed:', treeifyError(parsedTypeIndex.error)); + } + expect(parsedTypeIndex.success).toBe(true); + + const types = parsedTypeIndex.success ? parsedTypeIndex.data.types : []; + if (types.length > 0) { + const type = await client.sendRequest(wow.questType(types[0]!.id)); + const parsedType = questTypeResponseSchema.safeParse(type); + if (!parsedType.success) { + console.error('Quest type detail validation failed:', treeifyError(parsedType.error)); + } + expect(parsedType.success).toBe(true); + } + }); +}); diff --git a/packages/integration-tests/wow/realm.integration.test.ts b/packages/integration-tests/wow/realm.integration.test.ts new file mode 100644 index 00000000..49ccab85 --- /dev/null +++ b/packages/integration-tests/wow/realm.integration.test.ts @@ -0,0 +1,54 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + realmIndexResponseSchema, + realmResponseSchema, + realmSearchResponseSchema, +} from '../../../generated/schemas/wow/realm'; + +describe('wow realm integration', () => { + it('validates realm index and fetches realm detail', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const resp = await client.sendRequest(wow.realmIndex()); + const parsed = realmIndexResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Realm index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + + const first = parsed.success ? parsed.data.realms[0] : undefined; + if (first) { + const realm = await client.sendRequest(wow.realm(first.slug)); + const parsedRealm = realmResponseSchema.safeParse(realm); + if (!parsedRealm.success) { + console.error('Realm detail validation failed:', treeifyError(parsedRealm.error)); + console.log(parsedRealm.error); + console.log('realm', realm); + } + expect(parsedRealm.success).toBe(true); + } + }); + + it('validates realm search', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const search = await client.sendRequest(wow.realmSearch({ _page: 1 })); + const parsed = realmSearchResponseSchema.safeParse(search); + if (!parsed.success) { + console.error('Realm search validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/region.integration.test.ts b/packages/integration-tests/wow/region.integration.test.ts new file mode 100644 index 00000000..8c305515 --- /dev/null +++ b/packages/integration-tests/wow/region.integration.test.ts @@ -0,0 +1,23 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { regionIndexResponseSchema } from '../../../generated/schemas/wow'; + +describe('wow region integration', () => { + it('validates region index', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'us', + secret: environment.blizzardClientSecret, + }); + + const resp = await client.sendRequest(wow.regionIndex()); + const parsed = regionIndexResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Region index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/reputations.integration.test.ts b/packages/integration-tests/wow/reputations.integration.test.ts new file mode 100644 index 00000000..b1354932 --- /dev/null +++ b/packages/integration-tests/wow/reputations.integration.test.ts @@ -0,0 +1,80 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + reputationFactionIndexResponseSchema, + reputationFactionResponseSchema, + reputationTiersIndexResponseSchema, + reputationTiersResponseSchema, +} from '../../../generated/schemas/wow/reputations'; + +describe('wow reputations integration', async () => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + it('validates reputation factions', async ({ expect }) => { + const factions = await client.sendRequest(wow.reputationFactionIndex()); + const parsedFactions = reputationFactionIndexResponseSchema.safeParse(factions); + if (!parsedFactions.success) { + console.error('Reputation faction index validation failed:', treeifyError(parsedFactions.error)); + } + expect(parsedFactions.success).toBe(true); + + const factionItems = parsedFactions.success ? parsedFactions.data.factions : []; + const sampleSize = Math.min(5, factionItems.length); + const sampled = + factionItems.length > sampleSize + ? // eslint-disable-next-line sonarjs/pseudo-random + factionItems.toSorted(() => 0.5 - Math.random()).slice(0, sampleSize) + : factionItems.slice(0, sampleSize); + + const factionRequests = []; + for (const f of sampled) { + factionRequests.push(client.sendRequest(wow.reputationFaction(f.id))); + } + + const factionResponses = await Promise.all(factionRequests); + for (const fr of factionResponses) { + const parsed = reputationFactionResponseSchema.safeParse(fr); + if (!parsed.success) { + console.error('Reputation faction validation failed for id', fr.id, treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + } + }); + it('validates reputation tiers', async ({ expect }) => { + const tiers = await client.sendRequest(wow.reputationTiersIndex()); + const parsedTiers = reputationTiersIndexResponseSchema.safeParse(tiers); + if (!parsedTiers.success) { + console.error('Reputation tiers index validation failed:', treeifyError(parsedTiers.error)); + } + expect(parsedTiers.success).toBe(true); + + const tierItems = parsedTiers.success ? parsedTiers.data.reputation_tiers : []; + const sampleSize = Math.min(5, tierItems.length); + const sampled = + tierItems.length > sampleSize + ? // eslint-disable-next-line sonarjs/pseudo-random + tierItems.toSorted(() => 0.5 - Math.random()).slice(0, sampleSize) + : tierItems.slice(0, sampleSize); + + const tierRequests = []; + for (const t of sampled) { + tierRequests.push(client.sendRequest(wow.reputationTiers(t.id))); + } + const tierResponses = await Promise.all(tierRequests); + for (const tr of tierResponses) { + const parsed = reputationTiersResponseSchema.safeParse(tr); + if (!parsed.success) { + console.error('Reputation tiers validation failed for id', tr.id, treeifyError(parsed.error)); + console.log('fr', tr); + console.log('parsed.error', parsed.error); + } + expect(parsed.success).toBe(true); + } + }); +}); diff --git a/packages/integration-tests/wow/spell.integration.test.ts b/packages/integration-tests/wow/spell.integration.test.ts new file mode 100644 index 00000000..176fbdb9 --- /dev/null +++ b/packages/integration-tests/wow/spell.integration.test.ts @@ -0,0 +1,41 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + spellMediaResponseSchema, + spellResponseSchema, + spellSearchResponseSchema, +} from '../../../generated/schemas/wow/spell'; + +describe('wow spell integration', () => { + it('validates spell search and media responses', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + + const spell = await client.sendRequest(wow.spell(217_200)); + const parsedSpell = spellResponseSchema.safeParse(spell); + if (!parsedSpell.success) { + console.error('Spell detail validation failed:', treeifyError(parsedSpell.error)); + } + expect(parsedSpell.success).toBe(true); + + const search = await client.sendRequest(wow.spellSearch({ locale: 'en_GB', name: 'Barbed' })); + const parsedSearch = spellSearchResponseSchema.safeParse(search); + if (!parsedSearch.success) { + console.error('Spell search validation failed:', treeifyError(parsedSearch.error)); + } + expect(parsedSearch.success).toBe(true); + + const media = await client.sendRequest(wow.spellMedia(1_264_781)); + const parsedMedia = spellMediaResponseSchema.safeParse(media); + if (!parsedMedia.success) { + console.error('Spell media validation failed:', treeifyError(parsedMedia.error)); + } + expect(parsedMedia.success).toBe(true); + }); +}); diff --git a/packages/integration-tests/wow/talent.integration.test.ts b/packages/integration-tests/wow/talent.integration.test.ts new file mode 100644 index 00000000..4d5d2b83 --- /dev/null +++ b/packages/integration-tests/wow/talent.integration.test.ts @@ -0,0 +1,109 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + pvpTalentIndexResponseSchema, + pvpTalentResponseSchema, + talentIndexResponseSchema, + talentResponseSchema, + talentTreeIndexResponseSchema, + talentTreeNodesResponseSchema, + talentTreeResponseSchema, +} from '../../../generated/schemas/wow/talent'; + +describe.concurrent('wow talent integration', async () => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + it('validates pvp talents', async ({ expect }) => { + const pvpIndex = await client.sendRequest(wow.pvpTalentIndex()); + const parsedPvpIndex = pvpTalentIndexResponseSchema.safeParse(pvpIndex); + if (!parsedPvpIndex.success) { + console.error('PvP talent index validation failed:', treeifyError(parsedPvpIndex.error)); + } + expect(parsedPvpIndex.success).toBe(true); + + const pvpTalents = parsedPvpIndex.success ? parsedPvpIndex.data.pvp_talents : []; + const sampleSize = Math.min(5, pvpTalents.length); + const sampled = + pvpTalents.length > sampleSize + ? // eslint-disable-next-line sonarjs/pseudo-random + pvpTalents.toSorted(() => 0.5 - Math.random()).slice(0, sampleSize) + : pvpTalents.slice(0, sampleSize); + + const requests = []; + for (const t of sampled) { + requests.push(client.sendRequest(wow.pvpTalent(t.id))); + } + const responses = await Promise.all(requests); + for (const resp of responses) { + const parsed = pvpTalentResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('PvP talent validation failed for id', resp.id, treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + } + }); + it('validates talents', async ({ expect }) => { + const talentIndex = await client.sendRequest(wow.talentIndex()); + const parsedTalentIndex = talentIndexResponseSchema.safeParse(talentIndex); + if (!parsedTalentIndex.success) { + console.error('Talent index validation failed:', treeifyError(parsedTalentIndex.error)); + } + expect(parsedTalentIndex.success).toBe(true); + + const talents = parsedTalentIndex.success ? parsedTalentIndex.data.talents : []; + const sampleSize = Math.min(5, talents.length); + const sampled = + talents.length > sampleSize + ? // eslint-disable-next-line sonarjs/pseudo-random + talents.toSorted(() => 0.5 - Math.random()).slice(0, sampleSize) + : talents.slice(0, sampleSize); + const requests = []; + for (const t of sampled) { + requests.push(client.sendRequest(wow.talent(t.id))); + } + const responses = await Promise.all(requests); + for (const resp of responses) { + const parsed = talentResponseSchema.safeParse(resp); + if (!parsed.success) { + console.error('Talent validation failed for id', resp.id, treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + } + }); + it('validates talent trees', async ({ expect }) => { + const treeIndex = await client.sendRequest(wow.talentTreeIndex()); + const parsedTreeIndex = talentTreeIndexResponseSchema.safeParse(treeIndex); + if (!parsedTreeIndex.success) { + console.error('Talent tree index validation failed:', treeifyError(parsedTreeIndex.error)); + } + expect(parsedTreeIndex.success).toBe(true); + + const hunterSpecHeroCombinations = [ + { specId: 253, treeId: 774 }, + { specId: 254, treeId: 774 }, + { specId: 255, treeId: 774 }, + ]; + + for (const combo of hunterSpecHeroCombinations) { + const talentTree = await client.sendRequest(wow.talentTree(combo.treeId, combo.specId)); + const parsedTrees = talentTreeResponseSchema.safeParse(talentTree); + if (!parsedTrees.success) { + console.error('Talent tree validation failed for combo', combo, treeifyError(parsedTrees.error)); + } + expect(parsedTrees.success).toBe(true); + + const nodes = await client.sendRequest(wow.talentTreeNodes(combo.treeId)); + const parsedNodes = talentTreeNodesResponseSchema.safeParse(nodes); + if (!parsedNodes.success) { + console.error('Talent tree nodes validation failed for treeId', combo.treeId, treeifyError(parsedNodes.error)); + } + expect(parsedNodes.success).toBe(true); + } + }); +}); diff --git a/packages/integration-tests/wow/tech-talent.integration.test.ts b/packages/integration-tests/wow/tech-talent.integration.test.ts new file mode 100644 index 00000000..c25b02d4 --- /dev/null +++ b/packages/integration-tests/wow/tech-talent.integration.test.ts @@ -0,0 +1,93 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { + techTalentIndexResponseSchema, + techTalentMediaResponseSchema, + techTalentResponseSchema, + techTalentTreeIndexResponseSchema, + techTalentTreeResponseSchema, +} from '../../../generated/schemas/wow/tech-talent'; + +describe('wow tech-talent integration', async () => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + it('validates tech talent index, detail, and media', async ({ expect }) => { + const index = await client.sendRequest(wow.techTalentIndex()); + const parsedIndex = techTalentIndexResponseSchema.safeParse(index); + if (!parsedIndex.success) { + console.error('Tech talent index validation failed:', treeifyError(parsedIndex.error)); + } + expect(parsedIndex.success).toBe(true); + + const talents = parsedIndex.success ? parsedIndex.data.talents : []; + const sampleSize = Math.min(5, talents.length); + const sampled = + talents.length > sampleSize + ? // eslint-disable-next-line sonarjs/pseudo-random + talents.toSorted(() => 0.5 - Math.random()).slice(0, sampleSize) + : talents.slice(0, sampleSize); + + const detailRequests = []; + const mediaRequests = []; + for (const t of sampled) { + detailRequests.push(client.sendRequest(wow.techTalent(t.id))); + mediaRequests.push(client.sendRequest(wow.techTalentMedia(t.id))); + } + + const details = await Promise.all(detailRequests); + for (const d of details) { + const parsed = techTalentResponseSchema.safeParse(d); + if (!parsed.success) { + console.error('Tech talent detail validation failed for id', d.id, treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + } + + const medias = await Promise.all(mediaRequests); + for (const m of medias) { + const parsed = techTalentMediaResponseSchema.safeParse(m); + if (!parsed.success) { + console.error('Tech talent media validation failed for id', m, treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + } + }); + it('validates tech talent trees', async ({ expect }) => { + const treeIndex = await client.sendRequest(wow.techTalentTreeIndex()); + const parsedTreeIndex = techTalentTreeIndexResponseSchema.safeParse(treeIndex); + if (!parsedTreeIndex.success) { + console.error('Tech talent tree index validation failed:', treeifyError(parsedTreeIndex.error)); + } + expect(parsedTreeIndex.success).toBe(true); + + const techTalentTrees = parsedTreeIndex.success ? parsedTreeIndex.data.talent_trees : []; + const sampleSize = Math.min(5, techTalentTrees.length); + + const sampled = + techTalentTrees.length > sampleSize + ? // eslint-disable-next-line sonarjs/pseudo-random + techTalentTrees.toSorted(() => 0.5 - Math.random()).slice(0, sampleSize) + : techTalentTrees.slice(0, sampleSize); + + const detailRequests = []; + + for (const t of sampled) { + detailRequests.push(client.sendRequest(wow.techTalentTree(t.id))); + } + + const details = await Promise.all(detailRequests); + for (const d of details) { + const parsed = techTalentTreeResponseSchema.safeParse(d); + if (!parsed.success) { + console.error('Tech talent tree validation failed for id', d.id, treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + } + }); +}); diff --git a/packages/integration-tests/wow/title.integration.test.ts b/packages/integration-tests/wow/title.integration.test.ts new file mode 100644 index 00000000..b2ad1044 --- /dev/null +++ b/packages/integration-tests/wow/title.integration.test.ts @@ -0,0 +1,45 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { titleIndexResponseSchema, titleResponseSchema } from '../../../generated/schemas/wow/title'; + +describe('wow title integration', () => { + it('validates title index and fetches title detail', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + const index = await client.sendRequest(wow.titleIndex()); + const parsed = titleIndexResponseSchema.safeParse(index); + if (!parsed.success) { + console.error('Title index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + + // Pick up to 5 titles at random from the index to fetch details + const titles = parsed.success ? parsed.data.titles : []; + const sampleSize = Math.min(5, titles.length); + const sampled = + titles.length > sampleSize + ? // eslint-disable-next-line sonarjs/pseudo-random + titles.toSorted(() => 0.5 - Math.random()).slice(0, sampleSize) + : titles.slice(0, sampleSize); + + const requests = []; + + for (const t of sampled) { + requests.push(client.sendRequest(wow.title(t.id))); + } + const responses = await Promise.all(requests); + for (const title of responses) { + const parsedTitle = titleResponseSchema.safeParse(title); + if (!parsedTitle.success) { + console.error('Title detail validation failed for id', title.id, treeifyError(parsedTitle.error)); + } + expect(parsedTitle.success).toBe(true); + } + }); +}); diff --git a/packages/integration-tests/wow/toy.integration.test.ts b/packages/integration-tests/wow/toy.integration.test.ts new file mode 100644 index 00000000..685a0cda --- /dev/null +++ b/packages/integration-tests/wow/toy.integration.test.ts @@ -0,0 +1,45 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { toyIndexResponseSchema, toyResponseSchema } from '../../../generated/schemas/wow/toy'; + +describe('wow toy integration', () => { + it('validates toy index and fetches toy detail', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + const index = await client.sendRequest(wow.toyIndex()); + const parsed = toyIndexResponseSchema.safeParse(index); + if (!parsed.success) { + console.error('Toy index validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + + // Pick up to 5 toys at random from the index to fetch details + const toys = parsed.success ? parsed.data.toys : []; + const sampleSize = Math.min(5, toys.length); + const sampled = + toys.length > sampleSize + ? // eslint-disable-next-line sonarjs/pseudo-random + toys.toSorted(() => 0.5 - Math.random()).slice(0, sampleSize) + : toys.slice(0, sampleSize); + + const requests = []; + + for (const t of sampled) { + requests.push(client.sendRequest(wow.toy(t.id))); + } + const responses = await Promise.all(requests); + for (const toy of responses) { + const parsedToy = toyResponseSchema.safeParse(toy); + if (!parsedToy.success) { + console.error('Toy detail validation failed for id', toy.id, treeifyError(parsedToy.error)); + } + expect(parsedToy.success).toBe(true); + } + }); +}); diff --git a/packages/integration-tests/wow/wow-token.integration.test.ts b/packages/integration-tests/wow/wow-token.integration.test.ts new file mode 100644 index 00000000..a16c2f18 --- /dev/null +++ b/packages/integration-tests/wow/wow-token.integration.test.ts @@ -0,0 +1,22 @@ +import { createBlizzardApiClient } from '@blizzard-api/client'; +import * as wow from '@blizzard-api/wow'; +import { describe, it } from 'vitest'; +import { treeifyError } from 'zod'; +import { environment } from '../../../environment'; +import { wowTokenResponseSchema } from '../../../generated/schemas/wow/wow-token'; + +describe('wow wow-token integration', () => { + it('validates wow token response', async ({ expect }) => { + const client = await createBlizzardApiClient({ + key: environment.blizzardClientId, + origin: 'eu', + secret: environment.blizzardClientSecret, + }); + const token = await client.sendRequest(wow.wowToken()); + const parsed = wowTokenResponseSchema.safeParse(token); + if (!parsed.success) { + console.error('Wow token validation failed:', treeifyError(parsed.error)); + } + expect(parsed.success).toBe(true); + }); +}); diff --git a/packages/sc2/package.json b/packages/sc2/package.json index 232e8579..e159e20a 100644 --- a/packages/sc2/package.json +++ b/packages/sc2/package.json @@ -7,7 +7,7 @@ "repository": "https://github.com/Pewtro/blizzard-api/tree/main/packages/sc2", "type": "module", "engines": { - "node": "^18.18 || >=20.9" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "module": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/sc2/src/ladder/ladder.test.ts b/packages/sc2/src/ladder/ladder.test.ts index 6d337b4f..ed526bdf 100644 --- a/packages/sc2/src/ladder/ladder.test.ts +++ b/packages/sc2/src/ladder/ladder.test.ts @@ -1,6 +1,6 @@ import type { Resource } from '@blizzard-api/core'; import { describe, expect, it } from 'vitest'; -import type { StarcraftRegion } from '../base'; +import type { StarcraftRegion } from '../regions'; import { grandmasterLeaderboard, season } from './ladder'; import type { GrandmasterLeaderboardResponse, SeasonResponse } from './types'; diff --git a/packages/sc2/src/ladder/ladder.ts b/packages/sc2/src/ladder/ladder.ts index a47fcb53..6f110cc2 100644 --- a/packages/sc2/src/ladder/ladder.ts +++ b/packages/sc2/src/ladder/ladder.ts @@ -1,6 +1,6 @@ import type { Resource } from '@blizzard-api/core'; -import { starcraftRegion } from '../base'; -import type { StarcraftRegion } from '../base'; +import { starcraftRegion } from '../regions'; +import type { StarcraftRegion } from '../regions'; import type { GrandmasterLeaderboardResponse, SeasonResponse } from './types'; /** diff --git a/packages/sc2/src/league/types.ts b/packages/sc2/src/league/types.ts index f9277aa0..4ae3f599 100644 --- a/packages/sc2/src/league/types.ts +++ b/packages/sc2/src/league/types.ts @@ -1,4 +1,4 @@ -import type { ResponseBase } from '../base'; +import type { ResponseBase } from '@blizzard-api/core'; export interface LeagueDataResponse extends ResponseBase { key: Key; diff --git a/packages/sc2/src/legacy/legacy.ts b/packages/sc2/src/legacy/legacy.ts index bed052e7..17e4f09b 100644 --- a/packages/sc2/src/legacy/legacy.ts +++ b/packages/sc2/src/legacy/legacy.ts @@ -1,6 +1,6 @@ import type { Resource } from '@blizzard-api/core'; -import { starcraftRegion } from '../base'; -import type { StarcraftRegion } from '../base'; +import { starcraftRegion } from '../regions'; +import type { StarcraftRegion } from '../regions'; import type { LegacyAchievementsResponse, LegacyLaddersResponse, diff --git a/packages/sc2/src/legacy/types.ts b/packages/sc2/src/legacy/types.ts index b4146594..7fbd0f66 100644 --- a/packages/sc2/src/legacy/types.ts +++ b/packages/sc2/src/legacy/types.ts @@ -82,7 +82,13 @@ interface Career { interface Category { categoryId: string; - children?: Array; + children?: Array; + featuredAchievementId: string; + title: string; +} + +interface CategoryChild { + categoryId: string; featuredAchievementId: string; title: string; } diff --git a/packages/sc2/src/profile/profile.test.ts b/packages/sc2/src/profile/profile.test.ts index 8b4d17f5..9cc3876d 100644 --- a/packages/sc2/src/profile/profile.test.ts +++ b/packages/sc2/src/profile/profile.test.ts @@ -1,7 +1,7 @@ import type { Resource } from '@blizzard-api/core'; import { describe, expect, it } from 'vitest'; -import { starcraftRegion } from '../base'; -import type { StarcraftRegion } from '../base'; +import { starcraftRegion } from '../regions'; +import type { StarcraftRegion } from '../regions'; import { ladder, ladderSummary, metadata, profile, staticProfile } from './profile'; import type { LadderResponse, LadderSummaryResponse, MetadataResponse, StaticProfileResponse } from './types'; diff --git a/packages/sc2/src/profile/profile.ts b/packages/sc2/src/profile/profile.ts index b5d91267..e5514596 100644 --- a/packages/sc2/src/profile/profile.ts +++ b/packages/sc2/src/profile/profile.ts @@ -1,6 +1,6 @@ import type { Resource } from '@blizzard-api/core'; -import { starcraftRegion } from '../base'; -import type { StarcraftRegion } from '../base'; +import { starcraftRegion } from '../regions'; +import type { StarcraftRegion } from '../regions'; import type { LadderResponse, LadderSummaryResponse, MetadataResponse, StaticProfileResponse } from './types'; /** diff --git a/packages/sc2/src/base.ts b/packages/sc2/src/regions.ts similarity index 57% rename from packages/sc2/src/base.ts rename to packages/sc2/src/regions.ts index d67d25d9..2b83362a 100644 --- a/packages/sc2/src/base.ts +++ b/packages/sc2/src/regions.ts @@ -1,21 +1,10 @@ -/** - * Base interface for Blizzard API responses. - */ -export interface ResponseBase { - _links: { - self: { - href: string; - }; - }; -} - -//The region (1=US, 2=EU, 3=KO and TW, 5=CN). -export type StarcraftRegion = 'cn' | 'eu' | 'kr' | 'tw' | 'us'; - -export const starcraftRegion: Record = { - cn: 5, - eu: 2, - kr: 3, - tw: 3, - us: 1, -}; +//The region (1=US, 2=EU, 3=KO and TW, 5=CN). +export type StarcraftRegion = 'cn' | 'eu' | 'kr' | 'tw' | 'us'; + +export const starcraftRegion: Record = { + cn: 5, + eu: 2, + kr: 3, + tw: 3, + us: 1, +}; diff --git a/packages/wow/package.json b/packages/wow/package.json index 32f752bc..4847cc3e 100644 --- a/packages/wow/package.json +++ b/packages/wow/package.json @@ -7,7 +7,7 @@ "repository": "https://github.com/Pewtro/blizzard-api/tree/main/packages/wow", "type": "module", "engines": { - "node": "^18.18 || >=20.9" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "module": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/wow/src/account-profile/types.ts b/packages/wow/src/account-profile/types.ts index 98e56bf8..4a17578c 100644 --- a/packages/wow/src/account-profile/types.ts +++ b/packages/wow/src/account-profile/types.ts @@ -1,4 +1,4 @@ -import type { Faction, Gender, Href, KeyBase, NameId, NameIdKey, Realm } from '../base'; +import type { Faction, Gender, Href, KeyBase, NameId, NameIdKey, Realm } from '@blizzard-api/core'; export interface AccountCollectionsIndexResponse { _links: Links; @@ -118,7 +118,7 @@ interface ProtectedStats { } interface Quality { - name: 'Common' | 'Poor' | 'Rare' | 'Uncommon'; + name: string; type: 'COMMON' | 'POOR' | 'RARE' | 'UNCOMMON'; } diff --git a/packages/wow/src/achievements/achievements.test.ts b/packages/wow/src/achievements/achievements.test.ts index 2cb0c9fb..d1e204a8 100644 --- a/packages/wow/src/achievements/achievements.test.ts +++ b/packages/wow/src/achievements/achievements.test.ts @@ -1,5 +1,5 @@ +import { wowBasePath, wowMediaBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base, mediaBase } from '../base'; import { achievement, achievementCategory, @@ -11,31 +11,31 @@ import { describe.concurrent('Achievements', () => { it('should return correct path and namespace for achievementCategory', ({ expect }) => { const resource = achievementCategory(1); - expect(resource.path).toBe(`${base}/achievement-category/1`); + expect(resource.path).toBe(`${wowBasePath}/achievement-category/1`); expect(resource.namespace).toBe('static'); }); it('should return correct path and namespace for achievementCategoryIndex', ({ expect }) => { const resource = achievementCategoryIndex(); - expect(resource.path).toBe(`${base}/achievement-category/index`); + expect(resource.path).toBe(`${wowBasePath}/achievement-category/index`); expect(resource.namespace).toBe('static'); }); it('should return correct path and namespace for achievement', ({ expect }) => { const resource = achievement(1); - expect(resource.path).toBe(`${base}/achievement/1`); + expect(resource.path).toBe(`${wowBasePath}/achievement/1`); expect(resource.namespace).toBe('static'); }); it('should return correct path and namespace for achievementIndex', ({ expect }) => { const resource = achievementIndex(); - expect(resource.path).toBe(`${base}/achievement/index`); + expect(resource.path).toBe(`${wowBasePath}/achievement/index`); expect(resource.namespace).toBe('static'); }); it('should return correct path and namespace for achievementMedia', ({ expect }) => { const resource = achievementMedia(1); - expect(resource.path).toBe(`${mediaBase}/achievement/1`); + expect(resource.path).toBe(`${wowMediaBasePath}/achievement/1`); expect(resource.namespace).toBe('static'); }); }); diff --git a/packages/wow/src/achievements/achievements.ts b/packages/wow/src/achievements/achievements.ts index e8c97510..751610a3 100644 --- a/packages/wow/src/achievements/achievements.ts +++ b/packages/wow/src/achievements/achievements.ts @@ -1,5 +1,5 @@ +import { wowBasePath, wowMediaBasePath } from '@blizzard-api/core'; import type { Resource } from '@blizzard-api/core'; -import { base, mediaBase } from '../base'; import type { AchievementCategoryIndexResponse, AchievementCategoryResponse, @@ -8,8 +8,8 @@ import type { AchievementResponse, } from './types'; -const achievementBase = `${base}/achievement`; -const achievementCategoryBase = `${base}/achievement-category`; +const achievementBase = `${wowBasePath}/achievement`; +const achievementCategoryBase = `${wowBasePath}/achievement-category`; /** * Get an achievement by ID. @@ -59,5 +59,5 @@ export function achievementIndex(): Resource { * @returns The achievement media. See {@link AchievementMediaResponse}. */ export function achievementMedia(achievementId: number): Resource { - return { namespace: 'static', path: `${mediaBase}/achievement/${achievementId}` }; + return { namespace: 'static', path: `${wowMediaBasePath}/achievement/${achievementId}` }; } diff --git a/packages/wow/src/achievements/types.ts b/packages/wow/src/achievements/types.ts index 8b15f3f0..83ac0386 100644 --- a/packages/wow/src/achievements/types.ts +++ b/packages/wow/src/achievements/types.ts @@ -1,4 +1,4 @@ -import type { KeyBase, NameId, NameIdKey, ResponseBase } from '../base'; +import type { Faction, KeyBase, MediaAsset, NameId, NameIdKey, ResponseBase } from '@blizzard-api/core'; /** * Interface for a response from the achievement category index endpoint. @@ -27,8 +27,9 @@ export interface AchievementCategoryResponse extends NameId, ResponseBase { }; }; display_order: number; - isGuildCategory: boolean; - parent_category: NameIdKey; + is_guild_category: boolean; + parent_category?: NameIdKey; + subcategories?: Array; } /** @@ -44,7 +45,7 @@ export interface AchievementIndexResponse extends ResponseBase { * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} */ export interface AchievementMediaResponse extends ResponseBase { - assets: Array; + assets: Array; id: number; } @@ -54,20 +55,65 @@ export interface AchievementMediaResponse extends ResponseBase { */ export interface AchievementResponse extends NameId, ResponseBase { category: NameIdKey; - criteria: { - amount: number; - description: string; - id: number; - }; + criteria?: Criteria; description: string; display_order: number; + guild_reward_items?: Array; is_account_wide: boolean; - media: KeyBase; + media: KeyBase & { id: number }; + next_achievement?: NameIdKey; points: number; + prerequisite_achievement?: NameIdKey; + requirements?: { faction: Faction }; + reward_description?: string; + reward_item?: NameIdKey; +} + +interface ChildCriteria { + achievement?: NameIdKey; + amount: number; + child_criteria?: Array; + description: null | string; + faction?: Faction; + id: number; + is_gold?: boolean; + operator?: Operator; + show_progress_bar?: boolean; +} + +interface ChildCriteria2 { + achievement?: NameIdKey; + amount: number; + child_criteria?: Array; + description: null | string; + faction?: Faction; + id: number; + is_gold?: boolean; + operator?: Operator; + show_progress_bar?: boolean; +} + +interface ChildCriteria3 { + achievement?: NameIdKey; + amount: number; + description: null | string; + faction?: Faction; + id: number; + is_gold?: boolean; + operator?: Operator; + show_progress_bar?: boolean; } -interface AchievementMediaItem { - file_data_id: number; - key: string; - value: string; +interface Criteria { + amount: number; + child_criteria?: Array; + description: null | string; + faction?: Faction; + id: number; + operator?: Operator; + show_progress_bar?: boolean; +} +interface Operator { + name: string; + type: 'AND' | 'COMPLETE_AT_LEAST'; } diff --git a/packages/wow/src/auction-house/auction-house.ts b/packages/wow/src/auction-house/auction-house.ts index 117c7d34..726ac25c 100644 --- a/packages/wow/src/auction-house/auction-house.ts +++ b/packages/wow/src/auction-house/auction-house.ts @@ -1,5 +1,5 @@ +import { wowBasePath } from '@blizzard-api/core'; import type { Resource } from '@blizzard-api/core'; -import { base } from '../base'; import type { AuctionHouseCommoditiesResponse, AuctionHouseResponse } from './types'; /** @@ -10,7 +10,7 @@ import type { AuctionHouseCommoditiesResponse, AuctionHouseResponse } from './ty export function auctions(connectedRealmId: number): Resource { return { namespace: 'dynamic', - path: `${base}/connected-realm/${connectedRealmId}/auctions`, + path: `${wowBasePath}/connected-realm/${connectedRealmId}/auctions`, }; } /** @@ -20,6 +20,6 @@ export function auctions(connectedRealmId: number): Resource { return { namespace: 'dynamic', - path: `${base}/auctions/commodities`, + path: `${wowBasePath}/auctions/commodities`, }; } diff --git a/packages/wow/src/auction-house/types.ts b/packages/wow/src/auction-house/types.ts index bba9f8d2..80da267b 100644 --- a/packages/wow/src/auction-house/types.ts +++ b/packages/wow/src/auction-house/types.ts @@ -1,4 +1,4 @@ -import type { ResponseBase } from '../base'; +import type { ResponseBase } from '@blizzard-api/core'; /** * Interface for a response from the auction house commodities endpoint. @@ -31,14 +31,18 @@ interface AuctionHouseCommodity { } interface AuctionHousePosting { - bid: number; + bid?: number; buyout: number; id: number; item: { - bonus_lists: Array; - context: number; + bonus_lists?: Array; + context?: number; id: number; - modifiers: Array<{ type: number; value: number }>; + modifiers?: Array<{ type: number; value: number }>; + pet_breed_id?: number; + pet_level?: number; + pet_quality_id?: number; + pet_species_id?: number; }; quantity: number; time_left: AuctionHouseTimeLeft; diff --git a/packages/wow/src/azerite-essence/azerite-essence.test.ts b/packages/wow/src/azerite-essence/azerite-essence.test.ts index 14a8ee0b..aa0e6659 100644 --- a/packages/wow/src/azerite-essence/azerite-essence.test.ts +++ b/packages/wow/src/azerite-essence/azerite-essence.test.ts @@ -1,5 +1,5 @@ +import { wowBasePath, wowMediaBasePath, wowSearchBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base, mediaBase, searchBase } from '../base'; import { azeriteEssence, azeriteEssenceIndex, azeriteEssenceMedia, azeriteEssenceSearch } from './azerite-essence'; describe.concurrent('azeriteEssenceApi', () => { @@ -7,14 +7,14 @@ describe.concurrent('azeriteEssenceApi', () => { const azeriteEssenceId = 123; const resource = azeriteEssence(azeriteEssenceId); - expect(resource.path).toBe(`${base}/azerite-essence/123`); + expect(resource.path).toBe(`${wowBasePath}/azerite-essence/123`); expect(resource.namespace).toBe('static'); }); it('should return the correct path and namespace for azeriteEssenceIndex', ({ expect }) => { const resource = azeriteEssenceIndex(); - expect(resource.path).toBe(`${base}/azerite-essence/index`); + expect(resource.path).toBe(`${wowBasePath}/azerite-essence/index`); expect(resource.namespace).toBe('static'); }); @@ -22,14 +22,14 @@ describe.concurrent('azeriteEssenceApi', () => { const azeriteEssenceId = 123; const resource = azeriteEssenceMedia(azeriteEssenceId); - expect(resource.path).toBe(`${mediaBase}/azerite-essence/123`); + expect(resource.path).toBe(`${wowMediaBasePath}/azerite-essence/123`); expect(resource.namespace).toBe('static'); }); it('should return the correct path and namespace for azeriteEssenceSearch', ({ expect }) => { const resource = azeriteEssenceSearch({ _page: 1 }); - expect(resource.path).toBe(`${searchBase}/azerite-essence`); + expect(resource.path).toBe(`${wowSearchBasePath}/azerite-essence`); expect(resource.namespace).toBe('static'); expect(resource.parameters).toEqual({ _page: 1 }); }); @@ -40,7 +40,7 @@ describe.concurrent('azeriteEssenceApi', () => { orderby: 'name', }); - expect(resource.path).toBe(`${searchBase}/azerite-essence`); + expect(resource.path).toBe(`${wowSearchBasePath}/azerite-essence`); expect(resource.namespace).toBe('static'); expect(resource.parameters).toEqual({ _page: 1, @@ -56,7 +56,7 @@ describe.concurrent('azeriteEssenceApi', () => { orderby: ['name', 'id'], }); - expect(resource.path).toBe(`${searchBase}/azerite-essence`); + expect(resource.path).toBe(`${wowSearchBasePath}/azerite-essence`); expect(resource.namespace).toBe('static'); expect(resource.parameters).toEqual({ _page: 1, diff --git a/packages/wow/src/azerite-essence/azerite-essence.ts b/packages/wow/src/azerite-essence/azerite-essence.ts index 65fdd674..9fafe1c6 100644 --- a/packages/wow/src/azerite-essence/azerite-essence.ts +++ b/packages/wow/src/azerite-essence/azerite-essence.ts @@ -1,11 +1,11 @@ -import type { Resource, SearchResponse } from '@blizzard-api/core'; -import { base, mediaBase, searchBase } from '../base'; +import type { Resource } from '@blizzard-api/core'; +import { wowBasePath, wowMediaBasePath, wowSearchBasePath } from '@blizzard-api/core'; import type { AzeriteEssenceIndexResponse, AzeriteEssenceMediaResponse, AzeriteEssenceResponse, AzeriteEssenceSearchParameters, - AzeriteEssenceSearchResponseItem, + AzeriteEssenceSearchResponse, } from './types'; /** @@ -16,7 +16,7 @@ import type { export function azeriteEssence(azeriteEssenceId: number): Resource { return { namespace: 'static', - path: `${base}/azerite-essence/${azeriteEssenceId}`, + path: `${wowBasePath}/azerite-essence/${azeriteEssenceId}`, }; } /** @@ -26,7 +26,7 @@ export function azeriteEssence(azeriteEssenceId: number): Resource { return { namespace: 'static', - path: `${base}/azerite-essence/index`, + path: `${wowBasePath}/azerite-essence/index`, }; } /** @@ -35,16 +35,16 @@ export function azeriteEssenceIndex(): Resource { * @returns The azerite essence media. See {@link AzeriteEssenceMediaResponse}. */ export function azeriteEssenceMedia(azeriteEssenceId: number): Resource { - return { namespace: 'static', path: `${mediaBase}/azerite-essence/${azeriteEssenceId}` }; + return { namespace: 'static', path: `${wowMediaBasePath}/azerite-essence/${azeriteEssenceId}` }; } /** * Search for azerite essences. * @param options The search parameters. See {@link AzeriteEssenceSearchParameters}. - * @returns The search results. See {@link SearchResponse}. + * @returns The search results. See {@link AzeriteEssenceSearchResponse}. */ export function azeriteEssenceSearch( options: AzeriteEssenceSearchParameters, -): Resource, AzeriteEssenceSearchParameters> { +): Resource { return { namespace: 'static', parameters: { @@ -52,6 +52,6 @@ export function azeriteEssenceSearch( 'allowed_specializations.id': options['allowed_specializations.id'], orderby: Array.isArray(options.orderby) ? options.orderby.join(',') : options.orderby, }, - path: `${searchBase}/azerite-essence`, + path: `${wowSearchBasePath}/azerite-essence`, }; } diff --git a/packages/wow/src/azerite-essence/types.ts b/packages/wow/src/azerite-essence/types.ts index e1d3e01d..dffd91cb 100644 --- a/packages/wow/src/azerite-essence/types.ts +++ b/packages/wow/src/azerite-essence/types.ts @@ -1,5 +1,13 @@ -import type { BaseSearchParameters, Locales } from '@blizzard-api/core'; -import type { KeyBase, MediaAsset, NameId, NameIdKey, ResponseBase } from '../base'; +import type { + BaseSearchParameters, + KeyBase, + Locales, + MediaAsset, + NameId, + NameIdKey, + ResponseBase, + SearchResponseWithoutResults, +} from '@blizzard-api/core'; /** * Interface for a response from the azerite essence index endpoint. @@ -42,9 +50,12 @@ export interface AzeriteEssenceSearchParameters extends BaseSearchParameters { * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} * @see {@link https://develop.battle.net/documentation/world-of-warcraft/guides/search} */ -export interface AzeriteEssenceSearchResponseItem extends KeyBase { +export interface AzeriteEssenceSearchResponse extends SearchResponseWithoutResults { + results: Array; +} +interface AzeriteEssenceSearchResponseItem extends KeyBase { data: { - allowed_specializations: Array; + allowed_specializations: Array<{ id: number; name: Record }>; name: Record; }; } diff --git a/packages/wow/src/character-achievements/types.ts b/packages/wow/src/character-achievements/types.ts index 6beac988..117947b6 100644 --- a/packages/wow/src/character-achievements/types.ts +++ b/packages/wow/src/character-achievements/types.ts @@ -1,4 +1,4 @@ -import type { Character, Href, NameIdKey, ResponseBase } from '../base'; +import type { Character, Href, NameIdKey, ResponseBase } from '@blizzard-api/core'; export interface CharacterAchievementsSummaryResponse extends ResponseBase { achievements: Array; @@ -23,10 +23,10 @@ interface Achievement { } interface Category { - id: number; + id?: number; name: string; - statistics: Array; - sub_categories: Array; + statistics?: Array; + sub_categories?: Array; } interface CategoryProgress { @@ -35,9 +35,29 @@ interface CategoryProgress { quantity: number; } +interface ChildCriterum { + amount?: number; + child_criteria?: Array; + id: number; + is_completed: boolean; +} + +interface ChildCriterum2 { + amount?: number; + child_criteria?: Array; + id: number; + is_completed: boolean; +} + +interface ChildCriterum3 { + amount?: number; + id: number; + is_completed: boolean; +} + interface Criteria { amount?: number; - child_criteria?: Array; + child_criteria?: Array; id: number; is_completed: boolean; } diff --git a/packages/wow/src/character-appearance/types.ts b/packages/wow/src/character-appearance/types.ts index f73ee5c9..edd9b187 100644 --- a/packages/wow/src/character-appearance/types.ts +++ b/packages/wow/src/character-appearance/types.ts @@ -1,4 +1,4 @@ -import type { Character, Color, Faction, Gender, KeyBase, NameId, NameIdKey, ResponseBase } from '../base'; +import type { Character, Color, Faction, Gender, KeyBase, NameId, NameIdKey, ResponseBase } from '@blizzard-api/core'; export interface CharacterAppearanceResponse extends ResponseBase { active_spec: NameIdKey; @@ -39,9 +39,12 @@ interface Item { enchant: number; id: number; internal_slot_id: number; - item_appearance_modifier_id: number; + item_appearance_modifier_id?: number; + secondary_id?: number; + secondary_item_appearance_modifier_id?: number; + secondary_subclass?: number; slot: { name: string; type: string }; - subclass: number; + subclass?: number; } interface RGBWithId { diff --git a/packages/wow/src/character-collections/types.ts b/packages/wow/src/character-collections/types.ts index d0bbd032..a61290a9 100644 --- a/packages/wow/src/character-collections/types.ts +++ b/packages/wow/src/character-collections/types.ts @@ -1,7 +1,8 @@ -import type { Character, Href, KeyBase, NameIdKey, ResponseBase } from '../base'; +import type { Character, Href, KeyBase, NameIdKey, ResponseBase } from '@blizzard-api/core'; export interface CharacterCollectionsIndexResponse extends ResponseBase { character: Character; + decors: Href; heirlooms: Href; mounts: Href; pets: Href; @@ -57,16 +58,16 @@ interface Pet { } interface Quality { - name: 'Common' | 'Poor' | 'Rare' | 'Uncommon'; + name: string; type: 'COMMON' | 'POOR' | 'RARE' | 'UNCOMMON'; } interface Slot { appearances: Array; - slot: Slot; + slot: SlotSlot; } -interface Slot { +interface SlotSlot { name: string; type: string; } diff --git a/packages/wow/src/character-encounters/types.ts b/packages/wow/src/character-encounters/types.ts index 2864f204..d06781f2 100644 --- a/packages/wow/src/character-encounters/types.ts +++ b/packages/wow/src/character-encounters/types.ts @@ -1,7 +1,7 @@ -import type { Character, Href, NameIdKey, ResponseBase } from '../base'; +import type { Character, Href, NameIdKey, ResponseBase } from '@blizzard-api/core'; export interface CharacterDungeonsResponse extends ResponseBase { - expansions: Array>; + expansions: Array; } export interface CharacterEncountersSummaryResponse extends ResponseBase { @@ -12,12 +12,17 @@ export interface CharacterEncountersSummaryResponse extends ResponseBase { export interface CharacterRaidsResponse extends ResponseBase { character: Character; - expansions: Array>; + expansions: Array; } interface DungeonDifficulties { - name: 'Heroic' | 'Mythic' | 'Mythic+ Dungeons' | 'Normal'; - type: 'HEROIC' | 'MYTHIC' | 'MYTHIC_KEYSTONE' | 'NORMAL'; + name?: string; + type?: 'HEROIC' | 'MYTHIC' | 'MYTHIC_KEYSTONE' | 'NORMAL'; +} + +interface DungeonInstance { + instance: NameIdKey; + modes: Array; } interface DungeonMode { @@ -32,14 +37,14 @@ interface Encounter { last_kill_timestamp: number; } -interface Expansion { +interface ExpansionWithDungeonInstances { expansion: NameIdKey; - instances: Array>; + instances: Array; } -interface Instance { - instance: NameIdKey; - modes: Array; +interface ExpansionWithRaidInstances { + expansion: NameIdKey; + instances: Array; } interface Progress { @@ -49,15 +54,7 @@ interface Progress { } interface RaidDifficulties { - name: - | '10 Player' - | '10 Player (Heroic)' - | '25 Player' - | '25 Player (Heroic)' - | 'Heroic' - | 'Mythic' - | 'Normal' - | 'Raid Finder'; + name: string; type: | 'HEROIC' | 'LEGACY_10_MAN' @@ -69,6 +66,11 @@ interface RaidDifficulties { | 'NORMAL'; } +interface RaidInstance { + instance: NameIdKey; + modes: Array; +} + interface RaidMode { difficulty: RaidDifficulties; progress: Progress; @@ -76,6 +78,6 @@ interface RaidMode { } interface Status { - name: 'Complete' | 'In Progress'; + name: string; type: 'COMPLETE' | 'IN_PROGRESS'; } diff --git a/packages/wow/src/character-equipment/types.ts b/packages/wow/src/character-equipment/types.ts index 16769044..b605753a 100644 --- a/packages/wow/src/character-equipment/types.ts +++ b/packages/wow/src/character-equipment/types.ts @@ -1,4 +1,4 @@ -import type { Character, Color, KeyBase, NameIdKey, ResponseBase } from '../base'; +import type { Character, Color, KeyBase, NameIdKey, ResponseBase } from '@blizzard-api/core'; export interface CharacterEquipmentSummaryResponse extends ResponseBase { character: Character; @@ -67,7 +67,7 @@ interface EquippedItem { modified_appearance_id?: number; modified_crafting_stat?: Array; name: string; - name_description: NameDescription; + name_description?: NameDescription; quality: NameType; quantity: number; requirements?: Requirements; @@ -82,8 +82,9 @@ interface EquippedItem { weapon?: Weapon; } -interface ItemElement extends NameIdKey { +interface ItemElement { is_equipped?: boolean; + item: NameIdKey; } interface ModifiedCraftingStat { @@ -125,6 +126,8 @@ interface Set { } interface Socket { + context?: number; + display_color?: Color; display_string: string; item: NameIdKey; media: KeyBase & { id: number }; diff --git a/packages/wow/src/character-hunter-pets/types.ts b/packages/wow/src/character-hunter-pets/types.ts index 30d673d7..87c9914a 100644 --- a/packages/wow/src/character-hunter-pets/types.ts +++ b/packages/wow/src/character-hunter-pets/types.ts @@ -1,4 +1,4 @@ -import type { Character, KeyBase, NameIdKey, ResponseBase } from '../base'; +import type { Character, KeyBase, NameIdKey, ResponseBase } from '@blizzard-api/core'; export interface CharacterHunterPetsSummaryResponse extends ResponseBase { character: Character; diff --git a/packages/wow/src/character-media/types.ts b/packages/wow/src/character-media/types.ts index e7af6970..fca9b71c 100644 --- a/packages/wow/src/character-media/types.ts +++ b/packages/wow/src/character-media/types.ts @@ -1,4 +1,4 @@ -import type { Character, ResponseBase } from '../base'; +import type { Character, ResponseBase } from '@blizzard-api/core'; export interface CharacterMediaSummaryResponse extends ResponseBase { assets: Array; diff --git a/packages/wow/src/character-mythic-keystone-profile/types.ts b/packages/wow/src/character-mythic-keystone-profile/types.ts index 59824ac4..47a26874 100644 --- a/packages/wow/src/character-mythic-keystone-profile/types.ts +++ b/packages/wow/src/character-mythic-keystone-profile/types.ts @@ -1,4 +1,4 @@ -import type { Character, Color, KeyBase, NameId, NameIdKey, Realm, ResponseBase } from '../base'; +import type { Character, Color, KeyBase, NameId, NameIdKey, Realm, ResponseBase } from '@blizzard-api/core'; export interface CharacterMythicKeystoneProfileIndexResponse extends ResponseBase { character: Character; @@ -8,7 +8,7 @@ export interface CharacterMythicKeystoneProfileIndexResponse extends ResponseBas export interface CharacterMythicKeystoneSeasonDetailsResponse extends ResponseBase { best_runs: Array; - character: NameIdKey; + character: Character; mythic_rating: MythicRating; season: KeyBase & { id: number }; } diff --git a/packages/wow/src/character-professions/types.ts b/packages/wow/src/character-professions/types.ts index 5b5f6847..d1a92a40 100644 --- a/packages/wow/src/character-professions/types.ts +++ b/packages/wow/src/character-professions/types.ts @@ -1,4 +1,4 @@ -import type { Character, NameId, NameIdKey, ResponseBase } from '../base'; +import type { Character, NameId, NameIdKey, ResponseBase } from '@blizzard-api/core'; export interface CharacterProfessionsSummaryResponse extends ResponseBase { character: Character; diff --git a/packages/wow/src/character-profile/types.ts b/packages/wow/src/character-profile/types.ts index c0227ee7..1deef20c 100644 --- a/packages/wow/src/character-profile/types.ts +++ b/packages/wow/src/character-profile/types.ts @@ -1,4 +1,4 @@ -import type { Faction, Gender, Href, NameIdKey, Realm, ResponseBase } from '../base'; +import type { Faction, Gender, Href, NameIdKey, Realm, ResponseBase } from '@blizzard-api/core'; export interface CharacterProfileStatusResponse extends ResponseBase { id: number; @@ -10,7 +10,7 @@ export interface CharacterProfileSummaryResponse extends ResponseBase { achievements: Href; achievements_statistics: Href; active_spec: NameIdKey; - active_title: NameIdKey & { display_string: string }; + active_title?: NameIdKey & { display_string: string }; appearance: Href; average_item_level: number; character_class: NameIdKey; @@ -25,6 +25,7 @@ export interface CharacterProfileSummaryResponse extends ResponseBase { guild: Guild; hunter_pets: Href; id: number; + is_remix: boolean; last_login_timestamp: number; level: number; media: Href; diff --git a/packages/wow/src/character-pvp/types.ts b/packages/wow/src/character-pvp/types.ts index 0340e538..d6c94227 100644 --- a/packages/wow/src/character-pvp/types.ts +++ b/packages/wow/src/character-pvp/types.ts @@ -1,4 +1,4 @@ -import type { Character, Faction, KeyBase, NameId, ResponseBase } from '../base'; +import type { Character, Faction, KeyBase, NameId, ResponseBase } from '@blizzard-api/core'; export interface CharacterPvpBracketStatisticsResponse extends ResponseBase { bracket: Bracket; diff --git a/packages/wow/src/character-quests/types.ts b/packages/wow/src/character-quests/types.ts index 8d53315e..3437d39b 100644 --- a/packages/wow/src/character-quests/types.ts +++ b/packages/wow/src/character-quests/types.ts @@ -1,4 +1,4 @@ -import type { Character, Href, NameIdKey, ResponseBase } from '../base'; +import type { Character, Href, NameIdKey, ResponseBase } from '@blizzard-api/core'; export interface CharacterCompletedQuestsResponse extends ResponseBase { character: Character; diff --git a/packages/wow/src/character-reputations/types.ts b/packages/wow/src/character-reputations/types.ts index 1eb3b892..6802ca55 100644 --- a/packages/wow/src/character-reputations/types.ts +++ b/packages/wow/src/character-reputations/types.ts @@ -1,4 +1,4 @@ -import type { Character, NameIdKey, ResponseBase } from '../base'; +import type { Character, NameIdKey, ResponseBase } from '@blizzard-api/core'; export interface CharacterReputationsSummaryResponse extends ResponseBase { character: Character; @@ -21,6 +21,7 @@ interface Standing { max: number; name: string; raw: number; - tier: number; + renown_level?: number; + tier?: number; value: number; } diff --git a/packages/wow/src/character-soulbinds/types.ts b/packages/wow/src/character-soulbinds/types.ts index d5232bf7..34eda19d 100644 --- a/packages/wow/src/character-soulbinds/types.ts +++ b/packages/wow/src/character-soulbinds/types.ts @@ -1,4 +1,4 @@ -import type { Character, NameIdKey, ResponseBase } from '../base'; +import type { Character, NameIdKey, ResponseBase } from '@blizzard-api/core'; export interface CharacterSoulbindsResponse extends ResponseBase { character: Character; diff --git a/packages/wow/src/character-specializations/types.ts b/packages/wow/src/character-specializations/types.ts index d24369b7..f569c371 100644 --- a/packages/wow/src/character-specializations/types.ts +++ b/packages/wow/src/character-specializations/types.ts @@ -1,7 +1,7 @@ -import type { Character, NameIdKey, ResponseBase } from '../base'; +import type { Character, KeyBase, NameIdKey, ResponseBase } from '@blizzard-api/core'; export interface CharacterSpecializationsSummaryResponse extends ResponseBase { - active_hero_talent: NameIdKey; + active_hero_talent_tree: NameIdKey; active_specialization: NameIdKey; character: Character; specializations: Array; @@ -9,9 +9,11 @@ export interface CharacterSpecializationsSummaryResponse extends ResponseBase { interface Loadout { is_active: boolean; - selected_class_talent_tree: NameIdKey; + selected_class_talent_tree: KeyBase & { name: string }; selected_class_talents: Array; - selected_spec_talent_tree: NameIdKey; + selected_hero_talent_tree: NameIdKey; + selected_hero_talents: Array; + selected_spec_talent_tree: KeyBase & { name: string }; selected_spec_talents?: Array; talent_loadout_code: string; } @@ -23,14 +25,14 @@ interface PvpTalentSlot { interface Selected { spell_tooltip: SpellTooltip; - talent: NameIdKey; + talent: KeyBase & { id: number; name?: string }; } interface SelectedTalent { default_points?: number; id: number; rank: number; - tooltip: Selected; + tooltip?: Selected; } interface Specialization { @@ -41,9 +43,9 @@ interface Specialization { } interface SpellTooltip { - cast_time: '1.5 sec cast' | '2.5 sec cast' | '3 sec cast' | 'Channeled' | 'Instant' | 'Passive'; + cast_time?: '1.5 sec cast' | '2.5 sec cast' | '3 sec cast' | 'Channeled' | 'Instant' | 'Passive'; cooldown?: string; - description: string; + description?: string; power_cost?: string; range?: | '8-30 yd range' @@ -54,5 +56,5 @@ interface SpellTooltip { | '55 yd range' | '100 yd range' | 'Melee Range'; - spell: NameIdKey; + spell: KeyBase & { id: number; name?: string }; } diff --git a/packages/wow/src/character-statistics/types.ts b/packages/wow/src/character-statistics/types.ts index 25481820..02284e6d 100644 --- a/packages/wow/src/character-statistics/types.ts +++ b/packages/wow/src/character-statistics/types.ts @@ -1,4 +1,4 @@ -import type { Character, ResponseBase } from '../base'; +import type { Character, NameIdKey, ResponseBase } from '@blizzard-api/core'; export interface CharacterStatisticsSummaryResponse extends ResponseBase { agility: BaseEffectiveStat; @@ -27,7 +27,7 @@ export interface CharacterStatisticsSummaryResponse extends ResponseBase { off_hand_speed: number; parry: RatingWithValue; power: number; - power_type: Character; + power_type: NameIdKey; ranged_crit: RatingWithValue; ranged_haste: RatingWithValue; speed: Rating; @@ -49,12 +49,12 @@ interface BaseEffectiveStat { } interface Rating { - rating: number; rating_bonus: number; + rating_normalized: number; } interface RatingWithValue { - rating: number; rating_bonus: number; + rating_normalized: number; value: number; } diff --git a/packages/wow/src/character-titles/types.ts b/packages/wow/src/character-titles/types.ts index 432cea7d..3ee1c740 100644 --- a/packages/wow/src/character-titles/types.ts +++ b/packages/wow/src/character-titles/types.ts @@ -1,7 +1,7 @@ -import type { Character, NameIdKey, ResponseBase } from '../base'; +import type { Character, NameIdKey, ResponseBase } from '@blizzard-api/core'; export interface CharacterTitlesSummaryResponse extends ResponseBase { - active_title: NameIdKey & { display_string: string }; + active_title?: NameIdKey & { display_string: string }; character: Character; titles: Array; } diff --git a/packages/wow/src/connected-realm/connected-realm.test.ts b/packages/wow/src/connected-realm/connected-realm.test.ts index baf7bb71..062cbf49 100644 --- a/packages/wow/src/connected-realm/connected-realm.test.ts +++ b/packages/wow/src/connected-realm/connected-realm.test.ts @@ -1,5 +1,5 @@ +import { wowSearchBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { searchBase } from '../base'; import { connectedRealm, connectedRealmIndex, connectedRealmSearch } from './connected-realm'; describe.concurrent('connectedRealm', () => { @@ -21,7 +21,7 @@ describe.concurrent('connectedRealm', () => { it('should return the correct resource for connected realm search', ({ expect }) => { const resource = connectedRealmSearch({ _page: 1 }); - expect(resource.path).toBe(`${searchBase}/connected-realm`); + expect(resource.path).toBe(`${wowSearchBasePath}/connected-realm`); expect(resource.namespace).toBe('dynamic'); expect(resource.parameters).toEqual({ _page: 1 }); }); @@ -32,7 +32,7 @@ describe.concurrent('connectedRealm', () => { orderby: ['name', 'id'], }); - expect(resource.path).toBe(`${searchBase}/connected-realm`); + expect(resource.path).toBe(`${wowSearchBasePath}/connected-realm`); expect(resource.namespace).toBe('dynamic'); expect(resource.parameters).toEqual({ _page: 1, diff --git a/packages/wow/src/connected-realm/connected-realm.ts b/packages/wow/src/connected-realm/connected-realm.ts index 5318d000..a2ab31e3 100644 --- a/packages/wow/src/connected-realm/connected-realm.ts +++ b/packages/wow/src/connected-realm/connected-realm.ts @@ -1,10 +1,10 @@ -import type { Resource, SearchResponse } from '@blizzard-api/core'; -import { base } from '../base'; +import type { Resource } from '@blizzard-api/core'; +import { wowBasePath } from '@blizzard-api/core'; import type { ConnectedRealmIndexResponse, ConnectedRealmResponse, ConnectedRealmSearchParameters, - ConnectedRealmSearchResponseItem, + ConnectedRealmSearchResponse, } from './types'; /** @@ -15,7 +15,7 @@ import type { export function connectedRealm(connectedRealmId: number): Resource { return { namespace: 'dynamic', - path: `${base}/connected-realm/${connectedRealmId}`, + path: `${wowBasePath}/connected-realm/${connectedRealmId}`, }; } /** @@ -25,17 +25,17 @@ export function connectedRealm(connectedRealmId: number): Resource { return { namespace: 'dynamic', - path: `${base}/connected-realm/index`, + path: `${wowBasePath}/connected-realm/index`, }; } /** * Search for connected realms. * @param options The search parameters. See {@link ConnectedRealmSearchParameters}. - * @returns The search results. See {@link SearchResponse} & {@link ConnectedRealmSearchResponseItem}. + * @returns The search results. See {@link ConnectedRealmSearchResponse}. */ export function connectedRealmSearch( options: ConnectedRealmSearchParameters, -): Resource, ConnectedRealmSearchParameters> { +): Resource { return { namespace: 'dynamic', parameters: { @@ -44,6 +44,6 @@ export function connectedRealmSearch( 'realms.timezone': options['realms.timezone'], 'status.type': options['status.type'], }, - path: `${base}/search/connected-realm`, + path: `${wowBasePath}/search/connected-realm`, }; } diff --git a/packages/wow/src/connected-realm/types.ts b/packages/wow/src/connected-realm/types.ts index 588990d4..aca5a51f 100644 --- a/packages/wow/src/connected-realm/types.ts +++ b/packages/wow/src/connected-realm/types.ts @@ -1,27 +1,34 @@ -import type { BaseSearchParameters, Locales } from '@blizzard-api/core'; -import type { KeyBase, NameIdKey, ResponseBase } from '../base'; -import type { RealmCategory, RealmTimezone, RealmType, RealmTypeCapitalized, WithoutUnderscore } from '../realm/types'; +import type { + BaseSearchParameters, + Href, + KeyBase, + Locales, + NameIdKey, + ResponseBase, + SearchResponseWithoutResults, +} from '@blizzard-api/core'; +import type { RealmCategory, RealmLocales, RealmTimezone, RealmTypeCapitalized } from '../realm/types'; /** * Connected Realm Index API response. * @see https://develop.battle.net/documentation/world-of-warcraft/game-data-apis */ export interface ConnectedRealmIndexResponse extends ResponseBase { - connected_realms: Array<{ href: string }>; + connected_realms: Array; } /** * Connected Realm API response. * @see https://develop.battle.net/documentation/world-of-warcraft/game-data-apis */ export interface ConnectedRealmResponse extends ResponseBase { - auctions: { href: string }; + auctions: Href; has_queue: boolean; id: number; - mythic_leaderboards: { href: string }; - population: { name: RealmPopulation; type: RealmPopulationCapitalized }; + mythic_leaderboards: Href; + population: { name: string; type: RealmPopulationCapitalized }; realm_locked_status?: RealmLockedStatus; realms: Array; - status: { name: RealmStatus; type: Uppercase }; + status: { name: RealmStatus; type: RealmStatusCapitalized }; } /** * Connected Realm Search API parameters. @@ -30,7 +37,7 @@ export interface ConnectedRealmResponse extends ResponseBase { */ export interface ConnectedRealmSearchParameters extends BaseSearchParameters { 'realms.timezone'?: RealmTimezone; - 'status.type'?: Uppercase; + 'status.type'?: RealmStatusCapitalized; } /** @@ -38,7 +45,11 @@ export interface ConnectedRealmSearchParameters extends BaseSearchParameters { * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} * @see {@link https://develop.battle.net/documentation/world-of-warcraft/guides/search} */ -export interface ConnectedRealmSearchResponseItem extends KeyBase { +export interface ConnectedRealmSearchResponse extends SearchResponseWithoutResults { + results: Array; +} + +interface ConnectedRealmSearchResponseItem extends KeyBase { data: { has_queue: boolean; id: number; @@ -50,15 +61,15 @@ export interface ConnectedRealmSearchResponseItem extends KeyBase { interface Realm { category: RealmCategory; - connected_realm: { href: string }; + connected_realm: Href; id: number; is_tournament: boolean; - locale: WithoutUnderscore; + locale: RealmLocales; name: string; region: NameIdKey; slug: string; timezone: RealmTimezone; - type: { name: RealmType; type: RealmTypeCapitalized }; + type: { name: string; type: RealmTypeCapitalized }; } interface RealmLockedStatus { @@ -66,22 +77,22 @@ interface RealmLockedStatus { is_locked_for_pct: boolean; } -type RealmPopulation = 'Full' | 'High' | 'Low' | 'Medium' | 'New Players'; - type RealmPopulationCapitalized = 'FULL' | 'HIGH' | 'LOW' | 'MEDIUM' | 'RECOMMENDED'; type RealmStatus = 'Down' | 'Up'; +type RealmStatusCapitalized = 'DOWN' | 'UP'; + interface SearchRealm { - category: Record; + category: Record; id: number; is_tournament: boolean; - locale: WithoutUnderscore; - name: Record; - region: { id: number; name: Record }; + locale: RealmLocales; + name: Record; + region: { id: number; name: Record }; slug: string; timezone: RealmTimezone; - type: { name: Record; type: RealmTypeCapitalized }; + type: { name: Record; type: RealmTypeCapitalized }; } interface SearchRealmPopulation { @@ -91,5 +102,5 @@ interface SearchRealmPopulation { interface SearchRealmStatus { name: Record; - type: Uppercase; + type: RealmStatusCapitalized; } diff --git a/packages/wow/src/covenant/covenant.test.ts b/packages/wow/src/covenant/covenant.test.ts index e9a05259..75928136 100644 --- a/packages/wow/src/covenant/covenant.test.ts +++ b/packages/wow/src/covenant/covenant.test.ts @@ -1,5 +1,5 @@ +import { wowBasePath, wowMediaBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base, mediaBase } from '../base'; import { conduit, conduitIndex, covenant, covenantIndex, covenantMedia, soulbind, soulbindIndex } from './covenant'; describe.concurrent('covenantApi', () => { @@ -7,14 +7,14 @@ describe.concurrent('covenantApi', () => { const conduitId = 123; const resource = conduit(conduitId); - expect(resource.path).toBe(`${base}/covenant/conduit/123`); + expect(resource.path).toBe(`${wowBasePath}/covenant/conduit/123`); expect(resource.namespace).toBe('static'); }); it('should return the correct path and namespace for conduitIndex', ({ expect }) => { const resource = conduitIndex(); - expect(resource.path).toBe(`${base}/covenant/conduit/index`); + expect(resource.path).toBe(`${wowBasePath}/covenant/conduit/index`); expect(resource.namespace).toBe('static'); }); @@ -22,14 +22,14 @@ describe.concurrent('covenantApi', () => { const covenantId = 123; const resource = covenant(covenantId); - expect(resource.path).toBe(`${base}/covenant/123`); + expect(resource.path).toBe(`${wowBasePath}/covenant/123`); expect(resource.namespace).toBe('static'); }); it('should return the correct path and namespace for covenantIndex', ({ expect }) => { const resource = covenantIndex(); - expect(resource.path).toBe(`${base}/covenant/index`); + expect(resource.path).toBe(`${wowBasePath}/covenant/index`); expect(resource.namespace).toBe('static'); }); @@ -37,7 +37,7 @@ describe.concurrent('covenantApi', () => { const covenantId = 123; const resource = covenantMedia(covenantId); - expect(resource.path).toBe(`${mediaBase}/covenant/123`); + expect(resource.path).toBe(`${wowMediaBasePath}/covenant/123`); expect(resource.namespace).toBe('static'); }); @@ -45,14 +45,14 @@ describe.concurrent('covenantApi', () => { const soulbindId = 123; const resource = soulbind(soulbindId); - expect(resource.path).toBe(`${base}/covenant/soulbind/123`); + expect(resource.path).toBe(`${wowBasePath}/covenant/soulbind/123`); expect(resource.namespace).toBe('static'); }); it('should return the correct path and namespace for soulbindIndex', ({ expect }) => { const resource = soulbindIndex(); - expect(resource.path).toBe(`${base}/covenant/soulbind/index`); + expect(resource.path).toBe(`${wowBasePath}/covenant/soulbind/index`); expect(resource.namespace).toBe('static'); }); }); diff --git a/packages/wow/src/covenant/covenant.ts b/packages/wow/src/covenant/covenant.ts index 055d036c..8765d1f8 100644 --- a/packages/wow/src/covenant/covenant.ts +++ b/packages/wow/src/covenant/covenant.ts @@ -1,5 +1,5 @@ import type { Resource } from '@blizzard-api/core'; -import { base, mediaBase } from '../base'; +import { wowBasePath, wowMediaBasePath } from '@blizzard-api/core'; import type { ConduitIndexResponse, ConduitResponse, @@ -18,7 +18,7 @@ import type { export function conduit(conduitId: number): Resource { return { namespace: 'static', - path: `${base}/covenant/conduit/${conduitId}`, + path: `${wowBasePath}/covenant/conduit/${conduitId}`, }; } /** @@ -28,7 +28,7 @@ export function conduit(conduitId: number): Resource { export function conduitIndex(): Resource { return { namespace: 'static', - path: `${base}/covenant/conduit/index`, + path: `${wowBasePath}/covenant/conduit/index`, }; } /** @@ -39,7 +39,7 @@ export function conduitIndex(): Resource { export function covenant(covenantId: number): Resource { return { namespace: 'static', - path: `${base}/covenant/${covenantId}`, + path: `${wowBasePath}/covenant/${covenantId}`, }; } /** @@ -49,7 +49,7 @@ export function covenant(covenantId: number): Resource { export function covenantIndex(): Resource { return { namespace: 'static', - path: `${base}/covenant/index`, + path: `${wowBasePath}/covenant/index`, }; } /** @@ -60,7 +60,7 @@ export function covenantIndex(): Resource { export function covenantMedia(covenantId: number): Resource { return { namespace: 'static', - path: `${mediaBase}/covenant/${covenantId}`, + path: `${wowMediaBasePath}/covenant/${covenantId}`, }; } /** @@ -71,7 +71,7 @@ export function covenantMedia(covenantId: number): Resource { return { namespace: 'static', - path: `${base}/covenant/soulbind/${soulbindId}`, + path: `${wowBasePath}/covenant/soulbind/${soulbindId}`, }; } /** @@ -81,6 +81,6 @@ export function soulbind(soulbindId: number): Resource { export function soulbindIndex(): Resource { return { namespace: 'static', - path: `${base}/covenant/soulbind/index`, + path: `${wowBasePath}/covenant/soulbind/index`, }; } diff --git a/packages/wow/src/covenant/types.ts b/packages/wow/src/covenant/types.ts index 683a127e..1b1dc178 100644 --- a/packages/wow/src/covenant/types.ts +++ b/packages/wow/src/covenant/types.ts @@ -1,4 +1,4 @@ -import type { KeyBase, NameIdKey, ResponseBase } from '../base'; +import type { KeyBase, MediaAsset, NameId, NameIdKey, ResponseBase } from '@blizzard-api/core'; /** * Interface for a response from the conduit index endpoint. @@ -14,7 +14,7 @@ export interface ConduitIndexResponse extends ResponseBase { */ export interface ConduitResponse extends ResponseBase { id: number; - item: Item; + item: NameIdKey; name: string; ranks: Array; socket_type: SocketType; @@ -33,14 +33,7 @@ export interface CovenantIndexResponse extends ResponseBase { * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} */ export interface CovenantMediaResponse extends ResponseBase { - class_abilities: Array; - description: string; - id: number; - media: Media; - name: string; - renown_rewards: Array; - signature_ability: SignatureAbility; - soulbinds: Array; + assets?: Array; } /** @@ -48,10 +41,14 @@ export interface CovenantMediaResponse extends ResponseBase { * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} */ export interface CovenantResponse extends ResponseBase { + class_abilities?: Array; description: string; id: number; + media?: Media; name: string; renown_rewards: Array; + signature_ability?: SignatureAbility; + soulbinds?: Array; } /** @@ -69,7 +66,7 @@ export interface SoulbindIndexResponse extends ResponseBase { export interface SoulbindResponse extends ResponseBase { covenant: NameIdKey; creature: NameIdKey; - follower: NameIdKey; + follower: NameId; id: number; name: string; talent_tree: NameIdKey; @@ -90,10 +87,6 @@ interface ClassAbilitySpellTooltip { spell: NameIdKey; } -interface Item extends KeyBase { - id: number; -} - interface Media extends KeyBase { id: number; } @@ -116,8 +109,9 @@ interface SignatureAbility { interface SignatureAbilitySpellTooltip { cast_time: string; - cooldown: string; + cooldown?: string; description: string; + range?: string; spell: NameIdKey; } @@ -129,5 +123,5 @@ interface SocketType { interface SpellTooltip { cast_time: string; description: string; - spell: Item; + spell: NameIdKey; } diff --git a/packages/wow/src/creature/creature.test.ts b/packages/wow/src/creature/creature.test.ts index 575ed4f3..cb2cd383 100644 --- a/packages/wow/src/creature/creature.test.ts +++ b/packages/wow/src/creature/creature.test.ts @@ -1,5 +1,5 @@ +import { wowBasePath, wowMediaBasePath, wowSearchBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base, mediaBase, searchBase } from '../base'; import { creature, creatureDisplayMedia, @@ -16,7 +16,7 @@ describe.concurrent('creatureApi', () => { const creatureId = 123; const resource = creature(creatureId); - expect(resource.path).toBe(`${base}/creature/${creatureId}`); + expect(resource.path).toBe(`${wowBasePath}/creature/${creatureId}`); expect(resource.namespace).toBe('static'); }); @@ -24,7 +24,7 @@ describe.concurrent('creatureApi', () => { const creatureDisplayId = 123; const resource = creatureDisplayMedia(creatureDisplayId); - expect(resource.path).toBe(`${mediaBase}/creature-display/${creatureDisplayId}`); + expect(resource.path).toBe(`${wowMediaBasePath}/creature-display/${creatureDisplayId}`); expect(resource.namespace).toBe('static'); }); @@ -32,14 +32,14 @@ describe.concurrent('creatureApi', () => { const creatureFamilyId = 123; const resource = creatureFamily(creatureFamilyId); - expect(resource.path).toBe(`${base}/creature-family/${creatureFamilyId}`); + expect(resource.path).toBe(`${wowBasePath}/creature-family/${creatureFamilyId}`); expect(resource.namespace).toBe('static'); }); it('should return the correct path and namespace for creatureFamilyIndex', ({ expect }) => { const resource = creatureFamilyIndex(); - expect(resource.path).toBe(`${base}/creature-family/index`); + expect(resource.path).toBe(`${wowBasePath}/creature-family/index`); expect(resource.namespace).toBe('static'); }); @@ -47,7 +47,7 @@ describe.concurrent('creatureApi', () => { const creatureFamilyId = 123; const resource = creatureFamilyMedia(creatureFamilyId); - expect(resource.path).toBe(`${mediaBase}/creature-family/${creatureFamilyId}`); + expect(resource.path).toBe(`${wowMediaBasePath}/creature-family/${creatureFamilyId}`); expect(resource.namespace).toBe('static'); }); @@ -55,14 +55,14 @@ describe.concurrent('creatureApi', () => { const creatureTypeId = 123; const resource = creatureType(creatureTypeId); - expect(resource.path).toBe(`${base}/creature-type/${creatureTypeId}`); + expect(resource.path).toBe(`${wowBasePath}/creature-type/${creatureTypeId}`); expect(resource.namespace).toBe('static'); }); it('should return the correct path and namespace for creatureTypeIndex', ({ expect }) => { const resource = creatureTypeIndex(); - expect(resource.path).toBe(`${base}/creature-type/index`); + expect(resource.path).toBe(`${wowBasePath}/creature-type/index`); expect(resource.namespace).toBe('static'); }); @@ -73,7 +73,7 @@ describe.concurrent('creatureApi', () => { name: 'test', }); - expect(resource.path).toBe(`${searchBase}/creature`); + expect(resource.path).toBe(`${wowSearchBasePath}/creature`); expect(resource.namespace).toBe('static'); expect(resource.parameters).toEqual({ _page: 1, @@ -89,7 +89,7 @@ describe.concurrent('creatureApi', () => { orderby: ['name', 'id'], }); - expect(resource.path).toBe(`${searchBase}/creature`); + expect(resource.path).toBe(`${wowSearchBasePath}/creature`); expect(resource.namespace).toBe('static'); expect(resource.parameters).toEqual({ _page: 1, diff --git a/packages/wow/src/creature/creature.ts b/packages/wow/src/creature/creature.ts index f80161d4..00799dde 100644 --- a/packages/wow/src/creature/creature.ts +++ b/packages/wow/src/creature/creature.ts @@ -1,5 +1,5 @@ -import type { Resource, SearchResponse } from '@blizzard-api/core'; -import { base, mediaBase, searchBase } from '../base'; +import type { Resource } from '@blizzard-api/core'; +import { wowBasePath, wowMediaBasePath, wowSearchBasePath } from '@blizzard-api/core'; import type { CreatureDisplayMediaResponse, CreatureFamilyIndexResponse, @@ -7,7 +7,7 @@ import type { CreatureFamilyResponse, CreatureResponse, CreatureSearchParameters, - CreatureSearchResponseItem, + CreatureSearchResponse, CreatureTypeIndexResponse, CreatureTypeResponse, } from './types'; @@ -20,7 +20,7 @@ import type { export function creature(creatureId: number): Resource { return { namespace: 'static', - path: `${base}/creature/${creatureId}`, + path: `${wowBasePath}/creature/${creatureId}`, }; } /** @@ -31,7 +31,7 @@ export function creature(creatureId: number): Resource { export function creatureDisplayMedia(creatureDisplayId: number): Resource { return { namespace: 'static', - path: `${mediaBase}/creature-display/${creatureDisplayId}`, + path: `${wowMediaBasePath}/creature-display/${creatureDisplayId}`, }; } /** @@ -42,7 +42,7 @@ export function creatureDisplayMedia(creatureDisplayId: number): Resource { return { namespace: 'static', - path: `${base}/creature-family/${creatureFamilyId}`, + path: `${wowBasePath}/creature-family/${creatureFamilyId}`, }; } /** @@ -52,7 +52,7 @@ export function creatureFamily(creatureFamilyId: number): Resource { return { namespace: 'static', - path: `${base}/creature-family/index`, + path: `${wowBasePath}/creature-family/index`, }; } /** @@ -63,17 +63,17 @@ export function creatureFamilyIndex(): Resource { export function creatureFamilyMedia(creatureFamilyId: number): Resource { return { namespace: 'static', - path: `${mediaBase}/creature-family/${creatureFamilyId}`, + path: `${wowMediaBasePath}/creature-family/${creatureFamilyId}`, }; } /** * Search for creatures. * @param options The creature search parameters. See {@link CreatureSearchParameters}. - * @returns The creature search results. See {@link SearchResponse} & {@link CreatureSearchResponseItem}. + * @returns The creature search results. See {@link CreatureSearchResponse}. */ export function creatureSearch( options: CreatureSearchParameters, -): Resource, Omit> { +): Resource> { return { namespace: 'static', parameters: { @@ -81,7 +81,7 @@ export function creatureSearch( [`name.${options.locale}`]: options.name, orderby: Array.isArray(options.orderby) ? options.orderby.join(',') : options.orderby, }, - path: `${searchBase}/creature`, + path: `${wowSearchBasePath}/creature`, }; } /** @@ -92,7 +92,7 @@ export function creatureSearch( export function creatureType(creatureTypeId: number): Resource { return { namespace: 'static', - path: `${base}/creature-type/${creatureTypeId}`, + path: `${wowBasePath}/creature-type/${creatureTypeId}`, }; } /** @@ -102,6 +102,6 @@ export function creatureType(creatureTypeId: number): Resource { return { namespace: 'static', - path: `${base}/creature-type/index`, + path: `${wowBasePath}/creature-type/index`, }; } diff --git a/packages/wow/src/creature/types.ts b/packages/wow/src/creature/types.ts index 3049ce95..83d105d3 100644 --- a/packages/wow/src/creature/types.ts +++ b/packages/wow/src/creature/types.ts @@ -1,5 +1,12 @@ -import type { BaseSearchParameters, Locales } from '@blizzard-api/core'; -import type { KeyBase, MediaAsset, NameIdKey, ResponseBase } from '../base'; +import type { + BaseSearchParameters, + KeyBase, + Locales, + MediaAsset, + NameIdKey, + ResponseBase, + SearchResponseWithoutResults, +} from '@blizzard-api/core'; /** * The response for creature display media. @@ -66,15 +73,8 @@ export interface CreatureSearchParameters extends BaseSearchParameters { * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} * @see {@link https://develop.battle.net/documentation/world-of-warcraft/guides/search} */ -export interface CreatureSearchResponseItem extends KeyBase { - data: { - creature_displays: Array<{ id: number }>; - family?: { id: number; name: Record }; - id: number; - is_tameable: boolean; - name: Record; - type: { id: number; name: Record }; - }; +export interface CreatureSearchResponse extends SearchResponseWithoutResults { + results: Array; } /** @@ -98,6 +98,17 @@ interface CreatureDisplay extends KeyBase { id: number; } +interface CreatureSearchResponseItem extends KeyBase { + data: { + creature_displays: Array<{ id: number }>; + family?: { id: number; name: Record }; + id: number; + is_tameable: boolean; + name: Record; + type: { id: number; name: Record }; + }; +} + interface DisplayMediaAsset { key: string; value: string; diff --git a/packages/wow/src/guild-crest/guild-crest.test.ts b/packages/wow/src/guild-crest/guild-crest.test.ts index 6b5093d6..16fcb1ff 100644 --- a/packages/wow/src/guild-crest/guild-crest.test.ts +++ b/packages/wow/src/guild-crest/guild-crest.test.ts @@ -1,25 +1,25 @@ +import { wowBasePath, wowMediaBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base, mediaBase } from '../base'; import { guildCrestBorder, guildCrestComponentsIndex, guildCrestEmblem } from './guild-crest'; describe.concurrent('guildCrestApi', () => { it('should return the guild crest components index resource', ({ expect }) => { const resource = guildCrestComponentsIndex(); - expect(resource.path).toBe(`${base}/guild-crest/index`); + expect(resource.path).toBe(`${wowBasePath}/guild-crest/index`); expect(resource.namespace).toBe('static'); }); it('should return the guild crest border resource for a given borderId', ({ expect }) => { const borderId = 123; const resource = guildCrestBorder(borderId); - expect(resource.path).toBe(`${mediaBase}/guild-crest/border/123`); + expect(resource.path).toBe(`${wowMediaBasePath}/guild-crest/border/123`); expect(resource.namespace).toBe('static'); }); it('should return the guild crest emblem resource for a given emblemId', ({ expect }) => { const emblemId = 456; const resource = guildCrestEmblem(emblemId); - expect(resource.path).toBe(`${mediaBase}/guild-crest/emblem/456`); + expect(resource.path).toBe(`${wowMediaBasePath}/guild-crest/emblem/456`); expect(resource.namespace).toBe('static'); }); }); diff --git a/packages/wow/src/guild-crest/guild-crest.ts b/packages/wow/src/guild-crest/guild-crest.ts index ec9f3c13..959f44ab 100644 --- a/packages/wow/src/guild-crest/guild-crest.ts +++ b/packages/wow/src/guild-crest/guild-crest.ts @@ -1,5 +1,5 @@ import type { Resource } from '@blizzard-api/core'; -import { base, mediaBase } from '../base'; +import { wowBasePath, wowMediaBasePath } from '@blizzard-api/core'; import type { GuildCrestBorderEmblemResponse, GuildCrestComponentsIndexResponse } from './types'; /** @@ -10,7 +10,7 @@ import type { GuildCrestBorderEmblemResponse, GuildCrestComponentsIndexResponse export function guildCrestBorder(borderId: number): Resource { return { namespace: 'static', - path: `${mediaBase}/guild-crest/border/${borderId}`, + path: `${wowMediaBasePath}/guild-crest/border/${borderId}`, }; } /** @@ -20,7 +20,7 @@ export function guildCrestBorder(borderId: number): Resource { return { namespace: 'static', - path: `${base}/guild-crest/index`, + path: `${wowBasePath}/guild-crest/index`, }; } /** @@ -31,6 +31,6 @@ export function guildCrestComponentsIndex(): Resource { return { namespace: 'static', - path: `${mediaBase}/guild-crest/emblem/${emblemId}`, + path: `${wowMediaBasePath}/guild-crest/emblem/${emblemId}`, }; } diff --git a/packages/wow/src/guild-crest/types.ts b/packages/wow/src/guild-crest/types.ts index 6e0c2b2e..c786d7fa 100644 --- a/packages/wow/src/guild-crest/types.ts +++ b/packages/wow/src/guild-crest/types.ts @@ -1,4 +1,4 @@ -import type { KeyBase, ResponseBase } from '../base'; +import type { Color, KeyBase, ResponseBase } from '@blizzard-api/core'; /** * The response for a guild crest border or emblem. @@ -21,7 +21,7 @@ export interface GuildCrestComponentsIndexResponse extends ResponseBase { interface Background { id: number; - rgba: RGBA; + rgba: Color; } interface Border { @@ -43,10 +43,3 @@ interface GuildCrestAsset { interface Media extends KeyBase { id: number; } - -interface RGBA { - a: number; - b: number; - g: number; - r: number; -} diff --git a/packages/wow/src/guild/types.ts b/packages/wow/src/guild/types.ts index 07bb7510..e0d7f606 100644 --- a/packages/wow/src/guild/types.ts +++ b/packages/wow/src/guild/types.ts @@ -1,4 +1,14 @@ -import type { Character, Color, Faction, Href, KeyBase, NameIdKey, Realm, ResponseBase } from '../base'; +import type { + Character, + Color, + Faction, + Factions, + Href, + KeyBase, + NameIdKey, + Realm, + ResponseBase, +} from '@blizzard-api/core'; export interface GuildAchievementsResponse extends ResponseBase { achievements: Array; @@ -43,7 +53,8 @@ interface Achievement { interface ActivityElement { activity: { type: string }; - character_achievement: CharacterAchievement; + character_achievement?: CharacterAchievement; + encounter_completed?: EncounterActivity; timestamp: number; } @@ -64,6 +75,12 @@ interface CharacterAchievement { character: Character; } +interface ChildCriterum { + amount: number; + id: number; + is_completed: boolean; +} + interface Crest { background: { color: RgbWithId }; border: Border; @@ -72,11 +89,16 @@ interface Crest { interface Criteria { amount?: number; - child_criteria?: Array; + child_criteria?: Array; id: number; is_completed: boolean; } +interface EncounterActivity { + encounter: NameIdKey; + mode: { name: string; type: 'MYTHIC' }; +} + interface Guild extends NameIdKey { faction: Faction; realm: Realm; @@ -102,6 +124,7 @@ interface RgbWithId { } interface RosterMemberCharacter extends Character { + faction: { type: Factions }; level: number; playable_class: Playable; playable_race: Playable; diff --git a/packages/wow/src/heirloom/heirloom.test.ts b/packages/wow/src/heirloom/heirloom.test.ts index 265bed64..f4eefaac 100644 --- a/packages/wow/src/heirloom/heirloom.test.ts +++ b/packages/wow/src/heirloom/heirloom.test.ts @@ -1,18 +1,18 @@ +import { wowBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base } from '../base'; import { heirloom, heirloomIndex } from './heirloom'; describe.concurrent('heirloomApi', () => { it('should return the heirloom resource for a given heirloomId', ({ expect }) => { const heirloomId = 123; const resource = heirloom(heirloomId); - expect(resource.path).toBe(`${base}/heirloom/${heirloomId}`); + expect(resource.path).toBe(`${wowBasePath}/heirloom/${heirloomId}`); expect(resource.namespace).toBe('static'); }); it('should return the heirloom index resource', ({ expect }) => { const resource = heirloomIndex(); - expect(resource.path).toBe(`${base}/heirloom/index`); + expect(resource.path).toBe(`${wowBasePath}/heirloom/index`); expect(resource.namespace).toBe('static'); }); }); diff --git a/packages/wow/src/heirloom/heirloom.ts b/packages/wow/src/heirloom/heirloom.ts index 55eb6291..7789a896 100644 --- a/packages/wow/src/heirloom/heirloom.ts +++ b/packages/wow/src/heirloom/heirloom.ts @@ -1,5 +1,5 @@ import type { Resource } from '@blizzard-api/core'; -import { base } from '../base'; +import { wowBasePath } from '@blizzard-api/core'; import type { HeirloomIndexResponse, HeirloomResponse } from './types'; /** @@ -10,7 +10,7 @@ import type { HeirloomIndexResponse, HeirloomResponse } from './types'; export function heirloom(heirloomId: number): Resource { return { namespace: 'static', - path: `${base}/heirloom/${heirloomId}`, + path: `${wowBasePath}/heirloom/${heirloomId}`, }; } /** @@ -20,6 +20,6 @@ export function heirloom(heirloomId: number): Resource { export function heirloomIndex(): Resource { return { namespace: 'static', - path: `${base}/heirloom/index`, + path: `${wowBasePath}/heirloom/index`, }; } diff --git a/packages/wow/src/heirloom/types.ts b/packages/wow/src/heirloom/types.ts index 1ca4d932..7b87dda6 100644 --- a/packages/wow/src/heirloom/types.ts +++ b/packages/wow/src/heirloom/types.ts @@ -1,4 +1,4 @@ -import type { Color, KeyBase, NameIdKey, ResponseBase } from '../base'; +import type { Color, KeyBase, NameIdKey, ResponseBase } from '@blizzard-api/core'; /** * The response for the heirloom index. diff --git a/packages/wow/src/item/item.test.ts b/packages/wow/src/item/item.test.ts index 7acbaab5..cd67bffb 100644 --- a/packages/wow/src/item/item.test.ts +++ b/packages/wow/src/item/item.test.ts @@ -1,19 +1,19 @@ +import { wowBasePath, wowMediaBasePath, wowSearchBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base, mediaBase, searchBase } from '../base'; import { item, itemClass, itemClassIndex, itemMedia, itemSearch, itemSet, itemSetIndex, itemSubClass } from './item'; describe.concurrent('itemApi', () => { it('should return the item resource for a given itemId', ({ expect }) => { const itemId = 123; const resource = item(itemId); - expect(resource.path).toBe(`${base}/item/${itemId}`); + expect(resource.path).toBe(`${wowBasePath}/item/${itemId}`); expect(resource.namespace).toBe('static'); }); it('should return the item class resource for a given itemClassId', ({ expect }) => { const itemClassId = 456; const resource = itemClass(itemClassId); - expect(resource.path).toBe(`${base}/item-class/${itemClassId}`); + expect(resource.path).toBe(`${wowBasePath}/item-class/${itemClassId}`); expect(resource.namespace).toBe('static'); }); @@ -21,33 +21,33 @@ describe.concurrent('itemApi', () => { const itemClassId = 456; const itemSubClassId = 789; const resource = itemSubClass(itemClassId, itemSubClassId); - expect(resource.path).toBe(`${base}/item-class/${itemClassId}/item-subclass/${itemSubClassId}`); + expect(resource.path).toBe(`${wowBasePath}/item-class/${itemClassId}/item-subclass/${itemSubClassId}`); expect(resource.namespace).toBe('static'); }); it('should return the item class index resource', ({ expect }) => { const resource = itemClassIndex(); - expect(resource.path).toBe(`${base}/item-class/index`); + expect(resource.path).toBe(`${wowBasePath}/item-class/index`); expect(resource.namespace).toBe('static'); }); it('should return the item media resource for a given itemId', ({ expect }) => { const itemId = 789; const resource = itemMedia(itemId); - expect(resource.path).toBe(`${mediaBase}/item/${itemId}`); + expect(resource.path).toBe(`${wowMediaBasePath}/item/${itemId}`); expect(resource.namespace).toBe('static'); }); it('should return the item set resource for a given itemSetId', ({ expect }) => { const itemSetId = 987; const resource = itemSet(itemSetId); - expect(resource.path).toBe(`${base}/item-set/${itemSetId}`); + expect(resource.path).toBe(`${wowBasePath}/item-set/${itemSetId}`); expect(resource.namespace).toBe('static'); }); it('should return the item set index resource', ({ expect }) => { const resource = itemSetIndex(); - expect(resource.path).toBe(`${base}/item-set/index`); + expect(resource.path).toBe(`${wowBasePath}/item-set/index`); expect(resource.namespace).toBe('static'); }); @@ -59,7 +59,7 @@ describe.concurrent('itemApi', () => { orderby: 'name', }); - expect(resource.path).toBe(`${searchBase}/item`); + expect(resource.path).toBe(`${wowSearchBasePath}/item`); expect(resource.namespace).toBe('static'); expect(resource.parameters).toEqual({ _page: 1, @@ -76,7 +76,7 @@ describe.concurrent('itemApi', () => { orderby: ['name', 'id'], }); - expect(resource.path).toBe(`${searchBase}/item`); + expect(resource.path).toBe(`${wowSearchBasePath}/item`); expect(resource.namespace).toBe('static'); expect(resource.parameters).toEqual({ _page: 1, diff --git a/packages/wow/src/item/item.ts b/packages/wow/src/item/item.ts index 20ec0772..400d50b5 100644 --- a/packages/wow/src/item/item.ts +++ b/packages/wow/src/item/item.ts @@ -1,12 +1,12 @@ -import type { Resource, SearchResponse } from '@blizzard-api/core'; -import { base, mediaBase, searchBase } from '../base'; +import type { Resource } from '@blizzard-api/core'; +import { wowBasePath, wowMediaBasePath, wowSearchBasePath } from '@blizzard-api/core'; import type { ItemClassIndexResponse, ItemClassResponse, ItemMediaResponse, ItemResponse, ItemSearchParameters, - ItemSearchResponseItem, + ItemSearchResponse, ItemSetIndexResponse, ItemSetResponse, ItemSubClassResponse, @@ -20,7 +20,7 @@ import type { export function item(itemId: number): Resource { return { namespace: 'static', - path: `${base}/item/${itemId}`, + path: `${wowBasePath}/item/${itemId}`, }; } /** @@ -31,7 +31,7 @@ export function item(itemId: number): Resource { export function itemClass(itemClassId: number): Resource { return { namespace: 'static', - path: `${base}/item-class/${itemClassId}`, + path: `${wowBasePath}/item-class/${itemClassId}`, }; } /** @@ -41,7 +41,7 @@ export function itemClass(itemClassId: number): Resource { export function itemClassIndex(): Resource { return { namespace: 'static', - path: `${base}/item-class/index`, + path: `${wowBasePath}/item-class/index`, }; } /** @@ -52,17 +52,17 @@ export function itemClassIndex(): Resource { export function itemMedia(itemId: number): Resource { return { namespace: 'static', - path: `${mediaBase}/item/${itemId}`, + path: `${wowMediaBasePath}/item/${itemId}`, }; } /** * Search for items. * @param options The search parameters. See {@link ItemSearchParameters}. - * @returns The search results. See {@link SearchResponse}. + * @returns The search results. See {@link ItemSearchResponse}. */ export function itemSearch( options: ItemSearchParameters, -): Resource, Omit> { +): Resource> { return { namespace: 'static', parameters: { @@ -70,7 +70,7 @@ export function itemSearch( [`name.${options.locale}`]: options.name, orderby: Array.isArray(options.orderby) ? options.orderby.join(',') : options.orderby, }, - path: `${searchBase}/item`, + path: `${wowSearchBasePath}/item`, }; } /** @@ -81,7 +81,7 @@ export function itemSearch( export function itemSet(itemSetId: number): Resource { return { namespace: 'static', - path: `${base}/item-set/${itemSetId}`, + path: `${wowBasePath}/item-set/${itemSetId}`, }; } /** @@ -91,7 +91,7 @@ export function itemSet(itemSetId: number): Resource { export function itemSetIndex(): Resource { return { namespace: 'static', - path: `${base}/item-set/index`, + path: `${wowBasePath}/item-set/index`, }; } /** @@ -103,6 +103,6 @@ export function itemSetIndex(): Resource { export function itemSubClass(itemClassId: number, itemSubclassId: number): Resource { return { namespace: 'static', - path: `${base}/item-class/${itemClassId}/item-subclass/${itemSubclassId}`, + path: `${wowBasePath}/item-class/${itemClassId}/item-subclass/${itemSubclassId}`, }; } diff --git a/packages/wow/src/item/types.ts b/packages/wow/src/item/types.ts index a2a45db2..473491bf 100644 --- a/packages/wow/src/item/types.ts +++ b/packages/wow/src/item/types.ts @@ -1,5 +1,14 @@ -import type { BaseSearchParameters, Locales } from '@blizzard-api/core'; -import type { Color, KeyBase, MediaAsset, NameId, NameIdKey, ResponseBase } from '../base'; +import type { + BaseSearchParameters, + Color, + KeyBase, + Locales, + MediaAsset, + NameId, + NameIdKey, + ResponseBase, + SearchResponseWithoutResults, +} from '@blizzard-api/core'; /** * The response for an item class index. @@ -33,8 +42,9 @@ export interface ItemMediaResponse extends ResponseBase { * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} */ export interface ItemResponse extends NameId, ResponseBase { + appearances?: Array; description?: string; - inventory_type: InventoryType; + inventory_type: InventoryTypeName; is_equippable: boolean; is_stackable: boolean; item_class: NameIdKey; @@ -65,24 +75,8 @@ export interface ItemSearchParameters extends BaseSearchParameters { * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} * @see {@link https://develop.battle.net/documentation/world-of-warcraft/guides/search} */ -export interface ItemSearchResponseItem extends KeyBase { - data: { - id: number; - inventory_type: InventoryType; - is_equippable: boolean; - is_stackable: boolean; - item_class: { id: number; name: Record }; - item_subclass: { id: number; name: Record }; - level: number; - max_count: number; - media: { id: number }; - name: Record; - purchase_price: number; - purchase_quantity: number; - quality: ItemQuality; - required_level: number; - sell_price: number; - }; +export interface ItemSearchResponse extends SearchResponseWithoutResults { + results: Array; } /** @@ -111,9 +105,9 @@ export interface ItemSetResponse extends ResponseBase { export interface ItemSubClassResponse extends ResponseBase { class_id: number; display_name: string; - hide_subclass_in_tooltips: boolean; + hide_subclass_in_tooltips?: boolean; subclass_id: number; - verbose_name: string; + verbose_name?: string; } interface Armor { @@ -146,33 +140,74 @@ interface Effect { required_count: number; } -interface InventoryType { - name: Record; - type: //Armor - | 'BACK' - | 'BAG' - | 'CHEST' - | 'FEET' - | 'FINGER' - | 'HANDS' - | 'HEAD' - | 'LEGS' - | 'NECK' - | 'NON_EQUIP' - | 'SHIRT' - | 'SHOULDER' - | 'TABARD' - | 'TRINKET' - //Weapons - | 'TWOHWEAPON' - //Misc - | 'WAIST' - | 'WRIST'; +type InventoryType = + //Armor + | 'BACK' + | 'CHEST' + | 'FEET' + | 'FINGER' + | 'HAND' + | 'HANDS' + | 'HEAD' + | 'LEGS' + | 'NECK' + | 'SHOULDER' + | 'THROWN' + | 'TRINKET' + | 'WAIST' + | 'WRIST' + //Weapons + | 'RANGED' + | 'TWOHWEAPON' + | 'WEAPON' + | 'WEAPONMAINHAND' + | 'WEAPONOFFHAND' + //Misc + | 'BAG' + | 'NON_EQUIP' + | 'SHIRT' + | 'TABARD'; + +interface InventoryTypeName { + name: string; + type: InventoryType; +} +interface InventoryTypeNameFromSearch { + name: Record; + type: InventoryType; } interface ItemQuality { - name: Record; - type: 'ARTIFACT' | 'COMMON' | 'EPIC' | 'HEIRLOOM' | 'LEGENDARY' | 'POOR' | 'RARE' | 'UNCOMMON'; + name: string; + type: ItemQualityType; +} + +interface ItemQualityFromSearch { + name: Record; + type: ItemQualityType; +} + +type ItemQualityType = 'ARTIFACT' | 'COMMON' | 'EPIC' | 'HEIRLOOM' | 'LEGENDARY' | 'POOR' | 'RARE' | 'UNCOMMON'; + +interface ItemSearchResponseItem extends KeyBase { + data: { + appearances?: Array<{ id: number }>; + id: number; + inventory_type: InventoryTypeNameFromSearch; + is_equippable: boolean; + is_stackable: boolean; + item_class: { id: number; name: Record }; + item_subclass: { id: number; name: Record }; + level: number; + max_count: number; + media: { id: number }; + name: Record; + purchase_price: number; + purchase_quantity: number; + quality: ItemQualityFromSearch; + required_level: number; + sell_price: number; + }; } interface Media extends KeyBase { @@ -191,7 +226,7 @@ interface PreviewItem { crafting_reagent?: string; description?: string; durability?: Durability; - inventory_type: InventoryType; + inventory_type: InventoryTypeName; is_subclass_hidden?: boolean; item: Media; item_class: NameIdKey; @@ -223,7 +258,7 @@ interface RecipeItem { type: string; }; durability: Durability; - inventory_type: InventoryType; + inventory_type: InventoryTypeName; item: Media; item_class: NameIdKey; item_subclass: NameIdKey; @@ -257,28 +292,23 @@ interface Stat { display: Display; is_negated?: boolean; type: { - name: StatType; + name: string; type: StatTypeCapitalized; }; value: number; } -type StatType = - | 'Agility' - | 'Critical Strike' - | 'Haste' - | 'Intellect' - | 'Mastery' - | 'Stamina' - | 'Strength' - | 'Versatility'; - type StatTypeCapitalized = | 'AGILITY' + | 'ARCANE_RESISTANCE' | 'CRIT_RATING' + | 'FIRE_RESISTANCE' + | 'FROST_RESISTANCE' | 'HASTE_RATING' | 'INTELLECT' | 'MASTERY' + | 'NATURE_RESISTANCE' + | 'SHADOW_RESISTANCE' | 'STAMINA' | 'STRENGTH' | 'VERSATILITY'; diff --git a/packages/wow/src/journal/journal.test.ts b/packages/wow/src/journal/journal.test.ts index cbb61099..b7a4e24c 100644 --- a/packages/wow/src/journal/journal.test.ts +++ b/packages/wow/src/journal/journal.test.ts @@ -1,5 +1,5 @@ +import { wowBasePath, wowMediaBasePath, wowSearchBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base, mediaBase, searchBase } from '../base'; import { journalEncounter, journalEncounterIndex, @@ -15,46 +15,46 @@ describe.concurrent('journalApi', () => { it('should return the journal encounter resource for a given journalEncounterId', ({ expect }) => { const journalEncounterId = 123; const resource = journalEncounter(journalEncounterId); - expect(resource.path).toBe(`${base}/journal-encounter/123`); + expect(resource.path).toBe(`${wowBasePath}/journal-encounter/123`); expect(resource.namespace).toBe('static'); }); it('should return the journal encounter index resource', ({ expect }) => { const resource = journalEncounterIndex(); - expect(resource.path).toBe(`${base}/journal-encounter/index`); + expect(resource.path).toBe(`${wowBasePath}/journal-encounter/index`); expect(resource.namespace).toBe('static'); }); it('should return the journal expansion resource for a given journalExpansionId', ({ expect }) => { const journalExpansionId = 456; const resource = journalExpansion(journalExpansionId); - expect(resource.path).toBe(`${base}/journal-expansion/456`); + expect(resource.path).toBe(`${wowBasePath}/journal-expansion/456`); expect(resource.namespace).toBe('static'); }); it('should return the journal expansion index resource', ({ expect }) => { const resource = journalExpansionIndex(); - expect(resource.path).toBe(`${base}/journal-expansion/index`); + expect(resource.path).toBe(`${wowBasePath}/journal-expansion/index`); expect(resource.namespace).toBe('static'); }); it('should return the journal instance resource for a given journalInstanceId', ({ expect }) => { const journalInstanceId = 789; const resource = journalInstance(journalInstanceId); - expect(resource.path).toBe(`${base}/journal-instance/789`); + expect(resource.path).toBe(`${wowBasePath}/journal-instance/789`); expect(resource.namespace).toBe('static'); }); it('should return the journal instance index resource', ({ expect }) => { const resource = journalInstanceIndex(); - expect(resource.path).toBe(`${base}/journal-instance/index`); + expect(resource.path).toBe(`${wowBasePath}/journal-instance/index`); expect(resource.namespace).toBe('static'); }); it('should return the journal instance media resource for a given journalInstanceId', ({ expect }) => { const journalInstanceId = 789; const resource = journalInstanceMedia(journalInstanceId); - expect(resource.path).toBe(`${mediaBase}/journal-instance/789`); + expect(resource.path).toBe(`${wowMediaBasePath}/journal-instance/789`); expect(resource.namespace).toBe('static'); }); @@ -65,7 +65,7 @@ describe.concurrent('journalApi', () => { locale: 'en_US', orderby: 'name', }); - expect(resource.path).toBe(`${searchBase}/journal-encounter`); + expect(resource.path).toBe(`${wowSearchBasePath}/journal-encounter`); expect(resource.namespace).toBe('static'); expect(resource.parameters).toEqual({ _page: 1, @@ -81,7 +81,7 @@ describe.concurrent('journalApi', () => { locale: 'en_US', orderby: ['name', 'id'], }); - expect(resource.path).toBe(`${searchBase}/journal-encounter`); + expect(resource.path).toBe(`${wowSearchBasePath}/journal-encounter`); expect(resource.namespace).toBe('static'); expect(resource.parameters).toEqual({ _page: 1, diff --git a/packages/wow/src/journal/journal.ts b/packages/wow/src/journal/journal.ts index 3442d57d..1c72e441 100644 --- a/packages/wow/src/journal/journal.ts +++ b/packages/wow/src/journal/journal.ts @@ -1,10 +1,10 @@ -import type { Resource, SearchResponse } from '@blizzard-api/core'; -import { base, mediaBase, searchBase } from '../base'; +import type { Resource } from '@blizzard-api/core'; +import { wowBasePath, wowMediaBasePath, wowSearchBasePath } from '@blizzard-api/core'; import type { JournalEncounterIndexResponse, JournalEncounterResponse, JournalEncounterSearchParameters, - JournalEncounterSearchResponseItem, + JournalEncounterSearchResponse, JournalExpansionIndexResponse, JournalExpansionResponse, JournalInstanceIndexResponse, @@ -20,7 +20,7 @@ import type { export function journalEncounter(journalEncounterId: number): Resource { return { namespace: 'static', - path: `${base}/journal-encounter/${journalEncounterId}`, + path: `${wowBasePath}/journal-encounter/${journalEncounterId}`, }; } /** @@ -30,20 +30,17 @@ export function journalEncounter(journalEncounterId: number): Resource { return { namespace: 'static', - path: `${base}/journal-encounter/index`, + path: `${wowBasePath}/journal-encounter/index`, }; } /** * Search for journal encounters. * @param options The search parameters. See {@link JournalEncounterSearchParameters}. - * @returns The search results. See {@link SearchResponse}. + * @returns The search results. See {@link JournalEncounterSearchResponse}. */ export function journalEncounterSearch( options: JournalEncounterSearchParameters, -): Resource< - SearchResponse, - Omit -> { +): Resource> { return { namespace: 'static', parameters: { @@ -51,7 +48,7 @@ export function journalEncounterSearch( [`instance.name.${options.locale}`]: options.instanceName, orderby: Array.isArray(options.orderby) ? options.orderby.join(',') : options.orderby, }, - path: `${searchBase}/journal-encounter`, + path: `${wowSearchBasePath}/journal-encounter`, }; } /** @@ -62,7 +59,7 @@ export function journalEncounterSearch( export function journalExpansion(journalExpansionId: number): Resource { return { namespace: 'static', - path: `${base}/journal-expansion/${journalExpansionId}`, + path: `${wowBasePath}/journal-expansion/${journalExpansionId}`, }; } /** @@ -72,7 +69,7 @@ export function journalExpansion(journalExpansionId: number): Resource { return { namespace: 'static', - path: `${base}/journal-expansion/index`, + path: `${wowBasePath}/journal-expansion/index`, }; } /** @@ -83,7 +80,7 @@ export function journalExpansionIndex(): Resource export function journalInstance(journalInstanceId: number): Resource { return { namespace: 'static', - path: `${base}/journal-instance/${journalInstanceId}`, + path: `${wowBasePath}/journal-instance/${journalInstanceId}`, }; } /** @@ -93,7 +90,7 @@ export function journalInstance(journalInstanceId: number): Resource { return { namespace: 'static', - path: `${base}/journal-instance/index`, + path: `${wowBasePath}/journal-instance/index`, }; } /** @@ -104,6 +101,6 @@ export function journalInstanceIndex(): Resource { export function journalInstanceMedia(journalInstanceId: number): Resource { return { namespace: 'static', - path: `${mediaBase}/journal-instance/${journalInstanceId}`, + path: `${wowMediaBasePath}/journal-instance/${journalInstanceId}`, }; } diff --git a/packages/wow/src/journal/types.ts b/packages/wow/src/journal/types.ts index 49c004b5..757bf50d 100644 --- a/packages/wow/src/journal/types.ts +++ b/packages/wow/src/journal/types.ts @@ -1,5 +1,13 @@ -import type { BaseSearchParameters, Locales } from '@blizzard-api/core'; -import type { Faction, KeyBase, NameId, NameIdKey, ResponseBase } from '../base'; +import type { + BaseSearchParameters, + Faction, + KeyBase, + Locales, + NameId, + NameIdKey, + ResponseBase, + SearchResponseWithoutResults, +} from '@blizzard-api/core'; /** * The response for a journal encounter index. @@ -15,13 +23,13 @@ export interface JournalEncounterIndexResponse extends ResponseBase { */ export interface JournalEncounterResponse extends NameId, ResponseBase { category: Category; - creatures: Array; - description: string; + creatures?: Array; + description?: string; faction?: Faction; - instance: NameIdKey; - items: Array; + instance: KeyBase & { id: number; name?: string }; + items?: Array; modes?: Array; - sections: Array; + sections?: Array; } /** @@ -38,17 +46,8 @@ export interface JournalEncounterSearchParameters extends BaseSearchParameters { * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} * @see {@link https://develop.battle.net/documentation/world-of-warcraft/guides/search} */ -export interface JournalEncounterSearchResponseItem extends KeyBase { - data: { - category: Category; - creatures: Array; - id: number; - instance: { id: number; name: Record }; - items: Array; - modes?: Array<{ name: Record; type: EncounterMode }>; - name: Record; - sections: Array; - }; +export interface JournalEncounterSearchResponse extends SearchResponseWithoutResults { + results: Array; } /** @@ -66,6 +65,7 @@ export interface JournalExpansionIndexResponse extends ResponseBase { export interface JournalExpansionResponse extends NameId, ResponseBase { dungeons: Array; raids: Array; + world_bosses?: Array; } /** @@ -89,17 +89,17 @@ export interface JournalInstanceMediaResponse extends ResponseBase { * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} */ export interface JournalInstanceResponse extends NameId, ResponseBase { - area: NameId; + area?: NameId; category: Category; - description: string; + description?: string; encounters: Array; - expansion: NameIdKey; - location: NameId; - map: NameId; + expansion?: NameIdKey; + location?: NameId; + map?: NameId; media: Media; - minimum_level: number; - modes: Array; - order_index: number; + minimum_level?: number; + modes?: Array; + order_index?: number; } interface Asset { @@ -108,7 +108,7 @@ interface Asset { } interface Category { - type: EncounterCategory; + type?: EncounterCategory; } interface Creature extends NameId { @@ -120,7 +120,7 @@ interface CreatureDisplay extends KeyBase { id: number; } -type EncounterCategory = 'DUNGEON' | 'RAID' | 'WORLD_BOSS'; +type EncounterCategory = 'DUNGEON' | 'EVENT' | 'RAID' | 'WORLD_BOSS'; type EncounterMode = 'HEROIC' | 'LFR' | 'MYTHIC' | 'NORMAL'; @@ -140,13 +140,79 @@ interface JournalEncounterSearchItem { item: { id: number; name: Record }; } +interface JournalEncounterSearchResponseItem extends KeyBase { + data: { + category: Category; + creatures: Array; + id: number; + instance: { id: number; name?: Record }; + items?: Array; + modes?: Array<{ name: Record; type: EncounterMode }>; + name: Record; + sections?: Array; + }; +} + interface JournalSection { - body_text?: string; + body_text?: null | string; creature_display?: CreatureDisplay; id: number; - sections?: Array; - spell?: NameIdKey; - title: string; + sections?: Array; + spell?: KeyBase & { id: number; name?: string }; + title?: string; +} + +interface JournalSubSection { + body_text?: null | string; + creature_display?: CreatureDisplay; + id: number; + sections?: Array; + spell?: KeyBase & { id: number; name?: string }; + title?: string; +} + +interface JournalSubSection2 { + body_text?: null | string; + creature_display?: CreatureDisplay; + id: number; + sections?: Array; + spell?: KeyBase & { id: number; name?: string }; + title?: string; +} + +interface JournalSubSection3 { + body_text?: null | string; + creature_display?: CreatureDisplay; + id: number; + sections?: Array; + spell?: KeyBase & { id: number; name?: string }; + title?: string; +} + +interface JournalSubSection4 { + body_text?: null | string; + creature_display?: CreatureDisplay; + id: number; + sections?: Array; + spell?: KeyBase & { id: number; name?: string }; + title?: string; +} + +interface JournalSubSection5 { + body_text?: null | string; + creature_display?: CreatureDisplay; + id: number; + sections?: Array; + spell?: KeyBase & { id: number; name?: string }; + title?: string; +} + +interface JournalSubSection6 { + body_text?: null | string; + creature_display?: CreatureDisplay; + id: number; + spell?: KeyBase & { id: number; name?: string }; + title?: string; } interface Media extends KeyBase { @@ -159,6 +225,7 @@ interface Mode { } interface ModeElement { + is_timewalking?: boolean; is_tracked: boolean; mode: Mode; players: number; diff --git a/packages/wow/src/media-search/media-search.test.ts b/packages/wow/src/media-search/media-search.test.ts index ce16daf3..b397f855 100644 --- a/packages/wow/src/media-search/media-search.test.ts +++ b/packages/wow/src/media-search/media-search.test.ts @@ -1,11 +1,11 @@ +import { wowSearchBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { searchBase } from '../base'; import { mediaSearch } from './media-search'; describe.concurrent('mediaSearchApi', () => { it('should return the media search resource', ({ expect }) => { const resource = mediaSearch({}); - expect(resource.path).toBe(`${searchBase}/media`); + expect(resource.path).toBe(`${wowSearchBasePath}/media`); expect(resource.namespace).toBe('static'); expect(resource.parameters).toEqual({}); }); @@ -16,7 +16,7 @@ describe.concurrent('mediaSearchApi', () => { orderby: 'name', tags: 'tag', }); - expect(resource.path).toBe(`${searchBase}/media`); + expect(resource.path).toBe(`${wowSearchBasePath}/media`); expect(resource.namespace).toBe('static'); expect(resource.parameters).toEqual({ _page: 1, @@ -31,7 +31,7 @@ describe.concurrent('mediaSearchApi', () => { orderby: ['name', 'id'], tags: 'tag', }); - expect(resource.path).toBe(`${searchBase}/media`); + expect(resource.path).toBe(`${wowSearchBasePath}/media`); expect(resource.namespace).toBe('static'); expect(resource.parameters).toEqual({ _page: 1, diff --git a/packages/wow/src/media-search/media-search.ts b/packages/wow/src/media-search/media-search.ts index 92e37680..356ac37e 100644 --- a/packages/wow/src/media-search/media-search.ts +++ b/packages/wow/src/media-search/media-search.ts @@ -1,15 +1,13 @@ -import type { Resource, SearchResponse } from '@blizzard-api/core'; -import { searchBase } from '../base'; -import type { MediaSearchParameters, MediaSearchResponseItem } from './types'; +import type { Resource } from '@blizzard-api/core'; +import { wowSearchBasePath } from '@blizzard-api/core'; +import type { MediaSearchParameters, MediaSearchResponse } from './types'; /** * Search for media. * @param options The search parameters. See {@link MediaSearchParameters}. - * @returns The search results. See {@link SearchResponse}. + * @returns The search results. See {@link MediaSearchResponse}. */ -export function mediaSearch( - options: MediaSearchParameters, -): Resource, MediaSearchParameters> { +export function mediaSearch(options: MediaSearchParameters): Resource { return { namespace: 'static', parameters: { @@ -17,6 +15,6 @@ export function mediaSearch( orderby: Array.isArray(options.orderby) ? options.orderby.join(',') : options.orderby, tags: options.tags, }, - path: `${searchBase}/media`, + path: `${wowSearchBasePath}/media`, }; } diff --git a/packages/wow/src/media-search/types.ts b/packages/wow/src/media-search/types.ts index 14c4f861..d95c5aed 100644 --- a/packages/wow/src/media-search/types.ts +++ b/packages/wow/src/media-search/types.ts @@ -1,5 +1,4 @@ -import type { BaseSearchParameters } from '@blizzard-api/core'; -import type { KeyBase } from '../base'; +import type { BaseSearchParameters, KeyBase, MediaAsset, SearchResponseWithoutResults } from '@blizzard-api/core'; /** * The search parameters for media. @@ -15,15 +14,13 @@ export interface MediaSearchParameters extends BaseSearchParameters { * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} * @see {@link https://develop.battle.net/documentation/world-of-warcraft/guides/search} */ -export interface MediaSearchResponseItem extends KeyBase { +export interface MediaSearchResponse extends SearchResponseWithoutResults { + results: Array; +} + +interface MediaSearchResponseItem extends KeyBase { data: { assets: Array; - id: number; + id?: number; }; } - -interface MediaAsset { - file_data_id: number; - key: string; - value: string; -} diff --git a/packages/wow/src/modified-crafting/modified-crafting.test.ts b/packages/wow/src/modified-crafting/modified-crafting.test.ts index 7599aa03..5b7b6ce0 100644 --- a/packages/wow/src/modified-crafting/modified-crafting.test.ts +++ b/packages/wow/src/modified-crafting/modified-crafting.test.ts @@ -1,5 +1,5 @@ +import { wowBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base } from '../base'; import { modifiedCraftingCategory, modifiedCraftingCategoryIndex, @@ -12,32 +12,32 @@ describe.concurrent('modifiedCraftingApi', () => { it('should return the correct path for modifiedCraftingCategory', ({ expect }) => { const modifiedCraftingCategoryId = 123; const resource = modifiedCraftingCategory(modifiedCraftingCategoryId); - expect(resource.path).toBe(`${base}/modified-crafting/category/123`); + expect(resource.path).toBe(`${wowBasePath}/modified-crafting/category/123`); expect(resource.namespace).toBe('static'); }); it('should return the correct path for modifiedCraftingCategoryIndex', ({ expect }) => { const resource = modifiedCraftingCategoryIndex(); - expect(resource.path).toBe(`${base}/modified-crafting/category/index`); + expect(resource.path).toBe(`${wowBasePath}/modified-crafting/category/index`); expect(resource.namespace).toBe('static'); }); it('should return the correct path for modifiedCraftingIndex', ({ expect }) => { const resource = modifiedCraftingIndex(); - expect(resource.path).toBe(`${base}/modified-crafting/index`); + expect(resource.path).toBe(`${wowBasePath}/modified-crafting/index`); expect(resource.namespace).toBe('static'); }); it('should return the correct path for modifiedCraftingReagentSlotType', ({ expect }) => { const modifiedCraftingReagentSlotTypeId = 456; const resource = modifiedCraftingReagentSlotType(modifiedCraftingReagentSlotTypeId); - expect(resource.path).toBe(`${base}/modified-crafting/reagent-slot-type/456`); + expect(resource.path).toBe(`${wowBasePath}/modified-crafting/reagent-slot-type/456`); expect(resource.namespace).toBe('static'); }); it('should return the correct path for modifiedCraftingReagentSlotTypeIndex', ({ expect }) => { const resource = modifiedCraftingReagentSlotTypeIndex(); - expect(resource.path).toBe(`${base}/modified-crafting/reagent-slot-type/index`); + expect(resource.path).toBe(`${wowBasePath}/modified-crafting/reagent-slot-type/index`); expect(resource.namespace).toBe('static'); }); }); diff --git a/packages/wow/src/modified-crafting/modified-crafting.ts b/packages/wow/src/modified-crafting/modified-crafting.ts index ea2818b4..a5fb971d 100644 --- a/packages/wow/src/modified-crafting/modified-crafting.ts +++ b/packages/wow/src/modified-crafting/modified-crafting.ts @@ -1,5 +1,5 @@ import type { Resource } from '@blizzard-api/core'; -import { base } from '../base'; +import { wowBasePath } from '@blizzard-api/core'; import type { ModifiedCraftingCategoryIndexResponse, ModifiedCraftingCategoryResponse, @@ -18,7 +18,7 @@ export function modifiedCraftingCategory( ): Resource { return { namespace: 'static', - path: `${base}/modified-crafting/category/${modifiedCraftingCategoryId}`, + path: `${wowBasePath}/modified-crafting/category/${modifiedCraftingCategoryId}`, }; } /** @@ -28,7 +28,7 @@ export function modifiedCraftingCategory( export function modifiedCraftingCategoryIndex(): Resource { return { namespace: 'static', - path: `${base}/modified-crafting/category/index`, + path: `${wowBasePath}/modified-crafting/category/index`, }; } /** @@ -38,7 +38,7 @@ export function modifiedCraftingCategoryIndex(): Resource { return { namespace: 'static', - path: `${base}/modified-crafting/index`, + path: `${wowBasePath}/modified-crafting/index`, }; } /** @@ -51,7 +51,7 @@ export function modifiedCraftingReagentSlotType( ): Resource { return { namespace: 'static', - path: `${base}/modified-crafting/reagent-slot-type/${modifiedCraftingReagentSlotTypeId}`, + path: `${wowBasePath}/modified-crafting/reagent-slot-type/${modifiedCraftingReagentSlotTypeId}`, }; } /** @@ -61,6 +61,6 @@ export function modifiedCraftingReagentSlotType( export function modifiedCraftingReagentSlotTypeIndex(): Resource { return { namespace: 'static', - path: `${base}/modified-crafting/reagent-slot-type/index`, + path: `${wowBasePath}/modified-crafting/reagent-slot-type/index`, }; } diff --git a/packages/wow/src/modified-crafting/types.ts b/packages/wow/src/modified-crafting/types.ts index 4729978b..1ede2755 100644 --- a/packages/wow/src/modified-crafting/types.ts +++ b/packages/wow/src/modified-crafting/types.ts @@ -1,26 +1,29 @@ -import type { KeyBase, NameId, NameIdKey, ResponseBase } from '../base'; +import type { Href, KeyBase, NameIdKey, ResponseBase } from '@blizzard-api/core'; /** * The response for a modified crafting category index. * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} */ export interface ModifiedCraftingCategoryIndexResponse extends ResponseBase { - categories: Array; + categories: Array; } /** * The response for a modified crafting category. * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} */ -export interface ModifiedCraftingCategoryResponse extends NameId, ResponseBase {} +export interface ModifiedCraftingCategoryResponse extends ResponseBase { + id: number; + name?: string; +} /** * The response for a modified crafting index. * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} */ export interface ModifiedCraftingIndexResponse extends ResponseBase { - categories: { href: string }; - slot_types: { href: string }; + categories: Href; + slot_types: Href; } /** diff --git a/packages/wow/src/mount/mount.test.ts b/packages/wow/src/mount/mount.test.ts index da5fcbdb..b31ae0a1 100644 --- a/packages/wow/src/mount/mount.test.ts +++ b/packages/wow/src/mount/mount.test.ts @@ -1,5 +1,5 @@ +import { wowBasePath, wowSearchBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base, searchBase } from '../base'; import { mount, mountIndex, mountSearch } from './mount'; describe.concurrent('mountApi', () => { @@ -7,14 +7,14 @@ describe.concurrent('mountApi', () => { const mountId = 123; const resource = mount(mountId); - expect(resource.path).toBe(`${base}/mount/123`); + expect(resource.path).toBe(`${wowBasePath}/mount/123`); expect(resource.namespace).toBe('static'); }); it('mountIndex should return a resource object with the correct path and namespace', ({ expect }) => { const resource = mountIndex(); - expect(resource.path).toBe(`${base}/mount/index`); + expect(resource.path).toBe(`${wowBasePath}/mount/index`); expect(resource.namespace).toBe('static'); }); @@ -26,7 +26,7 @@ describe.concurrent('mountApi', () => { orderby: 'name', }); - expect(resource.path).toBe(`${searchBase}/mount`); + expect(resource.path).toBe(`${wowSearchBasePath}/mount`); expect(resource.namespace).toBe('static'); expect(resource.parameters).toEqual({ _page: 1, @@ -43,7 +43,7 @@ describe.concurrent('mountApi', () => { orderby: ['name', 'id'], }); - expect(resource.path).toBe(`${searchBase}/mount`); + expect(resource.path).toBe(`${wowSearchBasePath}/mount`); expect(resource.namespace).toBe('static'); expect(resource.parameters).toEqual({ _page: 1, diff --git a/packages/wow/src/mount/mount.ts b/packages/wow/src/mount/mount.ts index d86ef8c6..0109f0e4 100644 --- a/packages/wow/src/mount/mount.ts +++ b/packages/wow/src/mount/mount.ts @@ -1,6 +1,6 @@ -import type { Resource, SearchResponse } from '@blizzard-api/core'; -import { base, searchBase } from '../base'; -import type { MountIndexResponse, MountResponse, MountSearchParameters, MountSearchResponseItem } from './types'; +import type { Resource } from '@blizzard-api/core'; +import { wowBasePath, wowSearchBasePath } from '@blizzard-api/core'; +import type { MountIndexResponse, MountResponse, MountSearchParameters, MountSearchResponse } from './types'; /** * Get a mount by ID. @@ -10,7 +10,7 @@ import type { MountIndexResponse, MountResponse, MountSearchParameters, MountSea export function mount(mountId: number): Resource { return { namespace: 'static', - path: `${base}/mount/${mountId}`, + path: `${wowBasePath}/mount/${mountId}`, }; } /** @@ -20,17 +20,17 @@ export function mount(mountId: number): Resource { export function mountIndex(): Resource { return { namespace: 'static', - path: `${base}/mount/index`, + path: `${wowBasePath}/mount/index`, }; } /** * Get a mount search. * @param options The search parameters. See {@link MountSearchParameters}. - * @returns The search results. See {@link SearchResponse}. + * @returns The search results. See {@link MountSearchResponse}. */ export function mountSearch( options: MountSearchParameters, -): Resource, Omit> { +): Resource> { return { namespace: 'static', parameters: { @@ -38,6 +38,6 @@ export function mountSearch( [`name.${options.locale}`]: options.name, orderby: Array.isArray(options.orderby) ? options.orderby.join(',') : options.orderby, }, - path: `${searchBase}/mount`, + path: `${wowSearchBasePath}/mount`, }; } diff --git a/packages/wow/src/mount/types.ts b/packages/wow/src/mount/types.ts index b6eab871..1d5e9b97 100644 --- a/packages/wow/src/mount/types.ts +++ b/packages/wow/src/mount/types.ts @@ -1,5 +1,13 @@ -import type { BaseSearchParameters, Locales } from '@blizzard-api/core'; -import type { Factions, KeyBase, NameIdKey, ResponseBase } from '../base'; +import type { + BaseSearchParameters, + Faction, + Factions, + KeyBase, + Locales, + NameIdKey, + ResponseBase, + SearchResponseWithoutResults, +} from '@blizzard-api/core'; /** * The response for a mount index. @@ -15,11 +23,13 @@ export interface MountIndexResponse extends ResponseBase { */ export interface MountResponse extends ResponseBase { creature_displays: Array; - description: string; + description: null | string; + faction?: Faction; id: number; name: string; - should_exclude_if_uncollected: boolean; - source: Source; + requirements?: { classes?: Array; faction?: Faction; races?: Array }; + should_exclude_if_uncollected?: boolean; + source?: Source; } /** @@ -37,20 +47,24 @@ export interface MountSearchParameters extends BaseSearchParameters { * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} * @see {@link https://develop.battle.net/documentation/world-of-warcraft/guides/search} */ -export interface MountSearchResponseItem extends KeyBase { +export interface MountSearchResponse extends SearchResponseWithoutResults { + results: Array; +} + +interface CreatureDisplay extends KeyBase { + id: number; +} + +interface MountSearchResponseItem extends KeyBase { data: { creature_displays: Array<{ id: number }>; - faction?: { name: Record; type: keyof typeof Factions }; + faction?: { name: Record; type: Factions }; id: number; name: Record; source: { name: Record; type: string }; }; } -interface CreatureDisplay extends KeyBase { - id: number; -} - interface Source { name: string; type: string; diff --git a/packages/wow/src/mythic-keystone-affix/mythic-keystone-affix.test.ts b/packages/wow/src/mythic-keystone-affix/mythic-keystone-affix.test.ts index ef360b6f..50efbc5f 100644 --- a/packages/wow/src/mythic-keystone-affix/mythic-keystone-affix.test.ts +++ b/packages/wow/src/mythic-keystone-affix/mythic-keystone-affix.test.ts @@ -1,5 +1,5 @@ +import { wowBasePath, wowMediaBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base, mediaBase } from '../base'; import { mythicKeystoneAffix, mythicKeystoneAffixIndex, mythicKeystoneAffixMedia } from './mythic-keystone-affix'; describe.concurrent('mythicKeystoneAffixApi', () => { @@ -7,14 +7,14 @@ describe.concurrent('mythicKeystoneAffixApi', () => { const mythicKeystoneAffixId = 123; const resource = mythicKeystoneAffix(mythicKeystoneAffixId); - expect(resource.path).toBe(`${base}/keystone-affix/${mythicKeystoneAffixId}`); + expect(resource.path).toBe(`${wowBasePath}/keystone-affix/${mythicKeystoneAffixId}`); expect(resource.namespace).toBe('static'); }); it('mythicKeystoneAffixIndex should return a resource object with the correct path and namespace', ({ expect }) => { const resource = mythicKeystoneAffixIndex(); - expect(resource.path).toBe(`${base}/keystone-affix/index`); + expect(resource.path).toBe(`${wowBasePath}/keystone-affix/index`); expect(resource.namespace).toBe('static'); }); @@ -22,7 +22,7 @@ describe.concurrent('mythicKeystoneAffixApi', () => { const mythicKeystoneAffixId = 123; const resource = mythicKeystoneAffixMedia(mythicKeystoneAffixId); - expect(resource.path).toBe(`${mediaBase}/keystone-affix/${mythicKeystoneAffixId}`); + expect(resource.path).toBe(`${wowMediaBasePath}/keystone-affix/${mythicKeystoneAffixId}`); expect(resource.namespace).toBe('static'); }); }); diff --git a/packages/wow/src/mythic-keystone-affix/mythic-keystone-affix.ts b/packages/wow/src/mythic-keystone-affix/mythic-keystone-affix.ts index 902ec3c9..dad11746 100644 --- a/packages/wow/src/mythic-keystone-affix/mythic-keystone-affix.ts +++ b/packages/wow/src/mythic-keystone-affix/mythic-keystone-affix.ts @@ -1,5 +1,5 @@ import type { Resource } from '@blizzard-api/core'; -import { base, mediaBase } from '../base'; +import { wowBasePath, wowMediaBasePath } from '@blizzard-api/core'; import type { MythicKeystoneAffixIndexResponse, MythicKeystoneAffixMediaResponse, @@ -14,7 +14,7 @@ import type { export function mythicKeystoneAffix(mythicKeystoneAffixId: number): Resource { return { namespace: 'static', - path: `${base}/keystone-affix/${mythicKeystoneAffixId}`, + path: `${wowBasePath}/keystone-affix/${mythicKeystoneAffixId}`, }; } /** @@ -24,7 +24,7 @@ export function mythicKeystoneAffix(mythicKeystoneAffixId: number): Resource { return { namespace: 'static', - path: `${base}/keystone-affix/index`, + path: `${wowBasePath}/keystone-affix/index`, }; } /** @@ -35,6 +35,6 @@ export function mythicKeystoneAffixIndex(): Resource { return { namespace: 'static', - path: `${mediaBase}/keystone-affix/${mythicKeystoneAffixId}`, + path: `${wowMediaBasePath}/keystone-affix/${mythicKeystoneAffixId}`, }; } diff --git a/packages/wow/src/mythic-keystone-affix/types.ts b/packages/wow/src/mythic-keystone-affix/types.ts index 2aaefb64..252f2692 100644 --- a/packages/wow/src/mythic-keystone-affix/types.ts +++ b/packages/wow/src/mythic-keystone-affix/types.ts @@ -1,11 +1,11 @@ -import type { KeyBase, MediaAsset, NameId, NameIdKey, ResponseBase } from '../base'; +import type { KeyBase, MediaAsset, ResponseBase } from '@blizzard-api/core'; /** * The response for a Mythic Keystone affix index. * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} */ export interface MythicKeystoneAffixIndexResponse extends ResponseBase { - affixes: Array; + affixes: Array; } /** @@ -13,7 +13,7 @@ export interface MythicKeystoneAffixIndexResponse extends ResponseBase { * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} */ export interface MythicKeystoneAffixMediaResponse extends ResponseBase { - assets: Array; + assets?: Array; id: number; } @@ -21,9 +21,11 @@ export interface MythicKeystoneAffixMediaResponse extends ResponseBase { * The response for a Mythic Keystone affix. * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} */ -export interface MythicKeystoneAffixResponse extends NameId, ResponseBase { - description: string; +export interface MythicKeystoneAffixResponse extends ResponseBase { + description: null | string; + id: number; media: Media; + name: null | string; } interface Media extends KeyBase { diff --git a/packages/wow/src/mythic-keystone-dungeon/mythic-keystone-dungeon.test.ts b/packages/wow/src/mythic-keystone-dungeon/mythic-keystone-dungeon.test.ts index 25d74496..3641ab20 100644 --- a/packages/wow/src/mythic-keystone-dungeon/mythic-keystone-dungeon.test.ts +++ b/packages/wow/src/mythic-keystone-dungeon/mythic-keystone-dungeon.test.ts @@ -1,5 +1,5 @@ +import { wowBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base } from '../base'; import { mythicKeystoneDungeon, mythicKeystoneDungeonIndex, @@ -15,21 +15,21 @@ describe.concurrent('mythicKeystoneDungeonApi', () => { const mythicKeystoneDungeonId = 123; const resource = mythicKeystoneDungeon(mythicKeystoneDungeonId); - expect(resource.path).toBe(`${base}/mythic-keystone/dungeon/${mythicKeystoneDungeonId}`); + expect(resource.path).toBe(`${wowBasePath}/mythic-keystone/dungeon/${mythicKeystoneDungeonId}`); expect(resource.namespace).toBe('dynamic'); }); it('mythicKeystoneDungeonIndex should return a resource object with the correct path and namespace', ({ expect }) => { const resource = mythicKeystoneDungeonIndex(); - expect(resource.path).toBe(`${base}/mythic-keystone/dungeon/index`); + expect(resource.path).toBe(`${wowBasePath}/mythic-keystone/dungeon/index`); expect(resource.namespace).toBe('dynamic'); }); it('mythicKeystoneIndex should return a resource object with the correct path and namespace', ({ expect }) => { const resource = mythicKeystoneIndex(); - expect(resource.path).toBe(`${base}/mythic-keystone/index`); + expect(resource.path).toBe(`${wowBasePath}/mythic-keystone/index`); expect(resource.namespace).toBe('dynamic'); }); @@ -37,14 +37,14 @@ describe.concurrent('mythicKeystoneDungeonApi', () => { const mythicKeystonePeriodId = 456; const resource = mythicKeystonePeriod(mythicKeystonePeriodId); - expect(resource.path).toBe(`${base}/mythic-keystone/period/${mythicKeystonePeriodId}`); + expect(resource.path).toBe(`${wowBasePath}/mythic-keystone/period/${mythicKeystonePeriodId}`); expect(resource.namespace).toBe('dynamic'); }); it('mythicKeystonePeriodIndex should return a resource object with the correct path and namespace', ({ expect }) => { const resource = mythicKeystonePeriodIndex(); - expect(resource.path).toBe(`${base}/mythic-keystone/period/index`); + expect(resource.path).toBe(`${wowBasePath}/mythic-keystone/period/index`); expect(resource.namespace).toBe('dynamic'); }); @@ -52,14 +52,14 @@ describe.concurrent('mythicKeystoneDungeonApi', () => { const mythicKeystoneSeasonId = 789; const resource = mythicKeystoneSeason(mythicKeystoneSeasonId); - expect(resource.path).toBe(`${base}/mythic-keystone/season/${mythicKeystoneSeasonId}`); + expect(resource.path).toBe(`${wowBasePath}/mythic-keystone/season/${mythicKeystoneSeasonId}`); expect(resource.namespace).toBe('dynamic'); }); it('mythicKeystoneSeasonIndex should return a resource object with the correct path and namespace', ({ expect }) => { const resource = mythicKeystoneSeasonIndex(); - expect(resource.path).toBe(`${base}/mythic-keystone/season/index`); + expect(resource.path).toBe(`${wowBasePath}/mythic-keystone/season/index`); expect(resource.namespace).toBe('dynamic'); }); }); diff --git a/packages/wow/src/mythic-keystone-dungeon/mythic-keystone-dungeon.ts b/packages/wow/src/mythic-keystone-dungeon/mythic-keystone-dungeon.ts index fcc205f9..1f68af07 100644 --- a/packages/wow/src/mythic-keystone-dungeon/mythic-keystone-dungeon.ts +++ b/packages/wow/src/mythic-keystone-dungeon/mythic-keystone-dungeon.ts @@ -1,5 +1,5 @@ import type { Resource } from '@blizzard-api/core'; -import { base } from '../base'; +import { wowBasePath } from '@blizzard-api/core'; import type { MythicKeystoneDungeonIndexResponse, MythicKeystoneDungeonResponse, @@ -18,7 +18,7 @@ import type { export function mythicKeystoneDungeon(mythicKeystoneDungeonId: number): Resource { return { namespace: 'dynamic', - path: `${base}/mythic-keystone/dungeon/${mythicKeystoneDungeonId}`, + path: `${wowBasePath}/mythic-keystone/dungeon/${mythicKeystoneDungeonId}`, }; } /** @@ -28,7 +28,7 @@ export function mythicKeystoneDungeon(mythicKeystoneDungeonId: number): Resource export function mythicKeystoneDungeonIndex(): Resource { return { namespace: 'dynamic', - path: `${base}/mythic-keystone/dungeon/index`, + path: `${wowBasePath}/mythic-keystone/dungeon/index`, }; } /** @@ -38,7 +38,7 @@ export function mythicKeystoneDungeonIndex(): Resource { return { namespace: 'dynamic', - path: `${base}/mythic-keystone/index`, + path: `${wowBasePath}/mythic-keystone/index`, }; } /** @@ -49,7 +49,7 @@ export function mythicKeystoneIndex(): Resource { export function mythicKeystonePeriod(mythicKeystonePeriodId: number): Resource { return { namespace: 'dynamic', - path: `${base}/mythic-keystone/period/${mythicKeystonePeriodId}`, + path: `${wowBasePath}/mythic-keystone/period/${mythicKeystonePeriodId}`, }; } /** @@ -59,7 +59,7 @@ export function mythicKeystonePeriod(mythicKeystonePeriodId: number): Resource { return { namespace: 'dynamic', - path: `${base}/mythic-keystone/period/index`, + path: `${wowBasePath}/mythic-keystone/period/index`, }; } /** @@ -70,7 +70,7 @@ export function mythicKeystonePeriodIndex(): Resource { return { namespace: 'dynamic', - path: `${base}/mythic-keystone/season/${mythicKeystoneSeasonId}`, + path: `${wowBasePath}/mythic-keystone/season/${mythicKeystoneSeasonId}`, }; } /** @@ -80,6 +80,6 @@ export function mythicKeystoneSeason(mythicKeystoneSeasonId: number): Resource { return { namespace: 'dynamic', - path: `${base}/mythic-keystone/season/index`, + path: `${wowBasePath}/mythic-keystone/season/index`, }; } diff --git a/packages/wow/src/mythic-keystone-dungeon/types.ts b/packages/wow/src/mythic-keystone-dungeon/types.ts index 60584d77..30a99687 100644 --- a/packages/wow/src/mythic-keystone-dungeon/types.ts +++ b/packages/wow/src/mythic-keystone-dungeon/types.ts @@ -1,4 +1,4 @@ -import type { KeyBase, NameId, NameIdKey, ResponseBase } from '../base'; +import type { Href, KeyBase, NameId, NameIdKey, ResponseBase } from '@blizzard-api/core'; /** * The response for a Mythic Keystone dungeon index. @@ -25,8 +25,8 @@ export interface MythicKeystoneDungeonResponse extends NameId, ResponseBase { * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} */ export interface MythicKeystoneIndexResponse extends ResponseBase { - dungeons: { href: string }; - seasons: { href: string }; + dungeons: Href; + seasons: Href; } /** diff --git a/packages/wow/src/mythic-keystone-leaderboard/mythic-keystone-leaderboard.test.ts b/packages/wow/src/mythic-keystone-leaderboard/mythic-keystone-leaderboard.test.ts index a23c854d..3cc3e75e 100644 --- a/packages/wow/src/mythic-keystone-leaderboard/mythic-keystone-leaderboard.test.ts +++ b/packages/wow/src/mythic-keystone-leaderboard/mythic-keystone-leaderboard.test.ts @@ -1,5 +1,5 @@ +import { wowBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base } from '../base'; import { mythicKeystoneLeaderboard, mythicKeystoneLeaderboardIndex } from './mythic-keystone-leaderboard'; describe.concurrent('mythicKeystoneLeaderboardApi', () => { @@ -10,7 +10,7 @@ describe.concurrent('mythicKeystoneLeaderboardApi', () => { const resource = mythicKeystoneLeaderboard(connectedRealmId, dungeonId, period); expect(resource.path).toBe( - `${base}/connected-realm/${connectedRealmId}/mythic-leaderboard/${dungeonId}/period/${period}`, + `${wowBasePath}/connected-realm/${connectedRealmId}/mythic-leaderboard/${dungeonId}/period/${period}`, ); expect(resource.namespace).toBe('dynamic'); }); @@ -21,7 +21,7 @@ describe.concurrent('mythicKeystoneLeaderboardApi', () => { const connectedRealmId = 456; const resource = mythicKeystoneLeaderboardIndex(connectedRealmId); - expect(resource.path).toBe(`${base}/connected-realm/${connectedRealmId}/mythic-leaderboard/index`); + expect(resource.path).toBe(`${wowBasePath}/connected-realm/${connectedRealmId}/mythic-leaderboard/index`); expect(resource.namespace).toBe('dynamic'); }); }); diff --git a/packages/wow/src/mythic-keystone-leaderboard/mythic-keystone-leaderboard.ts b/packages/wow/src/mythic-keystone-leaderboard/mythic-keystone-leaderboard.ts index 06ff8937..67ae47ab 100644 --- a/packages/wow/src/mythic-keystone-leaderboard/mythic-keystone-leaderboard.ts +++ b/packages/wow/src/mythic-keystone-leaderboard/mythic-keystone-leaderboard.ts @@ -1,5 +1,5 @@ import type { Resource } from '@blizzard-api/core'; -import { base } from '../base'; +import { wowBasePath } from '@blizzard-api/core'; import type { MythicKeystoneLeaderboardIndexResponse, MythicKeystoneLeaderboardResponse } from './types'; /** @@ -16,7 +16,7 @@ export function mythicKeystoneLeaderboard( ): Resource { return { namespace: 'dynamic', - path: `${base}/connected-realm/${connectedRealmId}/mythic-leaderboard/${dungeonId}/period/${period}`, + path: `${wowBasePath}/connected-realm/${connectedRealmId}/mythic-leaderboard/${dungeonId}/period/${period}`, }; } /** @@ -29,6 +29,6 @@ export function mythicKeystoneLeaderboardIndex( ): Resource { return { namespace: 'dynamic', - path: `${base}/connected-realm/${connectedRealmId}/mythic-leaderboard/index`, + path: `${wowBasePath}/connected-realm/${connectedRealmId}/mythic-leaderboard/index`, }; } diff --git a/packages/wow/src/mythic-keystone-leaderboard/types.ts b/packages/wow/src/mythic-keystone-leaderboard/types.ts index 1f56636f..48e7fe32 100644 --- a/packages/wow/src/mythic-keystone-leaderboard/types.ts +++ b/packages/wow/src/mythic-keystone-leaderboard/types.ts @@ -1,4 +1,4 @@ -import type { Color, Factions, KeyBase, NameId, NameIdKey, ResponseBase } from '../base'; +import type { Factions, Href, KeyBase, NameId, NameIdKey, ResponseBase } from '@blizzard-api/core'; /** * The response for a Mythic Keystone leaderboard index. @@ -13,7 +13,7 @@ export interface MythicKeystoneLeaderboardIndexResponse extends ResponseBase { * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} */ export interface MythicKeystoneLeaderboardResponse extends ResponseBase { - connected_realm: { href: string }; + connected_realm: Href; keystone_affixes: Array; leading_groups: Array; map: NameId; @@ -34,21 +34,15 @@ interface LeadingGroup { duration: number; keystone_level: number; members: Array; - mythic_rating: MythicRating; ranking: number; } interface Member { - faction: { type: keyof typeof Factions }; + faction: { type: Factions }; profile: Profile; specialization: Specialization; } -interface MythicRating { - color: Color; - rating: number; -} - interface Profile extends NameId { realm: Realm; } diff --git a/packages/wow/src/mythic-raid-leaderboard/mythic-raid-leaderboard.test.ts b/packages/wow/src/mythic-raid-leaderboard/mythic-raid-leaderboard.test.ts index a8bd6baa..b558f349 100644 --- a/packages/wow/src/mythic-raid-leaderboard/mythic-raid-leaderboard.test.ts +++ b/packages/wow/src/mythic-raid-leaderboard/mythic-raid-leaderboard.test.ts @@ -1,5 +1,5 @@ +import { wowBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base } from '../base'; import { mythicRaidLeaderboard } from './mythic-raid-leaderboard'; describe.concurrent('mythicRaidLeaderboardApi', () => { @@ -8,7 +8,7 @@ describe.concurrent('mythicRaidLeaderboardApi', () => { const faction = 'alliance'; const resource = mythicRaidLeaderboard(raid, faction); - expect(resource.path).toBe(`${base}/leaderboard/hall-of-fame/${raid}/${faction}`); + expect(resource.path).toBe(`${wowBasePath}/leaderboard/hall-of-fame/${raid}/${faction}`); expect(resource.namespace).toBe('dynamic'); }); @@ -19,7 +19,7 @@ describe.concurrent('mythicRaidLeaderboardApi', () => { const faction = 'horde'; const resource = mythicRaidLeaderboard(raid, faction); - expect(resource.path).toBe(`${base}/leaderboard/hall-of-fame/${raid}/${faction}`); + expect(resource.path).toBe(`${wowBasePath}/leaderboard/hall-of-fame/${raid}/${faction}`); expect(resource.namespace).toBe('dynamic'); }); }); diff --git a/packages/wow/src/mythic-raid-leaderboard/mythic-raid-leaderboard.ts b/packages/wow/src/mythic-raid-leaderboard/mythic-raid-leaderboard.ts index c1c66407..3025dfcd 100644 --- a/packages/wow/src/mythic-raid-leaderboard/mythic-raid-leaderboard.ts +++ b/packages/wow/src/mythic-raid-leaderboard/mythic-raid-leaderboard.ts @@ -1,6 +1,5 @@ -import type { Resource } from '@blizzard-api/core'; -import type { Factions } from '../base'; -import { base } from '../base'; +import type { Factions, Resource } from '@blizzard-api/core'; +import { wowBasePath } from '@blizzard-api/core'; import type { MythicRaidLeaderboardResponse } from './types'; /** @@ -11,10 +10,10 @@ import type { MythicRaidLeaderboardResponse } from './types'; */ export function mythicRaidLeaderboard( raid: string, - faction: Lowercase, + faction: Lowercase, ): Resource { return { namespace: 'dynamic', - path: `${base}/leaderboard/hall-of-fame/${raid}/${faction}`, + path: `${wowBasePath}/leaderboard/hall-of-fame/${raid}/${faction}`, }; } diff --git a/packages/wow/src/mythic-raid-leaderboard/types.ts b/packages/wow/src/mythic-raid-leaderboard/types.ts index 29632289..799eb2e0 100644 --- a/packages/wow/src/mythic-raid-leaderboard/types.ts +++ b/packages/wow/src/mythic-raid-leaderboard/types.ts @@ -1,5 +1,4 @@ -import type { Origins } from '@blizzard-api/core'; -import type { Factions, KeyBase, NameId, ResponseBase } from '../base'; +import type { Factions, KeyBase, NameId, Origins, ResponseBase } from '@blizzard-api/core'; /** * The response for a Mythic Raid leaderboard. @@ -13,7 +12,7 @@ export interface MythicRaidLeaderboardResponse extends ResponseBase { } interface Entry { - faction: { type: keyof typeof Factions }; + faction: { type: Factions }; guild: Guild; rank: number; region: Origins; diff --git a/packages/wow/src/pet/pet.test.ts b/packages/wow/src/pet/pet.test.ts index b3e8a8b7..78bac02e 100644 --- a/packages/wow/src/pet/pet.test.ts +++ b/packages/wow/src/pet/pet.test.ts @@ -1,5 +1,5 @@ +import { wowBasePath, wowMediaBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base, mediaBase } from '../base'; import { pet, petAbility, petAbilityIndex, petAbilityMedia, petIndex, petMedia } from './pet'; describe.concurrent('petApi', () => { @@ -7,14 +7,14 @@ describe.concurrent('petApi', () => { const petId = 123; const resource = pet(petId); - expect(resource.path).toBe(`${base}/pet/${petId}`); + expect(resource.path).toBe(`${wowBasePath}/pet/${petId}`); expect(resource.namespace).toBe('static'); }); it('petIndex should return a resource object with the correct path and namespace', ({ expect }) => { const resource = petIndex(); - expect(resource.path).toBe(`${base}/pet/index`); + expect(resource.path).toBe(`${wowBasePath}/pet/index`); expect(resource.namespace).toBe('static'); }); @@ -22,7 +22,7 @@ describe.concurrent('petApi', () => { const petId = 123; const resource = petMedia(petId); - expect(resource.path).toBe(`${mediaBase}/pet/${petId}`); + expect(resource.path).toBe(`${wowMediaBasePath}/pet/${petId}`); expect(resource.namespace).toBe('static'); }); @@ -30,14 +30,14 @@ describe.concurrent('petApi', () => { const petAbilityId = 123; const resource = petAbility(petAbilityId); - expect(resource.path).toBe(`${base}/pet-ability/${petAbilityId}`); + expect(resource.path).toBe(`${wowBasePath}/pet-ability/${petAbilityId}`); expect(resource.namespace).toBe('static'); }); it('petAbilityIndex should return a resource object with the correct path and namespace', ({ expect }) => { const resource = petAbilityIndex(); - expect(resource.path).toBe(`${base}/pet-ability/index`); + expect(resource.path).toBe(`${wowBasePath}/pet-ability/index`); expect(resource.namespace).toBe('static'); }); @@ -45,7 +45,7 @@ describe.concurrent('petApi', () => { const petAbilityId = 123; const resource = petAbilityMedia(petAbilityId); - expect(resource.path).toBe(`${mediaBase}/pet-ability/${petAbilityId}`); + expect(resource.path).toBe(`${wowMediaBasePath}/pet-ability/${petAbilityId}`); expect(resource.namespace).toBe('static'); }); }); diff --git a/packages/wow/src/pet/pet.ts b/packages/wow/src/pet/pet.ts index f8430f47..a6fad05a 100644 --- a/packages/wow/src/pet/pet.ts +++ b/packages/wow/src/pet/pet.ts @@ -1,5 +1,5 @@ import type { Resource } from '@blizzard-api/core'; -import { base, mediaBase } from '../base'; +import { wowBasePath, wowMediaBasePath } from '@blizzard-api/core'; import type { PetAbilityIndexResponse, PetAbilityMediaResponse, @@ -17,7 +17,7 @@ import type { export function pet(petId: number): Resource { return { namespace: 'static', - path: `${base}/pet/${petId}`, + path: `${wowBasePath}/pet/${petId}`, }; } /** @@ -28,7 +28,7 @@ export function pet(petId: number): Resource { export function petAbility(petAbilityId: number): Resource { return { namespace: 'static', - path: `${base}/pet-ability/${petAbilityId}`, + path: `${wowBasePath}/pet-ability/${petAbilityId}`, }; } /** @@ -38,7 +38,7 @@ export function petAbility(petAbilityId: number): Resource { export function petAbilityIndex(): Resource { return { namespace: 'static', - path: `${base}/pet-ability/index`, + path: `${wowBasePath}/pet-ability/index`, }; } /** @@ -49,7 +49,7 @@ export function petAbilityIndex(): Resource { export function petAbilityMedia(petAbilityId: number): Resource { return { namespace: 'static', - path: `${mediaBase}/pet-ability/${petAbilityId}`, + path: `${wowMediaBasePath}/pet-ability/${petAbilityId}`, }; } /** @@ -59,7 +59,7 @@ export function petAbilityMedia(petAbilityId: number): Resource { return { namespace: 'static', - path: `${base}/pet/index`, + path: `${wowBasePath}/pet/index`, }; } /** @@ -70,6 +70,6 @@ export function petIndex(): Resource { export function petMedia(petId: number): Resource { return { namespace: 'static', - path: `${mediaBase}/pet/${petId}`, + path: `${wowMediaBasePath}/pet/${petId}`, }; } diff --git a/packages/wow/src/pet/types.ts b/packages/wow/src/pet/types.ts index d290abbf..e568614a 100644 --- a/packages/wow/src/pet/types.ts +++ b/packages/wow/src/pet/types.ts @@ -1,4 +1,4 @@ -import type { KeyBase, MediaAsset, NameId, NameIdKey, ResponseBase } from '../base'; +import type { KeyBase, MediaAsset, NameId, NameIdKey, ResponseBase } from '@blizzard-api/core'; /** * The response for a pet ability index. @@ -23,6 +23,7 @@ export interface PetAbilityMediaResponse extends ResponseBase { */ export interface PetAbilityResponse extends NameId, ResponseBase { battle_pet_type: BattlePetType; + cooldown?: number; media: Media; rounds: number; } @@ -49,10 +50,10 @@ export interface PetMediaResponse extends ResponseBase { * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} */ export interface PetResponse extends NameId, ResponseBase { - abilities: Array; + abilities?: Array; battle_pet_type: BattlePetType; creature: NameIdKey; - description: string; + description: null | string; icon: string; is_alliance_only: boolean; is_battlepet: boolean; @@ -61,8 +62,8 @@ export interface PetResponse extends NameId, ResponseBase { is_random_creature_display: boolean; is_tradable: boolean; media: Media; - should_exclude_if_uncollected: boolean; - source: Source; + should_exclude_if_uncollected?: boolean; + source?: Source; } interface Ability { diff --git a/packages/wow/src/playable-class/playable-class.test.ts b/packages/wow/src/playable-class/playable-class.test.ts index 9751ed00..5889f57b 100644 --- a/packages/wow/src/playable-class/playable-class.test.ts +++ b/packages/wow/src/playable-class/playable-class.test.ts @@ -1,5 +1,5 @@ +import { wowBasePath, wowMediaBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base, mediaBase } from '../base'; import { playableClass, playableClassIndex, playableClassMedia, pvpTalentSlots } from './playable-class'; describe.concurrent('playableClassApi', () => { @@ -7,14 +7,14 @@ describe.concurrent('playableClassApi', () => { const playableClassId = 123; const resource = playableClass(playableClassId); - expect(resource.path).toBe(`${base}/playable-class/${playableClassId}`); + expect(resource.path).toBe(`${wowBasePath}/playable-class/${playableClassId}`); expect(resource.namespace).toBe('static'); }); it('playableClassIndex should return a resource object with the correct path and namespace', ({ expect }) => { const resource = playableClassIndex(); - expect(resource.path).toBe(`${base}/playable-class/index`); + expect(resource.path).toBe(`${wowBasePath}/playable-class/index`); expect(resource.namespace).toBe('static'); }); @@ -22,7 +22,7 @@ describe.concurrent('playableClassApi', () => { const playableClassId = 123; const resource = playableClassMedia(playableClassId); - expect(resource.path).toBe(`${mediaBase}/playable-class/${playableClassId}`); + expect(resource.path).toBe(`${wowMediaBasePath}/playable-class/${playableClassId}`); expect(resource.namespace).toBe('static'); }); @@ -30,7 +30,7 @@ describe.concurrent('playableClassApi', () => { const playableClassId = 123; const resource = pvpTalentSlots(playableClassId); - expect(resource.path).toBe(`${base}/playable-class/${playableClassId}/pvp-talent-slots`); + expect(resource.path).toBe(`${wowBasePath}/playable-class/${playableClassId}/pvp-talent-slots`); expect(resource.namespace).toBe('static'); }); }); diff --git a/packages/wow/src/playable-class/playable-class.ts b/packages/wow/src/playable-class/playable-class.ts index 3189d9ef..dabd7da3 100644 --- a/packages/wow/src/playable-class/playable-class.ts +++ b/packages/wow/src/playable-class/playable-class.ts @@ -1,5 +1,5 @@ import type { Resource } from '@blizzard-api/core'; -import { base, mediaBase } from '../base'; +import { wowBasePath, wowMediaBasePath } from '@blizzard-api/core'; import type { PlayableClassIndexResponse, PlayableClassMediaResponse, @@ -15,7 +15,7 @@ import type { export function playableClass(playableClassId: number): Resource { return { namespace: 'static', - path: `${base}/playable-class/${playableClassId}`, + path: `${wowBasePath}/playable-class/${playableClassId}`, }; } /** @@ -25,7 +25,7 @@ export function playableClass(playableClassId: number): Resource { return { namespace: 'static', - path: `${base}/playable-class/index`, + path: `${wowBasePath}/playable-class/index`, }; } /** @@ -36,7 +36,7 @@ export function playableClassIndex(): Resource { export function playableClassMedia(playableClassId: number): Resource { return { namespace: 'static', - path: `${mediaBase}/playable-class/${playableClassId}`, + path: `${wowMediaBasePath}/playable-class/${playableClassId}`, }; } /** @@ -47,6 +47,6 @@ export function playableClassMedia(playableClassId: number): Resource { return { namespace: 'static', - path: `${base}/playable-class/${playableClassId}/pvp-talent-slots`, + path: `${wowBasePath}/playable-class/${playableClassId}/pvp-talent-slots`, }; } diff --git a/packages/wow/src/playable-class/types.ts b/packages/wow/src/playable-class/types.ts index 6b9092d6..dafd8bf2 100644 --- a/packages/wow/src/playable-class/types.ts +++ b/packages/wow/src/playable-class/types.ts @@ -1,4 +1,4 @@ -import type { GenderName, KeyBase, MediaAsset, NameId, NameIdKey, ResponseBase } from '../base'; +import type { GenderName, Href, KeyBase, MediaAsset, NameId, NameIdKey, ResponseBase } from '@blizzard-api/core'; /** * The response for a playable class index. @@ -26,7 +26,7 @@ export interface PlayableClassResponse extends NameId, ResponseBase { media: Media; playable_races: Array; power_type: NameIdKey; - pvp_talent_slots: { href: string }; + pvp_talent_slots: Href; specializations: Array; } diff --git a/packages/wow/src/playable-race/playable-race.test.ts b/packages/wow/src/playable-race/playable-race.test.ts index 1f811d57..a2814615 100644 --- a/packages/wow/src/playable-race/playable-race.test.ts +++ b/packages/wow/src/playable-race/playable-race.test.ts @@ -1,5 +1,5 @@ +import { wowBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base } from '../base'; import { playableRace, playableRaceIndex } from './playable-race'; describe.concurrent('playableRaceApi', () => { @@ -7,14 +7,14 @@ describe.concurrent('playableRaceApi', () => { const playableRaceId = 456; const resource = playableRace(playableRaceId); - expect(resource.path).toBe(`${base}/playable-race/${playableRaceId}`); + expect(resource.path).toBe(`${wowBasePath}/playable-race/${playableRaceId}`); expect(resource.namespace).toBe('static'); }); it('playableRaceIndex should return a resource object with the correct path and namespace', ({ expect }) => { const resource = playableRaceIndex(); - expect(resource.path).toBe(`${base}/playable-race/index`); + expect(resource.path).toBe(`${wowBasePath}/playable-race/index`); expect(resource.namespace).toBe('static'); }); }); diff --git a/packages/wow/src/playable-race/playable-race.ts b/packages/wow/src/playable-race/playable-race.ts index b36f2725..ad2d5267 100644 --- a/packages/wow/src/playable-race/playable-race.ts +++ b/packages/wow/src/playable-race/playable-race.ts @@ -1,5 +1,5 @@ import type { Resource } from '@blizzard-api/core'; -import { base } from '../base'; +import { wowBasePath } from '@blizzard-api/core'; import type { PlayableRaceIndexResponse, PlayableRaceResponse } from './types'; /** @@ -10,7 +10,7 @@ import type { PlayableRaceIndexResponse, PlayableRaceResponse } from './types'; export function playableRace(playableRaceId: number): Resource { return { namespace: 'static', - path: `${base}/playable-race/${playableRaceId}`, + path: `${wowBasePath}/playable-race/${playableRaceId}`, }; } /** @@ -20,6 +20,6 @@ export function playableRace(playableRaceId: number): Resource { return { namespace: 'static', - path: `${base}/playable-race/index`, + path: `${wowBasePath}/playable-race/index`, }; } diff --git a/packages/wow/src/playable-race/types.ts b/packages/wow/src/playable-race/types.ts index 50c7634c..0d7bd8ca 100644 --- a/packages/wow/src/playable-race/types.ts +++ b/packages/wow/src/playable-race/types.ts @@ -1,4 +1,4 @@ -import type { Faction, GenderName, NameId, NameIdKey, ResponseBase } from '../base'; +import type { Faction, GenderName, NameId, NameIdKey, ResponseBase } from '@blizzard-api/core'; /** * The playable race index response. @@ -18,4 +18,5 @@ export interface PlayableRaceResponse extends NameId, ResponseBase { is_allied_race: boolean; is_selectable: boolean; playable_classes: Array; + racial_spells: Array; } diff --git a/packages/wow/src/playable-specialization/playable-specialization.test.ts b/packages/wow/src/playable-specialization/playable-specialization.test.ts index e62635e1..2bcbf236 100644 --- a/packages/wow/src/playable-specialization/playable-specialization.test.ts +++ b/packages/wow/src/playable-specialization/playable-specialization.test.ts @@ -1,5 +1,5 @@ +import { wowBasePath, wowMediaBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base, mediaBase } from '../base'; import { playableSpecialization, playableSpecializationIndex, @@ -11,7 +11,7 @@ describe.concurrent('playableSpecializationApi', () => { const specializationId = 123; const resource = playableSpecialization(specializationId); - expect(resource.path).toBe(`${base}/playable-specialization/${specializationId}`); + expect(resource.path).toBe(`${wowBasePath}/playable-specialization/${specializationId}`); expect(resource.namespace).toBe('static'); }); @@ -20,7 +20,7 @@ describe.concurrent('playableSpecializationApi', () => { }) => { const resource = playableSpecializationIndex(); - expect(resource.path).toBe(`${base}/playable-specialization/index`); + expect(resource.path).toBe(`${wowBasePath}/playable-specialization/index`); expect(resource.namespace).toBe('static'); }); @@ -30,7 +30,7 @@ describe.concurrent('playableSpecializationApi', () => { const specializationId = 123; const resource = playableSpecializationMedia(specializationId); - expect(resource.path).toBe(`${mediaBase}/playable-specialization/${specializationId}`); + expect(resource.path).toBe(`${wowMediaBasePath}/playable-specialization/${specializationId}`); expect(resource.namespace).toBe('static'); }); }); diff --git a/packages/wow/src/playable-specialization/playable-specialization.ts b/packages/wow/src/playable-specialization/playable-specialization.ts index 37224115..c978fc7a 100644 --- a/packages/wow/src/playable-specialization/playable-specialization.ts +++ b/packages/wow/src/playable-specialization/playable-specialization.ts @@ -1,5 +1,5 @@ import type { Resource } from '@blizzard-api/core'; -import { base, mediaBase } from '../base'; +import { wowBasePath, wowMediaBasePath } from '@blizzard-api/core'; import type { PlayableSpecializationIndexResponse, PlayableSpecializationMediaResponse, @@ -14,7 +14,7 @@ import type { export function playableSpecialization(specializationId: number): Resource { return { namespace: 'static', - path: `${base}/playable-specialization/${specializationId}`, + path: `${wowBasePath}/playable-specialization/${specializationId}`, }; } /** @@ -24,7 +24,7 @@ export function playableSpecialization(specializationId: number): Resource { return { namespace: 'static', - path: `${base}/playable-specialization/index`, + path: `${wowBasePath}/playable-specialization/index`, }; } /** @@ -35,6 +35,6 @@ export function playableSpecializationIndex(): Resource { return { namespace: 'static', - path: `${mediaBase}/playable-specialization/${specializationId}`, + path: `${wowMediaBasePath}/playable-specialization/${specializationId}`, }; } diff --git a/packages/wow/src/playable-specialization/types.ts b/packages/wow/src/playable-specialization/types.ts index 68aa3dc9..0731ba3e 100644 --- a/packages/wow/src/playable-specialization/types.ts +++ b/packages/wow/src/playable-specialization/types.ts @@ -1,4 +1,4 @@ -import type { GenderName, KeyBase, MediaAsset, NameId, NameIdKey, ResponseBase } from '../base'; +import type { GenderName, KeyBase, MediaAsset, NameId, NameIdKey, ResponseBase } from '@blizzard-api/core'; /** * The response for a playable specialization index. @@ -24,6 +24,7 @@ export interface PlayableSpecializationMediaResponse extends ResponseBase { */ export interface PlayableSpecializationResponse extends NameId, ResponseBase { gender_description: GenderName; + hero_talent_trees: Array; media: Media; playable_class: NameIdKey; power_type: NameIdKey; @@ -55,6 +56,6 @@ interface SpellTooltip { cast_time: string; cooldown?: string; description: string; - power_cost?: string; + power_cost?: null | string; range?: string; } diff --git a/packages/wow/src/power-type/power-type.test.ts b/packages/wow/src/power-type/power-type.test.ts index 1d78bae4..833cc3ef 100644 --- a/packages/wow/src/power-type/power-type.test.ts +++ b/packages/wow/src/power-type/power-type.test.ts @@ -1,5 +1,5 @@ +import { wowBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base } from '../base'; import { powerType, powerTypeIndex } from './power-type'; describe.concurrent('powerTypeApi', () => { @@ -7,14 +7,14 @@ describe.concurrent('powerTypeApi', () => { const powerTypeId = 123; const resource = powerType(powerTypeId); - expect(resource.path).toBe(`${base}/power-type/${powerTypeId}`); + expect(resource.path).toBe(`${wowBasePath}/power-type/${powerTypeId}`); expect(resource.namespace).toBe('static'); }); it('powerTypeIndex should return a resource object with the correct path and namespace', ({ expect }) => { const resource = powerTypeIndex(); - expect(resource.path).toBe(`${base}/power-type/index`); + expect(resource.path).toBe(`${wowBasePath}/power-type/index`); expect(resource.namespace).toBe('static'); }); }); diff --git a/packages/wow/src/power-type/power-type.ts b/packages/wow/src/power-type/power-type.ts index a6912146..c9bfce89 100644 --- a/packages/wow/src/power-type/power-type.ts +++ b/packages/wow/src/power-type/power-type.ts @@ -1,5 +1,5 @@ import type { Resource } from '@blizzard-api/core'; -import { base } from '../base'; +import { wowBasePath } from '@blizzard-api/core'; import type { PowerTypeIndexResponse, PowerTypeResponse } from './types'; /** @@ -10,7 +10,7 @@ import type { PowerTypeIndexResponse, PowerTypeResponse } from './types'; export function powerType(powerTypeId: number): Resource { return { namespace: 'static', - path: `${base}/power-type/${powerTypeId}`, + path: `${wowBasePath}/power-type/${powerTypeId}`, }; } /** @@ -20,6 +20,6 @@ export function powerType(powerTypeId: number): Resource { export function powerTypeIndex(): Resource { return { namespace: 'static', - path: `${base}/power-type/index`, + path: `${wowBasePath}/power-type/index`, }; } diff --git a/packages/wow/src/power-type/types.ts b/packages/wow/src/power-type/types.ts index baae4a9e..ea0197ed 100644 --- a/packages/wow/src/power-type/types.ts +++ b/packages/wow/src/power-type/types.ts @@ -1,4 +1,4 @@ -import type { NameId, NameIdKey, ResponseBase } from '../base'; +import type { NameId, NameIdKey, ResponseBase } from '@blizzard-api/core'; /** * The response for a power type index. diff --git a/packages/wow/src/profession/profession.test.ts b/packages/wow/src/profession/profession.test.ts index 7f363123..f1625295 100644 --- a/packages/wow/src/profession/profession.test.ts +++ b/packages/wow/src/profession/profession.test.ts @@ -1,5 +1,5 @@ +import { wowBasePath, wowMediaBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base, mediaBase } from '../base'; import { profession, professionIndex, professionMedia, professionSkillTier, recipe, recipeMedia } from './profession'; describe.concurrent('professionApi', () => { @@ -7,14 +7,14 @@ describe.concurrent('professionApi', () => { const professionId = 123; const resource = profession(professionId); - expect(resource.path).toBe(`${base}/profession/${professionId}`); + expect(resource.path).toBe(`${wowBasePath}/profession/${professionId}`); expect(resource.namespace).toBe('static'); }); it('professionIndex should return a resource object with the correct path and namespace', ({ expect }) => { const resource = professionIndex(); - expect(resource.path).toBe(`${base}/profession/index`); + expect(resource.path).toBe(`${wowBasePath}/profession/index`); expect(resource.namespace).toBe('static'); }); @@ -22,7 +22,7 @@ describe.concurrent('professionApi', () => { const professionId = 123; const resource = professionMedia(professionId); - expect(resource.path).toBe(`${mediaBase}/profession/${professionId}`); + expect(resource.path).toBe(`${wowMediaBasePath}/profession/${professionId}`); expect(resource.namespace).toBe('static'); }); @@ -31,7 +31,7 @@ describe.concurrent('professionApi', () => { const skillTierId = 456; const resource = professionSkillTier(professionId, skillTierId); - expect(resource.path).toBe(`${base}/profession/${professionId}/skill-tier/${skillTierId}`); + expect(resource.path).toBe(`${wowBasePath}/profession/${professionId}/skill-tier/${skillTierId}`); expect(resource.namespace).toBe('static'); }); @@ -39,7 +39,7 @@ describe.concurrent('professionApi', () => { const recipeId = 123; const resource = recipe(recipeId); - expect(resource.path).toBe(`${base}/recipe/${recipeId}`); + expect(resource.path).toBe(`${wowBasePath}/recipe/${recipeId}`); expect(resource.namespace).toBe('static'); }); @@ -47,7 +47,7 @@ describe.concurrent('professionApi', () => { const recipeId = 123; const resource = recipeMedia(recipeId); - expect(resource.path).toBe(`${mediaBase}/recipe/${recipeId}`); + expect(resource.path).toBe(`${wowMediaBasePath}/recipe/${recipeId}`); expect(resource.namespace).toBe('static'); }); }); diff --git a/packages/wow/src/profession/profession.ts b/packages/wow/src/profession/profession.ts index 931cec29..2a7ec74e 100644 --- a/packages/wow/src/profession/profession.ts +++ b/packages/wow/src/profession/profession.ts @@ -1,5 +1,5 @@ import type { Resource } from '@blizzard-api/core'; -import { base, mediaBase } from '../base'; +import { wowBasePath, wowMediaBasePath } from '@blizzard-api/core'; import type { ProfessionIndexResponse, ProfessionMediaResponse, @@ -17,7 +17,7 @@ import type { export function profession(professionId: number): Resource { return { namespace: 'static', - path: `${base}/profession/${professionId}`, + path: `${wowBasePath}/profession/${professionId}`, }; } /** @@ -27,7 +27,7 @@ export function profession(professionId: number): Resource { export function professionIndex(): Resource { return { namespace: 'static', - path: `${base}/profession/index`, + path: `${wowBasePath}/profession/index`, }; } /** @@ -38,7 +38,7 @@ export function professionIndex(): Resource { export function professionMedia(professionId: number): Resource { return { namespace: 'static', - path: `${mediaBase}/profession/${professionId}`, + path: `${wowMediaBasePath}/profession/${professionId}`, }; } /** @@ -50,7 +50,7 @@ export function professionMedia(professionId: number): Resource { return { namespace: 'static', - path: `${base}/profession/${professionId}/skill-tier/${skillTierId}`, + path: `${wowBasePath}/profession/${professionId}/skill-tier/${skillTierId}`, }; } /** @@ -61,7 +61,7 @@ export function professionSkillTier(professionId: number, skillTierId: number): export function recipe(recipeId: number): Resource { return { namespace: 'static', - path: `${base}/recipe/${recipeId}`, + path: `${wowBasePath}/recipe/${recipeId}`, }; } /** @@ -72,6 +72,6 @@ export function recipe(recipeId: number): Resource { export function recipeMedia(recipeId: number): Resource { return { namespace: 'static', - path: `${mediaBase}/recipe/${recipeId}`, + path: `${wowMediaBasePath}/recipe/${recipeId}`, }; } diff --git a/packages/wow/src/profession/types.ts b/packages/wow/src/profession/types.ts index e0634ec7..48a11f4a 100644 --- a/packages/wow/src/profession/types.ts +++ b/packages/wow/src/profession/types.ts @@ -1,4 +1,4 @@ -import type { KeyBase, MediaAsset, NameId, NameIdKey, ResponseBase } from '../base'; +import type { KeyBase, MediaAsset, NameId, NameIdKey, ResponseBase } from '@blizzard-api/core'; /** * The response for a profession index. @@ -52,10 +52,13 @@ export interface RecipeMediaResponse extends ResponseBase { * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} */ export interface RecipeResponse extends NameId, ResponseBase { - crafted_item: NameIdKey; - crafted_quantity: CraftedQuantity; + crafted_item?: NameIdKey; + crafted_quantity?: CraftedQuantity; + description?: string; media: Media; - reagents: Array; + modified_crafting_slots?: Array<{ display_order: number; slot_type: NameIdKey }>; + rank?: number; + reagents?: Array; } interface Category { @@ -64,7 +67,9 @@ interface Category { } interface CraftedQuantity { - value: number; + maximum?: number; + minimum?: number; + value?: number; } interface Media extends KeyBase { diff --git a/packages/wow/src/pvp-season/pvp-season.test.ts b/packages/wow/src/pvp-season/pvp-season.test.ts index 20d24e67..2275ae9a 100644 --- a/packages/wow/src/pvp-season/pvp-season.test.ts +++ b/packages/wow/src/pvp-season/pvp-season.test.ts @@ -1,5 +1,5 @@ +import { wowBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base } from '../base'; import { pvpLeaderboard, pvpLeaderboardIndex, pvpRewardsIndex, pvpSeason, pvpSeasonIndex } from './pvp-season'; describe.concurrent('pvpSeasonApi', () => { @@ -9,35 +9,35 @@ describe.concurrent('pvpSeasonApi', () => { it('pvpLeaderboard should return a resource object with the correct path and namespace', ({ expect }) => { const resource = pvpLeaderboard(pvpSeasonId, bracket); - expect(resource.path).toBe(`${base}/pvp-season/${pvpSeasonId}/pvp-leaderboard/${bracket}`); + expect(resource.path).toBe(`${wowBasePath}/pvp-season/${pvpSeasonId}/pvp-leaderboard/${bracket}`); expect(resource.namespace).toBe('dynamic'); }); it('pvpLeaderboardIndex should return a resource object with the correct path and namespace', ({ expect }) => { const resource = pvpLeaderboardIndex(pvpSeasonId); - expect(resource.path).toBe(`${base}/pvp-season/${pvpSeasonId}/pvp-leaderboard/index`); + expect(resource.path).toBe(`${wowBasePath}/pvp-season/${pvpSeasonId}/pvp-leaderboard/index`); expect(resource.namespace).toBe('dynamic'); }); it('pvpRewardsIndex should return a resource object with the correct path and namespace', ({ expect }) => { const resource = pvpRewardsIndex(pvpSeasonId); - expect(resource.path).toBe(`${base}/pvp-season/${pvpSeasonId}/pvp-reward/index`); + expect(resource.path).toBe(`${wowBasePath}/pvp-season/${pvpSeasonId}/pvp-reward/index`); expect(resource.namespace).toBe('dynamic'); }); it('pvpSeason should return a resource object with the correct path and namespace', ({ expect }) => { const resource = pvpSeason(pvpSeasonId); - expect(resource.path).toBe(`${base}/pvp-season/${pvpSeasonId}`); + expect(resource.path).toBe(`${wowBasePath}/pvp-season/${pvpSeasonId}`); expect(resource.namespace).toBe('dynamic'); }); it('pvpSeasonIndex should return a resource object with the correct path and namespace', ({ expect }) => { const resource = pvpSeasonIndex(); - expect(resource.path).toBe(`${base}/pvp-season/index`); + expect(resource.path).toBe(`${wowBasePath}/pvp-season/index`); expect(resource.namespace).toBe('dynamic'); }); }); diff --git a/packages/wow/src/pvp-season/pvp-season.ts b/packages/wow/src/pvp-season/pvp-season.ts index 2020796b..736eea0c 100644 --- a/packages/wow/src/pvp-season/pvp-season.ts +++ b/packages/wow/src/pvp-season/pvp-season.ts @@ -1,5 +1,5 @@ import type { Resource } from '@blizzard-api/core'; -import { base } from '../base'; +import { wowBasePath } from '@blizzard-api/core'; import type { PvpLeaderboardIndexResponse, PvpLeaderboardResponse, @@ -17,7 +17,7 @@ import type { export function pvpLeaderboard(pvpSeasonId: number, bracket: string): Resource { return { namespace: 'dynamic', - path: `${base}/pvp-season/${pvpSeasonId}/pvp-leaderboard/${bracket}`, + path: `${wowBasePath}/pvp-season/${pvpSeasonId}/pvp-leaderboard/${bracket}`, }; } /** @@ -28,7 +28,7 @@ export function pvpLeaderboard(pvpSeasonId: number, bracket: string): Resource

{ return { namespace: 'dynamic', - path: `${base}/pvp-season/${pvpSeasonId}/pvp-leaderboard/index`, + path: `${wowBasePath}/pvp-season/${pvpSeasonId}/pvp-leaderboard/index`, }; } /** @@ -39,7 +39,7 @@ export function pvpLeaderboardIndex(pvpSeasonId: number): Resource { return { namespace: 'dynamic', - path: `${base}/pvp-season/${pvpSeasonId}/pvp-reward/index`, + path: `${wowBasePath}/pvp-season/${pvpSeasonId}/pvp-reward/index`, }; } /** @@ -50,7 +50,7 @@ export function pvpRewardsIndex(pvpSeasonId: number): Resource { return { namespace: 'dynamic', - path: `${base}/pvp-season/${pvpSeasonId}`, + path: `${wowBasePath}/pvp-season/${pvpSeasonId}`, }; } /** @@ -60,6 +60,6 @@ export function pvpSeason(pvpSeasonId: number): Resource { export function pvpSeasonIndex(): Resource { return { namespace: 'dynamic', - path: `${base}/pvp-season/index`, + path: `${wowBasePath}/pvp-season/index`, }; } diff --git a/packages/wow/src/pvp-season/types.ts b/packages/wow/src/pvp-season/types.ts index 952268e8..a28d23d9 100644 --- a/packages/wow/src/pvp-season/types.ts +++ b/packages/wow/src/pvp-season/types.ts @@ -1,11 +1,11 @@ -import type { Faction, Factions, KeyBase, NameId, NameIdKey, ResponseBase } from '../base'; +import type { Faction, Factions, Href, KeyBase, NameId, NameIdKey, ResponseBase } from '@blizzard-api/core'; /** * The response for a PvP leaderboard index. * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} */ export interface PvpLeaderboardIndexResponse extends ResponseBase { - leaderboards: Array; + leaderboards: Array; season: Season; } @@ -44,15 +44,16 @@ export interface PvpSeasonIndexResponse extends ResponseBase { */ export interface PvpSeasonResponse extends ResponseBase { id: number; - leaderboards: { href: string }; - rewards: { href: string }; - season_name?: string; + leaderboards: Href; + rewards: Href; + season_end_timestamp?: number; + season_name?: null | string; season_start_timestamp: number; } interface Bracket { id: number; - type: 'ARENA_3v3' | 'BATTLEGROUNDS' | 'SHUFFLE'; + type: 'ARENA_3v3' | 'BATTLEGROUNDS' | 'BLITZ' | 'SHUFFLE'; } interface Character extends NameId { @@ -61,7 +62,7 @@ interface Character extends NameId { interface Entry { character: Character; - faction: { type: keyof typeof Factions }; + faction: { type: Factions }; rank: number; rating: number; season_match_statistics: SeasonMatchStatistics; diff --git a/packages/wow/src/pvp-tier/pvp-tier.test.ts b/packages/wow/src/pvp-tier/pvp-tier.test.ts index 4c2007de..fcc85e7a 100644 --- a/packages/wow/src/pvp-tier/pvp-tier.test.ts +++ b/packages/wow/src/pvp-tier/pvp-tier.test.ts @@ -1,5 +1,5 @@ +import { wowBasePath, wowMediaBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base, mediaBase } from '../base'; import { pvpTier, pvpTierIndex, pvpTierMedia } from './pvp-tier'; describe.concurrent('pvpTierApi', () => { @@ -7,14 +7,14 @@ describe.concurrent('pvpTierApi', () => { const pvpTierId = 123; const resource = pvpTier(pvpTierId); - expect(resource.path).toBe(`${base}/pvp-tier/${pvpTierId}`); + expect(resource.path).toBe(`${wowBasePath}/pvp-tier/${pvpTierId}`); expect(resource.namespace).toBe('static'); }); it('pvpTierIndex should return a resource object with the correct path and namespace', ({ expect }) => { const resource = pvpTierIndex(); - expect(resource.path).toBe(`${base}/pvp-tier/index`); + expect(resource.path).toBe(`${wowBasePath}/pvp-tier/index`); expect(resource.namespace).toBe('static'); }); @@ -22,7 +22,7 @@ describe.concurrent('pvpTierApi', () => { const pvpTierId = 123; const resource = pvpTierMedia(pvpTierId); - expect(resource.path).toBe(`${mediaBase}/pvp-tier/${pvpTierId}`); + expect(resource.path).toBe(`${wowMediaBasePath}/pvp-tier/${pvpTierId}`); expect(resource.namespace).toBe('static'); }); }); diff --git a/packages/wow/src/pvp-tier/pvp-tier.ts b/packages/wow/src/pvp-tier/pvp-tier.ts index 2b46e331..9d4be394 100644 --- a/packages/wow/src/pvp-tier/pvp-tier.ts +++ b/packages/wow/src/pvp-tier/pvp-tier.ts @@ -1,5 +1,5 @@ import type { Resource } from '@blizzard-api/core'; -import { base, mediaBase } from '../base'; +import { wowBasePath, wowMediaBasePath } from '@blizzard-api/core'; import type { PvpTierIndexResponse, PvpTierMediaResponse, PvpTierResponse } from './types'; /** @@ -10,7 +10,7 @@ import type { PvpTierIndexResponse, PvpTierMediaResponse, PvpTierResponse } from export function pvpTier(pvpTierId: number): Resource { return { namespace: 'static', - path: `${base}/pvp-tier/${pvpTierId}`, + path: `${wowBasePath}/pvp-tier/${pvpTierId}`, }; } /** @@ -20,7 +20,7 @@ export function pvpTier(pvpTierId: number): Resource { export function pvpTierIndex(): Resource { return { namespace: 'static', - path: `${base}/pvp-tier/index`, + path: `${wowBasePath}/pvp-tier/index`, }; } /** @@ -31,6 +31,6 @@ export function pvpTierIndex(): Resource { export function pvpTierMedia(pvpTierId: number): Resource { return { namespace: 'static', - path: `${mediaBase}/pvp-tier/${pvpTierId}`, + path: `${wowMediaBasePath}/pvp-tier/${pvpTierId}`, }; } diff --git a/packages/wow/src/pvp-tier/types.ts b/packages/wow/src/pvp-tier/types.ts index b09ce7d0..ba0a90bc 100644 --- a/packages/wow/src/pvp-tier/types.ts +++ b/packages/wow/src/pvp-tier/types.ts @@ -1,4 +1,4 @@ -import type { KeyBase, MediaAsset, NameId, NameIdKey, ResponseBase } from '../base'; +import type { KeyBase, MediaAsset, NameId, NameIdKey, ResponseBase } from '@blizzard-api/core'; /** * The response for a PvP tier index. diff --git a/packages/wow/src/quest/quest.test.ts b/packages/wow/src/quest/quest.test.ts index ea8bee84..285c8d50 100644 --- a/packages/wow/src/quest/quest.test.ts +++ b/packages/wow/src/quest/quest.test.ts @@ -1,5 +1,5 @@ +import { wowBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base } from '../base'; import { quest, questArea, @@ -16,14 +16,14 @@ describe.concurrent('questApi', () => { const questId = 123; const resource = quest(questId); - expect(resource.path).toBe(`${base}/quest/${questId}`); + expect(resource.path).toBe(`${wowBasePath}/quest/${questId}`); expect(resource.namespace).toBe('static'); }); it('questIndex should return a resource object with the correct path and namespace', ({ expect }) => { const resource = questIndex(); - expect(resource.path).toBe(`${base}/quest/index`); + expect(resource.path).toBe(`${wowBasePath}/quest/index`); expect(resource.namespace).toBe('static'); }); @@ -31,14 +31,14 @@ describe.concurrent('questApi', () => { const questAreaId = 456; const resource = questArea(questAreaId); - expect(resource.path).toBe(`${base}/quest/area/${questAreaId}`); + expect(resource.path).toBe(`${wowBasePath}/quest/area/${questAreaId}`); expect(resource.namespace).toBe('static'); }); it('questAreaIndex should return a resource object with the correct path and namespace', ({ expect }) => { const resource = questAreaIndex(); - expect(resource.path).toBe(`${base}/quest/area/index`); + expect(resource.path).toBe(`${wowBasePath}/quest/area/index`); expect(resource.namespace).toBe('static'); }); @@ -46,14 +46,14 @@ describe.concurrent('questApi', () => { const questCategoryId = 789; const resource = questCategory(questCategoryId); - expect(resource.path).toBe(`${base}/quest/category/${questCategoryId}`); + expect(resource.path).toBe(`${wowBasePath}/quest/category/${questCategoryId}`); expect(resource.namespace).toBe('static'); }); it('questCategoryIndex should return a resource object with the correct path and namespace', ({ expect }) => { const resource = questCategoryIndex(); - expect(resource.path).toBe(`${base}/quest/category/index`); + expect(resource.path).toBe(`${wowBasePath}/quest/category/index`); expect(resource.namespace).toBe('static'); }); @@ -61,14 +61,14 @@ describe.concurrent('questApi', () => { const questTypeId = 987; const resource = questType(questTypeId); - expect(resource.path).toBe(`${base}/quest/type/${questTypeId}`); + expect(resource.path).toBe(`${wowBasePath}/quest/type/${questTypeId}`); expect(resource.namespace).toBe('static'); }); it('questTypeIndex should return a resource object with the correct path and namespace', ({ expect }) => { const resource = questTypeIndex(); - expect(resource.path).toBe(`${base}/quest/type/index`); + expect(resource.path).toBe(`${wowBasePath}/quest/type/index`); expect(resource.namespace).toBe('static'); }); }); diff --git a/packages/wow/src/quest/quest.ts b/packages/wow/src/quest/quest.ts index ddf46f1c..477c1ddb 100644 --- a/packages/wow/src/quest/quest.ts +++ b/packages/wow/src/quest/quest.ts @@ -1,5 +1,5 @@ import type { Resource } from '@blizzard-api/core'; -import { base } from '../base'; +import { wowBasePath } from '@blizzard-api/core'; import type { QuestAreaIndexResponse, QuestAreaResponse, @@ -19,7 +19,7 @@ import type { export function quest(questId: number): Resource { return { namespace: 'static', - path: `${base}/quest/${questId}`, + path: `${wowBasePath}/quest/${questId}`, }; } /** @@ -30,7 +30,7 @@ export function quest(questId: number): Resource { export function questArea(questAreaId: number): Resource { return { namespace: 'static', - path: `${base}/quest/area/${questAreaId}`, + path: `${wowBasePath}/quest/area/${questAreaId}`, }; } /** @@ -40,7 +40,7 @@ export function questArea(questAreaId: number): Resource { export function questAreaIndex(): Resource { return { namespace: 'static', - path: `${base}/quest/area/index`, + path: `${wowBasePath}/quest/area/index`, }; } /** @@ -51,7 +51,7 @@ export function questAreaIndex(): Resource { export function questCategory(questCategoryId: number): Resource { return { namespace: 'static', - path: `${base}/quest/category/${questCategoryId}`, + path: `${wowBasePath}/quest/category/${questCategoryId}`, }; } /** @@ -61,7 +61,7 @@ export function questCategory(questCategoryId: number): Resource { return { namespace: 'static', - path: `${base}/quest/category/index`, + path: `${wowBasePath}/quest/category/index`, }; } /** @@ -71,7 +71,7 @@ export function questCategoryIndex(): Resource { export function questIndex(): Resource { return { namespace: 'static', - path: `${base}/quest/index`, + path: `${wowBasePath}/quest/index`, }; } /** @@ -82,7 +82,7 @@ export function questIndex(): Resource { export function questType(questTypeId: number): Resource { return { namespace: 'static', - path: `${base}/quest/type/${questTypeId}`, + path: `${wowBasePath}/quest/type/${questTypeId}`, }; } /** @@ -92,6 +92,6 @@ export function questType(questTypeId: number): Resource { export function questTypeIndex(): Resource { return { namespace: 'static', - path: `${base}/quest/type/index`, + path: `${wowBasePath}/quest/type/index`, }; } diff --git a/packages/wow/src/quest/types.ts b/packages/wow/src/quest/types.ts index cb74b838..9c8dcb13 100644 --- a/packages/wow/src/quest/types.ts +++ b/packages/wow/src/quest/types.ts @@ -1,4 +1,4 @@ -import type { Faction, NameIdKey, ResponseBase } from '../base'; +import type { Faction, Href, NameIdKey, ResponseBase } from '@blizzard-api/core'; /** * The response for a quest area index. @@ -41,9 +41,9 @@ export interface QuestCategoryResponse extends ResponseBase { * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} */ export interface QuestIndexResponse extends ResponseBase { - areas: { href: string }; - categories: { href: string }; - types: { href: string }; + areas: Href; + categories: Href; + types: Href; } /** @@ -51,7 +51,8 @@ export interface QuestIndexResponse extends ResponseBase { * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} */ export interface QuestResponse extends ResponseBase { - area: NameIdKey; + area?: NameIdKey; + category: NameIdKey; description: string; id: number; requirements: Requirements; @@ -87,10 +88,16 @@ interface Reputation { value: number; } +interface ReputationRequirement { + faction: NameIdKey; + min_reputation: number; +} + interface Requirements { faction: Faction; max_character_level: number; min_character_level: number; + reputations: Array; } interface Rewards { diff --git a/packages/wow/src/realm/realm.test.ts b/packages/wow/src/realm/realm.test.ts index 84a6d39c..43f49ad2 100644 --- a/packages/wow/src/realm/realm.test.ts +++ b/packages/wow/src/realm/realm.test.ts @@ -1,5 +1,5 @@ +import { wowBasePath, wowSearchBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base, searchBase } from '../base'; import { realm, realmIndex, realmSearch } from './realm'; describe.concurrent('realmApi', () => { @@ -7,14 +7,14 @@ describe.concurrent('realmApi', () => { const realmSlug = 'my-realm'; const resource = realm(realmSlug); - expect(resource.path).toBe(`${base}/realm/${realmSlug}`); + expect(resource.path).toBe(`${wowBasePath}/realm/${realmSlug}`); expect(resource.namespace).toBe('dynamic'); }); it('realmIndex should return a resource object with the correct path and namespace', ({ expect }) => { const resource = realmIndex(); - expect(resource.path).toBe(`${base}/realm/index`); + expect(resource.path).toBe(`${wowBasePath}/realm/index`); expect(resource.namespace).toBe('dynamic'); }); @@ -25,7 +25,7 @@ describe.concurrent('realmApi', () => { timezone: 'Europe/Paris', }); - expect(resource.path).toBe(`${searchBase}/realm`); + expect(resource.path).toBe(`${wowSearchBasePath}/realm`); expect(resource.namespace).toBe('dynamic'); expect(resource.parameters).toEqual({ _page: 1, @@ -41,7 +41,7 @@ describe.concurrent('realmApi', () => { timezone: 'America/Chicago', }); - expect(resource.path).toBe(`${searchBase}/realm`); + expect(resource.path).toBe(`${wowSearchBasePath}/realm`); expect(resource.namespace).toBe('dynamic'); expect(resource.parameters).toEqual({ _page: 1, diff --git a/packages/wow/src/realm/realm.ts b/packages/wow/src/realm/realm.ts index 6a39f277..0ff8ddf6 100644 --- a/packages/wow/src/realm/realm.ts +++ b/packages/wow/src/realm/realm.ts @@ -1,6 +1,6 @@ -import type { Resource, SearchResponse } from '@blizzard-api/core'; -import { base, searchBase } from '../base'; -import type { RealmIndexResponse, RealmResponse, RealmSearchParameters, RealmSearchResponseItem } from './types'; +import type { Resource } from '@blizzard-api/core'; +import { wowBasePath, wowSearchBasePath } from '@blizzard-api/core'; +import type { RealmIndexResponse, RealmResponse, RealmSearchParameters, RealmSearchResponse } from './types'; /** * Get a realm by slug. @@ -10,7 +10,7 @@ import type { RealmIndexResponse, RealmResponse, RealmSearchParameters, RealmSea export function realm(realmSlug: string): Resource { return { namespace: 'dynamic', - path: `${base}/realm/${realmSlug}`, + path: `${wowBasePath}/realm/${realmSlug}`, }; } /** @@ -20,17 +20,15 @@ export function realm(realmSlug: string): Resource { export function realmIndex(): Resource { return { namespace: 'dynamic', - path: `${base}/realm/index`, + path: `${wowBasePath}/realm/index`, }; } /** * Search for realms. * @param options The search parameters. See {@link RealmSearchParameters}. - * @returns The search results. See {@link SearchResponse}. + * @returns The search results. See {@link RealmSearchResponse}. */ -export function realmSearch( - options: RealmSearchParameters, -): Resource, RealmSearchParameters> { +export function realmSearch(options: RealmSearchParameters): Resource { return { namespace: 'dynamic', parameters: { @@ -38,6 +36,6 @@ export function realmSearch( orderby: Array.isArray(options.orderby) ? options.orderby.join(',') : options.orderby, timezone: options.timezone, }, - path: `${searchBase}/realm`, + path: `${wowSearchBasePath}/realm`, }; } diff --git a/packages/wow/src/realm/types.ts b/packages/wow/src/realm/types.ts index 91657a59..b6d57e1a 100644 --- a/packages/wow/src/realm/types.ts +++ b/packages/wow/src/realm/types.ts @@ -1,5 +1,14 @@ -import type { BaseSearchParameters, Locales } from '@blizzard-api/core'; -import type { KeyBase, NameId, NameIdKey, Realm, ResponseBase } from '../base'; +import type { + BaseSearchParameters, + Href, + KeyBase, + Locales, + NameId, + NameIdKey, + Realm, + ResponseBase, + SearchResponseWithoutResults, +} from '@blizzard-api/core'; /** * The category of a realm. @@ -27,19 +36,34 @@ export interface RealmIndexResponse extends ResponseBase { realms: Array; } +export type RealmLocales = + | 'deDE' + | 'enGB' + | 'enUS' + | 'esES' + | 'esMX' + | 'frFR' + | 'itIT' + | 'koKR' + | 'ptBR' + | 'ptPT' + | 'ruRU' + | 'zhCN' + | 'zhTW'; + /** * The response for a realm. * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} */ export interface RealmResponse extends NameId, ResponseBase { category: RealmCategory; - connected_realm: { href: string }; + connected_realm: Href; is_tournament: boolean; - locale: WithoutUnderscore; + locale: RealmLocales; region: NameIdKey; slug: string; timezone: RealmTimezone; - type: { name: RealmType; type: RealmTypeCapitalized }; + type: { name: string; type: RealmTypeCapitalized }; } /** @@ -56,18 +80,8 @@ export interface RealmSearchParameters extends BaseSearchParameters { * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} * @see {@link https://develop.battle.net/documentation/world-of-warcraft/guides/search} */ -export interface RealmSearchResponseItem extends KeyBase { - data: { - category: Record; - id: number; - is_tournament: boolean; - locale: WithoutUnderscore; - name: Record; - region: { id: number; name: Record }; - slug: string; - timezone: RealmTimezone; - type: { name: Record; type: RealmTypeCapitalized }; - }; +export interface RealmSearchResponse extends SearchResponseWithoutResults { + results: Array; } /** @@ -84,16 +98,20 @@ export type RealmTimezone = | 'Europe/Paris'; /** - * The type of a realm, not capitalized or shortened. - */ -export type RealmType = 'Normal' | 'Roleplaying'; - -/** - * The type of a realm, capitalized and shortended). + * The type of a realm, capitalized and shortened). */ export type RealmTypeCapitalized = 'NORMAL' | 'RP'; -// RealmLocale is the same as Locales but without the _ in the middle, assuming that `multi` cannot be used in this context -export type WithoutUnderscore = T extends `${infer Prefix}_${infer Suffix}` - ? `${Prefix}${Suffix}` - : never; +interface RealmSearchResponseItem extends KeyBase { + data: { + category: Record; + id: number; + is_tournament: boolean; + locale: RealmLocales; + name: Record; + region: { id: number; name: Record }; + slug: string; + timezone: RealmTimezone; + type: { name: Record; type: RealmTypeCapitalized }; + }; +} diff --git a/packages/wow/src/region/region.test.ts b/packages/wow/src/region/region.test.ts index 38fca1b4..68e430d5 100644 --- a/packages/wow/src/region/region.test.ts +++ b/packages/wow/src/region/region.test.ts @@ -1,5 +1,5 @@ +import { wowBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base } from '../base'; import { region, regionIndex } from './region'; describe.concurrent('regionApi', () => { @@ -7,14 +7,14 @@ describe.concurrent('regionApi', () => { const regionId = 123; const resource = region(regionId); - expect(resource.path).toBe(`${base}/region/123`); + expect(resource.path).toBe(`${wowBasePath}/region/123`); expect(resource.namespace).toBe('dynamic'); }); it('regionIndex should return a resource object with the correct path and namespace', ({ expect }) => { const resource = regionIndex(); - expect(resource.path).toBe(`${base}/region/index`); + expect(resource.path).toBe(`${wowBasePath}/region/index`); expect(resource.namespace).toBe('dynamic'); }); }); diff --git a/packages/wow/src/region/region.ts b/packages/wow/src/region/region.ts index 1ff917eb..0996a5c6 100644 --- a/packages/wow/src/region/region.ts +++ b/packages/wow/src/region/region.ts @@ -1,5 +1,5 @@ import type { Resource } from '@blizzard-api/core'; -import { base } from '../base'; +import { wowBasePath } from '@blizzard-api/core'; import type { RegionIndexResponse, RegionResponse } from './types'; /** @@ -10,7 +10,7 @@ import type { RegionIndexResponse, RegionResponse } from './types'; export function region(regionId: number): Resource { return { namespace: 'dynamic', - path: `${base}/region/${regionId}`, + path: `${wowBasePath}/region/${regionId}`, }; } /** @@ -20,6 +20,6 @@ export function region(regionId: number): Resource { export function regionIndex(): Resource { return { namespace: 'dynamic', - path: `${base}/region/index`, + path: `${wowBasePath}/region/index`, }; } diff --git a/packages/wow/src/region/types.ts b/packages/wow/src/region/types.ts index 98f78955..51abe9c5 100644 --- a/packages/wow/src/region/types.ts +++ b/packages/wow/src/region/types.ts @@ -1,11 +1,11 @@ -import type { NameId, ResponseBase } from '../base'; +import type { Href, NameId, ResponseBase } from '@blizzard-api/core'; /** * The response for a region index. * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} */ export interface RegionIndexResponse extends ResponseBase { - regions: Array<{ href: string }>; + regions: Array; } /** diff --git a/packages/wow/src/reputations/reputations.test.ts b/packages/wow/src/reputations/reputations.test.ts index 67f418c8..fbb1c29a 100644 --- a/packages/wow/src/reputations/reputations.test.ts +++ b/packages/wow/src/reputations/reputations.test.ts @@ -1,5 +1,5 @@ +import { wowBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base } from '../base'; import { reputationFaction, reputationFactionIndex, reputationTiers, reputationTiersIndex } from './reputations'; describe.concurrent('reputationApi', () => { @@ -7,14 +7,14 @@ describe.concurrent('reputationApi', () => { const reputationFactionId = 123; const resource = reputationFaction(reputationFactionId); - expect(resource.path).toBe(`${base}/reputation-faction/${reputationFactionId}`); + expect(resource.path).toBe(`${wowBasePath}/reputation-faction/${reputationFactionId}`); expect(resource.namespace).toBe('static'); }); it('reputationFactionIndex should return a resource object with the correct path and namespace', ({ expect }) => { const resource = reputationFactionIndex(); - expect(resource.path).toBe(`${base}/reputation-faction/index`); + expect(resource.path).toBe(`${wowBasePath}/reputation-faction/index`); expect(resource.namespace).toBe('static'); }); @@ -22,14 +22,14 @@ describe.concurrent('reputationApi', () => { const reputationTiersId = 456; const resource = reputationTiers(reputationTiersId); - expect(resource.path).toBe(`${base}/reputation-tiers/${reputationTiersId}`); + expect(resource.path).toBe(`${wowBasePath}/reputation-tiers/${reputationTiersId}`); expect(resource.namespace).toBe('static'); }); it('reputationTiersIndex should return a resource object with the correct path and namespace', ({ expect }) => { const resource = reputationTiersIndex(); - expect(resource.path).toBe(`${base}/reputation-tiers/index`); + expect(resource.path).toBe(`${wowBasePath}/reputation-tiers/index`); expect(resource.namespace).toBe('static'); }); }); diff --git a/packages/wow/src/reputations/reputations.ts b/packages/wow/src/reputations/reputations.ts index e0cad51c..2aee7e96 100644 --- a/packages/wow/src/reputations/reputations.ts +++ b/packages/wow/src/reputations/reputations.ts @@ -1,5 +1,5 @@ import type { Resource } from '@blizzard-api/core'; -import { base } from '../base'; +import { wowBasePath } from '@blizzard-api/core'; import type { ReputationFactionIndexResponse, ReputationFactionResponse, @@ -15,7 +15,7 @@ import type { export function reputationFaction(reputationFactionId: number): Resource { return { namespace: 'static', - path: `${base}/reputation-faction/${reputationFactionId}`, + path: `${wowBasePath}/reputation-faction/${reputationFactionId}`, }; } /** @@ -25,7 +25,7 @@ export function reputationFaction(reputationFactionId: number): Resource { return { namespace: 'static', - path: `${base}/reputation-faction/index`, + path: `${wowBasePath}/reputation-faction/index`, }; } /** @@ -36,7 +36,7 @@ export function reputationFactionIndex(): Resource { return { namespace: 'static', - path: `${base}/reputation-tiers/${reputationTiersId}`, + path: `${wowBasePath}/reputation-tiers/${reputationTiersId}`, }; } /** @@ -46,6 +46,6 @@ export function reputationTiers(reputationTiersId: number): Resource { return { namespace: 'static', - path: `${base}/reputation-tiers/index`, + path: `${wowBasePath}/reputation-tiers/index`, }; } diff --git a/packages/wow/src/reputations/types.ts b/packages/wow/src/reputations/types.ts index 29730b19..73647a39 100644 --- a/packages/wow/src/reputations/types.ts +++ b/packages/wow/src/reputations/types.ts @@ -1,4 +1,4 @@ -import type { KeyBase, NameIdKey, ResponseBase } from '../base'; +import type { Faction, KeyBase, NameIdKey, ResponseBase } from '@blizzard-api/core'; /** * The response for a reputation faction index. @@ -14,10 +14,17 @@ export interface ReputationFactionIndexResponse extends ResponseBase { * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} */ export interface ReputationFactionResponse extends ResponseBase { - description: string; + can_paragon?: boolean; + description?: string; + factions?: Array; + header_shows_bar?: boolean; id: number; + is_header?: boolean; + is_renown?: boolean; name: string; - reputation_tiers: ReputationTiers; + player_faction?: Faction; + renown_tiers?: Array; + reputation_tiers?: ReputationTier; } /** @@ -38,13 +45,15 @@ export interface ReputationTiersResponse extends ResponseBase { tiers: Array; } -interface ReputationTier extends KeyBase { - id: number; - name?: string; +interface RenownTier { + level: number; + name: string; + rewards: Array; } -interface ReputationTiers extends KeyBase { +interface ReputationTier extends KeyBase { id: number; + name?: string; } interface Tier { diff --git a/packages/wow/src/spell/spell.test.ts b/packages/wow/src/spell/spell.test.ts index ec8f07f5..1c22ecda 100644 --- a/packages/wow/src/spell/spell.test.ts +++ b/packages/wow/src/spell/spell.test.ts @@ -1,5 +1,5 @@ +import { wowBasePath, wowMediaBasePath, wowSearchBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base, mediaBase, searchBase } from '../base'; import { spell, spellMedia, spellSearch } from './spell'; describe.concurrent('spellApi', () => { @@ -7,7 +7,7 @@ describe.concurrent('spellApi', () => { const spellId = 456; const resource = spell(spellId); - expect(resource.path).toBe(`${base}/spell/${spellId}`); + expect(resource.path).toBe(`${wowBasePath}/spell/${spellId}`); expect(resource.namespace).toBe('static'); }); @@ -15,7 +15,7 @@ describe.concurrent('spellApi', () => { const spellId = 789; const resource = spellMedia(spellId); - expect(resource.path).toBe(`${mediaBase}/spell/${spellId}`); + expect(resource.path).toBe(`${wowMediaBasePath}/spell/${spellId}`); expect(resource.namespace).toBe('static'); }); @@ -27,7 +27,7 @@ describe.concurrent('spellApi', () => { orderby: 'name', }); - expect(resource.path).toBe(`${searchBase}/spell`); + expect(resource.path).toBe(`${wowSearchBasePath}/spell`); expect(resource.namespace).toBe('static'); expect(resource.parameters).toEqual({ _page: 1, @@ -44,7 +44,7 @@ describe.concurrent('spellApi', () => { orderby: ['name', 'id'], }); - expect(resource.path).toBe(`${searchBase}/spell`); + expect(resource.path).toBe(`${wowSearchBasePath}/spell`); expect(resource.namespace).toBe('static'); expect(resource.parameters).toEqual({ _page: 1, diff --git a/packages/wow/src/spell/spell.ts b/packages/wow/src/spell/spell.ts index 99d88b69..ebf15756 100644 --- a/packages/wow/src/spell/spell.ts +++ b/packages/wow/src/spell/spell.ts @@ -1,6 +1,6 @@ -import type { Resource, SearchResponse } from '@blizzard-api/core'; -import { base, mediaBase, searchBase } from '../base'; -import type { SpellMediaResponse, SpellResponse, SpellSearchParameters, SpellSearchResponseItem } from './types'; +import type { Resource } from '@blizzard-api/core'; +import { wowBasePath, wowMediaBasePath, wowSearchBasePath } from '@blizzard-api/core'; +import type { SpellMediaResponse, SpellResponse, SpellSearchParameters, SpellSearchResponse } from './types'; /** * Get a spell by ID. @@ -10,7 +10,7 @@ import type { SpellMediaResponse, SpellResponse, SpellSearchParameters, SpellSea export function spell(spellId: number): Resource { return { namespace: 'static', - path: `${base}/spell/${spellId}`, + path: `${wowBasePath}/spell/${spellId}`, }; } /** @@ -21,17 +21,17 @@ export function spell(spellId: number): Resource { export function spellMedia(spellId: number): Resource { return { namespace: 'static', - path: `${mediaBase}/spell/${spellId}`, + path: `${wowMediaBasePath}/spell/${spellId}`, }; } /** * Get a spell search. * @param options The spell search options. See {@link SpellSearchParameters}. - * @returns The spell search. See {@link SearchResponse}. + * @returns The spell search. See {@link SpellSearchResponse}. */ export function spellSearch( options: SpellSearchParameters, -): Resource, Omit> { +): Resource> { return { namespace: 'static', parameters: { @@ -39,6 +39,6 @@ export function spellSearch( [`name.${options.locale}`]: options.name, orderby: Array.isArray(options.orderby) ? options.orderby.join(',') : options.orderby, }, - path: `${searchBase}/spell`, + path: `${wowSearchBasePath}/spell`, }; } diff --git a/packages/wow/src/spell/types.ts b/packages/wow/src/spell/types.ts index 79c66d5c..9cff2ca9 100644 --- a/packages/wow/src/spell/types.ts +++ b/packages/wow/src/spell/types.ts @@ -1,5 +1,12 @@ -import type { BaseSearchParameters, Locales } from '@blizzard-api/core'; -import type { KeyBase, MediaAsset, NameId, ResponseBase } from '../base'; +import type { + BaseSearchParameters, + KeyBase, + Locales, + MediaAsset, + NameId, + ResponseBase, + SearchResponseWithoutResults, +} from '@blizzard-api/core'; /** * The response for a spell media. @@ -34,14 +41,18 @@ export interface SpellSearchParameters extends BaseSearchParameters { * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} * @see {@link https://develop.battle.net/documentation/world-of-warcraft/guides/search} */ -export interface SpellSearchResponseItem extends KeyBase { - data: { - id: number; - media: { id: number }; - name: Record; - }; +export interface SpellSearchResponse extends SearchResponseWithoutResults { + results: Array; } interface Media extends KeyBase { id: number; } + +interface SpellSearchResponseItem extends KeyBase { + data: { + id: number; + media: { id: number }; + name: Record; + }; +} diff --git a/packages/wow/src/talent/talent.test.ts b/packages/wow/src/talent/talent.test.ts index 54d57d35..3cf5fad5 100644 --- a/packages/wow/src/talent/talent.test.ts +++ b/packages/wow/src/talent/talent.test.ts @@ -1,31 +1,31 @@ +import { wowBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base } from '../base'; import { pvpTalent, pvpTalentIndex, talent, talentIndex, talentTree, talentTreeIndex, talentTreeNodes } from './talent'; describe.concurrent('talentApi', () => { it('should return the correct path for pvpTalent', ({ expect }) => { const pvpTalentId = 123; const resource = pvpTalent(pvpTalentId); - expect(resource.path).toBe(`${base}/pvp-talent/123`); + expect(resource.path).toBe(`${wowBasePath}/pvp-talent/123`); expect(resource.namespace).toBe('static'); }); it('should return the correct path for pvpTalentIndex', ({ expect }) => { const resource = pvpTalentIndex(); - expect(resource.path).toBe(`${base}/pvp-talent/index`); + expect(resource.path).toBe(`${wowBasePath}/pvp-talent/index`); expect(resource.namespace).toBe('static'); }); it('should return the correct path for talent', ({ expect }) => { const talentId = 456; const resource = talent(talentId); - expect(resource.path).toBe(`${base}/talent/456`); + expect(resource.path).toBe(`${wowBasePath}/talent/456`); expect(resource.namespace).toBe('static'); }); it('should return the correct path for talentIndex', ({ expect }) => { const resource = talentIndex(); - expect(resource.path).toBe(`${base}/talent/index`); + expect(resource.path).toBe(`${wowBasePath}/talent/index`); expect(resource.namespace).toBe('static'); }); @@ -33,20 +33,20 @@ describe.concurrent('talentApi', () => { const talentTreeId = 789; const specId = 10; const resource = talentTree(talentTreeId, specId); - expect(resource.path).toBe(`${base}/talent-tree/789/playable-specialization/10`); + expect(resource.path).toBe(`${wowBasePath}/talent-tree/789/playable-specialization/10`); expect(resource.namespace).toBe('static'); }); it('should return the correct path for talentTreeIndex', ({ expect }) => { const resource = talentTreeIndex(); - expect(resource.path).toBe(`${base}/talent-tree/index`); + expect(resource.path).toBe(`${wowBasePath}/talent-tree/index`); expect(resource.namespace).toBe('static'); }); it('should return the correct path for talentTreeNodes', ({ expect }) => { const talentTreeId = 789; const resource = talentTreeNodes(talentTreeId); - expect(resource.path).toBe(`${base}/talent-tree/789`); + expect(resource.path).toBe(`${wowBasePath}/talent-tree/789`); expect(resource.namespace).toBe('static'); }); }); diff --git a/packages/wow/src/talent/talent.ts b/packages/wow/src/talent/talent.ts index c43e0b6a..8e7cac55 100644 --- a/packages/wow/src/talent/talent.ts +++ b/packages/wow/src/talent/talent.ts @@ -1,5 +1,5 @@ import type { Resource } from '@blizzard-api/core'; -import { base } from '../base'; +import { wowBasePath } from '@blizzard-api/core'; import type { PvpTalentIndexResponse, PvpTalentResponse, @@ -18,7 +18,7 @@ import type { export function pvpTalent(pvpTalentId: number): Resource { return { namespace: 'static', - path: `${base}/pvp-talent/${pvpTalentId}`, + path: `${wowBasePath}/pvp-talent/${pvpTalentId}`, }; } /** @@ -28,7 +28,7 @@ export function pvpTalent(pvpTalentId: number): Resource { export function pvpTalentIndex(): Resource { return { namespace: 'static', - path: `${base}/pvp-talent/index`, + path: `${wowBasePath}/pvp-talent/index`, }; } /** @@ -39,7 +39,7 @@ export function pvpTalentIndex(): Resource { export function talent(talentId: number): Resource { return { namespace: 'static', - path: `${base}/talent/${talentId}`, + path: `${wowBasePath}/talent/${talentId}`, }; } /** @@ -49,7 +49,7 @@ export function talent(talentId: number): Resource { export function talentIndex(): Resource { return { namespace: 'static', - path: `${base}/talent/index`, + path: `${wowBasePath}/talent/index`, }; } /** @@ -61,7 +61,7 @@ export function talentIndex(): Resource { export function talentTree(talentTreeId: number, specId: number): Resource { return { namespace: 'static', - path: `${base}/talent-tree/${talentTreeId}/playable-specialization/${specId}`, + path: `${wowBasePath}/talent-tree/${talentTreeId}/playable-specialization/${specId}`, }; } /** @@ -71,7 +71,7 @@ export function talentTree(talentTreeId: number, specId: number): Resource { return { namespace: 'static', - path: `${base}/talent-tree/index`, + path: `${wowBasePath}/talent-tree/index`, }; } /** @@ -82,6 +82,6 @@ export function talentTreeIndex(): Resource { export function talentTreeNodes(talentTreeId: number): Resource { return { namespace: 'static', - path: `${base}/talent-tree/${talentTreeId}`, + path: `${wowBasePath}/talent-tree/${talentTreeId}`, }; } diff --git a/packages/wow/src/talent/types.ts b/packages/wow/src/talent/types.ts index 2eb6267c..4ae36e60 100644 --- a/packages/wow/src/talent/types.ts +++ b/packages/wow/src/talent/types.ts @@ -1,4 +1,4 @@ -import type { KeyBase, NameId, NameIdKey, ResponseBase } from '../base'; +import type { KeyBase, NameId, NameIdKey, ResponseBase } from '@blizzard-api/core'; /** * The response for a pvp talent index. @@ -16,6 +16,7 @@ export interface PvpTalentResponse extends ResponseBase { compatible_slots: Array; description: string; id: number; + overrides_spell?: NameIdKey; playable_specialization: NameIdKey; spell: NameIdKey; unlock_player_level: number; @@ -35,9 +36,11 @@ export interface TalentIndexResponse extends ResponseBase { */ export interface TalentResponse extends ResponseBase { id: number; - playable_class: PlayableClass; - rank_descriptions: Array; - spell: NameIdKey; + overrides_spell?: NameIdKey; + playable_class?: KeyBase & { id: number; name?: string }; + playable_specialization?: NameIdKey; + rank_descriptions?: Array; + spell?: NameIdKey; } /** @@ -46,6 +49,7 @@ export interface TalentResponse extends ResponseBase { */ export interface TalentTreeIndexResponse extends ResponseBase { class_talent_trees: Array; + hero_talent_trees: Array; spec_talent_trees: Array; } @@ -65,7 +69,8 @@ export interface TalentTreeNodesResponse extends ResponseBase { */ export interface TalentTreeResponse extends NameId, ResponseBase { class_talent_nodes: Array; - media: { href: string }; + hero_talent_trees: Array; + media: KeyBase; playable_class: NameIdKey; playable_specialization: NameIdKey; restriction_lines: Array; @@ -96,13 +101,28 @@ interface ClassTalentNodeRank { tooltip?: Tooltip; } -interface NodeType { +interface HeroTalentTree extends NameId { + hero_talent_nodes: Array; + media: KeyBase & { id: number }; + playable_class: NameIdKey; + playable_specializations: Array; +} + +interface HeroTalentTreeNode { + display_col: number; + display_row: number; id: number; - type: 'ACTIVE' | 'CHOICE' | 'PASSIVE'; + locked_by?: Array; + node_type: { id: number; type: 'ACTIVE' | 'CHOICE' | 'PASSIVE' }; + ranks: Array; + raw_position_x: number; + raw_position_y: number; + unlocks?: Array; } -interface PlayableClass extends KeyBase { +interface NodeType { id: number; + type: 'ACTIVE' | 'CHOICE' | 'PASSIVE'; } interface PurpleSpellTooltip { @@ -113,12 +133,13 @@ interface PurpleSpellTooltip { interface Rank { choice_of_tooltips?: Array; + default_points?: number; rank: number; tooltip?: Tooltip; } interface RankDescription { - description: null; + description: null | string; rank: number; } @@ -154,10 +175,12 @@ interface TalentNode { display_col: number; display_row: number; id: number; + locked_by?: Array; node_type: NodeType; ranks: Array; raw_position_x: number; raw_position_y: number; + unlocks?: Array; } interface TalentTree extends KeyBase { diff --git a/packages/wow/src/tech-talent/tech-talent.test.ts b/packages/wow/src/tech-talent/tech-talent.test.ts index 37cc9030..ed0bc8a5 100644 --- a/packages/wow/src/tech-talent/tech-talent.test.ts +++ b/packages/wow/src/tech-talent/tech-talent.test.ts @@ -1,38 +1,38 @@ +import { wowBasePath, wowMediaBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base, mediaBase } from '../base'; import { techTalent, techTalentIndex, techTalentMedia, techTalentTree, techTalentTreeIndex } from './tech-talent'; describe.concurrent('techTalentApi', () => { it('should return the correct path for techTalent', ({ expect }) => { const techTalentId = 123; const resource = techTalent(techTalentId); - expect(resource.path).toBe(`${base}/tech-talent/123`); + expect(resource.path).toBe(`${wowBasePath}/tech-talent/123`); expect(resource.namespace).toBe('static'); }); it('should return the correct path for techTalentIndex', ({ expect }) => { const resource = techTalentIndex(); - expect(resource.path).toBe(`${base}/tech-talent/index`); + expect(resource.path).toBe(`${wowBasePath}/tech-talent/index`); expect(resource.namespace).toBe('static'); }); it('should return the correct path for techTalentMedia', ({ expect }) => { const techTalentId = 456; const resource = techTalentMedia(techTalentId); - expect(resource.path).toBe(`${mediaBase}/tech-talent/456`); + expect(resource.path).toBe(`${wowMediaBasePath}/tech-talent/456`); expect(resource.namespace).toBe('static'); }); it('should return the correct path for techTalentTree', ({ expect }) => { const techTalentTreeId = 789; const resource = techTalentTree(techTalentTreeId); - expect(resource.path).toBe(`${base}/tech-talent-tree/789`); + expect(resource.path).toBe(`${wowBasePath}/tech-talent-tree/789`); expect(resource.namespace).toBe('static'); }); it('should return the correct path for techTalentTreeIndex', ({ expect }) => { const resource = techTalentTreeIndex(); - expect(resource.path).toBe(`${base}/tech-talent-tree/index`); + expect(resource.path).toBe(`${wowBasePath}/tech-talent-tree/index`); expect(resource.namespace).toBe('static'); }); }); diff --git a/packages/wow/src/tech-talent/tech-talent.ts b/packages/wow/src/tech-talent/tech-talent.ts index f0b701cd..73f0f384 100644 --- a/packages/wow/src/tech-talent/tech-talent.ts +++ b/packages/wow/src/tech-talent/tech-talent.ts @@ -1,5 +1,5 @@ import type { Resource } from '@blizzard-api/core'; -import { base, mediaBase } from '../base'; +import { wowBasePath, wowMediaBasePath } from '@blizzard-api/core'; import type { TechTalentIndexResponse, TechTalentMediaResponse, @@ -16,7 +16,7 @@ import type { export function techTalent(techTalentId: number): Resource { return { namespace: 'static', - path: `${base}/tech-talent/${techTalentId}`, + path: `${wowBasePath}/tech-talent/${techTalentId}`, }; } /** @@ -26,7 +26,7 @@ export function techTalent(techTalentId: number): Resource { export function techTalentIndex(): Resource { return { namespace: 'static', - path: `${base}/tech-talent/index`, + path: `${wowBasePath}/tech-talent/index`, }; } /** @@ -37,7 +37,7 @@ export function techTalentIndex(): Resource { export function techTalentMedia(techTalentId: number): Resource { return { namespace: 'static', - path: `${mediaBase}/tech-talent/${techTalentId}`, + path: `${wowMediaBasePath}/tech-talent/${techTalentId}`, }; } /** @@ -48,7 +48,7 @@ export function techTalentMedia(techTalentId: number): Resource { return { namespace: 'static', - path: `${base}/tech-talent-tree/${techTalentTreeId}`, + path: `${wowBasePath}/tech-talent-tree/${techTalentTreeId}`, }; } /** @@ -58,6 +58,6 @@ export function techTalentTree(techTalentTreeId: number): Resource { return { namespace: 'static', - path: `${base}/tech-talent-tree/index`, + path: `${wowBasePath}/tech-talent-tree/index`, }; } diff --git a/packages/wow/src/tech-talent/types.ts b/packages/wow/src/tech-talent/types.ts index e7a7f8d8..3ab68c5a 100644 --- a/packages/wow/src/tech-talent/types.ts +++ b/packages/wow/src/tech-talent/types.ts @@ -1,4 +1,4 @@ -import type { KeyBase, MediaAsset, NameId, NameIdKey, ResponseBase } from '../base'; +import type { KeyBase, MediaAsset, NameId, NameIdKey, ResponseBase } from '@blizzard-api/core'; /** * The response for a tech talent index. @@ -21,9 +21,13 @@ export interface TechTalentMediaResponse extends ResponseBase { * @see {@link https://develop.battle.net/documentation/world-of-warcraft/game-data-apis} */ export interface TechTalentResponse extends NameId, ResponseBase { + description?: string; display_order: number; media: Media; - talent_tree: Media; + prerequisite_talent?: NameIdKey; + socket_type?: { name: string; type: 'ENDURANCE' | 'FINESSE' | 'POTENCY' }; + spell_tooltip?: SpellTooltip; + talent_tree: KeyBase & { id: number; name?: string }; tier: number; } @@ -42,7 +46,7 @@ export interface TechTalentTreeIndexResponse extends ResponseBase { export interface TechTalentTreeResponse extends ResponseBase { id: number; max_tiers: number; - playable_class: NameIdKey; + playable_class?: NameIdKey; talents: Array; } @@ -50,6 +54,15 @@ interface Media extends KeyBase { id: number; } +interface SpellTooltip { + cast_time: string; + cooldown?: string; + description: null | string; + power_cost?: null | string; + range?: string; + spell: NameIdKey; +} + interface TalentTree extends KeyBase { id: number; name?: string; diff --git a/packages/wow/src/title/title.test.ts b/packages/wow/src/title/title.test.ts index 26f41935..04ed9dfc 100644 --- a/packages/wow/src/title/title.test.ts +++ b/packages/wow/src/title/title.test.ts @@ -1,18 +1,18 @@ +import { wowBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base } from '../base'; import { title, titleIndex } from './title'; describe.concurrent('titleApi', () => { it('should return the correct path for title', ({ expect }) => { const titleId = 123; const resource = title(titleId); - expect(resource.path).toBe(`${base}/title/123`); + expect(resource.path).toBe(`${wowBasePath}/title/123`); expect(resource.namespace).toBe('static'); }); it('should return the correct path for titleIndex', ({ expect }) => { const resource = titleIndex(); - expect(resource.path).toBe(`${base}/title/index`); + expect(resource.path).toBe(`${wowBasePath}/title/index`); expect(resource.namespace).toBe('static'); }); }); diff --git a/packages/wow/src/title/title.ts b/packages/wow/src/title/title.ts index e5608278..d17bf604 100644 --- a/packages/wow/src/title/title.ts +++ b/packages/wow/src/title/title.ts @@ -1,5 +1,5 @@ import type { Resource } from '@blizzard-api/core'; -import { base } from '../base'; +import { wowBasePath } from '@blizzard-api/core'; import type { TitleIndexResponse, TitleResponse } from './types'; /** @@ -10,7 +10,7 @@ import type { TitleIndexResponse, TitleResponse } from './types'; export function title(titleId: number): Resource { return { namespace: 'static', - path: `${base}/title/${titleId}`, + path: `${wowBasePath}/title/${titleId}`, }; } /** @@ -20,6 +20,6 @@ export function title(titleId: number): Resource { export function titleIndex(): Resource { return { namespace: 'static', - path: `${base}/title/index`, + path: `${wowBasePath}/title/index`, }; } diff --git a/packages/wow/src/title/types.ts b/packages/wow/src/title/types.ts index ab7fb129..d002d605 100644 --- a/packages/wow/src/title/types.ts +++ b/packages/wow/src/title/types.ts @@ -1,4 +1,4 @@ -import type { GenderName, NameId, NameIdKey, ResponseBase } from '../base'; +import type { GenderName, NameId, NameIdKey, ResponseBase } from '@blizzard-api/core'; /** * The response for a title index. @@ -14,4 +14,11 @@ export interface TitleIndexResponse extends ResponseBase { */ export interface TitleResponse extends NameId, ResponseBase { gender_name: GenderName; + source?: TitleSource; +} + +interface TitleSource { + achievements?: Array; + quests?: Array; + type: { name: 'Achievement'; type: 'ACHIEVEMENT' } | { name: 'Quest'; type: 'QUEST' }; } diff --git a/packages/wow/src/toy/toy.test.ts b/packages/wow/src/toy/toy.test.ts index 4bcf5290..9b4510ed 100644 --- a/packages/wow/src/toy/toy.test.ts +++ b/packages/wow/src/toy/toy.test.ts @@ -1,18 +1,18 @@ +import { wowBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base } from '../base'; import { toy, toyIndex } from './toy'; describe.concurrent('toyApi', () => { it('should return the correct path for toy', ({ expect }) => { const toyId = 123; const resource = toy(toyId); - expect(resource.path).toBe(`${base}/toy/123`); + expect(resource.path).toBe(`${wowBasePath}/toy/123`); expect(resource.namespace).toBe('static'); }); it('should return the correct path for toyIndex', ({ expect }) => { const resource = toyIndex(); - expect(resource.path).toBe(`${base}/toy/index`); + expect(resource.path).toBe(`${wowBasePath}/toy/index`); expect(resource.namespace).toBe('static'); }); }); diff --git a/packages/wow/src/toy/toy.ts b/packages/wow/src/toy/toy.ts index 99a61215..fe25f9a4 100644 --- a/packages/wow/src/toy/toy.ts +++ b/packages/wow/src/toy/toy.ts @@ -1,5 +1,5 @@ import type { Resource } from '@blizzard-api/core'; -import { base } from '../base'; +import { wowBasePath } from '@blizzard-api/core'; import type { ToyIndexResponse, ToyResponse } from './types'; /** @@ -10,7 +10,7 @@ import type { ToyIndexResponse, ToyResponse } from './types'; export function toy(toyId: number): Resource { return { namespace: 'static', - path: `${base}/toy/${toyId}`, + path: `${wowBasePath}/toy/${toyId}`, }; } /** @@ -20,6 +20,6 @@ export function toy(toyId: number): Resource { export function toyIndex(): Resource { return { namespace: 'static', - path: `${base}/toy/index`, + path: `${wowBasePath}/toy/index`, }; } diff --git a/packages/wow/src/toy/types.ts b/packages/wow/src/toy/types.ts index f0755ded..c3adcb2b 100644 --- a/packages/wow/src/toy/types.ts +++ b/packages/wow/src/toy/types.ts @@ -1,4 +1,4 @@ -import type { KeyBase, NameIdKey, ResponseBase } from '../base'; +import type { KeyBase, NameIdKey, ResponseBase } from '@blizzard-api/core'; /** * The response for a toy index. @@ -16,8 +16,9 @@ export interface ToyResponse extends ResponseBase { id: number; item: NameIdKey; media: Media; + should_exclude_if_uncollected?: boolean; source: Source; - source_description: string; + source_description?: string; } interface Media extends KeyBase { diff --git a/packages/wow/src/wow-token/types.ts b/packages/wow/src/wow-token/types.ts index 581b9c05..924c7635 100644 --- a/packages/wow/src/wow-token/types.ts +++ b/packages/wow/src/wow-token/types.ts @@ -1,4 +1,4 @@ -import type { ResponseBase } from '../base'; +import type { ResponseBase } from '@blizzard-api/core'; /** * The response for a WoW token. diff --git a/packages/wow/src/wow-token/wow-token.test.ts b/packages/wow/src/wow-token/wow-token.test.ts index e5419808..a3442434 100644 --- a/packages/wow/src/wow-token/wow-token.test.ts +++ b/packages/wow/src/wow-token/wow-token.test.ts @@ -1,11 +1,11 @@ +import { wowBasePath } from '@blizzard-api/core'; import { describe, it } from 'vitest'; -import { base } from '../base'; import { wowToken } from './wow-token'; describe.concurrent('wowTokenApi', () => { it('should return the wow token resource', ({ expect }) => { const resource = wowToken(); - expect(resource.path).toBe(`${base}/token/index`); + expect(resource.path).toBe(`${wowBasePath}/token/index`); expect(resource.namespace).toBe('dynamic'); }); }); diff --git a/packages/wow/src/wow-token/wow-token.ts b/packages/wow/src/wow-token/wow-token.ts index 4e2f6792..9b2ecbb6 100644 --- a/packages/wow/src/wow-token/wow-token.ts +++ b/packages/wow/src/wow-token/wow-token.ts @@ -1,5 +1,5 @@ import type { Resource } from '@blizzard-api/core'; -import { base } from '../base'; +import { wowBasePath } from '@blizzard-api/core'; import type { WowTokenResponse } from './types'; /** @@ -9,6 +9,6 @@ import type { WowTokenResponse } from './types'; export function wowToken(): Resource { return { namespace: 'dynamic', - path: `${base}/token/index`, + path: `${wowBasePath}/token/index`, }; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 54b9e422..9a7b90c9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,28 +10,28 @@ importers: devDependencies: '@changesets/cli': specifier: 2.29.8 - version: 2.29.8(@types/node@24.10.1) + version: 2.29.8(@types/node@24.10.10) '@putstack/eslint-config-typescript': - specifier: 4.11.0 - version: 4.11.0(@eslint/js@9.39.1)(@typescript-eslint/utils@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript-eslint@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(typescript@5.9.3) + specifier: 4.14.0 + version: 4.14.0(@eslint/js@9.39.2)(@typescript-eslint/utils@8.54.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(typescript-eslint@8.54.0(eslint@9.39.2)(typescript@5.9.3))(typescript@5.9.3) '@putstack/prettier-config': specifier: 2.0.0 - version: 2.0.0(prettier@3.7.4) + version: 2.0.0(prettier@3.8.1) '@types/node': - specifier: 24.10.1 - version: 24.10.1 + specifier: 24.10.10 + version: 24.10.10 '@vitest/coverage-v8': - specifier: 4.0.15 - version: 4.0.15(vitest@4.0.15) + specifier: 4.0.18 + version: 4.0.18(vitest@4.0.18) '@vitest/ui': - specifier: 4.0.15 - version: 4.0.15(vitest@4.0.15) + specifier: 4.0.18 + version: 4.0.18(vitest@4.0.18) eslint: - specifier: 9.39.1 - version: 9.39.1(jiti@2.6.1) + specifier: 9.39.2 + version: 9.39.2 eslint-plugin-jsdoc: - specifier: 61.4.1 - version: 61.4.1(eslint@9.39.1(jiti@2.6.1)) + specifier: 62.5.0 + version: 62.5.0(eslint@9.39.2) husky: specifier: 9.1.7 version: 9.1.7 @@ -42,32 +42,38 @@ importers: specifier: 8.0.4 version: 8.0.4 prettier: - specifier: 3.7.4 - version: 3.7.4 + specifier: 3.8.1 + version: 3.8.1 + ts-to-zod: + specifier: 5.1.0 + version: 5.1.0 tsdown: - specifier: 0.17.0 - version: 0.17.0(typescript@5.9.3) + specifier: 0.20.1 + version: 0.20.1(typescript@5.9.3) + tsx: + specifier: 4.21.0 + version: 4.21.0 turbo: - specifier: 2.6.3 - version: 2.6.3 + specifier: 2.8.2 + version: 2.8.2 typedoc: - specifier: 0.28.15 - version: 0.28.15(typescript@5.9.3) + specifier: 0.28.16 + version: 0.28.16(typescript@5.9.3) typedoc-github-theme: specifier: 0.3.1 - version: 0.3.1(typedoc@0.28.15(typescript@5.9.3)) + version: 0.3.1(typedoc@0.28.16(typescript@5.9.3)) typescript: specifier: 5.9.3 version: 5.9.3 typescript-eslint: - specifier: 8.48.1 - version: 8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + specifier: 8.54.0 + version: 8.54.0(eslint@9.39.2)(typescript@5.9.3) vitest: - specifier: 4.0.15 - version: 4.0.15(@types/node@24.10.1)(@vitest/ui@4.0.15)(jiti@2.6.1)(yaml@2.8.2) + specifier: 4.0.18 + version: 4.0.18(@types/node@24.10.10)(@vitest/ui@4.0.18)(tsx@4.21.0)(yaml@2.8.2) zod: - specifier: 4.1.13 - version: 4.1.13 + specifier: 4.3.6 + version: 4.3.6 packages/classic-wow: devDependencies: @@ -78,8 +84,8 @@ importers: packages/client: dependencies: ky: - specifier: 1.14.0 - version: 1.14.0 + specifier: 1.14.3 + version: 1.14.3 devDependencies: '@blizzard-api/classic-wow': specifier: workspace:* @@ -114,6 +120,30 @@ importers: specifier: workspace:* version: link:../core + packages/integration-tests: + devDependencies: + '@blizzard-api/classic-wow': + specifier: workspace:* + version: link:../classic-wow + '@blizzard-api/client': + specifier: workspace:* + version: link:../client + '@blizzard-api/core': + specifier: workspace:* + version: link:../core + '@blizzard-api/d3': + specifier: workspace:* + version: link:../d3 + '@blizzard-api/hs': + specifier: workspace:* + version: link:../hs + '@blizzard-api/sc2': + specifier: workspace:* + version: link:../sc2 + '@blizzard-api/wow': + specifier: workspace:* + version: link:../wow + packages/sc2: devDependencies: '@blizzard-api/core': @@ -128,31 +158,48 @@ importers: packages: - '@babel/generator@7.28.5': - resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} - engines: {node: '>=6.9.0'} + '@babel/generator@8.0.0-rc.1': + resolution: {integrity: sha512-3ypWOOiC4AYHKr8vYRVtWtWmyvcoItHtVqF8paFax+ydpmUdPsJpLBkBBs5ItmhdrwC3a0ZSqqFAdzls4ODP3w==} + engines: {node: ^20.19.0 || >=22.12.0} '@babel/helper-string-parser@7.27.1': resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@8.0.0-rc.1': + resolution: {integrity: sha512-vi/pfmbrOtQmqgfboaBhaCU50G7mcySVu69VU8z+lYoPPB6WzI9VgV7WQfL908M4oeSH5fDkmoupIqoE0SdApw==} + engines: {node: ^20.19.0 || >=22.12.0} + '@babel/helper-validator-identifier@7.28.5': resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} - '@babel/parser@7.28.5': - resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + '@babel/helper-validator-identifier@8.0.0-rc.1': + resolution: {integrity: sha512-I4YnARytXC2RzkLNVnf5qFNFMzp679qZpmtw/V3Jt2uGnWiIxyJtaukjG7R8pSx8nG2NamICpGfljQsogj+FbQ==} + engines: {node: ^20.19.0 || >=22.12.0} + + '@babel/parser@7.29.0': + resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/runtime@7.28.4': - resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} + '@babel/parser@8.0.0-rc.1': + resolution: {integrity: sha512-6HyyU5l1yK/7h9Ki52i5h6mDAx4qJdiLQO4FdCyJNoB/gy3T3GGJdhQzzbZgvgZCugYBvwtQiWRt94QKedHnkA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + '@babel/runtime@7.28.6': + resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} engines: {node: '>=6.9.0'} - '@babel/types@7.28.5': - resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} + '@babel/types@8.0.0-rc.1': + resolution: {integrity: sha512-ubmJ6TShyaD69VE9DQrlXcdkvJbmwWPB8qYj0H2kaJi29O7vJT9ajSdBd2W8CG34pwL9pYA74fi7RHC1qbLoVQ==} + engines: {node: ^20.19.0 || >=22.12.0} + '@bcoe/v8-coverage@1.0.2': resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} @@ -212,189 +259,191 @@ packages: '@changesets/write@0.4.0': resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} - '@emnapi/core@1.7.1': - resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==} + '@clack/core@1.0.0-alpha.4': + resolution: {integrity: sha512-VCtU+vjyKPMSakVrB9q1bOnXN7QW/w4+YQDQCOF59GrzydW+169i0fVx/qzRRXJgt8KGj/pZZ/JxXroFZIDByg==} - '@emnapi/runtime@1.7.1': - resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} + '@clack/prompts@1.0.0-alpha.4': + resolution: {integrity: sha512-KnmtDF2xQGoI5AlBme9akHtvCRV0RKAARUXHBQO2tMwnY8B08/4zPWigT7uLK25UPrMCEqnyQPkKRjNdhPbf8g==} + + '@emnapi/core@1.8.1': + resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==} + + '@emnapi/runtime@1.8.1': + resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} - '@es-joy/jsdoccomment@0.76.0': - resolution: {integrity: sha512-g+RihtzFgGTx2WYCuTHbdOXJeAlGnROws0TeALx9ow/ZmOROOZkVg5wp/B44n0WJgI4SQFP1eWM2iRPlU2Y14w==} - engines: {node: '>=20.11.0'} + '@es-joy/jsdoccomment@0.83.0': + resolution: {integrity: sha512-e1MHSEPJ4m35zkBvNT6kcdeH1SvMaJDsPC3Xhfseg3hvF50FUE3f46Yn36jgbrPYYXezlWUQnevv23c+lx2MCA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} '@es-joy/resolve.exports@1.2.0': resolution: {integrity: sha512-Q9hjxWI5xBM+qW2enxfe8wDKdFWMfd0Z29k5ZJnuBqD/CasY5Zryj09aCA6owbGATWz+39p5uIdaHXpopOcG8g==} engines: {node: '>=10'} - '@esbuild/aix-ppc64@0.25.12': - resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + '@esbuild/aix-ppc64@0.27.2': + resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.25.12': - resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + '@esbuild/android-arm64@0.27.2': + resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.25.12': - resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + '@esbuild/android-arm@0.27.2': + resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.25.12': - resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + '@esbuild/android-x64@0.27.2': + resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.25.12': - resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + '@esbuild/darwin-arm64@0.27.2': + resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.25.12': - resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + '@esbuild/darwin-x64@0.27.2': + resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.25.12': - resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + '@esbuild/freebsd-arm64@0.27.2': + resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.12': - resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + '@esbuild/freebsd-x64@0.27.2': + resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.25.12': - resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + '@esbuild/linux-arm64@0.27.2': + resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.25.12': - resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + '@esbuild/linux-arm@0.27.2': + resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.25.12': - resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + '@esbuild/linux-ia32@0.27.2': + resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.25.12': - resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + '@esbuild/linux-loong64@0.27.2': + resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.25.12': - resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + '@esbuild/linux-mips64el@0.27.2': + resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.25.12': - resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + '@esbuild/linux-ppc64@0.27.2': + resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.25.12': - resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + '@esbuild/linux-riscv64@0.27.2': + resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.25.12': - resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + '@esbuild/linux-s390x@0.27.2': + resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.25.12': - resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + '@esbuild/linux-x64@0.27.2': + resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.12': - resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + '@esbuild/netbsd-arm64@0.27.2': + resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.12': - resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + '@esbuild/netbsd-x64@0.27.2': + resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.12': - resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + '@esbuild/openbsd-arm64@0.27.2': + resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.12': - resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + '@esbuild/openbsd-x64@0.27.2': + resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.25.12': - resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + '@esbuild/openharmony-arm64@0.27.2': + resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.25.12': - resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + '@esbuild/sunos-x64@0.27.2': + resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.25.12': - resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + '@esbuild/win32-arm64@0.27.2': + resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.25.12': - resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + '@esbuild/win32-ia32@0.27.2': + resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.25.12': - resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + '@esbuild/win32-x64@0.27.2': + resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==} engines: {node: '>=18'} cpu: [x64] os: [win32] - '@eslint-community/eslint-utils@4.9.0': - resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - '@eslint-community/regexpp@4.12.1': - resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint-community/regexpp@4.12.2': resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} @@ -415,8 +464,8 @@ packages: resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.39.1': - resolution: {integrity: sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==} + '@eslint/js@9.39.2': + resolution: {integrity: sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/object-schema@2.1.7': @@ -427,8 +476,8 @@ packages: resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@gerrit0/mini-shiki@3.19.0': - resolution: {integrity: sha512-ZSlWfLvr8Nl0T4iA3FF/8VH8HivYF82xQts2DY0tJxZd4wtXJ8AA0nmdW9lmO4hlrh3f9xNwEPtOgqETPqKwDA==} + '@gerrit0/mini-shiki@3.22.0': + resolution: {integrity: sha512-jMpciqEVUBKE1QwU64S4saNMzpsSza6diNCk4MWAeCxO2+LFi2FIFmL2S0VDLzEJCxuvCbU783xi8Hp/gkM5CQ==} '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} @@ -459,8 +508,8 @@ packages: resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} engines: {node: 20 || >=22} - '@isaacs/brace-expansion@5.0.0': - resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} + '@isaacs/brace-expansion@5.0.1': + resolution: {integrity: sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==} engines: {node: 20 || >=22} '@jridgewell/gen-mapping@0.3.13': @@ -485,8 +534,8 @@ packages: '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} - '@napi-rs/wasm-runtime@1.1.0': - resolution: {integrity: sha512-Fq6DJW+Bb5jaWE69/qOE0D1TUN9+6uWhCeZpdnSBk14pjLcCWR7Q8n49PTSPHazM37JqrsdpEthXy2xn6jWWiA==} + '@napi-rs/wasm-runtime@1.1.1': + resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} @@ -500,18 +549,18 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@oxc-project/runtime@0.101.0': - resolution: {integrity: sha512-t3qpfVZIqSiLQ5Kqt/MC4Ge/WCOGrrcagAdzTcDaggupjiGxUx4nJF2v6wUCXWSzWHn5Ns7XLv13fCJEwCOERQ==} - engines: {node: ^20.19.0 || >=22.12.0} + '@oclif/core@4.8.0': + resolution: {integrity: sha512-jteNUQKgJHLHFbbz806aGZqf+RJJ7t4gwF4MYa8fCwCxQ8/klJNWc0MvaJiBebk7Mc+J39mdlsB4XraaCKznFw==} + engines: {node: '>=18.0.0'} - '@oxc-project/types@0.101.0': - resolution: {integrity: sha512-nuFhqlUzJX+gVIPPfuE6xurd4lST3mdcWOhyK/rZO0B9XWMKm79SuszIQEnSMmmDhq1DC8WWVYGVd+6F93o1gQ==} + '@oxc-project/types@0.110.0': + resolution: {integrity: sha512-6Ct21OIlrEnFEJk5LT4e63pk3btsI6/TusD/GStLi7wYlGJNOl1GI9qvXAnRAxQU9zqA2Oz+UwhfTOU2rPZVow==} '@polka/url@1.0.0-next.29': resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} - '@putstack/eslint-config-typescript@4.11.0': - resolution: {integrity: sha512-q5xNFc1xC2pQUO5WO6KZYDVgysNcIG/NcQQS8jzo69De1bObM6KWQPpYxJ7iedADj420ptAg8HXCmCHsWKpOQw==} + '@putstack/eslint-config-typescript@4.14.0': + resolution: {integrity: sha512-mPWiyzN3i1nsbOJDbJXIVIDQRXehfHSUA2HnlIDzUYbSQo66J3TuIC5reEZ8GuA30KQUqVmI+XsgbnxQ+UDOVg==} engines: {node: ^20.9 || >=22} peerDependencies: '@eslint/js': ^9.20.0 @@ -528,207 +577,222 @@ packages: '@quansync/fs@1.0.0': resolution: {integrity: sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==} - '@rolldown/binding-android-arm64@1.0.0-beta.53': - resolution: {integrity: sha512-Ok9V8o7o6YfSdTTYA/uHH30r3YtOxLD6G3wih/U9DO0ucBBFq8WPt/DslU53OgfteLRHITZny9N/qCUxMf9kjQ==} + '@rolldown/binding-android-arm64@1.0.0-rc.1': + resolution: {integrity: sha512-He6ZoCfv5D7dlRbrhNBkuMVIHd0GDnjJwbICE1OWpG7G3S2gmJ+eXkcNLJjzjNDpeI2aRy56ou39AJM9AD8YFA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.0.0-beta.53': - resolution: {integrity: sha512-yIsKqMz0CtRnVa6x3Pa+mzTihr4Ty+Z6HfPbZ7RVbk1Uxnco4+CUn7Qbm/5SBol1JD/7nvY8rphAgyAi7Lj6Vg==} + '@rolldown/binding-darwin-arm64@1.0.0-rc.1': + resolution: {integrity: sha512-YzJdn08kSOXnj85ghHauH2iHpOJ6eSmstdRTLyaziDcUxe9SyQJgGyx/5jDIhDvtOcNvMm2Ju7m19+S/Rm1jFg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.0-beta.53': - resolution: {integrity: sha512-GTXe+mxsCGUnJOFMhfGWmefP7Q9TpYUseHvhAhr21nCTgdS8jPsvirb0tJwM3lN0/u/cg7bpFNa16fQrjKrCjQ==} + '@rolldown/binding-darwin-x64@1.0.0-rc.1': + resolution: {integrity: sha512-cIvAbqM+ZVV6lBSKSBtlNqH5iCiW933t1q8j0H66B3sjbe8AxIRetVqfGgcHcJtMzBIkIALlL9fcDrElWLJQcQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.0.0-beta.53': - resolution: {integrity: sha512-9Tmp7bBvKqyDkMcL4e089pH3RsjD3SUungjmqWtyhNOxoQMh0fSmINTyYV8KXtE+JkxYMPWvnEt+/mfpVCkk8w==} + '@rolldown/binding-freebsd-x64@1.0.0-rc.1': + resolution: {integrity: sha512-rVt+B1B/qmKwCl1XD02wKfgh3vQPXRXdB/TicV2w6g7RVAM1+cZcpigwhLarqiVCxDObFZ7UgXCxPC7tpDoRog==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.53': - resolution: {integrity: sha512-a1y5fiB0iovuzdbjUxa7+Zcvgv+mTmlGGC4XydVIsyl48eoxgaYkA3l9079hyTyhECsPq+mbr0gVQsFU11OJAQ==} + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.1': + resolution: {integrity: sha512-69YKwJJBOFprQa1GktPgbuBOfnn+EGxu8sBJ1TjPER+zhSpYeaU4N07uqmyBiksOLGXsMegymuecLobfz03h8Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.53': - resolution: {integrity: sha512-bpIGX+ov9PhJYV+wHNXl9rzq4F0QvILiURn0y0oepbQx+7stmQsKA0DhPGwmhfvF856wq+gbM8L92SAa/CBcLg==} + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.1': + resolution: {integrity: sha512-9JDhHUf3WcLfnViFWm+TyorqUtnSAHaCzlSNmMOq824prVuuzDOK91K0Hl8DUcEb9M5x2O+d2/jmBMsetRIn3g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - '@rolldown/binding-linux-arm64-musl@1.0.0-beta.53': - resolution: {integrity: sha512-bGe5EBB8FVjHBR1mOLOPEFg1Lp3//7geqWkU5NIhxe+yH0W8FVrQ6WRYOap4SUTKdklD/dC4qPLREkMMQ855FA==} + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.1': + resolution: {integrity: sha512-UvApLEGholmxw/HIwmUnLq3CwdydbhaHHllvWiCTNbyGom7wTwOtz5OAQbAKZYyiEOeIXZNPkM7nA4Dtng7CLw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - '@rolldown/binding-linux-x64-gnu@1.0.0-beta.53': - resolution: {integrity: sha512-qL+63WKVQs1CMvFedlPt0U9PiEKJOAL/bsHMKUDS6Vp2Q+YAv/QLPu8rcvkfIMvQ0FPU2WL0aX4eWwF6e/GAnA==} + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.1': + resolution: {integrity: sha512-uVctNgZHiGnJx5Fij7wHLhgw4uyZBVi6mykeWKOqE7bVy9Hcxn0fM/IuqdMwk6hXlaf9fFShDTFz2+YejP+x0A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - '@rolldown/binding-linux-x64-musl@1.0.0-beta.53': - resolution: {integrity: sha512-VGl9JIGjoJh3H8Mb+7xnVqODajBmrdOOb9lxWXdcmxyI+zjB2sux69br0hZJDTyLJfvBoYm439zPACYbCjGRmw==} + '@rolldown/binding-linux-x64-musl@1.0.0-rc.1': + resolution: {integrity: sha512-T6Eg0xWwcxd/MzBcuv4Z37YVbUbJxy5cMNnbIt/Yr99wFwli30O4BPlY8hKeGyn6lWNtU0QioBS46lVzDN38bg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - '@rolldown/binding-openharmony-arm64@1.0.0-beta.53': - resolution: {integrity: sha512-B4iIserJXuSnNzA5xBLFUIjTfhNy7d9sq4FUMQY3GhQWGVhS2RWWzzDnkSU6MUt7/aHUrep0CdQfXUJI9D3W7A==} + '@rolldown/binding-openharmony-arm64@1.0.0-rc.1': + resolution: {integrity: sha512-PuGZVS2xNJyLADeh2F04b+Cz4NwvpglbtWACgrDOa5YDTEHKwmiTDjoD5eZ9/ptXtcpeFrMqD2H4Zn33KAh1Eg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-wasm32-wasi@1.0.0-beta.53': - resolution: {integrity: sha512-BUjAEgpABEJXilGq/BPh7jeU3WAJ5o15c1ZEgHaDWSz3LB881LQZnbNJHmUiM4d1JQWMYYyR1Y490IBHi2FPJg==} + '@rolldown/binding-wasm32-wasi@1.0.0-rc.1': + resolution: {integrity: sha512-2mOxY562ihHlz9lEXuaGEIDCZ1vI+zyFdtsoa3M62xsEunDXQE+DVPO4S4x5MPK9tKulG/aFcA/IH5eVN257Cw==} engines: {node: '>=14.0.0'} cpu: [wasm32] - '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.53': - resolution: {integrity: sha512-s27uU7tpCWSjHBnxyVXHt3rMrQdJq5MHNv3BzsewCIroIw3DJFjMH1dzCPPMUFxnh1r52Nf9IJ/eWp6LDoyGcw==} + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.1': + resolution: {integrity: sha512-oQVOP5cfAWZwRD0Q3nGn/cA9FW3KhMMuQ0NIndALAe6obqjLhqYVYDiGGRGrxvnjJsVbpLwR14gIUYnpIcHR1g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.0-beta.53': - resolution: {integrity: sha512-cjWL/USPJ1g0en2htb4ssMjIycc36RvdQAx1WlXnS6DpULswiUTVXPDesTifSKYSyvx24E0YqQkEm0K/M2Z/AA==} + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.1': + resolution: {integrity: sha512-Ydsxxx++FNOuov3wCBPaYjZrEvKOOGq3k+BF4BPridhg2pENfitSRD2TEuQ8i33bp5VptuNdC9IzxRKU031z5A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@rolldown/pluginutils@1.0.0-beta.53': - resolution: {integrity: sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==} + '@rolldown/pluginutils@1.0.0-rc.1': + resolution: {integrity: sha512-UTBjtTxVOhodhzFVp/ayITaTETRHPUPYZPXQe0WU0wOgxghMojXxYjOiPOauKIYNWJAWS2fd7gJgGQK8GU8vDA==} - '@rollup/rollup-android-arm-eabi@4.53.3': - resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==} + '@rollup/rollup-android-arm-eabi@4.57.1': + resolution: {integrity: sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.53.3': - resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==} + '@rollup/rollup-android-arm64@4.57.1': + resolution: {integrity: sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.53.3': - resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==} + '@rollup/rollup-darwin-arm64@4.57.1': + resolution: {integrity: sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.53.3': - resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==} + '@rollup/rollup-darwin-x64@4.57.1': + resolution: {integrity: sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.53.3': - resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==} + '@rollup/rollup-freebsd-arm64@4.57.1': + resolution: {integrity: sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.53.3': - resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==} + '@rollup/rollup-freebsd-x64@4.57.1': + resolution: {integrity: sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.53.3': - resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} + '@rollup/rollup-linux-arm-gnueabihf@4.57.1': + resolution: {integrity: sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.53.3': - resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} + '@rollup/rollup-linux-arm-musleabihf@4.57.1': + resolution: {integrity: sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.53.3': - resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} + '@rollup/rollup-linux-arm64-gnu@4.57.1': + resolution: {integrity: sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.53.3': - resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} + '@rollup/rollup-linux-arm64-musl@4.57.1': + resolution: {integrity: sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loong64-gnu@4.53.3': - resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} + '@rollup/rollup-linux-loong64-gnu@4.57.1': + resolution: {integrity: sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-loong64-musl@4.57.1': + resolution: {integrity: sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-ppc64-gnu@4.53.3': - resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} + '@rollup/rollup-linux-ppc64-gnu@4.57.1': + resolution: {integrity: sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.53.3': - resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} + '@rollup/rollup-linux-ppc64-musl@4.57.1': + resolution: {integrity: sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.57.1': + resolution: {integrity: sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.53.3': - resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} + '@rollup/rollup-linux-riscv64-musl@4.57.1': + resolution: {integrity: sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.53.3': - resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} + '@rollup/rollup-linux-s390x-gnu@4.57.1': + resolution: {integrity: sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.53.3': - resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} + '@rollup/rollup-linux-x64-gnu@4.57.1': + resolution: {integrity: sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.53.3': - resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} + '@rollup/rollup-linux-x64-musl@4.57.1': + resolution: {integrity: sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==} cpu: [x64] os: [linux] - '@rollup/rollup-openharmony-arm64@4.53.3': - resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==} + '@rollup/rollup-openbsd-x64@4.57.1': + resolution: {integrity: sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.57.1': + resolution: {integrity: sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.53.3': - resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==} + '@rollup/rollup-win32-arm64-msvc@4.57.1': + resolution: {integrity: sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.53.3': - resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==} + '@rollup/rollup-win32-ia32-msvc@4.57.1': + resolution: {integrity: sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.53.3': - resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==} + '@rollup/rollup-win32-x64-gnu@4.57.1': + resolution: {integrity: sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.53.3': - resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==} + '@rollup/rollup-win32-x64-msvc@4.57.1': + resolution: {integrity: sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==} cpu: [x64] os: [win32] - '@shikijs/engine-oniguruma@3.19.0': - resolution: {integrity: sha512-1hRxtYIJfJSZeM5ivbUXv9hcJP3PWRo5prG/V2sWwiubUKTa+7P62d2qxCW8jiVFX4pgRHhnHNp+qeR7Xl+6kg==} + '@shikijs/engine-oniguruma@3.22.0': + resolution: {integrity: sha512-DyXsOG0vGtNtl7ygvabHd7Mt5EY8gCNqR9Y7Lpbbd/PbJvgWrqaKzH1JW6H6qFkuUa8aCxoiYVv8/YfFljiQxA==} - '@shikijs/langs@3.19.0': - resolution: {integrity: sha512-dBMFzzg1QiXqCVQ5ONc0z2ebyoi5BKz+MtfByLm0o5/nbUu3Iz8uaTCa5uzGiscQKm7lVShfZHU1+OG3t5hgwg==} + '@shikijs/langs@3.22.0': + resolution: {integrity: sha512-x/42TfhWmp6H00T6uwVrdTJGKgNdFbrEdhaDwSR5fd5zhQ1Q46bHq9EO61SCEWJR0HY7z2HNDMaBZp8JRmKiIA==} - '@shikijs/themes@3.19.0': - resolution: {integrity: sha512-H36qw+oh91Y0s6OlFfdSuQ0Ld+5CgB/VE6gNPK+Hk4VRbVG/XQgkjnt4KzfnnoO6tZPtKJKHPjwebOCfjd6F8A==} + '@shikijs/themes@3.22.0': + resolution: {integrity: sha512-o+tlOKqsr6FE4+mYJG08tfCFDS+3CG20HbldXeVoyP+cYSUxDhrFf3GPjE60U55iOkkjbpY2uC3It/eeja35/g==} - '@shikijs/types@3.19.0': - resolution: {integrity: sha512-Z2hdeEQlzuntf/BZpFG8a+Fsw9UVXdML7w0o3TgSXV3yNESGon+bs9ITkQb3Ki7zxoXOOu5oJWqZ2uto06V9iQ==} + '@shikijs/types@3.22.0': + resolution: {integrity: sha512-491iAekgKDBFE67z70Ok5a8KBMsQ2IJwOWw3us/7ffQkIBCyOQfm/aNwVMBUriP02QshIfgHCBSIYAl3u2eWjg==} '@shikijs/vscode-textmate@10.0.2': resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} @@ -737,8 +801,8 @@ packages: resolution: {integrity: sha512-TeheYy0ILzBEI/CO55CP6zJCSdSWeRtGnHy8U8dWSUH4I68iqTsy7HkMktR4xakThc9jotkPQUXT4ITdbV7cHA==} engines: {node: '>=18'} - '@standard-schema/spec@1.0.0': - resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} @@ -755,77 +819,85 @@ packages: '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + '@types/jsesc@2.5.1': + resolution: {integrity: sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} '@types/node@12.20.55': resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} - '@types/node@24.10.1': - resolution: {integrity: sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==} + '@types/node@24.10.10': + resolution: {integrity: sha512-+0/4J266CBGPUq/ELg7QUHhN25WYjE0wYTPSQJn1xeu8DOlIOPxXxrNGiLmfAWl7HMMgWFWXpt9IDjMWrF5Iow==} '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} - '@typescript-eslint/eslint-plugin@8.48.1': - resolution: {integrity: sha512-X63hI1bxl5ohelzr0LY5coufyl0LJNthld+abwxpCoo6Gq+hSqhKwci7MUWkXo67mzgUK6YFByhmaHmUcuBJmA==} + '@typescript-eslint/eslint-plugin@8.54.0': + resolution: {integrity: sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.48.1 + '@typescript-eslint/parser': ^8.54.0 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.48.1': - resolution: {integrity: sha512-PC0PDZfJg8sP7cmKe6L3QIL8GZwU5aRvUFedqSIpw3B+QjRSUZeeITC2M5XKeMXEzL6wccN196iy3JLwKNvDVA==} + '@typescript-eslint/parser@8.54.0': + resolution: {integrity: sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.48.1': - resolution: {integrity: sha512-HQWSicah4s9z2/HifRPQ6b6R7G+SBx64JlFQpgSSHWPKdvCZX57XCbszg/bapbRsOEv42q5tayTYcEFpACcX1w==} + '@typescript-eslint/project-service@8.54.0': + resolution: {integrity: sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/scope-manager@8.48.1': - resolution: {integrity: sha512-rj4vWQsytQbLxC5Bf4XwZ0/CKd362DkWMUkviT7DCS057SK64D5lH74sSGzhI6PDD2HCEq02xAP9cX68dYyg1w==} + '@typescript-eslint/scope-manager@8.54.0': + resolution: {integrity: sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.48.1': - resolution: {integrity: sha512-k0Jhs4CpEffIBm6wPaCXBAD7jxBtrHjrSgtfCjUvPp9AZ78lXKdTR8fxyZO5y4vWNlOvYXRtngSZNSn+H53Jkw==} + '@typescript-eslint/tsconfig-utils@8.54.0': + resolution: {integrity: sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.48.1': - resolution: {integrity: sha512-1jEop81a3LrJQLTf/1VfPQdhIY4PlGDBc/i67EVWObrtvcziysbLN3oReexHOM6N3jyXgCrkBsZpqwH0hiDOQg==} + '@typescript-eslint/type-utils@8.54.0': + resolution: {integrity: sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@8.48.1': - resolution: {integrity: sha512-+fZ3LZNeiELGmimrujsDCT4CRIbq5oXdHe7chLiW8qzqyPMnn1puNstCrMNVAqwcl2FdIxkuJ4tOs/RFDBVc/Q==} + '@typescript-eslint/types@8.54.0': + resolution: {integrity: sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.48.1': - resolution: {integrity: sha512-/9wQ4PqaefTK6POVTjJaYS0bynCgzh6ClJHGSBj06XEHjkfylzB+A3qvyaXnErEZSaxhIo4YdyBgq6j4RysxDg==} + '@typescript-eslint/typescript-estree@8.54.0': + resolution: {integrity: sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.48.1': - resolution: {integrity: sha512-fAnhLrDjiVfey5wwFRwrweyRlCmdz5ZxXz2G/4cLn0YDLjTapmN4gcCsTBR1N2rWnZSDeWpYtgLDsJt+FpmcwA==} + '@typescript-eslint/utils@8.54.0': + resolution: {integrity: sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/visitor-keys@8.48.1': - resolution: {integrity: sha512-BmxxndzEWhE4TIEEMBs8lP3MBWN3jFPs/p6gPm/wkv02o41hI6cq9AuSmGAaTTHPtA1FTi2jBre4A9rm5ZmX+Q==} + '@typescript-eslint/visitor-keys@8.54.0': + resolution: {integrity: sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript/vfs@1.6.2': + resolution: {integrity: sha512-hoBwJwcbKHmvd2QVebiytN1aELvpk9B74B4L1mFm/XT1Q/VOYAWl2vQ9AWRFtQq8zmz6enTpfTV8WRc4ATjW/g==} + peerDependencies: + typescript: '*' + '@unrs/resolver-binding-android-arm-eabi@1.11.1': resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} cpu: [arm] @@ -921,20 +993,20 @@ packages: cpu: [x64] os: [win32] - '@vitest/coverage-v8@4.0.15': - resolution: {integrity: sha512-FUJ+1RkpTFW7rQITdgTi93qOCWJobWhBirEPCeXh2SW2wsTlFxy51apDz5gzG+ZEYt/THvWeNmhdAoS9DTwpCw==} + '@vitest/coverage-v8@4.0.18': + resolution: {integrity: sha512-7i+N2i0+ME+2JFZhfuz7Tg/FqKtilHjGyGvoHYQ6iLV0zahbsJ9sljC9OcFcPDbhYKCet+sG8SsVqlyGvPflZg==} peerDependencies: - '@vitest/browser': 4.0.15 - vitest: 4.0.15 + '@vitest/browser': 4.0.18 + vitest: 4.0.18 peerDependenciesMeta: '@vitest/browser': optional: true - '@vitest/expect@4.0.15': - resolution: {integrity: sha512-Gfyva9/GxPAWXIWjyGDli9O+waHDC0Q0jaLdFP1qPAUUfo1FEXPXUfUkp3eZA0sSq340vPycSyOlYUeM15Ft1w==} + '@vitest/expect@4.0.18': + resolution: {integrity: sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==} - '@vitest/mocker@4.0.15': - resolution: {integrity: sha512-CZ28GLfOEIFkvCFngN8Sfx5h+Se0zN+h4B7yOsPVCcgtiO7t5jt9xQh2E1UkFep+eb9fjyMfuC5gBypwb07fvQ==} + '@vitest/mocker@4.0.18': + resolution: {integrity: sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0-0 @@ -944,25 +1016,25 @@ packages: vite: optional: true - '@vitest/pretty-format@4.0.15': - resolution: {integrity: sha512-SWdqR8vEv83WtZcrfLNqlqeQXlQLh2iilO1Wk1gv4eiHKjEzvgHb2OVc3mIPyhZE6F+CtfYjNlDJwP5MN6Km7A==} + '@vitest/pretty-format@4.0.18': + resolution: {integrity: sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==} - '@vitest/runner@4.0.15': - resolution: {integrity: sha512-+A+yMY8dGixUhHmNdPUxOh0la6uVzun86vAbuMT3hIDxMrAOmn5ILBHm8ajrqHE0t8R9T1dGnde1A5DTnmi3qw==} + '@vitest/runner@4.0.18': + resolution: {integrity: sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==} - '@vitest/snapshot@4.0.15': - resolution: {integrity: sha512-A7Ob8EdFZJIBjLjeO0DZF4lqR6U7Ydi5/5LIZ0xcI+23lYlsYJAfGn8PrIWTYdZQRNnSRlzhg0zyGu37mVdy5g==} + '@vitest/snapshot@4.0.18': + resolution: {integrity: sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==} - '@vitest/spy@4.0.15': - resolution: {integrity: sha512-+EIjOJmnY6mIfdXtE/bnozKEvTC4Uczg19yeZ2vtCz5Yyb0QQ31QWVQ8hswJ3Ysx/K2EqaNsVanjr//2+P3FHw==} + '@vitest/spy@4.0.18': + resolution: {integrity: sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==} - '@vitest/ui@4.0.15': - resolution: {integrity: sha512-sxSyJMaKp45zI0u+lHrPuZM1ZJQ8FaVD35k+UxVrha1yyvQ+TZuUYllUixwvQXlB7ixoDc7skf3lQPopZIvaQw==} + '@vitest/ui@4.0.18': + resolution: {integrity: sha512-CGJ25bc8fRi8Lod/3GHSvXRKi7nBo3kxh0ApW4yCjmrWmRmlT53B5E08XRSZRliygG0aVNxLrBEqPYdz/KcCtQ==} peerDependencies: - vitest: 4.0.15 + vitest: 4.0.18 - '@vitest/utils@4.0.15': - resolution: {integrity: sha512-HXjPW2w5dxhTD0dLwtYHDnelK3j8sR8cWIaLxr22evTyY6q8pRCjZSmhRWVjBaOVXChQd6AwMzi9pucorXCPZA==} + '@vitest/utils@4.0.18': + resolution: {integrity: sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==} acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} @@ -981,6 +1053,10 @@ packages: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} + ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + ansi-escapes@7.2.0: resolution: {integrity: sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==} engines: {node: '>=18'} @@ -1001,6 +1077,10 @@ packages: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} + ansis@3.17.0: + resolution: {integrity: sha512-0qWUglt9JEqLFr3w1I1pbrChn1grhaiAR2ocX1PP/flRmxgtwTzPFFFnfIlD6aMOLQZgSuCRlidD70lvx8yhzg==} + engines: {node: '>=14'} + ansis@4.2.0: resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} engines: {node: '>=14'} @@ -1023,26 +1103,29 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} - ast-kit@2.2.0: - resolution: {integrity: sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==} + ast-kit@3.0.0-beta.1: + resolution: {integrity: sha512-trmleAnZ2PxN/loHWVhhx1qeOHSRXq4TDsBBxq3GqeJitfk3+jTQ+v/C1km/KYq9M7wKqCewMh+/NAvVH7m+bw==} engines: {node: '>=20.19.0'} - ast-v8-to-istanbul@0.3.8: - resolution: {integrity: sha512-szgSZqUxI5T8mLKvS7WTjF9is+MVbOeLADU73IseOcrqhxr/VAvy6wfoVE39KnKzA7JRhjF5eUagNlHwvZPlKQ==} + ast-v8-to-istanbul@0.3.11: + resolution: {integrity: sha512-Qya9fkoofMjCBNVdWINMjB5KZvkYfaO9/anwkWnjxibpWUxo5iHl2sOdP7/uAqaRuUYuoo8rDwnbaaKVFxoUvw==} + + async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - baseline-browser-mapping@2.9.2: - resolution: {integrity: sha512-PxSsosKQjI38iXkmb3d0Y32efqyA0uW4s41u4IVBsLlWLhCiYNpH/AfNOVWRqCQBlD8TFJTz6OUWNd4DFJCnmw==} + baseline-browser-mapping@2.9.19: + resolution: {integrity: sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==} hasBin: true better-path-resolve@1.0.0: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} - birpc@3.0.0: - resolution: {integrity: sha512-by+04pHuxpCEQcucAXqzopqfhyI8TLK5Qg5MST0cB6MP+JhHna9ollrtK9moVh27aq6Q6MEJgebD0cVm//yBkg==} + birpc@4.0.0: + resolution: {integrity: sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==} brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} @@ -1079,11 +1162,11 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - caniuse-lite@1.0.30001759: - resolution: {integrity: sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw==} + caniuse-lite@1.0.30001767: + resolution: {integrity: sha512-34+zUAMhSH+r+9eKmYG+k2Rpt8XttfE4yXAjoZvkAPs15xcYQhyBYdalJ65BzivAvGRMViEjy6oKr/S91loekQ==} - chai@6.2.1: - resolution: {integrity: sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==} + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} chalk@4.1.2: @@ -1096,22 +1179,34 @@ packages: chardet@2.1.1: resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} - ci-info@4.3.1: - resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==} + ci-info@4.4.0: + resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} engines: {node: '>=8'} clean-regexp@1.0.0: resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} engines: {node: '>=4'} + clean-stack@3.0.1: + resolution: {integrity: sha512-lR9wNiMRcVQjSB3a7xXGLuz4cr4wJuuXlaAEbRutGowQTmlp7R72/DOgN21e8jdwblMWl9UOJMJXarX94pzKdg==} + engines: {node: '>=10'} + cli-cursor@5.0.0: resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} engines: {node: '>=18'} + cli-spinners@2.9.2: + resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} + engines: {node: '>=6'} + cli-truncate@5.1.1: resolution: {integrity: sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A==} engines: {node: '>=20'} @@ -1126,19 +1221,19 @@ packages: colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} - commander@14.0.2: - resolution: {integrity: sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==} + commander@14.0.3: + resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} engines: {node: '>=20'} - comment-parser@1.4.1: - resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==} + comment-parser@1.4.5: + resolution: {integrity: sha512-aRDkn3uyIlCFfk5NUA+VdwMmMsh8JGhc4hapfV4yxymHGQ3BVskMQfoXGpCo5IoBuQ9tS5iiVKhCpTcB4pW4qw==} engines: {node: '>= 12.0.0'} concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - core-js-compat@3.47.0: - resolution: {integrity: sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==} + core-js-compat@3.48.0: + resolution: {integrity: sha512-OM4cAF3D6VtH/WkLtWvyNC56EZVXsZdU3iqaMG2B4WvYrlqU831pc4UtG5yp0sE9z8Y02wVN7PjW5Zf9Gt0f1Q==} cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} @@ -1156,6 +1251,9 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + detect-indent@6.1.0: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} @@ -1173,12 +1271,20 @@ packages: oxc-resolver: optional: true - electron-to-chromium@1.5.266: - resolution: {integrity: sha512-kgWEglXvkEfMH7rxP5OSZZwnaDWT7J9EoZCujhnpLbfi0bbNtRkgdX2E3gt0Uer11c61qCYktB3hwkAS325sJg==} + ejs@3.1.10: + resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} + engines: {node: '>=0.10.0'} + hasBin: true + + electron-to-chromium@1.5.286: + resolution: {integrity: sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==} emoji-regex@10.6.0: resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + empathic@2.0.0: resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} engines: {node: '>=14'} @@ -1198,8 +1304,8 @@ packages: es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} - esbuild@0.25.12: - resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + esbuild@0.27.2: + resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} engines: {node: '>=18'} hasBin: true @@ -1259,20 +1365,20 @@ packages: eslint-import-resolver-node: optional: true - eslint-plugin-jsdoc@61.4.1: - resolution: {integrity: sha512-3c1QW/bV25sJ1MsIvsvW+EtLtN6yZMduw7LVQNVt72y2/5BbV5Pg5b//TE5T48LRUxoEQGaZJejCmcj3wCxBzw==} - engines: {node: '>=20.11.0'} + eslint-plugin-jsdoc@62.5.0: + resolution: {integrity: sha512-D+1haMVDzW/ZMoPwOnsbXCK07rJtsq98Z1v+ApvDKxSzYTTcPgmFc/nyUDCGmxm2cP7g7hszyjYHO7Zodl/43w==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} peerDependencies: eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 - eslint-plugin-perfectionist@4.15.1: - resolution: {integrity: sha512-MHF0cBoOG0XyBf7G0EAFCuJJu4I18wy0zAoT1OHfx2o6EOx1EFTIzr2HGeuZa1kDcusoX0xJ9V7oZmaeFd773Q==} - engines: {node: ^18.0.0 || >=20.0.0} + eslint-plugin-perfectionist@5.4.0: + resolution: {integrity: sha512-XxpUMpeVaSJF5rpF6NHmhj3xavHZrflKcRbDssAUWrHUU/+l3l7PPYnVJ6IOpR2KjQ1Blucaeb0cFL3LIBis0A==} + engines: {node: ^20.0.0 || >=22.0.0} peerDependencies: eslint: '>=8.45.0' - eslint-plugin-sonarjs@3.0.5: - resolution: {integrity: sha512-dI62Ff3zMezUToi161hs2i1HX1ie8Ia2hO0jtNBfdgRBicAG4ydy2WPt0rMTrAe3ZrlqhpAO3w1jcQEdneYoFA==} + eslint-plugin-sonarjs@3.0.6: + resolution: {integrity: sha512-3mVUqsAUSylGfkJMj2v0aC2Cu/eUunDLm+XMjLf0uLjAZao205NWF3g6EXxcCAFO+rCZiQ6Or1WQkUcU9/sKFQ==} peerDependencies: eslint: ^8.0.0 || ^9.0.0 @@ -1294,8 +1400,12 @@ packages: resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.39.1: - resolution: {integrity: sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==} + eslint-visitor-keys@5.0.0: + resolution: {integrity: sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint@9.39.2: + resolution: {integrity: sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -1308,13 +1418,17 @@ packages: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + espree@11.1.0: + resolution: {integrity: sha512-WFWYhO1fV4iYkqOOvq8FbqIhr2pYfoDY0kCotMkDeNtGpiGGkZ1iov2u8ydjtgM8yF8rzK7oaTbw2NAzbAbehw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} hasBin: true - esquery@1.6.0: - resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} engines: {node: '>=0.10'} esrecurse@4.3.0: @@ -1332,11 +1446,11 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} - eventemitter3@5.0.1: - resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + eventemitter3@5.0.4: + resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} - expect-type@1.2.2: - resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} extendable-error@0.1.7: @@ -1355,8 +1469,8 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fastq@1.19.1: - resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} @@ -1374,6 +1488,9 @@ packages: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} + filelist@1.0.4: + resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -1417,8 +1534,12 @@ packages: resolution: {integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==} engines: {node: '>=18'} - get-tsconfig@4.13.0: - resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + + get-tsconfig@4.13.1: + resolution: {integrity: sha512-EoY1N2xCn44xU6750Sx7OjOIT59FkmstNc3X6y5xpz7D5cBtZRe/3pSlTkDJgqsOk3WwZPkWfonhhUJfttQo3w==} glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} @@ -1443,15 +1564,12 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - hookable@5.5.3: - resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + hookable@6.0.1: + resolution: {integrity: sha512-uKGyY8BuzN/a5gvzvA+3FVWo0+wUjgtfSdnmjtrOVwQCZPHpHDH2WRO3VZSOeluYrHoDCiXFffZXs8Dj1ULWtw==} html-entities@2.6.0: resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==} @@ -1468,8 +1586,8 @@ packages: engines: {node: '>=18'} hasBin: true - iconv-lite@0.7.0: - resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==} + iconv-lite@0.7.2: + resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} engines: {node: '>=0.10.0'} ignore@5.3.2: @@ -1484,14 +1602,18 @@ packages: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} - import-without-cache@0.2.2: - resolution: {integrity: sha512-4TTuRrZ0jBULXzac3EoX9ZviOs8Wn9iAbNhJEyLhTpAGF9eNmYSruaMMN/Tec/yqaO7H6yS2kALfQDJ5FxfatA==} + import-without-cache@0.2.5: + resolution: {integrity: sha512-B6Lc2s6yApwnD2/pMzFh/d5AVjdsDXjgkeJ766FmFuJELIGHNycKRj+l3A39yZPM4CchqNCB4RITEAYB1KUM6A==} engines: {node: '>=20.19.0'} imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + indent-string@5.0.0: resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} engines: {node: '>=12'} @@ -1503,10 +1625,19 @@ packages: is-bun-module@2.0.0: resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==} + is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + is-fullwidth-code-point@5.1.0: resolution: {integrity: sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==} engines: {node: '>=18'} @@ -1527,6 +1658,10 @@ packages: resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} engines: {node: '>=0.10.0'} + is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -1542,20 +1677,17 @@ packages: resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} engines: {node: '>=10'} - istanbul-lib-source-maps@5.0.6: - resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} - engines: {node: '>=10'} - istanbul-reports@3.2.0: resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} engines: {node: '>=8'} - jiti@2.6.1: - resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + jake@10.9.4: + resolution: {integrity: sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==} + engines: {node: '>=10'} hasBin: true - js-tokens@9.0.1: - resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + js-tokens@10.0.0: + resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} js-yaml@3.14.2: resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} @@ -1565,8 +1697,8 @@ packages: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true - jsdoc-type-pratt-parser@6.10.0: - resolution: {integrity: sha512-+LexoTRyYui5iOhJGn13N9ZazL23nAHGkXsa1p/C8yeq79WRfLBag6ZZ0FQG2aRoc9yfo59JT9EYCQonOkHKkQ==} + jsdoc-type-pratt-parser@7.1.0: + resolution: {integrity: sha512-SX7q7XyCwzM/MEDCYz0l8GgGbJAACGFII9+WfNYr5SLEKukHWRy2Jk3iWRe7P+lpYJNs7oQ+OSei4JtKGUjd7A==} engines: {node: '>=20.0.0'} jsesc@3.1.0: @@ -1597,14 +1729,18 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - ky@1.14.0: - resolution: {integrity: sha512-Rczb6FMM6JT0lvrOlP5WUOCB7s9XKxzwgErzhKlKde1bEV90FXplV1o87fpt4PU/asJFiqjYJxAJyzJhcrxOsQ==} + ky@1.14.3: + resolution: {integrity: sha512-9zy9lkjac+TR1c2tG+mkNSVlyOpInnWdSMiue4F+kq8TwJSgv6o8jhLRg8Ho6SnZ9wOYUq/yozts9qQCfk7bIw==} engines: {node: '>=18'} levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + linkify-it@5.0.0: resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} @@ -1675,15 +1811,23 @@ packages: resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} engines: {node: 20 || >=22} + minimatch@10.1.2: + resolution: {integrity: sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw==} + engines: {node: 20 || >=22} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} - module-replacements@2.10.1: - resolution: {integrity: sha512-qkKuLpMHDqRSM676OPL7HUpCiiP3NSxgf8NNR1ga2h/iJLNKTsOSjMEwrcT85DMSti2vmOqxknOVBGWj6H6etQ==} + module-replacements@2.11.0: + resolution: {integrity: sha512-j5sNQm3VCpQQ7nTqGeOZtoJtV3uKERgCBm9QRhmGRiXiqkf7iRFOkfxdJRZWLkqYY8PNf4cDQF/WfXUYLENrRA==} mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} @@ -1839,8 +1983,8 @@ packages: engines: {node: '>=10.13.0'} hasBin: true - prettier@3.7.4: - resolution: {integrity: sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==} + prettier@3.8.1: + resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} engines: {node: '>=14'} hasBin: true @@ -1869,6 +2013,10 @@ packages: resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} engines: {node: '>=6'} + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + refa@0.12.1: resolution: {integrity: sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} @@ -1911,15 +2059,15 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - rolldown-plugin-dts@0.18.3: - resolution: {integrity: sha512-rd1LZ0Awwfyn89UndUF/HoFF4oH9a5j+2ZeuKSJYM80vmeN/p0gslYMnHTQHBEXPhUlvAlqGA3tVgXB/1qFNDg==} + rolldown-plugin-dts@0.21.9: + resolution: {integrity: sha512-macIh4TtSv84N33YcI8SbULUPbMOgwPHDLweUKgzb+LV2OrVzrXihb2pC33xR0Hoh+hz07Un9/EuUeqMiPsePw==} engines: {node: '>=20.19.0'} peerDependencies: '@ts-macro/tsc': ^0.3.6 '@typescript/native-preview': '>=7.0.0-dev.20250601.1' - rolldown: ^1.0.0-beta.51 + rolldown: ^1.0.0-beta.57 typescript: ^5.0.0 - vue-tsc: ~3.1.0 + vue-tsc: ~3.2.0 peerDependenciesMeta: '@ts-macro/tsc': optional: true @@ -1930,13 +2078,13 @@ packages: vue-tsc: optional: true - rolldown@1.0.0-beta.53: - resolution: {integrity: sha512-Qd9c2p0XKZdgT5AYd+KgAMggJ8ZmCs3JnS9PTMWkyUfteKlfmKtxJbWTHkVakxwXs1Ub7jrRYVeFeF7N0sQxyw==} + rolldown@1.0.0-rc.1: + resolution: {integrity: sha512-M3AeZjYE6UclblEf531Hch0WfVC/NOL43Cc+WdF3J50kk5/fvouHhDumSGTh0oRjbZ8C4faaVr5r6Nx1xMqDGg==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - rollup@4.53.3: - resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==} + rollup@4.57.1: + resolution: {integrity: sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -1950,11 +2098,6 @@ packages: resolution: {integrity: sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==} engines: {node: ^14.0.0 || >=16.0.0} - semver@7.7.2: - resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} - engines: {node: '>=10'} - hasBin: true - semver@7.7.3: resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} engines: {node: '>=10'} @@ -1983,10 +2126,17 @@ packages: resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} engines: {node: '>=18'} + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} + slash@5.1.0: + resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} + engines: {node: '>=14.16'} + slice-ansi@7.1.2: resolution: {integrity: sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==} engines: {node: '>=18'} @@ -2024,12 +2174,16 @@ packages: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} engines: {node: '>=0.6.19'} + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + string-width@7.2.0: resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} engines: {node: '>=18'} - string-width@8.1.0: - resolution: {integrity: sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==} + string-width@8.1.1: + resolution: {integrity: sha512-KpqHIdDL9KwYk22wEOg/VIqYbrnLeSApsKT/bSj6Ez7pn3CftUiLAv2Lccpq1ALcpLV9UX1Ppn92npZWu2w/aw==} engines: {node: '>=20'} strip-ansi@6.0.1: @@ -2056,10 +2210,77 @@ packages: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + term-size@2.2.1: resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} engines: {node: '>=8'} + text-camel-case@1.2.10: + resolution: {integrity: sha512-KNrWeZzQT+gh73V1LnmgTkjK7V+tMRjLCc6VrGwkqbiRdnGVIWBUgIvVnvnaVCxIvZ/2Ke8DCmgPirlQcCqD3Q==} + + text-capital-case@1.2.10: + resolution: {integrity: sha512-yvViUJKSSQcRO58je224bhPHg/Hij9MEY43zuKShtFzrPwW/fOAarUJ5UkTMSB81AOO1m8q+JiFdxMF4etKZbA==} + + text-case@1.2.10: + resolution: {integrity: sha512-5bY3Ks/u7OJ5YO69iyXrG5Xf2wUZeyko7U78nPUnYoSeuNeAfA5uAix5hTspfkl6smm3yCBObrex+kFvzeIcJg==} + + text-constant-case@1.2.10: + resolution: {integrity: sha512-/OfU798O2wrwKN9kQf71WhJeAlklGnbby0Tupp+Ez9NXymW+6oF9LWDRTkN+OreTmHucdvp4WQd6O5Rah5zj8A==} + + text-dot-case@1.2.10: + resolution: {integrity: sha512-vf4xguy5y6e39RlDZeWZFMDf2mNkR23VTSVb9e68dUSpfJscG9/1YWWpW3n8TinzQxBZlsn5sT5olL33MvvQXw==} + + text-header-case@1.2.10: + resolution: {integrity: sha512-sVb1NY9bwxtu+Z7CVyWbr+I0AkWtF0kEHL/Zz5V2u/WdkjK5tKBwl5nXf0NGy9da4ZUYTBb+TmQpOIqihzvFMQ==} + + text-is-lower-case@1.2.10: + resolution: {integrity: sha512-dMTeTgrdWWfYf3fKxvjMkDPuXWv96cWbd1Uym6Zjv9H855S1uHxjkFsGbTYJ2tEK0NvAylRySTQlI6axlcMc4w==} + + text-is-upper-case@1.2.10: + resolution: {integrity: sha512-PGD/cXoXECGAY1HVZxDdmpJUW2ZUAKQ6DTamDfCHC9fc/z4epOz0pB/ThBnjJA3fz+d2ApkMjAfZDjuZFcodzg==} + + text-kebab-case@1.2.10: + resolution: {integrity: sha512-3XZJAApx5JQpUO7eXo7GQ2TyRcGw3OVbqxz6QJb2h+N8PbLLbz3zJVeXdGrhTkoUIbkSZ6PmHx6LRDaHXTdMcA==} + + text-lower-case-first@1.2.10: + resolution: {integrity: sha512-Oro84jZPDLD9alfdZWmtFHYTvCaaSz2o4thPtjMsK4GAkTyVg9juYXWj0y0YFyjLYGH69muWsBe4/MR5S7iolw==} + + text-lower-case@1.2.10: + resolution: {integrity: sha512-c9j5pIAN3ObAp1+4R7970e1bgtahTRF/5ZQdX2aJBuBngYTYZZIck0NwFXUKk5BnYpLGsre5KFHvpqvf4IYKgg==} + + text-no-case@1.2.10: + resolution: {integrity: sha512-4/m79pzQrywrwEG5lCULY1lQvFY+EKjhH9xSMT6caPK5plqzm9Y7rXyv+UXPd3s9qH6QODZnvsAYWW3M0JgxRA==} + + text-param-case@1.2.10: + resolution: {integrity: sha512-hkavcLsRRzZcGryPAshct1AwIOMj/FexYjMaLpGZCYYBn1lcZEeyMzJZPSckzkOYpq35LYSQr3xZto9XU5OAsw==} + + text-pascal-case@1.2.10: + resolution: {integrity: sha512-/kynZD8vTYOmm/RECjIDaz3qYEUZc/N/bnC79XuAFxwXjdNVjj/jGovKJLRzqsYK/39N22XpGcVmGg7yIrbk6w==} + + text-path-case@1.2.10: + resolution: {integrity: sha512-vbKdRCaVEeOaW6sm24QP9NbH7TS9S4ZQ3u19H8eylDox7m2HtFwYIBjAPv+v3z4I/+VjrMy9LB54lNP1uEqRHw==} + + text-sentence-case@1.2.10: + resolution: {integrity: sha512-NO4MRlbfxFhl9QgQLuCL4xHmvE7PUWHVPWsZxQ5nzRtDjXOUllWvtsvl8CP5tBEvBmzg0kwfflxfhRtr5vBQGg==} + + text-snake-case@1.2.10: + resolution: {integrity: sha512-6ttMZ+B9jkHKun908HYr4xSvEtlbfJJ4MvpQ06JEKRGhwjMI0x8t2Wywp+MEzN6142O6E/zKhra18KyBL6cvXA==} + + text-swap-case@1.2.10: + resolution: {integrity: sha512-vO3jwInIk0N77oEFakYZ2Hn/llTmRwf2c3RvkX/LfvmLWVp+3QcIc6bwUEtbqGQ5Xh2okjFhYrfkHZstVc3N4Q==} + + text-title-case@1.2.10: + resolution: {integrity: sha512-bqA+WWexUMWu9A3fdNar+3GXXW+c5xOvMyuK5hOx/w0AlqhyQptyCrMFjGB8Fd9dxbryBNmJ+5rWtC1OBDxlaA==} + + text-upper-case-first@1.2.10: + resolution: {integrity: sha512-VXs7j7BbpKwvolDh5fwpYRmMrUHGkxbY8E90fhBzKUoKfadvWmPT/jFieoZ4UPLzr208pXvQEFbb2zO9Qzs9Fg==} + + text-upper-case@1.2.10: + resolution: {integrity: sha512-L1AtZ8R+jtSMTq0Ffma9R4Rzbrc3iuYW89BmWFH41AwnDfRmEBlBOllm1ZivRLQ/6pEu2p+3XKBHx9fsMl2CWg==} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} @@ -2091,19 +2312,23 @@ packages: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true - ts-api-utils@2.1.0: - resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + ts-api-utils@2.4.0: + resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==} engines: {node: '>=18.12'} peerDependencies: typescript: '>=4.8.4' - tsdown@0.17.0: - resolution: {integrity: sha512-NPZRrlC51X9Bb55ZTDwrWges8Dm1niCvNA5AYw7aix6pfnDnB4WR0neG5RPq75xIodg3hqlQUzzyrX7n4dmnJg==} + ts-to-zod@5.1.0: + resolution: {integrity: sha512-giqqlvRHunlJqG9tBL/KAO3wWIVZGF//mZiWLKm/fdQnKnz4EN2mtiK5cugN9slytBkdMEXQIaLvMzIScbhhFw==} + hasBin: true + + tsdown@0.20.1: + resolution: {integrity: sha512-Wo1BzqNQVZ6SFQV8rjQBwMmNubO+yV3F+vp2WNTjEaS4S5CT1C1dHtUbeFMrCEasZpGy5w6TshpehNnfTe8QBQ==} engines: {node: '>=20.19.0'} hasBin: true peerDependencies: '@arethetypeswrong/core': ^0.18.1 - '@vitejs/devtools': ^0.0.0-alpha.18 + '@vitejs/devtools': '*' publint: ^0.3.0 typescript: ^5.0.0 unplugin-lightningcss: ^0.4.0 @@ -2122,62 +2347,80 @@ packages: unplugin-unused: optional: true + tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - turbo-darwin-64@2.6.3: - resolution: {integrity: sha512-BlJJDc1CQ7SK5Y5qnl7AzpkvKSnpkfPmnA+HeU/sgny3oHZckPV2776ebO2M33CYDSor7+8HQwaodY++IINhYg==} + tsutils@3.21.0: + resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} + engines: {node: '>= 6'} + peerDependencies: + typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + + tsx@4.21.0: + resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} + engines: {node: '>=18.0.0'} + hasBin: true + + turbo-darwin-64@2.8.2: + resolution: {integrity: sha512-sumREbxABHxrWIwlK67sZEaDRE7+BFSU8gZj8OK+X7dLpgW1vTjsHzTECB5m2qzWlXHRdueAk8sKv7wyHqv9jw==} cpu: [x64] os: [darwin] - turbo-darwin-arm64@2.6.3: - resolution: {integrity: sha512-MwVt7rBKiOK7zdYerenfCRTypefw4kZCue35IJga9CH1+S50+KTiCkT6LBqo0hHeoH2iKuI0ldTF2a0aB72z3w==} + turbo-darwin-arm64@2.8.2: + resolution: {integrity: sha512-J3zoDkf+k9yozdJmdNUOc9YfIoFs01Zm+GgNyfY8pU6siMWlPlgdt+3ezbIMeOns6CAQUzUcqo9awowykAS9Vw==} cpu: [arm64] os: [darwin] - turbo-linux-64@2.6.3: - resolution: {integrity: sha512-cqpcw+dXxbnPtNnzeeSyWprjmuFVpHJqKcs7Jym5oXlu/ZcovEASUIUZVN3OGEM6Y/OTyyw0z09tOHNt5yBAVg==} + turbo-linux-64@2.8.2: + resolution: {integrity: sha512-iVYUM+tyNAPd34HhMSjYWi7OSXnxnDhPjFKVvzSb7cZmQS6GlDSr7MALc5Wt/zn6/7jm1FuS7c5Wffg9WD2e1Q==} cpu: [x64] os: [linux] - turbo-linux-arm64@2.6.3: - resolution: {integrity: sha512-MterpZQmjXyr4uM7zOgFSFL3oRdNKeflY7nsjxJb2TklsYqiu3Z9pQ4zRVFFH8n0mLGna7MbQMZuKoWqqHb45w==} + turbo-linux-arm64@2.8.2: + resolution: {integrity: sha512-v7FJAHUhY2nSEE87mr5ZBO51GmsFKp0EmK2P6rO+vGimCPmnGlLNj1at/eVcnp/cHRDnJj8J+b3QHWdUzTPTkg==} cpu: [arm64] os: [linux] - turbo-windows-64@2.6.3: - resolution: {integrity: sha512-biDU70v9dLwnBdLf+daoDlNJVvqOOP8YEjqNipBHzgclbQlXbsi6Gqqelp5er81Qo3BiRgmTNx79oaZQTPb07Q==} + turbo-windows-64@2.8.2: + resolution: {integrity: sha512-d1X+U5JLhyAse0VXM0rpmu6iLbBTAvjwc7MX0PBkEaTz2aZQqOHBpQkkrxia7bZzRNbfXHbGSqY/vbE3GSFWzw==} cpu: [x64] os: [win32] - turbo-windows-arm64@2.6.3: - resolution: {integrity: sha512-dDHVKpSeukah3VsI/xMEKeTnV9V9cjlpFSUs4bmsUiLu3Yv2ENlgVEZv65wxbeE0bh0jjpmElDT+P1KaCxArQQ==} + turbo-windows-arm64@2.8.2: + resolution: {integrity: sha512-fMln07/l/5kscs79V0kTwdf17gkZW+E2iyqnzz691gLM7Jf6la0afd3IMsNtLzUh+dxKIFCswNiFVmHe8g+2jA==} cpu: [arm64] os: [win32] - turbo@2.6.3: - resolution: {integrity: sha512-bf6YKUv11l5Xfcmg76PyWoy/e2vbkkxFNBGJSnfdSXQC33ZiUfutYh6IXidc5MhsnrFkWfdNNLyaRk+kHMLlwA==} + turbo@2.8.2: + resolution: {integrity: sha512-biW/S5hENCcJ5vxxJszCozEKcXtwGK29vxXzNbdfY/0q7QpYTCoyKdj0e8k/ADA6qkqaKDJwgrrHbC8Vy6wszg==} hasBin: true type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + typedoc-github-theme@0.3.1: resolution: {integrity: sha512-j6PmkAGmf/MGCzYjQcUH6jS9djPsNl/IoTXooxC+MoeMkBhbmPyKJlpR6Lw12BLoe2OYpYA2J1KMktUJXp/8Sw==} engines: {node: '>=18.0.0'} peerDependencies: typedoc: ~0.28.0 - typedoc@0.28.15: - resolution: {integrity: sha512-mw2/2vTL7MlT+BVo43lOsufkkd2CJO4zeOSuWQQsiXoV2VuEn7f6IZp2jsUDPmBMABpgR0R5jlcJ2OGEFYmkyg==} + typedoc@0.28.16: + resolution: {integrity: sha512-x4xW77QC3i5DUFMBp0qjukOTnr/sSg+oEs86nB3LjDslvAmwe/PUGDWbe3GrIqt59oTqoXK5GRK9tAa0sYMiog==} engines: {node: '>= 18', pnpm: '>= 10'} hasBin: true peerDependencies: typescript: 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x - typescript-eslint@8.48.1: - resolution: {integrity: sha512-FbOKN1fqNoXp1hIl5KYpObVrp0mCn+CLgn479nmu2IsRMrx2vyv74MmsBLVlhg8qVwNFGbXSp8fh1zp8pEoC2A==} + typescript-eslint@8.54.0: + resolution: {integrity: sha512-CKsJ+g53QpsNPqbzUsfKVgd3Lny4yKZ1pP4qN3jdMOg/sisIDLGyDMezycquXLE5JsEU0wp3dGNdzig0/fmSVQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -2204,8 +2447,8 @@ packages: unrs-resolver@1.11.1: resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} - unrun@0.2.16: - resolution: {integrity: sha512-DBkjUpQv9AQs1464XWnWQ97RuxPCu+CImvQMPmqFeHoL2Bi6C1BGPacMuXVw4VMIfQewNJZWUxPt5envG90oUA==} + unrun@0.2.26: + resolution: {integrity: sha512-A3DQLBcDyTui4Hlaoojkldg+8x+CIR+tcSHY0wzW+CgB4X/DNyH58jJpXp1B/EkE+yG6tU8iH1mWsLtwFU3IQg==} engines: {node: '>=20.19.0'} hasBin: true peerDependencies: @@ -2214,8 +2457,8 @@ packages: synckit: optional: true - update-browserslist-db@1.2.2: - resolution: {integrity: sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==} + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -2223,8 +2466,8 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - vite@7.2.6: - resolution: {integrity: sha512-tI2l/nFHC5rLh7+5+o7QjKjSR04ivXDF4jcgV0f/bTQ+OJiITy5S6gaynVsEM+7RqzufMnVbIon6Sr5x1SDYaQ==} + vite@7.3.1: + resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -2263,18 +2506,18 @@ packages: yaml: optional: true - vitest@4.0.15: - resolution: {integrity: sha512-n1RxDp8UJm6N0IbJLQo+yzLZ2sQCDyl1o0LeugbPWf8+8Fttp29GghsQBjYJVmWq3gBFfe9Hs1spR44vovn2wA==} + vitest@4.0.18: + resolution: {integrity: sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.0.15 - '@vitest/browser-preview': 4.0.15 - '@vitest/browser-webdriverio': 4.0.15 - '@vitest/ui': 4.0.15 + '@vitest/browser-playwright': 4.0.18 + '@vitest/browser-preview': 4.0.18 + '@vitest/browser-webdriverio': 4.0.18 + '@vitest/ui': 4.0.18 happy-dom: '*' jsdom: '*' peerDependenciesMeta: @@ -2312,10 +2555,21 @@ packages: engines: {node: '>=8'} hasBin: true + widest-line@3.1.0: + resolution: {integrity: sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==} + engines: {node: '>=8'} + word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + wordwrap@1.0.0: + resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + wrap-ansi@9.0.2: resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} engines: {node: '>=18'} @@ -2329,34 +2583,48 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - zod@4.1.13: - resolution: {integrity: sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==} + zod@4.3.6: + resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} snapshots: - '@babel/generator@7.28.5': + '@babel/generator@8.0.0-rc.1': dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 + '@babel/parser': 8.0.0-rc.1 + '@babel/types': 8.0.0-rc.1 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 + '@types/jsesc': 2.5.1 jsesc: 3.1.0 '@babel/helper-string-parser@7.27.1': {} + '@babel/helper-string-parser@8.0.0-rc.1': {} + '@babel/helper-validator-identifier@7.28.5': {} - '@babel/parser@7.28.5': + '@babel/helper-validator-identifier@8.0.0-rc.1': {} + + '@babel/parser@7.29.0': dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.29.0 - '@babel/runtime@7.28.4': {} + '@babel/parser@8.0.0-rc.1': + dependencies: + '@babel/types': 8.0.0-rc.1 + + '@babel/runtime@7.28.6': {} - '@babel/types@7.28.5': + '@babel/types@7.29.0': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 + '@babel/types@8.0.0-rc.1': + dependencies: + '@babel/helper-string-parser': 8.0.0-rc.1 + '@babel/helper-validator-identifier': 8.0.0-rc.1 + '@bcoe/v8-coverage@1.0.2': {} '@changesets/apply-release-plan@7.0.14': @@ -2388,7 +2656,7 @@ snapshots: dependencies: '@changesets/types': 6.1.0 - '@changesets/cli@2.29.8(@types/node@24.10.1)': + '@changesets/cli@2.29.8(@types/node@24.10.10)': dependencies: '@changesets/apply-release-plan': 7.0.14 '@changesets/assemble-release-plan': 6.0.9 @@ -2404,7 +2672,7 @@ snapshots: '@changesets/should-skip-package': 0.1.2 '@changesets/types': 6.1.0 '@changesets/write': 0.4.0 - '@inquirer/external-editor': 1.0.3(@types/node@24.10.1) + '@inquirer/external-editor': 1.0.3(@types/node@24.10.10) '@manypkg/get-packages': 1.1.3 ansi-colors: 4.1.3 ci-info: 3.9.0 @@ -2503,13 +2771,24 @@ snapshots: human-id: 4.1.3 prettier: 2.8.8 - '@emnapi/core@1.7.1': + '@clack/core@1.0.0-alpha.4': + dependencies: + picocolors: 1.1.1 + sisteransi: 1.0.5 + + '@clack/prompts@1.0.0-alpha.4': + dependencies: + '@clack/core': 1.0.0-alpha.4 + picocolors: 1.1.1 + sisteransi: 1.0.5 + + '@emnapi/core@1.8.1': dependencies: '@emnapi/wasi-threads': 1.1.0 tslib: 2.8.1 optional: true - '@emnapi/runtime@1.7.1': + '@emnapi/runtime@1.8.1': dependencies: tslib: 2.8.1 optional: true @@ -2519,107 +2798,105 @@ snapshots: tslib: 2.8.1 optional: true - '@es-joy/jsdoccomment@0.76.0': + '@es-joy/jsdoccomment@0.83.0': dependencies: '@types/estree': 1.0.8 - '@typescript-eslint/types': 8.48.1 - comment-parser: 1.4.1 - esquery: 1.6.0 - jsdoc-type-pratt-parser: 6.10.0 + '@typescript-eslint/types': 8.54.0 + comment-parser: 1.4.5 + esquery: 1.7.0 + jsdoc-type-pratt-parser: 7.1.0 '@es-joy/resolve.exports@1.2.0': {} - '@esbuild/aix-ppc64@0.25.12': + '@esbuild/aix-ppc64@0.27.2': optional: true - '@esbuild/android-arm64@0.25.12': + '@esbuild/android-arm64@0.27.2': optional: true - '@esbuild/android-arm@0.25.12': + '@esbuild/android-arm@0.27.2': optional: true - '@esbuild/android-x64@0.25.12': + '@esbuild/android-x64@0.27.2': optional: true - '@esbuild/darwin-arm64@0.25.12': + '@esbuild/darwin-arm64@0.27.2': optional: true - '@esbuild/darwin-x64@0.25.12': + '@esbuild/darwin-x64@0.27.2': optional: true - '@esbuild/freebsd-arm64@0.25.12': + '@esbuild/freebsd-arm64@0.27.2': optional: true - '@esbuild/freebsd-x64@0.25.12': + '@esbuild/freebsd-x64@0.27.2': optional: true - '@esbuild/linux-arm64@0.25.12': + '@esbuild/linux-arm64@0.27.2': optional: true - '@esbuild/linux-arm@0.25.12': + '@esbuild/linux-arm@0.27.2': optional: true - '@esbuild/linux-ia32@0.25.12': + '@esbuild/linux-ia32@0.27.2': optional: true - '@esbuild/linux-loong64@0.25.12': + '@esbuild/linux-loong64@0.27.2': optional: true - '@esbuild/linux-mips64el@0.25.12': + '@esbuild/linux-mips64el@0.27.2': optional: true - '@esbuild/linux-ppc64@0.25.12': + '@esbuild/linux-ppc64@0.27.2': optional: true - '@esbuild/linux-riscv64@0.25.12': + '@esbuild/linux-riscv64@0.27.2': optional: true - '@esbuild/linux-s390x@0.25.12': + '@esbuild/linux-s390x@0.27.2': optional: true - '@esbuild/linux-x64@0.25.12': + '@esbuild/linux-x64@0.27.2': optional: true - '@esbuild/netbsd-arm64@0.25.12': + '@esbuild/netbsd-arm64@0.27.2': optional: true - '@esbuild/netbsd-x64@0.25.12': + '@esbuild/netbsd-x64@0.27.2': optional: true - '@esbuild/openbsd-arm64@0.25.12': + '@esbuild/openbsd-arm64@0.27.2': optional: true - '@esbuild/openbsd-x64@0.25.12': + '@esbuild/openbsd-x64@0.27.2': optional: true - '@esbuild/openharmony-arm64@0.25.12': + '@esbuild/openharmony-arm64@0.27.2': optional: true - '@esbuild/sunos-x64@0.25.12': + '@esbuild/sunos-x64@0.27.2': optional: true - '@esbuild/win32-arm64@0.25.12': + '@esbuild/win32-arm64@0.27.2': optional: true - '@esbuild/win32-ia32@0.25.12': + '@esbuild/win32-ia32@0.27.2': optional: true - '@esbuild/win32-x64@0.25.12': + '@esbuild/win32-x64@0.27.2': optional: true - '@eslint-community/eslint-utils@4.9.0(eslint@9.39.1(jiti@2.6.1))': + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2)': dependencies: - eslint: 9.39.1(jiti@2.6.1) + eslint: 9.39.2 eslint-visitor-keys: 3.4.3 - '@eslint-community/regexpp@4.12.1': {} - '@eslint-community/regexpp@4.12.2': {} '@eslint/config-array@0.21.1': dependencies: '@eslint/object-schema': 2.1.7 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -2635,7 +2912,7 @@ snapshots: '@eslint/eslintrc@3.3.3': dependencies: ajv: 6.12.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) espree: 10.4.0 globals: 14.0.0 ignore: 5.3.2 @@ -2646,7 +2923,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@9.39.1': {} + '@eslint/js@9.39.2': {} '@eslint/object-schema@2.1.7': {} @@ -2655,12 +2932,12 @@ snapshots: '@eslint/core': 0.17.0 levn: 0.4.1 - '@gerrit0/mini-shiki@3.19.0': + '@gerrit0/mini-shiki@3.22.0': dependencies: - '@shikijs/engine-oniguruma': 3.19.0 - '@shikijs/langs': 3.19.0 - '@shikijs/themes': 3.19.0 - '@shikijs/types': 3.19.0 + '@shikijs/engine-oniguruma': 3.22.0 + '@shikijs/langs': 3.22.0 + '@shikijs/themes': 3.22.0 + '@shikijs/types': 3.22.0 '@shikijs/vscode-textmate': 10.0.2 '@humanfs/core@0.19.1': {} @@ -2674,16 +2951,16 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} - '@inquirer/external-editor@1.0.3(@types/node@24.10.1)': + '@inquirer/external-editor@1.0.3(@types/node@24.10.10)': dependencies: chardet: 2.1.1 - iconv-lite: 0.7.0 + iconv-lite: 0.7.2 optionalDependencies: - '@types/node': 24.10.1 + '@types/node': 24.10.10 '@isaacs/balanced-match@4.0.1': {} - '@isaacs/brace-expansion@5.0.0': + '@isaacs/brace-expansion@5.0.1': dependencies: '@isaacs/balanced-match': 4.0.1 @@ -2703,14 +2980,14 @@ snapshots: '@manypkg/find-root@1.1.0': dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.28.6 '@types/node': 12.20.55 find-up: 4.1.0 fs-extra: 8.1.0 '@manypkg/get-packages@1.1.3': dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.28.6 '@changesets/types': 4.1.0 '@manypkg/find-root': 1.1.0 fs-extra: 8.1.0 @@ -2719,15 +2996,15 @@ snapshots: '@napi-rs/wasm-runtime@0.2.12': dependencies: - '@emnapi/core': 1.7.1 - '@emnapi/runtime': 1.7.1 + '@emnapi/core': 1.8.1 + '@emnapi/runtime': 1.8.1 '@tybys/wasm-util': 0.10.1 optional: true - '@napi-rs/wasm-runtime@1.1.0': + '@napi-rs/wasm-runtime@1.1.1': dependencies: - '@emnapi/core': 1.7.1 - '@emnapi/runtime': 1.7.1 + '@emnapi/core': 1.8.1 + '@emnapi/runtime': 1.8.1 '@tybys/wasm-util': 0.10.1 optional: true @@ -2741,164 +3018,192 @@ snapshots: '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.19.1 - - '@oxc-project/runtime@0.101.0': {} + fastq: 1.20.1 + + '@oclif/core@4.8.0': + dependencies: + ansi-escapes: 4.3.2 + ansis: 3.17.0 + clean-stack: 3.0.1 + cli-spinners: 2.9.2 + debug: 4.4.3(supports-color@8.1.1) + ejs: 3.1.10 + get-package-type: 0.1.0 + indent-string: 4.0.0 + is-wsl: 2.2.0 + lilconfig: 3.1.3 + minimatch: 9.0.5 + semver: 7.7.3 + string-width: 4.2.3 + supports-color: 8.1.1 + tinyglobby: 0.2.15 + widest-line: 3.1.0 + wordwrap: 1.0.0 + wrap-ansi: 7.0.0 - '@oxc-project/types@0.101.0': {} + '@oxc-project/types@0.110.0': {} '@polka/url@1.0.0-next.29': {} - '@putstack/eslint-config-typescript@4.11.0(@eslint/js@9.39.1)(@typescript-eslint/utils@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript-eslint@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(typescript@5.9.3)': + '@putstack/eslint-config-typescript@4.14.0(@eslint/js@9.39.2)(@typescript-eslint/utils@8.54.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(typescript-eslint@8.54.0(eslint@9.39.2)(typescript@5.9.3))(typescript@5.9.3)': dependencies: - '@eslint/js': 9.39.1 - '@typescript-eslint/utils': 8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.1(jiti@2.6.1) - eslint-import-resolver-typescript: 4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)) - eslint-plugin-de-morgan: 2.0.0(eslint@9.39.1(jiti@2.6.1)) + '@eslint/js': 9.39.2 + '@typescript-eslint/utils': 8.54.0(eslint@9.39.2)(typescript@5.9.3) + eslint: 9.39.2 + eslint-import-resolver-typescript: 4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.54.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2))(eslint@9.39.2) + eslint-plugin-de-morgan: 2.0.0(eslint@9.39.2) eslint-plugin-depend: 1.4.0 - eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)) - eslint-plugin-perfectionist: 4.15.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-sonarjs: 3.0.5(eslint@9.39.1(jiti@2.6.1)) - eslint-plugin-unicorn: 62.0.0(eslint@9.39.1(jiti@2.6.1)) + eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.54.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2) + eslint-plugin-perfectionist: 5.4.0(eslint@9.39.2)(typescript@5.9.3) + eslint-plugin-sonarjs: 3.0.6(eslint@9.39.2) + eslint-plugin-unicorn: 62.0.0(eslint@9.39.2) typescript: 5.9.3 - typescript-eslint: 8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + typescript-eslint: 8.54.0(eslint@9.39.2)(typescript@5.9.3) transitivePeerDependencies: - eslint-import-resolver-node - eslint-plugin-import - supports-color - '@putstack/prettier-config@2.0.0(prettier@3.7.4)': + '@putstack/prettier-config@2.0.0(prettier@3.8.1)': dependencies: - prettier: 3.7.4 + prettier: 3.8.1 '@quansync/fs@1.0.0': dependencies: quansync: 1.0.0 - '@rolldown/binding-android-arm64@1.0.0-beta.53': + '@rolldown/binding-android-arm64@1.0.0-rc.1': optional: true - '@rolldown/binding-darwin-arm64@1.0.0-beta.53': + '@rolldown/binding-darwin-arm64@1.0.0-rc.1': optional: true - '@rolldown/binding-darwin-x64@1.0.0-beta.53': + '@rolldown/binding-darwin-x64@1.0.0-rc.1': optional: true - '@rolldown/binding-freebsd-x64@1.0.0-beta.53': + '@rolldown/binding-freebsd-x64@1.0.0-rc.1': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.53': + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.1': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.53': + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.1': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.0-beta.53': + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.1': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.0-beta.53': + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.1': optional: true - '@rolldown/binding-linux-x64-musl@1.0.0-beta.53': + '@rolldown/binding-linux-x64-musl@1.0.0-rc.1': optional: true - '@rolldown/binding-openharmony-arm64@1.0.0-beta.53': + '@rolldown/binding-openharmony-arm64@1.0.0-rc.1': optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-beta.53': + '@rolldown/binding-wasm32-wasi@1.0.0-rc.1': dependencies: - '@napi-rs/wasm-runtime': 1.1.0 + '@napi-rs/wasm-runtime': 1.1.1 optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.53': + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.1': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.0-beta.53': + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.1': optional: true - '@rolldown/pluginutils@1.0.0-beta.53': {} + '@rolldown/pluginutils@1.0.0-rc.1': {} + + '@rollup/rollup-android-arm-eabi@4.57.1': + optional: true + + '@rollup/rollup-android-arm64@4.57.1': + optional: true - '@rollup/rollup-android-arm-eabi@4.53.3': + '@rollup/rollup-darwin-arm64@4.57.1': optional: true - '@rollup/rollup-android-arm64@4.53.3': + '@rollup/rollup-darwin-x64@4.57.1': optional: true - '@rollup/rollup-darwin-arm64@4.53.3': + '@rollup/rollup-freebsd-arm64@4.57.1': optional: true - '@rollup/rollup-darwin-x64@4.53.3': + '@rollup/rollup-freebsd-x64@4.57.1': optional: true - '@rollup/rollup-freebsd-arm64@4.53.3': + '@rollup/rollup-linux-arm-gnueabihf@4.57.1': optional: true - '@rollup/rollup-freebsd-x64@4.53.3': + '@rollup/rollup-linux-arm-musleabihf@4.57.1': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.53.3': + '@rollup/rollup-linux-arm64-gnu@4.57.1': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.53.3': + '@rollup/rollup-linux-arm64-musl@4.57.1': optional: true - '@rollup/rollup-linux-arm64-gnu@4.53.3': + '@rollup/rollup-linux-loong64-gnu@4.57.1': optional: true - '@rollup/rollup-linux-arm64-musl@4.53.3': + '@rollup/rollup-linux-loong64-musl@4.57.1': optional: true - '@rollup/rollup-linux-loong64-gnu@4.53.3': + '@rollup/rollup-linux-ppc64-gnu@4.57.1': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.53.3': + '@rollup/rollup-linux-ppc64-musl@4.57.1': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.53.3': + '@rollup/rollup-linux-riscv64-gnu@4.57.1': optional: true - '@rollup/rollup-linux-riscv64-musl@4.53.3': + '@rollup/rollup-linux-riscv64-musl@4.57.1': optional: true - '@rollup/rollup-linux-s390x-gnu@4.53.3': + '@rollup/rollup-linux-s390x-gnu@4.57.1': optional: true - '@rollup/rollup-linux-x64-gnu@4.53.3': + '@rollup/rollup-linux-x64-gnu@4.57.1': optional: true - '@rollup/rollup-linux-x64-musl@4.53.3': + '@rollup/rollup-linux-x64-musl@4.57.1': optional: true - '@rollup/rollup-openharmony-arm64@4.53.3': + '@rollup/rollup-openbsd-x64@4.57.1': optional: true - '@rollup/rollup-win32-arm64-msvc@4.53.3': + '@rollup/rollup-openharmony-arm64@4.57.1': optional: true - '@rollup/rollup-win32-ia32-msvc@4.53.3': + '@rollup/rollup-win32-arm64-msvc@4.57.1': optional: true - '@rollup/rollup-win32-x64-gnu@4.53.3': + '@rollup/rollup-win32-ia32-msvc@4.57.1': optional: true - '@rollup/rollup-win32-x64-msvc@4.53.3': + '@rollup/rollup-win32-x64-gnu@4.57.1': optional: true - '@shikijs/engine-oniguruma@3.19.0': + '@rollup/rollup-win32-x64-msvc@4.57.1': + optional: true + + '@shikijs/engine-oniguruma@3.22.0': dependencies: - '@shikijs/types': 3.19.0 + '@shikijs/types': 3.22.0 '@shikijs/vscode-textmate': 10.0.2 - '@shikijs/langs@3.19.0': + '@shikijs/langs@3.22.0': dependencies: - '@shikijs/types': 3.19.0 + '@shikijs/types': 3.22.0 - '@shikijs/themes@3.19.0': + '@shikijs/themes@3.22.0': dependencies: - '@shikijs/types': 3.19.0 + '@shikijs/types': 3.22.0 - '@shikijs/types@3.19.0': + '@shikijs/types@3.22.0': dependencies: '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.4 @@ -2907,7 +3212,7 @@ snapshots: '@sindresorhus/base62@1.0.0': {} - '@standard-schema/spec@1.0.0': {} + '@standard-schema/spec@1.1.0': {} '@tybys/wasm-util@0.10.1': dependencies: @@ -2927,108 +3232,116 @@ snapshots: dependencies: '@types/unist': 3.0.3 + '@types/jsesc@2.5.1': {} + '@types/json-schema@7.0.15': {} '@types/node@12.20.55': {} - '@types/node@24.10.1': + '@types/node@24.10.10': dependencies: undici-types: 7.16.0 '@types/unist@3.0.3': {} - '@typescript-eslint/eslint-plugin@8.48.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.48.1 - '@typescript-eslint/type-utils': 8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.48.1 - eslint: 9.39.1(jiti@2.6.1) - graphemer: 1.4.0 + '@typescript-eslint/parser': 8.54.0(eslint@9.39.2)(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.54.0 + '@typescript-eslint/type-utils': 8.54.0(eslint@9.39.2)(typescript@5.9.3) + '@typescript-eslint/utils': 8.54.0(eslint@9.39.2)(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.54.0 + eslint: 9.39.2 ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 2.1.0(typescript@5.9.3) + ts-api-utils: 2.4.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/parser@8.54.0(eslint@9.39.2)(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.48.1 - '@typescript-eslint/types': 8.48.1 - '@typescript-eslint/typescript-estree': 8.48.1(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.48.1 - debug: 4.4.3 - eslint: 9.39.1(jiti@2.6.1) + '@typescript-eslint/scope-manager': 8.54.0 + '@typescript-eslint/types': 8.54.0 + '@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.54.0 + debug: 4.4.3(supports-color@8.1.1) + eslint: 9.39.2 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.48.1(typescript@5.9.3)': + '@typescript-eslint/project-service@8.54.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.48.1(typescript@5.9.3) - '@typescript-eslint/types': 8.48.1 - debug: 4.4.3 + '@typescript-eslint/tsconfig-utils': 8.54.0(typescript@5.9.3) + '@typescript-eslint/types': 8.54.0 + debug: 4.4.3(supports-color@8.1.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.48.1': + '@typescript-eslint/scope-manager@8.54.0': dependencies: - '@typescript-eslint/types': 8.48.1 - '@typescript-eslint/visitor-keys': 8.48.1 + '@typescript-eslint/types': 8.54.0 + '@typescript-eslint/visitor-keys': 8.54.0 - '@typescript-eslint/tsconfig-utils@8.48.1(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.54.0(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.54.0(eslint@9.39.2)(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.48.1 - '@typescript-eslint/typescript-estree': 8.48.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - debug: 4.4.3 - eslint: 9.39.1(jiti@2.6.1) - ts-api-utils: 2.1.0(typescript@5.9.3) + '@typescript-eslint/types': 8.54.0 + '@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.54.0(eslint@9.39.2)(typescript@5.9.3) + debug: 4.4.3(supports-color@8.1.1) + eslint: 9.39.2 + ts-api-utils: 2.4.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.48.1': {} + '@typescript-eslint/types@8.54.0': {} - '@typescript-eslint/typescript-estree@8.48.1(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.54.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.48.1(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.48.1(typescript@5.9.3) - '@typescript-eslint/types': 8.48.1 - '@typescript-eslint/visitor-keys': 8.48.1 - debug: 4.4.3 + '@typescript-eslint/project-service': 8.54.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.54.0(typescript@5.9.3) + '@typescript-eslint/types': 8.54.0 + '@typescript-eslint/visitor-keys': 8.54.0 + debug: 4.4.3(supports-color@8.1.1) minimatch: 9.0.5 semver: 7.7.3 tinyglobby: 0.2.15 - ts-api-utils: 2.1.0(typescript@5.9.3) + ts-api-utils: 2.4.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/utils@8.54.0(eslint@9.39.2)(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.48.1 - '@typescript-eslint/types': 8.48.1 - '@typescript-eslint/typescript-estree': 8.48.1(typescript@5.9.3) - eslint: 9.39.1(jiti@2.6.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2) + '@typescript-eslint/scope-manager': 8.54.0 + '@typescript-eslint/types': 8.54.0 + '@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3) + eslint: 9.39.2 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.48.1': + '@typescript-eslint/visitor-keys@8.54.0': dependencies: - '@typescript-eslint/types': 8.48.1 + '@typescript-eslint/types': 8.54.0 eslint-visitor-keys: 4.2.1 + '@typescript/vfs@1.6.2(typescript@5.9.3)': + dependencies: + debug: 4.4.3(supports-color@8.1.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@unrs/resolver-binding-android-arm-eabi@1.11.1': optional: true @@ -3088,71 +3401,68 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true - '@vitest/coverage-v8@4.0.15(vitest@4.0.15)': + '@vitest/coverage-v8@4.0.18(vitest@4.0.18)': dependencies: '@bcoe/v8-coverage': 1.0.2 - '@vitest/utils': 4.0.15 - ast-v8-to-istanbul: 0.3.8 + '@vitest/utils': 4.0.18 + ast-v8-to-istanbul: 0.3.11 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 5.0.6 istanbul-reports: 3.2.0 magicast: 0.5.1 obug: 2.1.1 std-env: 3.10.0 tinyrainbow: 3.0.3 - vitest: 4.0.15(@types/node@24.10.1)(@vitest/ui@4.0.15)(jiti@2.6.1)(yaml@2.8.2) - transitivePeerDependencies: - - supports-color + vitest: 4.0.18(@types/node@24.10.10)(@vitest/ui@4.0.18)(tsx@4.21.0)(yaml@2.8.2) - '@vitest/expect@4.0.15': + '@vitest/expect@4.0.18': dependencies: - '@standard-schema/spec': 1.0.0 + '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.0.15 - '@vitest/utils': 4.0.15 - chai: 6.2.1 + '@vitest/spy': 4.0.18 + '@vitest/utils': 4.0.18 + chai: 6.2.2 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.15(vite@7.2.6(@types/node@24.10.1)(jiti@2.6.1)(yaml@2.8.2))': + '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@24.10.10)(tsx@4.21.0)(yaml@2.8.2))': dependencies: - '@vitest/spy': 4.0.15 + '@vitest/spy': 4.0.18 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.2.6(@types/node@24.10.1)(jiti@2.6.1)(yaml@2.8.2) + vite: 7.3.1(@types/node@24.10.10)(tsx@4.21.0)(yaml@2.8.2) - '@vitest/pretty-format@4.0.15': + '@vitest/pretty-format@4.0.18': dependencies: tinyrainbow: 3.0.3 - '@vitest/runner@4.0.15': + '@vitest/runner@4.0.18': dependencies: - '@vitest/utils': 4.0.15 + '@vitest/utils': 4.0.18 pathe: 2.0.3 - '@vitest/snapshot@4.0.15': + '@vitest/snapshot@4.0.18': dependencies: - '@vitest/pretty-format': 4.0.15 + '@vitest/pretty-format': 4.0.18 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.0.15': {} + '@vitest/spy@4.0.18': {} - '@vitest/ui@4.0.15(vitest@4.0.15)': + '@vitest/ui@4.0.18(vitest@4.0.18)': dependencies: - '@vitest/utils': 4.0.15 + '@vitest/utils': 4.0.18 fflate: 0.8.2 flatted: 3.3.3 pathe: 2.0.3 sirv: 3.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vitest: 4.0.15(@types/node@24.10.1)(@vitest/ui@4.0.15)(jiti@2.6.1)(yaml@2.8.2) + vitest: 4.0.18(@types/node@24.10.10)(@vitest/ui@4.0.18)(tsx@4.21.0)(yaml@2.8.2) - '@vitest/utils@4.0.15': + '@vitest/utils@4.0.18': dependencies: - '@vitest/pretty-format': 4.0.15 + '@vitest/pretty-format': 4.0.18 tinyrainbow: 3.0.3 acorn-jsx@5.3.2(acorn@8.15.0): @@ -3170,6 +3480,10 @@ snapshots: ansi-colors@4.1.3: {} + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + ansi-escapes@7.2.0: dependencies: environment: 1.1.0 @@ -3184,6 +3498,8 @@ snapshots: ansi-styles@6.2.3: {} + ansis@3.17.0: {} + ansis@4.2.0: {} are-docs-informative@0.0.2: {} @@ -3198,26 +3514,29 @@ snapshots: assertion-error@2.0.1: {} - ast-kit@2.2.0: + ast-kit@3.0.0-beta.1: dependencies: - '@babel/parser': 7.28.5 + '@babel/parser': 8.0.0-rc.1 + estree-walker: 3.0.3 pathe: 2.0.3 - ast-v8-to-istanbul@0.3.8: + ast-v8-to-istanbul@0.3.11: dependencies: '@jridgewell/trace-mapping': 0.3.31 estree-walker: 3.0.3 - js-tokens: 9.0.1 + js-tokens: 10.0.0 + + async@3.2.6: {} balanced-match@1.0.2: {} - baseline-browser-mapping@2.9.2: {} + baseline-browser-mapping@2.9.19: {} better-path-resolve@1.0.0: dependencies: is-windows: 1.0.2 - birpc@3.0.0: {} + birpc@4.0.0: {} brace-expansion@1.1.12: dependencies: @@ -3234,11 +3553,11 @@ snapshots: browserslist@4.28.1: dependencies: - baseline-browser-mapping: 2.9.2 - caniuse-lite: 1.0.30001759 - electron-to-chromium: 1.5.266 + baseline-browser-mapping: 2.9.19 + caniuse-lite: 1.0.30001767 + electron-to-chromium: 1.5.286 node-releases: 2.0.27 - update-browserslist-db: 1.2.2(browserslist@4.28.1) + update-browserslist-db: 1.2.3(browserslist@4.28.1) builtin-modules@3.3.0: {} @@ -3250,9 +3569,9 @@ snapshots: callsites@3.1.0: {} - caniuse-lite@1.0.30001759: {} + caniuse-lite@1.0.30001767: {} - chai@6.2.1: {} + chai@6.2.2: {} chalk@4.1.2: dependencies: @@ -3263,22 +3582,32 @@ snapshots: chardet@2.1.1: {} + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + ci-info@3.9.0: {} - ci-info@4.3.1: {} + ci-info@4.4.0: {} clean-regexp@1.0.0: dependencies: escape-string-regexp: 1.0.5 + clean-stack@3.0.1: + dependencies: + escape-string-regexp: 4.0.0 + cli-cursor@5.0.0: dependencies: restore-cursor: 5.1.0 + cli-spinners@2.9.2: {} + cli-truncate@5.1.1: dependencies: slice-ansi: 7.1.2 - string-width: 8.1.0 + string-width: 8.1.1 color-convert@2.0.1: dependencies: @@ -3288,13 +3617,13 @@ snapshots: colorette@2.0.20: {} - commander@14.0.2: {} + commander@14.0.3: {} - comment-parser@1.4.1: {} + comment-parser@1.4.5: {} concat-map@0.0.1: {} - core-js-compat@3.47.0: + core-js-compat@3.48.0: dependencies: browserslist: 4.28.1 @@ -3304,12 +3633,16 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - debug@4.4.3: + debug@4.4.3(supports-color@8.1.1): dependencies: ms: 2.1.3 + optionalDependencies: + supports-color: 8.1.1 deep-is@0.1.4: {} + defu@6.1.4: {} + detect-indent@6.1.0: {} dir-glob@3.0.1: @@ -3318,10 +3651,16 @@ snapshots: dts-resolver@2.1.3: {} - electron-to-chromium@1.5.266: {} + ejs@3.1.10: + dependencies: + jake: 10.9.4 + + electron-to-chromium@1.5.286: {} emoji-regex@10.6.0: {} + emoji-regex@8.0.0: {} + empathic@2.0.0: {} enquirer@2.4.1: @@ -3335,34 +3674,34 @@ snapshots: es-module-lexer@1.7.0: {} - esbuild@0.25.12: + esbuild@0.27.2: optionalDependencies: - '@esbuild/aix-ppc64': 0.25.12 - '@esbuild/android-arm': 0.25.12 - '@esbuild/android-arm64': 0.25.12 - '@esbuild/android-x64': 0.25.12 - '@esbuild/darwin-arm64': 0.25.12 - '@esbuild/darwin-x64': 0.25.12 - '@esbuild/freebsd-arm64': 0.25.12 - '@esbuild/freebsd-x64': 0.25.12 - '@esbuild/linux-arm': 0.25.12 - '@esbuild/linux-arm64': 0.25.12 - '@esbuild/linux-ia32': 0.25.12 - '@esbuild/linux-loong64': 0.25.12 - '@esbuild/linux-mips64el': 0.25.12 - '@esbuild/linux-ppc64': 0.25.12 - '@esbuild/linux-riscv64': 0.25.12 - '@esbuild/linux-s390x': 0.25.12 - '@esbuild/linux-x64': 0.25.12 - '@esbuild/netbsd-arm64': 0.25.12 - '@esbuild/netbsd-x64': 0.25.12 - '@esbuild/openbsd-arm64': 0.25.12 - '@esbuild/openbsd-x64': 0.25.12 - '@esbuild/openharmony-arm64': 0.25.12 - '@esbuild/sunos-x64': 0.25.12 - '@esbuild/win32-arm64': 0.25.12 - '@esbuild/win32-ia32': 0.25.12 - '@esbuild/win32-x64': 0.25.12 + '@esbuild/aix-ppc64': 0.27.2 + '@esbuild/android-arm': 0.27.2 + '@esbuild/android-arm64': 0.27.2 + '@esbuild/android-x64': 0.27.2 + '@esbuild/darwin-arm64': 0.27.2 + '@esbuild/darwin-x64': 0.27.2 + '@esbuild/freebsd-arm64': 0.27.2 + '@esbuild/freebsd-x64': 0.27.2 + '@esbuild/linux-arm': 0.27.2 + '@esbuild/linux-arm64': 0.27.2 + '@esbuild/linux-ia32': 0.27.2 + '@esbuild/linux-loong64': 0.27.2 + '@esbuild/linux-mips64el': 0.27.2 + '@esbuild/linux-ppc64': 0.27.2 + '@esbuild/linux-riscv64': 0.27.2 + '@esbuild/linux-s390x': 0.27.2 + '@esbuild/linux-x64': 0.27.2 + '@esbuild/netbsd-arm64': 0.27.2 + '@esbuild/netbsd-x64': 0.27.2 + '@esbuild/openbsd-arm64': 0.27.2 + '@esbuild/openbsd-x64': 0.27.2 + '@esbuild/openharmony-arm64': 0.27.2 + '@esbuild/sunos-x64': 0.27.2 + '@esbuild/win32-arm64': 0.27.2 + '@esbuild/win32-ia32': 0.27.2 + '@esbuild/win32-x64': 0.27.2 escalade@3.2.0: {} @@ -3372,64 +3711,64 @@ snapshots: eslint-import-context@0.1.9(unrs-resolver@1.11.1): dependencies: - get-tsconfig: 4.13.0 + get-tsconfig: 4.13.1 stable-hash-x: 0.2.0 optionalDependencies: unrs-resolver: 1.11.1 - eslint-import-resolver-typescript@4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)): + eslint-import-resolver-typescript@4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.54.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2))(eslint@9.39.2): dependencies: - debug: 4.4.3 - eslint: 9.39.1(jiti@2.6.1) + debug: 4.4.3(supports-color@8.1.1) + eslint: 9.39.2 eslint-import-context: 0.1.9(unrs-resolver@1.11.1) - get-tsconfig: 4.13.0 + get-tsconfig: 4.13.1 is-bun-module: 2.0.0 stable-hash-x: 0.2.0 tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)) + eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.54.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2) transitivePeerDependencies: - supports-color - eslint-plugin-de-morgan@2.0.0(eslint@9.39.1(jiti@2.6.1)): + eslint-plugin-de-morgan@2.0.0(eslint@9.39.2): dependencies: - eslint: 9.39.1(jiti@2.6.1) + eslint: 9.39.2 eslint-plugin-depend@1.4.0: dependencies: empathic: 2.0.0 - module-replacements: 2.10.1 + module-replacements: 2.11.0 semver: 7.7.3 - eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)): + eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.54.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2): dependencies: - '@typescript-eslint/types': 8.48.1 - comment-parser: 1.4.1 - debug: 4.4.3 - eslint: 9.39.1(jiti@2.6.1) + '@typescript-eslint/types': 8.54.0 + comment-parser: 1.4.5 + debug: 4.4.3(supports-color@8.1.1) + eslint: 9.39.2 eslint-import-context: 0.1.9(unrs-resolver@1.11.1) is-glob: 4.0.3 - minimatch: 10.1.1 + minimatch: 10.1.2 semver: 7.7.3 stable-hash-x: 0.2.0 unrs-resolver: 1.11.1 optionalDependencies: - '@typescript-eslint/utils': 8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.54.0(eslint@9.39.2)(typescript@5.9.3) transitivePeerDependencies: - supports-color - eslint-plugin-jsdoc@61.4.1(eslint@9.39.1(jiti@2.6.1)): + eslint-plugin-jsdoc@62.5.0(eslint@9.39.2): dependencies: - '@es-joy/jsdoccomment': 0.76.0 + '@es-joy/jsdoccomment': 0.83.0 '@es-joy/resolve.exports': 1.2.0 are-docs-informative: 0.0.2 - comment-parser: 1.4.1 - debug: 4.4.3 + comment-parser: 1.4.5 + debug: 4.4.3(supports-color@8.1.1) escape-string-regexp: 4.0.0 - eslint: 9.39.1(jiti@2.6.1) - espree: 10.4.0 - esquery: 1.6.0 + eslint: 9.39.2 + espree: 11.1.0 + esquery: 1.7.0 html-entities: 2.6.0 object-deep-merge: 2.0.0 parse-imports-exports: 0.2.4 @@ -3439,41 +3778,40 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-perfectionist@4.15.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3): + eslint-plugin-perfectionist@5.4.0(eslint@9.39.2)(typescript@5.9.3): dependencies: - '@typescript-eslint/types': 8.48.1 - '@typescript-eslint/utils': 8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.1(jiti@2.6.1) + '@typescript-eslint/utils': 8.54.0(eslint@9.39.2)(typescript@5.9.3) + eslint: 9.39.2 natural-orderby: 5.0.0 transitivePeerDependencies: - supports-color - typescript - eslint-plugin-sonarjs@3.0.5(eslint@9.39.1(jiti@2.6.1)): + eslint-plugin-sonarjs@3.0.6(eslint@9.39.2): dependencies: - '@eslint-community/regexpp': 4.12.1 + '@eslint-community/regexpp': 4.12.2 builtin-modules: 3.3.0 bytes: 3.1.2 - eslint: 9.39.1(jiti@2.6.1) + eslint: 9.39.2 functional-red-black-tree: 1.0.1 jsx-ast-utils-x: 0.1.0 lodash.merge: 4.6.2 - minimatch: 9.0.5 + minimatch: 10.1.1 scslre: 0.3.0 - semver: 7.7.2 + semver: 7.7.3 typescript: 5.9.3 - eslint-plugin-unicorn@62.0.0(eslint@9.39.1(jiti@2.6.1)): + eslint-plugin-unicorn@62.0.0(eslint@9.39.2): dependencies: '@babel/helper-validator-identifier': 7.28.5 - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2) '@eslint/plugin-kit': 0.4.1 change-case: 5.4.4 - ci-info: 4.3.1 + ci-info: 4.4.0 clean-regexp: 1.0.0 - core-js-compat: 3.47.0 - eslint: 9.39.1(jiti@2.6.1) - esquery: 1.6.0 + core-js-compat: 3.48.0 + eslint: 9.39.2 + esquery: 1.7.0 find-up-simple: 1.0.1 globals: 16.5.0 indent-string: 5.0.0 @@ -3494,15 +3832,17 @@ snapshots: eslint-visitor-keys@4.2.1: {} - eslint@9.39.1(jiti@2.6.1): + eslint-visitor-keys@5.0.0: {} + + eslint@9.39.2: dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2) '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.21.1 '@eslint/config-helpers': 0.4.2 '@eslint/core': 0.17.0 '@eslint/eslintrc': 3.3.3 - '@eslint/js': 9.39.1 + '@eslint/js': 9.39.2 '@eslint/plugin-kit': 0.4.1 '@humanfs/node': 0.16.7 '@humanwhocodes/module-importer': 1.0.1 @@ -3511,12 +3851,12 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) escape-string-regexp: 4.0.0 eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 espree: 10.4.0 - esquery: 1.6.0 + esquery: 1.7.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 8.0.0 @@ -3530,8 +3870,6 @@ snapshots: minimatch: 3.1.2 natural-compare: 1.4.0 optionator: 0.9.4 - optionalDependencies: - jiti: 2.6.1 transitivePeerDependencies: - supports-color @@ -3541,9 +3879,15 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.15.0) eslint-visitor-keys: 4.2.1 + espree@11.1.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 5.0.0 + esprima@4.0.1: {} - esquery@1.6.0: + esquery@1.7.0: dependencies: estraverse: 5.3.0 @@ -3559,9 +3903,9 @@ snapshots: esutils@2.0.3: {} - eventemitter3@5.0.1: {} + eventemitter3@5.0.4: {} - expect-type@1.2.2: {} + expect-type@1.3.0: {} extendable-error@0.1.7: {} @@ -3579,7 +3923,7 @@ snapshots: fast-levenshtein@2.0.6: {} - fastq@1.19.1: + fastq@1.20.1: dependencies: reusify: 1.1.0 @@ -3593,6 +3937,10 @@ snapshots: dependencies: flat-cache: 4.0.1 + filelist@1.0.4: + dependencies: + minimatch: 5.1.6 + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -3635,7 +3983,9 @@ snapshots: get-east-asian-width@1.4.0: {} - get-tsconfig@4.13.0: + get-package-type@0.1.0: {} + + get-tsconfig@4.13.1: dependencies: resolve-pkg-maps: 1.0.0 @@ -3662,11 +4012,9 @@ snapshots: graceful-fs@4.2.11: {} - graphemer@1.4.0: {} - has-flag@4.0.0: {} - hookable@5.5.3: {} + hookable@6.0.1: {} html-entities@2.6.0: {} @@ -3676,7 +4024,7 @@ snapshots: husky@9.1.7: {} - iconv-lite@0.7.0: + iconv-lite@0.7.2: dependencies: safer-buffer: 2.1.2 @@ -3689,10 +4037,12 @@ snapshots: parent-module: 1.0.1 resolve-from: 4.0.0 - import-without-cache@0.2.2: {} + import-without-cache@0.2.5: {} imurmurhash@0.1.4: {} + indent-string@4.0.0: {} + indent-string@5.0.0: {} is-builtin-module@5.0.0: @@ -3703,8 +4053,12 @@ snapshots: dependencies: semver: 7.7.3 + is-docker@2.2.1: {} + is-extglob@2.1.1: {} + is-fullwidth-code-point@3.0.0: {} + is-fullwidth-code-point@5.1.0: dependencies: get-east-asian-width: 1.4.0 @@ -3721,6 +4075,10 @@ snapshots: is-windows@1.0.2: {} + is-wsl@2.2.0: + dependencies: + is-docker: 2.2.1 + isexe@2.0.0: {} isexe@3.1.1: {} @@ -3733,23 +4091,18 @@ snapshots: make-dir: 4.0.0 supports-color: 7.2.0 - istanbul-lib-source-maps@5.0.6: - dependencies: - '@jridgewell/trace-mapping': 0.3.31 - debug: 4.4.3 - istanbul-lib-coverage: 3.2.2 - transitivePeerDependencies: - - supports-color - istanbul-reports@3.2.0: dependencies: html-escaper: 2.0.2 istanbul-lib-report: 3.0.1 - jiti@2.6.1: - optional: true + jake@10.9.4: + dependencies: + async: 3.2.6 + filelist: 1.0.4 + picocolors: 1.1.1 - js-tokens@9.0.1: {} + js-tokens@10.0.0: {} js-yaml@3.14.2: dependencies: @@ -3760,7 +4113,7 @@ snapshots: dependencies: argparse: 2.0.1 - jsdoc-type-pratt-parser@6.10.0: {} + jsdoc-type-pratt-parser@7.1.0: {} jsesc@3.1.0: {} @@ -3782,20 +4135,22 @@ snapshots: dependencies: json-buffer: 3.0.1 - ky@1.14.0: {} + ky@1.14.3: {} levn@0.4.1: dependencies: prelude-ls: 1.2.1 type-check: 0.4.0 + lilconfig@3.1.3: {} + linkify-it@5.0.0: dependencies: uc.micro: 2.1.0 lint-staged@16.2.7: dependencies: - commander: 14.0.2 + commander: 14.0.3 listr2: 9.0.5 micromatch: 4.0.8 nano-spawn: 2.0.0 @@ -3807,7 +4162,7 @@ snapshots: dependencies: cli-truncate: 5.1.1 colorette: 2.0.20 - eventemitter3: 5.0.1 + eventemitter3: 5.0.4 log-update: 6.1.0 rfdc: 1.4.1 wrap-ansi: 9.0.2 @@ -3840,8 +4195,8 @@ snapshots: magicast@0.5.1: dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 source-map-js: 1.2.1 make-dir@4.0.0: @@ -3872,17 +4227,25 @@ snapshots: minimatch@10.1.1: dependencies: - '@isaacs/brace-expansion': 5.0.0 + '@isaacs/brace-expansion': 5.0.1 + + minimatch@10.1.2: + dependencies: + '@isaacs/brace-expansion': 5.0.1 minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 + minimatch@5.1.6: + dependencies: + brace-expansion: 2.0.2 + minimatch@9.0.5: dependencies: brace-expansion: 2.0.2 - module-replacements@2.10.1: {} + module-replacements@2.11.0: {} mri@1.2.0: {} @@ -4002,7 +4365,7 @@ snapshots: prettier@2.8.8: {} - prettier@3.7.4: {} + prettier@3.8.1: {} punycode.js@2.3.1: {} @@ -4026,13 +4389,15 @@ snapshots: pify: 4.0.1 strip-bom: 3.0.0 + readdirp@4.1.2: {} + refa@0.12.1: dependencies: - '@eslint-community/regexpp': 4.12.1 + '@eslint-community/regexpp': 4.12.2 regexp-ast-analysis@0.7.1: dependencies: - '@eslint-community/regexpp': 4.12.1 + '@eslint-community/regexpp': 4.12.2 refa: 0.12.1 regexp-tree@0.1.27: {} @@ -4058,68 +4423,70 @@ snapshots: rfdc@1.4.1: {} - rolldown-plugin-dts@0.18.3(rolldown@1.0.0-beta.53)(typescript@5.9.3): + rolldown-plugin-dts@0.21.9(rolldown@1.0.0-rc.1)(typescript@5.9.3): dependencies: - '@babel/generator': 7.28.5 - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 - ast-kit: 2.2.0 - birpc: 3.0.0 + '@babel/generator': 8.0.0-rc.1 + '@babel/parser': 8.0.0-rc.1 + '@babel/types': 8.0.0-rc.1 + ast-kit: 3.0.0-beta.1 + birpc: 4.0.0 dts-resolver: 2.1.3 - get-tsconfig: 4.13.0 - magic-string: 0.30.21 + get-tsconfig: 4.13.1 obug: 2.1.1 - rolldown: 1.0.0-beta.53 + rolldown: 1.0.0-rc.1 optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - oxc-resolver - rolldown@1.0.0-beta.53: + rolldown@1.0.0-rc.1: dependencies: - '@oxc-project/types': 0.101.0 - '@rolldown/pluginutils': 1.0.0-beta.53 + '@oxc-project/types': 0.110.0 + '@rolldown/pluginutils': 1.0.0-rc.1 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-beta.53 - '@rolldown/binding-darwin-arm64': 1.0.0-beta.53 - '@rolldown/binding-darwin-x64': 1.0.0-beta.53 - '@rolldown/binding-freebsd-x64': 1.0.0-beta.53 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.53 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.53 - '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.53 - '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.53 - '@rolldown/binding-linux-x64-musl': 1.0.0-beta.53 - '@rolldown/binding-openharmony-arm64': 1.0.0-beta.53 - '@rolldown/binding-wasm32-wasi': 1.0.0-beta.53 - '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.53 - '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.53 - - rollup@4.53.3: + '@rolldown/binding-android-arm64': 1.0.0-rc.1 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.1 + '@rolldown/binding-darwin-x64': 1.0.0-rc.1 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.1 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.1 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.1 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.1 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.1 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.1 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.1 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.1 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.1 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.1 + + rollup@4.57.1: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.53.3 - '@rollup/rollup-android-arm64': 4.53.3 - '@rollup/rollup-darwin-arm64': 4.53.3 - '@rollup/rollup-darwin-x64': 4.53.3 - '@rollup/rollup-freebsd-arm64': 4.53.3 - '@rollup/rollup-freebsd-x64': 4.53.3 - '@rollup/rollup-linux-arm-gnueabihf': 4.53.3 - '@rollup/rollup-linux-arm-musleabihf': 4.53.3 - '@rollup/rollup-linux-arm64-gnu': 4.53.3 - '@rollup/rollup-linux-arm64-musl': 4.53.3 - '@rollup/rollup-linux-loong64-gnu': 4.53.3 - '@rollup/rollup-linux-ppc64-gnu': 4.53.3 - '@rollup/rollup-linux-riscv64-gnu': 4.53.3 - '@rollup/rollup-linux-riscv64-musl': 4.53.3 - '@rollup/rollup-linux-s390x-gnu': 4.53.3 - '@rollup/rollup-linux-x64-gnu': 4.53.3 - '@rollup/rollup-linux-x64-musl': 4.53.3 - '@rollup/rollup-openharmony-arm64': 4.53.3 - '@rollup/rollup-win32-arm64-msvc': 4.53.3 - '@rollup/rollup-win32-ia32-msvc': 4.53.3 - '@rollup/rollup-win32-x64-gnu': 4.53.3 - '@rollup/rollup-win32-x64-msvc': 4.53.3 + '@rollup/rollup-android-arm-eabi': 4.57.1 + '@rollup/rollup-android-arm64': 4.57.1 + '@rollup/rollup-darwin-arm64': 4.57.1 + '@rollup/rollup-darwin-x64': 4.57.1 + '@rollup/rollup-freebsd-arm64': 4.57.1 + '@rollup/rollup-freebsd-x64': 4.57.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.57.1 + '@rollup/rollup-linux-arm-musleabihf': 4.57.1 + '@rollup/rollup-linux-arm64-gnu': 4.57.1 + '@rollup/rollup-linux-arm64-musl': 4.57.1 + '@rollup/rollup-linux-loong64-gnu': 4.57.1 + '@rollup/rollup-linux-loong64-musl': 4.57.1 + '@rollup/rollup-linux-ppc64-gnu': 4.57.1 + '@rollup/rollup-linux-ppc64-musl': 4.57.1 + '@rollup/rollup-linux-riscv64-gnu': 4.57.1 + '@rollup/rollup-linux-riscv64-musl': 4.57.1 + '@rollup/rollup-linux-s390x-gnu': 4.57.1 + '@rollup/rollup-linux-x64-gnu': 4.57.1 + '@rollup/rollup-linux-x64-musl': 4.57.1 + '@rollup/rollup-openbsd-x64': 4.57.1 + '@rollup/rollup-openharmony-arm64': 4.57.1 + '@rollup/rollup-win32-arm64-msvc': 4.57.1 + '@rollup/rollup-win32-ia32-msvc': 4.57.1 + '@rollup/rollup-win32-x64-gnu': 4.57.1 + '@rollup/rollup-win32-x64-msvc': 4.57.1 fsevents: 2.3.3 run-parallel@1.2.0: @@ -4130,12 +4497,10 @@ snapshots: scslre@0.3.0: dependencies: - '@eslint-community/regexpp': 4.12.1 + '@eslint-community/regexpp': 4.12.2 refa: 0.12.1 regexp-ast-analysis: 0.7.1 - semver@7.7.2: {} - semver@7.7.3: {} shebang-command@2.0.0: @@ -4156,8 +4521,12 @@ snapshots: mrmime: 2.0.1 totalist: 3.0.1 + sisteransi@1.0.5: {} + slash@3.0.0: {} + slash@5.1.0: {} + slice-ansi@7.1.2: dependencies: ansi-styles: 6.2.3 @@ -4189,13 +4558,19 @@ snapshots: string-argv@0.3.2: {} + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + string-width@7.2.0: dependencies: emoji-regex: 10.6.0 get-east-asian-width: 1.4.0 strip-ansi: 7.1.2 - string-width@8.1.0: + string-width@8.1.1: dependencies: get-east-asian-width: 1.4.0 strip-ansi: 7.1.2 @@ -4218,8 +4593,105 @@ snapshots: dependencies: has-flag: 4.0.0 + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + term-size@2.2.1: {} + text-camel-case@1.2.10: + dependencies: + text-pascal-case: 1.2.10 + + text-capital-case@1.2.10: + dependencies: + text-no-case: 1.2.10 + text-upper-case-first: 1.2.10 + + text-case@1.2.10: + dependencies: + text-camel-case: 1.2.10 + text-capital-case: 1.2.10 + text-constant-case: 1.2.10 + text-dot-case: 1.2.10 + text-header-case: 1.2.10 + text-is-lower-case: 1.2.10 + text-is-upper-case: 1.2.10 + text-kebab-case: 1.2.10 + text-lower-case: 1.2.10 + text-lower-case-first: 1.2.10 + text-no-case: 1.2.10 + text-param-case: 1.2.10 + text-pascal-case: 1.2.10 + text-path-case: 1.2.10 + text-sentence-case: 1.2.10 + text-snake-case: 1.2.10 + text-swap-case: 1.2.10 + text-title-case: 1.2.10 + text-upper-case: 1.2.10 + text-upper-case-first: 1.2.10 + + text-constant-case@1.2.10: + dependencies: + text-no-case: 1.2.10 + text-upper-case: 1.2.10 + + text-dot-case@1.2.10: + dependencies: + text-no-case: 1.2.10 + + text-header-case@1.2.10: + dependencies: + text-capital-case: 1.2.10 + + text-is-lower-case@1.2.10: {} + + text-is-upper-case@1.2.10: {} + + text-kebab-case@1.2.10: + dependencies: + text-no-case: 1.2.10 + + text-lower-case-first@1.2.10: {} + + text-lower-case@1.2.10: {} + + text-no-case@1.2.10: + dependencies: + text-lower-case: 1.2.10 + + text-param-case@1.2.10: + dependencies: + text-dot-case: 1.2.10 + + text-pascal-case@1.2.10: + dependencies: + text-no-case: 1.2.10 + + text-path-case@1.2.10: + dependencies: + text-dot-case: 1.2.10 + + text-sentence-case@1.2.10: + dependencies: + text-no-case: 1.2.10 + text-upper-case-first: 1.2.10 + + text-snake-case@1.2.10: + dependencies: + text-dot-case: 1.2.10 + + text-swap-case@1.2.10: {} + + text-title-case@1.2.10: + dependencies: + text-no-case: 1.2.10 + text-upper-case-first: 1.2.10 + + text-upper-case-first@1.2.10: {} + + text-upper-case@1.2.10: {} + tinybench@2.9.0: {} tinyexec@1.0.2: {} @@ -4244,26 +4716,44 @@ snapshots: tree-kill@1.2.2: {} - ts-api-utils@2.1.0(typescript@5.9.3): + ts-api-utils@2.4.0(typescript@5.9.3): dependencies: typescript: 5.9.3 - tsdown@0.17.0(typescript@5.9.3): + ts-to-zod@5.1.0: + dependencies: + '@clack/prompts': 1.0.0-alpha.4 + '@oclif/core': 4.8.0 + '@typescript/vfs': 1.6.2(typescript@5.9.3) + chokidar: 4.0.3 + listr2: 9.0.5 + slash: 5.1.0 + text-case: 1.2.10 + tslib: 2.8.1 + tsutils: 3.21.0(typescript@5.9.3) + typescript: 5.9.3 + zod: 4.3.6 + transitivePeerDependencies: + - supports-color + + tsdown@0.20.1(typescript@5.9.3): dependencies: ansis: 4.2.0 cac: 6.7.14 + defu: 6.1.4 empathic: 2.0.0 - hookable: 5.5.3 - import-without-cache: 0.2.2 + hookable: 6.0.1 + import-without-cache: 0.2.5 obug: 2.1.1 - rolldown: 1.0.0-beta.53 - rolldown-plugin-dts: 0.18.3(rolldown@1.0.0-beta.53)(typescript@5.9.3) + picomatch: 4.0.3 + rolldown: 1.0.0-rc.1 + rolldown-plugin-dts: 0.21.9(rolldown@1.0.0-rc.1)(typescript@5.9.3) semver: 7.7.3 tinyexec: 1.0.2 tinyglobby: 0.2.15 tree-kill: 1.2.2 unconfig-core: 7.4.2 - unrun: 0.2.16 + unrun: 0.2.26 optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -4273,60 +4763,75 @@ snapshots: - synckit - vue-tsc - tslib@2.8.1: - optional: true + tslib@1.14.1: {} + + tslib@2.8.1: {} + + tsutils@3.21.0(typescript@5.9.3): + dependencies: + tslib: 1.14.1 + typescript: 5.9.3 + + tsx@4.21.0: + dependencies: + esbuild: 0.27.2 + get-tsconfig: 4.13.1 + optionalDependencies: + fsevents: 2.3.3 - turbo-darwin-64@2.6.3: + turbo-darwin-64@2.8.2: optional: true - turbo-darwin-arm64@2.6.3: + turbo-darwin-arm64@2.8.2: optional: true - turbo-linux-64@2.6.3: + turbo-linux-64@2.8.2: optional: true - turbo-linux-arm64@2.6.3: + turbo-linux-arm64@2.8.2: optional: true - turbo-windows-64@2.6.3: + turbo-windows-64@2.8.2: optional: true - turbo-windows-arm64@2.6.3: + turbo-windows-arm64@2.8.2: optional: true - turbo@2.6.3: + turbo@2.8.2: optionalDependencies: - turbo-darwin-64: 2.6.3 - turbo-darwin-arm64: 2.6.3 - turbo-linux-64: 2.6.3 - turbo-linux-arm64: 2.6.3 - turbo-windows-64: 2.6.3 - turbo-windows-arm64: 2.6.3 + turbo-darwin-64: 2.8.2 + turbo-darwin-arm64: 2.8.2 + turbo-linux-64: 2.8.2 + turbo-linux-arm64: 2.8.2 + turbo-windows-64: 2.8.2 + turbo-windows-arm64: 2.8.2 type-check@0.4.0: dependencies: prelude-ls: 1.2.1 - typedoc-github-theme@0.3.1(typedoc@0.28.15(typescript@5.9.3)): + type-fest@0.21.3: {} + + typedoc-github-theme@0.3.1(typedoc@0.28.16(typescript@5.9.3)): dependencies: - typedoc: 0.28.15(typescript@5.9.3) + typedoc: 0.28.16(typescript@5.9.3) - typedoc@0.28.15(typescript@5.9.3): + typedoc@0.28.16(typescript@5.9.3): dependencies: - '@gerrit0/mini-shiki': 3.19.0 + '@gerrit0/mini-shiki': 3.22.0 lunr: 2.3.9 markdown-it: 14.1.0 minimatch: 9.0.5 typescript: 5.9.3 yaml: 2.8.2 - typescript-eslint@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3): + typescript-eslint@8.54.0(eslint@9.39.2)(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.48.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.48.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.1(jiti@2.6.1) + '@typescript-eslint/eslint-plugin': 8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(typescript@5.9.3) + '@typescript-eslint/parser': 8.54.0(eslint@9.39.2)(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.54.0(eslint@9.39.2)(typescript@5.9.3) + eslint: 9.39.2 typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -4368,12 +4873,11 @@ snapshots: '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 - unrun@0.2.16: + unrun@0.2.26: dependencies: - '@oxc-project/runtime': 0.101.0 - rolldown: 1.0.0-beta.53 + rolldown: 1.0.0-rc.1 - update-browserslist-db@1.2.2(browserslist@4.28.1): + update-browserslist-db@1.2.3(browserslist@4.28.1): dependencies: browserslist: 4.28.1 escalade: 3.2.0 @@ -4383,31 +4887,31 @@ snapshots: dependencies: punycode: 2.3.1 - vite@7.2.6(@types/node@24.10.1)(jiti@2.6.1)(yaml@2.8.2): + vite@7.3.1(@types/node@24.10.10)(tsx@4.21.0)(yaml@2.8.2): dependencies: - esbuild: 0.25.12 + esbuild: 0.27.2 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.53.3 + rollup: 4.57.1 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 24.10.1 + '@types/node': 24.10.10 fsevents: 2.3.3 - jiti: 2.6.1 + tsx: 4.21.0 yaml: 2.8.2 - vitest@4.0.15(@types/node@24.10.1)(@vitest/ui@4.0.15)(jiti@2.6.1)(yaml@2.8.2): + vitest@4.0.18(@types/node@24.10.10)(@vitest/ui@4.0.18)(tsx@4.21.0)(yaml@2.8.2): dependencies: - '@vitest/expect': 4.0.15 - '@vitest/mocker': 4.0.15(vite@7.2.6(@types/node@24.10.1)(jiti@2.6.1)(yaml@2.8.2)) - '@vitest/pretty-format': 4.0.15 - '@vitest/runner': 4.0.15 - '@vitest/snapshot': 4.0.15 - '@vitest/spy': 4.0.15 - '@vitest/utils': 4.0.15 + '@vitest/expect': 4.0.18 + '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@24.10.10)(tsx@4.21.0)(yaml@2.8.2)) + '@vitest/pretty-format': 4.0.18 + '@vitest/runner': 4.0.18 + '@vitest/snapshot': 4.0.18 + '@vitest/spy': 4.0.18 + '@vitest/utils': 4.0.18 es-module-lexer: 1.7.0 - expect-type: 1.2.2 + expect-type: 1.3.0 magic-string: 0.30.21 obug: 2.1.1 pathe: 2.0.3 @@ -4417,11 +4921,11 @@ snapshots: tinyexec: 1.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 7.2.6(@types/node@24.10.1)(jiti@2.6.1)(yaml@2.8.2) + vite: 7.3.1(@types/node@24.10.10)(tsx@4.21.0)(yaml@2.8.2) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 24.10.1 - '@vitest/ui': 4.0.15(vitest@4.0.15) + '@types/node': 24.10.10 + '@vitest/ui': 4.0.18(vitest@4.0.18) transitivePeerDependencies: - jiti - less @@ -4448,8 +4952,20 @@ snapshots: siginfo: 2.0.0 stackback: 0.0.2 + widest-line@3.1.0: + dependencies: + string-width: 4.2.3 + word-wrap@1.2.5: {} + wordwrap@1.0.0: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi@9.0.2: dependencies: ansi-styles: 6.2.3 @@ -4460,4 +4976,4 @@ snapshots: yocto-queue@0.1.0: {} - zod@4.1.13: {} + zod@4.3.6: {} diff --git a/scripts/generate-zod.ts b/scripts/generate-zod.ts new file mode 100644 index 00000000..16337e28 --- /dev/null +++ b/scripts/generate-zod.ts @@ -0,0 +1,117 @@ +#!/usr/bin/env node +/* eslint-disable sonarjs/cognitive-complexity */ +/* eslint-disable jsdoc/require-jsdoc */ +import { existsSync } from 'node:fs'; +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { generate } from 'ts-to-zod'; +import { inputOutputMappings } from './input-output-mapping'; + +const root = process.cwd(); +const packagesDirectory = path.join(root, 'packages'); + +// Maintain an explicit whitelist of packages to process. +const PACKAGE_WHITELIST = new Set(['classic-wow', 'core', 'd3', 'hs', 'sc2', 'wow']); +const HANDLE_ALL_FILE_FOLDERS = new Set(['core']); + +async function main() { + try { + await run(); + } catch (error) { + console.error(error); + process.exit(1); + } +} + +async function run(): Promise { + // Iterate packages/* and generate for each package that has a `src` folder + const packageEntries = await fs.readdir(packagesDirectory, { withFileTypes: true }); + for (const packageEntry of packageEntries) { + if (!packageEntry.isDirectory()) continue; + const packageName = packageEntry.name; + + // Only process packages listed in the whitelist + if (!PACKAGE_WHITELIST.has(packageName)) continue; + const packageSource = path.join(packagesDirectory, packageName, 'src'); + if (!existsSync(packageSource)) { + // no src for this package — skip + continue; + } + + console.log('Processing package', packageName); + + const allFiles = await walk(packageSource); + // For some packages, such as `core`, we want to generate from all `.ts` files (except `.test.ts`). + // For other packages, only convert `types.ts` files. + const tsFiles: Array = HANDLE_ALL_FILE_FOLDERS.has(packageName) + ? allFiles.filter((f) => f.endsWith('.ts') && !f.endsWith('.test.ts') && !f.endsWith('index.ts')) + : allFiles.filter((f) => path.basename(f) === 'types.ts'); + + const packageOut = path.join(root, 'generated', 'schemas', packageName); + // Clean package output + await fs.rm(packageOut, { force: true, recursive: true }); + await fs.mkdir(packageOut, { recursive: true }); + + for (const file of tsFiles) { + try { + const content = await fs.readFile(file, 'utf8'); + const generator = generate({ + inputOutputMappings, + keepComments: false, + skipParseJSDoc: false, + sourceText: content, + }); + + const schema = generator.getZodSchemasFile(file).replaceAll('z.object', 'z.strictObject'); + + if (generator.errors.length > 0) { + for (const error of generator.errors) { + console.error(error); + } + } + + const parentName = path.basename(path.dirname(file)); + // For the packages where we only handle `types.ts`, use the parent folder name as output file name. + // E.g. `packages/wow/src/character-hunter-pets/types.ts` -> `generated/wow/character-hunter-pets.ts` + // For other packages (like `core`), we use the original file name. + const outName = HANDLE_ALL_FILE_FOLDERS.has(packageName) ? path.basename(file) : `${parentName}.ts`; + const outPath = path.join(packageOut, outName); + await fs.writeFile(outPath, schema, 'utf8'); + } catch (error) { + console.error('Failed to generate for', file, (error as Error)?.message ?? error); + } + } + + // After generating all files for the package, write an `index.ts` that + // re-exports everything in the package output directory. + try { + const generatedFiles = await fs.readdir(packageOut); + const exportLines = generatedFiles + .filter((f) => f.endsWith('.ts') && f !== 'index.ts') + .map((f) => `export * from './${path.basename(f, '.ts')}';`); + + if (exportLines.length > 0) { + const indexContent = exportLines.join('\n') + '\n'; + await fs.writeFile(path.join(packageOut, 'index.ts'), indexContent, 'utf8'); + console.log('Wrote', path.relative(root, path.join(packageOut, 'index.ts'))); + } + } catch (error) { + console.error('Failed to write index.ts for', packageName, (error as Error)?.message ?? error); + } + } +} + +async function walk(directory: string, filelist: Array = []): Promise> { + const entries = await fs.readdir(directory, { withFileTypes: true }); + for (const entry of entries) { + const full = path.join(directory, entry.name); + if (entry.isDirectory()) { + await walk(full, filelist); + } else { + filelist.push(full); + } + } + return filelist; +} + +await main(); diff --git a/scripts/input-output-mapping.ts b/scripts/input-output-mapping.ts new file mode 100644 index 00000000..acab126e --- /dev/null +++ b/scripts/input-output-mapping.ts @@ -0,0 +1,9 @@ +import type { InputOutputMapping } from 'ts-to-zod/lib/config'; + +export const inputOutputMappings: Array = [ + //Core + { + input: '@blizzard-api/core', + output: '../core', + }, +]; diff --git a/tsconfig.json b/tsconfig.json index e5d99de5..f303bd88 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -47,5 +47,5 @@ //"composite": true, //"declarationMap": true, }, - "include": ["*.*ts", "*.*js", "packages/**/*"] + "include": ["*.*ts", "*.*js", "packages/**/*", "scripts/*", "generated/**/*"] }