move enable redis to flag

This commit is contained in:
miloschwartz 2025-06-15 13:24:51 -04:00
parent 139c9d2ce3
commit af32dfbbcd
No known key found for this signature in database
2 changed files with 233 additions and 222 deletions

View file

@ -14,7 +14,7 @@ class RedisManager {
> = new Map(); > = new Map();
private constructor() { private constructor() {
this.isEnabled = config.getRawConfig().redis?.enabled || false; this.isEnabled = config.getRawConfig().flags?.enable_redis || false;
if (this.isEnabled) { if (this.isEnabled) {
this.initializeClients(); this.initializeClients();
} }

View file

@ -12,244 +12,255 @@ const getEnvOrYaml = (envVar: string) => (valFromYaml: any) => {
return process.env[envVar] ?? valFromYaml; return process.env[envVar] ?? valFromYaml;
}; };
export const configSchema = z.object({ export const configSchema = z
app: z.object({ .object({
dashboard_url: z app: z.object({
.string() dashboard_url: z
.url() .string()
.optional() .url()
.pipe(z.string().url())
.transform((url) => url.toLowerCase()),
log_level: z
.enum(["debug", "info", "warn", "error"])
.optional()
.default("info"),
save_logs: z.boolean().optional().default(false),
log_failed_attempts: z.boolean().optional().default(false)
}),
domains: z
.record(
z.string(),
z.object({
base_domain: z
.string()
.nonempty("base_domain must not be empty")
.transform((url) => url.toLowerCase()),
cert_resolver: z.string().optional().default("letsencrypt"),
prefer_wildcard_cert: z.boolean().optional().default(false)
})
)
.refine(
(domains) => {
const keys = Object.keys(domains);
if (keys.length === 0) {
return false;
}
return true;
},
{
message: "At least one domain must be defined"
}
),
server: z.object({
integration_port: portSchema
.optional()
.default(3003)
.transform(stoi)
.pipe(portSchema.optional()),
external_port: portSchema
.optional()
.default(3000)
.transform(stoi)
.pipe(portSchema),
internal_port: portSchema
.optional()
.default(3001)
.transform(stoi)
.pipe(portSchema),
next_port: portSchema
.optional()
.default(3002)
.transform(stoi)
.pipe(portSchema),
internal_hostname: z
.string()
.optional()
.default("pangolin")
.transform((url) => url.toLowerCase()),
session_cookie_name: z.string().optional().default("p_session_token"),
resource_access_token_param: z.string().optional().default("p_token"),
resource_access_token_headers: z
.object({
id: z.string().optional().default("P-Access-Token-Id"),
token: z.string().optional().default("P-Access-Token")
})
.optional()
.default({}),
resource_session_request_param: z
.string()
.optional()
.default("resource_session_request_param"),
dashboard_session_length_hours: z
.number()
.positive()
.gt(0)
.optional()
.default(720),
resource_session_length_hours: z
.number()
.positive()
.gt(0)
.optional()
.default(720),
cors: z
.object({
origins: z.array(z.string()).optional(),
methods: z.array(z.string()).optional(),
allowed_headers: z.array(z.string()).optional(),
credentials: z.boolean().optional()
})
.optional(),
trust_proxy: z.boolean().optional().default(true),
secret: z
.string()
.optional()
.transform(getEnvOrYaml("SERVER_SECRET"))
.pipe(z.string().min(8))
}),
postgres: z
.object({
connection_string: z.string(),
replicas: z
.array(
z.object({
connection_string: z.string()
})
)
.optional() .optional()
}) .pipe(z.string().url())
.optional(), .transform((url) => url.toLowerCase()),
redis: z log_level: z
.object({ .enum(["debug", "info", "warn", "error"])
enabled: z.boolean(), .optional()
host: z.string().optional(), .default("info"),
port: portSchema.optional(), save_logs: z.boolean().optional().default(false),
password: z.string().optional(), log_failed_attempts: z.boolean().optional().default(false)
db: z.number().int().nonnegative().optional().default(0), }),
tls: z domains: z
.object({ .record(
rejectUnauthorized: z.boolean().optional().default(true) z.string(),
z.object({
base_domain: z
.string()
.nonempty("base_domain must not be empty")
.transform((url) => url.toLowerCase()),
cert_resolver: z.string().optional().default("letsencrypt"),
prefer_wildcard_cert: z.boolean().optional().default(false)
}) })
.optional() )
}) .refine(
.refine( (domains) => {
(redis) => { const keys = Object.keys(domains);
if (!redis.enabled) {
if (keys.length === 0) {
return false;
}
return true; return true;
},
{
message: "At least one domain must be defined"
} }
return redis.host !== undefined && redis.port !== undefined; ),
}, server: z.object({
{ integration_port: portSchema
message:
"If Redis is enabled, connection details must be provided"
}
)
.optional(),
traefik: z
.object({
http_entrypoint: z.string().optional().default("web"),
https_entrypoint: z.string().optional().default("websecure"),
additional_middlewares: z.array(z.string()).optional()
})
.optional()
.default({}),
gerbil: z
.object({
start_port: portSchema
.optional() .optional()
.default(51820) .default(3003)
.transform(stoi)
.pipe(portSchema.optional()),
external_port: portSchema
.optional()
.default(3000)
.transform(stoi) .transform(stoi)
.pipe(portSchema), .pipe(portSchema),
base_endpoint: z internal_port: portSchema
.optional()
.default(3001)
.transform(stoi)
.pipe(portSchema),
next_port: portSchema
.optional()
.default(3002)
.transform(stoi)
.pipe(portSchema),
internal_hostname: z
.string() .string()
.optional() .optional()
.pipe(z.string()) .default("pangolin")
.transform((url) => url.toLowerCase()), .transform((url) => url.toLowerCase()),
use_subdomain: z.boolean().optional().default(false), session_cookie_name: z
subnet_group: z.string().optional().default("100.89.137.0/20"), .string()
block_size: z.number().positive().gt(0).optional().default(24), .optional()
site_block_size: z.number().positive().gt(0).optional().default(30) .default("p_session_token"),
}) resource_access_token_param: z
.optional() .string()
.default({}), .optional()
rate_limits: z .default("p_token"),
.object({ resource_access_token_headers: z
global: z
.object({ .object({
window_minutes: z id: z.string().optional().default("P-Access-Token-Id"),
.number() token: z.string().optional().default("P-Access-Token")
.positive()
.gt(0)
.optional()
.default(1),
max_requests: z
.number()
.positive()
.gt(0)
.optional()
.default(500)
}) })
.optional() .optional()
.default({}), .default({}),
auth: z resource_session_request_param: z
.object({
window_minutes: z.number().positive().gt(0),
max_requests: z.number().positive().gt(0)
})
.optional()
})
.optional()
.default({}),
email: z
.object({
smtp_host: z.string().optional(),
smtp_port: portSchema.optional(),
smtp_user: z.string().optional(),
smtp_pass: z.string().optional(),
smtp_secure: z.boolean().optional(),
smtp_tls_reject_unauthorized: z.boolean().optional(),
no_reply: z.string().email().optional()
})
.optional(),
users: z.object({
server_admin: z.object({
email: z
.string() .string()
.email()
.optional() .optional()
.transform(getEnvOrYaml("USERS_SERVERADMIN_EMAIL")) .default("resource_session_request_param"),
.pipe(z.string().email()) dashboard_session_length_hours: z
.transform((v) => v.toLowerCase()), .number()
password: passwordSchema .positive()
.gt(0)
.optional() .optional()
.transform(getEnvOrYaml("USERS_SERVERADMIN_PASSWORD")) .default(720),
.pipe(passwordSchema) resource_session_length_hours: z
}) .number()
}), .positive()
flags: z .gt(0)
.object({ .optional()
require_email_verification: z.boolean().optional(), .default(720),
disable_signup_without_invite: z.boolean().optional(), cors: z
disable_user_create_org: z.boolean().optional(), .object({
allow_raw_resources: z.boolean().optional(), origins: z.array(z.string()).optional(),
allow_base_domain_resources: z.boolean().optional(), methods: z.array(z.string()).optional(),
allow_local_sites: z.boolean().optional(), allowed_headers: z.array(z.string()).optional(),
enable_integration_api: z.boolean().optional() credentials: z.boolean().optional()
}) })
.optional() .optional(),
}); trust_proxy: z.boolean().optional().default(true),
secret: z
.string()
.optional()
.transform(getEnvOrYaml("SERVER_SECRET"))
.pipe(z.string().min(8))
}),
postgres: z
.object({
connection_string: z.string(),
replicas: z
.array(
z.object({
connection_string: z.string()
})
)
.optional()
})
.optional(),
redis: z
.object({
host: z.string(),
port: portSchema,
password: z.string().optional(),
db: z.number().int().nonnegative().optional().default(0),
tls: z
.object({
rejectUnauthorized: z.boolean().optional().default(true)
})
.optional()
})
.optional(),
traefik: z
.object({
http_entrypoint: z.string().optional().default("web"),
https_entrypoint: z.string().optional().default("websecure"),
additional_middlewares: z.array(z.string()).optional()
})
.optional()
.default({}),
gerbil: z
.object({
start_port: portSchema
.optional()
.default(51820)
.transform(stoi)
.pipe(portSchema),
base_endpoint: z
.string()
.optional()
.pipe(z.string())
.transform((url) => url.toLowerCase()),
use_subdomain: z.boolean().optional().default(false),
subnet_group: z.string().optional().default("100.89.137.0/20"),
block_size: z.number().positive().gt(0).optional().default(24),
site_block_size: z
.number()
.positive()
.gt(0)
.optional()
.default(30)
})
.optional()
.default({}),
rate_limits: z
.object({
global: z
.object({
window_minutes: z
.number()
.positive()
.gt(0)
.optional()
.default(1),
max_requests: z
.number()
.positive()
.gt(0)
.optional()
.default(500)
})
.optional()
.default({}),
auth: z
.object({
window_minutes: z.number().positive().gt(0),
max_requests: z.number().positive().gt(0)
})
.optional()
})
.optional()
.default({}),
email: z
.object({
smtp_host: z.string().optional(),
smtp_port: portSchema.optional(),
smtp_user: z.string().optional(),
smtp_pass: z.string().optional(),
smtp_secure: z.boolean().optional(),
smtp_tls_reject_unauthorized: z.boolean().optional(),
no_reply: z.string().email().optional()
})
.optional(),
users: z.object({
server_admin: z.object({
email: z
.string()
.email()
.optional()
.transform(getEnvOrYaml("USERS_SERVERADMIN_EMAIL"))
.pipe(z.string().email())
.transform((v) => v.toLowerCase()),
password: passwordSchema
.optional()
.transform(getEnvOrYaml("USERS_SERVERADMIN_PASSWORD"))
.pipe(passwordSchema)
})
}),
flags: z
.object({
require_email_verification: z.boolean().optional(),
disable_signup_without_invite: z.boolean().optional(),
disable_user_create_org: z.boolean().optional(),
allow_raw_resources: z.boolean().optional(),
allow_base_domain_resources: z.boolean().optional(),
allow_local_sites: z.boolean().optional(),
enable_integration_api: z.boolean().optional(),
enable_redis: z.boolean().optional()
})
.optional()
})
.refine(
(data) => {
if (data.flags?.enable_redis) {
return data?.redis !== undefined;
}
return true;
},
{
message: "If Redis is enabled, configuration details must be provided"
}
);
export function readConfigFile() { export function readConfigFile() {
const loadConfig = (configPath: string) => { const loadConfig = (configPath: string) => {