Merge branch 'dev'

This commit is contained in:
Owen
2025-10-07 15:08:32 -07:00
22 changed files with 232 additions and 2397 deletions

View File

@@ -115,7 +115,8 @@ export async function updateProxyResources(
path: targetData.path,
pathMatchType: targetData["path-match"],
rewritePath: targetData.rewritePath,
rewritePathType: targetData["rewrite-match"]
rewritePathType: targetData["rewrite-match"],
priority: targetData.priority
})
.returning();
@@ -392,7 +393,8 @@ export async function updateProxyResources(
path: targetData.path,
pathMatchType: targetData["path-match"],
rewritePath: targetData.rewritePath,
rewritePathType: targetData["rewrite-match"]
rewritePathType: targetData["rewrite-match"],
priority: targetData.priority
})
.where(eq(targets.targetId, existingTarget.targetId))
.returning();

View File

@@ -33,7 +33,8 @@ export const TargetSchema = z.object({
"path-match": z.enum(["exact", "prefix", "regex"]).optional().nullable(),
healthcheck: TargetHealthCheckSchema.optional(),
rewritePath: z.string().optional(),
"rewrite-match": z.enum(["exact", "prefix", "regex", "stripPrefix"]).optional().nullable()
"rewrite-match": z.enum(["exact", "prefix", "regex", "stripPrefix"]).optional().nullable(),
priority: z.number().int().min(1).max(1000).optional().default(100)
});
export type TargetData = z.infer<typeof TargetSchema>;

View File

@@ -64,7 +64,7 @@ export const configSchema = z
server: z.object({
integration_port: portSchema
.optional()
.default(3004)
.default(3003)
.transform(stoi)
.pipe(portSchema.optional()),
external_port: portSchema
@@ -158,7 +158,21 @@ export const configSchema = z
connection_string: z.string()
})
)
.optional(),
pool: z
.object({
max_connections: z.number().positive().optional().default(20),
max_replica_connections: z.number().positive().optional().default(10),
idle_timeout_ms: z.number().positive().optional().default(30000),
connection_timeout_ms: z.number().positive().optional().default(5000)
})
.optional()
.default({
max_connections: 20,
max_replica_connections: 10,
idle_timeout_ms: 30000,
connection_timeout_ms: 5000
})
})
.optional(),
traefik: z

View File

