mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 02:37:05 +02:00
feat: dailystats
This commit is contained in:
1 parent
f729aee3de
commit
e37a7947b4
18 files changed
+637
-153
No files matched your search
@@ -43,8 +43,5 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: yarn
|
||||
|
||||
- name: Install playwright
|
||||
run: npx playwright install
|
||||
|
||||
- name: Host
|
||||
run: yarn run start discord-token=${{ secrets.DISCORD_TOKEN }} wargaming-application-id=${{ secrets.WARGAMING_APPLICATION_ID }}
|
||||
@@ -1,2 +1,3 @@
|
||||
tasks:
|
||||
- init: yarn
|
||||
- command: npx playwright install && npx playwright install-deps
|
||||
@@ -5,6 +5,7 @@
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"install": "playwright install && playwright install-deps",
|
||||
"start": "vite-node src/index.ts --script",
|
||||
"lint": "tsc"
|
||||
},
|
||||
|
||||
+81
-78
@@ -1,7 +1,8 @@
|
||||
import { SlashCommandBuilder } from 'discord.js';
|
||||
import escapeHTML from 'escape-html';
|
||||
import GenericStats from '../components/GenericStats/index.js';
|
||||
import Screenshot from '../components/Screenshot.js';
|
||||
import NoBattlesInPeriod from '../components/NoBattlesInPeriod.js';
|
||||
import PoweredByBlitzStars from '../components/PoweredByBlitzStars.js';
|
||||
import TitleBar from '../components/TitleBar.js';
|
||||
import Wrapper from '../components/Wrapper.js';
|
||||
import { BLITZ_SERVERS } from '../constants/servers.js';
|
||||
@@ -12,8 +13,8 @@ import getBlitzStarsAccount from '../core/blitzstars/getBlitzStarsAccount.js';
|
||||
import cmdName from '../core/interaction/cmdName.js';
|
||||
import addUsernameOption from '../core/options/addUsernameOption.js';
|
||||
import { args } from '../core/process/args.js';
|
||||
import screenshotHTML from '../core/ui/screenshotHTML.js';
|
||||
import { CommandRegistry } from '../events/interactionCreate.js';
|
||||
import { browser } from '../index.js';
|
||||
import { AccountInfo, AllStats } from '../types/accountInfo.js';
|
||||
import { PlayerClanData } from '../types/playerClanData.js';
|
||||
import { BlitzStartsComputedPeriodicStatistics } from '../types/statistics.js';
|
||||
@@ -29,7 +30,7 @@ const periodNames: Record<Period, string> = {
|
||||
|
||||
export default {
|
||||
inProduction: true,
|
||||
inDevelopment: true,
|
||||
inDevelopment: false,
|
||||
inPublic: true,
|
||||
|
||||
command: new SlashCommandBuilder()
|
||||
@@ -72,8 +73,8 @@ export default {
|
||||
const a2 = accountInfo[id].statistics;
|
||||
const battles = a2.all.battles - a1.all.battles;
|
||||
|
||||
function pb(value: (allStats: AllStats) => number) {
|
||||
return (value(a2.all) - value(a1.all)) / battles;
|
||||
function max(value: (allStats: AllStats) => number) {
|
||||
return Math.max(value(a2.all), value(a1.all));
|
||||
}
|
||||
function diff(value: (allStats: AllStats) => number) {
|
||||
return value(a2.all) - value(a1.all);
|
||||
@@ -82,18 +83,16 @@ export default {
|
||||
stats = {
|
||||
all: {
|
||||
battles,
|
||||
capture_points: pb((a) => a.capture_points),
|
||||
damage_dealt: pb((a) => a.damage_dealt),
|
||||
damage_received: pb((a) => a.damage_received),
|
||||
capture_points: diff((a) => a.capture_points),
|
||||
damage_dealt: diff((a) => a.damage_dealt),
|
||||
damage_received: diff((a) => a.damage_received),
|
||||
dropped_capture_points: diff((a) => a.dropped_capture_points),
|
||||
frags: pb((a) => a.frags),
|
||||
frags8p: pb((a) => a.frags8p),
|
||||
frags: diff((a) => a.frags),
|
||||
frags8p: diff((a) => a.frags8p),
|
||||
hits: diff((a) => a.hits),
|
||||
losses: diff((a) => a.losses),
|
||||
max_frags: pb((a) => a.max_frags),
|
||||
max_frags_tank_id: pb((a) => a.max_frags_tank_id),
|
||||
max_xp: pb((a) => a.max_xp),
|
||||
max_xp_tank_id: pb((a) => a.max_xp_tank_id),
|
||||
max_frags: max((a) => a.max_frags),
|
||||
max_xp: max((a) => a.max_xp),
|
||||
shots: diff((a) => a.shots),
|
||||
spotted: diff((a) => a.spotted),
|
||||
survived_battles: diff((a) => a.survived_battles),
|
||||
@@ -113,73 +112,77 @@ export default {
|
||||
}
|
||||
if (!stats) return;
|
||||
|
||||
const page = await browser.newPage();
|
||||
await page.setViewportSize({ width: 640, height: 1 });
|
||||
await page.setContent(
|
||||
Screenshot(
|
||||
Wrapper(
|
||||
TitleBar(
|
||||
escapeHTML(blitzStarsAccount.nickname),
|
||||
clanData[id]?.clan
|
||||
? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clanData[id]?.clan?.emblem_set_id}.png`
|
||||
: 'https://i.imgur.com/uq6pKbh.png',
|
||||
clanData[id]?.clan ? `[${clanData[id]?.clan?.tag}]` : '',
|
||||
`${periodNames[period]} • ${new Date().toDateString()} • ${
|
||||
BLITZ_SERVERS[server]
|
||||
}`,
|
||||
),
|
||||
GenericStats([
|
||||
[
|
||||
'Winrate',
|
||||
`${(100 * (stats.all.wins / stats.all.battles)).toFixed(2)}%`,
|
||||
],
|
||||
['WN8', stats.wn8.toFixed(0)],
|
||||
[
|
||||
'Survival',
|
||||
`${(
|
||||
100 *
|
||||
(stats.all.survived_battles / stats.all.battles)
|
||||
).toFixed(2)}%`,
|
||||
],
|
||||
[
|
||||
'Accuracy',
|
||||
`${((stats.all.hits / stats.all.shots) * 100).toFixed(2)}%`,
|
||||
],
|
||||
['Battles', stats.all.battles],
|
||||
['Wins', stats.all.wins],
|
||||
['Losses', stats.all.losses],
|
||||
[
|
||||
'Average damage',
|
||||
(stats.all.damage_dealt / stats.all.battles).toFixed(0),
|
||||
],
|
||||
['Average XP', (stats.all.xp / stats.all.battles).toFixed(0)],
|
||||
['Average shots', (stats.all.shots / stats.all.battles).toFixed(2)],
|
||||
['Average hits', (stats.all.hits / stats.all.battles).toFixed(2)],
|
||||
['Average kills', (stats.all.frags / stats.all.battles).toFixed(2)],
|
||||
[
|
||||
'Average spots',
|
||||
(stats.all.spotted / stats.all.battles).toFixed(2),
|
||||
],
|
||||
['Average tier', stats.avg_tier.toFixed(2)],
|
||||
[
|
||||
'Damage ratio',
|
||||
(stats.all.damage_dealt / stats.all.damage_received).toFixed(2),
|
||||
],
|
||||
[
|
||||
'Kills to death ratio',
|
||||
(
|
||||
stats.all.frags /
|
||||
(stats.all.battles - stats.all.survived_battles)
|
||||
).toFixed(2),
|
||||
],
|
||||
]),
|
||||
const screenshot = await screenshotHTML(
|
||||
Wrapper(
|
||||
TitleBar(
|
||||
escapeHTML(blitzStarsAccount.nickname),
|
||||
clanData[id]?.clan ? `[${clanData[id]?.clan?.tag}]` : '',
|
||||
clanData[id]?.clan
|
||||
? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clanData[id]?.clan?.emblem_set_id}.png`
|
||||
: undefined,
|
||||
`${periodNames[period]} • ${new Date().toDateString()} • ${
|
||||
BLITZ_SERVERS[server]
|
||||
}`,
|
||||
),
|
||||
|
||||
stats.all.battles === 0
|
||||
? NoBattlesInPeriod()
|
||||
: GenericStats([
|
||||
[
|
||||
'Winrate',
|
||||
`${(100 * (stats.all.wins / stats.all.battles)).toFixed(2)}%`,
|
||||
],
|
||||
['WN8', stats.wn8.toFixed(0)],
|
||||
[
|
||||
'Survival',
|
||||
`${(
|
||||
100 *
|
||||
(stats.all.survived_battles / stats.all.battles)
|
||||
).toFixed(2)}%`,
|
||||
],
|
||||
[
|
||||
'Accuracy',
|
||||
`${((stats.all.hits / stats.all.shots) * 100).toFixed(2)}%`,
|
||||
],
|
||||
['Battles', stats.all.battles],
|
||||
['Wins', stats.all.wins],
|
||||
['Losses', stats.all.losses],
|
||||
[
|
||||
'Average damage',
|
||||
(stats.all.damage_dealt / stats.all.battles).toFixed(0),
|
||||
],
|
||||
['Average XP', (stats.all.xp / stats.all.battles).toFixed(0)],
|
||||
[
|
||||
'Average shots',
|
||||
(stats.all.shots / stats.all.battles).toFixed(2),
|
||||
],
|
||||
['Average hits', (stats.all.hits / stats.all.battles).toFixed(2)],
|
||||
[
|
||||
'Average kills',
|
||||
(stats.all.frags / stats.all.battles).toFixed(2),
|
||||
],
|
||||
[
|
||||
'Average spots',
|
||||
(stats.all.spotted / stats.all.battles).toFixed(2),
|
||||
],
|
||||
['Average tier', stats.avg_tier.toFixed(2)],
|
||||
[
|
||||
'Damage ratio',
|
||||
(stats.all.damage_dealt / stats.all.damage_received).toFixed(2),
|
||||
],
|
||||
[
|
||||
'Kills to death ratio',
|
||||
(
|
||||
stats.all.frags /
|
||||
(stats.all.battles - stats.all.survived_battles)
|
||||
).toFixed(2),
|
||||
],
|
||||
]),
|
||||
|
||||
PoweredByBlitzStars(),
|
||||
),
|
||||
);
|
||||
const screenshot = await page
|
||||
.locator('#screenshot')
|
||||
.screenshot({ omitBackground: true, scale: 'css' });
|
||||
await page.close();
|
||||
|
||||
await interaction.editReply({ files: [screenshot] });
|
||||
|
||||
console.log(`Showing stats for ${blitzStarsAccount.nickname}`);
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
import { SlashCommandBuilder } from 'discord.js';
|
||||
import escapeHTML from 'escape-html';
|
||||
import Breakdown from '../components/Breakdown.js';
|
||||
import NoBattlesInPeriod from '../components/NoBattlesInPeriod.js';
|
||||
import PoweredByBlitzStars from '../components/PoweredByBlitzStars.js';
|
||||
import TitleBar from '../components/TitleBar.js';
|
||||
import Wrapper from '../components/Wrapper.js';
|
||||
import { BLITZ_SERVERS } from '../constants/servers.js';
|
||||
import usernameAutocomplete from '../core/autocomplete/username.js';
|
||||
import getBlitzAccount from '../core/blitz/getBlitzAccount.js';
|
||||
import getWargamingResponse from '../core/blitz/getWargamingResponse.js';
|
||||
import getTankStatsOverTime from '../core/blitzstars/getTankStatsOverTime.js';
|
||||
import last5AM from '../core/blitzstars/last5AM.js';
|
||||
import { tankopedia } from '../core/blitzstars/tankopedia.js';
|
||||
import cmdName from '../core/interaction/cmdName.js';
|
||||
import addUsernameOption from '../core/options/addUsernameOption.js';
|
||||
import { args } from '../core/process/args.js';
|
||||
import screenshotHTML from '../core/ui/screenshotHTML.js';
|
||||
import { CommandRegistry } from '../events/interactionCreate.js';
|
||||
import { AccountInfo, AllStats } from '../types/accountInfo.js';
|
||||
import { PlayerClanData } from '../types/playerClanData.js';
|
||||
import { TanksStats } from '../types/tanksStats.js';
|
||||
import resolveTankName from '../utilities/resolveTankName.js';
|
||||
|
||||
export default {
|
||||
inProduction: true,
|
||||
inDevelopment: true,
|
||||
inPublic: true,
|
||||
|
||||
command: new SlashCommandBuilder()
|
||||
.setName(cmdName('today'))
|
||||
.setDescription('A general daily breakdown of your performance')
|
||||
.addStringOption(addUsernameOption),
|
||||
|
||||
async execute(interaction) {
|
||||
const username = interaction.options.getString('username')!;
|
||||
const blitzAccount = await getBlitzAccount(interaction, username);
|
||||
if (!blitzAccount) return;
|
||||
const { id, server } = blitzAccount;
|
||||
const tankStatsOverTime = await getTankStatsOverTime(
|
||||
server,
|
||||
id,
|
||||
last5AM().getTime() / 1000,
|
||||
new Date().getTime() / 1000,
|
||||
);
|
||||
if (!tankStatsOverTime) return;
|
||||
const accountInfo = await getWargamingResponse<AccountInfo>(
|
||||
`https://api.wotblitz.${server}/wotb/account/info/?application_id=${args['wargaming-application-id']}&account_id=${id}`,
|
||||
);
|
||||
if (!accountInfo) return;
|
||||
const clanData = await getWargamingResponse<PlayerClanData>(
|
||||
`https://api.wotblitz.${server}/wotb/clans/accountinfo/?application_id=${args['wargaming-application-id']}&account_id=${id}&extra=clan`,
|
||||
);
|
||||
if (!clanData) return;
|
||||
const careerTankStatsRaw = await getWargamingResponse<TanksStats>(
|
||||
`https://api.wotblitz.${server}/wotb/tanks/stats/?application_id=${args['wargaming-application-id']}&account_id=${id}`,
|
||||
);
|
||||
if (!careerTankStatsRaw) return;
|
||||
const careerStats: Record<number, AllStats> = {};
|
||||
|
||||
Object.entries(careerTankStatsRaw[id]).forEach(([, tankStats]) => {
|
||||
careerStats[tankStats.tank_id] = tankStats.all;
|
||||
});
|
||||
|
||||
const rows = Object.entries(tankStatsOverTime).map(
|
||||
([tankId, tankStats]) => {
|
||||
const career = careerStats[tankId as unknown as number];
|
||||
|
||||
return Breakdown.Row(
|
||||
resolveTankName({
|
||||
tank_id: tankId as unknown as number,
|
||||
name: tankopedia.data[tankId as unknown as number].name,
|
||||
}),
|
||||
tankStats.wins / tankStats.battles,
|
||||
career.wins / career.battles,
|
||||
-Infinity,
|
||||
-Infinity,
|
||||
tankStats.damage_dealt / tankStats.battles,
|
||||
career.damage_dealt / career.battles,
|
||||
(tankStats.battles - tankStats.survived_battles) / tankStats.battles,
|
||||
(career.battles - career.survived_battles) / career.battles,
|
||||
tankStats.battles,
|
||||
career.battles,
|
||||
tankopedia.data[tankId as unknown as number].images.normal,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
const screenshot = await screenshotHTML(
|
||||
Wrapper(
|
||||
TitleBar(
|
||||
escapeHTML(accountInfo[id].nickname),
|
||||
clanData[id]?.clan ? `[${clanData[id]?.clan?.tag}]` : '',
|
||||
clanData[id]?.clan
|
||||
? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clanData[id]?.clan?.emblem_set_id}.png`
|
||||
: undefined,
|
||||
`Today's breakdown • ${new Date().toDateString()} • ${
|
||||
BLITZ_SERVERS[server]
|
||||
}`,
|
||||
),
|
||||
|
||||
rows.length === 0 ? NoBattlesInPeriod() : Breakdown.Root(...rows),
|
||||
|
||||
PoweredByBlitzStars(),
|
||||
),
|
||||
);
|
||||
|
||||
await interaction.editReply({ files: [screenshot] });
|
||||
|
||||
console.log(`Showing daily breakdown for ${accountInfo[id].nickname}`);
|
||||
},
|
||||
|
||||
autocomplete: usernameAutocomplete,
|
||||
} satisfies CommandRegistry;
|
||||
@@ -0,0 +1,183 @@
|
||||
import Children from './Children.js';
|
||||
|
||||
const Breakdown = {
|
||||
Root(...children: string[]) {
|
||||
return `
|
||||
<style>
|
||||
.breakdown {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="breakdown">
|
||||
${Children(children)}
|
||||
</div>
|
||||
`;
|
||||
},
|
||||
|
||||
Row(
|
||||
name: string,
|
||||
winrate: number,
|
||||
careerWinrate: number,
|
||||
wn8: number,
|
||||
careerWn8: number,
|
||||
averageDamage: number,
|
||||
careerAverageDamage: number,
|
||||
survival: number,
|
||||
careerSurvival: number,
|
||||
battles: number,
|
||||
careerBattles: number,
|
||||
icon?: string,
|
||||
) {
|
||||
return `
|
||||
<style>
|
||||
.breakdown-row {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="breakdown-row">
|
||||
${this.RowDiscriminator(name, icon)}
|
||||
${this.RowStat(
|
||||
'Winrate',
|
||||
`${(winrate * 100).toFixed(2)}%`,
|
||||
`${(careerWinrate * 100).toFixed(2)}%`,
|
||||
winrate - careerWinrate,
|
||||
)}
|
||||
${this.RowStat(
|
||||
'Damage',
|
||||
averageDamage.toFixed(2),
|
||||
careerAverageDamage.toFixed(2),
|
||||
averageDamage - careerAverageDamage,
|
||||
)}
|
||||
${this.RowStat(
|
||||
'Survival',
|
||||
`${(survival * 100).toFixed(2)}%`,
|
||||
`${(careerSurvival * 100).toFixed(2)}%`,
|
||||
survival - careerSurvival,
|
||||
)}
|
||||
${this.RowStat('Battles', battles.toFixed(0), careerBattles.toFixed(0))}
|
||||
</div>
|
||||
`;
|
||||
|
||||
/*
|
||||
${this.RowStat(
|
||||
'WN8',
|
||||
wn8.toFixed(0),
|
||||
careerWn8.toFixed(0),
|
||||
wn8 - careerWn8,
|
||||
)}
|
||||
*/
|
||||
},
|
||||
|
||||
RowDiscriminator(name: string, icon?: string) {
|
||||
return `
|
||||
<style>
|
||||
.breakdown-row-discriminator {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
width: 0px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.breakdown-row-discriminator-icon {
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.breakdown-row-discriminator-name {
|
||||
color: #A0A0A0;
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="breakdown-row-discriminator">
|
||||
${
|
||||
icon
|
||||
? `<img src="${icon}" class="breakdown-row-discriminator-icon" />`
|
||||
: ''
|
||||
}
|
||||
<span class="breakdown-row-discriminator-name">${name}</span>
|
||||
</div>
|
||||
`;
|
||||
},
|
||||
|
||||
RowStat(name: string, value: string, career: string, delta?: number) {
|
||||
return `
|
||||
<style>
|
||||
.breakdown-row-stat {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.breakdown-row-stat-career {
|
||||
color: #A0A0A0;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.breakdown-row-stat-name {
|
||||
color: #A0A0A0;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.breakdown-row-stat-value {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.breakdown-row-stat-value-delta {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
.breakdown-row-stat-value-text {
|
||||
color: white;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="breakdown-row-stat">
|
||||
<span class="breakdown-row-stat-career">${career}</span>
|
||||
|
||||
<div class="breakdown-row-stat-value">
|
||||
${
|
||||
delta
|
||||
? `<img src="${
|
||||
(delta ?? 0) > 0
|
||||
? 'https://i.imgur.com/qbjiXa1.png'
|
||||
: 'https://i.imgur.com/3uyNhun.png'
|
||||
}" class="breakdown-row-stat-value-delta" />`
|
||||
: ''
|
||||
}
|
||||
|
||||
<span class="breakdown-row-stat-value-text">${value}</span>
|
||||
</div>
|
||||
|
||||
<span class="breakdown-row-stat-name">${name}</span>
|
||||
</div>
|
||||
`;
|
||||
},
|
||||
};
|
||||
|
||||
export default Breakdown;
|
||||
@@ -0,0 +1,20 @@
|
||||
export default function NoBattlesInPeriod() {
|
||||
return `
|
||||
<style>
|
||||
.no-battles-in-period {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.no-battles-in-period-text {
|
||||
font-size: 16px;
|
||||
color: #A0A0A0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="no-battles-in-period">
|
||||
<span class="no-battles-in-period-text">No battles played in this period</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
export default function PoweredByBlitzStars() {
|
||||
return `
|
||||
<style>
|
||||
.powered-by-blitz-stars {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.powered-by-blitz-stars-icon {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.powered-by-blitz-stars-text {
|
||||
font-size: 16px;
|
||||
color: #A0A0A0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="powered-by-blitz-stars">
|
||||
<img class="powered-by-blitz-stars-icon" src="https://www.blitzstars.com/assets/images/4b4cb591.TankyMcPewpew.png" />
|
||||
<span class="powered-by-blitz-stars-text">Powered by BlitzStars</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import Children from './Children.js';
|
||||
|
||||
export default function Screenshot(...children: string[]) {
|
||||
export default function Root(...children: string[]) {
|
||||
return `
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Roboto+Flex:[email protected]');
|
||||
@@ -14,12 +14,12 @@ export default function Screenshot(...children: string[]) {
|
||||
font-family: 'Roboto Flex', sans-serif;
|
||||
}
|
||||
|
||||
#screenshot {
|
||||
#root {
|
||||
display: flex;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="screenshot">
|
||||
<div id="root">
|
||||
${Children(children)}
|
||||
</div>
|
||||
`;
|
||||
@@ -1,8 +1,8 @@
|
||||
export default function TitleBar(
|
||||
name: string,
|
||||
image: string,
|
||||
nameDiscriminator = '',
|
||||
description = '',
|
||||
nameDiscriminator: string,
|
||||
image?: string,
|
||||
description?: string,
|
||||
) {
|
||||
return `
|
||||
<style>
|
||||
@@ -51,7 +51,7 @@ export default function TitleBar(
|
||||
|
||||
<div class="title-bar">
|
||||
<div class="title-bar-info">
|
||||
<img class="title-bar-avatar" src="${image}" />
|
||||
${image ? `<img class="title-bar-avatar" src="${image}" />` : ''}
|
||||
|
||||
<div class="title-bar-text">
|
||||
<span class="title-bar-name">
|
||||
|
||||
@@ -12,7 +12,9 @@ export default async function getWargamingResponse<Data extends object>(
|
||||
if (parsed.status === 'ok') {
|
||||
return parsed.data;
|
||||
} else {
|
||||
console.error(`Wargaming response status ${parsed.status}`);
|
||||
console.error(
|
||||
`Wargaming response status ${parsed.status} ${parsed.error.message}`,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
import fetch from 'node-fetch';
|
||||
import { BlitzServer } from '../../constants/servers.js';
|
||||
import { AllStats } from '../../types/accountInfo.js';
|
||||
import { TanksStats } from '../../types/tanksStats.js';
|
||||
import getWargamingResponse from '../blitz/getWargamingResponse.js';
|
||||
import { args } from '../process/args.js';
|
||||
|
||||
export interface TankHistoryNode {
|
||||
all: AllStats;
|
||||
last_battle_time: number;
|
||||
mark_of_mastery: number;
|
||||
battle_life_time: number;
|
||||
account_id: number;
|
||||
tank_id: number;
|
||||
}
|
||||
|
||||
export const emptyTankHistoryNode: TankHistoryNode = {
|
||||
account_id: 0,
|
||||
battle_life_time: 0,
|
||||
last_battle_time: 0,
|
||||
mark_of_mastery: 0,
|
||||
tank_id: 0,
|
||||
all: {
|
||||
battles: 0,
|
||||
capture_points: 0,
|
||||
damage_dealt: 0,
|
||||
damage_received: 0,
|
||||
dropped_capture_points: 0,
|
||||
frags: 0,
|
||||
frags8p: 0,
|
||||
hits: 0,
|
||||
losses: 0,
|
||||
max_frags: 0,
|
||||
max_xp: 0,
|
||||
shots: 0,
|
||||
spotted: 0,
|
||||
survived_battles: 0,
|
||||
xp: 0,
|
||||
win_and_survived: 0,
|
||||
wins: 0,
|
||||
},
|
||||
};
|
||||
|
||||
export type TankHistory = TankHistoryNode[];
|
||||
|
||||
export default async function getTankStatsOverTime(
|
||||
server: BlitzServer,
|
||||
id: number,
|
||||
start = -Infinity,
|
||||
end = Infinity,
|
||||
) {
|
||||
const latestTankStatsRaw = await getWargamingResponse<TanksStats>(
|
||||
`https://api.wotblitz.${server}/wotb/tanks/stats/?application_id=${args['wargaming-application-id']}&account_id=${id}`,
|
||||
);
|
||||
if (!latestTankStatsRaw) return;
|
||||
const tankHistoriesResponse = await fetch(
|
||||
`https://www.blitzstars.com/api/tankhistories/for/${id}/`,
|
||||
);
|
||||
const tankHistories = (await tankHistoriesResponse.json()) as TankHistory;
|
||||
const history = [...tankHistories, ...latestTankStatsRaw[id]];
|
||||
|
||||
// sort them even though most won't be used
|
||||
const tankSortedHistory: Record<number, TankHistory> = {};
|
||||
const tankIds: number[] = [];
|
||||
history.forEach((node) => {
|
||||
if (!tankSortedHistory[node.tank_id]) {
|
||||
tankSortedHistory[node.tank_id] = [node];
|
||||
tankIds.push(node.tank_id);
|
||||
} else {
|
||||
tankSortedHistory[node.tank_id].push(node);
|
||||
}
|
||||
});
|
||||
|
||||
// find the ones played within the range
|
||||
const tankIdsInRange = tankIds.filter((tankId) =>
|
||||
tankSortedHistory[tankId].some(
|
||||
(node) => node.last_battle_time > start && node.last_battle_time < end,
|
||||
),
|
||||
);
|
||||
|
||||
// fetch history node right before "start" and right before "end"
|
||||
const tanksBeforeAndAfter: Record<number, AllStats> = {};
|
||||
tankIdsInRange.forEach((tankId) => {
|
||||
const sortedHistory = tankSortedHistory[tankId];
|
||||
const previousIndex =
|
||||
sortedHistory.findIndex((node) => node.last_battle_time > start) - 1;
|
||||
const latestIndex =
|
||||
sortedHistory.findIndex((node) => node.last_battle_time > end) - 1;
|
||||
const previous = sortedHistory[previousIndex] ?? emptyTankHistoryNode;
|
||||
const latest =
|
||||
sortedHistory[latestIndex] ?? sortedHistory[sortedHistory.length - 1];
|
||||
|
||||
function diff(get: (allStats: AllStats) => number) {
|
||||
return get(latest.all) - get(previous.all);
|
||||
}
|
||||
function max(get: (allStats: AllStats) => number) {
|
||||
return Math.max(get(latest.all), get(previous.all));
|
||||
}
|
||||
|
||||
tanksBeforeAndAfter[tankId] = {
|
||||
battles: diff((a) => a.battles),
|
||||
capture_points: diff((a) => a.capture_points),
|
||||
damage_dealt: diff((a) => a.damage_dealt),
|
||||
damage_received: diff((a) => a.damage_received),
|
||||
dropped_capture_points: diff((a) => a.dropped_capture_points),
|
||||
frags: diff((a) => a.frags),
|
||||
frags8p: diff((a) => a.frags8p),
|
||||
hits: diff((a) => a.hits),
|
||||
losses: diff((a) => a.losses),
|
||||
max_frags: max((a) => a.max_frags),
|
||||
max_xp: max((a) => a.max_xp),
|
||||
shots: diff((a) => a.shots),
|
||||
spotted: diff((a) => a.spotted),
|
||||
survived_battles: diff((a) => a.survived_battles),
|
||||
win_and_survived: diff((a) => a.win_and_survived),
|
||||
wins: diff((a) => a.wins),
|
||||
xp: diff((a) => a.xp),
|
||||
};
|
||||
});
|
||||
|
||||
return tanksBeforeAndAfter;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
export default function last5AM() {
|
||||
const fiveAM = new Date();
|
||||
fiveAM.setHours(5, 0, 0, 0); // Set the time to 5:00 AM today
|
||||
|
||||
if (fiveAM > new Date()) {
|
||||
// If it's now before 5:00 AM, go back one day
|
||||
fiveAM.setDate(fiveAM.getDate() - 1);
|
||||
}
|
||||
|
||||
return fiveAM;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import Root from '../../components/Root.js';
|
||||
import { browser } from '../../index.js';
|
||||
|
||||
export default async function screenshotHTML(children: string) {
|
||||
const page = await browser.newPage();
|
||||
await page.setViewportSize({ width: 640, height: 1 });
|
||||
await page.setContent(Root(children));
|
||||
const screenshot = await page
|
||||
.locator('#root')
|
||||
.screenshot({ omitBackground: true, scale: 'css' });
|
||||
await page.close();
|
||||
|
||||
return screenshot;
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
export interface AllStats {
|
||||
spotted: number;
|
||||
max_frags_tank_id: number;
|
||||
hits: number;
|
||||
frags: number;
|
||||
max_xp: number;
|
||||
max_xp_tank_id: number;
|
||||
wins: number;
|
||||
losses: number;
|
||||
capture_points: number;
|
||||
|
||||
+17
-31
@@ -1,33 +1,19 @@
|
||||
import { AllStats } from './accountInfo.js';
|
||||
|
||||
export interface IndividualTankStats {
|
||||
all: AllStats;
|
||||
last_battle_time: number;
|
||||
account_id: number;
|
||||
max_xp: number;
|
||||
in_garage_updated: number;
|
||||
max_frags: number;
|
||||
frags: number | null;
|
||||
mark_of_mastery: number;
|
||||
battle_life_time: number;
|
||||
in_garage: number | null;
|
||||
tank_id: number;
|
||||
}
|
||||
|
||||
export type TanksStats = {
|
||||
[accountId: number]: {
|
||||
all: {
|
||||
spotted: number;
|
||||
hits: number;
|
||||
frags: number;
|
||||
max_xp: number;
|
||||
wins: number;
|
||||
losses: number;
|
||||
capture_points: number;
|
||||
battles: number;
|
||||
damage_dealt: number;
|
||||
damage_received: number;
|
||||
max_frags: number;
|
||||
shots: number;
|
||||
frags8p: number;
|
||||
xp: number;
|
||||
win_and_survived: number;
|
||||
survived_battles: number;
|
||||
dropped_capture_points: number;
|
||||
};
|
||||
last_battle_time: number;
|
||||
account_id: number;
|
||||
max_xp: number;
|
||||
in_garage_updated: number;
|
||||
max_frags: number;
|
||||
frags: number | null;
|
||||
mark_of_mastery: number;
|
||||
battle_life_time: number;
|
||||
in_garage: number | null;
|
||||
tank_id: number;
|
||||
}[];
|
||||
[accountId: number]: IndividualTankStats[];
|
||||
};
|
||||
@@ -1,6 +1,12 @@
|
||||
export type WargamingResponse<Data extends object> =
|
||||
| {
|
||||
status: 'error';
|
||||
error: {
|
||||
field: string;
|
||||
message: string;
|
||||
code: 402;
|
||||
value: null;
|
||||
};
|
||||
}
|
||||
| {
|
||||
status: 'ok';
|
||||
|
||||
@@ -123,7 +123,7 @@
|
||||
|
||||
"@esbuild/[email protected]":
|
||||
version "0.17.19"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz#8a0e9738b1635f0c53389e515ae83826dec22aa4"
|
||||
resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz"
|
||||
integrity sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==
|
||||
|
||||
"@esbuild/[email protected]":
|
||||
@@ -158,7 +158,7 @@
|
||||
|
||||
"@playwright/test@^1.34.2":
|
||||
version "1.34.2"
|
||||
resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.34.2.tgz#938ccfb8c162e8ef83dbef3d88ce6851acd469e6"
|
||||
resolved "https://registry.npmjs.org/@playwright/test/-/test-1.34.2.tgz"
|
||||
integrity sha512-v/LBnwzD0225q8xEv3t9DmNPX61yvNnEbiA8PoNk1fbkxApJFCWYLPpQbdVWzHaARdZD9g1PYBoOvnffortfKw==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
@@ -191,29 +191,29 @@
|
||||
|
||||
"@total-typescript/ts-reset@^0.4.2":
|
||||
version "0.4.2"
|
||||
resolved "https://registry.yarnpkg.com/@total-typescript/ts-reset/-/ts-reset-0.4.2.tgz#c564c173ba09973968e1046c93965b7a257878a4"
|
||||
resolved "https://registry.npmjs.org/@total-typescript/ts-reset/-/ts-reset-0.4.2.tgz"
|
||||
integrity sha512-vqd7ZUDSrXFVT1n8b2kc3LnklncDQFPvR58yUS1kEP23/nHPAO9l1lMjUfnPrXYYk4Hj54rrLKMW5ipwk7k09A==
|
||||
|
||||
"@types/escape-html@^1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/escape-html/-/escape-html-1.0.2.tgz#072b7b13784fb3cee9c2450c22f36405983f5e3c"
|
||||
resolved "https://registry.npmjs.org/@types/escape-html/-/escape-html-1.0.2.tgz"
|
||||
integrity sha512-gaBLT8pdcexFztLSPRtriHeXY/Kn4907uOCZ4Q3lncFBkheAWOuNt53ypsF8szgxbEJ513UeBzcf4utN0EzEwA==
|
||||
|
||||
"@types/lodash.startcase@^4.4.7":
|
||||
version "4.4.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/lodash.startcase/-/lodash.startcase-4.4.7.tgz#69857f17be0aa5ce74da4fa386e32e22c012258a"
|
||||
resolved "https://registry.npmjs.org/@types/lodash.startcase/-/lodash.startcase-4.4.7.tgz"
|
||||
integrity sha512-6v8FVOcfxdomO1Vammc1Zsah7/4aif/Lx16oQQ0WZmKVGF/Yf5c5m68LqI/ELOhKaKUr8KfnDdKrytdrThoRQw==
|
||||
dependencies:
|
||||
"@types/lodash" "*"
|
||||
|
||||
"@types/lodash@*":
|
||||
version "4.14.194"
|
||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.194.tgz#b71eb6f7a0ff11bff59fc987134a093029258a76"
|
||||
resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.194.tgz"
|
||||
integrity sha512-r22s9tAS7imvBt2lyHC9B8AGwWnXaYb1tY09oyLkXDs4vArpYJzw09nj8MLx5VfciBPGIb+ZwG0ssYnEPJxn/g==
|
||||
|
||||
"@types/markdown-escape@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/markdown-escape/-/markdown-escape-1.1.0.tgz#8bd940d6701880eb7229467542c029bc05a7b22f"
|
||||
resolved "https://registry.npmjs.org/@types/markdown-escape/-/markdown-escape-1.1.0.tgz"
|
||||
integrity sha512-bJZh73L6fSt8MmTON/btR8hiKRipoIoPfLO41lxr6l65QXdG1rwUjR8Hu5xU7XYHBwKHiJZ+sTQ8L2TKkQrBpw==
|
||||
|
||||
"@types/node@*":
|
||||
@@ -223,7 +223,7 @@
|
||||
|
||||
"@types/node@^20.2.1":
|
||||
version "20.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.2.1.tgz#de559d4b33be9a808fd43372ccee822c70f39704"
|
||||
resolved "https://registry.npmjs.org/@types/node/-/node-20.2.1.tgz"
|
||||
integrity sha512-DqJociPbZP1lbZ5SQPk4oag6W7AyaGMO6gSfRwq3PWl4PXTwJpRQJhDq4W0kzrg3w6tJ1SwlvGZ5uKFHY13LIg==
|
||||
|
||||
"@types/ws@^8.5.4":
|
||||
@@ -235,7 +235,7 @@
|
||||
|
||||
acorn@^8.8.2:
|
||||
version "8.8.2"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a"
|
||||
resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz"
|
||||
integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==
|
||||
|
||||
busboy@^1.6.0:
|
||||
@@ -247,7 +247,7 @@ busboy@^1.6.0:
|
||||
|
||||
cac@^6.7.14:
|
||||
version "6.7.14"
|
||||
resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959"
|
||||
resolved "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz"
|
||||
integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==
|
||||
|
||||
data-uri-to-buffer@^4.0.0:
|
||||
@@ -257,7 +257,7 @@ data-uri-to-buffer@^4.0.0:
|
||||
|
||||
debug@^4.3.4:
|
||||
version "4.3.4"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
|
||||
resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz"
|
||||
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
|
||||
dependencies:
|
||||
ms "2.1.2"
|
||||
@@ -288,7 +288,7 @@ discord.js@^14.9.0:
|
||||
|
||||
esbuild@^0.17.5:
|
||||
version "0.17.19"
|
||||
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.17.19.tgz#087a727e98299f0462a3d0bcdd9cd7ff100bd955"
|
||||
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz"
|
||||
integrity sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==
|
||||
optionalDependencies:
|
||||
"@esbuild/android-arm" "0.17.19"
|
||||
@@ -316,7 +316,7 @@ esbuild@^0.17.5:
|
||||
|
||||
escape-html@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
|
||||
resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz"
|
||||
integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
|
||||
|
||||
fast-deep-equal@^3.1.3:
|
||||
@@ -355,7 +355,7 @@ [email protected], fsevents@~2.3.2:
|
||||
|
||||
fuzzysort@^2.0.4:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/fuzzysort/-/fuzzysort-2.0.4.tgz#a21d1ce8947eaf2797dc3b7c28c36db9d1165f84"
|
||||
resolved "https://registry.npmjs.org/fuzzysort/-/fuzzysort-2.0.4.tgz"
|
||||
integrity sha512-Api1mJL+Ad7W7vnDZnWq5pGaXJjyencT+iKGia2PlHUcSsSzWwIQ3S1isiMpwpavjYtGd2FzhUIhnnhOULZgDw==
|
||||
|
||||
ieee754@^1.2.1:
|
||||
@@ -370,7 +370,7 @@ inherits@^2.0.3:
|
||||
|
||||
jsonc-parser@^3.2.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76"
|
||||
resolved "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz"
|
||||
integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==
|
||||
|
||||
lodash.snakecase@^4.1.1:
|
||||
@@ -380,7 +380,7 @@ lodash.snakecase@^4.1.1:
|
||||
|
||||
lodash.startcase@^4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.startcase/-/lodash.startcase-4.4.0.tgz#9436e34ed26093ed7ffae1936144350915d9add8"
|
||||
resolved "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz"
|
||||
integrity sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==
|
||||
|
||||
lodash@^4.17.21:
|
||||
@@ -390,12 +390,12 @@ lodash@^4.17.21:
|
||||
|
||||
markdown-escape@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/markdown-escape/-/markdown-escape-2.0.0.tgz#44484d30d7845b91575c77fd8898f23a0a6f890c"
|
||||
resolved "https://registry.npmjs.org/markdown-escape/-/markdown-escape-2.0.0.tgz"
|
||||
integrity sha512-Trz4v0+XWlwy68LJIyw3bLbsJiC8XAbRCKF9DbEtZjyndKOGVx6n+wNB0VfoRmY2LKboQLeniap3xrb6LGSJ8A==
|
||||
|
||||
mlly@^1.2.0:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.2.1.tgz#cd50151f5712b651c5c379085157bcdff661133b"
|
||||
resolved "https://registry.npmjs.org/mlly/-/mlly-1.2.1.tgz"
|
||||
integrity sha512-1aMEByaWgBPEbWV2BOPEMySRrzl7rIHXmQxam4DM8jVjalTQDjpN2ZKOLUrwyhfZQO7IXHml2StcHMhooDeEEQ==
|
||||
dependencies:
|
||||
acorn "^8.8.2"
|
||||
@@ -405,12 +405,12 @@ mlly@^1.2.0:
|
||||
|
||||
[email protected]:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||
resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
|
||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||
|
||||
nanoid@^3.3.6:
|
||||
version "3.3.6"
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c"
|
||||
resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz"
|
||||
integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==
|
||||
|
||||
node-domexception@^1.0.0:
|
||||
@@ -429,7 +429,7 @@ node-fetch@^3.3.1:
|
||||
|
||||
pathe@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.0.tgz#e2e13f6c62b31a3289af4ba19886c230f295ec03"
|
||||
resolved "https://registry.npmjs.org/pathe/-/pathe-1.1.0.tgz"
|
||||
integrity sha512-ODbEPR0KKHqECXW1GoxdDb+AZvULmXjVPy4rt+pGo2+TnjJTIPJQSVS6N63n8T2Ip+syHhbn52OewKicV0373w==
|
||||
|
||||
peek-readable@^5.0.0:
|
||||
@@ -439,12 +439,12 @@ peek-readable@^5.0.0:
|
||||
|
||||
picocolors@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
|
||||
resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz"
|
||||
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
|
||||
|
||||
pkg-types@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.0.3.tgz#988b42ab19254c01614d13f4f65a2cfc7880f868"
|
||||
resolved "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz"
|
||||
integrity sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==
|
||||
dependencies:
|
||||
jsonc-parser "^3.2.0"
|
||||
@@ -453,12 +453,12 @@ pkg-types@^1.0.3:
|
||||
|
||||
[email protected]:
|
||||
version "1.34.2"
|
||||
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.34.2.tgz#4989ba082f623f21679724033629b2333b626569"
|
||||
resolved "https://registry.npmjs.org/playwright-core/-/playwright-core-1.34.2.tgz"
|
||||
integrity sha512-MrkgGWLANc5qthXduvIY1a/tuafROyTORVd86fwKwgoYrmnBooN/GgeZSBm7ljTLV2FCWNSXV3se7qeScKn83g==
|
||||
|
||||
postcss@^8.4.23:
|
||||
version "8.4.23"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.23.tgz#df0aee9ac7c5e53e1075c24a3613496f9e6552ab"
|
||||
resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz"
|
||||
integrity sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==
|
||||
dependencies:
|
||||
nanoid "^3.3.6"
|
||||
@@ -483,7 +483,7 @@ readable-web-to-node-stream@^3.0.2:
|
||||
|
||||
rollup@^3.21.0:
|
||||
version "3.22.0"
|
||||
resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.22.0.tgz#e6671baebdd473154ac7998bbc57faabcd7bba20"
|
||||
resolved "https://registry.npmjs.org/rollup/-/rollup-3.22.0.tgz"
|
||||
integrity sha512-imsigcWor5Y/dC0rz2q0bBt9PabcL3TORry2hAa6O6BuMvY71bqHyfReAz5qyAqiQATD1m70qdntqBfBQjVWpQ==
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
@@ -495,7 +495,7 @@ safe-buffer@~5.2.0:
|
||||
|
||||
source-map-js@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
|
||||
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz"
|
||||
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
|
||||
|
||||
streamsearch@^1.1.0:
|
||||
@@ -538,12 +538,12 @@ tslib@^2.5.0:
|
||||
|
||||
typescript@^5.0.4:
|
||||
version "5.0.4"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.4.tgz#b217fd20119bd61a94d4011274e0ab369058da3b"
|
||||
resolved "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz"
|
||||
integrity sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==
|
||||
|
||||
ufo@^1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.1.2.tgz#d0d9e0fa09dece0c31ffd57bd363f030a35cfe76"
|
||||
resolved "https://registry.npmjs.org/ufo/-/ufo-1.1.2.tgz"
|
||||
integrity sha512-TrY6DsjTQQgyS3E3dBaOXf0TpPD8u9FVrVYmKVegJuFw51n/YB9XPt+U6ydzFG5ZIN7+DIjPbNmXoBj9esYhgQ==
|
||||
|
||||
undici@^5.21.0:
|
||||
@@ -560,7 +560,7 @@ util-deprecate@^1.0.1:
|
||||
|
||||
vite-node@^0.31.1:
|
||||
version "0.31.1"
|
||||
resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-0.31.1.tgz#9fea18cbf9552ab262b969068249a8b8e7fb8b38"
|
||||
resolved "https://registry.npmjs.org/vite-node/-/vite-node-0.31.1.tgz"
|
||||
integrity sha512-BajE/IsNQ6JyizPzu9zRgHrBwczkAs0erQf/JRpgTIESpKvNj9/Gd0vxX905klLkb0I0SJVCKbdrl5c6FnqYKA==
|
||||
dependencies:
|
||||
cac "^6.7.14"
|
||||
@@ -572,7 +572,7 @@ vite-node@^0.31.1:
|
||||
|
||||
"vite@^3.0.0 || ^4.0.0":
|
||||
version "4.3.8"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-4.3.8.tgz#70cd6a294ab52d7fb8f37f5bc63d117dd19e9918"
|
||||
resolved "https://registry.npmjs.org/vite/-/vite-4.3.8.tgz"
|
||||
integrity sha512-uYB8PwN7hbMrf4j1xzGDk/lqjsZvCDbt/JC5dyfxc19Pg8kRm14LinK/uq+HSLNswZEoKmweGdtpbnxRtrAXiQ==
|
||||
dependencies:
|
||||
esbuild "^0.17.5"
|
||||
|
||||
Reference in new issue
Block a user