From 0e07a0d4bcaabfaf043f74164ecf006d920702e2 Mon Sep 17 00:00:00 2001
From: AnthonyFuller <24512050+AnthonyFuller@users.noreply.github.com>
Date: Sun, 22 Mar 2026 03:24:15 +0000
Subject: [PATCH 01/11] feat: initial implementation of checking entitlements
with Steam directly using the app ticket
---
components/entitlementStrategies.ts | 234 +++++++++++++++++++++++++++-
components/flags.ts | 20 +++
components/oauthToken.ts | 59 +++++--
package.json | 3 +-
yarn.lock | 180 ++++++++++++++++++++-
5 files changed, 481 insertions(+), 15 deletions(-)
diff --git a/components/entitlementStrategies.ts b/components/entitlementStrategies.ts
index d3fd1ad24..a51444e84 100644
--- a/components/entitlementStrategies.ts
+++ b/components/entitlementStrategies.ts
@@ -16,7 +16,7 @@
* along with this program. If not, see .
*/
-import { AxiosError, AxiosResponse } from "axios"
+import axios, { AxiosError, AxiosResponse } from "axios"
import { log, LogLevel } from "./loggingInterop"
import { userAuths } from "./officialServerAuth"
import {
@@ -28,6 +28,14 @@ import {
} from "./platformEntitlements"
import { GameVersion } from "./types/types"
import { getRemoteService } from "./utils"
+import { getFlag } from "./flags"
+import { parseAppTicket } from "steam-appticket"
+import { createHash } from "crypto"
+
+// An in-memory cache of Steam ownership tickets to entitlements (they're valid for up to 21 days)
+// For most users, this won't provide any benefit since they'll be restarting Peacock often,
+// but this is more here for those running it 24/7 on a server somewhere.
+const STEAM_TICKET_CACHE: Map = new Map()
/**
* The base class for an entitlement strategy.
@@ -39,6 +47,12 @@ abstract class EntitlementStrategy {
accessToken: string,
userId: string,
): string[] | Promise
+
+ abstract get(
+ clientToken: string,
+ identity: string,
+ steamId: string,
+ ): string[] | Promise
}
/**
@@ -56,6 +70,224 @@ export class EpicH3Strategy extends EntitlementStrategy {
}
}
+/**
+ * Provider for any Steam-based game using the ISteamUserAuth API.
+ *
+ * @internal
+ */
+type SteamAuthMethod = "OFFICIAL" | "BACKEND" | "STEAM" | "STEAM_STRICT"
+type SteamAuthResult =
+ | {
+ success: true
+ steamId: string
+ entitlements: string[]
+ }
+ | {
+ success: false
+ code: number
+ error: string
+ }
+type SteamAuthResponse = {
+ response: {
+ error?: {
+ errorcode: number
+ errordesc: string
+ }
+ params?: {
+ result: string
+ steamid: string
+ ownersteamid: string
+ vacbanned: boolean
+ publisherbanned: boolean
+ }
+ }
+}
+
+export class SteamStrategy extends EntitlementStrategy {
+ private readonly _apiKey: string = getFlag("steamApiKey") as SteamAuthMethod
+ public readonly isValid: boolean = false
+
+ constructor(private readonly _appId: string) {
+ super()
+ this._appId = _appId
+
+ const method = getFlag("steamAuthenticationMethod") as SteamAuthMethod
+
+ switch (method) {
+ case "BACKEND": {
+ const host = getFlag("leaderboardsHost") as string
+
+ if (!host) {
+ log(
+ LogLevel.WARN,
+ "steamAuthenticationMethod is set to 'BACKEND' but 'leaderboardsHost' is null or empty - using official!",
+ "SteamStrategy",
+ )
+ break
+ }
+
+ this.isValid = true
+ break
+ }
+ case "STEAM":
+ case "STEAM_STRICT": {
+ if (!this._apiKey) {
+ log(
+ LogLevel.WARN,
+ `steamAuthenticationMethod is set to '${method}' but 'steamApiKey' is null or empty${method !== "STEAM_STRICT" ? " - using official" : ""}!`,
+ "SteamStrategy",
+ )
+ break
+ }
+
+ this.isValid = true
+ break
+ }
+ case "OFFICIAL":
+ break
+ }
+ }
+
+ private async _getFromBackend(
+ _clientToken: string,
+ ): Promise {
+ return {
+ success: false,
+ code: 500,
+ error: "Backend validation not implemented",
+ }
+ }
+
+ private async _getFromSteam(
+ clientToken: string,
+ identity: string,
+ ): Promise {
+ const ticket = parseAppTicket(Buffer.from(clientToken, "hex"))
+
+ if (!ticket?.isValid) {
+ return {
+ success: false,
+ code: 400,
+ error: "Invalid app ticket.",
+ }
+ }
+
+ try {
+ const resp = await axios(
+ "https://api.steampowered.com/ISteamUserAuth/AuthenticateUserTicket/v1",
+ {
+ params: {
+ key: this._apiKey,
+ appid: this._appId,
+ ticket: clientToken,
+ identity,
+ },
+ },
+ )
+
+ if (resp.status !== 200) {
+ return {
+ success: false,
+ code: resp.status,
+ error: `${resp.statusText}`,
+ }
+ }
+
+ const data = resp.data as SteamAuthResponse
+
+ if (data.response.error) {
+ return {
+ success: false,
+ code: data.response.error.errorcode,
+ error: `${data.response.error.errordesc}`,
+ }
+ }
+
+ if (data.response.params!.result !== "OK") {
+ return {
+ success: false,
+ code: 200,
+ error: `${data.response.params!.result}`,
+ }
+ }
+
+ return {
+ success: true,
+ steamId: data.response.params!.steamid,
+ entitlements: [
+ ticket.appID.toString(),
+ ...ticket.dlc.map((dlc) => dlc.appID.toString()),
+ ],
+ }
+ } catch (error) {
+ if (error instanceof AxiosError) {
+ return {
+ success: false,
+ code: error.response?.status ?? 400,
+ error: `${error.response?.statusText}`,
+ }
+ } else {
+ return {
+ success: false,
+ code: 400,
+ error: `${error}`,
+ }
+ }
+ }
+ }
+
+ // @ts-expect-error There are two functions we can overload
+ override async get(
+ clientToken: string,
+ identity: string,
+ steamId: string,
+ ): Promise {
+ if (!this.isValid) return []
+
+ const hash = createHash("sha256")
+ .update(
+ clientToken.startsWith("14000000") &&
+ clientToken.length > 52 * 2
+ ? clientToken.substring(52 * 2) // Skip 52 bytes to get the ownership ticket (this part can be valid for up to 21 days)
+ : clientToken,
+ )
+ .digest("hex")
+
+ if (STEAM_TICKET_CACHE.has(hash)) {
+ return STEAM_TICKET_CACHE.get(hash)!
+ }
+
+ const authMethod = getFlag(
+ "steamAuthenticationMethod",
+ ) as SteamAuthMethod
+ const res = await (authMethod === "BACKEND"
+ ? this._getFromBackend(clientToken)
+ : this._getFromSteam(clientToken, identity))
+
+ if (!res.success) {
+ log(
+ LogLevel.WARN,
+ `Failed to get entitlements from ${authMethod.split("_")[0]}. Code: ${res.code}, Error: ${res.error} `,
+ "SteamStrategy",
+ )
+ return []
+ }
+
+ if (res.steamId !== steamId) {
+ log(
+ LogLevel.WARN,
+ `Encountered mismatched SteamID when validating authentication token! Expected: ${steamId}, Got: ${res.steamId}`,
+ "SteamStrategy",
+ )
+ return []
+ }
+
+ STEAM_TICKET_CACHE.set(hash, res.entitlements)
+
+ return res.entitlements
+ }
+}
+
/**
* Provider for any game using the official servers.
*
diff --git a/components/flags.ts b/components/flags.ts
index 4cab8e440..f58d7758a 100644
--- a/components/flags.ts
+++ b/components/flags.ts
@@ -130,6 +130,26 @@ export const defaultFlags: Flags = {
possibleValues: ["SAVEASREQUESTED", "ONLINE", "OFFLINE"],
default: "SAVEASREQUESTED",
},
+ steamAuthenticationMethod: {
+ category: "Services",
+ title: "steamAuthenticationMethod",
+ desc: "How users connecting via Steam should be authenticated. OFFICIAL = Official Servers, BACKEND = Using a separate backend server (uses leaderboardsHost), STEAM = Issues requests to Steam directly from Peacock, requires 'steamApiKey' to be set, STEAM_STRICT = Same as Steam, but will never fallback to official. OFFICIAL is used as a fallback if other methods fail.",
+ possibleValues: [
+ "OFFICIAL",
+ "BACKEND",
+ "STEAM",
+ "STEAM_STRICT",
+ ],
+ default: "OFFICIAL", // TODO: Change this to BACKEND when ready.
+ showIngame: false,
+ },
+ steamApiKey: {
+ category: "Services",
+ title: "Steam API Key",
+ desc: "The Steam API key to use when 'steamAuthenticationMethod' is set to 'STEAM' or 'STEAM_STRICT'.",
+ default: "",
+ showIngame: false,
+ },
liveSplit: {
category: "Splitter",
title: "LiveSplit",
diff --git a/components/oauthToken.ts b/components/oauthToken.ts
index fe2f70efd..2a2268431 100644
--- a/components/oauthToken.ts
+++ b/components/oauthToken.ts
@@ -39,10 +39,12 @@ import {
EpicH1Strategy,
EpicH3Strategy,
IOIStrategy,
+ SteamStrategy,
SteamH1Strategy,
SteamH2Strategy,
SteamScpcStrategy,
} from "./entitlementStrategies"
+import { getFlag } from "./flags"
export const JWT_SECRET = PEACOCK_DEV
? "secret"
@@ -51,6 +53,8 @@ export const JWT_SECRET = PEACOCK_DEV
export type OAuthTokenBody = {
grant_type: "external_steam" | "external_epic" | "refresh_token"
steam_userid?: string
+ steam_clienttoken?: string
+ steam_identity?: string
epic_userid?: string
access_token: string
pId?: string
@@ -222,17 +226,19 @@ export async function handleOAuthToken(
/*
Store user auth for all games except scpc
*/
- if (!isScpc) {
- const authContainer = new OfficialServerAuth(
- gameVersion,
- req.body.access_token,
- )
+ const authUser = async () => {
+ if (!isScpc) {
+ const authContainer = new OfficialServerAuth(
+ gameVersion,
+ req.body.access_token,
+ )
- log(LogLevel.DEBUG, `Setting up container with ID ${req.body.pId}.`)
+ log(LogLevel.DEBUG, `Setting up container with ID ${req.body.pId}.`)
- userAuths.set(req.body.pId, authContainer)
+ userAuths.set(req.body.pId!, authContainer)
- await authContainer._initiallyAuthenticate(req)
+ await authContainer._initiallyAuthenticate(req)
+ }
}
let userData = getUserData(req.body.pId, gameVersion)
@@ -266,6 +272,10 @@ export async function handleOAuthToken(
return new SteamScpcStrategy().get()
}
+ // Authenticate user with official if we're not on H3 Steam (otherwise the token will be invalidated)
+ if (gameVersion !== "h3" || external_platform !== "steam")
+ await authUser()
+
if (gameVersion === "h1") {
if (external_platform === "steam") {
return new SteamH1Strategy().get()
@@ -288,10 +298,35 @@ export async function handleOAuthToken(
req.body.epic_userid!,
)
} else if (external_platform === "steam") {
- return await new IOIStrategy(
- gameVersion,
- STEAM_NAMESPACE_2021,
- ).get(req.body.pId!)
+ let ents = await new SteamStrategy(external_appid).get(
+ req.body.steam_clienttoken!,
+ req.body.steam_identity!,
+ req.body.steam_userid!,
+ )
+ await authUser()
+
+ if (ents.length === 0) {
+ if (
+ getFlag("steamAuthenticationMethod") === "STEAM_STRICT"
+ ) {
+ log(
+ LogLevel.WARN,
+ "No entitlements returned by SteamStrategy with strict mode enabled!",
+ )
+ return []
+ }
+
+ log(
+ LogLevel.WARN,
+ "No entitlements returned by SteamStrategy - defaulting to official!",
+ )
+ ents = await new IOIStrategy(
+ gameVersion,
+ external_appid,
+ ).get(req.body.pId!)
+ }
+
+ return ents
} else {
log(LogLevel.ERROR, "Unsupported platform.")
return []
diff --git a/package.json b/package.json
index a8a755c82..ae21a64b5 100644
--- a/package.json
+++ b/package.json
@@ -69,7 +69,8 @@
"random": "^5.3.0",
"semver": "^7.7.1",
"send": "^1.1.0",
- "serve-static": "^2.1.0"
+ "serve-static": "^2.1.0",
+ "steam-appticket": "^2.0.1"
},
"devDependencies": {
"@eslint/compat": "^1.2.7",
diff --git a/yarn.lock b/yarn.lock
index 5c0983045..0c93008ef 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -39,6 +39,22 @@ __metadata:
languageName: node
linkType: hard
+"@doctormckay/stdlib@npm:^2.10.0":
+ version: 2.10.0
+ resolution: "@doctormckay/stdlib@npm:2.10.0"
+ dependencies:
+ psl: "npm:^1.9.0"
+ checksum: 10/44b0075fd9316355e7cac7bfb349a2b69e57423be88b89b6e6249ac9d69436242933fc801d0f49cf3248815bfd2a75df214622d1b85c9f027f822351423dec9e
+ languageName: node
+ linkType: hard
+
+"@doctormckay/steam-crypto@npm:^1.2.0":
+ version: 1.2.0
+ resolution: "@doctormckay/steam-crypto@npm:1.2.0"
+ checksum: 10/b614ff92f68eebec154ec3f1ce002ad0e40158b1ea193080924dee68a7ca1b36c5831f21eefc86827f7dca3d4686877747931a27d1c4e8f13af2480388be21d1
+ languageName: node
+ linkType: hard
+
"@esbuild/aix-ppc64@npm:0.25.0":
version: 0.25.0
resolution: "@esbuild/aix-ppc64@npm:0.25.0"
@@ -598,6 +614,7 @@ __metadata:
semver: "npm:^7.7.1"
send: "npm:^1.1.0"
serve-static: "npm:^2.1.0"
+ steam-appticket: "npm:^2.0.1"
terser: "npm:^5.39.0"
typescript: "npm:5.8.2"
winston: "npm:3.13.0"
@@ -664,6 +681,79 @@ __metadata:
languageName: node
linkType: hard
+"@protobufjs/aspromise@npm:^1.1.1, @protobufjs/aspromise@npm:^1.1.2":
+ version: 1.1.2
+ resolution: "@protobufjs/aspromise@npm:1.1.2"
+ checksum: 10/8a938d84fe4889411296db66b29287bd61ea3c14c2d23e7a8325f46a2b8ce899857c5f038d65d7641805e6c1d06b495525c7faf00c44f85a7ee6476649034969
+ languageName: node
+ linkType: hard
+
+"@protobufjs/base64@npm:^1.1.2":
+ version: 1.1.2
+ resolution: "@protobufjs/base64@npm:1.1.2"
+ checksum: 10/c71b100daeb3c9bdccab5cbc29495b906ba0ae22ceedc200e1ba49717d9c4ab15a6256839cebb6f9c6acae4ed7c25c67e0a95e734f612b258261d1a3098fe342
+ languageName: node
+ linkType: hard
+
+"@protobufjs/codegen@npm:^2.0.4":
+ version: 2.0.4
+ resolution: "@protobufjs/codegen@npm:2.0.4"
+ checksum: 10/c6ee5fa172a8464f5253174d3c2353ea520c2573ad7b6476983d9b1346f4d8f2b44aa29feb17a949b83c1816bc35286a5ea265ed9d8fdd2865acfa09668c0447
+ languageName: node
+ linkType: hard
+
+"@protobufjs/eventemitter@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "@protobufjs/eventemitter@npm:1.1.0"
+ checksum: 10/03af3e99f17ad421283d054c88a06a30a615922a817741b43ca1b13e7c6b37820a37f6eba9980fb5150c54dba6e26cb6f7b64a6f7d8afa83596fafb3afa218c3
+ languageName: node
+ linkType: hard
+
+"@protobufjs/fetch@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "@protobufjs/fetch@npm:1.1.0"
+ dependencies:
+ "@protobufjs/aspromise": "npm:^1.1.1"
+ "@protobufjs/inquire": "npm:^1.1.0"
+ checksum: 10/67ae40572ad536e4ef94269199f252c024b66e3059850906bdaee161ca1d75c73d04d35cd56f147a8a5a079f5808e342b99e61942c1dae15604ff0600b09a958
+ languageName: node
+ linkType: hard
+
+"@protobufjs/float@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "@protobufjs/float@npm:1.0.2"
+ checksum: 10/634c2c989da0ef2f4f19373d64187e2a79f598c5fb7991afb689d29a2ea17c14b796b29725945fa34b9493c17fb799e08ac0a7ccaae460ee1757d3083ed35187
+ languageName: node
+ linkType: hard
+
+"@protobufjs/inquire@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "@protobufjs/inquire@npm:1.1.0"
+ checksum: 10/c09efa34a5465cb120775e1a482136f2340a58b4abce7e93d72b8b5a9324a0e879275016ef9fcd73d72a4731639c54f2bb755bb82f916e4a78892d1d840bb3d2
+ languageName: node
+ linkType: hard
+
+"@protobufjs/path@npm:^1.1.2":
+ version: 1.1.2
+ resolution: "@protobufjs/path@npm:1.1.2"
+ checksum: 10/bb709567935fd385a86ad1f575aea98131bbd719c743fb9b6edd6b47ede429ff71a801cecbd64fc72deebf4e08b8f1bd8062793178cdaed3713b8d15771f9b83
+ languageName: node
+ linkType: hard
+
+"@protobufjs/pool@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "@protobufjs/pool@npm:1.1.0"
+ checksum: 10/b9c7047647f6af28e92aac54f6f7c1f7ff31b201b4bfcc7a415b2861528854fce3ec666d7e7e10fd744da905f7d4aef2205bbcc8944ca0ca7a82e18134d00c46
+ languageName: node
+ linkType: hard
+
+"@protobufjs/utf8@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "@protobufjs/utf8@npm:1.1.0"
+ checksum: 10/131e289c57534c1d73a0e55782d6751dd821db1583cb2f7f7e017c9d6747addaebe79f28120b2e0185395d990aad347fb14ffa73ef4096fa38508d61a0e64602
+ languageName: node
+ linkType: hard
+
"@radix-ui/primitive@npm:1.0.1":
version: 1.0.1
resolution: "@radix-ui/primitive@npm:1.0.1"
@@ -1288,6 +1378,15 @@ __metadata:
languageName: node
linkType: hard
+"@types/node@npm:>=13.7.0":
+ version: 25.5.0
+ resolution: "@types/node@npm:25.5.0"
+ dependencies:
+ undici-types: "npm:~7.18.0"
+ checksum: 10/b1e8116bd8c9ff62e458b76d28a59cf7631537bb17e8961464bf754dd5b07b46f1620f568b2f89970505af9eef478dd74c614651b454c1ea95949ec472c64fcb
+ languageName: node
+ linkType: hard
+
"@types/parseurl@npm:^1.3.3":
version: 1.3.3
resolution: "@types/parseurl@npm:1.3.3"
@@ -1885,6 +1984,15 @@ __metadata:
languageName: node
linkType: hard
+"bytebuffer@npm:^5.0.1":
+ version: 5.0.1
+ resolution: "bytebuffer@npm:5.0.1"
+ dependencies:
+ long: "npm:~3"
+ checksum: 10/f3e9739ed9ab30e19d985fc3dadfdbd631d030874bbb313feefddac756f21ac10957257737e630fd9959744318e6e8b7d8c35b797519693bf1897be16c560970
+ languageName: node
+ linkType: hard
+
"bytes@npm:3.1.2, bytes@npm:^3.1.2":
version: 3.1.2
resolution: "bytes@npm:3.1.2"
@@ -3600,6 +3708,20 @@ __metadata:
languageName: node
linkType: hard
+"long@npm:^5.0.0":
+ version: 5.3.2
+ resolution: "long@npm:5.3.2"
+ checksum: 10/b6b55ddae56fcce2864d37119d6b02fe28f6dd6d9e44fd22705f86a9254b9321bd69e9ffe35263b4846d54aba197c64882adcb8c543f2383c1e41284b321ea64
+ languageName: node
+ linkType: hard
+
+"long@npm:~3":
+ version: 3.2.0
+ resolution: "long@npm:3.2.0"
+ checksum: 10/ffc685ec458ddf71a830d6deb62ff7dc551a736d47473350d9e077c22db96ec88c8a3554c11ffce7d7f2291b0c30da36629e4d0a97c29b5360dc977533c96d28
+ languageName: node
+ linkType: hard
+
"loose-envify@npm:^1.0.0, loose-envify@npm:^1.1.0":
version: 1.4.0
resolution: "loose-envify@npm:1.4.0"
@@ -4305,6 +4427,26 @@ __metadata:
languageName: node
linkType: hard
+"protobufjs@npm:^7.3.2":
+ version: 7.5.4
+ resolution: "protobufjs@npm:7.5.4"
+ dependencies:
+ "@protobufjs/aspromise": "npm:^1.1.2"
+ "@protobufjs/base64": "npm:^1.1.2"
+ "@protobufjs/codegen": "npm:^2.0.4"
+ "@protobufjs/eventemitter": "npm:^1.1.0"
+ "@protobufjs/fetch": "npm:^1.1.0"
+ "@protobufjs/float": "npm:^1.0.2"
+ "@protobufjs/inquire": "npm:^1.1.0"
+ "@protobufjs/path": "npm:^1.1.2"
+ "@protobufjs/pool": "npm:^1.1.0"
+ "@protobufjs/utf8": "npm:^1.1.0"
+ "@types/node": "npm:>=13.7.0"
+ long: "npm:^5.0.0"
+ checksum: 10/88d677bb6f11a2ecec63fdd053dfe6d31120844d04e865efa9c8fbe0674cd077d6624ecfdf014018a20dcb114ae2a59c1b21966dd8073e920650c71370966439
+ languageName: node
+ linkType: hard
+
"proxy-addr@npm:~2.0.7":
version: 2.0.7
resolution: "proxy-addr@npm:2.0.7"
@@ -4322,6 +4464,15 @@ __metadata:
languageName: node
linkType: hard
+"psl@npm:^1.9.0":
+ version: 1.15.0
+ resolution: "psl@npm:1.15.0"
+ dependencies:
+ punycode: "npm:^2.3.1"
+ checksum: 10/5e7467eb5196eb7900d156783d12907d445c0122f76c73203ce96b148a6ccf8c5450cc805887ffada38ff92d634afcf33720c24053cb01d5b6598d1c913c5caf
+ languageName: node
+ linkType: hard
+
"pump@npm:^3.0.0":
version: 3.0.0
resolution: "pump@npm:3.0.0"
@@ -4343,7 +4494,7 @@ __metadata:
languageName: node
linkType: hard
-"punycode@npm:^2.1.0":
+"punycode@npm:^2.1.0, punycode@npm:^2.3.1":
version: 2.3.1
resolution: "punycode@npm:2.3.1"
checksum: 10/febdc4362bead22f9e2608ff0171713230b57aff9dddc1c273aa2a651fbd366f94b7d6a71d78342a7c0819906750351ca7f2edd26ea41b626d87d6a13d1bd059
@@ -4996,6 +5147,26 @@ __metadata:
languageName: node
linkType: hard
+"steam-appticket@npm:^2.0.1":
+ version: 2.0.1
+ resolution: "steam-appticket@npm:2.0.1"
+ dependencies:
+ "@doctormckay/stdlib": "npm:^2.10.0"
+ "@doctormckay/steam-crypto": "npm:^1.2.0"
+ bytebuffer: "npm:^5.0.1"
+ protobufjs: "npm:^7.3.2"
+ steamid: "npm:^2.1.0"
+ checksum: 10/9643eb026b1fbf0b7b3bca2633050d59c4eebe61fba7311cf69361a5fc60cdefd42f2acf2495aa440306475e1efe782999cf9b6b32ec4ba18cf1d036217109a5
+ languageName: node
+ linkType: hard
+
+"steamid@npm:^2.1.0":
+ version: 2.1.0
+ resolution: "steamid@npm:2.1.0"
+ checksum: 10/e23d0eb1d3296199ff827eab9415c136fe5b94ce492e696b0c29caf33afeb74a9cfc3802437b319d008db82024b525411cf6fabb76cef61cc70744358fe870a4
+ languageName: node
+ linkType: hard
+
"stream-shift@npm:^1.0.0":
version: 1.0.3
resolution: "stream-shift@npm:1.0.3"
@@ -5320,6 +5491,13 @@ __metadata:
languageName: node
linkType: hard
+"undici-types@npm:~7.18.0":
+ version: 7.18.2
+ resolution: "undici-types@npm:7.18.2"
+ checksum: 10/e61a5918f624d68420c3ca9d301e9f15b61cba6e97be39fe2ce266dd6151e4afe424d679372638826cb506be33952774e0424141200111a9857e464216c009af
+ languageName: node
+ linkType: hard
+
"unique-filename@npm:^3.0.0":
version: 3.0.0
resolution: "unique-filename@npm:3.0.0"
From 96dfce0f6d84d5c54863bc3475615aa35ce9b16e Mon Sep 17 00:00:00 2001
From: AnthonyFuller <24512050+AnthonyFuller@users.noreply.github.com>
Date: Sat, 28 Mar 2026 23:14:58 +0000
Subject: [PATCH 02/11] chore: update yarn lockfile
---
yarn.lock | 882 +++++++++++++++++++++++++++++++-----------------------
1 file changed, 505 insertions(+), 377 deletions(-)
diff --git a/yarn.lock b/yarn.lock
index 0c93008ef..f99adf94b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -431,6 +431,13 @@ __metadata:
languageName: node
linkType: hard
+"@jridgewell/sourcemap-codec@npm:^1.5.5":
+ version: 1.5.5
+ resolution: "@jridgewell/sourcemap-codec@npm:1.5.5"
+ checksum: 10/5d9d207b462c11e322d71911e55e21a4e2772f71ffe8d6f1221b8eb5ae6774458c1d242f897fb0814e8714ca9a6b498abfa74dfe4f434493342902b1a48b33a5
+ languageName: node
+ linkType: hard
+
"@jridgewell/trace-mapping@npm:^0.3.9":
version: 0.3.22
resolution: "@jridgewell/trace-mapping@npm:0.3.22"
@@ -483,6 +490,18 @@ __metadata:
languageName: node
linkType: hard
+"@napi-rs/wasm-runtime@npm:^1.1.1":
+ version: 1.1.2
+ resolution: "@napi-rs/wasm-runtime@npm:1.1.2"
+ dependencies:
+ "@tybys/wasm-util": "npm:^0.10.1"
+ peerDependencies:
+ "@emnapi/core": ^1.7.1
+ "@emnapi/runtime": ^1.7.1
+ checksum: 10/fcb8a5cff65dfb6c44277a1f7a16da5a1be2ed609c83e13f4bb621db97b511129b8ccf808794c8906abd3561e10c2e66d3ba550f0a1a0db18f53f1e399a0a5f8
+ languageName: node
+ linkType: hard
+
"@nodelib/fs.scandir@npm:2.1.5":
version: 2.1.5
resolution: "@nodelib/fs.scandir@npm:2.1.5"
@@ -532,6 +551,13 @@ __metadata:
languageName: node
linkType: hard
+"@oxc-project/types@npm:=0.122.0":
+ version: 0.122.0
+ resolution: "@oxc-project/types@npm:0.122.0"
+ checksum: 10/2b33895c7701a595d10b9c7b0927222954becc4c6cbde7a7b582e9524828937368baacba1cbb6e3c33bc9a18e0a35435ffff6c53f511762ae872d55d3e993a8c
+ languageName: node
+ linkType: hard
+
"@peacockproject/core@workspace:packaging/typedefs":
version: 0.0.0-use.local
resolution: "@peacockproject/core@workspace:packaging/typedefs"
@@ -634,9 +660,9 @@ __metadata:
resolution: "@peacockproject/tests@workspace:tests"
dependencies:
"@rdil/factorygirl": "npm:^0.2.0"
- "@vitest/ui": "npm:^3.0.8"
- vite: "npm:^6.2.1"
- vitest: "npm:^3.0.8"
+ "@vitest/ui": "npm:^4.1.0"
+ vite: "npm:^8.0.1"
+ vitest: "npm:^4.1.0"
languageName: unknown
linkType: soft
@@ -658,7 +684,7 @@ __metadata:
rollup-plugin-license: "npm:^3.4.0"
swr: "npm:^2.3.3"
typescript: "npm:5.8.2"
- vite: "npm:^6.2.1"
+ vite: "npm:^8.0.1"
peerDependencies:
rollup: "*"
peerDependenciesMeta:
@@ -1103,136 +1129,117 @@ __metadata:
languageName: node
linkType: hard
-"@rollup/rollup-android-arm-eabi@npm:4.35.0":
- version: 4.35.0
- resolution: "@rollup/rollup-android-arm-eabi@npm:4.35.0"
- conditions: os=android & cpu=arm
- languageName: node
- linkType: hard
-
-"@rollup/rollup-android-arm64@npm:4.35.0":
- version: 4.35.0
- resolution: "@rollup/rollup-android-arm64@npm:4.35.0"
+"@rolldown/binding-android-arm64@npm:1.0.0-rc.12":
+ version: 1.0.0-rc.12
+ resolution: "@rolldown/binding-android-arm64@npm:1.0.0-rc.12"
conditions: os=android & cpu=arm64
languageName: node
linkType: hard
-"@rollup/rollup-darwin-arm64@npm:4.35.0":
- version: 4.35.0
- resolution: "@rollup/rollup-darwin-arm64@npm:4.35.0"
+"@rolldown/binding-darwin-arm64@npm:1.0.0-rc.12":
+ version: 1.0.0-rc.12
+ resolution: "@rolldown/binding-darwin-arm64@npm:1.0.0-rc.12"
conditions: os=darwin & cpu=arm64
languageName: node
linkType: hard
-"@rollup/rollup-darwin-x64@npm:4.35.0":
- version: 4.35.0
- resolution: "@rollup/rollup-darwin-x64@npm:4.35.0"
+"@rolldown/binding-darwin-x64@npm:1.0.0-rc.12":
+ version: 1.0.0-rc.12
+ resolution: "@rolldown/binding-darwin-x64@npm:1.0.0-rc.12"
conditions: os=darwin & cpu=x64
languageName: node
linkType: hard
-"@rollup/rollup-freebsd-arm64@npm:4.35.0":
- version: 4.35.0
- resolution: "@rollup/rollup-freebsd-arm64@npm:4.35.0"
- conditions: os=freebsd & cpu=arm64
- languageName: node
- linkType: hard
-
-"@rollup/rollup-freebsd-x64@npm:4.35.0":
- version: 4.35.0
- resolution: "@rollup/rollup-freebsd-x64@npm:4.35.0"
+"@rolldown/binding-freebsd-x64@npm:1.0.0-rc.12":
+ version: 1.0.0-rc.12
+ resolution: "@rolldown/binding-freebsd-x64@npm:1.0.0-rc.12"
conditions: os=freebsd & cpu=x64
languageName: node
linkType: hard
-"@rollup/rollup-linux-arm-gnueabihf@npm:4.35.0":
- version: 4.35.0
- resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.35.0"
- conditions: os=linux & cpu=arm & libc=glibc
- languageName: node
- linkType: hard
-
-"@rollup/rollup-linux-arm-musleabihf@npm:4.35.0":
- version: 4.35.0
- resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.35.0"
- conditions: os=linux & cpu=arm & libc=musl
+"@rolldown/binding-linux-arm-gnueabihf@npm:1.0.0-rc.12":
+ version: 1.0.0-rc.12
+ resolution: "@rolldown/binding-linux-arm-gnueabihf@npm:1.0.0-rc.12"
+ conditions: os=linux & cpu=arm
languageName: node
linkType: hard
-"@rollup/rollup-linux-arm64-gnu@npm:4.35.0":
- version: 4.35.0
- resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.35.0"
+"@rolldown/binding-linux-arm64-gnu@npm:1.0.0-rc.12":
+ version: 1.0.0-rc.12
+ resolution: "@rolldown/binding-linux-arm64-gnu@npm:1.0.0-rc.12"
conditions: os=linux & cpu=arm64 & libc=glibc
languageName: node
linkType: hard
-"@rollup/rollup-linux-arm64-musl@npm:4.35.0":
- version: 4.35.0
- resolution: "@rollup/rollup-linux-arm64-musl@npm:4.35.0"
+"@rolldown/binding-linux-arm64-musl@npm:1.0.0-rc.12":
+ version: 1.0.0-rc.12
+ resolution: "@rolldown/binding-linux-arm64-musl@npm:1.0.0-rc.12"
conditions: os=linux & cpu=arm64 & libc=musl
languageName: node
linkType: hard
-"@rollup/rollup-linux-loongarch64-gnu@npm:4.35.0":
- version: 4.35.0
- resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.35.0"
- conditions: os=linux & cpu=loong64 & libc=glibc
+"@rolldown/binding-linux-ppc64-gnu@npm:1.0.0-rc.12":
+ version: 1.0.0-rc.12
+ resolution: "@rolldown/binding-linux-ppc64-gnu@npm:1.0.0-rc.12"
+ conditions: os=linux & cpu=ppc64 & libc=glibc
languageName: node
linkType: hard
-"@rollup/rollup-linux-powerpc64le-gnu@npm:4.35.0":
- version: 4.35.0
- resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.35.0"
- conditions: os=linux & cpu=ppc64 & libc=glibc
+"@rolldown/binding-linux-s390x-gnu@npm:1.0.0-rc.12":
+ version: 1.0.0-rc.12
+ resolution: "@rolldown/binding-linux-s390x-gnu@npm:1.0.0-rc.12"
+ conditions: os=linux & cpu=s390x & libc=glibc
languageName: node
linkType: hard
-"@rollup/rollup-linux-riscv64-gnu@npm:4.35.0":
- version: 4.35.0
- resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.35.0"
- conditions: os=linux & cpu=riscv64 & libc=glibc
+"@rolldown/binding-linux-x64-gnu@npm:1.0.0-rc.12":
+ version: 1.0.0-rc.12
+ resolution: "@rolldown/binding-linux-x64-gnu@npm:1.0.0-rc.12"
+ conditions: os=linux & cpu=x64 & libc=glibc
languageName: node
linkType: hard
-"@rollup/rollup-linux-s390x-gnu@npm:4.35.0":
- version: 4.35.0
- resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.35.0"
- conditions: os=linux & cpu=s390x & libc=glibc
+"@rolldown/binding-linux-x64-musl@npm:1.0.0-rc.12":
+ version: 1.0.0-rc.12
+ resolution: "@rolldown/binding-linux-x64-musl@npm:1.0.0-rc.12"
+ conditions: os=linux & cpu=x64 & libc=musl
languageName: node
linkType: hard
-"@rollup/rollup-linux-x64-gnu@npm:4.35.0":
- version: 4.35.0
- resolution: "@rollup/rollup-linux-x64-gnu@npm:4.35.0"
- conditions: os=linux & cpu=x64 & libc=glibc
+"@rolldown/binding-openharmony-arm64@npm:1.0.0-rc.12":
+ version: 1.0.0-rc.12
+ resolution: "@rolldown/binding-openharmony-arm64@npm:1.0.0-rc.12"
+ conditions: os=openharmony & cpu=arm64
languageName: node
linkType: hard
-"@rollup/rollup-linux-x64-musl@npm:4.35.0":
- version: 4.35.0
- resolution: "@rollup/rollup-linux-x64-musl@npm:4.35.0"
- conditions: os=linux & cpu=x64 & libc=musl
+"@rolldown/binding-wasm32-wasi@npm:1.0.0-rc.12":
+ version: 1.0.0-rc.12
+ resolution: "@rolldown/binding-wasm32-wasi@npm:1.0.0-rc.12"
+ dependencies:
+ "@napi-rs/wasm-runtime": "npm:^1.1.1"
+ conditions: cpu=wasm32
languageName: node
linkType: hard
-"@rollup/rollup-win32-arm64-msvc@npm:4.35.0":
- version: 4.35.0
- resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.35.0"
+"@rolldown/binding-win32-arm64-msvc@npm:1.0.0-rc.12":
+ version: 1.0.0-rc.12
+ resolution: "@rolldown/binding-win32-arm64-msvc@npm:1.0.0-rc.12"
conditions: os=win32 & cpu=arm64
languageName: node
linkType: hard
-"@rollup/rollup-win32-ia32-msvc@npm:4.35.0":
- version: 4.35.0
- resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.35.0"
- conditions: os=win32 & cpu=ia32
+"@rolldown/binding-win32-x64-msvc@npm:1.0.0-rc.12":
+ version: 1.0.0-rc.12
+ resolution: "@rolldown/binding-win32-x64-msvc@npm:1.0.0-rc.12"
+ conditions: os=win32 & cpu=x64
languageName: node
linkType: hard
-"@rollup/rollup-win32-x64-msvc@npm:4.35.0":
- version: 4.35.0
- resolution: "@rollup/rollup-win32-x64-msvc@npm:4.35.0"
- conditions: os=win32 & cpu=x64
+"@rolldown/pluginutils@npm:1.0.0-rc.12":
+ version: 1.0.0-rc.12
+ resolution: "@rolldown/pluginutils@npm:1.0.0-rc.12"
+ checksum: 10/6ce1601849b3095a2b6e57074c1f8a661eba67ebf65cf9afdf894d903302318247ddb69ab6cbc621e7f582408af301ea0523ed59ddb9a4ef3ea97f3d7002683e
languageName: node
linkType: hard
@@ -1243,6 +1250,22 @@ __metadata:
languageName: node
linkType: hard
+"@standard-schema/spec@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "@standard-schema/spec@npm:1.1.0"
+ checksum: 10/a209615c9e8b2ea535d7db0a5f6aa0f962fd4ab73ee86a46c100fb78116964af1f55a27c1794d4801e534a196794223daa25ff5135021e03c7828aa3d95e1763
+ languageName: node
+ linkType: hard
+
+"@tybys/wasm-util@npm:^0.10.1":
+ version: 0.10.1
+ resolution: "@tybys/wasm-util@npm:0.10.1"
+ dependencies:
+ tslib: "npm:^2.4.0"
+ checksum: 10/7fe0d239397aebb002ac4855d30c197c06a05ea8df8511350a3a5b1abeefe26167c60eda8a5508337571161e4c4b53d7c1342296123f9607af8705369de9fa7f
+ languageName: node
+ linkType: hard
+
"@types/body-parser@npm:*":
version: 1.19.5
resolution: "@types/body-parser@npm:1.19.5"
@@ -1253,6 +1276,16 @@ __metadata:
languageName: node
linkType: hard
+"@types/chai@npm:^5.2.2":
+ version: 5.2.3
+ resolution: "@types/chai@npm:5.2.3"
+ dependencies:
+ "@types/deep-eql": "npm:*"
+ assertion-error: "npm:^2.0.1"
+ checksum: 10/e79947307dc235953622e65f83d2683835212357ca261389116ab90bed369ac862ba28b146b4fed08b503ae1e1a12cb93ce783f24bb8d562950469f4320e1c7c
+ languageName: node
+ linkType: hard
+
"@types/connect@npm:*":
version: 3.4.38
resolution: "@types/connect@npm:3.4.38"
@@ -1262,6 +1295,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/deep-eql@npm:*":
+ version: 4.0.2
+ resolution: "@types/deep-eql@npm:4.0.2"
+ checksum: 10/249a27b0bb22f6aa28461db56afa21ec044fa0e303221a62dff81831b20c8530502175f1a49060f7099e7be06181078548ac47c668de79ff9880241968d43d0c
+ languageName: node
+ linkType: hard
+
"@types/emscripten@npm:^1.39.6":
version: 1.39.10
resolution: "@types/emscripten@npm:1.39.10"
@@ -1269,7 +1309,7 @@ __metadata:
languageName: node
linkType: hard
-"@types/estree@npm:1.0.6, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.6":
+"@types/estree@npm:^1.0.0, @types/estree@npm:^1.0.6":
version: 1.0.6
resolution: "@types/estree@npm:1.0.6"
checksum: 10/9d35d475095199c23e05b431bcdd1f6fec7380612aed068b14b2a08aa70494de8a9026765a5a91b1073f636fb0368f6d8973f518a31391d519e20c59388ed88d
@@ -1602,101 +1642,102 @@ __metadata:
languageName: node
linkType: hard
-"@vitest/expect@npm:3.0.8":
- version: 3.0.8
- resolution: "@vitest/expect@npm:3.0.8"
+"@vitest/expect@npm:4.1.2":
+ version: 4.1.2
+ resolution: "@vitest/expect@npm:4.1.2"
dependencies:
- "@vitest/spy": "npm:3.0.8"
- "@vitest/utils": "npm:3.0.8"
- chai: "npm:^5.2.0"
- tinyrainbow: "npm:^2.0.0"
- checksum: 10/6cb8a707ff8be140f5d1a5f61a9b0622b2783af1cb591b286e20ebeab9d04081567ef0f9bd697e60b08bc5be0008ea4687b78fb1134e7f3956f2fb06c74c59f8
+ "@standard-schema/spec": "npm:^1.1.0"
+ "@types/chai": "npm:^5.2.2"
+ "@vitest/spy": "npm:4.1.2"
+ "@vitest/utils": "npm:4.1.2"
+ chai: "npm:^6.2.2"
+ tinyrainbow: "npm:^3.1.0"
+ checksum: 10/536c5a8903927e324bbb66967be4e0ec2ec4ff6234f0b8fe20987841b0705c931c7e3ce2e61c7665f4ded65ba736de6cda8d2d37ee114efeedb187ca5d597ea1
languageName: node
linkType: hard
-"@vitest/mocker@npm:3.0.8":
- version: 3.0.8
- resolution: "@vitest/mocker@npm:3.0.8"
+"@vitest/mocker@npm:4.1.2":
+ version: 4.1.2
+ resolution: "@vitest/mocker@npm:4.1.2"
dependencies:
- "@vitest/spy": "npm:3.0.8"
+ "@vitest/spy": "npm:4.1.2"
estree-walker: "npm:^3.0.3"
- magic-string: "npm:^0.30.17"
+ magic-string: "npm:^0.30.21"
peerDependencies:
msw: ^2.4.9
- vite: ^5.0.0 || ^6.0.0
+ vite: ^6.0.0 || ^7.0.0 || ^8.0.0
peerDependenciesMeta:
msw:
optional: true
vite:
optional: true
- checksum: 10/456cafc5c2701a3cfffd7549e3bef0313f96672aea1c3f3da449b0d28744b69d466e510afdf6d5ad08beb7126954c75468c8408e099a2faea8733b364c5523fd
+ checksum: 10/1d7976e19ef168357aba2ca41cd8db86236a98dfb2209bd3152a3a20e9a5b8cbfd8f73356c43a934b384d3b4c7a63835fb1037d3f56a7824faa838331eaa214e
languageName: node
linkType: hard
-"@vitest/pretty-format@npm:3.0.8, @vitest/pretty-format@npm:^3.0.8":
- version: 3.0.8
- resolution: "@vitest/pretty-format@npm:3.0.8"
+"@vitest/pretty-format@npm:4.1.2":
+ version: 4.1.2
+ resolution: "@vitest/pretty-format@npm:4.1.2"
dependencies:
- tinyrainbow: "npm:^2.0.0"
- checksum: 10/255a7929e814fd8cfd8978ae6342479a8f453ccca97a0a968efbe45b5d39d2c56e1bfa3a5400816f54d3a82c944c8407f7fe2426ec57499a9210bdccf06dbc78
+ tinyrainbow: "npm:^3.1.0"
+ checksum: 10/a07a6023c52b25be5c75fc05bb3317629390cc1b50eae6cbea91ba4c13193ec88e54abaa56b46b40ddb8a6a4558d667f2ba0e1cf2ee2d0e32b463244f3002aa7
languageName: node
linkType: hard
-"@vitest/runner@npm:3.0.8":
- version: 3.0.8
- resolution: "@vitest/runner@npm:3.0.8"
+"@vitest/runner@npm:4.1.2":
+ version: 4.1.2
+ resolution: "@vitest/runner@npm:4.1.2"
dependencies:
- "@vitest/utils": "npm:3.0.8"
+ "@vitest/utils": "npm:4.1.2"
pathe: "npm:^2.0.3"
- checksum: 10/d1c3661ed1a5b2ffc3b90b99eac6133b318b2f32ff49e805e153d7128b3a824ff7906eced8d08d7a43b9f34a280432b060c59b2fcede942cde2de4c5684ae003
+ checksum: 10/13fd019a63ee3225420474cbd1ca0ae7c5c2dcdd241f2a958ca45731c10de36131f15303ae8ab1196133ec4e955b7c6de658c7b5e19736d550f310c8195fa9b2
languageName: node
linkType: hard
-"@vitest/snapshot@npm:3.0.8":
- version: 3.0.8
- resolution: "@vitest/snapshot@npm:3.0.8"
+"@vitest/snapshot@npm:4.1.2":
+ version: 4.1.2
+ resolution: "@vitest/snapshot@npm:4.1.2"
dependencies:
- "@vitest/pretty-format": "npm:3.0.8"
- magic-string: "npm:^0.30.17"
+ "@vitest/pretty-format": "npm:4.1.2"
+ "@vitest/utils": "npm:4.1.2"
+ magic-string: "npm:^0.30.21"
pathe: "npm:^2.0.3"
- checksum: 10/61b66ca6a3362de8724fd7cfa17b27a1d59d884693e5c1a2b4edfbcdc75621a7d3314ecb207c88aabff6e6360e7d4ed08c1997ecf3f71e28c485bd590a98919e
+ checksum: 10/9d124412dbe44db43ca5277180bf5fe5dad7373218a177830bba631b53d225f7d4de368a20d6f5740ec07402e9e4dd179609db2b2f691d2d8b02f1bdbfd8c1a3
languageName: node
linkType: hard
-"@vitest/spy@npm:3.0.8":
- version: 3.0.8
- resolution: "@vitest/spy@npm:3.0.8"
- dependencies:
- tinyspy: "npm:^3.0.2"
- checksum: 10/a6be428cedd4052d44ffd90ebd0c422d389f313996e08c5a655148b7d1c5695a94a321c66acc8331e20a3988e3946d4231722a8c5040afe1fe41035e3d390297
+"@vitest/spy@npm:4.1.2":
+ version: 4.1.2
+ resolution: "@vitest/spy@npm:4.1.2"
+ checksum: 10/e20e417ac430fee34e4be58802b2eb31e1c1163296a8921c0878be14e1ae77c7a7cae1b9b515d56fe623e05ee21b092aff7eb5e0d412f656650b72ecd02bb30a
languageName: node
linkType: hard
-"@vitest/ui@npm:^3.0.8":
- version: 3.0.8
- resolution: "@vitest/ui@npm:3.0.8"
+"@vitest/ui@npm:^4.1.0":
+ version: 4.1.2
+ resolution: "@vitest/ui@npm:4.1.2"
dependencies:
- "@vitest/utils": "npm:3.0.8"
+ "@vitest/utils": "npm:4.1.2"
fflate: "npm:^0.8.2"
- flatted: "npm:^3.3.3"
+ flatted: "npm:^3.4.2"
pathe: "npm:^2.0.3"
- sirv: "npm:^3.0.1"
- tinyglobby: "npm:^0.2.12"
- tinyrainbow: "npm:^2.0.0"
+ sirv: "npm:^3.0.2"
+ tinyglobby: "npm:^0.2.15"
+ tinyrainbow: "npm:^3.1.0"
peerDependencies:
- vitest: 3.0.8
- checksum: 10/d38c3ebf31b62fb6c987ce663e8a04e36642cbdcba4e521fcef13c41346435847885f180854ee20592c56d6722b6b5c5f46c211bd2d86403023b0ce99ff23f0b
+ vitest: 4.1.2
+ checksum: 10/ce53323d553fb08a228e29c3d162aefbc78a20cb90635d92ea40f3482d7c15a2962a65c50ead858272b2871dde84f71667dc618cf160189f06238a36498b50af
languageName: node
linkType: hard
-"@vitest/utils@npm:3.0.8":
- version: 3.0.8
- resolution: "@vitest/utils@npm:3.0.8"
+"@vitest/utils@npm:4.1.2":
+ version: 4.1.2
+ resolution: "@vitest/utils@npm:4.1.2"
dependencies:
- "@vitest/pretty-format": "npm:3.0.8"
- loupe: "npm:^3.1.3"
- tinyrainbow: "npm:^2.0.0"
- checksum: 10/207281dc59cd37e4aabb56db4b9bd66d281b4ef314cbed7f9642e61dfcd65bb12d29600291d676f56c3eb82b9831722a59b13f0d65b1a7af4e3ed2a5c18e98b7
+ "@vitest/pretty-format": "npm:4.1.2"
+ convert-source-map: "npm:^2.0.0"
+ tinyrainbow: "npm:^3.1.0"
+ checksum: 10/854decf0eb639758d012c9aa53c3d7aed547e37c05ece6704d5f53035be77f704a24973ed95089926e1768c0b55902d42c4438660788e7a0f0e80d0fda1c713b
languageName: node
linkType: hard
@@ -2000,13 +2041,6 @@ __metadata:
languageName: node
linkType: hard
-"cac@npm:^6.7.14":
- version: 6.7.14
- resolution: "cac@npm:6.7.14"
- checksum: 10/002769a0fbfc51c062acd2a59df465a2a947916b02ac50b56c69ec6c018ee99ac3e7f4dd7366334ea847f1ecacf4defaa61bcd2ac283db50156ce1f1d8c8ad42
- languageName: node
- linkType: hard
-
"cacache@npm:^18.0.0":
version: 18.0.2
resolution: "cacache@npm:18.0.2"
@@ -2034,16 +2068,10 @@ __metadata:
languageName: node
linkType: hard
-"chai@npm:^5.2.0":
- version: 5.2.0
- resolution: "chai@npm:5.2.0"
- dependencies:
- assertion-error: "npm:^2.0.1"
- check-error: "npm:^2.1.1"
- deep-eql: "npm:^5.0.1"
- loupe: "npm:^3.1.0"
- pathval: "npm:^2.0.0"
- checksum: 10/2ce03671c159c6a567bf1912756daabdbb7c075f3c0078f1b59d61da8d276936367ee696dfe093b49e1479d9ba93a6074c8e55d49791dddd8061728cdcad249e
+"chai@npm:^6.2.2":
+ version: 6.2.2
+ resolution: "chai@npm:6.2.2"
+ checksum: 10/13cda42cc40aa46da04a41cf7e5c61df6b6ae0b4e8a8c8b40e04d6947e4d7951377ea8c14f9fa7fe5aaa9e8bd9ba414f11288dc958d4cee6f5221b9436f2778f
languageName: node
linkType: hard
@@ -2057,13 +2085,6 @@ __metadata:
languageName: node
linkType: hard
-"check-error@npm:^2.1.1":
- version: 2.1.1
- resolution: "check-error@npm:2.1.1"
- checksum: 10/d785ed17b1d4a4796b6e75c765a9a290098cf52ff9728ce0756e8ffd4293d2e419dd30c67200aee34202463b474306913f2fcfaf1890641026d9fc6966fea27a
- languageName: node
- linkType: hard
-
"chownr@npm:^2.0.0":
version: 2.0.0
resolution: "chownr@npm:2.0.0"
@@ -2241,6 +2262,13 @@ __metadata:
languageName: node
linkType: hard
+"convert-source-map@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "convert-source-map@npm:2.0.0"
+ checksum: 10/c987be3ec061348cdb3c2bfb924bec86dea1eacad10550a85ca23edb0fe3556c3a61c7399114f3331ccb3499d7fd0285ab24566e5745929412983494c3926e15
+ languageName: node
+ linkType: hard
+
"cookie-signature@npm:^1.2.1":
version: 1.2.2
resolution: "cookie-signature@npm:1.2.2"
@@ -2292,13 +2320,6 @@ __metadata:
languageName: node
linkType: hard
-"deep-eql@npm:^5.0.1":
- version: 5.0.2
- resolution: "deep-eql@npm:5.0.2"
- checksum: 10/a529b81e2ef8821621d20a36959a0328873a3e49d393ad11f8efe8559f31239494c2eb889b80342808674c475802ba95b9d6c4c27641b9a029405104c1b59fcf
- languageName: node
- linkType: hard
-
"deep-is@npm:^0.1.3":
version: 0.1.4
resolution: "deep-is@npm:0.1.4"
@@ -2350,6 +2371,13 @@ __metadata:
languageName: node
linkType: hard
+"detect-libc@npm:^2.0.3":
+ version: 2.1.2
+ resolution: "detect-libc@npm:2.1.2"
+ checksum: 10/b736c8d97d5d46164c0d1bed53eb4e6a3b1d8530d460211e2d52f1c552875e706c58a5376854e4e54f8b828c9cada58c855288c968522eb93ac7696d65970766
+ languageName: node
+ linkType: hard
+
"detect-node-es@npm:^1.1.0":
version: 1.1.0
resolution: "detect-node-es@npm:1.1.0"
@@ -2459,10 +2487,10 @@ __metadata:
languageName: node
linkType: hard
-"es-module-lexer@npm:^1.6.0":
- version: 1.6.0
- resolution: "es-module-lexer@npm:1.6.0"
- checksum: 10/807ee7020cc46a9c970c78cad1f2f3fc139877e5ebad7f66dbfbb124d451189ba1c48c1c632bd5f8ce1b8af2caef3fca340ba044a410fa890d17b080a59024bb
+"es-module-lexer@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "es-module-lexer@npm:2.0.0"
+ checksum: 10/b075855289b5f40ee496f3d7525c5c501d029c3da15c22298a0030d625bf36d1da0768b26278f7f4bada2a602459b505888e20b77c414fba5da5619b0e84dbd1
languageName: node
linkType: hard
@@ -2762,10 +2790,10 @@ __metadata:
languageName: node
linkType: hard
-"expect-type@npm:^1.1.0":
- version: 1.2.0
- resolution: "expect-type@npm:1.2.0"
- checksum: 10/12a081159e87451a96e2e2f8a5e101509b63a4f0738590bb27988d2017c6e5aff6bf722889fe7afd96cf7e343b332b040460db41850fcd7a1392a4c8e26e51e3
+"expect-type@npm:^1.3.0":
+ version: 1.3.0
+ resolution: "expect-type@npm:1.3.0"
+ checksum: 10/a5fada3d0c621649261f886e7d93e6bf80ce26d8a86e5d517e38301b8baec8450ab2cb94ba6e7a0a6bf2fc9ee55f54e1b06938ef1efa52ddcfeffbfa01acbbcc
languageName: node
linkType: hard
@@ -2866,15 +2894,15 @@ __metadata:
languageName: node
linkType: hard
-"fdir@npm:^6.4.3":
- version: 6.4.3
- resolution: "fdir@npm:6.4.3"
+"fdir@npm:^6.5.0":
+ version: 6.5.0
+ resolution: "fdir@npm:6.5.0"
peerDependencies:
picomatch: ^3 || ^4
peerDependenciesMeta:
picomatch:
optional: true
- checksum: 10/8e6d20f4590dc168de1374a9cadaa37e20ca6e0b822aa247c230e7ea1d9e9674a68cd816146435e4ecc98f9285091462ab7e5e56eebc9510931a1794e4db68b2
+ checksum: 10/14ca1c9f0a0e8f4f2e9bf4e8551065a164a09545dae548c12a18d238b72e51e5a7b39bd8e5494b56463a0877672d0a6c1ef62c6fa0677db1b0c847773be939b1
languageName: node
linkType: hard
@@ -2953,13 +2981,20 @@ __metadata:
languageName: node
linkType: hard
-"flatted@npm:^3.2.9, flatted@npm:^3.3.3":
+"flatted@npm:^3.2.9":
version: 3.3.3
resolution: "flatted@npm:3.3.3"
checksum: 10/8c96c02fbeadcf4e8ffd0fa24983241e27698b0781295622591fc13585e2f226609d95e422bcf2ef044146ffacb6b68b1f20871454eddf75ab3caa6ee5f4a1fe
languageName: node
linkType: hard
+"flatted@npm:^3.4.2":
+ version: 3.4.2
+ resolution: "flatted@npm:3.4.2"
+ checksum: 10/a9e78fe5c2c1fcd98209a015ccee3a6caa953e01729778e83c1fe92e68601a63e1e69cd4e573010ca99eaf585a581b80ccf1018b99283e6cbc2117bcba1e030f
+ languageName: node
+ linkType: hard
+
"fn.name@npm:1.x.x":
version: 1.1.0
resolution: "fn.name@npm:1.1.0"
@@ -3044,7 +3079,7 @@ __metadata:
languageName: node
linkType: hard
-"fsevents@npm:~2.3.2, fsevents@npm:~2.3.3":
+"fsevents@npm:~2.3.3":
version: 2.3.3
resolution: "fsevents@npm:2.3.3"
dependencies:
@@ -3054,7 +3089,7 @@ __metadata:
languageName: node
linkType: hard
-"fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin":
+"fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin":
version: 2.3.3
resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1"
dependencies:
@@ -3612,6 +3647,126 @@ __metadata:
languageName: node
linkType: hard
+"lightningcss-android-arm64@npm:1.32.0":
+ version: 1.32.0
+ resolution: "lightningcss-android-arm64@npm:1.32.0"
+ conditions: os=android & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"lightningcss-darwin-arm64@npm:1.32.0":
+ version: 1.32.0
+ resolution: "lightningcss-darwin-arm64@npm:1.32.0"
+ conditions: os=darwin & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"lightningcss-darwin-x64@npm:1.32.0":
+ version: 1.32.0
+ resolution: "lightningcss-darwin-x64@npm:1.32.0"
+ conditions: os=darwin & cpu=x64
+ languageName: node
+ linkType: hard
+
+"lightningcss-freebsd-x64@npm:1.32.0":
+ version: 1.32.0
+ resolution: "lightningcss-freebsd-x64@npm:1.32.0"
+ conditions: os=freebsd & cpu=x64
+ languageName: node
+ linkType: hard
+
+"lightningcss-linux-arm-gnueabihf@npm:1.32.0":
+ version: 1.32.0
+ resolution: "lightningcss-linux-arm-gnueabihf@npm:1.32.0"
+ conditions: os=linux & cpu=arm
+ languageName: node
+ linkType: hard
+
+"lightningcss-linux-arm64-gnu@npm:1.32.0":
+ version: 1.32.0
+ resolution: "lightningcss-linux-arm64-gnu@npm:1.32.0"
+ conditions: os=linux & cpu=arm64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"lightningcss-linux-arm64-musl@npm:1.32.0":
+ version: 1.32.0
+ resolution: "lightningcss-linux-arm64-musl@npm:1.32.0"
+ conditions: os=linux & cpu=arm64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"lightningcss-linux-x64-gnu@npm:1.32.0":
+ version: 1.32.0
+ resolution: "lightningcss-linux-x64-gnu@npm:1.32.0"
+ conditions: os=linux & cpu=x64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"lightningcss-linux-x64-musl@npm:1.32.0":
+ version: 1.32.0
+ resolution: "lightningcss-linux-x64-musl@npm:1.32.0"
+ conditions: os=linux & cpu=x64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"lightningcss-win32-arm64-msvc@npm:1.32.0":
+ version: 1.32.0
+ resolution: "lightningcss-win32-arm64-msvc@npm:1.32.0"
+ conditions: os=win32 & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"lightningcss-win32-x64-msvc@npm:1.32.0":
+ version: 1.32.0
+ resolution: "lightningcss-win32-x64-msvc@npm:1.32.0"
+ conditions: os=win32 & cpu=x64
+ languageName: node
+ linkType: hard
+
+"lightningcss@npm:^1.32.0":
+ version: 1.32.0
+ resolution: "lightningcss@npm:1.32.0"
+ dependencies:
+ detect-libc: "npm:^2.0.3"
+ lightningcss-android-arm64: "npm:1.32.0"
+ lightningcss-darwin-arm64: "npm:1.32.0"
+ lightningcss-darwin-x64: "npm:1.32.0"
+ lightningcss-freebsd-x64: "npm:1.32.0"
+ lightningcss-linux-arm-gnueabihf: "npm:1.32.0"
+ lightningcss-linux-arm64-gnu: "npm:1.32.0"
+ lightningcss-linux-arm64-musl: "npm:1.32.0"
+ lightningcss-linux-x64-gnu: "npm:1.32.0"
+ lightningcss-linux-x64-musl: "npm:1.32.0"
+ lightningcss-win32-arm64-msvc: "npm:1.32.0"
+ lightningcss-win32-x64-msvc: "npm:1.32.0"
+ dependenciesMeta:
+ lightningcss-android-arm64:
+ optional: true
+ lightningcss-darwin-arm64:
+ optional: true
+ lightningcss-darwin-x64:
+ optional: true
+ lightningcss-freebsd-x64:
+ optional: true
+ lightningcss-linux-arm-gnueabihf:
+ optional: true
+ lightningcss-linux-arm64-gnu:
+ optional: true
+ lightningcss-linux-arm64-musl:
+ optional: true
+ lightningcss-linux-x64-gnu:
+ optional: true
+ lightningcss-linux-x64-musl:
+ optional: true
+ lightningcss-win32-arm64-msvc:
+ optional: true
+ lightningcss-win32-x64-msvc:
+ optional: true
+ checksum: 10/098e61007f0d0ec8b5c50884e33b543b551d1ff21bc7b062434b6638fd0b8596858f823b60dfc2a4aa756f3cb120ad79f2b7f4a55b1bda2c0269ab8cf476f114
+ languageName: node
+ linkType: hard
+
"locate-path@npm:^6.0.0":
version: 6.0.0
resolution: "locate-path@npm:6.0.0"
@@ -3733,13 +3888,6 @@ __metadata:
languageName: node
linkType: hard
-"loupe@npm:^3.1.0, loupe@npm:^3.1.3":
- version: 3.1.3
- resolution: "loupe@npm:3.1.3"
- checksum: 10/9e98c34daf0eba48ccc603595e51f2ae002110982d84879cf78c51de2c632f0c571dfe82ce4210af60c32203d06b443465c269bda925076fe6d9b612cc65c321
- languageName: node
- linkType: hard
-
"lru-cache@npm:^10.0.1, lru-cache@npm:^9.1.1 || ^10.0.0":
version: 10.2.0
resolution: "lru-cache@npm:10.2.0"
@@ -3747,7 +3895,16 @@ __metadata:
languageName: node
linkType: hard
-"magic-string@npm:^0.30.17, magic-string@npm:~0.30.0":
+"magic-string@npm:^0.30.21":
+ version: 0.30.21
+ resolution: "magic-string@npm:0.30.21"
+ dependencies:
+ "@jridgewell/sourcemap-codec": "npm:^1.5.5"
+ checksum: 10/57d5691f41ed40d962d8bd300148114f53db67fadbff336207db10a99f2bdf4a1be9cac3a68ee85dba575912ee1d4402e4396408196ec2d3afd043b076156221
+ languageName: node
+ linkType: hard
+
+"magic-string@npm:~0.30.0":
version: 0.30.17
resolution: "magic-string@npm:0.30.17"
dependencies:
@@ -4052,12 +4209,12 @@ __metadata:
languageName: node
linkType: hard
-"nanoid@npm:^3.3.8":
- version: 3.3.9
- resolution: "nanoid@npm:3.3.9"
+"nanoid@npm:^3.3.11":
+ version: 3.3.11
+ resolution: "nanoid@npm:3.3.11"
bin:
nanoid: bin/nanoid.cjs
- checksum: 10/80ec0f2f7fe0f472f459fbeab6afd88f6739e3da94cf2c2307bc83ef0203ec3b72e6113a9e3196ac4be79540440184136ee96e77c10a965e37d8347f43b265fa
+ checksum: 10/73b5afe5975a307aaa3c95dfe3334c52cdf9ae71518176895229b8d65ab0d1c0417dd081426134eb7571c055720428ea5d57c645138161e7d10df80815527c48
languageName: node
linkType: hard
@@ -4140,6 +4297,13 @@ __metadata:
languageName: node
linkType: hard
+"obug@npm:^2.1.1":
+ version: 2.1.1
+ resolution: "obug@npm:2.1.1"
+ checksum: 10/bdcf9213361786688019345f3452b95a1dc73710e4b403c82a1994b98bad6abc31b26cb72a482128c5fd53ea9daf6fbb7d0e0e7b2b7e9c8be6d779deeccee07f
+ languageName: node
+ linkType: hard
+
"on-finished@npm:2.4.1, on-finished@npm:^2.4.1":
version: 2.4.1
resolution: "on-finished@npm:2.4.1"
@@ -4311,13 +4475,6 @@ __metadata:
languageName: node
linkType: hard
-"pathval@npm:^2.0.0":
- version: 2.0.0
- resolution: "pathval@npm:2.0.0"
- checksum: 10/b91575bf9cdf01757afd7b5e521eb8a0b874a49bc972d08e0047cfea0cd3c019f5614521d4bc83d2855e3fcc331db6817dfd533dd8f3d90b16bc76fad2450fc1
- languageName: node
- linkType: hard
-
"picocolors@npm:^1.1.1":
version: 1.1.1
resolution: "picocolors@npm:1.1.1"
@@ -4332,21 +4489,21 @@ __metadata:
languageName: node
linkType: hard
-"picomatch@npm:^4.0.2":
- version: 4.0.2
- resolution: "picomatch@npm:4.0.2"
- checksum: 10/ce617b8da36797d09c0baacb96ca8a44460452c89362d7cb8f70ca46b4158ba8bc3606912de7c818eb4a939f7f9015cef3c766ec8a0c6bfc725fdc078e39c717
+"picomatch@npm:^4.0.3, picomatch@npm:^4.0.4":
+ version: 4.0.4
+ resolution: "picomatch@npm:4.0.4"
+ checksum: 10/f6ef80a3590827ce20378ae110ac78209cc4f74d39236370f1780f957b7ee41c12acde0e4651b90f39983506fd2f5e449994716f516db2e9752924aff8de93ce
languageName: node
linkType: hard
-"postcss@npm:^8.5.3":
- version: 8.5.3
- resolution: "postcss@npm:8.5.3"
+"postcss@npm:^8.5.8":
+ version: 8.5.8
+ resolution: "postcss@npm:8.5.8"
dependencies:
- nanoid: "npm:^3.3.8"
+ nanoid: "npm:^3.3.11"
picocolors: "npm:^1.1.1"
source-map-js: "npm:^1.2.1"
- checksum: 10/6d7e21a772e8b05bf102636918654dac097bac013f0dc8346b72ac3604fc16829646f94ea862acccd8f82e910b00e2c11c1f0ea276543565d278c7ca35516a7c
+ checksum: 10/cbacbfd7f767e2c820d4bf09a3a744834dd7d14f69ff08d1f57b1a7defce9ae5efcf31981890d9697a972a64e9965de677932ef28e4c8ba23a87aad45b82c459
languageName: node
linkType: hard
@@ -4727,94 +4884,80 @@ __metadata:
languageName: node
linkType: hard
-"rollup-plugin-license@npm:^3.4.0":
- version: 3.4.0
- resolution: "rollup-plugin-license@npm:3.4.0"
- dependencies:
- commenting: "npm:~1.1.0"
- glob: "npm:~7.2.0"
- lodash: "npm:~4.17.21"
- magic-string: "npm:~0.30.0"
- mkdirp: "npm:~3.0.0"
- moment: "npm:~2.30.1"
- package-name-regex: "npm:~2.0.6"
- spdx-expression-validate: "npm:~2.0.0"
- spdx-satisfies: "npm:~5.0.1"
- peerDependencies:
- rollup: ^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0
- checksum: 10/2a3accaf3966a3a55f85b9d2704d7343c884b7f9bbd37d9b96e176bb0147f264ab3acacb8110ccec20f27107e0edaa28ed38740df14073f8e3e57f1f04c0e76f
- languageName: node
- linkType: hard
-
-"rollup@npm:^4.30.1":
- version: 4.35.0
- resolution: "rollup@npm:4.35.0"
- dependencies:
- "@rollup/rollup-android-arm-eabi": "npm:4.35.0"
- "@rollup/rollup-android-arm64": "npm:4.35.0"
- "@rollup/rollup-darwin-arm64": "npm:4.35.0"
- "@rollup/rollup-darwin-x64": "npm:4.35.0"
- "@rollup/rollup-freebsd-arm64": "npm:4.35.0"
- "@rollup/rollup-freebsd-x64": "npm:4.35.0"
- "@rollup/rollup-linux-arm-gnueabihf": "npm:4.35.0"
- "@rollup/rollup-linux-arm-musleabihf": "npm:4.35.0"
- "@rollup/rollup-linux-arm64-gnu": "npm:4.35.0"
- "@rollup/rollup-linux-arm64-musl": "npm:4.35.0"
- "@rollup/rollup-linux-loongarch64-gnu": "npm:4.35.0"
- "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.35.0"
- "@rollup/rollup-linux-riscv64-gnu": "npm:4.35.0"
- "@rollup/rollup-linux-s390x-gnu": "npm:4.35.0"
- "@rollup/rollup-linux-x64-gnu": "npm:4.35.0"
- "@rollup/rollup-linux-x64-musl": "npm:4.35.0"
- "@rollup/rollup-win32-arm64-msvc": "npm:4.35.0"
- "@rollup/rollup-win32-ia32-msvc": "npm:4.35.0"
- "@rollup/rollup-win32-x64-msvc": "npm:4.35.0"
- "@types/estree": "npm:1.0.6"
- fsevents: "npm:~2.3.2"
+"rolldown@npm:1.0.0-rc.12":
+ version: 1.0.0-rc.12
+ resolution: "rolldown@npm:1.0.0-rc.12"
+ dependencies:
+ "@oxc-project/types": "npm:=0.122.0"
+ "@rolldown/binding-android-arm64": "npm:1.0.0-rc.12"
+ "@rolldown/binding-darwin-arm64": "npm:1.0.0-rc.12"
+ "@rolldown/binding-darwin-x64": "npm:1.0.0-rc.12"
+ "@rolldown/binding-freebsd-x64": "npm:1.0.0-rc.12"
+ "@rolldown/binding-linux-arm-gnueabihf": "npm:1.0.0-rc.12"
+ "@rolldown/binding-linux-arm64-gnu": "npm:1.0.0-rc.12"
+ "@rolldown/binding-linux-arm64-musl": "npm:1.0.0-rc.12"
+ "@rolldown/binding-linux-ppc64-gnu": "npm:1.0.0-rc.12"
+ "@rolldown/binding-linux-s390x-gnu": "npm:1.0.0-rc.12"
+ "@rolldown/binding-linux-x64-gnu": "npm:1.0.0-rc.12"
+ "@rolldown/binding-linux-x64-musl": "npm:1.0.0-rc.12"
+ "@rolldown/binding-openharmony-arm64": "npm:1.0.0-rc.12"
+ "@rolldown/binding-wasm32-wasi": "npm:1.0.0-rc.12"
+ "@rolldown/binding-win32-arm64-msvc": "npm:1.0.0-rc.12"
+ "@rolldown/binding-win32-x64-msvc": "npm:1.0.0-rc.12"
+ "@rolldown/pluginutils": "npm:1.0.0-rc.12"
dependenciesMeta:
- "@rollup/rollup-android-arm-eabi":
- optional: true
- "@rollup/rollup-android-arm64":
- optional: true
- "@rollup/rollup-darwin-arm64":
- optional: true
- "@rollup/rollup-darwin-x64":
- optional: true
- "@rollup/rollup-freebsd-arm64":
- optional: true
- "@rollup/rollup-freebsd-x64":
+ "@rolldown/binding-android-arm64":
optional: true
- "@rollup/rollup-linux-arm-gnueabihf":
+ "@rolldown/binding-darwin-arm64":
optional: true
- "@rollup/rollup-linux-arm-musleabihf":
+ "@rolldown/binding-darwin-x64":
optional: true
- "@rollup/rollup-linux-arm64-gnu":
+ "@rolldown/binding-freebsd-x64":
optional: true
- "@rollup/rollup-linux-arm64-musl":
+ "@rolldown/binding-linux-arm-gnueabihf":
optional: true
- "@rollup/rollup-linux-loongarch64-gnu":
+ "@rolldown/binding-linux-arm64-gnu":
optional: true
- "@rollup/rollup-linux-powerpc64le-gnu":
+ "@rolldown/binding-linux-arm64-musl":
optional: true
- "@rollup/rollup-linux-riscv64-gnu":
+ "@rolldown/binding-linux-ppc64-gnu":
optional: true
- "@rollup/rollup-linux-s390x-gnu":
+ "@rolldown/binding-linux-s390x-gnu":
optional: true
- "@rollup/rollup-linux-x64-gnu":
+ "@rolldown/binding-linux-x64-gnu":
optional: true
- "@rollup/rollup-linux-x64-musl":
+ "@rolldown/binding-linux-x64-musl":
optional: true
- "@rollup/rollup-win32-arm64-msvc":
+ "@rolldown/binding-openharmony-arm64":
optional: true
- "@rollup/rollup-win32-ia32-msvc":
+ "@rolldown/binding-wasm32-wasi":
optional: true
- "@rollup/rollup-win32-x64-msvc":
+ "@rolldown/binding-win32-arm64-msvc":
optional: true
- fsevents:
+ "@rolldown/binding-win32-x64-msvc":
optional: true
bin:
- rollup: dist/bin/rollup
- checksum: 10/1fd13b8cb874106727cc4241e7b09167b835247185f52a0ac0d4b302df6dd01feec32e53ee3fead757c0c033f8b15ae6f0e093854de1878ae9e5dee37ec52579
+ rolldown: bin/cli.mjs
+ checksum: 10/b8cc0d9df80b495a57b63d69a16a5566c600162046edd407f335a6d27e5b6618a2d88d63e82c4e77a1447d18edcc6900696e041c33236ef38ab51d33cf5da2fe
+ languageName: node
+ linkType: hard
+
+"rollup-plugin-license@npm:^3.4.0":
+ version: 3.4.0
+ resolution: "rollup-plugin-license@npm:3.4.0"
+ dependencies:
+ commenting: "npm:~1.1.0"
+ glob: "npm:~7.2.0"
+ lodash: "npm:~4.17.21"
+ magic-string: "npm:~0.30.0"
+ mkdirp: "npm:~3.0.0"
+ moment: "npm:~2.30.1"
+ package-name-regex: "npm:~2.0.6"
+ spdx-expression-validate: "npm:~2.0.0"
+ spdx-satisfies: "npm:~5.0.1"
+ peerDependencies:
+ rollup: ^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0
+ checksum: 10/2a3accaf3966a3a55f85b9d2704d7343c884b7f9bbd37d9b96e176bb0147f264ab3acacb8110ccec20f27107e0edaa28ed38740df14073f8e3e57f1f04c0e76f
languageName: node
linkType: hard
@@ -4978,14 +5121,14 @@ __metadata:
languageName: node
linkType: hard
-"sirv@npm:^3.0.1":
- version: 3.0.1
- resolution: "sirv@npm:3.0.1"
+"sirv@npm:^3.0.2":
+ version: 3.0.2
+ resolution: "sirv@npm:3.0.2"
dependencies:
"@polka/url": "npm:^1.0.0-next.24"
mrmime: "npm:^2.0.0"
totalist: "npm:^3.0.0"
- checksum: 10/b110ebe28eb1740772fbbfacb6c71c58d1ec8ec17a5ae2852a5418c3ef41d52d473663613de808f8a6337ec29dd446414d0d059e75bfd13fb9630d18651c99f2
+ checksum: 10/259617f4ab57664be6d963f5b27b38a6351d3e91ce70d6726985d087b40efd595fcf7f72ae010babf5e0acb63bcb3e3d6db8de34604da1011be6e28ee32aa15d
languageName: node
linkType: hard
@@ -5140,10 +5283,10 @@ __metadata:
languageName: node
linkType: hard
-"std-env@npm:^3.8.0":
- version: 3.8.1
- resolution: "std-env@npm:3.8.1"
- checksum: 10/ee119570e2e449be86aa4972f119f9086a918307cc524f6e891b7a7c1327a5c970cf1b7d5898c881777845292a7e3380cf7d80ad34aee355d2c22ac5eb628542
+"std-env@npm:^4.0.0-rc.1":
+ version: 4.0.0
+ resolution: "std-env@npm:4.0.0"
+ checksum: 10/19ef21cd85da52dc1178288d1b69e242b6579c0a76ddba2374f859aa58678797ec4a34c4f1fe6b9007a032e04d6fd3fca4e27349c88809265a9cbd90d924203f
languageName: node
linkType: hard
@@ -5329,41 +5472,27 @@ __metadata:
languageName: node
linkType: hard
-"tinyexec@npm:^0.3.2":
- version: 0.3.2
- resolution: "tinyexec@npm:0.3.2"
- checksum: 10/b9d5fed3166fb1acd1e7f9a89afcd97ccbe18b9c1af0278e429455f6976d69271ba2d21797e7c36d57d6b05025e525d2882d88c2ab435b60d1ddf2fea361de57
+"tinyexec@npm:^1.0.2":
+ version: 1.0.4
+ resolution: "tinyexec@npm:1.0.4"
+ checksum: 10/ccebe4044eef6fa5050929df7862fda70b4fb700f15d94aef8ae6109b9d194dbc3a990125d99944fd25b90fe2115e1927f055b909a604c571a81b647ede5757a
languageName: node
linkType: hard
-"tinyglobby@npm:^0.2.12":
- version: 0.2.12
- resolution: "tinyglobby@npm:0.2.12"
+"tinyglobby@npm:^0.2.15":
+ version: 0.2.15
+ resolution: "tinyglobby@npm:0.2.15"
dependencies:
- fdir: "npm:^6.4.3"
- picomatch: "npm:^4.0.2"
- checksum: 10/4ad28701fa9118b32ef0e27f409e0a6c5741e8b02286d50425c1f6f71e6d6c6ded9dd5bbbbb714784b08623c4ec4d150151f1d3d996cfabe0495f908ab4f7002
- languageName: node
- linkType: hard
-
-"tinypool@npm:^1.0.2":
- version: 1.0.2
- resolution: "tinypool@npm:1.0.2"
- checksum: 10/6109322f14b3763f65c8fa49fddab72cd3edd96b82dd50e05e63de74867329ff5353bff4377281ec963213d9314f37f4a353e9ee34bbac85fd4c1e4a568d6076
+ fdir: "npm:^6.5.0"
+ picomatch: "npm:^4.0.3"
+ checksum: 10/d72bd826a8b0fa5fa3929e7fe5ba48fceb2ae495df3a231b6c5408cd7d8c00b58ab5a9c2a76ba56a62ee9b5e083626f1f33599734bed1ffc4b792406408f0ca2
languageName: node
linkType: hard
-"tinyrainbow@npm:^2.0.0":
- version: 2.0.0
- resolution: "tinyrainbow@npm:2.0.0"
- checksum: 10/94d4e16246972614a5601eeb169ba94f1d49752426312d3cf8cc4f2cc663a2e354ffc653aa4de4eebccbf9eeebdd0caef52d1150271fdfde65d7ae7f3dcb9eb5
- languageName: node
- linkType: hard
-
-"tinyspy@npm:^3.0.2":
- version: 3.0.2
- resolution: "tinyspy@npm:3.0.2"
- checksum: 10/5db671b2ff5cd309de650c8c4761ca945459d7204afb1776db9a04fb4efa28a75f08517a8620c01ee32a577748802231ad92f7d5b194dc003ee7f987a2a06337
+"tinyrainbow@npm:^3.1.0":
+ version: 3.1.0
+ resolution: "tinyrainbow@npm:3.1.0"
+ checksum: 10/4c2c01dde1e5bb9a74973daaae141d4d733d246280b2f9a7f6a9e7dd8e940d48b2580a6086125278777897bc44635d6ccec5f9f563c2179dd2129f4542d0ec05
languageName: node
linkType: hard
@@ -5603,38 +5732,26 @@ __metadata:
languageName: node
linkType: hard
-"vite-node@npm:3.0.8":
- version: 3.0.8
- resolution: "vite-node@npm:3.0.8"
- dependencies:
- cac: "npm:^6.7.14"
- debug: "npm:^4.4.0"
- es-module-lexer: "npm:^1.6.0"
- pathe: "npm:^2.0.3"
- vite: "npm:^5.0.0 || ^6.0.0"
- bin:
- vite-node: vite-node.mjs
- checksum: 10/9a06d27d9f56f17cf9586cd36f19e4c275227f55f0d9b71c0002d7dbe1a76398cac836b639e2c2537be67f16adb33c40d6d64d3640a97696ebfdfd731e5ea13f
- languageName: node
- linkType: hard
-
-"vite@npm:^5.0.0 || ^6.0.0, vite@npm:^6.2.1":
- version: 6.2.1
- resolution: "vite@npm:6.2.1"
+"vite@npm:^6.0.0 || ^7.0.0 || ^8.0.0, vite@npm:^8.0.1":
+ version: 8.0.3
+ resolution: "vite@npm:8.0.3"
dependencies:
- esbuild: "npm:^0.25.0"
fsevents: "npm:~2.3.3"
- postcss: "npm:^8.5.3"
- rollup: "npm:^4.30.1"
+ lightningcss: "npm:^1.32.0"
+ picomatch: "npm:^4.0.4"
+ postcss: "npm:^8.5.8"
+ rolldown: "npm:1.0.0-rc.12"
+ tinyglobby: "npm:^0.2.15"
peerDependencies:
- "@types/node": ^18.0.0 || ^20.0.0 || >=22.0.0
+ "@types/node": ^20.19.0 || >=22.12.0
+ "@vitejs/devtools": ^0.1.0
+ esbuild: ^0.27.0
jiti: ">=1.21.0"
- less: "*"
- lightningcss: ^1.21.0
- sass: "*"
- sass-embedded: "*"
- stylus: "*"
- sugarss: "*"
+ less: ^4.0.0
+ sass: ^1.70.0
+ sass-embedded: ^1.70.0
+ stylus: ">=0.54.8"
+ sugarss: ^5.0.0
terser: ^5.16.0
tsx: ^4.8.1
yaml: ^2.4.2
@@ -5644,12 +5761,14 @@ __metadata:
peerDependenciesMeta:
"@types/node":
optional: true
+ "@vitejs/devtools":
+ optional: true
+ esbuild:
+ optional: true
jiti:
optional: true
less:
optional: true
- lightningcss:
- optional: true
sass:
optional: true
sass-embedded:
@@ -5666,50 +5785,57 @@ __metadata:
optional: true
bin:
vite: bin/vite.js
- checksum: 10/a37cbc33a3d9746434e8e96614dd6d8d45d821e61e9d266f389808da290b3128ac93ba0059ab09a098cdeab8b790d6d3ae7cdd5e1ce7d55c31b8bece650b3790
+ checksum: 10/745b791cb71297ac3877af061da44751d93f198413426bbb76a1f8384d76d4162a6ad739b2bcdf5fb966cd1295db59412614aee60738e40e1c99cee561e682f0
languageName: node
linkType: hard
-"vitest@npm:^3.0.8":
- version: 3.0.8
- resolution: "vitest@npm:3.0.8"
- dependencies:
- "@vitest/expect": "npm:3.0.8"
- "@vitest/mocker": "npm:3.0.8"
- "@vitest/pretty-format": "npm:^3.0.8"
- "@vitest/runner": "npm:3.0.8"
- "@vitest/snapshot": "npm:3.0.8"
- "@vitest/spy": "npm:3.0.8"
- "@vitest/utils": "npm:3.0.8"
- chai: "npm:^5.2.0"
- debug: "npm:^4.4.0"
- expect-type: "npm:^1.1.0"
- magic-string: "npm:^0.30.17"
+"vitest@npm:^4.1.0":
+ version: 4.1.2
+ resolution: "vitest@npm:4.1.2"
+ dependencies:
+ "@vitest/expect": "npm:4.1.2"
+ "@vitest/mocker": "npm:4.1.2"
+ "@vitest/pretty-format": "npm:4.1.2"
+ "@vitest/runner": "npm:4.1.2"
+ "@vitest/snapshot": "npm:4.1.2"
+ "@vitest/spy": "npm:4.1.2"
+ "@vitest/utils": "npm:4.1.2"
+ es-module-lexer: "npm:^2.0.0"
+ expect-type: "npm:^1.3.0"
+ magic-string: "npm:^0.30.21"
+ obug: "npm:^2.1.1"
pathe: "npm:^2.0.3"
- std-env: "npm:^3.8.0"
+ picomatch: "npm:^4.0.3"
+ std-env: "npm:^4.0.0-rc.1"
tinybench: "npm:^2.9.0"
- tinyexec: "npm:^0.3.2"
- tinypool: "npm:^1.0.2"
- tinyrainbow: "npm:^2.0.0"
- vite: "npm:^5.0.0 || ^6.0.0"
- vite-node: "npm:3.0.8"
+ tinyexec: "npm:^1.0.2"
+ tinyglobby: "npm:^0.2.15"
+ tinyrainbow: "npm:^3.1.0"
+ vite: "npm:^6.0.0 || ^7.0.0 || ^8.0.0"
why-is-node-running: "npm:^2.3.0"
peerDependencies:
"@edge-runtime/vm": "*"
- "@types/debug": ^4.1.12
- "@types/node": ^18.0.0 || ^20.0.0 || >=22.0.0
- "@vitest/browser": 3.0.8
- "@vitest/ui": 3.0.8
+ "@opentelemetry/api": ^1.9.0
+ "@types/node": ^20.0.0 || ^22.0.0 || >=24.0.0
+ "@vitest/browser-playwright": 4.1.2
+ "@vitest/browser-preview": 4.1.2
+ "@vitest/browser-webdriverio": 4.1.2
+ "@vitest/ui": 4.1.2
happy-dom: "*"
jsdom: "*"
+ vite: ^6.0.0 || ^7.0.0 || ^8.0.0
peerDependenciesMeta:
"@edge-runtime/vm":
optional: true
- "@types/debug":
+ "@opentelemetry/api":
optional: true
"@types/node":
optional: true
- "@vitest/browser":
+ "@vitest/browser-playwright":
+ optional: true
+ "@vitest/browser-preview":
+ optional: true
+ "@vitest/browser-webdriverio":
optional: true
"@vitest/ui":
optional: true
@@ -5717,9 +5843,11 @@ __metadata:
optional: true
jsdom:
optional: true
+ vite:
+ optional: false
bin:
vitest: vitest.mjs
- checksum: 10/83b246ded7dab20db40a0dfa93a45a7a4de3d41f1860889b53d2896761db48ca42b88d1a5d8920681d6f5b96b76a46d5ab27456affb89be7ea2138d95531c87e
+ checksum: 10/6b037387e59d403f6570f887f6ac96b81ff6e768dbd02d32a812ddff5bdebef022dd6d9f20b84fb9535866e0c5dbdf80e6705cc428b6a8f8a8e67e1335235848
languageName: node
linkType: hard
From 99b38291b65a3029b48abb3104fc0c970632501f Mon Sep 17 00:00:00 2001
From: AnthonyFuller <24512050+AnthonyFuller@users.noreply.github.com>
Date: Sun, 29 Mar 2026 03:04:53 +0100
Subject: [PATCH 03/11] refactor(SteamStrategy): remove dependency on
steam-appticket
---
components/entitlementStrategies.ts | 9 +-
components/utils.ts | 87 ++++++++++++++
package.json | 3 +-
yarn.lock | 180 +---------------------------
4 files changed, 93 insertions(+), 186 deletions(-)
diff --git a/components/entitlementStrategies.ts b/components/entitlementStrategies.ts
index a51444e84..053e343b9 100644
--- a/components/entitlementStrategies.ts
+++ b/components/entitlementStrategies.ts
@@ -27,9 +27,8 @@ import {
STEAM_NAMESPACE_2016,
} from "./platformEntitlements"
import { GameVersion } from "./types/types"
-import { getRemoteService } from "./utils"
+import { getRemoteService, parseAppTicket } from "./utils"
import { getFlag } from "./flags"
-import { parseAppTicket } from "steam-appticket"
import { createHash } from "crypto"
// An in-memory cache of Steam ownership tickets to entitlements (they're valid for up to 21 days)
@@ -164,7 +163,7 @@ export class SteamStrategy extends EntitlementStrategy {
): Promise {
const ticket = parseAppTicket(Buffer.from(clientToken, "hex"))
- if (!ticket?.isValid) {
+ if (!ticket?.valid) {
return {
success: false,
code: 400,
@@ -215,8 +214,8 @@ export class SteamStrategy extends EntitlementStrategy {
success: true,
steamId: data.response.params!.steamid,
entitlements: [
- ticket.appID.toString(),
- ...ticket.dlc.map((dlc) => dlc.appID.toString()),
+ ticket.appId.toString(),
+ ...ticket.dlc.map((dlc) => dlc.toString()),
],
}
} catch (error) {
diff --git a/components/utils.ts b/components/utils.ts
index e90eb0474..3e171221a 100644
--- a/components/utils.ts
+++ b/components/utils.ts
@@ -37,6 +37,7 @@ import { getConfig, getVersionedConfig } from "./configSwizzleManager"
import { compare } from "semver"
import assert from "assert"
import { getUnlockableById } from "./inventory"
+import { createVerify } from "crypto"
/**
* True if the server is being run by the launcher, false otherwise.
@@ -860,3 +861,89 @@ export function parsePageNumber(page: unknown): number {
page = Math.max(page as number, 0)
return page as number
}
+
+// Steam Utility Functions
+const STEAM_PUBLIC_KEY: string =
+ "-----BEGIN PUBLIC KEY-----\n" +
+ "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDf7BrWLBBmLBc1OhSwfFkRf53T\n" +
+ "2Ct64+AVzRkeRuh7h3SiGEYxqQMUeYKO6UWiSRKpI2hzic9pobFhRr3Bvr/WARvY\n" +
+ "gdTckPv+T1JzZsuVcNfFjrocejN1oWI0Rrtgt4Bo+hOneoo3S57G9F1fOpn5nsQ6\n" +
+ "6WOiu4gZKODnFMBCiQIBEQ==\n" +
+ "-----END PUBLIC KEY-----"
+
+// A subset of the full app ticket data
+export interface AppTicket {
+ steamId: string
+ appId: number
+ expiry: Date
+ dlc: number[]
+ valid: boolean
+}
+
+export function parseAppTicket(ticket: Buffer): AppTicket | undefined {
+ try {
+ // Adapted from the structs found at https://github.com/SteamRE/SteamKit/blob/master/Resources/Structs/steam3_appticket.hsl
+ const appTicket: AppTicket = {
+ steamId: "",
+ appId: 0,
+ expiry: new Date(),
+ dlc: [],
+ valid: false,
+ }
+
+ let offset = 0
+
+ if (ticket.readUInt32LE() === 20) {
+ // This ticket includes a GCTOKEN, skip this (extra + 4 to skip the length from OWNERSHIPSECTIONWITHSIGNATURE)
+ offset += 52 + 4
+ }
+
+ // Invalid app ticket
+ if (ticket.length <= offset) return
+
+ const ownershipTicket = ticket.subarray(
+ offset,
+ offset + ticket.readUInt32LE(offset),
+ )
+ appTicket.steamId = ticket.readBigUInt64LE((offset += 8)).toString()
+ appTicket.appId = ticket.readUInt32LE((offset += 8))
+ appTicket.expiry = new Date(ticket.readUInt32LE((offset += 20)) * 1000)
+
+ // Skip past licenses
+ const licensesLength = ticket.readUInt16LE((offset += 4))
+ offset += 2 + licensesLength * 4
+
+ const dlcLength = ticket.readUInt16LE(offset)
+ offset += 2
+
+ for (let i = 0; i < dlcLength; ++i) {
+ appTicket.dlc.push(ticket.readUInt32LE(offset))
+
+ // DLC Licenses array, usually empty
+ const licensesLength = ticket.readUInt16LE((offset += 4))
+ offset += 2 + licensesLength * 4
+ }
+
+ // Skip past reserved
+ offset += 2
+
+ // We require a valid signature
+ let validSignature = false
+
+ if (offset + 128 === ticket.length) {
+ const signature = ticket.subarray(offset, offset + 128)
+
+ const verify = createVerify("RSA-SHA1")
+ verify.update(ownershipTicket)
+ verify.end()
+
+ validSignature = verify.verify(STEAM_PUBLIC_KEY, signature)
+ }
+
+ appTicket.valid = new Date() < appTicket.expiry && validSignature
+
+ return appTicket
+ } catch {
+ return
+ }
+}
diff --git a/package.json b/package.json
index ae21a64b5..a8a755c82 100644
--- a/package.json
+++ b/package.json
@@ -69,8 +69,7 @@
"random": "^5.3.0",
"semver": "^7.7.1",
"send": "^1.1.0",
- "serve-static": "^2.1.0",
- "steam-appticket": "^2.0.1"
+ "serve-static": "^2.1.0"
},
"devDependencies": {
"@eslint/compat": "^1.2.7",
diff --git a/yarn.lock b/yarn.lock
index f99adf94b..ee81184d0 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -39,22 +39,6 @@ __metadata:
languageName: node
linkType: hard
-"@doctormckay/stdlib@npm:^2.10.0":
- version: 2.10.0
- resolution: "@doctormckay/stdlib@npm:2.10.0"
- dependencies:
- psl: "npm:^1.9.0"
- checksum: 10/44b0075fd9316355e7cac7bfb349a2b69e57423be88b89b6e6249ac9d69436242933fc801d0f49cf3248815bfd2a75df214622d1b85c9f027f822351423dec9e
- languageName: node
- linkType: hard
-
-"@doctormckay/steam-crypto@npm:^1.2.0":
- version: 1.2.0
- resolution: "@doctormckay/steam-crypto@npm:1.2.0"
- checksum: 10/b614ff92f68eebec154ec3f1ce002ad0e40158b1ea193080924dee68a7ca1b36c5831f21eefc86827f7dca3d4686877747931a27d1c4e8f13af2480388be21d1
- languageName: node
- linkType: hard
-
"@esbuild/aix-ppc64@npm:0.25.0":
version: 0.25.0
resolution: "@esbuild/aix-ppc64@npm:0.25.0"
@@ -640,7 +624,6 @@ __metadata:
semver: "npm:^7.7.1"
send: "npm:^1.1.0"
serve-static: "npm:^2.1.0"
- steam-appticket: "npm:^2.0.1"
terser: "npm:^5.39.0"
typescript: "npm:5.8.2"
winston: "npm:3.13.0"
@@ -707,79 +690,6 @@ __metadata:
languageName: node
linkType: hard
-"@protobufjs/aspromise@npm:^1.1.1, @protobufjs/aspromise@npm:^1.1.2":
- version: 1.1.2
- resolution: "@protobufjs/aspromise@npm:1.1.2"
- checksum: 10/8a938d84fe4889411296db66b29287bd61ea3c14c2d23e7a8325f46a2b8ce899857c5f038d65d7641805e6c1d06b495525c7faf00c44f85a7ee6476649034969
- languageName: node
- linkType: hard
-
-"@protobufjs/base64@npm:^1.1.2":
- version: 1.1.2
- resolution: "@protobufjs/base64@npm:1.1.2"
- checksum: 10/c71b100daeb3c9bdccab5cbc29495b906ba0ae22ceedc200e1ba49717d9c4ab15a6256839cebb6f9c6acae4ed7c25c67e0a95e734f612b258261d1a3098fe342
- languageName: node
- linkType: hard
-
-"@protobufjs/codegen@npm:^2.0.4":
- version: 2.0.4
- resolution: "@protobufjs/codegen@npm:2.0.4"
- checksum: 10/c6ee5fa172a8464f5253174d3c2353ea520c2573ad7b6476983d9b1346f4d8f2b44aa29feb17a949b83c1816bc35286a5ea265ed9d8fdd2865acfa09668c0447
- languageName: node
- linkType: hard
-
-"@protobufjs/eventemitter@npm:^1.1.0":
- version: 1.1.0
- resolution: "@protobufjs/eventemitter@npm:1.1.0"
- checksum: 10/03af3e99f17ad421283d054c88a06a30a615922a817741b43ca1b13e7c6b37820a37f6eba9980fb5150c54dba6e26cb6f7b64a6f7d8afa83596fafb3afa218c3
- languageName: node
- linkType: hard
-
-"@protobufjs/fetch@npm:^1.1.0":
- version: 1.1.0
- resolution: "@protobufjs/fetch@npm:1.1.0"
- dependencies:
- "@protobufjs/aspromise": "npm:^1.1.1"
- "@protobufjs/inquire": "npm:^1.1.0"
- checksum: 10/67ae40572ad536e4ef94269199f252c024b66e3059850906bdaee161ca1d75c73d04d35cd56f147a8a5a079f5808e342b99e61942c1dae15604ff0600b09a958
- languageName: node
- linkType: hard
-
-"@protobufjs/float@npm:^1.0.2":
- version: 1.0.2
- resolution: "@protobufjs/float@npm:1.0.2"
- checksum: 10/634c2c989da0ef2f4f19373d64187e2a79f598c5fb7991afb689d29a2ea17c14b796b29725945fa34b9493c17fb799e08ac0a7ccaae460ee1757d3083ed35187
- languageName: node
- linkType: hard
-
-"@protobufjs/inquire@npm:^1.1.0":
- version: 1.1.0
- resolution: "@protobufjs/inquire@npm:1.1.0"
- checksum: 10/c09efa34a5465cb120775e1a482136f2340a58b4abce7e93d72b8b5a9324a0e879275016ef9fcd73d72a4731639c54f2bb755bb82f916e4a78892d1d840bb3d2
- languageName: node
- linkType: hard
-
-"@protobufjs/path@npm:^1.1.2":
- version: 1.1.2
- resolution: "@protobufjs/path@npm:1.1.2"
- checksum: 10/bb709567935fd385a86ad1f575aea98131bbd719c743fb9b6edd6b47ede429ff71a801cecbd64fc72deebf4e08b8f1bd8062793178cdaed3713b8d15771f9b83
- languageName: node
- linkType: hard
-
-"@protobufjs/pool@npm:^1.1.0":
- version: 1.1.0
- resolution: "@protobufjs/pool@npm:1.1.0"
- checksum: 10/b9c7047647f6af28e92aac54f6f7c1f7ff31b201b4bfcc7a415b2861528854fce3ec666d7e7e10fd744da905f7d4aef2205bbcc8944ca0ca7a82e18134d00c46
- languageName: node
- linkType: hard
-
-"@protobufjs/utf8@npm:^1.1.0":
- version: 1.1.0
- resolution: "@protobufjs/utf8@npm:1.1.0"
- checksum: 10/131e289c57534c1d73a0e55782d6751dd821db1583cb2f7f7e017c9d6747addaebe79f28120b2e0185395d990aad347fb14ffa73ef4096fa38508d61a0e64602
- languageName: node
- linkType: hard
-
"@radix-ui/primitive@npm:1.0.1":
version: 1.0.1
resolution: "@radix-ui/primitive@npm:1.0.1"
@@ -1418,15 +1328,6 @@ __metadata:
languageName: node
linkType: hard
-"@types/node@npm:>=13.7.0":
- version: 25.5.0
- resolution: "@types/node@npm:25.5.0"
- dependencies:
- undici-types: "npm:~7.18.0"
- checksum: 10/b1e8116bd8c9ff62e458b76d28a59cf7631537bb17e8961464bf754dd5b07b46f1620f568b2f89970505af9eef478dd74c614651b454c1ea95949ec472c64fcb
- languageName: node
- linkType: hard
-
"@types/parseurl@npm:^1.3.3":
version: 1.3.3
resolution: "@types/parseurl@npm:1.3.3"
@@ -2025,15 +1926,6 @@ __metadata:
languageName: node
linkType: hard
-"bytebuffer@npm:^5.0.1":
- version: 5.0.1
- resolution: "bytebuffer@npm:5.0.1"
- dependencies:
- long: "npm:~3"
- checksum: 10/f3e9739ed9ab30e19d985fc3dadfdbd631d030874bbb313feefddac756f21ac10957257737e630fd9959744318e6e8b7d8c35b797519693bf1897be16c560970
- languageName: node
- linkType: hard
-
"bytes@npm:3.1.2, bytes@npm:^3.1.2":
version: 3.1.2
resolution: "bytes@npm:3.1.2"
@@ -3863,20 +3755,6 @@ __metadata:
languageName: node
linkType: hard
-"long@npm:^5.0.0":
- version: 5.3.2
- resolution: "long@npm:5.3.2"
- checksum: 10/b6b55ddae56fcce2864d37119d6b02fe28f6dd6d9e44fd22705f86a9254b9321bd69e9ffe35263b4846d54aba197c64882adcb8c543f2383c1e41284b321ea64
- languageName: node
- linkType: hard
-
-"long@npm:~3":
- version: 3.2.0
- resolution: "long@npm:3.2.0"
- checksum: 10/ffc685ec458ddf71a830d6deb62ff7dc551a736d47473350d9e077c22db96ec88c8a3554c11ffce7d7f2291b0c30da36629e4d0a97c29b5360dc977533c96d28
- languageName: node
- linkType: hard
-
"loose-envify@npm:^1.0.0, loose-envify@npm:^1.1.0":
version: 1.4.0
resolution: "loose-envify@npm:1.4.0"
@@ -4584,26 +4462,6 @@ __metadata:
languageName: node
linkType: hard
-"protobufjs@npm:^7.3.2":
- version: 7.5.4
- resolution: "protobufjs@npm:7.5.4"
- dependencies:
- "@protobufjs/aspromise": "npm:^1.1.2"
- "@protobufjs/base64": "npm:^1.1.2"
- "@protobufjs/codegen": "npm:^2.0.4"
- "@protobufjs/eventemitter": "npm:^1.1.0"
- "@protobufjs/fetch": "npm:^1.1.0"
- "@protobufjs/float": "npm:^1.0.2"
- "@protobufjs/inquire": "npm:^1.1.0"
- "@protobufjs/path": "npm:^1.1.2"
- "@protobufjs/pool": "npm:^1.1.0"
- "@protobufjs/utf8": "npm:^1.1.0"
- "@types/node": "npm:>=13.7.0"
- long: "npm:^5.0.0"
- checksum: 10/88d677bb6f11a2ecec63fdd053dfe6d31120844d04e865efa9c8fbe0674cd077d6624ecfdf014018a20dcb114ae2a59c1b21966dd8073e920650c71370966439
- languageName: node
- linkType: hard
-
"proxy-addr@npm:~2.0.7":
version: 2.0.7
resolution: "proxy-addr@npm:2.0.7"
@@ -4621,15 +4479,6 @@ __metadata:
languageName: node
linkType: hard
-"psl@npm:^1.9.0":
- version: 1.15.0
- resolution: "psl@npm:1.15.0"
- dependencies:
- punycode: "npm:^2.3.1"
- checksum: 10/5e7467eb5196eb7900d156783d12907d445c0122f76c73203ce96b148a6ccf8c5450cc805887ffada38ff92d634afcf33720c24053cb01d5b6598d1c913c5caf
- languageName: node
- linkType: hard
-
"pump@npm:^3.0.0":
version: 3.0.0
resolution: "pump@npm:3.0.0"
@@ -4651,7 +4500,7 @@ __metadata:
languageName: node
linkType: hard
-"punycode@npm:^2.1.0, punycode@npm:^2.3.1":
+"punycode@npm:^2.1.0":
version: 2.3.1
resolution: "punycode@npm:2.3.1"
checksum: 10/febdc4362bead22f9e2608ff0171713230b57aff9dddc1c273aa2a651fbd366f94b7d6a71d78342a7c0819906750351ca7f2edd26ea41b626d87d6a13d1bd059
@@ -5290,26 +5139,6 @@ __metadata:
languageName: node
linkType: hard
-"steam-appticket@npm:^2.0.1":
- version: 2.0.1
- resolution: "steam-appticket@npm:2.0.1"
- dependencies:
- "@doctormckay/stdlib": "npm:^2.10.0"
- "@doctormckay/steam-crypto": "npm:^1.2.0"
- bytebuffer: "npm:^5.0.1"
- protobufjs: "npm:^7.3.2"
- steamid: "npm:^2.1.0"
- checksum: 10/9643eb026b1fbf0b7b3bca2633050d59c4eebe61fba7311cf69361a5fc60cdefd42f2acf2495aa440306475e1efe782999cf9b6b32ec4ba18cf1d036217109a5
- languageName: node
- linkType: hard
-
-"steamid@npm:^2.1.0":
- version: 2.1.0
- resolution: "steamid@npm:2.1.0"
- checksum: 10/e23d0eb1d3296199ff827eab9415c136fe5b94ce492e696b0c29caf33afeb74a9cfc3802437b319d008db82024b525411cf6fabb76cef61cc70744358fe870a4
- languageName: node
- linkType: hard
-
"stream-shift@npm:^1.0.0":
version: 1.0.3
resolution: "stream-shift@npm:1.0.3"
@@ -5620,13 +5449,6 @@ __metadata:
languageName: node
linkType: hard
-"undici-types@npm:~7.18.0":
- version: 7.18.2
- resolution: "undici-types@npm:7.18.2"
- checksum: 10/e61a5918f624d68420c3ca9d301e9f15b61cba6e97be39fe2ce266dd6151e4afe424d679372638826cb506be33952774e0424141200111a9857e464216c009af
- languageName: node
- linkType: hard
-
"unique-filename@npm:^3.0.0":
version: 3.0.0
resolution: "unique-filename@npm:3.0.0"
From 8eb7e688f7d57fdf81e9401edce8990896d63825 Mon Sep 17 00:00:00 2001
From: AnthonyFuller <24512050+AnthonyFuller@users.noreply.github.com>
Date: Mon, 30 Mar 2026 22:48:14 +0100
Subject: [PATCH 04/11] refactor(parseAppTicket): return app id and dlcs as
strings, compute hash
---
components/utils.ts | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/components/utils.ts b/components/utils.ts
index 3e171221a..4fcf9f722 100644
--- a/components/utils.ts
+++ b/components/utils.ts
@@ -37,7 +37,7 @@ import { getConfig, getVersionedConfig } from "./configSwizzleManager"
import { compare } from "semver"
import assert from "assert"
import { getUnlockableById } from "./inventory"
-import { createVerify } from "crypto"
+import { createHash, createVerify } from "crypto"
/**
* True if the server is being run by the launcher, false otherwise.
@@ -874,10 +874,11 @@ const STEAM_PUBLIC_KEY: string =
// A subset of the full app ticket data
export interface AppTicket {
steamId: string
- appId: number
+ appId: string
expiry: Date
- dlc: number[]
+ dlc: string[]
valid: boolean
+ hash: string
}
export function parseAppTicket(ticket: Buffer): AppTicket | undefined {
@@ -885,10 +886,11 @@ export function parseAppTicket(ticket: Buffer): AppTicket | undefined {
// Adapted from the structs found at https://github.com/SteamRE/SteamKit/blob/master/Resources/Structs/steam3_appticket.hsl
const appTicket: AppTicket = {
steamId: "",
- appId: 0,
+ appId: "",
expiry: new Date(),
dlc: [],
valid: false,
+ hash: ""
}
let offset = 0
@@ -906,8 +908,9 @@ export function parseAppTicket(ticket: Buffer): AppTicket | undefined {
offset + ticket.readUInt32LE(offset),
)
appTicket.steamId = ticket.readBigUInt64LE((offset += 8)).toString()
- appTicket.appId = ticket.readUInt32LE((offset += 8))
+ appTicket.appId = ticket.readUInt32LE((offset += 8)).toString()
appTicket.expiry = new Date(ticket.readUInt32LE((offset += 20)) * 1000)
+ appTicket.hash = createHash("sha256").update(ownershipTicket).digest("hex")
// Skip past licenses
const licensesLength = ticket.readUInt16LE((offset += 4))
@@ -917,7 +920,7 @@ export function parseAppTicket(ticket: Buffer): AppTicket | undefined {
offset += 2
for (let i = 0; i < dlcLength; ++i) {
- appTicket.dlc.push(ticket.readUInt32LE(offset))
+ appTicket.dlc.push(ticket.readUInt32LE(offset).toString())
// DLC Licenses array, usually empty
const licensesLength = ticket.readUInt16LE((offset += 4))
From 89132255817b761e37b051519cbdb33079fa3854 Mon Sep 17 00:00:00 2001
From: AnthonyFuller <24512050+AnthonyFuller@users.noreply.github.com>
Date: Mon, 30 Mar 2026 22:51:31 +0100
Subject: [PATCH 05/11] refactor(SteamStrategy): parse ticket before calling
out to steam, update to reflect changes made to parseAppTicket, use app id
from the ticket, change cache to a set
---
components/entitlementStrategies.ts | 53 ++++++++++++++---------------
components/oauthToken.ts | 2 +-
2 files changed, 26 insertions(+), 29 deletions(-)
diff --git a/components/entitlementStrategies.ts b/components/entitlementStrategies.ts
index 053e343b9..44cae3e7e 100644
--- a/components/entitlementStrategies.ts
+++ b/components/entitlementStrategies.ts
@@ -27,14 +27,13 @@ import {
STEAM_NAMESPACE_2016,
} from "./platformEntitlements"
import { GameVersion } from "./types/types"
-import { getRemoteService, parseAppTicket } from "./utils"
+import { AppTicket, getRemoteService, parseAppTicket } from "./utils"
import { getFlag } from "./flags"
-import { createHash } from "crypto"
-// An in-memory cache of Steam ownership tickets to entitlements (they're valid for up to 21 days)
+// An in-memory cache of valid Steam ownership ticket hashes (they're valid for up to 21 days)
// For most users, this won't provide any benefit since they'll be restarting Peacock often,
// but this is more here for those running it 24/7 on a server somewhere.
-const STEAM_TICKET_CACHE: Map = new Map()
+const STEAM_TICKET_CACHE: Set = new Set()
/**
* The base class for an entitlement strategy.
@@ -106,9 +105,8 @@ export class SteamStrategy extends EntitlementStrategy {
private readonly _apiKey: string = getFlag("steamApiKey") as SteamAuthMethod
public readonly isValid: boolean = false
- constructor(private readonly _appId: string) {
+ constructor() {
super()
- this._appId = _appId
const method = getFlag("steamAuthenticationMethod") as SteamAuthMethod
@@ -159,10 +157,10 @@ export class SteamStrategy extends EntitlementStrategy {
private async _getFromSteam(
clientToken: string,
+ ticket: AppTicket,
identity: string,
): Promise {
- const ticket = parseAppTicket(Buffer.from(clientToken, "hex"))
-
+ // We already check this before calling, but it's just for sanity.
if (!ticket?.valid) {
return {
success: false,
@@ -177,7 +175,7 @@ export class SteamStrategy extends EntitlementStrategy {
{
params: {
key: this._apiKey,
- appid: this._appId,
+ appid: ticket.appId,
ticket: clientToken,
identity,
},
@@ -210,13 +208,11 @@ export class SteamStrategy extends EntitlementStrategy {
}
}
+ ticket.dlc.unshift(ticket.appId)
return {
success: true,
steamId: data.response.params!.steamid,
- entitlements: [
- ticket.appId.toString(),
- ...ticket.dlc.map((dlc) => dlc.toString()),
- ],
+ entitlements: ticket.dlc,
}
} catch (error) {
if (error instanceof AxiosError) {
@@ -243,17 +239,17 @@ export class SteamStrategy extends EntitlementStrategy {
): Promise {
if (!this.isValid) return []
- const hash = createHash("sha256")
- .update(
- clientToken.startsWith("14000000") &&
- clientToken.length > 52 * 2
- ? clientToken.substring(52 * 2) // Skip 52 bytes to get the ownership ticket (this part can be valid for up to 21 days)
- : clientToken,
- )
- .digest("hex")
+ const ticket = parseAppTicket(Buffer.from(clientToken, "hex"))
+
+ if (!ticket?.valid)
+ {
+ log(LogLevel.WARN, "Invalid ticket.", "SteamStrategy")
+ return []
+ }
- if (STEAM_TICKET_CACHE.has(hash)) {
- return STEAM_TICKET_CACHE.get(hash)!
+ if (STEAM_TICKET_CACHE.has(ticket.hash)) {
+ ticket.dlc.unshift(ticket.appId)
+ return ticket.dlc
}
const authMethod = getFlag(
@@ -261,7 +257,7 @@ export class SteamStrategy extends EntitlementStrategy {
) as SteamAuthMethod
const res = await (authMethod === "BACKEND"
? this._getFromBackend(clientToken)
- : this._getFromSteam(clientToken, identity))
+ : this._getFromSteam(clientToken, ticket, identity))
if (!res.success) {
log(
@@ -281,7 +277,7 @@ export class SteamStrategy extends EntitlementStrategy {
return []
}
- STEAM_TICKET_CACHE.set(hash, res.entitlements)
+ STEAM_TICKET_CACHE.add(ticket.hash)
return res.entitlements
}
@@ -294,13 +290,14 @@ export class SteamStrategy extends EntitlementStrategy {
*/
export class IOIStrategy extends EntitlementStrategy {
private readonly _remoteService: string
+ private readonly _issuerId: string
constructor(
gameVersion: GameVersion,
- private readonly issuerId: string,
+ issuerId: string,
) {
super()
- this.issuerId = issuerId
+ this._issuerId = issuerId
this._remoteService = getRemoteService(gameVersion)!
}
@@ -319,7 +316,7 @@ export class IOIStrategy extends EntitlementStrategy {
`https://${this._remoteService}.hitman.io/authentication/api/userchannel/ProfileService/GetPlatformEntitlements`,
false,
{
- issuerId: this.issuerId,
+ issuerId: this._issuerId,
},
)
} catch (error) {
diff --git a/components/oauthToken.ts b/components/oauthToken.ts
index 2a2268431..580baa2a6 100644
--- a/components/oauthToken.ts
+++ b/components/oauthToken.ts
@@ -298,7 +298,7 @@ export async function handleOAuthToken(
req.body.epic_userid!,
)
} else if (external_platform === "steam") {
- let ents = await new SteamStrategy(external_appid).get(
+ let ents = await new SteamStrategy().get(
req.body.steam_clienttoken!,
req.body.steam_identity!,
req.body.steam_userid!,
From 9bb00bc2c83404c54d1799289ccf2f577ed293be Mon Sep 17 00:00:00 2001
From: AnthonyFuller <24512050+AnthonyFuller@users.noreply.github.com>
Date: Mon, 30 Mar 2026 23:04:04 +0100
Subject: [PATCH 06/11] feat(SteamStrategy): implement validation via the
backend (and a prettier run)
---
components/entitlementStrategies.ts | 86 ++++++++++++++++++++++++-----
components/utils.ts | 6 +-
2 files changed, 77 insertions(+), 15 deletions(-)
diff --git a/components/entitlementStrategies.ts b/components/entitlementStrategies.ts
index 44cae3e7e..dcb38e0cd 100644
--- a/components/entitlementStrategies.ts
+++ b/components/entitlementStrategies.ts
@@ -27,7 +27,12 @@ import {
STEAM_NAMESPACE_2016,
} from "./platformEntitlements"
import { GameVersion } from "./types/types"
-import { AppTicket, getRemoteService, parseAppTicket } from "./utils"
+import {
+ AppTicket,
+ getRemoteService,
+ parseAppTicket,
+ PEACOCKVERSTRING,
+} from "./utils"
import { getFlag } from "./flags"
// An in-memory cache of valid Steam ownership ticket hashes (they're valid for up to 21 days)
@@ -100,6 +105,16 @@ type SteamAuthResponse = {
}
}
}
+type SteamAuthBackendResponse =
+ | {
+ success: true
+ steam_id: string
+ entitlements: string[]
+ }
+ | {
+ success: false
+ error: string
+ }
export class SteamStrategy extends EntitlementStrategy {
private readonly _apiKey: string = getFlag("steamApiKey") as SteamAuthMethod
@@ -146,12 +161,61 @@ export class SteamStrategy extends EntitlementStrategy {
}
private async _getFromBackend(
- _clientToken: string,
+ clientToken: string,
+ identity: string,
): Promise {
- return {
- success: false,
- code: 500,
- error: "Backend validation not implemented",
+ try {
+ const host = getFlag("leaderboardsHost") as string
+ const resp = await axios.post(
+ `${host}/peacock/steam/validate_ticket`,
+ {
+ ticket: clientToken,
+ identity,
+ },
+ {
+ headers: {
+ "Peacock-Version": PEACOCKVERSTRING,
+ },
+ },
+ )
+
+ if (resp.status !== 200 && resp.status !== 400) {
+ return {
+ success: false,
+ code: resp.status,
+ error: `${resp.statusText}`,
+ }
+ }
+
+ const data = resp.data as SteamAuthBackendResponse
+
+ if (!data.success) {
+ return {
+ success: false,
+ code: resp.status,
+ error: data.error,
+ }
+ }
+
+ return {
+ success: true,
+ steamId: data.steam_id,
+ entitlements: data.entitlements,
+ }
+ } catch (error) {
+ if (error instanceof AxiosError) {
+ return {
+ success: false,
+ code: error.response?.status ?? 400,
+ error: `${error.response?.statusText}`,
+ }
+ } else {
+ return {
+ success: false,
+ code: 400,
+ error: `${error}`,
+ }
+ }
}
}
@@ -241,8 +305,7 @@ export class SteamStrategy extends EntitlementStrategy {
const ticket = parseAppTicket(Buffer.from(clientToken, "hex"))
- if (!ticket?.valid)
- {
+ if (!ticket?.valid) {
log(LogLevel.WARN, "Invalid ticket.", "SteamStrategy")
return []
}
@@ -256,7 +319,7 @@ export class SteamStrategy extends EntitlementStrategy {
"steamAuthenticationMethod",
) as SteamAuthMethod
const res = await (authMethod === "BACKEND"
- ? this._getFromBackend(clientToken)
+ ? this._getFromBackend(clientToken, identity)
: this._getFromSteam(clientToken, ticket, identity))
if (!res.success) {
@@ -292,10 +355,7 @@ export class IOIStrategy extends EntitlementStrategy {
private readonly _remoteService: string
private readonly _issuerId: string
- constructor(
- gameVersion: GameVersion,
- issuerId: string,
- ) {
+ constructor(gameVersion: GameVersion, issuerId: string) {
super()
this._issuerId = issuerId
this._remoteService = getRemoteService(gameVersion)!
diff --git a/components/utils.ts b/components/utils.ts
index 4fcf9f722..3eaf9b618 100644
--- a/components/utils.ts
+++ b/components/utils.ts
@@ -890,7 +890,7 @@ export function parseAppTicket(ticket: Buffer): AppTicket | undefined {
expiry: new Date(),
dlc: [],
valid: false,
- hash: ""
+ hash: "",
}
let offset = 0
@@ -910,7 +910,9 @@ export function parseAppTicket(ticket: Buffer): AppTicket | undefined {
appTicket.steamId = ticket.readBigUInt64LE((offset += 8)).toString()
appTicket.appId = ticket.readUInt32LE((offset += 8)).toString()
appTicket.expiry = new Date(ticket.readUInt32LE((offset += 20)) * 1000)
- appTicket.hash = createHash("sha256").update(ownershipTicket).digest("hex")
+ appTicket.hash = createHash("sha256")
+ .update(ownershipTicket)
+ .digest("hex")
// Skip past licenses
const licensesLength = ticket.readUInt16LE((offset += 4))
From 678334259af3820f93aa1f6abd396329e4ed4537 Mon Sep 17 00:00:00 2001
From: AnthonyFuller <24512050+AnthonyFuller@users.noreply.github.com>
Date: Mon, 30 Mar 2026 23:22:02 +0100
Subject: [PATCH 07/11] feat(parseAppTicket): validate ownership ticket version
---
components/utils.ts | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/components/utils.ts b/components/utils.ts
index 3eaf9b618..c43ba8837 100644
--- a/components/utils.ts
+++ b/components/utils.ts
@@ -907,7 +907,15 @@ export function parseAppTicket(ticket: Buffer): AppTicket | undefined {
offset,
offset + ticket.readUInt32LE(offset),
)
- appTicket.steamId = ticket.readBigUInt64LE((offset += 8)).toString()
+
+ const ticketVersion = ticket.readUInt32LE((offset += 4))
+ if (ticketVersion !== 4)
+ {
+ log(LogLevel.ERROR, `Encountered unknown ownership ticket version! Expected: 4, Got: ${ticketVersion}`, "parseAppTicket")
+ return
+ }
+
+ appTicket.steamId = ticket.readBigUInt64LE((offset += 4)).toString()
appTicket.appId = ticket.readUInt32LE((offset += 8)).toString()
appTicket.expiry = new Date(ticket.readUInt32LE((offset += 20)) * 1000)
appTicket.hash = createHash("sha256")
From 7eed7e53bcae4e77f16c1ca28649c15508a8e9f1 Mon Sep 17 00:00:00 2001
From: AnthonyFuller <24512050+AnthonyFuller@users.noreply.github.com>
Date: Mon, 30 Mar 2026 23:24:45 +0100
Subject: [PATCH 08/11] chore: prettier run
---
components/utils.ts | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/components/utils.ts b/components/utils.ts
index c43ba8837..bbc51c125 100644
--- a/components/utils.ts
+++ b/components/utils.ts
@@ -909,9 +909,12 @@ export function parseAppTicket(ticket: Buffer): AppTicket | undefined {
)
const ticketVersion = ticket.readUInt32LE((offset += 4))
- if (ticketVersion !== 4)
- {
- log(LogLevel.ERROR, `Encountered unknown ownership ticket version! Expected: 4, Got: ${ticketVersion}`, "parseAppTicket")
+ if (ticketVersion !== 4) {
+ log(
+ LogLevel.ERROR,
+ `Encountered unknown ownership ticket version! Expected: 4, Got: ${ticketVersion}`,
+ "parseAppTicket",
+ )
return
}
From 35378e1ec0655795bf47974b5e99c05f2443cab4 Mon Sep 17 00:00:00 2001
From: AnthonyFuller <24512050+AnthonyFuller@users.noreply.github.com>
Date: Mon, 30 Mar 2026 23:26:29 +0100
Subject: [PATCH 09/11] chore: prettier run
---
components/utils.ts | 1 +
1 file changed, 1 insertion(+)
diff --git a/components/utils.ts b/components/utils.ts
index bbc51c125..0ade23419 100644
--- a/components/utils.ts
+++ b/components/utils.ts
@@ -909,6 +909,7 @@ export function parseAppTicket(ticket: Buffer): AppTicket | undefined {
)
const ticketVersion = ticket.readUInt32LE((offset += 4))
+
if (ticketVersion !== 4) {
log(
LogLevel.ERROR,
From 263c19d6d93f4672250a4b4f358cbfa14490b031 Mon Sep 17 00:00:00 2001
From: AnthonyFuller <24512050+AnthonyFuller@users.noreply.github.com>
Date: Tue, 31 Mar 2026 00:49:36 +0100
Subject: [PATCH 10/11] fix(SteamStrategy/Backend): don't throw if the response
status is 400
---
components/entitlementStrategies.ts | 1 +
1 file changed, 1 insertion(+)
diff --git a/components/entitlementStrategies.ts b/components/entitlementStrategies.ts
index dcb38e0cd..564bfd5d0 100644
--- a/components/entitlementStrategies.ts
+++ b/components/entitlementStrategies.ts
@@ -176,6 +176,7 @@ export class SteamStrategy extends EntitlementStrategy {
headers: {
"Peacock-Version": PEACOCKVERSTRING,
},
+ validateStatus: status => status === 400 || (status >= 200 && status < 300)
},
)
From dbe2cb31d8801996ba9431a2ef3a55fb8922714a Mon Sep 17 00:00:00 2001
From: AnthonyFuller <24512050+AnthonyFuller@users.noreply.github.com>
Date: Wed, 1 Apr 2026 19:33:10 +0100
Subject: [PATCH 11/11] chore: prettier run
---
components/entitlementStrategies.ts | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/components/entitlementStrategies.ts b/components/entitlementStrategies.ts
index 564bfd5d0..9152dd03e 100644
--- a/components/entitlementStrategies.ts
+++ b/components/entitlementStrategies.ts
@@ -176,7 +176,8 @@ export class SteamStrategy extends EntitlementStrategy {
headers: {
"Peacock-Version": PEACOCKVERSTRING,
},
- validateStatus: status => status === 400 || (status >= 200 && status < 300)
+ validateStatus: (status) =>
+ status === 400 || (status >= 200 && status < 300),
},
)