@playfast/reform-remote 1.0.2 → 1.2.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/README.md +16 -16
- package/dist/client.d.ts +33 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +80 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/memory.d.ts +7 -0
- package/dist/memory.d.ts.map +1 -0
- package/dist/memory.js +21 -0
- package/dist/memory.js.map +1 -0
- package/dist/react.d.ts +15 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +11 -0
- package/dist/react.js.map +1 -0
- package/dist/server.d.ts +16 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +56 -0
- package/dist/server.js.map +1 -0
- package/dist/transport.d.ts +53 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +171 -0
- package/dist/transport.js.map +1 -0
- package/dist/wireNode.d.ts +24 -0
- package/dist/wireNode.d.ts.map +1 -0
- package/dist/wireNode.js +80 -0
- package/dist/wireNode.js.map +1 -0
- package/dist/wireRender.d.ts +20 -0
- package/dist/wireRender.d.ts.map +1 -0
- package/dist/wireRender.js +97 -0
- package/dist/wireRender.js.map +1 -0
- package/package.json +34 -22
- package/src/client-keyed-slot.test.ts +19 -6
- package/src/client-remount.test.ts +14 -5
- package/src/client.ts +74 -41
- package/src/counterFixtures.ts +142 -0
- package/src/fixtures.ts +10 -247
- package/src/listFixtures.ts +174 -0
- package/src/optionalFixtures.ts +64 -0
- package/src/react.ts +1 -6
- package/src/remote-view.typecheck.ts +3 -2
- package/src/server.test.ts +26 -12
- package/src/server.ts +150 -211
- package/src/slottedFixtures.ts +120 -0
- package/src/transport.test.ts +2 -1
- package/src/transport.ts +88 -24
- package/src/wireNode.ts +153 -0
- package/src/wireRender.ts +235 -0
- package/src/connect.ts +0 -44
- package/src/contract.ts +0 -3
- package/src/remote-server.ts +0 -109
- package/src/transport.types.ts +0 -29
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Effect, Option, type ParseResult } from 'effect';
|
|
2
|
+
import { type SlotFill, type Structure, type Trigger, type UiContract } from '@playfast/reform';
|
|
3
|
+
import { type AnyComposition, type AnySlot, type AnySlotChild, type TriggerRegistryApi, type WireNode } from '@playfast/reform/internal';
|
|
4
|
+
export declare const SETTLE_DRAIN = 30;
|
|
5
|
+
export declare const settleDrain: Effect.Effect<void>;
|
|
6
|
+
export declare const eventsOf: (structure: Structure<UiContract>) => Record<string, Trigger<unknown>>;
|
|
7
|
+
export interface Mounted {
|
|
8
|
+
readonly comp: AnyComposition;
|
|
9
|
+
readonly props: unknown;
|
|
10
|
+
readonly id: string;
|
|
11
|
+
readonly parentId: Option.Option<string>;
|
|
12
|
+
readonly slot: Option.Option<string>;
|
|
13
|
+
readonly childIndex: number;
|
|
14
|
+
readonly key: Option.Option<string>;
|
|
15
|
+
}
|
|
16
|
+
export declare const childComposition: (child: AnySlotChild) => AnyComposition;
|
|
17
|
+
export declare const isRecord: (candidate: unknown) => candidate is Record<string, unknown>;
|
|
18
|
+
export declare const handlesOf: (node: WireNode) => ReadonlyArray<string>;
|
|
19
|
+
export declare const noRegister: TriggerRegistryApi['register'];
|
|
20
|
+
export declare const toWireNodeFromStructure: (mounted: Mounted, structure: Structure<UiContract>, register: TriggerRegistryApi['register']) => Effect.Effect<WireNode, ParseResult.ParseError>;
|
|
21
|
+
export declare const isSlotFill: (candidate: unknown) => candidate is SlotFill<unknown>;
|
|
22
|
+
export declare const structureFills: (structure: Structure<UiContract>) => Record<string, SlotFill<unknown>>;
|
|
23
|
+
export declare const slotsOf: (comp: AnyComposition) => Record<string, AnySlot>;
|
|
24
|
+
//# sourceMappingURL=wireNode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wireNode.d.ts","sourceRoot":"","sources":["../src/wireNode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,MAAM,EAAE,MAAM,EAAE,KAAK,WAAW,EAAyB,MAAM,QAAQ,CAAA;AAC9F,OAAO,EAGL,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,OAAO,EACZ,KAAK,UAAU,EAChB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,OAAO,EACZ,KAAK,YAAY,EACjB,KAAK,kBAAkB,EAEvB,KAAK,QAAQ,EAEd,MAAM,2BAA2B,CAAA;AAElC,eAAO,MAAM,YAAY,KAAK,CAAA;AAC9B,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAwD,CAAA;AAGpG,eAAO,MAAM,QAAQ,GAAI,WAAW,SAAS,CAAC,UAAU,CAAC,KAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,CAIvF,CAAA;AAEJ,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAA;IAC7B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;CACpC;AAED,eAAO,MAAM,gBAAgB,GAAI,OAAO,YAAY,KAAG,cAKtD,CAAA;AAED,eAAO,MAAM,QAAQ,GAAI,WAAW,OAAO,KAAG,SAAS,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CACC,CAAA;AAElF,eAAO,MAAM,SAAS,GAAI,MAAM,QAAQ,KAAG,aAAa,CAAC,MAAM,CACa,CAAA;AAG5E,eAAO,MAAM,UAAU,EAAE,kBAAkB,CAAC,UAAU,CAAqB,CAAA;AAE3E,eAAO,MAAM,uBAAuB,EAAE,CACpC,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,SAAS,CAAC,UAAU,CAAC,EAChC,QAAQ,EAAE,kBAAkB,CAAC,UAAU,CAAC,KACrC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,UAAU,CA6DjD,CAAA;AAGF,eAAO,MAAM,UAAU,GAAI,WAAW,OAAO,KAAG,SAAS,IAAI,QAAQ,CAAC,OAAO,CAIW,CAAA;AAExF,eAAO,MAAM,cAAc,GAAI,WAAW,SAAS,CAAC,UAAU,CAAC,KAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,CAM/F,CAAA;AAEH,eAAO,MAAM,OAAO,GAAI,MAAM,cAAc,KAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAejE,CAAA"}
|
package/dist/wireNode.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { Array as Arr, Effect, Option, Record as Rec, Schema } from 'effect';
|
|
2
|
+
import { isFeatureBinding, isSlot, } from '@playfast/reform';
|
|
3
|
+
import {} from '@playfast/reform/internal';
|
|
4
|
+
export const SETTLE_DRAIN = 30;
|
|
5
|
+
export const settleDrain = Effect.yieldNow().pipe(Effect.repeatN(SETTLE_DRAIN));
|
|
6
|
+
// The erased event map's never values remain assignable to Trigger<unknown> without a cast.
|
|
7
|
+
export const eventsOf = (structure) => Option.match(Option.fromNullable(structure.events), {
|
|
8
|
+
onNone: () => ({}),
|
|
9
|
+
onSome: (events) => events,
|
|
10
|
+
});
|
|
11
|
+
export const childComposition = (child) => {
|
|
12
|
+
if (!isFeatureBinding(child)) {
|
|
13
|
+
return child;
|
|
14
|
+
}
|
|
15
|
+
return child.capture((binding) => binding.composition);
|
|
16
|
+
};
|
|
17
|
+
export const isRecord = (candidate) => typeof candidate === 'object' && candidate !== null && !Array.isArray(candidate);
|
|
18
|
+
export const handlesOf = (node) => node.props.flatMap((prop) => (prop._tag === 'Event' ? [prop.handle] : []));
|
|
19
|
+
// One-shot renders still emit deterministic handles but have no client registry.
|
|
20
|
+
export const noRegister = () => Effect.void;
|
|
21
|
+
export const toWireNodeFromStructure = Effect.fn('toWireNodeFromStructure')(function* (mounted, structure, register) {
|
|
22
|
+
const manifest = mounted.comp.manifest.ui.manifest;
|
|
23
|
+
const name = manifest.name;
|
|
24
|
+
// The manifest stores schema AST only; reconstruct an unknown-safe schema at this wire seam.
|
|
25
|
+
const encodedProps = yield* Option.match(Option.fromNullable(manifest.props), {
|
|
26
|
+
onNone: () => Effect.succeed({}),
|
|
27
|
+
onSome: (reflection) => Schema.encodeUnknown(Schema.make(reflection.ast))(structure.props).pipe(Effect.flatMap((encoded) => {
|
|
28
|
+
if (isRecord(encoded)) {
|
|
29
|
+
return Effect.succeed(encoded);
|
|
30
|
+
}
|
|
31
|
+
return Effect.dieMessage(`reform-remote: ${manifest.name} props did not encode to a record`);
|
|
32
|
+
})),
|
|
33
|
+
});
|
|
34
|
+
const dataProps = Rec.toEntries(encodedProps).map(([propName, propValue]) => ({
|
|
35
|
+
_tag: 'Data',
|
|
36
|
+
name: propName,
|
|
37
|
+
value: propValue,
|
|
38
|
+
}));
|
|
39
|
+
const eventSchemas = Option.fromNullable(manifest.events);
|
|
40
|
+
const events = eventsOf(structure);
|
|
41
|
+
const eventProps = yield* Effect.forEach(Rec.toEntries(events), ([eventName, trigger]) => Effect.gen(function* () {
|
|
42
|
+
const schema = Option.flatMap(eventSchemas, (schemas) => Rec.get(schemas, eventName));
|
|
43
|
+
if (Option.isNone(schema)) {
|
|
44
|
+
return Option.none();
|
|
45
|
+
}
|
|
46
|
+
const handle = `${mounted.id}:${eventName}`;
|
|
47
|
+
yield* register(handle, trigger, Schema.make(schema.value.ast));
|
|
48
|
+
return Option.some({
|
|
49
|
+
_tag: 'Event',
|
|
50
|
+
name: eventName,
|
|
51
|
+
handle,
|
|
52
|
+
});
|
|
53
|
+
})).pipe(Effect.map(Arr.getSomes));
|
|
54
|
+
return {
|
|
55
|
+
id: mounted.id,
|
|
56
|
+
name,
|
|
57
|
+
parentId: Option.getOrNull(mounted.parentId),
|
|
58
|
+
childIndex: mounted.childIndex,
|
|
59
|
+
slot: Option.getOrNull(mounted.slot),
|
|
60
|
+
key: Option.getOrNull(mounted.key),
|
|
61
|
+
props: [...dataProps, ...eventProps],
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
// Structure erases per-slot fill types; recover SlotFill structurally without `as`.
|
|
65
|
+
export const isSlotFill = (candidate) => typeof candidate === 'object' &&
|
|
66
|
+
candidate !== null &&
|
|
67
|
+
'_tag' in candidate &&
|
|
68
|
+
(candidate._tag === 'Each' || candidate._tag === 'One' || candidate._tag === 'Absent');
|
|
69
|
+
export const structureFills = (structure) => Rec.fromEntries(Rec.toEntries(structure.slots).flatMap(([slotName, fillValue]) => isSlotFill(fillValue) ? [[slotName, fillValue]] : []));
|
|
70
|
+
export const slotsOf = (comp) => comp.capture((exact) => {
|
|
71
|
+
if (!('slots' in exact.manifest)) {
|
|
72
|
+
return {};
|
|
73
|
+
}
|
|
74
|
+
const candidate = exact.manifest.slots;
|
|
75
|
+
if (!isRecord(candidate)) {
|
|
76
|
+
return {};
|
|
77
|
+
}
|
|
78
|
+
return Rec.fromEntries(Rec.toEntries(candidate).flatMap(([name, slotDefinition]) => isSlot(slotDefinition) ? [[name, slotDefinition]] : []));
|
|
79
|
+
});
|
|
80
|
+
//# sourceMappingURL=wireNode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wireNode.js","sourceRoot":"","sources":["../src/wireNode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,GAAG,EAAE,MAAM,EAAE,MAAM,EAAoB,MAAM,IAAI,GAAG,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC9F,OAAO,EACL,gBAAgB,EAChB,MAAM,GAKP,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAQN,MAAM,2BAA2B,CAAA;AAElC,MAAM,CAAC,MAAM,YAAY,GAAG,EAAE,CAAA;AAC9B,MAAM,CAAC,MAAM,WAAW,GAAwB,MAAM,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAA;AAEpG,4FAA4F;AAC5F,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,SAAgC,EAAoC,EAAE,CAC7F,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE;IAClD,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;IAClB,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM;CAC3B,CAAC,CAAA;AAYJ,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAAmB,EAAkB,EAAE;IACtE,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,KAAK,CAAA;IACd,CAAC;IACD,OAAO,KAAK,CAAC,OAAO,CAAiB,CAAC,OAAO,EAAkB,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;AACxF,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,SAAkB,EAAwC,EAAE,CACnF,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;AAElF,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAc,EAAyB,EAAE,CACjE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;AAE5E,iFAAiF;AACjF,MAAM,CAAC,MAAM,UAAU,GAAmC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAA;AAE3E,MAAM,CAAC,MAAM,uBAAuB,GAImB,MAAM,CAAC,EAAE,CAAC,yBAAyB,CAAC,CACzF,QAAQ,CAAC,EACT,OAAgB,EAChB,SAAgC,EAChC,QAAwC;IAExC,MAAM,QAAQ,GAAe,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAA;IAC9D,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAA;IAE1B,6FAA6F;IAC7F,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;QAC5E,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;QAChC,MAAM,EAAE,CAAC,UAAU,EAAE,EAAE,CACrB,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAmB,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,IAAI,CACvF,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YACzB,IAAI,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;gBACtB,OAAO,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;YAChC,CAAC;YACD,OAAO,MAAM,CAAC,UAAU,CACtB,kBAAkB,QAAQ,CAAC,IAAI,mCAAmC,CACnE,CAAA;QACH,CAAC,CAAC,CACH;KACJ,CAAC,CAAA;IACF,MAAM,SAAS,GAA4B,GAAG,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,GAAG,CACxE,CAAC,CAAC,QAAQ,EAAE,SAAS,CAAC,EAAY,EAAE,CAAC,CAAC;QACpC,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,QAAQ;QACd,KAAK,EAAE,SAAS;KACjB,CAAC,CACH,CAAA;IAED,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;IACzD,MAAM,MAAM,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAA;IAClC,MAAM,UAAU,GAA4B,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAC/D,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,EACrB,CAAC,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE,CACvB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAA;QACrF,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,OAAO,MAAM,CAAC,IAAI,EAAY,CAAA;QAChC,CAAC;QACD,MAAM,MAAM,GAAG,GAAG,OAAO,CAAC,EAAE,IAAI,SAAS,EAAE,CAAA;QAC3C,KAAK,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,CAAmB,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAA;QACjF,OAAO,MAAM,CAAC,IAAI,CAAW;YAC3B,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,SAAS;YACf,MAAM;SACP,CAAC,CAAA;IACJ,CAAC,CAAC,CACL,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAA;IAEhC,OAAO;QACL,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,IAAI;QACJ,QAAQ,EAAE,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC;QAC5C,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,IAAI,EAAE,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC;QACpC,GAAG,EAAE,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC;QAClC,KAAK,EAAE,CAAC,GAAG,SAAS,EAAE,GAAG,UAAU,CAAC;KACrC,CAAA;AACH,CAAC,CAAC,CAAA;AAEF,oFAAoF;AACpF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,SAAkB,EAAkC,EAAE,CAC/E,OAAO,SAAS,KAAK,QAAQ;IAC7B,SAAS,KAAK,IAAI;IAClB,MAAM,IAAI,SAAS;IACnB,CAAC,SAAS,CAAC,IAAI,KAAK,MAAM,IAAI,SAAS,CAAC,IAAI,KAAK,KAAK,IAAI,SAAS,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAA;AAExF,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,SAAgC,EAAqC,EAAE,CACpG,GAAG,CAAC,WAAW,CACb,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CACpC,CAAC,CAAC,QAAQ,EAAE,SAAS,CAAC,EAAuD,EAAE,CAC7E,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CACvD,CACF,CAAA;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,IAAoB,EAA2B,EAAE,CACvE,IAAI,CAAC,OAAO,CAA0B,CAAC,KAAK,EAAE,EAAE;IAC9C,IAAI,CAAC,CAAC,OAAO,IAAI,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;QACjC,OAAO,EAAE,CAAA;IACX,CAAC;IACD,MAAM,SAAS,GAAY,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAA;IAC/C,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,CAAA;IACX,CAAC;IACD,OAAO,GAAG,CAAC,WAAW,CACpB,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,OAAO,CAC9B,CAAC,CAAC,IAAI,EAAE,cAAc,CAAC,EAA6C,EAAE,CACpE,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CACzD,CACF,CAAA;AACH,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Context, Effect, type ParseResult } from 'effect';
|
|
2
|
+
import { type SlotFill, type Structure, type UiContract } from '@playfast/reform';
|
|
3
|
+
import { type AnyComposition, type AnyScene, type AnySlot, type AnySlotChild, type TriggerRegistryApi, type WireNode, type WireTree } from '@playfast/reform/internal';
|
|
4
|
+
import { type Mounted } from './wireNode.js';
|
|
5
|
+
export interface RenderSceneToWireOptions {
|
|
6
|
+
readonly register: TriggerRegistryApi['register'];
|
|
7
|
+
}
|
|
8
|
+
export declare const serviceFromContext: <Services, Identifier, Service>(context: Context.Context<Services>, tag: Context.Tag<Identifier, Service>, missing: string) => Effect.Effect<Service, never, never>;
|
|
9
|
+
export declare const capturedSlotProvider: <Services>(context: Context.Context<Services>, slotDefinition: AnySlot) => Effect.Effect<AnySlotChild, never, never>;
|
|
10
|
+
export declare const renderCapturedComposition: <Services>(context: Context.Context<Services>, composition: AnyComposition, props: unknown) => Effect.Effect<Structure<UiContract>, never, never>;
|
|
11
|
+
export declare const enqueueStructureSlot: (parent: Mounted, slotName: string, child: AnyComposition, fill: SlotFill<unknown>) => ReadonlyArray<Mounted>;
|
|
12
|
+
export type SlotProvider<Services> = (slotDefinition: AnySlot) => Effect.Effect<AnySlotChild, never, Services>;
|
|
13
|
+
export declare const collect: <Services>(root: AnyComposition, provideSlot: SlotProvider<Services>) => Effect.Effect<Map<AnySlot, AnyComposition>, never, Services>;
|
|
14
|
+
export type CompositionRenderer<Services> = (composition: AnyComposition, props: unknown) => Effect.Effect<Structure<UiContract>, never, Services>;
|
|
15
|
+
export interface RenderLevel {
|
|
16
|
+
<Services>(frontier: ReadonlyArray<Mounted>, bindings: ReadonlyMap<AnySlot, AnyComposition>, register: TriggerRegistryApi['register'], render: CompositionRenderer<Services>): Effect.Effect<ReadonlyArray<WireNode>, ParseResult.ParseError, Services>;
|
|
17
|
+
}
|
|
18
|
+
export declare const renderLevel: RenderLevel;
|
|
19
|
+
export declare const renderSceneWith: <SlotServices, CompositionServices>(scene: AnyScene, options: RenderSceneToWireOptions | undefined, provideSlot: SlotProvider<SlotServices>, render: CompositionRenderer<CompositionServices>) => Effect.Effect<WireTree, ParseResult.ParseError, SlotServices | CompositionServices>;
|
|
20
|
+
//# sourceMappingURL=wireRender.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wireRender.d.ts","sourceRoot":"","sources":["../src/wireRender.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { Context, Effect, Match, Option, Record as Rec } from 'effect';
|
|
2
|
+
import { Composition, isStructure, } from '@playfast/reform';
|
|
3
|
+
import {} from '@playfast/reform/internal';
|
|
4
|
+
import { childComposition, noRegister, slotsOf, structureFills, toWireNodeFromStructure, } from './wireNode.js';
|
|
5
|
+
export const serviceFromContext = (context, tag, missing) => Option.match(Context.getOption(context, tag), {
|
|
6
|
+
onNone: () => Effect.dieMessage(missing),
|
|
7
|
+
onSome: Effect.succeed,
|
|
8
|
+
});
|
|
9
|
+
export const capturedSlotProvider = (context, slotDefinition) => slotDefinition.capture((exact) => serviceFromContext(context, exact.provider, 'reform-remote: scene does not provide a declared slot'));
|
|
10
|
+
export const renderCapturedComposition = (context, composition, props) => composition.capture((exact) => Option.match(exact.parseProps(props), {
|
|
11
|
+
onNone: () => Effect.dieMessage(`reform-remote: invalid props for composition ${composition.manifest.name}`),
|
|
12
|
+
onSome: (parsed) => serviceFromContext(context, exact.tag, `reform-remote: scene does not provide composition ${composition.manifest.name}`).pipe(Effect.flatMap((service) => Composition.render(service, {
|
|
13
|
+
props: parsed,
|
|
14
|
+
tracker: { add: () => { } },
|
|
15
|
+
})), Effect.flatMap((frame) => {
|
|
16
|
+
if (isStructure(frame)) {
|
|
17
|
+
return Effect.succeed(frame);
|
|
18
|
+
}
|
|
19
|
+
return Effect.dieMessage(`reform-remote: composition ${composition.manifest.name} did not return a Structure`);
|
|
20
|
+
})),
|
|
21
|
+
}));
|
|
22
|
+
export const enqueueStructureSlot = (parent, slotName, child, fill) => Match.value(fill).pipe(Match.tag('Each', (each) => each.items.map((entry, index) => ({
|
|
23
|
+
comp: child,
|
|
24
|
+
props: entry.props,
|
|
25
|
+
id: `${parent.id}.${slotName}.${index}`,
|
|
26
|
+
parentId: Option.some(parent.id),
|
|
27
|
+
slot: Option.some(slotName),
|
|
28
|
+
childIndex: index,
|
|
29
|
+
key: Option.fromNullable(entry.key),
|
|
30
|
+
}))), Match.tag('One', (single) => [
|
|
31
|
+
{
|
|
32
|
+
comp: child,
|
|
33
|
+
props: single.props,
|
|
34
|
+
id: `${parent.id}.${slotName}.0`,
|
|
35
|
+
parentId: Option.some(parent.id),
|
|
36
|
+
slot: Option.some(slotName),
|
|
37
|
+
childIndex: 0,
|
|
38
|
+
key: Option.none(),
|
|
39
|
+
},
|
|
40
|
+
]), Match.tag('Absent', () => []), Match.exhaustive);
|
|
41
|
+
export const collect = Effect.fn('collect')(function* (root, provideSlot) {
|
|
42
|
+
const bindings = new Map();
|
|
43
|
+
// Explicit type keeps the recursive reference cast-free.
|
|
44
|
+
const walk = Effect.fn('walk')(function* (comp) {
|
|
45
|
+
yield* Effect.forEach(Rec.values(slotsOf(comp)), (slotClass) => Effect.gen(function* () {
|
|
46
|
+
if (bindings.has(slotClass)) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const child = childComposition(yield* provideSlot(slotClass));
|
|
50
|
+
bindings.set(slotClass, child);
|
|
51
|
+
yield* walk(child);
|
|
52
|
+
}));
|
|
53
|
+
});
|
|
54
|
+
yield* walk(root);
|
|
55
|
+
return bindings;
|
|
56
|
+
});
|
|
57
|
+
export const renderLevel = Effect.fn('renderLevel')(function* (frontier, bindings, register, render) {
|
|
58
|
+
if (frontier.length === 0) {
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
const rendered = yield* Effect.forEach(frontier, (mounted) => Effect.gen(function* () {
|
|
62
|
+
const frame = yield* render(mounted.comp, mounted.props);
|
|
63
|
+
const node = yield* toWireNodeFromStructure(mounted, frame, register);
|
|
64
|
+
const fills = structureFills(frame);
|
|
65
|
+
const children = Rec.toEntries(slotsOf(mounted.comp)).flatMap(([slotName, slotClass]) => {
|
|
66
|
+
const child = bindings.get(slotClass);
|
|
67
|
+
if (child === undefined) {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
const fill = fills[slotName];
|
|
71
|
+
if (fill === undefined) {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
return enqueueStructureSlot(mounted, slotName, child, fill);
|
|
75
|
+
});
|
|
76
|
+
return { node, children };
|
|
77
|
+
}));
|
|
78
|
+
const nodes = rendered.map((entry) => entry.node);
|
|
79
|
+
const next = rendered.flatMap((entry) => entry.children);
|
|
80
|
+
const rest = yield* renderLevel(next, bindings, register, render);
|
|
81
|
+
return [...nodes, ...rest];
|
|
82
|
+
});
|
|
83
|
+
export const renderSceneWith = Effect.fn('renderSceneWith')(function* (scene, options, provideSlot, render) {
|
|
84
|
+
const register = options?.register ?? noRegister;
|
|
85
|
+
const bindings = yield* collect(scene.composition, provideSlot);
|
|
86
|
+
const root = {
|
|
87
|
+
comp: scene.composition,
|
|
88
|
+
props: {},
|
|
89
|
+
id: '0',
|
|
90
|
+
parentId: Option.none(),
|
|
91
|
+
slot: Option.none(),
|
|
92
|
+
childIndex: 0,
|
|
93
|
+
key: Option.none(),
|
|
94
|
+
};
|
|
95
|
+
return yield* renderLevel([root], bindings, register, render);
|
|
96
|
+
});
|
|
97
|
+
//# sourceMappingURL=wireRender.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wireRender.js","sourceRoot":"","sources":["../src/wireRender.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,52 +1,64 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@playfast/reform-remote",
|
|
3
|
-
"
|
|
4
|
-
"version": "1.0.2",
|
|
5
|
-
"type": "module",
|
|
3
|
+
"version": "1.2.0",
|
|
6
4
|
"description": "Run a reform scene's logic on the server and stream its rendered UI to a thin client over any duplex transport.",
|
|
7
5
|
"keywords": [
|
|
8
|
-
"reform",
|
|
9
6
|
"effect",
|
|
7
|
+
"react",
|
|
8
|
+
"reform",
|
|
10
9
|
"remote",
|
|
11
10
|
"server-driven-ui",
|
|
12
|
-
"transport"
|
|
13
|
-
"react"
|
|
11
|
+
"transport"
|
|
14
12
|
],
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/playfast/reform/issues"
|
|
15
|
+
},
|
|
15
16
|
"license": "MIT",
|
|
16
17
|
"repository": {
|
|
17
18
|
"type": "git",
|
|
18
19
|
"url": "https://github.com/playfast/reform.git",
|
|
19
20
|
"directory": "packages/reform-remote"
|
|
20
21
|
},
|
|
21
|
-
"bugs": {
|
|
22
|
-
"url": "https://github.com/playfast/reform/issues"
|
|
23
|
-
},
|
|
24
|
-
"sideEffects": false,
|
|
25
|
-
"exports": {
|
|
26
|
-
"./package.json": "./package.json",
|
|
27
|
-
".": "./src/index.ts",
|
|
28
|
-
"./*": "./src/*.ts"
|
|
29
|
-
},
|
|
30
22
|
"files": [
|
|
23
|
+
"dist",
|
|
31
24
|
"src",
|
|
32
25
|
"README.md"
|
|
33
26
|
],
|
|
27
|
+
"type": "module",
|
|
28
|
+
"sideEffects": false,
|
|
29
|
+
"main": "./dist/index.js",
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"exports": {
|
|
32
|
+
"./package.json": "./package.json",
|
|
33
|
+
".": {
|
|
34
|
+
"playfast-src": "./src/index.ts",
|
|
35
|
+
"types": "./dist/index.d.ts",
|
|
36
|
+
"default": "./dist/index.js"
|
|
37
|
+
},
|
|
38
|
+
"./*": {
|
|
39
|
+
"playfast-src": "./src/*.ts",
|
|
40
|
+
"types": "./dist/*.d.ts",
|
|
41
|
+
"default": "./dist/*.js"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public"
|
|
46
|
+
},
|
|
34
47
|
"scripts": {
|
|
35
48
|
"clean": "rm -rf dist .tsbuildinfo",
|
|
36
49
|
"check": "tsc --noEmit",
|
|
37
|
-
"build": "tsc -p tsconfig.build.json",
|
|
50
|
+
"build": "rm -rf dist .tsbuildinfo && tsc -p tsconfig.build.json && bun ../../scripts/fix-esm-extensions.ts dist",
|
|
38
51
|
"test": "vitest run",
|
|
39
52
|
"test:watch": "vitest",
|
|
40
53
|
"coverage": "vitest run --coverage",
|
|
41
54
|
"lint": "oxlint src",
|
|
42
|
-
"lint:fix": "oxlint --fix src"
|
|
55
|
+
"lint:fix": "oxlint --fix src",
|
|
56
|
+
"prepack": "bun run build"
|
|
43
57
|
},
|
|
44
58
|
"peerDependencies": {
|
|
59
|
+
"@playfast/reform": "*",
|
|
45
60
|
"effect": "*",
|
|
46
|
-
"react": "^19.0.0"
|
|
47
|
-
"@playfast/reform": "*"
|
|
61
|
+
"react": "^19.0.0"
|
|
48
62
|
},
|
|
49
|
-
"
|
|
50
|
-
"access": "public"
|
|
51
|
-
}
|
|
63
|
+
"playbook": "./playbook"
|
|
52
64
|
}
|
|
@@ -4,13 +4,18 @@ import { createRoot } from 'react-dom/client'
|
|
|
4
4
|
import { expect, test } from 'vitest'
|
|
5
5
|
import { Schema as S } from 'effect'
|
|
6
6
|
import { Composition, slot, Ui, ui } from '@playfast/reform'
|
|
7
|
-
import type { WireNode } from '@playfast/reform'
|
|
7
|
+
import type { WireNode } from '@playfast/reform/internal'
|
|
8
8
|
import { remoteViews, renderWireTree, type RemoteViews } from './client'
|
|
9
9
|
|
|
10
10
|
class ItemUi extends ui('Item', { props: S.Struct({ label: S.String }) }) {}
|
|
11
|
-
|
|
12
|
-
class
|
|
13
|
-
|
|
11
|
+
|
|
12
|
+
class ItemComp extends Composition.make('Item', { title: 'Item', ui: ItemUi })<ItemComp>() {}
|
|
13
|
+
|
|
14
|
+
class ItemSlot extends slot('Item')<ItemSlot, typeof ItemComp>() {}
|
|
15
|
+
class ListUi extends ui('List', {
|
|
16
|
+
props: S.Struct({ mode: S.String }),
|
|
17
|
+
slots: { Item: ItemSlot },
|
|
18
|
+
}) {}
|
|
14
19
|
|
|
15
20
|
const node = (over: Partial<WireNode> & Pick<WireNode, 'id' | 'name'>): WireNode => ({
|
|
16
21
|
parentId: null,
|
|
@@ -77,8 +82,16 @@ test('a keyed slot renders ONE matching child per call site, not the whole list'
|
|
|
77
82
|
createElement(
|
|
78
83
|
'div',
|
|
79
84
|
null,
|
|
80
|
-
createElement(
|
|
81
|
-
|
|
85
|
+
createElement(
|
|
86
|
+
'section',
|
|
87
|
+
{ 'data-section': 'one' },
|
|
88
|
+
createElement(slots.Item, { slotKey: 'a' }),
|
|
89
|
+
),
|
|
90
|
+
createElement(
|
|
91
|
+
'section',
|
|
92
|
+
{ 'data-section': 'two' },
|
|
93
|
+
createElement(slots.Item, { slotKey: 'b' }),
|
|
94
|
+
),
|
|
82
95
|
),
|
|
83
96
|
)
|
|
84
97
|
const container = await renderWith(ListView, tree)
|
|
@@ -5,16 +5,21 @@ import { createRoot } from 'react-dom/client'
|
|
|
5
5
|
import { expect, test } from 'vitest'
|
|
6
6
|
import { Schema as S } from 'effect'
|
|
7
7
|
import { Composition, slot, Ui, ui } from '@playfast/reform'
|
|
8
|
-
import type { WireNode } from '@playfast/reform'
|
|
8
|
+
import type { WireNode } from '@playfast/reform/internal'
|
|
9
9
|
import type { ServerMessage } from './transport'
|
|
10
10
|
import { connect } from './transport'
|
|
11
11
|
import { inMemoryTransportPair } from './memory'
|
|
12
12
|
import { remoteViews } from './client'
|
|
13
13
|
|
|
14
14
|
class ChildUi extends ui('Child', { props: S.Struct({}) }) {}
|
|
15
|
-
|
|
16
|
-
class
|
|
17
|
-
|
|
15
|
+
|
|
16
|
+
class ChildComp extends Composition.make('Child', { title: 'Child', ui: ChildUi })<ChildComp>() {}
|
|
17
|
+
|
|
18
|
+
class MainSlot extends slot('Main')<MainSlot, typeof ChildComp>() {}
|
|
19
|
+
class HostUi extends ui('Host', {
|
|
20
|
+
props: S.Struct({ count: S.Number }),
|
|
21
|
+
slots: { Main: MainSlot },
|
|
22
|
+
}) {}
|
|
18
23
|
|
|
19
24
|
const node = (over: Partial<WireNode> & Pick<WireNode, 'id' | 'name'>): WireNode => ({
|
|
20
25
|
parentId: null,
|
|
@@ -84,7 +89,11 @@ test('a background patch on the PARENT keeps its slot child mounted (local useSt
|
|
|
84
89
|
patches: [
|
|
85
90
|
{
|
|
86
91
|
_tag: 'Upsert',
|
|
87
|
-
node: node({
|
|
92
|
+
node: node({
|
|
93
|
+
id: '0',
|
|
94
|
+
name: 'Host',
|
|
95
|
+
props: [{ _tag: 'Data', name: 'count', value: 7 }],
|
|
96
|
+
}),
|
|
88
97
|
},
|
|
89
98
|
],
|
|
90
99
|
})
|
package/src/client.ts
CHANGED
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
import { createElement, Fragment, type ReactNode, useRef } from 'react'
|
|
2
|
-
import {
|
|
2
|
+
import { Effect, Record as Rec, Schema } from 'effect'
|
|
3
|
+
import { type MadeView, Ui, type UiContract, UiViewContract, type ViewImpl } from '@playfast/reform'
|
|
3
4
|
import {
|
|
4
|
-
type
|
|
5
|
-
|
|
6
|
-
type
|
|
7
|
-
|
|
5
|
+
type AnyMadeView,
|
|
6
|
+
type AnyUi,
|
|
7
|
+
type UiReflection,
|
|
8
|
+
type WiredUiManifest,
|
|
8
9
|
Wire,
|
|
9
10
|
type WireNode,
|
|
10
11
|
type WireTree,
|
|
11
|
-
} from '@playfast/reform'
|
|
12
|
-
|
|
13
|
-
type AnyValue = Schema.Schema.Type<Schema.Schema.Any>
|
|
14
|
-
|
|
15
|
-
// Variance escape (like Schema<any, any>): heterogeneous contract-typed views can't share one element type.
|
|
16
|
-
type AnyMadeView = MadeView<AnyValue>
|
|
12
|
+
} from '@playfast/reform/internal'
|
|
17
13
|
|
|
18
14
|
export interface SlotPropsExternalApi {
|
|
19
15
|
readonly slotKey?: string
|
|
@@ -28,40 +24,74 @@ export type RemoteView = (
|
|
|
28
24
|
export interface RegisteredRemoteView {
|
|
29
25
|
readonly name: string
|
|
30
26
|
readonly view: RemoteView
|
|
31
|
-
readonly propsSchema: Option.Option<Schema.Schema<Record<string, unknown>, unknown>>
|
|
32
27
|
}
|
|
33
28
|
|
|
34
29
|
type ViewRegistry = Readonly<Record<string, RegisteredRemoteView>>
|
|
35
30
|
|
|
36
|
-
// Phantom brand of C (function never called) so remoteViews can brand cast-free with type-only C.
|
|
37
31
|
const ViewSetContract: unique symbol = Symbol.for('reform-remote/view-set-contract')
|
|
38
32
|
|
|
39
33
|
export type RemoteViewSet<C extends RemoteContract> = ViewRegistry & {
|
|
40
|
-
readonly [ViewSetContract]: (contract: C) =>
|
|
34
|
+
readonly [ViewSetContract]: (contract: C) => C
|
|
41
35
|
}
|
|
42
36
|
|
|
43
|
-
|
|
37
|
+
type RemoteUi = UiReflection<UiContract, string> & AnyUi & { readonly manifest: WiredUiManifest }
|
|
38
|
+
export type RemoteContract = Readonly<Record<string, RemoteUi>>
|
|
44
39
|
|
|
45
|
-
export
|
|
40
|
+
export const remoteContract = <const C extends RemoteContract>(contract: C): C => contract
|
|
46
41
|
|
|
42
|
+
type RemoteViewFor<U extends RemoteUi> =
|
|
43
|
+
U extends UiReflection<infer Contract, infer Name> ? MadeView<Contract, Name, U> : never
|
|
47
44
|
export type RemoteViews<C extends RemoteContract> = {
|
|
48
|
-
readonly [K in keyof C]:
|
|
45
|
+
readonly [K in keyof C]: RemoteViewFor<C[K]>
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
type RemoteSlots = Record<string, (slotProps?: SlotPropsExternalApi) => ReactNode>
|
|
49
|
+
type RemoteEvents = Record<string, (payload: unknown) => void>
|
|
50
|
+
|
|
51
|
+
function bindSlots<C extends Ui.UiContract>(slots: RemoteSlots): Parameters<ViewImpl<C>>[1]
|
|
52
|
+
function bindSlots(slots: RemoteSlots): unknown {
|
|
53
|
+
return slots
|
|
49
54
|
}
|
|
50
55
|
|
|
56
|
+
function bindEvents<C extends Ui.UiContract>(events: RemoteEvents): Parameters<ViewImpl<C>>[2]
|
|
57
|
+
function bindEvents(events: RemoteEvents): unknown {
|
|
58
|
+
return events
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const registerView = (view: AnyMadeView): RegisteredRemoteView =>
|
|
62
|
+
view.capture(
|
|
63
|
+
<C extends Ui.UiContract, N extends string, U extends Ui.AnyUi>(exact: MadeView<C, N, U>) => {
|
|
64
|
+
const contract = exact[UiViewContract]
|
|
65
|
+
const propsReflection = contract.manifest.props
|
|
66
|
+
if (propsReflection === undefined) {
|
|
67
|
+
return Effect.runSync(
|
|
68
|
+
Effect.dieMessage(
|
|
69
|
+
`reform-remote: view ${contract.manifest.name} needs a wire props schema`,
|
|
70
|
+
),
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
const propsSchema = Schema.make<C['props'], unknown>(propsReflection.ast)
|
|
74
|
+
return {
|
|
75
|
+
name: contract.manifest.name,
|
|
76
|
+
view: (encoded, slots, events) =>
|
|
77
|
+
exact(
|
|
78
|
+
Schema.decodeUnknownSync(propsSchema)(encoded),
|
|
79
|
+
bindSlots<C>(slots),
|
|
80
|
+
bindEvents<C>(events),
|
|
81
|
+
),
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
)
|
|
85
|
+
|
|
51
86
|
export const remoteViews = <C extends RemoteContract>(views: RemoteViews<C>): RemoteViewSet<C> => {
|
|
52
87
|
const madeViews: ReadonlyArray<AnyMadeView> = Object.values(views)
|
|
53
88
|
const byName: ViewRegistry = Rec.fromEntries(
|
|
54
89
|
madeViews.map((view): readonly [string, RegisteredRemoteView] => {
|
|
55
|
-
const
|
|
56
|
-
const entry: RegisteredRemoteView = {
|
|
57
|
-
name: viewContract.manifest.name,
|
|
58
|
-
view,
|
|
59
|
-
propsSchema: Option.fromNullable(viewContract.manifest.props),
|
|
60
|
-
}
|
|
90
|
+
const entry = registerView(view)
|
|
61
91
|
return [entry.name, entry]
|
|
62
92
|
}),
|
|
63
93
|
)
|
|
64
|
-
return { ...byName, [ViewSetContract]: (
|
|
94
|
+
return { ...byName, [ViewSetContract]: (contract: C): C => contract }
|
|
65
95
|
}
|
|
66
96
|
|
|
67
97
|
export interface ClientConfig<C extends RemoteContract> {
|
|
@@ -81,10 +111,10 @@ interface WireNodeViewProps {
|
|
|
81
111
|
}
|
|
82
112
|
|
|
83
113
|
const WireNodeView = ({ node, tree, config }: WireNodeViewProps): ReactNode => {
|
|
84
|
-
//
|
|
114
|
+
// Stable slot closures read current inputs through this ref.
|
|
85
115
|
const latest = useRef({ node, tree, config })
|
|
86
116
|
latest.current = { node, tree, config }
|
|
87
|
-
//
|
|
117
|
+
// Fresh slot component types remount descendants and reset their hooks.
|
|
88
118
|
const slotCache = useRef<Record<string, () => ReactNode>>({})
|
|
89
119
|
|
|
90
120
|
const registered = config.views[node.name]
|
|
@@ -93,21 +123,22 @@ const WireNodeView = ({ node, tree, config }: WireNodeViewProps): ReactNode => {
|
|
|
93
123
|
}
|
|
94
124
|
|
|
95
125
|
const encoded: Record<string, unknown> = Rec.fromEntries(
|
|
96
|
-
node.props.flatMap(
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
node.props.flatMap((prop) =>
|
|
100
|
-
prop._tag === 'Event'
|
|
101
|
-
? [[prop.name, (payload: unknown) => config.invoke(prop.handle, payload)] as const]
|
|
102
|
-
: [],
|
|
126
|
+
node.props.flatMap(
|
|
127
|
+
(prop): ReadonlyArray<readonly [string, unknown]> =>
|
|
128
|
+
prop._tag === 'Data' ? [[prop.name, prop.value]] : [],
|
|
103
129
|
),
|
|
104
130
|
)
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
131
|
+
const eventEntries = node.props.flatMap(
|
|
132
|
+
(prop): ReadonlyArray<readonly [string, (payload: unknown) => void]> => {
|
|
133
|
+
if (prop._tag !== 'Event') {
|
|
134
|
+
return []
|
|
135
|
+
}
|
|
136
|
+
return [[prop.name, (payload: unknown) => config.invoke(prop.handle, payload)]]
|
|
137
|
+
},
|
|
138
|
+
)
|
|
139
|
+
const events: Record<string, (payload: unknown) => void> = Rec.fromEntries(eventEntries)
|
|
109
140
|
|
|
110
|
-
// slotKey
|
|
141
|
+
// slotKey selects one wire child; omitting it renders every child in the slot.
|
|
111
142
|
const slotFor = (slotName: string): ((slotProps?: SlotPropsExternalApi) => ReactNode) => {
|
|
112
143
|
const cached = slotCache.current[slotName]
|
|
113
144
|
if (cached !== undefined) {
|
|
@@ -136,13 +167,15 @@ const WireNodeView = ({ node, tree, config }: WireNodeViewProps): ReactNode => {
|
|
|
136
167
|
return stable
|
|
137
168
|
}
|
|
138
169
|
|
|
139
|
-
//
|
|
170
|
+
// Empty slots must still produce a callable component, not an invalid undefined element type.
|
|
140
171
|
const slots: Record<string, (slotProps?: SlotPropsExternalApi) => ReactNode> = new Proxy(
|
|
141
172
|
Object.create(null),
|
|
142
|
-
{
|
|
173
|
+
{
|
|
174
|
+
get: (_target, key) => (typeof key === 'string' ? slotFor(key) : undefined),
|
|
175
|
+
},
|
|
143
176
|
)
|
|
144
177
|
|
|
145
|
-
return registered.view(
|
|
178
|
+
return registered.view(encoded, slots, events)
|
|
146
179
|
}
|
|
147
180
|
|
|
148
181
|
export const renderWireTree = <C extends RemoteContract>(
|