let lib = import ; allowedEndpointKeys = [ "type" "domain" "endpoint" "port" "force_ssl" "content" ]; allowedProxyContentKeys = [ "type" "ip" "port" "proxyWebsockets" ]; allowedWebContentKeys = [ "type" "files" ]; allowedWebFileKeys = [ "path" "filePath" "contentType" "status" ]; allowedInlineContentKeys = [ "body" "contentType" "status" ]; ensureNoUnknownKeys = context: obj: allowedKeys: let unknown = builtins.filter (key: !(lib.elem key allowedKeys)) (builtins.attrNames obj); in if unknown != [] then throw "${context} contains unknown keys: ${builtins.concatStringsSep ", " unknown}" else obj; ensurePath = value: builtins.isString value && builtins.substring 0 1 value == "/"; ensurePort = value: builtins.isInt value && value > 0 && value <= 65535; validateEndpointShape = index: endpoint: let _ = if !builtins.isAttrs endpoint then throw "Endpoint at index ${toString index} must be an attrset." else null; __ = ensureNoUnknownKeys "Endpoint at index ${toString index}" endpoint allowedEndpointKeys; ___ = if endpoint ? forceSsl then throw "Endpoint at index ${toString index} uses forceSsl. Use force_ssl instead." else null; typeValue = if endpoint ? type && builtins.isString endpoint.type then endpoint.type else throw "Endpoint at index ${toString index} must define type as a string."; _type = if lib.elem typeValue [ "proxy" "web" "inline" ] then null else throw "Endpoint at index ${toString index} type must be 'proxy', 'web', or 'inline'."; _domain = if endpoint ? domain && builtins.isString endpoint.domain && endpoint.domain != "" then null else throw "Endpoint at index ${toString index} must define a non-empty domain string."; _endpoint = if endpoint ? endpoint && ensurePath endpoint.endpoint then null else throw "Endpoint at index ${toString index} must define endpoint as a path starting with '/'."; _port = if endpoint ? port && ensurePort endpoint.port then null else throw "Endpoint at index ${toString index} must define port as int in range 1..65535."; _forceSsl = if endpoint ? force_ssl && builtins.isBool endpoint.force_ssl then null else throw "Endpoint at index ${toString index} must define force_ssl as a bool."; contentValue = if endpoint ? content then endpoint.content else throw "Endpoint at index ${toString index} must define content."; _content = if typeValue == "proxy" then let _attrs = if builtins.isAttrs contentValue then null else throw "Proxy endpoint at index ${toString index} must define content as an attrset."; ____ = ensureNoUnknownKeys "Proxy content at endpoint index ${toString index}" contentValue allowedProxyContentKeys; in if !(contentValue ? type) || !builtins.isString contentValue.type then throw "Proxy endpoint at index ${toString index} must define content.type as a string." else if !(contentValue ? ip) || !builtins.isString contentValue.ip || contentValue.ip == "" then throw "Proxy endpoint at index ${toString index} must define content.ip as a non-empty string." else if !(contentValue ? port) || !ensurePort contentValue.port then throw "Proxy endpoint at index ${toString index} must define content.port as int in range 1..65535." else if !(contentValue ? proxyWebsockets) || !builtins.isBool contentValue.proxyWebsockets then throw "Proxy endpoint at index ${toString index} must define content.proxyWebsockets as a bool." else null else if typeValue == "web" then let _attrs = if builtins.isAttrs contentValue then null else throw "Web endpoint at index ${toString index} must define content as an attrset."; ____ = ensureNoUnknownKeys "Web content at endpoint index ${toString index}" contentValue allowedWebContentKeys; filesValue = if contentValue ? files && builtins.isList contentValue.files then contentValue.files else throw "Web endpoint at index ${toString index} must define content.files as a list."; _____ = if contentValue ? type && contentValue.type == "store" then null else throw "Web endpoint at index ${toString index} must define content.type = 'store'."; ______ = lib.imap0 (fileIndex: file: let _______ = if builtins.isAttrs file then null else throw "Web endpoint at index ${toString index} file at position ${toString fileIndex} must be an attrset."; ________ = ensureNoUnknownKeys "Web endpoint at index ${toString index} file at position ${toString fileIndex}" file allowedWebFileKeys; _________ = if file ? path && builtins.isString file.path && file.path != "" && builtins.substring 0 1 file.path != "/" then null else throw "Web endpoint at index ${toString index} file at position ${toString fileIndex} must define path as a relative path string."; __________ = if file ? filePath && (builtins.isString file.filePath || builtins.isPath file.filePath) then null else throw "Web endpoint at index ${toString index} file at position ${toString fileIndex} must define filePath as string or path."; ___________ = if file ? contentType && builtins.isString file.contentType && file.contentType != "" then null else throw "Web endpoint at index ${toString index} file at position ${toString fileIndex} must define contentType as non-empty string."; ____________ = if file ? status && builtins.isInt file.status then null else throw "Web endpoint at index ${toString index} file at position ${toString fileIndex} must define status as int."; in file ) filesValue; in null else if builtins.isString contentValue then null else if builtins.isAttrs contentValue then let ____ = ensureNoUnknownKeys "Inline content at endpoint index ${toString index}" contentValue allowedInlineContentKeys; _____ = if contentValue ? body && builtins.isString contentValue.body then null else throw "Inline endpoint at index ${toString index} must define content.body as a string when content is an attrset."; ______ = if !(contentValue ? contentType) || (builtins.isString contentValue.contentType && contentValue.contentType != "") then null else throw "Inline endpoint at index ${toString index} content.contentType must be a non-empty string when provided."; _______ = if !(contentValue ? status) || builtins.isInt contentValue.status then null else throw "Inline endpoint at index ${toString index} content.status must be an int when provided."; in null else throw "Inline endpoint at index ${toString index} must define content as a string or an attrset."; in endpoint; validateEndpointsShape = endpoints: if !builtins.isList endpoints then throw "config/endpoints.nix must evaluate to a list of endpoint attrsets." else lib.imap0 validateEndpointShape endpoints; in { inherit validateEndpointShape validateEndpointsShape; }