feat: add update indicator (#1626)

This commit is contained in:
Manuel
2024-12-14 18:58:46 +01:00
committed by GitHub
parent cf9656d91e
commit dd9d8b5261
13 changed files with 441 additions and 7 deletions

View File

@@ -1,13 +1,21 @@
import { UnstyledButton } from "@mantine/core";
import { Indicator, UnstyledButton } from "@mantine/core";
import { api } from "@homarr/api/server";
import { auth } from "@homarr/auth/next";
import { CurrentUserAvatar } from "~/components/user-avatar";
import { UserAvatarMenu } from "~/components/user-avatar-menu";
export const UserButton = () => {
export const UserButton = async () => {
const data = await api.updateChecker.getAvailableUpdates();
const session = await auth();
const isAdmin = session?.user.permissions.includes("admin");
return (
<UserAvatarMenu>
<UserAvatarMenu availableUpdates={isAdmin ? data : undefined}>
<UnstyledButton>
<CurrentUserAvatar size="md" />
<Indicator disabled={data.length === 0 || !isAdmin} size={15} processing withBorder>
<CurrentUserAvatar size="md" />
</Indicator>
</UnstyledButton>
</UserAvatarMenu>
);

View File

@@ -7,6 +7,7 @@ import { useRouter } from "next/navigation";
import { Center, Menu, Stack, Text, useMantineColorScheme } from "@mantine/core";
import { useHotkeys, useTimeout } from "@mantine/hooks";
import {
IconBellRinging,
IconCheck,
IconHome,
IconLogin,
@@ -23,14 +24,17 @@ import { useScopedI18n } from "@homarr/translation/client";
import "flag-icons/css/flag-icons.min.css";
import type { RouterOutputs } from "@homarr/api";
import { useAuthContext } from "~/app/[locale]/_client-providers/session";
import { CurrentLanguageCombobox } from "./language/current-language-combobox";
interface UserAvatarMenuProps {
children: ReactNode;
availableUpdates?: RouterOutputs["updateChecker"]["getAvailableUpdates"];
}
export const UserAvatarMenu = ({ children }: UserAvatarMenuProps) => {
export const UserAvatarMenu = ({ children, availableUpdates }: UserAvatarMenuProps) => {
const t = useScopedI18n("common.userAvatar.menu");
const { colorScheme, toggleColorScheme } = useMantineColorScheme();
useHotkeys([["mod+J", toggleColorScheme]]);
@@ -64,6 +68,21 @@ export const UserAvatarMenu = ({ children }: UserAvatarMenuProps) => {
// We use keepMounted so we can add event listeners to prevent navigating away without saving the board
<Menu width={300} withArrow withinPortal keepMounted>
<Menu.Dropdown>
{availableUpdates && availableUpdates.length > 0 && availableUpdates[0] && (
<>
<Menu.Item
component={"a"}
href={availableUpdates[0].url}
target="_blank"
leftSection={<IconBellRinging size="1rem" />}
>
<Text fw="bold" size="sm">
{t("updateAvailable", { countUpdates: availableUpdates.length, tag: availableUpdates[0].tagName })}
</Text>
</Menu.Item>
<Menu.Divider />
</>
)}
<Menu.Item onClick={toggleColorScheme} leftSection={<ColorSchemeIcon size="1rem" />}>
{colorSchemeText}
</Menu.Item>

View File

@@ -1,6 +1,7 @@
{
"name": "homarr",
"private": true,
"version": "1.0.0",
"scripts": {
"build": "cross-env CI=true turbo build",
"clean": "git clean -xdf node_modules",

View File

@@ -13,6 +13,7 @@ import { logRouter } from "./router/log";
import { mediaRouter } from "./router/medias/media-router";
import { searchEngineRouter } from "./router/search-engine/search-engine-router";
import { serverSettingsRouter } from "./router/serverSettings";
import { updateCheckerRouter } from "./router/update-checker";
import { userRouter } from "./router/user";
import { widgetRouter } from "./router/widgets";
import { createTRPCRouter } from "./trpc";
@@ -35,6 +36,7 @@ export const appRouter = createTRPCRouter({
cronJobs: cronJobsRouter,
apiKeys: apiKeysRouter,
media: mediaRouter,
updateChecker: updateCheckerRouter,
});
// export type definition of API

View File

@@ -0,0 +1,11 @@
import { updateCheckerRequestHandler } from "@homarr/request-handler/update-checker";
import { createTRPCRouter, protectedProcedure } from "../trpc";
export const updateCheckerRouter = createTRPCRouter({
getAvailableUpdates: protectedProcedure.query(async () => {
const handler = updateCheckerRequestHandler.handler({});
const data = await handler.getCachedOrUpdatedDataAsync({});
return data.data.availableUpdates;
}),
});

View File

@@ -38,7 +38,8 @@
"@homarr/request-handler": "workspace:^0.1.0",
"@homarr/server-settings": "workspace:^0.1.0",
"@homarr/translation": "workspace:^0.1.0",
"@homarr/validation": "workspace:^0.1.0"
"@homarr/validation": "workspace:^0.1.0",
"semver-parser": "^4.1.7"
},
"devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0",

View File

@@ -12,6 +12,7 @@ import { pingJob } from "./jobs/ping";
import type { RssFeed } from "./jobs/rss-feeds";
import { rssFeedsJob } from "./jobs/rss-feeds";
import { sessionCleanupJob } from "./jobs/session-cleanup";
import { updateCheckerJob } from "./jobs/update-checker";
import { createCronJobGroup } from "./lib";
export const jobGroup = createCronJobGroup({
@@ -29,6 +30,7 @@ export const jobGroup = createCronJobGroup({
indexerManager: indexerManagerJob,
healthMonitoring: healthMonitoringJob,
sessionCleanup: sessionCleanupJob,
updateChecker: updateCheckerJob,
});
export type JobGroupKeys = ReturnType<(typeof jobGroup)["getKeys"]>[number];

View File

@@ -0,0 +1,13 @@
import { EVERY_HOUR } from "@homarr/cron-jobs-core/expressions";
import { updateCheckerRequestHandler } from "@homarr/request-handler/update-checker";
import { createCronJob } from "../lib";
export const updateCheckerJob = createCronJob("updateChecker", EVERY_HOUR, {
runOnStart: true,
}).withCallback(async () => {
const handler = updateCheckerRequestHandler.handler({});
await handler.getCachedOrUpdatedDataAsync({
forceUpdate: true,
});
});

View File

@@ -7,6 +7,7 @@ export {
createIntegrationOptionsChannel,
createChannelWithLatestAndEvents,
handshakeAsync,
createSubPubChannel,
} from "./lib/channel";
export const exampleChannel = createSubPubChannel<{ message: string }>("example");

View File

@@ -29,6 +29,7 @@
"@homarr/log": "workspace:^0.1.0",
"@homarr/redis": "workspace:^0.1.0",
"dayjs": "^1.11.13",
"octokit": "^4.0.2",
"pretty-print-error": "^1.1.2",
"superjson": "2.2.2"
},

View File

@@ -0,0 +1,59 @@
import dayjs from "dayjs";
import { Octokit } from "octokit";
import { compareSemVer, isValidSemVer } from "semver-parser";
import { logger } from "@homarr/log";
import { createChannelWithLatestAndEvents } from "@homarr/redis";
import { createCachedRequestHandler } from "@homarr/request-handler/lib/cached-request-handler";
import packageJson from "../../../package.json";
export const updateCheckerRequestHandler = createCachedRequestHandler({
queryKey: "homarr-update-checker",
cacheDuration: dayjs.duration(1, "hour"),
async requestAsync(_) {
const octokit = new Octokit();
const releases = await octokit.rest.repos.listReleases({
owner: "homarr-labs",
repo: "homarr",
});
const currentVersion = (packageJson as { version: string }).version;
const availableReleases = [];
for (const release of releases.data) {
if (!isValidSemVer(release.tag_name)) {
logger.warn(`Unable to parse semantic tag '${release.tag_name}'. Update check might not work.`);
continue;
}
availableReleases.push(release);
}
const availableNewerReleases = availableReleases
.filter((release) => compareSemVer(release.tag_name, currentVersion) > 0)
.sort((releaseA, releaseB) => compareSemVer(releaseB.tag_name, releaseA.tag_name));
if (availableReleases.length > 0) {
logger.info(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
`Update checker found a new available version: ${availableReleases[0]!.tag_name}. Current version is ${currentVersion}`,
);
} else {
logger.debug(`Update checker did not find any available updates. Current version is ${currentVersion}`);
}
return {
availableUpdates: availableNewerReleases.map((release) => ({
name: release.name,
contentHtml: release.body_html,
url: release.html_url,
tagName: release.tag_name,
})),
};
},
createRedisChannel() {
return createChannelWithLatestAndEvents<{
availableUpdates: { name: string | null; contentHtml?: string; url: string; tagName: string }[];
}>("homarr:update");
},
});

View File

@@ -733,7 +733,8 @@
"logout": "Logout",
"login": "Login",
"homeBoard": "Your home board",
"loggedOut": "Logged out"
"loggedOut": "Logged out",
"updateAvailable": "{countUpdates} updates available: {tag}"
}
},
"dangerZone": "Danger zone",
@@ -2153,6 +2154,9 @@
},
"sessionCleanup": {
"label": "Session Cleanup"
},
"updateChecker": {
"label": "Update checker"
}
}
},

312
pnpm-lock.yaml generated
View File

@@ -797,6 +797,9 @@ importers:
'@homarr/validation':
specifier: workspace:^0.1.0
version: link:../validation
semver-parser:
specifier: ^4.1.7
version: 4.1.7
devDependencies:
'@homarr/eslint-config':
specifier: workspace:^0.2.0
@@ -1346,6 +1349,9 @@ importers:
dayjs:
specifier: ^1.11.13
version: 1.11.13
octokit:
specifier: ^4.0.2
version: 4.0.2
pretty-print-error:
specifier: ^1.1.2
version: 1.1.2(patch_hash=4arrfgbz7em6s4gqywse7esg4u)
@@ -3047,6 +3053,113 @@ packages:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'}
'@octokit/app@15.1.1':
resolution: {integrity: sha512-fk8xrCSPTJGpyBdBNI+DcZ224dm0aApv4vi6X7/zTmANXlegKV2Td+dJ+fd7APPaPN7R+xttUsj2Fm+AFDSfMQ==}
engines: {node: '>= 18'}
'@octokit/auth-app@7.1.3':
resolution: {integrity: sha512-GZdkOp2kZTIy5dG9oXqvzUAZiPvDx4C/lMlN6yQjtG9d/+hYa7W8WXTJoOrXE8UdfL9A/sZMl206dmtkl9lwVQ==}
engines: {node: '>= 18'}
'@octokit/auth-oauth-app@8.1.1':
resolution: {integrity: sha512-5UtmxXAvU2wfcHIPPDWzVSAWXVJzG3NWsxb7zCFplCWEmMCArSZV0UQu5jw5goLQXbFyOr5onzEH37UJB3zQQg==}
engines: {node: '>= 18'}
'@octokit/auth-oauth-device@7.1.1':
resolution: {integrity: sha512-HWl8lYueHonuyjrKKIup/1tiy0xcmQCdq5ikvMO1YwkNNkxb6DXfrPjrMYItNLyCP/o2H87WuijuE+SlBTT8eg==}
engines: {node: '>= 18'}
'@octokit/auth-oauth-user@5.1.1':
resolution: {integrity: sha512-rRkMz0ErOppdvEfnemHJXgZ9vTPhBuC6yASeFaB7I2yLMd7QpjfrL1mnvRPlyKo+M6eeLxrKanXJ9Qte29SRsw==}
engines: {node: '>= 18'}
'@octokit/auth-token@5.1.1':
resolution: {integrity: sha512-rh3G3wDO8J9wSjfI436JUKzHIxq8NaiL0tVeB2aXmG6p/9859aUOAjA9pmSPNGGZxfwmaJ9ozOJImuNVJdpvbA==}
engines: {node: '>= 18'}
'@octokit/auth-unauthenticated@6.1.0':
resolution: {integrity: sha512-zPSmfrUAcspZH/lOFQnVnvjQZsIvmfApQH6GzJrkIunDooU1Su2qt2FfMTSVPRp7WLTQyC20Kd55lF+mIYaohQ==}
engines: {node: '>= 18'}
'@octokit/core@6.1.2':
resolution: {integrity: sha512-hEb7Ma4cGJGEUNOAVmyfdB/3WirWMg5hDuNFVejGEDFqupeOysLc2sG6HJxY2etBp5YQu5Wtxwi020jS9xlUwg==}
engines: {node: '>= 18'}
'@octokit/endpoint@10.1.1':
resolution: {integrity: sha512-JYjh5rMOwXMJyUpj028cu0Gbp7qe/ihxfJMLc8VZBMMqSwLgOxDI1911gV4Enl1QSavAQNJcwmwBF9M0VvLh6Q==}
engines: {node: '>= 18'}
'@octokit/graphql@8.1.1':
resolution: {integrity: sha512-ukiRmuHTi6ebQx/HFRCXKbDlOh/7xEV6QUXaE7MJEKGNAncGI/STSbOkl12qVXZrfZdpXctx5O9X1AIaebiDBg==}
engines: {node: '>= 18'}
'@octokit/oauth-app@7.1.3':
resolution: {integrity: sha512-EHXbOpBkSGVVGF1W+NLMmsnSsJRkcrnVmDKt0TQYRBb6xWfWzoi9sBD4DIqZ8jGhOWO/V8t4fqFyJ4vDQDn9bg==}
engines: {node: '>= 18'}
'@octokit/oauth-authorization-url@7.1.1':
resolution: {integrity: sha512-ooXV8GBSabSWyhLUowlMIVd9l1s2nsOGQdlP2SQ4LnkEsGXzeCvbSbCPdZThXhEFzleGPwbapT0Sb+YhXRyjCA==}
engines: {node: '>= 18'}
'@octokit/oauth-methods@5.1.2':
resolution: {integrity: sha512-C5lglRD+sBlbrhCUTxgJAFjWgJlmTx5bQ7Ch0+2uqRjYv7Cfb5xpX4WuSC9UgQna3sqRGBL9EImX9PvTpMaQ7g==}
engines: {node: '>= 18'}
'@octokit/openapi-types@22.2.0':
resolution: {integrity: sha512-QBhVjcUa9W7Wwhm6DBFu6ZZ+1/t/oYxqc2tp81Pi41YNuJinbFRx8B133qVOrAaBbF7D/m0Et6f9/pZt9Rc+tg==}
'@octokit/openapi-webhooks-types@8.5.1':
resolution: {integrity: sha512-i3h1b5zpGSB39ffBbYdSGuAd0NhBAwPyA3QV3LYi/lx4lsbZiu7u2UHgXVUR6EpvOI8REOuVh1DZTRfHoJDvuQ==}
'@octokit/plugin-paginate-graphql@5.2.4':
resolution: {integrity: sha512-pLZES1jWaOynXKHOqdnwZ5ULeVR6tVVCMm+AUbp0htdcyXDU95WbkYdU4R2ej1wKj5Tu94Mee2Ne0PjPO9cCyA==}
engines: {node: '>= 18'}
peerDependencies:
'@octokit/core': '>=6'
'@octokit/plugin-paginate-rest@11.3.6':
resolution: {integrity: sha512-zcvqqf/+TicbTCa/Z+3w4eBJcAxCFymtc0UAIsR3dEVoNilWld4oXdscQ3laXamTszUZdusw97K8+DrbFiOwjw==}
engines: {node: '>= 18'}
peerDependencies:
'@octokit/core': '>=6'
'@octokit/plugin-rest-endpoint-methods@13.2.6':
resolution: {integrity: sha512-wMsdyHMjSfKjGINkdGKki06VEkgdEldIGstIEyGX0wbYHGByOwN/KiM+hAAlUwAtPkP3gvXtVQA9L3ITdV2tVw==}
engines: {node: '>= 18'}
peerDependencies:
'@octokit/core': '>=6'
'@octokit/plugin-retry@7.1.2':
resolution: {integrity: sha512-XOWnPpH2kJ5VTwozsxGurw+svB2e61aWlmk5EVIYZPwFK5F9h4cyPyj9CIKRyMXMHSwpIsI3mPOdpMmrRhe7UQ==}
engines: {node: '>= 18'}
peerDependencies:
'@octokit/core': '>=6'
'@octokit/plugin-throttling@9.3.2':
resolution: {integrity: sha512-FqpvcTpIWFpMMwIeSoypoJXysSAQ3R+ALJhXXSG1HTP3YZOIeLmcNcimKaXxTcws+Sh6yoRl13SJ5r8sXc1Fhw==}
engines: {node: '>= 18'}
peerDependencies:
'@octokit/core': ^6.0.0
'@octokit/request-error@6.1.5':
resolution: {integrity: sha512-IlBTfGX8Yn/oFPMwSfvugfncK2EwRLjzbrpifNaMY8o/HTEAFqCA1FZxjD9cWvSKBHgrIhc4CSBIzMxiLsbzFQ==}
engines: {node: '>= 18'}
'@octokit/request@9.1.3':
resolution: {integrity: sha512-V+TFhu5fdF3K58rs1pGUJIDH5RZLbZm5BI+MNF+6o/ssFNT4vWlCh/tVpF3NxGtP15HUxTTMUbsG5llAuU2CZA==}
engines: {node: '>= 18'}
'@octokit/types@13.6.2':
resolution: {integrity: sha512-WpbZfZUcZU77DrSW4wbsSgTPfKcp286q3ItaIgvSbBpZJlu6mnYXAkjZz6LVZPXkEvLIM8McanyZejKTYUHipA==}
'@octokit/webhooks-methods@5.1.0':
resolution: {integrity: sha512-yFZa3UH11VIxYnnoOYCVoJ3q4ChuSOk2IVBBQ0O3xtKX4x9bmKb/1t+Mxixv2iUhzMdOl1qeWJqEhouXXzB3rQ==}
engines: {node: '>= 18'}
'@octokit/webhooks@13.4.1':
resolution: {integrity: sha512-I5YPUtfWidh+OzyrlDahJsUpkpGK0kCTmDRbuqGmlCUzOtxdEkX3R4d6Cd08ijQYwkVXQJanPdbKuZBeV2NMaA==}
engines: {node: '>= 18'}
'@panva/hkdf@1.2.1':
resolution: {integrity: sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==}
@@ -3693,6 +3806,9 @@ packages:
'@types/asn1@0.2.4':
resolution: {integrity: sha512-V91DSJ2l0h0gRhVP4oBfBzRBN9lAbPUkGDMCnwedqPKX2d84aAMc9CulOvxdw1f7DfEYx99afab+Rsm3e52jhA==}
'@types/aws-lambda@8.10.146':
resolution: {integrity: sha512-3BaDXYTh0e6UCJYL/jwV/3+GRslSc08toAiZSmleYtkAUyV5rtvdPYxrG/88uqvTuT6sb27WE9OS90ZNTIuQ0g==}
'@types/babel__core@7.20.5':
resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
@@ -4306,6 +4422,9 @@ packages:
resolution: {integrity: sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==}
engines: {node: '>= 10.0.0'}
before-after-hook@3.0.2:
resolution: {integrity: sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==}
bellajs@11.2.0:
resolution: {integrity: sha512-Wjss+Bc674ZABPr+SCKWTqA4V1pyYFhzDTjNBJy4jdmgOv0oGIGXeKBRJyINwP5tIy+iIZD9SfgZpztduzQ5QA==}
engines: {node: '>= 18.4'}
@@ -4322,6 +4441,9 @@ packages:
bl@4.1.0:
resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
bottleneck@2.19.5:
resolution: {integrity: sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==}
boxen@5.1.2:
resolution: {integrity: sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==}
engines: {node: '>=10'}
@@ -6511,6 +6633,10 @@ packages:
resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==}
engines: {node: '>= 0.4'}
octokit@4.0.2:
resolution: {integrity: sha512-wbqF4uc1YbcldtiBFfkSnquHtECEIpYD78YUXI6ri1Im5OO2NLo6ZVpRdbJpdnpZ05zMrVPssNiEo6JQtea+Qg==}
engines: {node: '>= 18'}
ofetch@1.4.1:
resolution: {integrity: sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==}
@@ -7250,6 +7376,9 @@ packages:
resolution: {integrity: sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==}
engines: {node: '>=8'}
semver-parser@4.1.7:
resolution: {integrity: sha512-RNNvmr1JKZ4Eia7Cyfxtr6aR7eiQs1bPGBv4EC3OJ5pTKEoHjLsT+dY1SSny2tq/uqx9bzNR4lL8tzaB70TN9A==}
semver@6.3.1:
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
hasBin: true
@@ -7685,6 +7814,10 @@ packages:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
toad-cache@3.7.0:
resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==}
engines: {node: '>=12'}
toggle-selection@1.0.6:
resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==}
@@ -7921,6 +8054,12 @@ packages:
resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==}
engines: {node: '>=8'}
universal-github-app-jwt@2.2.0:
resolution: {integrity: sha512-G5o6f95b5BggDGuUfKDApKaCgNYy2x7OdHY0zSMF081O0EJobw+1130VONhrA7ezGSV2FNOGyM+KQpQZAr9bIQ==}
universal-user-agent@7.0.2:
resolution: {integrity: sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q==}
universalify@2.0.1:
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
engines: {node: '>= 10.0.0'}
@@ -9391,6 +9530,152 @@ snapshots:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.17.1
'@octokit/app@15.1.1':
dependencies:
'@octokit/auth-app': 7.1.3
'@octokit/auth-unauthenticated': 6.1.0
'@octokit/core': 6.1.2
'@octokit/oauth-app': 7.1.3
'@octokit/plugin-paginate-rest': 11.3.6(@octokit/core@6.1.2)
'@octokit/types': 13.6.2
'@octokit/webhooks': 13.4.1
'@octokit/auth-app@7.1.3':
dependencies:
'@octokit/auth-oauth-app': 8.1.1
'@octokit/auth-oauth-user': 5.1.1
'@octokit/request': 9.1.3
'@octokit/request-error': 6.1.5
'@octokit/types': 13.6.2
toad-cache: 3.7.0
universal-github-app-jwt: 2.2.0
universal-user-agent: 7.0.2
'@octokit/auth-oauth-app@8.1.1':
dependencies:
'@octokit/auth-oauth-device': 7.1.1
'@octokit/auth-oauth-user': 5.1.1
'@octokit/request': 9.1.3
'@octokit/types': 13.6.2
universal-user-agent: 7.0.2
'@octokit/auth-oauth-device@7.1.1':
dependencies:
'@octokit/oauth-methods': 5.1.2
'@octokit/request': 9.1.3
'@octokit/types': 13.6.2
universal-user-agent: 7.0.2
'@octokit/auth-oauth-user@5.1.1':
dependencies:
'@octokit/auth-oauth-device': 7.1.1
'@octokit/oauth-methods': 5.1.2
'@octokit/request': 9.1.3
'@octokit/types': 13.6.2
universal-user-agent: 7.0.2
'@octokit/auth-token@5.1.1': {}
'@octokit/auth-unauthenticated@6.1.0':
dependencies:
'@octokit/request-error': 6.1.5
'@octokit/types': 13.6.2
'@octokit/core@6.1.2':
dependencies:
'@octokit/auth-token': 5.1.1
'@octokit/graphql': 8.1.1
'@octokit/request': 9.1.3
'@octokit/request-error': 6.1.5
'@octokit/types': 13.6.2
before-after-hook: 3.0.2
universal-user-agent: 7.0.2
'@octokit/endpoint@10.1.1':
dependencies:
'@octokit/types': 13.6.2
universal-user-agent: 7.0.2
'@octokit/graphql@8.1.1':
dependencies:
'@octokit/request': 9.1.3
'@octokit/types': 13.6.2
universal-user-agent: 7.0.2
'@octokit/oauth-app@7.1.3':
dependencies:
'@octokit/auth-oauth-app': 8.1.1
'@octokit/auth-oauth-user': 5.1.1
'@octokit/auth-unauthenticated': 6.1.0
'@octokit/core': 6.1.2
'@octokit/oauth-authorization-url': 7.1.1
'@octokit/oauth-methods': 5.1.2
'@types/aws-lambda': 8.10.146
universal-user-agent: 7.0.2
'@octokit/oauth-authorization-url@7.1.1': {}
'@octokit/oauth-methods@5.1.2':
dependencies:
'@octokit/oauth-authorization-url': 7.1.1
'@octokit/request': 9.1.3
'@octokit/request-error': 6.1.5
'@octokit/types': 13.6.2
'@octokit/openapi-types@22.2.0': {}
'@octokit/openapi-webhooks-types@8.5.1': {}
'@octokit/plugin-paginate-graphql@5.2.4(@octokit/core@6.1.2)':
dependencies:
'@octokit/core': 6.1.2
'@octokit/plugin-paginate-rest@11.3.6(@octokit/core@6.1.2)':
dependencies:
'@octokit/core': 6.1.2
'@octokit/types': 13.6.2
'@octokit/plugin-rest-endpoint-methods@13.2.6(@octokit/core@6.1.2)':
dependencies:
'@octokit/core': 6.1.2
'@octokit/types': 13.6.2
'@octokit/plugin-retry@7.1.2(@octokit/core@6.1.2)':
dependencies:
'@octokit/core': 6.1.2
'@octokit/request-error': 6.1.5
'@octokit/types': 13.6.2
bottleneck: 2.19.5
'@octokit/plugin-throttling@9.3.2(@octokit/core@6.1.2)':
dependencies:
'@octokit/core': 6.1.2
'@octokit/types': 13.6.2
bottleneck: 2.19.5
'@octokit/request-error@6.1.5':
dependencies:
'@octokit/types': 13.6.2
'@octokit/request@9.1.3':
dependencies:
'@octokit/endpoint': 10.1.1
'@octokit/request-error': 6.1.5
'@octokit/types': 13.6.2
universal-user-agent: 7.0.2
'@octokit/types@13.6.2':
dependencies:
'@octokit/openapi-types': 22.2.0
'@octokit/webhooks-methods@5.1.0': {}
'@octokit/webhooks@13.4.1':
dependencies:
'@octokit/openapi-webhooks-types': 8.5.1
'@octokit/request-error': 6.1.5
'@octokit/webhooks-methods': 5.1.0
'@panva/hkdf@1.2.1': {}
'@paralleldrive/cuid2@2.2.2':
@@ -10239,6 +10524,8 @@ snapshots:
dependencies:
'@types/node': 22.10.2
'@types/aws-lambda@8.10.146': {}
'@types/babel__core@7.20.5':
dependencies:
'@babel/parser': 7.26.2
@@ -11020,6 +11307,8 @@ snapshots:
- encoding
- supports-color
before-after-hook@3.0.2: {}
bellajs@11.2.0: {}
better-sqlite3@11.7.0:
@@ -11039,6 +11328,8 @@ snapshots:
inherits: 2.0.4
readable-stream: 3.6.2
bottleneck@2.19.5: {}
boxen@5.1.2:
dependencies:
ansi-align: 3.0.1
@@ -13424,6 +13715,19 @@ snapshots:
define-properties: 1.2.1
es-object-atoms: 1.0.0
octokit@4.0.2:
dependencies:
'@octokit/app': 15.1.1
'@octokit/core': 6.1.2
'@octokit/oauth-app': 7.1.3
'@octokit/plugin-paginate-graphql': 5.2.4(@octokit/core@6.1.2)
'@octokit/plugin-paginate-rest': 11.3.6(@octokit/core@6.1.2)
'@octokit/plugin-rest-endpoint-methods': 13.2.6(@octokit/core@6.1.2)
'@octokit/plugin-retry': 7.1.2(@octokit/core@6.1.2)
'@octokit/plugin-throttling': 9.3.2(@octokit/core@6.1.2)
'@octokit/request-error': 6.1.5
'@octokit/types': 13.6.2
ofetch@1.4.1:
dependencies:
destr: 2.0.3
@@ -14319,6 +14623,8 @@ snapshots:
dependencies:
semver: 6.3.1
semver-parser@4.1.7: {}
semver@6.3.1: {}
semver@7.6.2: {}
@@ -14876,6 +15182,8 @@ snapshots:
dependencies:
is-number: 7.0.0
toad-cache@3.7.0: {}
toggle-selection@1.0.6: {}
toidentifier@1.0.1: {}
@@ -15114,6 +15422,10 @@ snapshots:
dependencies:
crypto-random-string: 2.0.0
universal-github-app-jwt@2.2.0: {}
universal-user-agent@7.0.2: {}
universalify@2.0.1: {}
unpipe@1.0.0: {}