redux-cluster-ws 2.0.1 → 2.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.
Files changed (40) hide show
  1. package/dist/cjs/client.js +0 -1
  2. package/dist/cjs/index.js +0 -1
  3. package/dist/cjs/server.js +0 -1
  4. package/dist/cjs/types.js +0 -1
  5. package/dist/cjs/utils.js +0 -1
  6. package/dist/esm/client.js +126 -141
  7. package/dist/esm/index.js +0 -1
  8. package/dist/esm/server.js +252 -263
  9. package/dist/esm/types.js +0 -1
  10. package/dist/esm/utils.js +0 -1
  11. package/package.json +22 -14
  12. package/FUNDING.yml +0 -7
  13. package/dist/cjs/client.js.map +0 -1
  14. package/dist/cjs/index.js.map +0 -1
  15. package/dist/cjs/server.js.map +0 -1
  16. package/dist/cjs/types.js.map +0 -1
  17. package/dist/cjs/utils.js.map +0 -1
  18. package/dist/esm/client.d.ts +0 -43
  19. package/dist/esm/client.js.map +0 -1
  20. package/dist/esm/index.d.ts +0 -4
  21. package/dist/esm/index.js.map +0 -1
  22. package/dist/esm/server.d.ts +0 -31
  23. package/dist/esm/server.js.map +0 -1
  24. package/dist/esm/types.d.ts +0 -83
  25. package/dist/esm/types.js.map +0 -1
  26. package/dist/esm/utils.d.ts +0 -17
  27. package/dist/esm/utils.js.map +0 -1
  28. package/eslint.config.js +0 -143
  29. package/examples/browser-example.cjs +0 -350
  30. package/examples/browser.html +0 -255
  31. package/examples/client.cjs +0 -155
  32. package/examples/cross-library-browser.html +0 -655
  33. package/examples/cross-library-client.cjs +0 -190
  34. package/examples/cross-library-server.cjs +0 -213
  35. package/examples/server.cjs +0 -96
  36. /package/dist/{cjs → types}/client.d.ts +0 -0
  37. /package/dist/{cjs → types}/index.d.ts +0 -0
  38. /package/dist/{cjs → types}/server.d.ts +0 -0
  39. /package/dist/{cjs → types}/types.d.ts +0 -0
  40. /package/dist/{cjs → types}/utils.d.ts +0 -0
