@agentxjs/portagent 0.1.8 → 1.0.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.
- package/README.md +357 -0
- package/dist/public/Portagent.gif +0 -0
- package/dist/public/assets/index-1uLnFQV1.js +2 -0
- package/dist/public/assets/index-1uLnFQV1.js.map +1 -0
- package/dist/public/assets/{index-CNC7DxMj.js → index-Bq2LVeC5.js} +54 -54
- package/dist/public/assets/index-Bq2LVeC5.js.map +1 -0
- package/dist/public/assets/reconnecting-websocket-mjs-Dd04wD44.js +20 -0
- package/dist/public/assets/reconnecting-websocket-mjs-Dd04wD44.js.map +1 -0
- package/dist/public/index.html +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/package.json +4 -4
- package/dist/public/assets/index-CNC7DxMj.js.map +0 -1
package/README.md
ADDED
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
# Portagent
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
Portagent is a multi-user AI Agent gateway powered by [AgentX](https://github.com/Deepractice/AgentX). It provides a web-based interface for interacting with Claude AI agents, with built-in user authentication and session management.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Multi-User Support**: User registration and authentication with JWT tokens
|
|
10
|
+
- **WebSocket Communication**: Real-time bidirectional communication with AI agents
|
|
11
|
+
- **Invite Code System**: Optional invite code for controlled access
|
|
12
|
+
- **Persistent Storage**: SQLite-based storage for users, sessions, and agent data
|
|
13
|
+
- **Docker Ready**: Pre-built Docker images for easy deployment
|
|
14
|
+
- **Claude Integration**: Powered by Anthropic's Claude API via Claude Agent SDK
|
|
15
|
+
|
|
16
|
+
## Quick Start
|
|
17
|
+
|
|
18
|
+
### Using Docker (Recommended)
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
docker run -d \
|
|
22
|
+
--name portagent \
|
|
23
|
+
-p 5200:5200 \
|
|
24
|
+
-e LLM_PROVIDER_KEY=sk-ant-xxxxx \
|
|
25
|
+
-v ./data:/home/agentx/.agentx \
|
|
26
|
+
deepracticexs/portagent:latest
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Then open <http://localhost:5200> in your browser.
|
|
30
|
+
|
|
31
|
+
### Using Docker Compose
|
|
32
|
+
|
|
33
|
+
Create a `.env` file:
|
|
34
|
+
|
|
35
|
+
```env
|
|
36
|
+
LLM_PROVIDER_KEY=sk-ant-xxxxx
|
|
37
|
+
JWT_SECRET=your-secure-random-secret
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Create `docker-compose.yml`:
|
|
41
|
+
|
|
42
|
+
```yaml
|
|
43
|
+
services:
|
|
44
|
+
portagent:
|
|
45
|
+
image: deepracticexs/portagent:latest
|
|
46
|
+
container_name: portagent
|
|
47
|
+
restart: unless-stopped
|
|
48
|
+
ports:
|
|
49
|
+
- "5200:5200"
|
|
50
|
+
environment:
|
|
51
|
+
- LLM_PROVIDER_KEY=${LLM_PROVIDER_KEY}
|
|
52
|
+
- LLM_PROVIDER_URL=${LLM_PROVIDER_URL:-https://api.anthropic.com}
|
|
53
|
+
- LLM_PROVIDER_MODEL=${LLM_PROVIDER_MODEL:-claude-sonnet-4-20250514}
|
|
54
|
+
- JWT_SECRET=${JWT_SECRET}
|
|
55
|
+
- INVITE_CODE_REQUIRED=${INVITE_CODE_REQUIRED:-false}
|
|
56
|
+
- LOG_LEVEL=${LOG_LEVEL:-info}
|
|
57
|
+
volumes:
|
|
58
|
+
- ./data:/home/agentx/.agentx
|
|
59
|
+
healthcheck:
|
|
60
|
+
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:5200/health"]
|
|
61
|
+
interval: 30s
|
|
62
|
+
timeout: 10s
|
|
63
|
+
start_period: 5s
|
|
64
|
+
retries: 3
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Run:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
docker compose up -d
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Using npm
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Install globally
|
|
77
|
+
npm install -g @agentxjs/portagent
|
|
78
|
+
|
|
79
|
+
# Run with required API key
|
|
80
|
+
export LLM_PROVIDER_KEY=sk-ant-xxxxx
|
|
81
|
+
portagent
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Configuration
|
|
85
|
+
|
|
86
|
+
### Environment Variables
|
|
87
|
+
|
|
88
|
+
| Variable | Required | Default | Description |
|
|
89
|
+
| ---------------------- | -------- | --------------------------- | ------------------------------------------- |
|
|
90
|
+
| `LLM_PROVIDER_KEY` | **Yes** | - | Anthropic API key (starts with `sk-ant-`) |
|
|
91
|
+
| `LLM_PROVIDER_URL` | No | `https://api.anthropic.com` | API base URL |
|
|
92
|
+
| `LLM_PROVIDER_MODEL` | No | `claude-sonnet-4-20250514` | Claude model to use |
|
|
93
|
+
| `PORT` | No | `5200` | Server port |
|
|
94
|
+
| `DATA_DIR` | No | `~/.agentx` | Data directory path |
|
|
95
|
+
| `JWT_SECRET` | No | Auto-generated | Secret for JWT token signing |
|
|
96
|
+
| `INVITE_CODE_REQUIRED` | No | `false` | Require invite code for registration |
|
|
97
|
+
| `LOG_LEVEL` | No | `info` | Log level: `debug`, `info`, `warn`, `error` |
|
|
98
|
+
| `NODE_ENV` | No | `production` | Environment mode |
|
|
99
|
+
|
|
100
|
+
### CLI Options
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
portagent [options]
|
|
104
|
+
|
|
105
|
+
Options:
|
|
106
|
+
-p, --port <port> Port to listen on (default: 5200)
|
|
107
|
+
-d, --data-dir <path> Data directory (default: ~/.agentx)
|
|
108
|
+
-e, --env-file <path> Path to environment file
|
|
109
|
+
--jwt-secret <secret> JWT secret for token signing
|
|
110
|
+
--api-key <key> LLM provider API key
|
|
111
|
+
--api-url <url> LLM provider base URL
|
|
112
|
+
--model <model> LLM model name
|
|
113
|
+
-h, --help Display help
|
|
114
|
+
-V, --version Display version
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Data Directory Structure
|
|
118
|
+
|
|
119
|
+
```text
|
|
120
|
+
~/.agentx/ # Default data directory (configurable via DATA_DIR)
|
|
121
|
+
├── data/ # Database files
|
|
122
|
+
│ ├── agentx.db # AgentX data (containers, images, sessions)
|
|
123
|
+
│ └── portagent.db # User authentication data
|
|
124
|
+
└── logs/ # Log files
|
|
125
|
+
└── portagent.log
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Invite Code System
|
|
129
|
+
|
|
130
|
+
Portagent uses a daily rotating invite code for registration security. The invite code is the **Unix timestamp (in seconds) of today's 00:00:01** in the server's timezone.
|
|
131
|
+
|
|
132
|
+
### Calculating the Invite Code
|
|
133
|
+
|
|
134
|
+
**Linux/macOS:**
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
# For server's local timezone
|
|
138
|
+
date -d "today 00:00:01" +%s
|
|
139
|
+
|
|
140
|
+
# For UTC (Docker default)
|
|
141
|
+
TZ=UTC date -d "today 00:00:01" +%s
|
|
142
|
+
|
|
143
|
+
# macOS syntax
|
|
144
|
+
date -j -f "%Y-%m-%d %H:%M:%S" "$(date +%Y-%m-%d) 00:00:01" "+%s"
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**JavaScript:**
|
|
148
|
+
|
|
149
|
+
```javascript
|
|
150
|
+
// Server's local timezone
|
|
151
|
+
const now = new Date();
|
|
152
|
+
const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 1);
|
|
153
|
+
const inviteCode = Math.floor(todayStart.getTime() / 1000);
|
|
154
|
+
console.log(inviteCode);
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Note:** Docker containers typically run in UTC timezone. Make sure to calculate the invite code for the correct timezone.
|
|
158
|
+
|
|
159
|
+
### Enabling Invite Codes
|
|
160
|
+
|
|
161
|
+
Set `INVITE_CODE_REQUIRED=true` to require invite codes for registration:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
docker run -e INVITE_CODE_REQUIRED=true ...
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## API Endpoints
|
|
168
|
+
|
|
169
|
+
| Method | Path | Auth | Description |
|
|
170
|
+
| ------ | -------------------- | ---- | ---------------------- |
|
|
171
|
+
| GET | `/health` | No | Health check |
|
|
172
|
+
| GET | `/api/auth/config` | No | Get auth configuration |
|
|
173
|
+
| POST | `/api/auth/register` | No | Register new user |
|
|
174
|
+
| POST | `/api/auth/login` | No | Login |
|
|
175
|
+
| GET | `/api/auth/verify` | Yes | Verify token |
|
|
176
|
+
| POST | `/api/auth/logout` | No | Logout (client-side) |
|
|
177
|
+
| GET | `/agentx/info` | Yes | Get platform info |
|
|
178
|
+
| WS | `/ws` | Yes | WebSocket connection |
|
|
179
|
+
|
|
180
|
+
### Authentication
|
|
181
|
+
|
|
182
|
+
All protected endpoints require a JWT token in the Authorization header:
|
|
183
|
+
|
|
184
|
+
```text
|
|
185
|
+
Authorization: Bearer <token>
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
For WebSocket connections (which don't support headers), pass the token as a query parameter:
|
|
189
|
+
|
|
190
|
+
```text
|
|
191
|
+
ws://localhost:5200/ws?token=<token>
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Register
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
curl -X POST http://localhost:5200/api/auth/register \
|
|
198
|
+
-H "Content-Type: application/json" \
|
|
199
|
+
-d '{
|
|
200
|
+
"username": "john",
|
|
201
|
+
"password": "secret123",
|
|
202
|
+
"inviteCode": "1765152001",
|
|
203
|
+
"email": "john@example.com",
|
|
204
|
+
"displayName": "John Doe"
|
|
205
|
+
}'
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Login
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
curl -X POST http://localhost:5200/api/auth/login \
|
|
212
|
+
-H "Content-Type: application/json" \
|
|
213
|
+
-d '{
|
|
214
|
+
"usernameOrEmail": "john",
|
|
215
|
+
"password": "secret123"
|
|
216
|
+
}'
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Docker Images
|
|
220
|
+
|
|
221
|
+
Pre-built images are available on Docker Hub:
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
# Latest version
|
|
225
|
+
docker pull deepracticexs/portagent:latest
|
|
226
|
+
|
|
227
|
+
# Specific version
|
|
228
|
+
docker pull deepracticexs/portagent:0.1.9
|
|
229
|
+
|
|
230
|
+
# Available architectures: linux/amd64, linux/arm64
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Building Locally
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
# From repository root
|
|
237
|
+
docker build -t portagent:local -f apps/portagent/Dockerfile .
|
|
238
|
+
|
|
239
|
+
# Run local build
|
|
240
|
+
docker run -d \
|
|
241
|
+
--name portagent \
|
|
242
|
+
-p 5200:5200 \
|
|
243
|
+
-e LLM_PROVIDER_KEY=sk-ant-xxxxx \
|
|
244
|
+
portagent:local
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Production Deployment
|
|
248
|
+
|
|
249
|
+
### Recommended Settings
|
|
250
|
+
|
|
251
|
+
```yaml
|
|
252
|
+
services:
|
|
253
|
+
portagent:
|
|
254
|
+
image: deepracticexs/portagent:0.1.9 # Pin to specific version
|
|
255
|
+
restart: unless-stopped
|
|
256
|
+
environment:
|
|
257
|
+
- LLM_PROVIDER_KEY=${LLM_PROVIDER_KEY}
|
|
258
|
+
- JWT_SECRET=${JWT_SECRET} # Use a strong, persistent secret
|
|
259
|
+
- INVITE_CODE_REQUIRED=true # Enable for production
|
|
260
|
+
- LOG_LEVEL=info
|
|
261
|
+
volumes:
|
|
262
|
+
- ./data:/home/agentx/.agentx # Persist data
|
|
263
|
+
ports:
|
|
264
|
+
- "5200:5200"
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Security Considerations
|
|
268
|
+
|
|
269
|
+
1. **API Key**: Never expose `LLM_PROVIDER_KEY` in client-side code or logs
|
|
270
|
+
2. **JWT Secret**: Use a strong, random secret and keep it consistent across restarts
|
|
271
|
+
3. **Invite Codes**: Enable invite codes in production to control access
|
|
272
|
+
4. **HTTPS**: Use a reverse proxy (nginx, Caddy) with TLS in production
|
|
273
|
+
5. **Volume Permissions**: The container runs as non-root user (uid 1001)
|
|
274
|
+
|
|
275
|
+
### Reverse Proxy (nginx example)
|
|
276
|
+
|
|
277
|
+
```nginx
|
|
278
|
+
server {
|
|
279
|
+
listen 443 ssl;
|
|
280
|
+
server_name portagent.example.com;
|
|
281
|
+
|
|
282
|
+
ssl_certificate /path/to/cert.pem;
|
|
283
|
+
ssl_certificate_key /path/to/key.pem;
|
|
284
|
+
|
|
285
|
+
location / {
|
|
286
|
+
proxy_pass http://localhost:5200;
|
|
287
|
+
proxy_http_version 1.1;
|
|
288
|
+
proxy_set_header Upgrade $http_upgrade;
|
|
289
|
+
proxy_set_header Connection "upgrade";
|
|
290
|
+
proxy_set_header Host $host;
|
|
291
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
## Troubleshooting
|
|
297
|
+
|
|
298
|
+
### "LLM_PROVIDER_KEY is required"
|
|
299
|
+
|
|
300
|
+
- Ensure `LLM_PROVIDER_KEY` environment variable is set
|
|
301
|
+
- For Docker, use `-e LLM_PROVIDER_KEY=xxx` or `environment:` in compose
|
|
302
|
+
|
|
303
|
+
### "Invalid invite code"
|
|
304
|
+
|
|
305
|
+
- Invite code changes daily at midnight (server timezone)
|
|
306
|
+
- Docker uses UTC by default
|
|
307
|
+
- Calculate code for correct timezone (see Invite Code section)
|
|
308
|
+
- Set `INVITE_CODE_REQUIRED=false` to disable
|
|
309
|
+
|
|
310
|
+
### Permission denied errors
|
|
311
|
+
|
|
312
|
+
- Docker container runs as user `agentx` (uid 1001)
|
|
313
|
+
- Ensure mounted volumes have correct permissions:
|
|
314
|
+
|
|
315
|
+
```bash
|
|
316
|
+
sudo chown -R 1001:1001 ./data
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### WebSocket connection fails
|
|
320
|
+
|
|
321
|
+
- Ensure token is passed as query parameter for WS connections
|
|
322
|
+
- Check reverse proxy WebSocket configuration
|
|
323
|
+
|
|
324
|
+
### Viewing Logs
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
# Docker logs
|
|
328
|
+
docker logs portagent
|
|
329
|
+
|
|
330
|
+
# Follow logs
|
|
331
|
+
docker logs -f portagent
|
|
332
|
+
|
|
333
|
+
# Log files inside container
|
|
334
|
+
docker exec portagent cat /home/agentx/.agentx/logs/portagent.log
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
## Development
|
|
338
|
+
|
|
339
|
+
```bash
|
|
340
|
+
# Clone repository
|
|
341
|
+
git clone https://github.com/Deepractice/AgentX.git
|
|
342
|
+
cd AgentX
|
|
343
|
+
|
|
344
|
+
# Install dependencies
|
|
345
|
+
pnpm install
|
|
346
|
+
|
|
347
|
+
# Build all packages
|
|
348
|
+
pnpm build
|
|
349
|
+
|
|
350
|
+
# Start development server
|
|
351
|
+
cd apps/portagent
|
|
352
|
+
pnpm dev
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
## License
|
|
356
|
+
|
|
357
|
+
MIT License - see [LICENSE](./LICENSE) for details.
|
|
Binary file
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{_ as w}from"./index-Bq2LVeC5.js";var p=Object.defineProperty,m=(e,r,t)=>r in e?p(e,r,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[r]=t,c=(e,r,t)=>m(e,typeof r!="symbol"?r+"":r,t),b=class u{constructor(r,t={}){c(this,"name"),c(this,"level"),c(this,"colors"),c(this,"timestamps"),this.name=r,this.level=t.level??"info",this.colors=t.colors??this.isNodeEnvironment(),this.timestamps=t.timestamps??!0}debug(r,t){this.isDebugEnabled()&&this.log("DEBUG",r,t)}info(r,t){this.isInfoEnabled()&&this.log("INFO",r,t)}warn(r,t){this.isWarnEnabled()&&this.log("WARN",r,t)}error(r,t){this.isErrorEnabled()&&(r instanceof Error?this.log("ERROR",r.message,{...t,stack:r.stack}):this.log("ERROR",r,t))}isDebugEnabled(){return this.getLevelValue(this.level)<=this.getLevelValue("debug")}isInfoEnabled(){return this.getLevelValue(this.level)<=this.getLevelValue("info")}isWarnEnabled(){return this.getLevelValue(this.level)<=this.getLevelValue("warn")}isErrorEnabled(){return this.getLevelValue(this.level)<=this.getLevelValue("error")}getLevelValue(r){return{debug:0,info:1,warn:2,error:3,silent:4}[r]}log(r,t,o){const s=[];if(this.timestamps&&s.push(new Date().toISOString()),this.colors){const d=u.COLORS[r];s.push(`${d}${r.padEnd(5)}${u.COLORS.RESET}`)}else s.push(r.padEnd(5));s.push(`[${this.name}]`),s.push(t);const n=s.join(" "),l=this.getConsoleMethod(r);o&&Object.keys(o).length>0?l(n,o):l(n)}getConsoleMethod(r){switch(r){case"DEBUG":return console.debug.bind(console);case"INFO":return console.info.bind(console);case"WARN":return console.warn.bind(console);case"ERROR":return console.error.bind(console);default:return console.log.bind(console)}}isNodeEnvironment(){var r;return typeof process<"u"&&((r=process.versions)==null?void 0:r.node)!==void 0}};c(b,"COLORS",{DEBUG:"\x1B[36m",INFO:"\x1B[32m",WARN:"\x1B[33m",ERROR:"\x1B[31m",RESET:"\x1B[0m"});var E=b,h=null,g=class{static getLogger(e){const r=typeof e=="string"?e:e.name;if(this.loggers.has(r))return this.loggers.get(r);const t=this.createLazyLogger(r);return this.loggers.set(r,t),t}static configure(e){this.config={...this.config,...e}}static reset(){this.loggers.clear(),this.config={defaultLevel:"info"},h=null}static createLazyLogger(e){let r=null;const t=()=>(r||(r=this.createLogger(e)),r);return{name:e,level:this.config.defaultLevel||"info",debug:(o,s)=>t().debug(o,s),info:(o,s)=>t().info(o,s),warn:(o,s)=>t().warn(o,s),error:(o,s)=>t().error(o,s),isDebugEnabled:()=>t().isDebugEnabled(),isInfoEnabled:()=>t().isInfoEnabled(),isWarnEnabled:()=>t().isWarnEnabled(),isErrorEnabled:()=>t().isErrorEnabled()}}static createLogger(e){return h?h.getLogger(e):this.config.defaultImplementation?this.config.defaultImplementation(e):new E(e,{level:this.config.defaultLevel,...this.config.consoleOptions})}};c(g,"loggers",new Map);c(g,"config",{defaultLevel:"info"});function v(e){return g.getLogger(e)}var S=Object.defineProperty,H=(e,r,t)=>r in e?S(e,r,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[r]=t,i=(e,r,t)=>H(e,typeof r!="symbol"?r+"":r,t),a=v("network/WebSocketClient"),f=typeof globalThis<"u"&&typeof globalThis.window<"u"&&typeof globalThis.window.WebSocket<"u",L=class{constructor(e){if(i(this,"ws",null),i(this,"serverUrl"),i(this,"messageHandlers",new Set),i(this,"openHandlers",new Set),i(this,"closeHandlers",new Set),i(this,"errorHandlers",new Set),f)throw new Error("Use createBrowserWebSocketClient() in browser environment for auto-reconnect support");this.serverUrl=e.serverUrl}get readyState(){if(!this.ws)return"closed";const e=this.ws.readyState;return e===0?"connecting":e===1?"open":e===2?"closing":"closed"}async connect(){if(this.ws)throw new Error("Already connected or connecting");const{WebSocket:e}=await w(async()=>{const{WebSocket:r}=await import("./browser-C0DG1J1h.js").then(t=>t.b);return{WebSocket:r}},[]);return this.ws=new e(this.serverUrl),new Promise((r,t)=>{const o=()=>{a.info("WebSocket connected",{serverUrl:this.serverUrl});for(const n of this.openHandlers)n();r()},s=n=>{a.error("WebSocket connection failed",{serverUrl:this.serverUrl,error:n==null?void 0:n.message}),t(n||new Error("WebSocket connection failed"))};this.ws.once("open",o),this.ws.once("error",s),this.ws.on("message",n=>{const l=n.toString();for(const d of this.messageHandlers)d(l)}),this.ws.on("close",()=>{a.warn("WebSocket closed");for(const n of this.closeHandlers)n()}),this.ws.on("error",n=>{a.error("WebSocket error",{error:n.message});for(const l of this.errorHandlers)l(n)})})}send(e){if(!this.ws||this.ws.readyState!==1)throw new Error("WebSocket is not open");this.ws.send(e)}onMessage(e){return this.messageHandlers.add(e),()=>{this.messageHandlers.delete(e)}}onOpen(e){return this.openHandlers.add(e),()=>{this.openHandlers.delete(e)}}onClose(e){return this.closeHandlers.add(e),()=>{this.closeHandlers.delete(e)}}onError(e){return this.errorHandlers.add(e),()=>{this.errorHandlers.delete(e)}}close(){this.ws&&(this.ws.close(),this.ws=null)}dispose(){this.close(),this.messageHandlers.clear(),this.openHandlers.clear(),this.closeHandlers.clear(),this.errorHandlers.clear()}},W=class{constructor(e){if(i(this,"ws",null),i(this,"serverUrl"),i(this,"options"),i(this,"messageHandlers",new Set),i(this,"openHandlers",new Set),i(this,"closeHandlers",new Set),i(this,"errorHandlers",new Set),i(this,"hasConnectedBefore",!1),!f)throw new Error("BrowserWebSocketClient can only be used in browser environment");this.serverUrl=e.serverUrl,this.options={autoReconnect:!0,minReconnectionDelay:1e3,maxReconnectionDelay:1e4,maxRetries:1/0,connectionTimeout:4e3,debug:!1,...e}}get readyState(){if(!this.ws)return"closed";const e=this.ws.readyState;return e===0?"connecting":e===1?"open":e===2?"closing":"closed"}async connect(){if(this.ws)throw new Error("Already connected or connecting");if(this.options.autoReconnect){const e=(await w(async()=>{const{default:r}=await import("./reconnecting-websocket-mjs-Dd04wD44.js");return{default:r}},[])).default;this.ws=new e(this.serverUrl,[],{maxReconnectionDelay:this.options.maxReconnectionDelay,minReconnectionDelay:this.options.minReconnectionDelay,reconnectionDelayGrowFactor:1.3,connectionTimeout:this.options.connectionTimeout,maxRetries:this.options.maxRetries,debug:this.options.debug})}else this.ws=new WebSocket(this.serverUrl);return new Promise((e,r)=>{const t=()=>{this.hasConnectedBefore?a.info("WebSocket reconnected successfully",{serverUrl:this.serverUrl}):(a.info("WebSocket connected",{serverUrl:this.serverUrl}),this.hasConnectedBefore=!0);for(const s of this.openHandlers)s();e()},o=s=>{a.error("WebSocket connection failed",{serverUrl:this.serverUrl});const n=new Error("WebSocket connection failed");for(const l of this.errorHandlers)l(n);r(n)};this.ws.addEventListener("open",t,{once:!0}),this.ws.addEventListener("error",o,{once:!0}),this.ws.addEventListener("message",(s=>{const n=s.data;for(const l of this.messageHandlers)l(n)})),this.ws.addEventListener("close",(()=>{a.info("WebSocket closed, attempting to reconnect...");for(const s of this.closeHandlers)s()})),this.ws.addEventListener("error",(s=>{a.error("WebSocket error");const n=new Error("WebSocket error");for(const l of this.errorHandlers)l(n)}))})}send(e){if(!this.ws||this.ws.readyState!==1)throw new Error("WebSocket is not open");this.ws.send(e)}onMessage(e){return this.messageHandlers.add(e),()=>{this.messageHandlers.delete(e)}}onOpen(e){return this.openHandlers.add(e),()=>{this.openHandlers.delete(e)}}onClose(e){return this.closeHandlers.add(e),()=>{this.closeHandlers.delete(e)}}onError(e){return this.errorHandlers.add(e),()=>{this.errorHandlers.delete(e)}}close(){this.ws&&(this.ws.close(),this.ws=null)}dispose(){this.close(),this.messageHandlers.clear(),this.openHandlers.clear(),this.closeHandlers.clear(),this.errorHandlers.clear()}};async function y(e){if(f){const r=new W(e);return await r.connect(),r}else{const r=new L(e);return await r.connect(),r}}v("network/WebSocketServer");export{L as WebSocketClient,y as createWebSocketClient};
|
|
2
|
+
//# sourceMappingURL=index-1uLnFQV1.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"mappings":"wCAAA,IAAIA,EAAY,OAAO,eACnBC,EAAkB,CAACC,EAAKC,EAAKC,IAAUD,KAAOD,EAAMF,EAAUE,EAAKC,EAAK,CAAE,WAAY,GAAM,aAAc,GAAM,SAAU,GAAM,MAAAC,CAAK,CAAE,EAAIF,EAAIC,CAAG,EAAIC,EACtJC,EAAgB,CAACH,EAAKC,EAAKC,IAAUH,EAAgBC,EAAK,OAAOC,GAAQ,SAAWA,EAAM,GAAKA,EAAKC,CAAK,EAGzGE,EAAiB,MAAMA,CAAe,CACxC,YAAYC,EAAMC,EAAU,GAAI,CAC9BH,EAAc,KAAM,MAAM,EAC1BA,EAAc,KAAM,OAAO,EAC3BA,EAAc,KAAM,QAAQ,EAC5BA,EAAc,KAAM,YAAY,EAChC,KAAK,KAAOE,EACZ,KAAK,MAAQC,EAAQ,OAAS,OAC9B,KAAK,OAASA,EAAQ,QAAU,KAAK,kBAAiB,EACtD,KAAK,WAAaA,EAAQ,YAAc,EAC1C,CACA,MAAMC,EAASC,EAAS,CAClB,KAAK,kBACP,KAAK,IAAI,QAASD,EAASC,CAAO,CAEtC,CACA,KAAKD,EAASC,EAAS,CACjB,KAAK,iBACP,KAAK,IAAI,OAAQD,EAASC,CAAO,CAErC,CACA,KAAKD,EAASC,EAAS,CACjB,KAAK,iBACP,KAAK,IAAI,OAAQD,EAASC,CAAO,CAErC,CACA,MAAMD,EAASC,EAAS,CAClB,KAAK,mBACHD,aAAmB,MACrB,KAAK,IAAI,QAASA,EAAQ,QAAS,CAAE,GAAGC,EAAS,MAAOD,EAAQ,MAAO,EAEvE,KAAK,IAAI,QAASA,EAASC,CAAO,EAGxC,CACA,gBAAiB,CACf,OAAO,KAAK,cAAc,KAAK,KAAK,GAAK,KAAK,cAAc,OAAO,CACrE,CACA,eAAgB,CACd,OAAO,KAAK,cAAc,KAAK,KAAK,GAAK,KAAK,cAAc,MAAM,CACpE,CACA,eAAgB,CACd,OAAO,KAAK,cAAc,KAAK,KAAK,GAAK,KAAK,cAAc,MAAM,CACpE,CACA,gBAAiB,CACf,OAAO,KAAK,cAAc,KAAK,KAAK,GAAK,KAAK,cAAc,OAAO,CACrE,CACA,cAAcC,EAAO,CAQnB,MAPe,CACb,MAAO,EACP,KAAM,EACN,KAAM,EACN,MAAO,EACP,OAAQ,CACd,EACkBA,CAAK,CACrB,CACA,IAAIA,EAAOF,EAASC,EAAS,CAC3B,MAAME,EAAQ,GAId,GAHI,KAAK,YACPA,EAAM,KAAsB,IAAI,KAAI,EAAI,YAAW,CAAE,EAEnD,KAAK,OAAQ,CACf,MAAMC,EAAQP,EAAe,OAAOK,CAAK,EACzCC,EAAM,KAAK,GAAGC,CAAK,GAAGF,EAAM,OAAO,CAAC,CAAC,GAAGL,EAAe,OAAO,KAAK,EAAE,CACvE,MACEM,EAAM,KAAKD,EAAM,OAAO,CAAC,CAAC,EAE5BC,EAAM,KAAK,IAAI,KAAK,IAAI,GAAG,EAC3BA,EAAM,KAAKH,CAAO,EAClB,MAAMK,EAAUF,EAAM,KAAK,GAAG,EACxBG,EAAgB,KAAK,iBAAiBJ,CAAK,EAC7CD,GAAW,OAAO,KAAKA,CAAO,EAAE,OAAS,EAC3CK,EAAcD,EAASJ,CAAO,EAE9BK,EAAcD,CAAO,CAEzB,CACA,iBAAiBH,EAAO,CACtB,OAAQA,EAAK,CACX,IAAK,QACH,OAAO,QAAQ,MAAM,KAAK,OAAO,EACnC,IAAK,OACH,OAAO,QAAQ,KAAK,KAAK,OAAO,EAClC,IAAK,OACH,OAAO,QAAQ,KAAK,KAAK,OAAO,EAClC,IAAK,QACH,OAAO,QAAQ,MAAM,KAAK,OAAO,EACnC,QACE,OAAO,QAAQ,IAAI,KAAK,OAAO,CACvC,CACE,CACA,mBAAoB,OAClB,OAAO,OAAO,QAAY,OAAeK,EAAA,QAAQ,WAAR,YAAAA,EAAkB,QAAS,MACtE,CACF,EACAX,EAAcC,EAAgB,SAAU,CACtC,MAAO,WACP,KAAM,WACN,KAAM,WACN,MAAO,WACP,MAAO,SACT,CAAC,EACD,IAAIW,EAAgBX,EAGhBY,EAAkB,KAClBC,EAAoB,KAAM,CAC5B,OAAO,UAAUC,EAAa,CAC5B,MAAMb,EAAO,OAAOa,GAAgB,SAAWA,EAAcA,EAAY,KACzE,GAAI,KAAK,QAAQ,IAAIb,CAAI,EACvB,OAAO,KAAK,QAAQ,IAAIA,CAAI,EAE9B,MAAMc,EAAa,KAAK,iBAAiBd,CAAI,EAC7C,YAAK,QAAQ,IAAIA,EAAMc,CAAU,EAC1BA,CACT,CACA,OAAO,UAAUC,EAAQ,CACvB,KAAK,OAAS,CAAE,GAAG,KAAK,OAAQ,GAAGA,CAAM,CAC3C,CACA,OAAO,OAAQ,CACb,KAAK,QAAQ,MAAK,EAClB,KAAK,OAAS,CAAE,aAAc,MAAM,EACpCJ,EAAkB,IACpB,CACA,OAAO,iBAAiBX,EAAM,CAC5B,IAAIgB,EAAa,KACjB,MAAMC,EAAgB,KACfD,IACHA,EAAa,KAAK,aAAahB,CAAI,GAE9BgB,GAET,MAAO,CACL,KAAAhB,EACA,MAAO,KAAK,OAAO,cAAgB,OACnC,MAAO,CAACE,EAASC,IAAYc,EAAa,EAAG,MAAMf,EAASC,CAAO,EACnE,KAAM,CAACD,EAASC,IAAYc,EAAa,EAAG,KAAKf,EAASC,CAAO,EACjE,KAAM,CAACD,EAASC,IAAYc,EAAa,EAAG,KAAKf,EAASC,CAAO,EACjE,MAAO,CAACD,EAASC,IAAYc,EAAa,EAAG,MAAMf,EAASC,CAAO,EACnE,eAAgB,IAAMc,EAAa,EAAG,eAAc,EACpD,cAAe,IAAMA,EAAa,EAAG,cAAa,EAClD,cAAe,IAAMA,EAAa,EAAG,cAAa,EAClD,eAAgB,IAAMA,EAAa,EAAG,eAAc,CAC1D,CACE,CACA,OAAO,aAAajB,EAAM,CACxB,OAAIW,EACKA,EAAgB,UAAUX,CAAI,EAEnC,KAAK,OAAO,sBACP,KAAK,OAAO,sBAAsBA,CAAI,EAExC,IAAIU,EAAcV,EAAM,CAC7B,MAAO,KAAK,OAAO,aACnB,GAAG,KAAK,OAAO,cACrB,CAAK,CACH,CACF,EACAF,EAAcc,EAAmB,UAA2B,IAAI,GAAK,EACrEd,EAAcc,EAAmB,SAAU,CACzC,aAAc,MAChB,CAAC,EAMD,SAASM,EAAalB,EAAM,CAC1B,OAAOY,EAAkB,UAAUZ,CAAI,CACzC,CC/KA,IAAIP,EAAY,OAAO,eACnBC,EAAkB,CAACC,EAAKC,EAAKC,IAAUD,KAAOD,EAAMF,EAAUE,EAAKC,EAAK,CAAE,WAAY,GAAM,aAAc,GAAM,SAAU,GAAM,MAAAC,CAAK,CAAE,EAAIF,EAAIC,CAAG,EAAIC,EACtJC,EAAgB,CAACH,EAAKC,EAAKC,IAAUH,EAAgBC,EAAK,OAAOC,GAAQ,SAAWA,EAAM,GAAKA,EAAKC,CAAK,EAIzGsB,EAASD,EAAa,yBAAyB,EAC/CE,EAAY,OAAO,WAAe,KAAe,OAAO,WAAW,OAAW,KAAe,OAAO,WAAW,OAAO,UAAc,IACpIC,EAAkB,KAAM,CAC1B,YAAYpB,EAAS,CAOnB,GANAH,EAAc,KAAM,KAAM,IAAI,EAC9BA,EAAc,KAAM,WAAW,EAC/BA,EAAc,KAAM,kBAAmC,IAAI,GAAK,EAChEA,EAAc,KAAM,eAAgC,IAAI,GAAK,EAC7DA,EAAc,KAAM,gBAAiC,IAAI,GAAK,EAC9DA,EAAc,KAAM,gBAAiC,IAAI,GAAK,EAC1DsB,EACF,MAAM,IAAI,MACR,sFACR,EAEI,KAAK,UAAYnB,EAAQ,SAC3B,CACA,IAAI,YAAa,CACf,GAAI,CAAC,KAAK,GAAI,MAAO,SACrB,MAAMqB,EAAQ,KAAK,GAAG,WACtB,OAAIA,IAAU,EAAU,aACpBA,IAAU,EAAU,OACpBA,IAAU,EAAU,UACjB,QACT,CACA,MAAM,SAAU,CACd,GAAI,KAAK,GACP,MAAM,IAAI,MAAM,iCAAiC,EAEnD,KAAM,CAAE,UAAWC,GAAkB,MAAKC,EAAA,0BAAAD,CAAA,OAAC,QAAO,uBAAI,OAAAE,KAAA,oBAAAF,CAAA,OACtD,YAAK,GAAK,IAAIA,EAAc,KAAK,SAAS,EACnC,IAAI,QAAQ,CAACG,EAASC,IAAW,CACtC,MAAMC,EAAS,IAAM,CACnBT,EAAO,KAAK,sBAAuB,CAAE,UAAW,KAAK,UAAW,EAChE,UAAWU,KAAW,KAAK,aACzBA,EAAO,EAETH,EAAO,CACT,EACMI,EAAWC,GAAQ,CACvBZ,EAAO,MAAM,8BAA+B,CAC1C,UAAW,KAAK,UAChB,MAAOY,GAAA,YAAAA,EAAK,OACtB,CAAS,EACDJ,EAAOI,GAAO,IAAI,MAAM,6BAA6B,CAAC,CACxD,EACA,KAAK,GAAG,KAAK,OAAQH,CAAM,EAC3B,KAAK,GAAG,KAAK,QAASE,CAAO,EAC7B,KAAK,GAAG,GAAG,UAAYE,GAAS,CAC9B,MAAM9B,EAAU8B,EAAK,SAAQ,EAC7B,UAAWH,KAAW,KAAK,gBACzBA,EAAQ3B,CAAO,CAEnB,CAAC,EACD,KAAK,GAAG,GAAG,QAAS,IAAM,CACxBiB,EAAO,KAAK,kBAAkB,EAC9B,UAAWU,KAAW,KAAK,cACzBA,EAAO,CAEX,CAAC,EACD,KAAK,GAAG,GAAG,QAAUE,GAAQ,CAC3BZ,EAAO,MAAM,kBAAmB,CAAE,MAAOY,EAAI,QAAS,EACtD,UAAWF,KAAW,KAAK,cACzBA,EAAQE,CAAG,CAEf,CAAC,CACH,CAAC,CACH,CACA,KAAK7B,EAAS,CACZ,GAAI,CAAC,KAAK,IAAM,KAAK,GAAG,aAAe,EACrC,MAAM,IAAI,MAAM,uBAAuB,EAEzC,KAAK,GAAG,KAAKA,CAAO,CACtB,CACA,UAAU2B,EAAS,CACjB,YAAK,gBAAgB,IAAIA,CAAO,EACzB,IAAM,CACX,KAAK,gBAAgB,OAAOA,CAAO,CACrC,CACF,CACA,OAAOA,EAAS,CACd,YAAK,aAAa,IAAIA,CAAO,EACtB,IAAM,CACX,KAAK,aAAa,OAAOA,CAAO,CAClC,CACF,CACA,QAAQA,EAAS,CACf,YAAK,cAAc,IAAIA,CAAO,EACvB,IAAM,CACX,KAAK,cAAc,OAAOA,CAAO,CACnC,CACF,CACA,QAAQA,EAAS,CACf,YAAK,cAAc,IAAIA,CAAO,EACvB,IAAM,CACX,KAAK,cAAc,OAAOA,CAAO,CACnC,CACF,CACA,OAAQ,CACF,KAAK,KACP,KAAK,GAAG,MAAK,EACb,KAAK,GAAK,KAEd,CACA,SAAU,CACR,KAAK,MAAK,EACV,KAAK,gBAAgB,MAAK,EAC1B,KAAK,aAAa,MAAK,EACvB,KAAK,cAAc,MAAK,EACxB,KAAK,cAAc,MAAK,CAC1B,CACF,EACII,EAAyB,KAAM,CAEjC,YAAYhC,EAAS,CASnB,GARAH,EAAc,KAAM,KAAM,IAAI,EAC9BA,EAAc,KAAM,WAAW,EAC/BA,EAAc,KAAM,SAAS,EAC7BA,EAAc,KAAM,kBAAmC,IAAI,GAAK,EAChEA,EAAc,KAAM,eAAgC,IAAI,GAAK,EAC7DA,EAAc,KAAM,gBAAiC,IAAI,GAAK,EAC9DA,EAAc,KAAM,gBAAiC,IAAI,GAAK,EAC9DA,EAAc,KAAM,qBAAsB,EAAK,EAC3C,CAACsB,EACH,MAAM,IAAI,MAAM,gEAAgE,EAElF,KAAK,UAAYnB,EAAQ,UACzB,KAAK,QAAU,CACb,cAAe,GACf,qBAAsB,IACtB,qBAAsB,IACtB,WAAY,IACZ,kBAAmB,IACnB,MAAO,GACP,GAAGA,CACT,CACE,CACA,IAAI,YAAa,CACf,GAAI,CAAC,KAAK,GAAI,MAAO,SACrB,MAAMqB,EAAQ,KAAK,GAAG,WACtB,OAAIA,IAAU,EAAU,aACpBA,IAAU,EAAU,OACpBA,IAAU,EAAU,UACjB,QACT,CACA,MAAM,SAAU,CACd,GAAI,KAAK,GACP,MAAM,IAAI,MAAM,iCAAiC,EAEnD,GAAI,KAAK,QAAQ,cAAe,CAC9B,MAAMY,GAAyB,MAAKV,EAAA,wBAAAW,CAAA,OAAC,QAAO,0CAAwB,iBAAAA,CAAA,QAAG,QACvE,KAAK,GAAK,IAAID,EAAsB,KAAK,UAAW,GAAI,CACtD,qBAAsB,KAAK,QAAQ,qBACnC,qBAAsB,KAAK,QAAQ,qBACnC,4BAA6B,IAC7B,kBAAmB,KAAK,QAAQ,kBAChC,WAAY,KAAK,QAAQ,WACzB,MAAO,KAAK,QAAQ,KAC5B,CAAO,CACH,MACE,KAAK,GAAK,IAAI,UAAU,KAAK,SAAS,EAExC,OAAO,IAAI,QAAQ,CAACR,EAASC,IAAW,CACtC,MAAMC,EAAS,IAAM,CACf,KAAK,mBACPT,EAAO,KAAK,qCAAsC,CAAE,UAAW,KAAK,UAAW,GAE/EA,EAAO,KAAK,sBAAuB,CAAE,UAAW,KAAK,UAAW,EAChE,KAAK,mBAAqB,IAE5B,UAAWU,KAAW,KAAK,aACzBA,EAAO,EAETH,EAAO,CACT,EACMI,EAAWM,GAAW,CAC1BjB,EAAO,MAAM,8BAA+B,CAAE,UAAW,KAAK,UAAW,EACzE,MAAMkB,EAAQ,IAAI,MAAM,6BAA6B,EACrD,UAAWR,KAAW,KAAK,cACzBA,EAAQQ,CAAK,EAEfV,EAAOU,CAAK,CACd,EACA,KAAK,GAAG,iBAAiB,OAAQT,EAAQ,CAAE,KAAM,GAAM,EACvD,KAAK,GAAG,iBAAiB,QAASE,EAAS,CAAE,KAAM,GAAM,EACzD,KAAK,GAAG,iBAAiB,WAAaQ,GAAU,CAC9C,MAAMpC,EAAUoC,EAAM,KACtB,UAAWT,KAAW,KAAK,gBACzBA,EAAQ3B,CAAO,CAEnB,EAAC,EACD,KAAK,GAAG,iBAAiB,SAAU,IAAM,CACvCiB,EAAO,KAAK,8CAA8C,EAC1D,UAAWU,KAAW,KAAK,cACzBA,EAAO,CAEX,EAAC,EACD,KAAK,GAAG,iBAAiB,SAAWO,GAAW,CAC7CjB,EAAO,MAAM,iBAAiB,EAC9B,MAAMkB,EAAQ,IAAI,MAAM,iBAAiB,EACzC,UAAWR,KAAW,KAAK,cACzBA,EAAQQ,CAAK,CAEjB,EAAC,CACH,CAAC,CACH,CACA,KAAKnC,EAAS,CACZ,GAAI,CAAC,KAAK,IAAM,KAAK,GAAG,aAAe,EACrC,MAAM,IAAI,MAAM,uBAAuB,EAEzC,KAAK,GAAG,KAAKA,CAAO,CACtB,CACA,UAAU2B,EAAS,CACjB,YAAK,gBAAgB,IAAIA,CAAO,EACzB,IAAM,CACX,KAAK,gBAAgB,OAAOA,CAAO,CACrC,CACF,CACA,OAAOA,EAAS,CACd,YAAK,aAAa,IAAIA,CAAO,EACtB,IAAM,CACX,KAAK,aAAa,OAAOA,CAAO,CAClC,CACF,CACA,QAAQA,EAAS,CACf,YAAK,cAAc,IAAIA,CAAO,EACvB,IAAM,CACX,KAAK,cAAc,OAAOA,CAAO,CACnC,CACF,CACA,QAAQA,EAAS,CACf,YAAK,cAAc,IAAIA,CAAO,EACvB,IAAM,CACX,KAAK,cAAc,OAAOA,CAAO,CACnC,CACF,CACA,OAAQ,CACF,KAAK,KACP,KAAK,GAAG,MAAK,EACb,KAAK,GAAK,KAEd,CACA,SAAU,CACR,KAAK,MAAK,EACV,KAAK,gBAAgB,MAAK,EAC1B,KAAK,aAAa,MAAK,EACvB,KAAK,cAAc,MAAK,EACxB,KAAK,cAAc,MAAK,CAC1B,CACF,EACA,eAAeU,EAAsBtC,EAAS,CAC5C,GAAImB,EAAW,CACb,MAAMoB,EAAS,IAAIP,EAAuBhC,CAAO,EACjD,aAAMuC,EAAO,QAAO,EACbA,CACT,KAAO,CACL,MAAMA,EAAS,IAAInB,EAAgBpB,CAAO,EAC1C,aAAMuC,EAAO,QAAO,EACbA,CACT,CACF,CClQatB,EAAa,yBAAyB","names":["__defProp","__defNormalProp","obj","key","value","__publicField","_ConsoleLogger","name","options","message","context","level","parts","color","logLine","consoleMethod","_a","ConsoleLogger","externalFactory","LoggerFactoryImpl","nameOrClass","lazyLogger","config","realLogger","getRealLogger","createLogger","logger","isBrowser","WebSocketClient","state","NodeWebSocket","__vitePreload","n","resolve","reject","onOpen","handler","onError","err","data","BrowserWebSocketClient","ReconnectingWebSocket","__vite_default__","_event","error","event","createWebSocketClient","client"],"ignoreList":[],"sources":["../../../../../packages/common/dist/index.js","../../../../../packages/network/dist/chunk-63P5VUHB.js","../../../../../packages/network/dist/index.js"],"sourcesContent":["var __defProp = Object.defineProperty;\nvar __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;\nvar __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== \"symbol\" ? key + \"\" : key, value);\n\n// src/logger/ConsoleLogger.ts\nvar _ConsoleLogger = class _ConsoleLogger {\n constructor(name, options = {}) {\n __publicField(this, \"name\");\n __publicField(this, \"level\");\n __publicField(this, \"colors\");\n __publicField(this, \"timestamps\");\n this.name = name;\n this.level = options.level ?? \"info\";\n this.colors = options.colors ?? this.isNodeEnvironment();\n this.timestamps = options.timestamps ?? true;\n }\n debug(message, context) {\n if (this.isDebugEnabled()) {\n this.log(\"DEBUG\", message, context);\n }\n }\n info(message, context) {\n if (this.isInfoEnabled()) {\n this.log(\"INFO\", message, context);\n }\n }\n warn(message, context) {\n if (this.isWarnEnabled()) {\n this.log(\"WARN\", message, context);\n }\n }\n error(message, context) {\n if (this.isErrorEnabled()) {\n if (message instanceof Error) {\n this.log(\"ERROR\", message.message, { ...context, stack: message.stack });\n } else {\n this.log(\"ERROR\", message, context);\n }\n }\n }\n isDebugEnabled() {\n return this.getLevelValue(this.level) <= this.getLevelValue(\"debug\");\n }\n isInfoEnabled() {\n return this.getLevelValue(this.level) <= this.getLevelValue(\"info\");\n }\n isWarnEnabled() {\n return this.getLevelValue(this.level) <= this.getLevelValue(\"warn\");\n }\n isErrorEnabled() {\n return this.getLevelValue(this.level) <= this.getLevelValue(\"error\");\n }\n getLevelValue(level) {\n const levels = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n silent: 4\n };\n return levels[level];\n }\n log(level, message, context) {\n const parts = [];\n if (this.timestamps) {\n parts.push((/* @__PURE__ */ new Date()).toISOString());\n }\n if (this.colors) {\n const color = _ConsoleLogger.COLORS[level];\n parts.push(`${color}${level.padEnd(5)}${_ConsoleLogger.COLORS.RESET}`);\n } else {\n parts.push(level.padEnd(5));\n }\n parts.push(`[${this.name}]`);\n parts.push(message);\n const logLine = parts.join(\" \");\n const consoleMethod = this.getConsoleMethod(level);\n if (context && Object.keys(context).length > 0) {\n consoleMethod(logLine, context);\n } else {\n consoleMethod(logLine);\n }\n }\n getConsoleMethod(level) {\n switch (level) {\n case \"DEBUG\":\n return console.debug.bind(console);\n case \"INFO\":\n return console.info.bind(console);\n case \"WARN\":\n return console.warn.bind(console);\n case \"ERROR\":\n return console.error.bind(console);\n default:\n return console.log.bind(console);\n }\n }\n isNodeEnvironment() {\n return typeof process !== \"undefined\" && process.versions?.node !== void 0;\n }\n};\n__publicField(_ConsoleLogger, \"COLORS\", {\n DEBUG: \"\\x1B[36m\",\n INFO: \"\\x1B[32m\",\n WARN: \"\\x1B[33m\",\n ERROR: \"\\x1B[31m\",\n RESET: \"\\x1B[0m\"\n});\nvar ConsoleLogger = _ConsoleLogger;\n\n// src/logger/LoggerFactoryImpl.ts\nvar externalFactory = null;\nvar LoggerFactoryImpl = class {\n static getLogger(nameOrClass) {\n const name = typeof nameOrClass === \"string\" ? nameOrClass : nameOrClass.name;\n if (this.loggers.has(name)) {\n return this.loggers.get(name);\n }\n const lazyLogger = this.createLazyLogger(name);\n this.loggers.set(name, lazyLogger);\n return lazyLogger;\n }\n static configure(config) {\n this.config = { ...this.config, ...config };\n }\n static reset() {\n this.loggers.clear();\n this.config = { defaultLevel: \"info\" };\n externalFactory = null;\n }\n static createLazyLogger(name) {\n let realLogger = null;\n const getRealLogger = () => {\n if (!realLogger) {\n realLogger = this.createLogger(name);\n }\n return realLogger;\n };\n return {\n name,\n level: this.config.defaultLevel || \"info\",\n debug: (message, context) => getRealLogger().debug(message, context),\n info: (message, context) => getRealLogger().info(message, context),\n warn: (message, context) => getRealLogger().warn(message, context),\n error: (message, context) => getRealLogger().error(message, context),\n isDebugEnabled: () => getRealLogger().isDebugEnabled(),\n isInfoEnabled: () => getRealLogger().isInfoEnabled(),\n isWarnEnabled: () => getRealLogger().isWarnEnabled(),\n isErrorEnabled: () => getRealLogger().isErrorEnabled()\n };\n }\n static createLogger(name) {\n if (externalFactory) {\n return externalFactory.getLogger(name);\n }\n if (this.config.defaultImplementation) {\n return this.config.defaultImplementation(name);\n }\n return new ConsoleLogger(name, {\n level: this.config.defaultLevel,\n ...this.config.consoleOptions\n });\n }\n};\n__publicField(LoggerFactoryImpl, \"loggers\", /* @__PURE__ */ new Map());\n__publicField(LoggerFactoryImpl, \"config\", {\n defaultLevel: \"info\"\n});\nfunction setLoggerFactory(factory) {\n externalFactory = factory;\n LoggerFactoryImpl.reset();\n externalFactory = factory;\n}\nfunction createLogger(name) {\n return LoggerFactoryImpl.getLogger(name);\n}\nexport {\n ConsoleLogger,\n LoggerFactoryImpl,\n createLogger,\n setLoggerFactory\n};\n//# sourceMappingURL=index.js.map","var __defProp = Object.defineProperty;\nvar __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;\nvar __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== \"symbol\" ? key + \"\" : key, value);\n\n// src/WebSocketClient.ts\nimport { createLogger } from \"@agentxjs/common\";\nvar logger = createLogger(\"network/WebSocketClient\");\nvar isBrowser = typeof globalThis !== \"undefined\" && typeof globalThis.window !== \"undefined\" && typeof globalThis.window.WebSocket !== \"undefined\";\nvar WebSocketClient = class {\n constructor(options) {\n __publicField(this, \"ws\", null);\n __publicField(this, \"serverUrl\");\n __publicField(this, \"messageHandlers\", /* @__PURE__ */ new Set());\n __publicField(this, \"openHandlers\", /* @__PURE__ */ new Set());\n __publicField(this, \"closeHandlers\", /* @__PURE__ */ new Set());\n __publicField(this, \"errorHandlers\", /* @__PURE__ */ new Set());\n if (isBrowser) {\n throw new Error(\n \"Use createBrowserWebSocketClient() in browser environment for auto-reconnect support\"\n );\n }\n this.serverUrl = options.serverUrl;\n }\n get readyState() {\n if (!this.ws) return \"closed\";\n const state = this.ws.readyState;\n if (state === 0) return \"connecting\";\n if (state === 1) return \"open\";\n if (state === 2) return \"closing\";\n return \"closed\";\n }\n async connect() {\n if (this.ws) {\n throw new Error(\"Already connected or connecting\");\n }\n const { WebSocket: NodeWebSocket } = await import(\"ws\");\n this.ws = new NodeWebSocket(this.serverUrl);\n return new Promise((resolve, reject) => {\n const onOpen = () => {\n logger.info(\"WebSocket connected\", { serverUrl: this.serverUrl });\n for (const handler of this.openHandlers) {\n handler();\n }\n resolve();\n };\n const onError = (err) => {\n logger.error(\"WebSocket connection failed\", {\n serverUrl: this.serverUrl,\n error: err?.message\n });\n reject(err || new Error(\"WebSocket connection failed\"));\n };\n this.ws.once(\"open\", onOpen);\n this.ws.once(\"error\", onError);\n this.ws.on(\"message\", (data) => {\n const message = data.toString();\n for (const handler of this.messageHandlers) {\n handler(message);\n }\n });\n this.ws.on(\"close\", () => {\n logger.warn(\"WebSocket closed\");\n for (const handler of this.closeHandlers) {\n handler();\n }\n });\n this.ws.on(\"error\", (err) => {\n logger.error(\"WebSocket error\", { error: err.message });\n for (const handler of this.errorHandlers) {\n handler(err);\n }\n });\n });\n }\n send(message) {\n if (!this.ws || this.ws.readyState !== 1) {\n throw new Error(\"WebSocket is not open\");\n }\n this.ws.send(message);\n }\n onMessage(handler) {\n this.messageHandlers.add(handler);\n return () => {\n this.messageHandlers.delete(handler);\n };\n }\n onOpen(handler) {\n this.openHandlers.add(handler);\n return () => {\n this.openHandlers.delete(handler);\n };\n }\n onClose(handler) {\n this.closeHandlers.add(handler);\n return () => {\n this.closeHandlers.delete(handler);\n };\n }\n onError(handler) {\n this.errorHandlers.add(handler);\n return () => {\n this.errorHandlers.delete(handler);\n };\n }\n close() {\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n }\n dispose() {\n this.close();\n this.messageHandlers.clear();\n this.openHandlers.clear();\n this.closeHandlers.clear();\n this.errorHandlers.clear();\n }\n};\nvar BrowserWebSocketClient = class {\n // Track if this is a reconnection\n constructor(options) {\n __publicField(this, \"ws\", null);\n __publicField(this, \"serverUrl\");\n __publicField(this, \"options\");\n __publicField(this, \"messageHandlers\", /* @__PURE__ */ new Set());\n __publicField(this, \"openHandlers\", /* @__PURE__ */ new Set());\n __publicField(this, \"closeHandlers\", /* @__PURE__ */ new Set());\n __publicField(this, \"errorHandlers\", /* @__PURE__ */ new Set());\n __publicField(this, \"hasConnectedBefore\", false);\n if (!isBrowser) {\n throw new Error(\"BrowserWebSocketClient can only be used in browser environment\");\n }\n this.serverUrl = options.serverUrl;\n this.options = {\n autoReconnect: true,\n minReconnectionDelay: 1e3,\n maxReconnectionDelay: 1e4,\n maxRetries: Infinity,\n connectionTimeout: 4e3,\n debug: false,\n ...options\n };\n }\n get readyState() {\n if (!this.ws) return \"closed\";\n const state = this.ws.readyState;\n if (state === 0) return \"connecting\";\n if (state === 1) return \"open\";\n if (state === 2) return \"closing\";\n return \"closed\";\n }\n async connect() {\n if (this.ws) {\n throw new Error(\"Already connected or connecting\");\n }\n if (this.options.autoReconnect) {\n const ReconnectingWebSocket = (await import(\"reconnecting-websocket\")).default;\n this.ws = new ReconnectingWebSocket(this.serverUrl, [], {\n maxReconnectionDelay: this.options.maxReconnectionDelay,\n minReconnectionDelay: this.options.minReconnectionDelay,\n reconnectionDelayGrowFactor: 1.3,\n connectionTimeout: this.options.connectionTimeout,\n maxRetries: this.options.maxRetries,\n debug: this.options.debug\n });\n } else {\n this.ws = new WebSocket(this.serverUrl);\n }\n return new Promise((resolve, reject) => {\n const onOpen = () => {\n if (this.hasConnectedBefore) {\n logger.info(\"WebSocket reconnected successfully\", { serverUrl: this.serverUrl });\n } else {\n logger.info(\"WebSocket connected\", { serverUrl: this.serverUrl });\n this.hasConnectedBefore = true;\n }\n for (const handler of this.openHandlers) {\n handler();\n }\n resolve();\n };\n const onError = (_event) => {\n logger.error(\"WebSocket connection failed\", { serverUrl: this.serverUrl });\n const error = new Error(\"WebSocket connection failed\");\n for (const handler of this.errorHandlers) {\n handler(error);\n }\n reject(error);\n };\n this.ws.addEventListener(\"open\", onOpen, { once: true });\n this.ws.addEventListener(\"error\", onError, { once: true });\n this.ws.addEventListener(\"message\", ((event) => {\n const message = event.data;\n for (const handler of this.messageHandlers) {\n handler(message);\n }\n }));\n this.ws.addEventListener(\"close\", (() => {\n logger.info(\"WebSocket closed, attempting to reconnect...\");\n for (const handler of this.closeHandlers) {\n handler();\n }\n }));\n this.ws.addEventListener(\"error\", ((_event) => {\n logger.error(\"WebSocket error\");\n const error = new Error(\"WebSocket error\");\n for (const handler of this.errorHandlers) {\n handler(error);\n }\n }));\n });\n }\n send(message) {\n if (!this.ws || this.ws.readyState !== 1) {\n throw new Error(\"WebSocket is not open\");\n }\n this.ws.send(message);\n }\n onMessage(handler) {\n this.messageHandlers.add(handler);\n return () => {\n this.messageHandlers.delete(handler);\n };\n }\n onOpen(handler) {\n this.openHandlers.add(handler);\n return () => {\n this.openHandlers.delete(handler);\n };\n }\n onClose(handler) {\n this.closeHandlers.add(handler);\n return () => {\n this.closeHandlers.delete(handler);\n };\n }\n onError(handler) {\n this.errorHandlers.add(handler);\n return () => {\n this.errorHandlers.delete(handler);\n };\n }\n close() {\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n }\n dispose() {\n this.close();\n this.messageHandlers.clear();\n this.openHandlers.clear();\n this.closeHandlers.clear();\n this.errorHandlers.clear();\n }\n};\nasync function createWebSocketClient(options) {\n if (isBrowser) {\n const client = new BrowserWebSocketClient(options);\n await client.connect();\n return client;\n } else {\n const client = new WebSocketClient(options);\n await client.connect();\n return client;\n }\n}\n\nexport {\n __publicField,\n WebSocketClient,\n BrowserWebSocketClient,\n createWebSocketClient\n};\n//# sourceMappingURL=chunk-63P5VUHB.js.map","import {\n WebSocketClient,\n __publicField,\n createWebSocketClient\n} from \"./chunk-63P5VUHB.js\";\n\n// src/WebSocketServer.ts\nimport { createLogger } from \"@agentxjs/common\";\nvar logger = createLogger(\"network/WebSocketServer\");\nvar WebSocketConnection = class {\n constructor(ws, options) {\n __publicField(this, \"id\");\n __publicField(this, \"ws\");\n __publicField(this, \"messageHandlers\", /* @__PURE__ */ new Set());\n __publicField(this, \"closeHandlers\", /* @__PURE__ */ new Set());\n __publicField(this, \"errorHandlers\", /* @__PURE__ */ new Set());\n __publicField(this, \"heartbeatInterval\");\n __publicField(this, \"isAlive\", true);\n this.ws = ws;\n this.id = `conn_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;\n if (options.heartbeat !== false) {\n const interval = options.heartbeatInterval || 3e4;\n ws.on(\"pong\", () => {\n this.isAlive = true;\n logger.debug(\"Heartbeat pong received\", { id: this.id });\n });\n this.heartbeatInterval = setInterval(() => {\n if (!this.isAlive) {\n logger.warn(\"Client heartbeat timeout, terminating connection\", { id: this.id });\n clearInterval(this.heartbeatInterval);\n ws.terminate();\n return;\n }\n this.isAlive = false;\n ws.ping();\n logger.debug(\"Heartbeat ping sent\", { id: this.id });\n }, interval);\n }\n ws.on(\"message\", (data) => {\n const message = data.toString();\n for (const handler of this.messageHandlers) {\n handler(message);\n }\n });\n ws.on(\"close\", () => {\n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n }\n for (const handler of this.closeHandlers) {\n handler();\n }\n });\n ws.on(\"error\", (err) => {\n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n }\n for (const handler of this.errorHandlers) {\n handler(err);\n }\n });\n }\n send(message) {\n if (this.ws.readyState === 1) {\n this.ws.send(message);\n }\n }\n onMessage(handler) {\n this.messageHandlers.add(handler);\n return () => {\n this.messageHandlers.delete(handler);\n };\n }\n onClose(handler) {\n this.closeHandlers.add(handler);\n return () => {\n this.closeHandlers.delete(handler);\n };\n }\n onError(handler) {\n this.errorHandlers.add(handler);\n return () => {\n this.errorHandlers.delete(handler);\n };\n }\n close() {\n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n }\n this.ws.close();\n }\n};\nvar WebSocketServer = class {\n constructor(options = {}) {\n __publicField(this, \"wss\", null);\n __publicField(this, \"connections\", /* @__PURE__ */ new Set());\n __publicField(this, \"connectionHandlers\", /* @__PURE__ */ new Set());\n __publicField(this, \"options\");\n __publicField(this, \"attachedToServer\", false);\n this.options = options;\n }\n async listen(port, host = \"0.0.0.0\") {\n if (this.wss) {\n throw new Error(\"Server already listening\");\n }\n if (this.attachedToServer) {\n throw new Error(\n \"Cannot listen when attached to existing server. The server should call listen() instead.\"\n );\n }\n const { WebSocketServer: WSS } = await import(\"ws\");\n this.wss = new WSS({ port, host });\n this.wss.on(\"connection\", (ws) => {\n this.handleConnection(ws);\n });\n logger.info(\"WebSocket server listening\", { port, host });\n }\n attach(server, path = \"/ws\") {\n if (this.wss) {\n throw new Error(\"Server already initialized\");\n }\n import(\"ws\").then(({ WebSocketServer: WSS }) => {\n this.wss = new WSS({ noServer: true });\n server.on(\"upgrade\", (request, socket, head) => {\n const url = new URL(request.url || \"\", `http://${request.headers.host}`);\n if (url.pathname === path) {\n this.wss.handleUpgrade(request, socket, head, (ws) => {\n this.wss.emit(\"connection\", ws, request);\n });\n } else {\n socket.destroy();\n }\n });\n this.wss.on(\"connection\", (ws) => {\n this.handleConnection(ws);\n });\n this.attachedToServer = true;\n logger.info(\"WebSocket attached to existing HTTP server\", { path });\n });\n }\n handleConnection(ws) {\n const connection = new WebSocketConnection(ws, this.options);\n this.connections.add(connection);\n logger.info(\"Client connected\", {\n connectionId: connection.id,\n totalConnections: this.connections.size\n });\n connection.onClose(() => {\n this.connections.delete(connection);\n logger.info(\"Client disconnected\", {\n connectionId: connection.id,\n totalConnections: this.connections.size\n });\n });\n for (const handler of this.connectionHandlers) {\n handler(connection);\n }\n }\n onConnection(handler) {\n this.connectionHandlers.add(handler);\n return () => {\n this.connectionHandlers.delete(handler);\n };\n }\n broadcast(message) {\n for (const connection of this.connections) {\n connection.send(message);\n }\n }\n async close() {\n if (!this.wss) return;\n for (const connection of this.connections) {\n connection.close();\n }\n this.connections.clear();\n if (!this.attachedToServer) {\n await new Promise((resolve) => {\n this.wss.close(() => resolve());\n });\n }\n this.wss = null;\n }\n async dispose() {\n await this.close();\n this.connectionHandlers.clear();\n }\n};\nexport {\n WebSocketClient,\n WebSocketServer,\n createWebSocketClient\n};\n//# sourceMappingURL=index.js.map"],"file":"assets/index-1uLnFQV1.js"}
|