Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
ca247e6
feat: add API endpoint to send messages to WebSocket connections
pr0head Apr 3, 2026
fff6da1
feat: refactor WebSocket and SSE stats handlers to reduce code duplic…
pr0head Apr 4, 2026
bcb906c
feat: enhance WebSocket connection management with server-initiated m…
pr0head Apr 4, 2026
9b8a6be
feat: improve error handling for WebSocket message sending and enhanc…
pr0head Apr 4, 2026
ab093f4
feat: implement WebSocket auto-reconnect on mock update and delete
pr0head Apr 5, 2026
9657a8c
feat: add MQTT connection management API with per-client control
zach-snell Apr 5, 2026
dde6e05
feat: implement gRPC connection tracking for streaming RPCs
zach-snell Apr 5, 2026
8443530
feat: implement SSE auto-disconnect on mock update and delete
zach-snell Apr 5, 2026
b6c508b
feat: align SSE response types and add engine tests
zach-snell Apr 5, 2026
26ec035
feat: add CLI connection management commands for all protocols
zach-snell Apr 6, 2026
d001a23
fix: resolve critical and high-priority review findings for unified c…
zach-snell Apr 7, 2026
6ca1126
fix: resolve golangci-lint failures
zach-snell Apr 9, 2026
7f176bb
fix: remaining lint issues - unchecked Fprintf returns and gosec fals…
zach-snell Apr 9, 2026
fb9a477
fix: remove .mcp.json with credentials, add to gitignore
zach-snell Apr 9, 2026
4c6b20f
fix: resolve dupl lint findings in connection handlers
zach-snell Apr 9, 2026
4dee62b
fix: bump Go to 1.26.2 for stdlib CVE fixes (crypto/tls, crypto/x509,…
zach-snell Apr 9, 2026
8d9acf0
fix: remove stale worktree ref, add to gitignore
zach-snell Apr 9, 2026
bfd88c1
fix: bump Dockerfile to Go 1.26.2
zach-snell Apr 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/benchmark.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: "1.26.1"
go-version: "1.26.2"
cache: true

- name: Install Apache Bench
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: "1.26.1"
go-version: "1.26.2"
cache: true

- name: Run golangci-lint
Expand All @@ -38,7 +38,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: "1.26.1"
go-version: "1.26.2"
cache: true

- name: Download dependencies
Expand Down Expand Up @@ -66,7 +66,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: "1.26.1"
go-version: "1.26.2"
cache: true

- name: Install govulncheck
Expand All @@ -87,7 +87,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: "1.26.1"
go-version: "1.26.2"
cache: true

- name: Run E2E tests
Expand All @@ -105,7 +105,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: "1.26.1"
go-version: "1.26.2"
cache: true

- name: Build binary
Expand Down Expand Up @@ -321,7 +321,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: "1.26.1"
go-version: "1.26.2"
cache: true

- name: Build
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/docker.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
name: Docker

on:
pull_request:
branches: [main]
push:
branches: [main]
tags:
- "v*"
workflow_dispatch:

permissions:
contents: read
Expand All @@ -29,6 +32,7 @@ jobs:
uses: docker/setup-buildx-action@v3

- name: Login to GitHub Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
Expand Down Expand Up @@ -63,7 +67,7 @@ jobs:
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,5 @@ completions/
# Dashboard frontend dist (copied from mockd-desktop at release time)
pkg/admin/dashboard/dist/assets/
pkg/admin/dashboard/dist/index.html
.mcp.json
.claude/worktrees/
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- **WebSocket connection management API** — `GET /websocket/connections`, `GET /websocket/connections/{id}`, `DELETE /websocket/connections/{id}`, `POST /websocket/connections/{id}/send`, `GET /websocket/stats` added to the Admin API for real-time visibility, control, and server-initiated messaging of active WebSocket connections
- **SSE connection management API** — `GET /sse/connections`, `GET /sse/connections/{id}`, `DELETE /sse/connections/{id}`, `GET /sse/stats` for managing active SSE connections with auto-disconnect on mock update
- **SSE response type improvements** — SSE connection list responses now include full stats alongside connections
- **MQTT connection management API** — `GET /mqtt-connections`, `GET /mqtt-connections/{id}`, `DELETE /mqtt-connections/{id}`, `GET /mqtt-connections/stats` for managing active MQTT client connections with connection time tracking
- **gRPC stream tracking and management** — `GET /grpc/connections`, `GET /grpc/connections/{id}`, `DELETE /grpc/connections/{id}`, `GET /grpc/stats` for managing active gRPC streaming RPCs with proper Canceled vs Unavailable status codes
- **CLI connection management commands** — `mockd connections list`, `mockd connections get`, `mockd connections close` for all protocols (WebSocket, SSE, MQTT, gRPC)
- **Connection management UI** — unified connections view in the web dashboard showing all active connections across protocols with real-time stats, search, and filtering
- **WebSocket auto-reconnect on mock update** — updating or deleting a WebSocket mock now automatically closes all active connections with close code 1012 (Service Restart) so clients reconnect and pick up the new configuration immediately
- **Workspace-scoped stateful resources** — stateful resources, custom operations, and request logs are now isolated per workspace
- **`--workspace` persistent CLI flag** — scope any CLI command to a specific workspace without switching context
- **`?workspaceId=` API parameter** — all admin API endpoints now accept workspace filtering
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# =============================================================================
# Stage 1: Builder
# =============================================================================
FROM golang:1.26.1-alpine AS builder
FROM golang:1.26.2-alpine AS builder

# Build arguments for version info
ARG VERSION=dev
Expand Down
196 changes: 186 additions & 10 deletions docs/src/content/docs/reference/admin-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,12 @@ The response includes ports for:

### Mock Management

:::note[WebSocket: active clients reconnect on mock changes]
When a WebSocket mock is updated or deleted, all clients currently connected to that endpoint receive a **close frame with code 1012 (Service Restart)**. Most WebSocket client libraries treat code 1012 as a signal to reconnect automatically. On reconnect, the client establishes a fresh connection that uses the new mock configuration.

This applies to `PUT /mocks/{id}`, `DELETE /mocks/{id}`, `POST /mocks/{id}/toggle` (when disabling), bulk `DELETE /mocks` (delete all), and `POST /config` with `replace: true`.
:::

#### GET /mocks

List all configured mocks.
Expand Down Expand Up @@ -929,6 +935,34 @@ Export mocks as Insomnia v4 collection (JSON format, legacy).

List active SSE connections.

**Response:**

```json
{
"connections": [
{
"id": "sse-abc123",
"mockId": "mock-1",
"path": "/events",
"clientIp": "127.0.0.1",
"userAgent": "Mozilla/5.0",
"connectedAt": "2024-01-15T10:30:00Z",
"eventsSent": 42,
"bytesSent": 1024,
"status": "active"
}
],
"stats": {
"totalConnections": 10,
"activeConnections": 1,
"totalEventsSent": 500,
"totalBytesSent": 51200,
"connectionErrors": 0,
"connectionsByMock": {"mock-1": 1}
}
}
```

#### GET /sse/connections/{id}

Get SSE connection details.
Expand All @@ -937,6 +971,10 @@ Get SSE connection details.

Close an SSE connection.

:::note[SSE auto-disconnect on mock update]
When an SSE mock is updated or deleted, all active SSE connections to that endpoint are automatically closed. Clients should reconnect to pick up the new configuration.
:::

#### GET /sse/stats

Get SSE statistics.
Expand All @@ -945,21 +983,46 @@ Get SSE statistics.

### WebSocket Management

#### GET /admin/ws/connections
#### GET /websocket/connections

List active WebSocket connections.

#### GET /admin/ws/connections/{id}
**Response:**

```json
{
"connections": [
{
"id": "ws-abc123",
"mockId": "mock-1",
"path": "/ws/chat",
"connectedAt": "2024-01-15T10:30:00Z",
"messagesSent": 15,
"messagesRecv": 10,
"status": "connected"
}
],
"stats": {
"totalConnections": 50,
"activeConnections": 1,
"totalMessagesSent": 500,
"totalMessagesRecv": 300,
"connectionsByMock": {"mock-1": 1}
}
}
```

#### GET /websocket/connections/{id}

Get connection details.

#### DELETE /admin/ws/connections/{id}
#### DELETE /websocket/connections/{id}

Close a WebSocket connection.

#### POST /admin/ws/connections/{id}/send
#### POST /websocket/connections/{id}/send

Send a message to a specific connection.
Send a text or binary message to a specific active WebSocket connection.

**Request:**

Expand All @@ -970,15 +1033,34 @@ Send a message to a specific connection.
}
```

#### POST /admin/ws/broadcast
| Field | Type | Description |
|-------|------|-------------|
| `type` | string | Message type: `"text"` (default) or `"binary"` |
| `data` | string | Message payload. For `"text"`, a plain UTF-8 string. For `"binary"`, a **base64-encoded** string — the server decodes it before writing raw bytes to the WebSocket. |

Broadcast message to all connections.
**Response:**

#### GET /admin/ws/endpoints
```json
{
"message": "Message sent",
"connection": "ws-abc123",
"type": "text"
}
```

Returns `404` if the connection is not found.

#### GET /mocks/{id}/websocket/connections

List active WebSocket connections for a specific mock.

List configured WebSocket endpoints.
**Response:** Same format as `GET /websocket/connections`, filtered to the given mock ID.

#### GET /admin/ws/stats
#### DELETE /mocks/{id}/websocket/connections

Close all WebSocket connections for a specific mock.

#### GET /websocket/stats

Get WebSocket statistics.

Expand Down Expand Up @@ -1024,6 +1106,100 @@ Stop a replay session.

---

### MQTT Connection Management

#### GET /mqtt-connections

List active MQTT client connections.

**Response:**

```json
{
"connections": [
{
"id": "client-abc123",
"brokerId": "mqtt-broker-1",
"connectedAt": "2024-01-15T10:30:00Z",
"subscriptions": ["sensors/#", "devices/+"],
"protocolVersion": 5,
"username": "device-1",
"remoteAddr": "192.168.1.10:54321",
"status": "connected"
}
],
"stats": {
"connectedClients": 1,
"totalSubscriptions": 2,
"topicCount": 5,
"port": 1883,
"tlsEnabled": false,
"authEnabled": false,
"subscriptionsByClient": {"client-abc123": 2}
}
}
```

#### GET /mqtt-connections/{id}

Get details of a specific MQTT client connection.

#### DELETE /mqtt-connections/{id}

Disconnect an MQTT client.

#### GET /mqtt-connections/stats

Get MQTT connection statistics.

---

### gRPC Stream Management

#### GET /grpc/connections

List active gRPC streaming RPCs.

**Response:**

```json
{
"streams": [
{
"id": "grpc-stream-1",
"method": "/myapp.ChatService/StreamMessages",
"streamType": "bidi",
"clientAddr": "127.0.0.1:54321",
"connectedAt": "2024-01-15T10:30:00Z",
"messagesSent": 15,
"messagesRecv": 10
}
],
"stats": {
"activeStreams": 1,
"totalStreams": 50,
"totalRPCs": 200,
"totalMessagesSent": 1000,
"totalMessagesRecv": 800,
"streamsByMethod": {"/myapp.ChatService/StreamMessages": 1}
}
}
```

#### GET /grpc/connections/{id}

Get details of a specific gRPC stream.

#### DELETE /grpc/connections/{id}

Cancel a gRPC stream. The client receives a `codes.Unavailable` status, signaling it should reconnect.

#### GET /grpc/stats

Get gRPC stream statistics.

---

### gRPC Management

#### GET /grpc
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/getmockd/mockd

go 1.26.1
go 1.26.2

require (
github.com/beevik/etree v1.6.0
Expand Down
Loading
Loading