Bootstrap Sequence
This page is a lifecycle and configuration reference. The sequence diagrams describe Host initialization; they are not application bootstrap code to copy.
After receiving its configuration, the Web Host runs a fixed initialization sequence before rendering the full interface. Configuration arrives either through a JS module that takes over the page or through a manually embedded iframe. The internal steps are identical once configuration is available.
Path A — JS Module (Standard, facade path)
The current wippy/facade uses this path. It serves a page that loads a Web
Host JS-module entry: module.js for compat mode or managed-layout.js for
managed mode. The module then takes over the page and its browser history.
-
Fetch configuration and register the map. The facade requirement is named
import_map;/facade/configexposes it ascfg.importMap. The shell loads the shared import-map bootstrap and registers the composed map before importing Host modules. -
Import the Host module and initialize the app. The shell imports
module.jsormanaged-layout.js, which exposeswindow.initWippyApp. It then callsinitWippyApp(appConfig, rootContainer?)with the initialAppConfig, includingimportMap: cfg.importMap. There is no PostMessage handshake. -
Initialization proceeds — see Internal Init Sequence below.
Path B — Iframe (manual, facade-less)
Use this path to embed the full host inside an iframe for partial-page rendering
with stronger isolation. It loads iframe.html?waitForCustomConfig and receives
configuration through a SetConfig PostMessage. The current facade does not
produce this embedding.
-
Parent prepares the iframe. Add
?waitForCustomConfigto the versionediframe.htmlURL. Install amessagelistener before assigningiframe.src. The standalone bootstrap waits for the parentSetConfigbefore registering the import map or importing Host app modules. This happens before the Host app mounts. -
Parent answers
GetConfig. Wait for the iframe'sget-configmessage. Accept it only when bothevent.originequals the trusted iframe origin andevent.sourceequalsiframe.contentWindow. Then send a completeAppConfigin aset-configmessage, using the trusted origin astargetOrigin. A/facade/configresponse can provide deployment settings, but the parent must add$schema,auth, andcontext. See the manual iframe example for the full listener and message flow. -
Web Host receives
AppConfig. It validates the message envelope, accepts an iframe message only from the physical parent window, and checksevent.originagainst the parent origin when that origin is accessible. In a Web Fragment, it also requiresfragmentIdto match that occurrence’s own ID. Later validSetConfigmessages can update that document’s config. -
Initialization proceeds — the internal path is identical to Path A from this point forward.
Internal Init Sequence
Once AppConfig is available (via either path), the Web Host runs the following
startup sequence:
1. Resolve and normalize configuration.
resolveConfig() initializes and merges the supplied configuration, applies
schema migrations, normalizes session policy, and populates the configuration,
authentication, and environment state used by the rest of the Host.
2. Fetch backend page routes.
Before creating or mounting the Vue application, the Host awaits
GET /api/public/pages/routes. A backend syntax or duplicate-route error aborts
startup and is relayed through the Host error path; it is not a post-mount route
installation step.
3. Create the application and router.
The Vue application is created. The router uses the history mode from
AppConfig.hostConfig.history and registers both static system routes and the
backend mount routes before the application mounts.
4. Install application providers.
setupApp() installs Pinia, configures Axios and authentication, installs
PrimeVue and the theme providers, and wires the remaining application services.
Child applications receive the configured API surface through the proxy layer.
5. Mount and resolve the current URL.
Only after configuration, route loading, router creation, and provider setup
have completed does the module entry mount App.vue. The router then resolves
the current browser or hash URL against the complete route table.
6. Create WebSocket clients when requested.
WebSocket setup is consumer-driven rather than a fixed final bootstrap step.
useWsClientRaw() creates the client when a consuming component or composable
requests it. The connection starts eagerly unless hostConfig.lazyWS is true;
with lazy mode, it starts when a subscription requires it.
AppConfig TypeScript Interface
The following abridged declaration shows the main configuration fields accepted
by both initWippyApp and SetConfig. Supporting types and less commonly used
fields remain authoritative in the pinned Web Host app-config/types.ts; do not
treat this excerpt as a replacement for the shipped schema. There is no
feature or fe_mode field in AppConfig — fe_mode is a facade requirement
parameter that selects the module entry, and managed mode is conveyed through
hostConfig.layout:
interface AppConfig {
$schema: string // cfg.schema_url || (cfg.facade_url + '/schemas/wippy-context-2.0.xsd')
auth: AppAuthConfig
env: AppEnv
axiosDefaults?: Partial<AxiosDefaults>
routePrefix?: string
apiRoutes?: ApiRoutesOverride
tanstack?: TanstackConfig // TanStack Query defaults (global + per role-based category)
iconify?: IconifyConfig | null
themeMode?: 'auto' | 'light' | 'dark'
theming: AppTheming
allowSelectModel?: boolean
hideSessionSelector?: boolean
allowAdditionalTags?: Record<string, string[]>
hostConfig: HostConfig
context: AppContext
}
interface AppAuthConfig {
token: string // Bearer token
expiresAt: string // ISO 8601 expiry timestamp
}
interface AppEnv {
APP_API_URL: string
APP_AUTH_API_URL: string
APP_WEBSOCKET_URL: string
}
interface AppTheming {
global?: ThemingScope
host?: HostThemingScope
children?: ChildrenThemingScope
}
interface CssVariablesMap {
[key: string]: string | Record<string, string> | undefined
'@dark'?: Record<string, string>
'@light'?: Record<string, string>
}
interface ThemingScope {
customCSS?: string
cssVariables?: CssVariablesMap
fonts?: FontConfig[]
icons?: Record<string, unknown>
iconSets?: Record<string, Record<string, unknown>>
}
interface HostThemingScope extends ThemingScope {
i18n?: Partial<I18NTextTypes>
}
interface ChildrenThemingScope {
customCSS?: string
cssVariables?: CssVariablesMap
fonts?: FontConfig[]
}
interface HostConfig {
session?: { type: 'non-persistent' | 'cookie' }
history?: 'browser' | 'hash'
showAdmin?: boolean
allowSelectModel?: boolean
startNavOpen?: boolean
hideNavBar?: boolean
disableRightPanel?: boolean
hideSessionSelector?: boolean
renderEngine?: 'iframe' | 'fragment'
lazyWS?: boolean
additionalNavItems?: PageApi.Page[]
stateCache?: { maxPages?: number; maxSizePerPage?: number }
allowAdditionalTags?: Record<string, string[]> // tag → allowed attributes
chat?: {
convertPasteToFile?: {
enabled: boolean
minFileSize: number
allowHtml: boolean
}
}
layout?: HostLayoutDeclaration
}
// TanStack Query defaults. A top-level field (shared by host + children, like
// apiRoutes). Default behavior (no config) is refetchOnWindowFocus: false so
// alt-tabbing back doesn't reload in-flight content.
interface TanstackConfig {
default?: TanstackQueryOptions // overrides the global query defaults
content?: TanstackQueryOptions // single-resource renders (page/artifact/session/entry/model/upload)
lists?: TanstackQueryOptions // navigation / index / list queries
}
interface IconifyConfig {
providers?: Record<string, {
resources: string[]
path?: string
timeout?: number
} | null> | null
}
// JSON-safe subset of TanStack query options (no functions — config is JSON).
interface TanstackQueryOptions {
refetchOnWindowFocus?: boolean
refetchOnReconnect?: boolean
refetchOnMount?: boolean
staleTime?: number
gcTime?: number
retry?: boolean | number
refetchInterval?: number | false
}
interface AppContext {
resourceId: string
resourceType: 'page' | 'artifact'
route?: string
parentResourceId?: string
nestingDepth?: number
isNavOwner?: boolean
layoutPanelId?: string
layoutId?: string
layout?: unknown
extensions?: Record<string, unknown>
}
AppConfig.iconify selects Iconify collection sources. The default remains online when this field is omitted. Set it explicitly to use a local collection. See Iconify providers for the provider format and reset behavior. Explicitly configured values are projected to child applications through AppConfig.
PrimeVue is available to application imports through the exact specifiers in the pinned Host import map. Rebuilt consumers use the Host's shared PrimeVue vendor graph within their JavaScript realm. Each iframe or Web Fragment has its own realm and module graph. The import map does not inject styles; request the needed PrimeVue CSS through the documented Host CSS keys. Existing embedded consumer bundles must be rebuilt against the new map.
Current facade limitation. Web Host accepts
AppConfig.tanstack, and the facade config endpoint returns the configuredtanstackobject. The standard facade shell does not currently copy that field into theAppConfigpassed toinitWippyApp. Do not rely on the facadetanstackparameter on the standard shell path until that forwarding is implemented. A manual embedder can include it in theAppConfigit assembles.
Configuration Sources and Priority
The Web Host resolves configuration from multiple sources, in priority order from lowest to highest:
- Built-in defaults — defined in the Web Host bundle itself.
- URL query parameters —
?token=<token>,?expiresAt=<timestamp>,?persistfor cookie sessions. Useful for direct development access without a parent page. initWippyApp()argument — theAppConfigassembled by the standard facade shell; takes precedence over URL parameters.- PostMessage
SetConfig— the manual, facade-less iframe path, used when?waitForCustomConfigis present.
In practice, production deployments always use initWippyApp() (the facade path) or PostMessage (manual iframe embedding). URL parameters are a development convenience for loading the host directly in the browser with a token.
Bootstrap Diagram
The standard facade (JS-module) path:
facade shell fetches /facade/config (requirement import_map → cfg.importMap)
│
├─ fetches the Host map and loads the shared import-map bootstrap
├─ registers the composed import map
├─ imports module.js / managed-layout.js
├─ module exposes window.initWippyApp
├─ shell calls initWippyApp({ ..., importMap: cfg.importMap }, '#app')
├─ resolveConfig() → migrate, normalize, and populate config/auth/env state
├─ await GET /api/public/pages/routes
├─ create Vue app + router
│ static system routes + validated backend mount routes
├─ setupApp() → Pinia, Axios, PrimeVue, theming, and other providers
├─ mount App.vue → resolve the current URL
└─ consuming components request WebSocket clients
See Also
- Facade Entry Point — how
AppConfigis constructed and delivered bywippy/facade - Multi-Panel Layout — the managed-layout boot path served by
managed-layout.js - Render Engines — how a page renders once loaded (srcdoc iframe vs Web Fragment)
AppConfig import map
AppConfig.importMap is an optional top-level browser import map with standard imports and scopes fields.
interface AppConfig {
importMap?: {
imports?: Record<string, string>
scopes?: Record<string, Record<string, string>>
} | null
}
For srcdoc page documents, the Host composes the page map, generated Host defaults, then AppConfig.importMap. Standalone and facade documents have no page-provided srcdoc map; they compose Host defaults then AppConfig.importMap. Within imports and each scope, the last value for a matching key wins and unrelated entries remain. Configuration can replace page or Host mappings, including Vue, PrimeVue, and Wippy packages. An exact key matches one specifier. A key ending in / matches that specifier prefix, and its target must also end in /. scopes select mappings by the importing module URL. Relative target URLs resolve against the document base URL.
Compose the map before registering the native import map and before loading modules. Omitting importMap from an update keeps the current extension. Set it to null or {} to clear the extension.
An import-map update applies when a document is created. It does not change module resolution in an existing document. Reload that document to use the update; later-created documents use the latest configuration. Web Fragment AppConfig.importMap and scopes support is deferred: wippy/views 0.5.12 does not guarantee that the composed map is registered before fragment modules load.
Overriding a shared Vue, PrimeVue, or Wippy entry can split module or service identity between the Host and child code. Test those integrations against the exact released map before deploying an override.
The verified Web Host release baseline for direct AppConfig.importMap use is 1.0.64.
UI policy in 1.0.62
Web Host 1.0.62 shares the following chat policy with child applications. hostConfig belongs to the Web Host wrapper and is never included in child payloads. A managed layout has no built-in chat by default. Applications that live entirely in a child use top-level policy or package overrides.
// Shared reader: host override, shared root field, then default.
const value = config.hostConfig?.[key] ?? config[key] ?? fallback
// Child override in package.json (no hostConfig in child payloads).
const configOverrides = {
allowSelectModel: false,
hideSessionSelector: true,
allowAdditionalTags: { svg: ['viewBox', 'preserveAspectRatio'], path: ['d'] },
}
An explicit WC attribute wins for that instance. show-selector overrides the inverse of hideSessionSelector; without either setting, the WC selector remains hidden. Built-in host chat keeps its visible-selector default. allow-select-model accepts "false". An absent attribute inherits config, and removing it restores inheritance. Configured tag maps replace the previous map, including {}. Built-in sanitizer tags remain available. Runtime tag registrations belong to the loading scope and do not mutate declared config. Only successful definitions grant their declared attributes. Tag allowlists come from AppConfig and successful component loads, with no WC attribute override.
The existing SetConfig message updates the owning runtime through the internal configUpdated event. The proxy exposes the notification as on('@config', callback), following the naming of @theme and @history. It refreshes raw injected config and the public config view before callbacks run. Independently bundled chat WCs use that subscription and seed their stores from raw injected config. Direct config.auth reads are supported and emit no warning; use api for ordinary authenticated HTTP requests. No new PostMessage action or childrenConfig is added. Legacy feature fields and schema 2.0 inputs remain accepted; old host-only settings stay host-only. SVG allowlists can retain viewBox and preserveAspectRatio without allowing script tags, event handlers, or unsafe URLs.