diff --git a/apps/nextjs/next.config.ts b/apps/nextjs/next.config.ts index 5a082309c..53148f725 100644 --- a/apps/nextjs/next.config.ts +++ b/apps/nextjs/next.config.ts @@ -2,6 +2,7 @@ import "@homarr/auth/env"; import "@homarr/db/env"; import "@homarr/common/env"; +import "@homarr/docker/env"; import type { NextConfig } from "next"; import MillionLint from "@million/lint"; diff --git a/apps/nextjs/package.json b/apps/nextjs/package.json index 43651d5fd..4ac217d27 100644 --- a/apps/nextjs/package.json +++ b/apps/nextjs/package.json @@ -23,6 +23,7 @@ "@homarr/cron-job-status": "workspace:^0.1.0", "@homarr/db": "workspace:^0.1.0", "@homarr/definitions": "workspace:^0.1.0", + "@homarr/docker": "workspace:^0.1.0", "@homarr/form": "workspace:^0.1.0", "@homarr/gridstack": "^1.12.0", "@homarr/icons": "workspace:^0.1.0", diff --git a/apps/nextjs/src/app/[locale]/manage/tools/docker/docker-table.tsx b/apps/nextjs/src/app/[locale]/manage/tools/docker/docker-table.tsx index 5398aaff3..b3d8663d2 100644 --- a/apps/nextjs/src/app/[locale]/manage/tools/docker/docker-table.tsx +++ b/apps/nextjs/src/app/[locale]/manage/tools/docker/docker-table.tsx @@ -16,7 +16,7 @@ import { MantineReactTable } from "mantine-react-table"; import type { RouterOutputs } from "@homarr/api"; import { clientApi } from "@homarr/api/client"; import { useTimeAgo } from "@homarr/common"; -import type { DockerContainerState } from "@homarr/definitions"; +import type { ContainerState } from "@homarr/docker"; import { useModalAction } from "@homarr/modals"; import { AddDockerAppToHomarr } from "@homarr/modals-collection"; import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; @@ -246,9 +246,9 @@ const containerStates = { exited: "red", removing: "pink", dead: "dark", -} satisfies Record; +} satisfies Record; -const ContainerStateBadge = ({ state }: { state: DockerContainerState }) => { +const ContainerStateBadge = ({ state }: { state: ContainerState }) => { const t = useScopedI18n("docker.field.state.option"); return ( diff --git a/apps/nextjs/src/env.ts b/apps/nextjs/src/env.ts index 91787c8bb..f3e419641 100644 --- a/apps/nextjs/src/env.ts +++ b/apps/nextjs/src/env.ts @@ -12,11 +12,7 @@ export const env = createEnv({ * Specify your server-side environment variables schema here. This way you can ensure the app isn't * built with invalid env vars. */ - server: { - // Comma separated list of docker hostnames that can be used to connect to query the docker endpoints (localhost:2375,host.docker.internal:2375, ...) - DOCKER_HOSTNAMES: z.string().optional(), - DOCKER_PORTS: z.string().optional(), - }, + server: {}, /** * Specify your client-side environment variables schema here. * For them to be exposed to the client, prefix them with `NEXT_PUBLIC_`. @@ -30,8 +26,6 @@ export const env = createEnv({ runtimeEnv: { PORT: process.env.PORT, NODE_ENV: process.env.NODE_ENV, - DOCKER_HOSTNAMES: process.env.DOCKER_HOSTNAMES, - DOCKER_PORTS: process.env.DOCKER_PORTS, // NEXT_PUBLIC_CLIENTVAR: process.env.NEXT_PUBLIC_CLIENTVAR, }, skipValidation: shouldSkipEnvValidation(), diff --git a/packages/api/package.json b/packages/api/package.json index 0c46010ff..dcbfc6b7d 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -29,6 +29,7 @@ "@homarr/cron-jobs": "workspace:^0.1.0", "@homarr/db": "workspace:^0.1.0", "@homarr/definitions": "workspace:^0.1.0", + "@homarr/docker": "workspace:^0.1.0", "@homarr/icons": "workspace:^0.1.0", "@homarr/integrations": "workspace:^0.1.0", "@homarr/log": "workspace:^", @@ -42,7 +43,6 @@ "@trpc/client": "next", "@trpc/react-query": "next", "@trpc/server": "next", - "dockerode": "4.0.2", "lodash.clonedeep": "^4.5.0", "next": "15.1.6", "react": "19.0.0", @@ -54,7 +54,6 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "@types/dockerode": "^3.3.34", "eslint": "^9.18.0", "prettier": "^3.4.2", "typescript": "^5.7.3" diff --git a/packages/api/src/router/docker/docker-router.ts b/packages/api/src/router/docker/docker-router.ts index 6a8b99a1f..299db0090 100644 --- a/packages/api/src/router/docker/docker-router.ts +++ b/packages/api/src/router/docker/docker-router.ts @@ -1,26 +1,24 @@ import { TRPCError } from "@trpc/server"; -import type Docker from "dockerode"; -import type { Container } from "dockerode"; import { db, like, or } from "@homarr/db"; import { icons } from "@homarr/db/schema"; -import type { DockerContainerState } from "@homarr/definitions"; +import { DockerSingleton } from "@homarr/docker"; +import type { Container, ContainerInfo, ContainerState, Docker, Port } from "@homarr/docker"; import { logger } from "@homarr/log"; import { createCacheChannel } from "@homarr/redis"; import { z } from "@homarr/validation"; import { createTRPCRouter, permissionRequiredProcedure } from "../../trpc"; -import { DockerSingleton } from "./docker-singleton"; const dockerCache = createCacheChannel<{ - containers: (Docker.ContainerInfo & { instance: string; iconUrl: string | null })[]; + containers: (ContainerInfo & { instance: string; iconUrl: string | null })[]; }>("docker-containers", 5 * 60 * 1000); export const dockerRouter = createTRPCRouter({ getContainers: permissionRequiredProcedure.requiresPermission("admin").query(async () => { const result = await dockerCache .consumeAsync(async () => { - const dockerInstances = DockerSingleton.getInstance(); + const dockerInstances = DockerSingleton.getInstances(); const containers = await Promise.all( // Return all the containers of all the instances into only one item dockerInstances.map(({ instance, host: key }) => @@ -33,8 +31,7 @@ export const dockerRouter = createTRPCRouter({ ), ).then((containers) => containers.flat()); - const extractImage = (container: Docker.ContainerInfo) => - container.Image.split("/").at(-1)?.split(":").at(0) ?? ""; + const extractImage = (container: ContainerInfo) => container.Image.split("/").at(-1)?.split(":").at(0) ?? ""; const likeQueries = containers.map((container) => like(icons.name, `%${extractImage(container)}%`)); const dbIcons = likeQueries.length >= 1 @@ -151,7 +148,7 @@ const getContainerOrDefaultAsync = async (instance: Docker, id: string) => { }; const getContainerOrThrowAsync = async (id: string) => { - const dockerInstances = DockerSingleton.getInstance(); + const dockerInstances = DockerSingleton.getInstances(); const containers = await Promise.all(dockerInstances.map(({ instance }) => getContainerOrDefaultAsync(instance, id))); const foundContainer = containers.find((container) => container) ?? null; @@ -168,21 +165,21 @@ const getContainerOrThrowAsync = async (id: string) => { interface DockerContainer { name: string; id: string; - state: DockerContainerState; + state: ContainerState; image: string; - ports: Docker.Port[]; + ports: Port[]; iconUrl: string | null; } function sanitizeContainers( - containers: (Docker.ContainerInfo & { instance: string; iconUrl: string | null })[], + containers: (ContainerInfo & { instance: string; iconUrl: string | null })[], ): DockerContainer[] { return containers.map((container) => { return { name: container.Names[0]?.split("/")[1] ?? "Unknown", id: container.Id, instance: container.instance, - state: container.State as DockerContainerState, + state: container.State as ContainerState, image: container.Image, ports: container.Ports, iconUrl: container.iconUrl, diff --git a/packages/api/src/router/docker/docker-singleton.ts b/packages/api/src/router/docker/docker-singleton.ts deleted file mode 100644 index f95a58418..000000000 --- a/packages/api/src/router/docker/docker-singleton.ts +++ /dev/null @@ -1,51 +0,0 @@ -import Docker from "dockerode"; - -interface DockerInstance { - host: string; - instance: Docker; -} - -export class DockerSingleton { - private static instances: DockerInstance[]; - - private createInstances() { - const instances: DockerInstance[] = []; - const hostVariable = process.env.DOCKER_HOST; - const portVariable = process.env.DOCKER_PORT; - if (hostVariable === undefined || portVariable === undefined) { - instances.push({ host: "socket", instance: new Docker() }); - return instances; - } - const hosts = hostVariable.split(","); - const ports = portVariable.split(","); - - if (hosts.length !== ports.length) { - throw new Error("The number of hosts and ports must match"); - } - - hosts.forEach((host, i) => { - instances.push({ - host: `${host}:${ports[i]}`, - instance: new Docker({ - host, - port: parseInt(ports[i] ?? "", 10), - }), - }); - return instances; - }); - return instances; - } - - public static findInstance(key: string): DockerInstance | undefined { - return this.instances.find((instance) => instance.host === key); - } - - public static getInstance(): DockerInstance[] { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - if (!DockerSingleton.instances) { - DockerSingleton.instances = new DockerSingleton().createInstances(); - } - - return this.instances; - } -} diff --git a/packages/docker/eslint.config.js b/packages/docker/eslint.config.js new file mode 100644 index 000000000..5b19b6f8a --- /dev/null +++ b/packages/docker/eslint.config.js @@ -0,0 +1,9 @@ +import baseConfig from "@homarr/eslint-config/base"; + +/** @type {import('typescript-eslint').Config} */ +export default [ + { + ignores: [], + }, + ...baseConfig, +]; diff --git a/packages/docker/index.ts b/packages/docker/index.ts new file mode 100644 index 000000000..3bd16e178 --- /dev/null +++ b/packages/docker/index.ts @@ -0,0 +1 @@ +export * from "./src"; diff --git a/packages/docker/package.json b/packages/docker/package.json new file mode 100644 index 000000000..a82c1719e --- /dev/null +++ b/packages/docker/package.json @@ -0,0 +1,38 @@ +{ + "name": "@homarr/docker", + "version": "0.1.0", + "private": true, + "license": "MIT", + "type": "module", + "exports": { + ".": "./index.ts", + "./env": "./src/env.ts" + }, + "typesVersions": { + "*": { + "*": [ + "src/*" + ] + } + }, + "scripts": { + "clean": "rm -rf .turbo node_modules", + "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", + "typecheck": "tsc --noEmit" + }, + "prettier": "@homarr/prettier-config", + "dependencies": { + "@homarr/common": "workspace:^0.1.0", + "@t3-oss/env-nextjs": "^0.11.1", + "dockerode": "^4.0.4" + }, + "devDependencies": { + "@homarr/eslint-config": "workspace:^0.2.0", + "@homarr/prettier-config": "workspace:^0.1.0", + "@homarr/tsconfig": "workspace:^0.1.0", + "@types/dockerode": "^3.3.34", + "eslint": "^9.18.0", + "typescript": "^5.7.3" + } +} diff --git a/packages/docker/src/env.ts b/packages/docker/src/env.ts new file mode 100644 index 000000000..0f4984961 --- /dev/null +++ b/packages/docker/src/env.ts @@ -0,0 +1,18 @@ +import { createEnv } from "@t3-oss/env-nextjs"; +import { z } from "zod"; + +import { shouldSkipEnvValidation } from "@homarr/common/env-validation"; + +export const env = createEnv({ + server: { + // Comma separated list of docker hostnames that can be used to connect to query the docker endpoints (localhost:2375,host.docker.internal:2375, ...) + DOCKER_HOSTNAMES: z.string().optional(), + DOCKER_PORTS: z.string().optional(), + }, + runtimeEnv: { + DOCKER_HOSTNAMES: process.env.DOCKER_HOSTNAMES, + DOCKER_PORTS: process.env.DOCKER_PORTS, + }, + skipValidation: shouldSkipEnvValidation(), + emptyStringAsUndefined: true, +}); diff --git a/packages/docker/src/index.ts b/packages/docker/src/index.ts new file mode 100644 index 000000000..131507d6a --- /dev/null +++ b/packages/docker/src/index.ts @@ -0,0 +1,10 @@ +import type Docker from "dockerode"; + +export type { DockerInstance } from "./singleton"; +export { DockerSingleton } from "./singleton"; +export type { ContainerInfo, Container, Port } from "dockerode"; +export type { Docker }; + +export const containerStates = ["created", "running", "paused", "restarting", "exited", "removing", "dead"] as const; + +export type ContainerState = (typeof containerStates)[number]; diff --git a/packages/docker/src/singleton.ts b/packages/docker/src/singleton.ts new file mode 100644 index 000000000..86ce9661e --- /dev/null +++ b/packages/docker/src/singleton.ts @@ -0,0 +1,53 @@ +import Docker from "dockerode"; + +import { env } from "./env"; + +export interface DockerInstance { + host: string; + instance: Docker; +} + +export class DockerSingleton { + private static instances: DockerInstance[] | null = null; + + private createInstances() { + const hostVariable = env.DOCKER_HOSTNAMES; + const portVariable = env.DOCKER_PORTS; + if (hostVariable === undefined || portVariable === undefined) { + return [{ host: "socket", instance: new Docker() }]; + } + const hostnames = hostVariable.split(","); + const ports = portVariable.split(","); + + if (hostnames.length !== ports.length) { + throw new Error("The number of hosts and ports must match"); + } + + return hostnames.map((host, i) => { + // Check above ensures that ports[i] is not undefined + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const port = ports[i]!; + + return { + host: `${host}:${port}`, + instance: new Docker({ + host, + port: parseInt(port, 10), + }), + }; + }); + } + + public static findInstance(host: string): DockerInstance | undefined { + return this.instances?.find((instance) => instance.host === host); + } + + public static getInstances(): DockerInstance[] { + if (this.instances) { + return this.instances; + } + + this.instances = new DockerSingleton().createInstances(); + return this.instances; + } +} diff --git a/packages/docker/tsconfig.json b/packages/docker/tsconfig.json new file mode 100644 index 000000000..cbe8483d9 --- /dev/null +++ b/packages/docker/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@homarr/tsconfig/base.json", + "compilerOptions": { + "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json" + }, + "include": ["*.ts", "src"], + "exclude": ["node_modules"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c7a0bba81..4de2636e0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -106,6 +106,9 @@ importers: '@homarr/definitions': specifier: workspace:^0.1.0 version: link:../../packages/definitions + '@homarr/docker': + specifier: workspace:^0.1.0 + version: link:../../packages/docker '@homarr/form': specifier: workspace:^0.1.0 version: link:../../packages/form @@ -521,6 +524,9 @@ importers: '@homarr/definitions': specifier: workspace:^0.1.0 version: link:../definitions + '@homarr/docker': + specifier: workspace:^0.1.0 + version: link:../docker '@homarr/icons': specifier: workspace:^0.1.0 version: link:../icons @@ -560,9 +566,6 @@ importers: '@trpc/server': specifier: next version: 11.0.0-rc.711(typescript@5.7.3) - dockerode: - specifier: 4.0.2 - version: 4.0.2 lodash.clonedeep: specifier: ^4.5.0 version: 4.5.0 @@ -591,9 +594,6 @@ importers: '@homarr/tsconfig': specifier: workspace:^0.1.0 version: link:../../tooling/typescript - '@types/dockerode': - specifier: ^3.3.34 - version: 3.3.34 eslint: specifier: ^9.18.0 version: 9.18.0 @@ -1022,6 +1022,37 @@ importers: specifier: ^5.7.3 version: 5.7.3 + packages/docker: + dependencies: + '@homarr/common': + specifier: workspace:^0.1.0 + version: link:../common + '@t3-oss/env-nextjs': + specifier: ^0.11.1 + version: 0.11.1(typescript@5.7.3)(zod@3.24.1) + dockerode: + specifier: ^4.0.4 + version: 4.0.4 + devDependencies: + '@homarr/eslint-config': + specifier: workspace:^0.2.0 + version: link:../../tooling/eslint + '@homarr/prettier-config': + specifier: workspace:^0.1.0 + version: link:../../tooling/prettier + '@homarr/tsconfig': + specifier: workspace:^0.1.0 + version: link:../../tooling/typescript + '@types/dockerode': + specifier: ^3.3.34 + version: 3.3.34 + eslint: + specifier: ^9.18.0 + version: 9.18.0 + typescript: + specifier: ^5.7.3 + version: 5.7.3 + packages/form: dependencies: '@homarr/common': @@ -3000,6 +3031,15 @@ packages: '@formatjs/intl-localematcher@0.5.5': resolution: {integrity: sha512-t5tOGMgZ/i5+ALl2/offNqAQq/lfUnKLEw0mXQI4N4bqpedhrSE+fyKLpwnd22sK0dif6AV+ufQcTsKShB9J1g==} + '@grpc/grpc-js@1.12.5': + resolution: {integrity: sha512-d3iiHxdpg5+ZcJ6jnDSOT8Z0O0VMVGy34jAnYLUX8yd36b1qn8f1TwOA/Lc7TsOh03IkPJ38eGI5qD2EjNkoEA==} + engines: {node: '>=12.10.0'} + + '@grpc/proto-loader@0.7.13': + resolution: {integrity: sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==} + engines: {node: '>=6'} + hasBin: true + '@hapi/bourne@3.0.0': resolution: {integrity: sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w==} @@ -3186,6 +3226,9 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@js-sdsl/ordered-map@4.4.2': + resolution: {integrity: sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==} + '@libsql/client-wasm@0.14.0': resolution: {integrity: sha512-gB/jtz0xuwrqAHApBv9e9JSew2030Fhj2edyZ83InZ4yPj/Q2LTUlEhaspEYT0T0xsAGqPy38uGrmq/OGS+DdQ==} bundledDependencies: @@ -3614,6 +3657,36 @@ packages: '@popperjs/core@2.11.8': resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + + '@protobufjs/codegen@2.0.4': + resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} + + '@protobufjs/eventemitter@1.1.0': + resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} + + '@protobufjs/fetch@1.1.0': + resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@protobufjs/inquire@1.1.0': + resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} + + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + + '@protobufjs/utf8@1.1.0': + resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + '@remirror/core-constants@3.0.0': resolution: {integrity: sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==} @@ -5490,16 +5563,16 @@ packages: resolution: {integrity: sha512-f0ReSURdM3pcKPNS30mxOHSbaFLcknGmQjwSfmbcdOw1XWKXVhukM3NJHhr7NpY9BIyyWQb0EBo3KQvvuU5egQ==} engines: {node: '>= 8.0'} - docker-modem@5.0.5: - resolution: {integrity: sha512-Cxw8uEcvNTRmsQuGqzzfiCnfGgf96tVJItLh8taOX0miTcIBALKH5TckCSuZbpbjP7uhAl81dOL9sxfa6HgCIg==} + docker-modem@5.0.6: + resolution: {integrity: sha512-ens7BiayssQz/uAxGzH8zGXCtiV24rRWXdjNha5V4zSOcxmAZsfGVm/PPFbwQdqEkDnhG+SyR9E3zSHUbOKXBQ==} engines: {node: '>= 8.0'} dockerode@3.3.5: resolution: {integrity: sha512-/0YNa3ZDNeLr/tSckmD69+Gq+qVNhvKfAHNeZJBnp7EOP6RGKV8ORrJHkUn20So5wU+xxT7+1n5u8PjHbfjbSA==} engines: {node: '>= 8.0'} - dockerode@4.0.2: - resolution: {integrity: sha512-9wM1BVpVMFr2Pw3eJNXrYYt6DT9k0xMcsSCjtPvyQ+xa1iPg/Mo3T/gUcwI0B2cczqCeCYRPF8yFYDwtFXT0+w==} + dockerode@4.0.4: + resolution: {integrity: sha512-6GYP/EdzEY50HaOxTVTJ2p+mB5xDHTMJhS+UoGrVyS6VC+iQRh7kZ4FRpUYq6nziby7hPqWhOrFFUFTMUZJJ5w==} engines: {node: '>= 8.0'} doctrine@2.1.0: @@ -7001,6 +7074,9 @@ packages: lodash-es@4.17.21: resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + lodash.camelcase@4.3.0: + resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + lodash.capitalize@4.2.1: resolution: {integrity: sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw==} @@ -8044,6 +8120,10 @@ packages: proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + protobufjs@7.4.0: + resolution: {integrity: sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==} + engines: {node: '>=12.0.0'} + proxmox-api@1.1.1: resolution: {integrity: sha512-2qH7pxKBBHa7WtEBmxPaBY2FZEH2R04hqr9zD9PmErLzJ7RGGcfNcXoS/v5G4vBM2Igmnx0EAYBstPwwfDwHnA==} @@ -9431,6 +9511,10 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + uuid@10.0.0: + resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} + hasBin: true + uuid@11.0.4: resolution: {integrity: sha512-IzL6VtTTYcAhA/oghbFJ1Dkmqev+FpQWnCBaKq/gUluLxliWvO8DPFWfIviRmYbtaavtSQe4WBL++rFjdcGWEg==} hasBin: true @@ -10557,6 +10641,18 @@ snapshots: dependencies: tslib: 2.7.0 + '@grpc/grpc-js@1.12.5': + dependencies: + '@grpc/proto-loader': 0.7.13 + '@js-sdsl/ordered-map': 4.4.2 + + '@grpc/proto-loader@0.7.13': + dependencies: + lodash.camelcase: 4.3.0 + long: 5.2.3 + protobufjs: 7.4.0 + yargs: 17.7.2 + '@hapi/bourne@3.0.0': {} '@homarr/gridstack@1.12.0': {} @@ -10708,6 +10804,8 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 + '@js-sdsl/ordered-map@4.4.2': {} + '@libsql/client-wasm@0.14.0': dependencies: '@libsql/core': 0.14.0 @@ -11200,6 +11298,29 @@ snapshots: '@popperjs/core@2.11.8': {} + '@protobufjs/aspromise@1.1.2': {} + + '@protobufjs/base64@1.1.2': {} + + '@protobufjs/codegen@2.0.4': {} + + '@protobufjs/eventemitter@1.1.0': {} + + '@protobufjs/fetch@1.1.0': + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/inquire': 1.1.0 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/inquire@1.1.0': {} + + '@protobufjs/path@1.1.2': {} + + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.0': {} + '@remirror/core-constants@3.0.0': {} '@rollup/pluginutils@5.1.0(rollup@4.21.3)': @@ -13521,7 +13642,7 @@ snapshots: transitivePeerDependencies: - supports-color - docker-modem@5.0.5: + docker-modem@5.0.6: dependencies: debug: 4.4.0 readable-stream: 3.6.2 @@ -13538,11 +13659,15 @@ snapshots: transitivePeerDependencies: - supports-color - dockerode@4.0.2: + dockerode@4.0.4: dependencies: '@balena/dockerignore': 1.0.2 - docker-modem: 5.0.5 + '@grpc/grpc-js': 1.12.5 + '@grpc/proto-loader': 0.7.13 + docker-modem: 5.0.6 + protobufjs: 7.4.0 tar-fs: 2.0.1 + uuid: 10.0.0 transitivePeerDependencies: - supports-color @@ -15330,6 +15455,8 @@ snapshots: lodash-es@4.17.21: {} + lodash.camelcase@4.3.0: {} + lodash.capitalize@4.2.1: {} lodash.clonedeep@4.5.0: {} @@ -16336,6 +16463,21 @@ snapshots: proto-list@1.2.4: {} + protobufjs@7.4.0: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.4 + '@protobufjs/eventemitter': 1.1.0 + '@protobufjs/fetch': 1.1.0 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.0 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.0 + '@types/node': 22.10.7 + long: 5.2.3 + proxmox-api@1.1.1: dependencies: undici: 7.3.0 @@ -17987,6 +18129,8 @@ snapshots: util-deprecate@1.0.2: {} + uuid@10.0.0: {} + uuid@11.0.4: {} uuid@8.3.2: {} diff --git a/turbo/generators/templates/package.json.hbs b/turbo/generators/templates/package.json.hbs index b8fda8d8e..e288ab93c 100644 --- a/turbo/generators/templates/package.json.hbs +++ b/turbo/generators/templates/package.json.hbs @@ -24,8 +24,8 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.15.0", - "typescript": "^5.6.3" + "eslint": "^9.18.0", + "typescript": "^5.7.3" }, "prettier": "@homarr/prettier-config" } \ No newline at end of file