import { SiteResource, siteResources, Transaction, } from "@server/db"; import { sites } from "@server/db"; import { eq, and } from "drizzle-orm"; import { Config, } from "./types"; import logger from "@server/logger"; export type ClientResourcesResults = { resource: SiteResource; }[]; export async function updateClientResources( orgId: string, config: Config, trx: Transaction, siteId?: number ): Promise { const results: ClientResourcesResults = []; for (const [resourceNiceId, resourceData] of Object.entries( config["client-resources"] )) { const [existingResource] = await trx .select() .from(siteResources) .where( and( eq(siteResources.orgId, orgId), eq(siteResources.niceId, resourceNiceId) ) ) .limit(1); const resourceSiteId = resourceData.site; let site; if (resourceSiteId) { // Look up site by niceId [site] = await trx .select({ siteId: sites.siteId }) .from(sites) .where( and( eq(sites.niceId, resourceSiteId), eq(sites.orgId, orgId) ) ) .limit(1); } else if (siteId) { // Use the provided siteId directly, but verify it belongs to the org [site] = await trx .select({ siteId: sites.siteId }) .from(sites) .where(and(eq(sites.siteId, siteId), eq(sites.orgId, orgId))) .limit(1); } else { throw new Error(`Target site is required`); } if (!site) { throw new Error( `Site not found: ${resourceSiteId} in org ${orgId}` ); } if (existingResource) { // Update existing resource const [updatedResource] = await trx .update(siteResources) .set({ name: resourceData.name || resourceNiceId, siteId: site.siteId, proxyPort: resourceData["proxy-port"]!, destinationIp: resourceData.hostname, destinationPort: resourceData["internal-port"], protocol: resourceData.protocol }) .where( eq( siteResources.siteResourceId, existingResource.siteResourceId ) ) .returning(); results.push({ resource: updatedResource }); } else { // Create new resource const [newResource] = await trx .insert(siteResources) .values({ orgId: orgId, siteId: site.siteId, niceId: resourceNiceId, name: resourceData.name || resourceNiceId, proxyPort: resourceData["proxy-port"]!, destinationIp: resourceData.hostname, destinationPort: resourceData["internal-port"], protocol: resourceData.protocol }) .returning(); logger.info( `Created new client resource ${newResource.name} (${newResource.siteResourceId}) for org ${orgId}` ); results.push({ resource: newResource }); } } return results; }