# 🌊 IoTide

**A powerful, real-time communication layer for secure and modular socket-based networking.**  
Provides the ultimate solution for real-time event management. Designed to make your applications dynamic and responsive, IoTide offers unparalleled flexibility in handling events on-the-fly. Effortlessly create interactive web applications, live data dashboards, chat applications, and collaborative tools with seamless communication between your server and connected clients.

---

## 🚀 Features

- 📡 **Event-Driven Socket Server** – Built with rich customization hooks  
- 🌐 **Flexible HTTPS/HTTP Support** – Easily configure secure or standard transports  
- 🧩 **RoomIO Support** – Enable join, leave, broadcast, and message semantics per room  
- 🧠 **Tide Identity System** – Enforces socket identity using custom or generated IDs  
- 🧰 **Custom Hooks** – Inject your own logic at connection, disconnection, and room events  
- 🏷️ **Dynamic Event Registration** – Easily bind handlers to any incoming socket event  
- 🧼 **Cleanup Utilities** – Manage socket lifecycle, disconnects, and teardown gracefully  

---

## 🧠 Use Cases

IoTide powers secure and scalable systems like:

- Multiplayer game lobbies  
- Real-time dashboards  
- OTA deployment systems  
- Mesh sync engines  
- Collaborative tools  
- Message relays  
- Device/agent coordination
- Just about any application requiring real-time communication

---

## ⚙️ System Requirements

| Requirement    | Version            |
|----------------|--------------------|
| **Node.js**    | ≥ 18.x             |
| **npm**        | ≥ 9.x (recommended)|
| **OS**         | Windows, macOS, Linux |

---

## 🛠️ Constructor

```js
const IoTide = require("@trap_stevo/iotide");

const server = new IoTide(
     3000,
     { useCors : true },
     true,
     (socket) =>  { console.log("Client connected:", socket.id); },
     (_, socket) =>  { console.log("Client disconnected:", socket.id); },
     () =>  { console.log("Server launched"); }
);
```

### Parameters

| Name                          | Type       | Description |
|-------------------------------|------------|-------------|
| `port`                        | `number`   | Port to bind server |
| `options`                     | `object`   | Configuration object (see below) |
| `roomIO`                      | `boolean`  | Enable room/channel functionality |
| `onConnect(socket)`           | `function` | Callback on connection |
| `onDisconnect(ctx, socket)`   | `function` | Callback on disconnect |
| `onLaunch()`                  | `function` | Callback when server launches |
| `joinRoomAction(socket, data)`| `function` | Custom hook on room join |
| `leaveRoomAction(socket, data)`| `function`| Custom hook on room leave |
| `messageRoomAction(...)`      | `function` | Custom hook when messaging a room |
| `removeAllFromRoomAction(...)`| `function` | Custom logic for kicking all from room |

---

## ⚙️ Options

| Option                        | Type      | Description |
|-------------------------------|-----------|-------------|
| `useHTTPS`                   | `boolean` | Use HTTPS server |
| `sslCertPath`                | `string`  | Path to SSL cert |
| `sslKeyPath`                 | `string`  | Path to SSL key |
| `sslCaPath`                  | `string`  | Path to CA chain file |
| `useCors`                    | `boolean` | Enable CORS middleware |
| `corsOptions`                | `object`  | Custom CORS config |
| `tidalCoreOptions`           | `object`  | TidalCore ID config |
| `socketOptions`              | `object`  | Options passed to `socket.io()` |
| `joinChannelEventID`         | `string`  | Event name override |
| `joinedChannelEventID`       | `string`  | Event after successful join |
| `userJoinedChannelEventID`   | `string`  | Broadcast when user joins |
| `allUsersChannelEventID`     | `string`  | Event that lists users in room |
| `messageChannelEventID`      | `string`  | Event to send room message |
| `incomingMessageChannelEventID` | `string` | Incoming message response |
| `leaveChannelEventID`        | `string`  | Leave event name override |
| `userLeftChannelEventID`     | `string`  | Broadcast on leave |
| `onDidNotLaunch`             | `function`| Callback if launch fails |
| `allowLaunchRetry`           | `boolean` | Retry port binding if true |

