milestone 8: web server, rest api, sse, auth, metrics and static assets

This commit is contained in:
2026-08-02 00:54:13 +02:00
parent a8092bb1b9
commit 5253c47303
59 changed files with 19640 additions and 150 deletions
+44 -2
View File
@@ -21,6 +21,14 @@ pub fn build(b: *std.Build) void {
const fuzz = b.option(bool, "fuzz", "Build the fuzz targets with the LLVM backend (required for --fuzz)") orelse false;
const version_string = b.option([]const u8, "version-string", "Version reported by `nxdns version`") orelse "0.1.0-dev";
const git_commit = b.option([]const u8, "git-commit", "Git commit reported by `nxdns version`") orelse "unknown";
const web_dist = b.option([]const u8, "web-dist", "Built web UI directory to embed (default: the placeholder page)") orelse "web/dist-placeholder";
// `b.path` panics on absolute paths, and a CI artifact directory is one.
const web_dist_path: std.Build.LazyPath = if (std.fs.path.isAbsolute(web_dist))
.{ .cwd_relative = web_dist }
else
b.path(web_dist);
const web_assets = webAssetsIndex(b, web_dist_path);
const options = b.addOptions();
options.addOption(bool, "integration", integration);
@@ -29,7 +37,7 @@ pub fn build(b: *std.Build) void {
options.addOption([]const u8, "git_commit", git_commit);
options.addOption([]const u8, "zig_version_string", builtin.zig_version_string);
const exe = addExecutable(b, target, optimize, options);
const exe = addExecutable(b, target, optimize, options, web_assets);
b.installArtifact(exe);
const run = b.addRunArtifact(exe);
@@ -53,6 +61,7 @@ pub fn build(b: *std.Build) void {
tests.root_module.addAnonymousImport("test_fixtures", .{
.root_source_file = b.path("tests/fixtures/fixtures.zig"),
});
tests.root_module.addAnonymousImport("web_assets", .{ .root_source_file = web_assets });
const test_step = b.step("test", "Run the test suite");
test_step.dependOn(&b.addRunArtifact(tests).step);
@@ -102,7 +111,7 @@ pub fn build(b: *std.Build) void {
const query = std.Target.Query.parse(.{ .arch_os_abi = triple }) catch |err| {
std.debug.panic("invalid cross target '{s}': {t}", .{ triple, err });
};
const cross_exe = addExecutable(b, b.resolveTargetQuery(query), optimize, options);
const cross_exe = addExecutable(b, b.resolveTargetQuery(query), optimize, options, web_assets);
cross_exe.linkage = .static;
const install = b.addInstallArtifact(cross_exe, .{
.dest_dir = .{ .override = .{ .custom = b.fmt("cross/{s}", .{triple}) } },
@@ -116,6 +125,7 @@ fn addExecutable(
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
options: *std.Build.Step.Options,
web_assets: std.Build.LazyPath,
) *std.Build.Step.Compile {
const exe = b.addExecutable(.{
.name = "nxdns",
@@ -127,11 +137,43 @@ fn addExecutable(
}),
});
exe.root_module.addOptions("build_options", options);
exe.root_module.addAnonymousImport("web_assets", .{ .root_source_file = web_assets });
exe.root_module.linkLibrary(sqliteLibrary(b, target, optimize));
exe.root_module.linkLibrary(mbedtlsLibrary(b, target, optimize));
return exe;
}
/// The embedded web UI (milestone-8 ruling 24): the dist directory plus the
/// generated `assets.zig` index and build-time gzip siblings, merged into one
/// WriteFiles directory so every `@embedFile` path resolves inside the module
/// root. Returns the index file, the root of the `web_assets` module.
///
/// The dist is staged through its own WriteFiles step before it reaches the
/// tool because a Run step hashes only the resolved path string of a directory
/// argument, not its contents; the staged copy lives at a content-hashed path,
/// so editing an asset re-runs the tool instead of replaying a stale cache.
fn webAssetsIndex(b: *std.Build, dist: std.Build.LazyPath) std.Build.LazyPath {
const staged = b.addWriteFiles().addCopyDirectory(dist, ".", .{});
const tool = b.addExecutable(.{
.name = "gen_web_assets",
.root_module = b.createModule(.{
.root_source_file = b.path("tools/gen_web_assets.zig"),
.target = b.graph.host,
.optimize = .ReleaseSafe,
}),
});
const run = b.addRunArtifact(tool);
run.addDirectoryArg(staged);
const generated = run.addOutputDirectoryArg("web_assets");
const merged = b.addWriteFiles();
_ = merged.addCopyDirectory(staged, ".", .{});
_ = merged.addCopyDirectory(generated, ".", .{});
return merged.getDirectory().path(b, "assets.zig");
}
/// SQLite 3.53.4 amalgamation (see build.zig.zon for the pinned URL and hash).
fn sqliteLibrary(
b: *std.Build,