@reactpy/client 0.2.1 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../src/components.tsx"],"names":[],"mappings":";AAcA,OAAO,EACL,WAAW,EAMZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAIjD,wBAAgB,MAAM,CAAC,KAAK,EAAE;IAAE,MAAM,EAAE,aAAa,CAAA;CAAE,GAAG,GAAG,CAAC,OAAO,CAyBpE;AAED,wBAAgB,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,WAAW,CAAA;CAAE,GAAG,GAAG,CAAC,OAAO,GAAG,IAAI,CAoB7E"}
1
+ {"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../src/components.tsx"],"names":[],"mappings":";AAaA,OAAO,EACL,WAAW,EAMZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAIjD,wBAAgB,MAAM,CAAC,KAAK,EAAE;IAAE,MAAM,EAAE,aAAa,CAAA;CAAE,GAAG,GAAG,CAAC,OAAO,CAsBpE;AAED,wBAAgB,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,WAAW,CAAA;CAAE,GAAG,GAAG,CAAC,OAAO,GAAG,IAAI,CAoB7E"}
@@ -6,19 +6,15 @@ const ClientContext = createContext(null);
6
6
  export function Layout(props) {
7
7
  const currentModel = useState({ tagName: "" })[0];
8
8
  const forceUpdate = useForceUpdate();
9
- useEffect(() => {
10
- props.client.onMessage("layout-update", ({ path, model }) => {
11
- if (path === "") {
12
- Object.assign(currentModel, model);
13
- }
14
- else {
15
- setJsonPointer(currentModel, path, model);
16
- }
17
- forceUpdate();
18
- });
19
- props.client.start();
20
- return () => props.client.stop();
21
- }, [currentModel, props.client]);
9
+ useEffect(() => props.client.onMessage("layout-update", ({ path, model }) => {
10
+ if (path === "") {
11
+ Object.assign(currentModel, model);
12
+ }
13
+ else {
14
+ setJsonPointer(currentModel, path, model);
15
+ }
16
+ forceUpdate();
17
+ }), [currentModel, props.client]);
22
18
  return (React.createElement(ClientContext.Provider, { value: props.client },
23
19
  React.createElement(Element, { model: currentModel })));
24
20
  }
@@ -94,7 +90,7 @@ function ScriptElement({ model }) {
94
90
  ref.current.appendChild(scriptElement);
95
91
  }
