@wireflowapp/react-websocket 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,41 @@
1
- # Temporary Holding Version
1
+ # @wireflowapp/react-websocket
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ React hook adapter for native WebSocket connection management in **Wireflow**.
4
+
5
+ ## Features
6
+
7
+ - **Reactive Status**: Exposes `"Idle" | "Connecting" | "Connected" | "Failed"` as React state.
8
+ - **Reference-Stable**: Prevents infinite reconnect loops from inline option objects and callback functions.
9
+ - **Strict Mode Ready**: Supports React 18+ double mounting and fast refresh without leaking resources.
10
+ - **Next.js & SSR Friendly**: Ships with `"use client"` directive.
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ pnpm add @wireflowapp/react-websocket @wireflowapp/websocket-core @wireflowapp/core
16
+ ```
17
+
18
+ ## Quick Start
19
+
20
+ ```tsx
21
+ import { useWebSocket } from "@wireflowapp/react-websocket";
22
+
23
+ export function ChatComponent() {
24
+ const { status, connect, retry, disconnect, send } = useWebSocket("wss://example.com/ws", {
25
+ retryAttempts: 5,
26
+ retryDelay: 3000,
27
+ onMessage: (event) => {
28
+ console.log("Message received:", event.data);
29
+ },
30
+ });
31
+
32
+ return (
33
+ <div>
34
+ <div>Status: {status}</div>
35
+ <button onClick={() => send("Ping")}>Send</button>
36
+ <button onClick={disconnect}>Disconnect</button>
37
+ <button onClick={retry}>Retry</button>
38
+ </div>
39
+ );
40
+ }
41
+ ```
@@ -0,0 +1,41 @@
1
+ import { ConnectionStatus } from '@wireflowapp/core';
2
+ import { WebSocketOptions, WebSocketDataType, WebSocketClient } from '@wireflowapp/websocket-core';
3
+
4
+ interface UseWebSocketOptions extends WebSocketOptions {
5
+ }
6
+ interface UseWebSocketResult {
7
+ /**
8
+ * Current connection status.
9
+ */
10
+ readonly status: ConnectionStatus;
11
+ /**
12
+ * Initiates connection to the WebSocket server.
13
+ */
14
+ connect: () => void;
15
+ /**
16
+ * Manually retries connection if currently idle or failed.
17
+ */
18
+ retry: () => void;
19
+ /**
20
+ * Disconnects the active socket connection and cancels retry timers.
21
+ */
22
+ disconnect: () => void;
23
+ /**
24
+ * Transmits data through the active WebSocket connection.
25
+ */
26
+ send: (data: WebSocketDataType) => boolean;
27
+ /**
28
+ * The underlying WebSocketClient instance.
29
+ */
30
+ client: WebSocketClient | null;
31
+ }
32
+
33
+ /**
34
+ * React hook providing reactive connection state and controls over a native WebSocket connection.
35
+ *
36
+ * @param url The WebSocket server URL to connect to.
37
+ * @param options Optional configuration parameters and lifecycle event handlers.
38
+ */
39
+ declare function useWebSocket(url: string, options?: UseWebSocketOptions): UseWebSocketResult;
40
+
41
+ export { type UseWebSocketOptions, type UseWebSocketResult, useWebSocket };
@@ -0,0 +1,41 @@
1
+ import { ConnectionStatus } from '@wireflowapp/core';
2
+ import { WebSocketOptions, WebSocketDataType, WebSocketClient } from '@wireflowapp/websocket-core';
3
+
4
+ interface UseWebSocketOptions extends WebSocketOptions {
5
+ }
6
+ interface UseWebSocketResult {
7
+ /**
8
+ * Current connection status.
9
+ */
10
+ readonly status: ConnectionStatus;
11
+ /**
12
+ * Initiates connection to the WebSocket server.
13
+ */
14
+ connect: () => void;
15
+ /**
16
+ * Manually retries connection if currently idle or failed.
17
+ */
18
+ retry: () => void;
19
+ /**
20
+ * Disconnects the active socket connection and cancels retry timers.
21
+ */
22
+ disconnect: () => void;
23
+ /**
24
+ * Transmits data through the active WebSocket connection.
25
+ */
26
+ send: (data: WebSocketDataType) => boolean;
27
+ /**
28
+ * The underlying WebSocketClient instance.
29
+ */
30
+ client: WebSocketClient | null;
31
+ }
32
+
33
+ /**
34
+ * React hook providing reactive connection state and controls over a native WebSocket connection.
35
+ *
36
+ * @param url The WebSocket server URL to connect to.
37
+ * @param options Optional configuration parameters and lifecycle event handlers.
38
+ */
39
+ declare function useWebSocket(url: string, options?: UseWebSocketOptions): UseWebSocketResult;
40
+
41
+ export { type UseWebSocketOptions, type UseWebSocketResult, useWebSocket };
package/dist/index.js ADDED
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ "use client";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/index.ts
22
+ var index_exports = {};
23
+ __export(index_exports, {
24
+ useWebSocket: () => useWebSocket
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+
28
+ // src/hooks/useWebSocket.ts
29
+ var import_react = require("react");
30
+ var import_websocket_core = require("@wireflowapp/websocket-core");
31
+ function useWebSocket(url, options = {}) {
32
+ const [status, setStatus] = (0, import_react.useState)("Idle");
33
+ const clientRef = (0, import_react.useRef)(null);
34
+ const callbacksRef = (0, import_react.useRef)({
35
+ onOpen: options.onOpen,
36
+ onClose: options.onClose,
37
+ onError: options.onError,
38
+ onMessage: options.onMessage,
39
+ onStatusChange: options.onStatusChange
40
+ });
41
+ callbacksRef.current = {
42
+ onOpen: options.onOpen,
43
+ onClose: options.onClose,
44
+ onError: options.onError,
45
+ onMessage: options.onMessage,
46
+ onStatusChange: options.onStatusChange
47
+ };
48
+ const protocolsSerialized = Array.isArray(options.protocols) ? options.protocols.join(",") : options.protocols;
49
+ const retryAttempts = options.retryAttempts;
50
+ const retryDelay = options.retryDelay;
51
+ const autoConnect = options.autoConnect;
52
+ const retryOnDisconnect = options.retryOnDisconnect;
53
+ const binaryType = options.binaryType;
54
+ (0, import_react.useEffect)(() => {
55
+ if (typeof window === "undefined" && typeof WebSocket === "undefined") {
56
+ return;
57
+ }
58
+ const clientOptions = {
59
+ protocols: options.protocols,
60
+ binaryType,
61
+ retryAttempts,
62
+ retryDelay,
63
+ autoConnect: autoConnect ?? true,
64
+ retryOnDisconnect: retryOnDisconnect ?? true,
65
+ onOpen: (e) => callbacksRef.current.onOpen?.(e),
66
+ onClose: (e) => callbacksRef.current.onClose?.(e),
67
+ onError: (e) => callbacksRef.current.onError?.(e),
68
+ onMessage: (e) => callbacksRef.current.onMessage?.(e),
69
+ onStatusChange: (newStatus) => {
70
+ setStatus(newStatus);
71
+ callbacksRef.current.onStatusChange?.(newStatus);
72
+ }
73
+ };
74
+ const client = new import_websocket_core.WebSocketClient(url, clientOptions);
75
+ clientRef.current = client;
76
+ setStatus(client.status);
77
+ return () => {
78
+ client.dispose();
79
+ clientRef.current = null;
80
+ };
81
+ }, [
82
+ url,
83
+ protocolsSerialized,
84
+ binaryType,
85
+ retryAttempts,
86
+ retryDelay,
87
+ autoConnect,
88
+ retryOnDisconnect
89
+ ]);
90
+ const connect = (0, import_react.useCallback)(() => {
91
+ clientRef.current?.connect();
92
+ }, []);
93
+ const retry = (0, import_react.useCallback)(() => {
94
+ clientRef.current?.retry();
95
+ }, []);
96
+ const disconnect = (0, import_react.useCallback)(() => {
97
+ clientRef.current?.disconnect();
98
+ }, []);
99
+ const send = (0, import_react.useCallback)((data) => {
100
+ return clientRef.current?.send(data) ?? false;
101
+ }, []);
102
+ return (0, import_react.useMemo)(
103
+ () => ({
104
+ status,
105
+ connect,
106
+ retry,
107
+ disconnect,
108
+ send,
109
+ client: clientRef.current
110
+ }),
111
+ [status, connect, retry, disconnect, send]
112
+ );
113
+ }
114
+ // Annotate the CommonJS export names for ESM import in node:
115
+ 0 && (module.exports = {
116
+ useWebSocket
117
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,93 @@
1
+ "use client";
2
+
3
+ // src/hooks/useWebSocket.ts
4
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
5
+ import {
6
+ WebSocketClient
7
+ } from "@wireflowapp/websocket-core";
8
+ function useWebSocket(url, options = {}) {
9
+ const [status, setStatus] = useState("Idle");
10
+ const clientRef = useRef(null);
11
+ const callbacksRef = useRef({
12
+ onOpen: options.onOpen,
13
+ onClose: options.onClose,
14
+ onError: options.onError,
15
+ onMessage: options.onMessage,
16
+ onStatusChange: options.onStatusChange
17
+ });
18
+ callbacksRef.current = {
19
+ onOpen: options.onOpen,
20
+ onClose: options.onClose,
21
+ onError: options.onError,
22
+ onMessage: options.onMessage,
23
+ onStatusChange: options.onStatusChange
24
+ };
25
+ const protocolsSerialized = Array.isArray(options.protocols) ? options.protocols.join(",") : options.protocols;
26
+ const retryAttempts = options.retryAttempts;
27
+ const retryDelay = options.retryDelay;
28
+ const autoConnect = options.autoConnect;
29
+ const retryOnDisconnect = options.retryOnDisconnect;
30
+ const binaryType = options.binaryType;
31
+ useEffect(() => {
32
+ if (typeof window === "undefined" && typeof WebSocket === "undefined") {
33
+ return;
34
+ }
35
+ const clientOptions = {
36
+ protocols: options.protocols,
37
+ binaryType,
38
+ retryAttempts,
39
+ retryDelay,
40
+ autoConnect: autoConnect ?? true,
41
+ retryOnDisconnect: retryOnDisconnect ?? true,
42
+ onOpen: (e) => callbacksRef.current.onOpen?.(e),
43
+ onClose: (e) => callbacksRef.current.onClose?.(e),
44
+ onError: (e) => callbacksRef.current.onError?.(e),
45
+ onMessage: (e) => callbacksRef.current.onMessage?.(e),
46
+ onStatusChange: (newStatus) => {
47
+ setStatus(newStatus);
48
+ callbacksRef.current.onStatusChange?.(newStatus);
49
+ }
50
+ };
51
+ const client = new WebSocketClient(url, clientOptions);
52
+ clientRef.current = client;
53
+ setStatus(client.status);
54
+ return () => {
55
+ client.dispose();
56
+ clientRef.current = null;
57
+ };
58
+ }, [
59
+ url,
60
+ protocolsSerialized,
61
+ binaryType,
62
+ retryAttempts,
63
+ retryDelay,
64
+ autoConnect,
65
+ retryOnDisconnect
66
+ ]);
67
+ const connect = useCallback(() => {
68
+ clientRef.current?.connect();
69
+ }, []);
70
+ const retry = useCallback(() => {
71
+ clientRef.current?.retry();
72
+ }, []);
73
+ const disconnect = useCallback(() => {
74
+ clientRef.current?.disconnect();
75
+ }, []);
76
+ const send = useCallback((data) => {
77
+ return clientRef.current?.send(data) ?? false;
78
+ }, []);
79
+ return useMemo(
80
+ () => ({
81
+ status,
82
+ connect,
83
+ retry,
84
+ disconnect,
85
+ send,
86
+ client: clientRef.current
87
+ }),
88
+ [status, connect, retry, disconnect, send]
89
+ );
90
+ }
91
+ export {
92
+ useWebSocket
93
+ };
package/package.json CHANGED
@@ -1,6 +1,55 @@
1
1
  {
2
2
  "name": "@wireflowapp/react-websocket",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "1.0.0",
4
+ "description": "React hook adapter for native WebSocket connection management with Wireflow",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": {
11
+ "types": "./dist/index.d.mts",
12
+ "default": "./dist/index.mjs"
13
+ },
14
+ "require": {
15
+ "types": "./dist/index.d.ts",
16
+ "default": "./dist/index.js"
17
+ }
18
+ }
19
+ },
20
+ "sideEffects": false,
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "files": [
25
+ "dist"
26
+ ],
27
+ "peerDependencies": {
28
+ "react": ">=18.0.0"
29
+ },
30
+ "dependencies": {
31
+ "@wireflowapp/core": "1.0.0",
32
+ "@wireflowapp/websocket-core": "1.0.0"
33
+ },
34
+ "devDependencies": {
35
+ "@testing-library/react": "^16.1.0",
36
+ "@types/react": "^18.3.18",
37
+ "@types/react-dom": "^18.3.5",
38
+ "react": "^18.3.1",
39
+ "react-dom": "^18.3.1"
40
+ },
41
+ "keywords": [
42
+ "react",
43
+ "hooks",
44
+ "websocket",
45
+ "wireflow",
46
+ "real-time"
47
+ ],
48
+ "author": "",
49
+ "license": "MIT",
50
+ "scripts": {
51
+ "build": "tsup src/index.ts --format esm,cjs --dts --clean",
52
+ "typecheck": "tsc --noEmit",
53
+ "test": "vitest run"
54
+ }
6
55
  }