feat(logging): add log level env variable (#2299)
This commit is contained in:
@@ -12,6 +12,8 @@ AUTH_SECRET="supersecret"
|
|||||||
# or starting the project without any (which will show a randomly generated one).
|
# or starting the project without any (which will show a randomly generated one).
|
||||||
SECRET_ENCRYPTION_KEY=0000000000000000000000000000000000000000000000000000000000000000
|
SECRET_ENCRYPTION_KEY=0000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
|
||||||
|
LOG_LEVEL='info'
|
||||||
|
|
||||||
# This is how you can use the sqlite driver:
|
# This is how you can use the sqlite driver:
|
||||||
DB_DRIVER='better-sqlite3'
|
DB_DRIVER='better-sqlite3'
|
||||||
DB_URL='FULL_PATH_TO_YOUR_SQLITE_DB_FILE'
|
DB_URL='FULL_PATH_TO_YOUR_SQLITE_DB_FILE'
|
||||||
|
|||||||
@@ -2,14 +2,13 @@
|
|||||||
import "@homarr/auth/env";
|
import "@homarr/auth/env";
|
||||||
import "@homarr/db/env";
|
import "@homarr/db/env";
|
||||||
import "@homarr/common/env";
|
import "@homarr/common/env";
|
||||||
|
import "@homarr/log/env";
|
||||||
import "@homarr/docker/env";
|
import "@homarr/docker/env";
|
||||||
|
|
||||||
import type { NextConfig } from "next";
|
import type { NextConfig } from "next";
|
||||||
import MillionLint from "@million/lint";
|
import MillionLint from "@million/lint";
|
||||||
import createNextIntlPlugin from "next-intl/plugin";
|
import createNextIntlPlugin from "next-intl/plugin";
|
||||||
|
|
||||||
import "./src/env.ts";
|
|
||||||
|
|
||||||
// Package path does not work... so we need to use relative path
|
// Package path does not work... so we need to use relative path
|
||||||
const withNextIntl = createNextIntlPlugin("../../packages/translation/src/request.ts");
|
const withNextIntl = createNextIntlPlugin("../../packages/translation/src/request.ts");
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,6 @@
|
|||||||
"@mantine/modals": "^7.17.0",
|
"@mantine/modals": "^7.17.0",
|
||||||
"@mantine/tiptap": "^7.17.0",
|
"@mantine/tiptap": "^7.17.0",
|
||||||
"@million/lint": "1.0.14",
|
"@million/lint": "1.0.14",
|
||||||
"@t3-oss/env-nextjs": "^0.12.0",
|
|
||||||
"@tabler/icons-react": "^3.30.0",
|
"@tabler/icons-react": "^3.30.0",
|
||||||
"@tanstack/react-query": "^5.66.7",
|
"@tanstack/react-query": "^5.66.7",
|
||||||
"@tanstack/react-query-devtools": "^5.66.7",
|
"@tanstack/react-query-devtools": "^5.66.7",
|
||||||
|
|||||||
@@ -20,8 +20,7 @@ import type { SuperJSONResult } from "superjson";
|
|||||||
import type { AppRouter } from "@homarr/api";
|
import type { AppRouter } from "@homarr/api";
|
||||||
import { clientApi } from "@homarr/api/client";
|
import { clientApi } from "@homarr/api/client";
|
||||||
import { createHeadersCallbackForSource, getTrpcUrl } from "@homarr/api/shared";
|
import { createHeadersCallbackForSource, getTrpcUrl } from "@homarr/api/shared";
|
||||||
|
import { env } from "@homarr/common/env";
|
||||||
import { env } from "~/env";
|
|
||||||
|
|
||||||
const getWebSocketProtocol = () => {
|
const getWebSocketProtocol = () => {
|
||||||
// window is not defined on server side
|
// window is not defined on server side
|
||||||
@@ -66,7 +65,7 @@ export function TRPCReactProvider(props: PropsWithChildren) {
|
|||||||
links: [
|
links: [
|
||||||
loggerLink({
|
loggerLink({
|
||||||
enabled: (opts) =>
|
enabled: (opts) =>
|
||||||
process.env.NODE_ENV === "development" || (opts.direction === "down" && opts.result instanceof Error),
|
env.NODE_ENV === "development" || (opts.direction === "down" && opts.result instanceof Error),
|
||||||
}),
|
}),
|
||||||
splitLink({
|
splitLink({
|
||||||
condition: ({ type }) => type === "subscription",
|
condition: ({ type }) => type === "subscription",
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import { clientApi } from "@homarr/api/client";
|
|||||||
import { useRequiredBoard } from "@homarr/boards/context";
|
import { useRequiredBoard } from "@homarr/boards/context";
|
||||||
import { useEditMode } from "@homarr/boards/edit-mode";
|
import { useEditMode } from "@homarr/boards/edit-mode";
|
||||||
import { revalidatePathActionAsync } from "@homarr/common/client";
|
import { revalidatePathActionAsync } from "@homarr/common/client";
|
||||||
|
import { env } from "@homarr/common/env";
|
||||||
import { useConfirmModal, useModalAction } from "@homarr/modals";
|
import { useConfirmModal, useModalAction } from "@homarr/modals";
|
||||||
import { showErrorNotification, showSuccessNotification } from "@homarr/notifications";
|
import { showErrorNotification, showSuccessNotification } from "@homarr/notifications";
|
||||||
import { useI18n, useScopedI18n } from "@homarr/translation/client";
|
import { useI18n, useScopedI18n } from "@homarr/translation/client";
|
||||||
@@ -33,7 +34,6 @@ import { useCategoryActions } from "~/components/board/sections/category/categor
|
|||||||
import { CategoryEditModal } from "~/components/board/sections/category/category-edit-modal";
|
import { CategoryEditModal } from "~/components/board/sections/category/category-edit-modal";
|
||||||
import { useDynamicSectionActions } from "~/components/board/sections/dynamic/dynamic-actions";
|
import { useDynamicSectionActions } from "~/components/board/sections/dynamic/dynamic-actions";
|
||||||
import { HeaderButton } from "~/components/layout/header/button";
|
import { HeaderButton } from "~/components/layout/header/button";
|
||||||
import { env } from "~/env";
|
|
||||||
|
|
||||||
export const BoardContentHeaderActions = () => {
|
export const BoardContentHeaderActions = () => {
|
||||||
const [isEditMode] = useEditMode();
|
const [isEditMode] = useEditMode();
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
import { Center } from "@mantine/core";
|
import { Center } from "@mantine/core";
|
||||||
|
|
||||||
|
import { env } from "@homarr/common/env";
|
||||||
import { db } from "@homarr/db";
|
import { db } from "@homarr/db";
|
||||||
import type { WidgetKind } from "@homarr/definitions";
|
import type { WidgetKind } from "@homarr/definitions";
|
||||||
import { widgetImports } from "@homarr/widgets";
|
import { widgetImports } from "@homarr/widgets";
|
||||||
|
|
||||||
import { env } from "~/env";
|
|
||||||
import { WidgetPreviewPageContent } from "./_content";
|
import { WidgetPreviewPageContent } from "./_content";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
import { createEnv } from "@t3-oss/env-nextjs";
|
|
||||||
import { z } from "zod";
|
|
||||||
|
|
||||||
import { shouldSkipEnvValidation } from "@homarr/common/env-validation";
|
|
||||||
|
|
||||||
export const env = createEnv({
|
|
||||||
shared: {
|
|
||||||
PORT: z.coerce.number().default(3000),
|
|
||||||
NODE_ENV: z.enum(["development", "production", "test"]).default("development"),
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Specify your server-side environment variables schema here. This way you can ensure the app isn't
|
|
||||||
* built with invalid env vars.
|
|
||||||
*/
|
|
||||||
server: {},
|
|
||||||
/**
|
|
||||||
* Specify your client-side environment variables schema here.
|
|
||||||
* For them to be exposed to the client, prefix them with `NEXT_PUBLIC_`.
|
|
||||||
*/
|
|
||||||
client: {
|
|
||||||
// NEXT_PUBLIC_CLIENTVAR: z.string(),
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Destructure all variables from `process.env` to make sure they aren't tree-shaken away.
|
|
||||||
*/
|
|
||||||
runtimeEnv: {
|
|
||||||
PORT: process.env.PORT,
|
|
||||||
NODE_ENV: process.env.NODE_ENV,
|
|
||||||
// NEXT_PUBLIC_CLIENTVAR: process.env.NEXT_PUBLIC_CLIENTVAR,
|
|
||||||
},
|
|
||||||
skipValidation: shouldSkipEnvValidation(),
|
|
||||||
emptyStringAsUndefined: true,
|
|
||||||
});
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import { createEnv } from "@t3-oss/env-nextjs";
|
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { createBooleanSchema, createDurationSchema, shouldSkipEnvValidation } from "@homarr/common/env-validation";
|
|
||||||
import { supportedAuthProviders } from "@homarr/definitions";
|
import { supportedAuthProviders } from "@homarr/definitions";
|
||||||
|
import { createEnv } from "@homarr/env";
|
||||||
|
import { createBooleanSchema, createDurationSchema } from "@homarr/env/schemas";
|
||||||
|
|
||||||
const authProvidersSchema = z
|
const authProvidersSchema = z
|
||||||
.string()
|
.string()
|
||||||
@@ -22,8 +22,7 @@ const authProvidersSchema = z
|
|||||||
)
|
)
|
||||||
.default("credentials");
|
.default("credentials");
|
||||||
|
|
||||||
const skipValidation = shouldSkipEnvValidation();
|
const authProviders = authProvidersSchema.safeParse(process.env.AUTH_PROVIDERS).data ?? [];
|
||||||
const authProviders = skipValidation ? [] : authProvidersSchema.parse(process.env.AUTH_PROVIDERS);
|
|
||||||
|
|
||||||
export const env = createEnv({
|
export const env = createEnv({
|
||||||
server: {
|
server: {
|
||||||
@@ -59,32 +58,5 @@ export const env = createEnv({
|
|||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
},
|
},
|
||||||
client: {},
|
experimental__runtimeEnv: process.env,
|
||||||
runtimeEnv: {
|
|
||||||
AUTH_LOGOUT_REDIRECT_URL: process.env.AUTH_LOGOUT_REDIRECT_URL,
|
|
||||||
AUTH_SESSION_EXPIRY_TIME: process.env.AUTH_SESSION_EXPIRY_TIME,
|
|
||||||
AUTH_PROVIDERS: process.env.AUTH_PROVIDERS,
|
|
||||||
AUTH_LDAP_BASE: process.env.AUTH_LDAP_BASE,
|
|
||||||
AUTH_LDAP_BIND_DN: process.env.AUTH_LDAP_BIND_DN,
|
|
||||||
AUTH_LDAP_BIND_PASSWORD: process.env.AUTH_LDAP_BIND_PASSWORD,
|
|
||||||
AUTH_LDAP_GROUP_CLASS: process.env.AUTH_LDAP_GROUP_CLASS,
|
|
||||||
AUTH_LDAP_GROUP_FILTER_EXTRA_ARG: process.env.AUTH_LDAP_GROUP_FILTER_EXTRA_ARG,
|
|
||||||
AUTH_LDAP_GROUP_MEMBER_ATTRIBUTE: process.env.AUTH_LDAP_GROUP_MEMBER_ATTRIBUTE,
|
|
||||||
AUTH_LDAP_GROUP_MEMBER_USER_ATTRIBUTE: process.env.AUTH_LDAP_GROUP_MEMBER_USER_ATTRIBUTE,
|
|
||||||
AUTH_LDAP_SEARCH_SCOPE: process.env.AUTH_LDAP_SEARCH_SCOPE,
|
|
||||||
AUTH_LDAP_URI: process.env.AUTH_LDAP_URI,
|
|
||||||
AUTH_OIDC_CLIENT_ID: process.env.AUTH_OIDC_CLIENT_ID,
|
|
||||||
AUTH_OIDC_CLIENT_NAME: process.env.AUTH_OIDC_CLIENT_NAME,
|
|
||||||
AUTH_OIDC_CLIENT_SECRET: process.env.AUTH_OIDC_CLIENT_SECRET,
|
|
||||||
AUTH_OIDC_ISSUER: process.env.AUTH_OIDC_ISSUER,
|
|
||||||
AUTH_OIDC_SCOPE_OVERWRITE: process.env.AUTH_OIDC_SCOPE_OVERWRITE,
|
|
||||||
AUTH_OIDC_GROUPS_ATTRIBUTE: process.env.AUTH_OIDC_GROUPS_ATTRIBUTE,
|
|
||||||
AUTH_LDAP_USERNAME_ATTRIBUTE: process.env.AUTH_LDAP_USERNAME_ATTRIBUTE,
|
|
||||||
AUTH_LDAP_USER_MAIL_ATTRIBUTE: process.env.AUTH_LDAP_USER_MAIL_ATTRIBUTE,
|
|
||||||
AUTH_LDAP_USERNAME_FILTER_EXTRA_ARG: process.env.AUTH_LDAP_USERNAME_FILTER_EXTRA_ARG,
|
|
||||||
AUTH_OIDC_AUTO_LOGIN: process.env.AUTH_OIDC_AUTO_LOGIN,
|
|
||||||
AUTH_OIDC_NAME_ATTRIBUTE_OVERWRITE: process.env.AUTH_OIDC_NAME_ATTRIBUTE_OVERWRITE,
|
|
||||||
},
|
|
||||||
skipValidation,
|
|
||||||
emptyStringAsUndefined: true,
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -28,9 +28,9 @@
|
|||||||
"@homarr/common": "workspace:^0.1.0",
|
"@homarr/common": "workspace:^0.1.0",
|
||||||
"@homarr/db": "workspace:^0.1.0",
|
"@homarr/db": "workspace:^0.1.0",
|
||||||
"@homarr/definitions": "workspace:^0.1.0",
|
"@homarr/definitions": "workspace:^0.1.0",
|
||||||
|
"@homarr/env": "workspace:^0.1.0",
|
||||||
"@homarr/log": "workspace:^0.1.0",
|
"@homarr/log": "workspace:^0.1.0",
|
||||||
"@homarr/validation": "workspace:^0.1.0",
|
"@homarr/validation": "workspace:^0.1.0",
|
||||||
"@t3-oss/env-nextjs": "^0.12.0",
|
|
||||||
"bcrypt": "^5.1.1",
|
"bcrypt": "^5.1.1",
|
||||||
"cookies": "^0.9.1",
|
"cookies": "^0.9.1",
|
||||||
"ldapts": "7.3.1",
|
"ldapts": "7.3.1",
|
||||||
|
|||||||
@@ -6,10 +6,11 @@ import { rootCertificates } from "node:tls";
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { fetch } from "undici";
|
import { fetch } from "undici";
|
||||||
|
|
||||||
|
import { env } from "@homarr/common/env";
|
||||||
import { LoggingAgent } from "@homarr/common/server";
|
import { LoggingAgent } from "@homarr/common/server";
|
||||||
|
|
||||||
const getCertificateFolder = () => {
|
const getCertificateFolder = () => {
|
||||||
return process.env.NODE_ENV === "production"
|
return env.NODE_ENV === "production"
|
||||||
? path.join("/appdata", "trusted-certificates")
|
? path.join("/appdata", "trusted-certificates")
|
||||||
: process.env.LOCAL_CERTIFICATE_PATH;
|
: process.env.LOCAL_CERTIFICATE_PATH;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import { randomBytes } from "crypto";
|
import { randomBytes } from "crypto";
|
||||||
import { createEnv } from "@t3-oss/env-nextjs";
|
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { shouldSkipEnvValidation } from "./src/env-validation";
|
import { createEnv } from "@homarr/env";
|
||||||
|
|
||||||
const errorSuffix = `, please generate a 64 character secret in hex format or use the following: "${randomBytes(32).toString("hex")}"`;
|
const errorSuffix = `, please generate a 64 character secret in hex format or use the following: "${randomBytes(32).toString("hex")}"`;
|
||||||
|
|
||||||
export const env = createEnv({
|
export const env = createEnv({
|
||||||
|
shared: {
|
||||||
|
NODE_ENV: z.enum(["development", "production", "test"]).default("development"),
|
||||||
|
},
|
||||||
server: {
|
server: {
|
||||||
SECRET_ENCRYPTION_KEY: z
|
SECRET_ENCRYPTION_KEY: z
|
||||||
.string({
|
.string({
|
||||||
@@ -24,7 +26,6 @@ export const env = createEnv({
|
|||||||
},
|
},
|
||||||
runtimeEnv: {
|
runtimeEnv: {
|
||||||
SECRET_ENCRYPTION_KEY: process.env.SECRET_ENCRYPTION_KEY,
|
SECRET_ENCRYPTION_KEY: process.env.SECRET_ENCRYPTION_KEY,
|
||||||
|
NODE_ENV: process.env.NODE_ENV,
|
||||||
},
|
},
|
||||||
skipValidation: shouldSkipEnvValidation(),
|
|
||||||
emptyStringAsUndefined: true,
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
},
|
},
|
||||||
"prettier": "@homarr/prettier-config",
|
"prettier": "@homarr/prettier-config",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@homarr/env": "workspace:^0.1.0",
|
||||||
"@homarr/log": "workspace:^0.1.0",
|
"@homarr/log": "workspace:^0.1.0",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"next": "15.1.7",
|
"next": "15.1.7",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { createEnv } from "@t3-oss/env-nextjs";
|
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { shouldSkipEnvValidation } from "@homarr/common/env-validation";
|
import { env as commonEnv } from "@homarr/common/env";
|
||||||
|
import { createEnv } from "@homarr/env";
|
||||||
|
|
||||||
const drivers = {
|
const drivers = {
|
||||||
betterSqlite3: "better-sqlite3",
|
betterSqlite3: "better-sqlite3",
|
||||||
@@ -29,7 +29,7 @@ export const env = createEnv({
|
|||||||
? {
|
? {
|
||||||
DB_URL:
|
DB_URL:
|
||||||
// Fallback to the default sqlite file path in production
|
// Fallback to the default sqlite file path in production
|
||||||
process.env.NODE_ENV === "production" && isDriver("better-sqlite3")
|
commonEnv.NODE_ENV === "production" && isDriver("better-sqlite3")
|
||||||
? z.string().default("/appdata/db/db.sqlite")
|
? z.string().default("/appdata/db/db.sqlite")
|
||||||
: z.string().nonempty(),
|
: z.string().nonempty(),
|
||||||
}
|
}
|
||||||
@@ -49,18 +49,5 @@ export const env = createEnv({
|
|||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
},
|
},
|
||||||
/**
|
experimental__runtimeEnv: process.env,
|
||||||
* Destructure all variables from `process.env` to make sure they aren't tree-shaken away.
|
|
||||||
*/
|
|
||||||
runtimeEnv: {
|
|
||||||
DB_DRIVER: process.env.DB_DRIVER,
|
|
||||||
DB_URL: process.env.DB_URL,
|
|
||||||
DB_HOST: process.env.DB_HOST,
|
|
||||||
DB_USER: process.env.DB_USER,
|
|
||||||
DB_PASSWORD: process.env.DB_PASSWORD,
|
|
||||||
DB_NAME: process.env.DB_NAME,
|
|
||||||
DB_PORT: process.env.DB_PORT,
|
|
||||||
},
|
|
||||||
skipValidation: shouldSkipEnvValidation(),
|
|
||||||
emptyStringAsUndefined: true,
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -40,11 +40,11 @@
|
|||||||
"@auth/core": "^0.37.4",
|
"@auth/core": "^0.37.4",
|
||||||
"@homarr/common": "workspace:^0.1.0",
|
"@homarr/common": "workspace:^0.1.0",
|
||||||
"@homarr/definitions": "workspace:^0.1.0",
|
"@homarr/definitions": "workspace:^0.1.0",
|
||||||
|
"@homarr/env": "workspace:^0.1.0",
|
||||||
"@homarr/log": "workspace:^0.1.0",
|
"@homarr/log": "workspace:^0.1.0",
|
||||||
"@homarr/server-settings": "workspace:^0.1.0",
|
"@homarr/server-settings": "workspace:^0.1.0",
|
||||||
"@mantine/core": "^7.17.0",
|
"@mantine/core": "^7.17.0",
|
||||||
"@paralleldrive/cuid2": "^2.2.2",
|
"@paralleldrive/cuid2": "^2.2.2",
|
||||||
"@t3-oss/env-nextjs": "^0.12.0",
|
|
||||||
"@testcontainers/mysql": "^10.18.0",
|
"@testcontainers/mysql": "^10.18.0",
|
||||||
"better-sqlite3": "^11.8.1",
|
"better-sqlite3": "^11.8.1",
|
||||||
"dotenv": "^16.4.7",
|
"dotenv": "^16.4.7",
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
"prettier": "@homarr/prettier-config",
|
"prettier": "@homarr/prettier-config",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@homarr/common": "workspace:^0.1.0",
|
"@homarr/common": "workspace:^0.1.0",
|
||||||
"@t3-oss/env-nextjs": "^0.12.0",
|
"@homarr/env": "workspace:^0.1.0",
|
||||||
"dockerode": "^4.0.4"
|
"dockerode": "^4.0.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { createEnv } from "@t3-oss/env-nextjs";
|
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { shouldSkipEnvValidation } from "@homarr/common/env-validation";
|
import { createEnv } from "@homarr/env";
|
||||||
|
|
||||||
export const env = createEnv({
|
export const env = createEnv({
|
||||||
server: {
|
server: {
|
||||||
@@ -9,10 +8,5 @@ export const env = createEnv({
|
|||||||
DOCKER_HOSTNAMES: z.string().optional(),
|
DOCKER_HOSTNAMES: z.string().optional(),
|
||||||
DOCKER_PORTS: z.string().optional(),
|
DOCKER_PORTS: z.string().optional(),
|
||||||
},
|
},
|
||||||
runtimeEnv: {
|
experimental__runtimeEnv: process.env,
|
||||||
DOCKER_HOSTNAMES: process.env.DOCKER_HOSTNAMES,
|
|
||||||
DOCKER_PORTS: process.env.DOCKER_PORTS,
|
|
||||||
},
|
|
||||||
skipValidation: shouldSkipEnvValidation(),
|
|
||||||
emptyStringAsUndefined: true,
|
|
||||||
});
|
});
|
||||||
|
|||||||
9
packages/env/eslint.config.js
vendored
Normal file
9
packages/env/eslint.config.js
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import baseConfig from "@homarr/eslint-config/base";
|
||||||
|
|
||||||
|
/** @type {import('typescript-eslint').Config} */
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
ignores: [],
|
||||||
|
},
|
||||||
|
...baseConfig,
|
||||||
|
];
|
||||||
1
packages/env/index.ts
vendored
Normal file
1
packages/env/index.ts
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from "./src";
|
||||||
36
packages/env/package.json
vendored
Normal file
36
packages/env/package.json
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"name": "@homarr/env",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"type": "module",
|
||||||
|
"exports": {
|
||||||
|
".": "./index.ts",
|
||||||
|
"./schemas": "./src/schemas.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": {
|
||||||
|
"@t3-oss/env-nextjs": "^0.12.0",
|
||||||
|
"zod": "^3.24.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
"@homarr/prettier-config": "workspace:^0.1.0",
|
||||||
|
"@homarr/tsconfig": "workspace:^0.1.0",
|
||||||
|
"eslint": "^9.20.1",
|
||||||
|
"typescript": "^5.7.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
9
packages/env/src/index.ts
vendored
Normal file
9
packages/env/src/index.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { createEnv as createEnvT3 } from "@t3-oss/env-nextjs";
|
||||||
|
|
||||||
|
export const defaultEnvOptions = {
|
||||||
|
emptyStringAsUndefined: true,
|
||||||
|
skipValidation:
|
||||||
|
Boolean(process.env.CI) || Boolean(process.env.SKIP_ENV_VALIDATION) || process.env.npm_lifecycle_event === "lint",
|
||||||
|
} satisfies Partial<Parameters<typeof createEnvT3>[0]>;
|
||||||
|
|
||||||
|
export const createEnv: typeof createEnvT3 = (options) => createEnvT3({ ...defaultEnvOptions, ...options });
|
||||||
39
packages/env/src/schemas.ts
vendored
Normal file
39
packages/env/src/schemas.ts
vendored
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
const trueStrings = ["1", "yes", "t", "true"];
|
||||||
|
const falseStrings = ["0", "no", "f", "false"];
|
||||||
|
|
||||||
|
export const createBooleanSchema = (defaultValue: boolean) =>
|
||||||
|
z
|
||||||
|
.string()
|
||||||
|
.default(defaultValue.toString())
|
||||||
|
.transform((value, ctx) => {
|
||||||
|
const normalized = value.trim().toLowerCase();
|
||||||
|
if (trueStrings.includes(normalized)) return true;
|
||||||
|
if (falseStrings.includes(normalized)) return false;
|
||||||
|
|
||||||
|
throw new Error(`Invalid boolean value for ${ctx.path.join(".")}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
export const createDurationSchema = (defaultValue: `${number}${"s" | "m" | "h" | "d"}`) =>
|
||||||
|
z
|
||||||
|
.string()
|
||||||
|
.regex(/^\d+[smhd]?$/)
|
||||||
|
.default(defaultValue)
|
||||||
|
.transform((duration) => {
|
||||||
|
const lastChar = duration[duration.length - 1] as "s" | "m" | "h" | "d";
|
||||||
|
if (!isNaN(Number(lastChar))) {
|
||||||
|
return Number(defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
const multipliers = {
|
||||||
|
s: 1,
|
||||||
|
m: 60,
|
||||||
|
h: 60 * 60,
|
||||||
|
d: 60 * 60 * 24,
|
||||||
|
};
|
||||||
|
const numberDuration = Number(duration.slice(0, -1));
|
||||||
|
const multiplier = multipliers[lastChar];
|
||||||
|
|
||||||
|
return numberDuration * multiplier;
|
||||||
|
});
|
||||||
8
packages/env/tsconfig.json
vendored
Normal file
8
packages/env/tsconfig.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"extends": "@homarr/tsconfig/base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json"
|
||||||
|
},
|
||||||
|
"include": ["*.ts", "src"],
|
||||||
|
"exclude": ["node_modules"]
|
||||||
|
}
|
||||||
@@ -5,11 +5,8 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": "./src/index.ts",
|
||||||
"types": "./src/index.d.ts",
|
"./env": "./src/env.ts"
|
||||||
"default": "./src/index.mjs"
|
|
||||||
},
|
|
||||||
"./override": "./src/override.cjs"
|
|
||||||
},
|
},
|
||||||
"typesVersions": {
|
"typesVersions": {
|
||||||
"*": {
|
"*": {
|
||||||
@@ -26,9 +23,11 @@
|
|||||||
},
|
},
|
||||||
"prettier": "@homarr/prettier-config",
|
"prettier": "@homarr/prettier-config",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@homarr/env": "workspace:^0.1.0",
|
||||||
"ioredis": "5.5.0",
|
"ioredis": "5.5.0",
|
||||||
"superjson": "2.2.2",
|
"superjson": "2.2.2",
|
||||||
"winston": "3.17.0"
|
"winston": "3.17.0",
|
||||||
|
"zod": "^3.24.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
10
packages/log/src/env.ts
Normal file
10
packages/log/src/env.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { createEnv } from "@homarr/env";
|
||||||
|
|
||||||
|
export const env = createEnv({
|
||||||
|
server: {
|
||||||
|
LOG_LEVEL: z.enum(["debug", "info", "warn", "error"]).default("info"),
|
||||||
|
},
|
||||||
|
experimental__runtimeEnv: process.env,
|
||||||
|
});
|
||||||
4
packages/log/src/index.d.ts
vendored
4
packages/log/src/index.d.ts
vendored
@@ -1,4 +0,0 @@
|
|||||||
import type { Logger } from "winston";
|
|
||||||
|
|
||||||
// The following is just to make prettier happy
|
|
||||||
export const logger: Logger = undefined as unknown as Logger;
|
|
||||||
@@ -1,12 +1,14 @@
|
|||||||
|
import type { transport as Transport } from "winston";
|
||||||
import winston, { format, transports } from "winston";
|
import winston, { format, transports } from "winston";
|
||||||
|
|
||||||
import { RedisTransport } from "./redis-transport.mjs";
|
import { env } from "./env";
|
||||||
|
import { RedisTransport } from "./redis-transport";
|
||||||
|
|
||||||
const logMessageFormat = format.printf(({ level, message, timestamp }) => {
|
const logMessageFormat = format.printf(({ level, message, timestamp }) => {
|
||||||
return `${timestamp} ${level}: ${message}`;
|
return `${timestamp as string} ${level}: ${message as string}`;
|
||||||
});
|
});
|
||||||
|
|
||||||
const logTransports = [new transports.Console()];
|
const logTransports: Transport[] = [new transports.Console()];
|
||||||
|
|
||||||
// Only add the Redis transport if we are not in CI
|
// Only add the Redis transport if we are not in CI
|
||||||
if (!(Boolean(process.env.CI) || Boolean(process.env.DISABLE_REDIS_LOGS))) {
|
if (!(Boolean(process.env.CI) || Boolean(process.env.DISABLE_REDIS_LOGS))) {
|
||||||
@@ -16,6 +18,7 @@ if (!(Boolean(process.env.CI) || Boolean(process.env.DISABLE_REDIS_LOGS))) {
|
|||||||
const logger = winston.createLogger({
|
const logger = winston.createLogger({
|
||||||
format: format.combine(format.colorize(), format.timestamp(), logMessageFormat),
|
format: format.combine(format.colorize(), format.timestamp(), logMessageFormat),
|
||||||
transports: logTransports,
|
transports: logTransports,
|
||||||
|
level: env.LOG_LEVEL,
|
||||||
});
|
});
|
||||||
|
|
||||||
export { logger };
|
export { logger };
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
void (async () => {
|
|
||||||
const { logger } = await import("./index.mjs");
|
|
||||||
|
|
||||||
const nextLogger = require("next/dist/build/output/log");
|
|
||||||
|
|
||||||
const getWinstonMethodForConsole = (consoleMethod) => {
|
|
||||||
switch (consoleMethod) {
|
|
||||||
case "error":
|
|
||||||
return (...messages) => logger.error(messages.join(" "));
|
|
||||||
case "warn":
|
|
||||||
return (...messages) => logger.warn(messages.join(" "));
|
|
||||||
case "debug":
|
|
||||||
return (...messages) => logger.debug(messages.join(" "));
|
|
||||||
case "log":
|
|
||||||
case "info":
|
|
||||||
default:
|
|
||||||
return (...messages) => logger.info(messages.join(" "));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const consoleMethods = ["log", "debug", "info", "warn", "error"];
|
|
||||||
consoleMethods.forEach((method) => {
|
|
||||||
console[method] = getWinstonMethodForConsole(method);
|
|
||||||
});
|
|
||||||
|
|
||||||
const getWinstonMethodForNext = (nextMethod) => {
|
|
||||||
switch (nextMethod) {
|
|
||||||
case "error":
|
|
||||||
return (...messages) => logger.error(messages.join(" "));
|
|
||||||
case "warn":
|
|
||||||
return (...messages) => logger.warn(messages.join(" "));
|
|
||||||
case "trace":
|
|
||||||
return (...messages) => logger.info(messages.join(" "));
|
|
||||||
default:
|
|
||||||
return (...messages) => logger.info(messages.join(" "));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Object.keys(nextLogger.prefixes).forEach((method) => {
|
|
||||||
nextLogger[method] = getWinstonMethodForNext(method);
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
@@ -7,15 +7,12 @@ import Transport from "winston-transport";
|
|||||||
// of the base functionality and `.exceptions.handle()`.
|
// of the base functionality and `.exceptions.handle()`.
|
||||||
//
|
//
|
||||||
export class RedisTransport extends Transport {
|
export class RedisTransport extends Transport {
|
||||||
/** @type {Redis} */
|
private redis: Redis | null = null;
|
||||||
redis;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log the info to the Redis channel
|
* Log the info to the Redis channel
|
||||||
* @param {{ message: string; timestamp: string; level: string; }} info
|
|
||||||
* @param {() => void} callback
|
|
||||||
*/
|
*/
|
||||||
log(info, callback) {
|
log(info: { message: string; timestamp: string; level: string }, callback: () => void) {
|
||||||
setImmediate(() => {
|
setImmediate(() => {
|
||||||
this.emit("logged", info);
|
this.emit("logged", info);
|
||||||
});
|
});
|
||||||
@@ -3,6 +3,6 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json"
|
"tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json"
|
||||||
},
|
},
|
||||||
"include": ["*.ts", "src", "index.mjs"],
|
"include": ["*.ts", "src"],
|
||||||
"exclude": ["node_modules"]
|
"exclude": ["node_modules"]
|
||||||
}
|
}
|
||||||
|
|||||||
63
pnpm-lock.yaml
generated
63
pnpm-lock.yaml
generated
@@ -202,9 +202,6 @@ importers:
|
|||||||
'@million/lint':
|
'@million/lint':
|
||||||
specifier: 1.0.14
|
specifier: 1.0.14
|
||||||
version: 1.0.14(rollup@4.21.3)(webpack-sources@3.2.3)
|
version: 1.0.14(rollup@4.21.3)(webpack-sources@3.2.3)
|
||||||
'@t3-oss/env-nextjs':
|
|
||||||
specifier: ^0.12.0
|
|
||||||
version: 0.12.0(typescript@5.7.3)(zod@3.24.2)
|
|
||||||
'@tabler/icons-react':
|
'@tabler/icons-react':
|
||||||
specifier: ^3.30.0
|
specifier: ^3.30.0
|
||||||
version: 3.30.0(react@19.0.0)
|
version: 3.30.0(react@19.0.0)
|
||||||
@@ -651,15 +648,15 @@ importers:
|
|||||||
'@homarr/definitions':
|
'@homarr/definitions':
|
||||||
specifier: workspace:^0.1.0
|
specifier: workspace:^0.1.0
|
||||||
version: link:../definitions
|
version: link:../definitions
|
||||||
|
'@homarr/env':
|
||||||
|
specifier: workspace:^0.1.0
|
||||||
|
version: link:../env
|
||||||
'@homarr/log':
|
'@homarr/log':
|
||||||
specifier: workspace:^0.1.0
|
specifier: workspace:^0.1.0
|
||||||
version: link:../log
|
version: link:../log
|
||||||
'@homarr/validation':
|
'@homarr/validation':
|
||||||
specifier: workspace:^0.1.0
|
specifier: workspace:^0.1.0
|
||||||
version: link:../validation
|
version: link:../validation
|
||||||
'@t3-oss/env-nextjs':
|
|
||||||
specifier: ^0.12.0
|
|
||||||
version: 0.12.0(typescript@5.7.3)(zod@3.24.2)
|
|
||||||
bcrypt:
|
bcrypt:
|
||||||
specifier: ^5.1.1
|
specifier: ^5.1.1
|
||||||
version: 5.1.1
|
version: 5.1.1
|
||||||
@@ -802,6 +799,9 @@ importers:
|
|||||||
|
|
||||||
packages/common:
|
packages/common:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@homarr/env':
|
||||||
|
specifier: workspace:^0.1.0
|
||||||
|
version: link:../env
|
||||||
'@homarr/log':
|
'@homarr/log':
|
||||||
specifier: workspace:^0.1.0
|
specifier: workspace:^0.1.0
|
||||||
version: link:../log
|
version: link:../log
|
||||||
@@ -999,6 +999,9 @@ importers:
|
|||||||
'@homarr/definitions':
|
'@homarr/definitions':
|
||||||
specifier: workspace:^0.1.0
|
specifier: workspace:^0.1.0
|
||||||
version: link:../definitions
|
version: link:../definitions
|
||||||
|
'@homarr/env':
|
||||||
|
specifier: workspace:^0.1.0
|
||||||
|
version: link:../env
|
||||||
'@homarr/log':
|
'@homarr/log':
|
||||||
specifier: workspace:^0.1.0
|
specifier: workspace:^0.1.0
|
||||||
version: link:../log
|
version: link:../log
|
||||||
@@ -1011,9 +1014,6 @@ importers:
|
|||||||
'@paralleldrive/cuid2':
|
'@paralleldrive/cuid2':
|
||||||
specifier: ^2.2.2
|
specifier: ^2.2.2
|
||||||
version: 2.2.2
|
version: 2.2.2
|
||||||
'@t3-oss/env-nextjs':
|
|
||||||
specifier: ^0.12.0
|
|
||||||
version: 0.12.0(typescript@5.7.3)(zod@3.24.2)
|
|
||||||
'@testcontainers/mysql':
|
'@testcontainers/mysql':
|
||||||
specifier: ^10.18.0
|
specifier: ^10.18.0
|
||||||
version: 10.18.0
|
version: 10.18.0
|
||||||
@@ -1091,9 +1091,9 @@ importers:
|
|||||||
'@homarr/common':
|
'@homarr/common':
|
||||||
specifier: workspace:^0.1.0
|
specifier: workspace:^0.1.0
|
||||||
version: link:../common
|
version: link:../common
|
||||||
'@t3-oss/env-nextjs':
|
'@homarr/env':
|
||||||
specifier: ^0.12.0
|
specifier: workspace:^0.1.0
|
||||||
version: 0.12.0(typescript@5.7.3)(zod@3.24.2)
|
version: link:../env
|
||||||
dockerode:
|
dockerode:
|
||||||
specifier: ^4.0.4
|
specifier: ^4.0.4
|
||||||
version: 4.0.4
|
version: 4.0.4
|
||||||
@@ -1117,6 +1117,31 @@ importers:
|
|||||||
specifier: ^5.7.3
|
specifier: ^5.7.3
|
||||||
version: 5.7.3
|
version: 5.7.3
|
||||||
|
|
||||||
|
packages/env:
|
||||||
|
dependencies:
|
||||||
|
'@t3-oss/env-nextjs':
|
||||||
|
specifier: ^0.12.0
|
||||||
|
version: 0.12.0(typescript@5.7.3)(zod@3.24.2)
|
||||||
|
zod:
|
||||||
|
specifier: ^3.24.2
|
||||||
|
version: 3.24.2
|
||||||
|
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
|
||||||
|
eslint:
|
||||||
|
specifier: ^9.20.1
|
||||||
|
version: 9.20.1
|
||||||
|
typescript:
|
||||||
|
specifier: ^5.7.3
|
||||||
|
version: 5.7.3
|
||||||
|
|
||||||
packages/form:
|
packages/form:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@homarr/common':
|
'@homarr/common':
|
||||||
@@ -1300,6 +1325,9 @@ importers:
|
|||||||
|
|
||||||
packages/log:
|
packages/log:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@homarr/env':
|
||||||
|
specifier: workspace:^0.1.0
|
||||||
|
version: link:../env
|
||||||
ioredis:
|
ioredis:
|
||||||
specifier: 5.5.0
|
specifier: 5.5.0
|
||||||
version: 5.5.0
|
version: 5.5.0
|
||||||
@@ -1309,6 +1337,9 @@ importers:
|
|||||||
winston:
|
winston:
|
||||||
specifier: 3.17.0
|
specifier: 3.17.0
|
||||||
version: 3.17.0
|
version: 3.17.0
|
||||||
|
zod:
|
||||||
|
specifier: ^3.24.2
|
||||||
|
version: 3.24.2
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@homarr/eslint-config':
|
'@homarr/eslint-config':
|
||||||
specifier: workspace:^0.2.0
|
specifier: workspace:^0.2.0
|
||||||
@@ -16475,7 +16506,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@babel/code-frame': 7.26.2
|
'@babel/code-frame': 7.26.2
|
||||||
index-to-position: 0.1.2
|
index-to-position: 0.1.2
|
||||||
type-fest: 4.34.1
|
type-fest: 4.30.2
|
||||||
|
|
||||||
parse-ms@3.0.0: {}
|
parse-ms@3.0.0: {}
|
||||||
|
|
||||||
@@ -17039,14 +17070,14 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
find-up-simple: 1.0.0
|
find-up-simple: 1.0.0
|
||||||
read-pkg: 9.0.1
|
read-pkg: 9.0.1
|
||||||
type-fest: 4.34.1
|
type-fest: 4.30.2
|
||||||
|
|
||||||
read-pkg@9.0.1:
|
read-pkg@9.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/normalize-package-data': 2.4.4
|
'@types/normalize-package-data': 2.4.4
|
||||||
normalize-package-data: 6.0.2
|
normalize-package-data: 6.0.2
|
||||||
parse-json: 8.1.0
|
parse-json: 8.1.0
|
||||||
type-fest: 4.34.1
|
type-fest: 4.30.2
|
||||||
unicorn-magic: 0.1.0
|
unicorn-magic: 0.1.0
|
||||||
|
|
||||||
readable-stream@2.3.8:
|
readable-stream@2.3.8:
|
||||||
@@ -18354,7 +18385,7 @@ snapshots:
|
|||||||
consola: 3.2.3
|
consola: 3.2.3
|
||||||
defu: 6.1.4
|
defu: 6.1.4
|
||||||
mime: 3.0.0
|
mime: 3.0.0
|
||||||
node-fetch-native: 1.6.6
|
node-fetch-native: 1.6.4
|
||||||
pathe: 1.1.2
|
pathe: 1.1.2
|
||||||
|
|
||||||
unicode-emoji-modifier-base@1.0.0: {}
|
unicode-emoji-modifier-base@1.0.0: {}
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
"NODE_ENV",
|
"NODE_ENV",
|
||||||
"PORT",
|
"PORT",
|
||||||
"LOCAL_CERTIFICATE_PATH",
|
"LOCAL_CERTIFICATE_PATH",
|
||||||
|
"LOG_LEVEL",
|
||||||
"SECRET_ENCRYPTION_KEY",
|
"SECRET_ENCRYPTION_KEY",
|
||||||
"SKIP_ENV_VALIDATION"
|
"SKIP_ENV_VALIDATION"
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user