redux-cluster-ws 1.4.0 → 2.0.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.
Files changed (54) hide show
  1. package/FUNDING.yml +7 -0
  2. package/LICENSE +21 -21
  3. package/README.md +394 -90
  4. package/dist/cjs/client.d.ts +43 -0
  5. package/dist/cjs/client.js +276 -0
  6. package/dist/cjs/client.js.map +1 -0
  7. package/dist/cjs/index.d.ts +4 -0
  8. package/dist/cjs/index.js +25 -0
  9. package/dist/cjs/index.js.map +1 -0
  10. package/dist/cjs/package.json +1 -0
  11. package/dist/cjs/server.d.ts +31 -0
  12. package/dist/cjs/server.js +295 -0
  13. package/dist/cjs/server.js.map +1 -0
  14. package/dist/cjs/types.d.ts +83 -0
  15. package/dist/cjs/types.js +3 -0
  16. package/dist/cjs/types.js.map +1 -0
  17. package/dist/cjs/utils.d.ts +17 -0
  18. package/dist/cjs/utils.js +75 -0
  19. package/dist/cjs/utils.js.map +1 -0
  20. package/dist/esm/client.d.ts +43 -0
  21. package/dist/esm/client.js +282 -0
  22. package/dist/esm/client.js.map +1 -0
  23. package/dist/esm/index.d.ts +4 -0
  24. package/dist/esm/index.js +5 -0
  25. package/dist/esm/index.js.map +1 -0
  26. package/dist/esm/server.d.ts +31 -0
  27. package/dist/esm/server.js +299 -0
  28. package/dist/esm/server.js.map +1 -0
  29. package/dist/esm/types.d.ts +83 -0
  30. package/dist/esm/types.js +2 -0
  31. package/dist/esm/types.js.map +1 -0
  32. package/dist/esm/utils.d.ts +17 -0
  33. package/dist/esm/utils.js +69 -0
  34. package/dist/esm/utils.js.map +1 -0
  35. package/eslint.config.js +143 -0
  36. package/examples/browser-example.cjs +350 -0
  37. package/examples/browser.html +255 -0
  38. package/examples/client.cjs +155 -0
  39. package/examples/cross-library-browser.html +655 -0
  40. package/examples/cross-library-client.cjs +190 -0
  41. package/examples/cross-library-server.cjs +213 -0
  42. package/examples/server.cjs +96 -0
  43. package/package.json +96 -18
  44. package/client.js +0 -192
  45. package/index.js +0 -12
  46. package/server.js +0 -173
  47. package/test.auto.proc1.js +0 -100
  48. package/test.auto.proc2.js +0 -74
  49. package/test.visual.client.html +0 -37
  50. package/test.visual.client.js +0 -63
  51. package/test.visual.server.js +0 -66
  52. package/umd/ReduxCluster.js +0 -18
  53. package/webpack-src.js +0 -6
  54. package/webpack.config.js +0 -25