96
92
  else if (scriptContent) {
97
- let scriptResult = eval(scriptContent);
93
+ const scriptResult = eval(scriptContent);
98
94
  if (typeof scriptResult == "function") {
99
95
  return scriptResult();
100
96
  }
@@ -170,3 +166,4 @@ const SPECIAL_ELEMENTS = {
170
166
  select: UserInputElement,
171
167
  textarea: UserInputElement,
172
168
  };
169
+ //# sourceMappingURL=components.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"components.js","sourceRoot":"","sources":["../src/components.tsx"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -3,3 +3,4 @@ export * from "./messages";
3
3
  export * from "./mount";
4
4
  export * from "./reactpy-client";
5
5
  export * from "./reactpy-vdom";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC"}
package/dist/logger.js CHANGED
@@ -3,3 +3,4 @@ export default {
3
3
  warn: (...args) => console.warn("[ReactPy]", ...args),
4
4
  error: (...args) => console.error("[ReactPy]", ...args),
5
5
  };
6
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,eAAe;IACb,GAAG,EAAE,CAAC,GAAG,IAAW,EAAQ,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC;IAChE,IAAI,EAAE,CAAC,GAAG,IAAW,EAAQ,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC;IAClE,KAAK,EAAE,CAAC,GAAG,IAAW,EAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC;CACrE,CAAC"}
@@ -1,13 +1,4 @@
1
1
  import { ReactPyVdom } from "./reactpy-vdom";
2
- export interface IMessage {
3
- type: string;
4
- }
5
- export type ConnectionOpenMessage = {
6
- type: "connection-open";
7
- };
8
- export type ConnectionCloseMessage = {
9
- type: "connection-close";
10
- };
11
2
  export type LayoutUpdateMessage = {
12
3
  type: "layout-update";
13
4
  path: string;
@@ -18,7 +9,7 @@ export type LayoutEventMessage = {
18
9
  target: string;
19
10
  data: any;
20
11
  };
21
- export type IncomingMessage = LayoutUpdateMessage | ConnectionOpenMessage | ConnectionCloseMessage;
12
+ export type IncomingMessage = LayoutUpdateMessage;
22
13
  export type OutgoingMessage = LayoutEventMessage;
23
14
  export type Message = IncomingMessage | OutgoingMessage;
24
15
  //# sourceMappingURL=messages.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,iBAAiB,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,EAAE,kBAAkB,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,eAAe,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,WAAW,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,cAAc,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,GAAG,CAAC;CACX,CAAC;AAEF,MAAM,MAAM,eAAe,GACvB,mBAAmB,GACnB,qBAAqB,GACrB,sBAAsB,CAAC;AAC3B,MAAM,MAAM,eAAe,GAAG,kBAAkB,CAAC;AACjD,MAAM,MAAM,OAAO,GAAG,eAAe,GAAG,eAAe,CAAC"}
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,eAAe,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,WAAW,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,cAAc,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,GAAG,CAAC;CACX,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,mBAAmB,CAAC;AAClD,MAAM,MAAM,eAAe,GAAG,kBAAkB,CAAC;AACjD,MAAM,MAAM,OAAO,GAAG,eAAe,GAAG,eAAe,CAAC"}
package/dist/messages.js CHANGED
@@ -1 +1,2 @@
1
1
  export {};
2
+ //# sourceMappingURL=messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.js","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":""}
package/dist/mount.js CHANGED
@@ -4,3 +4,4 @@ import { Layout } from "./components";
4
4
  export function mount(element, client) {
5
5
  render(React.createElement(Layout, { client: client }), element);
6
6
  }
7
+ //# sourceMappingURL=mount.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mount.js","sourceRoot":"","sources":["../src/mount.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACnC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAGtC,MAAM,UAAU,KAAK,CAAC,OAAoB,EAAE,MAAqB;IAC/D,MAAM,CAAC,oBAAC,MAAM,IAAC,MAAM,EAAE,MAAM,GAAI,EAAE,OAAO,CAAC,CAAC;AAC9C,CAAC"}
@@ -1,32 +1,47 @@
1
- import { OutgoingMessage, IncomingMessage } from "./messages";
2
1
  import { ReactPyModule } from "./reactpy-vdom";
3
2
  /**
4
3
  * A client for communicating with a ReactPy server.
5
4
  */
6
5
  export interface ReactPyClient {
7
6
  /**
8
- * Connect to the server and start receiving messages.
7
+ * Register a handler for a message type.
9
8
  *
10
- * Message handlers should be registered before calling this method in order to
11
- * garuntee that messages are not missed.
12
- */
13
- start: () => void;
14
- /**
15
- * Disconnect from the server and stop receiving messages.
9
+ * The first time this is called, the client will be considered ready.
10
+ *
11
+ * @param type The type of message to handle.
12
+ * @param handler The handler to call when a message of the given type is received.
13
+ * @returns A function to unregister the handler.
16
14
  */
17
- stop: () => void;
15
+ onMessage(type: string, handler: (message: any) => void): () => void;
18
16
  /**
19
- * Register a handler for a message type.
17
+ * Send a message to the server.
18
+ *
19
+ * @param message The message to send. Messages must have a `type` property.
20
20
  */
21
- onMessage: <M extends IncomingMessage>(type: M["type"], handler: (message: M) => void) => void;
21
+ sendMessage(message: any): void;
22
22
  /**
23
- * Send a message to the server.
23
+ * Load a module from the server.
24
+ * @param moduleName The name of the module to load.
25
+ * @returns A promise that resolves to the module.
24
26
  */
25
- sendMessage: (message: OutgoingMessage) => void;
27
+ loadModule(moduleName: string): Promise<ReactPyModule>;
28
+ }
29
+ export declare abstract class BaseReactPyClient implements ReactPyClient {
30
+ private readonly handlers;
31
+ protected readonly ready: Promise<void>;
32
+ private resolveReady;
33
+ constructor();
34
+ onMessage(type: string, handler: (message: any) => void): () => void;
35
+ abstract sendMessage(message: any): void;
36
+ abstract loadModule(moduleName: string): Promise<ReactPyModule>;
26
37
  /**
27
- * Dynamically load a module from the server.
38
+ * Handle an incoming message.
39
+ *
40
+ * This should be called by subclasses when a message is received.
41
+ *
42
+ * @param message The message to handle. The message must have a `type` property.
28
43
  */
29
- loadModule: (moduleName: string) => Promise<ReactPyModule>;
44
+ protected handleIncoming(message: any): void;
30
45
  }
31
46
  export type SimpleReactPyClientProps = {
32
47
  serverLocation?: LocationProps;
@@ -68,19 +83,12 @@ type ReconnectProps = {
68
83
  backoffRate?: number;
69
84
  intervalJitter?: number;
70
85
  };
71
- export declare class SimpleReactPyClient implements ReactPyClient {
72
- private resolveShouldOpen;
73
- private resolveShouldClose;
86
+ export declare class SimpleReactPyClient extends BaseReactPyClient implements ReactPyClient {
74
87
  private readonly urls;
75
- private readonly handlers;
76
88
  private readonly socket;
77
89
  constructor(props: SimpleReactPyClientProps);
78
- start(): void;
79
- stop(): void;
80
- onMessage<M extends IncomingMessage>(type: M["type"], handler: (message: M) => void): void;
81
- sendMessage(message: OutgoingMessage): void;
90
+ sendMessage(message: any): void;
82
91
  loadModule(moduleName: string): Promise<ReactPyModule>;
83
- private handleIncoming;
84
92
  }
85
93
  export {};
86
94
  //# sourceMappingURL=reactpy-client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"reactpy-client.d.ts","sourceRoot":"","sources":["../src/reactpy-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAG/C;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB;;OAEG;IACH,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB;;OAEG;IACH,SAAS,EAAE,CAAC,CAAC,SAAS,eAAe,EACnC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,EACf,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,IAAI,KAC1B,IAAI,CAAC;IACV;;OAEG;IACH,WAAW,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IAChD;;OAEG;IACH,UAAU,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;CAC5D;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,cAAc,CAAC,EAAE,aAAa,CAAC;IAC/B,gBAAgB,CAAC,EAAE,cAAc,CAAC;CACnC,CAAC;AAEF;;;;;;;;;GASG;AACH,KAAK,aAAa,GAAG;IACnB;;;;OAIG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,KAAK,cAAc,GAAG;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,qBAAa,mBAAoB,YAAW,aAAa;IACvD,OAAO,CAAC,iBAAiB,CAA2B;IACpD,OAAO,CAAC,kBAAkB,CAA2B;IACrD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAEvB;IACF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0B;gBAErC,KAAK,EAAE,wBAAwB;IAmC3C,KAAK,IAAI,IAAI;IAKb,IAAI,IAAI,IAAI;IAKZ,SAAS,CAAC,CAAC,SAAS,eAAe,EACjC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,EACf,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,IAAI,GAC5B,IAAI;IAIP,WAAW,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI;IAI3C,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAItD,OAAO,CAAC,cAAc;CAevB"}
1
+ {"version":3,"file":"reactpy-client.d.ts","sourceRoot":"","sources":["../src/reactpy-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAG/C;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;;;;OAQG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAErE;;;;OAIG;IACH,WAAW,CAAC,OAAO,EAAE,GAAG,GAAG,IAAI,CAAC;IAEhC;;;;OAIG;IACH,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CACxD;AAED,8BAAsB,iBAAkB,YAAW,aAAa;IAC9D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqD;IAC9E,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,OAAO,CAAC,YAAY,CAA6B;;IAOjD,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,GAAG,MAAM,IAAI;IAQpE,QAAQ,CAAC,WAAW,CAAC,OAAO,EAAE,GAAG,GAAG,IAAI;IACxC,QAAQ,CAAC,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAE/D;;;;;;OAMG;IACH,SAAS,CAAC,cAAc,CAAC,OAAO,EAAE,GAAG,GAAG,IAAI;CAe7C;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,cAAc,CAAC,EAAE,aAAa,CAAC;IAC/B,gBAAgB,CAAC,EAAE,cAAc,CAAC;CACnC,CAAC;AAEF;;;;;;;;;GASG;AACH,KAAK,aAAa,GAAG;IACnB;;;;OAIG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,KAAK,cAAc,GAAG;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,qBAAa,mBACX,SAAQ,iBACR,YAAW,aAAa;IAExB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0B;gBAErC,KAAK,EAAE,wBAAwB;IAmB3C,WAAW,CAAC,OAAO,EAAE,GAAG,GAAG,IAAI;IAI/B,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;CAGvD"}
@@ -1,68 +1,62 @@
1
1
  import logger from "./logger";
2
- export class SimpleReactPyClient {
3
- resolveShouldOpen;
4
- resolveShouldClose;
2
+ export class BaseReactPyClient {
3
+ handlers = {};
4
+ ready;
5
+ resolveReady;
6
+ constructor() {
7
+ this.resolveReady = () => { };
8
+ this.ready = new Promise((resolve) => (this.resolveReady = resolve));
9
+ }
10
+ onMessage(type, handler) {
11
+ (this.handlers[type] || (this.handlers[type] = [])).push(handler);
12
+ this.resolveReady(undefined);
13
+ return () => {
14
+ this.handlers[type] = this.handlers[type].filter((h) => h !== handler);
15
+ };
16
+ }
17
+ /**
18
+ * Handle an incoming message.
19
+ *
20
+ * This should be called by subclasses when a message is received.
21
+ *
22
+ * @param message The message to handle. The message must have a `type` property.
23
+ */
24
+ handleIncoming(message) {
25
+ if (!message.type) {
26
+ logger.warn("Received message without type", message);
27
+ return;
28
+ }
29
+ const messageHandlers = this.handlers[message.type];
30
+ if (!messageHandlers) {
31
+ logger.warn("Received message without handler", message);
32
+ return;
33
+ }
34
+ messageHandlers.forEach((h) => h(message));
35
+ }
36
+ }
37
+ export class SimpleReactPyClient extends BaseReactPyClient {
5
38
  urls;
6
- handlers;
7
39
  socket;
8
40
  constructor(props) {
9
- this.handlers = {
10
- "connection-open": [],
11
- "connection-close": [],
12
- "layout-update": [],
13
- };
41
+ super();
14
42
  this.urls = getServerUrls(props.serverLocation || {
15
43
  url: document.location.origin,
16
44
  route: document.location.pathname,
17
45
  query: document.location.search,
18
46
  });
19
- this.resolveShouldOpen = () => {
20
- throw new Error("Could not start client");
21
- };
22
- this.resolveShouldClose = () => {
23
- throw new Error("Could not stop client");
24
- };
25
- const shouldOpen = new Promise((r) => (this.resolveShouldOpen = r));
26
- const shouldClose = new Promise((r) => (this.resolveShouldClose = r));
27
- this.socket = startReconnectingWebSocket({
28
- shouldOpen,
29
- shouldClose,
47
+ this.socket = createReconnectingWebSocket({
48
+ readyPromise: this.ready,
30
49
  url: this.urls.stream,
31
- onOpen: () => this.handleIncoming({ type: "connection-open" }),
32
50
  onMessage: async ({ data }) => this.handleIncoming(JSON.parse(data)),
33
- onClose: () => this.handleIncoming({ type: "connection-close" }),
34
51
  ...props.reconnectOptions,
35
52
  });
36
53
  }
37
- start() {
38
- logger.log("starting client...");
39
- this.resolveShouldOpen(undefined);
40
- }
41
- stop() {
42
- logger.log("stopping client...");
43
- this.resolveShouldClose(undefined);
44
- }
45
- onMessage(type, handler) {
46
- this.handlers[type].push(handler);
47
- }
48
54
  sendMessage(message) {
49
55
  this.socket.current?.send(JSON.stringify(message));
50
56
  }
51
57
  loadModule(moduleName) {
52
58
  return import(`${this.urls.modules}/${moduleName}`);
53
59
  }
54
- handleIncoming(message) {
55
- if (!message.type) {
56
- logger.warn("Received message without type", message);
57
- return;
58
- }
59
- const messageHandlers = this.handlers[message.type];
60
- if (!messageHandlers) {
61
- logger.warn("Received message without handler", message);
62
- return;
63
- }
64
- messageHandlers.forEach((h) => h(message));
65
- }
66
60
  }
67
61
  function getServerUrls(props) {
68
62
  const base = new URL(`${props.url || document.location.origin}/_reactpy`);
@@ -73,12 +67,12 @@ function getServerUrls(props) {
73
67
  const stream = `${streamProtocol}://${base.host}${streamPath}${props.query}`;
74
68
  return { base, modules, assets, stream };
75
69
  }
76
- function startReconnectingWebSocket(props) {
70
+ function createReconnectingWebSocket(props) {
77
71
  const { maxInterval = 60000, maxRetries = 50, backoffRate = 1.1, intervalJitter = 0.1, } = props;
78
72
  const startInterval = 750;
79
73
  let retries = 0;
80
74
  let interval = startInterval;
81
- let closed = false;
75
+ const closed = false;
82
76
  let everConnected = false;
83
77
  const socket = {};
84
78
  const connect = () => {
@@ -91,7 +85,9 @@ function startReconnectingWebSocket(props) {
91
85
  logger.log("client connected");
92
86
  interval = startInterval;
93
87
  retries = 0;
94
- props.onOpen();
88
+ if (props.onOpen) {
89
+ props.onOpen();
90
+ }
95
91
  };
96
92
  socket.current.onmessage = props.onMessage;
97
93
  socket.current.onclose = () => {
@@ -100,7 +96,9 @@ function startReconnectingWebSocket(props) {
100
96
  return;
101
97
  }
102
98
  logger.log("client disconnected");
103
- props.onClose();
99
+ if (props.onClose) {
100
+ props.onClose();
101
+ }
104
102
  if (retries >= maxRetries) {
105
103
  return;
106
104
  }
@@ -111,11 +109,7 @@ function startReconnectingWebSocket(props) {
111
109
  retries++;
112
110
  };
113
111
  };
114
- props.shouldOpen.then(connect);
115
- props.shouldClose.then(() => {
116
- closed = true;
117
- socket.current?.close();
118
- });
112
+ props.readyPromise.then(() => logger.log("starting client...")).then(connect);
119
113
  return socket;
120
114
  }
121
115
  function nextInterval(currentInterval, backoffRate, maxInterval) {
@@ -131,3 +125,4 @@ function addJitter(interval, jitter) {
131
125
  function rtrim(text, trim) {
132
126
  return text.replace(new RegExp(`${trim}+$`), "");
133
127
  }
128
+ //# sourceMappingURL=reactpy-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reactpy-client.js","sourceRoot":"","sources":["../src/reactpy-client.ts"],"names":[],"mappings":"AACA,OAAO,MAAM,MAAM,UAAU,CAAC;AAgC9B,MAAM,OAAgB,iBAAiB;IACpB,QAAQ,GAAkD,EAAE,CAAC;IAC3D,KAAK,CAAgB;IAChC,YAAY,CAA6B;IAEjD;QACE,IAAI,CAAC,YAAY,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;QAC7B,IAAI,CAAC,KAAK,GAAG,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC;IACvE,CAAC;IAED,SAAS,CAAC,IAAY,EAAE,OAA+B;QACrD,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAClE,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;QAC7B,OAAO,GAAG,EAAE;YACV,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC;QACzE,CAAC,CAAC;IACJ,CAAC;IAKD;;;;;;OAMG;IACO,cAAc,CAAC,OAAY;QACnC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE;YACjB,MAAM,CAAC,IAAI,CAAC,+BAA+B,EAAE,OAAO,CAAC,CAAC;YACtD,OAAO;SACR;QAED,MAAM,eAAe,GACnB,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,CAAC,eAAe,EAAE;YACpB,MAAM,CAAC,IAAI,CAAC,kCAAkC,EAAE,OAAO,CAAC,CAAC;YACzD,OAAO;SACR;QAED,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAC7C,CAAC;CACF;AA6CD,MAAM,OAAO,mBACX,SAAQ,iBAAiB;IAGR,IAAI,CAAa;IACjB,MAAM,CAA0B;IAEjD,YAAY,KAA+B;QACzC,KAAK,EAAE,CAAC;QAER,IAAI,CAAC,IAAI,GAAG,aAAa,CACvB,KAAK,CAAC,cAAc,IAAI;YACtB,GAAG,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM;YAC7B,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,QAAQ;YACjC,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM;SAChC,CACF,CAAC;QAEF,IAAI,CAAC,MAAM,GAAG,2BAA2B,CAAC;YACxC,YAAY,EAAE,IAAI,CAAC,KAAK;YACxB,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM;YACrB,SAAS,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACpE,GAAG,KAAK,CAAC,gBAAgB;SAC1B,CAAC,CAAC;IACL,CAAC;IAED,WAAW,CAAC,OAAY;QACtB,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;IACrD,CAAC;IAED,UAAU,CAAC,UAAkB;QAC3B,OAAO,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,UAAU,EAAE,CAAC,CAAC;IACtD,CAAC;CACF;AASD,SAAS,aAAa,CAAC,KAAoB;IACzC,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,WAAW,CAAC,CAAC;IAC1E,MAAM,OAAO,GAAG,GAAG,IAAI,UAAU,CAAC;IAClC,MAAM,MAAM,GAAG,GAAG,IAAI,SAAS,CAAC;IAEhC,MAAM,cAAc,GAAG,KAAK,IAAI,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IACpE,MAAM,UAAU,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC,QAAQ,UAAU,KAAK,CAAC,KAAK,IAAI,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;IAC7E,MAAM,MAAM,GAAG,GAAG,cAAc,MAAM,IAAI,CAAC,IAAI,GAAG,UAAU,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;IAE7E,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC3C,CAAC;AAED,SAAS,2BAA2B,CAClC,KAMkB;IAElB,MAAM,EACJ,WAAW,GAAG,KAAK,EACnB,UAAU,GAAG,EAAE,EACf,WAAW,GAAG,GAAG,EACjB,cAAc,GAAG,GAAG,GACrB,GAAG,KAAK,CAAC;IAEV,MAAM,aAAa,GAAG,GAAG,CAAC;IAC1B,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,QAAQ,GAAG,aAAa,CAAC;IAC7B,MAAM,MAAM,GAAG,KAAK,CAAC;IACrB,IAAI,aAAa,GAAG,KAAK,CAAC;IAC1B,MAAM,MAAM,GAA4B,EAAE,CAAC;IAE3C,MAAM,OAAO,GAAG,GAAG,EAAE;QACnB,IAAI,MAAM,EAAE;YACV,OAAO;SACR;QACD,MAAM,CAAC,OAAO,GAAG,IAAI,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC1C,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,GAAG,EAAE;YAC3B,aAAa,GAAG,IAAI,CAAC;YACrB,MAAM,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;YAC/B,QAAQ,GAAG,aAAa,CAAC;YACzB,OAAO,GAAG,CAAC,CAAC;YACZ,IAAI,KAAK,CAAC,MAAM,EAAE;gBAChB,KAAK,CAAC,MAAM,EAAE,CAAC;aAChB;QACH,CAAC,CAAC;QACF,MAAM,CAAC,OAAO,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;QAC3C,MAAM,CAAC,OAAO,CAAC,OAAO,GAAG,GAAG,EAAE;YAC5B,IAAI,CAAC,aAAa,EAAE;gBAClB,MAAM,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;gBAChC,OAAO;aACR;YAED,MAAM,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;YAClC,IAAI,KAAK,CAAC,OAAO,EAAE;gBACjB,KAAK,CAAC,OAAO,EAAE,CAAC;aACjB;YAED,IAAI,OAAO,IAAI,UAAU,EAAE;gBACzB,OAAO;aACR;YAED,MAAM,YAAY,GAAG,SAAS,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;YACzD,MAAM,CAAC,GAAG,CACR,mBAAmB,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,aAAa,CACrE,CAAC;YACF,UAAU,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;YAClC,QAAQ,GAAG,YAAY,CAAC,QAAQ,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;YAC5D,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC;IACJ,CAAC,CAAC;IAEF,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAE9E,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,YAAY,CACnB,eAAuB,EACvB,WAAmB,EACnB,WAAmB;IAEnB,OAAO,IAAI,CAAC,GAAG,CACb,eAAe;QACb,oCAAoC;QACpC,WAAW;IACb,4BAA4B;IAC5B,WAAW,CACZ,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,QAAgB,EAAE,MAAc;IACjD,OAAO,QAAQ,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,MAAM,GAAG,QAAQ,GAAG,CAAC,GAAG,MAAM,GAAG,QAAQ,CAAC,CAAC;AAChF,CAAC;AAED,SAAS,KAAK,CAAC,IAAY,EAAE,IAAY;IACvC,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;AACnD,CAAC"}
@@ -98,8 +98,8 @@ export function createAttributes(model, client) {
98
98
  function createEventHandler(client, name, { target, preventDefault, stopPropagation }) {
99
99
  return [
100
100
  name,
101
- function () {
102
- const data = Array.from(arguments).map((value) => {
101
+ function (...args) {
102
+ const data = Array.from(args).map((value) => {
103
103
  if (!(typeof value === "object" && value.nativeEvent)) {
104
104
  return value;
105
105
  }
@@ -138,3 +138,4 @@ function snakeToCamel(str) {
138
138
  // see list of HTML attributes with dashes in them:
139
139
  // https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes#attribute_list
140
140
  const DASHED_HTML_ATTRS = ["accept_charset", "http_equiv"];
141
+ //# sourceMappingURL=reactpy-vdom.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reactpy-vdom.js","sourceRoot":"","sources":["../src/reactpy-vdom.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "license": "MIT",
7
7
  "name": "@reactpy/client",
8
8
  "type": "module",
9
- "version": "0.2.1",
9
+ "version": "0.3.1",
10
10
  "dependencies": {
11
11
  "event-to-object": "^0.1.2",
12
12
  "json-pointer": "^0.6.2"
@@ -15,7 +15,6 @@
15
15
  "@types/json-pointer": "^1.0.31",
16
16
  "@types/react": "^17.0",
17
17
  "@types/react-dom": "^17.0",
18
- "prettier": "^3.0.0-alpha.6",
19
18
  "typescript": "^4.9.5"
20
19
  },
21
20
  "peerDependencies": {
@@ -28,9 +27,7 @@
28
27
  },
29
28
  "scripts": {
30
29
  "build": "tsc -b",
31
- "format": "prettier --write .",
32
30
  "test": "npm run check:tests",
33
- "check:format": "prettier --check .",
34
31
  "check:tests": "echo 'no tests'",
35
32
  "check:types": "tsc --noEmit"
36
33
  }
@@ -11,7 +11,6 @@ import React, {
11
11
  } from "react";
12
12
  // @ts-ignore
13
13
  import { set as setJsonPointer } from "json-pointer";
14
- import { LayoutUpdateMessage } from "./messages";
15
14
  import {
16
15
  ReactPyVdom,
17
16
  ReactPyComponent,
@@ -28,21 +27,18 @@ export function Layout(props: { client: ReactPyClient }): JSX.Element {
28
27
  const currentModel: ReactPyVdom = useState({ tagName: "" })[0];
29
28
  const forceUpdate = useForceUpdate();
30
29
 
31
- useEffect(() => {
32
- props.client.onMessage<LayoutUpdateMessage>(
33
- "layout-update",
34
- ({ path, model }) => {
30
+ useEffect(
31
+ () =>
32
+ props.client.onMessage("layout-update", ({ path, model }) => {
35
33
  if (path === "") {
36
34
  Object.assign(currentModel, model);
37
35
  } else {
38
36
  setJsonPointer(currentModel, path, model);
39
37
  }
40
38
  forceUpdate();
41
- },
42
- );
43
- props.client.start();
44
- return () => props.client.stop();
45
- }, [currentModel, props.client]);
39
+ }),
40
+ [currentModel, props.client],
41
+ );
46
42
 
47
43
  return (
48
44
  <ClientContext.Provider value={props.client}>
@@ -140,7 +136,7 @@ function ScriptElement({ model }: { model: ReactPyVdom }) {
140
136
  }
141
137
  ref.current.appendChild(scriptElement);
142
138
  } else if (scriptContent) {
143
- let scriptResult = eval(scriptContent);
139
+ const scriptResult = eval(scriptContent);
144
140
  if (typeof scriptResult == "function") {
145
141
  return scriptResult();
146
142
  }
package/src/messages.ts CHANGED
@@ -1,17 +1,5 @@
1
1
  import { ReactPyVdom } from "./reactpy-vdom";
2
2
 
3
- export interface IMessage {
4
- type: string;
5
- }
6
-
7
- export type ConnectionOpenMessage = {
8
- type: "connection-open";
9
- };
10
-
11
- export type ConnectionCloseMessage = {
12
- type: "connection-close";
13
- };
14
-
15
3
  export type LayoutUpdateMessage = {
16
4
  type: "layout-update";
17
5
  path: string;
@@ -24,9 +12,6 @@ export type LayoutEventMessage = {
24
12
  data: any;
25
13
  };
26
14
 
27
- export type IncomingMessage =
28
- | LayoutUpdateMessage
29
- | ConnectionOpenMessage
30
- | ConnectionCloseMessage;
15
+ export type IncomingMessage = LayoutUpdateMessage;
31
16
  export type OutgoingMessage = LayoutEventMessage;
32
17
  export type Message = IncomingMessage | OutgoingMessage;
@@ -1,4 +1,3 @@
1
- import { OutgoingMessage, IncomingMessage } from "./messages";
2
1
  import { ReactPyModule } from "./reactpy-vdom";
3
2
  import logger from "./logger";
4
3
 
@@ -7,31 +6,74 @@ import logger from "./logger";
7
6
  */
8
7
  export interface ReactPyClient {
9
8
  /**
10
- * Connect to the server and start receiving messages.
9
+ * Register a handler for a message type.
11
10
  *
12
- * Message handlers should be registered before calling this method in order to
13
- * garuntee that messages are not missed.
14
- */
15
- start: () => void;
16
- /**
17
- * Disconnect from the server and stop receiving messages.
11
+ * The first time this is called, the client will be considered ready.
12
+ *
13
+ * @param type The type of message to handle.
14
+ * @param handler The handler to call when a message of the given type is received.
15
+ * @returns A function to unregister the handler.
18
16
  */
19
- stop: () => void;
17
+ onMessage(type: string, handler: (message: any) => void): () => void;
18
+
20
19
  /**
21
- * Register a handler for a message type.
20
+ * Send a message to the server.
21
+ *
22
+ * @param message The message to send. Messages must have a `type` property.
22
23
  */
23
- onMessage: <M extends IncomingMessage>(
24
- type: M["type"],
25
- handler: (message: M) => void,
26
- ) => void;
24
+ sendMessage(message: any): void;
25
+
27
26
  /**
28
- * Send a message to the server.
27
+ * Load a module from the server.
28
+ * @param moduleName The name of the module to load.
29
+ * @returns A promise that resolves to the module.
29
30
  */
30
- sendMessage: (message: OutgoingMessage) => void;
31
+ loadModule(moduleName: string): Promise<ReactPyModule>;
32
+ }
33
+
34
+ export abstract class BaseReactPyClient implements ReactPyClient {
35
+ private readonly handlers: { [key: string]: ((message: any) => void)[] } = {};
36
+ protected readonly ready: Promise<void>;
37
+ private resolveReady: (value: undefined) => void;
38
+
39
+ constructor() {
40
+ this.resolveReady = () => {};
41
+ this.ready = new Promise((resolve) => (this.resolveReady = resolve));
42
+ }
43
+
44
+ onMessage(type: string, handler: (message: any) => void): () => void {
45
+ (this.handlers[type] || (this.handlers[type] = [])).push(handler);
46
+ this.resolveReady(undefined);
47
+ return () => {
48
+ this.handlers[type] = this.handlers[type].filter((h) => h !== handler);
49
+ };
50
+ }
51
+
52
+ abstract sendMessage(message: any): void;
53
+ abstract loadModule(moduleName: string): Promise<ReactPyModule>;
54
+
31
55
  /**
32
- * Dynamically load a module from the server.
56
+ * Handle an incoming message.
57
+ *
58
+ * This should be called by subclasses when a message is received.
59
+ *
60
+ * @param message The message to handle. The message must have a `type` property.
33
61
  */
34
- loadModule: (moduleName: string) => Promise<ReactPyModule>;
62
+ protected handleIncoming(message: any): void {
63
+ if (!message.type) {
64
+ logger.warn("Received message without type", message);
65
+ return;
66
+ }
67
+
68
+ const messageHandlers: ((m: any) => void)[] | undefined =
69
+ this.handlers[message.type];
70
+ if (!messageHandlers) {
71
+ logger.warn("Received message without handler", message);
72
+ return;
73
+ }
74
+
75
+ messageHandlers.forEach((h) => h(message));
76
+ }
35
77
  }
36
78
 
37
79
  export type SimpleReactPyClientProps = {
@@ -77,21 +119,15 @@ type ReconnectProps = {
77
119
  intervalJitter?: number;
78
120
  };
79
121
 
80
- export class SimpleReactPyClient implements ReactPyClient {
81
- private resolveShouldOpen: (value: unknown) => void;
82
- private resolveShouldClose: (value: unknown) => void;
122
+ export class SimpleReactPyClient
123
+ extends BaseReactPyClient
124
+ implements ReactPyClient
125
+ {
83
126
  private readonly urls: ServerUrls;
84
- private readonly handlers: {
85
- [key in IncomingMessage["type"]]: ((message: any) => void)[];
86
- };
87
127
  private readonly socket: { current?: WebSocket };
88
128
 
89
129
  constructor(props: SimpleReactPyClientProps) {
90
- this.handlers = {
91
- "connection-open": [],
92
- "connection-close": [],
93
- "layout-update": [],
94
- };
130
+ super();
95
131
 
96
132
  this.urls = getServerUrls(
97
133
  props.serverLocation || {
@@ -101,66 +137,21 @@ export class SimpleReactPyClient implements ReactPyClient {
101
137
  },
102
138
  );
103
139
 
104
- this.resolveShouldOpen = () => {
105
- throw new Error("Could not start client");
106
- };
107
- this.resolveShouldClose = () => {
108
- throw new Error("Could not stop client");
109
- };
110
- const shouldOpen = new Promise((r) => (this.resolveShouldOpen = r));
111
- const shouldClose = new Promise((r) => (this.resolveShouldClose = r));
112
-
113
- this.socket = startReconnectingWebSocket({
114
- shouldOpen,
115
- shouldClose,
140
+ this.socket = createReconnectingWebSocket({
141
+ readyPromise: this.ready,
116
142
  url: this.urls.stream,
117
- onOpen: () => this.handleIncoming({ type: "connection-open" }),
118
143
  onMessage: async ({ data }) => this.handleIncoming(JSON.parse(data)),
119
- onClose: () => this.handleIncoming({ type: "connection-close" }),
120
144
  ...props.reconnectOptions,
121
145
  });
122
146
  }
123
147
 
124
- start(): void {
125
- logger.log("starting client...");
126
- this.resolveShouldOpen(undefined);
127
- }
128
-
129
- stop(): void {
130
- logger.log("stopping client...");
131
- this.resolveShouldClose(undefined);
132
- }
133
-
134
- onMessage<M extends IncomingMessage>(
135
- type: M["type"],
136
- handler: (message: M) => void,
137
- ): void {
138
- this.handlers[type].push(handler);
139
- }
140
-
141
- sendMessage(message: OutgoingMessage): void {
148
+ sendMessage(message: any): void {
142
149
  this.socket.current?.send(JSON.stringify(message));
143
150
  }
144
151
 
145
152
  loadModule(moduleName: string): Promise<ReactPyModule> {
146
153
  return import(`${this.urls.modules}/${moduleName}`);
147
154
  }
148
-
149
- private handleIncoming(message: IncomingMessage): void {
150
- if (!message.type) {
151
- logger.warn("Received message without type", message);
152
- return;
153
- }
154
-
155
- const messageHandlers: ((m: any) => void)[] | undefined =
156
- this.handlers[message.type];
157
- if (!messageHandlers) {
158
- logger.warn("Received message without handler", message);
159
- return;
160
- }
161
-
162
- messageHandlers.forEach((h) => h(message));
163
- }
164
155
  }
165
156
 
166
157
  type ServerUrls = {
@@ -182,14 +173,13 @@ function getServerUrls(props: LocationProps): ServerUrls {
182
173
  return { base, modules, assets, stream };
183
174
  }
184
175
 
185
- function startReconnectingWebSocket(
176
+ function createReconnectingWebSocket(
186
177
  props: {
187
- shouldOpen: Promise<any>;
188
- shouldClose: Promise<any>;
189
178
  url: string;
190
- onOpen: () => void;
179
+ readyPromise: Promise<void>;
180
+ onOpen?: () => void;
191
181
  onMessage: (message: MessageEvent<any>) => void;
192
- onClose: () => void;
182
+ onClose?: () => void;
193
183
  } & ReconnectProps,
194
184
  ) {
195
185
  const {
@@ -202,7 +192,7 @@ function startReconnectingWebSocket(
202
192
  const startInterval = 750;
203
193
  let retries = 0;
204
194
  let interval = startInterval;
205
- let closed = false;
195
+ const closed = false;
206
196
  let everConnected = false;
207
197
  const socket: { current?: WebSocket } = {};
208
198
 
@@ -216,7 +206,9 @@ function startReconnectingWebSocket(
216
206
  logger.log("client connected");
217
207
  interval = startInterval;
218
208
  retries = 0;
219
- props.onOpen();
209
+ if (props.onOpen) {
210
+ props.onOpen();
211
+ }
220
212
  };
221
213
  socket.current.onmessage = props.onMessage;
222
214
  socket.current.onclose = () => {
@@ -226,7 +218,9 @@ function startReconnectingWebSocket(
226
218
  }
227
219
 
228
220
  logger.log("client disconnected");
229
- props.onClose();
221
+ if (props.onClose) {
222
+ props.onClose();
223
+ }
230
224
 
231
225
  if (retries >= maxRetries) {
232
226
  return;
@@ -242,11 +236,7 @@ function startReconnectingWebSocket(
242
236
  };
243
237
  };
244
238
 
245
- props.shouldOpen.then(connect);
246
- props.shouldClose.then(() => {
247
- closed = true;
248
- socket.current?.close();
249
- });
239
+ props.readyPromise.then(() => logger.log("starting client...")).then(connect);
250
240
 
251
241
  return socket;
252
242
  }
@@ -155,8 +155,8 @@ function createEventHandler(
155
155
  ): [string, () => void] {
156
156
  return [
157
157
  name,
158
- function () {
159
- const data = Array.from(arguments).map((value) => {
158
+ function (...args: any[]) {
159
+ const data = Array.from(args).map((value) => {
160
160
  if (!(typeof value === "object" && value.nativeEvent)) {
161
161
  return value;
162
162
  }