weeks of bullshit

This commit is contained in:
Relism
2026-04-17 08:18:11 +02:00
parent b5d4481502
commit 9efbe38c0c
157 changed files with 5171 additions and 1273 deletions
@@ -23,7 +23,7 @@ class RouteViewerDataHandler {
Object handle(Request req, Response res) {
if (cachedJson == null) cachedJson = GraphSerializer.toJson(graph);
res.setContentType(ContentType.JSON);
res.type(ContentType.JSON);
res.header("Cache-Control", "no-cache");
return cachedJson;
}
@@ -1,6 +1,7 @@
package dev.relism.ext.routeviewer;
import dev.relism.ext.routeviewer.model.RouteGraph;
import dev.relism.extension.ExtensionPhase;
import dev.relism.extension.FlashContext;
import dev.relism.extension.FlashExtension;
import dev.relism.extension.FlashRegistrar;
@@ -21,22 +22,17 @@ import dev.relism.http.ContentType;
* <li>{@code GET <path>/data} — graph JSON consumed by the SPA</li>
* </ul>
*
* <h3>Install order</h3>
* Install <em>after</em> extensions that register annotation processors
* (e.g. {@code OidcExtension}) but <em>before</em> {@code scan()} or
* {@code register()} calls so the listener captures all routes:
* <p>The route listener is registered during the {@link #provide} phase, before any routes
* are compiled. Combined with the two-phase extension model, this guarantees all routes
* (including those from other extensions) are always captured — install order is irrelevant.
*
* <pre>{@code
* FlashApp.create(8080)
* .install(new OidcExtension(config))
* .install(new JacksonExtension())
* .install(new RouteViewerExtension()) // before scan
* .install(new RouteViewerExtension())
* .scan("dev.example.handlers")
* .start();
* }</pre>
*
* <p>All route metadata is collected once at boot time via
* {@link FlashContext#addRouteListener}. Zero overhead on the request hot-path.
*/
public class RouteViewerExtension implements FlashExtension {
@@ -45,6 +41,9 @@ public class RouteViewerExtension implements FlashExtension {
private final String path;
private final RouteGraph graph = new RouteGraph();
/** Observability — runs last so the viewer sees the complete middleware chain. */
@Override public int priority() { return ExtensionPhase.LATE.value; }
/** Installs the viewer at {@value #DEFAULT_PATH}. */
public RouteViewerExtension() { this(DEFAULT_PATH); }
@@ -55,20 +54,16 @@ public class RouteViewerExtension implements FlashExtension {
public RouteViewerExtension(String path) { this.path = path; }
@Override
public void install(FlashRegistrar app, FlashContext ctx) {
RouteViewerHandler shell = new RouteViewerHandler();
RouteViewerDataHandler data = new RouteViewerDataHandler(graph);
// Static assets (Vite build output, bundled in JAR)
app.get(path, shell::handle);
app.get(path + "/app.js", new RouteViewerStaticHandler("routeviewer/app.js", ContentType.TEXT_JAVASCRIPT)::handle);
app.get(path + "/app.css", new RouteViewerStaticHandler("routeviewer/app.css", ContentType.TEXT_CSS)::handle);
// Graph data API — must be registered before the listener so it is
// flushed and captured AFTER the listener is attached (shows in the graph)
app.get(path + "/data", data::handle);
// Start listening — routes registered after this point are captured
public void provide(FlashContext ctx) {
// Register listener before any routes compile — captures everything.
ctx.addRouteListener(graph::add);
}
@Override
public void routes(FlashRegistrar<?> app, FlashContext ctx) {
app.get(path, new RouteViewerHandler()::handle);
app.get(path + "/app.js", new RouteViewerStaticHandler("routeviewer/app.js", ContentType.TEXT_JAVASCRIPT)::handle);
app.get(path + "/app.css", new RouteViewerStaticHandler("routeviewer/app.css", ContentType.TEXT_CSS)::handle);
app.get(path + "/data", new RouteViewerDataHandler(graph)::handle);
}
}
@@ -25,7 +25,7 @@ class RouteViewerHandler {
Object handle(Request req, Response res) throws IOException {
if (cached == null) cached = load();
res.setContentType(ContentType.TEXT_HTML);
res.type(ContentType.TEXT_HTML);
return cached;
}
@@ -28,11 +28,11 @@ class RouteViewerStaticHandler {
Object handle(Request req, Response res) throws IOException {
if (cached == null) cached = load();
if (cached == null) {
res.setStatusCode(404);
res.status(404);
return null;
}
res.setStatusCode(200);
res.setContentType(contentType);
res.status(200);
res.type(contentType);
res.header("Cache-Control", "public, max-age=3600");
return cached;
}