@@ -1,5 +1,5 @@
import { db, exitNodes, targetHealthCheck } from "@server/db";
import { and, eq, inArray, or, isNull, ne, isNotNull } from "drizzle-orm";
import { and, eq, inArray, or, isNull, ne, isNotNull, desc } from "drizzle-orm";
import logger from "@server/logger";
import config from "@server/lib/config";
import { orgs, resources, sites, Target, targets } from "@server/db";
@@ -59,6 +59,8 @@ export async function getTraefikConfig(
pathMatchType: targets.pathMatchType,
rewritePath: targets.rewritePath,
rewritePathType: targets.rewritePathType,
priority: targets.priority,
// Site fields
siteId: sites.siteId,
siteType: sites.type,
@@ -87,7 +89,8 @@ export async function getTraefikConfig(
? isNotNull(resources.http) // ignore the http check if allow_raw_resources is true
: eq(resources.http, true)
)
);
)
.orderBy(desc(targets.priority), targets.targetId); // stable ordering
// Group by resource and include targets with their unique site data
const resourcesMap = new Map();
@@ -99,6 +102,7 @@ export async function getTraefikConfig(
const pathMatchType = row.pathMatchType || "";
const rewritePath = row.rewritePath || "";
const rewritePathType = row.rewritePathType || "";
const priority = row.priority ?? 100;
// Create a unique key combining resourceId, path config, and rewrite config
const pathKey = [targetPath, pathMatchType, rewritePath, rewritePathType]
@@ -140,7 +144,8 @@ export async function getTraefikConfig(
path: row.path, // the targets will all have the same path
pathMatchType: row.pathMatchType, // the targets will all have the same pathMatchType
rewritePath: row.rewritePath,
rewritePathType: row.rewritePathType
rewritePathType: row.rewritePathType,
priority: priority // may be null, we fallback later
});
}
@@ -155,6 +160,7 @@ export async function getTraefikConfig(
enabled: row.targetEnabled,
rewritePath: row.rewritePath,
rewritePathType: row.rewritePathType,
priority: row.priority,
site: {
siteId: row.siteId,
type: row.siteType,
@@ -338,10 +344,30 @@ export async function getTraefikConfig(
// Build routing rules
let rule = `Host(\`${fullDomain}\`)`;
let priority = 100;
// priority logic
let priority: number;
if (resource.priority && resource.priority != 100) {
priority = resource.priority;
} else {
priority = 100;
if (resource.path && resource.pathMatchType) {
priority += 10;
if (resource.pathMatchType === "exact") {
priority += 5;
} else if (resource.pathMatchType === "prefix") {
priority += 3;
} else if (resource.pathMatchType === "regex") {
priority += 2;
}
if (resource.path === "/") {
priority = 1; // lowest for catch-all
}
}
}
if (resource.path && resource.pathMatchType) {
priority += 1;
// priority += 1;
// add path to rule based on match type
let path = resource.path;
// if the path doesn't start with a /, add it

View File

@@ -19,7 +19,7 @@ import {
loginPage,
targetHealthCheck
} from "@server/db";
import { and, eq, inArray, or, isNull, ne, isNotNull } from "drizzle-orm";
import { and, eq, inArray, or, isNull, ne, isNotNull, desc } from "drizzle-orm";
import logger from "@server/logger";
import HttpCode from "@server/types/HttpCode";
import config from "@server/lib/config";
@@ -78,7 +78,8 @@ export async function getTraefikConfig(
hcHealth: targetHealthCheck.hcHealth,
path: targets.path,
pathMatchType: targets.pathMatchType,
priority: targets.priority,
// Site fields
siteId: sites.siteId,
siteType: sites.type,
@@ -119,7 +120,8 @@ export async function getTraefikConfig(
? isNotNull(resources.http) // ignore the http check if allow_raw_resources is true
: eq(resources.http, true)
)
);
)
.orderBy(desc(targets.priority), targets.targetId); // stable ordering
// Group by resource and include targets with their unique site data
const resourcesMap = new Map();
@@ -129,6 +131,7 @@ export async function getTraefikConfig(
const resourceName = sanitize(row.resourceName) || "";
const targetPath = sanitize(row.path) || ""; // Handle null/undefined paths
const pathMatchType = row.pathMatchType || "";
const priority = row.priority ?? 100;
if (filterOutNamespaceDomains && row.domainNamespaceId) {
return;
@@ -159,7 +162,8 @@ export async function getTraefikConfig(
targets: [],
headers: row.headers,
path: row.path, // the targets will all have the same path
pathMatchType: row.pathMatchType // the targets will all have the same pathMatchType
pathMatchType: row.pathMatchType, // the targets will all have the same pathMatchType
priority: priority // may be null, we fallback later
});
}
@@ -172,6 +176,7 @@ export async function getTraefikConfig(
port: row.port,
internalPort: row.internalPort,
enabled: row.targetEnabled,
priority: row.priority,
site: {
siteId: row.siteId,
type: row.siteType,
@@ -335,9 +340,30 @@ export async function getTraefikConfig(
}
let rule = `Host(\`${fullDomain}\`)`;
let priority = 100;
// priority logic
let priority: number;
if (resource.priority && resource.priority != 100) {
priority = resource.priority;
} else {
priority = 100;
if (resource.path && resource.pathMatchType) {
priority += 10;
if (resource.pathMatchType === "exact") {
priority += 5;
} else if (resource.pathMatchType === "prefix") {
priority += 3;
} else if (resource.pathMatchType === "regex") {
priority += 2;
}
if (resource.path === "/") {
priority = 1; // lowest for catch-all
}
}
}
if (resource.path && resource.pathMatchType) {
priority += 1;
//priority += 1;
// add path to rule based on match type
let path = resource.path;
// if the path doesn't start with a /, add it
@@ -393,7 +419,7 @@ export async function getTraefikConfig(
return (
(targets as TargetWithSite[])
.filter((target: TargetWithSite) => {
.filter((target: TargetWithSite) => {
if (!target.enabled) {
return false;
}
@@ -414,7 +440,7 @@ export async function getTraefikConfig(
) {
return false;
}
} else if (target.site.type === "newt") {
} else if (target.site.type === "newt") {
if (
!target.internalPort ||
!target.method ||
@@ -422,10 +448,10 @@ export async function getTraefikConfig(
) {
return false;
}
}
return true;
})
.map((target: TargetWithSite) => {
}
return true;
})
.map((target: TargetWithSite) => {
if (
target.site.type === "local" ||
target.site.type === "wireguard"
@@ -433,14 +459,14 @@ export async function getTraefikConfig(
return {
url: `${target.method}://${target.ip}:${target.port}`
};
} else if (target.site.type === "newt") {
} else if (target.site.type === "newt") {
const ip =
target.site.subnet!.split("/")[0];
return {
url: `${target.method}://${ip}:${target.internalPort}`
};
}
})
}
})
// filter out duplicates
.filter(
(v, i, a) =>