Soundorv0.13.0

The pipeline

How config, generation, UI bundling and lifecycle dispatch fit together.

Purpose

The toolchain turns a project's config and UI into a contract and a bundle, then asks each selected runtime to build or run them. The CLI orchestrates the phases; runtimes own their build graph and execution.

Where the code is

SourceResponsibility
packages/config/src/load.ts, schema.ts, parse.tsLoad and validate config
packages/config/src/registry.tsResolve descriptors and dispatch phases
packages/core/src/generate.ts and *-dts.tsPortable generated declarations
packages/cli/src/commands/Command ordering and runtime selection
packages/cli/src/ui/bundle.tsShared UI bundling
packages/cli/src/dev/Watch sessions, logs, source maps and terminal

How it works

flowchart TD
    config["Load and validate soundor.config.ts"] --> gen["Generate portable contract"]
    gen --> runtimegen["Selected runtimes: gen"]
    runtimegen --> bundle["Bundle src/main.tsx once"]
    bundle --> native["bundle.js: native module function"]
    bundle --> esm["bundle.mjs: ES module"]
    native --> phases["Selected runtimes: dev or build"]
    esm --> phases

Config imports live runtime factories, such as juceRuntime(); their descriptors carry an ID, options and the implementation. Resolution uses these descriptors. The CLI does not import a concrete runtime to dispatch a command.

soundor gen first writes portable declarations, then collects each runtime's ctx.codegen output under its generated directory. --check compares expected contents without writing. Ownership lists the directories and explains why init is separate.

soundor build runs generation in production mode, bundles the UI once, then calls the selected runtimes in production mode. It records per-runtime results and reports an aggregate error after attempting the runtime builds.

The bundler inlines npm dependencies and leaves soundor:* imports for the runtime. bundle.mjs is an ES2023 module. bundle.js is a CommonJS module function lowered for Hermes by the engine's module-lowering tool, re-exported as toNativeModule() from core. Assets travel with the bundle. A project with no src/main.ts[x] has no ctx.ui; runtimes must handle that case.

During development the CLI watches the UI, rebuilds its directory in place, and writes build-id last after a successful build. The runtime reloads from that directory. The CLI tails the runtime's JSON-lines UI log and maps stack frames through source maps. Runtime-specific native builds or browser serving remain the runtime's job.

Invariants and tests

The bundle is shared by runtimes and contains no runtime-specific module implementation. Generation is deterministic and --check does not write. Runtime failures retain their ID and lifecycle phase. Build and dev commands pass the appropriate mode and bundle context.

packages/cli/src/commands/*.test.ts checks orchestration and failure reporting; ui/bundle.test.ts checks bundling. Config registry tests cover dispatch, and core generation tests cover declarations and stale-file detection. The dev directory has focused tests for logs, source maps, terminal and shortcuts.

How to change it

Start with the command's orchestration test. Change config validation and portable generation before runtime-specific consumers when the contract changes. Keep the native and ES module bundle forms equivalent. For a new lifecycle field, update its type, dispatch, SDK re-exports and tests, then the runtime lifecycle guide.

On this page