@playfast/reform-remote 1.2.0 → 1.3.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/dist/client.d.ts.map +1 -1
- package/dist/client.js +19 -2
- package/dist/client.js.map +1 -1
- package/dist/clientBinding.d.ts +18 -0
- package/dist/clientBinding.d.ts.map +1 -0
- package/dist/clientBinding.js +70 -0
- package/dist/clientBinding.js.map +1 -0
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +8 -3
- package/dist/react.js.map +1 -1
- package/dist/transport.d.ts +1 -13
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +13 -27
- package/dist/transport.js.map +1 -1
- package/dist/wireRender.d.ts.map +1 -1
- package/dist/wireRender.js +30 -9
- package/dist/wireRender.js.map +1 -1
- package/package.json +1 -1
- package/src/client-prop-decode.test.ts +98 -0
- package/src/client.ts +25 -9
- package/src/clientBinding.ts +103 -0
- package/src/react.ts +14 -3
- package/src/server.test.ts +6 -6
- package/src/transport.ts +15 -47
- package/src/wire-id-uniqueness.test.ts +287 -0
- package/src/wire-identity.test.ts +369 -0
- package/src/wire-keyed-identity.test.ts +434 -0
- package/src/wireRender.ts +47 -33
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,KAAK,SAAS,EAAU,MAAM,OAAO,CAAA;AAEvE,OAAO,EAAE,KAAK,QAAQ,EAAM,KAAK,UAAU,EAAiC,MAAM,kBAAkB,CAAA;AACpG,OAAO,EAEL,KAAK,KAAK,EACV,KAAK,YAAY,EACjB,KAAK,eAAe,EAGpB,KAAK,QAAQ,EACd,MAAM,2BAA2B,CAAA;AAElC,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED,MAAM,MAAM,UAAU,GAAG,CACvB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,EAAE,oBAAoB,KAAK,SAAS,CAAC,EACtE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC,KAC/C,SAAS,CAAA;AAEd,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;CAC1B;AAED,KAAK,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAAA;AAElE,QAAA,MAAM,eAAe,EAAE,OAAO,MAAsD,CAAA;AAEpF,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,cAAc,IAAI,YAAY,GAAG;IACnE,QAAQ,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAA;CAC/C,CAAA;AAED,KAAK,QAAQ,GAAG,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,GAAG,KAAK,GAAG;IAAE,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAA;CAAE,CAAA;AACjG,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAA;AAE/D,eAAO,MAAM,cAAc,GAAI,KAAK,CAAC,CAAC,SAAS,cAAc,EAAE,UAAU,CAAC,KAAG,CAAa,CAAA;AAE1F,KAAK,aAAa,CAAC,CAAC,SAAS,QAAQ,IACnC,CAAC,SAAS,YAAY,CAAC,MAAM,QAAQ,EAAE,MAAM,IAAI,CAAC,GAAG,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,KAAK,CAAA;AAC1F,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,cAAc,IAAI;IAClD,QAAQ,EAAE,CAAC,IAAI,MAAM,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAC7C,CAAA;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,KAAK,SAAS,EAAU,MAAM,OAAO,CAAA;AAEvE,OAAO,EAAE,KAAK,QAAQ,EAAM,KAAK,UAAU,EAAiC,MAAM,kBAAkB,CAAA;AACpG,OAAO,EAEL,KAAK,KAAK,EACV,KAAK,YAAY,EACjB,KAAK,eAAe,EAGpB,KAAK,QAAQ,EACd,MAAM,2BAA2B,CAAA;AAElC,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED,MAAM,MAAM,UAAU,GAAG,CACvB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,EAAE,oBAAoB,KAAK,SAAS,CAAC,EACtE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC,KAC/C,SAAS,CAAA;AAEd,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;CAC1B;AAED,KAAK,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAAA;AAElE,QAAA,MAAM,eAAe,EAAE,OAAO,MAAsD,CAAA;AAEpF,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,cAAc,IAAI,YAAY,GAAG;IACnE,QAAQ,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAA;CAC/C,CAAA;AAED,KAAK,QAAQ,GAAG,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,GAAG,KAAK,GAAG;IAAE,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAA;CAAE,CAAA;AACjG,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAA;AAE/D,eAAO,MAAM,cAAc,GAAI,KAAK,CAAC,CAAC,SAAS,cAAc,EAAE,UAAU,CAAC,KAAG,CAAa,CAAA;AAE1F,KAAK,aAAa,CAAC,CAAC,SAAS,QAAQ,IACnC,CAAC,SAAS,YAAY,CAAC,MAAM,QAAQ,EAAE,MAAM,IAAI,CAAC,GAAG,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,KAAK,CAAA;AAC1F,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,cAAc,IAAI;IAClD,QAAQ,EAAE,CAAC,IAAI,MAAM,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAC7C,CAAA;AAoDD,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,cAAc,EAAE,OAAO,WAAW,CAAC,CAAC,CAAC,KAAG,aAAa,CAAC,CAAC,CAS5F,CAAA;AAED,MAAM,WAAW,YAAY,CAAC,CAAC,SAAS,cAAc;IACpD,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,CAAA;IAChC,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;CAC5D;AAqFD,eAAO,MAAM,cAAc,GAAI,CAAC,SAAS,cAAc,EACrD,MAAM,QAAQ,EACd,QAAQ,YAAY,CAAC,CAAC,CAAC,KACtB,SAOA,CAAA"}
|
package/dist/client.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createElement, Fragment, useRef } from 'react';
|
|
2
|
-
import { Effect, Record as Rec, Schema } from 'effect';
|
|
2
|
+
import { Effect, Option, Record as Rec, Schema } from 'effect';
|
|
3
3
|
import { Ui, UiViewContract } from '@playfast/reform';
|
|
4
4
|
import { Wire, } from '@playfast/reform/internal';
|
|
5
5
|
const ViewSetContract = Symbol.for('reform-remote/view-set-contract');
|
|
@@ -17,9 +17,21 @@ const registerView = (view) => view.capture((exact) => {
|
|
|
17
17
|
return Effect.runSync(Effect.dieMessage(`reform-remote: view ${contract.manifest.name} needs a wire props schema`));
|
|
18
18
|
}
|
|
19
19
|
const propsSchema = Schema.make(propsReflection.ast);
|
|
20
|
+
const decodeProps = Schema.decodeUnknownOption(propsSchema);
|
|
20
21
|
return {
|
|
21
22
|
name: contract.manifest.name,
|
|
22
|
-
|
|
23
|
+
// Props off the wire are untrusted — the envelope types a data prop as
|
|
24
|
+
// `Schema.Unknown`, so version skew against a differently-shaped server first
|
|
25
|
+
// shows up here, inside React's render phase. A throw would take the whole tree
|
|
26
|
+
// down; this node costs itself, which is what an unregistered node name already
|
|
27
|
+
// does one level up.
|
|
28
|
+
view: (encoded, slots, events) => Option.match(decodeProps(encoded), {
|
|
29
|
+
onNone: () => {
|
|
30
|
+
Effect.runSync(Effect.logWarning(`reform-remote: dropped node '${contract.manifest.name}' — props do not match its wire schema`));
|
|
31
|
+
return null;
|
|
32
|
+
},
|
|
33
|
+
onSome: (props) => exact(props, bindSlots(slots), bindEvents(events)),
|
|
34
|
+
}),
|
|
23
35
|
};
|
|
24
36
|
});
|
|
25
37
|
export const remoteViews = (views) => {
|
|
@@ -61,6 +73,11 @@ const WireNodeView = ({ node, tree, config }) => {
|
|
|
61
73
|
.filter((child) => child.slot === slotName)
|
|
62
74
|
.filter((child) => requestedKey === undefined || child.key === requestedKey)
|
|
63
75
|
.map((child) => createElement(WireNodeView, {
|
|
76
|
+
// Reconcile on the semantic key when the server sent one: node ids are
|
|
77
|
+
// positional, so a reorder would otherwise slide item state between rows.
|
|
78
|
+
// Matches the local host, which keys by `placement.key`.
|
|
79
|
+
// The node id, not the app's key: ids are derived from the key and so are
|
|
80
|
+
// stable across a reorder, but unlike a key they are unique by construction.
|
|
64
81
|
key: child.id,
|
|
65
82
|
node: child,
|
|
66
83
|
tree: currentTree,
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAkB,MAAM,EAAE,MAAM,OAAO,CAAA;AACvE,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,GAAG,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { type WireTree } from '@playfast/reform/internal';
|
|
3
|
+
import { type RemoteContract, type RemoteViewSet } from './client.js';
|
|
4
|
+
import type { InvokeMessage, RemoteTransport, ServerMessage } from './transport.js';
|
|
5
|
+
export interface ClientBinding {
|
|
6
|
+
readonly node: () => ReactNode;
|
|
7
|
+
readonly subscribe: (listener: () => void) => () => void;
|
|
8
|
+
readonly snapshot: () => WireTree;
|
|
9
|
+
readonly dispose: () => void;
|
|
10
|
+
readonly close: () => void;
|
|
11
|
+
}
|
|
12
|
+
export interface ConnectOptions<C extends RemoteContract> {
|
|
13
|
+
readonly transport: RemoteTransport<InvokeMessage, ServerMessage>;
|
|
14
|
+
readonly views: RemoteViewSet<C>;
|
|
15
|
+
readonly releaseWindowMs?: number;
|
|
16
|
+
}
|
|
17
|
+
export declare const connect: <C extends RemoteContract>(options: ConnectOptions<C>) => ClientBinding;
|
|
18
|
+
//# sourceMappingURL=clientBinding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clientBinding.d.ts","sourceRoot":"","sources":["../src/clientBinding.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC,OAAO,EAAQ,KAAK,QAAQ,EAAE,MAAM,2BAA2B,CAAA;AAC/D,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EAEnB,MAAM,UAAU,CAAA;AACjB,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEhF,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,SAAS,CAAA;IAC9B,QAAQ,CAAC,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAA;IACxD,QAAQ,CAAC,QAAQ,EAAE,MAAM,QAAQ,CAAA;IAEjC,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAA;IAG5B,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAA;CAC3B;AAED,MAAM,WAAW,cAAc,CAAC,CAAC,SAAS,cAAc;IACtD,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC,aAAa,EAAE,aAAa,CAAC,CAAA;IACjE,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,CAAA;IAGhC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAClC;AAYD,eAAO,MAAM,OAAO,GAAI,CAAC,SAAS,cAAc,EAAE,SAAS,cAAc,CAAC,CAAC,CAAC,KAAG,aA8D9E,CAAA"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Match, MutableRef, Option, Predicate } from 'effect';
|
|
2
|
+
import { Wire } from '@playfast/reform/internal';
|
|
3
|
+
import { renderWireTree, } from './client.js';
|
|
4
|
+
// oxlint-disable-next-line reform-rules/no-magic-numbers -- the window's length is the value being named
|
|
5
|
+
const defaultReleaseWindowMs = 10_000;
|
|
6
|
+
// Browsers hand back a number, which has no `unref`.
|
|
7
|
+
const detachTimer = (handle) => {
|
|
8
|
+
if (Predicate.hasProperty(handle, 'unref') && Predicate.isFunction(handle.unref)) {
|
|
9
|
+
handle.unref();
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
export const connect = (options) => {
|
|
13
|
+
const { transport, views } = options;
|
|
14
|
+
const state = { tree: [] };
|
|
15
|
+
const listeners = new Set();
|
|
16
|
+
const config = {
|
|
17
|
+
views,
|
|
18
|
+
invoke: (handle, payload) => transport.send({ _tag: 'Invoke', handle, payload }),
|
|
19
|
+
};
|
|
20
|
+
const receive = (message) => {
|
|
21
|
+
state.tree = Match.value(message).pipe(Match.tag('Snapshot', ({ tree }) => tree), Match.tag('Patches', ({ patches }) => Wire.apply(state.tree, patches)), Match.exhaustive);
|
|
22
|
+
listeners.forEach((listener) => listener());
|
|
23
|
+
};
|
|
24
|
+
// Subscribed for the binding's whole life, not for the span React happens to be
|
|
25
|
+
// listening. Patches are deltas against the server's own baseline and a delete is
|
|
26
|
+
// never re-sent, so a frame missed while detached is a permanent phantom node —
|
|
27
|
+
// and an effect cleanup is not an unmount (StrictMode, <Suspense>, <Activity> all
|
|
28
|
+
// tear effects down and put them back). `dispose` therefore only goes quiet; the
|
|
29
|
+
// transport subscription is released by `close`, which the connection's owner calls.
|
|
30
|
+
const off = transport.onMessage(receive);
|
|
31
|
+
const pending = MutableRef.make(Option.none());
|
|
32
|
+
const close = () => {
|
|
33
|
+
listeners.clear();
|
|
34
|
+
MutableRef.set(pending, Option.none());
|
|
35
|
+
off();
|
|
36
|
+
};
|
|
37
|
+
// `dispose()` cannot know whether React is unmounting the host or merely hiding it,
|
|
38
|
+
// so it goes quiet and starts a clock. A `subscribe` inside the window is the host
|
|
39
|
+
// coming back and stops it; nothing inside the window means the host is gone, and
|
|
40
|
+
// the transport subscription is released rather than left to accumulate one dead
|
|
41
|
+
// handler per mount/unmount cycle.
|
|
42
|
+
const cancelClose = () => Option.match(MutableRef.get(pending), {
|
|
43
|
+
onNone: () => undefined,
|
|
44
|
+
onSome: (handle) => {
|
|
45
|
+
MutableRef.set(pending, Option.none());
|
|
46
|
+
clearTimeout(handle);
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
return {
|
|
50
|
+
node: () => renderWireTree(state.tree, config),
|
|
51
|
+
subscribe: (listener) => {
|
|
52
|
+
cancelClose();
|
|
53
|
+
listeners.add(listener);
|
|
54
|
+
return () => void listeners.delete(listener);
|
|
55
|
+
},
|
|
56
|
+
snapshot: () => state.tree,
|
|
57
|
+
dispose: () => {
|
|
58
|
+
listeners.clear();
|
|
59
|
+
if (Option.isSome(MutableRef.get(pending))) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
// oxlint-disable-next-line reform-rules/no-set-timeout-interval -- must be unref-able; a binding waiting to be collected must not hold the host process open
|
|
63
|
+
const handle = setTimeout(close, options.releaseWindowMs ?? defaultReleaseWindowMs);
|
|
64
|
+
detachTimer(handle);
|
|
65
|
+
MutableRef.set(pending, Option.some(handle));
|
|
66
|
+
},
|
|
67
|
+
close,
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
//# sourceMappingURL=clientBinding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clientBinding.js","sourceRoot":"","sources":["../src/clientBinding.ts"],"names":[],"mappings":"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"}
|
package/dist/react.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAA2C,MAAM,OAAO,CAAA;AAC/E,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,aAAa,EACnB,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAE7D,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,cAAc,EAClD,WAAW,eAAe,CAAC,aAAa,EAAE,aAAa,CAAC,EACxD,OAAO,aAAa,CAAC,CAAC,CAAC,KACtB,SASF,CAAA;AAED,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,cAAc;IACrD,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC,aAAa,EAAE,aAAa,CAAC,CAAA;IACjE,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,CAAA;CACjC;AAED,eAAO,MAAM,QAAQ,GAAI,CAAC,SAAS,cAAc,EAAE,uBAGhD,aAAa,CAAC,CAAC,CAAC,KAAG,SAA0C,CAAA;AAEhE,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACxB,QAAQ,CAAC,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAA;CAC9D;AAED,eAAO,MAAM,mBAAmB,GAAI,CAAC,EAAE,UAAU,cAAc,CAAC,CAAC,CAAC,KAAG,CACY,CAAA"}
|
package/dist/react.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { Option } from 'effect';
|
|
2
|
+
import { useEffect, useRef, useSyncExternalStore } from 'react';
|
|
3
|
+
import { connect, } from './transport.js';
|
|
3
4
|
export const useRemoteUI = (transport, views) => {
|
|
4
|
-
|
|
5
|
+
// A ref, not `useState`: StrictMode double-invokes a state initializer, and the
|
|
6
|
+
// binding React discards would keep its transport subscription for good.
|
|
7
|
+
const held = useRef(Option.none());
|
|
8
|
+
const binding = Option.getOrElse(held.current, () => connect({ transport, views }));
|
|
9
|
+
held.current = Option.some(binding);
|
|
5
10
|
useEffect(() => () => binding.dispose(), [binding]);
|
|
6
11
|
useSyncExternalStore(binding.subscribe, binding.snapshot, binding.snapshot);
|
|
7
12
|
return binding.node();
|
package/dist/react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.js","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"react.js","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,EAAkB,SAAS,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAA;AAC/E,OAAO,EAEL,OAAO,GAIR,MAAM,aAAa,CAAA;AAGpB,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,SAAwD,EACxD,KAAuB,EACZ,EAAE;IACb,gFAAgF;IAChF,yEAAyE;IACzE,MAAM,IAAI,GAAG,MAAM,CAA+B,MAAM,CAAC,IAAI,EAAE,CAAC,CAAA;IAChE,MAAM,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA;IACnF,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACnC,SAAS,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAA;IACnD,oBAAoB,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;IAC3E,OAAO,OAAO,CAAC,IAAI,EAAE,CAAA;AACvB,CAAC,CAAA;AAOD,MAAM,CAAC,MAAM,QAAQ,GAAG,CAA2B,EACjD,SAAS,EACT,KAAK,GACY,EAAa,EAAE,CAAC,WAAW,CAAC,SAAS,EAAE,KAAK,CAAC,CAAA;AAOhE,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAI,QAA2B,EAAK,EAAE,CACvE,oBAAoB,CAAC,QAAQ,CAAC,cAAc,EAAE,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAA"}
|
package/dist/transport.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import type { ReactNode } from 'react';
|
|
2
1
|
import { type AnyScene, type WirePatch, type WireTree } from '@playfast/reform/internal';
|
|
3
|
-
import { type RemoteContract, type RemoteViewSet } from './client.js';
|
|
4
2
|
export interface SnapshotMessage {
|
|
5
3
|
readonly _tag: 'Snapshot';
|
|
6
4
|
readonly tree: WireTree;
|
|
@@ -39,15 +37,5 @@ export interface ServeSharedOptions {
|
|
|
39
37
|
readonly scene: AnyScene;
|
|
40
38
|
}
|
|
41
39
|
export declare const serveShared: (options: ServeSharedOptions) => SharedServerBinding;
|
|
42
|
-
export
|
|
43
|
-
readonly node: () => ReactNode;
|
|
44
|
-
readonly subscribe: (listener: () => void) => () => void;
|
|
45
|
-
readonly snapshot: () => WireTree;
|
|
46
|
-
readonly dispose: () => void;
|
|
47
|
-
}
|
|
48
|
-
export interface ConnectOptions<C extends RemoteContract> {
|
|
49
|
-
readonly transport: RemoteTransport<InvokeMessage, ServerMessage>;
|
|
50
|
-
readonly views: RemoteViewSet<C>;
|
|
51
|
-
}
|
|
52
|
-
export declare const connect: <C extends RemoteContract>(options: ConnectOptions<C>) => ClientBinding;
|
|
40
|
+
export { type ClientBinding, connect, type ConnectOptions } from './clientBinding.js';
|
|
53
41
|
//# sourceMappingURL=transport.d.ts.map
|
package/dist/transport.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,2BAA2B,CAAA;AAGxF,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;IACzB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;IACxB,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,SAAS,CAAC,CAAA;CAC3C;AAED,MAAM,MAAM,aAAa,GAAG,eAAe,GAAG,cAAc,CAAA;AAE5D,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAC1B;AAED,MAAM,WAAW,eAAe,CAAC,GAAG,EAAE,EAAE;IACtC,QAAQ,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,CAAA;IACrC,QAAQ,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,EAAE,KAAK,IAAI,KAAK,MAAM,IAAI,CAAA;CACnE;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CACtC;AAID,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAA;IACxB,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC,aAAa,EAAE,aAAa,CAAC,CAAA;CAClE;AAED,eAAO,MAAM,KAAK,GAAI,SAAS,YAAY,KAAG,aAqF7C,CAAA;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,IAAI,CAAA;CAC5B;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,SAAS,EAAE,CAClB,SAAS,EAAE,eAAe,CAAC,aAAa,EAAE,aAAa,CAAC,KACrD,kBAAkB,CAAA;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CACtC;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAA;CACzB;AAED,eAAO,MAAM,WAAW,GAAI,SAAS,kBAAkB,KAAG,mBAkHzD,CAAA;AAED,OAAO,EAAE,KAAK,aAAa,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAA"}
|
package/dist/transport.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { Effect, Fiber,
|
|
2
|
-
import {
|
|
1
|
+
import { Effect, Fiber, Option } from 'effect';
|
|
2
|
+
import {} from '@playfast/reform/internal';
|
|
3
3
|
import { makeRemoteServer } from './server.js';
|
|
4
|
-
import { renderWireTree, } from './client.js';
|
|
5
4
|
const BACKGROUND_FLUSH_MS = 16;
|
|
6
5
|
export const serve = (options) => {
|
|
7
6
|
const { scene, transport } = options;
|
|
@@ -52,7 +51,11 @@ export const serve = (options) => {
|
|
|
52
51
|
scheduleFlush();
|
|
53
52
|
};
|
|
54
53
|
const off = transport.onMessage((message) => {
|
|
55
|
-
void Effect.runPromise(Effect.promise(() => server.invoke(message.handle, message.payload)).pipe(Effect.zipRight(Effect.promise(push))
|
|
54
|
+
void Effect.runPromise(Effect.promise(() => server.invoke(message.handle, message.payload)).pipe(Effect.zipRight(Effect.promise(push)),
|
|
55
|
+
// A stale handle (its node was deleted by a patch still in flight) fails by
|
|
56
|
+
// design. Left unhandled that escapes as a rejected promise and, under Node's
|
|
57
|
+
// default --unhandled-rejections=throw, takes the server down for every client.
|
|
58
|
+
Effect.catchAllCause((cause) => Effect.logError(`reform-remote: invoke '${message.handle}' failed`, cause))));
|
|
56
59
|
});
|
|
57
60
|
const offChange = server.subscribe(scheduleFlush);
|
|
58
61
|
return {
|
|
@@ -120,7 +123,11 @@ export const serveShared = (options) => {
|
|
|
120
123
|
const offChange = server.subscribe(scheduleFlush);
|
|
121
124
|
const addClient = (transport) => {
|
|
122
125
|
const off = transport.onMessage((message) => {
|
|
123
|
-
void Effect.runPromise(Effect.promise(() => server.invoke(message.handle, message.payload)).pipe(Effect.zipRight(Effect.promise(push))
|
|
126
|
+
void Effect.runPromise(Effect.promise(() => server.invoke(message.handle, message.payload)).pipe(Effect.zipRight(Effect.promise(push)),
|
|
127
|
+
// A stale handle (its node was deleted by a patch still in flight) fails by
|
|
128
|
+
// design. Left unhandled that escapes as a rejected promise and, under Node's
|
|
129
|
+
// default --unhandled-rejections=throw, takes the server down for every client.
|
|
130
|
+
Effect.catchAllCause((cause) => Effect.logError(`reform-remote: invoke '${message.handle}' failed`, cause))));
|
|
124
131
|
});
|
|
125
132
|
// Snapshot and broadcast membership must change in one tick so no diff interleaves.
|
|
126
133
|
void Effect.runPromise(Effect.promise(() => ready).pipe(Effect.zipRight(Effect.sync(() => {
|
|
@@ -146,26 +153,5 @@ export const serveShared = (options) => {
|
|
|
146
153
|
},
|
|
147
154
|
};
|
|
148
155
|
};
|
|
149
|
-
export
|
|
150
|
-
const { transport, views } = options;
|
|
151
|
-
const state = { tree: [] };
|
|
152
|
-
const listeners = new Set();
|
|
153
|
-
const config = {
|
|
154
|
-
views,
|
|
155
|
-
invoke: (handle, payload) => transport.send({ _tag: 'Invoke', handle, payload }),
|
|
156
|
-
};
|
|
157
|
-
const off = transport.onMessage((message) => {
|
|
158
|
-
state.tree = Match.value(message).pipe(Match.tag('Snapshot', ({ tree }) => tree), Match.tag('Patches', ({ patches }) => Wire.apply(state.tree, patches)), Match.exhaustive);
|
|
159
|
-
listeners.forEach((listener) => listener());
|
|
160
|
-
});
|
|
161
|
-
return {
|
|
162
|
-
node: () => renderWireTree(state.tree, config),
|
|
163
|
-
subscribe: (listener) => {
|
|
164
|
-
listeners.add(listener);
|
|
165
|
-
return () => void listeners.delete(listener);
|
|
166
|
-
},
|
|
167
|
-
snapshot: () => state.tree,
|
|
168
|
-
dispose: off,
|
|
169
|
-
};
|
|
170
|
-
};
|
|
156
|
+
export { connect } from './clientBinding.js';
|
|
171
157
|
//# sourceMappingURL=transport.js.map
|
package/dist/transport.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"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"}
|
package/dist/wireRender.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wireRender.d.ts","sourceRoot":"","sources":["../src/wireRender.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAiB,KAAK,WAAW,EAAiB,MAAM,QAAQ,CAAA;AACxF,OAAO,EAIL,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,UAAU,EAChB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,OAAO,EACZ,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,QAAQ,EACb,KAAK,QAAQ,EACd,MAAM,2BAA2B,CAAA;AAClC,OAAO,EAEL,KAAK,OAAO,EAKb,MAAM,YAAY,CAAA;AAEnB,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC,UAAU,CAAC,CAAA;CAClD;AAED,eAAO,MAAM,kBAAkB,GAAI,QAAQ,EAAE,UAAU,EAAE,OAAO,EAC9D,SAAS,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAClC,KAAK,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,OAAO,CAAC,EACrC,SAAS,MAAM,KACd,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,CAIlC,CAAA;AAEJ,eAAO,MAAM,oBAAoB,GAAI,QAAQ,EAC3C,SAAS,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAClC,gBAAgB,OAAO,KACtB,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,KAAK,EAAE,KAAK,CAOxC,CAAA;AAEH,eAAO,MAAM,yBAAyB,GAAI,QAAQ,EAChD,SAAS,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAClC,aAAa,cAAc,EAC3B,OAAO,OAAO,KACb,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,CAgCjD,CAAA;AAEH,eAAO,MAAM,oBAAoB,GAC/B,QAAQ,OAAO,EACf,UAAU,MAAM,EAChB,OAAO,cAAc,EACrB,MAAM,QAAQ,CAAC,OAAO,CAAC,KACtB,aAAa,CAAC,OAAO,
|
|
1
|
+
{"version":3,"file":"wireRender.d.ts","sourceRoot":"","sources":["../src/wireRender.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAiB,KAAK,WAAW,EAAiB,MAAM,QAAQ,CAAA;AACxF,OAAO,EAIL,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,UAAU,EAChB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,OAAO,EACZ,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,QAAQ,EACb,KAAK,QAAQ,EACd,MAAM,2BAA2B,CAAA;AAClC,OAAO,EAEL,KAAK,OAAO,EAKb,MAAM,YAAY,CAAA;AAEnB,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC,UAAU,CAAC,CAAA;CAClD;AAED,eAAO,MAAM,kBAAkB,GAAI,QAAQ,EAAE,UAAU,EAAE,OAAO,EAC9D,SAAS,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAClC,KAAK,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,OAAO,CAAC,EACrC,SAAS,MAAM,KACd,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,CAIlC,CAAA;AAEJ,eAAO,MAAM,oBAAoB,GAAI,QAAQ,EAC3C,SAAS,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAClC,gBAAgB,OAAO,KACtB,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,KAAK,EAAE,KAAK,CAOxC,CAAA;AAEH,eAAO,MAAM,yBAAyB,GAAI,QAAQ,EAChD,SAAS,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAClC,aAAa,cAAc,EAC3B,OAAO,OAAO,KACb,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,CAgCjD,CAAA;AAEH,eAAO,MAAM,oBAAoB,GAC/B,QAAQ,OAAO,EACf,UAAU,MAAM,EAChB,OAAO,cAAc,EACrB,MAAM,QAAQ,CAAC,OAAO,CAAC,KACtB,aAAa,CAAC,OAAO,CA6CrB,CAAA;AAEH,MAAM,MAAM,YAAY,CAAC,QAAQ,IAAI,CACnC,cAAc,EAAE,OAAO,KACpB,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAA;AAEjD,eAAO,MAAM,OAAO,EAAE,CAAC,QAAQ,EAC7B,IAAI,EAAE,cAAc,EACpB,WAAW,EAAE,YAAY,CAAC,QAAQ,CAAC,KAChC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,cAAc,CAAC,EAAE,KAAK,EAAE,QAAQ,CAwB9D,CAAA;AAEF,MAAM,MAAM,mBAAmB,CAAC,QAAQ,IAAI,CAC1C,WAAW,EAAE,cAAc,EAC3B,KAAK,EAAE,OAAO,KACX,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAA;AAE1D,MAAM,WAAW,WAAW;IAC1B,CAAC,QAAQ,EACP,QAAQ,EAAE,aAAa,CAAC,OAAO,CAAC,EAChC,QAAQ,EAAE,WAAW,CAAC,OAAO,EAAE,cAAc,CAAC,EAC9C,QAAQ,EAAE,kBAAkB,CAAC,UAAU,CAAC,EACxC,MAAM,EAAE,mBAAmB,CAAC,QAAQ,CAAC,GACpC,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,WAAW,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;CAC5E;AAED,eAAO,MAAM,WAAW,EAAE,WAgCxB,CAAA;AAEF,eAAO,MAAM,eAAe,EAAE,CAAC,YAAY,EAAE,mBAAmB,EAC9D,KAAK,EAAE,QAAQ,EACf,OAAO,EAAE,wBAAwB,GAAG,SAAS,EAC7C,WAAW,EAAE,YAAY,CAAC,YAAY,CAAC,EACvC,MAAM,EAAE,mBAAmB,CAAC,mBAAmB,CAAC,KAC7C,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,UAAU,EAAE,YAAY,GAAG,mBAAmB,CAmBnF,CAAA"}
|
package/dist/wireRender.js
CHANGED
|
@@ -19,15 +19,36 @@ export const renderCapturedComposition = (context, composition, props) => compos
|
|
|
19
19
|
return Effect.dieMessage(`reform-remote: composition ${composition.manifest.name} did not return a Structure`);
|
|
20
20
|
})),
|
|
21
21
|
}));
|
|
22
|
-
export const enqueueStructureSlot = (parent, slotName, child, fill) => Match.value(fill).pipe(Match.tag('Each', (each) =>
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
22
|
+
export const enqueueStructureSlot = (parent, slotName, child, fill) => Match.value(fill).pipe(Match.tag('Each', (each) => {
|
|
23
|
+
// Keyed, not positional: a trigger handle embeds the node id, so an id built from
|
|
24
|
+
// the index silently re-points a handle the client already holds at whatever row
|
|
25
|
+
// slid into that slot. An accidental duplicate key falls back to the index rather
|
|
26
|
+
// than minting two nodes with one id.
|
|
27
|
+
const used = new Set();
|
|
28
|
+
// The disambiguator is retried rather than assumed free: a key that literally ends
|
|
29
|
+
// in `#<n>` can already hold the string a later repeat would mint, and two nodes
|
|
30
|
+
// sharing an id costs a whole row on the wire.
|
|
31
|
+
const unusedId = (base) => {
|
|
32
|
+
const attempt = (round) => {
|
|
33
|
+
const candidate = round === 0 ? base : `${base}#${round}`;
|
|
34
|
+
return used.has(candidate) ? attempt(round + 1) : candidate;
|
|
35
|
+
};
|
|
36
|
+
return attempt(0);
|
|
37
|
+
};
|
|
38
|
+
return each.items.map((entry, index) => {
|
|
39
|
+
const id = unusedId(`${parent.id}.${slotName}.${entry.key ?? index}`);
|
|
40
|
+
used.add(id);
|
|
41
|
+
return {
|
|
42
|
+
comp: child,
|
|
43
|
+
props: entry.props,
|
|
44
|
+
id,
|
|
45
|
+
parentId: Option.some(parent.id),
|
|
46
|
+
slot: Option.some(slotName),
|
|
47
|
+
childIndex: index,
|
|
48
|
+
key: Option.fromNullable(entry.key),
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
}), Match.tag('One', (single) => [
|
|
31
52
|
{
|
|
32
53
|
comp: child,
|
|
33
54
|
props: single.props,
|
package/dist/wireRender.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wireRender.js","sourceRoot":"","sources":["../src/wireRender.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAoB,MAAM,IAAI,GAAG,EAAE,MAAM,QAAQ,CAAA;AACxF,OAAO,EACL,WAAW,EAEX,WAAW,GAIZ,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAQN,MAAM,2BAA2B,CAAA;AAClC,OAAO,EACL,gBAAgB,EAEhB,UAAU,EACV,OAAO,EACP,cAAc,EACd,uBAAuB,GACxB,MAAM,YAAY,CAAA;AAMnB,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,OAAkC,EAClC,GAAqC,EACrC,OAAe,EACuB,EAAE,CACxC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE;IAC5C,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC;IACxC,MAAM,EAAE,MAAM,CAAC,OAAO;CACvB,CAAC,CAAA;AAEJ,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,OAAkC,EAClC,cAAuB,EACoB,EAAE,CAC7C,cAAc,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAC/B,kBAAkB,CAChB,OAAO,EACP,KAAK,CAAC,QAAQ,EACd,uDAAuD,CACxD,CACF,CAAA;AAEH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CACvC,OAAkC,EAClC,WAA2B,EAC3B,KAAc,EACsC,EAAE,CACtD,WAAW,CAAC,OAAO,CACjB,CACE,KAA6C,EACO,EAAE,CACtD,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE;IACpC,MAAM,EAAE,GAAG,EAAE,CACX,MAAM,CAAC,UAAU,CACf,gDAAgD,WAAW,CAAC,QAAQ,CAAC,IAAI,EAAE,CAC5E;IACH,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE,CACjB,kBAAkB,CAChB,OAAO,EACP,KAAK,CAAC,GAAG,EACT,qDAAqD,WAAW,CAAC,QAAQ,CAAC,IAAI,EAAE,CACjF,CAAC,IAAI,CACJ,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CACzB,WAAW,CAAC,MAAM,CAAO,OAAO,EAAE;QAChC,KAAK,EAAE,MAAM;QACb,OAAO,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE;KAC3B,CAAC,CACH,EACD,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;QACvB,IAAI,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;QAC9B,CAAC;QACD,OAAO,MAAM,CAAC,UAAU,CACtB,8BAA8B,WAAW,CAAC,QAAQ,CAAC,IAAI,6BAA6B,CACrF,CAAA;IACH,CAAC,CAAC,CACH;CACJ,CAAC,CACL,CAAA;AAEH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,MAAe,EACf,QAAgB,EAChB,KAAqB,EACrB,IAAuB,EACC,EAAE,CAC1B,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CACpB,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,
|
|
1
|
+
{"version":3,"file":"wireRender.js","sourceRoot":"","sources":["../src/wireRender.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { createElement } from 'react'
|
|
2
|
+
import { renderToStaticMarkup } from 'react-dom/server'
|
|
3
|
+
import { expect, test } from 'vitest'
|
|
4
|
+
import { Either, Schema as S } from 'effect'
|
|
5
|
+
import { Ui, ui } from '@playfast/reform'
|
|
6
|
+
import type { WireNode } from '@playfast/reform/internal'
|
|
7
|
+
import { remoteViews, renderWireTree, type RemoteViews } from './client'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Round-4 adversarial audit — the transport-decode fix, sibling half.
|
|
11
|
+
*
|
|
12
|
+
* `reform-remote-web/src/transport.ts` moved `decodeServerMessage` from
|
|
13
|
+
* `Schema.decodeUnknownSync` to `Schema.decodeUnknownOption` so a frame this
|
|
14
|
+
* client cannot parse costs that frame and nothing else. That fix is sound for
|
|
15
|
+
* the *envelope*.
|
|
16
|
+
*
|
|
17
|
+
* It does not reach the second `decodeUnknownSync` on the same path. The frame
|
|
18
|
+
* schema types a data prop as `value: Schema.Unknown` (transport.ts, WirePropSchema),
|
|
19
|
+
* so ANY JSON value passes the envelope decode and is handed to the tree. The
|
|
20
|
+
* per-view props schema is applied later, in `client.ts`:
|
|
21
|
+
*
|
|
22
|
+
* view: (encoded, slots, events) =>
|
|
23
|
+
* exact(Schema.decodeUnknownSync(propsSchema)(encoded), ...)
|
|
24
|
+
*
|
|
25
|
+
* and `registered.view(...)` is the return statement of `WireNodeView`, a React
|
|
26
|
+
* component. A prop the client's schema rejects — version skew against a newer
|
|
27
|
+
* server, a hostile endpoint, a hand-rolled server — therefore throws out of
|
|
28
|
+
* React's render phase, where the blast radius is not one node but every sibling
|
|
29
|
+
* in the tree: with no error boundary React unmounts the whole root.
|
|
30
|
+
*
|
|
31
|
+
* The two halves of the same frame path now answer the same untrusted input in
|
|
32
|
+
* two different ways.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
class AuditItemUi extends ui('audit4.Item', { props: S.Struct({ label: S.String }) }) {}
|
|
36
|
+
|
|
37
|
+
const AuditItemView = Ui.make(AuditItemUi, ({ label }) =>
|
|
38
|
+
createElement('span', { 'data-item': label }, label),
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
const node = (over: Partial<WireNode> & Pick<WireNode, 'id' | 'name'>): WireNode => ({
|
|
42
|
+
parentId: null,
|
|
43
|
+
childIndex: 0,
|
|
44
|
+
slot: null,
|
|
45
|
+
key: null,
|
|
46
|
+
props: [],
|
|
47
|
+
...over,
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
type AuditContract = { Item: typeof AuditItemUi }
|
|
51
|
+
|
|
52
|
+
const views: RemoteViews<AuditContract> = { Item: AuditItemView }
|
|
53
|
+
|
|
54
|
+
const render = (tree: ReadonlyArray<WireNode>): string =>
|
|
55
|
+
renderToStaticMarkup(
|
|
56
|
+
renderWireTree(tree, {
|
|
57
|
+
views: remoteViews<AuditContract>(views),
|
|
58
|
+
invoke: () => undefined,
|
|
59
|
+
}),
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
// The frame the server actually put on the wire. `label` is a string on the
|
|
63
|
+
// server's schema and a number here — the plainest form of version skew, and
|
|
64
|
+
// exactly what `WirePropSchema`'s `value: Schema.Unknown` lets through.
|
|
65
|
+
const wellFormed = node({
|
|
66
|
+
id: 'ok',
|
|
67
|
+
name: 'audit4.Item',
|
|
68
|
+
childIndex: 0,
|
|
69
|
+
props: [{ _tag: 'Data', name: 'label', value: 'still-here' }],
|
|
70
|
+
})
|
|
71
|
+
const skewed = node({
|
|
72
|
+
id: 'skewed',
|
|
73
|
+
name: 'audit4.Item',
|
|
74
|
+
childIndex: 1,
|
|
75
|
+
props: [{ _tag: 'Data', name: 'label', value: 7 }],
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
// The render is what is under test, so its outcome is data, not an exception.
|
|
79
|
+
const attempt = (tree: ReadonlyArray<WireNode>): Either.Either<string, unknown> =>
|
|
80
|
+
Either.try(() => render(tree))
|
|
81
|
+
|
|
82
|
+
test('a wire prop this client cannot decode costs that node, not the whole render', () => {
|
|
83
|
+
// CONTROL — the harness renders, the view is registered, and a well-formed
|
|
84
|
+
// node produces its markup.
|
|
85
|
+
expect(Either.getOrElse(attempt([wellFormed]), () => '')).toContain('still-here')
|
|
86
|
+
|
|
87
|
+
// CONTROL — a node whose NAME this client does not know is already handled the
|
|
88
|
+
// way the fix asks for: `WireNodeView` returns null for it and its siblings
|
|
89
|
+
// render. Rejecting a prop is the same class of skew, one field deeper.
|
|
90
|
+
const unknownView = node({ id: 'unknown', name: 'audit4.NotRegistered', childIndex: 1 })
|
|
91
|
+
expect(Either.getOrElse(attempt([wellFormed, unknownView]), () => '')).toContain('still-here')
|
|
92
|
+
|
|
93
|
+
// THE DEFECT — one node the client's props schema rejects takes the render
|
|
94
|
+
// down with it, so the sibling that decoded fine is never painted either.
|
|
95
|
+
const skewedRender = attempt([wellFormed, skewed])
|
|
96
|
+
expect(Either.isRight(skewedRender)).toBe(true)
|
|
97
|
+
expect(Either.getOrElse(skewedRender, () => '')).toContain('still-here')
|
|
98
|
+
})
|
package/src/client.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createElement, Fragment, type ReactNode, useRef } from 'react'
|
|
2
|
-
import { Effect, Record as Rec, Schema } from 'effect'
|
|
2
|
+
import { Effect, Option, Record as Rec, Schema } from 'effect'
|
|
3
3
|
import { type MadeView, Ui, type UiContract, UiViewContract, type ViewImpl } from '@playfast/reform'
|
|
4
4
|
import {
|
|
5
5
|
type AnyMadeView,
|
|
@@ -71,14 +71,26 @@ const registerView = (view: AnyMadeView): RegisteredRemoteView =>
|
|
|
71
71
|
)
|
|
72
72
|
}
|
|
73
73
|
const propsSchema = Schema.make<C['props'], unknown>(propsReflection.ast)
|
|
74
|
+
const decodeProps = Schema.decodeUnknownOption(propsSchema)
|
|
74
75
|
return {
|
|
75
76
|
name: contract.manifest.name,
|
|
77
|
+
// Props off the wire are untrusted — the envelope types a data prop as
|
|
78
|
+
// `Schema.Unknown`, so version skew against a differently-shaped server first
|
|
79
|
+
// shows up here, inside React's render phase. A throw would take the whole tree
|
|
80
|
+
// down; this node costs itself, which is what an unregistered node name already
|
|
81
|
+
// does one level up.
|
|
76
82
|
view: (encoded, slots, events) =>
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
83
|
+
Option.match(decodeProps(encoded), {
|
|
84
|
+
onNone: () => {
|
|
85
|
+
Effect.runSync(
|
|
86
|
+
Effect.logWarning(
|
|
87
|
+
`reform-remote: dropped node '${contract.manifest.name}' — props do not match its wire schema`,
|
|
88
|
+
),
|
|
89
|
+
)
|
|
90
|
+
return null
|
|
91
|
+
},
|
|
92
|
+
onSome: (props) => exact(props, bindSlots<C>(slots), bindEvents<C>(events)),
|
|
93
|
+
}),
|
|
82
94
|
}
|
|
83
95
|
},
|
|
84
96
|
)
|
|
@@ -123,9 +135,8 @@ const WireNodeView = ({ node, tree, config }: WireNodeViewProps): ReactNode => {
|
|
|
123
135
|
}
|
|
124
136
|
|
|
125
137
|
const encoded: Record<string, unknown> = Rec.fromEntries(
|
|
126
|
-
node.props.flatMap(
|
|
127
|
-
|
|
128
|
-
prop._tag === 'Data' ? [[prop.name, prop.value]] : [],
|
|
138
|
+
node.props.flatMap((prop): ReadonlyArray<readonly [string, unknown]> =>
|
|
139
|
+
prop._tag === 'Data' ? [[prop.name, prop.value]] : [],
|
|
129
140
|
),
|
|
130
141
|
)
|
|
131
142
|
const eventEntries = node.props.flatMap(
|
|
@@ -155,6 +166,11 @@ const WireNodeView = ({ node, tree, config }: WireNodeViewProps): ReactNode => {
|
|
|
155
166
|
.filter((child) => requestedKey === undefined || child.key === requestedKey)
|
|
156
167
|
.map((child) =>
|
|
157
168
|
createElement(WireNodeView, {
|
|
169
|
+
// Reconcile on the semantic key when the server sent one: node ids are
|
|
170
|
+
// positional, so a reorder would otherwise slide item state between rows.
|
|
171
|
+
// Matches the local host, which keys by `placement.key`.
|
|
172
|
+
// The node id, not the app's key: ids are derived from the key and so are
|
|
173
|
+
// stable across a reorder, but unlike a key they are unique by construction.
|
|
158
174
|
key: child.id,
|
|
159
175
|
node: child,
|
|
160
176
|
tree: currentTree,
|