@steijnveer/fbr-plugin-io 0.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.
- package/README.md +216 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +54 -0
- package/dist/types.d.ts +16 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# @steijnveer/fbr-plugin-io
|
|
2
|
+
|
|
3
|
+
Socket.io integration plugin for [@steijnveer/file-based-router](https://github.com/steijnveer/file-based-router)
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This plugin adds Socket.io support to your file-based-router application with automatic event handler discovery and registration. Define your Socket.io event handlers in files, and the plugin will automatically load and register them.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @steijnveer/fbr-plugin-io
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
### 1. Configure the plugin
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
// '/fbr.config.ts'
|
|
21
|
+
import ioPlugin from '@steijnveer/fbr-plugin-io';
|
|
22
|
+
import defineConfig from '@steijnveer/file-based-router/defineConfig';
|
|
23
|
+
|
|
24
|
+
export default defineConfig({
|
|
25
|
+
plugins: [
|
|
26
|
+
ioPlugin({
|
|
27
|
+
eventsDir: 'src\\events', // Directory containing event handlers
|
|
28
|
+
extensions: ['.ts', '.js'] // File extensions to load
|
|
29
|
+
})
|
|
30
|
+
]
|
|
31
|
+
});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 2. Create event handlers
|
|
35
|
+
|
|
36
|
+
Create event handler files in your events directory (default: `src/events`):
|
|
37
|
+
|
|
38
|
+
**src/events/message.ts**
|
|
39
|
+
```typescript
|
|
40
|
+
import type { Socket } from '@steijnveer/fbr-plugin-io';
|
|
41
|
+
|
|
42
|
+
// Export named functions - function name becomes the event name
|
|
43
|
+
export function message(socket: Socket, data: { text: string }) {
|
|
44
|
+
log('Received message:', data.text);
|
|
45
|
+
socket.emit('message:response', { echo: data.text });
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**src/events/chat.ts**
|
|
50
|
+
```typescript
|
|
51
|
+
import type { Socket } from '@steijnveer/fbr-plugin-io';
|
|
52
|
+
|
|
53
|
+
export function join(socket: Socket, data: { room: string }) {
|
|
54
|
+
socket.join(data.room);
|
|
55
|
+
socket.to(data.room).emit('user:joined', { id: socket.id });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function leave(socket: Socket, data: { room: string }) {
|
|
59
|
+
socket.leave(data.room);
|
|
60
|
+
socket.to(data.room).emit('user:left', { id: socket.id });
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**src/events/index.ts** (for connection handlers)
|
|
65
|
+
```typescript
|
|
66
|
+
import type { Socket } from '@steijnveer/fbr-plugin-io';
|
|
67
|
+
|
|
68
|
+
// Special 'connection' event handlers
|
|
69
|
+
export function connection(socket: Socket) {
|
|
70
|
+
log('User connected: ' + socket.id);
|
|
71
|
+
socket.emit('welcome', { message: 'Welcome to the server!' });
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 3. Access Socket.io server instance
|
|
76
|
+
|
|
77
|
+
The Socket.io server instance is available on your server object:
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import type { Io } from '@steijnveer/fbr-plugin-io';
|
|
81
|
+
|
|
82
|
+
// Emit to all connected clients
|
|
83
|
+
server._io.emit('broadcast', { message: 'Hello everyone!' });
|
|
84
|
+
|
|
85
|
+
// Access specific rooms
|
|
86
|
+
server._io.to('room-name').emit('room:message', { text: 'Hello room!' });
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Configuration
|
|
90
|
+
|
|
91
|
+
### Plugin Options
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
interface IoPluginConfig {
|
|
95
|
+
eventsDir?: string; // Directory containing event handlers (default: 'src\\events')
|
|
96
|
+
extensions?: string[]; // File extensions to load (default: ['.ts', '.js'])
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Event Handler Conventions
|
|
101
|
+
|
|
102
|
+
### Event Naming
|
|
103
|
+
|
|
104
|
+
- **File name becomes event prefix**: `message.ts` → `message` event
|
|
105
|
+
- **Named exports**: Use function name as event name
|
|
106
|
+
- `export function join()` in `chat.ts` → `chat:join` event
|
|
107
|
+
- **Default exports**: Use file name as event name
|
|
108
|
+
- `export default function()` in `message.ts` → `message` event
|
|
109
|
+
- **index.ts**: Exports use direct function names
|
|
110
|
+
- `export function connection()` in `index.ts` → `connection` event
|
|
111
|
+
|
|
112
|
+
### Event Handler Signature
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
type EventHandler = (socket: Socket, data: any) => void;
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
- **socket**: The Socket.io socket instance for the connected client
|
|
119
|
+
- **data**: The data sent from the client (null if no data provided)
|
|
120
|
+
|
|
121
|
+
### Special Events
|
|
122
|
+
|
|
123
|
+
- **connection**: Handlers named `connection` are executed when a client connects
|
|
124
|
+
- These handlers run after other event listeners are attached to the socket
|
|
125
|
+
|
|
126
|
+
## Examples
|
|
127
|
+
|
|
128
|
+
### Broadcasting to all clients
|
|
129
|
+
|
|
130
|
+
**src/events/admin.ts**
|
|
131
|
+
```typescript
|
|
132
|
+
import type { Socket } from '@steijnveer/fbr-plugin-io';
|
|
133
|
+
|
|
134
|
+
export function announce(socket: Socket, data: { message: string }) {
|
|
135
|
+
// Broadcast to all clients including sender
|
|
136
|
+
socket.server.emit('announcement', { message: data.message });
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Room-based chat
|
|
141
|
+
|
|
142
|
+
**src/events/room.ts**
|
|
143
|
+
```typescript
|
|
144
|
+
import type { Socket } from '@steijnveer/fbr-plugin-io';
|
|
145
|
+
|
|
146
|
+
export function join(socket: Socket, data: { roomId: string }) {
|
|
147
|
+
socket.join(data.roomId);
|
|
148
|
+
socket.to(data.roomId).emit('room:userJoined', {
|
|
149
|
+
userId: socket.id,
|
|
150
|
+
roomId: data.roomId
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function message(socket: Socket, data: { roomId: string, text: string }) {
|
|
155
|
+
socket.to(data.roomId).emit('room:message', {
|
|
156
|
+
userId: socket.id,
|
|
157
|
+
text: data.text,
|
|
158
|
+
timestamp: Date.now()
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## TypeScript Support
|
|
164
|
+
|
|
165
|
+
The plugin includes full TypeScript support with type definitions:
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
import type {
|
|
169
|
+
Socket, // Socket.io socket instance with type safety
|
|
170
|
+
Io, // Socket.io server instance
|
|
171
|
+
EventsMap, // Event name to handler mapping
|
|
172
|
+
IoPluginConfig // Plugin configuration options
|
|
173
|
+
} from '@steijnveer/fbr-plugin-io';
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Client-Side Usage
|
|
177
|
+
|
|
178
|
+
```html
|
|
179
|
+
<!DOCTYPE html>
|
|
180
|
+
<html>
|
|
181
|
+
<head>
|
|
182
|
+
<script src="/socket.io/socket.io.js"></script>
|
|
183
|
+
</head>
|
|
184
|
+
<body>
|
|
185
|
+
<script>
|
|
186
|
+
const socket = io();
|
|
187
|
+
|
|
188
|
+
// Listen for events
|
|
189
|
+
socket.on('welcome', (data) => {
|
|
190
|
+
console.log(data.message);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// Emit events (matches your handler in message.ts)
|
|
194
|
+
socket.emit('message', { text: 'Hello server!' });
|
|
195
|
+
|
|
196
|
+
// Listen for responses
|
|
197
|
+
socket.on('message:response', (data) => {
|
|
198
|
+
console.log('Echo:', data.echo);
|
|
199
|
+
});
|
|
200
|
+
</script>
|
|
201
|
+
</body>
|
|
202
|
+
</html>
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Debug Logging
|
|
206
|
+
|
|
207
|
+
The plugin includes built-in debug logging for:
|
|
208
|
+
- User connections/disconnections
|
|
209
|
+
- All incoming events with data
|
|
210
|
+
- All outgoing events with data
|
|
211
|
+
|
|
212
|
+
Logs include the socket ID for easy debugging.
|
|
213
|
+
|
|
214
|
+
## License
|
|
215
|
+
|
|
216
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Server } from '@steijnveer/file-based-router';
|
|
2
|
+
import '@steijnveer/file-based-router/utils';
|
|
3
|
+
import type { IoPluginConfig } from './types';
|
|
4
|
+
declare function ioPlugin({ eventsDir, extensions }?: IoPluginConfig): (server: Server) => Promise<void>;
|
|
5
|
+
export default ioPlugin;
|
|
6
|
+
export type * from './types';
|
|
7
|
+
export { ioPlugin };
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,qCAAqC,CAAC;AAK7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAqB9C,iBAAS,QAAQ,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,GAAE,cAAmB,IAEhD,QAAQ,MAAM,mBAyB7B;AAGD,eAAe,QAAQ,CAAC;AACxB,mBAAmB,SAAS,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import '@steijnveer/file-based-router/utils';
|
|
2
|
+
import { readdirSync } from 'fs';
|
|
3
|
+
import { extname, join, resolve } from 'path';
|
|
4
|
+
import { Server as Io } from 'socket.io';
|
|
5
|
+
import { pathToFileURL } from 'url';
|
|
6
|
+
async function importEvents(eventsDir, extensions) {
|
|
7
|
+
const eventsDirPath = resolve(eventsDir);
|
|
8
|
+
const files = readdirSync(eventsDirPath, { withFileTypes: true })
|
|
9
|
+
.filter(entry => entry.isFile() && extensions.includes(extname(entry.name)));
|
|
10
|
+
const events = await Promise.all(files.map(async (file) => {
|
|
11
|
+
const fileName = file.name.replace(extname(file.name), '');
|
|
12
|
+
const module = await import(pathToFileURL(join(eventsDirPath, fileName)).href);
|
|
13
|
+
const eventHandlers = Object.entries(module)
|
|
14
|
+
.filter(([_, handler]) => typeof handler === 'function');
|
|
15
|
+
return fileName === 'index'
|
|
16
|
+
? eventHandlers
|
|
17
|
+
: eventHandlers.map(([exportName, handler]) => [
|
|
18
|
+
exportName === 'default'
|
|
19
|
+
? fileName
|
|
20
|
+
: `${fileName}:${exportName}`, handler
|
|
21
|
+
]);
|
|
22
|
+
}));
|
|
23
|
+
return events.flat();
|
|
24
|
+
}
|
|
25
|
+
function ioPlugin({ eventsDir, extensions } = {}) {
|
|
26
|
+
const eventsPromise = importEvents(eventsDir ?? 'src\\events', extensions ?? ['.ts', '.js']);
|
|
27
|
+
return async (server) => {
|
|
28
|
+
server._io = new Io(server._httpServer);
|
|
29
|
+
const allEvents = await eventsPromise;
|
|
30
|
+
const events = allEvents
|
|
31
|
+
.filter(([eventName]) => eventName !== 'connection');
|
|
32
|
+
const connectionhandlers = allEvents
|
|
33
|
+
.filter(([eventName]) => eventName === 'connection')
|
|
34
|
+
.map(([_, handler]) => handler);
|
|
35
|
+
server._io.on('connection', (socket) => {
|
|
36
|
+
log(`a user connected: ${socket.id}`);
|
|
37
|
+
socket.on('disconnect', () => {
|
|
38
|
+
log(`(${socket.id}) user disconnected`);
|
|
39
|
+
});
|
|
40
|
+
socket.onAny((event, data) => {
|
|
41
|
+
log(`(${socket.id}) Received event: ${event} with args: ${JSON.stringify(data)}`);
|
|
42
|
+
});
|
|
43
|
+
socket.onAnyOutgoing((event, data) => {
|
|
44
|
+
log(`(${socket.id}) Emitting event: ${event} with args: ${JSON.stringify(data)}`);
|
|
45
|
+
});
|
|
46
|
+
for (const [eventName, handler] of events)
|
|
47
|
+
socket.on(eventName, (data) => handler(socket, data ?? null));
|
|
48
|
+
for (const handler of connectionhandlers)
|
|
49
|
+
handler(socket, null);
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export default ioPlugin;
|
|
54
|
+
export { ioPlugin };
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import '@steijnveer/file-based-router/utils';
|
|
2
|
+
import type { Server as IoServer, Socket as IoSocket } from 'socket.io';
|
|
3
|
+
type IoPluginConfig = {
|
|
4
|
+
eventsDir?: string;
|
|
5
|
+
extensions?: string[];
|
|
6
|
+
};
|
|
7
|
+
type EventsMap = Record<string, (data?: any) => void>;
|
|
8
|
+
type Io<SocketData = any> = IoServer<EventsMap, EventsMap, never, SocketData>;
|
|
9
|
+
type Socket<SocketData = any> = IoSocket<EventsMap, EventsMap, never, SocketData>;
|
|
10
|
+
declare module '@steijnveer/file-based-router' {
|
|
11
|
+
interface Server {
|
|
12
|
+
_io: Io;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export type { EventsMap, Io, IoPluginConfig, Socket };
|
|
16
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,qCAAqC,CAAC;AAC7C,OAAO,KAAK,EAAE,MAAM,IAAI,QAAQ,EAAE,MAAM,IAAI,QAAQ,EAAE,MAAM,WAAW,CAAC;AAExE,KAAK,cAAc,GAAG;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB,CAAC;AAEF,KAAK,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC,CAAC;AAEtD,KAAK,EAAE,CAAC,UAAU,GAAG,GAAG,IAAI,QAAQ,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;AAE9E,KAAK,MAAM,CAAC,UAAU,GAAG,GAAG,IAAI,QAAQ,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;AAElF,OAAO,QAAQ,+BAA+B,CAAC;IAC7C,UAAU,MAAM;QACd,GAAG,EAAE,EAAE,CAAC;KACT;CACF;AAGD,YAAY,EAAE,SAAS,EAAE,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '@steijnveer/file-based-router/utils';
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"author": "Steijn Veer",
|
|
3
|
+
"dependencies": {
|
|
4
|
+
"@steijnveer/file-based-router": "^0.0.9",
|
|
5
|
+
"socket.io": "^4.8.3"
|
|
6
|
+
},
|
|
7
|
+
"description": "fbr plugin: Socket.io integration",
|
|
8
|
+
"devDependencies": {
|
|
9
|
+
"@types/express": "^5.0.6",
|
|
10
|
+
"@types/node": "^24.10.1",
|
|
11
|
+
"@types/socket.io": "^3.0.1",
|
|
12
|
+
"typescript": "~5.9.3"
|
|
13
|
+
},
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"import": "./dist/index.js",
|
|
17
|
+
"types": "./dist/index.d.ts"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"README.md"
|
|
23
|
+
],
|
|
24
|
+
"keywords": [
|
|
25
|
+
"fbr",
|
|
26
|
+
"io",
|
|
27
|
+
"socket.io",
|
|
28
|
+
"file-based",
|
|
29
|
+
"plugin",
|
|
30
|
+
"typescript",
|
|
31
|
+
"websocket"
|
|
32
|
+
],
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"main": "./dist/index.js",
|
|
35
|
+
"name": "@steijnveer/fbr-plugin-io",
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsc",
|
|
38
|
+
"prepublishOnly": "npm run build"
|
|
39
|
+
},
|
|
40
|
+
"type": "module",
|
|
41
|
+
"types": "./dist/index.d.ts",
|
|
42
|
+
"version": "0.0.1"
|
|
43
|
+
}
|