@@ -1,350 +0,0 @@
1
- /**
2
- * Redux-Cluster-WS Browser Example JavaScript
3
- *
4
- * This script demonstrates how to use redux-cluster-ws in a browser environment.
5
- * It creates a simple counter application that synchronizes with a WebSocket server.
6
- */
7
-
8
- // Store instance
9
- let store = null;
10
- let wsClient = null;
11
-
12
- // Simple Redux implementation for browser (minimal version)
13
- function createSimpleRedux(reducer) {
14
- let state = reducer(undefined, {});
15
- let listeners = [];
16
-
17
- return {
18
- getState: () => state,
19
- dispatch: (action) => {
20
- state = reducer(state, action);
21
- listeners.forEach((listener) => listener());
22
- return action;
23
- },
24
- subscribe: (listener) => {
25
- listeners.push(listener);
26
- return () => {
27
- listeners = listeners.filter((l) => l !== listener);
28
- };
29
- },
30
- };
31
- }
32
-
33
- // Counter reducer (same as server)
34
- function counterReducer(state = { count: 0, lastUpdate: null }, action) {
35
- switch (action.type) {
36
- case "INCREMENT":
37
- return {
38
- count: state.count + 1,
39
- lastUpdate: new Date().toISOString(),
40
- };
41
-
42
- case "DECREMENT":
43
- return {
44
- count: state.count - 1,
45
- lastUpdate: new Date().toISOString(),
46
- };
47
-
48
- case "RESET":
49
- return {
50
- count: 0,
51
- lastUpdate: new Date().toISOString(),
52
- };
53
-
54
- default:
55
- return state;
56
- }
57
- }
58
-
59
- // Simple hash function (simplified version of redux-cluster-ws hasher)
60
- function simpleHash(str) {
61
- let hash = 0;
62
- for (let i = 0; i < str.length; i++) {
63
- const char = str.charCodeAt(i);
64
- hash = (hash << 5) - hash + char;
65
- hash = hash & hash;
66
- }
67
- return hash.toString(16);
68
- }
69
-
70
- // WebSocket Client implementation
71
- class BrowserWSClient {
72
- constructor(store, config) {
73
- this.store = store;
74
- this.config = config;
75
- this.authenticated = false;
76
- this.login = simpleHash(`REDUX_CLUSTER${config.login}`);
77
- this.password = simpleHash(`REDUX_CLUSTER${config.password}`);
78
- this.originalDispatch = store.dispatch;
79
-
80
- // Override store dispatch
81
- this.store.dispatch = this.dispatch.bind(this);
82
- this.store.connected = false;
83
- this.store.RCHash = "browser-example-hash";
84
- }
85
-
86
- connect() {
87
- const url = `${this.config.host}:${this.config.port}/redux-cluster-${this.store.RCHash}`;
88
- log(`Connecting to: ${url}`, "info");
89
-
90
- try {
91
- this.ws = new WebSocket(url);
92
-
93
- this.ws.onopen = () => {
94
- log("WebSocket connected", "success");
95
- this.sendMessage({
96
- _msg: "REDUX_CLUSTER_SOCKET_AUTH",
97
- _hash: this.store.RCHash,
98
- _login: this.login,
99
- _password: this.password,
100
- });
101
- };
102
-
103
- this.ws.onmessage = (event) => {
104
- try {
105
- const message = JSON.parse(event.data);
106
- this.handleMessage(message);
107
- } catch (error) {
108
- log(`Message parse error: ${error.message}`, "error");
109
- }
110
- };
111
-
112
- this.ws.onclose = () => {
113
- log("WebSocket disconnected", "warning");
114
- this.authenticated = false;
115
- this.store.connected = false;
116
- updateUI();
117
- };
118
-
119
- this.ws.onerror = (error) => {
120
- log(`WebSocket error: ${error}`, "error");
121
- this.authenticated = false;
122
- this.store.connected = false;
123
- updateUI();
124
- };
125
- } catch (error) {
126
- log(`Connection error: ${error.message}`, "error");
127
- this.store.connected = false;
128
- updateUI();
129
- }
130
- }
131
-
132
- handleMessage(message) {
133
- if (message._hash !== this.store.RCHash) {
134
- return;
135
- }
136
-
137
- switch (message._msg) {
138
- case "REDUX_CLUSTER_MSGTOWORKER":
139
- if (message._action) {
140
- log(`Received action: ${message._action.type}`, "info");
141
- this.originalDispatch(message._action);
142
- }
143
- break;
144
-
145
- case "REDUX_CLUSTER_SOCKET_AUTHSTATE":
146
- if (message._value === true) {
147
- this.authenticated = true;
148
- this.store.connected = true;
149
- log("Authentication successful", "success");
150
- updateUI();
151
-
152
- // Request initial sync
153
- this.sendMessage({
154
- _msg: "REDUX_CLUSTER_START",
155
- _hash: this.store.RCHash,
156
- });
157
- } else {
158
- this.authenticated = false;
159
- this.store.connected = false;
160
-
161
- if (message._banned) {
162
- log("Authentication failed: IP banned", "error");
163
- } else {
164
- log("Authentication failed: Invalid credentials", "error");
165
- }
166
- updateUI();
167
- }
168
- break;
169
- }
170
- }
171
-
172
- dispatch(action) {
173
- try {
174
- if (
175
- this.ws &&
176
- this.ws.readyState === WebSocket.OPEN &&
177
- this.authenticated
178
- ) {
179
- log(`Sending action: ${action.type}`, "info");
180
- this.sendMessage({
181
- _msg: "REDUX_CLUSTER_MSGTOMASTER",
182
- _hash: this.store.RCHash,
183
- _action: action,
184
- });
185
- } else {
186
- log("Cannot dispatch: not connected or not authenticated", "warning");
187
- }
188
- } catch (error) {
189
- log(`Dispatch error: ${error.message}`, "error");
190
- }
191
- return action;
192
- }
193
-
194
- sendMessage(message) {
195
- if (this.ws && this.ws.readyState === WebSocket.OPEN) {
196
- this.ws.send(JSON.stringify(message));
197
- }
198
- }
199
-
200
- disconnect() {
201
- if (this.ws) {
202
- this.ws.close();
203
- }
204
- this.store.dispatch = this.originalDispatch;
205
- }
206
- }
207
-
208
- // Logging function
209
- function log(message, type = "info") {
210
- const logEl = document.getElementById("log");
211
- const timestamp = new Date().toLocaleTimeString();
212
- const entry = document.createElement("div");
213
- entry.className = `log-entry log-${type}`;
214
- entry.textContent = `[${timestamp}] ${message}`;
215
-
216
- logEl.appendChild(entry);
217
- logEl.scrollTop = logEl.scrollHeight;
218
-
219
- // Keep only last 50 entries
220
- while (logEl.children.length > 50) {
221
- logEl.removeChild(logEl.firstChild);
222
- }
223
- }
224
-
225
- // UI update function
226
- function updateUI() {
227
- const statusEl = document.getElementById("status");
228
- const connectBtn = document.getElementById("connectBtn");
229
- const counterEl = document.getElementById("counterValue");
230
- const lastUpdateEl = document.getElementById("lastUpdate");
231
- const buttons = ["incBtn", "decBtn", "resetBtn"];
232
-
233
- if (store && store.connected) {
234
- statusEl.textContent = "Connected";
235
- statusEl.className = "status connected";
236
- connectBtn.textContent = "Disconnect";
237
-
238
- // Enable action buttons
239
- buttons.forEach((id) => {
240
- document.getElementById(id).disabled = false;
241
- });
242
-
243
- // Update counter display
244
- const state = store.getState();
245
- counterEl.textContent = state.count;
246
- lastUpdateEl.textContent = state.lastUpdate
247
- ? `Last updated: ${new Date(state.lastUpdate).toLocaleString()}`
248
- : "Never updated";
249
- } else if (store) {
250
- statusEl.textContent = "Connecting...";
251
- statusEl.className = "status connecting";
252
- connectBtn.textContent = "Cancel";
253
-
254
- // Disable action buttons
255
- buttons.forEach((id) => {
256
- document.getElementById(id).disabled = true;
257
- });
258
- } else {
259
- statusEl.textContent = "Disconnected";
260
- statusEl.className = "status disconnected";
261
- connectBtn.textContent = "Connect";
262
-
263
- // Disable action buttons
264
- buttons.forEach((id) => {
265
- document.getElementById(id).disabled = true;
266
- });
267
-
268
- counterEl.textContent = "0";
269
- lastUpdateEl.textContent = "Never updated";
270
- }
271
- }
272
-
273
- // Connection toggle function
274
- function toggleConnection() {
275
- if (store && store.connected) {
276
- // Disconnect
277
- log("Disconnecting...", "info");
278
- if (wsClient) {
279
- wsClient.disconnect();
280
- }
281
- store = null;
282
- wsClient = null;
283
- updateUI();
284
- } else if (store && !store.connected) {
285
- // Cancel connection attempt
286
- if (wsClient) {
287
- wsClient.disconnect();
288
- }
289
- store = null;
290
- wsClient = null;
291
- updateUI();
292
- } else {
293
- // Connect
294
- const host = document.getElementById("host").value.trim();
295
- const port = document.getElementById("port").value.trim();
296
- const login = document.getElementById("login").value.trim();
297
- const password = document.getElementById("password").value.trim();
298
-
299
- if (!host || !port || !login || !password) {
300
- log("Please fill in all connection fields", "error");
301
- return;
302
- }
303
-
304
- log("Creating store and connecting...", "info");
305
-
306
- // Create store
307
- store = createSimpleRedux(counterReducer);
308
-
309
- // Subscribe to state changes
310
- store.subscribe(() => {
311
- updateUI();
312
- });
313
-
314
- // Create WebSocket client
315
- wsClient = new BrowserWSClient(store, {
316
- host: host,
317
- port: parseInt(port),
318
- login: login,
319
- password: password,
320
- });
321
-
322
- updateUI();
323
- wsClient.connect();
324
- }
325
- }
326
-
327
- // Action functions
328
- function increment() {
329
- if (store && store.connected) {
330
- store.dispatch({ type: "INCREMENT" });
331
- }
332
- }
333
-
334
- function decrement() {
335
- if (store && store.connected) {
336
- store.dispatch({ type: "DECREMENT" });
337
- }
338
- }
339
-
340
- function reset() {
341
- if (store && store.connected) {
342
- store.dispatch({ type: "RESET" });
343
- }
344
- }
345
-
346
- // Initialize UI on page load
347
- document.addEventListener("DOMContentLoaded", () => {
348
- log("Browser example loaded", "success");
349
- updateUI();
350
- });
@@ -1,255 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>Redux-Cluster-WS Browser Example</title>
7
- <style>
8
- body {
9
- font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
10
- max-width: 800px;
11
- margin: 0 auto;
12
- padding: 20px;
13
- background-color: #f5f5f5;
14
- }
15
-
16
- .container {
17
- background: white;
18
- padding: 30px;
19
- border-radius: 10px;
20
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
21
- }
22
-
23
- h1 {
24
- color: #333;
25
- text-align: center;
26
- margin-bottom: 30px;
27
- }
28
-
29
- .status {
30
- padding: 15px;
31
- border-radius: 5px;
32
- margin-bottom: 20px;
33
- font-weight: bold;
34
- text-align: center;
35
- }
36
-
37
- .connected {
38
- background-color: #d4edda;
39
- color: #155724;
40
- border: 1px solid #c3e6cb;
41
- }
42
-
43
- .disconnected {
44
- background-color: #f8d7da;
45
- color: #721c24;
46
- border: 1px solid #f5c6cb;
47
- }
48
-
49
- .connecting {
50
- background-color: #fff3cd;
51
- color: #856404;
52
- border: 1px solid #ffeaa7;
53
- }
54
-
55
- .counter-display {
56
- text-align: center;
57
- margin: 30px 0;
58
- }
59
-
60
- .counter-value {
61
- font-size: 48px;
62
- font-weight: bold;
63
- color: #007bff;
64
- margin: 20px 0;
65
- }
66
-
67
- .last-update {
68
- color: #666;
69
- font-size: 14px;
70
- }
71
-
72
- .controls {
73
- display: flex;
74
- gap: 10px;
75
- justify-content: center;
76
- margin: 30px 0;
77
- flex-wrap: wrap;
78
- }
79
-
80
- button {
81
- background-color: #007bff;
82
- color: white;
83
- border: none;
84
- padding: 12px 24px;
85
- border-radius: 5px;
86
- cursor: pointer;
87
- font-size: 16px;
88
- min-width: 120px;
89
- transition: background-color 0.3s;
90
- }
91
-
92
- button:hover:not(:disabled) {
93
- background-color: #0056b3;
94
- }
95
-
96
- button:disabled {
97
- background-color: #6c757d;
98
- cursor: not-allowed;
99
- }
100
-
101
- .increment {
102
- background-color: #28a745;
103
- }
104
- .increment:hover:not(:disabled) {
105
- background-color: #218838;
106
- }
107
-
108
- .decrement {
109
- background-color: #dc3545;
110
- }
111
- .decrement:hover:not(:disabled) {
112
- background-color: #c82333;
113
- }
114
-
115
- .reset {
116
- background-color: #ffc107;
117
- color: #212529;
118
- }
119
- .reset:hover:not(:disabled) {
120
- background-color: #e0a800;
121
- }
122
-
123
- .connection-form {
124
- background-color: #f8f9fa;
125
- padding: 20px;
126
- border-radius: 5px;
127
- margin-bottom: 20px;
128
- }
129
-
130
- .form-group {
131
- margin-bottom: 15px;
132
- }
133
-
134
- label {
135
- display: block;
136
- margin-bottom: 5px;
137
- font-weight: bold;
138
- color: #333;
139
- }
140
-
141
- input {
142
- width: 100%;
143
- padding: 8px 12px;
144
- border: 1px solid #ddd;
145
- border-radius: 4px;
146
- font-size: 14px;
147
- box-sizing: border-box;
148
- }
149
-
150
- .log {
151
- background-color: #f8f9fa;
152
- border: 1px solid #dee2e6;
153
- border-radius: 5px;
154
- padding: 15px;
155
- margin-top: 20px;
156
- max-height: 200px;
157
- overflow-y: auto;
158
- font-family: "Courier New", monospace;
159
- font-size: 12px;
160
- }
161
-
162
- .log-entry {
163
- margin-bottom: 5px;
164
- padding: 2px 0;
165
- }
166
-
167
- .log-info {
168
- color: #17a2b8;
169
- }
170
- .log-success {
171
- color: #28a745;
172
- }
173
- .log-warning {
174
- color: #ffc107;
175
- }
176
- .log-error {
177
- color: #dc3545;
178
- }
179
-
180
- @media (max-width: 600px) {
181
- .controls {
182
- flex-direction: column;
183
- align-items: center;
184
- }
185
-
186
- button {
187
- width: 100%;
188
- max-width: 300px;
189
- }
190
- }
191
- </style>
192
- </head>
193
- <body>
194
- <div class="container">
195
- <h1>🚀 Redux-Cluster-WS Browser Example</h1>
196
-
197
- <div id="status" class="status disconnected">Disconnected</div>
198
-
199
- <div class="connection-form">
200
- <h3>Connection Settings</h3>
201
- <div class="form-group">
202
- <label for="host">Server Host:</label>
203
- <input
204
- type="text"
205
- id="host"
206
- value="ws://localhost"
207
- placeholder="ws://localhost"
208
- />
209
- </div>
210
- <div class="form-group">
211
- <label for="port">Port:</label>
212
- <input type="number" id="port" value="8080" placeholder="8080" />
213
- </div>
214
- <div class="form-group">
215
- <label for="login">Login:</label>
216
- <input type="text" id="login" value="demo" placeholder="demo" />
217
- </div>
218
- <div class="form-group">
219
- <label for="password">Password:</label>
220
- <input
221
- type="password"
222
- id="password"
223
- value="demo"
224
- placeholder="demo"
225
- />
226
- </div>
227
- <button onclick="toggleConnection()" id="connectBtn">Connect</button>
228
- </div>
229
-
230
- <div class="counter-display">
231
- <h2>Counter Value</h2>
232
- <div class="counter-value" id="counterValue">0</div>
233
- <div class="last-update" id="lastUpdate">Never updated</div>
234
- </div>
235
-
236
- <div class="controls">
237
- <button class="increment" onclick="increment()" id="incBtn" disabled>
238
- ➕ Increment
239
- </button>
240
- <button class="decrement" onclick="decrement()" id="decBtn" disabled>
241
- ➖ Decrement
242
- </button>
243
- <button class="reset" onclick="reset()" id="resetBtn" disabled>
244
- 🔄 Reset
245
- </button>
246
- </div>
247
-
248
- <div class="log" id="log">
249
- <div class="log-entry log-info">Ready to connect...</div>
250
- </div>
251
- </div>
252
-
253
- <script src="browser-example.js"></script>
254
- </body>
255
- </html>