@playfast/proof 0.0.1

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.
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UnknownSlot = exports.UnknownAction = exports.AssertionFailed = void 0;
4
+ const effect_1 = require("effect");
5
+ /**
6
+ * Tagged errors for the proof harness. A failed assertion or a malformed proof
7
+ * navigation throws one of these — tagged and structured, never a bare `Error` —
8
+ * so a runner can distinguish an assertion failure from a harness misuse.
9
+ */
10
+ /** An `expect(...)` matcher did not hold. */
11
+ class AssertionFailed extends effect_1.Data.TaggedError('reform-proof/AssertionFailed') {
12
+ get message() {
13
+ return `reform-proof: assertion failed — ${this.detail}`;
14
+ }
15
+ }
16
+ exports.AssertionFailed = AssertionFailed;
17
+ /** A proof referenced an action the rendered composition never exposed. */
18
+ class UnknownAction extends effect_1.Data.TaggedError('reform-proof/UnknownAction') {
19
+ get message() {
20
+ return `reform-proof: '${this.composition}' has no action '${this.action}' (rendered ${this.rendered} instance(s))`;
21
+ }
22
+ }
23
+ exports.UnknownAction = UnknownAction;
24
+ /** A proof navigated into a slot the parent composition does not declare. */
25
+ class UnknownSlot extends effect_1.Data.TaggedError('reform-proof/UnknownSlot') {
26
+ get message() {
27
+ return `reform-proof: '${this.parent}' has no slot '${this.slot}'`;
28
+ }
29
+ }
30
+ exports.UnknownSlot = UnknownSlot;
@@ -0,0 +1,324 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Proof = exports.expect = exports.Product = exports.ProductRequirement = void 0;
4
+ const effect_1 = require("effect");
5
+ const Utils_1 = require("effect/Utils");
6
+ const react_1 = require("react");
7
+ const errors_js_1 = require("./errors.js");
8
+ const reform_1 = require("reform");
9
+ /**
10
+ * A named, human-readable behavioural statement bound to the composition it
11
+ * specifies. The composition types the proof facade; the statement's literal
12
+ * type is re-stated (and enforced) at `Proof.implement`.
13
+ */
14
+ const makeRequirement = (composition, statement) => Object.assign(class {
15
+ }, {
16
+ manifest: { kind: 'ProductRequirement', name: statement, statement, composition },
17
+ });
18
+ exports.ProductRequirement = { make: makeRequirement };
19
+ /**
20
+ * Group a composition with the full list of requirements that specify it. The
21
+ * shared `Comp` type-checks that every requirement targets this composition.
22
+ */
23
+ const makeProduct = (composition, config) => Object.assign(class {
24
+ }, {
25
+ manifest: {
26
+ kind: 'Product',
27
+ name: composition.manifest.name,
28
+ composition,
29
+ requirements: config.requirements,
30
+ },
31
+ });
32
+ exports.Product = { make: makeProduct };
33
+ // ---------------------------------------------------------------------------
34
+ // Assertions — Effect-returning matchers; a failed match fails the proof.
35
+ // ---------------------------------------------------------------------------
36
+ const deepEqual = (a, b) => Object.is(a, b) || JSON.stringify(a) === JSON.stringify(b);
37
+ const fail = (message) => effect_1.Effect.sync(() => {
38
+ throw new errors_js_1.AssertionFailed({ detail: message });
39
+ });
40
+ const expect = (actual) => ({
41
+ toBe: (expected) => Object.is(actual, expected)
42
+ ? effect_1.Effect.void
43
+ : fail(`expected ${JSON.stringify(actual)} to be ${JSON.stringify(expected)}`),
44
+ toEqual: (expected) => deepEqual(actual, expected)
45
+ ? effect_1.Effect.void
46
+ : fail(`expected ${JSON.stringify(actual)} to equal ${JSON.stringify(expected)}`),
47
+ toContain: (expected) => Array.isArray(actual) && actual.some((item) => deepEqual(item, expected))
48
+ ? effect_1.Effect.void
49
+ : fail(`expected ${JSON.stringify(actual)} to contain ${JSON.stringify(expected)}`),
50
+ });
51
+ exports.expect = expect;
52
+ // The drain loop, channels, RPC, and reducers run on forked fibers, so a
53
+ // dispatched event takes an unknown number of ticks to flow through. Each poll
54
+ // first drains COOPERATIVELY — a burst of `yieldNow` lets those forked fibers
55
+ // cascade (event → channel → procedure → in-memory RPC → fact → reducer) with no
56
+ // real time — so a synchronous flow reaches its final state within one poll. A
57
+ // real-time `sleep` is still paid each poll to remain the correctness authority
58
+ // for a genuinely time-delayed client (the cooperative drain alone could read a
59
+ // flow waiting on a real timer as falsely "stable" and settle early). The render
60
+ // then re-runs until the captured tree stops changing, bounded so a stuck flow
61
+ // fails fast instead of hanging.
62
+ const SETTLE_DRAIN = 30;
63
+ const SETTLE_STEP = '1 milli';
64
+ const SETTLE_MAX_RENDERS = 100;
65
+ /** Cooperatively run forked engine fibers to a fixpoint without advancing real time. */
66
+ const settleDrain = effect_1.Effect.yieldNow().pipe(effect_1.Effect.repeatN(SETTLE_DRAIN));
67
+ // A keyed view backed by a getter — the only place dynamic keys are needed.
68
+ const keyed = (get) => {
69
+ const target = Object.create(null);
70
+ return new Proxy(target, { get: (_t, key) => get(String(key)) });
71
+ };
72
+ const uiNameOf = (comp) => comp.manifest.ui.manifest.name;
73
+ const makeSink = () => {
74
+ // A const holder whose array we swap on reset (no reassigned binding).
75
+ const state = { captures: [] };
76
+ return {
77
+ api: { record: (capture) => state.captures.push(capture) },
78
+ get captures() {
79
+ return state.captures;
80
+ },
81
+ reset: () => {
82
+ state.captures = [];
83
+ },
84
+ };
85
+ };
86
+ /**
87
+ * Build a proof's runtime layer: the scene's closed wiring with the capture sink
88
+ * merged in, so `Ui`'s `serviceOption(CaptureSink)` finds it and records each
89
+ * render (absent in production, the same layer renders to React). The scene's
90
+ * `provide` is typed to the host-read subset (`MountedServices`); a proof also
91
+ * resolves slot-binding tags (`CompositionClass`), which the same closed layer
92
+ * supplies at runtime — restate that broader `RuntimeServices` surface here. This
93
+ * is the one erasure boundary, the same seam the react host crosses when it reads
94
+ * a slot tag with the requirement erased.
95
+ */
96
+ const proofLayer = (scene, sink) => {
97
+ const sceneLayer = scene.provide.reduce((a, b) => effect_1.Layer.merge(a, b));
98
+ return effect_1.Layer.provideMerge(sceneLayer, effect_1.Layer.succeed(reform_1.CaptureSink, sink.api));
99
+ };
100
+ /**
101
+ * Walk a rendered node tree and invoke any slot components it contains (JSX
102
+ * defers them to the host; headless we drive them ourselves), enqueuing the
103
+ * child each stands for. Slot components are matched by identity, so this never
104
+ * calls — and never needs hooks from — ordinary components.
105
+ */
106
+ const drive = (node, enqueueBy) => {
107
+ if (Array.isArray(node)) {
108
+ for (const child of node)
109
+ drive(child, enqueueBy);
110
+ return;
111
+ }
112
+ if (!(0, react_1.isValidElement)(node))
113
+ return;
114
+ if (node.type instanceof Function) {
115
+ const enqueue = enqueueBy.get(node.type);
116
+ if (enqueue !== undefined) {
117
+ enqueue(node.props);
118
+ return;
119
+ }
120
+ }
121
+ drive(node.props.children, enqueueBy);
122
+ };
123
+ const makeFacade = (runtime, root, sink) => {
124
+ // Slot bindings (`provide(slot, composition)`) are static, so resolve the
125
+ // whole child tree once, up front — keeping `renderTree` and slot navigation
126
+ // synchronous (no nested runtime drive).
127
+ const bindings = new Map();
128
+ // A slot's child is a plain composition or a `FeatureBinding`. A proof drives the
129
+ // composition the feature mounts; for a `default` feature that composition's logic
130
+ // is already live (its eager `.live` was merged into the scene by `provide`), so
131
+ // unwrapping is all that's needed. (Driving a `lazy` feature — load gap +
132
+ // placeholders — is the proof host's Part B increment; until then a scene wires
133
+ // features as `default`, the eagerly-resolvable form.)
134
+ const childComposition = (child) => (0, reform_1.isFeatureBinding)(child) ? child.composition : child;
135
+ const collect = (comp) => effect_1.Effect.gen(function* () {
136
+ for (const slotClass of Object.values(comp.manifest.slots ?? {})) {
137
+ if (bindings.has(slotClass))
138
+ continue;
139
+ const child = childComposition(yield* slotClass.tag);
140
+ bindings.set(slotClass, child);
141
+ yield* collect(child);
142
+ }
143
+ });
144
+ runtime.runSync(collect(root));
145
+ // One breadth-first render of the whole tree. Each view reports its
146
+ // `(props, events)` to the sink; each slot it renders enqueues a child (built
147
+ // on the next level), so a single sweep renders everything.
148
+ const renderLevel = (frontier) => effect_1.Effect.gen(function* () {
149
+ if (frontier.length === 0)
150
+ return;
151
+ const next = [];
152
+ for (const { comp, props } of frontier) {
153
+ const service = yield* comp.tag;
154
+ // A slot renders to a deferred component (JSX `<slots.Item/>`); map each
155
+ // back to the child it stands for so the tree walk can enqueue it.
156
+ const enqueueBy = new Map();
157
+ const slots = {
158
+ slot: (name) => {
159
+ const slotClass = comp.manifest.slots?.[name];
160
+ const child = slotClass && bindings.get(slotClass);
161
+ const component = () => null;
162
+ if (child)
163
+ enqueueBy.set(component, (childProps) => next.push({ comp: child, props: childProps }));
164
+ return component;
165
+ },
166
+ };
167
+ const env = { props, tracker: { add: () => { } }, slots };
168
+ const node = yield* reform_1.Composition.render(service, env);
169
+ drive(node, enqueueBy);
170
+ }
171
+ yield* renderLevel(next);
172
+ });
173
+ const renderTree = effect_1.Effect.gen(function* () {
174
+ sink.reset();
175
+ yield* renderLevel([{ comp: root, props: {} }]);
176
+ });
177
+ const capturesFor = (name) => sink.captures.filter((capture) => capture.name === name);
178
+ // A cheap fingerprint of the rendered tree; when two successive renders match,
179
+ // the engine has stopped producing new state and the read is safe.
180
+ const fingerprint = () => JSON.stringify(sink.captures.map((capture) => [capture.name, capture.props]));
181
+ // Re-render until the tree is stable for two consecutive renders, or give up.
182
+ const settleFrom = (previous, remaining) => effect_1.Effect.gen(function* () {
183
+ if (remaining === 0)
184
+ return;
185
+ yield* settleDrain;
186
+ yield* effect_1.Effect.sleep(SETTLE_STEP);
187
+ yield* renderTree;
188
+ const current = fingerprint();
189
+ if (current === previous)
190
+ return;
191
+ yield* settleFrom(current, remaining - 1);
192
+ });
193
+ const settle = effect_1.Effect.gen(function* () {
194
+ yield* settleDrain;
195
+ yield* renderTree;
196
+ yield* settleFrom(fingerprint(), SETTLE_MAX_RENDERS);
197
+ });
198
+ const triggerOf = (name, index, event) => {
199
+ const trigger = capturesFor(name)[index]?.events[event];
200
+ if (trigger === undefined) {
201
+ throw new errors_js_1.UnknownAction({ composition: name, action: event, rendered: capturesFor(name).length });
202
+ }
203
+ return trigger;
204
+ };
205
+ const nodeFacade = (name, index, comp) => ({
206
+ props: effect_1.Effect.map(renderTree, () => capturesFor(name)[index]?.props),
207
+ // `keyed` resolves event/slot names at runtime; cast the string-keyed proxy
208
+ // to the contract-typed surface. This is the one reflection boundary, the
209
+ // same seam as `definitionClass` — every name the proxy serves is a real
210
+ // contract member, so the cast is sound.
211
+ actions: keyed((event) => (payload) => renderTree.pipe(effect_1.Effect.flatMap(() => effect_1.Effect.sync(() => triggerOf(name, index, event)(payload))), effect_1.Effect.flatMap(() => settle))),
212
+ slots: keyed((slotName) => slotFacade(comp, slotName)),
213
+ frame: settle,
214
+ });
215
+ const slotFacade = (parent, slotName) => {
216
+ const slotClass = parent.manifest.slots?.[slotName];
217
+ const child = slotClass && bindings.get(slotClass);
218
+ if (child === undefined) {
219
+ throw new errors_js_1.UnknownSlot({ parent: uiNameOf(parent), slot: slotName });
220
+ }
221
+ const childName = uiNameOf(child);
222
+ const at = (index) => effect_1.Effect.as(renderTree, nodeFacade(childName, index, child));
223
+ const first = nodeFacade(childName, 0, child);
224
+ return {
225
+ first: at(0),
226
+ at,
227
+ all: effect_1.Effect.map(renderTree, () => capturesFor(childName).map((_capture, index) => nodeFacade(childName, index, child))),
228
+ // Used directly, a slot behaves as its first instance.
229
+ props: first.props,
230
+ actions: first.actions,
231
+ slots: first.slots,
232
+ frame: first.frame,
233
+ };
234
+ };
235
+ return { facade: nodeFacade(uiNameOf(root), 0, root), settle };
236
+ };
237
+ /**
238
+ * Implement (prove) a requirement by driving the facade against a scene. A proof
239
+ * is a VALUE. The scene supplies the runtime (its closed `provide` + `boot`) and
240
+ * the composition that types the facade; its contract must equal the
241
+ * requirement's composition contract, so a scene for the wrong composition — or
242
+ * one whose contract has drifted — is a compile error. The `app` facade is fully
243
+ * typed from that contract.
244
+ */
245
+ const implement = (requirement, scene, body) => ({ requirement, scene, body: body });
246
+ /** Compose proofs with the product whose requirements they prove. */
247
+ const suite = (product, config) => ({ product, proofs: config.proofs });
248
+ /**
249
+ * Run every proof against a fresh runtime, returning per-requirement results.
250
+ * Each proof gets its own environment, so nothing leaks between proofs.
251
+ */
252
+ const run = async (proofSuite) => {
253
+ const results = [];
254
+ for (const proof of proofSuite.proofs) {
255
+ const sink = makeSink();
256
+ const runtime = effect_1.ManagedRuntime.make(proofLayer(proof.scene, sink));
257
+ try {
258
+ const { facade, settle } = makeFacade(runtime, proof.scene.composition, sink);
259
+ // Boot the scene as the host would, then settle before the proof drives.
260
+ await runtime.runPromise(effect_1.Effect.forEach(proof.scene.boot ?? [], (event) => (0, reform_1.publish)('High', event)).pipe(effect_1.Effect.flatMap(() => settle)));
261
+ await runtime.runPromise(effect_1.Effect.gen(() => proof.body(facade)));
262
+ results.push({ requirement: proof.requirement.manifest.statement, ok: true });
263
+ }
264
+ catch (error) {
265
+ results.push({
266
+ requirement: proof.requirement.manifest.statement,
267
+ ok: false,
268
+ error: error instanceof Error ? error.message : String(error),
269
+ });
270
+ }
271
+ finally {
272
+ await runtime.dispose();
273
+ }
274
+ }
275
+ return { product: proofSuite.product.manifest.name, results, ok: results.every((r) => r.ok) };
276
+ };
277
+ /**
278
+ * Drive one proof a step at a time, recording a `StepFrame` after each yielded
279
+ * effect settles. Reuses the same makeFacade runtime/facade/settle as `run`,
280
+ * but instead of handing the body to `Effect.gen` (which runs it to completion),
281
+ * it pumps the generator by hand — `gen.next(value)` yields the next effect, we
282
+ * run it on the live runtime, snapshot the sink, and feed the result back. So the
283
+ * editor gets the per-step timeline with no change to the proof authoring API.
284
+ */
285
+ const driveProof = async (proof) => {
286
+ const sink = makeSink();
287
+ const runtime = effect_1.ManagedRuntime.make(proofLayer(proof.scene, sink));
288
+ const frames = [];
289
+ const statement = proof.requirement.manifest.statement;
290
+ try {
291
+ const { facade, settle } = makeFacade(runtime, proof.scene.composition, sink);
292
+ await runtime.runPromise(effect_1.Effect.forEach(proof.scene.boot ?? [], (event) => (0, reform_1.publish)('High', event)).pipe(effect_1.Effect.flatMap(() => settle)));
293
+ frames.push({ index: 0, captures: [...sink.captures] });
294
+ const generator = proof.body(facade);
295
+ // Pump the generator: run each yielded effect on the runtime, snapshot, recur.
296
+ const pump = async (input, index) => {
297
+ const step = generator.next(input);
298
+ if (step.done === true)
299
+ return;
300
+ const value = await runtime.runPromise((0, Utils_1.yieldWrapGet)(step.value));
301
+ frames.push({ index, captures: [...sink.captures] });
302
+ await pump(value, index + 1);
303
+ };
304
+ await pump(undefined, 1);
305
+ return { requirement: statement, frames, ok: true };
306
+ }
307
+ catch (error) {
308
+ return {
309
+ requirement: statement,
310
+ frames,
311
+ ok: false,
312
+ error: error instanceof Error ? error.message : String(error),
313
+ };
314
+ }
315
+ finally {
316
+ await runtime.dispose();
317
+ }
318
+ };
319
+ /** A driver per proof in the suite — the editor's Test-play entry point. */
320
+ const driver = (proofSuite) => proofSuite.proofs.map((proof) => ({
321
+ requirement: proof.requirement.manifest.statement,
322
+ run: () => driveProof(proof),
323
+ }));
324
+ exports.Proof = { implement, suite, run, driver };
@@ -0,0 +1,4 @@
1
+ {
2
+ "type": "commonjs",
3
+ "sideEffects": []
4
+ }
@@ -0,0 +1,37 @@
1
+ declare const AssertionFailed_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
2
+ readonly _tag: "reform-proof/AssertionFailed";
3
+ } & Readonly<A>;
4
+ /**
5
+ * Tagged errors for the proof harness. A failed assertion or a malformed proof
6
+ * navigation throws one of these — tagged and structured, never a bare `Error` —
7
+ * so a runner can distinguish an assertion failure from a harness misuse.
8
+ */
9
+ /** An `expect(...)` matcher did not hold. */
10
+ export declare class AssertionFailed extends AssertionFailed_base<{
11
+ readonly detail: string;
12
+ }> {
13
+ get message(): string;
14
+ }
15
+ declare const UnknownAction_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
16
+ readonly _tag: "reform-proof/UnknownAction";
17
+ } & Readonly<A>;
18
+ /** A proof referenced an action the rendered composition never exposed. */
19
+ export declare class UnknownAction extends UnknownAction_base<{
20
+ readonly composition: string;
21
+ readonly action: string;
22
+ readonly rendered: number;
23
+ }> {
24
+ get message(): string;
25
+ }
26
+ declare const UnknownSlot_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
27
+ readonly _tag: "reform-proof/UnknownSlot";
28
+ } & Readonly<A>;
29
+ /** A proof navigated into a slot the parent composition does not declare. */
30
+ export declare class UnknownSlot extends UnknownSlot_base<{
31
+ readonly parent: string;
32
+ readonly slot: string;
33
+ }> {
34
+ get message(): string;
35
+ }
36
+ export {};
37
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":";;;AAEA;;;;GAIG;AAEH,6CAA6C;AAC7C,qBAAa,eAAgB,SAAQ,qBAAiD;IACpF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB,CAAC;IACA,IAAa,OAAO,IAAI,MAAM,CAE7B;CACF;;;;AAED,2EAA2E;AAC3E,qBAAa,aAAc,SAAQ,mBAA+C;IAChF,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAC1B,CAAC;IACA,IAAa,OAAO,IAAI,MAAM,CAE7B;CACF;;;;AAED,6EAA6E;AAC7E,qBAAa,WAAY,SAAQ,iBAA6C;IAC5E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB,CAAC;IACA,IAAa,OAAO,IAAI,MAAM,CAE7B;CACF"}
@@ -0,0 +1,139 @@
1
+ import { Effect } from 'effect';
2
+ import { type YieldWrap } from 'effect/Utils';
3
+ import { type CompositionClass, type CompositionService, type Scene, type SlotInstance, type Trigger, type UiCapture, type UiContract } from 'reform';
4
+ /** Any composition, used where the contract type is irrelevant. */
5
+ type AnyComposition = CompositionClass<any, any>;
6
+ export interface RequirementManifest<Comp extends AnyComposition, Statement extends string> {
7
+ readonly kind: 'ProductRequirement';
8
+ readonly name: Statement;
9
+ /** The human-readable behavioural statement; doubles as the manifest name. */
10
+ readonly statement: Statement;
11
+ /** The composition this requirement specifies — its contract types the facade. */
12
+ readonly composition: Comp;
13
+ }
14
+ export interface RequirementClass<Comp extends AnyComposition, Statement extends string> {
15
+ new (): {};
16
+ readonly manifest: RequirementManifest<Comp, Statement>;
17
+ }
18
+ export interface ProductManifest<Comp extends AnyComposition> {
19
+ readonly kind: 'Product';
20
+ readonly name: string;
21
+ readonly composition: Comp;
22
+ readonly requirements: ReadonlyArray<RequirementClass<Comp, string>>;
23
+ }
24
+ export interface ProductClass<Comp extends AnyComposition = AnyComposition> {
25
+ new (): {};
26
+ readonly manifest: ProductManifest<Comp>;
27
+ }
28
+ export declare const ProductRequirement: {
29
+ make: <Comp extends AnyComposition, const Statement extends string>(composition: Comp, statement: Statement) => RequirementClass<Comp, Statement>;
30
+ };
31
+ export declare const Product: {
32
+ make: <Comp extends AnyComposition>(composition: Comp, config: {
33
+ readonly requirements: ReadonlyArray<RequirementClass<Comp, string>>;
34
+ }) => ProductClass<Comp>;
35
+ };
36
+ export declare const expect: <A>(actual: A) => {
37
+ toBe: (expected: A) => Effect.Effect<void>;
38
+ toEqual: (expected: A) => Effect.Effect<void>;
39
+ toContain: (expected: A extends ReadonlyArray<infer E> ? E : unknown) => Effect.Effect<void>;
40
+ };
41
+ /** The event payloads of a contract, keyed by event name. */
42
+ type EventsOf<C extends UiContract> = C extends {
43
+ events: infer E;
44
+ } ? E : Record<never, never>;
45
+ /** The slot instances of a contract, keyed by slot name. */
46
+ type SlotsOf<C extends UiContract> = C extends {
47
+ slots: infer S;
48
+ } ? S : Record<never, never>;
49
+ /** The payload a trigger accepts. */
50
+ type PayloadOf<T> = T extends Trigger<infer P> ? P : never;
51
+ /** The UI contract a composition resolves. */
52
+ export type ContractOf<Comp> = Comp extends CompositionClass<any, infer C> ? C : never;
53
+ /** The child contract a slot stands for — the contract of the composition it holds. */
54
+ type ContractOfSlot<S> = S extends SlotInstance<infer Comp> ? ContractOf<Comp> : never;
55
+ /** The contract's events as facade actions: payload in, dispatch-and-settle Effect out. */
56
+ export type ActionsOf<C extends UiContract> = {
57
+ readonly [K in keyof EventsOf<C>]: (payload: PayloadOf<EventsOf<C>[K]>) => Effect.Effect<void, never, CompositionService>;
58
+ };
59
+ /** The contract's slots as child facades, each typed by the child's own contract. */
60
+ export type SlotFacadesOf<C extends UiContract> = {
61
+ readonly [K in keyof SlotsOf<C>]: SlotFacade<ContractOfSlot<SlotsOf<C>[K]>>;
62
+ };
63
+ /** The Effect a facade action returns: dispatch the event, then settle. */
64
+ export type Action = (payload: unknown) => Effect.Effect<void, never, CompositionService>;
65
+ /**
66
+ * The handle a proof drives — the same surface the production UI receives, fully
67
+ * typed from the composition's contract `C`: read state (`props`), trigger events
68
+ * (`actions`), reach children (`slots`), and wait for the next frame (`frame`).
69
+ * Each access yields a real Effect/SlotFacade against the running engine.
70
+ */
71
+ export interface Facade<C extends UiContract> {
72
+ /** Re-render the tree and read the props this node last computed. */
73
+ readonly props: Effect.Effect<C['props'], never, CompositionService>;
74
+ /** The contract's events as callables; calling one dispatches and settles. */
75
+ readonly actions: ActionsOf<C>;
76
+ /** Child composition facades, keyed by slot name. */
77
+ readonly slots: SlotFacadesOf<C>;
78
+ /** Settle the engine and re-render — wait for the next stable frame. */
79
+ readonly frame: Effect.Effect<void, never, CompositionService>;
80
+ }
81
+ /** A slot may hold many instances (a list); it is also usable as its first one. */
82
+ export interface SlotFacade<C extends UiContract> extends Facade<C> {
83
+ readonly first: Effect.Effect<Facade<C>, never, CompositionService>;
84
+ readonly at: (index: number) => Effect.Effect<Facade<C>, never, CompositionService>;
85
+ readonly all: Effect.Effect<ReadonlyArray<Facade<C>>, never, CompositionService>;
86
+ }
87
+ /** An erased facade — the runtime shape before the contract type is re-attached. */
88
+ type AnyFacade = Facade<UiContract>;
89
+ /** The generator a proof body produces — its yielded effects run on the engine. */
90
+ type ProofGenerator = Generator<YieldWrap<Effect.Effect<unknown, unknown, CompositionService>>, void, unknown>;
91
+ /** The erased body stored on a `Proof` value; `implement` types the contract in. */
92
+ export type ProofBody = (app: AnyFacade) => ProofGenerator;
93
+ export interface Proof {
94
+ readonly requirement: RequirementClass<AnyComposition, string>;
95
+ /** The scene this proof runs against: its closed wiring + boot events. */
96
+ readonly scene: Scene;
97
+ readonly body: ProofBody;
98
+ }
99
+ export interface ProofSuite {
100
+ readonly product: ProductClass;
101
+ readonly proofs: ReadonlyArray<Proof>;
102
+ }
103
+ export interface ProofResult {
104
+ readonly requirement: string;
105
+ readonly ok: boolean;
106
+ readonly error?: string;
107
+ }
108
+ export interface SuiteResult {
109
+ readonly product: string;
110
+ readonly results: ReadonlyArray<ProofResult>;
111
+ readonly ok: boolean;
112
+ }
113
+ /** One step of a driven proof: the rendered tree captured right after the
114
+ * proof's i-th yielded effect settled. Index 0 is the booted, pre-drive tree. */
115
+ export interface StepFrame {
116
+ readonly index: number;
117
+ readonly captures: ReadonlyArray<UiCapture>;
118
+ }
119
+ export interface DriveResult {
120
+ readonly requirement: string;
121
+ readonly frames: ReadonlyArray<StepFrame>;
122
+ readonly ok: boolean;
123
+ readonly error?: string;
124
+ }
125
+ export interface ProofDriver {
126
+ readonly requirement: string;
127
+ /** Run the proof, snapshotting the captured tree after each yielded step. */
128
+ readonly run: () => Promise<DriveResult>;
129
+ }
130
+ export declare const Proof: {
131
+ implement: <Comp extends AnyComposition>(requirement: RequirementClass<Comp, string>, scene: Scene<ContractOf<Comp>>, body: (app: Facade<ContractOf<Comp>>) => ProofGenerator) => Proof;
132
+ suite: (product: ProductClass, config: {
133
+ readonly proofs: ReadonlyArray<Proof>;
134
+ }) => ProofSuite;
135
+ run: (proofSuite: ProofSuite) => Promise<SuiteResult>;
136
+ driver: (proofSuite: ProofSuite) => ReadonlyArray<ProofDriver>;
137
+ };
138
+ export {};
139
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { Data } from 'effect';
2
+ /**
3
+ * Tagged errors for the proof harness. A failed assertion or a malformed proof
4
+ * navigation throws one of these — tagged and structured, never a bare `Error` —
5
+ * so a runner can distinguish an assertion failure from a harness misuse.
6
+ */
7
+ /** An `expect(...)` matcher did not hold. */
8
+ export class AssertionFailed extends Data.TaggedError('reform-proof/AssertionFailed') {
9
+ get message() {
10
+ return `reform-proof: assertion failed — ${this.detail}`;
11
+ }
12
+ }
13
+ /** A proof referenced an action the rendered composition never exposed. */
14
+ export class UnknownAction extends Data.TaggedError('reform-proof/UnknownAction') {
15
+ get message() {
16
+ return `reform-proof: '${this.composition}' has no action '${this.action}' (rendered ${this.rendered} instance(s))`;
17
+ }
18
+ }
19
+ /** A proof navigated into a slot the parent composition does not declare. */
20
+ export class UnknownSlot extends Data.TaggedError('reform-proof/UnknownSlot') {
21
+ get message() {
22
+ return `reform-proof: '${this.parent}' has no slot '${this.slot}'`;
23
+ }
24
+ }
25
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAE7B;;;;GAIG;AAEH,6CAA6C;AAC7C,MAAM,OAAO,eAAgB,SAAQ,IAAI,CAAC,WAAW,CAAC,8BAA8B,CAElF;IACA,IAAa,OAAO;QAClB,OAAO,oCAAoC,IAAI,CAAC,MAAM,EAAE,CAAA;IAC1D,CAAC;CACF;AAED,2EAA2E;AAC3E,MAAM,OAAO,aAAc,SAAQ,IAAI,CAAC,WAAW,CAAC,4BAA4B,CAI9E;IACA,IAAa,OAAO;QAClB,OAAO,kBAAkB,IAAI,CAAC,WAAW,oBAAoB,IAAI,CAAC,MAAM,eAAe,IAAI,CAAC,QAAQ,eAAe,CAAA;IACrH,CAAC;CACF;AAED,6EAA6E;AAC7E,MAAM,OAAO,WAAY,SAAQ,IAAI,CAAC,WAAW,CAAC,0BAA0B,CAG1E;IACA,IAAa,OAAO;QAClB,OAAO,kBAAkB,IAAI,CAAC,MAAM,kBAAkB,IAAI,CAAC,IAAI,GAAG,CAAA;IACpE,CAAC;CACF"}
@@ -0,0 +1,321 @@
1
+ import { Effect, Layer, ManagedRuntime } from 'effect';
2
+ import { yieldWrapGet } from 'effect/Utils';
3
+ import { isValidElement } from 'react';
4
+ import { AssertionFailed, UnknownAction, UnknownSlot } from './errors.js';
5
+ import { Bus, CaptureSink, Composition, isFeatureBinding, publish, } from 'reform';
6
+ /**
7
+ * A named, human-readable behavioural statement bound to the composition it
8
+ * specifies. The composition types the proof facade; the statement's literal
9
+ * type is re-stated (and enforced) at `Proof.implement`.
10
+ */
11
+ const makeRequirement = (composition, statement) => Object.assign(class {
12
+ }, {
13
+ manifest: { kind: 'ProductRequirement', name: statement, statement, composition },
14
+ });
15
+ export const ProductRequirement = { make: makeRequirement };
16
+ /**
17
+ * Group a composition with the full list of requirements that specify it. The
18
+ * shared `Comp` type-checks that every requirement targets this composition.
19
+ */
20
+ const makeProduct = (composition, config) => Object.assign(class {
21
+ }, {
22
+ manifest: {
23
+ kind: 'Product',
24
+ name: composition.manifest.name,
25
+ composition,
26
+ requirements: config.requirements,
27
+ },
28
+ });
29
+ export const Product = { make: makeProduct };
30
+ // ---------------------------------------------------------------------------
31
+ // Assertions — Effect-returning matchers; a failed match fails the proof.
32
+ // ---------------------------------------------------------------------------
33
+ const deepEqual = (a, b) => Object.is(a, b) || JSON.stringify(a) === JSON.stringify(b);
34
+ const fail = (message) => Effect.sync(() => {
35
+ throw new AssertionFailed({ detail: message });
36
+ });
37
+ export const expect = (actual) => ({
38
+ toBe: (expected) => Object.is(actual, expected)
39
+ ? Effect.void
40
+ : fail(`expected ${JSON.stringify(actual)} to be ${JSON.stringify(expected)}`),
41
+ toEqual: (expected) => deepEqual(actual, expected)
42
+ ? Effect.void
43
+ : fail(`expected ${JSON.stringify(actual)} to equal ${JSON.stringify(expected)}`),
44
+ toContain: (expected) => Array.isArray(actual) && actual.some((item) => deepEqual(item, expected))
45
+ ? Effect.void
46
+ : fail(`expected ${JSON.stringify(actual)} to contain ${JSON.stringify(expected)}`),
47
+ });
48
+ // The drain loop, channels, RPC, and reducers run on forked fibers, so a
49
+ // dispatched event takes an unknown number of ticks to flow through. Each poll
50
+ // first drains COOPERATIVELY — a burst of `yieldNow` lets those forked fibers
51
+ // cascade (event → channel → procedure → in-memory RPC → fact → reducer) with no
52
+ // real time — so a synchronous flow reaches its final state within one poll. A
53
+ // real-time `sleep` is still paid each poll to remain the correctness authority
54
+ // for a genuinely time-delayed client (the cooperative drain alone could read a
55
+ // flow waiting on a real timer as falsely "stable" and settle early). The render
56
+ // then re-runs until the captured tree stops changing, bounded so a stuck flow
57
+ // fails fast instead of hanging.
58
+ const SETTLE_DRAIN = 30;
59
+ const SETTLE_STEP = '1 milli';
60
+ const SETTLE_MAX_RENDERS = 100;
61
+ /** Cooperatively run forked engine fibers to a fixpoint without advancing real time. */
62
+ const settleDrain = Effect.yieldNow().pipe(Effect.repeatN(SETTLE_DRAIN));
63
+ // A keyed view backed by a getter — the only place dynamic keys are needed.
64
+ const keyed = (get) => {
65
+ const target = Object.create(null);
66
+ return new Proxy(target, { get: (_t, key) => get(String(key)) });
67
+ };
68
+ const uiNameOf = (comp) => comp.manifest.ui.manifest.name;
69
+ const makeSink = () => {
70
+ // A const holder whose array we swap on reset (no reassigned binding).
71
+ const state = { captures: [] };
72
+ return {
73
+ api: { record: (capture) => state.captures.push(capture) },
74
+ get captures() {
75
+ return state.captures;
76
+ },
77
+ reset: () => {
78
+ state.captures = [];
79
+ },
80
+ };
81
+ };
82
+ /**
83
+ * Build a proof's runtime layer: the scene's closed wiring with the capture sink
84
+ * merged in, so `Ui`'s `serviceOption(CaptureSink)` finds it and records each
85
+ * render (absent in production, the same layer renders to React). The scene's
86
+ * `provide` is typed to the host-read subset (`MountedServices`); a proof also
87
+ * resolves slot-binding tags (`CompositionClass`), which the same closed layer
88
+ * supplies at runtime — restate that broader `RuntimeServices` surface here. This
89
+ * is the one erasure boundary, the same seam the react host crosses when it reads
90
+ * a slot tag with the requirement erased.
91
+ */
92
+ const proofLayer = (scene, sink) => {
93
+ const sceneLayer = scene.provide.reduce((a, b) => Layer.merge(a, b));
94
+ return Layer.provideMerge(sceneLayer, Layer.succeed(CaptureSink, sink.api));
95
+ };
96
+ /**
97
+ * Walk a rendered node tree and invoke any slot components it contains (JSX
98
+ * defers them to the host; headless we drive them ourselves), enqueuing the
99
+ * child each stands for. Slot components are matched by identity, so this never
100
+ * calls — and never needs hooks from — ordinary components.
101
+ */
102
+ const drive = (node, enqueueBy) => {
103
+ if (Array.isArray(node)) {
104
+ for (const child of node)
105
+ drive(child, enqueueBy);
106
+ return;
107
+ }
108
+ if (!isValidElement(node))
109
+ return;
110
+ if (node.type instanceof Function) {
111
+ const enqueue = enqueueBy.get(node.type);
112
+ if (enqueue !== undefined) {
113
+ enqueue(node.props);
114
+ return;
115
+ }
116
+ }
117
+ drive(node.props.children, enqueueBy);
118
+ };
119
+ const makeFacade = (runtime, root, sink) => {
120
+ // Slot bindings (`provide(slot, composition)`) are static, so resolve the
121
+ // whole child tree once, up front — keeping `renderTree` and slot navigation
122
+ // synchronous (no nested runtime drive).
123
+ const bindings = new Map();
124
+ // A slot's child is a plain composition or a `FeatureBinding`. A proof drives the
125
+ // composition the feature mounts; for a `default` feature that composition's logic
126
+ // is already live (its eager `.live` was merged into the scene by `provide`), so
127
+ // unwrapping is all that's needed. (Driving a `lazy` feature — load gap +
128
+ // placeholders — is the proof host's Part B increment; until then a scene wires
129
+ // features as `default`, the eagerly-resolvable form.)
130
+ const childComposition = (child) => isFeatureBinding(child) ? child.composition : child;
131
+ const collect = (comp) => Effect.gen(function* () {
132
+ for (const slotClass of Object.values(comp.manifest.slots ?? {})) {
133
+ if (bindings.has(slotClass))
134
+ continue;
135
+ const child = childComposition(yield* slotClass.tag);
136
+ bindings.set(slotClass, child);
137
+ yield* collect(child);
138
+ }
139
+ });
140
+ runtime.runSync(collect(root));
141
+ // One breadth-first render of the whole tree. Each view reports its
142
+ // `(props, events)` to the sink; each slot it renders enqueues a child (built
143
+ // on the next level), so a single sweep renders everything.
144
+ const renderLevel = (frontier) => Effect.gen(function* () {
145
+ if (frontier.length === 0)
146
+ return;
147
+ const next = [];
148
+ for (const { comp, props } of frontier) {
149
+ const service = yield* comp.tag;
150
+ // A slot renders to a deferred component (JSX `<slots.Item/>`); map each
151
+ // back to the child it stands for so the tree walk can enqueue it.
152
+ const enqueueBy = new Map();
153
+ const slots = {
154
+ slot: (name) => {
155
+ const slotClass = comp.manifest.slots?.[name];
156
+ const child = slotClass && bindings.get(slotClass);
157
+ const component = () => null;
158
+ if (child)
159
+ enqueueBy.set(component, (childProps) => next.push({ comp: child, props: childProps }));
160
+ return component;
161
+ },
162
+ };
163
+ const env = { props, tracker: { add: () => { } }, slots };
164
+ const node = yield* Composition.render(service, env);
165
+ drive(node, enqueueBy);
166
+ }
167
+ yield* renderLevel(next);
168
+ });
169
+ const renderTree = Effect.gen(function* () {
170
+ sink.reset();
171
+ yield* renderLevel([{ comp: root, props: {} }]);
172
+ });
173
+ const capturesFor = (name) => sink.captures.filter((capture) => capture.name === name);
174
+ // A cheap fingerprint of the rendered tree; when two successive renders match,
175
+ // the engine has stopped producing new state and the read is safe.
176
+ const fingerprint = () => JSON.stringify(sink.captures.map((capture) => [capture.name, capture.props]));
177
+ // Re-render until the tree is stable for two consecutive renders, or give up.
178
+ const settleFrom = (previous, remaining) => Effect.gen(function* () {
179
+ if (remaining === 0)
180
+ return;
181
+ yield* settleDrain;
182
+ yield* Effect.sleep(SETTLE_STEP);
183
+ yield* renderTree;
184
+ const current = fingerprint();
185
+ if (current === previous)
186
+ return;
187
+ yield* settleFrom(current, remaining - 1);
188
+ });
189
+ const settle = Effect.gen(function* () {
190
+ yield* settleDrain;
191
+ yield* renderTree;
192
+ yield* settleFrom(fingerprint(), SETTLE_MAX_RENDERS);
193
+ });
194
+ const triggerOf = (name, index, event) => {
195
+ const trigger = capturesFor(name)[index]?.events[event];
196
+ if (trigger === undefined) {
197
+ throw new UnknownAction({ composition: name, action: event, rendered: capturesFor(name).length });
198
+ }
199
+ return trigger;
200
+ };
201
+ const nodeFacade = (name, index, comp) => ({
202
+ props: Effect.map(renderTree, () => capturesFor(name)[index]?.props),
203
+ // `keyed` resolves event/slot names at runtime; cast the string-keyed proxy
204
+ // to the contract-typed surface. This is the one reflection boundary, the
205
+ // same seam as `definitionClass` — every name the proxy serves is a real
206
+ // contract member, so the cast is sound.
207
+ actions: keyed((event) => (payload) => renderTree.pipe(Effect.flatMap(() => Effect.sync(() => triggerOf(name, index, event)(payload))), Effect.flatMap(() => settle))),
208
+ slots: keyed((slotName) => slotFacade(comp, slotName)),
209
+ frame: settle,
210
+ });
211
+ const slotFacade = (parent, slotName) => {
212
+ const slotClass = parent.manifest.slots?.[slotName];
213
+ const child = slotClass && bindings.get(slotClass);
214
+ if (child === undefined) {
215
+ throw new UnknownSlot({ parent: uiNameOf(parent), slot: slotName });
216
+ }
217
+ const childName = uiNameOf(child);
218
+ const at = (index) => Effect.as(renderTree, nodeFacade(childName, index, child));
219
+ const first = nodeFacade(childName, 0, child);
220
+ return {
221
+ first: at(0),
222
+ at,
223
+ all: Effect.map(renderTree, () => capturesFor(childName).map((_capture, index) => nodeFacade(childName, index, child))),
224
+ // Used directly, a slot behaves as its first instance.
225
+ props: first.props,
226
+ actions: first.actions,
227
+ slots: first.slots,
228
+ frame: first.frame,
229
+ };
230
+ };
231
+ return { facade: nodeFacade(uiNameOf(root), 0, root), settle };
232
+ };
233
+ /**
234
+ * Implement (prove) a requirement by driving the facade against a scene. A proof
235
+ * is a VALUE. The scene supplies the runtime (its closed `provide` + `boot`) and
236
+ * the composition that types the facade; its contract must equal the
237
+ * requirement's composition contract, so a scene for the wrong composition — or
238
+ * one whose contract has drifted — is a compile error. The `app` facade is fully
239
+ * typed from that contract.
240
+ */
241
+ const implement = (requirement, scene, body) => ({ requirement, scene, body: body });
242
+ /** Compose proofs with the product whose requirements they prove. */
243
+ const suite = (product, config) => ({ product, proofs: config.proofs });
244
+ /**
245
+ * Run every proof against a fresh runtime, returning per-requirement results.
246
+ * Each proof gets its own environment, so nothing leaks between proofs.
247
+ */
248
+ const run = async (proofSuite) => {
249
+ const results = [];
250
+ for (const proof of proofSuite.proofs) {
251
+ const sink = makeSink();
252
+ const runtime = ManagedRuntime.make(proofLayer(proof.scene, sink));
253
+ try {
254
+ const { facade, settle } = makeFacade(runtime, proof.scene.composition, sink);
255
+ // Boot the scene as the host would, then settle before the proof drives.
256
+ await runtime.runPromise(Effect.forEach(proof.scene.boot ?? [], (event) => publish('High', event)).pipe(Effect.flatMap(() => settle)));
257
+ await runtime.runPromise(Effect.gen(() => proof.body(facade)));
258
+ results.push({ requirement: proof.requirement.manifest.statement, ok: true });
259
+ }
260
+ catch (error) {
261
+ results.push({
262
+ requirement: proof.requirement.manifest.statement,
263
+ ok: false,
264
+ error: error instanceof Error ? error.message : String(error),
265
+ });
266
+ }
267
+ finally {
268
+ await runtime.dispose();
269
+ }
270
+ }
271
+ return { product: proofSuite.product.manifest.name, results, ok: results.every((r) => r.ok) };
272
+ };
273
+ /**
274
+ * Drive one proof a step at a time, recording a `StepFrame` after each yielded
275
+ * effect settles. Reuses the same makeFacade runtime/facade/settle as `run`,
276
+ * but instead of handing the body to `Effect.gen` (which runs it to completion),
277
+ * it pumps the generator by hand — `gen.next(value)` yields the next effect, we
278
+ * run it on the live runtime, snapshot the sink, and feed the result back. So the
279
+ * editor gets the per-step timeline with no change to the proof authoring API.
280
+ */
281
+ const driveProof = async (proof) => {
282
+ const sink = makeSink();
283
+ const runtime = ManagedRuntime.make(proofLayer(proof.scene, sink));
284
+ const frames = [];
285
+ const statement = proof.requirement.manifest.statement;
286
+ try {
287
+ const { facade, settle } = makeFacade(runtime, proof.scene.composition, sink);
288
+ await runtime.runPromise(Effect.forEach(proof.scene.boot ?? [], (event) => publish('High', event)).pipe(Effect.flatMap(() => settle)));
289
+ frames.push({ index: 0, captures: [...sink.captures] });
290
+ const generator = proof.body(facade);
291
+ // Pump the generator: run each yielded effect on the runtime, snapshot, recur.
292
+ const pump = async (input, index) => {
293
+ const step = generator.next(input);
294
+ if (step.done === true)
295
+ return;
296
+ const value = await runtime.runPromise(yieldWrapGet(step.value));
297
+ frames.push({ index, captures: [...sink.captures] });
298
+ await pump(value, index + 1);
299
+ };
300
+ await pump(undefined, 1);
301
+ return { requirement: statement, frames, ok: true };
302
+ }
303
+ catch (error) {
304
+ return {
305
+ requirement: statement,
306
+ frames,
307
+ ok: false,
308
+ error: error instanceof Error ? error.message : String(error),
309
+ };
310
+ }
311
+ finally {
312
+ await runtime.dispose();
313
+ }
314
+ };
315
+ /** A driver per proof in the suite — the editor's Test-play entry point. */
316
+ const driver = (proofSuite) => proofSuite.proofs.map((proof) => ({
317
+ requirement: proof.requirement.manifest.statement,
318
+ run: () => driveProof(proof),
319
+ }));
320
+ export const Proof = { implement, suite, run, driver };
321
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ {
2
+ "type": "module",
3
+ "sideEffects": []
4
+ }
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@playfast/proof",
3
+ "version": "0.0.1",
4
+ "type": "module",
5
+ "sideEffects": [],
6
+ "license": "MIT",
7
+ "module": "./dist/esm/index.js",
8
+ "types": "./dist/dts/index.d.ts",
9
+ "main": "./dist/cjs/index.js",
10
+ "exports": {
11
+ "./package.json": "./package.json",
12
+ ".": {
13
+ "types": "./dist/dts/index.d.ts",
14
+ "import": "./dist/esm/index.js",
15
+ "default": "./dist/cjs/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "peerDependencies": {
25
+ "effect": "*",
26
+ "react": "^19.0.0",
27
+ "@playfast/reform": "^0.0.1"
28
+ }
29
+ }