let lib = import ; webConfig = import ../config/web.nix; webValidation = import ../validation/web.nix; stores = webValidation.getStores webConfig; stripPrefix = prefix: value: let prefixLen = builtins.stringLength prefix; valueLen = builtins.stringLength value; in if valueLen >= prefixLen && builtins.substring 0 prefixLen value == prefix then builtins.substring prefixLen (valueLen - prefixLen) value else value; trimLeadingSlash = value: if builtins.stringLength value > 0 && builtins.substring 0 1 value == "/" then builtins.substring 1 (builtins.stringLength value - 1) value else value; findFiles = dir: let entries = builtins.readDir dir; processEntry = name: type: let path = dir + "/${name}"; in if type == "directory" then findFiles path else if type == "regular" then [ path ] else []; in lib.concatLists (lib.mapAttrsToList processEntry entries); detectContentType = relativePath: if lib.hasSuffix ".html" relativePath then "text/html" else if lib.hasSuffix ".css" relativePath then "text/css" else if lib.hasSuffix ".js" relativePath then "application/javascript" else if lib.hasSuffix ".json" relativePath then "application/json" else if lib.hasSuffix ".svg" relativePath then "image/svg+xml" else if lib.hasSuffix ".png" relativePath then "image/png" else if lib.hasSuffix ".jpg" relativePath || lib.hasSuffix ".jpeg" relativePath then "image/jpeg" else if lib.hasSuffix ".gif" relativePath then "image/gif" else if lib.hasSuffix ".webp" relativePath then "image/webp" else if lib.hasSuffix ".ico" relativePath then "image/x-icon" else if lib.hasSuffix ".txt" relativePath then "text/plain" else if lib.hasSuffix ".xml" relativePath then "application/xml" else if lib.hasSuffix ".pdf" relativePath then "application/pdf" else if lib.hasSuffix ".wasm" relativePath then "application/wasm" else "application/octet-stream"; mkStorePath = storeName: rootPath: builtins.path { path = rootPath; name = "web-store-${storeName}"; }; mkStoreFileEntries = storeName: store: let storeRoot = mkStorePath storeName store.root; files = findFiles storeRoot; mkFileEntry = filePath: let filePathString = toString filePath; relative = trimLeadingSlash (stripPrefix (toString storeRoot) filePathString); in { path = relative; filePath = filePath; contentType = detectContentType relative; status = 200; }; entries = map mkFileEntry files; sortedEntries = builtins.sort (a: b: a.path < b.path) entries; paths = map (entry: entry.path) sortedEntries; uniquePaths = lib.unique paths; _ = if builtins.length paths == builtins.length uniquePaths then null else throw "config/web.nix store '${storeName}' produces duplicate relative file paths in root '${toString store.root}'."; in sortedEntries; storeFilesByName = lib.mapAttrs mkStoreFileEntries stores; storePayloads = lib.mapAttrs (_: files: { type = "store"; files = files; }) storeFilesByName; in rec { inherit stores storeFilesByName storePayloads; }