fix: harden UCE runtime and starter

This commit is contained in:
udo
2026-06-11 13:44:24 +00:00
parent 71ddcaf7d4
commit 7f757654b6
128 changed files with 276200 additions and 872 deletions
@@ -1,9 +1,8 @@
#load "../../lib/app.uce"
RENDER(Request& context)
COMPONENT(Request& context)
{
starter_boot(context);
context.call["starter"]["page_title"] = "Login";
context.call["app"]["page_title"] = "Login";
StarterUser users(context);
DTree result;
if(context.params["REQUEST_METHOD"] == "POST")
@@ -11,7 +10,7 @@ RENDER(Request& context)
result = users.sign_in(context.post["email"], context.post["password"]);
if(result["result"].to_string() != "")
{
starter_redirect("account/profile", context);
redirect(app_link("account/profile", context));
return;
}
}
@@ -23,6 +22,6 @@ RENDER(Request& context)
<label>Password: <input type="password" name="password" required></label><br>
<button type="submit">Login</button>
</form>
<p><a href="<?= starter_link("account/register", context) ?>">Register</a></p>
<p><a href="<?= app_link("account/register", context) ?>">Register</a></p>
</>
}
@@ -1,8 +1,7 @@
#load "../../lib/app.uce"
RENDER(Request& context)
COMPONENT(Request& context)
{
starter_boot(context);
StarterUser(context).logout();
starter_redirect("account/login", context);
redirect(app_link("account/login", context));
}
@@ -1,15 +1,14 @@
#load "../../lib/app.uce"
RENDER(Request& context)
COMPONENT(Request& context)
{
starter_boot(context);
StarterUser users(context);
if(!users.is_signed_in())
{
starter_redirect("account/login", context);
redirect(app_link("account/login", context));
return;
}
context.call["starter"]["page_title"] = "Profile";
context.call["app"]["page_title"] = "Profile";
DTree user = users.current();
String roles = "";
user["roles"].each([&](DTree role, String key) {
@@ -22,6 +21,6 @@ RENDER(Request& context)
<p>Email: <?= user["email"].to_string() ?></p>
<p>Roles: <?= roles ?></p>
<p>Created: <?= time_format_local("%Y-%m-%dT%H:%M:%S", int_val(user["created"].to_string())) ?></p>
<p><a href="<?= starter_link("account/logout", context) ?>">Logout</a></p>
<p><a href="<?= app_link("account/logout", context) ?>">Logout</a></p>
</>
}
@@ -1,9 +1,8 @@
#load "../../lib/app.uce"
RENDER(Request& context)
COMPONENT(Request& context)
{
starter_boot(context);
context.call["starter"]["page_title"] = "Register";
context.call["app"]["page_title"] = "Register";
StarterUser users(context);
DTree result;
if(context.params["REQUEST_METHOD"] == "POST")
@@ -11,7 +10,7 @@ RENDER(Request& context)
<>
<h1>Register</h1>
<? if(result["result"].to_string() != "") { ?><div class="banner success">Registration successful. <a href="<?= starter_link("account/login", context) ?>">Log in</a></div><? } ?>
<? if(result["result"].to_string() != "") { ?><div class="banner success">Registration successful. <a href="<?= app_link("account/login", context) ?>">Log in</a></div><? } ?>
<? if(result["message"].to_string() != "" && result["result"].to_string() == "") { ?><div class="banner error"><?= result["message"].to_string() ?></div><? } ?>
<form method="post">
<label>Email: <input type="email" name="email" required></label><br>
@@ -1,9 +1,8 @@
#load "../../lib/app.uce"
RENDER(Request& context)
COMPONENT(Request& context)
{
starter_boot(context);
context.call["starter"]["page_title"] = "OAuth Callback";
context.call["app"]["page_title"] = "OAuth Callback";
String code = context.get["code"];
String state = context.get["state"];
String error = context.get["error"];
@@ -18,8 +17,8 @@ RENDER(Request& context)
<h2>Authentication Failed</h2>
<p><?= first(error_description, error) ?></p>
<div class="callback-actions">
<a href="<?= starter_link("auth/demo", context) ?>" class="btn btn-primary">Try Again</a>
<a href="<?= starter_link("", context) ?>" class="btn btn-outline">Go Home</a>
<a href="<?= app_link("auth/demo", context) ?>" class="btn btn-primary">Try Again</a>
<a href="<?= app_link("", context) ?>" class="btn btn-outline">Go Home</a>
</div>
</div>
<? } else if(code != "" && state != "") { ?>
@@ -33,8 +32,8 @@ RENDER(Request& context)
<p><strong>State:</strong> <?= state ?></p>
</div>
<div class="callback-actions">
<a href="<?= starter_link("auth/demo", context) ?>" class="btn btn-primary">Back to Auth Demo</a>
<a href="<?= starter_link("", context) ?>" class="btn btn-outline">Go Home</a>
<a href="<?= app_link("auth/demo", context) ?>" class="btn btn-primary">Back to Auth Demo</a>
<a href="<?= app_link("", context) ?>" class="btn btn-outline">Go Home</a>
</div>
</div>
<? } else { ?>
@@ -1,10 +1,11 @@
#load "../../lib/app.uce"
RENDER(Request& context)
COMPONENT(Request& context)
{
starter_boot(context);
context.call["starter"]["page_title"] = "Auth";
starter_register_css("views/marketing.css", context);
DTree asset_props;
asset_props["css"]["0"] = "views/marketing.css";
print(component("../../components/theme/assets", asset_props, context));
context.call["app"]["page_title"] = "Auth";
DTree props;
props["title"] = "Sign In to Your Account";
@@ -13,7 +14,7 @@ RENDER(Request& context)
props["github_client_id"] = "YOUR_GITHUB_CLIENT_ID";
props["discord_client_id"] = "YOUR_DISCORD_CLIENT_ID";
props["twitch_client_id"] = "YOUR_TWITCH_CLIENT_ID";
props["callback_url"] = starter_link("auth/callback", context);
props["callback_url"] = app_link("auth/callback", context);
<>
<h1>Authentication Demo</h1>
@@ -1,21 +1,24 @@
#load "../../lib/app.uce"
RENDER(Request& context)
COMPONENT(Request& context)
{
starter_boot(context);
context.call["starter"]["page_type"] = "json";
context.call["app"]["page_type"] = "json";
DTree response;
DTree body = json_decode(context.in);
if(context.params["REQUEST_METHOD"] == "POST" && body["oauth_service"].to_string() != "" && body["oauth_state"].to_string() != "")
{
context.session["oauth_service"] = body["oauth_service"].to_string();
context.session["oauth_state"] = body["oauth_state"].to_string();
context.call["starter"]["json"]["status"] = "success";
response["status"] = "success";
}
else
{
context.set_status(400, "Bad Request");
context.call["starter"]["json"]["status"] = "error";
context.call["starter"]["json"]["message"] = "Invalid input";
response["status"] = "error";
response["message"] = "Invalid input";
}
print(json_encode(response));
}
@@ -1,10 +1,13 @@
#load "../lib/app.uce"
RENDER(Request& context)
ONCE(Request& context)
{
starter_boot(context);
context.call["starter"]["page_title"] = "Dashboard";
starter_register_css("views/dashboard.css", context);
?><link rel="stylesheet" href="<?= app_asset_url("views/dashboard.css", context) ?>" /><?
}
COMPONENT(Request& context)
{
context.call["app"]["page_title"] = "Dashboard";
DTree props;
DTree item;
+5 -4
View File
@@ -1,10 +1,11 @@
#load "../lib/app.uce"
RENDER(Request& context)
COMPONENT(Request& context)
{
starter_boot(context);
context.call["starter"]["page_title"] = "Features";
starter_register_css("views/marketing.css", context);
DTree asset_props;
asset_props["css"]["0"] = "views/marketing.css";
print(component("../components/theme/assets", asset_props, context));
context.call["app"]["page_title"] = "Features";
<>
<h1>Features</h1>
<p class="card">This page exists in the UCE port so the starter menu resolves cleanly as a full route, while still reusing the same marketing components as the home page.</p>
+2 -4
View File
@@ -1,10 +1,8 @@
#load "../lib/app.uce"
RENDER(Request& context)
COMPONENT(Request& context)
{
starter_boot(context);
context.call["starter"]["page_title"] = "Gauges";
starter_register_css("themes/common/css/gauges.css", context);
context.call["app"]["page_title"] = "Gauges";
f64 pi = 3.14159265358979323846;
DTree props;
+14 -6
View File
@@ -1,10 +1,11 @@
#load "../lib/app.uce"
RENDER(Request& context)
COMPONENT(Request& context)
{
starter_boot(context);
context.call["starter"]["page_title"] = "Home";
starter_register_css("views/marketing.css", context);
DTree asset_props;
asset_props["css"]["0"] = "views/marketing.css";
print(component("../components/theme/assets", asset_props, context));
context.call["app"]["page_title"] = "Home";
DTree props;
@@ -79,13 +80,13 @@ RENDER(Request& context)
?><div class="component-card">
<h3><?= theme["label"].to_string() ?></h3>
<p><?= theme["description"].to_string() ?></p>
<a class="btn" href="<?= starter_link("themes", theme_params, context) ?>">Preview Theme</a>
<a class="btn" href="<?= app_link("themes", theme_params, context) ?>">Preview Theme</a>
</div><?
}); ?>
<div class="component-card">
<h3>Starter Themes</h3>
<p>The original light and dark starter skins remain available in the same gallery for side-by-side checks.</p>
<a class="btn btn-secondary" href="<?= starter_link("themes", context) ?>">Open Gallery</a>
<a class="btn btn-secondary" href="<?= app_link("themes", context) ?>">Open Gallery</a>
</div>
</div>
</div>
@@ -98,9 +99,16 @@ RENDER(Request& context)
props["secondary_text"] = "View GitHub";
print(component("../components/example/marketing_blocks:CTA_SECTION", props, context));
DTree island_props;
island_props["name"] = "StarterGuidelines";
island_props["id"] = "starter-guidelines-island";
island_props["props"]["route"] = context.call["route"]["l_path"].to_string();
island_props["props"]["enhancement"] = "progressive";
<>
<div class="card">
<h2>Component Development Guidelines</h2>
<?: component("../components/theme/web_affordances:island", island_props, context) ?>
<div class="guidelines-grid">
<div class="guideline-item" style="border-left-color: var(--primary);"><span class="guideline-icon">🏷️</span><span>Use semantic HTML5 elements</span></div>
<div class="guideline-item" style="border-left-color: var(--secondary);"><span class="guideline-icon">🎨</span><span>Implement CSS custom properties for theming</span></div>
+5 -4
View File
@@ -1,10 +1,11 @@
#load "../lib/app.uce"
RENDER(Request& context)
COMPONENT(Request& context)
{
starter_boot(context);
context.call["starter"]["page_title"] = "Components";
starter_register_css("views/marketing.css", context);
DTree asset_props;
asset_props["css"]["0"] = "views/marketing.css";
print(component("../components/theme/assets", asset_props, context));
context.call["app"]["page_title"] = "Components";
<>
<h1>Component System</h1>
@@ -1,9 +1,8 @@
#load "../lib/app.uce"
RENDER(Request& context)
COMPONENT(Request& context)
{
starter_boot(context);
context.call["starter"]["page_type"] = "blank";
context.call["app"]["page_type"] = "blank";
<>
<?= std::to_string((u64)time()) ?> - Page 2 Section 1 loaded
<pre>UCE starter AJAX fragment response</pre>
+3 -4
View File
@@ -1,16 +1,15 @@
#load "../lib/app.uce"
RENDER(Request& context)
COMPONENT(Request& context)
{
starter_boot(context);
context.call["starter"]["page_title"] = "Ajaxy";
context.call["app"]["page_title"] = "Ajaxy";
<>
<h1>Ajax Demo</h1>
<div id="page2-section1">
<p>This is the content of Page 2. You can add more information here.</p>
<p>Sed at dolor leo. Morbi a tellus sed nisl dictum ultricies sit amet at purus. Nam mattis metus sed nunc egestas convallis.</p>
<br/>
<button id="page2-load-button" data-load-url="<?= starter_link("page2-section1", context) ?>" type="button">Load new text</button>
<button id="page2-load-button" data-load-url="<?= app_link("page2-section1", context) ?>" type="button">Load new text</button>
</div>
<script>
(function () {
@@ -1,10 +1,11 @@
#load "../lib/app.uce"
RENDER(Request& context)
COMPONENT(Request& context)
{
starter_boot(context);
context.call["starter"]["page_title"] = "Theme Preview";
starter_register_css("views/themes.css", context);
DTree asset_props;
asset_props["css"]["0"] = "views/themes.css";
print(component("../components/theme/assets", asset_props, context));
context.call["app"]["page_title"] = "Theme Preview";
String current_theme_key = context.cfg.get_by_path("theme/key").to_string();
String theme_label = first(context.cfg.get_by_path("theme/label").to_string(), current_theme_key);
String theme_mode = context.cfg.get_by_path("theme/mode").to_string();
@@ -18,8 +19,8 @@ RENDER(Request& context)
<h1><?= theme_label ?></h1>
<p>This route renders the same neutral content inside each theme so downstream projects can compare layout, typography, color tokens, and chrome.</p>
<div class="theme-preview-actions">
<a class="btn" href="<?= starter_link("themes", theme_params, context) ?>">Back to Gallery</a>
<a class="btn btn-secondary" href="<?= starter_link("", theme_params, context) ?>">Open Home in This Theme</a>
<a class="btn" href="<?= app_link("themes", theme_params, context) ?>">Back to Gallery</a>
<a class="btn btn-secondary" href="<?= app_link("", theme_params, context) ?>">Open Home in This Theme</a>
</div>
</section>
<section class="theme-preview-grid">
@@ -59,7 +60,6 @@ RENDER(Request& context)
<tbody>
<tr><td>Navigation</td><td>Should remain readable when menus get long.</td><td>Verified</td></tr>
<tr><td>Cards</td><td>Should keep spacing and hierarchy on both desktop and mobile.</td><td>Verified</td></tr>
<tr><td>Embeds</td><td>Should render cleanly inside the gallery iframe.</td><td>Verified</td></tr>
</tbody>
</table>
</div>
@@ -82,21 +82,6 @@
margin-bottom: 1rem;
}
.theme-gallery-frame-wrap {
border: 1px solid var(--border);
border-radius: calc(var(--radius-lg, var(--radius)) - 4px);
overflow: hidden;
background: var(--bg-secondary);
}
.theme-gallery-frame-wrap iframe {
display: block;
width: 100%;
height: 430px;
border: 0;
background: #fff;
}
.theme-preview-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
@@ -150,20 +135,6 @@
gap: 0.85rem;
}
.embed-mode nav,
.embed-mode footer,
.embed-mode #theme-switcher,
.embed-mode .admin-toolbar {
display: none !important;
}
.embed-mode #content,
.embed-mode .admin-content {
margin-top: 0 !important;
min-height: 100vh !important;
padding-top: 1rem !important;
}
@media (max-width: 720px) {
.theme-gallery-grid,
.theme-preview-grid {
@@ -173,8 +144,4 @@
.theme-gallery-head {
flex-direction: column;
}
.theme-gallery-frame-wrap iframe {
height: 360px;
}
}
+9 -13
View File
@@ -1,26 +1,25 @@
#load "../lib/app.uce"
RENDER(Request& context)
COMPONENT(Request& context)
{
starter_boot(context);
context.call["starter"]["page_title"] = "Themes";
starter_register_css("views/themes.css", context);
DTree asset_props;
asset_props["css"]["0"] = "views/themes.css";
print(component("../components/theme/assets", asset_props, context));
context.call["app"]["page_title"] = "Themes";
String current_theme = context.cfg.get_by_path("theme/key").to_string();
<>
<div class="theme-gallery-shell">
<section class="theme-gallery-hero card">
<span class="theme-gallery-kicker">Starter Theme Gallery</span>
<h1>Compare Themes Side by Side</h1>
<p>The gallery renders the same preview content in each theme family. This makes it easier to judge shell fit, typography, token balance, and embed behavior.</p>
<h1>Compare Themes</h1>
<p>Open each theme preview directly to judge shell fit, typography, and token balance.</p>
</section>
<div class="theme-gallery-grid">
<? context.cfg.get_by_path("theme/options").each([&](DTree theme_info, String theme_key) {
StringMap params;
params["theme"] = theme_key;
String preview_href = starter_link("theme-preview", params, context);
params["embed"] = "1";
String iframe_href = starter_link("theme-preview", params, context);
String preview_href = app_link("theme-preview", params, context);
StringMap home_params;
home_params["theme"] = theme_key;
?><section class="theme-gallery-card<?= theme_key == current_theme ? " is-active" : "" ?>">
@@ -33,10 +32,7 @@ RENDER(Request& context)
</div>
<div class="theme-gallery-actions">
<a class="btn" href="<?= preview_href ?>">Open Preview</a>
<a class="btn btn-secondary" href="<?= starter_link("", home_params, context) ?>">Open Home</a>
</div>
<div class="theme-gallery-frame-wrap">
<iframe title="<?= theme_info["label"].to_string() ?> preview" src="<?= iframe_href ?>"></iframe>
<a class="btn btn-secondary" href="<?= app_link("", home_params, context) ?>">Open Home</a>
</div>
</section><?
}); ?>
@@ -1,10 +1,9 @@
#load "../../lib/app.uce"
RENDER(Request& context)
COMPONENT(Request& context)
{
starter_boot(context);
context.call["starter"]["page_title"] = "Workspace";
String section = first(context.call["starter"]["route"]["param"].to_string(), "overview");
context.call["app"]["page_title"] = "Workspace";
String section = first(context.call["route"]["param"].to_string(), "overview");
if(section != "overview" && section != "projects" && section != "activity")
section = "overview";
@@ -19,9 +18,9 @@ RENDER(Request& context)
<>
<div class="ws-nav-group-label">Workspace areas</div>
<div class="ws-nav-list">
<a class="ws-nav-item<?= section == "overview" ? " is-active" : "" ?>" href="<?= starter_link("workspace/overview", context) ?>"><span class="ws-nav-item-inner"><span class="ws-nav-icon"><i class="fas fa-compass"></i></span><span class="ws-nav-item-text"><span class="ws-nav-title">Overview</span><span class="ws-nav-meta">Shell</span></span></span></a>
<a class="ws-nav-item<?= section == "projects" ? " is-active" : "" ?>" href="<?= starter_link("workspace/projects", context) ?>"><span class="ws-nav-item-inner"><span class="ws-nav-icon"><i class="fas fa-folder-tree"></i></span><span class="ws-nav-item-text"><span class="ws-nav-title">Projects</span><span class="ws-nav-meta">Routes</span></span></span></a>
<a class="ws-nav-item<?= section == "activity" ? " is-active" : "" ?>" href="<?= starter_link("workspace/activity", context) ?>"><span class="ws-nav-item-inner"><span class="ws-nav-icon"><i class="fas fa-wave-square"></i></span><span class="ws-nav-item-text"><span class="ws-nav-title">Activity</span><span class="ws-nav-meta">State</span></span></span></a>
<a class="ws-nav-item<?= section == "overview" ? " is-active" : "" ?>" href="<?= app_link("workspace/overview", context) ?>"><span class="ws-nav-item-inner"><span class="ws-nav-icon"><i class="fas fa-compass"></i></span><span class="ws-nav-item-text"><span class="ws-nav-title">Overview</span><span class="ws-nav-meta">Shell</span></span></span></a>
<a class="ws-nav-item<?= section == "projects" ? " is-active" : "" ?>" href="<?= app_link("workspace/projects", context) ?>"><span class="ws-nav-item-inner"><span class="ws-nav-icon"><i class="fas fa-folder-tree"></i></span><span class="ws-nav-item-text"><span class="ws-nav-title">Projects</span><span class="ws-nav-meta">Routes</span></span></span></a>
<a class="ws-nav-item<?= section == "activity" ? " is-active" : "" ?>" href="<?= app_link("workspace/activity", context) ?>"><span class="ws-nav-item-inner"><span class="ws-nav-icon"><i class="fas fa-wave-square"></i></span><span class="ws-nav-item-text"><span class="ws-nav-title">Activity</span><span class="ws-nav-meta">State</span></span></span></a>
</div>
<div class="ws-demo-sidebar-copy"><p>This sidebar and mobile shell pattern was extracted from the AI portal app and normalized against starter theme tokens.</p></div>
</>
@@ -32,7 +31,7 @@ RENDER(Request& context)
sidebar_body += component("../../components/workspace/primitives:LIST_STATE", sidebar_note, context);
DTree toolbar_props;
toolbar_props["action_html"] = "<a class=\"ws-sidebar-action-btn\" href=\"" + starter_link("workspace/overview", context) + "\"><i class=\"fas fa-grid-2\"></i><span>Open shell</span></a>";
toolbar_props["action_html"] = "<a class=\"ws-sidebar-action-btn\" href=\"" + app_link("workspace/overview", context) + "\"><i class=\"fas fa-grid-2\"></i><span>Open shell</span></a>";
toolbar_props["search_input_id"] = "workspace-demo-search";
toolbar_props["search_input_name"] = "workspace_demo_search";
toolbar_props["search_placeholder"] = "Search workspace sections";
@@ -95,7 +94,7 @@ RENDER(Request& context)
String demo_head = component("../../components/workspace/primitives:SECTION_HEAD", section_head, context);
section_props.clear();
section_props["header_html"] = demo_head;
section_props["body_html"] = detail_html + "<p class=\"ws-inline-note\">Try visiting <strong>" + html_escape(starter_link("workspace/projects", context)) + "</strong> or <strong>" + html_escape(starter_link("workspace/activity", context)) + "</strong> to see the nested route fallback in action.</p>";
section_props["body_html"] = detail_html + "<p class=\"ws-inline-note\">Try visiting <strong>" + html_escape(app_link("workspace/projects", context)) + "</strong> or <strong>" + html_escape(app_link("workspace/activity", context)) + "</strong> to see the nested route fallback in action.</p>";
main_body += component("../../components/workspace/primitives:SECTION", section_props, context);
if(section == "activity")
@@ -104,7 +103,7 @@ RENDER(Request& context)
empty_props["icon_class"] = "fas fa-clock-rotate-left";
empty_props["title"] = "No live stream wired yet";
empty_props["text"] = "The shell is generic. Add your own websocket, polling, or event-driven runtime behind it when a real product needs one.";
empty_props["action_html"] = "<a class=\"ws-primary-btn\" href=\"" + starter_link("dashboard", context) + "\">Open dashboard demo</a>";
empty_props["action_html"] = "<a class=\"ws-primary-btn\" href=\"" + app_link("dashboard", context) + "\">Open dashboard demo</a>";
main_body += component("../../components/workspace/primitives:EMPTY_STATE", empty_props, context);
}