Today Canvas Kit
SDK packages

@todayai-labs/tck-bundler

Compile a .tck.tsx widget source into a distributable .tckb bundle. CLI + programmatic.

The widget-side build tool. Takes a .tck.tsx source, runs esbuild + Tailwind v4 over it, and emits a .tckb envelope ready to ship to a host. CLI for one-shot builds; programmatic for higher-level pipelines.

tck-bundler calls @todayai-labs/tck-bundle-format's packTckb to construct the envelope — tck-bundler derives the manifest, compiles the JS, scopes the CSS; the format package owns the envelope bytes.

CLI

# Bundle a single widget
pnpm exec tck-bundle widgets/counter/widget.tck.tsx --out widgets/counter/dist/widget.tckb

# Bundle every widget in the workspace
pnpm exec tck-bundle --all

# Scaffold a new widget package
pnpm exec tck-init widgets/my-widget

Programmatic surface

import { bundleWidget, readWidgetSource, type BundleOptions } from '@todayai-labs/tck-bundler'

const result = await bundleWidget({
  entry: 'widgets/counter/widget.tck.tsx',
  outFile: 'widgets/counter/dist/widget.tckb',
  // ... see BundleOptions
})
ExportWhat it does
bundleWidget(options)Compile + scope CSS + pack .tckb. Returns the BundleResult.
BundleErrorThrown when a widget imports a bare specifier outside TCK_EXTERNAL_SPECIFIERS, exceeds maxSizeBytes, or fails manifest validation.
readWidgetSource(path)Read a .tck.tsx file as UTF-8 text. Useful for tests and dev tools that want the source before invoking esbuild.
buildWidgetCss, scopeCssThe CSS scoping pipeline. Lifted into its own export for tooling that wants to lint or pre-process scoped CSS.
initWidget(options)Programmatic widget-package scaffold (the tck-init CLI delegates here).

Constraints

  • Externals whitelist enforced at build time. BundleError: bundle imports "<spec>", which is not on the TCK externals whitelist — fail-fast at CI, not at load time.
  • Soft cap 256 KB on widget.mjs. Configurable via maxSizeBytes. Exceeding it is a build error, not a load error.
  • JSX: automatic transform throughout. Classic-transform output (banner-injected import React) is internal — widget source itself uses react-jsx.

Source

On this page