Architecture Overview
The dev branch, which currently targets version 3.0, separates ownership of the Kawaikara application from ownership of individual site integrations.
Main Goals
The dev branch, which currently targets version 3.0, separates ownership of the Kawaikara application from ownership of individual site integrations.
srcis the application: Electron startup, windows, IPC, preferences, updates, download integration, and UI.packages/site-apiis the stable contract consumed by site plugins.packages/builtin-sitesis the official Bundle shipped with the app.- Site-specific selectors, login workarounds, user-agent changes, and injected scripts belong to their Provider rather than to a central manager.
- A Provider receives narrow capabilities through
SiteContextinstead of direct access to Electron window objects.
Repository layout
repository/
├── src/
│ ├── Common/ # Shared IPC, preferences, build, shortcut, and PiP types
│ ├── Main/
│ │ ├── Main.ts # Composition root and application lifecycle
│ │ ├── DependencyInjection/ # Manager tokens, construction, and ownership
│ │ ├── Functional/ # Stateless Main-process helpers and platform bridges
│ │ ├── Manager/ # Window, site, IPC, logging, preference, update, and service managers
│ │ ├── Inject/ # Application-owned page injection builders
│ │ └── Plugin/ # PluginHost
│ ├── Preload/ # Restricted bridges for app-owned and remote renderers
│ └── Renderer/
│ ├── Component/ # Reusable application UI
│ └── View/ # Menu, Preference, and Video views
├── packages/
│ ├── site-api/ # Electron-independent plugin contract
│ └── builtin-sites/ # One directory and manifest per Provider
├── stories/ # Component and view stories with Electron API mocks
└── docs/Developer/ # Developer documentation
Directories and files under Renderer, View, and Component use PascalCase to match the project convention.
src/Main/Main.ts is intentionally the only file at the src/Main root;
implementation files belong to one of its responsibility-based subdirectories.
Dependency direction
flowchart LR
Renderer["src/Renderer"] --> IPC["src/Common"]
Preload["src/Preload"] --> IPC
Main["src/Main"] --> IPC
Main --> SiteAPI["packages/site-api"]
Main --> Builtin["packages/builtin-sites"]
Builtin --> SiteAPI
Main --> Electron["Electron"]
Preload --> Electron
The important rules are:
site-apidoes not exposeBrowserWindow,WebContents,Session, or other Electron types.builtin-sitesuses onlysite-apicapabilities.- Renderer code does not import Main-process managers.
- Main/Preload/Renderer contracts live in
src/Common. - Remote site pages never receive the full application renderer API.
Composition root
src/Main/Main.ts is the only place that assembles the runtime.
sequenceDiagram
participant Electron as Electron app
participant Logging as LoggingManager
participant Preferences as PreferenceManager
participant Windows as WindowManager
participant Sites as SiteManager
participant Plugins as PluginHost
participant IPC as IpcManager
Electron->>Electron: wait for Widevine component
Electron->>Logging: initialize and register
Electron->>Preferences: load()
Electron->>Windows: createWindows()
Electron->>Sites: create with SiteContext factory
Electron->>Windows: attach Provider policies
Electron->>Plugins: install(builtinBundle)
Electron->>IPC: initialize()
Electron->>Windows: loadOverlay()
Electron->>Sites: load startup or default site
Electron->>Electron: start presence and optional update check
The app also creates managers for logging, shortcuts, the external downloader, developer links, updates, and Discord Rich Presence. Shutdown runs in the reverse direction: IPC handlers are removed, the global PiP shortcut is unregistered, the active Provider is unloaded, external resources are closed, the log session is finished, and only then does Electron quit.
Main responsibilities
WindowManager
- Owns the viewer host, overlay, site
WebContentsView, popups, and unified PiP window. - Creates the concrete
SiteContextcapabilities. - Applies navigation, new-window, PiP, action-URL, and request-header policies from the active Provider.
- Runs external browser login and restores the viewer afterward.
- Redirects supported dropped video files to the internal Video site.
- Emulates the selected app color scheme in active remote site and popup WebContents.
- Keeps HTML media fullscreen inside the configured app window; application fullscreen is a separate explicit action.
SiteManager
- Registers Bundles and validates Provider, Plugin, and profile references.
- Maintains exactly one active Provider and its matching Plugin instances.
- Resolves the site locale and Electron Session profile.
- Forwards policy hooks to the active Provider.
- Reloads the current site when its browser-profile assignment changes.
PluginHost
- Checks
KAWAIKARA_SITE_API_VERSION. - Prevents duplicate Bundle installation.
- Installs Bundles through
SiteManager.
User-installed Bundle discovery and compiled JavaScript loading are handled by BundleManager.
Renderer
- Renders the menu, full-overlay preferences, internal Video view, and external-login status.
- Uses KawaiUI for application-owned controls.
- Accesses Main functionality only through a preload API.
- Is developed independently through Storybook mocks where practical.
Typed IPC
src/Common/IPC.ts defines the complete namespace-shaped channel tree with defineIpcChannels().
export const IPC_CHANNELS = defineIpcChannels({
sites: {
list: 'kawaikara:sites:list',
open: 'kawaikara:sites:open',
},
// ...
} as const);
export type IpcChannel = LeafValues<typeof IPC_CHANNELS>;
export type IpcChannels = typeof IPC_CHANNELS;
This gives Main and Preload autocomplete for both channel paths and channel literal values. Renderer autocomplete comes from KawaikaraRendererApi and KawaikaraVideoApi, which type the objects exposed through contextBridge.
Registration decision
Decorators attach metadata to Provider and Plugin classes, but they do not register them globally. Registration is explicit through defineProvider(), definePlugin(), and defineBundle().
This avoids import-order behavior, shared reflection registries between tests, partial discovery, and ambiguous plugin ownership. It also gives a future external loader one export to validate before installation.
Current boundary versus future work
The application/package split, explicit Bundle definitions, Provider-scoped Plugin activation, profile isolation, typed IPC, runtime capability enforcement, built-in Bundle, validated third-party .kawai installation, and HTTPS archive updates/removal are implemented. .kawai is a ZIP container with an application-specific extension. External Bundle code loads and unloads on restart under an explicit trusted-code model. Sandboxing, signature checks, and automatic rollback remain planned work.
Change rules
- Add the smallest possible capability to
site-apibefore exposing a new application function to Providers. - Do not add site-ID conditionals to
WindowManagerfor behavior that belongs to one integration. - Every listener or external resource started by
load()must be disposed byunload(). - A breaking contract change requires a
KAWAIKARA_SITE_API_VERSIONincrement and migration notes. - Keep IPC channel names, preload methods, Main handlers, and renderer types in sync.