Compare commits

...

18 Commits

Author SHA1 Message Date
Chubby Granny Chaser
a21f2b9614 Merge pull request #1579 from hydralauncher/feat/ludusavi-upgrade
Feat/ludusavi upgrade
2025-04-18 23:12:48 +01:00
Chubby Granny Chaser
c16cbfe04e Merge branch 'main' into feat/ludusavi-upgrade 2025-04-18 23:09:33 +01:00
Chubby Granny Chaser
4ff41da05a Merge branch 'feat/ludusavi-upgrade' of github.com:hydralauncher/hydra into feat/ludusavi-upgrade 2025-04-18 22:59:56 +01:00
Chubby Granny Chaser
a12e5a15fa chore: bumping version 2025-04-18 22:57:28 +01:00
Zamitto
cc2311529b Merge pull request #1580 from caumeira/patch-1
chore: update create-desktop-shortcuts
2025-04-18 17:04:41 -03:00
Carlos Meira
18b63d735d Update yarn.lock 2025-04-18 16:47:49 -03:00
Zamitto
7379113dc8 chore: update issue template 2025-04-18 12:33:33 -03:00
Carlos Meira
ea85da259c chore: update create-desktop-shortcuts
Fix a issue with bugged icons
2025-04-18 11:27:07 -03:00
Zamitto
b8084d6f67 feat: add await to ensure HydraApi is setup before renderer opens window 2025-04-18 07:22:01 -03:00
Chubby Granny Chaser
97589e63fa Merge branch 'feat/ludusavi-upgrade' of github.com:hydralauncher/hydra into feat/ludusavi-upgrade 2025-04-18 00:07:43 +01:00
Chubby Granny Chaser
2539f67e13 Merge branch 'main' of github.com:hydralauncher/hydra into feat/ludusavi-upgrade 2025-04-18 00:07:36 +01:00
Chubby Granny Chaser
cc4aed2e17 fix: fixing date on backup upload 2025-04-18 00:06:30 +01:00
Chubby Granny Chaser
9ea68e629a Merge branch 'main' into feat/ludusavi-upgrade 2025-04-17 23:48:49 +01:00
Chubby Granny Chaser
8c66b9a499 fix: fixing date on backup upload 2025-04-17 23:44:25 +01:00
Chubby Granny Chaser
8fb183007a Merge pull request #1571 from Lianela/main
Update spanish translation.json
2025-04-17 23:29:23 +01:00
Chubby Granny Chaser
d0ac819da5 feat: upgrading ludusavi 2025-04-17 23:27:22 +01:00
Chubby Granny Chaser
f4e428a574 feat: upgrading ludusavi 2025-04-17 23:23:06 +01:00
Lianela
69879a0303 Update translation.json 2025-04-15 18:29:38 -06:00
13 changed files with 95 additions and 75 deletions

View File

@@ -33,9 +33,9 @@ body:
attributes: attributes:
label: Additional information and data label: Additional information and data
description: | description: |
Add screenshots and upload your logs file here. Add screenshots and upload your all logs file here.
Logs location on Windows: "%appdata%/hydra" Logs location on Windows: "%appdata%/hydralauncher/logs"
Logs location on Linux: "~/.config/hydra/" Logs location on Linux: "~/.config/hydralauncher/logs"
validations: validations:
required: true required: true
- type: input - type: input

View File

