rename web/ to admin/, along with the web-named build and cli identifiers
This commit is contained in:
+4
-4
@@ -658,10 +658,10 @@ fn serve(r: cli.Runner, args: cli.RunArgs) !u8 {
|
||||
.querylog_db = if (web_querylog_db) |*database| database else null,
|
||||
.version = version.string,
|
||||
.started_unix = std.Io.Clock.real.now(io).toSeconds(),
|
||||
// Ruling 24: `--web-dev` serves from disk with no cache headers;
|
||||
// Ruling 24: `--admin-dev` serves from disk with no cache headers;
|
||||
// otherwise the embedded assets answer every non-/api miss.
|
||||
.fallback = if (args.web_dev != null) serveWebDev else static.fallback,
|
||||
.dev_dir = args.web_dev orelse "",
|
||||
.fallback = if (args.admin_dev != null) serveAdminDev else static.fallback,
|
||||
.dev_dir = args.admin_dev orelse "",
|
||||
.reload_fn = reloadManager,
|
||||
};
|
||||
|
||||
@@ -799,7 +799,7 @@ fn reloadManager(state: *web_server.WebState, io: std.Io) anyerror!void {
|
||||
|
||||
/// Dev-mode asset serving (ruling 24): straight from disk, no cache headers,
|
||||
/// so an edit shows up on the next reload.
|
||||
fn serveWebDev(
|
||||
fn serveAdminDev(
|
||||
state: *web_server.WebState,
|
||||
io: std.Io,
|
||||
request: *http_util.Request,
|
||||
|
||||
+17
-17
@@ -69,12 +69,12 @@ pub const ImportArgs = struct { paths: Paths = .{}, file: []const u8, allow_dele
|
||||
/// makes that file the sole declarative source of truth: it is read, validated
|
||||
/// and reconciled into the database on every start.
|
||||
///
|
||||
/// `web_dev` is milestone-8 ruling 24's `--web-dev <dir>`: serve the web
|
||||
/// `admin_dev` is milestone-8 ruling 24's `--admin-dev <dir>`: serve the web
|
||||
/// interface from that directory instead of the embedded assets.
|
||||
pub const RunArgs = struct {
|
||||
paths: Paths = .{},
|
||||
config: ?[]const u8 = null,
|
||||
web_dev: ?[]const u8 = null,
|
||||
admin_dev: ?[]const u8 = null,
|
||||
};
|
||||
|
||||
pub const Command = union(enum) {
|
||||
@@ -179,7 +179,7 @@ fn flagValue(flag: Flag, argv: []const []const u8, i: *usize) ParseError![]const
|
||||
return argv[i.*];
|
||||
}
|
||||
|
||||
/// `run` takes `check`'s two flags plus `--web-dev`, which only a process that
|
||||
/// `run` takes `check`'s two flags plus `--admin-dev`, which only a process that
|
||||
/// serves has any use for; `check` deliberately rejects it.
|
||||
fn parseRunArgs(argv: []const []const u8) ParseError!RunArgs {
|
||||
var args: RunArgs = .{};
|
||||
@@ -190,8 +190,8 @@ fn parseRunArgs(argv: []const []const u8) ParseError!RunArgs {
|
||||
args.paths.data_dir = try flagValue(flag, argv, &i);
|
||||
} else if (eql(flag.name, "config")) {
|
||||
args.config = try flagValue(flag, argv, &i);
|
||||
} else if (eql(flag.name, "web-dev")) {
|
||||
args.web_dev = try flagValue(flag, argv, &i);
|
||||
} else if (eql(flag.name, "admin-dev")) {
|
||||
args.admin_dev = try flagValue(flag, argv, &i);
|
||||
} else return error.UnknownFlag;
|
||||
}
|
||||
return args;
|
||||
@@ -396,7 +396,7 @@ const usage_text =
|
||||
\\ check: grade FILE instead of the database
|
||||
\\ --out FILE write the export to FILE instead of stdout
|
||||
\\ --allow-delete let import apply a file whose diff deletes rows
|
||||
\\ --web-dev DIR run only: serve the web interface from DIR instead of
|
||||
\\ --admin-dev DIR run only: serve the web interface from DIR instead of
|
||||
\\ the embedded assets
|
||||
\\
|
||||
;
|
||||
@@ -1030,7 +1030,7 @@ test "run without --config selects database authority" {
|
||||
const command = try parseArgs(&.{"run"});
|
||||
try testing.expectEqualStrings("/var/lib/nxdns", command.run.paths.data_dir);
|
||||
try testing.expectEqual(@as(?[]const u8, null), command.run.config);
|
||||
try testing.expectEqual(@as(?[]const u8, null), command.run.web_dev);
|
||||
try testing.expectEqual(@as(?[]const u8, null), command.run.admin_dev);
|
||||
}
|
||||
|
||||
test "run --config selects file authority and the path lands in the run args" {
|
||||
@@ -1042,19 +1042,19 @@ test "run --config selects file authority and the path lands in the run args" {
|
||||
try testing.expectEqualStrings("/tmp/c.zon", command.run.config.?);
|
||||
}
|
||||
|
||||
test "parseArgs accepts run with --web-dev in both spellings" {
|
||||
const attached = try parseArgs(&.{ "run", "--web-dev=web/dist" });
|
||||
try testing.expectEqualStrings("web/dist", attached.run.web_dev.?);
|
||||
test "parseArgs accepts run with --admin-dev in both spellings" {
|
||||
const attached = try parseArgs(&.{ "run", "--admin-dev=admin/dist" });
|
||||
try testing.expectEqualStrings("admin/dist", attached.run.admin_dev.?);
|
||||
|
||||
const separate = try parseArgs(&.{ "run", "--web-dev", "web/dist" });
|
||||
try testing.expectEqualStrings("web/dist", separate.run.web_dev.?);
|
||||
const separate = try parseArgs(&.{ "run", "--admin-dev", "admin/dist" });
|
||||
try testing.expectEqualStrings("admin/dist", separate.run.admin_dev.?);
|
||||
}
|
||||
|
||||
test "parseArgs rejects --web-dev without a value and outside run" {
|
||||
try testing.expectError(error.MissingValue, parseArgs(&.{ "run", "--web-dev" }));
|
||||
try testing.expectError(error.MissingValue, parseArgs(&.{ "run", "--web-dev=" }));
|
||||
try testing.expectError(error.UnknownFlag, parseArgs(&.{ "check", "--web-dev", "web/dist" }));
|
||||
try testing.expectError(error.UnknownFlag, parseArgs(&.{ "export", "--web-dev", "web/dist" }));
|
||||
test "parseArgs rejects --admin-dev without a value and outside run" {
|
||||
try testing.expectError(error.MissingValue, parseArgs(&.{ "run", "--admin-dev" }));
|
||||
try testing.expectError(error.MissingValue, parseArgs(&.{ "run", "--admin-dev=" }));
|
||||
try testing.expectError(error.UnknownFlag, parseArgs(&.{ "check", "--admin-dev", "admin/dist" }));
|
||||
try testing.expectError(error.UnknownFlag, parseArgs(&.{ "export", "--admin-dev", "admin/dist" }));
|
||||
}
|
||||
|
||||
test "parseArgs accepts --data-dir with and without an equals sign" {
|
||||
|
||||
+13
-13
@@ -22,9 +22,9 @@
|
||||
//! the assembled notices — says which artifacts the file speaks for.
|
||||
//!
|
||||
//! One question is out of reach here and lives in `gates.yml` instead: which
|
||||
//! packages actually contribute a module to `web/dist`. Answering it means
|
||||
//! packages actually contribute a module to `admin/dist`. Answering it means
|
||||
//! running the bundler. The frontend gate does that, compares the result with
|
||||
//! the `[npm packages bundled into web/dist]` section, and this file checks the
|
||||
//! the `[npm packages bundled into admin/dist]` section, and this file checks the
|
||||
//! inventory against that same section.
|
||||
//!
|
||||
//! Everything is embedded at compile time through the `licenses_files` module:
|
||||
@@ -35,27 +35,27 @@ const builtin = @import("builtin");
|
||||
const licenses = @import("licenses_files");
|
||||
|
||||
/// The npm packages that are `devDependencies` in the lockfile but whose own
|
||||
/// output ends up in `web/dist`, and so in the binary. None of them runs in the
|
||||
/// output ends up in `admin/dist`, and so in the binary. None of them runs in the
|
||||
/// browser; their emitted bytes do.
|
||||
///
|
||||
/// The set was settled by building `web/` with `--sourcemap` and reading two
|
||||
/// The set was settled by building `admin/` with `--sourcemap` and reading two
|
||||
/// things off the result: the sourcemap `sources` lists, which name the
|
||||
/// packages whose modules were bundled, and the regions of each chunk that no
|
||||
/// sourcemap segment maps back to a source file, which are the bytes the
|
||||
/// toolchain injected on its own. Tailwind is here for its generated
|
||||
/// stylesheet; vite for `vite/preload-helper` and `vite/modulepreload-polyfill`;
|
||||
/// rolldown for the CommonJS interop helpers it prepends to any chunk pulling in
|
||||
/// a CommonJS module. Every other devDependency left `web/dist` untouched.
|
||||
/// a CommonJS module. Every other devDependency left `admin/dist` untouched.
|
||||
/// Anything added here must also be inventoried.
|
||||
const npm_generators = [_][]const u8{ "rolldown", "vite" };
|
||||
|
||||
/// Packages of the recorded runtime closure that put no byte in `web/dist`, so
|
||||
/// Packages of the recorded runtime closure that put no byte in `admin/dist`, so
|
||||
/// the inventory names them in a note rather than carrying their licence. The
|
||||
/// note has to exist: each name below must still appear in
|
||||
/// `licenses/inventory.zon`.
|
||||
///
|
||||
/// This list is a claim about the build, and the build is what settles it: a
|
||||
/// name here that turns up in the recorded `web/dist` bundle fails, so a
|
||||
/// name here that turns up in the recorded `admin/dist` bundle fails, so a
|
||||
/// package that starts shipping cannot stay on this list quietly.
|
||||
const npm_not_shipped = [_][]const u8{
|
||||
"cookie-es",
|
||||
@@ -135,7 +135,7 @@ const ZigDependencyVersion = struct {
|
||||
/// on 2026-08-12, and `licenses/react-aria-apache-2.0.txt` carries the text
|
||||
/// Section 4 asks for.
|
||||
///
|
||||
/// Packages that put no byte in `web/dist` are here too. They redistribute
|
||||
/// Packages that put no byte in `admin/dist` are here too. They redistribute
|
||||
/// nothing today, so their licence carries no obligation today — but "not
|
||||
/// shipped" is a claim about the build that a future build can falsify, and
|
||||
/// recording the licence now means the answer is already reviewed when it does.
|
||||
@@ -197,7 +197,7 @@ const zig_section = "[build.zig.zon dependencies]";
|
||||
const npm_section = "[npm runtime closure]";
|
||||
const generator_section = "[npm build-time generators whose output ships]";
|
||||
const base_image_section = "[container base image]";
|
||||
const bundled_section = "[npm packages bundled into web/dist]";
|
||||
const bundled_section = "[npm packages bundled into admin/dist]";
|
||||
|
||||
/// The shape `tools/dist_stage.zig` parses when it assembles
|
||||
/// THIRD-PARTY-NOTICES. Parsing `licenses/inventory.zon` into it here is itself
|
||||
@@ -619,7 +619,7 @@ test "the licence texts that must be reproduced in full are unmodified" {
|
||||
// the recorded list honest against the build; this keeps the inventory honest
|
||||
// against the recorded list. Neither works alone: the gate cannot say what the
|
||||
// inventory covers, and this test cannot run rollup.
|
||||
test "every package bundled into web/dist is inventoried" {
|
||||
test "every package bundled into admin/dist is inventoried" {
|
||||
const gpa = std.testing.allocator;
|
||||
const entries = try parseInventory(gpa);
|
||||
defer std.zon.parse.free(gpa, entries);
|
||||
@@ -632,7 +632,7 @@ test "every package bundled into web/dist is inventoried" {
|
||||
|
||||
if (isNotShipped(name)) {
|
||||
std.debug.print(
|
||||
"npm package '{s}' is in the recorded web/dist bundle but npm_not_shipped still" ++
|
||||
"npm package '{s}' is in the recorded admin/dist bundle but npm_not_shipped still" ++
|
||||
" claims it ships nothing. It does now: inventory it and take it out of that" ++
|
||||
" list.\n",
|
||||
.{name},
|
||||
@@ -642,7 +642,7 @@ test "every package bundled into web/dist is inventoried" {
|
||||
|
||||
if (!inventoryNamesPackage(entries, name)) {
|
||||
std.debug.print(
|
||||
"npm package '{s}' is bundled into web/dist but no licenses/inventory.zon entry" ++
|
||||
"npm package '{s}' is bundled into admin/dist but no licenses/inventory.zon entry" ++
|
||||
" names it\n",
|
||||
.{name},
|
||||
);
|
||||
@@ -1078,7 +1078,7 @@ fn skipWhitespace(text: []const u8, from: usize) usize {
|
||||
|
||||
const NpmSet = enum { runtime, generators };
|
||||
|
||||
/// `name version licence` for every package in `web/package-lock.json` that is
|
||||
/// `name version licence` for every package in `admin/package-lock.json` that is
|
||||
/// not marked `dev`, or for the build-time generators, sorted by name. The
|
||||
/// non-dev set is a superset of what the bundler emits — it cannot run rollup —
|
||||
/// so a new runtime dependency always trips the guard even when tree-shaking
|
||||
|
||||
+1
-1
@@ -180,7 +180,7 @@ pub const WebState = struct {
|
||||
querylog_db: ?*db.Db = null,
|
||||
|
||||
version: []const u8 = "",
|
||||
/// The `--web-dev` asset directory, read by the dev-mode fallback. Empty
|
||||
/// The `--admin-dev` asset directory, read by the dev-mode fallback. Empty
|
||||
/// whenever that fallback is not wired.
|
||||
dev_dir: []const u8 = "",
|
||||
/// Unix seconds at process start, for uptime.
|
||||
|
||||
+10
-10
@@ -1,7 +1,7 @@
|
||||
//! Static asset serving (milestone-8 ruling 24).
|
||||
//!
|
||||
//! Production serves from `web_assets`, the module the build generates from
|
||||
//! `-Dweb-dist`: bytes, content type and a strong ETag per file, plus a
|
||||
//! Production serves from `admin_assets`, the module the build generates from
|
||||
//! `-Dadmin-dist`: bytes, content type and a strong ETag per file, plus a
|
||||
//! `<name>.gz` sibling entry where compressing at build time paid off. Serving
|
||||
//! is a linear scan over a handful of immutable entries — no allocation, no
|
||||
//! clock, no disk.
|
||||
@@ -18,12 +18,12 @@
|
||||
//! ETag so a `304` is always judged against the representation that would be
|
||||
//! served.
|
||||
//!
|
||||
//! Dev mode (`nxdns run --web-dev <dir>`, wired by the CLI) serves from disk
|
||||
//! Dev mode (`nxdns run --admin-dev <dir>`, wired by the CLI) serves from disk
|
||||
//! with no cache headers, so a UI developer sees an edit on reload.
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const assets = @import("web_assets");
|
||||
const assets = @import("admin_assets");
|
||||
const http_util = @import("http_util.zig");
|
||||
const server = @import("server.zig");
|
||||
|
||||
@@ -37,7 +37,7 @@ pub const embedded: []const File = assets.files;
|
||||
pub const index_path = "/index.html";
|
||||
|
||||
/// A disk asset a dev-mode request may read. Matches the embed limit in
|
||||
/// tools/gen_web_assets.zig.
|
||||
/// tools/gen_admin_assets.zig.
|
||||
pub const max_disk_asset_bytes = 64 * 1024 * 1024;
|
||||
|
||||
pub const Selection = struct {
|
||||
@@ -193,7 +193,7 @@ pub fn diskRelativePath(buf: []u8, segments: []const []const u8) ?[]const u8 {
|
||||
return writer.buffered();
|
||||
}
|
||||
|
||||
/// Dev-mode disk serving for `--web-dev` (ruling 24). No cache headers: the
|
||||
/// Dev-mode disk serving for `--admin-dev` (ruling 24). No cache headers: the
|
||||
/// point of the flag is that an edit shows up on the next reload. The CLI
|
||||
/// wiring (W9) closes over the directory and passes it here.
|
||||
pub fn serveFromDisk(
|
||||
@@ -209,8 +209,8 @@ pub fn serveFromDisk(
|
||||
return http_util.respondError(request, .not_found, "not found");
|
||||
|
||||
var dir = std.Io.Dir.cwd().openDir(io, root, .{}) catch |err| {
|
||||
log.warn("web-dev directory '{s}' is unreadable: {t}", .{ root, err });
|
||||
return http_util.respondError(request, .internal_server_error, "web-dev directory unavailable");
|
||||
log.warn("admin-dev directory '{s}' is unreadable: {t}", .{ root, err });
|
||||
return http_util.respondError(request, .internal_server_error, "admin-dev directory unavailable");
|
||||
};
|
||||
defer dir.close(io);
|
||||
|
||||
@@ -233,7 +233,7 @@ fn readDiskFile(
|
||||
return dir.readFileAlloc(io, sub_path, request.arena, .limited(max_disk_asset_bytes)) catch |err| {
|
||||
switch (err) {
|
||||
error.FileNotFound, error.IsDir => {},
|
||||
else => log.warn("web-dev read of '{s}' failed: {t}", .{ sub_path, err }),
|
||||
else => log.warn("admin-dev read of '{s}' failed: {t}", .{ sub_path, err }),
|
||||
}
|
||||
return null;
|
||||
};
|
||||
@@ -255,7 +255,7 @@ fn resolvesUnderRoot(dir: std.Io.Dir, io: std.Io, sub_path: []const u8) bool {
|
||||
}
|
||||
|
||||
/// Extension → MIME type for dev-mode disk serving. The embedded entries carry
|
||||
/// the same mapping, stamped by tools/gen_web_assets.zig; a test below keeps
|
||||
/// the same mapping, stamped by tools/gen_admin_assets.zig; a test below keeps
|
||||
/// the two from drifting.
|
||||
pub fn contentType(path: []const u8) []const u8 {
|
||||
const map = [_]struct { ext: []const u8, mime: []const u8 }{
|
||||
|
||||
Reference in New Issue
Block a user