@playfast/reform-remote 0.0.2 → 0.0.3
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/package.json +2 -2
- package/src/client-keyed-slot.test.ts +136 -0
- package/src/client-remount.test.ts +127 -0
- package/src/client.ts +284 -0
- package/src/fixtures.ts +246 -0
- package/src/index.ts +49 -0
- package/src/memory.ts +36 -0
- package/src/react.ts +62 -0
- package/src/remote-view.typecheck.ts +75 -0
- package/src/server.test.ts +309 -0
- package/src/server.ts +333 -0
- package/src/transport.test.ts +205 -0
- package/src/transport.ts +192 -0
- package/dist/client.d.ts +0 -127
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js +0 -127
- package/dist/client.js.map +0 -1
- package/dist/index.d.ts +0 -11
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -20
- package/dist/index.js.map +0 -1
- package/dist/memory.d.ts +0 -15
- package/dist/memory.d.ts.map +0 -1
- package/dist/memory.js +0 -21
- package/dist/memory.js.map +0 -1
- package/dist/react.d.ts +0 -38
- package/dist/react.d.ts.map +0 -1
- package/dist/react.js +0 -29
- package/dist/react.js.map +0 -1
- package/dist/server.d.ts +0 -26
- package/dist/server.d.ts.map +0 -1
- package/dist/server.js +0 -206
- package/dist/server.js.map +0 -1
- package/dist/transport.d.ts +0 -69
- package/dist/transport.d.ts.map +0 -1
- package/dist/transport.js +0 -116
- package/dist/transport.js.map +0 -1
package/dist/index.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export * as Server from './server';
|
|
2
|
-
export * as Client from './client';
|
|
3
|
-
export * as Transport from './transport';
|
|
4
|
-
export * as Memory from './memory';
|
|
5
|
-
export * as React from './react';
|
|
6
|
-
export { makeRemoteServer, type RemoteServer } from './server';
|
|
7
|
-
export { type ClientConfig, type RegisteredRemoteView, type RemoteContract, remoteContract, type RemoteView, type RemoteViews, type RemoteViewSet, remoteViews, renderWireTree, } from './client';
|
|
8
|
-
export { type ClientBinding, connect, type ConnectOptions, type InvokeMessage, type PatchesMessage, type RemoteTransport, serve, type ServeOptions, type ServerBinding, type ServerMessage, type SnapshotMessage, } from './transport';
|
|
9
|
-
export { inMemoryTransportPair, type TransportPair } from './memory';
|
|
10
|
-
export { RemoteUI, type RemoteUIProps, type StatusReporter, useConnectionStatus, useRemoteUI, } from './react';
|
|
11
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,MAAM,MAAM,UAAU,CAAA;AAClC,OAAO,KAAK,MAAM,MAAM,UAAU,CAAA;AAClC,OAAO,KAAK,SAAS,MAAM,aAAa,CAAA;AACxC,OAAO,KAAK,MAAM,MAAM,UAAU,CAAA;AAClC,OAAO,KAAK,KAAK,MAAM,SAAS,CAAA;AAEhC,OAAO,EAAE,gBAAgB,EAAE,KAAK,YAAY,EAAE,MAAM,UAAU,CAAA;AAC9D,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,cAAc,EACd,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,WAAW,EACX,cAAc,GACf,MAAM,UAAU,CAAA;AACjB,OAAO,EACL,KAAK,aAAa,EAClB,OAAO,EACP,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,EACL,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,eAAe,GACrB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,qBAAqB,EAAE,KAAK,aAAa,EAAE,MAAM,UAAU,CAAA;AACpE,OAAO,EACL,QAAQ,EACR,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,mBAAmB,EACnB,WAAW,GACZ,MAAM,SAAS,CAAA"}
|
package/dist/index.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
// @playfast/reform-remote — run a reform scene's logic on the server and stream
|
|
2
|
-
// its rendered UI to a thin client over a transport. A fourth consumer of a
|
|
3
|
-
// `Scene`, alongside @playfast/react, @playfast/react-native, and @playfast/proof.
|
|
4
|
-
// See REMOTE_UI.md.
|
|
5
|
-
//
|
|
6
|
-
// Public API is exposed two ways (Effect-style): namespace barrels for discovery
|
|
7
|
-
// (`import { Transport } from "@playfast/reform-remote"`) and per-path subpaths
|
|
8
|
-
// for direct use (`import { connect } from "@playfast/reform-remote/transport"`).
|
|
9
|
-
// The select re-exports below keep the common entry points nameable from the root.
|
|
10
|
-
export * as Server from './server';
|
|
11
|
-
export * as Client from './client';
|
|
12
|
-
export * as Transport from './transport';
|
|
13
|
-
export * as Memory from './memory';
|
|
14
|
-
export * as React from './react';
|
|
15
|
-
export { makeRemoteServer } from './server';
|
|
16
|
-
export { remoteContract, remoteViews, renderWireTree, } from './client';
|
|
17
|
-
export { connect, serve, } from './transport';
|
|
18
|
-
export { inMemoryTransportPair } from './memory';
|
|
19
|
-
export { RemoteUI, useConnectionStatus, useRemoteUI, } from './react';
|
|
20
|
-
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,4EAA4E;AAC5E,mFAAmF;AACnF,oBAAoB;AACpB,EAAE;AACF,iFAAiF;AACjF,gFAAgF;AAChF,kFAAkF;AAClF,mFAAmF;AAEnF,OAAO,KAAK,MAAM,MAAM,UAAU,CAAA;AAClC,OAAO,KAAK,MAAM,MAAM,UAAU,CAAA;AAClC,OAAO,KAAK,SAAS,MAAM,aAAa,CAAA;AACxC,OAAO,KAAK,MAAM,MAAM,UAAU,CAAA;AAClC,OAAO,KAAK,KAAK,MAAM,SAAS,CAAA;AAEhC,OAAO,EAAE,gBAAgB,EAAqB,MAAM,UAAU,CAAA;AAC9D,OAAO,EAIL,cAAc,EAId,WAAW,EACX,cAAc,GACf,MAAM,UAAU,CAAA;AACjB,OAAO,EAEL,OAAO,EAKP,KAAK,GAKN,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,qBAAqB,EAAsB,MAAM,UAAU,CAAA;AACpE,OAAO,EACL,QAAQ,EAGR,mBAAmB,EACnB,WAAW,GACZ,MAAM,SAAS,CAAA"}
|
package/dist/memory.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { RemoteTransport } from './transport';
|
|
2
|
-
/**
|
|
3
|
-
* The in-memory transport adapter: a duplex pair where what one end sends, the
|
|
4
|
-
* other receives — synchronously, in process. It is the simplest concrete
|
|
5
|
-
* `RemoteTransport`, and the one the test suite drives `serve`/`connect` over
|
|
6
|
-
* without a socket. A WebSocket adapter is the same shape with JSON framing
|
|
7
|
-
* across a wire; proving the loop here proves it everywhere.
|
|
8
|
-
*/
|
|
9
|
-
/** A linked `server`/`client` transport: each receives exactly what the other sends. */
|
|
10
|
-
export interface TransportPair<Server, Client> {
|
|
11
|
-
readonly server: RemoteTransport<Server, Client>;
|
|
12
|
-
readonly client: RemoteTransport<Client, Server>;
|
|
13
|
-
}
|
|
14
|
-
export declare const inMemoryTransportPair: <Server, Client>() => TransportPair<Server, Client>;
|
|
15
|
-
//# sourceMappingURL=memory.d.ts.map
|
package/dist/memory.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAElD;;;;;;GAMG;AAEH,wFAAwF;AACxF,MAAM,WAAW,aAAa,CAAC,MAAM,EAAE,MAAM;IAC3C,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChD,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACjD;AAED,eAAO,MAAM,qBAAqB,GAAI,MAAM,EAAE,MAAM,OAAK,aAAa,CAAC,MAAM,EAAE,MAAM,CAmBpF,CAAA"}
|
package/dist/memory.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
export const inMemoryTransportPair = () => {
|
|
2
|
-
const serverHandlers = new Set();
|
|
3
|
-
const clientHandlers = new Set();
|
|
4
|
-
return {
|
|
5
|
-
server: {
|
|
6
|
-
send: (message) => clientHandlers.forEach((handler) => handler(message)),
|
|
7
|
-
onMessage: (handler) => {
|
|
8
|
-
serverHandlers.add(handler);
|
|
9
|
-
return () => void serverHandlers.delete(handler);
|
|
10
|
-
},
|
|
11
|
-
},
|
|
12
|
-
client: {
|
|
13
|
-
send: (message) => serverHandlers.forEach((handler) => handler(message)),
|
|
14
|
-
onMessage: (handler) => {
|
|
15
|
-
clientHandlers.add(handler);
|
|
16
|
-
return () => void clientHandlers.delete(handler);
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
};
|
|
20
|
-
};
|
|
21
|
-
//# sourceMappingURL=memory.js.map
|
package/dist/memory.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"AAgBA,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAkD,EAAE;IACvF,MAAM,cAAc,GAAG,IAAI,GAAG,EAA6B,CAAA;IAC3D,MAAM,cAAc,GAAG,IAAI,GAAG,EAA6B,CAAA;IAC3D,OAAO;QACL,MAAM,EAAE;YACN,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YACxE,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE;gBACrB,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;gBAC3B,OAAO,GAAG,EAAE,CAAC,KAAK,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;YAClD,CAAC;SACF;QACD,MAAM,EAAE;YACN,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YACxE,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE;gBACrB,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;gBAC3B,OAAO,GAAG,EAAE,CAAC,KAAK,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;YAClD,CAAC;SACF;KACF,CAAA;AACH,CAAC,CAAA"}
|
package/dist/react.d.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { type ReactNode } from 'react';
|
|
2
|
-
import { type InvokeMessage, type RemoteTransport, type ServerMessage } from './transport';
|
|
3
|
-
import type { RemoteContract, RemoteViewSet } from './client';
|
|
4
|
-
/**
|
|
5
|
-
* The React binding for the remote client. A consumer hands it a transport and a
|
|
6
|
-
* `views` map and gets a live React subtree — the framework owns the transport
|
|
7
|
-
* wiring (connect, the patch subscription, re-render on each frame, teardown on
|
|
8
|
-
* unmount). No `useSyncExternalStore`, `binding.subscribe`, or `binding.node()`
|
|
9
|
-
* at the call site.
|
|
10
|
-
*/
|
|
11
|
-
/**
|
|
12
|
-
* Render the remote scene as React. Pass a stable `transport` (created once,
|
|
13
|
-
* e.g. by `createWebSocketClientTransport`) — the binding is established on mount
|
|
14
|
-
* and disposed on unmount.
|
|
15
|
-
*/
|
|
16
|
-
export declare const useRemoteUI: <C extends RemoteContract>(transport: RemoteTransport<InvokeMessage, ServerMessage>, views: RemoteViewSet<C>) => ReactNode;
|
|
17
|
-
export interface RemoteUIProps<C extends RemoteContract> {
|
|
18
|
-
readonly transport: RemoteTransport<InvokeMessage, ServerMessage>;
|
|
19
|
-
/** A contract-checked view set from `remoteViews<C>(…)` — an unbranded `Record` is rejected,
|
|
20
|
-
* so `<RemoteUI>` can only render views proven to implement the server's shape. */
|
|
21
|
-
readonly views: RemoteViewSet<C>;
|
|
22
|
-
}
|
|
23
|
-
/** Component form of {@link useRemoteUI}: `<RemoteUI transport={…} views={…} />`. `C` is
|
|
24
|
-
* inferred from `views` (the `remoteViews<AppContract>(…)` result), so the whole subtree is
|
|
25
|
-
* typed to that app's contract. */
|
|
26
|
-
export declare const RemoteUI: <C extends RemoteContract>({ transport, views, }: RemoteUIProps<C>) => ReactNode;
|
|
27
|
-
/**
|
|
28
|
-
* Anything that reports an observable connection status — implemented by the
|
|
29
|
-
* WebSocket client transport. Kept structural so the React binding needs no
|
|
30
|
-
* dependency on a specific adapter.
|
|
31
|
-
*/
|
|
32
|
-
export interface StatusReporter<S> {
|
|
33
|
-
readonly status: () => S;
|
|
34
|
-
readonly onStatusChange: (listener: () => void) => () => void;
|
|
35
|
-
}
|
|
36
|
-
/** Subscribe to a transport's connection status (e.g. to show a reconnecting badge). */
|
|
37
|
-
export declare const useConnectionStatus: <S>(reporter: StatusReporter<S>) => S;
|
|
38
|
-
//# sourceMappingURL=react.d.ts.map
|
package/dist/react.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAA6C,MAAM,OAAO,CAAA;AACjF,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,aAAa,EACnB,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAE7D;;;;;;GAMG;AAEH;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,cAAc,EAClD,WAAW,eAAe,CAAC,aAAa,EAAE,aAAa,CAAC,EACxD,OAAO,aAAa,CAAC,CAAC,CAAC,KACtB,SAOF,CAAA;AAED,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,cAAc;IACrD,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC,aAAa,EAAE,aAAa,CAAC,CAAA;IACjE;wFACoF;IACpF,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,CAAA;CACjC;AAED;;oCAEoC;AACpC,eAAO,MAAM,QAAQ,GAAI,CAAC,SAAS,cAAc,EAAE,uBAGhD,aAAa,CAAC,CAAC,CAAC,KAAG,SAA0C,CAAA;AAEhE;;;;GAIG;AACH,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,wFAAwF;AACxF,eAAO,MAAM,mBAAmB,GAAI,CAAC,EAAE,UAAU,cAAc,CAAC,CAAC,CAAC,KAAG,CACY,CAAA"}
|
package/dist/react.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState, useSyncExternalStore } from 'react';
|
|
2
|
-
import { connect, } from './transport';
|
|
3
|
-
/**
|
|
4
|
-
* The React binding for the remote client. A consumer hands it a transport and a
|
|
5
|
-
* `views` map and gets a live React subtree — the framework owns the transport
|
|
6
|
-
* wiring (connect, the patch subscription, re-render on each frame, teardown on
|
|
7
|
-
* unmount). No `useSyncExternalStore`, `binding.subscribe`, or `binding.node()`
|
|
8
|
-
* at the call site.
|
|
9
|
-
*/
|
|
10
|
-
/**
|
|
11
|
-
* Render the remote scene as React. Pass a stable `transport` (created once,
|
|
12
|
-
* e.g. by `createWebSocketClientTransport`) — the binding is established on mount
|
|
13
|
-
* and disposed on unmount.
|
|
14
|
-
*/
|
|
15
|
-
export const useRemoteUI = (transport, views) => {
|
|
16
|
-
// One binding for the life of the component (the transport is stable).
|
|
17
|
-
const [binding] = useState(() => connect({ transport, views }));
|
|
18
|
-
useEffect(() => () => binding.dispose(), [binding]);
|
|
19
|
-
// Re-render whenever a frame changes the tree; `snapshot` is a stable ref.
|
|
20
|
-
useSyncExternalStore(binding.subscribe, binding.snapshot, binding.snapshot);
|
|
21
|
-
return binding.node();
|
|
22
|
-
};
|
|
23
|
-
/** Component form of {@link useRemoteUI}: `<RemoteUI transport={…} views={…} />`. `C` is
|
|
24
|
-
* inferred from `views` (the `remoteViews<AppContract>(…)` result), so the whole subtree is
|
|
25
|
-
* typed to that app's contract. */
|
|
26
|
-
export const RemoteUI = ({ transport, views, }) => useRemoteUI(transport, views);
|
|
27
|
-
/** Subscribe to a transport's connection status (e.g. to show a reconnecting badge). */
|
|
28
|
-
export const useConnectionStatus = (reporter) => useSyncExternalStore(reporter.onStatusChange, reporter.status, reporter.status);
|
|
29
|
-
//# sourceMappingURL=react.js.map
|
package/dist/react.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"react.js","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,SAAS,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAA;AACjF,OAAO,EACL,OAAO,GAIR,MAAM,aAAa,CAAA;AAGpB;;;;;;GAMG;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,SAAwD,EACxD,KAAuB,EACZ,EAAE;IACb,uEAAuE;IACvE,MAAM,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA;IAC/D,SAAS,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAA;IACnD,2EAA2E;IAC3E,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;AASD;;oCAEoC;AACpC,MAAM,CAAC,MAAM,QAAQ,GAAG,CAA2B,EACjD,SAAS,EACT,KAAK,GACY,EAAa,EAAE,CAAC,WAAW,CAAC,SAAS,EAAE,KAAK,CAAC,CAAA;AAYhE,wFAAwF;AACxF,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/server.d.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { type Scene, type WirePatch, type WireTree } from '@playfast/reform';
|
|
2
|
-
export interface RemoteServer {
|
|
3
|
-
/** Render the current frame to a full wire tree; triggers are (re-)registered behind stable handles. */
|
|
4
|
-
readonly render: () => Promise<WireTree>;
|
|
5
|
-
/**
|
|
6
|
-
* Render and return only the patches since the previous frame (the streaming
|
|
7
|
-
* form). Handles of deleted nodes are revoked, so a stale client invocation
|
|
8
|
-
* fails cleanly rather than firing a dangling trigger.
|
|
9
|
-
*/
|
|
10
|
-
readonly renderDiff: () => Promise<ReadonlyArray<WirePatch>>;
|
|
11
|
-
/** Fire a trigger the client referenced by handle, then settle the runtime. */
|
|
12
|
-
readonly invoke: (handle: string, encodedPayload: unknown) => Promise<void>;
|
|
13
|
-
/**
|
|
14
|
-
* Observe SERVER-INITIATED state changes. The listener fires (after the drain
|
|
15
|
-
* settles) whenever an event flows on the engine bus — i.e. when an async procedure
|
|
16
|
-
* resolves, a boot loader completes, or a scheduler ticks — NOT just in response to a
|
|
17
|
-
* client invoke. `serve` registers a `renderDiff`-and-push listener here so the client
|
|
18
|
-
* sees background updates (a repo list that finishes loading, a reconcile sweep) that
|
|
19
|
-
* no user interaction triggered. Returns an unsubscribe handle.
|
|
20
|
-
*/
|
|
21
|
-
readonly subscribe: (listener: () => void) => () => void;
|
|
22
|
-
/** Tear down the runtime and its forked fibers. */
|
|
23
|
-
readonly dispose: () => Promise<void>;
|
|
24
|
-
}
|
|
25
|
-
export declare const makeRemoteServer: (scene: Scene) => RemoteServer;
|
|
26
|
-
//# sourceMappingURL=server.d.ts.map
|
package/dist/server.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAEA,OAAO,EAYL,KAAK,KAAK,EAUV,KAAK,SAAS,EAEd,KAAK,QAAQ,EACd,MAAM,kBAAkB,CAAA;AA2FzB,MAAM,WAAW,YAAY;IAC3B,wGAAwG;IACxG,QAAQ,CAAC,MAAM,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAA;IACxC;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAA;IAC5D,+EAA+E;IAC/E,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3E;;;;;;;OAOG;IACH,QAAQ,CAAC,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAA;IACxD,mDAAmD;IACnD,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CACtC;AAED,eAAO,MAAM,gBAAgB,GAAI,OAAO,KAAK,KAAG,YA8L/C,CAAA"}
|
package/dist/server.js
DELETED
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
import { Effect, Layer, ManagedRuntime, PubSub, Queue, Schema } from 'effect';
|
|
2
|
-
import { isValidElement } from 'react';
|
|
3
|
-
import { Bus, CaptureSink, Composition, forceSync, isFeatureBinding, publish, Triggers, Wire, } from '@playfast/reform';
|
|
4
|
-
const SETTLE_DRAIN = 30;
|
|
5
|
-
const settleDrain = Effect.yieldNow().pipe(Effect.repeatN(SETTLE_DRAIN));
|
|
6
|
-
const makeSink = () => {
|
|
7
|
-
const state = { captures: [] };
|
|
8
|
-
return {
|
|
9
|
-
api: { record: (capture) => state.captures.push(capture) },
|
|
10
|
-
get captures() {
|
|
11
|
-
return state.captures;
|
|
12
|
-
},
|
|
13
|
-
reset: () => {
|
|
14
|
-
state.captures = [];
|
|
15
|
-
},
|
|
16
|
-
};
|
|
17
|
-
};
|
|
18
|
-
const closedSceneLayer = (scene) => scene.provide.reduce((a, b) => Layer.merge(a, b));
|
|
19
|
-
const childComposition = (child) => isFeatureBinding(child) ? child.composition : child;
|
|
20
|
-
/**
|
|
21
|
-
* Walk a rendered node and enqueue the child each slot placeholder stands for.
|
|
22
|
-
* Slot components are matched by identity (the host defers them as JSX), so this
|
|
23
|
-
* never invokes — nor needs hooks from — ordinary presentation components.
|
|
24
|
-
*/
|
|
25
|
-
const drive = (node, enqueueBy) => {
|
|
26
|
-
if (Array.isArray(node)) {
|
|
27
|
-
for (const child of node)
|
|
28
|
-
drive(child, enqueueBy);
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
if (!isValidElement(node))
|
|
32
|
-
return;
|
|
33
|
-
if (node.type instanceof Function) {
|
|
34
|
-
const enqueue = enqueueBy.get(node.type);
|
|
35
|
-
if (enqueue !== undefined) {
|
|
36
|
-
// `node.key` is the React key the parent set (`createElement(slots.Row, { key })`),
|
|
37
|
-
// carried onto the wire node so a KEYED slot can select this child on the client
|
|
38
|
-
// (see WireNode.key). React coerces a set key to a string; absent → null.
|
|
39
|
-
enqueue(node.props, node.key);
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
drive(node.props.children, enqueueBy);
|
|
44
|
-
};
|
|
45
|
-
const handlesOf = (node) => node.props.flatMap((prop) => (prop._tag === 'Event' ? [prop.handle] : []));
|
|
46
|
-
export const makeRemoteServer = (scene) => {
|
|
47
|
-
const sink = makeSink();
|
|
48
|
-
const runtime = ManagedRuntime.make(Layer.provideMerge(closedSceneLayer(scene), Layer.succeed(CaptureSink, sink.api)));
|
|
49
|
-
const registry = forceSync(() => runtime.runSync(Triggers.make));
|
|
50
|
-
const collect = (root) => Effect.gen(function* () {
|
|
51
|
-
const bindings = new Map();
|
|
52
|
-
const walk = (comp) => Effect.gen(function* () {
|
|
53
|
-
for (const slotClass of Object.values(comp.manifest.slots ?? {})) {
|
|
54
|
-
if (bindings.has(slotClass))
|
|
55
|
-
continue;
|
|
56
|
-
const child = childComposition(yield* slotClass.tag);
|
|
57
|
-
bindings.set(slotClass, child);
|
|
58
|
-
yield* walk(child);
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
yield* walk(root);
|
|
62
|
-
return bindings;
|
|
63
|
-
});
|
|
64
|
-
const toWireNode = (m, capture) => Effect.gen(function* () {
|
|
65
|
-
// The composition's contract carries the wire schemas at runtime (the type is
|
|
66
|
-
// the erased `{ manifest }` carrier — `composition.ts:34`); read them as `UiManifest`.
|
|
67
|
-
const manifest = m.comp.manifest.ui.manifest;
|
|
68
|
-
const dataProps = [];
|
|
69
|
-
if (manifest.props !== undefined) {
|
|
70
|
-
const encoded = yield* Schema.encodeUnknown(manifest.props)(capture.props);
|
|
71
|
-
for (const [name, value] of Object.entries(encoded)) {
|
|
72
|
-
dataProps.push({ _tag: 'Data', name, value });
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
const eventSchemas = manifest.events ?? {};
|
|
76
|
-
const eventProps = [];
|
|
77
|
-
for (const [name, trigger] of Object.entries(capture.events)) {
|
|
78
|
-
const schema = eventSchemas[name];
|
|
79
|
-
if (schema === undefined)
|
|
80
|
-
continue;
|
|
81
|
-
const handle = `${m.id}:${name}`;
|
|
82
|
-
yield* registry.register(handle, trigger, schema);
|
|
83
|
-
eventProps.push({ _tag: 'Event', name, handle });
|
|
84
|
-
}
|
|
85
|
-
return {
|
|
86
|
-
id: m.id,
|
|
87
|
-
name: capture.name,
|
|
88
|
-
parentId: m.parentId,
|
|
89
|
-
childIndex: m.childIndex,
|
|
90
|
-
slot: m.slot,
|
|
91
|
-
key: m.key,
|
|
92
|
-
props: [...dataProps, ...eventProps],
|
|
93
|
-
};
|
|
94
|
-
});
|
|
95
|
-
const renderLevel = (frontier, bindings) => Effect.gen(function* () {
|
|
96
|
-
if (frontier.length === 0)
|
|
97
|
-
return [];
|
|
98
|
-
const next = [];
|
|
99
|
-
const nodes = [];
|
|
100
|
-
for (const mounted of frontier) {
|
|
101
|
-
const service = yield* mounted.comp.tag;
|
|
102
|
-
const slotIndex = new Map();
|
|
103
|
-
const enqueueBy = new Map();
|
|
104
|
-
const slots = {
|
|
105
|
-
slot: (name) => {
|
|
106
|
-
const slotClass = mounted.comp.manifest.slots?.[name];
|
|
107
|
-
const child = slotClass ? bindings.get(slotClass) : undefined;
|
|
108
|
-
const component = () => null;
|
|
109
|
-
if (child !== undefined) {
|
|
110
|
-
enqueueBy.set(component, (childProps, key) => {
|
|
111
|
-
const index = slotIndex.get(name) ?? 0;
|
|
112
|
-
slotIndex.set(name, index + 1);
|
|
113
|
-
next.push({
|
|
114
|
-
comp: child,
|
|
115
|
-
props: childProps,
|
|
116
|
-
id: `${mounted.id}.${name}.${index}`,
|
|
117
|
-
parentId: mounted.id,
|
|
118
|
-
slot: name,
|
|
119
|
-
childIndex: index,
|
|
120
|
-
key,
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
return component;
|
|
125
|
-
},
|
|
126
|
-
};
|
|
127
|
-
const before = sink.captures.length;
|
|
128
|
-
const env = { props: mounted.props, tracker: { add: () => { } }, slots };
|
|
129
|
-
const node = yield* Composition.render(service, env);
|
|
130
|
-
const capture = sink.captures[before];
|
|
131
|
-
if (capture !== undefined)
|
|
132
|
-
nodes.push(yield* toWireNode(mounted, capture));
|
|
133
|
-
drive(node, enqueueBy);
|
|
134
|
-
}
|
|
135
|
-
const rest = yield* renderLevel(next, bindings);
|
|
136
|
-
return [...nodes, ...rest];
|
|
137
|
-
});
|
|
138
|
-
const renderEffect = Effect.gen(function* () {
|
|
139
|
-
yield* settleDrain;
|
|
140
|
-
sink.reset();
|
|
141
|
-
const bindings = yield* collect(scene.composition);
|
|
142
|
-
const root = {
|
|
143
|
-
comp: scene.composition,
|
|
144
|
-
props: {},
|
|
145
|
-
id: '0',
|
|
146
|
-
parentId: null,
|
|
147
|
-
slot: null,
|
|
148
|
-
childIndex: 0,
|
|
149
|
-
key: null,
|
|
150
|
-
};
|
|
151
|
-
return yield* renderLevel([root], bindings);
|
|
152
|
-
});
|
|
153
|
-
// Server-initiated change notification: a forked daemon subscribes to the engine bus
|
|
154
|
-
// and, after each batch settles, fans out to registered listeners. This is what lets a
|
|
155
|
-
// streaming binding push frames the client never asked for — a background load resolving
|
|
156
|
-
// long after connect. Forked BEFORE the boot publish below so nothing is missed (the
|
|
157
|
-
// listener set is empty until `subscribe` runs, so early ticks are harmless no-ops; the
|
|
158
|
-
// binding's opening snapshot captures all state up to `start`).
|
|
159
|
-
const changeListeners = new Set();
|
|
160
|
-
const notifyChange = () => {
|
|
161
|
-
for (const listener of changeListeners)
|
|
162
|
-
listener();
|
|
163
|
-
};
|
|
164
|
-
runtime.runFork(Effect.scoped(Effect.gen(function* () {
|
|
165
|
-
const bus = yield* Bus;
|
|
166
|
-
const subscription = yield* PubSub.subscribe(bus);
|
|
167
|
-
// Notify on each event; the consumer (`serve`) debounces, so the render it triggers
|
|
168
|
-
// runs a tick later — after the drain has folded this event into state. No settle
|
|
169
|
-
// here: it would only perturb the drain's own scheduling for no benefit.
|
|
170
|
-
yield* Queue.take(subscription).pipe(Effect.zipRight(Effect.sync(notifyChange)), Effect.forever);
|
|
171
|
-
})));
|
|
172
|
-
runtime.runSync(Effect.forEach(scene.boot ?? [], (event) => publish('High', event)));
|
|
173
|
-
// The last emitted frame, to diff against. A const holder whose field we swap
|
|
174
|
-
// (no reassigned binding), matching the sink's immutable-swap idiom.
|
|
175
|
-
const frame = { tree: [] };
|
|
176
|
-
const render = () => runtime.runPromise(renderEffect).then((tree) => {
|
|
177
|
-
frame.tree = tree;
|
|
178
|
-
return tree;
|
|
179
|
-
});
|
|
180
|
-
const renderDiff = () => runtime.runPromise(renderEffect).then((next) => {
|
|
181
|
-
const previous = frame.tree;
|
|
182
|
-
const patches = Wire.diff(previous, next);
|
|
183
|
-
frame.tree = next;
|
|
184
|
-
const nextIds = new Set(next.map((node) => node.id));
|
|
185
|
-
const staleHandles = previous
|
|
186
|
-
.filter((node) => !nextIds.has(node.id))
|
|
187
|
-
.flatMap(handlesOf);
|
|
188
|
-
return runtime
|
|
189
|
-
.runPromise(Effect.forEach(staleHandles, (handle) => registry.revoke(handle)))
|
|
190
|
-
.then(() => patches);
|
|
191
|
-
});
|
|
192
|
-
return {
|
|
193
|
-
render,
|
|
194
|
-
renderDiff,
|
|
195
|
-
invoke: (handle, encodedPayload) => runtime.runPromise(Effect.gen(function* () {
|
|
196
|
-
yield* registry.invoke(handle, encodedPayload);
|
|
197
|
-
yield* settleDrain;
|
|
198
|
-
})),
|
|
199
|
-
subscribe: (listener) => {
|
|
200
|
-
changeListeners.add(listener);
|
|
201
|
-
return () => void changeListeners.delete(listener);
|
|
202
|
-
},
|
|
203
|
-
dispose: () => runtime.dispose(),
|
|
204
|
-
};
|
|
205
|
-
};
|
|
206
|
-
//# sourceMappingURL=server.js.map
|
package/dist/server.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,EAAoB,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/F,OAAO,EAAE,cAAc,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,EACL,GAAG,EACH,WAAW,EAEX,WAAW,EAGX,SAAS,EACT,gBAAgB,EAEhB,OAAO,EAMP,QAAQ,EAIR,IAAI,GAKL,MAAM,kBAAkB,CAAA;AAiBzB,MAAM,YAAY,GAAG,EAAE,CAAA;AACvB,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAA;AAQxE,MAAM,QAAQ,GAAG,GAAS,EAAE;IAC1B,MAAM,KAAK,GAA8B,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAA;IACzD,OAAO;QACL,GAAG,EAAE,EAAE,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;QAC1D,IAAI,QAAQ;YACV,OAAO,KAAK,CAAC,QAAQ,CAAA;QACvB,CAAC;QACD,KAAK,EAAE,GAAG,EAAE;YACV,KAAK,CAAC,QAAQ,GAAG,EAAE,CAAA;QACrB,CAAC;KACF,CAAA;AACH,CAAC,CAAA;AAED,MAAM,gBAAgB,GAAG,CAAC,KAAY,EAA8C,EAAE,CACpF,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAI/C,CAAA;AAcH,MAAM,gBAAgB,GAAG,CAAC,KAAgB,EAA6B,EAAE,CACvE,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAA;AAErD;;;;GAIG;AACH,MAAM,KAAK,GAAG,CACZ,IAAU,EACV,SAAsE,EAChE,EAAE;IACR,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,KAAK,MAAM,KAAK,IAAI,IAAI;YAAE,KAAK,CAAC,KAAK,EAAE,SAAS,CAAC,CAAA;QACjD,OAAM;IACR,CAAC;IACD,IAAI,CAAC,cAAc,CAA+B,IAAI,CAAC;QAAE,OAAM;IAC/D,IAAI,IAAI,CAAC,IAAI,YAAY,QAAQ,EAAE,CAAC;QAClC,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACxC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,oFAAoF;YACpF,iFAAiF;YACjF,0EAA0E;YAC1E,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAA;YAC7B,OAAM;QACR,CAAC;IACH,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAA;AACvC,CAAC,CAAA;AAED,MAAM,SAAS,GAAG,CAAC,IAAc,EAAyB,EAAE,CAC1D,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;AA0B5E,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAAY,EAAgB,EAAE;IAC7D,MAAM,IAAI,GAAG,QAAQ,EAAE,CAAA;IACvB,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,CACjC,KAAK,CAAC,YAAY,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAClF,CAAA;IACD,MAAM,QAAQ,GAAuB,SAAS,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAA;IAEpF,MAAM,OAAO,GAAG,CACd,IAA+B,EAC6C,EAAE,CAC9E,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAwC,CAAA;QAChE,MAAM,IAAI,GAAG,CAAC,IAA+B,EAAyC,EAAE,CACtF,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAClB,KAAK,MAAM,SAAS,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC;gBACjE,IAAI,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC;oBAAE,SAAQ;gBACrC,MAAM,KAAK,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;gBACpD,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAA;gBAC9B,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACpB,CAAC;QACH,CAAC,CAAC,CAAA;QACJ,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACjB,OAAO,QAAQ,CAAA;IACjB,CAAC,CAAC,CAAA;IAEJ,MAAM,UAAU,GAAG,CAAC,CAAU,EAAE,OAAkB,EAAmD,EAAE,CACrG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,8EAA8E;QAC9E,uFAAuF;QACvF,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAsB,CAAA;QAE1D,MAAM,SAAS,GAAe,EAAE,CAAA;QAChC,IAAI,QAAQ,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YACjC,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;YAC1E,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAkC,CAAC,EAAE,CAAC;gBAC/E,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;YAC/C,CAAC;QACH,CAAC;QAED,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAA;QAC1C,MAAM,UAAU,GAAe,EAAE,CAAA;QACjC,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC7D,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAA;YACjC,IAAI,MAAM,KAAK,SAAS;gBAAE,SAAQ;YAClC,MAAM,MAAM,GAAG,GAAG,CAAC,CAAC,EAAE,IAAI,IAAI,EAAE,CAAA;YAChC,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAA;YACjD,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAA;QAClD,CAAC;QAED,OAAO;YACL,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,UAAU,EAAE,CAAC,CAAC,UAAU;YACxB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,GAAG,EAAE,CAAC,CAAC,GAAG;YACV,KAAK,EAAE,CAAC,GAAG,SAAS,EAAE,GAAG,UAAU,CAAC;SACrC,CAAA;IACH,CAAC,CAAC,CAAA;IAEJ,MAAM,WAAW,GAAG,CAClB,QAAgC,EAChC,QAA2D,EACyB,EAAE,CACtF,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAA;QACpC,MAAM,IAAI,GAAc,EAAE,CAAA;QAC1B,MAAM,KAAK,GAAe,EAAE,CAAA;QAC5B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAA;YACvC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAA;YAC3C,MAAM,SAAS,GAAG,IAAI,GAAG,EAA+D,CAAA;YACxF,MAAM,KAAK,GAAa;gBACtB,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE;oBACb,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAA;oBACrD,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;oBAC7D,MAAM,SAAS,GAAkC,GAAG,EAAE,CAAC,IAAI,CAAA;oBAC3D,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;wBACxB,SAAS,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,UAAU,EAAE,GAAG,EAAE,EAAE;4BAC3C,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;4BACtC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,GAAG,CAAC,CAAC,CAAA;4BAC9B,IAAI,CAAC,IAAI,CAAC;gCACR,IAAI,EAAE,KAAK;gCACX,KAAK,EAAE,UAAU;gCACjB,EAAE,EAAE,GAAG,OAAO,CAAC,EAAE,IAAI,IAAI,IAAI,KAAK,EAAE;gCACpC,QAAQ,EAAE,OAAO,CAAC,EAAE;gCACpB,IAAI,EAAE,IAAI;gCACV,UAAU,EAAE,KAAK;gCACjB,GAAG;6BACJ,CAAC,CAAA;wBACJ,CAAC,CAAC,CAAA;oBACJ,CAAC;oBACD,OAAO,SAAS,CAAA;gBAClB,CAAC;aACF,CAAA;YACD,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAA;YACnC,MAAM,GAAG,GAAc,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,EAAE,KAAK,EAAE,CAAA;YAClF,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;YACpD,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;YACrC,IAAI,OAAO,KAAK,SAAS;gBAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAA;YAC1E,KAAK,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;QACxB,CAAC;QACD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;QAC/C,OAAO,CAAC,GAAG,KAAK,EAAE,GAAG,IAAI,CAAC,CAAA;IAC5B,CAAC,CAAC,CAAA;IAEJ,MAAM,YAAY,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QACvC,KAAK,CAAC,CAAC,WAAW,CAAA;QAClB,IAAI,CAAC,KAAK,EAAE,CAAA;QACZ,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;QAClD,MAAM,IAAI,GAAY;YACpB,IAAI,EAAE,KAAK,CAAC,WAAW;YACvB,KAAK,EAAE,EAAE;YACT,EAAE,EAAE,GAAG;YACP,QAAQ,EAAE,IAAI;YACd,IAAI,EAAE,IAAI;YACV,UAAU,EAAE,CAAC;YACb,GAAG,EAAE,IAAI;SACV,CAAA;QACD,OAAO,KAAK,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAA;IAC7C,CAAC,CAAC,CAAA;IAEF,qFAAqF;IACrF,uFAAuF;IACvF,yFAAyF;IACzF,qFAAqF;IACrF,wFAAwF;IACxF,gEAAgE;IAChE,MAAM,eAAe,GAAG,IAAI,GAAG,EAAc,CAAA;IAC7C,MAAM,YAAY,GAAG,GAAS,EAAE;QAC9B,KAAK,MAAM,QAAQ,IAAI,eAAe;YAAE,QAAQ,EAAE,CAAA;IACpD,CAAC,CAAA;IACD,OAAO,CAAC,OAAO,CACb,MAAM,CAAC,MAAM,CACX,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,GAAG,CAAA;QACtB,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;QACjD,oFAAoF;QACpF,kFAAkF;QAClF,yEAAyE;QACzE,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAClC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,EAC1C,MAAM,CAAC,OAAO,CACf,CAAA;IACH,CAAC,CAAC,CACH,CACF,CAAA;IAED,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,CAAA;IAEpF,8EAA8E;IAC9E,qEAAqE;IACrE,MAAM,KAAK,GAAuB,EAAE,IAAI,EAAE,EAAE,EAAE,CAAA;IAE9C,MAAM,MAAM,GAAG,GAAsB,EAAE,CACrC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;QAC7C,KAAK,CAAC,IAAI,GAAG,IAAI,CAAA;QACjB,OAAO,IAAI,CAAA;IACb,CAAC,CAAC,CAAA;IAEJ,MAAM,UAAU,GAAG,GAAsC,EAAE,CACzD,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;QAC7C,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAA;QAC3B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;QACzC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAA;QACjB,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;QACpD,MAAM,YAAY,GAAG,QAAQ;aAC1B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;aACvC,OAAO,CAAC,SAAS,CAAC,CAAA;QACrB,OAAO,OAAO;aACX,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;aAC7E,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,CAAA;IACxB,CAAC,CAAC,CAAA;IAEJ,OAAO;QACL,MAAM;QACN,UAAU;QACV,MAAM,EAAE,CAAC,MAAM,EAAE,cAAc,EAAE,EAAE,CACjC,OAAO,CAAC,UAAU,CAChB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAClB,KAAK,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;YAC9C,KAAK,CAAC,CAAC,WAAW,CAAA;QACpB,CAAC,CAAC,CACH;QACH,SAAS,EAAE,CAAC,QAAQ,EAAE,EAAE;YACtB,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;YAC7B,OAAO,GAAG,EAAE,CAAC,KAAK,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;QACpD,CAAC;QACD,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE;KACjC,CAAA;AACH,CAAC,CAAA"}
|
package/dist/transport.d.ts
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import type { ReactNode } from 'react';
|
|
2
|
-
import { type WirePatch, type WireTree } from '@playfast/reform';
|
|
3
|
-
import type { Scene } from '@playfast/reform';
|
|
4
|
-
import { type RemoteContract, type RemoteViewSet } from './client';
|
|
5
|
-
/**
|
|
6
|
-
* Binds the server driver and the client renderer to a transport. The wire
|
|
7
|
-
* carries only serializable data — patches one way, trigger invocations the
|
|
8
|
-
* other — so any duplex channel (WebSocket, postMessage, in-memory) works; a
|
|
9
|
-
* concrete adapter just implements `RemoteTransport`. See REMOTE_UI.md §5.
|
|
10
|
-
*/
|
|
11
|
-
/**
|
|
12
|
-
* Server → client: the full current tree, replacing whatever the client holds.
|
|
13
|
-
* The first frame of every (re)connection — a fresh server runtime diffs from
|
|
14
|
-
* empty, so it can only *add* nodes; a snapshot is what lets a reconnecting
|
|
15
|
-
* client drop the stale tree it accumulated on the previous socket.
|
|
16
|
-
*/
|
|
17
|
-
export interface SnapshotMessage {
|
|
18
|
-
readonly _tag: 'Snapshot';
|
|
19
|
-
readonly tree: WireTree;
|
|
20
|
-
}
|
|
21
|
-
/** Server → client: a batch of tree patches to fold with `Wire.apply`. */
|
|
22
|
-
export interface PatchesMessage {
|
|
23
|
-
readonly _tag: 'Patches';
|
|
24
|
-
readonly patches: ReadonlyArray<WirePatch>;
|
|
25
|
-
}
|
|
26
|
-
/** Everything the server sends the client: a fresh snapshot or incremental patches. */
|
|
27
|
-
export type ServerMessage = SnapshotMessage | PatchesMessage;
|
|
28
|
-
/** Client → server: fire the trigger behind `handle` with an encoded payload. */
|
|
29
|
-
export interface InvokeMessage {
|
|
30
|
-
readonly _tag: 'Invoke';
|
|
31
|
-
readonly handle: string;
|
|
32
|
-
readonly payload: unknown;
|
|
33
|
-
}
|
|
34
|
-
/** A duplex channel: send `Out`, receive `In`. */
|
|
35
|
-
export interface RemoteTransport<Out, In> {
|
|
36
|
-
readonly send: (message: Out) => void;
|
|
37
|
-
readonly onMessage: (handler: (message: In) => void) => () => void;
|
|
38
|
-
}
|
|
39
|
-
export interface ServerBinding {
|
|
40
|
-
/** Render the first frame and push it. Call once the client is connected. */
|
|
41
|
-
readonly start: () => Promise<void>;
|
|
42
|
-
readonly dispose: () => Promise<void>;
|
|
43
|
-
}
|
|
44
|
-
/** Options for {@link serve} — a single named object so every reform-remote binding shares one shape. */
|
|
45
|
-
export interface ServeOptions {
|
|
46
|
-
readonly scene: Scene;
|
|
47
|
-
readonly transport: RemoteTransport<ServerMessage, InvokeMessage>;
|
|
48
|
-
}
|
|
49
|
-
export declare const serve: (options: ServeOptions) => ServerBinding;
|
|
50
|
-
export interface ClientBinding {
|
|
51
|
-
/** The current rendered node — re-read on each `subscribe` notification. */
|
|
52
|
-
readonly node: () => ReactNode;
|
|
53
|
-
/** Notified whenever applied patches change the tree. */
|
|
54
|
-
readonly subscribe: (listener: () => void) => () => void;
|
|
55
|
-
/**
|
|
56
|
-
* The current wire tree — a stable reference that changes only when a frame is
|
|
57
|
-
* applied, so it is a valid `useSyncExternalStore` snapshot (the React binding
|
|
58
|
-
* builds on this).
|
|
59
|
-
*/
|
|
60
|
-
readonly snapshot: () => WireTree;
|
|
61
|
-
readonly dispose: () => void;
|
|
62
|
-
}
|
|
63
|
-
/** Options for {@link connect} — a single named object, mirroring {@link ServeOptions}. */
|
|
64
|
-
export interface ConnectOptions<C extends RemoteContract> {
|
|
65
|
-
readonly transport: RemoteTransport<InvokeMessage, ServerMessage>;
|
|
66
|
-
readonly views: RemoteViewSet<C>;
|
|
67
|
-
}
|
|
68
|
-
export declare const connect: <C extends RemoteContract>(options: ConnectOptions<C>) => ClientBinding;
|
|
69
|
-
//# sourceMappingURL=transport.d.ts.map
|
package/dist/transport.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,EAAQ,KAAK,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AACtE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAE7C,OAAO,EAAkB,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,UAAU,CAAA;AAElF;;;;;GAKG;AAEH;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;IACzB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CACxB;AAED,0EAA0E;AAC1E,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;IACxB,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,SAAS,CAAC,CAAA;CAC3C;AAED,uFAAuF;AACvF,MAAM,MAAM,aAAa,GAAG,eAAe,GAAG,cAAc,CAAA;AAE5D,iFAAiF;AACjF,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,kDAAkD;AAClD,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,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CACtC;AAUD,yGAAyG;AACzG,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC,aAAa,EAAE,aAAa,CAAC,CAAA;CAClE;AAED,eAAO,MAAM,KAAK,GAAI,SAAS,YAAY,KAAG,aA0E7C,CAAA;AAED,MAAM,WAAW,aAAa;IAC5B,4EAA4E;IAC5E,QAAQ,CAAC,IAAI,EAAE,MAAM,SAAS,CAAA;IAC9B,yDAAyD;IACzD,QAAQ,CAAC,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAA;IACxD;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,QAAQ,CAAA;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAA;CAC7B;AAED,2FAA2F;AAC3F,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;CACjC;AAED,eAAO,MAAM,OAAO,GAAI,CAAC,SAAS,cAAc,EAAE,SAAS,cAAc,CAAC,CAAC,CAAC,KAAG,aA4B9E,CAAA"}
|
package/dist/transport.js
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { Match } from 'effect';
|
|
2
|
-
import { Wire } from '@playfast/reform';
|
|
3
|
-
import { makeRemoteServer } from './server';
|
|
4
|
-
import { renderWireTree } from './client';
|
|
5
|
-
/**
|
|
6
|
-
* Debounce window for SERVER-initiated frame pushes (background loads, scheduler ticks).
|
|
7
|
-
* Long enough that the engine drain has folded the change into state and a burst of facts
|
|
8
|
-
* coalesces into one render; short enough to feel live. Client invokes don't wait on this —
|
|
9
|
-
* they push immediately.
|
|
10
|
-
*/
|
|
11
|
-
const BACKGROUND_FLUSH_MS = 16;
|
|
12
|
-
export const serve = (options) => {
|
|
13
|
-
const { scene, transport } = options;
|
|
14
|
-
const server = makeRemoteServer(scene);
|
|
15
|
-
// The first frame is a full snapshot (replace); every frame after is the diff since the
|
|
16
|
-
// last (apply). Both keep the server's `frame` baseline in step, so the diffs always
|
|
17
|
-
// reference what the client actually holds. Diffs are emitted both after a client invoke
|
|
18
|
-
// AND whenever the server's OWN state changes (a background load resolving, a scheduler
|
|
19
|
-
// tick) — without the latter, anything the user didn't directly trigger would never reach
|
|
20
|
-
// the client (it would sit on the snapshot's loading state forever).
|
|
21
|
-
//
|
|
22
|
-
// `started` gates pushes until the opening snapshot is sent: a diff that raced ahead of
|
|
23
|
-
// the snapshot would reference a tree the client has not received.
|
|
24
|
-
//
|
|
25
|
-
// `push` is a COALESCING single-flight render: at most one `renderDiff` runs at a time
|
|
26
|
-
// (concurrent ones would interleave the sink captures and corrupt the frame baseline). If
|
|
27
|
-
// a change arrives WHILE a render is in flight — e.g. an async procedure folds its result
|
|
28
|
-
// mid-render — `dirty` is set and a follow-up render runs when the current one settles, so
|
|
29
|
-
// a late state change is never dropped. Both a client invoke and a server-side change
|
|
30
|
-
// (the bus subscriber) funnel through here, so there is exactly one push path.
|
|
31
|
-
const started = { value: false };
|
|
32
|
-
const flight = { promise: null, dirty: false };
|
|
33
|
-
const push = () => {
|
|
34
|
-
if (!started.value)
|
|
35
|
-
return Promise.resolve();
|
|
36
|
-
if (flight.promise !== null) {
|
|
37
|
-
flight.dirty = true;
|
|
38
|
-
return flight.promise;
|
|
39
|
-
}
|
|
40
|
-
const run = (async () => {
|
|
41
|
-
const patches = await server.renderDiff();
|
|
42
|
-
if (patches.length > 0)
|
|
43
|
-
transport.send({ _tag: 'Patches', patches });
|
|
44
|
-
})().finally(() => {
|
|
45
|
-
flight.promise = null;
|
|
46
|
-
if (flight.dirty) {
|
|
47
|
-
flight.dirty = false;
|
|
48
|
-
void push();
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
flight.promise = run;
|
|
52
|
-
return run;
|
|
53
|
-
};
|
|
54
|
-
// Server-initiated changes are flushed on a short DEBOUNCE rather than synchronously: it
|
|
55
|
-
// coalesces a burst (a procedure that dispatches several facts) into one render, and the
|
|
56
|
-
// delay lets the drain fold the change into state before we read it — so the diff reflects
|
|
57
|
-
// the settled result, and the background flush never races the synchronous invoke push
|
|
58
|
-
// above. A client invoke still pushes immediately (its own settle path), so user actions
|
|
59
|
-
// stay snappy; this path only carries updates no interaction triggered.
|
|
60
|
-
const debounce = { handle: null };
|
|
61
|
-
const scheduleFlush = () => {
|
|
62
|
-
if (!started.value || debounce.handle !== null)
|
|
63
|
-
return;
|
|
64
|
-
debounce.handle = setTimeout(() => {
|
|
65
|
-
debounce.handle = null;
|
|
66
|
-
void push();
|
|
67
|
-
}, BACKGROUND_FLUSH_MS);
|
|
68
|
-
};
|
|
69
|
-
const start = async () => {
|
|
70
|
-
const tree = await server.render();
|
|
71
|
-
transport.send({ _tag: 'Snapshot', tree });
|
|
72
|
-
started.value = true;
|
|
73
|
-
// Flush anything that changed during the (async) opening render window.
|
|
74
|
-
scheduleFlush();
|
|
75
|
-
};
|
|
76
|
-
const off = transport.onMessage((message) => {
|
|
77
|
-
void server.invoke(message.handle, message.payload).then(push);
|
|
78
|
-
});
|
|
79
|
-
const offChange = server.subscribe(scheduleFlush);
|
|
80
|
-
return {
|
|
81
|
-
start,
|
|
82
|
-
dispose: async () => {
|
|
83
|
-
off();
|
|
84
|
-
offChange();
|
|
85
|
-
if (debounce.handle !== null)
|
|
86
|
-
clearTimeout(debounce.handle);
|
|
87
|
-
await server.dispose();
|
|
88
|
-
},
|
|
89
|
-
};
|
|
90
|
-
};
|
|
91
|
-
export const connect = (options) => {
|
|
92
|
-
const { transport, views } = options;
|
|
93
|
-
const state = { tree: [] };
|
|
94
|
-
const listeners = new Set();
|
|
95
|
-
const config = {
|
|
96
|
-
views,
|
|
97
|
-
invoke: (handle, payload) => transport.send({ _tag: 'Invoke', handle, payload }),
|
|
98
|
-
};
|
|
99
|
-
const off = transport.onMessage((message) => {
|
|
100
|
-
// A snapshot replaces the tree wholesale (a fresh or reconnected session);
|
|
101
|
-
// patches fold into it. So a reconnect re-syncs without leaking stale nodes.
|
|
102
|
-
state.tree = Match.value(message).pipe(Match.tag('Snapshot', ({ tree }) => tree), Match.tag('Patches', ({ patches }) => Wire.apply(state.tree, patches)), Match.exhaustive);
|
|
103
|
-
for (const listener of listeners)
|
|
104
|
-
listener();
|
|
105
|
-
});
|
|
106
|
-
return {
|
|
107
|
-
node: () => renderWireTree(state.tree, config),
|
|
108
|
-
subscribe: (listener) => {
|
|
109
|
-
listeners.add(listener);
|
|
110
|
-
return () => void listeners.delete(listener);
|
|
111
|
-
},
|
|
112
|
-
snapshot: () => state.tree,
|
|
113
|
-
dispose: off,
|
|
114
|
-
};
|
|
115
|
-
};
|
|
116
|
-
//# sourceMappingURL=transport.js.map
|
package/dist/transport.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"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"}
|