@furlow/pipes 0.1.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.
@@ -0,0 +1,226 @@
1
+ // src/websocket/index.ts
2
+ import WebSocket from "ws";
3
+ var WebSocketPipe = class {
4
+ name;
5
+ type = "websocket";
6
+ ws = null;
7
+ config;
8
+ reconnectAttempts = 0;
9
+ reconnecting = false;
10
+ heartbeatInterval = null;
11
+ messageHandlers = /* @__PURE__ */ new Map();
12
+ connected = false;
13
+ constructor(options) {
14
+ this.name = options.name;
15
+ this.config = options.config;
16
+ }
17
+ /**
18
+ * Connect to the WebSocket server
19
+ */
20
+ async connect() {
21
+ return new Promise((resolve, reject) => {
22
+ try {
23
+ const headers = this.config.headers;
24
+ this.ws = new WebSocket(this.config.url, { headers });
25
+ this.ws.on("open", () => {
26
+ this.connected = true;
27
+ this.reconnectAttempts = 0;
28
+ this.reconnecting = false;
29
+ this.startHeartbeat();
30
+ resolve();
31
+ });
32
+ this.ws.on("message", (data) => {
33
+ this.handleMessage(data);
34
+ });
35
+ this.ws.on("close", () => {
36
+ this.connected = false;
37
+ this.stopHeartbeat();
38
+ this.handleDisconnect();
39
+ });
40
+ this.ws.on("error", (error) => {
41
+ if (!this.connected) {
42
+ reject(error);
43
+ }
44
+ this.emit("error", error);
45
+ });
46
+ } catch (error) {
47
+ reject(error);
48
+ }
49
+ });
50
+ }
51
+ /**
52
+ * Disconnect from the server
53
+ */
54
+ async disconnect() {
55
+ this.stopHeartbeat();
56
+ this.reconnecting = false;
57
+ if (this.ws) {
58
+ this.ws.close();
59
+ this.ws = null;
60
+ }
61
+ this.connected = false;
62
+ }
63
+ /**
64
+ * Check if connected
65
+ */
66
+ isConnected() {
67
+ return this.connected && this.ws?.readyState === WebSocket.OPEN;
68
+ }
69
+ /**
70
+ * Send a message
71
+ */
72
+ send(data) {
73
+ if (!this.isConnected()) {
74
+ return false;
75
+ }
76
+ const message = typeof data === "string" ? data : JSON.stringify(data);
77
+ this.ws.send(message);
78
+ return true;
79
+ }
80
+ /**
81
+ * Send and wait for a response (request-response pattern)
82
+ */
83
+ async request(data, options = {}) {
84
+ const { timeout = 3e4, responseEvent = "response" } = options;
85
+ if (!this.isConnected()) {
86
+ return { success: false, error: "Not connected" };
87
+ }
88
+ return new Promise((resolve) => {
89
+ const timer = setTimeout(() => {
90
+ this.off(responseEvent, handler);
91
+ resolve({ success: false, error: "Request timeout" });
92
+ }, timeout);
93
+ const handler = (response) => {
94
+ clearTimeout(timer);
95
+ this.off(responseEvent, handler);
96
+ resolve({ success: true, data: response });
97
+ };
98
+ this.on(responseEvent, handler);
99
+ this.send(data);
100
+ });
101
+ }
102
+ /**
103
+ * Register a message handler
104
+ */
105
+ on(event, handler) {
106
+ const handlers = this.messageHandlers.get(event) ?? [];
107
+ handlers.push(handler);
108
+ this.messageHandlers.set(event, handlers);
109
+ }
110
+ /**
111
+ * Remove a message handler
112
+ */
113
+ off(event, handler) {
114
+ const handlers = this.messageHandlers.get(event) ?? [];
115
+ const index = handlers.indexOf(handler);
116
+ if (index !== -1) {
117
+ handlers.splice(index, 1);
118
+ }
119
+ }
120
+ /**
121
+ * Emit an event to handlers
122
+ */
123
+ emit(event, data) {
124
+ const handlers = this.messageHandlers.get(event) ?? [];
125
+ for (const handler of handlers) {
126
+ try {
127
+ handler(data);
128
+ } catch (error) {
129
+ console.error(`WebSocket handler error for "${event}":`, error);
130
+ }
131
+ }
132
+ }
133
+ /**
134
+ * Handle incoming messages
135
+ */
136
+ handleMessage(rawData) {
137
+ let data;
138
+ try {
139
+ const str = rawData.toString();
140
+ data = JSON.parse(str);
141
+ } catch {
142
+ data = rawData.toString();
143
+ }
144
+ this.emit("message", data);
145
+ if (typeof data === "object" && data !== null && "event" in data) {
146
+ const event = data.event;
147
+ this.emit(event, data);
148
+ }
149
+ }
150
+ /**
151
+ * Handle disconnection
152
+ */
153
+ handleDisconnect() {
154
+ if (!this.config.reconnect?.enabled || this.reconnecting) {
155
+ return;
156
+ }
157
+ const maxAttempts = this.config.reconnect.max_attempts ?? 10;
158
+ const delay = this.parseDuration(this.config.reconnect.delay ?? "5s");
159
+ if (this.reconnectAttempts >= maxAttempts) {
160
+ this.emit("reconnect_failed", { attempts: this.reconnectAttempts });
161
+ return;
162
+ }
163
+ this.reconnecting = true;
164
+ this.reconnectAttempts++;
165
+ setTimeout(async () => {
166
+ try {
167
+ await this.connect();
168
+ this.emit("reconnected", { attempts: this.reconnectAttempts });
169
+ } catch {
170
+ this.reconnecting = false;
171
+ this.handleDisconnect();
172
+ }
173
+ }, delay);
174
+ }
175
+ /**
176
+ * Start heartbeat
177
+ */
178
+ startHeartbeat() {
179
+ if (!this.config.heartbeat?.interval) return;
180
+ const interval = this.parseDuration(this.config.heartbeat.interval);
181
+ const message = this.config.heartbeat.message ?? "ping";
182
+ this.heartbeatInterval = setInterval(() => {
183
+ if (this.isConnected()) {
184
+ this.send(message);
185
+ }
186
+ }, interval);
187
+ }
188
+ /**
189
+ * Stop heartbeat
190
+ */
191
+ stopHeartbeat() {
192
+ if (this.heartbeatInterval) {
193
+ clearInterval(this.heartbeatInterval);
194
+ this.heartbeatInterval = null;
195
+ }
196
+ }
197
+ /**
198
+ * Parse duration string to milliseconds
199
+ */
200
+ parseDuration(duration) {
201
+ const match = duration.match(/^(\d+)(ms|s|m|h)?$/);
202
+ if (!match) return 5e3;
203
+ const value = parseInt(match[1], 10);
204
+ const unit = match[2] ?? "s";
205
+ switch (unit) {
206
+ case "ms":
207
+ return value;
208
+ case "s":
209
+ return value * 1e3;
210
+ case "m":
211
+ return value * 60 * 1e3;
212
+ case "h":
213
+ return value * 60 * 60 * 1e3;
214
+ default:
215
+ return value * 1e3;
216
+ }
217
+ }
218
+ };
219
+ function createWebSocketPipe(options) {
220
+ return new WebSocketPipe(options);
221
+ }
222
+ export {
223
+ WebSocketPipe,
224
+ createWebSocketPipe
225
+ };
226
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/websocket/index.ts"],"sourcesContent":["/**\n * WebSocket pipe for bidirectional communication\n */\n\nimport WebSocket from 'ws';\nimport type { Pipe, PipeResponse, WebSocketPipeConfig } from '../types.js';\n\nexport interface WebSocketPipeOptions {\n name: string;\n config: WebSocketPipeConfig;\n}\n\nexport type WebSocketMessageHandler = (data: unknown) => void | Promise<void>;\n\nexport class WebSocketPipe implements Pipe {\n public readonly name: string;\n public readonly type = 'websocket';\n private ws: WebSocket | null = null;\n private config: WebSocketPipeConfig;\n private reconnectAttempts = 0;\n private reconnecting = false;\n private heartbeatInterval: NodeJS.Timeout | null = null;\n private messageHandlers: Map<string, WebSocketMessageHandler[]> = new Map();\n private connected = false;\n\n constructor(options: WebSocketPipeOptions) {\n this.name = options.name;\n this.config = options.config;\n }\n\n /**\n * Connect to the WebSocket server\n */\n async connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n try {\n const headers = this.config.headers as Record<string, string>;\n this.ws = new WebSocket(this.config.url, { headers });\n\n this.ws.on('open', () => {\n this.connected = true;\n this.reconnectAttempts = 0;\n this.reconnecting = false;\n this.startHeartbeat();\n resolve();\n });\n\n this.ws.on('message', (data) => {\n this.handleMessage(data);\n });\n\n this.ws.on('close', () => {\n this.connected = false;\n this.stopHeartbeat();\n this.handleDisconnect();\n });\n\n this.ws.on('error', (error) => {\n if (!this.connected) {\n reject(error);\n }\n this.emit('error', error);\n });\n\n } catch (error) {\n reject(error);\n }\n });\n }\n\n /**\n * Disconnect from the server\n */\n async disconnect(): Promise<void> {\n this.stopHeartbeat();\n this.reconnecting = false;\n\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n\n this.connected = false;\n }\n\n /**\n * Check if connected\n */\n isConnected(): boolean {\n return this.connected && this.ws?.readyState === WebSocket.OPEN;\n }\n\n /**\n * Send a message\n */\n send(data: unknown): boolean {\n if (!this.isConnected()) {\n return false;\n }\n\n const message = typeof data === 'string' ? data : JSON.stringify(data);\n this.ws!.send(message);\n return true;\n }\n\n /**\n * Send and wait for a response (request-response pattern)\n */\n async request<T = unknown>(\n data: unknown,\n options: { timeout?: number; responseEvent?: string } = {}\n ): Promise<PipeResponse<T>> {\n const { timeout = 30000, responseEvent = 'response' } = options;\n\n if (!this.isConnected()) {\n return { success: false, error: 'Not connected' };\n }\n\n return new Promise((resolve) => {\n const timer = setTimeout(() => {\n this.off(responseEvent, handler);\n resolve({ success: false, error: 'Request timeout' });\n }, timeout);\n\n const handler = (response: unknown) => {\n clearTimeout(timer);\n this.off(responseEvent, handler);\n resolve({ success: true, data: response as T });\n };\n\n this.on(responseEvent, handler);\n this.send(data);\n });\n }\n\n /**\n * Register a message handler\n */\n on(event: string, handler: WebSocketMessageHandler): void {\n const handlers = this.messageHandlers.get(event) ?? [];\n handlers.push(handler);\n this.messageHandlers.set(event, handlers);\n }\n\n /**\n * Remove a message handler\n */\n off(event: string, handler: WebSocketMessageHandler): void {\n const handlers = this.messageHandlers.get(event) ?? [];\n const index = handlers.indexOf(handler);\n if (index !== -1) {\n handlers.splice(index, 1);\n }\n }\n\n /**\n * Emit an event to handlers\n */\n private emit(event: string, data: unknown): void {\n const handlers = this.messageHandlers.get(event) ?? [];\n for (const handler of handlers) {\n try {\n handler(data);\n } catch (error) {\n console.error(`WebSocket handler error for \"${event}\":`, error);\n }\n }\n }\n\n /**\n * Handle incoming messages\n */\n private handleMessage(rawData: WebSocket.RawData): void {\n let data: unknown;\n\n try {\n const str = rawData.toString();\n data = JSON.parse(str);\n } catch {\n data = rawData.toString();\n }\n\n // Emit to 'message' handlers\n this.emit('message', data);\n\n // Check for event field in JSON messages\n if (typeof data === 'object' && data !== null && 'event' in data) {\n const event = (data as { event: string }).event;\n this.emit(event, data);\n }\n }\n\n /**\n * Handle disconnection\n */\n private handleDisconnect(): void {\n if (!this.config.reconnect?.enabled || this.reconnecting) {\n return;\n }\n\n const maxAttempts = this.config.reconnect.max_attempts ?? 10;\n const delay = this.parseDuration(this.config.reconnect.delay ?? '5s');\n\n if (this.reconnectAttempts >= maxAttempts) {\n this.emit('reconnect_failed', { attempts: this.reconnectAttempts });\n return;\n }\n\n this.reconnecting = true;\n this.reconnectAttempts++;\n\n setTimeout(async () => {\n try {\n await this.connect();\n this.emit('reconnected', { attempts: this.reconnectAttempts });\n } catch {\n this.reconnecting = false;\n this.handleDisconnect();\n }\n }, delay);\n }\n\n /**\n * Start heartbeat\n */\n private startHeartbeat(): void {\n if (!this.config.heartbeat?.interval) return;\n\n const interval = this.parseDuration(this.config.heartbeat.interval);\n const message = this.config.heartbeat.message ?? 'ping';\n\n this.heartbeatInterval = setInterval(() => {\n if (this.isConnected()) {\n this.send(message);\n }\n }, interval);\n }\n\n /**\n * Stop heartbeat\n */\n private stopHeartbeat(): void {\n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n this.heartbeatInterval = null;\n }\n }\n\n /**\n * Parse duration string to milliseconds\n */\n private parseDuration(duration: string): number {\n const match = duration.match(/^(\\d+)(ms|s|m|h)?$/);\n if (!match) return 5000;\n\n const value = parseInt(match[1]!, 10);\n const unit = match[2] ?? 's';\n\n switch (unit) {\n case 'ms':\n return value;\n case 's':\n return value * 1000;\n case 'm':\n return value * 60 * 1000;\n case 'h':\n return value * 60 * 60 * 1000;\n default:\n return value * 1000;\n }\n }\n}\n\n/**\n * Create a WebSocket pipe\n */\nexport function createWebSocketPipe(options: WebSocketPipeOptions): WebSocketPipe {\n return new WebSocketPipe(options);\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,83 @@
1
+ {
2
+ "name": "@furlow/pipes",
3
+ "version": "0.1.0",
4
+ "description": "External integration pipes for FURLOW bot framework",
5
+ "keywords": [
6
+ "furlow",
7
+ "discord",
8
+ "pipes",
9
+ "http",
10
+ "websocket",
11
+ "mqtt"
12
+ ],
13
+ "license": "MIT",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://github.com/virgilvox/discord-furlow",
17
+ "directory": "packages/pipes"
18
+ },
19
+ "author": "virgilvox",
20
+ "type": "module",
21
+ "exports": {
22
+ ".": {
23
+ "types": "./dist/index.d.ts",
24
+ "import": "./dist/index.js"
25
+ },
26
+ "./http": {
27
+ "types": "./dist/http/index.d.ts",
28
+ "import": "./dist/http/index.js"
29
+ },
30
+ "./websocket": {
31
+ "types": "./dist/websocket/index.d.ts",
32
+ "import": "./dist/websocket/index.js"
33
+ },
34
+ "./mqtt": {
35
+ "types": "./dist/mqtt/index.d.ts",
36
+ "import": "./dist/mqtt/index.js"
37
+ },
38
+ "./tcp": {
39
+ "types": "./dist/tcp/index.d.ts",
40
+ "import": "./dist/tcp/index.js"
41
+ },
42
+ "./webhook": {
43
+ "types": "./dist/webhook/index.d.ts",
44
+ "import": "./dist/webhook/index.js"
45
+ },
46
+ "./database": {
47
+ "types": "./dist/database/index.d.ts",
48
+ "import": "./dist/database/index.js"
49
+ },
50
+ "./file": {
51
+ "types": "./dist/file/index.d.ts",
52
+ "import": "./dist/file/index.js"
53
+ }
54
+ },
55
+ "main": "./dist/index.js",
56
+ "types": "./dist/index.d.ts",
57
+ "files": [
58
+ "dist"
59
+ ],
60
+ "dependencies": {
61
+ "axios": "^1.6.0",
62
+ "chokidar": "^3.5.0",
63
+ "mqtt": "^5.3.0",
64
+ "ws": "^8.16.0",
65
+ "@furlow/core": "0.1.0"
66
+ },
67
+ "devDependencies": {
68
+ "@types/node": "^20.11.0",
69
+ "@types/ws": "^8.5.0",
70
+ "tsup": "^8.0.0",
71
+ "typescript": "^5.3.0",
72
+ "vitest": "^1.2.0"
73
+ },
74
+ "scripts": {
75
+ "build": "tsup",
76
+ "clean": "rm -rf dist .turbo",
77
+ "dev": "tsup --watch",
78
+ "lint": "eslint src/",
79
+ "test": "vitest run",
80
+ "test:unit": "vitest run",
81
+ "typecheck": "tsc --noEmit"
82
+ }
83
+ }