---

## 🔄 RoomIO Events

| Event             | Payload                            | Description |
|------------------|-------------------------------------|-------------|
| `join room`       | `{ roomName, userID }`             | Join a room |
| `leave room`      | `{ roomName, userID }`             | Leave a room |
| `message room`    | `{ roomName, message, userID }`    | Broadcast message |
| `room joined`     | `{ roomName, userID }`             | Ack of join |
| `user joined`     | `{ userID }`                       | Others notified |
| `user left`       | `{ userID }`                       | Others notified |
| `all users`       | `{ roomName, users : [userID] }`   | Room user list |
| `incoming message`| `{ userID, message }`              | Room message received |

---

## 📚 Specifications

| Method                          | Description                                                                 | Async |
|----------------------------------|-----------------------------------------------------------------------------|--------|
| `emit(event, ...args)`          | Broadcasts an event to all connected sockets                               | ❌     |
| `emitToTide(tideID, event, ...args)` | Emits an event to a specific client by tideID                      | ❌     |
| `emitOnChannel(channel, event, message, userID)` | Broadcasts a message to a specific channel                | ❌     |
| `emitToChannel(tideID, channel, event, message, userID, includeSender?)` | Emits to room, optionally including sender | ❌     |
| `emitTideWithResponse(event, args, eventID, timeout?)` | Emits an event and waits for a response                     | ✅     |
| `emitTide(event, ...args)`      | Emits an event internally for server-side chaining                             | ❌     |
| `on(event, handler, tideGuardian?)` | Registers a handler for any custom event                          | ❌     |
| `onChannel(event, handler, tideGuardian?)` | Registers a handler for a specific channel-scope event        | ❌     |
| `joinChannel(tideID, roomData)` | Joins a socket to a room                                                   | ❌     |
| `leaveChannel(tideID, roomData)`| Removes a socket from a room                                               | ❌     |
| `messageChannel(tideID, roomData)`| Sends a message from a socket to a room                                  | ❌     |
| `removeAllFromChannel(roomData, options?)` | Removes all sockets from a room                                   | ❌     |
| `disconnectTide(tideID, reason?)` | Forcefully disconnects a specific client                                 | ❌     |
| `close()`                       | Shuts down the IoTide server and disconnects all clients                    | ❌     |

---

## 📘 Method Overview

### `emit(event, ...args)`
Broadcast an event globally to all connected sockets.  
Useful for system-wide alerts, status updates, or global sync events.

```js
iotide.emit("system:announcement", {
     message : "Server will restart in 5 minutes"
});
```

---

### `emitToTide(tideID, event, ...args)`
Send a targeted message to a specific socket using its `tideID`.  
Ideal for private messages, acknowledgments, or scoped commands.

```js
iotide.emitToTide("tide-user-123", "notification", {
     title : "New message",
     body : "You have 1 unread message"
});
```

---

### `emitOnChannel(channel, event, message, userID)`
Emit a message to all sockets in a specific room or channel.  
Inject `userID` to track the emitter for logging or replay.

```js
iotide.emitOnChannel("support", "chat:message", "Hello, how can I help?", "agent42");
```

---

### `emitToChannel(tideID, channel, event, message, userID, includeSender = false)`
Send a message to everyone in a room.  
Set `includeSender = true` to include the emitting client in the broadcast.

```js
iotide.emitToChannel("tide-user-123", "general", "chat:message", "Hey everyone!", "user123", true);
```

---

### `emitTide(event, ...args)`
Trigger internal server-side event logic.  
Use this to chain actions as if they were client-driven — ideal for orchestration or flow triggers.

```js
iotide.emitTide("internal:sync:data", { resource : "users" });
```

---

### `emitTideWithResponse(event, args, eventID, timeout = 15000)`
Emit an event and wait for a response tied to a separate event ID.  
Times out if no response returns within the given window.  
Useful for request–response flows, handshake validation, or async control pipelines.

