import { signal } from "../signals/primitives.js"; //#region src/core/composition/create-composition.ts /** * Create a composition from a set of behaviors. * * Composition unions the behaviors' declared `stateKeys` / `contextKeys` * to know which signals to create. Each signal is seeded from * `initialState` / `initialContext` when supplied, defaulting to * `undefined`. Behaviors are responsible for writing their own slots * once their preconditions are met. * * Cross-behavior type conflicts (e.g. two behaviors disagreeing on a * field's type) surface as a compose-time type error via * `ValidateComposition`. * * @example * ```ts * const composition = createComposition([resolvePresentation, switchVideoTrack], { * config: { parsePresentation: parseMultivariantPlaylist, initialBandwidth: 2_000_000 }, * initialState: { bandwidthState: { fastEstimate: 0, ... } }, * }); * ``` */ /** * Create a typed signal map for a given set of keys, seeded from an * optional partial initial value. * * Pipeline: `Set` dedupes the iterable (insertion order preserved, so * first occurrence wins) → `Object.fromEntries` materializes one * `signal()` per unique key, seeded from `initial[key]` or `undefined`. * * Per-key value types live in TypeScript only — at runtime every signal * is `Signal`. The boundary cast at the return narrows the wide * `Record>` shape to the caller's expected * per-key types from `S`. * * Used by `createComposition` to derive engine state/context maps from * the union of behaviors' declared `stateKeys` / `contextKeys`. * * @example * ```ts * interface State { count?: number; label?: string } * const state = buildSignalMap(['count', 'label'], { count: 5 }); * state.count.get(); // 5 * state.label.get(); // undefined * ``` */ function buildSignalMap(keys, initial) { const init = initial; const uniqueKeys = new Set(keys); return Object.fromEntries([...uniqueKeys].map((key) => [key, signal(init[key])])); } function createComposition(behaviors, options) { const validBehaviors = behaviors; const state = buildSignalMap(validBehaviors.flatMap((b) => b.stateKeys), options?.initialState ?? {}); const context = buildSignalMap(validBehaviors.flatMap((b) => b.contextKeys), options?.initialContext ?? {}); const deps = { state, context, config: options?.config ?? {} }; const cleanups = validBehaviors.map((behavior) => behavior.setup(deps)); return { state, context, async destroy() { const results = []; for (const cleanup of cleanups) { if (cleanup == null) continue; if (typeof cleanup === "function") results.push(cleanup()); else if ("destroy" in cleanup) results.push(cleanup.destroy()); } await Promise.all(results); for (const sig of Object.values(state)) sig.set(void 0); for (const sig of Object.values(context)) sig.set(void 0); } }; } function defineBehavior(behavior) { return behavior; } //#endregion export { buildSignalMap, createComposition, defineBehavior }; //# sourceMappingURL=create-composition.js.map