@czap/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +19 -0
- package/dist/addressed-digest.d.ts +15 -0
- package/dist/addressed-digest.d.ts.map +1 -0
- package/dist/addressed-digest.js +35 -0
- package/dist/addressed-digest.js.map +1 -0
- package/dist/animation.d.ts +46 -0
- package/dist/animation.d.ts.map +1 -0
- package/dist/animation.js +70 -0
- package/dist/animation.js.map +1 -0
- package/dist/assembly.d.ts +25 -0
- package/dist/assembly.d.ts.map +1 -0
- package/dist/assembly.js +58 -0
- package/dist/assembly.js.map +1 -0
- package/dist/av-bridge.d.ts +74 -0
- package/dist/av-bridge.d.ts.map +1 -0
- package/dist/av-bridge.js +107 -0
- package/dist/av-bridge.js.map +1 -0
- package/dist/av-renderer.d.ts +56 -0
- package/dist/av-renderer.d.ts.map +1 -0
- package/dist/av-renderer.js +65 -0
- package/dist/av-renderer.js.map +1 -0
- package/dist/blend.d.ts +61 -0
- package/dist/blend.d.ts.map +1 -0
- package/dist/blend.js +100 -0
- package/dist/blend.js.map +1 -0
- package/dist/boundary.d.ts +154 -0
- package/dist/boundary.d.ts.map +1 -0
- package/dist/boundary.js +269 -0
- package/dist/boundary.js.map +1 -0
- package/dist/brands.d.ts +63 -0
- package/dist/brands.d.ts.map +1 -0
- package/dist/brands.js +31 -0
- package/dist/brands.js.map +1 -0
- package/dist/caps.d.ts +49 -0
- package/dist/caps.d.ts.map +1 -0
- package/dist/caps.js +73 -0
- package/dist/caps.js.map +1 -0
- package/dist/capsule.d.ts +77 -0
- package/dist/capsule.d.ts.map +1 -0
- package/dist/capsule.js +18 -0
- package/dist/capsule.js.map +1 -0
- package/dist/capsules/boundary-evaluate.d.ts +28 -0
- package/dist/capsules/boundary-evaluate.d.ts.map +1 -0
- package/dist/capsules/boundary-evaluate.js +117 -0
- package/dist/capsules/boundary-evaluate.js.map +1 -0
- package/dist/capsules/canonical-cbor.d.ts +13 -0
- package/dist/capsules/canonical-cbor.d.ts.map +1 -0
- package/dist/capsules/canonical-cbor.js +60 -0
- package/dist/capsules/canonical-cbor.js.map +1 -0
- package/dist/capsules/token-buffer.d.ts +24 -0
- package/dist/capsules/token-buffer.d.ts.map +1 -0
- package/dist/capsules/token-buffer.js +53 -0
- package/dist/capsules/token-buffer.js.map +1 -0
- package/dist/capture.d.ts +40 -0
- package/dist/capture.d.ts.map +1 -0
- package/dist/capture.js +10 -0
- package/dist/capture.js.map +1 -0
- package/dist/cbor.d.ts +33 -0
- package/dist/cbor.d.ts.map +1 -0
- package/dist/cbor.js +179 -0
- package/dist/cbor.js.map +1 -0
- package/dist/cell.d.ts +53 -0
- package/dist/cell.d.ts.map +1 -0
- package/dist/cell.js +83 -0
- package/dist/cell.js.map +1 -0
- package/dist/codec.d.ts +30 -0
- package/dist/codec.d.ts.map +1 -0
- package/dist/codec.js +25 -0
- package/dist/codec.js.map +1 -0
- package/dist/component.d.ts +52 -0
- package/dist/component.d.ts.map +1 -0
- package/dist/component.js +44 -0
- package/dist/component.js.map +1 -0
- package/dist/composable.d.ts +76 -0
- package/dist/composable.d.ts.map +1 -0
- package/dist/composable.js +221 -0
- package/dist/composable.js.map +1 -0
- package/dist/compositor-pool.d.ts +74 -0
- package/dist/compositor-pool.d.ts.map +1 -0
- package/dist/compositor-pool.js +119 -0
- package/dist/compositor-pool.js.map +1 -0
- package/dist/compositor.d.ts +90 -0
- package/dist/compositor.d.ts.map +1 -0
- package/dist/compositor.js +278 -0
- package/dist/compositor.js.map +1 -0
- package/dist/config.d.ts +72 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +97 -0
- package/dist/config.js.map +1 -0
- package/dist/dag.d.ts +251 -0
- package/dist/dag.d.ts.map +1 -0
- package/dist/dag.js +450 -0
- package/dist/dag.js.map +1 -0
- package/dist/defaults.d.ts +45 -0
- package/dist/defaults.d.ts.map +1 -0
- package/dist/defaults.js +45 -0
- package/dist/defaults.js.map +1 -0
- package/dist/derived.d.ts +34 -0
- package/dist/derived.d.ts.map +1 -0
- package/dist/derived.js +101 -0
- package/dist/derived.js.map +1 -0
- package/dist/diagnostics.d.ts +77 -0
- package/dist/diagnostics.d.ts.map +1 -0
- package/dist/diagnostics.js +122 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/dirty.d.ts +55 -0
- package/dist/dirty.d.ts.map +1 -0
- package/dist/dirty.js +80 -0
- package/dist/dirty.js.map +1 -0
- package/dist/easing.d.ts +55 -0
- package/dist/easing.d.ts.map +1 -0
- package/dist/easing.js +291 -0
- package/dist/easing.js.map +1 -0
- package/dist/ecs.d.ts +105 -0
- package/dist/ecs.d.ts.map +1 -0
- package/dist/ecs.js +245 -0
- package/dist/ecs.js.map +1 -0
- package/dist/fnv.d.ts +14 -0
- package/dist/fnv.d.ts.map +1 -0
- package/dist/fnv.js +28 -0
- package/dist/fnv.js.map +1 -0
- package/dist/frame-budget.d.ts +73 -0
- package/dist/frame-budget.d.ts.map +1 -0
- package/dist/frame-budget.js +114 -0
- package/dist/frame-budget.js.map +1 -0
- package/dist/gen-frame.d.ts +102 -0
- package/dist/gen-frame.d.ts.map +1 -0
- package/dist/gen-frame.js +121 -0
- package/dist/gen-frame.js.map +1 -0
- package/dist/harness/arbitrary-from-schema.d.ts +28 -0
- package/dist/harness/arbitrary-from-schema.d.ts.map +1 -0
- package/dist/harness/arbitrary-from-schema.js +262 -0
- package/dist/harness/arbitrary-from-schema.js.map +1 -0
- package/dist/harness/cached-projection.d.ts +19 -0
- package/dist/harness/cached-projection.d.ts.map +1 -0
- package/dist/harness/cached-projection.js +39 -0
- package/dist/harness/cached-projection.js.map +1 -0
- package/dist/harness/index.d.ts +16 -0
- package/dist/harness/index.d.ts.map +1 -0
- package/dist/harness/index.js +15 -0
- package/dist/harness/index.js.map +1 -0
- package/dist/harness/policy-gate.d.ts +18 -0
- package/dist/harness/policy-gate.d.ts.map +1 -0
- package/dist/harness/policy-gate.js +46 -0
- package/dist/harness/policy-gate.js.map +1 -0
- package/dist/harness/pure-transform.d.ts +42 -0
- package/dist/harness/pure-transform.d.ts.map +1 -0
- package/dist/harness/pure-transform.js +76 -0
- package/dist/harness/pure-transform.js.map +1 -0
- package/dist/harness/receipted-mutation.d.ts +23 -0
- package/dist/harness/receipted-mutation.d.ts.map +1 -0
- package/dist/harness/receipted-mutation.js +52 -0
- package/dist/harness/receipted-mutation.js.map +1 -0
- package/dist/harness/scene-composition.d.ts +19 -0
- package/dist/harness/scene-composition.d.ts.map +1 -0
- package/dist/harness/scene-composition.js +47 -0
- package/dist/harness/scene-composition.js.map +1 -0
- package/dist/harness/site-adapter.d.ts +18 -0
- package/dist/harness/site-adapter.d.ts.map +1 -0
- package/dist/harness/site-adapter.js +38 -0
- package/dist/harness/site-adapter.js.map +1 -0
- package/dist/harness/state-machine.d.ts +19 -0
- package/dist/harness/state-machine.d.ts.map +1 -0
- package/dist/harness/state-machine.js +44 -0
- package/dist/harness/state-machine.js.map +1 -0
- package/dist/hlc.d.ts +99 -0
- package/dist/hlc.d.ts.map +1 -0
- package/dist/hlc.js +219 -0
- package/dist/hlc.js.map +1 -0
- package/dist/index.d.ts +104 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +137 -0
- package/dist/index.js.map +1 -0
- package/dist/interpolate.d.ts +14 -0
- package/dist/interpolate.d.ts.map +1 -0
- package/dist/interpolate.js +31 -0
- package/dist/interpolate.js.map +1 -0
- package/dist/live-cell.d.ts +46 -0
- package/dist/live-cell.d.ts.map +1 -0
- package/dist/live-cell.js +154 -0
- package/dist/live-cell.js.map +1 -0
- package/dist/op.d.ts +58 -0
- package/dist/op.d.ts.map +1 -0
- package/dist/op.js +171 -0
- package/dist/op.js.map +1 -0
- package/dist/plan.d.ts +195 -0
- package/dist/plan.d.ts.map +1 -0
- package/dist/plan.js +211 -0
- package/dist/plan.js.map +1 -0
- package/dist/protocol.d.ts +33 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +10 -0
- package/dist/protocol.js.map +1 -0
- package/dist/quantizer-types.d.ts +28 -0
- package/dist/quantizer-types.d.ts.map +1 -0
- package/dist/quantizer-types.js +9 -0
- package/dist/quantizer-types.js.map +1 -0
- package/dist/receipt.d.ts +294 -0
- package/dist/receipt.d.ts.map +1 -0
- package/dist/receipt.js +352 -0
- package/dist/receipt.js.map +1 -0
- package/dist/runtime-coordinator.d.ts +75 -0
- package/dist/runtime-coordinator.d.ts.map +1 -0
- package/dist/runtime-coordinator.js +149 -0
- package/dist/runtime-coordinator.js.map +1 -0
- package/dist/scheduler.d.ts +58 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +109 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/ship-capsule.d.ts +54 -0
- package/dist/ship-capsule.d.ts.map +1 -0
- package/dist/ship-capsule.js +142 -0
- package/dist/ship-capsule.js.map +1 -0
- package/dist/ship-manifest.d.ts +45 -0
- package/dist/ship-manifest.d.ts.map +1 -0
- package/dist/ship-manifest.js +175 -0
- package/dist/ship-manifest.js.map +1 -0
- package/dist/signal.d.ts +149 -0
- package/dist/signal.d.ts.map +1 -0
- package/dist/signal.js +277 -0
- package/dist/signal.js.map +1 -0
- package/dist/speculative.d.ts +67 -0
- package/dist/speculative.d.ts.map +1 -0
- package/dist/speculative.js +139 -0
- package/dist/speculative.js.map +1 -0
- package/dist/store.d.ts +39 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +42 -0
- package/dist/store.js.map +1 -0
- package/dist/style.d.ts +119 -0
- package/dist/style.d.ts.map +1 -0
- package/dist/style.js +168 -0
- package/dist/style.js.map +1 -0
- package/dist/testing.d.ts +14 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +14 -0
- package/dist/testing.js.map +1 -0
- package/dist/theme.d.ts +78 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +109 -0
- package/dist/theme.js.map +1 -0
- package/dist/timeline.d.ts +45 -0
- package/dist/timeline.d.ts.map +1 -0
- package/dist/timeline.js +101 -0
- package/dist/timeline.js.map +1 -0
- package/dist/token-buffer.d.ts +43 -0
- package/dist/token-buffer.d.ts.map +1 -0
- package/dist/token-buffer.js +112 -0
- package/dist/token-buffer.js.map +1 -0
- package/dist/token.d.ts +107 -0
- package/dist/token.d.ts.map +1 -0
- package/dist/token.js +143 -0
- package/dist/token.js.map +1 -0
- package/dist/tuple.d.ts +16 -0
- package/dist/tuple.d.ts.map +1 -0
- package/dist/tuple.js +16 -0
- package/dist/tuple.js.map +1 -0
- package/dist/type-utils.d.ts +41 -0
- package/dist/type-utils.d.ts.map +1 -0
- package/dist/type-utils.js +10 -0
- package/dist/type-utils.js.map +1 -0
- package/dist/typed-ref.d.ts +50 -0
- package/dist/typed-ref.d.ts.map +1 -0
- package/dist/typed-ref.js +59 -0
- package/dist/typed-ref.js.map +1 -0
- package/dist/ui-quality.d.ts +50 -0
- package/dist/ui-quality.d.ts.map +1 -0
- package/dist/ui-quality.js +64 -0
- package/dist/ui-quality.js.map +1 -0
- package/dist/validation-error.d.ts +25 -0
- package/dist/validation-error.d.ts.map +1 -0
- package/dist/validation-error.js +32 -0
- package/dist/validation-error.js.map +1 -0
- package/dist/vector-clock.d.ts +46 -0
- package/dist/vector-clock.d.ts.map +1 -0
- package/dist/vector-clock.js +91 -0
- package/dist/vector-clock.js.map +1 -0
- package/dist/video.d.ts +62 -0
- package/dist/video.d.ts.map +1 -0
- package/dist/video.js +59 -0
- package/dist/video.js.map +1 -0
- package/dist/wasm-dispatch.d.ts +52 -0
- package/dist/wasm-dispatch.d.ts.map +1 -0
- package/dist/wasm-dispatch.js +204 -0
- package/dist/wasm-dispatch.js.map +1 -0
- package/dist/wasm-fallback.d.ts +19 -0
- package/dist/wasm-fallback.d.ts.map +1 -0
- package/dist/wasm-fallback.js +93 -0
- package/dist/wasm-fallback.js.map +1 -0
- package/dist/wire.d.ts +49 -0
- package/dist/wire.d.ts.map +1 -0
- package/dist/wire.js +201 -0
- package/dist/wire.js.map +1 -0
- package/dist/zap.d.ts +42 -0
- package/dist/zap.d.ts.map +1 -0
- package/dist/zap.js +172 -0
- package/dist/zap.js.map +1 -0
- package/package.json +71 -0
- package/src/addressed-digest.ts +48 -0
- package/src/animation.ts +103 -0
- package/src/assembly.ts +76 -0
- package/src/av-bridge.ts +161 -0
- package/src/av-renderer.ts +118 -0
- package/src/blend.ts +135 -0
- package/src/boundary.ts +363 -0
- package/src/brands.ts +86 -0
- package/src/caps.ts +100 -0
- package/src/capsule.ts +95 -0
- package/src/capsules/boundary-evaluate.ts +128 -0
- package/src/capsules/canonical-cbor.ts +60 -0
- package/src/capsules/token-buffer.ts +57 -0
- package/src/capture.ts +48 -0
- package/src/cbor.ts +199 -0
- package/src/cell.ts +130 -0
- package/src/codec.ts +39 -0
- package/src/component.ts +102 -0
- package/src/composable.ts +328 -0
- package/src/compositor-pool.ts +162 -0
- package/src/compositor.ts +387 -0
- package/src/config.ts +157 -0
- package/src/dag.ts +527 -0
- package/src/defaults.ts +60 -0
- package/src/derived.ts +164 -0
- package/src/diagnostics.ts +186 -0
- package/src/dirty.ts +101 -0
- package/src/easing.ts +334 -0
- package/src/ecs.ts +382 -0
- package/src/fnv.ts +31 -0
- package/src/frame-budget.ts +149 -0
- package/src/gen-frame.ts +229 -0
- package/src/harness/arbitrary-from-schema.ts +270 -0
- package/src/harness/cached-projection.ts +46 -0
- package/src/harness/index.ts +16 -0
- package/src/harness/policy-gate.ts +51 -0
- package/src/harness/pure-transform.ts +121 -0
- package/src/harness/receipted-mutation.ts +59 -0
- package/src/harness/scene-composition.ts +54 -0
- package/src/harness/site-adapter.ts +43 -0
- package/src/harness/state-machine.ts +49 -0
- package/src/hlc.ts +238 -0
- package/src/index.ts +274 -0
- package/src/interpolate.ts +37 -0
- package/src/live-cell.ts +199 -0
- package/src/op.ts +233 -0
- package/src/plan.ts +317 -0
- package/src/protocol.ts +49 -0
- package/src/quantizer-types.ts +29 -0
- package/src/receipt.ts +444 -0
- package/src/runtime-coordinator.ts +230 -0
- package/src/scheduler.ts +161 -0
- package/src/ship-capsule.ts +191 -0
- package/src/signal.ts +345 -0
- package/src/speculative.ts +186 -0
- package/src/store.ts +77 -0
- package/src/style.ts +249 -0
- package/src/testing.ts +14 -0
- package/src/theme.ts +153 -0
- package/src/timeline.ts +146 -0
- package/src/token-buffer.ts +151 -0
- package/src/token.ts +197 -0
- package/src/tuple.ts +19 -0
- package/src/type-utils.ts +48 -0
- package/src/typed-ref.ts +79 -0
- package/src/ui-quality.ts +105 -0
- package/src/validation-error.ts +34 -0
- package/src/vector-clock.ts +111 -0
- package/src/video.ts +106 -0
- package/src/wasm-dispatch.ts +300 -0
- package/src/wasm-fallback.ts +102 -0
- package/src/wire.ts +274 -0
- package/src/zap.ts +241 -0
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compositor -- merge multiple quantizers into composite state.
|
|
3
|
+
*
|
|
4
|
+
* The compositor aggregates discrete + blended state from all
|
|
5
|
+
* active quantizers into a single CompositeState, producing
|
|
6
|
+
* typed output channels (css, glsl, aria).
|
|
7
|
+
*
|
|
8
|
+
* Wired: DirtyFlags (selective recomputation), CompositorStatePool
|
|
9
|
+
* (zero-allocation), FrameBudget (priority scheduling), microtask batching,
|
|
10
|
+
* and RuntimeCoordinator (Plan + ECS-backed runtime bookkeeping).
|
|
11
|
+
*
|
|
12
|
+
* Hot path (computeStateSync) is plain JS — no Effect overhead.
|
|
13
|
+
* Effect is used only for resource lifecycle (create/scope) and
|
|
14
|
+
* reactive stream (SubscriptionRef.changes).
|
|
15
|
+
*
|
|
16
|
+
* @module
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import type { Scope, Stream } from 'effect';
|
|
20
|
+
import { Effect, SubscriptionRef } from 'effect';
|
|
21
|
+
import type { Boundary } from './boundary.js';
|
|
22
|
+
import { COMPOSITOR_POOL_CAP, DIRTY_FLAGS_MAX } from './defaults.js';
|
|
23
|
+
import { CompositorStatePool, accessCompositeState } from './compositor-pool.js';
|
|
24
|
+
import { DirtyFlags } from './dirty.js';
|
|
25
|
+
import type { FrameBudget } from './frame-budget.js';
|
|
26
|
+
import type { Quantizer } from './quantizer-types.js';
|
|
27
|
+
import { RuntimeCoordinator } from './runtime-coordinator.js';
|
|
28
|
+
import { SpeculativeEvaluator } from './speculative.js';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Snapshot of the compositor's output per tick: discrete state names for each
|
|
32
|
+
* quantizer, their blend-weight vectors, and the compiled per-target output
|
|
33
|
+
* maps (`css` / `glsl` / `aria`).
|
|
34
|
+
*/
|
|
35
|
+
export interface CompositeState {
|
|
36
|
+
readonly discrete: Record<string, string>;
|
|
37
|
+
readonly blend: Record<string, Record<string, number>>;
|
|
38
|
+
readonly outputs: {
|
|
39
|
+
readonly css: Record<string, number | string>;
|
|
40
|
+
readonly glsl: Record<string, number>;
|
|
41
|
+
readonly aria: Record<string, string>;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Options accepted by `Compositor.create`: pool capacity, optional
|
|
47
|
+
* frame-budget gating, and whether to enable speculative pre-evaluation.
|
|
48
|
+
*/
|
|
49
|
+
export interface CompositorConfig {
|
|
50
|
+
readonly poolCapacity?: number;
|
|
51
|
+
readonly frameBudget?: FrameBudget.Shape;
|
|
52
|
+
readonly speculative?: boolean;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Widen a Quantizer's boundary parameter to Boundary.Shape for storage in
|
|
57
|
+
* a heterogeneous registry. Safe because Quantizer<B> is covariant in B
|
|
58
|
+
* (B only appears in return positions on Quantizer).
|
|
59
|
+
*/
|
|
60
|
+
function widenQuantizer<B extends Boundary.Shape>(q: Quantizer<B>): Quantizer<Boundary.Shape> {
|
|
61
|
+
return q as unknown as Quantizer<Boundary.Shape>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
interface CompositorShape {
|
|
65
|
+
add<B extends Boundary.Shape>(name: string, quantizer: Quantizer<B>): Effect.Effect<void>;
|
|
66
|
+
remove(name: string): Effect.Effect<void>;
|
|
67
|
+
compute(): Effect.Effect<CompositeState>;
|
|
68
|
+
setBlendWeights(name: string, weights: Record<string, number>): Effect.Effect<void>;
|
|
69
|
+
evaluateSpeculative(name: string, value: number, velocity?: number): void;
|
|
70
|
+
scheduleBatch(): void;
|
|
71
|
+
readonly changes: Stream.Stream<CompositeState>;
|
|
72
|
+
readonly runtime: RuntimeCoordinator.Shape;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
interface CompositorFactory {
|
|
76
|
+
create(config?: CompositorConfig): Effect.Effect<CompositorShape, never, Scope.Scope>;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
interface QuantizerMeta {
|
|
80
|
+
readonly cssKey: string;
|
|
81
|
+
readonly glslKey: string;
|
|
82
|
+
readonly ariaKey: string;
|
|
83
|
+
readonly oneHotWeights: Readonly<Record<string, Readonly<Record<string, number>>>>;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function emptyCompositeState(): CompositeState {
|
|
87
|
+
return {
|
|
88
|
+
discrete: {},
|
|
89
|
+
blend: {},
|
|
90
|
+
outputs: { css: {}, glsl: {}, aria: {} },
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const MAX_DIRTY_KEYS = DIRTY_FLAGS_MAX;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Compositor — the live merge point for every attached {@link Quantizer}.
|
|
98
|
+
*
|
|
99
|
+
* `Compositor.create` hands back a scoped Effect that, when run inside a
|
|
100
|
+
* `Scope`, produces a compositor bound to a {@link RuntimeCoordinator}. Adding
|
|
101
|
+
* quantizers, marking dirty flags, and emitting CSS/GLSL/ARIA outputs all flow
|
|
102
|
+
* through the zero-allocation hot path backed by {@link CompositorStatePool}.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```ts
|
|
106
|
+
* import { Effect } from 'effect';
|
|
107
|
+
* import { Compositor } from '@czap/core';
|
|
108
|
+
*
|
|
109
|
+
* const program = Effect.scoped(Effect.gen(function* () {
|
|
110
|
+
* const compositor = yield* Compositor.create({ poolCapacity: 64, speculative: true });
|
|
111
|
+
* yield* compositor.add('viewport', viewportQuantizer);
|
|
112
|
+
* const state = yield* compositor.compute();
|
|
113
|
+
* // state.discrete.viewport === 'tablet'
|
|
114
|
+
* // state.outputs.css['--czap-viewport'] === 'tablet'
|
|
115
|
+
* }));
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
export const Compositor: CompositorFactory = {
|
|
119
|
+
/** Build a scoped compositor bound to a fresh {@link RuntimeCoordinator}. */
|
|
120
|
+
create(config?: CompositorConfig): Effect.Effect<CompositorShape, never, Scope.Scope> {
|
|
121
|
+
return Effect.gen(function* () {
|
|
122
|
+
const stateRef = yield* SubscriptionRef.make<CompositeState>(emptyCompositeState());
|
|
123
|
+
|
|
124
|
+
const qMap = new Map<string, Quantizer<Boundary.Shape>>();
|
|
125
|
+
const metaMap = new Map<string, QuantizerMeta>();
|
|
126
|
+
const overrides = new Map<string, Record<string, number>>();
|
|
127
|
+
|
|
128
|
+
const pool = CompositorStatePool.make(config?.poolCapacity ?? COMPOSITOR_POOL_CAP);
|
|
129
|
+
const frameBudget = config?.frameBudget;
|
|
130
|
+
const useSpeculative = config?.speculative ?? false;
|
|
131
|
+
const runtime = RuntimeCoordinator.create({
|
|
132
|
+
capacity: Math.max(config?.poolCapacity ?? COMPOSITOR_POOL_CAP, MAX_DIRTY_KEYS + 8),
|
|
133
|
+
name: 'czap-compositor-runtime',
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
const speculativeEvaluators = new Map<string, SpeculativeEvaluator.Shape<Boundary.Shape>>();
|
|
137
|
+
const prefetchedStates = new Map<string, string>();
|
|
138
|
+
|
|
139
|
+
let nameList: string[] = [];
|
|
140
|
+
let dirty: DirtyFlags.Shape<string> | null = null;
|
|
141
|
+
let recomputeAll = false;
|
|
142
|
+
let previousState: CompositeState = emptyCompositeState();
|
|
143
|
+
let priorPreviousState: CompositeState | null = null;
|
|
144
|
+
let batchScheduled = false;
|
|
145
|
+
function rebuildDirtyFlags(): void {
|
|
146
|
+
if (nameList.length > MAX_DIRTY_KEYS) {
|
|
147
|
+
dirty = null;
|
|
148
|
+
recomputeAll = true;
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
dirty = DirtyFlags.make(nameList);
|
|
153
|
+
recomputeAll = false;
|
|
154
|
+
for (const name of nameList) {
|
|
155
|
+
dirty.mark(name);
|
|
156
|
+
runtime.markDirty(name);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function computeStateSync(): CompositeState {
|
|
161
|
+
const dirtyFlags = dirty;
|
|
162
|
+
const dirtyNames = recomputeAll || dirtyFlags === null ? Array.from(qMap.keys()) : dirtyFlags.getDirty();
|
|
163
|
+
const shouldRecompute =
|
|
164
|
+
recomputeAll || dirtyFlags === null ? () => true : (name: string) => dirtyFlags.isDirty(name);
|
|
165
|
+
|
|
166
|
+
const state = pool.acquire();
|
|
167
|
+
const { discrete, blend, css, glsl, aria } = accessCompositeState(state);
|
|
168
|
+
|
|
169
|
+
for (const [name] of qMap) {
|
|
170
|
+
if (shouldRecompute(name)) {
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const meta = metaMap.get(name)!;
|
|
175
|
+
const previousDiscrete = previousState.discrete[name];
|
|
176
|
+
if (previousDiscrete !== undefined) {
|
|
177
|
+
discrete[name] = previousDiscrete;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const previousBlend = previousState.blend[name]!;
|
|
181
|
+
blend[name] = previousBlend;
|
|
182
|
+
|
|
183
|
+
const previousCss = previousState.outputs.css[meta.cssKey];
|
|
184
|
+
if (previousCss !== undefined) {
|
|
185
|
+
css[meta.cssKey] = previousCss;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const previousGlsl = previousState.outputs.glsl[meta.glslKey];
|
|
189
|
+
if (previousGlsl !== undefined) {
|
|
190
|
+
glsl[meta.glslKey] = previousGlsl;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const previousAria = previousState.outputs.aria[meta.ariaKey];
|
|
194
|
+
if (previousAria !== undefined) {
|
|
195
|
+
aria[meta.ariaKey] = previousAria;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
for (const phase of runtime.phases) {
|
|
200
|
+
switch (phase) {
|
|
201
|
+
case 'compute-discrete':
|
|
202
|
+
for (const name of dirtyNames) {
|
|
203
|
+
const quantizer = qMap.get(name)!;
|
|
204
|
+
|
|
205
|
+
const prefetched = prefetchedStates.get(name);
|
|
206
|
+
const stateStr =
|
|
207
|
+
prefetched ?? (quantizer.stateSync ? quantizer.stateSync() : Effect.runSync(quantizer.state));
|
|
208
|
+
discrete[name] = stateStr;
|
|
209
|
+
runtime.setState(name, stateStr);
|
|
210
|
+
prefetchedStates.delete(name);
|
|
211
|
+
}
|
|
212
|
+
break;
|
|
213
|
+
|
|
214
|
+
case 'compute-blend':
|
|
215
|
+
for (const name of dirtyNames) {
|
|
216
|
+
const meta = metaMap.get(name)!;
|
|
217
|
+
|
|
218
|
+
const override = overrides.get(name);
|
|
219
|
+
if (override !== undefined) {
|
|
220
|
+
blend[name] = override;
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
blend[name] = meta.oneHotWeights[discrete[name] ?? ''] ?? {};
|
|
225
|
+
}
|
|
226
|
+
break;
|
|
227
|
+
|
|
228
|
+
case 'emit-css':
|
|
229
|
+
for (const name of dirtyNames) {
|
|
230
|
+
const meta = metaMap.get(name);
|
|
231
|
+
const stateStr = discrete[name];
|
|
232
|
+
if (stateStr !== undefined && meta) {
|
|
233
|
+
css[meta.cssKey] = stateStr;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
break;
|
|
237
|
+
|
|
238
|
+
case 'emit-glsl':
|
|
239
|
+
if (!frameBudget || frameBudget.canRun('high')) {
|
|
240
|
+
for (const name of dirtyNames) {
|
|
241
|
+
const meta = metaMap.get(name)!;
|
|
242
|
+
glsl[meta.glslKey] = runtime.getStateIndex(name);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
break;
|
|
246
|
+
|
|
247
|
+
case 'emit-aria':
|
|
248
|
+
if (!frameBudget || frameBudget.canRun('low')) {
|
|
249
|
+
for (const name of dirtyNames) {
|
|
250
|
+
const meta = metaMap.get(name)!;
|
|
251
|
+
const stateStr = discrete[name];
|
|
252
|
+
if (stateStr !== undefined) {
|
|
253
|
+
aria[meta.ariaKey] = stateStr;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (dirty) {
|
|
262
|
+
dirty.clearAll();
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Two-slot rotation: the most-recently-published state stays readable for one
|
|
266
|
+
// more tick (so consumers who hold a reference returned from compute() see live
|
|
267
|
+
// data until the *next-next* publish). Without this rotation, every tick takes
|
|
268
|
+
// the overflow path in CompositorStatePool.acquire and the pool grows unboundedly.
|
|
269
|
+
const releasable = priorPreviousState;
|
|
270
|
+
priorPreviousState = previousState;
|
|
271
|
+
previousState = state;
|
|
272
|
+
Effect.runSync(SubscriptionRef.set(stateRef, state));
|
|
273
|
+
if (releasable && releasable !== state) pool.release(releasable);
|
|
274
|
+
return state;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const compositor: CompositorShape = {
|
|
278
|
+
add: <B extends Boundary.Shape>(name: string, quantizer: Quantizer<B>) =>
|
|
279
|
+
Effect.sync(() => {
|
|
280
|
+
// Quantizer<B> is covariant in B (B only appears in return types), so widening
|
|
281
|
+
// to Quantizer<Boundary.Shape> is sound; wrap in a named helper to document.
|
|
282
|
+
qMap.set(name, widenQuantizer(quantizer));
|
|
283
|
+
metaMap.set(name, {
|
|
284
|
+
cssKey: `--czap-${name}`,
|
|
285
|
+
glslKey: `u_${name}`,
|
|
286
|
+
ariaKey: `data-czap-${name}`,
|
|
287
|
+
oneHotWeights: Object.fromEntries(
|
|
288
|
+
quantizer.boundary.states.map((activeState) => [
|
|
289
|
+
activeState as string,
|
|
290
|
+
Object.freeze(
|
|
291
|
+
Object.fromEntries(
|
|
292
|
+
quantizer.boundary.states.map((stateName) => [
|
|
293
|
+
stateName as string,
|
|
294
|
+
stateName === activeState ? 1 : 0,
|
|
295
|
+
]),
|
|
296
|
+
),
|
|
297
|
+
),
|
|
298
|
+
]),
|
|
299
|
+
),
|
|
300
|
+
});
|
|
301
|
+
runtime.registerQuantizer(name, quantizer.boundary.states as readonly string[]);
|
|
302
|
+
runtime.markDirty(name);
|
|
303
|
+
|
|
304
|
+
if (!nameList.includes(name)) {
|
|
305
|
+
nameList.push(name);
|
|
306
|
+
rebuildDirtyFlags();
|
|
307
|
+
}
|
|
308
|
+
if (dirty) {
|
|
309
|
+
dirty.mark(name);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (useSpeculative) {
|
|
313
|
+
speculativeEvaluators.set(name, SpeculativeEvaluator.make(quantizer.boundary));
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
computeStateSync();
|
|
317
|
+
}),
|
|
318
|
+
|
|
319
|
+
remove: (name: string) =>
|
|
320
|
+
Effect.sync(() => {
|
|
321
|
+
qMap.delete(name);
|
|
322
|
+
metaMap.delete(name);
|
|
323
|
+
nameList = nameList.filter((entry) => entry !== name);
|
|
324
|
+
rebuildDirtyFlags();
|
|
325
|
+
runtime.removeQuantizer(name);
|
|
326
|
+
speculativeEvaluators.delete(name);
|
|
327
|
+
prefetchedStates.delete(name);
|
|
328
|
+
computeStateSync();
|
|
329
|
+
}),
|
|
330
|
+
|
|
331
|
+
compute: () => Effect.sync(() => computeStateSync()),
|
|
332
|
+
|
|
333
|
+
setBlendWeights: (name: string, weights: Record<string, number>) =>
|
|
334
|
+
Effect.sync(() => {
|
|
335
|
+
overrides.set(name, weights);
|
|
336
|
+
if (dirty) {
|
|
337
|
+
dirty.mark(name);
|
|
338
|
+
}
|
|
339
|
+
runtime.markDirty(name);
|
|
340
|
+
}),
|
|
341
|
+
|
|
342
|
+
evaluateSpeculative(name: string, value: number, velocity?: number): void {
|
|
343
|
+
const speculative = speculativeEvaluators.get(name);
|
|
344
|
+
if (!speculative) {
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const result = speculative.evaluate(value, velocity);
|
|
349
|
+
if (result.prefetched && result.confidence > 0.7) {
|
|
350
|
+
prefetchedStates.set(name, result.prefetched as string);
|
|
351
|
+
runtime.markDirty(name);
|
|
352
|
+
if (dirty) {
|
|
353
|
+
dirty.mark(name);
|
|
354
|
+
}
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
prefetchedStates.delete(name);
|
|
359
|
+
},
|
|
360
|
+
|
|
361
|
+
scheduleBatch(): void {
|
|
362
|
+
if (batchScheduled) {
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
batchScheduled = true;
|
|
367
|
+
queueMicrotask(() => {
|
|
368
|
+
batchScheduled = false;
|
|
369
|
+
computeStateSync();
|
|
370
|
+
});
|
|
371
|
+
},
|
|
372
|
+
|
|
373
|
+
changes: SubscriptionRef.changes(stateRef),
|
|
374
|
+
runtime,
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
return compositor;
|
|
378
|
+
});
|
|
379
|
+
},
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
export declare namespace Compositor {
|
|
383
|
+
/** Structural shape of a live compositor instance. */
|
|
384
|
+
export type Shape = CompositorShape;
|
|
385
|
+
/** Alias for {@link CompositorConfig}. */
|
|
386
|
+
export type Config = CompositorConfig;
|
|
387
|
+
}
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config -- unified project configuration hub.
|
|
3
|
+
*
|
|
4
|
+
* Config.make() produces a frozen, FNV-1a content-addressed Config.Shape.
|
|
5
|
+
* Projection functions are pure — no side effects, no I/O.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ContentAddress } from './brands.js';
|
|
9
|
+
import type { Boundary } from './boundary.js';
|
|
10
|
+
import type { Token } from './token.js';
|
|
11
|
+
import type { Theme } from './theme.js';
|
|
12
|
+
import type { Style } from './style.js';
|
|
13
|
+
import { fnv1a } from './fnv.js';
|
|
14
|
+
|
|
15
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
16
|
+
// Public types
|
|
17
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
/** Top-level discriminator for czap primitives: which bucket a declaration belongs to. */
|
|
20
|
+
export type PrimitiveKind = 'boundary' | 'token' | 'theme' | 'style';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Vite-plugin slice of a czap {@link Config.Shape}: source directories per
|
|
24
|
+
* primitive kind, HMR opt-in, environment targeting, and optional WASM hints.
|
|
25
|
+
*/
|
|
26
|
+
export interface PluginConfig {
|
|
27
|
+
readonly dirs?: Partial<Record<PrimitiveKind, string>>;
|
|
28
|
+
readonly hmr?: boolean;
|
|
29
|
+
readonly environments?: readonly ('browser' | 'server' | 'shader')[];
|
|
30
|
+
readonly wasm?: { readonly enabled?: boolean; readonly path?: string };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Astro-integration slice of a czap {@link Config.Shape}. */
|
|
34
|
+
export interface AstroConfig {
|
|
35
|
+
readonly satellite?: boolean;
|
|
36
|
+
readonly edgeRuntime?: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
40
|
+
// Config namespace + value object (declaration merging — same pattern as Boundary)
|
|
41
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Config namespace — the single hub that every czap adapter (Vite, Astro, test
|
|
45
|
+
* runners, edge runtime) projects from. {@link Config.make} produces a frozen,
|
|
46
|
+
* FNV-1a content-addressed {@link Config.Shape}; every projection function
|
|
47
|
+
* (`toViteConfig`, `toAstroConfig`, `toTestAliases`) is pure.
|
|
48
|
+
*/
|
|
49
|
+
export const Config = {
|
|
50
|
+
/** Build a frozen, content-addressed {@link Config.Shape} from raw input. */
|
|
51
|
+
make(input: Config.Input): Config.Shape {
|
|
52
|
+
// Sort named collection keys so insertion order doesn't affect the hash.
|
|
53
|
+
const sortKeys = <V>(obj: Record<string, V>): Record<string, V> =>
|
|
54
|
+
Object.fromEntries(Object.entries(obj).sort());
|
|
55
|
+
const canonical = JSON.stringify({
|
|
56
|
+
boundaries: sortKeys(input.boundaries ?? {}),
|
|
57
|
+
tokens: sortKeys(input.tokens ?? {}),
|
|
58
|
+
themes: sortKeys(input.themes ?? {}),
|
|
59
|
+
styles: sortKeys(input.styles ?? {}),
|
|
60
|
+
vite: input.vite,
|
|
61
|
+
astro: input.astro,
|
|
62
|
+
});
|
|
63
|
+
const id = fnv1a(canonical);
|
|
64
|
+
return Object.freeze({
|
|
65
|
+
_tag: 'ConfigDef' as const,
|
|
66
|
+
id,
|
|
67
|
+
boundaries: input.boundaries ?? {},
|
|
68
|
+
tokens: input.tokens ?? {},
|
|
69
|
+
themes: input.themes ?? {},
|
|
70
|
+
styles: input.styles ?? {},
|
|
71
|
+
vite: input.vite,
|
|
72
|
+
astro: input.astro,
|
|
73
|
+
});
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
/** Project the Vite-plugin slice of a config for `@czap/vite`. */
|
|
77
|
+
toViteConfig(cfg: Config.Shape): PluginConfig {
|
|
78
|
+
return {
|
|
79
|
+
...(cfg.vite?.dirs !== undefined && { dirs: cfg.vite.dirs }),
|
|
80
|
+
...(cfg.vite?.hmr !== undefined && { hmr: cfg.vite.hmr }),
|
|
81
|
+
...(cfg.vite?.environments !== undefined && { environments: cfg.vite.environments }),
|
|
82
|
+
...(cfg.vite?.wasm !== undefined && { wasm: cfg.vite.wasm }),
|
|
83
|
+
};
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
/** Project the Astro-integration slice of a config for `@czap/astro`. */
|
|
87
|
+
toAstroConfig(cfg: Config.Shape): AstroConfig {
|
|
88
|
+
return {
|
|
89
|
+
...(cfg.astro?.satellite !== undefined && { satellite: cfg.astro.satellite }),
|
|
90
|
+
...(cfg.astro?.edgeRuntime !== undefined && { edgeRuntime: cfg.astro.edgeRuntime }),
|
|
91
|
+
};
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
/** Materialize the `@czap/*` → source-path alias map used by the vitest runner. */
|
|
95
|
+
toTestAliases(cfg: Config.Shape, repoRoot: string): Record<string, string> {
|
|
96
|
+
void cfg; // cfg reserved for future per-project customisation
|
|
97
|
+
// Use forward-slash join so paths are portable across platforms.
|
|
98
|
+
const r = (sub: string) => `${repoRoot.replace(/\\/g, '/')}/${sub}`;
|
|
99
|
+
// NOTE: longer prefixes MUST come before shorter ones — vitest's alias
|
|
100
|
+
// resolver matches the first prefix in iteration order, so e.g.
|
|
101
|
+
// `@czap/core/testing` would be intercepted by `@czap/core` if listed first.
|
|
102
|
+
return {
|
|
103
|
+
'@czap/core/testing': r('packages/core/src/testing.ts'),
|
|
104
|
+
'@czap/core/harness': r('packages/core/src/harness/index.ts'),
|
|
105
|
+
'@czap/core': r('packages/core/src/index.ts'),
|
|
106
|
+
'@czap/quantizer/testing': r('packages/quantizer/src/testing.ts'),
|
|
107
|
+
'@czap/quantizer': r('packages/quantizer/src/index.ts'),
|
|
108
|
+
'@czap/compiler': r('packages/compiler/src/index.ts'),
|
|
109
|
+
'@czap/web/lite': r('packages/web/src/lite.ts'),
|
|
110
|
+
'@czap/web': r('packages/web/src/index.ts'),
|
|
111
|
+
'@czap/detect': r('packages/detect/src/index.ts'),
|
|
112
|
+
'@czap/vite/html-transform': r('packages/vite/src/html-transform.ts'),
|
|
113
|
+
'@czap/vite': r('packages/vite/src/index.ts'),
|
|
114
|
+
'@czap/astro/runtime': r('packages/astro/src/runtime/index.ts'),
|
|
115
|
+
'@czap/astro': r('packages/astro/src/index.ts'),
|
|
116
|
+
'@czap/remotion': r('packages/remotion/src/index.ts'),
|
|
117
|
+
'@czap/scene/dev': r('packages/scene/src/dev/server.ts'),
|
|
118
|
+
'@czap/scene': r('packages/scene/src/index.ts'),
|
|
119
|
+
'@czap/assets/testing': r('packages/assets/src/testing.ts'),
|
|
120
|
+
'@czap/assets': r('packages/assets/src/index.ts'),
|
|
121
|
+
'@czap/cli': r('packages/cli/src/index.ts'),
|
|
122
|
+
'@czap/mcp-server': r('packages/mcp-server/src/index.ts'),
|
|
123
|
+
'@czap/edge': r('packages/edge/src/index.ts'),
|
|
124
|
+
'@czap/worker': r('packages/worker/src/index.ts'),
|
|
125
|
+
'@czap/_spine': r('packages/_spine'),
|
|
126
|
+
};
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
export declare namespace Config {
|
|
131
|
+
/** Raw user-facing input to {@link Config.make} — every field is optional. */
|
|
132
|
+
interface Input {
|
|
133
|
+
readonly boundaries?: Record<string, Boundary.Shape>;
|
|
134
|
+
readonly tokens?: Record<string, Token.Shape>;
|
|
135
|
+
readonly themes?: Record<string, Theme.Shape>;
|
|
136
|
+
readonly styles?: Record<string, Style.Shape>;
|
|
137
|
+
readonly vite?: Partial<PluginConfig>;
|
|
138
|
+
readonly astro?: Partial<AstroConfig>;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Frozen, content-addressed result of {@link Config.make}. */
|
|
142
|
+
interface Shape {
|
|
143
|
+
readonly _tag: 'ConfigDef';
|
|
144
|
+
readonly id: ContentAddress;
|
|
145
|
+
readonly boundaries: Record<string, Boundary.Shape>;
|
|
146
|
+
readonly tokens: Record<string, Token.Shape>;
|
|
147
|
+
readonly themes: Record<string, Theme.Shape>;
|
|
148
|
+
readonly styles: Record<string, Style.Shape>;
|
|
149
|
+
readonly vite?: Partial<PluginConfig>;
|
|
150
|
+
readonly astro?: Partial<AstroConfig>;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** Thin alias for {@link Config.make} — matches the `defineConfig(...)` ergonomics other tools use. */
|
|
155
|
+
export function defineConfig(input: Config.Input): Config.Shape {
|
|
156
|
+
return Config.make(input);
|
|
157
|
+
}
|