# Architecture `dsh-style-hub` is one package with two halves that never import from each other's DSH surface: the Host half runs in the composition's Node process, the browser half runs in the page, and the only thing they share is the durable `style-hub` section plus the wallpaper wire contract. ``` src/ shared/ settings.ts · wallpaper-css.ts · wallpapers.ts ← both halves import these index.ts Host half: schema, storage, route, boot rule routes.ts the prefix route's dispatch storage.ts the on-disk library client/ index.ts browser half: registration + reconciliation controller.ts section reads/writes for the card StyleHubCard.tsx the card itself palettes · tokens · color · tweaks ← style derivation api · locales · styles ← transport, copy, chrome ``` ## Contracts with the composition | What the plugin needs | How it arrives | Why | | --- | --- | --- | | carrier for the wallpaper route | `inject = ['webServer']` | routes must be registered before the server accepts requests | | settings namespace | `ctx.inject(['settings'], …)` | graceful degradation: without a settings provider the routes still stand | | slot to contribute the card | `ctx.slots.inject('settings.plugin.item', …)` | the tab dispatches one key per *served* namespace | | theme registry | `ctx.theme.register` / `setTheme` / `overrideTokens` | the design system owns palette composition | | copy | `ctx.locale.register(LOCALE_NS, { zh, en })` | the card renders through the locale service | Bundle purity holds throughout: **no cross-plugin value imports**. DSH packages appear only as `import type …/client` side-effect imports (which is what augments the shared `Context` type), and every runtime service is reached through `ctx`. ## Host half `apply(ctx)` does three things: 1. Registers the `style-hub` namespace with `StyleHubSchema` (defaults for every field) plus `validateSettings`, which owns the ranges and the shape checks so a stored document can be re-judged without a schema upgrade. 2. Opens an `ImageStore` and registers **one** prefix route (`/api/style-hub/wallpapers`). Everything else is dispatched on the route's own sub-path, so there is exactly one registration to reason about. 3. Subscribes to `webserver/index-inject` and pushes two rows per render: the wallpaper `