@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
package/dist/receipt.js
ADDED
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Receipt -- chain validation and envelope construction.
|
|
3
|
+
*
|
|
4
|
+
* Salvaged from `@kit/core`.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
import { Effect } from 'effect';
|
|
9
|
+
import { TypedRef as TypedRefModule } from './typed-ref.js';
|
|
10
|
+
import { HLC as HLCOps } from './hlc.js';
|
|
11
|
+
/** Sentinel `previous` value marking the root of a receipt chain. */
|
|
12
|
+
export const GENESIS = 'genesis';
|
|
13
|
+
/**
|
|
14
|
+
* Compute the content hash of a receipt envelope.
|
|
15
|
+
*
|
|
16
|
+
* Normalizes the `previous` field (sorts array form), canonicalizes the
|
|
17
|
+
* payload, and hashes with SHA-256 via TypedRef.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { Effect } from 'effect';
|
|
22
|
+
*
|
|
23
|
+
* const hash = yield* Receipt.hashEnvelope(envelope);
|
|
24
|
+
* // hash === envelope.hash (if envelope is valid)
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export const hashEnvelope = (envelope) => {
|
|
28
|
+
const previousNormalized = Array.isArray(envelope.previous)
|
|
29
|
+
? [...envelope.previous].sort()
|
|
30
|
+
: envelope.previous;
|
|
31
|
+
const hashInput = TypedRefModule.canonicalize({
|
|
32
|
+
kind: envelope.kind,
|
|
33
|
+
timestamp: envelope.timestamp,
|
|
34
|
+
subject: envelope.subject,
|
|
35
|
+
payload: envelope.payload,
|
|
36
|
+
previous: previousNormalized,
|
|
37
|
+
});
|
|
38
|
+
return TypedRefModule.hash(hashInput);
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Create a new receipt envelope with an auto-computed content hash.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* const envelope = yield* Receipt.createEnvelope(
|
|
46
|
+
* 'state-change',
|
|
47
|
+
* { type: 'effect', id: 'actor-1' },
|
|
48
|
+
* { _tag: 'TypedRef', mediaType: 'application/json', data: { key: 'value' } },
|
|
49
|
+
* hlcTimestamp,
|
|
50
|
+
* Receipt.GENESIS,
|
|
51
|
+
* );
|
|
52
|
+
* // envelope.hash is the computed SHA-256 content address
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export const createEnvelope = (kind, subject, payload, timestamp, previousHash) => Effect.gen(function* () {
|
|
56
|
+
const previousNormalized = Array.isArray(previousHash)
|
|
57
|
+
? [...previousHash].sort()
|
|
58
|
+
: previousHash;
|
|
59
|
+
const partial = { kind, timestamp, subject, payload, previous: previousNormalized };
|
|
60
|
+
const h = yield* TypedRefModule.hash(TypedRefModule.canonicalize(partial));
|
|
61
|
+
return { kind, timestamp, subject, payload, hash: h, previous: previousNormalized };
|
|
62
|
+
});
|
|
63
|
+
/**
|
|
64
|
+
* Build a linear chain of receipt envelopes from an array of entries.
|
|
65
|
+
*
|
|
66
|
+
* Each envelope's `previous` points to the prior envelope's hash,
|
|
67
|
+
* starting from GENESIS.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts
|
|
71
|
+
* const chain = yield* Receipt.buildChain([
|
|
72
|
+
* { kind: 'init', subject: { type: 'effect', id: 'a' }, payload, timestamp: ts1 },
|
|
73
|
+
* { kind: 'update', subject: { type: 'effect', id: 'a' }, payload, timestamp: ts2 },
|
|
74
|
+
* ]);
|
|
75
|
+
* // chain.length === 2
|
|
76
|
+
* // chain[1].previous === chain[0].hash
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export const buildChain = (entries) => Effect.gen(function* () {
|
|
80
|
+
const chain = [];
|
|
81
|
+
let previousHash = GENESIS;
|
|
82
|
+
for (const entry of entries) {
|
|
83
|
+
const envelope = yield* createEnvelope(entry.kind, entry.subject, entry.payload, entry.timestamp, previousHash);
|
|
84
|
+
chain.push(envelope);
|
|
85
|
+
previousHash = envelope.hash;
|
|
86
|
+
}
|
|
87
|
+
return chain;
|
|
88
|
+
});
|
|
89
|
+
/**
|
|
90
|
+
* Validate a receipt chain: genesis link, hash integrity, chain continuity, HLC ordering.
|
|
91
|
+
*
|
|
92
|
+
* Returns true on success or fails with an Error describing the violation.
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```ts
|
|
96
|
+
* const chain = yield* Receipt.buildChain(entries);
|
|
97
|
+
* const valid = yield* Receipt.validateChain(chain);
|
|
98
|
+
* // valid === true
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
export const validateChain = (chain) => Effect.gen(function* () {
|
|
102
|
+
if (chain.length === 0)
|
|
103
|
+
return true;
|
|
104
|
+
const first = chain[0];
|
|
105
|
+
const firstPrev = first.previous;
|
|
106
|
+
if (firstPrev !== GENESIS && !(Array.isArray(firstPrev) && firstPrev.includes(GENESIS))) {
|
|
107
|
+
return yield* Effect.fail(new Error('First envelope must have previous=genesis'));
|
|
108
|
+
}
|
|
109
|
+
for (let i = 0; i < chain.length; i++) {
|
|
110
|
+
const envelope = chain[i];
|
|
111
|
+
const computedHash = yield* hashEnvelope(envelope);
|
|
112
|
+
if (computedHash !== envelope.hash) {
|
|
113
|
+
return yield* Effect.fail(new Error(`Envelope ${i}: hash mismatch (expected "${envelope.hash}", computed "${computedHash}")`));
|
|
114
|
+
}
|
|
115
|
+
const isMerge = Array.isArray(envelope.previous);
|
|
116
|
+
if (!isMerge && i > 0 && envelope.previous !== chain[i - 1].hash) {
|
|
117
|
+
return yield* Effect.fail(new Error(`Envelope ${i}: chain break`));
|
|
118
|
+
}
|
|
119
|
+
if (!isMerge && i > 0 && HLCOps.compare(chain[i - 1].timestamp, envelope.timestamp) >= 0) {
|
|
120
|
+
return yield* Effect.fail(new Error(`Envelope ${i}: HLC not monotonically increasing`));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return true;
|
|
124
|
+
});
|
|
125
|
+
/**
|
|
126
|
+
* Validate a receipt chain with detailed, structured error reporting.
|
|
127
|
+
*
|
|
128
|
+
* Returns `true` on success or fails with a typed `ChainValidationError`
|
|
129
|
+
* discriminated union (not_genesis | hash_mismatch | chain_break | hlc_not_increasing).
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```ts
|
|
133
|
+
* import { Effect } from 'effect';
|
|
134
|
+
*
|
|
135
|
+
* const result = yield* Effect.either(Receipt.validateChainDetailed(chain));
|
|
136
|
+
* // result._tag === 'Right' on success
|
|
137
|
+
* // result._tag === 'Left' with .left.type on failure
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
export const validateChainDetailed = (chain) => Effect.gen(function* () {
|
|
141
|
+
if (chain.length === 0)
|
|
142
|
+
return true;
|
|
143
|
+
const first = chain[0];
|
|
144
|
+
const firstPrev = first.previous;
|
|
145
|
+
const firstIsGenesis = firstPrev === GENESIS || (Array.isArray(firstPrev) && firstPrev.includes(GENESIS));
|
|
146
|
+
if (!firstIsGenesis) {
|
|
147
|
+
return yield* Effect.fail({ type: 'not_genesis', index: 0 });
|
|
148
|
+
}
|
|
149
|
+
for (let i = 0; i < chain.length; i++) {
|
|
150
|
+
const envelope = chain[i];
|
|
151
|
+
const isMerge = Array.isArray(envelope.previous);
|
|
152
|
+
const computedHash = yield* hashEnvelope(envelope);
|
|
153
|
+
if (computedHash !== envelope.hash) {
|
|
154
|
+
return yield* Effect.fail({
|
|
155
|
+
type: 'hash_mismatch',
|
|
156
|
+
index: i,
|
|
157
|
+
computed: computedHash,
|
|
158
|
+
stored: envelope.hash,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
if (!isMerge && i > 0 && envelope.previous !== chain[i - 1].hash) {
|
|
162
|
+
return yield* Effect.fail({
|
|
163
|
+
type: 'chain_break',
|
|
164
|
+
index: i,
|
|
165
|
+
expected: chain[i - 1].hash,
|
|
166
|
+
actual: envelope.previous,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
if (!isMerge && i > 0 && HLCOps.compare(chain[i - 1].timestamp, envelope.timestamp) >= 0) {
|
|
170
|
+
return yield* Effect.fail({
|
|
171
|
+
type: 'hlc_not_increasing',
|
|
172
|
+
index: i,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return true;
|
|
177
|
+
});
|
|
178
|
+
/**
|
|
179
|
+
* Check whether a receipt envelope is a genesis (root) envelope.
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* ```ts
|
|
183
|
+
* const chain = yield* Receipt.buildChain(entries);
|
|
184
|
+
* Receipt.isGenesis(chain[0]); // true
|
|
185
|
+
* Receipt.isGenesis(chain[1]); // false
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
188
|
+
export const isGenesis = (receipt) => receipt.previous === GENESIS ||
|
|
189
|
+
(Array.isArray(receipt.previous) && receipt.previous.includes(GENESIS));
|
|
190
|
+
/**
|
|
191
|
+
* Get the last (most recent) envelope in a chain.
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```ts
|
|
195
|
+
* const latest = Receipt.head(chain);
|
|
196
|
+
* // latest === chain[chain.length - 1]
|
|
197
|
+
* ```
|
|
198
|
+
*/
|
|
199
|
+
export const head = (chain) => chain.length > 0 ? chain[chain.length - 1] : undefined;
|
|
200
|
+
/**
|
|
201
|
+
* Get the first (genesis) envelope in a chain.
|
|
202
|
+
*
|
|
203
|
+
* @example
|
|
204
|
+
* ```ts
|
|
205
|
+
* const first = Receipt.tail(chain);
|
|
206
|
+
* // first === chain[0]
|
|
207
|
+
* ```
|
|
208
|
+
*/
|
|
209
|
+
export const tail = (chain) => chain.length > 0 ? chain[0] : undefined;
|
|
210
|
+
/**
|
|
211
|
+
* Append a new entry to an existing chain, auto-linking to the previous hash.
|
|
212
|
+
*
|
|
213
|
+
* Optionally accepts explicit previous hashes for merge envelopes.
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* ```ts
|
|
217
|
+
* const chain = yield* Receipt.buildChain([entry1]);
|
|
218
|
+
* const extended = yield* Receipt.append(chain, {
|
|
219
|
+
* kind: 'update', subject: { type: 'effect', id: 'a' }, payload, timestamp: ts2,
|
|
220
|
+
* });
|
|
221
|
+
* // extended.length === 2
|
|
222
|
+
* ```
|
|
223
|
+
*/
|
|
224
|
+
export const append = (chain, entry, previousHashes) => Effect.gen(function* () {
|
|
225
|
+
const previousHash = previousHashes
|
|
226
|
+
? previousHashes
|
|
227
|
+
: chain.length > 0
|
|
228
|
+
? chain[chain.length - 1].hash
|
|
229
|
+
: GENESIS;
|
|
230
|
+
const envelope = yield* createEnvelope(entry.kind, entry.subject, entry.payload, entry.timestamp, previousHash);
|
|
231
|
+
return [...chain, envelope];
|
|
232
|
+
});
|
|
233
|
+
/**
|
|
234
|
+
* Find an envelope in a chain by its content hash.
|
|
235
|
+
*
|
|
236
|
+
* @example
|
|
237
|
+
* ```ts
|
|
238
|
+
* const found = Receipt.findByHash(chain, targetHash);
|
|
239
|
+
* // found?.hash === targetHash
|
|
240
|
+
* ```
|
|
241
|
+
*/
|
|
242
|
+
export const findByHash = (chain, hash) => chain.find((e) => e.hash === hash);
|
|
243
|
+
/**
|
|
244
|
+
* Find all envelopes in a chain matching a given kind.
|
|
245
|
+
*
|
|
246
|
+
* @example
|
|
247
|
+
* ```ts
|
|
248
|
+
* const updates = Receipt.findByKind(chain, 'update');
|
|
249
|
+
* // updates contains all envelopes with kind === 'update'
|
|
250
|
+
* ```
|
|
251
|
+
*/
|
|
252
|
+
export const findByKind = (chain, kind) => chain.filter((e) => e.kind === kind);
|
|
253
|
+
/**
|
|
254
|
+
* Generate an HMAC-SHA-256 key for signing receipt envelopes.
|
|
255
|
+
*
|
|
256
|
+
* @example
|
|
257
|
+
* ```ts
|
|
258
|
+
* const key = yield* Receipt.generateMACKey();
|
|
259
|
+
* const signed = yield* Receipt.macEnvelope(envelope, key);
|
|
260
|
+
* // signed.signature is a hex string
|
|
261
|
+
* ```
|
|
262
|
+
*/
|
|
263
|
+
export const generateMACKey = () => Effect.tryPromise({
|
|
264
|
+
try: () => crypto.subtle.generateKey({ name: 'HMAC', hash: { name: 'SHA-256' } }, true, ['sign', 'verify']),
|
|
265
|
+
catch: (error) => new Error(`Failed to generate MAC key: ${error}`),
|
|
266
|
+
});
|
|
267
|
+
/**
|
|
268
|
+
* Sign a receipt envelope with an HMAC key, adding a `signature` field.
|
|
269
|
+
*
|
|
270
|
+
* @example
|
|
271
|
+
* ```ts
|
|
272
|
+
* const key = yield* Receipt.generateMACKey();
|
|
273
|
+
* const signed = yield* Receipt.macEnvelope(envelope, key);
|
|
274
|
+
* // signed.signature !== undefined
|
|
275
|
+
* ```
|
|
276
|
+
*/
|
|
277
|
+
export const macEnvelope = (envelope, key) => Effect.gen(function* () {
|
|
278
|
+
const data = new TextEncoder().encode(envelope.hash);
|
|
279
|
+
const signatureBuffer = yield* Effect.tryPromise({
|
|
280
|
+
try: () => crypto.subtle.sign('HMAC', key, data),
|
|
281
|
+
catch: (error) => new Error(`Failed to MAC envelope: ${error}`),
|
|
282
|
+
});
|
|
283
|
+
const signatureArray = Array.from(new Uint8Array(signatureBuffer));
|
|
284
|
+
const signature = signatureArray.map((b) => b.toString(16).padStart(2, '0')).join('');
|
|
285
|
+
return { ...envelope, signature };
|
|
286
|
+
});
|
|
287
|
+
/**
|
|
288
|
+
* Verify an envelope's HMAC signature against a key.
|
|
289
|
+
*
|
|
290
|
+
* Returns false if the envelope has no signature.
|
|
291
|
+
*
|
|
292
|
+
* @example
|
|
293
|
+
* ```ts
|
|
294
|
+
* const valid = yield* Receipt.verifyMAC(signedEnvelope, key);
|
|
295
|
+
* // valid === true if signature matches
|
|
296
|
+
* ```
|
|
297
|
+
*/
|
|
298
|
+
export const verifyMAC = (envelope, key) => Effect.gen(function* () {
|
|
299
|
+
if (!envelope.signature)
|
|
300
|
+
return false;
|
|
301
|
+
const signatureHex = envelope.signature;
|
|
302
|
+
if (!/^[0-9a-fA-F]+$/.test(signatureHex) || signatureHex.length % 2 !== 0) {
|
|
303
|
+
return yield* Effect.fail(new Error('Invalid signature hex: expected even-length hex string'));
|
|
304
|
+
}
|
|
305
|
+
const signatureArray = new Uint8Array(signatureHex.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)));
|
|
306
|
+
const data = new TextEncoder().encode(envelope.hash);
|
|
307
|
+
const valid = yield* Effect.tryPromise({
|
|
308
|
+
try: () => crypto.subtle.verify('HMAC', key, signatureArray, data),
|
|
309
|
+
catch: (error) => new Error(`Failed to verify signature: ${error}`),
|
|
310
|
+
});
|
|
311
|
+
return valid;
|
|
312
|
+
});
|
|
313
|
+
/**
|
|
314
|
+
* Receipt namespace -- chain validation and envelope construction.
|
|
315
|
+
*
|
|
316
|
+
* Build, validate, append, query, and sign linear receipt chains.
|
|
317
|
+
* Each envelope is content-addressed and linked to its predecessor.
|
|
318
|
+
* Supports HMAC signing/verification for tamper detection.
|
|
319
|
+
*
|
|
320
|
+
* @example
|
|
321
|
+
* ```ts
|
|
322
|
+
* import { Effect } from 'effect';
|
|
323
|
+
* import { Receipt, HLC } from '@czap/core';
|
|
324
|
+
*
|
|
325
|
+
* const program = Effect.gen(function* () {
|
|
326
|
+
* const ts = HLC.increment(HLC.create('node-1'), Date.now());
|
|
327
|
+
* const chain = yield* Receipt.buildChain([
|
|
328
|
+
* { kind: 'init', subject: { type: 'effect', id: 'a' }, payload, timestamp: ts },
|
|
329
|
+
* ]);
|
|
330
|
+
* const valid = yield* Receipt.validateChain(chain);
|
|
331
|
+
* const latest = Receipt.head(chain);
|
|
332
|
+
* });
|
|
333
|
+
* ```
|
|
334
|
+
*/
|
|
335
|
+
export const Receipt = {
|
|
336
|
+
GENESIS,
|
|
337
|
+
createEnvelope,
|
|
338
|
+
buildChain,
|
|
339
|
+
validateChain,
|
|
340
|
+
validateChainDetailed,
|
|
341
|
+
hashEnvelope,
|
|
342
|
+
isGenesis,
|
|
343
|
+
head,
|
|
344
|
+
tail,
|
|
345
|
+
append,
|
|
346
|
+
findByHash,
|
|
347
|
+
findByKind,
|
|
348
|
+
generateMACKey,
|
|
349
|
+
macEnvelope,
|
|
350
|
+
verifyMAC,
|
|
351
|
+
};
|
|
352
|
+
//# sourceMappingURL=receipt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"receipt.js","sourceRoot":"","sources":["../src/receipt.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RuntimeCoordinator -- shared host/runtime coordination surface.
|
|
3
|
+
*
|
|
4
|
+
* Bridges Plan and ECS into the live host path by:
|
|
5
|
+
* - defining the execution graph for runtime passes
|
|
6
|
+
* - backing quantizer state indices and dirty epochs with dense stores
|
|
7
|
+
*
|
|
8
|
+
* The coordinator is intentionally light-weight on the hot path: the plan is
|
|
9
|
+
* constructed once up front, and dense stores are used for numeric state that
|
|
10
|
+
* is read repeatedly during runtime work.
|
|
11
|
+
*
|
|
12
|
+
* @module
|
|
13
|
+
*/
|
|
14
|
+
import { EntityId } from './ecs.js';
|
|
15
|
+
import type { DenseStore } from './ecs.js';
|
|
16
|
+
import { Plan } from './plan.js';
|
|
17
|
+
/**
|
|
18
|
+
* Named stages of the runtime frame pass, in canonical topological order:
|
|
19
|
+
* discrete quantization first, then blend weights, then target emitters.
|
|
20
|
+
*/
|
|
21
|
+
export type RuntimePhase = 'compute-discrete' | 'compute-blend' | 'emit-css' | 'emit-glsl' | 'emit-aria';
|
|
22
|
+
/** Options accepted by {@link RuntimeCoordinator.create}: entity capacity and plan name. */
|
|
23
|
+
export interface RuntimeCoordinatorConfig {
|
|
24
|
+
readonly capacity?: number;
|
|
25
|
+
readonly name?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Live coordinator surface: the immutable runtime {@link Plan}, ordered phase
|
|
29
|
+
* list, dense stores for state index + dirty epoch, and registration/mutation
|
|
30
|
+
* APIs used by the compositor on the hot path.
|
|
31
|
+
*/
|
|
32
|
+
export interface RuntimeCoordinatorShape {
|
|
33
|
+
readonly plan: Plan.IR;
|
|
34
|
+
readonly phases: readonly RuntimePhase[];
|
|
35
|
+
readonly stores: {
|
|
36
|
+
readonly stateIndex: DenseStore;
|
|
37
|
+
readonly dirtyEpoch: DenseStore;
|
|
38
|
+
};
|
|
39
|
+
reset(registrations?: readonly {
|
|
40
|
+
readonly name: string;
|
|
41
|
+
readonly states: readonly string[];
|
|
42
|
+
}[]): void;
|
|
43
|
+
registerQuantizer(name: string, states: readonly string[]): EntityId;
|
|
44
|
+
removeQuantizer(name: string): void;
|
|
45
|
+
hasQuantizer(name: string): boolean;
|
|
46
|
+
setState(name: string, state: string): void;
|
|
47
|
+
applyState(name: string, state: string): number;
|
|
48
|
+
getStateIndex(name: string): number;
|
|
49
|
+
markDirty(name: string): void;
|
|
50
|
+
getDirtyEpoch(name: string): number;
|
|
51
|
+
registeredNames(): readonly string[];
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Build a fresh {@link RuntimeCoordinator} with dense backing stores and the
|
|
55
|
+
* canonical runtime plan. Prefer {@link RuntimeCoordinator.create}, which is
|
|
56
|
+
* the exported entry point.
|
|
57
|
+
*/
|
|
58
|
+
export declare function createRuntimeCoordinator(config?: RuntimeCoordinatorConfig): RuntimeCoordinatorShape;
|
|
59
|
+
/**
|
|
60
|
+
* Runtime coordinator namespace — single entry point for building the shared
|
|
61
|
+
* {@link Plan} + ECS store bundle consumed by every host adapter.
|
|
62
|
+
*/
|
|
63
|
+
export declare const RuntimeCoordinator: {
|
|
64
|
+
/** Create a fresh coordinator. See {@link createRuntimeCoordinator}. */
|
|
65
|
+
readonly create: typeof createRuntimeCoordinator;
|
|
66
|
+
};
|
|
67
|
+
export declare namespace RuntimeCoordinator {
|
|
68
|
+
/** Alias for `RuntimeCoordinatorShape`. */
|
|
69
|
+
type Shape = RuntimeCoordinatorShape;
|
|
70
|
+
/** Alias for `RuntimeCoordinatorConfig`. */
|
|
71
|
+
type Config = RuntimeCoordinatorConfig;
|
|
72
|
+
/** Alias for `RuntimePhase`. */
|
|
73
|
+
type Phase = RuntimePhase;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=runtime-coordinator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-coordinator.d.ts","sourceRoot":"","sources":["../src/runtime-coordinator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAQ,QAAQ,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,kBAAkB,GAAG,eAAe,GAAG,UAAU,GAAG,WAAW,GAAG,WAAW,CAAC;AAEzG,4FAA4F;AAC5F,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,CAAC;IACzC,QAAQ,CAAC,MAAM,EAAE;QACf,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;QAChC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;KACjC,CAAC;IACF,KAAK,CACH,aAAa,CAAC,EAAE,SAAS;QACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;KACpC,EAAE,GACF,IAAI,CAAC;IACR,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,QAAQ,CAAC;IACrE,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAChD,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACpC,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACpC,eAAe,IAAI,SAAS,MAAM,EAAE,CAAC;CACtC;AAkCD;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,CAAC,EAAE,wBAAwB,GAAG,uBAAuB,CAmHnG;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB;IAC7B,wEAAwE;;CAEhE,CAAC;AAEX,MAAM,CAAC,OAAO,WAAW,kBAAkB,CAAC;IAC1C,2CAA2C;IAC3C,KAAY,KAAK,GAAG,uBAAuB,CAAC;IAC5C,4CAA4C;IAC5C,KAAY,MAAM,GAAG,wBAAwB,CAAC;IAC9C,gCAAgC;IAChC,KAAY,KAAK,GAAG,YAAY,CAAC;CAClC"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RuntimeCoordinator -- shared host/runtime coordination surface.
|
|
3
|
+
*
|
|
4
|
+
* Bridges Plan and ECS into the live host path by:
|
|
5
|
+
* - defining the execution graph for runtime passes
|
|
6
|
+
* - backing quantizer state indices and dirty epochs with dense stores
|
|
7
|
+
*
|
|
8
|
+
* The coordinator is intentionally light-weight on the hot path: the plan is
|
|
9
|
+
* constructed once up front, and dense stores are used for numeric state that
|
|
10
|
+
* is read repeatedly during runtime work.
|
|
11
|
+
*
|
|
12
|
+
* @module
|
|
13
|
+
*/
|
|
14
|
+
import { Part, EntityId } from './ecs.js';
|
|
15
|
+
import { Plan } from './plan.js';
|
|
16
|
+
const DEFAULT_RUNTIME_CAPACITY = 128;
|
|
17
|
+
function makeRuntimePlan(name) {
|
|
18
|
+
return Plan.make(name)
|
|
19
|
+
.step('compute-discrete', { type: 'noop' }, { phase: 'compute-discrete' })
|
|
20
|
+
.step('compute-blend', { type: 'noop' }, { phase: 'compute-blend' })
|
|
21
|
+
.step('emit-css', { type: 'noop' }, { phase: 'emit-css' })
|
|
22
|
+
.step('emit-glsl', { type: 'noop' }, { phase: 'emit-glsl' })
|
|
23
|
+
.step('emit-aria', { type: 'noop' }, { phase: 'emit-aria' })
|
|
24
|
+
.seq('step-1', 'step-2')
|
|
25
|
+
.par('step-2', 'step-3')
|
|
26
|
+
.par('step-2', 'step-4')
|
|
27
|
+
.par('step-2', 'step-5')
|
|
28
|
+
.build();
|
|
29
|
+
}
|
|
30
|
+
function orderedPhases(plan) {
|
|
31
|
+
const sorted = Plan.topoSort(plan).sorted;
|
|
32
|
+
const stepsById = new Map(plan.steps.map((step) => [step.id, step]));
|
|
33
|
+
return sorted
|
|
34
|
+
.map((id) => stepsById.get(id)?.metadata?.['phase'])
|
|
35
|
+
.filter((phase) => typeof phase === 'string');
|
|
36
|
+
}
|
|
37
|
+
const RUNTIME_PLAN_TEMPLATE = makeRuntimePlan('czap-runtime');
|
|
38
|
+
const RUNTIME_PHASES = orderedPhases(RUNTIME_PLAN_TEMPLATE);
|
|
39
|
+
/**
|
|
40
|
+
* Build a fresh {@link RuntimeCoordinator} with dense backing stores and the
|
|
41
|
+
* canonical runtime plan. Prefer {@link RuntimeCoordinator.create}, which is
|
|
42
|
+
* the exported entry point.
|
|
43
|
+
*/
|
|
44
|
+
export function createRuntimeCoordinator(config) {
|
|
45
|
+
const name = config?.name ?? 'czap-runtime';
|
|
46
|
+
const plan = name === RUNTIME_PLAN_TEMPLATE.name ? RUNTIME_PLAN_TEMPLATE : { ...RUNTIME_PLAN_TEMPLATE, name };
|
|
47
|
+
const phases = RUNTIME_PHASES;
|
|
48
|
+
const stateIndex = Part.dense('state-index', config?.capacity ?? DEFAULT_RUNTIME_CAPACITY);
|
|
49
|
+
const dirtyEpoch = Part.dense('dirty-epoch', config?.capacity ?? DEFAULT_RUNTIME_CAPACITY);
|
|
50
|
+
const quantizerByName = new Map();
|
|
51
|
+
let nextEntity = 0;
|
|
52
|
+
const ensureQuantizer = (name) => quantizerByName.get(name);
|
|
53
|
+
return {
|
|
54
|
+
plan,
|
|
55
|
+
phases,
|
|
56
|
+
stores: {
|
|
57
|
+
stateIndex,
|
|
58
|
+
dirtyEpoch,
|
|
59
|
+
},
|
|
60
|
+
reset(registrations) {
|
|
61
|
+
quantizerByName.clear();
|
|
62
|
+
nextEntity = 0;
|
|
63
|
+
stateIndex.reset();
|
|
64
|
+
dirtyEpoch.reset();
|
|
65
|
+
for (const registration of registrations ?? []) {
|
|
66
|
+
this.registerQuantizer(registration.name, registration.states);
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
registerQuantizer(name, states) {
|
|
70
|
+
const existing = ensureQuantizer(name);
|
|
71
|
+
if (existing) {
|
|
72
|
+
return existing.entityId;
|
|
73
|
+
}
|
|
74
|
+
const entityId = EntityId(`runtime-${++nextEntity}`);
|
|
75
|
+
const stateLookup = Object.create(null);
|
|
76
|
+
for (let index = 0; index < states.length; index++) {
|
|
77
|
+
stateLookup[states[index]] = index;
|
|
78
|
+
}
|
|
79
|
+
quantizerByName.set(name, {
|
|
80
|
+
entityId,
|
|
81
|
+
stateLookup,
|
|
82
|
+
});
|
|
83
|
+
stateIndex.set(entityId, 0);
|
|
84
|
+
dirtyEpoch.set(entityId, 1);
|
|
85
|
+
return entityId;
|
|
86
|
+
},
|
|
87
|
+
removeQuantizer(name) {
|
|
88
|
+
const quantizer = ensureQuantizer(name);
|
|
89
|
+
if (!quantizer) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
quantizerByName.delete(name);
|
|
93
|
+
stateIndex.delete(quantizer.entityId);
|
|
94
|
+
dirtyEpoch.delete(quantizer.entityId);
|
|
95
|
+
},
|
|
96
|
+
hasQuantizer(name) {
|
|
97
|
+
return quantizerByName.has(name);
|
|
98
|
+
},
|
|
99
|
+
setState(name, state) {
|
|
100
|
+
const quantizer = ensureQuantizer(name);
|
|
101
|
+
if (!quantizer) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
stateIndex.set(quantizer.entityId, quantizer.stateLookup[state] ?? 0);
|
|
105
|
+
},
|
|
106
|
+
applyState(name, state) {
|
|
107
|
+
const quantizer = ensureQuantizer(name);
|
|
108
|
+
if (!quantizer) {
|
|
109
|
+
return 0;
|
|
110
|
+
}
|
|
111
|
+
const nextIndex = quantizer.stateLookup[state] ?? 0;
|
|
112
|
+
stateIndex.set(quantizer.entityId, nextIndex);
|
|
113
|
+
return nextIndex;
|
|
114
|
+
},
|
|
115
|
+
getStateIndex(name) {
|
|
116
|
+
const quantizer = ensureQuantizer(name);
|
|
117
|
+
if (!quantizer) {
|
|
118
|
+
return 0;
|
|
119
|
+
}
|
|
120
|
+
return stateIndex.get(quantizer.entityId);
|
|
121
|
+
},
|
|
122
|
+
markDirty(name) {
|
|
123
|
+
const quantizer = ensureQuantizer(name);
|
|
124
|
+
if (!quantizer) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
dirtyEpoch.set(quantizer.entityId, dirtyEpoch.get(quantizer.entityId) + 1);
|
|
128
|
+
},
|
|
129
|
+
getDirtyEpoch(name) {
|
|
130
|
+
const quantizer = ensureQuantizer(name);
|
|
131
|
+
if (!quantizer) {
|
|
132
|
+
return 0;
|
|
133
|
+
}
|
|
134
|
+
return dirtyEpoch.get(quantizer.entityId);
|
|
135
|
+
},
|
|
136
|
+
registeredNames() {
|
|
137
|
+
return Array.from(quantizerByName.keys());
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Runtime coordinator namespace — single entry point for building the shared
|
|
143
|
+
* {@link Plan} + ECS store bundle consumed by every host adapter.
|
|
144
|
+
*/
|
|
145
|
+
export const RuntimeCoordinator = {
|
|
146
|
+
/** Create a fresh coordinator. See {@link createRuntimeCoordinator}. */
|
|
147
|
+
create: createRuntimeCoordinator,
|
|
148
|
+
};
|
|
149
|
+
//# sourceMappingURL=runtime-coordinator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-coordinator.js","sourceRoot":"","sources":["../src/runtime-coordinator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scheduler -- clock abstraction decoupling animation from requestAnimationFrame.
|
|
3
|
+
*
|
|
4
|
+
* Four implementations:
|
|
5
|
+
* - raf: browser real-time (default)
|
|
6
|
+
* - noop: SSR-safe
|
|
7
|
+
* - fixedStep: deterministic timestamps at target fps (video rendering)
|
|
8
|
+
* - audioSync: ticks in lockstep with an AVBridge sample counter
|
|
9
|
+
*
|
|
10
|
+
* @module
|
|
11
|
+
*/
|
|
12
|
+
import type { AVBridge } from './av-bridge.js';
|
|
13
|
+
interface SchedulerShape {
|
|
14
|
+
readonly _tag: 'FrameScheduler';
|
|
15
|
+
schedule(callback: (now: number) => void): number;
|
|
16
|
+
cancel(id: number): void;
|
|
17
|
+
}
|
|
18
|
+
interface FixedStepShape extends SchedulerShape {
|
|
19
|
+
step(): void;
|
|
20
|
+
readonly frame: number;
|
|
21
|
+
}
|
|
22
|
+
/** Default: requestAnimationFrame. Used by Timeline/animate in browser. */
|
|
23
|
+
declare function _raf(): SchedulerShape;
|
|
24
|
+
/** SSR-safe: noop scheduler for server environments. */
|
|
25
|
+
declare function _noop(): SchedulerShape;
|
|
26
|
+
declare function _fixedStep(fps: number): FixedStepShape;
|
|
27
|
+
interface AudioSyncShape extends SchedulerShape {
|
|
28
|
+
poll(): void;
|
|
29
|
+
readonly frame: number;
|
|
30
|
+
readonly bridge: AVBridge.Shape;
|
|
31
|
+
}
|
|
32
|
+
declare function _audioSync(bridge: AVBridge.Shape): AudioSyncShape;
|
|
33
|
+
/**
|
|
34
|
+
* Scheduler — clock abstraction that decouples animation driver from real time.
|
|
35
|
+
* Pick the impl that matches the runtime: `raf` in browser, `noop` on the
|
|
36
|
+
* server, `fixedStep` for deterministic video render, `audioSync` to drive UI
|
|
37
|
+
* in lockstep with an {@link AVBridge}.
|
|
38
|
+
*/
|
|
39
|
+
export declare const Scheduler: {
|
|
40
|
+
/** `requestAnimationFrame`-backed scheduler for browser real-time work. */
|
|
41
|
+
raf: typeof _raf;
|
|
42
|
+
/** No-op scheduler for SSR / environments without rAF. */
|
|
43
|
+
noop: typeof _noop;
|
|
44
|
+
/** Fixed-step scheduler at the given fps — deterministic timestamps for offline rendering. */
|
|
45
|
+
fixedStep: typeof _fixedStep;
|
|
46
|
+
/** Scheduler that polls an {@link AVBridge} and fires callbacks when the sample frame advances. */
|
|
47
|
+
audioSync: typeof _audioSync;
|
|
48
|
+
};
|
|
49
|
+
export declare namespace Scheduler {
|
|
50
|
+
/** Common structural shape every scheduler variant satisfies. */
|
|
51
|
+
type Shape = SchedulerShape;
|
|
52
|
+
/** Fixed-step scheduler with manual `step()` advancement. */
|
|
53
|
+
type FixedStep = FixedStepShape;
|
|
54
|
+
/** Audio-synchronized scheduler bound to an {@link AVBridge}. */
|
|
55
|
+
type AudioSync = AudioSyncShape;
|
|
56
|
+
}
|
|
57
|
+
export {};
|
|
58
|
+
//# sourceMappingURL=scheduler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../src/scheduler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAM/C,UAAU,cAAc;IACtB,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,CAAC;IAClD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,UAAU,cAAe,SAAQ,cAAc;IAC7C,IAAI,IAAI,IAAI,CAAC;IACb,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAMD,2EAA2E;AAC3E,iBAAS,IAAI,IAAI,cAAc,CAM9B;AAED,wDAAwD;AACxD,iBAAS,KAAK,IAAI,cAAc,CAM/B;AAqCD,iBAAS,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAE/C;AAMD,UAAU,cAAe,SAAQ,cAAc;IAC7C,IAAI,IAAI,IAAI,CAAC;IACb,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC;CACjC;AAED,iBAAS,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,GAAG,cAAc,CAkC1D;AAED;;;;;GAKG;AACH,eAAO,MAAM,SAAS;IACpB,2EAA2E;;IAE3E,0DAA0D;;IAE1D,8FAA8F;;IAE9F,mGAAmG;;CAEpG,CAAC;AAEF,MAAM,CAAC,OAAO,WAAW,SAAS,CAAC;IACjC,iEAAiE;IACjE,KAAY,KAAK,GAAG,cAAc,CAAC;IACnC,6DAA6D;IAC7D,KAAY,SAAS,GAAG,cAAc,CAAC;IACvC,iEAAiE;IACjE,KAAY,SAAS,GAAG,cAAc,CAAC;CACxC"}
|