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
@@ -4,7 +4,7 @@ COMPONENT(Request& context)
{
String title = first(context.props["title"].to_string(), "Sign in with OAuth");
String subtitle = first(context.props["subtitle"].to_string(), "Choose your preferred authentication method");
String callback_url = first(context.props["callback_url"].to_string(), starter_link("auth/callback", context));
String callback_url = first(context.props["callback_url"].to_string(), app_link("auth/callback", context));
DTree services = context.props["services"];
if(services.get_type_name() != "array" || services["google"]["name"].to_string() == "")
@@ -46,7 +46,7 @@ COMPONENT(Request& context)
String service_name = service["name"].to_string();
String scope = service["scope"].to_string();
String auth_url = service["auth_url"].to_string();
String store_url = starter_link("auth/store-oauth-session", context);
String store_url = app_link("auth/store-oauth-session", context);
?><div data-service="<?= service_key ?>">
<button type="button" class="btn" onclick='initiateOAuth_<?= handler_name ?>()'>
<i class="<?= service["icon"].to_string() ?>" style="color: <?= service["color"].to_string() ?>"></i>
@@ -2,7 +2,6 @@
COMPONENT(Request& context)
{
starter_boot(context);
<>
<div id="cookie-consent" style="
@@ -0,0 +1,15 @@
#load "../../lib/app.uce"
COMPONENT(Request& context)
{
String message = first(context.props["message"].to_string(), "The requested page does not exist.");
context.set_status(404, "Not Found");
context.call["app"]["page_title"] = "404 Not Found";
<>
<section class="card">
<h1>404 Not Found</h1>
<p><?= message ?></p>
<p>The starter router looked for the route as an exact view, a directory index, and then parent index handlers.</p>
</section>
</>
}
@@ -1,5 +1,15 @@
#load "../../lib/app.uce"
ONCE(Request& context)
{
?><link rel="stylesheet" href="<?= app_asset_url("js/ag-grid/ag-grid.css", context) ?>" />
<link rel="stylesheet" href="<?= app_asset_url("js/ag-grid/ag-theme-alpine.css", context) ?>" />
<script src="<?= app_asset_url("js/u-format.js", context) ?>"></script>
<script src="<?= app_asset_url("js/u-timeseries-chart.js", context) ?>"></script>
<script src="<?= app_asset_url("js/u-sortable-table.js", context) ?>"></script>
<script src="<?= app_asset_url("js/ag-grid/ag-grid-community.min.js", context) ?>"></script><?
}
String data_format_bytes(String raw, bool disk = false)
{
if(trim(raw) == "")
@@ -105,8 +115,6 @@ COMPONENT:SUMMARY_METRICS(Request& context)
COMPONENT:TIMESERIES_CHART(Request& context)
{
starter_register_js("js/u-format.js", context);
starter_register_js("js/u-timeseries-chart.js", context);
String chart_id = first(context.props["id"].to_string(), "ts-chart-" + std::to_string((u64)time()));
String canvas_id = chart_id + "-canvas";
@@ -148,8 +156,6 @@ COMPONENT:TIMESERIES_CHART(Request& context)
COMPONENT:SORTABLE_TABLE(Request& context)
{
starter_register_js("js/u-format.js", context);
starter_register_js("js/u-sortable-table.js", context);
String table_id = first(context.props["id"].to_string(), "sortable-table-" + std::to_string((u64)time()));
String title = context.props["title"].to_string();
@@ -214,9 +220,6 @@ COMPONENT:SORTABLE_TABLE(Request& context)
COMPONENT:DATA_TABLE(Request& context)
{
String table_id = first(context.props["id"].to_string(), "data-grid-" + std::to_string((u64)time()));
starter_register_js("js/ag-grid/ag-grid-community.min.js", context);
starter_register_css("js/ag-grid/ag-grid.css", context);
starter_register_css("js/ag-grid/ag-theme-alpine.css", context);
DTree columns = context.props["columns"];
if(columns.get_type_name() != "array")
@@ -2,10 +2,9 @@
COMPONENT(Request& context)
{
starter_boot(context);
String current_theme = context.cfg.get_by_path("theme/key").to_string();
String current_label = first(context.cfg.get_by_path("theme/label").to_string(), current_theme);
String route_path = context.call["starter"]["route"]["l_path"].to_string();
String route_path = context.call["route"]["l_path"].to_string();
<>
<div id="theme-switcher" style="position: fixed; right: 1.5rem; bottom: 1.5rem; z-index: 9999; font-family: inherit;">
@@ -111,7 +110,7 @@ COMPONENT(Request& context)
<? context.cfg.get_by_path("theme/options").each([&](DTree theme_info, String theme_key) {
StringMap params;
params["theme"] = theme_key;
String href = starter_link(route_path == "index" ? "" : route_path, params, context);
String href = app_link(route_path == "index" ? "" : route_path, params, context);
?><a class="theme-option<?= theme_key == current_theme ? " is-active" : "" ?>" href="<?= href ?>">
<span><?= theme_info["label"].to_string() ?></span>
<? if(theme_key == current_theme) { ?><small>Active</small><? } ?>
@@ -2,8 +2,10 @@
COMPONENT(Request& context)
{
starter_register_js("components/gauges/common.js", context);
starter_register_css("themes/common/css/gauges.css", context);
DTree asset_props;
asset_props["css"]["0"] = "themes/common/css/gauges.css";
asset_props["js"]["0"] = "components/gauges/common.js";
print(component("../theme/assets", asset_props, context));
String gauge_id = first(context.props["id"].to_string(), "arcgauge-" + std::to_string((u64)time()));
String title = context.props["title"].to_string();
@@ -2,8 +2,10 @@
COMPONENT(Request& context)
{
starter_register_js("components/gauges/common.js", context);
starter_register_css("themes/common/css/gauges.css", context);
DTree asset_props;
asset_props["css"]["0"] = "themes/common/css/gauges.css";
asset_props["js"]["0"] = "components/gauges/common.js";
print(component("../theme/assets", asset_props, context));
String gauge_id = first(context.props["id"].to_string(), "needlegauge-" + std::to_string((u64)time()));
String style = context.props["style"].to_string();
@@ -2,8 +2,10 @@
COMPONENT(Request& context)
{
starter_register_js("components/gauges/common.js", context);
starter_register_css("themes/common/css/gauges.css", context);
DTree asset_props;
asset_props["css"]["0"] = "themes/common/css/gauges.css";
asset_props["js"]["0"] = "components/gauges/common.js";
print(component("../theme/assets", asset_props, context));
String gauge_id = first(context.props["id"].to_string(), "progressbar-" + std::to_string((u64)time()));
String style = context.props["style"].to_string();
@@ -2,7 +2,6 @@
COMPONENT(Request& context)
{
starter_boot(context);
StarterUser users(context);
DTree user = users.current();
bool signed_in = user["email"].to_string() != "";
@@ -16,14 +15,14 @@ COMPONENT(Request& context)
<? if(signed_in) { ?>
<span class="<?= name_class ?>"><?= first(user["username"].to_string(), user["email"].to_string(), "Account") ?></span>
<? if(links_class != "") { ?><div class="<?= links_class ?>"><? } ?>
<a href="<?= starter_link("account/profile", context) ?>">Profile</a>
<a href="<?= starter_link("account/logout", context) ?>">Logout</a>
<a href="<?= app_link("account/profile", context) ?>">Profile</a>
<a href="<?= app_link("account/logout", context) ?>">Logout</a>
<? if(links_class != "") { ?></div><? } ?>
<? } else { ?>
<? if(links_class != "") { ?><div class="<?= links_class ?>"><? } ?>
<a href="<?= starter_link("account/login", context) ?>">Login</a>
<a href="<?= app_link("account/login", context) ?>">Login</a>
<? if(context.cfg.get_by_path("users/enable_signup").to_string() != "") { ?>
<a href="<?= starter_link("account/register", context) ?>">Register</a>
<a href="<?= app_link("account/register", context) ?>">Register</a>
<? } ?>
<? if(links_class != "") { ?></div><? } ?>
<? } ?>
@@ -0,0 +1,39 @@
#load "../../lib/app.uce"
void app_asset_tag_once(Request& context, String kind, String path)
{
if(path == "")
return;
String key = kind + ":" + path;
if(context.call["assets"][key].to_bool())
return;
context.call["assets"][key].set_bool(true);
if(kind == "css")
{
?><link rel="stylesheet" href="<?= app_asset_url(path, context) ?>" /><?
}
else if(kind == "js")
{
?><script src="<?= app_asset_url(path, context) ?>"></script><?
}
}
void app_asset_tags(Request& context, String kind, DTree assets)
{
String scalar = assets.to_string();
if(scalar != "")
{
app_asset_tag_once(context, kind, scalar);
return;
}
assets.each([&](DTree item, String key) {
app_asset_tag_once(context, kind, item.to_string());
});
}
COMPONENT(Request& context)
@fragment head
{
app_asset_tags(context, "css", context.props["css"]);
app_asset_tags(context, "js", context.props["js"]);
}
@@ -2,11 +2,6 @@
COMPONENT(Request& context)
{
starter_boot(context);
bool embed_mode = starter_page_embed_mode(context);
if(embed_mode)
return;
String text = first(context.cfg.get_by_path("theme/footer_text").to_string(), context.cfg.get_by_path("site/name").to_string());
String inner_class = first(context.props["inner_class"].to_string(), context.cfg.get_by_path("theme/key").to_string() == "portal-light" ? "footer-inner" : "");
@@ -2,10 +2,6 @@
COMPONENT(Request& context)
{
starter_boot(context);
if(starter_page_embed_mode(context))
return;
String cookie_value = context.props["cookie_consent"].to_string();
bool cookie_consent = !(cookie_value == "0" || cookie_value == "false" || cookie_value == "FALSE" || cookie_value == "no" || cookie_value == "NO");
@@ -2,11 +2,10 @@
COMPONENT(Request& context)
{
starter_boot(context);
String title = first(context.call["starter"]["page_title"].to_string(), context.cfg.get_by_path("site/default_page_title").to_string());
String title = first(context.call["app"]["page_title"].to_string(), context.cfg.get_by_path("site/default_page_title").to_string());
String description = first(context.cfg.get_by_path("theme/meta_description").to_string(), "UCE starter example");
String theme_color = first(context.cfg.get_by_path("theme/theme_color").to_string(), "#0f172a");
String icon = starter_asset_url(context.cfg.get_by_path("theme/path").to_string() + "icon.png", context);
String icon = app_asset_url(context.cfg.get_by_path("theme/path").to_string() + "icon.png", context);
<>
<meta charset="utf-8">
@@ -16,7 +15,11 @@ COMPONENT(Request& context)
<meta name="theme-color" content="<?= theme_color ?>">
<link rel="apple-touch-icon" href="<?= icon ?>" />
<link rel="icon" type="image/png" sizes="32x32" href="<?= icon ?>" />
<? starter_render_registered_css(context); ?>
<? starter_render_registered_js(context); ?>
<link rel="stylesheet" href="<?= app_asset_url(context.cfg.get_by_path("theme/path").to_string() + "css/style.css", context) ?>" />
<link rel="stylesheet" href="<?= app_asset_url("themes/common/fontawesome/css/all.min.css", context) ?>" />
<script src="<?= app_asset_url("js/u-query.js", context) ?>"></script>
<script src="<?= app_asset_url("js/morphdom.js", context) ?>"></script>
<script src="<?= app_asset_url("js/site.js", context) ?>"></script>
<?: context.call["fragments"]["head"].to_string() ?>
</>
}
@@ -1,20 +0,0 @@
#load "../../lib/app.uce"
COMPONENT(Request& context)
{
starter_boot(context);
if(context.props["main_html"].to_string() != "")
context.call["starter"]["fragments"]["main"] = context.props["main_html"];
if(context.props["json"].get_type_name() == "array")
context.call["starter"]["json"] = context.props["json"];
if(context.props["page_type"].to_string() != "")
context.call["starter"]["page_type"] = context.props["page_type"];
if(context.props["embed_mode"].to_string() != "")
context.call["starter"]["embed_mode"] = context.props["embed_mode"];
starter_render_page(context);
}
COMPONENT:HEAD(Request& context)
{
print(component("head", context.props, context));
}
@@ -2,7 +2,6 @@
COMPONENT(Request& context)
{
starter_boot(context);
String nav_class = context.props["nav_class"].to_string();
if(nav_class == "" && (context.cfg.get_by_path("theme/key").to_string() == "portal-dark" || context.cfg.get_by_path("theme/key").to_string() == "dark" || context.cfg.get_by_path("theme/key").to_string() == "retro-gaming"))
nav_class = "nav-shell";
@@ -18,11 +17,12 @@ COMPONENT(Request& context)
<>
<nav<?: nav_class != "" ? " class=\"" + html_escape(nav_class) + "\"" : "" ?>>
<div class="nav-menu">
<a href="<?= starter_link("", context) ?>"><?= context.cfg.get_by_path("site/name").to_string() ?></a>
<a href="<?= app_link("", context) ?>"><?= context.cfg.get_by_path("site/name").to_string() ?></a>
<? context.cfg.get_by_path("menu").each([&](DTree menu_item, String menu_key) {
if(menu_item["hidden"].to_string() == "1")
return;
?><a href="<?= starter_menu_href(menu_key, menu_item, context) ?>"><?= menu_item["title"].to_string() ?></a><?
String href = menu_item["external"].to_string() != "" ? "/" + menu_key : app_link(menu_key, context);
?><a href="<?= href ?>"><?= menu_item["title"].to_string() ?></a><?
}); ?>
</div>
<?: component("account_links", account_props, context) ?>
@@ -0,0 +1,18 @@
#load "../../lib/app.uce"
COMPONENT:island(Request& context)
{
String name = context.props["name"].to_string();
String module = context.props["module"].to_string();
String id = first(context.props["id"].to_string(), "island-" + ascii_safe_name(name));
String payload = json_encode(context.props["props"]);
if(name == "")
return;
<>
<div id="<?= id ?>" data-uce-island="<?= name ?>" data-props="<?: html_escape(payload) ?>"></div>
</>
if(module != "")
{
<><script type="module" src="<?= app_asset_url(module, context) ?>"></script></>
}
}
@@ -1,9 +1,13 @@
#load "../../lib/app.uce"
ONCE(Request& context)
{
?><link rel="stylesheet" href="<?= app_asset_url("themes/common/css/workspace.css", context) ?>" />
<script src="<?= app_asset_url("js/u-workspace-shell.js", context) ?>"></script><?
}
COMPONENT:APP_FRAME(Request& context)
{
starter_register_css("themes/common/css/workspace.css", context);
starter_register_js("js/u-workspace-shell.js", context);
String id = context.props["id"].to_string();
String overlay_id = context.props["overlay_id"].to_string();
String class_name = context.props["class"].to_string();