@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 +40 -2
- package/dist/index.d.mts +41 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +117 -0
- package/dist/index.mjs +93 -0
- package/package.json +52 -3
package/README.md
CHANGED
|
@@ -1,3 +1,41 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @wireflowapp/react-websocket
|
|
2
2
|
|
|
3
|
-
|
|
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
|
+
```
|
package/dist/index.d.mts
ADDED
|
@@ -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.d.ts
ADDED
|
@@ -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": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
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
|
}
|