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.23
WEB_HOST_CDN = https://web-host.wippy.ai/webcomponents-1.0.25

# Files to sync from CDN into public/@wippy-fe/
CDN_FILES = loading.js
Expand Down
30 changes: 25 additions & 5 deletions src/facade/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,29 @@ Portable iframe facade for the Wippy frontend. Serves a thin HTML shell that loa
1. `index.html` is served as a static file via `http.static`
2. On load, it fetches `GET /api/public/facade/config` to get runtime configuration
3. Checks `localStorage` for an auth token, redirects to `login_path` if missing
4. Loads the Web Host bundle from CDN (`facade_url + '/module.js'`)
5. Calls `initWippyApp()` with the full AppConfig (wippy-context-2.0 format)
4. Loads the Web Host bundle from CDN — picks the module file based on `fe_mode`:
- `compat` (default) → `module.js` — full Wippy host chrome
- `managed` → `managed-layout.js` — declarative multi-panel host driven by `hostConfig.layout`
5. Calls `window.initWippyApp(config)` — both entries expose the same symbol; the mounted shell is the only difference
6. Shows `<wippy-loading>` / `<wippy-error>` during initialization (vendored from Wippy Web Host CDN)

## Modes

| Mode | Entry loaded | Mounted shell | Use case |
|---|---|---|---|
| `compat` _(default)_ | `module.js` | Full Wippy chrome (sidebar + chat + pages + right panel) | Backwards-compatible — existing facades keep working unchanged |
| `managed` | `managed-layout.js` | Declarative multi-panel layout — no default chrome, every panel declared via `hostConfig.layout` | IDE-style apps, dashboards, Adobe-style multi-pane tools |

Both entries expose the same `window.initWippyApp(config, rootContainer?)` signature — the parent integration code does not change between modes. Set via the `fe_mode` requirement; unknown values normalize to `compat`.

### When to switch to `managed` mode

- You want a multi-panel app with separator-drag resizing
- You want to embed a custom panel configuration driven by config (not by the standard sidebar/chat layout)
- You want breakpoint-responsive layouts (desktop vs mobile)

Leave `fe_mode` at `compat` unless you have a specific reason to opt in — the managed shell omits every piece of default Wippy chrome (no sidebar, no chat wrapper, no right panel) and expects the declaration to provide equivalents.

## Vendored CDN files

`public/@wippy-fe/` contains files copied from the Wippy Web Host CDN. These are loaded before the CDN URL is known (pre-config-fetch), so they must be vendored locally.
Expand Down Expand Up @@ -47,8 +66,9 @@ 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.23` | CDN base URL for the Web Host frontend bundle |
| `fe_facade_url` | `https://web-host.wippy.ai/webcomponents-1.0.25` | 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 |

### App Identity

Expand Down Expand Up @@ -189,9 +209,9 @@ Only override what differs from defaults.

```json
{
"facade_url": "https://web-host.wippy.ai/webcomponents-1.0.23",
"facade_url": "https://web-host.wippy.ai/webcomponents-1.0.25",
"iframe_origin": "https://web-host.wippy.ai",
"iframe_url": "https://web-host.wippy.ai/webcomponents-1.0.23/iframe.html?waitForCustomConfig",
"iframe_url": "https://web-host.wippy.ai/webcomponents-1.0.25/iframe.html?waitForCustomConfig",
"login_path": "/login.html",
"env": {
"APP_API_URL": "http://localhost:8085",
Expand Down
15 changes: 14 additions & 1 deletion src/facade/_index.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ entries:
targets:
- entry: wippy.facade:fe_facade_url
path: .default
default: https://web-host.wippy.ai/webcomponents-1.0.23
default: https://web-host.wippy.ai/webcomponents-1.0.25

- name: fe_entry_path
kind: ns.requirement
Expand All @@ -44,6 +44,19 @@ entries:
path: .default
default: /iframe.html

- name: fe_mode
kind: ns.requirement
meta:
description: |
Frontend bundle mode. `compat` (default) loads module.js and renders
the standard Wippy host (sidebar + chat + pages + right panel).
`managed` loads managed-layout.js and renders a declarative
multi-panel host defined by hostConfig.layout — no default chrome.
targets:
- entry: wippy.facade:fe_mode
path: .default
default: compat

# App identity
- name: app_title
kind: ns.requirement
Expand Down
13 changes: 13 additions & 0 deletions src/facade/config_handler.lua
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,17 @@ local function handler()

local facade_url = get_req("fe_facade_url")
local entry_path = get_req("fe_entry_path")
local fe_mode = get_req("fe_mode")

-- Normalize mode: anything other than "managed" falls back to compat.
if fe_mode ~= "managed" then
fe_mode = "compat"
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).
local module_file = fe_mode == "managed" and "/managed-layout.js" or "/module.js"

local iframe_origin: string? = ""
if facade_url ~= "" then
Expand Down Expand Up @@ -164,6 +175,8 @@ local function handler()
iframe_origin = iframe_origin,
iframe_url = iframe_url,
login_path = get_req("login_path"),
mode = fe_mode,
module_file = module_file,

env = {
APP_API_URL = api_url,
Expand Down
2 changes: 1 addition & 1 deletion src/facade/config_handler_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,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.23"
local facade_url = "https://web-host.wippy.ai/webcomponents-1.0.25"
local origin = facade_url:match("^(https?://[^/]+)")

test.eq(origin, "https://web-host.wippy.ai")
Expand Down
11 changes: 8 additions & 3 deletions src/facade/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,16 @@
console.warn('Failed to load import map:', e);
}

// Now safe to load modules — import map is already in the DOM
// Now safe to load modules — import map is already in the DOM.
// `cfg.module_file` is "/module.js" (compat) or "/managed-layout.js"
// (managed). Both entries set the same `window.initWippyApp` symbol;
// the rendered shell is the only difference. Backend normalizes
// unknown modes to "compat", so the fallback below is purely defensive.
var moduleFile = cfg.module_file || '/module.js';
try {
await import(cfg.facade_url + '/module.js');
await import(cfg.facade_url + moduleFile);
} catch (importErr) {
showError('Failed to load frontend bundle', 'Could not load ' + cfg.facade_url + '/module.js — ' + importErr.message);
showError('Failed to load frontend bundle', 'Could not load ' + cfg.facade_url + moduleFile + ' — ' + importErr.message);
throw importErr;
}

Expand Down
Loading