diff --git a/README.md b/README.md index 33c4b6b..d06bb02 100644 --- a/README.md +++ b/README.md @@ -15,3 +15,110 @@ yarn ``` yarn add @nitrots/nitro-renderer ``` + +## JSON / JSON5 configuration parser + +Every configuration file and gamedata file loaded by the renderer (figuredata, +furnidata, productdata, effectmap, avatar actions, etc.) goes through +`@nitrots/utils` → `JsonParser.ts`. The parser supports three modes, selected at +the **host build time** through the compile-time constant `__NITRO_JSON_MODE__`: + +| Mode | Behaviour | +|----------|---------------------------------------------------------------------------| +| `legacy` | Strict `JSON.parse` only. Comments / trailing commas raise a clear error. | +| `json5` | `JSON5.parse` only. Accepts comments, trailing commas, single quotes. | +| `auto` | Try strict JSON first, fall back to JSON5. Default when the flag is unset.| + +URL hints are still honoured: files ending in `.json5` (or served with a +`application/json5` content-type) always go through JSON5, regardless of mode. + +### Wiring the flag into a host + +The renderer does **not** ship its own build for the flag — the host application +(typically [Nitro V3](https://github.com/duckietm/Nitro-V3.git)) defines it via +its bundler. Example with Vite: + +```js +// vite.config.mjs in the host +export default defineConfig({ + define: { + __NITRO_JSON_MODE__: JSON.stringify('json5') // or 'legacy' / 'auto' + } +}); +``` + +If the constant is not defined the parser falls back to `auto`, which preserves +the original behaviour of older releases — so existing hosts keep working +without any change. + +### Using the parser directly + +```ts +import { parseConfigJson, fetchConfigJson } from '@nitrots/utils'; + +const data = parseConfigJson(rawText, '/configuration/ui-config.json'); +const data2 = await fetchConfigJson('/configuration/ui-config.json5'); +``` + +Errors carry the source URL and, in `legacy` mode, a hint about switching to +JSON5 — making misconfigurations easy to diagnose in production logs. + +## Split-aware gamedata loader + +`@nitrots/utils` also exports `loadGamedata`, the loader that backs every +gamedata consumer in the renderer (FurnitureDataLoader, ProductDataLoader, +EffectAssetDownloadManager, AvatarRenderManager, LocalizationManager). It +accepts either a **single-file URL** (legacy) or a **directory URL** (split +mode) — detected automatically by the trailing slash. + +### Directory layout + +``` +/ + manifest.json5 # OPTIONAL — { "tiers": ["core", "custom", "seasonal"] } + core/ + manifest.json5 # REQUIRED — { "files": ["a.json5", "b.json5", ...] } + a.json5 + b.json5 + custom/ # OPTIONAL tier + manifest.json5 + overrides.json5 + seasonal/ # OPTIONAL tier + manifest.json5 + xmas.json5 +``` + +If the directory `manifest.json5` is absent, the loader falls back to the +default tier order `core → custom → seasonal`. Each tier is skipped silently +if its `manifest.json5` is missing. + +### Merge semantics + +`mergeGamedata(a, b)` (also exported) implements the rules below; tiers and +files within a tier are merged in order, with later layers overriding +earlier ones: + +| Combination | Result | +|------------------------------------------|----------------------------------------------| +| Two plain objects | recursive merge, key by key | +| Two arrays of objects sharing an id key | merged by id (later overrides earlier) | +| Two arrays without an id key | concatenated | +| Anything else | later value wins | + +Recognised id keys (in priority order): `id`, `classname`, `name`. Pass +`mergeArrayIdKeys` in the options object to extend or override them. + +### Programmatic usage + +```ts +import { loadGamedata, mergeGamedata } from '@nitrots/utils'; + +// host code never needs to care whether the URL is split or not +const furnidata = await loadGamedata('https://example.com/gamedata/furnidata/'); + +// merge ad-hoc if you load tiers manually +const merged = mergeGamedata(coreData, customData); +``` + +A CLI splitter for legacy single-file gamedata lives in the Nitro V3 client +repo at `scripts/split-gamedata.mjs` — see the Nitro V3 README for usage. diff --git a/package.json b/package.json index e007a89..60ecedc 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "@thumbmarkjs/thumbmarkjs": "^1.9.0", "gifuct-js": "^2.1.2", "howler": "^2.2.4", + "json5": "^2.2.3", "pako": "^2.1.0", "pixi-filters": "^6.1.5", "pixi.js": "^8.18.1" diff --git a/packages/assets/src/AssetManager.ts b/packages/assets/src/AssetManager.ts index 7d992f7..a9d652a 100644 --- a/packages/assets/src/AssetManager.ts +++ b/packages/assets/src/AssetManager.ts @@ -1,5 +1,5 @@ import { IAssetData, IAssetManager, IGraphicAsset, IGraphicAssetCollection } from '@nitrots/api'; -import { NitroBundle, NitroLogger } from '@nitrots/utils'; +import { NitroBundle, NitroLogger, parseConfigJsonFromResponse } from '@nitrots/utils'; import { AnimatedGIF } from '@pixi/gif'; import { Assets, Spritesheet, SpritesheetData, Texture } from 'pixi.js'; import { GraphicAssetCollection } from './GraphicAssetCollection'; @@ -159,7 +159,7 @@ export class AssetManager implements IAssetManager } } } - else if(url.endsWith('.json')) + else if(url.endsWith('.json') || url.endsWith('.json5')) { let response: Response; @@ -178,18 +178,18 @@ export class AssetManager implements IAssetManager try { - data = await response.json() as IAssetData; + data = await parseConfigJsonFromResponse(response, url); } catch(parseErr) { - throw new Error(`Invalid JSON in "${ url }" — the URL may be wrong and returning an HTML page instead of JSON (${ parseErr.message })`); + throw new Error(`Invalid asset data "${ url }" — JSON/JSON5 parse failed (${ parseErr.message })`); } let texture: Texture = null; const imagePath = data?.spritesheet?.meta?.image; const fallbackImagePath = ((data?.name && data.name.length > 0) ? `${data.name}.png` - : url.replace(/\.json$/i, '.png')); + : url.replace(/\.json5?$/i, '.png')); const resolvedImageUrl = (imagePath ? new URL(imagePath, url).toString() : new URL(fallbackImagePath, url).toString()); diff --git a/packages/avatar/src/AvatarAssetDownloadManager.ts b/packages/avatar/src/AvatarAssetDownloadManager.ts index ada5077..3eec7bd 100644 --- a/packages/avatar/src/AvatarAssetDownloadManager.ts +++ b/packages/avatar/src/AvatarAssetDownloadManager.ts @@ -1,6 +1,7 @@ import { IAssetManager, IAvatarFigureContainer, IAvatarImageListener } from '@nitrots/api'; import { GetConfiguration } from '@nitrots/configuration'; import { AvatarRenderLibraryEvent, GetEventDispatcher, NitroEvent, NitroEventType } from '@nitrots/events'; +import { parseConfigJsonFromResponse } from '@nitrots/utils'; import { AvatarAssetDownloadLibrary } from './AvatarAssetDownloadLibrary'; import { AvatarStructure } from './AvatarStructure'; @@ -57,11 +58,11 @@ export class AvatarAssetDownloadManager try { - responseData = await response.json(); + responseData = await parseConfigJsonFromResponse(response, url); } catch(parseErr) { - throw new Error(`Invalid JSON in figure map "${ url }" — the URL may be wrong. Check "avatar.figuremap.url" in renderer-config.json (${ parseErr.message })`); + throw new Error(`Invalid figure map "${ url }" — JSON/JSON5 parse failed. Check "avatar.figuremap.url" in renderer-config.json (${ parseErr.message })`); } this.processFigureMap(responseData.libraries); diff --git a/packages/avatar/src/AvatarRenderManager.ts b/packages/avatar/src/AvatarRenderManager.ts index 57a8694..af0790e 100644 --- a/packages/avatar/src/AvatarRenderManager.ts +++ b/packages/avatar/src/AvatarRenderManager.ts @@ -2,6 +2,7 @@ import { AvatarSetType, IAssetManager, IAvatarEffectListener, IAvatarFigureConta import { GetAssetManager } from '@nitrots/assets'; import { GetConfiguration } from '@nitrots/configuration'; import { GetEventDispatcher, NitroEventType } from '@nitrots/events'; +import { loadGamedata } from '@nitrots/utils'; import { AvatarAssetDownloadManager } from './AvatarAssetDownloadManager'; import { AvatarFigureContainer } from './AvatarFigureContainer'; import { AvatarImage } from './AvatarImage'; @@ -72,26 +73,13 @@ export class AvatarRenderManager implements IAvatarRenderManager if(!url || !url.length) throw new Error('Missing "avatar.actions.url" in config — add the URL to your renderer-config.json'); - let response: Response; - try { - response = await fetch(url); + this._structure.updateActions(await loadGamedata(url)); } - catch(fetchErr) + catch(err) { - throw new Error(`Could not fetch avatar actions from "${ url }" — check "avatar.actions.url" in renderer-config.json (${ fetchErr.message })`); - } - - if(response.status !== 200) throw new Error(`Failed to load avatar actions from "${ url }" — server returned HTTP ${ response.status }. Check "avatar.actions.url" in renderer-config.json`); - - try - { - this._structure.updateActions(await response.json()); - } - catch(parseErr) - { - throw new Error(`Invalid JSON from "${ url }" — the URL may be wrong and returning an HTML page instead of JSON. Check "avatar.actions.url" in renderer-config.json (${ parseErr.message })`); + throw new Error(`Could not load avatar actions from "${ url }" — check "avatar.actions.url" in renderer-config.json (${ err?.message || err })`); } } @@ -105,26 +93,13 @@ export class AvatarRenderManager implements IAvatarRenderManager if(!url || !url.length) throw new Error('Missing "avatar.figuredata.url" in config — add the URL to your renderer-config.json'); - let response: Response; - try { - response = await fetch(url); + this._structure.figureData.appendJSON(await loadGamedata(url)); } - catch(fetchErr) + catch(err) { - throw new Error(`Could not fetch figure data from "${ url }" — check "avatar.figuredata.url" in renderer-config.json (${ fetchErr.message })`); - } - - if(response.status !== 200) throw new Error(`Failed to load figure data from "${ url }" — server returned HTTP ${ response.status }. Check "avatar.figuredata.url" in renderer-config.json`); - - try - { - this._structure.figureData.appendJSON(await response.json()); - } - catch(parseErr) - { - throw new Error(`Invalid JSON from "${ url }" — the URL may be wrong and returning an HTML page instead of JSON. Check "avatar.figuredata.url" in renderer-config.json (${ parseErr.message })`); + throw new Error(`Could not load figure data from "${ url }" — check "avatar.figuredata.url" in renderer-config.json (${ err?.message || err })`); } this._structure.init(); diff --git a/packages/avatar/src/EffectAssetDownloadManager.ts b/packages/avatar/src/EffectAssetDownloadManager.ts index 9dae1d6..bbed796 100644 --- a/packages/avatar/src/EffectAssetDownloadManager.ts +++ b/packages/avatar/src/EffectAssetDownloadManager.ts @@ -1,6 +1,7 @@ import { IAssetManager, IAvatarEffectListener } from '@nitrots/api'; import { GetConfiguration } from '@nitrots/configuration'; import { AvatarRenderEffectLibraryEvent, GetEventDispatcher, NitroEvent, NitroEventType } from '@nitrots/events'; +import { loadGamedata } from '@nitrots/utils'; import { AvatarStructure } from './AvatarStructure'; import { EffectAssetDownloadLibrary } from './EffectAssetDownloadLibrary'; @@ -31,28 +32,15 @@ export class EffectAssetDownloadManager if(!url || !url.length) throw new Error('Missing "avatar.effectmap.url" in config — add the effect map URL to your renderer-config.json'); - let response: Response; - - try - { - response = await fetch(url); - } - catch(fetchErr) - { - throw new Error(`Could not fetch effect map from "${ url }" — check "avatar.effectmap.url" in renderer-config.json (${ fetchErr.message })`); - } - - if(response.status !== 200) throw new Error(`Failed to load effect map from "${ url }" — server returned HTTP ${ response.status }. Check "avatar.effectmap.url" in renderer-config.json`); - let responseData: any; try { - responseData = await response.json(); + responseData = await loadGamedata(url); } - catch(parseErr) + catch(err) { - throw new Error(`Invalid JSON in effect map "${ url }" — the URL may be wrong. Check "avatar.effectmap.url" in renderer-config.json (${ parseErr.message })`); + throw new Error(`Could not load effect map from "${ url }" — check "avatar.effectmap.url" in renderer-config.json (${ err?.message || err })`); } this.processEffectMap(responseData.effects); diff --git a/packages/configuration/src/ConfigurationManager.ts b/packages/configuration/src/ConfigurationManager.ts index 457adab..ff7366a 100644 --- a/packages/configuration/src/ConfigurationManager.ts +++ b/packages/configuration/src/ConfigurationManager.ts @@ -1,4 +1,4 @@ -import { NitroLogger, NitroVersion } from '@nitrots/utils'; +import { NitroLogger, NitroVersion, parseConfigJsonFromResponse } from '@nitrots/utils'; import { IConfigurationManager } from './IConfigurationManager'; export class ConfigurationManager implements IConfigurationManager @@ -54,11 +54,11 @@ export class ConfigurationManager implements IConfigurationManager try { - json = await response.json(); + json = await parseConfigJsonFromResponse(response, url); } catch(parseError) { - throw new Error(`Invalid JSON in config "${ url }" — check for syntax errors like trailing commas or missing quotes (${ parseError.message })`); + throw new Error(`Invalid config "${ url }" — JSON/JSON5 parse failed. JSON5 allows comments, trailing commas and unquoted keys (${ parseError.message })`); } this.parseConfiguration(json); diff --git a/packages/localization/package.json b/packages/localization/package.json index c275ef3..95e92b6 100644 --- a/packages/localization/package.json +++ b/packages/localization/package.json @@ -13,6 +13,7 @@ "@nitrots/communication": "1.0.0", "@nitrots/configuration": "1.0.0", "@nitrots/events": "1.0.0", + "@nitrots/utils": "1.0.0", "pixi.js": "^8.8.1" }, "devDependencies": { diff --git a/packages/localization/src/LocalizationManager.ts b/packages/localization/src/LocalizationManager.ts index 1acb949..3086bcc 100644 --- a/packages/localization/src/LocalizationManager.ts +++ b/packages/localization/src/LocalizationManager.ts @@ -1,6 +1,7 @@ import { ILocalizationManager } from '@nitrots/api'; import { BadgePointLimitsEvent, GetCommunication } from '@nitrots/communication'; import { GetConfiguration } from '@nitrots/configuration'; +import { loadGamedata } from '@nitrots/utils'; import { BadgeBaseAndLevel } from './BadgeBaseAndLevel'; export class LocalizationManager implements ILocalizationManager @@ -25,28 +26,15 @@ export class LocalizationManager implements ILocalizationManager url = GetConfiguration().interpolate(url); - let response: Response; - - try - { - response = await fetch(url); - } - catch(fetchErr) - { - throw new Error(`Could not fetch localization file "${ url }" — check "external.texts.url" in ui-config.json (${ fetchErr.message })`); - } - - if(response.status !== 200) throw new Error(`Failed to load localization file "${ url }" — server returned HTTP ${ response.status }. Check "external.texts.url" in ui-config.json`); - let data: any; try { - data = await response.json(); + data = await loadGamedata(url); } - catch(parseErr) + catch(err) { - throw new Error(`Invalid JSON in localization file "${ url }" — the URL may be wrong. Check "external.texts.url" in ui-config.json (${ parseErr.message })`); + throw new Error(`Could not load localization file "${ url }" — check "external.texts.url" in ui-config.json (${ err?.message || err })`); } this.parseLocalization(data); diff --git a/packages/session/package.json b/packages/session/package.json index d6edb8e..6cc8eb1 100644 --- a/packages/session/package.json +++ b/packages/session/package.json @@ -15,6 +15,7 @@ "@nitrots/configuration": "1.0.0", "@nitrots/events": "1.0.0", "@nitrots/localization": "1.0.0", + "@nitrots/utils": "1.0.0", "pixi.js": "^8.8.1" }, "devDependencies": { diff --git a/packages/session/src/SessionDataManager.ts b/packages/session/src/SessionDataManager.ts index c92c52a..c2f15e9 100644 --- a/packages/session/src/SessionDataManager.ts +++ b/packages/session/src/SessionDataManager.ts @@ -3,7 +3,7 @@ import { AccountSafetyLockStatusChangeMessageEvent, AccountSafetyLockStatusChang import { GetConfiguration } from '@nitrots/configuration'; import { GetLocalizationManager } from '@nitrots/localization'; import { GetEventDispatcher, MysteryBoxKeysUpdateEvent, NitroEvent, NitroEventType, NitroSettingsEvent, SessionDataPreferencesEvent, UserNameUpdateEvent } from '@nitrots/events'; -import { CreateLinkEvent, HabboWebTools } from '@nitrots/utils'; +import { CreateLinkEvent, HabboWebTools, parseConfigJsonFromResponse } from '@nitrots/utils'; import { Texture } from 'pixi.js'; import { GroupInformationManager } from './GroupInformationManager'; import { IgnoredUsersManager } from './IgnoredUsersManager'; @@ -194,7 +194,7 @@ export class SessionDataManager implements ISessionDataManager if(response.status !== 200) throw new Error(`Unable to load ${ url }`); - const data = await response.json(); + const data = await parseConfigJsonFromResponse(response, url); this._floorItemOverrides = this.parseFurnitureOverrides(data?.roomitemtypes?.furnitype || []); this._wallItemOverrides = this.parseFurnitureOverrides(data?.wallitemtypes?.furnitype || []); diff --git a/packages/session/src/furniture/FurnitureDataLoader.ts b/packages/session/src/furniture/FurnitureDataLoader.ts index 9505fe0..2ad8857 100644 --- a/packages/session/src/furniture/FurnitureDataLoader.ts +++ b/packages/session/src/furniture/FurnitureDataLoader.ts @@ -1,6 +1,7 @@ import { FurnitureType, IFurnitureData } from '@nitrots/api'; import { GetConfiguration } from '@nitrots/configuration'; import { GetLocalizationManager } from '@nitrots/localization'; +import { loadGamedata } from '@nitrots/utils'; import { FurnitureData } from './FurnitureData'; export class FurnitureDataLoader @@ -20,28 +21,15 @@ export class FurnitureDataLoader if(!url || !url.length) throw new Error('Missing "furnidata.url" in config — add the furniture data URL to your renderer-config.json'); - let response: Response; - - try - { - response = await fetch(url); - } - catch(fetchErr) - { - throw new Error(`Could not fetch furniture data from "${ url }" — check "furnidata.url" in renderer-config.json (${ fetchErr.message })`); - } - - if(response.status !== 200) throw new Error(`Failed to load furniture data from "${ url }" — server returned HTTP ${ response.status }. Check "furnidata.url" in renderer-config.json`); - let responseData: any; try { - responseData = await response.json(); + responseData = await loadGamedata(url); } - catch(parseErr) + catch(err) { - throw new Error(`Invalid JSON in furniture data "${ url }" — the URL may be wrong. Check "furnidata.url" in renderer-config.json (${ parseErr.message })`); + throw new Error(`Could not load furniture data from "${ url }" — check "furnidata.url" in renderer-config.json (${ err?.message || err })`); } if(responseData.roomitemtypes) this.parseFloorItems(responseData.roomitemtypes); diff --git a/packages/session/src/product/ProductDataLoader.ts b/packages/session/src/product/ProductDataLoader.ts index 61da2de..087ce56 100644 --- a/packages/session/src/product/ProductDataLoader.ts +++ b/packages/session/src/product/ProductDataLoader.ts @@ -1,5 +1,6 @@ import { IProductData } from '@nitrots/api'; import { GetConfiguration } from '@nitrots/configuration'; +import { loadGamedata } from '@nitrots/utils'; import { ProductData } from './ProductData'; export class ProductDataLoader @@ -17,28 +18,15 @@ export class ProductDataLoader if(!url || !url.length) throw new Error('Missing "productdata.url" in config — add the product data URL to your renderer-config.json'); - let response: Response; - - try - { - response = await fetch(url); - } - catch(fetchErr) - { - throw new Error(`Could not fetch product data from "${ url }" — check "productdata.url" in renderer-config.json (${ fetchErr.message })`); - } - - if(response.status !== 200) throw new Error(`Failed to load product data from "${ url }" — server returned HTTP ${ response.status }. Check "productdata.url" in renderer-config.json`); - let responseData: any; try { - responseData = await response.json(); + responseData = await loadGamedata(url); } - catch(parseErr) + catch(err) { - throw new Error(`Invalid JSON in product data "${ url }" — the URL may be wrong. Check "productdata.url" in renderer-config.json (${ parseErr.message })`); + throw new Error(`Could not load product data from "${ url }" — check "productdata.url" in renderer-config.json (${ err?.message || err })`); } this.parseProducts(responseData.productdata); diff --git a/packages/utils/package.json b/packages/utils/package.json index ebd3ad0..9309805 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -10,6 +10,7 @@ "main": "./index", "dependencies": { "@nitrots/api": "1.0.0", + "json5": "^2.2.3", "pako": "^2.1.0", "pixi.js": "^8.8.1" }, diff --git a/packages/utils/src/GamedataLoader.ts b/packages/utils/src/GamedataLoader.ts new file mode 100644 index 0000000..cf4dadc --- /dev/null +++ b/packages/utils/src/GamedataLoader.ts @@ -0,0 +1,181 @@ +import { fetchConfigJson } from './JsonParser'; + +export const DEFAULT_TIERS = [ 'core', 'custom', 'seasonal' ] as const; +export type GamedataTier = typeof DEFAULT_TIERS[number] | string; + +export interface GamedataLoadOptions +{ + tiers?: readonly GamedataTier[]; + mergeArrayIdKeys?: readonly string[]; +} + +const DEFAULT_ID_KEYS = [ 'id', 'classname', 'name' ] as const; + +const looksLikeDirectory = (url: string): boolean => +{ + if(!url) return false; + + const stripped = url.split('?')[0].split('#')[0]; + + return stripped.endsWith('/'); +}; + +const joinUrl = (base: string, path: string): string => +{ + const cleanBase = base.endsWith('/') ? base : `${ base }/`; + const cleanPath = path.startsWith('/') ? path.slice(1) : path; + + return `${ cleanBase }${ cleanPath }`; +}; + +const tryFetchOrNull = async (url: string): Promise => +{ + try + { + return await fetchConfigJson(url); + } + catch + { + return null; + } +}; + +const isPlainObject = (value: any): value is Record => !!value && typeof value === 'object' && !Array.isArray(value); + +const arrayItemsLookKeyed = (arr: any[], idKeys: readonly string[]): string | null => +{ + if(!arr.length) return null; + + for(const key of idKeys) + { + let allHave = true; + + for(const item of arr) + { + if(!isPlainObject(item) || item[key] === undefined || item[key] === null) + { + allHave = false; + break; + } + } + + if(allHave) return key; + } + + return null; +}; + +export const mergeGamedata = (a: any, b: any, idKeys: readonly string[] = DEFAULT_ID_KEYS): any => +{ + if(b === undefined) return a; + if(a === undefined) return b; + + if(Array.isArray(a) && Array.isArray(b)) + { + const idKey = arrayItemsLookKeyed(a, idKeys) || arrayItemsLookKeyed(b, idKeys); + + if(!idKey) return a.concat(b); + + const index = new Map(); + const out: any[] = []; + + for(const item of a) + { + index.set(item[idKey], out.length); + out.push(item); + } + + for(const item of b) + { + const key = item[idKey]; + const at = index.get(key); + + if(at !== undefined) + { + out[at] = mergeGamedata(out[at], item, idKeys); + } + else + { + index.set(key, out.length); + out.push(item); + } + } + + return out; + } + + if(isPlainObject(a) && isPlainObject(b)) + { + const out: Record = { ...a }; + + for(const k of Object.keys(b)) + { + out[k] = mergeGamedata(a[k], b[k], idKeys); + } + + return out; + } + + return b; +}; + +interface TierManifest +{ + files?: string[]; +} + +interface RootManifest +{ + tiers?: GamedataTier[]; + files?: string[]; +} + +export const loadGamedata = async (url: string, options: GamedataLoadOptions = {}): Promise => +{ + if(!url) throw new Error('loadGamedata: empty URL'); + + if(!looksLikeDirectory(url)) + { + return await fetchConfigJson(url); + } + + const idKeys = options.mergeArrayIdKeys ?? DEFAULT_ID_KEYS; + const rootManifest = await tryFetchOrNull(joinUrl(url, 'manifest.json5')) + ?? await tryFetchOrNull(joinUrl(url, 'manifest.json')); + + const tiers = (rootManifest?.tiers && rootManifest.tiers.length) + ? rootManifest.tiers + : (options.tiers ?? DEFAULT_TIERS); + + let merged: any = undefined; + + if(rootManifest?.files?.length) + { + for(const file of rootManifest.files) + { + const fileUrl = joinUrl(url, file); + const part = await fetchConfigJson(fileUrl); + merged = (merged === undefined) ? part : mergeGamedata(merged, part, idKeys); + } + } + + for(const tier of tiers) + { + const tierUrl = joinUrl(url, `${ tier }/`); + const tierManifest = await tryFetchOrNull(joinUrl(tierUrl, 'manifest.json5')) + ?? await tryFetchOrNull(joinUrl(tierUrl, 'manifest.json')); + + if(!tierManifest?.files?.length) continue; + + for(const file of tierManifest.files) + { + const fileUrl = joinUrl(tierUrl, file); + const part = await fetchConfigJson(fileUrl); + merged = (merged === undefined) ? part : mergeGamedata(merged, part, idKeys); + } + } + + if(merged === undefined) throw new Error(`loadGamedata: directory mode at "${ url }" produced no data — make sure at least one tier (core/custom/seasonal) has a manifest.json5 with a 'files' array`); + + return merged as T; +}; diff --git a/packages/utils/src/JsonParser.ts b/packages/utils/src/JsonParser.ts new file mode 100644 index 0000000..c812d63 --- /dev/null +++ b/packages/utils/src/JsonParser.ts @@ -0,0 +1,126 @@ +import JSON5 from 'json5'; + +declare const __NITRO_JSON_MODE__: 'legacy' | 'json5' | 'auto' | undefined; + +const JSON5_EXTENSION = /\.json5(?:[?#]|$)/i; +const JSON5_MIME = /(?:application|text)\/(?:json5|x-json5)/i; + +const resolveJsonMode = (): 'legacy' | 'json5' | 'auto' => +{ + try + { + if(typeof __NITRO_JSON_MODE__ !== 'undefined' && __NITRO_JSON_MODE__) + { + if(__NITRO_JSON_MODE__ === 'legacy' || __NITRO_JSON_MODE__ === 'json5' || __NITRO_JSON_MODE__ === 'auto') return __NITRO_JSON_MODE__; + } + } + catch {} + + return 'auto'; +}; + +const looksLikeJson5Url = (url: string): boolean => !!url && JSON5_EXTENSION.test(url); + +const looksLikeJson5ContentType = (contentType: string): boolean => !!contentType && JSON5_MIME.test(contentType); + +const formatParseError = (sourceUrl: string, strictError: unknown, json5Error: unknown): string => +{ + const strictMessage = (strictError as Error)?.message || String(strictError); + const json5Message = (json5Error as Error)?.message || String(json5Error); + const source = sourceUrl ? ` in "${ sourceUrl }"` : ''; + + if(strictMessage === json5Message) return `Failed to parse JSON/JSON5${ source } — ${ json5Message }`; + + return `Failed to parse JSON/JSON5${ source } — JSON5: ${ json5Message } (strict JSON: ${ strictMessage })`; +}; + +const formatStrictError = (sourceUrl: string, err: unknown): string => +{ + const message = (err as Error)?.message || String(err); + const source = sourceUrl ? ` in "${ sourceUrl }"` : ''; + + return `Failed to parse strict JSON${ source } — ${ message } (build is in 'legacy' mode; switch to JSON5 mode via 'yarn configure' to accept comments/trailing commas)`; +}; + +export const parseConfigJson = (text: string, sourceUrl: string = ''): T => +{ + if(text === null || text === undefined) throw new Error(`Empty response${ sourceUrl ? ` for "${ sourceUrl }"` : '' }`); + + const trimmed = text.length > 0 ? text : ''; + const mode = resolveJsonMode(); + + if(mode === 'legacy') + { + try + { + return JSON.parse(trimmed) as T; + } + catch(err) + { + throw new Error(formatStrictError(sourceUrl, err)); + } + } + + if(mode === 'json5' || looksLikeJson5Url(sourceUrl)) + { + try + { + return JSON5.parse(trimmed); + } + catch(err) + { + throw new Error(formatParseError(sourceUrl, err, err)); + } + } + + let strictError: unknown; + + try + { + return JSON.parse(trimmed) as T; + } + catch(err) + { + strictError = err; + } + + try + { + return JSON5.parse(trimmed); + } + catch(json5Error) + { + throw new Error(formatParseError(sourceUrl, strictError, json5Error)); + } +}; + +export const parseConfigJsonFromResponse = async (response: Response, sourceUrl: string = ''): Promise => +{ + const contentType = response.headers?.get?.('content-type') || ''; + const text = await response.text(); + const url = sourceUrl || (response as any).url || ''; + const mode = resolveJsonMode(); + + if(mode === 'auto' && looksLikeJson5ContentType(contentType) && !looksLikeJson5Url(url)) + { + try + { + return JSON5.parse(text); + } + catch(err) + { + throw new Error(formatParseError(url, err, err)); + } + } + + return parseConfigJson(text, url); +}; + +export const fetchConfigJson = async (url: string, init?: RequestInit): Promise => +{ + const response = await fetch(url, init); + + if(!response || response.status !== 200) throw new Error(`Failed to fetch "${ url }" — server returned HTTP ${ response?.status ?? 'no response' }`); + + return parseConfigJsonFromResponse(response, url); +}; diff --git a/packages/utils/src/__tests__/JsonParser.test.ts b/packages/utils/src/__tests__/JsonParser.test.ts new file mode 100644 index 0000000..3c2ccb6 --- /dev/null +++ b/packages/utils/src/__tests__/JsonParser.test.ts @@ -0,0 +1,109 @@ +import { describe, expect, it } from 'vitest'; +import { fetchConfigJson, parseConfigJson, parseConfigJsonFromResponse } from '../JsonParser'; + +describe('parseConfigJson', () => +{ + it('parses strict JSON', () => + { + const result = parseConfigJson('{"a": 1, "b": [2, 3]}'); + expect(result).toEqual({ a: 1, b: [ 2, 3 ] }); + }); + + it('falls back to JSON5 for trailing commas', () => + { + const result = parseConfigJson('{"a": 1, "b": [2, 3,],}'); + expect(result).toEqual({ a: 1, b: [ 2, 3 ] }); + }); + + it('falls back to JSON5 for comments', () => + { + const result = parseConfigJson(`{ + // a number + "a": 1, + /* a list */ + "b": [2, 3] + }`); + expect(result).toEqual({ a: 1, b: [ 2, 3 ] }); + }); + + it('falls back to JSON5 for unquoted keys and single quotes', () => + { + const result = parseConfigJson("{ a: 1, b: 'hello' }"); + expect(result).toEqual({ a: 1, b: 'hello' }); + }); + + it('uses JSON5 directly for .json5 URLs', () => + { + const result = parseConfigJson('{ a: 1, /* hi */ b: 2 }', 'https://example.com/cfg.json5'); + expect(result).toEqual({ a: 1, b: 2 }); + }); + + it('throws a helpful error when both strict and JSON5 fail', () => + { + expect(() => parseConfigJson('{ this is :: not json ::', 'cfg.json')) + .toThrowError(/Failed to parse JSON\/JSON5 in "cfg\.json"/); + }); +}); + +describe('parseConfigJsonFromResponse', () => +{ + const buildResponse = (body: string, contentType = 'application/json', url = 'https://example.com/x.json'): Response => + { + const headers = new Headers({ 'content-type': contentType }); + return new Response(body, { status: 200, headers }); + }; + + it('parses JSON response bodies', async () => + { + const res = buildResponse('{"a": 1}'); + await expect(parseConfigJsonFromResponse(res, 'https://example.com/x.json')).resolves.toEqual({ a: 1 }); + }); + + it('parses JSON5 response bodies with comments', async () => + { + const res = buildResponse('{ /* yo */ a: 1, b: 2, }'); + await expect(parseConfigJsonFromResponse(res, 'https://example.com/x.json')).resolves.toEqual({ a: 1, b: 2 }); + }); + + it('respects application/json5 content-type', async () => + { + const res = buildResponse('{ a: 1 }', 'application/json5'); + await expect(parseConfigJsonFromResponse(res, 'https://example.com/x.txt')).resolves.toEqual({ a: 1 }); + }); +}); + +describe('fetchConfigJson', () => +{ + it('fetches and parses JSON or JSON5', async () => + { + const originalFetch = globalThis.fetch; + globalThis.fetch = (async () => new Response('{ a: 1, b: 2, }', { + status: 200, + headers: { 'content-type': 'application/json' } + })) as any; + + try + { + await expect(fetchConfigJson('https://example.com/cfg.json')).resolves.toEqual({ a: 1, b: 2 }); + } + finally + { + globalThis.fetch = originalFetch; + } + }); + + it('throws for non-200 responses', async () => + { + const originalFetch = globalThis.fetch; + globalThis.fetch = (async () => new Response('', { status: 404 })) as any; + + try + { + await expect(fetchConfigJson('https://example.com/missing.json')).rejects.toThrowError(/HTTP 404/); + } + finally + { + globalThis.fetch = originalFetch; + } + }); +}); diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index a25613d..056453b 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -4,6 +4,7 @@ export * from './BinaryReader'; export * from './BinaryWriter'; export * from './ColorConverter'; export * from './FurniId'; +export * from './GamedataLoader'; export * from './GetPixi'; export * from './GetRenderer'; export * from './GetStage'; @@ -13,6 +14,7 @@ export * from './GetTickerFPS'; export * from './GetTickerTime'; export * from './HabboWebTools'; export * from './Int32'; +export * from './JsonParser'; export * from './LegacyExternalInterface'; export * from './LinkTracker'; export * from './Matrix4x4'; diff --git a/yarn.lock b/yarn.lock index 257b9cd..288c306 100644 --- a/yarn.lock +++ b/yarn.lock @@ -44,7 +44,7 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz#010b6938fab7cb7df74aa2bbc06aa503b8fe5fb4" integrity sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q== -"@babel/parser@^7.29.0": +"@babel/parser@^7.29.3": version "7.29.3" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.29.3.tgz#116f70a77958307fceac27747573032f8a62f88e" integrity sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA== @@ -69,18 +69,18 @@ resolved "https://registry.yarnpkg.com/@csstools/color-helpers/-/color-helpers-6.0.2.tgz#82c59fd30649cf0b4d3c82160489748666e6550b" integrity sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q== -"@csstools/css-calc@^3.0.0", "@csstools/css-calc@^3.2.0": - version "3.2.0" - resolved "https://registry.yarnpkg.com/@csstools/css-calc/-/css-calc-3.2.0.tgz#15ca1a80a026ced0f6c4e12124c398e3db8e1617" - integrity sha512-bR9e6o2BDB12jzN/gIbjHa5wLJ4UjD1CB9pM7ehlc0ddk6EBz+yYS1EV2MF55/HUxrHcB/hehAyt5vhsA3hx7w== +"@csstools/css-calc@^3.0.0", "@csstools/css-calc@^3.2.1": + version "3.2.1" + resolved "https://registry.yarnpkg.com/@csstools/css-calc/-/css-calc-3.2.1.tgz#b30e061ca9f297ccb2b3b032bfee32fda02b1b27" + integrity sha512-DtdHlgXh5ZkA43cwBcAm+huzgJiwx3ZTWVjBs94kwz2xKqSimDA3lBgCjphYgwgVUMWatSM0pDd8TILB1yrVVg== "@csstools/css-color-parser@^4.0.1": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@csstools/css-color-parser/-/css-color-parser-4.1.0.tgz#1d64ea09c548d3ed331648ea0b831e16b80c891c" - integrity sha512-U0KhLYmy2GVj6q4T3WaAe6NPuFYCPQoE3b0dRGxejWDgcPp8TP7S5rVdM5ZrFaqu4N67X8YaPBw14dQSYx3IyQ== + version "4.1.1" + resolved "https://registry.yarnpkg.com/@csstools/css-color-parser/-/css-color-parser-4.1.1.tgz#70c322112e2aafb0b09f34b51ce3482db6aab2ac" + integrity sha512-eZ5XOtyhK+mggRafYUWzA0tvaYOFgdY8AkgQiCJF9qNAePnUo/zmsqqYubBBb3sQ8uNUaSKTY9s9klfRaAXL0g== dependencies: "@csstools/color-helpers" "^6.0.2" - "@csstools/css-calc" "^3.2.0" + "@csstools/css-calc" "^3.2.1" "@csstools/css-parser-algorithms@^4.0.0": version "4.0.0" @@ -88,9 +88,9 @@ integrity sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w== "@csstools/css-syntax-patches-for-csstree@^1.0.21": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.3.tgz#3204cf40deb97db83e225b0baa9e37d9c3bd344d" - integrity sha512-SH60bMfrRCJF3morcdk57WklujF4Jr/EsQUzqkarfHXEFcAR1gg7fS/chAE922Sehgzc1/+Tz5H3Ypa1HiEKrg== + version "1.1.4" + resolved "https://registry.yarnpkg.com/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.4.tgz#8f4e5e23574e8c76005588984308d2b216993720" + integrity sha512-wgsqt92b7C7tQhIdPNxj0n9zuUbQlvAuI1exyzeNrOKOi62SD7ren8zqszmpVREjAOqg8cD2FqYhQfAuKjk4sw== "@csstools/css-tokenizer@^4.0.0": version "4.0.0" @@ -248,10 +248,10 @@ dependencies: "@tybys/wasm-util" "^0.10.1" -"@oxc-project/types@=0.128.0": - version "0.128.0" - resolved "https://registry.yarnpkg.com/@oxc-project/types/-/types-0.128.0.tgz#efc7524f948ff9e8ab1404ecad1823849c6fe149" - integrity sha512-huv1Y/LzBJkBVHt3OlC7u0zHBW9qXf1FdD7sGmc1rXc2P1mTwHssYv7jyGx5KAACSCH+9B3Bhn6Z9luHRvf7pQ== +"@oxc-project/types@=0.130.0": + version "0.130.0" + resolved "https://registry.yarnpkg.com/@oxc-project/types/-/types-0.130.0.tgz#a7825148711dc28805c46cfc21d94b63a4d41e88" + integrity sha512-ibD2usx9JRu7f5pu2tMKMI4cpA4NgXJQoYRP4pQ7Pxmn1l6k/53qWtQWZayhYy3X4QZkt90Ot+mJEaeXouio6Q== "@pixi/colord@^2.9.6": version "2.9.6" @@ -263,89 +263,89 @@ resolved "https://registry.yarnpkg.com/@pixi/gif/-/gif-3.0.1.tgz#2709d6559d316161cde1821b0f29cc2c05f88794" integrity sha512-oGl0nkbFAe1vaRLyIvGbJc3fcIrS8vF1E00cwjiV+9f1pYe072D+yijJxHsgYnXs6jdzERh+D0MqSrEag0jRzg== -"@rolldown/binding-android-arm64@1.0.0-rc.18": - version "1.0.0-rc.18" - resolved "https://registry.yarnpkg.com/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.18.tgz#3af8b2242086125934a85c1915b76e0a6a2054c1" - integrity sha512-lIDyUAfD7U3+BWKzdxMbJcsYHuqXqmGz40aeRqvuAm3y5TkJSYTBW2RDrn65DJFPQqVjUAUqq5uz8urzQ8aBdQ== +"@rolldown/binding-android-arm64@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.1.tgz#7b250c89f16d74affd581dbe38f702e8c2c644d3" + integrity sha512-fJI3I0r3C3Oj/zdBCpaCmBRZYf07xpaq4yCfDDoSFm+beWNzbIl26puW8RraUdugoJw/95zerNOn6jasAhzSmg== -"@rolldown/binding-darwin-arm64@1.0.0-rc.18": - version "1.0.0-rc.18" - resolved "https://registry.yarnpkg.com/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.18.tgz#ae0b4467d24ecd6c6589f03d4d4699616ee9649c" - integrity sha512-apJq2ktnGp27nSInMR5Vcj8kY6xJzDAvfdIFlpDcAK/w4cDO58qVoi1YQsES/SKiFNge/6e4CUzgjfHduYqWpQ== +"@rolldown/binding-darwin-arm64@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.1.tgz#cd4de96687e6522062984b0503fbffbbc9220023" + integrity sha512-cKnAhWEsV7TPcA/5EAteDp6KcJZBQ2G+BqE7zayMMi7kMvwRsbv7WT9aOnn0WNl4SKEIf43vjS31iUPu80nzXg== -"@rolldown/binding-darwin-x64@1.0.0-rc.18": - version "1.0.0-rc.18" - resolved "https://registry.yarnpkg.com/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.18.tgz#23cf24b0a7b96c8990bbdd8a91e7fd3ba82b00e7" - integrity sha512-5Ofot8xbs+pxRHJqm9/9N/4sTQOvdrwEsmPE9pdLEEoAbdZtG6F2LMDfO1sp6ZAtXJuJV/21ew2srq3W8NXB5g== +"@rolldown/binding-darwin-x64@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.1.tgz#5b0a631e3784d5a7741dd93097dcf6dfca029960" + integrity sha512-YKrVwQjIRBPo+5G/u03wGjbdy4q7pyzCe93DK9VJ7zkVmeg8LJ7GbgsiHWdR4xSoe4CAXRD7Bcjgbtr64bkXNg== -"@rolldown/binding-freebsd-x64@1.0.0-rc.18": - version "1.0.0-rc.18" - resolved "https://registry.yarnpkg.com/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.18.tgz#a047a770f94dc451c062b729e5d1cf82e5c6f9c4" - integrity sha512-7h8eeOTT1eyqJyx64BFCnWZpNm486hGWt2sqeLLgDxA0xI1oGZ9H7gK1S85uNGmBhkdPwa/6reTxfFFKvIsebw== +"@rolldown/binding-freebsd-x64@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.1.tgz#d82e561079db89f796438f56ec11bb3565ee1875" + integrity sha512-z/oBsREo46SsFqBwYtFe0kpJeBijAT48O/WXLI4suiCLBkr03RTtTJMCzSdDd2znlh8VJizL09XVkQgk8IZonw== -"@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.18": - version "1.0.0-rc.18" - resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.18.tgz#c0b7f346cbf50301cea669a4632bc63aabe6a72c" - integrity sha512-eRcm/HVt9U/JFu5RKAEKwGQYtDCKWLiaH6wOnsSEp6NMBb/3Os8LgHZlNyzMpFVNmiiMFlfb2zEnebfzJrHFmg== +"@rolldown/binding-linux-arm-gnueabihf@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.1.tgz#f2645afff4253c7b46b80ba14af5fd3fc18d45dc" + integrity sha512-ik8q7GM11zxvYxFc2PeDcT6TBvhCQMaUxfph/M5l9sKuTs/Sjg3L+Byw0F7w0ZVLBZmx30P+gG0ECzzN+MFcmQ== -"@rolldown/binding-linux-arm64-gnu@1.0.0-rc.18": - version "1.0.0-rc.18" - resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.18.tgz#af56373c7996ebe6379207cd699c9f7f705e235d" - integrity sha512-SOrT/cT4ukTmgnrEz/Hg3m7LBnuCLW9psDeMKrimRWY4I8DmnO7Lco8W2vtqPmMkbVu8iJ+g4GFLVLLOVjJ9DQ== +"@rolldown/binding-linux-arm64-gnu@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.1.tgz#a16b97f175e7b115c5ece77c7b648d0c868f4486" + integrity sha512-QoSx2EkyrrdZ6kcyE8stqZ62t0Yra8Fs5ia9lOxJrh6TMQJK7gQKmscdTHf7pOXKREKrVwOtJcQG3qVSfc866A== -"@rolldown/binding-linux-arm64-musl@1.0.0-rc.18": - version "1.0.0-rc.18" - resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.18.tgz#a8f5acd21fcffc8991aa84710e3ae603c4240ea4" - integrity sha512-QWjdxN1HJCpBTAcZ5N5F7wju3gVPzRzSpmGzx7na0c/1qpN9CFil+xt+l9lV/1M6/gqHSNXCiqPfwhVJPeLnug== +"@rolldown/binding-linux-arm64-musl@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.1.tgz#e695aec4ef2c8713c9d959b42a208059891276da" + integrity sha512-uwNwFpwKeNiZawfAWBgg0VIztPTV3ihhh1vV334h9ivnNLorxnQMU6Fz8wG1Zb4Qh9LC1/MkcyT3YlDXG3Rsgg== -"@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.18": - version "1.0.0-rc.18" - resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.18.tgz#1d4a89e040ff82141fc46e717cfab80b05f7c13f" - integrity sha512-ugCOyj7a4d9h3q9B+wXmf6g3a68UsjGh6dob5DHevHGMwDUbhsYNbSPxJsENcIttJZ9jv7qGM2UesLw5jqIhdg== +"@rolldown/binding-linux-ppc64-gnu@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.1.tgz#4a9edf16112cbe99cdd396c60efac39cbd1758ac" + integrity sha512-zY1bul7OWr7DFBiJ++wofXvnr8B45ce3QsQUhKrIhXsygAh7bTkwyeM1bi1a2g5C/yC/N8TZyGDEoMfm/l9mpg== -"@rolldown/binding-linux-s390x-gnu@1.0.0-rc.18": - version "1.0.0-rc.18" - resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.18.tgz#97c21feeb2ed87d07820f0b2dcc5dd663e7a7f3b" - integrity sha512-kKWRhbsotpXkGbcd5dllUWg5gEXcDAa8u5YnP9AV5DYNbvJHGzzuwv7dpmhc8NqKMJldl0a+x76IHbspEpEmdA== +"@rolldown/binding-linux-s390x-gnu@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.1.tgz#314aa3ec1ce8251501d865f98fb91e42a1e671e4" + integrity sha512-0frlsT/f4Ft6I7SMESTKnF3cZsdicQn1dCMkF/jT9wDLE+gGoiQfv1nmT9e+s7s/fekvvy6tZM2jHvI2tkbJDQ== -"@rolldown/binding-linux-x64-gnu@1.0.0-rc.18": - version "1.0.0-rc.18" - resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.18.tgz#06310d40fe139ccc3c433b361120d337c66ebec2" - integrity sha512-uCo8ElcCIAMyYAZyuIZ81oFkhTSIllNvUCHCAlbhlN4ji3uC28h7IIdlXyIvGO7HsuqnV9p3rD/bpH7XhIyhRw== +"@rolldown/binding-linux-x64-gnu@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.1.tgz#7c51f13cf1141c503ee162830b4fc692d91640be" + integrity sha512-XABVmGp9Tg0WspTVvwduTc4fpqy6JnAUrSQe6OuyqD/03nI7r0O9OWUkMIwFrjKAIqolvqoA4ZrJppgwE0Gxmw== -"@rolldown/binding-linux-x64-musl@1.0.0-rc.18": - version "1.0.0-rc.18" - resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.18.tgz#6a711258841f42609b238050cfcd5db13ac136d0" - integrity sha512-XNOQZtuE6yUIvx4rwGemwh8kpL1xvU41FXy/s9K7T/3JVcqGzo3NfKM2HrbrGgfPYGFW42f07Wk++aOC6B9NWA== +"@rolldown/binding-linux-x64-musl@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.1.tgz#b7213936bbc9310b02a34f71cefd25f9e71f329b" + integrity sha512-bV4fzswuzVcKD90o/VM6QqKxnxlDq0g2BISDLNVmxrnhpv1DDbyPhCIjYfvzYLV+MvkKKnQt2Q6AO86SEBULUQ== -"@rolldown/binding-openharmony-arm64@1.0.0-rc.18": - version "1.0.0-rc.18" - resolved "https://registry.yarnpkg.com/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.18.tgz#15cb644beeafdbec930d79ed45c2a7c2573eac70" - integrity sha512-tSn/kzrfa7tNOXr7sEacDBN4YsIqTyLqh45IO0nHDwtpKIDNDJr+VFojt+4klSpChxB29JLyduSsE0MKEwa65A== +"@rolldown/binding-openharmony-arm64@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.1.tgz#006e88acde4f12b41a4c72292685c9dc9e6a3627" + integrity sha512-/Mh0Zhq3OP7fVs0kcQHZP6lZEthMGTaSf8UBQYSFEZDWGXXlEC+nJ6EqenaK2t4LBXMe3A+K/G2BVXXdtOr4PQ== -"@rolldown/binding-wasm32-wasi@1.0.0-rc.18": - version "1.0.0-rc.18" - resolved "https://registry.yarnpkg.com/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.18.tgz#ca3a56d11dfd533d743711141b3bb4c1ec10110e" - integrity sha512-+J9YGmc+czgqlhYmwun3S3O0FIZhsH8ep2456xwjAdIOmuJxM7xz4P4PtrxU+Bz17a/5bqPA8o3HAAoX0teUdg== +"@rolldown/binding-wasm32-wasi@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.1.tgz#033525c84da217418232f35be19f1ddc0af4f31e" + integrity sha512-+1xc9X45l8ufsBAm6Gjvx2qDRIY9lTVt0cgWNcJ+1gdhXvkbxePA60yRTwSTuXL09CMhyJmjpV7E3NoyxbqFQQ== dependencies: "@emnapi/core" "1.10.0" "@emnapi/runtime" "1.10.0" "@napi-rs/wasm-runtime" "^1.1.4" -"@rolldown/binding-win32-arm64-msvc@1.0.0-rc.18": - version "1.0.0-rc.18" - resolved "https://registry.yarnpkg.com/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.18.tgz#8c2117d68331d7de59d24631146d538fc203d27c" - integrity sha512-zsu47DgU0FQzSwi6sU9dZoEdUv7pc1AptSEz/Z8HBg54sV0Pbs3N0+CrIbTsgiu6EyoaNN9CHboqbLaz9lhOyQ== +"@rolldown/binding-win32-arm64-msvc@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.1.tgz#febbf109cf1b5837e21369f0e0d2fefca1519c39" + integrity sha512-1D+UqZdfnuR+Jy1GgMJwi85bD40H21uNmOPRWQhw4oRSuolZ/B5rixZ45DK2KXOTCvmVCecauWgEhbw8bI7tOw== -"@rolldown/binding-win32-x64-msvc@1.0.0-rc.18": - version "1.0.0-rc.18" - resolved "https://registry.yarnpkg.com/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.18.tgz#bb5c28df3095046778cc1b020ef52fc5ee7b7e70" - integrity sha512-7H+3yqGgmnlDTRRhw/xpYY9J1kf4GC681nVc4GqKhExZTDrVVrV2tsOR9kso0fvgBdcTCcQShx4SLLoHgaLwhg== +"@rolldown/binding-win32-x64-msvc@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.1.tgz#dfb32a67ccb0deaa3c9a57f6cb4890b5697dfa2c" + integrity sha512-INAycaWuhlOK3wk4mRHGsdgwYWmd9cChdPdE9bwWmy6rn9VqVNYNFGhOdXrofXUxwHIncSiPNb8tNm8knDVIeQ== -"@rolldown/pluginutils@1.0.0-rc.18": - version "1.0.0-rc.18" - resolved "https://registry.yarnpkg.com/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.18.tgz#51cf2589596a179ebe8cbf313f1358c7b51a2fdc" - integrity sha512-CUY5Mnhe64xQBGZEEXQ5WyZwsc1JU3vAZLIxtrsBt3LO6UOb+C8GunVKqe9sT8NeWb4lqSaoJtp2xo6GxT1MNw== +"@rolldown/pluginutils@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz#e3fcee093fbb5ce765e1ad088ff4de2889f6f9be" + integrity sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw== "@rollup/plugin-typescript@^11.1.6": version "11.1.6" @@ -369,7 +369,7 @@ resolved "https://registry.yarnpkg.com/@standard-schema/spec/-/spec-1.1.0.tgz#a79b55dbaf8604812f52d140b2c9ab41bc150bb8" integrity sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w== -"@thumbmarkjs/thumbmarkjs@^1.9.0": +"@thumbmarkjs/thumbmarkjs@^1.8.1": version "1.9.0" resolved "https://registry.yarnpkg.com/@thumbmarkjs/thumbmarkjs/-/thumbmarkjs-1.9.0.tgz#a6444ac1f924f061cfc1507a21dcaf83ee705cab" integrity sha512-6LooyYk8i5L2zEZgDMLE6m2sGDcIHHBiZfxdFp0A16Q4ZXafEmhHmt+zCqQEBMiQHi+08e/v5q77IY2KhvAJwg== @@ -410,9 +410,9 @@ integrity sha512-r7K3NkJz3A95WkVVmjs0NcchhHstC2C/VIYNX4JC6tieviUNo774FFeOHjThr3Vw/WCeMP9kAT77MKbIRlO/4w== "@types/howler@^2.2.11": - version "2.2.12" - resolved "https://registry.yarnpkg.com/@types/howler/-/howler-2.2.12.tgz#078d20787911f6e3e871a0e93a23832e13abaa59" - integrity sha512-hy769UICzOSdK0Kn1FBk4gN+lswcj1EKRkmiDtMkUGvFfYJzgaDXmVXkSShS2m89ERAatGIPnTUlp2HhfkVo5g== + version "2.2.13" + resolved "https://registry.yarnpkg.com/@types/howler/-/howler-2.2.13.tgz#16fe866b3494f5a825041b232ae06de18ec1b2e7" + integrity sha512-40+EBjqIHHrC4VShlz/7i0lBUsE3QkgzZinQQji74Hd8sBkJZUBaT7LWFLK6rcabsDOOQpoMbEJvtaFQwxOu/g== "@types/json-schema@^7.0.15": version "7.0.15" @@ -420,9 +420,9 @@ integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== "@types/node@^20.14.12": - version "20.19.40" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.19.40.tgz#80a4a7236e27817636777836ceedb889adf6da2f" - integrity sha512-xxx6M2IpSTnnKcR0cMvIiohkiCx20/oRPtWGbenFygKCGl3zqUzdNjQ/1V4solq1LU+dgv0nQzeGOuqkqZGg0Q== + version "20.19.41" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.19.41.tgz#bb266a1e0aaa2f4537d14ae8ebf238dd9ca73ce6" + integrity sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ== dependencies: undici-types "~6.21.0" @@ -431,157 +431,109 @@ resolved "https://registry.yarnpkg.com/@types/pako/-/pako-2.0.4.tgz#c3575ef8125e176c345fa0e7b301c1db41170c15" integrity sha512-VWDCbrLeVXJM9fihYodcLiIv0ku+AlOa/TQ1SvYOaBuyrSKgEcro95LJyIsJ4vSo6BXIxOKxiJAat04CmST9Fw== -"@typescript-eslint/eslint-plugin@8.59.2": - version "8.59.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.59.2.tgz#f37b2c189a0177141fe3de3b08f2a83991bfdbfa" - integrity sha512-j/bwmkBvHUtPNxzuWe5z6BEk3q54YRyGlBXkSsmfoih7zNrBvl5A9A98anlp/7JbyZcWIJ8KXo/3Tq/DjFLtuQ== +"@typescript-eslint/eslint-plugin@8.59.3": + version "8.59.3" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.59.3.tgz#5d6da7e7b236b46452fa00d3904bb6f59615bfde" + integrity sha512-PwFvSKsXGShKGW6n5bZOhGHEcCZXM8HofLK9fNsEwZXzFRjoY+XT1Vsf1zgyXdwTr0ZYz1/2tkZ0DBTT9jZjhw== dependencies: "@eslint-community/regexpp" "^4.12.2" - "@typescript-eslint/scope-manager" "8.59.2" - "@typescript-eslint/type-utils" "8.59.2" - "@typescript-eslint/utils" "8.59.2" - "@typescript-eslint/visitor-keys" "8.59.2" + "@typescript-eslint/scope-manager" "8.59.3" + "@typescript-eslint/type-utils" "8.59.3" + "@typescript-eslint/utils" "8.59.3" + "@typescript-eslint/visitor-keys" "8.59.3" ignore "^7.0.5" natural-compare "^1.4.0" ts-api-utils "^2.5.0" -"@typescript-eslint/parser@8.59.2": - version "8.59.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.59.2.tgz#e2fd0084baa5dd0c24cd789af1c72cbc3a7a1c62" - integrity sha512-plR3pp6D+SSUn1HM7xvSkx12/DhoHInI2YF35KAcVFNZvlC0gtrWqx7Qq1oH2Ssgi0vlFRCTbP+DZc7B9+TtsQ== +"@typescript-eslint/parser@8.59.3": + version "8.59.3" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.59.3.tgz#f46cbc70ae0a25119ef94eac9ecd46714788e1a1" + integrity sha512-HPwA+hVkfcriajbNvTmZv4VRauibay+cWArYUYq7u7W7PmGShMxbPxLvrwDme55a6d5alG3nrYfhyJ/G28XlLg== dependencies: - "@typescript-eslint/scope-manager" "8.59.2" - "@typescript-eslint/types" "8.59.2" - "@typescript-eslint/typescript-estree" "8.59.2" - "@typescript-eslint/visitor-keys" "8.59.2" + "@typescript-eslint/scope-manager" "8.59.3" + "@typescript-eslint/types" "8.59.3" + "@typescript-eslint/typescript-estree" "8.59.3" + "@typescript-eslint/visitor-keys" "8.59.3" debug "^4.4.3" -"@typescript-eslint/project-service@8.59.2": - version "8.59.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.59.2.tgz#f8b8cbf8692e3a51c2c394acf8cf6900f7e755af" - integrity sha512-+2hqvEkeyf/0FBor67duF0Ll7Ot8jyKzDQOSrxazF/danillRq2DwR9dLptsXpoZQqxE1UisSmoZewrlPas9Vw== +"@typescript-eslint/project-service@8.59.3": + version "8.59.3" + resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.59.3.tgz#1be5ae152aad987a156c9a1a9b4256e75cfbbe0c" + integrity sha512-ECiUWa/KYRGDFUqTNehaRgzDshnJfkTABJxVemHk4ko22gcr0ukloKjWvyQ64g8YCV/UI47kN1dbmjf/GaQYng== dependencies: - "@typescript-eslint/tsconfig-utils" "^8.59.2" - "@typescript-eslint/types" "^8.59.2" + "@typescript-eslint/tsconfig-utils" "^8.59.3" + "@typescript-eslint/types" "^8.59.3" debug "^4.4.3" -"@typescript-eslint/scope-manager@8.59.2": - version "8.59.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.59.2.tgz#63cbd0af2e3180949d6be81122cc555bc71e736d" - integrity sha512-JzfyEpEtOU89CcFSwyNS3mu4MLvLSXqnmX05+aKBDM+TdR5jzcGOEBwxwGNxrEQ7p/z6kK2WyioCGBf2zZBnvg== +"@typescript-eslint/scope-manager@8.59.3": + version "8.59.3" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.59.3.tgz#91a60f66803fe9dae0696fbab2451f5723f119d2" + integrity sha512-t2LvZnoEfzKtnPjgeEu41xw5gxq9mQVfYy4OoZ4Vlt0sk3JwxmhCca/AR7DwOiHrjWgjAj6as4AhRLKSDfvZIA== dependencies: - "@typescript-eslint/types" "8.59.2" - "@typescript-eslint/visitor-keys" "8.59.2" + "@typescript-eslint/types" "8.59.3" + "@typescript-eslint/visitor-keys" "8.59.3" -"@typescript-eslint/tsconfig-utils@8.59.2", "@typescript-eslint/tsconfig-utils@^8.59.2": - version "8.59.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.59.2.tgz#6e92bc412083753185a79c9f1431e78169d9232f" - integrity sha512-BKK4alN7oi4C/zv4VqHQ+uRU+lTa6JGIZ7s1juw7b3RHo9OfKB+bKX3u0iVZetdsUCBBkSbdWbarJbmN0fTeSw== +"@typescript-eslint/tsconfig-utils@8.59.3", "@typescript-eslint/tsconfig-utils@^8.59.3": + version "8.59.3" + resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.59.3.tgz#88ca9036b42ccdd1e630cfdafd2e042c2ca6a835" + integrity sha512-PcIJHjmaREXLgIAIzLnSY9VucEzz8FKXsRgFa1DmdGCK/5tJpW03TKJF01Q6VZd1lLdz2sIKPWaDUZN9dp//dw== -"@typescript-eslint/type-utils@8.59.2": - version "8.59.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.59.2.tgz#a60a1192a804fa472a92c41656853ac6a9ba7176" - integrity sha512-nhqaj1nmTdVVl/BP5omXNRGO38jn5iosis2vbdmupF2txCf8ylWT8lx+JlvMYYVqzGVKtjojUFoQ3JRWK+mfzQ== +"@typescript-eslint/type-utils@8.59.3": + version "8.59.3" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.59.3.tgz#421fb2448bdfeb301d134a01cd02503f67fd8192" + integrity sha512-g71d8QD8UaiHGvrJwyIS1hCX5r63w6Jll+4VEYhEAHXTDIqX1JgxhTAbEHtKntL9kuc4jRo7/GWw5xfCepSccQ== dependencies: - "@typescript-eslint/types" "8.59.2" - "@typescript-eslint/typescript-estree" "8.59.2" - "@typescript-eslint/utils" "8.59.2" + "@typescript-eslint/types" "8.59.3" + "@typescript-eslint/typescript-estree" "8.59.3" + "@typescript-eslint/utils" "8.59.3" debug "^4.4.3" ts-api-utils "^2.5.0" -"@typescript-eslint/types@8.59.2", "@typescript-eslint/types@^8.59.2": - version "8.59.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.59.2.tgz#01caabcd7e4715c33ad5e11cab260829714d6b9c" - integrity sha512-e82GVOE8Ps3E++Egvb6Y3Dw0S10u8NkQ9KXmtRhCWJJ8kDhOJTvtMAWnFL16kB1583goCWXsr0NieKCZMs2/0Q== +"@typescript-eslint/types@8.59.3", "@typescript-eslint/types@^8.59.3": + version "8.59.3" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.59.3.tgz#b7ca539c5e302fdde9a7cadb73caed107ef8f2cd" + integrity sha512-ePFoH0g4ludssdRFqqDxQePCxU4WQyRa9+XVwjm7yLn0FKhMeoetC+qBEEI1Eyb1pGSDveTIT09Bvw2WhlGayg== -"@typescript-eslint/typescript-estree@8.59.2": - version "8.59.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.59.2.tgz#6a217ef65b18dbd12c718fc86a675d1d7a1414cc" - integrity sha512-o0XPGNwcWw+FIwStOWn+BwBuEmL6QXP0rsvAFg7ET1dey1Nr6Wb1ac8p5HEsK0ygO/6mUxlk+YWQD9xcb/nnXg== +"@typescript-eslint/typescript-estree@8.59.3": + version "8.59.3" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.59.3.tgz#e6bb1408e00b47e431427a40268db4e86cb121ab" + integrity sha512-CbRjVRAf7Lr9Kr8RopKcbY45p2VfmmHrm0ygOCYFi7oU8q19m0Fs/6iHS7kNOmwpp+ob07ZVcAqlxUod9lYdmg== dependencies: - "@typescript-eslint/project-service" "8.59.2" - "@typescript-eslint/tsconfig-utils" "8.59.2" - "@typescript-eslint/types" "8.59.2" - "@typescript-eslint/visitor-keys" "8.59.2" + "@typescript-eslint/project-service" "8.59.3" + "@typescript-eslint/tsconfig-utils" "8.59.3" + "@typescript-eslint/types" "8.59.3" + "@typescript-eslint/visitor-keys" "8.59.3" debug "^4.4.3" minimatch "^10.2.2" semver "^7.7.3" tinyglobby "^0.2.15" ts-api-utils "^2.5.0" -"@typescript-eslint/utils@8.59.2": - version "8.59.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.59.2.tgz#ff619a6a3075f4017fa91b8610b752a8ca3366aa" - integrity sha512-Juw3EinkXqjaffxz6roowvV7GZT/kET5vSKKZT6upl5TXdWkLkYmNPXwDDL2Vkt2DPn0nODIS4egC/0AGxKo/Q== +"@typescript-eslint/utils@8.59.3": + version "8.59.3" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.59.3.tgz#f693f979deb4dc3994de03ff8b23976d625c36c5" + integrity sha512-JAvT14goBzRzzzZyqq3P9BLArIxTtQURUtFgQ/V7FO+eU+Gg6ES+5ymOPP1wRxXcxAYeivCk4uS3jCKWI1K8Zg== dependencies: "@eslint-community/eslint-utils" "^4.9.1" - "@typescript-eslint/scope-manager" "8.59.2" - "@typescript-eslint/types" "8.59.2" - "@typescript-eslint/typescript-estree" "8.59.2" + "@typescript-eslint/scope-manager" "8.59.3" + "@typescript-eslint/types" "8.59.3" + "@typescript-eslint/typescript-estree" "8.59.3" -"@typescript-eslint/visitor-keys@8.59.2": - version "8.59.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.2.tgz#5ccc486913cd347883d69158836b1189a660bfe6" - integrity sha512-NwjLUnGy8/Zfx23fl50tRC8rYaYnM52xNRYFAXvmiil9yh1+K6aRVQMnzW6gQB/1DLgWt977lYQn7C+wtgXZiA== +"@typescript-eslint/visitor-keys@8.59.3": + version "8.59.3" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.3.tgz#820843b1b5ca4290009cf189382abcf6fe00dfa6" + integrity sha512-f1UQF7ggd42YiwI5wGrRaPsa+P0CINBlrkLPmGfpq/u/I/oVtecoEIfFR9ag/oa1sLOsRNZ6xehf6qMZhQGBDg== dependencies: - "@typescript-eslint/types" "8.59.2" + "@typescript-eslint/types" "8.59.3" eslint-visitor-keys "^5.0.0" -"@typescript/native-preview-darwin-arm64@7.0.0-dev.20260510.1": - version "7.0.0-dev.20260510.1" - resolved "https://registry.yarnpkg.com/@typescript/native-preview-darwin-arm64/-/native-preview-darwin-arm64-7.0.0-dev.20260510.1.tgz#318a841447a879e9590edf549fbf2b231a109d91" - integrity sha512-YpG99bf/Va1aLGP8SUQy1ClUvi4c6uTFrEQ0B5KzZb9TsOwH1RIrc/2n8UO3IAuilvwEA0EU4q8fEO3otVP2Sw== - -"@typescript/native-preview-darwin-x64@7.0.0-dev.20260510.1": - version "7.0.0-dev.20260510.1" - resolved "https://registry.yarnpkg.com/@typescript/native-preview-darwin-x64/-/native-preview-darwin-x64-7.0.0-dev.20260510.1.tgz#6ca57655a39f13acc7f868c3e44aff2edaa4b02b" - integrity sha512-NUwhwHpQn7aSX2GGBuY2bjec+hFnIz2DAna4ksVneexVE20h2U0MFzBvWrqH2C0PzPxVvGOMg4fGCvhTs93nlw== - -"@typescript/native-preview-linux-arm64@7.0.0-dev.20260510.1": - version "7.0.0-dev.20260510.1" - resolved "https://registry.yarnpkg.com/@typescript/native-preview-linux-arm64/-/native-preview-linux-arm64-7.0.0-dev.20260510.1.tgz#2ad2edc4ca931d9697956093d63f32970ce10fed" - integrity sha512-T7Zuy6h0sU+38w+N3A+YgW0XVqxIMjeHyu+945rJkiP9zk52Mwp663t1ndyeAE/N2zV+q0SWQmHNuFSXl99wJw== - -"@typescript/native-preview-linux-arm@7.0.0-dev.20260510.1": - version "7.0.0-dev.20260510.1" - resolved "https://registry.yarnpkg.com/@typescript/native-preview-linux-arm/-/native-preview-linux-arm-7.0.0-dev.20260510.1.tgz#e01d73e1bf9fd5780326b35ab7cc97a3f9836d01" - integrity sha512-UE+PIWWg7vvszSU0gS9rzgIIHCWexz3hMZDHpHRSLAleAvULCNI3EzwTRFOA4BHyQ8eReD1KZ8e76BuStEPspw== - -"@typescript/native-preview-linux-x64@7.0.0-dev.20260510.1": - version "7.0.0-dev.20260510.1" - resolved "https://registry.yarnpkg.com/@typescript/native-preview-linux-x64/-/native-preview-linux-x64-7.0.0-dev.20260510.1.tgz#9a1ff6947c184fcb548856e1b480adc106de1a5b" - integrity sha512-gJu4q4YREvjR2Lx1jUaCd/bRbTuyKf2r3rJ4tReuHyAvNse23HdGI0a9w4Z3wUbvRznxYt640IIItWsr/f3LEQ== - -"@typescript/native-preview-win32-arm64@7.0.0-dev.20260510.1": - version "7.0.0-dev.20260510.1" - resolved "https://registry.yarnpkg.com/@typescript/native-preview-win32-arm64/-/native-preview-win32-arm64-7.0.0-dev.20260510.1.tgz#d517af09f7ff86b9e7104714f975880c56ad4de9" - integrity sha512-00DtjrtkdAHOU/soYr8ncrjUvIsple8nvb29ZUATnLraNnzUgv5AS3yMve/pG/N7rVLlKy2FrXlVyVW7WAx29w== - -"@typescript/native-preview-win32-x64@7.0.0-dev.20260510.1": - version "7.0.0-dev.20260510.1" - resolved "https://registry.yarnpkg.com/@typescript/native-preview-win32-x64/-/native-preview-win32-x64-7.0.0-dev.20260510.1.tgz#1896d9112a99dbf24cc90814d8b6e0fd76b98d6b" - integrity sha512-27UeujQTEPFxhfkZL7aHnA1TlNol3nwDVFp5d6jFoP14yTXMe47kBnAJLEU2ta3REZE5PzLCs7HLV8H4VdxGgA== - -"@typescript/native-preview@^7.0.0-dev.20260510.1": - version "7.0.0-dev.20260510.1" - resolved "https://registry.yarnpkg.com/@typescript/native-preview/-/native-preview-7.0.0-dev.20260510.1.tgz#983a6d94d132b34d916b95bb1e3d0e687525d12a" - integrity sha512-05U6/Im+vmqGrFAVrHSeuoXBCwShhbiA+93VpSwEBYP4LMWk2JW9q87MydamL5g6ISEjIVlwQ4Dx35CauPAwpA== - optionalDependencies: - "@typescript/native-preview-darwin-arm64" "7.0.0-dev.20260510.1" - "@typescript/native-preview-darwin-x64" "7.0.0-dev.20260510.1" - "@typescript/native-preview-linux-arm" "7.0.0-dev.20260510.1" - "@typescript/native-preview-linux-arm64" "7.0.0-dev.20260510.1" - "@typescript/native-preview-linux-x64" "7.0.0-dev.20260510.1" - "@typescript/native-preview-win32-arm64" "7.0.0-dev.20260510.1" - "@typescript/native-preview-win32-x64" "7.0.0-dev.20260510.1" - "@vitest/coverage-v8@^4.0.18": - version "4.1.5" - resolved "https://registry.yarnpkg.com/@vitest/coverage-v8/-/coverage-v8-4.1.5.tgz#26bbdbebecd66be77fa1b63a9ed985dd86a3ba85" - integrity sha512-38C0/Ddb7HcRG0Z4/DUem8x57d2p9jYgp18mkaYswEOQBGsI1CG4f/hjm0ZCeaJfWhSZ4k7jgs29V1Zom7Ki9A== + version "4.1.6" + resolved "https://registry.yarnpkg.com/@vitest/coverage-v8/-/coverage-v8-4.1.6.tgz#1eacee5def68dfcb08c3ed5355edbad2a4c869b3" + integrity sha512-36l628fQ/9a/8ihy97eOtEnvWQEdqULQOJtcaxtoNq0G1w3Mxd4szSahOaMM9/NGyZ+hyKcMtIW/WIxq0XQViQ== dependencies: "@bcoe/v8-coverage" "^1.0.2" - "@vitest/utils" "4.1.5" + "@vitest/utils" "4.1.6" ast-v8-to-istanbul "^1.0.0" istanbul-lib-coverage "^3.2.2" istanbul-lib-report "^3.0.1" @@ -591,70 +543,70 @@ std-env "^4.0.0-rc.1" tinyrainbow "^3.1.0" -"@vitest/expect@4.1.5": - version "4.1.5" - resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-4.1.5.tgz#5caab19535cfb04fbc37087c5608d46e74dc9292" - integrity sha512-PWBaRY5JoKuRnHlUHfpV/KohFylaDZTupcXN1H9vYryNLOnitSw60Mw9IAE2r67NbwwzBw/Cc/8q9BK3kIX8Kw== +"@vitest/expect@4.1.6": + version "4.1.6" + resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-4.1.6.tgz#b50c9390aae6957ab4d9e20722cebb17d5bf169a" + integrity sha512-7EHDquPthALSV0jhhjgEW8FXaviMx7rSqu8W6oqCoAuOhKov814P99QDV1pxMA3QPv21YudvJngIhjrNI4opLg== dependencies: "@standard-schema/spec" "^1.1.0" "@types/chai" "^5.2.2" - "@vitest/spy" "4.1.5" - "@vitest/utils" "4.1.5" + "@vitest/spy" "4.1.6" + "@vitest/utils" "4.1.6" chai "^6.2.2" tinyrainbow "^3.1.0" -"@vitest/mocker@4.1.5": - version "4.1.5" - resolved "https://registry.yarnpkg.com/@vitest/mocker/-/mocker-4.1.5.tgz#9d5791733e4866cfb8af2d48ca371b127e7d2e93" - integrity sha512-/x2EmFC4mT4NNzqvC3fmesuV97w5FC903KPmey4gsnJiMQ3Be1IlDKVaDaG8iqaLFHqJ2FVEkxZk5VmeLjIItw== +"@vitest/mocker@4.1.6": + version "4.1.6" + resolved "https://registry.yarnpkg.com/@vitest/mocker/-/mocker-4.1.6.tgz#6b624045745236b02aca879a02aef68b72d9d4cd" + integrity sha512-MCFc63czMjEInOlcY2cpQCvCN+KgbAn+60xu9cMgP4sKaLC5JNAKw7JH8QdAnoAC88hW1IiSNZ+GgVXlN1UcMQ== dependencies: - "@vitest/spy" "4.1.5" + "@vitest/spy" "4.1.6" estree-walker "^3.0.3" magic-string "^0.30.21" -"@vitest/pretty-format@4.1.5": - version "4.1.5" - resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-4.1.5.tgz#4c13d77a77e2931e44db95522ed5700bcf0570d4" - integrity sha512-7I3q6l5qr03dVfMX2wCo9FxwSJbPdwKjy2uu/YPpU3wfHvIL4QHwVRp57OfGrDFeUJ8/8QdfBKIV12FTtLn00g== +"@vitest/pretty-format@4.1.6": + version "4.1.6" + resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-4.1.6.tgz#24a1c03a6b68a8775f8ddfec51d3636315edc3f5" + integrity sha512-h5SxD/IzNhZYnrSZRsUZQIC+vD0GY8cUvq0iwsmkFKixRCKLLWqCXa/FIQ4S1R+sI+PGoojkHsdNrbZiM9Qpgw== dependencies: tinyrainbow "^3.1.0" -"@vitest/runner@4.1.5": - version "4.1.5" - resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-4.1.5.tgz#a14dd2d2f48603f906dd52304a10c7fc623bb1de" - integrity sha512-2D+o7Pr82IEO46YPpoA/YU0neeyr6FTerQb5Ro7BUnBuv6NQtT/kmVnczngiMEBhzgqz2UZYl5gArejsyERDSQ== +"@vitest/runner@4.1.6": + version "4.1.6" + resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-4.1.6.tgz#b6d189e68bd9927c4f111ad089ff96e4757591b1" + integrity sha512-nOPCmn2+yD0ZNmKdsXGv/UxMMWbMuKeD6GyYncNwdkYDxpQvrPSKYj2rWuDjC2Y4b6w6hjip5dBKFzEUuZe3vA== dependencies: - "@vitest/utils" "4.1.5" + "@vitest/utils" "4.1.6" pathe "^2.0.3" -"@vitest/snapshot@4.1.5": - version "4.1.5" - resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-4.1.5.tgz#d07970d1448190ee5a258db6ab79c65b8018c13b" - integrity sha512-zypXEt4KH/XgKGPUz4eC2AvErYx0My5hfL8oDb1HzGFpEk1P62bxSohdyOmvz+d9UJwanI68MKwr2EquOaOgMQ== +"@vitest/snapshot@4.1.6": + version "4.1.6" + resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-4.1.6.tgz#14fdfc8baf6b4b3e4e35763431dbea3aaa8aa0eb" + integrity sha512-YhsdE6xAVfTDmzjxL2ZDUvjj+ZsgyOKe+TdQzqkD72wIOmHka8NuGQ6NpTNZv9D2Z63fbwWKJPeVpEw4EQgYxw== dependencies: - "@vitest/pretty-format" "4.1.5" - "@vitest/utils" "4.1.5" + "@vitest/pretty-format" "4.1.6" + "@vitest/utils" "4.1.6" magic-string "^0.30.21" pathe "^2.0.3" -"@vitest/spy@4.1.5": - version "4.1.5" - resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-4.1.5.tgz#fa7858ffab746fa9ac29496e626f5a0caf9a5a7f" - integrity sha512-2lNOsh6+R2Idnf1TCZqSwYlKN2E/iDlD8sgU59kYVl+OMDmvldO1VDk39smRfpUNwYpNRVn3w4YfuC7KfbBnkQ== +"@vitest/spy@4.1.6": + version "4.1.6" + resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-4.1.6.tgz#0a316893630f47fa545e33026cfc91575070d165" + integrity sha512-JFKxMx6udhwKh/Ldo270e17QX710vgunMkuPAvXjHSvC6oqLWAHhVhjg/I71q0u0CBSErIODV1Kjv0FQNSWjdg== -"@vitest/utils@4.1.5": - version "4.1.5" - resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-4.1.5.tgz#20d6a6ae651a0dd33f945548921698d49701fa43" - integrity sha512-76wdkrmfXfqGjueGgnb45ITPyUi1ycZ4IHgC2bhPDUfWHklY/q3MdLOAB+TF1e6xfl8NxNY0ZYaPCFNWSsw3Ug== +"@vitest/utils@4.1.6": + version "4.1.6" + resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-4.1.6.tgz#3f4acf1f60e135ec1ce896f10baa4cd6466d0d38" + integrity sha512-FxIY+U81R3LGKCxaHHFRQ5+g6/iRgGLmeHWdp2Amj4ljQRrEIWHmZyDfDYBRZlpyqA7qKxtS9DD1dhk8RnRIVQ== dependencies: - "@vitest/pretty-format" "4.1.5" + "@vitest/pretty-format" "4.1.6" convert-source-map "^2.0.0" tinyrainbow "^3.1.0" "@webgpu/types@^0.1.69": - version "0.1.69" - resolved "https://registry.yarnpkg.com/@webgpu/types/-/types-0.1.69.tgz#6b849bf370a1f29c78bd3aeba8e84c1150b237f2" - integrity sha512-RPmm6kgRbI8e98zSD3RVACvnuktIja5+yLgDAkTmxLr90BEwdTXRQWNLF3ETTTyH/8mKhznZuN5AveXYFEsMGQ== + version "0.1.70" + resolved "https://registry.yarnpkg.com/@webgpu/types/-/types-0.1.70.tgz#2beaf197eb97e0020a218d8158251ee3af7ba583" + integrity sha512-LFiNHHKMvmAEvwVew3JLJmTdShhbdwRFSImUshGhE2mGE8ybQzIo63l5uRp+YKnNx+8Qno8Kf6gN+DKMreIJCA== "@xmldom/xmldom@^0.8.12": version "0.8.13" @@ -1243,6 +1195,11 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + keyv@^4.5.4: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" @@ -1345,9 +1302,9 @@ lodash.merge@^4.6.2: integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== lru-cache@^11.2.4, lru-cache@^11.2.5, lru-cache@^11.2.6: - version "11.3.6" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.3.6.tgz#f0306ad6e9f0a5dc25b16aeba4e8f57b7ec2df55" - integrity sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A== + version "11.4.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.4.0.tgz#87a577bfa71f7c94dfd71692874b859d1ca41a28" + integrity sha512-W+R+kFL4HgVxONq2bhXPi3bGpzGe/yEhVOp233qw9wCRtgncJ15P3bC+e4zZMu4Cq7d+WAJjXGW0uUkifhcatA== magic-string@^0.30.21: version "0.30.21" @@ -1357,11 +1314,11 @@ magic-string@^0.30.21: "@jridgewell/sourcemap-codec" "^1.5.5" magicast@^0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/magicast/-/magicast-0.5.2.tgz#70cea9df729c164485049ea5df85a390281dfb9d" - integrity sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ== + version "0.5.3" + resolved "https://registry.yarnpkg.com/magicast/-/magicast-0.5.3.tgz#1800f6e76dd8b0dbe7257438a2c336aefabbd905" + integrity sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw== dependencies: - "@babel/parser" "^7.29.0" + "@babel/parser" "^7.29.3" "@babel/types" "^7.29.0" source-map-js "^1.2.1" @@ -1553,29 +1510,29 @@ resolve@^1.22.1: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -rolldown@1.0.0-rc.18: - version "1.0.0-rc.18" - resolved "https://registry.yarnpkg.com/rolldown/-/rolldown-1.0.0-rc.18.tgz#c597f89a4ce12e6fc918fa91e4f892b340aa92f0" - integrity sha512-phmyKBpuBdRYDf4hgyynGAYn/rDDe+iZXKVJ7WX5b1zQzpLkP5oJRPGsfJuHdzPMlyyEO/4sPW6yfSx2gf7lVg== +rolldown@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/rolldown/-/rolldown-1.0.1.tgz#2e2e839106dc47951e42dbba414f0f0ecf97ac68" + integrity sha512-X0KQHljNnEkWNqqiz9zJrGunh1B0HgOxLXvnFpCOcadzcy5qohZ3tqMEUg00vncoRovXuK3ZqCT9KnnKzoInFQ== dependencies: - "@oxc-project/types" "=0.128.0" - "@rolldown/pluginutils" "1.0.0-rc.18" + "@oxc-project/types" "=0.130.0" + "@rolldown/pluginutils" "^1.0.0" optionalDependencies: - "@rolldown/binding-android-arm64" "1.0.0-rc.18" - "@rolldown/binding-darwin-arm64" "1.0.0-rc.18" - "@rolldown/binding-darwin-x64" "1.0.0-rc.18" - "@rolldown/binding-freebsd-x64" "1.0.0-rc.18" - "@rolldown/binding-linux-arm-gnueabihf" "1.0.0-rc.18" - "@rolldown/binding-linux-arm64-gnu" "1.0.0-rc.18" - "@rolldown/binding-linux-arm64-musl" "1.0.0-rc.18" - "@rolldown/binding-linux-ppc64-gnu" "1.0.0-rc.18" - "@rolldown/binding-linux-s390x-gnu" "1.0.0-rc.18" - "@rolldown/binding-linux-x64-gnu" "1.0.0-rc.18" - "@rolldown/binding-linux-x64-musl" "1.0.0-rc.18" - "@rolldown/binding-openharmony-arm64" "1.0.0-rc.18" - "@rolldown/binding-wasm32-wasi" "1.0.0-rc.18" - "@rolldown/binding-win32-arm64-msvc" "1.0.0-rc.18" - "@rolldown/binding-win32-x64-msvc" "1.0.0-rc.18" + "@rolldown/binding-android-arm64" "1.0.1" + "@rolldown/binding-darwin-arm64" "1.0.1" + "@rolldown/binding-darwin-x64" "1.0.1" + "@rolldown/binding-freebsd-x64" "1.0.1" + "@rolldown/binding-linux-arm-gnueabihf" "1.0.1" + "@rolldown/binding-linux-arm64-gnu" "1.0.1" + "@rolldown/binding-linux-arm64-musl" "1.0.1" + "@rolldown/binding-linux-ppc64-gnu" "1.0.1" + "@rolldown/binding-linux-s390x-gnu" "1.0.1" + "@rolldown/binding-linux-x64-gnu" "1.0.1" + "@rolldown/binding-linux-x64-musl" "1.0.1" + "@rolldown/binding-openharmony-arm64" "1.0.1" + "@rolldown/binding-wasm32-wasi" "1.0.1" + "@rolldown/binding-win32-arm64-msvc" "1.0.1" + "@rolldown/binding-win32-x64-msvc" "1.0.1" saxes@^6.0.0: version "6.0.0" @@ -1715,19 +1672,24 @@ type-check@^0.4.0, type-check@~0.4.0: prelude-ls "^1.2.1" typescript-eslint@^8.26.1: - version "8.59.2" - resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.59.2.tgz#e24b4f7232e20112e40572dba162a829a738ce98" - integrity sha512-pJw051uomb3ZeCzGTpRb8RbEqB5Y4WWet8gl/GcTlU35BSx0PVdZ86/bqkQCyKKuraVQEK7r6kBHQXF+fBhkoQ== + version "8.59.3" + resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.59.3.tgz#4a41d9007faa539a66292189e2795eeb0b9fca29" + integrity sha512-KgusgyDgG4LI8Ih/sWaCtZ06tckLAS5CvT5A4D1Q7bYVoAAyzwiZvE4BmwDHkhRVkvhRBepKeASoFzQetha7Fg== dependencies: - "@typescript-eslint/eslint-plugin" "8.59.2" - "@typescript-eslint/parser" "8.59.2" - "@typescript-eslint/typescript-estree" "8.59.2" - "@typescript-eslint/utils" "8.59.2" + "@typescript-eslint/eslint-plugin" "8.59.3" + "@typescript-eslint/parser" "8.59.3" + "@typescript-eslint/typescript-estree" "8.59.3" + "@typescript-eslint/utils" "8.59.3" -typescript@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-6.0.3.tgz#90251dc007916e972786cb94d74d15b185577d21" - integrity sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw== +typescript@~5.5.4: + version "5.5.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.4.tgz#d9852d6c82bad2d2eda4fd74a5762a8f5909e9ba" + integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q== + +typescript@~5.8.2: + version "5.8.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e" + integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ== undici-types@~6.21.0: version "6.21.0" @@ -1742,30 +1704,30 @@ uri-js@^4.2.2: punycode "^2.1.0" "vite@^6.0.0 || ^7.0.0 || ^8.0.0", vite@^8.0.10: - version "8.0.11" - resolved "https://registry.yarnpkg.com/vite/-/vite-8.0.11.tgz#d128fe82a0dd24da5127d20560735f1cd7ade0a6" - integrity sha512-Jz1mxtUBR5xTT65VOdJZUUeoyLtqljmFkiUXhPTLZka3RDc9vpi/xXkyrnsdRcm2lIi3l3GPMnAidTsEGIj3Ow== + version "8.0.13" + resolved "https://registry.yarnpkg.com/vite/-/vite-8.0.13.tgz#d75fb40aeee761051b0eb4620993da625c7719ab" + integrity sha512-MFtjBYgzmSxmgA4RAfjIyXWpGe1oALnjgUTzzV7QLx/TKxCzjtMH6Fd9/eVK+5Fg1qNoz5VAwsmMs/NofrmJvw== dependencies: lightningcss "^1.32.0" picomatch "^4.0.4" postcss "^8.5.14" - rolldown "1.0.0-rc.18" + rolldown "1.0.1" tinyglobby "^0.2.16" optionalDependencies: fsevents "~2.3.3" vitest@^4.1.5: - version "4.1.5" - resolved "https://registry.yarnpkg.com/vitest/-/vitest-4.1.5.tgz#cda189c0cd9dd1c920be477c0f371b64ec14782a" - integrity sha512-9Xx1v3/ih3m9hN+SbfkUyy0JAs72ap3r7joc87XL6jwF0jGg6mFBvQ1SrwaX+h8BlkX6Hz9shdd1uo6AF+ZGpg== + version "4.1.6" + resolved "https://registry.yarnpkg.com/vitest/-/vitest-4.1.6.tgz#754875c9a09c5a3e8ca7d07d440659d92c19787f" + integrity sha512-6lvjbS3p9b4CrdCmguzbh2/4uoXhGE2q71R4OX5sqF9R1bo9Xd6fGrMAfvp5wnCzlBnFVdCOp6onuTQVbo8iUQ== dependencies: - "@vitest/expect" "4.1.5" - "@vitest/mocker" "4.1.5" - "@vitest/pretty-format" "4.1.5" - "@vitest/runner" "4.1.5" - "@vitest/snapshot" "4.1.5" - "@vitest/spy" "4.1.5" - "@vitest/utils" "4.1.5" + "@vitest/expect" "4.1.6" + "@vitest/mocker" "4.1.6" + "@vitest/pretty-format" "4.1.6" + "@vitest/runner" "4.1.6" + "@vitest/snapshot" "4.1.6" + "@vitest/spy" "4.1.6" + "@vitest/utils" "4.1.6" es-module-lexer "^2.0.0" expect-type "^1.3.0" magic-string "^0.30.21" @@ -1831,9 +1793,9 @@ word-wrap@^1.2.5: integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== ws@^8.18.3: - version "8.20.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.20.0.tgz#4cd9532358eba60bc863aad1623dfb045a4d4af8" - integrity sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA== + version "8.20.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.20.1.tgz#91a9ae2b312ccf98e0a85ec499b48cef45ab0ddb" + integrity sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w== xml-name-validator@^5.0.0: version "5.0.0"