@todayai-labs/tck-host
Browser-side host runtime. Manifest registry, widget loader, layout grid, patch dispatcher, agent channel, two-tier mount surface.
The browser-side host runtime. A host app (today-platform-web, the workbench, the native WebView shell) wires up a single TodayHost and consumes it through React. tck-host owns the doc store, the patch dispatcher, the manifest registry, the widget loader, the layout canvas, the bus the agent talks on, and the <WidgetMount> mount primitive.
Widgets do not import this package — it's host-only, and the bundler enforces that absence at build time.
Deterministic product-policy helpers live separately in
@todayai-labs/tck-host-utils. Keeping those helpers
free of React, timers, and ambient browser reads lets web, native, and Preview Hosts share
the same calculations while owning their own lifecycle.
The package is split into multiple subpaths to keep the import graph minimal per consumer-class — a Next.js server module evaluating getHostHeadNodes must not transitively reach createContext, and an import-map-served mountHost must not drag in the full React component graph. The split is structurally enforced by __tests__/export-safety.test.ts; see the design memo for the rationale.
Subpaths
@todayai-labs/tck-host (root)
The core runtime. Safe to import anywhere a client React runtime exists.
| Export | What it does |
|---|---|
TodayHost | The host root. Owns registry + loader + dispatcher + docStore + canvas state. See § TodayHost. |
TodayHostOptions | Constructor options: storage, loaderOptions, onSizeMismatch. |
WidgetInstance | Immutable per-mount metadata returned by host.mountWidget / host.restoreWidget. |
SizeMismatchPolicy | 'warn' | 'throw' — see container contract. |
TodayWidgetCanvas | React component: the grid surface. Drag-to-move, tile chrome. |
TodayWidgetCanvasProps | Props + types for canvas tile rendering (WidgetTileRenderArgs, CanvasTileDragBindings). |
TodayFeedStack | React component: the feed surface (linear column of full-width cards). |
TodayFeedStackProps | Props + types for feed card rendering (FeedCardRenderArgs). |
WidgetLoader | Given a bundle URL → WidgetModule. Verifies named exports, ABI label, manifest schema. |
WidgetLoaderOptions, WidgetModule, ModuleMap, DEFAULT_HOST_ABI | Loader plumbing. |
WidgetLoadError | Loader-side rejection (malformed bundle / missing exports / failed manifest validation). |
WidgetAbiError | manifest.engines.abi does not match the host's ABI label. |
WidgetSizeError | Mount offered a size not in manifest.sizes. See container contract. |
WidgetMount | Low-level shadow-DOM mount primitive (also re-exported by /bootstrap). |
WidgetMountProps, WidgetMountFallbackControls | <WidgetMount> types. |
PatchDispatcher | Single sequencer per doc. Applies RFC-6902 patches; rejects stale baseVersion; idempotent on patchId. |
PatchDispatcherOptions | Dispatcher tuning. |
ManifestRegistry | In-memory {manifestId → RegisteredWidget} index. |
RegisteredWidget | Registry entry shape. |
DocStore, ephemeralStorage | Per-instance JSON-doc snapshots; pluggable storage backends. |
DocSnapshot, DocStorage | Storage backend contract. |
migrateDoc, MigrationError | Forward-only state migrations on schemaVersion mismatch. |
WidgetErrorBoundary | Per-widget React error boundary. Chrome-level "Reload widget" + "Reset to defaults". |
AgentChannelImpl, makeWidgetAgentChannel | Host-side agent bus implementation. |
CanvasDescriptor, CanvasItem | Page-level wire format for "what's on a canvas" — items + per-item bundle URL + pin bit. The shape a registry endpoint returns; the host hydrates from it on cold start. |
| Layout helpers | DEFAULT_GRID, canPlaceAt, canvasWidth, effectiveFootprint, findFirstFreeSlot, gridCssVars, pointerToGridPosition, widgetPixelSize, TodayGridConfig. |
@todayai-labs/tck-host/bootstrap
Tier-1 mount components — closed-contract single-widget surfaces. Client React only.
| Export | What it does |
|---|---|
TodayHostBoundary | React provider exposing the host + docStore to descendant <TodayWidget> mounts. |
TodayHostBoundaryProps | Props. |
TodayWidget | Closed-contract widget mount; accepts {src, instanceId} OR {devModule, instanceId} plus optional size and reactive slotValues. No loadModule escape hatch — every module flows through WidgetLoader.parseModule. See Tier 1 mount surface. |
TodayWidgetProps | Discriminated-union prop shape. |
TodayWidgetMountedInfo | onMounted callback payload. |
WidgetMount | Low-level shadow-DOM primitive (re-exported from root). |
@todayai-labs/tck-host/server
SSR-head slice. Safe to import in server modules — does not call createContext or touch the DOM.
| Export | What it does |
|---|---|
getHostHeadNodes | Returns <link> / <script type="importmap"> / <html data-theme> React elements for the host's <head>. |
@todayai-labs/tck-host/mount
Client-imperative slice — mountHost only. Safe to import anywhere; no React, no createContext.
| Export | What it does |
|---|---|
mountHost(document, options) | Installs shared CSS/importmap concerns and root-scoped data-theme / data-tck-pointer state. Concurrent controls update their own roots. Returns a MountHostControl. |
MountHostControl | { setTheme, setPointer, dispose } — runtime theme / pointer flips + cleanup. |
MountHostOptions | { theme, pointer?, themeRoot?, pointerRoot?, hostCssUrl? }; theme and pointer accept explicit values or 'system'. |
HostBootstrapError | Thrown when mountHost cannot verify the import-map's presence on the document. |
@todayai-labs/tck-host/vite
Vite plugin: build-time importmap injection. For no-SSR Vite hosts (workbench, tck-preview) — the dev-server equivalent of getHostHeadNodes.
| Export | What it does |
|---|---|
hostImportMapPlugin() | Vite plugin. In vite serve mode (dev), reads Vite's own dep-optimiser metadata at transformIndexHtml and injects <script type="importmap"> mapping each TCK_EXTERNAL_SPECIFIER to its /node_modules/.vite/deps/... URL (npm) or /@fs/.../packages/... URL (workspace). In vite build (production), the plugin currently emits { imports: {} } — production wiring that consumes a tck-shared-deps manifest.json via the manifest option is a documented deferred seam. |
@todayai-labs/tck-host/messages
Cross-window message types for <TodayWidget>'s iframe-mode bridge. Internal-protocol; typed shapes only.
@todayai-labs/tck-host/style.css
Default host stylesheet (preflight + theme tokens + the [data-theme='dark'] variant binding). Import once at the host app's root, or copy alongside tck-shared-deps's output for serving over importmap-resolved URLs.
import '@todayai-labs/tck-host/style.css'TodayHost
The canvas-tier API. Use this when building a Tier-2 host (workbench, drag-canvas, persisted layout); for embedding surfaces, prefer <TodayWidget> from /bootstrap.
import { TodayHost, ephemeralStorage } from '@todayai-labs/tck-host'
const host = new TodayHost({
storage: ephemeralStorage, // or an idb-keyval-backed DocStorage
loaderOptions: { loadModule: (url) => import(url) },
onSizeMismatch: 'warn', // or 'throw' for debug surfaces
})
host.registerWidget({
manifest: parsedManifest,
bundleUrl: 'https://.../widget.mjs',
cssUrl: 'https://.../widget.css',
})
const instance = await host.mountWidget({
manifestId: 'com.example.counter',
position: { col: 0, row: 0 },
size: '2x1', // optional; defaults to manifest.defaultSize
seedState: { count: 0 }, // optional; defaults to manifest.defaultState
})Methods:
registerWidget/mountWidget/restoreWidget/resetWidget/removeWidgetmoveWidget(instanceId, position)/resizeWidget(instanceId, size)setTransient(instanceId, transient)— flip the suggestion / pinned bitsetAmbientWidgetCss(css, propertiesCss?)— for unbundled (workspace dev) widgetslist()/get(instanceId)/subscribeLayout(fn)submitPatch({instanceId, baseVersion, patch})— build envelope + dispatch + handle stale rebasepublishAgent(message)— broadcast onto the agent bus
Source
- Package:
packages/tck-host - Reference Tier-2 host:
apps/host-playground - Reference Tier-1 consumer:
today-platform-web/apps/web/src/canvas-boot/ - Host-side ABI contract: Platform ABI § Host-side ABI contract
- Two-tier mount design: Platform ABI § Mount tiers