Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/facade/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# Run `make sync` after every Wippy Web Host version bump to pull fresh copies.

# Web Host CDN base — update version when Wippy Web Host releases
WEB_HOST_CDN = https://web-host.wippy.ai/webcomponents-1.0.44
WEB_HOST_CDN = https://web-host.wippy.ai/webcomponents-1.0.45

# Files to sync from CDN into public/@wippy-fe/
CDN_FILES = loading.js
Expand Down
7 changes: 4 additions & 3 deletions src/facade/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,10 @@ These fields are NOT configurable via requirements — they are computed at runt

| Requirement | Default | Description |
|---|---|---|
| `fe_facade_url` | `https://web-host.wippy.ai/webcomponents-1.0.44` | CDN base URL for the Web Host frontend bundle |
| `fe_facade_url` | `https://web-host.wippy.ai/webcomponents-1.0.45` | CDN base URL for the Web Host frontend bundle |
| `fe_entry_path` | `/iframe.html` | Iframe HTML entry point path (appended to `fe_facade_url`) |
| `fe_mode` | `compat` | `compat` (default — loads `module.js`) or `managed` (loads `managed-layout.js` for declarative multi-panel apps). See [Modes](#modes) above |
| `render_engine` | `iframe` | Global page render engine for packaged `view.page` micro-frontends: `iframe` (default — legacy srcdoc iframe) or `fragment` (Web Fragment / reframed realm reflected into a shadow root). `fragment` **requires** the `wippy/views` fragment gateway and a fragment-capable host bundle serving `/@wippy-fe/proxy-fragment.js`. Flows to the host as `hostConfig.renderEngine`; the child app is engine-agnostic (same package renders under either engine). |

### App Identity

Expand Down Expand Up @@ -377,9 +378,9 @@ Returns an empty body (200 OK) when no variables are configured. Response has `C

```json
{
"facade_url": "https://web-host.wippy.ai/webcomponents-1.0.44",
"facade_url": "https://web-host.wippy.ai/webcomponents-1.0.45",
"iframe_origin": "https://web-host.wippy.ai",
"iframe_url": "https://web-host.wippy.ai/webcomponents-1.0.44/iframe.html?waitForCustomConfig",
"iframe_url": "https://web-host.wippy.ai/webcomponents-1.0.45/iframe.html?waitForCustomConfig",
"login_path": "/login.html",
"login_redirect_param": null,
"env": {
Expand Down
19 changes: 18 additions & 1 deletion src/facade/_index.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ entries:
targets:
- entry: wippy.facade:fe_facade_url
path: .default
default: https://web-host.wippy.ai/webcomponents-1.0.44
default: https://web-host.wippy.ai/webcomponents-1.0.45

- name: fe_entry_path
kind: ns.requirement
Expand All @@ -63,6 +63,23 @@ entries:
path: .default
default: compat

- name: render_engine
kind: ns.requirement
meta:
description: |
Global page render engine for packaged view.page micro-frontends.
`iframe` (default) renders each page in a legacy srcdoc iframe.
`fragment` renders each page as a Web Fragment (a reframed realm
reflected into a shadow root). `fragment` REQUIRES the wippy/views
fragment gateway AND a fragment-capable host bundle serving
/@wippy-fe/proxy-fragment.js. Flows to the host as
hostConfig.renderEngine; the child app is engine-agnostic (the same
package renders identically under either engine).
targets:
- entry: wippy.facade:render_engine
path: .default
default: iframe

# App identity
- name: app_title
kind: ns.requirement
Expand Down
10 changes: 10 additions & 0 deletions src/facade/config_handler.lua
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,15 @@ local function handler()
fe_mode = "compat"
end

-- Global page render engine (EE2-2313). Only the exact string "fragment"
-- opts a deployment into the Web Fragment engine; anything else (default,
-- typo, blank) clamps to the legacy srcdoc "iframe" engine so a bad value
-- can never silently ship the non-legacy path.
local render_engine = get_req("render_engine")
if render_engine ~= "fragment" then
render_engine = "iframe"
end

-- Module filename loaded by index.html. `compat` keeps the historical
-- module.js (full Wippy host chrome); `managed` loads managed-layout.js
-- (declarative multi-panel host via hostConfig.layout).
Expand Down Expand Up @@ -141,6 +150,7 @@ local function handler()
hideNavBar = get_req("hide_nav_bar") == "true",
disableRightPanel = get_req("disable_right_panel") == "true",
hideSessionSelector = get_req("hide_session_selector") == "true",
renderEngine = render_engine,
}

local api_routes = non_empty_map_or_nil(get_req_json_any("api_routes"))
Expand Down
30 changes: 28 additions & 2 deletions src/facade/config_handler_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ local registry = require("registry")
local NS = "wippy.facade:"

local REQ_NAMES: {string} = {
"fe_facade_url", "fe_entry_path", "fe_mode", "session_type",
"fe_facade_url", "fe_entry_path", "fe_mode", "render_engine", "session_type",
"history_mode", "show_admin", "start_nav_open", "allow_select_model",
"hide_nav_bar", "disable_right_panel", "hide_session_selector",
"custom_css", "css_variables", "icon_sets",
Expand All @@ -26,6 +26,7 @@ local function setup_registry(overrides: {[string]: string}?)
fe_facade_url = "https://front.wippy.ai",
fe_entry_path = "/iframe.html",
fe_mode = "compat",
render_engine = "iframe",
session_type = "non-persistent",
history_mode = "hash",
show_admin = "true",
Expand Down Expand Up @@ -113,6 +114,15 @@ local function clamp_theme_storage_key(value: string): string
return value
end

-- Mirrors the clamp in config_handler.lua: only the exact string "fragment"
-- opts into the Web Fragment engine; anything else (default/typo/blank) → iframe.
local function clamp_render_engine(value: string): string
if value ~= "fragment" then
return "iframe"
end
return value
end

local function define_tests()
test.describe("config handler", function()
test.describe("ws url derivation", function()
Expand Down Expand Up @@ -155,6 +165,19 @@ local function define_tests()
end)
end)

test.describe("render engine clamping", function()
test.it("keeps fragment as-is", function()
test.eq(clamp_render_engine("fragment"), "fragment")
end)

test.it("clamps default / unknown / typo / blank to iframe", function()
test.eq(clamp_render_engine("iframe"), "iframe")
test.eq(clamp_render_engine(""), "iframe")
test.eq(clamp_render_engine("Fragment"), "iframe")
test.eq(clamp_render_engine("srcdoc"), "iframe")
end)
end)

test.describe("iframe URL construction", function()
test.it("builds iframe URL from facade_url and entry_path", function()
local facade_url = "https://front.wippy.ai"
Expand All @@ -165,7 +188,7 @@ local function define_tests()
end)

test.it("extracts iframe origin from facade URL", function()
local facade_url = "https://web-host.wippy.ai/webcomponents-1.0.44"
local facade_url = "https://web-host.wippy.ai/webcomponents-1.0.45"
local origin = facade_url:match("^(https?://[^/]+)")

test.eq(origin, "https://web-host.wippy.ai")
Expand Down Expand Up @@ -256,6 +279,9 @@ local function define_tests()

entry = registry.get(NS .. "history_mode")
test.eq(entry.data.default, "hash")

entry = registry.get(NS .. "render_engine")
test.eq(entry.data.default, "iframe")
end)

test.it("host_config_layout requirement defaults to empty JSON object", function()
Expand Down
9 changes: 8 additions & 1 deletion src/facade/index_handler.lua
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,13 @@ local function handler()
end
end

local set = templates.get(TEMPLATE_SET)
local set, get_err = templates.get(TEMPLATE_SET)
if not set then
res:set_status(http.STATUS.INTERNAL_SERVER_ERROR)
res:set_content_type("text/html")
res:write("<!doctype html><meta charset=\"utf-8\"><title>Wippy</title>Failed to load shell template set: " .. tostring(get_err))
return nil, get_err
end
local html, err = set:render("index", {
hasTheme = has_theme,
themeClass = theme_class,
Expand All @@ -81,6 +87,7 @@ local function handler()
res:set_header("Cache-Control", "no-store")
res:set_status(http.STATUS.OK)
res:write(html)
set:release()
end

return { handler = handler }
10 changes: 5 additions & 5 deletions src/facade/public/@wippy-fe/loading.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/facade/security_policy_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ local function run()
test.it("grants facade config registry and public API env reads only", function()
test.eq(decision("wippy.facade:config_read_runtime", "registry.get", "wippy.facade:fe_facade_url"), "allow")
test.eq(decision("wippy.facade:config_read_runtime", "env.get", "PUBLIC_API_URL"), "allow")
test.eq(decision("wippy.facade:config_read_runtime", "template.get", "wippy.facade:templates"), "allow")
test.eq(decision("wippy.facade:config_read_runtime", "env.get", "ENCRYPTION_KEY"), "undefined")
test.eq(decision("wippy.facade:config_read_runtime", "registry.apply", "wippy.facade:fe_facade_url"), "undefined")
end)
Expand Down
4 changes: 4 additions & 0 deletions src/views/_index.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ entries:
path: .meta.router
- entry: wippy.views.api:list_routes.endpoint
path: .meta.router
- entry: wippy.views.api:fragment_gateway
path: .meta.router
- entry: wippy.views.api:fragment_gateway.endpoint
path: .meta.router
- name: public_api_url
kind: env.variable
meta:
Expand Down
Loading
Loading