```js
const result = await iotide.emitTideWithResponse("get:status", {}, "status:response");
console.log("Received response:", result);
```

---

### `on(event, handler, tideGuardian = null)`
Attach a handler to a specific event.  
Pass a `tideGuardian` to guard access — see **TideGuardians** below.

```js
iotide.on("upload:file", (socket, fileData) => {
     console.log("Received upload:", fileData);
}, (socket) => socket.userRole === "editor");
```

---

### `onChannel(event, handler, tideGuardian = null)`
Same as `on()`, but scoped to channel-based logic.  
Applies to any room-interaction-based events.

```js
iotide.onChannel("room:edit", (socket, data) => {
     console.log(`Room ${data.roomName} modified`);
});
```

---

### `joinChannel(tideID, roomData)`
Manually join a socket to a room.  
Useful when bypassing the default `"join room"` event, or initiating on behalf of a socket.

```js
iotide.joinChannel("tide-user-456", { roomName : "admin", userID : "admin456" });
```

---

### `leaveChannel(tideID, roomData)`
Force a socket to leave a specific room.  
Typically paired with permission logic or cleanup routines.

```js
iotide.leaveChannel("tide-user-456", { roomName : "admin", userID : "admin456" });
```

---

### `messageChannel(tideID, roomData)`
Push a message into a room from a specific user.  
IoTide handles rebroadcasting to all members.

```js
iotide.messageChannel("tide-user-789", {
     roomName : "support",
     message : "Customer left the chat",
     userID : "support-bot"
});
```

---

### `removeAllFromChannel(roomData, options = {})`
Remove every socket from a specified room.  
Inject optional logic for permission checks or state cleanup via `options`.

```js
iotide.removeAllFromChannel({ roomName : "beta-testers" });
```

---

### `disconnectTide(tideID, reason = "manual disconnect")`
Disconnect a specific socket.  
Specify a `reason` for auditing or in-client diagnostics.

```js
iotide.disconnectTide("tide-user-321", "Idle too long");
```

---

### `close()`
Gracefully shut down the server and disconnect all clients.  
Use this during process exits, restarts, or maintenance flows.

```js
process.on("SIGINT", () => {
     iotide.close();
     process.exit();
});
```

---

## 🧱 TideGuardians

**TideGuardians** enforce access control for event handlers.  
Use them to validate context, roles, or message content before proceeding.

### Example

```js
iotide.on("admin:delete", (socket, data) => {
     console.log("Deleting entry:", data.id);
}, (socket) => socket.userRole === "admin");
```

If the guardian returns `false`, IoTide skips the handler and denies the action.

Use TideGuardians to:

- Protect privileged events
- Enforce custom permissions
- Apply rule-based logic without bloating handlers

---

## 🔐 TidalCore Integration

Each **IoTide server instance** holds a unique `tideID` generated by **TidalCore**.  
This identifier supports:

- Authenticating across multiple IoTide nodes  
- Synchronizing trusted events between server instances  
- Logging session fingerprints tied to the server  
- Validating signed identity payloads

Access the server’s identity:

```js
const myTideID = iotide.ioTideID;
```

All connected sockets receive scoped identifiers for targeted communication and tracking.  
Custom identity flows or authorization layers can further enhance validation.

---

---

## 📦 Installation

```bash
npm install @trap_stevo/iotide
```

---

## 💡 Example Usage

```js
const IoTide = require("@trap_stevo/iotide");

const iotide = new IoTide(443, {
     useHTTPS : true,
     sslCertPath : "./cert.pem",
     sslKeyPath : "./key.pem",
     useCors : true,
     corsOptions : { origin : "*" }
}, true, (socket) => {
     console.log("Connected:", socket.tideID);
}, null, () => {
     console.log("IoTide server launched");
});
```

---

## 📜 License

[SCL-1.0-Universal](./SCL-1.0-Universal.md)

---

## 🌟 IoTide: Real-time Networking Made Legendary

Use IoTide to bridge everything — users, apps, devices, or microservices — with clean event architecture, ID-aware logic, and cross-room control.

> **Built for performance. Designed for flexibility. Yours to shape.**