@@ -88,6 +88,18 @@ jobs:
dist/*.blockmap dist/*.blockmap
dist/*.pacman dist/*.pacman
- name: Upload build
env:
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
S3_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
S3_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID }}
S3_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY }}
S3_BUILDS_BUCKET_NAME: ${{ secrets.S3_BUILDS_BUCKET_NAME }}
BUILDS_URL: ${{ secrets.BUILDS_URL }}
BUILD_WEBHOOK_URL: ${{ secrets.BUILD_WEBHOOK_URL }}
GITHUB_ACTOR: ${{ github.actor }}
run: node scripts/upload-build.cjs
- name: Release - name: Release
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@v2
with: with:

View File

@@ -1,6 +1,6 @@
{ {
"name": "hydralauncher", "name": "hydralauncher",
"version": "3.4.3", "version": "3.4.4",
"description": "Hydra", "description": "Hydra",
"main": "./out/main/index.js", "main": "./out/main/index.js",
"author": "Los Broxas", "author": "Los Broxas",
@@ -48,7 +48,7 @@
"classnames": "^2.5.1", "classnames": "^2.5.1",
"color": "^4.2.3", "color": "^4.2.3",
"color.js": "^1.2.0", "color.js": "^1.2.0",
"create-desktop-shortcuts": "^1.11.0", "create-desktop-shortcuts": "^1.11.1",
"date-fns": "^3.6.0", "date-fns": "^3.6.0",
"dexie": "^4.0.10", "dexie": "^4.0.10",
"diskusage": "^1.2.0", "diskusage": "^1.2.0",
@@ -59,7 +59,6 @@
"i18next-browser-languagedetector": "^7.2.1", "i18next-browser-languagedetector": "^7.2.1",
"jsdom": "^24.0.0", "jsdom": "^24.0.0",
"jsonwebtoken": "^9.0.2", "jsonwebtoken": "^9.0.2",
"kill-port": "^2.0.1",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"parse-torrent": "^11.0.17", "parse-torrent": "^11.0.17",
"piscina": "^4.7.0", "piscina": "^4.7.0",

View File

@@ -1,4 +1,5 @@
const { default: axios } = require("axios"); const { default: axios } = require("axios");
const tar = require("tar");
const util = require("node:util"); const util = require("node:util");
const fs = require("node:fs"); const fs = require("node:fs");
const path = require("node:path"); const path = require("node:path");
@@ -6,10 +7,12 @@ const { spawnSync } = require("node:child_process");
const exec = util.promisify(require("node:child_process").exec); const exec = util.promisify(require("node:child_process").exec);
const ludusaviVersion = "0.29.0";
const fileName = { const fileName = {
win32: "ludusavi-v0.25.0-win64.zip", win32: `ludusavi-v${ludusaviVersion}-win64.zip`,
linux: "ludusavi-v0.25.0-linux.zip", linux: `ludusavi-v${ludusaviVersion}-linux.tar.gz`,
darwin: "ludusavi-v0.25.0-mac.zip", darwin: `ludusavi-v${ludusaviVersion}-mac.tar.gz`,
}; };
const downloadLudusavi = async () => { const downloadLudusavi = async () => {
@@ -19,7 +22,7 @@ const downloadLudusavi = async () => {
} }
const file = fileName[process.platform]; const file = fileName[process.platform];
const downloadUrl = `https://github.com/mtkennerly/ludusavi/releases/download/v0.25.0/${file}`; const downloadUrl = `https://github.com/mtkennerly/ludusavi/releases/download/v${ludusaviVersion}/${file}`;
console.log(`Downloading ${file}...`); console.log(`Downloading ${file}...`);
@@ -31,10 +34,18 @@ const downloadLudusavi = async () => {
console.log(`Downloaded ${file}, extracting...`); console.log(`Downloaded ${file}, extracting...`);
const pwd = process.cwd(); const pwd = process.cwd();
const targetPath = path.join(pwd, "ludusavi"); const targetPath = path.join(pwd, "ludusavi");
await exec(`npx extract-zip ${file} ${targetPath}`); await fs.promises.mkdir(targetPath, { recursive: true });
if (process.platform === "win32") {
await exec(`npx extract-zip ${file} ${targetPath}`);
} else {
await tar.x({
file: file,
cwd: targetPath,
});
}
if (process.platform !== "win32") { if (process.platform !== "win32") {
fs.chmodSync(path.join(targetPath, "ludusavi"), 0o755); fs.chmodSync(path.join(targetPath, "ludusavi"), 0o755);

View File

@@ -44,6 +44,9 @@
"downloading_metadata": "Descargando metadatos de {{title}}…", "downloading_metadata": "Descargando metadatos de {{title}}…",
"downloading": "Descargando {{title}}… ({{percentage}} completado) - Finalizando {{eta}} - {{speed}}", "downloading": "Descargando {{title}}… ({{percentage}} completado) - Finalizando {{eta}} - {{speed}}",
"calculating_eta": "Descargando {{title}}… ({{percentage}} completado) - Calculando tiempo restante…", "calculating_eta": "Descargando {{title}}… ({{percentage}} completado) - Calculando tiempo restante…",
"installation_complete": "Instalación completada",
"installation_complete_message": "Common redistributables instalados exitosamente",
"installing_common_redist": "{{log}}…",
"checking_files": "Verificando archivos de {{title}}… ({{percentage}} completado)" "checking_files": "Verificando archivos de {{title}}… ({{percentage}} completado)"
}, },
"catalogue": { "catalogue": {
@@ -59,6 +62,8 @@
}, },
"game_details": { "game_details": {
"open_download_options": "Ver opciones de descargas", "open_download_options": "Ver opciones de descargas",
"automatically_extract_downloaded_files": "Extraer automáticamente archivos descargados",
"download_error_not_cached_on_hydra": "Esta descarga no está disponible en Nimbus.",
"download_options_zero": "No hay opciones de descargas disponibles", "download_options_zero": "No hay opciones de descargas disponibles",
"download_options_one": "{{count}} opción de descarga", "download_options_one": "{{count}} opción de descarga",
"download_options_other": "{{count}} opciones de descargas", "download_options_other": "{{count}} opciones de descargas",
@@ -230,10 +235,19 @@
"seeding": "Seeding", "seeding": "Seeding",
"stop_seeding": "Detener seeding", "stop_seeding": "Detener seeding",
"resume_seeding": "Continuar seeding", "resume_seeding": "Continuar seeding",
"extract": "Extraer archivos",
"extracting": "Extrayendo archivos…",
"options": "Gestionar" "options": "Gestionar"
}, },
"settings": { "settings": {
"downloads_path": "Ruta de descarga", "downloads_path": "Ruta de descarga",
"common_redist": "Common redistributables",
"common_redist_description": "Las Common redistributables son requeridos para ejecutar algunos juegos. Es recomendado instalarlos para evitar problemas.",
"create_real_debrid_account": "Presiona acá si no tienes una cuenta de Real-Debrid aún",
"create_torbox_account": "Presiona acá si no tienes una cuenta de TorBox aún",
"install_common_redist": "Instalar",
"installing_common_redist": "Instalando…",
"show_download_speed_in_megabytes": "Mostrar velocidad de descargar en megabytes por segundo",
"change": "Cambiar", "change": "Cambiar",
"notifications": "Notificaciones", "notifications": "Notificaciones",
"enable_download_notifications": "Cuando se completa una descarga", "enable_download_notifications": "Cuando se completa una descarga",
@@ -346,6 +360,8 @@
}, },
"notifications": { "notifications": {
"download_complete": "Descarga completada", "download_complete": "Descarga completada",
"extraction_complete": "Extracción completada",
"game_extracted": "{{title}} extraído exitosamente",
"game_ready_to_install": "{{title}} está listo para instalarse", "game_ready_to_install": "{{title}} está listo para instalarse",
"repack_list_updated": "Lista de repacks actualizadas", "repack_list_updated": "Lista de repacks actualizadas",
"repack_count_one": "{{count}} repack ha sido añadido", "repack_count_one": "{{count}} repack ha sido añadido",
@@ -475,6 +491,7 @@
}, },
"hydra_cloud": { "hydra_cloud": {
"subscription_tour_title": "Suscripción Hydra Cloud", "subscription_tour_title": "Suscripción Hydra Cloud",
"debrid_description": "Descargas hasta x4 más rápidas con Nimbus",
"subscribe_now": "Suscribirse ahora", "subscribe_now": "Suscribirse ahora",
"cloud_saving": "Guardado en la nube", "cloud_saving": "Guardado en la nube",
"cloud_achievements": "Guarda tus logros en la nube", "cloud_achievements": "Guarda tus logros en la nube",

View File

@@ -1,8 +1,6 @@
import { CloudSync } from "@main/services"; import { CloudSync } from "@main/services";
import { registerEvent } from "../register-event"; import { registerEvent } from "../register-event";
import type { GameShop } from "@types"; import type { GameShop } from "@types";
import i18next, { t } from "i18next";
import { formatDate } from "date-fns";
const uploadSaveGame = async ( const uploadSaveGame = async (
_event: Electron.IpcMainInvokeEvent, _event: Electron.IpcMainInvokeEvent,
@@ -10,16 +8,11 @@ const uploadSaveGame = async (
shop: GameShop, shop: GameShop,
downloadOptionTitle: string | null downloadOptionTitle: string | null
) => { ) => {
const { language } = i18next;
return CloudSync.uploadSaveGame( return CloudSync.uploadSaveGame(
objectId, objectId,
shop, shop,
downloadOptionTitle, downloadOptionTitle,
t("backup_from", { CloudSync.getBackupLabel(false)
ns: "game_details",
date: formatDate(new Date(), language),
})
); );
}; };

View File

@@ -3,7 +3,6 @@ import updater from "electron-updater";
import i18n from "i18next"; import i18n from "i18next";
import path from "node:path"; import path from "node:path";
import url from "node:url"; import url from "node:url";
import kill from "kill-port";
import { electronApp, optimizer } from "@electron-toolkit/utils"; import { electronApp, optimizer } from "@electron-toolkit/utils";
import { logger, WindowManager } from "@main/services"; import { logger, WindowManager } from "@main/services";
import resources from "@locales"; import resources from "@locales";
@@ -58,7 +57,7 @@ app.whenReady().then(async () => {
return net.fetch(url.pathToFileURL(decodeURI(filePath)).toString()); return net.fetch(url.pathToFileURL(decodeURI(filePath)).toString());
}); });
await kill(PythonRPC.RPC_PORT).finally(() => loadState()); await loadState();
const language = await db.get<string, string>(levelKeys.language, { const language = await db.get<string, string>(levelKeys.language, {
valueEncoding: "utf-8", valueEncoding: "utf-8",

View File

@@ -32,7 +32,7 @@ export const loadState = async () => {
Ludusavi.addManifestToLudusaviConfig(); Ludusavi.addManifestToLudusaviConfig();
HydraApi.setupApi().then(() => { await HydraApi.setupApi().then(() => {
uploadGamesBatch(); uploadGamesBatch();
}); });

View File

@@ -13,9 +13,28 @@ import { logger } from "./logger";
import { WindowManager } from "./window-manager"; import { WindowManager } from "./window-manager";
import axios from "axios"; import axios from "axios";
import { Ludusavi } from "./ludusavi"; import { Ludusavi } from "./ludusavi";
import { SubscriptionRequiredError } from "@shared"; import { formatDate, SubscriptionRequiredError } from "@shared";
import i18next, { t } from "i18next";
export class CloudSync { export class CloudSync {
public static getBackupLabel(automatic: boolean) {
const language = i18next.language;
const date = formatDate(new Date(), language);
if (automatic) {
return t("automatic_backup_from", {
ns: "game_details",
date,
});
}
return t("backup_from", {
ns: "game_details",
date,
});
}
private static async bundleBackup( private static async bundleBackup(
shop: GameShop, shop: GameShop,
objectId: string, objectId: string,
@@ -25,7 +44,11 @@ export class CloudSync {
// Remove existing backup // Remove existing backup
if (fs.existsSync(backupPath)) { if (fs.existsSync(backupPath)) {
fs.rmSync(backupPath, { recursive: true }); try {
await fs.promises.rm(backupPath, { recursive: true });
} catch (error) {
logger.error("Failed to remove backup path", error);
}
} }
await Ludusavi.backupGame(shop, objectId, backupPath, winePrefix); await Ludusavi.backupGame(shop, objectId, backupPath, winePrefix);
@@ -101,11 +124,10 @@ export class CloudSync {
true true
); );
fs.rm(bundleLocation, (err) => { try {
if (err) { await fs.promises.unlink(bundleLocation);
logger.error("Failed to remove tar file", err); } catch (error) {
throw err; logger.error("Failed to remove tar file", error);
} }
});
} }
} }

View File

@@ -6,9 +6,7 @@ import axios from "axios";
import { exec } from "child_process"; import { exec } from "child_process";
import { ProcessPayload } from "./download/types"; import { ProcessPayload } from "./download/types";
import { gamesSublevel, levelKeys } from "@main/level"; import { gamesSublevel, levelKeys } from "@main/level";
import i18next, { t } from "i18next";
import { CloudSync } from "./cloud-sync"; import { CloudSync } from "./cloud-sync";
import { formatDate } from "date-fns";
const commands = { const commands = {
findWineDir: `lsof -c wine 2>/dev/null | grep '/drive_c/windows$' | head -n 1 | awk '{for(i=9;i<=NF;i++) printf "%s ", $i; print ""}'`, findWineDir: `lsof -c wine 2>/dev/null | grep '/drive_c/windows$' | head -n 1 | awk '{for(i=9;i<=NF;i++) printf "%s ", $i; print ""}'`,
@@ -229,17 +227,12 @@ function onOpenGame(game: Game) {
if (game.remoteId) { if (game.remoteId) {
updateGamePlaytime(game, 0, new Date()).catch(() => {}); updateGamePlaytime(game, 0, new Date()).catch(() => {});
const { language } = i18next;
if (game.automaticCloudSync) { if (game.automaticCloudSync) {
CloudSync.uploadSaveGame( CloudSync.uploadSaveGame(
game.objectId, game.objectId,
game.shop, game.shop,
null, null,
t("automatic_backup_from", { CloudSync.getBackupLabel(true)
ns: "game_details",
date: formatDate(new Date(), language),
})
); );
} }
} else { } else {
@@ -298,8 +291,6 @@ const onCloseGame = (game: Game) => {
)!; )!;
gamesPlaytime.delete(levelKeys.game(game.shop, game.objectId)); gamesPlaytime.delete(levelKeys.game(game.shop, game.objectId));
const { language } = i18next;
if (game.remoteId) { if (game.remoteId) {
updateGamePlaytime( updateGamePlaytime(
game, game,
@@ -312,10 +303,7 @@ const onCloseGame = (game: Game) => {
game.objectId, game.objectId,
game.shop, game.shop,
null, null,
t("automatic_backup_from", { CloudSync.getBackupLabel(true)
ns: "game_details",
date: formatDate(new Date(), language),
})
); );
} }
} else { } else {

View File

@@ -1,7 +1,6 @@
import { formatDate, getDateLocale } from "@shared"; import { formatDate, getDateLocale } from "@shared";
import { format, formatDistance, subMilliseconds } from "date-fns"; import { format, formatDistance, subMilliseconds } from "date-fns";
import type { FormatDistanceOptions } from "date-fns"; import type { FormatDistanceOptions } from "date-fns";
import { enUS } from "date-fns/locale";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
export function useDate() { export function useDate() {
@@ -41,10 +40,10 @@ export function useDate() {
}, },
formatDateTime: (date: number | Date | string): string => { formatDateTime: (date: number | Date | string): string => {
const locale = getDateLocale(language);
return format( return format(
date, date,
locale == enUS ? "MM/dd/yyyy - HH:mm" : "dd/MM/yyyy HH:mm" language == "en" ? "MM-dd-yyyy - hh:mm a" : "dd/MM/yyyy HH:mm",
{ locale: getDateLocale(language) }
); );
}, },

View File

@@ -173,7 +173,5 @@ export const formatDate = (
language: string language: string
): string => { ): string => {
if (isNaN(new Date(date).getDate())) return "N/A"; if (isNaN(new Date(date).getDate())) return "N/A";
return format(date, language == "en" ? "MM-dd-yyyy" : "dd/MM/yyyy");
const locale = getDateLocale(language);
return format(date, locale == enUS ? "MM/dd/yyyy" : "dd/MM/yyyy");
}; };

View File

@@ -1460,9 +1460,9 @@
optionalDependencies: optionalDependencies:
global-agent "^3.0.0" global-agent "^3.0.0"
"@electron/node-gyp@git+https://github.com/electron/node-gyp.git#06b29aafb7708acef8b3669835c8a7857ebc92d2": "@electron/node-gyp@https://github.com/electron/node-gyp#06b29aafb7708acef8b3669835c8a7857ebc92d2":
version "10.2.0-electron.1" version "10.2.0-electron.1"
resolved "git+https://github.com/electron/node-gyp.git#06b29aafb7708acef8b3669835c8a7857ebc92d2" resolved "https://github.com/electron/node-gyp#06b29aafb7708acef8b3669835c8a7857ebc92d2"
dependencies: dependencies:
env-paths "^2.2.0" env-paths "^2.2.0"
exponential-backoff "^3.1.1" exponential-backoff "^3.1.1"
@@ -4501,10 +4501,10 @@ crc@^3.8.0:
dependencies: dependencies:
buffer "^5.1.0" buffer "^5.1.0"
create-desktop-shortcuts@^1.11.0: create-desktop-shortcuts@^1.11.1:
version "1.11.0" version "1.11.1"
resolved "https://registry.yarnpkg.com/create-desktop-shortcuts/-/create-desktop-shortcuts-1.11.0.tgz#8eed89329e9bce70dece46d02a80573fe1f2536d" resolved "https://registry.yarnpkg.com/create-desktop-shortcuts/-/create-desktop-shortcuts-1.11.1.tgz#59f9dced7931bda551c0717791a909419472c809"
integrity sha512-nmVtPVqNyMuAyMpDnd7l++hb2laqCWZXnHQaFhqGT1YEi2Ve3unu6QyuyIpGxAwIscNHcG1Ehnl+lFw6ygB2nQ== integrity sha512-EiHvxrMXXEp4xDD3Nvu1FKLueL9+aBWFYtuTlstYZLIg9H45SoYciizteNB+hvQAls3cRSpoXCM7c4q+lcJpyw==
dependencies: dependencies:
which "2.0.2" which "2.0.2"
@@ -5814,11 +5814,6 @@ get-symbol-description@^1.1.0:
es-errors "^1.3.0" es-errors "^1.3.0"
get-intrinsic "^1.2.6" get-intrinsic "^1.2.6"
get-them-args@1.3.2:
version "1.3.2"
resolved "https://registry.yarnpkg.com/get-them-args/-/get-them-args-1.3.2.tgz#74a20ba8a4abece5ae199ad03f2bcc68fdfc9ba5"
integrity sha512-LRn8Jlk+DwZE4GTlDbT3Hikd1wSHgLMme/+7ddlqKd7ldwR6LjJgTVWzBnR01wnYGe4KgrXjg287RaI22UHmAw==
git-raw-commits@^4.0.0: git-raw-commits@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-4.0.0.tgz#b212fd2bff9726d27c1283a1157e829490593285" resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-4.0.0.tgz#b212fd2bff9726d27c1283a1157e829490593285"
@@ -6826,14 +6821,6 @@ keyv@^4.0.0, keyv@^4.5.3:
dependencies: dependencies:
json-buffer "3.0.1" json-buffer "3.0.1"
kill-port@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/kill-port/-/kill-port-2.0.1.tgz#e5e18e2706b13d54320938be42cb7d40609b15cf"
integrity sha512-e0SVOV5jFo0mx8r7bS29maVWp17qGqLBZ5ricNSajON6//kmb7qqqNnml4twNE8Dtj97UQD+gNFOaipS/q1zzQ==
dependencies:
get-them-args "1.3.2"
shell-exec "1.0.2"
language-subtag-registry@^0.3.20: language-subtag-registry@^0.3.20:
version "0.3.23" version "0.3.23"
resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz#23529e04d9e3b74679d70142df3fd2eb6ec572e7" resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz#23529e04d9e3b74679d70142df3fd2eb6ec572e7"
@@ -8459,11 +8446,6 @@ shebang-regex@^3.0.0:
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
shell-exec@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/shell-exec/-/shell-exec-1.0.2.tgz#2e9361b0fde1d73f476c4b6671fa17785f696756"
integrity sha512-jyVd+kU2X+mWKMmGhx4fpWbPsjvD53k9ivqetutVW/BQ+WIZoDoP4d8vUMGezV6saZsiNoW2f9GIhg9Dondohg==
side-channel-list@^1.0.0: side-channel-list@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad"