Merge branch 'metadata-improvements' of https://github.com/Huskydog9988/drop into Huskydog9988-metadata-improvements

This commit is contained in:
DecDuck
2025-03-13 15:54:51 +11:00
13 changed files with 1409 additions and 35 deletions

1
.gitattributes vendored
View File

@ -2,3 +2,4 @@
/.yarn/releases/* binary
/.yarn/plugins/**/* binary
/.pnp.* binary linguist-generated
* text=auto eol=lf

View File

@ -10,7 +10,7 @@
[![GitHub License](https://img.shields.io/github/license/Drop-OSS/drop-app)](LICENSE)
[![Gitlab Pipeline Status](https://img.shields.io/gitlab/pipeline-status/drop-oss%2Fdrop?gitlab_url=https%3A%2F%2Flab.deepcore.dev)](https://lab.deepcore.dev/drop-oss/drop/-/pipelines)
[![Discord](https://img.shields.io/discord/1291622805124812871?label=discord)](https://discord.gg/ZVGggfXN)
[![Discord](https://img.shields.io/discord/1291622805124812871?label=discord)](https://discord.gg/ACq4qZp4a9)
[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-%23FE5196?logo=conventionalcommits&logoColor=white)](https://conventionalcommits.org)
# Drop
@ -64,11 +64,12 @@ Drop uses a utility package called droplet that's written in Rust. It has builts
Steps:
1. Run `git submodule update --init --recursive` to setup submodules
1. Copy the `.env.example` to `.env` and add your GiantBomb metadata key (more metadata providers coming)
2. Create the `.data` directory with `mkdir .data`
3. Ensure that your user owns the `.data` directory with `sudo chown -R $(id -u $(whoami))`
4. Open up a terminal and navigate to `dev-tools`, and run `docker compose up`
5. Open up another terminal in the root directory of the project and run `yarn` and then `yarn dev` to start the dev server
1. Create the `.data` directory with `mkdir .data`
1. Ensure that your user owns the `.data` directory with `sudo chown -R $(id -u $(whoami))`
1. Open up a terminal and navigate to `dev-tools`, and run `docker compose up`
1. Open up another terminal in the root directory of the project and run `yarn` and then `yarn dev` to start the dev server
As part of the first-time bootstrap, Drop creates an invitation with the fixed id of 'admin'. So, to create an admin account, go to:

View File

@ -1,5 +1,197 @@
## Release 0.2.0-beta
### Fixes
- fix recursive dirs util #02d6346
- Fix username length requirement #0a5a649
- remove dynamic imports #0f10626
- fix for missing developers or publishers #25fc957
- split prisma schemas #2859005
- results are returned alphabetically #33d3770
- update prisma schemas #36776cc
- removed global flag #43e32b4
- properly disconnect websockets from task handler #5358f1f
- follow best practices #54c5d55
- future lenience #5c78b20
- fix width of token breaking things #61d88c3
- fixed websocket authentication #62ea9a1
- fix delta manifest generation #6df560c
- admin invitation w/ system user #8463e35
- properly import icons #8945196
- prisma create footprint #952ece8
- game panel now always shows 3 lines exactly #9c2249e
- remove unnecessary import #a361c38
- fix disconnect code #a8f2106
- fix types #b511b40
- add drop-base as git submodule #b75ebd1
- Update README.md with discord link #c6bb21d
- fix expires requirement in the admin endpoint #c7b675f
- fix always being created as admin #c7eb11a
- moved icons and created PlatformClient so we can use the enum on the frontend #cada630
- recurse submodules #db103de
- fix FATAL: "root"... message #dbb315a
- only show versions that are directories #ef8f3ae
### Features
- update prisma & delete games #089c3e0
- manual handshake #12e3125
- fetch game endpoint #1f4d075
- under the hood organisation and consolidation #26a31f6
- 'no images' slide on image carousel #28baabc
- improve feedback when metadata fails #2c19e13
- introduction of 'system user' #2c21a23
- change name, description and icon #2cfe75a
- 'manual' metadata provider #2f52a16
- add disabled state #38fc6b8
- overhauled version importing #39d7ce7
- automatically create library folder if it doesn't exist #39fe9d5
- smoother bar in admin task ui #4488ae2
- add noWrapper option #4f9b949
- add version metadata route #5393db3
- completed admin UI, with minor changes to backend #599da0e
- adjust gradient #5a1f841
- keep track of last connected #69e4c25
- added notification system w/ interwoven refactoring #6e6f09d
- content length header for chunk downloads #76bceb1
- add title to tab #7b0756c
- add button to open in admin panel #7b3b919
- client capability framework + peer API configuration #7d72a86
- customisable image carousel and new layout #937954f
- support more types #9b12d45
- generate a server certificate for mtls APIs #9c4b6f3
- new endpoints, ui and beginnings of main store page #9cbdcbc
- backend #a309651
- more subtle design improvements #a815542
- add aden's carousel pagination design #a86045c
- add header #a8a152e
- client side search #b50e27f
- new ws handler #bc0c47c
- user widget now redirects to actual page #bfafe02
- require lowercase usernames #d7160ab
- more ui improvements #e408ac5
- add modifying game descriptions #e505e58
- mobile nav #e5cf13f
- slightly improved game page #e796b46
- game carousel #ecc819e
- add enum dictionary type #f2e0182
- improved ux #f3ed0f6
- cleanup and raw accessors #f7d767d
- add support for overriding UMU id #fd4a7d1
- add .sh for linux #fe9373a
### Other Changes
- quexeky <git@quexeky.dev>
- fixed manifest generation #03a37f7
- manual ci/cd #03b0b0c
- ability to fetch client certs for p2p #0a715fe
- disable tls in build #0f80fcd
- Updated README.md #17971e0
- Merge pull request #18 from Drop-OSS/develop
- initial work on metadata system #196f87c
- more ui #1bd19ad
- remove log statements #1d5e1bd
- small fixes & SSR disabled #1f575b2
- update information and setup guide #2236622
- metadata engine #22ac7f6
- Update CONTRIBUTING.md #2309407
- slight bug fixes and clean up #24a0d11
- almst complete admin ui and initial store designs #27070b6
- handshakes #2b4382d
- user mobile header #2e44ef3
- more consistent naming for globals #305de9f
- replaced markdown-it with micromark #31e8359
- fixes to store page for mobile clients #328b9ba
- game version re-ordering #329c74d
- verbose yarn install #36568c3
- patch for no version check in manifest generation #395219d
- migrate bcrypt to bcryptjs #3a51c9c
- added download chunk endpoint #3dd6062
- Update README.md #425934d
- build only ci #4273a20
- object storage + full permission system + testing #435551c
- rename admin socket session map #44c6028
- bump droplet and add vue carousel #46551f9
- version importing #46c8f0c
- back to yarn, with nuxt telemetry force disabled #46d35ad
- finished object endpoints #486bce8
- update dependencies and add note about optional dependencies #4fa771a
- use configuration from docs for ci/cd #52315d0
- slight fixes to register logic #583301f
- removed yarn.lock #584bcf1
- Version bump #5f29c28
- immutable application settings framework #5fe2036
- fixed docker daemon location #62a111b
- copy autodevops configuration #6328c24
- Delete .gitlab-ci.yml #69f341b
- admin ui shell #6b5e48d
- bump @drop/droplet version for windows developers #6ba5cdd
- Add LICENSE #6e2dc89
- custom dind #716eac7
- task API #718f5ba
- use gitlab ci variable declaration #7194d35
- move icons into dedicated folder #74fa671
- another stage of client authentication #7523e53
- refactoring #7869043
- moved windows logo into logos dir #789d3ba
- updated text colours across app #7a88f4c
- starting docs infra #7d2a1c6
- more cleaning #7e17626
- slight patch to rename query to be more consistent #7f4db0c
- move to raw docker #803752e
- server side and user client side completed for registration #848a611
- beginnings of download implementation #8674ac7
- more consistent naming for object handler #87230fb
- use autodevops build stage #886beb6
- Updated tailwind config #88c95d6
- change name of store file #8999303
- split prisma schemas #9011cf5
- client initiate #909432a
- more client routes to support Drop app update #91b7e10
- additional polish and QoL features #93bc143
- upload images to games #9b7ee4e
- migrate to pnpm due to ci/cd issues with yarn #9cb2d6d
- run yarn install in CI/CD non interactively #a208fbe
- completed game importing; partial work on version importing #a7c33e7
- remove canvas from dependencies #a8f58eb
- fix registry authentication #ad25d3e
- consolidate type utils #adb4b73
- Updated README.md #b0ef675
- add proper carousel to store page #b2ab827
- move to yarn v2 #b744671
- remove client API deadweight #b9ae26c
- add expires field #be6c30d
- ca groundwork #bfafd2a
- cleanup & polish #c355f6f
- remove bcrypt (debug) #c3914cc
- non rounded bottom #c4391d3
- failed gracefully on invalid chunk index #c4a3e4e
- update deploy template #c4a419f
- migrate to new droplet ca system #c4d8113
- docker based deployment #c5d00b4
- updated CONTRIBUTING.md #cd0d2bf
- update prisma version #ce0a9ab
- README update #ceacd84
- patch metadata handler #cf578bd
- Added SECURITY.md #d3d93b0
- finalised client APIs and authentication method #d4e2dc8
- Update README.md #db916bf
- object storage interface + utility functions #de388a9
- initial commit #e1a789f
- fixed task system #e1c1d7e
- Update file chunk.get.ts #e4339c3
- ui groundwork #e52f072
- Update changelog #eadcaa1
- check for no version in manifest generation #eb3f9f9
- break into single column store on lg devices #ecb381e
- better server side signin redirects #ef13b68
- patch signin #f3672f8
_changelog generated by_ [go-conventional-commits](https://github.com/joselitofilho/go-conventional-commits)
## Release 0.1.0-beta
### Fixes

View File

@ -35,7 +35,7 @@ export default defineNuxtConfig({
extends: ["./drop-base"],
// Module config from here down
modules: ["@nuxt/content", "vue3-carousel-nuxt"],
modules: ["@nuxt/content", "vue3-carousel-nuxt", "nuxt-security"],
carousel: {
prefix: "Vue",
@ -56,4 +56,18 @@ export default defineNuxtConfig({
},
},
},
security: {
headers: {
contentSecurityPolicy: {
"img-src": [
"'self'",
"data:",
"https://www.giantbomb.com",
"https://images.pcgamingwiki.com",
"https://images.igdb.com",
],
},
},
},
});

View File

@ -27,6 +27,7 @@
"micromark": "^4.0.1",
"moment": "^2.30.1",
"nuxt": "^3.13.2",
"nuxt-security": "2.2.0",
"prisma": "^6.1.0",
"sanitize-filename": "^1.6.3",
"stream": "^0.0.3",

View File

@ -0,0 +1,10 @@
-- AlterEnum
-- This migration adds more than one value to an enum.
-- With PostgreSQL versions 11 and earlier, this is not possible
-- in a single migration. This can be worked around by creating
-- multiple migrations, each migration adding only one value to
-- the enum.
ALTER TYPE "MetadataSource" ADD VALUE 'PCGamingWiki';
ALTER TYPE "MetadataSource" ADD VALUE 'IGDB';

View File

@ -1,6 +1,8 @@
enum MetadataSource {
Manual
GiantBomb
PCGamingWiki
IGDB
}
model Game {

View File

@ -1,5 +1,5 @@
import { Developer, MetadataSource, Publisher } from "@prisma/client";
import { MetadataProvider } from ".";
import { MetadataProvider, MissingMetadataProviderConfig } from ".";
import {
GameMetadataSearchResult,
_FetchGameMetadataParams,
@ -74,13 +74,18 @@ interface CompanySearchResult {
};
}
// Api Docs: https://www.giantbomb.com/api/
export class GiantBombProvider implements MetadataProvider {
private apikey: string;
private turndown: TurndownService;
constructor() {
const apikey = process.env.GIANT_BOMB_API_KEY;
if (!apikey) throw new Error("No GIANT_BOMB_API_KEY in environment");
if (!apikey)
throw new MissingMetadataProviderConfig(
"GIANT_BOMB_API_KEY",
this.name()
);
this.apikey = apikey;
@ -96,18 +101,14 @@ export class GiantBombProvider implements MetadataProvider {
private async request<T>(
resource: string,
url: string,
query: { [key: string]: string | Array<string> },
query: { [key: string]: string },
options?: AxiosRequestConfig
) {
const queryOptions = { ...query, api_key: this.apikey, format: "json" };
const queryString = Object.entries(queryOptions)
.map(([key, value]) => {
if (Array.isArray(value)) {
return `${key}=${value.map(encodeURIComponent).join(",")}`;
}
return `${key}=${encodeURIComponent(value)}`;
})
.join("&");
const queryString = new URLSearchParams({
...query,
api_key: this.apikey,
format: "json",
}).toString();
const finalURL = `https://www.giantbomb.com/api/${resource}/${url}?${queryString}`;
@ -134,7 +135,7 @@ export class GiantBombProvider implements MetadataProvider {
async search(query: string): Promise<GameMetadataSearchResult[]> {
const results = await this.request<Array<GameSearchResult>>("search", "", {
query: query,
resources: ["game"],
resources: ["game"].join(","),
});
const mapped = results.data.results.map((result) => {
const date =

View File

@ -0,0 +1,406 @@
import { Developer, MetadataSource, Publisher } from "@prisma/client";
import { MetadataProvider, MissingMetadataProviderConfig } from ".";
import {
GameMetadataSearchResult,
_FetchGameMetadataParams,
GameMetadata,
_FetchPublisherMetadataParams,
PublisherMetadata,
_FetchDeveloperMetadataParams,
DeveloperMetadata,
} from "./types";
import axios, { AxiosRequestConfig } from "axios";
import { inspect } from "util";
import moment from "moment";
type IGDBID = number;
interface TwitchAuthResponse {
access_token: string;
expires_in: number;
token_type: string; // likely 'bearer'
}
interface IGDBErrorResponse {
title: string;
status: number;
cause: string;
}
interface IGDBItem {
id: IGDBID;
}
// denotes role a company had in a game
interface IGDBInvolvedCompany extends IGDBItem {
company: IGDBID;
game: IGDBID;
developer: boolean;
porting: boolean;
publisher: boolean;
supporting: boolean;
created_at: number;
updated_at: number;
}
interface IGDBCompany extends IGDBItem {
name: string;
country: number; // ISO 3166-1 country code
description: string;
logo: IGDBID;
parent: IGDBID;
slug: string;
start_date: number;
status: IGDBID;
websites: IGDBID[];
}
interface IGDBCompanyWebsite extends IGDBItem {
trusted: boolean;
url: string;
}
interface IGDBCover extends IGDBItem {
url: string;
}
interface IGDBSearchStub extends IGDBItem {
name: string;
cover: IGDBID;
first_release_date: number; // unix timestamp
summary: string;
}
// https://api-docs.igdb.com/?shell#game
interface IGDBGameFull extends IGDBSearchStub {
age_ratings?: IGDBID[];
aggregated_rating?: number;
aggregated_rating_count?: number;
alternative_names?: IGDBID[];
artworks?: IGDBID[];
bundles?: IGDBID[];
checksum?: string;
collections?: IGDBID[];
created_at: number; // unix timestamp
dlcs?: IGDBID[];
expanded_games?: IGDBID[];
expansions?: IGDBID[];
external_games?: IGDBID[];
forks?: IGDBID[];
franchise?: IGDBID;
franchises?: IGDBID[];
game_engines?: IGDBID[];
game_localizations?: IGDBID[];
game_modes?: IGDBID[];
game_status?: IGDBID;
game_type?: IGDBID;
genres?: IGDBID[];
hypes?: number;
involved_companies?: IGDBID[];
keywords?: IGDBID[];
language_supports?: IGDBID[];
multiplayer_modes?: IGDBID[];
platforms?: IGDBID[];
player_perspectives?: IGDBID[];
ports?: IGDBID[];
rating?: number;
rating_count?: number;
release_dates?: IGDBID[];
remakes?: IGDBID[];
remasters?: IGDBID[];
screenshots?: IGDBID[];
similar_games?: IGDBID[];
slug: string;
standalone_expansions?: IGDBID[];
storyline?: string;
tags?: IGDBID[];
themes?: IGDBID[];
total_rating?: number;
total_rating_count?: number;
updated_at: number;
url: string;
version_parent?: IGDBID;
version_title?: string;
videos?: IGDBID[];
websites?: IGDBID[];
}
// Api Docs: https://api-docs.igdb.com/
export class IGDBProvider implements MetadataProvider {
private client_id: string;
private client_secret: string;
private access_token: string;
private access_token_expire: moment.Moment;
constructor() {
const client_id = process.env.IGDB_CLIENT_ID;
if (!client_id)
throw new MissingMetadataProviderConfig("IGDB_CLIENT_ID", this.name());
const client_secret = process.env.IGDB_CLIENT_SECRET;
if (!client_secret)
throw new MissingMetadataProviderConfig(
"IGDB_CLIENT_SECRET",
this.name()
);
this.client_id = client_id;
this.client_secret = client_secret;
this.access_token = "";
this.access_token_expire = moment();
this.authWithTwitch();
}
private async authWithTwitch() {
const params = new URLSearchParams({
client_id: this.client_id,
client_secret: this.client_secret,
grant_type: "client_credentials",
});
const response = await axios.request<TwitchAuthResponse>({
url: `https://id.twitch.tv/oauth2/token?${params.toString()}`,
baseURL: "",
method: "POST",
});
this.access_token = response.data.access_token;
this.access_token_expire = moment().add(
response.data.expires_in,
"seconds"
);
}
private async refreshCredentials() {
const futureTime = moment().add(1, "day");
// if the token expires before this future time (aka soon), refresh
if (this.access_token_expire.isBefore(futureTime)) this.authWithTwitch();
}
private async request<T extends Object>(
resource: string,
body: string,
options?: AxiosRequestConfig
) {
await this.refreshCredentials();
// prevent calling api before auth is complete
if (this.access_token.length <= 0)
throw new Error(
"IGDB either failed to authenticate, or has not done so yet"
);
const finalURL = `https://api.igdb.com/v4/${resource}`;
const overlay: AxiosRequestConfig = {
url: finalURL,
baseURL: "",
method: "POST",
data: body,
headers: {
Accept: "application/json",
"Client-ID": this.client_id,
Authorization: `Bearer ${this.access_token}`,
"content-type": "text/plain",
},
};
const response = await axios.request<T[] | IGDBErrorResponse[]>(
Object.assign({}, options, overlay)
);
if (response.status !== 200) {
let cause = "";
response.data.forEach((item) => {
if ("cause" in item) cause = item.cause;
});
throw new Error(
`Error in igdb \nStatus Code: ${response.status} \nCause: ${cause}`
);
}
// should not have an error object if the status code is 200
return <T[]>response.data;
}
private async _getMediaInternal(mediaID: IGDBID, type: string) {
const body = `where id = ${mediaID}; fields url;`;
const response = await this.request<IGDBCover>(type, body);
let result = "";
response.forEach((cover) => {
if (cover.url.startsWith("https:")) {
result = cover.url;
} else {
// twitch *sometimes* provides it in the format "//images.igdb.com"
result = `https:${cover.url}`;
}
});
return result;
}
private async getCoverURL(id: IGDBID) {
return await this._getMediaInternal(id, "covers");
}
private async getArtworkURL(id: IGDBID) {
return await this._getMediaInternal(id, "artworks");
}
private async getCompanyLogoURl(id: IGDBID) {
return await this._getMediaInternal(id, "company_logos");
}
private trimMessage(msg: string, len: number) {
return msg.length > len ? msg.substring(0, 280) + "..." : msg;
}
id() {
return "igdb";
}
name() {
return "IGDB";
}
source() {
return MetadataSource.IGDB;
}
async search(query: string): Promise<GameMetadataSearchResult[]> {
const body = `search "${query}"; fields name,cover,first_release_date,summary; limit 3;`;
const response = await this.request<IGDBSearchStub>("games", body);
const results: GameMetadataSearchResult[] = [];
for (let i = 0; i < response.length; i++) {
results.push({
id: "" + response[i].id,
name: response[i].name,
icon: await this.getCoverURL(response[i].cover),
description: response[i].summary,
year: moment.unix(response[i].first_release_date).year(),
});
}
return results;
}
async fetchGame({
id,
publisher,
developer,
createObject,
}: _FetchGameMetadataParams): Promise<GameMetadata> {
const body = `where id = ${id}; fields *;`;
const response = await this.request<IGDBGameFull>("games", body);
for (let i = 0; i < response.length; i++) {
const icon = createObject(await this.getCoverURL(response[i].cover));
let banner = "";
const images = [icon];
for (const art of response[i]?.artworks ?? []) {
// if banner not set
if (banner.length <= 0) {
banner = createObject(await this.getArtworkURL(art));
images.push(banner);
} else {
images.push(createObject(await this.getArtworkURL(art)));
}
}
const publishers: Publisher[] = [];
const developers: Developer[] = [];
for (const involvedCompany of response[i]?.involved_companies ?? []) {
// get details about the involved company
const involved_company_response =
await this.request<IGDBInvolvedCompany>(
"involved_companies",
`where id = ${involvedCompany}; fields *;`
);
for (const foundInvolved of involved_company_response) {
// now we need to get the actual company so we can get the name
const findCompanyResponse = await this.request<
{ name: string } & IGDBItem
>("companies", `where id = ${foundInvolved.company}; fields name;`);
for (const company of findCompanyResponse) {
// if company was a dev or publisher
// CANNOT use else since a company can be both
if (foundInvolved.developer)
developers.push(await developer(company.name));
if (foundInvolved.publisher)
publishers.push(await publisher(company.name));
}
}
}
return {
id: "" + response[i].id,
name: response[i].name,
shortDescription: this.trimMessage(response[i].summary, 280),
description: response[i].summary,
released: moment.unix(response[i].first_release_date).toDate(),
reviewCount: response[i]?.total_rating_count ?? 0,
reviewRating: (response[i]?.total_rating ?? 0) / 100,
publishers: [],
developers: [],
icon,
bannerId: banner,
coverId: icon,
images,
};
}
throw new Error("No game found on igdb with that id");
}
async fetchPublisher({
query,
createObject,
}: _FetchPublisherMetadataParams): Promise<PublisherMetadata> {
const response = await this.request<IGDBCompany>(
"companies",
`where name = "${query}"; fields *; limit 1;`
);
for (const company of response) {
const logo = createObject(await this.getCompanyLogoURl(company.logo));
let company_url = "";
for (const companySite of company.websites) {
const companySiteRes = await this.request<IGDBCompanyWebsite>(
"company_websites",
`where id = ${companySite}; fields *;`
);
for (const site of companySiteRes) {
if (company_url.length <= 0) company_url = site.url;
}
}
const metadata: PublisherMetadata = {
id: "" + company.id,
name: company.name,
shortDescription: this.trimMessage(company.description, 280),
description: company.description,
website: company_url,
logo: logo,
banner: logo,
};
return metadata;
}
throw new Error("No results found");
}
async fetchDeveloper(
params: _FetchDeveloperMetadataParams
): Promise<DeveloperMetadata> {
return await this.fetchPublisher(params);
}
}

View File

@ -19,6 +19,24 @@ import { ObjectTransactionalHandler } from "../objects/transactional";
import { PriorityList, PriorityListIndexed } from "../utils/prioritylist";
import { GiantBombProvider } from "./giantbomb";
import { ManualMetadataProvider } from "./manual";
import { PCGamingWikiProvider } from "./pcgamingwiki";
import { IGDBProvider } from "./igdb";
export class MissingMetadataProviderConfig extends Error {
private providerName: string;
constructor(configKey: string, providerName: string) {
super(`Missing config item ${configKey} for ${providerName}`);
this.providerName = providerName;
}
getProviderName() {
return this.providerName;
}
}
// TODO: add useragent to all outbound api calls (best practice)
export const DropUserAgent = "Drop/0.2";
export abstract class MetadataProvider {
abstract id(): string;
@ -46,7 +64,6 @@ export class MetadataHandler {
this.providers.push(provider, priority);
}
/**
* Returns provider IDs, used to save to applicationConfig
* @returns The provider IDs in order, missing manual
@ -143,7 +160,6 @@ export class MetadataHandler {
throw e;
}
await pullObjects();
const game = await prisma.game.create({
data: {
metadataSource: provider.source(),
@ -171,6 +187,7 @@ export class MetadataHandler {
libraryBasePath,
},
});
await pullObjects();
return game;
}
@ -195,8 +212,8 @@ export class MetadataHandler {
// Type-checking this thing is impossible
private async fetchDeveloperPublisher(
query: string,
functionName: any,
databaseName: any
functionName: "fetchDeveloper" | "fetchPublisher",
databaseName: "developer" | "publisher"
) {
const existing = await (prisma as any)[databaseName].findFirst({
where: {
@ -205,12 +222,15 @@ export class MetadataHandler {
});
if (existing) return existing;
for (const provider of this.providers.values() as any) {
for (const provider of this.providers.values()) {
// don't allow manual provider to "fetch" metadata
if (provider.source() === MetadataSource.Manual) continue;
const [createObject, pullObjects, dumpObjects] = this.objectHandler.new(
{},
["internal:read"]
);
let result;
let result: PublisherMetadata;
try {
result = await provider[functionName]({ query, createObject });
} catch (e) {

View File

@ -0,0 +1,259 @@
import { Developer, MetadataSource, Publisher } from "@prisma/client";
import { MetadataProvider, MissingMetadataProviderConfig } from ".";
import {
GameMetadataSearchResult,
_FetchGameMetadataParams,
GameMetadata,
_FetchPublisherMetadataParams,
PublisherMetadata,
_FetchDeveloperMetadataParams,
DeveloperMetadata,
} from "./types";
import axios, { AxiosRequestConfig } from "axios";
import moment from "moment";
import * as jdenticon from "jdenticon";
interface PCGamingWikiPage {
PageID: string;
PageName: string;
}
interface PCGamingWikiSearchStub extends PCGamingWikiPage {
"Cover URL": string | null;
Released: string | null;
Released__precision: string | null;
}
interface PCGamingWikiGame extends PCGamingWikiSearchStub {
Developers: string | null;
Genres: string | null;
Publishers: string | null;
Themes: string | null;
Series: string | null;
Modes: string | null;
}
interface PCGamingWikiCompany extends PCGamingWikiPage {
Parent: string | null;
Founded: string | null;
Website: string | null;
Founded__precision: string | null;
Defunct__precision: string | null;
}
interface PCGamingWikiCargoResult<T> {
cargoquery: [
{
title: T;
}
];
error?: {
code?: string;
info?: string;
errorclass?: string;
"*"?: string;
};
}
// Api Docs: https://www.pcgamingwiki.com/wiki/PCGamingWiki:API
// Good tool for helping build cargo queries: https://www.pcgamingwiki.com/wiki/Special:CargoQuery
export class PCGamingWikiProvider implements MetadataProvider {
constructor() {}
id() {
return "pcgamingwiki";
}
name() {
return "PCGamingWiki";
}
source() {
return MetadataSource.PCGamingWiki;
}
private async request<T>(
query: URLSearchParams,
options?: AxiosRequestConfig
) {
const finalURL = `https://www.pcgamingwiki.com/w/api.php?${query.toString()}`;
const overlay: AxiosRequestConfig = {
url: finalURL,
baseURL: "",
};
const response = await axios.request<PCGamingWikiCargoResult<T>>(
Object.assign({}, options, overlay)
);
if (response.status !== 200)
throw new Error(
`Error in pcgamingwiki \nStatus Code: ${response.status}`
);
else if (response.data.error !== undefined)
throw new Error(`Error in pcgamingwiki, malformed query`);
return response;
}
async search(query: string) {
const searchParams = new URLSearchParams({
action: "cargoquery",
tables: "Infobox_game",
fields:
"Infobox_game._pageID=PageID,Infobox_game._pageName=PageName,Infobox_game.Cover_URL,Infobox_game.Released",
where: `Infobox_game._pageName="${query}"`,
format: "json",
});
const res = await this.request<PCGamingWikiSearchStub>(searchParams);
const mapped = res.data.cargoquery.map((result) => {
const game = result.title;
const metadata: GameMetadataSearchResult = {
id: game.PageID,
name: game.PageName,
icon: game["Cover URL"] ?? "",
description: "", // TODO: need to render the `Introduction` template somehow (or we could just hardcode it)
year:
game.Released !== null && game.Released.length > 0
? moment(game.Released).year()
: 0,
};
return metadata;
});
return mapped;
}
/**
* Parses the specific format that the wiki returns when specifying a company
* @param companyStr
* @returns
*/
private parseCompanyStr(companyStr: string): string[] {
const results: string[] = [];
// provides the string as a list of companies
// ie: "Company:Digerati Distribution,Company:Greylock Studio"
const items = companyStr.split(",");
items.forEach((item) => {
// remove the `Company:` and trim and whitespace
results.push(item.replace("Company:", "").trim());
});
return results;
}
async fetchGame({
id,
name,
publisher,
developer,
createObject,
}: _FetchGameMetadataParams): Promise<GameMetadata> {
const searchParams = new URLSearchParams({
action: "cargoquery",
tables: "Infobox_game",
fields:
"Infobox_game._pageID=PageID,Infobox_game._pageName=PageName,Infobox_game.Cover_URL,Infobox_game.Developers,Infobox_game.Released,Infobox_game.Genres,Infobox_game.Publishers,Infobox_game.Themes,Infobox_game.Series,Infobox_game.Modes",
where: `Infobox_game._pageID="${id}"`,
format: "json",
});
const res = await this.request<PCGamingWikiGame>(searchParams);
if (res.data.cargoquery.length < 1)
throw new Error("Error in pcgamingwiki, no game");
const game = res.data.cargoquery[0].title;
const publishers: Publisher[] = [];
if (game.Publishers !== null) {
const pubListClean = this.parseCompanyStr(game.Publishers);
for (const pub of pubListClean) {
publishers.push(await publisher(pub));
}
}
const developers: Developer[] = [];
if (game.Developers !== null) {
const devListClean = this.parseCompanyStr(game.Developers);
for (const dev of devListClean) {
developers.push(await developer(dev));
}
}
const icon =
game["Cover URL"] !== null
? createObject(game["Cover URL"])
: createObject(jdenticon.toPng(name, 512));
const metadata: GameMetadata = {
id: game.PageID,
name: game.PageName,
shortDescription: "", // TODO: (again) need to render the `Introduction` template somehow (or we could just hardcode it)
description: "",
released: game.Released
? moment(game.Released.split(";").at(0)).toDate()
: new Date(),
reviewCount: 0,
reviewRating: 0,
publishers,
developers,
icon: icon,
bannerId: icon,
coverId: icon,
images: [icon],
};
return metadata;
}
async fetchPublisher({
query,
createObject,
}: _FetchPublisherMetadataParams): Promise<PublisherMetadata> {
const searchParams = new URLSearchParams({
action: "cargoquery",
tables: "Company",
fields:
"Company.Parent,Company.Founded,Company.Defunct,Company.Website,Company._pageName=PageName,Company._pageID=pageID",
where: `Company._pageName="Company:${query}"`,
format: "json",
});
const res = await this.request<PCGamingWikiCompany>(searchParams);
// TODO: replace
const icon = createObject(jdenticon.toPng(query, 512));
for (let i = 0; i < res.data.cargoquery.length; i++) {
const company = res.data.cargoquery[i].title;
const fixedCompanyName =
company.PageName.split("Company:").at(1) ?? company.PageName;
const metadata: PublisherMetadata = {
id: company.PageID,
name: fixedCompanyName,
shortDescription: "",
description: "",
website: company?.Website ?? "",
logo: icon,
banner: icon,
};
return metadata;
}
throw new Error("Error in pcgamingwiki, no publisher");
}
async fetchDeveloper(
params: _FetchDeveloperMetadataParams
): Promise<DeveloperMetadata> {
return await this.fetchPublisher(params);
}
}

View File

@ -1,10 +1,16 @@
import { applicationSettings } from "../internal/config/application-configuration";
import metadataHandler, { MetadataProvider } from "../internal/metadata";
import { GiantBombProvider } from "../internal/metadata/giantbomb";
import { IGDBProvider } from "../internal/metadata/igdb";
import { ManualMetadataProvider } from "../internal/metadata/manual";
import { PCGamingWikiProvider } from "../internal/metadata/pcgamingwiki";
export default defineNitroPlugin(async (nitro) => {
const metadataProviders = [GiantBombProvider];
const metadataProviders = [
GiantBombProvider,
PCGamingWikiProvider,
IGDBProvider,
];
const providers: { [key: string]: MetadataProvider } = {};

479
yarn.lock
View File

@ -20,7 +20,7 @@
resolved "https://registry.yarnpkg.com/@antfu/utils/-/utils-0.7.10.tgz#ae829f170158e297a9b6a28f161a8e487d00814d"
integrity sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==
"@babel/code-frame@^7.12.13", "@babel/code-frame@^7.22.13", "@babel/code-frame@^7.24.7", "@babel/code-frame@^7.25.9", "@babel/code-frame@^7.26.0":
"@babel/code-frame@^7.12.13", "@babel/code-frame@^7.22.13", "@babel/code-frame@^7.24.7", "@babel/code-frame@^7.25.9", "@babel/code-frame@^7.26.0", "@babel/code-frame@^7.26.2":
version "7.26.2"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85"
integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==
@ -34,6 +34,11 @@
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.2.tgz#278b6b13664557de95b8f35b90d96785850bb56e"
integrity sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==
"@babel/compat-data@^7.26.5":
version "7.26.8"
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.8.tgz#821c1d35641c355284d4a870b8a4a7b0c141e367"
integrity sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==
"@babel/core@^7.23.0", "@babel/core@^7.24.7", "@babel/core@^7.25.7":
version "7.26.0"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.26.0.tgz#d78b6023cc8f3114ccf049eb219613f74a747b40"
@ -55,6 +60,38 @@
json5 "^2.2.3"
semver "^6.3.1"
"@babel/core@^7.25.2":
version "7.26.10"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.26.10.tgz#5c876f83c8c4dcb233ee4b670c0606f2ac3000f9"
integrity sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==
dependencies:
"@ampproject/remapping" "^2.2.0"
"@babel/code-frame" "^7.26.2"
"@babel/generator" "^7.26.10"
"@babel/helper-compilation-targets" "^7.26.5"
"@babel/helper-module-transforms" "^7.26.0"
"@babel/helpers" "^7.26.10"
"@babel/parser" "^7.26.10"
"@babel/template" "^7.26.9"
"@babel/traverse" "^7.26.10"
"@babel/types" "^7.26.10"
convert-source-map "^2.0.0"
debug "^4.1.0"
gensync "^1.0.0-beta.2"
json5 "^2.2.3"
semver "^6.3.1"
"@babel/generator@^7.25.0", "@babel/generator@^7.26.10":
version "7.26.10"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.26.10.tgz#a60d9de49caca16744e6340c3658dfef6138c3f7"
integrity sha512-rRHT8siFIXQrAYOYqZQVsAr8vJ+cBNqcVAY6m5V8/4QqzaPl+zDBe6cLEPRDuNOUf3ww8RfJVlOyQMoSI+5Ang==
dependencies:
"@babel/parser" "^7.26.10"
"@babel/types" "^7.26.10"
"@jridgewell/gen-mapping" "^0.3.5"
"@jridgewell/trace-mapping" "^0.3.25"
jsesc "^3.0.2"
"@babel/generator@^7.25.9", "@babel/generator@^7.26.0":
version "7.26.2"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.26.2.tgz#87b75813bec87916210e5e01939a4c823d6bb74f"
@ -84,6 +121,17 @@
lru-cache "^5.1.1"
semver "^6.3.1"
"@babel/helper-compilation-targets@^7.26.5":
version "7.26.5"
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz#75d92bb8d8d51301c0d49e52a65c9a7fe94514d8"
integrity sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==
dependencies:
"@babel/compat-data" "^7.26.5"
"@babel/helper-validator-option" "^7.25.9"
browserslist "^4.24.0"
lru-cache "^5.1.1"
semver "^6.3.1"
"@babel/helper-create-class-features-plugin@^7.25.9":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz#7644147706bb90ff613297d49ed5266bde729f83"
@ -174,6 +222,14 @@
"@babel/template" "^7.25.9"
"@babel/types" "^7.26.0"
"@babel/helpers@^7.26.10":
version "7.26.10"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.26.10.tgz#6baea3cd62ec2d0c1068778d63cb1314f6637384"
integrity sha512-UPYc3SauzZ3JGgj87GgZ89JVdC5dj0AoetR5Bw6wj4niittNyFh6+eOGonYvJ1ao6B8lEa3Q3klS7ADZ53bc5g==
dependencies:
"@babel/template" "^7.26.9"
"@babel/types" "^7.26.10"
"@babel/parser@^7.25.3", "@babel/parser@^7.25.4", "@babel/parser@^7.25.6", "@babel/parser@^7.25.8", "@babel/parser@^7.25.9", "@babel/parser@^7.26.0", "@babel/parser@^7.26.2":
version "7.26.2"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.2.tgz#fd7b6f487cfea09889557ef5d4eeb9ff9a5abd11"
@ -181,6 +237,13 @@
dependencies:
"@babel/types" "^7.26.0"
"@babel/parser@^7.26.10", "@babel/parser@^7.26.9":
version "7.26.10"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.10.tgz#e9bdb82f14b97df6569b0b038edd436839c57749"
integrity sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA==
dependencies:
"@babel/types" "^7.26.10"
"@babel/plugin-proposal-decorators@^7.23.0":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.25.9.tgz#8680707f943d1a3da2cd66b948179920f097e254"
@ -250,6 +313,28 @@
"@babel/parser" "^7.25.9"
"@babel/types" "^7.25.9"
"@babel/template@^7.26.9":
version "7.26.9"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.26.9.tgz#4577ad3ddf43d194528cff4e1fa6b232fa609bb2"
integrity sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==
dependencies:
"@babel/code-frame" "^7.26.2"
"@babel/parser" "^7.26.9"
"@babel/types" "^7.26.9"
"@babel/traverse@^7.25.3", "@babel/traverse@^7.26.10":
version "7.26.10"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.26.10.tgz#43cca33d76005dbaa93024fae536cc1946a4c380"
integrity sha512-k8NuDrxr0WrPH5Aupqb2LCVURP/S0vBEn5mK6iH+GIYob66U5EtoZvcdudR2jQ4cmTwhEwW1DLB+Yyas9zjF6A==
dependencies:
"@babel/code-frame" "^7.26.2"
"@babel/generator" "^7.26.10"
"@babel/parser" "^7.26.10"
"@babel/template" "^7.26.9"
"@babel/types" "^7.26.10"
debug "^4.3.1"
globals "^11.1.0"
"@babel/traverse@^7.25.6", "@babel/traverse@^7.25.9":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.9.tgz#a50f8fe49e7f69f53de5bea7e413cd35c5e13c84"
@ -271,6 +356,14 @@
"@babel/helper-string-parser" "^7.25.9"
"@babel/helper-validator-identifier" "^7.25.9"
"@babel/types@^7.26.10", "@babel/types@^7.26.9":
version "7.26.10"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.10.tgz#396382f6335bd4feb65741eacfc808218f859259"
integrity sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==
dependencies:
"@babel/helper-string-parser" "^7.25.9"
"@babel/helper-validator-identifier" "^7.25.9"
"@cloudflare/kv-asset-handler@^0.3.4":
version "0.3.4"
resolved "https://registry.yarnpkg.com/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.3.4.tgz#5cc152847c8ae4d280ec5d7f4f6ba8c976b585c3"
@ -836,6 +929,34 @@
unimport "^3.13.1"
untyped "^1.5.1"
"@nuxt/kit@^3.11.2":
version "3.16.0"
resolved "https://registry.yarnpkg.com/@nuxt/kit/-/kit-3.16.0.tgz#ce78cfd7aac9d43596d36a078e52b4ba610a7c0a"
integrity sha512-yPfhk58BG6wJhELkGOTCOlkMDbZkizk3IaINcyTKm+hBKiK3SheLt7S9HStNL+qZSfH2Cf7A8sYp6M72lOIEtA==
dependencies:
c12 "^3.0.2"
consola "^3.4.0"
defu "^6.1.4"
destr "^2.0.3"
errx "^0.1.0"
exsolve "^1.0.2"
globby "^14.1.0"
ignore "^7.0.3"
jiti "^2.4.2"
klona "^2.0.6"
knitwork "^1.2.0"
mlly "^1.7.4"
ohash "^2.0.11"
pathe "^2.0.3"
pkg-types "^2.1.0"
scule "^1.3.0"
semver "^7.7.1"
std-env "^3.8.1"
ufo "^1.5.4"
unctx "^2.4.1"
unimport "^4.1.2"
untyped "^2.0.0"
"@nuxt/schema@3.14.0", "@nuxt/schema@^3.13.2":
version "3.14.0"
resolved "https://registry.yarnpkg.com/@nuxt/schema/-/schema-3.14.0.tgz#b98223ecf5d5469b126b056842b317ef6105a5c1"
@ -2128,6 +2249,13 @@ base64-js@^1.3.1:
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
basic-auth@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a"
integrity sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==
dependencies:
safe-buffer "5.1.2"
bcryptjs@^2.4.3:
version "2.4.3"
resolved "https://registry.yarnpkg.com/bcryptjs/-/bcryptjs-2.4.3.tgz#9ab5627b93e60621ff7cdac5da9733027df1d0cb"
@ -2230,6 +2358,24 @@ c12@2.0.1, c12@^2.0.1:
pkg-types "^1.2.0"
rc9 "^2.1.2"
c12@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/c12/-/c12-3.0.2.tgz#5ceba55cf081ff4cf95b22c593c80b34cf1f3d2e"
integrity sha512-6Tzk1/TNeI3WBPpK0j/Ss4+gPj3PUJYbWl/MWDJBThFvwNGNkXtd7Cz8BJtD4aRwoGHtzQD0SnxamgUiBH0/Nw==
dependencies:
chokidar "^4.0.3"
confbox "^0.1.8"
defu "^6.1.4"
dotenv "^16.4.7"
exsolve "^1.0.0"
giget "^2.0.0"
jiti "^2.4.2"
ohash "^2.0.5"
pathe "^2.0.3"
perfect-debounce "^1.0.0"
pkg-types "^2.0.0"
rc9 "^2.1.2"
cac@^6.7.14:
version "6.7.14"
resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959"
@ -2335,6 +2481,13 @@ chokidar@^4.0.0, chokidar@^4.0.1:
dependencies:
readdirp "^4.0.1"
chokidar@^4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.3.tgz#7be37a4c03c9aee1ecfe862a4a23b2c70c205d30"
integrity sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==
dependencies:
readdirp "^4.0.1"
chownr@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece"
@ -2424,7 +2577,7 @@ comma-separated-tokens@^2.0.0:
resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz#4e89c9458acb61bc8fef19f4529973b2392839ee"
integrity sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==
commander@^2.20.0:
commander@^2.20.0, commander@^2.20.3:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
@ -2485,11 +2638,21 @@ confbox@^0.1.7, confbox@^0.1.8:
resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.8.tgz#820d73d3b3c82d9bd910652c5d4d599ef8ff8b06"
integrity sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==
confbox@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.2.1.tgz#ae39f2c99699afa451d00206479f15f9a1208a8b"
integrity sha512-hkT3yDPFbs95mNCy1+7qNKC6Pro+/ibzYxtM2iqEigpf0sVw+bg4Zh9/snjsBcf990vfIsg5+1U7VyiyBb3etg==
consola@^3.2.3:
version "3.2.3"
resolved "https://registry.yarnpkg.com/consola/-/consola-3.2.3.tgz#0741857aa88cfa0d6fd53f1cff0375136e98502f"
integrity sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==
consola@^3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/consola/-/consola-3.4.0.tgz#4cfc9348fd85ed16a17940b3032765e31061ab88"
integrity sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==
console-control-strings@^1.0.0, console-control-strings@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
@ -2623,6 +2786,11 @@ cssesc@^3.0.0:
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
cssfilter@0.0.10:
version "0.0.10"
resolved "https://registry.yarnpkg.com/cssfilter/-/cssfilter-0.0.10.tgz#c6d2672632a2e5c83e013e6864a42ce8defd20ae"
integrity sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==
cssnano-preset-default@^7.0.6:
version "7.0.6"
resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-7.0.6.tgz#0220fa7507478369aa2a226bac03e1204cd024c1"
@ -2757,7 +2925,7 @@ define-lazy-prop@^3.0.0:
resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz#dbb19adfb746d7fc6d734a06b72f4a00d021255f"
integrity sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==
defu@^6.1.4:
defu@^6.1.1, defu@^6.1.4:
version "6.1.4"
resolved "https://registry.yarnpkg.com/defu/-/defu-6.1.4.tgz#4e0c9cf9ff68fe5f3d7f2765cc1a012dfdcb0479"
integrity sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==
@ -2886,6 +3054,11 @@ dotenv@^16.4.5:
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f"
integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==
dotenv@^16.4.7:
version "16.4.7"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.7.tgz#0e20c5b82950140aa99be360a8a5f52335f53c26"
integrity sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==
duplexer@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6"
@ -3114,6 +3287,11 @@ execa@^8.0.1:
signal-exit "^4.1.0"
strip-final-newline "^3.0.0"
exsolve@^1.0.0, exsolve@^1.0.1, exsolve@^1.0.2:
version "1.0.4"
resolved "https://registry.yarnpkg.com/exsolve/-/exsolve-1.0.4.tgz#7de5c75af82ecd15998328fbf5f2295883be3a39"
integrity sha512-xsZH6PXaER4XoV+NiT7JHp1bJodJVT+cxeSH1G0f0tlT0lJqYuHUP3bUx2HtfTDvOagMINYp8rsqusxud3RXhw==
extend@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
@ -3157,6 +3335,17 @@ fast-glob@^3.2.7, fast-glob@^3.3.2:
merge2 "^1.3.0"
micromatch "^4.0.4"
fast-glob@^3.3.3:
version "3.3.3"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818"
integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==
dependencies:
"@nodelib/fs.stat" "^2.0.2"
"@nodelib/fs.walk" "^1.2.3"
glob-parent "^5.1.2"
merge2 "^1.3.0"
micromatch "^4.0.8"
fast-npm-meta@^0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/fast-npm-meta/-/fast-npm-meta-0.2.2.tgz#619e4ab6b71f4ce19d9fad48bba6ffa8164b7361"
@ -3174,6 +3363,11 @@ fdir@^6.2.0, fdir@^6.4.2:
resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.2.tgz#ddaa7ce1831b161bc3657bb99cb36e1622702689"
integrity sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==
fdir@^6.4.3:
version "6.4.3"
resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.3.tgz#011cdacf837eca9b811c89dbb902df714273db72"
integrity sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==
file-type-mime@^0.4.3:
version "0.4.5"
resolved "https://registry.yarnpkg.com/file-type-mime/-/file-type-mime-0.4.5.tgz#acfbcfe088ed07eb8b6b3eefc16a419a80d57547"
@ -3337,6 +3531,18 @@ giget@^1.2.3:
pathe "^1.1.2"
tar "^6.2.0"
giget@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/giget/-/giget-2.0.0.tgz#395fc934a43f9a7a29a29d55b99f23e30c14f195"
integrity sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==
dependencies:
citty "^0.1.6"
consola "^3.4.0"
defu "^6.1.4"
node-fetch-native "^1.6.6"
nypm "^0.6.0"
pathe "^2.0.3"
git-config-path@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/git-config-path/-/git-config-path-2.0.0.tgz#62633d61af63af4405a5024efd325762f58a181b"
@ -3424,6 +3630,18 @@ globby@^14.0.2:
slash "^5.1.0"
unicorn-magic "^0.1.0"
globby@^14.1.0:
version "14.1.0"
resolved "https://registry.yarnpkg.com/globby/-/globby-14.1.0.tgz#138b78e77cf5a8d794e327b15dce80bf1fb0a73e"
integrity sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==
dependencies:
"@sindresorhus/merge-streams" "^2.1.0"
fast-glob "^3.3.3"
ignore "^7.0.3"
path-type "^6.0.0"
slash "^5.1.0"
unicorn-magic "^0.3.0"
graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.9:
version "4.2.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
@ -3709,6 +3927,11 @@ ignore@^6.0.2:
resolved "https://registry.yarnpkg.com/ignore/-/ignore-6.0.2.tgz#77cccb72a55796af1b6d2f9eb14fa326d24f4283"
integrity sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A==
ignore@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-7.0.3.tgz#397ef9315dfe0595671eefe8b633fec6943ab733"
integrity sha512-bAH5jbK/F3T3Jls4I0SO1hmPR0dKU0a7+SY6n1yzRtG54FLO8d6w/nxLFX2Nb7dBu6cCWXPaAME6cYqFUMmuCA==
image-meta@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/image-meta/-/image-meta-0.2.1.tgz#3a9eb9f0bfd2f767ca2b0720623c2e03742aa29f"
@ -4005,6 +4228,11 @@ js-tokens@^9.0.0:
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-9.0.0.tgz#0f893996d6f3ed46df7f0a3b12a03f5fd84223c1"
integrity sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==
js-tokens@^9.0.1:
version "9.0.1"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-9.0.1.tgz#2ec43964658435296f6761b34e10671c2d9527f4"
integrity sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==
js-yaml@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
@ -4058,6 +4286,11 @@ knitwork@^1.0.0, knitwork@^1.1.0:
resolved "https://registry.yarnpkg.com/knitwork/-/knitwork-1.1.0.tgz#d8c9feafadd7ee744ff64340b216a52c7199c417"
integrity sha512-oHnmiBUVHz1V+URE77PNot2lv3QiYU2zQf1JjOVkMt3YDKGbu8NAFr+c4mcNOhdsGrB/VpVbRwPwhiXrPhxQbw==
knitwork@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/knitwork/-/knitwork-1.2.0.tgz#3cc92e76249aeb35449cfbed3f31c6df8444db3f"
integrity sha512-xYSH7AvuQ6nXkq42x0v5S8/Iry+cfulBz/DJQzhIyESdLD7425jXsPy4vn5cCXU+HhRN2kVw51Vd1K6/By4BQg==
koa-compose@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-4.1.0.tgz#507306b9371901db41121c812e923d0d67d3e877"
@ -4252,6 +4485,15 @@ local-pkg@^0.5.0:
mlly "^1.4.2"
pkg-types "^1.0.3"
local-pkg@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-1.1.1.tgz#f5fe74a97a3bd3c165788ee08ca9fbe998dc58dd"
integrity sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==
dependencies:
mlly "^1.7.4"
pkg-types "^2.0.1"
quansync "^0.2.8"
lodash.castarray@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/lodash.castarray/-/lodash.castarray-4.4.0.tgz#c02513515e309daddd4c24c60cfddcf5976d9115"
@ -4328,6 +4570,13 @@ magic-string@^0.30.0, magic-string@^0.30.10, magic-string@^0.30.11, magic-string
dependencies:
"@jridgewell/sourcemap-codec" "^1.5.0"
magic-string@^0.30.17:
version "0.30.17"
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.17.tgz#450a449673d2460e5bbcfba9a61916a1714c7453"
integrity sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==
dependencies:
"@jridgewell/sourcemap-codec" "^1.5.0"
magicast@^0.3.5:
version "0.3.5"
resolved "https://registry.yarnpkg.com/magicast/-/magicast-0.3.5.tgz#8301c3c7d66704a0771eb1bad74274f0ec036739"
@ -4946,6 +5195,16 @@ mlly@^1.3.0, mlly@^1.4.2, mlly@^1.6.1, mlly@^1.7.1, mlly@^1.7.2:
pkg-types "^1.2.0"
ufo "^1.5.4"
mlly@^1.7.4:
version "1.7.4"
resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.7.4.tgz#3d7295ea2358ec7a271eaa5d000a0f84febe100f"
integrity sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==
dependencies:
acorn "^8.14.0"
pathe "^2.0.1"
pkg-types "^1.3.0"
ufo "^1.5.4"
moment@^2.30.1:
version "2.30.1"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae"
@ -5099,6 +5358,11 @@ node-fetch-native@^1.6.3, node-fetch-native@^1.6.4:
resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.6.4.tgz#679fc8fd8111266d47d7e72c379f1bed9acff06e"
integrity sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==
node-fetch-native@^1.6.6:
version "1.6.6"
resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.6.6.tgz#ae1d0e537af35c2c0b0de81cbff37eedd410aa37"
integrity sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ==
node-fetch@^2.6.1, node-fetch@^2.6.7:
version "2.7.0"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d"
@ -5174,6 +5438,28 @@ nuxi@^3.15.0:
resolved "https://registry.yarnpkg.com/nuxi/-/nuxi-3.15.0.tgz#ed54923ca46727c6e7df10495143db340d9791c9"
integrity sha512-ZVu45nuDrdb7nzKW2kLGY/N1vvFYLLbUVX6gUYw4BApKGGu4+GktTR5o48dGVgMYX9A8chaugl7TL9ZYmwC9Mg==
nuxt-csurf@^1.6.5:
version "1.6.5"
resolved "https://registry.yarnpkg.com/nuxt-csurf/-/nuxt-csurf-1.6.5.tgz#c900f8817f565d91fe35c712dde7f2b0b46b8c20"
integrity sha512-/DMNTON8LIVhntamKbBmAuM879B0QnuSJa7ZAkmkZe+21m+1QGcjVUxtSkizaM48NUvkuAGYOG0ncn+kqEgrzw==
dependencies:
"@nuxt/kit" "^3.13.2"
defu "^6.1.4"
uncsrf "^1.2.0"
nuxt-security@2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/nuxt-security/-/nuxt-security-2.2.0.tgz#c9c17f9023b289c97c0f85a1a2f6c13f18d07325"
integrity sha512-bTdgAAAdnvM1R1wAX3zQBbYJh6YNFyvsKJwbT9oVv+0U9J/9+k+mufQlJMFO8AdTefi/EDFHG75in9RTnCpngQ==
dependencies:
"@nuxt/kit" "^3.11.2"
basic-auth "^2.0.1"
defu "^6.1.1"
nuxt-csurf "^1.6.5"
pathe "^1.0.0"
unplugin-remove "^1.0.3"
xss "^1.0.14"
nuxt@^3.13.2:
version "3.14.0"
resolved "https://registry.yarnpkg.com/nuxt/-/nuxt-3.14.0.tgz#a3e5c39f6eced7336384b92579a5dbf35f63ba00"
@ -5256,6 +5542,17 @@ nypm@^0.3.11, nypm@^0.3.12, nypm@^0.3.8:
pkg-types "^1.2.0"
ufo "^1.5.4"
nypm@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/nypm/-/nypm-0.6.0.tgz#3a04623d1c358a93fc4b3cb9cfb6a11af080feca"
integrity sha512-mn8wBFV9G9+UFHIrq+pZ2r2zL4aPau/by3kJb3cM7+5tQHMt6HGQB8FDIeKFYp8o0D2pnH6nVsO88N4AmUxIWg==
dependencies:
citty "^0.1.6"
consola "^3.4.0"
pathe "^2.0.3"
pkg-types "^2.0.0"
tinyexec "^0.3.2"
object-assign@^4.0.1, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
@ -5280,6 +5577,11 @@ ohash@^1.1.3, ohash@^1.1.4:
resolved "https://registry.yarnpkg.com/ohash/-/ohash-1.1.4.tgz#ae8d83014ab81157d2c285abf7792e2995fadd72"
integrity sha512-FlDryZAahJmEF3VR3w1KogSEdWX3WhA5GPakFx4J81kEAiHyLMpdLLElS8n8dfNadMgAne/MywcvmogzscVt4g==
ohash@^2.0.11, ohash@^2.0.5:
version "2.0.11"
resolved "https://registry.yarnpkg.com/ohash/-/ohash-2.0.11.tgz#60b11e8cff62ca9dee88d13747a5baa145f5900b"
integrity sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==
on-finished@2.4.1, on-finished@^2.3.0:
version "2.4.1"
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
@ -5462,11 +5764,21 @@ path-type@^5.0.0:
resolved "https://registry.yarnpkg.com/path-type/-/path-type-5.0.0.tgz#14b01ed7aea7ddf9c7c3f46181d4d04f9c785bb8"
integrity sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==
pathe@^1.1.1, pathe@^1.1.2:
path-type@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-6.0.0.tgz#2f1bb6791a91ce99194caede5d6c5920ed81eb51"
integrity sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==
pathe@^1.0.0, pathe@^1.1.1, pathe@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.2.tgz#6c4cb47a945692e48a1ddd6e4094d170516437ec"
integrity sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==
pathe@^2.0.1, pathe@^2.0.2, pathe@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/pathe/-/pathe-2.0.3.tgz#3ecbec55421685b70a9da872b2cff3e1cbed1716"
integrity sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==
peek-readable@^5.1.3:
version "5.3.1"
resolved "https://registry.yarnpkg.com/peek-readable/-/peek-readable-5.3.1.tgz#9cc2c275cceda9f3d07a988f4f664c2080387dff"
@ -5511,6 +5823,24 @@ pkg-types@^1.0.3, pkg-types@^1.2.0, pkg-types@^1.2.1:
mlly "^1.7.2"
pathe "^1.1.2"
pkg-types@^1.3.0, pkg-types@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.3.1.tgz#bd7cc70881192777eef5326c19deb46e890917df"
integrity sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==
dependencies:
confbox "^0.1.8"
mlly "^1.7.4"
pathe "^2.0.1"
pkg-types@^2.0.0, pkg-types@^2.0.1, pkg-types@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-2.1.0.tgz#70c9e1b9c74b63fdde749876ee0aa007ea9edead"
integrity sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==
dependencies:
confbox "^0.2.1"
exsolve "^1.0.1"
pathe "^2.0.3"
pluralize@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1"
@ -5849,6 +6179,11 @@ proxy-from-env@^1.1.0:
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
quansync@^0.2.8:
version "0.2.8"
resolved "https://registry.yarnpkg.com/quansync/-/quansync-0.2.8.tgz#2e893d17bb754ba0988ea399ff0bc5f2a8467793"
integrity sha512-4+saucphJMazjt7iOM27mbFCk+D9dd/zmgMDCzRZ8MEoBfYp7lAvoN38et/phRQF6wOPMy/OROBGgoWeSKyluA==
queue-microtask@^1.2.2:
version "1.2.3"
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
@ -6200,16 +6535,16 @@ run-parallel@^1.1.9:
dependencies:
queue-microtask "^1.2.2"
safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
safe-buffer@5.2.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
sanitize-filename@^1.6.3:
version "1.6.3"
resolved "https://registry.yarnpkg.com/sanitize-filename/-/sanitize-filename-1.6.3.tgz#755ebd752045931977e30b2025d340d7c9090378"
@ -6243,6 +6578,11 @@ semver@^7.3.4, semver@^7.3.5, semver@^7.6.3:
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143"
integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==
semver@^7.7.1:
version "7.7.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f"
integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==
send@0.19.0:
version "0.19.0"
resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8"
@ -6461,6 +6801,11 @@ std-env@^3.7.0:
resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.7.0.tgz#c9f7386ced6ecf13360b6c6c55b8aaa4ef7481d2"
integrity sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==
std-env@^3.8.1:
version "3.8.1"
resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.8.1.tgz#2b81c631c62e3d0b964b87f099b8dcab6c9a5346"
integrity sha512-vj5lIj3Mwf9D79hBkltk5qmkFI+biIKWS2IBxEyEU3AX1tUf7AoL8nSazCOiiqQsGKIq01SClsKEzweu34uwvA==
stream-head@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/stream-head/-/stream-head-3.0.0.tgz#cf69c14f3f6d8c63b1475a0e3ccc0ee58ddd2c1c"
@ -6577,6 +6922,13 @@ strip-literal@^2.1.0:
dependencies:
js-tokens "^9.0.0"
strip-literal@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/strip-literal/-/strip-literal-3.0.0.tgz#ce9c452a91a0af2876ed1ae4e583539a353df3fc"
integrity sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==
dependencies:
js-tokens "^9.0.1"
strtok3@^7.0.0:
version "7.1.1"
resolved "https://registry.yarnpkg.com/strtok3/-/strtok3-7.1.1.tgz#f548fd9dc59d0a76d5567ff8c16be31221f29dfc"
@ -6777,6 +7129,11 @@ tiny-invariant@^1.1.0:
resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127"
integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==
tinyexec@^0.3.2:
version "0.3.2"
resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-0.3.2.tgz#941794e657a85e496577995c6eef66f53f42b3d2"
integrity sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==
tinyglobby@0.2.10, tinyglobby@^0.2.6:
version "0.2.10"
resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.10.tgz#e712cf2dc9b95a1f5c5bbd159720e15833977a0f"
@ -6785,6 +7142,14 @@ tinyglobby@0.2.10, tinyglobby@^0.2.6:
fdir "^6.4.2"
picomatch "^4.0.2"
tinyglobby@^0.2.11:
version "0.2.12"
resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.12.tgz#ac941a42e0c5773bd0b5d08f32de82e74a1a61b5"
integrity sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==
dependencies:
fdir "^6.4.3"
picomatch "^4.0.2"
to-regex-range@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
@ -6882,6 +7247,11 @@ uncrypto@^0.1.3:
resolved "https://registry.yarnpkg.com/uncrypto/-/uncrypto-0.1.3.tgz#e1288d609226f2d02d8d69ee861fa20d8348ef2b"
integrity sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==
uncsrf@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/uncsrf/-/uncsrf-1.2.0.tgz#ed6ee2609726848869983cc639b907abed9dff21"
integrity sha512-EyeG1tIx1zisLuqokSXZ5LhndzaUd2WBMS+18IlBUYobJsKSUQMpLIEm6QUfY/Azmhnnz0v2QbkrT6/u2K/Y1g==
unctx@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/unctx/-/unctx-2.3.1.tgz#5eb4aa9f96fb5fdac18b88fe5ba8e122fe671a62"
@ -6892,6 +7262,16 @@ unctx@^2.3.1:
magic-string "^0.30.0"
unplugin "^1.3.1"
unctx@^2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/unctx/-/unctx-2.4.1.tgz#93346a98d4a38c64cc5861f6098f4ce7c6f8164a"
integrity sha512-AbaYw0Nm4mK4qjhns67C+kgxR2YWiwlDBPzxrN8h8C6VtAdCgditAY5Dezu3IJy4XVqAnbrXt9oQJvsn3fyozg==
dependencies:
acorn "^8.14.0"
estree-walker "^3.0.3"
magic-string "^0.30.17"
unplugin "^2.1.0"
undici-types@~6.19.8:
version "6.19.8"
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02"
@ -6936,6 +7316,11 @@ unicorn-magic@^0.1.0:
resolved "https://registry.yarnpkg.com/unicorn-magic/-/unicorn-magic-0.1.0.tgz#1bb9a51c823aaf9d73a8bfcd3d1a23dde94b0ce4"
integrity sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==
unicorn-magic@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/unicorn-magic/-/unicorn-magic-0.3.0.tgz#4efd45c85a69e0dd576d25532fbfa22aa5c8a104"
integrity sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==
unified@^11.0.0, unified@^11.0.4, unified@^11.0.5:
version "11.0.5"
resolved "https://registry.yarnpkg.com/unified/-/unified-11.0.5.tgz#f66677610a5c0a9ee90cab2b8d4d66037026d9e1"
@ -6968,6 +7353,26 @@ unimport@^3.12.0, unimport@^3.13.1:
strip-literal "^2.1.0"
unplugin "^1.14.1"
unimport@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/unimport/-/unimport-4.1.2.tgz#10ba452519ec23113c1e68b8e9ab26c307a6eebd"
integrity sha512-oVUL7PSlyVV3QRhsdcyYEMaDX8HJyS/CnUonEJTYA3//bWO+o/4gG8F7auGWWWkrrxBQBYOO8DKe+C53ktpRXw==
dependencies:
acorn "^8.14.0"
escape-string-regexp "^5.0.0"
estree-walker "^3.0.3"
local-pkg "^1.0.0"
magic-string "^0.30.17"
mlly "^1.7.4"
pathe "^2.0.3"
picomatch "^4.0.2"
pkg-types "^1.3.1"
scule "^1.3.0"
strip-literal "^3.0.0"
tinyglobby "^0.2.11"
unplugin "^2.2.0"
unplugin-utils "^0.2.4"
unist-builder@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/unist-builder/-/unist-builder-4.0.0.tgz#817b326c015a6f9f5e92bb55b8e8bc5e578fe243"
@ -7018,6 +7423,27 @@ universalify@^2.0.0:
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d"
integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==
unplugin-remove@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/unplugin-remove/-/unplugin-remove-1.0.3.tgz#daf24110c2a0f5f679bb72aed9418078b1008043"
integrity sha512-BZMt9v8Y/Z27cY7YQv+DpcW928znjP1cqplBXOirbANiFQtM2YCdiyNAJhHCvjppT0lScNn1aDrQnXqnRp32pQ==
dependencies:
"@babel/core" "^7.25.2"
"@babel/generator" "^7.25.0"
"@babel/parser" "^7.25.3"
"@babel/traverse" "^7.25.3"
"@rollup/pluginutils" "^5.1.0"
magic-string "^0.30.11"
unplugin "^1.12.0"
unplugin-utils@^0.2.4:
version "0.2.4"
resolved "https://registry.yarnpkg.com/unplugin-utils/-/unplugin-utils-0.2.4.tgz#56e4029a6906645a10644f8befc404b06d5d24d0"
integrity sha512-8U/MtpkPkkk3Atewj1+RcKIjb5WBimZ/WSLhhR3w6SsIj8XJuKTacSP8g+2JhfSGw0Cb125Y+2zA/IzJZDVbhA==
dependencies:
pathe "^2.0.2"
picomatch "^4.0.2"
unplugin-vue-router@^0.10.8:
version "0.10.8"
resolved "https://registry.yarnpkg.com/unplugin-vue-router/-/unplugin-vue-router-0.10.8.tgz#a868cb64e3c27aba98b312aa757e8cb48830b891"
@ -7046,6 +7472,22 @@ unplugin@^1.10.0, unplugin@^1.12.2, unplugin@^1.14.1, unplugin@^1.15.0, unplugin
acorn "^8.14.0"
webpack-virtual-modules "^0.6.2"
unplugin@^1.12.0:
version "1.16.1"
resolved "https://registry.yarnpkg.com/unplugin/-/unplugin-1.16.1.tgz#a844d2e3c3b14a4ac2945c42be80409321b61199"
integrity sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==
dependencies:
acorn "^8.14.0"
webpack-virtual-modules "^0.6.2"
unplugin@^2.1.0, unplugin@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/unplugin/-/unplugin-2.2.0.tgz#2659dee5c6b3de9b7ea671228c18263886ae58b6"
integrity sha512-m1ekpSwuOT5hxkJeZGRxO7gXbXT3gF26NjQ7GdVHoLoF8/nopLcd/QfPigpCy7i51oFHiRJg/CyHhj4vs2+KGw==
dependencies:
acorn "^8.14.0"
webpack-virtual-modules "^0.6.2"
unstorage@^1.12.0, unstorage@^1.13.1:
version "1.13.1"
resolved "https://registry.yarnpkg.com/unstorage/-/unstorage-1.13.1.tgz#090b30de978ee8755b3ad7bbc00acfade124ac13"
@ -7084,6 +7526,17 @@ untyped@^1.5.1:
mri "^1.2.0"
scule "^1.3.0"
untyped@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/untyped/-/untyped-2.0.0.tgz#86bc205a4ec4b0137282285866b8278557aeee97"
integrity sha512-nwNCjxJTjNuLCgFr42fEak5OcLuB3ecca+9ksPFNvtfYSLpjf+iJqSIaSnIile6ZPbKYxI5k2AfXqeopGudK/g==
dependencies:
citty "^0.1.6"
defu "^6.1.4"
jiti "^2.4.2"
knitwork "^1.2.0"
scule "^1.3.0"
unwasm@^0.3.9:
version "0.3.9"
resolved "https://registry.yarnpkg.com/unwasm/-/unwasm-0.3.9.tgz#01eca80a1cf2133743bc1bf5cfa749cc145beea0"
@ -7429,6 +7882,14 @@ xmlhttprequest-ssl@~2.1.1:
resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz#e9e8023b3f29ef34b97a859f584c5e6c61418e23"
integrity sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==
xss@^1.0.14:
version "1.0.15"
resolved "https://registry.yarnpkg.com/xss/-/xss-1.0.15.tgz#96a0e13886f0661063028b410ed1b18670f4e59a"
integrity sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==
dependencies:
commander "^2.20.3"
cssfilter "0.0.10"
y18n@^5.0.5:
version "5.0.8"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"