@@ -0,0 +1,299 @@
1
+ import { createServer as createHttpServer } from "http";
2
+ import { createServer as createHttpsServer } from "https";
3
+ import { readFileSync } from "fs";
4
+ import { hasher, replacer, generateUID } from "./utils.js";
5
+ // Import WebSocket server for Node.js
6
+ import { WebSocketServer } from "ws";
7
+ export class ReduxClusterWSServerWrapper {
8
+ store;
9
+ uid;
10
+ connections;
11
+ authDatabase;
12
+ ipBanDatabase;
13
+ config;
14
+ server;
15
+ wss;
16
+ unsubscribe;
17
+ IP_BAN_ATTEMPTS = 15;
18
+ IP_BAN_TIMEOUT = 10800000; // 3 hours
19
+ CONNECTION_TIMEOUT = 30000;
20
+ gcInterval;
21
+ constructor(store) {
22
+ this.store = store;
23
+ this.uid = generateUID();
24
+ this.connections = new Map();
25
+ this.authDatabase = {};
26
+ this.ipBanDatabase = {};
27
+ this.config = { host: "0.0.0.0", port: 10002 };
28
+ // Attach createWSServer method to store
29
+ store.createWSServer = this.createWSServer.bind(this);
30
+ }
31
+ createWSServer = (config) => {
32
+ this.config = { ...this.config, ...config };
33
+ // Setup authentication database
34
+ if (this.config.logins) {
35
+ for (const [login, password] of Object.entries(this.config.logins)) {
36
+ const hashedLogin = hasher(`REDUX_CLUSTER${login}`);
37
+ const hashedPassword = hasher(`REDUX_CLUSTER${password}`);
38
+ this.authDatabase[hashedLogin] = hashedPassword;
39
+ }
40
+ }
41
+ // Start garbage collection for banned IPs
42
+ this.startGarbageCollection();
43
+ // Create HTTP/HTTPS server if not provided
44
+ if (!this.config.server) {
45
+ if (this.config.ssl?.key && this.config.ssl?.cert) {
46
+ const ssl = {
47
+ key: readFileSync(this.config.ssl.key),
48
+ cert: readFileSync(this.config.ssl.cert) +
49
+ (this.config.ssl.ca ? "\n" + readFileSync(this.config.ssl.ca) : ""),
50
+ };
51
+ this.server = createHttpsServer(ssl);
52
+ }
53
+ else {
54
+ this.server = createHttpServer();
55
+ }
56
+ this.server.setTimeout(this.CONNECTION_TIMEOUT);
57
+ this.server.listen(this.config.port, this.config.host);
58
+ }
59
+ else {
60
+ this.server = this.config.server;
61
+ }
62
+ // Create WebSocket server
63
+ this.wss = new WebSocketServer({
64
+ server: this.server,
65
+ path: `/redux-cluster-${this.store.RCHash}`,
66
+ });
67
+ this.wss.on("connection", this.handleConnection.bind(this));
68
+ // Subscribe to store changes
69
+ this.unsubscribe = this.store.subscribe(() => {
70
+ if (this.store.mode === "snapshot") {
71
+ this.sendToAll();
72
+ }
73
+ });
74
+ // For action mode, override dispatch to send individual actions
75
+ if (this.store.mode === "action") {
76
+ const originalDispatch = this.store.dispatch;
77
+ this.store.dispatch = (action) => {
78
+ const result = originalDispatch(action);
79
+ // Send the action to all connected clients
80
+ if (action.type !== "@@INIT" && action.type !== "REDUX_CLUSTER_SYNC") {
81
+ this.sendToAll({
82
+ _msg: "REDUX_CLUSTER_MSGTOWORKER",
83
+ _hash: this.store.RCHash,
84
+ _action: action,
85
+ });
86
+ }
87
+ return result;
88
+ };
89
+ }
90
+ // Add server role
91
+ if (!this.store.role.includes("server")) {
92
+ this.store.role.push("server");
93
+ }
94
+ };
95
+ handleConnection = (ws, req) => {
96
+ const connectionId = generateUID();
97
+ const ip = this.extractIP(req);
98
+ const processedIP = replacer(ip, true);
99
+ // Check if IP is banned
100
+ if (this.isIPBanned(processedIP)) {
101
+ this.sendMessage(ws, {
102
+ _msg: "REDUX_CLUSTER_SOCKET_AUTHSTATE",
103
+ _hash: this.store.RCHash,
104
+ _value: false,
105
+ _banned: true,
106
+ });
107
+ ws.close();
108
+ return;
109
+ }
110
+ const connection = {
111
+ id: connectionId,
112
+ ws,
113
+ authenticated: false,
114
+ ip: processedIP,
115
+ };
116
+ this.connections.set(connectionId, connection);
117
+ ws.on("message", (data) => {
118
+ try {
119
+ const message = JSON.parse(data.toString());
120
+ this.handleMessage(connectionId, message);
121
+ }
122
+ catch (error) {
123
+ this.store.stderr(`ReduxCluster.createWSServer message parse error: ${error}`);
124
+ this.removeConnection(connectionId);
125
+ }
126
+ });
127
+ ws.on("close", () => {
128
+ this.removeConnection(connectionId);
129
+ });
130
+ ws.on("error", (error) => {
131
+ this.store.stderr(`ReduxCluster.createWSServer connection error: ${error.message}`);
132
+ this.removeConnection(connectionId);
133
+ });
134
+ };
135
+ handleMessage = (connectionId, message) => {
136
+ const connection = this.connections.get(connectionId);
137
+ if (!connection || message._hash !== this.store.RCHash) {
138
+ return;
139
+ }
140
+ switch (message._msg) {
141
+ case "REDUX_CLUSTER_SOCKET_AUTH":
142
+ this.handleAuthentication(connectionId, message);
143
+ break;
144
+ case "REDUX_CLUSTER_START":
145
+ if (connection.authenticated) {
146
+ this.sendMessage(connection.ws, {
147
+ _msg: "REDUX_CLUSTER_MSGTOWORKER",
148
+ _hash: this.store.RCHash,
149
+ _action: {
150
+ type: "REDUX_CLUSTER_SYNC",
151
+ payload: this.store.getState(),
152
+ },
153
+ });
154
+ }
155
+ break;
156
+ case "REDUX_CLUSTER_MSGTOMASTER":
157
+ if (connection.authenticated && message._action) {
158
+ if (message._action.type === "REDUX_CLUSTER_SYNC") {
159
+ throw new Error("Please don't use REDUX_CLUSTER_SYNC action type!");
160
+ }
161
+ this.store.dispatch(message._action);
162
+ }
163
+ break;
164
+ }
165
+ };
166
+ handleAuthentication = (connectionId, message) => {
167
+ const connection = this.connections.get(connectionId);
168
+ if (!connection)
169
+ return;
170
+ const { _login, _password } = message;
171
+ if (_login &&
172
+ _password &&
173
+ this.authDatabase[_login] &&
174
+ this.authDatabase[_login] === _password) {
175
+ // Authentication successful
176
+ connection.authenticated = true;
177
+ this.clearIPBan(connection.ip);
178
+ this.sendMessage(connection.ws, {
179
+ _msg: "REDUX_CLUSTER_SOCKET_AUTHSTATE",
180
+ _hash: this.store.RCHash,
181
+ _value: true,
182
+ });
183
+ }
184
+ else {
185
+ // Authentication failed
186
+ this.recordFailedAttempt(connection.ip);
187
+ this.sendMessage(connection.ws, {
188
+ _msg: "REDUX_CLUSTER_SOCKET_AUTHSTATE",
189
+ _hash: this.store.RCHash,
190
+ _value: false,
191
+ });
192
+ this.removeConnection(connectionId);
193
+ }
194
+ };
195
+ sendToAll = (message) => {
196
+ const msg = message || {
197
+ _msg: "REDUX_CLUSTER_MSGTOWORKER",
198
+ _hash: this.store.RCHash,
199
+ _action: { type: "REDUX_CLUSTER_SYNC", payload: this.store.getState() },
200
+ };
201
+ for (const connection of this.connections.values()) {
202
+ if (connection.authenticated && connection.ws.readyState === 1) {
203
+ // WebSocket.OPEN = 1
204
+ try {
205
+ this.sendMessage(connection.ws, msg);
206
+ }
207
+ catch (error) {
208
+ this.store.stderr(`ReduxCluster.createWSServer write error: ${error}`);
209
+ }
210
+ }
211
+ }
212
+ };
213
+ sendMessage = (ws, message) => {
214
+ if (ws.readyState === 1) {
215
+ // WebSocket.OPEN = 1
216
+ ws.send(JSON.stringify(message));
217
+ }
218
+ };
219
+ extractIP = (req) => {
220
+ const forwarded = req.headers["x-forwarded-for"];
221
+ if (typeof forwarded === "string") {
222
+ return forwarded.split(",")[0].trim();
223
+ }
224
+ if (Array.isArray(forwarded)) {
225
+ return forwarded[0];
226
+ }
227
+ return req.socket.remoteAddress || "127.0.0.1";
228
+ };
229
+ isIPBanned = (ip) => {
230
+ const banInfo = this.ipBanDatabase[ip];
231
+ if (!banInfo)
232
+ return false;
233
+ const isTimedOut = banInfo.time + this.IP_BAN_TIMEOUT < Date.now();
234
+ if (isTimedOut) {
235
+ delete this.ipBanDatabase[ip];
236
+ return false;
237
+ }
238
+ return banInfo.count >= this.IP_BAN_ATTEMPTS;
239
+ };
240
+ recordFailedAttempt = (ip) => {
241
+ const existing = this.ipBanDatabase[ip];
242
+ let count = 0;
243
+ if (existing) {
244
+ const isTimedOut = existing.time + this.IP_BAN_TIMEOUT < Date.now();
245
+ count = isTimedOut ? 0 : existing.count;
246
+ }
247
+ this.ipBanDatabase[ip] = {
248
+ time: Date.now(),
249
+ count: count + 1,
250
+ };
251
+ };
252
+ clearIPBan = (ip) => {
253
+ delete this.ipBanDatabase[ip];
254
+ };
255
+ removeConnection = (connectionId) => {
256
+ const connection = this.connections.get(connectionId);
257
+ if (connection) {
258
+ try {
259
+ connection.ws.close();
260
+ }
261
+ catch {
262
+ // Ignore errors when closing
263
+ }
264
+ this.connections.delete(connectionId);
265
+ }
266
+ };
267
+ startGarbageCollection = () => {
268
+ this.gcInterval = setInterval(() => {
269
+ const now = Date.now();
270
+ for (const [ip, banInfo] of Object.entries(this.ipBanDatabase)) {
271
+ if (banInfo.time + this.IP_BAN_TIMEOUT < now) {
272
+ delete this.ipBanDatabase[ip];
273
+ }
274
+ }
275
+ }, 60000); // Run every minute
276
+ };
277
+ destroy = () => {
278
+ if (this.gcInterval) {
279
+ clearInterval(this.gcInterval);
280
+ }
281
+ if (this.unsubscribe) {
282
+ this.unsubscribe();
283
+ }
284
+ for (const connection of this.connections.values()) {
285
+ this.removeConnection(connection.id);
286
+ }
287
+ if (this.wss) {
288
+ this.wss.close();
289
+ }
290
+ if (this.server && this.server.close) {
291
+ this.server.close();
292
+ }
293
+ };
294
+ }
295
+ export function server(store) {
296
+ new ReduxClusterWSServerWrapper(store);
297
+ return store;
298
+ }
299
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ import type { Reducer, Action, AnyAction, Dispatch } from "redux";
2
+ export interface WSServerConfig {
3
+ host?: string;
4
+ port?: number;
5
+ server?: any;
6
+ logins?: Record<string, string>;
7
+ ssl?: {
8
+ key: string;
9
+ cert: string;
10
+ ca?: string;
11
+ };
12
+ }
13
+ export interface WSClientConfig {
14
+ host: string;
15
+ port?: number;
16
+ login: string;
17
+ password: string;
18
+ reconnectInterval?: number;
19
+ timeout?: number;
20
+ }
21
+ export interface ReduxClusterMessage {
22
+ _msg: string;
23
+ _hash: string;
24
+ _action?: AnyAction;
25
+ _login?: string;
26
+ _password?: string;
27
+ _value?: boolean;
28
+ _banned?: boolean;
29
+ }
30
+ export interface ReduxClusterStore<S = any, A extends Action = AnyAction> {
31
+ getState(): S;
32
+ dispatch: Dispatch<A>;
33
+ subscribe(listener: () => void): () => void;
34
+ replaceReducer(nextReducer: Reducer<S, A>): void;
35
+ [Symbol.observable](): any;
36
+ createWSServer?: (config: WSServerConfig) => void;
37
+ createWSClient?: (config: WSClientConfig) => void;
38
+ RCHash: string;
39
+ role: string[];
40
+ mode: "action" | "snapshot";
41
+ connected: boolean;
42
+ stderr: (message: string) => void;
43
+ version: string;
44
+ homepage: string;
45
+ }
46
+ export interface WSConnection {
47
+ id: string;
48
+ ws: any;
49
+ authenticated: boolean;
50
+ ip: string;
51
+ }
52
+ export interface BanInfo {
53
+ time: number;
54
+ count: number;
55
+ }
56
+ export interface AuthDatabase {
57
+ [hashedLogin: string]: string;
58
+ }
59
+ export interface IPBanDatabase {
60
+ [ip: string]: BanInfo;
61
+ }
62
+ export interface ReduxClusterWSServer {
63
+ store: ReduxClusterStore;
64
+ uid: string;
65
+ connections: Map<string, WSConnection>;
66
+ authDatabase: AuthDatabase;
67
+ ipBanDatabase: IPBanDatabase;
68
+ config: WSServerConfig;
69
+ server?: any;
70
+ wss?: any;
71
+ sendToAll: (message?: ReduxClusterMessage) => void;
72
+ unsubscribe?: () => void;
73
+ }
74
+ export interface ReduxClusterWSClient {
75
+ store: ReduxClusterStore;
76
+ config: WSClientConfig;
77
+ ws?: any;
78
+ reconnectTimer?: any;
79
+ authenticated: boolean;
80
+ login: string;
81
+ password: string;
82
+ reconnect: () => void;
83
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Hash a string using SHA-1
3
+ */
4
+ export declare function hasher(data: string): string;
5
+ /**
6
+ * Replace dots with underscores and vice versa
7
+ */
8
+ export declare function replacer(data: string, dotToUnderscore?: boolean): string;
9
+ /**
10
+ * Generate a unique identifier using crypto.randomUUID
11
+ * Supports Node.js 14.17+ and modern browsers (Chrome 92+, Firefox 95+, Safari 15.4+)
12
+ */
13
+ export declare function generateUID(): string;
14
+ /**
15
+ * Deep clone an object
16
+ */
17
+ export declare function deepClone<T>(obj: T): T;
@@ -0,0 +1,69 @@
1
+ import { createHash, randomUUID } from "crypto";
2
+ /**
3
+ * Hash a string using SHA-1
4
+ */
5
+ export function hasher(data) {
6
+ if (typeof data === "string") {
7
+ const hash = createHash("sha1");
8
+ hash.update(data);
9
+ return hash.digest("hex");
10
+ }
11
+ throw new Error("Data must be a string");
12
+ }
13
+ /**
14
+ * Replace dots with underscores and vice versa
15
+ */
16
+ export function replacer(data, dotToUnderscore = true) {
17
+ if (typeof data === "string") {
18
+ if (dotToUnderscore) {
19
+ return data.replace(/\./g, "_");
20
+ }
21
+ else {
22
+ return data.replace(/_/g, ".");
23
+ }
24
+ }
25
+ throw new Error("Data must be a string");
26
+ }
27
+ /**
28
+ * Generate a unique identifier using crypto.randomUUID
29
+ * Supports Node.js 14.17+ and modern browsers (Chrome 92+, Firefox 95+, Safari 15.4+)
30
+ */
31
+ export function generateUID() {
32
+ // Use crypto.randomUUID if available (Node.js 14.17+ and modern browsers)
33
+ if (typeof randomUUID === "function") {
34
+ return randomUUID();
35
+ }
36
+ // Browser global crypto.randomUUID
37
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
38
+ return crypto.randomUUID();
39
+ }
40
+ // Final fallback for very old environments
41
+ return (Math.random().toString(36).substring(2, 15) +
42
+ Math.random().toString(36).substring(2, 15) +
43
+ Date.now().toString(36));
44
+ }
45
+ /**
46
+ * Deep clone an object
47
+ */
48
+ export function deepClone(obj) {
49
+ if (obj === null || typeof obj !== "object") {
50
+ return obj;
51
+ }
52
+ if (obj instanceof Date) {
53
+ return new Date(obj.getTime());
54
+ }
55
+ if (obj instanceof Array) {
56
+ return obj.map((item) => deepClone(item));
57
+ }
58
+ if (typeof obj === "object") {
59
+ const cloned = {};
60
+ for (const key in obj) {
61
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
62
+ cloned[key] = deepClone(obj[key]);
63
+ }
64
+ }
65
+ return cloned;
66
+ }
67
+ return obj;
68
+ }
69
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEhD;;GAEG;AACH,MAAM,UAAU,MAAM,CAAC,IAAY;IACjC,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;QAChC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAClB,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;AAC3C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,QAAQ,CACtB,IAAY,EACZ,kBAA2B,IAAI;IAE/B,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,IAAI,eAAe,EAAE,CAAC;YACpB,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAClC,CAAC;aAAM,CAAC;YACN,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;AAC3C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW;IACzB,0EAA0E;IAC1E,IAAI,OAAO,UAAU,KAAK,UAAU,EAAE,CAAC;QACrC,OAAO,UAAU,EAAE,CAAC;IACtB,CAAC;IAED,mCAAmC;IACnC,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QACvD,OAAO,MAAM,CAAC,UAAU,EAAE,CAAC;IAC7B,CAAC;IAED,2CAA2C;IAC3C,OAAO,CACL,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC;QAC3C,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC;QAC3C,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CACxB,CAAC;AACJ,CAAC;AACD;;GAEG;AACH,MAAM,UAAU,SAAS,CAAI,GAAM;IACjC,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5C,OAAO,GAAG,CAAC;IACb,CAAC;IAED,IAAI,GAAG,YAAY,IAAI,EAAE,CAAC;QACxB,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAM,CAAC;IACtC,CAAC;IAED,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;QACzB,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAM,CAAC;IACjD,CAAC;IAED,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAG,EAAO,CAAC;QACvB,KAAK,MAAM,GAAG,IAAI,GAAG,EAAE,CAAC;YACtB,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC;gBACnD,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;YACpC,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,143 @@
1
+ import js from "@eslint/js";
2
+ import tsPlugin from "@typescript-eslint/eslint-plugin";
3
+ import tsParser from "@typescript-eslint/parser";
4
+
5
+ export default [
6
+ js.configs.recommended,
7
+ {
8
+ ignores: ["*.md", "**/*.md"], // Ignore Markdown files
9
+ },
10
+ {
11
+ files: ["src/**/*.ts"],
12
+ languageOptions: {
13
+ parser: tsParser,
14
+ parserOptions: {
15
+ ecmaVersion: 2020,
16
+ sourceType: "module",
17
+ project: "./tsconfig.json",
18
+ },
19
+ globals: {
20
+ // Node.js globals
21
+ global: "readonly",
22
+ process: "readonly",
23
+ console: "readonly",
24
+ Buffer: "readonly",
25
+ require: "readonly",
26
+ module: "readonly",
27
+ exports: "readonly",
28
+ __dirname: "readonly",
29
+ __filename: "readonly",
30
+ setTimeout: "readonly",
31
+ clearTimeout: "readonly",
32
+ setInterval: "readonly",
33
+ clearInterval: "readonly",
34
+ setImmediate: "readonly",
35
+ clearImmediate: "readonly",
36
+ structuredClone: "readonly",
37
+ // TypeScript globals
38
+ NodeJS: "readonly",
39
+ BufferEncoding: "readonly",
40
+ },
41
+ },
42
+ plugins: {
43
+ "@typescript-eslint": tsPlugin,
44
+ },
45
+ rules: {
46
+ ...tsPlugin.configs.recommended.rules,
47
+ "@typescript-eslint/no-explicit-any": "off",
48
+ "@typescript-eslint/no-unused-vars": [
49
+ "error",
50
+ { argsIgnorePattern: "^_" },
51
+ ],
52
+ "@typescript-eslint/explicit-function-return-type": "off",
53
+ "@typescript-eslint/explicit-module-boundary-types": "off",
54
+ "@typescript-eslint/no-empty-function": "off",
55
+ "no-case-declarations": "off",
56
+ "no-undef": "off", // TypeScript handles this
57
+ },
58
+ },
59
+ {
60
+ files: ["tests/**/*.cjs", "*.test.cjs", "test.*.cjs"],
61
+ languageOptions: {
62
+ parser: tsParser,
63
+ parserOptions: {
64
+ ecmaVersion: 2020,
65
+ sourceType: "script",
66
+ },
67
+ globals: {
68
+ // Node.js globals
69
+ global: "readonly",
70
+ process: "readonly",
71
+ console: "readonly",
72
+ Buffer: "readonly",
73
+ require: "readonly",
74
+ module: "readonly",
75
+ exports: "readonly",
76
+ __dirname: "readonly",
77
+ __filename: "readonly",
78
+ setTimeout: "readonly",
79
+ clearTimeout: "readonly",
80
+ setInterval: "readonly",
81
+ clearInterval: "readonly",
82
+ setImmediate: "readonly",
83
+ clearImmediate: "readonly",
84
+ structuredClone: "readonly",
85
+ },
86
+ },
87
+ plugins: {
88
+ "@typescript-eslint": tsPlugin,
89
+ },
90
+ rules: {
91
+ ...tsPlugin.configs.recommended.rules,
92
+ "@typescript-eslint/no-explicit-any": "off",
93
+ "no-case-declarations": "off",
94
+ "no-undef": "off",
95
+ // Allow console in test files
96
+ "no-console": "off",
97
+ // Allow require in CommonJS
98
+ "@typescript-eslint/no-var-requires": "off",
99
+ },
100
+ },
101
+ {
102
+ files: ["examples/**/*.cjs", "*.cjs"],
103
+ languageOptions: {
104
+ parser: tsParser,
105
+ parserOptions: {
106
+ ecmaVersion: 2020,
107
+ sourceType: "script",
108
+ },
109
+ globals: {
110
+ // Node.js globals
111
+ global: "readonly",
112
+ process: "readonly",
113
+ console: "readonly",
114
+ Buffer: "readonly",
115
+ require: "readonly",
116
+ module: "readonly",
117
+ exports: "readonly",
118
+ __dirname: "readonly",
119
+ __filename: "readonly",
120
+ setTimeout: "readonly",
121
+ clearTimeout: "readonly",
122
+ setInterval: "readonly",
123
+ clearInterval: "readonly",
124
+ setImmediate: "readonly",
125
+ clearImmediate: "readonly",
126
+ structuredClone: "readonly",
127
+ },
128
+ },
129
+ plugins: {
130
+ "@typescript-eslint": tsPlugin,
131
+ },
132
+ rules: {
133
+ ...tsPlugin.configs.recommended.rules,
134
+ "@typescript-eslint/no-explicit-any": "off",
135
+ "no-case-declarations": "off",
136
+ "no-undef": "off",
137
+ // Allow console in examples
138
+ "no-console": "off",
139
+ // Allow require in CommonJS
140
+ "@typescript-eslint/no-var-requires": "off",
141
+ },
142
+ },
143
+ ];